Got first character on serial

This commit is contained in:
Your Name 2022-09-08 08:22:50 -04:00
parent 911cea1f32
commit 7013869f15
9 changed files with 348 additions and 115 deletions

View file

@ -3,4 +3,5 @@
A WIP PlayStation 2 emulator
Currently implemented:
Some Emotion Engine opcodes

View file

@ -30,4 +30,6 @@ Bus::Bus(std::string fileName, bool& s)
s = true;
printf("[emu/Bus]: %s: Bus initialized\n", __FUNCTION__);
console.open("log.txt");
}

View file

@ -2,6 +2,7 @@
#include <bits/stdint-uintn.h>
#include <string>
#include <fstream>
class Bus
{
@ -10,6 +11,8 @@ private:
uint8_t bios[0x400000];
uint8_t scratchpad[0x4000];
std::ofstream console;
uint32_t Translate(uint32_t addr)
{
if (addr <= 0x7FFFFFFF)
@ -35,6 +38,14 @@ public:
if (addr >= 0x1FC00000 && addr < 0x21C00000)
return *(T*)&bios[addr - 0x1FC00000];
if (addr >= 0x70000000 && addr < 0x70004000)
return *(T*)&scratchpad[addr - 0x70000000];
switch (addr)
{
case 0x1000f130: // SIO status
return 0;
}
printf("[emu/Bus]: %s: Failed to read from address 0x%08x\n", __FUNCTION__, addr);
exit(1);
@ -53,10 +64,17 @@ public:
switch (addr)
{
// misc SIO settings
case 0x1000f100:
case 0x1000f120:
case 0x1000f140:
case 0x1000f150:
case 0x1000f500:
return;
case 0x1000f180:
console << (char)data;
console.flush();
return;
}
printf("[emu/Bus]: %s: Write to unknown addr 0x%08x\n", __FUNCTION__, addr);

View file

@ -13,12 +13,20 @@ EmotionEngine::EmotionEngine(Bus* bus)
next_pc = pc + 4;
cop0_regs[15] = 0x2E20;
for (int i = 0; i < 128; i++)
{
icache[i].tag[0] = 1 << 31;
icache[i].tag[1] = 1 << 31;
icache[i].lfu[0] = false;
icache[i].lfu[1] = false;
}
}
void EmotionEngine::Clock()
{
Opcode instr;
instr.full = Read32Instr(pc);
instr.full = Read32(pc, true);
AdvancePC();
@ -37,6 +45,9 @@ void EmotionEngine::Clock()
case 0x00:
sll(instr);
break;
case 0x03:
sra(instr);
break;
case 0x08:
jr(instr);
break;
@ -46,9 +57,15 @@ void EmotionEngine::Clock()
case 0x0F:
printf("sync\n");
break;
case 0x12:
mflo(instr);
break;
case 0x18:
mult(instr);
break;
case 0x1B:
divu(instr);
break;
case 0x25:
op_or(instr);
break;
@ -62,9 +79,26 @@ void EmotionEngine::Clock()
}
}
break;
case 0x03:
case 0x01:
{
switch (instr.i_type.rt)
{
case 0x00:
bltz(instr);
break;
default:
printf("[emu/CPU]: %s: Unknown regimm instruction 0x%08x (0x%02x)\n", __FUNCTION__, instr.full, instr.i_type.rt);
Application::Exit(1);
break;
}
}
break;
case 0x02:
j(instr);
break;
case 0x03:
jal(instr);
break;
case 0x04:
beq(instr);
break;
@ -77,6 +111,9 @@ void EmotionEngine::Clock()
case 0x0A:
slti(instr);
break;
case 0x0B:
sltiu(instr);
break;
case 0x0C:
andi(instr);
break;
@ -106,9 +143,33 @@ void EmotionEngine::Clock()
}
}
break;
case 0x14:
beql(instr);
break;
case 0x15:
bnel(instr);
break;
case 0x20:
lb(instr);
break;
case 0x23:
lw(instr);
break;
case 0x24:
lbu(instr);
break;
case 0x28:
sb(instr);
break;
case 0x2B:
sw(instr);
break;
case 0x37:
ld(instr);
break;
case 0x39:
swc1(instr);
break;
case 0x3f:
sd(instr);
break;
@ -124,4 +185,5 @@ void EmotionEngine::Dump()
{
for (int i = 0; i < 32; i++)
printf("[emu/CPU]: %s: %s\t->\t%s\n", __FUNCTION__, Reg(i), print_128(regs[i]));
printf("[emu/CPU]: %s: pc\t->\t0x%08x\n", __FUNCTION__, pc-4);
}

