void executeVm(Cpu_t *cpu) { uint16_t tmp; uint16_t mode; uint16_t instr,k; //SYSTEMOUTHEX("\npc:",cpu->Pc); tmp=readMemory(cpu,IMM); //SYSTEMOUTHEX(" instr code:",tmp); //showCpu(cpu); //SYSTEMOUTHEX("pc:",cpu->Pc); mode=tmp&03000; instr=tmp&0777; switch(instr) { // ALU instructions // two word instructions // instruction with addressing mode, operand //#define NOP2 00000 // A->A nop with 2 instructions case NOP2:{ DISASM("NOP2"); INCPC(cpu); }break; //#define MINUS 00006 // A-M-1 -> A case MINUS:{ DISASM("MINUS"); INCPC(cpu); tmp=readMemory(cpu,mode); cpu->A-=tmp; cpu->A--; if(cpu->flags&(1<<AF_FLAG))cpu->A++; if(cpu->A>0777)cpu->flags|=(1<<AF_FLAG); else cpu->flags&=~(1<<AF_FLAG); cpu->A&=0777; }break; //#define PLUS 00011 // A+M -> A case PLUS:{ DISASM("PLUS"); INCPC(cpu); //SYSTEMOUTHEX("@:",cpu->Pc); tmp=readMemory(cpu,mode); //SYSTEMOUTHEX("plus:",tmp); cpu->A+=tmp; if(cpu->flags&(1<<AF_FLAG))cpu->A++; if(cpu->A>0777)cpu->flags|=(1<<AF_FLAG); else cpu->flags&=~(1<<AF_FLAG); cpu->A&=0777; }break; //#define DOUBLE 00014 // A*2 -> A, operand not used case DOUBLE:{ DISASM("DOUBLE"); INCPC(cpu); tmp=readMemory(cpu,mode); cpu->A=2*tmp; //if(cpu->flags&(1<<AF_FLAG))cpu->A++; if(cpu->A>0777)cpu->flags|=(1<<AF_FLAG); else cpu->flags&=~(1<<AF_FLAG); cpu->A&=0777; }break; //#define DEC 00017 // A-1 -> A, operand not used case DEC:{ DISASM("DEC"); INCPC(cpu); //tmp=readMemory(cpu,mode); cpu->A--; //if(cpu->flags&(1<<AF_FLAG))cpu->A++; //if(cpu->A>0777)cpu->flags|=(1<<AF_FLAG); //else cpu->flags&=~(1<<AF_FLAG); cpu->A&=0777; }break; //#define INV 00020 // NOT A -> A, operand not used case INV:{ DISASM("INV"); INCPC(cpu); cpu->A=~cpu->A; cpu->A&=0777; }break; //#define NOR 00021 // A NOR M -> A case NOR:{ DISASM("NOR"); INCPC(cpu); tmp=readMemory(cpu,mode); cpu->A=~(cpu->A|tmp); cpu->A&=0777; }break; //#define ZERO 00023 // 0 -> A -> A case ZERO:{ DISASM("ZERO"); INCPC(cpu); cpu->A=0; }break; //#define NAND 00024 // A NAND M -> A case NAND:{ DISASM("NAND"); INCPC(cpu); tmp=readMemory(cpu,mode); cpu->A=~(cpu->A&tmp); cpu->A&=0777; }break; //#define INVM 00025 // NOT M -> A case INVM:{ DISASM("INVM"); INCPC(cpu); tmp=readMemory(cpu,mode); cpu->A=~tmp; cpu->A&=0777; }break; //#define EXOR 00026 // A EXOR M -> A case EXOR:{ DISASM("EXOR"); INCPC(cpu); tmp=readMemory(cpu,mode); cpu->A=(cpu->A^tmp); cpu->A&=0777; }break; //#define EXNOR 00031 // A EXNOR M -> A case EXNOR:{ DISASM("EXNOR"); INCPC(cpu); tmp=readMemory(cpu,mode); cpu->A=~(cpu->A^tmp); cpu->A&=0777; }break; //#define AND 00033 // A and M -> A case AND:{ DISASM("AND"); INCPC(cpu); tmp=readMemory(cpu,mode); cpu->A=(cpu->A&tmp); cpu->A&=0777; }break; //#define ONES 00034 // 0777->A set all ones case ONES:{ DISASM("ZERO"); INCPC(cpu); cpu->A=0777; }break; //#define OR 00036 // A or M -> A case OR:{ DISASM("OR"); INCPC(cpu); tmp=readMemory(cpu,mode); cpu->A=(cpu->A|tmp); cpu->A&=0777; }break; //****************************************************** // stack instructions //****************************************************** //#define PLPC 00600 // pull PC ( return ) case PLPC:{ DISASM("PLPC (return)"); cpu->Pc=pop(cpu)-1; }break; //#define PLP 00601 // pull P case PLP:{ DISASM("PLP ( display )"); cpu->display=pop(cpu)-1; }break; //#define PLIO 00602 // pull I/O case PLIO:{ DISASM("PLIO (outport)"); cpu->outport=pop(cpu)-1; }break; //#define PLA 00603 // pull A case PLA:{ DISASM("PLA"); cpu->A=pop(cpu)-1; }break; //#define PHPC 00604 // push PC case PHPC:{ DISASM("PHPC"); push(cpu,cpu->Pc); // warning: check if original T3 pushes next address }break; //#define PHP 00614 // push P case PHP:{ DISASM("PHP (keys)"); push(cpu,cpu->keys); }break; //#define PHIO 00624 // push I/O case PHIO:{ DISASM("PHIO (outport)"); push(cpu,cpu->outport); }break; //#define PHA 00634 // push A case PHA:{ DISASM("PHA"); push(cpu,cpu->A); }break; //****************************************************** // register memory transfer instructions //****************************************************** //#define STPC 00100 // PC -> M case STPC:{ DISASM("STPC"); INCPC(cpu); writeMemory(cpu,mode,cpu->Pc); }break; //#define STP 00110 // P -> M case STP:{ DISASM("STP"); INCPC(cpu); writeMemory(cpu,mode,cpu->keys); }break; //#define STIO 00120 // I/O -> M case STIO:{ DISASM("STIO"); INCPC(cpu); writeMemory(cpu,mode,cpu->inport); }break; //#define STA 00130 // A -> M case STA:{ DISASM("STA"); INCPC(cpu); writeMemory(cpu,mode,cpu->A); }break; //#define LDPC 00104 // M -> PC case LDPC:{ DISASM("LDA"); INCPC(cpu); cpu->A=readMemory(cpu,mode); }break; //#define LDP 00105 // M -> P case LDP:{ DISASM("LDP"); INCPC(cpu); cpu->display=readMemory(cpu,mode); }break; //#define LDIO 00106 // M -> I/O case LDIO:{ DISASM("LDP"); INCPC(cpu); cpu->outport=readMemory(cpu,mode); }break; //#define LDA 00107 // M -> A case LDA:{ DISASM("LDA"); INCPC(cpu); cpu->A=readMemory(cpu,mode); }break; // compare instructions //****************************************************** // compare instruction //****************************************************** //#define CMP 00200 // A-M -> FLG case CMP:{ DISASM("CMP"); INCPC(cpu); tmp=readMemory(cpu,mode); cpu->flags&=~((1<<EQ_FLAG)|(1<<GT_FLAG)|(1<<SM_FLAG)|(1<<MSB_FLAG)); //#define EQ_FLAG 0 // A = OPR if(tmp==cpu->A)cpu->flags|=(1<<EQ_FLAG); //printf("a:%x dest:%x\n",cpu->A,tmp); //#define GT_FLAG 1 // A > OPR if(tmp>cpu->A)cpu->flags|=(1<<GT_FLAG); //#define SM_FLAG 2 // A < OPR if(tmp<cpu->A)cpu->flags|=(1<<SM_FLAG); //#define ALU_FLAG 3 // //#define MSB_FLAG 4 // MSB of A if(cpu->A&0400)cpu->flags|=(1<<MSB_FLAG); }break; //****************************************************** // machine control instructions //****************************************************** //#define RST 00400 // 0001->PC case RST:{ DISASM("RST"); cpu->Pc=1; }break; //#define STOP 00401 // stop case STOP:{ DISASM("STOP"); cpu->Pc--; }break; //#define RSD 00402 // reset display case RSD:{ DISASM("RSD"); cpu->display=0; }break; //#define SHIB 00403 // select high bank case SHIB:{ DISASM("select high bank"); cpu->bank=1; }break; //#define SLOB 00404 // select low bank case SLOB:{ DISASM("select low bank"); cpu->bank=0; }break; //#define RSSP 00405 // 0->SP, reset stack pointer case RSSP:{ DISASM("RSSP"); cpu->Sp=0; }break; //#define RSA 00406 // 0->ACCU, reset accumulator case RSA:{ DISASM("RSA"); cpu->A=0; }break; //#define STB 00407 // strobe ? case STB:{ DISASM("strobe?"); }break; //SAF 00410 // set accu flag ( AF_FLAG ) case SAF:{ DISASM("SAF"); cpu->flags|=(1<<AF_FLAG); }break; //#define CAF 00411 // clear accu flag ( AF_FLAG ) case CAF:{ DISASM("CAF"); cpu->flags&=~(1<<AF_FLAG); }break; //#define SSF 00412 // set shift flag ( SF_FLAG ) case SSF:{ DISASM("SSF"); cpu->flags|=(1<<SF_FLAG); }break; //#define CSF 00413 // clear shift flag ( SF_FLAG ) case CSF:{ DISASM("CSF"); cpu->flags&=~(1<<SF_FLAG); }break; //#define NOP1 00414 // one word nop case NOP1:{ DISASM("NOP1"); }break; //****************************************************** // register register transfer instructions //****************************************************** //#define TPCP 00501 // PC -> P // PC -> display case TPCP:{ DISASM("TPCP"); cpu->display=cpu->Pc; }break; //#define TPCIO 00502 // PC -> IO ( outport ) case TPCIO:{ DISASM("TPCIO"); cpu->outport=cpu->Pc; }break; //#define TPCA 00503 // PC -> A case TPCA:{ DISASM("TPCA"); cpu->A=cpu->Pc; }break; //#define TPPC 00510 // (keys) P -> PC case TPPC:{ DISASM("TPPC (keys)"); cpu->Pc=cpu->keys; }break; //#define TPP 00511 // P -> P read keyboard, write display case TPP:{ DISASM("TPP (keys->display)"); cpu->display=cpu->keys; }break; //#define TPIO 00512 // P -> IO case TPIO:{ DISASM("TPIO (keys->outport)"); cpu->outport=cpu->keys; }break; //#define TPA 00513 // P -> A // keys -> A case TPA:{ DISASM("TPIO (keys->outport)"); cpu->A=cpu->keys; }break; //#define TIOPC 00520 // IO->PC case TIOPC:{ DISASM("TIOPC (inport->pc)"); cpu->Pc=cpu->inport; }break; //#define TIOP 00521 // IO->P case TIOP:{ DISASM("TIOP (inport->display)"); cpu->display=cpu->inport; }break; //#define TIOA 00523 // IO->A case TIOA:{ DISASM("TIOA"); cpu->A=cpu->inport; }break; //#define TAPC 00530 // A->PC ( variable jump ) case TAPC:{ DISASM("TAPC (jmp(A))"); cpu->Pc=cpu->A; }break; //#define TAP 00531 // A->P store A in display case TAP:{ DISASM("TAP"); cpu->display=cpu->A; }break; //#define TAIO 00532 // A->IO store A in outport case TAIO:{ DISASM("TAIO"); cpu->outport=cpu->A; }break; //****************************************************** // masked functions //****************************************************** default:{ tmp=instr&JMPMASK; uint8_t flags; flags=instr&FLAGMASK; //ERROR("instr", tmp); SYSTEMOUTHEX("flag selector",flags); SYSTEMOUTHEX(" cpu.flags",cpu->flags); SYSTEMOUTCR; switch(tmp) { //****************************************************** // program flow instructions //****************************************************** case JMPS:{ DISASM("JMPS"); INCPC(cpu); if(cpu->flags&(1<<flags)) { DISASM("jump"); cpu->Pc=readMemory(cpu,mode)-1; } }break; case JMPR:{ DISASM("JMPR"); INCPC(cpu); if(!(cpu->flags&(1<<flags))) { DISASM("jump"); cpu->Pc=readMemory(cpu,mode)-1; } }break; case GSBS:{ DISASM("GSBS"); INCPC(cpu); if(cpu->flags&(1<<flags)) { DISASM(" (call)"); push(cpu,cpu->Pc+1); cpu->Pc=readMemory(cpu,mode)-1; } }break; case GSBR:{ DISASM("GSBR"); INCPC(cpu); if(!(cpu->flags&(1<<flags))) { DISASM(" (call)"); push(cpu,cpu->Pc+1); cpu->Pc=readMemory(cpu,mode)-1; //dumpMem1(cpu); } }break; default: { //****************************************************** // shift instructions //****************************************************** tmp=instr&SHIFTMASK; uint8_t shift=instr&07; switch(tmp) { //#define ROL 00700 // rotate left n bits case ROL:{ tmp=cpu->A; tmp=tmp<<shift; tmp|=cpu->A>>(13-shift); if(tmp&010000)cpu->flags|=(1<<SF_FLAG); else cpu->flags&=~(1<<SF_FLAG); cpu->A=tmp&0777; }break; //#define ROR 00710 // rotate right n bits case ROR:{ tmp=cpu->A; tmp=tmp>>shift; tmp|=cpu->A<<(13-shift); if(tmp&010000)cpu->flags|=(1<<SF_FLAG); else cpu->flags&=~(1<<SF_FLAG); cpu->A=tmp&0777; }break; //#define SFL 00720 // shift left n bits case SFL:{ tmp=cpu->A; tmp=tmp<<shift; cpu->A=tmp&0777; if(tmp&010000)cpu->flags|=(1<<SF_FLAG); else cpu->flags&=~(1<<SF_FLAG); }break; //#define SFR 00730 // shift right n bits case SFR:{ tmp=cpu->A; tmp=tmp>>shift; cpu->A=tmp&0777; if((cpu->A)>>(shift-1)&1)cpu->flags|=(1<<SF_FLAG); else cpu->flags&=~(1<<SF_FLAG); }break; default: { ERROR("error: unknown instruction",instr); simulatorReset(cpu); cpu->Pc--; }break; } } } }break; }
void DeclareLabels(ParserState *P) { unsigned asmpc = 0; unsigned datoff = 0; unsigned inc = 0; unsigned delta; AST *ast = NULL; AST *pendingLabels = NULL; for (ast = P->datblock; ast; ast = ast->right) { switch (ast->kind) { case AST_BYTELIST: pendingLabels = emitPendingLabels(P, pendingLabels, datoff, asmpc, ast_type_byte); replaceHereDataList(ast->left, asmpc, 1); INCPC(dataListLen(ast->left, 1)); break; case AST_WORDLIST: ALIGNPC(2); pendingLabels = emitPendingLabels(P, pendingLabels, datoff, asmpc, ast_type_word); replaceHereDataList(ast->left, asmpc, 2); INCPC(dataListLen(ast->left, 2)); break; case AST_LONGLIST: ALIGNPC(4); pendingLabels = emitPendingLabels(P, pendingLabels, datoff, asmpc, ast_type_long); replaceHereDataList(ast->left, asmpc, 4); INCPC(dataListLen(ast->left, 4)); break; case AST_INSTRHOLDER: ALIGNPC(4); pendingLabels = emitPendingLabels(P, pendingLabels, datoff, asmpc, ast_type_long); replaceHeres(ast->left, asmpc/4); INCPC(4); break; case AST_IDENTIFIER: pendingLabels = AddToList(pendingLabels, NewAST(AST_LISTHOLDER, ast, NULL)); break; case AST_ORG: pendingLabels = emitPendingLabels(P, pendingLabels, datoff, asmpc, ast_type_long); if (ast->left) { replaceHeres(ast->left, asmpc/4); asmpc = 4*EvalPasmExpr(ast->left); } else { asmpc = 0; } break; case AST_RES: asmpc = align(asmpc, 4); pendingLabels = emitPendingLabels(P, pendingLabels, datoff, asmpc, ast_type_long); delta = EvalPasmExpr(ast->left); asmpc += 4*delta; break; case AST_FIT: asmpc = align(asmpc, 4); pendingLabels = emitPendingLabels(P, pendingLabels, datoff, asmpc, ast_type_long); if (ast->left) { int32_t max = EvalPasmExpr(ast->left); int32_t cur = (asmpc) / 4; if ( cur > max ) { ERROR(ast, "fit %d failed: pc is %d", max, cur); } } break; case AST_FILE: pendingLabels = emitPendingLabels(P, pendingLabels, datoff, asmpc, ast_type_byte); INCPC(filelen(ast->left)); break; default: ERROR(ast, "unknown element %d in data block", ast->kind); break; } } }