diff --git a/TIKI-100_emul-src/Codes.h b/TIKI-100_emul-src/Codes.h new file mode 100644 index 0000000..819ecd8 --- /dev/null +++ b/TIKI-100_emul-src/Codes.h @@ -0,0 +1,378 @@ +/** Z80: portable Z80 emulator *******************************/ +/** **/ +/** Codes.h **/ +/** **/ +/** This file contains implementation for the main table of **/ +/** Z80 commands. It is included from Z80.c. **/ +/** **/ +/** Copyright (C) Marat Fayzullin 1994,1995,1996,1997 **/ +/** You are not allowed to distribute this software **/ +/** commercially. Please, notify me, if you make any **/ +/** changes to this file. **/ +/*************************************************************/ + +case JR_NZ: if(R->AF.B.l&Z_FLAG) R->PC.W++; else { R->ICount-=5;M_JR; } break; +case JR_NC: if(R->AF.B.l&C_FLAG) R->PC.W++; else { R->ICount-=5;M_JR; } break; +case JR_Z: if(R->AF.B.l&Z_FLAG) { R->ICount-=5;M_JR; } else R->PC.W++; break; +case JR_C: if(R->AF.B.l&C_FLAG) { R->ICount-=5;M_JR; } else R->PC.W++; break; + +case JP_NZ: if(R->AF.B.l&Z_FLAG) R->PC.W+=2; else { M_JP; } break; +case JP_NC: if(R->AF.B.l&C_FLAG) R->PC.W+=2; else { M_JP; } break; +case JP_PO: if(R->AF.B.l&P_FLAG) R->PC.W+=2; else { M_JP; } break; +case JP_P: if(R->AF.B.l&S_FLAG) R->PC.W+=2; else { M_JP; } break; +case JP_Z: if(R->AF.B.l&Z_FLAG) { M_JP; } else R->PC.W+=2; break; +case JP_C: if(R->AF.B.l&C_FLAG) { M_JP; } else R->PC.W+=2; break; +case JP_PE: if(R->AF.B.l&P_FLAG) { M_JP; } else R->PC.W+=2; break; +case JP_M: if(R->AF.B.l&S_FLAG) { M_JP; } else R->PC.W+=2; break; + +case RET_NZ: if(!(R->AF.B.l&Z_FLAG)) { R->ICount-=6;M_RET; } break; +case RET_NC: if(!(R->AF.B.l&C_FLAG)) { R->ICount-=6;M_RET; } break; +case RET_PO: if(!(R->AF.B.l&P_FLAG)) { R->ICount-=6;M_RET; } break; +case RET_P: if(!(R->AF.B.l&S_FLAG)) { R->ICount-=6;M_RET; } break; +case RET_Z: if(R->AF.B.l&Z_FLAG) { R->ICount-=6;M_RET; } break; +case RET_C: if(R->AF.B.l&C_FLAG) { R->ICount-=6;M_RET; } break; +case RET_PE: if(R->AF.B.l&P_FLAG) { R->ICount-=6;M_RET; } break; +case RET_M: if(R->AF.B.l&S_FLAG) { R->ICount-=6;M_RET; } break; + +case CALL_NZ: if(R->AF.B.l&Z_FLAG) R->PC.W+=2; else { R->ICount-=7;M_CALL; } break; +case CALL_NC: if(R->AF.B.l&C_FLAG) R->PC.W+=2; else { R->ICount-=7;M_CALL; } break; +case CALL_PO: if(R->AF.B.l&P_FLAG) R->PC.W+=2; else { R->ICount-=7;M_CALL; } break; +case CALL_P: if(R->AF.B.l&S_FLAG) R->PC.W+=2; else { R->ICount-=7;M_CALL; } break; +case CALL_Z: if(R->AF.B.l&Z_FLAG) { R->ICount-=7;M_CALL; } else R->PC.W+=2; break; +case CALL_C: if(R->AF.B.l&C_FLAG) { R->ICount-=7;M_CALL; } else R->PC.W+=2; break; +case CALL_PE: if(R->AF.B.l&P_FLAG) { R->ICount-=7;M_CALL; } else R->PC.W+=2; break; +case CALL_M: if(R->AF.B.l&S_FLAG) { R->ICount-=7;M_CALL; } else R->PC.W+=2; break; + +case ADD_B: M_ADD(R->BC.B.h);break; +case ADD_C: M_ADD(R->BC.B.l);break; +case ADD_D: M_ADD(R->DE.B.h);break; +case ADD_E: M_ADD(R->DE.B.l);break; +case ADD_H: M_ADD(R->HL.B.h);break; +case ADD_L: M_ADD(R->HL.B.l);break; +case ADD_A: M_ADD(R->AF.B.h);break; +case ADD_xHL: I=RdZ80(R->HL.W);M_ADD(I);break; +case ADD_BYTE: I=RdZ80(R->PC.W++);M_ADD(I);break; + +case SUB_B: M_SUB(R->BC.B.h);break; +case SUB_C: M_SUB(R->BC.B.l);break; +case SUB_D: M_SUB(R->DE.B.h);break; +case SUB_E: M_SUB(R->DE.B.l);break; +case SUB_H: M_SUB(R->HL.B.h);break; +case SUB_L: M_SUB(R->HL.B.l);break; +case SUB_A: R->AF.B.h=0;R->AF.B.l=N_FLAG|Z_FLAG;break; +case SUB_xHL: I=RdZ80(R->HL.W);M_SUB(I);break; +case SUB_BYTE: I=RdZ80(R->PC.W++);M_SUB(I);break; + +case AND_B: M_AND(R->BC.B.h);break; +case AND_C: M_AND(R->BC.B.l);break; +case AND_D: M_AND(R->DE.B.h);break; +case AND_E: M_AND(R->DE.B.l);break; +case AND_H: M_AND(R->HL.B.h);break; +case AND_L: M_AND(R->HL.B.l);break; +case AND_A: M_AND(R->AF.B.h);break; +case AND_xHL: I=RdZ80(R->HL.W);M_AND(I);break; +case AND_BYTE: I=RdZ80(R->PC.W++);M_AND(I);break; + +case OR_B: M_OR(R->BC.B.h);break; +case OR_C: M_OR(R->BC.B.l);break; +case OR_D: M_OR(R->DE.B.h);break; +case OR_E: M_OR(R->DE.B.l);break; +case OR_H: M_OR(R->HL.B.h);break; +case OR_L: M_OR(R->HL.B.l);break; +case OR_A: M_OR(R->AF.B.h);break; +case OR_xHL: I=RdZ80(R->HL.W);M_OR(I);break; +case OR_BYTE: I=RdZ80(R->PC.W++);M_OR(I);break; + +case ADC_B: M_ADC(R->BC.B.h);break; +case ADC_C: M_ADC(R->BC.B.l);break; +case ADC_D: M_ADC(R->DE.B.h);break; +case ADC_E: M_ADC(R->DE.B.l);break; +case ADC_H: M_ADC(R->HL.B.h);break; +case ADC_L: M_ADC(R->HL.B.l);break; +case ADC_A: M_ADC(R->AF.B.h);break; +case ADC_xHL: I=RdZ80(R->HL.W);M_ADC(I);break; +case ADC_BYTE: I=RdZ80(R->PC.W++);M_ADC(I);break; + +case SBC_B: M_SBC(R->BC.B.h);break; +case SBC_C: M_SBC(R->BC.B.l);break; +case SBC_D: M_SBC(R->DE.B.h);break; +case SBC_E: M_SBC(R->DE.B.l);break; +case SBC_H: M_SBC(R->HL.B.h);break; +case SBC_L: M_SBC(R->HL.B.l);break; +case SBC_A: M_SBC(R->AF.B.h);break; +case SBC_xHL: I=RdZ80(R->HL.W);M_SBC(I);break; +case SBC_BYTE: I=RdZ80(R->PC.W++);M_SBC(I);break; + +case XOR_B: M_XOR(R->BC.B.h);break; +case XOR_C: M_XOR(R->BC.B.l);break; +case XOR_D: M_XOR(R->DE.B.h);break; +case XOR_E: M_XOR(R->DE.B.l);break; +case XOR_H: M_XOR(R->HL.B.h);break; +case XOR_L: M_XOR(R->HL.B.l);break; +case XOR_A: R->AF.B.h=0;R->AF.B.l=P_FLAG|Z_FLAG;break; +case XOR_xHL: I=RdZ80(R->HL.W);M_XOR(I);break; +case XOR_BYTE: I=RdZ80(R->PC.W++);M_XOR(I);break; + +case CP_B: M_CP(R->BC.B.h);break; +case CP_C: M_CP(R->BC.B.l);break; +case CP_D: M_CP(R->DE.B.h);break; +case CP_E: M_CP(R->DE.B.l);break; +case CP_H: M_CP(R->HL.B.h);break; +case CP_L: M_CP(R->HL.B.l);break; +case CP_A: R->AF.B.l=N_FLAG|Z_FLAG;break; +case CP_xHL: I=RdZ80(R->HL.W);M_CP(I);break; +case CP_BYTE: I=RdZ80(R->PC.W++);M_CP(I);break; + +case LD_BC_WORD: M_LDWORD(BC);break; +case LD_DE_WORD: M_LDWORD(DE);break; +case LD_HL_WORD: M_LDWORD(HL);break; +case LD_SP_WORD: M_LDWORD(SP);break; + +case LD_PC_HL: R->PC.W=R->HL.W;break; +case LD_SP_HL: R->SP.W=R->HL.W;break; +case LD_A_xBC: R->AF.B.h=RdZ80(R->BC.W);break; +case LD_A_xDE: R->AF.B.h=RdZ80(R->DE.W);break; + +case ADD_HL_BC: M_ADDW(HL,BC);break; +case ADD_HL_DE: M_ADDW(HL,DE);break; +case ADD_HL_HL: M_ADDW(HL,HL);break; +case ADD_HL_SP: M_ADDW(HL,SP);break; + +case DEC_BC: R->BC.W--;break; +case DEC_DE: R->DE.W--;break; +case DEC_HL: R->HL.W--;break; +case DEC_SP: R->SP.W--;break; + +case INC_BC: R->BC.W++;break; +case INC_DE: R->DE.W++;break; +case INC_HL: R->HL.W++;break; +case INC_SP: R->SP.W++;break; + +case DEC_B: M_DEC(R->BC.B.h);break; +case DEC_C: M_DEC(R->BC.B.l);break; +case DEC_D: M_DEC(R->DE.B.h);break; +case DEC_E: M_DEC(R->DE.B.l);break; +case DEC_H: M_DEC(R->HL.B.h);break; +case DEC_L: M_DEC(R->HL.B.l);break; +case DEC_A: M_DEC(R->AF.B.h);break; +case DEC_xHL: I=RdZ80(R->HL.W);M_DEC(I);WrZ80(R->HL.W,I);break; + +case INC_B: M_INC(R->BC.B.h);break; +case INC_C: M_INC(R->BC.B.l);break; +case INC_D: M_INC(R->DE.B.h);break; +case INC_E: M_INC(R->DE.B.l);break; +case INC_H: M_INC(R->HL.B.h);break; +case INC_L: M_INC(R->HL.B.l);break; +case INC_A: M_INC(R->AF.B.h);break; +case INC_xHL: I=RdZ80(R->HL.W);M_INC(I);WrZ80(R->HL.W,I);break; + +case RLCA: + I=R->AF.B.h&0x80? C_FLAG:0; + R->AF.B.h=(R->AF.B.h<<1)|I; + R->AF.B.l=(R->AF.B.l&~(C_FLAG|N_FLAG|H_FLAG))|I; + break; +case RLA: + I=R->AF.B.h&0x80? C_FLAG:0; + R->AF.B.h=(R->AF.B.h<<1)|(R->AF.B.l&C_FLAG); + R->AF.B.l=(R->AF.B.l&~(C_FLAG|N_FLAG|H_FLAG))|I; + break; +case RRCA: + I=R->AF.B.h&0x01; + R->AF.B.h=(R->AF.B.h>>1)|(I? 0x80:0); + R->AF.B.l=(R->AF.B.l&~(C_FLAG|N_FLAG|H_FLAG))|I; + break; +case RRA: + I=R->AF.B.h&0x01; + R->AF.B.h=(R->AF.B.h>>1)|(R->AF.B.l&C_FLAG? 0x80:0); + R->AF.B.l=(R->AF.B.l&~(C_FLAG|N_FLAG|H_FLAG))|I; + break; + +case RST00: M_RST(0x0000);break; +case RST08: M_RST(0x0008);break; +case RST10: M_RST(0x0010);break; +case RST18: M_RST(0x0018);break; +case RST20: M_RST(0x0020);break; +case RST28: M_RST(0x0028);break; +case RST30: M_RST(0x0030);break; +case RST38: M_RST(0x0038);break; + +case PUSH_BC: M_PUSH(BC);break; +case PUSH_DE: M_PUSH(DE);break; +case PUSH_HL: M_PUSH(HL);break; +case PUSH_AF: M_PUSH(AF);break; + +case POP_BC: M_POP(BC);break; +case POP_DE: M_POP(DE);break; +case POP_HL: M_POP(HL);break; +case POP_AF: M_POP(AF);break; + +case DJNZ: if(--R->BC.B.h) { M_JR; } else R->PC.W++;break; +case JP: M_JP;break; +case JR: M_JR;break; +case CALL: M_CALL;break; +case RET: M_RET;break; +case SCF: S(C_FLAG);R(N_FLAG|H_FLAG);break; +case CPL: R->AF.B.h=~R->AF.B.h;S(N_FLAG|H_FLAG);break; +case NOP: break; +case OUTA: OutZ80(RdZ80(R->PC.W++),R->AF.B.h);break; +case INA: R->AF.B.h=InZ80(RdZ80(R->PC.W++));break; +case HALT: R->PC.W--;R->IFF|=0x80;R->ICount=0;break; + +case DI: + R->IFF&=0xFE; + break; +case EI: + R->IFF|=0x01; + if(R->IRequest!=INT_NONE) + { + R->IFF|=0x20; + R->IBackup=R->ICount; + R->ICount=1; + } + break; + +case CCF: + R->AF.B.l^=C_FLAG;R(N_FLAG|H_FLAG); + R->AF.B.l|=R->AF.B.l&C_FLAG? 0:H_FLAG; + break; + +case EXX: + J.W=R->BC.W;R->BC.W=R->BC1.W;R->BC1.W=J.W; + J.W=R->DE.W;R->DE.W=R->DE1.W;R->DE1.W=J.W; + J.W=R->HL.W;R->HL.W=R->HL1.W;R->HL1.W=J.W; + break; + +case EX_DE_HL: J.W=R->DE.W;R->DE.W=R->HL.W;R->HL.W=J.W;break; +case EX_AF_AF: J.W=R->AF.W;R->AF.W=R->AF1.W;R->AF1.W=J.W;break; + +case LD_B_B: R->BC.B.h=R->BC.B.h;break; +case LD_C_B: R->BC.B.l=R->BC.B.h;break; +case LD_D_B: R->DE.B.h=R->BC.B.h;break; +case LD_E_B: R->DE.B.l=R->BC.B.h;break; +case LD_H_B: R->HL.B.h=R->BC.B.h;break; +case LD_L_B: R->HL.B.l=R->BC.B.h;break; +case LD_A_B: R->AF.B.h=R->BC.B.h;break; +case LD_xHL_B: WrZ80(R->HL.W,R->BC.B.h);break; + +case LD_B_C: R->BC.B.h=R->BC.B.l;break; +case LD_C_C: R->BC.B.l=R->BC.B.l;break; +case LD_D_C: R->DE.B.h=R->BC.B.l;break; +case LD_E_C: R->DE.B.l=R->BC.B.l;break; +case LD_H_C: R->HL.B.h=R->BC.B.l;break; +case LD_L_C: R->HL.B.l=R->BC.B.l;break; +case LD_A_C: R->AF.B.h=R->BC.B.l;break; +case LD_xHL_C: WrZ80(R->HL.W,R->BC.B.l);break; + +case LD_B_D: R->BC.B.h=R->DE.B.h;break; +case LD_C_D: R->BC.B.l=R->DE.B.h;break; +case LD_D_D: R->DE.B.h=R->DE.B.h;break; +case LD_E_D: R->DE.B.l=R->DE.B.h;break; +case LD_H_D: R->HL.B.h=R->DE.B.h;break; +case LD_L_D: R->HL.B.l=R->DE.B.h;break; +case LD_A_D: R->AF.B.h=R->DE.B.h;break; +case LD_xHL_D: WrZ80(R->HL.W,R->DE.B.h);break; + +case LD_B_E: R->BC.B.h=R->DE.B.l;break; +case LD_C_E: R->BC.B.l=R->DE.B.l;break; +case LD_D_E: R->DE.B.h=R->DE.B.l;break; +case LD_E_E: R->DE.B.l=R->DE.B.l;break; +case LD_H_E: R->HL.B.h=R->DE.B.l;break; +case LD_L_E: R->HL.B.l=R->DE.B.l;break; +case LD_A_E: R->AF.B.h=R->DE.B.l;break; +case LD_xHL_E: WrZ80(R->HL.W,R->DE.B.l);break; + +case LD_B_H: R->BC.B.h=R->HL.B.h;break; +case LD_C_H: R->BC.B.l=R->HL.B.h;break; +case LD_D_H: R->DE.B.h=R->HL.B.h;break; +case LD_E_H: R->DE.B.l=R->HL.B.h;break; +case LD_H_H: R->HL.B.h=R->HL.B.h;break; +case LD_L_H: R->HL.B.l=R->HL.B.h;break; +case LD_A_H: R->AF.B.h=R->HL.B.h;break; +case LD_xHL_H: WrZ80(R->HL.W,R->HL.B.h);break; + +case LD_B_L: R->BC.B.h=R->HL.B.l;break; +case LD_C_L: R->BC.B.l=R->HL.B.l;break; +case LD_D_L: R->DE.B.h=R->HL.B.l;break; +case LD_E_L: R->DE.B.l=R->HL.B.l;break; +case LD_H_L: R->HL.B.h=R->HL.B.l;break; +case LD_L_L: R->HL.B.l=R->HL.B.l;break; +case LD_A_L: R->AF.B.h=R->HL.B.l;break; +case LD_xHL_L: WrZ80(R->HL.W,R->HL.B.l);break; + +case LD_B_A: R->BC.B.h=R->AF.B.h;break; +case LD_C_A: R->BC.B.l=R->AF.B.h;break; +case LD_D_A: R->DE.B.h=R->AF.B.h;break; +case LD_E_A: R->DE.B.l=R->AF.B.h;break; +case LD_H_A: R->HL.B.h=R->AF.B.h;break; +case LD_L_A: R->HL.B.l=R->AF.B.h;break; +case LD_A_A: R->AF.B.h=R->AF.B.h;break; +case LD_xHL_A: WrZ80(R->HL.W,R->AF.B.h);break; + +case LD_xBC_A: WrZ80(R->BC.W,R->AF.B.h);break; +case LD_xDE_A: WrZ80(R->DE.W,R->AF.B.h);break; + +case LD_B_xHL: R->BC.B.h=RdZ80(R->HL.W);break; +case LD_C_xHL: R->BC.B.l=RdZ80(R->HL.W);break; +case LD_D_xHL: R->DE.B.h=RdZ80(R->HL.W);break; +case LD_E_xHL: R->DE.B.l=RdZ80(R->HL.W);break; +case LD_H_xHL: R->HL.B.h=RdZ80(R->HL.W);break; +case LD_L_xHL: R->HL.B.l=RdZ80(R->HL.W);break; +case LD_A_xHL: R->AF.B.h=RdZ80(R->HL.W);break; + +case LD_B_BYTE: R->BC.B.h=RdZ80(R->PC.W++);break; +case LD_C_BYTE: R->BC.B.l=RdZ80(R->PC.W++);break; +case LD_D_BYTE: R->DE.B.h=RdZ80(R->PC.W++);break; +case LD_E_BYTE: R->DE.B.l=RdZ80(R->PC.W++);break; +case LD_H_BYTE: R->HL.B.h=RdZ80(R->PC.W++);break; +case LD_L_BYTE: R->HL.B.l=RdZ80(R->PC.W++);break; +case LD_A_BYTE: R->AF.B.h=RdZ80(R->PC.W++);break; +case LD_xHL_BYTE: WrZ80(R->HL.W,RdZ80(R->PC.W++));break; + +case LD_xWORD_HL: + J.B.l=RdZ80(R->PC.W++); + J.B.h=RdZ80(R->PC.W++); + WrZ80(J.W++,R->HL.B.l); + WrZ80(J.W,R->HL.B.h); + break; + +case LD_HL_xWORD: + J.B.l=RdZ80(R->PC.W++); + J.B.h=RdZ80(R->PC.W++); + R->HL.B.l=RdZ80(J.W++); + R->HL.B.h=RdZ80(J.W); + break; + +case LD_A_xWORD: + J.B.l=RdZ80(R->PC.W++); + J.B.h=RdZ80(R->PC.W++); + R->AF.B.h=RdZ80(J.W); + break; + +case LD_xWORD_A: + J.B.l=RdZ80(R->PC.W++); + J.B.h=RdZ80(R->PC.W++); + WrZ80(J.W,R->AF.B.h); + break; + +case EX_HL_xSP: + J.B.l=RdZ80(R->SP.W);WrZ80(R->SP.W++,R->HL.B.l); + J.B.h=RdZ80(R->SP.W);WrZ80(R->SP.W--,R->HL.B.h); + R->HL.W=J.W; + break; + +case DAA: + J.W=R->AF.B.h; + if(R->AF.B.l&C_FLAG) J.W|=256; + if(R->AF.B.l&H_FLAG) J.W|=512; + if(R->AF.B.l&N_FLAG) J.W|=1024; + R->AF.W=DAATable[J.W]; + break; + +default: + if(R->TrapBadOps) + printf + ( + "[Z80 %lX] Unrecognized instruction: %02X at PC=%04X\n", + (long)R->User,RdZ80(R->PC.W-1),R->PC.W-1 + ); + break; diff --git a/TIKI-100_emul-src/CodesCB.h b/TIKI-100_emul-src/CodesCB.h new file mode 100644 index 0000000..ef829cb --- /dev/null +++ b/TIKI-100_emul-src/CodesCB.h @@ -0,0 +1,204 @@ +/** Z80: portable Z80 emulator *******************************/ +/** **/ +/** CodesCB.h **/ +/** **/ +/** This file contains implementation for the CB table of **/ +/** Z80 commands. It is included from Z80.c. **/ +/** **/ +/** Copyright (C) Marat Fayzullin 1994,1995,1996,1997 **/ +/** You are not allowed to distribute this software **/ +/** commercially. Please, notify me, if you make any **/ +/** changes to this file. **/ +/*************************************************************/ + +case RLC_B: M_RLC(R->BC.B.h);break; case RLC_C: M_RLC(R->BC.B.l);break; +case RLC_D: M_RLC(R->DE.B.h);break; case RLC_E: M_RLC(R->DE.B.l);break; +case RLC_H: M_RLC(R->HL.B.h);break; case RLC_L: M_RLC(R->HL.B.l);break; +case RLC_xHL: I=RdZ80(R->HL.W);M_RLC(I);WrZ80(R->HL.W,I);break; +case RLC_A: M_RLC(R->AF.B.h);break; + +case RRC_B: M_RRC(R->BC.B.h);break; case RRC_C: M_RRC(R->BC.B.l);break; +case RRC_D: M_RRC(R->DE.B.h);break; case RRC_E: M_RRC(R->DE.B.l);break; +case RRC_H: M_RRC(R->HL.B.h);break; case RRC_L: M_RRC(R->HL.B.l);break; +case RRC_xHL: I=RdZ80(R->HL.W);M_RRC(I);WrZ80(R->HL.W,I);break; +case RRC_A: M_RRC(R->AF.B.h);break; + +case RL_B: M_RL(R->BC.B.h);break; case RL_C: M_RL(R->BC.B.l);break; +case RL_D: M_RL(R->DE.B.h);break; case RL_E: M_RL(R->DE.B.l);break; +case RL_H: M_RL(R->HL.B.h);break; case RL_L: M_RL(R->HL.B.l);break; +case RL_xHL: I=RdZ80(R->HL.W);M_RL(I);WrZ80(R->HL.W,I);break; +case RL_A: M_RL(R->AF.B.h);break; + +case RR_B: M_RR(R->BC.B.h);break; case RR_C: M_RR(R->BC.B.l);break; +case RR_D: M_RR(R->DE.B.h);break; case RR_E: M_RR(R->DE.B.l);break; +case RR_H: M_RR(R->HL.B.h);break; case RR_L: M_RR(R->HL.B.l);break; +case RR_xHL: I=RdZ80(R->HL.W);M_RR(I);WrZ80(R->HL.W,I);break; +case RR_A: M_RR(R->AF.B.h);break; + +case SLA_B: M_SLA(R->BC.B.h);break; case SLA_C: M_SLA(R->BC.B.l);break; +case SLA_D: M_SLA(R->DE.B.h);break; case SLA_E: M_SLA(R->DE.B.l);break; +case SLA_H: M_SLA(R->HL.B.h);break; case SLA_L: M_SLA(R->HL.B.l);break; +case SLA_xHL: I=RdZ80(R->HL.W);M_SLA(I);WrZ80(R->HL.W,I);break; +case SLA_A: M_SLA(R->AF.B.h);break; + +case SRA_B: M_SRA(R->BC.B.h);break; case SRA_C: M_SRA(R->BC.B.l);break; +case SRA_D: M_SRA(R->DE.B.h);break; case SRA_E: M_SRA(R->DE.B.l);break; +case SRA_H: M_SRA(R->HL.B.h);break; case SRA_L: M_SRA(R->HL.B.l);break; +case SRA_xHL: I=RdZ80(R->HL.W);M_SRA(I);WrZ80(R->HL.W,I);break; +case SRA_A: M_SRA(R->AF.B.h);break; + +case SLL_B: M_SLL(R->BC.B.h);break; case SLL_C: M_SLL(R->BC.B.l);break; +case SLL_D: M_SLL(R->DE.B.h);break; case SLL_E: M_SLL(R->DE.B.l);break; +case SLL_H: M_SLL(R->HL.B.h);break; case SLL_L: M_SLL(R->HL.B.l);break; +case SLL_xHL: I=RdZ80(R->HL.W);M_SLL(I);WrZ80(R->HL.W,I);break; +case SLL_A: M_SLL(R->AF.B.h);break; + +case SRL_B: M_SRL(R->BC.B.h);break; case SRL_C: M_SRL(R->BC.B.l);break; +case SRL_D: M_SRL(R->DE.B.h);break; case SRL_E: M_SRL(R->DE.B.l);break; +case SRL_H: M_SRL(R->HL.B.h);break; case SRL_L: M_SRL(R->HL.B.l);break; +case SRL_xHL: I=RdZ80(R->HL.W);M_SRL(I);WrZ80(R->HL.W,I);break; +case SRL_A: M_SRL(R->AF.B.h);break; + +case BIT0_B: M_BIT(0,R->BC.B.h);break; case BIT0_C: M_BIT(0,R->BC.B.l);break; +case BIT0_D: M_BIT(0,R->DE.B.h);break; case BIT0_E: M_BIT(0,R->DE.B.l);break; +case BIT0_H: M_BIT(0,R->HL.B.h);break; case BIT0_L: M_BIT(0,R->HL.B.l);break; +case BIT0_xHL: I=RdZ80(R->HL.W);M_BIT(0,I);break; +case BIT0_A: M_BIT(0,R->AF.B.h);break; + +case BIT1_B: M_BIT(1,R->BC.B.h);break; case BIT1_C: M_BIT(1,R->BC.B.l);break; +case BIT1_D: M_BIT(1,R->DE.B.h);break; case BIT1_E: M_BIT(1,R->DE.B.l);break; +case BIT1_H: M_BIT(1,R->HL.B.h);break; case BIT1_L: M_BIT(1,R->HL.B.l);break; +case BIT1_xHL: I=RdZ80(R->HL.W);M_BIT(1,I);break; +case BIT1_A: M_BIT(1,R->AF.B.h);break; + +case BIT2_B: M_BIT(2,R->BC.B.h);break; case BIT2_C: M_BIT(2,R->BC.B.l);break; +case BIT2_D: M_BIT(2,R->DE.B.h);break; case BIT2_E: M_BIT(2,R->DE.B.l);break; +case BIT2_H: M_BIT(2,R->HL.B.h);break; case BIT2_L: M_BIT(2,R->HL.B.l);break; +case BIT2_xHL: I=RdZ80(R->HL.W);M_BIT(2,I);break; +case BIT2_A: M_BIT(2,R->AF.B.h);break; + +case BIT3_B: M_BIT(3,R->BC.B.h);break; case BIT3_C: M_BIT(3,R->BC.B.l);break; +case BIT3_D: M_BIT(3,R->DE.B.h);break; case BIT3_E: M_BIT(3,R->DE.B.l);break; +case BIT3_H: M_BIT(3,R->HL.B.h);break; case BIT3_L: M_BIT(3,R->HL.B.l);break; +case BIT3_xHL: I=RdZ80(R->HL.W);M_BIT(3,I);break; +case BIT3_A: M_BIT(3,R->AF.B.h);break; + +case BIT4_B: M_BIT(4,R->BC.B.h);break; case BIT4_C: M_BIT(4,R->BC.B.l);break; +case BIT4_D: M_BIT(4,R->DE.B.h);break; case BIT4_E: M_BIT(4,R->DE.B.l);break; +case BIT4_H: M_BIT(4,R->HL.B.h);break; case BIT4_L: M_BIT(4,R->HL.B.l);break; +case BIT4_xHL: I=RdZ80(R->HL.W);M_BIT(4,I);break; +case BIT4_A: M_BIT(4,R->AF.B.h);break; + +case BIT5_B: M_BIT(5,R->BC.B.h);break; case BIT5_C: M_BIT(5,R->BC.B.l);break; +case BIT5_D: M_BIT(5,R->DE.B.h);break; case BIT5_E: M_BIT(5,R->DE.B.l);break; +case BIT5_H: M_BIT(5,R->HL.B.h);break; case BIT5_L: M_BIT(5,R->HL.B.l);break; +case BIT5_xHL: I=RdZ80(R->HL.W);M_BIT(5,I);break; +case BIT5_A: M_BIT(5,R->AF.B.h);break; + +case BIT6_B: M_BIT(6,R->BC.B.h);break; case BIT6_C: M_BIT(6,R->BC.B.l);break; +case BIT6_D: M_BIT(6,R->DE.B.h);break; case BIT6_E: M_BIT(6,R->DE.B.l);break; +case BIT6_H: M_BIT(6,R->HL.B.h);break; case BIT6_L: M_BIT(6,R->HL.B.l);break; +case BIT6_xHL: I=RdZ80(R->HL.W);M_BIT(6,I);break; +case BIT6_A: M_BIT(6,R->AF.B.h);break; + +case BIT7_B: M_BIT(7,R->BC.B.h);break; case BIT7_C: M_BIT(7,R->BC.B.l);break; +case BIT7_D: M_BIT(7,R->DE.B.h);break; case BIT7_E: M_BIT(7,R->DE.B.l);break; +case BIT7_H: M_BIT(7,R->HL.B.h);break; case BIT7_L: M_BIT(7,R->HL.B.l);break; +case BIT7_xHL: I=RdZ80(R->HL.W);M_BIT(7,I);break; +case BIT7_A: M_BIT(7,R->AF.B.h);break; + +case RES0_B: M_RES(0,R->BC.B.h);break; case RES0_C: M_RES(0,R->BC.B.l);break; +case RES0_D: M_RES(0,R->DE.B.h);break; case RES0_E: M_RES(0,R->DE.B.l);break; +case RES0_H: M_RES(0,R->HL.B.h);break; case RES0_L: M_RES(0,R->HL.B.l);break; +case RES0_xHL: I=RdZ80(R->HL.W);M_RES(0,I);WrZ80(R->HL.W,I);break; +case RES0_A: M_RES(0,R->AF.B.h);break; + +case RES1_B: M_RES(1,R->BC.B.h);break; case RES1_C: M_RES(1,R->BC.B.l);break; +case RES1_D: M_RES(1,R->DE.B.h);break; case RES1_E: M_RES(1,R->DE.B.l);break; +case RES1_H: M_RES(1,R->HL.B.h);break; case RES1_L: M_RES(1,R->HL.B.l);break; +case RES1_xHL: I=RdZ80(R->HL.W);M_RES(1,I);WrZ80(R->HL.W,I);break; +case RES1_A: M_RES(1,R->AF.B.h);break; + +case RES2_B: M_RES(2,R->BC.B.h);break; case RES2_C: M_RES(2,R->BC.B.l);break; +case RES2_D: M_RES(2,R->DE.B.h);break; case RES2_E: M_RES(2,R->DE.B.l);break; +case RES2_H: M_RES(2,R->HL.B.h);break; case RES2_L: M_RES(2,R->HL.B.l);break; +case RES2_xHL: I=RdZ80(R->HL.W);M_RES(2,I);WrZ80(R->HL.W,I);break; +case RES2_A: M_RES(2,R->AF.B.h);break; + +case RES3_B: M_RES(3,R->BC.B.h);break; case RES3_C: M_RES(3,R->BC.B.l);break; +case RES3_D: M_RES(3,R->DE.B.h);break; case RES3_E: M_RES(3,R->DE.B.l);break; +case RES3_H: M_RES(3,R->HL.B.h);break; case RES3_L: M_RES(3,R->HL.B.l);break; +case RES3_xHL: I=RdZ80(R->HL.W);M_RES(3,I);WrZ80(R->HL.W,I);break; +case RES3_A: M_RES(3,R->AF.B.h);break; + +case RES4_B: M_RES(4,R->BC.B.h);break; case RES4_C: M_RES(4,R->BC.B.l);break; +case RES4_D: M_RES(4,R->DE.B.h);break; case RES4_E: M_RES(4,R->DE.B.l);break; +case RES4_H: M_RES(4,R->HL.B.h);break; case RES4_L: M_RES(4,R->HL.B.l);break; +case RES4_xHL: I=RdZ80(R->HL.W);M_RES(4,I);WrZ80(R->HL.W,I);break; +case RES4_A: M_RES(4,R->AF.B.h);break; + +case RES5_B: M_RES(5,R->BC.B.h);break; case RES5_C: M_RES(5,R->BC.B.l);break; +case RES5_D: M_RES(5,R->DE.B.h);break; case RES5_E: M_RES(5,R->DE.B.l);break; +case RES5_H: M_RES(5,R->HL.B.h);break; case RES5_L: M_RES(5,R->HL.B.l);break; +case RES5_xHL: I=RdZ80(R->HL.W);M_RES(5,I);WrZ80(R->HL.W,I);break; +case RES5_A: M_RES(5,R->AF.B.h);break; + +case RES6_B: M_RES(6,R->BC.B.h);break; case RES6_C: M_RES(6,R->BC.B.l);break; +case RES6_D: M_RES(6,R->DE.B.h);break; case RES6_E: M_RES(6,R->DE.B.l);break; +case RES6_H: M_RES(6,R->HL.B.h);break; case RES6_L: M_RES(6,R->HL.B.l);break; +case RES6_xHL: I=RdZ80(R->HL.W);M_RES(6,I);WrZ80(R->HL.W,I);break; +case RES6_A: M_RES(6,R->AF.B.h);break; + +case RES7_B: M_RES(7,R->BC.B.h);break; case RES7_C: M_RES(7,R->BC.B.l);break; +case RES7_D: M_RES(7,R->DE.B.h);break; case RES7_E: M_RES(7,R->DE.B.l);break; +case RES7_H: M_RES(7,R->HL.B.h);break; case RES7_L: M_RES(7,R->HL.B.l);break; +case RES7_xHL: I=RdZ80(R->HL.W);M_RES(7,I);WrZ80(R->HL.W,I);break; +case RES7_A: M_RES(7,R->AF.B.h);break; + +case SET0_B: M_SET(0,R->BC.B.h);break; case SET0_C: M_SET(0,R->BC.B.l);break; +case SET0_D: M_SET(0,R->DE.B.h);break; case SET0_E: M_SET(0,R->DE.B.l);break; +case SET0_H: M_SET(0,R->HL.B.h);break; case SET0_L: M_SET(0,R->HL.B.l);break; +case SET0_xHL: I=RdZ80(R->HL.W);M_SET(0,I);WrZ80(R->HL.W,I);break; +case SET0_A: M_SET(0,R->AF.B.h);break; + +case SET1_B: M_SET(1,R->BC.B.h);break; case SET1_C: M_SET(1,R->BC.B.l);break; +case SET1_D: M_SET(1,R->DE.B.h);break; case SET1_E: M_SET(1,R->DE.B.l);break; +case SET1_H: M_SET(1,R->HL.B.h);break; case SET1_L: M_SET(1,R->HL.B.l);break; +case SET1_xHL: I=RdZ80(R->HL.W);M_SET(1,I);WrZ80(R->HL.W,I);break; +case SET1_A: M_SET(1,R->AF.B.h);break; + +case SET2_B: M_SET(2,R->BC.B.h);break; case SET2_C: M_SET(2,R->BC.B.l);break; +case SET2_D: M_SET(2,R->DE.B.h);break; case SET2_E: M_SET(2,R->DE.B.l);break; +case SET2_H: M_SET(2,R->HL.B.h);break; case SET2_L: M_SET(2,R->HL.B.l);break; +case SET2_xHL: I=RdZ80(R->HL.W);M_SET(2,I);WrZ80(R->HL.W,I);break; +case SET2_A: M_SET(2,R->AF.B.h);break; + +case SET3_B: M_SET(3,R->BC.B.h);break; case SET3_C: M_SET(3,R->BC.B.l);break; +case SET3_D: M_SET(3,R->DE.B.h);break; case SET3_E: M_SET(3,R->DE.B.l);break; +case SET3_H: M_SET(3,R->HL.B.h);break; case SET3_L: M_SET(3,R->HL.B.l);break; +case SET3_xHL: I=RdZ80(R->HL.W);M_SET(3,I);WrZ80(R->HL.W,I);break; +case SET3_A: M_SET(3,R->AF.B.h);break; + +case SET4_B: M_SET(4,R->BC.B.h);break; case SET4_C: M_SET(4,R->BC.B.l);break; +case SET4_D: M_SET(4,R->DE.B.h);break; case SET4_E: M_SET(4,R->DE.B.l);break; +case SET4_H: M_SET(4,R->HL.B.h);break; case SET4_L: M_SET(4,R->HL.B.l);break; +case SET4_xHL: I=RdZ80(R->HL.W);M_SET(4,I);WrZ80(R->HL.W,I);break; +case SET4_A: M_SET(4,R->AF.B.h);break; + +case SET5_B: M_SET(5,R->BC.B.h);break; case SET5_C: M_SET(5,R->BC.B.l);break; +case SET5_D: M_SET(5,R->DE.B.h);break; case SET5_E: M_SET(5,R->DE.B.l);break; +case SET5_H: M_SET(5,R->HL.B.h);break; case SET5_L: M_SET(5,R->HL.B.l);break; +case SET5_xHL: I=RdZ80(R->HL.W);M_SET(5,I);WrZ80(R->HL.W,I);break; +case SET5_A: M_SET(5,R->AF.B.h);break; + +case SET6_B: M_SET(6,R->BC.B.h);break; case SET6_C: M_SET(6,R->BC.B.l);break; +case SET6_D: M_SET(6,R->DE.B.h);break; case SET6_E: M_SET(6,R->DE.B.l);break; +case SET6_H: M_SET(6,R->HL.B.h);break; case SET6_L: M_SET(6,R->HL.B.l);break; +case SET6_xHL: I=RdZ80(R->HL.W);M_SET(6,I);WrZ80(R->HL.W,I);break; +case SET6_A: M_SET(6,R->AF.B.h);break; + +case SET7_B: M_SET(7,R->BC.B.h);break; case SET7_C: M_SET(7,R->BC.B.l);break; +case SET7_D: M_SET(7,R->DE.B.h);break; case SET7_E: M_SET(7,R->DE.B.l);break; +case SET7_H: M_SET(7,R->HL.B.h);break; case SET7_L: M_SET(7,R->HL.B.l);break; +case SET7_xHL: I=RdZ80(R->HL.W);M_SET(7,I);WrZ80(R->HL.W,I);break; +case SET7_A: M_SET(7,R->AF.B.h);break; diff --git a/TIKI-100_emul-src/CodesED.h b/TIKI-100_emul-src/CodesED.h new file mode 100644 index 0000000..ab0fc34 --- /dev/null +++ b/TIKI-100_emul-src/CodesED.h @@ -0,0 +1,281 @@ +/** Z80: portable Z80 emulator *******************************/ +/** **/ +/** CodesED.h **/ +/** **/ +/** This file contains implementation for the ED table of **/ +/** Z80 commands. It is included from Z80.c. **/ +/** **/ +/** Copyright (C) Marat Fayzullin 1994,1995,1996,1997 **/ +/** You are not allowed to distribute this software **/ +/** commercially. Please, notify me, if you make any **/ +/** changes to this file. **/ +/*************************************************************/ + +/** This is a special patch for emulating BIOS calls: ********/ +case DB_FE: PatchZ80(R);break; +/*************************************************************/ + +case ADC_HL_BC: M_ADCW(BC);break; +case ADC_HL_DE: M_ADCW(DE);break; +case ADC_HL_HL: M_ADCW(HL);break; +case ADC_HL_SP: M_ADCW(SP);break; + +case SBC_HL_BC: M_SBCW(BC);break; +case SBC_HL_DE: M_SBCW(DE);break; +case SBC_HL_HL: M_SBCW(HL);break; +case SBC_HL_SP: M_SBCW(SP);break; + +case LD_xWORDe_HL: + J.B.l=RdZ80(R->PC.W++); + J.B.h=RdZ80(R->PC.W++); + WrZ80(J.W++,R->HL.B.l); + WrZ80(J.W,R->HL.B.h); + break; +case LD_xWORDe_DE: + J.B.l=RdZ80(R->PC.W++); + J.B.h=RdZ80(R->PC.W++); + WrZ80(J.W++,R->DE.B.l); + WrZ80(J.W,R->DE.B.h); + break; +case LD_xWORDe_BC: + J.B.l=RdZ80(R->PC.W++); + J.B.h=RdZ80(R->PC.W++); + WrZ80(J.W++,R->BC.B.l); + WrZ80(J.W,R->BC.B.h); + break; +case LD_xWORDe_SP: + J.B.l=RdZ80(R->PC.W++); + J.B.h=RdZ80(R->PC.W++); + WrZ80(J.W++,R->SP.B.l); + WrZ80(J.W,R->SP.B.h); + break; + +case LD_HL_xWORDe: + J.B.l=RdZ80(R->PC.W++); + J.B.h=RdZ80(R->PC.W++); + R->HL.B.l=RdZ80(J.W++); + R->HL.B.h=RdZ80(J.W); + break; +case LD_DE_xWORDe: + J.B.l=RdZ80(R->PC.W++); + J.B.h=RdZ80(R->PC.W++); + R->DE.B.l=RdZ80(J.W++); + R->DE.B.h=RdZ80(J.W); + break; +case LD_BC_xWORDe: + J.B.l=RdZ80(R->PC.W++); + J.B.h=RdZ80(R->PC.W++); + R->BC.B.l=RdZ80(J.W++); + R->BC.B.h=RdZ80(J.W); + break; +case LD_SP_xWORDe: + J.B.l=RdZ80(R->PC.W++); + J.B.h=RdZ80(R->PC.W++); + R->SP.B.l=RdZ80(J.W++); + R->SP.B.h=RdZ80(J.W); + break; + +case RRD: + I=RdZ80(R->HL.W); + J.B.l=(I>>4)|(R->AF.B.h<<4); + WrZ80(R->HL.W,J.B.l); + R->AF.B.h=(I&0x0F)|(R->AF.B.h&0xF0); + R->AF.B.l=PZSTable[R->AF.B.h]|(R->AF.B.l&C_FLAG); + break; +case RLD: + I=RdZ80(R->HL.W); + J.B.l=(I<<4)|(R->AF.B.h&0x0F); + WrZ80(R->HL.W,J.B.l); + R->AF.B.h=(I>>4)|(R->AF.B.h&0xF0); + R->AF.B.l=PZSTable[R->AF.B.h]|(R->AF.B.l&C_FLAG); + break; + +case LD_A_I: + R->AF.B.h=R->I; + R->AF.B.l=(R->AF.B.l&C_FLAG)|(R->IFF&1? P_FLAG:0)|ZSTable[R->AF.B.h]; + break; + +case LD_A_R: + R->AF.B.h=(byte)(-R->ICount&0xFF); + R->AF.B.l=(R->AF.B.l&C_FLAG)|(R->IFF&1? P_FLAG:0)|ZSTable[R->AF.B.h]; + break; + +case LD_I_A: R->I=R->AF.B.h;break; +case LD_R_A: break; + +case IM_0: R->IFF&=0xF9;break; +case IM_1: R->IFF=(R->IFF&0xF9)|2;break; +case IM_2: R->IFF=(R->IFF&0xF9)|4;break; + +case RETI: M_RET;break; +case RETN: if(R->IFF&0x40) R->IFF|=0x01; else R->IFF&=0xFE; + M_RET;break; + +case NEG: I=R->AF.B.h;R->AF.B.h=0;M_SUB(I);break; + +case IN_B_xC: M_IN(R->BC.B.h);break; +case IN_C_xC: M_IN(R->BC.B.l);break; +case IN_D_xC: M_IN(R->DE.B.h);break; +case IN_E_xC: M_IN(R->DE.B.l);break; +case IN_H_xC: M_IN(R->HL.B.h);break; +case IN_L_xC: M_IN(R->HL.B.l);break; +case IN_A_xC: M_IN(R->AF.B.h);break; +case IN_F_xC: M_IN(J.B.l);break; + +case OUT_xC_B: OutZ80(R->BC.B.l,R->BC.B.h);break; +case OUT_xC_C: OutZ80(R->BC.B.l,R->BC.B.l);break; +case OUT_xC_D: OutZ80(R->BC.B.l,R->DE.B.h);break; +case OUT_xC_E: OutZ80(R->BC.B.l,R->DE.B.l);break; +case OUT_xC_H: OutZ80(R->BC.B.l,R->HL.B.h);break; +case OUT_xC_L: OutZ80(R->BC.B.l,R->HL.B.l);break; +case OUT_xC_A: OutZ80(R->BC.B.l,R->AF.B.h);break; + +case INI: + WrZ80(R->HL.W++,InZ80(R->BC.B.l)); + R->BC.B.h--; + R->AF.B.l=N_FLAG|(R->BC.B.h? 0:Z_FLAG); + break; + +case INIR: + do + { + WrZ80(R->HL.W++,InZ80(R->BC.B.l)); + R->BC.B.h--;R->ICount-=21; + } + while(R->BC.B.h&&(R->ICount>0)); + if(R->BC.B.h) { R->AF.B.l=N_FLAG;R->PC.W-=2; } + else { R->AF.B.l=Z_FLAG|N_FLAG;R->ICount+=5; } + break; + +case IND: + WrZ80(R->HL.W--,InZ80(R->BC.B.l)); + R->BC.B.h--; + R->AF.B.l=N_FLAG|(R->BC.B.h? 0:Z_FLAG); + break; + +case INDR: + do + { + WrZ80(R->HL.W--,InZ80(R->BC.B.l)); + R->BC.B.h--;R->ICount-=21; + } + while(R->BC.B.h&&(R->ICount>0)); + if(R->BC.B.h) { R->AF.B.l=N_FLAG;R->PC.W-=2; } + else { R->AF.B.l=Z_FLAG|N_FLAG;R->ICount+=5; } + break; + +case OUTI: + OutZ80(R->BC.B.l,RdZ80(R->HL.W++)); + R->BC.B.h--; + R->AF.B.l=N_FLAG|(R->BC.B.h? 0:Z_FLAG); + break; + +case OTIR: + do + { + OutZ80(R->BC.B.l,RdZ80(R->HL.W++)); + R->BC.B.h--;R->ICount-=21; + } + while(R->BC.B.h&&(R->ICount>0)); + if(R->BC.B.h) { R->AF.B.l=N_FLAG;R->PC.W-=2; } + else { R->AF.B.l=Z_FLAG|N_FLAG;R->ICount+=5; } + break; + +case OUTD: + OutZ80(R->BC.B.l,RdZ80(R->HL.W--)); + R->BC.B.h--; + R->AF.B.l=N_FLAG|(R->BC.B.h? 0:Z_FLAG); + break; + +case OTDR: + do + { + OutZ80(R->BC.B.l,RdZ80(R->HL.W--)); + R->BC.B.h--;R->ICount-=21; + } + while(R->BC.B.h&&(R->ICount>0)); + if(R->BC.B.h) { R->AF.B.l=N_FLAG;R->PC.W-=2; } + else { R->AF.B.l=Z_FLAG|N_FLAG;R->ICount+=5; } + break; + +case LDI: + WrZ80(R->DE.W++,RdZ80(R->HL.W++)); + R->BC.W--; + R->AF.B.l=(R->AF.B.l&~(N_FLAG|H_FLAG|P_FLAG))|(R->BC.W? P_FLAG:0); + break; + +case LDIR: + do + { + WrZ80(R->DE.W++,RdZ80(R->HL.W++)); + R->BC.W--;R->ICount-=21; + } + while(R->BC.W&&(R->ICount>0)); + R->AF.B.l&=~(N_FLAG|H_FLAG|P_FLAG); + if(R->BC.W) { R->AF.B.l|=N_FLAG;R->PC.W-=2; } + else R->ICount+=5; + break; + +case LDD: + WrZ80(R->DE.W--,RdZ80(R->HL.W--)); + R->BC.W--; + R->AF.B.l=(R->AF.B.l&~(N_FLAG|H_FLAG|P_FLAG))|(R->BC.W? P_FLAG:0); + break; + +case LDDR: + do + { + WrZ80(R->DE.W--,RdZ80(R->HL.W--)); + R->BC.W--;R->ICount-=21; + } + while(R->BC.W&&(R->ICount>0)); + R->AF.B.l&=~(N_FLAG|H_FLAG|P_FLAG); + if(R->BC.W) { R->AF.B.l|=N_FLAG;R->PC.W-=2; } + else R->ICount+=5; + break; + +case CPI: + I=RdZ80(R->HL.W++); + J.B.l=R->AF.B.h-I; + R->BC.W--; + R->AF.B.l = + N_FLAG|(R->AF.B.l&C_FLAG)|ZSTable[J.B.l]| + ((R->AF.B.h^I^J.B.l)&H_FLAG)|(R->BC.W? P_FLAG:0); + break; + +case CPIR: + do + { + I=RdZ80(R->HL.W++); + J.B.l=R->AF.B.h-I; + R->BC.W--;R->ICount-=21; + } + while(R->BC.W&&J.B.l&&(R->ICount>0)); + R->AF.B.l = + N_FLAG|(R->AF.B.l&C_FLAG)|ZSTable[J.B.l]| + ((R->AF.B.h^I^J.B.l)&H_FLAG)|(R->BC.W? P_FLAG:0); + if(R->BC.W&&J.B.l) R->PC.W-=2; else R->ICount+=5; + break; + +case CPD: + I=RdZ80(R->HL.W--); + J.B.l=R->AF.B.h-I; + R->BC.W--; + R->AF.B.l = + N_FLAG|(R->AF.B.l&C_FLAG)|ZSTable[J.B.l]| + ((R->AF.B.h^I^J.B.l)&H_FLAG)|(R->BC.W? P_FLAG:0); + break; + +case CPDR: + do + { + I=RdZ80(R->HL.W--); + J.B.l=R->AF.B.h-I; + R->BC.W--;R->ICount-=21; + } + while(R->BC.W&&J.B.l); + R->AF.B.l = + N_FLAG|(R->AF.B.l&C_FLAG)|ZSTable[J.B.l]| + ((R->AF.B.h^I^J.B.l)&H_FLAG)|(R->BC.W? P_FLAG:0); + if(R->BC.W&&J.B.l) R->PC.W-=2; else R->ICount+=5; + break; diff --git a/TIKI-100_emul-src/CodesXCB.h b/TIKI-100_emul-src/CodesXCB.h new file mode 100644 index 0000000..0a87e78 --- /dev/null +++ b/TIKI-100_emul-src/CodesXCB.h @@ -0,0 +1,64 @@ +/** Z80: portable Z80 emulator *******************************/ +/** **/ +/** CodesXCB.h **/ +/** **/ +/** This file contains implementation for FD/DD-CB tables **/ +/** of Z80 commands. It is included from Z80.c. **/ +/** **/ +/** Copyright (C) Marat Fayzullin 1994,1995,1996,1997 **/ +/** You are not allowed to distribute this software **/ +/** commercially. Please, notify me, if you make any **/ +/** changes to this file. **/ +/*************************************************************/ + +case RLC_xHL: I=RdZ80(J.W);M_RLC(I);WrZ80(J.W,I);break; +case RRC_xHL: I=RdZ80(J.W);M_RRC(I);WrZ80(J.W,I);break; +case RL_xHL: I=RdZ80(J.W);M_RL(I);WrZ80(J.W,I);break; +case RR_xHL: I=RdZ80(J.W);M_RR(I);WrZ80(J.W,I);break; +case SLA_xHL: I=RdZ80(J.W);M_SLA(I);WrZ80(J.W,I);break; +case SRA_xHL: I=RdZ80(J.W);M_SRA(I);WrZ80(J.W,I);break; +case SLL_xHL: I=RdZ80(J.W);M_SLL(I);WrZ80(J.W,I);break; +case SRL_xHL: I=RdZ80(J.W);M_SRL(I);WrZ80(J.W,I);break; + +case BIT0_B: case BIT0_C: case BIT0_D: case BIT0_E: +case BIT0_H: case BIT0_L: case BIT0_A: +case BIT0_xHL: I=RdZ80(J.W);M_BIT(0,I);break; +case BIT1_B: case BIT1_C: case BIT1_D: case BIT1_E: +case BIT1_H: case BIT1_L: case BIT1_A: +case BIT1_xHL: I=RdZ80(J.W);M_BIT(1,I);break; +case BIT2_B: case BIT2_C: case BIT2_D: case BIT2_E: +case BIT2_H: case BIT2_L: case BIT2_A: +case BIT2_xHL: I=RdZ80(J.W);M_BIT(2,I);break; +case BIT3_B: case BIT3_C: case BIT3_D: case BIT3_E: +case BIT3_H: case BIT3_L: case BIT3_A: +case BIT3_xHL: I=RdZ80(J.W);M_BIT(3,I);break; +case BIT4_B: case BIT4_C: case BIT4_D: case BIT4_E: +case BIT4_H: case BIT4_L: case BIT4_A: +case BIT4_xHL: I=RdZ80(J.W);M_BIT(4,I);break; +case BIT5_B: case BIT5_C: case BIT5_D: case BIT5_E: +case BIT5_H: case BIT5_L: case BIT5_A: +case BIT5_xHL: I=RdZ80(J.W);M_BIT(5,I);break; +case BIT6_B: case BIT6_C: case BIT6_D: case BIT6_E: +case BIT6_H: case BIT6_L: case BIT6_A: +case BIT6_xHL: I=RdZ80(J.W);M_BIT(6,I);break; +case BIT7_B: case BIT7_C: case BIT7_D: case BIT7_E: +case BIT7_H: case BIT7_L: case BIT7_A: +case BIT7_xHL: I=RdZ80(J.W);M_BIT(7,I);break; + +case RES0_xHL: I=RdZ80(J.W);M_RES(0,I);WrZ80(J.W,I);break; +case RES1_xHL: I=RdZ80(J.W);M_RES(1,I);WrZ80(J.W,I);break; +case RES2_xHL: I=RdZ80(J.W);M_RES(2,I);WrZ80(J.W,I);break; +case RES3_xHL: I=RdZ80(J.W);M_RES(3,I);WrZ80(J.W,I);break; +case RES4_xHL: I=RdZ80(J.W);M_RES(4,I);WrZ80(J.W,I);break; +case RES5_xHL: I=RdZ80(J.W);M_RES(5,I);WrZ80(J.W,I);break; +case RES6_xHL: I=RdZ80(J.W);M_RES(6,I);WrZ80(J.W,I);break; +case RES7_xHL: I=RdZ80(J.W);M_RES(7,I);WrZ80(J.W,I);break; + +case SET0_xHL: I=RdZ80(J.W);M_SET(0,I);WrZ80(J.W,I);break; +case SET1_xHL: I=RdZ80(J.W);M_SET(1,I);WrZ80(J.W,I);break; +case SET2_xHL: I=RdZ80(J.W);M_SET(2,I);WrZ80(J.W,I);break; +case SET3_xHL: I=RdZ80(J.W);M_SET(3,I);WrZ80(J.W,I);break; +case SET4_xHL: I=RdZ80(J.W);M_SET(4,I);WrZ80(J.W,I);break; +case SET5_xHL: I=RdZ80(J.W);M_SET(5,I);WrZ80(J.W,I);break; +case SET6_xHL: I=RdZ80(J.W);M_SET(6,I);WrZ80(J.W,I);break; +case SET7_xHL: I=RdZ80(J.W);M_SET(7,I);WrZ80(J.W,I);break; diff --git a/TIKI-100_emul-src/CodesXX.h b/TIKI-100_emul-src/CodesXX.h new file mode 100644 index 0000000..2cbe095 --- /dev/null +++ b/TIKI-100_emul-src/CodesXX.h @@ -0,0 +1,388 @@ +/** Z80: portable Z80 emulator *******************************/ +/** **/ +/** CodesXX.h **/ +/** **/ +/** This file contains implementation for FD/DD tables of **/ +/** Z80 commands. It is included from Z80.c. **/ +/** **/ +/** Copyright (C) Marat Fayzullin 1994,1995,1996,1997 **/ +/** You are not allowed to distribute this software **/ +/** commercially. Please, notify me, if you make any **/ +/** changes to this file. **/ +/*************************************************************/ + +case JR_NZ: if(R->AF.B.l&Z_FLAG) R->PC.W++; else { M_JR; } break; +case JR_NC: if(R->AF.B.l&C_FLAG) R->PC.W++; else { M_JR; } break; +case JR_Z: if(R->AF.B.l&Z_FLAG) { M_JR; } else R->PC.W++; break; +case JR_C: if(R->AF.B.l&C_FLAG) { M_JR; } else R->PC.W++; break; + +case JP_NZ: if(R->AF.B.l&Z_FLAG) R->PC.W+=2; else { M_JP; } break; +case JP_NC: if(R->AF.B.l&C_FLAG) R->PC.W+=2; else { M_JP; } break; +case JP_PO: if(R->AF.B.l&P_FLAG) R->PC.W+=2; else { M_JP; } break; +case JP_P: if(R->AF.B.l&S_FLAG) R->PC.W+=2; else { M_JP; } break; +case JP_Z: if(R->AF.B.l&Z_FLAG) { M_JP; } else R->PC.W+=2; break; +case JP_C: if(R->AF.B.l&C_FLAG) { M_JP; } else R->PC.W+=2; break; +case JP_PE: if(R->AF.B.l&P_FLAG) { M_JP; } else R->PC.W+=2; break; +case JP_M: if(R->AF.B.l&S_FLAG) { M_JP; } else R->PC.W+=2; break; + +case RET_NZ: if(!(R->AF.B.l&Z_FLAG)) { M_RET; } break; +case RET_NC: if(!(R->AF.B.l&C_FLAG)) { M_RET; } break; +case RET_PO: if(!(R->AF.B.l&P_FLAG)) { M_RET; } break; +case RET_P: if(!(R->AF.B.l&S_FLAG)) { M_RET; } break; +case RET_Z: if(R->AF.B.l&Z_FLAG) { M_RET; } break; +case RET_C: if(R->AF.B.l&C_FLAG) { M_RET; } break; +case RET_PE: if(R->AF.B.l&P_FLAG) { M_RET; } break; +case RET_M: if(R->AF.B.l&S_FLAG) { M_RET; } break; + +case CALL_NZ: if(R->AF.B.l&Z_FLAG) R->PC.W+=2; else { M_CALL; } break; +case CALL_NC: if(R->AF.B.l&C_FLAG) R->PC.W+=2; else { M_CALL; } break; +case CALL_PO: if(R->AF.B.l&P_FLAG) R->PC.W+=2; else { M_CALL; } break; +case CALL_P: if(R->AF.B.l&S_FLAG) R->PC.W+=2; else { M_CALL; } break; +case CALL_Z: if(R->AF.B.l&Z_FLAG) { M_CALL; } else R->PC.W+=2; break; +case CALL_C: if(R->AF.B.l&C_FLAG) { M_CALL; } else R->PC.W+=2; break; +case CALL_PE: if(R->AF.B.l&P_FLAG) { M_CALL; } else R->PC.W+=2; break; +case CALL_M: if(R->AF.B.l&S_FLAG) { M_CALL; } else R->PC.W+=2; break; + +case ADD_B: M_ADD(R->BC.B.h);break; +case ADD_C: M_ADD(R->BC.B.l);break; +case ADD_D: M_ADD(R->DE.B.h);break; +case ADD_E: M_ADD(R->DE.B.l);break; +case ADD_H: M_ADD(R->XX.B.h);break; +case ADD_L: M_ADD(R->XX.B.l);break; +case ADD_A: M_ADD(R->AF.B.h);break; +case ADD_xHL: I=RdZ80(R->XX.W+(offset)RdZ80(R->PC.W++)); + M_ADD(I);break; +case ADD_BYTE: I=RdZ80(R->PC.W++);M_ADD(I);break; + +case SUB_B: M_SUB(R->BC.B.h);break; +case SUB_C: M_SUB(R->BC.B.l);break; +case SUB_D: M_SUB(R->DE.B.h);break; +case SUB_E: M_SUB(R->DE.B.l);break; +case SUB_H: M_SUB(R->XX.B.h);break; +case SUB_L: M_SUB(R->XX.B.l);break; +case SUB_A: R->AF.B.h=0;R->AF.B.l=N_FLAG|Z_FLAG;break; +case SUB_xHL: I=RdZ80(R->XX.W+(offset)RdZ80(R->PC.W++)); + M_SUB(I);break; +case SUB_BYTE: I=RdZ80(R->PC.W++);M_SUB(I);break; + +case AND_B: M_AND(R->BC.B.h);break; +case AND_C: M_AND(R->BC.B.l);break; +case AND_D: M_AND(R->DE.B.h);break; +case AND_E: M_AND(R->DE.B.l);break; +case AND_H: M_AND(R->XX.B.h);break; +case AND_L: M_AND(R->XX.B.l);break; +case AND_A: M_AND(R->AF.B.h);break; +case AND_xHL: I=RdZ80(R->XX.W+(offset)RdZ80(R->PC.W++)); + M_AND(I);break; +case AND_BYTE: I=RdZ80(R->PC.W++);M_AND(I);break; + +case OR_B: M_OR(R->BC.B.h);break; +case OR_C: M_OR(R->BC.B.l);break; +case OR_D: M_OR(R->DE.B.h);break; +case OR_E: M_OR(R->DE.B.l);break; +case OR_H: M_OR(R->XX.B.h);break; +case OR_L: M_OR(R->XX.B.l);break; +case OR_A: M_OR(R->AF.B.h);break; +case OR_xHL: I=RdZ80(R->XX.W+(offset)RdZ80(R->PC.W++)); + M_OR(I);break; +case OR_BYTE: I=RdZ80(R->PC.W++);M_OR(I);break; + +case ADC_B: M_ADC(R->BC.B.h);break; +case ADC_C: M_ADC(R->BC.B.l);break; +case ADC_D: M_ADC(R->DE.B.h);break; +case ADC_E: M_ADC(R->DE.B.l);break; +case ADC_H: M_ADC(R->XX.B.h);break; +case ADC_L: M_ADC(R->XX.B.l);break; +case ADC_A: M_ADC(R->AF.B.h);break; +case ADC_xHL: I=RdZ80(R->XX.W+(offset)RdZ80(R->PC.W++)); + M_ADC(I);break; +case ADC_BYTE: I=RdZ80(R->PC.W++);M_ADC(I);break; + +case SBC_B: M_SBC(R->BC.B.h);break; +case SBC_C: M_SBC(R->BC.B.l);break; +case SBC_D: M_SBC(R->DE.B.h);break; +case SBC_E: M_SBC(R->DE.B.l);break; +case SBC_H: M_SBC(R->XX.B.h);break; +case SBC_L: M_SBC(R->XX.B.l);break; +case SBC_A: M_SBC(R->AF.B.h);break; +case SBC_xHL: I=RdZ80(R->XX.W+(offset)RdZ80(R->PC.W++)); + M_SBC(I);break; +case SBC_BYTE: I=RdZ80(R->PC.W++);M_SBC(I);break; + +case XOR_B: M_XOR(R->BC.B.h);break; +case XOR_C: M_XOR(R->BC.B.l);break; +case XOR_D: M_XOR(R->DE.B.h);break; +case XOR_E: M_XOR(R->DE.B.l);break; +case XOR_H: M_XOR(R->XX.B.h);break; +case XOR_L: M_XOR(R->XX.B.l);break; +case XOR_A: R->AF.B.h=0;R->AF.B.l=P_FLAG|Z_FLAG;break; +case XOR_xHL: I=RdZ80(R->XX.W+(offset)RdZ80(R->PC.W++)); + M_XOR(I);break; +case XOR_BYTE: I=RdZ80(R->PC.W++);M_XOR(I);break; + +case CP_B: M_CP(R->BC.B.h);break; +case CP_C: M_CP(R->BC.B.l);break; +case CP_D: M_CP(R->DE.B.h);break; +case CP_E: M_CP(R->DE.B.l);break; +case CP_H: M_CP(R->XX.B.h);break; +case CP_L: M_CP(R->XX.B.l);break; +case CP_A: R->AF.B.l=N_FLAG|Z_FLAG;break; +case CP_xHL: I=RdZ80(R->XX.W+(offset)RdZ80(R->PC.W++)); + M_CP(I);break; +case CP_BYTE: I=RdZ80(R->PC.W++);M_CP(I);break; + +case LD_BC_WORD: M_LDWORD(BC);break; +case LD_DE_WORD: M_LDWORD(DE);break; +case LD_HL_WORD: M_LDWORD(XX);break; +case LD_SP_WORD: M_LDWORD(SP);break; + +case LD_PC_HL: R->PC.W=R->XX.W;break; +case LD_SP_HL: R->SP.W=R->XX.W;break; +case LD_A_xBC: R->AF.B.h=RdZ80(R->BC.W);break; +case LD_A_xDE: R->AF.B.h=RdZ80(R->DE.W);break; + +case ADD_HL_BC: M_ADDW(XX,BC);break; +case ADD_HL_DE: M_ADDW(XX,DE);break; +case ADD_HL_HL: M_ADDW(XX,XX);break; +case ADD_HL_SP: M_ADDW(XX,SP);break; + +case DEC_BC: R->BC.W--;break; +case DEC_DE: R->DE.W--;break; +case DEC_HL: R->XX.W--;break; +case DEC_SP: R->SP.W--;break; + +case INC_BC: R->BC.W++;break; +case INC_DE: R->DE.W++;break; +case INC_HL: R->XX.W++;break; +case INC_SP: R->SP.W++;break; + +case DEC_B: M_DEC(R->BC.B.h);break; +case DEC_C: M_DEC(R->BC.B.l);break; +case DEC_D: M_DEC(R->DE.B.h);break; +case DEC_E: M_DEC(R->DE.B.l);break; +case DEC_H: M_DEC(R->XX.B.h);break; +case DEC_L: M_DEC(R->XX.B.l);break; +case DEC_A: M_DEC(R->AF.B.h);break; +case DEC_xHL: I=RdZ80(R->XX.W+(offset)RdZ80(R->PC.W));M_DEC(I); + WrZ80(R->XX.W+(offset)RdZ80(R->PC.W++),I); + break; + +case INC_B: M_INC(R->BC.B.h);break; +case INC_C: M_INC(R->BC.B.l);break; +case INC_D: M_INC(R->DE.B.h);break; +case INC_E: M_INC(R->DE.B.l);break; +case INC_H: M_INC(R->XX.B.h);break; +case INC_L: M_INC(R->XX.B.l);break; +case INC_A: M_INC(R->AF.B.h);break; +case INC_xHL: I=RdZ80(R->XX.W+(offset)RdZ80(R->PC.W));M_INC(I); + WrZ80(R->XX.W+(offset)RdZ80(R->PC.W++),I); + break; + +case RLCA: + I=(R->AF.B.h&0x80? C_FLAG:0); + R->AF.B.h=(R->AF.B.h<<1)|I; + R->AF.B.l=(R->AF.B.l&~(C_FLAG|N_FLAG|H_FLAG))|I; + break; +case RLA: + I=(R->AF.B.h&0x80? C_FLAG:0); + R->AF.B.h=(R->AF.B.h<<1)|(R->AF.B.l&C_FLAG); + R->AF.B.l=(R->AF.B.l&~(C_FLAG|N_FLAG|H_FLAG))|I; + break; +case RRCA: + I=R->AF.B.h&0x01; + R->AF.B.h=(R->AF.B.h>>1)|(I? 0x80:0); + R->AF.B.l=(R->AF.B.l&~(C_FLAG|N_FLAG|H_FLAG))|I; + break; +case RRA: + I=R->AF.B.h&0x01; + R->AF.B.h=(R->AF.B.h>>1)|(R->AF.B.l&C_FLAG? 0x80:0); + R->AF.B.l=(R->AF.B.l&~(C_FLAG|N_FLAG|H_FLAG))|I; + break; + +case RST00: M_RST(0x0000);break; +case RST08: M_RST(0x0008);break; +case RST10: M_RST(0x0010);break; +case RST18: M_RST(0x0018);break; +case RST20: M_RST(0x0020);break; +case RST28: M_RST(0x0028);break; +case RST30: M_RST(0x0030);break; +case RST38: M_RST(0x0038);break; + +case PUSH_BC: M_PUSH(BC);break; +case PUSH_DE: M_PUSH(DE);break; +case PUSH_HL: M_PUSH(XX);break; +case PUSH_AF: M_PUSH(AF);break; + +case POP_BC: M_POP(BC);break; +case POP_DE: M_POP(DE);break; +case POP_HL: M_POP(XX);break; +case POP_AF: M_POP(AF);break; + +case DJNZ: if(--R->BC.B.h) { M_JR; } else R->PC.W++;break; +case JP: M_JP;break; +case JR: M_JR;break; +case CALL: M_CALL;break; +case RET: M_RET;break; +case SCF: S(C_FLAG);R(N_FLAG|H_FLAG);break; +case CPL: R->AF.B.h=~R->AF.B.h;S(N_FLAG|H_FLAG);break; +case NOP: break; +case OUTA: OutZ80(RdZ80(R->PC.W++),R->AF.B.h);break; +case INA: R->AF.B.h=InZ80(RdZ80(R->PC.W++));break; + +case DI: + R->IFF&=0xFE; + break; +case EI: + R->IFF|=0x01; + if(R->IRequest!=INT_NONE) + { + R->IFF|=0x20; + R->IBackup=R->ICount; + R->ICount=1; + } + break; + +case CCF: + R->AF.B.l^=C_FLAG;R(N_FLAG|H_FLAG); + R->AF.B.l|=R->AF.B.l&C_FLAG? 0:H_FLAG; + break; + +case EXX: + J.W=R->BC.W;R->BC.W=R->BC1.W;R->BC1.W=J.W; + J.W=R->DE.W;R->DE.W=R->DE1.W;R->DE1.W=J.W; + J.W=R->HL.W;R->HL.W=R->HL1.W;R->HL1.W=J.W; + break; + +case EX_DE_HL: J.W=R->DE.W;R->DE.W=R->HL.W;R->HL.W=J.W;break; +case EX_AF_AF: J.W=R->AF.W;R->AF.W=R->AF1.W;R->AF1.W=J.W;break; + +case LD_B_B: R->BC.B.h=R->BC.B.h;break; +case LD_C_B: R->BC.B.l=R->BC.B.h;break; +case LD_D_B: R->DE.B.h=R->BC.B.h;break; +case LD_E_B: R->DE.B.l=R->BC.B.h;break; +case LD_H_B: R->XX.B.h=R->BC.B.h;break; +case LD_L_B: R->XX.B.l=R->BC.B.h;break; +case LD_A_B: R->AF.B.h=R->BC.B.h;break; +case LD_xHL_B: J.W=R->XX.W+(offset)RdZ80(R->PC.W++); + WrZ80(J.W,R->BC.B.h);break; + +case LD_B_C: R->BC.B.h=R->BC.B.l;break; +case LD_C_C: R->BC.B.l=R->BC.B.l;break; +case LD_D_C: R->DE.B.h=R->BC.B.l;break; +case LD_E_C: R->DE.B.l=R->BC.B.l;break; +case LD_H_C: R->XX.B.h=R->BC.B.l;break; +case LD_L_C: R->XX.B.l=R->BC.B.l;break; +case LD_A_C: R->AF.B.h=R->BC.B.l;break; +case LD_xHL_C: J.W=R->XX.W+(offset)RdZ80(R->PC.W++); + WrZ80(J.W,R->BC.B.l);break; + +case LD_B_D: R->BC.B.h=R->DE.B.h;break; +case LD_C_D: R->BC.B.l=R->DE.B.h;break; +case LD_D_D: R->DE.B.h=R->DE.B.h;break; +case LD_E_D: R->DE.B.l=R->DE.B.h;break; +case LD_H_D: R->XX.B.h=R->DE.B.h;break; +case LD_L_D: R->XX.B.l=R->DE.B.h;break; +case LD_A_D: R->AF.B.h=R->DE.B.h;break; +case LD_xHL_D: J.W=R->XX.W+(offset)RdZ80(R->PC.W++); + WrZ80(J.W,R->DE.B.h);break; + +case LD_B_E: R->BC.B.h=R->DE.B.l;break; +case LD_C_E: R->BC.B.l=R->DE.B.l;break; +case LD_D_E: R->DE.B.h=R->DE.B.l;break; +case LD_E_E: R->DE.B.l=R->DE.B.l;break; +case LD_H_E: R->XX.B.h=R->DE.B.l;break; +case LD_L_E: R->XX.B.l=R->DE.B.l;break; +case LD_A_E: R->AF.B.h=R->DE.B.l;break; +case LD_xHL_E: J.W=R->XX.W+(offset)RdZ80(R->PC.W++); + WrZ80(J.W,R->DE.B.l);break; + +case LD_B_H: R->BC.B.h=R->XX.B.h;break; +case LD_C_H: R->BC.B.l=R->XX.B.h;break; +case LD_D_H: R->DE.B.h=R->XX.B.h;break; +case LD_E_H: R->DE.B.l=R->XX.B.h;break; +case LD_H_H: R->XX.B.h=R->XX.B.h;break; +case LD_L_H: R->XX.B.l=R->XX.B.h;break; +case LD_A_H: R->AF.B.h=R->XX.B.h;break; +case LD_xHL_H: J.W=R->XX.W+(offset)RdZ80(R->PC.W++); + WrZ80(J.W,R->HL.B.h);break; + +case LD_B_L: R->BC.B.h=R->XX.B.l;break; +case LD_C_L: R->BC.B.l=R->XX.B.l;break; +case LD_D_L: R->DE.B.h=R->XX.B.l;break; +case LD_E_L: R->DE.B.l=R->XX.B.l;break; +case LD_H_L: R->XX.B.h=R->XX.B.l;break; +case LD_L_L: R->XX.B.l=R->XX.B.l;break; +case LD_A_L: R->AF.B.h=R->XX.B.l;break; +case LD_xHL_L: J.W=R->XX.W+(offset)RdZ80(R->PC.W++); + WrZ80(J.W,R->HL.B.l);break; + +case LD_B_A: R->BC.B.h=R->AF.B.h;break; +case LD_C_A: R->BC.B.l=R->AF.B.h;break; +case LD_D_A: R->DE.B.h=R->AF.B.h;break; +case LD_E_A: R->DE.B.l=R->AF.B.h;break; +case LD_H_A: R->XX.B.h=R->AF.B.h;break; +case LD_L_A: R->XX.B.l=R->AF.B.h;break; +case LD_A_A: R->AF.B.h=R->AF.B.h;break; +case LD_xHL_A: J.W=R->XX.W+(offset)RdZ80(R->PC.W++); + WrZ80(J.W,R->AF.B.h);break; + +case LD_xBC_A: WrZ80(R->BC.W,R->AF.B.h);break; +case LD_xDE_A: WrZ80(R->DE.W,R->AF.B.h);break; + +case LD_B_xHL: R->BC.B.h=RdZ80(R->XX.W+(offset)RdZ80(R->PC.W++));break; +case LD_C_xHL: R->BC.B.l=RdZ80(R->XX.W+(offset)RdZ80(R->PC.W++));break; +case LD_D_xHL: R->DE.B.h=RdZ80(R->XX.W+(offset)RdZ80(R->PC.W++));break; +case LD_E_xHL: R->DE.B.l=RdZ80(R->XX.W+(offset)RdZ80(R->PC.W++));break; +case LD_H_xHL: R->HL.B.h=RdZ80(R->XX.W+(offset)RdZ80(R->PC.W++));break; +case LD_L_xHL: R->HL.B.l=RdZ80(R->XX.W+(offset)RdZ80(R->PC.W++));break; +case LD_A_xHL: R->AF.B.h=RdZ80(R->XX.W+(offset)RdZ80(R->PC.W++));break; + +case LD_B_BYTE: R->BC.B.h=RdZ80(R->PC.W++);break; +case LD_C_BYTE: R->BC.B.l=RdZ80(R->PC.W++);break; +case LD_D_BYTE: R->DE.B.h=RdZ80(R->PC.W++);break; +case LD_E_BYTE: R->DE.B.l=RdZ80(R->PC.W++);break; +case LD_H_BYTE: R->XX.B.h=RdZ80(R->PC.W++);break; +case LD_L_BYTE: R->XX.B.l=RdZ80(R->PC.W++);break; +case LD_A_BYTE: R->AF.B.h=RdZ80(R->PC.W++);break; +case LD_xHL_BYTE: J.W=R->XX.W+(offset)RdZ80(R->PC.W++); + WrZ80(J.W,RdZ80(R->PC.W++));break; + +case LD_xWORD_HL: + J.B.l=RdZ80(R->PC.W++); + J.B.h=RdZ80(R->PC.W++); + WrZ80(J.W++,R->XX.B.l); + WrZ80(J.W,R->XX.B.h); + break; + +case LD_HL_xWORD: + J.B.l=RdZ80(R->PC.W++); + J.B.h=RdZ80(R->PC.W++); + R->XX.B.l=RdZ80(J.W++); + R->XX.B.h=RdZ80(J.W); + break; + +case LD_A_xWORD: + J.B.l=RdZ80(R->PC.W++); + J.B.h=RdZ80(R->PC.W++); + R->AF.B.h=RdZ80(J.W); + break; + +case LD_xWORD_A: + J.B.l=RdZ80(R->PC.W++); + J.B.h=RdZ80(R->PC.W++); + WrZ80(J.W,R->AF.B.h); + break; + +case EX_HL_xSP: + J.B.l=RdZ80(R->SP.W);WrZ80(R->SP.W++,R->XX.B.l); + J.B.h=RdZ80(R->SP.W);WrZ80(R->SP.W--,R->XX.B.h); + R->XX.W=J.W; + break; + +case DAA: + J.W=R->AF.B.h; + if(R->AF.B.l&C_FLAG) J.W|=256; + if(R->AF.B.l&H_FLAG) J.W|=512; + if(R->AF.B.l&N_FLAG) J.W|=1024; + R->AF.W=DAATable[J.W]; + break; diff --git a/TIKI-100_emul-src/Debug.c b/TIKI-100_emul-src/Debug.c new file mode 100644 index 0000000..b86b280 --- /dev/null +++ b/TIKI-100_emul-src/Debug.c @@ -0,0 +1,411 @@ +/** Z80: portable Z80 emulator *******************************/ +/** **/ +/** Debug.c **/ +/** **/ +/** This file contains the built-in debugging routine for **/ +/** the Z80 emulator which is called on each Z80 step when **/ +/** Trap!=0. **/ +/** **/ +/** Copyright (C) Marat Fayzullin 1995,1996,1997 **/ +/** You are not allowed to distribute this software **/ +/** commercially. Please, notify me, if you make any **/ +/** changes to this file. **/ +/*************************************************************/ +#include "Z80.h" + +#ifdef DEBUG + +#include +#include +#include + +static char *Mnemonics[256] = +{ + "NOP","LD BC,#h","LD (BC),A","INC BC","INC B","DEC B","LD B,*h","RLCA", + "EX AF,AF'","ADD HL,BC","LD A,(BC)","DEC BC","INC C","DEC C","LD C,*h","RRCA", + "DJNZ @h","LD DE,#h","LD (DE),A","INC DE","INC D","DEC D","LD D,*h","RLA", + "JR @h","ADD HL,DE","LD A,(DE)","DEC DE","INC E","DEC E","LD E,*h","RRA", + "JR NZ,@h","LD HL,#h","LD (#h),HL","INC HL","INC H","DEC H","LD H,*h","DAA", + "JR Z,@h","ADD HL,HL","LD HL,(#h)","DEC HL","INC L","DEC L","LD L,*h","CPL", + "JR NC,@h","LD SP,#h","LD (#h),A","INC SP","INC (HL)","DEC (HL)","LD (HL),*h","SCF", + "JR C,@h","ADD HL,SP","LD A,(#h)","DEC SP","INC A","DEC A","LD A,*h","CCF", + "LD B,B","LD B,C","LD B,D","LD B,E","LD B,H","LD B,L","LD B,(HL)","LD B,A", + "LD C,B","LD C,C","LD C,D","LD C,E","LD C,H","LD C,L","LD C,(HL)","LD C,A", + "LD D,B","LD D,C","LD D,D","LD D,E","LD D,H","LD D,L","LD D,(HL)","LD D,A", + "LD E,B","LD E,C","LD E,D","LD E,E","LD E,H","LD E,L","LD E,(HL)","LD E,A", + "LD H,B","LD H,C","LD H,D","LD H,E","LD H,H","LD H,L","LD H,(HL)","LD H,A", + "LD L,B","LD L,C","LD L,D","LD L,E","LD L,H","LD L,L","LD L,(HL)","LD L,A", + "LD (HL),B","LD (HL),C","LD (HL),D","LD (HL),E","LD (HL),H","LD (HL),L","HALT","LD (HL),A", + "LD A,B","LD A,C","LD A,D","LD A,E","LD A,H","LD A,L","LD A,(HL)","LD A,A", + "ADD B","ADD C","ADD D","ADD E","ADD H","ADD L","ADD (HL)","ADD A", + "ADC B","ADC C","ADC D","ADC E","ADC H","ADC L","ADC (HL)","ADC A", + "SUB B","SUB C","SUB D","SUB E","SUB H","SUB L","SUB (HL)","SUB A", + "SBC B","SBC C","SBC D","SBC E","SBC H","SBC L","SBC (HL)","SBC A", + "AND B","AND C","AND D","AND E","AND H","AND L","AND (HL)","AND A", + "XOR B","XOR C","XOR D","XOR E","XOR H","XOR L","XOR (HL)","XOR A", + "OR B","OR C","OR D","OR E","OR H","OR L","OR (HL)","OR A", + "CP B","CP C","CP D","CP E","CP H","CP L","CP (HL)","CP A", + "RET NZ","POP BC","JP NZ,#h","JP #h","CALL NZ,#h","PUSH BC","ADD *h","RST 00h", + "RET Z","RET","JP Z,#h","PFX_CB","CALL Z,#h","CALL #h","ADC *h","RST 08h", + "RET NC","POP DE","JP NC,#h","OUTA (*h)","CALL NC,#h","PUSH DE","SUB *h","RST 10h", + "RET C","EXX","JP C,#h","INA (*h)","CALL C,#h","PFX_DD","SBC *h","RST 18h", + "RET PO","POP HL","JP PO,#h","EX HL,(SP)","CALL PO,#h","PUSH HL","AND *h","RST 20h", + "RET PE","LD PC,HL","JP PE,#h","EX DE,HL","CALL PE,#h","PFX_ED","XOR *h","RST 28h", + "RET P","POP AF","JP P,#h","DI","CALL P,#h","PUSH AF","OR *h","RST 30h", + "RET M","LD SP,HL","JP M,#h","EI","CALL M,#h","PFX_FD","CP *h","RST 38h" +}; + +static char *MnemonicsCB[256] = +{ + "RLC B","RLC C","RLC D","RLC E","RLC H","RLC L","RLC (HL)","RLC A", + "RRC B","RRC C","RRC D","RRC E","RRC H","RRC L","RRC (HL)","RRC A", + "RL B","RL C","RL D","RL E","RL H","RL L","RL (HL)","RL A", + "RR B","RR C","RR D","RR E","RR H","RR L","RR (HL)","RR A", + "SLA B","SLA C","SLA D","SLA E","SLA H","SLA L","SLA (HL)","SLA A", + "SRA B","SRA C","SRA D","SRA E","SRA H","SRA L","SRA (HL)","SRA A", + "SLL B","SLL C","SLL D","SLL E","SLL H","SLL L","SLL (HL)","SLL A", + "SRL B","SRL C","SRL D","SRL E","SRL H","SRL L","SRL (HL)","SRL A", + "BIT 0,B","BIT 0,C","BIT 0,D","BIT 0,E","BIT 0,H","BIT 0,L","BIT 0,(HL)","BIT 0,A", + "BIT 1,B","BIT 1,C","BIT 1,D","BIT 1,E","BIT 1,H","BIT 1,L","BIT 1,(HL)","BIT 1,A", + "BIT 2,B","BIT 2,C","BIT 2,D","BIT 2,E","BIT 2,H","BIT 2,L","BIT 2,(HL)","BIT 2,A", + "BIT 3,B","BIT 3,C","BIT 3,D","BIT 3,E","BIT 3,H","BIT 3,L","BIT 3,(HL)","BIT 3,A", + "BIT 4,B","BIT 4,C","BIT 4,D","BIT 4,E","BIT 4,H","BIT 4,L","BIT 4,(HL)","BIT 4,A", + "BIT 5,B","BIT 5,C","BIT 5,D","BIT 5,E","BIT 5,H","BIT 5,L","BIT 5,(HL)","BIT 5,A", + "BIT 6,B","BIT 6,C","BIT 6,D","BIT 6,E","BIT 6,H","BIT 6,L","BIT 6,(HL)","BIT 6,A", + "BIT 7,B","BIT 7,C","BIT 7,D","BIT 7,E","BIT 7,H","BIT 7,L","BIT 7,(HL)","BIT 7,A", + "RES 0,B","RES 0,C","RES 0,D","RES 0,E","RES 0,H","RES 0,L","RES 0,(HL)","RES 0,A", + "RES 1,B","RES 1,C","RES 1,D","RES 1,E","RES 1,H","RES 1,L","RES 1,(HL)","RES 1,A", + "RES 2,B","RES 2,C","RES 2,D","RES 2,E","RES 2,H","RES 2,L","RES 2,(HL)","RES 2,A", + "RES 3,B","RES 3,C","RES 3,D","RES 3,E","RES 3,H","RES 3,L","RES 3,(HL)","RES 3,A", + "RES 4,B","RES 4,C","RES 4,D","RES 4,E","RES 4,H","RES 4,L","RES 4,(HL)","RES 4,A", + "RES 5,B","RES 5,C","RES 5,D","RES 5,E","RES 5,H","RES 5,L","RES 5,(HL)","RES 5,A", + "RES 6,B","RES 6,C","RES 6,D","RES 6,E","RES 6,H","RES 6,L","RES 6,(HL)","RES 6,A", + "RES 7,B","RES 7,C","RES 7,D","RES 7,E","RES 7,H","RES 7,L","RES 7,(HL)","RES 7,A", + "SET 0,B","SET 0,C","SET 0,D","SET 0,E","SET 0,H","SET 0,L","SET 0,(HL)","SET 0,A", + "SET 1,B","SET 1,C","SET 1,D","SET 1,E","SET 1,H","SET 1,L","SET 1,(HL)","SET 1,A", + "SET 2,B","SET 2,C","SET 2,D","SET 2,E","SET 2,H","SET 2,L","SET 2,(HL)","SET 2,A", + "SET 3,B","SET 3,C","SET 3,D","SET 3,E","SET 3,H","SET 3,L","SET 3,(HL)","SET 3,A", + "SET 4,B","SET 4,C","SET 4,D","SET 4,E","SET 4,H","SET 4,L","SET 4,(HL)","SET 4,A", + "SET 5,B","SET 5,C","SET 5,D","SET 5,E","SET 5,H","SET 5,L","SET 5,(HL)","SET 5,A", + "SET 6,B","SET 6,C","SET 6,D","SET 6,E","SET 6,H","SET 6,L","SET 6,(HL)","SET 6,A", + "SET 7,B","SET 7,C","SET 7,D","SET 7,E","SET 7,H","SET 7,L","SET 7,(HL)","SET 7,A" +}; + +static char *MnemonicsED[256] = +{ + "DB EDh,00h","DB EDh,01h","DB EDh,02h","DB EDh,03h", + "DB EDh,04h","DB EDh,05h","DB EDh,06h","DB EDh,07h", + "DB EDh,08h","DB EDh,09h","DB EDh,0Ah","DB EDh,0Bh", + "DB EDh,0Ch","DB EDh,0Dh","DB EDh,0Eh","DB EDh,0Fh", + "DB EDh,10h","DB EDh,11h","DB EDh,12h","DB EDh,13h", + "DB EDh,14h","DB EDh,15h","DB EDh,16h","DB EDh,17h", + "DB EDh,18h","DB EDh,19h","DB EDh,1Ah","DB EDh,1Bh", + "DB EDh,1Ch","DB EDh,1Dh","DB EDh,1Eh","DB EDh,1Fh", + "DB EDh,20h","DB EDh,21h","DB EDh,22h","DB EDh,23h", + "DB EDh,24h","DB EDh,25h","DB EDh,26h","DB EDh,27h", + "DB EDh,28h","DB EDh,29h","DB EDh,2Ah","DB EDh,2Bh", + "DB EDh,2Ch","DB EDh,2Dh","DB EDh,2Eh","DB EDh,2Fh", + "DB EDh,30h","DB EDh,31h","DB EDh,32h","DB EDh,33h", + "DB EDh,34h","DB EDh,35h","DB EDh,36h","DB EDh,37h", + "DB EDh,38h","DB EDh,39h","DB EDh,3Ah","DB EDh,3Bh", + "DB EDh,3Ch","DB EDh,3Dh","DB EDh,3Eh","DB EDh,3Fh", + "IN B,(C)","OUT (C),B","SBC HL,BC","LD (#h),BC", + "NEG","RETN","IM 0","LD I,A", + "IN C,(C)","OUT (C),C","ADC HL,BC","LD BC,(#h)", + "DB EDh,4Ch","RETI","DB EDh,4Eh","LD R,A", + "IN D,(C)","OUT (C),D","SBC HL,DE","LD (#h),DE", + "DB EDh,54h","DB EDh,55h","IM 1","LD A,I", + "IN E,(C)","OUT (C),E","ADC HL,DE","LD DE,(#h)", + "DB EDh,5Ch","DB EDh,5Dh","IM 2","LD A,R", + "IN H,(C)","OUT (C),H","SBC HL,HL","LD (#h),HL", + "DB EDh,64h","DB EDh,65h","DB EDh,66h","RRD", + "IN L,(C)","OUT (C),L","ADC HL,HL","LD HL,(#h)", + "DB EDh,6Ch","DB EDh,6Dh","DB EDh,6Eh","RLD", + "IN F,(C)","DB EDh,71h","SBC HL,SP","LD (#h),SP", + "DB EDh,74h","DB EDh,75h","DB EDh,76h","DB EDh,77h", + "IN A,(C)","OUT (C),A","ADC HL,SP","LD SP,(#h)", + "DB EDh,7Ch","DB EDh,7Dh","DB EDh,7Eh","DB EDh,7Fh", + "DB EDh,80h","DB EDh,81h","DB EDh,82h","DB EDh,83h", + "DB EDh,84h","DB EDh,85h","DB EDh,86h","DB EDh,87h", + "DB EDh,88h","DB EDh,89h","DB EDh,8Ah","DB EDh,8Bh", + "DB EDh,8Ch","DB EDh,8Dh","DB EDh,8Eh","DB EDh,8Fh", + "DB EDh,90h","DB EDh,91h","DB EDh,92h","DB EDh,93h", + "DB EDh,94h","DB EDh,95h","DB EDh,96h","DB EDh,97h", + "DB EDh,98h","DB EDh,99h","DB EDh,9Ah","DB EDh,9Bh", + "DB EDh,9Ch","DB EDh,9Dh","DB EDh,9Eh","DB EDh,9Fh", + "LDI","CPI","INI","OUTI", + "DB EDh,A4h","DB EDh,A5h","DB EDh,A6h","DB EDh,A7h", + "LDD","CPD","IND","OUTD", + "DB EDh,ACh","DB EDh,ADh","DB EDh,AEh","DB EDh,AFh", + "LDIR","CPIR","INIR","OTIR", + "DB EDh,B4h","DB EDh,B5h","DB EDh,B6h","DB EDh,B7h", + "LDDR","CPDR","INDR","OTDR", + "DB EDh,BCh","DB EDh,BDh","DB EDh,BEh","DB EDh,BFh", + "DB EDh,C0h","DB EDh,C1h","DB EDh,C2h","DB EDh,C3h", + "DB EDh,C4h","DB EDh,C5h","DB EDh,C6h","DB EDh,C7h", + "DB EDh,C8h","DB EDh,C9h","DB EDh,CAh","DB EDh,CBh", + "DB EDh,CCh","DB EDh,CDh","DB EDh,CEh","DB EDh,CFh", + "DB EDh,D0h","DB EDh,D1h","DB EDh,D2h","DB EDh,D3h", + "DB EDh,D4h","DB EDh,D5h","DB EDh,D6h","DB EDh,D7h", + "DB EDh,D8h","DB EDh,D9h","DB EDh,DAh","DB EDh,DBh", + "DB EDh,DCh","DB EDh,DDh","DB EDh,DEh","DB EDh,DFh", + "DB EDh,E0h","DB EDh,E1h","DB EDh,E2h","DB EDh,E3h", + "DB EDh,E4h","DB EDh,E5h","DB EDh,E6h","DB EDh,E7h", + "DB EDh,E8h","DB EDh,E9h","DB EDh,EAh","DB EDh,EBh", + "DB EDh,ECh","DB EDh,EDh","DB EDh,EEh","DB EDh,EFh", + "DB EDh,F0h","DB EDh,F1h","DB EDh,F2h","DB EDh,F3h", + "DB EDh,F4h","DB EDh,F5h","DB EDh,F6h","DB EDh,F7h", + "DB EDh,F8h","DB EDh,F9h","DB EDh,FAh","DB EDh,FBh", + "DB EDh,FCh","DB EDh,FDh","DB EDh,FEh","DB EDh,FFh" +}; + +static char *MnemonicsXX[256] = +{ + "NOP","LD BC,#h","LD (BC),A","INC BC","INC B","DEC B","LD B,*h","RLCA", + "EX AF,AF'","ADD I%,BC","LD A,(BC)","DEC BC","INC C","DEC C","LD C,*h","RRCA", + "DJNZ @h","LD DE,#h","LD (DE),A","INC DE","INC D","DEC D","LD D,*h","RLA", + "JR @h","ADD I%,DE","LD A,(DE)","DEC DE","INC E","DEC E","LD E,*h","RRA", + "JR NZ,@h","LD I%,#h","LD (#h),I%","INC I%","INC I%h","DEC I%h","LD I%h,*h","DAA", + "JR Z,@h","ADD I%,I%","LD I%,(#h)","DEC I%","INC I%l","DEC I%l","LD I%l,*h","CPL", + "JR NC,@h","LD SP,#h","LD (#h),A","INC SP","INC (I%+^h)","DEC (I%+^h)","LD (I%+^h),*h","SCF", + "JR C,@h","ADD I%,SP","LD A,(#h)","DEC SP","INC A","DEC A","LD A,*h","CCF", + "LD B,B","LD B,C","LD B,D","LD B,E","LD B,I%h","LD B,I%l","LD B,(I%+^h)","LD B,A", + "LD C,B","LD C,C","LD C,D","LD C,E","LD C,I%h","LD C,I%l","LD C,(I%+^h)","LD C,A", + "LD D,B","LD D,C","LD D,D","LD D,E","LD D,I%h","LD D,I%l","LD D,(I%+^h)","LD D,A", + "LD E,B","LD E,C","LD E,D","LD E,E","LD E,I%h","LD E,I%l","LD E,(I%+^h)","LD E,A", + "LD I%h,B","LD I%h,C","LD I%h,D","LD I%h,E","LD I%h,I%h","LD I%h,I%l","LD H,(I%+^h)","LD I%h,A", + "LD I%l,B","LD I%l,C","LD I%l,D","LD I%l,E","LD I%l,I%h","LD I%l,I%l","LD L,(I%+^h)","LD I%l,A", + "LD (I%+^h),B","LD (I%+^h),C","LD (I%+^h),D","LD (I%+^h),E","LD (I%+^h),H","LD (I%+^h),L","HALT","LD (I%+^h),A", + "LD A,B","LD A,C","LD A,D","LD A,E","LD A,I%h","LD A,I%l","LD A,(I%+^h)","LD A,A", + "ADD B","ADD C","ADD D","ADD E","ADD I%h","ADD I%l","ADD (I%+^h)","ADD A", + "ADC B","ADC C","ADC D","ADC E","ADC I%h","ADC I%l","ADC (I%+^h)","ADC,A", + "SUB B","SUB C","SUB D","SUB E","SUB I%h","SUB I%l","SUB (I%+^h)","SUB A", + "SBC B","SBC C","SBC D","SBC E","SBC I%h","SBC I%l","SBC (I%+^h)","SBC A", + "AND B","AND C","AND D","AND E","AND I%h","AND I%l","AND (I%+^h)","AND A", + "XOR B","XOR C","XOR D","XOR E","XOR I%h","XOR I%l","XOR (I%+^h)","XOR A", + "OR B","OR C","OR D","OR E","OR I%h","OR I%l","OR (I%+^h)","OR A", + "CP B","CP C","CP D","CP E","CP I%h","CP I%l","CP (I%+^h)","CP A", + "RET NZ","POP BC","JP NZ,#h","JP #h","CALL NZ,#h","PUSH BC","ADD *h","RST 00h", + "RET Z","RET","JP Z,#h","PFX_CB","CALL Z,#h","CALL #h","ADC *h","RST 08h", + "RET NC","POP DE","JP NC,#h","OUTA (*h)","CALL NC,#h","PUSH DE","SUB *h","RST 10h", + "RET C","EXX","JP C,#h","INA (*h)","CALL C,#h","PFX_DD","SBC *h","RST 18h", + "RET PO","POP I%","JP PO,#h","EX I%,(SP)","CALL PO,#h","PUSH I%","AND *h","RST 20h", + "RET PE","LD PC,I%","JP PE,#h","EX DE,I%","CALL PE,#h","PFX_ED","XOR *h","RST 28h", + "RET P","POP AF","JP P,#h","DI","CALL P,#h","PUSH AF","OR *h","RST 30h", + "RET M","LD SP,I%","JP M,#h","EI","CALL M,#h","PFX_FD","CP *h","RST 38h" +}; + +static char *MnemonicsXCB[256] = +{ + "RLC B","RLC C","RLC D","RLC E","RLC H","RLC L","RLC (I%@h)","RLC A", + "RRC B","RRC C","RRC D","RRC E","RRC H","RRC L","RRC (I%@h)","RRC A", + "RL B","RL C","RL D","RL E","RL H","RL L","RL (I%@h)","RL A", + "RR B","RR C","RR D","RR E","RR H","RR L","RR (I%@h)","RR A", + "SLA B","SLA C","SLA D","SLA E","SLA H","SLA L","SLA (I%@h)","SLA A", + "SRA B","SRA C","SRA D","SRA E","SRA H","SRA L","SRA (I%@h)","SRA A", + "SLL B","SLL C","SLL D","SLL E","SLL H","SLL L","SLL (I%@h)","SLL A", + "SRL B","SRL C","SRL D","SRL E","SRL H","SRL L","SRL (I%@h)","SRL A", + "BIT 0,B","BIT 0,C","BIT 0,D","BIT 0,E","BIT 0,H","BIT 0,L","BIT 0,(I%@h)","BIT 0,A", + "BIT 1,B","BIT 1,C","BIT 1,D","BIT 1,E","BIT 1,H","BIT 1,L","BIT 1,(I%@h)","BIT 1,A", + "BIT 2,B","BIT 2,C","BIT 2,D","BIT 2,E","BIT 2,H","BIT 2,L","BIT 2,(I%@h)","BIT 2,A", + "BIT 3,B","BIT 3,C","BIT 3,D","BIT 3,E","BIT 3,H","BIT 3,L","BIT 3,(I%@h)","BIT 3,A", + "BIT 4,B","BIT 4,C","BIT 4,D","BIT 4,E","BIT 4,H","BIT 4,L","BIT 4,(I%@h)","BIT 4,A", + "BIT 5,B","BIT 5,C","BIT 5,D","BIT 5,E","BIT 5,H","BIT 5,L","BIT 5,(I%@h)","BIT 5,A", + "BIT 6,B","BIT 6,C","BIT 6,D","BIT 6,E","BIT 6,H","BIT 6,L","BIT 6,(I%@h)","BIT 6,A", + "BIT 7,B","BIT 7,C","BIT 7,D","BIT 7,E","BIT 7,H","BIT 7,L","BIT 7,(I%@h)","BIT 7,A", + "RES 0,B","RES 0,C","RES 0,D","RES 0,E","RES 0,H","RES 0,L","RES 0,(I%@h)","RES 0,A", + "RES 1,B","RES 1,C","RES 1,D","RES 1,E","RES 1,H","RES 1,L","RES 1,(I%@h)","RES 1,A", + "RES 2,B","RES 2,C","RES 2,D","RES 2,E","RES 2,H","RES 2,L","RES 2,(I%@h)","RES 2,A", + "RES 3,B","RES 3,C","RES 3,D","RES 3,E","RES 3,H","RES 3,L","RES 3,(I%@h)","RES 3,A", + "RES 4,B","RES 4,C","RES 4,D","RES 4,E","RES 4,H","RES 4,L","RES 4,(I%@h)","RES 4,A", + "RES 5,B","RES 5,C","RES 5,D","RES 5,E","RES 5,H","RES 5,L","RES 5,(I%@h)","RES 5,A", + "RES 6,B","RES 6,C","RES 6,D","RES 6,E","RES 6,H","RES 6,L","RES 6,(I%@h)","RES 6,A", + "RES 7,B","RES 7,C","RES 7,D","RES 7,E","RES 7,H","RES 7,L","RES 7,(I%@h)","RES 7,A", + "SET 0,B","SET 0,C","SET 0,D","SET 0,E","SET 0,H","SET 0,L","SET 0,(I%@h)","SET 0,A", + "SET 1,B","SET 1,C","SET 1,D","SET 1,E","SET 1,H","SET 1,L","SET 1,(I%@h)","SET 1,A", + "SET 2,B","SET 2,C","SET 2,D","SET 2,E","SET 2,H","SET 2,L","SET 2,(I%@h)","SET 2,A", + "SET 3,B","SET 3,C","SET 3,D","SET 3,E","SET 3,H","SET 3,L","SET 3,(I%@h)","SET 3,A", + "SET 4,B","SET 4,C","SET 4,D","SET 4,E","SET 4,H","SET 4,L","SET 4,(I%@h)","SET 4,A", + "SET 5,B","SET 5,C","SET 5,D","SET 5,E","SET 5,H","SET 5,L","SET 5,(I%@h)","SET 5,A", + "SET 6,B","SET 6,C","SET 6,D","SET 6,E","SET 6,H","SET 6,L","SET 6,(I%@h)","SET 6,A", + "SET 7,B","SET 7,C","SET 7,D","SET 7,E","SET 7,H","SET 7,L","SET 7,(I%@h)","SET 7,A" +}; +#if 1 +/** DAsm() ***************************************************/ +/** DAsm() will disassemble the code at adress A and put **/ +/** the output text into S. It will return the number of **/ +/** bytes disassembled. **/ +/*************************************************************/ +static int DAsm(char *S,word A) +{ + char R[128],H[10],C,*T,*P; + byte J,Offset=0; + word B; + + B=A;C='\0';J=0; + + switch(RdZ80(B)) + { + case 0xCB: B++;T=MnemonicsCB[RdZ80(B++)];break; + case 0xED: B++;T=MnemonicsED[RdZ80(B++)];break; + case 0xDD: B++;C='X'; + if(RdZ80(B)!=0xCB) T=MnemonicsXX[RdZ80(B++)]; + else + { B++;Offset=RdZ80(B++);J=1;T=MnemonicsXCB[RdZ80(B++)]; } + break; + case 0xFD: B++;C='Y'; + if(RdZ80(B)!=0xCB) T=MnemonicsXX[RdZ80(B++)]; + else + { B++;Offset=RdZ80(B++);J=1;T=MnemonicsXCB[RdZ80(B++)]; } + break; + default: T=Mnemonics[RdZ80(B++)]; + } + + if((P=strchr(T,'^'))) + { + strncpy(R,T,P-T);R[P-T]='\0'; + sprintf(H,"%02X",RdZ80(B++)); + strcat(R,H);strcat(R,P+1); + } + else strcpy(R,T); + if((P=strchr(R,'%'))) *P=C; + + if((P=strchr(R,'*'))) + { + strncpy(S,R,P-R);S[P-R]='\0'; + sprintf(H,"%02X",RdZ80(B++)); + strcat(S,H);strcat(S,P+1); + } + else + if((P=strchr(R,'@'))) + { + strncpy(S,R,P-R);S[P-R]='\0'; + if(!J) Offset=RdZ80(B++); + strcat(S,Offset&0x80? "-":"+"); + J=Offset&0x80? 256-Offset:Offset; + sprintf(H,"%02X",J); + strcat(S,H);strcat(S,P+1); + } + else + if((P=strchr(R,'#'))) + { + strncpy(S,R,P-R);S[P-R]='\0'; + sprintf(H,"%04X",RdZ80(B)+256*RdZ80(B+1)); + strcat(S,H);strcat(S,P+1); + B+=2; + } + else strcpy(S,R); + + return(B-A); +} + +/** DebugZ80() ***********************************************/ +/** This function should exist if DEBUG is #defined. When **/ +/** Trace!=0, it is called after each command executed by **/ +/** the CPU, and given the Z80 registers. **/ +/*************************************************************/ +byte DebugZ80(Z80 *R) +{ + static char Flags[8] = "SZ.H.PNC"; + char S[128],T[10]; + byte J,I; + + DAsm(S,R->PC.W); + for(J=0,I=R->AF.B.l;J<8;J++,I<<=1) T[J]=I&0x80? Flags[J]:'.'; + T[8]='\0'; + + printf + ( + "AF:%04X HL:%04X DE:%04X BC:%04X PC:%04X SP:%04X IX:%04X IY:%04X\n", + R->AF.W,R->HL.W,R->DE.W,R->BC.W,R->PC.W,R->SP.W,R->IX.W,R->IY.W + ); + printf + ( + "AT PC: [%02X - %s] AT SP: [%04X] FLAGS: [%s]\n\n", + RdZ80(R->PC.W),S,RdZ80(R->SP.W)+RdZ80(R->SP.W+1)*256,T + ); + + while(1) + { + printf("\n[Command,'?']-> "); + fflush(stdout);fflush(stdin); + + fgets(S,50,stdin); + for(J=0;S[J]>=' ';J++) + S[J]=toupper(S[J]); + S[J]='\0'; + + switch(S[0]) + { + case 'H': + case '?': + puts("\n***** Built-in Z80 Debugger Commands *****"); + puts(" : Break at next instruction"); + puts("= : Break at addr"); + puts("+ : Break at PC + offset"); + puts("c : Continue without break"); + puts("j : Continue from addr"); + puts("m : Memory dump at addr"); + puts("d : Disassembly at addr"); + puts("?,h : Show this help text"); + puts("q : Exit Z80 emulation"); + break; + + case '\0': return(1); + case '=': if(strlen(S)>=2) + { sscanf(S+1,"%hX",&(R->Trap));R->Trace=0;return(1); } + break; + case '+': if(strlen(S)>=2) + { + sscanf(S+1,"%hX",&(R->Trap)); + R->Trap+=R->PC.W;R->Trace=0; + return(1); + } + break; + case 'J': if(strlen(S)>=2) + { sscanf(S+1,"%hX",&(R->PC.W));R->Trace=0;return(1); } + break; + case 'C': R->Trap=0xFFFF;R->Trace=0;return(1); + case 'Q': return(0); + + case 'M': + { + word Addr; + + if(strlen(S)>1) sscanf(S+1,"%hX",&Addr); else Addr=R->PC.W; + puts(""); + for(J=0;J<16;J++) + { + printf("%04X: ",Addr); + for(I=0;I<16;I++,Addr++) + printf("%02X ",RdZ80(Addr)); + printf(" | ");Addr-=16; + for(I=0;I<16;I++,Addr++) + putchar(isprint(RdZ80(Addr))? RdZ80(Addr):'.'); + puts(""); + } + } + break; + + case 'D': + { + word Addr; + + if(strlen(S)>1) sscanf(S+1,"%hX",&Addr); else Addr=R->PC.W; + puts(""); + for(J=0;J<16;J++) + { + printf("%04X: ",Addr); + Addr+=DAsm(S,Addr); + puts(S); + } + } + break; + } + } + + /* Continue emulation */ + return(1); +} +#endif +#endif /* DEBUG */ diff --git a/TIKI-100_emul-src/LESMEG b/TIKI-100_emul-src/LESMEG new file mode 100644 index 0000000..4c65e4b --- /dev/null +++ b/TIKI-100_emul-src/LESMEG @@ -0,0 +1,140 @@ +TIKI-100_emul V1.1.1, 25 august 2001 +------------------------------------ + +Dette er kildefilene til TIKI-100_emul. Denne fila gir en oppskrift på +hvordan kompilere. Den gir også en generell beskrivelse av +kildefilene dersom du skulle være interessert i det, men det er ikke +nødvendig dersom du bare vil kompilere og få en kjørbar emulator. For +mer informasjon om bruk av emulatoren, se TIKI-100_emul.txt. + +Bortsett fra filene til Z80-emulatoren, er alle kildefilene mine. Jeg +gir tillatelse til å bruke og spre disse fritt. Men ønsker du å gjøre +forandringer vil jeg at du tar kontakt med meg. Dette fordi jeg ikke +anser meg for ferdig med emulatoren enda. På den måten unngår vi at +flere forskjellige personer jobber på de samme tingene. Men kom gjerne +med forslag til hvordan ting kan gjøres bedre. + +Disse kildefilene skal ikke brukes til kommersielle formål på noen som +helst måte, hverken i original eller modifisert form. + +Kompilering: +------------ + +Kompilering skal være temmelig enkelt. Kildefilene er skrevet i +ansi-c og skal kompilere med de aller fleste c-kompilatorer. Makefile +er skrevet for GCC og GNU make. For unix vil du ofte ha det som trengs +allerede. For win32 må du skaffe deg cygwin, som finnes gratis på +http://www.cygwin.com. En full installasjon anbefales. Amigaversjonen +kan kompileres med verktøyene fra Geek Gadgets som finnes gratis på +http://www.ninemoons.com. Dessuten trenger du NDK fra Amiga +International, inc. Disse finner du bl.a på Amiga Developer CD. + +Før kompilering må filen Makefile justeres til å passe ditt +system. For Amiga og win32 vil dette bare bestå i å velge rett +system. For unix må du i tillegg sette en del andre ting. Alt dette +skal være forklart i Makefile. + +Etter dette er det bare å skrive "make" i katalogen du har kildefilene +i. Resultatet blir en kjørbar fil tikiemul eller tikiemul.exe. Kopier +(minimum) denne fila og tiki.rom dit du ønsker å ha programmet. I +tillegg anbefaler jeg at du kopierer plater-katalogen og +TIKI-100_emul.txt til samme plass. Så skulle alt være klart til bruk. + +Har du problemer, så ta kontakt med meg. + +Generell beskrivelse av kildefiler: +----------------------------------- + +Skal du forstå hvordan denne emulatoren virker, bør du kjenne til +hvordan en TIKI-100 fungerer. Se på min TIKI-100 hjemmeside for mer +informasjon om det. + +Disse filene skal være med: + +Systemuavhengige filer (selve emulatorkoden): +- TIKI-100_emul.c Hovedmodul, inneholder toppnivå + emulatorrutiner +- TIKI-100_emul.h Inneholder alle prototyper, konstanter + etc. som er nødvendig for den + systemspesifikke koden. +- ctc.c Z80-CTC emulering +- disk.c FD17xx emulering +- keyboard.c Tastaturhåndtering +- mem.c RAM og I/O-port håndtering +- parallel.c Z80-PIO emulering +- protos.h Prototyper for funksjoner internt i den + systemuavhengige koden. +- serial.c Z80-DART emulering +- sound.c AY-3-8912 emulering +- video.c Videoemulering + +Z80-emulator av Marat Fayzullin. Disse filene er inkludert med +tillatelse men tilhører ikke meg. Les egen copyrightnotis i filene og +se på http://www.komkon.org/fms/EMUL8 for mer informasjon: +- Z80.c +- Z80.h +- Codes.h +- CodesCB.h +- CodesED.h +- CodesXCB.h +- CodesXX.h +- Debug.c +- Tables.h + +Systemkode for Amiga: +- amiga.c +- amiga.cd Katalogdeskriptor (locale) +- amiga_icons/* Diverse ikoner +- amiga_translations/* Oversettelser til andre språk + +Systemkode for win32: +- win32.c +- win32.ico Ikoner +- win32_res.h Konstanter brukt av resources +- win32_res.rc Resources + +Systemkode for unix: +- unix.c + +Andre filer: +- Makefile GNU make kompatibel Makefile +- plater/t90.dsk Tom 90k diskfil +- plater/t200.dsk Tom 200k diskfil +- plater/t400.dsk Tom 400k diskfil +- plater/t800.dsk Tom 800k diskfil +- plater/tiko_kjerne_v4.01.dsk TIKO-systemdiskett +- tiki.rom TIKI-100 rombilde +- TIKI-100_emul.txt Beskrivelse av emulatoren +- LESMEG Filen du leser på nå + +Som du ser kan kildefilene deles inn i 2 grupper. Den systemuavhengige +koden som inneholder alt som kan programmeres uten bruk av annet enn +standard c-bibliotek, og systemkoden som inneholder de tingene som må +programmeres for et spesielt system (bl.a GUI). Dette vil si at all +emulatorlogikk er adskilt fra systemkoden. + +Grensesnittet mellom disse to delene er laget så enkelt som mulig og +er definert i TIKI-100_emul.h (i form av prototyper for funksjoner som +må implementeres og funksjoner som kan kalles). Dette er den eneste +fila man trenger kjennskap til dersom man ønsker å lage en versjon for +et nytt system. Har du lyst til dette, så ta kontakt med meg. + +Emulatorens main() funksjon (eller tilsvarende) befinner seg i +systemkoden. Når systemkoden er klar til å starte emulatorkoden kaller +den runEmul() som tar over kontrollen (går i en uendelig loop). Hver +80.000 cycle (skal tilsvare 20 ms) kalles funksjonen loopEmul() i +systemkoden. Dette gjør systemkoden i stand til å måle og senke +hastighet samt sjekke brukeraktivitet. Resten av funksjonene som +systemkoden må implementere (definert i TIKI-100_emul.h) kalles +etterhvert som emulatoren har bruk for de. + +Etter noe initialisering vil runEmul() starte Z80 emulator. Z80 +emulator trenger funksjoner for å lese/skrive til/fra +RAM/ROM/IO. Disse (sammen med emulert RAM/ROM) er implementert i +mem.c. Disse funksjonene vil, hver gang Z80 emulator benytter I/O, +kalle en funksjon i en av de andre c-filene. F.eks dersom Z80 leser +fra I/O-port 0x03 (tastatur-register) vil funksjonen readKeyboard() i +keyboard.c kalles. Tilsvarende for alle andre I/O-porter. + +--- +Asbjørn Djupdal, djupdal@stud.ntnu.no diff --git a/TIKI-100_emul-src/Makefile b/TIKI-100_emul-src/Makefile new file mode 100644 index 0000000..e6b5d07 --- /dev/null +++ b/TIKI-100_emul-src/Makefile @@ -0,0 +1,148 @@ +# Makefile for TIKI-100_emul V1.1 +# Asbjørn Djupdal 2001 +# +# make - Bygger emulator +# make clean - Sletter alle automatisk genererte filer +# make amiga_translations - kompilerer catalog-filer for Amiga-versjon + +#------------------------------------------------------------------------------ +# Generelle innstillinger +#------------------------------------------------------------------------------ + +# Velg system du skal kompilere for: +#SYSTEM = amiga +#SYSTEM = win32 +SYSTEM = unix + +# Ta med denne dersom Z80-debugger ønskes inkludert: +#Z80_DEBUGGER = -DDEBUG + +# Velg C-kompilator du ønsker å bruke: +CC = gcc + +# Generelle kompilatoropsjoner: +CFLAGS = -Wall -O + +# Generelle linkeropsjoner: +LDFLAGS = -s + +#------------------------------------------------------------------------------ +# Dersom SYSTEM=unix må følgende settes: +#------------------------------------------------------------------------------ + +# Velg CPU-type - big-endian eller little-endian: +#ENDIAN = -DMSB_FIRST # big-endian CPU, bl.a: M68k, Sun-maskiner +ENDIAN = -DLSB_FIRST # little-endian CPU, bl.a: intel-x86 + +# Skriv inn stien til X11-includefiler: +X11_INCLUDE_PATH = -I/usr/X11R6/include + +# Skriv inn stien til X11-linkbibliotek: +X11_LIB_PATH = -L/usr/X11R6/lib + +# Skriv inn hvilke bibliotek som må linkes: +X11_LINK_LIBS = -lX11 + +#------------------------------------------------------------------------------ +# Det skal ikke være nødvendig å forandre på resten av denne filen! +#------------------------------------------------------------------------------ + +#------------------------------------------------------------------------------ +# Systemspesifikke innstillinger +#------------------------------------------------------------------------------ + +# amiga +CFLAGS_amiga = -DMSB_FIRST $(CFLAGS) $(Z80_DEBUGGER) +LDFLAGS_amiga = -lm -noixemul $(LDFLAGS) +SYS_OBJECTS_amiga = amiga.o + +# win32 +NO_CONSOLE_ = -mno-cygwin -Wl,--subsystem,windows +CFLAGS_win32 = -DLSB_FIRST $(CFLAGS) $(Z80_DEBUGGER) +LDFLAGS_win32 = $(NO_CONSOLE_$(Z80_DEBUGGER)) -e _mainCRTStartup -lgdi32 -lcomdlg32 -lcomctl32 $(LDFLAGS) +SYS_OBJECTS_win32 = win32.o win32_res.res + +# unix +CFLAGS_unix = $(ENDIAN) $(X11_INCLUDE_PATH) $(CFLAGS) $(Z80_DEBUGGER) +LDFLAGS_unix = $(LDFLAGS) $(X11_LIB_PATH) $(X11_LINK_LIBS) +SYS_OBJECTS_unix = unix.o + +#------------------------------------------------------------------------------ +# Regler +#------------------------------------------------------------------------------ + +# Alle objektfiler som skal linkes +OBJECTS = TIKI-100_emul.o mem.o video.o sound.o ctc.o keyboard.o disk.o serial.o parallel.o Z80.o Debug.o $(SYS_OBJECTS_$(SYSTEM)) + +tikiemul : $(OBJECTS) Makefile + $(CC) -o $@ $(OBJECTS) $(LDFLAGS_$(SYSTEM)) + +TIKI-100_emul.o : TIKI-100_emul.c TIKI-100_emul.h protos.h Z80.h Makefile + $(CC) -c $< $(CFLAGS_$(SYSTEM)) + +mem.o : mem.c TIKI-100_emul.h protos.h Z80.h Makefile + $(CC) -c $< $(CFLAGS_$(SYSTEM)) + +video.o : video.c TIKI-100_emul.h protos.h Z80.h Makefile + $(CC) -c $< $(CFLAGS_$(SYSTEM)) + +sound.o : sound.c TIKI-100_emul.h protos.h Z80.h Makefile + $(CC) -c $< $(CFLAGS_$(SYSTEM)) + +ctc.o : ctc.c TIKI-100_emul.h protos.h Z80.h Makefile + $(CC) -c $< $(CFLAGS_$(SYSTEM)) + +keyboard.o : keyboard.c TIKI-100_emul.h protos.h Z80.h Makefile + $(CC) -c $< $(CFLAGS_$(SYSTEM)) + +disk.o : disk.c TIKI-100_emul.h protos.h Z80.h Makefile + $(CC) -c $< $(CFLAGS_$(SYSTEM)) + +serial.o : serial.c TIKI-100_emul.h protos.h Z80.h Makefile + $(CC) -c $< $(CFLAGS_$(SYSTEM)) + +parallel.o : parallel.c TIKI-100_emul.h protos.h Z80.h Makefile + $(CC) -c $< $(CFLAGS_$(SYSTEM)) + +Z80.o : Z80.c Z80.h Codes.h CodesED.h CodesCB.h CodesXX.h Tables.h CodesXCB.h Makefile + $(CC) -c $< $(CFLAGS_$(SYSTEM)) + +Debug.o : Debug.c Z80.h Makefile + $(CC) -c $< $(CFLAGS_$(SYSTEM)) + +.PHONY : clean +clean : + rm -rf tikiemul tikiemul.exe amiga_strings.h *.res *.o *~ catalogs + +#------ +# amiga +#------ + +amiga.o : amiga.c amiga_strings.h TIKI-100_emul.h Z80.h Makefile + $(CC) -c $< $(CFLAGS_$(SYSTEM)) + +amiga_strings.h : amiga.cd Makefile + catcomp DESCRIPTOR amiga.cd CFILE amiga_strings.h + +.PHONY : amiga_translations +amiga_translations : + mkdir -p catalogs/norsk + catcomp DESCRIPTOR amiga.cd TRANSLATION amiga_translations/norsk.ct CATALOG catalogs/norsk/tikiemul.catalog VB 0 + +#------ +# win32 +#------ + +win32.o : win32.c win32_res.h TIKI-100_emul.h Z80.h Makefile + $(CC) -c $< $(CFLAGS_$(SYSTEM)) + +win32_res.res : win32_res.rc win32_res.h TIKI-100_emul.h Z80.h Makefile + windres $< $(Z80_DEBUGGER) -O coff -o $@ + +#------ +# unix +#------ + +unix.o : unix.c TIKI-100_emul.h Z80.h Makefile + $(CC) -c $< $(CFLAGS_$(SYSTEM)) + diff --git a/TIKI-100_emul-src/TIKI-100_emul-eng.txt b/TIKI-100_emul-src/TIKI-100_emul-eng.txt new file mode 100644 index 0000000..fd28c1c --- /dev/null +++ b/TIKI-100_emul-src/TIKI-100_emul-eng.txt @@ -0,0 +1,32 @@ +TIKI-100_emul V1.1.1, 25-aug-2001 + +A freeware TIKI-100 Rev. C emulator + +Z80 emulation copyright (C) Marat Fayzullin +The rest is copyright (C) Asbjørn Djupdal + +I permit redistribution and free use of this emulator. It is not legal +to use it for commersial purposes. + +--------------------------------------------------------------------------- + +This emulator emulates the TIKI-100 computer, a norwegian +home computer released in 1984. It uses a norwegian operating system, +TIKO, compatible with CP/M-2.2. + +It should be quite easy to understand how to use the emulator if you +are familiar with how emulators in general works. If you have any +problems at all, contact me (email-address below). + +I'm sorry this text doesn't describe the emulator in more detail, but +because of it's norwegian operating system I guess most people that is +interested can read norwegian. See the norwegian text for more detail. + +My TIKI-100 homepage, with TIKI programs, information and +emulator-source/binaries is located here (norwegian only): + +http://www.stud.ntnu.no/~djupdal/tiki/ + +Send comments and questions to: + +djupdal@stud.ntnu.no diff --git a/TIKI-100_emul-src/TIKI-100_emul.c b/TIKI-100_emul-src/TIKI-100_emul.c new file mode 100644 index 0000000..81ef3ef --- /dev/null +++ b/TIKI-100_emul-src/TIKI-100_emul.c @@ -0,0 +1,58 @@ +/* TIKI-100_emul.c V1.1.0 + * + * Hovedmodul for TIKI-100_emul + * Copyright (C) Asbjørn Djupdal 2000-2001 + */ + +#include "TIKI-100_emul.h" +#include "protos.h" + +/* variabler */ + +Z80 cpu; +static boolean done = FALSE; + +/*****************************************************************************/ + +/* starter emulering, returnerer når emulering avslutter */ +boolean runEmul (void) { +#ifdef DEBUG + cpu.Trap = 0xffff; +#endif + cpu.IPeriod = 4000; + if (initMem()) { + ResetZ80 (&cpu); + RunZ80 (&cpu); + return TRUE; + } + return FALSE; +} +/* ikke i bruk */ +void PatchZ80 (register Z80 *R) { +} +/* kalles regelmessig av z80-emulator */ +word LoopZ80 (register Z80 *R) { + static int guiCount = 20; + if (done) return INT_QUIT; + updateCTC (cpu.IPeriod); + if (--guiCount == 0) { + loopEmul (20); + guiCount = 20; + } + return INT_NONE; +} +/* reset emulator */ +void resetEmul (void) { + OutZ80 (0x1c, 0x00); + ResetZ80 (&cpu); +} +/* avslutt emulator */ +void quitEmul (void) { + done = TRUE; +} +#ifdef DEBUG +/* start z80-debugger */ +void trace (void) { + cpu.Trace = 1; +} +#endif diff --git a/TIKI-100_emul-src/TIKI-100_emul.h b/TIKI-100_emul-src/TIKI-100_emul.h new file mode 100644 index 0000000..4a44e8c --- /dev/null +++ b/TIKI-100_emul-src/TIKI-100_emul.h @@ -0,0 +1,200 @@ +/* TIKI-100_emul.h V1.1.0 + * + * Definisjoner og konstanter nyttige for alle TIKI-100_emul moduler + * Copyright (C) Asbjørn Djupdal 2000-2001 + */ + +#ifndef TIKI_EMUL_H +#define TIKI_EMUL_H + +#include "Z80.h" + +/* byte og word definert i Z80.h */ +typedef short boolean; + +#define TRUE ~0 +#define FALSE 0 + +/* video */ + +#define HIGHRES 16 /* 1024 * 256 * 2 */ +#define MEDRES 32 /* 512 * 256 * 4 */ +#define LOWRES 48 /* 256 * 256 * 16 */ + +/* serie */ + +enum parity { + PAR_NONE, PAR_EVEN, PAR_ODD +}; +enum stopBits { + ONE_SB, ONE_PT_FIVE_SB, TWO_SB +}; +struct serParams { + int receiveBits; /* antall bits i innkommende tegn */ + int sendBits; /* antall bits i tegn som sendes */ + int parity; /* paritet, en av de angitt over */ + int stopBits; /* antall stopbits, en av de angitt over */ + int baud; /* baud */ + /* følgende er kun for bruk i serial.c: */ + int regPtr; + int clkDiv; + boolean exi; + boolean txi; + boolean sav; + int rxi; + boolean rxe; + boolean ae; + boolean txe; + boolean rxa; + boolean newChar; +}; + +/* tastatur - ikke-alfanumeriske taster */ + +#define KEY_NONE 0x80 +#define KEY_CTRL 0x81 +#define KEY_SHIFT 0x82 +#define KEY_BRYT 0x03 +#define KEY_CR 0x0d +#define KEY_SPACE 0x20 +#define KEY_SLETT 0x7f +#define KEY_GRAFIKK 0x84 +#define KEY_ANGRE 0x1a +#define KEY_LOCK 0x83 +#define KEY_HJELP 0x0a +#define KEY_LEFT 0x08 +#define KEY_UTVID 0x05 +#define KEY_F1 0x01 +#define KEY_F4 0x07 +#define KEY_RIGHT 0x0c +#define KEY_F2 0x02 +#define KEY_F3 0x06 +#define KEY_F5 0x0e +#define KEY_F6 0x0f +#define KEY_DOWN 0x1c +#define KEY_PGUP 0x17 +#define KEY_PGDOWN 0x1f +#define KEY_UP 0x0b +#define KEY_HOME 0x09 +#define KEY_TABLEFT 0x1d +#define KEY_TABRIGHT 0x18 +#define KEY_NUMDIV 0x80 | 0x2f +#define KEY_NUMPLUS 0x80 | 0x2b +#define KEY_NUMMINUS 0x80 | 0x2d +#define KEY_NUMMULT 0x80 | 0x2a +#define KEY_NUMPERCENT 0x80 | 0x25 +#define KEY_NUMEQU 0x80 | 0x3d +#define KEY_ENTER 0x80 | 0x0d +#define KEY_NUM0 0x80 | 0x30 +#define KEY_NUM1 0x80 | 0x31 +#define KEY_NUM2 0x80 | 0x32 +#define KEY_NUM3 0x80 | 0x33 +#define KEY_NUM4 0x80 | 0x34 +#define KEY_NUM5 0x80 | 0x35 +#define KEY_NUM6 0x80 | 0x36 +#define KEY_NUM7 0x80 | 0x37 +#define KEY_NUM8 0x80 | 0x38 +#define KEY_NUM9 0x80 | 0x39 +#define KEY_NUMDOT 0x80 | 0x2e + +/* Må implementeres av system-koden + **********************************/ + +/* Forandre oppløsning. + * Må samtidig fylle alle pixler med farge 0 + */ +void changeRes (int newRes); + +/* Plott en pixel med farge tatt fra pallett */ +void plotPixel (int x, int y, int color); + +/* Scroll skjerm 'distance' linjer oppover + * 'distance' kan være både positiv og negativ + */ +void scrollScreen (int distance); + +/* Ny farge, gitt pallettnummer og intensitet 0-255. + * Må oppdatere alle pixler med dette pallettnummeret til ny farge + */ +void changePalette (int colornumber, byte red, byte green, byte blue); + +/* Kalles periodisk. Lar system kode måle / senke emuleringshastighet + * Kan også brukes til sjekk av brukeraktivitet / serieporter + * ms er antall "emulerte" millisekunder siden forrige gang loopEmul ble kalt + */ +void loopEmul (int ms); + +/* Tenn/slukk lock lys */ +void lockLight (boolean status); + +/* Tenn/slukk grafikk lys */ +void grafikkLight (boolean status); + +/* Tenn/slukk disk lys for gitt stasjon */ +void diskLight (int drive, boolean status); + +/* Sjekk status til hver av de gitte tastene + * Sett bit n i returkode hvis tast n IKKE er nedtrykt + * Taster er enten ascii-kode eller en av konstantene over + */ +byte testKey (byte keys[8]); + +/* Setter seriekanalparametre */ +void setParams (struct serParams *p1Params, struct serParams *p2Params); + +/* Send tegn til seriekanal + * port = 0: port 1 + * port = 1: port 2 + */ +void sendChar (int port, byte value); + +/* Hent tegn fra seriekanal + * port = 0: port 1 + * port = 1: port 2 + */ +byte getChar (int port); + +/* Send tegn til skriver (port 3) */ +void printChar (byte value); + +/* Kan kalles av system-koden + ****************************/ + +/* Starter emulering, returnerer når emulering avsluttes + * Returverdi ved feil: FALSE + * Ellers returneres TRUE (etter at quitEmul() er kalt) + */ +boolean runEmul (void); + +/* Ny diskett i stasjon + * disk: Hvilken stasjon (0 eller 1) + * diskImage: Peker til diskettbilde-data + * Resten er diskparametre + */ +void insertDisk (int drive, byte *diskImage, int tracks, + int sides, int sectors, int sectSize); + +/* Fjern diskett fra stasjon (0 eller 1) */ +void removeDisk (int drive); + +/* Resetter TIKI-100 */ +void resetEmul (void); + +/* Avslutter emulator */ +void quitEmul (void); + +#ifdef DEBUG +/* Åpner avlusnings monitor */ +void trace (void); +#endif + +/* Setter bøyle ST 28 b */ +void setST28b (boolean status); + +/* Nytt serietegn mottatt + * port = 0: port 1 + * port = 1: port 2 + */ +void charAvailable (int port); + +#endif diff --git a/TIKI-100_emul-src/TIKI-100_emul.txt b/TIKI-100_emul-src/TIKI-100_emul.txt new file mode 100644 index 0000000..d1c4b39 --- /dev/null +++ b/TIKI-100_emul-src/TIKI-100_emul.txt @@ -0,0 +1,339 @@ +TIKI-100_emul V1.1.1, 25 august 2001 + +En freeware TIKI-100 Rev. C emulator + +Z80 emulering copyright (C) Marat Fayzullin. +Resten copyright (C) Asbjørn Djupdal. + +Jeg gir tillatelse til å bruke og spre denne emulatoren fritt bortsett +fra til kommersielle formål. Det skal aldri tjenes penger på denne +emulatoren. + + +Introduksjon +------------ + +TIKI-100 er en norskbygd maskin lansert i 1984. Den kjører et norsk +operativsystem, TIKO, som er kompatibelt med CP/M-2.2. Maskina har en +Z80A på 4MHz, fargegrafikk og 3 kanalers lyd. Den ble mye brukt i norske +skoler. + +Programmet du nå leser om er en TIKI-100 emulator, dvs et program som +lar deg kjøre all programvare som finnes til TIKI-100 på en mer +moderne datamaskin. + +Emulatoren er skrevet i C. Kildefilene er tilgjengelig på emulatorens +hjemmeside: http://www.stud.ntnu.no/~djupdal/tiki/emulator/ + +Hva som emuleres +---------------- + +- Z80 CPU +- CTC klokkekrets +- DART rs-232 serieporter (begrenset) +- PIO parallellporter (svært begrenset) +- Videokrets +- FD17xx diskettkontroller +- Div andre småting som minnehåndtering, tastatur, etc. + +Hva som mangler +--------------- + +- AY-3-8912 lydgenerator +- Modemsignaler (DART). Emulering av serieporter skjer uten noen + kontroll på modemsignaler. +- Skikkelig emulering av parallellporter (PIO). Nå emuleres bare + det aller mest nødvendige for å kunne bruke skriver. +- Emulering av diverse tilleggsutstyr (harddisk, 8088-kort, etc.) + +Bruk av emulatoren +------------------ + +Denne emulatoren er en såkalt maskinvareemulator, dvs den etterligner +maskinvaren i en TIKI-100. Det gjør at alle operativsystemer som +finnes til TIKI-100 vil kjøre på denne emulatoren, såfremt de ikke +forutsetter tilleggsutstyr som ikke støttes. + +Når emulatoren starter opp prøver den å laste inn fila +"tiki.rom". Denne inneholder en kopi av ROM'en i en ekte +TIKI-100. Ønsker du å bruke en annen ROM kan du bare bytte ut denne +fila. Emulatoren støtter alle ROM-filer opp til 16kB, akkurat som en +ekte TIKI-100. OBS: En slik fil MÅ være tilstede! + +Emulatoren bruker diskettfiler. En diskettfil er en TIKI-100 diskett +som i sin helhet har blitt kopiert inn på en enkelt fil. Det som er +viktig å vite om diskettfilene i denne emulatoren er at forandringer +som gjøres på en diskett i emulatoren ikke blir lagret før du +eksplisitt ber emulatoren om det. + +Etter at emulatoren har startet opp vil du få det velkjente TIKI-100 +oppstartsbildet på skjermen: "Sett inn en TIKI diskett og trykk B" + +Bruk av emulatoren utenom dette avhenger av hvilken versjon du bruker. + +Amiga-versjonen +--------------- + +Merk at serieporter og parallellport foreløpig ikke støttes av +Amigaversjonen. + +Nederst i emulatorvinduet ser du 4 "lysdioder". Disse tilsvarer +lysdiodene på lock-tasten, grafikk-tasten, diskettstasjon a og +diskettstasjon b. + +Amigaversjonen har disse menyene som burde være selvforklarende: + + - Emulator + - Reset + - Om... + - Avslutt + - Diskettstasjon + - Hent plate A... + - Hent plate B... + - Lagre plate A... + - Lagre plate B... + - Fjern plate A... + - Fjern plate B... + - Innstillinger + - Begrens hastighet (foreløpig ikke i bruk) + - Bevar forhold + - 40-modus størrelse + - Standard + - Fordoblet + - Firedoblet + - 80-modus størrelse + - Standard + - Fordoblet + +Plassering av TIKI taster på tastaturet: + + GRAFIKK: ` (til venstre for tasten 1) + BRYT: Tab + ANGRE: Esc + LOCK: Venstre Alt + UTVID: \ (til venstre for slettetasten) + HJEM: Del + Side opp: F7 + Side ned: F8 + Venstre tab: F9 + Høyre tab: F10 + %: [ (på numerisk tastatur) + =: ] (på numerisk tastatur) + +Resten av tastene er plassert på de tilsvarende Amiga-tastene. + +Win32-versjonen +--------------- + +Nederst i emulatorvinduet ser du 4 "lysdioder". Disse tilsvarer +lysdiodene på lock-tasten, grafikk-tasten, diskettstasjon a og +diskettstasjon b. + +Win32-versjonen har disse menyene som burde være selvforklarende: + + - Emulator + - Reset + - Innstillinger... + - Om... + - Avslutt + - diskettstasjon + - Hent plate A... + - Hent plate B... + - Lagre plate A... + - Lagre plate B... + - Fjern plate A + - Fjern plate B + +Menyvalget "Innstillinger" bringer fram en dialogboks der du kan +stille inn diverse: + + - Merk "Senk hastighet" dersom du vil at emulatoren skal kjøre på + samme hastighet som en ekte TIKI-100. Denne har bare virkning + dersom din datamaskin er for rask. + - Alt innenfor boksen "Skjermforstørring" styrer forstørring av + TIKI-skjermbilde. "Bevar forhold" gir samme forhold på + emulatorvinduet som på en ekte TIKI-skjerm. + - Det innenfor boksen "Porter" bestemmer hvordan de emulerte + TIKI-portene skal brukes. Skriv inn navnet på PC-portene du vil + skal benyttes til de forskjellige TIKI-portene. Skriver du inn et + filnavn i stedet vil alt som skulle blitt sendt til en port i + stedet bli lagret til den fila. + Merker du av "Sett ST 28 b" vil du få samme effekt som om du satte + den tilsvarende bøylen ("jumper'en") i en ekte TIKI-100. Du vil + neppe få bruk for denne. + +Plassering av TIKI taster på tastaturet: + + GRAFIKK: | (til venstre for tasten 1) + BRYT: Tab + ANGRE: Esc + UTVID: Insert + Venstre tab: Delete + Høyre tab: End + HJELP: F8 + ENTER (num): F9 + %: F11 + =: F12 + +Resten av tastene er plassert på de tilsvarende PC-tastene. + +Unix-versjonen +-------------- + +Nederst i emulatorvinduet ser du 4 "lysdioder". Disse tilsvarer +lysdiodene på lock-tasten, grafikk-tasten, diskettstasjon a og +diskettstasjon b. + +Trykk Escape-tasten i emulatorvinduet for å gå inn i kommandomodus. Da +vil en prompt komme fram i xtermen du startet emulatoren fra. Følgende +kommandoer kan da skrives inn: + +hjelp : Vis hjelpetekst +h : Forkortelse for 'hjelp' + +disk : Hent inn diskettfil +d : Forkortelse for 'disk ...' + +lagre : Lagre diskettfil +l : Forkortelse for 'lagre...' + +fjern : Fjern diskettfil +f : Forkortelse for 'fjern...' + +pk [kommandonavn] : Send utskrift til print-kommando + +pf [filnavn] : Send utskrift til fil + +reset : Reset emulator + +fortsett : Fortsett emulering +c : Forkortelse for 'fortsett' + +om : Om emulator (bl.a versjonsnummer) + +avslutt : Avslutt emulator +q : Forkortelse for 'avslutt' + +Alle diskettkommandoene tar et stasjonsargument. Det er enten a eller +b, avhengig av hvilken diskettstasjon du ønsker å benytte kommandoen +på. Stasjon a er oppstartsdiskettstasjonen i en TIKI-100. + +Eksempel: For å hente inn diskettfil 'plater/tiko_kjerne_v4.01.dsk' +til stasjon a skriver du: 'disk a plater/tiko_kjerne_v4.01.dsk'. + +Kommandoene pk og pf spesifiserer hhv en printkommando eller en fil +som utskrift fra TIKI-programmer skal sendes til. Dersom du ønsker å +skru av utskriftsmulighetene igjen så gi kommandoen uten argument. Du +kan skrive til både kommando og fil samtidig. Vær oppmerksom på at +utskrift til en printkommando som oftest ikke sendes til skriver før +forbindelsen til den avsluttes. Så selv om TIKI-programmet er ferdig +med utskriften må du avslutte printkommando med "pk" for å sende +utskrift til skriver. + +Eksempel: For å sende utskrift til kommandoen 'lpr' skriver du: +'pk lpr'. For å sende utskrift til fila 'utskrift' skriver du: +'pf utskrift'. + +Plassering av TIKI taster på tastaturet: + +BRYT: Break, F10 +SLETT: BackSpace, Delete +GRAFIKK: F8 +ANGRE: Redo, F9 +LOCK: Caps_Lock, Shift_Lock, F7 +HJELP: Help, F11 +UTVID: Insert, F12 +Venstre TAB: Prior +Høyre TAB: Tab, Next + +Navnet på TIKI-tasten er til venstre og navnet på den (eller de) +tilsvarende X11-keysym tasten(e) er til høyre. For mer informasjon om +keysyms, les man-siden til 'xmodmap'. + +Resten av tastene er mappet til tilsvarende keysyms. Merk at TIKI-100 +bare har 6 F-taster, så dersom et program ber deg trykke på F7, er det +antakelig ute etter shift-F1 i stedet. + +Følgende kommandolinjeargumenter kan benyttes ved oppstart: + + -display Angi display + -d Samme som over + + -geometry Angi vindusplassering (størrelse ignoreres) + -g Samme som over + + -diska Angi diskettfil til stasjon A + -diskb Angi diskettfil til stasjon B + + -bevarforhold Emulatorvindu har samme forhold som en ekte + TIKI-skjerm + -ikkebevarforhold Negasjonen av den over + + -40x Angi forstørring av 40-modus skjerm (1-4) + -80x Angi forstørring av 80-modus skjerm (1-2) + + -begrens Dersom datamaskin er for rask, sett ned + hastigheten til "normal" TIKI-100 + hastighet + -ikkebegrens Negasjonen av den over + + -port1 Angi hvilken device du vil skal benyttes til + TIKI-serieport P1 (f.eks /dev/tty00) + -port2 Samme som -port1 men for TIKI-serieport P2. + + -pk Angi hvilken kommando utskrift skal sendes til. + -pf Angi hvilken fil utskrift skal sendes til. + + -st28b Tilsvarende å sette bøyle ('jumper') ST 28 b i en + ekte TIKI-100. Du vil neppe få bruk for denne. + -ikkest28b Negasjonen av den over + +Disse kan også settes i .Xresources filen: + +Tikiemul.geometry (geometry) +Tikiemul.diska (filnavn) +Tikiemul.diskb (filnavn) +Tikiemul.bevarforhold (on eller off) +Tikiemul.40x (1-4) +Tikiemul.80x (1-2) +Tikiemul.begrens (on eller off) +Tikiemul.port1 (device) +Tikiemul.port2 (device) +Tikiemul.pk (utskriftskommando) +Tikiemul.pf (utskriftsfil) +Tikiemul.st28b (on eller off) + +Dersom du ikke gir noen kommandolinjeargumenter, og ingen verdier er +satt i .Xresources, vil følgende standardverdier benyttes: +'-begrens -ikkest28b -ikkebevarforhold -40x 1 -80x 1', ingen +diskettfiler i stasjonen, og ingen printkommando/fil. + +Annet +----- + +På min TIKI-100 hjemmeside finner du mer informasjon om TIKI-100. Der +finner du også mange kjente TIKI-100 programmer som kan benyttes i +denne emulatoren. Her finner du også emulatorens hjemmeside. + +http://www.stud.ntnu.no/~djupdal/tiki/ + +Send spørsmål, forslag til forbedringer og andre kommentarer til: + +djupdal@stud.ntnu.no + +Historie +-------- + +* 25 aug 2001 Versjon 1.1.1 + - Fikset feil i diskettkontrolleremulering +* 24 aug 2001 Versjon 1.1.0 for Amiga, win32, unix. + - Generell opprenskning i alle kildefiler. + - Fikset feil i diskkontrolleremulering + - Fikset feil i videoemulering + - Laget (begrenset) serie og parallellport emulering + - Laget unix-versjon + - Laget helt ny Amiga-versjon + - Forbedret win32-versjon + - Kildefiler tilgjengelig +* 21 sep 2000 Versjon 1.0.1 for win32 +* 26 aug 2000 Versjon 1.0.0 for Amiga diff --git a/TIKI-100_emul-src/Tables.h b/TIKI-100_emul-src/Tables.h new file mode 100644 index 0000000..22fd0be --- /dev/null +++ b/TIKI-100_emul-src/Tables.h @@ -0,0 +1,447 @@ +/** Z80: portable Z80 emulator *******************************/ +/** **/ +/** Tables.h **/ +/** **/ +/** This file contains tables of used by Z80 emulation to **/ +/** compute SIGN,ZERO, PARITY flags, and decimal correction **/ +/** There are also timing tables for Z80 opcodes. This file **/ +/** is included from Z80.c. **/ +/** **/ +/** Copyright (C) Marat Fayzullin 1994,1995,1996,1997 **/ +/** You are not allowed to distribute this software **/ +/** commercially. Please, notify me, if you make any **/ +/** changes to this file. **/ +/*************************************************************/ + +static byte Cycles[256] = +{ + 4,10, 7, 6, 4, 4, 7, 4, 4,11, 7, 6, 4, 4, 7, 4, + 8,10, 7, 6, 4, 4, 7, 4,12,11, 7, 6, 4, 4, 7, 4, + 7,10,16, 6, 4, 4, 7, 4, 7,11,16, 6, 4, 4, 7, 4, + 7,10,13, 6,11,11,10, 4, 7,11,13, 6, 4, 4, 7, 4, + 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, + 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, + 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, + 7, 7, 7, 7, 7, 7, 4, 7, 4, 4, 4, 4, 4, 4, 7, 4, + 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, + 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, + 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, + 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, + 5,10,10,10,10,11, 7,11, 5,10,10, 0,10,17, 7,11, + 5,10,10,11,10,11, 7,11, 5, 4,10,11,10, 0, 7,11, + 5,10,10,19,10,11, 7,11, 5, 4,10, 4,10, 0, 7,11, + 5,10,10, 4,10,11, 7,11, 5, 6,10, 4,10, 0, 7,11 +}; + +static byte CyclesCB[256] = +{ + 8, 8, 8, 8, 8, 8,15, 8, 8, 8, 8, 8, 8, 8,15, 8, + 8, 8, 8, 8, 8, 8,15, 8, 8, 8, 8, 8, 8, 8,15, 8, + 8, 8, 8, 8, 8, 8,15, 8, 8, 8, 8, 8, 8, 8,15, 8, + 8, 8, 8, 8, 8, 8,15, 8, 8, 8, 8, 8, 8, 8,15, 8, + 8, 8, 8, 8, 8, 8,12, 8, 8, 8, 8, 8, 8, 8,12, 8, + 8, 8, 8, 8, 8, 8,12, 8, 8, 8, 8, 8, 8, 8,12, 8, + 8, 8, 8, 8, 8, 8,12, 8, 8, 8, 8, 8, 8, 8,12, 8, + 8, 8, 8, 8, 8, 8,12, 8, 8, 8, 8, 8, 8, 8,12, 8, + 8, 8, 8, 8, 8, 8,15, 8, 8, 8, 8, 8, 8, 8,15, 8, + 8, 8, 8, 8, 8, 8,15, 8, 8, 8, 8, 8, 8, 8,15, 8, + 8, 8, 8, 8, 8, 8,15, 8, 8, 8, 8, 8, 8, 8,15, 8, + 8, 8, 8, 8, 8, 8,15, 8, 8, 8, 8, 8, 8, 8,15, 8, + 8, 8, 8, 8, 8, 8,15, 8, 8, 8, 8, 8, 8, 8,15, 8, + 8, 8, 8, 8, 8, 8,15, 8, 8, 8, 8, 8, 8, 8,15, 8, + 8, 8, 8, 8, 8, 8,15, 8, 8, 8, 8, 8, 8, 8,15, 8, + 8, 8, 8, 8, 8, 8,15, 8, 8, 8, 8, 8, 8, 8,15, 8 +}; + +static byte CyclesED[256] = +{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 12,12,15,20, 8,14, 8, 9,12,12,15,20, 0,14, 0, 9, + 12,12,15,20, 0, 0, 8, 9,12,12,15,20, 0, 0, 8, 9, + 12,12,15,20, 0, 0, 0,18,12,12,15,20, 0, 0, 0,18, + 12, 0,15,20, 0, 0, 0, 0,12,12,15,20, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 16,16,16,16, 0, 0, 0, 0,16,16,16,16, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +static byte CyclesXX[256] = +{ + 0, 0, 0, 0, 0, 0, 0, 0, 0,15, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0,15, 0, 0, 0, 0, 0, 0, + 0,14,20,10, 9, 9, 9, 0, 0,15,20,10, 9, 9, 9, 0, + 0, 0, 0, 0,23,23,19, 0, 0,15, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 9, 9,19, 0, 0, 0, 0, 0, 9, 9,19, 0, + 0, 0, 0, 0, 9, 9,19, 0, 0, 0, 0, 0, 9, 9,19, 0, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 19,19,19,19,19,19,19,19, 0, 0, 0, 0, 9, 9,19, 0, + 0, 0, 0, 0, 9, 9,19, 0, 0, 0, 0, 0, 9, 9,19, 0, + 0, 0, 0, 0, 9, 9,19, 0, 0, 0, 0, 0, 9, 9,19, 0, + 0, 0, 0, 0, 9, 9,19, 0, 0, 0, 0, 0, 9, 9,19, 0, + 0, 0, 0, 0, 9, 9,19, 0, 0, 0, 0, 0, 9, 9,19, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0,14, 0,23, 0,15, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0,10, 0, 0, 0, 0, 0, 0 +}; + +static byte CyclesXXCB[256] = +{ + 0, 0, 0, 0, 0, 0,23, 0, 0, 0, 0, 0, 0, 0,23, 0, + 0, 0, 0, 0, 0, 0,23, 0, 0, 0, 0, 0, 0, 0,23, 0, + 0, 0, 0, 0, 0, 0,23, 0, 0, 0, 0, 0, 0, 0,23, 0, + 0, 0, 0, 0, 0, 0,23, 0, 0, 0, 0, 0, 0, 0,23, 0, + 20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20, + 20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20, + 20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20, + 20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20, + 0, 0, 0, 0, 0, 0,23, 0, 0, 0, 0, 0, 0, 0,23, 0, + 0, 0, 0, 0, 0, 0,23, 0, 0, 0, 0, 0, 0, 0,23, 0, + 0, 0, 0, 0, 0, 0,23, 0, 0, 0, 0, 0, 0, 0,23, 0, + 0, 0, 0, 0, 0, 0,23, 0, 0, 0, 0, 0, 0, 0,23, 0, + 0, 0, 0, 0, 0, 0,23, 0, 0, 0, 0, 0, 0, 0,23, 0, + 0, 0, 0, 0, 0, 0,23, 0, 0, 0, 0, 0, 0, 0,23, 0, + 0, 0, 0, 0, 0, 0,23, 0, 0, 0, 0, 0, 0, 0,23, 0, + 0, 0, 0, 0, 0, 0,23, 0, 0, 0, 0, 0, 0, 0,23, 0 +}; + +static byte ZSTable[256] = +{ + Z_FLAG,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG, + S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG, + S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG, + S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG, + S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG, + S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG, + S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG, + S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG, + S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG, + S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG, + S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG, + S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG, + S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG, + S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG, + S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG, + S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG +}; + +static byte PZSTable[256] = +{ + Z_FLAG|P_FLAG,0,0,P_FLAG,0,P_FLAG,P_FLAG,0, + 0,P_FLAG,P_FLAG,0,P_FLAG,0,0,P_FLAG, + 0,P_FLAG,P_FLAG,0,P_FLAG,0,0,P_FLAG,P_FLAG,0,0,P_FLAG,0,P_FLAG,P_FLAG,0, + 0,P_FLAG,P_FLAG,0,P_FLAG,0,0,P_FLAG,P_FLAG,0,0,P_FLAG,0,P_FLAG,P_FLAG,0, + P_FLAG,0,0,P_FLAG,0,P_FLAG,P_FLAG,0,0,P_FLAG,P_FLAG,0,P_FLAG,0,0,P_FLAG, + 0,P_FLAG,P_FLAG,0,P_FLAG,0,0,P_FLAG,P_FLAG,0,0,P_FLAG,0,P_FLAG,P_FLAG,0, + P_FLAG,0,0,P_FLAG,0,P_FLAG,P_FLAG,0,0,P_FLAG,P_FLAG,0,P_FLAG,0,0,P_FLAG, + P_FLAG,0,0,P_FLAG,0,P_FLAG,P_FLAG,0,0,P_FLAG,P_FLAG,0,P_FLAG,0,0,P_FLAG, + 0,P_FLAG,P_FLAG,0,P_FLAG,0,0,P_FLAG,P_FLAG,0,0,P_FLAG,0,P_FLAG,P_FLAG,0, + S_FLAG,S_FLAG|P_FLAG,S_FLAG|P_FLAG,S_FLAG, + S_FLAG|P_FLAG,S_FLAG,S_FLAG,S_FLAG|P_FLAG, + S_FLAG|P_FLAG,S_FLAG,S_FLAG,S_FLAG|P_FLAG, + S_FLAG,S_FLAG|P_FLAG,S_FLAG|P_FLAG,S_FLAG, + S_FLAG|P_FLAG,S_FLAG,S_FLAG,S_FLAG|P_FLAG, + S_FLAG,S_FLAG|P_FLAG,S_FLAG|P_FLAG,S_FLAG, + S_FLAG,S_FLAG|P_FLAG,S_FLAG|P_FLAG,S_FLAG, + S_FLAG|P_FLAG,S_FLAG,S_FLAG,S_FLAG|P_FLAG, + S_FLAG|P_FLAG,S_FLAG,S_FLAG,S_FLAG|P_FLAG, + S_FLAG,S_FLAG|P_FLAG,S_FLAG|P_FLAG,S_FLAG, + S_FLAG,S_FLAG|P_FLAG,S_FLAG|P_FLAG,S_FLAG, + S_FLAG|P_FLAG,S_FLAG,S_FLAG,S_FLAG|P_FLAG, + S_FLAG,S_FLAG|P_FLAG,S_FLAG|P_FLAG,S_FLAG, + S_FLAG|P_FLAG,S_FLAG,S_FLAG,S_FLAG|P_FLAG, + S_FLAG|P_FLAG,S_FLAG,S_FLAG,S_FLAG|P_FLAG, + S_FLAG,S_FLAG|P_FLAG,S_FLAG|P_FLAG,S_FLAG, + S_FLAG|P_FLAG,S_FLAG,S_FLAG,S_FLAG|P_FLAG, + S_FLAG,S_FLAG|P_FLAG,S_FLAG|P_FLAG,S_FLAG, + S_FLAG,S_FLAG|P_FLAG,S_FLAG|P_FLAG,S_FLAG, + S_FLAG|P_FLAG,S_FLAG,S_FLAG,S_FLAG|P_FLAG, + S_FLAG,S_FLAG|P_FLAG,S_FLAG|P_FLAG,S_FLAG, + S_FLAG|P_FLAG,S_FLAG,S_FLAG,S_FLAG|P_FLAG, + S_FLAG|P_FLAG,S_FLAG,S_FLAG,S_FLAG|P_FLAG, + S_FLAG,S_FLAG|P_FLAG,S_FLAG|P_FLAG,S_FLAG, + S_FLAG,S_FLAG|P_FLAG,S_FLAG|P_FLAG,S_FLAG, + S_FLAG|P_FLAG,S_FLAG,S_FLAG,S_FLAG|P_FLAG, + S_FLAG|P_FLAG,S_FLAG,S_FLAG,S_FLAG|P_FLAG, + S_FLAG,S_FLAG|P_FLAG,S_FLAG|P_FLAG,S_FLAG, + S_FLAG|P_FLAG,S_FLAG,S_FLAG,S_FLAG|P_FLAG, + S_FLAG,S_FLAG|P_FLAG,S_FLAG|P_FLAG,S_FLAG, + S_FLAG,S_FLAG|P_FLAG,S_FLAG|P_FLAG,S_FLAG, + S_FLAG|P_FLAG,S_FLAG,S_FLAG,S_FLAG|P_FLAG +}; + +static word DAATable[2048] = +{ + 0x0044,0x0100,0x0200,0x0304,0x0400,0x0504,0x0604,0x0700, + 0x0808,0x090C,0x1010,0x1114,0x1214,0x1310,0x1414,0x1510, + 0x1000,0x1104,0x1204,0x1300,0x1404,0x1500,0x1600,0x1704, + 0x180C,0x1908,0x2030,0x2134,0x2234,0x2330,0x2434,0x2530, + 0x2020,0x2124,0x2224,0x2320,0x2424,0x2520,0x2620,0x2724, + 0x282C,0x2928,0x3034,0x3130,0x3230,0x3334,0x3430,0x3534, + 0x3024,0x3120,0x3220,0x3324,0x3420,0x3524,0x3624,0x3720, + 0x3828,0x392C,0x4010,0x4114,0x4214,0x4310,0x4414,0x4510, + 0x4000,0x4104,0x4204,0x4300,0x4404,0x4500,0x4600,0x4704, + 0x480C,0x4908,0x5014,0x5110,0x5210,0x5314,0x5410,0x5514, + 0x5004,0x5100,0x5200,0x5304,0x5400,0x5504,0x5604,0x5700, + 0x5808,0x590C,0x6034,0x6130,0x6230,0x6334,0x6430,0x6534, + 0x6024,0x6120,0x6220,0x6324,0x6420,0x6524,0x6624,0x6720, + 0x6828,0x692C,0x7030,0x7134,0x7234,0x7330,0x7434,0x7530, + 0x7020,0x7124,0x7224,0x7320,0x7424,0x7520,0x7620,0x7724, + 0x782C,0x7928,0x8090,0x8194,0x8294,0x8390,0x8494,0x8590, + 0x8080,0x8184,0x8284,0x8380,0x8484,0x8580,0x8680,0x8784, + 0x888C,0x8988,0x9094,0x9190,0x9290,0x9394,0x9490,0x9594, + 0x9084,0x9180,0x9280,0x9384,0x9480,0x9584,0x9684,0x9780, + 0x9888,0x998C,0x0055,0x0111,0x0211,0x0315,0x0411,0x0515, + 0x0045,0x0101,0x0201,0x0305,0x0401,0x0505,0x0605,0x0701, + 0x0809,0x090D,0x1011,0x1115,0x1215,0x1311,0x1415,0x1511, + 0x1001,0x1105,0x1205,0x1301,0x1405,0x1501,0x1601,0x1705, + 0x180D,0x1909,0x2031,0x2135,0x2235,0x2331,0x2435,0x2531, + 0x2021,0x2125,0x2225,0x2321,0x2425,0x2521,0x2621,0x2725, + 0x282D,0x2929,0x3035,0x3131,0x3231,0x3335,0x3431,0x3535, + 0x3025,0x3121,0x3221,0x3325,0x3421,0x3525,0x3625,0x3721, + 0x3829,0x392D,0x4011,0x4115,0x4215,0x4311,0x4415,0x4511, + 0x4001,0x4105,0x4205,0x4301,0x4405,0x4501,0x4601,0x4705, + 0x480D,0x4909,0x5015,0x5111,0x5211,0x5315,0x5411,0x5515, + 0x5005,0x5101,0x5201,0x5305,0x5401,0x5505,0x5605,0x5701, + 0x5809,0x590D,0x6035,0x6131,0x6231,0x6335,0x6431,0x6535, + 0x6025,0x6121,0x6221,0x6325,0x6421,0x6525,0x6625,0x6721, + 0x6829,0x692D,0x7031,0x7135,0x7235,0x7331,0x7435,0x7531, + 0x7021,0x7125,0x7225,0x7321,0x7425,0x7521,0x7621,0x7725, + 0x782D,0x7929,0x8091,0x8195,0x8295,0x8391,0x8495,0x8591, + 0x8081,0x8185,0x8285,0x8381,0x8485,0x8581,0x8681,0x8785, + 0x888D,0x8989,0x9095,0x9191,0x9291,0x9395,0x9491,0x9595, + 0x9085,0x9181,0x9281,0x9385,0x9481,0x9585,0x9685,0x9781, + 0x9889,0x998D,0xA0B5,0xA1B1,0xA2B1,0xA3B5,0xA4B1,0xA5B5, + 0xA0A5,0xA1A1,0xA2A1,0xA3A5,0xA4A1,0xA5A5,0xA6A5,0xA7A1, + 0xA8A9,0xA9AD,0xB0B1,0xB1B5,0xB2B5,0xB3B1,0xB4B5,0xB5B1, + 0xB0A1,0xB1A5,0xB2A5,0xB3A1,0xB4A5,0xB5A1,0xB6A1,0xB7A5, + 0xB8AD,0xB9A9,0xC095,0xC191,0xC291,0xC395,0xC491,0xC595, + 0xC085,0xC181,0xC281,0xC385,0xC481,0xC585,0xC685,0xC781, + 0xC889,0xC98D,0xD091,0xD195,0xD295,0xD391,0xD495,0xD591, + 0xD081,0xD185,0xD285,0xD381,0xD485,0xD581,0xD681,0xD785, + 0xD88D,0xD989,0xE0B1,0xE1B5,0xE2B5,0xE3B1,0xE4B5,0xE5B1, + 0xE0A1,0xE1A5,0xE2A5,0xE3A1,0xE4A5,0xE5A1,0xE6A1,0xE7A5, + 0xE8AD,0xE9A9,0xF0B5,0xF1B1,0xF2B1,0xF3B5,0xF4B1,0xF5B5, + 0xF0A5,0xF1A1,0xF2A1,0xF3A5,0xF4A1,0xF5A5,0xF6A5,0xF7A1, + 0xF8A9,0xF9AD,0x0055,0x0111,0x0211,0x0315,0x0411,0x0515, + 0x0045,0x0101,0x0201,0x0305,0x0401,0x0505,0x0605,0x0701, + 0x0809,0x090D,0x1011,0x1115,0x1215,0x1311,0x1415,0x1511, + 0x1001,0x1105,0x1205,0x1301,0x1405,0x1501,0x1601,0x1705, + 0x180D,0x1909,0x2031,0x2135,0x2235,0x2331,0x2435,0x2531, + 0x2021,0x2125,0x2225,0x2321,0x2425,0x2521,0x2621,0x2725, + 0x282D,0x2929,0x3035,0x3131,0x3231,0x3335,0x3431,0x3535, + 0x3025,0x3121,0x3221,0x3325,0x3421,0x3525,0x3625,0x3721, + 0x3829,0x392D,0x4011,0x4115,0x4215,0x4311,0x4415,0x4511, + 0x4001,0x4105,0x4205,0x4301,0x4405,0x4501,0x4601,0x4705, + 0x480D,0x4909,0x5015,0x5111,0x5211,0x5315,0x5411,0x5515, + 0x5005,0x5101,0x5201,0x5305,0x5401,0x5505,0x5605,0x5701, + 0x5809,0x590D,0x6035,0x6131,0x6231,0x6335,0x6431,0x6535, + 0x0604,0x0700,0x0808,0x090C,0x0A0C,0x0B08,0x0C0C,0x0D08, + 0x0E08,0x0F0C,0x1010,0x1114,0x1214,0x1310,0x1414,0x1510, + 0x1600,0x1704,0x180C,0x1908,0x1A08,0x1B0C,0x1C08,0x1D0C, + 0x1E0C,0x1F08,0x2030,0x2134,0x2234,0x2330,0x2434,0x2530, + 0x2620,0x2724,0x282C,0x2928,0x2A28,0x2B2C,0x2C28,0x2D2C, + 0x2E2C,0x2F28,0x3034,0x3130,0x3230,0x3334,0x3430,0x3534, + 0x3624,0x3720,0x3828,0x392C,0x3A2C,0x3B28,0x3C2C,0x3D28, + 0x3E28,0x3F2C,0x4010,0x4114,0x4214,0x4310,0x4414,0x4510, + 0x4600,0x4704,0x480C,0x4908,0x4A08,0x4B0C,0x4C08,0x4D0C, + 0x4E0C,0x4F08,0x5014,0x5110,0x5210,0x5314,0x5410,0x5514, + 0x5604,0x5700,0x5808,0x590C,0x5A0C,0x5B08,0x5C0C,0x5D08, + 0x5E08,0x5F0C,0x6034,0x6130,0x6230,0x6334,0x6430,0x6534, + 0x6624,0x6720,0x6828,0x692C,0x6A2C,0x6B28,0x6C2C,0x6D28, + 0x6E28,0x6F2C,0x7030,0x7134,0x7234,0x7330,0x7434,0x7530, + 0x7620,0x7724,0x782C,0x7928,0x7A28,0x7B2C,0x7C28,0x7D2C, + 0x7E2C,0x7F28,0x8090,0x8194,0x8294,0x8390,0x8494,0x8590, + 0x8680,0x8784,0x888C,0x8988,0x8A88,0x8B8C,0x8C88,0x8D8C, + 0x8E8C,0x8F88,0x9094,0x9190,0x9290,0x9394,0x9490,0x9594, + 0x9684,0x9780,0x9888,0x998C,0x9A8C,0x9B88,0x9C8C,0x9D88, + 0x9E88,0x9F8C,0x0055,0x0111,0x0211,0x0315,0x0411,0x0515, + 0x0605,0x0701,0x0809,0x090D,0x0A0D,0x0B09,0x0C0D,0x0D09, + 0x0E09,0x0F0D,0x1011,0x1115,0x1215,0x1311,0x1415,0x1511, + 0x1601,0x1705,0x180D,0x1909,0x1A09,0x1B0D,0x1C09,0x1D0D, + 0x1E0D,0x1F09,0x2031,0x2135,0x2235,0x2331,0x2435,0x2531, + 0x2621,0x2725,0x282D,0x2929,0x2A29,0x2B2D,0x2C29,0x2D2D, + 0x2E2D,0x2F29,0x3035,0x3131,0x3231,0x3335,0x3431,0x3535, + 0x3625,0x3721,0x3829,0x392D,0x3A2D,0x3B29,0x3C2D,0x3D29, + 0x3E29,0x3F2D,0x4011,0x4115,0x4215,0x4311,0x4415,0x4511, + 0x4601,0x4705,0x480D,0x4909,0x4A09,0x4B0D,0x4C09,0x4D0D, + 0x4E0D,0x4F09,0x5015,0x5111,0x5211,0x5315,0x5411,0x5515, + 0x5605,0x5701,0x5809,0x590D,0x5A0D,0x5B09,0x5C0D,0x5D09, + 0x5E09,0x5F0D,0x6035,0x6131,0x6231,0x6335,0x6431,0x6535, + 0x6625,0x6721,0x6829,0x692D,0x6A2D,0x6B29,0x6C2D,0x6D29, + 0x6E29,0x6F2D,0x7031,0x7135,0x7235,0x7331,0x7435,0x7531, + 0x7621,0x7725,0x782D,0x7929,0x7A29,0x7B2D,0x7C29,0x7D2D, + 0x7E2D,0x7F29,0x8091,0x8195,0x8295,0x8391,0x8495,0x8591, + 0x8681,0x8785,0x888D,0x8989,0x8A89,0x8B8D,0x8C89,0x8D8D, + 0x8E8D,0x8F89,0x9095,0x9191,0x9291,0x9395,0x9491,0x9595, + 0x9685,0x9781,0x9889,0x998D,0x9A8D,0x9B89,0x9C8D,0x9D89, + 0x9E89,0x9F8D,0xA0B5,0xA1B1,0xA2B1,0xA3B5,0xA4B1,0xA5B5, + 0xA6A5,0xA7A1,0xA8A9,0xA9AD,0xAAAD,0xABA9,0xACAD,0xADA9, + 0xAEA9,0xAFAD,0xB0B1,0xB1B5,0xB2B5,0xB3B1,0xB4B5,0xB5B1, + 0xB6A1,0xB7A5,0xB8AD,0xB9A9,0xBAA9,0xBBAD,0xBCA9,0xBDAD, + 0xBEAD,0xBFA9,0xC095,0xC191,0xC291,0xC395,0xC491,0xC595, + 0xC685,0xC781,0xC889,0xC98D,0xCA8D,0xCB89,0xCC8D,0xCD89, + 0xCE89,0xCF8D,0xD091,0xD195,0xD295,0xD391,0xD495,0xD591, + 0xD681,0xD785,0xD88D,0xD989,0xDA89,0xDB8D,0xDC89,0xDD8D, + 0xDE8D,0xDF89,0xE0B1,0xE1B5,0xE2B5,0xE3B1,0xE4B5,0xE5B1, + 0xE6A1,0xE7A5,0xE8AD,0xE9A9,0xEAA9,0xEBAD,0xECA9,0xEDAD, + 0xEEAD,0xEFA9,0xF0B5,0xF1B1,0xF2B1,0xF3B5,0xF4B1,0xF5B5, + 0xF6A5,0xF7A1,0xF8A9,0xF9AD,0xFAAD,0xFBA9,0xFCAD,0xFDA9, + 0xFEA9,0xFFAD,0x0055,0x0111,0x0211,0x0315,0x0411,0x0515, + 0x0605,0x0701,0x0809,0x090D,0x0A0D,0x0B09,0x0C0D,0x0D09, + 0x0E09,0x0F0D,0x1011,0x1115,0x1215,0x1311,0x1415,0x1511, + 0x1601,0x1705,0x180D,0x1909,0x1A09,0x1B0D,0x1C09,0x1D0D, + 0x1E0D,0x1F09,0x2031,0x2135,0x2235,0x2331,0x2435,0x2531, + 0x2621,0x2725,0x282D,0x2929,0x2A29,0x2B2D,0x2C29,0x2D2D, + 0x2E2D,0x2F29,0x3035,0x3131,0x3231,0x3335,0x3431,0x3535, + 0x3625,0x3721,0x3829,0x392D,0x3A2D,0x3B29,0x3C2D,0x3D29, + 0x3E29,0x3F2D,0x4011,0x4115,0x4215,0x4311,0x4415,0x4511, + 0x4601,0x4705,0x480D,0x4909,0x4A09,0x4B0D,0x4C09,0x4D0D, + 0x4E0D,0x4F09,0x5015,0x5111,0x5211,0x5315,0x5411,0x5515, + 0x5605,0x5701,0x5809,0x590D,0x5A0D,0x5B09,0x5C0D,0x5D09, + 0x5E09,0x5F0D,0x6035,0x6131,0x6231,0x6335,0x6431,0x6535, + 0x0046,0x0102,0x0202,0x0306,0x0402,0x0506,0x0606,0x0702, + 0x080A,0x090E,0x0402,0x0506,0x0606,0x0702,0x080A,0x090E, + 0x1002,0x1106,0x1206,0x1302,0x1406,0x1502,0x1602,0x1706, + 0x180E,0x190A,0x1406,0x1502,0x1602,0x1706,0x180E,0x190A, + 0x2022,0x2126,0x2226,0x2322,0x2426,0x2522,0x2622,0x2726, + 0x282E,0x292A,0x2426,0x2522,0x2622,0x2726,0x282E,0x292A, + 0x3026,0x3122,0x3222,0x3326,0x3422,0x3526,0x3626,0x3722, + 0x382A,0x392E,0x3422,0x3526,0x3626,0x3722,0x382A,0x392E, + 0x4002,0x4106,0x4206,0x4302,0x4406,0x4502,0x4602,0x4706, + 0x480E,0x490A,0x4406,0x4502,0x4602,0x4706,0x480E,0x490A, + 0x5006,0x5102,0x5202,0x5306,0x5402,0x5506,0x5606,0x5702, + 0x580A,0x590E,0x5402,0x5506,0x5606,0x5702,0x580A,0x590E, + 0x6026,0x6122,0x6222,0x6326,0x6422,0x6526,0x6626,0x6722, + 0x682A,0x692E,0x6422,0x6526,0x6626,0x6722,0x682A,0x692E, + 0x7022,0x7126,0x7226,0x7322,0x7426,0x7522,0x7622,0x7726, + 0x782E,0x792A,0x7426,0x7522,0x7622,0x7726,0x782E,0x792A, + 0x8082,0x8186,0x8286,0x8382,0x8486,0x8582,0x8682,0x8786, + 0x888E,0x898A,0x8486,0x8582,0x8682,0x8786,0x888E,0x898A, + 0x9086,0x9182,0x9282,0x9386,0x9482,0x9586,0x9686,0x9782, + 0x988A,0x998E,0x3423,0x3527,0x3627,0x3723,0x382B,0x392F, + 0x4003,0x4107,0x4207,0x4303,0x4407,0x4503,0x4603,0x4707, + 0x480F,0x490B,0x4407,0x4503,0x4603,0x4707,0x480F,0x490B, + 0x5007,0x5103,0x5203,0x5307,0x5403,0x5507,0x5607,0x5703, + 0x580B,0x590F,0x5403,0x5507,0x5607,0x5703,0x580B,0x590F, + 0x6027,0x6123,0x6223,0x6327,0x6423,0x6527,0x6627,0x6723, + 0x682B,0x692F,0x6423,0x6527,0x6627,0x6723,0x682B,0x692F, + 0x7023,0x7127,0x7227,0x7323,0x7427,0x7523,0x7623,0x7727, + 0x782F,0x792B,0x7427,0x7523,0x7623,0x7727,0x782F,0x792B, + 0x8083,0x8187,0x8287,0x8383,0x8487,0x8583,0x8683,0x8787, + 0x888F,0x898B,0x8487,0x8583,0x8683,0x8787,0x888F,0x898B, + 0x9087,0x9183,0x9283,0x9387,0x9483,0x9587,0x9687,0x9783, + 0x988B,0x998F,0x9483,0x9587,0x9687,0x9783,0x988B,0x998F, + 0xA0A7,0xA1A3,0xA2A3,0xA3A7,0xA4A3,0xA5A7,0xA6A7,0xA7A3, + 0xA8AB,0xA9AF,0xA4A3,0xA5A7,0xA6A7,0xA7A3,0xA8AB,0xA9AF, + 0xB0A3,0xB1A7,0xB2A7,0xB3A3,0xB4A7,0xB5A3,0xB6A3,0xB7A7, + 0xB8AF,0xB9AB,0xB4A7,0xB5A3,0xB6A3,0xB7A7,0xB8AF,0xB9AB, + 0xC087,0xC183,0xC283,0xC387,0xC483,0xC587,0xC687,0xC783, + 0xC88B,0xC98F,0xC483,0xC587,0xC687,0xC783,0xC88B,0xC98F, + 0xD083,0xD187,0xD287,0xD383,0xD487,0xD583,0xD683,0xD787, + 0xD88F,0xD98B,0xD487,0xD583,0xD683,0xD787,0xD88F,0xD98B, + 0xE0A3,0xE1A7,0xE2A7,0xE3A3,0xE4A7,0xE5A3,0xE6A3,0xE7A7, + 0xE8AF,0xE9AB,0xE4A7,0xE5A3,0xE6A3,0xE7A7,0xE8AF,0xE9AB, + 0xF0A7,0xF1A3,0xF2A3,0xF3A7,0xF4A3,0xF5A7,0xF6A7,0xF7A3, + 0xF8AB,0xF9AF,0xF4A3,0xF5A7,0xF6A7,0xF7A3,0xF8AB,0xF9AF, + 0x0047,0x0103,0x0203,0x0307,0x0403,0x0507,0x0607,0x0703, + 0x080B,0x090F,0x0403,0x0507,0x0607,0x0703,0x080B,0x090F, + 0x1003,0x1107,0x1207,0x1303,0x1407,0x1503,0x1603,0x1707, + 0x180F,0x190B,0x1407,0x1503,0x1603,0x1707,0x180F,0x190B, + 0x2023,0x2127,0x2227,0x2323,0x2427,0x2523,0x2623,0x2727, + 0x282F,0x292B,0x2427,0x2523,0x2623,0x2727,0x282F,0x292B, + 0x3027,0x3123,0x3223,0x3327,0x3423,0x3527,0x3627,0x3723, + 0x382B,0x392F,0x3423,0x3527,0x3627,0x3723,0x382B,0x392F, + 0x4003,0x4107,0x4207,0x4303,0x4407,0x4503,0x4603,0x4707, + 0x480F,0x490B,0x4407,0x4503,0x4603,0x4707,0x480F,0x490B, + 0x5007,0x5103,0x5203,0x5307,0x5403,0x5507,0x5607,0x5703, + 0x580B,0x590F,0x5403,0x5507,0x5607,0x5703,0x580B,0x590F, + 0x6027,0x6123,0x6223,0x6327,0x6423,0x6527,0x6627,0x6723, + 0x682B,0x692F,0x6423,0x6527,0x6627,0x6723,0x682B,0x692F, + 0x7023,0x7127,0x7227,0x7323,0x7427,0x7523,0x7623,0x7727, + 0x782F,0x792B,0x7427,0x7523,0x7623,0x7727,0x782F,0x792B, + 0x8083,0x8187,0x8287,0x8383,0x8487,0x8583,0x8683,0x8787, + 0x888F,0x898B,0x8487,0x8583,0x8683,0x8787,0x888F,0x898B, + 0x9087,0x9183,0x9283,0x9387,0x9483,0x9587,0x9687,0x9783, + 0x988B,0x998F,0x9483,0x9587,0x9687,0x9783,0x988B,0x998F, + 0xFABE,0xFBBA,0xFCBE,0xFDBA,0xFEBA,0xFFBE,0x0046,0x0102, + 0x0202,0x0306,0x0402,0x0506,0x0606,0x0702,0x080A,0x090E, + 0x0A1E,0x0B1A,0x0C1E,0x0D1A,0x0E1A,0x0F1E,0x1002,0x1106, + 0x1206,0x1302,0x1406,0x1502,0x1602,0x1706,0x180E,0x190A, + 0x1A1A,0x1B1E,0x1C1A,0x1D1E,0x1E1E,0x1F1A,0x2022,0x2126, + 0x2226,0x2322,0x2426,0x2522,0x2622,0x2726,0x282E,0x292A, + 0x2A3A,0x2B3E,0x2C3A,0x2D3E,0x2E3E,0x2F3A,0x3026,0x3122, + 0x3222,0x3326,0x3422,0x3526,0x3626,0x3722,0x382A,0x392E, + 0x3A3E,0x3B3A,0x3C3E,0x3D3A,0x3E3A,0x3F3E,0x4002,0x4106, + 0x4206,0x4302,0x4406,0x4502,0x4602,0x4706,0x480E,0x490A, + 0x4A1A,0x4B1E,0x4C1A,0x4D1E,0x4E1E,0x4F1A,0x5006,0x5102, + 0x5202,0x5306,0x5402,0x5506,0x5606,0x5702,0x580A,0x590E, + 0x5A1E,0x5B1A,0x5C1E,0x5D1A,0x5E1A,0x5F1E,0x6026,0x6122, + 0x6222,0x6326,0x6422,0x6526,0x6626,0x6722,0x682A,0x692E, + 0x6A3E,0x6B3A,0x6C3E,0x6D3A,0x6E3A,0x6F3E,0x7022,0x7126, + 0x7226,0x7322,0x7426,0x7522,0x7622,0x7726,0x782E,0x792A, + 0x7A3A,0x7B3E,0x7C3A,0x7D3E,0x7E3E,0x7F3A,0x8082,0x8186, + 0x8286,0x8382,0x8486,0x8582,0x8682,0x8786,0x888E,0x898A, + 0x8A9A,0x8B9E,0x8C9A,0x8D9E,0x8E9E,0x8F9A,0x9086,0x9182, + 0x9282,0x9386,0x3423,0x3527,0x3627,0x3723,0x382B,0x392F, + 0x3A3F,0x3B3B,0x3C3F,0x3D3B,0x3E3B,0x3F3F,0x4003,0x4107, + 0x4207,0x4303,0x4407,0x4503,0x4603,0x4707,0x480F,0x490B, + 0x4A1B,0x4B1F,0x4C1B,0x4D1F,0x4E1F,0x4F1B,0x5007,0x5103, + 0x5203,0x5307,0x5403,0x5507,0x5607,0x5703,0x580B,0x590F, + 0x5A1F,0x5B1B,0x5C1F,0x5D1B,0x5E1B,0x5F1F,0x6027,0x6123, + 0x6223,0x6327,0x6423,0x6527,0x6627,0x6723,0x682B,0x692F, + 0x6A3F,0x6B3B,0x6C3F,0x6D3B,0x6E3B,0x6F3F,0x7023,0x7127, + 0x7227,0x7323,0x7427,0x7523,0x7623,0x7727,0x782F,0x792B, + 0x7A3B,0x7B3F,0x7C3B,0x7D3F,0x7E3F,0x7F3B,0x8083,0x8187, + 0x8287,0x8383,0x8487,0x8583,0x8683,0x8787,0x888F,0x898B, + 0x8A9B,0x8B9F,0x8C9B,0x8D9F,0x8E9F,0x8F9B,0x9087,0x9183, + 0x9283,0x9387,0x9483,0x9587,0x9687,0x9783,0x988B,0x998F, + 0x9A9F,0x9B9B,0x9C9F,0x9D9B,0x9E9B,0x9F9F,0xA0A7,0xA1A3, + 0xA2A3,0xA3A7,0xA4A3,0xA5A7,0xA6A7,0xA7A3,0xA8AB,0xA9AF, + 0xAABF,0xABBB,0xACBF,0xADBB,0xAEBB,0xAFBF,0xB0A3,0xB1A7, + 0xB2A7,0xB3A3,0xB4A7,0xB5A3,0xB6A3,0xB7A7,0xB8AF,0xB9AB, + 0xBABB,0xBBBF,0xBCBB,0xBDBF,0xBEBF,0xBFBB,0xC087,0xC183, + 0xC283,0xC387,0xC483,0xC587,0xC687,0xC783,0xC88B,0xC98F, + 0xCA9F,0xCB9B,0xCC9F,0xCD9B,0xCE9B,0xCF9F,0xD083,0xD187, + 0xD287,0xD383,0xD487,0xD583,0xD683,0xD787,0xD88F,0xD98B, + 0xDA9B,0xDB9F,0xDC9B,0xDD9F,0xDE9F,0xDF9B,0xE0A3,0xE1A7, + 0xE2A7,0xE3A3,0xE4A7,0xE5A3,0xE6A3,0xE7A7,0xE8AF,0xE9AB, + 0xEABB,0xEBBF,0xECBB,0xEDBF,0xEEBF,0xEFBB,0xF0A7,0xF1A3, + 0xF2A3,0xF3A7,0xF4A3,0xF5A7,0xF6A7,0xF7A3,0xF8AB,0xF9AF, + 0xFABF,0xFBBB,0xFCBF,0xFDBB,0xFEBB,0xFFBF,0x0047,0x0103, + 0x0203,0x0307,0x0403,0x0507,0x0607,0x0703,0x080B,0x090F, + 0x0A1F,0x0B1B,0x0C1F,0x0D1B,0x0E1B,0x0F1F,0x1003,0x1107, + 0x1207,0x1303,0x1407,0x1503,0x1603,0x1707,0x180F,0x190B, + 0x1A1B,0x1B1F,0x1C1B,0x1D1F,0x1E1F,0x1F1B,0x2023,0x2127, + 0x2227,0x2323,0x2427,0x2523,0x2623,0x2727,0x282F,0x292B, + 0x2A3B,0x2B3F,0x2C3B,0x2D3F,0x2E3F,0x2F3B,0x3027,0x3123, + 0x3223,0x3327,0x3423,0x3527,0x3627,0x3723,0x382B,0x392F, + 0x3A3F,0x3B3B,0x3C3F,0x3D3B,0x3E3B,0x3F3F,0x4003,0x4107, + 0x4207,0x4303,0x4407,0x4503,0x4603,0x4707,0x480F,0x490B, + 0x4A1B,0x4B1F,0x4C1B,0x4D1F,0x4E1F,0x4F1B,0x5007,0x5103, + 0x5203,0x5307,0x5403,0x5507,0x5607,0x5703,0x580B,0x590F, + 0x5A1F,0x5B1B,0x5C1F,0x5D1B,0x5E1B,0x5F1F,0x6027,0x6123, + 0x6223,0x6327,0x6423,0x6527,0x6627,0x6723,0x682B,0x692F, + 0x6A3F,0x6B3B,0x6C3F,0x6D3B,0x6E3B,0x6F3F,0x7023,0x7127, + 0x7227,0x7323,0x7427,0x7523,0x7623,0x7727,0x782F,0x792B, + 0x7A3B,0x7B3F,0x7C3B,0x7D3F,0x7E3F,0x7F3B,0x8083,0x8187, + 0x8287,0x8383,0x8487,0x8583,0x8683,0x8787,0x888F,0x898B, + 0x8A9B,0x8B9F,0x8C9B,0x8D9F,0x8E9F,0x8F9B,0x9087,0x9183, + 0x9283,0x9387,0x9483,0x9587,0x9687,0x9783,0x988B,0x998F +}; diff --git a/TIKI-100_emul-src/Z80.c b/TIKI-100_emul-src/Z80.c new file mode 100644 index 0000000..1dfa6fb --- /dev/null +++ b/TIKI-100_emul-src/Z80.c @@ -0,0 +1,573 @@ +/** Z80: portable Z80 emulator *******************************/ +/** **/ +/** Z80.c **/ +/** **/ +/** This file contains implementation for Z80 CPU. Don't **/ +/** forget to provide RdZ80(), WrZ80(), InZ80(), OutZ80(), **/ +/** LoopZ80(), and PatchZ80() functions to accomodate the **/ +/** emulated machine's architecture. **/ +/** **/ +/** Copyright (C) Marat Fayzullin 1994,1995,1996,1997 **/ +/** You are not allowed to distribute this software **/ +/** commercially. Please, notify me, if you make any **/ +/** changes to this file. **/ +/*************************************************************/ + +#include "Z80.h" +#include "Tables.h" +#include + +/** INLINE ***************************************************/ +/** Different compilers inline C functions differently. **/ +/*************************************************************/ +#ifdef __GNUC__ +#define INLINE inline +#else +#define INLINE static +#endif + +/** System-Dependent Stuff ***********************************/ +/** This is system-dependent code put here to speed things **/ +/** up. It has to stay inlined to be fast. **/ +/*************************************************************/ +#ifdef COLEM +extern byte *RAM; +INLINE byte RdZ80(word A) { return(RAM[A]); } +#endif +#ifdef MG +extern byte *Page[]; +INLINE byte RdZ80(word A) { return(Page[A>>13][A&0x1FFF]); } +#endif +#ifdef FMSX +extern byte *RAM[],PSL[],SSLReg; +INLINE byte RdZ80(word A) +{ + if(A!=0xFFFF) return(RAM[A>>13][A&0x1FFF]); + else return((PSL[3]==3)? ~SSLReg:RAM[7][0x1FFF]); +} +#endif + +#define S(Fl) R->AF.B.l|=Fl +#define R(Fl) R->AF.B.l&=~(Fl) +#define FLAGS(Rg,Fl) R->AF.B.l=Fl|ZSTable[Rg] + +#define M_RLC(Rg) \ + R->AF.B.l=Rg>>7;Rg=(Rg<<1)|R->AF.B.l;R->AF.B.l|=PZSTable[Rg] +#define M_RRC(Rg) \ + R->AF.B.l=Rg&0x01;Rg=(Rg>>1)|(R->AF.B.l<<7);R->AF.B.l|=PZSTable[Rg] +#define M_RL(Rg) \ + if(Rg&0x80) \ + { \ + Rg=(Rg<<1)|(R->AF.B.l&C_FLAG); \ + R->AF.B.l=PZSTable[Rg]|C_FLAG; \ + } \ + else \ + { \ + Rg=(Rg<<1)|(R->AF.B.l&C_FLAG); \ + R->AF.B.l=PZSTable[Rg]; \ + } +#define M_RR(Rg) \ + if(Rg&0x01) \ + { \ + Rg=(Rg>>1)|(R->AF.B.l<<7); \ + R->AF.B.l=PZSTable[Rg]|C_FLAG; \ + } \ + else \ + { \ + Rg=(Rg>>1)|(R->AF.B.l<<7); \ + R->AF.B.l=PZSTable[Rg]; \ + } + +#define M_SLA(Rg) \ + R->AF.B.l=Rg>>7;Rg<<=1;R->AF.B.l|=PZSTable[Rg] +#define M_SRA(Rg) \ + R->AF.B.l=Rg&C_FLAG;Rg=(Rg>>1)|(Rg&0x80);R->AF.B.l|=PZSTable[Rg] + +#define M_SLL(Rg) \ + R->AF.B.l=Rg>>7;Rg=(Rg<<1)|0x01;R->AF.B.l|=PZSTable[Rg] +#define M_SRL(Rg) \ + R->AF.B.l=Rg&0x01;Rg>>=1;R->AF.B.l|=PZSTable[Rg] + +#define M_BIT(Bit,Rg) \ + R->AF.B.l=(R->AF.B.l&~(N_FLAG|Z_FLAG))|H_FLAG|(Rg&(1<Rg.B.l=RdZ80(R->SP.W++);R->Rg.B.h=RdZ80(R->SP.W++) +#define M_PUSH(Rg) \ + WrZ80(--R->SP.W,R->Rg.B.h);WrZ80(--R->SP.W,R->Rg.B.l) + +#define M_CALL \ + J.B.l=RdZ80(R->PC.W++);J.B.h=RdZ80(R->PC.W++); \ + WrZ80(--R->SP.W,R->PC.B.h);WrZ80(--R->SP.W,R->PC.B.l); \ + R->PC.W=J.W + +#define M_JP J.B.l=RdZ80(R->PC.W++);J.B.h=RdZ80(R->PC.W);R->PC.W=J.W +#define M_JR R->PC.W+=(offset)RdZ80(R->PC.W)+1 +#define M_RET R->PC.B.l=RdZ80(R->SP.W++);R->PC.B.h=RdZ80(R->SP.W++) + +#define M_RST(Ad) \ + WrZ80(--R->SP.W,R->PC.B.h);WrZ80(--R->SP.W,R->PC.B.l);R->PC.W=Ad + +#define M_LDWORD(Rg) \ + R->Rg.B.l=RdZ80(R->PC.W++);R->Rg.B.h=RdZ80(R->PC.W++) + +#define M_ADD(Rg) \ + J.W=R->AF.B.h+Rg; \ + R->AF.B.l= \ + (~(R->AF.B.h^Rg)&(Rg^J.B.l)&0x80? V_FLAG:0)| \ + J.B.h|ZSTable[J.B.l]| \ + ((R->AF.B.h^Rg^J.B.l)&H_FLAG); \ + R->AF.B.h=J.B.l + +#define M_SUB(Rg) \ + J.W=R->AF.B.h-Rg; \ + R->AF.B.l= \ + ((R->AF.B.h^Rg)&(R->AF.B.h^J.B.l)&0x80? V_FLAG:0)| \ + N_FLAG|-J.B.h|ZSTable[J.B.l]| \ + ((R->AF.B.h^Rg^J.B.l)&H_FLAG); \ + R->AF.B.h=J.B.l + +#define M_ADC(Rg) \ + J.W=R->AF.B.h+Rg+(R->AF.B.l&C_FLAG); \ + R->AF.B.l= \ + (~(R->AF.B.h^Rg)&(Rg^J.B.l)&0x80? V_FLAG:0)| \ + J.B.h|ZSTable[J.B.l]| \ + ((R->AF.B.h^Rg^J.B.l)&H_FLAG); \ + R->AF.B.h=J.B.l + +#define M_SBC(Rg) \ + J.W=R->AF.B.h-Rg-(R->AF.B.l&C_FLAG); \ + R->AF.B.l= \ + ((R->AF.B.h^Rg)&(R->AF.B.h^J.B.l)&0x80? V_FLAG:0)| \ + N_FLAG|-J.B.h|ZSTable[J.B.l]| \ + ((R->AF.B.h^Rg^J.B.l)&H_FLAG); \ + R->AF.B.h=J.B.l + +#define M_CP(Rg) \ + J.W=R->AF.B.h-Rg; \ + R->AF.B.l= \ + ((R->AF.B.h^Rg)&(R->AF.B.h^J.B.l)&0x80? V_FLAG:0)| \ + N_FLAG|-J.B.h|ZSTable[J.B.l]| \ + ((R->AF.B.h^Rg^J.B.l)&H_FLAG) + +#define M_AND(Rg) R->AF.B.h&=Rg;R->AF.B.l=H_FLAG|PZSTable[R->AF.B.h] +#define M_OR(Rg) R->AF.B.h|=Rg;R->AF.B.l=PZSTable[R->AF.B.h] +#define M_XOR(Rg) R->AF.B.h^=Rg;R->AF.B.l=PZSTable[R->AF.B.h] +#define M_IN(Rg) Rg=InZ80(R->BC.B.l);R->AF.B.l=PZSTable[Rg]|(R->AF.B.l&C_FLAG) + +#define M_INC(Rg) \ + Rg++; \ + R->AF.B.l= \ + (R->AF.B.l&C_FLAG)|ZSTable[Rg]| \ + (Rg==0x80? V_FLAG:0)|(Rg&0x0F? 0:H_FLAG) + +#define M_DEC(Rg) \ + Rg--; \ + R->AF.B.l= \ + N_FLAG|(R->AF.B.l&C_FLAG)|ZSTable[Rg]| \ + (Rg==0x7F? V_FLAG:0)|((Rg&0x0F)==0x0F? H_FLAG:0) + +#define M_ADDW(Rg1,Rg2) \ + J.W=(R->Rg1.W+R->Rg2.W)&0xFFFF; \ + R->AF.B.l= \ + (R->AF.B.l&~(H_FLAG|N_FLAG|C_FLAG))| \ + ((R->Rg1.W^R->Rg2.W^J.W)&0x1000? H_FLAG:0)| \ + (((long)R->Rg1.W+(long)R->Rg2.W)&0x10000? C_FLAG:0); \ + R->Rg1.W=J.W + +#define M_ADCW(Rg) \ + I=R->AF.B.l&C_FLAG;J.W=(R->HL.W+R->Rg.W+I)&0xFFFF; \ + R->AF.B.l= \ + (((long)R->HL.W+(long)R->Rg.W+(long)I)&0x10000? C_FLAG:0)| \ + (~(R->HL.W^R->Rg.W)&(R->Rg.W^J.W)&0x8000? V_FLAG:0)| \ + ((R->HL.W^R->Rg.W^J.W)&0x1000? H_FLAG:0)| \ + (J.W? 0:Z_FLAG)|(J.B.h&S_FLAG); \ + R->HL.W=J.W + +#define M_SBCW(Rg) \ + I=R->AF.B.l&C_FLAG;J.W=(R->HL.W-R->Rg.W-I)&0xFFFF; \ + R->AF.B.l= \ + N_FLAG| \ + (((long)R->HL.W-(long)R->Rg.W-(long)I)&0x10000? C_FLAG:0)| \ + ((R->HL.W^R->Rg.W)&(R->HL.W^J.W)&0x8000? V_FLAG:0)| \ + ((R->HL.W^R->Rg.W^J.W)&0x1000? H_FLAG:0)| \ + (J.W? 0:Z_FLAG)|(J.B.h&S_FLAG); \ + R->HL.W=J.W + +enum Codes +{ + NOP,LD_BC_WORD,LD_xBC_A,INC_BC,INC_B,DEC_B,LD_B_BYTE,RLCA, + EX_AF_AF,ADD_HL_BC,LD_A_xBC,DEC_BC,INC_C,DEC_C,LD_C_BYTE,RRCA, + DJNZ,LD_DE_WORD,LD_xDE_A,INC_DE,INC_D,DEC_D,LD_D_BYTE,RLA, + JR,ADD_HL_DE,LD_A_xDE,DEC_DE,INC_E,DEC_E,LD_E_BYTE,RRA, + JR_NZ,LD_HL_WORD,LD_xWORD_HL,INC_HL,INC_H,DEC_H,LD_H_BYTE,DAA, + JR_Z,ADD_HL_HL,LD_HL_xWORD,DEC_HL,INC_L,DEC_L,LD_L_BYTE,CPL, + JR_NC,LD_SP_WORD,LD_xWORD_A,INC_SP,INC_xHL,DEC_xHL,LD_xHL_BYTE,SCF, + JR_C,ADD_HL_SP,LD_A_xWORD,DEC_SP,INC_A,DEC_A,LD_A_BYTE,CCF, + LD_B_B,LD_B_C,LD_B_D,LD_B_E,LD_B_H,LD_B_L,LD_B_xHL,LD_B_A, + LD_C_B,LD_C_C,LD_C_D,LD_C_E,LD_C_H,LD_C_L,LD_C_xHL,LD_C_A, + LD_D_B,LD_D_C,LD_D_D,LD_D_E,LD_D_H,LD_D_L,LD_D_xHL,LD_D_A, + LD_E_B,LD_E_C,LD_E_D,LD_E_E,LD_E_H,LD_E_L,LD_E_xHL,LD_E_A, + LD_H_B,LD_H_C,LD_H_D,LD_H_E,LD_H_H,LD_H_L,LD_H_xHL,LD_H_A, + LD_L_B,LD_L_C,LD_L_D,LD_L_E,LD_L_H,LD_L_L,LD_L_xHL,LD_L_A, + LD_xHL_B,LD_xHL_C,LD_xHL_D,LD_xHL_E,LD_xHL_H,LD_xHL_L,HALT,LD_xHL_A, + LD_A_B,LD_A_C,LD_A_D,LD_A_E,LD_A_H,LD_A_L,LD_A_xHL,LD_A_A, + ADD_B,ADD_C,ADD_D,ADD_E,ADD_H,ADD_L,ADD_xHL,ADD_A, + ADC_B,ADC_C,ADC_D,ADC_E,ADC_H,ADC_L,ADC_xHL,ADC_A, + SUB_B,SUB_C,SUB_D,SUB_E,SUB_H,SUB_L,SUB_xHL,SUB_A, + SBC_B,SBC_C,SBC_D,SBC_E,SBC_H,SBC_L,SBC_xHL,SBC_A, + AND_B,AND_C,AND_D,AND_E,AND_H,AND_L,AND_xHL,AND_A, + XOR_B,XOR_C,XOR_D,XOR_E,XOR_H,XOR_L,XOR_xHL,XOR_A, + OR_B,OR_C,OR_D,OR_E,OR_H,OR_L,OR_xHL,OR_A, + CP_B,CP_C,CP_D,CP_E,CP_H,CP_L,CP_xHL,CP_A, + RET_NZ,POP_BC,JP_NZ,JP,CALL_NZ,PUSH_BC,ADD_BYTE,RST00, + RET_Z,RET,JP_Z,PFX_CB,CALL_Z,CALL,ADC_BYTE,RST08, + RET_NC,POP_DE,JP_NC,OUTA,CALL_NC,PUSH_DE,SUB_BYTE,RST10, + RET_C,EXX,JP_C,INA,CALL_C,PFX_DD,SBC_BYTE,RST18, + RET_PO,POP_HL,JP_PO,EX_HL_xSP,CALL_PO,PUSH_HL,AND_BYTE,RST20, + RET_PE,LD_PC_HL,JP_PE,EX_DE_HL,CALL_PE,PFX_ED,XOR_BYTE,RST28, + RET_P,POP_AF,JP_P,DI,CALL_P,PUSH_AF,OR_BYTE,RST30, + RET_M,LD_SP_HL,JP_M,EI,CALL_M,PFX_FD,CP_BYTE,RST38 +}; + +enum CodesCB +{ + RLC_B,RLC_C,RLC_D,RLC_E,RLC_H,RLC_L,RLC_xHL,RLC_A, + RRC_B,RRC_C,RRC_D,RRC_E,RRC_H,RRC_L,RRC_xHL,RRC_A, + RL_B,RL_C,RL_D,RL_E,RL_H,RL_L,RL_xHL,RL_A, + RR_B,RR_C,RR_D,RR_E,RR_H,RR_L,RR_xHL,RR_A, + SLA_B,SLA_C,SLA_D,SLA_E,SLA_H,SLA_L,SLA_xHL,SLA_A, + SRA_B,SRA_C,SRA_D,SRA_E,SRA_H,SRA_L,SRA_xHL,SRA_A, + SLL_B,SLL_C,SLL_D,SLL_E,SLL_H,SLL_L,SLL_xHL,SLL_A, + SRL_B,SRL_C,SRL_D,SRL_E,SRL_H,SRL_L,SRL_xHL,SRL_A, + BIT0_B,BIT0_C,BIT0_D,BIT0_E,BIT0_H,BIT0_L,BIT0_xHL,BIT0_A, + BIT1_B,BIT1_C,BIT1_D,BIT1_E,BIT1_H,BIT1_L,BIT1_xHL,BIT1_A, + BIT2_B,BIT2_C,BIT2_D,BIT2_E,BIT2_H,BIT2_L,BIT2_xHL,BIT2_A, + BIT3_B,BIT3_C,BIT3_D,BIT3_E,BIT3_H,BIT3_L,BIT3_xHL,BIT3_A, + BIT4_B,BIT4_C,BIT4_D,BIT4_E,BIT4_H,BIT4_L,BIT4_xHL,BIT4_A, + BIT5_B,BIT5_C,BIT5_D,BIT5_E,BIT5_H,BIT5_L,BIT5_xHL,BIT5_A, + BIT6_B,BIT6_C,BIT6_D,BIT6_E,BIT6_H,BIT6_L,BIT6_xHL,BIT6_A, + BIT7_B,BIT7_C,BIT7_D,BIT7_E,BIT7_H,BIT7_L,BIT7_xHL,BIT7_A, + RES0_B,RES0_C,RES0_D,RES0_E,RES0_H,RES0_L,RES0_xHL,RES0_A, + RES1_B,RES1_C,RES1_D,RES1_E,RES1_H,RES1_L,RES1_xHL,RES1_A, + RES2_B,RES2_C,RES2_D,RES2_E,RES2_H,RES2_L,RES2_xHL,RES2_A, + RES3_B,RES3_C,RES3_D,RES3_E,RES3_H,RES3_L,RES3_xHL,RES3_A, + RES4_B,RES4_C,RES4_D,RES4_E,RES4_H,RES4_L,RES4_xHL,RES4_A, + RES5_B,RES5_C,RES5_D,RES5_E,RES5_H,RES5_L,RES5_xHL,RES5_A, + RES6_B,RES6_C,RES6_D,RES6_E,RES6_H,RES6_L,RES6_xHL,RES6_A, + RES7_B,RES7_C,RES7_D,RES7_E,RES7_H,RES7_L,RES7_xHL,RES7_A, + SET0_B,SET0_C,SET0_D,SET0_E,SET0_H,SET0_L,SET0_xHL,SET0_A, + SET1_B,SET1_C,SET1_D,SET1_E,SET1_H,SET1_L,SET1_xHL,SET1_A, + SET2_B,SET2_C,SET2_D,SET2_E,SET2_H,SET2_L,SET2_xHL,SET2_A, + SET3_B,SET3_C,SET3_D,SET3_E,SET3_H,SET3_L,SET3_xHL,SET3_A, + SET4_B,SET4_C,SET4_D,SET4_E,SET4_H,SET4_L,SET4_xHL,SET4_A, + SET5_B,SET5_C,SET5_D,SET5_E,SET5_H,SET5_L,SET5_xHL,SET5_A, + SET6_B,SET6_C,SET6_D,SET6_E,SET6_H,SET6_L,SET6_xHL,SET6_A, + SET7_B,SET7_C,SET7_D,SET7_E,SET7_H,SET7_L,SET7_xHL,SET7_A +}; + +enum CodesED +{ + DB_00,DB_01,DB_02,DB_03,DB_04,DB_05,DB_06,DB_07, + DB_08,DB_09,DB_0A,DB_0B,DB_0C,DB_0D,DB_0E,DB_0F, + DB_10,DB_11,DB_12,DB_13,DB_14,DB_15,DB_16,DB_17, + DB_18,DB_19,DB_1A,DB_1B,DB_1C,DB_1D,DB_1E,DB_1F, + DB_20,DB_21,DB_22,DB_23,DB_24,DB_25,DB_26,DB_27, + DB_28,DB_29,DB_2A,DB_2B,DB_2C,DB_2D,DB_2E,DB_2F, + DB_30,DB_31,DB_32,DB_33,DB_34,DB_35,DB_36,DB_37, + DB_38,DB_39,DB_3A,DB_3B,DB_3C,DB_3D,DB_3E,DB_3F, + IN_B_xC,OUT_xC_B,SBC_HL_BC,LD_xWORDe_BC,NEG,RETN,IM_0,LD_I_A, + IN_C_xC,OUT_xC_C,ADC_HL_BC,LD_BC_xWORDe,DB_4C,RETI,DB_,LD_R_A, + IN_D_xC,OUT_xC_D,SBC_HL_DE,LD_xWORDe_DE,DB_54,DB_55,IM_1,LD_A_I, + IN_E_xC,OUT_xC_E,ADC_HL_DE,LD_DE_xWORDe,DB_5C,DB_5D,IM_2,LD_A_R, + IN_H_xC,OUT_xC_H,SBC_HL_HL,LD_xWORDe_HL,DB_64,DB_65,DB_66,RRD, + IN_L_xC,OUT_xC_L,ADC_HL_HL,LD_HL_xWORDe,DB_6C,DB_6D,DB_6E,RLD, + IN_F_xC,DB_71,SBC_HL_SP,LD_xWORDe_SP,DB_74,DB_75,DB_76,DB_77, + IN_A_xC,OUT_xC_A,ADC_HL_SP,LD_SP_xWORDe,DB_7C,DB_7D,DB_7E,DB_7F, + DB_80,DB_81,DB_82,DB_83,DB_84,DB_85,DB_86,DB_87, + DB_88,DB_89,DB_8A,DB_8B,DB_8C,DB_8D,DB_8E,DB_8F, + DB_90,DB_91,DB_92,DB_93,DB_94,DB_95,DB_96,DB_97, + DB_98,DB_99,DB_9A,DB_9B,DB_9C,DB_9D,DB_9E,DB_9F, + LDI,CPI,INI,OUTI,DB_A4,DB_A5,DB_A6,DB_A7, + LDD,CPD,IND,OUTD,DB_AC,DB_AD,DB_AE,DB_AF, + LDIR,CPIR,INIR,OTIR,DB_B4,DB_B5,DB_B6,DB_B7, + LDDR,CPDR,INDR,OTDR,DB_BC,DB_BD,DB_BE,DB_BF, + DB_C0,DB_C1,DB_C2,DB_C3,DB_C4,DB_C5,DB_C6,DB_C7, + DB_C8,DB_C9,DB_CA,DB_CB,DB_CC,DB_CD,DB_CE,DB_CF, + DB_D0,DB_D1,DB_D2,DB_D3,DB_D4,DB_D5,DB_D6,DB_D7, + DB_D8,DB_D9,DB_DA,DB_DB,DB_DC,DB_DD,DB_DE,DB_DF, + DB_E0,DB_E1,DB_E2,DB_E3,DB_E4,DB_E5,DB_E6,DB_E7, + DB_E8,DB_E9,DB_EA,DB_EB,DB_EC,DB_ED,DB_EE,DB_EF, + DB_F0,DB_F1,DB_F2,DB_F3,DB_F4,DB_F5,DB_F6,DB_F7, + DB_F8,DB_F9,DB_FA,DB_FB,DB_FC,DB_FD,DB_FE,DB_FF +}; + +static void CodesCB(register Z80 *R) +{ + register byte I; + + I=RdZ80(R->PC.W++); + R->ICount-=CyclesCB[I]; + switch(I) + { +#include "CodesCB.h" + default: + if(R->TrapBadOps) + printf + ( + "[Z80 %lX] Unrecognized instruction: CB %02X at PC=%04X\n", + (long)(R->User),RdZ80(R->PC.W-1),R->PC.W-2 + ); + } +} + +static void CodesDDCB(register Z80 *R) +{ + register pair J; + register byte I; + +#define XX IX + J.W=R->XX.W+(offset)RdZ80(R->PC.W++); + I=RdZ80(R->PC.W++); + R->ICount-=CyclesXXCB[I]; + switch(I) + { +#include "CodesXCB.h" + default: + if(R->TrapBadOps) + printf + ( + "[Z80 %lX] Unrecognized instruction: DD CB %02X %02X at PC=%04X\n", + (long)(R->User),RdZ80(R->PC.W-2),RdZ80(R->PC.W-1),R->PC.W-4 + ); + } +#undef XX +} + +static void CodesFDCB(register Z80 *R) +{ + register pair J; + register byte I; + +#define XX IY + J.W=R->XX.W+(offset)RdZ80(R->PC.W++); + I=RdZ80(R->PC.W++); + R->ICount-=CyclesXXCB[I]; + switch(I) + { +#include "CodesXCB.h" + default: + if(R->TrapBadOps) + printf + ( + "[Z80 %lX] Unrecognized instruction: FD CB %02X %02X at PC=%04X\n", + (long)R->User,RdZ80(R->PC.W-2),RdZ80(R->PC.W-1),R->PC.W-4 + ); + } +#undef XX +} + +static void CodesED(register Z80 *R) +{ + register byte I; + register pair J; + + I=RdZ80(R->PC.W++); + R->ICount-=CyclesED[I]; + switch(I) + { +#include "CodesED.h" + case PFX_ED: + R->PC.W--;break; + default: + if(R->TrapBadOps) + printf + ( + "[Z80 %lX] Unrecognized instruction: ED %02X at PC=%04X\n", + (long)R->User,RdZ80(R->PC.W-1),R->PC.W-2 + ); + } +} + +static void CodesDD(register Z80 *R) +{ + register byte I; + register pair J; + +#define XX IX + I=RdZ80(R->PC.W++); + R->ICount-=CyclesXX[I]; + switch(I) + { +#include "CodesXX.h" + case PFX_FD: + case PFX_DD: + R->PC.W--;break; + case PFX_CB: + CodesDDCB(R);break; + case HALT: + R->PC.W--;R->IFF|=0x80;R->ICount=0;break; + default: + if(R->TrapBadOps) + printf + ( + "[Z80 %lX] Unrecognized instruction: DD %02X at PC=%04X\n", + (long)R->User,RdZ80(R->PC.W-1),R->PC.W-2 + ); + } +#undef XX +} + +static void CodesFD(register Z80 *R) +{ + register byte I; + register pair J; + +#define XX IY + I=RdZ80(R->PC.W++); + R->ICount-=CyclesXX[I]; + switch(I) + { +#include "CodesXX.h" + case PFX_FD: + case PFX_DD: + R->PC.W--;break; + case PFX_CB: + CodesFDCB(R);break; + case HALT: + R->PC.W--;R->IFF|=0x80;R->ICount=0;break; + default: + printf + ( + "Unrecognized instruction: FD %02X at PC=%04X\n", + RdZ80(R->PC.W-1),R->PC.W-2 + ); + } +#undef XX +} + +/** ResetZ80() ***********************************************/ +/** This function can be used to reset the register struct **/ +/** before starting execution with Z80(). It sets the **/ +/** registers to their supposed initial values. **/ +/*************************************************************/ +void ResetZ80(Z80 *R) +{ + R->PC.W=0x0000;R->SP.W=0xF000; + R->AF.W=R->BC.W=R->DE.W=R->HL.W=0x0000; + R->AF1.W=R->BC1.W=R->DE1.W=R->HL1.W=0x0000; + R->IX.W=R->IY.W=0x0000; + R->I=0x00;R->IFF=0x00; + R->ICount=R->IPeriod; + R->IRequest=INT_NONE; +} + +/** ExecZ80() ************************************************/ +/** This function will execute a single Z80 opcode. It will **/ +/** then return next PC, and current register values in R. **/ +/*************************************************************/ +word ExecZ80(Z80 *R) +{ + register byte I; + register pair J; + + I=RdZ80(R->PC.W++); + R->ICount-=Cycles[I]; + switch(I) + { +#include "Codes.h" + case PFX_CB: CodesCB(R);break; + case PFX_ED: CodesED(R);break; + case PFX_FD: CodesFD(R);break; + case PFX_DD: CodesDD(R);break; + } + + /* We are done */ + return(R->PC.W); +} + +/** IntZ80() *************************************************/ +/** This function will generate interrupt of given vector. **/ +/*************************************************************/ +void IntZ80(Z80 *R,word Vector) +{ + if((R->IFF&0x01)||(Vector==INT_NMI)) + { + /* Experimental V Shouldn't disable all interrupts? */ + R->IFF=(R->IFF&0x9E)|((R->IFF&0x01)<<6); + if(R->IFF&0x80) { R->PC.W++;R->IFF&=0x7F; } + M_PUSH(PC); + + if(Vector==INT_NMI) R->PC.W=INT_NMI; + else + if(R->IFF&0x04) + { + Vector=(Vector&0xFF)|((word)(R->I)<<8); + R->PC.B.l=RdZ80(Vector++); + R->PC.B.h=RdZ80(Vector); + } + else + if(R->IFF&0x02) R->PC.W=INT_IRQ; + else R->PC.W=Vector; + } +} + +/** RunZ80() *************************************************/ +/** This function will run Z80 code until an LoopZ80() call **/ +/** returns INT_QUIT. It will return the PC at which **/ +/** emulation stopped, and current register values in R. **/ +/*************************************************************/ +word RunZ80(Z80 *R) +{ + register byte I; + register pair J; + + for(;;) + { +#ifdef DEBUG + /* Turn tracing on when reached trap address */ + if(R->PC.W==R->Trap) R->Trace=1; + /* Call single-step debugger, exit if requested */ + if(R->Trace) + if(!DebugZ80(R)) return(R->PC.W); +#endif + + I=RdZ80(R->PC.W++); + R->ICount-=Cycles[I]; + switch(I) + { +#include "Codes.h" + case PFX_CB: CodesCB(R);break; + case PFX_ED: CodesED(R);break; + case PFX_FD: CodesFD(R);break; + case PFX_DD: CodesDD(R);break; + } + + /* If cycle counter expired... */ + if(R->ICount<=0) + { + /* If we have come after EI, get address from IRequest */ + /* Otherwise, get it from the loop handler */ + if(R->IFF&0x20) + { + J.W=R->IRequest; /* Get pending interrupt */ + R->ICount+=R->IBackup-1; /* Restore the ICount */ + R->IFF&=0xDF; /* Done with AfterEI state */ + } + else + { + J.W=LoopZ80(R); /* Call periodic handler */ + R->ICount=R->IPeriod; /* Reset the cycle counter */ + } + + if(J.W==INT_QUIT) return(R->PC.W); /* Exit if INT_QUIT */ + if(J.W!=INT_NONE) IntZ80(R,J.W); /* Int-pt if needed */ + } + } + + /* Execution stopped */ + return(R->PC.W); +} diff --git a/TIKI-100_emul-src/Z80.h b/TIKI-100_emul-src/Z80.h new file mode 100644 index 0000000..5b479f7 --- /dev/null +++ b/TIKI-100_emul-src/Z80.h @@ -0,0 +1,139 @@ +/** Z80: portable Z80 emulator *******************************/ +/** **/ +/** Z80.h **/ +/** **/ +/** This file contains declarations relevant to emulation **/ +/** of Z80 CPU. **/ +/** **/ +/** Copyright (C) Marat Fayzullin 1994,1995,1996,1997 **/ +/** You are not allowed to distribute this software **/ +/** commercially. Please, notify me, if you make any **/ +/** changes to this file. **/ +/*************************************************************/ +#ifndef Z80_H +#define Z80_H + + /* Compilation options: */ +/* #define DEBUG */ /* Compile debugging version */ +/* #define LSB_FIRST */ /* Compile for low-endian CPU */ +/* #define MSB_FIRST */ /* Compile for hi-endian CPU */ + + /* LoopZ80() may return: */ +#define INT_IRQ 0x0038 /* Standard RST 38h interrupt */ +#define INT_NMI 0x0066 /* Non-maskable interrupt */ +#define INT_NONE 0xFFFF /* No interrupt required */ +#define INT_QUIT 0xFFFE /* Exit the emulation */ + + /* Bits in Z80 F register: */ +#define S_FLAG 0x80 /* 1: Result negative */ +#define Z_FLAG 0x40 /* 1: Result is zero */ +#define H_FLAG 0x10 /* 1: Halfcarry/Halfborrow */ +#define P_FLAG 0x04 /* 1: Result is even */ +#define V_FLAG 0x04 /* 1: Overflow occured */ +#define N_FLAG 0x02 /* 1: Subtraction occured */ +#define C_FLAG 0x01 /* 1: Carry/Borrow occured */ + +/** Simple Datatypes *****************************************/ +/** NOTICE: sizeof(byte)=1 and sizeof(word)=2 **/ +/*************************************************************/ +typedef unsigned char byte; +typedef unsigned short word; +typedef signed char offset; + +/** Structured Datatypes *************************************/ +/** NOTICE: #define LSB_FIRST for machines where least **/ +/** signifcant byte goes first. **/ +/*************************************************************/ +typedef union +{ +#ifdef LSB_FIRST + struct { byte l,h; } B; +#else + struct { byte h,l; } B; +#endif + word W; +} pair; + +typedef struct +{ + pair AF,BC,DE,HL,IX,IY,PC,SP; /* Main registers */ + pair AF1,BC1,DE1,HL1; /* Shadow registers */ + byte IFF,I; /* Interrupt registers */ + + int IPeriod,ICount; /* Set IPeriod to number of CPU cycles */ + /* between calls to LoopZ80() */ + int IBackup; /* Private, don't touch */ + word IRequest; /* Set to address of pending IRQ */ + void *User; /* Arbitrary user data (ID,RAM*,etc.) */ + byte TrapBadOps; /* Set to 1 to warn of illegal opcodes */ + word Trap; /* Set Trap to address to trace from */ + byte Trace; /* Set Trace=1 to start tracing */ +} Z80; + +/** ResetZ80() ***********************************************/ +/** This function can be used to reset the registers before **/ +/** starting execution with RunZ80(). It sets registers to **/ +/** their initial values. **/ +/*************************************************************/ +void ResetZ80(register Z80 *R); + +/** ExecZ80() ************************************************/ +/** This function will execute a single Z80 opcode. It will **/ +/** then return next PC, and current register values in R. **/ +/*************************************************************/ +word ExecZ80(register Z80 *R); + +/** IntZ80() *************************************************/ +/** This function will generate interrupt of given vector. **/ +/*************************************************************/ +void IntZ80(register Z80 *R,register word Vector); + +/** RunZ80() *************************************************/ +/** This function will run Z80 code until an LoopZ80() call **/ +/** returns INT_QUIT. It will return the PC at which **/ +/** emulation stopped, and current register values in R. **/ +/*************************************************************/ +word RunZ80(register Z80 *R); + +/** RdZ80()/WrZ80() ******************************************/ +/** These functions are called when access to RAM occurs. **/ +/** They allow to control memory access. **/ +/************************************ TO BE WRITTEN BY USER **/ +void WrZ80(register word Addr,register byte Value); +byte RdZ80(register word Addr); + +/** InZ80()/OutZ80() *****************************************/ +/** Z80 emulation calls these functions to read/write from **/ +/** I/O ports. There can be 65536 I/O ports, but only first **/ +/** 256 are usually used **/ +/************************************ TO BE WRITTEN BY USER **/ +void OutZ80(register word Port,register byte Value); +byte InZ80(register word Port); + +/** PatchZ80() ***********************************************/ +/** Z80 emulation calls this function when it encounters a **/ +/** special patch command (ED FE) provided for user needs. **/ +/** For example, it can be called to emulate BIOS calls, **/ +/** such as disk and tape access. Replace it with an empty **/ +/** macro for no patching. **/ +/************************************ TO BE WRITTEN BY USER **/ +void PatchZ80(register Z80 *R); + +/** DebugZ80() ***********************************************/ +/** This function should exist if DEBUG is #defined. When **/ +/** Trace!=0, it is called after each command executed by **/ +/** the CPU, and given the Z80 registers. Emulation exits **/ +/** if DebugZ80() returns 0. **/ +/*************************************************************/ +byte DebugZ80(register Z80 *R); + +/** LoopZ80() ************************************************/ +/** Z80 emulation calls this function periodically to check **/ +/** if the system hardware requires any interrupts. This **/ +/** function must return an address of the interrupt vector **/ +/** (0x0038, 0x0066, etc.) or INT_NONE for no interrupt. **/ +/** Return INT_QUIT to exit the emulation loop. **/ +/************************************ TO BE WRITTEN BY USER **/ +word LoopZ80(register Z80 *R); + +#endif /* Z80_H */ diff --git a/TIKI-100_emul-src/amiga.c b/TIKI-100_emul-src/amiga.c new file mode 100644 index 0000000..ee0f15a --- /dev/null +++ b/TIKI-100_emul-src/amiga.c @@ -0,0 +1,636 @@ +/* amiga.c V1.1.0 + * + * Amiga systemspesifikk kode for TIKI-100_emul + * Copyright (C) Asbjørn Djupdal 2000-2001 + */ + +#include "TIKI-100_emul.h" + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define CATCOMP_NUMBERS +#define CATCOMP_STRINGS +#define CATCOMP_BLOCK +#define CATCOMP_CODE +#include "amiga_strings.h" + +#define DEFAULT_DIR "PROGDIR:plater" +#define STATUSBAR_HEIGHT 15 + +/* protos */ + +int main (int argc, char *argv[]); +static struct Menu *CreateLocMenus(struct NewMenu *newMenus, ULONG tag, ...); +static void createStatusBar (void); +static void draw3dBox (int x, int y, int w, int h, boolean raise); +static void doIDCMP (void); +static void loadDiskImage (int drive); +static void saveDiskImage (int drive); + +/* variabler */ + +static byte keyTable[0x80] = { + KEY_GRAFIKK, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + 0x38, 0x39, 0x30, 0x2b, 0x40, KEY_UTVID, KEY_NONE, KEY_NUM0, + 0x71, 0x77, 0x65, 0x72, 0x74, 0x79, 0x75, 0x69, + 0x6f, 0x70, 0xe5, 0x5e, KEY_NONE, KEY_NUM1, KEY_NUM2, KEY_NUM3, + 0x61, 0x73, 0x64, 0x66, 0x67, 0x68, 0x6a, 0x6b, + 0x6c, 0xf8, 0xe6, 0x27, KEY_NONE, KEY_NUM4, KEY_NUM5, KEY_NUM6, + 0x3c, 0x7a, 0x78, 0x63, 0x76, 0x62, 0x6e, 0x6d, + 0x2c, 0x2e, 0x2d, KEY_NONE, KEY_NUMDOT, KEY_NUM7, KEY_NUM8, KEY_NUM9, + KEY_SPACE, KEY_SLETT, KEY_BRYT, KEY_ENTER, KEY_CR, KEY_ANGRE, KEY_HOME, KEY_NONE, + KEY_NONE, KEY_NONE, KEY_NUMMINUS, KEY_NONE, KEY_UP, KEY_DOWN, KEY_RIGHT, KEY_LEFT, + KEY_F1, KEY_F2, KEY_F3, KEY_F4, KEY_F5, KEY_F6, KEY_PGUP, KEY_PGDOWN, + KEY_TABLEFT, KEY_TABRIGHT, KEY_NUMPERCENT, KEY_NUMEQU, KEY_NUMDIV, KEY_NUMMULT, KEY_NUMPLUS, KEY_HJELP, + KEY_SHIFT, KEY_SHIFT, KEY_NONE, KEY_CTRL, KEY_LOCK, KEY_NONE, KEY_NONE, KEY_NONE, + KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, + KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, + KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE +}; + +static struct NewMenu mn[] = { + {NM_TITLE, (char *)MSG_EMULATOR_MENU, 0, 0, 0, 0, }, + {NM_ITEM, (char *)MSG_EMULATOR_RESET, 0, 0, 0, 0, }, + {NM_ITEM, (char *)MSG_EMULATOR_ABOUT, 0, 0, 0, 0, }, + {NM_ITEM, (char *)MSG_EMULATOR_QUIT, 0, 0, 0, 0, }, + + {NM_TITLE, (char *)MSG_DISKDRIVE_MENU, 0, 0, 0, 0, }, + {NM_ITEM, (char *)MSG_DISKDRIVE_LOADA, 0, 0, 0, 0, }, + {NM_ITEM, (char *)MSG_DISKDRIVE_LOADB, 0, 0, 0, 0, }, + {NM_ITEM, (char *)MSG_DISKDRIVE_SAVEA, 0, NM_ITEMDISABLED, 0, 0, }, + {NM_ITEM, (char *)MSG_DISKDRIVE_SAVEB, 0, NM_ITEMDISABLED, 0, 0, }, + {NM_ITEM, (char *)MSG_DISKDRIVE_REMOVEA, 0, 0, 0, 0, }, + {NM_ITEM, (char *)MSG_DISKDRIVE_REMOVEB, 0, 0, 0, 0, }, + + {NM_TITLE, (char *)MSG_OPTIONS_MENU, 0, 0, 0, 0, }, + {NM_ITEM, (char *)MSG_OPTIONS_SLOWDOWN, 0, NM_ITEMDISABLED | CHECKIT | MENUTOGGLE, 0, 0, }, + {NM_ITEM, (char *)MSG_OPTIONS_SCANLINES, 0, CHECKIT | MENUTOGGLE, 0, 0, }, + {NM_ITEM, (char *)MSG_OPTIONS_SIZE40, 0, 0, 0, 0, }, + {NM_SUB, (char *)MSG_OPTIONS_SIZE40_ONE, 0, CHECKIT | CHECKED, ~1, 0, }, + {NM_SUB, (char *)MSG_OPTIONS_SIZE40_TWO, 0, CHECKIT, ~2, 0, }, + {NM_SUB, (char *)MSG_OPTIONS_SIZE40_FOUR, 0, CHECKIT, ~4, 0, }, + {NM_ITEM, (char *)MSG_OPTIONS_SIZE80, 0, 0, 0, 0, }, + {NM_SUB, (char *)MSG_OPTIONS_SIZE80_ONE, 0, CHECKIT | CHECKED, ~1, 0, }, + {NM_SUB, (char *)MSG_OPTIONS_SIZE80_TWO, 0, CHECKIT, ~2, 0, }, + +#ifdef DEBUG + {NM_TITLE, (char *)MSG_DEBUG_MENU, 0, 0, 0, 0, }, + {NM_ITEM, (char *)MSG_DEBUG_MONITOR, 0, 0, 0, 0, }, +#endif + + {NM_END, NULL, 0, 0, 0, 0, }, +}; + +static byte pressedKeys[0x100]; +static struct Screen *pubScreen; +static struct Window *window; +static struct Menu *menuStrip; +static long pens[16]; +static struct LocaleInfo localeInfo; +struct Library *IntuitionBase; +struct Library *GfxBase; +struct Library *GadToolsBase; +struct Library *AslBase; +struct Library *LocaleBase; +static int topOffset, leftOffset; +static int borderX, borderY; +static int resolution = MEDRES; +static BOOL scanlines = FALSE; +static int times40 = 1; +static int times80 = 1; +static byte *dsk[2]; +static ULONG fileSize[2]; +static int width; +static int height; +static boolean changingWinSize; +static boolean lock = FALSE; +static boolean grafikk = FALSE; +static boolean disk[2] = {FALSE, FALSE}; + +/*****************************************************************************/ + +int main (int argc, char *argv[]) { + memset (pressedKeys, 1, 0x100); + + /* åpne bibliotek */ + if ((AslBase = (struct Library *)OpenLibrary ("asl.library", 37L))) { + if ((IntuitionBase = (struct Library *)OpenLibrary ("intuition.library", 39L))) { + if ((GfxBase = (struct Library *)OpenLibrary ("graphics.library", 39L))) { + if ((GadToolsBase = (struct Library *)OpenLibrary ("gadtools.library", 39L))) { + if ((LocaleBase = (struct Library *)OpenLibrary ("locale.library", 38L))) { + + /* finn katalog */ + localeInfo.li_LocaleBase = LocaleBase; + localeInfo.li_Catalog = OpenCatalog (NULL, "tikiemul.catalog", + OC_BuiltInLanguage, "english", TAG_DONE); + + /* skaff public screen */ + if ((pubScreen = LockPubScreen (NULL))) { + + /* finn vindusrammetykkelse */ + topOffset = pubScreen->WBorTop + pubScreen->Font->ta_YSize + 1; + leftOffset = pubScreen->WBorLeft; + borderX = leftOffset + pubScreen->WBorRight; + borderY = topOffset + pubScreen->WBorBottom + STATUSBAR_HEIGHT; + + /* finn vindusstørrelse */ + width = 512 * times80; + height = 256 * times80 * (scanlines ? 2 : 1); + + /* åpne vindu */ + if ((window = (struct Window *)OpenWindowTags (NULL, WA_Left, 0, WA_Top, 0, + WA_Width, width + borderX, + WA_Height, height + borderY, + WA_Activate, TRUE, WA_SmartRefresh, TRUE, + WA_Title, "TIKI-100_emul", + WA_PubScreen, pubScreen, + WA_NewLookMenus, TRUE, WA_DepthGadget, TRUE, + WA_CloseGadget, TRUE, WA_DragBar, TRUE, + WA_IDCMP, IDCMP_RAWKEY | IDCMP_MENUPICK | + IDCMP_CLOSEWINDOW | IDCMP_NEWSIZE, + TAG_DONE))) { + + /* skaff 16 pens */ + { + BOOL cont = TRUE; + int i; + + for (i = 0; i < 16; i++) { + if ((pens[i] = ObtainPen (pubScreen->ViewPort.ColorMap, -1, 0, 0, 0, PEN_EXCLUSIVE)) + == -1) { + cont = FALSE; + } + } + if (cont) { + + /* sett bakgrunnsfarge til farge 0 */ + SetAPen (window->RPort, pens[0]); + SetBPen (window->RPort, pens[0]); + RectFill (window->RPort, leftOffset, + topOffset, width - 1 + leftOffset, + height - 1 + topOffset); + + createStatusBar(); + + /* lag menystripe */ + { + APTR *visInfo; + if ((visInfo = (APTR)GetVisualInfo (window->WScreen, TAG_END))) { + if ((menuStrip = (struct Menu *)CreateLocMenus (mn, TAG_END))) { + if (LayoutMenus (menuStrip, visInfo, GTMN_NewLookMenus, TRUE, TAG_END)) { + if (SetMenuStrip (window, menuStrip)) { + + /* kjør emulator */ + runEmul(); + + /* avlutt */ + ClearMenuStrip (window); + } + FreeMenus (menuStrip); + } + } + FreeVisualInfo (visInfo); + } + } + } + for (i = 0; i < 16; i++) { + ReleasePen (pubScreen->ViewPort.ColorMap, pens[i]); + } + } + CloseWindow (window); + } + UnlockPubScreen (NULL, pubScreen); + } + CloseCatalog (localeInfo.li_Catalog); + CloseLibrary (LocaleBase); + } + CloseLibrary (GadToolsBase); + } + CloseLibrary (GfxBase); + } + CloseLibrary (IntuitionBase); + } + CloseLibrary (AslBase); + } + free (dsk[0]); + free (dsk[1]); + return 0; +} +/* Tatt (nesten) direkte fra NDK + * Lokalisert CreateMenus() + */ +static struct Menu *CreateLocMenus(struct NewMenu *newMenus, ULONG tag, ...) { + UWORD i = 0; + struct NewMenu *nm; + struct Menu *menus; + + /* gå til slutten */ + while (newMenus[i++].nm_Type != NM_END) {} + + /* alloker minne til menystruktur */ + if (!(nm = AllocVec (sizeof (struct NewMenu) * i, MEMF_CLEAR | MEMF_PUBLIC))) + return NULL; + + /* sett alle strenger i menystruktur */ + while (i--) { + nm[i] = newMenus[i]; + + if (nm[i].nm_Label != NM_BARLABEL) { + nm[i].nm_CommKey = GetString (&localeInfo, (LONG)nm[i].nm_Label); + + nm[i].nm_Label = nm[i].nm_CommKey + 2; + + if (nm[i].nm_CommKey[0] == ' ') + nm[i].nm_CommKey = NULL; + } + } + + /* lag meny */ + menus = CreateMenusA (nm, (struct TagItem *)&tag); + + FreeVec (nm); + + return (menus); +} +/* lager statusbar */ +static void createStatusBar (void) { + SetAPen (window->RPort, 0); + RectFill (window->RPort, leftOffset, height + topOffset, + width - 1 + leftOffset, height - 1 + STATUSBAR_HEIGHT + topOffset); + + draw3dBox (0, height, width, STATUSBAR_HEIGHT, TRUE); + + draw3dBox (20, height + 3, 9, 9, FALSE); + draw3dBox (40, height + 3, 9, 9, FALSE); + draw3dBox (60, height + 3, 9, 9, FALSE); + draw3dBox (80, height + 3, 9, 9, FALSE); + + lockLight (lock); + grafikkLight (grafikk); + diskLight (0, disk[0]); + diskLight (1, disk[1]); +} +/* lager en 3d-boks */ +static void draw3dBox (int x, int y, int w, int h, boolean raise) { + long pen1 = (raise ? 2 : 1); + long pen2 = (raise ? 1 : 2); + + SetAPen (window->RPort, pen1); + Move (window->RPort, x + leftOffset, y + h - 1 + topOffset); + Draw (window->RPort, x + leftOffset, y + topOffset); + Draw (window->RPort, x + w - 1 + leftOffset, y + topOffset); + SetAPen (window->RPort, pen2); + Draw (window->RPort, x + w - 1 + leftOffset, y + h - 1 + topOffset); + Draw (window->RPort, x + leftOffset, y + h - 1 + topOffset); +} + +/* Forandre oppløsning */ +void changeRes (int newRes) { + resolution = newRes; + switch (resolution) { + case LOWRES: + width = 256 * times40; + height = 256 * times40; + break; + case MEDRES: + width = 512 * times80; + height = 256 * times80 * (scanlines ? 2 : 1); + break; + case HIGHRES: + width = 1024; + height = 256 * (scanlines ? 4 : 1); + break; + } + ChangeWindowBox (window, 0, 0, width + borderX, height + borderY); + /* må vente til vindu har fått ny størrelse */ + changingWinSize = TRUE; + while (changingWinSize) { + Wait (1L << window->UserPort->mp_SigBit); + doIDCMP(); + } + /* rensk vindu */ + SetAPen (window->RPort, pens[0]); + RectFill (window->RPort, leftOffset, topOffset, width - 1 + leftOffset, height - 1 + topOffset); + + createStatusBar(); +} +/* Plotter en pixel med farge tatt fra pallett */ +void plotPixel (int x, int y, int color) { + SetAPen (window->RPort, pens[color]); + switch (resolution) { + case LOWRES: + x *= times40; + y *= times40; + break; + case MEDRES: + x *= times80; + y *= times80 * (scanlines ? 2 : 1); + break; + case HIGHRES: + y *= scanlines ? 4 : 1; + break; + } + WritePixel (window->RPort, x + leftOffset, y + topOffset); +} +/* Scroller skjerm 'distance' linjer oppover */ +void scrollScreen (int distance) { + switch (resolution) { + case LOWRES: + distance *= times40; + break; + case MEDRES: + distance *= times80 * (scanlines ? 2 : 1); + break; + case HIGHRES: + distance *= scanlines ? 4 : 1; + break; + } + ScrollRaster (window->RPort, 0, distance, leftOffset, topOffset, + width - 1 + leftOffset, height - 1 + topOffset); +} +/* Ny farge, gitt pallett nummer og intensitet 0-255 */ +void changePalette (int colornumber, byte red, byte green, byte blue) { + SetRGB32 (&(pubScreen->ViewPort), pens[colornumber], red << 24, green << 24, blue << 24); +} +/* Kalles periodisk. Lar system kode måle / senke emuleringshastighet + * Kan også brukes til sjekk av brukeraktivitet + * ms er antall "emulerte" millisekunder siden forrige gang loopEmul ble kalt + */ +void loopEmul (int ms) { + doIDCMP(); +} +/* Prosesserer alle nye IDCMP-events */ +static void doIDCMP (void) { + struct IntuiMessage *msg; + + while ((msg = (struct IntuiMessage *)GetMsg (window->UserPort))) { + struct MenuItem *item; + UWORD menuNumber; + + switch (msg->Class) { + case IDCMP_MENUPICK: + menuNumber = msg->Code; + while (menuNumber != MENUNULL) { + item = (struct MenuItem *)ItemAddress (menuStrip, menuNumber); + switch (MENUNUM (menuNumber)) { + case 0: /* emulator */ + switch (ITEMNUM (menuNumber)) { + case 0: /* reset */ + resetEmul(); + break; + case 1: { /* om */ + struct EasyStruct omReq = { + sizeof (struct EasyStruct), 0, + GetString (&localeInfo, MSG_ABOUTBOX_TITLE), + GetString (&localeInfo, MSG_ABOUTBOX_TEXT), + GetString (&localeInfo, MSG_ABOUTBOX_BUTTON) + }; + EasyRequest (NULL, &omReq, NULL); + break; + } + case 2: /* avslutt */ + quitEmul(); + break; + } + break; + case 1: /* diskettstasjon */ + switch (ITEMNUM (menuNumber)) { + case 0: /* hent plate a */ + loadDiskImage (0); + break; + case 1: /* hent plate b */ + loadDiskImage (1); + break; + case 2: /* lagre plate a */ + saveDiskImage (0); + break; + case 3: /* lagre plate b */ + saveDiskImage (1); + break; + case 4: /* fjern plate a */ + removeDisk (0); + OffMenu (window, FULLMENUNUM (1, 2, 0)); + break; + case 5: /* fjern plate b */ + removeDisk (1); + OffMenu (window, FULLMENUNUM (1, 3, 0)); + break; + } + break; + case 2: /* innstillinger */ + switch (ITEMNUM (menuNumber)) { + case 0: /* reduser hastighet */ + /* ikke implementert, har for treg maskin :-/ */ + break; + case 1: /* bevar forhold */ + scanlines = item->Flags & CHECKED; + changeRes (resolution); + resetEmul(); + break; + case 2: /* forstørr 40 modus */ + switch (SUBNUM (menuNumber)) { + case 0: /* 1 */ + times40 = 1; + break; + case 1: /* 2 */ + times40 = 2; + break; + case 2: /* 4 */ + times40 = 4; + break; + } + changeRes (resolution); + resetEmul(); + break; + case 3: /* forstærr 80 modus */ + switch (SUBNUM (menuNumber)) { + case 0: /* 1 */ + times80 = 1; + break; + case 1: /* 2 */ + times80 = 2; + break; + } + changeRes (resolution); + resetEmul(); + break; + } + break; +#ifdef DEBUG + case 3: /* debug */ + switch (ITEMNUM (menuNumber)) { + case 0: /* monitor */ + trace(); + break; + } + break; +#endif + } + menuNumber = item->NextSelect; + } + break; + case IDCMP_RAWKEY: + if (msg->Code < 0x80) { + pressedKeys[keyTable[msg->Code]] = 0; + } else { + pressedKeys[keyTable[msg->Code - 0x80]] = 1; + } + break; + case IDCMP_CLOSEWINDOW: + quitEmul(); + break; + case IDCMP_NEWSIZE: + changingWinSize = FALSE; + break; + } + ReplyMsg ((struct Message *)msg); + } +} +/* Hent inn diskbilde fra fil */ +static void loadDiskImage (int drive) { + struct FileRequester *fr; + static char drawer[256] = DEFAULT_DIR; /* hvilken skuffe filreq. skal åpne i */ + + if ((fr = (struct FileRequester *)AllocAslRequestTags (ASL_FileRequest, ASLFR_DoPatterns, + TRUE, ASLFR_InitialPattern, "~(#?.info)", + ASLFR_InitialDrawer, drawer, TAG_DONE))) { + if (AslRequest (fr, NULL)) { + char fileName[256]; + strcpy (fileName, fr->rf_Dir); + strcpy (drawer, fr->rf_Dir); + if (AddPart (fileName, fr->rf_File, 256)) { + BPTR fp; + if ((fp = Open ((STRPTR)&fileName, MODE_OLDFILE))) { + struct FileInfoBlock *fileInfo = 0L; + if ((fileInfo = (struct FileInfoBlock *)AllocDosObject (DOS_FIB, TAG_DONE))) { + if (ExamineFH (fp, fileInfo)) { + FILE *f; + fileSize[drive] = fileInfo->fib_Size; + free (dsk[drive]); + OnMenu (window, FULLMENUNUM (1, (drive + 2), 0)); + if ((dsk[drive] = (byte *)malloc (fileSize[drive]))) { + if ((f = fopen (fileName, "r"))) { + if (fread (dsk[drive], 1, fileSize[drive], f)) { + switch (fileSize[drive]) { + case 40*1*18*128: + insertDisk (drive, dsk[drive], 40, 1, 18, 128); + break; + case 40*1*10*512: + insertDisk (drive, dsk[drive], 40, 1, 10, 512); + break; + case 40*2*10*512: + insertDisk (drive, dsk[drive], 40, 2, 10, 512); + break; + case 80*2*10*512: + insertDisk (drive, dsk[drive], 80, 2, 10, 512); + break; + default: + removeDisk (drive); + OffMenu (window, FULLMENUNUM (1, (drive + 2), 0)); + } + } else { + removeDisk (drive); + OffMenu (window, FULLMENUNUM (1, (drive + 2), 0)); + } + fclose (f); + } else { + removeDisk (drive); + OffMenu (window, FULLMENUNUM (1, (drive + 2), 0)); + } + } else { + removeDisk (drive); + OffMenu (window, FULLMENUNUM (1, (drive + 2), 0)); + } + } + FreeDosObject (DOS_FIB, fileInfo); + } + Close (fp); + } + } + } + FreeAslRequest (fr); + } +} +/* Lagre diskbilde til fil */ +static void saveDiskImage (int drive) { + struct FileRequester *fr; + FILE *fp; + static char drawer[256] = DEFAULT_DIR; /* hvilken skuffe filreq. skal åpne i */ + + if ((fr = (struct FileRequester *)AllocAslRequestTags (ASL_FileRequest, ASL_FuncFlags, FILF_SAVE, + ASLFR_DoPatterns, TRUE, ASLFR_InitialPattern, + "~(#?.info)", ASLFR_InitialDrawer, drawer, + TAG_DONE))) { + if (AslRequest (fr, NULL)) { + char fileName[256]; + strcpy (fileName, fr->rf_Dir); + strcpy (drawer, fr->rf_Dir); + if (AddPart (fileName, fr->rf_File, 256)) { + if ((fp = fopen (fileName, "w"))) { + fwrite (dsk[drive], 1, fileSize[drive], fp); + fclose (fp); + } + } + } + FreeAslRequest (fr); + } +} +/* Tenn/slukk lock lys */ +void lockLight (boolean status) { + lock = status; + SetAPen (window->RPort, status ? 3 : 0); + RectFill (window->RPort, 21 + leftOffset, height + 4 + topOffset, + 27 + leftOffset, height + 10 + topOffset); +} +/* Tenn/slukk grafikk lys */ +void grafikkLight (boolean status) { + grafikk = status; + SetAPen (window->RPort, status ? 3 : 0); + RectFill (window->RPort, 41 + leftOffset, height + 4 + topOffset, + 47 + leftOffset, height + 10 + topOffset); +} +/* Tenn/slukk disk lys for gitt stasjon */ +void diskLight (int drive, boolean status) { + int x = (drive ? 80 : 60); + disk[drive] = status; + SetAPen (window->RPort, status ? 3 : 0); + RectFill (window->RPort, x + 1 + leftOffset, height + 4 + topOffset, + x + 7 + leftOffset, height + 10 + topOffset); +} +/* Sjekk status til hver av de gitte tastene + * Sett bit n i returkode hvis tast n IKKE er nedtrykt + * Taster er enten ascii-kode eller en av konstantene over + */ +byte testKey (byte keys[8]) { + return pressedKeys[keys[0]] | (pressedKeys[keys[1]] << 1) | (pressedKeys[keys[2]] << 2) | + (pressedKeys[keys[3]] << 3) | (pressedKeys[keys[4]] << 4) | (pressedKeys[keys[5]] << 5) | + (pressedKeys[keys[6]] << 6) | (pressedKeys[keys[7]] << 7); +} +/* Setter seriekanalparametre */ +void setParams (struct serParams *p1Params, struct serParams *p2Params) { + /* ikke implementert */ +} +/* Send tegn til seriekanal */ +void sendChar (int port, byte value) { + /* ikke implementert */ +} +/* Hent tegn fra seriekanal */ +byte getChar (int port) { + /* ikke implementert */ + return 0; +} +/* Send tegn til skriver */ +void printChar (byte value) { + /* ikke implementert */ +} diff --git a/TIKI-100_emul-src/amiga.cd b/TIKI-100_emul-src/amiga.cd new file mode 100644 index 0000000..fea1bd5 --- /dev/null +++ b/TIKI-100_emul-src/amiga.cd @@ -0,0 +1,84 @@ +; amiga.cd V1.1.0 +; +; Katalogdeskriptor for TIKI-100_emul (amiga) +; Copyright (C) Asbjørn Djupdal 2001 +; +MSG_EMULATOR_MENU (//) + \0Emulator +; +MSG_EMULATOR_RESET (//) +R\0Reset +; +MSG_EMULATOR_ABOUT (//) + \0About... +; +MSG_EMULATOR_QUIT (//) +Q\0Quit +; +MSG_DISKDRIVE_MENU (//) + \0Diskdrive +; +MSG_DISKDRIVE_LOADA (//) +A\0Load disk A... +; +MSG_DISKDRIVE_LOADB (//) +B\0Load disk B... +; +MSG_DISKDRIVE_SAVEA (//) + \0Save disk A... +; +MSG_DISKDRIVE_SAVEB (//) + \0Save disk B... +; +MSG_DISKDRIVE_REMOVEA (//) + \0Remove disk A +; +MSG_DISKDRIVE_REMOVEB (//) + \0Remove disk B +; +MSG_OPTIONS_MENU (//) + \0Options +; +MSG_OPTIONS_SLOWDOWN (//) + \0Slow down +; +MSG_OPTIONS_SCANLINES (//) + \0Scanlines +; +MSG_OPTIONS_SIZE40 (//) + \000Lowres size +; +MSG_OPTIONS_SIZE40_ONE (//) + \0Standard +; +MSG_OPTIONS_SIZE40_TWO (//) + \0Double +; +MSG_OPTIONS_SIZE40_FOUR (//) + \0Quadruple +; +MSG_OPTIONS_SIZE80 (//) + \0Medres size +; +MSG_OPTIONS_SIZE80_ONE (//) + \0Standard +; +MSG_OPTIONS_SIZE80_TWO (//) + \0Double +; brukes bare av debugversjon +MSG_DEBUG_MENU (//) + \0Debug +; +MSG_DEBUG_MONITOR (//) +M\0Monitor +; +MSG_ABOUTBOX_TITLE (//) +About TIKI-100_emul +; +MSG_ABOUTBOX_TEXT (//) +TIKI-100_emul V1.1.1 - a freeware TIKI 100 Rev. C emulator.\n\ +Z80 emulation copyright (C) Marat Fayzullin 1994,1995,1996,1997.\n\ +The rest is copyright (C) Asbjørn Djupdal 2000-2001. +; +MSG_ABOUTBOX_BUTTON (//) +Ok diff --git a/TIKI-100_emul-src/amiga_icons/disk.info b/TIKI-100_emul-src/amiga_icons/disk.info new file mode 100644 index 0000000..ca96793 Binary files /dev/null and b/TIKI-100_emul-src/amiga_icons/disk.info differ diff --git a/TIKI-100_emul-src/amiga_icons/document.info b/TIKI-100_emul-src/amiga_icons/document.info new file mode 100644 index 0000000..4facf7f Binary files /dev/null and b/TIKI-100_emul-src/amiga_icons/document.info differ diff --git a/TIKI-100_emul-src/amiga_icons/drawer.info b/TIKI-100_emul-src/amiga_icons/drawer.info new file mode 100644 index 0000000..1d8286a Binary files /dev/null and b/TIKI-100_emul-src/amiga_icons/drawer.info differ diff --git a/TIKI-100_emul-src/amiga_icons/tikiemul.info b/TIKI-100_emul-src/amiga_icons/tikiemul.info new file mode 100644 index 0000000..e33a380 Binary files /dev/null and b/TIKI-100_emul-src/amiga_icons/tikiemul.info differ diff --git a/TIKI-100_emul-src/amiga_translations/empty.ct b/TIKI-100_emul-src/amiga_translations/empty.ct new file mode 100644 index 0000000..fb81aed --- /dev/null +++ b/TIKI-100_emul-src/amiga_translations/empty.ct @@ -0,0 +1,108 @@ +## version $VER: tikiemul.catalog 1.1 (02.06.01) +## codeset 0 +## language X +; +MSG_EMULATOR_MENU + +; \0Emulator +; +MSG_EMULATOR_RESET + +; R\0Reset +; +MSG_EMULATOR_ABOUT + +; \0About... +; +MSG_EMULATOR_QUIT + +; Q\0Quit +; +MSG_DISKDRIVE_MENU + +; \0Diskdrive +; +MSG_DISKDRIVE_LOADA + +; A\0Load disk A... +; +MSG_DISKDRIVE_LOADB + +; B\0Load disk B... +; +MSG_DISKDRIVE_SAVEA + +; \0Save disk A... +; +MSG_DISKDRIVE_SAVEB + +; \0Save disk B... +; +MSG_DISKDRIVE_REMOVEA + +; \0Remove disk A +; +MSG_DISKDRIVE_REMOVEB + +; \0Remove disk B +; +MSG_OPTIONS_MENU + +; \0Options +; +MSG_OPTIONS_SLOWDOWN + +; \0Slow down +; +MSG_OPTIONS_SCANLINES + +; \0Scanlines +; +MSG_OPTIONS_SIZE40 + +; \000Lowres size +; +MSG_OPTIONS_SIZE40_ONE + +; \0Standard +; +MSG_OPTIONS_SIZE40_TWO + +; \0Double +; +MSG_OPTIONS_SIZE40_FOUR + +; \0Quadruple +; +MSG_OPTIONS_SIZE80 + +; \0Medres size +; +MSG_OPTIONS_SIZE80_ONE + +; \0Standard +; +MSG_OPTIONS_SIZE80_TWO + +; \0Double +; +MSG_DEBUG_MENU + +; \0Debug +; +MSG_DEBUG_MONITOR + +; M\0Monitor +; +MSG_ABOUTBOX_TITLE + +; About TIKI-100_emul +; +MSG_ABOUTBOX_TEXT + +; TIKI-100_emul V1.1.1 - a freeware TIKI 100 Rev. C emulator.\nZ80 emulation copyright (C) Marat Fayzullin 1994,1995,1996,1997.\nThe rest is copyright (C) Asbjørn Djupdal 2000-2001. +; +MSG_ABOUTBOX_BUTTON + +; Ok +; diff --git a/TIKI-100_emul-src/amiga_translations/norsk.ct b/TIKI-100_emul-src/amiga_translations/norsk.ct new file mode 100644 index 0000000..1bfee1c --- /dev/null +++ b/TIKI-100_emul-src/amiga_translations/norsk.ct @@ -0,0 +1,83 @@ +## version $VER: tikiemul.catalog 1.1 (02.06.01) +## codeset 0 +## language norsk +; +MSG_EMULATOR_MENU + \0Emulator +; +MSG_EMULATOR_RESET +R\0Reset +; +MSG_EMULATOR_ABOUT + \0Om... +; +MSG_EMULATOR_QUIT +Q\0Avslutt +; +MSG_DISKDRIVE_MENU + \0Diskettstasjon +; +MSG_DISKDRIVE_LOADA +A\0Hent plate A... +; +MSG_DISKDRIVE_LOADB +B\0Hent plate B... +; +MSG_DISKDRIVE_SAVEA + \0Lagre plate A... +; +MSG_DISKDRIVE_SAVEB + \0Lagre plate B... +; +MSG_DISKDRIVE_REMOVEA + \0Fjern plate A +; +MSG_DISKDRIVE_REMOVEB + \0Fjern plate B +; +MSG_OPTIONS_MENU + \0Innstillinger +; +MSG_OPTIONS_SLOWDOWN + \0Begrens hastighet +; +MSG_OPTIONS_SCANLINES + \0Bevar forhold +; +MSG_OPTIONS_SIZE40 + \00040-modus størrelse +; +MSG_OPTIONS_SIZE40_ONE + \0Standard +; +MSG_OPTIONS_SIZE40_TWO + \0Fordoblet +; +MSG_OPTIONS_SIZE40_FOUR + \0Firedoblet +; +MSG_OPTIONS_SIZE80 + \00080-modus størrelse +; +MSG_OPTIONS_SIZE80_ONE + \0Standard +; +MSG_OPTIONS_SIZE80_TWO + \0Fordoblet +; +MSG_DEBUG_MENU + \0Debug +; +MSG_DEBUG_MONITOR +M\0Monitor +; +MSG_ABOUTBOX_TITLE +Om TIKI-100_emul +; +MSG_ABOUTBOX_TEXT +TIKI-100_emul V1.1.1 - en freeware TIKI 100 Rev. C emulator.\n\ +Z80 emulering copyright (C) Marat Fayzullin 1994,1995,1996,1997.\n\ +Resten copyright (C) Asbjørn Djupdal 2000-2001. +; +MSG_ABOUTBOX_BUTTON +Ok diff --git a/TIKI-100_emul-src/ctc.c b/TIKI-100_emul-src/ctc.c new file mode 100644 index 0000000..eb23fa5 --- /dev/null +++ b/TIKI-100_emul-src/ctc.c @@ -0,0 +1,149 @@ +/* ctc.c V1.1.0 + * + * Z80 CTC emulering for TIKI-100_emul + * Copyright (C) Asbjørn Djupdal 2000-2001 + */ + +#include "TIKI-100_emul.h" +#include "protos.h" + +/* data for en seriekanal */ +struct ctcParams { + boolean interrupt; /* om interrupt skal genereres */ + boolean enable; /* om teller av på eller av */ + int in; /* inngang - ant. sykler mellom hver inn-puls */ + int out; /* utgang - ant. sykler mellom hver ut-puls */ + boolean use4MHz; /* om klokke skal brukes i stedet for inngang */ + int count; /* sykler igjen til neste ut-puls */ + boolean writeTk; /* skriv tidskonstant neste gang */ + byte timeConst; /* tidskonstant */ + int scale; /* skaleringsfaktor */ +}; + +/* protos */ + +static void writeCtc (byte value, struct ctcParams *params); +static void recalcCtc (void); + +/* variabler */ + +extern Z80 cpu; +static struct ctcParams params0 = {FALSE, FALSE, 2, FALSE, 0, FALSE, 0, 0}; +static struct ctcParams params1 = {FALSE, FALSE, 2, FALSE, 0, FALSE, 0, 0}; +static struct ctcParams params2 = {FALSE, FALSE, 1, FALSE, 0, FALSE, 0, 0}; +static struct ctcParams params3 = {FALSE, FALSE, 1, FALSE, 0, FALSE, 0, 0}; + +/*****************************************************************************/ + +/* skriv til ctc0-register */ +void writeCtc0 (byte value) { + writeCtc (value, ¶ms0); +} +/* skriv til ctc1-register */ +void writeCtc1 (byte value) { + writeCtc (value, ¶ms1); +} +/* skriv til ctc2-register */ +void writeCtc2 (byte value) { + writeCtc (value, ¶ms2); +} +/* skriv til ctc3-register */ +void writeCtc3 (byte value) { + writeCtc (value, ¶ms3); +} +/* setter data til gitt seriekanal */ +static void writeCtc (byte value, struct ctcParams *params) { + if (params->writeTk) { + params->writeTk = FALSE; + params->timeConst = value; + params->enable = TRUE; + } else { + params->interrupt = value & 128; + if (value & 64) { + params->use4MHz = FALSE; + params->scale = 1; + } else { + params->use4MHz = TRUE; + params->scale = value & 32 ? 256 : 16; + } + params->writeTk = value & 4; + params->enable = !(value & 2); + } + recalcCtc(); +} +/* rekalkulerer frekvenser for tellerkanalene */ +static void recalcCtc (void) { + params2.in = params0.out; + params3.in = params2.out; + + params0.out = params0.timeConst * params0.scale * (params0.use4MHz ? 1 : params0.in); + params1.out = params1.timeConst * params1.scale * (params1.use4MHz ? 1 : params1.in); + params2.out = params2.timeConst * params2.scale * (params2.use4MHz ? 1 : params2.in); + params3.out = params3.timeConst * params3.scale * (params3.use4MHz ? 1 : params3.in); + + params0.count = params0.out; /* dette er ikke helt riktig, men bra nok */ + params1.count = params1.out; + params2.count = params2.out; + params3.count = params3.out; + + recalcBaud(); +} +/* les ctc0-register */ +byte readCtc0 (void) { + return params0.count / params0.in; +} +/* les ctc1-register */ +byte readCtc1 (void) { + return params1.count / params1.in; +} +/* les ctc2-register */ +byte readCtc2 (void) { + return params2.count / params2.in; +} +/* les ctc3-register */ +byte readCtc3 (void) { + return params3.count / params3.in; +} +/* må kalles regelmessig for å oppdatere tellere og sjekke om interrupt skal genereres */ +void updateCTC (int cycles) { + if (params0.enable) params0.count -= cycles; + if (params1.enable) params1.count -= cycles; + if (params2.enable) params2.count -= cycles; + if (params3.enable) params3.count -= cycles; + + if (params0.count <= 0) { + params0.count += params0.out; + if (params0.interrupt) { + IntZ80 (&cpu, 0x10); + } + } + if (params1.count <= 0) { + params1.count += params1.out; + if (params1.interrupt) { + IntZ80 (&cpu, 0x12); + } + } + if (params2.count <= 0) { + params2.count += params2.out; + if (params2.interrupt) { + IntZ80 (&cpu, 0x14); + } + } + if (params3.count <= 0) { + params3.count += params3.out; + if (params3.interrupt) { + IntZ80 (&cpu, 0x16); + } + } +} +/* returnerer antall sykler mellom hver ut puls på gitt ctc-kanal */ +int getCtc (int c) { + switch (c) { + case 0: return params0.out; + case 1: return params1.out; + case 2: return params2.out; + case 3: return params3.out; + } + return 0; +} + diff --git a/TIKI-100_emul-src/disk.c b/TIKI-100_emul-src/disk.c new file mode 100644 index 0000000..e9c8832 --- /dev/null +++ b/TIKI-100_emul-src/disk.c @@ -0,0 +1,339 @@ +/* disk.c V1.1.1 + * + * FD17xx emulering for TIKI-100_emul + * Copyright (C) Asbjørn Djupdal 2000-2001 + */ + +#include "TIKI-100_emul.h" +#include "protos.h" + +#include + +enum diskCommands { + NO_COMMAND, READ_SECT, READ_ADDR, WRITE_SECT, READ_TRACK, WRITE_TRACK +}; + +#define STEPIN 1 +#define STEPOUT -1 + +/* data for en diskettstasjon */ +struct diskParams { + byte *diskImage; /* diskettbilde */ + boolean active; /* om det er diskett i stasjonen */ + int tracks; /* antall spor */ + int sides; /* antall sider - 1 */ + int sectors; /* sektorer pr spor */ + int sectSize; /* bytes pr sektor */ + int realTrack; /* hvilken spor r/w-hode står over */ +}; + +/* protos */ + +static void setLights (void); +static void setLight (int drive, boolean status); + +/* variabler */ + +static struct diskParams params0; /* data for stasjon 0 */ +static struct diskParams params1; /* data for stasjon 1 */ +static struct diskParams *params; /* data for aktiv plate */ + +static int side = 0; /* gjeldende side (0 eller 1) */ +static boolean motOn = FALSE; /* om motor er på */ + +static byte track = 0; /* sporregister */ +static byte sector = 1; /* sektorregister */ +static byte data = 0; /* dataregister */ +static byte status = 0x20; /* statusregister */ + +static byte stepDir = STEPIN; /* verdi som legges til realTrack ved STEP */ +static byte command = NO_COMMAND; /* kommando som pågår */ +static long imageOffset = 0; /* offset inn i diskImage, ved r/w */ +static long endOffset = 0; /* hvor en r/w kommando skal avslutte */ +static int byteCount = 0; /* antall behandlede bytes ved READ_ADDR, WRITE_TRACK */ + + +/*****************************************************************************/ + +/* skriv til kontrollregister */ +void diskControl (byte value) { + /* restore */ + if ((value & 0xf0) == 0x00) { + track = 0; + params->realTrack = 0; + status = 0x24; + } + /* søk */ + else if ((value & 0xf0) == 0x10) { + if (data >= params->tracks) + status = 0x30 | (params->realTrack == 0 ? 0x04 : 0x00); + else { + params->realTrack = data; + track = params->realTrack; + status = 0x20 | (params->realTrack == 0 ? 0x04 : 0x00); + } + } + /* step */ + else if ((value & 0xe0) == 0x20) { + params->realTrack += stepDir; + if (params->realTrack >= params->tracks) params->realTrack = params->tracks - 1; + if (params->realTrack < 0) params->realTrack = 0; + status = 0x20 | (params->realTrack == 0 ? 0x04 : 0x00); + if (value & 0x10) + track = params->realTrack; + } + /* step inn */ + else if ((value & 0xe0) == 0x40) { + params->realTrack += STEPIN; + if (params->realTrack >= params->tracks) params->realTrack = params->tracks - 1; + stepDir = STEPIN; + status = 0x20; + if (value & 0x10) + track = params->realTrack; + } + /* step ut */ + else if ((value & 0xe0) == 0x60) { + params->realTrack += STEPOUT; + if (params->realTrack < 0) params->realTrack = 0; + stepDir = STEPOUT; + status = 0x20 | (params->realTrack == 0 ? 0x04 : 0x00); + if (value & 0x10) + track = params->realTrack; + } + /* les sektor */ + else if ((value & 0xe0) == 0x80) { + if (params->active) { + side = (value & 0x02) ? 1 : 0; + if ((sector > params->sectors) || (side > params->sides)) { + status = 0x10; + } + else { + if (value & 0x10) /* les resten av sektor i spor */ + endOffset = (((params->realTrack+1) << params->sides) + side) * /* BUG ?? */ + params->sectors * params->sectSize; + else /* les kun 1 sektor */ + endOffset = ((params->realTrack << params->sides) + side) * params->sectors * + params->sectSize + sector * params->sectSize; + imageOffset = ((params->realTrack << params->sides) + side) * params->sectors * + params->sectSize + (sector-1) * params->sectSize; + command = READ_SECT; + status = 0x02; + } + } else { + status = 0x80; + } + } + /* skriv sektor */ + else if ((value & 0xe0) == 0xa0) { + if (params->active) { + side = (value & 0x02) ? 1 : 0; + if ((sector > params->sectors) || (side > params->sides)) { + status = 0x10; + } + else { + if (value & 0x10) /* skriv resten av sektor i spor */ + endOffset = (((params->realTrack+1) << params->sides) + side) * /* BUG ?? */ + params->sectors * params->sectSize; + else /* skriv kun 1 sektor */ + endOffset = ((params->realTrack << params->sides) + side) * params->sectors * + params->sectSize + sector * params->sectSize; + imageOffset = ((params->realTrack << params->sides) + side) * params->sectors * + params->sectSize + (sector-1) * params->sectSize; + command = WRITE_SECT; + status = 0x02; + } + } else { + status = 0x80; + } + } + /* les adresse */ + else if ((value & 0xf8) == 0xc0) { + if (params->active) { + side = (value & 0x02) ? 1 : 0; + if (side > params->sides) { + status = 0x10; + } + else { + command = READ_ADDR; + byteCount = 0; + status = 0x02; + } + } else { + status = 0x80; + } + } + /* les spor -- ikke implementert */ + else if ((value & 0xf8) == 0xe0) { + status = 0x80; + } + /* skriv spor -- kun delvis implementert */ + else if ((value & 0xf8) == 0xf0) { + if (params->active) { + side = (value & 0x02) ? 1 : 0; + if (side > params->sides) { + status = 0x10; + } + else { + command = WRITE_TRACK; + byteCount = 0; + status = 0x02; + } + } else { + status = 0x80; + } + } + /* avbryt */ + else if ((value & 0xf0) == 0xd0) { + command = NO_COMMAND; + if (status & 0x01) { + status = status & 0xfe; + } else { + status = 0x20 | (params->realTrack == 0 ? 0x04 : 0x00); + } + } +} +/* skriv til sporregister */ +void newTrack (byte value) { + track = value; +} +/* skriv til sektorregister */ +void newSector (byte value) { + sector = value; +} +/* skriv til dataregister */ +void newDiskData (byte value) { + data = value; + switch (command) { + case WRITE_SECT: + params->diskImage[imageOffset++] = data; + if (imageOffset == endOffset) { + command = NO_COMMAND; + status = 0x00; + } + break; + case WRITE_TRACK: + /* kun delvis implementert */ + if (++byteCount > 6200) { + memset (¶ms->diskImage[((params->realTrack << params->sides) + side) * params->sectors * + params->sectSize], + 0xe5, params->sectors * params->sectSize); + command = NO_COMMAND; + status = 0x00; + } + break; + } +} +/* les statusregister */ +byte diskStatus (void) { + return status; +} +/* les sporregister */ +byte getTrack (void) { + return track; +} +/* les sektorregister */ +byte getSector (void) { + return sector; +} +/* les dataregister */ +byte getDiskData (void) { + switch (command) { + case READ_SECT: + data = params->diskImage[imageOffset++]; + if (imageOffset == endOffset) { + command = NO_COMMAND; + status = 0x00; + } + break; + case READ_ADDR: + switch (byteCount++) { + case 0: data = params->realTrack; break; + case 1: data = side; break; + case 2: data = 1; break; + case 3: switch (params->sectSize) { + case 128: data = 0; break; + case 256: data = 1; break; + case 512: data = 2; break; + case 1024: data = 3; break; + } + break; + case 4: data = 0; break; + case 5: data = 0; + command = NO_COMMAND; + status = 0x00; + break; + } + break; + case READ_TRACK: + /* ikke implementert */ + break; + } + return data; +} +/* sett disk 0 aktiv / inaktiv */ +void disk0 (boolean status) { + if (status) { + params = ¶ms0; + } else { + params = ¶ms1; + } + setLights(); +} +/* sett disk 1 aktiv / inaktiv */ +void disk1 (boolean status) { + if (status) { + params = ¶ms1; + } else { + params = ¶ms0; + } + setLights(); +} +/* skru motor på / av */ +void diskMotor (boolean status) { + motOn = status; + setLights(); +} +/* sett alle disklys */ +static void setLights (void) { + int disk = params == ¶ms0 ? 0 : 1; + int otherDisk = disk == 1 ? 0 : 1; + + if (motOn) { + setLight (disk, 1); + setLight (otherDisk, 0); + } else { + setLight (0, 0); + setLight (1, 0); + } +} +/* sett disk lys til gitt stasjon og status */ +static void setLight (int drive, boolean status) { + static int l[2] = {0, 0}; + + if (l[drive] != status) { + l[drive] = status; + diskLight (drive, status); + } +} +/* ny diskett i stasjon + * disk: Hvilken stasjon + * diskImage: Peker til diskettbilde-data + * resten er diskparametre + */ +void insertDisk (int drive, byte *dskImg, int trcks, int sds, + int sctrs, int sctSize) { + struct diskParams *dp = drive ? ¶ms1 : ¶ms0; + + dp->active = TRUE; + dp->diskImage = dskImg; + dp->tracks = trcks; + dp->sides = sds - 1; + dp->sectors = sctrs; + dp->sectSize = sctSize; +} +/* fjern diskett fra stasjon */ +void removeDisk (int drive) { + struct diskParams *dp = drive ? ¶ms1 :¶ms0; + + dp->active = FALSE; +} diff --git a/TIKI-100_emul-src/keyboard.c b/TIKI-100_emul-src/keyboard.c new file mode 100644 index 0000000..bfc36cf --- /dev/null +++ b/TIKI-100_emul-src/keyboard.c @@ -0,0 +1,39 @@ +/* keyboard.c V1.1.0 + * + * Tastatur emulering for TIKI-100_emul + * Copyright (C) Asbjørn Djupdal 2000-2001 + */ + +#include "TIKI-100_emul.h" +#include "protos.h" + +/* variabler */ + +static byte keyMatrix[12][8] = { + {KEY_CTRL, KEY_SHIFT, KEY_BRYT, KEY_CR, KEY_SPACE, KEY_NUMDIV, KEY_SLETT, KEY_NONE}, + {KEY_GRAFIKK, '1', KEY_ANGRE, 'a', '<', 'z', 'q', KEY_LOCK}, + {'2', 'w', 's', 'x', '3', 'e', 'd', 'c'}, + {'4', 'r', 'f', 'v', '5', 't', 'g', 'b'}, + {'6', 'y', 'h', 'n', '7', 'u', 'j', 'm'}, + {'8', 'i', 'k', ',', '9', 'o', 'l', '.'}, + {'0', 'p', (byte)'ø', '-', '+', (byte)'å', (byte)'æ', KEY_HJELP}, + {'@', '^', '\'', KEY_LEFT, KEY_UTVID, KEY_F1, KEY_F4, KEY_PGUP}, + {KEY_F2, KEY_F3, KEY_F5, KEY_F6, KEY_UP, KEY_PGDOWN, KEY_TABLEFT, KEY_DOWN}, + {KEY_NUMPLUS, KEY_NUMMINUS, KEY_NUMMULT, KEY_NUM7, KEY_NUM8, KEY_NUM9, KEY_NUMPERCENT, KEY_NUMEQU}, + {KEY_NUM4, KEY_NUM5, KEY_NUM6, KEY_TABRIGHT, KEY_NUM1, KEY_NUM0, KEY_NUMDOT, KEY_NONE}, + {KEY_HOME, KEY_RIGHT, KEY_NUM2, KEY_NUM3, KEY_ENTER, KEY_NONE, KEY_NONE, KEY_NONE}, +}; + +static int column = 0; + +/*****************************************************************************/ + +/* skriv til tastatur-register */ +void resetKeyboard (void) { + column = 0; +} +/* les tastatur-register */ +byte readKeyboard (void) { + return testKey (keyMatrix[column++]); +} + diff --git a/TIKI-100_emul-src/mem.c b/TIKI-100_emul-src/mem.c new file mode 100644 index 0000000..214f8ea --- /dev/null +++ b/TIKI-100_emul-src/mem.c @@ -0,0 +1,203 @@ +/* mem.c V1.1.0 + * + * Tar seg av minne-håndtering for TIKI-100_emul + * Copyright (C) Asbjørn Djupdal 2000-2001 + */ + +#include "TIKI-100_emul.h" +#include "protos.h" +#include + +#define ROM_FILENAME "tiki.rom" + +/* variabler */ + +byte ram[64 * 1024]; /* hoved minne */ +extern byte gfxRam[]; /* grafikk minne */ +byte rom[16 * 1024]; /* monitor eprom, vanligvis bare 8k men støtter 16k */ + +static boolean gfxIn; /* TRUE hvis grafikkram er synlig for prosessor */ +static boolean romIn; /* TRUE hvis rom er synlig for prosessor */ + +/*****************************************************************************/ + +/* må kalles før emulering starter */ +int initMem() { + FILE *fp; + + /* hent ROM */ + if ((fp = fopen (ROM_FILENAME, "rb"))) { + fread (rom, 1, 16 * 1024, fp); + fclose (fp); + OutZ80 (0x1c, 0x00); + return TRUE; + } + return FALSE; +} +/* skriv til minnet */ +void WrZ80 (register word addr, register byte value) { + if (gfxIn && !(addr & 0x8000)) { + if (gfxRam[addr] != value) { + gfxRam[addr] = value; + drawByte (addr); + } + } + else if (romIn && !(addr & 0xc000)) { + return; + } + else { + ram[addr] = value; + } +} +/* les fra minnet */ +byte RdZ80 (register word addr) { + if (gfxIn && !(addr & 0x8000)) { + return gfxRam[addr]; + } + if (romIn && !(addr & 0xc000)) { + return rom[addr]; + } + return ram[addr]; +} +/* skriv til i/o-port */ +void OutZ80 (register word port, register byte value) { + static int lock = 0; + static int gfx = 0; + + switch (port) { + case 0x00: /* tastatur */ + case 0x01: + case 0x02: + case 0x03: + resetKeyboard(); + break; + case 0x04: /* serie A data */ + newSerAData (value); + break; + case 0x05: /* serie B data */ + newSerBData (value); + break; + case 0x06: /* serie A styreord */ + serAControl (value); + break; + case 0x07: /* serie B styreord */ + serBControl (value); + break; + case 0x08: /* parallell A data */ + newParAData (value); + break; + case 0x09: /* parallell B data */ + newParBData (value); + break; + case 0x0a: /* parallell A styreord */ + parAControl (value); + break; + case 0x0b: /* parallell B styreord */ + parBControl (value); + break; + case 0x0c: /* grafikk-modus */ + case 0x0d: + case 0x0e: + case 0x0f: + newMode (value); + break; + case 0x10: /* disk styreord */ + diskControl (value); + break; + case 0x11: /* disk spornummer */ + newTrack (value); + break; + case 0x12: /* disk sektorregister */ + newSector (value); + break; + case 0x13: /* disk dataregister */ + newDiskData (value); + break; + case 0x14: /* farge-register */ + case 0x15: + newColor (value); + break; + case 0x16: /* lyd-scroll peker */ + soundReg (value); + break; + case 0x17: /* lyd-scroll data */ + soundData (value); + break; + case 0x18: /* ctc kanal 0 */ + writeCtc0 (value); + break; + case 0x19: /* ctc kanal 1 */ + writeCtc1 (value); + break; + case 0x1a: /* ctc kanal 2 */ + writeCtc2 (value); + break; + case 0x1b: /* ctc kanal 3 */ + writeCtc3 (value); + break; + case 0x1c: /* system-register */ + case 0x1d: + case 0x1e: + case 0x1f: + disk0 (value & 1); + disk1 (value & 2); + romIn = !(value & 4); + gfxIn = value & 8; + if (gfx != !(value & 32)) { + grafikkLight (!(value & 32)); + gfx = !(value & 32); + } + diskMotor (value & 64); + if (lock != !(value & 128)) { + lockLight (!(value & 128)); + lock = !(value & 128); + } + break; + } +} +/* les fra i/o-port */ +byte InZ80 (register word port) { + switch (port) { + case 0x00: /* tastatur */ + case 0x01: + case 0x02: + case 0x03: + return readKeyboard(); + case 0x04: /* serie A data */ + return serAData(); + case 0x05: /* serie B data */ + return serBData(); + case 0x06: /* serie A status */ + return serAStatus(); + case 0x07: /* serie B status */ + return serBStatus(); + case 0x08: /* parallell A data */ + return parAData(); + case 0x09: /* parallell B data */ + return parBData(); + case 0x0a: /* parallell A status */ + return parAStatus(); + case 0x0b: /* parallell B status */ + return parBStatus(); + case 0x10: /* disk status */ + return diskStatus(); + case 0x11: /* disk spornummer */ + return getTrack(); + case 0x12: /* disk sektorregister */ + return getSector(); + case 0x13: /* disk dataregister */ + return getDiskData(); + case 0x17: /* lyd-scroll data */ + return getSoundData(); + case 0x18: /* ctc kanal 0 */ + return readCtc0(); + case 0x19: /* ctc kanal 1 */ + return readCtc1(); + case 0x1a: /* ctc kanal 2 */ + return readCtc2(); + case 0x1b: /* ctc kanal 3 */ + return readCtc3(); + default: + return 0xff; + } +} diff --git a/TIKI-100_emul-src/parallel.c b/TIKI-100_emul-src/parallel.c new file mode 100644 index 0000000..8293836 --- /dev/null +++ b/TIKI-100_emul-src/parallel.c @@ -0,0 +1,40 @@ +/* parallel.c V1.1.0 + * + * Z80 PIO emulering for TIKI-100_emul + * Copyright (C) Asbjørn Djupdal 2001 + */ + +#include "TIKI-100_emul.h" +#include "protos.h" + +/*****************************************************************************/ + +/* skriv til dataregister A */ +void newParAData (byte value) { + printChar (value); +} +/* skriv til dataregister B */ +void newParBData (byte value) { +} +/* skriv til kontrollregister A */ +void parAControl (byte value) { +} +/* skriv til kontrollregister B */ +void parBControl (byte value) { +} +/* les dataregister A */ +byte parAData (void) { + return 0; +} +/* les dataregister B */ +byte parBData (void) { + return 0x10; /* Ack på, busy og no-paper av */ +} +/* les statusregister A */ +byte parAStatus (void) { + return 0; +} +/* les statusregister B */ +byte parBStatus (void) { + return 0; +} diff --git a/TIKI-100_emul-src/plater/t200.dsk b/TIKI-100_emul-src/plater/t200.dsk new file mode 100644 index 0000000..aaf71cf Binary files /dev/null and b/TIKI-100_emul-src/plater/t200.dsk differ diff --git a/TIKI-100_emul-src/plater/t400.dsk b/TIKI-100_emul-src/plater/t400.dsk new file mode 100644 index 0000000..68a30c7 Binary files /dev/null and b/TIKI-100_emul-src/plater/t400.dsk differ diff --git a/TIKI-100_emul-src/plater/t800.dsk b/TIKI-100_emul-src/plater/t800.dsk new file mode 100644 index 0000000..cbeb116 Binary files /dev/null and b/TIKI-100_emul-src/plater/t800.dsk differ diff --git a/TIKI-100_emul-src/plater/t90.dsk b/TIKI-100_emul-src/plater/t90.dsk new file mode 100644 index 0000000..a2a2692 Binary files /dev/null and b/TIKI-100_emul-src/plater/t90.dsk differ diff --git a/TIKI-100_emul-src/plater/tiko_kjerne_v4.01.dsk b/TIKI-100_emul-src/plater/tiko_kjerne_v4.01.dsk new file mode 100644 index 0000000..fc94f0a Binary files /dev/null and b/TIKI-100_emul-src/plater/tiko_kjerne_v4.01.dsk differ diff --git a/TIKI-100_emul-src/protos.h b/TIKI-100_emul-src/protos.h new file mode 100644 index 0000000..7b4f6a1 --- /dev/null +++ b/TIKI-100_emul-src/protos.h @@ -0,0 +1,124 @@ +/* protos.h V1.1.0 + * + * Prototyper for funksjoner som kun skal brukes av den systemuavhengige koden. + * Resten av prototypene er i TIKI-100_emul.h + * Copyright (C) Asbjørn Djupdal 2000-2001 + */ + +#ifndef PROTOS_H +#define PROTOS_H + +/*****************************************************************************/ +/* ctc.c */ +/*****************************************************************************/ + +/* skriv til ctc-kontrollregister */ +void writeCtc0 (byte value); +void writeCtc1 (byte value); +void writeCtc2 (byte value); +void writeCtc3 (byte value); +/* les ctc-register */ +byte readCtc0 (void); +byte readCtc1 (void); +byte readCtc2 (void); +byte readCtc3 (void); +/* må kalles regelmessig for å oppdatere tellere og sjekke om interrupt skal genereres */ +void updateCTC (int cycles); +/* returnerer antall sykler mellom hver ut puls på gitt ctc-kanal */ +int getCtc (int c); + +/*****************************************************************************/ +/* disk.c */ +/*****************************************************************************/ + +/* skriv til disk-register */ +void diskControl (byte value); +void newTrack (byte value); +void newSector (byte value); +void newDiskData (byte value); +/* les disk-register */ +byte diskStatus (void); +byte getTrack (void); +byte getSector (void); +byte getDiskData (void); +/* sett stasjon aktiv / inaktiv */ +void disk0 (boolean status); +void disk1 (boolean status); +/* skru motor på / av */ +void diskMotor (boolean status); + +/*****************************************************************************/ +/* keyboard.c */ +/*****************************************************************************/ + +/* skriv til tastatur-register */ +void resetKeyboard (void); +/* les tastatur-register */ +byte readKeyboard (void); + +/*****************************************************************************/ +/* mem.c */ +/*****************************************************************************/ + +/* må kalles før emulering starter */ +int initMem(); + +/*****************************************************************************/ +/* sound.c */ +/*****************************************************************************/ + +/* skriv til lyd-register */ +void soundReg (byte value); +void soundData (byte value); +/* les lyd-register */ +byte getSoundData (void); + +/*****************************************************************************/ +/* video.c */ +/*****************************************************************************/ + +/* tegn gitt byte i grafikkminne til skjerm */ +void drawByte (word addr); +/* skriv til grafikk-sregister */ +void newMode (byte mode); +void newColor (byte color); +/* ny offset (dvs scroll) */ +void newOffset (byte newOffset); + +/*****************************************************************************/ +/* serial.c */ +/*****************************************************************************/ + +/* skriv til data-register */ +void newSerAData (byte value); +void newSerBData (byte value); +/* skriv til kontroll-register */ +void serAControl (byte value); +void serBControl (byte value); +/* les data-register */ +byte serAData (void); +byte serBData (void); +/* les status-register */ +byte serAStatus (void); +byte serBStatus (void); +/* rekalkuler buad-rate (nye ctc-verdier) */ +void recalcBaud (void); + +/*****************************************************************************/ +/* parallel.c */ +/*****************************************************************************/ + +/* skriv til data-register */ +void newParAData (byte value); +void newParBData (byte value); +/* skriv til kontroll-register */ +void parAControl (byte value); +void parBControl (byte value); +/* les data-register */ +byte parAData (void); +byte parBData (void); +/* les status-register */ +byte parAStatus (void); +byte parBStatus (void); + +#endif diff --git a/TIKI-100_emul-src/serial.c b/TIKI-100_emul-src/serial.c new file mode 100644 index 0000000..b2338fc --- /dev/null +++ b/TIKI-100_emul-src/serial.c @@ -0,0 +1,206 @@ +/* serial.c V1.1.0 + * + * Z80 DART emulering for TIKI-100_emul + * Copyright (C) Asbjørn Djupdal 2001 + */ + +#include "TIKI-100_emul.h" +#include "protos.h" + +enum rxiType { + RXI_NONE, RXI_FIRST, RXI_ALL_PAR_CHANGE_VEC, RXI_ALL_PAR_DONT_CHANGE_VEC +}; + +/* protos */ + +static void serControl (byte value, struct serParams *sParams); +static byte serStatus (struct serParams *sParams); + +/* variabler */ + +extern Z80 cpu; /* må ha tilgang til cpu for å gjøre interrupt */ + +static boolean st28b = FALSE; /* jumper i TIKI-100 */ + +/* parametre for de to seriekanalene */ +static struct serParams serAParams; +static struct serParams serBParams; + +static byte intVector = 0; /* interrupt vektor, delt mellom kanalene */ + +/*****************************************************************************/ + +/* skriv til dataregister A */ +void newSerAData (byte value) { + if (serAParams.txe) { + sendChar (1, value); + } +} +/* skriv til dataregister B */ +void newSerBData (byte value) { + if (serBParams.txe) { + sendChar (0, value); + } +} +/* skriv til kontrollregister A */ +void serAControl (byte value) { + serControl (value, &serAParams); +} +/* skriv til kontrollregister B */ +void serBControl (byte value) { + serControl (value, &serBParams); +} +static void serControl (byte value, struct serParams *sParams) { + switch (sParams->regPtr) { + case 0: /* Command Register */ + sParams->regPtr = value & 7; + /* nullstill status interrupt */ + /* nullstill hele kanalen */ + if ((value & 0x38) == 0x18) { + sParams->newChar = FALSE; + } + /* Sett interrupt når neste tegn mottas */ + if ((value & 0x38) == 0x20) { + sParams->newChar = FALSE; + } + /* nullstill senderinterrupt */ + /* nullstill feilmelding */ + /* retur fra interrupt */ + break; + case 1: /* Transmit/Receive Interrupt */ + sParams->regPtr = 0; + sParams->exi = value & 0x01; + sParams->txi = value & 0x02; + sParams->sav = value & 0x04; + switch (value & 0x18) { + case 0x00: sParams->rxi = RXI_NONE; break; + case 0x08: sParams->rxi = RXI_FIRST; break; + case 0x10: sParams->rxi = RXI_ALL_PAR_CHANGE_VEC; break; + case 0x18: sParams->rxi = RXI_ALL_PAR_DONT_CHANGE_VEC; break; + } + break; + case 2: /* Interrupt Vector */ + sParams->regPtr = 0; + intVector = value; + break; + case 3: /* Receive Parameters */ + sParams->regPtr = 0; + sParams->rxe = value & 0x01; + sParams->ae = value & 0x20; + switch (value & 0xc0) { + case 0x00: sParams->receiveBits = 5; break; + case 0x40: sParams->receiveBits = 7; break; + case 0x80: sParams->receiveBits = 6; break; + case 0xc0: sParams->receiveBits = 8; break; + } + break; + case 4: /* Transmit/Receive Misc Parameters */ + sParams->regPtr = 0; + if (!(value & 0x01)) { + sParams->parity = PAR_NONE; + } else { + sParams->parity = value & 0x02 ? PAR_EVEN : PAR_ODD; + } + switch (value & 0x0c) { + case 0x00: /* ugyldig */ + case 0x04: sParams->stopBits = ONE_SB; break; + case 0x08: sParams->stopBits = ONE_PT_FIVE_SB; break; + case 0x0c: sParams->stopBits = TWO_SB; break; + } + switch (value & 0xc0) { + case 0x00: sParams->clkDiv = 1; break; + case 0x40: sParams->clkDiv = 16; break; + case 0x80: sParams->clkDiv = 32; break; + case 0xc0: sParams->clkDiv = 64; break; + } + break; + case 5: /* Transmit Parameters */ + sParams->regPtr = 0; + /* rts */ + sParams->txe = value & 0x08; + /* break */ + switch (value & 0xc0) { + case 0x00: sParams->sendBits = 5; break; + case 0x40: sParams->sendBits = 7; break; + case 0x80: sParams->sendBits = 6; break; + case 0xc0: sParams->sendBits = 8; break; + } + break; + } + recalcBaud(); +} +/* rekalkuler baud-rate (nye ctc-verdier) */ +void recalcBaud (void) { + int ctc0 = getCtc (0); + int ctc1 = getCtc (1); + int ctc2 = getCtc (2); + + if ((ctc0 != 0) && ((st28b ? ctc2 : ctc1) != 0) && (serAParams.clkDiv != 0) && (serBParams.clkDiv != 0)) { + serAParams.baud = 4000000/ctc0/serAParams.clkDiv; + serBParams.baud = 4000000/(st28b ? ctc2 : ctc1)/serBParams.clkDiv; + setParams (&serBParams, &serAParams); + } +} +/* les dataregister A */ +byte serAData (void) { + if (serAParams.rxa) { + serAParams.rxa = FALSE; + return getChar (1); + } + return 0; +} +/* les dataregister B */ +byte serBData (void) { + if (serBParams.rxa) { + serBParams.rxa = FALSE; + return getChar (0); + } + return 0; +} +/* les statusregister A */ +byte serAStatus (void) { + return serStatus (&serAParams); +} +/* les statusregister B */ +byte serBStatus (void) { + return serStatus (&serBParams); +} +static byte serStatus (struct serParams *sParams) { + byte returnValue = 0; + + switch (sParams->regPtr) { + case 0: returnValue = 0x34 | (sParams->rxa ? 1 : 0); + break; + case 1: returnValue = 0x01; + break; + case 2: returnValue = intVector; + break; + } + sParams->regPtr = 0; + return returnValue; +} +/* sett jumper ST28b */ +void setST28b (boolean status) { + st28b = status; + recalcBaud(); +} +/* nytt tegn tilgjengelig */ +void charAvailable (int port) { + struct serParams *sParams = port ? &serAParams : &serBParams; + int channel = port ? 0 : 1; + + sParams->rxa = TRUE; + sParams->newChar = TRUE; + + if (sParams->sav) { + intVector = (intVector & 0xf1) | (channel ? 0 : 8) | 4; + } + switch (sParams->rxi) { + case RXI_FIRST: if (!(sParams->newChar)) IntZ80 (&cpu, intVector); + break; + case RXI_ALL_PAR_CHANGE_VEC: + case RXI_ALL_PAR_DONT_CHANGE_VEC: + IntZ80 (&cpu, intVector); + break; + } +} diff --git a/TIKI-100_emul-src/sound.c b/TIKI-100_emul-src/sound.c new file mode 100644 index 0000000..f338d22 --- /dev/null +++ b/TIKI-100_emul-src/sound.c @@ -0,0 +1,30 @@ +/* sound.c V1.1.0 + * + * AY-3-8912 emulering for TIKI-100_emul + * Copyright (C) Asbjørn Djupdal 2000-2001 + */ + +#include "TIKI-100_emul.h" +#include "protos.h" + +/* variabler */ + +static byte reg = 0; + +/*****************************************************************************/ + +/* skriv til kontrollregister */ +void soundReg (byte value) { + reg = value; +} +/* skriv til dataregister */ +void soundData (byte value) { + switch (reg) { + case 14: newOffset (value); break; + } +} +/* les dataregister */ +byte getSoundData (void) { + return 0xff; +} + diff --git a/TIKI-100_emul-src/tiki.rom b/TIKI-100_emul-src/tiki.rom new file mode 100644 index 0000000..baf2f58 Binary files /dev/null and b/TIKI-100_emul-src/tiki.rom differ diff --git a/TIKI-100_emul-src/unix.c b/TIKI-100_emul-src/unix.c new file mode 100644 index 0000000..0b6ec7e --- /dev/null +++ b/TIKI-100_emul-src/unix.c @@ -0,0 +1,1135 @@ +/* unix.c V1.1.1 + * + * Unix (med X11) systemspesifikk kode for TIKI-100_emul + * Copyright (C) Asbjørn Djupdal 2001 + */ + +#include "TIKI-100_emul.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#ifndef FIONREAD +#include /* antar at FIONREAD er definert i sys/filio.h */ +#endif + +#include +#include +#include +#include + +#define STATUSBAR_HEIGHT 19 + +/* protos */ +int main (int argc, char *argv[]); +static void update (int x, int y, int w, int h); +static void createStatusBar (void); +static byte keysymToTikikey (KeySym keysym); +static void commandline (void); +static void readDiskImage (int drive, char *filename); +static void setParam (int portfd, struct serParams *params); +static void setPrintCmd (char *p); +static void setPrintFile (char *p); + +/* variabler */ + +static byte *dsk[2] = {NULL, NULL}; +static int dsksize[2] = {0, 0}; +static int resolution = MEDRES; +static byte pressedKeys[256]; +static boolean updateWindow = FALSE; +static unsigned int xmin = (unsigned)~0; +static unsigned int ymin = (unsigned)~0; +static unsigned int xmax = 0; +static unsigned int ymax = 0; +static boolean scanlines; +static boolean slowDown; +static int width[3]; +static int height[3]; +static int times40; +static int times80; +static byte *screen; +static FILE *printCmd = 0; +static FILE *printFile = 0; +static int port1 = 0; +static int port2 = 0; +static boolean lock = FALSE; +static boolean grafikk = FALSE; +static boolean disk[2] = {FALSE, FALSE}; +static boolean dyn_cmap; +static Colormap default_cmap; +static unsigned long pixels[16]; +static unsigned long blackpix, whitepix, backpix, diodepix; +static Display *display; +static Window mainwindow; +static Pixmap mainpixmap; +static GC colorGC[16]; +static GC blackGC, backGC, diodeGC; +static XrmDatabase options_db = NULL; +static XSizeHints xsh; + +static XrmOptionDescRec options[] = { + {"-display", "*display", XrmoptionSepArg, NULL}, + {"-d", "*display", XrmoptionSepArg, NULL}, + {"-geometry", "*geometry", XrmoptionSepArg, NULL}, + {"-g", "*geometry", XrmoptionSepArg, NULL}, + {"-diska", "*diska", XrmoptionSepArg, NULL}, + {"-diskb", "*diskb", XrmoptionSepArg, NULL}, + {"-bevarforhold", "*bevarforhold", XrmoptionNoArg, "on"}, + {"-ikkebevarforhold", "*bevarforhold", XrmoptionNoArg, "off"}, + {"-40x", "*40x", XrmoptionSepArg, NULL}, + {"-80x", "*80x", XrmoptionSepArg, NULL}, + {"-begrens", "*begrens", XrmoptionNoArg, "on"}, + {"-ikkebegrens", "*begrens", XrmoptionNoArg, "off"}, + {"-port1", "*port1", XrmoptionSepArg, NULL}, + {"-port2", "*port2", XrmoptionSepArg, NULL}, + {"-pk", "*pk", XrmoptionSepArg, NULL}, + {"-pf", "*pf", XrmoptionSepArg, NULL}, + {"-st28b", "*st28b", XrmoptionNoArg, "on"}, + {"-ikkest28b", "*st28b", XrmoptionNoArg, "off"} +}; + +static int num_opts = (sizeof options / sizeof options[0]); + +typedef struct KeyConv { + byte tikikey; + KeySym keysym; +} KeyConv; + +/* Tabell som konverterer X11-keysym til TIKI-100 tasteverdier */ +static const KeyConv keyConvTable[] = { + {KEY_CTRL, XK_Control_L}, {KEY_CTRL, XK_Control_R}, {KEY_SHIFT, XK_Shift_L}, + {KEY_SHIFT, XK_Shift_R}, {KEY_BRYT, XK_Break}, {KEY_BRYT, XK_F10}, + {KEY_CR, XK_Return}, {KEY_SPACE, XK_space}, {KEY_SLETT, XK_BackSpace}, + {KEY_SLETT, XK_Delete}, {KEY_GRAFIKK, XK_F8}, {KEY_ANGRE, XK_Redo}, + {KEY_ANGRE, XK_F9}, {KEY_LOCK, XK_Caps_Lock}, {KEY_LOCK, XK_Shift_Lock}, + {KEY_LOCK, XK_F7}, {KEY_HJELP, XK_Help}, {KEY_HJELP, XK_F11}, + {KEY_LEFT, XK_Left}, {KEY_UTVID, XK_Insert}, {KEY_UTVID, XK_F12}, + {KEY_F1, XK_F1}, {KEY_F4, XK_F4}, {KEY_RIGHT, XK_Right}, + {KEY_F2, XK_F2}, {KEY_F3, XK_F3}, {KEY_F5, XK_F5}, + {KEY_F6, XK_F6}, {KEY_DOWN, XK_Down}, {KEY_PGUP, XK_Page_Up}, + {KEY_PGDOWN, XK_Page_Down}, {KEY_UP, XK_Up}, {KEY_HOME, XK_Home}, + {KEY_TABLEFT, XK_Prior}, {KEY_TABRIGHT, XK_Tab}, {KEY_TABRIGHT, XK_Next}, + {KEY_NUMDIV, XK_KP_Divide}, {KEY_NUMPLUS, XK_KP_Add}, {KEY_NUMMINUS, XK_KP_Subtract}, + {KEY_NUMMULT, XK_KP_Multiply}, {KEY_NUMPERCENT, XK_percent}, {KEY_NUMEQU, XK_KP_Equal}, + {KEY_ENTER, XK_KP_Enter}, {KEY_NUM0, XK_KP_0}, {KEY_NUM1, XK_KP_1}, + {KEY_NUM2, XK_KP_2}, {KEY_NUM3, XK_KP_3}, {KEY_NUM4, XK_KP_4}, + {KEY_NUM5, XK_KP_5}, {KEY_NUM6, XK_KP_6}, {KEY_NUM7, XK_KP_7}, + {KEY_NUM8, XK_KP_8}, {KEY_NUM9, XK_KP_9}, {KEY_NUMDOT, XK_KP_Separator}, + {KEY_NUMDOT, XK_KP_Decimal}, {(byte)'a', XK_a}, {(byte)'b', XK_b}, + {(byte)'c', XK_c}, {(byte)'d', XK_d}, {(byte)'e', XK_e}, + {(byte)'f', XK_f}, {(byte)'g', XK_g}, {(byte)'h', XK_h}, + {(byte)'i', XK_i}, {(byte)'j', XK_j}, {(byte)'k', XK_k}, + {(byte)'l', XK_l}, {(byte)'m', XK_m}, {(byte)'n', XK_n}, + {(byte)'o', XK_o}, {(byte)'p', XK_p}, {(byte)'q', XK_q}, + {(byte)'r', XK_r}, {(byte)'s', XK_s}, {(byte)'t', XK_t}, + {(byte)'u', XK_u}, {(byte)'v', XK_v}, {(byte)'w', XK_w}, + {(byte)'x', XK_x}, {(byte)'y', XK_y}, {(byte)'z', XK_z}, + {(byte)'1', XK_1}, {(byte)'2', XK_2}, {(byte)'3', XK_3}, + {(byte)'4', XK_4}, {(byte)'5', XK_5}, {(byte)'6', XK_6}, + {(byte)'7', XK_7}, {(byte)'8', XK_8}, {(byte)'9', XK_9}, + {(byte)'0', XK_0}, {(byte)'<', XK_less}, {(byte)',', XK_comma}, + {(byte)'.', XK_period}, {(byte)'-', XK_minus}, {(byte)'æ', XK_ae}, + {(byte)'ø', XK_oslash}, {(byte)'å', XK_aring}, {(byte)'\'', XK_apostrophe}, + {(byte)'^', XK_asciicircum}, {(byte)'+', XK_plus}, {(byte)'@', XK_at} +}; + +/*****************************************************************************/ + +int main (int argc, char *argv[]) { + char *resType; /* for resourcekall */ + XrmValue resValue; /* -- " -- */ + XrmDatabase cline_db = NULL; + + XrmInitialize(); + + /* parse kommandolinjeopsoner */ + XrmParseCommand (&cline_db, options, num_opts, "tikiemul", &argc, argv); + + /* feil i argumenter */ + if (argc > 1) { + printf ("TIKI-100_emul V1.1.1 brukes:\n" + " tikiemul [-opsjoner...]\n" + "\n" + "Opsjoner:\n" + " -display displaynavn X-server som skal benyttes\n" + " -d displaynavn Forkortelse for den over\n" + " -geometry geom Vindusposisjon\n" + " -g geom Forkortelse for den over\n" + " -diska diskettfilnavn Diskettfil i stasjon a\n" + " -diskb diskettfilnavn Diskettfil i stasjon b\n" + " -bevarforhold Emulatorvindu formlik TIKI-100 skjerm\n" + " -ikkebevarforhold Negasjonen av den over\n" + " -40x forstørrelsesfaktor Forstørring av 40-modus vindu\n" + " -80x forstørrelsesfaktor Forstørring av 80-modus vindu\n" + " -begrens Begrens hastighet til vanlig TIKI-hastighet\n" + " -ikkebegrens Negasjonen av den over\n" + " -port1 devicenavn Skru på serieport P1\n" + " -port2 devicenavn Skru på serieport P2\n" + " -pk utskriftskommando Send utskrift til kommando\n" + " -pf utskriftsfil Send utskrift til fil\n" + " -st28b Sett bøyle ST 28 b\n" + " -ikkest28b Negasjonen av den over\n" + "\n" + "Underveis i emulering kan du trykke på Escapetasten for å gå inn i\n" + "kommandomodus. Kommandoen 'hjelp' gir en liste over gyldige kommandoer.\n" + "\n"); + exit (1); + } + + /* åpne display */ + XrmGetResource (cline_db, "tikiemul.display", "Tikiemul.display", &resType, &resValue); + if ((display = XOpenDisplay (resValue.addr)) == NULL) { + fprintf (stderr, "Kan ikke åpne display %s\n", XDisplayName (resValue.addr)); + exit (1); + } + + { /* hent defaults fra server */ + char *xrms; + + xrms = XResourceManagerString (display); + if (xrms != NULL) { + options_db = XrmGetStringDatabase (xrms); + XrmMergeDatabases (cline_db, &options_db); + } else { + options_db = cline_db; + } + } + + /* finn geometry */ + XrmGetResource (options_db, "tikiemul.geometry", "Tikiemul.geometry", &resType, &resValue); + XGeometry (display, DefaultScreen (display), resValue.addr, "+0+0", 1, + 1, 1, 0, 0, &(xsh.x), &(xsh.y), &(xsh.width), &(xsh.height)); + + /* skal forhold bevares? */ + XrmGetResource (options_db, "tikiemul.bevarforhold", "Tikiemul.bevarforhold", + &resType, &resValue); + scanlines = FALSE; + if (resValue.addr) { + if (!strcmp (resValue.addr, "on")) { + scanlines = TRUE; + } + } + + /* finn forstørring og vindusstørrelse */ + XrmGetResource (options_db, "tikiemul.40x", "Tikiemul.40x", &resType, &resValue); + if (resValue.addr) times40 = atoi (resValue.addr); + if (times40 > 4) times40 = 4; + if (times40 < 1) times40 = 1; + width[0] = 256 * times40; + height[0] = 256 * times40; + XrmGetResource (options_db, "tikiemul.80x", "Tikiemul.80x", &resType, &resValue); + if (resValue.addr) times80 = atoi (resValue.addr); + if (times80 > 2) times80 = 2; + if (times80 < 1) times80 = 1; + width[1] = 512 * times80; + height[1] = 256 * times80 * (scanlines ? 2 : 1); + width[2] = 1024; + height[2] = 256 * (scanlines ? 4 : 1); + + /* skal hastighet begrenses? */ + XrmGetResource (options_db, "tikiemul.begrens", "Tikiemul.begrens", &resType, &resValue); + slowDown = TRUE; + if (resValue.addr) { + if (!strcmp (resValue.addr, "off")) { + slowDown = FALSE; + } + } + + /* hent inn eventuelle diskfiler */ + XrmGetResource (options_db, "tikiemul.diska", "Tikiemul.diska", &resType, &resValue); + if (resValue.addr) readDiskImage (0, resValue.addr); + XrmGetResource (options_db, "tikiemul.diskb", "Tikiemul.diskb", &resType, &resValue); + if (resValue.addr) readDiskImage (1, resValue.addr); + + /* sett opp farger */ + default_cmap = DefaultColormap (display, DefaultScreen (display)); + { + int visclass = DefaultVisual (display, DefaultScreen (display))->class; + + whitepix = WhitePixel (display, DefaultScreen (display)); + blackpix = BlackPixel (display, DefaultScreen (display)); + { /* farger for statusbar */ + XColor color; + XColor exact; + + if (!XAllocNamedColor (display, default_cmap, "grey80", &exact, &color)) { + backpix = blackpix; + } else { + backpix = color.pixel; + } + if (!XAllocNamedColor (display, default_cmap, "green", &exact, &color)) { + diodepix = whitepix; + } else { + diodepix = color.pixel; + } + } + + if (visclass == PseudoColor || visclass == DirectColor) { + /* dynamisk colormap - skaff r/w-fargeceller */ + if (!XAllocColorCells (display, default_cmap, False, NULL, 0, pixels, 16)) { + printf ("For få ledige fargeceller\n"); + free (dsk[0]); + free (dsk[1]); + XCloseDisplay (display); + exit (1); + } + dyn_cmap = TRUE; + } else if (visclass == TrueColor || visclass == StaticColor) { + /* statisk colormap - skaff ny pixel hver gang farge forandres */ + int i; + + if (!(screen = malloc (1024 * 256))) { + fprintf (stderr, "Ikke nok minne\n"); + free (dsk[0]); + free (dsk[1]); + XCloseDisplay (display); + exit (1); + } + memset (screen, 0, 1024 * 256); + + for (i = 0; i < 16; i++) { + pixels[i] = blackpix; + } + dyn_cmap = FALSE; + } else { + /* svart/hvitt display, kan ikke brukes */ + fprintf (stderr, "Display ikke tilstrekkelig!\n"); + free (dsk[0]); + free (dsk[1]); + XCloseDisplay (display); + exit (1); + } + } + + { /* graphics context, en for hver farge */ + int i; + XGCValues gcv; + + gcv.foreground = blackpix; + blackGC = XCreateGC (display, DefaultRootWindow (display), + GCForeground | GCBackground, &gcv); + gcv.foreground = backpix; + backGC = XCreateGC (display, DefaultRootWindow (display), + GCForeground | GCBackground, &gcv); + gcv.foreground = diodepix; + diodeGC = XCreateGC (display, DefaultRootWindow (display), + GCForeground | GCBackground, &gcv); + + for (i = 0; i < 16; i++) { + gcv.foreground = pixels[i]; + colorGC[i] = XCreateGC (display, DefaultRootWindow (display), + GCForeground | GCBackground, &gcv); + } + } + + /* lag vindu */ + mainwindow = + XCreateSimpleWindow (display, DefaultRootWindow (display), + xsh.x, xsh.y, width[1], height[1] + STATUSBAR_HEIGHT, + 1, pixels[0], pixels[0]); + + { /* gi hint til window manager */ + XWMHints xwmh; + + xsh.flags = (PPosition | PSize | PMinSize | PMaxSize); + xsh.width = width[1]; + xsh.height = height[1] + STATUSBAR_HEIGHT; + xsh.min_width = xsh.width; + xsh.min_height = xsh.height; + xsh.max_width = xsh.width; + xsh.max_height = xsh.height; + XSetStandardProperties (display, mainwindow, "tikiemul", "tikiemul", None, + argv, argc, &xsh); + xwmh.flags = (InputHint | StateHint); + xwmh.input = True; + xwmh.initial_state = NormalState; + XSetWMHints (display, mainwindow, &xwmh); + } + + { /* lag pixmap. Alt tegnes til pixmap, kopieres til vindu hver loopEmul() */ + int maxheight = height[0]; + + if (height[1] > maxheight) maxheight = height[1]; + if (height[2] > maxheight) maxheight = height[2]; + + mainpixmap = XCreatePixmap (display, mainwindow, 1024, maxheight + STATUSBAR_HEIGHT, + DefaultDepth (display, DefaultScreen (display))); + XFillRectangle (display, mainpixmap, colorGC[0], 0, 0, xsh.width, xsh.height); + update (0, 0, xsh.width, xsh.height); + } + + /* lag statusbar */ + createStatusBar(); + + /* gi beskjed om hvilke events som trengs */ + XSelectInput (display, mainwindow, + ExposureMask | KeyPressMask | KeyReleaseMask); + + /* gjør vindu synlig */ + XMapWindow (display, mainwindow); + + /* init pressedKeys tabell */ + memset (pressedKeys, 1, 256); + + /* bøyle st28b? */ + XrmGetResource (options_db, "tikiemul.st28b", "Tikiemul.st28b", &resType, &resValue); + if (resValue.addr) { + if (!strcmp (resValue.addr, "on")) { + setST28b (TRUE); + } else { + setST28b (FALSE); + } + } + + /* sett opp printfil/kommando */ + XrmGetResource (options_db, "tikiemul.pk", "Tikiemul.pk", &resType, &resValue); + if (resValue.addr) { + setPrintCmd (resValue.addr); + } + XrmGetResource (options_db, "tikiemul.pf", "Tikiemul.pf", &resType, &resValue); + if (resValue.addr) { + setPrintFile (resValue.addr); + } + + /* sett opp serieporter */ + XrmGetResource (options_db, "tikiemul.port1", "Tikiemul.port1", &resType, &resValue); + if (resValue.addr) { + if ((port1 = open (resValue.addr, O_RDWR | O_NOCTTY | O_NDELAY)) == -1) { + fprintf (stderr, "Kan ikke åpne port %s\n", resValue.addr); + port1 = 0; + } else { + fcntl (port1, F_SETFL, 0); + } + } + XrmGetResource (options_db, "tikiemul.port2", "Tikiemul.port2", &resType, &resValue); + if (resValue.addr) { + if ((port2 = open (resValue.addr, O_RDWR | O_NOCTTY | O_NDELAY)) == -1) { + fprintf (stderr, "Kan ikke åpne port %s\n", resValue.addr); + port2 = 0; + } else { + fcntl (port2, F_SETFL, 0); + } + } + + /* kjør emulator */ + if (!runEmul()) { + fprintf (stderr, "Finner ikke ROM-fil\n"); + } + + /* avslutt */ + if (port2) close (port2); + if (port1) close (port1); + if (printFile) fclose (printFile); + if (printCmd) fclose (printCmd); + XFreePixmap (display, mainpixmap); + { + int i; + + XFreeGC (display, blackGC); + XFreeGC (display, backGC); + XFreeGC (display, diodeGC); + + for (i = 0; i < 16; i++) { + XFreeGC (display, colorGC[i]); + } + } + XDestroyWindow (display, mainwindow); + if (dyn_cmap) { + XFreeColors (display, default_cmap, pixels, 16, 0); + } else { + free (screen); + } + free (dsk[0]); + free (dsk[1]); + XCloseDisplay (display); + + exit (0); +} +/* oppdater gitt rektangel ved neste loopEmul() */ +static void update (int x, int y, int w, int h) { + if (xmin > x) xmin = x; + if (ymin > y) ymin = y; + if (xmax < (x + w)) xmax = x + w; + if (ymax < (y + h)) ymax = y + h; + updateWindow = TRUE; +} +/* tegner statusbar */ +static void createStatusBar (void) { + /* statuslinje */ + XFillRectangle (display, mainpixmap, backGC, + 0, xsh.height - STATUSBAR_HEIGHT, xsh.width, STATUSBAR_HEIGHT); + + /* "hull" til dioder */ + XFillRectangle (display, mainpixmap, blackGC, + 20, xsh.height - STATUSBAR_HEIGHT + 3, 10, 10); + XFillRectangle (display, mainpixmap, blackGC, + 40, xsh.height - STATUSBAR_HEIGHT + 3, 10, 10); + XFillRectangle (display, mainpixmap, blackGC, + 60, xsh.height - STATUSBAR_HEIGHT + 3, 10, 10); + XFillRectangle (display, mainpixmap, blackGC, + 80, xsh.height - STATUSBAR_HEIGHT + 3, 10, 10); + + /* oppdater diodelys */ + lockLight (lock); + grafikkLight (grafikk); + diskLight (0, disk[0]); + diskLight (1, disk[1]); + + update (0, xsh.height - STATUSBAR_HEIGHT, xsh.width, STATUSBAR_HEIGHT); +} +/* Forandre oppløsning */ +void changeRes (int newRes) { + resolution = newRes; + + switch (resolution) { + case LOWRES: + xsh.width = width[0]; + xsh.height = height[0]; + break; + case MEDRES: + xsh.width = width[1]; + xsh.height = height[1]; + break; + case HIGHRES: + xsh.width = width[2]; + xsh.height = height[2]; + break; + } + xsh.height += STATUSBAR_HEIGHT; + + /* slett gammelt innhold */ + XFillRectangle (display, mainpixmap, colorGC[0], 0, 0, xsh.width, xsh.height - STATUSBAR_HEIGHT); + update (0, 0, xsh.width, xsh.height - STATUSBAR_HEIGHT); + + /* nye hints til window manager */ + xsh.flags = (PSize | PMinSize | PMaxSize); + xsh.min_width = xsh.width; + xsh.min_height = xsh.height; + xsh.max_width = xsh.width; + xsh.max_height = xsh.height; + XSetNormalHints (display, mainwindow, &xsh); + + /* forandre vindusstørrelse */ + XResizeWindow (display, mainwindow, xsh.width, xsh.height); + + if (!dyn_cmap) { + /* slett gammelt innhold i screen */ + memset (screen, 0, 1024 * 256); + } + + /* lag statusbar */ + createStatusBar(); +} +/* Plotter en pixel med farge tatt fra pallett */ +void plotPixel (int x, int y, int color) { + if (!dyn_cmap) { + screen[x + y * 1024] = color; + } + + switch (resolution) { + case LOWRES: + x = x * times40; + y = y * times40; + break; + case MEDRES: + x = x * times80; + y = y * times80 * (scanlines ? 2 : 1); + break; + case HIGHRES: + y = y * (scanlines ? 4 : 1); + break; + } + + XDrawPoint (display, mainpixmap, colorGC[color], x, y); + + update (x, y, 1, 1); +} +/* Scroller skjerm 'distance' linjer oppover */ +void scrollScreen (int distance) { + if (!dyn_cmap) { + /* scroll screen */ + if (distance > 0) { + memmove (screen, screen + distance * 1024, (256 - distance) * 1024); + memset (screen + (256 - distance) * 1024, 0, distance * 1024); + } else { + memmove (screen + (-distance * 1024), screen, (byte)distance * 1024); + memset (screen, 0, -distance * 1024); + } + } + switch (resolution) { + case LOWRES: + distance *= times40; + break; + case MEDRES: + distance *= times80 * (scanlines ? 2 : 1); + break; + case HIGHRES: + distance *= (scanlines ? 4 : 1); + break; + } + /* scroll pixmap */ + if (distance > 0) { + XCopyArea (display, mainpixmap, mainpixmap, colorGC[1], + 0, distance, xsh.width, xsh.height - STATUSBAR_HEIGHT - distance, 0, 0); + XFillRectangle (display, mainpixmap, colorGC[0], 0, xsh.height - STATUSBAR_HEIGHT - distance, + xsh.width, distance); + } else { + XCopyArea (display, mainpixmap, mainpixmap, colorGC[1], + 0, 0, xsh.width, xsh.height - STATUSBAR_HEIGHT - (-distance), 0, -distance); + XFillRectangle (display, mainpixmap, colorGC[0], 0, 0, + xsh.width, -distance); + } + /* oppdater hele vinduet */ + update (0, 0, xsh.width, xsh.height - STATUSBAR_HEIGHT); +} +/* Ny farge, gitt pallett nummer og intensitet 0-255 */ +void changePalette (int colornumber, byte red, byte green, byte blue) { + XColor color; + + color.red = red << 8; + color.green = green << 8; + color.blue = blue << 8; + if (dyn_cmap) { + color.flags = DoRed | DoGreen | DoBlue; + color.pixel = pixels[colornumber]; + XStoreColor (display, default_cmap, &color); + } else { + XGCValues gcv; + + /* skaff pixel */ + if (!XAllocColor (display, default_cmap, &color)) { + fprintf (stderr, "Farge %x %x %x ikke tilgjengelig, bruker hvit!\n", red, green, blue); + color.pixel = whitepix; + } + pixels[colornumber] = color.pixel; + /* forandre GC */ + gcv.foreground = pixels[colornumber]; + XChangeGC (display, colorGC[colornumber], GCForeground, &gcv); + { /* oppdater skjerm */ + int x, y; + + for (y = 0; y < 256; y++) { + for (x = 0; x < 1024; x++) { + if (screen[x + y * 1024] == colornumber) { + plotPixel (x, y, colornumber); + } + } + } + } + } +} +/* Kalles periodisk. Lar system kode måle / senke emuleringshastighet + * Kan også brukes til sjekk av brukeraktivitet + * ms er antall "emulerte" millisekunder siden forrige gang loopEmul ble kalt + */ +void loopEmul (int ms) { + int events; + XEvent event; + + /* senk hastighet */ + if (slowDown) { + static boolean firsttime = TRUE; /* brukes for å initialisere lastTOD */ + static struct timeval lastTOD; + struct timeval currentTOD; + + if (firsttime) { /* initialiser lastTOD */ + gettimeofday (&lastTOD, NULL); + firsttime = FALSE; + } else { + long sleepPeriod; + + gettimeofday (¤tTOD, NULL); + + /* finner soveintervall */ + if ((currentTOD.tv_sec - lastTOD.tv_sec) != 0) { /* har krysset sekundgrense */ + sleepPeriod = (ms * 1000) - (currentTOD.tv_usec + (1000000 - lastTOD.tv_usec)); + } else { + sleepPeriod = (ms * 1000) - (currentTOD.tv_usec - lastTOD.tv_usec); + } + + lastTOD = currentTOD; + + /* ta en liten lur */ + if (sleepPeriod > 0) { + usleep (sleepPeriod); + + /* lastTOD += sleepPeriod */ + lastTOD.tv_usec = lastTOD.tv_usec + sleepPeriod; + if (lastTOD.tv_usec > 999999) { + lastTOD.tv_sec++; + lastTOD.tv_usec -= 1000000; + } + } + } + } + + /* oppdater skjerm */ + if (updateWindow) { + XCopyArea (display, mainpixmap, mainwindow, colorGC[1], + xmin, ymin, xmax - xmin, ymax - ymin, xmin, ymin); + xmin = (unsigned)~0; ymin = (unsigned)~0; xmax = 0; ymax = 0; + updateWindow = FALSE; + } + + XFlush (display); + + /* sjekk events */ + if ((events = XEventsQueued (display, QueuedAfterReading))) { + while (events--) { + XNextEvent (display, &event); + switch (event.type) { + case MappingNotify: + XRefreshKeyboardMapping ((XMappingEvent *)&event); + break; + case Expose: + XCopyArea (display, mainpixmap, mainwindow, colorGC[1], + event.xexpose.x, event.xexpose.y, + event.xexpose.width, event.xexpose.height, + event.xexpose.x, event.xexpose.y); + break; + case KeyPress: { + if (XKeycodeToKeysym (display, event.xkey.keycode, 0) == XK_Escape) { + commandline(); + } else { + pressedKeys[keysymToTikikey (XKeycodeToKeysym (display, event.xkey.keycode, 0))] + = 0; + } + break; + } + case KeyRelease: { + pressedKeys[keysymToTikikey (XKeycodeToKeysym (display, event.xkey.keycode, 0))] + = 1; + break; + } + } + } + } + + /* sjekk serieporter */ + if (port1) { + int bytes; + + ioctl (port1, FIONREAD, &bytes); + if (bytes) { + charAvailable (0); + } + } + if (port2) { + int bytes; + + ioctl (port2, FIONREAD, &bytes); + if (bytes) { + charAvailable (1); + } + } +} +/* oversetter fra keysym til tikitaster */ +static byte keysymToTikikey (KeySym keysym) { + int i; + + /* lineærsøk gjennom tabell */ + for (i = 0; i < (sizeof keyConvTable / sizeof (struct KeyConv)); i++) { + if (keyConvTable[i].keysym == keysym) + return keyConvTable[i].tikikey; + } + return KEY_NONE; +} +/* tar imot kommandoer via konsoll */ +static void commandline (void) { + while (TRUE) { + char cmdline[256]; + char *cmd; + + printf ("Kommando [h for hjelp]> "); + fflush (stdout); + + fgets (cmdline, 256, stdin); + + if ((cmd = strtok (cmdline, " \t\n"))) { + if (!strcmp (cmd, "h") || !strcmp (cmd, "hjelp")) { + /* vis hjelpetekst */ + puts ("\n***** Kommandoer *****"); + puts ("hjelp : Vis denne hjelpeteksten"); + puts ("h : "); + puts ("disk : Hent inn diskettfil"); + puts ("d : "); + puts ("lagre : Lagre diskettfil"); + puts ("l : "); + puts ("fjern : Fjern diskettfil"); + puts ("f : "); + puts ("pk [kommandonavn] : Send utskrift til print-kommando"); + puts ("pf [filnavn] : Send utskrift til fil"); + puts ("reset : Reset emulator"); + puts ("fortsett : Fortsett emulering"); + puts ("c : "); + puts ("om : Om emulator"); + puts ("avslutt : Avslutt emulator"); + puts ("q : "); +#ifdef DEBUG + puts ("monitor : Z80-monitor"); + puts ("m : "); +#endif + puts (""); + } else if (!strcmp (cmd, "d") || !strcmp (cmd, "disk")) { + /* hent diskfil */ + char *driveString = strtok (NULL, " \t\n"); + char *filename = strtok (NULL, " \t\n"); + + if (!filename) { + fprintf (stderr, "For få argumenter\n"); + continue; + } + + if (!strcmp (driveString, "a") || !strcmp (driveString, "a:")) { + readDiskImage (0, filename); + } else if (!strcmp (driveString, "b") || !strcmp (driveString, "b:")) { + readDiskImage (1, filename); + } else fprintf (stderr, "Ugyldig stasjon\n"); + } else if (!strcmp (cmd, "l") || !strcmp (cmd, "lagre")) { + /* lagre diskfil */ + int drive; + char *driveString = strtok (NULL, " \t\n"); + char *filename = strtok (NULL, " \t\n"); + + if (!filename) { + fprintf (stderr, "For få argumenter\n"); + continue; + } + + if (!strcmp (driveString, "a") || !strcmp (driveString, "a:")) { + drive = 0; + } else if (!strcmp (driveString, "b") || !strcmp (driveString, "b:")) { + drive = 1; + } else { + fprintf (stderr, "Ugyldig stasjon\n"); + continue; + } + if (dsksize[drive] != 0) { + int fd; + + if ((fd = creat (filename, 0640)) != -1) { + if (write (fd, dsk[drive], dsksize[drive]) == -1) { + fprintf (stderr, "Kan ikke skrive til fil %s\n", filename); + } + close (fd); + } else fprintf (stderr, "Kan ikke skrive til fil %s\n", filename); + } + } else if (!strcmp (cmd, "f") || !strcmp (cmd, "fjern")) { + /* fjern diskfil */ + int drive; + char *driveString = strtok (NULL, " \t\n"); + + if (!driveString) { + fprintf (stderr, "For få argumenter\n"); + continue; + } + + if (!strcmp (driveString, "a") || !strcmp (driveString, "a:")) { + drive = 0; + } else if (!strcmp (driveString, "b") || !strcmp (driveString, "b:")) { + drive = 1; + } else { + fprintf (stderr, "Ugyldig stasjon\n"); + continue; + } + removeDisk (drive); + free (dsk[drive]); + dsk[drive] = NULL; + dsksize[drive] = 0; + } else if (!strcmp (cmd, "pk")) { + char *pc = strtok (NULL, " \t\n"); + + if (!pc) { + if (printCmd) { + pclose (printCmd); + printCmd = 0; + } + } else { + setPrintCmd (pc); + } + } else if (!strcmp (cmd, "pf")) { + char *pf = strtok (NULL, " \t\n"); + + if (!pf) { + if (printFile) { + fclose (printFile); + printFile = 0; + } + } else { + setPrintFile (pf); + } + } else if (!strcmp (cmd, "reset")) { + /* reset */ + resetEmul(); + } else if (!strcmp (cmd, "c") || !strcmp (cmd, "fortsett")) { + /* fortsett emulering */ + return; + } else if (!strcmp (cmd, "om")) { + /* vis "om"-tekst */ + puts ("\nTIKI-100_emul V1.1.1 - en freeware TIKI 100 Rev. C emulator."); + puts ("Z80 emulering copyright (C) Marat Fayzullin 1994,1995,1996,1997."); + puts ("Resten copyright (C) Asbjørn Djupdal 2000-2001.\n"); + } else if (!strcmp (cmd, "q") || !strcmp (cmd, "avslutt")) { + /* avslutt */ + quitEmul(); + return; +#ifdef DEBUG + } else if (!strcmp (cmd, "m") || !strcmp (cmd, "monitor")) { + /* z80-debugger */ + trace(); + return; +#endif + } else { + fprintf (stderr, "Ugyldig kommando\n"); + } + } + } +} +/* setter opp printkommando/fil */ +static void setPrintCmd (char *p) { + if (printCmd) pclose (printCmd); + if (!(printCmd = popen (p, "w"))) { + fprintf (stderr, "Kan ikke starte printkommando\n"); + } +} +static void setPrintFile (char *p) { + if (printFile) fclose (printFile); + if (!(printFile = fopen (p, "wb"))) { + fprintf (stderr, "Kan ikke lage printerfil %s\n", p); + } +} +/* henter inn diskbilde fra fil */ +static void readDiskImage (int drive, char *filename) { + int fd; + + if ((fd = open (filename, O_RDONLY)) != -1) { + struct stat fileInfo; + + removeDisk (drive); + free (dsk[drive]); + fstat (fd, &fileInfo); + if ((dsk[drive] = malloc (fileInfo.st_size))) { + dsksize[drive] = read (fd, dsk[drive], fileInfo.st_size); + + switch (dsksize[drive]) { + case 40*1*18*128: + insertDisk (drive, dsk[drive], 40, 1, 18, 128); + break; + case 40*1*10*512: + insertDisk (drive, dsk[drive], 40, 1, 10, 512); + break; + case 40*2*10*512: + insertDisk (drive, dsk[drive], 40, 2, 10, 512); + break; + case 80*2*10*512: + insertDisk (drive, dsk[drive], 80, 2, 10, 512); + break; + case -1: + fprintf (stderr, "Klarer ikke lese fra fil %s\n", filename); + break; + default: + fprintf (stderr, "Kjenner ikke diskformatet\n"); + dsksize[drive] = 0; + free (dsk[drive]); + dsk[drive] = NULL; + break; + } + } else { + fprintf (stderr, "Ikke nok minne til diskettfil\n"); + dsksize[drive] = 0; + } + close (fd); + } else { + fprintf (stderr, "Klarer ikke lese fra fil %s\n", filename); + } +} + +/* Tenn/slukk lock lys */ +void lockLight (boolean status) { + GC gc = (status ? diodeGC : blackGC); + + XFillRectangle (display, mainpixmap, gc, + 21, xsh.height - STATUSBAR_HEIGHT + 4, 8, 8); + + update (21, xsh.height - STATUSBAR_HEIGHT + 4, 9, 9); + lock = status; +} +/* Tenn/slukk grafikk lys */ +void grafikkLight (boolean status) { + GC gc = (status ? diodeGC : blackGC); + + XFillRectangle (display, mainpixmap, gc, + 41, xsh.height - STATUSBAR_HEIGHT + 4, 8, 8); + + update (41, xsh.height - STATUSBAR_HEIGHT + 4, 9, 9); + grafikk = status; +} +/* Tenn/slukk disk lys for gitt stasjon */ +void diskLight (int drive, boolean status) { + GC gc = (status ? diodeGC : blackGC); + int x = (drive ? 81 : 61); + + XFillRectangle (display, mainpixmap, gc, + x, xsh.height - STATUSBAR_HEIGHT + 4, 8, 8); + + update (x, xsh.height - STATUSBAR_HEIGHT + 4, 9, 9); + disk[drive] = status; +} +/* Sjekk status til hver av de gitte tastene + * Sett bit n i returkode hvis tast n IKKE er nedtrykt + */ +byte testKey (byte keys[8]) { + return pressedKeys[keys[0]] | (pressedKeys[keys[1]] << 1) | (pressedKeys[keys[2]] << 2) | + (pressedKeys[keys[3]] << 3) | (pressedKeys[keys[4]] << 4) | (pressedKeys[keys[5]] << 5) | + (pressedKeys[keys[6]] << 6) | (pressedKeys[keys[7]] << 7); +} +/* setter seriekanalparametre */ +void setParams (struct serParams *p1Params, struct serParams *p2Params) { + if (port1) setParam (port1, p1Params); + if (port2) setParam (port2, p2Params); +} +static void setParam (int portfd, struct serParams *params) { + struct termios options; + + tcgetattr (portfd, &options); + + options.c_iflag = 0; + options.c_oflag = 0; + options.c_lflag = 0; + memset (options.c_cc, 0, sizeof (options.c_cc)); + + options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); + options.c_cflag |= (CLOCAL | CREAD); + + /* rec/send bits */ + options.c_cflag &= ~CSIZE; + switch (params->sendBits) { + case 5: + options.c_cflag |= CS5; + break; + case 6: + options.c_cflag |= CS6; + break; + case 7: + options.c_cflag |= CS7; + break; + default: + case 8: + options.c_cflag |= CS8; + break; + } + /* parity */ + switch (params->parity) { + case PAR_NONE: + options.c_cflag &= ~PARENB; + options.c_iflag &= ~(INPCK | ISTRIP); + break; + case PAR_EVEN: + options.c_cflag |= PARENB; + options.c_cflag &= ~PARODD; + options.c_iflag |= (INPCK | ISTRIP); + break; + case PAR_ODD: + options.c_cflag |= PARENB; + options.c_cflag |= PARODD; + options.c_iflag |= (INPCK | ISTRIP); + break; + } + /* stopbits */ + switch (params->stopBits) { + case ONE_SB: + options.c_cflag &= ~CSTOPB; + break; + case ONE_PT_FIVE_SB: + case TWO_SB: + options.c_cflag |= CSTOPB; + break; + } + /* baud */ + if (params->baud < 62) { + params->baud = B50; + } else if (params->baud < 92) { + params->baud = B75; + } else if (params->baud < 122) { + params->baud = B110; + } else if (params->baud < 142) { + params->baud = B134; + } else if (params->baud < 175) { + params->baud = B150; + } else if (params->baud < 250) { + params->baud = B200; + } else if (params->baud < 450) { + params->baud = B300; + } else if (params->baud < 900) { + params->baud = B600; + } else if (params->baud < 1500) { + params->baud = B1200; + } else if (params->baud < 2100) { + params->baud = B1800; + } else if (params->baud < 3600) { + params->baud = B2400; + } else if (params->baud < 7200) { + params->baud = B4800; + } else if (params->baud < 14400) { + params->baud = B9600; + } else { + params->baud = B19200; + } + cfsetispeed (&options, params->baud); + cfsetospeed (&options, params->baud); + + tcsetattr (portfd, TCSADRAIN, &options); +} +/* send tegn til seriekanal */ +void sendChar (int port, byte value) { + int portfd = port ? port2 : port1; + + if (portfd) { + if (write (portfd, &value, 1) == -1) { + /* klarer ikke sende tegn */ + } + } +} +/* hent tegn fra seriekanal */ +byte getChar (int port) { + int portfd = port ? port2 : port1; + byte value; + + if (portfd) { + read (portfd, &value, 1); + + { /* flere tegn? */ + int bytes; + + ioctl (portfd, FIONREAD, &bytes); + if (bytes) { + charAvailable (port); + } + } + } + return value; +} +/* send tegn til skriver */ +void printChar (byte value) { + if (printCmd) { + if (fputc (value, printCmd) == EOF) { + /* klarer ikke skrive til printkommando */ + } + } + if (printFile) { + if (fputc (value, printFile) == EOF) { + /* klarer ikke skrive til printfil */ + } + } +} diff --git a/TIKI-100_emul-src/video.c b/TIKI-100_emul-src/video.c new file mode 100644 index 0000000..81912c9 --- /dev/null +++ b/TIKI-100_emul-src/video.c @@ -0,0 +1,123 @@ +/* video.c V1.1.0 + * + * Grafikk emulering for TIKI-100_emul + * Copyright (C) Asbjørn Djupdal 2000-2001 + */ + +#include "TIKI-100_emul.h" +#include "protos.h" +#include + +/* variabler */ + +/* konverteringstabeller */ +static const byte redGreenTable[8] = {0, 36, 73, 109, 146, 182, 219, 255}; +static const byte blueTable[4] = {0, 85, 170, 255}; + +byte gfxRam[32 * 1024]; + +static byte red = 0, green = 0, blue = 0; /* farge-register */ +static int res = MEDRES; /* gjeldende oppløsning */ +static boolean changeColor = FALSE; /* forandre farge hver gang fargeregister forandres */ +static int colornumber = 0; + +/*****************************************************************************/ + +/* Tegn alle pixler representert i gitt byte */ +void drawByte (word addr) { + int x; + byte y = addr >> 7; + + switch (res) { + case HIGHRES: x = (addr & 0x7f) << 3; + plotPixel (x, y, gfxRam[addr] & 0x01); + plotPixel (++x, y, (gfxRam[addr] & 0x02) >> 1); + plotPixel (++x, y, (gfxRam[addr] & 0x04) >> 2); + plotPixel (++x, y, (gfxRam[addr] & 0x08) >> 3); + plotPixel (++x, y, (gfxRam[addr] & 0x10) >> 4); + plotPixel (++x, y, (gfxRam[addr] & 0x20) >> 5); + plotPixel (++x, y, (gfxRam[addr] & 0x40) >> 6); + plotPixel (++x, y, (gfxRam[addr] & 0x80) >> 7); + break; + case MEDRES: x = (addr & 0x7f) << 2; + plotPixel (x, y, gfxRam[addr] & 0x03); + plotPixel (++x, y, (gfxRam[addr] & 0x0c) >> 2); + plotPixel (++x, y, (gfxRam[addr] & 0x30) >> 4); + plotPixel (++x, y, (gfxRam[addr] & 0xc0) >> 6); + break; + case LOWRES: x = (addr & 0x7f) << 1; + plotPixel (x, y, gfxRam[addr] & 0x0f); + plotPixel (++x, y, (gfxRam[addr] & 0xf0) >> 4); + break; + } +} +/* Ny verdi til modusregister */ +void newMode (byte mode) { + colornumber = mode & 0x0f; + if (mode & 128) { /* sett farge */ + changeColor = TRUE; + changePalette (colornumber, red, green, blue); + } else { + changeColor = FALSE; + } + if (res != (mode & 48)) { + res = (mode & 48); /* ny oppløsning */ + changeRes (res); + { /* oppdater skjerm */ + int i; + + for (i = 0; i < 32768; i++) { + if (gfxRam[i]) drawByte (i); + } + } + } +} +/* Ny verdi i fargeregister */ +void newColor (byte color) { + red = redGreenTable[(~color & 224) >> 5]; + green = redGreenTable[(~color & 28) >> 2]; + blue = blueTable[~color & 3]; + if (changeColor) { + changePalette (colornumber, red, green, blue); + } +} +/* Ny verdi i scrollregister fra AY-3-8912 */ +void newOffset (byte newOffset) { + static byte vOffset = 0; /* scrollregister */ + + /* ignorer hvis ikke noen forskjell */ + if (newOffset != vOffset) { + int distance = (signed char)(newOffset - vOffset); + byte buffer[128 * 128]; /* skroller aldri mer enn halve skjermen */ + word addr; + + /* flytt på skjerm */ + scrollScreen (distance); + + if (distance > 0) { + /* flytt i ram */ + memmove (buffer, gfxRam, distance * 128); /* øverst -> buffer */ + memmove (gfxRam, gfxRam + distance * 128, (256 - distance) * 128); /* nederst -> øverst */ + memmove (gfxRam + (256 - distance) * 128, buffer, distance * 128); /* buffer -> nederst */ + + /* oppdater nederste del av skjerm */ + for (addr = 32768 - (distance * 128); addr < 32768; addr++) { + if (gfxRam[addr]) drawByte (addr); + } + } else { + /* flytt i ram */ + memmove (buffer, gfxRam + (byte)distance * 128, -distance * 128); /* nederst -> buffer */ + memmove (gfxRam + (-distance * 128), gfxRam, (byte)distance * 128); /* øverst -> nederst */ + memmove (gfxRam, buffer, -distance * 128); /* buffer -> øverst */ + + /* oppdater øverste del av skjerm */ + for (addr = 0; addr < -distance * 128; addr++) { + if (gfxRam[addr]) drawByte (addr); + } + } + + /* oppdater scrollregister */ + vOffset = newOffset; + } +} + diff --git a/TIKI-100_emul-src/win32.c b/TIKI-100_emul-src/win32.c new file mode 100644 index 0000000..632c047 --- /dev/null +++ b/TIKI-100_emul-src/win32.c @@ -0,0 +1,792 @@ +/* win32.c V1.1.1 + * + * Win32 systemspesifikk kode for TIKI-100_emul + * Copyright (C) Asbjørn Djupdal 2000-2001 + */ + +#include "TIKI-100_emul.h" +#include "win32_res.h" + +#include +#include + +#include +#include + +#define ERROR_CAPTION "TIKI-100_emul feilmelding" +#define STATUSBAR_HEIGHT 19 + +/* protos */ +int WINAPI WinMain (HINSTANCE hThisInst, HINSTANCE hPrevInst, LPSTR lpszArgs, int nWinMode); +static LRESULT CALLBACK WindowFunc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); +static BOOL CALLBACK DialogFunc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); + +static void update (int x, int y, int w, int h); +static void draw3dBox (int x, int y, int w, int h); +static void getDiskImage (int drive); +static void saveDiskImage (int drive); +static void setParam (HANDLE portHandle, struct serParams *params); + +/* variabler */ + +static byte keyTable[256] = { + KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, + KEY_SLETT, KEY_BRYT, KEY_NONE, KEY_NONE, KEY_NONE, KEY_CR, KEY_NONE, KEY_NONE, + KEY_SHIFT, KEY_CTRL, KEY_NONE, KEY_NONE, KEY_LOCK, KEY_NONE, KEY_NONE, KEY_NONE, + KEY_NONE, KEY_NONE, KEY_NONE, KEY_ANGRE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, + KEY_SPACE, KEY_PGUP, KEY_PGDOWN, KEY_TABRIGHT, KEY_HOME, KEY_LEFT, KEY_UP, KEY_RIGHT, + KEY_DOWN, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_UTVID, KEY_TABLEFT, KEY_NONE, + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, + KEY_NONE, 'a', 'b', 'c', 'd', 'e', 'f', 'g', + 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', + 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', + 'x', 'y', 'z', KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, + KEY_NUM0, KEY_NUM1, KEY_NUM2, KEY_NUM3, KEY_NUM4, KEY_NUM5, KEY_NUM6, KEY_NUM7, + KEY_NUM8, KEY_NUM9, KEY_NUMMULT, KEY_NUMPLUS, KEY_NONE, KEY_NUMMINUS, KEY_NUMDOT, KEY_NUMDIV, + KEY_F1, KEY_F2, KEY_F3, KEY_F4, KEY_F5, KEY_F6, KEY_NONE, KEY_HJELP, + KEY_ENTER, KEY_NONE, KEY_NUMPERCENT, KEY_NUMEQU, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, + KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, + KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, + KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, + KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, + KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, + KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, + KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, + KEY_NONE, KEY_NONE, '^', '+', ',', '-', '.', '\'', + 'ø', KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, + KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, + KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, + KEY_NONE, KEY_NONE, KEY_NONE, '@', KEY_GRAFIKK, 'å', 'æ', KEY_NONE, + KEY_NONE, KEY_NONE, '<', KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, + KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, + KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, + KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE +}; + +static HWND hwnd; +static HINSTANCE appInst; +static HDC memdc; +static HBITMAP hbit; +static byte screen[1024*256]; +static COLORREF colors[16]; +static char defaultDir[256]; +static byte pressedKeys[256]; +static byte *dsk[2]; +static DWORD fileSize[2]; +static int resolution; +static boolean slowDown = TRUE; +static boolean scanlines = FALSE; +static boolean st28b = FALSE; +static int width, height; +static int size40x = 1, size80x = 1; +static unsigned int xmin = (unsigned)~0; +static unsigned int ymin = (unsigned)~0; +static unsigned int xmax = 0; +static unsigned int ymax = 0; +static boolean updateWindow = FALSE; +static boolean lock = FALSE; +static boolean grafikk = FALSE; +static boolean disk[2] = {FALSE, FALSE}; +static HANDLE port1; +static HANDLE port2; +static HANDLE port3; +static char port1Name[256] = "COM1"; +static char port2Name[256] = "COM2"; +static char port3Name[256] = "LPT1"; + +/*****************************************************************************/ + +int WINAPI WinMain (HINSTANCE hThisInst, HINSTANCE hPrevInst, LPSTR lpszArgs, int nWinMode) { + char szWinName[] = "TIKIWin"; + MSG msg; + WNDCLASSEX wcl; + + appInst = hThisInst; + + InitCommonControls(); + + /* lag og registrer vindusklasse */ + wcl.cbSize = sizeof (WNDCLASSEX); + wcl.hInstance = hThisInst; + wcl.lpszClassName = szWinName; + wcl.lpfnWndProc = WindowFunc; + wcl.style = 0; + wcl.hIcon = LoadIcon (appInst, "icon"); + wcl.hIconSm = NULL; + wcl.hCursor = LoadCursor (NULL, IDC_ARROW); + wcl.lpszMenuName = "menu"; + wcl.cbClsExtra = 0; + wcl.cbWndExtra = 0; + wcl.hbrBackground = (HBRUSH)GetStockObject (BLACK_BRUSH); + if (!RegisterClassEx (&wcl)) { + return 0; + } + + /* lag vindu */ + hwnd = CreateWindow (szWinName, "TIKI-100_emul", WS_OVERLAPPEDWINDOW & ~WS_SIZEBOX & ~WS_MAXIMIZEBOX, CW_USEDEFAULT, + CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, HWND_DESKTOP, NULL, hThisInst, NULL); + changeRes (MEDRES); + ShowWindow (hwnd, nWinMode); + + /* initialiser arrays */ + memset (pressedKeys, 1, 256); + memset (screen, 0, 1024*256); + + /* finn katalog */ + GetCurrentDirectory (256, defaultDir); + + /* kjør emulator */ + if (!runEmul()) { + MessageBox (hwnd, "Finner ikke ROM-fil!", ERROR_CAPTION, MB_OK); + } + + /* avslutt */ + free (dsk[0]); + free (dsk[1]); + if (port1) CloseHandle (port1); + if (port2) CloseHandle (port2); + if (port3) CloseHandle (port3); + + return msg.wParam; +} + +static LRESULT CALLBACK WindowFunc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { + switch (msg) { + case WM_CREATE: + { /* sett opp memdc */ + HDC hdc = GetDC (hwnd); + memdc = CreateCompatibleDC (hdc); + hbit = CreateCompatibleBitmap (hdc, 1024, 1024 + STATUSBAR_HEIGHT); + SelectObject (memdc, hbit); + SelectObject (memdc, GetStockObject (BLACK_BRUSH)); + PatBlt (memdc, 0, 0, 1024, 1024 + STATUSBAR_HEIGHT, PATCOPY); + ReleaseDC (hwnd, hdc); + } + break; + case WM_PAINT: + { /* kopier fra memdc til hdc */ + PAINTSTRUCT ps; + HDC hdc = BeginPaint (hwnd, &ps); + BitBlt (hdc, ps.rcPaint.left, ps.rcPaint.top, ps.rcPaint.right - ps.rcPaint.left, + ps.rcPaint.bottom - ps.rcPaint.top, memdc, ps.rcPaint.left, ps.rcPaint.top, SRCCOPY); + EndPaint (hwnd, &ps); + } + break; + case WM_SIZE: + /* statusbar */ + SelectObject (memdc, GetSysColorBrush (COLOR_3DFACE)); + PatBlt (memdc, 0, height, width, STATUSBAR_HEIGHT, PATCOPY); + + /* tegn småbokser */ + draw3dBox (20, height + 5, 9, 9); + draw3dBox (40, height + 5, 9, 9); + draw3dBox (60, height + 5, 9, 9); + draw3dBox (80, height + 5, 9, 9); + + /* oppdater diodelys */ + lockLight (lock); + grafikkLight (grafikk); + diskLight (0, disk[0]); + diskLight (1, disk[1]); + break; + case WM_DESTROY: + PostQuitMessage (0); + break; + case WM_KEYDOWN: + pressedKeys[keyTable[(byte)wParam]] = 0; + break; + case WM_KEYUP: + pressedKeys[keyTable[(byte)wParam]] = 1; + break; + case WM_COMMAND: + switch (LOWORD (wParam)) { + case IDM_RESET: + resetEmul(); + break; + case IDM_INNSTILLINGER: + DialogBox (appInst, "dialog", hwnd, (DLGPROC)DialogFunc); + break; + case IDM_OM: + MessageBox (hwnd, + "TIKI-100_emul V1.1.1 - en freeware TIKI 100 Rev. C emulator.\n" + "Z80 emulering copyright (C) Marat Fayzullin 1994,1995,1996,1997.\n" + "Resten copyright (C) Asbjørn Djupdal 2000-2001.", + "Om TIKI-100_emul", + MB_OK); + break; + case IDM_AVSLUTT: + PostQuitMessage (0); + break; + case IDM_HENT_A: + getDiskImage (0); + break; + case IDM_HENT_B: + getDiskImage (1); + break; + case IDM_LAGRE_A: + saveDiskImage (0); + break; + case IDM_LAGRE_B: + saveDiskImage (1); + break; + case IDM_FJERN_A: + EnableMenuItem (GetSubMenu (GetMenu (hwnd), 1), IDM_LAGRE_A, MF_BYCOMMAND | MF_GRAYED); + removeDisk (0); + break; + case IDM_FJERN_B: + EnableMenuItem (GetSubMenu (GetMenu (hwnd), 1), IDM_LAGRE_B, MF_BYCOMMAND | MF_GRAYED); + removeDisk (1); + break; +#ifdef DEBUG + case IDM_MONITOR: + trace(); + break; +#endif + } + default: + return DefWindowProc (hwnd, msg, wParam, lParam); + } + return 0; +} +/* tegner en 3d-boks */ +static void draw3dBox (int x, int y, int w, int h) { + HGDIOBJ obj; + HPEN pen1 = CreatePen (PS_SOLID, 0, GetSysColor (COLOR_3DDKSHADOW)); + HPEN pen2 = CreatePen (PS_SOLID, 0, GetSysColor (COLOR_3DHILIGHT)); + + MoveToEx (memdc, x, y + h - 1, NULL); + obj = SelectObject (memdc, pen1); + LineTo (memdc, x, y); + LineTo (memdc, x + w - 1, y); + SelectObject (memdc, pen2); + LineTo (memdc, x + w - 1, y + h - 1); + LineTo (memdc, x, y + h - 1); + + SelectObject (memdc, obj); + DeleteObject (pen2); + DeleteObject (pen1); +} +static BOOL CALLBACK DialogFunc (HWND hdwnd, UINT message, WPARAM wParam, LPARAM lParam) { + static HWND ud40Wnd, ud80Wnd; + + switch (message) { + case WM_INITDIALOG: + /* oppdater alle felter */ + ud40Wnd = CreateUpDownControl (WS_CHILD | WS_BORDER | WS_VISIBLE | UDS_SETBUDDYINT | UDS_ALIGNRIGHT, + 48, 52, 11, 14, hdwnd, IDD_40SPIN, appInst, GetDlgItem (hdwnd, IDD_40EDIT), + 4, 1, size40x); + ud80Wnd = CreateUpDownControl (WS_CHILD | WS_BORDER | WS_VISIBLE | UDS_SETBUDDYINT | UDS_ALIGNRIGHT, + 48, 71, 11, 14, hdwnd, IDD_80SPIN, appInst, GetDlgItem (hdwnd, IDD_80EDIT), + 2, 1, size80x); + if (slowDown) SendDlgItemMessage (hdwnd, IDD_HASTIGHET, BM_SETCHECK, 1, 0); + if (scanlines) SendDlgItemMessage (hdwnd, IDD_BEVARFORHOLD, BM_SETCHECK, 1, 0); + if (st28b) SendDlgItemMessage (hdwnd, IDD_ST28B, BM_SETCHECK, 1, 0); + if (port1) SendDlgItemMessage (hdwnd, IDD_P1, BM_SETCHECK, 1, 0); + if (port2) SendDlgItemMessage (hdwnd, IDD_P2, BM_SETCHECK, 1, 0); + if (port3) SendDlgItemMessage (hdwnd, IDD_P3, BM_SETCHECK, 1, 0); + SendDlgItemMessage (hdwnd, IDD_P1EDIT, WM_SETTEXT, 0, (LPARAM)port1Name); + SendDlgItemMessage (hdwnd, IDD_P2EDIT, WM_SETTEXT, 0, (LPARAM)port2Name); + SendDlgItemMessage (hdwnd, IDD_P3EDIT, WM_SETTEXT, 0, (LPARAM)port3Name); + break; + case WM_COMMAND: + switch (LOWORD(wParam)) { + case IDD_OK: { + int s40x, s80x; + boolean sl; + boolean st; + char p1[256]; + char p2[256]; + char p3[256]; + + /* begrense hastighet */ + slowDown = SendDlgItemMessage (hdwnd, IDD_HASTIGHET, BM_GETCHECK, 0, 0); + + /* forandre vindus-størrelse */ + s40x = SendMessage (ud40Wnd, UDM_GETPOS, 0, 0); + s80x = SendMessage (ud80Wnd, UDM_GETPOS, 0, 0); + sl = SendDlgItemMessage (hdwnd, IDD_BEVARFORHOLD, BM_GETCHECK, 0, 0); + if (s40x != size40x || s80x != size80x || sl != scanlines) { + size40x = s40x; size80x = s80x; scanlines = sl; + changeRes (resolution); + resetEmul(); + } + + /* sett ST 28 b */ + st = SendDlgItemMessage (hdwnd, IDD_ST28B, BM_GETCHECK, 0, 0); + if (st != st28b) { + st28b = st; + setST28b (st28b); + } + + /* skaff nye portnavn */ + SendDlgItemMessage (hdwnd, IDD_P1EDIT, WM_GETTEXT, 256, (LPARAM)p1); + SendDlgItemMessage (hdwnd, IDD_P2EDIT, WM_GETTEXT, 256, (LPARAM)p2); + SendDlgItemMessage (hdwnd, IDD_P3EDIT, WM_GETTEXT, 256, (LPARAM)p3); + + /* åpne/lukke porter */ + if (SendDlgItemMessage (hdwnd, IDD_P1, BM_GETCHECK, 0, 0)) { + /* port 1 */ + if (!port1 || strcmp (p1, port1Name)) { + if (port1) CloseHandle (port1); + SetCurrentDirectory (defaultDir); + if ((port1 = CreateFile(p1, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, 0, NULL)) == + INVALID_HANDLE_VALUE) { + MessageBox (hwnd, "Angitt navn på P1 ikke tilgjengelig!", ERROR_CAPTION, MB_OK); + port1 = 0; + } + } + } else if (port1) { + CloseHandle (port1); + port1 = 0; + } + if (SendDlgItemMessage (hdwnd, IDD_P2, BM_GETCHECK, 0, 0)) { + /* port 2 */ + if (!port2 || strcmp (p2, port2Name)) { + if (port2) CloseHandle (port2); + SetCurrentDirectory (defaultDir); + if ((port2 = CreateFile(p2, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, 0, NULL)) == + INVALID_HANDLE_VALUE) { + MessageBox (hwnd, "Angitt navn på P2 ikke tilgjengelig!", ERROR_CAPTION, MB_OK); + port1 = 0; + } + } + } else if (port2) { + CloseHandle (port2); + port2 = 0; + } + if (SendDlgItemMessage (hdwnd, IDD_P3, BM_GETCHECK, 0, 0)) { + /* port 3 */ + if (!port3 || strcmp (p3, port3Name)) { + if (port3) CloseHandle (port3); + SetCurrentDirectory (defaultDir); + if ((port3 = CreateFile(p3, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, 0, NULL)) == + INVALID_HANDLE_VALUE) { + MessageBox (hwnd, "Angitt navn på P3 ikke tilgjengelig!", ERROR_CAPTION, MB_OK); + port1 = 0; + } + } + } else if (port3) { + CloseHandle (port3); + port3 = 0; + } + + /* ta vare på portnavn */ + strcpy (port1Name, p1); + strcpy (port2Name, p2); + strcpy (port3Name, p3); + } + case 2: /* lukkeknapp for dialogboks, vet ikke makronavnet for den */ + case IDD_AVBRYT: + EndDialog (hdwnd, 0); + break; + } + break; + } + return 0; +} +/* hent inn diskbilde fra fil */ +static void getDiskImage (int drive) { + OPENFILENAME fname; + char fn[256] = "\0"; + HANDLE hFile; + + memset (&fname, 0, sizeof (OPENFILENAME)); + fname.lStructSize = sizeof (OPENFILENAME); + fname.hwndOwner = hwnd; + fname.lpstrFile = fn; + fname.nMaxFile = sizeof (fn); + fname.Flags = OFN_FILEMUSTEXIST; + + if (GetOpenFileName (&fname)) { + if ((hFile = CreateFile (fn, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL)) != INVALID_HANDLE_VALUE) { + fileSize[drive] = GetFileSize (hFile, NULL); + free (dsk[drive]); + if ((dsk[drive] = (byte *)malloc (fileSize[drive]))) { + DWORD dwRead; + if (ReadFile (hFile, dsk[drive], fileSize[drive], &dwRead, NULL)) { + switch (fileSize[drive]) { + case 40*1*18*128: + EnableMenuItem (GetSubMenu (GetMenu (hwnd), 1), drive == 0 ? IDM_LAGRE_A : IDM_LAGRE_B, + MF_BYCOMMAND | MF_ENABLED); + insertDisk (drive, dsk[drive], 40, 1, 18, 128); + break; + case 40*1*10*512: + EnableMenuItem (GetSubMenu (GetMenu (hwnd), 1), drive == 0 ? IDM_LAGRE_A : IDM_LAGRE_B, + MF_BYCOMMAND | MF_ENABLED); + insertDisk (drive, dsk[drive], 40, 1, 10, 512); + break; + case 40*2*10*512: + EnableMenuItem (GetSubMenu (GetMenu (hwnd), 1), drive == 0 ? IDM_LAGRE_A : IDM_LAGRE_B, + MF_BYCOMMAND | MF_ENABLED); + insertDisk (drive, dsk[drive], 40, 2, 10, 512); + break; + case 80*2*10*512: + EnableMenuItem (GetSubMenu (GetMenu (hwnd), 1), drive == 0 ? IDM_LAGRE_A : IDM_LAGRE_B, + MF_BYCOMMAND | MF_ENABLED); + insertDisk (drive, dsk[drive], 80, 2, 10, 512); + break; + default: + removeDisk (drive); + fileSize[drive] = 0; + } + } + } + CloseHandle (hFile); + } + } +} +/* lagre diskbilde til fil */ +static void saveDiskImage (int drive) { + OPENFILENAME fname; + char fn[256] = "\0"; + HANDLE hFile; + + memset (&fname, 0, sizeof (OPENFILENAME)); + fname.lStructSize = sizeof (OPENFILENAME); + fname.hwndOwner = hwnd; + fname.lpstrFile = fn; + fname.nMaxFile = sizeof (fn); + fname.Flags = OFN_HIDEREADONLY; + + if (GetSaveFileName (&fname)) { + if ((hFile = CreateFile (fn, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL)) + != INVALID_HANDLE_VALUE) { + DWORD dwWritten; + WriteFile (hFile, dsk[drive], fileSize[drive], &dwWritten, NULL); + CloseHandle (hFile); + } + } +} +/* Forandre oppløsning */ +void changeRes (int newRes) { + RECT windowRect; + + switch (newRes) { + case HIGHRES: + width = 1024; + height = 256 * (scanlines ? 4 : 1); + break; + case MEDRES: + width = 512 * size80x; + height = 256 * size80x * (scanlines ? 2 : 1); + break; + case LOWRES: + default: + width = 256 * size40x; + height = 256 * size40x; + break; + } + GetWindowRect (hwnd, &windowRect); + MoveWindow (hwnd, windowRect.left, windowRect.top, width + 2 * GetSystemMetrics (SM_CXFIXEDFRAME), + height + 2 * GetSystemMetrics (SM_CYFIXEDFRAME) + GetSystemMetrics (SM_CYCAPTION) + + GetSystemMetrics (SM_CYMENU) + STATUSBAR_HEIGHT, 1); + /* slett bakgrunn */ + SelectObject (memdc, GetStockObject (BLACK_BRUSH)); + PatBlt (memdc, 0, 0, width, height, PATCOPY); + if (newRes != resolution) { + memset (screen, 0, 1024*256); + resolution = newRes; + } + /* oppdater vindu */ + InvalidateRect (hwnd, NULL, FALSE); +} +/* Plotter en pixel med farge tatt fra pallett */ +void plotPixel (int x, int y, int color) { + screen[x+y*1024] = color; + switch (resolution) { + case HIGHRES: + y *= scanlines ? 4 : 1; + break; + case MEDRES: + x *= size80x; + y *= size80x * (scanlines ? 2 : 1); + break; + case LOWRES: + x *= size40x; + y *= size40x; + break; + } + SetPixelV (memdc, x, y, colors[color]); + update (x, y, 1, 1); +} +/* Scroller skjerm 'distance' linjer oppover */ +void scrollScreen (int distance) { + /* scroll screen */ + if (distance > 0) { + memmove (screen, screen + distance * 1024, (256 - distance) * 1024); + memset (screen + distance * 1024, 0, (256 - distance) * 1024); + } else { + memmove (screen + -(distance * 1024), screen, (byte)distance * 1024); + memset (screen, 0, -distance * 1024); + } + /* finn avstand */ + switch (resolution) { + case HIGHRES: + distance *= scanlines ? 4 : 1; + break; + case MEDRES: + distance *= size80x * (scanlines ? 2 : 1); + break; + case LOWRES: + default: + distance *= size40x; + break; + } + /* scroll memdc */ + BitBlt (memdc, 0, -distance, width, height + distance, memdc, 0, 0, SRCCOPY); + SelectObject (memdc, GetStockObject (BLACK_BRUSH)); + /* slett resten */ + if (distance > 0) { + PatBlt (memdc, 0, height - distance, width, distance, PATCOPY); + } else { + PatBlt (memdc, 0, 0, width, -distance, PATCOPY); + } + /* oppdater vindu */ + InvalidateRect (hwnd, NULL, FALSE); +} +/* Ny farge, gitt pallett nummer og intensitet 0-255 */ +void changePalette (int colornumber, byte red, byte green, byte blue) { + if (colors[colornumber] != RGB (red, green, blue)) { + int x, y; + + colors[colornumber] = RGB (red, green, blue); + + /* oppdater pixler med denne fargen */ + for (y = 0; y < 256; y++) { + for (x = 0; x < 1024; x++) { + if (screen[x+y*1024] == colornumber) { + plotPixel (x, y, colornumber); + } + } + } + } +} +/* Kalles periodisk. Lar system kode måle / senke emuleringshastighet + * Kan også brukes til sjekk av brukeraktivitet + * ms er antall "emulerte" millisekunder siden forrige gang loopEmul ble kalt + */ +void loopEmul (int ms) { + /* senk hastigheten */ + if (slowDown) { + static boolean firstTime = TRUE; + static LARGE_INTEGER lastTime; + LARGE_INTEGER currentTime; + static LARGE_INTEGER freq; + + if (QueryPerformanceCounter (¤tTime)) { + if (firstTime) { + QueryPerformanceFrequency (&freq); + lastTime = currentTime; + firstTime = FALSE; + } else { + long sleepPeriod = ms - ((currentTime.QuadPart - lastTime.QuadPart) * 1000 / freq.QuadPart); + + lastTime = currentTime; + + if (sleepPeriod > 0) { + Sleep (sleepPeriod); + QueryPerformanceCounter (&lastTime); + } + } + } + } + /* oppdater skjerm */ + if (updateWindow) { + RECT rect = {xmin, ymin, xmax, ymax}; + InvalidateRect (hwnd, &rect, FALSE); + xmin = (unsigned)~0, ymin = (unsigned)~0, xmax = 0, ymax = 0; + updateWindow = FALSE; + } + /* sjekk seriekanaler */ + { + DWORD error; + COMSTAT comstat; + + if (port1) { + if (ClearCommError (port1, &error, &comstat)) { + if (comstat.cbInQue != 0) { + charAvailable (0); + } + } + } + if (port2) { + if (ClearCommError (port2, &error, &comstat)) { + if (comstat.cbInQue != 0) { + charAvailable (1); + } + } + } + } + /* sjekk om der er events som venter */ + { + MSG msg; + + while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE)) { + if (msg.message == WM_QUIT) { + DeleteDC (memdc); + DeleteObject (hbit); + quitEmul(); + } else { + DispatchMessage (&msg); + } + } + } +} +/* Tenn/slukk lock lys */ +void lockLight (boolean status) { + HBRUSH brush = (status ? + GetSysColorBrush (COLOR_HIGHLIGHT) : + GetSysColorBrush (COLOR_3DFACE)); + SelectObject (memdc, brush); + PatBlt (memdc, 21, height + 6, 7, 7, PATCOPY); + update (21, height + 6, 7, 7); + lock = status; +} +/* Tenn/slukk grafikk lys */ +void grafikkLight (boolean status) { + HBRUSH brush = (status ? + GetSysColorBrush (COLOR_HIGHLIGHT) : + GetSysColorBrush (COLOR_3DFACE)); + SelectObject (memdc, brush); + PatBlt (memdc, 41, height + 6, 7, 7, PATCOPY); + update (41, height + 6, 7, 7); + grafikk = status; +} +/* Tenn/slukk disk lys for gitt stasjon */ +void diskLight (int drive, boolean status) { + int x = (drive ? 81 : 61); + HBRUSH brush = (status ? + GetSysColorBrush (COLOR_HIGHLIGHT) : + GetSysColorBrush (COLOR_3DFACE)); + SelectObject (memdc, brush); + PatBlt (memdc, x, height + 6, 7, 7, PATCOPY); + update (61, height + 6, 7, 7); + disk[drive] = status; +} +static void update (int x, int y, int w, int h) { + if (xmin > x) xmin = x; + if (ymin > y) ymin = y; + if (xmax < (x + w)) xmax = x + w; + if (ymax < (y + h)) ymax = y + h; + updateWindow = TRUE; +} +/* Sjekk status til hver av de gitte tastene + * Sett bit n i returkode hvis tast n IKKE er nedtrykt + * Taster er enten ascii-kode eller en av konstantene over + */ +byte testKey (byte keys[8]) { + return pressedKeys[keys[0]] | (pressedKeys[keys[1]] << 1) | (pressedKeys[keys[2]] << 2) | + (pressedKeys[keys[3]] << 3) | (pressedKeys[keys[4]] << 4) | (pressedKeys[keys[5]] << 5) | + (pressedKeys[keys[6]] << 6) | (pressedKeys[keys[7]] << 7); +} +/* setter seriekanalparametre */ +void setParams (struct serParams *p1Params, struct serParams *p2Params) { + if (port1) setParam (port1, p1Params); + if (port2) setParam (port2, p2Params); +} +static void setParam (HANDLE portHandle, struct serParams *params) { + DCB dcb = {sizeof (DCB), + 0, /* BaudRate */ + TRUE, /* fBinary */ + 0, /* fParity */ + FALSE, /* fOutxCtsFlow */ + FALSE, /* fOutxDsrFlow */ + DTR_CONTROL_ENABLE, /* fDtrControl */ + FALSE, /* fDsrSensitivity */ + TRUE, /* fTXContinueOnXoff */ + FALSE, /* fOutX */ + FALSE, /* fInX */ + FALSE, /* fErrorChar */ + FALSE, /* fNull */ + RTS_CONTROL_ENABLE, /* fRtsControl */ + FALSE, /* fAbortOnError */ + 17, /* fDummy2 */ + 0, /* wReserved */ + 0, /* XonLim */ + 0, /* XoffLim */ + 0, /* ByteSize */ + 0, /* Parity */ + 0, /* StopBits */ + 0, /* XonChar */ + 0, /* XoffChar */ + 0, /* ErrorChar */ + -1, /* EofChar */ + 0, /* EvtChar */ + 0}; /* wReservedl */ + + dcb.BaudRate = params->baud; + dcb.BaudRate = dcb.BaudRate - dcb.BaudRate % 100; + + dcb.ByteSize = params->sendBits; /* obs: receiveBits blir ikke tatt hensyn til */ + switch (params->parity) { + case PAR_NONE: + dcb.Parity = NOPARITY; + dcb.fParity = FALSE; + break; + case PAR_EVEN: + dcb.Parity = EVENPARITY; + dcb.fParity = TRUE; + break; + case PAR_ODD: + dcb.Parity = ODDPARITY; + dcb.fParity = TRUE; + break; + } + switch (params->stopBits) { + case ONE_SB: dcb.StopBits = ONESTOPBIT; break; + case ONE_PT_FIVE_SB: dcb.StopBits = ONE5STOPBITS; break; + case TWO_SB: dcb.StopBits = TWOSTOPBITS; break; + } + + if (!SetCommState(portHandle, &dcb)) { + /* ingen aksjon */ + } + return; +} +/* send tegn til seriekanal */ +void sendChar (int port, byte value) { + DWORD bytesWritten; + HANDLE portHandle = port ? port2 : port1; + + if (portHandle) { + if (!WriteFile (portHandle, &value, 1, &bytesWritten, NULL)) { + /* kan ikke skrive til port */ + } + } +} +/* hent tegn fra seriekanal */ +byte getChar (int port) { + HANDLE portHandle = port ? port2 : port1; + byte value = 0; + DWORD bytesRead; + + if (portHandle) { + if (!ReadFile (portHandle, &value, 1, &bytesRead, NULL)) { + /* kan ikke lese fra port */ + } + + /* flere tegn i buffer? */ + { + DWORD error; + COMSTAT comstat; + + if (ClearCommError (portHandle, &error, &comstat)) { + if (comstat.cbInQue != 0) { + charAvailable (port); + } + } + } + } + return value; +} +/* send tegn til skriver */ +void printChar (byte value) { + DWORD bytesWritten; + + if (port3) { + if (!WriteFile (port3, &value, 1, &bytesWritten, NULL)) { + /* kan ikke skrive til port */ + } + } +} diff --git a/TIKI-100_emul-src/win32.ico b/TIKI-100_emul-src/win32.ico new file mode 100644 index 0000000..b917c31 Binary files /dev/null and b/TIKI-100_emul-src/win32.ico differ diff --git a/TIKI-100_emul-src/win32_res.h b/TIKI-100_emul-src/win32_res.h new file mode 100644 index 0000000..6fed3e2 --- /dev/null +++ b/TIKI-100_emul-src/win32_res.h @@ -0,0 +1,39 @@ +/* win32_res.h V1.1.0 + * + * Konstanter for win32 ressurser + * Copyright (C) Asbjørn Djupdal 2000-2001 + */ + +#include "TIKI-100_emul.h" + +#define IDM_RESET 0 +#define IDM_INNSTILLINGER 1 +#define IDM_OM 2 +#define IDM_AVSLUTT 3 +#define IDM_HENT_A 4 +#define IDM_HENT_B 5 +#define IDM_LAGRE_A 6 +#define IDM_LAGRE_B 7 +#define IDM_FJERN_A 8 +#define IDM_FJERN_B 9 + +#ifdef DEBUG +#define IDM_MONITOR 10 +#endif + +#define IDD_HASTIGHET 11 +#define IDD_BEVARFORHOLD 12 +#define IDD_SOLID 13 +#define IDD_40SPIN 14 +#define IDD_80SPIN 15 +#define IDD_40EDIT 16 +#define IDD_80EDIT 17 +#define IDD_OK 18 +#define IDD_AVBRYT 19 +#define IDD_P1EDIT 20 +#define IDD_P2EDIT 21 +#define IDD_P3EDIT 22 +#define IDD_P1 23 +#define IDD_P2 24 +#define IDD_P3 25 +#define IDD_ST28B 26 diff --git a/TIKI-100_emul-src/win32_res.rc b/TIKI-100_emul-src/win32_res.rc new file mode 100644 index 0000000..6e549d6 --- /dev/null +++ b/TIKI-100_emul-src/win32_res.rc @@ -0,0 +1,59 @@ +/* win32_res.rc V1.1.0 + * + * Win32 resources for TIKI-100_emul + * Copyright (C) Asbjørn Djupdal 2000-2001 + */ + +#include +#include "win32_res.h" +#include "TIKI-100_emul.h" + +menu MENU { + POPUP "&Emulator" { + MENUITEM "&Reset", IDM_RESET + MENUITEM "&Innstillinger...", IDM_INNSTILLINGER + MENUITEM "&Om...", IDM_OM + MENUITEM "&Avslutt", IDM_AVSLUTT + } + POPUP "&Diskettstasjon" { + MENUITEM "Hent plate &A...", IDM_HENT_A + MENUITEM "Hent plate &B...", IDM_HENT_B + MENUITEM "Lagre plate A...", IDM_LAGRE_A, GRAYED + MENUITEM "Lagre plate B...", IDM_LAGRE_B, GRAYED + MENUITEM "Fjern plate A", IDM_FJERN_A + MENUITEM "Fjern plate B", IDM_FJERN_B + } +#ifdef DEBUG + POPUP "&Debug" { + MENUITEM "&Monitor...", IDM_MONITOR + } +#endif +} + +dialog DIALOG DISCARDABLE 30, 30, 269, 137 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "TIKI-100_emul innstillinger" +{ + DEFPUSHBUTTON "OK", IDD_OK, 155, 114, 50, 14 + PUSHBUTTON "Avbryt", IDD_AVBRYT, 211, 114, 50, 14 + + AUTOCHECKBOX "Senk hastighet", IDD_HASTIGHET, 7, 7, 63, 10 + + GROUPBOX "Skjermforstørring", -1, 7, 26, 121, 78 + EDITTEXT IDD_40EDIT, 21, 42, 25, 14, ES_LEFT | WS_CHILD | WS_VISIBLE | WS_BORDER + EDITTEXT IDD_80EDIT, 21, 61, 25, 14, ES_LEFT | WS_CHILD | WS_VISIBLE | WS_BORDER + LTEXT "40 tegns skjerm", -1, 55, 45, 60, 8 + LTEXT "80 tegns skjerm", -1, 55, 64, 60, 8 + AUTOCHECKBOX "Bevar forhold", IDD_BEVARFORHOLD, 21, 80, 58, 10 + + GROUPBOX "Porter", -1, 133, 9, 128, 95 + AUTOCHECKBOX "Sett ST 28 b", IDD_ST28B, 145, 23, 56, 10 + EDITTEXT IDD_P1EDIT, 145, 42, 42, 14, ES_AUTOHSCROLL + EDITTEXT IDD_P2EDIT, 145, 61, 42, 14, ES_AUTOHSCROLL + EDITTEXT IDD_P3EDIT, 145, 80, 42, 14, ES_AUTOHSCROLL + AUTOCHECKBOX "Serieport P1", IDD_P1, 193, 45, 63, 8 + AUTOCHECKBOX "Serieport P2", IDD_P2, 193, 64, 63, 8 + AUTOCHECKBOX "Parallellport P3", IDD_P3, 193, 83, 63, 8 +} + +icon ICON win32.ico