O2Hawk start
This commit is contained in:
parent
41caf0e616
commit
520ba97caa
|
@ -305,7 +305,6 @@ sha1:17473C223453D2D80FCB9DCFA317947287DC5C52 Xing He Zhan Shi (China) (Unl) NE
|
|||
sha1:B1C74236FD17FAB4AB9AA6AB28E38864C66D6255 Pocahontus (UNL) NES board=MAPPER182;PRG=256;CHR=256;WRAM=8;PAD_H=1
|
||||
sha1:5FA23F88432006DCF6874EA36E9E7DA8934427BE Super Donkey Kong (Unl) NES board=MAPPER182;PRG=128;CHR=128;WRAM=8;PAD_H=1
|
||||
sha1:8A7DAB8B78DA1C5EA159BA9EEC00FF97742245F1 B Super Donkey Kong (Unl) [b1] NES board=MAPPER182;PRG=128;CHR=128;WRAM=8;PAD_H=1
|
||||
sha1:8A7DAB8B78DA1C5EA159BA9EEC00FF97742245F1 O Super Donkey Kong (Unl) [o1] NES board=MAPPER182;PRG=128;CHR=128;WRAM=8;PAD_H=1
|
||||
|
||||
;wrong vram info
|
||||
sha1:32D71DD6C5A8D78A918FE1B9D6D6C4A570D9652D Oeka Kids Anpanman no Hiragana Daisuki (J) NES board=MAPPER096;VRAM=32
|
||||
|
|
|
@ -709,6 +709,38 @@
|
|||
</Compile>
|
||||
<Compile Include="Consoles\Intellivision\PSG.cs" />
|
||||
<Compile Include="Consoles\Intellivision\STIC.cs" />
|
||||
<Compile Include="Consoles\Magnavox\Odyssey2\Audio.cs" />
|
||||
<Compile Include="Consoles\Magnavox\Odyssey2\O2Hawk.cs" />
|
||||
<Compile Include="Consoles\Magnavox\Odyssey2\O2Hawk.ICodeDataLog.cs" />
|
||||
<Compile Include="Consoles\Magnavox\Odyssey2\O2Hawk.IDebuggable.cs">
|
||||
<DependentUpon>O2Hawk.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Consoles\Magnavox\Odyssey2\O2Hawk.IEmulator.cs">
|
||||
<DependentUpon>O2Hawk.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Consoles\Magnavox\Odyssey2\O2Hawk.IInputPollable.cs">
|
||||
<DependentUpon>O2Hawk.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Consoles\Magnavox\Odyssey2\O2Hawk.IMemoryDomains.cs">
|
||||
<DependentUpon>O2Hawk.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Consoles\Magnavox\Odyssey2\O2Hawk.ISaveRam.cs">
|
||||
<DependentUpon>O2Hawk.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Consoles\Magnavox\Odyssey2\O2Hawk.ISettable.cs">
|
||||
<DependentUpon>O2Hawk.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Consoles\Magnavox\Odyssey2\O2Hawk.IStatable.cs">
|
||||
<DependentUpon>O2Hawk.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Consoles\Magnavox\Odyssey2\O2HawkControllerDeck.cs" />
|
||||
<Compile Include="Consoles\Magnavox\Odyssey2\O2HawkControllers.cs" />
|
||||
<Compile Include="Consoles\Magnavox\Odyssey2\HW_Registers.cs" />
|
||||
<Compile Include="Consoles\Magnavox\Odyssey2\Mappers\MapperBase.cs" />
|
||||
<Compile Include="Consoles\Magnavox\Odyssey2\Mappers\Mapper_Default.cs" />
|
||||
<Compile Include="Consoles\Magnavox\Odyssey2\MemoryMap.cs" />
|
||||
<Compile Include="Consoles\Magnavox\Odyssey2\PPU.cs" />
|
||||
<Compile Include="Consoles\Magnavox\Odyssey2\SerialPort.cs" />
|
||||
<Compile Include="Consoles\Magnavox\LibO2Em.cs" />
|
||||
<Compile Include="Consoles\Magnavox\O2Em.cs" />
|
||||
<Compile Include="Consoles\NEC\PCFX\LibTst.cs" />
|
||||
|
@ -1607,6 +1639,13 @@
|
|||
<Compile Include="CPUs\MC6800\Operations.cs" />
|
||||
<Compile Include="CPUs\MC6800\OP_Tables.cs" />
|
||||
<Compile Include="CPUs\MC6800\Registers.cs" />
|
||||
<Compile Include="CPUs\Intel8048\Disassembler.cs" />
|
||||
<Compile Include="CPUs\Intel8048\Execute.cs" />
|
||||
<Compile Include="CPUs\Intel8048\Interrupts.cs" />
|
||||
<Compile Include="CPUs\Intel8048\I8048.cs" />
|
||||
<Compile Include="CPUs\Intel8048\Operations.cs" />
|
||||
<Compile Include="CPUs\Intel8048\OP_Tables.cs" />
|
||||
<Compile Include="CPUs\Intel8048\Registers.cs" />
|
||||
<Compile Include="CPUs\MC6809\Execute.cs" />
|
||||
<Compile Include="CPUs\MC6809\Interrupts.cs" />
|
||||
<Compile Include="CPUs\MC6809\MC6809.cs" />
|
||||
|
|
|
@ -0,0 +1,494 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace BizHawk.Emulation.Common.Components.I8048
|
||||
{
|
||||
public sealed partial class I8048
|
||||
{
|
||||
static string[] table =
|
||||
{
|
||||
"NEG DP+i8", // 00
|
||||
"???", // 01
|
||||
"???", // 02
|
||||
"COM DP+i8", // 03
|
||||
"LSR DP+i8", // 04
|
||||
"???", // 05
|
||||
"ROR DP+i8", // 06
|
||||
"ASR DP+i8", // 07
|
||||
"ASL DP+i8", // 08
|
||||
"ROL DP+i8", // 09
|
||||
"DEC DP+i8", // 0a
|
||||
"???", // 0b
|
||||
"INC DP+i8", // 0c
|
||||
"TST DP+i8", // 0d
|
||||
"JMP DP+i8", // 0e
|
||||
"CLR DP+i8", // 0f
|
||||
"PAGE 2", // 10
|
||||
"PAGE 3", // 11
|
||||
"NOP", // 12
|
||||
"SYNC", // 13
|
||||
"???", // 14
|
||||
"???", // 15
|
||||
"LBRA i16", // 16
|
||||
"LBSR i16", // 17
|
||||
"???", // 18
|
||||
"DAA", // 19
|
||||
"ORCC i8", // 1a
|
||||
"???", // 1b
|
||||
"ANDCC i8", // 1c
|
||||
"SEX", // 1d
|
||||
"EXG i8", // 1e
|
||||
"TFR i8", // 1f
|
||||
"BRA i8", // 20
|
||||
"BRN i8", // 21
|
||||
"BHI i8", // 22
|
||||
"BLS i8", // 23
|
||||
"BHS i8", // 24
|
||||
"BLO i8", // 25
|
||||
"BNE i8", // 26
|
||||
"BEQ i8", // 27
|
||||
"BVC i8", // 28
|
||||
"BVS i8", // 29
|
||||
"BPL i8", // 2a
|
||||
"BMI i8", // 2b
|
||||
"BGE i8", // 2c
|
||||
"BLT i8", // 2d
|
||||
"BGT i8", // 2e
|
||||
"BLE i8", // 2f
|
||||
"LEAX ix16", // 30
|
||||
"LEAY ix16", // 31
|
||||
"LEAS ix16", // 32
|
||||
"LEAU ix16", // 33
|
||||
"PSHS i8", // 34
|
||||
"PULS i8", // 35
|
||||
"PSHU i8", // 36
|
||||
"PULU i8", // 37
|
||||
"???", // 38
|
||||
"RTS", // 39
|
||||
"ABX", // 3a
|
||||
"RTI", // 3b
|
||||
"CWAI i8", // 3c
|
||||
"MUL", // 3d
|
||||
"???", // 3e
|
||||
"SWI1", // 3f
|
||||
"NEG A", // 40
|
||||
"???", // 41
|
||||
"???", // 42
|
||||
"COM A", // 43
|
||||
"LSR A", // 44
|
||||
"???", // 45
|
||||
"ROR A", // 46
|
||||
"ASR A", // 47
|
||||
"ASL A", // 48
|
||||
"ROL A", // 49
|
||||
"DEC A", // 4a
|
||||
"???", // 4b
|
||||
"INC A", // 4c
|
||||
"TST A", // 4d
|
||||
"???", // 4e
|
||||
"CLR A", // 4f
|
||||
"NEG B", // 50
|
||||
"???", // 51
|
||||
"???", // 52
|
||||
"COM B", // 53
|
||||
"LSR B", // 54
|
||||
"???", // 55
|
||||
"ROR B", // 56
|
||||
"ASR B", // 57
|
||||
"ASL B", // 58
|
||||
"ROL B", // 59
|
||||
"DEC B", // 5a
|
||||
"???", // 5b
|
||||
"INC B", // 5c
|
||||
"TST B", // 5d
|
||||
"???", // 5e
|
||||
"CLR B", // 5f
|
||||
"NEG ix16", // 60
|
||||
"???", // 61
|
||||
"???", // 62
|
||||
"COM ix16", // 63
|
||||
"LSR ix16", // 64
|
||||
"???", // 65
|
||||
"ROR ix16", // 66
|
||||
"ASR ix16", // 67
|
||||
"ASL ix16", // 68
|
||||
"ROL ix16", // 69
|
||||
"DEC ix16", // 6a
|
||||
"???", // 6b
|
||||
"INC ix16", // 6c
|
||||
"TST ix16", // 6d
|
||||
"JMP ix16", // 6e
|
||||
"CLR ix16", // 6f
|
||||
"NEG ex16", // 70
|
||||
"???", // 71
|
||||
"???", // 72
|
||||
"COM ex16", // 73
|
||||
"LSR ex16", // 74
|
||||
"???", // 75
|
||||
"ROR ex16", // 76
|
||||
"ASR ex16", // 77
|
||||
"ASL ex16", // 78
|
||||
"ROL ex16", // 79
|
||||
"DEC ex16", // 7a
|
||||
"???", // 7b
|
||||
"INC ex16", // 7c
|
||||
"TST ex16", // 7d
|
||||
"JMP ex16", // 7e
|
||||
"CLR ex16", // 7f
|
||||
"SUB A,i8", // 80
|
||||
"CMP A,i8", // 81
|
||||
"SBC A,i8", // 82
|
||||
"SUB D,i16", // 83
|
||||
"AND A,i8", // 84
|
||||
"BIT A,i8", // 85
|
||||
"LD A,i8", // 86
|
||||
"???", // 87
|
||||
"EOR A,i8", // 88
|
||||
"ADC A,i8", // 89
|
||||
"OR A,i8", // 8a
|
||||
"ADD A,i8", // 8b
|
||||
"CMP X,i16", // 8c
|
||||
"BSR i8", // 8d
|
||||
"LD X,i16", // 8e
|
||||
"???", // 8f
|
||||
"SUB A,DP+i8", // 90
|
||||
"CMP A,DP+i8", // 91
|
||||
"SBC A,DP+i8", // 92
|
||||
"SUB D,DP+i8", // 93
|
||||
"AND A,DP+i8", // 94
|
||||
"BIT A,DP+i8", // 95
|
||||
"LD A,DP+i8", // 96
|
||||
"ST A,DP+i8", // 97
|
||||
"EOR A,DP+i8", // 98
|
||||
"ADC A,DP+i8", // 99
|
||||
"OR A,DP+i8", // 9a
|
||||
"ADD A,DP+i8", // 9b
|
||||
"CMP X,DP+i8", // 9c
|
||||
"JSR DP+i8", // 9d
|
||||
"LD X,DP+i8", // 9e
|
||||
"ST X,DP+i8", // 9f
|
||||
"SUB A,ix16", // a0
|
||||
"CMP A,ix16", // a1
|
||||
"SBC A,ix16", // a2
|
||||
"SUB D,ix16", // a3
|
||||
"AND A,ix16", // a4
|
||||
"BIT A,ix16", // a5
|
||||
"LD A,ix16", // a6
|
||||
"ST A,ix16", // a7
|
||||
"EOR A,ix16", // a8
|
||||
"ADC A,ix16", // a9
|
||||
"OR A,ix16", // aa
|
||||
"ADD A,ix16", // ab
|
||||
"CMP X,ix16", // ac
|
||||
"JSR ix16", // ad
|
||||
"LD X,ix16", // ae
|
||||
"ST X,ix16", // af
|
||||
"SUB A,ex16", // b0
|
||||
"CMP A,ex16", // b1
|
||||
"SBC A,ex16", // b2
|
||||
"SUB D,ex16", // b3
|
||||
"AND A,ex16", // b4
|
||||
"BIT A,ex16", // b5
|
||||
"LD A,ex16", // b6
|
||||
"ST A,ex16", // b7
|
||||
"EOR A,ex16", // b8
|
||||
"ADC A,ex16", // b9
|
||||
"OR A,ex16", // ba
|
||||
"ADD A,ex16", // bb
|
||||
"CMP X,ex16", // bc
|
||||
"JSR ex16", // bd
|
||||
"LD X,ex16", // be
|
||||
"ST X,ex16", // bf
|
||||
"SUB B,i8", // c0
|
||||
"CMP B,i8", // c1
|
||||
"SBC B,i8", // c2
|
||||
"ADD D,i16", // c3
|
||||
"AND B,i8", // c4
|
||||
"BIT B,i8", // c5
|
||||
"LD B,i8", // c6
|
||||
"???", // c7
|
||||
"EOR B,i8", // c8
|
||||
"ADC B,i8", // c9
|
||||
"OR B,i8", // ca
|
||||
"ADD B,i8", // cb
|
||||
"LD D,i16", // cc
|
||||
"???", // cd
|
||||
"LD U,i16", // ce
|
||||
"???", // cf
|
||||
"SUB B,DP+i8", // d0
|
||||
"CMP B,DP+i8", // d1
|
||||
"SBC B,DP+i8", // d2
|
||||
"ADD D,DP+i8", // d3
|
||||
"AND B,DP+i8", // d4
|
||||
"BIT B,DP+i8", // d5
|
||||
"LD B,DP+i8", // d6
|
||||
"ST B,DP+i8", // d7
|
||||
"EOR B,DP+i8", // d8
|
||||
"ADC B,DP+i8", // d9
|
||||
"OR B,DP+i8", // da
|
||||
"ADD B,DP+i8", // db
|
||||
"LD D,DP+i8", // dc
|
||||
"ST D,DP+i8", // dd
|
||||
"LD U,DP+i8", // de
|
||||
"ST U,DP+i8", // df
|
||||
"SUB B,ix16", // e0
|
||||
"CMP B,ix16", // e1
|
||||
"SBC B,ix16", // e2
|
||||
"ADD D,ix16", // e3
|
||||
"AND B,ix16", // e4
|
||||
"BIT B,ix16", // e5
|
||||
"LD B,ix16", // e6
|
||||
"ST B,ix16", // e7
|
||||
"EOR B,ix16", // e8
|
||||
"ADC B,ix16", // e9
|
||||
"OR B,ix16", // ea
|
||||
"ADD B,ix16", // eb
|
||||
"LD D,ix16", // ec
|
||||
"ST D,ix16", // ed
|
||||
"LD U,ix16", // ee
|
||||
"ST U,ix16", // ef
|
||||
"SUB B,ex16", // f0
|
||||
"CMP B,ex16", // f1
|
||||
"SBC B,ex16", // f2
|
||||
"ADD D,ex16", // f3
|
||||
"AND B,ex16", // f4
|
||||
"BIT B,ex16", // f5
|
||||
"LD B,ex16", // f6
|
||||
"ST B,ex16", // f7
|
||||
"EOR B,ex16", // f8
|
||||
"ADC B,ex16", // f9
|
||||
"OR B,ex16", // fa
|
||||
"ADD B,ex16", // fb
|
||||
"LD D,ex16", // fc
|
||||
"ST D,ex16", // fd
|
||||
"LD U,ex16", // fe
|
||||
"ST U,ex16", // ff
|
||||
};
|
||||
|
||||
public static string Disassemble(ushort addr, Func<ushort, byte> reader, out ushort size)
|
||||
{
|
||||
ushort origaddr = addr;
|
||||
List<byte> bytes = new List<byte>();
|
||||
bytes.Add(reader(addr++));
|
||||
|
||||
string result = table[bytes[0]];
|
||||
|
||||
if (result.Contains("i8"))
|
||||
{
|
||||
byte d = reader(addr++);
|
||||
bytes.Add(d);
|
||||
result = result.Replace("i8", string.Format("#{0:X2}h", d));
|
||||
}
|
||||
else if (result.Contains("i16"))
|
||||
{
|
||||
byte dhi = reader(addr++);
|
||||
byte dlo = reader(addr++);
|
||||
bytes.Add(dhi);
|
||||
bytes.Add(dlo);
|
||||
result = result.Replace("i16", string.Format("#{0:X2}{1:X2}h", dhi, dlo));
|
||||
}
|
||||
else if (result.Contains("ex16"))
|
||||
{
|
||||
byte dhi = reader(addr++);
|
||||
byte dlo = reader(addr++);
|
||||
bytes.Add(dhi);
|
||||
bytes.Add(dlo);
|
||||
result = result.Replace("ex16", "(" + string.Format("#{0:X2}{1:X2}h", dhi, dlo) + ")");
|
||||
}
|
||||
else if (result.Contains("ix16"))
|
||||
{
|
||||
byte d = reader(addr++);
|
||||
bytes.Add(d);
|
||||
|
||||
string temp_reg = "";
|
||||
|
||||
switch ((d >> 5) & 3)
|
||||
{
|
||||
case 0: temp_reg = "X"; break;
|
||||
case 1: temp_reg = "Y"; break;
|
||||
case 2: temp_reg = "US"; break;
|
||||
case 3: temp_reg = "SP"; break;
|
||||
}
|
||||
|
||||
if ((d & 0x80) == 0)
|
||||
{
|
||||
short tempdis = (short)(d & 0x1F);
|
||||
if (tempdis >= 16)
|
||||
tempdis -= 32;
|
||||
|
||||
result = result.Replace("ix16", temp_reg + " + ea");
|
||||
result = result.Replace("ea", string.Format("{0:N}h", tempdis));
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((d & 0x10) == 0x10)
|
||||
{
|
||||
switch (d & 0xF)
|
||||
{
|
||||
case 0x0:
|
||||
result = result.Replace("ix16", "???");
|
||||
break;
|
||||
case 0x1:
|
||||
result = result.Replace("ix16","(" + temp_reg + ")++");
|
||||
break;
|
||||
case 0x2:
|
||||
result = result.Replace("ix16", "???");
|
||||
break;
|
||||
case 0x3:
|
||||
result = result.Replace("ix16", "--(" + temp_reg + ")");
|
||||
break;
|
||||
case 0x4:
|
||||
result = result.Replace("ix16", "(" + temp_reg + ")");
|
||||
break;
|
||||
case 0x5:
|
||||
result = result.Replace("ix16", "(" + temp_reg + " + B)");
|
||||
break;
|
||||
case 0x6:
|
||||
result = result.Replace("ix16", "(" + temp_reg + " + A)");
|
||||
break;
|
||||
case 0x7:
|
||||
result = result.Replace("ix16", "???");
|
||||
break;
|
||||
case 0x8:
|
||||
byte e = reader(addr++);
|
||||
bytes.Add(e);
|
||||
result = result.Replace("ix16", "(" + temp_reg + " + ea)");
|
||||
result = result.Replace("ea", string.Format("{0:X2}h", e));
|
||||
break;
|
||||
case 0x9:
|
||||
byte f = reader(addr++);
|
||||
bytes.Add(f);
|
||||
byte g = reader(addr++);
|
||||
bytes.Add(g);
|
||||
result = result.Replace("ix16", "(" + temp_reg + " + ea)");
|
||||
result = result.Replace("ea", string.Format("{0:X2}{1:X2}h", f, g));
|
||||
break;
|
||||
case 0xA:
|
||||
result = result.Replace("ix16", "???");
|
||||
break;
|
||||
case 0xB:
|
||||
result = result.Replace("ix16", "(" + temp_reg + " + D)");
|
||||
break;
|
||||
case 0xC:
|
||||
temp_reg = "PC";
|
||||
byte h = reader(addr++);
|
||||
bytes.Add(h);
|
||||
result = result.Replace("ix16", "(" + temp_reg + " + ea)");
|
||||
result = result.Replace("ea", string.Format("{0:X2}h", h));
|
||||
break;
|
||||
case 0xD:
|
||||
temp_reg = "PC";
|
||||
byte i = reader(addr++);
|
||||
bytes.Add(i);
|
||||
byte j = reader(addr++);
|
||||
bytes.Add(j);
|
||||
result = result.Replace("ix16", "(" + temp_reg + " + ea)");
|
||||
result = result.Replace("ea", string.Format("{0:X2}{1:X2}h", i, j));
|
||||
break;
|
||||
case 0xE:
|
||||
result = result.Replace("ix16", "???");
|
||||
break;
|
||||
case 0xF:
|
||||
if (((d >> 5) & 3) == 0)
|
||||
{
|
||||
byte k = reader(addr++);
|
||||
bytes.Add(k);
|
||||
byte l = reader(addr++);
|
||||
bytes.Add(l);
|
||||
result = result.Replace("ix16", "(" + string.Format("{0:X2}{1:X2}h", k, l) + ")");
|
||||
}
|
||||
else
|
||||
{
|
||||
result = result.Replace("ix16", "???");
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (d & 0xF)
|
||||
{
|
||||
case 0x0:
|
||||
result = result.Replace("ix16", temp_reg + "+");
|
||||
break;
|
||||
case 0x1:
|
||||
result = result.Replace("ix16", temp_reg + "++");
|
||||
break;
|
||||
case 0x2:
|
||||
result = result.Replace("ix16", "-" + temp_reg);
|
||||
break;
|
||||
case 0x3:
|
||||
result = result.Replace("ix16", "--" + temp_reg);
|
||||
break;
|
||||
case 0x4:
|
||||
result = result.Replace("ix16", temp_reg);
|
||||
break;
|
||||
case 0x5:
|
||||
result = result.Replace("ix16", temp_reg + " + B");
|
||||
break;
|
||||
case 0x6:
|
||||
result = result.Replace("ix16", temp_reg + " + A");
|
||||
break;
|
||||
case 0x7:
|
||||
result = result.Replace("ix16", "???");
|
||||
break;
|
||||
case 0x8:
|
||||
byte e = reader(addr++);
|
||||
bytes.Add(e);
|
||||
result = result.Replace("ix16", temp_reg + " + ea");
|
||||
result = result.Replace("ea", string.Format("{0:X2}h", e));
|
||||
break;
|
||||
case 0x9:
|
||||
byte f = reader(addr++);
|
||||
bytes.Add(f);
|
||||
byte g = reader(addr++);
|
||||
bytes.Add(g);
|
||||
result = result.Replace("ix16", temp_reg + " + ea");
|
||||
result = result.Replace("ea", string.Format("{0:X2}{1:X2}h", f, g));
|
||||
break;
|
||||
case 0xA:
|
||||
result = result.Replace("ix16", "???");
|
||||
break;
|
||||
case 0xB:
|
||||
result = result.Replace("ix16", temp_reg + " + D");
|
||||
break;
|
||||
case 0xC:
|
||||
temp_reg = "PC";
|
||||
byte h = reader(addr++);
|
||||
bytes.Add(h);
|
||||
result = result.Replace("ix16", temp_reg + " + ea");
|
||||
result = result.Replace("ea", string.Format("{0:X2}h", h));
|
||||
break;
|
||||
case 0xD:
|
||||
temp_reg = "PC";
|
||||
byte i = reader(addr++);
|
||||
bytes.Add(i);
|
||||
byte j = reader(addr++);
|
||||
bytes.Add(j);
|
||||
result = result.Replace("ix16", temp_reg + " + ea");
|
||||
result = result.Replace("ea", string.Format("{0:X2}{1:X2}h", i, j));
|
||||
break;
|
||||
case 0xE:
|
||||
result = result.Replace("ix16", "???");
|
||||
break;
|
||||
case 0xF:
|
||||
result = result.Replace("ix16", "???");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
StringBuilder ret = new StringBuilder();
|
||||
ret.Append(string.Format("{0:X4}: ", origaddr));
|
||||
foreach (var b in bytes)
|
||||
ret.Append(string.Format("{0:X2} ", b));
|
||||
while (ret.Length < 22)
|
||||
ret.Append(' ');
|
||||
ret.Append(result);
|
||||
size = (ushort)(addr - origaddr);
|
||||
return ret.ToString();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,285 @@
|
|||
using System;
|
||||
|
||||
namespace BizHawk.Emulation.Common.Components.I8048
|
||||
{
|
||||
public partial class I8048
|
||||
{
|
||||
public ulong TotalExecutedCycles;
|
||||
|
||||
// variables for executing instructions
|
||||
public int instr_pntr = 0;
|
||||
public ushort[] cur_instr = new ushort[60];
|
||||
public int opcode_see;
|
||||
|
||||
public int IRQS;
|
||||
public int irq_pntr;
|
||||
|
||||
ushort reg_d_ad;
|
||||
ushort reg_h_ad;
|
||||
ushort reg_l_ad;
|
||||
|
||||
public void FetchInstruction(byte opcode)
|
||||
{
|
||||
opcode_see = opcode;
|
||||
switch (opcode)
|
||||
{
|
||||
case 0x00: OP_IMP(IDLE); break; // NOP
|
||||
case 0x01: ILLEGAL(); break; // ILLEGAL
|
||||
case 0x02: ILLEGAL(); break; // ILLEGAL
|
||||
case 0x03: OP_A_DIR(ADD8); break; // ADD A,#
|
||||
case 0x04: ILLEGAL(); break; // LSR (Direct)
|
||||
case 0x05: OP_IMP(EI); break; // EI
|
||||
case 0x06: ILLEGAL(); break; // ROR (Direct)
|
||||
case 0x07: OP_IMP(DECA); break; // DEC A
|
||||
case 0x08: ILLEGAL(); break; // ASL , LSL (Direct)
|
||||
case 0x09: ILLEGAL(); break; // ROL (Direct)
|
||||
case 0x0A: ILLEGAL(); break; // DEC (Direct)
|
||||
case 0x0B: ILLEGAL(); break; // ILLEGAL
|
||||
case 0x0C: ILLEGAL(); break; // INC (Direct)
|
||||
case 0x0D: ILLEGAL(); break; // TST (Direct)
|
||||
case 0x0E: ILLEGAL(); break; // JMP (Direct)
|
||||
case 0x0F: ILLEGAL(); break; // CLR (Direct)
|
||||
case 0x10: ILLEGAL(); break; // Page 2
|
||||
case 0x11: ILLEGAL(); break; // Page 3
|
||||
case 0x12: ILLEGAL(); break; // NOP (Inherent)
|
||||
case 0x13: OP_A_DIR(ADC8); break; // ADC A,#
|
||||
case 0x14: CALL(0); break; // CALL
|
||||
case 0x15: OP_IMP(DI); break; // DI
|
||||
case 0x16: ILLEGAL(); break; // LBRA (Relative)
|
||||
case 0x17: OP_IMP(INCA); break; // INC A
|
||||
case 0x18: ILLEGAL(); break; // ILLEGAL
|
||||
case 0x19: ILLEGAL(); break; // DAA (Inherent)
|
||||
case 0x1A: ILLEGAL(); break; // ORCC (Immediate)
|
||||
case 0x1B: ILLEGAL(); break; // ILLEGAL
|
||||
case 0x1C: ILLEGAL(); break; // ANDCC (Immediate)
|
||||
case 0x1D: ILLEGAL(); break; // SEX (Inherent)
|
||||
case 0x1E: ILLEGAL(); break; // EXG (Immediate)
|
||||
case 0x1F: ILLEGAL(); break; // TFR (Immediate)
|
||||
case 0x20: ILLEGAL(); break; // BRA (Relative)
|
||||
case 0x21: ILLEGAL(); break; // BRN (Relative)
|
||||
case 0x22: ILLEGAL(); break; // BHI (Relative)
|
||||
case 0x23: ILLEGAL(); break; // BLS (Relative)
|
||||
case 0x24: ILLEGAL(); break; // BHS , BCC (Relative)
|
||||
case 0x25: OP_IMP(EN); break; // EN
|
||||
case 0x26: ILLEGAL(); break; // BNE (Relative)
|
||||
case 0x27: OP_IMP(CLR); break; // CLR A
|
||||
case 0x28: ILLEGAL(); break; // BVC (Relative)
|
||||
case 0x29: ILLEGAL(); break; // BVS (Relative)
|
||||
case 0x2A: ILLEGAL(); break; // BPL (Relative)
|
||||
case 0x2B: ILLEGAL(); break; // BMI (Relative)
|
||||
case 0x2C: ILLEGAL(); break; // BGE (Relative)
|
||||
case 0x2D: ILLEGAL(); break; // BLT (Relative)
|
||||
case 0x2E: ILLEGAL(); break; // BGT (Relative)
|
||||
case 0x2F: ILLEGAL(); break; // BLE (Relative)
|
||||
case 0x30: ILLEGAL(); break; // LEAX (Indexed)
|
||||
case 0x31: ILLEGAL(); break; // LEAY (Indexed)
|
||||
case 0x32: ILLEGAL(); break; // LEAS (Indexed)
|
||||
case 0x33: ILLEGAL(); break; // LEAU (Indexed)
|
||||
case 0x34: CALL(1); break; // CALL
|
||||
case 0x35: OP_IMP(DN); break; // DN
|
||||
case 0x36: ILLEGAL(); break; // PSHU (Immediate)
|
||||
case 0x37: OP_IMP(COM); break; // COM A
|
||||
case 0x38: ILLEGAL(); break; // ILLEGAL
|
||||
case 0x39: ILLEGAL(); break; // RTS (Inherent)
|
||||
case 0x3A: ILLEGAL(); break; // ABX (Inherent)
|
||||
case 0x3B: ILLEGAL(); break; // RTI (Inherent)
|
||||
case 0x3C: ILLEGAL(); break; // CWAI (Inherent)
|
||||
case 0x3D: ILLEGAL(); break; // MUL (Inherent)
|
||||
case 0x3E: ILLEGAL(); break; // ILLEGAL
|
||||
case 0x3F: ILLEGAL(); break; // SWI (Inherent)
|
||||
case 0x40: OP_A_R(OR8RAM, R0); break; // OR A,@R0
|
||||
case 0x41: OP_A_R(OR8RAM, R1); break; // OR A,@R1
|
||||
case 0x42: ILLEGAL(); break; // ILLEGAL
|
||||
case 0x43: OP_A_DIR(OR8); break; // OR A,#
|
||||
case 0x44: ILLEGAL(); break; // LSRA (Inherent)
|
||||
case 0x45: ILLEGAL(); break; // ILLEGAL
|
||||
case 0x46: ILLEGAL(); break; // RORA (Inherent)
|
||||
case 0x47: OP_IMP(SWP); break; // SWP
|
||||
case 0x48: OP_A_R(OR8, R0); break; // OR A,R0
|
||||
case 0x49: OP_A_R(OR8, R1); break; // OR A,R1
|
||||
case 0x4A: OP_A_R(OR8, R2); break; // OR A,R2
|
||||
case 0x4B: OP_A_R(OR8, R3); break; // OR A,R3
|
||||
case 0x4C: OP_A_R(OR8, R4); break; // OR A,R4
|
||||
case 0x4D: OP_A_R(OR8, R5); break; // OR A,R5
|
||||
case 0x4E: OP_A_R(OR8, R6); break; // OR A,R6
|
||||
case 0x4F: OP_A_R(OR8, R7); break; // OR A,R7
|
||||
case 0x50: OP_A_R(AND8RAM, R0); break; // AND A,@R0
|
||||
case 0x51: OP_A_R(AND8RAM, R1); break; // AND A,@R1
|
||||
case 0x52: ILLEGAL(); break; // ILLEGAL
|
||||
case 0x53: OP_A_DIR(AND8); break; // AND A,#
|
||||
case 0x54: CALL(2); break; // CALL
|
||||
case 0x55: ILLEGAL(); break; // ILLEGAL
|
||||
case 0x56: ILLEGAL(); break; // RORB (Inherent)
|
||||
case 0x57: OP_IMP(DA); break; // DA A
|
||||
case 0x58: OP_A_R(AND8, R0); break; // AND A,R0
|
||||
case 0x59: OP_A_R(AND8, R1); break; // AND A,R1
|
||||
case 0x5A: OP_A_R(AND8, R2); break; // AND A,R2
|
||||
case 0x5B: OP_A_R(AND8, R3); break; // AND A,R3
|
||||
case 0x5C: OP_A_R(AND8, R4); break; // AND A,R4
|
||||
case 0x5D: OP_A_R(AND8, R5); break; // AND A,R5
|
||||
case 0x5E: OP_A_R(AND8, R6); break; // AND A,R6
|
||||
case 0x5F: OP_A_R(AND8, R7); break; // AND A,R7
|
||||
case 0x60: OP_A_R(ADD8RAM, R0); break; // ADD A,@R0
|
||||
case 0x61: OP_A_R(ADD8RAM, R1); break; // ADD A,@R1
|
||||
case 0x62: ILLEGAL(); break; // ILLEGAL
|
||||
case 0x63: ILLEGAL(); break; // COM (Indexed)
|
||||
case 0x64: ILLEGAL(); break; // LSR (Indexed)
|
||||
case 0x65: ILLEGAL(); break; // ILLEGAL
|
||||
case 0x66: ILLEGAL(); break; // ROR (Indexed)
|
||||
case 0x67: OP_IMP(RRC); break; // RRC
|
||||
case 0x68: OP_A_R(ADD8, R0); break; // ADD A,R0
|
||||
case 0x69: OP_A_R(ADD8, R1); break; // ADD A,R1
|
||||
case 0x6A: OP_A_R(ADD8, R2); break; // ADD A,R2
|
||||
case 0x6B: OP_A_R(ADD8, R3); break; // ADD A,R3
|
||||
case 0x6C: OP_A_R(ADD8, R4); break; // ADD A,R4
|
||||
case 0x6D: OP_A_R(ADD8, R5); break; // ADD A,R5
|
||||
case 0x6E: OP_A_R(ADD8, R6); break; // ADD A,R6
|
||||
case 0x6F: OP_A_R(ADD8, R7); break; // ADD A,R7
|
||||
case 0x70: OP_A_R(ADC8RAM, R0); break; // ADC A,@R0
|
||||
case 0x71: OP_A_R(ADC8RAM, R1); break; // ADC A,@R1
|
||||
case 0x72: ILLEGAL(); break; // ILLEGAL
|
||||
case 0x73: ILLEGAL(); break; // COM (Extended)
|
||||
case 0x74: CALL(3); break; // CALL
|
||||
case 0x75: ILLEGAL(); break; // ILLEGAL
|
||||
case 0x76: ILLEGAL(); break; // ROR (Extended)
|
||||
case 0x77: OP_IMP(ROR); break; // ROR
|
||||
case 0x78: OP_A_R(ADC8, R0); break; // ADC A,R0
|
||||
case 0x79: OP_A_R(ADC8, R1); break; // ADC A,R1
|
||||
case 0x7A: OP_A_R(ADC8, R2); break; // ADC A,R2
|
||||
case 0x7B: OP_A_R(ADC8, R3); break; // ADC A,R3
|
||||
case 0x7C: OP_A_R(ADC8, R4); break; // ADC A,R4
|
||||
case 0x7D: OP_A_R(ADC8, R5); break; // ADC A,R5
|
||||
case 0x7E: OP_A_R(ADC8, R6); break; // ADC A,R6
|
||||
case 0x7F: OP_A_R(ADC8, R7); break; // ADC A,R7
|
||||
case 0x80: ILLEGAL(); break; // SUBA (Immediate)
|
||||
case 0x81: ILLEGAL(); break; // CMPA (Immediate)
|
||||
case 0x82: ILLEGAL(); break; // SBCA (Immediate)
|
||||
case 0x83: ILLEGAL(); break; // SUBD (Immediate)
|
||||
case 0x84: ILLEGAL(); break; // ANDA (Immediate)
|
||||
case 0x85: OP_IMP(CL0); break; // CLR F0
|
||||
case 0x86: ILLEGAL(); break; // LDA (Immediate)
|
||||
case 0x87: ILLEGAL(); break; // ILLEGAL
|
||||
case 0x88: OP_PB_DIR(OR8, BUS); break; // OR BUS,#
|
||||
case 0x89: OP_PB_DIR(OR8, P1); break; // OR P1,#
|
||||
case 0x8A: OP_PB_DIR(OR8, P2); break; // OR P2,#
|
||||
case 0x8B: ILLEGAL(); break; // ILLEGAL
|
||||
case 0x8C: OP_EXP_A(OR8, P4); break; // OR P4,A
|
||||
case 0x8D: OP_EXP_A(OR8, P5); break; // OR P5,A
|
||||
case 0x8E: OP_EXP_A(OR8, P6); break; // OR P6,A
|
||||
case 0x8F: OP_EXP_A(OR8, P7); break; // OR P7,A
|
||||
case 0x90: ILLEGAL(); break; // SUBA (Direct)
|
||||
case 0x91: ILLEGAL(); break; // CMPA (Direct)
|
||||
case 0x92: ILLEGAL(); break; // SBCA (Direct)
|
||||
case 0x93: ILLEGAL(); break; // SUBD (Direct)
|
||||
case 0x94: CALL(4); break; // CALL
|
||||
case 0x95: OP_IMP(CM0); break; // COM F0
|
||||
case 0x96: ILLEGAL(); break; // LDA (Direct)
|
||||
case 0x97: OP_IMP(CLC); break; // CLR C
|
||||
case 0x98: OP_PB_DIR(AND8, BUS); break; // AND BUS,#
|
||||
case 0x99: OP_PB_DIR(AND8, P1); break; // AND P1,#
|
||||
case 0x9A: OP_PB_DIR(AND8, P2); break; // AND P2,#
|
||||
case 0x9B: ILLEGAL(); break; // ILLEGAL
|
||||
case 0x9C: OP_EXP_A(AND8, P4); break; // AND P4,A
|
||||
case 0x9D: OP_EXP_A(AND8, P5); break; // AND P5,A
|
||||
case 0x9E: OP_EXP_A(AND8, P6); break; // AND P6,A
|
||||
case 0x9F: OP_EXP_A(AND8, P7); break; // AND P7,A
|
||||
case 0xA0: ILLEGAL(); break; // SUBA (Indexed)
|
||||
case 0xA1: ILLEGAL(); break; // CMPA (Indexed)
|
||||
case 0xA2: ILLEGAL(); break; // SBCA (Indexed)
|
||||
case 0xA3: ILLEGAL(); break; // SUBD (Indexed)
|
||||
case 0xA4: ILLEGAL(); break; // ANDA (Indexed)
|
||||
case 0xA5: OP_IMP(CL1); break; // CLR F1
|
||||
case 0xA6: ILLEGAL(); break; // LDA (Indexed)
|
||||
case 0xA7: OP_IMP(CMC); break; // COM C
|
||||
case 0xA8: ILLEGAL(); break; // EORA (Indexed)
|
||||
case 0xA9: ILLEGAL(); break; // ADCA (Indexed)
|
||||
case 0xAA: ILLEGAL(); break; // ORA (Indexed)
|
||||
case 0xAB: ILLEGAL(); break; // ADDA (Indexed)
|
||||
case 0xAC: ILLEGAL(); break; // CMPX (Indexed)
|
||||
case 0xAD: ILLEGAL(); break; // JSR (Indexed)
|
||||
case 0xAE: ILLEGAL(); break; // LDX (Indexed)
|
||||
case 0xAF: ILLEGAL(); break; // STX (Indexed)
|
||||
case 0xB0: ILLEGAL(); break; // SUBA (Extended)
|
||||
case 0xB1: ILLEGAL(); break; // CMPA (Extended)
|
||||
case 0xB2: ILLEGAL(); break; // SBCA (Extended)
|
||||
case 0xB3: ILLEGAL(); break; // SUBD (Extended)
|
||||
case 0xB4: CALL(5); break; // CALL
|
||||
case 0xB5: OP_IMP(CM1); break; // COM F1
|
||||
case 0xB6: ILLEGAL(); break; // LDA (Extended)
|
||||
case 0xB7: ILLEGAL(); break; // STA (Extended)
|
||||
case 0xB8: ILLEGAL(); break; // EORA (Extended)
|
||||
case 0xB9: ILLEGAL(); break; // ADCA (Extended)
|
||||
case 0xBA: ILLEGAL(); break; // ORA (Extended)
|
||||
case 0xBB: ILLEGAL(); break; // ADDA (Extended)
|
||||
case 0xBC: ILLEGAL(); break; // CMPX (Extended)
|
||||
case 0xBD: ILLEGAL(); break; // JSR (Extended)
|
||||
case 0xBE: ILLEGAL(); break; // LDX (Extended)
|
||||
case 0xBF: ILLEGAL(); break; // STX (Extended)
|
||||
case 0xC0: ILLEGAL(); break; // SUBB (Immediate)
|
||||
case 0xC1: ILLEGAL(); break; // CMPB (Immediate)
|
||||
case 0xC2: ILLEGAL(); break; // SBCB (Immediate)
|
||||
case 0xC3: ILLEGAL(); break; // ADDD (Immediate)
|
||||
case 0xC4: ILLEGAL(); break; // ANDB (Immediate)
|
||||
case 0xC5: ILLEGAL(); break; // BITB (Immediate)
|
||||
case 0xC6: ILLEGAL(); break; // LDB (Immediate)
|
||||
case 0xC7: ILLEGAL(); break; // ILLEGAL
|
||||
case 0xC8: OP_R_IMP(DEC8, R0); break; // DEC R0
|
||||
case 0xC9: OP_R_IMP(DEC8, R1); break; // DEC R1
|
||||
case 0xCA: OP_R_IMP(DEC8, R2); break; // DEC R2
|
||||
case 0xCB: OP_R_IMP(DEC8, R3); break; // DEC R3
|
||||
case 0xCC: OP_R_IMP(DEC8, R4); break; // DEC R4
|
||||
case 0xCD: OP_R_IMP(DEC8, R5); break; // DEC R5
|
||||
case 0xCE: OP_R_IMP(DEC8, R6); break; // DEC R6
|
||||
case 0xCF: OP_R_IMP(DEC8, R7); break; // DEC R7
|
||||
case 0xD0: OP_A_R(XOR8RAM, R0); break; // XOR A,@R0
|
||||
case 0xD1: OP_A_R(XOR8RAM, R1); break; // XOR A,@R1
|
||||
case 0xD2: ILLEGAL(); break; // ILLEGAL
|
||||
case 0xD3: OP_A_DIR(XOR8); break; // XOR A,#
|
||||
case 0xD4: CALL(6); break; // CALL
|
||||
case 0xD5: ILLEGAL(); break; // BITB (Direct)
|
||||
case 0xD6: ILLEGAL(); break; // LDB (Direct)
|
||||
case 0xD7: ILLEGAL(); break; // STB (Direct)
|
||||
case 0xD8: OP_A_R(XOR8, R0); break; // XOR A,R0
|
||||
case 0xD9: OP_A_R(XOR8, R1); break; // XOR A,R1
|
||||
case 0xDA: OP_A_R(XOR8, R2); break; // XOR A,R2
|
||||
case 0xDB: OP_A_R(XOR8, R3); break; // XOR A,R3
|
||||
case 0xDC: OP_A_R(XOR8, R4); break; // XOR A,R4
|
||||
case 0xDD: OP_A_R(XOR8, R5); break; // XOR A,R5
|
||||
case 0xDE: OP_A_R(XOR8, R6); break; // XOR A,R6
|
||||
case 0xDF: OP_A_R(XOR8, R7); break; // XOR A,R7
|
||||
case 0xE0: ILLEGAL(); break; // SUBB (Indexed)
|
||||
case 0xE1: ILLEGAL(); break; // CMPB (Indexed)
|
||||
case 0xE2: ILLEGAL(); break; // SBCB (Indexed)
|
||||
case 0xE3: ILLEGAL(); break; // ADDD (Indexed)
|
||||
case 0xE4: ILLEGAL(); break; // ANDB (Indexed)
|
||||
case 0xE5: ILLEGAL(); break; // BITB (Indexed)
|
||||
case 0xE6: ILLEGAL(); break; // LDB (Indexed)
|
||||
case 0xE7: OP_IMP(ROL); break; // ROL
|
||||
case 0xE8: ILLEGAL(); break; // EORB (Indexed)
|
||||
case 0xE9: ILLEGAL(); break; // ADCB (Indexed)
|
||||
case 0xEA: ILLEGAL(); break; // ORB (Indexed)
|
||||
case 0xEB: ILLEGAL(); break; // ADDB (Indexed)
|
||||
case 0xEC: ILLEGAL(); break; // LDD (Indexed)
|
||||
case 0xED: ILLEGAL(); break; // STD (Indexed)
|
||||
case 0xEE: ILLEGAL(); break; // LDU (Indexed)
|
||||
case 0xEF: ILLEGAL(); break; // STU (Indexed)
|
||||
case 0xF0: ILLEGAL(); break; // SUBB (Extended)
|
||||
case 0xF1: ILLEGAL(); break; // CMPB (Extended)
|
||||
case 0xF2: ILLEGAL(); break; // SBCB (Extended)
|
||||
case 0xF3: ILLEGAL(); break; // ADDD (Extended)
|
||||
case 0xF4: CALL(7); break; // CALL
|
||||
case 0xF5: ILLEGAL(); break; // BITB (Extended)
|
||||
case 0xF6: ILLEGAL(); break; // LDB (Extended)
|
||||
case 0xF7: OP_IMP(RLC); break; // RLC
|
||||
case 0xF8: ILLEGAL(); break; // EORB (Extended)
|
||||
case 0xF9: ILLEGAL(); break; // ADCB (Extended)
|
||||
case 0xFA: ILLEGAL(); break; // ORB (Extended)
|
||||
case 0xFB: ILLEGAL(); break; // ADDB (Extended)
|
||||
case 0xFC: ILLEGAL(); break; // LDD (Extended)
|
||||
case 0xFD: ILLEGAL(); break; // STD (Extended)
|
||||
case 0xFE: ILLEGAL(); break; // LDU (Extended)
|
||||
case 0xFF: ILLEGAL(); break; // STU (Extended)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,369 @@
|
|||
using System;
|
||||
|
||||
using BizHawk.Common;
|
||||
|
||||
// Intel Corp 8048
|
||||
namespace BizHawk.Emulation.Common.Components.I8048
|
||||
{
|
||||
public sealed partial class I8048
|
||||
{
|
||||
// operations that can take place in an instruction
|
||||
public const ushort IDLE = 0;
|
||||
public const ushort OP = 1;
|
||||
public const ushort RD = 2;
|
||||
public const ushort WR = 3;
|
||||
public const ushort TR = 4;
|
||||
public const ushort ADD16BR = 5;
|
||||
public const ushort ADD8 = 6;
|
||||
public const ushort ADD8RAM = 7;
|
||||
public const ushort ADC8 = 8;
|
||||
public const ushort ADC8RAM = 9;
|
||||
public const ushort INC16 = 10;
|
||||
public const ushort INC8 = 11;
|
||||
public const ushort INCA = 12;
|
||||
public const ushort DEC16 = 13;
|
||||
public const ushort DEC8 = 14;
|
||||
public const ushort DECA = 15;
|
||||
public const ushort ROL = 16;
|
||||
public const ushort ROR = 17;
|
||||
public const ushort RLC = 18;
|
||||
public const ushort RRC = 19;
|
||||
public const ushort SWP = 20;
|
||||
public const ushort COM = 21;
|
||||
public const ushort CMC = 22;
|
||||
public const ushort CM0 = 23;
|
||||
public const ushort CM1 = 24;
|
||||
public const ushort DA = 25;
|
||||
public const ushort AND8 = 26;
|
||||
public const ushort AND8RAM = 27;
|
||||
public const ushort XOR8 = 28;
|
||||
public const ushort XOR8RAM = 29;
|
||||
public const ushort OR8 = 30;
|
||||
public const ushort OR8RAM = 31;
|
||||
public const ushort ASL = 32;
|
||||
public const ushort ASR = 33;
|
||||
public const ushort LSR = 34;
|
||||
public const ushort BIT = 35;
|
||||
public const ushort RD_INC = 36;
|
||||
public const ushort SET_ADDR = 37;
|
||||
public const ushort NEG = 38;
|
||||
public const ushort TST = 39;
|
||||
public const ushort CLR = 40;
|
||||
public const ushort CLC = 41;
|
||||
public const ushort CL0 = 42;
|
||||
public const ushort CL1 = 43;
|
||||
public const ushort EI = 44;
|
||||
public const ushort EN = 45;
|
||||
public const ushort DI = 46;
|
||||
public const ushort DN = 47;
|
||||
public const ushort TFR = 48;
|
||||
public const ushort ADD8BR = 49;
|
||||
public const ushort ABX = 50;
|
||||
public const ushort JPE = 51;
|
||||
public const ushort MSK = 52;
|
||||
public const ushort CMP8 = 53;
|
||||
public const ushort SUB16 = 54;
|
||||
public const ushort ADD16 = 55;
|
||||
public const ushort CMP16 = 56;
|
||||
public const ushort CMP16D = 57;
|
||||
public const ushort CLR_E = 63;
|
||||
|
||||
public I8048()
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
ResetRegisters();
|
||||
ResetInterrupts();
|
||||
TotalExecutedCycles = 0;
|
||||
Regs[PC] = 0xFFFE;
|
||||
PopulateCURINSTR(IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
RD_INC, ALU, PC,
|
||||
RD_INC, ALU2, PC,
|
||||
SET_ADDR, PC, ALU, ALU2);
|
||||
|
||||
IRQS = 6;
|
||||
instr_pntr = irq_pntr = 0;
|
||||
}
|
||||
|
||||
// Memory Access
|
||||
|
||||
public Func<ushort, byte> ReadMemory;
|
||||
public Action<ushort, byte> WriteMemory;
|
||||
public Func<ushort, byte> PeekMemory;
|
||||
public Func<ushort, byte> DummyReadMemory;
|
||||
|
||||
//this only calls when the first byte of an instruction is fetched.
|
||||
public Action<ushort> OnExecFetch;
|
||||
|
||||
public void UnregisterMemoryMapper()
|
||||
{
|
||||
ReadMemory = null;
|
||||
ReadMemory = null;
|
||||
PeekMemory = null;
|
||||
DummyReadMemory = null;
|
||||
}
|
||||
|
||||
public void SetCallbacks
|
||||
(
|
||||
Func<ushort, byte> ReadMemory,
|
||||
Func<ushort, byte> DummyReadMemory,
|
||||
Func<ushort, byte> PeekMemory,
|
||||
Action<ushort, byte> WriteMemory
|
||||
)
|
||||
{
|
||||
this.ReadMemory = ReadMemory;
|
||||
this.DummyReadMemory = DummyReadMemory;
|
||||
this.PeekMemory = PeekMemory;
|
||||
this.WriteMemory = WriteMemory;
|
||||
}
|
||||
|
||||
//a little CDL related stuff
|
||||
public delegate void DoCDLCallbackType(ushort addr, I8048.eCDLogMemFlags flags);
|
||||
|
||||
public DoCDLCallbackType CDLCallback;
|
||||
|
||||
public enum eCDLogMemFlags
|
||||
{
|
||||
FetchFirst = 1,
|
||||
FetchOperand = 2,
|
||||
Data = 4,
|
||||
Write = 8
|
||||
};
|
||||
|
||||
// Execute instructions
|
||||
public void ExecuteOne()
|
||||
{
|
||||
//Console.Write(opcode_see + " ");
|
||||
//Console.WriteLine(Regs[PC] + " ");
|
||||
switch (cur_instr[instr_pntr++])
|
||||
{
|
||||
case IDLE:
|
||||
// do nothing
|
||||
break;
|
||||
case OP:
|
||||
// Read the opcode of the next instruction
|
||||
if (OnExecFetch != null) OnExecFetch(PC);
|
||||
if (TraceCallback != null) TraceCallback(State());
|
||||
if (CDLCallback != null) CDLCallback(PC, eCDLogMemFlags.FetchFirst);
|
||||
FetchInstruction(ReadMemory(Regs[PC]++));
|
||||
instr_pntr = 0;
|
||||
irq_pntr = -1;
|
||||
break;
|
||||
case RD:
|
||||
Read_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
|
||||
break;
|
||||
case RD_INC:
|
||||
Read_Inc_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
|
||||
break;
|
||||
case WR:
|
||||
Write_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
|
||||
break;
|
||||
case TR:
|
||||
TR_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
|
||||
break;
|
||||
case TFR:
|
||||
TFR_Func(cur_instr[instr_pntr++]);
|
||||
break;
|
||||
case SET_ADDR:
|
||||
reg_d_ad = cur_instr[instr_pntr++];
|
||||
reg_h_ad = cur_instr[instr_pntr++];
|
||||
reg_l_ad = cur_instr[instr_pntr++];
|
||||
|
||||
// Console.WriteLine(reg_d_ad + " " + reg_h_ad + " " + reg_l_ad);
|
||||
// Console.WriteLine(Regs[reg_d_ad] + " " + Regs[reg_h_ad] + " " + Regs[reg_l_ad]);
|
||||
|
||||
Regs[reg_d_ad] = (ushort)((Regs[reg_h_ad] << 8) | Regs[reg_l_ad]);
|
||||
break;
|
||||
case TST:
|
||||
TST_Func(cur_instr[instr_pntr++]);
|
||||
break;
|
||||
case CLR:
|
||||
CLR_Func(cur_instr[instr_pntr++]);
|
||||
break;
|
||||
case CLR_E:
|
||||
|
||||
break;
|
||||
case ADD16BR:
|
||||
ADD16BR_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
|
||||
break;
|
||||
case ADD8BR:
|
||||
ADD8BR_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
|
||||
break;
|
||||
case ADD8:
|
||||
ADD8_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
|
||||
break;
|
||||
case ADC8:
|
||||
ADC8_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
|
||||
break;
|
||||
case CMP8:
|
||||
CMP8_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
|
||||
break;
|
||||
case INC16:
|
||||
INC16_Func(cur_instr[instr_pntr++]);
|
||||
break;
|
||||
case INC8:
|
||||
INC8_Func(cur_instr[instr_pntr++]);
|
||||
break;
|
||||
case DEC16:
|
||||
DEC16_Func(cur_instr[instr_pntr++]);
|
||||
break;
|
||||
case CMP16:
|
||||
CMP16_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
|
||||
break;
|
||||
case DEC8:
|
||||
DEC8_Func(cur_instr[instr_pntr++]);
|
||||
break;
|
||||
case ROL:
|
||||
ROL_Func(cur_instr[instr_pntr++]);
|
||||
break;
|
||||
case ROR:
|
||||
ROR_Func(cur_instr[instr_pntr++]);
|
||||
break;
|
||||
case COM:
|
||||
COM_Func(cur_instr[instr_pntr++]);
|
||||
break;
|
||||
case DA:
|
||||
DA_Func(cur_instr[instr_pntr++]);
|
||||
break;
|
||||
case AND8:
|
||||
AND8_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
|
||||
break;
|
||||
case XOR8:
|
||||
XOR8_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
|
||||
break;
|
||||
case OR8:
|
||||
OR8_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
|
||||
break;
|
||||
case ASL:
|
||||
ASL_Func(cur_instr[instr_pntr++]);
|
||||
break;
|
||||
case ASR:
|
||||
ASR_Func(cur_instr[instr_pntr++]);
|
||||
break;
|
||||
case LSR:
|
||||
LSR_Func(cur_instr[instr_pntr++]);
|
||||
break;
|
||||
case BIT:
|
||||
BIT_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
|
||||
break;
|
||||
}
|
||||
|
||||
if (++irq_pntr == IRQS)
|
||||
{
|
||||
// then regular IRQ
|
||||
if (IRQPending && IntEn)
|
||||
{
|
||||
IRQPending = false;
|
||||
|
||||
if (TraceCallback != null) { TraceCallback(new TraceInfo { Disassembly = "====IRQ====", RegisterInfo = "" }); }
|
||||
|
||||
IRQ_();
|
||||
IRQCallback();
|
||||
instr_pntr = irq_pntr = 0;
|
||||
}
|
||||
// otherwise start the next instruction
|
||||
else
|
||||
{
|
||||
PopulateCURINSTR(OP);
|
||||
instr_pntr = irq_pntr = 0;
|
||||
IRQS = -1;
|
||||
}
|
||||
}
|
||||
|
||||
TotalExecutedCycles++;
|
||||
}
|
||||
|
||||
// tracer stuff
|
||||
|
||||
public Action<TraceInfo> TraceCallback;
|
||||
|
||||
public string TraceHeader
|
||||
{
|
||||
get { return "MC6809: PC, machine code, mnemonic, operands, registers (A, B, X, Y, US, SP, DP, CC), Cy, flags (EFHINZVC)"; }
|
||||
}
|
||||
|
||||
public TraceInfo State(bool disassemble = true)
|
||||
{
|
||||
ushort notused;
|
||||
|
||||
return new TraceInfo
|
||||
{
|
||||
Disassembly = $"{(disassemble ? Disassemble(Regs[PC], ReadMemory, out notused) : "---")} ".PadRight(50),
|
||||
RegisterInfo = string.Format(
|
||||
"A:{0:X2} R0:{1:X2} R1:{2:X2} R2:{3:X2} R3:{4:X2} R4:{5:X2} R5:{6:X2} R6:{7:X2} R7:{8:X2} PSW:{9:X4} Cy:{10} {11}{12}{13}{14} {15}{16}{17}{18}",
|
||||
Regs[A],
|
||||
Regs[R0],
|
||||
Regs[R1],
|
||||
Regs[R2],
|
||||
Regs[R3],
|
||||
Regs[R4],
|
||||
Regs[R5],
|
||||
Regs[R6],
|
||||
Regs[R7],
|
||||
Regs[PSW],
|
||||
TotalExecutedCycles,
|
||||
FlagC ? "C" : "c",
|
||||
FlagAC ? "A" : "a",
|
||||
FlagF0 ? "F" : "f",
|
||||
FlagBS ? "B" : "b",
|
||||
IntEn ? "I" : "i",
|
||||
F1 ? "F" : "f",
|
||||
T0 ? "T" : "t",
|
||||
T1 ? "T" : "t"
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Optimization method to set cur_instr
|
||||
/// </summary>
|
||||
private void PopulateCURINSTR(ushort d0 = 0, ushort d1 = 0, ushort d2 = 0, ushort d3 = 0, ushort d4 = 0, ushort d5 = 0, ushort d6 = 0, ushort d7 = 0, ushort d8 = 0,
|
||||
ushort d9 = 0, ushort d10 = 0, ushort d11 = 0, ushort d12 = 0, ushort d13 = 0, ushort d14 = 0, ushort d15 = 0, ushort d16 = 0, ushort d17 = 0, ushort d18 = 0,
|
||||
ushort d19 = 0, ushort d20 = 0, ushort d21 = 0, ushort d22 = 0, ushort d23 = 0, ushort d24 = 0, ushort d25 = 0, ushort d26 = 0, ushort d27 = 0, ushort d28 = 0,
|
||||
ushort d29 = 0, ushort d30 = 0, ushort d31 = 0, ushort d32 = 0, ushort d33 = 0, ushort d34 = 0, ushort d35 = 0, ushort d36 = 0, ushort d37 = 0, ushort d38 = 0)
|
||||
{
|
||||
cur_instr[0] = d0; cur_instr[1] = d1; cur_instr[2] = d2;
|
||||
cur_instr[3] = d3; cur_instr[4] = d4; cur_instr[5] = d5;
|
||||
cur_instr[6] = d6; cur_instr[7] = d7; cur_instr[8] = d8;
|
||||
cur_instr[9] = d9; cur_instr[10] = d10; cur_instr[11] = d11;
|
||||
cur_instr[12] = d12; cur_instr[13] = d13; cur_instr[14] = d14;
|
||||
cur_instr[15] = d15; cur_instr[16] = d16; cur_instr[17] = d17;
|
||||
cur_instr[18] = d18; cur_instr[19] = d19; cur_instr[20] = d20;
|
||||
cur_instr[21] = d21; cur_instr[22] = d22; cur_instr[23] = d23;
|
||||
cur_instr[24] = d24; cur_instr[25] = d25; cur_instr[26] = d26;
|
||||
cur_instr[27] = d27; cur_instr[28] = d28; cur_instr[29] = d29;
|
||||
cur_instr[30] = d30; cur_instr[31] = d31; cur_instr[32] = d32;
|
||||
cur_instr[33] = d33; cur_instr[34] = d34; cur_instr[35] = d35;
|
||||
cur_instr[36] = d36; cur_instr[37] = d37; cur_instr[38] = d38;
|
||||
}
|
||||
|
||||
// State Save/Load
|
||||
public void SyncState(Serializer ser)
|
||||
{
|
||||
ser.BeginSection("MC6809");
|
||||
|
||||
ser.Sync(nameof(IntEn), ref IntEn);
|
||||
ser.Sync(nameof(IRQPending), ref IRQPending);
|
||||
|
||||
ser.Sync(nameof(instr_pntr), ref instr_pntr);
|
||||
ser.Sync(nameof(cur_instr), ref cur_instr, false);
|
||||
ser.Sync(nameof(opcode_see), ref opcode_see);
|
||||
ser.Sync(nameof(IRQS), ref IRQS);
|
||||
ser.Sync(nameof(irq_pntr), ref irq_pntr);
|
||||
|
||||
ser.Sync(nameof(Regs), ref Regs, false);
|
||||
ser.Sync(nameof(RAM), ref RAM, false);
|
||||
ser.Sync(nameof(F1), ref F1);
|
||||
ser.Sync(nameof(T0), ref T0);
|
||||
ser.Sync(nameof(T1), ref T1);
|
||||
ser.Sync(nameof(TotalExecutedCycles), ref TotalExecutedCycles);
|
||||
|
||||
ser.EndSection();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
using System;
|
||||
|
||||
namespace BizHawk.Emulation.Common.Components.I8048
|
||||
{
|
||||
public partial class I8048
|
||||
{
|
||||
private void IRQ_()
|
||||
{
|
||||
Regs[ADDR] = 0xFFF8;
|
||||
PopulateCURINSTR(IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
RD_INC, ALU, ADDR,
|
||||
RD_INC, ALU2, ADDR,
|
||||
SET_ADDR, PC, ALU, ALU2);
|
||||
|
||||
IRQS = 19;
|
||||
}
|
||||
|
||||
public bool IRQPending;
|
||||
public bool IntEn;
|
||||
|
||||
public Action IRQCallback = delegate () { };
|
||||
|
||||
private void ResetInterrupts()
|
||||
{
|
||||
IntEn = true;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,113 @@
|
|||
using System;
|
||||
using BizHawk.Common.NumberExtensions;
|
||||
|
||||
namespace BizHawk.Emulation.Common.Components.I8048
|
||||
{
|
||||
public partial class I8048
|
||||
{
|
||||
// this contains the vectors of instrcution operations
|
||||
// NOTE: This list is NOT confirmed accurate for each individual cycle
|
||||
public void ILLEGAL()
|
||||
{
|
||||
PopulateCURINSTR(IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
IDLE);
|
||||
|
||||
IRQS = 4;
|
||||
}
|
||||
|
||||
public void OP_IMP(ushort oper)
|
||||
{
|
||||
PopulateCURINSTR(IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
oper);
|
||||
|
||||
IRQS = 4;
|
||||
}
|
||||
|
||||
public void OP_R_IMP(ushort oper, ushort reg)
|
||||
{
|
||||
PopulateCURINSTR(IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
oper, reg);
|
||||
|
||||
IRQS = 4;
|
||||
}
|
||||
|
||||
|
||||
public void OP_A_R(ushort oper, ushort reg)
|
||||
{
|
||||
PopulateCURINSTR(IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
oper,A,reg);
|
||||
|
||||
IRQS = 4;
|
||||
}
|
||||
|
||||
public void OP_A_DIR(ushort oper)
|
||||
{
|
||||
PopulateCURINSTR(IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
RD, ALU, PC,
|
||||
INC16, PC,
|
||||
IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
oper, A, ALU);
|
||||
|
||||
IRQS = 9;
|
||||
}
|
||||
|
||||
public void OP_PB_DIR(ushort oper, ushort reg)
|
||||
{
|
||||
PopulateCURINSTR(IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
RD, ALU, PC,
|
||||
INC16, PC,
|
||||
IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
oper, reg, ALU);
|
||||
|
||||
IRQS = 9;
|
||||
}
|
||||
|
||||
public void OP_EXP_A(ushort oper, ushort reg)
|
||||
{
|
||||
// Lower 4 bits only
|
||||
PopulateCURINSTR(IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
TR, ALU, A,
|
||||
IDLE,
|
||||
IDLE,
|
||||
MSK, ALU,
|
||||
IDLE,
|
||||
oper, reg, ALU);
|
||||
|
||||
IRQS = 9;
|
||||
}
|
||||
|
||||
public void CALL(ushort dest_h)
|
||||
{
|
||||
// Lower 4 bits only
|
||||
PopulateCURINSTR(IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
TR, ALU, A,
|
||||
IDLE,
|
||||
IDLE,
|
||||
MSK, ALU,
|
||||
IDLE,
|
||||
ALU);
|
||||
|
||||
IRQS = 9;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,291 @@
|
|||
using System;
|
||||
using BizHawk.Common.NumberExtensions;
|
||||
|
||||
namespace BizHawk.Emulation.Common.Components.I8048
|
||||
{
|
||||
public partial class I8048
|
||||
{
|
||||
public void Read_Func(ushort dest, ushort src)
|
||||
{
|
||||
if (CDLCallback != null)
|
||||
{
|
||||
if (src == PC) CDLCallback(Regs[src], eCDLogMemFlags.FetchOperand);
|
||||
else CDLCallback(Regs[src], eCDLogMemFlags.Data);
|
||||
}
|
||||
Regs[dest] = ReadMemory(Regs[src]);
|
||||
}
|
||||
|
||||
public void Read_Inc_Func(ushort dest, ushort src)
|
||||
{
|
||||
if (CDLCallback != null)
|
||||
{
|
||||
if (src == PC) CDLCallback(Regs[src], eCDLogMemFlags.FetchOperand);
|
||||
else CDLCallback(Regs[src], eCDLogMemFlags.Data);
|
||||
}
|
||||
//Console.WriteLine(dest + " " + src + " " + opcode_see);
|
||||
|
||||
Regs[dest] = ReadMemory(Regs[src]);
|
||||
|
||||
Regs[src]++;
|
||||
}
|
||||
|
||||
public void Write_Func(ushort dest, ushort src)
|
||||
{
|
||||
if (CDLCallback != null) CDLCallback(Regs[dest], eCDLogMemFlags.Write | eCDLogMemFlags.Data);
|
||||
WriteMemory(Regs[dest], (byte)Regs[src]);
|
||||
}
|
||||
|
||||
public void TR_Func(ushort dest, ushort src)
|
||||
{
|
||||
Regs[dest] = Regs[src];
|
||||
}
|
||||
|
||||
public void LD_8_Func(ushort dest, ushort src)
|
||||
{
|
||||
Regs[dest] = Regs[src];
|
||||
}
|
||||
|
||||
public void TST_Func(ushort src)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void CLR_Func(ushort src)
|
||||
{
|
||||
Regs[src] = 0;
|
||||
|
||||
FlagC = false;
|
||||
}
|
||||
|
||||
// source is considered a 16 bit signed value, used for long relative branch
|
||||
// no flags used
|
||||
public void ADD16BR_Func(ushort dest, ushort src)
|
||||
{
|
||||
Regs[dest] = (ushort)(Regs[dest] + (short)Regs[src]);
|
||||
}
|
||||
|
||||
public void ADD8BR_Func(ushort dest, ushort src)
|
||||
{
|
||||
if (Regs[src] > 127) { Regs[src] |= 0xFF00; }
|
||||
Regs[dest] = (ushort)(Regs[dest] + (short)Regs[src]);
|
||||
}
|
||||
|
||||
public void ADD8_Func(ushort dest, ushort src)
|
||||
{
|
||||
int Reg16_d = Regs[dest];
|
||||
Reg16_d += Regs[src];
|
||||
|
||||
FlagC = Reg16_d.Bit(8);
|
||||
|
||||
ushort ans = (ushort)(Reg16_d & 0xFF);
|
||||
|
||||
// redo for half carry flag
|
||||
Reg16_d = Regs[dest] & 0xF;
|
||||
Reg16_d += (Regs[src] & 0xF);
|
||||
|
||||
Regs[dest] = ans;
|
||||
}
|
||||
|
||||
public void SUB8_Func(ushort dest, ushort src)
|
||||
{
|
||||
int Reg16_d = Regs[dest];
|
||||
Reg16_d -= Regs[src];
|
||||
|
||||
FlagC = Reg16_d.Bit(8);
|
||||
|
||||
ushort ans = (ushort)(Reg16_d & 0xFF);
|
||||
|
||||
// redo for half carry flag
|
||||
Reg16_d = Regs[dest] & 0xF;
|
||||
Reg16_d -= (Regs[src] & 0xF);
|
||||
|
||||
Regs[dest] = ans;
|
||||
}
|
||||
|
||||
// same as SUB8 but result not stored
|
||||
public void CMP8_Func(ushort dest, ushort src)
|
||||
{
|
||||
int Reg16_d = Regs[dest];
|
||||
Reg16_d -= Regs[src];
|
||||
|
||||
FlagC = Reg16_d.Bit(8);
|
||||
|
||||
ushort ans = (ushort)(Reg16_d & 0xFF);
|
||||
|
||||
// redo for half carry flag
|
||||
Reg16_d = Regs[dest] & 0xF;
|
||||
Reg16_d -= (Regs[src] & 0xF);
|
||||
}
|
||||
|
||||
public void BIT_Func(ushort dest, ushort src)
|
||||
{
|
||||
ushort ans = (ushort)(Regs[dest] & Regs[src]);
|
||||
}
|
||||
|
||||
public void ASL_Func(ushort src)
|
||||
{
|
||||
FlagC = Regs[src].Bit(7);
|
||||
|
||||
Regs[src] = (ushort)((Regs[src] << 1) & 0xFF);
|
||||
}
|
||||
|
||||
public void ASR_Func(ushort src)
|
||||
{
|
||||
FlagC = Regs[src].Bit(0);
|
||||
|
||||
ushort temp = (ushort)(Regs[src] & 0x80); // MSB doesn't change in this operation
|
||||
|
||||
Regs[src] = (ushort)((Regs[src] >> 1) | temp);
|
||||
}
|
||||
|
||||
public void LSR_Func(ushort src)
|
||||
{
|
||||
FlagC = Regs[src].Bit(0);
|
||||
|
||||
Regs[src] = (ushort)(Regs[src] >> 1);
|
||||
}
|
||||
|
||||
public void COM_Func(ushort src)
|
||||
{
|
||||
Regs[src] = (ushort)((~Regs[src]) & 0xFF);
|
||||
|
||||
FlagC = true;
|
||||
}
|
||||
|
||||
public void AND8_Func(ushort dest, ushort src)
|
||||
{
|
||||
Regs[dest] = (ushort)(Regs[dest] & Regs[src]);
|
||||
}
|
||||
|
||||
public void OR8_Func(ushort dest, ushort src)
|
||||
{
|
||||
Regs[dest] = (ushort)(Regs[dest] | Regs[src]);
|
||||
}
|
||||
|
||||
public void XOR8_Func(ushort dest, ushort src)
|
||||
{
|
||||
Regs[dest] = (ushort)(Regs[dest] ^ Regs[src]);
|
||||
}
|
||||
|
||||
public void ROR_Func(ushort src)
|
||||
{
|
||||
ushort c = (ushort)(FlagC ? 0x80 : 0);
|
||||
|
||||
FlagC = Regs[src].Bit(0);
|
||||
|
||||
Regs[src] = (ushort)(c | (Regs[src] >> 1));
|
||||
}
|
||||
|
||||
public void ROL_Func(ushort src)
|
||||
{
|
||||
ushort c = (ushort)(FlagC ? 1 : 0);
|
||||
FlagC = Regs[src].Bit(7);
|
||||
|
||||
Regs[src] = (ushort)(((Regs[src] << 1) & 0xFF) | c);
|
||||
}
|
||||
|
||||
public void RRC_Func(ushort src)
|
||||
{
|
||||
ushort c = (ushort)(FlagC ? 0x80 : 0);
|
||||
|
||||
FlagC = Regs[src].Bit(0);
|
||||
|
||||
Regs[src] = (ushort)(c | (Regs[src] >> 1));
|
||||
}
|
||||
|
||||
public void RLC_Func(ushort src)
|
||||
{
|
||||
ushort c = (ushort)(FlagC ? 1 : 0);
|
||||
FlagC = Regs[src].Bit(7);
|
||||
|
||||
Regs[src] = (ushort)(((Regs[src] << 1) & 0xFF) | c);
|
||||
}
|
||||
|
||||
public void INC8_Func(ushort src)
|
||||
{
|
||||
Regs[src] = (ushort)((Regs[src] + 1) & 0xFF);
|
||||
}
|
||||
|
||||
public void DEC8_Func(ushort src)
|
||||
{
|
||||
Regs[src] = (ushort)((Regs[src] - 1) & 0xFF);
|
||||
}
|
||||
|
||||
public void INC16_Func(ushort src)
|
||||
{
|
||||
Regs[src] += 1;
|
||||
}
|
||||
|
||||
public void DEC16_Func(ushort src)
|
||||
{
|
||||
Regs[src] -= 1;
|
||||
}
|
||||
|
||||
public void ADC8_Func(ushort dest, ushort src)
|
||||
{
|
||||
int Reg16_d = Regs[dest];
|
||||
int c = FlagC ? 1 : 0;
|
||||
|
||||
Reg16_d += (Regs[src] + c);
|
||||
|
||||
FlagC = Reg16_d.Bit(8);
|
||||
|
||||
ushort ans = (ushort)(Reg16_d & 0xFF);
|
||||
|
||||
// redo for half carry flag
|
||||
Reg16_d = Regs[dest] & 0xF;
|
||||
Reg16_d += ((Regs[src] & 0xF) + c);
|
||||
|
||||
Regs[dest] = ans;
|
||||
}
|
||||
|
||||
public void DA_Func(ushort src)
|
||||
{
|
||||
int a = Regs[src];
|
||||
|
||||
byte CF = 0;
|
||||
if (FlagC || ((a & 0xF) > 9))
|
||||
{
|
||||
CF = 6;
|
||||
}
|
||||
if (FlagC || (((a >> 4) & 0xF) > 9) || ((((a >> 4) & 0xF) > 8) && ((a & 0xF) > 9)))
|
||||
{
|
||||
CF |= (byte)(6 << 4);
|
||||
}
|
||||
|
||||
a += CF;
|
||||
|
||||
if ((a > 0xFF) || FlagC)
|
||||
{
|
||||
FlagC = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
FlagC = false;
|
||||
}
|
||||
Regs[src] = (byte)a;
|
||||
}
|
||||
|
||||
public void CMP16_Func(ushort dest, ushort src)
|
||||
{
|
||||
int Reg16_d = Regs[dest];
|
||||
int Reg16_s = Regs[src];
|
||||
|
||||
Reg16_d -= Reg16_s;
|
||||
|
||||
FlagC = Reg16_d.Bit(16);
|
||||
|
||||
ushort ans = (ushort)(Reg16_d & 0xFFFF);
|
||||
}
|
||||
|
||||
public void EXG_Func(ushort sel)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void TFR_Func(ushort sel)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
TODO: STOP for second byte nonzero
|
|
@ -0,0 +1,86 @@
|
|||
using System;
|
||||
|
||||
namespace BizHawk.Emulation.Common.Components.I8048
|
||||
{
|
||||
public partial class I8048
|
||||
{
|
||||
// registers
|
||||
public ushort[] Regs = new ushort[21];
|
||||
|
||||
// 64 bytes of onboard ram
|
||||
public ushort[] RAM = new ushort[64];
|
||||
|
||||
// The 8048 has 2 flags that can be used for conditionals
|
||||
// F0 is on the PSW, F1 is seperate
|
||||
public bool F1;
|
||||
|
||||
// The 8048 has 2 test lines which can be used for conditionals, T0 can be used as an output
|
||||
public bool T0, T1;
|
||||
|
||||
public const ushort PC = 0;
|
||||
public const ushort PSW = 1;
|
||||
public const ushort BUS = 2;
|
||||
public const ushort A = 3;
|
||||
public const ushort R0 = 4;
|
||||
public const ushort R1 = 5;
|
||||
public const ushort R2 = 6;
|
||||
public const ushort R3 = 7;
|
||||
public const ushort R4 = 8;
|
||||
public const ushort R5 = 9;
|
||||
public const ushort R6 = 10;
|
||||
public const ushort R7 = 11;
|
||||
public const ushort ADDR = 12; // internal
|
||||
public const ushort ALU = 13; // internal
|
||||
public const ushort ALU2 = 14; // internal
|
||||
public const ushort P1 = 15;
|
||||
public const ushort P2 = 16;
|
||||
public const ushort P4 = 17;
|
||||
public const ushort P5 = 18;
|
||||
public const ushort P6 = 19;
|
||||
public const ushort P7 = 20;
|
||||
|
||||
public bool Flag3
|
||||
{
|
||||
get { return (Regs[PSW] & 0x08) != 0; }
|
||||
set { Regs[PSW] = (byte)((Regs[PSW] & ~0x08) | 0x08); }
|
||||
}
|
||||
|
||||
public bool FlagBS
|
||||
{
|
||||
get { return (Regs[PSW] & 0x10) != 0; }
|
||||
set { Regs[PSW] = (byte)((Regs[PSW] & ~0x10) | (value ? 0x10 : 0x00)); }
|
||||
}
|
||||
|
||||
public bool FlagF0
|
||||
{
|
||||
get { return (Regs[PSW] & 0x20) != 0; }
|
||||
set { Regs[PSW] = (byte)((Regs[PSW] & ~0x20) | (value ? 0x20 : 0x00)); }
|
||||
}
|
||||
|
||||
public bool FlagAC
|
||||
{
|
||||
get { return (Regs[PSW] & 0x40) != 0; }
|
||||
set { Regs[PSW] = (byte)((Regs[PSW] & ~0x40) | (value ? 0x40 : 0x00)); }
|
||||
}
|
||||
|
||||
public bool FlagC
|
||||
{
|
||||
get { return (Regs[PSW] & 0x80) != 0; }
|
||||
set { Regs[PSW] = (byte)((Regs[PSW] & ~0x80) | (value ? 0x80 : 0x00)); }
|
||||
}
|
||||
|
||||
private void ResetRegisters()
|
||||
{
|
||||
for (int i = 0; i < 21; i++)
|
||||
{
|
||||
Regs[i] = 0;
|
||||
}
|
||||
|
||||
F1 = false;
|
||||
|
||||
T0 = T1 = false;
|
||||
|
||||
Flag3 = true;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -473,16 +473,13 @@ namespace BizHawk.Emulation.Common.Components.MC6800
|
|||
// then regular IRQ
|
||||
else if (IRQPending && !FlagI)
|
||||
{
|
||||
if (!FlagI)
|
||||
{
|
||||
IRQPending = false;
|
||||
IRQPending = false;
|
||||
|
||||
if (TraceCallback != null) { TraceCallback(new TraceInfo { Disassembly = "====IRQ====", RegisterInfo = "" }); }
|
||||
if (TraceCallback != null) { TraceCallback(new TraceInfo { Disassembly = "====IRQ====", RegisterInfo = "" }); }
|
||||
|
||||
IRQ_();
|
||||
IRQCallback();
|
||||
instr_pntr = irq_pntr = 0;
|
||||
}
|
||||
IRQ_();
|
||||
IRQCallback();
|
||||
instr_pntr = irq_pntr = 0;
|
||||
}
|
||||
// otherwise start the next instruction
|
||||
else
|
||||
|
|
|
@ -503,16 +503,85 @@ namespace BizHawk.Emulation.Common.Components.MC6809
|
|||
else
|
||||
{
|
||||
PopulateCURINSTR(CWAI);
|
||||
irq_pntr = 0;
|
||||
irq_pntr = instr_pntr = 0;
|
||||
IRQS = -1;
|
||||
}
|
||||
instr_pntr = 0;
|
||||
break;
|
||||
case SYNC:
|
||||
IN_SYNC = true;
|
||||
IRQS = 1;
|
||||
instr_pntr = irq_pntr = 0;
|
||||
PopulateCURINSTR(SYNC);
|
||||
if (NMIPending)
|
||||
{
|
||||
NMIPending = false;
|
||||
IN_SYNC = false;
|
||||
|
||||
Regs[ADDR] = 0xFFFC;
|
||||
PopulateCURINSTR(RD_INC, ALU, ADDR,
|
||||
RD_INC, ALU2, ADDR,
|
||||
SET_ADDR, PC, ALU, ALU2);
|
||||
irq_pntr = -1;
|
||||
IRQS = 3;
|
||||
|
||||
if (TraceCallback != null) { TraceCallback(new TraceInfo { Disassembly = "====SYNC NMI====", RegisterInfo = "" }); }
|
||||
}
|
||||
else if (FIRQPending)
|
||||
{
|
||||
if (!FlagF)
|
||||
{
|
||||
FIRQPending = false;
|
||||
|
||||
Regs[ADDR] = 0xFFF6;
|
||||
PopulateCURINSTR(RD_INC, ALU, ADDR,
|
||||
RD_INC, ALU2, ADDR,
|
||||
SET_ADDR, PC, ALU, ALU2);
|
||||
irq_pntr = -1;
|
||||
IRQS = 3;
|
||||
|
||||
if (TraceCallback != null) { TraceCallback(new TraceInfo { Disassembly = "====SYNC FIRQ====", RegisterInfo = "" }); }
|
||||
}
|
||||
else
|
||||
{
|
||||
FIRQPending = false;
|
||||
IN_SYNC = false;
|
||||
IRQS = 2;
|
||||
instr_pntr = irq_pntr = 0;
|
||||
PopulateCURINSTR(IDLE,
|
||||
IDLE);
|
||||
}
|
||||
}
|
||||
else if (IRQPending)
|
||||
{
|
||||
if (!FlagI)
|
||||
{
|
||||
IRQPending = false;
|
||||
IN_SYNC = false;
|
||||
|
||||
Regs[ADDR] = 0xFFF8;
|
||||
PopulateCURINSTR(RD_INC, ALU, ADDR,
|
||||
RD_INC, ALU2, ADDR,
|
||||
SET_ADDR, PC, ALU, ALU2);
|
||||
irq_pntr = -1;
|
||||
IRQS = 3;
|
||||
|
||||
if (TraceCallback != null) { TraceCallback(new TraceInfo { Disassembly = "====SYNC IRQ====", RegisterInfo = "" }); }
|
||||
}
|
||||
else
|
||||
{
|
||||
FIRQPending = false;
|
||||
IN_SYNC = false;
|
||||
IRQS = 2;
|
||||
instr_pntr = irq_pntr = 0;
|
||||
PopulateCURINSTR(IDLE,
|
||||
IDLE);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
IN_SYNC = true;
|
||||
IRQS = -1;
|
||||
instr_pntr = irq_pntr = 0;
|
||||
PopulateCURINSTR(SYNC);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -525,62 +594,31 @@ namespace BizHawk.Emulation.Common.Components.MC6809
|
|||
|
||||
if (TraceCallback != null) { TraceCallback(new TraceInfo { Disassembly = "====NMI====", RegisterInfo = "" }); }
|
||||
|
||||
IN_SYNC = false;
|
||||
NMI_();
|
||||
NMICallback();
|
||||
instr_pntr = irq_pntr = 0;
|
||||
}
|
||||
// fast IRQ has next priority
|
||||
else if (FIRQPending)
|
||||
else if (FIRQPending && !FlagF)
|
||||
{
|
||||
if (!FlagF)
|
||||
{
|
||||
FIRQPending = false;
|
||||
FIRQPending = false;
|
||||
|
||||
if (TraceCallback != null) { TraceCallback(new TraceInfo { Disassembly = "====FIRQ====", RegisterInfo = "" }); }
|
||||
if (TraceCallback != null) { TraceCallback(new TraceInfo { Disassembly = "====FIRQ====", RegisterInfo = "" }); }
|
||||
|
||||
IN_SYNC = false;
|
||||
FIRQ_();
|
||||
FIRQCallback();
|
||||
instr_pntr = irq_pntr = 0;
|
||||
}
|
||||
else if (IN_SYNC)
|
||||
{
|
||||
FIRQPending = false;
|
||||
|
||||
if (TraceCallback != null) { TraceCallback(new TraceInfo { Disassembly = "====SYNC====", RegisterInfo = "" }); }
|
||||
|
||||
IN_SYNC = false;
|
||||
IRQS = 1;
|
||||
instr_pntr = irq_pntr = 0;
|
||||
PopulateCURINSTR(IDLE);
|
||||
}
|
||||
FIRQ_();
|
||||
FIRQCallback();
|
||||
instr_pntr = irq_pntr = 0;
|
||||
}
|
||||
// then regular IRQ
|
||||
else if (IRQPending && !FlagI)
|
||||
{
|
||||
if (!FlagI)
|
||||
{
|
||||
IRQPending = false;
|
||||
IRQPending = false;
|
||||
|
||||
if (TraceCallback != null) { TraceCallback(new TraceInfo { Disassembly = "====IRQ====", RegisterInfo = "" }); }
|
||||
if (TraceCallback != null) { TraceCallback(new TraceInfo { Disassembly = "====IRQ====", RegisterInfo = "" }); }
|
||||
|
||||
IN_SYNC = false;
|
||||
IRQ_();
|
||||
IRQCallback();
|
||||
instr_pntr = irq_pntr = 0;
|
||||
}
|
||||
else if (IN_SYNC)
|
||||
{
|
||||
IRQPending = false;
|
||||
|
||||
if (TraceCallback != null) { TraceCallback(new TraceInfo { Disassembly = "====SYNC====", RegisterInfo = "" }); }
|
||||
|
||||
IN_SYNC = false;
|
||||
IRQS = 1;
|
||||
instr_pntr = irq_pntr = 0;
|
||||
PopulateCURINSTR(IDLE);
|
||||
}
|
||||
IRQ_();
|
||||
IRQCallback();
|
||||
instr_pntr = irq_pntr = 0;
|
||||
}
|
||||
// otherwise start the next instruction
|
||||
else
|
||||
|
|
|
@ -7,7 +7,10 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
|
|||
{
|
||||
public partial class Atari2600 : IStatable
|
||||
{
|
||||
public bool BinarySaveStatesPreferred => false;
|
||||
public bool BinarySaveStatesPreferred
|
||||
{
|
||||
get { return true; }
|
||||
}
|
||||
|
||||
public void SaveStateText(TextWriter writer)
|
||||
{
|
||||
|
|
|
@ -0,0 +1,220 @@
|
|||
using System;
|
||||
|
||||
using BizHawk.Common;
|
||||
using BizHawk.Common.BufferExtensions;
|
||||
using BizHawk.Emulation.Common;
|
||||
using BizHawk.Common.NumberExtensions;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Nintendo.O2Hawk
|
||||
{
|
||||
// Audio Emulation
|
||||
public class Audio : ISoundProvider
|
||||
{
|
||||
public O2Hawk Core { get; set; }
|
||||
|
||||
private BlipBuffer _blip_L = new BlipBuffer(15000);
|
||||
private BlipBuffer _blip_R = new BlipBuffer(15000);
|
||||
|
||||
public const int NR10 = 0;
|
||||
public const int NR11 = 1;
|
||||
public const int NR12 = 2;
|
||||
public const int NR13 = 3;
|
||||
public const int NR14 = 4;
|
||||
public const int NR21 = 5;
|
||||
public const int NR22 = 6;
|
||||
public const int NR23 = 7;
|
||||
public const int NR24 = 8;
|
||||
public const int NR30 = 9;
|
||||
public const int NR31 = 10;
|
||||
public const int NR32 = 11;
|
||||
public const int NR33 = 12;
|
||||
public const int NR34 = 13;
|
||||
public const int NR41 = 14;
|
||||
public const int NR42 = 15;
|
||||
public const int NR43 = 16;
|
||||
public const int NR44 = 17;
|
||||
public const int NR50 = 18;
|
||||
public const int NR51 = 19;
|
||||
public const int NR52 = 20;
|
||||
|
||||
|
||||
public byte[] Audio_Regs = new byte[21];
|
||||
|
||||
// Contol Variables
|
||||
public bool AUD_CTRL_vin_L_en;
|
||||
public bool AUD_CTRL_vin_R_en;
|
||||
public bool AUD_CTRL_sq1_L_en;
|
||||
public bool AUD_CTRL_sq2_L_en;
|
||||
public bool AUD_CTRL_wave_L_en;
|
||||
public bool AUD_CTRL_noise_L_en;
|
||||
public bool AUD_CTRL_sq1_R_en;
|
||||
public bool AUD_CTRL_sq2_R_en;
|
||||
public bool AUD_CTRL_wave_R_en;
|
||||
public bool AUD_CTRL_noise_R_en;
|
||||
public bool AUD_CTRL_power;
|
||||
public byte AUD_CTRL_vol_L;
|
||||
public byte AUD_CTRL_vol_R;
|
||||
|
||||
public byte sample;
|
||||
|
||||
public uint master_audio_clock;
|
||||
|
||||
public int latched_sample_L, latched_sample_R;
|
||||
|
||||
public byte ReadReg(int addr)
|
||||
{
|
||||
byte ret = 0;
|
||||
|
||||
switch (addr)
|
||||
{
|
||||
case 0xFF10: ret = (byte)(Audio_Regs[NR10]); break; // NR10 (sweep)
|
||||
case 0xFF11: ret = (byte)(Audio_Regs[NR11]); break; // NR11 (sound length / wave pattern duty %)
|
||||
case 0xFF12: ret = (byte)(Audio_Regs[NR12]); break; // NR12 (envelope)
|
||||
case 0xFF13: ret = (byte)(Audio_Regs[NR13]); break; // NR13 (freq low)
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
public void WriteReg(int addr, byte value)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void tick()
|
||||
{
|
||||
|
||||
// add up components to each channel
|
||||
int L_final = 0;
|
||||
int R_final = 0;
|
||||
|
||||
if (AUD_CTRL_sq1_L_en) { L_final += 0; }
|
||||
|
||||
|
||||
if (AUD_CTRL_sq1_R_en) { R_final += 0; }
|
||||
|
||||
L_final *= (AUD_CTRL_vol_L + 1) * 40;
|
||||
R_final *= (AUD_CTRL_vol_R + 1) * 40;
|
||||
|
||||
if (L_final != latched_sample_L)
|
||||
{
|
||||
_blip_L.AddDelta(master_audio_clock, L_final - latched_sample_L);
|
||||
latched_sample_L = L_final;
|
||||
}
|
||||
|
||||
if (R_final != latched_sample_R)
|
||||
{
|
||||
_blip_R.AddDelta(master_audio_clock, R_final - latched_sample_R);
|
||||
latched_sample_R = R_final;
|
||||
}
|
||||
|
||||
master_audio_clock++;
|
||||
}
|
||||
|
||||
public void power_off()
|
||||
{
|
||||
for (int i = 0; i < 0x16; i++)
|
||||
{
|
||||
WriteReg(0xFF10 + i, 0);
|
||||
}
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
Audio_Regs = new byte[21];
|
||||
|
||||
master_audio_clock = 0;
|
||||
|
||||
sample = 0;
|
||||
|
||||
_blip_L.SetRates(4194304, 44100);
|
||||
_blip_R.SetRates(4194304, 44100);
|
||||
}
|
||||
|
||||
public void SyncState(Serializer ser)
|
||||
{
|
||||
ser.Sync(nameof(Audio_Regs), ref Audio_Regs, false);
|
||||
|
||||
ser.Sync(nameof(master_audio_clock), ref master_audio_clock);
|
||||
|
||||
ser.Sync(nameof(sample), ref sample);
|
||||
ser.Sync(nameof(latched_sample_L), ref latched_sample_L);
|
||||
ser.Sync(nameof(latched_sample_R), ref latched_sample_R);
|
||||
|
||||
ser.Sync(nameof(AUD_CTRL_vin_L_en), ref AUD_CTRL_vin_L_en);
|
||||
ser.Sync(nameof(AUD_CTRL_vin_R_en), ref AUD_CTRL_vin_R_en);
|
||||
ser.Sync(nameof(AUD_CTRL_sq1_L_en), ref AUD_CTRL_sq1_L_en);
|
||||
ser.Sync(nameof(AUD_CTRL_sq2_L_en), ref AUD_CTRL_sq2_L_en);
|
||||
ser.Sync(nameof(AUD_CTRL_wave_L_en), ref AUD_CTRL_wave_L_en);
|
||||
ser.Sync(nameof(AUD_CTRL_noise_L_en), ref AUD_CTRL_noise_L_en);
|
||||
ser.Sync(nameof(AUD_CTRL_sq1_R_en), ref AUD_CTRL_sq1_R_en);
|
||||
ser.Sync(nameof(AUD_CTRL_sq2_R_en), ref AUD_CTRL_sq2_R_en);
|
||||
ser.Sync(nameof(AUD_CTRL_wave_R_en), ref AUD_CTRL_wave_R_en);
|
||||
ser.Sync(nameof(AUD_CTRL_noise_R_en), ref AUD_CTRL_noise_R_en);
|
||||
ser.Sync(nameof(AUD_CTRL_power), ref AUD_CTRL_power);
|
||||
ser.Sync(nameof(AUD_CTRL_vol_L), ref AUD_CTRL_vol_L);
|
||||
ser.Sync(nameof(AUD_CTRL_vol_R), ref AUD_CTRL_vol_R);
|
||||
}
|
||||
|
||||
#region audio
|
||||
|
||||
public bool CanProvideAsync => false;
|
||||
|
||||
public void SetSyncMode(SyncSoundMode mode)
|
||||
{
|
||||
if (mode != SyncSoundMode.Sync)
|
||||
{
|
||||
throw new InvalidOperationException("Only Sync mode is supported_");
|
||||
}
|
||||
}
|
||||
|
||||
public SyncSoundMode SyncMode => SyncSoundMode.Sync;
|
||||
|
||||
public void GetSamplesSync(out short[] samples, out int nsamp)
|
||||
{
|
||||
_blip_L.EndFrame(master_audio_clock);
|
||||
_blip_R.EndFrame(master_audio_clock);
|
||||
|
||||
nsamp = _blip_L.SamplesAvailable();
|
||||
|
||||
samples = new short[nsamp * 2];
|
||||
|
||||
if (nsamp != 0)
|
||||
{
|
||||
_blip_L.ReadSamplesLeft(samples, nsamp);
|
||||
_blip_R.ReadSamplesRight(samples, nsamp);
|
||||
}
|
||||
|
||||
master_audio_clock = 0;
|
||||
}
|
||||
|
||||
public void GetSamplesAsync(short[] samples)
|
||||
{
|
||||
throw new NotSupportedException("Async is not available");
|
||||
}
|
||||
|
||||
public void DiscardSamples()
|
||||
{
|
||||
_blip_L.Clear();
|
||||
_blip_R.Clear();
|
||||
master_audio_clock = 0;
|
||||
}
|
||||
|
||||
private void GetSamples(short[] samples)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void DisposeSound()
|
||||
{
|
||||
_blip_L.Clear();
|
||||
_blip_R.Clear();
|
||||
_blip_L.Dispose();
|
||||
_blip_R.Dispose();
|
||||
_blip_L = null;
|
||||
_blip_R = null;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
|
@ -0,0 +1,291 @@
|
|||
using System;
|
||||
using BizHawk.Common.NumberExtensions;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Nintendo.O2Hawk
|
||||
{
|
||||
public partial class O2Hawk
|
||||
{
|
||||
public byte Read_Registers(int addr)
|
||||
{
|
||||
byte ret = 0;
|
||||
|
||||
switch (addr)
|
||||
{
|
||||
// Read Input
|
||||
case 0xFF00:
|
||||
_islag = false;
|
||||
ret = input_register;
|
||||
break;
|
||||
|
||||
// Serial data port
|
||||
case 0xFF01:
|
||||
ret = serialport.ReadReg(addr);
|
||||
break;
|
||||
|
||||
// Serial port control
|
||||
case 0xFF02:
|
||||
ret = serialport.ReadReg(addr);
|
||||
break;
|
||||
|
||||
// Interrupt flags
|
||||
case 0xFF0F:
|
||||
|
||||
break;
|
||||
|
||||
// audio regs
|
||||
case 0xFF10:
|
||||
case 0xFF11:
|
||||
case 0xFF12:
|
||||
case 0xFF13:
|
||||
case 0xFF14:
|
||||
case 0xFF16:
|
||||
case 0xFF17:
|
||||
case 0xFF18:
|
||||
case 0xFF19:
|
||||
case 0xFF1A:
|
||||
case 0xFF1B:
|
||||
case 0xFF1C:
|
||||
case 0xFF1D:
|
||||
case 0xFF1E:
|
||||
case 0xFF20:
|
||||
case 0xFF21:
|
||||
case 0xFF22:
|
||||
case 0xFF23:
|
||||
case 0xFF24:
|
||||
case 0xFF25:
|
||||
case 0xFF26:
|
||||
case 0xFF30:
|
||||
case 0xFF31:
|
||||
case 0xFF32:
|
||||
case 0xFF33:
|
||||
case 0xFF34:
|
||||
case 0xFF35:
|
||||
case 0xFF36:
|
||||
case 0xFF37:
|
||||
case 0xFF38:
|
||||
case 0xFF39:
|
||||
case 0xFF3A:
|
||||
case 0xFF3B:
|
||||
case 0xFF3C:
|
||||
case 0xFF3D:
|
||||
case 0xFF3E:
|
||||
case 0xFF3F:
|
||||
ret = audio.ReadReg(addr);
|
||||
break;
|
||||
|
||||
// PPU Regs
|
||||
case 0xFF40:
|
||||
case 0xFF41:
|
||||
case 0xFF42:
|
||||
case 0xFF43:
|
||||
case 0xFF44:
|
||||
case 0xFF45:
|
||||
case 0xFF46:
|
||||
case 0xFF47:
|
||||
case 0xFF48:
|
||||
case 0xFF49:
|
||||
case 0xFF4A:
|
||||
case 0xFF4B:
|
||||
ret = ppu.ReadReg(addr);
|
||||
break;
|
||||
|
||||
// Speed Control for GBC
|
||||
case 0xFF4D:
|
||||
|
||||
break;
|
||||
|
||||
case 0xFF4F: // VBK
|
||||
|
||||
break;
|
||||
|
||||
// Bios control register. Not sure if it is readable
|
||||
case 0xFF50:
|
||||
ret = 0xFF;
|
||||
break;
|
||||
|
||||
// PPU Regs for GBC
|
||||
case 0xFF51:
|
||||
case 0xFF52:
|
||||
case 0xFF53:
|
||||
case 0xFF54:
|
||||
case 0xFF55:
|
||||
|
||||
break;
|
||||
|
||||
case 0xFF56:
|
||||
|
||||
break;
|
||||
|
||||
case 0xFF68:
|
||||
case 0xFF69:
|
||||
case 0xFF6A:
|
||||
case 0xFF6B:
|
||||
|
||||
break;
|
||||
|
||||
// Speed Control for GBC
|
||||
case 0xFF70:
|
||||
|
||||
break;
|
||||
|
||||
case 0xFF6C:
|
||||
case 0xFF72:
|
||||
case 0xFF73:
|
||||
case 0xFF74:
|
||||
case 0xFF75:
|
||||
case 0xFF76:
|
||||
case 0xFF77:
|
||||
|
||||
break;
|
||||
|
||||
// interrupt control register
|
||||
case 0xFFFF:
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
ret = 0xFF;
|
||||
break;
|
||||
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public void Write_Registers(int addr, byte value)
|
||||
{
|
||||
switch (addr)
|
||||
{
|
||||
// select input
|
||||
case 0xFF00:
|
||||
|
||||
break;
|
||||
|
||||
// Serial data port
|
||||
case 0xFF01:
|
||||
serialport.WriteReg(addr, value);
|
||||
break;
|
||||
|
||||
// Serial port control
|
||||
case 0xFF02:
|
||||
serialport.WriteReg(addr, value);
|
||||
break;
|
||||
|
||||
// Interrupt flags
|
||||
case 0xFF0F:
|
||||
|
||||
break;
|
||||
|
||||
// audio regs
|
||||
case 0xFF10:
|
||||
case 0xFF11:
|
||||
case 0xFF12:
|
||||
case 0xFF13:
|
||||
case 0xFF14:
|
||||
case 0xFF16:
|
||||
case 0xFF17:
|
||||
case 0xFF18:
|
||||
case 0xFF19:
|
||||
case 0xFF1A:
|
||||
case 0xFF1B:
|
||||
case 0xFF1C:
|
||||
case 0xFF1D:
|
||||
case 0xFF1E:
|
||||
case 0xFF20:
|
||||
case 0xFF21:
|
||||
case 0xFF22:
|
||||
case 0xFF23:
|
||||
case 0xFF24:
|
||||
case 0xFF25:
|
||||
case 0xFF26:
|
||||
case 0xFF30:
|
||||
case 0xFF31:
|
||||
case 0xFF32:
|
||||
case 0xFF33:
|
||||
case 0xFF34:
|
||||
case 0xFF35:
|
||||
case 0xFF36:
|
||||
case 0xFF37:
|
||||
case 0xFF38:
|
||||
case 0xFF39:
|
||||
case 0xFF3A:
|
||||
case 0xFF3B:
|
||||
case 0xFF3C:
|
||||
case 0xFF3D:
|
||||
case 0xFF3E:
|
||||
case 0xFF3F:
|
||||
audio.WriteReg(addr, value);
|
||||
break;
|
||||
|
||||
// PPU Regs
|
||||
case 0xFF40:
|
||||
case 0xFF41:
|
||||
case 0xFF42:
|
||||
case 0xFF43:
|
||||
case 0xFF44:
|
||||
case 0xFF45:
|
||||
case 0xFF46:
|
||||
case 0xFF47:
|
||||
case 0xFF48:
|
||||
case 0xFF49:
|
||||
case 0xFF4A:
|
||||
case 0xFF4B:
|
||||
ppu.WriteReg(addr, value);
|
||||
break;
|
||||
|
||||
// GBC compatibility register (I think)
|
||||
case 0xFF4C:
|
||||
|
||||
break;
|
||||
|
||||
// Speed Control for GBC
|
||||
case 0xFF4D:
|
||||
|
||||
break;
|
||||
|
||||
// VBK
|
||||
case 0xFF4F:
|
||||
|
||||
break;
|
||||
|
||||
// Bios control register. Writing 1 permanently disables BIOS until a power cycle occurs
|
||||
case 0xFF50:
|
||||
|
||||
break;
|
||||
|
||||
// PPU Regs for GBC
|
||||
case 0xFF51:
|
||||
case 0xFF52:
|
||||
case 0xFF53:
|
||||
case 0xFF54:
|
||||
case 0xFF55:
|
||||
|
||||
break;
|
||||
|
||||
case 0xFF56:
|
||||
|
||||
break;
|
||||
|
||||
case 0xFF68:
|
||||
case 0xFF69:
|
||||
case 0xFF6A:
|
||||
case 0xFF6B:
|
||||
//if (GBC_compat)
|
||||
//{
|
||||
ppu.WriteReg(addr, value);
|
||||
//}
|
||||
break;
|
||||
|
||||
default:
|
||||
Console.Write(addr);
|
||||
Console.Write(" ");
|
||||
Console.WriteLine(value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void Register_Reset()
|
||||
{
|
||||
input_register = 0xCF; // not reading any input
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
using BizHawk.Common;
|
||||
using System;
|
||||
|
||||
using BizHawk.Emulation.Common.Components.I8048;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Nintendo.O2Hawk
|
||||
{
|
||||
public class MapperBase
|
||||
{
|
||||
public O2Hawk Core { get; set; }
|
||||
|
||||
public virtual byte ReadMemory(ushort addr)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
public virtual byte PeekMemory(ushort addr)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
public virtual void WriteMemory(ushort addr, byte value)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void PokeMemory(ushort addr, byte value)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void SyncState(Serializer ser)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void Dispose()
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void Initialize()
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void Mapper_Tick()
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void RTC_Get(int value, int index)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void MapCDL(ushort addr, I8048.eCDLogMemFlags flags)
|
||||
{
|
||||
}
|
||||
|
||||
protected void SetCDLROM(I8048.eCDLogMemFlags flags, int cdladdr)
|
||||
{
|
||||
Core.SetCDL(flags, "ROM", cdladdr);
|
||||
}
|
||||
|
||||
protected void SetCDLRAM(I8048.eCDLogMemFlags flags, int cdladdr)
|
||||
{
|
||||
Core.SetCDL(flags, "CartRAM", cdladdr);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
using BizHawk.Common;
|
||||
using BizHawk.Common.NumberExtensions;
|
||||
using System;
|
||||
|
||||
using BizHawk.Emulation.Common.Components.I8048;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Nintendo.O2Hawk
|
||||
{
|
||||
// Default mapper with no bank switching
|
||||
public class MapperDefault : MapperBase
|
||||
{
|
||||
public override void Initialize()
|
||||
{
|
||||
// nothing to initialize
|
||||
}
|
||||
|
||||
public override byte ReadMemory(ushort addr)
|
||||
{
|
||||
if (addr < 0x8000)
|
||||
{
|
||||
return Core._rom[addr];
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Core.cart_RAM != null)
|
||||
{
|
||||
return Core.cart_RAM[addr - 0xA000];
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void MapCDL(ushort addr, I8048.eCDLogMemFlags flags)
|
||||
{
|
||||
if (addr < 0x8000)
|
||||
{
|
||||
SetCDLROM(flags, addr);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Core.cart_RAM != null)
|
||||
{
|
||||
SetCDLRAM(flags, addr - 0xA000);
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override byte PeekMemory(ushort addr)
|
||||
{
|
||||
return ReadMemory(addr);
|
||||
}
|
||||
|
||||
public override void WriteMemory(ushort addr, byte value)
|
||||
{
|
||||
if (addr < 0x8000)
|
||||
{
|
||||
// no mapping hardware available
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Core.cart_RAM != null)
|
||||
{
|
||||
Core.cart_RAM[addr - 0xA000] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void PokeMemory(ushort addr, byte value)
|
||||
{
|
||||
WriteMemory(addr, value);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
TODO:
|
||||
Official Mappers
|
||||
Unofficial Mappers
|
|
@ -0,0 +1,59 @@
|
|||
using System;
|
||||
|
||||
using BizHawk.Common.BufferExtensions;
|
||||
using BizHawk.Emulation.Common;
|
||||
|
||||
/*
|
||||
$0400-$0FFF Cartridge (Only 2K accessible, bit 10 not mapped to cart)
|
||||
$0000-$03FF BIOS
|
||||
*/
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Nintendo.O2Hawk
|
||||
{
|
||||
public partial class O2Hawk
|
||||
{
|
||||
public byte ReadMemory(ushort addr)
|
||||
{
|
||||
uint flags = (uint)(MemoryCallbackFlags.AccessRead);
|
||||
MemoryCallbacks.CallMemoryCallbacks(addr, 0, flags, "System Bus");
|
||||
addr_access = addr;
|
||||
|
||||
if (addr < 0x400)
|
||||
{
|
||||
return _bios[addr];
|
||||
}
|
||||
else
|
||||
{
|
||||
return mapper.ReadMemory(addr);
|
||||
}
|
||||
}
|
||||
|
||||
public void WriteMemory(ushort addr, byte value)
|
||||
{
|
||||
uint flags = (uint)(MemoryCallbackFlags.AccessWrite);
|
||||
MemoryCallbacks.CallMemoryCallbacks(addr, value, flags, "System Bus");
|
||||
addr_access = addr;
|
||||
|
||||
if (addr < 0x400)
|
||||
{
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
mapper.WriteMemory(addr, value);
|
||||
}
|
||||
}
|
||||
|
||||
public byte PeekMemory(ushort addr)
|
||||
{
|
||||
if (addr < 0x400)
|
||||
{
|
||||
return _bios[addr];
|
||||
}
|
||||
else
|
||||
{
|
||||
return mapper.PeekMemory(addr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using BizHawk.Emulation.Common;
|
||||
using BizHawk.Emulation.Common.Components.I8048;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Nintendo.O2Hawk
|
||||
{
|
||||
public partial class O2Hawk : ICodeDataLogger
|
||||
{
|
||||
private ICodeDataLog _cdl;
|
||||
|
||||
public void SetCDL(ICodeDataLog cdl)
|
||||
{
|
||||
_cdl = cdl;
|
||||
if (cdl == null)
|
||||
this.cpu.CDLCallback = null;
|
||||
else this.cpu.CDLCallback = CDLCpuCallback;
|
||||
}
|
||||
|
||||
public void NewCDL(ICodeDataLog cdl)
|
||||
{
|
||||
cdl["ROM"] = new byte[MemoryDomains["ROM"].Size];
|
||||
cdl["HRAM"] = new byte[MemoryDomains["Zero Page RAM"].Size];
|
||||
|
||||
cdl["WRAM"] = new byte[MemoryDomains["Main RAM"].Size];
|
||||
|
||||
if (MemoryDomains.Has("Cart RAM"))
|
||||
{
|
||||
cdl["CartRAM"] = new byte[MemoryDomains["Cart RAM"].Size];
|
||||
}
|
||||
|
||||
cdl.SubType = "O2";
|
||||
cdl.SubVer = 0;
|
||||
}
|
||||
|
||||
[FeatureNotImplemented]
|
||||
void ICodeDataLogger.DisassembleCDL(Stream s, ICodeDataLog cdl)
|
||||
{
|
||||
}
|
||||
|
||||
public void SetCDL(I8048.eCDLogMemFlags flags, string type, int cdladdr)
|
||||
{
|
||||
if (type == null) return;
|
||||
byte val = (byte)flags;
|
||||
_cdl[type][cdladdr] |= (byte)flags;
|
||||
}
|
||||
|
||||
void CDLCpuCallback(ushort addr, I8048.eCDLogMemFlags flags)
|
||||
{
|
||||
|
||||
if (addr < 0x400)
|
||||
{
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
mapper.MapCDL(addr, flags);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using BizHawk.Emulation.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Nintendo.O2Hawk
|
||||
{
|
||||
public partial class O2Hawk : IDebuggable
|
||||
{
|
||||
public IDictionary<string, RegisterValue> GetCpuFlagsAndRegisters()
|
||||
{
|
||||
return new Dictionary<string, RegisterValue>
|
||||
{
|
||||
/*
|
||||
["A"] = cpu.A,
|
||||
["X"] = cpu.X,
|
||||
["Y"] = cpu.Y,
|
||||
["S"] = cpu.S,
|
||||
["PC"] = cpu.PC,
|
||||
["Flag C"] = cpu.FlagC,
|
||||
["Flag Z"] = cpu.FlagZ,
|
||||
["Flag I"] = cpu.FlagI,
|
||||
["Flag D"] = cpu.FlagD,
|
||||
["Flag B"] = cpu.FlagB,
|
||||
["Flag V"] = cpu.FlagV,
|
||||
["Flag N"] = cpu.FlagN,
|
||||
["Flag T"] = cpu.FlagT
|
||||
*/
|
||||
};
|
||||
}
|
||||
|
||||
public void SetCpuRegister(string register, int value)
|
||||
{
|
||||
switch (register)
|
||||
{
|
||||
default:
|
||||
throw new InvalidOperationException();
|
||||
case "A":
|
||||
//cpu.A = (byte)value;
|
||||
break;
|
||||
case "X":
|
||||
//cpu.X = (byte)value;
|
||||
break;
|
||||
case "Y":
|
||||
//cpu.Y = (byte)value;
|
||||
break;
|
||||
case "S":
|
||||
//cpu.S = (byte)value;
|
||||
break;
|
||||
case "PC":
|
||||
//cpu.PC = (ushort)value;
|
||||
break;
|
||||
case "Flag I":
|
||||
//cpu.FlagI = value > 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public IMemoryCallbackSystem MemoryCallbacks { get; } = new MemoryCallbackSystem(new[] { "System Bus" });
|
||||
|
||||
public bool CanStep(StepType type)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
[FeatureNotImplemented]
|
||||
public void Step(StepType type)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public long TotalExecutedCycles
|
||||
{
|
||||
get { return (long)cpu.TotalExecutedCycles; }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,197 @@
|
|||
using BizHawk.Common.NumberExtensions;
|
||||
using BizHawk.Emulation.Common;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Nintendo.O2Hawk
|
||||
{
|
||||
public partial class O2Hawk : IEmulator, IVideoProvider
|
||||
{
|
||||
public IEmulatorServiceProvider ServiceProvider { get; }
|
||||
|
||||
public ControllerDefinition ControllerDefinition => _controllerDeck.Definition;
|
||||
|
||||
public byte controller_state;
|
||||
public ushort Acc_X_state;
|
||||
public ushort Acc_Y_state;
|
||||
public bool in_vblank_old;
|
||||
public bool in_vblank;
|
||||
public bool vblank_rise;
|
||||
|
||||
public bool FrameAdvance(IController controller, bool render, bool rendersound)
|
||||
{
|
||||
//Console.WriteLine("-----------------------FRAME-----------------------");
|
||||
|
||||
if (_tracer.Enabled)
|
||||
{
|
||||
cpu.TraceCallback = s => _tracer.Put(s);
|
||||
}
|
||||
else
|
||||
{
|
||||
cpu.TraceCallback = null;
|
||||
}
|
||||
|
||||
_frame++;
|
||||
|
||||
if (controller.IsPressed("Power"))
|
||||
{
|
||||
HardReset();
|
||||
}
|
||||
|
||||
_islag = true;
|
||||
|
||||
do_frame(controller);
|
||||
|
||||
if (_islag)
|
||||
{
|
||||
_lagcount++;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void do_frame(IController controller)
|
||||
{
|
||||
for (int i = 0; i < 70224; i++)
|
||||
{
|
||||
audio.tick();
|
||||
ppu.tick();
|
||||
ppu.DMA_tick();
|
||||
serialport.serial_transfer_tick();
|
||||
cpu.ExecuteOne();
|
||||
|
||||
if (in_vblank && !in_vblank_old)
|
||||
{
|
||||
// update the controller state on VBlank
|
||||
GetControllerState(controller);
|
||||
|
||||
// check if controller state caused interrupt
|
||||
do_controller_check();
|
||||
|
||||
// send the image on VBlank
|
||||
SendVideoBuffer();
|
||||
}
|
||||
|
||||
in_vblank_old = in_vblank;
|
||||
}
|
||||
|
||||
// turn off the screen so the image doesnt persist
|
||||
// but dont turn off blank_frame yet, it still needs to be true until the next VBL
|
||||
// this doesn't run for GBC, some games, ex MIB the series 2, rely on the screens persistence while off to make video look smooth.
|
||||
// But some GB gams, ex Battletoads, turn off the screen for a long time from the middle of the frame, so need to be cleared.
|
||||
if (ppu.clear_screen)
|
||||
{
|
||||
for (int j = 0; j < frame_buffer.Length; j++) { frame_buffer[j] = (int)color_palette[0]; }
|
||||
ppu.clear_screen = false;
|
||||
}
|
||||
}
|
||||
|
||||
public void do_single_step()
|
||||
{
|
||||
audio.tick();
|
||||
ppu.tick();
|
||||
ppu.DMA_tick();
|
||||
serialport.serial_transfer_tick();
|
||||
cpu.ExecuteOne();
|
||||
}
|
||||
|
||||
public void do_controller_check()
|
||||
{
|
||||
// check if new input changed the input register and triggered IRQ
|
||||
byte contr_prev = input_register;
|
||||
|
||||
input_register &= 0xF0;
|
||||
if ((input_register & 0x30) == 0x20)
|
||||
{
|
||||
input_register |= (byte)(controller_state & 0xF);
|
||||
}
|
||||
else if ((input_register & 0x30) == 0x10)
|
||||
{
|
||||
input_register |= (byte)((controller_state & 0xF0) >> 4);
|
||||
}
|
||||
else if ((input_register & 0x30) == 0x00)
|
||||
{
|
||||
// if both polls are set, then a bit is zero if either or both pins are zero
|
||||
byte temp = (byte)((controller_state & 0xF) & ((controller_state & 0xF0) >> 4));
|
||||
input_register |= temp;
|
||||
}
|
||||
else
|
||||
{
|
||||
input_register |= 0xF;
|
||||
}
|
||||
}
|
||||
|
||||
public void GetControllerState(IController controller)
|
||||
{
|
||||
InputCallbacks.Call();
|
||||
controller_state = _controllerDeck.ReadPort1(controller);
|
||||
|
||||
Acc_X_state = _controllerDeck.ReadAccX1(controller);
|
||||
Acc_Y_state = _controllerDeck.ReadAccY1(controller);
|
||||
}
|
||||
|
||||
public int Frame => _frame;
|
||||
|
||||
public string SystemId => "O2";
|
||||
|
||||
public bool DeterministicEmulation { get; set; }
|
||||
|
||||
public void ResetCounters()
|
||||
{
|
||||
_frame = 0;
|
||||
_lagcount = 0;
|
||||
_islag = false;
|
||||
}
|
||||
|
||||
public CoreComm CoreComm { get; }
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
audio.DisposeSound();
|
||||
}
|
||||
|
||||
#region Video provider
|
||||
|
||||
public int _frameHz = 60;
|
||||
|
||||
public int[] _vidbuffer;
|
||||
|
||||
public int[] frame_buffer;
|
||||
|
||||
public int[] GetVideoBuffer()
|
||||
{
|
||||
return frame_buffer;
|
||||
}
|
||||
|
||||
public void SendVideoBuffer()
|
||||
{
|
||||
if (ppu.blank_frame)
|
||||
{
|
||||
for (int i = 0; i < _vidbuffer.Length; i++)
|
||||
{
|
||||
_vidbuffer[i] = (int)color_palette[0];
|
||||
}
|
||||
}
|
||||
|
||||
for (int j = 0; j < frame_buffer.Length; j++) { frame_buffer[j] = _vidbuffer[j]; }
|
||||
|
||||
ppu.blank_frame = false;
|
||||
}
|
||||
|
||||
public int VirtualWidth => 160;
|
||||
public int VirtualHeight => 144;
|
||||
public int BufferWidth => 160;
|
||||
public int BufferHeight => 144;
|
||||
public int BackgroundColor => unchecked((int)0xFF000000);
|
||||
public int VsyncNumerator => _frameHz;
|
||||
public int VsyncDenominator => 1;
|
||||
|
||||
public static readonly uint[] color_palette_BW = { 0xFFFFFFFF , 0xFFAAAAAA, 0xFF555555, 0xFF000000 };
|
||||
public static readonly uint[] color_palette_Gr = { 0xFFA4C505, 0xFF88A905, 0xFF1D551D, 0xFF052505 };
|
||||
|
||||
public uint[] color_palette = new uint[4];
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
using BizHawk.Emulation.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Nintendo.O2Hawk
|
||||
{
|
||||
public partial class O2Hawk : IInputPollable
|
||||
{
|
||||
public int LagCount
|
||||
{
|
||||
get { return _lagcount; }
|
||||
set { _lagcount = value; }
|
||||
}
|
||||
|
||||
public bool IsLagFrame
|
||||
{
|
||||
get { return _islag; }
|
||||
set { _islag = value; }
|
||||
}
|
||||
|
||||
public IInputCallbackSystem InputCallbacks { get; } = new InputCallbackSystem();
|
||||
|
||||
public bool _islag = true;
|
||||
private int _lagcount;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
using BizHawk.Emulation.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Nintendo.O2Hawk
|
||||
{
|
||||
public partial class O2Hawk
|
||||
{
|
||||
private IMemoryDomains MemoryDomains;
|
||||
|
||||
public void SetupMemoryDomains()
|
||||
{
|
||||
var domains = new List<MemoryDomain>
|
||||
{
|
||||
new MemoryDomainDelegate(
|
||||
"Main RAM",
|
||||
RAM.Length,
|
||||
MemoryDomain.Endian.Little,
|
||||
addr => RAM[addr],
|
||||
(addr, value) => RAM[addr] = value,
|
||||
1),
|
||||
new MemoryDomainDelegate(
|
||||
"System Bus",
|
||||
0X1000,
|
||||
MemoryDomain.Endian.Little,
|
||||
addr => PeekSystemBus(addr),
|
||||
(addr, value) => PokeSystemBus(addr, value),
|
||||
1),
|
||||
new MemoryDomainDelegate(
|
||||
"ROM",
|
||||
_rom.Length,
|
||||
MemoryDomain.Endian.Little,
|
||||
addr => _rom[addr],
|
||||
(addr, value) => _rom[addr] = value,
|
||||
1),
|
||||
new MemoryDomainDelegate(
|
||||
"VRAM",
|
||||
VRAM.Length,
|
||||
MemoryDomain.Endian.Little,
|
||||
addr => VRAM[addr],
|
||||
(addr, value) => VRAM[addr] = value,
|
||||
1)
|
||||
};
|
||||
|
||||
if (cart_RAM != null)
|
||||
{
|
||||
var CartRam = new MemoryDomainByteArray("Cart RAM", MemoryDomain.Endian.Little, cart_RAM, true, 1);
|
||||
domains.Add(CartRam);
|
||||
}
|
||||
|
||||
MemoryDomains = new MemoryDomainList(domains);
|
||||
(ServiceProvider as BasicServiceProvider).Register<IMemoryDomains>(MemoryDomains);
|
||||
}
|
||||
|
||||
private byte PeekSystemBus(long addr)
|
||||
{
|
||||
ushort addr2 = (ushort)(addr & 0xFFF);
|
||||
return PeekMemory(addr2);
|
||||
}
|
||||
|
||||
private void PokeSystemBus(long addr, byte value)
|
||||
{
|
||||
ushort addr2 = (ushort)(addr & 0xFFF);
|
||||
WriteMemory(addr2, value);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
using System;
|
||||
using BizHawk.Emulation.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Nintendo.O2Hawk
|
||||
{
|
||||
public partial class O2Hawk : ISaveRam
|
||||
{
|
||||
public byte[] CloneSaveRam()
|
||||
{
|
||||
if (cart_RAM != null)
|
||||
{
|
||||
return (byte[])cart_RAM.Clone();
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public void StoreSaveRam(byte[] data)
|
||||
{
|
||||
if (_syncSettings.Use_SRAM)
|
||||
{
|
||||
Buffer.BlockCopy(data, 0, cart_RAM, 0, data.Length);
|
||||
Console.WriteLine("loading SRAM here");
|
||||
}
|
||||
}
|
||||
|
||||
public bool SaveRamModified
|
||||
{
|
||||
get
|
||||
{
|
||||
return has_bat & _syncSettings.Use_SRAM;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,92 @@
|
|||
using System;
|
||||
using System.ComponentModel;
|
||||
|
||||
using Newtonsoft.Json;
|
||||
|
||||
using BizHawk.Common;
|
||||
using BizHawk.Emulation.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Nintendo.O2Hawk
|
||||
{
|
||||
public partial class O2Hawk : IEmulator, IStatable, ISettable<O2Hawk.O2Settings, O2Hawk.O2SyncSettings>
|
||||
{
|
||||
public O2Settings GetSettings()
|
||||
{
|
||||
return _settings.Clone();
|
||||
}
|
||||
|
||||
public O2SyncSettings GetSyncSettings()
|
||||
{
|
||||
return _syncSettings.Clone();
|
||||
}
|
||||
|
||||
public bool PutSettings(O2Settings o)
|
||||
{
|
||||
_settings = o;
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool PutSyncSettings(O2SyncSettings o)
|
||||
{
|
||||
bool ret = O2SyncSettings.NeedsReboot(_syncSettings, o);
|
||||
_syncSettings = o;
|
||||
return ret;
|
||||
}
|
||||
|
||||
private O2Settings _settings = new O2Settings();
|
||||
public O2SyncSettings _syncSettings = new O2SyncSettings();
|
||||
|
||||
public class O2Settings
|
||||
{
|
||||
public O2Settings Clone()
|
||||
{
|
||||
return (O2Settings)MemberwiseClone();
|
||||
}
|
||||
}
|
||||
|
||||
public class O2SyncSettings
|
||||
{
|
||||
[JsonIgnore]
|
||||
public string Port1 = O2HawkControllerDeck.DefaultControllerName;
|
||||
|
||||
public enum ControllerType
|
||||
{
|
||||
Default,
|
||||
Tilt
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
private ControllerType _O2Controller;
|
||||
|
||||
[DisplayName("Controller")]
|
||||
[Description("Select Controller Type")]
|
||||
[DefaultValue(ControllerType.Default)]
|
||||
public ControllerType O2Controller
|
||||
{
|
||||
get { return _O2Controller; }
|
||||
set
|
||||
{
|
||||
if (value == ControllerType.Default) { Port1 = O2HawkControllerDeck.DefaultControllerName; }
|
||||
else { Port1 = "Gameboy Controller + Tilt"; }
|
||||
|
||||
_O2Controller = value;
|
||||
}
|
||||
}
|
||||
|
||||
[DisplayName("Use Existing SaveRAM")]
|
||||
[Description("When true, existing SaveRAM will be loaded at boot up")]
|
||||
[DefaultValue(false)]
|
||||
public bool Use_SRAM { get; set; }
|
||||
|
||||
public O2SyncSettings Clone()
|
||||
{
|
||||
return (O2SyncSettings)MemberwiseClone();
|
||||
}
|
||||
|
||||
public static bool NeedsReboot(O2SyncSettings x, O2SyncSettings y)
|
||||
{
|
||||
return !DeepEquality.DeepEquals(x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
using System.IO;
|
||||
|
||||
using BizHawk.Common;
|
||||
using BizHawk.Emulation.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Nintendo.O2Hawk
|
||||
{
|
||||
public partial class O2Hawk : IStatable
|
||||
{
|
||||
public bool BinarySaveStatesPreferred => true;
|
||||
|
||||
public void SaveStateText(TextWriter writer)
|
||||
{
|
||||
SyncState(new Serializer(writer));
|
||||
}
|
||||
|
||||
public void LoadStateText(TextReader reader)
|
||||
{
|
||||
SyncState(new Serializer(reader));
|
||||
}
|
||||
|
||||
public void SaveStateBinary(BinaryWriter bw)
|
||||
{
|
||||
SyncState(new Serializer(bw));
|
||||
}
|
||||
|
||||
public void LoadStateBinary(BinaryReader br)
|
||||
{
|
||||
SyncState(new Serializer(br));
|
||||
}
|
||||
|
||||
public byte[] SaveStateBinary()
|
||||
{
|
||||
MemoryStream ms = new MemoryStream();
|
||||
BinaryWriter bw = new BinaryWriter(ms);
|
||||
SaveStateBinary(bw);
|
||||
bw.Flush();
|
||||
return ms.ToArray();
|
||||
}
|
||||
|
||||
private void SyncState(Serializer ser)
|
||||
{
|
||||
byte[] core = null;
|
||||
if (ser.IsWriter)
|
||||
{
|
||||
var ms = new MemoryStream();
|
||||
ms.Close();
|
||||
core = ms.ToArray();
|
||||
}
|
||||
cpu.SyncState(ser);
|
||||
mapper.SyncState(ser);
|
||||
ppu.SyncState(ser);
|
||||
serialport.SyncState(ser);
|
||||
audio.SyncState(ser);
|
||||
|
||||
ser.BeginSection("Odyssey2");
|
||||
ser.Sync(nameof(core), ref core, false);
|
||||
ser.Sync("Lag", ref _lagcount);
|
||||
ser.Sync("Frame", ref _frame);
|
||||
ser.Sync("IsLag", ref _islag);
|
||||
_controllerDeck.SyncState(ser);
|
||||
|
||||
ser.Sync(nameof(controller_state), ref controller_state);
|
||||
ser.Sync(nameof(Acc_X_state), ref Acc_X_state);
|
||||
ser.Sync(nameof(Acc_Y_state), ref Acc_Y_state);
|
||||
ser.Sync(nameof(in_vblank), ref in_vblank);
|
||||
ser.Sync(nameof(in_vblank_old), ref in_vblank_old);
|
||||
ser.Sync(nameof(vblank_rise), ref vblank_rise);
|
||||
ser.Sync(nameof(input_register), ref input_register);
|
||||
|
||||
// memory domains
|
||||
ser.Sync(nameof(RAM), ref RAM, false);
|
||||
ser.Sync(nameof(VRAM), ref VRAM, false);
|
||||
ser.Sync(nameof(OAM), ref OAM, false);
|
||||
ser.Sync(nameof(_bios), ref _bios, false);
|
||||
ser.Sync(nameof(RAM_Bank), ref RAM_Bank);
|
||||
ser.Sync(nameof(addr_access), ref addr_access);
|
||||
|
||||
ser.Sync(nameof(frame_buffer), ref frame_buffer, false);
|
||||
ser.Sync(nameof(_vidbuffer), ref _vidbuffer, false);
|
||||
|
||||
// probably a better way to do this
|
||||
if (cart_RAM != null)
|
||||
{
|
||||
ser.Sync(nameof(cart_RAM), ref cart_RAM, false);
|
||||
}
|
||||
|
||||
ser.EndSection();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,144 @@
|
|||
using System;
|
||||
|
||||
using BizHawk.Common.BufferExtensions;
|
||||
using BizHawk.Emulation.Common;
|
||||
using BizHawk.Emulation.Common.Components.I8048;
|
||||
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Nintendo.O2Hawk
|
||||
{
|
||||
[Core(
|
||||
"O2Hawk",
|
||||
"",
|
||||
isPorted: false,
|
||||
isReleased: false)]
|
||||
[ServiceNotApplicable(typeof(IDriveLight))]
|
||||
public partial class O2Hawk : IEmulator, ISaveRam, IDebuggable, IStatable, IInputPollable, IRegionable, ISettable<O2Hawk.O2Settings, O2Hawk.O2SyncSettings>
|
||||
{
|
||||
public byte input_register;
|
||||
|
||||
// memory domains
|
||||
public byte[] RAM = new byte[0x80];
|
||||
|
||||
public byte[] VRAM = new byte[0x4000];
|
||||
public byte[] OAM = new byte[0xA0];
|
||||
|
||||
public int RAM_Bank;
|
||||
|
||||
public byte[] _bios;
|
||||
public readonly byte[] _rom;
|
||||
public readonly byte[] header = new byte[0x50];
|
||||
|
||||
public byte[] cart_RAM;
|
||||
public bool has_bat;
|
||||
|
||||
private int _frame = 0;
|
||||
|
||||
public ushort addr_access;
|
||||
|
||||
public MapperBase mapper;
|
||||
|
||||
private readonly ITraceable _tracer;
|
||||
|
||||
public I8048 cpu;
|
||||
public PPU ppu;
|
||||
public Audio audio;
|
||||
public SerialPort serialport;
|
||||
|
||||
[CoreConstructor("O2")]
|
||||
public O2Hawk(CoreComm comm, GameInfo game, byte[] rom, /*string gameDbFn,*/ object settings, object syncSettings)
|
||||
{
|
||||
var ser = new BasicServiceProvider(this);
|
||||
|
||||
cpu = new I8048
|
||||
{
|
||||
ReadMemory = ReadMemory,
|
||||
WriteMemory = WriteMemory,
|
||||
PeekMemory = PeekMemory,
|
||||
DummyReadMemory = ReadMemory,
|
||||
OnExecFetch = ExecFetch,
|
||||
};
|
||||
|
||||
audio = new Audio();
|
||||
serialport = new SerialPort();
|
||||
|
||||
CoreComm = comm;
|
||||
|
||||
_settings = (O2Settings)settings ?? new O2Settings();
|
||||
_syncSettings = (O2SyncSettings)syncSettings ?? new O2SyncSettings();
|
||||
_controllerDeck = new O2HawkControllerDeck(_syncSettings.Port1);
|
||||
|
||||
byte[] Bios = null;
|
||||
|
||||
Bios = comm.CoreFileProvider.GetFirmware("O2", "World", true, "BIOS Not Found, Cannot Load");
|
||||
ppu = new PPU();
|
||||
|
||||
if (Bios == null)
|
||||
{
|
||||
throw new MissingFirmwareException("Missing Odyssey2 Bios");
|
||||
}
|
||||
|
||||
_bios = Bios;
|
||||
|
||||
Buffer.BlockCopy(rom, 0x100, header, 0, 0x50);
|
||||
|
||||
Console.WriteLine("MD5: " + rom.HashMD5(0, rom.Length));
|
||||
Console.WriteLine("SHA1: " + rom.HashSHA1(0, rom.Length));
|
||||
_rom = rom;
|
||||
Setup_Mapper();
|
||||
|
||||
_frameHz = 60;
|
||||
|
||||
audio.Core = this;
|
||||
ppu.Core = this;
|
||||
serialport.Core = this;
|
||||
|
||||
ser.Register<IVideoProvider>(this);
|
||||
ser.Register<ISoundProvider>(audio);
|
||||
ServiceProvider = ser;
|
||||
|
||||
_settings = (O2Settings)settings ?? new O2Settings();
|
||||
_syncSettings = (O2SyncSettings)syncSettings ?? new O2SyncSettings();
|
||||
|
||||
_tracer = new TraceBuffer { Header = cpu.TraceHeader };
|
||||
ser.Register<ITraceable>(_tracer);
|
||||
|
||||
SetupMemoryDomains();
|
||||
HardReset();
|
||||
}
|
||||
|
||||
public DisplayType Region => DisplayType.NTSC;
|
||||
|
||||
private readonly O2HawkControllerDeck _controllerDeck;
|
||||
|
||||
public void HardReset()
|
||||
{
|
||||
in_vblank = true; // we start off in vblank since the LCD is off
|
||||
in_vblank_old = true;
|
||||
|
||||
RAM_Bank = 1; // RAM bank always starts as 1 (even writing zero still sets 1)
|
||||
|
||||
Register_Reset();
|
||||
ppu.Reset();
|
||||
audio.Reset();
|
||||
serialport.Reset();
|
||||
|
||||
cpu.SetCallbacks(ReadMemory, PeekMemory, PeekMemory, WriteMemory);
|
||||
|
||||
_vidbuffer = new int[VirtualWidth * VirtualHeight];
|
||||
frame_buffer = new int[VirtualWidth * VirtualHeight];
|
||||
}
|
||||
|
||||
private void ExecFetch(ushort addr)
|
||||
{
|
||||
uint flags = (uint)(MemoryCallbackFlags.AccessRead);
|
||||
MemoryCallbacks.CallMemoryCallbacks(addr, 0, flags, "System Bus");
|
||||
}
|
||||
|
||||
private void Setup_Mapper()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
using BizHawk.Common;
|
||||
using BizHawk.Common.ReflectionExtensions;
|
||||
using BizHawk.Emulation.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Nintendo.O2Hawk
|
||||
{
|
||||
public class O2HawkControllerDeck
|
||||
{
|
||||
public O2HawkControllerDeck(string controller1Name)
|
||||
{
|
||||
if (!ValidControllerTypes.ContainsKey(controller1Name))
|
||||
{
|
||||
throw new InvalidOperationException("Invalid controller type: " + controller1Name);
|
||||
}
|
||||
|
||||
Port1 = (IPort)Activator.CreateInstance(ValidControllerTypes[controller1Name], 1);
|
||||
|
||||
Definition = new ControllerDefinition
|
||||
{
|
||||
Name = Port1.Definition.Name,
|
||||
BoolButtons = Port1.Definition.BoolButtons
|
||||
.ToList()
|
||||
};
|
||||
|
||||
Definition.FloatControls.AddRange(Port1.Definition.FloatControls);
|
||||
|
||||
Definition.FloatRanges.AddRange(Port1.Definition.FloatRanges);
|
||||
}
|
||||
|
||||
public byte ReadPort1(IController c)
|
||||
{
|
||||
return Port1.Read(c);
|
||||
}
|
||||
|
||||
public ushort ReadAccX1(IController c)
|
||||
{
|
||||
return Port1.ReadAccX(c);
|
||||
}
|
||||
|
||||
public ushort ReadAccY1(IController c)
|
||||
{
|
||||
return Port1.ReadAccY(c);
|
||||
}
|
||||
|
||||
public ControllerDefinition Definition { get; }
|
||||
|
||||
public void SyncState(Serializer ser)
|
||||
{
|
||||
ser.BeginSection(nameof(Port1));
|
||||
Port1.SyncState(ser);
|
||||
ser.EndSection();
|
||||
}
|
||||
|
||||
private readonly IPort Port1;
|
||||
|
||||
private static Dictionary<string, Type> _controllerTypes;
|
||||
|
||||
public static Dictionary<string, Type> ValidControllerTypes
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_controllerTypes == null)
|
||||
{
|
||||
_controllerTypes = typeof(O2HawkControllerDeck).Assembly
|
||||
.GetTypes()
|
||||
.Where(t => typeof(IPort).IsAssignableFrom(t))
|
||||
.Where(t => !t.IsAbstract && !t.IsInterface)
|
||||
.ToDictionary(tkey => tkey.DisplayName());
|
||||
}
|
||||
|
||||
return _controllerTypes;
|
||||
}
|
||||
}
|
||||
|
||||
public static string DefaultControllerName => typeof(StandardControls).DisplayName();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,217 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
|
||||
using BizHawk.Common;
|
||||
using BizHawk.Emulation.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Nintendo.O2Hawk
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a O2 add on
|
||||
/// </summary>
|
||||
public interface IPort
|
||||
{
|
||||
byte Read(IController c);
|
||||
|
||||
ushort ReadAccX(IController c);
|
||||
|
||||
ushort ReadAccY(IController c);
|
||||
|
||||
ControllerDefinition Definition { get; }
|
||||
|
||||
void SyncState(Serializer ser);
|
||||
|
||||
int PortNum { get; }
|
||||
}
|
||||
|
||||
[DisplayName("Gameboy Controller")]
|
||||
public class StandardControls : IPort
|
||||
{
|
||||
public StandardControls(int portNum)
|
||||
{
|
||||
PortNum = portNum;
|
||||
Definition = new ControllerDefinition
|
||||
{
|
||||
Name = "Gameboy Controller H",
|
||||
BoolButtons = BaseDefinition
|
||||
.Select(b => "P" + PortNum + " " + b)
|
||||
.ToList()
|
||||
};
|
||||
}
|
||||
|
||||
public int PortNum { get; }
|
||||
|
||||
public ControllerDefinition Definition { get; }
|
||||
|
||||
public byte Read(IController c)
|
||||
{
|
||||
byte result = 0xFF;
|
||||
|
||||
if (c.IsPressed(Definition.BoolButtons[0]))
|
||||
{
|
||||
result -= 4;
|
||||
}
|
||||
if (c.IsPressed(Definition.BoolButtons[1]))
|
||||
{
|
||||
result -= 8;
|
||||
}
|
||||
if (c.IsPressed(Definition.BoolButtons[2]))
|
||||
{
|
||||
result -= 2;
|
||||
}
|
||||
if (c.IsPressed(Definition.BoolButtons[3]))
|
||||
{
|
||||
result -= 1;
|
||||
}
|
||||
if (c.IsPressed(Definition.BoolButtons[4]))
|
||||
{
|
||||
result -= 128;
|
||||
}
|
||||
if (c.IsPressed(Definition.BoolButtons[5]))
|
||||
{
|
||||
result -= 64;
|
||||
}
|
||||
if (c.IsPressed(Definition.BoolButtons[6]))
|
||||
{
|
||||
result -= 32;
|
||||
}
|
||||
if (c.IsPressed(Definition.BoolButtons[7]))
|
||||
{
|
||||
result -= 16;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public ushort ReadAccX(IController c)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
public ushort ReadAccY(IController c)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static readonly string[] BaseDefinition =
|
||||
{
|
||||
"Up", "Down", "Left", "Right", "Start", "Select", "B", "A", "Power"
|
||||
};
|
||||
|
||||
public void SyncState(Serializer ser)
|
||||
{
|
||||
//nothing
|
||||
}
|
||||
}
|
||||
|
||||
[DisplayName("Gameboy Controller + Tilt")]
|
||||
public class StandardTilt : IPort
|
||||
{
|
||||
public StandardTilt(int portNum)
|
||||
{
|
||||
PortNum = portNum;
|
||||
Definition = new ControllerDefinition
|
||||
{
|
||||
Name = "Gameboy Controller + Tilt",
|
||||
BoolButtons = BaseDefinition
|
||||
.Select(b => "P" + PortNum + " " + b)
|
||||
.ToList(),
|
||||
FloatControls = { "P" + PortNum + " Tilt X", "P" + PortNum + " Tilt Y" },
|
||||
FloatRanges = { new[] { -45.0f, 0, 45.0f }, new[] { -45.0f, 0, 45.0f } }
|
||||
};
|
||||
}
|
||||
|
||||
public int PortNum { get; }
|
||||
|
||||
public float theta, phi, theta_prev, phi_prev;
|
||||
|
||||
public ControllerDefinition Definition { get; }
|
||||
|
||||
public byte Read(IController c)
|
||||
{
|
||||
byte result = 0xFF;
|
||||
|
||||
if (c.IsPressed(Definition.BoolButtons[0]))
|
||||
{
|
||||
result -= 4;
|
||||
}
|
||||
if (c.IsPressed(Definition.BoolButtons[1]))
|
||||
{
|
||||
result -= 8;
|
||||
}
|
||||
if (c.IsPressed(Definition.BoolButtons[2]))
|
||||
{
|
||||
result -= 2;
|
||||
}
|
||||
if (c.IsPressed(Definition.BoolButtons[3]))
|
||||
{
|
||||
result -= 1;
|
||||
}
|
||||
if (c.IsPressed(Definition.BoolButtons[4]))
|
||||
{
|
||||
result -= 128;
|
||||
}
|
||||
if (c.IsPressed(Definition.BoolButtons[5]))
|
||||
{
|
||||
result -= 64;
|
||||
}
|
||||
if (c.IsPressed(Definition.BoolButtons[6]))
|
||||
{
|
||||
result -= 32;
|
||||
}
|
||||
if (c.IsPressed(Definition.BoolButtons[7]))
|
||||
{
|
||||
result -= 16;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// acc x is the result of rotating around body y AFTER rotating around body x
|
||||
// therefore this control scheme gives decreasing sensitivity in X as Y rotation inscreases
|
||||
public ushort ReadAccX(IController c)
|
||||
{
|
||||
theta_prev = theta;
|
||||
phi_prev = phi;
|
||||
|
||||
theta = (float)(c.GetFloat(Definition.FloatControls[1]) * Math.PI / 180.0);
|
||||
phi = (float)(c.GetFloat(Definition.FloatControls[0]) * Math.PI / 180.0);
|
||||
|
||||
float temp = (float)(Math.Cos(theta) * Math.Sin(phi));
|
||||
|
||||
// here we add in rates of change parameters.
|
||||
// a typical rate of change for a fast rotation is guessed at 0.5 rad / frame
|
||||
// since rotations about X have less of a moment arm compared to by, we take 1/5 of the effect as a baseline
|
||||
float temp2 = (float)((phi - phi_prev) / 0.5 * 25);
|
||||
|
||||
return (ushort)(0x81D0 - Math.Floor(temp * 125) - temp2);
|
||||
}
|
||||
|
||||
// acc y is just the sine of the angle
|
||||
// we assume that ReadAccX is called first, which updates the the states
|
||||
public ushort ReadAccY(IController c)
|
||||
{
|
||||
float temp = (float)Math.Sin(theta);
|
||||
|
||||
// here we add in rates of change parameters.
|
||||
// a typical rate of change for a fast rotation is guessed at 0.5 rad / frame
|
||||
// further it will be assumed that the resulting acceleration is roughly eqvuivalent to gravity
|
||||
float temp2 = (float)((theta - theta_prev)/0.5 * 125);
|
||||
|
||||
return (ushort)(0x81D0 - Math.Floor(temp * 125) + temp2);
|
||||
}
|
||||
|
||||
private static readonly string[] BaseDefinition =
|
||||
{
|
||||
"Up", "Down", "Left", "Right", "Start", "Select", "B", "A", "Power"
|
||||
};
|
||||
|
||||
public void SyncState(Serializer ser)
|
||||
{
|
||||
// since we need rate of change of angle, need to savestate them
|
||||
ser.Sync(nameof(theta), ref theta);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,272 @@
|
|||
using System;
|
||||
using BizHawk.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Nintendo.O2Hawk
|
||||
{
|
||||
public class PPU
|
||||
{
|
||||
public O2Hawk Core { get; set; }
|
||||
|
||||
public uint[] BG_palette = new uint[32];
|
||||
public uint[] OBJ_palette = new uint[32];
|
||||
|
||||
public bool HDMA_active;
|
||||
public bool clear_screen;
|
||||
|
||||
// register variables
|
||||
public byte LCDC;
|
||||
public byte STAT;
|
||||
public byte scroll_y;
|
||||
public byte scroll_x;
|
||||
public byte LY;
|
||||
public byte LY_actual;
|
||||
public byte LY_inc;
|
||||
public byte LYC;
|
||||
public byte DMA_addr;
|
||||
public byte BGP;
|
||||
public byte obj_pal_0;
|
||||
public byte obj_pal_1;
|
||||
public byte window_y;
|
||||
public byte window_x;
|
||||
public bool DMA_start;
|
||||
public int DMA_clock;
|
||||
public int DMA_inc;
|
||||
public byte DMA_byte;
|
||||
|
||||
// state variables
|
||||
public int cycle;
|
||||
public bool LYC_INT;
|
||||
public bool HBL_INT;
|
||||
public bool VBL_INT;
|
||||
public bool OAM_INT;
|
||||
public bool LCD_was_off;
|
||||
public bool stat_line;
|
||||
public bool stat_line_old;
|
||||
// OAM scan
|
||||
public bool DMA_OAM_access;
|
||||
public bool OAM_access_read;
|
||||
public bool OAM_access_write;
|
||||
public int OAM_scan_index;
|
||||
public int SL_sprites_index;
|
||||
public int[] SL_sprites = new int[40];
|
||||
public int write_sprite;
|
||||
public bool no_scan;
|
||||
// render
|
||||
public bool VRAM_access_read;
|
||||
public bool VRAM_access_write;
|
||||
public int read_case;
|
||||
public int internal_cycle;
|
||||
public int y_tile;
|
||||
public int y_scroll_offset;
|
||||
public int x_tile;
|
||||
public int x_scroll_offset;
|
||||
public int tile_byte;
|
||||
public int sprite_fetch_cycles;
|
||||
public bool fetch_sprite;
|
||||
public bool going_to_fetch;
|
||||
public bool first_fetch;
|
||||
public int sprite_fetch_counter;
|
||||
public byte[] sprite_attr_list = new byte[160];
|
||||
public byte[] sprite_pixel_list = new byte[160];
|
||||
public byte[] sprite_present_list = new byte[160];
|
||||
public int temp_fetch;
|
||||
public int tile_inc;
|
||||
public bool pre_render;
|
||||
public bool pre_render_2;
|
||||
public byte[] tile_data = new byte[3];
|
||||
public byte[] tile_data_latch = new byte[3];
|
||||
public int latch_counter;
|
||||
public bool latch_new_data;
|
||||
public int render_counter;
|
||||
public int render_offset;
|
||||
public int pixel_counter;
|
||||
public int pixel;
|
||||
public byte[] sprite_data = new byte[2];
|
||||
public byte[] sprite_sel = new byte[2];
|
||||
public int sl_use_index;
|
||||
public bool no_sprites;
|
||||
public int[] SL_sprites_ordered = new int[40]; // (x_end, data_low, data_high, attr)
|
||||
public int evaled_sprites;
|
||||
public int sprite_ordered_index;
|
||||
public bool blank_frame;
|
||||
public bool window_latch;
|
||||
public int consecutive_sprite;
|
||||
public int last_eval;
|
||||
|
||||
public int total_counter;
|
||||
// windowing state
|
||||
public int window_counter;
|
||||
public bool window_pre_render;
|
||||
public bool window_started;
|
||||
public bool window_is_reset;
|
||||
public int window_tile_inc;
|
||||
public int window_y_tile;
|
||||
public int window_x_tile;
|
||||
public int window_y_tile_inc;
|
||||
public int window_x_latch;
|
||||
public int window_y_latch;
|
||||
|
||||
public int hbl_countdown;
|
||||
|
||||
public byte ReadReg(int addr)
|
||||
{
|
||||
byte ret = 0;
|
||||
|
||||
switch (addr)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
public void WriteReg(int addr, byte value)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void tick()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
// might be needed, not sure yet
|
||||
public void latch_delay()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void render(int render_cycle)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void process_sprite()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
// normal DMA moves twice as fast in double speed mode on GBC
|
||||
// So give it it's own function so we can seperate it from PPU tick
|
||||
public void DMA_tick()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void OAM_scan(int OAM_cycle)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
// order sprites according to x coordinate
|
||||
// note that for sprites of equal x coordinate, priority goes to first on the list
|
||||
public void reorder_and_assemble_sprites()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void SyncState(Serializer ser)
|
||||
{
|
||||
ser.Sync(nameof(BG_palette), ref BG_palette, false);
|
||||
ser.Sync(nameof(OBJ_palette), ref OBJ_palette, false);
|
||||
ser.Sync(nameof(HDMA_active), ref HDMA_active);
|
||||
ser.Sync(nameof(clear_screen), ref clear_screen);
|
||||
|
||||
ser.Sync(nameof(LCDC), ref LCDC);
|
||||
ser.Sync(nameof(STAT), ref STAT);
|
||||
ser.Sync(nameof(scroll_y), ref scroll_y);
|
||||
ser.Sync(nameof(scroll_x), ref scroll_x);
|
||||
ser.Sync(nameof(LY), ref LY);
|
||||
ser.Sync(nameof(LY_actual), ref LY_actual);
|
||||
ser.Sync(nameof(LY_inc), ref LY_inc);
|
||||
ser.Sync(nameof(LYC), ref LYC);
|
||||
ser.Sync(nameof(DMA_addr), ref DMA_addr);
|
||||
ser.Sync(nameof(BGP), ref BGP);
|
||||
ser.Sync(nameof(obj_pal_0), ref obj_pal_0);
|
||||
ser.Sync(nameof(obj_pal_1), ref obj_pal_1);
|
||||
ser.Sync(nameof(window_y), ref window_y);
|
||||
ser.Sync(nameof(window_x), ref window_x);
|
||||
ser.Sync(nameof(DMA_start), ref DMA_start);
|
||||
ser.Sync(nameof(DMA_clock), ref DMA_clock);
|
||||
ser.Sync(nameof(DMA_inc), ref DMA_inc);
|
||||
ser.Sync(nameof(DMA_byte), ref DMA_byte);
|
||||
|
||||
ser.Sync(nameof(cycle), ref cycle);
|
||||
ser.Sync(nameof(LYC_INT), ref LYC_INT);
|
||||
ser.Sync(nameof(HBL_INT), ref HBL_INT);
|
||||
ser.Sync(nameof(VBL_INT), ref VBL_INT);
|
||||
ser.Sync(nameof(OAM_INT), ref OAM_INT);
|
||||
ser.Sync(nameof(stat_line), ref stat_line);
|
||||
ser.Sync(nameof(stat_line_old), ref stat_line_old);
|
||||
ser.Sync(nameof(LCD_was_off), ref LCD_was_off);
|
||||
ser.Sync(nameof(OAM_scan_index), ref OAM_scan_index);
|
||||
ser.Sync(nameof(SL_sprites_index), ref SL_sprites_index);
|
||||
ser.Sync(nameof(SL_sprites), ref SL_sprites, false);
|
||||
ser.Sync(nameof(write_sprite), ref write_sprite);
|
||||
ser.Sync(nameof(no_scan), ref no_scan);
|
||||
|
||||
ser.Sync(nameof(DMA_OAM_access), ref DMA_OAM_access);
|
||||
ser.Sync(nameof(OAM_access_read), ref OAM_access_read);
|
||||
ser.Sync(nameof(OAM_access_write), ref OAM_access_write);
|
||||
ser.Sync(nameof(VRAM_access_read), ref VRAM_access_read);
|
||||
ser.Sync(nameof(VRAM_access_write), ref VRAM_access_write);
|
||||
|
||||
ser.Sync(nameof(read_case), ref read_case);
|
||||
ser.Sync(nameof(internal_cycle), ref internal_cycle);
|
||||
ser.Sync(nameof(y_tile), ref y_tile);
|
||||
ser.Sync(nameof(y_scroll_offset), ref y_scroll_offset);
|
||||
ser.Sync(nameof(x_tile), ref x_tile);
|
||||
ser.Sync(nameof(x_scroll_offset), ref x_scroll_offset);
|
||||
ser.Sync(nameof(tile_byte), ref tile_byte);
|
||||
ser.Sync(nameof(sprite_fetch_cycles), ref sprite_fetch_cycles);
|
||||
ser.Sync(nameof(fetch_sprite), ref fetch_sprite);
|
||||
ser.Sync(nameof(going_to_fetch), ref going_to_fetch);
|
||||
ser.Sync(nameof(first_fetch), ref first_fetch);
|
||||
ser.Sync(nameof(sprite_fetch_counter), ref sprite_fetch_counter);
|
||||
ser.Sync(nameof(sprite_attr_list), ref sprite_attr_list, false);
|
||||
ser.Sync(nameof(sprite_pixel_list), ref sprite_pixel_list, false);
|
||||
ser.Sync(nameof(sprite_present_list), ref sprite_present_list, false);
|
||||
ser.Sync(nameof(temp_fetch), ref temp_fetch);
|
||||
ser.Sync(nameof(tile_inc), ref tile_inc);
|
||||
ser.Sync(nameof(pre_render), ref pre_render);
|
||||
ser.Sync(nameof(pre_render_2), ref pre_render_2);
|
||||
ser.Sync(nameof(tile_data), ref tile_data, false);
|
||||
ser.Sync(nameof(tile_data_latch), ref tile_data_latch, false);
|
||||
ser.Sync(nameof(latch_counter), ref latch_counter);
|
||||
ser.Sync(nameof(latch_new_data), ref latch_new_data);
|
||||
ser.Sync(nameof(render_counter), ref render_counter);
|
||||
ser.Sync(nameof(render_offset), ref render_offset);
|
||||
ser.Sync(nameof(pixel_counter), ref pixel_counter);
|
||||
ser.Sync(nameof(pixel), ref pixel);
|
||||
ser.Sync(nameof(sprite_data), ref sprite_data, false);
|
||||
ser.Sync(nameof(sl_use_index), ref sl_use_index);
|
||||
ser.Sync(nameof(sprite_sel), ref sprite_sel, false);
|
||||
ser.Sync(nameof(no_sprites), ref no_sprites);
|
||||
ser.Sync(nameof(evaled_sprites), ref evaled_sprites);
|
||||
ser.Sync(nameof(SL_sprites_ordered), ref SL_sprites_ordered, false);
|
||||
ser.Sync(nameof(sprite_ordered_index), ref sprite_ordered_index);
|
||||
ser.Sync(nameof(blank_frame), ref blank_frame);
|
||||
ser.Sync(nameof(window_latch), ref window_latch);
|
||||
ser.Sync(nameof(consecutive_sprite), ref consecutive_sprite);
|
||||
ser.Sync(nameof(last_eval), ref last_eval);
|
||||
|
||||
ser.Sync(nameof(window_counter), ref window_counter);
|
||||
ser.Sync(nameof(window_pre_render), ref window_pre_render);
|
||||
ser.Sync(nameof(window_started), ref window_started);
|
||||
ser.Sync(nameof(window_is_reset), ref window_is_reset);
|
||||
ser.Sync(nameof(window_tile_inc), ref window_tile_inc);
|
||||
ser.Sync(nameof(window_y_tile), ref window_y_tile);
|
||||
ser.Sync(nameof(window_x_tile), ref window_x_tile);
|
||||
ser.Sync(nameof(window_y_tile_inc), ref window_y_tile_inc);
|
||||
ser.Sync(nameof(window_x_latch), ref window_x_latch);
|
||||
ser.Sync(nameof(window_y_latch), ref window_y_latch);
|
||||
|
||||
ser.Sync(nameof(hbl_countdown), ref hbl_countdown);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
TODO:
|
|
@ -0,0 +1,150 @@
|
|||
using System;
|
||||
using BizHawk.Emulation.Common;
|
||||
using BizHawk.Common.NumberExtensions;
|
||||
using BizHawk.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Nintendo.O2Hawk
|
||||
{
|
||||
public class SerialPort
|
||||
{
|
||||
public O2Hawk Core { get; set; }
|
||||
|
||||
public byte serial_control;
|
||||
public byte serial_data;
|
||||
public bool serial_start;
|
||||
public bool can_pulse;
|
||||
public int serial_clock;
|
||||
public int serial_bits;
|
||||
public int clk_rate;
|
||||
public byte going_out;
|
||||
public byte coming_in;
|
||||
|
||||
public byte ReadReg(int addr)
|
||||
{
|
||||
switch (addr)
|
||||
{
|
||||
case 0xFF01:
|
||||
return serial_data;
|
||||
case 0xFF02:
|
||||
return serial_control;
|
||||
}
|
||||
|
||||
return 0xFF;
|
||||
}
|
||||
|
||||
public void WriteReg(int addr, byte value)
|
||||
{
|
||||
switch (addr)
|
||||
{
|
||||
case 0xFF01:
|
||||
serial_data = value;
|
||||
break;
|
||||
|
||||
case 0xFF02:
|
||||
if (((value & 0x80) > 0) && !serial_start)
|
||||
{
|
||||
serial_start = true;
|
||||
serial_bits = 8;
|
||||
if ((value & 1) > 0)
|
||||
{
|
||||
if (((value & 2) > 0))
|
||||
{
|
||||
clk_rate = 16;
|
||||
}
|
||||
else
|
||||
{
|
||||
clk_rate = 512;
|
||||
}
|
||||
serial_clock = clk_rate;
|
||||
can_pulse = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
clk_rate = -1;
|
||||
serial_clock = clk_rate;
|
||||
can_pulse = false;
|
||||
}
|
||||
}
|
||||
else if (serial_start)
|
||||
{
|
||||
if ((value & 1) > 0)
|
||||
{
|
||||
if (((value & 2) > 0))
|
||||
{
|
||||
clk_rate = 16;
|
||||
}
|
||||
else
|
||||
{
|
||||
clk_rate = 512;
|
||||
}
|
||||
serial_clock = clk_rate;
|
||||
can_pulse = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
clk_rate = -1;
|
||||
serial_clock = clk_rate;
|
||||
can_pulse = false;
|
||||
}
|
||||
}
|
||||
|
||||
serial_control = (byte)(0x7E | (value & 0x81)); // middle six bits always 1
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void serial_transfer_tick()
|
||||
{
|
||||
if (serial_start)
|
||||
{
|
||||
if (serial_clock > 0) { serial_clock--; }
|
||||
|
||||
if (serial_clock == 0)
|
||||
{
|
||||
if (serial_bits > 0)
|
||||
{
|
||||
byte temp = coming_in;
|
||||
serial_data = (byte)((serial_data << 1) | temp);
|
||||
|
||||
serial_bits--;
|
||||
|
||||
if (serial_bits == 0)
|
||||
{
|
||||
serial_control &= 0x7F;
|
||||
serial_start = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
serial_clock = clk_rate;
|
||||
if (clk_rate > 0) { can_pulse = true; }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
serial_control = 0x7E;
|
||||
serial_start = false;
|
||||
serial_data = 0x00;
|
||||
going_out = 0;
|
||||
coming_in = 1;
|
||||
}
|
||||
|
||||
public void SyncState(Serializer ser)
|
||||
{
|
||||
ser.Sync(nameof(serial_control), ref serial_control);
|
||||
ser.Sync(nameof(serial_data), ref serial_data);
|
||||
ser.Sync(nameof(serial_start), ref serial_start);
|
||||
ser.Sync(nameof(serial_clock), ref serial_clock);
|
||||
ser.Sync(nameof(serial_bits), ref serial_bits);
|
||||
ser.Sync(nameof(clk_rate), ref clk_rate);
|
||||
ser.Sync(nameof(going_out), ref going_out);
|
||||
ser.Sync(nameof(coming_in), ref coming_in);
|
||||
ser.Sync(nameof(can_pulse), ref can_pulse);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue