Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
716 | lvd | 1 | #include "std.h" |
2 | |||
3 | #include "emul.h" |
||
4 | #include "vars.h" |
||
5 | #include "memory.h" |
||
6 | #include "util.h" |
||
7 | |||
8 | // input: ports 7FFD,1FFD,DFFD,FFF7,FF77,EFF7, flags CF_TRDOS,CF_CACHEON |
||
9 | void set_banks() |
||
10 | { |
||
11 | bankw[1] = bankr[1] = RAM_BASE_M + 5*PAGE; |
||
12 | bankw[2] = bankr[2] = RAM_BASE_M + 2*PAGE; |
||
13 | |||
14 | // screen begining |
||
15 | temp.base = memory + ((comp.p7FFD & 8) ? 7*PAGE : 5*PAGE); |
||
16 | /* |
||
17 | if(conf.mem_model == MM_QUORUM) |
||
18 | temp.base = memory + (comp.p80FD & 7) * 0x2000 + 5*PAGE; |
||
19 | */ |
||
20 | |||
21 | if (temp.base_2) |
||
22 | temp.base_2 = temp.base; |
||
23 | |||
24 | // these flags will be re-calculated |
||
25 | comp.flags &= ~(CF_DOSPORTS | CF_Z80FBUS | CF_LEAVEDOSRAM | CF_LEAVEDOSADR | CF_SETDOSROM); |
||
26 | |||
27 | unsigned char *bank0, *bank3; |
||
28 | |||
29 | if (comp.flags & CF_TRDOS) |
||
30 | { |
||
31 | if(comp.p7FFD & 0x10) |
||
32 | { |
||
33 | bank0 = base_dos_rom; |
||
34 | } |
||
35 | else |
||
36 | { |
||
37 | bank0 = base_sys_rom; |
||
38 | } |
||
39 | } |
||
40 | else |
||
41 | bank0 = (comp.p7FFD & 0x10)? base_sos_rom : base_128_rom; |
||
42 | |||
43 | unsigned bank = (comp.p7FFD & 7); |
||
44 | |||
45 | switch (conf.mem_model) |
||
46 | { |
||
47 | case MM_PENTAGON: |
||
48 | if(!(comp.pEFF7 & EFF7_LOCKMEM)) |
||
49 | { |
||
50 | // 7FFD bits |
||
51 | // 210 - 128 |
||
52 | // 6210 - 256 |
||
53 | // 76210 - 512 |
||
54 | // 576210 - 1024 |
||
55 | bank |= (comp.p7FFD & 0xC0) >> 3; |
||
56 | bank |= (comp.p7FFD & 0x20); |
||
57 | } |
||
58 | |||
59 | bank3 = RAM_BASE_M + (bank & temp.ram_mask)*PAGE; |
||
60 | |||
61 | if (comp.pEFF7 & EFF7_ROCACHE) |
||
62 | bank0 = RAM_BASE_M + 0*PAGE; //Alone Coder 0.36.4 |
||
63 | break; |
||
64 | |||
65 | case MM_PROFSCORP: |
||
66 | membits[0x0100] &= ~MEMBITS_R; |
||
67 | membits[0x0104] &= ~MEMBITS_R; |
||
68 | membits[0x0108] &= ~MEMBITS_R; |
||
69 | membits[0x010C] &= ~MEMBITS_R; |
||
70 | case MM_SCORP: |
||
71 | bank += ((comp.p1FFD & 0x10) >> 1) + ((comp.p1FFD & 0xC0) >> 2); |
||
72 | bank3 = RAM_BASE_M + (bank & temp.ram_mask) * PAGE; |
||
73 | |||
74 | /* |
||
75 | // обработка памяти gmx (конфликтует со стандартным profrom) |
||
76 | // нужно сделать флаг записи в порт 7EFD, и если была хоть одна запись |
||
77 | // то обрабатывать rom по стандарту gmx |
||
78 | comp.profrom_bank = ((comp.p7EFD >> 4) & 3) & temp.profrom_mask; |
||
79 | { |
||
80 | unsigned char *base = ROM_BASE_M + (comp.profrom_bank * 64*1024); |
||
81 | base_128_rom = base + 0*PAGE; |
||
82 | base_sos_rom = base + 1*PAGE; |
||
83 | base_sys_rom = base + 2*PAGE; |
||
84 | base_dos_rom = base + 3*PAGE; |
||
85 | } |
||
86 | */ |
||
87 | |||
88 | // Доработка из книжки gmx (включение портов dos из ОЗУ, сделано немного не так как в реальной схеме) |
||
89 | if(comp.p1FFD & 4) |
||
90 | comp.flags |= CF_TRDOS; |
||
91 | if(comp.p1FFD & 2) |
||
92 | bank0 = base_sys_rom; |
||
93 | if(comp.p1FFD & 1) |
||
94 | bank0 = RAM_BASE_M + 0 * PAGE; |
||
95 | if(conf.mem_model == MM_PROFSCORP) |
||
96 | { |
||
97 | if (bank0 == base_sys_rom) |
||
98 | comp.flags |= CF_PROFROM; |
||
99 | else |
||
100 | comp.flags &= ~CF_PROFROM; |
||
101 | } |
||
102 | break; |
||
103 | |||
104 | case MM_KAY: |
||
105 | { |
||
106 | bank += ((comp.p1FFD & 0x10) >> 1) + ((comp.p1FFD & 0x80) >> 3) + ((comp.p7FFD & 0x80) >> 2); |
||
107 | bank3 = RAM_BASE_M + (bank & temp.ram_mask)*PAGE; |
||
108 | unsigned char rom1 = (comp.p1FFD >> 2) & 2; |
||
109 | if (comp.flags & CF_TRDOS) rom1 ^= 2; |
||
110 | switch (rom1+((comp.p7FFD & 0x10) >> 4)) |
||
111 | { |
||
112 | case 0: bank0 = base_128_rom; break; |
||
113 | case 1: bank0 = base_sos_rom; break; |
||
114 | case 2: bank0 = base_sys_rom; break; |
||
115 | case 3: bank0 = base_dos_rom; break; |
||
116 | default: __assume(0); |
||
117 | } |
||
118 | if (comp.p1FFD & 1) bank0 = RAM_BASE_M + 0*PAGE; |
||
119 | break; |
||
120 | } |
||
121 | |||
122 | case MM_PROFI: |
||
123 | bank += ((comp.pDFFD & 0x07) << 3); bank3 = RAM_BASE_M + (bank & temp.ram_mask)*PAGE; |
||
124 | if (comp.pDFFD & 0x08) bankr[1] = bankw[1] = bank3, bank3 = RAM_BASE_M+7*PAGE; |
||
125 | if (comp.pDFFD & 0x10) bank0 = RAM_BASE_M+0*PAGE; |
||
126 | if (comp.pDFFD & 0x20) comp.flags |= CF_DOSPORTS; |
||
127 | if (comp.pDFFD & 0x40) bankr[2] = bankw[2] = RAM_BASE_M + 6*PAGE; |
||
128 | break; |
||
129 | |||
130 | case MM_ATM450: |
||
131 | { |
||
132 | // RAM |
||
133 | // original ATM uses D2 as ROM address extension, not RAM |
||
134 | bank += ((comp.pFDFD & 0x07) << 3); |
||
135 | bank3 = RAM_BASE_M + (bank & temp.ram_mask)*PAGE; |
||
136 | if (!(comp.aFE & 0x80)) |
||
137 | { |
||
138 | bankw[1] = bankr[1] = RAM_BASE_M + 4*PAGE; |
||
139 | bank0 = RAM_BASE_M; |
||
140 | break; |
||
141 | } |
||
142 | |||
143 | // ROM |
||
144 | if (comp.p7FFD & 0x20) |
||
145 | comp.aFB &= ~0x80; |
||
146 | if ((comp.flags & CF_TRDOS) && (comp.pFDFD & 8)) |
||
147 | comp.aFB |= 0x80; // more priority, then 7FFD |
||
148 | |||
149 | if (comp.aFB & 0x80) // CPSYS signal |
||
150 | { |
||
151 | bank0 = base_sys_rom; |
||
152 | break; |
||
153 | } |
||
154 | // system rom not used on 7FFD.4=0 and DOS=1 |
||
155 | if (comp.flags & CF_TRDOS) |
||
156 | bank0 = base_dos_rom; |
||
157 | break; |
||
158 | } |
||
159 | |||
160 | case MM_ATM3: |
||
161 | if (comp.pBF & 1) // shaden |
||
162 | comp.flags |= CF_DOSPORTS; |
||
163 | |||
164 | case MM_ATM710: |
||
165 | { |
||
166 | if (!(comp.aFF77 & 0x200)) // ~cpm=0 |
||
167 | comp.flags |= CF_TRDOS; |
||
168 | |||
169 | if (!(comp.aFF77 & 0x100)) |
||
170 | { // pen=0 |
||
171 | bankr[1] = bankr[2] = bank3 = bank0 = ROM_BASE_M + PAGE * temp.rom_mask; |
||
172 | break; |
||
173 | } |
||
174 | |||
175 | unsigned i = ((comp.p7FFD & 0x10) >> 2); |
||
176 | for (unsigned bank = 0; bank < 4; bank++) |
||
177 | { |
||
178 | switch (comp.pFFF7[i+bank] & 0x300) |
||
179 | { |
||
180 | case 0x000: // RAM from 7FFD |
||
181 | bankr[bank] = bankw[bank] = RAM_BASE_M + PAGE * ((comp.p7FFD & 7) | (comp.pFFF7[i+bank] & 0xF8 & temp.ram_mask)); |
||
182 | break; |
||
183 | case 0x100: // ROM from 7FFD |
||
184 | bankr[bank] = ROM_BASE_M + PAGE*((comp.pFFF7[i+bank] & 0xFE & temp.rom_mask) + ((comp.flags & CF_TRDOS)?1:0)); |
||
185 | break; |
||
186 | case 0x200: // RAM from FFF7 |
||
187 | bankr[bank] = bankw[bank] = RAM_BASE_M + PAGE*(comp.pFFF7[i+bank] & 0xFF & temp.ram_mask); |
||
188 | break; |
||
189 | case 0x300: // ROM from FFF7 |
||
190 | bankr[bank] = ROM_BASE_M + PAGE*(comp.pFFF7[i+bank] & 0xFF & temp.rom_mask); |
||
191 | break; |
||
192 | } |
||
193 | } |
||
194 | bank0 = bankr[0]; bank3 = bankr[3]; |
||
195 | |||
196 | if(conf.mem_model == MM_ATM3 && cpu.nmi_in_progress) |
||
197 | bank0 = RAM_BASE_M + PAGE * 0xFF; |
||
198 | break; |
||
199 | } |
||
200 | |||
201 | case MM_PLUS3: |
||
202 | { |
||
203 | if(comp.p7FFD & 0x20) // paging disabled (48k mode) |
||
204 | { |
||
205 | bank3 = RAM_BASE_M + (bank & temp.ram_mask)*PAGE; |
||
206 | break; |
||
207 | } |
||
208 | |||
209 | if(!(comp.p1FFD & 1)) |
||
210 | { |
||
211 | unsigned RomBank = ((comp.p1FFD & 4) >> 1) | ((comp.p7FFD & 0x10) >> 4); |
||
212 | switch(RomBank) |
||
213 | { |
||
214 | case 0: bank0 = base_128_rom; break; |
||
215 | case 1: bank0 = base_sys_rom; break; |
||
216 | case 2: bank0 = base_dos_rom; break; |
||
217 | case 3: bank0 = base_sos_rom; break; |
||
218 | } |
||
219 | bank3 = RAM_BASE_M + (bank & temp.ram_mask)*PAGE; |
||
220 | } |
||
221 | else |
||
222 | { |
||
223 | unsigned RamPage = (comp.p1FFD >> 1) & 3; // d2,d1 |
||
224 | static const unsigned RamDecoder[4][4] = |
||
225 | { {0, 1, 2, 3}, {4, 5, 6, 7}, {4, 5, 6, 3}, {4, 7, 6, 3} }; |
||
226 | for(unsigned i = 0; i < 4; i++) |
||
227 | bankw[i] = bankr[i] = RAM_BASE_M + PAGE * RamDecoder[RamPage][i]; |
||
228 | bank0 = bankr[0]; |
||
229 | bank3 = bankr[3]; |
||
230 | } |
||
231 | break; |
||
232 | } |
||
233 | |||
234 | case MM_QUORUM: |
||
235 | { |
||
236 | if(!(comp.p00 & Q_TR_DOS)) |
||
237 | comp.flags |= CF_DOSPORTS; |
||
238 | |||
239 | if(comp.p00 & Q_B_ROM) |
||
240 | { |
||
241 | if (comp.flags & CF_TRDOS) |
||
242 | bank0 = base_dos_rom; |
||
243 | else |
||
244 | bank0 = (comp.p7FFD & 0x10) ? base_sos_rom : base_128_rom; |
||
245 | } |
||
246 | else |
||
247 | { |
||
248 | bank0 = base_sys_rom; |
||
249 | } |
||
250 | |||
251 | if(comp.p00 & Q_F_RAM) |
||
252 | { |
||
253 | unsigned bnk0 = (comp.p00 & Q_RAM_8) ? 8 : 0; |
||
254 | bank0 = RAM_BASE_M + (bnk0 & temp.ram_mask) * PAGE; |
||
255 | } |
||
256 | |||
257 | bank |= ((comp.p7FFD & 0xC0) >> 3) | (comp.p7FFD & 0x20); |
||
258 | bank3 = RAM_BASE_M + (bank & temp.ram_mask) * PAGE; |
||
259 | break; |
||
260 | } |
||
261 | |||
262 | default: bank3 = RAM_BASE_M + 0*PAGE; |
||
263 | } |
||
264 | |||
265 | bankw[0] = bankr[0] = bank0; |
||
266 | bankw[3] = bankr[3] = bank3; |
||
267 | |||
268 | if (bankr[0] >= ROM_BASE_M) bankw[0] = TRASH_M; |
||
269 | if (bankr[1] >= ROM_BASE_M) bankw[1] = TRASH_M; |
||
270 | if (bankr[2] >= ROM_BASE_M) bankw[2] = TRASH_M; |
||
271 | if (bankr[3] >= ROM_BASE_M) bankw[3] = TRASH_M; |
||
272 | |||
273 | |||
274 | unsigned char dosflags = CF_LEAVEDOSRAM; |
||
275 | if (conf.mem_model == MM_PENTAGON || conf.mem_model == MM_PROFI) |
||
276 | dosflags = CF_LEAVEDOSADR; |
||
277 | |||
278 | if (comp.flags & CF_TRDOS) |
||
279 | { |
||
280 | comp.flags |= dosflags | CF_DOSPORTS; |
||
281 | } |
||
282 | else if ((comp.p7FFD & 0x10) && conf.trdos_present) |
||
283 | { // B-48, inactive DOS, DOS present |
||
284 | // for Scorp, ATM-1/2 and KAY, TR-DOS not started on executing RAM 3Dxx |
||
285 | if (!((dosflags & CF_LEAVEDOSRAM) && bankr[0] < RAM_BASE_M+PAGE*MAX_RAM_PAGES)) |
||
286 | comp.flags |= CF_SETDOSROM; |
||
287 | } |
||
288 | |||
289 | if (comp.flags & CF_CACHEON) |
||
290 | { |
||
291 | unsigned char *cpage = CACHE_M; |
||
292 | if (conf.cache == 32 && !(comp.p7FFD & 0x10)) cpage += PAGE; |
||
293 | bankr[0] = bankw[0] = cpage; |
||
294 | // if (comp.pEFF7 & EFF7_ROCACHE) bankw[0] = TRASH_M; //Alone Coder 0.36.4 |
||
295 | } |
||
296 | |||
297 | if ((comp.flags & CF_DOSPORTS)? conf.floatdos : conf.floatbus) |
||
298 | comp.flags |= CF_Z80FBUS; |
||
299 | |||
300 | if (temp.led.osw && (trace_rom | trace_ram)) |
||
301 | { |
||
302 | for (unsigned i = 0; i < 4; i++) { |
||
303 | unsigned bank = (bankr[i] - RAM_BASE_M) / PAGE; |
||
304 | if (bank < MAX_PAGES) used_banks[bank] = 1; |
||
305 | } |
||
306 | } |
||
307 | |||
308 | /* |
||
309 | if ((unsigned)(bankr[0] - ROM_BASE_M) < PAGE*MAX_ROM_PAGES) |
||
310 | { |
||
311 | printf("ROM%2X\n", (bankr[0] - ROM_BASE_M)/PAGE); |
||
312 | printf("DOS=%p\n", base_dos_rom); |
||
313 | printf("SVM=%p\n", base_sys_rom); |
||
314 | printf("SOS=%p\n", base_sos_rom); |
||
315 | printf("128=%p\n", base_128_rom); |
||
316 | } |
||
317 | */ |
||
318 | } |
||
319 | |||
320 | void set_scorp_profrom(unsigned read_address) |
||
321 | { |
||
322 | static unsigned char switch_table[] = |
||
323 | { |
||
324 | 0,1,2,3, |
||
325 | 3,3,3,2, |
||
326 | 2,2,0,1, |
||
327 | 1,0,1,0 |
||
328 | }; |
||
329 | comp.profrom_bank = switch_table[read_address*4 + comp.profrom_bank] & temp.profrom_mask; |
||
330 | unsigned char *base = ROM_BASE_M + (comp.profrom_bank * 64*1024); |
||
331 | base_128_rom = base + 0*PAGE; |
||
332 | base_sos_rom = base + 1*PAGE; |
||
333 | base_sys_rom = base + 2*PAGE; |
||
334 | base_dos_rom = base + 3*PAGE; |
||
335 | set_banks(); |
||
336 | } |
||
337 | |||
338 | /* |
||
339 | u8 *__fastcall MemDbg(u32 addr) |
||
340 | { |
||
341 | return am_r(addr); |
||
342 | } |
||
343 | |||
344 | void __fastcall wmdbg(u32 addr, u8 val) |
||
345 | { |
||
346 | *am_r(addr) = val; |
||
347 | } |
||
348 | |||
349 | u8 __fastcall rmdbg(u32 addr) |
||
350 | { |
||
351 | return *am_r(addr); |
||
352 | } |
||
353 | */ |
||
354 | |||
355 | void set_mode(ROM_MODE mode) |
||
356 | { |
||
357 | if (mode == RM_NOCHANGE) |
||
358 | return; |
||
359 | |||
360 | if (mode == RM_CACHE) |
||
361 | { |
||
362 | comp.flags |= CF_CACHEON; |
||
363 | set_banks(); |
||
364 | return; |
||
365 | } |
||
366 | |||
367 | // no RAM/cache/SERVICE |
||
368 | comp.p1FFD &= ~7; |
||
369 | comp.pDFFD &= ~0x10; |
||
370 | comp.flags &= ~CF_CACHEON; |
||
371 | |||
372 | // comp.aFF77 |= 0x100; // enable ATM memory |
||
373 | |||
374 | switch (mode) |
||
375 | { |
||
376 | case RM_128: |
||
377 | comp.flags &= ~CF_TRDOS; |
||
378 | comp.p7FFD &= ~0x10; |
||
379 | break; |
||
380 | case RM_SOS: |
||
381 | comp.flags &= ~CF_TRDOS; |
||
382 | comp.p7FFD |= 0x10; |
||
383 | |||
384 | if(conf.mem_model == MM_PLUS3) // disable paging |
||
385 | comp.p7FFD |= 0x20; |
||
386 | break; |
||
387 | case RM_SYS: |
||
388 | comp.flags |= CF_TRDOS; |
||
389 | comp.p7FFD &= ~0x10; |
||
390 | break; |
||
391 | case RM_DOS: |
||
392 | comp.flags |= CF_TRDOS; |
||
393 | comp.p7FFD |= 0x10; |
||
394 | if(conf.mem_model == MM_ATM710 || conf.mem_model == MM_ATM3) |
||
395 | comp.p7FFD &= ~0x10; |
||
396 | break; |
||
397 | } |
||
398 | set_banks(); |
||
399 | } |
||
400 | |||
401 | unsigned char cmosBCD(unsigned char binary) |
||
402 | { |
||
403 | if (!(cmos[11] & 4)) binary = (binary % 10) + 0x10*((binary/10)%10); |
||
404 | return binary; |
||
405 | } |
||
406 | |||
407 | unsigned char cmos_read() |
||
408 | { |
||
409 | static SYSTEMTIME st; |
||
410 | static bool UF = false; |
||
411 | static unsigned Seconds = 0; |
||
412 | static unsigned long long last_tsc = 0ULL; |
||
413 | unsigned char reg = comp.cmos_addr; |
||
414 | unsigned char rv; |
||
415 | if (conf.cmos == 2) |
||
416 | reg &= 0x3F; |
||
417 | |||
418 | if ((1 << reg) & ((1<<0)|(1<<2)|(1<<4)|(1<<6)|(1<<7)|(1<<8)|(1<<9)|(1<<12))) |
||
419 | { |
||
420 | unsigned long long tsc = rdtsc(); |
||
421 | // [vv] Часы читаются не чаще двух раз в секунду |
||
422 | if ((tsc-last_tsc) >= 25 * temp.ticks_frame) |
||
423 | { |
||
424 | GetLocalTime(&st); |
||
425 | if(st.wSecond != Seconds) |
||
426 | { |
||
427 | UF = true; |
||
428 | Seconds = st.wSecond; |
||
429 | } |
||
430 | } |
||
431 | } |
||
432 | |||
433 | switch (reg) |
||
434 | { |
||
435 | case 0: return cmosBCD((BYTE)st.wSecond); |
||
436 | case 2: return cmosBCD((BYTE)st.wMinute); |
||
437 | case 4: return cmosBCD((BYTE)st.wHour); |
||
438 | case 6: return 1+(((BYTE)st.wDayOfWeek+8-conf.cmos) % 7); |
||
439 | case 7: return cmosBCD((BYTE)st.wDay); |
||
440 | case 8: return cmosBCD((BYTE)st.wMonth); |
||
441 | case 9: return cmosBCD(st.wYear % 100); |
||
442 | case 10: return 0x20 | (cmos [10] & 0xF); // molodcov_alex |
||
443 | case 11: return (cmos[11] & 4) | 2; |
||
444 | case 12: // [vv] UF |
||
445 | rv = UF ? 0x10 : 0; |
||
446 | UF = false; |
||
447 | return rv; |
||
448 | case 13: return 0x80; |
||
449 | } |
||
450 | return cmos[reg]; |
||
451 | } |
||
452 | |||
453 | void cmos_write(unsigned char val) |
||
454 | { |
||
455 | if (conf.cmos == 2) comp.cmos_addr &= 0x3F; |
||
456 | cmos[comp.cmos_addr] = val; |
||
457 | } |
||
458 | |||
459 | void NVRAM::write(unsigned char val) |
||
460 | { |
||
461 | const int SCL = 0x40, SDA = 0x10, WP = 0x20, |
||
462 | SDA_1 = 0xFF, SDA_0 = 0xBF, |
||
463 | SDA_SHIFT_IN = 4; |
||
464 | |||
465 | if ((val ^ prev) & SCL) // clock edge, data in/out |
||
466 | { |
||
467 | if (val & SCL) // nvram reads SDA |
||
468 | { |
||
469 | if (state == RD_ACK) |
||
470 | { |
||
471 | if (val & SDA) goto idle; // no ACK, stop |
||
472 | // move next byte to host |
||
473 | state = SEND_DATA; |
||
474 | dataout = nvram[address]; |
||
475 | address = (address+1) & 0x7FF; |
||
476 | bitsout = 0; goto exit; // out_z==1; |
||
477 | } |
||
478 | |||
479 | if ((1<<state) & ((1<<RCV_ADDR)|(1<<RCV_CMD)|(1<<RCV_DATA))) { |
||
480 | if (out_z) // skip nvram ACK before reading |
||
481 | datain = 2*datain + ((val >> SDA_SHIFT_IN) & 1), bitsin++; |
||
482 | } |
||
483 | |||
484 | } else { // nvram sets SDA |
||
485 | |||
486 | if (bitsin == 8) // byte received |
||
487 | { |
||
488 | bitsin = 0; |
||
489 | if (state == RCV_CMD) { |
||
490 | if ((datain & 0xF0) != 0xA0) goto idle; |
||
491 | address = (address & 0xFF) + ((datain << 7) & 0x700); |
||
492 | if (datain & 1) { // read from current address |
||
493 | dataout = nvram[address]; |
||
494 | address = (address+1) & 0x7FF; |
||
495 | bitsout = 0; |
||
496 | state = SEND_DATA; |
||
497 | } else |
||
498 | state = RCV_ADDR; |
||
499 | } else if (state == RCV_ADDR) { |
||
500 | address = (address & 0x700) + datain; |
||
501 | state = RCV_DATA; bitsin = 0; |
||
502 | } else if (state == RCV_DATA) { |
||
503 | nvram[address] = datain; |
||
504 | address = (address & 0x7F0) + ((address+1) & 0x0F); |
||
505 | // state unchanged |
||
506 | } |
||
507 | |||
508 | // EEPROM always acknowledges |
||
509 | out = SDA_0; out_z = 0; goto exit; |
||
510 | } |
||
511 | |||
512 | if (state == SEND_DATA) { |
||
513 | if (bitsout == 8) { state = RD_ACK; out_z = 1; goto exit; } |
||
514 | out = (dataout & 0x80)? SDA_1 : SDA_0; dataout *= 2; |
||
515 | bitsout++; out_z = 0; goto exit; |
||
516 | } |
||
517 | |||
518 | out_z = 1; // no ACK, reading |
||
519 | } |
||
520 | goto exit; |
||
521 | } |
||
522 | |||
523 | if ((val & SCL) && ((val ^ prev) & SDA)) // start/stop |
||
524 | { |
||
525 | if (val & SDA) { idle: state = IDLE; } // stop |
||
526 | else state = RCV_CMD, bitsin = 0; // start |
||
527 | out_z = 1; |
||
528 | } |
||
529 | |||
530 | // else SDA changed on low SCL |
||
531 | |||
532 | |||
533 | exit: |
||
534 | if (out_z) out = (val & SDA)? SDA_1 : SDA_0; |
||
535 | prev = val; |
||
536 | } |