/* *********************************************************************** * * Example implementation for APU API * * $Id: demoapu.c 77044 2016-09-15 14:00:38Z mplichta $ * $LastChangedRevision: 77044 $ * $LastChangedBy: mplichta $ * * (c) Lauterbach GmbH * http://www.lauterbach.com/ * * Description * This example demonstrates the implementation of a Sub Core debugger for * the Infineon PCP Coprocessor found on Infineon TriCore Chips. * It can be compiled and loaded into PowerView, but it is not expected to * work properly. There is no need to make this demo productive since PCP * is already supported by the TriCore debugger. * * Documentation: pdf/api_apu.pdf. * *********************************************************************** */ #include "t32apu.h" static int PcpVersion2; static unsigned int PcpControlMemoryBase; static unsigned int PcpCodeMemoryBase, PcpDataMemoryBase; static unsigned int PcpCodeMemorySize, PcpDataMemorySize; /************************************************************************** PCP state readout **************************************************************************/ static int APUAPI GetStatePcp(apuContext context, apuCallbackStruct * cbs, apuPtr proprietary) { int result; unsigned long pcpcs, pcpes; unsigned char DataBuffer[8]; result = APU_ReadMemory(context, PcpControlMemoryBase + 0x10, 0x40, DataBuffer, 8, 4); if (result != APU_OK) return result; pcpcs = DataBuffer[0] | (DataBuffer[1] << 8) | (DataBuffer[2] << 16) | (DataBuffer[3] << 24); pcpes = DataBuffer[4] | (DataBuffer[5] << 8) | (DataBuffer[6] << 16) | (DataBuffer[7] << 24); if (pcpcs & 0x04) { cbs->x.state.state = APU_STATE_RUNNING; } else if ((pcpes & 0xff) == 0) { cbs->x.state.state = APU_STATE_IDLE; } else { cbs->x.state.state = APU_STATE_STOPPED; cbs->x.state.pc = ((pcpes >> 16) & (PcpCodeMemorySize - 1)) * 2; } return APU_OK; } /************************************************************************** PCP Memory interface **************************************************************************/ static int APUAPI ReadPcpMemory(apuContext context, apuCallbackStruct * cbs, apuPtr proprietary) { if (cbs->x.memory.flags) return APU_ReadMemory(context, PcpCodeMemoryBase + cbs->x.memory.address, 0, cbs->x.memory.data, cbs->x.memory.length, cbs->x.memory.width); else return APU_ReadMemory(context, PcpDataMemoryBase + cbs->x.memory.address, 0, cbs->x.memory.data, cbs->x.memory.length, cbs->x.memory.width); } static int APUAPI WritePcpMemory(apuContext context, apuCallbackStruct * cbs, apuPtr proprietary) { if (cbs->x.memory.flags) return APU_WriteMemory(context, PcpCodeMemoryBase + cbs->x.memory.address, 0, cbs->x.memory.data, cbs->x.memory.length, cbs->x.memory.width); else return APU_WriteMemory(context, PcpDataMemoryBase + cbs->x.memory.address, 0, cbs->x.memory.data, cbs->x.memory.length, cbs->x.memory.width); } static int APUAPI TranslateMemoryAddress(apuContext context, apuCallbackStruct * cbs, apuPtr proprietary) { if (cbs->x.translate.direction) { if (cbs->x.translate.address >= PcpCodeMemoryBase && cbs->x.translate.address < PcpCodeMemoryBase + PcpCodeMemorySize * 2) { cbs->x.translate.address = cbs->x.translate.address - PcpCodeMemoryBase; cbs->x.translate.flags = 1; } else if (cbs->x.translate.address >= PcpDataMemoryBase && cbs->x.translate.address < PcpDataMemoryBase + PcpDataMemorySize * 4) { cbs->x.translate.address = cbs->x.translate.address - PcpDataMemoryBase; cbs->x.translate.flags = 0; } else return APU_FAIL; } else { if (cbs->x.translate.flags) { if (cbs->x.translate.address > PcpCodeMemorySize * 2) return APU_FAIL; cbs->x.translate.address = PcpCodeMemoryBase + cbs->x.translate.address; } else { if (cbs->x.translate.address > PcpDataMemorySize * 4) return APU_FAIL; cbs->x.translate.address = PcpDataMemoryBase + cbs->x.translate.address; } } return APU_OK; } static int OnchipBreakpointSet; static unsigned OnchipBreakpointAddress; static int SetOrClearOnchipBreakpoint(apuContext context, apuCallbackStruct * cbs, apuPtr proprietary) { if (cbs->x.breakpoint.bpid) { /* delete breakpoint */ OnchipBreakpointSet = 0; } else { /* set breakpoint */ if (OnchipBreakpointSet) return APU_OK; /* fail, breakpoint already set */ if (cbs->x.breakpoint.flags) return APU_OK; /* fail, wrong memory class (no breakpoints to code) */ OnchipBreakpointSet = 1; OnchipBreakpointAddress = cbs->x.breakpoint.address; cbs->x.breakpoint.addressto = cbs->x.breakpoint.address; /* shrink down ranges */ cbs->x.breakpoint.bpid = 1; } return APU_OK; } /************************************************************************** PCP Disassembler **************************************************************************/ #define WRITE_MNEMO(str) { static const char cstr[] = str; strcpy(target, cstr); target += strlen(cstr); } static char *condca[] = {"cc_uc", "cc_z", "cc_nz", "cc_v", "cc_ult", "cc_ugt", "cc_slt", "cc_sgt"}; static char *condcb[] = {"cc_uc", "cc_z", "cc_nz", "cc_v", "cc_ult", "cc_ugt", "cc_slt", "cc_sgt", "cc_n", "cc_nn", "cc_nv", "cc_uge", "cc_sge", "cc_sle", "cc_cnz", "cc_cnn" }; #define WRITE_RA() { *target++ = 'r'; *target++ = '0'+((code>>3)&0x07); } #define WRITE_RB() { *target++ = 'r'; *target++ = '0'+((code>>6)&0x07); } #define WRITE_RAC() { WRITE_RA(); *target++ = ','; } #define WRITE_RBC() { WRITE_RB(); *target++ = ','; } #define WRITE_IMM16() { *target++ = '#'; target += hexconvert(target,code2); } #define WRITE_IMM6() { *target++ = '#'; target += hexconvert(target,code&0x3f); } #define WRITE_IMM5() { *target++ = '#'; target += hexconvert(target,code&0x1f); } #define WRITE_IIMM6() { *target++ = '#'; target += hexconvert(target,code&0x3f); } #define WRITE_DISP6() { short disp = code<<10; cbs->x.dis.jumptarget = (address+(disp>>10)); cbs->x.dis.jumptarget &= (PcpCodeMemorySize-1); target += hexconvert(target,cbs->x.dis.jumptarget); } #define WRITE_DISP10() { short disp = code<<6; cbs->x.dis.jumptarget = (address+(disp>>6)); cbs->x.dis.jumptarget &= (PcpCodeMemorySize-1); target += hexconvert(target,cbs->x.dis.jumptarget); } #define WRITE_ADDR16() { cbs->x.dis.jumptarget = code2; cbs->x.dis.jumptarget &= (PcpCodeMemorySize-1); target += hexconvert(target,cbs->x.dis.jumptarget); } #define WRITE_SIZEOPT() { switch (code & 0x03) { case 0: WRITE_MNEMO(",size=8"); break; \ case 1: WRITE_MNEMO(",size=16"); break; \ case 3: WRITE_MNEMO(",size=res"); break; } } #define WRITE_SIZEOPT2() { switch (((code>>8) & 0x02)|((code>>5) & 0x01)) { case 0: WRITE_MNEMO(",size=8"); break; \ case 1: WRITE_MNEMO(",size=16"); break; \ case 3: WRITE_MNEMO(",size=res"); break; } } #define WRITE_CONDCA() { strcpy(target, condca[code&0x07]); target += strlen(target); } #define WRITE_CONDCB() { strcpy(target, condcb[(code>>6)&0x0f]); target += strlen(target); } #define WRITE_CONDCB0() { strcpy(target, condcb[code&0x0f]); target += strlen(target); } static int hexconvert(char * target, int code) { sprintf(target, "%x", code); return strlen(target); } static int APUAPI DisassemblePcp(apuContext context, apuCallbackStruct * cbs, apuPtr proprietary) { char *target; char *comment; unsigned long address; int code, code2; target = cbs->x.dis.mnemo; comment = cbs->x.dis.comment; address = ((cbs->x.dis.address & 0xffff) >> 1) + 1; code = cbs->x.dis.data[0] | (cbs->x.dis.data[1] << 8); code2 = cbs->x.dis.data[2] | (cbs->x.dis.data[3] << 8); switch (code >> 13) { case 0: /* Control1 */ switch ((code >> 11) & 0x03) { case 0: WRITE_MNEMO("nop "); break; case 1: WRITE_MNEMO("copy "); goto iscopy; case 3: WRITE_MNEMO("bcopy "); iscopy: switch ((code >> 9) & 0x03) { case 0: WRITE_MNEMO("DST,"); break; case 1: WRITE_MNEMO("DST+,"); break; case 2: WRITE_MNEMO("DST-,"); break; default: WRITE_MNEMO("res,"); break; } switch ((code >> 7) & 0x03) { case 0: WRITE_MNEMO("SRC,"); break; case 1: WRITE_MNEMO("SRC+,"); break; case 2: WRITE_MNEMO("SRC-,"); break; default: WRITE_MNEMO("res,"); break; } switch ((code >> 5) & 0x03) { case 0: WRITE_MNEMO("CNC=0,"); break; case 1: WRITE_MNEMO("CNC=1,"); break; case 2: WRITE_MNEMO("CNC=2,"); break; default: WRITE_MNEMO("CNC=3,"); break; } WRITE_MNEMO("CNT0="); *target++ = '0' + ((code >> 2) & 0x07); WRITE_SIZEOPT(); break; case 2: WRITE_MNEMO("exit "); if (code & 0x80) { WRITE_MNEMO("EC=1,"); } else { WRITE_MNEMO("EC=0,"); } if (code & 0x400) { WRITE_MNEMO("ST=1,"); } else { WRITE_MNEMO("ST=0,"); } if (code & 0x200) { WRITE_MNEMO("INT=1,"); } else { WRITE_MNEMO("INT=0,"); } if (code & 0x100) { WRITE_MNEMO("EP=1"); } else { WRITE_MNEMO("EP=0"); } if (PcpVersion2) { WRITE_MNEMO(","); WRITE_CONDCB0(); } break; } break; case 1: /* FPI */ switch ((code >> 9) & 0x0f) { case 0: WRITE_MNEMO("add.f "); break; case 1: WRITE_MNEMO("sub.f "); break; case 2: WRITE_MNEMO("comp.f "); break; case 5: WRITE_MNEMO("and.f "); break; case 7: WRITE_MNEMO("or.f "); break; case 8: WRITE_MNEMO("xor.f "); break; case 9: WRITE_MNEMO("ld.f "); break; case 10: WRITE_MNEMO("st.f "); break; case 11: WRITE_MNEMO("xch.f "); break; default: goto undef; } WRITE_RBC(); WRITE_RA(); WRITE_SIZEOPT(); break; case 2: /* PRAM */ switch ((code >> 9) & 0x0f) { case 0: WRITE_MNEMO("add.pi "); break; case 1: WRITE_MNEMO("sub.pi "); break; case 2: WRITE_MNEMO("comp.pi "); break; case 4: WRITE_MNEMO("mclr.pi "); break; case 5: WRITE_MNEMO("and.pi "); break; case 6: WRITE_MNEMO("mset.pi "); break; case 7: WRITE_MNEMO("or.pi "); break; case 8: WRITE_MNEMO("xor.pi "); break; case 9: WRITE_MNEMO("ld.pi "); break; case 10: WRITE_MNEMO("st.pi "); break; case 11: WRITE_MNEMO("xch.pi "); break; default: goto undef; } WRITE_RBC(); WRITE_IIMM6(); break; case 3: /* Arithmetic */ switch ((code >> 9) & 0x0f) { case 0: WRITE_MNEMO("add "); break; case 1: WRITE_MNEMO("sub "); break; case 2: WRITE_MNEMO("comp "); break; case 3: WRITE_MNEMO("neg "); break; case 4: WRITE_MNEMO("not "); break; case 5: WRITE_MNEMO("and "); break; case 7: WRITE_MNEMO("or "); break; case 8: WRITE_MNEMO("xor "); break; case 9: WRITE_MNEMO("ld.p "); break; case 10: WRITE_MNEMO("st.p "); break; case 12: WRITE_MNEMO("mov "); break; case 13: WRITE_MNEMO("inb "); break; case 14: WRITE_MNEMO("pri "); break; default: goto undef; } WRITE_RBC(); WRITE_RAC(); WRITE_CONDCA(); break; case 4: /* Immediate */ switch ((code >> 9) & 0x0f) { case 0: WRITE_MNEMO("add.i "); break; case 1: WRITE_MNEMO("sub.i "); break; case 2: WRITE_MNEMO("comp.i "); break; case 4: WRITE_MNEMO("shr "); break; case 5: WRITE_MNEMO("shl "); break; case 6: WRITE_MNEMO("rr "); break; case 7: WRITE_MNEMO("rl "); break; case 8: WRITE_MNEMO("ldl.iu "); WRITE_RBC(); WRITE_IMM16(); *target = '\0'; goto twowordend; case 9: WRITE_MNEMO("ldl.il "); WRITE_RBC(); WRITE_IMM16(); *target = '\0'; goto twowordend; case 10: WRITE_MNEMO("set "); goto bitops; case 11: WRITE_MNEMO("clr "); goto bitops; case 12: WRITE_MNEMO("ld.i "); break; case 13: WRITE_MNEMO("inb.i "); goto bitops; case 14: WRITE_MNEMO("chkb "); goto bitops; default: goto undef; } WRITE_RBC(); WRITE_IMM6(); break; bitops: WRITE_RBC(); WRITE_IMM6(); break; case 5: /* FPI Immediate */ switch ((code >> 10) & 0x07) { case 3: WRITE_MNEMO("set.f "); break; case 4: WRITE_MNEMO("clr.f "); break; case 5: WRITE_MNEMO("ld.if "); break; case 6: WRITE_MNEMO("st.if "); break; default: goto undef; } WRITE_RBC(); WRITE_IMM5(); WRITE_SIZEOPT2(); break; case 6: /* Complex Math */ switch ((code >> 9) & 0x0f) { case 0: WRITE_MNEMO("dinit "); break; case 1: WRITE_MNEMO("dstep "); break; case 2: WRITE_MNEMO("minit "); break; case 3: WRITE_MNEMO("mstep.l "); break; case 4: WRITE_MNEMO("mstep.u "); break; default: goto undef; } WRITE_RBC(); WRITE_RA(); break; case 7: /* Jump */ switch ((code >> 10) & 0x07) { case 0: WRITE_MNEMO("jl "); WRITE_DISP10(); cbs->x.dis.jumpflag = APU_JMPFLG_DIRECT; break; case 1: WRITE_MNEMO("jc "); WRITE_DISP6(); *target++ = ','; WRITE_CONDCB(); cbs->x.dis.jumpflag = APU_JMPFLG_DIRECTCOND; break; case 2: WRITE_MNEMO("jc.a "); WRITE_ADDR16(); *target++ = ','; WRITE_CONDCB(); cbs->x.dis.jumpflag = APU_JMPFLG_DIRECTCOND; goto twowordend; case 4: WRITE_MNEMO("jc.i "); WRITE_RAC(); WRITE_CONDCB(); cbs->x.dis.jumpflag = APU_JMPFLG_INDIRECTCOND; break; case 5: WRITE_MNEMO("jc.ia "); WRITE_RAC(); WRITE_CONDCB(); cbs->x.dis.jumpflag = APU_JMPFLG_INDIRECTCOND; break; case 7: WRITE_MNEMO("debug "); if (code & 0x002) { WRITE_MNEMO("EDA=1,"); } else { WRITE_MNEMO("EDA=0,"); } if (code & 0x001) { WRITE_MNEMO("SDB=1"); } else { WRITE_MNEMO("SDB=0"); } *target++ = ','; WRITE_CONDCB(); break; default: goto undef; } break; default: goto undef; } *target = '\0'; cbs->x.dis.jumptarget = cbs->x.dis.jumptarget * 2; cbs->x.dis.instlen = 2; return APU_OK; twowordend: *target = '\0'; cbs->x.dis.jumptarget = cbs->x.dis.jumptarget * 2; cbs->x.dis.instlen = 4; return APU_OK; undef: return APU_FAIL; } /************************************************************************** Entry point of APU **************************************************************************/ int APUAPI APU_Init(apuContext context, apuCallbackStruct * cbs) { static const unsigned char softbreakcode[] = { 0x03, 0xfc }; strcpy(cbs->x.init.modelname, __DATE__ " APU Demo"); if (cbs->x.init.argc != 3) { APU_Warning(context, "parameters: "); return APU_FAIL; } /* extract parameters for APU load command */ PcpCodeMemoryBase = cbs->x.init.argpaddress[1]; PcpDataMemoryBase = cbs->x.init.argpaddress[2]; PcpCodeMemorySize = 0x1000; PcpDataMemorySize = 0x1000; /* define APU architecture parameters */ APU_DefineEndianess(context, APU_ENDIANESS_LITTLE); /* little endian core */ APU_DefineMemory(context, 0, "D", 4, 4); /* D: access is 32bit wide addressed */ APU_DefineMemory(context, 1, "P", 2, 2); /* P: access is 16bit wide addressed */ /* translation of memory addresses vs APU addresses (optional) */ APU_RegisterTranslateCallback(context, TranslateMemoryAddress, 0); /* define software breakpoint code (optional) */ APU_DefineSoftbreak(context, 2, softbreakcode); /* opcode for software breakpoint is 2 byte */ /* get core state function */ APU_RegisterGetStateCallback(context, GetStatePcp, 0); /* memory access callback function */ APU_RegisterMemoryReadCallback(context, ReadPcpMemory, 0); APU_RegisterMemoryWriteCallback(context, WritePcpMemory, 0); /* disassembler callback function */ APU_RegisterDisassemblerCallback(context, DisassemblePcp, 0, 2, 4); /* 16 or 32 bit instructions */ /* onchip breakpoint support (optional) */ APU_RegisterBreakpointCallback(context, SetOrClearOnchipBreakpoint, 0, (APU_BPTYPE_READ | APU_BPTYPE_WRITE)); return APU_OK; }