Upload uARM emulator (linux4kolibri)

git-svn-id: svn://kolibrios.org@8327 a494cfbc-eb01-0410-851d-a64ba20cac60
This commit is contained in:
maxcodehack 2020-12-05 14:28:30 +00:00
parent f1979bad47
commit a03882245a
45 changed files with 8549 additions and 0 deletions

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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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

View 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);
}

View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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;
}

View 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
View 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
View 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
View 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
View 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

View 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;
}

View 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
View 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
View 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
View 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);
}

View 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
View 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);
}

View 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
View 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
View 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
View 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