Mercurial > repos > blastem
comparison romdb.c @ 1395:efa7225e0f07
Initial work to support parallel NOR flash and the Magistr 16
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Wed, 07 Jun 2017 23:06:14 -0700 |
parents | ae3b1721b226 |
children | 71b6e2298e4a |
comparison
equal
deleted
inserted
replaced
1394:ae3b1721b226 | 1395:efa7225e0f07 |
---|---|
17 #define RAM_ID 0x1B0 | 17 #define RAM_ID 0x1B0 |
18 #define RAM_FLAGS 0x1B2 | 18 #define RAM_FLAGS 0x1B2 |
19 #define RAM_START 0x1B4 | 19 #define RAM_START 0x1B4 |
20 #define RAM_END 0x1B8 | 20 #define RAM_END 0x1B8 |
21 #define REGION_START 0x1F0 | 21 #define REGION_START 0x1F0 |
22 | |
23 char const *save_type_name(uint8_t save_type) | |
24 { | |
25 if (save_type == SAVE_I2C) { | |
26 return "EEPROM"; | |
27 } else if(save_type == SAVE_NOR) { | |
28 return "NOR Flash"; | |
29 } | |
30 return "SRAM"; | |
31 } | |
22 | 32 |
23 enum { | 33 enum { |
24 I2C_IDLE, | 34 I2C_IDLE, |
25 I2C_START, | 35 I2C_START, |
26 I2C_DEVICE_ACK, | 36 I2C_DEVICE_ACK, |
185 uint8_t get_sda(eeprom_state *state) | 195 uint8_t get_sda(eeprom_state *state) |
186 { | 196 { |
187 return state->host_sda & state->slave_sda; | 197 return state->host_sda & state->slave_sda; |
188 } | 198 } |
189 | 199 |
200 enum { | |
201 NOR_NORMAL, | |
202 NOR_PRODUCTID, | |
203 NOR_BOOTBLOCK | |
204 }; | |
205 | |
206 enum { | |
207 NOR_CMD_IDLE, | |
208 NOR_CMD_AA, | |
209 NOR_CMD_55 | |
210 }; | |
211 | |
212 //Technically this value shoudl be slightly different between NTSC and PAL | |
213 //as it's defined as 200 micro-seconds, not in clock cycles | |
214 #define NOR_WRITE_PAUSE 10690 | |
215 | |
216 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) | |
217 { | |
218 state->buffer = buffer; | |
219 state->page_buffer = malloc(page_size); | |
220 memset(state->page_buffer, 0xFF, page_size); | |
221 state->size = size; | |
222 state->page_size = page_size; | |
223 state->product_id = product_id; | |
224 state->last_write_cycle = 0xFFFFFFFF; | |
225 state->mode = NOR_NORMAL; | |
226 state->cmd_state = NOR_CMD_IDLE; | |
227 state->alt_cmd = 0; | |
228 state->bus_flags = bus_flags; | |
229 } | |
230 | |
231 void nor_run(nor_state *state, uint32_t cycle) | |
232 { | |
233 if (state->last_write_cycle == 0xFFFFFFFF) { | |
234 return; | |
235 } | |
236 if (cycle - state->last_write_cycle >= NOR_WRITE_PAUSE) { | |
237 state->last_write_cycle = 0xFFFFFFFF; | |
238 for (uint32_t i = 0; i < state->page_size; i++) { | |
239 state->buffer[state->current_page + i] = state->page_buffer[i]; | |
240 } | |
241 memset(state->page_buffer, 0xFF, state->page_size); | |
242 } | |
243 } | |
244 | |
245 uint8_t nor_flash_read_b(uint32_t address, void *vcontext) | |
246 { | |
247 m68k_context *m68k = vcontext; | |
248 genesis_context *gen = m68k->system; | |
249 nor_state *state = &gen->nor; | |
250 if ( | |
251 ((address & 1) && state->bus_flags == RAM_FLAG_EVEN) || | |
252 (!(address & 1) && state->bus_flags == RAM_FLAG_ODD) | |
253 ) { | |
254 return 0xFF; | |
255 } | |
256 if (state->bus_flags != RAM_FLAG_BOTH) { | |
257 address = address >> 1; | |
258 } | |
259 | |
260 nor_run(state, m68k->current_cycle); | |
261 switch (state->mode) | |
262 { | |
263 case NOR_NORMAL: | |
264 return state->buffer[address & (state->size-1)]; | |
265 break; | |
266 case NOR_PRODUCTID: | |
267 switch (address & (state->size - 1)) | |
268 { | |
269 case 0: | |
270 return state->product_id >> 8; | |
271 case 1: | |
272 return state->product_id; | |
273 case 2: | |
274 //TODO: Implement boot block protection | |
275 return 0xFE; | |
276 default: | |
277 return 0xFE; | |
278 } | |
279 break; | |
280 case NOR_BOOTBLOCK: | |
281 break; | |
282 } | |
283 return 0xFF; | |
284 } | |
285 | |
286 uint16_t nor_flash_read_w(uint32_t address, void *context) | |
287 { | |
288 uint16_t value = nor_flash_read_b(address, context) << 8; | |
289 value |= nor_flash_read_b(address+1, context); | |
290 return value; | |
291 } | |
292 | |
293 void nor_write_byte(nor_state *state, uint32_t address, uint8_t value, uint32_t cycle) | |
294 { | |
295 switch(state->mode) | |
296 { | |
297 case NOR_NORMAL: | |
298 if (state->last_write_cycle != 0xFFFFFFFF) { | |
299 state->current_page = address & (state->size - 1) & ~(state->page_size - 1); | |
300 } | |
301 state->page_buffer[address & (state->page_size - 1)] = value; | |
302 break; | |
303 case NOR_PRODUCTID: | |
304 break; | |
305 case NOR_BOOTBLOCK: | |
306 //TODO: Implement boot block protection | |
307 state->mode = NOR_NORMAL; | |
308 break; | |
309 } | |
310 } | |
311 | |
312 void *nor_flash_write_b(uint32_t address, void *vcontext, uint8_t value) | |
313 { | |
314 m68k_context *m68k = vcontext; | |
315 genesis_context *gen = m68k->system; | |
316 nor_state *state = &gen->nor; | |
317 if ( | |
318 ((address & 1) && state->bus_flags == RAM_FLAG_EVEN) || | |
319 (!(address & 1) && state->bus_flags == RAM_FLAG_ODD) | |
320 ) { | |
321 return vcontext; | |
322 } | |
323 if (state->bus_flags != RAM_FLAG_BOTH) { | |
324 address = address >> 1; | |
325 } | |
326 | |
327 nor_run(state, m68k->current_cycle); | |
328 switch (state->cmd_state) | |
329 { | |
330 case NOR_CMD_IDLE: | |
331 if (value == 0xAA && (address & (state->size - 1)) == 0x5555) { | |
332 state->cmd_state = NOR_CMD_AA; | |
333 } else { | |
334 nor_write_byte(state, address, value, m68k->current_cycle); | |
335 state->cmd_state = NOR_CMD_IDLE; | |
336 } | |
337 break; | |
338 case NOR_CMD_AA: | |
339 if (value == 0x55 && (address & (state->size - 1)) == 0x2AAA) { | |
340 state->cmd_state = NOR_CMD_55; | |
341 } else { | |
342 nor_write_byte(state, 0x5555, 0xAA, m68k->current_cycle); | |
343 nor_write_byte(state, address, value, m68k->current_cycle); | |
344 state->cmd_state = NOR_CMD_IDLE; | |
345 } | |
346 break; | |
347 case NOR_CMD_55: | |
348 if ((address & (state->size - 1)) == 0x5555) { | |
349 if (state->alt_cmd) { | |
350 switch(value) | |
351 { | |
352 case 0x10: | |
353 puts("UNIMPLEMENTED: NOR flash erase"); | |
354 break; | |
355 case 0x20: | |
356 puts("UNIMPLEMENTED: NOR flash disable protection"); | |
357 break; | |
358 case 0x40: | |
359 state->mode = NOR_BOOTBLOCK; | |
360 break; | |
361 case 0x60: | |
362 state->mode = NOR_PRODUCTID; | |
363 break; | |
364 } | |
365 } else { | |
366 switch(value) | |
367 { | |
368 case 0x80: | |
369 state->alt_cmd = 1; | |
370 break; | |
371 case 0x90: | |
372 state->mode = NOR_PRODUCTID; | |
373 break; | |
374 case 0xA0: | |
375 puts("UNIMPLEMENTED: NOR flash enable protection"); | |
376 break; | |
377 case 0xF0: | |
378 state->mode = NOR_NORMAL; | |
379 break; | |
380 default: | |
381 printf("Unrecognized unshifted NOR flash command %X\n", value); | |
382 } | |
383 } | |
384 } else { | |
385 nor_write_byte(state, 0x5555, 0xAA, m68k->current_cycle); | |
386 nor_write_byte(state, 0x2AAA, 0x55, m68k->current_cycle); | |
387 nor_write_byte(state, address, value, m68k->current_cycle); | |
388 } | |
389 state->cmd_state = NOR_CMD_IDLE; | |
390 break; | |
391 } | |
392 return vcontext; | |
393 } | |
394 | |
395 void *nor_flash_write_w(uint32_t address, void *vcontext, uint16_t value) | |
396 { | |
397 nor_flash_write_b(address, vcontext, value >> 8); | |
398 return nor_flash_write_b(address + 1, vcontext, value); | |
399 } | |
400 | |
190 uint16_t read_sram_w(uint32_t address, m68k_context * context) | 401 uint16_t read_sram_w(uint32_t address, m68k_context * context) |
191 { | 402 { |
192 genesis_context * gen = context->system; | 403 genesis_context * gen = context->system; |
193 address &= gen->save_ram_mask; | 404 address &= gen->save_ram_mask; |
194 switch(gen->save_type) | 405 switch(gen->save_type) |
737 state->info->eeprom_map = malloc(sizeof(eeprom_map) * state->num_els); | 948 state->info->eeprom_map = malloc(sizeof(eeprom_map) * state->num_els); |
738 memset(state->info->eeprom_map, 0, sizeof(eeprom_map) * state->num_els); | 949 memset(state->info->eeprom_map, 0, sizeof(eeprom_map) * state->num_els); |
739 } | 950 } |
740 } | 951 } |
741 | 952 |
953 void process_nor_def(char *key, map_iter_state *state) | |
954 { | |
955 if (!state->info->save_size) { | |
956 char *size = tern_find_path(state->root, "NOR\0size\0", TVAL_PTR).ptrval; | |
957 if (!size) { | |
958 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); | |
959 } | |
960 state->info->save_size = atoi(size); | |
961 if (!state->info->save_size) { | |
962 fatal_error("NOR size %s is invalid\n", size); | |
963 } | |
964 char *page_size = tern_find_path(state->root, "NOR\0page_size\0", TVAL_PTR).ptrval; | |
965 if (!page_size) { | |
966 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); | |
967 } | |
968 state->info->save_page_size = atoi(size); | |
969 if (!state->info->save_page_size) { | |
970 fatal_error("NOR page size %s is invalid\n", size); | |
971 } | |
972 char *product_id = tern_find_path(state->root, "NOR\0product_id\0", TVAL_PTR).ptrval; | |
973 if (!product_id) { | |
974 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); | |
975 } | |
976 state->info->save_product_id = strtol(product_id, NULL, 16); | |
977 char *bus = tern_find_path(state->root, "NOR\0bus\0", TVAL_PTR).ptrval; | |
978 if (!strcmp(bus, "odd")) { | |
979 state->info->save_bus = RAM_FLAG_ODD; | |
980 } else if(!strcmp(bus, "even")) { | |
981 state->info->save_bus = RAM_FLAG_EVEN; | |
982 } else { | |
983 state->info->save_bus = RAM_FLAG_BOTH; | |
984 } | |
985 state->info->save_type = SAVE_NOR; | |
986 state->info->save_buffer = malloc(state->info->save_size); | |
987 memset(state->info->save_buffer, 0xFF, state->info->save_size); | |
988 } | |
989 } | |
990 | |
742 void add_eeprom_map(tern_node *node, uint32_t start, uint32_t end, map_iter_state *state) | 991 void add_eeprom_map(tern_node *node, uint32_t start, uint32_t end, map_iter_state *state) |
743 { | 992 { |
744 eeprom_map *eep_map = state->info->eeprom_map + state->info->num_eeprom; | 993 eeprom_map *eep_map = state->info->eeprom_map + state->info->num_eeprom; |
745 eep_map->start = start; | 994 eep_map->start = start; |
746 eep_map->end = end; | 995 eep_map->end = end; |
819 } else if (!strcmp(bus, "even")) { | 1068 } else if (!strcmp(bus, "even")) { |
820 map->flags |= MMAP_ONLY_EVEN; | 1069 map->flags |= MMAP_ONLY_EVEN; |
821 } else { | 1070 } else { |
822 map->flags |= MMAP_CODE; | 1071 map->flags |= MMAP_CODE; |
823 } | 1072 } |
1073 } else if (!strcmp(dtype, "NOR")) { | |
1074 process_nor_def(key, state); | |
1075 | |
1076 map->write_16 = nor_flash_write_w; | |
1077 map->write_8 = nor_flash_write_b; | |
1078 map->read_16 = nor_flash_read_w; | |
1079 map->read_8 = nor_flash_read_b; | |
1080 map->mask = 0xFFFFFF; | |
824 } else if (!strcmp(dtype, "Sega mapper")) { | 1081 } else if (!strcmp(dtype, "Sega mapper")) { |
825 state->info->mapper_start_index = state->ptr_index++; | 1082 state->info->mapper_start_index = state->ptr_index++; |
826 state->info->map_chunks+=7; | 1083 state->info->map_chunks+=7; |
827 state->info->map = realloc(state->info->map, sizeof(memmap_chunk) * state->info->map_chunks); | 1084 state->info->map = realloc(state->info->map, sizeof(memmap_chunk) * state->info->map_chunks); |
828 memset(state->info->map + state->info->map_chunks - 7, 0, sizeof(memmap_chunk) * 7); | 1085 memset(state->info->map + state->info->map_chunks - 7, 0, sizeof(memmap_chunk) * 7); |