Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
build
uf2
.vscode
8 changes: 6 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ add_subdirectory(ext/FatFs_SPI build)

add_executable(RP2040_GB
src/main.c
src/linkcable.c
src/mk_ili9225.c
ext/minigb_apu/minigb_apu.c
ext/i2s/i2s.c
Expand All @@ -25,7 +26,7 @@ target_link_libraries(RP2040_GB
FatFs_SPI
pico_stdlib pico_stdio pico_bootrom pico_multicore pico_stdio pico_multicore
hardware_clocks hardware_pio hardware_vreg hardware_pio
hardware_sync hardware_pll hardware_spi hardware_irq hardware_dma
hardware_sync hardware_pll hardware_spi hardware_irq hardware_dma hardware_flash
pico_binary_info)
target_compile_definitions(RP2040_GB PRIVATE
PARAM_ASSERTIONS_DISABLE_ALL=1
Expand All @@ -44,9 +45,12 @@ function(pico_add_verbose_dis_output TARGET)
)
endfunction()

pico_generate_pio_header(${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}/src/linkcable_master.pio)
pico_generate_pio_header(${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}/src/linkcable_slave.pio)

pico_set_binary_type(RP2040_GB copy_to_ram)
#pico_set_binary_type(RP2040_GB no_flash)
pico_enable_stdio_usb(RP2040_GB 1)
pico_enable_stdio_usb(RP2040_GB 0)
pico_enable_stdio_uart(RP2040_GB 0)
pico_add_verbose_dis_output(RP2040_GB)
pico_add_bin_output(RP2040_GB)
Expand Down
52 changes: 52 additions & 0 deletions inc/linkcable.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@

#ifndef LINKCABLE_H
#define LINKCABLE_H


#include "hardware/irq.h"
#include "hardware/pio.h"
#include "hardware/gpio.h"
#include "linkcable_slave.pio.h"
#include "linkcable_master.pio.h"

#define LINKCABLE_PIO pio1
#define LINKCABLE_SM 0

extern bool gLinkcable_isSlave;
extern uint gLinkgcable_pio_slave_pc;
extern uint gLinkgcable_pio_master_pc;

static inline void linkcable_isr_clear(void) {
pio_interrupt_clear(LINKCABLE_PIO, 0);
}

static inline void linkcable_set_slave(bool slave){
if (gLinkcable_isSlave != slave){
gLinkcable_isSlave = slave;
pio_sm_set_enabled(LINKCABLE_PIO, LINKCABLE_SM, false);
pio_sm_clear_fifos(LINKCABLE_PIO, LINKCABLE_SM);
pio_sm_restart(LINKCABLE_PIO, LINKCABLE_SM);
pio_sm_clkdiv_restart(LINKCABLE_PIO, LINKCABLE_SM);
if (slave){
linkcable_slave_program_init(LINKCABLE_PIO, LINKCABLE_SM, gLinkgcable_pio_slave_pc);
}else{
linkcable_master_program_init(LINKCABLE_PIO, LINKCABLE_SM, gLinkgcable_pio_master_pc);
}
pio_sm_set_enabled(LINKCABLE_PIO, LINKCABLE_SM, true);
}
}

static inline void linkcable_start(uint8_t byte){
pio_sm_clear_fifos(LINKCABLE_PIO, LINKCABLE_SM);
pio_sm_put(LINKCABLE_PIO, LINKCABLE_SM, byte);
}

static inline uint8_t linkcable_receive(void) {
return pio_sm_get(LINKCABLE_PIO, LINKCABLE_SM);
}

void linkcable_init(irq_handler_t irq_handler);

void linkcable_shutdown(void);

#endif //LINKCABLE_H
112 changes: 5 additions & 107 deletions inc/peanut_gb.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
#include <stdint.h> /* Required for int types */
#include <string.h> /* Required for memset */
#include <time.h> /* Required for tm struct */
#include "linkcable.h"

/**
* If PEANUT_GB_IS_LITTLE_ENDIAN is positive, then Peanut-GB will be configured
Expand Down Expand Up @@ -427,7 +428,6 @@ struct count_s
uint_fast16_t lcd_count; /* LCD Timing */
uint_fast16_t div_count; /* Divider Register Counter */
uint_fast16_t tima_count; /* Timer Counter */
uint_fast16_t serial_count; /* Serial Counter */
};

#if ENABLE_LCD
Expand Down Expand Up @@ -473,15 +473,6 @@ enum gb_init_error_e
GB_INIT_INVALID_CHECKSUM
};

/**
* Return codes for serial receive function, mainly for clarity.
*/
enum gb_serial_rx_ret_e
{
GB_SERIAL_RX_SUCCESS = 0,
GB_SERIAL_RX_NO_CONNECTION = 1
};

