📄 cpu.c
字号:
/* * Softcam plugin to VDR (C++) * * This code is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This code is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * Or, point your browser to http://www.gnu.org/copyleft/gpl.html */#include <stdio.h>#include <stdlib.h>#include <string.h>#include "data.h"#include "cpu.h"#include "log-nagra.h"#define LOGLBPUT(t...) loglb->Printf(t)#define CCLOGLBPUT(t...) do { if(doDisAsm) loglb->Printf(t); } while(0)// -- cMapMem ------------------------------------------------------------------cMapMem::cMapMem(unsigned short Offset, int Size){ offset=Offset; size=Size; if((mem=(unsigned char *)malloc(size))) memset(mem,0,size); PRINTF(L_SYS_EMU,"mapmem: new map off=%04x size=%04x",offset,size);}cMapMem::~cMapMem(){ free(mem);}bool cMapMem::IsFine(void){ return (mem!=0);}unsigned char cMapMem::Get(unsigned short ea){ return (ea>=offset && ea<offset+size) ? mem[ea-offset] : 0;}void cMapMem::Set(unsigned short ea, unsigned char val){ if(ea>=offset && ea<offset+size) mem[ea-offset]=val;}// -- cMapRom ------------------------------------------------------------------cMapRom::cMapRom(unsigned short Offset, const char *Filename, int InFileOffset){ offset=Offset; addr=0; fm=filemaps.GetFileMap(Filename,FILEMAP_DOMAIN,false); if(fm && fm->Map()) { addr=fm->Addr()+InFileOffset; size=fm->Size()-InFileOffset; PRINTF(L_SYS_EMU,"maprom: new map off=%04x size=%04x",offset,size); }}cMapRom::~cMapRom(){ if(fm) fm->Unmap();}bool cMapRom::IsFine(void){ return (addr!=0);}unsigned char cMapRom::Get(unsigned short ea){ return (ea>=offset && ea<offset+size) ? addr[ea-offset] : 0;}void cMapRom::Set(unsigned short ea, unsigned char val){ if(ea>=offset && ea<offset+size) LOGLBPUT("[ROM] "); // this is a ROM!}// -- cMapEeprom ---------------------------------------------------------------cMapEeprom::cMapEeprom(unsigned short Offset, const char *Filename, int OtpSize, int InFileOffset){ offset=Offset; otpSize=OtpSize; addr=0; fm=filemaps.GetFileMap(Filename,FILEMAP_DOMAIN,true); if(fm && fm->Map()) { addr=fm->Addr()+InFileOffset; size=fm->Size()-InFileOffset; PRINTF(L_SYS_EMU,"mapeeprom: new map off=%04x size=%04x otp=%04x",offset,size,otpSize); }}cMapEeprom::~cMapEeprom(){ if(fm) fm->Unmap();}bool cMapEeprom::IsFine(void){ return (addr!=0);}unsigned char cMapEeprom::Get(unsigned short ea){ return (ea>=offset && ea<offset+size) ? addr[ea-offset] : 0;}void cMapEeprom::Set(unsigned short ea, unsigned char val){ if(ea>=offset && ea<offset+otpSize) { if(addr[ea-offset]==0) { addr[ea-offset]=val; LOGLBPUT("[OTP-SET] "); } LOGLBPUT("[OTP] "); } if(ea>=offset+otpSize && ea<offset+size) { addr[ea-offset]=val; LOGLBPUT("[EEP] "); }}// -- c6805 --------------------------------------------------------------------#define HILO(ea) ((Get(ea)<<8)+Get((ea)+1))#define HILOS(s,ea) ((Get((s),(ea))<<8)+Get((s),(ea)+1))#define PAGEOFF(ea,s) (((ea)&0x8000) ? pageMap[s]:0)c6805::c6805(void) { cc.c=0; cc.z=0; cc.n=0; cc.i=0; cc.h=0; cc.v=1; pc=0; a=0; x=0; y=0; cr=dr=0; sp=spHi=0x100; spLow=0xC0; ClearBreakpoints(); InitMapper(); memset(stats,0,sizeof(stats)); loglb=new cLineBuff(128);}c6805::~c6805(){ if(LOG(L_SYS_CPUSTATS)) { int i, j, sort[256]; for(i=0; i<256; i++) sort[i]=i; for(i=0; i<256; i++) for(j=0; j<255; j++) if(stats[sort[j]]<stats[sort[j+1]]) { int x=sort[j]; sort[j]=sort[j+1]; sort[j+1]=x; } PRINTF(L_SYS_CPUSTATS,"opcode statistics"); for(i=0; i<256; i++) if((j=stats[sort[i]])) PRINTF(L_SYS_CPUSTATS,"opcode %02x: %d",sort[i],j); } ClearMapper(); delete loglb;}bool c6805::AddMapper(cMap *map, unsigned short start, int size, unsigned char seg){ if(map && map->IsFine()) { if(nextMapper<MAX_MAPPER) { map->loglb=loglb; mapper[nextMapper]=map; memset(&mapMap[start+PAGEOFF(start,seg)],nextMapper,size); nextMapper++; return true; } else PRINTF(L_SYS_EMU,"6805: too many mappers"); } else PRINTF(L_SYS_EMU,"6805: mapper not ready"); delete map; return false;}void c6805::ResetMapper(void){ ClearMapper(); InitMapper();}void c6805::InitMapper(void){ memset(mapMap,0,sizeof(mapMap)); memset(mapper,0,sizeof(mapper)); mapper[0]=new cMapMem(0,PAGE_SIZE*2); nextMapper=1; memset(pageMap,0,sizeof(pageMap)); pageMap[0]=PAGE_SIZE*0; pageMap[1]=PAGE_SIZE*1; pageMap[2]=PAGE_SIZE*2; pageMap[0x80]=PAGE_SIZE*3;}void c6805::ClearMapper(void){ for(int i=0; i<MAX_MAPPER; i++) delete mapper[i];}unsigned char c6805::Get(unsigned short ea) const{ return mapper[mapMap[ea+PAGEOFF(ea,cr)]&0x7f]->Get(ea);}unsigned char c6805::Get(unsigned char seg, unsigned short ea) const{ return mapper[mapMap[ea+PAGEOFF(ea,seg)]&0x7f]->Get(ea);}void c6805::Set(unsigned short ea, unsigned char val){ unsigned char mapId=mapMap[ea+PAGEOFF(ea,cr)]; if(!(mapId&0x80)) mapper[mapId&0x7f]->Set(ea,val);}void c6805::Set(unsigned char seg, unsigned short ea, unsigned char val){ unsigned char mapId=mapMap[ea+PAGEOFF(ea,seg)]; if(!(mapId&0x80)) mapper[mapId&0x7f]->Set(ea,val);}void c6805::ForceSet(unsigned short ea, unsigned char val, bool ro){ mapMap[ea]=0; // reset to RAM map Set(0,ea,val); // set value if(ro) mapMap[ea]|=0x80; // protect byte}void c6805::SetMem(unsigned short addr, const unsigned char *data, int len, unsigned char seg){ while(len>0) { Set(seg,addr++,*data++); len--; }}void c6805::GetMem(unsigned short addr, unsigned char *data, int len, unsigned char seg) const{ while(len>0) { *data++=Get(seg,addr++); len--; }}void c6805::SetSp(unsigned short SpHi, unsigned short SpLow){ spHi =sp=SpHi; spLow =SpLow;}void c6805::SetPc(unsigned short addr){ pc=addr;}void c6805::PopPc(void){ poppc();}void c6805::PopCr(void){ cr=pop();}void c6805::AddBreakpoint(unsigned short addr){ if(numBp<MAX_BREAKPOINTS) { bp[numBp++]=addr; PRINTF(L_SYS_EMU,"6805: setting breakpoint at 0x%04x",addr); } else PRINTF(L_SYS_EMU,"6805: too many breakpoints");}void c6805::ClearBreakpoints(void){ numBp=0; memset(bp,0,sizeof(bp));}static const char * const ops[] = {// 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0a 0x0b 0x0c 0x0d 0x0e 0x0f/* 0x00 */ "BRSET","BRCLR","BRSET","BRCLR","BRSET","BRCLR","BRSET","BRCLR","BRSET","BRCLR","BRSET","BRCLR","BRSET","BRCLR","BRSET","BRCLR",/* 0x10 */ "BSET", "BCLR", "BSET", "BCLR", "BSET", "BCLR", "BSET", "BCLR", "BSET", "BCLR", "BSET", "BCLR", "BSET", "BCLR", "BSET", "BCLR",/* 0x20 */ "BRA", "BRN", "BHI", "BLS", "BCC", "BCS", "BNE", "BEQ", "BHCC", "BHCS", "BPL", "BMI", "BMC", "BMS", "BIL", "BIH",/* 0x30 */ "NEG", "pre31","pre32","COM", "LSR", "op35", "ROR", "ASR", "ASL", "ROL", "DEC", "op3b", "INC", "TST", "SWAP", "CLR",/* 0x40 */ "NEG", "op41", "MUL", "COM", "LSR", "op45", "ROR", "ASR", "ASL", "ROL", "DEC", "op4b", "INC", "TST", "SWAP", "CLR",/* 0x50 */ "NEG", "op51", "MUL", "COM", "LSR", "op55", "ROR", "ASR", "ASL", "ROL", "DEC", "op5b", "INC", "TST", "SWAP", "CLR",/* 0x60 */ "NEG", "op61", "op62", "COM", "LSR", "op65", "ROR", "ASR", "ASL", "ROL", "DEC", "op6b", "INC", "TST", "SWAP", "CLR",/* 0x70 */ "NEG", "LDD", "LDD", "COM", "LSR", "LDD", "ROR", "ASR", "ASL", "ROL", "DEC", "TAD", "INC", "TST", "SWAP", "CLR",/* 0x80 */ "RTI", "RTS", "op82", "SWI", "POPA", "POP%c","POPC", "PRTS", "PUSHA","PUSH%c","PUSHC","TDA", "TCA", "PJSR", "STOP", "WAIT",/* 0x90 */ "pre90","pre91","pre92","T%2$c%1$c","T%cS","TAS","TS%c","TA%c", "CLC", "SEC", "CLI", "SEI", "RSP", "NOP", "TSA", "T%cA",/* 0xa0 */ "SUB", "CMP", "SBC", "CP%c", "AND", "BIT", "LDA", "opa7", "EOR", "ADC", "ORA", "ADD", "PUSHD","BSR", "LD%c", "POPD",/* 0xb0 */ "SUB", "CMP", "SBC", "CP%c", "AND", "BIT", "LDA", "STA", "EOR", "ADC", "ORA", "ADD", "JMP", "JSR", "LD%c", "ST%c",/* 0xc0 */ "SUB", "CMP", "SBC", "CP%c", "AND", "BIT", "LDA", "STA", "EOR", "ADC", "ORA", "ADD", "JMP", "JSR", "LD%c", "ST%c",/* 0xd0 */ "SUB", "CMP", "SBC", "CP%c", "AND", "BIT", "LDA", "STA", "EOR", "ADC", "ORA", "ADD", "JMP", "JSR", "LD%c", "ST%c",/* 0xe0 */ "SUB", "CMP", "SBC", "CP%c", "AND", "BIT", "LDA", "STA", "EOR", "ADC", "ORA", "ADD", "JMP", "JSR", "LD%c", "ST%c",/* 0xf0 */ "SUB", "CMP", "SBC", "CP%c", "AND", "BIT", "LDA", "STA", "EOR", "ADC", "ORA", "ADD", "JMP", "JSR", "LD%c", "ST%c", };static const char * const vops[] = { "BVGT","BVLE","BVGE","BVLT","BVC","BVS" };// Flags:// 1 - read operant// 2 - write operant// 4 - use dr register// 8 - special address mode in high nibblestatic const char opFlags[] = {// 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f/* 0x00 */ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,/* 0x10 */ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,/* 0x20 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,/* 0x30 */ 0x03, 0x00, 0x00, 0x03, 0x03, 0x00, 0x03, 0x03, 0x03, 0x03, 0x03, 0x00, 0x03, 0x01, 0x03, 0x02,/* 0x40 */ 0x03, 0x00, 0x00, 0x03, 0x03, 0x00, 0x03, 0x03, 0x03, 0x03, 0x03, 0x00, 0x03, 0x01, 0x03, 0x02,/* 0x50 */ 0x03, 0x00, 0x00, 0x03, 0x03, 0x00, 0x03, 0x03, 0x03, 0x03, 0x03, 0x00, 0x03, 0x01, 0x03, 0x02,/* 0x60 */ 0x03, 0x00, 0x00, 0x03, 0x03, 0x00, 0x03, 0x03, 0x03, 0x03, 0x03, 0x00, 0x03, 0x01, 0x03, 0x02,/* 0x70 */ 0x03, 0xA9, 0xB9, 0x03, 0x03, 0xC9, 0x03, 0x03, 0x03, 0x03, 0x03, 0x88, 0x03, 0x01, 0x03, 0x02,/* 0x80 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,/* 0x90 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,/* 0xa0 */ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x88, 0x88, 0x01, 0x88,/* 0xb0 */ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x01, 0x02,/* 0xc0 */ 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x06, 0x05, 0x05, 0x05, 0x05, 0x00, 0x00, 0x05, 0x06,/* 0xd0 */ 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x06, 0x05, 0x05, 0x05, 0x05, 0x00, 0x00, 0x05, 0x06,/* 0xe0 */ 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x06, 0x05, 0x05, 0x05, 0x05, 0x00, 0x00, 0x05, 0x06,/* 0xf0 */ 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x06, 0x05, 0x05, 0x05, 0x05, 0x00, 0x00, 0x05, 0x06, };char * c6805::PADDR(unsigned char s, unsigned short ea){ snprintf(addrBuff,sizeof(addrBuff),((ea&0x8000) && s>0)?"%2$x:%1$04x":"%04x",ea,s); return addrBuff;}int c6805::Run(int max_count){// returns:// 0 - breakpoint// 1 - stack overflow// 2 - instruction counter exeeded// 3 - unsupported instruction disAsmLogClass=L_SYS_DISASM; if(LOG(L_SYS_DISASM)) doDisAsm=true; else { doDisAsm=false; if(LOG(L_SYS_DISASM80)) disAsmLogClass=L_SYS_DISASM80; } PRINTF(disAsmLogClass,"cr:-pc- aa xx yy dr -sp- VHINZC -mem@pc- -mem@sp-"); int count=0; while (1) { if(sp<spLow) { PRINTF(L_SYS_EMU,"stack overflow (count=%d)",count); return 1; } if(spHi>spLow && sp>spHi) { PRINTF(L_SYS_EMU,"stack underflow (count=%d)",count); return 1; } count++; if(!LOG(L_SYS_DISASM) && LOG(L_SYS_DISASM80)) { bool flag=(pc>=0x80 && pc<0xE0); if(doDisAsm && !flag) PRINTF(disAsmLogClass,"[...]"); doDisAsm=flag; } CCLOGLBPUT("%02x:%04x %02x %02x %02x %02x %04x %c%c%c%c%c%c %02x%02x%02x%02x %02x%02x%02x%02x ", cr,pc,a,x,y,dr,sp, cc.v?'V':'.',cc.h?'H':'.',cc.i?'I':'.',cc.n?'N':'.',cc.z?'Z':'.',cc.c?'C':'.', Get(pc),Get(pc+1),Get(pc+2),Get(pc+3),Get(sp+1),Get(sp+2),Get(sp+3),Get(sp+4)); Stepper(); unsigned char *ex=&x; unsigned short idx=*ex; indirect=false; bool paged=false, vbra=false; unsigned char ins=Get(pc++); char xs='X', xi='X'; // check pre-bytes switch(ins) { case 0x31: // use SP indexed or indirect paged mode (ST19) ins=Get(pc++); switch(ins) { case 0x22 ... 0x27: vbra=true; PRINTF(L_SYS_EMU,"WARN: V-flag not yet calculated"); break; case 0x75: case 0x8D: case 0xC0 ... 0xCB: case 0xCE ... 0xCF: case 0xD0 ... 0xDB: case 0xDE ... 0xDF: paged=true; indirect=true; break; case 0xE0 ... 0xEB: case 0xEE ... 0xEF: idx=sp; xi='S'; break; } break; case 0x32: // use indirect SP indexed or indirect paged Y indexed mode (ST19) ins=Get(pc++); switch(ins) { case 0x22 ... 0x27: vbra=true; PRINTF(L_SYS_EMU,"WARN: V-flag not yet calculated"); indirect=true; break; case 0xC3: case 0xCE ... 0xCF: case 0xD0 ... 0xDB: case 0xDE ... 0xDF: paged=true; indirect=true; ex=&y; idx=*ex; xs='Y'; xi='Y'; break; case 0xE0 ... 0xEB: case 0xEE ... 0xEF: indirect=true; idx=sp; xi='S'; break; } break; case 0x91: // use Y register with indirect addr mode (ST7) indirect=true; // fall through case 0x90: // use Y register (ST7) ex=&y; idx=*ex; xs='Y'; xi='Y'; ins=Get(pc++); break; case 0x92: // use indirect addr mode (ST7) indirect=true; ins=Get(pc++); break; } if(doDisAsm) { char str[8]; if(!vbra) snprintf(str,sizeof(str),ops[ins],xs,xs^1); else snprintf(str,sizeof(str),"%s",vops[ins-0x22]); LOGLBPUT("%-5s ",str); } // address decoding unsigned short ea=0; unsigned char flags=opFlags[ins]; unsigned char pr=(flags&4) ? dr:cr; switch(((flags&8) ? flags:ins)>>4) { case 0x2: // no or special address mode case 0x8: case 0x9: break; case 0xA: // immediate CCLOGLBPUT("#%02x ",Get(pc)); ea=pc++; break; case 0x3: // short case 0xB: ea=Get(pc++); if(!indirect) { // short direct } else { // short indirect CCLOGLBPUT("[%02x] -> ",ea); ea=Get(ea); } CCLOGLBPUT("%02x ",ea); break; case 0xC: // long if(!indirect) { // long direct ea=HILO(pc); pc+=2; } else { // long indirect if(paged) { ea=HILO(pc); pc+=2; CCLOGLBPUT("[%s] -> ",PADDR(pr,ea)); unsigned char s=Get(pr,ea); ea=HILOS(pr,ea+1); pr=s; } else { ea=Get(pc++); CCLOGLBPUT("[%02x] -> ",ea); ea=HILO(ea); } } CCLOGLBPUT("%s ",PADDR(pr,ea)); break; case 0xD: // long indexed if(!indirect) { // long direct indexed ea=HILO(pc); pc+=2; CCLOGLBPUT("(%s",PADDR(cr,ea)); } else { // long indirect indexed if(paged) { ea=HILO(pc); pc+=2; CCLOGLBPUT("([%s]",PADDR(pr,ea)); unsigned char s=Get(pr,ea++); ea=HILOS(pr,ea); pr=s; } else { ea=Get(pc++); CCLOGLBPUT("([%02x]",ea); ea=HILO(ea); } CCLOGLBPUT(",%c) -> (%s",xi,PADDR(pr,ea)); } ea+=idx; CCLOGLBPUT(",%c) -> %s ",xi,PADDR(pr,ea)); break; case 0x6: // short indexed case 0xE: ea=Get(pc++); if(!indirect) { // short direct indexed CCLOGLBPUT("(%02x",ea); } else { // short indirect indexed CCLOGLBPUT("([%02x]",ea); ea=Get(ea); CCLOGLBPUT(",%c) -> (%02x",xi,ea); } ea+=idx; CCLOGLBPUT(",%c) -> %s ",xi,PADDR(pr,ea)); break; case 0x7: // indexed case 0xF: ea=idx; CCLOGLBPUT("(%c) -> %s ",xi,PADDR(pr,ea)); break; case 0x4: // inherent A CCLOGLBPUT("A "); break; case 0x5: // inherent X/Y CCLOGLBPUT("%c ",xs);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -