commit 79ffaadb5d386bbfb79a5d3251fc32470b2d49c7
parent e9dd53c3268ecb0a7177545d5abe7cce6e0cbb34
Author: root <root@fif>
Date: Mon, 1 Apr 2024 21:50:05 +0000
implemented all ops. heading for dma
Diffstat:
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;
}