ultimecia

A ps1 emulator in c
Log | Files | Refs

commit e9dd53c3268ecb0a7177545d5abe7cce6e0cbb34
parent fc19c67b4fd962219973c677cbf399163b142823
Author: root <root@fif>
Date:   Sat, 30 Mar 2024 17:03:19 +0000

Made it through gpu endless loop. Now few ops are left

Diffstat:
Mbuild.sh | 2+-
Msrc/cpu.c | 285++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------
Msrc/cpu.h | 28+++++++++++++++++++---------
Msrc/interconnect.c | 276+++++++++++++++++++++++++++++++++++++++++++------------------------------------
Msrc/interconnect.h | 5+++--
Msrc/mem.c | 18++++++++++++++++++
Msrc/mem.h | 6++++--
Msrc/util.c | 5+++--
Msrc/util.h | 2+-
Mtest.c | 1+
10 files changed, 454 insertions(+), 174 deletions(-)

diff --git a/build.sh b/build.sh @@ -1 +1 @@ -cc -static -std=c99 -O3 -Wall -pedantic -g src/*.c -o bin/ultimecia +c++ -Wall -Wpedantic -static -O3 -Wall -pedantic -g src/*.c -o bin/ultimecia diff --git a/src/cpu.c b/src/cpu.c @@ -10,20 +10,26 @@ CPU* new_cpu(Interconnect* inter) { CPU* cpu = (CPU*)malloc(sizeof(CPU)); + cpu->pc = 0xBFC00000; - cpu->sr = 0x0; - cpu->hi = 0xdeaddead; - cpu->lo = 0xdeaddead; + 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; + cpu->branch = 0; + cpu->delay_slot = 0; cpu->inter = inter; cpu->load._0 = 0; cpu->load._1 = 0; - cpu->next_instruction = new_instr(0x0); /* NOP */ + cpu->next_instruction = new_instr(0); /* NOP */ memset(cpu->regs, 0, sizeof(cpu->regs)); memset(cpu->out_regs, 0, sizeof(cpu->out_regs)); return cpu; } u32 CPU_load32(CPU* cpu, u32 addr) { return INTER_load32(cpu->inter, addr); } -//u16 CPU_load16(CPU* cpu, u16 addr) { return INTER_load16(cpu->inter, addr); } +u16 CPU_load16(CPU* cpu, u32 addr) { return INTER_load16(cpu->inter, addr); } 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); } @@ -44,6 +50,31 @@ reg(CPU* cpu, u32 reg) } void +exception(CPU* cpu, EXCEPTION cause) +{ + u32 handler, mode; + + handler = ((cpu->sr & (1 << 22)) != 0) ? 0xBFC00180 : 0x80000080; + mode = cpu->sr & 0x3f; + cpu->sr &= ~0x3f; + cpu->sr |= (mode << 2) & 0x3f; + cpu->cause = (u32)cause << 2; + cpu->epc = cpu->current_pc; + + if (cpu->delay_slot) + { + cpu->epc -= 4; + cpu->cause |= 1 << 31; + } + + cpu->pc = handler; + cpu->next_pc = cpu->pc + 4; + + return; +} + + +void op_lui(CPU* cpu, instruction* i) { u32 v = i->imm << 16; @@ -59,6 +90,14 @@ op_or(CPU* cpu, instruction* i) } void +op_nor(CPU* cpu, instruction* i) +{ + u32 v; + v = !(reg(cpu, i->s) | reg(cpu, i->t)); + set_reg(cpu, i->d, v); +} + +void op_and(CPU* cpu, instruction* i) { u32 v; @@ -91,7 +130,14 @@ op_sw(CPU* cpu, instruction* i) addr = reg(cpu, s) + imm_se; v = reg(cpu, t); - CPU_store32(cpu, addr, v); + if ((addr % 4) == 0) + { + CPU_store32(cpu, addr, v); + } + else + { + exception(cpu, E_STORE_ADRESS_ERROR); + } } void @@ -111,7 +157,17 @@ op_sh(CPU* cpu, instruction* i) addr = reg(cpu, s) + imm_se; v = reg(cpu, t); - CPU_store16(cpu, addr, (u16)v); + + if ((addr % 2) == 0) + { + CPU_store16(cpu, addr, (u16)v); + } + else + { + exception(cpu, E_STORE_ADRESS_ERROR); + } + + } void @@ -149,6 +205,24 @@ op_sll(CPU* cpu, instruction* i) } void +op_srlv(CPU* cpu, instruction* i) +{ + u32 v; + + v = reg(cpu, i->t) >> (reg(cpu, i->s) & 0x1f); + set_reg(cpu, i->d, v); +} + +void +op_sllv(CPU* cpu, instruction* i) +{ + u32 v; + + v = reg(cpu, i->t) << (reg(cpu, i->s) & 0x1f); + set_reg(cpu, i->d, v); +} + +void op_addiu(CPU* cpu, instruction* i) { u32 v; @@ -169,22 +243,35 @@ op_addi(CPU* cpu, instruction* i) if(checked_addi32(v, imm_se, &res)) set_reg(cpu, i->t, res); else - fprintf(stderr, "ADDI OVERFLOW!"), exit(EXIT_FAILURE); + exception(cpu, E_OVERFLOW); } void op_j(CPU* cpu, instruction* i) { - cpu->pc = (cpu->pc & 0xf0000000) | (i->imm_jump << 2); + cpu->next_pc = (cpu->next_pc & 0xf0000000) | (i->imm_jump << 2); + cpu->branch = 1; +} + +void +op_jal(CPU* cpu, instruction* i) +{ + set_reg(cpu, 31, cpu->next_pc); + op_j(cpu, i); } -void op_jal(CPU* cpu, instruction* i) { set_reg(cpu, 31, cpu->pc); op_j(cpu, i); } -void op_jr(CPU* cpu, instruction* i) { cpu->pc = reg(cpu, i->s); } +void +op_jr(CPU* cpu, instruction* i) +{ + cpu->next_pc = reg(cpu, i->s); + cpu->branch = 1; +} void op_jalr(CPU* cpu, instruction* i) { - set_reg(cpu, i->d, cpu->pc); - cpu->pc = reg(cpu, i->s); + set_reg(cpu, i->d, cpu->next_pc); + cpu->next_pc = reg(cpu, i->s); + cpu->branch = 1; } void @@ -232,8 +319,12 @@ op_mfc0(CPU* cpu, instruction* i) cpu->load._1 = cpu->sr; break; case 13: - fprintf(stderr, "Unhandled read from CAUSE register\n"); - exit(EXIT_FAILURE); + cpu->load._0 = i->t; + cpu->load._1 = cpu->cause; + break; + case 14: + cpu->load._0 = i->t; + cpu->load._1 = cpu->epc; break; default: fprintf(stderr, "Unhandled read from cop0r%d\n", cop_r); @@ -242,19 +333,37 @@ op_mfc0(CPU* cpu, instruction* i) } void +op_rfe(CPU* cpu, instruction* i) +{ + u32 mode; + + if ((i->_0 & 0x3f) != 0x10) + { + fprintf(stderr, "Invalid cop0 instruction %08X\n", i->_0); + exit(EXIT_FAILURE); + } + + mode = cpu->sr & 0x3f; + cpu->sr &= ~0x3f; + cpu->sr |= mode >> 2; +} + +void op_cop0(CPU* cpu, instruction* i) { switch (i->cop_opcode) { case 0x00: op_mfc0(cpu, i); break; case 0x04: op_mtc0(cpu, i); break; - default: printf("Unhandled cop0 instruction %08X", i->_0); exit(EXIT_FAILURE); + case 0x10: op_rfe(cpu, i); break; + default: printf("Unhandled cop0 instruction %08X\n", i->_0); exit(EXIT_FAILURE); } } void branch(CPU* cpu, u32 offset) { - cpu->pc += (offset << 2) - 4; + cpu->next_pc += (offset << 2) - 4; + cpu->branch = 1; } void @@ -322,10 +431,20 @@ op_lw(CPU* cpu, instruction* i) u32 v, addr; addr = reg(cpu, i->s) + i->imm_se; - v = CPU_load32(cpu, addr); - cpu->load._0 = i->t; - cpu->load._1 = v; + if ((addr % 4) == 0) + { + v = CPU_load32(cpu, addr); + + cpu->load._0 = i->t; + cpu->load._1 = v; + } + else + { + exception(cpu, E_STORE_ADRESS_ERROR); + } + + } void @@ -354,6 +473,47 @@ op_lbu(CPU* cpu, instruction* i) } void +op_lh(CPU* cpu, instruction* i) +{ + u32 addr; + i16 v; + + addr = reg(cpu, i->s) + i->imm_se; + + if (addr % 2 == 0) + { + v = (i16)CPU_load16(cpu, addr); + + cpu->load._0 = i->t; + cpu->load._1 = (u32)v; + } + else + { + exception(cpu, E_LOAD_ADRESS_ERROR); + } +} + +void +op_lhu(CPU* cpu, instruction* i) +{ + u32 v, addr; + + addr = reg(cpu, i->s) + i->imm_se; + + if (addr % 2 == 0) + { + v = CPU_load16(cpu, addr); + + cpu->load._0 = i->t; + cpu->load._1 = (u32)v; + } + else + { + exception(cpu, E_LOAD_ADRESS_ERROR); + } +} + +void op_slt(CPU* cpu, instruction* i) { u32 v; @@ -399,7 +559,7 @@ op_add(CPU* cpu, instruction* i) if(checked_addi32(s, t, &res)) set_reg(cpu, i->d, (u32)res); else - fprintf(stderr, "ADD OVERFLOW!"), exit(EXIT_FAILURE); + exception(cpu, E_OVERFLOW); } void @@ -417,7 +577,7 @@ op_subu(CPU* cpu, instruction* i) { u32 v; - v = reg(cpu, i->t) - reg(cpu, i->s); + v = reg(cpu, i->s) - reg(cpu, i->t); set_reg(cpu, i->d, v); } @@ -439,6 +599,15 @@ op_sra(CPU* cpu, instruction* i) } void +op_srav(CPU* cpu, instruction* i) +{ + i32 v; + + v = (i32)reg(cpu, i->t) >> (reg(cpu, i->s) & 0x1f); + set_reg(cpu, i->d, (u32)v); +} + +void op_srl(CPU* cpu, instruction* i) { u32 v; @@ -493,6 +662,22 @@ op_divu(CPU* cpu, instruction* i) cpu->lo = (n / d); } } + +void +op_multu(CPU* cpu, instruction* i) +{ + u64 a, b, v; + + a = (u64)reg(cpu, i->s); + b = (u64)reg(cpu, i->t); + + v = a * b; + + cpu->hi = (u32)(v >> 32); + cpu->lo = (u32)v; +} + + void op_mflo(CPU* cpu, instruction* i) { @@ -500,12 +685,30 @@ op_mflo(CPU* cpu, instruction* i) } void +op_mtlo(CPU* cpu, instruction* i) +{ + cpu->lo = reg(cpu, i->s); +} + +void op_mfhi(CPU* cpu, instruction* i) { set_reg(cpu, i->d, cpu->hi); } void +op_mthi(CPU* cpu, instruction* i) +{ + cpu->hi = reg(cpu, i->s); +} + +void op_syscall(CPU* cpu, instruction* i) +{ + exception(cpu, E_SYSCALL); +} + + +void CPU_decode_and_execute(CPU* cpu, instruction* i) { @@ -515,10 +718,14 @@ 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 0x07: op_srav(cpu, i); break; + case 0x04: op_sllv(cpu, i); break; + case 0x06: op_srlv(cpu, i); break; case 0x08: op_jr(cpu, i); break; case 0x09: op_jalr(cpu, i); break; case 0x24: op_and(cpu, i); break; case 0x25: op_or(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; @@ -527,7 +734,11 @@ CPU_decode_and_execute(CPU* cpu, instruction* i) case 0x1a: op_div(cpu, i); break; case 0x1b: op_divu(cpu, i); break; case 0x10: op_mfhi(cpu, i); break; + case 0x11: op_mthi(cpu, i); break; case 0x12: op_mflo(cpu, i); break; + case 0x13: op_mtlo(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); } break; @@ -547,8 +758,10 @@ CPU_decode_and_execute(CPU* cpu, instruction* i) case 0x0f: op_lui(cpu, i); break; case 0x10: op_cop0(cpu, i); break; case 0x20: op_lb(cpu, i); break; + case 0x21: op_lh(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 0x2b: op_sw(cpu, i); break; case 0x28: op_sb(cpu, i); break; case 0x29: op_sh(cpu, i); break; @@ -560,18 +773,26 @@ CPU_decode_and_execute(CPU* cpu, instruction* i) void CPU_run_next_instruction(CPU* cpu) { - u32 pc = cpu->pc; + instruction i = new_instr(CPU_load32(cpu, cpu->pc)); + + cpu->delay_slot = cpu->branch; + cpu->branch = 0; - /* Use previously loaded instruction */ - instruction i = cpu->next_instruction; + cpu->current_pc = cpu->pc; - cpu->next_instruction = new_instr(CPU_load32(cpu, pc)); + if ((cpu->current_pc % 4) != 0) + { + exception(cpu, E_LOAD_ADRESS_ERROR); + return; + } - cpu->pc += 4; + cpu->pc = cpu->next_pc; + cpu->next_pc = cpu->next_pc + 4; - set_reg(cpu, cpu->load._0, cpu->load._1); + set_reg(cpu, cpu->load._0, cpu->load._1); - cpu->load._0 = 0; cpu->load._1 = 0; + cpu->load._0 = 0; + cpu->load._1 = 0; CPU_decode_and_execute(cpu, &i); @@ -590,8 +811,8 @@ new_instr(u32 i) ins.d = (i >> 11) & 0x1f; ins.shift = (i >> 6) & 0x1f; ins.imm = i & 0xffff; - ins.imm_se = (u32)((i16)(i & 0xffff)); - ins.imm_jump = i & 0x3ffffff; - ins.cop_opcode = (i >> 21) & 0x1f; + ins.imm_se = (u32)((i16)(i & 0xffff)); + ins.imm_jump = i & 0x3ffffff; + ins.cop_opcode = (i >> 21) & 0x1f; return ins; } diff --git a/src/cpu.h b/src/cpu.h @@ -2,8 +2,9 @@ #include "interconnect.h" #include "types.h" +#include <iostream> -struct instruction { +typedef struct { u32 _0; u32 fn; u32 t; @@ -15,24 +16,26 @@ struct instruction { u32 sub; u32 shift; u32 cop_opcode; -}; - -typedef struct instruction instruction; +} instruction; -struct load { +typedef struct { u32 _0; u32 _1; -}; - -typedef struct load load; +} Load; struct CPU { /* Program Counter register */ u32 pc; /* Cop0 register 12: Status Register*/ + u32 next_pc; + u32 current_pc; + u32 cause; + u32 epc; u32 sr; u32 hi; u32 lo; + u32 branch; + u32 delay_slot; instruction next_instruction; Interconnect* inter; /* General Registers */ @@ -41,11 +44,18 @@ struct CPU { They contain the output of the current instruction */ u32 out_regs[32]; /* LOAD -> on load delay slots */ - load load; + Load load; }; typedef struct CPU CPU; +typedef enum { + E_SYSCALL = 0x8, + E_LOAD_ADRESS_ERROR = 0x4, + E_STORE_ADRESS_ERROR = 0x5, + E_OVERFLOW = 0xc, +} EXCEPTION; + CPU* new_cpu(Interconnect*); u32 CPU_load32(CPU*, u32); void CPU_decode_and_execute(CPU*, instruction*); diff --git a/src/interconnect.c b/src/interconnect.c @@ -11,8 +11,8 @@ Interconnect* new_interconnect(void) { Interconnect* inter = (Interconnect*)malloc(sizeof(Interconnect)); - inter->BIOS = BIOS_new("roms/scph1001.bin"); - inter->RAM = RAM_new(); + inter->bios = BIOS_new("roms/scph1001.bin"); + inter->ram = RAM_new(); return inter; } @@ -21,40 +21,83 @@ INTER_load8(Interconnect* inter, u32 addr) { u32 offset; u32 abs_addr; + u32 contains; offset = 0; + contains = 0; abs_addr = mask_region(addr); /* Assert abs_address Mappings */ - offset = UTIL_contains(BIOS_START, BIOS_SIZE, abs_addr); - if (offset != -1) - return BIOS_load8(inter->BIOS, offset); + contains = UTIL_contains(BIOS_START, BIOS_SIZE, abs_addr, &offset); + if (contains) + return BIOS_load8(inter->bios, offset); - offset = UTIL_contains(EXPANSION1_START, EXPANSION1_SIZE, abs_addr); - if (offset != -1) + contains = UTIL_contains(EXPANSION1_START, EXPANSION1_SIZE, abs_addr, &offset); + if (contains) return 0xff; - offset = UTIL_contains(RAM_START, RAM_SIZE, abs_addr); - if (offset != -1) - return RAM_load8(inter->RAM, offset); + contains = UTIL_contains(RAM_START, RAM_SIZE, abs_addr, &offset); + if (contains) + return RAM_load8(inter->ram, offset); - offset = UTIL_contains(IRQ_CONTROL_START, IRQ_CONTROL_SIZE, abs_addr); - if (offset != -1) + contains = UTIL_contains(IRQ_CONTROL_START, IRQ_CONTROL_SIZE, abs_addr, &offset); + if (contains) { - printf("IRQ CONTROL read %08X", offset); + printf("IRQ CONTROL read %08X\n", offset); return 0; } PANIC("Unhandled Load8 At Address %08X\n", addr); } +u16 +INTER_load16(Interconnect* inter, u32 addr) +{ + u32 offset; + u32 abs_addr; + u32 contains; + + offset = 0; + contains = 0; + abs_addr = mask_region(addr); + + if (addr % 2 != 0) + { + fprintf(stderr, "Unaligned_load16_abs_address: %08X\n", abs_addr); + exit(EXIT_FAILURE); + } + + /* Assert abs_address Mappings */ + contains = UTIL_contains(SPU_START, SPU_SIZE, abs_addr, &offset); + if (contains) + { + fprintf(stderr, "Unhandled read from SPU register: %08X\n", offset); + return 0; + } + + contains = UTIL_contains(RAM_START, RAM_SIZE, abs_addr, &offset); + if (contains) + return RAM_load16(inter->ram, offset); + + contains = UTIL_contains(IRQ_CONTROL_START, IRQ_CONTROL_SIZE, abs_addr, &offset); + if (contains) + { + printf("IRQ CONTROL read %08X\n", offset); + return 0; + } + + PANIC("Unhandled Load16 At Address %08X\n", abs_addr); +} + u32 INTER_load32(Interconnect* inter, u32 addr) { u32 offset; u32 abs_addr; + u32 contains; offset = 0; + contains = 0; abs_addr = mask_region(addr); if (addr % 4 != 0) @@ -64,18 +107,32 @@ INTER_load32(Interconnect* inter, u32 addr) } /* Assert abs_address Mappings */ - offset = UTIL_contains(BIOS_START, BIOS_SIZE, abs_addr); - if (offset != -1) - return BIOS_load32(inter->BIOS, offset); + contains = UTIL_contains(BIOS_START, BIOS_SIZE, abs_addr, &offset); + if (contains) + return BIOS_load32(inter->bios, offset); + + contains = UTIL_contains(RAM_START, RAM_SIZE, abs_addr, &offset); + if (contains) + return RAM_load32(inter->ram, offset); - offset = UTIL_contains(RAM_START, RAM_SIZE, abs_addr); - if (offset != -1) - return RAM_load32(inter->RAM, offset); + contains = UTIL_contains(IRQ_CONTROL_START, IRQ_CONTROL_SIZE, abs_addr, &offset); + if (contains) + { + printf("IRQ CONTROL read %08X\n", offset); + return 0; + } + + contains = UTIL_contains(DMA_START, DMA_SIZE, abs_addr, &offset); + if (contains) + { + printf("DMA read %08X\n", abs_addr); + return 0; + } - offset = UTIL_contains(IRQ_CONTROL_START, IRQ_CONTROL_SIZE, abs_addr); - if (offset != -1) + contains = UTIL_contains(GPU_START, GPU_SIZE, abs_addr, &offset); + if (contains) { - printf("IRQ CONTROL read %08X", offset); + printf("GPU read %08X\n", abs_addr); return 0; } @@ -85,130 +142,75 @@ INTER_load32(Interconnect* inter, u32 addr) void INTER_store8(Interconnect* inter, u32 addr, u8 val) { - u32 offset = 0; + u32 offset; + u32 contains; u32 abs_addr; + offset = 0; + contains = 0; abs_addr = mask_region(addr); - offset = UTIL_contains(EXPANSION2_START, EXPANSION2_SIZE, abs_addr); - if (offset != -1) + contains = UTIL_contains(EXPANSION2_START, EXPANSION2_SIZE, abs_addr, &offset); + if (contains) { fprintf(stdout, "Ignoring write to EXPANSION2 register at: %08X\n", abs_addr); return; } - offset = UTIL_contains(RAM_START, RAM_SIZE, abs_addr); - if (offset != -1) + contains = UTIL_contains(RAM_START, RAM_SIZE, abs_addr, &offset); + if (contains) { - RAM_store8(inter->RAM, offset, val); + RAM_store8(inter->ram, offset, val); return; } - //offset = UTIL_contains(RAM_SIZE_START, RAM_SIZE_SIZE, abs_addr); - //if (offset != -1) - //{ - // fprintf(stdout, "Ignoring RAM_SIZE register write %X\n", abs_addr); - // return; - //} - - //offset = UTIL_contains(CACHECONTROL_START, CACHECONTROL_SIZE, abs_addr); - //if (offset != -1) - //{ - // fprintf(stdout, "Ignoring CACHECONTROL abs_address write: %X\n", abs_addr); - // return; - //} - - //offset = UTIL_contains(SYSCONTROL_START, SYSCONTROL_SIZE, abs_addr); - //if (offset != -1) - //{ - // switch(offset) { - // case 0: - // if (val != 0x1F000000) { - // fprintf(stderr, "Bad Expansion 1 base abs_address: %08X", val); - // exit(EXIT_FAILURE); - // } - // break; - // case 4: - // if (val != 0x1F802000) { - // fprintf(stderr, "Bad expansion 2 base abs_address: %08X", val); - // exit(EXIT_FAILURE); - // } - // break; - // default: - // fprintf(stderr, "Unhandled write to SYSCONTROL register\n"); - // return; - // } - // return; - //} - PANIC("Unhandled store8 into abs_address: %08X\n", abs_addr); } void INTER_store16(Interconnect* inter, u32 addr, u16 val) { - u32 offset = 0; + u32 offset; + u32 contains; u32 abs_addr; + offset = 0; + contains = 0; abs_addr = mask_region(addr); if (addr % 2 != 0) { fprintf(stderr, "Unaligned_store16_address: %08X", addr); exit(EXIT_FAILURE); + } + contains = UTIL_contains(SPU_START, SPU_SIZE, abs_addr, &offset); + if (contains) + { + fprintf(stdout, "Ignoring SPU register write: %X\n", abs_addr); + return; } - offset = UTIL_contains(SPU_START, SPU_SIZE, abs_addr); - if (offset != -1) + contains = UTIL_contains(TIMERS_START, TIMERS_SIZE, abs_addr, &offset); + if (contains) { - fprintf(stdout, "Ignoring SPU register write; %X\n", abs_addr); + fprintf(stdout, "Ignoring TIMER register write to offset: %X\n", offset); return; } - //offset = UTIL_contains(RAM_START, RAM_SIZE, abs_addr); - //if (offset != -1) - //{ - // fprintf(stdout, "Ignoring RAM write; %X\n", abs_addr); - // return; - //} - - //offset = UTIL_contains(RAM_SIZE_START, RAM_SIZE_SIZE, abs_addr); - //if (offset != -1) - //{ - // fprintf(stdout, "Ignoring RAM_SIZE register write %X\n", abs_addr); - // return; - //} - - //offset = UTIL_contains(CACHECONTROL_START, CACHECONTROL_SIZE, abs_addr); - //if (offset != -1) - //{ - // fprintf(stdout, "Ignoring CACHECONTROL abs_address write: %X\n", abs_addr); - // return; - //} - - //offset = UTIL_contains(SYSCONTROL_START, SYSCONTROL_SIZE, abs_addr); - //if (offset != -1) - //{ - // switch(offset) { - // case 0: - // if (val != 0x1F000000) { - // fprintf(stderr, "Bad Expansion 1 base abs_address: %08X", val); - // exit(EXIT_FAILURE); - // } - // break; - // case 4: - // if (val != 0x1F802000) { - // fprintf(stderr, "Bad expansion 2 base abs_address: %08X", val); - // exit(EXIT_FAILURE); - // } - // break; - // default: - // fprintf(stderr, "Unhandled write to SYSCONTROL register\n"); - // return; - // } - // return; - //} + contains = UTIL_contains(RAM_START, RAM_SIZE, abs_addr, &offset); + if (contains) + { + RAM_store16(inter->ram, offset, val); + return; + } + + contains = UTIL_contains(IRQ_CONTROL_START, IRQ_CONTROL_SIZE, abs_addr, &offset); + if (contains) + { + printf("IRQ control write %08X\n at address %08X\n", val, offset); + return; + } PANIC("Unhandled store16 into abs_address: %08X\n", abs_addr); } @@ -216,44 +218,68 @@ INTER_store16(Interconnect* inter, u32 addr, u16 val) void INTER_store32(Interconnect* inter, u32 addr, u32 val) { - u32 offset = 0; + u32 offset; + u32 contains; u32 abs_addr; + offset = 0; + contains = 0; abs_addr = mask_region(addr); if (addr % 4 != 0) fprintf(stderr, "Unaligned_store32_address: %08X", addr); - offset = UTIL_contains(RAM_START, RAM_SIZE, abs_addr); - if (offset != -1) + contains = UTIL_contains(RAM_START, RAM_SIZE, abs_addr, &offset); + if (contains) { - RAM_store32(inter->RAM, offset, val); + RAM_store32(inter->ram, offset, val); return; } - offset = UTIL_contains(RAM_SIZE_START, RAM_SIZE_SIZE, abs_addr); - if (offset != -1) + contains = UTIL_contains(RAM_SIZE_START, RAM_SIZE_SIZE, abs_addr, &offset); + if (contains) { fprintf(stdout, "Ignoring RAM_SIZE register write %X\n", abs_addr); return; } - offset = UTIL_contains(CACHECONTROL_START, CACHECONTROL_SIZE, abs_addr); - if (offset != -1) + contains = UTIL_contains(CACHECONTROL_START, CACHECONTROL_SIZE, abs_addr, &offset); + if (contains) { fprintf(stdout, "Ignoring CACHECONTROL abs_address write: %X\n", abs_addr); return; } - offset = UTIL_contains(IRQ_CONTROL_START, IRQ_CONTROL_SIZE, abs_addr); - if (offset != -1) + contains = UTIL_contains(IRQ_CONTROL_START, IRQ_CONTROL_SIZE, abs_addr, &offset); + if (contains) { fprintf(stdout, "Ignoring IRQ CONTROL write %08X to address %08X\n", val, offset); return; } - offset = UTIL_contains(SYSCONTROL_START, SYSCONTROL_SIZE, abs_addr); - if (offset != -1) + contains = UTIL_contains(DMA_START, DMA_SIZE, abs_addr, &offset); + if (contains) + { + fprintf(stdout, "Ignoring DMA write %08X to address %08X\n", val, offset); + return; + } + + contains = UTIL_contains(TIMERS_START, TIMERS_SIZE, abs_addr, &offset); + if (contains) + { + fprintf(stdout, "TIMER register write %08X to offset: %08X\n", val, offset); + return; + } + + contains = UTIL_contains(GPU_START, GPU_SIZE, abs_addr, &offset); + if (contains) + { + fprintf(stdout, "GPU write %08X to address %08X\n", val, offset); + return; + } + + contains = UTIL_contains(SYSCONTROL_START, SYSCONTROL_SIZE, abs_addr, &offset); + if (contains) { switch(offset) { case 0: @@ -275,5 +301,5 @@ INTER_store32(Interconnect* inter, u32 addr, u32 val) return; } - PANIC("Unhandled store 32 into abs_address: %08X\n", abs_addr); + PANIC("Unhandled store32 into abs_address: %08X\n", addr); } diff --git a/src/interconnect.h b/src/interconnect.h @@ -5,14 +5,15 @@ #include "types.h" struct Interconnect { - BIOS* BIOS; - RAM* RAM; + BIOS* bios; + RAM* ram; }; typedef struct Interconnect Interconnect; Interconnect* new_interconnect(void); u32 INTER_load32(Interconnect*, u32); +u16 INTER_load16(Interconnect*, u32); u8 INTER_load8(Interconnect*, u32); void INTER_store32(Interconnect*, u32, u32); void INTER_store16(Interconnect*, u32, u16); diff --git a/src/mem.c b/src/mem.c @@ -23,6 +23,17 @@ RAM_load32(RAM* r, u32 offset) (r->data[offset + 0]); } +u16 +RAM_load16(RAM* r, u32 offset) +{ + u16 b0, b1; + + b0 = (u16)r->data[offset]; + b1 = (u16)r->data[offset + 1]; + + return b0 | (b1 << 8); +} + u8 RAM_load8(RAM* r, u32 offset) { @@ -36,6 +47,13 @@ RAM_store8(RAM* r, u32 offset, u8 val) } void +RAM_store16(RAM* r, u32 offset, u16 val) +{ + r->data[offset]=val; + r->data[offset+1] = val >> 8; +} + +void RAM_store32(RAM* r, u32 offset, u32 val) { u8 b0 = val; diff --git a/src/mem.h b/src/mem.h @@ -10,7 +10,9 @@ struct RAM { typedef struct RAM RAM; RAM* RAM_new(void); -u32 RAM_load32(RAM*, u32); u8 RAM_load8(RAM*, u32); -void RAM_store32(RAM* r, u32, u32); +u16 RAM_load16(RAM*, u32); +u32 RAM_load32(RAM*, u32); void RAM_store8(RAM* r, u32, u8); +void RAM_store16(RAM* r, u32, u16); +void RAM_store32(RAM* r, u32, u32); diff --git a/src/util.c b/src/util.c @@ -14,9 +14,10 @@ const u32 REGION_MASK[8] = { }; u32 -UTIL_contains(u32 start, u32 length, u32 addr) +UTIL_contains(u32 start, u32 length, u32 addr, u32 *res) { - return (addr >= start && addr < start + length) ? addr-start : -1; + *res = addr-start; + return (addr >= start && addr < start + length) ? 1 : 0; } u8 diff --git a/src/util.h b/src/util.h @@ -38,6 +38,6 @@ #define GPU_START 0x1F801810 #define GPU_SIZE 8 -u32 UTIL_contains(u32, u32, u32); +u32 UTIL_contains(u32, u32, u32, u32*); u8 checked_addi32(i32, i32, i32*); u32 mask_region(u32); diff --git a/test.c b/test.c @@ -10,6 +10,7 @@ void bar(struct foo *foo1) { foo1->pc +=1; + foo1->pc === 1;k }