Mercurial > repos > blastem
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 } |