add auto-generated instructions

This commit is contained in:
kishimisu 2023-11-12 18:35:51 +01:00
parent 019e74c127
commit 364e0a44f2
22 changed files with 11236 additions and 621 deletions

View File

@ -1,8 +1,13 @@
# Casio fx-9860 SH4 emulator
This is a work-in-progress emulator for the Casio fx-9860 SH4 models
It will display the content of the VRAM in the console at the end of the execution.
For now it only emulates 27 instructions and three syscalls. It can run the sample add-in auto-generated by the Casio SDK emulator - if we remove the getkey and infinite loop.
All non-DSP instructions are implemented, except the following ones:
- 'MOVUAL', 'MOVUALP', 'ICBI', 'OCBI',
- 'OCBP', 'OCBWB', 'PREFI', 'SLEEP',
- 'SYNCO', 'SETRC', 'SETRCI',
fx9860-emulator/ contains the source for the emulator
It will display the content of the VRAM in the console at the end of the execution.
scripts/ contains the code for auto-generating the instructions code from the doc

View File

@ -3,7 +3,7 @@
#
# Add source to this project's executable.
add_executable (fx9860-emulator "main.c" "headers/main.h" "headers/instructions/instructions.h" "instructions/instructions.c" "headers/utils.h" "utils.c" "memory.c" "headers/memory.h" "instructions/syscalls.c" "headers/instructions/syscalls.h" "instructions/implementations.c" "headers/instructions/implementations.h" "headers/stb_image.h" "headers/display.h" )
add_executable (fx9860-emulator "main.c" "headers/main.h" "headers/instructions/instructions.h" "instructions/instructions.c" "headers/utils.h" "utils.c" "memory.c" "headers/memory.h" "instructions/syscalls.c" "headers/instructions/syscalls.h" "headers/stb_image.h" "headers/display.h" )
if (CMAKE_VERSION VERSION_GREATER 3.12)
set_property(TARGET fx9860-emulator PROPERTY CXX_STANDARD 20)

View File

