add auto-generated instructions
This commit is contained in:
parent
019e74c127
commit
364e0a44f2
|
@ -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
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
|
@ -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
|
@ -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]);
|
||||
}
|
|
@ -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");
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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')
|
||||
}
|
|
@ -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
|
@ -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;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -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
|
||||
}
|
Loading…
Reference in New Issue