This commit is contained in:
Blue 2019-02-03 03:05:13 +01:00
parent c11d21c7f2
commit da19b7ee91
8 changed files with 206 additions and 110 deletions

View file

@ -1,9 +1,11 @@
using System;
using ProjectPSX.Devices;
using System;
using System.IO;
namespace ProjectPSX {
internal class MMU {
internal class BUS {
//Memory
private byte[] RAM = new byte[2048 * 1024];
private byte[] EX1 = new byte[512 * 1024];
private byte[] SCRATHPAD = new byte[1024];
@ -11,11 +13,17 @@ namespace ProjectPSX {
private byte[] BIOS = new byte[512 * 1024];
private byte[] IO = new byte[512];
//Other Subsystems
private DMA dma;
public BUS() {
dma = new DMA();
}
private const uint GPUSTAT = 0x1f801814;
private const uint GP0 = 0x1f801810;
internal uint read32(uint addr) {
//Console.WriteLine("READ ADDR: " + addr.ToString("x4"));
internal uint load32(uint addr) {
switch (addr) {
case uint KUSEG when addr >= 0x0000_0000 && addr < 0x1F00_0000:
case uint KSEG0 when addr >= 0x8000_0000 && addr < 0x9F00_0000:
@ -39,29 +47,22 @@ namespace ProjectPSX {
case uint KUSEG when addr >= 0x1F80_1000 && addr < 0x1F80_2000:
case uint KSEG0 when addr >= 0x9F80_1000 && addr < 0x9F80_2000:
case uint KSEG1 when addr >= 0xBF80_1000 && addr < 0xBF80_2000:
if (addr >= 0x1f801080 && addr <= 0x1f8010FF) {
Console.WriteLine("DMA ACCESS");
return 0;
} else if (addr == GPUSTAT) { Console.WriteLine("GPUSTAT ACCESS"); return 0x1000_0000; }
else if (addr == GP0) { Console.WriteLine("GP0 ACCESS"); return 0; }
else if (addr == 0x1f801104) { Console.WriteLine("Timer 1104 ACCESS"); return 0; }
else if (addr == 0x1f801114) { Console.WriteLine("Timer 1114 ACCESS"); return 0; }
else if (addr == 0x1f801118) { Console.WriteLine("Timer 1118 ACCESS"); return 0; }
else if (addr == 0x1f801070) { Console.WriteLine("Interrupt Mask ACCESS"); return 0; }
else if (addr == 0x1f801074) { Console.WriteLine("Interrupt Status ACCESS"); return 0; }
else if (addr == 0x1f801dae) { Console.WriteLine("SPU ACCESS"); return 0; }
if (addr == GPUSTAT) { Console.WriteLine("GPUSTAT ACCESS"); return 0x1000_0000; } else if (addr == GP0) { Console.WriteLine("GP0 ACCESS"); return 0; } else if (addr == 0x1f801104) { Console.WriteLine("Timer 1104 ACCESS"); return 0; } else if (addr == 0x1f801114) { Console.WriteLine("Timer 1114 ACCESS"); return 0; } else if (addr == 0x1f801118) { Console.WriteLine("Timer 1118 ACCESS"); return 0; } else if (addr == 0x1f801070) { Console.WriteLine("Interrupt Mask ACCESS"); return 0; } else if (addr == 0x1f801074) { Console.WriteLine("Interrupt Status ACCESS"); return 0; } else if (addr == 0x1f801dae) { Console.WriteLine("SPU ACCESS"); return 0; }
switch (addr) {
case uint DMA when addr >= 0x1F80_1080 && addr < 0x1F80_10FF:
Console.WriteLine("load at addr {0} = {1}", addr.ToString("x8"), dma.load32(addr).ToString("x8"));
return dma.load32(addr);
default:
addr &= 0xFFF;
return (uint)((REGISTERS[addr + 3] << 24) | (REGISTERS[addr + 2] << 16) | (REGISTERS[addr + 1] << 8) | REGISTERS[addr]);
}
addr &= 0xFFF;
return (uint)((REGISTERS[addr + 3] << 24) | (REGISTERS[addr + 2] << 16) | (REGISTERS[addr + 1] << 8) | REGISTERS[addr]);
case uint KUSEG when addr >= 0x1FC0_0000 && addr < 0x1FC8_0000:
case uint KSEG0 when addr >= 0x9FC0_0000 && addr < 0x9FC8_0000:
case uint KSEG1 when addr >= 0xBFC0_0000 && addr < 0xBFC8_0000: //BIOS mem map
if (0xbfc04190 == addr) {
Console.WriteLine("DMA LOOP");
return 0;
}
addr &= 0x7_FFFF;
return (uint)((BIOS[addr + 3] << 24) | (BIOS[addr + 2] << 16) | (BIOS[addr + 1] << 8) | BIOS[addr]);
@ -86,6 +87,7 @@ namespace ProjectPSX {
RAM[addr + 2] = (byte)(value >> 16);
RAM[addr + 3] = (byte)(value >> 24);
break;
case uint KUSEG when addr >= 0x1F00_0000 && addr < 0x1F08_0000:
case uint KSEG0 when addr >= 0x9F00_0000 && addr < 0x9F08_0000:
case uint KSEG1 when addr >= 0xBF00_0000 && addr < 0xBF08_0000:
@ -95,6 +97,7 @@ namespace ProjectPSX {
EX1[addr + 2] = (byte)(value >> 16);
EX1[addr + 3] = (byte)(value >> 24);
break;
case uint KUSEG when addr >= 0x1F80_0000 && addr < 0x1F80_0400:
case uint KSEG0 when addr >= 0x9F80_0000 && addr < 0x9F80_0400:
case uint KSEG1 when addr >= 0xBF80_0000 && addr < 0xBF80_0400:
@ -104,21 +107,33 @@ namespace ProjectPSX {
SCRATHPAD[addr + 2] = (byte)(value >> 16);
SCRATHPAD[addr + 3] = (byte)(value >> 24);
break;
case uint KUSEG when addr >= 0x1F80_1000 && addr < 0x1F80_2000:
case uint KSEG0 when addr >= 0x9F80_1000 && addr < 0x9F80_2000:
case uint KSEG1 when addr >= 0xBF80_1000 && addr < 0xBF80_2000:
addr &= 0xFFF;
REGISTERS[addr] = (byte)(value);
REGISTERS[addr + 1] = (byte)(value >> 8);
REGISTERS[addr + 2] = (byte)(value >> 16);
REGISTERS[addr + 3] = (byte)(value >> 24);
switch (addr) {
case uint DMA when addr >= 0x1F80_1080 && addr < 0x1F80_10FF:
dma.write32(addr, value);
break;
default:
addr &= 0xFFF;
REGISTERS[addr] = (byte)(value);
REGISTERS[addr + 1] = (byte)(value >> 8);
REGISTERS[addr + 2] = (byte)(value >> 16);
REGISTERS[addr + 3] = (byte)(value >> 24);
break;
}
break;
case uint KUSEG when addr >= 0x1FC0_0000 && addr < 0x1FC8_0000:
case uint KSEG0 when addr >= 0x9FC0_0000 && addr < 0x9FC8_0000:
case uint KSEG1 when addr >= 0xBFC0_0000 && addr < 0xBFC8_0000: //BIOS mem map
Console.WriteLine("WARNING WRITE 32 on BIOS RANGE" + addr.ToString("x8"));
Console.ReadLine();
break;
case uint KSEG2 when addr >= 0xFFFE_0000 && addr < 0xFFFE_0200:
addr &= 0x1FF;
IO[addr] = (byte)(value);
@ -126,6 +141,7 @@ namespace ProjectPSX {
IO[addr + 2] = (byte)(value >> 16);
IO[addr + 3] = (byte)(value >> 24);
break;
default:
Console.WriteLine("Unsupported WRITE AREA: " + addr.ToString("x4") + ": " + value.ToString("x4"));
break;

View file

@ -80,19 +80,20 @@ namespace ProjectPSX {
private WB wb;
private MEM mem;
internal void Run(MMU mmu) {
fetchDecode(mmu);
Execute(mmu);
internal void Run(BUS bus) {
fetchDecode(bus);
Execute(bus);
MemAccess();
WriteBack();
TTY();
//debug
TTY();
//disassemble();
//PrintRegs();
}
private void fetchDecode(MMU mmu) {
uint load = mmu.read32(PC);
private void fetchDecode(BUS bus) {
uint load = bus.load32(PC);
PC_Now = PC;
PC = PC_Predictor;
PC_Predictor += 4;
@ -122,7 +123,7 @@ namespace ProjectPSX {
REG[0] = 0;
}
private void Execute(MMU mmu) {
private void Execute(BUS bus) {
switch (instr.opcode) {
case 0b00_0000: //R-Type opcodes
switch (instr.function) {
@ -196,26 +197,26 @@ namespace ProjectPSX {
case 0b01_0010: COP2(); break;
case 0b01_0011: COP3(); break;
case 0b10_0000: LB(mmu); break;
case 0b10_0001: LH(mmu); break;
case 0b10_0010: LWL(mmu); break;
case 0b10_0011: LW(mmu); break;
case 0b10_0100: LBU(mmu); break;
case 0b10_0101: LHU(mmu); break;
case 0b10_0110: LWR(mmu); break;
case 0b10_1000: SB(mmu); break;
case 0b10_1001: SH(mmu); break;
case 0b10_1010: SWL(mmu); break;
case 0b10_1011: SW(mmu); break;
case 0b10_1110: SWR(mmu); break;
case 0b10_0000: LB(bus); break;
case 0b10_0001: LH(bus); break;
case 0b10_0010: LWL(bus); break;
case 0b10_0011: LW(bus); break;
case 0b10_0100: LBU(bus); break;
case 0b10_0101: LHU(bus); break;
case 0b10_0110: LWR(bus); break;
case 0b10_1000: SB(bus); break;
case 0b10_1001: SH(bus); break;
case 0b10_1010: SWL(bus); break;
case 0b10_1011: SW(bus); break;
case 0b10_1110: SWR(bus); break;
case 0b11_0000: //LWC0
case 0b11_0001: //LWC1
case 0b11_0011: //LWC3
case 0b11_1000: //SWC0
case 0b11_1001: //SWC1
case 0b11_1011: UNIMPL_LW_SW_COP0_1_3(); break;
case 0b11_0010: LWC2(mmu); break;
case 0b11_1010: SWC2(mmu); break;
case 0b11_0010: LWC2(bus); break;
case 0b11_1010: SWC2(bus); break;
//pending lwc0-3 and swc0-3 and illegal opc
default:
EXCEPTION(EX.ILLEGAL_INSTR);
@ -224,12 +225,12 @@ namespace ProjectPSX {
}
}
private void SWC2(MMU mmu) {
private void SWC2(BUS bus) {
Console.WriteLine("Store at GTE");
throw new NotImplementedException();
}
private void LWC2(MMU mmu) {
private void LWC2(BUS bus) {
Console.WriteLine("Load from GTE");
throw new NotImplementedException();
}
@ -238,11 +239,11 @@ namespace ProjectPSX {
EXCEPTION(EX.COPROCESSOR_ERROR);
}
private void SWR(MMU mmu) {
private void SWR(BUS bus) {
uint addr = REG[instr.rs] + instr.imm_s;
uint aligned_addr = (uint)(addr & ~0b11);
uint aligned_load = mmu.read32(aligned_addr);
uint aligned_load = bus.load32(aligned_addr);
uint value = 0;
switch (addr & 0b11) {
@ -252,14 +253,14 @@ namespace ProjectPSX {
case 3: value = aligned_load & 0xFF_FFFF | REG[instr.rt] << 24; break;
}
mmu.write32(addr, value);
bus.write32(addr, value);
}
private void SWL(MMU mmu) {
private void SWL(BUS bus) {
uint addr = REG[instr.rs] + instr.imm_s;
uint aligned_addr = (uint)(addr & ~0b11);
uint aligned_load = mmu.read32(aligned_addr);
uint aligned_load = bus.load32(aligned_addr);
uint value = 0;
switch (addr & 0b11) {
@ -269,14 +270,14 @@ namespace ProjectPSX {
case 0: value = aligned_load & 0xFF_FFFF | REG[instr.rt] >> 24; break;
}
mmu.write32(addr, value);
bus.write32(addr, value);
}
private void LWR(MMU mmu) {
private void LWR(BUS bus) {
uint addr = REG[instr.rs] + instr.imm_s;
uint aligned_addr = (uint)(addr & ~0b11);
uint aligned_load = mmu.read32(aligned_addr);
uint aligned_load = bus.load32(aligned_addr);
uint value = 0;
switch (addr & 0b11) {
@ -291,11 +292,11 @@ namespace ProjectPSX {
delayedLoad(instr.rt, prev_value | value);
}
private void LWL(MMU mmu) {
private void LWL(BUS bus) {
uint addr = REG[instr.rs] + instr.imm_s;
uint aligned_addr = (uint)(addr & ~0b11);
uint aligned_load = mmu.read32(aligned_addr);
uint aligned_load = bus.load32(aligned_addr);
uint value = 0;
switch(addr & 0b11) {
@ -372,14 +373,14 @@ namespace ProjectPSX {
setReg(instr.rd, ~(REG[instr.rs] | REG[instr.rt]));
}
private void LH(MMU mmu) {
private void LH(BUS bus) {
if ((SR & 0x10000) == 0) {
uint addr = REG[instr.rs] + instr.imm_s;
if ((addr % 2) != 0) {
EXCEPTION(EX.LOAD_ADRESS_ERROR);
} else {
uint value = (uint)(short)mmu.read32(addr);
uint value = (uint)(short)bus.load32(addr);
delayedLoad(instr.rt, value);
}
@ -390,14 +391,14 @@ namespace ProjectPSX {
setReg(instr.rd, REG[instr.rt] << (int)(REG[instr.rs] & 0x1F));
}
private void LHU(MMU mmu) {
private void LHU(BUS bus) {
if ((SR & 0x10000) == 0) {
uint addr = REG[instr.rs] + instr.imm_s;
if ((addr % 2) != 0) {
EXCEPTION(EX.LOAD_ADRESS_ERROR);
} else {
uint value = (ushort)mmu.read32(addr);
uint value = (ushort)bus.load32(addr);
delayedLoad(instr.rt, value);
}
@ -418,7 +419,7 @@ namespace ProjectPSX {
LO = REG[instr.rs];
}
private void EXCEPTION(uint cause) {
private void EXCEPTION(EX cause) {
uint ExAdress;
if((SR & (1 << 22)) != 0) {
ExAdress = 0xBFC0_0180;
@ -430,7 +431,7 @@ namespace ProjectPSX {
SR = (uint)(SR & ~0x3F);
SR |= (mode << 2) & 0x3F;
CAUSE = cause << 2;
CAUSE = (uint)cause << 2;
EPC = PC_Now;
if (isDelaySlot) {
@ -538,9 +539,9 @@ namespace ProjectPSX {
JR();
}
private void LBU(MMU mmu) { //todo recheck this
private void LBU(BUS bus) { //todo recheck this
if ((SR & 0x10000) == 0) {
uint value = (byte)mmu.read32(REG[instr.rs] + instr.imm_s);
uint value = (byte)bus.load32(REG[instr.rs] + instr.imm_s);
delayedLoad(instr.rt, value);
} //else Console.WriteLine("Ignoring Load");
}
@ -582,9 +583,9 @@ namespace ProjectPSX {
}
}
private void LB(MMU mmu) { //todo redo this as it unnecesary read32
private void LB(BUS bus) { //todo redo this as it unnecesary load32
if ((SR & 0x10000) == 0) {
uint value = (uint)((sbyte)(mmu.read32(REG[instr.rs] + instr.imm_s)));
uint value = (uint)((sbyte)(bus.load32(REG[instr.rs] + instr.imm_s)));
delayedLoad(instr.rt, value);
} //else Console.WriteLine("Ignoring Write");
}
@ -594,9 +595,9 @@ namespace ProjectPSX {
PC_Predictor = REG[instr.rs];
}
private void SB(MMU mmu) {
private void SB(BUS bus) {
if ((SR & 0x10000) == 0)
mmu.write8(REG[instr.rs] + instr.imm_s, (byte)REG[instr.rt]);
bus.write8(REG[instr.rs] + instr.imm_s, (byte)REG[instr.rt]);
//else Console.WriteLine("Ignoring Write");
}
@ -609,14 +610,14 @@ namespace ProjectPSX {
J();
}
private void SH(MMU mmu) {
private void SH(BUS bus) {
if ((SR & 0x10000) == 0) {
uint addr = REG[instr.rs] + instr.imm_s;
if ((addr % 2) != 0) {
EXCEPTION(EX.STORE_ADRESS_ERROR);
} else {
mmu.write16(addr, (ushort)REG[instr.rt]);
bus.write16(addr, (ushort)REG[instr.rt]);
}
}
//else Console.WriteLine("Ignoring Write");
@ -631,14 +632,14 @@ namespace ProjectPSX {
setReg(instr.rd, condition ? 1u : 0u);
}
private void LW(MMU mmu) {
private void LW(BUS bus) {
if ((SR & 0x10000) == 0) {
uint addr = REG[instr.rs] + instr.imm_s;
if ((addr % 4) != 0) {
EXCEPTION(EX.LOAD_ADRESS_ERROR);
} else {
uint value = mmu.read32(addr);
uint value = bus.load32(addr);
delayedLoad(instr.rt, value);
}
@ -683,14 +684,14 @@ namespace ProjectPSX {
setReg(instr.rd, REG[instr.rt] << (int)instr.sa);
}
private void SW(MMU mmu) {
private void SW(BUS bus) {
if ((SR & 0x10000) == 0) {
uint addr = REG[instr.rs] + instr.imm_s;
if ((addr % 4) != 0) {
EXCEPTION(EX.STORE_ADRESS_ERROR);
} else {
mmu.write32(addr, REG[instr.rt]);
bus.write32(addr, REG[instr.rt]);
}
}
//else Console.WriteLine("Ignoring Write");
@ -857,36 +858,36 @@ namespace ProjectPSX {
}
break;
case 0b10_0000:// LB(mmu);
case 0b10_0000:// LB(bus);
output = "LB";
break;
case 0b10_0001: //LH(mmu); break;
case 0b10_0001: //LH(bus); break;
output = "LH";
break;
case 0b10_0010: output = "LWL"; break;
case 0b10_0100:// LBU(mmu);
case 0b10_0100:// LBU(bus);
output = "LBU";
break;
case 0b10_0101: //LHU(mmu); break;
case 0b10_0101: //LHU(bus); break;
output = "LHU";
break;
case 0b10_0011:// LW(mmu);
case 0b10_0011:// LW(bus);
if ((SR & 0x10000) == 0)
values = "R" + instr.rt + "[" + REG[instr.rt].ToString("x8") + "], " + instr.imm_s.ToString("x8") + "(" + REG[instr.rs].ToString("x8") + ")" + "[" + (instr.imm_s + REG[instr.rs]).ToString("x8") + "]";
else values = "R" + instr.rt + "[" + REG[instr.rt].ToString("x8") + "], " + instr.imm_s.ToString("x8") + "(" + REG[instr.rs].ToString("x8") + ")" + "[" + (instr.imm_s + REG[instr.rs]).ToString("x8") + "]" + " WARNING IGNORED LOAD";
output = "LW";
break;
case 0b10_1001:// SH(mmu);
case 0b10_1001:// SH(bus);
output = "SH";
break;
case 0b10_1010: output = "SWL"; break;
case 0b10_0110: output = "LWR"; break;
case 0b10_1000:// SB(mmu);
case 0b10_1000:// SB(bus);
output = "SB";
break;
case 0b10_1011:// SW(mmu);
case 0b10_1011:// SW(bus);
//if ((SR & 0x10000) == 0)
// mmu.write32(REG[instr.rs] + instr.imm_s, REG[instr.rt]);
// bus.write32(REG[instr.rs] + instr.imm_s, REG[instr.rt]);
output = "SW";
if ((SR & 0x10000) == 0)
values = "R" + instr.rt + "["+REG[instr.rt].ToString("x8") + "], " + instr.imm_s.ToString("x8") + "(" + REG[instr.rs].ToString("x8") +")" + "["+ (instr.imm_s + REG[instr.rs]).ToString("x8") + "]";

17
ProjectPSX/Core/EX.cs Normal file
View file

@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ProjectPSX {
enum EX {
LOAD_ADRESS_ERROR = 0x4,
STORE_ADRESS_ERROR = 0x5,
SYSCALL = 0x8,
BREAK = 0x9,
ILLEGAL_INSTR = 0xA,
COPROCESSOR_ERROR = 0xB,
OVERFLOW = 0xC
}
}

View file

@ -7,7 +7,7 @@ using System.Threading.Tasks;
namespace ProjectPSX {
class ProjectPSX {
private CPU cpu;
private MMU mmu;
private BUS mmu;
public ProjectPSX() {
@ -16,7 +16,7 @@ namespace ProjectPSX {
public void POWER_ON() {
cpu = new CPU();
mmu = new MMU();
mmu = new BUS();
mmu.loadBios();

26
ProjectPSX/Devices/DMA.cs Normal file
View file

@ -0,0 +1,26 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ProjectPSX.Devices {
public class DMA : Device {
private uint CONTROL;
private uint INTERRUPT;
public DMA() {
registers = new byte[0x80];
memOffset = 0x1F801080;
write32(0x1F8010F0, 0x07654321);
}
public new void write32(uint addr, uint value) {
base.write32(addr, value);
Console.WriteLine("Write32 on DMA Address: {0} Value: {1}", addr.ToString("x8"), value.ToString("x8"));
}
}
}

View file

@ -0,0 +1,51 @@

namespace ProjectPSX.Devices {
public class Device {
protected byte[] registers;
protected uint memOffset;
public byte load8(uint addr) {
addr -= memOffset;
return registers[addr];
}
public ushort load16(uint addr) {
addr -= memOffset;
byte b0 = registers[addr + 0];
byte b1 = registers[addr + 1];
return (ushort)(b1 << 8 | b0);
}
public uint load32(uint addr) {
addr -= memOffset;
byte b0 = registers[addr + 0];
byte b1 = registers[addr + 1];
byte b2 = registers[addr + 2];
byte b3 = registers[addr + 3];
return (uint)(b3 << 24 | b2 << 16 | b1 << 8 | b0);
}
public void write8(uint addr, byte value) {
addr -= memOffset;
registers[addr] = value;
}
public void write16(uint addr, ushort value) {
addr -= memOffset;
registers[addr + 0] = (byte)(value);
registers[addr + 1] = (byte)(value >> 8);
}
public void write32(uint addr, uint value) {
addr -= memOffset;
registers[addr + 0] = (byte)(value);
registers[addr + 1] = (byte)(value >> 8);
registers[addr + 2] = (byte)(value >> 16);
registers[addr + 3] = (byte)(value >> 24);
}
}
}

View file

@ -1,17 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ProjectPSX {
static class EX {
public const uint LOAD_ADRESS_ERROR = 0x4;
public const uint STORE_ADRESS_ERROR = 0x5;
public const uint SYSCALL = 0x8;
public const uint BREAK = 0x9;
public const uint ILLEGAL_INSTR = 0xA;
public const uint COPROCESSOR_ERROR = 0xB;
public const uint OVERFLOW = 0xC;
}
}

View file

@ -57,10 +57,12 @@
</Compile>
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="PSX\EX.cs" />
<Compile Include="PSX\CPU.cs" />
<Compile Include="PSX\MMU.cs" />
<Compile Include="PSX\ProjectPSX.cs" />
<Compile Include="Devices\Device.cs" />
<Compile Include="Devices\DMA.cs" />
<Compile Include="Core\EX.cs" />
<Compile Include="Core\CPU.cs" />
<Compile Include="Core\BUS.cs" />
<Compile Include="Core\ProjectPSX.cs" />
<EmbeddedResource Include="Form1.resx">
<DependentUpon>Form1.cs</DependentUpon>
</EmbeddedResource>