comparison nor.c @ 1414:d94855080529

Move I2C EEPROM and NOR Flash functions out of romdb.c into new files
author Michael Pavone <pavone@retrodev.com>
date Fri, 23 Jun 2017 21:48:38 -0700
parents
children 1f745318f10a
comparison
equal deleted inserted replaced
1413:3d7f668dce3d 1414:d94855080529
1 #include "genesis.h"
2 #include <stdlib.h>
3 #include <string.h>
4
5 enum {
6 NOR_NORMAL,
7 NOR_PRODUCTID,
8 NOR_BOOTBLOCK
9 };
10
11 enum {
12 NOR_CMD_IDLE,
13 NOR_CMD_AA,
14 NOR_CMD_55
15 };
16
17 //Technically this value shoudl be slightly different between NTSC and PAL
18 //as it's defined as 200 micro-seconds, not in clock cycles
19 #define NOR_WRITE_PAUSE 10690
20
21 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)
22 {
23 state->buffer = buffer;
24 state->page_buffer = malloc(page_size);
25 memset(state->page_buffer, 0xFF, page_size);
26 state->size = size;
27 state->page_size = page_size;
28 state->product_id = product_id;
29 state->last_write_cycle = 0xFFFFFFFF;
30 state->mode = NOR_NORMAL;
31 state->cmd_state = NOR_CMD_IDLE;
32 state->alt_cmd = 0;
33 state->bus_flags = bus_flags;
34 }
35
36 void nor_run(nor_state *state, uint32_t cycle)
37 {
38 if (state->last_write_cycle == 0xFFFFFFFF) {
39 return;
40 }
41 if (cycle - state->last_write_cycle >= NOR_WRITE_PAUSE) {
42 state->last_write_cycle = 0xFFFFFFFF;
43 for (uint32_t i = 0; i < state->page_size; i++) {
44 state->buffer[state->current_page + i] = state->page_buffer[i];
45 }
46 memset(state->page_buffer, 0xFF, state->page_size);
47 }
48 }
49
50 uint8_t nor_flash_read_b(uint32_t address, void *vcontext)
51 {
52 m68k_context *m68k = vcontext;
53 genesis_context *gen = m68k->system;
54 nor_state *state = &gen->nor;
55 if (
56 ((address & 1) && state->bus_flags == RAM_FLAG_EVEN) ||
57 (!(address & 1) && state->bus_flags == RAM_FLAG_ODD)
58 ) {
59 return 0xFF;
60 }
61 if (state->bus_flags != RAM_FLAG_BOTH) {
62 address = address >> 1;
63 }
64
65 nor_run(state, m68k->current_cycle);
66 switch (state->mode)
67 {
68 case NOR_NORMAL:
69 return state->buffer[address & (state->size-1)];
70 break;
71 case NOR_PRODUCTID:
72 switch (address & (state->size - 1))
73 {
74 case 0:
75 return state->product_id >> 8;
76 case 1:
77 return state->product_id;
78 case 2:
79 //TODO: Implement boot block protection
80 return 0xFE;
81 default:
82 return 0xFE;
83 }
84 break;
85 case NOR_BOOTBLOCK:
86 break;
87 }
88 return 0xFF;
89 }
90
91 uint16_t nor_flash_read_w(uint32_t address, void *context)
92 {
93 uint16_t value = nor_flash_read_b(address, context) << 8;
94 value |= nor_flash_read_b(address+1, context);
95 return value;
96 }
97
98 void nor_write_byte(nor_state *state, uint32_t address, uint8_t value, uint32_t cycle)
99 {
100 switch(state->mode)
101 {
102 case NOR_NORMAL:
103 if (state->last_write_cycle != 0xFFFFFFFF) {
104 state->current_page = address & (state->size - 1) & ~(state->page_size - 1);
105 }
106 state->page_buffer[address & (state->page_size - 1)] = value;
107 break;
108 case NOR_PRODUCTID:
109 break;
110 case NOR_BOOTBLOCK:
111 //TODO: Implement boot block protection
112 state->mode = NOR_NORMAL;
113 break;
114 }
115 }
116
117 void *nor_flash_write_b(uint32_t address, void *vcontext, uint8_t value)
118 {
119 m68k_context *m68k = vcontext;
120 genesis_context *gen = m68k->system;
121 nor_state *state = &gen->nor;
122 if (
123 ((address & 1) && state->bus_flags == RAM_FLAG_EVEN) ||
124 (!(address & 1) && state->bus_flags == RAM_FLAG_ODD)
125 ) {
126 return vcontext;
127 }
128 if (state->bus_flags != RAM_FLAG_BOTH) {
129 address = address >> 1;
130 }
131
132 nor_run(state, m68k->current_cycle);
133 switch (state->cmd_state)
134 {
135 case NOR_CMD_IDLE:
136 if (value == 0xAA && (address & (state->size - 1)) == 0x5555) {
137 state->cmd_state = NOR_CMD_AA;
138 } else {
139 nor_write_byte(state, address, value, m68k->current_cycle);
140 state->cmd_state = NOR_CMD_IDLE;
141 }
142 break;
143 case NOR_CMD_AA:
144 if (value == 0x55 && (address & (state->size - 1)) == 0x2AAA) {
145 state->cmd_state = NOR_CMD_55;
146 } else {
147 nor_write_byte(state, 0x5555, 0xAA, m68k->current_cycle);
148 nor_write_byte(state, address, value, m68k->current_cycle);
149 state->cmd_state = NOR_CMD_IDLE;
150 }
151 break;
152 case NOR_CMD_55:
153 if ((address & (state->size - 1)) == 0x5555) {
154 if (state->alt_cmd) {
155 switch(value)
156 {
157 case 0x10:
158 puts("UNIMPLEMENTED: NOR flash erase");
159 break;
160 case 0x20:
161 puts("UNIMPLEMENTED: NOR flash disable protection");
162 break;
163 case 0x40:
164 state->mode = NOR_BOOTBLOCK;
165 break;
166 case 0x60:
167 state->mode = NOR_PRODUCTID;
168 break;
169 }
170 } else {
171 switch(value)
172 {
173 case 0x80:
174 state->alt_cmd = 1;
175 break;
176 case 0x90:
177 state->mode = NOR_PRODUCTID;
178 break;
179 case 0xA0:
180 puts("UNIMPLEMENTED: NOR flash enable protection");
181 break;
182 case 0xF0:
183 state->mode = NOR_NORMAL;
184 break;
185 default:
186 printf("Unrecognized unshifted NOR flash command %X\n", value);
187 }
188 }
189 } else {
190 nor_write_byte(state, 0x5555, 0xAA, m68k->current_cycle);
191 nor_write_byte(state, 0x2AAA, 0x55, m68k->current_cycle);
192 nor_write_byte(state, address, value, m68k->current_cycle);
193 }
194 state->cmd_state = NOR_CMD_IDLE;
195 break;
196 }
197 return vcontext;
198 }
199
200 void *nor_flash_write_w(uint32_t address, void *vcontext, uint16_t value)
201 {
202 nor_flash_write_b(address, vcontext, value >> 8);
203 return nor_flash_write_b(address + 1, vcontext, value);
204 }