Do some stuff
This commit is contained in:
@@ -52,6 +52,10 @@ set(SOURCE_FILES
|
||||
peripherals/audio.h
|
||||
peripherals/peripheraldata.c
|
||||
peripherals/peripheraldata.h
|
||||
peripherals/sevenseg.c
|
||||
peripherals/sevenseg.h
|
||||
peripherals/switches.c
|
||||
peripherals/switches.h
|
||||
)
|
||||
|
||||
# Build the target executable
|
||||
|
42
cpu/core.c
42
cpu/core.c
@@ -7,9 +7,10 @@
|
||||
#include "string.h"
|
||||
|
||||
// Initialize CPU
|
||||
void init_cpu(CPU *cpu) {
|
||||
void init_cpu(CPU *cpu, SDL_Renderer *renderer) {
|
||||
memset(cpu, 0, sizeof(CPU));
|
||||
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,
|
||||
@@ -41,15 +42,15 @@ void step(CPU *cpu) {
|
||||
oldPC = cpu->pc;
|
||||
newPC = oldPC;
|
||||
|
||||
uint8_t opcode = read_mem(cpu, cpu->pc++);
|
||||
|
||||
|
||||
const uint32_t differenceAlignment = oldPC % CPU_INSTRUCTION_SIZE;
|
||||
|
||||
if (differenceAlignment) {
|
||||
cpu->pc += differenceAlignment;
|
||||
}
|
||||
|
||||
uint8_t opcode = read_mem(cpu, cpu->pc++);
|
||||
|
||||
|
||||
switch (opcode) {
|
||||
case NOP:
|
||||
//Don't do anything
|
||||
@@ -386,7 +387,7 @@ void step(CPU *cpu) {
|
||||
}
|
||||
temp |= (1 << bit);
|
||||
write_reg(cpu, reg1, temp);
|
||||
cpu->pc += CPU_INSTRUCTION_SIZE;
|
||||
//cpu->pc += CPU_INSTRUCTION_SIZE;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -402,9 +403,10 @@ void step(CPU *cpu) {
|
||||
if (bit > 7) {
|
||||
bit = 7;
|
||||
}
|
||||
|
||||
temp &= ~(1 << bit);
|
||||
write_reg(cpu, reg1, temp);
|
||||
cpu->pc += CPU_INSTRUCTION_SIZE;
|
||||
//cpu->pc += CPU_INSTRUCTION_SIZE;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -425,7 +427,8 @@ void step(CPU *cpu) {
|
||||
cpu->pc = newPC;
|
||||
break;
|
||||
}
|
||||
cpu->pc += CPU_INSTRUCTION_SIZE;
|
||||
//cpu->pc += CPU_INSTRUCTION_SIZE;
|
||||
cpu->pc -= 2;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -439,7 +442,7 @@ void step(CPU *cpu) {
|
||||
}
|
||||
temp |= (1 << bit);
|
||||
write_mem(cpu, addrTemp, temp);
|
||||
cpu->pc += CPU_INSTRUCTION_SIZE;
|
||||
//cpu->pc += CPU_INSTRUCTION_SIZE;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -454,7 +457,7 @@ void step(CPU *cpu) {
|
||||
}
|
||||
temp &= ~(1 << bit);
|
||||
write_mem(cpu, addrTemp, temp);
|
||||
cpu->pc += CPU_INSTRUCTION_SIZE;
|
||||
//cpu->pc += CPU_INSTRUCTION_SIZE;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -470,7 +473,8 @@ void step(CPU *cpu) {
|
||||
cpu->pc = newPC;
|
||||
break;
|
||||
}
|
||||
cpu->pc += CPU_INSTRUCTION_SIZE;
|
||||
//cpu->pc += CPU_INSTRUCTION_SIZE;
|
||||
cpu->pc -= 2;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -482,7 +486,7 @@ void step(CPU *cpu) {
|
||||
cpu->pc = newPC;
|
||||
break;
|
||||
}
|
||||
cpu->pc += CPU_INSTRUCTION_SIZE;
|
||||
//cpu->pc += CPU_INSTRUCTION_SIZE;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -499,7 +503,8 @@ void step(CPU *cpu) {
|
||||
cpu->pc = newPC;
|
||||
break;
|
||||
}
|
||||
cpu->pc += CPU_INSTRUCTION_SIZE;
|
||||
//cpu->pc += CPU_INSTRUCTION_SIZE;
|
||||
cpu->pc -= 2;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -515,7 +520,8 @@ void step(CPU *cpu) {
|
||||
cpu->pc = newPC;
|
||||
break;
|
||||
}
|
||||
cpu->pc += CPU_INSTRUCTION_SIZE;
|
||||
//cpu->pc += CPU_INSTRUCTION_SIZE;
|
||||
cpu->pc -= 2;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -526,7 +532,7 @@ void step(CPU *cpu) {
|
||||
cpu->pc = newPC;
|
||||
break;
|
||||
}
|
||||
cpu->pc += CPU_INSTRUCTION_SIZE;
|
||||
//cpu->pc += CPU_INSTRUCTION_SIZE;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -537,7 +543,7 @@ void step(CPU *cpu) {
|
||||
cpu->pc = newPC;
|
||||
break;
|
||||
}
|
||||
cpu->pc += CPU_INSTRUCTION_SIZE;
|
||||
//cpu->pc += CPU_INSTRUCTION_SIZE;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -548,7 +554,7 @@ void step(CPU *cpu) {
|
||||
cpu->pc = newPC;
|
||||
break;
|
||||
}
|
||||
cpu->pc += CPU_INSTRUCTION_SIZE;
|
||||
//cpu->pc += CPU_INSTRUCTION_SIZE;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -559,7 +565,7 @@ void step(CPU *cpu) {
|
||||
cpu->pc = newPC;
|
||||
break;
|
||||
}
|
||||
cpu->pc += CPU_INSTRUCTION_SIZE;
|
||||
//cpu->pc += CPU_INSTRUCTION_SIZE;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -570,7 +576,7 @@ void step(CPU *cpu) {
|
||||
cpu->pc = newPC;
|
||||
break;
|
||||
}
|
||||
cpu->pc += CPU_INSTRUCTION_SIZE;
|
||||
//cpu->pc += CPU_INSTRUCTION_SIZE;
|
||||
break;
|
||||
}
|
||||
|
||||
|
@@ -6,9 +6,10 @@
|
||||
#define RISCB_CORE_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <SDL_render.h>
|
||||
#include "stdio.h"
|
||||
|
||||
#define MEM_SIZE 65535
|
||||
#define MEM_SIZE 2097120
|
||||
// Register count (register names R0 to R7)
|
||||
#define REG_COUNT 64
|
||||
#define STACK_SIZE 255
|
||||
@@ -39,11 +40,12 @@ typedef struct {
|
||||
uint32_t programEnd;
|
||||
uint8_t mode;
|
||||
uint32_t cycle;
|
||||
SDL_Renderer *renderer;
|
||||
} 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,
|
||||
// and bit1 is the Negative flag).
|
||||
|
93
cpu/memory.c
93
cpu/memory.c
@@ -6,6 +6,12 @@
|
||||
|
||||
#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) {
|
||||
if (addr >= MEM_SIZE) {
|
||||
return 1;
|
||||
@@ -15,47 +21,110 @@ uint8_t write_mem(CPU *cpu, uint32_t addr, uint8_t value) {
|
||||
|
||||
case SFR_OFFSET + 0x00:
|
||||
pcm_buffer_push(&audioData.pcmVoice, value << 8 | cpu->memory[SFR_OFFSET + 0x01]);
|
||||
break;
|
||||
|
||||
case SFR_OFFSET + 0x02:
|
||||
audioData.synthVoices[0].volume = value;
|
||||
break;
|
||||
|
||||
case SFR_OFFSET + 0x03:
|
||||
audioData.synthVoices[0].waveform = value;
|
||||
break;
|
||||
|
||||
case SFR_OFFSET + 0x04:
|
||||
audioData.synthVoices[0].phase = value;
|
||||
break;
|
||||
|
||||
case SFR_OFFSET + 0x05:
|
||||
audioData.synthVoices[0].frequency = value << 8 | cpu->memory[SFR_OFFSET + 0x06];
|
||||
break;
|
||||
|
||||
case SFR_OFFSET + 0x07:
|
||||
audioData.synthVoices[1].volume = value;
|
||||
break;
|
||||
|
||||
case SFR_OFFSET + 0x08:
|
||||
audioData.synthVoices[1].waveform = value;
|
||||
break;
|
||||
|
||||
case SFR_OFFSET + 0x09:
|
||||
audioData.synthVoices[1].phase = value;
|
||||
break;
|
||||
|
||||
case SFR_OFFSET + 0x0A:
|
||||
audioData.synthVoices[1].frequency = value << 8 | cpu->memory[SFR_OFFSET + 0x0B];
|
||||
break;
|
||||
|
||||
case SFR_OFFSET + 0x0C:
|
||||
audioData.synthVoices[2].volume = value;
|
||||
break;
|
||||
|
||||
case SFR_OFFSET + 0x0D:
|
||||
audioData.synthVoices[2].waveform = value;
|
||||
break;
|
||||
|
||||
case SFR_OFFSET + 0x0E:
|
||||
audioData.synthVoices[2].phase = value;
|
||||
break;
|
||||
|
||||
case SFR_OFFSET + 0x0F:
|
||||
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:
|
||||
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;
|
||||
return 0;
|
||||
}
|
||||
@@ -66,6 +135,30 @@ uint8_t read_mem(CPU *cpu, uint32_t 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:
|
||||
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 R1, 0x10` - Move immediate value `0x10` to register `R1`
|
||||
`MOV 0x10, R1` - Move immediate value `0x10` to register `R1`
|
||||
|
||||
### **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 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 [0x2000], R1` - Store `R1` value to memory address `0x2000`
|
||||
`MOV R1, [0x2000]` - Store `R1` value to memory address `0x2000`
|
||||
|
||||
### **SWAP**
|
||||
|
||||
@@ -198,53 +198,14 @@
|
||||
|
||||
`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 [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 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 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.
|
||||
|
||||
`BITC R2, 6` - Clear bit `6` in register `R2`
|
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) {
|
||||
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) {
|
||||
pthread_mutex_lock(&cpu_mutex);
|
||||
|
||||
if (!(cpu.mode & (CPU_MODE_PAUSED | CPU_MODE_HALTED | CPU_MODE_ERROR))) {
|
||||
clock_gettime(CLOCK_MONOTONIC, &start); // Get start time
|
||||
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 {
|
||||
pthread_mutex_unlock(&cpu_mutex);
|
||||
msleep(10);
|
||||
@@ -102,13 +84,6 @@ void *cpu_loop(void *arg) {
|
||||
}
|
||||
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);
|
||||
}
|
||||
return NULL;
|
||||
@@ -189,6 +164,16 @@ int init() {
|
||||
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));
|
||||
|
||||
SDL_AudioSpec spec = {0};
|
||||
@@ -207,6 +192,30 @@ int init() {
|
||||
|
||||
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_RenderSetViewport(renderer, &viewport);
|
||||
|
||||
@@ -220,7 +229,7 @@ int init() {
|
||||
for (int i = 0; i < editorCount; i++) {
|
||||
generate_string_display(&codeEditor, renderer);
|
||||
}
|
||||
init_cpu(&cpu);
|
||||
init_cpu(&cpu, renderer);
|
||||
compile(true);
|
||||
|
||||
return 0;
|
||||
@@ -257,6 +266,37 @@ int render() {
|
||||
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);
|
||||
frames++;
|
||||
if (!(frames % 60)) {
|
||||
@@ -440,6 +480,17 @@ int processEvent(SDL_Event e) {
|
||||
move_cursor(&activeEditor, activeEditor.cursor_line, lineLen, false, renderer);
|
||||
moved = true;
|
||||
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:
|
||||
cpu.mode ^= CPU_MODE_LOOP;
|
||||
updateState(false);
|
||||
@@ -452,8 +503,9 @@ int processEvent(SDL_Event e) {
|
||||
cpu.mode &= ~CPU_MODE_SECOND;
|
||||
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
|
||||
cpu.mode |= CPU_MODE_STEP; // Restart cycle
|
||||
} else {
|
||||
cpu.mode |= CPU_MODE_STEP; // Restart cycle
|
||||
}
|
||||
@@ -474,6 +526,7 @@ int processEvent(SDL_Event e) {
|
||||
if (keyMod & (KMOD_CTRL | KMOD_SHIFT)) {
|
||||
cpu.mode |= CPU_MODE_HALTED;
|
||||
cpu.pc = 0;
|
||||
init_cpu(&cpu, renderer);
|
||||
}
|
||||
updateState(false);
|
||||
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;
|
||||
}
|
||||
@@ -630,6 +692,21 @@ int main(__attribute__((unused)) int argc, __attribute__((unused)) char *args[])
|
||||
if (cpuStatsTexture) SDL_DestroyTexture(cpuStatsTexture);
|
||||
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);
|
||||
if (renderer) SDL_DestroyRenderer(renderer);
|
||||
if (window) SDL_DestroyWindow(window);
|
||||
|
@@ -3,5 +3,37 @@
|
||||
//
|
||||
|
||||
#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
|
||||
|
||||
#include "audio.h"
|
||||
#include "sevenseg.h"
|
||||
#include "switches.h"
|
||||
|
||||
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
|
||||
|
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) {
|
||||
strcat(valueStr, "HLT ");
|
||||
} else if (cpu->mode & CPU_MODE_PAUSED) {
|
||||
strcat(valueStr, "PS ");
|
||||
strcat(valueStr, "PAU ");
|
||||
} else {
|
||||
strcat(valueStr, "RUN ");
|
||||
}
|
||||
|
@@ -371,10 +371,8 @@ void generate_string(TextEditor *editor) {
|
||||
|
||||
for (int i = 0; i < editor->maxLines; i++) {
|
||||
if (editor->lines[i].active) {
|
||||
if (strlen(editor->lines[i].text)) {
|
||||
strcat(editor->outputString, editor->lines[i].text);
|
||||
strcat(editor->outputString, "\n");
|
||||
}
|
||||
strcat(editor->outputString, editor->lines[i].text);
|
||||
strcat(editor->outputString, "\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user