sms wip: initial graphics support
[picodrive.git] / pico / sms.c
1 #include "pico_int.h"
2 #include "sound/sn76496.h"
3
4 static unsigned char vdp_data_read(void)
5 {
6   struct PicoVideo *pv = &Pico.video;
7   unsigned char d;
8
9   d = Pico.vramb[pv->addr];
10   pv->addr = (pv->addr + 1) & 0x3fff;
11   pv->pending = 0;
12   return d;
13 }
14
15 static unsigned char vdp_ctl_read(void)
16 {
17   unsigned char d = Pico.video.pending_ints << 7;
18   Pico.video.pending = 0;
19   Pico.video.pending_ints = 0;
20
21   elprintf(EL_SR, "VDP sr: %02x", d);
22   return d;
23 }
24
25 static void vdp_data_write(unsigned char d)
26 {
27   struct PicoVideo *pv = &Pico.video;
28
29   if (pv->type == 3) {
30     Pico.cram[pv->addr & 0x1f] = d;
31     Pico.m.dirtyPal = 1;
32   } else {
33     Pico.vramb[pv->addr] = d;
34   }
35   pv->addr = (pv->addr + 1) & 0x3fff;
36
37   pv->pending = 0;
38 }
39
40 static void vdp_ctl_write(unsigned char d)
41 {
42   struct PicoVideo *pv = &Pico.video;
43
44   if (pv->pending) {
45     if ((d >> 6) == 2) {
46       pv->reg[d & 0x0f] = pv->addr;
47       elprintf(EL_IO, "  VDP r%02x=%02x", d & 0x0f, pv->addr & 0xff);
48     }
49     pv->type = d >> 6;
50     pv->addr &= 0x00ff;
51     pv->addr |= (d & 0x3f) << 8;
52   } else {
53     pv->addr &= 0x3f00;
54     pv->addr |= d;
55   }
56   pv->pending ^= 1;
57 }
58
59 static unsigned char z80_sms_in(unsigned short a)
60 {
61   unsigned char d = 0;
62
63   elprintf(EL_IO, "z80 port %04x read", a);
64   a &= 0xc1;
65   switch (a)
66   {
67     case 0x00:
68     case 0x01:
69       d = 0xff;
70       break;
71
72     case 0x40: /* V counter */
73       d = Pico.video.v_counter;
74       break;
75
76     case 0x41: /* H counter */
77       d = Pico.m.rotate++;
78       break;
79
80     case 0x80:
81       d = vdp_data_read();
82       break;
83
84     case 0x81:
85       d = vdp_ctl_read();
86       break;
87
88     case 0xc0: /* I/O port A and B */
89       d = ~((PicoPad[0] & 0x3f) | (PicoPad[1] << 6));
90       break;
91
92     case 0xc1: /* I/O port B and miscellaneous */
93       d = (Pico.sms_io_ctl & 0x80) | ((Pico.sms_io_ctl << 1) & 0x40) | 0x30;
94       d |= ~(PicoPad[1] >> 2) & 0x0f;
95       break;
96   }
97
98   elprintf(EL_IO, "ret = %02x", d);
99   return d;
100 }
101
102 static void z80_sms_out(unsigned short a, unsigned char d)
103 {
104   elprintf(EL_IO, "z80 port %04x write %02x", a, d);
105   a &= 0xc1;
106   switch (a)
107   {
108     case 0x01:
109       Pico.sms_io_ctl = d;
110       break;
111
112     case 0x40:
113     case 0x41:
114       if (PicoOpt & POPT_EN_PSG)
115         SN76496Write(d);
116       break;
117
118     case 0x80:
119       vdp_data_write(d);
120       break;
121
122     case 0x81:
123       vdp_ctl_write(d);
124       break;
125   }
126 }
127
128 static void write_bank(unsigned short a, unsigned char d)
129 {
130   d &= 0x3f; // XXX
131   switch (a & 0x0f)
132   {
133     case 0x0c:
134       break;
135     case 0x0d:
136       if (d != 0)
137         elprintf(EL_STATUS|EL_ANOMALY, "bank0 changed to %d!", d);
138       break;
139     case 0x0e:
140       z80_map_set(z80_read_map, 0x4000, 0x7fff, Pico.rom + (d << 14), 0);
141 #ifdef _USE_CZ80
142       Cz80_Set_Fetch(&CZ80, 0x4000, 0x7fff, (UINT32)Pico.rom + (d << 14));
143 #endif
144       break;
145     case 0x0f:
146       z80_map_set(z80_read_map, 0x8000, 0xbfff, Pico.rom + (d << 14), 0);
147 #ifdef _USE_CZ80
148       Cz80_Set_Fetch(&CZ80, 0x8000, 0xbfff, (UINT32)Pico.rom + (d << 14));
149 #endif
150       break;
151   }
152 }
153
154 static void MEMH_FUNC xwrite(unsigned int a, unsigned char d)
155 {
156   elprintf(EL_IO, "z80 write [%04x] %02x", a, d);
157   if (a >= 0xc000)
158     Pico.zram[a & 0x1fff] = d;
159   if (a >= 0xfff0)
160     write_bank(a, d);
161 }
162
163 void PicoResetMS(void)
164 {
165   z80_reset();
166   PsndReset(); // pal must be known here
167 }
168
169 void PicoPowerMS(void)
170 {
171   memset(&Pico.ram,0,(unsigned int)&Pico.rom-(unsigned int)&Pico.ram);
172   memset(&Pico.video,0,sizeof(Pico.video));
173   memset(&Pico.m,0,sizeof(Pico.m));
174   Pico.m.pal = 0;
175
176   PicoReset();
177 }
178
179 void PicoMemSetupMS(void)
180 {
181   z80_map_set(z80_read_map, 0x0000, 0xbfff, Pico.rom, 0);
182   z80_map_set(z80_read_map, 0xc000, 0xdfff, Pico.zram, 0);
183   z80_map_set(z80_read_map, 0xe000, 0xffff, Pico.zram, 0);
184
185   z80_map_set(z80_write_map, 0x0000, 0xbfff, xwrite, 1);
186   z80_map_set(z80_write_map, 0xc000, 0xdfff, Pico.zram, 0);
187   z80_map_set(z80_write_map, 0xe000, 0xffff, xwrite, 1);
188  
189 #ifdef _USE_DRZ80
190   drZ80.z80_in = z80_sms_in;
191   drZ80.z80_out = z80_sms_out;
192 #endif
193 #ifdef _USE_CZ80
194   Cz80_Set_Fetch(&CZ80, 0x0000, 0xbfff, (UINT32)Pico.rom);
195   Cz80_Set_Fetch(&CZ80, 0xc000, 0xdfff, (UINT32)Pico.zram);
196   Cz80_Set_Fetch(&CZ80, 0xe000, 0xffff, (UINT32)Pico.zram);
197   Cz80_Set_INPort(&CZ80, z80_sms_in);
198   Cz80_Set_OUTPort(&CZ80, z80_sms_out);
199 #endif
200 }
201
202 void PicoFrameMS(void)
203 {
204   struct PicoVideo *pv = &Pico.video;
205   int is_pal = Pico.m.pal;
206   int lines = is_pal ? 313 : 262;
207   int cycles_line = is_pal ? 58020 : 58293; /* (226.6 : 227.7) * 256 */
208   int cycles_done = 0, cycles_aim = 0;
209   int lines_vis = 192;
210   int y;
211
212   PicoFrameStartMode4();
213
214   for (y = 0; y < lines; y++)
215   {
216     pv->v_counter = Pico.m.scanline = y;
217
218     if (y < lines_vis)
219       PicoLineMode4(y);
220     else if (y == lines_vis + 1) {
221       Pico.video.pending_ints |= 1;
222       if (Pico.video.reg[1] & 0x20) {
223         elprintf(EL_INTS, "vint");
224         z80_int();
225       }
226     }
227
228     cycles_aim += cycles_line;
229     cycles_done += z80_run((cycles_aim - cycles_done) >> 8) << 8;
230   }
231
232   PsndGetSamplesMS();
233 }
234