/*****************************************************************************/ /* */ /* */ /* CP/M emulator version 0.1 */ /* */ /* written by Michael Bischoff (mbi@mo.math.nat.tu-bs.de) */ /* June-1994 */ /* */ /* This file is distributed under the GNU COPYRIGHT */ /* see COPYRIGHT.GNU for Copyright details */ /* */ /* */ /*****************************************************************************/ #define NALIGN 2 /* 2, 3, or 4 (4 is 1% faster than 2) */ /* comment: PC (stored in %esi) is incremented as 32-bit counter (faster!), therefore a fall-through to addresses after 64 KB is possible. We catch such programs with a couple of HALTs stored after 64 KB. A similar problem is accessing word data at 0xffff! */ #define EXIT exitemu /* illegal opcodes for 8080 */ #define GETIXOFF movsbl (%ebp,%esi),%edi;incl %esi;addl z80regs+32,%edi #define GETIYOFF movsbl (%ebp,%esi),%edi;incl %esi;addl z80regs+36,%edi #define IX z80regs+32 #define IY z80regs+36 .data .align 2 jumptab: .long op00, op01, op02, op03, op04, op05, op06, op07 .long op08, op09, op0a, op0b, op0c, op0d, op0e, op0f .long op10, op11, op12, op13, op14, op15, op16, op17 .long op18, op19, op1a, op1b, op1c, op1d, op1e, op1f .long op20, op21, op22, op23, op24, op25, op26, op27 .long op28, op29, op2a, op2b, op2c, op2d, op2e, op2f .long op30, op31, op32, op33, op34, op35, op36, op37 .long op38, op39, op3a, op3b, op3c, op3d, op3e, op3f /* load commands: op00 are NOPs */ .long op00, op41, op42, op43, op44, op45, op46, op47 .long op48, op00, op4a, op4b, op4c, op4d, op4e, op4f .long op50, op51, op00, op53, op54, op55, op56, op57 .long op58, op59, op5a, op00, op5c, op5d, op5e, op5f .long op60, op61, op62, op63, op00, op65, op66, op67 .long op68, op69, op6a, op6b, op6c, op00, op6e, op6f .long op70, op71, op72, op73, op74, op75, EXIT, op77 .long op78, op79, op7a, op7b, op7c, op7d, op7e, op00 .long op80, op81, op82, op83, op84, op85, op86, op87 .long op88, op89, op8a, op8b, op8c, op8d, op8e, op8f .long op90, op91, op92, op93, op94, op95, op96, op97 .long op98, op99, op9a, op9b, op9c, op9d, op9e, op9f .long opa0, opa1, opa2, opa3, opa4, opa5, opa6, opa7 .long opa8, opa9, opaa, opab, opac, opad, opae, opaf .long opb0, opb1, opb2, opb3, opb4, opb5, opb6, opb7 .long opb8, opb9, opba, opbb, opbc, opbd, opbe, opbf .long opc0, opc1, opc2, opc3, opc4, opc5, opc6, opc7 .long opc8, opc9, opca, opcb, opcc, opcd, opce, opcf .long opd0, opd1, opd2, opd3, opd4, opd5, opd6, opd7 .long opd8, opd9, opda, EXIT, opdc, opdd, opde, opdf .long ope0, ope1, ope2, ope3, ope4, ope5, ope6, ope7 .long ope8, ope9, opea, opeb, opec, oped, opee, opef .long opf0, opf1, opf2, opf3, opf4, opf5, opf6, opf7 .long opf8, opf9, opfa, opfb, opfc, opfd, opfe, opff jumptab3: .long cb00, cb01, cb02, cb03, cb04, cb05, cb06, cb07 .long cb08, cb09, cb0a, cb0b, cb0c, cb0d, cb0e, cb0f .long cb10, cb11, cb12, cb13, cb14, cb15, cb16, cb17 .long cb18, cb19, cb1a, cb1b, cb1c, cb1d, cb1e, cb1f .long cb20, cb21, cb22, cb23, cb24, cb25, cb26, cb27 .long cb28, cb29, cb2a, cb2b, cb2c, cb2d, cb2e, cb2f .long EXIT2,EXIT2,EXIT2,EXIT2,EXIT2,EXIT2,EXIT2,EXIT2 .long cb38, cb39, cb3a, cb3b, cb3c, cb3d, cb3e, cb3f .long cb40, cb41, cb42, cb43, cb44, cb45, cb46, cb47 .long cb48, cb49, cb4a, cb4b, cb4c, cb4d, cb4e, cb4f .long cb50, cb51, cb52, cb53, cb54, cb55, cb56, cb57 .long cb58, cb59, cb5a, cb5b, cb5c, cb5d, cb5e, cb5f .long cb60, cb61, cb62, cb63, cb64, cb65, cb66, cb67 .long cb68, cb69, cb6a, cb6b, cb6c, cb65, cb6e, cb6f .long cb70, cb71, cb72, cb73, cb74, cb75, cb76, cb77 .long cb78, cb79, cb7a, cb7b, cb7c, cb7d, cb7e, cb7f .long cb80, cb81, cb82, cb83, cb84, cb85, cb86, cb87 .long cb88, cb89, cb8a, cb8b, cb8c, cb8d, cb8e, cb8f .long cb90, cb91, cb92, cb93, cb94, cb95, cb96, cb97 .long cb98, cb99, cb9a, cb9b, cb9c, cb9d, cb9e, cb9f .long cba0, cba1, cba2, cba3, cba4, cba5, cba6, cba7 .long cba8, cba9, cbaa, cbab, cbac, cbad, cbae, cbaf .long cbb0, cbb1, cbb2, cbb3, cbb4, cbb5, cbb6, cbb7 .long cbb8, cbb9, cbba, cbbb, cbbc, cbbd, cbbe, cbbf .long cbc0, cbc1, cbc2, cbc3, cbc4, cbc5, cbc6, cbc7 .long cbc8, cbc9, cbca, cbcb, cbcc, cbcd, cbce, cbcf .long cbd0, cbd1, cbd2, cbd3, cbd4, cbd5, cbd6, cbd7 .long cbd8, cbd9, cbda, cbdb, cbdc, cbdd, cbde, cbdf .long cbe0, cbe1, cbe2, cbe3, cbe4, cbe5, cbe6, cbe7 .long cbe8, cbe9, cbea, cbeb, cbec, cbed, cbee, cbef .long cbf0, cbf1, cbf2, cbf3, cbf4, cbf5, cbf6, cbf7 .long cbf8, cbf9, cbfa, cbfb, cbfc, cbfd, cbfe, cbff .text #define opcode(n) .align NALIGN,0x90 /* the registers have the following contents: esi = pc ebp = sp nope, z80mem! ecx = bc edx = de ebx = hl eax = af edi = temporary storage the other registers are kept in memory */ #define inc8mac(reg) /* increment 8 Bit Register */\ andb $0x29,%ah; /* clear all but carry & untrusted flags */\ incb reg; \ jmp setincdec_386 #define dec8mac(reg) /* increment 8 Bit Register */\ andb $0x29,%ah; /* clear all but carry & untrusted flags */\ orb $2,%ah; \ decb reg; \ jmp setincdec_386 .align 4,0x90 EXIT2: decl %esi jmp exitemu opcode(0x00) /* NOP */ op00: dispatch opcode(0x01) /* LD BC,nnnn */ op01: movzwl (%esi,%ebp,1),%ecx incl %esi incl %esi dispatch opcode (0x02) /* LD (BC),A */ op02: movb %al,(%ebp,%ecx,1) dispatch opcode (0x03) /* INC BC */ op03: incw %cx dispatch opcode (0x04) /* INC B */ op04: inc8mac(%ch) opcode (0x05) /* DEC B */ op05: dec8mac(%ch) opcode (0x06) /* LD B,nn */ op06: movb (%esi,%ebp),%ch incl %esi dispatch opcode (0x07) /* RLCA */ op07: andb $0xec,%ah rolb $1,%al adcb $0,%ah dispatch opcode (0x08) /* EX AF,AF' */ op08: xchgl z80regs+52,%eax dispatch opcode (0x09) /* ADD HL,BC */ op09: andb $0xec,%ah /* clear some Flags ### H noch falsch */ addw %cx,%bx adcb $0,%ah /* set carry flag if necessary (8 Byte) */ dispatch opcode (0x0a) /* LD A,(BC) */ op0a: movb (%ebp,%ecx,1),%al dispatch opcode (0x0b) /* DEC BC */ op0b: decw %cx dispatch opcode (0x0c) /* INC C */ op0c: inc8mac(%cl) opcode (0x0d) /* DEC C */ op0d: dec8mac(%cl) opcode (0x0e) /* LD C,nn */ op0e: movb (%esi,%ebp),%cl incl %esi dispatch opcode (0x0f) /* RRCA */ op0f: andb $0xec,%ah rorb $1,%al adcb $0,%ah dispatch opcode (0x10) /* DJNZ disp */ op10: decb %ch jnz op18 /* to JR disp */ incl %esi dispatch opcode (0x11) /* LD DE,nnnn */ op11: movzwl (%esi,%ebp),%edx incl %esi incl %esi dispatch opcode (0x12) /* LD (DE),A */ op12: movb %al,(%ebp,%edx) dispatch opcode (0x13) /* INC DE */ op13: incw %dx dispatch opcode (0x14) /* INC D */ op14: inc8mac(%dh) opcode (0x15) /* DEC D */ op15: dec8mac(%dh) opcode (0x16) /* LD D,nn */ op16: movb (%esi,%ebp),%dh incl %esi dispatch opcode (0x17) /* RLA */ op17: sahf rclb $1,%al xchg %eax,%edi lahf andl $0x0100,%eax andl $0xecff,%edi orl %edi,%eax dispatch opcode (0x18) /* JR disp */ op18: movsbl (%esi,%ebp),%edi incl %esi addl %edi,%esi /* BEWARE! check range 0-xffff */ andl $0xffff,%esi dispatch opcode (0x19) /* ADD HL,DE */ op19: andb $0xec,%ah /* clear some Flags ### H noch falsch */ addw %dx,%bx adc $0,%ah dispatch opcode (0x1a) /* LD A,(DE) */ op1a: movb (%edx,%ebp),%al dispatch opcode (0x1b) /* DEC DE */ op1b: decw %dx dispatch opcode (0x1c) /* INC E */ op1c: inc8mac(%dl) opcode (0x1d) /* DEC E */ op1d: dec8mac(%dl) opcode (0x1e) /* LD E,nn */ op1e: movb (%esi,%ebp),%dl incl %esi dispatch opcode (0x1f) /* RRA */ op1f: sahf rcrb $1,%al xchg %eax,%edi lahf andl $0x0100,%eax andl $0xecff,%edi orl %edi,%eax dispatch opcode (0x20) /* JR NZ,disp */ op20: sahf jnz op18 incl %esi dispatch opcode (0x21) /* LD HL,nnnn */ op21: movw (%esi,%ebp),%bx incl %esi incl %esi dispatch opcode (0x22) /* LD (nnnn),HL */ op22: movzwl (%esi,%ebp),%edi movw %bx,(%edi,%ebp) incl %esi incl %esi dispatch opcode (0x23) /* INC HL */ op23: incw %bx dispatch opcode (0x24) /* INC H */ op24: inc8mac(%bh) dispatch opcode (0x25) /* DEC H */ op25: dec8mac(%bh) dispatch opcode (0x26) /* LD H,nn */ op26: movb (%esi,%ebp),%bh incl %esi dispatch opcode (0x27) /* DAA */ op27: test $2,%ah jnz addsub sahf daa jmp afterdaa addsub: sahf das afterdaa: movl %eax,%edi lahf andl $0x0200,%edi andb $0xd5,%ah orl %edi,%eax dispatch opcode (0x28) /* JR Z,disp */ op28: sahf jz op18 incl %esi dispatch opcode (0x29) /* ADD HL,HL */ op29: andb $0xec,%ah /* clear some Flags ### H noch falsch */ addw %bx,%bx adc $0,%ah dispatch opcode (0x2a) /* LD HL,(nnnn) */ op2a: movzwl (%esi,%ebp),%edi movw (%edi,%ebp),%bx incl %esi incl %esi dispatch opcode (0x2b) /* DEC HL */ op2b: decw %bx dispatch opcode (0x2c) /* INC L */ op2c: inc8mac(%bl) opcode (0x2d) /* DEC L */ op2d: dec8mac(%bl) opcode (0x2e) /* LD L,nn */ op2e: movb (%esi,%ebp),%bl incl %esi dispatch opcode (0x1f) /* CPL */ op2f: notb %al orb $0x12,%ah dispatch opcode (0x30) /* JR NC,disp */ op30: sahf jnc op18 incl %esi dispatch opcode (0x31) /* LD SP,nnnn */ op31: movzwl (%esi,%ebp),%edi movl %edi,z80regs+4 incl %esi incl %esi dispatch opcode (0x32) /* LD (nnnn),A */ op32: movzwl (%esi,%ebp),%edi movb %al,(%edi,%ebp) incl %esi incl %esi dispatch opcode (0x33) /* INC SP */ op33: incw z80regs+4 dispatch opcode (0x34) /* INC (HL) */ op34: inc8mac((%ebp,%ebx)) dispatch opcode (0x35) /* DEC (HL) */ op35: dec8mac((%ebp,%ebx)) dispatch opcode (0x36) /* LD (HL),nn */ op36: xchgl %edi,%eax movb (%esi,%ebp),%al movb %al,(%ebx,%ebp) xchgl %edi,%eax incl %esi dispatch opcode (0x37) /* SCF */ op37: andb $0xec,%ah orb $1,%ah dispatch opcode (0x38) /* JR C,disp */ op38: sahf jc op18 incl %esi dispatch opcode (0x39) /* ADD HL,SP */ op39: andb $0xec,%ah /* clear some Flags ### H noch falsch */ addw z80regs+4,%bx adc $0,%ah dispatch opcode (0x3a) /* LD A,(nnnn) */ op3a: movzwl (%esi,%ebp),%edi movb (%edi,%ebp),%al incl %esi incl %esi dispatch opcode (0x3b) /* DEC SP */ op3b: decw z80regs+4 dispatch opcode (0x3c) /* INC A */ op3c: inc8mac(%al) opcode (0x3d) /* DEC A */ op3d: dec8mac(%al) opcode (0x3e) /* LD A,nn */ op3e: movb (%esi,%ebp),%al incl %esi dispatch opcode (0x3f) /* CCF */ op3f: andb $0xed,%ah xorb $1,%ah /* ### H noch falsch */ /* H sollte Wert des alten Carry haben */ dispatch setincdec_386: xchg %eax,%edi lahf seto %al shlb $2,%al andb $0xd0,%ah /* S,Z,H */ orb %al,%ah xorb %al,%al orl %edi,%eax dispatch #include "loads.s" setaddadc: movl %eax,%edi lahf seto %al shlb $2,%al andb $0xd1,%ah orb %al,%ah andl $0x2ff,%edi xorb %al,%al orl %edi,%eax dispatch /* Opcodes 0xc0 - 0xff */ opcode (0xc1) /* POP BC */ opc1: movl z80regs+4,%edi movw (%edi,%ebp),%cx jmp dopop opcode (0xd1) /* POP DE */ opd1: movl z80regs+4,%edi movw (%edi,%ebp),%dx jmp dopop opcode (0xe1) /* POP HL */ ope1: movl z80regs+4,%edi movw (%edi,%ebp),%bx jmp dopop opcode (0xf1) /* POP AF */ opf1: movl z80regs+4,%edi movw (%edi,%ebp),%ax xchg %al,%ah jmp dopop opcode (0xc3) /* JP add16 */ opc3: movzwl (%ebp,%esi),%esi dispatch opcode (0xc5) /* PUSH BC */ opc5: movl z80regs+4,%edi decw %di decw %di movw %cx,(%ebp,%edi) movl %edi,z80regs+4 dispatch opcode (0xd5) /* PUSH DE */ opd5: movl z80regs+4,%edi decw %di decw %di movw %dx,(%ebp,%edi) movl %edi,z80regs+4 dispatch opcode (0xe5) /* PUSH HL */ ope5: movl z80regs+4,%edi decw %di decw %di movw %bx,(%ebp,%edi) movl %edi,z80regs+4 dispatch opcode (0xf5) /* PUSH AF */ opf5: movl z80regs+4,%edi decw %di decw %di xchg %al,%ah movw %ax,(%ebp,%edi) xchg %al,%ah movl %edi,z80regs+4 dispatch opcode (0xc7) /* RST 00h */ opc7: xorl %edi,%edi jmp docall_di opcode (0xc9) /* RET */ opc9: movl z80regs+4,%edi movzwl (%ebp,%edi),%esi dopop: incl %edi incl %edi movl %edi,z80regs+4 dispatch opcode (0xcd) /* CALL add16 */ opcd: movzwl (%ebp,%esi),%edi incl %esi incl %esi docall_di: /* push esi to stack (return address) */ pushl %edi movl z80regs+4,%edi decw %di decw %di movw %si,(%ebp,%edi) movl %edi,z80regs+4 popl %esi dispatch opcode (0xc6) /* ADD A,nn */ opc6: andb $0xd5,%ah addb (%esi,%ebp),%al jmp setaddadc2 opcode (0xce) /* ADC A,nn */ opce: andb $0xd5,%ah sahf adcb (%ebp,%esi),%al jmp setaddadc2 opcode (0xd6) /* SUB nn */ opd6: orb $2,%ah subb (%esi,%ebp),%al jmp setaddadc2 opcode (0xde) /* SBC A,nn */ opde: orb $2,%ah sahf sbbb (%esi,%ebp),%al jmp setaddadc2 opcode (0xe6) /* AND nn */ ope6: andb (%esi,%ebp),%al lahf incl %esi orb $0x10,%ah andb $0xd4,%ah dispatch opcode (0xee) /* XOR nn */ opee: xorb (%esi,%ebp),%al lahf and $0xc4,%ah incl %esi dispatch opcode (0xf6) /* OR nn */ opf6: orb (%ebp,%esi),%al lahf incl %esi andb $0xc4,%ah dispatch opcode (0xfe) /* CP nn */ opfe: orb $2,%ah cmpb (%ebp,%esi),%al jmp setaddadc2 opcode (0xd9) /* EXX */ opd9: xchgl %ecx,z80regs+40 xchgl %edx,z80regs+44 xchgl %ebx,z80regs+48 dispatch opcode (0xe3) /* EX (SP),HL */ ope3: movl z80regs+4,%edi xchgw (%edi,%ebp),%bx dispatch opcode (0xe9) /* JP (HL) */ ope9: movl %ebx,%esi dispatch opcode (0xeb) /* EX DE,HL */ opeb: xchgl %ebx,%edx dispatch opcode (0xf3) /* DI */ opf3: movl $0x101,z80regs+56 /* only set Interrupt Flip-flops */ dispatch opcode (0xf9) /* LD SP,HL */ opf9: movl %ebx,z80regs+4 dispatch opcode (0xfb) /* EI */ opfb: movl $0,z80regs+56 /* only set Interrupt Flip-flops */ dispatch opcode (0xed) /* z80-commands */ oped: movzbl (%esi,%ebp),%edi inc %esi sall $2,%edi jmp *jumptab2(%edi) opcode (0xcb) /* z80 */ opcb: movzbl (%esi,%ebp),%edi inc %esi sall $2,%edi pushl jumptab3(%edi) movl %ebx,%edi /* ordinary HL */ ret opcode (0xcb) /* z80 */ ixcb: GETIXOFF /* IX + offset, offset before opcode!!! */ pushl %edi movzbl (%esi,%ebp),%edi inc %esi sall $2,%edi movl jumptab3(%edi),%edi xchg %edi,(%esp) ret opcode (0xcb) /* z80 */ iycb: GETIYOFF /* IY + offset */ pushl %edi movzbl (%esi,%ebp),%edi inc %esi sall $2,%edi movl jumptab3(%edi),%edi xchg %edi,(%esp) ret setaddadc2: movl %eax,%edi lahf seto %al shlb $2,%al andb $0xd1,%ah orb %al,%ah andl $0x2ff,%edi xorb %al,%al orl %edi,%eax incl %esi dispatch setbit: xchg %eax,%edi lahf andl $0x4000,%eax orl $0x100,%eax andl $0xbdff,%edi orl %edi,%eax dispatch /* extended Z80-commands: ix, iy prefix */ opcode (0xdd) opdd: movzbl (%esi,%ebp),%edi inc %esi sall $2,%edi jmp *jumptabix(%edi) opcode (0xfd) opfd: movzbl (%esi,%ebp),%edi inc %esi sall $2,%edi jmp *jumptabiy(%edi) /* out command: if no hardware access allowed, or if port != 0x61, */ /* trap this opcode and enter debugger */ opcode (0xd3) opd3: movl hardware_access,%edi orl %edi,%edi jz EXIT /* trap => no access allowed */ xchgl %edx,%edi xorl %edx,%edx movb (%esi,%ebp),%dl /* port */ cmpb $0x61,%dl jnz EXIT /* trap => not the speaker port */ pushl %eax inc %esi rolb $1,%al andb $2,%al movb %al,%ah inb %dx,%al andb $0xfc,%al orb %ah,%al outb %al,%dx popl %eax xchgl %edx,%edi dispatch set_SZV: /* this code is used after the z80-rotate commands */ /* these set the s,z,p/v and carry flags, but the */ /* 80386 counterpart only affect the carry-flag, */ /* similar to the z80 rla command */ xchgl %edi,%eax /* di is a copy of eax, carry-flag is set, al is data */ lahf /* get c flag into ah */ orb %al,%al /* set s,z,p/v flags */ movb %ah,%al /* c => al */ lahf andb $1,%al /* c */ andb $0xc4,%ah orb %al,%ah /* ah = flags */ xorb %al,%al /* al = 0 */ andl $0x28ff,%edi /* preserve undocumented flags */ orl %edi,%eax /* eax = A; flags H and N flags are zero */ dispatch #include "codeix.s" #include "codeiy.s"