View file

@ -15,6 +15,15 @@ private:
uint32_t pc, next_pc;
uint64_t hi, lo;
struct COP1
{
union
{
float f[32] = {0.0f};
uint32_t i[32];
};
} cop1;
struct CacheTag
{
bool valid = false;
@ -23,47 +32,68 @@ private:
uint32_t page = 0;
};
struct Cache
struct ICacheLine
{
CacheTag tag[2];
uint8_t data[2][64] = {0};
} icache[128], dcache[64];
bool lfu[2];
uint32_t tag[2];
uint8_t data[2][64];
};
ICacheLine icache[128];
bool isCacheEnabled = false;
uint32_t Read32Instr(uint32_t addr)
uint32_t Read32(uint32_t addr, bool isInstr = false)
{
if (!bus->IsCacheable(addr) || !isCacheEnabled)
if (!bus->IsCacheable(addr) || !isCacheEnabled || !isInstr)
return bus->read<uint32_t>(addr);
uint32_t page = (addr >> 14);
uint32_t index = (addr >> 5) & 8;
uint32_t offset = addr & 0x3F;
int index = (addr >> 6) & 0x7F;
uint16_t tag = addr >> 13;
int off = addr & 0x3F;
Cache& line = icache[index];
ICacheLine& line = icache[index];
for (int way = 0; way < 2; way++)
if (line.tag[0] != tag)
{
if (line.tag[way].page == page && line.tag[way].valid)
if (line.tag[1] != tag)
{
return *((uint32_t*)&line.data[way][offset]);
printf("Cache miss for addr 0x%08x\n", addr);
if (line.tag[0] & (1 << 31))
{
line.lfu[0] ^= true;
line.tag[0] = tag;
for (int i = 0; i < 64; i++)
line.data[0][i] = bus->read<uint8_t>((addr & 0xFFFFFFC0) + i);
return *(uint32_t*)&line.data[0][off];
}
else if (line.tag[1] & (1 << 31))
{
line.lfu[1] ^= true;
line.tag[1] = tag;
for (int i = 0; i < 64; i++)
line.data[1][i] = bus->read<uint8_t>((addr & 0xFFFFFFC0) + i);
return *(uint32_t*)&line.data[1][off];
}
else
{
int replace = line.lfu[0] ^ line.lfu[1];
line.lfu[replace] ^= true;
line.lfu[replace] = tag;
for (int i = 0; i < 64; i++)
line.data[replace][i] = bus->read<uint8_t>((addr & 0xFFFFFFC0) + i);
return *(uint32_t*)&line.data[replace][off];
}
}
else
{
return *(uint32_t*)&line.data[1][off];
}
}
// Welp, cache miss
printf("[emu/CPU]: Cache miss for address 0x%08x\n", addr);
int replace = 0;
if (!line.tag[0].valid && line.tag[1].valid)
replace = 0;
else if (line.tag[0].valid && !line.tag[1].valid)
replace = 1;
else
replace = line.tag[0].lrf ^ line.tag[1].lrf;
for (int i = 0; i < 64; i++)
line.data[replace][i] = bus->read<uint8_t>((page << 14) + i);
return *(uint32_t*)&line.data[replace][offset];
{
return *(uint32_t*)&line.data[0][off];
}
}
void Write32(uint32_t addr, uint32_t data)
@ -74,43 +104,7 @@ private:
return;
}
uint32_t page = (addr >> 13);
uint32_t index = (addr >> 5) & 0b1111111;
uint32_t offset = addr & 0x3F;
Cache& line = dcache[index];
for (int way = 0; way < 2; way++)
{
if (line.tag[way].page == page && line.tag[way].valid)
{
*((uint32_t*)&line.data[way][offset]) = data;
line.tag[way].dirty = true; // We mark as dirty to flush back to main memory on eviction
}
}
printf("[emu/CPU]: Cache miss for address 0x%08x\n", addr);
int replace = 0;
if (!line.tag[0].valid && line.tag[1].valid)
replace = 0;
else if (line.tag[0].valid && !line.tag[1].valid)
replace = 1;
else
replace = line.tag[0].lrf ^ line.tag[1].lrf;
if (line.tag[replace].dirty)
{
for (int i = 0; i < 64; i++)
bus->write((page << 13) + i, line.data[replace][i]);
}
for (int i = 0; i < 64; i++)
{
line.data[replace][i] = bus->read<uint8_t>((page << 13) + i);
}
*(uint32_t*)&line.data[replace][offset] = data;
line.tag[replace].dirty = true;
}
void Write64(uint32_t addr, uint64_t data)
@ -120,66 +114,43 @@ private:
bus->write(addr, data);
return;
}
uint32_t page = (addr >> 13);
uint32_t index = (addr >> 5) & 0b1111111;
uint32_t offset = addr & 0x3F;
Cache& line = dcache[index];
for (int way = 0; way < 2; way++)
{
if (line.tag[way].page == page && line.tag[way].valid)
{
*((uint64_t*)&line.data[way][offset]) = data;
line.tag[way].dirty = true; // We mark as dirty to flush back to main memory on eviction
}
}
printf("[emu/CPU]: Cache miss for address 0x%08x\n", addr);
int replace = 0;
if (!line.tag[0].valid && line.tag[1].valid)
replace = 0;
else if (line.tag[0].valid && !line.tag[1].valid)
replace = 1;
else
replace = line.tag[0].lrf ^ line.tag[1].lrf;
if (line.tag[replace].dirty)
{
for (int i = 0; i < 64; i++)
bus->write((page << 13) + i, line.data[replace][i]);
}
for (int i = 0; i < 64; i++)
{
line.data[replace][i] = bus->read<uint8_t>((page << 13) + i);
}
*(uint64_t*)&line.data[replace][offset] = data;
line.tag[replace].dirty = true;
}
void j(Opcode i); // 0x03
void j(Opcode i); // 0x02
void jal(Opcode i); // 0x03
void beq(Opcode i); // 0x04
void bne(Opcode i); // 0x05
void addiu(Opcode i); // 0x09
void slti(Opcode i); // 0x0A
void sltiu(Opcode i); // 0x0B
void andi(Opcode i); // 0x0C
void ori(Opcode i); // 0x0D
void lui(Opcode i); // 0x0F
void mfc0(Opcode i); // 0x10 0x00
void mtc0(Opcode i); // 0x10 0x04
void beql(Opcode i); // 0x14
void bnel(Opcode i); // 0x15
void lb(Opcode i); // 0x20
void lw(Opcode i); // 0x23
void lbu(Opcode i); // 0x24
void sb(Opcode i); // 0x28
void sw(Opcode i); // 0x2B
void ld(Opcode i); // 0x37
void swc1(Opcode i); // 0x39
void sd(Opcode i); // 0x3f
void sll(Opcode i); // 0x00
void sra(Opcode i); // 0x03
void jr(Opcode i); // 0x08
void jalr(Opcode i); // 0x09
void mflo(Opcode i); // 0x12
void mult(Opcode i); // 0x18
void divu(Opcode i); // 0x1B
void op_or(Opcode i); // 0x25
void daddu(Opcode i); // 0x2d
void bltz(Opcode i); // 0x00
void AdvancePC()
{
pc = next_pc;

View file

@ -4,6 +4,7 @@
#include <cstdio>
#include <emu/cpu/EmotionEngine.h>
void EmotionEngine::j(Opcode i)
{
uint32_t target = (i.j_type.target << 2);
@ -11,6 +12,14 @@ void EmotionEngine::j(Opcode i)
printf("j 0x%08x\n", next_pc);
}
void EmotionEngine::jal(Opcode i)
{
uint32_t target = (i.j_type.target << 2);
regs[31].u64[0] = next_pc;
next_pc = (pc & 0xF0000000) | target;
printf("jal 0x%08x\n", next_pc);
}
void EmotionEngine::beq(Opcode i)
{
int32_t imm = (int32_t)((uint32_t)i.i_type.imm << 2);
@ -41,38 +50,44 @@ void EmotionEngine::addiu(Opcode i)
int rs = i.i_type.rs;
int32_t imm = (int16_t)(uint32_t)i.i_type.imm;
regs[rt].u32[0] = (uint32_t)((int32_t)regs[rt].u32[0] + imm);
regs[rt].u64[0] = (uint32_t)((int32_t)regs[rt].u32[0] + imm);
printf("addiu %s, %s, %d\n", Reg(rt), Reg(rs), imm);
}
void EmotionEngine::slti(Opcode i)
{
regs[i.i_type.rt].u32[0] = (int32_t)regs[i.i_type.rs].u32[0] < (int32_t)(uint32_t)i.i_type.imm;
regs[i.i_type.rt].u64[0] = (int32_t)regs[i.i_type.rs].u32[0] < (int32_t)(uint32_t)i.i_type.imm;
printf("slti %s, %s, 0x%04x\n", Reg(i.i_type.rt), Reg(i.i_type.rs), i.i_type.imm);
}
void EmotionEngine::sltiu(Opcode i)
{
regs[i.i_type.rt].u64[0] = regs[i.i_type.rs].u32[0] < (uint32_t)i.i_type.imm;
printf("sltiu %s, %s, 0x%04x\n", Reg(i.i_type.rt), Reg(i.i_type.rs), i.i_type.imm);
}
void EmotionEngine::andi(Opcode i)
{
regs[i.i_type.rt].u32[0] = regs[i.i_type.rs].u32[0] & (uint32_t)(int32_t)i.i_type.imm;
regs[i.i_type.rt].u64[0] = regs[i.i_type.rs].u32[0] & (uint32_t)(int32_t)i.i_type.imm;
printf("andi %s, %s, 0x%08x\n", Reg(i.i_type.rt), Reg(i.i_type.rs), i.i_type.imm);
}
void EmotionEngine::ori(Opcode i)
{
regs[i.i_type.rt].u32[0] = regs[i.i_type.rs].u32[0] | (uint32_t)(int32_t)i.i_type.imm;
regs[i.i_type.rt].u64[0] = regs[i.i_type.rs].u32[0] | (uint32_t)(int32_t)i.i_type.imm;
printf("ori %s, %s, 0x%08x\n", Reg(i.i_type.rt), Reg(i.i_type.rs), i.i_type.imm);
}
void EmotionEngine::lui(Opcode i)
{
regs[i.i_type.rt].u32[0] = (int32_t)((uint32_t)i.i_type.imm << 16);
regs[i.i_type.rt].u64[0] = ((uint32_t)i.i_type.imm << 16);
printf("lui %s, 0x%08x\n", Reg(i.i_type.rt), regs[i.i_type.rt].u32[0]);
}
void EmotionEngine::mfc0(Opcode i)
{
regs[i.r_type.rt].u32[0] = cop0_regs[i.r_type.rd];
regs[i.r_type.rt].u64[0] = cop0_regs[i.r_type.rd];
printf("mfc0 %s, r%d\n", Reg(i.r_type.rt), i.r_type.rd);
}
@ -82,6 +97,89 @@ void EmotionEngine::mtc0(Opcode i)
printf("mtc0 %s, r%d\n", Reg(i.r_type.rt), i.r_type.rd);
}
void EmotionEngine::beql(Opcode i)
{
int32_t imm = (int32_t)((uint32_t)i.i_type.imm << 2);
printf("beql %s, %s, 0x%08x\n", Reg(i.i_type.rs), Reg(i.i_type.rt), next_pc + imm);
if ((int32_t)regs[i.i_type.rs].u32[0] == (int32_t)regs[i.i_type.rt].u32[0])
{
next_pc = pc + imm;
}
else
AdvancePC(); // Skip delay slot
}
void EmotionEngine::bnel(Opcode i)
{
int32_t imm = (int32_t)((uint32_t)i.i_type.imm << 2);
bool taken = false;
if ((int32_t)regs[i.i_type.rs].u32[0] != (int32_t)regs[i.i_type.rt].u32[0])
{
next_pc = pc + imm;
taken = true;
}
else
AdvancePC(); // Skip delay slot
printf("bnel %s, %s, 0x%08x (%s)\n", Reg(i.i_type.rs), Reg(i.i_type.rt), pc + imm, taken ? "taken" : "");
}
void EmotionEngine::lb(Opcode i)
{
int base = i.i_type.rs;
int rt = i.i_type.rt;
int16_t off = (int16_t)i.i_type.imm;
uint32_t addr = regs[base].u32[0] + off;
regs[rt].u64[0] = (int64_t)((uint8_t)(Read32(addr) & 0xFF));
printf("lb %s, %d(%s)\n", Reg(rt), off, Reg(base));
}
void EmotionEngine::lw(Opcode i)
{
int base = i.i_type.rs;
int rt = i.i_type.rt;
int16_t off = (int16_t)i.i_type.imm;
uint32_t addr = regs[base].u32[0] + off;
regs[rt].u32[0] = bus->read<uint32_t>(addr);
printf("lw %s, %d(%s)\n", Reg(rt), off, Reg(base));
}
void EmotionEngine::lbu(Opcode i)
{
int base = i.i_type.rs;
int rt = i.i_type.rt;
int16_t off = (int16_t)i.i_type.imm;
uint32_t addr = regs[base].u32[0] + off;
regs[rt].u64[0] = Read32(addr) & 0xFF;
printf("lbu %s, %d(%s)\n", Reg(rt), off, Reg(base));
}
void EmotionEngine::sb(Opcode i)
{
int base = i.i_type.rs;
int rt = i.i_type.rt;
int16_t off = (int16_t)i.i_type.imm;
uint32_t addr = regs[base].u32[0] + off;
bus->write<uint8_t>(addr, regs[rt].u32[0] & 0xFF);
printf("sb %s, %d(%s)\n", Reg(rt), off, Reg(base));
}
void EmotionEngine::sw(Opcode i)
{
int base = i.i_type.rs;
@ -95,6 +193,32 @@ void EmotionEngine::sw(Opcode i)
printf("sw %s, %d(%s)\n", Reg(rt), off, Reg(base));
}
void EmotionEngine::ld(Opcode i)
{
int base = i.i_type.rs;
int rt = i.i_type.rt;
int16_t off = (int16_t)i.i_type.imm;
uint32_t addr = regs[base].u32[0] + off;
regs[rt].u64[0] = bus->read<uint64_t>(addr);
printf("ld %s, %d(%s)\n", Reg(rt), off, Reg(base));
}
void EmotionEngine::swc1(Opcode i)
{
int base = i.i_type.rs;
int rt = i.i_type.rt;
int16_t off = (int16_t)i.i_type.imm;
uint32_t addr = regs[base].u32[0] + off;
Write32(addr, cop1.i[rt]);
printf("swc1 f%d, %d(%s)\n", rt, off, Reg(base));
}
void EmotionEngine::sd(Opcode i)
{
int base = i.i_type.rs;
@ -122,22 +246,43 @@ void EmotionEngine::sll(Opcode i)
int rt = i.r_type.rt;
int sa = i.r_type.sa;
regs[rd].u32[0] = regs[rt].u32[0] << sa;
regs[rd].u64[0] = regs[rt].u32[0] << sa;
printf("sll %s, %s, %d\n", Reg(rd), Reg(rt), sa);
}
void EmotionEngine::sra(Opcode i)
{
int rd = i.r_type.rd;
int rt = i.r_type.rt;
int sa = i.r_type.sa;
int32_t reg = (int32_t)regs[rt].u32[0];
regs[rd].u64[0] = reg >> sa;
printf("sra %s, %s, %d\n", Reg(rd), Reg(rt), sa);
}
void EmotionEngine::jalr(Opcode i)
{
int rs = i.r_type.rs;
int rd = i.r_type.rd;
regs[rd].u32[0] = next_pc;
regs[rd].u64[0] = next_pc;
next_pc = regs[rs].u32[0];
printf("jalr %s, %s\n", Reg(rs), Reg(rd));
}
void EmotionEngine::mflo(Opcode i)
{
int rd = i.r_type.rd;
regs[rd].u64[0] = lo;
printf("mflo %s\n", Reg(rd));
}
void EmotionEngine::mult(Opcode i)
{
int rs = i.r_type.rs;
@ -148,10 +293,29 @@ void EmotionEngine::mult(Opcode i)
int64_t reg2 = (int64_t)regs[rt].u32[0];
int64_t result = reg1 * reg2;
regs[rd].u32[0] = lo = (int32_t)(result & 0xFFFFFFFF);
regs[rd].u64[0] = lo = (int32_t)(result & 0xFFFFFFFF);
hi = (int32_t)(result >> 32);
printf("mult %s, %s, %s\n", Reg(rd), Reg(rs), Reg(rt));
printf("mult %s, %s, %s (0x%08x, 0x%08x)\n", Reg(rd), Reg(rs), Reg(rt), hi, lo);
}
void EmotionEngine::divu(Opcode i)
{
int rs = i.r_type.rs;
int rt = i.r_type.rt;
if (regs[rt].u32[0] == 0)
{
hi = (int32_t)regs[rs].u32[0];
lo = (int32_t)0xffffffff;
}
else
{
hi = (int32_t)(regs[rs].u32[0] % regs[rt].u32[0]);
lo = (int32_t)(regs[rs].u32[0] / regs[rt].u32[0]);
}
printf("divu %s (0x%08x), %s (0x%08x) (0x%08x, 0x%08x)\n", Reg(rs), regs[rs].u32[0], Reg(rt), regs[rt].u32[0], hi, lo);
}
void EmotionEngine::op_or(Opcode i)
@ -160,7 +324,7 @@ void EmotionEngine::op_or(Opcode i)
int rs = i.r_type.rs;
int rt = i.r_type.rt;
regs[rd].u32[0] = regs[rt].u32[0] | regs[rs].u32[0];
regs[rd].u64[0] = regs[rt].u32[0] | regs[rs].u32[0];
printf("or %s, %s, %s\n", Reg(rd), Reg(rt), Reg(rs));
}
@ -177,4 +341,19 @@ void EmotionEngine::daddu(Opcode i)
regs[rd].u64[0] = reg1 + reg2;
printf("daddu %s, %s, %s\n", Reg(rd), Reg(rs), Reg(rt));
}
void EmotionEngine::bltz(Opcode i)
{
int rs = i.i_type.rs;
int32_t val = (int32_t)regs[rs].u32[0];
int32_t off = (int32_t)(i.i_type.imm << 2);
printf("bltz %s, 0x%08x\n", Reg(rs), pc + off);
if (val < 0)
{
next_pc = pc + off;
}
}