/**
* Emulator context.
*
Expand Down Expand Up @@ -527,10 +518,6 @@ struct gb_s
*/
void (*gb_error)(struct gb_s*, const enum gb_error_e, const uint16_t addr);

/* Transmit one byte and return the received byte. */
void (*gb_serial_tx)(struct gb_s*, const uint8_t tx);
enum gb_serial_rx_ret_e (*gb_serial_rx)(struct gb_s*, uint8_t* rx);

/* Read byte from boot ROM at given address. */
uint8_t (*gb_bootrom_read)(struct gb_s*, const uint_fast16_t addr);

Expand Down Expand Up @@ -984,10 +971,13 @@ void __gb_write(struct gb_s *gb, uint_fast16_t addr, uint8_t val)
/* Serial */
case 0x01:
gb->hram_io[IO_SB] = val;
if (gLinkcable_isSlave) linkcable_start(val);
return;

case 0x02:
gb->hram_io[IO_SC] = val;
gb->hram_io[IO_SC] = val;
linkcable_set_slave((val & 1) ^ 1);
if ((val & 0x81) == 0x81) linkcable_start(gb->hram_io[IO_SB]);
return;

/* Timer Registers */
Expand Down Expand Up @@ -2383,15 +2373,6 @@ void __gb_step_cpu(struct gb_s *gb)
PGB_UNREACHABLE();
}

if(gb->hram_io[IO_SC] & SERIAL_SC_TX_START)
{
int serial_cycles = SERIAL_CYCLES -
gb->counter.serial_count;

if(serial_cycles < halt_cycles)
halt_cycles = serial_cycles;
}

if(gb->hram_io[IO_TAC] & IO_TAC_ENABLE_MASK)
{
int tac_cycles = TAC_CYCLES[gb->hram_io[IO_TAC] & IO_TAC_RATE_MASK] -
Expand Down Expand Up @@ -3202,56 +3183,6 @@ void __gb_step_cpu(struct gb_s *gb)
gb->counter.div_count -= DIV_CYCLES;
}

/* Check serial transmission. */
if(gb->hram_io[IO_SC] & SERIAL_SC_TX_START)
{
/* If new transfer, call TX function. */
if(gb->counter.serial_count == 0 &&
gb->gb_serial_tx != NULL)
(gb->gb_serial_tx)(gb, gb->hram_io[IO_SB]);

gb->counter.serial_count += inst_cycles;

/* If it's time to receive byte, call RX function. */
if(gb->counter.serial_count >= SERIAL_CYCLES)
{
/* If RX can be done, do it. */
/* If RX failed, do not change SB if using external
* clock, or set to 0xFF if using internal clock. */
uint8_t rx;

if(gb->gb_serial_rx != NULL &&
(gb->gb_serial_rx(gb, &rx) ==
GB_SERIAL_RX_SUCCESS))
{
gb->hram_io[IO_SB] = rx;

/* Inform game of serial TX/RX completion. */
gb->hram_io[IO_SC] &= 0x01;
gb->hram_io[IO_IF] |= SERIAL_INTR;
}
else if(gb->hram_io[IO_SC] & SERIAL_SC_CLOCK_SRC)
{
/* If using internal clock, and console is not
* attached to any external peripheral, shifted
* bits are replaced with logic 1. */
gb->hram_io[IO_SB] = 0xFF;

/* Inform game of serial TX/RX completion. */
gb->hram_io[IO_SC] &= 0x01;
gb->hram_io[IO_IF] |= SERIAL_INTR;
}
else
{
/* If using external clock, and console is not
* attached to any external peripheral, bits are
* not shifted, so SB is not modified. */
}

gb->counter.serial_count = 0;
}
}

/* TIMA register timing */
/* TODO: Change tac_enable to struct of TAC timer control bits. */
if(gb->hram_io[IO_TAC] & IO_TAC_ENABLE_MASK)
Expand Down Expand Up @@ -3413,15 +3344,6 @@ uint_fast32_t gb_get_save_size(struct gb_s *gb)
return ram_sizes[ram_size];
}

void gb_init_serial(struct gb_s *gb,
void (*gb_serial_tx)(struct gb_s*, const uint8_t),
enum gb_serial_rx_ret_e (*gb_serial_rx)(struct gb_s*,
uint8_t*))
{
gb->gb_serial_tx = gb_serial_tx;
gb->gb_serial_rx = gb_serial_rx;
}

