WindEmu/WindCore/arm.c

237 lines
5.7 KiB
C

/* Copyright (c) 2013-2014 Jeffrey Pfau
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "arm.h"
#include "isa-arm.h"
#include "isa-inlines.h"
static inline enum RegisterBank _ARMSelectBank(enum PrivilegeMode);
void ARMSetPrivilegeMode(struct ARMCore* cpu, enum PrivilegeMode mode) {
if (mode == cpu->privilegeMode) {
// Not switching modes after all
return;
}
enum RegisterBank newBank = _ARMSelectBank(mode);
enum RegisterBank oldBank = _ARMSelectBank(cpu->privilegeMode);
if (newBank != oldBank) {
// Switch banked registers
if (mode == MODE_FIQ || cpu->privilegeMode == MODE_FIQ) {
int oldFIQBank = oldBank == BANK_FIQ;
int newFIQBank = newBank == BANK_FIQ;
cpu->bankedRegisters[oldFIQBank][2] = cpu->gprs[8];
cpu->bankedRegisters[oldFIQBank][3] = cpu->gprs[9];
cpu->bankedRegisters[oldFIQBank][4] = cpu->gprs[10];
cpu->bankedRegisters[oldFIQBank][5] = cpu->gprs[11];
cpu->bankedRegisters[oldFIQBank][6] = cpu->gprs[12];
cpu->gprs[8] = cpu->bankedRegisters[newFIQBank][2];
cpu->gprs[9] = cpu->bankedRegisters[newFIQBank][3];
cpu->gprs[10] = cpu->bankedRegisters[newFIQBank][4];
cpu->gprs[11] = cpu->bankedRegisters[newFIQBank][5];
cpu->gprs[12] = cpu->bankedRegisters[newFIQBank][6];
}
cpu->bankedRegisters[oldBank][0] = cpu->gprs[ARM_SP];
cpu->bankedRegisters[oldBank][1] = cpu->gprs[ARM_LR];
cpu->gprs[ARM_SP] = cpu->bankedRegisters[newBank][0];
cpu->gprs[ARM_LR] = cpu->bankedRegisters[newBank][1];
cpu->bankedSPSRs[oldBank] = cpu->spsr.packed;
cpu->spsr.packed = cpu->bankedSPSRs[newBank];
}
cpu->privilegeMode = mode;
}
static inline enum RegisterBank _ARMSelectBank(enum PrivilegeMode mode) {
switch (mode) {
case MODE_USER:
case MODE_SYSTEM:
// No banked registers
return BANK_NONE;
case MODE_FIQ:
return BANK_FIQ;
case MODE_IRQ:
return BANK_IRQ;
case MODE_SUPERVISOR:
return BANK_SUPERVISOR;
case MODE_ABORT:
return BANK_ABORT;
case MODE_UNDEFINED:
return BANK_UNDEFINED;
default:
// This should be unreached
return BANK_NONE;
}
}
void ARMReset(struct ARMCore* cpu) {
int i;
for (i = 0; i < 16; ++i) {
cpu->gprs[i] = 0;
}
for (i = 0; i < 6; ++i) {
cpu->bankedRegisters[i][0] = 0;
cpu->bankedRegisters[i][1] = 0;
cpu->bankedRegisters[i][2] = 0;
cpu->bankedRegisters[i][3] = 0;
cpu->bankedRegisters[i][4] = 0;
cpu->bankedRegisters[i][5] = 0;
cpu->bankedRegisters[i][6] = 0;
cpu->bankedSPSRs[i] = 0;
}
cpu->privilegeMode = MODE_SYSTEM;
cpu->cpsr.packed = MODE_SYSTEM;
cpu->spsr.packed = 0;
cpu->shifterOperand = 0;
cpu->shifterCarryOut = 0;
ARMWritePC(cpu);
cpu->cycles = 0;
cpu->nextEvent = 0;
cpu->halted = 0;
cpu->irqh.reset(cpu);
}
void ARMRaiseFIQ(struct ARMCore* cpu) {
if (cpu->cpsr.f) {
return;
}
union PSR cpsr = cpu->cpsr;
ARMSetPrivilegeMode(cpu, MODE_FIQ);
cpu->cpsr.priv = MODE_FIQ;
cpu->gprs[ARM_LR] = cpu->gprs[ARM_PC];
cpu->gprs[ARM_PC] = BASE_FIQ;
cpu->cycles += ARMWritePC(cpu);
cpu->spsr = cpsr;
cpu->cpsr.f = 1;
cpu->cpsr.i = 1;
cpu->halted = 0;
}
void ARMRaiseIRQ(struct ARMCore* cpu) {
if (cpu->cpsr.i) {
return;
}
union PSR cpsr = cpu->cpsr;
ARMSetPrivilegeMode(cpu, MODE_IRQ);
cpu->cpsr.priv = MODE_IRQ;
cpu->gprs[ARM_LR] = cpu->gprs[ARM_PC];
cpu->gprs[ARM_PC] = BASE_IRQ;
cpu->cycles += ARMWritePC(cpu);
cpu->spsr = cpsr;
cpu->cpsr.i = 1;
cpu->halted = 0;
}
void ARMRaiseSWI(struct ARMCore* cpu) {
union PSR cpsr = cpu->cpsr;
ARMSetPrivilegeMode(cpu, MODE_SUPERVISOR);
cpu->cpsr.priv = MODE_SUPERVISOR;
cpu->gprs[ARM_LR] = cpu->gprs[ARM_PC] - 4;
cpu->gprs[ARM_PC] = BASE_SWI;
cpu->cycles += ARMWritePC(cpu);
cpu->spsr = cpsr;
cpu->cpsr.i = 1;
}
void ARMRaiseUndefined(struct ARMCore* cpu) {
union PSR cpsr = cpu->cpsr;
ARMSetPrivilegeMode(cpu, MODE_UNDEFINED);
cpu->cpsr.priv = MODE_UNDEFINED;
cpu->gprs[ARM_LR] = cpu->gprs[ARM_PC] - 4;
cpu->gprs[ARM_PC] = BASE_UNDEF;
cpu->cycles += ARMWritePC(cpu);
cpu->spsr = cpsr;
cpu->cpsr.i = 1;
}
static inline void ARMStep(struct ARMCore* cpu) {
uint32_t opcode = cpu->prefetch[0];
cpu->prefetch[0] = cpu->prefetch[1];
cpu->gprs[ARM_PC] += 4;
cpu->prefetch[1] = cpu->memory.load32(cpu, cpu->gprs[ARM_PC], NULL);
unsigned condition = opcode >> 28;
if (condition != 0xE) {
bool conditionMet = false;
switch (condition) {
case 0x0:
conditionMet = ARM_COND_EQ;
break;
case 0x1:
conditionMet = ARM_COND_NE;
break;
case 0x2:
conditionMet = ARM_COND_CS;
break;
case 0x3:
conditionMet = ARM_COND_CC;
break;
case 0x4:
conditionMet = ARM_COND_MI;
break;
case 0x5:
conditionMet = ARM_COND_PL;
break;
case 0x6:
conditionMet = ARM_COND_VS;
break;
case 0x7:
conditionMet = ARM_COND_VC;
break;
case 0x8:
conditionMet = ARM_COND_HI;
break;
case 0x9:
conditionMet = ARM_COND_LS;
break;
case 0xA:
conditionMet = ARM_COND_GE;
break;
case 0xB:
conditionMet = ARM_COND_LT;
break;
case 0xC:
conditionMet = ARM_COND_GT;
break;
case 0xD:
conditionMet = ARM_COND_LE;
break;
default:
break;
}
if (!conditionMet) {
cpu->cycles += ARM_PREFETCH_CYCLES;
return;
}
}
ARMInstruction instruction = _armTable[((opcode >> 16) & 0xFF0) | ((opcode >> 4) & 0x00F)];
instruction(cpu, opcode);
}
void ARMRun(struct ARMCore* cpu) {
ARMStep(cpu);
if (cpu->cycles >= cpu->nextEvent) {
cpu->irqh.processEvents(cpu);
}
}
void ARMRunLoop(struct ARMCore* cpu) {
while (cpu->cycles < cpu->nextEvent) {
ARMStep(cpu);
}
cpu->irqh.processEvents(cpu);
}
void ARMRunFake(struct ARMCore* cpu, uint32_t opcode) {
cpu->gprs[ARM_PC] -= 4;
cpu->prefetch[1] = cpu->prefetch[0];
cpu->prefetch[0] = opcode;
}