Do some stuff

This commit is contained in:
2025-02-05 20:32:36 +01:00
parent 2daec68484
commit 9837729656
7 changed files with 630 additions and 396 deletions

View File

@@ -9,7 +9,6 @@
// Initialize CPU
void init_cpu(CPU *cpu) {
memset(cpu, 0, sizeof(CPU));
cpu->sp = MEM_SIZE - 1; // Stack grows downward
}
// Helper function for setting flags in the CPU (here we assume bit0 is the Zero flag,
@@ -17,21 +16,25 @@ void init_cpu(CPU *cpu) {
static inline void set_flags(CPU *cpu, int32_t result) {
cpu->flags = 0;
if (result == 0)
cpu->flags |= 0x01; // Zero flag
cpu->flags |= CPU_FLAG_ZERO; // Zero flag
if (result < 0)
cpu->flags |= 0x02; // Negative flag
cpu->flags |= CPU_FLAG_NEGATIVE; // Negative flag
}
// Execute a program (a byte array) on the given CPU.
// Execute one cycle
void step(CPU *cpu) {
if (cpu->mode < EverySecond) {
if (!(cpu->mode & (CPU_MODE_HALTED | CPU_MODE_PAUSED | CPU_MODE_ERROR))) {
return;
}
if (cpu->pc >= MEM_SIZE) {
cpu->mode = Done; //terminate
if (cpu->mode | CPU_MODE_LOOP) {
cpu->pc = 0;
} else {
cpu->mode |= CPU_MODE_HALTED;
}
}
uint8_t opcode = read_mem(cpu, cpu->pc++);
uint8_t reg1, reg2, imm, temp;
uint8_t reg1, reg2, imm, temp, temp2;
uint32_t newPC, addrTemp;
int32_t cmpResult;
@@ -42,7 +45,7 @@ void step(CPU *cpu) {
case BRK:
//Pause CPU (for breakpoints)
cpu->mode = Paused;
cpu->mode |= CPU_MODE_PAUSED;
break;
case INC_RN:
@@ -50,11 +53,10 @@ void step(CPU *cpu) {
reg1 = read_reg_number(cpu);
temp = read_reg(cpu, reg1);
write_reg(cpu, reg1, temp + 1);
cpu->regs[reg1]++;
case INC_ADDR:
//Increment address
addrTemp = read_address(cpu);
addrTemp = read_address_argument(cpu);
temp = read_mem(cpu, addrTemp);
write_mem(cpu, addrTemp, temp + 1);
@@ -63,11 +65,10 @@ void step(CPU *cpu) {
reg1 = read_reg_number(cpu);
temp = read_reg(cpu, reg1);
write_reg(cpu, reg1, temp - 1);
cpu->regs[reg1]++;
case DEC_ADDR:
//Decrement address
addrTemp = read_address(cpu);
addrTemp = read_address_argument(cpu);
temp = read_mem(cpu, addrTemp);
write_mem(cpu, addrTemp, temp - 1);
@@ -88,211 +89,254 @@ void step(CPU *cpu) {
case MOV_RN_ADDR:
// Store register to memory
reg1 = read_reg_number(cpu);
addrTemp = read_address(cpu);
addrTemp = read_address_argument(cpu);
temp = read_reg(cpu, reg1);
write_mem(cpu, addrTemp, temp);
break;
case MOV_ADDR_RN:
// Load memory to register
addrTemp = read_address(cpu);
addrTemp = read_address_argument(cpu);
reg1 = read_reg_number(cpu);
temp = read
write_mem(cpu, addrTemp, cpu->regs[reg1]);
temp = read_mem(cpu, addrTemp);
write_reg(cpu, reg1, temp);
break;
case SWAP: {
// Swap contents of two registers.
reg1 = read_reg_number(cpu);
reg2 = read_reg_number(cpu);
temp = cpu->regs[reg1];
cpu->regs[reg1] = cpu->regs[reg2];
cpu->regs[reg2] = temp;
temp = read_reg(cpu, reg1);
temp2 = read_reg(cpu, reg2);
write_reg(cpu, reg1, temp2);
write_reg(cpu, reg2, temp);
break;
}
case SWAPN: {
// Swap the nibbles of a register.
reg1 = read_reg_number(cpu);
uint8_t val = (uint8_t) cpu->regs[reg1];
cpu->regs[reg1] = ((val & 0x0F) << 4) | ((val & 0xF0) >> 4);
temp = read_reg(cpu, reg1);
cpu->regs[reg1] = ((temp & 0x0F) << 4) | ((temp & 0xF0) >> 4);
write_reg(cpu, reg1, temp);
break;
}
case ADD_RN_RM:
reg1 = read_reg_number(cpu);
reg2 = read_reg_number(cpu);
cpu->regs[reg1] += cpu->regs[reg2];
set_flags(cpu, cpu->regs[reg1]);
temp = read_reg(cpu, reg1);
temp += read_reg(cpu, reg2);
write_reg(cpu, reg1, temp);
set_flags(cpu, temp);
break;
case ADD_RN_IMM:
reg1 = read_reg_number(cpu);
imm = read_mem(cpu, cpu->pc++);
cpu->regs[reg1] += imm;
set_flags(cpu, cpu->regs[reg1]);
temp = read_reg(cpu, reg1);
temp += imm;
write_reg(cpu, reg1, temp);
set_flags(cpu, temp);
break;
case SUB_RN_RM:
reg1 = read_reg_number(cpu);
reg2 = read_reg_number(cpu);
cpu->regs[reg1] -= cpu->regs[reg2];
set_flags(cpu, cpu->regs[reg1]);
temp = read_reg(cpu, reg1);
temp -= read_reg(cpu, reg2);
write_reg(cpu, reg1, temp);
set_flags(cpu, temp);
break;
case SUB_RN_IMM:
reg1 = read_reg_number(cpu);
imm = read_mem(cpu, cpu->pc++);
cpu->regs[reg1] -= imm;
set_flags(cpu, cpu->regs[reg1]);
temp = read_reg(cpu, reg1);
temp -= imm;
write_reg(cpu, reg1, temp);
set_flags(cpu, temp);
break;
case MUL_RN_RM:
reg1 = read_reg_number(cpu);
reg2 = read_reg_number(cpu);
cpu->regs[reg1] *= cpu->regs[reg2];
set_flags(cpu, cpu->regs[reg1]);
temp = read_reg(cpu, reg1);
temp *= read_reg(cpu, reg2);
write_reg(cpu, reg1, temp);
set_flags(cpu, temp);
break;
case MUL_RN_IMM:
reg1 = read_reg_number(cpu);
imm = read_mem(cpu, cpu->pc++);
cpu->regs[reg1] *= imm;
set_flags(cpu, cpu->regs[reg1]);
temp = read_reg(cpu, reg1);
temp *= imm;
write_reg(cpu, reg1, temp);
set_flags(cpu, temp);
break;
case DIV_RN_RM:
reg1 = read_reg_number(cpu);
reg2 = read_reg_number(cpu);
if (cpu->regs[reg2] == 0) {
temp = read_reg(cpu, reg1);
temp2 = read_reg(cpu, reg2);
if (temp2 == 0) {
printf("Error: Division by zero!\n");
cpu->mode = Error;
cpu->mode |= CPU_MODE_ERROR;
return;
}
cpu->regs[reg1] /= cpu->regs[reg2];
set_flags(cpu, cpu->regs[reg1]);
temp /= temp2;
write_reg(cpu, reg1, temp);
set_flags(cpu, temp);
break;
case DIV_RN_IMM:
reg1 = read_reg_number(cpu);
temp = read_reg(cpu, reg1);
imm = read_mem(cpu, cpu->pc++);
if (imm == 0) {
printf("Error: Division by zero!\n");
cpu->mode = Error;
cpu->mode |= CPU_MODE_ERROR;
return;
}
cpu->regs[reg1] /= imm;
set_flags(cpu, cpu->regs[reg1]);
temp /= imm;
write_reg(cpu, reg1, temp);
set_flags(cpu, temp);
break;
case MOD_RN_RM:
reg1 = read_reg_number(cpu);
reg2 = read_reg_number(cpu);
if (cpu->regs[reg2] == 0) {
temp = read_reg(cpu, reg1);
temp2 = read_reg(cpu, reg2);
if (temp2 == 0) {
printf("Error: Modulo by zero!\n");
cpu->mode = Error;
cpu->mode |= CPU_MODE_ERROR;
return;
}
cpu->regs[reg1] %= cpu->regs[reg2];
set_flags(cpu, cpu->regs[reg1]);
temp %= temp2;
write_reg(cpu, reg1, temp);
set_flags(cpu, temp);
break;
case MOD_RN_IMM:
reg1 = read_reg_number(cpu);
temp = read_reg(cpu, reg1);
imm = read_mem(cpu, cpu->pc++);
if (imm == 0) {
printf("Error: Modulo by zero!\n");
cpu->mode = Error;
cpu->mode |= CPU_MODE_ERROR;
return;
}
cpu->regs[reg1] %= imm;
set_flags(cpu, cpu->regs[reg1]);
temp %= imm;
write_reg(cpu, reg1, temp);
set_flags(cpu, temp);
break;
case NEG_RN:
reg1 = read_reg_number(cpu);
cpu->regs[reg1] = -((int32_t) cpu->regs[reg1]);
set_flags(cpu, cpu->regs[reg1]);
temp = -read_reg(cpu, reg1);
write_reg(cpu, reg1, temp);
set_flags(cpu, temp);
break;
case AND_RN_RM:
reg1 = read_reg_number(cpu);
reg2 = read_reg_number(cpu);
cpu->regs[reg1] &= cpu->regs[reg2];
set_flags(cpu, cpu->regs[reg1]);
temp = read_reg(cpu, reg1);
temp &= read_reg(cpu, reg2);
write_reg(cpu, reg1, temp);
set_flags(cpu, temp);
break;
case AND_RN_IMM:
reg1 = read_reg_number(cpu);
temp = read_reg(cpu, reg1);
imm = read_mem(cpu, cpu->pc++);
cpu->regs[reg1] &= imm;
set_flags(cpu, cpu->regs[reg1]);
temp &= imm;
write_reg(cpu, reg1, temp);
set_flags(cpu, temp);
break;
case OR_RN_RM:
reg1 = read_reg_number(cpu);
reg2 = read_reg_number(cpu);
cpu->regs[reg1] |= cpu->regs[reg2];
set_flags(cpu, cpu->regs[reg1]);
temp = read_reg(cpu, reg1);
temp |= read_reg(cpu, reg2);
write_reg(cpu, reg1, temp);
set_flags(cpu, temp);
break;
case OR_RN_IMM:
reg1 = read_reg_number(cpu);
imm = read_mem(cpu, cpu->pc++);
cpu->regs[reg1] |= imm;
set_flags(cpu, cpu->regs[reg1]);
temp = read_reg(cpu, reg1);
temp |= imm;
write_reg(cpu, reg1, temp);
set_flags(cpu, temp);
break;
case XOR_RN_RM:
reg1 = read_reg_number(cpu);
reg2 = read_reg_number(cpu);
cpu->regs[reg1] ^= cpu->regs[reg2];
set_flags(cpu, cpu->regs[reg1]);
temp = read_reg(cpu, reg1);
temp ^= read_reg(cpu, reg2);
write_reg(cpu, reg1, temp);
set_flags(cpu, temp);
break;
case XOR_RN_IMM:
reg1 = read_reg_number(cpu);
imm = read_mem(cpu, cpu->pc++);
cpu->regs[reg1] ^= imm;
set_flags(cpu, cpu->regs[reg1]);
temp = read_reg(cpu, reg1);
temp ^= imm;
write_reg(cpu, reg1, temp);
set_flags(cpu, temp);
break;
case NOT_RN:
reg1 = read_reg_number(cpu);
cpu->regs[reg1] = ~cpu->regs[reg1];
set_flags(cpu, cpu->regs[reg1]);
temp = ~read_reg(cpu, reg1);
write_reg(cpu, reg1, temp);
set_flags(cpu, temp);
break;
case SHL_RN_IMM:
reg1 = read_reg_number(cpu);
imm = read_mem(cpu, cpu->pc++);
cpu->regs[reg1] <<= imm;
set_flags(cpu, cpu->regs[reg1]);
temp = read_reg(cpu, reg1);
temp <<= imm;
write_reg(cpu, reg1, temp);
set_flags(cpu, temp);
break;
case SHR_RN_IMM:
reg1 = read_reg_number(cpu);
imm = read_mem(cpu, cpu->pc++);
cpu->regs[reg1] >>= imm; // Logical right shift (assuming unsigned value)
set_flags(cpu, cpu->regs[reg1]);
temp = read_reg(cpu, reg1);
temp >>= imm; // Logical right shift (assuming unsigned value)
write_reg(cpu, reg1, temp);
set_flags(cpu, temp);
break;
case SAR_RN_IMM:
reg1 = read_reg_number(cpu);
imm = read_mem(cpu, cpu->pc++);
temp = read_reg(cpu, reg1);
// Arithmetic right shift; cast to signed before shifting.
cpu->regs[reg1] = ((int32_t) cpu->regs[reg1]) >> imm;
set_flags(cpu, cpu->regs[reg1]);
temp = ((int32_t) temp) >> imm;
write_reg(cpu, reg1, temp);
set_flags(cpu, temp);
break;
case JMP:
newPC = read_mem32(cpu, cpu->pc);
cpu->pc += 4;
newPC = read_address_argument(cpu);
cpu->pc = newPC;
break;
case JMP_REL:
imm = (int32_t) read_mem(cpu, cpu->pc++);
imm = read_mem(cpu, cpu->pc++) & 0xFF;
cpu->pc += imm;
break;
@@ -300,31 +344,34 @@ void step(CPU *cpu) {
// Compare two registers: set flags (Zero, Negative)
reg1 = read_reg_number(cpu);
reg2 = read_reg_number(cpu);
cmpResult = (int32_t) cpu->regs[reg1] - (int32_t) cpu->regs[reg2];
temp = read_reg(cpu, reg1);
temp2 = read_reg(cpu, reg2);
cmpResult = (int32_t) temp - (int32_t) temp2;
set_flags(cpu, cmpResult);
break;
}
case JE_BIT_RN: {
case JMP_BIT_SET_RN: {
// Jump if bit in register set
reg1 = read_reg_number(cpu);
uint8_t bit = read_mem(cpu, cpu->pc++);
newPC = read_address_argument(cpu);
temp = read_reg(cpu, reg1);
if (reg1 >= REG_COUNT) {
reg1 = REG_COUNT - 1;
}
uint8_t bit = read_mem(cpu, cpu->pc++);
if (bit > 7) {
bit = 7;
}
newPC = read_mem32(cpu, cpu->pc);
cpu->pc += 4;
if (cpu->regs[reg1] & (1 << bit))
if (temp & (1 << bit))
cpu->pc = newPC;
break;
}
case JE_BIT_ADDR: {
case JMP_BIT_SET_ADDR: {
// Jump if bit in register set
addrTemp = read_mem32(cpu, cpu->pc);
addrTemp = read_address_argument(cpu);
if (addrTemp >= MEM_SIZE) {
addrTemp = MEM_SIZE - 1;
}
@@ -332,9 +379,8 @@ void step(CPU *cpu) {
if (bit > 7) {
bit = 7;
}
newPC = read_mem32(cpu, cpu->pc);
cpu->pc += 4;
if (cpu->memory[addrTemp] & (1 << bit))
newPC = read_address_argument(cpu);
if (read_mem(cpu, addrTemp) & (1 << bit))
cpu->pc = newPC;
break;
}
@@ -342,134 +388,98 @@ void step(CPU *cpu) {
case JE: {
// Jump if equal (Zero flag set)
newPC = read_mem32(cpu, cpu->pc);
cpu->pc += 4;
if (cpu->flags & 0x01)
newPC = read_address_argument(cpu);
if (cpu->flags & CPU_FLAG_ZERO)
cpu->pc = newPC;
break;
}
case JNE_BIT_RN: {
case JMP_BIT_CLEAR_RN: {
// Jump if bit in register set
reg1 = read_reg_number(cpu);
if (reg1 >= REG_COUNT) {
reg1 = REG_COUNT - 1;
}
temp = read_reg(cpu, reg1);
uint8_t bit = read_mem(cpu, cpu->pc++);
if (bit > 7) {
bit = 7;
}
newPC = read_mem32(cpu, cpu->pc);
cpu->pc += 4;
if (!(cpu->regs[reg1] & (1 << bit)))
newPC = read_address_argument(cpu);
if (!(temp & (1 << bit)))
cpu->pc = newPC;
break;
}
case JNE_BIT_ADDR: {
case JMP_BIT_CLEAR_ADDR: {
// Jump if bit in register set
addrTemp = read_mem32(cpu, cpu->pc);
if (addrTemp >= MEM_SIZE) {
addrTemp = MEM_SIZE - 1;
}
addrTemp = read_address_argument(cpu);
uint8_t bit = read_mem(cpu, cpu->pc++);
if (bit > 7) {
bit = 7;
}
newPC = read_mem32(cpu, cpu->pc);
cpu->pc += 4;
if (!(cpu->memory[addrTemp] & (1 << bit)))
newPC = read_address_argument(cpu);
if (!(read_mem(cpu, addrTemp) & (1 << bit)))
cpu->pc = newPC;
break;
}
case JNE: {
// Jump if not equal (Zero flag clear)
newPC = read_mem32(cpu, cpu->pc);
cpu->pc += 4;
if (!(cpu->flags & 0x01))
newPC = read_address_argument(cpu);
if (!(cpu->flags & CPU_FLAG_ZERO)) {
cpu->pc = newPC;
}
break;
}
case JG: {
// Jump if greater: not negative and not zero.
newPC = read_mem32(cpu, cpu->pc);
cpu->pc += 4;
if (((cpu->flags & 0x02) == 0) && ((cpu->flags & 0x01) == 0))
newPC = read_address_argument(cpu);
if (!(cpu->flags & CPU_FLAG_NEGATIVE) && !(cpu->flags & CPU_FLAG_ZERO)) {
cpu->pc = newPC;
}
break;
}
case JL: {
// Jump if less: Negative flag set.
newPC = read_mem32(cpu, cpu->pc);
cpu->pc += 4;
if (cpu->flags & 0x02)
newPC = read_address_argument(cpu);
if (cpu->flags & CPU_FLAG_NEGATIVE) {
cpu->pc = newPC;
}
break;
}
case JGE: {
// Jump if greater or equal: Zero flag set or negative clear.
newPC = read_mem32(cpu, cpu->pc);
cpu->pc += 4;
if ((cpu->flags & 0x01) || ((cpu->flags & 0x02) == 0))
newPC = read_address_argument(cpu);
if ((cpu->flags & CPU_FLAG_ZERO) || !(cpu->flags & CPU_FLAG_NEGATIVE)) {
cpu->pc = newPC;
}
break;
}
case JLE: {
// Jump if less or equal: Negative flag set or Zero flag set.
newPC = read_mem32(cpu, cpu->pc);
cpu->pc += 4;
if ((cpu->flags & 0x02) || (cpu->flags & 0x01))
newPC = read_address_argument(cpu);
if ((cpu->flags & CPU_FLAG_NEGATIVE) || (cpu->flags & CPU_FLAG_ZERO)) {
cpu->pc = newPC;
}
break;
}
case CALL: {
// Push the current PC onto the stack, then jump to the address.
newPC = read_mem32(cpu, cpu->pc);
cpu->pc += 4;
// Push return address (current PC) onto the stack.
write_mem32(cpu, cpu->sp, cpu->pc);
cpu->sp -= 4;
newPC = read_address_argument(cpu);
write_stack(cpu);
cpu->pc = newPC;
break;
}
case RET:
// For RET, assume that the return address was stored on the stack.
cpu->pc = read_mem(cpu, ++cpu->sp);
break;
case PUSH: {
// Push register value onto the stack.
reg1 = read_reg_number(cpu);
write_mem(cpu, cpu->sp--, (uint8_t) cpu->regs[reg1]);
break;
}
case POP: {
// Pop a value from the stack into a register.
reg1 = read_reg_number(cpu);
cpu->regs[reg1] = read_mem(cpu, ++cpu->sp);
break;
}
case PUSHF:
// Push the flags register.
write_mem(cpu, cpu->sp--, cpu->flags);
break;
case POPF:
// Pop into the flags register.
cpu->flags = read_mem(cpu, ++cpu->sp);
read_stack(cpu);
break;
default:
printf("Unknown opcode: %d\n", opcode);
cpu->mode = Error;
cpu->mode |= CPU_MODE_ERROR;
}
}

View File

@@ -8,27 +8,31 @@
#include <stdint.h>
#include "stdio.h"
enum Mode {
Paused,
Done,
Error,
EverySecond,
EveryFrame,
MaxSpeed
};
#define MEM_SIZE 65535
// Register count (register names R0 to R7)
#define REG_COUNT 32
#define STACK_SIZE 255
#define CPU_FLAG_ZERO (1 << 0)
#define CPU_FLAG_NEGATIVE (1 << 1)
#define CPU_MODE_PAUSED (1 << 0)
#define CPU_MODE_HALTED (1 << 1)
#define CPU_MODE_ERROR (1 << 2)
#define CPU_MODE_LOOP (1 << 3)
#define CPU_MODE_STEP (1 << 4)
#define CPU_MODE_SECOND (1 << 5)
// CPU state
typedef struct {
uint8_t regs[REG_COUNT];
uint8_t memory[MEM_SIZE];
uint32_t pc; // Program counter
uint32_t sp; // Stack pointer
uint32_t stack[STACK_SIZE]; // Stack pointer
uint32_t stack_ptr; // Stack pointer
uint8_t flags; // Status flags
enum Mode mode;
uint8_t mode;
} CPU;
void step(CPU *cpu);
@@ -45,12 +49,6 @@ typedef enum {
BRK, // BRK - Pause CPU (halts execution until resumed)
INC_RN, //INC Rn - Increment register
INC_ADDR, //INC [Addr] - Increment address
DEC_RN, //DEC Rn - Increment register
DEC_ADDR, //DEC [Addr] - Increment address
MOV_RN_IMM, // MOV Rn, Imm - Move immediate to register (Rn = Imm)
MOV_RN_RM, // MOV Rn, Rm - Move value from one register to another (Rn = Rm)
MOV_RN_ADDR, // MOV Rn, [Addr] - Load value from memory address into register (Rn = [Addr])
@@ -98,15 +96,22 @@ typedef enum {
JMP_REL, // JMP Offset - relative jump (offset is signed)
INC_RN, //INC Rn - Increment register
INC_ADDR, //INC [Addr] - Increment address
DEC_RN, //DEC Rn - Increment register
DEC_ADDR, //DEC [Addr] - Increment address
CMP, // CMP Rn, Rm - Compare two registers (sets flags based on Rn - Rm)
JE, // JE Addr - Jump if equal (if zero flag set, PC = Addr)
JE_BIT_RN, // jump relative if a given bit in a register is set
JE_BIT_ADDR, // jump relative if a given bit in memory is set
JNE, // JNE Addr - Jump if not equal (if zero flag not set, PC = Addr)
JNE_BIT_RN, // jump relative if a given bit in a register is not set
JNE_BIT_ADDR, // jump relative if a given bit in memory is not set
JMP_BIT_SET_RN, // jump relative if a given bit in a register is set
JMP_BIT_SET_ADDR, // jump relative if a given bit in memory is set
JMP_BIT_CLEAR_RN, // jump relative if a given bit in a register is not set
JMP_BIT_CLEAR_ADDR, // jump relative if a given bit in memory is not set
JG, // JG Addr - Jump if greater (if greater flag set, PC = Addr)
@@ -116,17 +121,9 @@ typedef enum {
JLE, // JLE Addr - Jump if less or equal (if less or zero flag set, PC = Addr)
CALL, // CALL Addr - Call subroutine (push PC to stack, PC = Addr)
CALL, // CALL Addr - Call subroutine (push PC, flags and registers to stack, PC = Addr)
RET, // RET - Return from subroutine (pop PC from stack)
PUSH, // PUSH Rn - Push register onto stack (stack[top] = Rn)
POP, // POP Rn - Pop value from stack into register (Rn = stack[top])
PUSHF, // PUSHF - Push flags onto stack (stack[top] = flags)
POPF // POPF - Pop flags from stack (flags = stack[top])
RET, // RET - Return from subroutine (pop PC, flags and registers from stack)
} Opcode;
#endif //RISCB_CORE_H

View File

@@ -37,8 +37,8 @@ uint32_t read_mem32(CPU *cpu, uint32_t addr) {
return read_mem16(cpu, addr) | (read_mem16(cpu, addr + 2) << 16);
}
uint32_t read_address(CPU *cpu) {
uint32_t out = read_mem16(cpu, cpu->pc) | (read_mem16(cpu, cpu->pc + 2) << 16);
uint32_t read_address_argument(CPU *cpu) {
uint32_t out = read_mem32(cpu, cpu->pc);
cpu->pc += 4;
if (out >= MEM_SIZE) {
out = MEM_SIZE - 1;
@@ -46,6 +46,54 @@ uint32_t read_address(CPU *cpu) {
return out;
}
// Push a 32-bit program counter (PC) onto the stack
void write_stack(CPU *cpu) {
if (cpu->pc >= MEM_SIZE) {
return; // Invalid memory address
}
if (cpu->stack_ptr >= STACK_SIZE - 1) {
return; // Stack overflow protection
}
cpu->stack[++cpu->stack_ptr] = cpu->pc;
for (uint32_t reg = 0; reg < REG_COUNT; reg += 4) {
uint32_t packed = cpu->regs[reg] |
((reg + 1 < REG_COUNT) ? (cpu->regs[reg + 1] << 8) : 0) |
((reg + 2 < REG_COUNT) ? (cpu->regs[reg + 2] << 16) : 0) |
((reg + 3 < REG_COUNT) ? (cpu->regs[reg + 3] << 24) : 0);
cpu->stack[++cpu->stack_ptr] = packed;
}
cpu->stack[++cpu->stack_ptr] = cpu->flags;
}
// Pop a 32-bit program counter (PC) and registers from the stack
void read_stack(CPU *cpu) {
if (cpu->stack_ptr == 0) {
return; // Stack underflow protection
}
// Restore flags
cpu->flags = cpu->stack[cpu->stack_ptr--];
// Restore registers
for (int32_t reg = REG_COUNT - 1; reg >= 0; reg -= 4) {
if (cpu->stack_ptr == 0) {
return; // Stack underflow protection
}
uint32_t packed = cpu->stack[cpu->stack_ptr--];
cpu->regs[reg] = (packed & 0xFF);
if (reg - 1 >= 0) cpu->regs[reg - 1] = ((packed >> 8) & 0xFF);
if (reg - 2 >= 0) cpu->regs[reg - 2] = ((packed >> 16) & 0xFF);
if (reg - 3 >= 0) cpu->regs[reg - 3] = ((packed >> 24) & 0xFF);
}
// Restore PC
if (cpu->stack_ptr == 0) {
return; // Stack underflow protection
}
cpu->pc = cpu->stack[cpu->stack_ptr--];
}
uint8_t read_reg_number(CPU *cpu) {
uint8_t out = read_mem(cpu, cpu->pc++);
if (out >= REG_COUNT) {

View File

@@ -8,25 +8,29 @@
#include <stdint.h>
#include "../cpu/core.h"
uint8_t write_mem32(CPU *cpu, uint32_t addr, uint32_t value);
inline uint8_t write_mem32(CPU *cpu, uint32_t addr, uint32_t value);
uint8_t write_mem16(CPU *cpu, uint32_t addr, uint16_t value);
inline uint8_t write_mem16(CPU *cpu, uint32_t addr, uint16_t value);
uint32_t read_mem32(CPU *cpu, uint32_t addr);
inline uint32_t read_mem32(CPU *cpu, uint32_t addr);
uint32_t read_address(CPU *cpu);
inline uint32_t read_address_argument(CPU *cpu);
uint8_t read_reg_number(CPU *cpu);
void read_stack(CPU *cpu);
uint8_t read_reg(CPU *cpu, uint8_t number);
void write_stack(CPU *cpu);
uint8_t write_reg(CPU *cpu, uint8_t number, uint8_t value);
inline uint8_t read_reg_number(CPU *cpu);
uint16_t read_mem16(CPU *cpu, uint32_t addr);
inline uint8_t read_reg(CPU *cpu, uint8_t number);
uint8_t read_mem(CPU *cpu, uint32_t addr);
inline uint8_t write_reg(CPU *cpu, uint8_t number, uint8_t value);
uint8_t write_mem(CPU *cpu, uint32_t addr, uint8_t value);
inline uint16_t read_mem16(CPU *cpu, uint32_t addr);
inline uint8_t read_mem(CPU *cpu, uint32_t addr);
inline uint8_t write_mem(CPU *cpu, uint32_t addr, uint8_t value);
#endif //RISCB_MEMORY_H