void dumpMem1(Cpu_t *cpu) { SYSTEMOUT("dump mem1:"); uint16_t n; for(n=0; n<0x50;n++)SYSTEMOUTHEX(" ",cpu->M[0][n]); SYSTEMOUT(" "); }
char getCharFromStream() { char c; #ifdef WITHFILESYSTEM if(InputStreamState==GETKEY)c=SYSTEMGETCHAR(); if(InputStreamState==OPENFILE) { //InputFile = fopen("test.fs", "r"); InputFile = fopen(WordBuffer, "r"); if (InputFile == NULL) { SYSTEMOUT_("file not found: "); SYSTEMOUT_(WordBuffer); InputStreamState=GETKEY; }else InputStreamState=READFROMFILE; } if(InputStreamState==READFROMFILE) { c=fgetc(InputFile); if(c==EOF) { fclose(InputFile); InputStreamState=GETKEY; // switch to keyboard SYSTEMOUT("\nok>"); c=' '; } } #else c=SYSTEMGETCHAR(); #endif return c; }
void cpuExternalCall(Cpu_t *cpu) { int32_t command=pop(cpu); uint16_t value; switch(command) { case EXTERNAL_C_GETMSTIME: { push(cpu,updateSysCounter()&0xFFFF); // low counts push(cpu,updateSysCounter()>>16); // high counts }break; case EXTERNAL_C_GETKEY: { push(cpu,SYSTEMGETCHAR()); push(cpu,0xFFFF); // true flag for char received }break; case EXTERNAL_C_PRINTCHAR: { value=pop(cpu); SYSTEMOUTCHAR(value); }break; case EXTERNAL_C_PRINTNUMBER: { value=pop(cpu); if(Base==10) { value=(value>0x8000L)? value-(int32_t) 0x10000L:value; SYSTEMOUTPRINTNUMBER(value); } else SYSTEMOUTPRINTHEXNUMBER(value); }break; case EXTERNAL_C_SETBASE: // set the calculation base { value=pop(cpu); Base=value; }break; default: SYSTEMOUT("external command not found");break; } }
void executeVm(Cpu_t *cpu) { uint8_t temp; uint8_t command; //SYSTEMOUTHEX("adr",cpu->Pc); //SYSTEMOUTHEX("flag",cpu->flag); command=cpu->M[cpu->Pc]; cpu->Pc++; switch(command) { // KA K->Ar 0, 1 The pressed key from the hex keypad is saved to the A register. // If a key is not pressed, the Flag is set to 1, otherwise it is 0. case KA:{ DISASM("KA "); if(KEYHIT()) { cpu->M[AR]=GETKEY(); cpu->flag=0; SYSTEMOUTHEX("Key:",cpu->M[AR]); }else { SYSTEMOUT("nokey"); cpu->flag=1; } }break; // AO Ar->Op 1 The 7-segment readout displays the value currently contained in the A register. case AO:{ DISASM("AO "); //show7Segment(cpu->M[AR]); DISPLAYOUTHEX(cpu->M[AR]); //PRINT7SEGMENT(x); cpu->flag=1; }break; // CH Ar<=>Br // Yr<=>Zr 1 Exchange the contents of the A and B registers, and the Y and Z registers. case CH:{ DISASM("CH "); temp=cpu->M[AR]; cpu->M[AR]=cpu->M[BR]; cpu->M[BR]=temp; temp=cpu->M[YR]; cpu->M[YR]=cpu->M[ZR]; cpu->M[ZR]=temp; cpu->flag=1; }break; // CY Ar<=>Yr 1 Exchange the contents of the A and Y registers. case CY:{ DISASM("CY "); temp=cpu->M[AR]; cpu->M[AR]=cpu->M[YR]; cpu->M[YR]=temp; cpu->flag=1; }break; // AM Ar->M 1 Write the contents of the A register to data memory (memory address is 50 + Y register). case AM:{ DISASM("AM "); cpu->M[((cpu->M[YR])&0xF)+M_OFFSET]=cpu->M[AR]; cpu->flag=1; }break; // MA M->Ar 1 Write the contents of data memory (50 + Y register) to the A register. case MA:{ DISASM("MA "); cpu->M[AR]=cpu->M[((cpu->M[YR])&0xF)+M_OFFSET]; cpu->flag=1; }break; // M+ M+Ar->Ar 0, 1 Add the contents of data memory (50 + Y register) to the A register. If there is overflow, the Flag is set to 1, otherwise 0. case MPLUS:{ DISASM("M+ "); cpu->M[AR]+=cpu->M[((cpu->M[YR])&0xF)+M_OFFSET]; if(((cpu->M[AR])&0x10)!=0)cpu->flag=1; else cpu->flag=0; cpu->M[AR]&=0x0F; }break; // M- M-Ar->Ar 0, 1 Subtract the contents of data memory (50 + Y register) from the A register. If the result is negative, the Flag is set to 1, otherwise 0. case MMINUS:{ DISASM("M- "); cpu->M[AR]-=cpu->M[((cpu->M[YR])&0xF)+M_OFFSET]; if(((cpu->M[AR])&0x10)!=0)cpu->flag=1; else cpu->flag=0; cpu->M[AR]&=0x0F; }break; // TIA [ ] [ ] -> Ar 1 Transfer immediate to the A register. case TIA:{ DISASM("TIA "); cpu->M[AR]=cpu->M[cpu->Pc]; cpu->Pc++; cpu->flag=1; }break; // AIA [ ] Ar + [ ] -> Ar 0, 1 Add immediate to the A register. If there is overflow, the Flag is set to 1, otherwise 0. case AIA:{ DISASM("AIA "); cpu->M[AR]+=cpu->M[cpu->Pc]; if(((cpu->M[AR])&0x10)!=0)cpu->flag=1; else cpu->flag=0; cpu->M[AR]&=0x0F; cpu->Pc++; }break; // TIY [ ] [ ] -> Yr 1 Transfer immediate to the Y register. case TIY:{ DISASM("TIA "); cpu->M[YR]=cpu->M[cpu->Pc]; cpu->Pc++; cpu->flag=1; }break; // AIY [ ] Yr + [ ] -> Yr 0, 1 Add immediate to the Y register. If there is overflow, the Flag is set to 1, otherwise 0. case AIY:{ DISASM("AIY "); cpu->M[YR]+=cpu->M[cpu->Pc]; if(((cpu->M[YR])&0x10)!=0)cpu->flag=1; else cpu->flag=0; cpu->M[YR]&=0x0F; cpu->Pc++; }break; // CIA [ ] Ar != [ ] ? 0, 1 Compare immediate to the A register. If equal, Flag reset to 0, otherwise set to 1. case CIA:{ DISASM("CIA "); if(cpu->M[AR]!=cpu->M[cpu->Pc])cpu->flag=0; else cpu->flag=1; cpu->Pc++; }break; // CIY [ ] Yr != [ ] ? 0, 1 Compare immediate to the Y register. If equal, Flag reset to 0, otherwise set to 1. case CIY:{ DISASM("CIY "); if(cpu->M[YR]!=cpu->M[cpu->Pc])cpu->flag=0; else cpu->flag=1; cpu->Pc++; }break; //JUMP [ ] [ ] 1 Jump to the immediate address if the Flag is 1, otherwise just increment the program counter. //The Flag is then set to 1. Note that this is an absolute address. That is, JUMP [0] [2] will change the address pointer to hex address 0x02. //You can jump both forward and backward in program space. case JUMP:{ DISASM("JUMP "); if((cpu->flag)==1) { temp=cpu->M[cpu->Pc]<<4; cpu->Pc++; temp+=cpu->M[cpu->Pc]<<4; cpu->Pc=temp; }else{ cpu->Pc++; cpu->flag=1; } }break; // --- --- --- Extended code. See table below. case EXTENDED:{ command=(cpu->M[cpu->Pc])|0xE0; SYSTEMOUTHEX("com:",command); cpu->Pc++; if(cpu->flag==1)switch(command) { case CAL_RSTO:{ DISASM("CAL_RSTO "); SYSTEMOUTCHAR(' '); //SYSTEMOUT("clear 7 seg"); }break; case CAL_SETR:{ DISASM("CAL_SETR "); cpu->leds|=(1<<(cpu->M[YR])); SHOWLEDS(cpu->leds); //SYSTEMOUT("led on"); }break; case CAL_RSTR:{ DISASM("CAL_RSTR "); cpu->leds&=~(1<<(cpu->M[YR])); SHOWLEDS(cpu->leds); //SYSTEMOUT("led off"); }break; // 0xE4 // CAL CMPL 1 Complement the A register (1 <=> 0). case CAL_CMPL:{ DISASM("CAL_CMPL "); cpu->M[AR]=(~cpu->M[AR])&0x0F; cpu->flag=1; }break; //0xE5 // CAL CHNG 1 Swap the A/B/Y/Z registers with A'/B'/Y'/Z' case CAL_CHNG:{ DISASM("CAL_CHNG "); temp=cpu->M[AR]; cpu->M[AR]=cpu->M[AR_]; cpu->M[AR_]=temp; temp=cpu->M[BR]; cpu->M[BR]=cpu->M[BR_]; cpu->M[BR_]=temp; temp=cpu->M[YR]; cpu->M[YR]=cpu->M[YR_]; cpu->M[YR_]=temp; temp=cpu->M[ZR]; cpu->M[ZR]=cpu->M[ZR_]; cpu->M[ZR_]=temp; cpu->flag=1; }break; // 0xE6 // CAL SIFT 0, 1 Shift the A register right 1 bit. If the starting value is even (bit 0 = 0), set the Flag to 1, otherwise 0. case CAL_SIFT:{ DISASM("CAL_SIFT "); if((cpu->M[AR])&1)cpu->flag=1; else cpu->flag=0; cpu->M[AR]=(~cpu->M[AR])>>1; }break; //0xE7 // CAL ENDS 1 Play the End sound. case CAL_ENDS:{ DISASM("CAL_ENDS "); SOUND(NOTE_D6,80); SOUND(NOTE_E6,80); SOUND(NOTE_F6,80); SOUND(NOTE_G6,80); SOUND(NOTE_A6,80); SOUND(NOTE_B6,80); //soundf(0); //SOUND(440,500); SYSTEMOUT("end sound"); cpu->flag=1; }break; //0xE8 // CAL ERRS 1 Play the Error sound. case CAL_ERRS:{ DISASM("CAL_ERRS "); for(int n = 0; n < 6; n++) { SOUND(NOTE_G5,20); SOUND(NOTE_A5,20); SOUND(NOTE_B5,20); SOUND(NOTE_C6,20); SOUND(NOTE_D6,20); SOUND(NOTE_E6,20); } //SOUND(200,500); SYSTEMOUT("play error sound"); cpu->flag=1; }break; //0xE9 // CAL SHTS 1 Play a short "pi" sound. case CAL_SHTS:{ DISASM("CAL_SHTS "); SOUND(NOTE_C5,150); SYSTEMOUT("play short peep sound"); cpu->flag=1; }break; //0xEA // CAL LONS 1 Play a longer "pi-" sound. case CAL_LONS:{ DISASM("CAL_LONS "); SOUND(NOTE_C5,450); SYSTEMOUT("play longer peep sound"); cpu->flag=1; }break; //0xEB // CAL SUND 1 Play a note based on the value of the A register //(allowed values are 1 - E). case CAL_SUND:{ DISASM("CAL_SUND "); //SOUND(cpu->M[AR],500); gmcSound(cpu->M[AR],300); SYSTEMOUT("play A reg"); cpu->flag=1; }break; //0xEC // CAL TIMR 1 //Pause for the time calculated by (value of A register +1) * 0.1 seconds. case CAL_TIMR:{ DISASM("CAL_TIMR "); showMatrix(((cpu->M[AR])*100+1)); cpu->flag=1; }break; //0xED // CAL DSPR 1 Set the 2-pin LEDs with the value from data memory. The data to display is as follows: the upper three bits come from memory address 5F (bits 0-2), and the lower four from memory address 5E (bits 0-3). case CAL_DSPR:{ DISASM("CAL_DSPR "); SYSTEMOUT("set LED"); cpu->flag=1; }break; //0xEE // CAL DEM- 1 //Subtract the value of the A register from the value in data memory. //The new value is stored in data memory as a decimal. //Afterwards, the Y register is decremented by 1. case CAL_DEMMINUS:{ DISASM("CAL_DEM- "); //SYSTEMOUT("dem-"); cpu->M[YR]=cpu->M[YR]-cpu->M[AR]; cpu->M[YR]++; cpu->M[YR]&=0xF; cpu->flag=1; }break; //0xEF // CAL DEM+ 1 //Add the value of the A register to the value in data memory. //The new value is stored in memory as a decimal. //If the result is overflow, data memory will be automatically adjusted. //Afterwards, the Y register is decremented. case CAL_DEMPLUS:{ DISASM("CAL_DEM+ "); cpu->M[YR]=cpu->M[YR]+cpu->M[AR]; cpu->M[YR]--; cpu->M[YR]&=0xF; cpu->flag=1; }break; } }break; } }