mirror of
https://github.com/libretro/Mu.git
synced 2026-07-08 17:57:01 +00:00
Add uARM as reference CPU core
This commit is contained in:
@@ -2,5 +2,6 @@ Bugs in other peoples code I found while writing Mu, haven't followed up on them
|
||||
(RetroArch)RETRO_ENVIRONMENT_GET_MIDI_INTERFACE states its passed a pointer to a pointer but its just a pointer to a struct
|
||||
(RetroArch)"led_driver" setting is not exposed to GUI
|
||||
(RetroArch)retro_set_environment will sometimes be called multiple times and provide invalid values fetching environment variables on the subsequent calls, this will cause function pointers to be corrupted if they are not checked for validity first
|
||||
QT will clobber object files when there are 2 source files with the same name even if they are in different folders
|
||||
|
||||
Fixed:
|
||||
@@ -56,14 +56,15 @@ MakePalmBitmap:
|
||||
|
||||
Other:
|
||||
Qt port dosent support Windows touchscreen input
|
||||
memory dumping dosent work for OS 5 yet
|
||||
T3 I2C currently has no ACK bits(should work without them its just inaccurate)(I2C works fine though)
|
||||
T3 emulation attempts to set GPIO1(reset button) as an output
|
||||
GPIO lines from misc chips to CPU are not implemented
|
||||
PXA260 idle mode is unimplemented
|
||||
0x0E071F16 MCR P15, #0, R1, C7, C2, #5 is unimplemented along with several other unknown CP15 opcodes
|
||||
|
||||
|
||||
Fixed:
|
||||
memory dumping dosent work for OS 5 yet
|
||||
Endian compatibility is broken(the CPU state needs to be standardized)
|
||||
RetroArch port crashes on exit(needed to check if environ_cb returned true, switched to libretro-common filestreams too)
|
||||
make the headers belong to the main file of the target chip being emulated for specs
|
||||
|
||||
@@ -156,6 +156,9 @@ support_palm_os5{
|
||||
../../src/pxa260/pxa260Ssp.c \
|
||||
../../src/pxa260/pxa260Udc.c \
|
||||
../../src/pxa260/pxa260.c \
|
||||
../../src/armv5te/uArm/CPU_2.c \
|
||||
../../src/armv5te/uArm/icache.c \
|
||||
../../src/armv5te/uArm/uArmGlue.cpp \
|
||||
../../src/armv5te/arm_interpreter.cpp \
|
||||
../../src/armv5te/cpu.cpp \
|
||||
../../src/armv5te/coproc.cpp \
|
||||
@@ -189,6 +192,9 @@ support_palm_os5{
|
||||
../../src/pxa260/pxa260Accessors.c.h \
|
||||
../../src/pxa260/pxa260.h \
|
||||
../../src/armv5te/os/os.h \
|
||||
../../src/armv5te/uArm/CPU_2.h \
|
||||
../../src/armv5te/uArm/icache.h \
|
||||
../../src/armv5te/uArm/uArmGlue.h \
|
||||
../../src/armv5te/asmcode.h \
|
||||
../../src/armv5te/bitfield.h \
|
||||
../../src/armv5te/cpu.h \
|
||||
|
||||
@@ -39,7 +39,7 @@ static QVector<QString> debugStrings;
|
||||
static uint64_t debugDeletedStrings;
|
||||
static QVector<uint64_t> debugDuplicateCallCount;
|
||||
static bool debugAbort = false;
|
||||
static QString debugAbortString = "Someone tried to set processor power mode (cp14 reg7) to 0x00000001, PC:0x200C2844\n";
|
||||
static QString debugAbortString = "PCMCIA";
|
||||
uint32_t frontendDebugStringSize;
|
||||
char* frontendDebugString;
|
||||
|
||||
@@ -51,7 +51,7 @@ void frontendHandleDebugPrint(){
|
||||
if(debugAbort)
|
||||
return;
|
||||
|
||||
if(newDebugString == debugAbortString)
|
||||
if(!debugAbortString.isEmpty() && newDebugString.contains(debugAbortString))
|
||||
debugAbort = true;
|
||||
|
||||
//this debug handler doesnt need the \n
|
||||
|
||||
@@ -23,7 +23,7 @@ I am planning on adding Tungsten T3 support as soon as possible.
|
||||
|
||||
## Credits
|
||||
[Firebird Emu](https://github.com/nspire-emus/firebird) (ARMv5TE Core)
|
||||
[uARM](https://dmitry.gr/?r=05.Projects&proj=07.%20Linux%20on%208bit) (PXA260 CPU Peripherals)
|
||||
[uARM](https://dmitry.gr/?r=05.Projects&proj=07.%20Linux%20on%208bit) (PXA260 CPU Peripherals and reference CPU core)
|
||||
[Musashi v3.4](https://github.com/kstenerud/Musashi) (last version that builds outside of MAME)(68k Core)
|
||||
[blip_buf 1.1.0](https://github.com/TASVideos/BizHawk/tree/master/blip_buf) (Audio Resampler)
|
||||
https://www.iconarchive.com/show/crystal-clear-icons-by-everaldo/App-palm-icon.html (Desktop Icon)
|
||||
|
||||
@@ -1,11 +1,6 @@
|
||||
/* Declarations for armsnippets */
|
||||
|
||||
#ifndef H_ARMSNIPPETS
|
||||
#define H_ARMSNIPPETS
|
||||
|
||||
//#include <stdbool.h>
|
||||
|
||||
#define armloader_cb()
|
||||
//bool armloader_load_snippet(enum SNIPPETS snippet, struct armloader_load_params params[], unsigned params_num, void (*callback)(struct arm_state *));
|
||||
|
||||
#endif
|
||||
|
||||
@@ -109,6 +109,7 @@ void do_cp15_mcr(uint32_t insn)
|
||||
arm.fault_address = value;
|
||||
break;
|
||||
case 0x070080: /* MCR p15, 0, <Rd>, c7, c0, 4: Wait for interrupt */
|
||||
emuprintf("Wait for interrupt, does not work with uARM core!\n");
|
||||
cycle_count_delta = 0;
|
||||
if (arm.interrupts == 0) {
|
||||
arm.reg[15] -= 4;
|
||||
@@ -141,7 +142,7 @@ void do_cp15_mcr(uint32_t insn)
|
||||
//TODO: Unknown(implmentation defined cp15 register)
|
||||
break;
|
||||
default:
|
||||
warn("Unknown coprocessor instruction MCR %08X", insn);
|
||||
warn("Unknown coprocessor instruction MCR %08X\n", insn);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -163,8 +164,7 @@ void do_cp14_instruction(Instruction i)
|
||||
|
||||
success = pxa260pwrClkPrvCoprocRegXferFunc(&pxa260PwrClk, specialInstr, (instr & 0x00100000) != 0, (instr >> 21) & 0x07, (instr >> 12) & 0x0F, (instr >> 16) & 0x0F, instr & 0x0F, (instr >> 5) & 0x07);
|
||||
|
||||
//fail if instr dosent actully exist
|
||||
if(!success)
|
||||
undefined_instruction();
|
||||
warn("Unknown coprocessor instruction MCR %08X\n", instr);
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,12 @@
|
||||
#include "mem.h"
|
||||
#include "os/os.h"
|
||||
|
||||
#if !defined(EMU_NO_SAFETY)
|
||||
#include "uArm/CPU_2.h"
|
||||
#include "uArm/icache.h"
|
||||
#include "../pxa260/pxa260.h"
|
||||
#endif
|
||||
|
||||
/* Copy of translation table in memory (hack to approximate effect of having a TLB) */
|
||||
static uint32_t mmu_translation_table[0x1000];
|
||||
|
||||
@@ -262,6 +268,10 @@ void *addr_cache_miss(uint32_t virt, bool writing, fault_proc *fault) {
|
||||
}
|
||||
|
||||
void addr_cache_flush(void) {
|
||||
#if !defined(EMU_NO_SAFETY)
|
||||
icacheInval(&pxa260CpuState.ic);//icache needs to be flushed when MMU state changes
|
||||
#endif
|
||||
|
||||
if (arm.control & 1) {
|
||||
void *table = phys_mem_ptr(arm.translation_table_base, 0x4000);
|
||||
if (!table)
|
||||
|
||||
2762
src/armv5te/uArm/CPU_2.c
Normal file
2762
src/armv5te/uArm/CPU_2.c
Normal file
File diff suppressed because it is too large
Load Diff
179
src/armv5te/uArm/CPU_2.h
Normal file
179
src/armv5te/uArm/CPU_2.h
Normal file
@@ -0,0 +1,179 @@
|
||||
#ifndef _CPU_H_
|
||||
#define _CPU_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
//#define ARM_V6 //define to allow v6 instructions
|
||||
//#define THUMB_2 //define to allow Thumb2
|
||||
|
||||
#include "../../pxa260/pxa260_types.h"
|
||||
|
||||
struct ArmCpu;
|
||||
|
||||
#define ARM_SR_N 0x80000000UL
|
||||
#define ARM_SR_Z 0x40000000UL
|
||||
#define ARM_SR_C 0x20000000UL
|
||||
#define ARM_SR_V 0x10000000UL
|
||||
#define ARM_SR_Q 0x08000000UL
|
||||
#ifdef ARM_V6 //V6KT2, but without T2 to be exact (we implement things like MLS, but not Thumb2 or ThumbEE)
|
||||
#define ARM_SR_J 0x01000000UL
|
||||
#define ARM_SR_E 0x00000200UL
|
||||
#define ARM_SR_A 0x00000100UL
|
||||
#define ARM_SR_GE_0 0x00010000UL
|
||||
#define ARM_SR_GE_1 0x00020000UL
|
||||
#define ARM_SR_GE_2 0x00040000UL
|
||||
#define ARM_SR_GE_3 0x00080000UL
|
||||
#define ARM_SR_GE_MASK 0x000F0000UL
|
||||
#define ARM_SR_GE_SHIFT 16
|
||||
#endif
|
||||
#define ARM_SR_I 0x00000080UL
|
||||
#define ARM_SR_F 0x00000040UL
|
||||
#define ARM_SR_T 0x00000020UL
|
||||
#define ARM_SR_M 0x0000001FUL
|
||||
|
||||
#define ARM_SR_MODE_USR 0x00000010UL
|
||||
#define ARM_SR_MODE_FIQ 0x00000011UL
|
||||
#define ARM_SR_MODE_IRQ 0x00000012UL
|
||||
#define ARM_SR_MODE_SVC 0x00000013UL
|
||||
#define ARM_SR_MODE_ABT 0x00000017UL
|
||||
#define ARM_SR_MODE_UND 0x0000001BUL
|
||||
#define ARM_SR_MODE_SYS 0x0000001FUL
|
||||
|
||||
#define ARV_VECTOR_OFFT_RST 0x00000000UL
|
||||
#define ARM_VECTOR_OFFT_UND 0x00000004UL
|
||||
#define ARM_VECTOR_OFFT_SWI 0x00000008UL
|
||||
#define ARM_VECTOR_OFFT_P_ABT 0x0000000CUL
|
||||
#define ARM_VECTOR_OFFT_D_ABT 0x00000010UL
|
||||
#define ARM_VECTOR_OFFT_UNUSED 0x00000014UL
|
||||
#define ARM_VECTOR_OFFT_IRQ 0x00000018UL
|
||||
#define ARM_VECTOR_OFFT_FIQ 0x0000001CUL
|
||||
|
||||
#define HYPERCALL_ARM 0xF7BBBBBBUL
|
||||
#define HYPERCALL_THUMB 0xBBBBUL
|
||||
|
||||
//the following are for cpuGetRegExternal() and are generally used for debugging purposes
|
||||
#define ARM_REG_NUM_CPSR 16
|
||||
#define ARM_REG_NUM_SPSR 17
|
||||
|
||||
struct ArmCpu;
|
||||
|
||||
typedef Boolean (*ArmCoprocRegXferF) (struct ArmCpu* cpu, void* userData, Boolean two/* MCR2/MRC2 ? */, Boolean MRC, UInt8 op1, UInt8 Rx, UInt8 CRn, UInt8 CRm, UInt8 op2);
|
||||
typedef Boolean (*ArmCoprocDatProcF) (struct ArmCpu* cpu, void* userData, Boolean two/* CDP2 ? */, UInt8 op1, UInt8 CRd, UInt8 CRn, UInt8 CRm, UInt8 op2);
|
||||
typedef Boolean (*ArmCoprocMemAccsF) (struct ArmCpu* cpu, void* userData, Boolean two /* LDC2/STC2 ? */, Boolean N, Boolean store, UInt8 CRd, UInt32 addr, UInt8* option /* NULL if none */);
|
||||
typedef Boolean (*ArmCoprocTwoRegF) (struct ArmCpu* cpu, void* userData, Boolean MRRC, UInt8 op, UInt8 Rd, UInt8 Rn, UInt8 CRm);
|
||||
|
||||
typedef Boolean (*ArmCpuMemF) (struct ArmCpu* cpu, void* buf, UInt32 vaddr, UInt8 size, Boolean write, Boolean priviledged, UInt8* fsr); //read/write
|
||||
typedef Boolean (*ArmCpuHypercall) (struct ArmCpu* cpu); //return true if handled
|
||||
typedef void (*ArmCpuEmulErr) (struct ArmCpu* cpu, const char* err_str);
|
||||
|
||||
typedef void (*ArmSetFaultAdrF) (struct ArmCpu* cpu, UInt32 adr, UInt8 faultStatus);
|
||||
|
||||
#include "icache.h"
|
||||
|
||||
|
||||
/*
|
||||
|
||||
coprocessors:
|
||||
|
||||
0 - DSP (pxa only)
|
||||
0, 1 - WMMX (pxa only)
|
||||
11 - VFP (arm standard)
|
||||
15 - system control (arm standard)
|
||||
*/
|
||||
|
||||
|
||||
typedef struct{
|
||||
|
||||
ArmCoprocRegXferF regXfer;
|
||||
ArmCoprocDatProcF dataProcessing;
|
||||
ArmCoprocMemAccsF memAccess;
|
||||
ArmCoprocTwoRegF twoRegF;
|
||||
void* userData;
|
||||
|
||||
}ArmCoprocessor;
|
||||
|
||||
typedef struct{
|
||||
|
||||
UInt32 R13, R14;
|
||||
UInt32 SPSR; //usr mode doesn't have an SPSR
|
||||
}ArmBankedRegs;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
typedef struct ArmCpu{
|
||||
|
||||
UInt32 regs[16]; //current active regs as per current mode
|
||||
UInt32 CPSR, SPSR;
|
||||
|
||||
ArmBankedRegs bank_usr; //usr regs when in another mode
|
||||
ArmBankedRegs bank_svc; //svc regs when in another mode
|
||||
ArmBankedRegs bank_abt; //abt regs when in another mode
|
||||
ArmBankedRegs bank_und; //und regs when in another mode
|
||||
ArmBankedRegs bank_irq; //irq regs when in another mode
|
||||
ArmBankedRegs bank_fiq; //fiq regs when in another mode
|
||||
UInt32 extra_regs[5]; //fiq regs when not in fiq mode, usr regs when in fiq mode. R8-12
|
||||
|
||||
UInt16 waitingIrqs;
|
||||
UInt16 waitingFiqs;
|
||||
UInt16 CPAR;
|
||||
|
||||
ArmCoprocessor coproc[16]; //coprocessors
|
||||
|
||||
// various other cpu config options
|
||||
UInt32 vectorBase; //address of vector base
|
||||
|
||||
#ifdef ARM_V6
|
||||
|
||||
Boolean EEE; //endianness one exception entry
|
||||
Boolean impreciseAbtWaiting;
|
||||
#endif
|
||||
|
||||
ArmCpuMemF memF;
|
||||
ArmCpuEmulErr emulErrF;
|
||||
ArmCpuHypercall hypercallF;
|
||||
ArmSetFaultAdrF setFaultAdrF;
|
||||
|
||||
icache ic;
|
||||
|
||||
void* userData; //shared by all callbacks
|
||||
}ArmCpu;
|
||||
|
||||
|
||||
Err cpuInit(ArmCpu* cpu, UInt32 pc, ArmCpuMemF memF, ArmCpuEmulErr emulErrF, ArmCpuHypercall hypercallF, ArmSetFaultAdrF setFaultAdrF);
|
||||
Err cpuDeinit(ArmCpu* cp);
|
||||
void cpuCycle(ArmCpu* cpu);
|
||||
void cpuIrq(ArmCpu* cpu, Boolean fiq, Boolean raise); //unraise when acknowledged
|
||||
|
||||
#ifdef ARM_V6
|
||||
|
||||
void cpuSignalImpreciseAbt(ArmCpu* cpu, Boolean raise);
|
||||
|
||||
#endif
|
||||
|
||||
UInt32 cpuGetRegExternal(ArmCpu* cpu, UInt8 reg);
|
||||
void cpuSetReg(ArmCpu* cpu, UInt8 reg, UInt32 val);
|
||||
|
||||
void cpuCoprocessorRegister(ArmCpu* cpu, UInt8 cpNum, ArmCoprocessor* coproc);
|
||||
void cpuCoprocessorUnregister(ArmCpu* cpu, UInt8 cpNum);
|
||||
|
||||
void cpuSetVectorAddr(ArmCpu* cpu, UInt32 adr);
|
||||
|
||||
UInt16 cpuGetCPAR(ArmCpu* cpu);
|
||||
void cpuSetCPAR(ArmCpu* cpu, UInt16 cpar);
|
||||
|
||||
void cpuIcacheInval(ArmCpu* cpu);
|
||||
void cpuIcacheInvalAddr(ArmCpu* cpu, UInt32 addr);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
140
src/armv5te/uArm/icache.c
Normal file
140
src/armv5te/uArm/icache.c
Normal file
@@ -0,0 +1,140 @@
|
||||
#include "../../pxa260/pxa260_types.h"
|
||||
#include "CPU_2.h"
|
||||
#include "icache.h"
|
||||
|
||||
//#define ICACHE_DEBUGGING
|
||||
|
||||
|
||||
|
||||
#ifdef ICACHE_DEBUGGING
|
||||
#define _icache_fetch_func icacheFetch_
|
||||
#define _icache_test_func icacheFetch
|
||||
#else
|
||||
#define _icache_fetch_func icacheFetch
|
||||
#define _icache_test_func icacheFetch_test
|
||||
#endif
|
||||
|
||||
void icacheInval(icache* ic){
|
||||
|
||||
UInt8 i, j;
|
||||
|
||||
for(i = 0; i < ICACHE_BUCKET_NUM; i++){
|
||||
for(j = 0; j < ICACHE_BUCKET_SZ; j++) ic->lines[i][j].info = 0;
|
||||
ic->ptr[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void icacheInit(icache* ic, ArmCpu* cpu, ArmCpuMemF memF){
|
||||
|
||||
ic->cpu = cpu;
|
||||
ic->memF = memF;
|
||||
|
||||
icacheInval(ic);
|
||||
}
|
||||
|
||||
|
||||
static UInt8 icachePrvHash(UInt32 addr){
|
||||
|
||||
addr >>= ICACHE_L;
|
||||
addr &= (1UL << ICACHE_S) - 1UL;
|
||||
|
||||
return addr;
|
||||
}
|
||||
|
||||
void icacheInvalAddr(icache* ic, UInt32 va){
|
||||
|
||||
UInt32 off = va % ICACHE_LINE_SZ;
|
||||
Int8 i, j, bucket;
|
||||
icacheLine* lines;
|
||||
|
||||
va -= off;
|
||||
|
||||
bucket = icachePrvHash(va);
|
||||
lines = ic->lines[bucket];
|
||||
|
||||
for(i = 0, j = ic->ptr[bucket]; (UInt8)i < ICACHE_BUCKET_SZ; i++){
|
||||
|
||||
if(--j == -1) j = ICACHE_BUCKET_SZ - 1;
|
||||
|
||||
if((lines[j].info & (ICACHE_ADDR_MASK | ICACHE_USED_MASK)) == (va | ICACHE_USED_MASK)){ //found it!
|
||||
|
||||
lines[j].info = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
we cannot have data overlap cachelines since data is self aligned (word on 4-byte boundary, halfwords on2, etc. this is enforced elsewhere
|
||||
*/
|
||||
|
||||
Boolean _icache_fetch_func(icache* ic, UInt32 va, UInt8 sz, Boolean priviledged, UInt8* fsrP, void* buf){
|
||||
|
||||
UInt32 off = va % ICACHE_LINE_SZ;
|
||||
Int8 i, j, bucket;
|
||||
icacheLine* lines;
|
||||
icacheLine* line;
|
||||
|
||||
va -= off;
|
||||
|
||||
bucket = icachePrvHash(va);
|
||||
lines = ic->lines[bucket];
|
||||
|
||||
for(i = 0, j = ic->ptr[bucket]; (UInt8)i < ICACHE_BUCKET_SZ; i++){
|
||||
|
||||
if(--j == -1) j = ICACHE_BUCKET_SZ - 1;
|
||||
|
||||
if((lines[j].info & (ICACHE_ADDR_MASK | ICACHE_USED_MASK)) == (va | ICACHE_USED_MASK)){ //found it!
|
||||
|
||||
if(sz == 4){
|
||||
*(UInt32*)buf = *(UInt32*)(lines[j].data + off);
|
||||
}
|
||||
else if(sz == 2){
|
||||
*(UInt16*)buf = *(UInt16*)(lines[j].data + off);
|
||||
}
|
||||
else __mem_copy(buf, lines[j].data + off, sz);
|
||||
return priviledged || !(lines[j].info & ICACHE_PRIV_MASK);
|
||||
}
|
||||
}
|
||||
//if we're here, we found nothing - time to populate the cache
|
||||
j = ic->ptr[bucket]++;
|
||||
if(ic->ptr[bucket] == ICACHE_BUCKET_SZ) ic->ptr[bucket] = 0;
|
||||
line = lines + j;
|
||||
|
||||
line->info = va | (priviledged ? ICACHE_PRIV_MASK : 0);
|
||||
if(!ic->memF(ic->cpu, line->data, va, ICACHE_LINE_SZ, false, priviledged, fsrP)){
|
||||
|
||||
return false;
|
||||
}
|
||||
line->info |= ICACHE_USED_MASK;
|
||||
|
||||
if(sz == 4){
|
||||
*(UInt32*)buf = *(UInt32*)(line->data + off);
|
||||
}
|
||||
else if(sz == 2){
|
||||
*(UInt16*)buf = *(UInt16*)(line->data + off);
|
||||
}
|
||||
else __mem_copy(buf, line->data + off, sz);
|
||||
return true;
|
||||
}
|
||||
|
||||
#include "stdio.h"
|
||||
Boolean _icache_test_func(icache* ic, UInt32 va, UInt8 sz, Boolean priviledged, UInt8* fsrP, void* buf){
|
||||
|
||||
UInt8 fsrO = -1, fsrT = -1;
|
||||
UInt8 dataO[4] = {0}, dataT[4] = {0};
|
||||
Boolean retO, retT;
|
||||
UInt8 i;
|
||||
|
||||
retO = _icache_fetch_func(ic, va, sz, priviledged, &fsrO, dataO);
|
||||
retT = ic->memF(ic->cpu, dataT, va, sz, false, priviledged, &fsrT);
|
||||
|
||||
if((retT != retO) || (fsrT != fsrO) || (dataT[0] != dataO[0]) || (dataT[1] != dataO[1]) || (dataT[2] != dataO[2]) || (dataT[3] != dataO[3])){
|
||||
|
||||
fprintf(stderr, "icache fail!");
|
||||
}
|
||||
|
||||
for(i = 0; i < sz; i++) ((UInt8*)buf)[i] = dataT[i];
|
||||
if(retT) *fsrP = fsrT;
|
||||
return retT;
|
||||
}
|
||||
|
||||
47
src/armv5te/uArm/icache.h
Normal file
47
src/armv5te/uArm/icache.h
Normal file
@@ -0,0 +1,47 @@
|
||||
#ifndef ICACHE_H
|
||||
#define ICACHE_H
|
||||
|
||||
|
||||
#include "../../pxa260/pxa260_types.h"
|
||||
#include "CPU_2.h"
|
||||
|
||||
|
||||
#define ICACHE_L 5UL //line size is 2^L bytes
|
||||
#define ICACHE_S 6UL //number of sets is 2^S
|
||||
#define ICACHE_A 3UL //set associativity
|
||||
|
||||
|
||||
#define ICACHE_LINE_SZ (1UL << ICACHE_L)
|
||||
#define ICACHE_BUCKET_NUM (1UL << ICACHE_S)
|
||||
#define ICACHE_BUCKET_SZ (ICACHE_A)
|
||||
|
||||
|
||||
#define ICACHE_ADDR_MASK ((UInt32)-ICACHE_LINE_SZ)
|
||||
#define ICACHE_USED_MASK 1UL
|
||||
#define ICACHE_PRIV_MASK 2UL
|
||||
|
||||
typedef struct{
|
||||
|
||||
UInt32 info; //addr, masks
|
||||
UInt8 data[ICACHE_LINE_SZ];
|
||||
|
||||
}icacheLine;
|
||||
|
||||
typedef struct{
|
||||
|
||||
struct ArmCpu* cpu;
|
||||
ArmCpuMemF memF;
|
||||
icacheLine lines[ICACHE_BUCKET_NUM][ICACHE_BUCKET_SZ];
|
||||
UInt8 ptr[ICACHE_BUCKET_NUM];
|
||||
|
||||
}icache;
|
||||
|
||||
|
||||
void icacheInit(icache* ic, struct ArmCpu* cpu, ArmCpuMemF memF);
|
||||
Boolean icacheFetch(icache* ic, UInt32 va, UInt8 sz, Boolean priviledged, UInt8* fsr, void* buf);
|
||||
void icacheInval(icache* ic);
|
||||
void icacheInvalAddr(icache* ic, UInt32 addr);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
164
src/armv5te/uArm/uArmGlue.cpp
Normal file
164
src/armv5te/uArm/uArmGlue.cpp
Normal file
@@ -0,0 +1,164 @@
|
||||
#include "uArmGlue.h"
|
||||
#include "CPU_2.h"
|
||||
|
||||
#include "../../emulator.h"
|
||||
#include "../../armv5te/cpu.h"
|
||||
#include "../../armv5te/asmcode.h"
|
||||
#include "../../armv5te/cpudefs.h"
|
||||
#include "../../pxa260/pxa260.h"
|
||||
|
||||
|
||||
static ArmCoprocessor uArmCp14;
|
||||
static ArmCoprocessor uArmCp15;
|
||||
|
||||
|
||||
Boolean uArmCp14RegXferF (struct ArmCpu* cpu, void* userData, Boolean two/* MCR2/MRC2 ? */, Boolean MRC, UInt8 op1, UInt8 Rx, UInt8 CRn, UInt8 CRm, UInt8 op2){
|
||||
//if(!cpu->coproc[vb8].regXfer(cpu, cpu->coproc[vb8].userData, specialInstr, (instr & 0x00100000UL) != 0, (instr >> 21) & 0x07, (instr >> 12) & 0x0F, (instr >> 16) & 0x0F, instr & 0x0F, (instr >> 5) & 0x07)) goto invalid_instr;
|
||||
Instruction inst;
|
||||
|
||||
inst.raw = 0xE000E10 | op1 << 21 | Rx << 12 | CRn << 16 | CRm | op2 << 5;
|
||||
|
||||
if(MRC)
|
||||
inst.raw |= 0x00100000;
|
||||
|
||||
do_cp14_instruction(inst);
|
||||
return true;
|
||||
}
|
||||
|
||||
Boolean uArmCp14DatProcF (struct ArmCpu* cpu, void* userData, Boolean two/* CDP2 ? */, UInt8 op1, UInt8 CRd, UInt8 CRn, UInt8 CRm, UInt8 op2){
|
||||
debugLog("uARM CP14 dat proc unimplemented\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
Boolean uArmCp14MemAccsF (struct ArmCpu* cpu, void* userData, Boolean two /* LDC2/STC2 ? */, Boolean N, Boolean store, UInt8 CRd, UInt32 addr, UInt8* option /* NULL if none */){
|
||||
debugLog("uARM CP14 mem access unimplemented\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
Boolean uArmCp14TwoRegF (struct ArmCpu* cpu, void* userData, Boolean MRRC, UInt8 op, UInt8 Rd, UInt8 Rn, UInt8 CRm){
|
||||
debugLog("uARM CP14 2 reg access unimplemented\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
Boolean uArmCp15RegXferF (struct ArmCpu* cpu, void* userData, Boolean two/* MCR2/MRC2 ? */, Boolean MRC, UInt8 op1, UInt8 Rx, UInt8 CRn, UInt8 CRm, UInt8 op2){
|
||||
//if(!cpu->coproc[vb8].regXfer(cpu, cpu->coproc[vb8].userData, specialInstr, (instr & 0x00100000UL) != 0, (instr >> 21) & 0x07, (instr >> 12) & 0x0F, (instr >> 16) & 0x0F, instr & 0x0F, (instr >> 5) & 0x07)) goto invalid_instr;
|
||||
Instruction inst;
|
||||
|
||||
if(two)
|
||||
debugLog("uARM unimplemented 2 register CP15 access\n");
|
||||
|
||||
if(Rx == 15)
|
||||
set_cpsr_full(pxa260CpuState.CPSR);
|
||||
else
|
||||
arm.reg[Rx] = pxa260CpuState.regs[Rx];
|
||||
|
||||
inst.raw = 0xE000F10 | op1 << 21 | Rx << 12 | CRn << 16 | CRm | op2 << 5;
|
||||
|
||||
if(MRC)
|
||||
inst.raw |= 0x00100000;
|
||||
|
||||
do_cp15_instruction(inst);
|
||||
//addr_cache_flush handles icache flushing too
|
||||
|
||||
if(Rx == 15)
|
||||
pxa260CpuState.CPSR = get_cpsr();//this could be catastrophic in any other circumstance but only the CPSR data flags can be changed by CP15
|
||||
else
|
||||
pxa260CpuState.regs[Rx] = arm.reg[Rx];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Boolean uArmCp15DatProcF (struct ArmCpu* cpu, void* userData, Boolean two/* CDP2 ? */, UInt8 op1, UInt8 CRd, UInt8 CRn, UInt8 CRm, UInt8 op2){
|
||||
debugLog("uARM CP15 dat proc unimplemented\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
Boolean uArmCp15MemAccsF (struct ArmCpu* cpu, void* userData, Boolean two /* LDC2/STC2 ? */, Boolean N, Boolean store, UInt8 CRd, UInt32 addr, UInt8* option /* NULL if none */){
|
||||
debugLog("uARM CP15 mem access unimplemented\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
Boolean uArmCp15TwoRegF (struct ArmCpu* cpu, void* userData, Boolean MRRC, UInt8 op, UInt8 Rd, UInt8 Rn, UInt8 CRm){
|
||||
debugLog("uARM CP15 2 reg access unimplemented\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
Boolean uArmMemAccess(struct ArmCpu* cpu, void* buf, UInt32 vaddr, UInt8 size, Boolean write, Boolean priviledged, UInt8* fsr){
|
||||
if(write){
|
||||
switch(size){
|
||||
case 1:
|
||||
write_byte(vaddr, *(uint8_t*)buf);
|
||||
return true;
|
||||
|
||||
case 2:
|
||||
write_half(vaddr, *(uint16_t*)buf);
|
||||
return true;
|
||||
|
||||
case 4:
|
||||
write_word(vaddr, *(uint32_t*)buf);
|
||||
return true;
|
||||
|
||||
default:
|
||||
debugLog("uARM wrote memory with invalid byte count:%d\n", size);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else{
|
||||
switch(size){
|
||||
case 1:
|
||||
*(uint8_t*)buf = read_byte(vaddr);
|
||||
return true;
|
||||
|
||||
case 2:
|
||||
*(uint16_t*)buf = read_half(vaddr);
|
||||
return true;
|
||||
|
||||
case 4:
|
||||
*(uint32_t*)buf = read_word(vaddr);
|
||||
return true;
|
||||
|
||||
case 32:
|
||||
((uint32_t*)buf)[0] = read_word(vaddr);
|
||||
((uint32_t*)buf)[1] = read_word(vaddr + 4);
|
||||
((uint32_t*)buf)[2] = read_word(vaddr + 8);
|
||||
((uint32_t*)buf)[3] = read_word(vaddr + 12);
|
||||
((uint32_t*)buf)[4] = read_word(vaddr + 16);
|
||||
((uint32_t*)buf)[5] = read_word(vaddr + 20);
|
||||
((uint32_t*)buf)[6] = read_word(vaddr + 24);
|
||||
((uint32_t*)buf)[7] = read_word(vaddr + 28);
|
||||
return true;
|
||||
|
||||
default:
|
||||
debugLog("uARM read memory with invalid byte count:%d\n", size);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Boolean uArmHypercall(struct ArmCpu* cpu){
|
||||
//no hypercalls
|
||||
return true;
|
||||
}
|
||||
|
||||
void uArmEmulErr (struct ArmCpu* cpu, const char* err_str){
|
||||
debugLog("uARM error:%s\n", err_str);
|
||||
}
|
||||
|
||||
void uArmSetFaultAddr(struct ArmCpu* cpu, UInt32 adr, UInt8 faultStatus){
|
||||
debugLog("uARM set fault addr:0x%08X, status:0x%02X\n", adr, faultStatus);
|
||||
}
|
||||
|
||||
void uArmInitCpXX(ArmCpu* cpu){
|
||||
uArmCp14.regXfer = uArmCp14RegXferF;
|
||||
uArmCp14.dataProcessing = uArmCp14DatProcF;
|
||||
uArmCp14.memAccess = uArmCp14MemAccsF;
|
||||
uArmCp14.twoRegF = uArmCp14TwoRegF;
|
||||
|
||||
uArmCp15.regXfer = uArmCp15RegXferF;
|
||||
uArmCp15.dataProcessing = uArmCp15DatProcF;
|
||||
uArmCp15.memAccess = uArmCp15MemAccsF;
|
||||
uArmCp15.twoRegF = uArmCp15TwoRegF;
|
||||
|
||||
cpuCoprocessorRegister(cpu, 14, &uArmCp14);
|
||||
cpuCoprocessorRegister(cpu, 15, &uArmCp15);
|
||||
}
|
||||
21
src/armv5te/uArm/uArmGlue.h
Normal file
21
src/armv5te/uArm/uArmGlue.h
Normal file
@@ -0,0 +1,21 @@
|
||||
#ifndef UARM_GLUE_H
|
||||
#define UARM_GLUE_H
|
||||
|
||||
#include "CPU_2.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
Boolean uArmMemAccess(struct ArmCpu* cpu, void* buf, UInt32 vaddr, UInt8 size, Boolean write, Boolean priviledged, UInt8* fsr); //read/write
|
||||
Boolean uArmHypercall(struct ArmCpu* cpu);//return true if handled
|
||||
void uArmEmulErr (struct ArmCpu* cpu, const char* err_str);
|
||||
void uArmSetFaultAddr(struct ArmCpu* cpu, UInt32 adr, UInt8 faultStatus);
|
||||
|
||||
void uArmInitCpXX(ArmCpu* cpu);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -41,13 +41,16 @@ ifeq ($(EMU_SUPPORT_PALM_OS5), 1)
|
||||
$(EMU_PATH)/pxa260/pxa260Ssp.c \
|
||||
$(EMU_PATH)/pxa260/pxa260Udc.c \
|
||||
$(EMU_PATH)/pxa260/pxa260.c \
|
||||
$(EMU_PATH)/armv5te/uArm/CPU_2.c \
|
||||
$(EMU_PATH)/armv5te/uArm/icache.c \
|
||||
$(EMU_PATH)/armv5te/emuVarPool.c \
|
||||
$(EMU_PATH)/armv5te/mem.c \
|
||||
$(EMU_PATH)/armv5te/mmu.c \
|
||||
$(EMU_PATH)/tps65010.c \
|
||||
$(EMU_PATH)/tsc2101.c \
|
||||
$(EMU_PATH)/w86l488.c
|
||||
EMU_SOURCES_CXX += $(EMU_PATH)/armv5te/arm_interpreter.cpp \
|
||||
EMU_SOURCES_CXX += $(EMU_PATH)/armv5te/uArm/uArmGlue.cpp \
|
||||
$(EMU_PATH)/armv5te/arm_interpreter.cpp \
|
||||
$(EMU_PATH)/armv5te/thumb_interpreter.cpp \
|
||||
$(EMU_PATH)/armv5te/cpu.cpp \
|
||||
$(EMU_PATH)/armv5te/coproc.cpp
|
||||
|
||||
@@ -16,6 +16,10 @@
|
||||
#include "pxa260Ssp.h"
|
||||
#include "pxa260Udc.h"
|
||||
#include "pxa260Timing.h"
|
||||
#if !defined(EMU_NO_SAFETY)
|
||||
#include "../armv5te/uArm/CPU_2.h"
|
||||
#include "../armv5te/uArm/uArmGlue.h"
|
||||
#endif
|
||||
#include "../armv5te/cpu.h"
|
||||
#include "../armv5te/emu.h"
|
||||
#include "../armv5te/mem.h"
|
||||
@@ -33,7 +37,9 @@
|
||||
|
||||
#define PXA260_TIMER_TICKS_PER_FRAME (TUNGSTEN_T3_CPU_CRYSTAL_FREQUENCY / EMU_FPS)
|
||||
|
||||
|
||||
#if !defined(EMU_NO_SAFETY)
|
||||
ArmCpu pxa260CpuState;
|
||||
#endif
|
||||
uint16_t* pxa260Framebuffer;
|
||||
Pxa260pwrClk pxa260PwrClk;
|
||||
Pxa260ic pxa260Ic;
|
||||
@@ -194,12 +200,19 @@ void pxa260Reset(void){
|
||||
//set first timer event
|
||||
pxa260TimingTriggerEvent(PXA260_TIMING_CALLBACK_TICK_CPU_TIMER, TUNGSTEN_T3_CPU_PLL_FREQUENCY / TUNGSTEN_T3_CPU_CRYSTAL_FREQUENCY);
|
||||
|
||||
#if !defined(EMU_NO_SAFETY)
|
||||
debugLog("Using uARM CPU core!\n");
|
||||
cpuInit(&pxa260CpuState, 0x00000000, uArmMemAccess, uArmEmulErr, uArmHypercall, uArmSetFaultAddr);
|
||||
uArmInitCpXX(&pxa260CpuState);
|
||||
#else
|
||||
memset(&arm, 0, sizeof arm);
|
||||
arm.control = 0x00050078;
|
||||
arm.cpsr_low28 = MODE_SVC | 0xC0;
|
||||
cycle_count_delta = 0;
|
||||
cpu_events = 0;
|
||||
//cpu_events &= EVENT_DEBUG_STEP;
|
||||
#endif
|
||||
|
||||
addr_cache_flush();//SIGSEGVs on reset without this because the MMU needs to be turned off
|
||||
|
||||
//PC starts at 0x00000000, the first opcode for Palm OS 5 is a jump
|
||||
@@ -226,8 +239,6 @@ void pxa260LoadState(uint8_t* data){
|
||||
}
|
||||
|
||||
void pxa260Execute(bool wantVideo){
|
||||
uint32_t index;
|
||||
|
||||
tsc2101UpdateInterrupt();
|
||||
tps65010UpdateInterrupt();
|
||||
pxa260gpioUpdateKeyMatrix(&pxa260Gpio);
|
||||
@@ -240,15 +251,27 @@ void pxa260Execute(bool wantVideo){
|
||||
}
|
||||
|
||||
uint32_t pxa260GetRegister(uint8_t reg){
|
||||
#if !defined(EMU_NO_SAFETY)
|
||||
return cpuGetRegExternal(&pxa260CpuState, reg);
|
||||
#else
|
||||
return reg_pc_mem(reg);
|
||||
#endif
|
||||
}
|
||||
|
||||
uint32_t pxa260GetCpsr(void){
|
||||
#if !defined(EMU_NO_SAFETY)
|
||||
return cpuGetRegExternal(&pxa260CpuState, ARM_REG_NUM_CPSR);
|
||||
#else
|
||||
return get_cpsr();
|
||||
#endif
|
||||
}
|
||||
|
||||
uint32_t pxa260GetSpsr(void){
|
||||
#if !defined(EMU_NO_SAFETY)
|
||||
return cpuGetRegExternal(&pxa260CpuState, ARM_REG_NUM_SPSR);
|
||||
#else
|
||||
return get_spsr();
|
||||
#endif
|
||||
}
|
||||
|
||||
uint64_t pxa260ReadArbitraryMemory(uint32_t address, uint8_t size){
|
||||
|
||||
@@ -11,7 +11,13 @@
|
||||
#include "pxa260_PwrClk.h"
|
||||
#include "pxa260_GPIO.h"
|
||||
#include "pxa260_TIMR.h"
|
||||
#if !defined(EMU_NO_SAFETY)
|
||||
#include "../armv5te/uArm/CPU_2.h"
|
||||
#endif
|
||||
|
||||
#if !defined(EMU_NO_SAFETY)
|
||||
extern ArmCpu pxa260CpuState;
|
||||
#endif
|
||||
extern uint16_t* pxa260Framebuffer;
|
||||
extern Pxa260pwrClk pxa260PwrClk;
|
||||
extern Pxa260ic pxa260Ic;
|
||||
|
||||
@@ -120,57 +120,57 @@ static void pxa260_lcd_write_word(uint32_t addr, uint32_t value){
|
||||
}
|
||||
|
||||
static uint8_t pxa260_pcmcia0_read_byte(uint32_t addr){
|
||||
debugLog("PCMCIA0 8 bit read:0x%08X\n", addr);
|
||||
debugLog("PCMCIA0 8 bit read:0x%08X, PC:0x%08X\n", addr, pxa260GetPc());
|
||||
return 0x00;
|
||||
}
|
||||
|
||||
static uint16_t pxa260_pcmcia0_read_half(uint32_t addr){
|
||||
debugLog("PCMCIA0 16 bit read:0x%08X\n", addr);
|
||||
debugLog("PCMCIA0 16 bit read:0x%08X, PC:0x%08X\n", addr, pxa260GetPc());
|
||||
return 0x0000;
|
||||
}
|
||||
|
||||
static uint32_t pxa260_pcmcia0_read_word(uint32_t addr){
|
||||
debugLog("PCMCIA0 32 bit read:0x%08X\n", addr);
|
||||
debugLog("PCMCIA0 32 bit read:0x%08X, PC:0x%08X\n", addr, pxa260GetPc());
|
||||
return 0x00000000;
|
||||
}
|
||||
|
||||
static void pxa260_pcmcia0_write_byte(uint32_t addr, uint8_t value){
|
||||
debugLog("PCMCIA0 8 bit write:0x%08X, value:0x%02X\n", addr, value);
|
||||
debugLog("PCMCIA0 8 bit write:0x%08X, value:0x%02X, PC:0x%08X\n", addr, value, pxa260GetPc());
|
||||
}
|
||||
|
||||
static void pxa260_pcmcia0_write_half(uint32_t addr, uint16_t value){
|
||||
debugLog("PCMCIA0 16 bit write:0x%08X, value:0x%04X\n", addr, value);
|
||||
debugLog("PCMCIA0 16 bit write:0x%08X, value:0x%04X, PC:0x%08X\n", addr, value, pxa260GetPc());
|
||||
}
|
||||
|
||||
static void pxa260_pcmcia0_write_word(uint32_t addr, uint32_t value){
|
||||
debugLog("PCMCIA0 32 bit write:0x%08X, value:0x%08X\n", addr, value);
|
||||
debugLog("PCMCIA0 32 bit write:0x%08X, value:0x%08X, PC:0x%08X\n", addr, value, pxa260GetPc());
|
||||
}
|
||||
|
||||
static uint8_t pxa260_pcmcia1_read_byte(uint32_t addr){
|
||||
debugLog("PCMCIA1 8 bit read:0x%08X\n", addr);
|
||||
debugLog("PCMCIA1 8 bit read:0x%08X, PC:0x%08X\n", addr, pxa260GetPc());
|
||||
return 0x00;
|
||||
}
|
||||
|
||||
static uint16_t pxa260_pcmcia1_read_half(uint32_t addr){
|
||||
debugLog("PCMCIA1 16 bit read:0x%08X\n", addr);
|
||||
debugLog("PCMCIA1 16 bit read:0x%08X, PC:0x%08X\n", addr, pxa260GetPc());
|
||||
return 0x0000;
|
||||
}
|
||||
|
||||
static uint32_t pxa260_pcmcia1_read_word(uint32_t addr){
|
||||
debugLog("PCMCIA1 32 bit read:0x%08X\n", addr);
|
||||
debugLog("PCMCIA1 32 bit read:0x%08X, PC:0x%08X\n", addr, pxa260GetPc());
|
||||
return 0x00000000;
|
||||
}
|
||||
|
||||
static void pxa260_pcmcia1_write_byte(uint32_t addr, uint8_t value){
|
||||
debugLog("PCMCIA1 8 bit write:0x%08X, value:0x%02X\n", addr, value);
|
||||
debugLog("PCMCIA1 8 bit write:0x%08X, value:0x%02X, PC:0x%08X\n", addr, value, pxa260GetPc());
|
||||
}
|
||||
|
||||
static void pxa260_pcmcia1_write_half(uint32_t addr, uint16_t value){
|
||||
debugLog("PCMCIA1 16 bit write:0x%08X, value:0x%04X\n", addr, value);
|
||||
debugLog("PCMCIA1 16 bit write:0x%08X, value:0x%04X, PC:0x%08X\n", addr, value, pxa260GetPc());
|
||||
}
|
||||
|
||||
static void pxa260_pcmcia1_write_word(uint32_t addr, uint32_t value){
|
||||
debugLog("PCMCIA1 32 bit write:0x%08X, value:0x%08X\n", addr, value);
|
||||
debugLog("PCMCIA1 32 bit write:0x%08X, value:0x%08X, PC:0x%08X\n", addr, value, pxa260GetPc());
|
||||
}
|
||||
|
||||
static uint16_t pxa260_static_chip_select_2_read_half(uint32_t addr){
|
||||
|
||||
@@ -9,6 +9,9 @@
|
||||
#include "pxa260Udc.h"
|
||||
#include "pxa260Timing.h"
|
||||
#include "../tsc2101.h"
|
||||
#if !defined(EMU_NO_SAFETY)
|
||||
#include "../armv5te/uArm/CPU_2.h"
|
||||
#endif
|
||||
#include "../armv5te/os/os.h"
|
||||
#include "../armv5te/emu.h"
|
||||
#include "../armv5te/cpu.h"
|
||||
@@ -83,25 +86,30 @@ void pxa260TimingRun(int32_t cycles){
|
||||
cycle_count_delta = -addCycles * palmClockMultiplier;
|
||||
|
||||
while (!exiting && cycle_count_delta < 0) {
|
||||
if (cpu_events & (EVENT_FIQ | EVENT_IRQ)) {
|
||||
// Align PC in case the interrupt occurred immediately after a jump
|
||||
if (arm.cpsr_low28 & 0x20)
|
||||
arm.reg[15] &= ~1;
|
||||
else
|
||||
arm.reg[15] &= ~3;
|
||||
#if !defined(EMU_NO_SAFETY)
|
||||
cpuCycle(&pxa260CpuState);
|
||||
cycle_count_delta += 1;
|
||||
#else
|
||||
if (cpu_events & (EVENT_FIQ | EVENT_IRQ)) {
|
||||
// Align PC in case the interrupt occurred immediately after a jump
|
||||
if (arm.cpsr_low28 & 0x20)
|
||||
arm.reg[15] &= ~1;
|
||||
else
|
||||
arm.reg[15] &= ~3;
|
||||
|
||||
if (cpu_events & EVENT_WAITING)
|
||||
arm.reg[15] += 4; // Skip over wait instruction
|
||||
if (cpu_events & EVENT_WAITING)
|
||||
arm.reg[15] += 4; // Skip over wait instruction
|
||||
|
||||
arm.reg[15] += 4;
|
||||
cpu_exception((cpu_events & EVENT_FIQ) ? EX_FIQ : EX_IRQ);
|
||||
}
|
||||
cpu_events &= ~EVENT_WAITING;//the wait opcode will be executed again if still waiting, that will clear the remaining cycle count and exit the function again
|
||||
arm.reg[15] += 4;
|
||||
cpu_exception((cpu_events & EVENT_FIQ) ? EX_FIQ : EX_IRQ);
|
||||
}
|
||||
cpu_events &= ~EVENT_WAITING;//the wait opcode will be executed again if still waiting, that will clear the remaining cycle count and exit the function again
|
||||
|
||||
if (arm.cpsr_low28 & 0x20)
|
||||
cpu_thumb_loop();
|
||||
else
|
||||
cpu_arm_loop();
|
||||
if (arm.cpsr_low28 & 0x20)
|
||||
cpu_thumb_loop();
|
||||
else
|
||||
cpu_arm_loop();
|
||||
#endif
|
||||
}
|
||||
|
||||
//if more then the requested cycles are executed count those too
|
||||
|
||||
@@ -2,23 +2,18 @@
|
||||
#define PXA260_CPU_H
|
||||
|
||||
#include "pxa260_types.h"
|
||||
|
||||
#if defined(EMU_NO_SAFETY)
|
||||
#include "../armv5te/emu.h"
|
||||
#include "../armv5te/cpu.h"
|
||||
|
||||
//UInt32 cpuGetRegExternal(ArmCpu* cpu, UInt8 reg);
|
||||
//void cpuSetReg(ArmCpu* cpu, UInt8 reg, UInt32 val);
|
||||
#define cpuGetRegExternal(x, regNum) reg_pc(regNum)
|
||||
#define cpuSetReg(x, regNum, value) set_reg(regNum, value)
|
||||
|
||||
//void cpuIrq(ArmCpu* cpu, Boolean fiq, Boolean raise); //unraise when acknowledged
|
||||
//#define cpuIrq(x, fiq, raise) if(raise)cpu_exception(fiq ? EX_FIQ : EX_IRQ)
|
||||
#define cpuIrq(x, fiq, raise) (raise ? (cpu_events |= (fiq ? EVENT_FIQ : EVENT_IRQ)) : (cpu_events &= (fiq ? ~EVENT_FIQ : ~EVENT_IRQ)))
|
||||
|
||||
//void cpuCoprocessorRegister(ArmCpu* cpu, UInt8 cpNum, ArmCoprocessor* coproc);
|
||||
//void cpuCoprocessorUnregister(ArmCpu* cpu, UInt8 cpNum);
|
||||
#define cpuCoprocessorRegister(x, y, z)
|
||||
#define cpuCoprocessorUnregister(x, y)
|
||||
//TODO: may need to actually implement these
|
||||
#else
|
||||
#include "../armv5te/uArm/CPU_2.h"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "pxa260_math64.h"
|
||||
#include "pxa260_CPU.h"
|
||||
#include "pxa260_DSP.h"
|
||||
#include "pxa260.h"
|
||||
|
||||
|
||||
Boolean pxa260dspAccess(void* userData, Boolean MRRC, UInt8 op, UInt8 RdLo, UInt8 RdHi, UInt8 acc){
|
||||
@@ -11,18 +12,18 @@ Boolean pxa260dspAccess(void* userData, Boolean MRRC, UInt8 op, UInt8 RdLo, UInt
|
||||
|
||||
if(MRRC){ //MRA: read acc0
|
||||
|
||||
cpuSetReg(cpu, RdLo, u64_64_to_32(dsp->acc0));
|
||||
cpuSetReg(cpu, RdHi, (UInt8)u64_get_hi(dsp->acc0));
|
||||
cpuSetReg(&pxa260CpuState, RdLo, u64_64_to_32(dsp->acc0));
|
||||
cpuSetReg(&pxa260CpuState, RdHi, (UInt8)u64_get_hi(dsp->acc0));
|
||||
}
|
||||
else{ //MAR: write acc0
|
||||
|
||||
dsp->acc0 = u64_from_halves(cpuGetRegExternal(cpu, RdHi) & 0xFF, cpuGetRegExternal(cpu, RdLo));
|
||||
dsp->acc0 = u64_from_halves(cpuGetRegExternal(&pxa260CpuState, RdHi) & 0xFF, cpuGetRegExternal(&pxa260CpuState, RdLo));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Boolean pxa260dspOp(struct ArmCpu* cpu, void* userData, Boolean two/* MCR2/MRC2 ? */, Boolean MRC, UInt8 op1, UInt8 Rs, UInt8 opcode_3, UInt8 Rm, UInt8 acc){
|
||||
Boolean pxa260dspOp(void* userData, Boolean two/* MCR2/MRC2 ? */, Boolean MRC, UInt8 op1, UInt8 Rs, UInt8 opcode_3, UInt8 Rm, UInt8 acc){
|
||||
|
||||
Pxa260dsp* dsp = userData;
|
||||
UInt64 addend = u64_zero();
|
||||
@@ -30,8 +31,8 @@ Boolean pxa260dspOp(struct ArmCpu* cpu, void* userData, Boolean two/* MCR2/MRC2
|
||||
|
||||
if(op1 != 1 || two || MRC || acc != 0) return false; //bad encoding
|
||||
|
||||
Vs = cpuGetRegExternal(cpu, Rs);
|
||||
Vm = cpuGetRegExternal(cpu, Rm);
|
||||
Vs = cpuGetRegExternal(&pxa260CpuState, Rs);
|
||||
Vm = cpuGetRegExternal(&pxa260CpuState, Rm);
|
||||
|
||||
switch(opcode_3 >> 2){
|
||||
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
#include "pxa260_IC.h"
|
||||
#include "pxa260_CPU.h"
|
||||
#include "pxa260.h"
|
||||
|
||||
|
||||
static void pxa260icPrvHandleChanges(Pxa260ic* ic){
|
||||
@@ -9,8 +11,8 @@ static void pxa260icPrvHandleChanges(Pxa260ic* ic){
|
||||
nowFiq = (unmasked & ic->ICLR) != 0;
|
||||
nowIrq = (unmasked & ~ic->ICLR) != 0;
|
||||
|
||||
if(nowFiq != ic->wasFiq) cpuIrq(ic->cpu, true, nowFiq);
|
||||
if(nowIrq != ic->wasIrq) cpuIrq(ic->cpu, false, nowIrq);
|
||||
if(nowFiq != ic->wasFiq) cpuIrq(&pxa260CpuState, true, nowFiq);
|
||||
if(nowIrq != ic->wasIrq) cpuIrq(&pxa260CpuState, false, nowIrq);
|
||||
|
||||
ic->wasFiq = nowFiq;
|
||||
ic->wasIrq = nowIrq;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "pxa260_PwrClk.h"
|
||||
#include "pxa260_CPU.h"
|
||||
#include "pxa260.h"
|
||||
|
||||
|
||||
@@ -7,7 +8,7 @@ Boolean pxa260pwrClkPrvCoprocRegXferFunc(void* userData, Boolean two, Boolean re
|
||||
Pxa260pwrClk* pc = userData;
|
||||
UInt32 val = 0;
|
||||
|
||||
if(!read) val = cpuGetRegExternal(cpu, Rx);
|
||||
if(!read) val = cpuGetRegExternal(&pxa260CpuState, Rx);
|
||||
|
||||
if(CRm == 0 && op2 == 0 && op1 == 0 && !two){
|
||||
|
||||
@@ -46,7 +47,7 @@ Boolean pxa260pwrClkPrvCoprocRegXferFunc(void* userData, Boolean two, Boolean re
|
||||
|
||||
success:
|
||||
|
||||
if(read) cpuSetReg(cpu, Rx, val);
|
||||
if(read) cpuSetReg(&pxa260CpuState, Rx, val);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -22,6 +22,11 @@ typedef uint8_t Boolean;//must use uint8_t, some functions store extra info in t
|
||||
#define _INLINE_ inline
|
||||
#define _UNUSED_
|
||||
|
||||
#define TYPE_CHECK ((sizeof(UInt32) == 4) && (sizeof(UInt16) == 2) && (sizeof(UInt8) == 1))
|
||||
|
||||
#define errNone 0x00
|
||||
#define errInternal 0x01
|
||||
|
||||
/* runtime stuffs */
|
||||
#define err_str(str) debugLog(str)
|
||||
#define err_hex(num) debugLog("0x%X", num)
|
||||
|
||||
@@ -210,4 +210,5 @@ uint8_t tps65010I2cExchange(uint8_t i2cBus){
|
||||
|
||||
void tps65010UpdateInterrupt(void){
|
||||
//TODO: implement this
|
||||
debugLog("Unimplemented TPS65010 interrupt check\n");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user