1 #ifdef SSMP_CPP
2 
ram_read(uint16 addr)3 alwaysinline uint8 sSMP::ram_read(uint16 addr) {
4   if(addr < 0xffc0) return memory::apuram[addr];
5   if(status.iplrom_enabled == false) return memory::apuram[addr];
6   return iplrom[addr & 0x3f];
7 }
8 
ram_write(uint16 addr,uint8 data)9 alwaysinline void sSMP::ram_write(uint16 addr, uint8 data) {
10   //writes to $ffc0-$ffff always go to spcram, even if the iplrom is enabled
11   memory::apuram[addr] = data;
12 }
13 
14 //
15 
port_read(uint8 port)16 alwaysinline uint8 sSMP::port_read(uint8 port) {
17   return memory::apuram[0xf4 + (port & 3)];
18 }
19 
port_write(uint8 port,uint8 data)20 alwaysinline void sSMP::port_write(uint8 port, uint8 data) {
21   memory::apuram[0xf4 + (port & 3)] = data;
22 }
23 
24 //
25 
op_busread(uint16 addr)26 alwaysinline uint8 sSMP::op_busread(uint16 addr) {
27   uint8 r;
28   if((addr & 0xfff0) == 0x00f0) {
29     //addr >= 0x00f0 && addr <= 0x00ff
30     switch(addr) {
31       case 0xf0: { //TEST -- write-only register
32         r = 0x00;
33       } break;
34 
35       case 0xf1: { //CONTROL -- write-only register
36         r = 0x00;
37       } break;
38 
39       case 0xf2: { //DSPADDR
40         r = status.dsp_addr;
41       } break;
42 
43       case 0xf3: { //DSPDATA
44         //0x80-0xff are read-only mirrors of 0x00-0x7f
45         r = dsp.read(status.dsp_addr & 0x7f);
46       } break;
47 
48       case 0xf4:   //CPUIO0
49       case 0xf5:   //CPUIO1
50       case 0xf6:   //CPUIO2
51       case 0xf7: { //CPUIO3
52         scheduler.sync_smpcpu();
53         r = cpu.port_read(addr & 3);
54       } break;
55 
56       case 0xf8: { //???
57         r = status.smp_f8;
58       } break;
59 
60       case 0xf9: { //???
61         r = status.smp_f9;
62       } break;
63 
64       case 0xfa:   //T0TARGET
65       case 0xfb:   //T1TARGET
66       case 0xfc: { //T2TARGET -- write-only registers
67         r = 0x00;
68       } break;
69 
70       case 0xfd: { //T0OUT -- 4-bit counter value
71         r = t0.stage3_ticks & 15;
72         t0.stage3_ticks = 0;
73       } break;
74 
75       case 0xfe: { //T1OUT -- 4-bit counter value
76         r = t1.stage3_ticks & 15;
77         t1.stage3_ticks = 0;
78       } break;
79 
80       case 0xff: { //T2OUT -- 4-bit counter value
81         r = t2.stage3_ticks & 15;
82         t2.stage3_ticks = 0;
83       } break;
84     }
85   } else {
86     r = ram_read(addr);
87   }
88 
89   return r;
90 }
91 
op_buswrite(uint16 addr,uint8 data)92 alwaysinline void sSMP::op_buswrite(uint16 addr, uint8 data) {
93   if((addr & 0xfff0) == 0x00f0) {
94     //addr >= 0x00f0 && addr >= 0x00ff
95     if(status.mmio_disabled == true) return;
96 
97     switch(addr) {
98       case 0xf0: { //TEST
99         if(regs.p.p) break; //writes only valid when P flag is clear
100 
101         //multiplier table may not be 100% accurate, some settings crash
102         //the processor due to S-SMP <> S-DSP bus access misalignment
103         //static uint8 clock_speed_tbl[16] =
104         //{ 3, 5, 9, 17, 4, 6, 10, 18, 6, 8, 12, 20, 10, 12, 16, 24 };
105 
106         //status.clock_speed   = 24 * clock_speed_tbl[data >> 4] / 3;
107         status.mmio_disabled = !!(data & 0x04);
108         status.ram_writable  = !!(data & 0x02);
109 
110         //if((data >> 4) != 0) {
111           //dprintf("* S-SMP critical warning: $00f0 (TEST) clock speed control modified!");
112           //dprintf("* S-SMP may crash on hardware as a result!");
113         //}
114       } break;
115 
116       case 0xf1: { //CONTROL
117         status.iplrom_enabled = !!(data & 0x80);
118 
119         if(data & 0x30) {
120           //one-time clearing of APU port read registers,
121           //emulated by simulating CPU writes of 0x00
122           scheduler.sync_smpcpu();
123           if(data & 0x20) {
124             cpu.port_write(2, 0x00);
125             cpu.port_write(3, 0x00);
126           }
127           if(data & 0x10) {
128             cpu.port_write(0, 0x00);
129             cpu.port_write(1, 0x00);
130           }
131         }
132 
133         //0->1 transistion resets timers
134         if(t2.enabled == false && (data & 0x04)) {
135           t2.stage2_ticks = 0;
136           t2.stage3_ticks = 0;
137         }
138         t2.enabled = !!(data & 0x04);
139 
140         if(t1.enabled == false && (data & 0x02)) {
141           t1.stage2_ticks = 0;
142           t1.stage3_ticks = 0;
143         }
144         t1.enabled = !!(data & 0x02);
145 
146         if(t0.enabled == false && (data & 0x01)) {
147           t0.stage2_ticks = 0;
148           t0.stage3_ticks = 0;
149         }
150         t0.enabled = !!(data & 0x01);
151       } break;
152 
153       case 0xf2: { //DSPADDR
154         status.dsp_addr = data;
155       } break;
156 
157       case 0xf3: { //DSPDATA
158         //0x80-0xff is a read-only mirror of 0x00-0x7f
159         if(!(status.dsp_addr & 0x80)) {
160           dsp.write(status.dsp_addr & 0x7f, data);
161         }
162       } break;
163 
164       case 0xf4:   //CPUIO0
165       case 0xf5:   //CPUIO1
166       case 0xf6:   //CPUIO2
167       case 0xf7: { //CPUIO3
168         scheduler.sync_smpcpu();
169         port_write(addr & 3, data);
170       } break;
171 
172       case 0xf8: { //???
173         status.smp_f8 = data;
174       } break;
175 
176       case 0xf9: { //???
177         status.smp_f9 = data;
178       } break;
179 
180       case 0xfa: { //T0TARGET
181         t0.target = data;
182       } break;
183 
184       case 0xfb: { //T1TARGET
185         t1.target = data;
186       } break;
187 
188       case 0xfc: { //T2TARGET
189         t2.target = data;
190       } break;
191 
192       case 0xfd:   //T0OUT
193       case 0xfe:   //T1OUT
194       case 0xff: { //T2OUT -- read-only registers
195       } break;
196     }
197   }
198 
199   //all writes, even to MMIO registers, appear on bus
200   if(status.ram_writable == true) {
201     ram_write(addr, data);
202   }
203 }
204 
205 //
206 
op_io()207 void sSMP::op_io() {
208   add_clocks(24);
209   tick_timers();
210 }
211 
op_read(uint16 addr)212 uint8 sSMP::op_read(uint16 addr) {
213   add_clocks(12);
214   uint8 r = op_busread(addr);
215   add_clocks(12);
216   tick_timers();
217   return r;
218 }
219 
op_write(uint16 addr,uint8 data)220 void sSMP::op_write(uint16 addr, uint8 data) {
221   add_clocks(24);
222   op_buswrite(addr, data);
223   tick_timers();
224 }
225 
226 #endif
227