# HG changeset patch # User Michael Pavone # Date 1496901974 25200 # Node ID efa7225e0f07a65b9d02a87c6b6fe599ad55677f # Parent ae3b1721b22615ad985f5f1b6ab29e5c1a3abb53 Initial work to support parallel NOR flash and the Magistr 16 diff -r ae3b1721b226 -r efa7225e0f07 blastem.c --- a/blastem.c Mon Jun 05 23:03:46 2017 -0700 +++ b/blastem.c Wed Jun 07 23:06:14 2017 -0700 @@ -154,7 +154,7 @@ if (!ensure_dir_exists(save_dir)) { warning("Failed to create save directory %s\n", save_dir); } - char const *parts[] = {save_dir, PATH_SEP, info->save_type == SAVE_I2C ? "save.eeprom" : "save.sram"}; + char const *parts[] = {save_dir, PATH_SEP, info->save_type == SAVE_I2C ? "save.eeprom" : info->save_type == SAVE_NOR ? "save.nor" : "save.sram"}; free(save_filename); save_filename = alloc_concat_m(3, parts); //TODO: make quick save filename dependent on system type diff -r ae3b1721b226 -r efa7225e0f07 genesis.c --- a/genesis.c Mon Jun 05 23:03:46 2017 -0700 +++ b/genesis.c Wed Jun 07 23:06:14 2017 -0700 @@ -967,12 +967,12 @@ } FILE * f = fopen(save_filename, "wb"); if (!f) { - fprintf(stderr, "Failed to open %s file %s for writing\n", gen->save_type == SAVE_I2C ? "EEPROM" : "SRAM", save_filename); + fprintf(stderr, "Failed to open %s file %s for writing\n", save_type_name(gen->save_type), save_filename); return; } fwrite(gen->save_storage, 1, gen->save_size, f); fclose(f); - printf("Saved %s to %s\n", gen->save_type == SAVE_I2C ? "EEPROM" : "SRAM", save_filename); + printf("Saved %s to %s\n", save_type_name(gen->save_type), save_filename); } static void load_save(system_header *system) @@ -983,7 +983,7 @@ uint32_t read = fread(gen->save_storage, 1, gen->save_size, f); fclose(f); if (read > 0) { - printf("Loaded %s from %s\n", gen->save_type == SAVE_I2C ? "EEPROM" : "SRAM", save_filename); + printf("Loaded %s from %s\n", save_type_name(gen->save_type), save_filename); } } } @@ -1115,6 +1115,8 @@ gen->num_eeprom = rom->num_eeprom; if (gen->save_type == SAVE_I2C) { eeprom_init(&gen->eeprom, gen->save_storage, gen->save_size); + } else if (gen->save_type == SAVE_NOR) { + nor_flash_init(&gen->nor, gen->save_storage, gen->save_size, rom->save_page_size, rom->save_product_id, rom->save_bus); } } else { gen->save_storage = NULL; diff -r ae3b1721b226 -r efa7225e0f07 genesis.h --- a/genesis.h Mon Jun 05 23:03:46 2017 -0700 +++ b/genesis.h Wed Jun 07 23:06:14 2017 -0700 @@ -50,6 +50,7 @@ uint8_t bus_busy; uint8_t reset_requested; eeprom_state eeprom; + nor_state nor; }; #define RAM_WORDS 32 * 1024 diff -r ae3b1721b226 -r efa7225e0f07 rom.db --- a/rom.db Mon Jun 05 23:03:46 2017 -0700 +++ b/rom.db Wed Jun 07 23:06:14 2017 -0700 @@ -891,3 +891,29 @@ } mouse_mode absolute } + +6568b3a4e096159776ef8687a80d43589741fd60 { + name Magistr 16 BIOS + NOR { + size 262144 + page_size 128 + product_id DA45 + bus even + } + map { + 0 { + device ROM + last 3FFFFF + } + 400000 { + device NOR + last 7FFFFF + } + E00000 { + device RAM + size 40000 + last FFFFFF + bus both + } + } +} diff -r ae3b1721b226 -r efa7225e0f07 romdb.c --- a/romdb.c Mon Jun 05 23:03:46 2017 -0700 +++ b/romdb.c Wed Jun 07 23:06:14 2017 -0700 @@ -20,6 +20,16 @@ #define RAM_END 0x1B8 #define REGION_START 0x1F0 +char const *save_type_name(uint8_t save_type) +{ + if (save_type == SAVE_I2C) { + return "EEPROM"; + } else if(save_type == SAVE_NOR) { + return "NOR Flash"; + } + return "SRAM"; +} + enum { I2C_IDLE, I2C_START, @@ -187,6 +197,207 @@ return state->host_sda & state->slave_sda; } +enum { + NOR_NORMAL, + NOR_PRODUCTID, + NOR_BOOTBLOCK +}; + +enum { + NOR_CMD_IDLE, + NOR_CMD_AA, + NOR_CMD_55 +}; + +//Technically this value shoudl be slightly different between NTSC and PAL +//as it's defined as 200 micro-seconds, not in clock cycles +#define NOR_WRITE_PAUSE 10690 + +void nor_flash_init(nor_state *state, uint8_t *buffer, uint32_t size, uint32_t page_size, uint16_t product_id, uint8_t bus_flags) +{ + state->buffer = buffer; + state->page_buffer = malloc(page_size); + memset(state->page_buffer, 0xFF, page_size); + state->size = size; + state->page_size = page_size; + state->product_id = product_id; + state->last_write_cycle = 0xFFFFFFFF; + state->mode = NOR_NORMAL; + state->cmd_state = NOR_CMD_IDLE; + state->alt_cmd = 0; + state->bus_flags = bus_flags; +} + +void nor_run(nor_state *state, uint32_t cycle) +{ + if (state->last_write_cycle == 0xFFFFFFFF) { + return; + } + if (cycle - state->last_write_cycle >= NOR_WRITE_PAUSE) { + state->last_write_cycle = 0xFFFFFFFF; + for (uint32_t i = 0; i < state->page_size; i++) { + state->buffer[state->current_page + i] = state->page_buffer[i]; + } + memset(state->page_buffer, 0xFF, state->page_size); + } +} + +uint8_t nor_flash_read_b(uint32_t address, void *vcontext) +{ + m68k_context *m68k = vcontext; + genesis_context *gen = m68k->system; + nor_state *state = &gen->nor; + if ( + ((address & 1) && state->bus_flags == RAM_FLAG_EVEN) || + (!(address & 1) && state->bus_flags == RAM_FLAG_ODD) + ) { + return 0xFF; + } + if (state->bus_flags != RAM_FLAG_BOTH) { + address = address >> 1; + } + + nor_run(state, m68k->current_cycle); + switch (state->mode) + { + case NOR_NORMAL: + return state->buffer[address & (state->size-1)]; + break; + case NOR_PRODUCTID: + switch (address & (state->size - 1)) + { + case 0: + return state->product_id >> 8; + case 1: + return state->product_id; + case 2: + //TODO: Implement boot block protection + return 0xFE; + default: + return 0xFE; + } + break; + case NOR_BOOTBLOCK: + break; + } + return 0xFF; +} + +uint16_t nor_flash_read_w(uint32_t address, void *context) +{ + uint16_t value = nor_flash_read_b(address, context) << 8; + value |= nor_flash_read_b(address+1, context); + return value; +} + +void nor_write_byte(nor_state *state, uint32_t address, uint8_t value, uint32_t cycle) +{ + switch(state->mode) + { + case NOR_NORMAL: + if (state->last_write_cycle != 0xFFFFFFFF) { + state->current_page = address & (state->size - 1) & ~(state->page_size - 1); + } + state->page_buffer[address & (state->page_size - 1)] = value; + break; + case NOR_PRODUCTID: + break; + case NOR_BOOTBLOCK: + //TODO: Implement boot block protection + state->mode = NOR_NORMAL; + break; + } +} + +void *nor_flash_write_b(uint32_t address, void *vcontext, uint8_t value) +{ + m68k_context *m68k = vcontext; + genesis_context *gen = m68k->system; + nor_state *state = &gen->nor; + if ( + ((address & 1) && state->bus_flags == RAM_FLAG_EVEN) || + (!(address & 1) && state->bus_flags == RAM_FLAG_ODD) + ) { + return vcontext; + } + if (state->bus_flags != RAM_FLAG_BOTH) { + address = address >> 1; + } + + nor_run(state, m68k->current_cycle); + switch (state->cmd_state) + { + case NOR_CMD_IDLE: + if (value == 0xAA && (address & (state->size - 1)) == 0x5555) { + state->cmd_state = NOR_CMD_AA; + } else { + nor_write_byte(state, address, value, m68k->current_cycle); + state->cmd_state = NOR_CMD_IDLE; + } + break; + case NOR_CMD_AA: + if (value == 0x55 && (address & (state->size - 1)) == 0x2AAA) { + state->cmd_state = NOR_CMD_55; + } else { + nor_write_byte(state, 0x5555, 0xAA, m68k->current_cycle); + nor_write_byte(state, address, value, m68k->current_cycle); + state->cmd_state = NOR_CMD_IDLE; + } + break; + case NOR_CMD_55: + if ((address & (state->size - 1)) == 0x5555) { + if (state->alt_cmd) { + switch(value) + { + case 0x10: + puts("UNIMPLEMENTED: NOR flash erase"); + break; + case 0x20: + puts("UNIMPLEMENTED: NOR flash disable protection"); + break; + case 0x40: + state->mode = NOR_BOOTBLOCK; + break; + case 0x60: + state->mode = NOR_PRODUCTID; + break; + } + } else { + switch(value) + { + case 0x80: + state->alt_cmd = 1; + break; + case 0x90: + state->mode = NOR_PRODUCTID; + break; + case 0xA0: + puts("UNIMPLEMENTED: NOR flash enable protection"); + break; + case 0xF0: + state->mode = NOR_NORMAL; + break; + default: + printf("Unrecognized unshifted NOR flash command %X\n", value); + } + } + } else { + nor_write_byte(state, 0x5555, 0xAA, m68k->current_cycle); + nor_write_byte(state, 0x2AAA, 0x55, m68k->current_cycle); + nor_write_byte(state, address, value, m68k->current_cycle); + } + state->cmd_state = NOR_CMD_IDLE; + break; + } + return vcontext; +} + +void *nor_flash_write_w(uint32_t address, void *vcontext, uint16_t value) +{ + nor_flash_write_b(address, vcontext, value >> 8); + return nor_flash_write_b(address + 1, vcontext, value); +} + uint16_t read_sram_w(uint32_t address, m68k_context * context) { genesis_context * gen = context->system; @@ -739,6 +950,44 @@ } } +void process_nor_def(char *key, map_iter_state *state) +{ + if (!state->info->save_size) { + char *size = tern_find_path(state->root, "NOR\0size\0", TVAL_PTR).ptrval; + if (!size) { + fatal_error("ROM DB map entry %d with address %s has device type NOR, but the NOR size is not defined\n", state->index, key); + } + state->info->save_size = atoi(size); + if (!state->info->save_size) { + fatal_error("NOR size %s is invalid\n", size); + } + char *page_size = tern_find_path(state->root, "NOR\0page_size\0", TVAL_PTR).ptrval; + if (!page_size) { + fatal_error("ROM DB map entry %d with address %s has device type NOR, but the NOR page size is not defined\n", state->index, key); + } + state->info->save_page_size = atoi(size); + if (!state->info->save_page_size) { + fatal_error("NOR page size %s is invalid\n", size); + } + char *product_id = tern_find_path(state->root, "NOR\0product_id\0", TVAL_PTR).ptrval; + if (!product_id) { + fatal_error("ROM DB map entry %d with address %s has device type NOR, but the NOR product ID is not defined\n", state->index, key); + } + state->info->save_product_id = strtol(product_id, NULL, 16); + char *bus = tern_find_path(state->root, "NOR\0bus\0", TVAL_PTR).ptrval; + if (!strcmp(bus, "odd")) { + state->info->save_bus = RAM_FLAG_ODD; + } else if(!strcmp(bus, "even")) { + state->info->save_bus = RAM_FLAG_EVEN; + } else { + state->info->save_bus = RAM_FLAG_BOTH; + } + state->info->save_type = SAVE_NOR; + state->info->save_buffer = malloc(state->info->save_size); + memset(state->info->save_buffer, 0xFF, state->info->save_size); + } +} + void add_eeprom_map(tern_node *node, uint32_t start, uint32_t end, map_iter_state *state) { eeprom_map *eep_map = state->info->eeprom_map + state->info->num_eeprom; @@ -821,6 +1070,14 @@ } else { map->flags |= MMAP_CODE; } + } else if (!strcmp(dtype, "NOR")) { + process_nor_def(key, state); + + map->write_16 = nor_flash_write_w; + map->write_8 = nor_flash_write_b; + map->read_16 = nor_flash_read_w; + map->read_8 = nor_flash_read_b; + map->mask = 0xFFFFFF; } else if (!strcmp(dtype, "Sega mapper")) { state->info->mapper_start_index = state->ptr_index++; state->info->map_chunks+=7; diff -r ae3b1721b226 -r efa7225e0f07 romdb.h --- a/romdb.h Mon Jun 05 23:03:46 2017 -0700 +++ b/romdb.h Wed Jun 07 23:06:14 2017 -0700 @@ -10,6 +10,7 @@ #define RAM_FLAG_BOTH 0x00 #define RAM_FLAG_MASK RAM_FLAG_ODD #define SAVE_I2C 0x01 +#define SAVE_NOR 0x02 #define SAVE_NONE 0xFF #include "tern.h" @@ -34,6 +35,20 @@ uint8_t latch; } eeprom_state; +typedef struct { + uint8_t *buffer; + uint8_t *page_buffer; + uint32_t size; + uint32_t page_size; + uint32_t current_page; + uint32_t last_write_cycle; + uint16_t product_id; + uint8_t mode; + uint8_t cmd_state; + uint8_t alt_cmd; + uint8_t bus_flags; +} nor_state; + typedef struct rom_info rom_info; @@ -52,8 +67,11 @@ uint32_t map_chunks; uint32_t save_size; uint32_t save_mask; + uint32_t save_page_size; + uint16_t save_product_id; uint16_t mapper_start_index; uint8_t save_type; + uint8_t save_bus; //only used for NOR currently uint8_t regions; }; @@ -65,5 +83,7 @@ rom_info configure_rom_heuristics(uint8_t *rom, uint32_t rom_size, memmap_chunk const *base_map, uint32_t base_chunks); uint8_t translate_region_char(uint8_t c); void eeprom_init(eeprom_state *state, uint8_t *buffer, uint32_t size); +void nor_flash_init(nor_state *state, uint8_t *buffer, uint32_t size, uint32_t page_size, uint16_t product_id, uint8_t bus_flags); +char const *save_type_name(uint8_t save_type); #endif //ROMDB_H_