commit 2b441df3713557728536ea2133a5960ab6684456
parent 57897fe670ecbe13e70032167987b8ba2bd65c3d
Author: Edea Kramer <edea@lunarcry.my.domain>
Date: Thu, 21 Mar 2024 22:24:43 +0200
half of the opcodes (roughly)
Diffstat:
22 files changed, 749 insertions(+), 188 deletions(-)
diff --git a/.gitignore b/.gitignore
@@ -0,0 +1,3 @@
+bin/
+a.out
+test.c
diff --git a/build.sh b/build.sh
@@ -0,0 +1 @@
+tcc -static -std=c99 -O3 -Wall -pedantic -g src/*.c -o bin/ultimecia
diff --git a/compile b/compile
@@ -1 +0,0 @@
-cc -std=c89 -Wall -pedantic -g src/*.c
diff --git a/include/bios.h b/include/bios.h
@@ -1,12 +0,0 @@
-#pragma once
-
-#include "types.h"
-
-struct BIOS {
- u8* data;
-};
-
-typedef struct BIOS BIOS;
-
-BIOS* BIOS_new(const char*);
-u32 BIOS_load32(BIOS*, u32);
diff --git a/include/cpu.h b/include/cpu.h
@@ -1,64 +0,0 @@
-#pragma once
-
-#include "../include/interconnect.h"
-#include "../include/types.h"
-
-#define IMM_JUMP(i) (i & 0x3ffffff)
-#define IMM_SE(i) (((u32)((i16)(i & 0xffff))));
-
-struct instruction {
- u32 _0;
- u32 fn;
- u32 t;
- u32 s;
- u32 d;
- u32 imm;
- u32 imm_se;
- u32 imm_jump;
- u32 sub;
- u32 shift;
- u32 cop_opcode;
-};
-
-typedef struct instruction instruction;
-
-struct load {
- u32 _0;
- u32 _1;
-};
-
-typedef struct load load;
-
-struct CPU {
-
- /* Program Counter register */
- u32 pc;
-
- /* Cop0 register 12: Status Register*/
- u32 sr;
-
- instruction next_instruction;
-
- Interconnect* inter;
-
- /* General Registers */
- u32 regs[32];
-
- /* Second set of regs to emulate the LOAD DELAY SLOT.
- They contain the output of the current instruction */
- u32 out_regs[32];
-
- /* LOAD -> on load delay slots */
- load load;
-
-};
-
-typedef struct CPU CPU;
-
-CPU* new_cpu(Interconnect*);
-u32 CPU_load32(CPU*, u32);
-void CPU_decode_and_execute(CPU*, instruction*);
-void CPU_run_next_instruction(CPU*);
-
-instruction new_instr(u32);
-void print_instr(instruction*);
diff --git a/include/interconnect.h b/include/interconnect.h
@@ -1,16 +0,0 @@
-#pragma once
-
-#include "../include/bios.h"
-#include "../include/mem.h"
-#include "../include/types.h"
-
-struct Interconnect {
- BIOS* BIOS;
- RAM* RAM;
-};
-
-typedef struct Interconnect Interconnect;
-
-Interconnect* new_interconnect(void);
-u32 INTER_load32(Interconnect*, u32);
-void INTER_store32(Interconnect*, u32, u32);
diff --git a/include/mem.h b/include/mem.h
@@ -1,14 +0,0 @@
-#pragma once
-
-#include "util.h"
-#include "types.h"
-
-struct RAM {
- u8* data;
-};
-
-typedef struct RAM RAM;
-
-RAM* RAM_new(void);
-u32 RAM_load32(RAM*, u32);
-void RAM_store32(RAM* r, u32, u32);
diff --git a/include/util.h b/include/util.h
@@ -1,21 +0,0 @@
-#pragma once
-
-#include "types.h"
-
-#define BIOS_SIZE 512 * 1024
-#define BIOS_START 0xBFC00000
-
-#define SYSCONTROL_SIZE 36
-#define SYSCONTROL_START 0x1F801000
-
-#define RAM_SIZE_SIZE 4
-#define RAM_SIZE_START 0x1F801060
-
-#define CACHECONTROL_SIZE 4
-#define CACHECONTROL_START 0xFFFE0130
-
-#define RAM_SIZE 2 * 1024 * 1024
-#define RAM_START 0xA0000000
-
-
-u32 UTIL_contains(u32, u32, u32);
diff --git a/src/bios.c b/src/bios.c
@@ -1,7 +1,7 @@
#include <stdio.h>
#include <stdlib.h>
-#include "../include/bios.h"
-#include "../include/types.h"
+#include "bios.h"
+#include "types.h"
BIOS*
BIOS_new(const char* path)
@@ -45,3 +45,5 @@ BIOS_load32(BIOS* b, u32 offset)
(b->data[offset + 1] << 8) |
(b->data[offset + 0]);
}
+
+u8 BIOS_load8(BIOS* b, u32 offset) { return b->data[offset]; }
diff --git a/src/bios.h b/src/bios.h
@@ -0,0 +1,13 @@
+#pragma once
+
+#include "types.h"
+
+struct BIOS {
+ u8* data;
+};
+
+typedef struct BIOS BIOS;
+
+BIOS* BIOS_new(const char*);
+u32 BIOS_load32(BIOS*, u32);
+u8 BIOS_load8(BIOS*, u32);
diff --git a/src/cpu.c b/src/cpu.c
@@ -1,10 +1,11 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include "../include/interconnect.h"
-#include "../include/cpu.h"
-#include "../include/types.h"
-#include "../include/defs.h"
+#include "interconnect.h"
+#include "cpu.h"
+#include "types.h"
+#include "defs.h"
+#include "util.h"
CPU*
new_cpu(Interconnect* inter) {
@@ -15,29 +16,29 @@ new_cpu(Interconnect* inter) {
cpu->load._0 = 0; cpu->load._1 = 0;
cpu->next_instruction = new_instr(0x0); /* NOP */
memset(cpu->regs, 0, sizeof(cpu->regs));
- //memset(cpu->out_regs, 0, sizeof(cpu->out_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); }
-//u8 CPU_load8(CPU* cpu, u8 addr) { return INTER_load8(cpu->INTER, addr); }
-//
+//u16 CPU_load16(CPU* cpu, u16 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); }
-//u16 CPU_store16(CPU* cpu, u16 addr) { return INTER_store16(cpu->INTER, addr); }
-//u8 CPU_store8(CPU* cpu, u8 addr) { return INTER_store8(cpu->INTER, addr); }
+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->regs[reg] = val;
- cpu->regs[0] = 0;
+ cpu->out_regs[reg] = val;
+ cpu->out_regs[0] = 0;
}
u32
reg(CPU* cpu, u32 reg)
{
- return cpu->regs[reg];
+ return cpu->out_regs[reg];
}
void
@@ -53,7 +54,14 @@ op_or(CPU* cpu, instruction* i)
u32 v;
v = reg(cpu, i->s) | reg(cpu, i->t);
set_reg(cpu, i->d, v);
- //printf("d: %d = %d\n", i->d, v);
+}
+
+void
+op_and(CPU* cpu, instruction* i)
+{
+ u32 v;
+ v = reg(cpu, i->s) & reg(cpu, i->t);
+ set_reg(cpu, i->d, v);
}
void
@@ -69,6 +77,12 @@ op_sw(CPU* cpu, instruction* i)
{
u32 imm_se, t, s, addr, v;
+ if ((cpu->sr & 0x10000) != 0)
+ {
+ printf("ignoring store while cache is isolated!\n");
+ return;
+ }
+
imm_se = i->imm_se;
t = i->t;
s = i->s;
@@ -79,6 +93,46 @@ op_sw(CPU* cpu, instruction* i)
}
void
+op_sh(CPU* cpu, instruction* i)
+{
+ u32 imm_se, t, s, addr, v;
+
+ if ((cpu->sr & 0x10000) != 0)
+ {
+ printf("ignoring store while cache is isolated!\n");
+ return;
+ }
+
+ imm_se = i->imm_se;
+ t = i->t;
+ s = i->s;
+
+ addr = reg(cpu, s) + imm_se;
+ v = reg(cpu, t);
+ CPU_store16(cpu, addr, (u16)v);
+}
+
+void
+op_sb(CPU* cpu, instruction* i)
+{
+ u32 imm_se, t, s, addr, v;
+
+ if ((cpu->sr & 0x10000) != 0)
+ {
+ printf("ignoring store while cache is isolated!\n");
+ return;
+ }
+
+ imm_se = i->imm_se;
+ t = i->t;
+ s = i->s;
+
+ addr = reg(cpu, s) + imm_se;
+ v = reg(cpu, t);
+ CPU_store8(cpu, addr, (u8)v);
+}
+
+void
op_sll(CPU* cpu, instruction* i)
{
u32 shift, t, d, v;
@@ -101,48 +155,309 @@ op_addiu(CPU* cpu, instruction* i)
}
void
+op_addi(CPU* cpu, instruction* i)
+{
+ u32 v;
+ u32 imm_se;
+ i32 res;
+
+ imm_se = (i32)i->imm_se;
+ v = (i32)reg(cpu, i->s);
+
+ if(checked_addi32(v, imm_se, &res))
+ set_reg(cpu, i->t, res);
+ else
+ fprintf(stderr, "ADDI OVERFLOW!"), exit(EXIT_FAILURE);
+}
+
+void
op_j(CPU* cpu, instruction* i)
{
cpu->pc = (cpu->pc & 0xf0000000) | (i->imm_jump << 2);
}
+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_jalr(CPU* cpu, instruction* i)
+{
+ set_reg(cpu, i->d, cpu->pc);
+ cpu->pc = reg(cpu, i->s);
+}
+
void
op_mtc0(CPU* cpu, instruction* i)
{
- return;
+ u32 cop_r, v;
+
+ cop_r = i->d;
+ v = reg(cpu, i->t);
+
+ switch(cop_r) {
+ case 3: case 5: case 6: case 7: case 9: case 11:
+ if (v != 0)
+ {
+ fprintf(stderr, "Unhandled cop0r%d", cop_r);
+ exit(EXIT_FAILURE);
+ }
+ break;
+ case 12:
+ cpu->sr = v;
+ break;
+ case 13:
+ if (v != 0)
+ {
+ fprintf(stderr, "Unhandled write to CAUSE register\n");
+ exit(EXIT_FAILURE);
+ }
+ break;
+ default:
+ fprintf(stderr, "Unhandled cop0 register %d\n", cop_r);
+ exit(EXIT_FAILURE);
+ }
}
+void
+op_mfc0(CPU* cpu, instruction* i)
+{
+ u32 cop_r, v;
+
+ cop_r = i->d;
+ v = reg(cpu, i->t);
+
+ switch(cop_r) {
+ case 12:
+ cpu->load._0 = i->t;
+ cpu->load._1 = cpu->sr;
+ break;
+ case 13:
+ fprintf(stderr, "Unhandled read from CAUSE register\n");
+ exit(EXIT_FAILURE);
+ break;
+ default:
+ fprintf(stderr, "Unhandled read from cop0r%d\n", cop_r);
+ exit(EXIT_FAILURE);
+ }
+}
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: PANIC("Unhandled cop0 instruction %08X", i->_0);
+ default: printf("Unhandled cop0 instruction %08X", i->_0); exit(EXIT_FAILURE);
+ }
+}
+
+void
+branch(CPU* cpu, u32 offset)
+{
+ cpu->pc += (offset << 2) - 4;
+}
+
+void
+op_bne(CPU* cpu, instruction* i)
+{
+ if (reg(cpu, i->s) != reg(cpu, i->t)) branch(cpu, i->imm_se);
+}
+
+void
+op_beq(CPU* cpu, instruction* i)
+{
+ if (reg(cpu, i->s) == reg(cpu, i->t)) branch(cpu, i->imm_se);
+}
+
+void
+op_bgtz(CPU* cpu, instruction* i)
+{
+ u32 v;
+
+ v = (i32)reg(cpu, i->s);
+
+ if (v > 0)
+ branch(cpu, i->imm_se);
+}
+
+void
+op_blez(CPU* cpu, instruction* i)
+{
+ u32 v;
+
+ v = (i32)reg(cpu, i->s);
+
+ if (v <= 0)
+ branch(cpu, i->imm_se);
+}
+
+void
+op_bxx(CPU* cpu, instruction* i)
+{
+ u8 is_bgez, is_link, test;
+ u32 v;
+
+ is_bgez = (i->_0 >> 16) & 1;
+ is_link = (i->_0 >> 20) & 1;
+
+ v = (i32)reg(cpu, i->s);
+
+ test = v < 0;
+
+ test = test ^ is_bgez;
+
+ if (test != 0)
+ {
+ if (is_link)
+ set_reg(cpu, 31, cpu->pc);
+
+ branch(cpu, i->imm_se);
}
}
void
+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;
+}
+
+void
+op_lb(CPU* cpu, instruction* i)
+{
+ u32 v, addr;
+
+ addr = reg(cpu, i->s) + i->imm_se;
+ v = (i8)CPU_load8(cpu, addr);
+
+ cpu->load._0 = i->t;
+ cpu->load._1 = (u32)v;
+}
+
+void
+op_lbu(CPU* cpu, instruction* i)
+{
+ u32 v, addr;
+
+ addr = reg(cpu, i->s) + i->imm_se;
+ v = CPU_load8(cpu, addr);
+
+ cpu->load._0 = i->t;
+ cpu->load._1 = (u32)v;
+}
+
+void
+op_sltu(CPU* cpu, instruction* i)
+{
+ u32 v;
+
+ v = reg(cpu, i->s) < reg(cpu, i->t);
+ set_reg(cpu, i->d, (u32)v);
+}
+
+void
+op_slti(CPU* cpu, instruction* i)
+{
+ u32 v;
+ v = (i32)reg(cpu, i->s) < (i32)i->imm_se;
+ set_reg(cpu, i->t, (u32)v);
+}
+
+void
+op_add(CPU* cpu, instruction* i)
+{
+ u32 v, s, t, res;
+
+ s = (i32)reg(cpu, i->s);
+ t = (i32)reg(cpu, i->t);
+
+ if(checked_addi32(s, t, &res))
+ set_reg(cpu, i->d, (u32)res);
+ else
+ fprintf(stderr, "ADD OVERFLOW!"), exit(EXIT_FAILURE);
+}
+
+void
+op_addu(CPU* cpu, instruction* i)
+{
+ u32 v;
+
+ v = reg(cpu, i->t) + reg(cpu, i->s);
+ set_reg(cpu, i->d, v);
+
+}
+
+void
+op_subu(CPU* cpu, instruction* i)
+{
+ u32 v;
+
+ v = reg(cpu, i->t) - reg(cpu, i->s);
+ set_reg(cpu, i->d, v);
+
+}
+
+void
+op_andi(CPU* cpu, instruction *i)
+{
+ u32 v;
+ v = reg(cpu, i->s) & i->imm;
+ set_reg(cpu, i->t, v);
+}
+
+void
+op_sra(CPU* cpu, instruction* i)
+{
+ i32 v;
+ v = (i32)reg(cpu, i->t) >> i->shift;
+ set_reg(cpu, i->d, (u32)v);
+}
+
+void
CPU_decode_and_execute(CPU* cpu, instruction* i)
{
switch(i->fn) {
case 0x0:
- {
switch(i->sub) {
case 0x0: op_sll(cpu, i); break;
+ case 0x03: op_sra(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;
- default: PANIC("Unhandled instruction %08X\n", i->_0); break;
+ case 0x2B: op_sltu(cpu, i); break;
+ case 0x20: op_add(cpu, i); break;
+ case 0x21: op_addu(cpu, i); break;
+ case 0x23: op_subu(cpu, i); break;
+ default: printf("Unhandled instruction %08X\n", i->_0); exit(EXIT_FAILURE);
}
break;
- }
- case 0x0f: op_lui(cpu, i); break;
- case 0x0d: op_ori(cpu, i); break;
- case 0x2b: op_sw(cpu, i); break;
- case 0x09: op_addiu(cpu, i); break;
+ case 0x01: op_bxx(cpu, i); break;
case 0x02: op_j(cpu, i); break;
+ case 0x03: op_jal(cpu, i); break;
+ case 0x04: op_beq(cpu, i); break;
+ case 0x05: op_bne(cpu, i); break;
+ case 0x06: op_blez(cpu, i); break;
+ case 0x07: op_bgtz(cpu, i); break;
+ case 0x08: op_addi(cpu, i); break;
+ case 0x09: op_addiu(cpu, i); break;
+ case 0x0a: op_slti(cpu, i); break;
+ case 0x0c: op_andi(cpu, i); break;
+ case 0x0d: op_ori(cpu, i); break;
+ case 0x0f: op_lui(cpu, i); break;
case 0x10: op_cop0(cpu, i); break;
- default: PANIC("Unhandled instruction %08X\n", i->_0);break;
+ case 0x20: op_lb(cpu, i); break;
+ case 0x23: op_lw(cpu, i); break;
+ case 0x24: op_lbu(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);
}
}
@@ -159,9 +474,13 @@ CPU_run_next_instruction(CPU* cpu)
cpu->pc += 4;
+ set_reg(cpu, cpu->load._0, cpu->load._1);
+
+ cpu->load._0 = 0; cpu->load._1 = 0;
+
CPU_decode_and_execute(cpu, &i);
- //memcpy(cpu->regs, cpu->out_regs, sizeof(u32) * 32);
+ memcpy(cpu->regs, cpu->out_regs, sizeof(u32) * 32);
}
instruction
diff --git a/src/cpu.h b/src/cpu.h
@@ -0,0 +1,61 @@
+#pragma once
+
+#include "interconnect.h"
+#include "types.h"
+
+struct instruction {
+ u32 _0;
+ u32 fn;
+ u32 t;
+ u32 s;
+ u32 d;
+ u32 imm;
+ u32 imm_se;
+ u32 imm_jump;
+ u32 sub;
+ u32 shift;
+ u32 cop_opcode;
+};
+
+typedef struct instruction instruction;
+
+struct load {
+ u32 _0;
+ u32 _1;
+};
+
+typedef struct load load;
+
+struct CPU {
+
+ /* Program Counter register */
+ u32 pc;
+
+ /* Cop0 register 12: Status Register*/
+ u32 sr;
+
+ instruction next_instruction;
+
+ Interconnect* inter;
+
+ /* General Registers */
+ u32 regs[32];
+
+ /* Second set of regs to emulate the LOAD DELAY SLOT.
+ They contain the output of the current instruction */
+ u32 out_regs[32];
+
+ /* LOAD -> on load delay slots */
+ load load;
+
+};
+
+typedef struct CPU CPU;
+
+CPU* new_cpu(Interconnect*);
+u32 CPU_load32(CPU*, u32);
+void CPU_decode_and_execute(CPU*, instruction*);
+void CPU_run_next_instruction(CPU*);
+
+instruction new_instr(u32);
+void print_instr(instruction*);
diff --git a/include/defs.h b/src/defs.h
diff --git a/src/interconnect.c b/src/interconnect.c
@@ -1,12 +1,12 @@
#include <stdio.h>
#include <stdlib.h>
-#include "../include/interconnect.h"
-#include "../include/bios.h"
-#include "../include/mem.h"
-#include "../include/util.h"
-#include "../include/types.h"
-#include "../include/defs.h"
+#include "interconnect.h"
+#include "bios.h"
+#include "mem.h"
+#include "util.h"
+#include "types.h"
+#include "defs.h"
Interconnect*
new_interconnect(void) {
@@ -16,67 +16,240 @@ new_interconnect(void) {
return inter;
}
+u8
+INTER_load8(Interconnect* inter, u32 addr)
+{
+ u32 offset;
+ u32 abs_addr;
+
+ offset = 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);
+
+ offset = UTIL_contains(EXPANSION1_START, EXPANSION1_SIZE, abs_addr);
+ if (offset != -1)
+ return 0xff;
+
+ offset = UTIL_contains(RAM_START, RAM_SIZE, abs_addr);
+ if (offset != -1)
+ return RAM_load8(inter->RAM, offset);
+
+ PANIC("Unhandled Load8 At Address %08X\n", abs_addr);
+}
+
u32
INTER_load32(Interconnect* inter, u32 addr)
{
- u32 offset = 0;
+ u32 offset;
+ u32 abs_addr;
- if (addr % 4 != 0) fprintf(stderr, "Unaligned_load32_address: %08X", addr);
+ offset = 0;
+ abs_addr = mask_region(addr);
+
+ if (addr % 4 != 0)
+ {
+ fprintf(stderr, "Unaligned_load32_abs_address: %08X\n", abs_addr);
+ exit(EXIT_FAILURE);
+ }
- /* Assert address Mappings */
- offset = UTIL_contains(BIOS_START, BIOS_SIZE, addr);
+ /* Assert abs_address Mappings */
+ offset = UTIL_contains(BIOS_START, BIOS_SIZE, abs_addr);
if (offset != -1)
return BIOS_load32(inter->BIOS, offset);
- offset = UTIL_contains(RAM_START, RAM_SIZE, addr);
+ offset = UTIL_contains(RAM_START, RAM_SIZE, abs_addr);
if (offset != -1)
return RAM_load32(inter->RAM, offset);
- PANIC("Unhandled Load32 At Address %08X\n", addr);
+ PANIC("Unhandled Load32 At Address %08X\n", abs_addr);
+}
+
+void
+INTER_store8(Interconnect* inter, u32 addr, u8 val)
+{
+ u32 offset = 0;
+ u32 abs_addr;
+
+ abs_addr = mask_region(addr);
+
+ offset = UTIL_contains(EXPANSION2_START, EXPANSION2_SIZE, abs_addr);
+ if (offset != -1)
+ {
+ 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)
+ {
+ return RAM_store8(inter->RAM, offset, val);
+ }
+
+ //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 abs_addr;
+
+ abs_addr = mask_region(addr);
+
+ if (addr % 2 != 0)
+ {
+ fprintf(stderr, "Unaligned_store16_address: %08X", addr);
+ exit(EXIT_FAILURE);
+
+ }
+
+ offset = UTIL_contains(SPU_START, SPU_SIZE, abs_addr);
+ if (offset != -1)
+ {
+ fprintf(stdout, "Ignoring SPU register write; %X\n", abs_addr);
+ 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;
+ //}
+
+ PANIC("Unhandled store16 into abs_address: %08X\n", abs_addr);
}
void
INTER_store32(Interconnect* inter, u32 addr, u32 val)
{
u32 offset = 0;
+ u32 abs_addr;
+
+ abs_addr = mask_region(addr);
if (addr % 4 != 0)
fprintf(stderr, "Unaligned_store32_address: %08X", addr);
- offset = UTIL_contains(RAM_START, RAM_SIZE, addr);
+ offset = UTIL_contains(RAM_START, RAM_SIZE, abs_addr);
if (offset != -1)
{
- fprintf(stdout, "Ignoring RAM write; %X\n", addr);
+ RAM_store32(inter->RAM, offset, val);
return;
}
- offset = UTIL_contains(RAM_SIZE_START, RAM_SIZE_SIZE, addr);
+ 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 RAM_SIZE register write %X\n", addr);
+ fprintf(stdout, "Ignoring CACHECONTROL abs_address write: %X\n", abs_addr);
return;
}
- offset = UTIL_contains(CACHECONTROL_START, CACHECONTROL_SIZE, addr);
+ offset = UTIL_contains(IRQ_CONTROL_START, IRQ_CONTROL_SIZE, abs_addr);
if (offset != -1)
{
- fprintf(stdout, "Ignoring CACHECONTROL address write: %X\n", addr);
+ fprintf(stdout, "Ignoring IRQ CONTROL write %08X to address %08X\n", val, offset);
return;
}
- offset = UTIL_contains(SYSCONTROL_START, SYSCONTROL_SIZE, addr);
+ 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 address: %08X", val);
+ 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 address: %08X", val);
+ fprintf(stderr, "Bad expansion 2 base abs_address: %08X", val);
exit(EXIT_FAILURE);
}
break;
@@ -87,5 +260,5 @@ INTER_store32(Interconnect* inter, u32 addr, u32 val)
return;
}
- PANIC("Unhandled store 32 into address: %08X\n", addr);
+ PANIC("Unhandled store 32 into abs_address: %08X\n", abs_addr);
}
diff --git a/src/interconnect.h b/src/interconnect.h
@@ -0,0 +1,19 @@
+#pragma once
+
+#include "bios.h"
+#include "mem.h"
+#include "types.h"
+
+struct Interconnect {
+ BIOS* BIOS;
+ RAM* RAM;
+};
+
+typedef struct Interconnect Interconnect;
+
+Interconnect* new_interconnect(void);
+u32 INTER_load32(Interconnect*, u32);
+u8 INTER_load8(Interconnect*, u32);
+void INTER_store32(Interconnect*, u32, u32);
+void INTER_store16(Interconnect*, u32, u16);
+void INTER_store8(Interconnect*, u32, u8);
diff --git a/src/main.c b/src/main.c
@@ -2,12 +2,12 @@
#include <string.h>
#include <stdlib.h>
-#include "../include/types.h"
-#include "../include/cpu.h"
-#include "../include/interconnect.h"
-#include "../include/bios.h"
-#include "../include/mem.h"
-#include "../include/defs.h"
+#include "types.h"
+#include "cpu.h"
+#include "interconnect.h"
+#include "bios.h"
+#include "mem.h"
+#include "defs.h"
int
main(int argc, char **argv)
diff --git a/src/mem.c b/src/mem.c
@@ -1,8 +1,8 @@
#include <stdlib.h>
#include <string.h>
-#include "../include/mem.h"
-#include "../include/types.h"
-#include "../include/util.h"
+#include "mem.h"
+#include "types.h"
+#include "util.h"
RAM*
RAM_new(void)
@@ -23,6 +23,18 @@ RAM_load32(RAM* r, u32 offset)
(r->data[offset + 0]);
}
+u8
+RAM_load8(RAM* r, u32 offset)
+{
+ return r->data[offset];
+}
+
+void
+RAM_store8(RAM* r, u32 offset, u8 val)
+{
+ r->data[offset]=val;
+}
+
void
RAM_store32(RAM* r, u32 offset, u32 val)
{
diff --git a/src/mem.h b/src/mem.h
@@ -0,0 +1,16 @@
+#pragma once
+
+#include "util.h"
+#include "types.h"
+
+struct RAM {
+ u8* data;
+};
+
+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);
+void RAM_store8(RAM* r, u32, u8);
diff --git a/include/types.h b/src/types.h
diff --git a/src/util.c b/src/util.c
@@ -1,8 +1,32 @@
-#include "../include/util.h"
-#include "../include/types.h"
+#include "util.h"
+#include "types.h"
+#include <limits.h>
+
+const u32 REGION_MASK[8] = {
+ // KUSEG: 2048MB
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ // KSEG0: 512MB //
+ 0x7fffffff,
+ // KSEG1: 512MB //
+ 0x1fffffff,
+ // KSEG2: 1024MB //
+ 0xffffffff, 0xffffffff
+};
u32
UTIL_contains(u32 start, u32 length, u32 addr)
{
return (addr >= start && addr < start + length) ? addr-start : -1;
}
+
+u8
+checked_addi32(i32 a, i32 b, i32* res)
+{
+ if ((b > 0 && a > INT_MAX - b) || (b < 0 && a < INT_MIN - b)) {
+ return 0;
+ }
+ *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
@@ -0,0 +1,43 @@
+#pragma once
+
+#include "types.h"
+
+#define BIOS_SIZE 512 * 1024
+#define BIOS_START 0x1FC00000
+
+#define SYSCONTROL_SIZE 36
+#define SYSCONTROL_START 0x1F801000
+
+#define RAM_SIZE_SIZE 4
+#define RAM_SIZE_START 0x1F801060
+
+#define CACHECONTROL_SIZE 4
+#define CACHECONTROL_START 0xFFFE0130
+
+#define RAM_SIZE 2 * 1024 * 1024
+#define RAM_START 0x00000000
+
+#define SPU_SIZE 640
+#define SPU_START 0x1F801C00
+
+#define EXPANSION2_SIZE 66
+#define EXPANSION2_START 0x1F802000
+
+#define EXPANSION1_START 0x1F000000
+#define EXPANSION1_SIZE 512*1024
+
+#define IRQ_CONTROL_START 0x1F801070
+#define IRQ_CONTROL_SIZE 8
+
+#define TIMERS_START 0x1F801100
+#define TIMERS_SIZE 0x30
+
+#define DMA_START 0x1F801080
+#define DMA_SIZE 0x80
+
+#define GPU_START 0x1F801810
+#define GPU_SIZE 8
+
+u32 UTIL_contains(u32, u32, u32);
+u8 checked_addi32(i32, i32, i32*);
+u32 mask_region(u32);
diff --git a/test.c b/test.c
@@ -20,5 +20,8 @@ main()
printf("%d", foo1.pc);
bar(&foo1);
printf("%d", foo1.pc);
+
+ (1) ? printf("hello there"), printf("what") : 0;
+ return 0;
}