diff --git a/Makefile b/Makefile index 39a860d..cb91c21 100644 --- a/Makefile +++ b/Makefile @@ -10,11 +10,13 @@ OBJCOPY := $(PREFIX)objcopy COMPRESSION_RATIO ?= 3 -# BOARD can be "sd" or "lite" +# BOARD can be "sd" or "lite" or "chis" BOARD ?= sd ifeq ($(BOARD),lite) - GLOBAL_DEFINES ?= -DSUPERCARD_LITE_IO + GLOBAL_DEFINES ?= -DSUPERCARD_LITE_IO -DSUPERCARD_LITE_READ -DSUPERCARD_LITE_ADDR_SORT +else ifeq ($(BOARD),chis) + GLOBAL_DEFINES ?= -DSUPERCHIS -DSUPERCARD_LITE_READ -DSUPERCARD_LITE_ADDR_SORT -DBUNDLE_GBC_EMULATOR -DWRITE_BUF_SIZE=512 -DSECTOR_SIZE=0x20000 else ifeq ($(BOARD),sd) GLOBAL_DEFINES ?= -DBUNDLE_GBC_EMULATOR else diff --git a/rom_boot.S b/rom_boot.S index 4673418..d92bb48 100644 --- a/rom_boot.S +++ b/rom_boot.S @@ -183,13 +183,13 @@ main: @ Figure out whether this payload is running on FW flash or on SDRAM. @ Place the mode (0x4 for flash or 0x5 for sdram) in r12 mov r0, $GAMEPAK_BASEADDR - mov r1, $63 + mov r1, $7 @ Check 8 blocks total (32MB address space = 8 * 4MB) mov r12, $0x4 @ Assume booting from flash ldmia r0, {r4-r7} 1: - add r0, $(512*1024) - ldmia r0, {r8-r11} @ Compare the first 16 bytes of each 512KB block. + add r0, $(4*1024*1024) + ldmia r0, {r8-r11} @ Compare the first 16 bytes of each 4MB block. cmp r4, r8 cmpeq r5, r9 cmpeq r6, r10 diff --git a/src/flash.c b/src/flash.c index ff223fd..a39abe7 100644 --- a/src/flash.c +++ b/src/flash.c @@ -66,7 +66,7 @@ // Given a desired flash address, it generates the gamepak address necessary // to access it, taking into consideration the address permutation described. -#ifndef SUPERCARD_LITE_IO +#ifndef SUPERCARD_LITE_ADDR_SORT static uint32_t addr_perm(uint32_t addr) { return (addr & 0xFFFFFE02) | ((addr & 0x001) << 7) | @@ -116,6 +116,7 @@ uint32_t flash_identify() { return ret; } +#ifndef SUPERCHIS // Performs a flash full-chip erase. bool flash_erase() { FLASH_WE_MODE(); @@ -190,6 +191,127 @@ bool flash_program(const uint8_t *buf, unsigned size) { return true; } +#else +// Performs a flash sector erase for first 4MByte + +void flash_erase_sector(uint32_t sa) { + SLOT2_BASE_U16[addr_perm(sa/2)] = 0xF0; + SLOT2_BASE_U16[addr_perm(0xAAA/2)] = 0xAA; + SLOT2_BASE_U16[addr_perm(0x555/2)] = 0x55; + SLOT2_BASE_U16[addr_perm(0xAAA/2)] = 0x80; + SLOT2_BASE_U16[addr_perm(0xAAA/2)] = 0xAA; + SLOT2_BASE_U16[addr_perm(0x555/2)] = 0x55; + SLOT2_BASE_U16[addr_perm(sa/2)] = 0x30; +} + +bool flash_polling_wait(uint32_t addr, uint16_t expected_data) +{ + while (1) { + uint16_t status1 = SLOT2_BASE_U16[addr_perm(addr/2)]; + // Check Erase + if ((status1 & 0x80) == (expected_data & 0x80)) { + // DQ7 = 1 + uint16_t status2 = SLOT2_BASE_U16[addr_perm(addr/2)]; + if ((status2 & 0x80) == (expected_data & 0x80)) { + break; + } + } + // Check Timeout + if (status1 & 0x20) { + // Timeout Check DQ7 + uint16_t status2 = SLOT2_BASE_U16[addr_perm(addr/2)]; + if ((status2 & 0x80) == (expected_data & 0x80)) { + break; + } else { + SLOT2_BASE_U16[addr_perm(0)] = 0xF0; + return false; + } + } + __asm("nop"); + } + SLOT2_BASE_U16[addr_perm(0)] = 0xF0; + return true; +} + +static bool is_pre_erased = false; +bool flash_program_auto(uint32_t address, const uint8_t *buffer, unsigned buffer_size, bool skip_erase, bool pre_erase) { + if (address == 0 || pre_erase == false) { + is_pre_erased = false; + } + uint32_t c = 0; + while (c < buffer_size) { + uint32_t pa = address + c; + uint8_t tmp[WRITE_BUF_SIZE]; + set_supercard_mode(MAPPED_SDRAM, true, true); + memcpy(tmp, &buffer[pa], WRITE_BUF_SIZE); + FLASH_WE_MODE(); + // Reset any previous command that might be ongoing. + for (unsigned i = 0; i < 32; i++) + SLOT2_BASE_U16[0] = 0x00F0; + // is sector boundary + if (!skip_erase && (pa % SECTOR_SIZE) == 0) { + if (is_pre_erased) { + if (!flash_polling_wait(pa, 0xFF)) { + is_pre_erased = false; + set_supercard_mode(MAPPED_SDRAM, true, true); + return false; + } + is_pre_erased = false; + } else { + flash_erase_sector(pa); + if (!flash_polling_wait(pa, 0xFF)) { + set_supercard_mode(MAPPED_SDRAM, true, true); + return false; + } + } + } + + SLOT2_BASE_U16[addr_perm(0xAAA/2)] = 0xAA; + SLOT2_BASE_U16[addr_perm(0x555/2)] = 0x55; + SLOT2_BASE_U16[addr_perm(pa/2)] = 0x25; + SLOT2_BASE_U16[addr_perm(pa/2)] = (WRITE_BUF_SIZE>>1)-1; + for (uint32_t i=0; i