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