Do some work on the CPU, assembler still needs update
This commit is contained in:
463
cpu/core.c
Normal file
463
cpu/core.c
Normal file
@@ -0,0 +1,463 @@
|
||||
//
|
||||
// Created by bruno on 2.2.2025.
|
||||
//
|
||||
|
||||
#include "core.h"
|
||||
#include "memory.h"
|
||||
#include "string.h"
|
||||
|
||||
// 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,
|
||||
// and bit1 is the Negative flag).
|
||||
static inline void set_flags(CPU *cpu, int32_t result) {
|
||||
cpu->flags = 0;
|
||||
if (result == 0)
|
||||
cpu->flags |= 0x01; // Zero flag
|
||||
if (result < 0)
|
||||
cpu->flags |= 0x02; // Negative flag
|
||||
}
|
||||
|
||||
// Execute a program (a byte array) on the given CPU.
|
||||
void step(CPU *cpu) {
|
||||
if (cpu->mode < EverySecond) {
|
||||
return;
|
||||
}
|
||||
if (cpu->pc >= MEM_SIZE) {
|
||||
cpu->mode = Done; //terminate
|
||||
}
|
||||
uint8_t opcode = read_mem(cpu, cpu->pc++);
|
||||
uint8_t reg1, reg2, imm;
|
||||
uint32_t temp, newPC;
|
||||
int32_t cmpResult;
|
||||
switch (opcode) {
|
||||
case NOP:
|
||||
cpu->pc++;
|
||||
break;
|
||||
|
||||
case BRK:
|
||||
cpu->pc++;
|
||||
cpu->mode = Paused;
|
||||
break;
|
||||
|
||||
case INC_RN:
|
||||
cpu->pc++;
|
||||
reg1 = read_mem(cpu, cpu->pc++);
|
||||
cpu->regs[reg1]++;
|
||||
|
||||
case INC_ADDR:
|
||||
cpu->pc++;
|
||||
imm = read_mem(cpu, cpu->pc++);
|
||||
write_mem(cpu, imm, read_mem(cpu, imm) + 1);
|
||||
|
||||
case DEC_RN:
|
||||
cpu->pc++;
|
||||
reg1 = read_mem(cpu, cpu->pc++);
|
||||
cpu->regs[reg1]--;
|
||||
|
||||
case DEC_ADDR:
|
||||
cpu->pc++;
|
||||
imm = read_mem(cpu, cpu->pc++);
|
||||
write_mem(cpu, imm, read_mem(cpu, imm) - 1);
|
||||
|
||||
case MOV_RN_IMM:
|
||||
reg1 = read_mem(cpu, cpu->pc++);
|
||||
imm = read_mem(cpu, cpu->pc++);
|
||||
cpu->regs[reg1] = imm;
|
||||
break;
|
||||
|
||||
case MOV_RN_RM:
|
||||
reg1 = read_mem(cpu, cpu->pc++);
|
||||
reg2 = read_mem(cpu, cpu->pc++);
|
||||
cpu->regs[reg1] = cpu->regs[reg2];
|
||||
break;
|
||||
|
||||
case MOV_RN_ADDR:
|
||||
// Load from memory into register.
|
||||
reg1 = read_mem(cpu, cpu->pc++);
|
||||
imm = read_mem(cpu, cpu->pc++);
|
||||
cpu->regs[reg1] = read_mem(cpu, imm);
|
||||
break;
|
||||
|
||||
case MOV_ADDR_RN:
|
||||
// Store from register into memory.
|
||||
imm = read_mem(cpu, cpu->pc++);
|
||||
reg1 = read_mem(cpu, cpu->pc++);
|
||||
write_mem(cpu, imm, cpu->regs[reg1]);
|
||||
break;
|
||||
|
||||
case SWAP: {
|
||||
// Swap contents of two registers.
|
||||
reg1 = read_mem(cpu, cpu->pc++);
|
||||
reg2 = read_mem(cpu, cpu->pc++);
|
||||
temp = cpu->regs[reg1];
|
||||
cpu->regs[reg1] = cpu->regs[reg2];
|
||||
cpu->regs[reg2] = temp;
|
||||
break;
|
||||
}
|
||||
|
||||
case SWAPN: {
|
||||
// Swap the nibbles of a register.
|
||||
reg1 = read_mem(cpu, cpu->pc++);
|
||||
uint8_t val = (uint8_t) cpu->regs[reg1];
|
||||
cpu->regs[reg1] = ((val & 0x0F) << 4) | ((val & 0xF0) >> 4);
|
||||
break;
|
||||
}
|
||||
|
||||
case ADD_RN_RM:
|
||||
reg1 = read_mem(cpu, cpu->pc++);
|
||||
reg2 = read_mem(cpu, cpu->pc++);
|
||||
cpu->regs[reg1] += cpu->regs[reg2];
|
||||
set_flags(cpu, cpu->regs[reg1]);
|
||||
break;
|
||||
|
||||
case ADD_RN_IMM:
|
||||
reg1 = read_mem(cpu, cpu->pc++);
|
||||
imm = read_mem(cpu, cpu->pc++);
|
||||
cpu->regs[reg1] += imm;
|
||||
set_flags(cpu, cpu->regs[reg1]);
|
||||
break;
|
||||
|
||||
case SUB_RN_RM:
|
||||
reg1 = read_mem(cpu, cpu->pc++);
|
||||
reg2 = read_mem(cpu, cpu->pc++);
|
||||
cpu->regs[reg1] -= cpu->regs[reg2];
|
||||
set_flags(cpu, cpu->regs[reg1]);
|
||||
break;
|
||||
|
||||
case SUB_RN_IMM:
|
||||
reg1 = read_mem(cpu, cpu->pc++);
|
||||
imm = read_mem(cpu, cpu->pc++);
|
||||
cpu->regs[reg1] -= imm;
|
||||
set_flags(cpu, cpu->regs[reg1]);
|
||||
break;
|
||||
|
||||
case MUL_RN_RM:
|
||||
reg1 = read_mem(cpu, cpu->pc++);
|
||||
reg2 = read_mem(cpu, cpu->pc++);
|
||||
cpu->regs[reg1] *= cpu->regs[reg2];
|
||||
set_flags(cpu, cpu->regs[reg1]);
|
||||
break;
|
||||
|
||||
case MUL_RN_IMM:
|
||||
reg1 = read_mem(cpu, cpu->pc++);
|
||||
imm = read_mem(cpu, cpu->pc++);
|
||||
cpu->regs[reg1] *= imm;
|
||||
set_flags(cpu, cpu->regs[reg1]);
|
||||
break;
|
||||
|
||||
case DIV_RN_RM:
|
||||
reg1 = read_mem(cpu, cpu->pc++);
|
||||
reg2 = read_mem(cpu, cpu->pc++);
|
||||
if (cpu->regs[reg2] == 0) {
|
||||
printf("Error: Division by zero!\n");
|
||||
cpu->mode = Error;
|
||||
return;
|
||||
}
|
||||
cpu->regs[reg1] /= cpu->regs[reg2];
|
||||
set_flags(cpu, cpu->regs[reg1]);
|
||||
break;
|
||||
|
||||
case DIV_RN_IMM:
|
||||
reg1 = read_mem(cpu, cpu->pc++);
|
||||
imm = read_mem(cpu, cpu->pc++);
|
||||
if (imm == 0) {
|
||||
printf("Error: Division by zero!\n");
|
||||
cpu->mode = Error;
|
||||
return;
|
||||
}
|
||||
cpu->regs[reg1] /= imm;
|
||||
set_flags(cpu, cpu->regs[reg1]);
|
||||
break;
|
||||
|
||||
case MOD_RN_RM:
|
||||
reg1 = read_mem(cpu, cpu->pc++);
|
||||
reg2 = read_mem(cpu, cpu->pc++);
|
||||
if (cpu->regs[reg2] == 0) {
|
||||
printf("Error: Modulo by zero!\n");
|
||||
cpu->mode = Error;
|
||||
return;
|
||||
}
|
||||
cpu->regs[reg1] %= cpu->regs[reg2];
|
||||
set_flags(cpu, cpu->regs[reg1]);
|
||||
break;
|
||||
|
||||
case MOD_RN_IMM:
|
||||
reg1 = read_mem(cpu, cpu->pc++);
|
||||
imm = read_mem(cpu, cpu->pc++);
|
||||
if (imm == 0) {
|
||||
printf("Error: Modulo by zero!\n");
|
||||
cpu->mode = Error;
|
||||
return;
|
||||
}
|
||||
cpu->regs[reg1] %= imm;
|
||||
set_flags(cpu, cpu->regs[reg1]);
|
||||
break;
|
||||
|
||||
case NEG_RN:
|
||||
reg1 = read_mem(cpu, cpu->pc++);
|
||||
cpu->regs[reg1] = -((int32_t) cpu->regs[reg1]);
|
||||
set_flags(cpu, cpu->regs[reg1]);
|
||||
break;
|
||||
|
||||
case AND_RN_RM:
|
||||
reg1 = read_mem(cpu, cpu->pc++);
|
||||
reg2 = read_mem(cpu, cpu->pc++);
|
||||
cpu->regs[reg1] &= cpu->regs[reg2];
|
||||
set_flags(cpu, cpu->regs[reg1]);
|
||||
break;
|
||||
|
||||
case AND_RN_IMM:
|
||||
reg1 = read_mem(cpu, cpu->pc++);
|
||||
imm = read_mem(cpu, cpu->pc++);
|
||||
cpu->regs[reg1] &= imm;
|
||||
set_flags(cpu, cpu->regs[reg1]);
|
||||
break;
|
||||
|
||||
case OR_RN_RM:
|
||||
reg1 = read_mem(cpu, cpu->pc++);
|
||||
reg2 = read_mem(cpu, cpu->pc++);
|
||||
cpu->regs[reg1] |= cpu->regs[reg2];
|
||||
set_flags(cpu, cpu->regs[reg1]);
|
||||
break;
|
||||
|
||||
case OR_RN_IMM:
|
||||
reg1 = read_mem(cpu, cpu->pc++);
|
||||
imm = read_mem(cpu, cpu->pc++);
|
||||
cpu->regs[reg1] |= imm;
|
||||
set_flags(cpu, cpu->regs[reg1]);
|
||||
break;
|
||||
|
||||
case XOR_RN_RM:
|
||||
reg1 = read_mem(cpu, cpu->pc++);
|
||||
reg2 = read_mem(cpu, cpu->pc++);
|
||||
cpu->regs[reg1] ^= cpu->regs[reg2];
|
||||
set_flags(cpu, cpu->regs[reg1]);
|
||||
break;
|
||||
|
||||
case XOR_RN_IMM:
|
||||
reg1 = read_mem(cpu, cpu->pc++);
|
||||
imm = read_mem(cpu, cpu->pc++);
|
||||
cpu->regs[reg1] ^= imm;
|
||||
set_flags(cpu, cpu->regs[reg1]);
|
||||
break;
|
||||
|
||||
case NOT_RN:
|
||||
reg1 = read_mem(cpu, cpu->pc++);
|
||||
cpu->regs[reg1] = ~cpu->regs[reg1];
|
||||
set_flags(cpu, cpu->regs[reg1]);
|
||||
break;
|
||||
|
||||
case SHL_RN_IMM:
|
||||
reg1 = read_mem(cpu, cpu->pc++);
|
||||
imm = read_mem(cpu, cpu->pc++);
|
||||
cpu->regs[reg1] <<= imm;
|
||||
set_flags(cpu, cpu->regs[reg1]);
|
||||
break;
|
||||
|
||||
case SHR_RN_IMM:
|
||||
reg1 = read_mem(cpu, cpu->pc++);
|
||||
imm = read_mem(cpu, cpu->pc++);
|
||||
cpu->regs[reg1] >>= imm; // Logical right shift (assuming unsigned value)
|
||||
set_flags(cpu, cpu->regs[reg1]);
|
||||
break;
|
||||
|
||||
case SAR_RN_IMM:
|
||||
reg1 = read_mem(cpu, cpu->pc++);
|
||||
imm = read_mem(cpu, cpu->pc++);
|
||||
// Arithmetic right shift; cast to signed before shifting.
|
||||
cpu->regs[reg1] = ((int32_t) cpu->regs[reg1]) >> imm;
|
||||
set_flags(cpu, cpu->regs[reg1]);
|
||||
break;
|
||||
|
||||
case JMP:
|
||||
newPC = read_mem32(cpu, cpu->pc);
|
||||
cpu->pc += 4;
|
||||
cpu->pc = newPC;
|
||||
break;
|
||||
|
||||
case JMP_REL:
|
||||
imm = (int32_t) read_mem(cpu, cpu->pc++);
|
||||
cpu->pc += imm;
|
||||
break;
|
||||
|
||||
case CMP: {
|
||||
// Compare two registers: set flags (Zero, Negative)
|
||||
reg1 = read_mem(cpu, cpu->pc++);
|
||||
reg2 = read_mem(cpu, cpu->pc++);
|
||||
cmpResult = (int32_t) cpu->regs[reg1] - (int32_t) cpu->regs[reg2];
|
||||
set_flags(cpu, cmpResult);
|
||||
break;
|
||||
}
|
||||
|
||||
case JE_BIT_RN: {
|
||||
// Jump if bit in register set
|
||||
reg1 = read_mem(cpu, cpu->pc++);
|
||||
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))
|
||||
cpu->pc = newPC;
|
||||
break;
|
||||
}
|
||||
|
||||
case JE_BIT_ADDR: {
|
||||
// Jump if bit in register set
|
||||
temp = read_mem32(cpu, cpu->pc);
|
||||
if (temp >= MEM_SIZE) {
|
||||
temp = MEM_SIZE - 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->memory[temp] & (1 << bit))
|
||||
cpu->pc = newPC;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
case JE: {
|
||||
// Jump if equal (Zero flag set)
|
||||
newPC = read_mem32(cpu, cpu->pc);
|
||||
cpu->pc += 4;
|
||||
if (cpu->flags & 0x01)
|
||||
cpu->pc = newPC;
|
||||
break;
|
||||
}
|
||||
|
||||
case JNE_BIT_RN: {
|
||||
// Jump if bit in register set
|
||||
reg1 = read_mem(cpu, cpu->pc++);
|
||||
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)))
|
||||
cpu->pc = newPC;
|
||||
break;
|
||||
}
|
||||
|
||||
case JNE_BIT_ADDR: {
|
||||
// Jump if bit in register set
|
||||
temp = read_mem32(cpu, cpu->pc);
|
||||
if (temp >= MEM_SIZE) {
|
||||
temp = MEM_SIZE - 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->memory[temp] & (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))
|
||||
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))
|
||||
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)
|
||||
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))
|
||||
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))
|
||||
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_mem(cpu, cpu->sp--, (uint8_t) (cpu->pc & 0xFF));
|
||||
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_mem(cpu, cpu->pc++);
|
||||
write_mem(cpu, cpu->sp--, (uint8_t) (cpu->regs[reg1] & 0xFF));
|
||||
break;
|
||||
}
|
||||
|
||||
case POP: {
|
||||
// Pop a value from the stack into a register.
|
||||
reg1 = read_mem(cpu, cpu->pc++);
|
||||
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);
|
||||
break;
|
||||
|
||||
default:
|
||||
printf("Unknown opcode: %d\n", opcode);
|
||||
cpu->mode = Error;
|
||||
}
|
||||
}
|
132
cpu/core.h
Normal file
132
cpu/core.h
Normal file
@@ -0,0 +1,132 @@
|
||||
//
|
||||
// Created by bruno on 2.2.2025.
|
||||
//
|
||||
|
||||
#ifndef RISCB_CORE_H
|
||||
#define RISCB_CORE_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include "stdio.h"
|
||||
|
||||
enum Mode {
|
||||
Paused,
|
||||
Done,
|
||||
Error,
|
||||
EverySecond,
|
||||
EveryFrame,
|
||||
MaxSpeed
|
||||
};
|
||||
|
||||
#define MEM_SIZE 8192
|
||||
// Register count (register names R0 to R7)
|
||||
#define REG_COUNT 32
|
||||
|
||||
// CPU state
|
||||
typedef struct {
|
||||
uint32_t regs[REG_COUNT];
|
||||
uint8_t memory[MEM_SIZE];
|
||||
uint32_t pc; // Program counter
|
||||
uint32_t sp; // Stack pointer
|
||||
uint8_t flags; // Status flags
|
||||
enum Mode mode;
|
||||
} CPU;
|
||||
|
||||
void step(CPU *cpu);
|
||||
|
||||
void init_cpu(CPU *cpu);
|
||||
|
||||
// Helper function for setting flags in the CPU (here we assume bit0 is the Zero flag,
|
||||
// and bit1 is the Negative flag).
|
||||
static inline void set_flags(CPU *cpu, int32_t result);
|
||||
|
||||
// Opcode definitions (should match the CPU’s enum)
|
||||
typedef enum {
|
||||
NOP, // NOP - No operation (does nothing, advances to next instruction)
|
||||
|
||||
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])
|
||||
MOV_ADDR_RN, // MOV [Addr], Rn - Store register value into memory address ([Addr] = Rn)
|
||||
|
||||
SWAP, // SWAP Rn, Rm - Swap values between two registers (Rn <-> Rm)
|
||||
|
||||
SWAPN, // SWAPN Rn - Swap nibbles within a register (Rn high/low nibbles swapped)
|
||||
|
||||
ADD_RN_RM, // ADD Rn, Rm - Add values of two registers (Rn = Rn + Rm)
|
||||
ADD_RN_IMM, // ADD Rn, Imm - Add immediate value to register (Rn = Rn + Imm)
|
||||
|
||||
SUB_RN_RM, // SUB Rn, Rm - Subtract one register from another (Rn = Rn - Rm)
|
||||
SUB_RN_IMM, // SUB Rn, Imm - Subtract immediate value from register (Rn = Rn - Imm)
|
||||
|
||||
MUL_RN_RM, // MUL Rn, Rm - Multiply two registers (Rn = Rn * Rm)
|
||||
MUL_RN_IMM, // MUL Rn, Imm - Multiply register by immediate (Rn = Rn * Imm)
|
||||
|
||||
DIV_RN_RM, // DIV Rn, Rm - Divide one register by another (Rn = Rn / Rm)
|
||||
DIV_RN_IMM, // DIV Rn, Imm - Divide register by immediate (Rn = Rn / Imm)
|
||||
|
||||
MOD_RN_RM, // MOD Rn, Rm - Compute remainder of division (Rn = Rn % Rm)
|
||||
MOD_RN_IMM, // MOD Rn, Imm - Compute remainder using immediate (Rn = Rn % Imm)
|
||||
|
||||
NEG_RN, // NEG Rn - Negate register value (Rn = -Rn)
|
||||
|
||||
AND_RN_RM, // AND Rn, Rm - Bitwise AND two registers (Rn = Rn & Rm)
|
||||
AND_RN_IMM, // AND Rn, Imm - Bitwise AND register with immediate (Rn = Rn & Imm)
|
||||
|
||||
OR_RN_RM, // OR Rn, Rm - Bitwise OR two registers (Rn = Rn | Rm)
|
||||
OR_RN_IMM, // OR Rn, Imm - Bitwise OR register with immediate (Rn = Rn | Imm)
|
||||
|
||||
XOR_RN_RM, // XOR Rn, Rm - Bitwise XOR two registers (Rn = Rn ^ Rm)
|
||||
XOR_RN_IMM, // XOR Rn, Imm - Bitwise XOR register with immediate (Rn = Rn ^ Imm)
|
||||
|
||||
NOT_RN, // NOT Rn - Bitwise NOT (Rn = ~Rn)
|
||||
|
||||
SHL_RN_IMM, // SHL Rn, Imm - Logical shift left (Rn = Rn << Imm)
|
||||
|
||||
SHR_RN_IMM, // SHR Rn, Imm - Logical shift right (Rn = Rn >> Imm)
|
||||
|
||||
SAR_RN_IMM, // SAR Rn, Imm - Arithmetic shift right (Rn = Rn >> Imm with sign extension)
|
||||
|
||||
JMP, // JMP Addr - Jump to address (PC = Addr)
|
||||
|
||||
JMP_REL, // JMP Offset - relative jump (offset is signed)
|
||||
|
||||
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
|
||||
|
||||
JG, // JG Addr - Jump if greater (if greater flag set, PC = Addr)
|
||||
|
||||
JL, // JL Addr - Jump if less (if less flag set, PC = Addr)
|
||||
|
||||
JGE, // JGE Addr - Jump if greater or equal (if greater or zero flag set, PC = Addr)
|
||||
|
||||
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)
|
||||
|
||||
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])
|
||||
} Opcode;
|
||||
|
||||
#endif //RISCB_CORE_H
|
62
cpu/memory.c
Normal file
62
cpu/memory.c
Normal file
@@ -0,0 +1,62 @@
|
||||
//
|
||||
// Created by bruno on 2.2.2025.
|
||||
//
|
||||
|
||||
#include "memory.h"
|
||||
|
||||
uint8_t write_mem(CPU *cpu, uint32_t addr, uint8_t value) {
|
||||
if (addr >= MEM_SIZE) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
switch (addr) {
|
||||
|
||||
default:
|
||||
cpu->memory[addr] = value;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t read_mem(CPU *cpu, uint32_t addr) {
|
||||
if (addr >= MEM_SIZE) {
|
||||
return 0;
|
||||
}
|
||||
switch (addr) {
|
||||
|
||||
default:
|
||||
return cpu->memory[addr];
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t read_mem16(CPU *cpu, uint32_t addr) {
|
||||
return read_mem(cpu, addr) | (read_mem(cpu, addr + 1) << 8);
|
||||
}
|
||||
|
||||
uint32_t read_mem32(CPU *cpu, uint32_t addr) {
|
||||
return read_mem16(cpu, addr) | (read_mem16(cpu, addr + 2) << 16);
|
||||
}
|
||||
|
||||
uint8_t write_mem16(CPU *cpu, uint32_t addr, uint16_t value) {
|
||||
uint8_t status = write_mem(cpu, addr, value & 0xFF);
|
||||
if (status) {
|
||||
return status;
|
||||
}
|
||||
status = write_mem(cpu, addr + 1, (value >> 8) & 0xFF);
|
||||
if (status) {
|
||||
return status;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t write_mem32(CPU *cpu, uint32_t addr, uint32_t value) {
|
||||
uint8_t status = write_mem16(cpu, addr, value & 0xFFFF);
|
||||
if (status) {
|
||||
return status;
|
||||
}
|
||||
status = write_mem16(cpu, addr + 2, (value >> 16) & 0xFFFF);
|
||||
if (status) {
|
||||
return status;
|
||||
}
|
||||
return 0;
|
||||
}
|
24
cpu/memory.h
Normal file
24
cpu/memory.h
Normal file
@@ -0,0 +1,24 @@
|
||||
//
|
||||
// Created by bruno on 2.2.2025.
|
||||
//
|
||||
|
||||
#ifndef RISCB_MEMORY_H
|
||||
#define RISCB_MEMORY_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include "../cpu/core.h"
|
||||
|
||||
uint8_t write_mem32(CPU *cpu, uint32_t addr, uint32_t value);
|
||||
|
||||
uint8_t write_mem16(CPU *cpu, uint32_t addr, uint16_t value);
|
||||
|
||||
uint32_t read_mem32(CPU *cpu, uint32_t addr);
|
||||
|
||||
uint16_t read_mem16(CPU *cpu, uint32_t addr);
|
||||
|
||||
uint8_t read_mem(CPU *cpu, uint32_t addr);
|
||||
|
||||
uint8_t write_mem(CPU *cpu, uint32_t addr, uint8_t value);
|
||||
|
||||
|
||||
#endif //RISCB_MEMORY_H
|
Reference in New Issue
Block a user