@ -1,6 +1,6 @@
#pragma once
#include <stdint.h>
#include "memory.h"
// Screen dimensions
#define SCREEN_WIDTH 128
@ -8,7 +8,11 @@
// VRAM Size & Address
#define VRAM_SIZE (SCREEN_WIDTH * SCREEN_HEIGHT / 8) // 1024 for 128*64 monochrome
#define VRAM_ADDRESS (64 * 1024) // Arbitrary address relative to start of RAM
#define VRAM_ADDRESS (RAM_START + RAM_SIZE) // (64 * 1024) // Arbitrary address relative to start of RAM
//#define VRAM_ADDRESS (64 * 1024) // Arbitrary address relative to start of RAM
#define LCD_SELECT_REGISTER 0xB4000000
#define LCD_DATA_REGISTER 0xB4010000
// Size of characters in ASCII texture
#define ASCII_CHAR_WIDTH 7
@ -28,7 +32,10 @@ typedef struct {
struct display_t {
// Pointer to virtual memory in RAM
uint8_t* vram;
uint8_t vram[VRAM_SIZE];
//uint8_t* vram;
uint8_t lcd_registers; // Unused, but still emulates access to the LCD screen
// Current cursor position
cursor_t cursor;

View File

@ -1,31 +0,0 @@
#pragma once
#include "../main.h"
void ADDI(cpu_t* cpu, uint16_t instruction);
void BF(cpu_t* cpu, uint16_t instruction);
void BRA(cpu_t* cpu, uint16_t instruction);
void BT(cpu_t* cpu, uint16_t instruction);
void BTS(cpu_t* cpu, uint16_t instruction);
void CMPGT(cpu_t* cpu, uint16_t instruction);
void CMPHS(cpu_t* cpu, uint16_t instruction);
void CMPPL(cpu_t* cpu, uint16_t instruction);
void EXTUW(cpu_t* cpu, uint16_t instruction);
void JMP(cpu_t* cpu, uint16_t instruction);
void LDSMPR(cpu_t* cpu, uint16_t instruction);
void MOV(cpu_t* cpu, uint16_t instruction);
void MOVLS(cpu_t* cpu, uint16_t instruction);
void MOVLL(cpu_t* cpu, uint16_t instruction);
void MOVLP(cpu_t* cpu, uint16_t instruction);
void MOVI(cpu_t* cpu, uint16_t instruction);
void MOVLI(cpu_t* cpu, uint16_t instruction);
void MOVWS4(cpu_t* cpu, uint16_t instruction);
void MOVWL4(cpu_t* cpu, uint16_t instruction);
void NOP(cpu_t* cpu, uint16_t instruction);
void RTS(cpu_t* cpu, uint16_t instruction);
void STSMMACH(cpu_t* cpu, uint16_t instruction);
void STSMMACL(cpu_t* cpu, uint16_t instruction);
void STSMPR(cpu_t* cpu, uint16_t instruction);
void SUB(cpu_t* cpu, uint16_t instruction);
void BSR(cpu_t* cpu, uint16_t instruction);
void JSR(cpu_t* cpu, uint16_t instruction);

View File

@ -1,7 +1,164 @@
#pragma once
#include <math.h>
#include "../main.h"
#include "implementations.h"
void (*get_instruction_impl(uint16_t instruction))(cpu_t*, uint16_t);
void (*get_instruction_impl(uint16_t instruction))(cpu_t*, uint16_t);
void ADD(cpu_t* cpu, uint16_t instruction);
void ADDI(cpu_t* cpu, uint16_t instruction);
void ADDC(cpu_t* cpu, uint16_t instruction);
void ADDV(cpu_t* cpu, uint16_t instruction);
void AND(cpu_t* cpu, uint16_t instruction);
void ANDI(cpu_t* cpu, uint16_t instruction);
void ANDM(cpu_t* cpu, uint16_t instruction);
void BF(cpu_t* cpu, uint16_t instruction);
void BFS(cpu_t* cpu, uint16_t instruction);
void BRA(cpu_t* cpu, uint16_t instruction);
void BRAF(cpu_t* cpu, uint16_t instruction);
void BT(cpu_t* cpu, uint16_t instruction);
void BTS(cpu_t* cpu, uint16_t instruction);
void CLRMAC(cpu_t* cpu, uint16_t instruction);
void CLRS(cpu_t* cpu, uint16_t instruction);
void CLRT(cpu_t* cpu, uint16_t instruction);
void CMPEQ(cpu_t* cpu, uint16_t instruction);
void CMPGE(cpu_t* cpu, uint16_t instruction);
void CMPGT(cpu_t* cpu, uint16_t instruction);
void CMPHI(cpu_t* cpu, uint16_t instruction);
void CMPHS(cpu_t* cpu, uint16_t instruction);
void CMPPL(cpu_t* cpu, uint16_t instruction);
void CMPPZ(cpu_t* cpu, uint16_t instruction);
void CMPSTR(cpu_t* cpu, uint16_t instruction);
void CMPIM(cpu_t* cpu, uint16_t instruction);
void DIV0S(cpu_t* cpu, uint16_t instruction);
void DIV0U(cpu_t* cpu, uint16_t instruction);
void DIV1(cpu_t* cpu, uint16_t instruction);
void DMULS(cpu_t* cpu, uint16_t instruction);
void DMULU(cpu_t* cpu, uint16_t instruction);
void DT(cpu_t* cpu, uint16_t instruction);
void EXTSB(cpu_t* cpu, uint16_t instruction);
void EXTSW(cpu_t* cpu, uint16_t instruction);
void EXTUB(cpu_t* cpu, uint16_t instruction);
void EXTUW(cpu_t* cpu, uint16_t instruction);
void JMP(cpu_t* cpu, uint16_t instruction);
void LDCGBR(cpu_t* cpu, uint16_t instruction);
void LDCVBR(cpu_t* cpu, uint16_t instruction);
void LDCSGR(cpu_t* cpu, uint16_t instruction);
void LDCSSR(cpu_t* cpu, uint16_t instruction);
void LDCSPC(cpu_t* cpu, uint16_t instruction);
void LDCDBR(cpu_t* cpu, uint16_t instruction);
void LDCMGBR(cpu_t* cpu, uint16_t instruction);
void LDCMVBR(cpu_t* cpu, uint16_t instruction);
void LDCMSGR(cpu_t* cpu, uint16_t instruction);
void LDCMSSR(cpu_t* cpu, uint16_t instruction);
void LDCMSPC(cpu_t* cpu, uint16_t instruction);
void LDCMDBR(cpu_t* cpu, uint16_t instruction);
void LDSMACH(cpu_t* cpu, uint16_t instruction);
void LDSMACL(cpu_t* cpu, uint16_t instruction);
void LDSPR(cpu_t* cpu, uint16_t instruction);
void LDSMMACH(cpu_t* cpu, uint16_t instruction);
void LDSMMACL(cpu_t* cpu, uint16_t instruction);
void LDSMPR(cpu_t* cpu, uint16_t instruction);
void MACL_(cpu_t* cpu, uint16_t instruction);
void MACW(cpu_t* cpu, uint16_t instruction);
void MOV(cpu_t* cpu, uint16_t instruction);
void MOVBS(cpu_t* cpu, uint16_t instruction);
void MOVWS(cpu_t* cpu, uint16_t instruction);
void MOVLS(cpu_t* cpu, uint16_t instruction);
void MOVBL(cpu_t* cpu, uint16_t instruction);
void MOVWL(cpu_t* cpu, uint16_t instruction);
void MOVLL(cpu_t* cpu, uint16_t instruction);
void MOVBM(cpu_t* cpu, uint16_t instruction);
void MOVWM(cpu_t* cpu, uint16_t instruction);
void MOVLM(cpu_t* cpu, uint16_t instruction);
void MOVBP(cpu_t* cpu, uint16_t instruction);
void MOVWP(cpu_t* cpu, uint16_t instruction);
void MOVLP(cpu_t* cpu, uint16_t instruction);
void MOVBS0(cpu_t* cpu, uint16_t instruction);
void MOVWS0(cpu_t* cpu, uint16_t instruction);
void MOVLS0(cpu_t* cpu, uint16_t instruction);
void MOVBL0(cpu_t* cpu, uint16_t instruction);
void MOVWL0(cpu_t* cpu, uint16_t instruction);
void MOVLL0(cpu_t* cpu, uint16_t instruction);
void MOVI(cpu_t* cpu, uint16_t instruction);
void MOVWI(cpu_t* cpu, uint16_t instruction);
void MOVLI(cpu_t* cpu, uint16_t instruction);
void MOVBLG(cpu_t* cpu, uint16_t instruction);
void MOVWLG(cpu_t* cpu, uint16_t instruction);
void MOVLLG(cpu_t* cpu, uint16_t instruction);
void MOVBSG(cpu_t* cpu, uint16_t instruction);
void MOVWSG(cpu_t* cpu, uint16_t instruction);
void MOVLSG(cpu_t* cpu, uint16_t instruction);
void MOVBS4(cpu_t* cpu, uint16_t instruction);
void MOVWS4(cpu_t* cpu, uint16_t instruction);
void MOVLS4(cpu_t* cpu, uint16_t instruction);
void MOVBL4(cpu_t* cpu, uint16_t instruction);
void MOVWL4(cpu_t* cpu, uint16_t instruction);
void MOVLL4(cpu_t* cpu, uint16_t instruction);
void MOVA(cpu_t* cpu, uint16_t instruction);
void MOVT(cpu_t* cpu, uint16_t instruction);
void MULL(cpu_t* cpu, uint16_t instruction);
void MULS(cpu_t* cpu, uint16_t instruction);
void MULU(cpu_t* cpu, uint16_t instruction);
void NEG(cpu_t* cpu, uint16_t instruction);
void NEGC(cpu_t* cpu, uint16_t instruction);
void NOP(cpu_t* cpu, uint16_t instruction);
void NOT(cpu_t* cpu, uint16_t instruction);
void OR(cpu_t* cpu, uint16_t instruction);
void ORI(cpu_t* cpu, uint16_t instruction);
void ORM(cpu_t* cpu, uint16_t instruction);
void PREF(cpu_t* cpu, uint16_t instruction);
void ROTCL(cpu_t* cpu, uint16_t instruction);
void ROTCR(cpu_t* cpu, uint16_t instruction);
void ROTL(cpu_t* cpu, uint16_t instruction);
void ROTR(cpu_t* cpu, uint16_t instruction);
void RTE(cpu_t* cpu, uint16_t instruction);
void RTS(cpu_t* cpu, uint16_t instruction);
void SETS(cpu_t* cpu, uint16_t instruction);
void SETT(cpu_t* cpu, uint16_t instruction);
void SHAD(cpu_t* cpu, uint16_t instruction);
void SHAL(cpu_t* cpu, uint16_t instruction);
void SHAR(cpu_t* cpu, uint16_t instruction);
void SHLD(cpu_t* cpu, uint16_t instruction);
void SHLL(cpu_t* cpu, uint16_t instruction);
void SHLL2(cpu_t* cpu, uint16_t instruction);
void SHLL8(cpu_t* cpu, uint16_t instruction);
void SHLL16(cpu_t* cpu, uint16_t instruction);
void SHLR(cpu_t* cpu, uint16_t instruction);
void SHLR2(cpu_t* cpu, uint16_t instruction);
void SHLR8(cpu_t* cpu, uint16_t instruction);
void SHLR16(cpu_t* cpu, uint16_t instruction);
void STCGBR(cpu_t* cpu, uint16_t instruction);
void STCVBR(cpu_t* cpu, uint16_t instruction);
void STCSSR(cpu_t* cpu, uint16_t instruction);
void STCSPC(cpu_t* cpu, uint16_t instruction);
void STCSGR(cpu_t* cpu, uint16_t instruction);
void STCDBR(cpu_t* cpu, uint16_t instruction);
void STCMGBR(cpu_t* cpu, uint16_t instruction);
void STCMVBR(cpu_t* cpu, uint16_t instruction);
void STCMSSR(cpu_t* cpu, uint16_t instruction);
void STCMSPC(cpu_t* cpu, uint16_t instruction);
void STCMSGR(cpu_t* cpu, uint16_t instruction);
void STCMDBR(cpu_t* cpu, uint16_t instruction);
void STSMACH(cpu_t* cpu, uint16_t instruction);
void STSMACL(cpu_t* cpu, uint16_t instruction);
void STSPR(cpu_t* cpu, uint16_t instruction);
void STSMMACH(cpu_t* cpu, uint16_t instruction);
void STSMMACL(cpu_t* cpu, uint16_t instruction);
void STSMPR(cpu_t* cpu, uint16_t instruction);
void SUB(cpu_t* cpu, uint16_t instruction);
void SUBC(cpu_t* cpu, uint16_t instruction);
void SUBV(cpu_t* cpu, uint16_t instruction);
void SWAPB(cpu_t* cpu, uint16_t instruction);
void SWAPW(cpu_t* cpu, uint16_t instruction);
void TAS(cpu_t* cpu, uint16_t instruction);
void TST(cpu_t* cpu, uint16_t instruction);
void TSTI(cpu_t* cpu, uint16_t instruction);
void TSTM(cpu_t* cpu, uint16_t instruction);
void XOR(cpu_t* cpu, uint16_t instruction);
void XORI(cpu_t* cpu, uint16_t instruction);
void XORM(cpu_t* cpu, uint16_t instruction);
void XTRCT(cpu_t* cpu, uint16_t instruction);
void BSR(cpu_t* cpu, uint16_t instruction);
void BSRF(cpu_t* cpu, uint16_t instruction);
void JSR(cpu_t* cpu, uint16_t instruction);

View File

@ -4,8 +4,14 @@
void run_syscall(cpu_t* cpu);
void syscall_GetVRAMAddress(cpu_t* cpu);
void syscall_Bdisp_AllClr_DD(cpu_t* cpu);
void syscall_Bdisp_AllClr_VRAM(cpu_t* cpu);
void syscall_Bdisp_AllClr_DDVRAM(cpu_t* cpu);
void syscall_locate(cpu_t* cpu, int x, int y);
void syscall_print(cpu_t* cpu, const unsigned char* str);
void syscall_Locate(cpu_t* cpu, int x, int y);
void syscall_Print(cpu_t* cpu, const unsigned char* str);
void syscall_PrintXY(cpu_t* cpu, int x, int y, const unsigned char* str, int type);
void syscall_GetAppName(cpu_t* cpu, char* dest);
void syscall_Malloc(cpu_t* cpu, uint32_t size);

View File

@ -1,5 +1,5 @@
#pragma once
#pragma warning (disable : 6011 6387)
#pragma warning (disable : 6011 6387 28182)
typedef struct memory_t memory_t;
typedef struct cpu_t cpu_t;
@ -8,6 +8,7 @@ typedef struct display_t display_t;
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include "memory.h"
#include "display.h"
#include "utils.h"
@ -38,6 +39,13 @@ struct cpu_t {
uint32_t mach; // Multiply-accumulate high
uint32_t macl; // Multiply-accumulate low
// To sort
uint32_t vbr; // Vector base register
uint32_t ssr; // Saved status register
uint32_t sgr; // Saved general register
uint32_t spc; // Saved program counter
uint32_t dbr; // Debug base register
// Custom variables
uint8_t isExecutionFinished; // Set to true when PR == PC_PROGRAM_START

View File

@ -15,6 +15,11 @@
#define YRAM_SIZE (8 * 1024)
#define ILRAM_SIZE (4 * 1024)
typedef struct{
uint32_t size;
uint32_t addr;
} malloc_info_t;
// MEMORY
struct memory_t {
uint8_t* rom; // Read-only memory
@ -22,14 +27,18 @@ struct memory_t {
uint8_t ram[RAM_SIZE]; // Random-access memory
uint8_t xram[XRAM_SIZE];
// uint8_t xram[XRAM_SIZE];
uint8_t yram[YRAM_SIZE];
// uint8_t yram[YRAM_SIZE];
uint8_t ilram[ILRAM_SIZE];
// uint8_t ilram[ILRAM_SIZE];
// Malloc
int mallocCount;
malloc_info_t* mallocs;
};
uint8_t* get_memory_for_address(cpu_t* cpu, uint32_t address, uint32_t* mapped, uint8_t* d_mem_type);
uint8_t* get_memory_for_address(cpu_t* cpu, uint32_t address);
uint32_t mem_read(cpu_t* cpu, uint32_t address, uint8_t bytes);

View File

@ -1,8 +1,5 @@
#pragma once
//#include <stdlib.h>
//#include <stdio.h>
//#include <stdint.h>
#include "main.h"
#include <stdarg.h>
@ -15,8 +12,4 @@ void print_binary(uint32_t x, int n);
void loadAsciiTexture(cpu_t* cpu);
void set_status_register_bit(cpu_t* cpu, uint8_t bit, uint8_t value);
uint8_t get_status_register_bit(cpu_t* cpu, uint8_t bit);
void cpu_debug(cpu_t* cpu);

View File

@ -1,363 +0,0 @@
#include "../headers/instructions/implementations.h"
// MOV #imm,Rn - 1110nnnniiiiiiii
void MOVI(cpu_t* cpu, uint16_t instruction) {
uint8_t rn = (instruction >> 8) & 0x0F;
int32_t imm = (int8_t)instruction; // Sign-extend (automatic with int8_t -> int32_t conversion)
printf("run MOVI\n");
cpu->r[rn] = imm;
cpu->pc += 2;
}
// MOV Rm,Rn - 0110nnnnmmmm0011
void MOV(cpu_t* cpu, uint16_t instruction) {
uint8_t rn = (instruction >> 8) & 0x0F;
uint8_t rm = (instruction >> 4) & 0x0F;
printf("run MOV R%01X -> R%01X : 0x%08X\n", rm, rn, cpu->r[rm]);
cpu->r[rn] = cpu->r[rm];
cpu->pc += 2;
}
// MOV.W @(disp*,Rm),R0 - 10000101mmmmdddd
void MOVWL4(cpu_t* cpu, uint16_t instruction) {
uint8_t rm = (instruction >> 4) & 0x0F;
uint32_t disp = instruction & 0x0F;
printf("run MOVWL4 R%X\n", rm);
uint32_t addr = cpu->r[rm] + (disp << 1);
cpu->r[0] = mem_read(cpu, addr, 2);
cpu->pc += 2;
}
// MOV.W R0,@(disp*,Rn) 10000001nnnndddd
void MOVWS4(cpu_t* cpu, uint16_t instruction) {
uint8_t rn = (instruction >> 4) & 0x0F;
uint32_t disp = instruction & 0x0F;
printf("run MOVWS4 R%X\n", rn);
uint32_t addr = cpu->r[rn] + (disp << 1);
mem_write(cpu, addr, cpu->r[0], 2);
cpu->pc += 2;
}
// MOV.L @Rm,Rn - 0110nnnnmmmm0010
void MOVLL(cpu_t* cpu, uint16_t instruction) {
uint8_t rn = (instruction >> 8) & 0x0F;
uint8_t rm = (instruction >> 4) & 0x0F;
printf("run MOVLL R%01X -> R%01X : 0x%08X\n", rm, rn, cpu->r[rm]);
cpu->r[rn] = mem_read(cpu, cpu->r[rm], 4);
cpu->pc += 2;
}
// MOV.L @Rm+, Rn - 0110nnnnmmmm0110
void MOVLP(cpu_t* cpu, uint16_t instruction) {
uint8_t rn = (instruction >> 8) & 0x0F;
uint8_t rm = (instruction >> 4) & 0x0F;
printf("run MOVLP R%01X -> R%01X : 0x%08X\n", rm, rn, cpu->r[rm]);
cpu->r[rn] = mem_read(cpu, cpu->r[rm], 4);
if (rn != rm) cpu->r[rm] += 4;
cpu->pc += 2;
}
// MOV.L @(disp,PC), Rn - 1101nnnndddddddd
void MOVLI(cpu_t* cpu, uint16_t instruction) {
uint8_t rn = (instruction >> 8) & 0x0F;
int8_t disp = instruction & 0xFF;
int32_t addr = (int32_t)(disp << 2) + (cpu->pc & 0xFFFFFFFC) + 4;
printf("run MOVLI R%1X disp:%1X\n", rn, disp);
cpu->r[rn] = mem_read(cpu, addr, 4);
cpu->pc += 2;
}
// MOV.L Rm,@Rn - 0010nnnnmmmm0010
void MOVLS(cpu_t* cpu, uint16_t instruction) {
uint8_t rn = (instruction >> 8) & 0x0F;
uint8_t rm = (instruction >> 4) & 0x0F;
printf("run MOVLS R%01X -> R%01X : 0x%08X\n", rm, rn, cpu->r[rm]);
mem_write(cpu, cpu->r[rn], cpu->r[rm], 4);
cpu->pc += 2;
}
// LDS.L @Rm+,PR - 0100mmmm00100110
void LDSMPR(cpu_t* cpu, uint16_t instruction) {
uint8_t rm = (instruction >> 8) & 0x0F;
printf("run LDSMPR R%01X : 0x%08X\n", rm, cpu->r[rm]);
cpu->pr = mem_read(cpu, cpu->r[rm], 4);
cpu->r[rm] += 4;
cpu->pc += 2;
}
// STS.L MACH,@-Rn - 0100nnnn00000010
void STSMMACH(cpu_t* cpu, uint16_t instruction) {
uint8_t rn = (instruction >> 8) & 0x0F;
printf("run STSMMACH R%01X\n", rn);
critical_error("not tested yet");
cpu->r[rn] -= 4;
mem_write(cpu, cpu->r[rn], cpu->mach, 4);
cpu->pc += 2;
}
// STS.L MACL,@-Rn - 0100nnnn00010010
void STSMMACL(cpu_t* cpu, uint16_t instruction) {
uint8_t rn = (instruction >> 8) & 0x0F;
printf("run STSMMACL R%01X\n", rn);
critical_error("not tested yet");
cpu->r[rn] -= 4;
mem_write(cpu, cpu->r[rn], cpu->macl, 4);
cpu->pc += 2;
}
// STS.L PR,@-Rn - 0100nnnn00100010
void STSMPR(cpu_t* cpu, uint16_t instruction) {
uint8_t rn = (instruction >> 8) & 0x0F;
printf("run STSMPR R%01X set 0x%08X to 0x%08X\n", rn, cpu->r[rn] - 4, cpu->pr);
cpu->r[rn] -= 4;
mem_write(cpu, cpu->r[rn], cpu->pr, 4);
cpu->pc += 2;
}
// ADD #imm, Rn - 0111nnnniiiiiiii
void ADDI(cpu_t* cpu, uint16_t instruction) {
uint8_t rn = (instruction >> 8) & 0x0F;
int32_t imm = (int8_t)instruction; // Sign extension
printf("run ADDI R%01X (0x%08X + 0x%02X = 0x%02X)\n", rn, cpu->r[rn], imm, cpu->r[rn] + imm);
cpu->r[rn] += imm;
cpu->pc += 2;
}
// SUB Rm, Rn - 0011nnnnmmmm1000
void SUB(cpu_t* cpu, uint16_t instruction) {
uint8_t rn = (instruction >> 8) & 0x0F;
uint8_t rm = (instruction >> 4) & 0x0F;
printf("run SUB R%01X (0x%08X - 0x%02X = 0x%02X)\n", rn, cpu->r[rn], cpu->r[rm], cpu->r[rn] - cpu->r[rm]);
cpu->r[rn] -= cpu->r[rm];
cpu->pc += 2;
}
// EXTU.W Rm,Rn - 0110nnnnmmmm1101
void EXTUW(cpu_t* cpu, uint16_t instruction) {
uint8_t n = (instruction >> 8) & 0x0F;
uint8_t m = (instruction >> 4) & 0x0F;
cpu->r[n] = cpu->r[m];
cpu->r[n] &= 0x0000FFFF;
cpu->pc += 2;
}
// CMP/GT Rm,Rn - 0011nnnnmmmm0111
void CMPGT(cpu_t* cpu, uint16_t instruction) {
uint8_t n = (instruction >> 8) & 0x0F;
uint8_t m = (instruction >> 4) & 0x0F;
printf("run CMPGT 0x%X >= 0x%X\n", n, m);
// Check with doc: are (long) necessary??
if (cpu->r[n] > cpu->r[m]) {
set_status_register_bit(cpu, SR_BIT_T, 1);
}
else {
set_status_register_bit(cpu, SR_BIT_T, 0);
}
cpu->pc += 2;
}
// CMP/HS Rm, Rn - 0011nnnnmmmm0010
void CMPHS(cpu_t* cpu, uint16_t instruction) {
uint32_t n = (instruction >> 8) & 0x0F;
uint32_t m = (instruction >> 4) & 0x0F;
printf("run CMPHS 0x%X >= 0x%X\n", n, m);
if (cpu->r[n] >= cpu->r[m]) {
set_status_register_bit(cpu, SR_BIT_T, 1);
}
else {
set_status_register_bit(cpu, SR_BIT_T, 0);
}
cpu->pc += 2;
}
// CMP/PL Rn - 0100nnnn00010101
void CMPPL(cpu_t* cpu, uint16_t instruction) {
uint32_t n = (instruction >> 8) & 0x0F;
printf("run CMPPL 0x%X\n", n);
if (cpu->r[n] > 0) {
set_status_register_bit(cpu, SR_BIT_T, 1);
}
else {
set_status_register_bit(cpu, SR_BIT_T, 1);
}
cpu->pc += 2;
}
// BF label - 10001011dddddddd
void BF(cpu_t* cpu, uint16_t instruction) {
uint32_t disp = (int8_t)instruction; // Sign extension
printf("run BF\n");
if (get_status_register_bit(cpu, SR_BIT_T) == 0) {
cpu->pc += 4 + (disp << 1);
}
else {
cpu->pc += 2;
}
}
// BT label - 10001001dddddddd
void BT(cpu_t* cpu, uint16_t instruction) {
uint32_t disp = (int8_t)instruction; // Sign extension
printf("run BT\n");
if (get_status_register_bit(cpu, SR_BIT_T) == 1) {
cpu->pc += 4 + (disp << 1);
}
else {
cpu->pc += 2;
}
}
// JMP @Rn - 0100nnnn00101011
void JMP(cpu_t* cpu, uint16_t instruction) {
uint8_t rn = (instruction >> 8) & 0x0F;
uint32_t temp = cpu->r[rn];
printf("=== (delayed branch) run JMP\n");
delay_slot(cpu, temp);
printf("=== (delayed branch) jump to: 0x%08X 0x%08X\n", temp, cpu->pc);
}
// BSR label - 1011dddddddddddd
void BSR(cpu_t* cpu, uint16_t instruction) {
uint32_t disp = ((int32_t)instruction << 20) >> 20;// ((instruction & 0x800) == 0) ? (0x00000FFF & instruction) : (0xFFFFF000 | instruction); // Sign extension
uint32_t temp = cpu->pc;
printf("=== (delayed branch) run BSR\n");
delay_slot(cpu, temp);
if (is_32_bit_instruction(cpu, cpu->pc + 2)) {
cpu->pr = cpu->pc + 6;
}
else {
cpu->pr = cpu->pc + 4;
}
cpu->pc += 4 + (disp << 1);
printf("=== (delayed branch) jump to: 0x%08X\n", cpu->pc);
}
// JSR @Rn - 0100nnnn00001011
void JSR(cpu_t* cpu, uint16_t instruction) {
uint8_t rn = (instruction >> 8) & 0x0F;
uint32_t temp = cpu->pc;
//uint32_t r = cpu->r[rn]; // TODO: Is this safe ?
printf("=== (delayed branch) run JSR\n");
delay_slot(cpu, temp);
if (is_32_bit_instruction(cpu, cpu->pc + 2)) {
cpu->pr = cpu->pc + 6;
}
else {
cpu->pr = cpu->pc + 4;
}
cpu->pc = cpu->r[rn]; // = r;
printf("=== (delayed branch) jump to: 0x%08X\n", cpu->pc);
}
// BRA label - 1010dddddddddddd
void BRA(cpu_t* cpu, uint16_t instruction) {
uint32_t disp = ((int32_t)instruction << 20) >> 20;// ((instruction & 0x800) == 0) ? (0x00000FFF & instruction) : (0xFFFFF000 | instruction); // Sign extension
uint32_t temp = cpu->pc;
printf("=== (delayed branch) run BRA\n");
delay_slot(cpu, temp);
cpu->pc += 4 + (disp << 1);
printf("=== (delayed branch) jump from 0x%08X to: 0x%08X - 0x%2X\n", temp, cpu->pc, disp);
}
// RTS - 0000000000001011
void RTS(cpu_t* cpu, uint16_t instruction) {
uint32_t temp = cpu->pr;
printf("=== (delayed branch) run RTS\n");
delay_slot(cpu, temp);
printf("=== (delayed branch) jump from 0x%08X to: 0x%08X\n", temp, cpu->pc);
}
// BT/S label - 10001101dddddddd
void BTS(cpu_t* cpu, uint16_t instruction) {
uint32_t temp;
uint32_t disp = (uint8_t)instruction;
printf("=== (delayed branch) run RTS\n");
if (get_status_register_bit(cpu, SR_BIT_T) == 1) {
temp = cpu->pc + 4 + (disp << 1);
}
else {
temp = cpu->pc + 4;
}
delay_slot(cpu, temp);
printf("=== (delayed branch) jump from 0x%08X to: 0x%08X\n", temp, cpu->pc);
}
// NOP - 0000000000001001
void NOP(cpu_t* cpu, uint16_t instruction) {
// Do nothing
printf("run NOP\n");
cpu->pc += 2;
}

File diff suppressed because it is too large Load Diff

View File

@ -4,36 +4,82 @@
void run_syscall(cpu_t* cpu) {
uint32_t syscall_code = cpu->r[0];
printf("Syscall: 0x%03X 0x%X 0x%X 0x%X 0x%X (Return: 0x%08X)\n", syscall_code, cpu->r[4], cpu->r[5], cpu->r[6], cpu->r[7], cpu->pr);
printf("run_syscall: 0x%03X 0x%X 0x%X 0x%X 0x%X (Return: 0x%08X)\n", syscall_code, cpu->r[4], cpu->r[5], cpu->r[6], cpu->r[7], cpu->pr);
int arg1 = cpu->r[4];
int arg2 = cpu->r[5];
int arg3 = cpu->r[6];
int arg4 = cpu->r[7];
if (syscall_code == 0x144) { // Bdisp_AllClr_DDVRAM
if (syscall_code == 0x135) { // GetVRAMAddress
syscall_GetVRAMAddress(cpu);
}
else if (syscall_code == 0x144) { // Bdisp_AllClr_DDVRAM
syscall_Bdisp_AllClr_DDVRAM(cpu);
}
else if (syscall_code == 0x807) { // locate
syscall_locate(cpu, arg1, arg2);
syscall_Locate(cpu, arg1, arg2);
}
else if (syscall_code == 0x808) { // Print
uint32_t mapped;
uint8_t d;
uint8_t* mem = get_memory_for_address(cpu, arg1, &mapped, &d);
uint8_t* mem = get_memory_for_address(cpu, arg1);
const unsigned char* str = (const unsigned char*)mem;
syscall_Print(cpu, str);
}
else if (syscall_code == 0x9AD) { // PrintXY
uint8_t* mem = get_memory_for_address(cpu, arg3);
const unsigned char* str = (const unsigned char*)mem;
syscall_PrintXY(cpu, arg1, arg2, str, arg4);
}
else if (syscall_code == 0xACD) { // malloc
syscall_Malloc(cpu, arg1);
}
else if (syscall_code == 0x462) { // GetAppName
syscall_GetAppName(cpu, arg1);
}
const unsigned char* str = (const unsigned char*)&mem[mapped];
syscall_print(cpu, str);
}
else if (syscall_code == 0x90F) { // GetKey
critical_error("TODO: Need to implement GetKey syscall!\n");
printf("Syscall not implemented, skipping: GetKey\n");
cpu->isExecutionFinished = 1;
}
// Not needed
else if (syscall_code == 0x24C) { // Keyboard_IsSpecialKeyDown
printf("Syscall not implemented, skipping: Keyboard_IsSpecialKeyDown\n");
cpu->isExecutionFinished = 1;
}
else if (syscall_code == 0x43B) { // Bfile_FindFirst
printf("Syscall not implemented, skipping: Bfile_FindFirst\n");
}
else if (syscall_code == 0x434) { // Bfile_CreateEntry_OS
printf("Syscall not implemented, skipping: Bfile_CreateEntry_OS\n");
}
else if (syscall_code == 0x42C) { // Bfile_OpenFile_OS
printf("Syscall not implemented, skipping: Bfile_OpenFile_OS\n");
}
else if (syscall_code == 0x82B) { // MCSPutVar2
printf("Syscall not implemented, skipping: MCSPutVar2\n");
}
else if (syscall_code == 0x840) { // MCSGetDlen2
printf("Syscall not implemented, skipping: MCSGetDlen2\n");
}
else if (syscall_code == 0x420) { // OS_inner_Sleep
// https://bible.planet-casio.com/simlo/chm/v20/fx_legacy_Sleep.HTM
printf("Syscall not implemented, skipping: OS_inner_Sleep\n");
}
else if (syscall_code == 0x014) { // GlibGetAddinLibInf
printf("Syscall not implemented, skipping: GlibGetAddinLibInf\n");
}
else if (syscall_code == 0x015) { // GlibGetOSVersionInfo
printf("Syscall not implemented, skipping: GlibGetOSVersionInfo\n");
}
else if (syscall_code == 0x494) { // void SetQuitHandler( void (*callback)(void) );
printf("Syscall not implemented, skipping: SetQuitHandler\n");
}
// Can be skipped
else if (syscall_code == 0x013) {} // GlibAddinAplExecutionCheck
else if (syscall_code == 0x3FA) {} // Hmem_SetMMU
else if (syscall_code == 0x494) {} // void SetQuitHandler( void (*callback)(void) );
else {
critical_error("Syscall not implemented: 0x%03X", syscall_code);
printf("Syscall not implemented: 0x%03X\n", syscall_code);
cpu->isExecutionFinished = 1;
}
cpu->pc = cpu->pr;
@ -58,29 +104,58 @@ void syscall_Bdisp_AllClr_DDVRAM(cpu_t* cpu) {
// Sets the position of the display cursor
// x: [1-21], y: [1-8]
void syscall_locate(cpu_t* cpu, int x, int y) {
void syscall_Locate(cpu_t* cpu, int x, int y) {
cpu->disp->cursor.col = x;
cpu->disp->cursor.row = y;
printf("syscall_locate: %d %d\n", x, y);
}
// Draw a character on screen
// pixel_start_x and y represent the top left pixel of the character
void draw_character(cpu_t* cpu, const char c, int pixel_start_x, int pixel_start_y) {
int offset = c - 0x0020;
// Character x,y in ASCII texture (16x6)
int char_x = offset % 16;
int char_y = offset / 16;
// Pixel start x, y in ASCII texture (112x54)
char_x = char_x * ASCII_CHAR_WIDTH;
char_y = char_y * ASCII_CHAR_HEIGHT;
for (int y = 0; y < ASCII_CHAR_HEIGHT; y++) {
for (int x = 0; x < ASCII_CHAR_WIDTH; x++) {
// Current pixel position in ASCII texture
int ascii_x = char_x + x;
int ascii_y = char_y + y;
int ascii_id = ascii_x + ascii_y * 112; // Pixel index
int ascii_bit = cpu->asciiTexture[ascii_id]; // Pixel value
if (ascii_id < 0 || ascii_id > 112 * 54) critical_error("ASCII Texture Access out of bounds: %d %d (%d)", ascii_x, ascii_y, ascii_id);
// Current pixel position on-screen
int vram_x = pixel_start_x + x;
int vram_y = pixel_start_y + y;
int vram_id = (vram_x + vram_y * SCREEN_WIDTH) / 8; // index in VRAM
int vram_bit = 7 - vram_x % 8; // Current bit
if (vram_id < 0 || vram_id > VRAM_SIZE) critical_error("VRAM Access out of bounds: %d %d (%d)", vram_x, vram_y, vram_id);
// Change one single bit in the VRAM
cpu->disp->vram[vram_id] = (cpu->disp->vram[vram_id] & ~(1 << vram_bit)) | (ascii_bit << vram_bit);
}
}
}
// Display a string at the current position of the display cursor
void syscall_print(cpu_t* cpu, const unsigned char* str) {
void syscall_Print(cpu_t* cpu, const unsigned char* str) {
printf("syscall_print: %s\n", str);
for (int i = 0; i < 999; i++) { // TODO: Check if arbitrary value OK
int c = str[i]; // Current character
int i = 0;
while(cpu->disp->cursor.col < 21) {
const char c = str[i++]; // Current character
if (c == 0x00) break; // Line terminator
int offset = c - 0x0020;
// Character x,y in ASCII texture (16x6)
int char_x = offset % 16;
int char_y = offset / 16;
// Pixel start x, y in ASCII texture (112x54)
char_x = char_x * ASCII_CHAR_WIDTH;
char_y = char_y * ASCII_CHAR_HEIGHT;
// Character x,y on screen (21x7)
int screen_x = cpu->disp->cursor.col;
int screen_y = cpu->disp->cursor.row;
@ -88,30 +163,78 @@ void syscall_print(cpu_t* cpu, const unsigned char* str) {
screen_x = screen_x * CHAR_WIDTH + 1;
screen_y = screen_y * CHAR_HEIGHT;
for (int y = 0; y < ASCII_CHAR_HEIGHT; y++) {
for (int x = 0; x < ASCII_CHAR_WIDTH; x++) {
// Current pixel position in ASCII texture
int ascii_x = char_x + x;
int ascii_y = char_y + y;
int ascii_id = ascii_x + ascii_y * 112; // Pixel index
int ascii_bit = cpu->asciiTexture[ascii_id]; // Pixel value
if (ascii_id < 0 || ascii_id > 112 * 54) critical_error("ASCII Texture Access out of bounds: %d %d (%d)", ascii_x, ascii_y, ascii_id);
// Current pixel position on-screen
int vram_x = screen_x + x;
int vram_y = screen_y + y;
int vram_id = (vram_x + vram_y * SCREEN_WIDTH) / 8; // index in VRAM
int vram_bit = vram_x % 8; // Current bit
if (vram_id < 0 || vram_id > VRAM_SIZE) critical_error("VRAM Access out of bounds: %d %d (%d)", vram_x, vram_y, vram_id);
// Change one single bit in the VRAM
cpu->disp->vram[vram_id] = (cpu->disp-> vram[vram_id] & ~(1 << vram_bit)) | (ascii_bit << vram_bit);
}
}
draw_character(cpu, c, screen_x, screen_y);
// Move the cursor the the right
cpu->disp->cursor.col++;
}
}
void syscall_PrintXY(cpu_t* cpu, int x, int y, const unsigned char* str, int type) {
printf("syscall_PrintXY: %d %d %s\n", x, y, str);
int i = 0;
while (x < SCREEN_WIDTH) {
const char c = str[i++]; // Current character
if (c == 0x00) break; // Line terminator
draw_character(cpu, c, x, y);
x += CHAR_WIDTH; // Move the cursor the the right
}
}
#define MALLOC_MEM_LOW RAM_START_MMU_ALIAS + (32 * 1042)
#define MALLOC_MEM_HIGH RAM_START_MMU_ALIAS + RAM_SIZE - (16 * 1024)
#define MALLOC_MARGIN 0x200
// Allocate memory and return the address of the allocated memory in r0
void syscall_Malloc(cpu_t* cpu, uint32_t size) {
memory_t* mem = cpu->mem;
// Initialize with the lowest address
int addr = MALLOC_MEM_LOW;
// If there are mallocs, start at the end of the last malloc
if (mem->mallocCount > 0) {
addr = mem->mallocs[mem->mallocCount - 1].addr +
mem->mallocs[mem->mallocCount - 1].size + MALLOC_MARGIN;
}
// Update malloc manager
mem->mallocCount++;
mem->mallocs = realloc(mem->mallocs, mem->mallocCount * sizeof(malloc_info_t));
if (mem->mallocs == 0) {
critical_error("syscall_malloc(): Could not allocate memory");
}
mem->mallocs[mem->mallocCount - 1] = (malloc_info_t){size, addr};
printf("syscall_malloc %d : 0x%08X\n", mem->mallocCount, addr);
// Return the address of the allocated memory
cpu->r[0] = addr;
}
// https://bible.planet-casio.com/simlo/chm/v20/fx_legacy_AppName.HTM
// Copies the registered name for the running application into the character array dest.
// dest must be able to hold 9 bytes. dest is returned.
void syscall_GetAppName(cpu_t* cpu, char* dest) {
// The app names is stored in 9 bytes
dest = malloc(9 * sizeof(char));
// Copies the app name to the new buffer
memcpy(dest, &cpu->mem->rom[0x20], 9);
// Return the buffer
cpu->r[0] = dest;
printf("syscall_GetAppName %s\n", dest);
}
void syscall_GetVRAMAddress(cpu_t* cpu) {
cpu->r[0] = VRAM_ADDRESS; // &cpu->mem->ram[VRAM_ADDRESS];
//printf("syscall_GetVRAMAddress 0x%08X\n", cpu->r[0]);
}

View File

@ -44,11 +44,11 @@ memory_t* init_memory(uint8_t* g1a_content, uint32_t g1a_size) {
// Initializes the Display component
display_t* init_display(memory_t* memory) {
display_t* disp = calloc(1, sizeof(disp));
display_t* disp = calloc(1, sizeof(display_t));
if(disp == NULL) critical_error("Could not allocate memory for Display");
disp->vram = &memory->ram[VRAM_ADDRESS];
//disp->vram = &memory->ram[VRAM_ADDRESS];
disp->cursor.row = 1;
disp->cursor.col = 1;
@ -97,9 +97,10 @@ void run_next_instruction(cpu_t* cpu) {
// Extract 16bits instruction code
uint16_t instruction = (mem_read_nolog(cpu, address, 1) << 8) | mem_read_nolog(cpu, address + 1, 1);
cpu_debug(cpu);
if (cpu->instruction_count % 1000000 == 0)
cpu_debug(cpu);
// Get a pointer to the function implenting the current instruction
// Get a pointer to the function implementing the current instruction
get_instruction_impl(instruction)
(cpu, instruction); // Actually run the instruction
}
@ -116,21 +117,25 @@ int main() {
loadAsciiTexture(cpu); // (Temporary) load the ASCII font texture
// Execute add-in (up to 1000 instructions for now)
for (int i = 0; i < 1000; i++) {
/// [Main Loop]
/// Execute add-in (up to 20M instructions for now)
for (int i = 0; i < 2e7; i++) {
run_next_instruction(cpu);
cpu->instruction_count++;
if (cpu->isExecutionFinished) break;
}
// (Temporary) Display VRAM
for (int y = 0; y < 64; y++) {
for (int x = 0; x < 16; x++) {
for (int b = 0; b < 8; b++) {
for (int b = 7; b >= 0; b--) {
int id = x + y * 16;
if (id < 0 || id >= VRAM_SIZE) critical_error("error %d", id);
int bit = (disp->vram[id] >> b) & 1;
printf(bit || y == 0 || y == 63 || (x==0 && b==0) || (x==15 && b==7) ? "X" : " ");
printf(bit || y == 0 || y == 63 || (x==0 && b==7) || (x==15 && b==0) ? "X" : " ");
}
}
printf("\n");

View File

@ -1,84 +1,73 @@
#include "headers/memory.h"
// Returns a pointer to the buffer (memory type)
// Returns a pointer to the buffer (memory)
// corresponding to the `address` parameter
// mapped: mapped memory address in buffer
// d_mem_type: (debug only) mapping type
uint8_t* get_memory_for_address(cpu_t* cpu, uint32_t address, uint32_t* mapped, uint8_t* d_mem_type) {
uint8_t* get_memory_for_address(cpu_t* cpu, uint32_t address) {
if (address >= ROM_START && address < ROM_START + cpu->mem->rom_size) {
*mapped = address - ROM_START;
*d_mem_type = 0;
return cpu->mem->rom;
// (ROM) - MMU
return &cpu->mem->rom[address - ROM_START];
}
else if (address >= RAM_START_MMU_ALIAS && address < RAM_START_MMU_ALIAS + RAM_SIZE) {
*mapped = address - RAM_START_MMU_ALIAS;
*d_mem_type = 1;
return cpu->mem->ram;
// (RAM) - MMU
return &cpu->mem->ram[address - RAM_START_MMU_ALIAS];
}
else if (address >= RAM_START && address < RAM_START + RAM_SIZE) {
*mapped = address - RAM_START;
*d_mem_type = 2;
return cpu->mem->ram;
// (RAM) - Physical
return &cpu->mem->ram[address - RAM_START];
}
else if (address >= VRAM_ADDRESS && address < VRAM_ADDRESS + VRAM_SIZE) {
// (VRAM)
return &cpu->disp->vram[address - VRAM_ADDRESS];
}
else if (address == LCD_SELECT_REGISTER || address == LCD_DATA_REGISTER) {
// LCD emulation
return &cpu->disp->lcd_registers;
}
else {
critical_error("Memory address 0x%08X is out of bounds\n", address);
critical_error("Request for memory at address 0x%08X is out of bounds\n", address);
}
}
const char* d_get_memory_type(int type) {
if (type == 0) return "ROM";
else if (type == 1) return "RAM";
else if (type == 2) return "RAM (direct)";
else return "undefined";
}
// Write to the memory
void mem_write(cpu_t* cpu, uint32_t address, uint32_t data, uint8_t bytes) {
uint32_t mapped; // Mapped address
uint8_t d_mem_type; // (debug) Memory type
uint8_t* mem = get_memory_for_address(cpu, address, &mapped, &d_mem_type);
uint8_t* mem = get_memory_for_address(cpu, address);
printf("Memory write [%s]: 0x%08X (Mapped: 0x%08X) : 0x%08X\n", d_get_memory_type(d_mem_type), address, mapped, data);
//printf("Memory write [0x%08X]: 0x%08X\n", address, data);
if (bytes == 1) {
mem[mapped] = data & 0xFF;
*mem = data & 0xFF;
}
else if (bytes == 2) {
mem[mapped] = (data >> 8) & 0xFF;
mem[mapped + 1] = data & 0xFF;
*(mem + 0) = (data >> 8) & 0xFF;
*(mem + 1) = data & 0xFF;
}
else if (bytes == 4) {
mem[mapped] = (data >> 24) & 0xFF;
mem[mapped + 1] = (data >> 16) & 0xFF;
mem[mapped + 2] = (data >> 8) & 0xFF;
mem[mapped + 3] = data & 0xFF;
*(mem + 0) = (data >> 24) & 0xFF;
*(mem + 1) = (data >> 16) & 0xFF;
*(mem + 2) = (data >> 8) & 0xFF;
*(mem + 3) = data & 0xFF;
}
}
// Read from the memory
uint32_t mem_read_(cpu_t* cpu, uint32_t address, uint8_t bytes, int logs) {
uint32_t mapped; // Mapped address
uint8_t d_mem_type; // (debug) Memory type
uint8_t* mem = get_memory_for_address(cpu, address, &mapped, &d_mem_type);
uint32_t mem_read_(cpu_t* cpu, uint32_t address, uint8_t bytes) {
uint8_t* mem = get_memory_for_address(cpu, address);
if (bytes == 1) {
if (logs) printf("Memory read [%s]: 0x%08X (Mapped: 0x%08X) : 0x%02X\n", d_get_memory_type(d_mem_type), address, mapped, mem[mapped]);
return mem[mapped];
return *mem;
}
else if (bytes == 2) {
uint16_t val = (mem[mapped] << 8) | (mem[mapped + 1]);
if (logs) printf("Memory read [%s]: 0x%08X (Mapped: 0x%08X) : 0x%04X\n", d_get_memory_type(d_mem_type), address, mapped, val);
return (int16_t) val;
return (*mem << 8) | (*(mem + 1));
}
else {
uint32_t val = (mem[mapped] << 24) | (mem[mapped + 1] << 16) | (mem[mapped + 2] << 8) | (mem[mapped + 3]);
if (logs) printf("Memory read [%s]: 0x%08X (Mapped: 0x%08X) : 0x%08X\n", d_get_memory_type(d_mem_type), address, mapped, val);
return val;
return (*mem << 24) | (*(mem + 1) << 16) | (*(mem + 2) << 8) | (*(mem + 3));
}
}
uint32_t mem_read_nolog(cpu_t* cpu, uint32_t address, uint8_t bytes) {
return mem_read_(cpu, address, bytes, 0);
return mem_read_(cpu, address, bytes);
}
uint32_t mem_read(cpu_t* cpu, uint32_t address, uint8_t bytes) {
return mem_read_(cpu, address, bytes, 1);
uint32_t value = mem_read_(cpu, address, bytes);
printf("Memory read [0x%08X]: : 0x%X\n", address, value);
return value;
}

View File

@ -73,19 +73,13 @@ void cpu_debug(cpu_t* cpu) {
print_binary(low, 4);
printf("\n");
/*
for (int i = 0; i < 16; i++) {
int r = cpu->r[i];
if (r != 0)
printf("r%d: 0x%08X, ", i, r);
}
printf("pr: 0x%08X, cursor: %d-%d, T: %d\n", cpu->pr, cpu->disp->cursor.col, cpu->disp->cursor.row, get_status_register_bit(cpu, SR_BIT_T));
*/
//printf("mem: 0x%02X 0x%02X 0x%02X 0x%02X\n", mem_read_nolog(cpu, 0x00300670, 1), mem_read_nolog(cpu, 0x00300670 + 1, 1), mem_read_nolog(cpu, 0x00300670 + 2, 1), mem_read_nolog(cpu, 0x00300670 + 3, 1));
}
void set_status_register_bit(cpu_t* cpu, uint8_t bit, uint8_t value) {
cpu->sr = (cpu->sr & ~(1 << bit)) | (value << bit);
}
uint8_t get_status_register_bit(cpu_t* cpu, uint8_t bit) {
return (cpu->sr >> bit) & 1;
}

View File

@ -0,0 +1,186 @@
const fs = require('fs')
// let debug_str = ''
main()
function main() {
let instructions = []
// Read the raw txt file
let string_content = fs.readFileSync('raw_instructions.txt', 'utf8').toString()
let instruction_count = string_content.match(/[01imnd]{16}/gm).length
// Remove lines of type "Rev. 1.50, 10/04, page 378 of 610"
string_content = string_content.split('\n').filter(s => !s.includes('Rev.')).join('\n')
// Process each instruction set
for (let i = 0; i < instruction_count * 0 + 100; i++) {
const [instruction_set, new_string] = extractNextInstructionSet(string_content)
// We reached the end of the file
if (instruction_set == null) break
string_content = new_string
// Add each instruction to the list
instructions.push(...instruction_set)
}
console.log(instructions.map(e => e.name))
// Check that the correct numbers of instructions were extracted
console.log(instructions.length, instruction_count)
// Save to file
fs.writeFileSync('generated/instructions.json', JSON.stringify(instructions, null, 4))
// fs.writeFileSync('debug.txt', debug_str)
}
// Extract the next instruction set from the string
// Starts with "Format Operation Instruction Code" string
// which is the header of the table containing the instructions
function extractNextInstructionSet(input_str) {
// Start index of the current instruction set
const start = input_str.indexOf('T Bit') + 5
// If it was not found, we reached the end of the file
if (start-5 == -1) return [null, null]
// Start index of the next instruction set
let tmp = input_str.slice(start)
const end = tmp.indexOf('Format Operation')
// Slice the string so it only contains the current instruction set
const instructionSet = tmp.slice(0, end)
// debug_str += instructionSet + '\n\n========================================\n\n'
// Extract the instructions from the table
const instructions = extractInstructions(instructionSet)
// Slice the string to advance to the "Operation" section
const operationStart = instructionSet.indexOf('Operation:') + 10
const operationSection = instructionSet.slice(operationStart)
// Add the implementation code to each instruction
extractImplementations(operationSection, instructions)
// Return the instructions and the remaining string
return [
instructions,
input_str.slice(start + end)
]
}
// Extract the code, type and description of each instruction
// given a string containing an instruction set table
function extractInstructions(input_str) {
const matches = input_str.match(/[01imnd]{16}/gm) // Match tokens like 0100nnnnmmmm1100, 1010dddddddddddd or 0000000000001011
// const matches_dsp = input_str.match(/[01ADefguxyz*]{16}/gm) // Match tokens like 0100nnnnmmmm1100, 1010dddddddddddd or 0000000000001011
const instructions = []
// For each token match
for (let code of matches) {
// Get the token position in the string
const id = input_str.indexOf(code)
// Isolate what's before the token
let str = input_str.slice(0, id)
// Advance the string to the next token
input_str = input_str.slice(id + 16)
// Extract name
const name = str.match(/[A-Z.01268\/]{2,}/)[0] // Match tokens like JSR, LDRS, MOV.L, DIV0S, CMP/EQ
// Extract description
const desc = str.slice(str.indexOf(name) + name.length).trim()
.replaceAll(', ', ',')
.split(' ')[0]
.split('\r')[0]
// console.log(code, '.', name, '.', desc)
console.log({
code,
desc,
family: name,
})
instructions.push({
code,
desc,
family: name,
})
}
return instructions
}
// Given a string containing the "Operation" section of an instruction set,
// extract every function in order and assign it to the corresponding instruction
function extractImplementations(input_str, instructions) {
// Match 3 groups: INSTRUCTION_NAME(OPERANDS) DESCRIPTION {
const matches = input_str.matchAll(/\n {0,1}([A-Znm_012468]{2,}) {0,1}(\([^)]*\))[^\/]*(\/*.*\/)/gm)
let index = 0
// For each function match
for (let [_, name, operands, desc] of matches) {
// Starting position of the function
const start = input_str.indexOf(name)
// Ending position of the function (last bracket)
const end = findLastFunctionBracket(input_str)
// Extract the function
const implementation = input_str.slice(start, end)
.replaceAll('', '~')
.replaceAll('', '-')
// Remove the function from the string
input_str = input_str.slice(end)
// Prevent macro name collision
if (name == 'MACL' || name == 'MACH') name += '_'
// console.log(start, end, name, operands, desc)
// Add the implementation details to the instruction
if (!name.includes('_BANK')) {
instructions[index].name = name
instructions[index].operands = operands
instructions[index].implementation = implementation
index++
}
// Special case for Rn_BANK instructions
else {
let i = 0
while (instructions[index].desc.includes('_BANK')) {
instructions[index].name = name.replace(/[nm]/, i++)
instructions[index].operands = operands
instructions[index].implementation = implementation
if (++index == instructions.length) break
}
}
}
if (index != instructions.length)
throw new Error(`Not all instructions were matched: ${index} != ${instructions.length}`)
}
// Get the index of the last bracket in a function passed as a string
function findLastFunctionBracket(input_str) {
const firstBracketIndex = input_str.indexOf('{')
let i = 0
let depth = 0
input_str = input_str.slice(firstBracketIndex)
for (const char of input_str) {
if (char == '{') depth++
if (char == '}') depth--
if (depth == 0) return i + firstBracketIndex + 1
i++
}
throw new Error('No closing bracket found')
}

View File

@ -0,0 +1,157 @@
void ADD(cpu_t* cpu, uint16_t instruction);
void ADDI(cpu_t* cpu, uint16_t instruction);
void ADDC(cpu_t* cpu, uint16_t instruction);
void ADDV(cpu_t* cpu, uint16_t instruction);
void AND(cpu_t* cpu, uint16_t instruction);
void ANDI(cpu_t* cpu, uint16_t instruction);
void ANDM(cpu_t* cpu, uint16_t instruction);
void BF(cpu_t* cpu, uint16_t instruction);
void BFS(cpu_t* cpu, uint16_t instruction);
void BRA(cpu_t* cpu, uint16_t instruction);
void BRAF(cpu_t* cpu, uint16_t instruction);
void BT(cpu_t* cpu, uint16_t instruction);
void BTS(cpu_t* cpu, uint16_t instruction);
void CLRMAC(cpu_t* cpu, uint16_t instruction);
void CLRS(cpu_t* cpu, uint16_t instruction);
void CLRT(cpu_t* cpu, uint16_t instruction);
void CMPEQ(cpu_t* cpu, uint16_t instruction);
void CMPGE(cpu_t* cpu, uint16_t instruction);
void CMPGT(cpu_t* cpu, uint16_t instruction);
void CMPHI(cpu_t* cpu, uint16_t instruction);
void CMPHS(cpu_t* cpu, uint16_t instruction);
void CMPPL(cpu_t* cpu, uint16_t instruction);
void CMPPZ(cpu_t* cpu, uint16_t instruction);
void CMPSTR(cpu_t* cpu, uint16_t instruction);
void CMPIM(cpu_t* cpu, uint16_t instruction);
void DIV0S(cpu_t* cpu, uint16_t instruction);
void DIV0U(cpu_t* cpu, uint16_t instruction);
void DIV1(cpu_t* cpu, uint16_t instruction);
void DMULS(cpu_t* cpu, uint16_t instruction);
void DMULU(cpu_t* cpu, uint16_t instruction);
void DT(cpu_t* cpu, uint16_t instruction);
void EXTSB(cpu_t* cpu, uint16_t instruction);
void EXTSW(cpu_t* cpu, uint16_t instruction);
void EXTUB(cpu_t* cpu, uint16_t instruction);
void EXTUW(cpu_t* cpu, uint16_t instruction);
void JMP(cpu_t* cpu, uint16_t instruction);
void LDCGBR(cpu_t* cpu, uint16_t instruction);
void LDCVBR(cpu_t* cpu, uint16_t instruction);
void LDCSGR(cpu_t* cpu, uint16_t instruction);
void LDCSSR(cpu_t* cpu, uint16_t instruction);
void LDCSPC(cpu_t* cpu, uint16_t instruction);
void LDCDBR(cpu_t* cpu, uint16_t instruction);
void LDCMGBR(cpu_t* cpu, uint16_t instruction);
void LDCMVBR(cpu_t* cpu, uint16_t instruction);
void LDCMSGR(cpu_t* cpu, uint16_t instruction);
void LDCMSSR(cpu_t* cpu, uint16_t instruction);
void LDCMSPC(cpu_t* cpu, uint16_t instruction);
void LDCMDBR(cpu_t* cpu, uint16_t instruction);
void LDSMACH(cpu_t* cpu, uint16_t instruction);
void LDSMACL(cpu_t* cpu, uint16_t instruction);
void LDSPR(cpu_t* cpu, uint16_t instruction);
void LDSMMACH(cpu_t* cpu, uint16_t instruction);
void LDSMMACL(cpu_t* cpu, uint16_t instruction);
void LDSMPR(cpu_t* cpu, uint16_t instruction);
void MACL_(cpu_t* cpu, uint16_t instruction);
void MACW(cpu_t* cpu, uint16_t instruction);
void MOV(cpu_t* cpu, uint16_t instruction);
void MOVBS(cpu_t* cpu, uint16_t instruction);
void MOVWS(cpu_t* cpu, uint16_t instruction);
void MOVLS(cpu_t* cpu, uint16_t instruction);
void MOVBL(cpu_t* cpu, uint16_t instruction);
void MOVWL(cpu_t* cpu, uint16_t instruction);
void MOVLL(cpu_t* cpu, uint16_t instruction);
void MOVBM(cpu_t* cpu, uint16_t instruction);
void MOVWM(cpu_t* cpu, uint16_t instruction);
void MOVLM(cpu_t* cpu, uint16_t instruction);
void MOVBP(cpu_t* cpu, uint16_t instruction);
void MOVWP(cpu_t* cpu, uint16_t instruction);
void MOVLP(cpu_t* cpu, uint16_t instruction);
void MOVBS0(cpu_t* cpu, uint16_t instruction);
void MOVWS0(cpu_t* cpu, uint16_t instruction);
void MOVLS0(cpu_t* cpu, uint16_t instruction);
void MOVBL0(cpu_t* cpu, uint16_t instruction);
void MOVWL0(cpu_t* cpu, uint16_t instruction);
void MOVLL0(cpu_t* cpu, uint16_t instruction);
void MOVI(cpu_t* cpu, uint16_t instruction);
void MOVWI(cpu_t* cpu, uint16_t instruction);
void MOVLI(cpu_t* cpu, uint16_t instruction);
void MOVBLG(cpu_t* cpu, uint16_t instruction);
void MOVWLG(cpu_t* cpu, uint16_t instruction);
void MOVLLG(cpu_t* cpu, uint16_t instruction);
void MOVBSG(cpu_t* cpu, uint16_t instruction);
void MOVWSG(cpu_t* cpu, uint16_t instruction);
void MOVLSG(cpu_t* cpu, uint16_t instruction);
void MOVBS4(cpu_t* cpu, uint16_t instruction);
void MOVWS4(cpu_t* cpu, uint16_t instruction);
void MOVLS4(cpu_t* cpu, uint16_t instruction);
void MOVBL4(cpu_t* cpu, uint16_t instruction);
void MOVWL4(cpu_t* cpu, uint16_t instruction);
void MOVLL4(cpu_t* cpu, uint16_t instruction);
void MOVA(cpu_t* cpu, uint16_t instruction);
void MOVT(cpu_t* cpu, uint16_t instruction);
void MULL(cpu_t* cpu, uint16_t instruction);
void MULS(cpu_t* cpu, uint16_t instruction);
void MULU(cpu_t* cpu, uint16_t instruction);
void NEG(cpu_t* cpu, uint16_t instruction);
void NEGC(cpu_t* cpu, uint16_t instruction);
void NOP(cpu_t* cpu, uint16_t instruction);
void NOT(cpu_t* cpu, uint16_t instruction);
void OR(cpu_t* cpu, uint16_t instruction);
void ORI(cpu_t* cpu, uint16_t instruction);
void ORM(cpu_t* cpu, uint16_t instruction);
void PREF(cpu_t* cpu, uint16_t instruction);
void ROTCL(cpu_t* cpu, uint16_t instruction);
void ROTCR(cpu_t* cpu, uint16_t instruction);
void ROTL(cpu_t* cpu, uint16_t instruction);
void ROTR(cpu_t* cpu, uint16_t instruction);
void RTE(cpu_t* cpu, uint16_t instruction);
void RTS(cpu_t* cpu, uint16_t instruction);
void SETS(cpu_t* cpu, uint16_t instruction);
void SETT(cpu_t* cpu, uint16_t instruction);
void SHAD(cpu_t* cpu, uint16_t instruction);
void SHAL(cpu_t* cpu, uint16_t instruction);
void SHAR(cpu_t* cpu, uint16_t instruction);
void SHLD(cpu_t* cpu, uint16_t instruction);
void SHLL(cpu_t* cpu, uint16_t instruction);
void SHLL2(cpu_t* cpu, uint16_t instruction);
void SHLL8(cpu_t* cpu, uint16_t instruction);
void SHLL16(cpu_t* cpu, uint16_t instruction);
void SHLR(cpu_t* cpu, uint16_t instruction);
void SHLR2(cpu_t* cpu, uint16_t instruction);
void SHLR8(cpu_t* cpu, uint16_t instruction);
void SHLR16(cpu_t* cpu, uint16_t instruction);
void STCGBR(cpu_t* cpu, uint16_t instruction);
void STCVBR(cpu_t* cpu, uint16_t instruction);
void STCSSR(cpu_t* cpu, uint16_t instruction);
void STCSPC(cpu_t* cpu, uint16_t instruction);
void STCSGR(cpu_t* cpu, uint16_t instruction);
void STCDBR(cpu_t* cpu, uint16_t instruction);
void STCMGBR(cpu_t* cpu, uint16_t instruction);
void STCMVBR(cpu_t* cpu, uint16_t instruction);
void STCMSSR(cpu_t* cpu, uint16_t instruction);
void STCMSPC(cpu_t* cpu, uint16_t instruction);
void STCMSGR(cpu_t* cpu, uint16_t instruction);
void STCMDBR(cpu_t* cpu, uint16_t instruction);
void STSMACH(cpu_t* cpu, uint16_t instruction);
void STSMACL(cpu_t* cpu, uint16_t instruction);
void STSPR(cpu_t* cpu, uint16_t instruction);
void STSMMACH(cpu_t* cpu, uint16_t instruction);
void STSMMACL(cpu_t* cpu, uint16_t instruction);
void STSMPR(cpu_t* cpu, uint16_t instruction);
void SUB(cpu_t* cpu, uint16_t instruction);
void SUBC(cpu_t* cpu, uint16_t instruction);
void SUBV(cpu_t* cpu, uint16_t instruction);
void SWAPB(cpu_t* cpu, uint16_t instruction);
void SWAPW(cpu_t* cpu, uint16_t instruction);
void TAS(cpu_t* cpu, uint16_t instruction);
void TST(cpu_t* cpu, uint16_t instruction);
void TSTI(cpu_t* cpu, uint16_t instruction);
void TSTM(cpu_t* cpu, uint16_t instruction);
void XOR(cpu_t* cpu, uint16_t instruction);
void XORI(cpu_t* cpu, uint16_t instruction);
void XORM(cpu_t* cpu, uint16_t instruction);
void XTRCT(cpu_t* cpu, uint16_t instruction);
void BSR(cpu_t* cpu, uint16_t instruction);
void BSRF(cpu_t* cpu, uint16_t instruction);
void JSR(cpu_t* cpu, uint16_t instruction);

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

50
scripts/header.c Normal file
View File

@ -0,0 +1,50 @@
struct SR0 {
unsigned long dummy0:22;
unsigned long M0:1;
unsigned long Q0:1;
unsigned long I0:4;
unsigned long dummy1:2;
unsigned long S0:1;
unsigned long T0:1;
};
#define M ((*(struct SR0 *)(&SR)).M0)
#define Q ((*(struct SR0 *)(&SR)).Q0)
#define S ((*(struct SR0 *)(&SR)).S0)
#define T ((*(struct SR0 *)(&SR)).T0)
#define SR cpu->sr
#define GBR cpu->gbr
#define SGR cpu->sgr
#define VBR cpu->vbr
#define SSR cpu->ssr
#define SPC cpu->spc
#define DBR cpu->dbr
#define PC cpu->pc
#define PR cpu->pr
#define R cpu->r
#define R0 cpu->r[0]
#define MACH cpu->mach
#define MACL cpu->macl
#define Read_Byte(addr) mem_read(cpu, addr, 1)
#define Read_Word(addr) mem_read(cpu, addr, 2)
#define Read_Long(addr) mem_read(cpu, addr, 4)
#define Write_Byte(addr, data) mem_write(cpu, addr, data, 1)
#define Write_Word(addr, data) mem_write(cpu, addr, data, 2)
#define Write_Long(addr, data) mem_write(cpu, addr, data, 4)
#define Delay_Slot(pc_next) \
uint32_t pc_save = cpu->pc; \
cpu->pc = pc_next; \
run_next_instruction(cpu); \
cpu->pc = pc_save;
#define is_32bit_instruction(addr) is_32bit_instruction_impl(cpu, addr)
int is_32bit_instruction_impl(cpu_t* cpu, int addr) {
// TODO
return 0;
}

4054
scripts/raw_instructions.txt Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,218 @@
const fs = require('fs')
main()
function main() {
let instructions = JSON.parse(fs.readFileSync('generated/instructions.json', 'utf8').toString())
// Exclude exceptions
const exceptions = [
'MOVUAL', 'MOVUALP', // unknown Read_Unaligned_Long functions
'ICBI', 'OCBI', 'OCBP', 'OCBWB', 'PREFI', 'SLEEP', 'SYNCO', 'SETRC', 'SETRCI', // Call to unknown functions
'LDSMX0', 'LDSMX1', 'LDSMY0', 'LDSMY1', 'LDCMSR', 'LDRC', 'LDRCI', 'CLRDMXY', 'TRAPA', // DSP-related
]
for (let i = 0; i < instructions.length; i++) {
if (exceptions.includes(instructions[i].name) ||
instructions[i].name.includes('_BANK') ||
instructions[i].implementation.includes('PTEH') ||
instructions[i].implementation.includes('PTEL') ||
instructions[i].implementation.includes('TLB') ||
instructions[i].implementation.includes('LDST') ||
instructions[i].implementation.includes('MISS')
) {
instructions.splice(i, 1)
i--
}
}
instructions = instructions.slice(0, 157)
console.log(instructions.map(e => e.name))
// instructions.c
const selector = writeInstructionSelector(instructions)
const implementations = writeInstructionImplementations(instructions)
fs.writeFileSync('generated/instructions.c', selector + '\n\n' + implementations)
// instruction.h
const header = instructions.map(instruction => `void ${instruction.name}(cpu_t* cpu, uint16_t instruction);\n`).join('')
fs.writeFileSync('generated/instruction.h', header)
}
function writeInstructionSelector(instructions) {
const reg16 = /[01]{16}/ // 0000000000001011
const reg8 = /[01]{8}[a-z]{8}/ // 00000000nnnnmmmm
const reg4 = /[01]{4}[a-z]{12}/ // 0000nnnnmmmmdddd
const reg48 = /[01]{4}[a-z]{4}[0-1]{8}/ // 0100nnnn00010010
const reg44 = /[01]{4}[a-z]{8}[01]{4}/ // 0110nnnnmmmm1000
const filterInstructions = (reg) => instructions.filter(e => e.code.match(reg))
let str = `#include "../headers/instructions/instructions.h"
// Returns a pointer to the function that implements the corresponding instruction
void (*get_instruction_impl(uint16_t instruction))(cpu_t*, uint16_t) {
uint8_t high = (instruction >> 12) & 0x0F;
uint8_t high8 = instruction >> 8;
uint8_t low = instruction & 0x0F;
uint8_t low8 = instruction & 0xFF;\n\n`
// Reg 16
for (const instruction of filterInstructions(reg16)) {
str += `\tif (instruction == 0b${instruction.code}) return ${instruction.name};\n`
}
// Reg 8
for (const instruction of filterInstructions(reg8)) {
str += `\tif (high8 == 0b${instruction.code.slice(0, 8)}) return ${instruction.name};\n`
}
// Reg 4
for (const instruction of filterInstructions(reg4)) {
str += `\tif (high == 0b${instruction.code.slice(0, 4)}) return ${instruction.name};\n`
}
// Get all unique combinations of the first 4 bits in the instruction codes, sorted by count
const getUniqueInstructions4 = (instructions) => Object.entries(
instructions.reduce((acc, e) => {
const key = e.code.slice(0, 4)
acc[key] = acc[key] ? acc[key] + 1 : 1
return acc
}, {})
).sort((a, b) => b[1] - a[1])
// Reg 48
const instructions48 = filterInstructions(reg48)
const unique48 = getUniqueInstructions4(instructions48)
for (const [code] of unique48) {
str += `\tif (high == 0b${code}) {\n`
for (const instruction of instructions48.filter(e => e.code.slice(0, 4) == code)) {
str += `\t\tif (low8 == 0b${instruction.code.slice(8, 16)}) return ${instruction.name};\n`
}
str += `\t}\n`
}
// Reg 44
const instructions44 = filterInstructions(reg44)
const unique44 = getUniqueInstructions4(instructions44)
for (const [code] of unique44) {
str += `\tif (high == 0b${code}) {\n`
for (const instruction of instructions44.filter(e => e.code.slice(0, 4) == code)) {
str += `\t\tif (low == 0b${instruction.code.slice(12, 16)}) return ${instruction.name};\n`
}
str += `\t}\n`
}
str += `\n\tprint_binary(instruction, 16);`
str += `\n\tcritical_error(" => Unknown instruction: 0x%04X\\n", instruction);\n}`
return str
}
function writeInstructionImplementations(instructions) {
const header = fs.readFileSync('header.c', 'utf8').toString()
let str = header + '\n\n'
// Extract variable character, start and end position from a binary code: 0100nnnnmmmm1100 -> n: 5-8, m: 9-12
const extractVariablesInfos = (str) => {
let variables = []
let currentChar = null
const beginVariable = (char, start) => { currentChar = { char, start } }
const endVariable = (end) => variables.push({...currentChar, end: end + 1})
for (let i = 0; i < 16; i++) {
const isDigit = Number.isInteger(Number.parseInt(str[i]))
// Current char is 0-1
if (isDigit) {
// If we were reading a variable, end it
if (currentChar != null) {
endVariable(i - 1)
currentChar = null
}
continue
}
// Current char is a letter
else {
// If we were not reading a variable, start it
if (currentChar == null) {
beginVariable(str[i], i)
}
// Otherwise if the current char is different from the previous one,
// end the variable and start a new one
else if (currentChar.char != str[i]) {
endVariable(i - 1)
beginVariable(str[i], i)
}
// Otherwise if we reached the end of the string, end the variable
else if (i == 15) {
endVariable(i)
}
}
}
// console.log(str, variables)
return variables
}
const createVariableImplementation = ({char, type, start, end}) => {
let str = `${type} ${char} = `
// Size 4
if (start == 4 && end == 8) str += `(instruction >> 8) & 0xF;`
else if (start == 8 && end == 12) str += `(instruction >> 4) & 0xF;`
else if (start == 12 && end == 16) str += `instruction & 0xF;`
// Size 8
else if (start == 8 && end == 16) str += `instruction & 0xFF;`
// Size 12
else if (start == 4 && end == 16) str += `instruction & 0xFFF;`
else throw new Error(`Unknown variable position: ${start} - ${end}`)
return str
}
for (const instruction of instructions) {
// Write function declaration
str += `// ${instruction.name} / ${instruction.desc} - ${instruction.code}\n`
str += `void ${instruction.name}(cpu_t* cpu, uint16_t instruction) {\n`
// Extract variables starting and ending positions in instruction code
const variableInfos = extractVariablesInfos(instruction.code)
// Extract variables types from operands string
const variableTypes = Object.fromEntries(
instruction.operands.replaceAll(/[()]/gm, '')
.split(',')
.map(e => e.trim().split(' ').reverse())
)
// Write variable declarations
for (const variableInfo of variableInfos) {
if (variableTypes[variableInfo.char] == null) {
console.log(instruction, variableInfos)
throw new Error('Missing variable type for ' + variableInfo.char)
}
variableInfo.type = variableTypes[variableInfo.char].toLowerCase()
str += ' '
str += createVariableImplementation(variableInfo) + '\n'
}
// Write instruction implementation
const impl = instruction.implementation.slice(instruction.implementation.indexOf('{') + 1)
.replaceAll(/^ /gm, ' ')
str += `${impl}\n\n`
}
return str
}