Do some stuff
This commit is contained in:
@@ -52,6 +52,10 @@ set(SOURCE_FILES
|
|||||||
peripherals/audio.h
|
peripherals/audio.h
|
||||||
peripherals/peripheraldata.c
|
peripherals/peripheraldata.c
|
||||||
peripherals/peripheraldata.h
|
peripherals/peripheraldata.h
|
||||||
|
peripherals/sevenseg.c
|
||||||
|
peripherals/sevenseg.h
|
||||||
|
peripherals/switches.c
|
||||||
|
peripherals/switches.h
|
||||||
)
|
)
|
||||||
|
|
||||||
# Build the target executable
|
# Build the target executable
|
||||||
|
42
cpu/core.c
42
cpu/core.c
@@ -7,9 +7,10 @@
|
|||||||
#include "string.h"
|
#include "string.h"
|
||||||
|
|
||||||
// Initialize CPU
|
// Initialize CPU
|
||||||
void init_cpu(CPU *cpu) {
|
void init_cpu(CPU *cpu, SDL_Renderer *renderer) {
|
||||||
memset(cpu, 0, sizeof(CPU));
|
memset(cpu, 0, sizeof(CPU));
|
||||||
cpu->mode = CPU_MODE_HALTED | CPU_MODE_SECOND;
|
cpu->mode = CPU_MODE_HALTED | CPU_MODE_SECOND;
|
||||||
|
cpu->renderer = renderer;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper function for setting flags in the CPU (here we assume bit0 is the Zero flag,
|
// Helper function for setting flags in the CPU (here we assume bit0 is the Zero flag,
|
||||||
@@ -41,15 +42,15 @@ void step(CPU *cpu) {
|
|||||||
oldPC = cpu->pc;
|
oldPC = cpu->pc;
|
||||||
newPC = oldPC;
|
newPC = oldPC;
|
||||||
|
|
||||||
uint8_t opcode = read_mem(cpu, cpu->pc++);
|
|
||||||
|
|
||||||
|
|
||||||
const uint32_t differenceAlignment = oldPC % CPU_INSTRUCTION_SIZE;
|
const uint32_t differenceAlignment = oldPC % CPU_INSTRUCTION_SIZE;
|
||||||
|
|
||||||
if (differenceAlignment) {
|
if (differenceAlignment) {
|
||||||
cpu->pc += differenceAlignment;
|
cpu->pc += differenceAlignment;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint8_t opcode = read_mem(cpu, cpu->pc++);
|
||||||
|
|
||||||
|
|
||||||
switch (opcode) {
|
switch (opcode) {
|
||||||
case NOP:
|
case NOP:
|
||||||
//Don't do anything
|
//Don't do anything
|
||||||
@@ -386,7 +387,7 @@ void step(CPU *cpu) {
|
|||||||
}
|
}
|
||||||
temp |= (1 << bit);
|
temp |= (1 << bit);
|
||||||
write_reg(cpu, reg1, temp);
|
write_reg(cpu, reg1, temp);
|
||||||
cpu->pc += CPU_INSTRUCTION_SIZE;
|
//cpu->pc += CPU_INSTRUCTION_SIZE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -402,9 +403,10 @@ void step(CPU *cpu) {
|
|||||||
if (bit > 7) {
|
if (bit > 7) {
|
||||||
bit = 7;
|
bit = 7;
|
||||||
}
|
}
|
||||||
|
|
||||||
temp &= ~(1 << bit);
|
temp &= ~(1 << bit);
|
||||||
write_reg(cpu, reg1, temp);
|
write_reg(cpu, reg1, temp);
|
||||||
cpu->pc += CPU_INSTRUCTION_SIZE;
|
//cpu->pc += CPU_INSTRUCTION_SIZE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -425,7 +427,8 @@ void step(CPU *cpu) {
|
|||||||
cpu->pc = newPC;
|
cpu->pc = newPC;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
cpu->pc += CPU_INSTRUCTION_SIZE;
|
//cpu->pc += CPU_INSTRUCTION_SIZE;
|
||||||
|
cpu->pc -= 2;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -439,7 +442,7 @@ void step(CPU *cpu) {
|
|||||||
}
|
}
|
||||||
temp |= (1 << bit);
|
temp |= (1 << bit);
|
||||||
write_mem(cpu, addrTemp, temp);
|
write_mem(cpu, addrTemp, temp);
|
||||||
cpu->pc += CPU_INSTRUCTION_SIZE;
|
//cpu->pc += CPU_INSTRUCTION_SIZE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -454,7 +457,7 @@ void step(CPU *cpu) {
|
|||||||
}
|
}
|
||||||
temp &= ~(1 << bit);
|
temp &= ~(1 << bit);
|
||||||
write_mem(cpu, addrTemp, temp);
|
write_mem(cpu, addrTemp, temp);
|
||||||
cpu->pc += CPU_INSTRUCTION_SIZE;
|
//cpu->pc += CPU_INSTRUCTION_SIZE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -470,7 +473,8 @@ void step(CPU *cpu) {
|
|||||||
cpu->pc = newPC;
|
cpu->pc = newPC;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
cpu->pc += CPU_INSTRUCTION_SIZE;
|
//cpu->pc += CPU_INSTRUCTION_SIZE;
|
||||||
|
cpu->pc -= 2;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -482,7 +486,7 @@ void step(CPU *cpu) {
|
|||||||
cpu->pc = newPC;
|
cpu->pc = newPC;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
cpu->pc += CPU_INSTRUCTION_SIZE;
|
//cpu->pc += CPU_INSTRUCTION_SIZE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -499,7 +503,8 @@ void step(CPU *cpu) {
|
|||||||
cpu->pc = newPC;
|
cpu->pc = newPC;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
cpu->pc += CPU_INSTRUCTION_SIZE;
|
//cpu->pc += CPU_INSTRUCTION_SIZE;
|
||||||
|
cpu->pc -= 2;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -515,7 +520,8 @@ void step(CPU *cpu) {
|
|||||||
cpu->pc = newPC;
|
cpu->pc = newPC;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
cpu->pc += CPU_INSTRUCTION_SIZE;
|
//cpu->pc += CPU_INSTRUCTION_SIZE;
|
||||||
|
cpu->pc -= 2;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -526,7 +532,7 @@ void step(CPU *cpu) {
|
|||||||
cpu->pc = newPC;
|
cpu->pc = newPC;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
cpu->pc += CPU_INSTRUCTION_SIZE;
|
//cpu->pc += CPU_INSTRUCTION_SIZE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -537,7 +543,7 @@ void step(CPU *cpu) {
|
|||||||
cpu->pc = newPC;
|
cpu->pc = newPC;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
cpu->pc += CPU_INSTRUCTION_SIZE;
|
//cpu->pc += CPU_INSTRUCTION_SIZE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -548,7 +554,7 @@ void step(CPU *cpu) {
|
|||||||
cpu->pc = newPC;
|
cpu->pc = newPC;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
cpu->pc += CPU_INSTRUCTION_SIZE;
|
//cpu->pc += CPU_INSTRUCTION_SIZE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -559,7 +565,7 @@ void step(CPU *cpu) {
|
|||||||
cpu->pc = newPC;
|
cpu->pc = newPC;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
cpu->pc += CPU_INSTRUCTION_SIZE;
|
//cpu->pc += CPU_INSTRUCTION_SIZE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -570,7 +576,7 @@ void step(CPU *cpu) {
|
|||||||
cpu->pc = newPC;
|
cpu->pc = newPC;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
cpu->pc += CPU_INSTRUCTION_SIZE;
|
//cpu->pc += CPU_INSTRUCTION_SIZE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -6,9 +6,10 @@
|
|||||||
#define RISCB_CORE_H
|
#define RISCB_CORE_H
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <SDL_render.h>
|
||||||
#include "stdio.h"
|
#include "stdio.h"
|
||||||
|
|
||||||
#define MEM_SIZE 65535
|
#define MEM_SIZE 2097120
|
||||||
// Register count (register names R0 to R7)
|
// Register count (register names R0 to R7)
|
||||||
#define REG_COUNT 64
|
#define REG_COUNT 64
|
||||||
#define STACK_SIZE 255
|
#define STACK_SIZE 255
|
||||||
@@ -39,11 +40,12 @@ typedef struct {
|
|||||||
uint32_t programEnd;
|
uint32_t programEnd;
|
||||||
uint8_t mode;
|
uint8_t mode;
|
||||||
uint32_t cycle;
|
uint32_t cycle;
|
||||||
|
SDL_Renderer *renderer;
|
||||||
} CPU;
|
} CPU;
|
||||||
|
|
||||||
void step(CPU *cpu);
|
void step(CPU *cpu);
|
||||||
|
|
||||||
void init_cpu(CPU *cpu);
|
void init_cpu(CPU *cpu, SDL_Renderer *renderer);
|
||||||
|
|
||||||
// Helper function for setting flags in the CPU (here we assume bit0 is the Zero flag,
|
// Helper function for setting flags in the CPU (here we assume bit0 is the Zero flag,
|
||||||
// and bit1 is the Negative flag).
|
// and bit1 is the Negative flag).
|
||||||
|
93
cpu/memory.c
93
cpu/memory.c
@@ -6,6 +6,12 @@
|
|||||||
|
|
||||||
#define SFR_OFFSET (0xDF00)
|
#define SFR_OFFSET (0xDF00)
|
||||||
|
|
||||||
|
#define GPU_OFFSET (0xEF00)
|
||||||
|
|
||||||
|
#define GPU_SIZE (160 * 160)
|
||||||
|
|
||||||
|
#define GPU_END (GPU_OFFSET + GPU_SIZE)
|
||||||
|
|
||||||
uint8_t write_mem(CPU *cpu, uint32_t addr, uint8_t value) {
|
uint8_t write_mem(CPU *cpu, uint32_t addr, uint8_t value) {
|
||||||
if (addr >= MEM_SIZE) {
|
if (addr >= MEM_SIZE) {
|
||||||
return 1;
|
return 1;
|
||||||
@@ -15,47 +21,110 @@ uint8_t write_mem(CPU *cpu, uint32_t addr, uint8_t value) {
|
|||||||
|
|
||||||
case SFR_OFFSET + 0x00:
|
case SFR_OFFSET + 0x00:
|
||||||
pcm_buffer_push(&audioData.pcmVoice, value << 8 | cpu->memory[SFR_OFFSET + 0x01]);
|
pcm_buffer_push(&audioData.pcmVoice, value << 8 | cpu->memory[SFR_OFFSET + 0x01]);
|
||||||
|
break;
|
||||||
|
|
||||||
case SFR_OFFSET + 0x02:
|
case SFR_OFFSET + 0x02:
|
||||||
audioData.synthVoices[0].volume = value;
|
audioData.synthVoices[0].volume = value;
|
||||||
|
break;
|
||||||
|
|
||||||
case SFR_OFFSET + 0x03:
|
case SFR_OFFSET + 0x03:
|
||||||
audioData.synthVoices[0].waveform = value;
|
audioData.synthVoices[0].waveform = value;
|
||||||
|
break;
|
||||||
|
|
||||||
case SFR_OFFSET + 0x04:
|
case SFR_OFFSET + 0x04:
|
||||||
audioData.synthVoices[0].phase = value;
|
audioData.synthVoices[0].phase = value;
|
||||||
|
break;
|
||||||
|
|
||||||
case SFR_OFFSET + 0x05:
|
case SFR_OFFSET + 0x05:
|
||||||
audioData.synthVoices[0].frequency = value << 8 | cpu->memory[SFR_OFFSET + 0x06];
|
audioData.synthVoices[0].frequency = value << 8 | cpu->memory[SFR_OFFSET + 0x06];
|
||||||
|
break;
|
||||||
|
|
||||||
case SFR_OFFSET + 0x07:
|
case SFR_OFFSET + 0x07:
|
||||||
audioData.synthVoices[1].volume = value;
|
audioData.synthVoices[1].volume = value;
|
||||||
|
break;
|
||||||
|
|
||||||
case SFR_OFFSET + 0x08:
|
case SFR_OFFSET + 0x08:
|
||||||
audioData.synthVoices[1].waveform = value;
|
audioData.synthVoices[1].waveform = value;
|
||||||
|
break;
|
||||||
|
|
||||||
case SFR_OFFSET + 0x09:
|
case SFR_OFFSET + 0x09:
|
||||||
audioData.synthVoices[1].phase = value;
|
audioData.synthVoices[1].phase = value;
|
||||||
|
break;
|
||||||
|
|
||||||
case SFR_OFFSET + 0x0A:
|
case SFR_OFFSET + 0x0A:
|
||||||
audioData.synthVoices[1].frequency = value << 8 | cpu->memory[SFR_OFFSET + 0x0B];
|
audioData.synthVoices[1].frequency = value << 8 | cpu->memory[SFR_OFFSET + 0x0B];
|
||||||
|
break;
|
||||||
|
|
||||||
case SFR_OFFSET + 0x0C:
|
case SFR_OFFSET + 0x0C:
|
||||||
audioData.synthVoices[2].volume = value;
|
audioData.synthVoices[2].volume = value;
|
||||||
|
break;
|
||||||
|
|
||||||
case SFR_OFFSET + 0x0D:
|
case SFR_OFFSET + 0x0D:
|
||||||
audioData.synthVoices[2].waveform = value;
|
audioData.synthVoices[2].waveform = value;
|
||||||
|
break;
|
||||||
|
|
||||||
case SFR_OFFSET + 0x0E:
|
case SFR_OFFSET + 0x0E:
|
||||||
audioData.synthVoices[2].phase = value;
|
audioData.synthVoices[2].phase = value;
|
||||||
|
break;
|
||||||
|
|
||||||
case SFR_OFFSET + 0x0F:
|
case SFR_OFFSET + 0x0F:
|
||||||
audioData.synthVoices[2].frequency = value << 8 | cpu->memory[SFR_OFFSET + 0x10];
|
audioData.synthVoices[2].frequency = value << 8 | cpu->memory[SFR_OFFSET + 0x10];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SFR_OFFSET + 0x12:
|
||||||
|
displayA.value = value;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SFR_OFFSET + 0x13:
|
||||||
|
displayB.value = value;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SFR_OFFSET + 0x14:
|
||||||
|
displayC.value = value;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SFR_OFFSET + 0x15:
|
||||||
|
displayD.value = value;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SFR_OFFSET + 0x16:
|
||||||
|
displayE.value = value;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SFR_OFFSET + 0x17:
|
||||||
|
displayF.value = value;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SFR_OFFSET + 0x18:
|
||||||
|
displayG.value = value;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SFR_OFFSET + 0x19:
|
||||||
|
displayH.value = value;
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (addr >= GPU_OFFSET && addr < GPU_END) {
|
||||||
|
const int index = addr - GPU_OFFSET;
|
||||||
|
int x = index % 160;
|
||||||
|
int y = index / 160;
|
||||||
|
|
||||||
|
// Proper color scaling from 3-bit and 2-bit channels
|
||||||
|
Uint8 r = ((value & 0xE0) >> 5) * 36; // 0–7 mapped to 0–255
|
||||||
|
Uint8 g = ((value & 0x1C) >> 2) * 36;
|
||||||
|
Uint8 b = ((value & 0x03)) * 85; // 0–3 mapped to 0–255
|
||||||
|
|
||||||
|
// Ensure texture format matches RGBA8888
|
||||||
|
Uint32 color = (255 << 24) | (r << 16) | (g << 8) | b;
|
||||||
|
|
||||||
|
Uint32 *pixels = (Uint32 *) gpuSurf->pixels;
|
||||||
|
pixels[(y * gpuSurf->w) + x] = color;
|
||||||
|
gpuSurfDirty = true;
|
||||||
|
}
|
||||||
|
|
||||||
cpu->memory[addr] = value;
|
cpu->memory[addr] = value;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -66,6 +135,30 @@ uint8_t read_mem(CPU *cpu, uint32_t addr) {
|
|||||||
}
|
}
|
||||||
switch (addr) {
|
switch (addr) {
|
||||||
|
|
||||||
|
case SFR_OFFSET + 0x20:
|
||||||
|
return (switchesA.value >> 8) & 0xFF;
|
||||||
|
|
||||||
|
case SFR_OFFSET + 0x21:
|
||||||
|
return switchesA.value & 0xFF;
|
||||||
|
|
||||||
|
case SFR_OFFSET + 0x22:
|
||||||
|
return (switchesB.value >> 8) & 0xFF;
|
||||||
|
|
||||||
|
case SFR_OFFSET + 0x23:
|
||||||
|
return switchesB.value & 0xFF;
|
||||||
|
|
||||||
|
case SFR_OFFSET + 0x24:
|
||||||
|
return (switchesC.value >> 8) & 0xFF;
|
||||||
|
|
||||||
|
case SFR_OFFSET + 0x25:
|
||||||
|
return switchesC.value & 0xFF;
|
||||||
|
|
||||||
|
case SFR_OFFSET + 0x26:
|
||||||
|
return (switchesD.value >> 8) & 0xFF;
|
||||||
|
|
||||||
|
case SFR_OFFSET + 0x27:
|
||||||
|
return switchesD.value & 0xFF;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return cpu->memory[addr];
|
return cpu->memory[addr];
|
||||||
}
|
}
|
||||||
|
3
docs/examples/disptest.bsm
Normal file
3
docs/examples/disptest.bsm
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
MOV 0XFF R1
|
||||||
|
MOV R1 [0XDF12]
|
||||||
|
HLT
|
@@ -1,53 +0,0 @@
|
|||||||
; Test Program using all opcodes
|
|
||||||
|
|
||||||
START:
|
|
||||||
NOP ; No operation (does nothing, advances to the next instruction)
|
|
||||||
MOV R1, 0x10 ; Move immediate value 0x10 to register R1
|
|
||||||
MOV R2, R1 ; Move value from R1 to R2
|
|
||||||
MOV [0x2000], R3 ; Load value from memory address 0x2000 into R3
|
|
||||||
MOV R1, [0x2000] ; Store R1 value to memory address 0x2000
|
|
||||||
SWAP R1, R2 ; Swap values between R1 and R2
|
|
||||||
SWAPN R1 ; Swap nibbles within R1
|
|
||||||
ADD R1, R2 ; Add R2 to R1
|
|
||||||
ADD R1, 0x10 ; Add immediate 0x10 to R1
|
|
||||||
SUB R1, R2 ; Subtract R2 from R1
|
|
||||||
SUB R1, 0x10 ; Subtract immediate 0x10 from R1
|
|
||||||
MUL R1, R2 ; Multiply R1 by R2
|
|
||||||
MUL R1, 0x10 ; Multiply R1 by immediate 0x10
|
|
||||||
DIV R1, R2 ; Divide R1 by R2
|
|
||||||
DIV R1, 0x10 ; Divide R1 by immediate 0x10
|
|
||||||
MOD R1, R2 ; Compute remainder of R1 / R2
|
|
||||||
MOD R1, 0x10 ; Compute remainder of R1 / 0x10
|
|
||||||
NEG R1 ; Negate R1
|
|
||||||
AND R1, R2 ; Bitwise AND of R1 and R2
|
|
||||||
AND R1, 0x10 ; Bitwise AND R1 with immediate 0x10
|
|
||||||
OR R1, R2 ; Bitwise OR of R1 and R2
|
|
||||||
OR R1, 0x10 ; Bitwise OR R1 with immediate 0x10
|
|
||||||
XOR R1, R2 ; Bitwise XOR of R1 and R2
|
|
||||||
XOR R1, 0x10 ; Bitwise XOR R1 with immediate 0x10
|
|
||||||
NOT R1 ; Bitwise NOT of R1
|
|
||||||
SHL R1, 2 ; Logical shift left R1 by 2 bits
|
|
||||||
SHR R1, 2 ; Logical shift right R1 by 2 bits
|
|
||||||
SAR R1, 2 ; Arithmetic shift right R1 by 2 bits (sign extended)
|
|
||||||
JMP 0x3000 ; Jump to address 0x3000
|
|
||||||
JMP +5 ; Jump 5 bytes forward
|
|
||||||
INC R1 ; Increment R1
|
|
||||||
INC [0x2000] ; Increment value at memory address 0x2000
|
|
||||||
DEC R1 ; Decrement R1
|
|
||||||
DEC [0x2000] ; Decrement value at memory address 0x2000
|
|
||||||
CMP R1, R2 ; Compare R1 and R2 (sets flags based on R1 - R2)
|
|
||||||
JE 0x4000 ; Jump to 0x4000 if equal (zero flag set)
|
|
||||||
JNE 0x4000 ; Jump to 0x4000 if not equal (zero flag not set)
|
|
||||||
JG 0x4000 ; Jump to 0x4000 if greater
|
|
||||||
JL 0x4000 ; Jump to 0x4000 if less
|
|
||||||
JGE 0x4000 ; Jump to 0x4000 if greater or equal
|
|
||||||
JLE 0x4000 ; Jump to 0x4000 if less or equal
|
|
||||||
CALL 0x5000 ; Call subroutine at 0x5000
|
|
||||||
RET ; Return from subroutine
|
|
||||||
JMPBC R1, 3, 0x4000 ; Jump to address 0x4000 if bit 3 in register R1 is not set
|
|
||||||
JMPBC 0x2000, 5, 0x5000 ; Jump to address 0x5000 if bit 5 in memory at address 0x2000 is not set
|
|
||||||
JMPBS R2, 1, 0x6000 ; Jump to address 0x6000 if bit 1 in register R2 is set
|
|
||||||
JMPBS 0x3000, 7, 0x7000 ; Jump to address 0x7000 if bit 7 in memory at address 0x3000 is set
|
|
||||||
|
|
||||||
; Halt the program
|
|
||||||
HLT
|
|
3
docs/examples/gputst.bsm
Normal file
3
docs/examples/gputst.bsm
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
MOV 255 R1
|
||||||
|
MOV R1 [0XEF00]
|
||||||
|
HLT
|
3
docs/examples/inctest.bsm
Normal file
3
docs/examples/inctest.bsm
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
LP:
|
||||||
|
INC R0
|
||||||
|
JMP LP
|
18
docs/examples/peritest.bsm
Normal file
18
docs/examples/peritest.bsm
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
LP:
|
||||||
|
MOV [0XDF20] R0
|
||||||
|
MOV [0XDF21] R1
|
||||||
|
MOV [0XDF22] R2
|
||||||
|
MOV [0XDF23] R3
|
||||||
|
MOV [0XDF24] R4
|
||||||
|
MOV [0XDF25] R5
|
||||||
|
MOV [0XDF26] R6
|
||||||
|
MOV [0XDF27] R7
|
||||||
|
MOV R0 [0XDF02]
|
||||||
|
MOV R1 [0XDF03]
|
||||||
|
MOV R2 [0XDF04]
|
||||||
|
MOV R3 [0XDF05]
|
||||||
|
MOV R4 [0XDF06]
|
||||||
|
MOV R5 [0XDF12]
|
||||||
|
MOV R6 [0XDF13]
|
||||||
|
MOV R7 [0XDF14]
|
||||||
|
JMP LP
|
10
docs/examples/snd.bsm
Normal file
10
docs/examples/snd.bsm
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
MOV 255 R1
|
||||||
|
MOV R1 [0XDF02]
|
||||||
|
MOV 0 R1
|
||||||
|
MOV R1 [0XDF03]
|
||||||
|
MOV R1 [0XDF04]
|
||||||
|
MOV 0X03 R1
|
||||||
|
MOV R1 [0XDF06]
|
||||||
|
MOV 0XE8 R1
|
||||||
|
MOV R1 [0XDF05]
|
||||||
|
HLT
|
@@ -12,19 +12,19 @@
|
|||||||
|
|
||||||
### **MOV_IMM_RN**
|
### **MOV_IMM_RN**
|
||||||
|
|
||||||
`MOV R1, 0x10` - Move immediate value `0x10` to register `R1`
|
`MOV 0x10, R1` - Move immediate value `0x10` to register `R1`
|
||||||
|
|
||||||
### **MOV_RN_RM**
|
### **MOV_RN_RM**
|
||||||
|
|
||||||
`MOV R2, R1` - Move value from `R1` to `R2`
|
`MOV R1, R2` - Move value from `R1` to `R2`
|
||||||
|
|
||||||
### **MOV_RN_ADDR**
|
### **MOV_RN_ADDR**
|
||||||
|
|
||||||
`MOV R3, [0x2000]` - Load value from memory address `0x2000` into `R3`
|
`MOV [0x2000], R3` - Load value from memory address `0x2000` into `R3`
|
||||||
|
|
||||||
### **MOV_ADDR_RN**
|
### **MOV_ADDR_RN**
|
||||||
|
|
||||||
`MOV [0x2000], R1` - Store `R1` value to memory address `0x2000`
|
`MOV R1, [0x2000]` - Store `R1` value to memory address `0x2000`
|
||||||
|
|
||||||
### **SWAP**
|
### **SWAP**
|
||||||
|
|
||||||
@@ -198,53 +198,14 @@
|
|||||||
|
|
||||||
`BITS [0x2000], 3` - Set bit `3` in memory at address `0x2000`
|
`BITS [0x2000], 3` - Set bit `3` in memory at address `0x2000`
|
||||||
|
|
||||||
- Reads a memory address as an argument.
|
|
||||||
- Reads a bit index from the next byte.
|
|
||||||
- Ensures the bit index is between `0-7`.
|
|
||||||
- Sets the specified bit in the memory address.
|
|
||||||
- Increments the program counter.
|
|
||||||
|
|
||||||
### **BITC_ADDR**
|
### **BITC_ADDR**
|
||||||
|
|
||||||
`BITC [0x2000], 5` - Clear bit `5` in memory at address `0x2000`
|
`BITC [0x2000], 5` - Clear bit `5` in memory at address `0x2000`
|
||||||
|
|
||||||
- Reads a memory address as an argument.
|
|
||||||
- Reads a bit index from the next byte.
|
|
||||||
- Ensures the bit index is between `0-7`.
|
|
||||||
- Clears the specified bit in the memory address.
|
|
||||||
- Increments the program counter.
|
|
||||||
|
|
||||||
### **BITS_RN**
|
### **BITS_RN**
|
||||||
|
|
||||||
`BITS R1, 2` - Set bit `2` in register `R1`
|
`BITS R1, 2` - Set bit `2` in register `R1`
|
||||||
|
|
||||||
- Reads a register number.
|
|
||||||
- Reads a bit index from the next byte.
|
|
||||||
- Ensures the register is valid (`0 - REG_COUNT - 1`).
|
|
||||||
- Ensures the bit index is between `0-7`.
|
|
||||||
- Sets the specified bit in the register.
|
|
||||||
- Increments the program counter.
|
|
||||||
|
|
||||||
### **BITC_RN**
|
### **BITC_RN**
|
||||||
|
|
||||||
`BITC R2, 6` - Clear bit `6` in register `R2`
|
`BITC R2, 6` - Clear bit `6` in register `R2`
|
||||||
|
|
||||||
- Reads a register number.
|
|
||||||
- Reads a bit index from the next byte.
|
|
||||||
- Ensures the register is valid (`0 - REG_COUNT - 1`).
|
|
||||||
- Ensures the bit index is between `0-7`.
|
|
||||||
- Clears the specified bit in the register.
|
|
||||||
- Increments the program counter.
|
|
||||||
|
|
||||||
### **BITS (Special Instruction)**
|
|
||||||
|
|
||||||
- This mnemonic decides between `BITS_RN` and `BITS_ADDR` based on the operand.
|
|
||||||
- If the operand is a register, `BITS_RN` is used.
|
|
||||||
- If the operand is a memory address, `BITS_ADDR` is used.
|
|
||||||
|
|
||||||
### **BITC (Special Instruction)**
|
|
||||||
|
|
||||||
- This mnemonic decides between `BITC_RN` and `BITC_ADDR` based on the operand.
|
|
||||||
- If the operand is a register, `BITC_RN` is used.
|
|
||||||
- If the operand is a memory address, `BITC_ADDR` is used.
|
|
||||||
|
|
||||||
|
53
docs/memory.md
Normal file
53
docs/memory.md
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
# Memory Map Documentation
|
||||||
|
|
||||||
|
#### PCM Buffer
|
||||||
|
|
||||||
|
| Function | Address |
|
||||||
|
|----------------------------------|----------|
|
||||||
|
| **PCM Voice Buffer (High Byte)** | `0xDF00` |
|
||||||
|
| **PCM Voice Buffer (Low Byte)** | `0xDF01` |
|
||||||
|
|
||||||
|
If you want to write to both, write low byte first
|
||||||
|
|
||||||
|
#### Voice Generators
|
||||||
|
|
||||||
|
| Voice | Volume | Waveform | Phase | Frequency (High Byte, write last) | Frequency (Low Byte) |
|
||||||
|
|-------------|----------|----------|----------|-----------------------------------|----------------------|
|
||||||
|
| **Voice 0** | `0xDF02` | `0xDF03` | `0xDF04` | `0xDF05` | `0xDF06` |
|
||||||
|
| **Voice 1** | `0xDF07` | `0xDF08` | `0xDF09` | `0xDF0A` | `0xDF0B` |
|
||||||
|
| **Voice 2** | `0xDF0C` | `0xDF0D` | `0xDF0E` | `0xDF0F` | `0xDF10` |
|
||||||
|
|
||||||
|
#### Display Controls
|
||||||
|
|
||||||
|
| Display | Address |
|
||||||
|
|---------------|----------|
|
||||||
|
| **Display A** | `0xDF12` |
|
||||||
|
| **Display B** | `0xDF13` |
|
||||||
|
| **Display C** | `0xDF14` |
|
||||||
|
| **Display D** | `0xDF15` |
|
||||||
|
| **Display E** | `0xDF16` |
|
||||||
|
| **Display F** | `0xDF17` |
|
||||||
|
| **Display G** | `0xDF18` |
|
||||||
|
| **Display H** | `0xDF19` |
|
||||||
|
|
||||||
|
#### Switch Inputs
|
||||||
|
|
||||||
|
| Switch Bank | First 2 rows Address | Last 2 rows Address |
|
||||||
|
|----------------|----------------------|---------------------|
|
||||||
|
| **Switches A** | `0xDF20` | `0xDF21` |
|
||||||
|
| **Switches B** | `0xDF22` | `0xDF23` |
|
||||||
|
| **Switches C** | `0xDF24` | `0xDF25` |
|
||||||
|
| **Switches D** | `0xDF26` | `0xDF27` |
|
||||||
|
|
||||||
|
### GPU Memory
|
||||||
|
|
||||||
|
- **Base Address:** `0xEF00`
|
||||||
|
- **Size:** `160 × 160` pixels
|
||||||
|
- **End Address:** `0xEF00 + (160 × 160) = GPU_END`
|
||||||
|
- **Color Encoding:**
|
||||||
|
- Red: Bits `[7:5]` scaled (0-7 → 0-255)
|
||||||
|
- Green: Bits `[4:2]` scaled (0-7 → 0-255)
|
||||||
|
- Blue: Bits `[1:0]` scaled (0-3 → 0-255)
|
||||||
|
- Pixels are stored in a texture-compatible `RGBA8888` format.
|
||||||
|
|
||||||
|
## Memory Operations
|
131
main.c
131
main.c
@@ -61,29 +61,11 @@ void msleep(unsigned int milliseconds) {
|
|||||||
|
|
||||||
void *cpu_loop(void *arg) {
|
void *cpu_loop(void *arg) {
|
||||||
uint64_t last_tick = SDL_GetTicks64();
|
uint64_t last_tick = SDL_GetTicks64();
|
||||||
uint64_t last_speed_check = last_tick;;
|
|
||||||
uint64_t step_count = 0;
|
|
||||||
struct timespec start, end, sleep_time;
|
|
||||||
while (running) {
|
while (running) {
|
||||||
pthread_mutex_lock(&cpu_mutex);
|
pthread_mutex_lock(&cpu_mutex);
|
||||||
|
|
||||||
if (!(cpu.mode & (CPU_MODE_PAUSED | CPU_MODE_HALTED | CPU_MODE_ERROR))) {
|
if (!(cpu.mode & (CPU_MODE_PAUSED | CPU_MODE_HALTED | CPU_MODE_ERROR))) {
|
||||||
clock_gettime(CLOCK_MONOTONIC, &start); // Get start time
|
|
||||||
step(&cpu);
|
step(&cpu);
|
||||||
clock_gettime(CLOCK_MONOTONIC, &end); // Get end time
|
|
||||||
// Compute step duration in nanoseconds
|
|
||||||
uint64_t step_duration_ns = (end.tv_sec - start.tv_sec) * 1000000000ULL +
|
|
||||||
(end.tv_nsec - start.tv_nsec);
|
|
||||||
|
|
||||||
// Compute remaining time to maintain 64 kHz
|
|
||||||
if (step_duration_ns < TARGET_CYCLE_TIME_NS) {
|
|
||||||
uint64_t remaining_ns = TARGET_CYCLE_TIME_NS - step_duration_ns;
|
|
||||||
sleep_time.tv_sec = 0;
|
|
||||||
sleep_time.tv_nsec = remaining_ns;
|
|
||||||
clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &sleep_time, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
step_count++;
|
|
||||||
} else {
|
} else {
|
||||||
pthread_mutex_unlock(&cpu_mutex);
|
pthread_mutex_unlock(&cpu_mutex);
|
||||||
msleep(10);
|
msleep(10);
|
||||||
@@ -102,13 +84,6 @@ void *cpu_loop(void *arg) {
|
|||||||
}
|
}
|
||||||
last_tick = SDL_GetTicks64();
|
last_tick = SDL_GetTicks64();
|
||||||
}
|
}
|
||||||
// Print speed every second
|
|
||||||
uint64_t now = SDL_GetTicks64();
|
|
||||||
if (now - last_speed_check >= 1000) {
|
|
||||||
printf("CPU Max Speed: %lu Hz\n", step_count);
|
|
||||||
step_count = 0;
|
|
||||||
last_speed_check = now;
|
|
||||||
}
|
|
||||||
pthread_mutex_unlock(&cpu_mutex);
|
pthread_mutex_unlock(&cpu_mutex);
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -189,6 +164,16 @@ int init() {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create OpenGL context
|
||||||
|
SDL_GLContext glContext = SDL_GL_CreateContext(window);
|
||||||
|
if (!glContext) {
|
||||||
|
fprintf(stderr, "SDL_GL_CreateContext failed: %s\n", SDL_GetError());
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use OpenGL context
|
||||||
|
SDL_GL_MakeCurrent(window, glContext); // Make sure OpenGL context is current before any OpenGL rendering
|
||||||
|
|
||||||
memset(&audioData, 0, sizeof(AudioData));
|
memset(&audioData, 0, sizeof(AudioData));
|
||||||
|
|
||||||
SDL_AudioSpec spec = {0};
|
SDL_AudioSpec spec = {0};
|
||||||
@@ -207,6 +192,30 @@ int init() {
|
|||||||
|
|
||||||
SDL_PauseAudioDevice(dev, 0);
|
SDL_PauseAudioDevice(dev, 0);
|
||||||
|
|
||||||
|
init_seven_segment(&displayA, renderer, 480, 240, 60, 120);
|
||||||
|
init_seven_segment(&displayB, renderer, 545, 240, 60, 120);
|
||||||
|
init_seven_segment(&displayC, renderer, 610, 240, 60, 120);
|
||||||
|
init_seven_segment(&displayD, renderer, 675, 240, 60, 120);
|
||||||
|
|
||||||
|
init_seven_segment(&displayE, renderer, 480, 375, 60, 120);
|
||||||
|
init_seven_segment(&displayF, renderer, 545, 375, 60, 120);
|
||||||
|
init_seven_segment(&displayG, renderer, 610, 375, 60, 120);
|
||||||
|
init_seven_segment(&displayH, renderer, 675, 375, 60, 120);
|
||||||
|
|
||||||
|
init_switches(&switchesA, renderer, 500, 500, 100, 100);
|
||||||
|
init_switches(&switchesB, renderer, 625, 500, 100, 100);
|
||||||
|
init_switches(&switchesC, renderer, 500, 610, 100, 100);
|
||||||
|
init_switches(&switchesD, renderer, 625, 610, 100, 100);
|
||||||
|
|
||||||
|
|
||||||
|
gpuSurf = SDL_CreateRGBSurfaceWithFormat(0, 160, 160, 32, SDL_PIXELFORMAT_RGBA8888);
|
||||||
|
gpuTex = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_STREAMING, 160, 160);
|
||||||
|
|
||||||
|
SDL_SetRenderTarget(renderer, gpuTex);
|
||||||
|
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
|
||||||
|
SDL_RenderClear(renderer);
|
||||||
|
SDL_SetRenderTarget(renderer, NULL);
|
||||||
|
|
||||||
SDL_Rect viewport = {0, 0, SCREEN_WIDTH, SCREEN_HEIGHT};
|
SDL_Rect viewport = {0, 0, SCREEN_WIDTH, SCREEN_HEIGHT};
|
||||||
SDL_RenderSetViewport(renderer, &viewport);
|
SDL_RenderSetViewport(renderer, &viewport);
|
||||||
|
|
||||||
@@ -220,7 +229,7 @@ int init() {
|
|||||||
for (int i = 0; i < editorCount; i++) {
|
for (int i = 0; i < editorCount; i++) {
|
||||||
generate_string_display(&codeEditor, renderer);
|
generate_string_display(&codeEditor, renderer);
|
||||||
}
|
}
|
||||||
init_cpu(&cpu);
|
init_cpu(&cpu, renderer);
|
||||||
compile(true);
|
compile(true);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@@ -257,6 +266,37 @@ int render() {
|
|||||||
SDL_RenderCopy(renderer, cpuStateTexture, NULL, &rect2);
|
SDL_RenderCopy(renderer, cpuStateTexture, NULL, &rect2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rect2.x = 530;
|
||||||
|
rect2.y = 50;
|
||||||
|
rect2.w = 0;
|
||||||
|
rect2.h = 0;
|
||||||
|
|
||||||
|
if (gpuSurfDirty) {
|
||||||
|
SDL_UpdateTexture(gpuTex, NULL, gpuSurf->pixels, gpuSurf->pitch);
|
||||||
|
gpuSurfDirty = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gpuTex) {
|
||||||
|
SDL_QueryTexture(gpuTex, NULL, NULL, &rect2.w, &rect2.h);
|
||||||
|
|
||||||
|
SDL_RenderCopy(renderer, gpuTex, NULL, &rect2);
|
||||||
|
}
|
||||||
|
|
||||||
|
render_seven_segment(&displayA, renderer);
|
||||||
|
render_seven_segment(&displayB, renderer);
|
||||||
|
render_seven_segment(&displayC, renderer);
|
||||||
|
render_seven_segment(&displayD, renderer);
|
||||||
|
|
||||||
|
render_seven_segment(&displayE, renderer);
|
||||||
|
render_seven_segment(&displayF, renderer);
|
||||||
|
render_seven_segment(&displayG, renderer);
|
||||||
|
render_seven_segment(&displayH, renderer);
|
||||||
|
|
||||||
|
render_switches_segment(&switchesA, renderer);
|
||||||
|
render_switches_segment(&switchesB, renderer);
|
||||||
|
render_switches_segment(&switchesC, renderer);
|
||||||
|
render_switches_segment(&switchesD, renderer);
|
||||||
|
|
||||||
SDL_RenderPresent(renderer);
|
SDL_RenderPresent(renderer);
|
||||||
frames++;
|
frames++;
|
||||||
if (!(frames % 60)) {
|
if (!(frames % 60)) {
|
||||||
@@ -440,6 +480,17 @@ int processEvent(SDL_Event e) {
|
|||||||
move_cursor(&activeEditor, activeEditor.cursor_line, lineLen, false, renderer);
|
move_cursor(&activeEditor, activeEditor.cursor_line, lineLen, false, renderer);
|
||||||
moved = true;
|
moved = true;
|
||||||
break;
|
break;
|
||||||
|
case SDLK_d:
|
||||||
|
if (keyMod & KMOD_CTRL && !activeEditor.readOnly) {
|
||||||
|
insert_line_rel(&activeEditor, renderer);
|
||||||
|
memset(activeEditor.lines[activeEditor.cursor_line].text, 0, activeEditor.max_line_width);
|
||||||
|
strcpy(activeEditor.lines[activeEditor.cursor_line].text,
|
||||||
|
activeEditor.lines[activeEditor.cursor_line - 1].text);
|
||||||
|
activeEditor.lines[activeEditor.cursor_line].active = 1;
|
||||||
|
move_cursor_relative(&activeEditor, 0, activeEditor.max_line_width, false, renderer);
|
||||||
|
generate_string_display(&activeEditor, renderer);
|
||||||
|
}
|
||||||
|
break;
|
||||||
case SDLK_F9:
|
case SDLK_F9:
|
||||||
cpu.mode ^= CPU_MODE_LOOP;
|
cpu.mode ^= CPU_MODE_LOOP;
|
||||||
updateState(false);
|
updateState(false);
|
||||||
@@ -452,8 +503,9 @@ int processEvent(SDL_Event e) {
|
|||||||
cpu.mode &= ~CPU_MODE_SECOND;
|
cpu.mode &= ~CPU_MODE_SECOND;
|
||||||
cpu.mode |= CPU_MODE_FRAME;
|
cpu.mode |= CPU_MODE_FRAME;
|
||||||
} else if (cpu.mode & CPU_MODE_FRAME) {
|
} else if (cpu.mode & CPU_MODE_FRAME) {
|
||||||
cpu.mode &= ~CPU_MODE_FRAME;
|
//cpu.mode &= ~CPU_MODE_FRAME;
|
||||||
// No specific mode set, defaults to none
|
// No specific mode set, defaults to none
|
||||||
|
cpu.mode |= CPU_MODE_STEP; // Restart cycle
|
||||||
} else {
|
} else {
|
||||||
cpu.mode |= CPU_MODE_STEP; // Restart cycle
|
cpu.mode |= CPU_MODE_STEP; // Restart cycle
|
||||||
}
|
}
|
||||||
@@ -474,6 +526,7 @@ int processEvent(SDL_Event e) {
|
|||||||
if (keyMod & (KMOD_CTRL | KMOD_SHIFT)) {
|
if (keyMod & (KMOD_CTRL | KMOD_SHIFT)) {
|
||||||
cpu.mode |= CPU_MODE_HALTED;
|
cpu.mode |= CPU_MODE_HALTED;
|
||||||
cpu.pc = 0;
|
cpu.pc = 0;
|
||||||
|
init_cpu(&cpu, renderer);
|
||||||
}
|
}
|
||||||
updateState(false);
|
updateState(false);
|
||||||
break;
|
break;
|
||||||
@@ -566,6 +619,15 @@ int processEvent(SDL_Event e) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if (e.type == SDL_MOUSEBUTTONDOWN) {
|
||||||
|
SDL_Rect mouse;
|
||||||
|
mouse.w = 1;
|
||||||
|
mouse.h = 1;
|
||||||
|
SDL_GetMouseState(&mouse.x, &mouse.y);
|
||||||
|
toggle_switch(mouse, &switchesA);
|
||||||
|
toggle_switch(mouse, &switchesB);
|
||||||
|
toggle_switch(mouse, &switchesC);
|
||||||
|
toggle_switch(mouse, &switchesD);
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -630,6 +692,21 @@ int main(__attribute__((unused)) int argc, __attribute__((unused)) char *args[])
|
|||||||
if (cpuStatsTexture) SDL_DestroyTexture(cpuStatsTexture);
|
if (cpuStatsTexture) SDL_DestroyTexture(cpuStatsTexture);
|
||||||
if (cpuStateTexture) SDL_DestroyTexture(cpuStateTexture);
|
if (cpuStateTexture) SDL_DestroyTexture(cpuStateTexture);
|
||||||
|
|
||||||
|
destroy_switches_segment(&switchesA);
|
||||||
|
destroy_switches_segment(&switchesB);
|
||||||
|
destroy_switches_segment(&switchesC);
|
||||||
|
destroy_switches_segment(&switchesD);
|
||||||
|
|
||||||
|
destroy_seven_segment(&displayA);
|
||||||
|
destroy_seven_segment(&displayB);
|
||||||
|
destroy_seven_segment(&displayC);
|
||||||
|
destroy_seven_segment(&displayD);
|
||||||
|
|
||||||
|
destroy_seven_segment(&displayE);
|
||||||
|
destroy_seven_segment(&displayF);
|
||||||
|
destroy_seven_segment(&displayG);
|
||||||
|
destroy_seven_segment(&displayH);
|
||||||
|
|
||||||
pthread_join(cpu_thread, NULL);
|
pthread_join(cpu_thread, NULL);
|
||||||
if (renderer) SDL_DestroyRenderer(renderer);
|
if (renderer) SDL_DestroyRenderer(renderer);
|
||||||
if (window) SDL_DestroyWindow(window);
|
if (window) SDL_DestroyWindow(window);
|
||||||
|
@@ -3,5 +3,37 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#include "peripheraldata.h"
|
#include "peripheraldata.h"
|
||||||
|
#include "sevenseg.h"
|
||||||
|
#include "switches.h"
|
||||||
|
|
||||||
AudioData audioData;
|
AudioData audioData;
|
||||||
|
|
||||||
|
SevenSegment displayA;
|
||||||
|
|
||||||
|
SevenSegment displayB;
|
||||||
|
|
||||||
|
SevenSegment displayC;
|
||||||
|
|
||||||
|
SevenSegment displayD;
|
||||||
|
|
||||||
|
SevenSegment displayE;
|
||||||
|
|
||||||
|
SevenSegment displayF;
|
||||||
|
|
||||||
|
SevenSegment displayG;
|
||||||
|
|
||||||
|
SevenSegment displayH;
|
||||||
|
|
||||||
|
Switches switchesA;
|
||||||
|
|
||||||
|
Switches switchesB;
|
||||||
|
|
||||||
|
Switches switchesC;
|
||||||
|
|
||||||
|
Switches switchesD;
|
||||||
|
|
||||||
|
SDL_Texture *gpuTex;
|
||||||
|
|
||||||
|
SDL_Surface *gpuSurf;
|
||||||
|
|
||||||
|
bool gpuSurfDirty = false;
|
@@ -6,6 +6,39 @@
|
|||||||
#define RISCB_PERIPHERALDATA_H
|
#define RISCB_PERIPHERALDATA_H
|
||||||
|
|
||||||
#include "audio.h"
|
#include "audio.h"
|
||||||
|
#include "sevenseg.h"
|
||||||
|
#include "switches.h"
|
||||||
|
|
||||||
extern AudioData audioData;
|
extern AudioData audioData;
|
||||||
|
|
||||||
|
extern SevenSegment displayA;
|
||||||
|
|
||||||
|
extern SevenSegment displayB;
|
||||||
|
|
||||||
|
extern SevenSegment displayC;
|
||||||
|
|
||||||
|
extern SevenSegment displayD;
|
||||||
|
|
||||||
|
extern SevenSegment displayE;
|
||||||
|
|
||||||
|
extern SevenSegment displayF;
|
||||||
|
|
||||||
|
extern SevenSegment displayG;
|
||||||
|
|
||||||
|
extern SevenSegment displayH;
|
||||||
|
|
||||||
|
extern Switches switchesA;
|
||||||
|
|
||||||
|
extern Switches switchesB;
|
||||||
|
|
||||||
|
extern Switches switchesC;
|
||||||
|
|
||||||
|
extern Switches switchesD;
|
||||||
|
|
||||||
|
extern SDL_Texture *gpuTex;
|
||||||
|
|
||||||
|
extern SDL_Surface *gpuSurf;
|
||||||
|
|
||||||
|
extern bool gpuSurfDirty;
|
||||||
|
|
||||||
#endif //RISCB_PERIPHERALDATA_H
|
#endif //RISCB_PERIPHERALDATA_H
|
||||||
|
84
peripherals/sevenseg.c
Normal file
84
peripherals/sevenseg.c
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
//
|
||||||
|
// Created by bruno on 17.2.2025.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "sevenseg.h"
|
||||||
|
|
||||||
|
#include <SDL2/SDL_render.h>
|
||||||
|
|
||||||
|
void render_segment(SDL_Renderer *renderer, SevenSegment *display) {
|
||||||
|
int seg_width = display->rect->w / 4;
|
||||||
|
int seg_height = display->rect->h / 10;
|
||||||
|
|
||||||
|
// Define segment positions
|
||||||
|
SDL_Rect segments[9] = {
|
||||||
|
{seg_width, display->rect->y, seg_width * 2, seg_height}, // Top
|
||||||
|
{3 * seg_width + 4, seg_height, seg_height, seg_height * 3.5}, // Top Right
|
||||||
|
{3 * seg_width + 4, 5.5 * seg_height, seg_height, seg_height * 3.5}, // Bottom Right
|
||||||
|
{seg_width, 9 * seg_height, seg_width * 2, seg_height}, // Bottom
|
||||||
|
{display->rect->x, 5.5 * seg_height, seg_height, seg_height * 3.5}, // Bottom Left
|
||||||
|
{display->rect->x, seg_height, seg_height, seg_height * 3.5}, // Top Left
|
||||||
|
{seg_width, 4.5 * seg_height, seg_width * 2, seg_height}, // Middle
|
||||||
|
};
|
||||||
|
|
||||||
|
if (display->value & (1 << 7)) {
|
||||||
|
SDL_SetRenderDrawColor(renderer, 0, 64, 64, 255);
|
||||||
|
} else {
|
||||||
|
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_RenderClear(renderer);
|
||||||
|
SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255);
|
||||||
|
for (int i = 0; i < 7; i++) {
|
||||||
|
if (display->value & (1 << i)) {
|
||||||
|
SDL_RenderFillRect(renderer, &segments[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void update_display_texture(SDL_Renderer *renderer, SevenSegment *display) {
|
||||||
|
SDL_SetRenderTarget(renderer, display->texture);
|
||||||
|
|
||||||
|
render_segment(renderer, display);
|
||||||
|
|
||||||
|
SDL_SetRenderTarget(renderer, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void init_seven_segment(SevenSegment *display, SDL_Renderer *renderer, int x, int y, int width, int height) {
|
||||||
|
display->rect = malloc(sizeof(SDL_Rect));
|
||||||
|
display->outRect = malloc(sizeof(SDL_Rect));
|
||||||
|
display->value = 0;
|
||||||
|
|
||||||
|
display->rect->x = 0;
|
||||||
|
display->rect->y = 0;
|
||||||
|
display->rect->w = width;
|
||||||
|
display->rect->h = height;
|
||||||
|
|
||||||
|
display->outRect->x = x;
|
||||||
|
display->outRect->y = y;
|
||||||
|
display->outRect->w = width;
|
||||||
|
display->outRect->h = height;
|
||||||
|
|
||||||
|
display->texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, width, height);
|
||||||
|
if (!display->texture) {
|
||||||
|
fprintf(stderr, "Failed to create texture: %s\n", SDL_GetError());
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
update_display_texture(renderer, display);
|
||||||
|
}
|
||||||
|
|
||||||
|
void render_seven_segment(SevenSegment *display, SDL_Renderer *renderer) {
|
||||||
|
if (display->oldValue != display->value) {
|
||||||
|
display->oldValue = display->value;
|
||||||
|
update_display_texture(renderer, display);
|
||||||
|
}
|
||||||
|
if (display->texture) {
|
||||||
|
SDL_RenderCopy(renderer, display->texture, NULL, display->outRect);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void destroy_seven_segment(SevenSegment *display) {
|
||||||
|
SDL_DestroyTexture(display->texture);
|
||||||
|
free(display->rect);
|
||||||
|
free(display->outRect);
|
||||||
|
}
|
34
peripherals/sevenseg.h
Normal file
34
peripherals/sevenseg.h
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
//
|
||||||
|
// Created by bruno on 17.2.2025.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef RISCB_SEVENSEG_H
|
||||||
|
#define RISCB_SEVENSEG_H
|
||||||
|
|
||||||
|
#include <SDL_rect.h>
|
||||||
|
#include <SDL2/SDL_render.h>
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
unsigned char value;
|
||||||
|
unsigned char oldValue;
|
||||||
|
SDL_Rect *rect;
|
||||||
|
SDL_Rect *outRect;
|
||||||
|
SDL_Texture *texture;
|
||||||
|
} SevenSegment;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Created by bruno on 17.2.2025.
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
void render_segment(SDL_Renderer *renderer, SevenSegment *display);
|
||||||
|
|
||||||
|
void update_display_texture(SDL_Renderer *renderer, SevenSegment *display);
|
||||||
|
|
||||||
|
void init_seven_segment(SevenSegment *display, SDL_Renderer *renderer, int x, int y, int width, int height);
|
||||||
|
|
||||||
|
void render_seven_segment(SevenSegment *display, SDL_Renderer *renderer);
|
||||||
|
|
||||||
|
void destroy_seven_segment(SevenSegment *display);
|
||||||
|
|
||||||
|
#endif //RISCB_SEVENSEG_H
|
105
peripherals/switches.c
Normal file
105
peripherals/switches.c
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
//
|
||||||
|
// Created by bruno on 17.2.2025.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "switches.h"
|
||||||
|
|
||||||
|
void generate_switch_rects(Switches *switches) {
|
||||||
|
int switch_width = switches->rect->w / 4;
|
||||||
|
int switch_height = switches->rect->h / 4;
|
||||||
|
|
||||||
|
for (int row = 0; row < 4; row++) {
|
||||||
|
for (int col = 0; col < 4; col++) {
|
||||||
|
int idx = row * 4 + col;
|
||||||
|
|
||||||
|
// Base rect inside switches->rect
|
||||||
|
switches->rects[idx] = (SDL_Rect) {
|
||||||
|
col * switch_width + 2,
|
||||||
|
row * switch_height + 2,
|
||||||
|
switch_width - 2,
|
||||||
|
switch_height - 2
|
||||||
|
};
|
||||||
|
|
||||||
|
// Rect relative to outRect
|
||||||
|
switches->outRects[idx] = (SDL_Rect) {
|
||||||
|
switches->outRect->x + col * switch_width + 2,
|
||||||
|
switches->outRect->y + row * switch_height + 2,
|
||||||
|
switch_width - 2,
|
||||||
|
switch_height - 2
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void render_switch_matrix(SDL_Renderer *renderer, Switches *switches) {
|
||||||
|
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
|
||||||
|
SDL_RenderClear(renderer);
|
||||||
|
|
||||||
|
for (int i = 0; i < 16; i++) {
|
||||||
|
if (switches->value & (1 << i)) {
|
||||||
|
SDL_SetRenderDrawColor(renderer, 0, 255, 0, 255);
|
||||||
|
} else {
|
||||||
|
// Render black for "off" switches
|
||||||
|
SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255);
|
||||||
|
}
|
||||||
|
SDL_RenderFillRect(renderer, &switches->rects[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void toggle_switch(SDL_Rect rect, Switches *switches) {
|
||||||
|
for (int i = 0; i < 16; i++) {
|
||||||
|
if (SDL_HasIntersection(&rect, &switches->outRects[i])) {
|
||||||
|
switches->value ^= (1 << i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void update_switches_texture(SDL_Renderer *renderer, Switches *display) {
|
||||||
|
SDL_SetRenderTarget(renderer, display->texture);
|
||||||
|
|
||||||
|
render_switch_matrix(renderer, display); // Render the 4x4 switch matrix
|
||||||
|
|
||||||
|
SDL_SetRenderTarget(renderer, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void init_switches(Switches *switches, SDL_Renderer *renderer, int x, int y, int width, int height) {
|
||||||
|
switches->rect = malloc(sizeof(SDL_Rect));
|
||||||
|
switches->outRect = malloc(sizeof(SDL_Rect));
|
||||||
|
switches->value = 0;
|
||||||
|
|
||||||
|
switches->rect->x = 0;
|
||||||
|
switches->rect->y = 0;
|
||||||
|
switches->rect->w = width;
|
||||||
|
switches->rect->h = height;
|
||||||
|
|
||||||
|
switches->outRect->x = x;
|
||||||
|
switches->outRect->y = y;
|
||||||
|
switches->outRect->w = width;
|
||||||
|
switches->outRect->h = height;
|
||||||
|
|
||||||
|
switches->texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, width, height);
|
||||||
|
if (!switches->texture) {
|
||||||
|
fprintf(stderr, "Failed to create texture: %s\n", SDL_GetError());
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
switches->value = (1 << 0) | (1 << 1);
|
||||||
|
generate_switch_rects(switches);
|
||||||
|
update_switches_texture(renderer, switches);
|
||||||
|
}
|
||||||
|
|
||||||
|
void render_switches_segment(Switches *display, SDL_Renderer *renderer) {
|
||||||
|
if (display->oldValue != display->value) {
|
||||||
|
display->oldValue = display->value;
|
||||||
|
update_switches_texture(renderer, display);
|
||||||
|
}
|
||||||
|
if (display->texture) {
|
||||||
|
SDL_RenderCopy(renderer, display->texture, NULL, display->outRect);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void destroy_switches_segment(Switches *switches) {
|
||||||
|
SDL_DestroyTexture(switches->texture);
|
||||||
|
free(switches->rect);
|
||||||
|
free(switches->outRect);
|
||||||
|
}
|
33
peripherals/switches.h
Normal file
33
peripherals/switches.h
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
//
|
||||||
|
// Created by bruno on 17.2.2025.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef RISCB_SWITCHES_H
|
||||||
|
#define RISCB_SWITCHES_H
|
||||||
|
|
||||||
|
#include <SDL_rect.h>
|
||||||
|
#include <SDL_render.h>
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint16_t value;
|
||||||
|
uint16_t oldValue;
|
||||||
|
SDL_Rect *rect;
|
||||||
|
SDL_Rect *outRect;
|
||||||
|
SDL_Texture *texture;
|
||||||
|
SDL_Rect rects[16];
|
||||||
|
SDL_Rect outRects[16];
|
||||||
|
} Switches;
|
||||||
|
|
||||||
|
void render_switch_matrix(SDL_Renderer *renderer, Switches *switches);
|
||||||
|
|
||||||
|
void update_switches_texture(SDL_Renderer *renderer, Switches *display);
|
||||||
|
|
||||||
|
void toggle_switch(SDL_Rect rect, Switches *switches);
|
||||||
|
|
||||||
|
void init_switches(Switches *switches, SDL_Renderer *renderer, int x, int y, int width, int height);
|
||||||
|
|
||||||
|
void render_switches_segment(Switches *display, SDL_Renderer *renderer);
|
||||||
|
|
||||||
|
void destroy_switches_segment(Switches *switches);
|
||||||
|
|
||||||
|
#endif //RISCB_SWITCHES_H
|
@@ -121,7 +121,7 @@ void renderState(CPU *cpu, BitmapFont *titleFont, SDL_Renderer *renderer, SDL_Te
|
|||||||
} else if (cpu->mode & CPU_MODE_HALTED) {
|
} else if (cpu->mode & CPU_MODE_HALTED) {
|
||||||
strcat(valueStr, "HLT ");
|
strcat(valueStr, "HLT ");
|
||||||
} else if (cpu->mode & CPU_MODE_PAUSED) {
|
} else if (cpu->mode & CPU_MODE_PAUSED) {
|
||||||
strcat(valueStr, "PS ");
|
strcat(valueStr, "PAU ");
|
||||||
} else {
|
} else {
|
||||||
strcat(valueStr, "RUN ");
|
strcat(valueStr, "RUN ");
|
||||||
}
|
}
|
||||||
|
@@ -371,13 +371,11 @@ void generate_string(TextEditor *editor) {
|
|||||||
|
|
||||||
for (int i = 0; i < editor->maxLines; i++) {
|
for (int i = 0; i < editor->maxLines; i++) {
|
||||||
if (editor->lines[i].active) {
|
if (editor->lines[i].active) {
|
||||||
if (strlen(editor->lines[i].text)) {
|
|
||||||
strcat(editor->outputString, editor->lines[i].text);
|
strcat(editor->outputString, editor->lines[i].text);
|
||||||
strcat(editor->outputString, "\n");
|
strcat(editor->outputString, "\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void fill_editor_from_string(TextEditor *editor, const char *content, int lineStart, bool isComplete,
|
void fill_editor_from_string(TextEditor *editor, const char *content, int lineStart, bool isComplete,
|
||||||
SDL_Renderer *renderer) {
|
SDL_Renderer *renderer) {
|
||||||
|
Reference in New Issue
Block a user