OSDN Git Service

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