ultimecia

A ps1 emulator in c
Log | Files | Refs

commit 79ffaadb5d386bbfb79a5d3251fc32470b2d49c7
parent e9dd53c3268ecb0a7177545d5abe7cce6e0cbb34
Author: root <root@fif>
Date:   Mon,  1 Apr 2024 21:50:05 +0000

implemented all ops. heading for dma

Diffstat:
Msrc/cpu.c | 225++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------
Msrc/cpu.h | 10+++++-----
Msrc/interconnect.c | 7++++++-
Msrc/main.c | 13++++++-------
Msrc/mem.h | 5+++++
Msrc/util.c | 10++++++++++
Msrc/util.h | 1+
Mtest.c | 6++----
8 files changed, 242 insertions(+), 35 deletions(-)

diff --git a/src/cpu.c b/src/cpu.c @@ -14,7 +14,6 @@ new_cpu(Interconnect* inter) { cpu->pc = 0xBFC00000; cpu->next_pc = cpu->pc + 4; cpu->current_pc = 0; - cpu->cause = 0x0; cpu->epc = 0x0; cpu->sr = 0x0; cpu->hi = 0xdeaddead; cpu->lo = 0xdeaddead; @@ -35,19 +34,8 @@ u8 CPU_load8(CPU* cpu, u32 addr) { return INTER_load8(cpu->inter, addr); } void CPU_store32(CPU* cpu, u32 addr, u32 val) { INTER_store32(cpu->inter, addr, val); } void CPU_store16(CPU* cpu, u32 addr, u16 val) { INTER_store16(cpu->inter, addr, val); } void CPU_store8(CPU* cpu, u32 addr, u8 val) { INTER_store8(cpu->inter, addr, val); } - -void -set_reg(CPU* cpu, u32 reg, u32 val) -{ - cpu->out_regs[reg] = val; - cpu->out_regs[0] = 0; -} - -u32 -reg(CPU* cpu, u32 reg) -{ - return cpu->out_regs[reg]; -} +void set_reg(CPU* cpu, u32 reg, u32 val) { cpu->out_regs[reg] = val; cpu->out_regs[0] = 0; } +u32 reg(CPU* cpu, u32 reg) { return cpu->out_regs[reg]; } void exception(CPU* cpu, EXCEPTION cause) @@ -90,6 +78,14 @@ op_or(CPU* cpu, instruction* i) } void +op_xor(CPU* cpu, instruction* i) +{ + u32 v; + v = reg(cpu, i->s) ^ reg(cpu, i->t); + set_reg(cpu, i->d, v); +} + +void op_nor(CPU* cpu, instruction* i) { u32 v; @@ -114,6 +110,14 @@ op_ori(CPU* cpu, instruction* i) } void +op_xori(CPU* cpu, instruction* i) +{ + u32 v; + v = reg(cpu, i->s) ^ i->imm; + set_reg(cpu, i->t, v); +} + +void op_sw(CPU* cpu, instruction* i) { u32 imm_se, t, s, addr, v; @@ -141,6 +145,50 @@ op_sw(CPU* cpu, instruction* i) } void +op_swl(CPU* cpu, instruction* i) +{ + u32 addr, v, aligned_addr, cur_mem, mem; + + addr = reg(cpu, i->s) + i->imm_se; + v = reg(cpu, i->t); + aligned_addr = addr & ~3; + cur_mem = CPU_load32(cpu, aligned_addr); + + switch(addr & 3) + { + case 0: mem = (cur_mem & 0xffffff00) | (v >> 24); break; + case 1: mem = (cur_mem & 0xffff0000) | (v >> 16); break; + case 2: mem = (cur_mem & 0xff000000) | (v >> 8); break; + case 3: mem = (cur_mem & 0x00000000) | (v >> 0); break; + default: fprintf(stderr, "* STORE WORD LEFT.. WHAT ARE YOU DOING *\n"); exit(EXIT_FAILURE); + } + + CPU_store32(cpu, addr, mem); +} + +void +op_swr(CPU* cpu, instruction* i) +{ + u32 addr, v, aligned_addr, cur_mem, mem; + + addr = reg(cpu, i->s) + i->imm_se; + v = reg(cpu, i->t); + aligned_addr = addr & ~3; + cur_mem = CPU_load32(cpu, aligned_addr); + + switch(addr & 3) + { + case 0: mem = (cur_mem & 0x00000000) | (v << 0); break; + case 1: mem = (cur_mem & 0x000000ff) | (v << 8); break; + case 2: mem = (cur_mem & 0x0000ffff) | (v << 16); break; + case 3: mem = (cur_mem & 0x00ffffff) | (v << 24); break; + default: fprintf(stderr, "* STORE WORD RIGHT.. WHAT ARE YOU DOING *\n"); exit(EXIT_FAILURE); + } + + CPU_store32(cpu, addr, mem); +} + +void op_sh(CPU* cpu, instruction* i) { u32 imm_se, t, s, addr, v; @@ -166,8 +214,6 @@ op_sh(CPU* cpu, instruction* i) { exception(cpu, E_STORE_ADRESS_ERROR); } - - } void @@ -360,6 +406,27 @@ op_cop0(CPU* cpu, instruction* i) } void +op_cop1(CPU* cpu, instruction* i) +{ + exception(cpu, E_COPROCESSOR_ERROR); +} + +// GTE +void +op_cop2(CPU* cpu, instruction* i) +{ + fprintf(stderr, "Unhandle GTE Instruction: %08X\n", i->_0); + exit(EXIT_FAILURE); + //exception(cpu, E_COPROCESSOR_ERROR); +} + +void +op_cop3(CPU* cpu, instruction* i) +{ + exception(cpu, E_COPROCESSOR_ERROR); +} + +void branch(CPU* cpu, u32 offset) { cpu->next_pc += (offset << 2) - 4; @@ -443,8 +510,56 @@ op_lw(CPU* cpu, instruction* i) { exception(cpu, E_STORE_ADRESS_ERROR); } +} + +void +op_lwl(CPU* cpu, instruction* i) +{ + u32 v, addr, cur_v, aligned_addr, aligned_word; + + addr = reg(cpu, i->s) + i->imm_se; + + cur_v = cpu->out_regs[i->t]; + + aligned_addr = addr & ~3; + aligned_word = CPU_load32(cpu, aligned_addr); + + switch(addr & 3) + { + case 0: v = (cur_v & 0x00ffffff) | (aligned_word << 24); break; + case 1: v = (cur_v & 0x0000ffff) | (aligned_word << 16); break; + case 2: v = (cur_v & 0x000000ff) | (aligned_word << 8); break; + case 3: v = (cur_v & 0x00000000) | (aligned_word << 0); break; + default: fprintf(stderr, "* LOAD WORD LEFT.. WHAT ARE YOU DOING *\n"); exit(EXIT_FAILURE); + } + + cpu->load._0 = i->t; + cpu->load._1 = v; +} + +void +op_lwr(CPU* cpu, instruction* i) +{ + u32 v, addr, cur_v, aligned_addr, aligned_word; + + addr = reg(cpu, i->s) + i->imm_se; + cur_v = cpu->out_regs[i->t]; + + aligned_addr = addr & ~3; + aligned_word = CPU_load32(cpu, aligned_addr); + + switch(addr & 3) + { + case 0: v = (cur_v & 0x00000000) | (aligned_word >> 0); break; + case 1: v = (cur_v & 0xff000000) | (aligned_word >> 8); break; + case 2: v = (cur_v & 0xffff0000) | (aligned_word >> 16); break; + case 3: v = (cur_v & 0xffffff00) | (aligned_word >> 24); break; + default: fprintf(stderr, "* LOAD WORD RIGHT.. WHAT ARE YOU DOING *\n"); exit(EXIT_FAILURE); + } + cpu->load._0 = i->t; + cpu->load._1 = v; } void @@ -573,6 +688,22 @@ op_addu(CPU* cpu, instruction* i) } void +op_sub(CPU* cpu, instruction* i) +{ + i32 s, t; + i32 res; + + s = (i32)reg(cpu, i->s); + t = (i32)reg(cpu, i->t); + + if(checked_subi32(s, t, &res)) + set_reg(cpu, i->d, (u32)res); + else + exception(cpu, E_OVERFLOW); + +} + +void op_subu(CPU* cpu, instruction* i) { u32 v; @@ -664,6 +795,21 @@ op_divu(CPU* cpu, instruction* i) } void +op_mult(CPU* cpu, instruction* i) +{ + i64 a, b; + u64 v; + + a = i64((i32)reg(cpu, i->s)); + b = i64((i32)reg(cpu, i->t)); + + v = u64(a * b); + + cpu->hi = (u32)(v >> 32); + cpu->lo = (u32)v; +} + +void op_multu(CPU* cpu, instruction* i) { u64 a, b, v; @@ -707,6 +853,29 @@ void op_syscall(CPU* cpu, instruction* i) exception(cpu, E_SYSCALL); } +void +op_break(CPU* cpu, instruction* i) +{ + exception(cpu, E_BREAK); +} + +void op_lwc0(CPU* cpu, instruction* i) { exception(cpu, E_COPROCESSOR_ERROR); } +void op_lwc1(CPU* cpu, instruction* i) { exception(cpu, E_COPROCESSOR_ERROR); } +void op_lwc2(CPU* cpu, instruction* i) { fprintf(stderr, "Unhandled GTE LWC: %08X\n", i->_0); exit(EXIT_FAILURE); } +void op_lwc3(CPU* cpu, instruction* i) { exception(cpu, E_COPROCESSOR_ERROR); } + +void op_swc0(CPU* cpu, instruction* i) { exception(cpu, E_COPROCESSOR_ERROR); } +void op_swc1(CPU* cpu, instruction* i) { exception(cpu, E_COPROCESSOR_ERROR); } +void op_swc2(CPU* cpu, instruction* i) { fprintf(stderr, "Unhandled GTE SWC: %08X\n", i->_0); exit(EXIT_FAILURE); } +void op_swc3(CPU* cpu, instruction* i) { exception(cpu, E_COPROCESSOR_ERROR); } + +void +op_illegal(CPU* cpu, instruction* i) +{ + printf("Illegal instruction %08X\n", i->_0); + exception(cpu, E_ILLEGAL_INSTRUCTION); +} + void CPU_decode_and_execute(CPU* cpu, instruction* i) @@ -718,6 +887,7 @@ CPU_decode_and_execute(CPU* cpu, instruction* i) case 0x0: op_sll(cpu, i); break; case 0x02: op_srl(cpu, i); break; case 0x03: op_sra(cpu, i); break; + case 0x0d: op_break(cpu, i); break; case 0x07: op_srav(cpu, i); break; case 0x04: op_sllv(cpu, i); break; case 0x06: op_srlv(cpu, i); break; @@ -725,11 +895,13 @@ CPU_decode_and_execute(CPU* cpu, instruction* i) case 0x09: op_jalr(cpu, i); break; case 0x24: op_and(cpu, i); break; case 0x25: op_or(cpu, i); break; + case 0x26: op_xor(cpu, i); break; case 0x27: op_nor(cpu, i); break; case 0x2a: op_slt(cpu, i); break; case 0x2B: op_sltu(cpu, i); break; case 0x20: op_add(cpu, i); break; case 0x21: op_addu(cpu, i); break; + case 0x22: op_sub(cpu, i); break; case 0x23: op_subu(cpu, i); break; case 0x1a: op_div(cpu, i); break; case 0x1b: op_divu(cpu, i); break; @@ -737,9 +909,10 @@ CPU_decode_and_execute(CPU* cpu, instruction* i) case 0x11: op_mthi(cpu, i); break; case 0x12: op_mflo(cpu, i); break; case 0x13: op_mtlo(cpu, i); break; + case 0x18: op_mult(cpu, i); break; case 0x19: op_multu(cpu, i); break; case 0x0C: op_syscall(cpu, i); break; - default: printf("Unhandled instruction %08X\n", i->_0); exit(EXIT_FAILURE); + default: op_illegal(cpu, i); break; } break; case 0x01: op_bxx(cpu, i); break; @@ -755,17 +928,33 @@ CPU_decode_and_execute(CPU* cpu, instruction* i) case 0x0b: op_sltiu(cpu, i); break; case 0x0c: op_andi(cpu, i); break; case 0x0d: op_ori(cpu, i); break; + case 0x0e: op_xori(cpu, i); break; case 0x0f: op_lui(cpu, i); break; case 0x10: op_cop0(cpu, i); break; + case 0x11: op_cop1(cpu, i); break; + case 0x12: op_cop2(cpu, i); break; + case 0x13: op_cop3(cpu, i); break; case 0x20: op_lb(cpu, i); break; case 0x21: op_lh(cpu, i); break; + case 0x22: op_lwl(cpu, i); break; case 0x23: op_lw(cpu, i); break; case 0x24: op_lbu(cpu, i); break; case 0x25: op_lhu(cpu, i); break; + case 0x26: op_lwr(cpu, i); break; + case 0x2a: op_swl(cpu, i); break; + case 0x2e: op_swr(cpu, i); break; case 0x2b: op_sw(cpu, i); break; case 0x28: op_sb(cpu, i); break; case 0x29: op_sh(cpu, i); break; - default: printf("Unhandled instruction %08X\n", i->_0); exit(EXIT_FAILURE); + case 0x30: op_lwc0(cpu, i); break; + case 0x31: op_lwc1(cpu, i); break; + case 0x32: op_lwc2(cpu, i); break; + case 0x33: op_lwc3(cpu, i); break; + case 0x38: op_swc0(cpu, i); break; + case 0x39: op_swc1(cpu, i); break; + case 0x3a: op_swc2(cpu, i); break; + case 0x3b: op_swc3(cpu, i); break; + default: op_illegal(cpu, i); break; } } diff --git a/src/cpu.h b/src/cpu.h @@ -2,7 +2,6 @@ #include "interconnect.h" #include "types.h" -#include <iostream> typedef struct { u32 _0; @@ -23,7 +22,7 @@ typedef struct { u32 _1; } Load; -struct CPU { +typedef struct { /* Program Counter register */ u32 pc; /* Cop0 register 12: Status Register*/ @@ -45,14 +44,15 @@ struct CPU { u32 out_regs[32]; /* LOAD -> on load delay slots */ Load load; -}; - -typedef struct CPU CPU; +} CPU; typedef enum { E_SYSCALL = 0x8, + E_BREAK = 0x9, E_LOAD_ADRESS_ERROR = 0x4, E_STORE_ADRESS_ERROR = 0x5, + E_COPROCESSOR_ERROR = 0xb, + E_ILLEGAL_INSTRUCTION = 0xa, E_OVERFLOW = 0xc, } EXCEPTION; diff --git a/src/interconnect.c b/src/interconnect.c @@ -133,7 +133,12 @@ INTER_load32(Interconnect* inter, u32 addr) if (contains) { printf("GPU read %08X\n", abs_addr); - return 0; + + switch(offset) + { + case 4: return 0x10000000; + default: return 0; + } } PANIC("Unhandled Load32 At Address %08X\n", addr); diff --git a/src/main.c b/src/main.c @@ -22,13 +22,12 @@ main(int argc, char **argv) CPU_run_next_instruction(cpu); } - //free(inter->BIOS->data); - //free(inter->BIOS); - //free(inter->RAM->data); - //free(inter->RAM); - //free(inter); - //free(cpu); - + free(inter->bios->data); + free(inter->bios); + free(inter->ram->data); + free(inter->ram); + free(inter); + free(cpu); return 0; } diff --git a/src/mem.h b/src/mem.h @@ -7,6 +7,11 @@ struct RAM { u8* data; }; +struct DMA { + u32 control; +}; + +typedef struct DMA DMA; typedef struct RAM RAM; RAM* RAM_new(void); diff --git a/src/util.c b/src/util.c @@ -30,4 +30,14 @@ checked_addi32(i32 a, i32 b, i32* res) return 1; } +u8 +checked_subi32(i32 a, i32 b, i32* res) +{ + if ((b > 0 && a > INT_MAX - b) || (b < 0 && a < INT_MIN - b) || (b == 0 && a == INT_MIN)) { + return 0; // Overflow occurred + } + *res = a - b; + return 1; +} + u32 mask_region(u32 addr) { return addr & REGION_MASK[addr >> 29]; } diff --git a/src/util.h b/src/util.h @@ -40,4 +40,5 @@ u32 UTIL_contains(u32, u32, u32, u32*); u8 checked_addi32(i32, i32, i32*); +u8 checked_subi32(i32, i32, i32*); u32 mask_region(u32); diff --git a/test.c b/test.c @@ -1,6 +1,5 @@ #include <stdio.h> - struct foo { int pc; int ra; @@ -10,10 +9,9 @@ void bar(struct foo *foo1) { foo1->pc +=1; - foo1->pc === 1;k + foo1->pc == 1; } - int main() { @@ -22,7 +20,7 @@ main() bar(&foo1); printf("%d", foo1.pc); - (1) ? printf("hello there"), printf("what") : 0; + 1 ? printf("hello there"), printf("what") : 0; return 0; }