comparison i2c.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
comparison
equal deleted inserted replaced
1413:3d7f668dce3d 1414:d94855080529
1 #include "genesis.h"
2 #include "util.h"
3
4 enum {
5 I2C_IDLE,
6 I2C_START,
7 I2C_DEVICE_ACK,
8 I2C_ADDRESS_HI,
9 I2C_ADDRESS_HI_ACK,
10 I2C_ADDRESS,
11 I2C_ADDRESS_ACK,
12 I2C_READ,
13 I2C_READ_ACK,
14 I2C_WRITE,
15 I2C_WRITE_ACK
16 };
17
18 char * i2c_states[] = {
19 "idle",
20 "start",
21 "device ack",
22 "address hi",
23 "address hi ack",
24 "address",
25 "address ack",
26 "read",
27 "read_ack",
28 "write",
29 "write_ack"
30 };
31
32 void eeprom_init(eeprom_state *state, uint8_t *buffer, uint32_t size)
33 {
34 state->slave_sda = 1;
35 state->host_sda = state->scl = 0;
36 state->buffer = buffer;
37 state->size = size;
38 state->state = I2C_IDLE;
39 }
40
41 void set_host_sda(eeprom_state *state, uint8_t val)
42 {
43 if (state->scl) {
44 if (val & ~state->host_sda) {
45 //low to high, stop condition
46 state->state = I2C_IDLE;
47 state->slave_sda = 1;
48 } else if (~val & state->host_sda) {
49 //high to low, start condition
50 state->state = I2C_START;
51 state->slave_sda = 1;
52 state->counter = 8;
53 }
54 }
55 state->host_sda = val;
56 }
57
58 void set_scl(eeprom_state *state, uint8_t val)
59 {
60 if (val & ~state->scl) {
61 //low to high transition
62 switch (state->state)
63 {
64 case I2C_START:
65 case I2C_ADDRESS_HI:
66 case I2C_ADDRESS:
67 case I2C_WRITE:
68 state->latch = state->host_sda | state->latch << 1;
69 state->counter--;
70 if (!state->counter) {
71 switch (state->state & 0x7F)
72 {
73 case I2C_START:
74 state->state = I2C_DEVICE_ACK;
75 break;
76 case I2C_ADDRESS_HI:
77 state->address = state->latch << 8;
78 state->state = I2C_ADDRESS_HI_ACK;
79 break;
80 case I2C_ADDRESS:
81 state->address |= state->latch;
82 state->state = I2C_ADDRESS_ACK;
83 break;
84 case I2C_WRITE:
85 state->buffer[state->address] = state->latch;
86 state->state = I2C_WRITE_ACK;
87 break;
88 }
89 }
90 break;
91 case I2C_DEVICE_ACK:
92 if (state->latch & 1) {
93 state->state = I2C_READ;
94 state->counter = 8;
95 if (state->size < 256) {
96 state->address = state->latch >> 1;
97 }
98 state->latch = state->buffer[state->address];
99 } else {
100 if (state->size < 256) {
101 state->address = state->latch >> 1;
102 state->state = I2C_WRITE;
103 } else if (state->size < 4096) {
104 state->address = (state->latch & 0xE) << 7;
105 state->state = I2C_ADDRESS;
106 } else {
107 state->state = I2C_ADDRESS_HI;
108 }
109 state->counter = 8;
110 }
111 break;
112 case I2C_ADDRESS_HI_ACK:
113 state->state = I2C_ADDRESS;
114 state->counter = 8;
115 break;
116 case I2C_ADDRESS_ACK:
117 state->state = I2C_WRITE;
118 state->address &= state->size-1;
119 state->counter = 8;
120 break;
121 case I2C_READ:
122 state->counter--;
123 if (!state->counter) {
124 state->state = I2C_READ_ACK;
125 }
126 break;
127 case I2C_READ_ACK:
128 state->state = I2C_READ;
129 state->counter = 8;
130 state->address++;
131 //TODO: page mask
132 state->address &= state->size-1;
133 state->latch = state->buffer[state->address];
134 break;
135 case I2C_WRITE_ACK:
136 state->state = I2C_WRITE;
137 state->counter = 8;
138 state->address++;
139 //TODO: page mask
140 state->address &= state->size-1;
141 break;
142 }
143 } else if (~val & state->scl) {
144 //high to low transition
145 switch (state->state & 0x7F)
146 {
147 case I2C_DEVICE_ACK:
148 case I2C_ADDRESS_HI_ACK:
149 case I2C_ADDRESS_ACK:
150 case I2C_READ_ACK:
151 case I2C_WRITE_ACK:
152 state->slave_sda = 0;
153 break;
154 case I2C_READ:
155 state->slave_sda = state->latch >> 7;
156 state->latch = state->latch << 1;
157 break;
158 default:
159 state->slave_sda = 1;
160 break;
161 }
162 }
163 state->scl = val;
164 }
165
166 uint8_t get_sda(eeprom_state *state)
167 {
168 return state->host_sda & state->slave_sda;
169 }
170
171 eeprom_map *find_eeprom_map(uint32_t address, genesis_context *gen)
172 {
173 for (int i = 0; i < gen->num_eeprom; i++)
174 {
175 if (address >= gen->eeprom_map[i].start && address <= gen->eeprom_map[i].end) {
176 return gen->eeprom_map + i;
177 }
178 }
179 return NULL;
180 }
181
182 void * write_eeprom_i2c_w(uint32_t address, void * context, uint16_t value)
183 {
184 genesis_context *gen = ((m68k_context *)context)->system;
185 eeprom_map *map = find_eeprom_map(address, gen);
186 if (!map) {
187 fatal_error("Could not find EEPROM map for address %X\n", address);
188 }
189 if (map->scl_mask) {
190 set_scl(&gen->eeprom, (value & map->scl_mask) != 0);
191 }
192 if (map->sda_write_mask) {
193 set_host_sda(&gen->eeprom, (value & map->sda_write_mask) != 0);
194 }
195 return context;
196 }
197
198 void * write_eeprom_i2c_b(uint32_t address, void * context, uint8_t value)
199 {
200 genesis_context *gen = ((m68k_context *)context)->system;
201 eeprom_map *map = find_eeprom_map(address, gen);
202 if (!map) {
203 fatal_error("Could not find EEPROM map for address %X\n", address);
204 }
205
206 uint16_t expanded, mask;
207 if (address & 1) {
208 expanded = value;
209 mask = 0xFF;
210 } else {
211 expanded = value << 8;
212 mask = 0xFF00;
213 }
214 if (map->scl_mask & mask) {
215 set_scl(&gen->eeprom, (expanded & map->scl_mask) != 0);
216 }
217 if (map->sda_write_mask & mask) {
218 set_host_sda(&gen->eeprom, (expanded & map->sda_write_mask) != 0);
219 }
220 return context;
221 }
222
223 uint16_t read_eeprom_i2c_w(uint32_t address, void * context)
224 {
225 genesis_context *gen = ((m68k_context *)context)->system;
226 eeprom_map *map = find_eeprom_map(address, gen);
227 if (!map) {
228 fatal_error("Could not find EEPROM map for address %X\n", address);
229 }
230 uint16_t ret = 0;
231 if (map->sda_read_bit < 16) {
232 ret = get_sda(&gen->eeprom) << map->sda_read_bit;
233 }
234 return ret;
235 }
236
237 uint8_t read_eeprom_i2c_b(uint32_t address, void * context)
238 {
239 genesis_context *gen = ((m68k_context *)context)->system;
240 eeprom_map *map = find_eeprom_map(address, gen);
241 if (!map) {
242 fatal_error("Could not find EEPROM map for address %X\n", address);
243 }
244 uint8_t bit = address & 1 ? map->sda_read_bit : map->sda_read_bit - 8;
245 uint8_t ret = 0;
246 if (bit < 8) {
247 ret = get_sda(&gen->eeprom) << bit;
248 }
249 return ret;
250 }