home *** CD-ROM | disk | FTP | other *** search
Text File | 1995-11-01 | 7.4 KB | 302 lines | [TEXT/CWIE] |
-
- /* Z80 Emulator
- Copyright (C) 1994 G.Woigk
-
- This file is part of Mac Spectacle and it is free software
- See application.c for details
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-
- This file must be #included in Z80.m68.c to work
- It contains the body of Z80() or Z80_T(), depending on #defines
- */
-
-
-
- // ----- Register usage -------------------------------------------------------------
- #define target a0 // general use as target pointer
-
- #define ai a1 // index register pointer in ix/iy cmnd processing
- #define ir (a1) // access ix or iy
- #define ih (a1) // access XH or YH
- #define il 1(a1) // access XL or YL
- #define air -2(a1) // access AIX or AIY
-
- #define ip a2 // instruction pointer: zreg.IP.ptr
- #define rp a3 // return stack pointer: zreg.RP.ptr
- #define loop a4 // -> main instruction dispatcher
- #define logflags a6 // -> array mlog_flags[]
-
- #define scratch d0
- #define scratch2 d1
-
- #define rom_end d2
- #define core d3 // upper half = CORE base address
- #define db d4 // 0x000000XX: upper 3 bytes are always 0; db MUST be D4
- #define a d5 // 0x00AA00AA: a.b = A; upper half = A'
- #define f d6 // 0x00FF00FF: f.b = F; upper half = F'
- #define cc d7 // T cycle counter: count down to 0; Z80_T() only
-
-
- // ----- option depending code macros ----------------------------------------
- #if exact_timing
- #define used_regs a2-a4/a6/d3-d7
- #define sto_cc move.l cc,CYCLES
- #define ld_cc move.l CYCLES,cc
- #define more1 subq.l #1,cc
- #define more2 subq.l #2,cc
- #define more3 subq.l #3,cc
- #define more4 subq.l #4,cc
- #define more5 subq.l #5,cc
- #define more6 subq.l #6,cc
- #define more7 subq.l #7,cc
- #define more8 subq.l #8,cc
-
- #else
- #define used_regs a2-a4/a6/d3-d6
- #define sto_cc
- #define ld_cc
- #define more1
- #define more2
- #define more3
- #define more4
- #define more5
- #define more6
- #define more7
- #define more8
- #endif
-
-
- #if rom_protection
- #define load_rom_end move.l core,rom_end; move.w #0x4000,rom_end
- #define if_rom(LBL) cmpa.l rom_end,a0; bcs LBL
- #define store_db if_rom(store_byte); move.b db,(a0); m_next
- #else
- #define load_rom_end
- #define if_rom(LBL)
- #define store_db move.b db,(a0); m_next
- #endif
-
-
- // ===== Z80 ENGINE BODY ===========================================
-
- //short asm Z80 ( ) {
- //short asm Z80_T ( ) {
-
- // save registers
- movem.l used_regs,-(a7)
-
- // load frequently needed constants into mc68020 registers:
- move.l CORE,core
- moveq #0,db
- lea mlog_flags,logflags
- lea nxtcmnd,loop
-
- // load the Z80 registers, which are held in mc68020 registers:
- ld_cc // cc
- load_r // r (optional)
- load_rom_end
-
- move.l zreg.aa2,a // A2 and A
-
- move.l zreg.ff2,f // F2 and F
- lea m68flags,a0
- move.b (a0,f.w),f // konvert F to m68 layout
- swap f
- move.b (a0,f.w),f // konvert F' to m68 layout
- swap f
-
- movea.l APC,ip // PC
-
- movea.l ASP,rp // SP
- cmp.l core,rp // sp == 0x0000 ?
- bne.s spok
- adda.l #0x00010000,rp; spok:
-
- // check WUFF to see, whether an NMI or IRPT is pending:
- check_wuff:
- tst.b WUFF
- beq nxtcmnd // no flag set
- bmi.s handle_nmi // bit7: nmi
- // bgt.s handle_irpt // bit0-6: irpt
-
-
- // ------ Interrupt dispatcher --------------------------------------------------
- handle_irpt:
- tst.b IFF1
- beq nxtcmnd // interrupts are disabled
- do_info_irpt
- subq.b #1,WUFF // clear interrupt request
- clr.w IFF1 // disable iff1 & iff2
- cmp.b #1,IM // which irpt mode ?
- bgt.s im2 // irpt mode 2: indirect call
- blt.s im0 // irpt mode 0: read irpt instruction
- im1: move.w #56,core // ---- irpt mode 1: rst 56
- j13: more5 // 13 T cycles
- j08: more8 //
- j00: move.w ip,d0 // push PC
- rol.w #8,d0 // ...
- move.w d0,-(rp) // ...
- movea.l core,ip // load irpt routine address
- m_next // next instruction
-
- im2: more6 // ---- irpt mode2: 19 T cycles ((6+8+5))
- move.w RI,core // read both: i-register & IRPTCMD !!!
- movea.l core,a0
- move.w (a0),core
- rol.w #8,core
- bra.s j13
-
- im0: more5 // ---- irpt mode 0: 1 T cycle + normal instruction timing
- move.b IRPTCMD,db // irpt mode 0 => read instruction from bus
- bra xx_im0 // perform instruction (multi-byte instructions not supported!)
-
- handle_nmi: // ---- nmi
- do_info_nmi
- more3 // nmi: 11 T cycles ((3+8))
- move.b IFF1,IFF2 // save iff1
- sf IFF1 // di
- bclr #7,WUFF // clear nmi flag
- move.w #0x0066,core // nmi address
- bra.s j08
-
-
- // ----- T cycle counter reached 0 --------------------------------------
- #if exact_timing
- cycle00:
- addq.l #4,cc // undo last subq
- sto_cc // update CYCLES
- jsr Do_Cycles // do whatever must be done
- load_rom_end
- ld_cc // get CYCLES again
- tst.b EXIT
- bne exit_watchdog // watchdog => exit!
- tst.b WUFF
- beq.s nxtcmnd // no flag set
- bgt handle_irpt // irpt
- blt.s handle_nmi // nmi
- #endif
-
-
- // ===== BRANCHING =========================================
-
-
- xx32: btst #2,f; beq.s xx24; more3; addq.l #1,ip; m_next // JR NZ,dis
- xx40: btst #2,f; bne.s xx24; more3; addq.l #1,ip; m_next // JR Z,dis
- xx48: btst #0,f; beq.s xx24; more3; addq.l #1,ip; m_next // JR NC,dis
- xx56: btst #0,f; bne.s xx24; more3; addq.l #1,ip; m_next // JR C,dis
-
- xx16a: addq.l #1,ip; more4; m_next
- xx16: subq.b #1,RB; beq.s xx16a; more1; // ---- DJNZ dis: Handler (( the most frequent instruction! ))
-
- xx24: // JR dis
- more8 // 12 T cycles if branched; except DJNZ: 13 T cycles
- move.b (ip)+,core
- ext.w core
- add.w ip,core
-
- nxtjmp: // ---- complete jump instruction
- movea.l core,ip
-
- nxtirpt: // ---- next instr. with test for EXIT ((Z80() only))
- #if !exact_timing
- tst.b EXIT
- bne exit_watchdog
- #endif
-
-
- // ----- THE MAIN INSTRUCTION DISPATCHER --------------------------------
-
- nxtcmnd:
- #include "cmd_xx.c" // used for all instructions which do not modify the PC
- #include "cmd_CB.c" // cmd_CB:
- #include "cmd_ED.c" // cmd_ED:
- #include "cmd_IX/iy.c" // cmd_IX: and cmd_IY:
- #include "cmd_IX/IY_CB.c" // XYCB:
- #include "cmd_DAA.c"
-
-
- // ----- Handling of ROM write accesses -------------------------------------
- #if rom_protection
- store_byte: // move.b db,(a0)
- move.b db,-(a7)
- move.w a0,-(a7)
- jsr write_to_rom
- addq.l #4,a7
- load_rom_end
- m_next
-
- store_word: // move.w d0,(a0)
- move.b d0,-(a7)
- move.w a0,-(a7)
- ror.w #8,d0
- addq.l #1,a0
- move.b d0,-(a7)
- move.w a0,-(a7)
- jsr write_to_rom
- addq.l #4,a7
- jsr write_to_rom
- addq.l #4,a7
- load_rom_end
- m_next
- #endif
-
-
- // ----- Exit points -------------------------------------------------------------
-
- exit_illinstr4: subq.l #2,ip
- exit_illinstr2: subq.l #1,ip
- exit_illinstr1: subq.l #1,ip
- exit_illinstr: moveq #nimp_instr,d0
- bra.s exit_z80
-
- exit_rst0: moveq #rst0_instr,d0
- bra.s exit_z80
-
- exit_halt: moveq #halt_instr,d0
- bra.s exit_z80
-
- exit_watchdog: sf EXIT // clear watchdog flag
- moveq #watchdog_irpt,d0 // select return code
-
- exit_z80: move.w ip,PC
- move.w rp,SP
- move.l a,zreg.aa2 // A2 and A
-
- lea z80flags,a0
- move.b (a0,f.w),f // konvert F to z80 layout
- swap f
- move.b (a0,f.w),f // konvert F' to z80 layout
- swap f
- move.l f,zreg.ff2
-
- sto_cc // cc (optional)
- store_r // r (optional)
- movem.l (a7)+,used_regs // restore old m68 registers
- rts
-
- // } end of Z80() or Z80_T()
-
-
- #undef exact_timing
- #undef rom_protection
- #undef more1
- #undef more2
- #undef more3
- #undef more4
- #undef more5
- #undef more6
- #undef more7
- #undef more8
- #undef sto_cc
- #undef ld_cc
- #undef store_db
- #undef if_rom
- #undef used_regs
- #undef load_rom_end
- #undef exact_bit
- #undef exact_xy_bit
-
-