fx9860-emulator-playground/fx9860-emulator/instructions/implementations.c

363 lines
9.0 KiB
C

#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;
}