vermaj equ $01 ;Major version number vermin equ $00 ;Minor version number revyear equ $87 ;Year last assembled revmonth equ $09 ;Month last assembled revday equ $15 ;Day last assembled ************************************************************************* * * * * * 8080 Simulator for MC68000 * * * * With CP/M 2.2 call support, and optional tracing * * * * * * Converted to AmigaDOS September 1987 by Charlie Gibbs * * (after painstakingly typing it all in from Dr. Dobbs * * Journal, January through March 1986). Improvements * * described by Jim Cathey in his letter in the June 1986 * * DDJ have been included. Repetitive code is generated * * by macros whenever it would save my fingers. * * * * * * Version 1.2 1/21/85 JEC * * Fixed Extent bug in OPEN logic. * * Sped up code, sample MAC from 2:13 to 1:40 * * Now runs at a 1.4 MHz equivalent based on MAC sample. * * * * Version 1.1 8/29/84 JEC * * Fixed BIOS call #6 bug. * * * * Version 1.0 05/25/84 by Jim Cathey * * * * This program has been written for speed whenever possible, * * as such tends to be large because of the separate subroutine * * for each and every opcode of the target processor. * * * * On an 8MHz 68000 (Compupro) system the simulation speed is * * a little better than a 1MHz Z-80 when running MAC. The time * * for a sample assembly was 2:13 for the simulation vs. 0:35 * * on a 4MHz Z-80, both systems used identical hard disk systems. * * * * It is not a complete simulation, as some flag handling * * isn't quite right, but it is enough to run the program * * I wrote for it (DDT, LU, MAC, and Morrow's FORMATW). * * * ************************************************************************* code page ************************************************************************* * * * This file contains the startup routines, the simulator core, * * tracing code, and the CP/M 2.2 simulation. * * * ************************************************************************* xref optabl,flags,mloop,traceit,tracesad,traceead,traceflg xdef illegl,service,dump h19 equ 1 ;Non-zero for H19 emulation * * ASCII character values * bel equ $07 ;Bell (or beep or whatever) bs equ $08 ;Backspace ht equ $09 ;Horizontal tab lf equ $0A ;Line feed ff equ $0C ;Form feed cr equ $0D ;Carriage return so equ $0E ;Shift out si equ $0F ;Shift in esc equ $1B ;Escape * * Register definitions for the simulation * Note, only leaves D0-D1/A0 free for use by entire * program without saving registers for temporary use. * return equr A6 ;JMP (return) is fast return to MLOOP. pseudopc equr A5 ;8080's PC is register A5. opptr equr A4 ;Pointer to opcode dispatch table pseudosp equr A3 ;8080's SP is register A3. flagptr equr A2 ;Pointer to 8080's flag lookup table is A2. targbase equr A1 ;Pointer to 8080's address space is A1. regs equr A1 ;Base pointer to 8080's registers is A1. regcon0e equr D7 ;Register-based constant #$E (for speed) regcon01 equr D6 ;Register-based constant #$1 regcon0f equr D5 ;Register-based constant #$F regconff equr D4 ;Register-based constant #$FF regf equr D3 ;8080's flags rega equr D2 ;8080's accumulator * * Target processor's data registers (offsets into storage area) * regop3 equ -9 ;Operand 3 for DAA storage regb equ -8 ;Offsets from register base pointer for regc equ -7 ; 8080's pseudo-registers. regd equ -6 ; A and F are in 68000's data registers. rege equ -5 ; Pseudo-PC is kept in an address register. regh equ -4 regl equ -3 regop1 equ -2 ;Operand 1 for DAA storage regop2 equ -1 ; " 2 " " " page *-------------------------------- * * Some commonly used macros * *-------------------------------- sys MACRO ;Call a system routine. jsr _LVO\1(a6) ENDM *---------------------- * Equates *---------------------- Absbase equ 4 MODE_OLDFILE equ 1005 MODE_NEWFILE equ 1006 *---------------------- * External references *---------------------- XREF _LVOOpenLibrary XREF _LVOCloseLibrary XREF _LVOClose XREF _LVODeleteFile XREF _LVOInput XREF _LVOIoErr XREF _LVOOpen XREF _LVOOutput XREF _LVORead XREF _LVORename XREF _LVOSeek XREF _LVOWaitForChar XREF _LVOWrite page ************************************************************************* * * * Initialization * * * ************************************************************************* start: move.l sp,savesp ;Save the stack pointer. move.b #1,testdol ;"pstring" should test for leading $. clr.w esclen ;No partial escape sequence is saved. clr.b insflag ;We're not in insert mode. clr.b btrcflg ;Turn off BIOS/BDOS call tracing. clr.b quitflg ;Clear the quit flag. clr.b bufflag ;Disable output buffering. clr.b listopn ;The list device is closed. move.l #strbuf,strptr ;Initialize output buffer pointer. lea handles,a1 moveq #(handlen-handles)/4-1,d1 clrhand clr.l (a1)+ ;Clear file handles. dbra d1,clrhand clr.l rawhand ;Clear RAW: handle too. * * Copy the command line to "cmdline", stripping out leading switches if any. * lea cmdline,a1 subq #1,d0 * Skip over leading blanks, if any. leadblk cmpi.b #' ',(a0)+ ;Leading blank? bne.s bufparm ;No. dbra d0,leadblk ;Skip over leading blank. * If the first parameter is "-b", skip over it but activate output buffering. bufparm subq.l #1,a0 ;Back onto the first non-blank. cmpi.b #'-',(a0) ;Possible buffer switch? bne.s savecmd ;No - start saving the command line. cmpi.b #'B',1(a0) ;Activate output buffering? beq.s setbuff ;Yes. cmpi.b #'b',1(a0) bne.s skipsw ;No. setbuff move.b #1,bufflag ;Set buffered-output flag. skipsw cmpi.b #' ',(a0)+ ;Skip over the switch. beq.s skipswx ; and look for start of command line. dbra d0,skipsw addq.l #1,a1 ;Adjust A1. bra.s gotcmd ;There is no command line left. skipswx subq.l #1,a0 ;Back onto the first blank. bra.s leadblk ;Look for the next non-blank. * Save the command line (except for leading switches). savecmd move.b (a0)+,(a1)+ ;Save the command line, if any. dbra d0,savecmd gotcmd move.b #0,-1(a1) ;Replace the newline with a null. move.b cmdline,cmdflag ;Save command-line flag. * * Open libraries and set up a RAW: window. * move.b #1,quitflg ;Quit immediately if failure below. move.l Absbase,a6 ;Find library lea dosname,a1 ;'dos.library' moveq #0,d0 ;Any version sys OpenLibrary ;Open dos.library. move.l d0,a6 ;Point to doslib for next operation. move.l d0,dosbase ;Save it for future reference. sys Input ;Get file handle for keyboard. move.l d0,stdin ;Save it here. beq quitprg ;Couldn't get keyboard handle. sys Output ;Get file handle for screen. move.l d0,stdout ;Save it here. beq quitprg ;Couldn't get screen handle. move.l #rawspec,d1 move.l #MODE_NEWFILE,d2 sys Open ;Open a RAW: window. move.l d0,rawhand ;Save the file handle here. bne.s opened ;We succeeded. move.l #rawerr,d1 bsr pstring ;Display error message... sys IoErr move.l d0,d1 bsr plong ; and error code. bsr pcrlf bra quitprg opened move.b cmdflag,quitflg ;If we have a command, execute it and quit. move.l #setwin,d1 bsr pstring ;Set the window to 24 by 80. * * Come back here to load another program. * nextprg lea target,targbase ;Start of target memory clr.b insflag ;Reset insert mode. move.l #simsg,d1 bsr pstring ;In case last program sent SHIFT OUT clr.b dumpcnt ;Reset dump pause counter. bsr entrads ;Enter trace delimiting addresses. bsr lodfdos ;Load up the fake FDOS in target memory. bsr lodregs ;Load the remaining simulation registers. bsr loadcom ;Load the .COM program. jmp mloop ;Execute simulation. page ************************************************************************* * * * Illegal instructions and dumping * * * ************************************************************************* illegl move.l #illgmsg,d1 ;Illegal opcode, say what & where, bsr pstring lea -1(pseudopc),a0 move.b (a0),d1 suba.l targbase,a0 bsr pbyte move.l #ilgmsg2,d1 bsr pstring move.l a0,d1 bsr pword move.l #ilgmsg3,d1 bsr pstring move.l #dumpmsg,d1 bsr pstring clr.b dumpcnt bsr dump ; and spill guts. bra quitprg ;Quit simulation. dump movem.l d0-d2,-(sp) move.l #dmpmsg2,d1 ;Dump all registers, bsr pstring ; used for illegals and tracing. lea workbuf,a0 move.b rega,d1 ;Accumulator bsr ubyte move.b regf,d1 ;Flags bsr ubyte move.b #' ',(a0)+ move.w regb(regs),d1 ;BC bsr uword move.b #' ',(a0)+ move.w regd(regs),d1 ;DE bsr uword move.b #' ',(a0)+ move.w regh(regs),d1 ;HL bsr uword move.b #' ',(a0)+ move.l pseudosp,d1 ;SP sub.l targbase,d1 bsr uword move.b #' ',(a0)+ move.l a1,-(sp) move.l pseudosp,a1 swap d2 move.w #3,d2 tosloop move.b 1(a1),d1 ;Display the top 4 stack entries. ror.w #8,d1 move.b 0(a1),d1 bsr uword move.b #' ',(a0)+ addq.l #2,a1 dbra d2,tosloop move.l (sp)+,a1 swap d2 move.l pseudopc,d1 ;PC sub.l targbase,d1 bsr uword move.b #' ',(a0)+ move.b #' ',(a0)+ move.b (pseudopc),d1 ;Current opcode byte bsr ubyte move.b #' ',(a0)+ move.b #' ',(a0)+ move.b #'$',(a0)+ move.l #workbuf,d1 bsr pstring ;Displaying as a single string is much faster. moveq #0,d0 move.b (pseudopc),d0 ;Opcode mulu #9,d0 ;Offset into opcode table lea mnops,a0 move.l a0,d1 add.l d0,d1 ;D1 -> opcode name move.l d1,-(sp) addq.l #1,d1 bsr pstring ;Display opcode name. move.l (sp)+,a0 cmpi.b #' ',(a0) beq.s nooprnd ;There are no operands. cmpi.b #'C',(a0) bne.s notcons move.b 1(pseudopc),d1 ;Display single-byte operand. bsr pbyte bra.s nooprnd notcons cmpi.b #'A',(a0) bne.s nooprnd move.b 2(pseudopc),d1 ;Display two-byte operand. bsr pbyte move.b 1(pseudopc),d1 bsr pbyte nooprnd bsr pcrlf addq.b #1,dumpcnt ;Count the number of times dumped. cmpi.b #8,dumpcnt ;Is the screen full of dumps? bmi.s dumpx ;No - exit. move.l #dmpmsg3,d1 bsr pstring ;Ask for operator action. bsr dmpstr ;Make sure the prompt gets out! movem.l d3/a0-a1/a6,-(sp) move.l rawhand,d1 ;Console input move.l #dumpcnt,d2 move.l dosbase,a6 moveq #1,d3 sys Read ;Get the operator's reply. movem.l (sp)+,d3/a0-a1/a6 bsr pcrlf cmpi.b #'Q',dumpcnt ;Does he want to quit? beq quitprg ;Yes. cmpi.b #'q',dumpcnt beq quitprg cmpi.b #'G',dumpcnt ;Go on with tracing disabled? beq.s dumpnt ;Yes. cmpi.b #'g',dumpcnt bne.s dmpcont dumpnt clr.b traceflg ;Disable tracing and continue. dmpcont clr.b dumpcnt ;Reset the counter. dumpx movem.l (sp)+,d0-d2 rts page ************************************************************************* * * * Initialization subroutines * * * ************************************************************************* * * Load up the fake FDOS. * lodfdos move.l a6,-(sp) lea fdos,a6 move.l targbase,pseudosp adda.l #$10000,pseudosp lea -256(pseudosp),a0 move.w #fdoslen,d0 lodloop move.b (a6)+,(a0)+ dbra d0,lodloop lea -256(pseudosp),a0 move.l a0,d0 sub.l targbase,d0 move.b #$C3,0(targbase) ;Build BIOS and BDOS jumps. move.b #$C3,5(targbase) move.b d0,6(targbase) rol.w #8,d0 move.b d0,7(targbase) rol.w #8,d0 addq.w #3,d0 move.b d0,1(targbase) rol.w #8,d0 move.b d0,2(targbase) clr.w -(pseudosp) ;Set up a return stack to exit simulation. move.l (sp)+,a6 rts * * Set up working registers. * lodregs lea optabl,opptr ;Point base reg. to opcode dispatch table. lea mloop,return lea flags,flagptr move.l targbase,pseudopc adda.l #$100,pseudopc ;Start execution at 0100H in target space. moveq #$E,regcon0e ;Set up quick constants. moveq #$1,regcon01 moveq #$F,regcon0f move.l #$FF,regconff moveq #0,rega moveq #0,regf rts page * * Get start and end addresses for tracing. * entrads tst.b traceit ;Is tracing required? beq entradx ;No. move.l #tracemsg,d1 ;Enter trace address if necessary. bsr pstring lea workbuf,a0 move.b #workbufn-workbuf-2,(a0) bsr getline ;Get the string. moveq #0,d0 move.b 1(a0),d0 ;Number of bytes read addq.l #2,a0 ;Skip over length information. clr.b 0(a0,d0) ;Insert string terminator. bsr atol ;Get trace start address. and.l #$FFFF,d1 add.l targbase,d1 move.l d1,tracesad * Now get the ending address. move.l #tracemg2,d1 bsr pstring lea workbuf,a0 move.b #workbufn-workbuf-2,(a0) bsr getline moveq #0,d0 move.b 1(a0),d0 addq.l #2,a0 clr.b 0(a0,d0) bsr atol and.l #$FFFF,d1 add.l targbase,d1 move.l d1,traceead bsr pcrlf * Find out whether BIOS/BDOS calls are to be traced. move.l #btrcmsg,d1 bsr pstring lea workbuf,a0 move.b #10,(a0) bsr getline move.b #1,btrcflg cmpi.b #'Y',workbuf+2 beq.s entradx cmpi.b #'y',workbuf+2 beq.s entradx clr.b btrcflg entradx clr.b traceflg ;Start with tracing turned off. rts * * Open the file to be loaded, and load it into * target space if successful. * loadcom movem.l d1-d3/a1-a2/a6,-(sp) ;Save registers. lea cmdline,a0 tst.b cmdflag ;Do we have a command already? bne.s scancmd ;Yes - process it. prompt move.l #aprompt,d1 bsr pstring ;Display the command prompt. lea cmdline,a0 move.b #cmdlinen-cmdline-2,(a0) bsr getline ;Get a command line. moveq #0,d0 move.b 1(a0),d0 ;Length of command line beq.s prompt ;Zero - try again. addq.l #2,a0 ;Skip over length information. clr.b 0(a0,d0) ;Insert command line terminator. cmpi.b #3,(a0) ;Control-C? bne.s scancmd ;No. move.b #1,quitflg ;Set quit flag. bra quitprg ;Exit the simulator. scancmd lea comname,a2 moveq #comnamen-comname-6,d1 ;Adjust length for DBcc. loadnam bsr ucase ;Convert file name to upper case. move.b d0,(a2)+ cmpi.b #' ',(a0) ;End of name? beq gotname ;Yes. tst.b (a0) ;End of command string? dbeq d1,loadnam ;No - keep on going. gotname move.l a0,comend ;Save position in command line. move.b #'.',(a2)+ ;Mash file name to .COM. move.b #'C',(a2)+ move.b #'O',(a2)+ move.b #'M',(a2)+ clr.b (a2) clr.b cmdline ;Ask for a new command next time. move.l #comname,d1 move.l #MODE_OLDFILE,d2 move.l dosbase,a6 sys Open ;Open the file. tst.l d0 ;Did the open fail? bne.s comopen ;No. lea comname,a0 openerr cmpi.b #'.',(a0)+ ;Find end of file name. bne.s openerr move.b #'?',-1(a0) move.b #cr,(a0)+ move.b #lf,(a0)+ move.b #'$',(a0) move.l #comname,d1 bsr pstring ;Echo "name?" bra prompt ;Try again. comopen move.l d0,-(sp) ;Save the file handle. move.l d0,d1 move.l pseudopc,d2 ;Start loading at $0100 in target. move.l #65536-512,d3 ;Maximum number of bytes to load move.l dosbase,a6 sys Read ;Load the .COM file. move.l (sp)+,d1 move.l dosbase,a6 sys Close ;Close the .COM file. * The program has now been loaded. movem.l (sp)+,d1-d3/a1-a2/a6 ;Refresh registers. movem.l d1-d3/a1-a2/a6,-(sp) lea $80(targbase),a0 ;Set up target's base page. move.l a0,dmaaddr * Set up FCBs and command line tail. lea $5C(targbase),a0 lea $6C(targbase),a2 clr.b (a0)+ clr.b (a2)+ moveq #10,d0 clrfcb move.b #' ',(a0)+ ;Clear FCBs. move.b #' ',(a2)+ dbra d0,clrfcb clr.b $80(targbase) ;Clear the command line tail. move.l comend,a0 ;Restore position in command line. fcb1 tst.b (a0) ;End of command line? beq loaded ;Yes. cmpi.b #' ',(a0)+ ;Skip over to first file name beq.s fcb1 subq.l #1,a0 ;Back onto start of file name. move.l a0,-(sp) ;Save position on command line. lea $81(targbase),a2;A2 loads the command line tail. gettail move.b (a0)+,(a2)+ ;Copy the command tail. bne.s gettail move.l a2,d0 lea $82(targbase),a0;Don't count null terminator! sub.l a0,d0 move.b d0,$80(targbase);Length of command line tail move.l (sp)+,a0 ;Go back to the first file name. lea $5C(targbase),a2;Address of current FCB getfcb move.l a2,fcbptr ;Save pointer to current FCB. cmpi.b #':',1(a0) ;Is a drive specified? bne.s getfcbf ;No. move.b (a0),(a2) ;Get drive letter. subi.b #'A'-1,(a2) ;Convert to drive code. addq.l #2,a0 ;Skip over drive designator. tst.b (a0) ;End of command line? beq.s loaded ;Yes - we're done. cmpi.b #' ',(a0) ;End of file name? beq.s getfcbx ;Yes. getfcbf addq.l #1,a2 ;Start of file name in FCB getfcbl move.b (a0)+,(a2)+ ;Copy file name to FCB. getfcbt tst.b (a0) ;End of command? beq.s loaded ;Yes. cmpi.b #' ',(a0) ;End of file name? beq.s getfcbx ;Yes. cmpi.b #'.',(a0) ;Start of file name extension? bne.s getfcbl ;No - continue loading file name. move.l fcbptr,a2 ;Copy original pointer adda.l #9,a2 ;Skip over to extension field. addq.l #1,a0 ;Skip over the period. bra.s getfcbt getfcbx tst.b (a0) ;End of command line? beq.s loaded ;Yes. cmpi.b #' ',(a0)+ ;Look for another file name. beq.s getfcbx subq.l #1,a0 ;Back onto start of file name. move.l fcbptr,d0 lea $5C(targbase),a2 cmp.l d0,a2 ;Was this the first FCB? bne.s loaded ;No - stop after two FCBs. adda.l #16,a2 ;Skip over to the next FCB. bra.s getfcb ;Load the next FCB. loaded movem.l (sp)+,d1-d3/a1-a2/a6 ;Restore registers. rts ;Exit. * * Subroutine to get a character and convert it to upper case * ucase move.b (a0)+,d0 cmpi.b #'a',d0 blt.s ucasex cmpi.b #'z',d0 bgt.s ucasex subi.b #'a'-'A',d0 ucasex rts page ************************************************************************* * * * BDOS / BIOS service routines * * * ************************************************************************* service movem.l a1/a6,-(sp) move.b rega,newrega ;Save 8080 accumulator (D2) move.l dosbase,a6 ;Get dos.library pointer * Decode the byte following the HLT instruction (BIOS call type). moveq #0,d0 ;Handle BIOS/BDOS service request move.b (pseudopc)+,d0 ; of form HLT DB opcode. cmp #(biostabn-biostab)/4,d0 blt.s dobios ;Function number is within range. badbios move.b d0,-(sp) ;Flag illegal BIOS call move.l #ilgbios,d1 ; and spill guts. bsr pstring move.b (sp)+,d1 bsr pbyte bsr pcrlf bsr dump bra quitprg dobios move.l d0,-(sp) ;Save BIOS function number. beq.s biostrx ;Zero - it's a BDOS call. tst.b btrcflg ;Trace BIOS calls? beq.s biostrx ;No. move.l #biosmsg,d1 bsr pstring move.l (sp),d1 bsr pbyte move.l #atmsg,d1 bsr pstring move.b 1(pseudosp),d1 ;Address where called (top stack entry) ror.w #8,d1 move.b 0(pseudosp),d1 bsr pword bsr pcrlf move.l (sp),d0 biostrx asl #2,d0 ;Multiply function number by 4. addi.l #biostab,d0 ;Point at address table entry. movea.l d0,a0 movea.l (a0),a0 ;Point to appropriate service routine. move.l (sp)+,d0 ;Restore BIOS function number. jmp (a0) ;Jump to the routine. * If the BIOS code is zero, it's a BDOS call. * Decode register C using a similar routine to the BIOS decoding above. bdosfn moveq #0,d0 move.b regc(regs),d0 ;Get BDOS function number. cmp #(bdostabn-bdostab)/4,d0 blt.s dobdos ;Function number is within range. badbdos move.b d0,-(sp) move.l #ilgbdos,d1 ;Illegal or unsupported BDOS call bsr pstring move.b (sp)+,d1 bsr pbyte bsr pcrlf bsr dump bra quitprg dobdos move.l d0,-(sp) ;Save BDOS function number. tst.b btrcflg ;Trace BDOS calls? beq.s bdostrx ;No. move.l #bdosmsg,d1 bsr pstring move.l (sp),d1 bsr pbyte move.l #atmsg,d1 bsr pstring move.b 1(pseudosp),d1 ror.w #8,d1 move.b 0(pseudosp),d1 bsr pword bsr pcrlf move.l (sp),d0 bdostrx cmpi.b #10,d0 ;BDOS function 10 or higher? blt.s bdosjmp ;No. bsr dmpstr ;Dump any outstanding console output. move.l (sp),d0 ;Restore BDOS function number. bdosjmp asl #2,d0 ;Multiply function number by 4. addi.l #bdostab,d0 ;Point at address table entry. movea.l d0,a0 movea.l (a0),a0 ;Point to appropriate service routine. move.l (sp)+,d0 ;Restore BDOS function number. moveq #0,d1 move.w regd(regs),d1 ;Get argument. jmp (a0) ;Jump to the routine. * Return here after performing the BDOS function. results movem.l (sp)+,a1/a6 moveq #0,rega move.b newrega,rega ;Get new accumulator value. * We have finished processing the BDOS function. move.b rega,d0 ;Set flags. and.w regconff,d0 move.b 0(flagptr,d0.w),regf rts * * Individual BDOS service routines * bdos00 bra quitprg ;Exit program. bdos01 bsr dmpstr ;Console input move.l rawhand,d1 move.l #newrega,d2 moveq #1,d3 sys Read bra results bdos02 move.b rege(regs),d1 ;Console output clr.b testdol ;Allow dollar signs bsr pchar bra results bdos03 equ badbdos ;Reader input bdos04 equ badbdos ;Punch output bdos05 pea rege(regs) ;List output byte bdos05t tst.b listopn ;Is the printer already open? bne.s bdos05w ;Yes. move.l #prtname,d1 move.l #MODE_NEWFILE,d2 sys Open ;Open the printer. move.l d0,prthand ;Save the file handle. bne.s bdos05o ;The open was successful. move.l #badprt,d1 bsr pstring ;Indicate an unsuccessful open. bsr dump ;Spill guts... bra quitprg ; and exit. bdos05o move.b #1,listopn ;Indicate that the list device is open. bdos05w move.l prthand,d1 move.l (sp)+,d2 ;Character to send to the list device moveq #1,d3 ;Just send one byte. sys Write ;Send the byte to the list device. bra results bdos06 cmpi.b #$FF,rege(regs) ;Direct console I/O bne.s bdos02 ;Send the byte. bsr dmpstr ;Dump any outstanding output. move.l rawhand,d1 moveq #1,d2 ;Wait for one microsecond. sys WaitForChar ;Check whether a character is ready. tst.l d0 ;Is a character ready? bne bdos01 ;Yes - get it. clr.b newrega ;Indicate that nothing is ready. bra results bdos07 move.b 3(targbase),newrega ;Get IOBYTE bra results bdos08 move.b rege(regs),3(targbase) ;Set IOBYTE bra results bdos09 add.l targbase,d1 ;Console output string bsr pstring bra results bdos10 add.l targbase,d1 ;Console input line movea.l d1,a0 ;The buffer is here. bsr getline ;Get a line. cmpi.b #3,2(a0) ;Was it a control-C? bne results ;No - continue processing. bra quitprg ;Terminate the program. bdos11 move.l rawhand,d1 ;Console status check moveq #1,d2 ;Wait for one microsecond. sys WaitForChar ;Check whether a character is ready. move.b d0,newrega ;Result is compatible with CP/M. bra results bdos12 clr.b regh(regs) ;Get system identification move.b #$22,regl(regs) ;Pretend we're CP/M 2.2. bra results bdos13 equ results ;Reset all drives (ignored) bdos14 move.b rege(regs),4(targbase) ;Select drive bra results bdos15 move.l #MODE_OLDFILE,d2;Open existing file bdos15o add.l targbase,d1 movea.l d1,a0 ;The FCB is here. move.l d1,-(sp) lea opnname,a1 ;Build AmigaDOS file name here. move.l a1,d1 ;We'll need it here. bsr convfn ;Make a file name. sys Open ;Open the file. move.l (sp)+,a1 ;The FCB is here. lea handles,a0 moveq #(handlen-handles)/4-1,d1 clr.b newrega ;Assume the open succeeded. tst.l d0 ;Did it fail? bne bdos15s ;No. move.b #$FF,newrega ;Set failure code. bra results bdos15s tst.l (a0)+ ;Find an available handle slot. dbeq d1,bdos15s tst d1 ;Did we find a slot? bmi bdos15e ;No - error! move.l d0,-4(a0) ;Save file handle address. moveq #(handlen-handles)/4-1,d0 sub.l d1,d0 move.b d0,13(a1) ;Save handle number in FCB. bra results bdos15e move.l #fullmsg,d1 ;File handle table overflow! bsr pstring ;Display an error message bra quitprg ; and forget the whole thing. bdos16 move.b #$FF,newrega ;Close file bsr gethand ;Get the file handle. beq results ;The file is not open. clr.l 0(a1,d0.w) ;Clear the handle table entry. sys Close ;Close the file. clr.b newrega ;Indicate success. bra results bdos17 equ badbdos ;Search for first file bdos18 equ badbdos ;Search for next file bdos19 add.l targbase,d1 ;Delete file movea.l d1,a0 ;The FCB is here. lea opnname,a1 ;Build AmigaDOS file name here. move.l a1,d1 ;We'll need it here. bsr convfn ;Make a file name. sys DeleteFile ;Delete the file. bra results bdos20 clr.b newrega ;Sequential read bsr gethand move.l dmaaddr,d2 move.l #128,d3 sys Read tst.l d0 ;Were we successful? bgt results ;Yes. move.b #$FF,newrega ;Set failure (EOF) flag. bra results bdos21 clr.b newrega ;Sequential write bsr gethand move.l dmaaddr,d2 move.l #128,d3 sys Write tst.l d0 ;Were we successful? bgt results ;Yes. move.b #$FF,newrega ;Set failure flag. bra results bdos22 move.l #MODE_NEWFILE,d2 ;Make new file bra bdos15o ;Use BDOS 15 open routine bdos23 add.l targbase,d1 ;Rename file movea.l d1,a0 lea opnname,a1 bsr convfn ;Convert old file name. movea.l d1,a0 adda.l #16,a0 lea renname,a1 bsr convfn ;Convert new file name. move.l #opnname,d1 move.l #renname,d2 sys Rename ;Rename the file. bra results bdos24 equ badbdos ;Get active drive map bdos25 move.b 4(targbase),newrega ;Get default drive number bra results bdos26 add.l targbase,d1 ;Set file buffer address move.l d1,dmaaddr bra results bdos27 equ badbdos ;Get allocation vector bdos28 equ badbdos ;Protect drive bdos29 equ badbdos ;Get read-only map bdos30 equ badbdos ;Set file attributes bdos31 equ badbdos ;Get disk parameter block bdos32 equ badbdos ;Get or set user code bdos33 pea _LVORead(a6) ;Direct access read bra.s bdos34c ;Use common read/write routine. bdos34 pea _LVOWrite(a6) ;Direct access write bdos34c clr.b newrega ;Common direct access read/write routine bsr gethand move.l d1,-(sp) ;Save file handle. moveq #0,d2 move.b 35(a0),d2 ;Get seek address. rol.l #8,d2 move.b 34(a0),d2 rol.l #8,d2 move.b 33(a0),d2 rol.l #7,d2 ;Convert record number to byte displacement. move.b 33(a0),32(a0) ;Set up current record number in extent. andi.b #$7F,32(a0) moveq #14,d0 ror.l d0,d2 move.b d2,12(a0) ;Current extent number rol.l d0,d2 moveq #-1,d3 sys Seek ;Seek to desired position. move.l (sp)+,d1 ;Get the file handle again. move.l (sp)+,a0 ;Address of read or write routine tst.l d0 ;Were we successful? bmi bdos34e ;No. move.l dmaaddr,d2 move.l #128,d3 jsr (a0) ;Read or write the desired record. tst.l d0 ;Were we successful? bgt results ;Yes. bdos34e move.b #6,newrega ;Set failure (invalid address) flag. bra results bdos35 equ badbdos ;Get file end address bdos36 equ badbdos ;Get direct address * * Individual BIOS service routines * bios01 bra quitprg ;Warm boot bios02 equ bdos11 ;Console status check bios03 equ bdos01 ;Console input byte bios04 move.b regc(regs),d1 ;Console output byte clr.b testdol ;Allow dollar signs bsr pchar bra results bios05 pea regc(regs) ;List output byte bra bdos05t bios06 equ badbios ;Punch output byte bios07 equ badbios ;Reader input byte bios08 equ badbios ;Home disk bios09 equ badbios ;Select disk bios10 equ badbios ;Set track bios11 equ badbios ;Set sector bios12 equ badbios ;Set DMA address bios13 equ badbios ;Read disk bios14 equ badbios ;Write disk bios15 move.b #$FF,newrega ;List status bra results * * End of program, one way or another * quitprg move.l savesp,sp ;Restore stack pointer. bsr dmpstr ;Dump any outstanding console output. * If the list device was used, close it. tst.b listopn ;Is the printer open? beq.s closprt ;No. move.l prthand,d1 sys Close ;Close the printer. closprt clr.b listopn ;Reset the "printer-open" flag. * If any files were left open by the last program, close them. lea handles,a0 moveq #(handlen-handles)/4-1,d0 closall move.l (a0)+,d1 beq.s closnxt ;This file isn't open. movem.l a0/d0,-(sp) move.l dosbase,a6 sys Close ;Close this file. movem.l (sp)+,a0/d0 closnxt dbra d0,closall * Check whether we should quit the simulation. tst.b quitflg ;Exit the simulator? bne.s exitsim ;Yes. tst.b cmdflag ;Was .COM file loaded from command line? beq nextprg ;No - re-display the command prompt. * Terminate execution of the simulator. exitsim move.l rawhand,d1 ;Is RAW: open? beq.s closlib ;No. move.l dosbase,a6 sys Close ;Close RAW: closlib move.l Absbase,a6 move.l dosbase,a1 sys CloseLibrary ;Close dos.library. moveq #0,d0 ;Return with no error. rts ;All done page ************************************************************************* * * * AmigaDOS interface routines * * * ************************************************************************* * * Get a line from the console. CP/M BDOS 10 conventions are used. * A0 is assumed to point to the start of the buffer. * If the first character encountered is a control-C, this routine * exits, leaving just the control-C in the buffer. * getline movem.l d2-d3/a0-a1/a6,-(sp) bsr dmpstr ;Flush the screen buffer first. move.l dosbase,a6 movea.l a0,a1 addq.l #2,a1 ;The current character loads here. clr.b 1(a0) ;Clear character count. getlinl move.l rawhand,d1 ;Read from RAW: move.l a1,d2 ; into current position moveq #1,d3 ; for a length of one byte. movem.l d1-d3/a0-a1,-(sp) sys Read ;Get a character. movem.l (sp)+,d1-d3/a0-a1 cmpi.b #cr,(a1) ;Did we get a carriage return? beq.s getlinc ;Yes - stop here. cmpi.b #lf,(a1) ;Stop on a line feed too. beq.s getlinc cmpi.b #bs,(a1) ;Backspace? bne.s getlinp ;No. tst.b 1(a0) ;Do we have anything yet? beq.s getlinl ;No - ignore the backspace. subq.l #1,a1 ;Back over the previous character. subq.b #1,1(a0) ;Decrement character count. movem.l a0-a1,-(sp) move.l #bsmsg,d1 jsr pstring ;Erase the previous character on the screen. movem.l (sp)+,a0-a1 bra.s getlinl getlinp movem.l a0-a1,-(sp) sys Write ;Echo the current character. movem.l (sp)+,a0-a1 getlinn addq.b #1,1(a0) ;Bump character count. move.b 1(a0),d0 ;Number of bytes read so far. cmpi.b #3,(a1)+ ;Did we get a control-C? bne.s getlinf ;No. cmpi.b #1,d0 ;Is is the first character? beq.s getlinx ;Yes - exit now. getlinf cmp.b (a0),d0 ;Is the buffer full? bne.s getlinl ;No - try for another character. bra.s getlinx getlinc bsr pcrlf ;Carriage return or line feed getlinx movem.l (sp)+,d2-d3/a0-a1/a6 rts ;Exit. * * Display the message pointed to by D1. * The message must be terminated by a dollar sign. * pstring movem.l d2-d3/a1-a2,-(sp) ;Save work registers. move.l d1,a0 ;A0 scans the message. bset #0,testdol ;Suppress $ test? beq.s pstrs ;Yes (used by BDOS/BIOS character output) cmpi.b #'$',(a0) ;Null string? beq pstrx ;Yes - do nothing. pstrs move.l strptr,a1 ;A1 loads the output buffer. move.l #strbufn,d3 sub.l a1,d3 ;Number of bytes left in buffer ifne h19 moveq #0,d0 move.w esclen,d0 ;Is a partial escape sequence saved? beq.s pstrl ;No. lea escbuf,a2 adda.l d0,a2 ;Continue loading it here. clr.w esclen ;Reset "saved length" counter. cmpi.w #2,d0 ;Did we just save one byte? blt.s pstresc ;Yes - get the remainder. bhi pstreY2 ;Get the last cursor positioning byte. subq.l #1,a2 ;Back over dummy byte. bra pstreY1 ;Get both cursor positioning bytes. endc pstrl: cmpi.b #lf,(a0) ;Line feed? bne.s notlf ;No. lea escbuf,a2 ;Translate it to a cursor-down sequence. move.b #$9B,(a2)+ move.b #'B',(a2)+ addq.l #1,a0 bra pstrsub notlf: ifne h19 * Optional H19 escape sequence translation cmpi.b #esc,(a0) ;Escape character? bne pstrm ;No - treat it normally. lea escbuf,a2 ;Build translated escape sequence here. move.b #$9B,(a2)+ ;Start with an AmigaDOS escape character. addq.l #1,a0 ;Check the next character. cmpi.b #'$',(a0) ;End of string? bne.s pstresc ;No - analyze the sequence. move.w #1,esclen ;We've saved one byte for next time. bra pstrw ;Write everything up to the ESC character. pstresc move.b (a0)+,d0 cmpi.b #'[',d0 ;ANSI escape sequence? beq pstrsub ;Yes - pass the sequence with $9B header. cmpi.b #'Y',d0 beq.s pstreY ;Set cursor position. cmpi.b #'@',d0 beq.s pstrein ;Set insert mode. cmpi.b #'A',d0 blt.s pstreun ;Unknown code - copy it as is. cmpi.b #'O',d0 beq.s pstreO ;Reset insert mode. bhi.s pstreun ;Unknown code move.l a0,-(sp) lea esctran,a0 ;Translation table with offset move.b -'A'(a0,d0.w),d2;Get the translated code. move.l (sp)+,a0 btst #6,d2 ;Does the translated code stand alone? bne.s pstresb ;No. subq.l #1,a2 ;Back over stored CSI character. pstresb move.b d2,(a2)+ ;Get the translated code. bra.s pstrsub pstrein move.b #1,insflag ;Set insert mode. bra.s pstrsbx pstreO clr.b insflag ;Reset insert mode. bra.s pstrsbx pstreY cmpi.b #'Y',d0 ;Set cursor position bne.s pstreun cmpi.b #'$',(a0) ;End of string? bne.s pstreY1 ;No. move.w #2,esclen ;Indicate we need both position bytes. bra pstrw ;Finish the sequence next time. pstreY1 moveq #0,d0 move.b (a0)+,d0 ;Get the first position byte. bsr pstrcvd ;Convert to decimal in save area. move.b #';',(a2)+ ;Add the separator character. cmpi.b #'$',(a0) ;End of string? bne.s pstreY2 ;No. sub.l #escbuf,a2 ;Number of bytes saved move.w a2,esclen bra pstrw ;Get the last byte next time. pstreY2 moveq #0,d0 move.b (a0)+,d0 ;Get the last position byte. bsr pstrcvd ;Convert to decimal in save area. move.b #'H',(a2)+ ;Terminate the sequence. bra.s pstrsub pstreun move.b #esc,escbuf ;Unidentified escape sequence - move.b d0,(a2)+ ; pass it through as is. * The translated escape sequence is now in "escbuf" - * copy it to the output buffer. pstrsub move.l a2,d0 lea escbuf,a2 ;A2 scans translated escape sequence. sub.l a2,d0 ;Length of translated escape sequence subq.l #1,d0 pstrsbl move.b (a2)+,(a1)+ ;Copy substitution to output string. subq.w #1,d3 ;Count down remaining length. dbra d0,pstrsbl pstrsbx cmpi.b #'$',(a0) ;End of string? beq pstrw ;Yes - write it out. tst.w d3 ;Is the buffer full? bmi pstrw ;Yes - write out what we have. cmpi.b #lf,-1(a0) ;Line feed? bne pstrl ;No. tst.b bufflag ;Is console buffering in effect? beq pstrl ;No. move.l a1,strptr bsr dmpstr ;Dump the buffer. move.l strptr,a1 bra pstrl ;Check for another escape sequence. * Subroutine to convert the byte in D0 to a character string at (A2)+ pstrcvd subi.b #' '-1,d0 ;Convert to binary row or column number. divu #10,d0 ;Convert to tens and units. tst.w d0 ;Is the number 10 or greater? beq.s pstrcv1 ;No - just create a one-digit number. addi.b #'0',d0 ;Convert the tens digit to ASCII. move.b d0,(a2)+ ;Move it to the result field. pstrcv1 swap d0 ;Get the units digit. addi.b #'0',d0 ;Convert it to ASCII. move.b d0,(a2)+ rts endc * Normal character processing pstrm tst.b insflag ;Are we in insert mode? beq.s pstrmv ;No. lea escbuf,a2 move.b #$9B,(a2)+ ;Build an insert-character sequence. move.b #'@',(a2)+ move.b (a0)+,(a2)+ ;Here's the character to insert. bra.s pstrsub ;Use the substitution routine. pstrmv move.b (a0)+,(a1)+ ;Move one character. tst.b bufflag ;Is console buffering in effect? beq.s pstreos ;No. cmpi.b #cr,-1(a0) ;Carriage return? beq.s pstrseg ;Yes - dump the current segment. cmpi.b #bel,-1(a0) ;Bell? bne.s pstreos ;No - continue buffering. pstrseg move.l a1,strptr bsr dmpstr ;Dump the buffer. move.l strptr,a1 pstreos cmpi.b #'$',(a0) ;Test for end of string. dbeq d3,pstrl ;Loop until we get there or buffer is full. pstrw move.l a1,strptr tst d3 ;Is the buffer full? bmi.s pstrdmp ;Yes - dump it regardless. tst.b bufflag ;Is console buffering in effect? bne.s pstrnxt ;Yes - don't write anything yet. pstrdmp bsr dmpstr ;Dump the buffer. move.l strptr,a1 pstrnxt tst d3 ;Did the output buffer overflow? bmi pstrs ;Yes - get another section of the message. pstrx movem.l (sp)+,d2-d3/a1-a2 ;Restore registers rts * * Write the contents of "strbuf" to RAW: if possible, or stdout if not. * The number of bytes to be written is calculated from "strptr". * dmpstr movem.l d2-d3/a0-a1/a6,-(sp) move.l strptr,d3 move.l #strbuf,d2 ;Address of buffer move.l d2,strptr ;Reset the buffer pointer. sub.l d2,d3 ;Length of output string beq.s dmpstrx ;Zero - don't write anything. move.l rawhand,d1 ;Assume we're writing to RAW: bne.s dmpstrp move.l stdout,d1 ;We don't have RAW: - use stdout. dmpstrp move.l dosbase,a6 sys Write ;Display the line. dmpstrx movem.l (sp)+,d2-d3/a0-a1/a6 rts * * Convert the file name in the FCB pointed to by A0 * to an AmigaDOS-format file name in the field pointed to by A1. * D0 is the only other register used by this routine. * convfn move.l a1,-(sp) move.l a0,-(sp) ;Save start address of FCB. tst.b (a0)+ ;Skip over drive code for now. moveq #7,d0 ;Maximum of 8 characters for file name convfn1 cmpi.b #' ',(a0) ;End of file name? beq.s convfnz ;Yes move.b (a0)+,(a1)+ ;Move one character of file name. dbra d0,convfn1 ;Try for more. convfnz movea.l (sp)+,a0 ;Back to start of FCB. adda.l #9,a0 ;Go to start of file name extension. cmpi.b #' ',(a0) ;Do we have an extension? beq.s convfnx ;No. move.b #'.',(a1)+ ;Insert extension separator. moveq #2,d0 ;Maximum of 3 characters for extension. convfn2 cmpi.b #' ',(a0) ;End of extension? beq.s convfnx ;Yes. move.b (a0)+,(a1)+ ;Move one character of extension. dbra d0,convfn2 ;Try for more. convfnx clr.b (a1) ;Terminate file name string. move.l (sp)+,a1 rts * * Get the file handle indicated by the number inserted into the * CP/M FCB by the open routine. It is copied from the file handle * table entry (whose address is set up as 0(A1,D0.W)) to D1. * The Z flag will be set if the handle is zero (i.e. file not open). * A0 points to the FCB. * gethand add.l targbase,d1 ;The FCB is here. movea.l d1,a0 lea handles,a1 moveq #0,d0 move.b 13(a0),d0 ;Get handle number from FCB. asl.w #2,d0 ;Convert to table offset. move.l 0(a1,d0.w),d1 ;Get the file handle. rts page ************************************************************************* * * * Miscellaneous service routines * * (Inelegant, but rarely used so they stand as is.) * * * ************************************************************************* * * Display the contents of D1 in hex. * pbyte move.l #$20018,d0 ;2 nybbles, 24-bit shift first bra.s phex pword move.l #$40010,d0 ;4 nybbles, 16-bit shift first bra.s phex paddr move.l #$60008,d0 ;6 nybbles, 8-bit shift first bra.s phex plong move.l #$80000,d0 ;8 nybbles, no shift first phex lea workbuf,a0 move.l a0,-(sp) bsr pdigits move.b #'$',(a0)+ move.l (sp)+,d1 bsr pstring rts * * Convert the contents of D1 to hex at (A0). * On exit, A0 points to the next available byte. * ubyte move.l #$20018,d0 ;2 nybbles, 24-bit shift first bra.s pdigits uword move.l #$40010,d0 ;4 nybbles, 16-bit shift first bra.s pdigits uaddr move.l #$60008,d0 ;6 nybbles, 8-bit shift first bra.s pdigits ulong move.l #$80000,d0 ;8 nybbles, no shift first pdigits rol.l d0,d1 ;Do shift. bra.s pdigent pdiglop swap d0 ;Save nybble count. rol.l #4,d1 ;Print variable in d1. move.l d1,-(sp) and #$F,d1 ;Isolate the current nybble. cmp #$A,d1 blt.s ntoa2 add.b #'A'-'9'-1,d1 ;Adjust for digits A through F. ntoa2 add.b #'0',d1 ;Convert to ASCII. move.b d1,(a0)+ ;Add to the result string. move.l (sp)+,d1 pdigent swap d0 ;Get nybble count. dbra d0,pdiglop rts pchar move.b d1,workbuf ;Print the character in D1. move.b #'$',workbuf+1 move.l #workbuf,d1 bsr pstring rts pspace move.l #spacemsg,d1 ;Print a space. bsr pstring rts pcrlf move.l #crlfmsg,d1 ;Print a carriage return and line feed. bsr pstring rts * * Convert the hex string pointed to by A0 to long in d1. * Stops on the first invalid hex digit, which is returned in d0. * A0 is left pointing to this first invalid digit. * d2 = 1 if any valid digits were found, 0 otherwise. * atol moveq #0,d1 moveq #0,d2 atol1 move.b (a0)+,d0 ;Get the current byte. cmpi.b #$40,d0 blt.s atol2 and #$5F,d0 ;Mask to upper case. atol2 cmpi.b #'0',d0 ;Check range (0..9,A..F). blt.s atolend cmpi.b #'F',d0 bhi.s atolend cmpi.b #'9',d0 ble.s atol3 cmpi.b #'A'-1,d0 bhi.s atol3 bra.s atolend atol3 moveq #1,d2 ;Valid characters entered, set flag. sub.b #'0',d0 ;Convert to binary cmp.b #$9,d0 ;Digit in range 0..9? ble.s atol4 ;Yes - conversion is complete sub.b #'A'-'9'-1,d0 ;Adjust digits A..F. atol4 ext d0 ;Convert to long. ext.l d0 asl.l #4,d1 ;Tack it onto d1. add.l d0,d1 bra.s atol1 ;Try for another digit. atolend subq.l #1,a0 ;Back onto the first invalid digit. rts page ************************************************************************* * * * This table contains the mnemonic strings for the 8080 * * opcodes. These are used in tracing. The first character * * flags operands. Blank is nothing, A is an address (i.e. * * a 16-bit value), and C is a constant (i.e. an 8-bit value). * * * ************************************************************************* data data mnops: dc.b ' NOP$ ALXI B,$ STAX B$ INX B$ ' ;00-03 dc.b ' INR B$ DCR B$ CMVI B,$ RLC$ ' ;04-07 dc.b ' ILLEGAL$ DAD B$ LDAX B$ DCX B$ ' ;08-0B dc.b ' INR C$ DCR C$ CMVI C,$ RRC$ ' ;0C-0F dc.b ' ILLEGAL$ALXI D,$ STAX D$ INX D$ ' ;10-13 dc.b ' INR D$ DCR D$ CMVI D,$ RAL$ ' ;14-17 dc.b ' ILLEGAL$ DAD D$ LDAX D$ DCX D$ ' ;18-1B dc.b ' INR E$ DCR E$ CMVI E,$ RAR$ ' ;1C-1F dc.b ' ILLEGAL$ALXI H,$ ASHLD $ INX H$ ' ;20-23 dc.b ' INR H$ DCR H$ CMVI H,$ DAA$ ' ;24-27 dc.b ' ILLEGAL$ DAD H$ ALHLD $ DCX H$ ' ;28-2B dc.b ' INR L$ DCR L$ CMVI L,$ CMA$ ' ;2C-2F dc.b ' ILLEGAL$ALXI SP,$ASTA $ INX SP$ ' ;30-33 dc.b ' INR M$ DCR M$ CMVI M,$ STC$ ' ;34-37 dc.b ' ILLEGAL$ DAD SP$ ALDA $ DCX SP$ ' ;38-3B dc.b ' INR A$ DCR A$ CMVI A,$ CMC$ ' ;3C-3F dc.b ' MOV B,B$ MOV B,C$ MOV B,D$ MOV B,E$' ;40-43 dc.b ' MOV B,H$ MOV B,L$ MOV B,M$ MOV B,A$' ;44-47 dc.b ' MOV C,B$ MOV C,C$ MOV C,D$ MOV C,E$' ;48-4B dc.b ' MOV C,H$ MOV C,L$ MOV C,M$ MOV C,A$' ;4C-4F dc.b ' MOV D,B$ MOV D,C$ MOV D,D$ MOV D,E$' ;50-53 dc.b ' MOV D,H$ MOV D,L$ MOV D,M$ MOV D,A$' ;54-57 dc.b ' MOV E,B$ MOV E,C$ MOV E,D$ MOV E,E$' ;58-5B dc.b ' MOV E,H$ MOV E,L$ MOV E,M$ MOV E,A$' ;5C-5F dc.b ' MOV H,B$ MOV H,C$ MOV H,D$ MOV H,E$' ;60-63 dc.b ' MOV H,H$ MOV H,L$ MOV H,M$ MOV H,A$' ;64-67 dc.b ' MOV L,B$ MOV L,C$ MOV L,D$ MOV L,E$' ;68-6B dc.b ' MOV L,H$ MOV L,L$ MOV L,M$ MOV L,A$' ;6C-6F dc.b ' MOV M,B$ MOV M,C$ MOV M,D$ MOV M,E$' ;70-73 dc.b ' MOV M,H$ MOV M,L$ HLT$ MOV M,A$' ;74-77 dc.b ' MOV A,B$ MOV A,C$ MOV A,D$ MOV A,E$' ;78-7B dc.b ' MOV A,H$ MOV A,L$ MOV A,M$ MOV A,A$' ;7C-7F dc.b ' ADD B$ ADD C$ ADD D$ ADD E$ ' ;80-83 dc.b ' ADD H$ ADD L$ ADD M$ ADD A$ ' ;84-87 dc.b ' ADC B$ ADC C$ ADC D$ ADC E$ ' ;88-8B dc.b ' ADC H$ ADC L$ ADC M$ ADC A$ ' ;8C-8F dc.b ' SUB B$ SUB C$ SUB D$ SUB E$ ' ;90-93 dc.b ' SUB H$ SUB L$ SUB M$ SUB A$ ' ;94-97 dc.b ' SBB B$ SBB C$ SBB D$ SBB E$ ' ;98-9B dc.b ' SBB H$ SBB L$ SBB M$ SBB A$ ' ;9C-9F dc.b ' ANA B$ ANA C$ ANA D$ ANA E$ ' ;A0-A3 dc.b ' ANA H$ ANA L$ ANA M$ ANA A$ ' ;A4-A7 dc.b ' XRA B$ XRA C$ XRA D$ XRA E$ ' ;A8-AB dc.b ' XRA H$ XRA L$ XRA M$ XRA A$ ' ;AC-AF dc.b ' ORA B$ ORA C$ ORA D$ ORA E$ ' ;B0-B3 dc.b ' ORA H$ ORA L$ ORA M$ ORA A$ ' ;B4-B7 dc.b ' CMP B$ CMP C$ CMP D$ CMP E$ ' ;B8-BB dc.b ' CMP H$ CMP L$ CMP M$ CMP A$ ' ;BC-BF dc.b ' RNZ$ POP B$ AJNZ $ AJMP $ ' ;C0-C3 dc.b 'ACNZ $ PUSH B$ CADI $ RST 0$ ' ;C4-C7 dc.b ' RZ$ RET$ AJZ $ ILLEGAL$' ;C8-CB dc.b 'ACZ $ ACALL $ CACI $ RST 1$ ' ;CC-CF dc.b ' RNC$ POP D$ AJNC $ COUT $ ' ;D0-D3 dc.b 'ACNC $ PUSH D$ CSUI $ RST 2$ ' ;D4-D7 dc.b ' RC$ ILLEGAL$AJC $ CIN $ ' ;D8-DB dc.b 'ACC $ ILLEGAL$CSBI $ RST 3$ ' ;DC-DF dc.b ' RPO$ POP H$ AJPO $ XTHL$ ' ;E0-E3 dc.b 'ACPO $ PUSH H$ CANI $ RST 4$ ' ;E4-E7 dc.b ' RPE$ PCHL$ AJPE $ XCHG$ ' ;E8-EB dc.b 'ACPE $ ILLEGAL$CXRI $ RST 5$ ' ;EC-EF dc.b ' RP$ POP PSW$AJP $ DI$ ' ;F0-F3 dc.b 'ACP $ PUSH P$ CORI $ RST 6$ ' ;F4-F7 dc.b ' RM$ SPHL$ AJM $ EI$ ' ;F8-FB dc.b 'ACM $ ILLEGAL$CCPI $ RST 7$ ' ;FC-FF page ************************************************************************* * * * Fake FDOS * * * ************************************************************************* * * Fake BDOS for target system * fdos dc.b $76,0,$C9 ;BIOS jump table dc.b $C3,$33,$FF ;Warm boot dc.b $C3,$36,$FF ;Console status dc.b $C3,$39,$FF ;Console input dc.b $C3,$3C,$FF ;Console output dc.b $C3,$3F,$FF ;List output dc.b $C3,$42,$FF ;Punch output dc.b $C3,$45,$FF ;Reader input dc.b $C3,$48,$FF ;Home disk dc.b $C3,$4B,$FF ;Select disk dc.b $C3,$4E,$FF ;Set track dc.b $C3,$51,$FF ;Set sector dc.b $C3,$54,$FF ;Set DMA address dc.b $C3,$57,$FF ;Read dc.b $C3,$5A,$FF ;Write dc.b $C3,$5D,$FF ;Get list device status dc.b $C3,$60,$FF ;Sector translation * * Fake BIOS for target system * dc.b $76,1,$C9 ;Warm boot dc.b $76,2,$C9 ;Console status dc.b $76,3,$C9 ;Console input dc.b $76,4,$C9 ;Console output dc.b $76,5,$C9 ;List output dc.b $76,6,$C9 ;Punch output dc.b $76,7,$C9 ;Reader input dc.b $76,8,$C9 ;Home disk * dc.b $76,9,$C9 ;Select disk * dc.b $76,10,$C9 ;Set track * dc.b $76,11,$C9 ;Set sector * dc.b $76,12,$C9 ;Set DMA address * dc.b $76,13,$C9 ;Read * dc.b $76,14,$C9 ;Write * dc.b $76,15,$C9 ;Get list device status * dc.b $76,16,$C9 ;Sector translation * fdoslen equ *-fdos * * BDOS function vector table * cnop 0,4 bdostab dc.l bdos00,bdos01,bdos02,bdos03,bdos04,bdos05,bdos06,bdos07 dc.l bdos08,bdos09,bdos10,bdos11,bdos12,bdos13,bdos14,bdos15 dc.l bdos16,bdos17,bdos18,bdos19,bdos20,bdos21,bdos22,bdos23 dc.l bdos24,bdos25,bdos26,bdos27,bdos28,bdos29,bdos30,bdos31 dc.l bdos32,bdos33,bdos34,bdos35,bdos36 bdostabn: * * BIOS function vector table * cnop 0,4 biostab dc.l bdosfn,bios01,bios02,bios03,bios04,bios05,bios06,bios07 dc.l bios08,bios09,bios10,bios11,bios12,bios13,bios14,bios15 biostabn: page ************************************************************************* * * * Messages * * * ************************************************************************* dosname dc.b 'dos.library',0 aprompt dc.b 'A>$' crlfmsg dc.b cr,lf,'$' spacemsg dc.b ' $' bsmsg dc.b bs,' ',bs,'$' ;Erases the previous character simsg dc.b si,'$' ;Resets MSB of each output character rawspec dc.b 'RAW:0/0/640/200/CP/M Emulator' dc.b ' by Jim Cathey and Charlie Gibbs - version ' dc.b vermaj&15+'0','.' dc.b vermin/16+'0',vermin&15+'0',' (' dc.b revyear/16+'0',revyear&15+'0','/' dc.b revmonth/16+'0',revmonth&15+'0','/' dc.b revday/16+'0',revday&15+'0',')',0 rawerr dc.b 'Unable to open RAW: - code $' setwin dc.b $9B,'0x',$9B,'8y',$9B,'24t',$9B,'80u',$9B,'H',$9B,'J$' fullmsg dc.b 'Too many files are open!',cr,lf,'$' illgmsg dc.b cr,lf,'Illegal instruction $' ilgmsg2 dc.b ' at $' ilgmsg3 dc.b '.$' dumpmsg dc.b cr,lf,'Register contents:$' dmpmsg2 dc.b cr,lf dc.b '-AF- -BC- -DE- -HL- -SP- -S0- -S1- -S2- -S3- -PC- -op-' dc.b cr,lf,'$' dmpmsg3 dc.b 'Q to quit program, G to go on without tracing,' dc.b 'any other key to continue: $' ilgbios dc.b cr,lf,'Illegal BIOS call $' ilgbdos dc.b cr,lf,'Illegal BDOS call $' tracemsg dc.b cr,lf,'Start trace at >$' tracemg2 dc.b ' End trace at >$' btrcmsg dc.b 'Trace BIOS/BDOS calls? >$' biosmsg dc.b 'BIOS call $' bdosmsg dc.b 'BDOS call $' atmsg dc.b ' at $' esctran dc.b 'ABCD',ff,so,si,'H',$8D,'JKLMP' ;Escape sequence translation prtname dc.b 'PRT:RAW',0 badprt dc.b 'Unable to open the list device!$' page ************************************************************************* * * * Variable storage * * * ************************************************************************* bss bss savesp ds.l 1 ;Stack pointer save area dosbase ds.l 1 ;Pointer to dos.library stdin ds.l 1 ;Keyboard handle (stdin) stdout ds.l 1 ;Screen handle (stdout) rawhand ds.l 1 ;RAW: file handle prthand ds.l 1 ;PRT:RAW file handle handles ds.l 8 ;File handles for opened files (or zero) handlen: ;End of file handle table dmaaddr ds.l 1 ;Current DMA address comend ds.l 1 ;End of .COM file name on command line cmdline ds.b 128 ;Command line cmdlinen: ;End of command line comname ds.b 13 ;Name of file to load comnamen: ;End of file name opnname ds.b 17 ;File name for OPEN or RENAME renname ds.b 17 ;New file name for RENAME newrega ds.b 1 ;BIOS/BDOS accumulator work area workbuf ds.b 80 ;Work buffer for "pstring" (including $) workbufn: ;End of work buffer strbuf ds.b 2048 ;String output buffer strbufn ds.b 8 ;"strbuf" overflow area - must follow "strbuf"! strptr ds.l 1 ;Current position in "strbuf" escbuf ds.b 8 ;Translated escape sequence esclen ds.w 1 ;Number of bytes saved in "escbuf" cmdflag ds.b 1 ;Take program name from command line. quitflg ds.b 1 ;"quitprg" exit flag testdol ds.b 1 ;"pstring" should test for leading $ insflag ds.b 1 ;We're in insert mode. dumpcnt ds.b 1 ;"dump" counter for pausing btrcflg ds.b 1 ;Trace BIOS/BDOS calls. bufflag ds.b 1 ;Console output is buffered. fcbptr ds.l 1 ;Pointer to current FCB listopn ds.b 1 ;The list device is open. ************************************************************************* * * * Target processor's address space * * * ************************************************************************* even registers ds.b 10 ;Actual storage for 8080's other registers target ds.b $10000 ;8080's universe end