From 8f46a76fd4126dfaa2c87d5b60135c612e97edd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bruno=20Ryb=C3=A1rsky?= Date: Tue, 18 Feb 2025 14:44:08 +0100 Subject: [PATCH] Do some stuff --- CMakeLists.txt | 4 ++ cpu/core.c | 42 ++++++----- cpu/core.h | 6 +- cpu/memory.c | 93 +++++++++++++++++++++++++ docs/examples/disptest.bsm | 3 + docs/examples/fulltest.bsm | 53 -------------- docs/examples/gputst.bsm | 3 + docs/examples/inctest.bsm | 3 + docs/examples/peritest.bsm | 18 +++++ docs/examples/snd.bsm | 10 +++ docs/instructions.md | 49 ++----------- docs/memory.md | 53 ++++++++++++++ main.c | 131 +++++++++++++++++++++++++++-------- peripherals/peripheraldata.c | 34 ++++++++- peripherals/peripheraldata.h | 33 +++++++++ peripherals/sevenseg.c | 84 ++++++++++++++++++++++ peripherals/sevenseg.h | 34 +++++++++ peripherals/switches.c | 105 ++++++++++++++++++++++++++++ peripherals/switches.h | 33 +++++++++ util/cpustatusui.c | 2 +- util/texteditor.c | 6 +- 21 files changed, 649 insertions(+), 150 deletions(-) create mode 100644 docs/examples/disptest.bsm delete mode 100644 docs/examples/fulltest.bsm create mode 100644 docs/examples/gputst.bsm create mode 100644 docs/examples/inctest.bsm create mode 100644 docs/examples/peritest.bsm create mode 100644 docs/examples/snd.bsm create mode 100644 docs/memory.md create mode 100644 peripherals/sevenseg.c create mode 100644 peripherals/sevenseg.h create mode 100644 peripherals/switches.c create mode 100644 peripherals/switches.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 38d23a0..5ec838b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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 diff --git a/cpu/core.c b/cpu/core.c index 133ee19..8f87b75 100644 --- a/cpu/core.c +++ b/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; } diff --git a/cpu/core.h b/cpu/core.h index 7e526f4..795d4ae 100644 --- a/cpu/core.h +++ b/cpu/core.h @@ -6,9 +6,10 @@ #define RISCB_CORE_H #include +#include #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). diff --git a/cpu/memory.c b/cpu/memory.c index ec12fcb..dcc92c8 100644 --- a/cpu/memory.c +++ b/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]; } diff --git a/docs/examples/disptest.bsm b/docs/examples/disptest.bsm new file mode 100644 index 0000000..dfed296 --- /dev/null +++ b/docs/examples/disptest.bsm @@ -0,0 +1,3 @@ +MOV 0XFF R1 +MOV R1 [0XDF12] +HLT diff --git a/docs/examples/fulltest.bsm b/docs/examples/fulltest.bsm deleted file mode 100644 index 5f054eb..0000000 --- a/docs/examples/fulltest.bsm +++ /dev/null @@ -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 diff --git a/docs/examples/gputst.bsm b/docs/examples/gputst.bsm new file mode 100644 index 0000000..8c72485 --- /dev/null +++ b/docs/examples/gputst.bsm @@ -0,0 +1,3 @@ +MOV 255 R1 +MOV R1 [0XEF00] +HLT diff --git a/docs/examples/inctest.bsm b/docs/examples/inctest.bsm new file mode 100644 index 0000000..9d02235 --- /dev/null +++ b/docs/examples/inctest.bsm @@ -0,0 +1,3 @@ +LP: +INC R0 +JMP LP diff --git a/docs/examples/peritest.bsm b/docs/examples/peritest.bsm new file mode 100644 index 0000000..e11cfce --- /dev/null +++ b/docs/examples/peritest.bsm @@ -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 diff --git a/docs/examples/snd.bsm b/docs/examples/snd.bsm new file mode 100644 index 0000000..a68dc75 --- /dev/null +++ b/docs/examples/snd.bsm @@ -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 diff --git a/docs/instructions.md b/docs/instructions.md index e1076b4..f466f76 100644 --- a/docs/instructions.md +++ b/docs/instructions.md @@ -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` \ No newline at end of file diff --git a/docs/memory.md b/docs/memory.md new file mode 100644 index 0000000..e051ef7 --- /dev/null +++ b/docs/memory.md @@ -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 \ No newline at end of file diff --git a/main.c b/main.c index b7f0516..30df78d 100644 --- a/main.c +++ b/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); diff --git a/peripherals/peripheraldata.c b/peripherals/peripheraldata.c index 0cc7036..dfe02e8 100644 --- a/peripherals/peripheraldata.c +++ b/peripherals/peripheraldata.c @@ -3,5 +3,37 @@ // #include "peripheraldata.h" +#include "sevenseg.h" +#include "switches.h" -AudioData audioData; \ No newline at end of file +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; \ No newline at end of file diff --git a/peripherals/peripheraldata.h b/peripherals/peripheraldata.h index 5725664..2f3325a 100644 --- a/peripherals/peripheraldata.h +++ b/peripherals/peripheraldata.h @@ -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 diff --git a/peripherals/sevenseg.c b/peripherals/sevenseg.c new file mode 100644 index 0000000..6925559 --- /dev/null +++ b/peripherals/sevenseg.c @@ -0,0 +1,84 @@ +// +// Created by bruno on 17.2.2025. +// + +#include "sevenseg.h" + +#include + +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); +} \ No newline at end of file diff --git a/peripherals/sevenseg.h b/peripherals/sevenseg.h new file mode 100644 index 0000000..5a8e597 --- /dev/null +++ b/peripherals/sevenseg.h @@ -0,0 +1,34 @@ +// +// Created by bruno on 17.2.2025. +// + +#ifndef RISCB_SEVENSEG_H +#define RISCB_SEVENSEG_H + +#include +#include + +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 diff --git a/peripherals/switches.c b/peripherals/switches.c new file mode 100644 index 0000000..5e46b7b --- /dev/null +++ b/peripherals/switches.c @@ -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); +} \ No newline at end of file diff --git a/peripherals/switches.h b/peripherals/switches.h new file mode 100644 index 0000000..70753c5 --- /dev/null +++ b/peripherals/switches.h @@ -0,0 +1,33 @@ +// +// Created by bruno on 17.2.2025. +// + +#ifndef RISCB_SWITCHES_H +#define RISCB_SWITCHES_H + +#include +#include + +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 diff --git a/util/cpustatusui.c b/util/cpustatusui.c index 86eae9c..1319d09 100644 --- a/util/cpustatusui.c +++ b/util/cpustatusui.c @@ -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 "); } diff --git a/util/texteditor.c b/util/texteditor.c index 38b2ca1..4aa1fd4 100644 --- a/util/texteditor.c +++ b/util/texteditor.c @@ -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"); } } }