aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlec Murphy <alec@checksum.fail>2017-07-09 17:44:53 -0400
committerAlec Murphy <alec@checksum.fail>2017-07-09 17:44:53 -0400
commit24690096e69fdaeb0f98ff810a636b99d860a5ea (patch)
tree3265df3fae00c0d95ae6b5e1920e6805f44283d4
parent750376b125d3e43b1e995596707d94e68ed4c7a7 (diff)
Add SNES gamepad support, adjust PC speaker sound settings
-rwxr-xr-xGamePad.HC16
-rwxr-xr-xKeyboard.HC119
-rw-r--r--Load.HC354
-rw-r--r--README.md30
-rw-r--r--Settings.HC11
-rwxr-xr-xSound.HC48
6 files changed, 412 insertions, 166 deletions
diff --git a/GamePad.HC b/GamePad.HC
new file mode 100755
index 0000000..eb3001a
--- /dev/null
+++ b/GamePad.HC
@@ -0,0 +1,16 @@
+U0 updateGamePad()
+{
+ OutU8(GP_TX_PORT,GP_SNES_POWER|GP_SNES_CLOCK|GP_SNES_LATCH);
+ Sleep(GP_SNES_DELAY*2);
+ OutU8(GP_TX_PORT,GP_SNES_POWER|GP_SNES_CLOCK);
+ gp_ctr=0;
+ while (gp_ctr<12)
+ {
+ Sleep(GP_SNES_DELAY);
+ OutU8(GP_TX_PORT,GP_SNES_POWER);
+ gp_data[gp_ctr]=InU8(GP_RX_PORT)^0x7F;
+ Sleep(GP_SNES_DELAY);
+ OutU8(GP_TX_PORT,GP_SNES_POWER|GP_SNES_CLOCK);
+ gp_ctr++;
+ };
+};
diff --git a/Keyboard.HC b/Keyboard.HC
new file mode 100755
index 0000000..2d3d80f
--- /dev/null
+++ b/Keyboard.HC
@@ -0,0 +1,119 @@
+U0 updateKeyboard()
+{
+ switch(sc)
+ {
+
+ // Reset (kbd only)
+ case 0x13:
+ kReset=0;
+ break;
+ case 0x13 + 0x80:
+ if(!kReset) {
+ kReset=1;
+ StrCpy(DisplayMsg,"Reset");
+ DisplayMsgTicks=1;
+ initEmulator;
+ };
+ break;
+
+ // Set Display Size (kbd only)
+ case 0x02 + 0x80:
+ LCDScale=1;
+ SetLCDScale;
+ break;
+ case 0x03 + 0x80:
+ LCDScale=2;
+ SetLCDScale;
+ break;
+ case 0x04 + 0x80:
+ LCDScale=3;
+ SetLCDScale;
+ break;
+
+ // Exit
+ case 0x01:
+ gp_data[10]=0x40;
+ break;
+ // LoadState
+ case 0x06:
+ gp_data[11]=0x40;
+ break;
+ // SaveState
+ case 0x08:
+ gp_data[9]=0x40;
+ break;
+ // ToggleSound
+ case 0x10:
+ gp_data[8]=0x40;
+ break;
+ // Exit(up)
+ case 0x01 + 0x80:
+ gp_data[10]=0x00;
+ break;
+ // LoadState(up)
+ case 0x06 + 0x80:
+ gp_data[11]=0x00;
+ break;
+ // SaveState(up)
+ case 0x08 + 0x80:
+ gp_data[9]=0x00;
+ break;
+ // ToggleSound(up)
+ case 0x10 + 0x80:
+ gp_data[8]=0x00;
+ break;
+
+ case 0x4D:
+ gp_data[7]=0x40;
+ break;
+ case 0x4B:
+ gp_data[6]=0x40;
+ break;
+ case 0x48:
+ gp_data[4]=0x40;
+ break;
+ case 0x50:
+ gp_data[5]=0x40;
+ break;
+ case 0x1F:
+ gp_data[0]=0x40;
+ break;
+ case 0x1E:
+ gp_data[1]=0x40;
+ break;
+ case 0x2A:
+ gp_data[2]=0x40;
+ break;
+ case 0x1C:
+ gp_data[3]=0x40;
+ break;
+
+ case 0x4D + 0x80:
+ gp_data[7]=0x00;
+ break;
+ case 0x4B + 0x80:
+ gp_data[6]=0x00;
+ break;
+ case 0x48 + 0x80:
+ gp_data[4]=0x00;
+ break;
+ case 0x50 + 0x80:
+ gp_data[5]=0x00;
+ break;
+ case 0x1F + 0x80:
+ gp_data[0]=0x00;
+ break;
+ case 0x1E + 0x80:
+ gp_data[1]=0x00;
+ break;
+ case 0x2A + 0x80:
+ gp_data[2]=0x00;
+ break;
+ case 0x1C + 0x80:
+ gp_data[3]=0x00;
+ break;
+
+ default:
+ break;
+ };
+};
diff --git a/Load.HC b/Load.HC
index fb55fad..6a3630b 100644
--- a/Load.HC
+++ b/Load.HC
@@ -2,6 +2,19 @@ StrCpy(Fs->task_name,"");
StrCpy(Fs->task_title,"");
// Settings
#include "Settings";
+
+#define GP_TX_PORT 0x0378
+#define GP_RX_PORT 0x0379
+
+#define GP_SNES_DELAY 0
+
+#define GP_SNES_POWER 0xFC
+#define GP_SNES_CLOCK 0x01
+#define GP_SNES_LATCH 0x02
+
+U8 gp_data[16];
+I64 gp_ctr;
+
I64 keyCtr=0;
I64 sc=0;
I64 ROMSize=0;
@@ -10,15 +23,17 @@ I64 obp03,obp02,obp01,obp00;
I64 obp13,obp12,obp11,obp10;
I64 jp_state[8];
+I64 exitApp=0;
+
+I64 tdCtr=0;
I64 apuCtr=0;
I64 apuToggle=1;
-I64 kAPUChan1=0;
-I64 kAPUChan2=0;
-I64 kAPUChan3=0;
I64 kLoad=0;
I64 kReset=0;
I64 kSave=0;
+I64 kSnd=0;
+I64 soundMode=2;
I64 DisplayMsgTicks=0;
U8 DisplayMsg[32];
@@ -921,6 +936,9 @@ U0 initEmulator()
registersHL = 0x014D;
}
+#include "GamePad";
+#include "Keyboard";
+
U0 saveState()
{
U8 *statebuf=CAlloc(2048*1024);
@@ -1018,6 +1036,9 @@ U0 runInterrupt()
}
testbit = 1 << ++bitShift;
}
+
+ tdCtr=0;
+ while(tdCtr<frameDelay) { tdCtr++; };
}
// #include "LCD";
@@ -1027,7 +1048,7 @@ U0 updateCore()
if (apuToggle==1)
{
apuCtr++;
- if(apuCtr>1000)
+ if(apuCtr>2000)
{
memory[0xFEED]++;
if(memory[0xFEED]>1) { memory[0xFEED]=0; };
@@ -1058,7 +1079,15 @@ U0 updateCore()
//Emulator Timing (Timed against audio for optimization):
emulatorTicks += audioTicks;
if (emulatorTicks >= machineCyclesPerLoop) {
- sc=InU8(0x60);
+ if (useGamePad==TRUE)
+ {
+ updateGamePad;
+ };
+ if (useKeyboard==TRUE)
+ {
+ sc=InU8(0x60);
+ updateKeyboard;
+ };
//LCD off takes at least 2 frames.
if (drewBlank == 0) {
@@ -1105,7 +1134,7 @@ U0 executeIteration()
//Iterate the interpreter loop:
I64 op = 0;
- while (sc!=1) {
+ while (exitApp!=1) {
//Fetch the current opcode.
op = memoryRead(programCounter);
if (!skipPCIncrement) {
@@ -1132,163 +1161,173 @@ U0 executeIteration()
}
//Timing:
updateCore;
- //Keyboard
-
- switch(sc) {
- case 0x10:
- kAPUChan1=0;
- break;
- case 0x10 + 0x80:
- if(!kAPUChan1) {
- kAPUChan1=1;
- apuToggle=0;
- memory[0xFEED]=0;
- StrCpy(DisplayMsg,"APU Ch 01");
- DisplayMsgTicks=1;
- };
- break;
-
- case 0x11:
- kAPUChan2=0;
- break;
- case 0x11 + 0x80:
- if(!kAPUChan2) {
- kAPUChan2=1;
- apuToggle=0;
- memory[0xFEED]=1;
- StrCpy(DisplayMsg,"APU Ch 02");
- DisplayMsgTicks=1;
- };
- break;
+ if (gp_data[7]==0)
+ {
+ jp_state[0]=FALSE;
+ }
+ else
+ {
+ jp_state[0]=TRUE;
+ };
+ if (gp_data[6]==0)
+ {
+ jp_state[1]=FALSE;
+ }
+ else
+ {
+ jp_state[1]=TRUE;
+ };
+ if (gp_data[4]==0)
+ {
+ jp_state[2]=FALSE;
+ }
+ else
+ {
+ jp_state[2]=TRUE;
+ };
+ if (gp_data[5]==0)
+ {
+ jp_state[3]=FALSE;
+ }
+ else
+ {
+ jp_state[3]=TRUE;
+ };
- case 0x12:
- kAPUChan3=0;
- break;
- case 0x12 + 0x80:
- if(!kAPUChan3) {
- kAPUChan3=1;
- apuToggle=1;
- StrCpy(DisplayMsg,"APU Ch Auto");
- DisplayMsgTicks=1;
- };
- break;
+ if (gp_data[0]==0)
+ {
+ jp_state[4]=FALSE;
+ }
+ else
+ {
+ jp_state[4]=TRUE;
+ };
+ if (gp_data[1]==0)
+ {
+ jp_state[5]=FALSE;
+ }
+ else
+ {
+ jp_state[5]=TRUE;
+ };
+ if (gp_data[2]==0)
+ {
+ jp_state[6]=FALSE;
+ }
+ else
+ {
+ jp_state[6]=TRUE;
+ };
+ if (gp_data[3]==0)
+ {
+ jp_state[7]=FALSE;
+ }
+ else
+ {
+ jp_state[7]=TRUE;
+ };
- case 0x13:
- kReset=0;
- break;
- case 0x13 + 0x80:
- if(!kReset) {
- kReset=1;
- StrCpy(DisplayMsg,"Reset");
- DisplayMsgTicks=1;
- initEmulator;
- };
- break;
+ for (keyCtr=0;keyCtr<8;keyCtr++) {
+ joyPadEvent(keyCtr,jp_state[keyCtr]);
+ };
- case 0x08:
- kSave=0;
- break;
- case 0x08 + 0x80:
- if(!kSave) {
- kSave=1;
- StrCpy(DisplayMsg,"State Saved");
- DisplayMsgTicks=1;
- saveState;
- };
- break;
+ Sleep(0);
+
+ if (gp_data[10]!=0)
+ {
+ exitApp=1;
+ };
- case 0x06:
- kLoad=0;
- break;
- case 0x06 + 0x80:
- if(!kLoad) {
- kLoad=1;
- if (FileFind(StateFile)) {
- StrCpy(DisplayMsg,"State Loaded");
- DisplayMsgTicks=1;
- initEmulator;
- loadState;
- } else {
- StrCpy(DisplayMsg,"No State Found");
- DisplayMsgTicks=1;
- };
- };
- break;
+ if (gp_data[11]!=0)
+ {
+ if(!kLoad)
+ {
+ kLoad=1;
+ if (FileFind(StateFile)) {
+ StrCpy(DisplayMsg,"State Loaded");
+ DisplayMsgTicks=1;
+ initEmulator;
+ loadState;
+ } else {
+ StrCpy(DisplayMsg,"No State Found");
+ DisplayMsgTicks=1;
+ };
+ };
+ }
+ else
+ {
+ kLoad=0;
+ };
- case 0x02 + 0x80:
- LCDScale=1;
- SetLCDScale;
- break;
- case 0x03 + 0x80:
- LCDScale=2;
- SetLCDScale;
- break;
- case 0x04 + 0x80:
- LCDScale=3;
- SetLCDScale;
- break;
- case 0x4D:
- joyPadState(0,TRUE);
- joyPadState(1,FALSE);
- break;
- case 0x4B:
- joyPadState(1,TRUE);
- joyPadState(0,FALSE);
- break;
- case 0x48:
- joyPadState(2,TRUE);
- joyPadState(3,FALSE);
- break;
- case 0x50:
- joyPadState(3,TRUE);
- joyPadState(2,FALSE);
- break;
- case 0x1F:
- joyPadState(4,TRUE);
- break;
- case 0x1E:
- joyPadState(5,TRUE);
- break;
- case 0x2A:
- joyPadState(6,TRUE);
- break;
- case 0x1C:
- joyPadState(7,TRUE);
- break;
- case 0x4D + 0x80:
- joyPadState(0,FALSE);
- break;
- case 0x4B + 0x80:
- joyPadState(1,FALSE);
- break;
- case 0x48 + 0x80:
- joyPadState(2,FALSE);
- break;
- case 0x50 + 0x80:
- joyPadState(3,FALSE);
- break;
- case 0x1F + 0x80:
- joyPadState(4,FALSE);
- break;
- case 0x1E + 0x80:
- joyPadState(5,FALSE);
- break;
- case 0x2A + 0x80:
- joyPadState(6,FALSE);
- break;
- case 0x1C + 0x80:
- joyPadState(7,FALSE);
- break;
- default:
- break;
+ if (gp_data[9]!=0)
+ {
+ if(!kSave) {
+ kSave=1;
+ StrCpy(DisplayMsg,"State Saved");
+ DisplayMsgTicks=1;
+ saveState;
+ };
+ }
+ else
+ {
+ kSave=0;
};
- for (keyCtr=0;keyCtr<8;keyCtr++) {
- joyPadEvent(keyCtr,jp_state[keyCtr]);
+ if (gp_data[8]!=0)
+ {
+ if(!kSnd) {
+ kSnd=1;
+ soundMode++;
+ if (soundMode>3)
+ {
+ soundMode=0;
+ };
+
+ if (soundMode==0)
+ {
+ StrCpy(DisplayMsg,"Snd Ch01");
+ };
+ if (soundMode==1)
+ {
+ StrCpy(DisplayMsg,"Snd Ch02");
+ };
+ if (soundMode==2)
+ {
+ StrCpy(DisplayMsg,"Snd Auto");
+ };
+ if (soundMode==3)
+ {
+ StrCpy(DisplayMsg,"Snd Off");
+ };
+
+ DisplayMsgTicks=1;
+ };
+ }
+ else
+ {
+ kSnd=0;
};
- Sleep(0);
+ if (soundMode==0)
+ {
+ apuToggle=0;
+ memory[0xFEED]=0;
+ };
+ if (soundMode==1)
+ {
+ apuToggle=0;
+ memory[0xFEED]=1;
+ };
+ if (soundMode==2)
+ {
+ apuToggle=1;
+ };
+ if (soundMode==3)
+ {
+ memory[0xFEED]=128;
+ apuToggle=0;
+ };
};
}
@@ -1348,6 +1387,15 @@ U0 start()
for (keyCtr=0;keyCtr<8;keyCtr++) {
jp_state[keyCtr]=0;
};
+
+ gp_ctr=0;
+ while(gp_ctr<12)
+ {
+ gp_data[gp_ctr]=0;
+ gp_ctr++;
+ };
+ gp_ctr=0;
+
SettingsPush;
DocClear;
DCFill(lcd,15);
diff --git a/README.md b/README.md
index ac831f4..1d0f45a 100644
--- a/README.md
+++ b/README.md
@@ -9,7 +9,29 @@ Z80 Core and timing routines ported from [PHP Terminal GameBoy Emulator](https:/
Put ROM files in `Roms` folder, and `#include "Run";`
-# Controls
+You can connect a SNES gamepad w/ adapter to the parallel port. Enable gamepad in `Settings.HC` with `useGamePad=TRUE;`
+
+# Gamepad Controls
+
+D-PAD: D-PAD
+
+B: `Y`
+
+A: `B`
+
+Select: `SELECT`
+
+Start: `START`
+
+Exit: `L`
+
+Load State: `R`
+
+Save State: `X`
+
+Toggle Sound: `A`
+
+# Keyboard Controls
D-PAD: `ARROW KEYS`
@@ -31,9 +53,5 @@ Load State: `5`
Save State: `7`
-Sound Channel 1: `Q`
-
-Sound Channel 2: `W`
-
-Sound Channel Auto Toggle: `E`
+Toggle Sound: `Q`
diff --git a/Settings.HC b/Settings.HC
index a696eec..6e77b53 100644
--- a/Settings.HC
+++ b/Settings.HC
@@ -3,12 +3,13 @@ I64 audioGranularity = 20;
//Auto Frame Skip
I64 autoFrameskip = TRUE;
-//Colorize GB mode? **No CGB support**
-I64 colorize = FALSE;
+I64 frameDelay = 120;
-//Keyboard button map. **Not implemented yet**
-//Order: Right, Left, Up, Down, A, B, Select, Start
-I64 keyboardButtonMap[8] = {'d', 'a', 'w', 's', ',', '.', 'n', 'm'};
+// Sound modes: 0 (Ch 01), 1 (Ch 02), 2 (Auto), 3 (Off)
+I64 soundMode=2;
+
+I64 useKeyboard=TRUE;
+I64 useGamePad=TRUE;
I64 LCDScale=3;
diff --git a/Sound.HC b/Sound.HC
index 45dd9e8..7d76086 100755
--- a/Sound.HC
+++ b/Sound.HC
@@ -1,5 +1,11 @@
U0 GBSoundTask(U8 *regs)
{
+
+ I64 frmCtr=0;
+ I64 restCtrA=0;
+ I64 restCtrB=0;
+ I64 restA=0;
+ I64 restB=0;
I64 div;
I64 freq;
I64 x;
@@ -9,9 +15,9 @@ U0 GBSoundTask(U8 *regs)
while (TRUE)
{
-
if(memory[0xFEED]==0)
{
+ restA=1;
if (memory[0xFF12]>0b10000)
{
x = memory[0xFF13];
@@ -28,13 +34,29 @@ U0 GBSoundTask(U8 *regs)
OutU8(0x42, div>>8);
OutU8(0x61,3|InU8(0x61));
prevA=x;
+ restA=0;
+ restCtrA=0;
};
} else {
};
+
+ if (restA==1)
+ {
+ restCtrA++;
+ if (restCtrA>30000)
+ {
+ SndRst;
+ SndRst;
+ restCtrA=0;
+ //prevB=0;
+ };
+ };
+
};
if(memory[0xFEED]==1)
{
+ restB=1;
if (memory[0xFF17]>0b10000)
{
x = memory[0xFF18];
@@ -48,11 +70,33 @@ U0 GBSoundTask(U8 *regs)
OutU8(0x42, div>>8);
OutU8(0x61,3|InU8(0x61));
prevB=x;
+ restB=0;
+ restCtrB=0;
};
} else {
};
+
+ if (restB==1)
+ {
+ restCtrB++;
+ if (restCtrB>30000)
+ {
+ SndRst;
+ SndRst;
+ restCtrB=0;
+ //prevA=0;
+ };
+ };
+
};
- Sleep(2);
+ if(memory[0xFEED]==128)
+ {
+ SndRst;
+ };
+
+
+ frmCtr=0;
+ while(frmCtr<30000){frmCtr++;};
};
}