1 #include <../base.hpp>
2 
3 #define SA1_CPP
4 namespace SNES {
5 
6 SA1 sa1;
7 
8 #include "serialization.cpp"
9 #include "bus/bus.cpp"
10 #include "dma/dma.cpp"
11 #include "memory/memory.cpp"
12 #include "mmio/mmio.cpp"
13 
enter()14 void SA1::enter() {
15   while(true) {
16     while(scheduler.sync == Scheduler::SyncAll) {
17       scheduler.exit(Scheduler::SynchronizeEvent);
18     }
19 
20     if(mmio.sa1_rdyb || mmio.sa1_resb) {
21       //SA-1 co-processor is asleep
22       tick();
23       scheduler.sync_copcpu();
24       continue;
25     }
26 
27     if(status.interrupt_pending) {
28       status.interrupt_pending = false;
29       interrupt(status.interrupt_vector);
30     }
31 
32     (this->*opcode_table[op_readpc()])();
33   }
34 }
35 
last_cycle()36 void SA1::last_cycle() {
37   if(mmio.sa1_nmi && !mmio.sa1_nmicl) {
38     status.interrupt_pending = true;
39     status.interrupt_vector  = mmio.cnv;
40     mmio.sa1_nmifl = true;
41     mmio.sa1_nmicl = 1;
42     regs.wai = false;
43   } else if(!regs.p.i) {
44     if(mmio.timer_irqen && !mmio.timer_irqcl) {
45       status.interrupt_pending = true;
46       status.interrupt_vector  = mmio.civ;
47       mmio.timer_irqfl = true;
48       regs.wai = false;
49     } else if(mmio.dma_irqen && !mmio.dma_irqcl) {
50       status.interrupt_pending = true;
51       status.interrupt_vector  = mmio.civ;
52       mmio.dma_irqfl = true;
53       regs.wai = false;
54     } else if(mmio.sa1_irq && !mmio.sa1_irqcl) {
55       status.interrupt_pending = true;
56       status.interrupt_vector  = mmio.civ;
57       mmio.sa1_irqfl = true;
58       regs.wai = false;
59     }
60   }
61 }
62 
interrupt(uint16 vector)63 void SA1::interrupt(uint16 vector) {
64   op_read(regs.pc.d);
65   op_io();
66   if(!regs.e) op_writestack(regs.pc.b);
67   op_writestack(regs.pc.h);
68   op_writestack(regs.pc.l);
69   op_writestack(regs.e ? (regs.p & ~0x10) : regs.p);
70   regs.pc.w = vector;
71   regs.pc.b = 0x00;
72   regs.p.i  = 1;
73   regs.p.d  = 0;
74 }
75 
interrupt_pending()76 bool SA1::interrupt_pending() {
77   return status.interrupt_pending;
78 }
79 
tick()80 void SA1::tick() {
81   scheduler.addclocks_cop(2);
82   if(++status.tick_counter == 0) scheduler.sync_copcpu();
83 
84   //adjust counters:
85   //note that internally, status counters are in clocks;
86   //whereas MMIO register counters are in dots (4 clocks = 1 dot)
87   if(mmio.hvselb == 0) {
88     //HV timer
89     status.hcounter += 2;
90     if(status.hcounter >= 1364) {
91       status.hcounter = 0;
92       if(++status.vcounter >= status.scanlines) status.vcounter = 0;
93     }
94   } else {
95     //linear timer
96     status.hcounter += 2;
97     status.vcounter += (status.hcounter >> 11);
98     status.hcounter &= 0x07ff;
99     status.vcounter &= 0x01ff;
100   }
101 
102   //test counters for timer IRQ
103   switch((mmio.ven << 1) + (mmio.hen << 0)) {
104     case 0: break;
105     case 1: if(status.hcounter == (mmio.hcnt << 2)) trigger_irq(); break;
106     case 2: if(status.vcounter == mmio.vcnt && status.hcounter == 0) trigger_irq(); break;
107     case 3: if(status.vcounter == mmio.hcnt && status.hcounter == (mmio.hcnt << 2)) trigger_irq(); break;
108   }
109 }
110 
trigger_irq()111 void SA1::trigger_irq() {
112   mmio.timer_irqfl = true;
113   if(mmio.timer_irqen) mmio.timer_irqcl = 0;
114 }
115 
init()116 void SA1::init() {
117 }
118 
enable()119 void SA1::enable() {
120 }
121 
power()122 void SA1::power() {
123   regs.a = regs.x = regs.y = 0x0000;
124   regs.s = 0x01ff;
125 
126   reset();
127 }
128 
reset()129 void SA1::reset() {
130   memory::vectorsp.access = 0;
131   memory::cc1bwram.dma = false;
132   for(unsigned addr = 0; addr < memory::iram.size(); addr++) {
133     memory::iram.write(addr, 0x00);
134   }
135   vbrbus.init();
136   sa1bus.init();
137 
138   regs.pc.d = 0x000000;
139   regs.x.h  = 0x00;
140   regs.y.h  = 0x00;
141   regs.s.h  = 0x01;
142   regs.d    = 0x0000;
143   regs.db   = 0x00;
144   regs.p    = 0x34;
145   regs.e    = 1;
146   regs.mdr  = 0x00;
147   regs.wai  = false;
148   CPUcore::update_table();
149 
150   status.tick_counter = 0;
151 
152   status.interrupt_pending = false;
153   status.interrupt_vector  = 0x0000;
154 
155   status.scanlines = (system.region() == System::NTSC ? 262 : 312);
156   status.vcounter  = 0;
157   status.hcounter  = 0;
158 
159   dma.line = 0;
160 
161   //$2200 CCNT
162   mmio.sa1_irq  = false;
163   mmio.sa1_rdyb = false;
164   mmio.sa1_resb = true;
165   mmio.sa1_nmi  = false;
166   mmio.smeg     = 0;
167 
168   //$2201 SIE
169   mmio.cpu_irqen   = false;
170   mmio.chdma_irqen = false;
171 
172   //$2202 SIC
173   mmio.cpu_irqcl   = false;
174   mmio.chdma_irqcl = false;
175 
176   //$2203,$2204 CRV
177   mmio.crv = 0x0000;
178 
179   //$2205,$2206 CNV
180   mmio.cnv = 0x0000;
181 
182   //$2207,$2208 CIV
183   mmio.civ = 0x0000;
184 
185   //$2209 SCNT
186   mmio.cpu_irq  = false;
187   mmio.cpu_ivsw = false;
188   mmio.cpu_nvsw = false;
189   mmio.cmeg     = 0;
190 
191   //$220a CIE
192   mmio.sa1_irqen   = false;
193   mmio.timer_irqen = false;
194   mmio.dma_irqen   = false;
195   mmio.sa1_nmien   = false;
196 
197   //$220b CIC
198   mmio.sa1_irqcl   = false;
199   mmio.timer_irqcl = false;
200   mmio.dma_irqcl   = false;
201   mmio.sa1_nmicl   = false;
202 
203   //$220c,$220d SNV
204   mmio.snv = 0x0000;
205 
206   //$220e,$220f SIV
207   mmio.siv = 0x0000;
208 
209   //$2210
210   mmio.hvselb = false;
211   mmio.ven    = false;
212   mmio.hen    = false;
213 
214   //$2212,$2213 HCNT
215   mmio.hcnt = 0x0000;
216 
217   //$2214,$2215 VCNT
218   mmio.vcnt = 0x0000;
219 
220   //$2220-2223 CXB, DXB, EXB, FXB
221   mmio.cbmode = 0;
222   mmio.dbmode = 0;
223   mmio.ebmode = 0;
224   mmio.fbmode = 0;
225 
226   mmio.cb = 0x00;
227   mmio.db = 0x01;
228   mmio.eb = 0x02;
229   mmio.fb = 0x03;
230 
231   //$2224 BMAPS
232   mmio.sbm = 0x00;
233 
234   //$2225 BMAP
235   mmio.sw46 = false;
236   mmio.cbm  = 0x00;
237 
238   //$2226 SWBE
239   mmio.swen = false;
240 
241   //$2227 CWBE
242   mmio.cwen = false;
243 
244   //$2228 BWPA
245   mmio.bwp = 0x0f;
246 
247   //$2229 SIWP
248   mmio.siwp = 0x00;
249 
250   //$222a CIWP
251   mmio.ciwp = 0x00;
252 
253   //$2230 DCNT
254   mmio.dmaen = false;
255   mmio.dprio = false;
256   mmio.cden  = false;
257   mmio.cdsel = false;
258   mmio.dd    = 0;
259   mmio.sd    = 0;
260 
261   //$2231 CDMA
262   mmio.chdend  = false;
263   mmio.dmasize = 0;
264   mmio.dmacb   = 0;
265 
266   //$2232-$2234 SDA
267   mmio.dsa = 0x000000;
268 
269   //$2235-$2237 DDA
270   mmio.dda = 0x000000;
271 
272   //$2238,$2239 DTC
273   mmio.dtc = 0x0000;
274 
275   //$223f BBF
276   mmio.bbf = 0;
277 
278   //$2240-$224f BRF
279   for(unsigned i = 0; i < 16; i++) {
280     mmio.brf[i] = 0x00;
281   }
282 
283   //$2250 MCNT
284   mmio.acm = 0;
285   mmio.md  = 0;
286 
287   //$2251,$2252 MA
288   mmio.ma = 0x0000;
289 
290   //$2253,$2254 MB
291   mmio.mb = 0x0000;
292 
293   //$2258 VBD
294   mmio.hl = false;
295   mmio.vb = 16;
296 
297   //$2259-$225b
298   mmio.va   = 0x000000;
299   mmio.vbit = 0;
300 
301   //$2300 SFR
302   mmio.cpu_irqfl   = false;
303   mmio.chdma_irqfl = false;
304 
305   //$2301 CFR
306   mmio.sa1_irqfl   = false;
307   mmio.timer_irqfl = false;
308   mmio.dma_irqfl   = false;
309   mmio.sa1_nmifl   = false;
310 
311   //$2302,$2303 HCR
312   mmio.hcr = 0x0000;
313 
314   //$2304,$2305 VCR
315   mmio.vcr = 0x0000;
316 
317   //$2306-$230a MR
318   mmio.mr = 0;
319 
320   //$230b
321   mmio.overflow = false;
322 }
323 
SA1()324 SA1::SA1() {
325 }
326 
327 };
328