From a03882245a68471008fff032074d69d58ee5d064 Mon Sep 17 00:00:00 2001 From: maxcodehack Date: Sat, 5 Dec 2020 14:28:30 +0000 Subject: [PATCH] Upload uARM emulator (linux4kolibri) git-svn-id: svn://kolibrios.org@8327 a494cfbc-eb01-0410-851d-a64ba20cac60 --- contrib/other/uarm/CPU.c | 2736 ++++++++++++++++++++++++++++ contrib/other/uarm/CPU.h | 173 ++ contrib/other/uarm/MMU.c | 454 +++++ contrib/other/uarm/MMU.h | 64 + contrib/other/uarm/Makefile | 20 + contrib/other/uarm/RAM.c | 113 ++ contrib/other/uarm/RAM.h | 24 + contrib/other/uarm/SoC.c | 776 ++++++++ contrib/other/uarm/SoC.h | 121 ++ contrib/other/uarm/callout_RAM.c | 16 + contrib/other/uarm/callout_RAM.h | 24 + contrib/other/uarm/console_obj.h | 141 ++ contrib/other/uarm/cp15.c | 186 ++ contrib/other/uarm/cp15.h | 27 + contrib/other/uarm/cpu.h | 173 ++ contrib/other/uarm/dcache.c | 155 ++ contrib/other/uarm/dcache.h | 49 + contrib/other/uarm/icache.c | 140 ++ contrib/other/uarm/icache.h | 47 + contrib/other/uarm/main_pc.c | 250 +++ contrib/other/uarm/math64.c | 197 ++ contrib/other/uarm/math64.h | 64 + contrib/other/uarm/mem.c | 96 + contrib/other/uarm/mem.h | 38 + contrib/other/uarm/pxa255_DMA.c | 116 ++ contrib/other/uarm/pxa255_DMA.h | 42 + contrib/other/uarm/pxa255_DSP.c | 81 + contrib/other/uarm/pxa255_DSP.h | 20 + contrib/other/uarm/pxa255_GPIO.c | 206 +++ contrib/other/uarm/pxa255_GPIO.h | 47 + contrib/other/uarm/pxa255_IC.c | 104 ++ contrib/other/uarm/pxa255_IC.h | 64 + contrib/other/uarm/pxa255_LCD.c | 454 +++++ contrib/other/uarm/pxa255_LCD.h | 63 + contrib/other/uarm/pxa255_PwrClk.c | 154 ++ contrib/other/uarm/pxa255_PwrClk.h | 32 + contrib/other/uarm/pxa255_RTC.c | 101 + contrib/other/uarm/pxa255_RTC.h | 37 + contrib/other/uarm/pxa255_TIMR.c | 123 ++ contrib/other/uarm/pxa255_TIMR.h | 37 + contrib/other/uarm/pxa255_UART.c | 588 ++++++ contrib/other/uarm/pxa255_UART.h | 88 + contrib/other/uarm/readme.txt | 12 + contrib/other/uarm/rt.c | 51 + contrib/other/uarm/types.h | 45 + 45 files changed, 8549 insertions(+) create mode 100755 contrib/other/uarm/CPU.c create mode 100755 contrib/other/uarm/CPU.h create mode 100755 contrib/other/uarm/MMU.c create mode 100755 contrib/other/uarm/MMU.h create mode 100755 contrib/other/uarm/Makefile create mode 100755 contrib/other/uarm/RAM.c create mode 100755 contrib/other/uarm/RAM.h create mode 100755 contrib/other/uarm/SoC.c create mode 100755 contrib/other/uarm/SoC.h create mode 100755 contrib/other/uarm/callout_RAM.c create mode 100755 contrib/other/uarm/callout_RAM.h create mode 100755 contrib/other/uarm/console_obj.h create mode 100755 contrib/other/uarm/cp15.c create mode 100755 contrib/other/uarm/cp15.h create mode 100755 contrib/other/uarm/cpu.h create mode 100755 contrib/other/uarm/dcache.c create mode 100755 contrib/other/uarm/dcache.h create mode 100755 contrib/other/uarm/icache.c create mode 100755 contrib/other/uarm/icache.h create mode 100755 contrib/other/uarm/main_pc.c create mode 100755 contrib/other/uarm/math64.c create mode 100755 contrib/other/uarm/math64.h create mode 100755 contrib/other/uarm/mem.c create mode 100755 contrib/other/uarm/mem.h create mode 100755 contrib/other/uarm/pxa255_DMA.c create mode 100755 contrib/other/uarm/pxa255_DMA.h create mode 100755 contrib/other/uarm/pxa255_DSP.c create mode 100755 contrib/other/uarm/pxa255_DSP.h create mode 100755 contrib/other/uarm/pxa255_GPIO.c create mode 100755 contrib/other/uarm/pxa255_GPIO.h create mode 100755 contrib/other/uarm/pxa255_IC.c create mode 100755 contrib/other/uarm/pxa255_IC.h create mode 100755 contrib/other/uarm/pxa255_LCD.c create mode 100755 contrib/other/uarm/pxa255_LCD.h create mode 100755 contrib/other/uarm/pxa255_PwrClk.c create mode 100755 contrib/other/uarm/pxa255_PwrClk.h create mode 100755 contrib/other/uarm/pxa255_RTC.c create mode 100755 contrib/other/uarm/pxa255_RTC.h create mode 100755 contrib/other/uarm/pxa255_TIMR.c create mode 100755 contrib/other/uarm/pxa255_TIMR.h create mode 100755 contrib/other/uarm/pxa255_UART.c create mode 100755 contrib/other/uarm/pxa255_UART.h create mode 100755 contrib/other/uarm/readme.txt create mode 100755 contrib/other/uarm/rt.c create mode 100755 contrib/other/uarm/types.h diff --git a/contrib/other/uarm/CPU.c b/contrib/other/uarm/CPU.c new file mode 100755 index 0000000000..0617fa6e10 --- /dev/null +++ b/contrib/other/uarm/CPU.c @@ -0,0 +1,2736 @@ +/* + TODO: + + -verify DSP adds, subtracts, multiplies + -MCR/MRC to R15 is special - handle it + + TOTOv6: + -Endianness support (incl for pagetable lookups) + +*/ + + +#include "CPU.h" +#include "math64.h" + + + +#define ARM_MODE_2_REG 0x0F +#define ARM_MODE_2_WORD 0x10 +#define ARM_MODE_2_LOAD 0x20 +#define ARM_MODE_2_T 0x40 +#define ARM_MODE_2_INV 0x80 + +#define ARM_MODE_3_REG 0x0F //flag for actual reg number used +#define ARM_MODE_3_TYPE 0x30 //flag for the below 4 types +#define ARM_MODE_3_H 0x00 +#define ARM_MODE_3_SH 0x10 +#define ARM_MODE_3_SB 0x20 +#define ARM_MODE_3_D 0x30 +#define ARM_MODE_3_LOAD 0x40 +#define ARM_MODE_3_INV 0x80 + +#define ARM_MODE_4_REG 0x0F +#define ARM_MODE_4_INC 0x10 //incr or decr +#define ARM_MODE_4_BFR 0x20 //before or after +#define ARM_MODE_4_WBK 0x40 //writeback? +#define ARM_MODE_4_S 0x80 //S bit set? + +#define ARM_MODE_5_REG 0x0F +#define ARM_MODE_5_ADD_BEFORE 0x10 //add value before? +#define ARM_MODE_5_ADD_AFTER 0x20 //add value after? +#define ARM_MODE_5_IS_OPTION 0x40 //is value option (as opposed to offset) +#define ARM_MODE_5_RR 0x80 //MCRR or MRCC instrs + + +#ifdef ARM_V6 + + #define ARM_CPSR_UND_AND (~(ARM_SR_M | ARM_SR_E)) + #define ARM_CPSR_UND_ORR (ARM_SR_I | ARM_SR_MODE_UND | (cpu->EEE ? ARM_SR_E : 0)) + + #define ARM_CPSR_SWI_AND (~(ARM_SR_M | ARM_SR_E)) + #define ARM_CPSR_SWI_ORR (ARM_SR_I | ARM_SR_MODE_SVC | (cpu->EEE ? ARM_SR_E : 0)) + + #define ARM_CPSR_PAB_AND (~(ARM_SR_M | ARM_SR_E)) + #define ARM_CPSR_PAB_ORR (ARM_SR_I | ARM_SR_A | ARM_SR_MODE_ABT | (cpu->EEE ? ARM_SR_E : 0)) + + #define ARM_CPSR_DAB_AND (~(ARM_SR_M | ARM_SR_E)) + #define ARM_CPSR_DAB_ORR (ARM_SR_I | ARM_SR_A | ARM_SR_MODE_ABT | (cpu->EEE ? ARM_SR_E : 0)) + + #define ARM_CPSR_IRQ_AND (~(ARM_SR_M | ARM_SR_E)) + #define ARM_CPSR_IRQ_ORR (ARM_SR_I | ARM_SR_A | ARM_SR_MODE_IRQ | (cpu->EEE ? ARM_SR_E : 0)) + + #define ARM_CPSR_FIQ_AND (~(ARM_SR_M | ARM_SR_E)) + #define ARM_CPSR_FIQ_ORR (ARM_SR_I | ARM_SR_A | ARM_SR_F | ARM_SR_MODE_IRQ | (cpu->EEE ? ARM_SR_E : 0)) + + +#else + + #define ARM_CPSR_UND_AND (~ARM_SR_M) + #define ARM_CPSR_UND_ORR (ARM_SR_I | ARM_SR_MODE_UND) + + #define ARM_CPSR_SWI_AND (~ARM_SR_M) + #define ARM_CPSR_SWI_ORR (ARM_SR_I | ARM_SR_MODE_SVC) + + #define ARM_CPSR_PAB_AND (~ARM_SR_M) + #define ARM_CPSR_PAB_ORR (ARM_SR_I | ARM_SR_MODE_ABT) + + #define ARM_CPSR_DAB_AND (~ARM_SR_M) + #define ARM_CPSR_DAB_ORR (ARM_SR_I | ARM_SR_MODE_ABT) + + #define ARM_CPSR_IRQ_AND (~ARM_SR_M) + #define ARM_CPSR_IRQ_ORR (ARM_SR_I | ARM_SR_MODE_IRQ) + + #define ARM_CPSR_FIQ_AND (~ARM_SR_M) + #define ARM_CPSR_FIQ_ORR (ARM_SR_I | ARM_SR_F | ARM_SR_MODE_FIQ) + + +#endif + + + +static _INLINE_ UInt32 cpuPrvROR(UInt32 val, UInt8 ror){ + + if(ror) val = (val >> (UInt32)ror) | (val << (UInt32)(32 - ror)); + + return val; +} + +static _INLINE_ void cpuPrvSetPC(ArmCpu* cpu, UInt32 pc){ + cpu->regs[15] = pc &~ 1UL; + cpu->CPSR &=~ ARM_SR_T; + if(pc & 1) cpu->CPSR |= ARM_SR_T; + else if(pc & 2) cpu->emulErrF(cpu, "Attempt to branch to non-word-aligned ARM address"); +} + +static _INLINE_ UInt32 cpuPrvGetReg(ArmCpu* cpu, UInt8 reg, Boolean wasT, Boolean specialPC){ + + UInt32 ret; + + ret = cpu->regs[reg]; + if(reg == 15) ret += (wasT) ? 2 : 4; + if(wasT && specialPC) ret &=~ 3UL; + + return ret; +} + +static _INLINE_ void cpuPrvSetReg(ArmCpu* cpu, UInt8 reg, UInt32 val){ + + if(reg == 15){ + cpuPrvSetPC(cpu, val); + } + else cpu->regs[reg] = val; +} + +UInt32 cpuGetRegExternal(ArmCpu* cpu, UInt8 reg){ + + if(reg < 16){ // real reg + + return (reg == 15) ? (cpu->regs[15] + ((cpu->CPSR & ARM_SR_T) ? 1 : 0)) : cpu->regs[reg]; + } + else if(reg == ARM_REG_NUM_CPSR){ + + return cpu->CPSR; + } + else if(reg == ARM_REG_NUM_SPSR){ + + return cpu->SPSR; + } + + return 0; +} + +void cpuSetReg(ArmCpu* cpu, UInt8 reg, UInt32 val){ + + cpuPrvSetReg(cpu, reg, val); +} + +#define cpuSetReg _DO_NOT_USE_cpuSetReg_IN_CPU_C_ + +static ArmBankedRegs* cpuPrvModeToBankedRegsPtr(ArmCpu* cpu, UInt8 mode){ + + switch(mode){ + case ARM_SR_MODE_USR: + case ARM_SR_MODE_SYS: + return &cpu->bank_usr; + + case ARM_SR_MODE_FIQ: + return &cpu->bank_fiq; + + case ARM_SR_MODE_IRQ: + return &cpu->bank_irq; + + case ARM_SR_MODE_SVC: + return &cpu->bank_svc; + + case ARM_SR_MODE_ABT: + return &cpu->bank_abt; + + case ARM_SR_MODE_UND: + return &cpu->bank_und; + + default: + cpu->emulErrF(cpu, "Invalid mode passed to cpuPrvModeToBankedRegsPtr()"); + return NULL; + } +} + +static void cpuPrvSwitchToMode(ArmCpu* cpu, UInt8 newMode){ + + ArmBankedRegs *saveTo, *getFrom; + UInt32 tmp; + UInt8 i, curMode; + + curMode = cpu->CPSR & ARM_SR_M; + if(curMode == newMode) return; + + if(curMode == ARM_SR_MODE_FIQ || newMode == ARM_SR_MODE_FIQ){ //bank/unbank the fiq regs + + for(i = 0; i < 5; i++){ + tmp = cpu->extra_regs[i]; + cpu->extra_regs[i] = cpu->regs[i + 8]; + cpu->regs[i + 8] = tmp; + } + } + + saveTo = cpuPrvModeToBankedRegsPtr(cpu, curMode); + getFrom = cpuPrvModeToBankedRegsPtr(cpu, newMode); + + if(saveTo == getFrom) return; //we're done if no regs to switch [this happens if we switch user<->system] + + saveTo->R13 = cpu->regs[13]; + saveTo->R14 = cpu->regs[14]; + saveTo->SPSR = cpu->SPSR; + + cpu->regs[13] = getFrom->R13; + cpu->regs[14] = getFrom->R14; + cpu->SPSR = getFrom->SPSR; + + cpu->CPSR = (cpu->CPSR &~ ARM_SR_M) | newMode; +} + +static void cpuPrvException(ArmCpu* cpu, UInt32 vector_pc, UInt32 lr, UInt32 newCPSR){ + + UInt32 cpsr = cpu->CPSR; + + cpuPrvSwitchToMode(cpu, newCPSR & ARM_SR_M); + cpu->CPSR = newCPSR; + cpu->SPSR = cpsr; + cpu->regs[14] = lr; + cpu->regs[15] = vector_pc; +} + +static void cpuPrvHandleMemErr(ArmCpu* cpu, UInt32 addr, _UNUSED_ UInt8 sz, _UNUSED_ Boolean write, Boolean instrFetch, UInt8 fsr){ + + if(cpu->setFaultAdrF) cpu->setFaultAdrF(cpu, addr, fsr); + + if(instrFetch){ + + //handle prefetch abort + cpuPrvException(cpu, cpu->vectorBase + ARM_VECTOR_OFFT_P_ABT, cpu->regs[15] + 4, ARM_CPSR_PAB_ORR | (cpu->CPSR & ARM_CPSR_PAB_AND)); + } + else{ + //handle data abort + cpuPrvException(cpu, cpu->vectorBase + ARM_VECTOR_OFFT_D_ABT, cpu->regs[15] + ((cpu->CPSR & ARM_SR_T) ? 6 : 4) /* instr + 8*/, ARM_CPSR_DAB_ORR | (cpu->CPSR & ARM_CPSR_DAB_AND)); + } +} + +static _INLINE_ UInt32 cpuPrvArmAdrMode_1(ArmCpu* cpu, UInt32 instr, Boolean* carryOutP, Boolean wasT, Boolean specialPC){ + + UInt32 ret; + UInt8 v, a; + Boolean co = ((cpu->CPSR & ARM_SR_C) != 0); //be default carry out = C flag + + if(instr & 0x02000000UL){ //immed + + v = (instr >> 7) & 0x1E; + ret = cpuPrvROR(instr & 0xFF, v); + if (v) co = ((ret & 0x80000000UL) != 0); + } + else{ + v = (instr >> 5) & 3; //get shift type + ret = cpuPrvGetReg(cpu, instr & 0x0F, wasT, specialPC); //get Rm + + if(instr & 0x00000010UL){ //reg with reg shift + + a = cpuPrvGetReg(cpu, (instr >> 8) & 0x0F, wasT, specialPC); //get the relevant part of Rs, we only care for lower 8 bits (note we use uint8 for this) + + if(a != 0){ //else all is already good + + switch(v){ //perform shifts + + case 0: //LSL + + if(a < 32){ + co = (ret >> (32 - a)) & 1; + ret = ret << a; + } + else if(a == 32){ + co = ret & 1; + ret = 0; + } + else{ // >32 + co = 0; + ret = 0; + } + break; + + case 1: //LSR + + if(a < 32){ + co = (ret >> (a - 1)) & 1; + ret = ret >> a; + } + else if(a == 32){ + co = ret >> 31; + ret = 0; + } + else{ // >32 + co = 0; + ret = 0; + } + break; + + case 2: //ASR + + if(a < 32){ + co = (ret >> (a - 1)) & 1; + ret = ((Int32)ret >> a); + } + else{ // >=32 + if(ret & 0x80000000UL){ + co = 1; + ret = 0xFFFFFFFFUL; + } + else{ + co = 0; + ret = 0; + } + } + break; + + case 3: //ROR + + if(a == 0){ + + //nothing... + } + else{ + a &= 0x1F; + if(a == 0){ + co = ret >> 31; + } + else{ + co = (ret >> (a - 1)) & 1; + ret = cpuPrvROR(ret, a); + } + } + break; + } + } + } + else{ //reg with immed shift + + a = (instr >> 7) & 0x1F; //get imm + + switch(v){ + + case 0: //LSL + + if(a == 0){ + //nothing + } + else{ + co = (ret >> (32 - a)) & 1; + ret = ret << a; + } + break; + + case 1: //LSR + + if(a == 0){ + co = ret >> 31; + ret = 0; + } + else{ + co = (ret >> (a - 1)) & 1; + ret = ret >> a; + } + break; + + case 2: //ASR + + if(a == 0){ + if(ret & 0x80000000UL){ + co = 1; + ret = 0xFFFFFFFFUL; + } + else{ + co = 0; + ret = 0; + } + } + else{ + co = (ret >> (a - 1)) & 1; + if(ret & 0x80000000UL){ + ret = (ret >> a) | (0xFFFFFFFFUL << (32 - a)); + } + else{ + ret = ret >> a; + } + } + break; + + case 3: //ROR or RRX + + if(a == 0){ //RRX + a = co; + co = ret & 1; + ret = ret >> 1; + if(a) ret |= 0x80000000UL; + } + else{ + co = (ret >> (a - 1)) & 1; + ret = cpuPrvROR(ret, a); + } + break; + } + } + } + + *carryOutP = co; + return ret; +} + +/* +idea: + +addbefore is what to add to add to base reg before addressing, addafter is what to add after. we ALWAYS do writeback, but if not requested by instr, it will be zero + +for [Rx, 5] baseReg = x addbefore = 5 addafter = -5 +for [Rx, 5]! baseReg = x addBefore = 0 addafter = 0 +for [Rx], 5 baseReg = x addBefore = 0 addAfter = 5 + +t = T bit (LDR vs LDRT) + +baseReg is returned in return val along with flags: + + +ARM_MODE_2_REG is mask for reg +ARM_MODE_2_WORD is flag for word access +ARM_MODE_2_LOAD is flag for load +ARM_MODE_2_INV is flag for invalid instructions +ARM_MODE_2_T is flag for T + + +*/ +static _INLINE_ UInt8 cpuPrvArmAdrMode_2(ArmCpu* cpu, UInt32 instr, UInt32* addBeforeP, UInt32* addWritebackP, Boolean wasT, Boolean specialPC){ + + UInt32 val; + UInt8 reg, shift; + + reg = (instr >> 16) & 0x0F; + + if(!(instr & 0x02000000UL)){ //immediate + val = instr & 0xFFFUL; + } + else{ //[scaled] register + + if(instr & 0x00000010UL) reg |= ARM_MODE_2_INV; //invalid instrucitons need to be reported + + val = cpuPrvGetReg(cpu, instr & 0x0F, wasT, specialPC); + shift = (instr >> 7) & 0x1F; + switch((instr >> 5) & 3){ + + case 0: //LSL + val <<= shift; + break; + + case 1: //LSR + val = shift ? (val >> shift) : 0; + break; + + case 2: //ASR + val = shift ? (UInt32)((((Int32)val) >> shift)) : ((val & 0x80000000UL) ? 0xFFFFFFFFUL : 0x00000000UL); + break; + + case 3: //ROR/RRX + if(shift){ + val = cpuPrvROR(val, shift); + } + else{ //RRX + val = val >> 1; + if(cpu->CPSR & ARM_SR_C) val |= 0x80000000UL; + } + } + + } + + if(!(instr & 0x00400000UL)) reg |= ARM_MODE_2_WORD; + if(instr & 0x00100000UL) reg |= ARM_MODE_2_LOAD; + if(!(instr & 0x00800000UL)) val = -val; + if(!(instr & 0x01000000UL)){ + *addBeforeP = 0; + *addWritebackP = val; + + if(instr & 0x00200000UL) reg |= ARM_MODE_2_T; + } + else if(instr & 0x00200000UL){ + *addBeforeP = val; + *addWritebackP = val; + } + else{ + *addBeforeP = val; + *addWritebackP = 0; + } + + return reg; +} + + +/* +same comments as for addr mode 2 apply + +#define ARM_MODE_3_REG 0x0F //flag for actual reg number used +#define ARM_MODE_3_TYPE 0x30 //flag for the below 4 types +#define ARM_MODE_3_H 0x00 +#define ARM_MODE_3_SH 0x10 +#define ARM_MODE_3_SB 0x20 +#define ARM_MODE_3_D 0x30 +#define ARM_MODE_3_LOAD 0x40 +#define ARM_MODE_3_INV 0x80 +*/ + +static _INLINE_ UInt8 cpuPrvArmAdrMode_3(ArmCpu* cpu, UInt32 instr, UInt32* addBeforeP, UInt32* addWritebackP, Boolean wasT, Boolean specialPC){ + + UInt32 val; + UInt8 reg; + Boolean S, H, L; + + reg = (instr >> 16) & 0x0F; + + if(instr & 0x00400000UL){ //immediate + val = ((instr >> 4) & 0xF0) | (instr & 0x0F); + } + else{ + if(instr & 0x00000F00UL) reg |= ARM_MODE_3_INV; //bits 8-11 must be 1 always + val = cpuPrvGetReg(cpu, instr & 0x0F, wasT, specialPC); + } + + + L = (instr & 0x00100000UL) != 0; + H = (instr & 0x00000020UL) != 0; + S = (instr & 0x00000040UL) != 0; + + if(S && H){ + reg |= ARM_MODE_3_SH; + } + else if(S){ + reg |= ARM_MODE_3_SB; + } + else if(H){ + reg |= ARM_MODE_3_H; + } + else{ + reg |= ARM_MODE_3_INV; //S == 0 && H == 0 is invalid mode 3 operation + } + + if((instr & 0x00000090UL) != 0x00000090UL) reg |= ARM_MODE_3_INV; //bits 4 and 7 must be 1 always + + if(S && !L){ //LDRD/STRD is encoded thusly + + reg = (reg &~ ARM_MODE_3_TYPE) | ARM_MODE_3_D; + L = !H; + } + if(L) reg |= ARM_MODE_3_LOAD; + if(!(instr & 0x00800000UL)) val = -val; + if(!(instr & 0x01000000UL)){ + *addBeforeP = 0; + *addWritebackP = val; + + if(instr & 0x00200000UL) reg |= ARM_MODE_3_INV; //W must be 0 in this case, else unpredictable (in this case - invalid instr) + } + else if(instr & 0x00200000UL){ + *addBeforeP = val; + *addWritebackP = val; + } + else{ + *addBeforeP = val; + *addWritebackP = 0; + } + + return reg; +} + +/* + #define ARM_MODE_4_REG 0x0F + #define ARM_MODE_4_INC 0x10 //incr or decr + #define ARM_MODE_4_BFR 0x20 //after or before + #define ARM_MODE_4_WBK 0x40 //writeback? + #define ARM_MODE_4_S 0x80 //S bit set? +*/ + +static UInt8 cpuPrvArmAdrMode_4(_UNUSED_ ArmCpu* cpu, UInt32 instr, UInt16* regs){ + + UInt8 reg; + + + *regs = instr; + + reg = (instr >> 16) & 0x0F; + if(instr & 0x00400000UL) reg |= ARM_MODE_4_S; + if(instr & 0x00200000UL) reg |= ARM_MODE_4_WBK; + if(instr & 0x00800000UL) reg |= ARM_MODE_4_INC; + if(instr & 0x01000000UL) reg |= ARM_MODE_4_BFR; + + return reg; +} + +/* +#define ARM_MODE_5_REG 0x0F +#define ARM_MODE_5_ADD_BEFORE 0x10 //add value before? +#define ARM_MODE_5_ADD_AFTER 0x20 //add value after? +#define ARM_MODE_5_IS_OPTION 0x40 //is value option (as opposed to offset) +#define ARM_MODE_5_RR 0x80 + +*/ +static _INLINE_ UInt8 cpuPrvArmAdrMode_5(_UNUSED_ ArmCpu* cpu, UInt32 instr, UInt32* valP){ + + UInt32 val; + UInt8 reg; + + + val = instr & 0xFF; + reg = (instr >> 16) & 0x0F; + + if(!(instr & 0x01000000UL)){ //unindexed or postindexed + + if(instr & 0x00200000UL){ //postindexed + + reg |= ARM_MODE_5_ADD_AFTER; + } + else{ //unindexed + + if(!(instr & 0x00800000UL)) reg |= ARM_MODE_5_RR; //U must be 1 for unindexed, else it is MCRR/MRCC + reg |= ARM_MODE_5_IS_OPTION; + } + } + else{ //offset or preindexed + + reg |= ARM_MODE_5_ADD_BEFORE; + + if(instr & 0x00200000UL){ //preindexed + + reg |= ARM_MODE_5_ADD_AFTER; + } + } + + if(!(reg & ARM_MODE_5_IS_OPTION)){ + + val = val << 2; + if(!(instr & 0x00800000UL)) val = -val; + } + + *valP = val; + return reg; +} + +static _INLINE_ void cpuPrvSetPSR(ArmCpu* cpu, UInt8 mask, Boolean privileged, Boolean R, UInt32 val){ + + if(R){ //setting SPSR in sys or usr mode is no harm since they arent used, so just do it without any checks + + cpu->SPSR = val; + } + else{ + + UInt32 newCPSR = cpu->CPSR; + + if(privileged){ + if(mask & 1){ + + cpuPrvSwitchToMode(cpu, val & ARM_SR_M); + newCPSR = (newCPSR & 0xFFFFFF00UL) | (val & 0x000000FFUL); + } + if(mask & 2) newCPSR = (newCPSR & 0xFFFF00FFUL) | (val & 0x0000FF00UL); + if(mask & 4) newCPSR = (newCPSR & 0xFF00FFFFUL) | (val & 0x00FF0000UL); + } + if(mask & 8) newCPSR = (newCPSR & 0x00FFFFFFUL) | (val & 0xFF000000UL); + + cpu->CPSR = newCPSR; + } +} + +static _INLINE_ Boolean cpuPrvSignedAdditionOverflows(UInt32 a, UInt32 b, UInt32 sum){ + + return ((a ^ b ^ 0x80000000UL) & (a ^ sum)) >> 31; +} + +static _INLINE_ Boolean cpuPrvSignedSubtractionOverflows(UInt32 a, UInt32 b, UInt32 diff){ //diff = a - b + + return ((a ^ b) & (a ^ diff)) >> 31; +} + +static _INLINE_ UInt32 cpuPrvMedia_signedSaturate32(UInt32 sign){ + + return (sign & 0x80000000UL) ? 0xFFFFFFFFUL : 0; +} + +#ifdef ARM_V6 + + static _INLINE_ UInt32 cpuPrvMedia_sxtb(UInt8 v){ + + UInt32 r = v; + if(v & 0x80) r |= 0xFFFFFF00UL; + + return r; + } + + static _INLINE_ UInt32 cpuPrvMedia_uxtb(UInt8 v){ + + UInt32 r = v; + + return r; + } + + static _INLINE_ UInt32 cpuPrvMedia_sxth(UInt16 v){ + + UInt32 r = v; + if(v & 0x8000UL) r |= 0xFFFF0000UL; + + return r; + } + + static _INLINE_ UInt32 cpuPrvMedia_uxth(UInt16 v){ + + UInt32 r = v; + + return r; + } + + static _INLINE_ UInt32 cpuPrvMedia_sxt16(UInt32 v){ + + if(v & 0x00800000UL){ + v |= 0xFF000000UL; + } + else{ + v &=~ 0xFF000000UL; + } + + if(v & 0x00000080UL){ + v |= 0x0000FF00UL; + } + else{ + v &=~ 0x0000FF00UL; + } + return v; + } + + static _INLINE_ UInt32 cpuPrvMedia_uxt16(UInt32 v){ + + v &=~ 0xFF00FF00UL; + + return v; + } + + static _INLINE_ UInt32 cpuPrvMedia_dualAdd(UInt32 a, UInt32 b){ //3 ands, 2 ads, 1 sub + + UInt32 sum = a + b; + sum -= (((a & 0xFFFFUL) + (b & 0xFFFFUL)) & 0xFFFF0000UL); //think about it...it should work... + + return sum; + } + + static _INLINE_ UInt32 cpuPrvMedia_SignedSat(UInt32 val, UInt8 from_bits, UInt8 to_bits){ //returns value. [orred with 0x80000000UL to indicate sat was done] + + UInt32 check_mask, top_in; + + if(from_bits <= to_bits) return val; //no saturation needed + + top_in = (1UL << (from_bits - 1)); + check_mask = (1UL << to_bits) - (1UL << from_bits); + + if(val & top_in){ //input was negative + + if((val & check_mask) != check_mask){ //saturate + + val = top_in | 0x80000000UL; + } + } + else{ + + if(val & check_mask){ //saturate + + val = (top_in - 1) | 0x80000000UL; + } + } + + + return val; + } + + static _INLINE_ Boolean cpuPrvMediaInstrs(ArmCpu* cpu, UInt32 instr, Boolean wasT, Boolean specialPC){ + + UInt64 v64; + UInt32 v32a, v32b, v32c, v32d; + Boolean vB = false; + UInt8 v8a, v8b; + UInt16 v16; + + switch((instr >> 20) & 0x1F){ + + case 0: //parrallel addition/subtraction signed + case 1: + case 2: + case 3: + + //TODO + break; + + case 4: //parrallel addition/subtraction unsigned + case 5: + case 6: + case 7: + + //TODO + break; + + case 8: //packing/unpacking/saturation/reversal + case 9: + case 10: + case 11: + case 12: + case 13: + case 14: + case 15: + + v8a = (instr >> 16) & 0x0F; + v8b = (instr >> 5) & 7; + switch((instr >> 20) & 7){ + + case 0: switch(v8b){ + + case 0: //PKH + case 2: + case 4: + case 6: + + v32a = cpuPrvGetReg(cpu, (instr >> 16) & 0x0F, wasT, specialPC); //Rn + v32b = cpuPrvGetReg(cpu, instr & 0x0F, wasT, specialPC); //Rm + v8a = (instr >> 7) & 0x1F; + if(instr & 0x00000040UL){ //ASR + + if(!v8a) v8a = 32; + v32b = (((Int32)v32b) >> v8a); + + v32c = (v32b & 0xFFFFUL) | (v32a & 0xFFFF0000UL); + } + else{ //LSL + + v32b <<= v8a; + v32c = (v32a & 0xFFFFUL) | (v32b & 0xFFFF0000UL); + } + cpuPrvSetReg(cpu, (instr >> 12) & 0x0F, v32c); + break; + + case 3: //SXTAB16 SXTB16 + + vB = true; //sign extend + goto xt16; + + case 5: //SEL + + v32a = cpuPrvGetReg(cpu, (instr >> 16) & 0x0F, wasT, specialPC); //Rn + v32b = cpuPrvGetReg(cpu, instr & 0x0F, wasT, specialPC); //Rm + + v32c = 0; + if(cpu->CPSR & ARM_SR_GE_0) v32c |= 0x000000FFUL; + if(cpu->CPSR & ARM_SR_GE_1) v32c |= 0x0000FF00UL; + if(cpu->CPSR & ARM_SR_GE_2) v32c |= 0x00FF0000UL; + if(cpu->CPSR & ARM_SR_GE_2) v32c |= 0xFF000000UL; + v32c = (v32a & v32c) | (v32b & ~v32c); + + cpuPrvSetReg(cpu, (instr >> 12) & 0x0F, v32c); + break; + + default: + + return false; + } + break; + + case 2: switch(v8b){ + + case 1: //SSAT16 + + //TODO; + break; + + case 3: //SXTAB SXTB + + vB = true; //sign extend + goto xtb; + + case 0: + case 2: + case 4: + case 6: + + goto ssat; + break; + + default: + + return false; + } + break; + + case 3: switch(v8b){ + + case 1: //REV + + //TODO; + break; + + case 3: //SXTAH SXTH + + vB = true; //sign extend + goto xth; + + case 5: //REV16 + + //TOOD; + break; + + case 0: //SSAT + case 2: + case 4: + case 6: + ssat: + //TODO + break; + + default: + + return false; + } + break; + + case 4: //UXTAB16 UXTB16 + if(v8b != 3) return false; + + vB = false; //not sign extend + xt16: + v32a = (v8a == 15) ? 0 : cpuPrvGetReg(cpu, v8a, wasT, specialPC); //Rn + v32b = cpuPrvGetReg(cpu, instr & 0x0F, wasT, specialPC); //Rm + v32b = cpuPrvROR(v32b, (instr >> 7) & 0x18); + v32b = vB ? cpuPrvMedia_sxt16(v32b) : cpuPrvMedia_uxt16(v32b); + + v32c = cpuPrvMedia_dualAdd(v32a, v32b); + cpuPrvSetReg(cpu, (instr >> 12) & 0x0F, v32a); + break; + + case 6: switch(v8b){ + + case 1: //USAT16 + + //TODO; + break; + + case 3: //UXTAB UXTB + vB = false; //not sign extend + xtb: + v32a = (v8a == 15) ? 0 : cpuPrvGetReg(cpu, v8a, wasT, specialPC); //Rn + v32b = cpuPrvGetReg(cpu, instr & 0x0F, wasT, specialPC) //Rm + v32b = cpuPrvROR(v32b, (instr >> 7) & 0x18); + v32b = vB ? cpuPrvMedia_sxtb(v32b) : cpuPrvMedia_uxtb(v32b); + + v32a += v32b; + cpuPrvSetReg(cpu, (instr >> 12) & 0x0F, v32a); + break; + + case 0: + case 2: + case 4: + case 6: + + goto usat; + + default: + + return false; + } + break; + + case 7: switch(v8b){ + + case 1: //RBIT + + v32a = cpuPrvGetReg(cpu, instr & 0x0F, wasT, specialPC); + v32b = 0; + v32c = 0x80000000UL; + v32d = 0x00000001UL; + + //faster ways exist, but this is smaller code + for(v8a = 0; v8a < 32; v8a++, v32c >>= 1, v32d <<= 1) if(v32a & v32c) v32b |= v32d; + + cpuPrvSetReg(cpu, (instr >> 12) & 0x0F, v32b); + break; + + case 3: //UXTAH UXTH + + vB = false; //not sign extend + xth: + v32a = (v8a == 15) ? 0 : cpuPrvGetReg(cpu, v8a, wasT, specialPC); //Rn + v32b = cpuPrvGetReg(cpu, instr & 0x0F, wasT, specialPC) //Rm + v32b = cpuPrvROR(v32b, (instr >> 7) & 0x18); + v32b = vB ? cpuPrvMedia_sxth(v32b) : cpuPrvMedia_uxth(v32b); + + v32a += v32b; + cpuPrvSetReg(cpu, (instr >> 12) & 0x0F, v32a); + break; + + case 5: //REVSH + + //TODO; + break; + + case 0: //USAT + case 2: + case 4: + case 6: + usat: + //TODO; + break; + + default: + + return false; + } + break; + + default: + return false; + } + break; + + case 16: //signed multiplies + case 17: + case 18: + case 19: + case 20: + case 21: + case 22: + case 23: + + v8a = (instr >> 12) & 0x0F; + if((instr & 0x00700000UL) == 0x00000000){ //SMLAD, SMUAD, SMLSD, SMUSD + + v32a = cpuPrvGetReg(cpu, (instr >> 8) & 0x0F, wasT, specialPC); //Rm + v32b = cpuPrvGetReg(cpu, (instr >> 0) & 0x0F, wasT, specialPC); //Rn + + if(instr & 0x00000020UL) v32a = cpuPrvROR(v32a, 16); + v32c = (Int32)((Int16)(v32a & 0xFFFFUL)) * (Int32)((Int16)(v32b & 0xFFFFUL)); + v32a = (Int32)((Int16)(v32a >> 16)) * (Int32)((Int16)(v32b >> 16)); + v32b = (v8a == 15) ? 0 : cpuPrvGetReg(cpu, v8a, wasT, specialPC); + + if((instr & 0x000000C0UL) == 0x00000000){ //SMLAD, SMUAD + + //now add them and mark Q flag is we overflow + v32d = v32a + v32c; + vB = cpuPrvSignedAdditionOverflows(v32a, v32c, v32d); + } + else if((instr & 0x000000C0UL) == 0x00000040UL){ //SMLSD, SMUSD + + v32d = v32a - v32c; + vB = cpuPrvSignedSubtractionOverflows(v32a, v32c, v32d); + } + else return false; + + v32a = v32d + v32b; + vB = vB || cpuPrvSignedAdditionOverflows(v32d, v32b, v32a); + cpuPrvSetReg(cpu, (instr >> 12) & 0x0F, v32a); + } + else if((instr & 0x00700000UL) == 0x00400000UL){ //SMLALD, SMLSLD + + v64 = u64_from_halves(cpuPrvGetReg(cpu, (instr >> 16) & 0x0F, wasT, specialPC), cpuPrvGetReg(cpu, (instr >> 12) & 0x0F, wasT, specialPC)); + v32a = cpuPrvGetReg(cpu, (instr >> 8) & 0x0F, wasT, specialPC); //Rm + v32b = cpuPrvGetReg(cpu, (instr >> 0) & 0x0F, wasT, specialPC); //Rn + + if(instr & 0x00000020UL) v32a = cpuPrvROR(v32a, 16); + v32c = (Int32)((Int16)(v32a & 0xFFFFUL)) * (Int32)((Int16)(v32b & 0xFFFFUL)); + v32a = (Int32)((Int16)(v32a >> 16)) * (Int32)((Int16)(v32b >> 16)); + + if((instr & 0x000000C0UL) == 0x00000000){ //SMLALD + + v64 = u64_add(v64, u64_add(u64_xtnd32(u64_32_to_64(v32a)), u64_xtnd32(u64_32_to_64(v32c)))); + } + else if((instr & 0x000000C0UL) == 0x00000040){ //SMLSLD + + v64 = u64_add(v64, u64_sub(u64_xtnd32(u64_32_to_64(v32a)), u64_xtnd32(u64_32_to_64(v32c)))); + } + else return false; + + cpuPrvSetReg(cpu, (instr >> 16) & 0x0F, u64_get_hi(v64)); + cpuPrvSetReg(cpu, (instr >> 12) & 0x0F, u64_64_to_32(v64)); + } + else if((instr & 0x00700000UL) == 0x00500000UL){ //SMMLA, SMMUL, SMMLS + + v32a = cpuPrvGetReg(cpu, (instr >> 8) & 0x0F, wasT, specialPC); //Rm + v32b = cpuPrvGetReg(cpu, (instr >> 0) & 0x0F, wasT, specialPC); //Rn + v32c = cpuPrvGetReg(cpu, (instr >> 12) & 0x0F, wasT, specialPC); //Ra + + v64 = u64_smul3232(v32a, v32b); + + if((instr & 0x000000C0UL) == 0x00000000){ //SMMLA, SMMUL + + if(v8a == 15){ //SMMUL + + //nothing to do here + } + else{ //SMMLA + + v64 = u64_add(v64, u64_shl(u64_32_to_64(v32c), 32)); + } + } + else if((instr & 0x000000C0UL) == 0x000000C0){ //SMMLS + + v64 = u64_sub(v64, u64_shl(u64_32_to_64(v32c), 32)); + } + else return false; + + if(instr & 0x00000010UL) v64 = u64_add(v64, u64_32_to_64(0x80000000UL)); //round if requested + + cpuPrvSetReg(cpu, (instr >> 16) & 0x0F, u64_get_hi(v64)); + } + else return false; + + if(vB){ //overflow + + cpu->CPSR |= ARM_SR_Q; + } + break; + + case 24: //USAD8 USADA8 + + if(instr & 0x000000E0UL) return false; + + v32a = ((instr & 0x0000F000UL) == 0x0000F000UL) ? 0 : cpuPrvGetReg(cpu, (instr >> 12) & 0x0F, wasT, specialPC); //Ra + v32b = cpuPrvGetReg(cpu, instr & 0x0F, wasT, specialPC); //Rn + v32c = cpuPrvGetReg(cpu, (instr >> 8) & 0x0F, wasT, specialPC); //Rm + + for(v8a = 0; v8a < 4; v8a++){ + v16 = (v32b & 0xFF) - (v32c & 0xFF); + if(v16 & 0x8000U) v16 = -v16; + v32a += v16; + v32b >>= 8; + v32c >>= 8; + } + cpuPrvSetReg(cpu, (instr >> 16) & 0x0F, v32a); + break; + + case 26: + case 27: + + vB = true; //sign extend + goto bitfield_extract; + + case 30: + case 31: + + vB = false; //do not sign extend + bitfield_extract: + + if((instr & 0x00000060UL) == 0x00000040){ //unsigned bitfield extract + + v32a = cpuPrvGetReg(cpu, instr & 0x0F, wasT, specialPC); + v8a = ((instr >> 16) & 0x1F) + 1; + v8b = (instr >> 7) & 0x1F; + v32a >>= v8b; + v32c = 0xFFFFFFFFUL << v8a; + v32a &=~ v32c; + if(vB){ //sign extend + if(v32a & (1UL << (v8a - 1))) v32a |= v32c; + } + cpuPrvSetReg(cpu, (instr >> 12) & 0x0F, v32a); + } + else return false; + break; + + case 28: + case 29: + if(instr & 0x00000060UL){ + + return false; + } + else{ //BFC BFI + + v8a = 31 - ((instr >> 16) & 0x1F); + v8b = (instr >> 7) & 0x1F; + v32a = 0xFFFFFFFFUL; + v32a >>= v8b; + v32a <<= v8b + v8a; + v32a >>= v8a; + + v32b = cpuPrvGetReg(cpu, (instr >> 12) & 0x0F, wasT, specialPC); + v32b &= ~v32a; + + if((instr & 0x0000000FUL) == 0x0000000F){ //BFC + + //bits already clear + } + else{ //BFI + + v32c = cpuPrvGetReg(cpu, instr & 0x0F, wasT, specialPC); + v32c >>= v8b; + v32c <<= v8b + v8a; + v32c >>= v8a; + v32b |= v32c; + } + cpuPrvSetReg(cpu, (instr >> 12) & 0x0F, v32b); + } + break; + + default: + + return false; + } + return true; + } +#endif + +static Err cpuPrvExecInstr(ArmCpu* cpu, UInt32 instr, UInt32 instrPC/* lower bit always clear */, Boolean wasT , Boolean privileged, Boolean specialPC/* for thumb*/){ + + Boolean specialInstr = false, usesUsrRegs, execute = false, L, ok; + UInt8 fsr; + + usesUsrRegs = ((cpu->CPSR & ARM_SR_M) == ARM_SR_MODE_USR) || ((cpu->CPSR & ARM_SR_M) == ARM_SR_MODE_SYS); + + //check condition code + { + switch(instr >> 29UL){ + + case 0: //EQ / NE + execute = (cpu->CPSR & ARM_SR_Z) != 0; + break; + + case 1: //CS / CC + execute = (cpu->CPSR & ARM_SR_C) != 0; + break; + + case 2: //MI/PL + execute = (cpu->CPSR & ARM_SR_N) != 0; + break; + + case 3: //VS/VC + execute = (cpu->CPSR & ARM_SR_V) != 0; + break; + + case 4: //HI/LS + execute = (cpu->CPSR & ARM_SR_C) && !(cpu->CPSR & ARM_SR_Z); + break; + + case 5: //GE/LT + execute = !(cpu->CPSR & ARM_SR_N) == !(cpu->CPSR & ARM_SR_V); //check for N == V + break; + + case 6: //GT/LE + execute = !(cpu->CPSR & ARM_SR_N) == !(cpu->CPSR & ARM_SR_V); //check for N == V + execute = execute && !(cpu->CPSR & ARM_SR_Z); //enforce Z==0 + break; + + case 7: + specialInstr = (instr & 0x10000000UL) != 0; + execute = true; + break; + } + if((instr & 0x10000000UL) && !specialInstr) execute = !execute; //invert for inverted conditions + } + + //execute, if needed + if(execute){ + UInt64 v64; + register UInt32 adr, tmp, v32; + UInt32 m32, x32; //non-register 32-bit val + UInt16 v16; + UInt8 va8, vb8 = 0, vc8; + + switch((instr >> 24) & 0x0F){ + + case 0: + case 1: //data processing immediate shift, register shift and misc instrs and mults + if(specialInstr) goto invalid_instr; + + if((instr & 0x00000090UL) == 0x00000090){ //multiplies, extra load/stores (table 3.2) + + if((instr & 0x00000060UL) == 0x00000000){ //swp[b], mult(acc), mult(acc) long + + if(instr & 0x01000000UL){ //SWB/SWPB + + switch((instr >> 20) & 0x0F){ + + case 0: //SWP + + adr = cpuPrvGetReg(cpu, (instr >> 16) & 0x0F, wasT, specialPC); + ok = cpu->memF(cpu, &m32, adr, 4, false, privileged, &fsr); + if(!ok){ + cpuPrvHandleMemErr(cpu, adr, 4, false, false, fsr); + goto instr_done; + } + tmp = m32; + m32 = cpuPrvGetReg(cpu, instr & 0x0F, wasT, specialPC); + ok = cpu->memF(cpu, &m32, adr, 4, true, privileged, &fsr); + if(!ok){ + cpuPrvHandleMemErr(cpu, adr, 4, true, false, fsr); + goto instr_done; + } + cpuPrvSetReg(cpu, (instr >> 12) & 0x0F, tmp); + break; + + case 4: //SWPB + + adr = cpuPrvGetReg(cpu, (instr >> 16) & 0x0F, wasT, specialPC); + ok = cpu->memF(cpu, &vc8, adr, 1, false, privileged, &fsr); + if(!ok){ + cpuPrvHandleMemErr(cpu, adr, 1, false, false, fsr); + goto instr_done; + } + va8 = vc8; + vc8 = cpuPrvGetReg(cpu, instr & 0x0F, wasT, specialPC); + ok = cpu->memF(cpu, &vc8, adr, 1, true, privileged, &fsr); + if(!ok){ + cpuPrvHandleMemErr(cpu, adr, 1, true, false, fsr); + goto instr_done; + } + cpuPrvSetReg(cpu, (instr >> 12) & 0x0F, va8); + break; + + #ifdef ARM_V6 + + /* about exclusives: these are for SMP. we do not have SMP, so for now they always succeed */ + + case 8: //STREX + + if((instr & 0x00000F00UL) != 0x00000F00UL) goto invalid_instr; + + adr = cpuPrvGetReg(cpu, (instr >> 16) & 0x0F, wasT, specialPC); + tmp = cpuPrvGetReg(cpu, instr & 0x0F, wasT, specialPC); + ok = cpu->memF(cpu, &tmp, adr, 4, true, privileged, &fsr); + if(!ok){ + cpuPrvHandleMemErr(cpu, adr, 4, true, false, fsr); + goto instr_done; + } + cpuPrvSetReg(cpu, (instr >> 12) & 0x0F, 0); //0 -> success + break; + + + case 9: //LDREX + + if((instr & 0x00000F0FUL) != 0x00000F0FUL) goto invalid_instr; + adr = cpuPrvGetReg(cpu, (instr >> 16) & 0x0F, wasT, specialPC); + ok = cpu->memF(cpu, &tmp, adr, 4, false, privileged, &fsr); + if(!ok){ + cpuPrvHandleMemErr(cpu, adr, 4, false, false, fsr); + goto instr_done; + } + cpuPrvSetReg(cpu, (instr >> 12) & 0x0F, tmp); + break; + + /* these are a v7/v6K thing - we do not bother + case 10: //STREXD + + //TODO + + + case 11: //LDREXD + + //TODO + + + case 12: //STREXB + + //TODO + + + case 13: //LDREXB + + //TODO + + + case 14: //STREXH + + //TODO + + + case 15: //LDREXH + + //TODO + */ + #endif + default: + goto invalid_instr; + } + + } + else switch((instr >> 20) & 0x0F){ //multiplies + + case 0: //MUL + case 1: + + tmp = 0; + if(instr & 0x0000F000UL) goto invalid_instr; + goto mul32; + + + case 2: //MLA + case 3: + + tmp = cpuPrvGetReg(cpu, (instr >> 12 ) & 0x0F, wasT, specialPC); + mul32: + tmp += cpuPrvGetReg(cpu, (instr >> 8) & 0x0F, wasT, specialPC) * cpuPrvGetReg(cpu, instr & 0x0F, wasT, specialPC); + cpuPrvSetReg(cpu, (instr >> 16) & 0x0F, tmp); + if(instr & 0x00100000UL){ //S + + adr = cpu->CPSR &~ (ARM_SR_Z | ARM_SR_N); + if(!tmp) adr |= ARM_SR_Z; + if(tmp & 0x80000000UL) adr |= ARM_SR_N; + cpu->CPSR = adr; + } + goto instr_done; + + #ifdef ARM_V6 + case 4: //UMAAL + + v64 = u64_32_to_64((instr >> 12) & 0x0F); + v64 = u64_add32(v64, (instr >> 16) & 0x0F); + goto mul64; + + + case 6: //MLS + + tmp = cpuPrvGetReg(cpu, (instr >> 8) & 0x0F, wasT, specialPC); + tmp *= cpuPrvGetReg(cpu, instr & 0x0F, wasT, specialPC); + tmp = cpuPrvGetReg(cpu, (instr >> 12) & 0x0F, wasT, specialPC) - tmp; + cpuPrvSetReg(cpu, (instr >> 16) & 0x0F, tmp); + break; + + #endif + case 8: //UMULL + case 9: + case 12: //SMULL + case 13: + + v64 = u64_zero(); + goto mul64; + + case 10: //UMLAL + case 11: + case 14: //SMLAL + case 15: + + v64 = u64_from_halves(cpuPrvGetReg(cpu, (instr >> 16) & 0x0F, wasT, specialPC), cpuPrvGetReg(cpu, (instr >> 12) & 0x0F, wasT, specialPC)); + + mul64: + adr = cpuPrvGetReg(cpu, (instr >> 8) & 0x0F, wasT, specialPC); + tmp = cpuPrvGetReg(cpu, instr & 0x0F, wasT, specialPC); + + v64 = u64_add(v64, (instr & 0x00400000UL) ? u64_smul3232(adr, tmp) : u64_umul3232(adr, tmp)); + + v32 = u64_get_hi(v64); + cpuPrvSetReg(cpu, (instr >> 12) & 0x0F, u64_64_to_32(v64)); + cpuPrvSetReg(cpu, (instr >> 16) & 0x0F, v32); + + if(instr & 0x00100000UL){ //S + + adr = cpu->CPSR &~ (ARM_SR_Z | ARM_SR_N); + if(u64_isZero(v64)) adr |= ARM_SR_Z; + if(v32 & 0x80000000UL) adr |= ARM_SR_N; + cpu->CPSR = adr; + } + break; + + default: + goto invalid_instr; + } + } + else{ //load/store signed/unsigned byte/halfword/two_words + + UInt32 store[2] = {0,0}; + UInt8* store8 = (UInt8*)store; + UInt16* store16 = (UInt16*)store; + + va8 = cpuPrvArmAdrMode_3(cpu, instr, &m32, &x32, wasT, specialPC); + tmp = m32; + v32 = x32; + if(va8 & ARM_MODE_3_INV ) goto invalid_instr; + adr = cpuPrvGetReg(cpu, va8 & ARM_MODE_3_REG, wasT, specialPC); + + switch(va8 & ARM_MODE_3_TYPE){ + case ARM_MODE_3_H: + case ARM_MODE_3_SH: + vb8 = 2; + break; + + case ARM_MODE_3_SB: + vb8 = 1; + break; + + case ARM_MODE_3_D: + vb8 = 8; + break; + } + if(va8 & ARM_MODE_3_LOAD){ + + ok = cpu->memF(cpu, store, adr + tmp, vb8, false, privileged, &fsr); + if(!ok){ + cpuPrvHandleMemErr(cpu, adr + tmp, vb8, false, false, fsr); + goto instr_done; + } + if(vb8 == 1){ + tmp = *store8; + if(tmp & 0x80) tmp |= 0xFFFFFF00UL; //sign-extend + cpuPrvSetReg(cpu, (instr >> 12) & 0x0F, tmp); + } + else if(vb8 == 2){ + tmp = *store16; + if(((va8 & ARM_MODE_3_TYPE) == ARM_MODE_3_SH) && (tmp & 0x8000UL)) tmp |= 0xFFFF0000UL; + cpuPrvSetReg(cpu, (instr >> 12) & 0x0F, tmp); + } + else{ + cpuPrvSetReg(cpu, ((instr >> 12) & 0x0F) + 0, store[0]); + cpuPrvSetReg(cpu, ((instr >> 12) & 0x0F) + 1, store[1]); + } + if(v32) cpuPrvSetReg(cpu, va8 & ARM_MODE_3_REG, v32 + adr); + } + else{ + if(v32){ + v32 += adr; + va8 |= ARM_MODE_3_INV; //re-use flag to mean writeback + } + if(vb8 == 1){ + *store8 = cpuPrvGetReg(cpu, (instr >> 12) & 0x0F, wasT, specialPC); + } + else if(vb8 == 2){ + *store16 = cpuPrvGetReg(cpu, (instr >> 12) & 0x0F, wasT, specialPC); + } + else{ + store[0] = cpuPrvGetReg(cpu, ((instr >> 12) & 0x0F) + 0, wasT, specialPC); + store[1] = cpuPrvGetReg(cpu, ((instr >> 12) & 0x0F) + 1, wasT, specialPC); + } + adr += tmp; + ok = cpu->memF(cpu, store, adr, vb8, true, privileged, &fsr); + if(!ok){ + cpuPrvHandleMemErr(cpu, adr, vb8, true, false, fsr); + goto instr_done; + } + if(va8 & ARM_MODE_3_INV) cpuPrvSetReg(cpu, va8 & ARM_MODE_3_REG, v32); + } + } + goto instr_done; + } + else if((instr & 0x01900000UL) == 0x01000000UL){ //misc instrs (table 3.3) + + tmp = (instr >> 4) & 0x0F; + + switch(tmp){ + + case 0: //move reg to PSR or move PSR to reg + + if((instr & 0x00BF0FFFUL) == 0x000F0000UL){ //move PSR to reg + + cpuPrvSetReg(cpu, (instr >> 12) & 0x0F, (instr & 0x00400000UL) ? cpu->SPSR : cpu->CPSR); //access in user and sys mode is undefined. for us that means returning garbage that is currently in "cpu->SPSR" + } + else if((instr & 0x00B0FFF0UL) == 0x0020F000UL){ //move reg to PSR + + cpuPrvSetPSR(cpu, (instr >> 16) & 0x0F, privileged, (instr & 0x00400000UL) !=0, cpuPrvGetReg(cpu, instr & 0x0F, wasT, specialPC)); + } + else goto invalid_instr; + goto instr_done; + + case 1: //BLX/BX/BXJ or CLZ + case 3: + + if(instr & 0x00400000UL){ //CLZ + + if((instr & 0x0FFF0FF0UL) != 0x016F0F10UL) goto invalid_instr; + tmp = cpuPrvGetReg(cpu, instr &0xF, wasT, specialPC); + adr = 0x80000000UL; + for(va8 = 0; va8 < 32; va8++, adr >>= 1) if(tmp & adr) break; + cpuPrvSetReg(cpu, (instr >> 12) & 0x0F, va8); + } + else{ //BL / BLX / BXJ + + if((instr & 0x0FFFFF00UL) != 0x012FFF00UL) goto invalid_instr; + + if((instr & 0x00000030UL) == 0x00000030UL) cpuPrvSetReg(cpu, 14, instrPC + (wasT ? 3 : 4)); //save return value for BLX + cpuPrvSetPC(cpu, cpuPrvGetReg(cpu, instr & 0x0F, wasT, specialPC)); + } + goto instr_done; + + case 5: //enhanced DSP adds/subtracts + + if(instr & 0x00000F00UL) goto invalid_instr; + tmp = cpuPrvGetReg(cpu, instr & 0x0F, wasT, specialPC); //Rm + adr = cpuPrvGetReg(cpu, (instr >> 16) & 0x0F, wasT, specialPC); //Rn + vb8 = 0; //used as boolead for if saturation happened + switch((instr >> 21) & 3){ //what op? + + case 0: //QADD + + v32 = tmp + adr; + vb8 = cpuPrvSignedAdditionOverflows(adr, tmp, v32); + if(vb8) v32 = cpuPrvMedia_signedSaturate32(adr); + break; + + case 1: //QSUB + + v32 = tmp - adr; + vb8 = cpuPrvSignedAdditionOverflows(tmp, adr, v32); + if(vb8) v32 = cpuPrvMedia_signedSaturate32(tmp); + break; + case 2: //QDADD + + v32 = adr << 1; + vb8 = cpuPrvSignedAdditionOverflows(adr, tmp, v32); + if(vb8) v32 = cpuPrvMedia_signedSaturate32(adr); + adr = v32; + v32 = tmp + adr; + if(cpuPrvSignedAdditionOverflows(adr, tmp, v32)){ + vb8 = 1; + v32 = cpuPrvMedia_signedSaturate32(adr); + } + break; + + case 3: //QDSUB + + v32 = adr << 1; + vb8 = cpuPrvSignedAdditionOverflows(adr, tmp, v32); + if(vb8) v32 = cpuPrvMedia_signedSaturate32(adr); + adr = v32; + v32 = tmp + adr; + if(cpuPrvSignedAdditionOverflows(adr, tmp, v32)){ + vb8 = 1; + v32 = cpuPrvMedia_signedSaturate32(adr); + } + break; + + default: + v32 = 0; //make compiler happy; + break; + + } + cpuPrvSetReg(cpu, (instr >> 12) & 0x0F, v32); //save result + if(vb8) cpu->CPSR |= ARM_SR_Q; + goto instr_done; + + case 7: //soft breakpoint + + cpuPrvException(cpu, cpu->vectorBase + ARM_VECTOR_OFFT_P_ABT, instrPC + 4, ARM_CPSR_PAB_ORR | (cpu->CPSR & ARM_CPSR_PAB_ORR)); + goto instr_done; + + case 8: //enhanced DSP multiplies + case 9: + case 10: + case 11: + case 12: + case 13: + case 14: + case 15: + if((instr & 0x00000090UL) != 0x00000080UL) goto invalid_instr; + tmp = cpuPrvGetReg(cpu, instr & 0x0F, wasT, specialPC); //Rm + adr = cpuPrvGetReg(cpu, (instr >> 8) & 0x0F, wasT, specialPC); //Rs + vb8 = 0; //used as boolead for if saturation happened + va8 = 0; //used as temporary boolean flag + switch((instr >> 21) & 3){ //what op? + case 0: //SMLAxy + if(instr & 0x20) tmp >>= 16; + else tmp &= 0xFFFFUL; + if(tmp & 0x8000UL) tmp |= 0xFFFF0000UL; + + if(instr & 0x40) adr >>= 16; + else adr &= 0xFFFFUL; + if(adr & 0x8000UL) adr |= 0xFFFF0000UL; + + tmp *= adr; + adr = cpuPrvGetReg(cpu, (instr >> 12) & 0x0F, wasT, specialPC); //Rn + v32 = tmp + adr; + vb8 = cpuPrvSignedAdditionOverflows(adr, tmp, v32); + break; + + case 1: //SMLAWy/SMULWy + + if(instr & 0x40) adr >>= 16; + else adr &= 0xFFFFUL; + if(adr & 0x8000UL) adr |= 0xFFFF0000UL; + + adr = u64_64_to_32(u64_shr(u64_smul3232(tmp, adr), 16)); //do the multiplication, WAS: adr = (((UInt64)tmp) * ((UInt64)adr)) >> 16; + + if(instr & 0x20){ //SMULWy + + v32 = adr; + if(instr & 0x0000F000UL) goto invalid_instr; + } + else{ //SMLAWy + + tmp = cpuPrvGetReg(cpu, (instr >> 12) & 0x0F, wasT, specialPC); //Rn + v32 = adr + tmp; + vb8 = cpuPrvSignedAdditionOverflows(adr, tmp, v32); + } + break; + + case 2: //SMLALxy + + if(instr & 0x20) tmp >>= 16; + else tmp &= 0xFFFFUL; + if(tmp & 0x8000UL) tmp |= 0xFFFF0000UL; + + if(instr & 0x40) adr >>= 16; + else adr &= 0xFFFFUL; + if(adr & 0x8000UL) adr |= 0xFFFF0000UL; + + adr *= tmp; + if(adr & 0x80000000UL) va8 |= 1; //neg + tmp = cpuPrvGetReg(cpu, (instr >> 12) & 0x0F, wasT, specialPC); //RdLo + if((tmp + adr) < tmp) va8 |= 2; //carry + cpuPrvSetReg(cpu, (instr >> 12) & 0x0F, tmp); + v32 = cpuPrvGetReg(cpu, (instr >> 16) & 0x0F, wasT, specialPC); //RdHi + if(va8 & 2) v32++; + if(va8 & 1) v32--; + break; + + case 3: //SMULxy + + if(instr & 0x0000F000UL) goto invalid_instr; + + if(instr & 0x20) tmp >>= 16; + else tmp &= 0xFFFFUL; + if(tmp & 0x8000UL) tmp |= 0xFFFF0000UL; + + if(instr & 0x40) adr >>= 16; + else adr &= 0xFFFFUL; + if(adr & 0x8000UL) adr |= 0xFFFF0000UL; + + v32 = tmp * adr; + break; + + default: //make compiler happy + + v32 = 0; + break; + } + cpuPrvSetReg(cpu, (instr >> 16) & 0x0F, v32); + if(vb8) cpu->CPSR |= ARM_SR_Q; + goto instr_done; + + default: + goto invalid_instr; + } + } + + goto data_processing; + break; + + case 2: + case 3: //data process immediate val, move imm to SR + + if(specialInstr) goto invalid_instr; + + if((instr & 0x01900000UL) == 0x01000000UL){ //all NON-data-processing instrs in this space are here + + if(instr & 0x00200000UL){ //MSR imm and hints + + if((instr & 0x00400000UL) || (instr & 0x000F0000UL)){ //move imm to PSR + + cpuPrvSetPSR(cpu, (instr >> 16) & 0x0F, privileged, (instr & 0x00400000UL) != 0, cpuPrvROR(instr & 0xFF, ((instr >> 8) & 0x0F) * 2)); + } + else{ + #ifdef ARM_V6 + if((instr & 0x000000F0UL) == 0x000000F0){ //debug hint + + err_str("DEBUG hint 0x"); + err_hex(instr & 0x0F); + err_str(" at 0x"); + err_hex(instrPC); + err_str("\r\n"); + } + else switch(instr){ + + case 0: //NOP + break; + + case 1: //YIELD; + break; + + case 2: //WFE + break; + + case 3: //WFI + break; + + case 4: //SEV + break; + } + goto instr_done; //all hints are treated as valid and do nothing... + #endif + goto invalid_instr; + } + } + else if(instr & 0x00400000UL){ //MOVT (high halfword 16-bit immediate load) + + adr = cpuPrvGetReg(cpu, (instr >> 12) & 0x0F, wasT, specialPC) & 0xFFFFUL; + adr |= ((instr & 0xFFFUL) << 16) | ((instr & 0xF0000UL) << 12); + cpuPrvSetReg(cpu, (instr >> 12) & 0x0F, adr); + } + else{ //MOVW (16-bit immediate load) + + cpuPrvSetReg(cpu, (instr >> 12) & 0x0F, (instr & 0xFFFUL) | ((instr >> 4) & 0xF000UL)); + } + goto instr_done; + } + +data_processing: //data processing + { + Boolean carryOut, carryIn, V, S, store = true; + S = (instr & 0x00100000UL) != 0; + V = (cpu->CPSR & ARM_SR_V) != 0; + carryIn = (cpu->CPSR & ARM_SR_C) != 0; + tmp = cpuPrvArmAdrMode_1(cpu, instr, &carryOut, wasT, specialPC); + va8 = (instr >> 16) & 0x0F; + + switch((instr >> 21) & 0x0F){ + case 0: //AND + tmp = cpuPrvGetReg(cpu, va8, wasT, specialPC) & tmp; + break; + + case 1: //EOR + + tmp = cpuPrvGetReg(cpu, va8, wasT, specialPC) ^ tmp; + break; + + case 2: //SUB + + adr = cpuPrvGetReg(cpu, va8, wasT, specialPC); + v32 = adr - tmp; + if(S) V = cpuPrvSignedSubtractionOverflows(adr, tmp, v32); + if(S) carryOut = adr >= tmp; + tmp = v32; + break; + + case 3: //RSB + + adr = cpuPrvGetReg(cpu, va8, wasT, specialPC); + v32 = tmp - adr; + if(S) V = cpuPrvSignedSubtractionOverflows(tmp, adr, v32); + if(S) carryOut = tmp >= adr; + tmp = v32; + break; + + case 4: //ADD + + adr = cpuPrvGetReg(cpu, va8, wasT, specialPC); + v32 = adr + tmp; + if(S) V = cpuPrvSignedAdditionOverflows(adr, tmp, v32); + if(S) carryOut = v32 < adr; + tmp = v32; + break; + + case 5: //ADC + + adr = cpuPrvGetReg(cpu, va8, wasT, specialPC); + if(carryIn){ + v32 = adr + tmp + 1; + if(S) carryOut = v32 <= adr; + } + else{ + v32 = adr + tmp; + if(S) carryOut = v32 < adr; + } + if(S) V = cpuPrvSignedAdditionOverflows(adr, tmp, v32); + tmp = v32; + break; + + case 6: //SBC + + adr = cpuPrvGetReg(cpu, va8, wasT, specialPC); + if(carryIn){ + + v32 = adr - tmp; + if(S) carryOut = adr >= tmp; + } + else{ + v32 = adr - tmp - 1; + if(S) carryOut = adr > tmp; + } + if(S) V = cpuPrvSignedSubtractionOverflows(adr, tmp, v32); + tmp = v32; + break; + + case 7: //RSC + + adr = cpuPrvGetReg(cpu, va8, wasT, specialPC); + if(carryIn){ + + v32 = tmp - adr; + if(S) carryOut = tmp >= adr; + } + else{ + v32 = tmp - adr - 1; + if(S) carryOut = tmp > adr; + } + if(S) V = cpuPrvSignedSubtractionOverflows(tmp, adr, v32); + tmp = v32; + break; + + case 8: //TST + if(!S) goto invalid_instr; + store = false; + tmp = cpuPrvGetReg(cpu, va8, wasT, specialPC) & tmp; + break; + + case 9: //TEQ + + if(!S) goto invalid_instr; + store = false; + tmp = cpuPrvGetReg(cpu, va8, wasT, specialPC) ^ tmp; + break; + + case 10: //CMP + + if(!S) goto invalid_instr; + store = false; + adr = cpuPrvGetReg(cpu, va8, wasT, specialPC); + V = cpuPrvSignedSubtractionOverflows(adr, tmp, adr - tmp); //((adr ^ tmp) & (adr ^ (adr - tmp))) >> 31; + carryOut = adr >= tmp; + tmp = adr - tmp; + break; + + case 11: //CMN + + if(!S) goto invalid_instr; + store = false; + adr = cpuPrvGetReg(cpu, va8, wasT, specialPC); + v32 = adr + tmp; + V = cpuPrvSignedAdditionOverflows(adr, tmp, v32); + carryOut = v32 < adr; + tmp = v32; + break; + + case 12: //ORR + + tmp = cpuPrvGetReg(cpu, va8, wasT, specialPC) | tmp; + break; + + case 13: //MOV + + //tmp already equals tmp + break; + + case 14: //BIC + + tmp = cpuPrvGetReg(cpu, va8, wasT, specialPC) & ~tmp; + break; + + case 15: //MVN + + tmp = ~tmp; + break; + } + vb8 = (instr >> 12) & 0x0F; + if(S){ //update flags or restore CPSR + + if(!usesUsrRegs && vb8 == 15 && store){ + + UInt32 sr; + + sr = cpu->SPSR; + cpuPrvSwitchToMode(cpu, sr & ARM_SR_M); + cpu->CPSR = sr; + cpu->regs[15] = tmp; //do it right here - if we let it use cpuPrvSetReg, it will check lower bit... + store = false; + } + else{ + adr = cpu->CPSR &~ (ARM_SR_Z | ARM_SR_N | ARM_SR_C | ARM_SR_V); + if(!tmp) adr |= ARM_SR_Z; + if(tmp & 0x80000000UL) adr |= ARM_SR_N; + if(carryOut) adr |= ARM_SR_C; + if(V) adr |= ARM_SR_V; + cpu->CPSR = adr; + } + } + if(store){ + if(vb8 == 15){ + cpuPrvSetReg(cpu, vb8, tmp &~ 1UL); + cpu->CPSR &=~ ARM_SR_T; + if(tmp & 1) cpu->CPSR |= ARM_SR_T; + } + else{ + cpu->regs[vb8] = tmp; //not pc - no need for func call cpuPrvSetReg(cpu, vb8, tmp); + } + } + goto instr_done; + } + break; + + case 4: + case 5: //load/stor imm offset + + goto load_store_mode_2; + break; + + case 6: + case 7: //load/store reg offset + + if(instr & 0x00000010UL){ //media and undefined instrs + + #ifdef ARM_V6 + if(cpuPrvMediaInstrs(cpu, instr, wasT, specialPC)) goto instr_done; + #endif + goto invalid_instr; + } + +load_store_mode_2: + if(specialInstr){ //handle PLD + + if((instr & 0x0D70F000UL) == 0x0550F000UL) goto instr_done; //PLD + goto invalid_instr; + } + + va8 = cpuPrvArmAdrMode_2(cpu, instr, &m32, &x32, wasT, specialPC); + tmp = m32; + v32 = x32; + if(va8 & ARM_MODE_2_INV) goto invalid_instr; + if(va8 & ARM_MODE_2_T) privileged = false; + vb8 = (va8 & ARM_MODE_2_WORD) ? 4 : 1; //get operation size + + adr = cpuPrvGetReg(cpu, va8 & ARM_MODE_2_REG, wasT, specialPC); + + if(va8 & ARM_MODE_2_LOAD){ + + ok = cpu->memF(cpu, &m32, adr + tmp, vb8, false, privileged, &fsr); + if(!ok){ + cpuPrvHandleMemErr(cpu, adr + tmp, vb8, false, false, fsr); + goto instr_done; + } + if(vb8 == 1) m32 = *(UInt8*)&m32; //endian-free way to make it a valid 8-bit value, if need be + tmp = m32; + cpuPrvSetReg(cpu, (instr >> 12) & 0x0F, tmp); + if(v32) cpuPrvSetReg(cpu, va8 & ARM_MODE_2_REG, v32 + adr); + } + else{ + if(v32){ + v32 += adr; + va8 |= ARM_MODE_2_INV; //re-use flag to mean writeack + } + + adr += tmp; + if(vb8 == 1){ + m32 = 0; + *(UInt8*)&m32 = cpuPrvGetReg(cpu, (instr >> 12) & 0x0F, wasT, specialPC); + } + else{ + m32 = cpuPrvGetReg(cpu, (instr >> 12) & 0x0F, wasT, specialPC); + } + ok = cpu->memF(cpu, &m32, adr, vb8, true, privileged, &fsr); + if(!ok){ + cpuPrvHandleMemErr(cpu, adr, vb8, true, false, fsr); + goto instr_done; + } + if(va8 & ARM_MODE_2_INV) cpuPrvSetReg(cpu, va8 & ARM_MODE_2_REG, v32); + } + + goto instr_done; + + case 8: + case 9: //load/store multiple + + if(specialInstr) goto invalid_instr; + + va8 = cpuPrvArmAdrMode_4(cpu, instr, &v16); + if((va8 & ARM_MODE_4_S) && usesUsrRegs) goto invalid_instr; //no S mode please in modes with no baked regs //or SPSR + L = (instr & 0x00100000UL) != 0; + tmp = adr = cpuPrvGetReg(cpu, va8 & ARM_MODE_4_REG, wasT, specialPC); + + specialInstr = L && (va8 & ARM_MODE_4_S) && (v16 & 0x8000UL) && !usesUsrRegs; //specialInstr = "copyCPSR" + + for(vc8 = 0; vc8 < 16; vc8++){ + + vb8 = (va8 & ARM_MODE_4_INC) ? vc8 : 15 - vc8; + + if(v16 & (1UL << vb8)){ + + UInt32* reg = cpu->regs + vb8; + + if(L){ + if(va8 & ARM_MODE_4_S){ //handle LDM(2) and LDM(3) + + if(v16 & 0x8000UL){ //handle LDM(3) + + /* nothing to do here, we did all we need above in line beginning with "specialInstr=" */ + } + else if(!usesUsrRegs){ //handle LDM(2) + + if(vb8 >= 8 && vb8 <= 12 && (cpu->CPSR & ARM_SR_M) == ARM_SR_MODE_FIQ){ //handle fiq/usr banked regs + + reg = cpu->extra_regs + vb8 - 8; + } + else if(vb8 == 13){ + + reg = &cpu->bank_usr.R13; + } + else if(vb8 == 14){ + + reg = &cpu->bank_usr.R14; + } + } + } + else if(vb8 == 15){ //handle LDM(1)'s use of PC + + /* nothing to do here - all is handled below */ + } + } + else if(va8 & ARM_MODE_4_S){ //handle STM(2)'s access to user regs + + if(!usesUsrRegs){ + + if(vb8 >= 8 && vb8 <= 12 && (cpu->CPSR & ARM_SR_M) == ARM_SR_MODE_FIQ){ //handle fiq/usr banked regs + + reg = cpu->extra_regs + vb8 - 8; + } + else if(vb8 == 13){ + + reg = &cpu->bank_usr.R13; + } + else if(vb8 == 14){ + + reg = &cpu->bank_usr.R14; + } + } + } + if(va8 & ARM_MODE_4_BFR) adr += (va8 & ARM_MODE_4_INC) ? 4L : -4L; + ok = cpu->memF(cpu, reg, adr, 4, !L, privileged, &fsr); + if(!ok){ + cpuPrvHandleMemErr(cpu, adr, 4, !L, false, fsr); + if(v16 & (1UL << (va8 & ARM_MODE_4_REG))) cpuPrvSetReg(cpu, va8 & ARM_MODE_4_REG, tmp); + goto instr_done; + } + if(!(va8 & ARM_MODE_4_BFR)) adr += (va8 & ARM_MODE_4_INC) ? 4L : -4L; + } + } + if(va8 & ARM_MODE_4_WBK){ + cpuPrvSetReg(cpu, va8 & ARM_MODE_4_REG, adr); + } + + if(specialInstr){ //process LDM(3) SPSR->CPSR copy + v32 = cpu->SPSR; + cpuPrvSwitchToMode(cpu, v32 & ARM_SR_M); + cpu->CPSR = v32; + } + else if((v16 & 0x8000U) && !(va8 & ARM_MODE_4_S)){ //we just loaded PC + if(cpu->regs[15] & 1){ + cpu->regs[15] &=~ 1UL; + cpu->CPSR |= ARM_SR_T; + } + else{ + cpu->CPSR &=~ ARM_SR_T; + } + } + + goto instr_done; + + case 10: + case 11: //B/BL/BLX(if cond=0b1111) + + tmp = instr & 0x00FFFFFFUL; //get offset + if(tmp & 0x00800000UL) tmp |= 0xFF000000UL; //sign extend + tmp = tmp << (wasT ? 1 : 2); //shift left 2(ARM) or 1(thumb) + tmp += instrPC + (wasT ? 4 : 8); //add where PC would point in an ARM + if(specialInstr){ //handle BLX + if(instr & 0x01000000UL) tmp += 2; + cpu->regs[14] = instrPC + (wasT ? 2 : 4); + if(!(cpu->CPSR & ARM_SR_T)) tmp |= 1UL; //set T flag if needed + } + else{ //not BLX -> differentiate between BL and B + if(instr & 0x01000000UL) cpu->regs[14] = instrPC + (wasT ? 2 : 4); + if(cpu->CPSR & ARM_SR_T) tmp |= 1UL; //keep T flag as needed + } + cpuPrvSetPC(cpu, tmp); + goto instr_done; + + case 12: + case 13: //coprocessor load/store and double register transfers + + va8 = cpuPrvArmAdrMode_5(cpu, instr, &m32); + v32 = m32; + vb8 = (instr >> 8) & 0x0F; + + if(vb8 >= 14){ //cp14 and cp15 are for priviledged users only + if(!privileged) goto invalid_instr; + } + else if(!(cpu->CPAR & (1UL << vb8))) goto invalid_instr; //others are access-controlled by CPAR + + if(va8 & ARM_MODE_5_RR){ //handle MCRR, MRCC + + if(!cpu->coproc[vb8].twoRegF) goto invalid_instr; + if(!cpu->coproc[vb8].twoRegF(cpu, cpu->coproc[vb8].userData, (instr & 0x00100000UL) != 0, (instr >> 4) & 0x0F,(instr >> 12) & 0x0F, (instr >> 16) & 0x0F, instr & 0x0F)) goto invalid_instr; + } + else{ + vc8 = v32; + tmp = adr = cpuPrvGetReg(cpu, va8 & ARM_MODE_5_REG, wasT, specialPC); + tmp += v32; + + if(!cpu->coproc[vb8].memAccess) goto invalid_instr; + if(!cpu->coproc[vb8].memAccess(cpu, cpu->coproc[vb8].userData, specialInstr, (instr & 0x00400000UL) !=0, !(instr & 0x00100000UL), (instr >> 12) & 0x0F, (va8 & ARM_MODE_5_ADD_BEFORE) ? tmp : adr, (va8 & ARM_MODE_5_IS_OPTION) ? &vc8 : NULL)) goto invalid_instr; + if(va8 & ARM_MODE_5_ADD_AFTER) cpuPrvSetReg(cpu, va8 & ARM_MODE_5_REG, tmp); + } + goto instr_done; + + case 14: //coprocessor data processing and register transfers + + vb8 = (instr >> 8) & 0x0F; + + if(vb8 >= 14){ //cp14 and cp15 are for priviledged users only + if(!privileged) goto invalid_instr; + } + else if(!(cpu->CPAR & (1UL << vb8))) goto invalid_instr; //others are access-controlled by CPAR + + if(instr & 0x00000010UL){ //MCR/MRC + + if(!cpu->coproc[vb8].regXfer) goto invalid_instr; + 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; + } + else{ //CDP + + if(!cpu->coproc[vb8].dataProcessing) goto invalid_instr; + if(!cpu->coproc[vb8].dataProcessing(cpu, cpu->coproc[vb8].userData, specialInstr, (instr >> 20) & 0x0F, (instr >> 12) & 0x0F, (instr >> 16) & 0x0F, instr & 0x0F, (instr >> 5) & 0x07)) goto invalid_instr; + } + goto instr_done; + + case 15: //SWI + + if(specialInstr) goto invalid_instr; + + cpuPrvException(cpu, cpu->vectorBase + ARM_VECTOR_OFFT_SWI, instrPC + (wasT ? 2 : 4), ARM_CPSR_SWI_ORR | (cpu->CPSR & ARM_CPSR_SWI_AND)); + goto instr_done; + } + + invalid_instr: + + if(instr == HYPERCALL_ARM && privileged){ + if(cpu->hypercallF && cpu->hypercallF(cpu)) goto instr_done; + } + + err_str("Invalid instr 0x"); + err_hex(instr); + err_str(" seen at 0x"); + err_hex(instrPC); + err_str(". CPSR=0x"); + err_hex(cpu->CPSR); + err_str("\r\n"); + cpuPrvException(cpu, cpu->vectorBase + ARM_VECTOR_OFFT_UND, instrPC + (wasT ? 2 : 4), ARM_CPSR_UND_ORR | (cpu->CPSR & ARM_CPSR_UND_AND)); + + instr_done:; + } + + return errNone; +} + +static Err cpuPrvCycleArm(ArmCpu* cpu){ + + Boolean privileged, ok; + UInt32 instr, pc; + UInt8 fsr; + + privileged = (cpu->CPSR & ARM_SR_M) != ARM_SR_MODE_USR; + //fetch instruction + { + ok = icacheFetch(&cpu->ic, pc = cpu->regs[15], 4, privileged, &fsr, &instr); + if(!ok){ + cpuPrvHandleMemErr(cpu, cpu->regs[15], 4, false, true, fsr); + return errNone; //exit here so that debugger can see us execute first instr of execption handler + } + cpu->regs[15] += 4; + } + + return cpuPrvExecInstr(cpu, instr, pc, false, privileged, false); +} + + +static Err cpuPrvCycleThumb(ArmCpu* cpu){ + + Boolean privileged, vB, specialPC = false, ok; + UInt32 instr = 0xE0000000UL /*most likely thing*/, pc; + UInt16 instrT, v16; + UInt8 v8, fsr; + + privileged = (cpu->CPSR & ARM_SR_M) != ARM_SR_MODE_USR; + + pc = cpu->regs[15]; + ok = icacheFetch(&cpu->ic, pc, 2, privileged, &fsr, &instrT); + if(!ok){ + cpuPrvHandleMemErr(cpu, pc, 2, false, true, fsr); + return errNone; //exit here so that debugger can see us execute first instr of execption handler + } + cpu->regs[15] += 2; + + switch(instrT >> 12){ + + case 0: // LSL(1) LSR(1) ASR(1) ADD(1) SUB(1) ADD(3) SUB(3) + case 1: + if((instrT & 0x1800) != 0x1800){ // LSL(1) LSR(1) ASR(1) + + instr |= 0x01B00000UL | ((instrT & 0x7) << 12) | ((instrT >> 3) & 7) | ((instrT >> 6) & 0x60) | ((instrT << 1) & 0xF80); + } + else{ + vB = (instrT & 0x0200) != 0; // SUB or ADD ? + instr |= ((vB ? 5UL : 9UL) << 20) | (((UInt32)(instrT & 0x38)) << 13) | ((instrT & 0x07) << 12) | ((instrT >> 6) & 0x07); + + if(instrT & 0x0400){ // ADD(1) SUB(1) + + instr |= 0x02000000UL; + } + else{ // ADD(3) SUB(3) + + // nothing to do here + } + } + break; + + case 2: // MOV(1) CMP(1) ADD(2) SUB(2) + case 3: + instr |= instrT & 0x00FF; + switch((instrT >> 11) & 3){ + case 0: // MOV(1) + instr |= 0x03B00000UL | ((instrT & 0x0700) << 4); + break; + + case 1: // CMP(1) + instr |= 0x03500000UL | (((UInt32)(instrT & 0x0700)) << 8); + break; + + case 2: // ADD(2) + instr |= 0x02900000UL | ((instrT & 0x0700) << 4) | (((UInt32)(instrT & 0x0700)) << 8); + break; + + case 3: // SUB(2) + instr |= 0x02500000UL | ((instrT & 0x0700) << 4) | (((UInt32)(instrT & 0x0700)) << 8); + break; + } + break; + + case 4: // LDR(3) ADD(4) CMP(3) MOV(3) BX MVN CMP(2) CMN TST ADC SBC NEG MUL LSL(2) LSR(2) ASR(2) ROR AND EOR ORR BIC + + if(instrT & 0x0800){ // LDR(3) + + instr |= 0x059F0000UL | ((instrT & 0xFF) << 2) | ((instrT & 0x700) << 4); + specialPC = true; + } + else if(instrT & 0x0400){ // ADD(4) CMP(3) MOV(3) BX + + UInt8 vD; + + vD = (instrT & 7) | ((instrT >> 4) & 0x08); + v8 = (instrT >> 3) & 0xF; + + switch((instrT >> 8) & 3){ + + case 0: // ADD(4) + + instr |= 0x00800000UL | (((UInt32)vD) << 16) | (((UInt32)vD) << 12) | v8; + break; + + case 1: // CMP(3) + + instr |= 0x01500000UL | (((UInt32)vD) << 16) | v8; + break; + + case 2: // MOV(3) + + instr |= 0x01A00000UL | (((UInt32)vD) << 12) | v8; + break; + + case 3: // BX + + if(instrT == 0x4778){ //special handing for thumb's "BX PC" as aparently docs are wrong on it + + cpuPrvSetPC(cpu, (cpu->regs[15] + 2) &~ 3UL); + goto instr_done; + } + + instr |= 0x012FFF10UL | ((instrT >> 3) & 0x0F); + break; + } + } + else{ // AND EOR LSL(2) LSR(2) ASR(2) ADC SBC ROR TST NEG CMP(2) CMN ORR MUL BIC MVN (in val_tabl order) + static const UInt32 val_tabl[16] = {0x00100000UL, 0x00300000UL, 0x01B00010UL, 0x01B00030UL, 0x01B00050UL, 0x00B00000UL, 0x00D00000UL, 0x01B00070UL, 0x01100000UL, 0x02700000UL, 0x01500000UL, 0x01700000UL, 0x01900000UL, 0x00100090UL, 0x01D00000UL, 0x01F00000UL}; + + //00 = none + //10 = bit0 val + //11 = bit3 val + //MVN BIC MUL ORR CMN CMP(2) NEG TST ROR SBC ADC ASR(2) LSR(2) LSL(2) EOR AND + + const UInt32 use16 = 0x2AAE280AUL; //0010 1010 1010 1110 0010 1000 0000 1010 + const UInt32 use12 = 0xA208AAAAUL; //1010 0010 0000 1000 1010 1010 1010 1010 + const UInt32 use8 = 0x0800C3F0UL; //0000 1000 0000 0000 1100 0011 1111 0000 + const UInt32 use0 = 0xFFF3BEAFUL; //1111 1111 1111 0011 1011 1110 1010 1111 + UInt8 vals[4] = {0}; + + vals[2] = (instrT & 7); + vals[3] = (instrT >> 3) & 7; + v8 = (instrT >> 6) & 15; + instr |= val_tabl[v8]; + v8 <<= 1; + instr |= ((UInt32)(vals[(use16 >> v8) & 3UL])) << 16; + instr |= ((UInt32)(vals[(use12 >> v8) & 3UL])) << 12; + instr |= ((UInt32)(vals[(use8 >> v8) & 3UL])) << 8; + instr |= ((UInt32)(vals[(use0 >> v8) & 3UL])) << 0; + } + break; + + case 5: // STR(2) STRH(2) STRB(2) LDRSB LDR(2) LDRH(2) LDRB(2) LDRSH (in val_tbl orver) + { + static const UInt32 val_tabl[8] = {0x07800000UL, 0x018000B0UL, 0x07C00000UL, 0x019000D0UL, 0x07900000UL, 0x019000B0UL, 0x07D00000UL, 0x019000F0UL}; + instr |= ((instrT >> 6) & 7) | ((instrT & 7) << 12) | (((UInt32)(instrT & 0x38)) << 13) | val_tabl[(instrT >> 9) & 7]; + } + break; + + case 6: // LDR(1) STR(1) (bit11 set = ldr) + + instr |= ((instrT & 7) << 12) | (((UInt32)(instrT & 0x38)) << 13) | ((instrT >> 4) & 0x7C) | 0x05800000UL; + if(instrT & 0x0800) instr |= 0x00100000UL; + break; + + case 7: // LDRB(1) STRB(1) (bit11 set = ldrb) + + instr |= ((instrT & 7) << 12) | (((UInt32)(instrT & 0x38)) << 13) | ((instrT >> 6) & 0x1F) | 0x05C00000UL; + if(instrT & 0x0800) instr |= 0x00100000UL; + break; + + case 8: // LDRH(1) STRH(1) (bit11 set = ldrh) + + instr |= ((instrT & 7) << 12) | (((UInt32)(instrT & 0x38)) << 13) | ((instrT >> 5) & 0x0E) | ((instrT >> 1) & 0x300) | 0x01C000B0UL; + if(instrT & 0x0800) instr |= 0x00100000UL; + break; + + case 9: // LDR(4) STR(3) (bit11 set = ldr) + + instr |= ((instrT & 0x700) << 4) | ((instrT & 0xFF) << 2) | 0x058D0000UL; + if(instrT & 0x0800) instr |= 0x00100000UL; + break; + + case 10: // ADD(5) ADD(6) (bit11 set = add(6)) + + instr |= ((instrT & 0x700) << 4) | (instrT &0xFF) | 0x028D0F00UL; //encode add to SP, line below sets the bit needed to reference PC instead when needed) + if(!(instrT & 0x0800)) instr |= 0x00020000UL; + else specialPC = true; + break; + + case 11: // ADD(7) SUB(4) PUSH POP BKPT + + if((instrT & 0x0600) == 0x0400){ //PUSH POP + + instr |= (instrT & 0xFF) | 0x000D0000UL; + + if(instrT & 0x0800){ //POP + + if(instrT & 0x0100) instr |= 0x00008000UL; + instr |= 0x08B00000UL; + } + else{ //PUSH + + if(instrT & 0x0100) instr |= 0x00004000UL; + instr |= 0x09200000UL; + } + } + else if(instrT & 0x0100){ + + goto undefined; + } + else switch((instrT >> 9) & 7){ + + case 0: // ADD(7) SUB(4) + + instr |= 0x020DDF00UL | (instrT & 0x7F) | ((instrT & 0x0080) ? 0x00400000UL : 0x00800000UL); + break; + #ifdef ARM_V6 + case 1: //SXTH SXTB UXTH UXTB + + instr |= 0x060F0070UL | ((instrT >> 3) & 7) | ((instrT & 7) << 12); + switch((instrT >> 6) & 3){ + + case 0: //SXTH + instr |= 0x00B00000UL; + break; + + case 1: //SXTB + instr |= 0x00A00000UL; + break; + + case 2: //UXTH + instr |= 0x00F00000UL; + break; + + case 3: //UXTB + instr |= 0x00E00000UL; + break; + } + break; + + case 3: //SETEND, CPY + + if((instrT & 0x00FE) == 0x0050){ //SETEND + + instr |= 0x01010000UL; + if(instrT & 0x0008) instr |= 0x00000200UL; + } + else if((instrT & 0x00E8) == 0x0060){ //CPS + + instr |= 0x01080000UL | ((instrT & 7) << 6); + if(instrT & 0x0010) instr |= 0x00040000UL; + } + else goto undefined; + break; + + case 5: //REV REV16, REVSH + + instr |= 0x060F0F00UL | ((instrT >> 3) & 7) | ((instrT & 7) << 12); + switch((instrT >> 6) & 3){ + + case 0: //REV + instr |= 0x00B00030UL; + break; + + case 1: //REV16 + instr |= 0x00B000B0UL; + break; + + case 2: // ??? + goto undefined; + + case 3: + instr |= 0x00F000B0UL; + break; + } + break; + #endif + case 7: //BKPT + + instr |= 0x01200070UL | (instrT & 0x0F) | ((instrT & 0xF0) << 4); + break; + + default: + + goto undefined; + } + break; + + case 12: // LDMIA STMIA (bit11 set = ldmia) + instr |= 0x08800000UL | (((UInt32)(instrT & 0x700)) << 8) | (instrT & 0xFF); + if(instrT & 0x0800) instr |= 0x00100000UL; + if(!((1UL << ((instrT >> 8) & 0x07)) & instrT)) instr |= 0x00200000UL; //set W bit if needed + break; + + case 13: // B(1), SWI, undefined instr space + v8 = ((instrT >> 8) & 0x0F); + if(v8 == 14){ // undefined instr + goto undefined; + } + else if(v8 == 15){ // SWI + instr |= 0x0F000000UL | (instrT & 0xFF); + } + else{ // B(1) + instr = (((UInt32)v8) << 28) | 0x0A000000UL | (instrT & 0xFF); + if(instrT & 0x80) instr |= 0x00FFFF00UL; + } + break; + + case 14: // B(2) BL BLX(1) undefined instr space + case 15: + v16 = (instrT & 0x7FF); + switch((instrT >> 11) & 3){ + + case 0: //B(2) + + instr |= 0x0A000000UL | v16; + if(instrT & 0x0400) instr |= 0x00FFF800UL; + break; + + case 1: //BLX(1)_suffix + instr = cpu->regs[15]; + cpu->regs[15] = (cpu->regs[14] + 2 + (((UInt32)v16) << 1)) &~ 3UL; + cpu->regs[14] = instr | 1UL; + cpu->CPSR &=~ ARM_SR_T; + goto instr_done; + + case 2: //BLX(1)_prefix BL_prefix + instr = v16; + if(instrT & 0x0400) instr |= 0x000FF800UL; + cpu->regs[14] = cpu->regs[15] + (instr << 12); + goto instr_done; + + case 3: //BL_suffix + instr = cpu->regs[15]; + cpu->regs[15] = cpu->regs[14] + 2 + (((UInt32)v16) << 1); + cpu->regs[14] = instr | 1UL; + goto instr_done; + } + + if(instrT & 0x0800) goto undefined; //avoid BLX_suffix and undefined instr space in there + instr |= 0x0A000000UL | (instrT & 0x7FF); + if(instrT & 0x0400) instr |= 0x00FFF800UL; + break; + } + +instr_execute: + return cpuPrvExecInstr(cpu, instr, pc, true, privileged, specialPC); +instr_done: + return errNone; +undefined: + if(instrT == HYPERCALL_THUMB){ + instr = HYPERCALL_ARM; + goto instr_execute; + } + + instr = 0xE7F000F0UL | (instrT & 0x0F) | ((instrT & 0xFFF0) << 4); //guranteed undefined instr, inside it we store the original thumb instr :)=-) + goto instr_execute; +} + +Err cpuInit(ArmCpu* cpu, UInt32 pc, ArmCpuMemF memF, ArmCpuEmulErr emulErrF, ArmCpuHypercall hypercallF, ArmSetFaultAdrF setFaultAdrF){ + + if(!TYPE_CHECK){ + emulErrF(cpu, "Type size error! CPU init aborted"); + return errInternal; + } + + __mem_zero(cpu, sizeof(ArmCpu)); + + cpu->CPSR = ARM_SR_I | ARM_SR_F | ARM_SR_MODE_SVC; //start w/o interrupts in supervisor mode + cpuPrvSetPC(cpu, pc); + + cpu->memF = memF; + cpu->emulErrF = emulErrF; + cpu->hypercallF = hypercallF; + cpu->setFaultAdrF = setFaultAdrF; + + icacheInit(&cpu->ic, cpu, memF); + + return errNone; +} + +Err cpuDeinit(_UNUSED_ ArmCpu* cpu){ + + return errNone; +} + +void cpuCycle(ArmCpu* cpu){ + + UInt32 vector, newCPSR; + + if(cpu->waitingFiqs && !(cpu->CPSR & ARM_SR_F)){ + + newCPSR = ARM_CPSR_FIQ_ORR | (cpu->CPSR & ARM_CPSR_FIQ_AND); + vector = cpu->vectorBase + ARM_VECTOR_OFFT_FIQ; + } + else if(cpu->waitingIrqs && !(cpu->CPSR & ARM_SR_I)){ + + newCPSR = ARM_CPSR_IRQ_ORR | (cpu->CPSR & ARM_CPSR_IRQ_AND); + vector = cpu->vectorBase + ARM_VECTOR_OFFT_IRQ; + } +#ifdef ARM_V6 + else if(cpu->impreciseAbtWaiting && !(cpu->CPSR & ARM_SR_A)){ + + newCPSR = ARM_CPSR_DAB_ORR | (cpu->CPSR & ARM_CPSR_DAB_AND); + vector = cpu->vectorBase + ARM_VECTOR_OFFT_D_ABT; + } +#endif + else{ + goto normal; + } + + cpuPrvException(cpu, vector, cpu->regs[15] + 4, newCPSR); + +normal: + + if(cpu->CPSR & ARM_SR_T){ + cpuPrvCycleThumb(cpu); + } + else{ + + cpuPrvCycleArm(cpu); + } +} + +void cpuIrq(ArmCpu* cpu, Boolean fiq, Boolean raise){ //unraise when acknowledged + + if(fiq){ + if(raise){ + cpu->waitingFiqs++; + } + else if(cpu->waitingFiqs){ + cpu->waitingFiqs--; + } + else{ + cpu->emulErrF(cpu,"Cannot unraise FIQ when none raised"); + } + } + else{ + if(raise){ + cpu->waitingIrqs++; + } + else if(cpu->waitingIrqs){ + cpu->waitingIrqs--; + } + else{ + cpu->emulErrF(cpu,"Cannot unraise IRQ when none raised"); + } + } +} + +void cpuIcacheInval(ArmCpu* cpu){ + + icacheInval(&cpu->ic); +} + +void cpuIcacheInvalAddr(ArmCpu* cpu, UInt32 addr){ + + icacheInvalAddr(&cpu->ic, addr); +} + + +void cpuCoprocessorRegister(ArmCpu* cpu, UInt8 cpNum, ArmCoprocessor* coproc){ + + cpu->coproc[cpNum] = *coproc; +} + +void cpuCoprocessorUnregister(ArmCpu* cpu, UInt8 cpNum){ + + ArmCoprocessor cp; + + __mem_zero(&cp, sizeof(ArmCoprocessor)); + + cpu->coproc[cpNum] = cp; +} + +void cpuSetVectorAddr(ArmCpu* cpu, UInt32 adr){ + + cpu->vectorBase = adr; +} + +UInt16 cpuGetCPAR(ArmCpu* cpu){ + + return cpu->CPAR; +} + +void cpuSetCPAR(ArmCpu* cpu, UInt16 cpar){ + + cpu->CPAR = cpar; +} + +#ifdef ARM_V6 + + void cpuSignalImpreciseAbt(ArmCpu* cpu, Boolean raise){ + + cpu->impreciseAbtWaiting = raise; + } + + +#endif + diff --git a/contrib/other/uarm/CPU.h b/contrib/other/uarm/CPU.h new file mode 100755 index 0000000000..3ef677d517 --- /dev/null +++ b/contrib/other/uarm/CPU.h @@ -0,0 +1,173 @@ +#ifndef _CPU_H_ +#define _CPU_H_ + + +//#define ARM_V6 //define to allow v6 instructions +//#define THUMB_2 //define to allow Thumb2 + +#include "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); + + +#endif + diff --git a/contrib/other/uarm/MMU.c b/contrib/other/uarm/MMU.c new file mode 100755 index 0000000000..5d68d7641e --- /dev/null +++ b/contrib/other/uarm/MMU.c @@ -0,0 +1,454 @@ +#include "MMU.h" + + + +void mmuTlbFlush(ArmMmu* mmu){ + + UInt8 i, j; + + for(i = 0; i < MMU_TLB_BUCKET_NUM; i++){ + for(j = 0; j < MMU_TLB_BUCKET_SIZE; j++) mmu->tlb[i][j].sz = 0; + mmu->replPos[i] = 0; + mmu->readPos[i] = 0; + } +} + + +void mmuInit(ArmMmu* mmu, ArmMmuReadF readF, void* userData){ + + __mem_zero(mmu, sizeof(ArmMmu)); + mmu->readF = readF; + mmu->userData = userData; + mmu->transTablPA = MMU_DISABLED_TTP; + mmu->domainCfg = 0; + mmuTlbFlush(mmu); +} + +void muDeinit(_UNUSED_ ArmMmu* mmu){ + + //nothing here +} + +static _INLINE_ UInt8 mmuPrvHashAddr(UInt32 addr){ //addresses are granular on 1K + + addr >>= 10; + + addr = addr ^ (addr >> 5) ^ (addr >> 10); + + return addr % MMU_TLB_BUCKET_NUM; +} + +Boolean mmuTranslate(ArmMmu* mmu, UInt32 adr, Boolean priviledged, Boolean write, UInt32* paP, UInt8* fsrP){ + + UInt32 va, pa = 0, sz, t; + UInt8 i, j, dom, ap = 0; + Boolean section = false, coarse = true, pxa_tex_page = false; + UInt8 bucket; + + //handle the 'MMU off' case + + if(mmu->transTablPA == MMU_DISABLED_TTP){ + va = pa = 0; + goto calc; + } + + //check the TLB + if(MMU_TLB_BUCKET_SIZE && MMU_TLB_BUCKET_NUM){ + + bucket = mmuPrvHashAddr(adr); + + for(j = 0, i = mmu->readPos[bucket]; j < MMU_TLB_BUCKET_SIZE; j++, i--){ + + if(i == 0xFF) i = MMU_TLB_BUCKET_SIZE - 1; + + va = mmu->tlb[bucket][i].va; + sz = mmu->tlb[bucket][i].sz; + + if(va <= adr && va + sz > adr){ + + pa = mmu->tlb[bucket][i].pa; + ap = mmu->tlb[bucket][i].ap; + dom = mmu->tlb[bucket][i].domain; + mmu->readPos[bucket] = i; + + goto check; + } + } + } + + //read first level table + + if(mmu->transTablPA & 3){ + *fsrP = 0x01; //alignment fault + return false; + } + + if(!mmu->readF(mmu->userData, &t, mmu->transTablPA + ((adr & 0xFFF00000) >> 18))){ + + *fsrP = 0x0C; //translation external abort first level + return false; + } + + dom = (t >> 5) & 0x0F; + switch(t & 3){ + + case 0: //fault + + *fsrP = 0x5; //section translation fault + return false; + + case 1: //coarse pagetable + + t &= 0xFFFFFC00UL; + t += (adr & 0x000FF000UL) >> 10; + break; + + case 2: //1MB section + + pa = t & 0xFFF00000UL; + va = adr & 0xFFF00000UL; + sz = 1UL << 20; + ap = (t >> 10) & 3; + section = true; + goto translated; + + case 3: //fine page table + + coarse = false; + t &= 0xFFFFF000UL; + t += (adr & 0x000FFC00UL) >> 8; + break; + } + + + //read second level table + + if(!mmu->readF(mmu->userData, &t, t)){ + *fsrP = 0x0E | (dom << 4); //translation external abort second level + return false; + } + + switch(t & 3){ + + case 0: //fault + + *fsrP = 0x07 | (dom << 4); //page translation fault + return false; + + case 1: //64K mapping + + pa = t & 0xFFFF0000UL; + va = adr & 0xFFFF0000UL; + sz = 65536UL; + ap = (adr >> 14) & 3; //in "ap" store which AP we need [of the 4] + break; + + case 2: //4K mapping (1K effective thenks to having 4 AP fields) + +page_size_4k: + pa = t & 0xFFFFF000UL; + va = adr & 0xFFFFF000UL; + sz = 4096; + ap = (adr >> 10) & 3; //in "ap" store which AP we need [of the 4] + break; + + case 3: //1K mapping + + if(coarse){ + + pxa_tex_page = true; + goto page_size_4k; + } + + pa = t & 0xFFFFFC00UL; + va = adr & 0xFFFFFC00UL; + ap = (t >> 4) & 3; //in "ap" store the actual AP [and skip quarter-page resolution later using the goto] + sz = 1024; + goto translated; + } + + + //handle 4 AP sections + + i = (t >> 4) & 0xFF; + if(pxa_tex_page || ((i & 0x0F) == (i >> 4) && (i & 0x03) == ((i >> 2) & 0x03))){ //if all domains are the same, add the whole thing + + ap = (t >> 4) & 3; + } + else{ //take the quarter that is the one we need + + err_str("quarter page found!\r\n"); + ap = (t >> (4 + 2 * ap)) & 3; + sz /= 4; + pa += ((UInt32)ap) * sz; + va += ((UInt32)ap) * sz; + } + + +translated: + + //insert tlb entry + if(MMU_TLB_BUCKET_NUM && MMU_TLB_BUCKET_SIZE){ + + mmu->tlb[bucket][mmu->replPos[bucket]].pa = pa; + mmu->tlb[bucket][mmu->replPos[bucket]].sz = sz; + mmu->tlb[bucket][mmu->replPos[bucket]].va = va; + mmu->tlb[bucket][mmu->replPos[bucket]].ap = ap; + mmu->tlb[bucket][mmu->replPos[bucket]].domain = dom; + mmu->readPos[bucket] = mmu->replPos[bucket]; + if(++mmu->replPos[bucket] == MMU_TLB_BUCKET_SIZE) mmu->replPos[bucket] = 0; + } + +check: + + //check domain permissions + + switch((mmu->domainCfg >> (dom * 2)) & 3){ + + case 0: //NO ACCESS: + case 2: //RESERVED: unpredictable (treat as no access) + + *fsrP = (section ? 0x08 : 0xB) | (dom << 4); //section or page domain fault + return false; + + + case 1: //CLIENT: check permissions + + break; + + + case 3: //MANAGER: allow all access + + goto calc; + + } + + //check permissions + + switch(ap){ + + case 0: + + if(write || (!mmu->R && (!priviledged || !mmu->S))) break; + goto calc; + + case 1: + + if(!priviledged) break; + goto calc; + + case 2: + + if(!priviledged && write) break; + goto calc; + + case 3: + + //all is good, allow access! + goto calc; + } + +//perm_err: + + *fsrP = (section ? 0x0D : 0x0F) | (dom << 4); //section or subpage permission fault + return false; + +calc: + + *paP = adr - va + pa; + return true; +} + +UInt32 mmuGetTTP(ArmMmu* mmu){ + + return mmu->transTablPA; +} + +void mmuSetTTP(ArmMmu* mmu, UInt32 ttp){ + + UInt8 i; + + mmuTlbFlush(mmu); + for(i = 0; i < MMU_TLB_BUCKET_NUM; i++){ + + mmu->replPos[i] = 0; + mmu->readPos[i] = 0; + } + mmu->transTablPA = ttp; +} + +void mmuSetS(ArmMmu* mmu, Boolean on){ + + mmu->S = on; +} + +void mmuSetR(ArmMmu* mmu, Boolean on){ + + mmu->R = on; +} + +Boolean mmuGetS(ArmMmu* mmu){ + + return mmu->S; +} + +Boolean mmuGetR(ArmMmu* mmu){ + + return mmu->R; +} + +UInt32 mmuGetDomainCfg(ArmMmu* mmu){ + + return mmu->domainCfg; +} + +void mmuSetDomainCfg(ArmMmu* mmu, UInt32 val){ + + mmu->domainCfg = val; +} + +/////////////////////////// debugging helpers /////////////////////////// + + + +UInt32 mmuDR(ArmMmu* mmu, UInt32 addr){ + + UInt32 t = 0; + + if(!mmu->readF(mmu->userData, &t, addr)) t = 0xFFFFFFF0UL; + + return t; +} + +static void mmuDumpUpdate(UInt32 va, UInt32 pa, UInt32 len, UInt8 dom, UInt8 ap, Boolean c, Boolean b, Boolean valid){ + + UInt32 va_end;; + + static Boolean wasValid = false; + static UInt8 wasDom = 0; + static UInt8 wasAp = 0; + static Boolean wasB = 0; + static Boolean wasC = 0; + static UInt32 startVa = 0; + static UInt32 startPa = 0; + static UInt32 expectPa = 0; + + + va_end = (va || len) ? va - 1 : 0xFFFFFFFFUL; + + if(!wasValid && !valid) return; //no need to bother... + + if(valid != wasValid || dom != wasDom || ap != wasAp || c != wasC || b != wasB || expectPa != pa){ //not a continuation of what we've been at... + + if(wasValid){ + + + err_str("0x"); + err_hex(startVa); + err_str("-0x"); + err_hex(va_end); + err_str(" -> 0x"); + err_hex(startPa); + err_str("-0x"); + err_hex(startPa + (va_end - startVa)); + err_str(" dom"); + err_dec(wasDom); + err_str(" ap"); + err_dec(wasAp); + err_str(" "); + err_str(wasC ? "c" : " "); + err_str(wasB ? "b" : " "); + err_str("\r\n"); + } + + wasValid = valid; + if(valid){ //start of a new range + + wasDom = dom; + wasAp = ap; + wasC = c; + wasB = b; + startVa = va; + startPa = pa; + expectPa = pa + len; + } + } + else{ //continuation of what we've been up to... + + expectPa += len; + } +} + +static void mmuDump(ArmMmu* mmu){ + + UInt32 i, j, t, sla, va, psz; + UInt8 dom; + Boolean coarse = false; + + for(i = 0; i < 0x1000; i++){ + + t = mmuDR(mmu, mmu->transTablPA + (i << 2)); + va = i << 20; + dom = (t >> 5) & 0x0F; + switch(t & 3){ + + case 0: //done + mmuDumpUpdate(va, 0, 1UL << 20, 0, 0, false, false, false); + continue; + + case 1: //coarse page table + coarse = true; + t &= 0xFFFFFC00UL; + break; + + case 2: //section + mmuDumpUpdate(va, t & 0xFFF00000UL, 1UL << 20, dom, (t >> 10) & 3, !!(t & 8), !!(t & 4), true); + continue; + + case 3: //fine page table + t &= 0xFFFFF000UL; + break; + } + + sla = t; + psz = coarse ? 4096 : 1024; + for(j = 0; j < ((1UL << 20) / psz); j++){ + t = mmuDR(mmu, sla + (j << 2)); + va = (i << 20) + (j * psz); + switch(t & 3){ + + case 0: //invalid + mmuDumpUpdate(va, 0, psz, 0, 0, false, false, false); + break; + + case 1: //large 64k page + mmuDumpUpdate(va + 0 * 16384UL, (t & 0xFFFF0000UL) + 0 * 16384UL, 16384, dom, (t >> 4) & 3, !!(t & 8), !!(t & 4), true); + mmuDumpUpdate(va + 1 * 16384UL, (t & 0xFFFF0000UL) + 1 * 16384UL, 16384, dom, (t >> 6) & 3, !!(t & 8), !!(t & 4), true); + mmuDumpUpdate(va + 2 * 16384UL, (t & 0xFFFF0000UL) + 2 * 16384UL, 16384, dom, (t >> 8) & 3, !!(t & 8), !!(t & 4), true); + mmuDumpUpdate(va + 3 * 16384UL, (t & 0xFFFF0000UL) + 3 * 16384UL, 16384, dom, (t >> 10) & 3, !!(t & 8), !!(t & 4), true); + j += coarse ? 15 : 63; + break; + + case 2: //small 4k page + mmuDumpUpdate(va + 0 * 1024, (t & 0xFFFFF000UL) + 0 * 1024, 1024, dom, (t >> 4) & 3, !!(t & 8), !!(t & 4), true); + mmuDumpUpdate(va + 1 * 1024, (t & 0xFFFFF000UL) + 1 * 1024, 1024, dom, (t >> 6) & 3, !!(t & 8), !!(t & 4), true); + mmuDumpUpdate(va + 2 * 1024, (t & 0xFFFFF000UL) + 2 * 1024, 1024, dom, (t >> 8) & 3, !!(t & 8), !!(t & 4), true); + mmuDumpUpdate(va + 3 * 1024, (t & 0xFFFFF000UL) + 3 * 1024, 1024, dom, (t >> 10) & 3, !!(t & 8), !!(t & 4), true); + if(!coarse) j += 3; + break; + + case 3: //tiny 1k page or TEX page on pxa + if(coarse){ + + mmuDumpUpdate(va, t & 0xFFFFF000UL, 4096, dom, (t >> 4) & 3, !!(t & 8), !!(t & 4), true); + } + else{ + + mmuDumpUpdate(va, t & 0xFFFFFC00UL, 1024, dom, (t >> 4) & 3, !!(t & 8), !!(t & 4), true); + } + break; + } + } + } + mmuDumpUpdate(0, 0, 0, 0, 0, false, false, false); //finish things off +} diff --git a/contrib/other/uarm/MMU.h b/contrib/other/uarm/MMU.h new file mode 100755 index 0000000000..2a0277b12e --- /dev/null +++ b/contrib/other/uarm/MMU.h @@ -0,0 +1,64 @@ +#ifndef _MMU_H_ +#define _MMU_H_ + + +#include "types.h" + + +#define MMU_TLB_BUCKET_SIZE 8 +#define MMU_TLB_BUCKET_NUM 32 +#define MMU_DISABLED_TTP 0xFFFFFFFFUL + + +typedef Err (*ArmMmuReadF)(void* userData, UInt32* buf, UInt32 pa); //read a word + +#define errMmuTranslation (errMmu + 1) +#define errMmuDomain (errMmu + 2) +#define errMmuPermission (errMmu + 3) + +typedef struct { + + UInt32 pa, va; + UInt32 sz; + UInt32 ap:2; + UInt32 domain:4; + +}ArmPrvTlb; + +typedef struct ArmMmu{ + + UInt32 transTablPA; + UInt8 S:1; + UInt8 R:1; + UInt8 readPos[MMU_TLB_BUCKET_NUM]; + UInt8 replPos[MMU_TLB_BUCKET_NUM]; + ArmPrvTlb tlb[MMU_TLB_BUCKET_NUM][MMU_TLB_BUCKET_SIZE]; + UInt32 domainCfg; + ArmMmuReadF readF; + void* userData; + +}ArmMmu; + + +void mmuInit(ArmMmu* mmu, ArmMmuReadF readF, void* userData); +void muDeinit(ArmMmu* mmu); +Boolean mmuTranslate(ArmMmu* mmu, UInt32 va, Boolean priviledged, Boolean write, UInt32* paP, UInt8* fsrP); + +UInt32 mmuGetTTP(ArmMmu* mmu); +void mmuSetTTP(ArmMmu* mmu, UInt32 ttp); + +void mmuSetS(ArmMmu* mmu, Boolean on); +void mmuSetR(ArmMmu* mmu, Boolean on); +Boolean mmuGetS(ArmMmu* mmu); +Boolean mmuGetR(ArmMmu* mmu); + +UInt32 mmuGetDomainCfg(ArmMmu* mmu); +void mmuSetDomainCfg(ArmMmu* mmu, UInt32 val); + +void mmuTlbFlush(ArmMmu* mmu); + + + + +#endif + diff --git a/contrib/other/uarm/Makefile b/contrib/other/uarm/Makefile new file mode 100755 index 0000000000..29abee91a8 --- /dev/null +++ b/contrib/other/uarm/Makefile @@ -0,0 +1,20 @@ +CC = kos32-gcc +LD = kos32-ld + +SDK_DIR = $(abspath ../../sdk) + +CFLAGS = -c -fno-ident -O2 -fomit-frame-pointer -fno-ident -U__WIN32__ -U_Win32 -U_WIN32 -U__MINGW32__ -UWIN32 +LDFLAGS = -static -S -nostdlib -T $(SDK_DIR)/sources/newlib/app.lds --image-base 0 + +INCLUDES = -I $(SDK_DIR)/sources/newlib/libc/include +LIBPATH = -L $(SDK_DIR)/lib -L /home/autobuild/tools/win32/mingw32/lib + +SRC := $(notdir $(wildcard *.c)) +OBJECTS = $(patsubst %.c, %.o, $(SRC)) + +default: $(patsubst %.c,%.o,$(SRC)) + kos32-ld $(LDFLAGS) $(LIBPATH) --subsystem console -o uARMk $(OBJECTS) -lgcc -lc.dll + objcopy uARMk -O binary + +%.o : %.c Makefile $(SRC) + $(CC) $(CFLAGS) $(INCLUDES) -o $@ $< diff --git a/contrib/other/uarm/RAM.c b/contrib/other/uarm/RAM.c new file mode 100755 index 0000000000..36fdbbf751 --- /dev/null +++ b/contrib/other/uarm/RAM.c @@ -0,0 +1,113 @@ +#include "mem.h" +#include "RAM.h" + + + +static Boolean ramAccessF(void* userData, UInt32 pa, UInt8 size, Boolean write, void* bufP){ + + ArmRam* ram = userData; + UInt8* addr = (UInt8*)ram->buf; + + pa -= ram->adr; + if(pa >= ram->sz) return false; + + addr += pa; + + if(write){ + + switch(size){ + + case 1: + + *((UInt8*)addr) = *(UInt8*)bufP; //our memory system is little-endian + break; + + case 2: + + *((UInt16*)addr) = *(UInt16*)bufP; //our memory system is little-endian + break; + + case 4: + + *((UInt32*)addr) = *(UInt32*)bufP; + break; + + case 8: + + *((UInt32*)(addr + 0)) = ((UInt32*)bufP)[0]; + *((UInt32*)(addr + 4)) = ((UInt32*)bufP)[1]; + break; + + default: + + return false; + } + } + else{ + + switch(size){ + + case 1: + + *(UInt8*)bufP = *((UInt8*)addr); + break; + + case 2: + + *(UInt16*)bufP = *((UInt16*)addr); + break; + + case 4: + + *(UInt32*)bufP = *((UInt32*)addr); + break; + + case 64: + ((UInt32*)bufP)[ 8] = *((UInt32*)(addr + 32)); + ((UInt32*)bufP)[ 9] = *((UInt32*)(addr + 36)); + ((UInt32*)bufP)[10] = *((UInt32*)(addr + 40)); + ((UInt32*)bufP)[11] = *((UInt32*)(addr + 44)); + ((UInt32*)bufP)[12] = *((UInt32*)(addr + 48)); + ((UInt32*)bufP)[13] = *((UInt32*)(addr + 52)); + ((UInt32*)bufP)[14] = *((UInt32*)(addr + 56)); + ((UInt32*)bufP)[15] = *((UInt32*)(addr + 60)); + //fallthrough + case 32: + + ((UInt32*)bufP)[4] = *((UInt32*)(addr + 16)); + ((UInt32*)bufP)[5] = *((UInt32*)(addr + 20)); + ((UInt32*)bufP)[6] = *((UInt32*)(addr + 24)); + ((UInt32*)bufP)[7] = *((UInt32*)(addr + 28)); + //fallthrough + case 16: + + ((UInt32*)bufP)[2] = *((UInt32*)(addr + 8)); + ((UInt32*)bufP)[3] = *((UInt32*)(addr + 12)); + //fallthrough + case 8: + ((UInt32*)bufP)[0] = *((UInt32*)(addr + 0)); + ((UInt32*)bufP)[1] = *((UInt32*)(addr + 4)); + break; + + default: + + return false; + } + } + + return true; +} + +Boolean ramInit(ArmRam* ram, ArmMem* mem, UInt32 adr, UInt32 sz, UInt32* buf){ + + ram->adr = adr; + ram->sz = sz; + ram->buf = buf; + + return memRegionAdd(mem, adr, sz, &ramAccessF, ram); +} + +Boolean ramDeinit(ArmRam* ram, ArmMem* mem){ + + return memRegionDel(mem, ram->adr, ram->sz); +} diff --git a/contrib/other/uarm/RAM.h b/contrib/other/uarm/RAM.h new file mode 100755 index 0000000000..1dd5e3beff --- /dev/null +++ b/contrib/other/uarm/RAM.h @@ -0,0 +1,24 @@ +#ifndef _RAM_H_ +#define _RAM_H_ + + +#include "types.h" + +typedef struct{ + + UInt32 adr; + UInt32 sz; + UInt32* buf; + +}ArmRam; + + +Boolean ramInit(ArmRam* ram, ArmMem* mem, UInt32 adr, UInt32 sz, UInt32* buf); +Boolean ramDeinit(ArmRam* ram, ArmMem* mem); + + + + + +#endif + diff --git a/contrib/other/uarm/SoC.c b/contrib/other/uarm/SoC.c new file mode 100755 index 0000000000..cff601fc06 --- /dev/null +++ b/contrib/other/uarm/SoC.c @@ -0,0 +1,776 @@ +#include "SoC.h" +#include "CPU.h" +#include "MMU.h" +#include "mem.h" +#include "callout_RAM.h" +#include "RAM.h" +#include "cp15.h" +#include "math64.h" +#include "pxa255_IC.h" +#include "pxa255_TIMR.h" +#include "pxa255_RTC.h" +#include "pxa255_UART.h" +#include "pxa255_PwrClk.h" +#include "pxa255_GPIO.h" +#include "pxa255_DMA.h" +#include "pxa255_DSP.h" +#include "pxa255_LCD.h" +#ifdef EMBEDDED + #include +#endif + + +#define ERR(s) do{err_str(s " Halting\r\n"); while(1); }while(0) + +static const UInt8 embedded_boot[] = { + 0x01, 0x00, 0x8F, 0xE2, 0x10, 0xFF, 0x2F, 0xE1, 0x04, 0x27, 0x01, 0x20, 0x00, 0x21, 0x00, 0xF0, + 0x0D, 0xF8, 0x0A, 0x24, 0x24, 0x07, 0x65, 0x1C, 0x05, 0x27, 0x00, 0x22, 0x00, 0xF0, 0x06, 0xF8, + 0x20, 0x60, 0x24, 0x1D, 0x49, 0x1C, 0x80, 0x29, 0xF8, 0xD1, 0x28, 0x47, 0xBC, 0x46, 0xBB, 0xBB, + 0x70, 0x47 + }; + +#define ROM_BASE 0x00000000UL +#define ROM_SIZE sizeof(embedded_boot) + +#define RAM_BASE 0xA0000000UL +#define RAM_SIZE 0x01000000UL //16M @ 0xA0000000 + + +static Boolean vMemF(ArmCpu* cpu, void* buf, UInt32 vaddr, UInt8 size, Boolean write, Boolean priviledged, UInt8* fsrP){ + + SoC* soc = cpu->userData; + UInt32 pa; + + if(size & (size - 1)){ //size is not a power of two + + return false; + } + if(vaddr & (size - 1)){ //bad alignment + + return false; + } + + return mmuTranslate(&soc->mmu, vaddr, priviledged, write, &pa, fsrP) && memAccess(&soc->mem, pa, size, write, buf); +} + + +static Boolean hyperF(ArmCpu* cpu){ //return true if handled + + SoC* soc = cpu->userData; + + if(cpu->regs[12] == 0){ + err_str("Hypercall 0 caught\r\n"); + soc->go = false; + } + else if(cpu->regs[12] == 1){ + err_dec(cpu->regs[0]); + } + else if(cpu->regs[12] == 2){ + char x[2]; + x[1] = 0; + x[0] = cpu->regs[0]; + err_str(x); + } + else if(cpu->regs[12] == 3){ //get ram size + cpu->regs[0] = RAM_SIZE; + } + else if(cpu->regs[12] == 4){ //block device access perform [do a read or write] + + //IN: + // R0 = op + // R1 = sector + + return soc->blkF(soc->blkD, cpu->regs[1], soc->blkDevBuf, cpu->regs[0]); + } + else if(cpu->regs[12] == 5){ //block device buffer access [read or fill emulator's buffer] + + //IN: + // R0 = word value + // R1 = word offset (0, 1, 2...) + // R2 = op (1 = write, 0 = read) + //OUT: + // R0 = word value + + if(cpu->regs[1] >= BLK_DEV_BLK_SZ / sizeof(UInt32)) return false; //invalid request + + if(cpu->regs[2] == 0){ + + cpu->regs[0] = soc->blkDevBuf[cpu->regs[1]]; + } + else if(cpu->regs[2] == 1){ + + soc->blkDevBuf[cpu->regs[1]] = cpu->regs[0]; + } + else return false; + } + return true; +} + +static void setFaultAdrF(ArmCpu* cpu, UInt32 adr, UInt8 faultStatus){ + + SoC* soc = cpu->userData; + + cp15SetFaultStatus(&soc->cp15, adr, faultStatus); +} + +static void emulErrF(_UNUSED_ ArmCpu* cpu, const char* str){ + err_str("Emulation error: <<"); + err_str(str); + err_str(">> halting\r\n"); + while(1); +} + +static Boolean pMemReadF(void* userData, UInt32* buf, UInt32 pa){ //for DMA engine and MMU pagetable walks + + ArmMem* mem = userData; + + return memAccess(mem, pa, 4, false, buf); +} + +static void dumpCpuState(ArmCpu* cpu, char* label){ + + UInt8 i; + + if(label){ + err_str("CPU "); + err_str(label); + err_str("\r\n"); + } + + for(i = 0; i < 16; i++){ + err_str("R"); + err_dec(i); + err_str("\t= 0x"); + err_hex(cpuGetRegExternal(cpu, i)); + err_str("\r\n"); + } + err_str("CPSR\t= 0x"); + err_hex(cpuGetRegExternal(cpu, ARM_REG_NUM_CPSR)); + err_str("\r\nSPSR\t= 0x"); + err_hex(cpuGetRegExternal(cpu, ARM_REG_NUM_SPSR)); + err_str("\r\n"); +} + +static UInt16 socUartPrvRead(void* userData){ //these are special funcs since they always get their own userData - the uart :) + + SoC* soc = userData; + UInt16 v; + int r; + + r = soc->rcF(); + if(r == CHAR_CTL_C) v = UART_CHAR_BREAK; + else if(r == CHAR_NONE) v = UART_CHAR_NONE; + else if(r >= 0x100) v = UART_CHAR_NONE; //we canot send this char!!! + else v = r; + + return v; +} + +static void socUartPrvWrite(UInt16 chr, void* userData){ //these are special funcs since they always get their own userData - the uart :) + + SoC* soc = userData; + + + if(chr == UART_CHAR_NONE) return; + + soc->wcF(chr); +} + +void LinkError_SIZEOF_STRUCT_SOC_wrong(); + + +void socRamModeAlloc(SoC* soc, _UNUSED_ void* ignored){ + + UInt32* ramB = emu_alloc(RAM_SIZE); + if(!ramB) ERR("Cannot allocate RAM buffer"); + if(!ramInit(&soc->ram.RAM, &soc->mem, RAM_BASE, RAM_SIZE, ramB)) ERR("Cannot init RAM"); + + soc->calloutMem = false; +} + +void socRamModeCallout(SoC* soc, void* callout){ + + if(!coRamInit(&soc->ram.coRAM, &soc->mem, RAM_BASE, RAM_SIZE, callout)) ERR("Cannot init coRAM"); + + soc->calloutMem = true; +} + +#define ERR_(s) ERR("error"); + +void socInit(SoC* soc, SocRamAddF raF, void*raD, readcharF rc, writecharF wc, blockOp blkF, void* blkD){ + +printf ("SoC init! \n"); + Err e; + + soc->rcF = rc; + soc->wcF = wc; + + soc->blkF = blkF; + soc->blkD = blkD; + + soc->go = true; + + e = cpuInit(&soc->cpu, ROM_BASE, vMemF, emulErrF, hyperF, &setFaultAdrF); + if(e){ + err_str("Failed to init CPU: "); + // err_dec(e); + // err_str(". Halting\r\n"); + while(1); + } + printf("CPU init\n"); + soc->cpu.userData = soc; + + memInit(&soc->mem); + mmuInit(&soc->mmu, pMemReadF, &soc->mem); + printf("Init complete\n"); + if(ROM_SIZE > sizeof(soc->romMem)) { + // err_str("Failed to init CPU: "); + err_str("ROM_SIZE to small"); + // err_str(". Halting\r\n"); + while(1); + } + + printf("RAF\n"); + + raF(soc, raD); + + if(!ramInit(&soc->ROM, &soc->mem, ROM_BASE, ROM_SIZE, soc->romMem)) ERR_("Cannot init ROM"); + + cp15Init(&soc->cp15, &soc->cpu, &soc->mmu); + + __mem_copy(soc->romMem, embedded_boot, sizeof(embedded_boot)); + + printf("Things...\n"); + + if(!pxa255icInit(&soc->ic, &soc->cpu, &soc->mem)) ERR_("Cannot init PXA255's interrupt controller"); + if(!pxa255timrInit(&soc->timr, &soc->mem, &soc->ic)) ERR_("Cannot init PXA255's OS timers"); + if(!pxa255rtcInit(&soc->rtc, &soc->mem, &soc->ic)) ERR_("Cannot init PXA255's RTC"); + if(!pxa255uartInit(&soc->ffuart, &soc->mem, &soc->ic,PXA255_FFUART_BASE, PXA255_I_FFUART)) ERR_("Cannot init PXA255's FFUART"); + if(!pxa255uartInit(&soc->btuart, &soc->mem, &soc->ic,PXA255_BTUART_BASE, PXA255_I_BTUART)) ERR_("Cannot init PXA255's BTUART"); + if(!pxa255uartInit(&soc->stuart, &soc->mem, &soc->ic,PXA255_STUART_BASE, PXA255_I_STUART)) ERR_("Cannot init PXA255's STUART"); + if(!pxa255pwrClkInit(&soc->pwrClk, &soc->cpu, &soc->mem)) ERR_("Cannot init PXA255's Power and Clock manager"); + if(!pxa255gpioInit(&soc->gpio, &soc->mem, &soc->ic)) ERR_("Cannot init PXA255's GPIO controller"); + if(!pxa255dmaInit(&soc->dma, &soc->mem, &soc->ic)) ERR_("Cannot init PXA255's DMA controller"); + if(!pxa255dspInit(&soc->dsp, &soc->cpu)) ERR_("Cannot init PXA255's cp0 DSP"); + if(!pxa255lcdInit(&soc->lcd, &soc->mem, &soc->ic)) ERR_("Cannot init PXA255's LCD controller"); + +printf("go?\n"); + + pxa255uartSetFuncs(&soc->ffuart, socUartPrvRead, socUartPrvWrite, soc); +} + +void gdbCmdWait(SoC* soc, unsigned gdbPort, int* ss); + +void socRun(SoC* soc, UInt32 gdbPort){ + + + printf("go2?\n"); + + UInt32 prevRtc = 0; + UInt32 cyclesCapt = 0; + + UInt32 cycles = 0; //make 64 if you REALLY need it... later + + #ifdef GDB_SUPPORT + int ss = 1; //for gdb stub single step + #else + gdbPort = 0; //use the param somehow to quiet GCC + #endif + + printf("run !\n"); + + while(soc->go){ + //printf("Soc go...\n"); + cycles++; + + #ifdef EMBEDDED + if(!(PIND & 0x10)){ //btn down + + if(!prevRtc){ + + do{ + prevRtc = gRtc; + }while(prevRtc != gRtc); + cyclesCapt = 0; + } + else{ + + UInt32 t; + + //we only care to go on if the rtc is now different + do{ + t = gRtc; + }while(t != gRtc); + + if(t != prevRtc){ + + if(!cyclesCapt){ + + //this code assumes we're called often enough that the next rtc vals we see is the NEXT second, not the one after or any other such thing + cyclesCapt = cycles; + prevRtc = t; + } + else{ + + err_dec(cycles - cyclesCapt); + err_str(" Hz\r\n"); + + cyclesCapt = 0; + prevRtc = 0; + } + } + } + } + #endif + + if(!(cycles & 0x00000FUL)) pxa255timrTick(&soc->timr); + if(!(cycles & 0x0000FFUL)) pxa255uartProcess(&soc->ffuart); + if(!(cycles & 0x000FFFUL)) pxa255rtcUpdate(&soc->rtc); + if(!(cycles & 0x01FFFFUL)) pxa255lcdFrame(&soc->lcd); + + #ifdef GDB_SUPPORT + gdbCmdWait(soc, gdbPort, &ss); + #endif + + cpuCycle(&soc->cpu); + } +} + + + + + + + + + +#ifdef GDB_SUPPORT + + + + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + + + + static int socdBkptDel(SoC* soc, UInt32 addr, UInt8 sz){ + + UInt8 i; + + for(i = 0; i < soc->nBkpt; i++){ + + if(soc->bkpt[i] == addr){ + + soc->nBkpt--; + soc->bkpt[i] = soc->bkpt[soc->nBkpt]; + i--; + } + } + return 1; + } + + + static int socdBkptAdd(SoC* soc, UInt32 addr, UInt8 sz){ //boolean + + socdBkptDel(soc, addr, sz); + + if(soc->nBkpt == MAX_BKPT) return 0; + + soc->bkpt[soc->nBkpt++] = addr; + + return 1; + } + + static int socdWtpDel(SoC* soc, UInt32 addr, UInt8 sz){ + + UInt8 i; + + for(i = 0; i < soc->nWtp; i++){ + + if(soc->wtpA[i] == addr && soc->wtpS[i] == sz){ + + soc->nWtp--; + soc->wtpA[i] = soc->wtpA[soc->nWtp]; + soc->wtpS[i] = soc->wtpS[soc->nWtp]; + i--; + } + } + return 1; + } + + + static int socdWtpAdd(SoC* soc, UInt32 addr, UInt8 sz){ //boolean + + socdWtpDel(soc, addr, sz); + + if(soc->nWtp == MAX_WTP) return 0; + + soc->wtpA[soc->nWtp] = addr; + soc->wtpS[soc->nWtp] = sz; + soc->nWtp++; + + return 1; + } + + + UInt32 htoi(const char** cP){ + + UInt32 i = 0; + const char* in = *cP; + char c; + + while((c = *in) != 0){ + + if(c >= '0' && c <= '9') i = (i * 16) + (c - '0'); + else if(c >= 'a' && c <= 'f') i = (i * 16) + (c + 10 - 'a'); + else if(c >= 'A' && c <= 'F') i = (i * 16) + (c + 10 - 'A'); + else break; + in++; + } + + *cP = in; + + return i; + } + + static UInt32 swap32(UInt32 x){ + + return ((x >> 24) & 0xff) | ((x >> 8) & 0xff00) | ((x & 0xff00) << 8) | ((x & 0xff) << 24); + } + + + int gdb_memAccess(SoC* soc, UInt32 addr, UInt8* buf, int write){ + + UInt32 pa = 0; + UInt8 fsr = 0; + + return mmuTranslate(&soc->mmu, addr, true, false, &pa, &fsr) && memAccess(&soc->mem, pa, 1, write | 0x80, buf); + } + + static int addRegToStr(SoC* soc, char* str, int reg){ + + if(reg == 0x19 || reg < 0x10){ + if(reg == 0x19) reg = ARM_REG_NUM_CPSR; + sprintf(str + strlen(str), "%08x", swap32(cpuGetRegExternal(&soc->cpu, reg))); + } + else if(reg >= 0x10 && reg < 0x18){ + + strcat(str, "000000000000000000000000"); + } + else if(reg == 0x18){ //fps + + strcat(str, "00000000"); + } + else return 0; + + return 1; + } + + static int interpPacket(SoC* soc,const char* in, char* out, int* ss){ //return 0 if we failed to interp a command, 1 is all ok, -1 to send no reply and run + + ArmCpu* cpu = &soc->cpu; + unsigned char c; + unsigned addr, len; + unsigned char* ptr; + int i; + int ret = 1; + + + + if(strcmp(in, "qSupported") == 0){ + + strcpy(out, "PacketSize=99"); + } + else if(strcmp(in, "vCont?") == 0){ + + out[0] = 0; + } + else if(strcmp(in, "s") == 0){ //single step + + *ss = 1; + return -1; + } + else if(strcmp(in, "c") == 0 || in[0] == 'C'){ //continue [with signal, which we ignore] + + return -1; + } + else if(in[0] == 'Z' || in[0] == 'z'){ + + char op = in[0]; + char type = in[1]; + int (*f)(SoC* soc, UInt32 addr, UInt8 sz) = NULL; + + in += 3; + addr = htoi(&in); + if(*in++ != ',') goto fail; //no comma? + len = htoi(&in); + if(*in) goto fail; //string not over? + + if(type == '0' || type == '1'){ //bkpt + + f = (op == 'Z') ? socdBkptAdd : socdBkptDel; + } + /* + else if(type == '2' || type == '3'){ //wtp + + f = (op == 'Z') ? socdWtpAdd : socdWtpDel; + } + else goto fail; + */ + strcpy(out,f(soc, addr, len) ? "OK" : "e00"); + } + else if(in[0] == 'H' && (in[1] == 'c' || in[1] == 'g')){ + strcpy(out, "OK"); + } + else if(in[0] == 'q'){ + + if(in[1] == 'C'){ + + strcpy(out, ""); + } + else if(strcmp(in +1, "Offsets") == 0){ + + strcpy(out, "Text=0;Data=0;Bss=0"); + } + else goto fail; + } + else if(in[0] == 'p'){ //read register + + in++; + i = htoi(&in); + if(*in) goto fail; //string not over? + + out[0] = 0; + if(!addRegToStr(soc, out, i)) goto fail; + } + else if(strcmp(in, "g") == 0){ //read all registers + + out[0] = 0; + for(i = 0; i < 0x1a; i++) if(!addRegToStr(soc, out, i)) goto fail; + } + else if(in[0] == 'P'){ //write register + + in++; + i = htoi(&in); + if(*in++ != '=') goto fail; //string not over? + if(i == 0x19 || i <16){ + if(i == 0x19) i = ARM_REG_NUM_CPSR; + addr = htoi(&in); + sprintf(out, "OK"); + cpuSetReg(cpu, i, addr); + } + else strcpy(out,"e00"); + } + else if(in[0] == 'm'){ //read memory + + in++; + addr = htoi(&in); + if(*in++ != ',') goto fail; + len = htoi(&in); + if(*in) goto fail; + out[0] = 0; + while(len--){ + + if(!gdb_memAccess(soc, addr++, &c, false)) break; + sprintf(out + strlen(out), "%02x", c); + } + } + else if(strcmp(in, "?") == 0){ + + strcpy(out,"S05"); + } + else goto fail; + + send_pkt: + return ret; + + fail: + out[0] = 0; + ret = 0; + goto send_pkt; + } + + static void sendpacket(int sock, char* packet, int withAck){ + + unsigned int c; + int i; + + c = 0; + for(i = 0; i < strlen(packet); i++) c += packet[i]; + memmove(packet + (withAck ? 2 : 1), packet, strlen(packet) + 1); + if(withAck){ + packet[0] = '+'; + packet[1] = '$'; + } + else{ + packet[0] = '$'; + } + sprintf(packet + strlen(packet), "#%02x", c & 0xFF); + + //printf("sending packet <<%s>>\n", packet); + send(sock, packet, strlen(packet), 0); + } + + void gdbCmdWait(SoC* soc, unsigned gdbPort, int* ss){ + + ArmCpu* cpu = &soc->cpu; + static int running = 0; + static int sock = -1; + char packet[4096]; + struct timeval tv = {0}; + fd_set set; + int ret; + + if(*ss && running){ + + strcpy(packet,"S05"); + sendpacket(sock, packet, 0); + running = 0; //perform single step + } + *ss = 0; + + if(running){ //check for breakpoints + + UInt8 i; + + for(i = 0; i < soc->nBkpt; i++){ + + if(soc->cpu.regs[15] == soc->bkpt[i]){ + + // printf("bkpt hit: pc=0x%08lX bk=0x%08lX i=%d\n", soc->cpu.regs[15], soc->bkpt[i], i); + strcpy(packet,"S05"); + sendpacket(sock, packet, 0); + running = 0; //perform breakpoint hit + break; + } + } + } + + if(gdbPort){ + + if(sock == -1){ //no socket yet - make one + + struct sockaddr_in sa = {AF_INET, htons(gdbPort)}; + socklen_t sl = sizeof(sa); + + inet_aton("127.0.0.1", &sa.sin_addr.s_addr); + + sock = socket(PF_INET, SOCK_STREAM, 0); + if(sock == -1){ + err_str("gdb socket creation fails: "); + err_dec(errno); + ERR("\n"); + } + + ret = bind(sock, (struct sockaddr*)&sa, sizeof(sa)); + if(ret){ + err_str("gdb socket bind fails: "); + err_dec(errno); + ERR("\n"); + } + + ret = listen(sock, 1); + if(ret){ + err_str("gdb socket listen fails: "); + err_dec(errno); + ERR("\n"); + } + + ret = accept(sock, (struct sockaddr*)&sa, &sl); + if(ret == -1){ + err_str("gdb socket accept fails: "); + err_dec(errno); + ERR("\n"); + } + close(sock); + sock = ret; + + soc->nBkpt = 0; + soc->nWtp = 0; + } + } + if(gdbPort){ + + do{ + + FD_ZERO(&set); + FD_SET(sock, &set); + tv.tv_sec = running ? 0 : 0x00f00000UL; + do{ + ret = select(sock + 1, &set, NULL, NULL, &tv); + }while(!ret && !running); + if(ret < 0){ + err_str("select fails: "); + err_dec(errno); + ERR("\n"); + } + if(ret > 0){ + char c; + char* p; + int i, len = 0, esc = 0, end = 0; + + ret = recv(sock, &c, 1, 0); + if(ret != 1) ERR("failed to receive byte (1)\n"); + + if(c == 3){ + strcpy(packet,"S11"); + sendpacket(sock, packet, 0); + running = 0; //perform breakpoint hit + } + else if(c != '$'){ + //printf("unknown packet header '%c'\n", c); + } + else{ + do{ + if(esc){ + c = c ^ 0x20; + esc = 0; + } + else if(c == 0x7d){ + esc = 1; + } + + if(!esc){ //we cannot be here if we're being escaped + + packet[len++] = c; + if(end == 0 && c == '#') end = 2; + else if(end){ + + end--; + if(!end) break; + } + + ret = recv(sock, &c, 1, 0); + if(ret != 1) ERR("failed to receive byte (2)\n"); + } + }while(1); + packet[len] = 0; + + memmove(packet, packet + 1, len); + len -= 4; + packet[len] = 0; + ret = interpPacket(soc, p = strdup(packet), packet, ss); + if(ret == 0) printf("how do i respond to packet <<%s>>\n", p); + if(ret == -1){ //ack it anyways + char c = '+'; + send(sock, &c, 1, 0); + running = 1; + } + else sendpacket(sock, packet, 1); + + emu_free(p); + } + } + }while(!running); + } + } + +#endif diff --git a/contrib/other/uarm/SoC.h b/contrib/other/uarm/SoC.h new file mode 100755 index 0000000000..a2c28ccb44 --- /dev/null +++ b/contrib/other/uarm/SoC.h @@ -0,0 +1,121 @@ +#ifndef _SOC_H_ +#define _SOC_H_ + +#include "types.h" + +//#define GDB_SUPPORT +//#define DYNAREC +#define MAX_WTP 32 +#define MAX_BKPT 32 + + + + +#ifndef GDB_SUPPORT + #ifdef DYNAREC + #define _JIT + #endif +#endif + + + +#define CHAR_CTL_C -1L +#define CHAR_NONE -2L +typedef int (*readcharF)(void); +typedef void (*writecharF)(int); + +#define BLK_DEV_BLK_SZ 512 + +#define BLK_OP_SIZE 0 +#define BLK_OP_READ 1 +#define BLK_OP_WRITE 2 + +typedef int (*blockOp)(void* data, UInt32 sec, void* ptr, UInt8 op); + +struct SoC; + +typedef void (*SocRamAddF)(struct SoC* soc, void* data); + +typedef struct{ + + UInt32 (*WordGet)(UInt32 wordAddr); + void (*WordSet)(UInt32 wordAddr, UInt32 val); + +}RamCallout; + +void socRamModeAlloc(struct SoC* soc, void* ignored); +void socRamModeCallout(struct SoC* soc, void* callout); //rally pointer to RamCallout + +void socInit(struct SoC* soc, SocRamAddF raF, void* raD, readcharF rc, writecharF wc, blockOp blkF, void* blkD); +void socRun(struct SoC* soc, UInt32 gdbPort); + + + +extern volatile UInt32 gRtc; //needed by SoC + +#include "CPU.h" +#include "MMU.h" +#include "mem.h" +#include "callout_RAM.h" +#include "RAM.h" +#include "cp15.h" +#include "math64.h" +#include "pxa255_IC.h" +#include "pxa255_TIMR.h" +#include "pxa255_RTC.h" +#include "pxa255_UART.h" +#include "pxa255_PwrClk.h" +#include "pxa255_GPIO.h" +#include "pxa255_DMA.h" +#include "pxa255_DSP.h" +#include "pxa255_LCD.h" + +typedef struct SoC{ + + readcharF rcF; + writecharF wcF; + + blockOp blkF; + void* blkD; + + UInt32 blkDevBuf[BLK_DEV_BLK_SZ / sizeof(UInt32)]; + + union{ + ArmRam RAM; + CalloutRam coRAM; + }ram; + ArmRam ROM; + ArmCpu cpu; + ArmMmu mmu; + ArmMem mem; + ArmCP15 cp15; + Pxa255ic ic; + Pxa255timr timr; + Pxa255rtc rtc; + Pxa255uart ffuart; + Pxa255uart btuart; + Pxa255uart stuart; + Pxa255pwrClk pwrClk; + Pxa255gpio gpio; + Pxa255dma dma; + Pxa255dsp dsp; + Pxa255lcd lcd; + + UInt8 go :1; + UInt8 calloutMem:1; + + UInt32 romMem[13]; //space for embeddedBoot + +#ifdef GDB_SUPPORT + + UInt8 nBkpt, nWtp; + UInt32 bkpt[MAX_BKPT]; + UInt32 wtpA[MAX_WTP]; + UInt8 wtpS[MAX_WTP]; + +#endif + +}SoC; + +#endif + diff --git a/contrib/other/uarm/callout_RAM.c b/contrib/other/uarm/callout_RAM.c new file mode 100755 index 0000000000..6a06648a6e --- /dev/null +++ b/contrib/other/uarm/callout_RAM.c @@ -0,0 +1,16 @@ +#include "mem.h" +#include "callout_RAM.h" + + +Boolean coRamInit(CalloutRam* ram, ArmMem* mem, UInt32 adr, UInt32 sz, ArmMemAccessF* coF){ + + ram->adr = adr; + ram->sz = sz; + + return memRegionAdd(mem, adr, sz, (void*)coF, ram); +} + +Boolean coRamDeinit(CalloutRam* ram, ArmMem* mem){ + + return memRegionDel(mem, ram->adr, ram->sz); +} diff --git a/contrib/other/uarm/callout_RAM.h b/contrib/other/uarm/callout_RAM.h new file mode 100755 index 0000000000..c66ea7c86d --- /dev/null +++ b/contrib/other/uarm/callout_RAM.h @@ -0,0 +1,24 @@ +#ifndef _CO_RAM_H_ +#define _CO_RAM_H_ + + +#include "types.h" +#include "mem.h" + +typedef struct{ + + UInt32 adr; + UInt32 sz; + +}CalloutRam; + + +Boolean coRamInit(CalloutRam* ram, ArmMem* mem, UInt32 adr, UInt32 sz, ArmMemAccessF* coF); +Boolean coRamDeinit(CalloutRam* ram, ArmMem* mem); + + + + + +#endif + diff --git a/contrib/other/uarm/console_obj.h b/contrib/other/uarm/console_obj.h new file mode 100755 index 0000000000..29d99ad0cf --- /dev/null +++ b/contrib/other/uarm/console_obj.h @@ -0,0 +1,141 @@ +// Console.obj loading for kos32-gcc +// Writed by rgimad and maxcodehack + +#include +#include + +#ifndef CONSOLE_OBJ_H +#define CONSOLE_OBJ_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef NULL +#define NULL 0 +#endif + +#ifndef cdecl +#define cdecl __attribute__ ((cdecl)) +#endif + +#ifndef stdcall +#define stdcall __attribute__ ((stdcall)) +#endif + +typedef unsigned int dword; +typedef unsigned short word; + +const char* imports[] = { + "START", "version", "con_init", "con_write_asciiz", "con_write_string", + "con_printf", "con_exit", "con_get_flags", "con_set_flags", "con_kbhit", + "con_getch", "con_getch2", "con_gets", "con_gets2", "con_get_font_height", + "con_get_cursor_height", "con_set_cursor_height", "con_cls", + "con_get_cursor_pos", "con_set_cursor_pos", "con_set_title", + (char*)0 +}; + +dword *version; + +typedef int (stdcall * con_gets2_callback)(int keycode, char** pstr, int* pn, + int* ppos); + +void stdcall (*con_init)(dword wnd_width, dword wnd_height, dword scr_width, dword scr_height, const char* title) = 0; +void stdcall (*con_exit)(int bCloseWindow) = 0; +void stdcall (*con_set_title)(const char* title) = 0; +void stdcall (*con_write_asciiz)(const char* str) = 0; +void stdcall (*con_write_string)(const char* str, dword length) = 0; +int cdecl (*con_printf)(const char* format, ...) = 0; +dword stdcall (*con_get_flags)(void) = 0; +dword stdcall (*con_set_flags)(dword new_flags) = 0; +int stdcall (*con_get_font_height)(void) = 0; +int stdcall (*con_get_cursor_height)(void) = 0; +int stdcall (*con_set_cursor_height)(int new_height) = 0; +int stdcall (*con_getch)(void) = 0; +word stdcall (*con_getch2)(void) = 0; +int stdcall (*con_kbhit)(void) = 0; +char* stdcall (*con_gets)(char* str, int n) = 0; +char* stdcall (*con_gets2)(con_gets2_callback callback, char* str, int n) = 0; +void stdcall (*con_cls)() = 0; +void stdcall (*con_get_cursor_pos)(int* px, int* py) = 0; +void stdcall (*con_set_cursor_pos)(int x, int y) = 0; + +const char lib_path[] = "/sys/lib/console.obj"; + +void* load_library(const char *name) +{ + void *table; + __asm__ __volatile__( + "int $0x40" + :"=a"(table) + :"a"(68), "b"(19), "c"(name)); + return table; +} + +void *load_library_procedure(void *exports, const char *name) +{ + if (exports == NULL) { return 0; } + while (*(dword*)exports != 0) + { + char *str1 = (char*)(*(dword*)exports); + if (strcmp(str1, name) == 0) + { + void *ptr = (void*)*(dword*)(exports + 4); + return ptr; + } + exports += 8; + } + return 0; +} + +void output_debug_string(const char *s) +{ + unsigned int i = 0; + while(*(s + i)) + { + asm volatile ("int $0x40"::"a"(63), "b"(1), "c"(*(s + i))); + i++; + } +} + +void load_console() +{ + void *lib = load_library(lib_path); + + if (!lib) + { + output_debug_string("Console.obj loading error\r\n"); + exit(1); + } + + dword (*start_lib)(dword) = (dword(*)(dword))load_library_procedure(lib, imports[0]); + + version = (dword*)load_library_procedure(lib, imports[1]); + + con_init = (void stdcall(*)(dword,dword,dword,dword,const char*))load_library_procedure(lib, imports[2]); + con_write_asciiz = (void stdcall(*)(const char*))load_library_procedure(lib, imports[3]); + con_write_string = (void stdcall(*)(const char*,dword))load_library_procedure(lib, imports[4]); + con_printf = (int cdecl(*)(const char*,...))load_library_procedure(lib, imports[5]); + con_exit = (void stdcall(*)(int))load_library_procedure(lib, imports[6]); + con_get_flags = (dword stdcall(*)(void))load_library_procedure(lib, imports[7]); + con_set_flags = (dword stdcall(*)(dword))load_library_procedure(lib, imports[8]); + con_kbhit = (int stdcall(*)(void))load_library_procedure(lib, imports[9]); + con_getch = (int stdcall(*)(void))load_library_procedure(lib, imports[10]); + con_getch2 = (word stdcall(*)(void))load_library_procedure(lib, imports[11]); + con_gets = (char* stdcall(*)(char*,int))load_library_procedure(lib, imports[12]); + con_gets2 = (char* stdcall(*)(con_gets2_callback,char*,int))load_library_procedure(lib, imports[13]); + con_get_font_height = (int stdcall(*)(void))load_library_procedure(lib, imports[14]); + con_get_cursor_height = (int stdcall(*)(void))load_library_procedure(lib, imports[15]); + con_set_cursor_height = (int stdcall(*)(int))load_library_procedure(lib, imports[16]); + con_cls = (void stdcall(*)(void))load_library_procedure(lib, imports[17]); + con_get_cursor_pos = (void stdcall(*)(int*,int*))load_library_procedure(lib, imports[18]); + con_set_cursor_pos = (void stdcall(*)(int,int))load_library_procedure(lib, imports[19]); + con_set_title = (void stdcall(*)(const char*))load_library_procedure(lib, imports[20]); + +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/contrib/other/uarm/cp15.c b/contrib/other/uarm/cp15.c new file mode 100755 index 0000000000..ec5e19fee7 --- /dev/null +++ b/contrib/other/uarm/cp15.c @@ -0,0 +1,186 @@ +#include "cp15.h" + + +#define CPUID_PXA255 0x69052D06UL //spepping A0 +#define CPUID_PXA270 0x69054114UL //stepping C0 + +static Boolean cp15prvCoprocRegXferFunc(struct ArmCpu* cpu, void* userData, Boolean two, Boolean read, UInt8 op1, UInt8 Rx, UInt8 CRn, UInt8 CRm, UInt8 op2){ + + ArmCP15* cp15 = userData; + UInt32 val = 0, tmp; + + + if(!read) val = cpuGetRegExternal(cpu, Rx); + + if(op1 != 0 || two) goto fail; //CP15 only accessed with MCR/MRC with op1 == 0 + + switch(CRn){ + + case 0: //ID codes + + if(!read) goto fail; //cannot write to ID codes register + if(CRm != 0) goto fail; //CRm must be zero for this read + if(op2 == 0){ //main ID register + + val = CPUID_PXA255; + goto success; + } + else if(op2 == 1){ //cahce type register - we lie here + + val = 0x0B16A16AUL; + goto success; + } + break; + + case 1: //control register + + if(op2 == 0){ + if(read){ + val = cp15->control; + } + else{ + tmp = val ^ cp15->control; //see what changed and mask off then chack for what we support changing of + if(tmp & 0x84F0UL){ + err_str("cp15: unknown bits changed 0x"); + err_hex(cp15->control); + err_str("->0x"); + err_hex(val); + err_str(", halting\r\n"); + while(true); + } + + if(tmp & 0x00002000UL){ // V bit + + cpuSetVectorAddr(cp15->cpu, (val & 0x00002000UL) ? 0xFFFF0000UL : 0x00000000UL); + cp15->control ^= 0x00002000UL; + } + if(tmp & 0x00000200UL){ // R bit + + mmuSetR(cp15->mmu, (val & 0x00000200UL) != 0); + cp15->control ^= 0x00000200UL; + } + if(tmp & 0x00000100UL){ // S bit + + mmuSetS(cp15->mmu, (val & 0x00000100UL) != 0); + cp15->control ^= 0x00000100UL; + } + if(tmp & 0x00000001UL){ // M bit + + mmuSetTTP(cp15->mmu, (val & 0x00000001UL) ? cp15->ttb : MMU_DISABLED_TTP); + mmuTlbFlush(cp15->mmu); + cp15->control ^= 0x00000001UL; + } + + } + } + else if(op2 == 1){ //PXA-specific thing + if(read) val = cp15->ACP; + else cp15->ACP = val; + } + else break; + goto success; + + case 2: //translation tabler base + if(read) val = cp15->ttb; + else{ + if(cp15->control & 0x00000001UL){ //mmu is on + + mmuSetTTP(cp15->mmu, val); + mmuTlbFlush(cp15->mmu); + } + cp15->ttb = val; + } + goto success; + + case 3: //domain access control + if(read) val = mmuGetDomainCfg(cp15->mmu); + else mmuSetDomainCfg(cp15->mmu, val); + goto success; + + case 5: //FSR + if(read) val = cp15->FSR; + else cp15->FSR = val; + goto success; + + case 6: //FAR + if(read) val = cp15->FAR; + else cp15->FAR = val; + goto success; + + case 7: //cache ops + if((CRm == 5 || CRm == 7)&& op2 == 0) cpuIcacheInval(cp15->cpu); //invalidate entire {icache(5) or both i and dcache(7)} + if((CRm == 5 || CRm == 7) && op2 == 1) cpuIcacheInvalAddr(cp15->cpu, val); //invalidate {icache(5) or both i and dcache(7)} line, given VA + if((CRm == 5 || CRm == 7) && op2 == 2) cpuIcacheInval(cp15->cpu); //invalidate {icache(5) or both i and dcache(7)} line, given set/index. i dont know how to do this, so flush thee whole thing + goto success; + + case 8: //TLB ops + mmuTlbFlush(cp15->mmu); + goto success; + + case 9: //cache lockdown + if(CRm == 1 && op2 == 0){ + err_str("Attempt to lock 0x"); + err_hex(val); + err_str("+32 in icache\r\n"); + } + else if(CRm == 2 && op2 == 0){ + err_str("Dcache now "); + err_str(val ? "in" : "out of"); + err_str(" lock mode\r\n"); + } + goto success; + + case 10: //TLB lockdown + goto success; + + case 13: //FCSE + err_str("FCSE not supported\n"); + break; + + case 15: + if(op2 == 0 && CRm == 1){ //CPAR + if(read) val = cpuGetCPAR(cp15->cpu); + else cpuSetCPAR(cp15->cpu, val & 0x3FFF); + goto success; + } + break; + } + +fail: + //TODO: cause invalid instruction trap in cpu + return false; + +success: + + if(read) cpuSetReg(cpu, Rx, val); + return true; +} + +void cp15Init(ArmCP15* cp15, ArmCpu* cpu, ArmMmu* mmu){ + + ArmCoprocessor cp; + + cp.regXfer = cp15prvCoprocRegXferFunc; + cp.dataProcessing = NULL; + cp.memAccess = NULL; + cp.twoRegF = NULL; + cp.userData = cp15; + + __mem_zero(cp15, sizeof(ArmCP15)); + cp15->cpu = cpu; + cp15->mmu = mmu; + cp15->control = 0x00004072UL; + + cpuCoprocessorRegister(cpu, 15, &cp); +} + +void cp15Deinit(ArmCP15* cp15){ + + cpuCoprocessorUnregister(cp15->cpu, 15); +} + +void cp15SetFaultStatus(ArmCP15* cp15, UInt32 addr, UInt8 faultStatus){ + + cp15->FAR = addr; + cp15->FSR = faultStatus; +} diff --git a/contrib/other/uarm/cp15.h b/contrib/other/uarm/cp15.h new file mode 100755 index 0000000000..0c15d63b96 --- /dev/null +++ b/contrib/other/uarm/cp15.h @@ -0,0 +1,27 @@ +#ifndef _CP15_H_ +#define _CP15_H_ + + +#include "types.h" +#include "CPU.h" +#include "MMU.h" + +typedef struct{ + + ArmCpu* cpu; + ArmMmu* mmu; + + UInt32 control; + UInt32 ttb; + UInt32 FSR; //fault sttaus register + UInt32 FAR; //fault address register + UInt32 CPAR; //coprocessor access register + UInt32 ACP; //auxilary control reg for xscale +}ArmCP15; + +void cp15Init(ArmCP15* cp15, ArmCpu* cpu, ArmMmu* mmu); +void cp15Deinit(ArmCP15* cp15); +void cp15SetFaultStatus(ArmCP15* cp15, UInt32 addr, UInt8 faultStatus); + +#endif + diff --git a/contrib/other/uarm/cpu.h b/contrib/other/uarm/cpu.h new file mode 100755 index 0000000000..3ef677d517 --- /dev/null +++ b/contrib/other/uarm/cpu.h @@ -0,0 +1,173 @@ +#ifndef _CPU_H_ +#define _CPU_H_ + + +//#define ARM_V6 //define to allow v6 instructions +//#define THUMB_2 //define to allow Thumb2 + +#include "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); + + +#endif + diff --git a/contrib/other/uarm/dcache.c b/contrib/other/uarm/dcache.c new file mode 100755 index 0000000000..c90d8feb6b --- /dev/null +++ b/contrib/other/uarm/dcache.c @@ -0,0 +1,155 @@ +#include "types.h" +#include "CPU.h" +#include "dcache.h" + +//#define DCACHE_DEBUGGING + + + +#ifdef DCACHE_DEBUGGING + #define _dcache_fetch_func dcacheFetch_ + #define _dcache_test_func dcacheFetch +#else + #define _dcache_fetch_func dcacheFetch + #define _dcache_test_func dcacheFetch_test +#endif + +void dcacheInval(dcache* dc){ + + UInt8 i, j; + + for(i = 0; i < DCACHE_BUCKET_NUM; i++){ + for(j = 0; j < DCACHE_BUCKET_SZ; j++) dc->lines[i][j].info = 0; + dc->ptr[i] = 0; + } +} + +void dcacheInit(dcache* dc, ArmCpu* cpu, ArmCpuMemF memF){ + + dc->cpu = cpu; + dc->memF = memF; + + dcacheInval(dc); +} + + +static UInt8 dcachePrvHash(UInt32 addr){ + + addr >>= DCACHE_L; + addr &= (1UL << DCACHE_S) - 1UL; + + return addr; +} + +void dcacheInvalAddr(dcache* dc, UInt32 va){ + + UInt32 off = va % DCACHE_LINE_SZ; + Int8 i, j, bucket; + dcacheLine* lines; + + va -= off; + + bucket = dcachePrvHash(va); + lines = dc->lines[bucket]; + + for(i = 0, j = dc->ptr[bucket]; i < DCACHE_BUCKET_SZ; i++){ + + if(--j == -1) j = DCACHE_BUCKET_SZ - 1; + + if((lines[j].info & (DCACHE_ADDR_MASK | DCACHE_USED_MASK)) == (va | DCACHE_USED_MASK)){ //found it! + + lines[j].info = 0; + } + } +} + +void dcacheFlush(dcache* dc){ + + +} + +void dcacheFlushAddr(dcache* dc, UInt32 va){ + + +} + +/* + we cannot have data overlap cachelines since data is self aligned (word on 4-byte boundary, halfwords on2, etc. this is enforced elsewhere +*/ + +Boolean dcacheWrite(dcache* dc, UInt32 va, UInt8 sz, Boolean priviledged, UInt8* fsrP, void* buf){ + + +} + +Boolean _dcache_fetch_func(dcache* dc, UInt32 va, UInt8 sz, Boolean priviledged, UInt8* fsrP, void* buf){ + + UInt32 off = va % DCACHE_LINE_SZ; + Int8 i, j, bucket; + dcacheLine* lines; + dcacheLine* line; + + va -= off; + + bucket = dcachePrvHash(va); + lines = dc->lines[bucket]; + + for(i = 0, j = dc->ptr[bucket]; i < DCACHE_BUCKET_SZ; i++){ + + if(--j == -1) j = DCACHE_BUCKET_SZ - 1; + + if((lines[j].info & (DCACHE_ADDR_MASK | DCACHE_USED_MASK)) == (va | DCACHE_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 & DCACHE_PRIV_MASK); + } + } + //if we're here, we found nothing - time to populate the cache + j = dc->ptr[bucket]++; + if(dc->ptr[bucket] == DCACHE_BUCKET_SZ) dc->ptr[bucket] = 0; + line = lines + j; + + line->info = va | (priviledged ? DCACHE_PRIV_MASK : 0); + if(!dc->memF(dc->cpu, line->data, va, DCACHE_LINE_SZ, false, priviledged, fsrP)){ + + return false; + } + line->info |= DCACHE_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 _dcache_test_func(dcache* dc, 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 = _dcache_fetch_func(dc, va, sz, priviledged, &fsrO, dataO); + retT = dc->memF(dc->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, "dcache fail!"); + } + + for(i = 0; i < sz; i++) ((UInt8*)buf)[i] = dataT[i]; + if(retT) *fsrP = fsrT; + return retT; +} + diff --git a/contrib/other/uarm/dcache.h b/contrib/other/uarm/dcache.h new file mode 100755 index 0000000000..a11d69a78a --- /dev/null +++ b/contrib/other/uarm/dcache.h @@ -0,0 +1,49 @@ +#ifndef _DCACHE_H_ +#define _DCACHE_H_ + + +#include "types.h" +#include "CPU.h" + + +#define DCACHE_L 5UL //line size is 2^L bytes +#define DCACHE_S 6UL //number of sets is 2^S +#define DCACHE_A 4UL //set associativity + +#define DCACHE_LINE_SZ (1UL << ICACHE_L) +#define DCACHE_BUCKET_NUM (1UL << ICACHE_S) +#define DCACHE_BUCKET_SZ (ICACHE_A) + + +#define DCACHE_ADDR_MASK ((UInt32)-ICACHE_LINE_SZ) +#define DCACHE_USED_MASK 1 +#define DCACHE_PRIV_MASK 2 + +typedef struct{ + + UInt32 info; //addr, masks + UInt8 data[DCACHE_LINE_SZ]; + +}dcacheLine; + +typedef struct{ + + struct ArmCpu* cpu; + ArmCpuMemF memF; + dcacheLine lines[DCACHE_BUCKET_NUM][DCACHE_BUCKET_SZ]; + UInt8 ptr[DCACHE_BUCKET_NUM]; + +}dcache; + + +void dcacheInit(dcache* ic, struct ArmCpu* cpu, ArmCpuMemF memF); +Boolean dcacheFetch(dcache* ic, UInt32 va, UInt8 sz, Boolean priviledged, UInt8* fsr, void* buf); +Boolean dcacheWrite(dcache* ic, UInt32 va, UInt8 sz, Boolean priviledged, UInt8* fsr, void* buf); +void dcacheFlush(dcache* ic); +void dcacheFlushAddr(dcache* ic, UInt32 addr); +void dcacheInval(dcache* ic); +void dcacheInvalAddr(dcache* ic, UInt32 addr); + + + +#endif diff --git a/contrib/other/uarm/icache.c b/contrib/other/uarm/icache.c new file mode 100755 index 0000000000..fa86b455b6 --- /dev/null +++ b/contrib/other/uarm/icache.c @@ -0,0 +1,140 @@ +#include "types.h" +#include "CPU.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; +} + diff --git a/contrib/other/uarm/icache.h b/contrib/other/uarm/icache.h new file mode 100755 index 0000000000..7c526287a9 --- /dev/null +++ b/contrib/other/uarm/icache.h @@ -0,0 +1,47 @@ +#ifndef _ICACHE_H_ +#define _ICACHE_H_ + + +#include "types.h" +#include "CPU.h" + + +#define ICACHE_L 4UL //line size is 2^L bytes +#define ICACHE_S 6UL //number of sets is 2^S +#define ICACHE_A 6UL //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 diff --git a/contrib/other/uarm/main_pc.c b/contrib/other/uarm/main_pc.c new file mode 100755 index 0000000000..bba68474ae --- /dev/null +++ b/contrib/other/uarm/main_pc.c @@ -0,0 +1,250 @@ +#include "SoC.h" + +#include +#include +#include +#include +#include +#include +#include +#include +//#include +#include +//#include +#include "console_obj.h" + +#define getch2 con_getch +#define cprintf printf + +#define off64_t off_t +unsigned char* readFile(const char* name, UInt32* lenP){ + + long len = 0; + unsigned char *r = NULL; + int i; + FILE* f; + + f = fopen(name, "r"); + if(!f){ + perror("cannot open file"); + return NULL; + } + + i = fseek(f, 0, SEEK_END); + if(i){ + return NULL; + perror("cannot seek to end"); + } + + len = ftell(f); + if(len < 0){ + perror("cannot get position"); + return NULL; + } + + i = fseek(f, 0, SEEK_SET); + if(i){ + return NULL; + perror("cannot seek to start"); + } + + + r = malloc(len); + if(!r){ + perror("cannot alloc memory"); + return NULL; + } + + if(len != (long)fread(r, 1, len, f)){ + perror("canot read file"); + free(r); + return NULL; + } + + *lenP = len; + return r; +} + + + +static int ctlCSeen = 0; + +static int readchar(void){ + + struct timeval tv; + fd_set set; + char c; + char tmp[20]; + int ret = CHAR_NONE; + +// if(ctlCSeen){ + //ctlCSeen = 0; + //return 0x03; + //} + + //tv.tv_sec = 0; + //tv.tv_usec = 0; + + //FD_ZERO(&set); + //FD_SET(0, &set); + + //i = 1; //(1, &set, NULL, NULL, &tv); + if(con_kbhit()){ + + ret = getch2(); + if (ret==0xD) {ret=0xA;} + } + + + + return ret; +} + +static void writechar(int chr){ + + if(!(chr & 0xFF00)){ + + cprintf("%c", chr); + } + else{ + cprintf("<<~~ EC_0x%x ~~>>", chr); + } + fflush(stdout); +} + +void ctl_cHandler(_UNUSED_ int v){ //handle SIGTERM + +// exit(-1); + ctlCSeen = 1; +} + +int rootOps(void* userData, UInt32 sector, void* buf, UInt8 op){ + + FILE* root = userData; + int i; + + switch(op){ + case BLK_OP_SIZE: + + if(sector == 0){ //num blocks + + if(root){ + + i = fseek(root, 0, SEEK_END); + if(i) return false; + + *(unsigned long*)buf = (off64_t)ftell(root) / (off64_t)BLK_DEV_BLK_SZ; + } + else{ + + *(unsigned long*)buf = 0; + } + } + else if(sector == 1){ //block size + + *(unsigned long*)buf = BLK_DEV_BLK_SZ; + } + else return 0; + return 1; + + case BLK_OP_READ: + + i = fseek(root, (off64_t)sector * (off64_t)BLK_DEV_BLK_SZ, SEEK_SET); + if(i) return false; + return fread(buf, 1, BLK_DEV_BLK_SZ, root) == BLK_DEV_BLK_SZ; + + case BLK_OP_WRITE: + + i = fseek(root, (off64_t)sector * (off64_t)BLK_DEV_BLK_SZ, SEEK_SET); + if(i) return false; + return fwrite(buf, 1, BLK_DEV_BLK_SZ, root) == BLK_DEV_BLK_SZ; + } + return 0; +} + +SoC soc; + +int main(int argc, char** argv){ + load_console(); + con_set_title("uARM"); + //CONSOLE_INIT("CONSOLE"); + +/* + struct termios cfg, old; +*/ + FILE* root = NULL; + int gdbPort = 0; + + if(argc != 3 && argc != 2){ + fprintf(stderr,"usage: %s path_to_disk [gdbPort]\n", argv[0]); + return -1; + } + + //setup the terminal + { + int ret; + + ret = 0; //tcgetattr(0, &old); + //cfg = old; + if(ret) perror("cannot get term attrs"); + + /* #ifndef _DARWIN_ + + cfg.c_iflag &=~ (INLCR | INPCK | ISTRIP | IUCLC | IXANY | IXOFF | IXON); + cfg.c_oflag &=~ (OPOST | OLCUC | ONLCR | OCRNL | ONOCR | ONLRET); + cfg.c_lflag &=~ (ECHO | ECHOE | ECHONL | ICANON | IEXTEN | XCASE); + #else */ + // cfmakeraw(&cfg); + //#endif + + ret = 0; //tcsetattr(0, TCSANOW, &cfg); + if(ret) perror("cannot set term attrs"); + } + + root = fopen(argv[1], "r+b"); + if(!root){ + fprintf(stderr,"Failed to open root device\n"); + exit(-1); + } + + fprintf(stderr,"Stderror ready\n"); + + if(argc >= 3) gdbPort = atoi(argv[2]); + + socInit(&soc, socRamModeAlloc, NULL, readchar, writechar, rootOps, root); + //(SIGINT, &ctl_cHandler); + socRun(&soc, gdbPort); + + fclose(root); + //tcsetattr(0, TCSANOW, &old); + + return 0; +} + + +//////// runtime things + +void* emu_alloc(UInt32 size){ + + return calloc(size,1); +} + +void emu_free(void* ptr){ + + free(ptr); +} + +UInt32 rtcCurTime(void){ + + struct timeval tv; + + gettimeofday(&tv, NULL); + + return tv.tv_sec; +} + +void err_str(const char* str){ + + printf( "%s", str); +} + diff --git a/contrib/other/uarm/math64.c b/contrib/other/uarm/math64.c new file mode 100755 index 0000000000..889f6ae5c7 --- /dev/null +++ b/contrib/other/uarm/math64.c @@ -0,0 +1,197 @@ +#include "math64.h" + +#ifndef COMPILER_SUPPORTS_LONG_LONG + + + +UInt64 u64_from_halves(UInt32 hi, UInt32 lo){ + + UInt64 r; + + r.lo = lo; + r.hi = hi; + + return r; +} + + +UInt64 u64_32_to_64(UInt32 v){ + + UInt64 r; + + r.hi = 0; + r.lo = v; + + return r; +} + +UInt32 u64_64_to_32(UInt64 v){ + + return v.lo; +} + +UInt32 u64_get_hi(UInt64 v){ + + return v.hi; +} + +UInt64 u64_add(UInt64 a, UInt64 b){ + + UInt64 r; + + r.lo = a.lo + b.lo; + r.hi = a.hi + b.hi; + if(r.lo < a.lo) r.hi++; + + return r; +} + +UInt64 u64_add32(UInt64 a, UInt32 b){ + + UInt64 r; + + r.lo = a.lo + b; + r.hi = a.hi; + if(r.lo < a.lo) r.hi++; + + return r; +} + +UInt64 u64_umul3232(UInt32 a, UInt32 b){ + + UInt64 r; + UInt32 ah, al, bh, bl; + + ah = a >> 16; + al = a & 0xFFFFUL; + bh = b >> 16; + bl = b & 0xFFFFUL; + + r = u64_shl(u64_32_to_64(ah * bh), 16); + r = u64_add32(r, ah * bl); + r = u64_add32(r, al * bh); + r = u64_add32(u64_shl(r, 16), al * bl); + + return r; +} + +UInt64 u64_smul3232(Int32 a, Int32 b){ + + Boolean negative = false; + UInt64 r; + + if(a < 0){ + a = -a; + negative = !negative; + } + + if(b < 0){ + b = -b; + negative = !negative; + } + + r = u64_umul3232(a, b); + + if(negative){ + + r.hi = ~r.hi; //negate r + r.lo = ~r.lo; + r = u64_inc(r); + } + + return r; +} + +UInt64 u64_shr(UInt64 v, unsigned bits){ + + UInt64 a = v; + + while(bits >= 32){ + a.lo = a.hi; + a.hi = 0; + bits -= 32; + } + + a.lo = (a.lo >> bits) + (a.hi << (32 - bits)); + a.hi >>= bits; + + return a; +} + +UInt64 u64_shl(UInt64 v, unsigned bits){ + + UInt64 a = v; + + while(bits >= 32){ + a.hi = a.lo; + a.lo = 0; + bits -= 32; + } + + a.hi = (a.hi << bits) + (a.lo >> (32 - bits)); + a.lo <<= bits; + + return a; +} + +UInt64 u64_xtnd32(UInt64 v){ + + UInt64 a = v; + + if(a.lo & 0x80000000UL) a.hi = 0xFFFFFFFFUL; + + return a; +} + +Boolean u64_isZero(UInt64 a){ + + return a.lo == 0 && a.hi == 0; +} + +UInt64 u64_inc(UInt64 v){ + + UInt64 a = v; + + if(!++a.lo) a.hi++; + + return a; +} + +UInt64 u64_and(UInt64 a, UInt64 b){ + + UInt64 r; + + r.lo = a.lo & b.lo; + r.hi = a.hi & b.hi; + + return r; +} + +UInt64 u64_zero(void){ + + UInt64 r; + + r.lo = 0; + r.hi = 0; + + return r; +} + + +UInt64 u64_sub(UInt64 a, UInt64 b){ + + UInt64 bn; + + bn.lo = ~b.lo; + bn.hi = ~b.hi; + + bn = u64_inc(bn); + + return u64_add(a, bn); +} + + + + + +#endif \ No newline at end of file diff --git a/contrib/other/uarm/math64.h b/contrib/other/uarm/math64.h new file mode 100755 index 0000000000..b163e64e4d --- /dev/null +++ b/contrib/other/uarm/math64.h @@ -0,0 +1,64 @@ +#ifndef _MATH_64_H_ +#define _MATH_64_H_ + +#include "types.h" + +#define COMPILER_SUPPORTS_LONG_LONG //undefine if compiler doe snot uspport long long + + +#ifdef COMPILER_SUPPORTS_LONG_LONG + +typedef unsigned long long UInt64; + +static inline UInt64 u64_from_halves(UInt32 hi, UInt32 lo) { return (((UInt64)hi) << 32ULL) | ((UInt64)lo); } +static inline UInt64 u64_32_to_64(UInt32 v) { return (UInt64)v; } +static inline UInt32 u64_64_to_32(UInt64 v) { return (UInt32)v; } +static inline UInt32 u64_get_hi(UInt64 v) { return (UInt32)(v >> 32ULL); } +static inline UInt64 u64_add(UInt64 a, UInt64 b) { return a + b; } +static inline UInt64 u64_add32(UInt64 a, UInt32 b) { return a + (UInt64)b; } +static inline UInt64 u64_umul3232(UInt32 a, UInt32 b) { return ((UInt64)a) * ((UInt64)b); } //sad but true: gcc has no u32xu32->64 multiply +static inline UInt64 u64_smul3232(Int32 a, Int32 b) { return ((signed long long)a) * ((signed long long)b); } //sad but true: gcc has no s32xs32->64 multiply +static inline UInt64 u64_shr(UInt64 a, unsigned bits) { return a >> (UInt64)bits; } +static inline UInt64 u64_shl(UInt64 a, unsigned bits) { return a << (UInt64)bits; } +static inline UInt64 u64_xtnd32(UInt64 a) { if(a & 0x80000000UL) a |= (((UInt64)-1) << 32ULL); return a; } +static inline Boolean u64_isZero(UInt64 a) { return a == 0; } +static inline UInt64 u64_inc(UInt64 a) { return a + 1ULL; } +static inline UInt64 u64_and(UInt64 a, UInt64 b) { return a & b; } +static inline UInt64 u64_zero(void) { return 0; } +static inline UInt64 u64_sub(UInt64 a, UInt64 b) { return a - b; } + +#else + +typedef struct{ + + UInt32 hi, lo; +}UInt64; + + +UInt64 u64_from_halves(UInt32 hi, UInt32 lo); +UInt64 u64_32_to_64(UInt32 v); +UInt32 u64_64_to_32(UInt64 v); +UInt32 u64_get_hi(UInt64 v); +UInt64 u64_add(UInt64 a, UInt64 b); +UInt64 u64_umul3232(UInt32 a, UInt32 b); +UInt64 u64_smul3232(Int32 a, Int32 b); +UInt64 u64_shr(UInt64 a, unsigned bits); +UInt64 u64_shl(UInt64 a, unsigned bits); +UInt64 u64_add32(UInt64 a, UInt32 b); +UInt64 u64_xtnd32(UInt64 a); +Boolean u64_isZero(UInt64 a); +UInt64 u64_inc(UInt64 a); +UInt64 u64_zero(void); +UInt64 u64_sub(UInt64 a, UInt64 b); + + + +UInt64 u64_and(UInt64 a, UInt64 b); + +#endif + + + +#endif + + diff --git a/contrib/other/uarm/mem.c b/contrib/other/uarm/mem.c new file mode 100755 index 0000000000..b9b1d49d1a --- /dev/null +++ b/contrib/other/uarm/mem.c @@ -0,0 +1,96 @@ +#include "mem.h" + + + +void memInit(ArmMem* mem){ + + UInt8 i; + + for(i = 0; i < MAX_MEM_REGIONS; i++){ + mem->regions[i].sz = 0; + } +} + + +void memDeinit(_UNUSED_ ArmMem* mem){ + + //nothing here +} + +Boolean memRegionAdd(ArmMem* mem, UInt32 pa, UInt32 sz, ArmMemAccessF aF, void* uD){ + + UInt8 i; + + //check for intersection with another region + + for(i = 0; i < MAX_MEM_REGIONS; i++){ + + if(!mem->regions[i].sz) continue; + if((mem->regions[i].pa <= pa && mem->regions[i].pa + mem->regions[i].sz > pa) || (pa <= mem->regions[i].pa && pa + sz > mem->regions[i].pa)){ + + return false; //intersection -> fail + } + } + + + //find a free region and put it there + + for(i = 0; i < MAX_MEM_REGIONS; i++){ + if(mem->regions[i].sz == 0){ + + mem->regions[i].pa = pa; + mem->regions[i].sz = sz; + mem->regions[i].aF = aF; + mem->regions[i].uD = uD; + + return true; + } + } + + + //fail miserably + + return false; +} + +Boolean memRegionDel(ArmMem* mem, UInt32 pa, UInt32 sz){ + + UInt8 i; + + for(i = 0; i < MAX_MEM_REGIONS; i++){ + if(mem->regions[i].pa == pa && mem->regions[i].sz ==sz){ + + mem->regions[i].sz = 0; + return true; + } + } + + return false; +} + +Boolean memAccess(ArmMem* mem, UInt32 addr, UInt8 size, Boolean write, void* buf){ + + UInt8 i; + + for(i = 0; i < MAX_MEM_REGIONS; i++){ + if(mem->regions[i].pa <= addr && mem->regions[i].pa + mem->regions[i].sz > addr){ + + return mem->regions[i].aF(mem->regions[i].uD, addr, size, write & 0x7F, buf); + } + } + + if(!(write & 0x80)){ //high bit in write tells us to not print this error (used by gdb stub) + + err_str("Memory "); + err_str(write ? "write" : "read"); + err_str(" of "); + err_dec(size); + err_str(" bytes at physical addr 0x"); + err_hex(addr); + err_str(" fails, halting\r\n"); + while(1); + } + + return false; +} + diff --git a/contrib/other/uarm/mem.h b/contrib/other/uarm/mem.h new file mode 100755 index 0000000000..abcd323f02 --- /dev/null +++ b/contrib/other/uarm/mem.h @@ -0,0 +1,38 @@ +#ifndef _MEM_H_ +#define _MEM_H_ + +#include "types.h" + +#define MAX_MEM_REGIONS 16 + +#define errPhysMemNoSuchRegion (errPhysMem + 1) //this physical address is not claimed by any region +#define errPhysMemInvalidAdr (errPhysMem + 2) //address is IN a region but access to it is not allowed (it doesn't exist really) +#define errPhysMemInvalidSize (errPhysMem + 3) //access that is not 1, 2 or 4-byte big + +typedef Boolean (*ArmMemAccessF)(void* userData, UInt32 pa, UInt8 size, Boolean write, void* buf); + +typedef struct{ + + UInt32 pa; + UInt32 sz; + ArmMemAccessF aF; + void* uD; + +}ArmMemRegion; + +typedef struct{ + + ArmMemRegion regions[MAX_MEM_REGIONS]; + +}ArmMem; + + +void memInit(ArmMem* mem); +void memDeinit(ArmMem* mem); + +Boolean memRegionAdd(ArmMem* mem, UInt32 pa, UInt32 sz, ArmMemAccessF af, void* uD); +Boolean memRegionDel(ArmMem* mem, UInt32 pa, UInt32 sz); + +Boolean memAccess(ArmMem* mem, UInt32 addr, UInt8 size, Boolean write, void* buf); + +#endif diff --git a/contrib/other/uarm/pxa255_DMA.c b/contrib/other/uarm/pxa255_DMA.c new file mode 100755 index 0000000000..c5704078c3 --- /dev/null +++ b/contrib/other/uarm/pxa255_DMA.c @@ -0,0 +1,116 @@ +#include "pxa255_DMA.h" +#include "mem.h" + +#define REG_DAR 0 +#define REG_SAR 1 +#define REG_TAR 2 +#define REG_CR 3 +#define REG_CSR 4 + + +static void pxa255dmaPrvChannelRegWrite(_UNUSED_ Pxa255dma* dma, UInt8 channel, UInt8 reg, UInt32 val){ + + if(val){ //we start with zeros, so non-zero writes are all we care about + + const char* regs[] = {"DADDR", "SADDR", "TADDR", "CR", "CSR"}; + + err_str("dma: writes unimpl!"); + // err_str("PXA255 dma engine: writes unimpl! (writing 0x"); + // err_hex(val); + // err_str(" to channel "); + // err_dec(channel); + // err_str(" reg "); + // err_str(regs[reg]); + // err_str(". Halting.\r\n"); + while(1); + } +} + +static UInt32 pxa255dmaPrvChannelRegRead(_UNUSED_ Pxa255dma* dma, _UNUSED_ UInt8 channel, _UNUSED_ UInt8 reg){ + + + return 0; +} + +static Boolean pxa255dmaPrvMemAccessF(void* userData, UInt32 pa, UInt8 size, Boolean write, void* buf){ + + Pxa255dma* dma = userData; + UInt8 reg, set; + UInt32 val = 0; + + if(size != 4) { + err_str(__FILE__ ": Unexpected "); + // err_str(write ? "write" : "read"); + // err_str(" of "); + // err_dec(size); + // err_str(" bytes to 0x"); + // err_hex(pa); + // err_str("\r\n"); + return true; //we do not support non-word accesses + } + + pa = (pa - PXA255_DMA_BASE) >> 2; + + if(write){ + val = *(UInt32*)buf; + + switch(pa >> 6){ //weird, but quick way to avoide repeated if-then-elses. this is faster + case 0: + if(pa < 16){ + reg = REG_CSR; + set = pa; + pxa255dmaPrvChannelRegWrite(dma, set, reg, val); + } + break; + + case 1: + pa -= 64; + if(pa < 40) dma->CMR[pa] = val; + break; + + case 2: + pa -= 128; + set = pa >> 2; + reg = pa & 3; + pxa255dmaPrvChannelRegWrite(dma, set, reg, val); + break; + } + } + else{ + switch(pa >> 6){ //weird, but quick way to avoide repeated if-then-elses. this is faster + case 0: + if(pa < 16){ + reg = REG_CSR; + set = pa; + val = pxa255dmaPrvChannelRegRead(dma, set, reg); + } + break; + + case 1: + pa -= 64; + if(pa < 40) val = dma->CMR[pa]; + break; + + case 2: + pa -= 128; + set = pa >> 2; + reg = pa & 3; + val = pxa255dmaPrvChannelRegRead(dma, set, reg); + break; + } + + *(UInt32*)buf = val; + } + + return true; +} + + +Boolean pxa255dmaInit(Pxa255dma* dma, ArmMem* physMem, Pxa255ic* ic){ + + __mem_zero(dma, sizeof(Pxa255dma)); + dma->ic = ic; + dma->mem = physMem; + + return memRegionAdd(physMem, PXA255_DMA_BASE, PXA255_DMA_SIZE, pxa255dmaPrvMemAccessF, dma); +} diff --git a/contrib/other/uarm/pxa255_DMA.h b/contrib/other/uarm/pxa255_DMA.h new file mode 100755 index 0000000000..61aff185ea --- /dev/null +++ b/contrib/other/uarm/pxa255_DMA.h @@ -0,0 +1,42 @@ +#ifndef _PXA255_DMA_H_ +#define _PXA255_DMA_H_ + +#include "mem.h" +#include "cpu.h" +#include "pxa255_IC.h" + +/* + PXA255 OS DMA controller + +*/ + +#define PXA255_DMA_BASE 0x40000000UL +#define PXA255_DMA_SIZE 0x00001000UL + +typedef struct{ + + UInt32 DAR; //descriptor address register + UInt32 SAR; //source address register + UInt32 TAR; //target address register + UInt32 CR; //command register + UInt32 CSR; //control and status register + +}Pxa255dmaChannel; + +typedef struct{ + + Pxa255ic* ic; + ArmMem* mem; + + UInt16 DINT; + Pxa255dmaChannel channels[16]; + UInt8 CMR[40]; //channel map registers [ we store lower 8 bits only :-) ] + +}Pxa255dma; + + + +Boolean pxa255dmaInit(Pxa255dma* gpio, ArmMem* physMem, Pxa255ic* ic); + +#endif + diff --git a/contrib/other/uarm/pxa255_DSP.c b/contrib/other/uarm/pxa255_DSP.c new file mode 100755 index 0000000000..5a5cc1b46a --- /dev/null +++ b/contrib/other/uarm/pxa255_DSP.c @@ -0,0 +1,81 @@ +#include "math64.h" +#include "pxa255_DSP.h" + + + + +Boolean pxa255dspAccess(struct ArmCpu* cpu, void* userData, Boolean MRRC, UInt8 op, UInt8 RdLo, UInt8 RdHi, UInt8 acc){ + + Pxa255dsp* dsp = userData; + + if(acc != 0 || op != 0) return false; //bad encoding + + if(MRRC){ //MRA: read acc0 + + cpuSetReg(cpu, RdLo, u64_64_to_32(dsp->acc0)); + cpuSetReg(cpu, RdHi, (UInt8)u64_get_hi(dsp->acc0)); + } + else{ //MAR: write acc0 + + dsp->acc0 = u64_from_halves(cpuGetRegExternal(cpu, RdHi) & 0xFF, cpuGetRegExternal(cpu, RdLo)); + } + + return true; +} + +Boolean pxa255dspOp(struct ArmCpu* cpu, void* userData, Boolean two/* MCR2/MRC2 ? */, Boolean MRC, UInt8 op1, UInt8 Rs, UInt8 opcode_3, UInt8 Rm, UInt8 acc){ + + Pxa255dsp* dsp = userData; + UInt64 addend = u64_zero(); + UInt32 Vs, Vm; + + if(op1 != 1 || two || MRC || acc != 0) return false; //bad encoding + + Vs = cpuGetRegExternal(cpu, Rs); + Vm = cpuGetRegExternal(cpu, Rm); + + switch(opcode_3 >> 2){ + + case 0: //MIA + addend = u64_smul3232(Vm, Vs); + break; + + case 1: //invalid + return false; + + case 2: //MIAPH + addend = u64_smul3232((Int32)((Int16)(Vm >> 0)), (Int32)((Int16)(Vs >> 0))); + addend = u64_add(addend, u64_smul3232((Int32)((Int16)(Vm >> 16)), (Int32)((Int16)(Vs >> 16)))); + break; + + case 3: //MIAxy + if(opcode_3 & 2) Vm >>= 16; //X set + if(opcode_3 & 1) Vs >>= 16; //Y set + addend = u64_smul3232((Int32)((Int16)Vm), (Int32)((Int16)Vs)); + break; + } + + dsp->acc0 = u64_and(u64_add(dsp->acc0, addend), u64_from_halves(0xFF, 0xFFFFFFFFUL)); + + return true; +} + + + +Boolean pxa255dspInit(Pxa255dsp* dsp, ArmCpu* cpu){ + + ArmCoprocessor cp; + + + __mem_zero(dsp, sizeof(Pxa255dsp)); + + cp.regXfer = pxa255dspOp; + cp.dataProcessing = NULL; + cp.memAccess = NULL; + cp.twoRegF = pxa255dspAccess; + cp.userData = dsp; + + cpuCoprocessorRegister(cpu, 0, &cp); + + return true; +} \ No newline at end of file diff --git a/contrib/other/uarm/pxa255_DSP.h b/contrib/other/uarm/pxa255_DSP.h new file mode 100755 index 0000000000..1351bc6056 --- /dev/null +++ b/contrib/other/uarm/pxa255_DSP.h @@ -0,0 +1,20 @@ +#ifndef _PXA255_DSP_H_ +#define _PXA255_DSP_H_ + +#include "mem.h" +#include "cpu.h" + + + +typedef struct{ + + UInt64 acc0; + +}Pxa255dsp; + + + +Boolean pxa255dspInit(Pxa255dsp* dsp, ArmCpu* cpu); + + +#endif \ No newline at end of file diff --git a/contrib/other/uarm/pxa255_GPIO.c b/contrib/other/uarm/pxa255_GPIO.c new file mode 100755 index 0000000000..28881a523d --- /dev/null +++ b/contrib/other/uarm/pxa255_GPIO.c @@ -0,0 +1,206 @@ +#include "pxa255_GPIO.h" +#include "mem.h" + + +static void pxa255gpioPrvRecalcValues(Pxa255gpio* gpio, UInt32 which){ + + UInt8 i; + UInt32 val, bit; + + val = gpio->dirs[which]; + gpio->levels[which] = (gpio->latches[which] & val) | (gpio->inputs[which] & (~val)); + + val = 3; + bit = 1; + for(i = 0 ; i < 16; i++, val <<= 2, bit <<= 1) if(gpio->AFRs[(which << 1) + 0] & val) gpio->levels[which] &=~ bit; //all AFRs read as zero to CPU + for(i = 16; i < 32; i++, val <<= 2, bit <<= 1) if(gpio->AFRs[(which << 1) + 1] & val) gpio->levels[which] &=~ bit; //all AFRs read as zero to CPU +} + +static void pxa255gpioPrvRecalcIntrs(Pxa255gpio* gpio){ + + pxa255icInt(gpio->ic, PXA255_I_GPIO_all, gpio->levels[1] || gpio->levels[2] || (gpio->levels[0] &~ 3)); + pxa255icInt(gpio->ic, PXA255_I_GPIO_1, (gpio->levels[0] & 2) != 0); + pxa255icInt(gpio->ic, PXA255_I_GPIO_0, (gpio->levels[0] & 1) != 0); +} + +static Boolean pxa255gpioPrvMemAccessF(void* userData, UInt32 pa, UInt8 size, Boolean write, void* buf){ + + Pxa255gpio* gpio = userData; + UInt32 val = 0; + + if(size != 4) { + err_str(__FILE__ ": Unexpected "); + // err_str(write ? "write" : "read"); + // err_str(" of "); + // err_dec(size); + // err_str(" bytes to 0x"); + // err_hex(pa); + // err_str("\r\n"); + return true; //we do not support non-word accesses + } + + pa = (pa - PXA255_GPIO_BASE) >> 2; + + if(write){ + val = *(UInt32*)buf; + + switch(pa){ + case 0: + case 1: + case 2: + + break; + + case 3: + case 4: + case 5: + pa -= 3; + gpio->dirs[pa] = val; + goto recalc; + + case 6: + case 7: + case 8: + pa -= 6; + gpio->levels[pa] |= val; + goto recalc; + + case 9: + case 10: + case 11: + pa -= 9; + gpio->levels[pa] &=~ val; + goto recalc; + + case 12: + case 13: + case 14: + gpio->riseDet[pa - 12] = val; + break; + + case 15: + case 16: + case 17: + gpio->fallDet[pa - 15] = val; + break; + + case 18: + case 19: + case 20: + gpio->detStatus[pa - 18] &=~ val; + goto trigger_intrs; + + case 21: + case 22: + case 23: + case 24: + case 25: + case 26: + val = gpio->AFRs[pa - 21]; + goto recalc; + } + + goto done; + +recalc: + pxa255gpioPrvRecalcValues(gpio, pa); + +trigger_intrs: + pxa255gpioPrvRecalcIntrs(gpio); + } + else{ + switch(pa){ + case 0: + case 1: + case 2: + val = gpio->levels[pa - 0]; + break; + + case 3: + case 4: + case 5: + val = gpio->dirs[pa - 3]; + break; + + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + val = 0; + break; + + case 12: + case 13: + case 14: + val = gpio->riseDet[pa - 12]; + break; + + case 15: + case 16: + case 17: + val = gpio->fallDet[pa - 15]; + break; + + case 18: + case 19: + case 20: + val = gpio->detStatus[pa - 18]; + break; + + case 21: + case 22: + case 23: + case 24: + case 25: + case 26: + val = gpio->AFRs[pa - 21]; + break; + + } + *(UInt32*)buf = val; + } + +done: + return true; +} + + +Boolean pxa255gpioInit(Pxa255gpio* gpio, ArmMem* physMem, Pxa255ic* ic){ + + __mem_zero(gpio, sizeof(Pxa255gpio)); + gpio->ic = ic; + + return memRegionAdd(physMem, PXA255_GPIO_BASE, PXA255_GPIO_SIZE, pxa255gpioPrvMemAccessF, gpio); +} + +void pxa255gpioSetState(Pxa255gpio* gpio, UInt8 gpioNum, Boolean on){ + + UInt32 set = gpioNum >> 5; + UInt32 v = 1UL << (gpioNum & 0x1F); + UInt32* p; + + if(gpioNum >= 85) return; + + p = gpio->inputs + set; + if(on) *p |= v; + else *p &=~ v; + + pxa255gpioPrvRecalcValues(gpio, set); + pxa255gpioPrvRecalcIntrs(gpio); +} + +UInt8 pxa255gpioGetState(Pxa255gpio* gpio, UInt8 gpioNum){ + + UInt32 sSet = gpioNum >> 5; + UInt32 bSet = gpioNum >> 4; + UInt32 sV = 1UL << (gpioNum & 0x1F); + UInt32 bV = 3UL << (gpioNum & 0x0F); + + + if(gpioNum >= 85) return PXA255_GPIO_NOT_PRESENT; + if(gpio->AFRs[bSet] & bV) return ((gpio->AFRs[bSet] & bV) >> (gpioNum & 0x0F)) + PXA255_GPIO_AFR1; + if(gpio->dirs[sSet] & sV) return (gpio->latches[sSet] & sV) ? PXA255_GPIO_HIGH : PXA255_GPIO_LOW; + return PXA255_GPIO_HiZ; +} diff --git a/contrib/other/uarm/pxa255_GPIO.h b/contrib/other/uarm/pxa255_GPIO.h new file mode 100755 index 0000000000..3585e90b98 --- /dev/null +++ b/contrib/other/uarm/pxa255_GPIO.h @@ -0,0 +1,47 @@ +#ifndef _PXA255_GPIO_H_ +#define _PXA255_GPIO_H_ + +#include "mem.h" +#include "cpu.h" +#include "pxa255_IC.h" + +/* + PXA255 OS GPIO controller + +*/ + +#define PXA255_GPIO_BASE 0x40E00000UL +#define PXA255_GPIO_SIZE 0x00001000UL + + +typedef struct{ + + Pxa255ic* ic; + + UInt32 latches[3]; //what pxa wants to be outputting + UInt32 inputs[3]; //what pxa is receiving [only set by the pxa255gpioSetState() API] + UInt32 levels[3]; //what pxa sees (it differs from above for IN pins) + UInt32 dirs[3]; //1 = output + UInt32 riseDet[3]; //1 = rise detect + UInt32 fallDet[3]; //1 = fall detect + UInt32 detStatus[3]; //1 = detect happened + UInt32 AFRs[6]; //1, 2, 3 = alt funcs + +}Pxa255gpio; + +#define PXA255_GPIO_LOW 0 //these values make it look like all HiZ, AFR, and nonexistent pins have pullups to those who dumbly assume gpioGEt returns a boolean +#define PXA255_GPIO_HIGH 1 +#define PXA255_GPIO_HiZ 2 +#define PXA255_GPIO_AFR1 3 +#define PXA255_GPIO_AFR2 4 +#define PXA255_GPIO_AFR3 5 +#define PXA255_GPIO_NOT_PRESENT 6 + +Boolean pxa255gpioInit(Pxa255gpio* gpio, ArmMem* physMem, Pxa255ic* ic); + +//for external use :) +UInt8 pxa255gpioGetState(Pxa255gpio* gpio, UInt8 gpioNum); +void pxa255gpioSetState(Pxa255gpio* gpio, UInt8 gpioNum, Boolean on); //we can only set value (and only of input pins), not direction + +#endif + diff --git a/contrib/other/uarm/pxa255_IC.c b/contrib/other/uarm/pxa255_IC.c new file mode 100755 index 0000000000..261f81eedf --- /dev/null +++ b/contrib/other/uarm/pxa255_IC.c @@ -0,0 +1,104 @@ +#include "pxa255_IC.h" +#include "mem.h" + + +static void pxa255icPrvHandleChanges(Pxa255ic* ic){ + + Boolean nowIrq, nowFiq; + UInt32 unmasked = ic->ICPR & ic->ICMR; + + 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); + + ic->wasFiq = nowFiq; + ic->wasIrq = nowIrq; +} + +static Boolean pxa255icPrvMemAccessF(void* userData, UInt32 pa, UInt8 size, Boolean write, void* buf){ + + Pxa255ic* ic = userData; + UInt32 val = 0; + + if(size != 4) { + err_str(__FILE__ ": Unexpected "); + // err_str(write ? "write" : "read"); + // err_str(" of "); + // err_dec(size); + // err_str(" bytes to 0x"); + // err_hex(pa); + // err_str("\r\n"); + return true; //we do not support non-word accesses + } + + pa = (pa - PXA255_IC_BASE) >> 2; + + if(write){ + if(pa == 1) ic->ICMR = *(UInt32*)buf; + else if(pa == 2) ic->ICLR = *(UInt32*)buf; + else if(pa == 5) ic->ICCR = *(UInt32*)buf; + else return true; + pxa255icPrvHandleChanges(ic); + } + else{ + switch(pa){ + + case 0: + val = ic->ICPR & ic->ICMR & ~ic->ICLR; + break; + + case 1: + val = ic->ICMR; + break; + + case 2: + val = ic->ICLR; + break; + + case 3: + val = ic->ICPR & ic->ICMR & ic->ICLR; + break; + + case 4: + val = ic->ICPR; + break; + + case 5: + val = ic->ICCR; + break; + + } + *(UInt32*)buf = val; + } + return true; +} + +Boolean pxa255icInit(Pxa255ic* ic, ArmCpu* cpu, ArmMem* physMem){ + + __mem_zero(ic, sizeof(Pxa255ic)); + ic->cpu = cpu; + return memRegionAdd(physMem, PXA255_IC_BASE, PXA255_IC_SIZE, pxa255icPrvMemAccessF, ic); +} + + +void pxa255icInt(Pxa255ic* ic, UInt8 intNum, Boolean raise){ //interrupt caused by emulated hardware + + UInt32 old_, new_; + + old_ = new_ = ic->ICPR; + + if(raise) new_ |= (1UL << intNum); + else new_ &=~ (1UL << intNum); + + if(new_ != old_){ + ic->ICPR = new_; + pxa255icPrvHandleChanges(ic); + } +} + + + + + diff --git a/contrib/other/uarm/pxa255_IC.h b/contrib/other/uarm/pxa255_IC.h new file mode 100755 index 0000000000..665b01404a --- /dev/null +++ b/contrib/other/uarm/pxa255_IC.h @@ -0,0 +1,64 @@ +#ifndef _PXA255_IC_H_ +#define _PXA255_IC_H_ + +#include "mem.h" +#include "CPU.h" +#include + +/* + PXA255 interrupt controller + + PURRPOSE: raises IRQ, FIQ as needed + +*/ + +#define PXA255_IC_BASE 0x40D00000UL +#define PXA255_IC_SIZE 0x00010000UL + + +#define PXA255_I_RTC_ALM 31 +#define PXA255_I_RTC_HZ 30 +#define PXA255_I_TIMR3 29 +#define PXA255_I_TIMR2 28 +#define PXA255_I_TIMR1 27 +#define PXA255_I_TIMR0 26 +#define PXA255_I_DMA 25 +#define PXA255_I_SSP 24 +#define PXA255_I_MMC 23 +#define PXA255_I_FFUART 22 +#define PXA255_I_BTUART 21 +#define PXA255_I_STUART 20 +#define PXA255_I_ICP 19 +#define PXA255_I_I2C 18 +#define PXA255_I_LCD 17 +#define PXA255_I_NET_SSP 16 +#define PXA255_I_AC97 14 +#define PXA255_I_I2S 13 +#define PXA255_I_PMU 12 +#define PXA255_I_USB 11 +#define PXA255_I_GPIO_all 10 +#define PXA255_I_GPIO_1 9 +#define PXA255_I_GPIO_0 8 +#define PXA255_I_HWUART 7 + + +typedef struct{ + + ArmCpu* cpu; + + UInt32 ICMR; //Mask Register + UInt32 ICLR; //Level Register + UInt32 ICCR; //Control Register + UInt32 ICPR; //Pending register + + Boolean wasIrq, wasFiq; + +}Pxa255ic; + +Boolean pxa255icInit(Pxa255ic* ic, ArmCpu* cpu, ArmMem* physMem); + +void pxa255icInt(Pxa255ic* ic, UInt8 intNum, Boolean raise); //interrupt caused by emulated hardware/ interrupt handled by guest + + +#endif + diff --git a/contrib/other/uarm/pxa255_LCD.c b/contrib/other/uarm/pxa255_LCD.c new file mode 100755 index 0000000000..a85995304d --- /dev/null +++ b/contrib/other/uarm/pxa255_LCD.c @@ -0,0 +1,454 @@ +#include "pxa255_LCD.h" +#include "mem.h" + + + +#define LCD_IMAGE "LCD.bmp" +#define UNMASKABLE_INTS 0x7C8E + + +static void pxa255lcdPrvUpdateInts(Pxa255lcd* lcd){ + + UInt16 ints = lcd->lcsr & lcd->intMask; + + if((ints && !lcd->intWasPending) || (!ints && lcd->intWasPending)){ + + lcd->intWasPending = !!ints; + pxa255icInt(lcd->ic, PXA255_I_LCD, !!ints); + } +} + +static Boolean pxa255lcdPrvMemAccessF(void* userData, UInt32 pa, UInt8 size, Boolean write, void* buf){ + + Pxa255lcd* lcd = userData; + UInt32 val = 0; + UInt16 v16; + + if(size != 4) { + err_str(__FILE__ ": Unexpected "); + // err_str(write ? "write" : "read"); + // err_str(" of "); + // err_dec(size); + // err_str(" bytes to 0x"); + // err_hex(pa); + // err_str("\r\n"); + return true; //we do not support non-word accesses + } + + pa = (pa - PXA255_LCD_BASE) >> 2; + + if(write){ + val = *(UInt32*)buf; + + switch(pa){ + case 0: + if((lcd->lccr0 ^ val) & 0x0001){ //something changed about enablement - handle it + + lcd->enbChanged = 1; + } + lcd->lccr0 = val; + //recalc intMask + v16 = UNMASKABLE_INTS; + if(val & 0x00200000UL){ //output fifo underrun + v16 |= 0x0040; + } + if(val & 0x00100000UL){ //branch int + v16 |= 0x0200; + } + if(val & 0x00000400UL){ //quick disable + v16 |= 0x0001; + } + if(val & 0x00000040UL){ //end of frame + v16 |= 0x0080; + } + if(val & 0x00000020UL){ //input fifo underrun + v16 |= 0x0030; + } + if(val & 0x00000010UL){ //start of frame + v16 |= 0x0002; + } + lcd->intMask = v16; + pxa255lcdPrvUpdateInts(lcd); + break; + + case 1: + lcd->lccr1 = val; + break; + + case 2: + lcd->lccr2 = val; + break; + + case 3: + lcd->lccr3 = val; + break; + + case 8: + lcd->fbr0 = val; + break; + + case 9: + lcd->fbr1 = val; + break; + + case 14: + lcd->lcsr &=~ val; + pxa255lcdPrvUpdateInts(lcd); + break; + + case 15: + lcd->liicr = val; + break; + + case 16: + lcd->trgbr = val; + break; + + case 17: + lcd->tcr = val; + break; + + case 128: + lcd->fdadr0 = val; + break; + + case 132: + lcd->fdadr1 = val; + break; + } + } + else{ + switch(pa){ + case 0: + val = lcd->lccr0; + break; + + case 1: + val = lcd->lccr1; + break; + + case 2: + val = lcd->lccr2; + break; + + case 3: + val = lcd->lccr3; + break; + + case 8: + val = lcd->fbr0; + break; + + case 9: + val = lcd->fbr1; + break; + + case 14: + val = lcd->lcsr; + break; + + case 15: + val = lcd->liicr; + break; + + case 16: + val = lcd->trgbr; + break; + + case 17: + val = lcd->tcr; + break; + + case 128: + val = lcd->fdadr0; + break; + + case 129: + val = lcd->fsadr0; + break; + + case 130: + val = lcd->fidr0; + break; + + case 131: + val = lcd->ldcmd0; + break; + + case 132: + val = lcd->fdadr1; + break; + + case 133: + val = lcd->fsadr1; + break; + + case 134: + val = lcd->fidr1; + break; + + case 135: + val = lcd->ldcmd1; + break; + } + *(UInt32*)buf = val; + } + + return true; +} + +static UInt32 pxa255PrvGetWord(Pxa255lcd* lcd, UInt32 addr){ + + UInt32 v; + + if(!memAccess(lcd->mem, addr, 4, false, &v)) return 0; + + return v; +} + +static void pxa255LcdPrvDma(Pxa255lcd* lcd, void* dest, UInt32 addr, UInt32 len){ + + UInt32 t; + UInt8* d = dest; + + //we assume aligntment here both on part of dest and of addr + + while(len){ + + t = pxa255PrvGetWord(lcd, addr); + if(len--) *d++ = t; + if(len--) *d++ = t >> 8; + if(len--) *d++ = t >> 16; + if(len--) *d++ = t >> 24; + addr += 4; + } +} + +#ifndef EMBEDDED + #include + + static _INLINE_ void pxa255LcdScreenDataPixel(Pxa255lcd* lcd, UInt8* buf){ + + UInt8 r, g, b; + const UInt32 W = 640; + const UInt32 H = 480; + + b = buf[0] << 3; + r = buf[1] & 0xF8; + g = (buf[1] << 5) | ((buf[0] >> 3) & 0x1C); + + { + static UInt32 pn = 0; + static FILE* bmp = NULL; + + if(pn == 0){ + bmp = fopen(LCD_IMAGE, "w+b"); + if(bmp){ + + const UInt32 off = 56; + const UInt32 sz = 320 * 320 * 3 + off; + #define LE32(x) ((int)((x) & 0xFF)), ((int)(((x) >> 8) & 0xFF)), ((int)(((x) >> 16) & 0xFF)), ((int)((x) >> 24)) + #define LE16(x) ((int)((x) & 0xFF)), ((int)(((x) >> 8) & 0xFF)) + + fprintf(bmp, "BM%c%c%c%c%c%c%c%c%c%c%c%c", LE32(sz), LE16(0), LE16(0), LE32(off)); //bitmap file header + fprintf(bmp, "%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c", LE32(40), LE32(W), LE32(-H), LE16(1), LE16(24), LE32(0), LE32(W * H * 3), LE32(2835), LE32(2835), LE32(0), LE32(0)); //BITMAPCOREHEADER + fprintf(bmp, "%c%c",0 ,0); //spacer to align bmp data to 4 bytes + + #undef LE32 + } + } + if(bmp){ + + fprintf(bmp, "%c%c%c", b, g, r); + } + pn++; + if(pn == W * H){ + pn = 0; + if(bmp){ + + fclose(bmp); + bmp = NULL; + } + } + } + } + + #ifndef PXA255_LCD_SUPPORTS_PALLETES + static void pxa255LcdSetFakePal(UInt8* buf, UInt8 bpp, UInt8 val){ + + while(bpp++ < 8) val = (val << 1) | (val & 1); //sign extend up (weird but works) + + buf[1] = (val & 0xF8) | (val >> 3); + buf[0] = ((val & 0xFC) << 5) | val >> 3; + } + #endif + + static void pxa255LcdScreenDataDma(Pxa255lcd* lcd, UInt32 addr/*PA*/, UInt32 len){ + + UInt8 data[4]; + UInt32 i, j; + void* ptr; + #ifndef PXA255_LCD_SUPPORTS_PALLETES + UInt8 val[2]; + #endif + + len /= 4; + while(len--){ + pxa255LcdPrvDma(lcd, data, addr, 4); + addr += 4; + + switch((lcd->lccr3 >> 24) & 7){ + + case 0: //1BPP + + #ifdef PXA255_LCD_SUPPORTS_PALLETES + ptr = lcd->palette + ((data[i] >> j) & 1) * 2; + #else + ptr = val; + pxa255LcdSetFakePal(val, 1, (data[i] >> j) & 1); + #endif + for(i = 0; i < 4; i += 1) for(j = 0; j < 8; j += 1) pxa255LcdScreenDataPixel(lcd, ptr); + break; + + case 1: //2BPP + + #ifdef PXA255_LCD_SUPPORTS_PALLETES + ptr = lcd->palette + ((data[i] >> j) & 3) * 2; + #else + ptr = val; + pxa255LcdSetFakePal(val, 2, (data[i] >> j) & 3); + #endif + for(i = 0; i < 4; i += 1) for(j = 0; j < 8; j += 2) pxa255LcdScreenDataPixel(lcd, ptr); + break; + + case 2: //4BPP + + #ifdef PXA255_LCD_SUPPORTS_PALLETES + ptr = lcd->palette + ((data[i] >> j) & 15) * 2; + #else + ptr = val; + pxa255LcdSetFakePal(val, 4, (data[i] >> j) & 15); + #endif + for(i = 0; i < 4; i += 1) for(j = 0; j < 8; j += 4) pxa255LcdScreenDataPixel(lcd, ptr); + break; + + case 3: //8BPP + + #ifdef PXA255_LCD_SUPPORTS_PALLETES + ptr = lcd->palette + (data[i] * 2); + #else + ptr = val; + pxa255LcdSetFakePal(val, 8, data[i]); + #endif + for(i = 0; i < 4; i += 1) pxa255LcdScreenDataPixel(lcd, ptr); + break; + + case 4: //16BPP + + for(i = 0; i < 4; i +=2 ) pxa255LcdScreenDataPixel(lcd, data + i); + break; + + default: + + ;//BAD + } + } + } +#else + static void pxa255LcdScreenDataDma(Pxa255lcd* lcd, UInt32 addr/*PA*/, UInt32 len){ + + //nothing + } +#endif + +void pxa255lcdFrame(Pxa255lcd* lcd){ + //every other call starts a frame, the others end one [this generates spacing between interrupts so as to not confuse guest OS] + + if(lcd->enbChanged){ + + if(lcd->lccr0 & 0x0001){ //just got enabled + + //TODO: perhaps check settings? + } + else{ // we just got quick disabled - kill current frame and do no more + + lcd->lcsr |= 0x0080; //quick disable happened + lcd->state = LCD_STATE_IDLE; + } + lcd->enbChanged = false; + } + + if(lcd->lccr0 & 0x0001){ //enabled - do a frame + + UInt32 descrAddr, len; + + switch(lcd->state){ + + case LCD_STATE_IDLE: + + if(lcd->fbr0 & 1){ //branch + + lcd->fbr0 &=~ 1UL; + if(lcd->fbr0 & 2) lcd->lcsr |= 0x0200; + descrAddr = lcd->fbr0 &~ 0xFUL; + } else descrAddr = lcd->fdadr0; + lcd->fdadr0 = pxa255PrvGetWord(lcd, descrAddr + 0); + lcd->fsadr0 = pxa255PrvGetWord(lcd, descrAddr + 4); + lcd->fidr0 = pxa255PrvGetWord(lcd, descrAddr + 8); + lcd->ldcmd0 = pxa255PrvGetWord(lcd, descrAddr + 12); + + lcd->state = LCD_STATE_DMA_0_START; + break; + + case LCD_STATE_DMA_0_START: + + if(lcd->ldcmd0 & 0x00400000UL) lcd->lcsr |= 0x0002; //set SOF is DMA 0 started + len = lcd->ldcmd0 & 0x000FFFFFUL; + + if(lcd->ldcmd0 & 0x04000000UL){ //pallette data + + #ifdef PXA255_LCD_SUPPORTS_PALLETES + if(len > sizeof(lcd->palette)){ + + len = sizeof(lcd->palette); + + pxa255LcdPrvDma(lcd, lcd->palette, lcd->fsadr0, len); + } + #endif + } + else{ + + lcd->frameNum++; + if(!(lcd->frameNum & 63)) pxa255LcdScreenDataDma(lcd, lcd->fsadr0, len); + } + + lcd->state = LCD_STATE_DMA_0_END; + break; + + case LCD_STATE_DMA_0_END: + + if(lcd->ldcmd0 & 0x00200000UL) lcd->lcsr |= 0x0100; //set EOF is DMA 0 finished + lcd->state = LCD_STATE_IDLE; + break; + } + } + pxa255lcdPrvUpdateInts(lcd); +} + + +Boolean pxa255lcdInit(Pxa255lcd* lcd, ArmMem* physMem, Pxa255ic* ic){ + + + __mem_zero(lcd, sizeof(Pxa255lcd)); + + lcd->ic = ic; + lcd->mem = physMem; + lcd->intMask = UNMASKABLE_INTS; + + return memRegionAdd(physMem, PXA255_LCD_BASE, PXA255_LCD_SIZE, pxa255lcdPrvMemAccessF, lcd); +} + + + + + diff --git a/contrib/other/uarm/pxa255_LCD.h b/contrib/other/uarm/pxa255_LCD.h new file mode 100755 index 0000000000..c2f3f6b471 --- /dev/null +++ b/contrib/other/uarm/pxa255_LCD.h @@ -0,0 +1,63 @@ +#ifndef _PXA255_LCD_H_ +#define _PXA255_LCD_H_ + +#include "mem.h" +#include "cpu.h" +#include "pxa255_IC.h" + +#ifndef EMBEDDED + #define PXA255_LCD_SUPPORTS_PALLETES +#endif + + +/* + PXA255 OS LCD controller + + PURRPOSE: it's nice to have a framebuffer + +*/ + +#define PXA255_LCD_BASE 0x44000000UL +#define PXA255_LCD_SIZE 0x00001000UL + + + + +#define LCD_STATE_IDLE 0 +#define LCD_STATE_DMA_0_START 1 +#define LCD_STATE_DMA_0_END 2 + +typedef struct{ + + Pxa255ic* ic; + ArmMem* mem; + + //registers + UInt32 lccr0, lccr1, lccr2, lccr3, fbr0, fbr1, liicr, trgbr, tcr; + UInt32 fdadr0, fsadr0, fidr0, ldcmd0; + UInt32 fdadr1, fsadr1, fidr1, ldcmd1; + UInt16 lcsr; //yes, 16-bit :) + + //for our use + UInt16 intMask; + + UInt8 state : 6; + UInt8 intWasPending : 1; + UInt8 enbChanged : 1; + +#ifdef PXA255_LCD_SUPPORTS_PALLETES + + UInt8 palette[512]; + +#endif + + UInt32 frameNum; + +}Pxa255lcd; + +Boolean pxa255lcdInit(Pxa255lcd* lcd, ArmMem* physMem, Pxa255ic* ic); +void pxa255lcdFrame(Pxa255lcd* lcd); + + +#endif + diff --git a/contrib/other/uarm/pxa255_PwrClk.c b/contrib/other/uarm/pxa255_PwrClk.c new file mode 100755 index 0000000000..9c37d7b8da --- /dev/null +++ b/contrib/other/uarm/pxa255_PwrClk.c @@ -0,0 +1,154 @@ +#include "pxa255_PwrClk.h" + + +static Boolean pxa255pwrClkPrvCoprocRegXferFunc(struct ArmCpu* cpu, void* userData, Boolean two, Boolean read, UInt8 op1, UInt8 Rx, UInt8 CRn, UInt8 CRm, UInt8 op2){ + + Pxa255pwrClk* pc = userData; + UInt32 val = 0; + + if(!read) val = cpuGetRegExternal(cpu, Rx); + + if(CRm == 0 && op2 == 0 && op1 == 0 && !two){ + + switch(CRn){ + + case 6: + if(read) val = 0; + else{ + pc->turbo = (val & 1) != 0; + if(val & 2){ + + err_str("Set speed mode"); + // err_str("(CCCR + cp14 reg6) to 0x"); + // err_hex(pc->CCCR); + // err_str(", 0x"); + // err_hex(val); + // err_str("\r\n"); + } + } + + case 7: + if(read) val = pc->turbo ? 1 : 0; + else if(val != 0){ + + // fprintf(stderr, "Someone tried to set processor power mode (cp14 reg7) to 0x%08lX\n", val); + } + goto success; + } + } + + return false; + +success: + + if(read) cpuSetReg(cpu, Rx, val); + return true; +} + +static Boolean pxa255pwrClkPrvClockMgrMemAccessF(void* userData, UInt32 pa, UInt8 size, Boolean write, void* buf){ + + Pxa255pwrClk* pc = userData; + UInt32 val = 0; + + if(size != 4) { + err_str(__FILE__ ": Unexpected "); + // err_str(write ? "write" : "read"); + // err_str(" of "); + // err_dec(size); + // err_str(" bytes to 0x"); + // err_hex(pa); + // err_str("\r\n"); + return true; //we do not support non-word accesses + } + + pa = (pa - PXA255_CLOCK_MANAGER_BASE) >> 2; + + if(write) val = *(UInt32*)buf; + + switch(pa){ + + case 0: //CCCR + if(write) pc->CCCR = val; + else val = pc->CCCR; + break; + + case 1: //CKEN + if(write) pc->CKEN = val; + else val = pc->CKEN; + break; + + case 2: //OSCR + if(!write) val = pc->OSCR; + //no writing to this register + break; + } + + if(!write) *(UInt32*)buf = val; + + return true; +} + +static Boolean pxa255pwrClkPrvPowerMgrMemAccessF(void* userData, UInt32 pa, UInt8 size, Boolean write, void* buf){ + + Pxa255pwrClk* pc = userData; + UInt32 val = 0; + + if(size != 4) { + err_str(__FILE__ ": Unexpected "); + // err_str(write ? "write" : "read"); + // err_str(" of "); + // err_dec(size); + // err_str(" bytes to 0x"); + // err_hex(pa); + // err_str("\r\n"); + return true; //we do not support non-word accesses + } + + pa = (pa - PXA255_POWER_MANAGER_BASE) >> 2; + + if(write) val = *(UInt32*)buf; + + if(pa < 13){ + + if(write) pc->pwrRegs[pa] = val; + else val = pc->pwrRegs[pa]; + } + + if(!write) *(UInt32*)buf = val; + + return true; +} + +Boolean pxa255pwrClkInit(Pxa255pwrClk* pc, ArmCpu* cpu, ArmMem* physMem){ + + ArmCoprocessor cp; + Boolean ok = true; + + __mem_zero(pc, sizeof(Pxa255pwrClk)); + + pc->cpu = cpu; + pc->CCCR = 0x00000122UL; //set CCCR to almost default value (we use mult 32 not 27) + pc->CKEN = 0x000179EFUL; //set CKEN to default value + pc->OSCR = 0x00000003UL; //32KHz oscillator on and stable + pc->pwrRegs[1] = 0x20; //set PSSR + pc->pwrRegs[3] = 3; //set PWER + pc->pwrRegs[4] = 3; //set PRER + pc->pwrRegs[5] = 3; //set PFER + pc->pwrRegs[12] = 1; //set RCSR + + + cp.regXfer = pxa255pwrClkPrvCoprocRegXferFunc; + cp.dataProcessing = NULL; + cp.memAccess = NULL; + cp.twoRegF = NULL; + cp.userData = pc; + + cpuCoprocessorRegister(cpu, 14, &cp); + + ok = ok && memRegionAdd(physMem, PXA255_CLOCK_MANAGER_BASE, PXA255_CLOCK_MANAGER_SIZE, pxa255pwrClkPrvClockMgrMemAccessF, pc); + ok = ok && memRegionAdd(physMem, PXA255_POWER_MANAGER_BASE, PXA255_POWER_MANAGER_SIZE, pxa255pwrClkPrvPowerMgrMemAccessF, pc); + + return ok; +} + + diff --git a/contrib/other/uarm/pxa255_PwrClk.h b/contrib/other/uarm/pxa255_PwrClk.h new file mode 100755 index 0000000000..e8ba87ba69 --- /dev/null +++ b/contrib/other/uarm/pxa255_PwrClk.h @@ -0,0 +1,32 @@ +#ifndef _PXA255_PWR_CLK_H_ +#define _PXA255_PWR_CLK_H_ + +#include "mem.h" +#include "cpu.h" + + + +typedef struct{ + + ArmCpu* cpu; + UInt32 CCCR, CKEN, OSCR; //clocks manager regs + UInt32 pwrRegs[13]; //we care so little about these, we don't even name them + Boolean turbo; + +}Pxa255pwrClk; + + +#define PXA255_CLOCK_MANAGER_BASE 0x41300000UL +#define PXA255_CLOCK_MANAGER_SIZE 0x00001000UL + +#define PXA255_POWER_MANAGER_BASE 0x40F00000UL +#define PXA255_POWER_MANAGER_SIZE 0x00001000UL + + +Boolean pxa255pwrClkInit(Pxa255pwrClk* pc, ArmCpu* cpu, ArmMem* physMem); + + + + + +#endif diff --git a/contrib/other/uarm/pxa255_RTC.c b/contrib/other/uarm/pxa255_RTC.c new file mode 100755 index 0000000000..9a364cd049 --- /dev/null +++ b/contrib/other/uarm/pxa255_RTC.c @@ -0,0 +1,101 @@ +#include "pxa255_RTC.h" +#include "mem.h" + + + +void pxa255rtcPrvUpdate(Pxa255rtc* rtc){ + + UInt32 time = rtcCurTime(); + + if(rtc->lastSeenTime != time){ //do not triger alarm more than once per second please + + if((rtc->RTSR & 0x4) && (time + rtc->RCNR_offset == rtc->RTAR)){ //check alarm + rtc->RTSR |= 1; + } + if(rtc->RTSR & 0x8){ //send HZ interrupt + rtc->RTSR |= 2; + } + } + pxa255icInt(rtc->ic, PXA255_I_RTC_ALM, (rtc->RTSR & 1) != 0); + pxa255icInt(rtc->ic, PXA255_I_RTC_HZ, (rtc->RTSR & 2) != 0); +} + +static Boolean pxa255rtcPrvMemAccessF(void* userData, UInt32 pa, UInt8 size, Boolean write, void* buf){ + + Pxa255rtc* rtc = userData; + UInt32 val = 0; + + if(size != 4) { + err_str(__FILE__ ": Unexpected "); + // err_str(write ? "write" : "read"); + // err_str(" of "); + // err_dec(size); + // err_str(" bytes to 0x"); + // err_hex(pa); + // err_str("\r\n"); + return true; //we do not support non-word accesses + } + + pa = (pa - PXA255_RTC_BASE) >> 2; + + if(write){ + val = *(UInt32*)buf; + + switch(pa){ + case 0: + rtc->RCNR_offset = rtcCurTime() - val; + break; + + case 1: + rtc->RTAR = val; + pxa255rtcPrvUpdate(rtc); + break; + + case 2: + rtc->RTSR = (val &~ 3UL) | ((rtc->RTSR &~ val) & 3UL); + pxa255rtcPrvUpdate(rtc); + break; + + case 3: + if(!(rtc->RTTR & 0x80000000UL)) rtc->RTTR = val; + break; + } + } + else{ + switch(pa){ + case 0: + val = rtcCurTime() - rtc->RCNR_offset; + break; + + case 1: + val = rtc->RTAR; + break; + + case 2: + val = rtc->RTSR; + break; + + case 3: + val = rtc->RTTR; + break; + } + *(UInt32*)buf = val; + } + + return true; +} + + +Boolean pxa255rtcInit(Pxa255rtc* rtc, ArmMem* physMem, Pxa255ic* ic){ + + __mem_zero(rtc, sizeof(Pxa255rtc)); + rtc->ic = ic; + rtc->RCNR_offset = 0; + rtc->RTTR = 0x7FFF; //nice default value + rtc->lastSeenTime = rtcCurTime(); + return memRegionAdd(physMem, PXA255_RTC_BASE, PXA255_RTC_SIZE, pxa255rtcPrvMemAccessF, rtc); +} + +void pxa255rtcUpdate(Pxa255rtc* rtc){ + pxa255rtcPrvUpdate(rtc); +} diff --git a/contrib/other/uarm/pxa255_RTC.h b/contrib/other/uarm/pxa255_RTC.h new file mode 100755 index 0000000000..2729320dc9 --- /dev/null +++ b/contrib/other/uarm/pxa255_RTC.h @@ -0,0 +1,37 @@ +#ifndef _PXA255_RTC_H_ +#define _PXA255_RTC_H_ + +#include "mem.h" +#include "cpu.h" +#include "pxa255_IC.h" + + +/* + PXA255 OS RTC controller + + PURRPOSE: it's nice to know what time it is + +*/ + +#define PXA255_RTC_BASE 0x40900000UL +#define PXA255_RTC_SIZE 0x00001000UL + + +typedef struct{ + + Pxa255ic* ic; + + UInt32 RCNR_offset; //RTC counter offset from our local time + UInt32 RTAR; //RTC alarm + UInt32 RTSR; //RTC status + UInt32 RTTR; //RTC trim - we ignore this alltogether + UInt32 lastSeenTime; //for HZ interrupt + +}Pxa255rtc; + +Boolean pxa255rtcInit(Pxa255rtc* rtc, ArmMem* physMem, Pxa255ic* ic); +void pxa255rtcUpdate(Pxa255rtc* rtc); + + +#endif + diff --git a/contrib/other/uarm/pxa255_TIMR.c b/contrib/other/uarm/pxa255_TIMR.c new file mode 100755 index 0000000000..757d43745c --- /dev/null +++ b/contrib/other/uarm/pxa255_TIMR.c @@ -0,0 +1,123 @@ +#include "pxa255_TIMR.h" +#include "mem.h" + + +static void pxa255timrPrvRaiseLowerInts(Pxa255timr* timr){ + + pxa255icInt(timr->ic, PXA255_I_TIMR0, (timr->OSSR & 1) != 0); + pxa255icInt(timr->ic, PXA255_I_TIMR1, (timr->OSSR & 2) != 0); + pxa255icInt(timr->ic, PXA255_I_TIMR2, (timr->OSSR & 4) != 0); + pxa255icInt(timr->ic, PXA255_I_TIMR3, (timr->OSSR & 8) != 0); +} + +static void pxa255timrPrvCheckMatch(Pxa255timr* timr, UInt8 idx){ + + UInt8 v = 1UL << idx; + + if((timr->OSCR == timr->OSMR[idx]) && (timr->OIER & v)){ + timr->OSSR |= v; + } +} + +static void pxa255timrPrvUpdate(Pxa255timr* timr){ + + pxa255timrPrvCheckMatch(timr, 0); + pxa255timrPrvCheckMatch(timr, 1); + pxa255timrPrvCheckMatch(timr, 2); + pxa255timrPrvCheckMatch(timr, 3); +} + +static Boolean pxa255timrPrvMemAccessF(void* userData, UInt32 pa, UInt8 size, Boolean write, void* buf){ + + Pxa255timr* timr = userData; + UInt32 val = 0; + + if(size != 4) { + err_str(__FILE__ ": Unexpected "); + // err_str(write ? "write" : "read"); + // err_str(" of "); + // err_dec(size); + // err_str(" bytes to 0x"); + // err_hex(pa); + // err_str("\r\n"); + return true; //we do not support non-word accesses + } + + pa = (pa - PXA255_TIMR_BASE) >> 2; + + if(write){ + val = *(UInt32*)buf; + + switch(pa){ + case 0: + case 1: + case 2: + case 3: + timr->OSMR[pa] = val; + break; + + case 4: + timr->OSCR = val; + break; + + case 5: + timr->OSSR = timr->OSSR &~ val; + pxa255timrPrvRaiseLowerInts(timr); + break; + + case 6: + timr->OWER = val; + break; + + case 7: + timr->OIER = val; + pxa255timrPrvUpdate(timr); + pxa255timrPrvRaiseLowerInts(timr); + break; + } + } + else{ + switch(pa){ + case 0: + case 1: + case 2: + case 3: + val = timr->OSMR[pa]; + break; + + case 4: + val = timr->OSCR; + break; + + case 5: + val = timr->OSSR; + break; + + case 6: + val = timr->OWER; + break; + + case 7: + val = timr->OIER; + break; + } + *(UInt32*)buf = val; + } + + return true; +} + + +Boolean pxa255timrInit(Pxa255timr* timr, ArmMem* physMem, Pxa255ic* ic){ + + __mem_zero(timr, sizeof(Pxa255timr)); + timr->ic = ic; + return memRegionAdd(physMem, PXA255_TIMR_BASE, PXA255_TIMR_SIZE, pxa255timrPrvMemAccessF, timr); +} + +void pxa255timrTick(Pxa255timr* timr){ + + timr->OSCR++; + pxa255timrPrvUpdate(timr); + pxa255timrPrvRaiseLowerInts(timr); +} diff --git a/contrib/other/uarm/pxa255_TIMR.h b/contrib/other/uarm/pxa255_TIMR.h new file mode 100755 index 0000000000..8f200526db --- /dev/null +++ b/contrib/other/uarm/pxa255_TIMR.h @@ -0,0 +1,37 @@ +#ifndef _PXA255_TIMR_H_ +#define _PXA255_TIMR_H_ + +#include "mem.h" +#include "cpu.h" +#include "pxa255_IC.h" + + +/* + PXA255 OS timers controller + + PURRPOSE: timers are useful for stuff :) + +*/ + +#define PXA255_TIMR_BASE 0x40A00000UL +#define PXA255_TIMR_SIZE 0x00010000UL + + +typedef struct{ + + Pxa255ic* ic; + + UInt32 OSMR[4]; //Match Register 0-3 + UInt32 OIER; //Interrupt Enable + UInt32 OWER; //Watchdog enable + UInt32 OSCR; //Counter Register + UInt32 OSSR; //Status Register + +}Pxa255timr; + +Boolean pxa255timrInit(Pxa255timr* timr, ArmMem* physMem, Pxa255ic* ic); +void pxa255timrTick(Pxa255timr* timr); + + +#endif + diff --git a/contrib/other/uarm/pxa255_UART.c b/contrib/other/uarm/pxa255_UART.c new file mode 100755 index 0000000000..283e5cf342 --- /dev/null +++ b/contrib/other/uarm/pxa255_UART.c @@ -0,0 +1,588 @@ +#include "pxa255_UART.h" +#include "mem.h" + + + +//TODO: signal handler for Ctl+C and send break to fifo :) +//todo: recalc ints after eveyr write and every call to "process" from SoC + + +#define UART_IER_DMAE 0x80 //DMA enable +#define UART_IER_UUE 0x40 //Uart unit enable +#define UART_IER_NRZE 0x20 //NRZI enable +#define UART_IER_RTOIE 0x10 //transmit timeout interrupt enable +#define UART_IER_MIE 0x08 //modem interrupt enable +#define UART_IER_RLSE 0x04 //receiver line status interrupt enable +#define UART_IER_TIE 0x02 //transmit data request interrupt enable +#define UART_IER_RAVIE 0x01 //receiver data available interrupt enable + +#define UART_IIR_FIFOES 0xC0 //fifo enable status +#define UART_IIR_TOD 0x08 //character timout interrupt pending +#define UART_IIR_RECV_ERR 0x06 //receive error(overrun, parity, framing, break) +#define UART_IIR_RECV_DATA 0x04 //receive data available +#define UART_IIR_RCV_TIMEOUT 0x0C //receive data in buffer and been a while since we've seen more +#define UART_IIR_SEND_DATA 0x02 //transmit fifo requests data +#define UART_IIR_MODEM_STAT 0x00 //modem lines changed state(CTS, DSR, DI, DCD) +#define UART_IIR_NOINT 0x01 //no interrupt pending + + +#define UART_FCR_ITL_MASK 0xC0 //mask for ITL part of FCR +#define UART_FCR_ITL_1 0x00 //interrupt when >=1 byte in recv fifo +#define UART_FCR_ITL_8 0x40 //interrupt when >=8 byte in recv fifo +#define UART_FCR_ITL_16 0x80 //interrupt when >=16 byte in recv fifo +#define UART_FCR_ITL_32 0xC0 //interrupt when >=32 byte in recv fifo +#define UART_FCR_RESETTF 0x04 //reset tranmitter fifo +#define UART_FCR_RESETRF 0x02 //reset receiver fifo +#define UART_FCR_TRFIFOE 0x01 //transmit and receive fifo enable + +#define UART_LCR_DLAB 0x80 //divisor latch access bit +#define UART_LCR_SB 0x40 //send break +#define UART_LCR_STKYP 0x20 //sticky parity (send parity bit but dont care what value) +#define UART_LCR_EPS 0x10 //even parity select +#define UART_LCR_PEN 0x08 //parity enable +#define UART_LCR_STB 0x04 //stop bits (1 = 2, 0 = 1) +#define UART_LCR_WLS_MASK 0x03 //mask for WLS values +#define UART_LCR_WLS_8 0x03 //8 bit words +#define UART_LCR_WLS_7 0x02 //7 bit words +#define UART_LCR_WLS_6 0x01 //6 bit words +#define UART_LCR_WLS_5 0x00 //5 bit words + +#define UART_LSR_FIFOE 0x80 //fifo contails an error (framing, parity, or break) +#define UART_LSR_TEMT 0x40 //tranmitter empty (shift reg is empty and no more byte sin fifo/no byte in holding reg) +#define UART_LSR_TDRQ 0x20 //transmitter data request (see docs) +#define UART_LSR_BI 0x10 //send when char at front of fifo (or in holding reg) was a break char (chr reads as zero by itself) +#define UART_LSR_FE 0x08 //same as above, but for framing errors +#define UART_LSR_PE 0x04 //dame as above, but for parity errors +#define UART_LSR_OE 0x02 //recv fifo overran +#define UART_LSR_DR 0x01 //byte received + +#define UART_MCR_LOOP 0x10 //loop modem control lines (not full loopback) +#define UART_MCR_OUT2 0x08 //when loop is 0 enables or disables UART interrupts +#define UART_MCR_OUT1 0x04 //force RI to 1 +#define UART_MCR_RTS 0x02 //1 -> nRTS is 0 +#define UART_MCR_DTR 0x01 //0 -> nDTR is 0 + +#define UART_MSR_DCD 0x80 +#define UART_MSR_RI 0x40 +#define UART_MSR_DSR 0x20 +#define UART_MSR_CTS 0x10 +#define UART_MSR_DDCD 0x08 //dcd changed since last read +#define UART_MSR_TERI 0x04 //ri has changed from 0 to 1 since last read +#define UART_MSR_DDSR 0x02 //dsr changed since last read +#define UART_MSR_DCTS 0x01 //cts changed since last read + + + +static void pxa255uartPrvRecalc(Pxa255uart* uart); + + +static void pxa255uartPrvIrq(Pxa255uart* uart, Boolean raise){ + + pxa255icInt(uart->ic, uart->irq, !(uart->MCR & UART_MCR_LOOP) && (uart->MCR & UART_MCR_OUT2) && raise/* only raise if ints are enabled */); +} + +static UInt16 pxa255uartPrvDefaultRead(_UNUSED_ void* userData){ //these are special funcs since they always get their own userData - the uart pointer :) + + return UART_CHAR_NONE; //we read nothing..as always +} + +static void pxa255uartPrvDefaultWrite(_UNUSED_ UInt16 chr, _UNUSED_ void* userData){ //these are special funcs since they always get their own userData - the uart pointer :) + + //nothing to do here +} + +static UInt16 pxa255uartPrvGetchar(Pxa255uart* uart){ + + Pxa255UartReadF func = uart->readF; + void* data = (func == pxa255uartPrvDefaultRead) ? uart : uart->accessFuncsData; + + return func(data); +} + +static void pxa255uartPrvPutchar(Pxa255uart* uart, UInt16 chr){ + + Pxa255UartWriteF func = uart->writeF; + void* data = (func == pxa255uartPrvDefaultWrite) ? uart : uart->accessFuncsData; + + func(chr, data); +} + +UInt8 pxa255uartPrvFifoUsed(UartFifo* fifo){ //return num spots used + + UInt8 v; + + if(fifo->read == UART_FIFO_EMPTY) return 0; + v = fifo->write + UART_FIFO_DEPTH - fifo->read; + if(v > UART_FIFO_DEPTH) v -=UART_FIFO_DEPTH; + + return v; +} + +void pxa255uartPrvFifoFlush(UartFifo* fifo){ + + fifo->read = UART_FIFO_EMPTY; + fifo->write = UART_FIFO_EMPTY; +} + +Boolean pxa255uartPrvFifoPut(UartFifo* fifo, UInt16 val){ //return success + + if(fifo->read == UART_FIFO_EMPTY){ + + fifo->read = 0; + fifo->write = 1; + fifo->buf[0] = val; + } + else if(fifo->read != fifo->write){ //only if not full + + fifo->buf[fifo->write++] = val; + if(fifo->write == UART_FIFO_DEPTH) fifo->write = 0; + } + else return false; + + return true; +} + +UInt16 pxa255uartPrvFifoGet(UartFifo* fifo){ + + UInt16 ret; + + if(fifo->read == UART_FIFO_EMPTY){ + + ret = 0xFFFF; //why not? + } + else{ + + ret = fifo->buf[fifo->read++]; + if(fifo->read == UART_FIFO_DEPTH) fifo->read = 0; + + if(fifo->read == fifo->write){ //it is now empty + + fifo->read = UART_FIFO_EMPTY; + fifo->write = UART_FIFO_EMPTY; + } + } + + return ret; +} + +UInt16 pxa255uartPrvFifoPeekNth(UartFifo* fifo, UInt8 n){ + + UInt16 ret; + + + if(fifo->read == UART_FIFO_EMPTY){ + + ret = 0xFFFF; //why not? + } + else{ + + n += fifo->read; + if(n >= UART_FIFO_DEPTH) n-= UART_FIFO_DEPTH; + ret = fifo->buf[n]; + } + + return ret; +} + +UInt16 pxa255uartPrvFifoPeek(UartFifo* fifo){ + + return pxa255uartPrvFifoPeekNth(fifo, 0); +} + + +static void sendVal(Pxa255uart* uart, UInt16 v){ + + if(uart->LSR & UART_LSR_TEMT){ //if transmit, put in shift register immediately if it's idle + + uart->transmitShift = v; + uart->LSR &=~ UART_LSR_TEMT; + } + else if(uart->FCR & UART_FCR_TRFIFOE){ //put in tx fifo if in fifo mode + + pxa255uartPrvFifoPut(&uart->TX, v); + if(pxa255uartPrvFifoUsed(&uart->TX) > UART_FIFO_DEPTH / 2){ //we go went below half-full buffer - set appropriate bit... + + uart->LSR &=~ UART_LSR_TDRQ; + } + } + else if(uart->LSR & UART_LSR_TDRQ){ //send without fifo if in polled mode + + uart->transmitHolding = v; + uart->LSR &=~ UART_LSR_TDRQ; + } + else{ + + //nothing to do - buffer is full so we ignore this request + } +} + +static Boolean pxa255uartPrvMemAccessF(void* userData, UInt32 pa, UInt8 size, Boolean write, void* buf){ + + Pxa255uart* uart = userData; + Boolean DLAB = (uart->LCR & UART_LCR_DLAB) != 0; + Boolean recalcValues = false; + UInt8 t, val = 0; + + if(size != 4 && size != 1) { + err_str(__FILE__ ": Unexpected "); + // err_str(write ? "write" : "read"); + // err_str(" of "); + // err_dec(size); + // err_str(" bytes to 0x"); + // err_hex(pa); + // err_str("\r\n"); + return true; //we do not support non-word accesses + } + + pa = (pa - uart->baseAddr) >> 2; + + if(write){ + recalcValues = true; + val = (size == 1) ? *(UInt8*)buf : *(UInt32*)buf; + + switch(pa){ + case 0: + if(DLAB){ //if DLAB - set "baudrate"... + uart->DLL = val; + recalcValues = false; + } + else{ + + sendVal(uart, val); + } + break; + + case 1: + if(DLAB){ + + uart->DLH = val; + recalcValues = false; + } + else{ + t = uart->IER ^ val; + + if(t & UART_IER_DMAE){ + + err_str("pxa255UART: DMA mode cannot be enabled"); + t &=~ UART_IER_DMAE; //undo the change + } + + if(t & UART_IER_UUE){ + + if(val & UART_IER_UUE){ + + uart->LSR = UART_LSR_TEMT | UART_LSR_TDRQ; + uart->MSR = UART_MSR_CTS; + } + } + + uart->IER ^= t; + } + break; + + case 2: + t = uart->FCR ^ val; + if(t & UART_FCR_TRFIFOE){ + if(val & UART_FCR_TRFIFOE){ //fifos are now on - perform other actions as requested + + if(val & UART_FCR_RESETRF){ + + pxa255uartPrvFifoFlush(&uart->RX); //clear the RX fifo now + } + if(val & UART_FCR_RESETTF){ + + pxa255uartPrvFifoFlush(&uart->TX); //clear the TX fifo now + uart->LSR = UART_LSR_TEMT | UART_LSR_TDRQ; + } + uart->IIR = UART_IIR_FIFOES |UART_IIR_NOINT; + } + else{ + pxa255uartPrvFifoFlush(&uart->TX); + pxa255uartPrvFifoFlush(&uart->RX); + uart->LSR = UART_LSR_TEMT | UART_LSR_TDRQ; + uart->IIR = UART_IIR_NOINT; + } + } + uart->FCR = val; + break; + + case 3: + t = uart->LCR ^ val; + if(t & UART_LCR_SB){ + if(val & UART_LCR_SB){ //break set (tx line pulled low) + + + } + else{ //break cleared (tx line released) + + sendVal(uart, UART_CHAR_BREAK); + } + } + uart->LCR = val; + break; + + case 4: + uart->MCR = val; + break; + + case 7: + uart->SPR = val; + break; + + case 8: + uart->ISR = val; + if(val & 3){ + err_str("UART: IrDA mode set on UART\n"); + } + break; + } + } + else{ + switch(pa){ + case 0: + if(DLAB) val = uart->DLL; + else if(!(uart->LSR & UART_LSR_DR)){ //no data-> too bad + + val = 0; + } + else if(uart->FCR & UART_FCR_TRFIFOE){ //fifo mode -> read fifo + + val = pxa255uartPrvFifoGet(&uart->RX); + if(!pxa255uartPrvFifoUsed(&uart->RX)) uart->LSR &=~ UART_LSR_DR; + recalcValues = true; //error bits might have changed + } + else{ //polled mode -> read rx polled reg + + val = uart->receiveHolding; + uart->LSR &=~ UART_LSR_DR; + } + break; + + case 1: + if(DLAB) val = uart->DLH; + else val = uart->IER; + break; + + case 2: + val = uart->IIR; + break; + + case 3: + val = uart->LCR; + break; + + case 4: + val = uart->MCR; + break; + + case 5: + val = uart->LSR; + break; + + case 6: + val = uart->MSR; + break; + + case 7: + val = uart->SPR; + break; + + case 8: + val = uart->ISR; + break; + } + if(size == 1) *(UInt8*)buf = val; + else *(UInt32*)buf = val; + } + + if(recalcValues) pxa255uartPrvRecalc(uart); + + return true; +} + +void pxa255uartSetFuncs(Pxa255uart* uart, Pxa255UartReadF readF, Pxa255UartWriteF writeF, void* userData){ + + if(!readF) readF = pxa255uartPrvDefaultRead; //these are special funcs since they get their own private data - the uart :) + if(!writeF) writeF = pxa255uartPrvDefaultWrite; + + uart->readF = readF; + uart->writeF = writeF; + uart->accessFuncsData = userData; +} + +Boolean pxa255uartInit(Pxa255uart* uart, ArmMem* physMem, Pxa255ic* ic, UInt32 baseAddr, UInt8 irq){ + + __mem_zero(uart, sizeof(Pxa255uart)); + uart->ic = ic; + uart->irq = irq; + uart->baseAddr = baseAddr; + uart->IIR = UART_IIR_NOINT; + uart->IER = UART_IER_UUE | UART_IER_NRZE; //uart on + uart->LSR = UART_LSR_TEMT | UART_LSR_TDRQ; + uart->MSR = UART_MSR_CTS; + pxa255uartPrvFifoFlush(&uart->TX); + pxa255uartPrvFifoFlush(&uart->RX); + + + pxa255uartSetFuncs(uart, NULL, NULL, NULL); + + return memRegionAdd(physMem, baseAddr, PXA255_UART_SIZE, pxa255uartPrvMemAccessF, uart); +} + +void pxa255uartProcess(Pxa255uart* uart){ //send and rceive up to one character + + UInt8 t; + UInt16 v; + + //first process sending (if any) + if(!(uart->LSR & UART_LSR_TEMT)){ + + pxa255uartPrvPutchar(uart, uart->transmitShift); + + if(uart->FCR & UART_FCR_TRFIFOE){ //fifo mode + + t = pxa255uartPrvFifoUsed(&uart->TX); + + if(t--){ + + uart->transmitShift = pxa255uartPrvFifoGet(&uart->TX); + if(t <= UART_FIFO_DEPTH / 2) uart->LSR |= UART_LSR_TDRQ; //above half full - clear TDRQ bit + } + else{ + + uart->LSR |= UART_LSR_TEMT; + } + } + else if (uart->LSR & UART_LSR_TDRQ){ + + uart->LSR |= UART_LSR_TEMT; + } + else{ + + uart->transmitShift = uart->transmitHolding; + uart->LSR |= UART_LSR_TDRQ; + } + } + + //now process receiving + v = pxa255uartPrvGetchar(uart); + if(v != UART_CHAR_NONE){ + + uart->cyclesSinceRecv = 0; + uart->LSR |= UART_LSR_DR; + + if(uart->FCR & UART_FCR_TRFIFOE){ //fifo mode + + if(!pxa255uartPrvFifoPut(&uart->RX, v)){ + + uart->LSR |= UART_LSR_OE; + } + } + else{ + + if(uart->LSR & UART_LSR_DR) uart->LSR |= UART_LSR_OE; + else uart->receiveHolding = v; + } + } + else if(uart->cyclesSinceRecv <= 4){ + uart->cyclesSinceRecv++; + } + + pxa255uartPrvRecalc(uart); +} + +static void pxa255uartPrvRecalcCharBits(Pxa255uart* uart, UInt16 c){ + + if(c & UART_CHAR_BREAK) uart->LSR |= UART_LSR_BI; + if(c & UART_CHAR_FRAME_ERR) uart->LSR |= UART_LSR_FE; + if(c & UART_CHAR_PAR_ERR) uart->LSR |= UART_LSR_PE; +} + +static void pxa255uartPrvRecalc(Pxa255uart* uart){ + + Boolean errorSet = false; + UInt8 v; + + uart->LSR &=~ UART_LSR_FIFOE; + uart->IIR &= UART_IIR_FIFOES; //clear all other bits... + uart->LSR &=~ (UART_LSR_BI | UART_LSR_FE | UART_LSR_PE); + + if(uart->FCR & UART_FCR_TRFIFOE){ //fifo mode + + + //check rx fifo for errors + for(v = 0; v < pxa255uartPrvFifoUsed(&uart->RX); v++){ + + if((pxa255uartPrvFifoPeekNth(&uart->RX, v) >> 8) && (uart->IER & UART_IER_RLSE)){ + + uart->LSR |= UART_LSR_FIFOE; + uart->IIR |= UART_IIR_RECV_ERR; + errorSet = true; + break; + } + } + + v = pxa255uartPrvFifoUsed(&uart->RX); + if(v){ + pxa255uartPrvRecalcCharBits(uart, pxa255uartPrvFifoPeek(&uart->RX)); + } + + switch(uart->FCR & UART_FCR_ITL_MASK){ + + case UART_FCR_ITL_1: + v = v >= 1; + break; + + case UART_FCR_ITL_8: + v = v >= 8; + break; + + case UART_FCR_ITL_16: + v = v >= 16; + break; + + case UART_FCR_ITL_32: + v = v >= 32; + break; + } + if(v && (uart->IER & UART_IER_RAVIE) && !errorSet){ + + errorSet = true; + uart->IIR |= UART_IIR_RECV_DATA; + } + if(pxa255uartPrvFifoUsed(&uart->RX) && uart->cyclesSinceRecv >= 4 && (uart->IER & UART_IER_RAVIE) && !errorSet){ + + errorSet = true; + uart->IIR |= UART_IIR_RCV_TIMEOUT; + } + } + else{ //polling mode + + UInt16 c = uart->receiveHolding; + + if(uart->LSR & UART_LSR_DR){ + + pxa255uartPrvRecalcCharBits(uart, c); + + if((c >> 8) && !errorSet && (uart->IER & UART_IER_RLSE)){ + + uart->IIR |= UART_IIR_RECV_ERR; + errorSet = true; + } + else if(!errorSet && (uart->IER & UART_IER_RAVIE)){ + + uart->IIR |= UART_IIR_RECV_DATA; + errorSet = true; + } + } + } + + if(uart->LSR & UART_LSR_TDRQ && !errorSet && (uart->IER & UART_IER_TIE)){ + + errorSet = true; + uart->IIR |= UART_IIR_SEND_DATA; + } + + if(!errorSet) uart->IIR |= UART_IIR_NOINT; + pxa255uartPrvIrq(uart, errorSet); +} diff --git a/contrib/other/uarm/pxa255_UART.h b/contrib/other/uarm/pxa255_UART.h new file mode 100755 index 0000000000..8209d181ba --- /dev/null +++ b/contrib/other/uarm/pxa255_UART.h @@ -0,0 +1,88 @@ +#ifndef _PXA255_UART_H_ +#define _PXA255_UART_H_ + +#include "mem.h" +#include "cpu.h" +#include "pxa255_IC.h" + + +/* + PXA255 UARTs + + PXA255 has three. they are identical, but at diff base addresses. this implements one. instanciate more than one of this struct to make all 3 work if needed. + PURRPOSE: this is how linux talks to us :) + + + by default we read nothing and write nowhere (buffer drains fast into nothingness) + this can be changed by addidng appropriate callbacks + +*/ + +#define PXA255_FFUART_BASE 0x40100000UL +#define PXA255_BTUART_BASE 0x40200000UL +#define PXA255_STUART_BASE 0x40700000UL +#define PXA255_UART_SIZE 0x00010000UL + +#define UART_FIFO_DEPTH 64 + + +#define UART_CHAR_BREAK 0x800 +#define UART_CHAR_FRAME_ERR 0x400 +#define UART_CHAR_PAR_ERR 0x200 +#define UART_CHAR_NONE 0x100 + +typedef UInt16 (*Pxa255UartReadF)(void* userData); +typedef void (*Pxa255UartWriteF)(UInt16 chr, void* userData); + +#define UART_FIFO_EMPTY 0xFF + +typedef struct{ + + UInt8 read; + UInt8 write; + UInt16 buf[UART_FIFO_DEPTH]; + +}UartFifo; + +typedef struct{ + + Pxa255ic* ic; + UInt32 baseAddr; + + Pxa255UartReadF readF; + Pxa255UartWriteF writeF; + void* accessFuncsData; + + UartFifo TX, RX; + + UInt16 transmitShift; //char currently "sending" + UInt16 transmitHolding; //holding register for no-fifo mode + + UInt16 receiveHolding; //char just received + + UInt8 irq:5; + UInt8 cyclesSinceRecv:3; + + UInt8 IER; //interrupt enable register + UInt8 IIR; //interrupt information register + UInt8 FCR; //fifo control register + UInt8 LCR; //line control register + UInt8 LSR; //line status register + UInt8 MCR; //modem control register + UInt8 MSR; //modem status register + UInt8 SPR; //scratchpad register + UInt8 DLL; //divisor latch low + UInt8 DLH; //divior latch high; + UInt8 ISR; //infrared selection register + + + +}Pxa255uart; + +Boolean pxa255uartInit(Pxa255uart* uart, ArmMem* physMem, Pxa255ic* ic, UInt32 baseAddr, UInt8 irq); +void pxa255uartProcess(Pxa255uart* uart); //write out data in TX fifo and read data into RX fifo + +void pxa255uartSetFuncs(Pxa255uart* uart, Pxa255UartReadF readF, Pxa255UartWriteF writeF, void* userData); + +#endif + diff --git a/contrib/other/uarm/readme.txt b/contrib/other/uarm/readme.txt new file mode 100755 index 0000000000..fefaebbaef --- /dev/null +++ b/contrib/other/uarm/readme.txt @@ -0,0 +1,12 @@ +uARM emulator. +Port to KolibriOS - SoUrcerer +menuetlibc -> newlibc - maxcodehack + +Build: +make + +Run: +Get image at http://xvilka.me/jaunty.rel.v2.bz2 + +And start: +uARMk jaunty.rel.v2 diff --git a/contrib/other/uarm/rt.c b/contrib/other/uarm/rt.c new file mode 100755 index 0000000000..e629488c28 --- /dev/null +++ b/contrib/other/uarm/rt.c @@ -0,0 +1,51 @@ +#include "types.h" + +void err_hex(UInt32 val){ + + char x[9]; + unsigned char i, c; + + x[8] = 0; + + for(i = 0; i < 8; i++){ + + c = val & 0x0F; + val >>= 4; + c = (c >= 10) ? (c + 'A' - 10) : (c + '0'); + x[7 - i] = c; + } + + err_str(x); +} + +void err_dec(UInt32 val){ + + char x[16]; + unsigned char i, c; + + x[sizeof(x) - 1] = 0; + + for(i = 0; i < sizeof(x) - 1; i++){ + + c = (val % 10) + '0'; + val /= 10; + x[sizeof(x) - 2 - i] = c; + if(!val) break; + } + err_str(x + sizeof(x) - 2 - i); +} + +void __mem_zero(void* ptr, UInt16 sz){ + + UInt8* p = ptr; + + while(sz--) *p++ = 0; +} + +void __mem_copy(void* d_, const void* s_, UInt32 sz){ + + UInt8* d = d_; + const UInt8* s = s_; + + while(sz--) *d++ = *s++; +} \ No newline at end of file diff --git a/contrib/other/uarm/types.h b/contrib/other/uarm/types.h new file mode 100755 index 0000000000..eab36821ac --- /dev/null +++ b/contrib/other/uarm/types.h @@ -0,0 +1,45 @@ +#ifndef _TYPES_H_ +#define _TYPES_H_ + + +typedef unsigned long UInt32; +typedef signed long Int32; +typedef unsigned short UInt16; +typedef signed short Int16; +typedef unsigned char UInt8; +typedef signed char Int8; +typedef unsigned char Err; +typedef unsigned char Boolean; + +#define true 1 +#define false 0 + +#ifndef NULL + #define NULL ((void*)0) +#endif + +#define TYPE_CHECK ((sizeof(UInt32) == 4) && (sizeof(UInt16) == 2) && (sizeof(UInt8) == 1)) + +#define errNone 0x00 +#define errInternal 0x01 + + +#define _INLINE_ inline __attribute__ ((always_inline)) +#define _UNUSED_ __attribute__((unused)) + + +/* runtime stuffs */ +void err_str(const char* str); +void err_hex(UInt32 val); +void err_dec(UInt32 val); +void __mem_zero(void* mem, UInt16 len); +UInt32 rtcCurTime(void); +void* emu_alloc(UInt32 size); +void emu_free(void* ptr); +void __mem_copy(void* d, const void* s, UInt32 sz); + +#define memset __memset_disabled__ +#define memcpy __memcpy_disabled__ + +#endif +