diff --git a/.gitignore b/.gitignore index 754f7df..eaa112f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ build uf2 +.vscode diff --git a/CMakeLists.txt b/CMakeLists.txt index bee5b41..81cb5c8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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 @@ -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 @@ -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) diff --git a/inc/linkcable.h b/inc/linkcable.h new file mode 100644 index 0000000..8531dd1 --- /dev/null +++ b/inc/linkcable.h @@ -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 diff --git a/inc/peanut_gb.h b/inc/peanut_gb.h index 5421d1e..c7f4765 100644 --- a/inc/peanut_gb.h +++ b/inc/peanut_gb.h @@ -45,6 +45,7 @@ #include /* Required for int types */ #include /* Required for memset */ #include /* Required for tm struct */ +#include "linkcable.h" /** * If PEANUT_GB_IS_LITTLE_ENDIAN is positive, then Peanut-GB will be configured @@ -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 @@ -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. * @@ -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); @@ -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 */ @@ -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] - @@ -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) @@ -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 @@ -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; @@ -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. */ @@ -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. diff --git a/src/linkcable.c b/src/linkcable.c new file mode 100644 index 0000000..dc6fb8d --- /dev/null +++ b/src/linkcable.c @@ -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); +} \ No newline at end of file diff --git a/src/linkcable_master.pio b/src/linkcable_master.pio new file mode 100644 index 0000000..d436420 --- /dev/null +++ b/src/linkcable_master.pio @@ -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); +} +%} \ No newline at end of file diff --git a/src/linkcable_slave.pio b/src/linkcable_slave.pio new file mode 100644 index 0000000..bbc6f62 --- /dev/null +++ b/src/linkcable_slave.pio @@ -0,0 +1,49 @@ +; Program name +.program linkcable_slave + +.wrap_target + set X, 7 + wait 0 gpio 10 ; FIXUP GPIO PIN_SCK HERE + pull noblock + out null, 24 + out pins, 1 [19] + jmp loop_start +bitloop: + nop [19] + wait 0 gpio 10 ; FIXUP GPIO PIN_SCK HERE + out pins, 1 [19] +loop_start: + wait 1 gpio 10 [19] ; FIXUP GPIO PIN_SCK HERE + in pins, 1 + jmp x-- bitloop + push noblock + irq 0 +.wrap + +% c-sdk { +#define PIN_SCK 10 +#define PIN_SIN 16 +#define PIN_SOUT 11 + +static inline void linkcable_slave_program_init(PIO pio, uint sm, uint offset) { + pio_sm_config c = linkcable_slave_program_get_default_config(offset); + + pio_sm_set_consecutive_pindirs(pio, sm, PIN_SCK, 1, false); + + 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); +} +%} \ No newline at end of file diff --git a/src/main.c b/src/main.c index 33c7bfc..ecd50fb 100644 --- a/src/main.c +++ b/src/main.c @@ -17,6 +17,8 @@ #define ENABLE_LCD 1 #define ENABLE_SOUND 1 #define ENABLE_SDCARD 1 +#define ENABLE_SERIAL_MONITOR 0 +#define ENABLE_LINK_CABLE 1 #define PEANUT_GB_HIGH_LCD_ACCURACY 1 #define PEANUT_GB_USE_BIOS 0 @@ -64,6 +66,7 @@ #include "sdcard.h" #include "i2s.h" #include "gbcolors.h" +#include "linkcable.h" /* GPIO Connections. */ #define GPIO_UP 2 @@ -140,6 +143,9 @@ union core_cmd { /* Pixel data is stored in here. */ static uint8_t pixels_buffer[LCD_WIDTH]; +static struct gb_s __uninitialized_ram(gGameBoy); + + #define putstdio(x) write(1, x, strlen(x)) /* Functions required for communication with the ILI9225. */ @@ -215,7 +221,9 @@ void gb_error(struct gb_s *gb, const enum gb_error_e gb_err, const uint16_t addr "INVALID READ", "INVALID WRITE" }; +#if ENABLE_SERIAL_MONITOR printf("Error %d occurred: %s at %04X\n.\n", gb_err, gb_err_str[gb_err], addr); +#endif //ENABLE_SERIAL_MONITOR // abort(); #endif } @@ -313,7 +321,9 @@ void read_cart_ram_file(struct gb_s *gb) { sd_card_t *pSD=sd_get_by_num(0); FRESULT fr=f_mount(&pSD->fatfs,pSD->pcName,1); if (FR_OK!=fr) { +#if ENABLE_SERIAL_MONITOR printf("E f_mount error: %s (%d)\n",FRESULT_str(fr),fr); +#endif //ENABLE_SERIAL_MONITOR return; } @@ -322,16 +332,22 @@ void read_cart_ram_file(struct gb_s *gb) { if (fr==FR_OK) { f_read(&fil,ram,f_size(&fil),&br); } else { +#if ENABLE_SERIAL_MONITOR printf("E f_open(%s) error: %s (%d)\n",filename,FRESULT_str(fr),fr); +#endif //ENABLE_SERIAL_MONITOR } fr=f_close(&fil); if(fr!=FR_OK) { +#if ENABLE_SERIAL_MONITOR printf("E f_close error: %s (%d)\n", FRESULT_str(fr), fr); +#endif //ENABLE_SERIAL_MONITOR } f_unmount(pSD->pcName); } +#if ENABLE_SERIAL_MONITOR printf("I read_cart_ram_file(%s) COMPLETE (%lu bytes)\n",filename,save_size); +#endif //ENABLE_SERIAL_MONITOR } /** @@ -348,7 +364,9 @@ void write_cart_ram_file(struct gb_s *gb) { sd_card_t *pSD=sd_get_by_num(0); FRESULT fr=f_mount(&pSD->fatfs,pSD->pcName,1); if (FR_OK!=fr) { +#if ENABLE_SERIAL_MONITOR printf("E f_mount error: %s (%d)\n",FRESULT_str(fr),fr); +#endif //ENABLE_SERIAL_MONITOR return; } @@ -357,16 +375,22 @@ void write_cart_ram_file(struct gb_s *gb) { if (fr==FR_OK) { f_write(&fil,ram,save_size,&bw); } else { +#if ENABLE_SERIAL_MONITOR printf("E f_open(%s) error: %s (%d)\n",filename,FRESULT_str(fr),fr); +#endif //ENABLE_SERIAL_MONITOR } fr=f_close(&fil); if(fr!=FR_OK) { +#if ENABLE_SERIAL_MONITOR printf("E f_close error: %s (%d)\n", FRESULT_str(fr), fr); +#endif //ENABLE_SERIAL_MONITOR } f_unmount(pSD->pcName); } +#if ENABLE_SERIAL_MONITOR printf("I write_cart_ram_file(%s) COMPLETE (%lu bytes)\n",filename,save_size); +#endif //ENABLE_SERIAL_MONITOR } /** @@ -379,7 +403,9 @@ void load_cart_rom_file(char *filename) { sd_card_t *pSD=sd_get_by_num(0); FRESULT fr=f_mount(&pSD->fatfs,pSD->pcName,1); if (FR_OK!=fr) { +#if ENABLE_SERIAL_MONITOR printf("E f_mount error: %s (%d)\n",FRESULT_str(fr),fr); +#endif //ENABLE_SERIAL_MONITOR return; } FIL fil; @@ -390,13 +416,19 @@ void load_cart_rom_file(char *filename) { f_read(&fil,buffer,sizeof buffer,&br); if(br==0) break; /* end of file */ +#if ENABLE_SERIAL_MONITOR printf("I Erasing target region...\n"); +#endif //ENABLE_SERIAL_MONITOR flash_range_erase(flash_target_offset,FLASH_SECTOR_SIZE); +#if ENABLE_SERIAL_MONITOR printf("I Programming target region...\n"); +#endif //ENABLE_SERIAL_MONITOR flash_range_program(flash_target_offset,buffer,FLASH_SECTOR_SIZE); /* Read back target region and check programming */ +#if ENABLE_SERIAL_MONITOR printf("I Done. Reading back target region...\n"); +#endif //ENABLE_SERIAL_MONITOR for(uint32_t i=0;ipcName); +#if ENABLE_SERIAL_MONITOR printf("I load_cart_rom_file(%s) COMPLETE (%lu bytes)\n",filename,br); +#endif //ENABLE_SERIAL_MONITOR } /** @@ -435,7 +477,9 @@ uint16_t rom_file_selector_display_page(char filename[22][256],uint16_t num_page fr=f_mount(&pSD->fatfs,pSD->pcName,1); if (FR_OK!=fr) { +#if ENABLE_SERIAL_MONITOR printf("E f_mount error: %s (%d)\n",FRESULT_str(fr),fr); +#endif //ENABLE_SERIAL_MONITOR return 0; } @@ -559,9 +603,19 @@ void rom_file_selector() { #endif +#if ENABLE_LINK_CABLE +void __not_in_flash_func(linkcable_interrupt_handler)(void){ + uint8_t r = linkcable_receive(); + gGameBoy.hram_io[IO_SB] = r; + gGameBoy.hram_io[IO_SC] &= 0x7F; + gGameBoy.hram_io[IO_IF] |= SERIAL_INTR; + linkcable_isr_clear(); + if (gLinkcable_isSlave) linkcable_start(r); +} +#endif + int main(void) { - static struct gb_s gb; enum gb_init_error_e ret; /* Overclock. */ @@ -579,7 +633,13 @@ int main(void) stdio_init_all(); time_init(); // sleep_ms(5000); +#if ENABLE_SERIAL_MONITOR putstdio("INIT: "); +#endif //ENABLE_SERIAL_MONITOR + +#if ENABLE_LINK_CABLE + linkcable_init(linkcable_interrupt_handler); +#endif //ENABLE_LINK_CABLE /* Initialise GPIO pins. */ gpio_set_function(GPIO_UP, GPIO_FUNC_SIO); @@ -655,122 +715,138 @@ while(true) /* Initialise GB context. */ memcpy(rom_bank0, rom, sizeof(rom_bank0)); - ret = gb_init(&gb, &gb_rom_read, &gb_cart_ram_read, + ret = gb_init(&gGameBoy, &gb_rom_read, &gb_cart_ram_read, &gb_cart_ram_write, &gb_error, NULL); +#if ENABLE_SERIAL_MONITOR putstdio("GB "); +#endif //ENABLE_SERIAL_MONITOR if(ret != GB_INIT_NO_ERROR) { +#if ENABLE_SERIAL_MONITOR printf("Error: %d\n", ret); +#endif //ENABLE_SERIAL_MONITOR goto out; } /* Automatically assign a colour palette to the game */ char rom_title[16]; - auto_assign_palette(palette, gb_colour_hash(&gb),gb_get_rom_name(&gb,rom_title)); + auto_assign_palette(palette, gb_colour_hash(&gGameBoy),gb_get_rom_name(&gGameBoy,rom_title)); #if ENABLE_LCD - gb_init_lcd(&gb, &lcd_draw_line); + gb_init_lcd(&gGameBoy, &lcd_draw_line); /* Start Core1, which processes requests to the LCD. */ +# if ENABLE_SERIAL_MONITOR putstdio("CORE1 "); +# endif //ENABLE_SERIAL_MONITOR multicore_launch_core1(main_core1); +# if ENABLE_SERIAL_MONITOR putstdio("LCD "); +# endif //ENABLE_SERIAL_MONITOR #endif #if ENABLE_SOUND // Initialize audio emulation audio_init(); +# if ENABLE_SERIAL_MONITOR putstdio("AUDIO "); +# endif //ENABLE_SERIAL_MONITOR #endif #if ENABLE_SDCARD /* Load Save File. */ - read_cart_ram_file(&gb); + read_cart_ram_file(&gGameBoy); #endif +#if ENABLE_SERIAL_MONITOR putstdio("\n> "); +#endif //ENABLE_SERIAL_MONITOR uint_fast32_t frames = 0; uint64_t start_time = time_us_64(); while(1) { int input; - gb.gb_frame = 0; + gGameBoy.gb_frame = 0; do { - __gb_step_cpu(&gb); + __gb_step_cpu(&gGameBoy); tight_loop_contents(); - } while(HEDLEY_LIKELY(gb.gb_frame == 0)); + } while(HEDLEY_LIKELY(gGameBoy.gb_frame == 0)); frames++; #if ENABLE_SOUND - if(!gb.direct.frame_skip) { + if(!gGameBoy.direct.frame_skip) { audio_callback(NULL, stream, AUDIO_BUFFER_SIZE_BYTES); i2s_dma_write(&i2s_config, stream); } #endif /* Update buttons state */ - prev_joypad_bits.up=gb.direct.joypad_bits.up; - prev_joypad_bits.down=gb.direct.joypad_bits.down; - prev_joypad_bits.left=gb.direct.joypad_bits.left; - prev_joypad_bits.right=gb.direct.joypad_bits.right; - prev_joypad_bits.a=gb.direct.joypad_bits.a; - prev_joypad_bits.b=gb.direct.joypad_bits.b; - prev_joypad_bits.select=gb.direct.joypad_bits.select; - prev_joypad_bits.start=gb.direct.joypad_bits.start; - gb.direct.joypad_bits.up=gpio_get(GPIO_UP); - gb.direct.joypad_bits.down=gpio_get(GPIO_DOWN); - gb.direct.joypad_bits.left=gpio_get(GPIO_LEFT); - gb.direct.joypad_bits.right=gpio_get(GPIO_RIGHT); - gb.direct.joypad_bits.a=gpio_get(GPIO_A); - gb.direct.joypad_bits.b=gpio_get(GPIO_B); - gb.direct.joypad_bits.select=gpio_get(GPIO_SELECT); - gb.direct.joypad_bits.start=gpio_get(GPIO_START); + prev_joypad_bits.up=gGameBoy.direct.joypad_bits.up; + prev_joypad_bits.down=gGameBoy.direct.joypad_bits.down; + prev_joypad_bits.left=gGameBoy.direct.joypad_bits.left; + prev_joypad_bits.right=gGameBoy.direct.joypad_bits.right; + prev_joypad_bits.a=gGameBoy.direct.joypad_bits.a; + prev_joypad_bits.b=gGameBoy.direct.joypad_bits.b; + prev_joypad_bits.select=gGameBoy.direct.joypad_bits.select; + prev_joypad_bits.start=gGameBoy.direct.joypad_bits.start; + gGameBoy.direct.joypad_bits.up=gpio_get(GPIO_UP); + gGameBoy.direct.joypad_bits.down=gpio_get(GPIO_DOWN); + gGameBoy.direct.joypad_bits.left=gpio_get(GPIO_LEFT); + gGameBoy.direct.joypad_bits.right=gpio_get(GPIO_RIGHT); + gGameBoy.direct.joypad_bits.a=gpio_get(GPIO_A); + gGameBoy.direct.joypad_bits.b=gpio_get(GPIO_B); + gGameBoy.direct.joypad_bits.select=gpio_get(GPIO_SELECT); + gGameBoy.direct.joypad_bits.start=gpio_get(GPIO_START); /* hotkeys (select + * combo)*/ - if(!gb.direct.joypad_bits.select) { + if(!gGameBoy.direct.joypad_bits.select) { #if ENABLE_SOUND - if(!gb.direct.joypad_bits.up && prev_joypad_bits.up) { + if(!gGameBoy.direct.joypad_bits.up && prev_joypad_bits.up) { /* select + up: increase sound volume */ i2s_increase_volume(&i2s_config); } - if(!gb.direct.joypad_bits.down && prev_joypad_bits.down) { + if(!gGameBoy.direct.joypad_bits.down && prev_joypad_bits.down) { /* select + down: decrease sound volume */ i2s_decrease_volume(&i2s_config); } #endif - if(!gb.direct.joypad_bits.right && prev_joypad_bits.right) { + if(!gGameBoy.direct.joypad_bits.right && prev_joypad_bits.right) { /* select + right: select the next manual color palette */ if(manual_palette_selected<12) { manual_palette_selected++; manual_assign_palette(palette,manual_palette_selected); } } - if(!gb.direct.joypad_bits.left && prev_joypad_bits.left) { + if(!gGameBoy.direct.joypad_bits.left && prev_joypad_bits.left) { /* select + left: select the previous manual color palette */ if(manual_palette_selected>0) { manual_palette_selected--; manual_assign_palette(palette,manual_palette_selected); } } - if(!gb.direct.joypad_bits.start && prev_joypad_bits.start) { + if(!gGameBoy.direct.joypad_bits.start && prev_joypad_bits.start) { /* select + start: save ram and resets to the game selection menu */ + linkcable_shutdown(); #if ENABLE_SDCARD - write_cart_ram_file(&gb); + write_cart_ram_file(&gGameBoy); #endif goto out; } - if(!gb.direct.joypad_bits.a && prev_joypad_bits.a) { + if(!gGameBoy.direct.joypad_bits.a && prev_joypad_bits.a) { /* select + A: enable/disable frame-skip => fast-forward */ - gb.direct.frame_skip=!gb.direct.frame_skip; - printf("I gb.direct.frame_skip = %d\n",gb.direct.frame_skip); + gGameBoy.direct.frame_skip=!gGameBoy.direct.frame_skip; +#if ENABLE_SERIAL_MONITOR + printf("I gGameBoy.direct.frame_skip = %d\n",gGameBoy.direct.frame_skip); +#endif //ENABLE_SERIAL_MONITOR } } +#if ENABLE_SERIAL_MONITOR /* Serial monitor commands */ input = getchar_timeout_us(0); if(input == PICO_ERROR_TIMEOUT) @@ -809,11 +885,11 @@ while(true) } case 'i': - gb.direct.interlace = !gb.direct.interlace; + gGameBoy.direct.interlace = !gGameBoy.direct.interlace; break; case 'f': - gb.direct.frame_skip = !gb.direct.frame_skip; + gGameBoy.direct.frame_skip = !gGameBoy.direct.frame_skip; break; case 'b': @@ -838,50 +914,50 @@ while(true) case '\n': case '\r': { - gb.direct.joypad_bits.start = 0; + gGameBoy.direct.joypad_bits.start = 0; break; } case '\b': { - gb.direct.joypad_bits.select = 0; + gGameBoy.direct.joypad_bits.select = 0; break; } case '8': { - gb.direct.joypad_bits.up = 0; + gGameBoy.direct.joypad_bits.up = 0; break; } case '2': { - gb.direct.joypad_bits.down = 0; + gGameBoy.direct.joypad_bits.down = 0; break; } case '4': { - gb.direct.joypad_bits.left= 0; + gGameBoy.direct.joypad_bits.left= 0; break; } case '6': { - gb.direct.joypad_bits.right = 0; + gGameBoy.direct.joypad_bits.right = 0; break; } case 'z': case 'w': { - gb.direct.joypad_bits.a = 0; + gGameBoy.direct.joypad_bits.a = 0; break; } case 'x': { - gb.direct.joypad_bits.b = 0; + gGameBoy.direct.joypad_bits.b = 0; break; } @@ -891,12 +967,14 @@ while(true) default: break; } +#endif //ENABLE_SERIAL_MONITOR } out: +#if ENABLE_SERIAL_MONITOR puts("\nEmulation Ended"); +#endif //ENABLE_SERIAL_MONITOR /* stop lcd task running on core 1 */ multicore_reset_core1(); - } }