Subversion Repositories Kolibri OS

Compare Revisions

No changes between revisions

Regard whitespace Rev 8326 → Rev 8327

/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
 
Property changes:
Added: svn:executable
+*
\ No newline at end of property
/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
 
Property changes:
Added: svn:executable
+*
\ No newline at end of property
/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
}
Property changes:
Added: svn:executable
+*
\ No newline at end of property
/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
 
Property changes:
Added: svn:executable
+*
\ No newline at end of property
/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 $@ $<
Property changes:
Added: svn:executable
+*
\ No newline at end of property
/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);
}
Property changes:
Added: svn:executable
+*
\ No newline at end of property
/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
 
Property changes:
Added: svn:executable
+*
\ No newline at end of property
/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 <avr/io.h>
#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 <sys/socket.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/select.h>
#include <unistd.h>
#include <errno.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <string.h>
#include <stdio.h>
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
Property changes:
Added: svn:executable
+*
\ No newline at end of property
/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
 
Property changes:
Added: svn:executable
+*
\ No newline at end of property
/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);
}
Property changes:
Added: svn:executable
+*
\ No newline at end of property
/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
 
Property changes:
Added: svn:executable
+*
\ No newline at end of property
/contrib/other/uarm/console_obj.h
0,0 → 1,141
// Console.obj loading for kos32-gcc
// Writed by rgimad and maxcodehack
 
#include <string.h>
#include <stdlib.h>
 
#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
Property changes:
Added: svn:executable
+*
\ No newline at end of property
/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;
}
Property changes:
Added: svn:executable
+*
\ No newline at end of property
/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
 
Property changes:
Added: svn:executable
+*
\ No newline at end of property
/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
 
Property changes:
Added: svn:executable
+*
\ No newline at end of property
/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;
}
 
Property changes:
Added: svn:executable
+*
\ No newline at end of property
/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
Property changes:
Added: svn:executable
+*
\ No newline at end of property
/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;
}
 
Property changes:
Added: svn:executable
+*
\ No newline at end of property
/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
Property changes:
Added: svn:executable
+*
\ No newline at end of property
/contrib/other/uarm/main_pc.c
0,0 → 1,250
#include "SoC.h"
 
#include <sys/time.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>
//#include <sys/select.h>
#include <signal.h>
//#include <termios.h>
#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);
}
 
Property changes:
Added: svn:executable
+*
\ No newline at end of property
/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
Property changes:
Added: svn:executable
+*
\ No newline at end of property
/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
 
 
Property changes:
Added: svn:executable
+*
\ No newline at end of property
/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;
}
 
Property changes:
Added: svn:executable
+*
\ No newline at end of property
/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
Property changes:
Added: svn:executable
+*
\ No newline at end of property
/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);
}
Property changes:
Added: svn:executable
+*
\ No newline at end of property
/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
 
Property changes:
Added: svn:executable
+*
\ No newline at end of property
/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;
}
Property changes:
Added: svn:executable
+*
\ No newline at end of property
/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
Property changes:
Added: svn:executable
+*
\ No newline at end of property
/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;
}
Property changes:
Added: svn:executable
+*
\ No newline at end of property
/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
 
Property changes:
Added: svn:executable
+*
\ No newline at end of property
/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);
}
}
 
 
 
 
 
Property changes:
Added: svn:executable
+*
\ No newline at end of property
/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 <stdio.h>
 
/*
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
 
Property changes:
Added: svn:executable
+*
\ No newline at end of property
/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 <stdio.h>
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);
}
 
 
 
 
 
Property changes:
Added: svn:executable
+*
\ No newline at end of property
/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
 
Property changes:
Added: svn:executable
+*
\ No newline at end of property
/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;
}
 
 
Property changes:
Added: svn:executable
+*
\ No newline at end of property
/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
Property changes:
Added: svn:executable
+*
\ No newline at end of property
/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);
}
Property changes:
Added: svn:executable
+*
\ No newline at end of property
/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
 
Property changes:
Added: svn:executable
+*
\ No newline at end of property
/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);
}
Property changes:
Added: svn:executable
+*
\ No newline at end of property
/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
 
Property changes:
Added: svn:executable
+*
\ No newline at end of property
/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);
}
Property changes:
Added: svn:executable
+*
\ No newline at end of property
/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
 
Property changes:
Added: svn:executable
+*
\ No newline at end of property
/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
Property changes:
Added: svn:executable
+*
\ No newline at end of property
/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++;
}
Property changes:
Added: svn:executable
+*
\ No newline at end of property
/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
 
Property changes:
Added: svn:executable
+*
\ No newline at end of property