mmio.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540
  1. #ifdef SCPU_CPP
  2. uint8 sCPU::pio() { return status.pio; }
  3. bool sCPU::joylatch() { return status.joypad_strobe_latch; }
  4. //WMDATA
  5. uint8 sCPU::mmio_r2180() {
  6. uint8 r = bus.read(0x7e0000 | status.wram_addr);
  7. status.wram_addr = (status.wram_addr + 1) & 0x01ffff;
  8. return r;
  9. }
  10. //WMDATA
  11. void sCPU::mmio_w2180(uint8 data) {
  12. bus.write(0x7e0000 | status.wram_addr, data);
  13. status.wram_addr = (status.wram_addr + 1) & 0x01ffff;
  14. }
  15. //WMADDL
  16. void sCPU::mmio_w2181(uint8 data) {
  17. status.wram_addr = (status.wram_addr & 0xffff00) | (data);
  18. status.wram_addr &= 0x01ffff;
  19. }
  20. //WMADDM
  21. void sCPU::mmio_w2182(uint8 data) {
  22. status.wram_addr = (status.wram_addr & 0xff00ff) | (data << 8);
  23. status.wram_addr &= 0x01ffff;
  24. }
  25. //WMADDH
  26. void sCPU::mmio_w2183(uint8 data) {
  27. status.wram_addr = (status.wram_addr & 0x00ffff) | (data << 16);
  28. status.wram_addr &= 0x01ffff;
  29. }
  30. //JOYSER0
  31. //bit 0 is shared between JOYSER0 and JOYSER1, therefore
  32. //strobing $4016.d0 affects both controller port latches.
  33. //$4017 bit 0 writes are ignored.
  34. void sCPU::mmio_w4016(uint8 data) {
  35. status.joypad_strobe_latch = !!(data & 1);
  36. if(status.joypad_strobe_latch == 1) {
  37. snes.input.poll();
  38. }
  39. }
  40. //JOYSER0
  41. //7-2 = MDR
  42. //1-0 = Joypad serial data
  43. //
  44. //TODO: test whether strobe latch of zero returns
  45. //realtime or buffered status of joypadN.b
  46. uint8 sCPU::mmio_r4016() {
  47. uint8 r = regs.mdr & 0xfc;
  48. r |= snes.input.port_read(0) & 3;
  49. return r;
  50. }
  51. //JOYSER1
  52. //7-5 = MDR
  53. //4-2 = Always 1 (pins are connected to GND)
  54. //1-0 = Joypad serial data
  55. uint8 sCPU::mmio_r4017() {
  56. uint8 r = (regs.mdr & 0xe0) | 0x1c;
  57. r |= snes.input.port_read(1) & 3;
  58. return r;
  59. }
  60. //NMITIMEN
  61. void sCPU::mmio_w4200(uint8 data) {
  62. status.auto_joypad_poll = !!(data & 0x01);
  63. nmitimen_update(data);
  64. }
  65. //WRIO
  66. void sCPU::mmio_w4201(uint8 data) {
  67. if((status.pio & 0x80) && !(data & 0x80)) {
  68. ppu.latch_counters();
  69. }
  70. status.pio = data;
  71. }
  72. //WRMPYA
  73. void sCPU::mmio_w4202(uint8 data) {
  74. status.mul_a = data;
  75. }
  76. //WRMPYB
  77. void sCPU::mmio_w4203(uint8 data) {
  78. status.mul_b = data;
  79. status.r4216 = status.mul_a * status.mul_b;
  80. status.alu_lock = true;
  81. event.enqueue(snes.config.cpu.alu_mul_delay, EventAluLockRelease);
  82. }
  83. //WRDIVL
  84. void sCPU::mmio_w4204(uint8 data) {
  85. status.div_a = (status.div_a & 0xff00) | (data);
  86. }
  87. //WRDIVH
  88. void sCPU::mmio_w4205(uint8 data) {
  89. status.div_a = (status.div_a & 0x00ff) | (data << 8);
  90. }
  91. //WRDIVB
  92. void sCPU::mmio_w4206(uint8 data) {
  93. status.div_b = data;
  94. status.r4214 = (status.div_b) ? status.div_a / status.div_b : 0xffff;
  95. status.r4216 = (status.div_b) ? status.div_a % status.div_b : status.div_a;
  96. status.alu_lock = true;
  97. event.enqueue(snes.config.cpu.alu_div_delay, EventAluLockRelease);
  98. }
  99. //HTIMEL
  100. void sCPU::mmio_w4207(uint8 data) {
  101. status.hirq_pos = (status.hirq_pos & ~0xff) | (data);
  102. status.hirq_pos &= 0x01ff;
  103. }
  104. //HTIMEH
  105. void sCPU::mmio_w4208(uint8 data) {
  106. status.hirq_pos = (status.hirq_pos & 0xff) | (data << 8);
  107. status.hirq_pos &= 0x01ff;
  108. }
  109. //VTIMEL
  110. void sCPU::mmio_w4209(uint8 data) {
  111. status.virq_pos = (status.virq_pos & ~0xff) | (data);
  112. status.virq_pos &= 0x01ff;
  113. }
  114. //VTIMEH
  115. void sCPU::mmio_w420a(uint8 data) {
  116. status.virq_pos = (status.virq_pos & 0xff) | (data << 8);
  117. status.virq_pos &= 0x01ff;
  118. }
  119. //DMAEN
  120. void sCPU::mmio_w420b(uint8 data) {
  121. for(unsigned i = 0; i < 8; i++) {
  122. channel[i].dma_enabled = data & (1 << i);
  123. }
  124. if(data) status.dma_pending = true;
  125. }
  126. //HDMAEN
  127. void sCPU::mmio_w420c(uint8 data) {
  128. for(unsigned i = 0; i < 8; i++) {
  129. channel[i].hdma_enabled = data & (1 << i);
  130. }
  131. }
  132. //MEMSEL
  133. void sCPU::mmio_w420d(uint8 data) {
  134. bus.set_speed(data & 1);
  135. }
  136. //RDNMI
  137. //7 = NMI acknowledge
  138. //6-4 = MDR
  139. //3-0 = CPU (5a22) version
  140. uint8 sCPU::mmio_r4210() {
  141. uint8 r = (regs.mdr & 0x70);
  142. r |= (uint8)(rdnmi()) << 7;
  143. r |= (cpu_version & 0x0f);
  144. return r;
  145. }
  146. //TIMEUP
  147. //7 = IRQ acknowledge
  148. //6-0 = MDR
  149. uint8 sCPU::mmio_r4211() {
  150. uint8 r = (regs.mdr & 0x7f);
  151. r |= (uint8)(timeup()) << 7;
  152. return r;
  153. }
  154. //HVBJOY
  155. //7 = VBLANK acknowledge
  156. //6 = HBLANK acknowledge
  157. //5-1 = MDR
  158. //0 = JOYPAD acknowledge
  159. uint8 sCPU::mmio_r4212() {
  160. uint8 r = (regs.mdr & 0x3e);
  161. uint16 vs = ppu.overscan() == false ? 225 : 240;
  162. //auto joypad polling
  163. if(ppu.vcounter() >= vs && ppu.vcounter() <= (vs + 2))r |= 0x01;
  164. //hblank
  165. if(ppu.hcounter() <= 2 || ppu.hcounter() >= 1096)r |= 0x40;
  166. //vblank
  167. if(ppu.vcounter() >= vs)r |= 0x80;
  168. return r;
  169. }
  170. //RDIO
  171. uint8 sCPU::mmio_r4213() {
  172. return status.pio;
  173. }
  174. //RDDIVL
  175. uint8 sCPU::mmio_r4214() {
  176. if(status.alu_lock) return 0;
  177. return status.r4214;
  178. }
  179. //RDDIVH
  180. uint8 sCPU::mmio_r4215() {
  181. if(status.alu_lock) return 0;
  182. return status.r4214 >> 8;
  183. }
  184. //RDMPYL
  185. uint8 sCPU::mmio_r4216() {
  186. if(status.alu_lock) return 0;
  187. return status.r4216;
  188. }
  189. //RDMPYH
  190. uint8 sCPU::mmio_r4217() {
  191. if(status.alu_lock) return 0;
  192. return status.r4216 >> 8;
  193. }
  194. //TODO: handle reads during joypad polling (v=225-227)
  195. uint8 sCPU::mmio_r4218() { return status.joy1l; } //JOY1L
  196. uint8 sCPU::mmio_r4219() { return status.joy1h; } //JOY1H
  197. uint8 sCPU::mmio_r421a() { return status.joy2l; } //JOY2L
  198. uint8 sCPU::mmio_r421b() { return status.joy2h; } //JOY2H
  199. uint8 sCPU::mmio_r421c() { return status.joy3l; } //JOY3L
  200. uint8 sCPU::mmio_r421d() { return status.joy3h; } //JOY3H
  201. uint8 sCPU::mmio_r421e() { return status.joy4l; } //JOY4L
  202. uint8 sCPU::mmio_r421f() { return status.joy4h; } //JOY4H
  203. //DMAPx
  204. uint8 sCPU::mmio_r43x0(uint8 i) {
  205. return channel[i].dmap;
  206. }
  207. //BBADx
  208. uint8 sCPU::mmio_r43x1(uint8 i) {
  209. return channel[i].destaddr;
  210. }
  211. //A1TxL
  212. uint8 sCPU::mmio_r43x2(uint8 i) {
  213. return channel[i].srcaddr;
  214. }
  215. //A1TxH
  216. uint8 sCPU::mmio_r43x3(uint8 i) {
  217. return channel[i].srcaddr >> 8;
  218. }
  219. //A1Bx
  220. uint8 sCPU::mmio_r43x4(uint8 i) {
  221. return channel[i].srcbank;
  222. }
  223. //DASxL
  224. //union { uint16 xfersize; uint16 hdma_iaddr; };
  225. uint8 sCPU::mmio_r43x5(uint8 i) {
  226. return channel[i].xfersize;
  227. }
  228. //DASxH
  229. //union { uint16 xfersize; uint16 hdma_iaddr; };
  230. uint8 sCPU::mmio_r43x6(uint8 i) {
  231. return channel[i].xfersize >> 8;
  232. }
  233. //DASBx
  234. uint8 sCPU::mmio_r43x7(uint8 i) {
  235. return channel[i].hdma_ibank;
  236. }
  237. //A2AxL
  238. uint8 sCPU::mmio_r43x8(uint8 i) {
  239. return channel[i].hdma_addr;
  240. }
  241. //A2AxH
  242. uint8 sCPU::mmio_r43x9(uint8 i) {
  243. return channel[i].hdma_addr >> 8;
  244. }
  245. //NTRLx
  246. uint8 sCPU::mmio_r43xa(uint8 i) {
  247. return channel[i].hdma_line_counter;
  248. }
  249. //???
  250. uint8 sCPU::mmio_r43xb(uint8 i) {
  251. return channel[i].unknown;
  252. }
  253. //DMAPx
  254. void sCPU::mmio_w43x0(uint8 i, uint8 data) {
  255. channel[i].dmap = data;
  256. channel[i].direction = !!(data & 0x80);
  257. channel[i].hdma_indirect = !!(data & 0x40);
  258. channel[i].reversexfer = !!(data & 0x10);
  259. channel[i].fixedxfer = !!(data & 0x08);
  260. channel[i].xfermode = data & 7;
  261. }
  262. //DDBADx
  263. void sCPU::mmio_w43x1(uint8 i, uint8 data) {
  264. channel[i].destaddr = data;
  265. }
  266. //A1TxL
  267. void sCPU::mmio_w43x2(uint8 i, uint8 data) {
  268. channel[i].srcaddr = (channel[i].srcaddr & 0xff00) | (data);
  269. }
  270. //A1TxH
  271. void sCPU::mmio_w43x3(uint8 i, uint8 data) {
  272. channel[i].srcaddr = (channel[i].srcaddr & 0x00ff) | (data << 8);
  273. }
  274. //A1Bx
  275. void sCPU::mmio_w43x4(uint8 i, uint8 data) {
  276. channel[i].srcbank = data;
  277. }
  278. //DASxL
  279. //union { uint16 xfersize; uint16 hdma_iaddr; };
  280. void sCPU::mmio_w43x5(uint8 i, uint8 data) {
  281. channel[i].xfersize = (channel[i].xfersize & 0xff00) | (data);
  282. }
  283. //DASxH
  284. //union { uint16 xfersize; uint16 hdma_iaddr; };
  285. void sCPU::mmio_w43x6(uint8 i, uint8 data) {
  286. channel[i].xfersize = (channel[i].xfersize & 0x00ff) | (data << 8);
  287. }
  288. //DASBx
  289. void sCPU::mmio_w43x7(uint8 i, uint8 data) {
  290. channel[i].hdma_ibank = data;
  291. }
  292. //A2AxL
  293. void sCPU::mmio_w43x8(uint8 i, uint8 data) {
  294. channel[i].hdma_addr = (channel[i].hdma_addr & 0xff00) | (data);
  295. }
  296. //A2AxH
  297. void sCPU::mmio_w43x9(uint8 i, uint8 data) {
  298. channel[i].hdma_addr = (channel[i].hdma_addr & 0x00ff) | (data << 8);
  299. }
  300. //NTRLx
  301. void sCPU::mmio_w43xa(uint8 i, uint8 data) {
  302. channel[i].hdma_line_counter = data;
  303. }
  304. //???
  305. void sCPU::mmio_w43xb(uint8 i, uint8 data) {
  306. channel[i].unknown = data;
  307. }
  308. void sCPU::mmio_power() {
  309. }
  310. void sCPU::mmio_reset() {
  311. //$2181-$2183
  312. status.wram_addr = 0x000000;
  313. //$4016-$4017
  314. status.joypad_strobe_latch = 0;
  315. status.joypad1_bits = ~0;
  316. status.joypad2_bits = ~0;
  317. //$4200
  318. status.nmi_enabled = false;
  319. status.hirq_enabled = false;
  320. status.virq_enabled = false;
  321. status.auto_joypad_poll = false;
  322. //$4201
  323. status.pio = 0xff;
  324. //$4202-$4203
  325. status.mul_a = 0xff;
  326. status.mul_b = 0xff;
  327. //$4204-$4206
  328. status.div_a = 0xffff;
  329. status.div_b = 0xff;
  330. //$4207-$420a
  331. status.hirq_pos = 0x01ff;
  332. status.virq_pos = 0x01ff;
  333. //$4214-$4217
  334. status.r4214 = 0x0000;
  335. status.r4216 = 0x0000;
  336. //$4218-$421f
  337. status.joy1l = 0x00;
  338. status.joy1h = 0x00;
  339. status.joy2l = 0x00;
  340. status.joy2h = 0x00;
  341. status.joy3l = 0x00;
  342. status.joy3h = 0x00;
  343. status.joy4l = 0x00;
  344. status.joy4h = 0x00;
  345. }
  346. uint8 sCPU::mmio_read(unsigned addr) {
  347. addr &= 0xffff;
  348. //APU
  349. if((addr & 0xffc0) == 0x2140) { //$2140-$217f
  350. scheduler.sync_cpusmp();
  351. return smp.port_read(addr & 3);
  352. }
  353. //DMA
  354. if((addr & 0xff80) == 0x4300) { //$4300-$437f
  355. unsigned i = (addr >> 4) & 7;
  356. switch(addr & 0xf) {
  357. case 0x0: return mmio_r43x0(i);
  358. case 0x1: return mmio_r43x1(i);
  359. case 0x2: return mmio_r43x2(i);
  360. case 0x3: return mmio_r43x3(i);
  361. case 0x4: return mmio_r43x4(i);
  362. case 0x5: return mmio_r43x5(i);
  363. case 0x6: return mmio_r43x6(i);
  364. case 0x7: return mmio_r43x7(i);
  365. case 0x8: return mmio_r43x8(i);
  366. case 0x9: return mmio_r43x9(i);
  367. case 0xa: return mmio_r43xa(i);
  368. case 0xb: return mmio_r43xb(i);
  369. case 0xc: return regs.mdr; //unmapped
  370. case 0xd: return regs.mdr; //unmapped
  371. case 0xe: return regs.mdr; //unmapped
  372. case 0xf: return mmio_r43xb(i); //mirror of $43xb
  373. }
  374. }
  375. switch(addr) {
  376. case 0x2180: return mmio_r2180();
  377. case 0x4016: return mmio_r4016();
  378. case 0x4017: return mmio_r4017();
  379. case 0x4210: return mmio_r4210();
  380. case 0x4211: return mmio_r4211();
  381. case 0x4212: return mmio_r4212();
  382. case 0x4213: return mmio_r4213();
  383. case 0x4214: return mmio_r4214();
  384. case 0x4215: return mmio_r4215();
  385. case 0x4216: return mmio_r4216();
  386. case 0x4217: return mmio_r4217();
  387. case 0x4218: return mmio_r4218();
  388. case 0x4219: return mmio_r4219();
  389. case 0x421a: return mmio_r421a();
  390. case 0x421b: return mmio_r421b();
  391. case 0x421c: return mmio_r421c();
  392. case 0x421d: return mmio_r421d();
  393. case 0x421e: return mmio_r421e();
  394. case 0x421f: return mmio_r421f();
  395. }
  396. return regs.mdr;
  397. }
  398. void sCPU::mmio_write(unsigned addr, uint8 data) {
  399. addr &= 0xffff;
  400. //APU
  401. if((addr & 0xffc0) == 0x2140) { //$2140-$217f
  402. scheduler.sync_cpusmp();
  403. port_write(addr & 3, data);
  404. return;
  405. }
  406. /*custom area*/
  407. if((addr & 0xff00) == 0x3000) { //$3000-$30ff
  408. return;
  409. }
  410. //DMA
  411. if((addr & 0xff80) == 0x4300) { //$4300-$437f
  412. unsigned i = (addr >> 4) & 7;
  413. switch(addr & 0xf) {
  414. case 0x0: mmio_w43x0(i, data); return;
  415. case 0x1: mmio_w43x1(i, data); return;
  416. case 0x2: mmio_w43x2(i, data); return;
  417. case 0x3: mmio_w43x3(i, data); return;
  418. case 0x4: mmio_w43x4(i, data); return;
  419. case 0x5: mmio_w43x5(i, data); return;
  420. case 0x6: mmio_w43x6(i, data); return;
  421. case 0x7: mmio_w43x7(i, data); return;
  422. case 0x8: mmio_w43x8(i, data); return;
  423. case 0x9: mmio_w43x9(i, data); return;
  424. case 0xa: mmio_w43xa(i, data); return;
  425. case 0xb: mmio_w43xb(i, data); return;
  426. case 0xc: return; //unmapped
  427. case 0xd: return; //unmapped
  428. case 0xe: return; //unmapped
  429. case 0xf: mmio_w43xb(i, data); return; //mirror of $43xb
  430. }
  431. }
  432. switch(addr) {
  433. case 0x2180: mmio_w2180(data); return;
  434. case 0x2181: mmio_w2181(data); return;
  435. case 0x2182: mmio_w2182(data); return;
  436. case 0x2183: mmio_w2183(data); return;
  437. case 0x4016: mmio_w4016(data); return;
  438. case 0x4017: return; //unmapped
  439. case 0x4200: mmio_w4200(data); return;
  440. case 0x4201: mmio_w4201(data); return;
  441. case 0x4202: mmio_w4202(data); return;
  442. case 0x4203: mmio_w4203(data); return;
  443. case 0x4204: mmio_w4204(data); return;
  444. case 0x4205: mmio_w4205(data); return;
  445. case 0x4206: mmio_w4206(data); return;
  446. case 0x4207: mmio_w4207(data); return;
  447. case 0x4208: mmio_w4208(data); return;
  448. case 0x4209: mmio_w4209(data); return;
  449. case 0x420a: mmio_w420a(data); return;
  450. case 0x420b: mmio_w420b(data); return;
  451. case 0x420c: mmio_w420c(data); return;
  452. case 0x420d: mmio_w420d(data); return;
  453. }
  454. }
  455. #endif //ifdef SCPU_CPP