home *** CD-ROM | disk | FTP | other *** search
- vermaj equ $02 ;Major version number
- vermin equ $30 ;Minor version number
- revyear equ $89 ;Year last assembled
- revmonth equ $01 ;Month last assembled
- revday equ $09 ;Day last assembled
- *************************************************************************
- * *
- * *
- * Z-80 Simulator for MC68000 *
- * *
- * With CP/M 2.2 call support, and optional tracing *
- * *
- * *
- * Amiga version 2.3 (December 1988, Charlie Gibbs): *
- * *
- * Incorporated modifications by Willi Kusche *
- * (his version 2.1, June 29, 1988): *
- * Register definitions split into "ecpmdefs.i" *
- * Improved macro usage *
- * Correction of errors in Z-80 flag setting routines *
- * Incorporated modified trace dump routines *
- * Allow changing of trace addresses during execution *
- * Added the following BDOS calls: *
- * 27 - get allocation vector *
- * (using a fake allocation vector) *
- * 31 - get disk parameter block *
- * (using a fake disk parameter block) *
- * *
- * Modifications inspired by Ulf Nordquist's CP/M emulator: *
- * - BDOS calls 17 and 18 (search for first file and *
- * search for next file) now put file size information *
- * into the FCB. *
- * - BDOS call 27 (get allocation vector) now builds a fake *
- * allocation vector based on actual volume information. *
- * *
- * The file handle table now also contains the first 12 bytes *
- * of the FCB to which the handle corresponds. The FCB is *
- * no longer modified with a sequence number. *
- * *
- * BDOS call 20 (sequential read) now returns 01h in the *
- * accumulator when end of file is reached, rather than 0FFh *
- * as is suggested by CP/M manuals. Some utilities (such as *
- * ASM.COM) assume 0FFh indicates an I/O error. *
- * *
- * A new INCLUDE file, options.i, has been added. This file *
- * contains EQUate statements which allow you to set options *
- * that cannot be easily set at execution time. Current options *
- * allow inclusion of Heath/Zenith 19 escape code translation, *
- * and support of 68010 and higher processors by replacing all *
- * MOVE SR instructions by MOVE CCR. *
- * *
- * *
- * Amiga version 2.2 (June 1988, Charlie Gibbs): *
- * *
- * BDOS call 23 (rename) was not working properly. *
- * *
- * BIOS and BDOS call messages (for tracing or errors) *
- * now indicate that the call number is in hexadecimal. *
- * *
- * The following BDOS calls have now been implemented: *
- * 35 - get file end address *
- * 36 - get direct address *
- * *
- * *
- * Amiga version 2.1 (May 1988, Charlie Gibbs): *
- * *
- * If a reference is made to any drive other than A:, SimCPM *
- * will insert the string CPMx: ahead of any file name it uses. *
- * For instance, if a program tries to open MYFILE.DAT on drive *
- * B:, SimCPM will try to open CPMB:MYFILE.DAT. You can ASSIGN *
- * these simulated drives anywhere you want. Drive A: will *
- * always go to the current directory, unless the user number *
- * is not zero. If you specify any user number other than zero, *
- * it will be included, e.g. if the above example were opened *
- * under user 1, SimCPM will look for CPMB01:MYFILE.DAT. *
- * If the file were on drive A under user 1, SimCPM will look *
- * for CPMA01:MYFILE.DAT. *
- * *
- * If the file handle table overflowed, the file which caused *
- * the overflow has already been opened. It was not being *
- * closed again. This file is now closed before the emulated *
- * program is aborted. *
- * *
- * If an emulated program failed to close all the files it opened, *
- * the emulator would close these files. However, it did not *
- * clear the open flag for any such files. If another program *
- * was then run, when it terminated the emulator would try to *
- * close these same files again. This bug has been corrected. *
- * *
- * Z-80 instructions not supported by version 2.0 have been *
- * implemented as follows: *
- * LD I,A moves to a dummy interrupt register. *
- * LD A,I moves from a dummy interrupt register. *
- * LD R,A is ignored. *
- * LD A,R moves a random value from the clock into *
- * the low-order 7 bits of the accumulator. *
- * IM1 and IM2 are ignored. *
- * *
- * The -z command-line switch has been implemented. *
- * It sets instruction tracing, just like the -t switch, *
- * but causes Z-80 instruction mnemonics to be used. *
- * If this switch is not set, 8080 mnemonics are used. *
- * *
- * BDOS call 32 (get or set user code) is now fully implemented. *
- * *
- * The following BDOS calls have now been implemented: *
- * 13 - reset all drives *
- * 24 - get active drive map *
- * 28 - protect drive *
- * 29 - get read-only drive map *
- * *
- * The USER and SAVE built-in commands have been implemented. *
- * These are the only build-in commands provided, since commands *
- * such as DIR or TYPE can be handled through a CLI window. *
- * *
- * *
- * Amiga version 2.0 (January 1988, Charlie Gibbs): *
- * *
- * Added all Z-80 instructions except the following: *
- * LD A,I *
- * LD I,A *
- * LD A,R *
- * LD R,A *
- * IM1 *
- * IM2 *
- * *
- * Added -t flag for tracing without needing *
- * a separate version to maintain speed. *
- * *
- * Added the following BDOS calls: *
- * 17 - search for first file *
- * 18 - search for next file *
- * 24 - get active drive map *
- * (assumes only drive A: is active) *
- * 28 - protect drive (ignored) *
- * 29 - get read-only map *
- * (assumes no drives are protected) *
- * 32 - get or set user code *
- * (always gets user code zero, any attempt *
- * to set to a user code other than zero *
- * results in a fatal error) *
- * *
- * Added serial port support (simulated 8251 on ports 14 and 15) *
- * *
- * *
- * 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,mloopt,tracesad,traceead,traceflg,start2
- xdef illegl,service,dump,inp,outp,movear
-
- xref _AbsExecBase
- xref _CreatePort
- xref _DeletePort
- xdef _SysBase
- xdef _DOSBase
-
- include "options.i"
- include "ecpmdefs.i"
-
- *
- * 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
- page
- *--------------------------------
- *
- * Some commonly used macros
- *
- *--------------------------------
-
- sys macro ;Call a system routine.
- ifnd _LVO\1
- xref _LVO\1
- endc
- jsr _LVO\1(a6)
- endm
-
- *----------------------------
- * Target system Mnemonics
- *----------------------------
- tHLT EQU $76
- tJMP EQU $C3
- tRET EQU $C9
-
- *----------------------
- * Equates
- *----------------------
-
- MODE_OLDFILE equ 1005
- MODE_NEWFILE equ 1006
- ACCESS_READ equ -2
- ACCESS_WRITE equ -1
- STARTBAUD equ 1200 ;Starting baud rate
- NUMBITS equ 8 ;Number of data bits
- CTLCHAR equ $11130501 ;XON, XOFF, ENQ, ACK
- SERFLAGS equ $A0 ;No XON/XOFF, shared
- PARITYON equ 1 ;Parity enabled
- PARITYODD equ 2 ;Odd parity
- * I/O command codes
- CMD_INVALID equ 0
- CMD_RESET equ 1
- CMD_READ equ 2
- CMD_WRITE equ 3
- CMD_UPDATE equ 4
- CMD_CLEAR equ 5
- CMD_STOP equ 6
- CMD_START equ 7
- CMD_FLUSH equ 8
- CMD_NONSTD equ 9
- SDCMD_QUERY equ CMD_NONSTD
- SDCMD_BREAK equ CMD_NONSTD+1
- SDCMD_SETPARAMS equ CMD_NONSTD+2 ;Set serial port parameters
- page
- *************************************************************************
- * *
- * Initialization *
- * *
- *************************************************************************
-
- start: move.l sp,savesp ;Save the stack pointer.
- move.l _AbsExecBase,a6
- move.l a6,_SysBase ;Working copy of _AbsExecBase
- 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 traceit ;Clear trace request flag.
- clr.b z80flag ;Clear Z-80 flag.
- 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.
- clr.b frstset ;First call to "setbaud"
- clr.b target+4 ;Set default drive and user to A0:.
- move.w #1,acmap ;Set active drive map to A: only.
- clr.w romap ;No drives are set read-only.
- move.l #STARTBAUD,baud ;Initial serial port parameters
- move.b #NUMBITS,bits
- move.l #strbuf,strptr ;Initialize output buffer pointer.
-
- lea handles,a1
- move.w #(handlen-handles)/4-1,d1
- 1$ clr.l (a1)+ ;Clear file handles.
- dbra d1,1$
- 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 setbuf ;No.
- dbra d0,leadblk ;Skip over leading blank.
- * If the -b switch is given, activate output buffering.
- setbuf 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 1$ ;Yes.
- cmpi.b #'b',1(a0)
- bne.s settrc ;No.
- 1$ move.b #1,bufflag ;Set buffered-output flag.
- bra.s skipsw
- * If the -t switch is given, set "traceit".
- settrc cmpi.b #'T',1(a0)
- beq.s 1$
- cmpi.b #'t',1(a0)
- bne.s setz80
- 1$ move.b #1,traceit ;Set trace flag.
- * If the -z switch is given, set both "z80flag" and "traceit".
- setz80 cmpi.b #'Z',1(a0)
- beq.s 1$
- cmpi.b #'z',1(a0)
- bne.s skipsw
- 1$ move.b #1,z80flag ;Set Z-80 flag.
- move.b #1,traceit ;Set trace flag also.
- * Skip over the switch and check for more.
- skipsw cmpi.b #' ',(a0)+ ;End of switch?
- beq.s 1$ ;Yes.
- dbra d0,skipsw
- addq.l #1,a1 ;Adjust A1.
- bra.s gotcmd ;There is no command line left.
- 1$ 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 _SysBase,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 #loadmsg,d1
- bsr pstring ;Display where we loaded.
- move.l #start,d1
- bsr plong
- bsr pspace
- move.b #'/',d1
- bsr pchar
- bsr pspace
- move.l #start2,d1
- bsr plong
- bsr pcrlf
- 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 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
-
- dosname dc.b 'dos.library',0
- loadmsg dc.b 'SimCPM version '
- dc.b vermaj&15+'0','.',vermin/16+'0',vermin&15+'0'
- dc.b ' has loaded at $'
- 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$'
-
- 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.
- clr.l rpport ;serial.device message port pointers
- clr.l wpport
- 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 (return) ;Execute the simulation.
-
- simsg dc.b si,'$' ;Resets MSB of each output character
- 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
- bsr pbyte
- cmpi.b #$CB,(a0) ;Display sub-op-code for prefixes CB...
- beq.s 1$
- cmpi.b #$DD,(a0) ;DD...
- beq.s 1$
- cmpi.b #$ED,(a0) ;ED...
- beq.s 1$
- cmpi.b #$FD,(a0) ;and FD.
- bne.s 2$
- 1$ move.b 1(a0),d1
- bsr pbyte
- 2$ move.l #ilgmsg2,d1
- bsr pstring
- suba.l targbase,a0
- 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.
-
- illgmsg dc.b cr,lf,'Illegal instruction $'
- ilgmsg2 dc.b ' at $'
- ilgmsg3 dc.b '.$'
- dumpmsg dc.b cr,lf,'Register contents:$'
-
- *
- * Dump all registers and decode the current instruction.
- *
- dump movem.l d0-d3/a1,-(sp)
- bsr pcrlf
- move.b regf,d0
- bsr dspflag
- move.b #'A',(a0)+
- move.b #'=',(a0)+
- move.b rega,d1 ;Accumulator
- bsr ubyte
- move.b #' ',(a0)+
- move.b #'B',(a0)+
- move.b #'=',(a0)+
- move.w regb(regs),d1 ;BC
- bsr uword
- move.b #' ',(a0)+
- move.b #'D',(a0)+
- move.b #'=',(a0)+
- move.w regd(regs),d1 ;DE
- bsr uword
- move.b #' ',(a0)+
- move.b #'H',(a0)+
- move.b #'=',(a0)+
- move.w regh(regs),d1 ;HL
- bsr uword
- move.b #' ',(a0)+
- move.b #'S',(a0)+
- move.b #'=',(a0)+
- move.l pseudosp,d1 ;SP
- sub.l targbase,d1
- bsr uword
- move.b #' ',(a0)+
- move.b #'P',(a0)+
- move.b #'=',(a0)+
- move.l pseudopc,d1 ;PC
- sub.l targbase,d1
- bsr uword
- move.b #' ',(a0)+
- move.l a1,-(sp)
- move.l pseudosp,a1
- moveq #3,d2
- moveq #'0',d3
- tosloop move.b #'S',(a0)+ ;Display the top 4 stack entries.
- move.b d3,(a0)+
- addq.b #1,d3
- move.b #'=',(a0)+
- move.b 1(a1),d1
- ror.w #8,d1
- move.b 0(a1),d1
- bsr uword
- move.b #' ',(a0)+
- addq.l #2,a1
- dbra d2,tosloop
- move.b #'$',(a0)+
- move.l (sp)+,a1
- move.l #workbuf,d1
- bsr pstring ;Displaying as a single string is much faster.
- bsr pcrlf
- move.b regf2(regs),d0 ;Alternate flags
- bsr dspflag
- move.b #'A',(a0)+
- move.b #'''',(a0)+
- move.b rega2(regs),d1 ;Alternate accumulator
- bsr ubyte
- move.b #' ',(a0)+
- move.b #'B',(a0)+
- move.b #'''',(a0)+
- move.w regb2(regs),d1 ;Alternate BC
- bsr uword
- move.b #' ',(a0)+
- move.b #'D',(a0)+
- move.b #'''',(a0)+
- move.w regd2(regs),d1 ;Alternate DE
- bsr uword
- move.b #' ',(a0)+
- move.b #'H',(a0)+
- move.b #'''',(a0)+
- move.w regh2(regs),d1 ;Alternate HL
- bsr uword
- move.b #' ',(a0)+
- move.b #'X',(a0)+
- move.b #'=',(a0)+
- move.w regix(regs),d1 ;IX
- bsr uword
- move.b #' ',(a0)+
- move.b #'Y',(a0)+
- move.b #'=',(a0)+
- move.w regiy(regs),d1 ;IY
- bsr uword
- move.b #' ',(a0)+
- move.b #' ',(a0)+
- move.b (pseudopc),d1 ;Current opcode byte
- cmpi.b #$CB,d1 ;Prefix?
- beq.s oppfx ;Yes.
- cmpi.b #$DD,d1
- beq.s oppfx
- cmpi.b #$ED,d1
- beq.s oppfx
- cmpi.b #$FD,d1
- beq.s oppfx
- move.b #' ',(a0)+
- bsr ubyte ;Unprefixed opcode
- move.b #' ',(a0)+
- bra.s opx
- oppfx bsr ubyte ;Prefix
- move.b 1(pseudopc),d1
- bsr ubyte ;Prefixed opcode
- opx move.b #' ',(a0)+
- *
- * Decode the instruction.
- *
- moveq #0,d0
- move.b (pseudopc),d0 ;Opcode
- clr.b prefix ;Assume it's not a prefix.
- cmpi.b #$DD,d0 ;Is it?
- beq.s dopfx ;Yes.
- cmpi.b #$FD,d0
- bne.s saveop ;No.
- dopfx move.b d0,prefix ;It's a prefix.
- move.b 1(pseudopc),d0 ;The opcode is really here.
- saveop move.b d0,opcode ;Save the opcode.
- * Look up the opcode.
- cmpi.b #$40,d0 ;Is opcode in range 00-3F?
- bcc.s lookupC ;No.
- * The opcode is in the range 00-3F.
- lea mnop008,a1 ;Assume we're using 8080 mnemonics.
- tst.b z80flag ;Should we use Z-80 mnemonics?
- beq.s lokup0c ;No
- lea mnop00z,a1
- lokup0c mulu #12,d0 ;Offset into opcode table
- add.l d0,a1 ;A1 points to decoded instruction
- bra decode ;Decode remainder of instruction.
- * The opcode is in the range C0-FF.
- lookupC cmpi.b #$C0,d0 ;Is opcode in range C0-FF?
- bcs.s lookup8 ;No.
- cmpi.b #$ED,d0 ;ED-prefix instructions?
- beq lookupE ;Yes.
- cmpi.b #$CB,d0 ;CB-prefix instructions?
- beq lookupB ;Yes.
- lea mnopC08,a1 ;Assume we're using 8080 mnemonics.
- tst.b z80flag ;Should we use Z-80 mnemonics?
- beq.s lokupCc ;No.
- lea mnopC0z,a1
- lokupCc subi.w #$C0,d0
- mulu #12,d0 ;Offset into opcode table
- add.l d0,a1 ;A1 points to decoded instruction
- bra decode ;Decode remainder of instruction.
- * The opcode is in the range 80-BF.
- lookup8 cmpi.b #$80,d0 ;Is opcode in range 80-BF?
- bcs.s lookup4 ;No - it's in range 40-7F.
- lea mnop808,a1 ;Assume we're using 8080 mnemonics.
- tst.b z80flag ;Are we?
- beq.s lokup8c ;Yes.
- lea mnop80z,a1 ;Use the Z-80 mnemonic table.
- lokup8c lsr.b #3,d0 ;Divide opcode by 8.
- andi.w #7,d0 ;Instruction type
- mulu #9,d0 ;Offset into opcode table
- add.l d0,a1 ;A1 points to decoded instruction
- bra decode ;Decode remainder of instruction.
- * The opcode is in the range 40-7F.
- lookup4 cmpi.b #$76,d0 ;Is this a HLT (Z-80 HALT) instruction?
- bne.s lokup4m ;No.
- lea mnop768,a1
- tst.b z80flag ;Do the Z-80 mnemonic?
- beq decode ;No.
- lea mnop76z,a1
- bra decode
- lokup4m lea mnop408,a1 ;Assume 8080 MOV instruction.
- tst.b z80flag ;Are we doing Z-80 mnemonics?
- beq decode ;No.
- lea mnop40z,a1 ;Make it a Z-80 LD instruction.
- bra decode
- * CB-prefix instruction decoding
- lookupB move.b 1(pseudopc),d0 ;Sub-opcode
- tst.b prefix ;IX or IY with displacement?
- beq.s lokupB0 ;No.
- move.b 2(pseudopc),d0 ;Skip over the displacement.
- lokupB0 move.b d0,opcode
- cmpi.b #$40,d0 ;Is opcode in range CB00-CB3F?
- bcc.s lokupB4 ;No.
- lea mnopCB08,a1
- lsr.b #3,d0
- mulu #8,d0
- add.l d0,a1
- bra decode
- lokupB4 move.b d0,d1 ;Save the sub-opcode.
- andi.w #$C0,d0 ;Opcode is in range CB40-CBFF.
- lsr.b #3,d0 ;Displacement into 8-byte entries
- lea mnopCB48,a1
- add.l d0,a1
- lokupBm move.b (a1)+,(a0)+ ;Move mnemonic to decoded area.
- cmpi.b #'$',(a1)
- bne.s lokupBm
- move.b d1,d0 ;Get the sub-opcode again.
- andi.w #$38,d0 ;Isolate the bit number.
- lsr.b #3,d0
- addi.b #'0',d0 ;Convert the bit number to ASCII.
- move.b d0,(a0)+ ;Move bit number to decoded instruction.
- move.b #',',(a0)+
- move.b d1,d0
- andi.b #7,d0 ;Isolate the register specification.
- bsr dspreg ;Set up the register number.
- bra dispop
- * ED-prefix instruction decoding
- lookupE move.b 1(pseudopc),d0 ;Sub-opcode
- move.b d0,opcode
- cmpi.b #$40,d0 ;Is it below ED40?
- bcs lookupI ;Yes - it's illegal.
- cmpi.b #$80,d0 ;Is it in range ED40-ED7F?
- bcc lokupE8 ;No.
- lea mnopE48,a1 ;Assume we're using 8080 mnemonics.
- tst.b z80flag ;Should we use Z-80 mnemonics?
- beq.s lokupEc ;No
- lea mnopE4z,a1
- lokupEc andi.w #$3F,d0
- mulu #12,d0 ;Offset into opcode table
- add.l d0,a1 ;A1 points to decoded instruction
- bra decode ;Decode remainder of instruction.
- lokupE8 cmpi.b #$A0,d0 ;Is opcode in range ED80-ED9F?
- bcs lookupI ;Yes - it's illegal.
- cmpi.b #$BC,d0 ;It must be in range EDA0-EDBB.
- bcc lookupI
- lea mnopEA8,a1
- andi.w #$1F,d0
- mulu #5,d0
- add.l d0,a1
- cmpi.b #' ',(a1) ;Is opcode blank?
- bne.s decode ;No - decode the instruction.
- * The instruction is illegal.
- lookupI lea mnopilg,a1 ;Point to "ILLEGAL" message.
- *
- * Decode the instruction according to the string pointed to by A1.
- * The decoded instruction is built where A0 points.
- * See the mnemonic tables for an explanation of operand codes.
- *
- decode:
- * Code "r" - register in bits 0-2 of opcode
- cmpi.b #'r',(a1)
- bne.s decodeq
- move.b opcode,d0
- bsr dspreg
- bra decodex
- * Code "q" - register in bits 3-5 of opcode
- decodeq cmpi.b #'q',(a1)
- bne.s decodep
- move.b opcode,d0
- lsr.b #3,d0
- bsr dspreg
- bra decodex
- * Code "p" - register pair in bits 4-5 of opcode
- decodep cmpi.b #'p',(a1)
- bne decodeh
- move.b opcode,d0
- andi.b #$30,d0 ;Isolate the register bits.
- bne.s decodpd ;They aren't 00.
- move.b #'B',(a0)+ ;00 - register B
- tst.b z80flag ;Are we using Z-80 mnemonics?
- beq decodex ;No.
- move.b #'C',(a0)+ ;Call it BC for Z-80.
- bra decodex
- decodpd cmpi.b #$20,d0
- beq.s decodph
- bhi.s decodps
- move.b #'D',(a0)+ ;01 - register D (DE for Z-80)
- tst.b z80flag
- beq decodex
- move.b #'E',(a0)+
- bra decodex
- decodph cmpi.b #$DD,prefix ;10 - check for index prefix.
- beq.s decodpx ;IX
- bhi.s decodpy ;IY
- move.b #'H',(a0)+ ;Register H (HL for Z-80)
- tst.b z80flag
- beq decodex
- move.b #'L',(a0)+
- bra decodex
- decodpx move.b #'I',(a0)+ ;IX
- move.b #'X',(a0)+
- bra decodex
- decodpy move.b #'I',(a0)+ ;IY
- move.b #'Y',(a0)+
- bra decodex
- decodps cmpi.b #$F0,opcode ;11 - depends on opcode
- bcc.s decodpp
- move.b #'S',(a0)+ ;11 is SP if opcode is less than F0.
- move.b #'P',(a0)+
- bra decodex
- decodpp tst.b z80flag ;Otherwise, it's PSW (AF for Z-80).
- bne.s decodpz
- move.b #'P',(a0)+
- move.b #'S',(a0)+
- move.b #'W',(a0)+
- bra.s decodex
- decodpz move.b #'A',(a0)+
- move.b #'F',(a0)+
- bra.s decodex
- * Code "h" - HL, IX, or IY depending on prefix
- decodeh cmpi.b #'h',(a1)
- bne.s decoden
- cmpi.b #$DD,prefix
- beq.s decodpx ;IX
- bhi.s decodpy ;IY
- move.b #'H',(a0)+ ;HL
- move.b #'L',(a0)+
- bra decodex
- * Code "n" - 8-bit value following opcode
- decoden cmpi.b #'n',(a1)
- bne.s decodea
- move.b 1(pseudopc),d1
- tst.b prefix ;DD or FD prefix?
- beq.s 1$ ;No - we have the value.
- cmpi.b #$36,opcode ;Is opcode below 36?
- bcs.s 1$ ;Yes - it's a move to index register half
- move.b 3(pseudopc),d1 ;The value is actually here.
- 1$ bsr ubyte ;Convert the value to a hex string.
- bra.s decodex
- * Code "a" - 16-bit value following opcode
- decodea cmpi.b #'a',(a1)
- bne.s decodem
- move.b 2(pseudopc),d1
- lsl.w #8,d1
- move.b 1(pseudopc),d1
- cmpi.b #$ED,(pseudopc) ;Is this an ED-prefix instruction?
- beq.s 1$ ;Yes - the value is shifted one byte.
- tst.b prefix ;DD or FD prefix?
- beq.s 2$ ;No - we have the value.
- 1$ move.b 3(pseudopc),d1 ;The value is actually here.
- lsl.w #8,d1
- move.b 2(pseudopc),d1
- 2$ bsr uword ;Convert the value to a hex string.
- bra.s decodex
- * Not a special code - just move the character as is.
- decodem move.b (a1),(a0)+
- * Try for another character to move (and possibly decode).
- decodex addq.l #1,a1
- cmpi.b #'$',(a1)
- bne decode
- *
- * Display the decoded instruction.
- *
- dispop move.b #cr,(a0)+
- move.b #lf,(a0)+
- move.b #'$',(a0)+
- move.l #workbuf,d1
- bsr pstring ;Displaying as a single string is much faster.
- * Pause after every screenful to give the operator time to read it.
- addq.b #1,dumpcnt ;Count the number of times dumped.
- cmpi.b #8,dumpcnt ;Is the screen full of dumps?
- bcs dumpx ;No - exit.
- move.l #dmpmsg3,d1
- bsr pstring ;Ask for operator action.
- bsr dmpstr ;Make sure the prompt gets out!
- movem.l 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)+,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 #'S',dumpcnt ;Stop tracing?
- beq.s 2$ ;Yes.
- cmpi.b #'s',dumpcnt
- beq.s 2$
- cmpi.b #'C',dumpcnt ;Change trace address?
- beq.s 1$ ;Yes.
- cmpi.b #'c',dumpcnt
- bne.s dmpcont
- 1$ bsr gtrange ;Get new trace range.
- 2$ clr.b traceflg ;Disable tracing and continue.
- dmpcont clr.b dumpcnt ;Reset the dump counter.
- dumpx movem.l (sp)+,d0-d3/a1
- rts
-
- dmpmsg3 dc.b 'Q to quit, S to stop tracing, C to change trace,'
- dc.b ' any other key to continue: $'
-
- *
- * Display the register number indicated by the low-order 3 bits of D0.
- * H and L will be displayed as XH and XL if necessary.
- * M ((HL) for Z-80) will be converted to (IX+d) or (IY+d) if necessary.
- *
- dspreg andi.b #7,d0 ;Isolate register number.
- cmpi.b #6,d0 ;Which register is it?
- beq.s dspregm ;M - might need a special routine.
- bhi.s dsprega ;A - this one is easy.
- addi.b #'B',d0 ;Registers B, C, D, E, H, and L
- cmpi.b #'F',d0 ;Is it H or L?
- bcs.s dspregb ;No - we're ready.
- bne.s dspregl ;It's L.
- moveq #'H',d0 ;It's H.
- bra.s dspregp
- dspregl moveq #'L',d0 ;It's L.
- dspregp cmpi.b #$DD,prefix ;Are we manipulating an index register?
- bcs.s dspregb ;No.
- bne.s dspregy ;Register YH or YL
- move.b #'X',(a0)+ ;Register XH or XL
- bra.s dspregb
- dspregy move.b #'Y',(a0)+
- dspregb move.b d0,(a0)+
- rts
- dsprega move.b #'A',(a0)+ ;It's the accumulator.
- rts
- dspregm cmpi.b #$DD,prefix ;Index register?
- bcc.s dspregi ;Yes.
- tst.b z80flag ;Are we using 8080 mnemonics?
- bne.s dspregz ;No.
- move.b #'M',(a0)+ ;It's M for 8080.
- rts
- dspregz move.b #'(',(a0)+ ;It's (HL) for Z-80.
- move.b #'H',(a0)+
- move.b #'L',(a0)+
- move.b #')',(a0)+
- rts
- dspregi move.b #'(',(a0)+ ;It's an indexed operand.
- move.b #'I',(a0)+
- move.b #'X',(a0)+ ;Assume it's IX.
- cmpi.b #$DD,prefix ;Is it?
- beq.s dspregd ;Yes.
- move.b #'Y',-1(a0) ;It's IY.
- dspregd move.b #'+',(a0)+
- move.b 2(pseudopc),d1 ;Displacement
- bsr ubyte
- move.b #')',(a0)+
- rts
-
- *
- * Display the contents of the flag register in D0.
- *
- dspflag lea workbuf,a0
- move.b #'-',d1 ;Carry (assume not set)
- btst #0,d0
- beq 1$
- move.b #'C',d1 ;Carry flag is set.
- 1$ move.b d1,(a0)+
- move.b #'-',d1 ;Zero
- btst #6,d0
- beq 2$
- move.b #'Z',d1
- 2$ move.b d1,(a0)+
- move.b #'-',d1 ;Minus
- btst #7,d0
- beq 3$
- move.b #'M',d1
- 3$ move.b d1,(a0)+
- move.b #'-',d1 ;Even parity
- btst #2,d0
- beq 4$
- move.b #'E',d1
- 4$ move.b d1,(a0)+
- move.b #'-',d1 ;Intermediate carry
- btst #4,d0
- beq 5$
- move.b #'I',d1
- 5$ move.b d1,(a0)+
- move.b #' ',(a0)+
- 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
- 1$ move.b (a6)+,(a0)+
- dbra d0,1$
- lea -256(pseudosp),a0
- move.l a0,d0
- sub.l targbase,d0
- move.b #tJMP,0(targbase) ;Build BIOS and BDOS jumps.
- move.b #tJMP,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
- tst.b traceit ;Is tracing required?
- beq.s 1$ ;No.
- lea mloopt,return ;Point return to trace test.
- 1$ lea flags,flagptr
- lea $100(targbase),pseudopc ;Start execution at 0100H.
- moveq #$E,regcon0e ;Set up quick constants.
- moveq #$1,regcon01
- moveq #$F,regcon0f
- move.l #$FF,regconff
- moveq #0,rega
- moveq #0,regf
- clr.b regi(regs)
- rts
- page
- *
- * Get start and end addresses for tracing.
- *
- entrads tst.b traceit ;Is tracing required?
- beq entradx ;No.
- bsr gtrange ;Get trace range.
- * 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
-
- gtrange 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.
- andi.l #$FFFF,d1
- add.l #target,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
- andi.l #$FFFF,d1
- add.l #target,d1
- move.l d1,traceead
- bsr pcrlf
- rts
-
- tracemsg dc.b cr,lf,'Start trace at >$'
- tracemg2 dc.b ' End trace at >$'
- btrcmsg dc.b 'Trace BIOS/BDOS calls? >$'
-
- *
- * 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.
- * Display the command prompt.
- prompt lea target,targbase ;Just in case "targbase" gets clobbered
- move.b 4(targbase),d1 ;Get the default drive code.
- andi.b #$0F,d1
- addi.b #'A',d1 ;Convert drive code to ASCII letter.
- bsr pchar ;Display the current drive.
- move.b 4(targbase),d1 ;Get user number.
- lsr.b #4,d1 ;Move it to low-order 4 bits.
- beq.s promptp ;Don't insert user number if it's zero.
- cmpi.b #10,d1 ;Is user number 10 or greater?
- bcs.s promptu ;No.
- move.b d1,-(sp)
- move.b #'1',d1
- bsr pchar ;Display tens digit of user number.
- move.b (sp)+,d1
- subi.b #10,d1
- promptu addi.b #'0',d1 ;Convert user number to ASCII.
- bsr pchar ;Display user number.
- promptp move.b #'>',d1
- bsr pchar
- 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 clr.b cmdflag ;Ask for a new command next time.
- clr.b builtin ;Clear "built-in command" flag.
- * Check for a change of drive number.
- tst.b 2(a0) ;Is the command two characters long?
- bne.s convcmd ;No - treat as a normal command.
- cmpi.b #':',1(a0) ;Drive specifier?
- bne.s convcmd ;No.
- bsr ucase ;Get the drive code.
- cmpi.b #'A',d0 ;Is it valid?
- bcs.s opensel ;No.
- cmpi.b #'P',d0
- bhi.s opensel
- subq.b #1,d0
- andi.b #$0F,d0 ;New drive code
- andi.b #$F0,4(targbase)
- or.b d0,4(targbase) ;Insert into current drive slot.
- bra prompt
- opensel move.l #1$,d1
- bsr pstring ;'BDOS Error on '
- bsr ucase
- move.b d0,d1
- bsr pchar ;Drive letter
- move.l #2$,d1
- bsr pstring ;': Select'
- bra prompt ;Try again.
-
- 1$ dc.b 'BDOS Error on $'
- 2$ dc.b ': Select',cr,lf,'$'
-
- * Convert the program file name to an AmigaDOS file name in "comname".
- convcmd lea comname,a2
- cmpi.b #':',1(a0) ;Is there a drive specifier?
- bne.s 1$ ;No.
- bsr ucase ;Get the drive letter.
- cmpi.b #'A',d0 ;Is it valid?
- bcs.s opensel ;No.
- cmpi.b #'P',d0
- bhi.s opensel
- addq.l #1,a0 ;Skip over the colon.
- bra.s 2$
- 1$ move.b 4(targbase),d0 ;Current drive and user number
- beq.s loadnam ;Drive A:, user 0
- andi.b #$0F,d0 ;Isolate current drive bits
- addi.b #'A',d0 ;Convert to drive code.
- 2$ move.b 4(targbase),d1 ;Current drive and user number
- lsr.b #4,d1 ;Isolate the user number.
- bne.s 3$ ;Not zero - make a directory name.
- cmpi.b #'A',d0 ;Are we loading from drive A:?
- beq.s loadnam ;Yes - use the current directory.
- 3$ move.b #'C',(a2)+ ;Convert to AmigaDOS device.
- move.b #'P',(a2)+
- move.b #'M',(a2)+
- move.b d0,(a2)+ ;Insert the drive letter.
- tst.b d1 ;User zero?
- beq.s 5$ ;Yes - don't bother inserting it.
- move.b #'0',(a2)+ ;Assume user number is less than 10.
- cmpi.b #10,d1 ;Is user number 10 or greater?
- bcs.s 4$ ;No.
- move.b #'1',-1(a2) ;Change the first digit to 1.
- subi.b #10,d1
- 4$ addi.b #'0',d1 ;Convert user number to ASCII.
- move.b d1,(a2)+ ;Insert user number into file spec.
- 5$ move.b #':',(a2)+ ;Insert a colon.
- loadnam move.l #comnamen,d1 ;End of name, allowing for .COM suffix
- subq.l #6,d1 ;Allow for .COM suffix.
- sub.l a2,d1 ;Adjust for directory prefix, if any.
- 1$ bsr ucase ;Convert file name to upper case.
- move.b d0,(a2)+
- cmpi.b #' ',(a0) ;End of name?
- beq.s gotname ;Yes.
- tst.b (a0) ;End of command string?
- dbeq d1,1$ ;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.
- * If this is a USER or SAVE command, don't look for a .COM file -
- * we'll process these commands ourselves.
- lea comname,a0 ;Scan for possible device name.
- move.l a0,a1 ;Use A1 as a scan pointer - preserve A0.
- 1$ tst.b (a1) ;End of command name?
- beq.s 2$ ;Yes - there is no device name.
- cmpi.b #':',(a1)+ ;End of device name?
- bne.s 1$ ;No - continue scanning.
- move.l a1,a0 ;Point A0 past the device name.
- 2$ cmpi.b #'.',4(a0) ;Is the command name four characters long?
- bne opencom ;No.
- cmpi.b #'U',(a0) ;Check for a USER command.
- bne.s tstsave
- cmpi.b #'S',1(a0)
- bne.s tstsave
- cmpi.b #'E',2(a0)
- bne.s tstsave
- cmpi.b #'R',3(a0)
- bne.s tstsave
- move.b #1,builtin ;Indicate we have a USER command.
- bra loaded
- tstsave cmpi.b #'S',(a0) ;Check for a SAVE command.
- bne.s opencom
- cmpi.b #'A',1(a0)
- bne.s opencom
- cmpi.b #'V',2(a0)
- bne.s opencom
- cmpi.b #'E',3(a0)
- bne.s opencom
- move.b #2,builtin ;Indicate we have a SAVE command.
- bra loaded
- * Open the command file and load it if it exists.
- opencom 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 (unless it's USER or SAVE).
- 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 loadusr ;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 1$ ;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 loadusr ;Yes - we're done.
- cmpi.b #' ',(a0) ;End of file name?
- beq.s getfcbx ;Yes.
- 1$ addq.l #1,a2 ;Start of file name in FCB
- 2$ move.b (a0)+,(a2)+ ;Copy file name to FCB.
- 3$ tst.b (a0) ;End of command?
- beq.s loadusr ;Yes.
- cmpi.b #' ',(a0) ;End of file name?
- beq.s getfcbx ;Yes.
- cmpi.b #'.',(a0) ;Start of file name extension?
- bne.s 2$ ;No - continue loading file name.
- move.l fcbptr,a2 ;Copy original pointer
- lea 9(a2),a2 ;Skip over to extension field.
- addq.l #1,a0 ;Skip over the period.
- bra.s 3$
- getfcbx tst.b (a0) ;End of command line?
- beq.s loadusr ;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 loadusr ;No - stop after two FCBs.
- lea 16(a2),a2 ;Skip over to the next FCB.
- bra.s getfcb ;Load the next FCB.
-
- * If this is a USER or SAVE command, process it here.
- * These are the only built-in commands that SimCPM supports,
- * since the rest are just as easily done through the CLI.
- * The first operand is a USER number or the number of pages to SAVE.
- loadusr tst.b builtin ;Is this a built-in command?
- beq loadcmx ;No - we're done.
- lea $5C(targbase),a0 ;Scan the first FCB.
- moveq #0,d0 ;Build the number here.
- tst.b (a0)+ ;Is drive code omitted?
- bne.s badunum ;No - we don't have a valid number.
- cmpi.b #' ',(a0) ;Is the number missing?
- beq.s badunum ;Yes - error.
- cmpi.b #' ',3(a0) ;Is the number too long?
- bne.s badunum ;Yes - it's likely too big.
- getuser cmpi.b #'0',(a0) ;Is the current digit valid?
- bcs.s badunum ;No.
- cmpi.b #'9',(a0)
- bhi.s badunum
- mulu #10,d0 ;Shift previous digits, if any.
- move.b (a0)+,d1 ;Get the current digit.
- andi.w #$0F,d1 ;Convert current digit to binary.
- add.w d1,d0 ;Accumulate total.
- cmpi.b #' ',(a0) ;End of number?
- bne.s getuser ;No - try for another digit.
- bra.s chkuser
- badunum moveq #-1,d0 ;Invalid number
- chkuser cmpi.b #1,builtin ;Is this a USER command?
- bne.s chksave ;No.
- cmpi.w #15,d0 ;Is user number over 15?
- bls.s setuser ;No - it's valid.
- move.l #badumsg,d1
- bsr pstring ;Display an error message and try again.
- bra prompt
- setuser andi.b #$0F,4(targbase);Clear original user number.
- lsl.b #4,d0 ;Move new user bits into position.
- or.b d0,4(targbase) ;Insert new user number.
- bra prompt
-
- badumsg dc.b 'Invalid user number',cr,lf,'$'
-
- chksave tst.w d0 ;Attempt to save zero blocks?
- beq.s badblks ;Yes - error.
- cmpi.w #255,d0 ;Is number of blocks to SAVE valid?
- bls.s savefn ;Yes.
- badblks move.l #1$,d1
- bsr pstring
- bra prompt
- 1$ dc.b 'Number of pages must be from 1 to 255.',cr,lf,'$'
- savefn lea $6C(targbase),a0;FCB for SAVE file name
- cmpi.b #' ',1(a0) ;Is file name missing?
- bne.s opensav ;No.
- move.l #1$,d1
- bsr pstring
- bra prompt
- 1$ dc.b 'File name is missing.',cr,lf,'$'
- opensav lea opnname,a1 ;Build AmigaDOS file name here.
- move.l a1,d1 ;We'll need it here.
- move.l d0,-(sp) ;Save number of blocks to save.
- bsr convfn ;Make a file name.
- move.l #MODE_NEWFILE,d2
- move.l _DOSBase,a6
- sys Open ;Open the file.
- tst.l d0 ;Did the open fail?
- bne.s saveit ;No.
- move.l (sp)+,d0 ;Clean up the stack.
- move.l #1$,d1
- bsr pstring
- bra prompt
- 1$ dc.b 'Unable to open file for SAVE.',cr,lf,'$'
- saveit move.l d0,d1 ;Handle for SAVE file
- lea target+$100,a0 ;"targbase" isn't intact right now.
- move.l a0,d2 ;Start of data to save
- move.l (sp)+,d3 ;Number of 256-byte pages to save
- asl.l #8,d3 ;Convert to number of bytes.
- move.l d1,-(sp) ;Save the file handle.
- sys Write ;Write the file.
- move.l (sp)+,d1
- sys Close ;Close the file.
- bra prompt ;Successful completion
-
- * We have successfully loaded a .COM file.
- loadcmx 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
- bcs.s ucasex
- cmpi.b #'z',d0
- bhi.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 Z-80 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
- 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
- bsr dump
- bra quitprg
-
- ilgbios dc.b cr,lf,'Illegal BIOS call $'
- biosmsg dc.b 'BIOS call $'
- atmsg dc.b ' (hex) at $'
-
- 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
- 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
- bsr dump
- bra quitprg
-
- ilgbdos dc.b cr,lf,'Illegal BDOS call $'
- bdosmsg dc.b 'BDOS call $'
-
- 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?
- bcs.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 1$ ;The open was successful.
- move.l #badprt,d1
- bsr pstring ;Indicate an unsuccessful open.
- bsr dump ;Spill guts...
- bra quitprg ; and exit.
- 1$ 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
-
- prtname dc.b 'PRT:RAW',0
- badprt dc.b 'Unable to open the list device!$'
-
- bdos06 cmpi.b #$FF,rege(regs) ;Direct console I/O
- bne 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.
- move.b #$22,newrega ;Some programs use undocumented return reg.
- clr.b regb(regs)
- bra results
-
- bdos13 move.b 4(targbase),d0 ;Reset all drives
- andi.b #$0F,d0 ;Current drive
- moveq #1,d1
- lsl.w d0,d1 ;Set up drive bit.
- move.w d1,acmap ;Set active drive map to current drive only.
- clr.w romap ;Reset read-only map.
- bra results
-
- bdos14 move.b rege(regs),d0 ;Select drive
- andi.b #$0F,d0 ;Isolate drive bits.
- andi.b #$F0,4(targbase)
- or.b d0,4(targbase) ;Insert new bits.
- moveq #1,d1
- lsl.w d0,d1 ;Set up drive bit.
- or.w d0,acmap ;Add new drive to active drive map.
- bra results
-
- bdos15 move.l d1,-(sp) ;Open existing file
- bsr gethand
- tst.l d1 ;Is the file already open?
- beq.s bdos15g ;No - go ahead.
- clr.l (a1) ;Clear file handle table entry.
- sys Close ;Close the file.
- bdos15g move.l (sp)+,d1
- add.l #target,d1
- move.l #MODE_OLDFILE,d2
- movea.l d1,a0 ;The FCB is here.
- bsr mapdrv ;Get drive map bit.
- bdos15o move.l a0,-(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)/16-1,d1
- move.b #$FF,newrega ;Assume the open failed.
- tst.l d0 ;Did it fail?
- beq results ;Yes.
- clr.b newrega ;Set flag to indicate success.
- 1$ tst.l (a0) ;Available handle entry?
- beq.s 2$ ;Yes.
- lea 16(a0),a0 ;Check the next entry.
- dbra d1,1$
- move.l d0,d1 ;File handle table overflow!
- sys Close ;Close the file.
- move.l #fullmsg,d1
- bsr pstring ;Display an error message
- bra quitprg ; and forget the whole thing.
- 2$ move.l d0,(a0)+ ;Save the file handle.
- moveq #11,d0
- 3$ move.b (a1)+,(a0)+ ;Move first 12 bytes of FCB to table.
- dbra d0,3$
- move.w newdmap,d0
- or.w d0,acmap ;Add drive to active drive map.
- bra results
-
- fullmsg dc.b 'Too many files are open!',cr,lf,'$'
-
- bdos16 move.b #$FF,newrega ;Close file
- bsr gethand ;Get the file handle.
- tst.l d1 ;Did we find it?
- beq results ;No - return failure code.
- clr.l (a1) ;Clear the handle table entry.
- sys Close ;Close the file.
- clr.b newrega ;Indicate success.
- bra results
-
- bdos18 lea renname,a0 ;Search for next file
- bra.s bdos17i
- bdos17 lea srchnam,a0 ;Search for first file
- bdos17i move.b #$FF,newrega ;Assume we'll fail.
- add.l targbase,d1
- movea.l d1,a1 ;The FCB is here.
- addq.l #1,a1 ;The file name is here.
- moveq #10,d0
- 1$ cmp.b #'*',(a1) ;Is this an asterisk?
- beq.s 2$ ;Yes - replace with question marks.
- move.b (a1)+,(a0)+ ;Move the current character.
- dbra d0,1$
- bra.s bdos17c
- 2$ move.b #'?',(a0)+ ;Convert to question marks.
- addq.l #1,a1
- subq #1,d0
- bmi.s bdos17c ;The asterisk was in the extension.
- cmpi.w #2,d0 ;End of file name?
- bne.s 2$ ;No - insert another question mark.
- bra.s 1$ ;Start the extension field.
- bdos17c lea target,targbase
- cmpi.b #18,regc(regs) ;Search for next file?
- bne.s bdos17k ;No.
- lea srchnam,a0
- lea renname,a1
- moveq #10,d0
- 1$ cmp.b (a0)+,(a1)+ ;Search for the same name as last time?
- bne results ;No - exit with failed status.
- dbra d0,1$
- tst.l fibsize ;Is the last file completely done?
- beq.s bdos17k ;Yes - try for another one.
- pea 0 ;Housekeeping for the stack
- bra.s bdos17b ;Create an entry for the next extent.
- bdos17k move.l #null,d1
- move.l #ACCESS_READ,d2
- sys Lock ;Get a file lock.
- tst.l d0 ;Did we fail?
- beq results ;Yes - exit.
- move.l d0,-(sp) ;Save the lock.
- move.l d0,d1 ;Put it here for Examine.
- move.l #fib,d2
- lea target,targbase
- move.w newdmap,d0
- or.w d0,acmap ;Add drive to active drive map.
- cmpi.b #18,regc(regs) ;Search for next file?
- beq.s bdos17n ;Yes.
- sys Examine ;Set up to find the first file.
- tst.l d0 ;Did we succeed?
- beq bdos17x ;No.
- bdos17n move.l (sp),d1
- move.l #fib,d2
- sys ExNext ;Look for the next file.
- tst.l d0 ;Did we succeed?
- beq bdos17x ;No.
- tst.l fibtype ;Is this a file entry?
- bpl bdos17n ;No - ignore subdirectory entries.
- clr.w ext17 ;Clear extent number.
-
- bdos17b move.l dmaaddr,a1 ;Build a fake FCB here.
- clr.b (a1)+ ;Clear drive code.
- move.l a1,-(sp) ;The file name starts here.
- moveq #10,d0
- 1$ move.b #' ',(a1)+ ;Clear file name and extension.
- dbra d0,1$
- moveq #19,d0
- 2$ clr.b (a1)+ ;Clear remainder of FCB to zeros.
- dbra d0,2$
- lea fibname,a0 ;A0 scans AmigaDOS file name.
- move.l (sp)+,a1 ;A1 builds CP/M file name.
- bdos17f tst.b (a0) ;End of file name?
- beq.s 2$ ;Yes.
- move.b (a0)+,d0 ;Get the current character.
- cmpi.b #'a',d0 ;Is it lower case?
- bcs.s 1$ ;No - leave it alone.
- cmpi.b #'z'+1,d0
- bcc.s 1$
- subi.b #'a'-'A',d0 ;Convert to upper case.
- 1$ move.b d0,(a1)+ ;Move the (possibly-converted) character.
- cmp.b #'.',(a0) ;Start of file name extension?
- bne.s bdos17f ;No.
- move.l dmaaddr,d0
- add.w #9,d0 ;Point to start of extension field.
- cmpa.l d0,a1 ;Is file name too long?
- bhi bdos17n ;Yes - not a valid CP/M file name - ignore it.
- move.l d0,a1
- addq.l #1,a0 ;Skip over period.
- bra.s bdos17f ;Get the file name extension.
- 2$ move.l dmaaddr,d0
- add.w #13,d0
- cmpa.l d0,a1 ;Is the file name too long?
- bhi bdos17n ;Yes - ignore it.
- move.l dmaaddr,a0
- addq.l #1,a0
- lea srchnam,a1
- moveq #10,d0
- 3$ cmpi.b #'?',(a1) ;Wild card character?
- bne.s 4$ ;No - compare it.
- addq.l #1,a0 ;Skip over wild card character.
- addq.l #1,a1
- dbra d0,3$
- bra.s bdos17w ;We found a wild card match.
- 4$ cmp.b (a0)+,(a1)+ ;Does the file name match the search name?
- bne bdos17n ;No - try for another one.
- dbra d0,3$ ;Check the next character.
- bdos17w lea target,targbase
- moveq #0,d1
- move.w regd(regs),d1
- moveq #0,d0
- move.b 12(targbase,d1.l),d0 ;Extent flag
- beq.s bdos17h ;Extent zero - take it.
- cmpi.b #'?',d0 ;Search for all extents?
- beq.s bdos17h ;Yes - take this one.
- move.w d0,ext17 ;Save extent number.
- moveq #14,d1
- lsl.l d1,d0 ;Multiply by 16384 to get byte displacement.
- sub.l d0,fibsize ;Beyond end of file? (Adjust byte count!)
- bcs bdos17n ;Yes - forget this entry.
-
- bdos17h clr.b newrega ;Set success flag.
- move.l dmaaddr,a0 ;The FCB is here.
- move.w ext17,d0 ;Current extent number (counts up from zero)
- move.b d0,12(a0) ;Insert it into the FCB.
- andi.b #$1F,12(a0) ;Only the low-order 5 bits go here.
- lsr.l #5,d0
- move.b d0,14(a0) ;High-order portion of extent number
- move.l fibsize,d0 ;Number of bytes remaining
- move.b #$80,15(a0) ;Assume the current extent is full.
- cmpi.l #16384,d0 ;Is it?
- bcc.s 1$ ;Yes.
- and.l #$3FFF,d0 ;Number of bytes in the last extent
- add.w #$7F,d0 ;(for rounding)
- lsr.l #7,d0 ;Number of 128-byte records in extent
- move.b d0,15(a0) ;Store record count in FCB.
- 1$ lea target,targbase
- moveq #0,d1
- move.w regd(regs),d1
- cmpi.b #'?',12(targbase,d1.l) ;Search for all extents?
- bne.s 2$ ;No - we're done with this file.
- addq.w #1,ext17 ;Bump extent counter.
- move.l #16384,d0
- sub.l d0,fibsize ;Decrement remaining byte count
- bhi.s bdos17x ;There's more to do.
- 2$ clr.l fibsize ;Set remaining count to zero.
- bdos17x move.l (sp)+,d1 ;Get the lock.
- beq results ;Ignore dummy entry for multi-extent file.
- sys UnLock ;Release the lock.
- bra results
-
- bdos19 add.l targbase,d1 ;Delete file
- movea.l d1,a0 ;The FCB is here.
- bsr mapdrv ;Get drive map bit.
- and.w romap,d1 ;Is this drive read-only?
- bne roerr ;Yes - abort the deletion.
- 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.
- move.w newdmap,d0
- or.w d0,acmap ;Add drive to active drive map.
- bra results
-
- bdos20 clr.b newrega ;Sequential read
- bsr gethand
- tst.l d1
- beq.s 1$
- move.l dmaaddr,d2
- move.l #128,d3
- sys Read
- tst.l d0 ;Were we successful?
- bgt results ;Yes.
- 1$ move.b #$1,newrega ;Set end-of-file flag.
- bra results
-
- bdos21 clr.b newrega ;Sequential write
- bsr gethand
- tst.l d1
- beq.s 1$
- move.l d1,-(sp)
- bsr mapdrv ;Get drive map bit.
- move.w d1,d0
- move.l (sp)+,d1
- and.w romap,d0 ;Is this drive read-only?
- bne.s roerr ;Yes - error
- move.l dmaaddr,d2
- move.l #128,d3
- sys Write
- tst.l d0 ;Were we successful?
- bgt results ;Yes.
- 1$ move.b #$FF,newrega ;Set failure flag.
- bra results
-
- bdos22 move.l d1,-(sp) ;Make new file
- bsr gethand
- tst.l d1 ;Is the file already open?
- beq.s bdos22g ;No - go ahead.
- clr.l (a1) ;Clear file handle table entry.
- sys Close ;Close the file.
- bdos22g move.l (sp)+,d1
- add.l #target,d1
- move.l #MODE_NEWFILE,d2
- movea.l d1,a0 ;The FCB is here.
- bsr mapdrv ;Get the drive map bit.
- and.w romap,d1 ;Is the drive read-only?
- beq bdos15o ;No - continue with BDOS 15 open routine
- roerr move.l #1$,d1
- bsr pstring ;'BDOS Error on '
- bsr ucase
- move.b d0,d1
- add.b #'A',d1
- bsr pchar ;Drive letter
- move.l #2$,d1
- bsr pstring ;': R/O'
- bra quitprg ;Abort the program.
-
- 1$ dc.b 'BDOS Error on $'
- 2$ dc.b ': R/O',cr,lf,'$'
-
- bdos23 add.l targbase,d1 ;Rename file
- movea.l d1,a0
- move.l a0,-(sp)
- bsr mapdrv ;Get drive map bit.
- and.w romap,d1 ;Is this drive read-only?
- bne roerr ;Yes - error
- lea opnname,a1
- bsr convfn ;Convert old file name.
- move.l (sp)+,a0
- lea 16(a0),a0
- lea renname,a1
- bsr convfn ;Convert new file name.
- move.l #opnname,d1
- move.l #renname,d2
- sys Rename ;Rename the file.
- move.w newdmap,d1
- or.w d1,acmap ;Add drive to active drive map.
- clr.b newrega ;Assume we succeeded.
- tst.l d0 ;Did we fail?
- bne results ;No.
- move.b #$FF,newrega
- bra results
-
- bdos24 move.w acmap,regh(regs);Get active drive map
- bra results
-
- bdos25 move.b 4(targbase),newrega ;Get default drive number
- andi.b #$0F,newrega ;Isolate drive bits.
- bra results
-
- bdos26 add.l targbase,d1 ;Set file buffer address
- move.l d1,dmaaddr
- bra results
-
- bdos27 move.w #fakealv-fdos+$FF00,regh(regs) ;Get allocation vector
- move.b regl(regs),newrega ;Make undocumented copy.
- move.b regh(regs),regb(regs)
- move.l #null,d1
- move.l #ACCESS_READ,d2
- sys Lock ;Get a file lock.
- move.l d0,d1 ;Did we fail?
- beq results ;Yes - exit.
- move.l d0,-(sp) ;Save the lock.
- move.l #InfoData,d2
- sys Info ;Get disk information.
- tst.l d0 ;Did we fail?
- beq bdos27x ;Yes - exit.
- lea fakealv-fdos+$FF00,a0
- adda.l targbase,a0 ;A0 loads allocation vector.
- move.b #$F0,(a0)+ ;Initial allocation for directory
- clr.b (a0)+
- move.l a0,-(sp)
- move.l id_NumBlocks,d1 ;Number of 512-byte blocks on disk
- addq.l #3,d1
- lsr.l #2,d1 ;Convert to 2048-byte blocks for CP/M.
- move.l d1,d0
- subq.l #1,d0
- move.b d0,fakedpb+5 ;Insert high block number in DPB.
- lsr.l #8,d0
- move.b d0,fakedpb+6
- 1$ clr.b (a0)+ ;Clear remainder of allocation vector.
- dbra d1,1$
- move.l (sp)+,a0
- move.l id_NumBlocksUsed,d0 ;Number of 512-byte blocks used
- moveq #11,d1
- lsr.w #2,d0 ;CP/M (2048-byte) blocks used
- beq.s bdos27x ;Nothing is allocated.
- move.w d0,d1
- and.w #7,d1 ;Number of bits to set in partial ALV byte
- beq.s 2$ ;No partial byte
- subq.w #1,d1 ;Number of bits less one
- move.b #$80,d2 ;Here's one bit.
- asr.b d1,d2 ;Make some more.
- move.b d2,(a0)+ ;Store partial allocation vector byte.
- 2$ lsr.w #3,d0 ;Number of ALV bytes to set all bits in
- beq bdos27x ;There are none - we're done.
- subq.w #1,d0
- 3$ move.b #$FF,(a0)+ ;Set all bits in these ALV bytes.
- dbra d0,3$
- bdos27x move.l (sp)+,d1
- sys UnLock ;Release the file lock.
- bra results
-
- bdos28 move.b 4(targbase),d0 ;Protect drive
- andi.b #$0F,d0 ;Current drive
- moveq #1,d1
- lsl.w d0,d1 ;Set up drive bit.
- or.w d1,romap ;Add it to read-only map.
- bra results
-
- bdos29 move.w romap,regh(regs);Get read-only map
- bra results
-
- bdos30 equ badbdos ;Set file attributes
-
- bdos31 move.w #fakedpb-fdos+$FF00,regh(regs) ;Get disk parameter block
- move.b regl(regs),newrega ;Make undocumented copy.
- move.b regh(regs),regb(regs)
- bra results
-
- bdos32 cmp.b #$FF,rege(regs) ;Get or set user code
- bne.s 1$ ;Set it.
- move.b 4(targbase),d0 ;Current drive and user code
- lsr.b #4,d0 ;Set up user code.
- move.b d0,newrega
- move.b newrega,regl(regs)
- move.b regh(regs),regb(regs)
- bra results
- 1$ andi.b #$0F,4(targbase);Clear old user code.
- move.b rege(regs),d0 ;Get new user code.
- lsl.b #4,d0 ;Shift bits into position.
- or.b d0,4(targbase) ;Insert new user code.
- bra results
-
- bdos33 pea _LVORead(a6) ;Direct access read
- clr.b newrega
- bsr gethand
- bra.s bdos34c ;Use common read/write routine.
-
- bdos34 pea _LVOWrite(a6) ;Direct access write
- clr.b newrega
- bsr gethand
- move.l d1,-(sp)
- bsr mapdrv ;Get drive map bit.
- move.w d1,d0
- move.l (sp)+,d1
- and.w romap,d0 ;Is this drive read-only?
- bne roerr ;Yes - error
- bdos34c move.l d1,-(sp) ;Save file handle (common read/write routine)
- 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 1$ ;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.
- 1$ move.b #6,newrega ;Set failure (invalid address) flag.
- bra results
-
- bdos35 bsr gethand ;Get file end address
- move.l a0,-(sp) ;Pointer to FCB
- move.l d1,-(sp)
- moveq #0,d2
- moveq #1,d3
- sys Seek ;Jump to end of file.
- move.l (sp)+,d1
- move.l d0,d2 ;Old position
- moveq #-1,d3
- sys Seek ;Go back to the old position.
- move.l (sp)+,a0 ;Restore FCB pointer.
- add.l #$7F,d0 ;Adjust for partial final block, if any.
- lsr.l #7,d0 ;File size in 128-byte records
- move.b d0,33(a0) ;Insert file size into FCB.
- lsr.l #8,d0
- move.b d0,34(a0)
- lsr.l #8,d0
- move.b d0,35(a0)
- bra results
-
- bdos36 bsr gethand ;Get direct address
- move.l a0,-(sp) ;Save pointer to FCB.
- moveq #0,d2
- moveq #0,d3
- sys Seek ;Seek to current position.
- move.l (sp)+,a0 ;Restore FCB pointer.
- lsr.l #7,d0 ;Convert to 128-byte record number.
- beq.s bdos36m ;Beginning of file
- subq.l #1,d0 ;Back up to record just read.
- bdos36m move.b d0,33(a0) ;Insert position into FCB.
- lsr.l #8,d0
- move.b d0,34(a0)
- lsr.l #8,d0
- move.b d0,35(a0)
- bra results
-
- *
- * 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
-
-
- *
- * Set "newdmap" with a bit corresponding to the drive code in the
- * FCB pointed to by A0 (or the default drive if necessary).
- * The contents of "newdmap" will also be in the low-order word of D1.
- * Register D0 will be set to 0 for drive A:, 1 for drive B:, 2 for C:, etc.
- * The contents of register A0 will be preserved.
- *
- mapdrv move.b (a0),d0 ;Drive code
- bne.s 1$ ;The drive is specified.
- move.b 4(targbase),d0 ;Get the default drive.
- andi.b #$0F,d0
- addq #1,d0
- 1$ subq.b #1,d0 ;Adjust drive code so that 0 is A:, etc.
- moveq #1,d1
- lsl.w d0,d1 ;Set up drive map bit.
- move.w d1,newdmap ;Save it.
- rts
-
-
- *
- * Simulation of the Z-80 LD A,R instruction -
- * load a random 7-bit value into the accumulator.
- *
- movear move.l #dtstamp,d1
- movem.l a1/a6,-(sp)
- move.l _DOSBase,a6
- sys DateStamp
- movem.l (sp)+,a1/a6
- move.b dtstamp+11,rega ;Low-order 7 bits of timer ticks
- andi.b #$7F,rega
- jmp (return)
-
-
- *
- * End of program, one way or another
- *
- quitprg move.l savesp,sp ;Restore stack pointer.
- bsr dmpstr ;Dump any outstanding console output.
- clr.w romap ;Clear the read-only map.
-
- * Close the serial.device if it was used.
- tst.l rpport
- beq.s closlis ;Nothing was opened.
- tst.l wpport
- beq.s q3 ;The output port wasn't opened.
-
- lea writreq,a1
- move.l _SysBase,a6
- sys CloseDevice ;Close the serial output device.
-
- move.l wpport,-(sp)
- jsr _DeletePort ;Delete the serial output port.
- addq.l #4,sp
- clr.l wpport
-
- q3 lea readreq,a1
- move.l _SysBase,a6
- sys CloseDevice ;Close the serial input device.
-
- move.l rpport,-(sp)
- jsr _DeletePort ;Delete the serial input port.
- addq.l #4,sp
- clr.l rpport
-
- * If the list device was used, close it.
- closlis 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)/16-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
- clr.l (a0) ;Clear the file handle.
- closnxt lea 16(a0),a0
- 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 _SysBase,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
- lea 2(a0),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
- bsr pstring ;Erase the previous character on the screen.
- movem.l (sp)+,a0-a1
- bra.s getlinl
- bsmsg dc.b bs,' ',bs,'$' ;Erases the previous character
- getlinp movem.l a0-a1,-(sp)
- sys Write ;Echo the current character.
- movem.l (sp)+,a0-a1
- 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 1$ ;No.
- cmpi.b #1,d0 ;Is is the first character?
- beq.s getlinx ;Yes - exit now.
- 1$ 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?
- bcs.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
- bcs pstreun ;Unknown code - copy it as is.
- cmpi.b #'O',d0
- beq.s pstreO ;Reset insert mode.
- bhi pstreun ;Unknown code
- move.l a0,-(sp)
- lea esctran(pc),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 1$ ;No.
- subq.l #1,a2 ;Back over stored CSI character.
- 1$ move.b d2,(a2)+ ;Get the translated code.
- bra.s pstrsub
- esctran dc.b 'ABCD',ff,so,si,'H',$8D,'JKLMP' ;Escape sequence translation
- 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.
- endc
- * 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
- 1$ move.b (a2)+,(a1)+ ;Copy substitution to output string.
- subq.w #1,d3 ;Count down remaining length.
- dbra d0,1$
- 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 1$ ;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.
- 1$ swap d0 ;Get the units digit.
- addi.b #'0',d0 ;Convert it to ASCII.
- move.b d0,(a2)+
- rts
- * 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 2$ ;No.
- cmpi.b #cr,-1(a0) ;Carriage return?
- beq.s 1$ ;Yes - dump the current segment.
- cmpi.b #bel,-1(a0) ;Bell?
- bne.s 2$ ;No - continue buffering.
- 1$ move.l a1,strptr
- bsr dmpstr ;Dump the buffer.
- move.l strptr,a1
- 2$ 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 1$ ;Yes - dump it regardless.
- tst.b bufflag ;Is console buffering in effect?
- bne.s 2$ ;Yes - don't write anything yet.
- 1$ bsr dmpstr ;Dump the buffer.
- move.l strptr,a1
- 2$ 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 2$ ;Zero - don't write anything.
- move.l rawhand,d1 ;Assume we're writing to RAW:
- bne.s 1$
- move.l stdout,d1 ;We don't have RAW: - use stdout.
- 1$ move.l _DOSBase,a6
- sys Write ;Display the line.
- 2$ 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.
- move.b (a0)+,d0 ;Get the drive code.
- bne.s 1$ ;We have a drive code.
- move.b target+4,d0 ;Use the default drive code.
- andi.b #$0F,d0
- addq.b #1,d0 ;Start at 1 for drive A:.
- 1$ cmpi.b #1,d0 ;Is it drive A:?
- beq.s 4$ ;Yes - don't add anything special.
- move.b #'C',(a1)+
- move.b #'P',(a1)+ ;Set up the prefix CPMx:
- move.b #'M',(a1)+ ; where x is the drive letter.
- add.b #'A'-1,d0
- move.b d0,(a1)+
- move.b target+4,d0 ;Get user number.
- lsr.b #4,d0 ;Move it to low-order 4 bits.
- beq.s 3$ ;Don't insert user number if it's zero.
- move.b #'0',(a1)+ ;Assume user number is less than 10.
- cmpi.b #10,d0 ;Is user number 10 or greater?
- bcs.s 2$ ;No.
- move.b #'1',-1(a1) ;Change the first digit to 1.
- subi.b #10,d0
- 2$ addi.b #'0',d0 ;Convert user number to ASCII.
- move.b d0,(a1)+ ;Insert user number into file spec.
- 3$ move.b #':',(a1)+
- 4$ moveq #7,d0 ;Maximum of 8 characters for file name
- convfn1 cmpi.b #' ',(a0) ;End of file name?
- beq.s 3$ ;Yes
- cmpi.b #'*',(a0) ;Wild card?
- bne.s 1$ ;No.
- move.b #'#',(a1)+ ;Convert to AmigaDOS format.
- move.b #'?',(a1)+
- addq.l #1,a0 ;Skip over the asterisk.
- bra.s 2$
- 1$ move.b (a0)+,(a1)+ ;Move one character of file name.
- 2$ dbra d0,convfn1 ;Try for more.
- 3$ movea.l (sp)+,a0 ;Back to start of FCB.
- lea 9(a0),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.
- cmpi.b #'*',(a0) ;Wild card?
- bne.s 1$ ;No.
- move.b #'#',(a1)+ ;Convert to AmigaDOS format.
- move.b #'?',(a1)+
- addq.l #1,a0 ;Skip over the asterisk.
- bra.s 2$
- 1$ move.b (a0)+,(a1)+ ;Move one character of extension.
- 2$ 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 first 12 bytes of the CP/M FCB
- * whose CP/M address is in D1. The file handle (if found) is copied
- * to D1 from the file handle table entry (which is pointed to by A1).
- * If the file handle cannot be found, D1 will be set to zero.
- * In any event, A0 will be set to point to the FCB.
- *
- gethand lea 0(targbase,d1.l),a0 ;The FCB is here.
- lea handles,a1 ;A1 scans the file handle table.
- moveq #(handlen-handles)/16-1,d0
- 1$ movem.l d0/a0-a1,-(sp)
- tst.l (a1) ;Is this entry empty?
- beq.s 3$ ;Yes - ignore it.
- addq.l #4,a1 ;Skip over to file name in table.
- moveq #11,d1
- 2$ cmp.b (a0)+,(a1)+ ;Compare first 12 bytes of FCB with table.
- bne.s 3$ ;No match.
- dbra d1,2$
- movem.l (sp)+,d0/a0-a1
- move.l (a1),d1 ;Here's the file handle.
- rts
- 3$ movem.l (sp)+,d0/a0-a1
- lea 16(a1),a1 ;Try the next table entry.
- dbra d0,1$
- moveq #0,d1 ;Couldn't find the handle!
- rts
- page
- *************************************************************************
- * *
- * Serial port routines *
- * *
- *************************************************************************
-
- *
- * Read a byte from the port whose number is in D0.
- * A0 points to where to put it.
- *
- inp movem.l a1/a6/d2-d3,-(sp)
- cmp.b #$14,d0 ;Port 14?
- bne.s inp15 ;No.
- move.l a0,-(sp)
- tst.l rpport ;Is serial.device open?
- bne.s 1$ ;Yes.
- bsr initser ;Set up serial.device.
- 1$ bsr checkio
- tst.l d0 ;Is a character ready?
- beq.s 2$ ;No - give the previous one again.
- bsr serread ;Read the new character.
- 2$ move.l (sp)+,a0
- move.b charin,(a0) ;Move it to user's area.
- bra.s inpx
- inp15 cmp.b #$15,d0 ;Port 15?
- bne.s inpx ;No - ignore it.
- move.b #7,(a0) ;Assume a character is ready.
- move.l a0,-(sp)
- bsr checkio ;Check whether a character is ready.
- move.l (sp)+,a0
- tst.l d0 ;Is a character ready?
- bne.s inpx ;Yes.
- move.b #5,(a0) ;Don't set "receiver ready" bit.
- inpx movem.l (sp)+,a1/a6/d2-d3
- rts
-
- *
- * Write the byte pointed to by A0 to the port whose number is in D0.
- *
- outp movem.l a1/a6/d2-d3,-(sp)
- cmp.l #$14,d0 ;Port 14?
- bne.s outpx ;No - ignore it.
- move.b (a0),charout ;Character to write
- tst.l rpport ;Is serial.device open?
- bne.s 1$ ;Yes.
- bsr initser ;Set up serial.device.
- 1$ bsr serwrit ;Write the character.
- outpx movem.l (sp)+,a1/a6/d2-d3
- rts
-
- *
- * Initialize the serial port.
- *
- initser:
-
- * Open a reply port for the serial input device.
- lea readreq,a0
- move.w #rsize-1,d0
- 1$ clr.b (a0)+ ;Clear the I/O request block.
- dbra d0,1$
- clr.l -(sp)
- move.l #2$,-(sp)
- jsr _CreatePort ;rpport = CreatePort ("Read_RS", NULL);
- addq.l #8,sp
- move.l d0,rpport
- move.l d0,r_ReplyPort
- bne.s openin
- move.l #3$,d1
- bsr pstring
- bra quitprg
- 2$ dc.b 'Read_RS',0
- 3$ dc.b 'Can''t create input port for serial.device!',cr,lf,'$'
-
- * Open the serial input device.
- openin move.w #rsize,r_MLength
- move.b #SERFLAGS,r_SerFlags
- move.l #CTLCHAR,r_CtlChar
- lea 1$,a0
- moveq #0,d0
- lea readreq,a1
- moveq #0,d1
- move.l _SysBase,a6
- sys OpenDevice
- tst.l d0 ;Were we successful?
- beq.s setin ;Yes.
- move.l #2$,d1
- bsr pstring
- bra quitprg
- 1$ dc.b 'serial.device',0
- 2$ dc.b 'Can''t open serial.device!',cr,lf,'$'
-
- setin move.l baud,r_Baud
- move.b bits,r_ReadLen ;Number of bits per character
- move.b bits,r_WriteLen
- move.w #SDCMD_SETPARAMS,r_Command
- lea readreq,a1
- move.l _SysBase,a6
- sys DoIO ;Set new input port parameters.
-
- * Set up the serial output port.
- lea readreq,a0
- lea writreq,a1
- move.w #wsize-1,d0
- copw move.b (a0)+,(a1)+ ;Clone the read request block.
- dbra d0,copw
- clr.l -(sp)
- move.l #1$,-(sp)
- jsr _CreatePort ;wpport = CreatePort ("Write_RS", NULL);
- addq.l #8,sp
- move.l d0,wpport
- move.l d0,w_ReplyPort
- bne.s startup
- move.l #2$,d1
- bsr pstring
- bra quitprg
- 1$ dc.b 'Write_RS',0
- 2$ dc.b 'Can''t create output port for serial.device!',cr,lf,'$'
-
- startup bsr setbaud ;Set parameters and start reading.
- rts
-
- *
- * Return TRUE (D0 <> 0) if the serial port has a character.
- *
- checkio lea readreq,a1
- move.l _SysBase,a6
- sys CheckIO
- rts
-
- *
- * Set the serial port's baud rate, number of data bits, etc.
- *
- setbaud tas frstset ;Is this the first call?
- beq.s 1$ ;Yes - input port is set up.
- lea readreq,a1
- move.l _SysBase,a6
- sys AbortIO ;Abort the outstanding read.
- move.l baud,r_Baud ;Baud rate
- move.b bits,r_ReadLen ;Number of bits per character
- move.b bits,r_WriteLen
- move.w #SDCMD_SETPARAMS,r_Command
- lea readreq,a1
- move.l _SysBase,a6
- sys DoIO ;Set new input port parameters.
- 1$ move.w #CMD_READ,r_Command
- move.l #1,r_Length
- move.l #charinb,r_Data
- lea readreq,a1
- move.l _SysBase,a6
- sys SendIO ;Start reading again.
- * Now set up the output port - this one is more straightforward.
- move.l baud,w_Baud
- move.b bits,w_ReadLen
- move.b bits,w_WriteLen
- move.w #SDCMD_SETPARAMS,w_Command
- lea writreq,a1
- move.l _SysBase,a6
- sys DoIO
- rts
-
- *
- * Write the byte in "charout" to the serial port.
- *
- serwrit move.w #CMD_WRITE,w_Command
- move.l #1,w_Length
- move.l #charout,w_Data
- lea writreq,a1
- move.l _SysBase,a6
- sys DoIO
- rts
-
- *
- * Read a byte from the serial port into "charin".
- * If a byte isn't ready, this routine will wait until one is.
- *
- serread lea readreq,a1
- move.l _SysBase,a6
- sys WaitIO ;Wait until a character is ready.
- move.b charinb,charin ;Get the character from the buffer.
- move.w #CMD_READ,r_Command
- move.l #1,r_Length
- move.l #charinb,r_Data
- lea readreq,a1
- move.l _SysBase,a6
- sys SendIO ;Get ready for the next character.
- 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 3$
- 1$ 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
- bcs.s 2$
- add.b #'A'-'9'-1,d1 ;Adjust for digits A through F.
- 2$ add.b #'0',d1 ;Convert to ASCII.
- move.b d1,(a0)+ ;Add to the result string.
- move.l (sp)+,d1
- 3$ swap d0 ;Get nybble count.
- dbra d0,1$
- 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 #1$,d1 ;Print a space.
- bsr pstring
- rts
- 1$ dc.b ' $'
-
- pcrlf move.l #1$,d1 ;Print a carriage return and line feed.
- bsr pstring
- rts
- 1$ dc.b cr,lf,'$'
-
- *
- * 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
- 1$ move.b (a0)+,d0 ;Get the current byte.
- cmpi.b #$60,d0
- bcs.s 2$
- andi.b #$5F,d0 ;Mask to upper case.
- 2$ cmpi.b #'0',d0 ;Check range (0..9,A..F).
- bcs.s atolend
- cmpi.b #'F',d0
- bhi.s atolend
- cmpi.b #'9',d0
- bls.s 3$
- cmpi.b #'A',d0
- bcs.s atolend
- 3$ moveq #1,d2 ;Valid characters entered, set flag.
- sub.b #'0',d0 ;Convert to binary
- cmpi.b #$9,d0 ;Digit in range 0..9?
- bls.s 4$ ;Yes - conversion is complete
- sub.b #'A'-'9'-1,d0 ;Adjust digits A..F.
- 4$ ext d0 ;Convert to long.
- ext.l d0
- asl.l #4,d1 ;Tack it onto d1.
- add.l d0,d1
- bra.s 1$ ;Try for another digit.
- atolend subq.l #1,a0 ;Back onto the first invalid digit.
- rts
- page
- *************************************************************************
- * *
- * Instruction mnemonic table (used for tracing) *
- * *
- *************************************************************************
-
- data data
-
- * This table contains the mnemonic strings for the 8080/Z-80 opcodes.
- *
- * "q" denotes a register number in bits 3 through 5 of the opcode.
- * Values are interpreted as follows:
- * Normal 8080 Normal Z-80 DD prefix FD prefix
- * 000 B B B B
- * 001 C C C C
- * 010 D D D D
- * 011 E E E E
- * 100 H H XH YH
- * 101 L L XL YL
- * 110 M (HL) (IX+n) (IY+n)
- * 111 A A A A
- *
- * "r" denotes a register number in bits 0 through 2 of the opcode.
- * Values are interpreted the same as for "q" above.
- *
- * "p" denotes a 2-bit register pair number in bits 4 and 5 of the opcode.
- * Values are interpreted as follows:
- * 8080 Z-80
- * 00 B BC
- * 01 D DE
- * 10 H HL (no DD or FD prefix)
- * 10 IX IX (with DD prefix)
- * 10 IX IX (with FD prefix)
- * 11 SP SP (if opcode is below F0)
- * 11 PSW AF (if opcode is F0 or greater)
- *
- * "h" is replaced by IX or IY if the opcode prefix is DD or FD respectively.
- * If the instruction is not prefixed, "h" is replaced by HL.
- *
- * "n" denotes an 8-bit number following the opcode.
- *
- * "a" denotes a 16-bit address following the opcode.
-
- * Mnemonics for 8080 opcodes 00 through 3F
- mnop008:
- dc.b 'NOP$ LXI p,a$ STAX p$ INX p$ ' ;00-03
- dc.b 'INR q$ DCR q$ MVI q,n$ RLC$ ' ;04-07
- dc.b 'EXAF$ DAD p$ LDAX p$ DCX p$ ' ;08-0B
- dc.b 'INR q$ DCR q$ MVI q,n$ RRC$ ' ;0C-0F
- dc.b 'DJNZ n$ LXI p,a$ STAX p$ INX p$ ' ;10-13
- dc.b 'INR q$ DCR q$ MVI q,n$ RAL$ ' ;14-17
- dc.b 'JR n$ DAD p$ LDAX p$ DCX p$ ' ;18-1B
- dc.b 'INR q$ DCR q$ MVI q,n$ RAR$ ' ;1C-1F
- dc.b 'JRNZ n$ LXI p,a$ ShD a$ INX p$ ' ;20-23
- dc.b 'INR q$ DCR q$ MVI q,n$ DAA$ ' ;24-27
- dc.b 'JRZ n$ DAD p$ LhD a$ DCX p$ ' ;28-2B
- dc.b 'INR q$ DCR q$ MVI q,n$ CMA$ ' ;2C-2F
- dc.b 'JRNC n$ LXI p,a$ STA a$ INX p$ ' ;30-33
- dc.b 'INR q$ DCR q$ MVI q,n$ STC$ ' ;34-37
- dc.b 'JRC n$ DAD p$ LDA a$ DCX p$ ' ;38-3B
- dc.b 'INR q$ DCR q$ MVI q,n$ CMC$ ' ;3C-3F
-
- * Mnemonics for Z-80 opcodes 00 through 3F
- mnop00z:
- dc.b 'NOP$ LD p,a$ LD (p),A$ INC p$ ' ;00-03
- dc.b 'INC q$ DEC q$ LD q,n$ RLCA$ ' ;04-07
- dc.b 'EX AF,AF$ ADD HL,p$ LD A,(p)$ DEC p$ ' ;08-0B
- dc.b 'INC q$ DEC q$ LD q,n$ RRCA$ ' ;0C-0F
- dc.b 'DJNZ n$ LD p,a$ LD (p),A$ INC p$ ' ;10-13
- dc.b 'INC q$ DEC q$ LD q,n$ RLA$ ' ;14-17
- dc.b 'JR n$ ADD HL,p$ LD A,(p)$ DEC p$ ' ;18-1B
- dc.b 'INC q$ DEC q$ LD q,n$ RRA$ ' ;1C-1F
- dc.b 'JR NZ,n$ LD p,a$ LD (a),HL$INC p$ ' ;20-23
- dc.b 'INC q$ DEC q$ LD q,n$ DAA$ ' ;24-27
- dc.b 'JR Z,n$ ADD HL,p$ LD HL,(a)$DEC p$ ' ;28-2B
- dc.b 'INC q$ DEC q$ LD q,n$ CPL$ ' ;2C-2F
- dc.b 'JR NC,n$ LD p,a$ LD (a),A$ INC p$ ' ;30-33
- dc.b 'INC q$ DEC q$ LD q,n$ SCF$ ' ;34-37
- dc.b 'JR C,n$ ADD HL,p$ LD A,(a)$ DEC p$ ' ;38-3B
- dc.b 'INC q$ DEC q$ LD q,n$ CCF$ ' ;3C-3F
-
- * Mnemonics for opcodes 40 through 7f are easy - 76 is HLT
- * (HALT for Z-80), and all others are MOV (LD for Z-80).
- mnop408 dc.b 'MOV q,r$'
- mnop40z dc.b 'LD q,r$'
- mnop768 dc.b 'HLT$'
- mnop76z dc.b 'HALT$'
-
- * Mnemonics for 8080 opcodes 80 through BF
- mnop808:
- dc.b 'ADD r$ ADC r$ SUB r$ SBB r$ ' ;80-9F
- dc.b 'ANA r$ XRA r$ ORA r$ CMP r$ ' ;A0-BF
-
- * Mnemonics for Z-80 opcodes 80 through BF
- mnop80z:
- dc.b 'ADD A,r$ADC A,r$SUB r$ SBC A,r$' ;80-9F
- dc.b 'AND r$ XOR r$ OR r$ CP r$ ' ;A0-BF
-
- * Mnemonics for 8080 opcodes C0 through FF
- * These are interpreted by the same routine as for opcodes 00 through 3F.
- mnopC08:
- dc.b 'RNZ$ POP p$ JNZ a$ JMP a$ ' ;C0-C3
- dc.b 'CNZ a$ PUSH p$ ADI n$ RST 0$ ' ;C4-C7
- dc.b 'RZ$ RET$ JZ a$ ILLEGAL$ ' ;C8-CB
- dc.b 'CZ a$ CALL a$ ACI n$ RST 1$ ' ;CC-CF
- dc.b 'RNC$ POP p$ JNC a$ OUT n$ ' ;D0-D3
- dc.b 'CNC a$ PUSH p$ SUI n$ RST 2$ ' ;D4-D7
- dc.b 'RC$ EXX$ JC a$ IN n$ ' ;D8-DB
- dc.b 'CC a$ ILLEGAL$ SBI n$ RST 3$ ' ;DC-DF
- dc.b 'RPO$ POP p$ JPO a$ XTh$ ' ;E0-E3
- dc.b 'CPO a$ PUSH p$ ANI n$ RST 4$ ' ;E4-E7
- dc.b 'RPE$ PCh$ JPE a$ XCHG$ ' ;E8-EB
- dc.b 'CPE a$ ILLEGAL$ XRI n$ RST 5$ ' ;EC-FF
- dc.b 'RP$ POP p$ JP a$ DI$ ' ;F0-F3
- dc.b 'CP a$ PUSH p$ ORI n$ RST 6$ ' ;F4-F7
- dc.b 'RM$ SPh$ JM a$ EI$ ' ;F8-FB
- dc.b 'CM a$ ILLEGAL$ CPI n$ RST 7$ ' ;FC-FF
-
- * Mnemonics for Z-80 opcodes C0 through FF
- * These are interpreted by the same routine as for opcodes 00 through 3F.
- mnopC0z:
- dc.b 'RET NZ$ LD p,(SP)$JP NZ,a$ JP a$ ' ;C0-C3
- dc.b 'CALL NZ,a$ LD (SP),p$ADD A,n$ RST 0$ ' ;C4-C7
- dc.b 'RET Z$ RET$ JP Z,a$ ILLEGAL$ ' ;C8-CB
- dc.b 'CALL Z,a$ CALL a$ ADC A,n$ RST 8$ ' ;CC-CF
- dc.b 'RET NC$ LD p,(SP)$JP NC,a$ OUT n,A$ ' ;D0-D3
- dc.b 'CALL NC,a$ LD (SP),p$SUB A,n$ RST 10$ ' ;D4-D7
- dc.b 'RET C$ EXX$ JP C,a$ IN A,n$ ' ;D8-DB
- dc.b 'CALL C,a$ ILLEGAL$ SBC A,n$ RST 18$ ' ;DC-DF
- dc.b 'RET PO$ LD p,(SP)$JP PO,a$ EX (SP),p$' ;E0-E3
- dc.b 'CALL PO,a$ LD (SP),p$AND A,n$ RST 20$ ' ;E4-E7
- dc.b 'RET PE$ JP (p)$ JP PE,a$ EX DE,p$ ' ;E8-EB
- dc.b 'CALL PE,a$ ILLEGAL$ XOR A,n$ RST 28$ ' ;EC-FF
- dc.b 'RET P$ LD p,(SP)$JP P,a$ DI$ ' ;F0-F3
- dc.b 'CALL P,a$ LD (SP),p$OR A,n$ RST 30$ ' ;F4-F7
- dc.b 'RET M$ LD SP,h$ JP M,a$ EI$ ' ;F8-FB
- dc.b 'CALL M,a$ ILLEGAL$ CP A,n$ RST 38$ ' ;FC-FF
-
- * Mnemonics for opcodes CB00 through CB3F -
- * these are the same for both the 8080 and the Z-80.
- mnopCB08:
- mnopCB0z:
- dc.b 'RLC r$ RRC r$ RL r$ RR r$ ' ;CB00-CB1F
- dc.b 'SLA r$ SRA r$ ILLEGAL$SRL r$ ' ;CB20-CB3F
-
- * Mnemonics for opcodes CB40 through CBFF -
- * these are the same for both the 8080 and the Z-80.
- mnopCB48:
- mnopCB4z:
- dc.b 'BIT $ RES $ SET $ '
-
- * Mnemonics for 8080 opcodes ED40 through ED7F
- * These are interpreted by the same routine as for opcodes 00 through 3F.
- mnopE48:
- dc.b 'IN q,(C)$ OUT (C),q$ DSBB p$ SBCD a$ ' ;ED40-ED43
- dc.b 'NEG$ RETN$ IM0$ MOV I,A$ ' ;ED44-ED47
- dc.b 'IN q,(C)$ OUT (C),q$ DADC p$ LBCD a$ ' ;ED48-ED4B
- dc.b 'ILLEGAL$ RETI$ ILLEGAL$ MOV R,A$ ' ;ED4C-ED4F
- dc.b 'IN q,(C)$ OUT (C),q$ DSBB p$ SDED a$ ' ;ED50-ED53
- dc.b 'ILLEGAL$ ILLEGAL$ IM1$ MOV A,I$ ' ;ED54-ED57
- dc.b 'IN q,(C)$ OUT (C),q$ DADC p$ LDED a$ ' ;ED58-ED5B
- dc.b 'ILLEGAL$ ILLEGAL$ IM2$ MOV A,R$ ' ;ED5C-ED5F
- dc.b 'IN q,(C)$ OUT (C),q$ DSBB p$ SHLD a$ ' ;ED60-ED63
- dc.b 'ILLEGAL$ ILLEGAL$ ILLEGAL$ RRD$ ' ;ED64-ED67
- dc.b 'IN q,(C)$ OUT (C),q$ DADC p$ LHLD a$ ' ;ED68-ED6B
- dc.b 'ILLEGAL$ ILLEGAL$ ILLEGAL$ RLD$ ' ;ED6C-ED6F
- dc.b 'IN q,(C)$ OUT (C),q$ DSBB p$ SSPD a$ ' ;ED70-ED73
- dc.b 'ILLEGAL$ ILLEGAL$ ILLEGAL$ ILLEGAL$ ' ;ED74-ED77
- dc.b 'IN q,(C)$ OUT (C),q$ DADC p$ LSPD a$ ' ;ED78-ED7B
- dc.b 'ILLEGAL$ ILLEGAL$ ILLEGAL$ ILLEGAL$ ' ;ED7C-ED7F
-
- * Mnemonics for Z-80 opcodes ED40 through ED7F
- * These are interpreted by the same routine as for opcodes 00 through 3F.
- mnopE4z:
- dc.b 'IN q,(C)$ OUT (C),q$ SBC HL,p$ LD (a),p$ ' ;ED40-ED43
- dc.b 'NEG$ RETN$ IM 0$ LD I,A$ ' ;ED44-ED47
- dc.b 'IN q,(C)$ OUT (C),q$ ADC HL,p$ LD p,(a)$ ' ;ED48-ED4B
- dc.b 'ILLEGAL$ RETI$ ILLEGAL$ LD R,A$ ' ;ED4C-ED4F
- dc.b 'IN q,(C)$ OUT (C),q$ SBC HL,p$ LD (a),p$ ' ;ED50-ED53
- dc.b 'ILLEGAL$ ILLEGAL$ IM 1$ LD A,I$ ' ;ED54-ED57
- dc.b 'IN q,(C)$ OUT (C),q$ ADC HL,p$ LD p,(a)$ ' ;ED58-ED5B
- dc.b 'ILLEGAL$ ILLEGAL$ IM 2$ LD A,R$ ' ;ED5C-ED5F
- dc.b 'IN q,(C)$ OUT (C),q$ SBC HL,p$ LD (a),p$ ' ;ED60-ED63
- dc.b 'ILLEGAL$ ILLEGAL$ ILLEGAL$ RRD$ ' ;ED64-ED67
- dc.b 'IN q,(C)$ OUT (C),q$ ADC HL,p$ LD p,(a)$ ' ;ED68-ED6B
- dc.b 'ILLEGAL$ ILLEGAL$ ILLEGAL$ RLD$ ' ;ED6C-ED6F
- dc.b 'IN q,(C)$ OUT (C),q$ SBC HL,p$ LD (a),p$ ' ;ED70-ED73
- dc.b 'ILLEGAL$ ILLEGAL$ ILLEGAL$ ILLEGAL$ ' ;ED74-ED77
- dc.b 'IN q,(C)$ OUT (C),q$ ADC HL,p$ LD p,(a)$ ' ;ED78-ED7B
- dc.b 'ILLEGAL$ ILLEGAL$ ILLEGAL$ ILLEGAL$ ' ;ED7C-ED7F
-
- * Mnemonics for miscellaneous ED-prefix instructions -
- * these are the same for both the 8080 and the Z-80.
- mnopEA8:
- mnopEAz:
- dc.b 'LDI$ CPI$ INI$ OUTI$' ;EDA0-EDA3
- dc.b ' ' ;EDA4-EDA7 (illegal)
- dc.b 'LDD$ CPD$ IND$ OUTD$' ;EDA8-EDAB
- dc.b ' ' ;EDAC-EDAF (illegal)
- dc.b 'LDIR$CPIR$INIR$OTIR$' ;EDB0-EDB3
- dc.b ' ' ;EDB4-EDB7 (illegal)
- dc.b 'LDDR$CPDR$INDR$OTDR$' ;EDB8-EDBB
-
- * Mnemonic for illegal instructions
- mnopilg dc.b 'ILLEGAL$'
- page
- *************************************************************************
- * *
- * Fake FDOS *
- * *
- *************************************************************************
-
- *
- * Fake BDOS for target system
- *
- fdos dc.b tHLT,0,tRET ;BIOS jump table
- dc.b tJMP,$33,$FF ;Warm boot
- dc.b tJMP,$36,$FF ;Console status
- dc.b tJMP,$39,$FF ;Console input
- dc.b tJMP,$3C,$FF ;Console output
- dc.b tJMP,$3F,$FF ;List output
- dc.b tJMP,$42,$FF ;Punch output
- dc.b tJMP,$45,$FF ;Reader input
- dc.b tJMP,$48,$FF ;Home disk
- dc.b tJMP,$4B,$FF ;Select disk
- dc.b tJMP,$4E,$FF ;Set track
- dc.b tJMP,$51,$FF ;Set sector
- dc.b tJMP,$54,$FF ;Set DMA address
- dc.b tJMP,$57,$FF ;Read
- dc.b tJMP,$5A,$FF ;Write
- dc.b tJMP,$5D,$FF ;Get list device status
- dc.b tJMP,$60,$FF ;Sector translation
-
- *
- * Fake BIOS for target system
- *
- dc.b tHLT,1,tRET ;Warm boot
- dc.b tHLT,2,tRET ;Console status
- dc.b tHLT,3,tRET ;Console input
- dc.b tHLT,4,tRET ;Console output
- dc.b tHLT,5,tRET ;List output
- dc.b tHLT,6,tRET ;Punch output
- dc.b tHLT,7,tRET ;Reader input
- dc.b tHLT,8,tRET ;Home disk *
- dc.b tHLT,9,tRET ;Select disk *
- dc.b tHLT,10,tRET ;Set track *
- dc.b tHLT,11,tRET ;Set sector *
- dc.b tHLT,12,tRET ;Set DMA address *
- dc.b tHLT,13,tRET ;Read *
- dc.b tHLT,14,tRET ;Write *
- dc.b tHLT,15,tRET ;Get list device status *
- dc.b tHLT,16,tRET ;Sector translation *
-
- *
- * Fake Disk Parameter Block
- *
- fakedpb dc.b 11,0 ;SPT (sectors per track)
- dc.b 4 ;BSH (block shift to record number)
- dc.b 15 ;BLM (block number mask to record no.)
- dc.b 0 ;EXM (logical->physical extent shift)
- dc.b 439&255,439/256 ;DSM (highest allocation block number)
- dc.b 255,0 ;DRM (highest directory entry number)
- dc.b $F0,0 ;AL0, AL1 (initial allocation vector)
- dc.b 64,0 ;CKS (size of directory check area)
- dc.b 0,0 ;OFF (offset, number of reserved tracks)
-
- *
- * Fake Disk Block Allocation Table
- *
- fakealv dcb.b 21,$FF
- dc.b %11111100
- dcb.b 10,0
-
- 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:
-
- null dc.b 0 ;Null string
- page
- *************************************************************************
- * *
- * Variable storage *
- * *
- *************************************************************************
-
- bss bss
-
- * File information block - must be on a 4-byte boundary!
- fib:
- fibkey ds.l 1
- fibtype ds.l 1 ;Type (file if negative, directory if positive)
- fibname ds.b 108 ;File name (null-terminated)
- fibprot ds.l 1 ;Protection mask
- fibent ds.l 1
- fibsize ds.l 1 ;Number of bytes in file
- fibblks ds.l 1 ;Number of blocks in file
- fibdays ds.l 1 ;Date stamp - number of days since Jan. 1, 1978
- fibmins ds.l 1 ;Date stamp - number of minutes past midnight
- fibtick ds.l 1 ;Date stamp - number of ticks past minute
- fibcmt ds.b 116 ;Comments (null-terminated)
-
- * InfoData structure
- InfoData:
- id_NumSoftErrors ds.l 1 ;number of soft errors on disk
- id_UnitNumber ds.l 1 ;Which unit disk is (was) mounted on
- id_DiskState ds.l 1 ;See defines below
- id_NumBlocks ds.l 1 ;Number of blocks on disk
- id_NumBlocksUsed ds.l 1 ;Number of block in use
- id_BytesPerBlock ds.l 1
- id_DiskType ds.l 1 ;Disk Type code
- id_VolumeNode ds.l 1 ;BCPL pointer to volume node
- id_InUse ds.l 1 ;Flag, zero if not in use
- id_SIZEOF equ 36
-
- * Miscellaneous storage areas
- savesp ds.l 1 ;Stack pointer save area
- _SysBase ds.l 1 ;Copy of _AbsExecBase
- _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*4 ;File handle (or zero) plus 12 bytes of FCB
- 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
- dtstamp ds.l 3 ;Date and time stamp
- rpport ds.l 1 ;Serial input message port
- wpport ds.l 1 ;Serial output message port
- baud ds.l 1 ;New baud rate for "setbaud"
- bits ds.b 1 ;Number of data bits
- charin ds.b 1 ;Current input character
- charinb ds.b 1 ;Serial input buffer
- charout ds.b 1 ;Current output character
- frstset ds.b 1 ;$80 after first call to "setbaud"
- cmdline ds.b 128 ;Command line
- cmdlinen: ;End of command line
- comname ds.b 20 ;Name of file to load
- comnamen: ;End of file name
- opnname ds.b 24 ;File name for OPEN or RENAME
- renname ds.b 24 ;New file name for RENAME
- srchnam ds.b 11 ;CP/M file name for search first/next
- ext17 ds.w 1 ;Extent counter for search first/next
- 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
- traceit ds.b 1 ;-t (trace) flag was set on command line
- btrcflg ds.b 1 ;Trace BIOS/BDOS calls.
- bufflag ds.b 1 ;Console output is buffered.
- z80flag ds.b 1 ;Display Z-80 mnemonics in instruction trace.
- opcode ds.b 1 ;Current opcode (used for tracing)
- prefix ds.b 1 ;Instruction prefix (DD or FD)
- fcbptr ds.l 1 ;Pointer to current FCB
- listopn ds.b 1 ;The list device is open.
- builtin ds.b 1 ;1 = USER command, 2 = SAVE command
- acmap ds.w 1 ;Active drive map
- romap ds.w 1 ;Read-only map
- newdmap ds.w 1 ;Map bit from "mapdrv"
-
- *
- * Serial port read request
- *
- ds.l 0
- readreq ;struct IOExtSer
- ;struct IOStdReq
- ;struct Message
- ds.b 14 ;struct Node
- r_ReplyPort ds.l 1 ;Pointer to MsgPort (message reply port)
- r_MLength ds.w 1 ;Message length in bytes
- ; End of struct Message
- ds.l 1 ;Pointer to device node
- ds.l 1 ;Pointer to Unit (driver private)
- r_Command ds.w 1 ;Device command
- ds.b 1 ;io_Flags
- ds.b 1 ;Error or warning number
- ; End of struct IOReq - IOStdReq continues...
- r_Actual ds.l 1 ;Actual number of bytes transferred
- r_Length ds.l 1 ;Requested number of bytes transferred
- r_Data ds.l 1 ;Points to data area.
- r_Offset ds.l 1 ;Offset for block-structured devices
- ; End of struct IOStdReq
- r_CtlChar ds.l 1 ;control char's (order = xON,xOFF,INQ,ACK)
- r_RBufLen ds.l 1 ;length in bytes of serial port's read buffer
- r_ExtFlags ds.l 1 ;additional serial flags (see bitdefs below)
- r_Baud ds.l 1 ;baud rate requested (true baud)
- ds.l 1 ;duration of break signal in MICROseconds
- ;struct IOTArray termination character array
- r_ReadLen ds.b 1 ;bits per read character (# of bits)
- r_WriteLen ds.b 1 ;bits per write character (# of bits)
- r_StopBits ds.b 1 ;stopbits for read (# of bits)
- r_SerFlags ds.b 1 ;see SerFlags bit definitions below
- r_Status ds.w 1 ;status of serial port
- rsize equ *-readreq
-
- *
- * Serial port write request
- *
- ds.l 0
- writreq ;struct IOExtSer
- ;struct IOStdReq
- ;struct Message
- ds.b 14 ;struct Node
- w_ReplyPort ds.l 1 ;Pointer to MsgPort (message reply port)
- w_MLength ds.w 1 ;Message length in bytes
- ; End of struct Message
- ds.l 1 ;Pointer to device node
- ds.l 1 ;Pointer to Unit (driver private)
- w_Command ds.w 1 ;Device command
- ds.b 1 ;io_Flags
- ds.b 1 ;Error or warning number
- ; End of struct IOReq - IOStdReq continues...
- w_Actual ds.l 1 ;Actual number of bytes transferred
- w_Length ds.l 1 ;Requested number of bytes transferred
- w_Data ds.l 1 ;Points to data area.
- w_Offset ds.l 1 ;Offset for block-structured devices
- ; End of struct IOStdReq
- w_CtlChar ds.l 1 ;control char's (order = xON,xOFF,INQ,ACK)
- w_RBufLen ds.l 1 ;length in bytes of serial port's read buffer
- w_ExtFlags ds.l 1 ;additional serial flags (see bitdefs below)
- w_Baud ds.l 1 ;baud rate requested (true baud)
- ds.l 1 ;duration of break signal in MICROseconds
- ;struct IOTArray termination character array
- w_ReadLen ds.b 1 ;bits per read character (# of bits)
- w_WriteLen ds.b 1 ;bits per write character (# of bits)
- w_StopBits ds.b 1 ;stopbits for read (# of bits)
- w_SerFlags ds.b 1 ;see SerFlags bit definitions below
- w_Status ds.w 1 ;status of serial port, as follows:
- wsize equ *-writreq
- * BIT ACTIVE FUNCTION
- * 0 low busy
- * 1 low paper out
- * 2 low select
- * 3 low Data Set Ready
- * 4 low Clear To Send
- * 5 low Carrier Detect
- * 6 low Ready To Send
- * 7 low Data Terminal Ready
- * 8 high read overrun
- * 9 high break sent
- * 10 high break received
- * 11 high transmit x-OFFed
- * 12 high receive x-OFFed
- * 13-15 reserved
-
- *************************************************************************
- * *
- * Target processor's address space *
- * *
- *************************************************************************
-
- even
-
- registers ds.b 22 ;Actual storage for Z-80's other registers
- target ds.b $10000 ;Z-80's universe
-
- end
-