289 lines
7.2 KiB
C
289 lines
7.2 KiB
C
//
|
||
// Created by bruno on 2.2.2025.
|
||
//
|
||
|
||
#include "memory.h"
|
||
|
||
#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;
|
||
}
|
||
|
||
switch (addr) {
|
||
|
||
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;
|
||
}
|
||
|
||
uint8_t read_mem(CPU *cpu, uint32_t addr) {
|
||
if (addr >= MEM_SIZE) {
|
||
return 0;
|
||
}
|
||
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];
|
||
}
|
||
}
|
||
|
||
uint16_t read_mem16(CPU *cpu, uint32_t addr) {
|
||
return read_mem(cpu, addr) | (read_mem(cpu, addr + 1) << 8);
|
||
}
|
||
|
||
uint32_t read_mem32(CPU *cpu, uint32_t addr) {
|
||
return read_mem16(cpu, addr) | (read_mem16(cpu, addr + 2) << 16);
|
||
}
|
||
|
||
uint32_t read_mem24(CPU *cpu, uint32_t addr) {
|
||
return read_mem16(cpu, addr) | (read_mem(cpu, addr + 2) << 16);
|
||
}
|
||
|
||
uint32_t read_address_argument(CPU *cpu) {
|
||
uint32_t out = read_mem24(cpu, cpu->pc);
|
||
cpu->pc += 3;
|
||
if (out >= MEM_SIZE) {
|
||
out = MEM_SIZE - 1;
|
||
}
|
||
return out;
|
||
}
|
||
|
||
uint8_t read_register_argument(CPU *cpu) {
|
||
uint8_t out = read_mem(cpu, cpu->pc);
|
||
cpu->pc += 1;
|
||
if (out >= REG_COUNT) {
|
||
out = REG_COUNT - 1;
|
||
}
|
||
return out;
|
||
}
|
||
|
||
// Push a 32-bit program counter (PC) onto the stack
|
||
void write_stack(CPU *cpu) {
|
||
if (cpu->pc >= MEM_SIZE) {
|
||
return; // Invalid memory address
|
||
}
|
||
if (cpu->stack_ptr >= STACK_SIZE - 1) {
|
||
return; // Stack overflow protection
|
||
}
|
||
cpu->stack[++cpu->stack_ptr] = cpu->pc;
|
||
for (uint32_t reg = 0; reg < REG_COUNT; reg += 4) {
|
||
uint32_t packed = cpu->regs[reg] |
|
||
((reg + 1 < REG_COUNT) ? (cpu->regs[reg + 1] << 8) : 0) |
|
||
((reg + 2 < REG_COUNT) ? (cpu->regs[reg + 2] << 16) : 0);
|
||
cpu->stack[++cpu->stack_ptr] = packed;
|
||
}
|
||
cpu->stack[++cpu->stack_ptr] = cpu->flags;
|
||
}
|
||
|
||
// Pop a 32-bit program counter (PC) and registers from the stack
|
||
void read_stack(CPU *cpu) {
|
||
if (cpu->stack_ptr == 0) {
|
||
return; // Stack underflow protection
|
||
}
|
||
|
||
// Restore flags
|
||
cpu->flags = cpu->stack[cpu->stack_ptr--];
|
||
|
||
// Restore registers
|
||
for (int32_t reg = REG_COUNT - 1; reg >= 0; reg -= 4) {
|
||
if (cpu->stack_ptr == 0) {
|
||
return; // Stack underflow protection
|
||
}
|
||
uint32_t packed = cpu->stack[cpu->stack_ptr--];
|
||
cpu->regs[reg] = (packed & 0xFF);
|
||
if (reg - 1 >= 0) cpu->regs[reg - 1] = ((packed >> 8) & 0xFF);
|
||
if (reg - 2 >= 0) cpu->regs[reg - 2] = ((packed >> 16) & 0xFF);
|
||
}
|
||
|
||
// Restore PC
|
||
if (cpu->stack_ptr == 0) {
|
||
return; // Stack underflow protection
|
||
}
|
||
cpu->pc = cpu->stack[cpu->stack_ptr--];
|
||
}
|
||
|
||
|
||
uint8_t read_reg_number(CPU *cpu) {
|
||
uint8_t out = read_mem(cpu, cpu->pc++);
|
||
if (out >= REG_COUNT) {
|
||
return 0;
|
||
}
|
||
return out;
|
||
}
|
||
|
||
uint8_t read_reg(CPU *cpu, uint8_t number) {
|
||
if (number >= REG_COUNT) {
|
||
return 0;
|
||
}
|
||
return cpu->regs[number];
|
||
}
|
||
|
||
uint8_t write_reg(CPU *cpu, uint8_t number, uint8_t value) {
|
||
if (number >= REG_COUNT) {
|
||
return 1;
|
||
}
|
||
cpu->regs[number] = value;
|
||
return 0;
|
||
}
|
||
|
||
uint8_t write_mem16(CPU *cpu, uint32_t addr, uint16_t value) {
|
||
uint8_t status = write_mem(cpu, addr, value & 0xFF);
|
||
if (status) {
|
||
return status;
|
||
}
|
||
status = write_mem(cpu, addr + 1, (value >> 8) & 0xFF);
|
||
if (status) {
|
||
return status;
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
uint8_t write_mem32(CPU *cpu, uint32_t addr, uint32_t value) {
|
||
uint8_t status = write_mem16(cpu, addr, value & 0xFFFF);
|
||
if (status) {
|
||
return status;
|
||
}
|
||
status = write_mem16(cpu, addr + 2, (value >> 16) & 0xFFFF);
|
||
if (status) {
|
||
return status;
|
||
}
|
||
return 0;
|
||
}
|