uint8_t gb_colour_hash(struct gb_s *gb)
{
#define ROM_TITLE_START_ADDR 0x0134
Expand Down Expand Up @@ -3487,7 +3409,6 @@ void gb_reset(struct gb_s *gb)
gb->counter.lcd_count = 0;
gb->counter.div_count = 0;
gb->counter.tima_count = 0;
gb->counter.serial_count = 0;

gb->direct.joypad = 0xFF;
gb->hram_io[IO_JOYP] = 0xCF;
Expand Down Expand Up @@ -3556,12 +3477,6 @@ enum gb_init_error_e gb_init(struct gb_s *gb,
gb->gb_error = gb_error;
gb->direct.priv = priv;

/* Initialise serial transfer function to NULL. If the front-end does
* not provide serial support, Peanut-GB will emulate no cable connected
* automatically. */
gb->gb_serial_tx = NULL;
gb->gb_serial_rx = NULL;

gb->gb_bootrom_read = NULL;

/* Check valid ROM using checksum value. */
Expand Down Expand Up @@ -3767,23 +3682,6 @@ void gb_init_lcd(struct gb_s *gb,
const uint_fast8_t line));
#endif

/**
* Initialises the serial connection of the emulator. This function is optional,
* and if not called, the emulator will assume that no link cable is connected
* to the game.
*
* \param gb An initialised emulator context. Must not be NULL.
* \param gb_serial_tx Pointer to function that transmits a byte of data over
* the serial connection. Must not be NULL.
* \param gb_serial_rx Pointer to function that receives a byte of data over the
* serial connection. If no byte is received,
* return GB_SERIAL_RX_NO_CONNECTION. Must not be NULL.
*/
void gb_init_serial(struct gb_s *gb,
void (*gb_serial_tx)(struct gb_s*, const uint8_t),
enum gb_serial_rx_ret_e (*gb_serial_rx)(struct gb_s*,
uint8_t*));

/**
* Obtains the save size of the game (size of the Cart RAM). Required by the
* frontend to allocate enough memory for the Cart RAM.
Expand Down
30 changes: 30 additions & 0 deletions src/linkcable.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@

#include "linkcable.h"
#include "pico/stdlib.h"
bool gLinkcable_isSlave = false;
uint gLinkgcable_pio_slave_pc = 0;
uint gLinkgcable_pio_master_pc = 0;

void linkcable_init(irq_handler_t irq_handler){
gpio_set_function(PIN_SCK, GPIO_FUNC_PIO1);
gpio_set_function(PIN_SIN, GPIO_FUNC_PIO1);
gpio_set_function(PIN_SOUT, GPIO_FUNC_PIO1);

gLinkgcable_pio_slave_pc = pio_add_program(LINKCABLE_PIO, &linkcable_slave_program);
gLinkgcable_pio_master_pc = pio_add_program(LINKCABLE_PIO, &linkcable_master_program);

pio_set_irq0_source_enabled(LINKCABLE_PIO, pis_interrupt0, true);
irq_set_exclusive_handler(PIO1_IRQ_0, irq_handler);
irq_set_enabled(PIO1_IRQ_0, true);
gLinkcable_isSlave = false;
linkcable_set_slave(true);
}

void __not_in_flash_func(linkcable_shutdown)(void){
// irq_set_enabled(LINK_DMA_IRQ, false);
// dma_channel_set_irq1_enabled(gLinkcable_dma_rx, false);
// dma_channel_abort(gLinkcable_dma_rx);
// dma_channel_abort(gLinkcable_dma_tx);
// dma_unclaim_mask((1u << gLinkcable_dma_tx) | (1u << gLinkcable_dma_rx));
// spi_deinit(spi1);
}
49 changes: 49 additions & 0 deletions src/linkcable_master.pio
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
; Program name
.program linkcable_master

.wrap_target
set X, 7
pull block
out null, 24
out pins, 1
set PINS, 0 [19]
jmp loop_start
bitloop:
nop [7]
nop [19]
set PINS, 0
out pins, 1 [19]
loop_start:
nop [18]
nop [9]
set PINS, 1 [19]
in pins, 1
jmp x-- bitloop
push noblock
irq 0
.wrap

% c-sdk {
static inline void linkcable_master_program_init(PIO pio, uint sm, uint offset) {
pio_sm_config c = linkcable_master_program_get_default_config(offset);

sm_config_set_set_pins(&c, PIN_SCK, 1 );
pio_sm_set_consecutive_pindirs(pio, sm, PIN_SCK, 1, true);

sm_config_set_in_pins(&c, PIN_SIN);
pio_sm_set_consecutive_pindirs(pio, sm, PIN_SIN, 1, false);
sm_config_set_in_shift(&c, false, false, 8);

sm_config_set_out_pins(&c, PIN_SOUT, 1);
pio_sm_set_consecutive_pindirs(pio, sm, PIN_SOUT, 1, true);
sm_config_set_out_shift(&c, false, false, 8);

sm_config_set_clkdiv(&c, 300);

pio_gpio_init(pio, PIN_SCK);
pio_gpio_init(pio, PIN_SIN);
pio_gpio_init(pio, PIN_SOUT);

pio_sm_init(pio, sm, offset, &c);
}
%}
Loading