forked from KolibriOS/kolibrios
Upload uARM emulator (linux4kolibri)
git-svn-id: svn://kolibrios.org@8327 a494cfbc-eb01-0410-851d-a64ba20cac60
This commit is contained in:
parent
f1979bad47
commit
a03882245a
2736
contrib/other/uarm/CPU.c
Executable file
2736
contrib/other/uarm/CPU.c
Executable file
File diff suppressed because it is too large
Load Diff
173
contrib/other/uarm/CPU.h
Executable file
173
contrib/other/uarm/CPU.h
Executable file
@ -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
|
||||||
|
|
454
contrib/other/uarm/MMU.c
Executable file
454
contrib/other/uarm/MMU.c
Executable file
@ -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
|
||||||
|
}
|
64
contrib/other/uarm/MMU.h
Executable file
64
contrib/other/uarm/MMU.h
Executable file
@ -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
|
||||||
|
|
20
contrib/other/uarm/Makefile
Executable file
20
contrib/other/uarm/Makefile
Executable file
@ -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 $@ $<
|
113
contrib/other/uarm/RAM.c
Executable file
113
contrib/other/uarm/RAM.c
Executable file
@ -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);
|
||||||
|
}
|
24
contrib/other/uarm/RAM.h
Executable file
24
contrib/other/uarm/RAM.h
Executable file
@ -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
|
||||||
|
|
776
contrib/other/uarm/SoC.c
Executable file
776
contrib/other/uarm/SoC.c
Executable file
@ -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
|
121
contrib/other/uarm/SoC.h
Executable file
121
contrib/other/uarm/SoC.h
Executable file
@ -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
|
||||||
|
|
16
contrib/other/uarm/callout_RAM.c
Executable file
16
contrib/other/uarm/callout_RAM.c
Executable file
@ -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);
|
||||||
|
}
|
24
contrib/other/uarm/callout_RAM.h
Executable file
24
contrib/other/uarm/callout_RAM.h
Executable file
@ -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
|
||||||
|
|
141
contrib/other/uarm/console_obj.h
Executable file
141
contrib/other/uarm/console_obj.h
Executable file
@ -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
|
186
contrib/other/uarm/cp15.c
Executable file
186
contrib/other/uarm/cp15.c
Executable file
@ -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;
|
||||||
|
}
|
27
contrib/other/uarm/cp15.h
Executable file
27
contrib/other/uarm/cp15.h
Executable file
@ -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
|
||||||
|
|
173
contrib/other/uarm/cpu.h
Executable file
173
contrib/other/uarm/cpu.h
Executable file
@ -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
|
||||||
|
|
155
contrib/other/uarm/dcache.c
Executable file
155
contrib/other/uarm/dcache.c
Executable file
@ -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;
|
||||||
|
}
|
||||||
|
|
49
contrib/other/uarm/dcache.h
Executable file
49
contrib/other/uarm/dcache.h
Executable file
@ -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
|
140
contrib/other/uarm/icache.c
Executable file
140
contrib/other/uarm/icache.c
Executable file
@ -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;
|
||||||
|
}
|
||||||
|
|
47
contrib/other/uarm/icache.h
Executable file
47
contrib/other/uarm/icache.h
Executable file
@ -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
|
250
contrib/other/uarm/main_pc.c
Executable file
250
contrib/other/uarm/main_pc.c
Executable file
@ -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);
|
||||||
|
}
|
||||||
|
|
197
contrib/other/uarm/math64.c
Executable file
197
contrib/other/uarm/math64.c
Executable file
@ -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
|
64
contrib/other/uarm/math64.h
Executable file
64
contrib/other/uarm/math64.h
Executable file
@ -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
|
||||||
|
|
||||||
|
|
96
contrib/other/uarm/mem.c
Executable file
96
contrib/other/uarm/mem.c
Executable file
@ -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;
|
||||||
|
}
|
||||||
|
|
38
contrib/other/uarm/mem.h
Executable file
38
contrib/other/uarm/mem.h
Executable file
@ -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
|
116
contrib/other/uarm/pxa255_DMA.c
Executable file
116
contrib/other/uarm/pxa255_DMA.c
Executable file
@ -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);
|
||||||
|
}
|
42
contrib/other/uarm/pxa255_DMA.h
Executable file
42
contrib/other/uarm/pxa255_DMA.h
Executable file
@ -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
|
||||||
|
|
81
contrib/other/uarm/pxa255_DSP.c
Executable file
81
contrib/other/uarm/pxa255_DSP.c
Executable file
@ -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;
|
||||||
|
}
|
20
contrib/other/uarm/pxa255_DSP.h
Executable file
20
contrib/other/uarm/pxa255_DSP.h
Executable file
@ -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
|
206
contrib/other/uarm/pxa255_GPIO.c
Executable file
206
contrib/other/uarm/pxa255_GPIO.c
Executable file
@ -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;
|
||||||
|
}
|
47
contrib/other/uarm/pxa255_GPIO.h
Executable file
47
contrib/other/uarm/pxa255_GPIO.h
Executable file
@ -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
|
||||||
|
|
104
contrib/other/uarm/pxa255_IC.c
Executable file
104
contrib/other/uarm/pxa255_IC.c
Executable file
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
64
contrib/other/uarm/pxa255_IC.h
Executable file
64
contrib/other/uarm/pxa255_IC.h
Executable file
@ -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
|
||||||
|
|
454
contrib/other/uarm/pxa255_LCD.c
Executable file
454
contrib/other/uarm/pxa255_LCD.c
Executable file
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
63
contrib/other/uarm/pxa255_LCD.h
Executable file
63
contrib/other/uarm/pxa255_LCD.h
Executable file
@ -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
|
||||||
|
|
154
contrib/other/uarm/pxa255_PwrClk.c
Executable file
154
contrib/other/uarm/pxa255_PwrClk.c
Executable file
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
32
contrib/other/uarm/pxa255_PwrClk.h
Executable file
32
contrib/other/uarm/pxa255_PwrClk.h
Executable file
@ -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
|
101
contrib/other/uarm/pxa255_RTC.c
Executable file
101
contrib/other/uarm/pxa255_RTC.c
Executable file
@ -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);
|
||||||
|
}
|
37
contrib/other/uarm/pxa255_RTC.h
Executable file
37
contrib/other/uarm/pxa255_RTC.h
Executable file
@ -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
|
||||||
|
|
123
contrib/other/uarm/pxa255_TIMR.c
Executable file
123
contrib/other/uarm/pxa255_TIMR.c
Executable file
@ -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);
|
||||||
|
}
|
37
contrib/other/uarm/pxa255_TIMR.h
Executable file
37
contrib/other/uarm/pxa255_TIMR.h
Executable file
@ -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
|
||||||
|
|
588
contrib/other/uarm/pxa255_UART.c
Executable file
588
contrib/other/uarm/pxa255_UART.c
Executable file
@ -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);
|
||||||
|
}
|
88
contrib/other/uarm/pxa255_UART.h
Executable file
88
contrib/other/uarm/pxa255_UART.h
Executable file
@ -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
|
||||||
|
|
12
contrib/other/uarm/readme.txt
Executable file
12
contrib/other/uarm/readme.txt
Executable file
@ -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
|
51
contrib/other/uarm/rt.c
Executable file
51
contrib/other/uarm/rt.c
Executable file
@ -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++;
|
||||||
|
}
|
45
contrib/other/uarm/types.h
Executable file
45
contrib/other/uarm/types.h
Executable file
@ -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
|
||||||
|
|
Loading…
Reference in New Issue
Block a user