diff --git a/console.html b/console.html
index c8dba709..f32338c7 100644
--- a/console.html
+++ b/console.html
@@ -12,6 +12,7 @@
+
diff --git a/index.html b/index.html
index ded90968..87672ffc 100644
--- a/index.html
+++ b/index.html
@@ -15,6 +15,7 @@
+
diff --git a/js/gba.js b/js/gba.js
index 6dadb17e..5e55628e 100644
--- a/js/gba.js
+++ b/js/gba.js
@@ -18,6 +18,7 @@ function GameBoyAdvance() {
this.audio = new GameBoyAdvanceAudio();
this.video = new GameBoyAdvanceVideo();
this.keypad = new GameBoyAdvanceKeypad();
+ this.sio = new GameBoyAdvanceSIO();
// TODO: simplify this graph
this.cpu.mmu = this.mmu;
@@ -36,6 +37,7 @@ function GameBoyAdvance() {
this.io.audio = this.audio;
this.io.video = this.video;
this.io.keypad = this.keypad;
+ this.io.sio = this.sio;
this.io.core = this;
this.audio.cpu = this.cpu;
@@ -46,6 +48,8 @@ function GameBoyAdvance() {
this.keypad.core = this;
+ this.sio.core = this;
+
this.keypad.registerHandlers();
this.doStep = this.waitFrame;
this.paused = false;
@@ -131,6 +135,7 @@ GameBoyAdvance.prototype.reset = function() {
this.io.clear();
this.audio.clear();
this.video.clear();
+ this.sio.clear();
this.mmu.mmap(this.mmu.REGION_IO, this.io);
this.mmu.mmap(this.mmu.REGION_PALETTE_RAM, this.video.renderPath.palette);
diff --git a/js/io.js b/js/io.js
index 7d45e2ad..7737ba43 100644
--- a/js/io.js
+++ b/js/io.js
@@ -108,8 +108,9 @@ function GameBoyAdvanceIO() {
this.TM3CNT_HI = 0x10E;
// SIO (note: some of these are repeated)
- this.SIODATA32 = 0x120;
+ this.SIODATA32_LO = 0x120;
this.SIOMULTI0 = 0x120;
+ this.SIODATA32_HI = 0x122;
this.SIOMULTI1 = 0x122;
this.SIOMULTI2 = 0x124;
this.SIOMULTI3 = 0x126;
@@ -139,14 +140,7 @@ function GameBoyAdvanceIO() {
this.DEFAULT_SOUNDBIAS = 0x200;
this.DEFAULT_BGPA = 1;
this.DEFAULT_BGPD = 1;
-};
-
-GameBoyAdvanceIO.prototype.setCPU = function(cpu) {
- this.cpu = cpu;
-};
-
-GameBoyAdvanceIO.prototype.setVideo = function(video) {
- this.video = video;
+ this.DEFAULT_RCNT = 0x8000;
};
GameBoyAdvanceIO.prototype.clear = function() {
@@ -158,6 +152,7 @@ GameBoyAdvanceIO.prototype.clear = function() {
this.registers[this.BG2PD >> 1] = this.DEFAULT_BGPD;
this.registers[this.BG3PA >> 1] = this.DEFAULT_BGPA;
this.registers[this.BG3PD >> 1] = this.DEFAULT_BGPD;
+ this.registers[this.RCNT >> 1] = this.RCNT;
};
GameBoyAdvanceIO.prototype.freeze = function() {
@@ -232,6 +227,8 @@ GameBoyAdvanceIO.prototype.loadU16 = function(offset) {
case this.DMA1CNT_HI:
case this.DMA2CNT_HI:
case this.DMA3CNT_HI:
+ case this.RCNT:
+ case this.SIOCNT:
case this.WAITCNT:
case this.IE:
case this.IF:
@@ -274,13 +271,6 @@ GameBoyAdvanceIO.prototype.loadU16 = function(offset) {
case this.TM3CNT_LO:
return this.cpu.irq.timerRead(3);
- case this.RCNT:
- this.core.STUB('Reading from unimplemented RCNT');
- return 0x8000;
- case this.SIOCNT:
- this.core.STUB('Reading from unimplemented SIOCNT');
- return 0;
-
case this.KEYINPUT:
return this.keypad.currentDown;
case this.KEYCNT:
@@ -722,10 +712,12 @@ GameBoyAdvanceIO.prototype.store16 = function(offset, value) {
this.STUB_REG('SIO', offset);
break;
case this.RCNT:
- this.STUB_REG('RCNT', offset);
+ this.sio.setMode(((value >> 12) & 0xC) | ((this.registers[this.SIOCNT >> 1] >> 12) & 0x3));
+ this.sio.writeRCNT(value);
break;
case this.SIOCNT:
- this.STUB_REG('SIOCNT', offset);
+ this.sio.setMode(((value >> 12) & 0x3) | ((this.registers[this.RCNT >> 1] >> 12) & 0xC));
+ this.sio.writeSIOCNT(value);
break;
case this.JOYCNT:
case this.JOYSTAT:
diff --git a/js/sio.js b/js/sio.js
new file mode 100644
index 00000000..a52c6b0a
--- /dev/null
+++ b/js/sio.js
@@ -0,0 +1,54 @@
+function GameBoyAdvanceSIO() {
+ this.SIO_NORMAL_8 = 0;
+ this.SIO_NORMAL_32 = 1;
+ this.SIO_MULTI = 2;
+ this.SIO_UART = 3;
+ this.SIO_GPIO = 8;
+ this.SIO_JOYBUS = 12;
+}
+
+GameBoyAdvanceSIO.prototype.clear = function() {
+ this.mode = this.SIO_GPIO;
+};
+
+GameBoyAdvanceSIO.prototype.setMode = function(mode) {
+ if (mode & 0x8) {
+ mode &= 0xC;
+ } else {
+ mode &= 0x3;
+ }
+ this.mode = mode;
+
+ this.core.INFO('Setting SIO mode to ' + hex(mode, 1));
+};
+
+GameBoyAdvanceSIO.prototype.writeRCNT = function(value) {
+ if (mode != this.SIO_GPIO) {
+ return;
+ }
+
+ this.core.STUB('General purpose serial not supported');
+};
+
+GameBoyAdvanceSIO.prototype.writeSIOCNT = function(value) {
+ switch (this.mode) {
+ case this.SIO_NORMAL_8:
+ this.core.STUB('8-bit transfer unsupported');
+ break;
+ case this.SIO_NORMAL_32:
+ this.core.STUB('32-bit transfer unsupported');
+ break;
+ case this.SIO_MULTI:
+ this.core.STUB('Multiplayer unsupported');
+ break;
+ case this.SIO_UART:
+ this.core.STUB('UART unsupported');
+ break;
+ case this.SIO_GPIO:
+ // Nothing to do
+ break;
+ case this.SIO_JOYBUS:
+ this.core.STUB('JOY BUS unsupported');
+ break;
+ }
+};
\ No newline at end of file