OSDN Git Service

21d30833d8e5e8051ea0a22f12dffa18daeed54f
[unagi/old-svn-converted.git] / kazzo / trunk / firmware / bus_access.c
1 #include <util/delay.h>
2 #include <avr/io.h>
3 #include "type.h"
4 #include "bus_access.h"
5
6 //avr/io.h use many macros, I want use IO access by inline function...
7 #define IO_DIRECTION(NAME) (DDR##NAME)
8 #define IO_OUT(NAME) (PORT##NAME)
9 #define IO_IN(NAME) (PIN##NAME)
10 /* PAx: output only
11 connected CPU and PPU databus*/
12 #define ADDRESSBUS_A0_A7_DIR IO_DIRECTION(A)
13 #define ADDRESSBUS_A0_A7_OUT IO_OUT(A)
14 /* PBx: output/input
15 connected address high latch(HC574), CPU and PPU databus*/
16 #define DATABUS_DIR IO_DIRECTION(B)
17 #define DATABUS_OUT IO_OUT(B)
18 #define DATABUS_IN IO_IN(B)
19 enum databus_dir{
20         DATABUS_DIR_OUT = 0xff,
21         DATABUS_DIR_IN = 0
22 };
23 /*PCx: output ADDRESS_HIGH_LATCH connect HC574 clock pin, bus control signal
24 VRAM_CS is input port this is design mistake!
25 */
26 #define BUS_CONTROL_DIR IO_DIRECTION(C)
27 #define BUS_CONTROL_OUT IO_OUT(C)
28 enum iobit_bus_control{
29         CPU_PHI2 = 0, CPU_ROMCS, CPU_RW,
30         RESERVE_PPU_POS_A13, PPU_RD, PPU_WR,
31         VRAM_CS, ADDRESS_HIGH_LATCH
32 };
33 //when cpu_write_flash, phi2 must be low. when phi2 is high, mmc3 and vrc4 changes bank.
34 enum {
35         BUS_CLOSE = 0xff
36 };
37 /*PDx: use input, empty pin is output*/
38 #define USB_MISC_DIR IO_DIRECTION(D)
39 #define USB_MISC_PULLUP IO_OUT(D)
40 #define USB_MISC_IN IO_IN(D)
41 enum iobit_usb_misc{
42         USB_DPLUS = 2, CPU_IRQ, 
43         USB_DMINUS, VRAM_A10
44 };
45 static inline uint8_t bit_get_negative(enum iobit_bus_control bit)
46 {
47         uint8_t ret = (1 << bit);
48         return ~ret;
49 }
50
51 void bus_init(void)
52 {
53         ADDRESSBUS_A0_A7_DIR = 0xff;
54         ADDRESSBUS_A0_A7_OUT = 0;
55         DATABUS_DIR = DATABUS_DIR_OUT;
56         BUS_CONTROL_DIR = bit_get_negative(VRAM_CS); //VRAM_CS is input port
57         BUS_CONTROL_OUT = BUS_CLOSE;
58         USB_MISC_DIR = (0b1100 << 4) | 0b0011; //empty pin use OUT
59         USB_MISC_PULLUP = (1 << CPU_IRQ) | (1 << VRAM_A10);
60 }
61
62 /*
63 make phi2 edge signal, this is needed by namcot mapper and RP2C33.
64 */
65 void phi2_init(void)
66 {
67         int i = 0x80;
68         while(i != 0){
69                 BUS_CONTROL_OUT = BUS_CLOSE;
70                 BUS_CONTROL_OUT = BUS_CLOSE ^ (1 << CPU_PHI2);
71                 i--;
72         }
73 }
74
75 //for RAM adapter DRAM refresh
76 void phi2_update(void)
77 {
78         static uint8_t i = 0;
79         uint8_t c = BUS_CLOSE;
80         if(i & 0b100){
81                 c ^= 1 << CPU_PHI2;
82         }
83         BUS_CONTROL_OUT = c;
84         i += 1;
85 }
86 /*
87 address high databus assignment
88 D0-D5: CPU and PPU A8-A13
89 D6: CPU A14
90 D7: PPU /A13
91 */
92 static void address_set(uint16_t address)
93 {
94         ADDRESSBUS_A0_A7_OUT = address & 0xff;
95         uint8_t high = (address & 0x7fff) >> 8; //mask A0-A14
96         if((address & (1 << 13)) == 0){ //if A13 == 0
97                 high |= 0x80; //set /A13
98         }
99         DATABUS_OUT = high;
100         BUS_CONTROL_OUT = bit_get_negative(ADDRESS_HIGH_LATCH);
101         BUS_CONTROL_OUT = BUS_CLOSE;
102 }
103 static inline void direction_write(void)
104 {
105         DATABUS_DIR = DATABUS_DIR_OUT;
106         asm("nop");
107         asm("nop");
108         asm("nop");
109 }
110
111 static inline void direction_read(void)
112 {
113         DATABUS_OUT = 0xff; //when input direction, pullup
114         DATABUS_DIR = DATABUS_DIR_IN;
115         asm("nop"); //wait for chaging port direction. do not remove.
116         asm("nop");
117         asm("nop");
118 }
119 //mmc5 ROM area need that phi2 is high
120 void cpu_read(uint16_t address, uint16_t length, uint8_t *data)
121 {
122         BUS_CONTROL_OUT = BUS_CLOSE;
123         while(length != 0){
124 //              uint8_t c = BUS_CLOSE;
125                 direction_write();
126                 address_set(address);
127                 if((address & 0x8000) != 0){
128 //                      c &= bit_get_negative(CPU_ROMCS) | (1 << CPU_ROMCS);
129 //                      BUS_CONTROL_OUT = c;
130                         BUS_CONTROL_OUT = bit_get_negative(CPU_ROMCS);
131                 }
132                 direction_read();
133                 *data = DATABUS_IN;
134                 data += 1;
135                 BUS_CONTROL_OUT = BUS_CLOSE;
136                 address += 1;
137                 length--;
138         }
139         direction_write();
140 }
141
142 void cpu_read_6502(uint16_t address, uint16_t length, uint8_t *data)
143 {
144         while(length != 0){
145                 //phi2 down
146                 uint8_t c = bit_get_negative(CPU_PHI2);
147                 BUS_CONTROL_OUT = c;
148
149                 //down -> up
150                 direction_write();
151                 address_set(address);
152                 if((address & 0x8000) != 0){
153                         c &= bit_get_negative(CPU_ROMCS);
154                 }
155                 BUS_CONTROL_OUT = c;
156                 clock_wait(1);
157                 
158                 //phi2 up
159                 c |= (1 << CPU_PHI2); // | (1 << CPU_ROMCS);
160                 BUS_CONTROL_OUT = c;
161                 if(1){
162                         direction_read();
163                         *data = DATABUS_IN;
164                         data += 1;
165                 }
166                 clock_wait(1);
167                 if(0){
168                         BUS_CONTROL_OUT = c;
169                         direction_read();
170                         *data = DATABUS_IN;
171                         data += 1;
172                 }
173                 BUS_CONTROL_OUT = c;
174                 
175                 //phi2 down
176                 if((address & 0x8000) != 0){
177                         c &= bit_get_negative(CPU_ROMCS);
178                 }
179                 c &= bit_get_negative(CPU_PHI2);
180                 if(0){
181                         BUS_CONTROL_OUT = c;
182                         direction_read();
183                         *data = DATABUS_IN;
184                         data += 1;
185                 }
186                 clock_wait(1);
187                 
188                 //bus close
189                 BUS_CONTROL_OUT = BUS_CLOSE;
190                 
191                 address += 1;
192                 length--;
193         }
194         direction_write();
195 }
196
197 void ppu_read(uint16_t address, uint16_t length, uint8_t *data)
198 {
199         //BUS_CONTROL_OUT = BUS_CLOSE;
200         while(length != 0){
201                 direction_write();
202                 address_set(address);
203                 BUS_CONTROL_OUT = bit_get_negative(PPU_RD);
204                 direction_read();
205                 *data = DATABUS_IN;
206                 data += 1;
207                 BUS_CONTROL_OUT = BUS_CLOSE;
208                 address += 1;
209                 length--;
210         }
211         direction_write();
212 }
213
214 enum compare_status cpu_compare(uint16_t address, uint16_t length, const uint8_t *data)
215 {
216         return OK;
217 }
218 enum compare_status ppu_compare(uint16_t address, uint16_t length, const uint8_t *data)
219 {
220         while(length != 0){
221                 direction_write();
222                 address_set(address);
223                 BUS_CONTROL_OUT = bit_get_negative(PPU_RD);
224                 direction_read();
225                 if(DATABUS_IN != *data){
226                         BUS_CONTROL_OUT = BUS_CLOSE;
227                         direction_write();
228                         return NG;
229                 }
230                 data += 1;
231                 BUS_CONTROL_OUT = BUS_CLOSE;
232                 address += 1;
233                 length--;
234         }
235         direction_write();
236         return OK;
237 }
238
239 void cpu_write_6502_nowait(uint16_t address, uint16_t length, const uint8_t *data)
240 {
241         while(length != 0){
242                 uint8_t control;
243                 address_set(address);
244                 
245                 //phi2 down
246                 control = bit_get_negative(CPU_PHI2);
247                 BUS_CONTROL_OUT = control;
248                 control &= bit_get_negative(CPU_RW);
249                 if((address & 0x8000) != 0){
250                         control &= bit_get_negative(CPU_ROMCS);
251                 }
252                 BUS_CONTROL_OUT = control;
253                 
254                 //phi2 up
255                 control |= (1 << CPU_PHI2) | (1 << CPU_ROMCS);
256                 BUS_CONTROL_OUT = control;
257                 DATABUS_OUT = *data;
258                 data++;
259                 
260                 //phi2 down
261                 control &= bit_get_negative(CPU_PHI2);
262                 if((address & 0x8000) != 0){
263                         control &= bit_get_negative(CPU_ROMCS);
264                 }
265                 BUS_CONTROL_OUT = control;
266                 
267                 //bus close
268                 BUS_CONTROL_OUT = BUS_CLOSE;
269                 
270                 address += 1;
271                 length--;
272         }
273 }
274
275 /*
276 /WE controlled write operation has busconflict
277 PHI2  |-__________-
278 R/W   |----___-----
279 /ROMCS|--_______---
280 A0-A14|-<vaild address>-
281 D0-D7 |--oo<i>**---
282 o is dataout, i is datain, * is bus-confilict
283
284 /CS controlled write operation is clean write cycle for flash memory
285 PHI2  |-__________-
286 R/W   |--_______---
287 /ROMCS|----___-----
288 A0-A14|-<vaild address>-
289 D0-D7 |----<iii>---
290 */
291 static inline void cpu_write_flash_waveform(uint16_t address, uint8_t data)
292 {
293         uint8_t control = bit_get_negative(CPU_PHI2);
294         address_set(address);
295         if(0){ //R/W = /WE controlled write operation
296                 if((address & 0x8000) != 0){
297                         control &= bit_get_negative(CPU_ROMCS);
298                         BUS_CONTROL_OUT = control;
299                 }
300                 control &= bit_get_negative(CPU_RW);
301                 BUS_CONTROL_OUT = control;
302                 DATABUS_OUT = data;
303                 control |= 1 << CPU_RW; //R/W close
304                 BUS_CONTROL_OUT = control;
305         }else{ ///ROMCS = /CS controlled write operation
306                 control &= bit_get_negative(CPU_RW);
307                 BUS_CONTROL_OUT = control;
308                 if((address & 0x8000) != 0){
309                         control &= bit_get_negative(CPU_ROMCS);
310                         BUS_CONTROL_OUT = control;
311                 }
312                 DATABUS_OUT = data;
313                 control |= 1 << CPU_ROMCS;
314                 BUS_CONTROL_OUT = control;
315         }
316         BUS_CONTROL_OUT = BUS_CLOSE;
317 }
318 void cpu_write_flash(uint16_t address, uint16_t length, const uint8_t *data)
319 {
320         direction_write();
321         while(length != 0){
322                 cpu_write_flash_waveform(address, *data);
323                 data++;
324                 address += 1;
325                 length--;
326         }
327 }
328
329 void cpu_write_flash_order(const struct flash_order *t)
330 {
331         int length = FLASH_PROGRAM_ORDER;
332         direction_write();
333         while(length != 0){
334                 cpu_write_flash_waveform(t->address, t->data);
335                 t++;
336                 length--;
337         }
338 }
339 /*
340 NTSC hardware timing
341 Master clock fsc: 21.4772272 MHz
342 CPU clock fsc/12: 1.789773MHz
343 clock per second 12/fsc: 5.58*10**-7 sec, 0.55 us
344 */
345 void cpu_write_6502(uint16_t address, uint16_t length, const uint8_t *data)
346 {
347         while(length != 0){
348                 uint8_t control;
349                 address_set(address);
350                 
351                 //phi2 down
352                 control = bit_get_negative(CPU_PHI2);
353                 BUS_CONTROL_OUT = control;
354                 control &= bit_get_negative(CPU_RW);
355                 if((address & 0x8000) != 0){
356                         control &= bit_get_negative(CPU_ROMCS);
357                 }
358                 BUS_CONTROL_OUT = control;
359                 clock_wait(1);
360
361                 //phi2 up
362                 control |= (1 << CPU_PHI2); //| (1 << CPU_ROMCS);
363                 DATABUS_OUT = *data;
364                 BUS_CONTROL_OUT = control;
365 //              DATABUS_OUT = *data;
366                 data++;
367                 clock_wait(1);
368                 
369                 //phi2 down
370                 control &= bit_get_negative(CPU_PHI2);
371                 BUS_CONTROL_OUT = control;
372                 if((address & 0x8000) != 0){
373                         control &= bit_get_negative(CPU_ROMCS);
374                 }
375 //              clock_wait(1);
376                 BUS_CONTROL_OUT = control;
377                 
378                 //bus close
379 //              clock_wait(1);
380                 BUS_CONTROL_OUT = BUS_CLOSE;
381                 
382                 address += 1;
383                 length--;
384         }
385 }
386
387 static inline void ppu_write_waveform(uint16_t address, uint8_t data)
388 {
389         address_set(address);//PPU charcter memory /CS open
390         BUS_CONTROL_OUT = bit_get_negative(PPU_WR);
391         DATABUS_OUT = data;
392         BUS_CONTROL_OUT = BUS_CLOSE;
393         address_set(0x3fff); ///CS close, use pallete area. When address bus is 0x2000-0x2fff, some cartriges enable tilemap area.
394 }
395 void ppu_write(uint16_t address, uint16_t length, const uint8_t *data)
396 {
397         while(length != 0){
398                 ppu_write_waveform(address, *data);
399                 data++;
400                 address += 1;
401                 length--;
402         }
403 }
404
405 void ppu_write_order(const struct flash_order *t)
406 {
407         int length = FLASH_PROGRAM_ORDER;
408         while(length != 0){
409                 ppu_write_waveform(t->address, t->data);
410                 t++;
411                 length--;
412         }
413 }
414
415 uint8_t vram_connection_get(void)
416 {
417         uint8_t ret;
418         uint16_t address = 0x2000;
419         direction_write();
420         address_set(address);
421         ret = bit_get(USB_MISC_IN, VRAM_A10);
422         address += 1 << 10;
423
424         address_set(address);
425         ret |= bit_get(USB_MISC_IN, VRAM_A10) << 1;
426         address += 1 << 10;
427         
428         address_set(address);
429         ret |= bit_get(USB_MISC_IN, VRAM_A10) << 2;
430         address += 1 << 10;
431
432         address_set(address);
433         ret |= bit_get(USB_MISC_IN, VRAM_A10) << 3;
434         address += 1 << 10;
435         
436         return ret;
437 }