IMD 1.17: 1/01/1998 2:38:41 SLICER Programs 12-06-85 Monitor 1.3P BIOS 3.8     SLICER 86  ///DEC20 84 \\\ CODES 86DEFIN 86F RESET 86KMEMTEST 86)ENTRY 86k !"#$%&'()*+,-DISK 86p./0123456789:;INTSERV 86<=>LD 86m?@ABCDEFGHIJKLCODES1 86MNOPDEBUG 86QRSTUVWXYZ[\]^_`DEBUG 86WabcdefghijkPATCHES 86lmnopqrstuvwxyz{PATCHES 86|}PIP MD;~PAGEWIDTH 90 ;***************************************************** ; MONITOR FOR 80186 BOARD BY E. HINRICHS ; D. KLEIN ; O. BAADE ; Copyright 1983, Slicer Computer Inc. ; Last update: OCTOBER 25,1983 ;***************************************************** TITLE 'MONITOR I.3 OCTORBER 25,1983' ;LIST NOLIST EJECT INCLUDE CODES.A86 ;Some additional 80186 codes ;LIST NOLIST EJECT INCLUDE DEFIN ;Segment definitions, RAM locations ;LIST NOLIST ;Chip select initialization, memory EJECT INCLUDE RESET ; and port definitions. ;LIST NOLIST ;memory test, other low level check EJECT INCLUDE MEMTEST ; out routines ;LIST NOLIST ;Monitor entry points EJECT INCLUDE ENTRY ;LIST NOLIST ;disk related routines EJECT INCLUDE DISK ;LIST NOLIST ;Interrupt service routines EJECT INCLUDE INTSERV ;LIST NOLIST EJECT INCLUDE DEBUG ;Slicer monitor program. MONTOP: INCLUDE PATCHES ;Some fixes. ORG 8800H LOADER: CSEG 500H  ORG 0 OLDLOADER: END o the eproms. When ;making patches remember that the even and odd addresses ;must be separated. Divide the program address by two to ;get the eprom address. For example if two program lines ;to patch are ; 0B19 BF0F85 ; 0B1C 8BF7 ;then patch ; 058D 0F ; 058E 8B ;in the even eprom, and ; 058C BF ; 058D 85 ; 058E F7 ;in the odd eprom. PATCH0: ;Pat   ;********************************************************** ;*** *** ;*** NEW 80186 CODES *** ;*** *** ;********************************************************** ;Code macro definitions for 80168 instructions which are not ;on the 8086, but may be useful for this program. ; *** PUSH AND POP INSTRUCTIONS *** ; ================================= CODEMACRO PUSH IMM:DW DB 6AH DW IMM ENDM CODEMACRO PUSH IMM:DB DB 68H DW IMM ENDM CODEMACRO PUSHA DB 60H  ENDM CODEMACRO POPA DB 61H ENDM ; *** MULTIPLY *** ; ================ CODEMACRO IMUL DST:RW,SRC:EW,IMM:DW DB 69H MODRM DST,SRC DW IMM ENDM CODEMACRO IMUL DST:RW,SRC:EW,IMM:DB DB 6BH MODRM DST,SRC DB IMM ENDM ; *** SHIFT BY COUNT INSTRUCTIONS *** ; =================================== CODEMACRO ROL DST:EB,COUNT:DB DB 0C0H MODRM 0,DST DB COUNT ENDM CODEMACRO ROR DST:EB,COUNT:DB DB 0C0H MODRM 1,DST DB COUNT ENDM CODEMACRO RCL DST:EB,COUNT:DB DB 0C0H MODRM 2,DST DB COUNT ENDM CODEMACRO RCR DST:EB,COUNT:DB DB 0C0H MODRM 3,DST DB COUNT ENDM CODEMACRO SLL DST:EB,COUNT:DB DB 0C0H MODRM 4,DST DB COUNT ENDM ;Assembler uses SHR and SHL as operators, and so does ;not allow them as code macro instructions. Use SLR ;and SLL (Shift Logical Right or Left) CODEMACRO SLR DST:EB,COUNT:DB DB 0C0H MODRM 5,DST DB COUNT ENDM CODEMACRO SAL DST:EB,COUNT:DB DB 0C0H MODRM 4,DST DB COUNT ENDM CODEMACRO SAR DST:EB,COUNT:DB DB 0C0H MODRM 7,DST DB COUNT ENDM CODEMACRO ROL DST:EW,COUNT:DB DB 0C1H MODRM 0,DST DB COUNT ENDM CODEMACRO ROR DST:EW,COUNT:DB DB 0C1H MODRM 1,DST DB COUNT ENDM CODEMACRO RCL DST:EW,COUNT:DB DB 0C1H MODRM 2,DST DB COUNT ENDM CODEMACRO RCR DST:EW,COUNT:DB DB 0C1H MODRM 3,DST DB COUNT ENDM CODEMACRO SLL DST:EW,COUNT:DB DB 0C1H MODRM 4,DST DB COUNT ENDM CODEMACRO SLR DST:EW,COUNT:DB DB 0C1H MODRM 5,DST DB COUNT ENDM CODEMACRO SAL DST:EW,COUNT:DB DB 0C1H MODRM 4,DST DB COUNT ENDM CODEMACRO SAR DST:EW,COUNT:DB DB 0C1H MODRM 7,DST DB COUNT ENDM y two to ;get the eprom address. For example if two program lines ;to patch are ; 0B19 BF0F85 ; 0B1C 8BF7 ;then patch ; 058D 0F ; 058E 8B ;in the even eprom, and ; 058C BF ; 058D 85 ; 058E F7 ;in the odd eprom. PATCH0: ;Pat;********************************************************** ;*** *** ;*** MEMORY DEFINITIONS *** ;*** *** ;********************************************************** EPROM EQU 32 ;Type of EPROM used. ROMSEG EQU 0F800H INTVEC EQU -ROMSEG*10H ;Absolute adr=0 MONRAM EQU INTVEC+400H ;Above interrupt vectors EJECT ;********************************************************** ;*** *** ;*** INTERRUPT VECTORS *** ;*** *** ;********************************************************** DSEG ROMSEG ORG INTVEC VDIV RW 2 ;0 VSS RW 2 ;1 VNMI RW 2 ;2 VBRK RW 2 ;3 VOVFL RW 2 ;4 VBOUND RW 2 ;5 VBADOP RW 2 ;6 VESC RW 2 ;7 VTMR0 RW 2 ;8 RW 2 ;9 VDMA0 RW 2 ;10 VDMA1 RW 2 ;11 VINT0 RW 2 ;12 VINT1 RW 2 ;13 VINT2 RW 2 ;14 VINT3 RW 2 ;15 RW 2 ;16 RW 2 ;17 VTMR1 RW 2 ;18 VTMR2 RW 2 ;19 ORG INTVEC+4*58 VSECOND RW 2 ;58 VENTRY RW 2 ;59 VSPOOL RW 2 ;60 VLST RW 2 ;61 VRESET RW 4 ;62,63 EJECT ;**********************  ************************************ ;*** *** ;*** RAM DEFINITIONS *** ;*** *** ;********************************************************** ; *** MONITOR VARIABLES *** ; ========================= ORG MONRAM JTBIOS RB 160 ;Jump table space DISKTABLE RW 32 ;Logical to physical disk table USR0 RW 2 ;User disk routine, DMA0 USR1 RW 2 ;User disk routine, DMA1 COUNT RB 1 ;Count between seconds NXTSEC RB 1 ;Count when next second starts SECONDS RW 1 ;Timer locations ORG OFFSET $ -2 SECLOW RB 1 ;For byte intervals SECHIGH RB 1 RW 1 MEMSIZE RW 1 ;RAM memory installed, in Ks. DUOUT RB 1 ;Image of output port. DUIMR RB 1 ;DUART interrupt mask register. DSKCMD RB 1 ;Disk command (0=read, 1=write) DSKSEG RW 1 ;Disk memory segment DSKMEM RW 1 ;Disk memory offset. DSKNUM RB 1 ;Disk number for disk operations. DSKTRACK RW 1 ;Disk track DSKSECTOR RB 1 ;Disk sector SECCNT RB 1 ;Sector count and sectors/track TRKSIZE RB 1 ;for multiple sector transfers FDSTOP RB 1 ;Floppy shut off time. DSKPTR RW 1 ;Table entry for last disk WINTASK RB 6 ;Winchester command WINDATA RB 8 ;Info for winchester init DESELECT RB 1 ;Time to desect floppies FDTIME RB 1 ;Delay before floppy shut off DSTIME RB 1 ;Delay before floppy deselect. FDELAY RB 1 ;Delay before giving up on disk CRTTYPE RB 1 ;CRT type byte CRTXOR1 RB 1 ;CRT conversion parameters CRTADD1 RB 1 CRTXOR2 RB 1 CRTADD2 RB 1 CRTLED RB 7 ;CRT cursor positioning lead in CRTMID RB 7 ;middle CRTEND RB 7 ;end CRTCLR RB 8 ;CRT clear screen sequence RS 280 STACK RS 0 ;Stack area LINBUF RB 50H ;Line input buffer. IF OFFSET $ AND 1 RS 1 ;Move to even address. ENDIF CONPUT RW 1 ;Pointer to put next console byte CONGET RW 1 ;Pointer to get next console byte CONBUF RS 80H ;Buffered console input area CONTOP RS 0 ;Top of console input buffer LSTPTR RW 1 ;Pointer for list spooling. LSTSEG RW 1 ;Segment for printer spooling. LSTEND RW 1 ;Last byte for printer. XROUT RW 1 ;Routine called externally XSEG RW 1 ;External segment XPTR RW 1 ;External pointer SELBUF RS 6 ;Used by floppy select routine. BITS RB 1 ;Flag bits. ; *** BIT FLAGS *** ; ----------------- INLINE EQU 1 ;Abort flag. WINON EQU 2 ;Winchester started. FDRDY EQU 4 ;Floppy ready ; *** DISK TABLES *** ; =================== BLK0 RB 9 TYP0 RB 12 BLK1 RB 9 TYP1 RB 12 BLK2 RB 9 TYP2 RB 12 BLK3 RB 9 TYP3 RB 12 BLK4 RB 9 TYP4 RB 12 ; *** MONITOR VARIABLES *** ; ========================== SEG1 RW 1 ;Memory pointers MEM1 RW 1 SEG2 RW 1 MEM2 RW 1 MEM3 RW 1 PORT1 RW 1 ;IO ports PORT2 RW 1 BYTE1 RB 1 ;Byte values BYTE2 RB 1 WORD1 RW 1 ;Word values WORD2 RW 1 SEC1 RW 1 ;Disk parameters EJECT ; *** REGISTER SAVE AREA *** ; ========================== AXSAVE RW 1  BXSAVE RW 1 CXSAVE RW 1 DXSAVE RW 1 BPSAVE RW 1 SISAVE RW 1 DISAVE RW 1 SPSAVE RW 1 CSSAVE RW 1 DSSAVE RW 1 SSSAVE RW 1 ESSAVE RW 1 IPSAVE RW 1 FSAVE RW 1 ; BREAK POINTS ; ------------ BREAK1 RW 3 BREAK2 RW 3 MONSP RW 1 ;STACK POINTER SAVE EJECT ; *** CONSTANTS *** ; ================= ; DISK TYPE TABLE ; --------------- ORG 0 DTYPE RB 1 STEPRATE RB 1 SECLEN RW 1 DATAADR RW 2 RDCMD RW 1 WRTCMD RW 1 ;masks for dtype MINI EQU 1 DOUBLE EQU 2  HALFTRK EQU 4 FLOPPY EQU 8 HARD EQU 10H DMACH1 EQU 20H ; DISK BLOCK ; ---------- ORG 0 DISK RB 1 SIDE RB 1 TRACK RW 1 SECTOR RB 1 LSTTRK RW 1 TYPEPTR RW 1 ; BOOT TABLE ; ---------- ORG 0 BLOAD RW 2 ;Load address. BJUMP RW 2 ;Start execution. BLOADSIZE RW 1 ;Number of sectors. BSECSIZE RW 1 ;Bytes per sector. BTRKSIZE RB 1 ;Sectors per track. ; ASCII CONTROL CODES ; ------------------- CR EQU 13 LF EQU 10 TAB EQU 9 BS EQU 8 CNTL EQU   -40H ; AN OPCODE ; --------- BRKCODE EQU 0CCH ; OTHER CONSTANTS ; --------------- CPS EQU 50 ;Counts per seconds EJECT ;********************************************************** ;*** *** ;*** I/O PORT DEFINITIONS *** ;*** *** ;********************************************************** ; *** EXTERNAL IO *** ; ==================== ; FLOPPY DISK CONTROLLER ; ---------------------- BASE EQU 0 ;set up base as defined in pacs FDCSTAT EQU BASE ;fdc status register FDCCMD EQU BASE ;fdc command register FDCTRK EQU BASE+2 ;fdc track register FDCSEC EQU BASE+4 ;fdc sector register FDCDAT EQU BASE+6 ;fdc data register ; SERIAL I/O ; ---------- ;PORTS DUART EQU BASE+128 ;DUART registers. ;read registers ;-------------- ;Mode register, port A DUART ;Status register, port A DUART+2 ;RX holding register, port A DUART+6 ;Input port change register DUART+8 ;Interrupt status register DUART+10 ;Counter/Timer upper  DUART+12 ;Counter/Timer lower DUART+14 ;Mode register, port B DUART+16 ;Status register, port B DUART+18 ;RX holding register, port B DUART+22 ;Input port DUART+26 ;Start counter command DUART+28 ;Stop counter command DUART+30 ;write registers ;--------------- ;Mode register, port A DUART ;Clock select, port A DUART+2 ;Command register, port A DUART+4 ;TX holding register, port A DUART+6 ;Aux. control register DUART+8 ;Interrupt mask register DUART+10 ;Counter/Timer upper DUART+12 ;Counter/Timer lower DUART+14 ;Mode register, port B DUART+16 ;Clock select, port B DUART+18 ;Command register, port B DUART+20 ;TX holding register, port B DUART+22 ;Output port conf. reg. DUART+26 ;Set output port bits command DUART+28 ;Reset output port bits command DUART+30 SASTAT EQU DUART+2 SADATA EQU DUART+6 DUARTB EQU DUART+16 SBSTAT EQU SASTAT+16 SBDATA EQU SADATA+16 ;MASKS RXRDY EQU 1 TXRDY EQU 4 FDMOTOR EQU 80H ;Input jumpers JUMP96 EQU 40H EJECT ; OTHER ; ----- SYSPORT EQU BASE+256 ;system control port (pcs2) ;SYSPORT outputs are mapped to eight different addresses. ;Output to a SYSPORT bit with D0=1 sets output high, D0=1, ;sets output low. ;Bit addresses ;SASI /SEL SYSPORT ;SASI /RST SYSPORT+2 ;FLOPPY DS3 SYSPORT+4 ;FLOPPY DS2 SYSPORT+6 ;FLOPPY DS1 SYSPORT+8 ;FLOPPY DS0 SYSPORT+10 ;FLOPPY MINI SYSPORT+12 ;FLOPPY /DDENS SYSPORT+14 SEL EQU 0 RST EQU 2  ; SASI PORT ; --------- SASI EQU BASE+184H ;sasi port (pcs3) ACK EQU -4 ;SASI I/O with ack. WINBUSY EQU 800H ;busy mask CONTROL EQU 2000H ;control mask REQ EQU 4000H ;request mask WINERR EQU 2 ;error mask EJECT ; *** INTERNAL I/O *** ; ==================== IPC EQU -100H ;Integrated peripherials control base ; DMA ; --- DMA0 EQU 0C0H DMA1 EQU 0D0H DMACTL EQU 10 DMATC EQU 8 DMADST EQU 4 DMASRC EQU 0 DMASTRT EQU 2 ;DMA start bit DMACHG EQU 4 ;DMA change bit ; CHIP SELECTS ; ------------ UMCS EQU 0A0H LMCS EQU 0A2H PACS EQU 0A4H MMCS EQU 0A6H MPCS EQU 0A8H ;Timer Addresses ;--------------- TIMER0 EQU 50H TIMER1 EQU 58H TIMER2 EQU 60H ;Timer Registers TIMCNT EQU 0 ;count register TIMCNA EQU 2 ;max count A TIMCNB EQU 4 ;max count B TIMCMD EQU 6 ;control/mode register ;Interrupt control registers ;--------------------------- INT3 EQU 3EH INT2 EQU 3CH INT1 EQU 3AH INT0 EQU 38H DMA1INT EQU 36H DMA0INT EQU 34H TMRINT EQU 32H INTSTAT EQU 30H INTREQ EQU 2EH INTSERVR EQU 2CH INTPRIOR EQU 2AH INTMASK EQU 28H INTPOLS EQU 26H INTPOLL EQU 24H EOI EQU 22H y two to ;get the eprom address. For example if two program lines ;to patch are ; 0B19 BF0F85 ; 0B1C 8BF7 ;then patch ; 058D 0F ; 058E 8B ;in the even eprom, and ; 058C BF ; 058D 85 ; 058E F7 ;in the odd eprom. PATCH0: ;Pat  CSEG ROMSEG ;********************************************************** ;*** *** ;*** RESET *** ;*** *** ;********************************************************** ;Reset code is at segment 0FFFFH. Compute location in ROM. ;Note that not all address lines are decoded. ;So for 2732s F800,FA00,FC00,FE00 are all the same. ORG EPROM*100H-10H MOV DX,IPC+UMCS ;Set UMCS MOV AX,ROMSEG+38H ;at ROMSEG with no waits OUT DX,AX ;and rdy JMPF INIT ;Set CS to ROMSEG ROMRET: RET ROMIRET: IRET DB 3 ;Version #. EJECT FALSE EQU 0 TRUE EQU NOT FALSE ;********************************************************** ;*** *** ;*** CHIP SELECT INITIALIZATION *** ;*** *** ;********************************************************** ORG 0 INIT: ; *** LOW MEMORY *** ; =================== LRDY EQU TRUE LWAITS EQU 0 LSIZE EQU 256 ;in Ks, power of 2, 1-256 MOV AX,40H*(LSIZE-1)+38H+4*(LRDY+1)+LWAITS MOV DX,IPC+LMCS OUT DX,AX ;  *** MID RANGE MEMORY *** ; ======================== MRDY EQU TRUE MWAITS EQU 1 MSIZE EQU 32 ;in Ks, power of 2, 2-128 MBASE EQU 768 ;must be a multple of 4*SIZE MOV AX,40H*MBASE+1F8H+4*(MRDY+1)+MWAITS MOV DX,IPC+MMCS OUT DX,AX ; *** PERIPHERIALS *** ; ==================== P0RDY EQU TRUE ;for PCS0-3 P0WAITS EQU 3 PBASE EQU 0 ;in Ks IO EQU TRUE A1A2 EQU FALSE MOV AX,40H*PBASE+38H+4*(P0RDY+1)+P0WAITS MOV DX,IPC+PACS OUT DX,AX P4RDY EQU TRUE ;for PCS4-6 P4WAITS EQU 3 MOV AX,80H*(MSIZE+A1A2+1)+40H*(IO+1)+38H+4*(P4RDY+1)+P4WAITS+8000H MOV DX,IPC+MPCS OUT DX,AX EJECT ;********************************************************** ;*** *** ;*** PERIPHERIAL AND MEMORY INITS *** ;*** *** ;********************************************************** ; SEGMENTS AND STACK ; ------------------ MOV AX,CS MOV DS,AX MOV ES,AX MOV SS,AX MOV SP,OFFSET STACK ;SASI reset. MOV DX,SYSPORT+SEL MOV AL,1 OUT DX,AL MOV DX,SYSPORT+RST OUT DX,AL ;Reset floppy disk controller MOV AL,0D0H ;Forced interrupt OUT FDCCMD,AL ;Set DUART command registers. MOV AL,00010101B ;Tx enable ; Rx enable OUT DUART+4,AL OUT DUARTB+4,AL ;Set DUART interrupt mask register. MOV AL,00000010B ;Interrupt on RXRDY OUT DUART+10,AL ;Initialize DUART outputs. MOV AL,-1 OUT DUART+28,AL MOV AL,0 OUT DUART+30,AL ; VALID MEMORY? ; ------------- ;Check if memory has been initialized.  MOV AX,VRESET+4 CMP AX,MEMSIZE ;MEMSIZE match? JNZ BAUD ADD AX,VRESET+2 ADD AX,VRESET ;Add up some memory XOR AX,0D0BEH SUB AX,VRESET+6 ;Strange checksum JNZ BAUD JMP RES2 EJECT ; *** COLD START *** ; ================== ; GET BAUD RATE ; ------------- BAUD: MOV AL,10010011B ;8 bits ; no parity ; Rx controls RTS OUT DUART,AL OUT DUARTB,AL MOV AL,00011111B ;CTS controls XMTR ; 2 stops OUT DUART,AL OUT DUARTB,AL MOV AL,0BBH ;9600 BAUD  OUT DUARTB+2,AL IN AL,DUART+26 ;Jumper decides whether TEST AL,JUMP96 ;baud rate is set by JNZ GETBAUD ;CR typed at console MOV AL,0BBH ;or just set to 9600 OUT DUART+2,AL JMP COLD GETBAUD: MOV CX,3 ;Retries BAUD0: JCXZ ECHO DEC CX ;Try again MOV BX,-1 BAUD1: INC BX ;Count breaks MOV AX,0CC00H ;38.4K MOV DI,OFFSET BAUD2 ;Set baud JMP BAUD6 ;and get char BAUD2: OR AL,AL ;Break? JZ BAUD1 ;Get another char CMP AL,CR ;If CR then 38.4K baud JZ BAUD9 ;is correct CMP BL,0 ;First char? JZ BAUD3 MOV AL,BL ;If not use break count. BAUD3: MOV BX,OFFSET BAUDTABLE BAUD4: MOV DX,[BX] ;Search table CMP DH,0 ;Error? JZ BAUD0 CMP DL,0 ;End of table? JZ BAUD5 ;Use default baud ADD BX,2 CMP AL,DL ;Test. JNZ BAUD4 BAUD5: MOV AH,DH ;Have it. Set baud MOV DI,OFFSET BAUD9 MOV AL,80H BAUD6: MOV BP,AX OUT DUART+8,AL MOV AL,00100001B ;Reset OUT DUART+4,AL MOV AL,AH ;Set baud OUT DUART+2,AL MOV AL,00010101B ;Tx enable ; Rx enable   OUT DUART+4,AL BAUD7: IN AL,SASTAT ;Get a char. TEST AL,RXRDY JZ BAUD7 IN AL,SADATA JMP DI ;RAMless return BAUD9: JMP COLD ;Couldn't determine baud rate. Set baud to 1200 and go ;into continuous echo mode. ECHO: MOV AL,66H OUT DUART+2,AL ECHO0: MOV AL,AH OUT SADATA,AL ECHO1: IN AL,SASTAT TEST AL,TXRDY JNZ ECHO0 TEST AL,RXRDY JZ ECHO1 IN AL,SADATA MOV AH,AL JMPS ECHO1 BAUDTABLE: DB 0E6H,0CCH ;19.2K DB 78H,0BBH ;9600 DB 80H,99H ;4800 DB 1,88H ;2400 DB 3,66H ;1200 DB 6,55H,7,55H ;600 DB 12,44H,13,44H,14,44H ;300 DB 0,0 ;Put default baud here. EJECT ; MEMORY TEST ; ----------- COLD: CLD MOV DI,OFFSET COLD3 MOV SI,OFFSET SIGNON JMP TXTOUT SIGNON DB CNTL+'L',CR,LF,' the SLICER',CR,LF,LF,80H COLD3: MOV AX,0 COLD0: MOV ES,AX ;Destination in low ram. MOV DI,0 MOV SI,DI MOV CX,OFFSET MONTOP/2 REP MOVSW ;Copy MOV DI,0 MOV SI,DI MOV CX,OFFSET MONTOP/2 REPZ CMPSW JNZ COLD1 ;If NZ then found end of ram. MOV AX,ES ;Else set ram segment to ADD AX,(OFFSET MONTOP)/16 ;next block. JMPS COLD0 COLD1: MOV AX,SI ;Found end of ram. SLR AX,4 MOV BX,ES ;Compute ram size. ADD AX,BX SLR AX,6 CMP AX,128 JNC COLD2 JMP MEMTEST ;If no ram goto memory test COLD2: MOV DX,AX MOV AX,DS MOV ES,AX MOV AX,0 ;Zero monitor RAM MOV DI,MONRAM MOV CX,200H REP STOSW MOV MEMSIZE,DX ;Set bomb vectors. MOV SI,OFFSET VDIV ;Set all interrupt vectors MOV DI,OFFSET VSS ;to "bomb" routine MOV AX,OFFSET BOMB MOV [SI],AX MOV 2[SI],CS MOV CX,1FEH REP MOVSW ;Initalize debugger ram variables. MOV DSKSECTOR,1 MOV AX,80H ;Initialize segments to above. MOV SEG1,AX ;monitor ram. MOV SEG2,AX MOV DSSAVE,AX MOV CSSAVE,AX MOV ESSAVE,AX MOV SSSAVE,AX MOV BREAK1+4,AX MOV BREAK2+4,AX MOV DSKSEG,AX ;Initialize ram jump table MOV DI,OFFSET JTBIOS ;Move bios jump table MOV SI,OFFSET JTROM ;to RAM MOV CX,JTLEN REP MOVSB ;Initialize disk table. MOV CX,16 MOV SI,OFFSET DTROM MOV DI,OFFSET DISKTABLE REP MOVSW MOV DL,4 ;4 disks MOV BX,OFFSET BLK0 MOV DI,OFFSET TYP0 RES4: MOV AL,4 SUB AL,DL MOV DISK[BX],AL ;disk number MOV WORD PTR LSTTRK[BX],-1 ;not calibrated MOV WORD PTR TYPEPTR[BX],DI MOV SI,OFFSET ROMTYP ;initially 8SD MOV CX,12 ;but can be changed REP MOVSB ;by 'D?' ADD BX,21 ADD DI,9 DEC DL JNZ RES4 MOV BYTE PTR DISK[BX],0 MOV WORD PTR LSTTRK[BX],-1 MOV WORD PTR TYPEPTR[BX],DI MOV SI,OFFSET WINTYPE MOV CX,12 REP MOVSB MOV WINTASK+4,1 ;Block count. MOV AX,OFFSET ROMRET ;Set user disks to return MOV CX,4 MOV DI,OFFSET USR0 REP STOSW MOV SI,OFFSET WINROM MOV DI,OFFSET WINDATA MOV CX,8 REP MOVSB ;Set time out values MOV FDTIME,120 MOV DSTIME,0 MOV FDELAY,64 ;Set default CRT parameters. MOV DI,OFFSET CRTTYPE MOV SI,OFFSET ROMCRT MOV CX,OFFSET RES3-OFFSET ROMCRT REP MOVSB JMPS RES3 ROMCRT: DB 0,0,20H,0,20H ;Type & offset DB 2,1BH,'=',0,0,0,0 ;lead in sequence DB 0,0,0,0,0,0,0 ;middle sequence DB 0,0,0,0,0,0,0 ;end sequence DB 1,'L'-40H,0,0,0,0,0,0 ;clear screen ;Set reset vector. RES3: MOV AX,OFFSET AUTOBOOT MOV DX,CS CALL SETRESET MOV TRKSIZE,26 ;Single density, 8" ; WARM START ; ---------- RES2: ;Deactivate reset vector ;If reset is pressed twice then a cold start is done. MOV VRESET+4,0 ;Initialize monitor stack. MOV MONSP,SP ;Store DUART state. MOV DUIMR,2 MOV DUOUT,0 ;Set console input interrupts. MOV AX,OFFSET CONBUF ;Set buffered console MOV CONGET,AX ;input pointers MOV CONPUT,AX MOV DX,IPC+INT0 MOV AX,17H ;enable ; level triggered ; priority 7 OUT DX,AX MOV VINT0,OFFSET STARTINT MOV VINT0+2,CS ;Set floppy disk interrupts. MOV DX,IPC+INT1 MOV AX,7 ;enable, edge triggered ; low priority OUT DX,AX MOV VINT1,OFFSET FDINT MOV VINT1+2,CS ;Set monitor entry point interrupt. MOV VENTRY,OFFSET MONENT MOV VE  NTRY+2,CS ;Interrupts for printer spooling. MOV VLST,OFFSET LSTINT MOV VLST+2,CS MOV VSPOOL,OFFSET ROMIRET MOV VSPOOL+2,CS ;Timer inits. MOV VSECOND,OFFSET SECOND MOV VSECOND+2,CS MOV VTMR2,OFFSET TIME ;Vector. MOV VTMR2+2,CS MOV DX,IPC+TIMER2+TIMCNA MOV AX,40000 ;Counts/msec, MOV DX,IPC+TIMER2+TIMCMD MOV AX,0E001H ;Enabled ;Generate interrupts ;Continuous OUT DX,AX MOV DX,IPC+TMRINT ;Enable ;Low priority MOV AX,7 OUT DX,AX ;Timer memory locations. MOV NXTSEC,CPS INT 62 ;Auto boot. ;Interrupt 62 points here on cold start. AUTOBOOT: MOV AX,OFFSET MONINIT ;Point reset vector PUSH AX ;and return to monitor. MOV DX,CS CALL SETRESET STI MOV AL,0 ;Then boot. JMP COLDBOOT ;Initial disk table. DTROM: DW OFFSET BLK0,OFFSET ROMRET DW OFFSET BLK1,OFFSET ROMRET DW OFFSET BLK2,OFFSET ROMRET DW OFFSET BLK3,OFFSET ROMRET DW OFFSET BLK4,OFFSET ROMRET DW 0,OFFSET ROMRET DW 0,OFFSET ROMRET DW 0,OFFSET ROMRET DW 0,OFFSET ROMRET DW 0,OFFSET ROMRET DW 0,OFFSET ROMRET DW 0,OFFSET ROMRET DW 0,OFFSET ROMRET DW 0,OFFSET ROMRET DW 0,OFFSET ROMRET DW 0,OFFSET ROMRET ROMTYP: DB 8,0BH DW 80H,6,0,0A240H,1680H WINTYPE: DB DMACH1+HARD,0 DW 512,SASI+ACK,0,0A240H,1680H  ; 058D 0F ; 058E 8B ;in the even eprom, and ; 058C BF ; 058D 85 ; 058E F7 ;in the odd eprom. PATCH0: ;Pat ;External Peripherals ;-------------------- ;Serial Communications port TXBIT EQU 4 RXBIT EQU 1 MEMTEST: CLI MOV AX,0 MOV DS,AX MOV SS,AX JMP SIGNON1 EJECT ;Text Output to Console ; pointed to by si, text terminated by 80h or control character TXTOUT: IN AL,SASTAT AND AL,TXBIT JZ TXTOUT ;not ready? MOV AL,CS: [SI] ;get character OUT SADATA,AL ;print it AND AL,80H ;test it JZ TXTOT1 ;not the last? JMP DI ;all done, return TXTOT1: INC SI ;point to next character JMPS TXTOUT ;Input from Console ; character returned in al converted to upper case CHRIN: IN AL,SASTAT AND AL,RXBIT JZ CHRIN ;not ready? IN AL,SADATA AND AL,7FH CMP AL,'A' JB CHRNXT CMP AL,'z' JA CHRNXT AND AL,5FH ;convert to upper case CHRNXT: JMP DI ;return with character EJECT ;Enter Data into BP WRD: MOV AH,0 MOV BP,0 MOV DI,OFFSET WRD2 WRD1: JMP CHRIN WRD2: MOV CH,AL CMP AL,0DH JNE WRD3 ;not done? JMP SP ;return WRD3: SUB AL,'0' JS WRD1 ;not hex? CMP AL,10 JB WRD4 ;10>entry? CMP AL,'A'-'0' JB WRD1 ;not hex? SUB AL,'A'-10-'0' CMP AL,0FH JA WRD1 ;not hex? WRD4: MOV CL,4 SHL BP,CL OR BP,AX WRD5: IN AL,SASTAT AND AL,TXBIT JZ WRD5 MOV AL,CH OUT SADATA,AL JMP WRD1 EJECT ;Print Word in SI PWRD: MOV CH,4 ;print 4 nibbles PWRD1: IN AL,SASTAT AND AL,TXBIT JZ PWRD1 ;port not ready? MOV CL,4 ROL SI,CL ;get the right nibble MOV AX,SI AND AL,0FH ADD AL,'0' CMP AL,'9' JBE PWRD2 ;ascii ok?  ADD AL,7 PWRD2: OUT SADATA,AL DEC CH JNZ PWRD1 ;more to do? ;now print a space PWRD3: IN AL,SASTAT AND AL,TXBIT JZ PWRD3 MOV AL,' ' OUT SADATA,AL JMP DI EJECT SIGNON1: MOV SI,OFFSET MESG1 PROMPT: MOV DI,OFFSET CMNDS JMP TXTOUT MESG1 DB 0CH,0AH,0DH DB ' SLICER memory test',0ah,0ah,0dh DB ' Ddddd enter data dddd',0dh,0ah DB ' Aaaaa enter address aaaa',0ah,0dh DB ' Sssss set segment register to ssss',0dh,0ah DB ' R read from location   ssss:aaaa',0dh,0ah DB ' W Write dddd to location ssss:aaaa',0dh,0ah DB ' T test memory segment ssss',0dh,0ah DB ' E exit to main monitor',0ah,0dh MESG2 DB 0DH,0AH,'>'+80h PROMPT1: JMP PROMPT CMNDS: MOV DI,OFFSET CMDTST JMP CHRIN CMDTST: MOV AH,AL CMND0: IN AL,SASTAT AND AL,TXBIT JZ CMND0 MOV AL,AH OUT SADATA,AL ;echo character back to terminal CMP AL,'A' ;command option ? JZ GETADR CMP AL,'D' JZ GETDAT CMP AL,'E' JNZ NOTEE JMP INIT NOTEE: CMP AL,'R' JZ DRAMRD CMP AL,'S' JZ DTSEG CMP AL,'T' JZ DRAMTST CMP AL,'W' JMPS DRAMWR CMND1: MOV SI,OFFSET MESG2 JMPS PROMPT1 EJECT ;D RAM write cycle DRAMWR: MOV AX,DX MOV [BX],AX IN AL,SASTAT AND AL,RXBIT JZ DRAMWR JMPS CMND1 ;D RAM read cycle DRAMRD: MOV AX,DX MOV [BX],AX RDCYCL: MOV AX,[BX] IN AL,SASTAT AND AL,RXBIT JZ RDCYCL JMPS CMND1 ;Get Address into bx GETADR: MOV SP,OFFSET ADR1 JMP WRD ADR1: MOV BX,BP JMPS CMND1 ;GET Data into dx GETDAT: MOV SP,OFFSET DAT1 JMP WRD DAT1: MOV DX,BP JMPS CMND1 ;Set data segment register DTSEG: MOV SP,OFFSET DTSEG1 JMP WRD DTSEG1: MOV DS,BP JMPS CMND1 EJECT ;D RAM test DRAMTST: MOV CX,SS XOR CX,-1 MOV SS,CX MOV BX,0 MOV BP,BX MTST1: MOV AX,CS:[BX] XOR AX,CX MOV DS:[BP],AX ;move data to ram CMP BX,0FFFEH AND OFFSET MONTOP JNE MTST2 ;not at end of test pattern? MOV BX,-2 ;restart test pattern MTST2: INC BX INC BX INC BP INC BP JNZ MTST1 ;ram not full?  MTST6: MOV BX,BP MTST3: MOV AX,DS:[BP] XOR AX,CX CMP AX,CS:[BX] JNZ MERROR MTST4: CMP BX,0FFFEH AND OFFSET MONTOP JNE MTST5 ;not at end of test pattern? MOV BX,-2 ;restart test pattern MTST5: INC BX INC BX INC BP INC BP JNZ MTST3 ;not all tested? MTST9: IN AL,SASTAT TEST AL,TXRDY JZ MTST9 MOV AL,'.' OUT SADATA,AL IN AL,SASTAT AND AL,RXBIT JZ MTSTA IN AL,SADATA CMP AL,0DH JNZ MTST8 JMP CMND1 MTST8: CMP AL,'S'-40H JNZ MTSTA ;Continue testing?  ;no, suspend test until console sends a ^S MTST7: IN AL,SASTAT AND AL,RXBIT JZ MTST7 IN AL,SADATA CMP AL,'S'-40H JNZ MTST7 ;no ^S? MTSTA: IN AL,DUART+26 ;read sense inputs on duart TEST AL,JUMP96 JZ MTST6 ;write once, then read only? JMPS DRAMTST ;write each cycle EJECT ;Show D Ram Error MERROR: XOR AX,CX MOV DX,AX ;save ref data MERR1: IN AL,SASTAT AND AL,TXBIT JZ MERR1 MOV AL,0DH ;carriage return OUT SADATA,AL MERR2: IN AL,SASTAT AND AL,TXBIT JZ MERR2  MOV AL,0AH ;line feed OUT SADATA,AL MERR3: MOV DI,OFFSET MERR4 MOV SI,BP ;ram address JMP PWRD MERR4: MOV DI,OFFSET MERR5 MOV SI,DX ;bad data JMP PWRD MERR5: MOV AX,CS:[BX] MOV CX,SS XOR AX,CX MOV SI,AX ;bad data MOV DI,OFFSET MERR6 JMP PWRD MERR6: MOV CX,SS IN AL,SASTAT AND AL,RXBIT JNZ MERRA JMP MTST4 ;continue MERRA: IN AL,SADATA CMP AL,0DH JNZ MERR7 JMP CMND1 MERR7: MOV DI,OFFSET MERR8 JMP CHRIN MERR8: MOV CX,SS CMP AL,0DH JNZ MERR9 JMP CMND1 MERR9: JMP MTST4  DW 0,OFFSET ROMRET DW 0,OFFSET ROMRET ROMTYP: DB 8,0BH DW 80H,6,0,0A240H,1680H WINTYPE: DB DMACH1+HARD,0 DW 512,SASI+ACK,0,0A240H,1680H  ; 058D 0F ; 058E 8B ;in the even eprom, and ; 058C BF ; 058D 85 ; 058E F7 ;in the odd eprom. PATCH0: ;Pat   ;********************************************************** ;*** *** ;*** MONITOR ENTRY POINTS *** ;*** *** ;********************************************************** ; Start of jump table for long jumps into BIOS ;This table is moved to RAM at F800:8400. This will ;be removed in later versions. JTROM: CALL START-JTOFF ;F800:8400 RETF CALL CONST-JTOFF ;F800:8404 RETF CALL CONIN-JTOFF ;F800:8408 RETF CALL CONOUT-JTOFF ;F800:840C RETF CALL DUBIN-JTOFF ;F800:8410 RETF CALL DUBOUT-JTOFF ;F800:8414 RETF CALL LSTSPOOL-JTOFF ;F800:8418 RETF CALL XHOME-JTOFF ;F800:841C RETF CALL XREAD-JTOFF ;F800:8420 RETF CALL XWRITE-JTOFF ;F800:8424 RETF CALL DUON-JTOFF ;F800:8428 RETF CALL DUOFF-JTOFF ;F800:842C RETF CALL DUHIGH-JTOFF ;F800:8430 RETF CALL DULOW-JTOFF ;F800:8434 RETF CALL DUBOUT-JTOFF ;F800:8438 RETF ;Table for routines for interrupt entry. VECTAB: DW OFFSET SETENT ;0 set entry point DW OFFSET CONST ;1 console status DW OFFSET CONIN ;2 console input DW OFFSET CONOUT ;3 console output DW OFFSET DUBIN ;4 port B input DW OFFSET DUBOUT ;5 port B output DW OFFSET LSTSPOOL ;6 print spooling DW OFFSET XHOME ;7 home disk drive DW OFFSET XREAD ;8 read a sector DW OFFSET XWRITE ;9 write a sector DW OFFSET DUON ;10 turn on interrupt DW OFFSET DUOFF ;11 turn off interrupt DW OFFSET DUHIGH ;12 set output high DW OFFSET DULOW ;13 set output low DW OFFSET DUBOUT ;14 printer output DW OFFSET LSTST ;15 printer status DW OFFSET XSETRESET ;16 set reset vector DW OFFSET XDSKCHECK ;17 check disk type DW OFFSET STOPSPOOL ;18 shut off spooling DW OFFSET DOLMESS ;19 console message ($) DW OFFSET XMESSAGE ;20 console message (NUL) DW OFFSET HEXWORD ;21 16 bit hex output DW OFFSET HEXBYTE ;22 8 bit hex output DW OFFSET DECDISP ;23 decimal output DW OFFSET CLRSCR ;24 clear screen DW OFFSET CRTSET ;25 cursor position DW OFFSET ROMRET ;26-36, fill in later DW OFFSET ROMRET DW OFFSET ROMRET DW OFFSET ROMRET DW OFFSET ROMRET DW OFFSET ROMRET DW OFFSET ROMRET DW OFFSET ROMRET DW OFFSET ROMRET DW OFFSET ROMRET DW OFFSET ROMRET JTLEN EQU OFFSET $ - OFFSET JTROM JTOFF EQU OFFSET JTBIOS-OFFSET JTROM ;Monitor entry point. ;Routine number in BL. ;No checking is made on the range of BL, ; values out of range will send the ; CPU into nowhere land. MONENT: MOV BH,0 ;compute table offset SHL BX,1 PUSH CS:VECTAB[BX] ;locate routine entry. MOV BX,SP ;restore flags (INT op PUSH SS:WORD PTR 6[BX] ;changes I flag). POPF POP BX ;call desired routine CALL BX RETF 2 ;return to caller, but ;without restoring flags. ;Set segments and stack as expected by monitor ;internals. XCALL: POP CS:XROUT ;Get return address PUSH DS ;save caller's segments PUSH ES MOV BX,CS ;set monitor segments MOV DS,BX MOV ES,BX MOV XSEG,SS ;save stack segment MOV XPTR,SP ;and stack pointer MOV SS,BX ;set monitor stack MOV SP,MONSP SUB SP,20H CALL XROUT ;do routine MOV SS,XSEG ;restore caller's stack MOV SP,XPTR POP ES ;and segments POP DS RET EJECT ;MONITOR ENTRY POINTS ;==================== ;Set entry vector. ;IN: AX=New value ; DX=Vector number SETENT: MOV BX,DX SHL BX,1 MOV CS:VECTAB+JTOFF[BX],AX RET ;Set reset vector ;IN: AX=New offset ; DX=New segment ;OUT: AX=Check value ; BX=Memory size (in Ks) XSETRESET: CALL XCALL SETRESET: MOV VRESET,AX MOV VRESET+2,DX ADD AX,DX MOV BX,MEMSIZE MOV VRESET+4,BX ADD AX,BX XOR AX,0D0BEH MOV VRESET+6,AX RET ; DUART ROUTINES ; ============== ; DUART INTERRUPT CONTROL ; ----------------------- ;Enable DUART interrupt. ;IN: AL=Interrupt bit mask ;OUT: AL=Current state of DUART IMR. DUON: OR AL,CS:DUIMR MOV CS:DUIMR,AL OUT DUART+10,AL RET ;Disable DUART interrupt. ;IN: AL=Interrupt bit mask. ;OUT: AL=Current state of DUART IMR. DUOFF: NOT AL AND AL,CS:DUIMR OUT DUART+10,AL MOV   CS:DUIMR,AL RET ; DUART BIT OUTPUTS CONTROL ; ------------------------- ;Set bit output to high level. ;IN: AL=Bit mask. ;OUT: AL=New output pattern. DUHIGH: OUT DUART+30,AL OR AL,CS:DUOUT MOV CS:DUOUT,AL RET ;Set bit output to low level. ;IN: AL=Bit mask. ;OUT: AL=New output pattern. DULOW: OUT DUART+28,AL NOT AL AND AL,CS:DUOUT MOV CS:DUOUT,AL RET ; *** CONSOLE I/O *** ; ==================== ;Increment BX to point to the next byte in the circular console ;IO buffer. Buffer ranges from CONBUF to CONTOP. CONINC: INC BX CMP BX,OFFSET CONTOP JNZ CON0 MOV BX,OFFSET CONBUF CON0: RET ;Clear buffer and pending character CONCLR: PUSH AX MOV AX,CS:CONPUT MOV CS:CONGET,AX ;clear buffer POP AX RET ;Console status routine. ; AL=0 if no character ready ; AL=0FFH if character is ready ;Routine will force an interrupt if status line shows ;that a character is ready. This way console input can ;still be done while interrupt is disable. CONST: PUSHF ;Save interrupt flag CLI ;Stop interrupts IN AL,SASTAT ;Interrupt pending? AND AL,RXRDY ;If so interrupts are JZ CON1 ;probably disabled INT 12 ;So force interrupt. CON1: MOV AX,CS:CONPUT ;Character ready? SUB AX,CS:CONGET JZ CON2 ;No, exit AL=0 MOV AL,0FFH ;Yes, set AL=0FFH CON2: POPF ;Restore interrupt flag OR AL,AL ;Set Z flag also RET ;Console input ; returns ASCII code in AL. ; parity is removed from AL, inverted ; and put into Z. (so NZ indicates parity=1) CONIN: CALL CONST JZ CONIN PUSH BX PUSHF CLI MOV BX,CS:CONGET MOV AL,CS:[BX] ;Get character from buffer CALL CONINC MOV CS:CONGET,BX ;Update pointer POPF MOV BL,AL AND AL,7FH CMP AL,BL POP BX RET ;Console output ; Output character in AL to console CONOUT: PUSH AX CON4: IN AL,SASTAT AND AL,TXRDY JZ CON4 POP AX OUT SADATA,AL RET EJECT ; *** OTHER SERIAL IO *** ; ========================= ;Output to DUART port B, probably a printer. DUBOUT: PUSH AX DUB3: IN AL,SBSTAT TEST AL,TXRDY JZ DUB3 POP AX OUT SBDATA,AL RET ;Input from DUART port B, could be used for a modem. DUBIN: IN AL,SBSTAT TEST AL,RXRDY JZ DUBIN IN AL,SBDATA RET ;Printer spooling entry. ;Set up and start buffered printer output. ;IN: AX=Data start ; DX=Data segment ; CX=Data end ;OUT: Carry set if interrupt active, this probably means ; that printer is busy. If interrupt is clear then ; pointers are set up, interrupt vectors set, and ; interrupts are enabled. User should set interrupt ; #60 to clean up routine, int. 60 is called when ; last character is sent to printer. LSTSPOOL: PUSH DS PUSH AX MOV AX,CS ;Set DSM1 MOV DS,AX CLI ;Shut off interrupt. MOV AL,10H ;Is printer active? TEST AL,DUIMR JNZ LST0 MOV VLST,OFFSET LSTINT ;Set up vector. MOV VLST+2,CS CALL DUON ;Enable interrupt. POP AX MOV LSTPTR,AX ;Set up buffer pointers. MOV LSTSEG,DX MOV LSTEND,CX CLC LST1: STI POP DS RET LST0: STC ;Interrupt already on, better POP AX ;not do anything with printer, JMPS LST1 ;return with C set. ;Shut off printer spooling. STOPSPOOL: PUSH AX PUSHF CLI MOV AL,10H TEST AL,CS:DUIMR JZ STOP0 CALL DUOFF INT 60 STOP0: POPF POP AX RET ;Return list status. ;OUT: AL=0 if not ready ; AL=-1 if ready ; Z set by the contents of AL. LSTST: MOV AL,0 TEST CS:DUOUT,10H ;Check if spooling is on JNZ LST5 IN AL,SBSTAT ;check busy. AND AL,TXRDY JZ LST5 MOV AL,-1 LST5: OR AL,AL RET ; DISK ROUTINES ; ------------- ;The disk routines generally use a lot of stack space and ;destroy register values. These routines switch to the ;monitor stack and segments (with CALL XCALL) which takes ;some pressure off the caller's stack. Then DOAX saves most ;of the other registers so the routines are consistant with ;the monitor entry convention of preserving registers. XDSKCHECK: CALL XCALL MOV AX,OFFSET DSKCHECK JMPS   DOAX XHOME: CALL XCALL MOV AX,OFFSET HOME JMPS DOAX XWRITE: CALL XCALL MOV AX,OFFSET DISKWRITE JMPS DOAX XREAD: CALL XCALL READ: MOV AX,OFFSET DISKREAD DOAX: PUSH BX PUSH CX PUSH DX PUSH DI CALL AX POP DI POP DX POP CX POP BX RET EJECT ; OTHER CONSOLE OUTPUT ROUTINES ; ----------------------------- ;Send ASCII at DS:BX to console until a 0 (mess0) or AH (mess1) ;is encountered. MESS0: MOV AH,0 MESS1: MOV AL,[BX] INC BX CMP AL,AH JZ MESS2 CALL CONOUT JMPS MESS1 MESS2: RET ;Send message contained in the code segment following ;the call to the console. Message ends with 0. Return ;is made to byte after the 0. It is assumed that DS=CS MESSAGE: PUSH AX PUSH BX PUSH BP MOV BP,SP MOV BX,6[BP] CALL MESS0 MOV 6[BP],BX POP BP POP BX POP AX RET ;Send message routine for external interrupts. Message ;is in caller's CS right after INT instruction. Message ;ends with 0. Return is made to byte after 0. XMESSAGE: PUSH AX PUSH BP PUSH DS MOV BP,SP MOV DS,10[BP] MOV BX,8[BP] CALL MESS0 MOV 8[BP],BX POP DS POP BP POP AX RET ;Send message at DS:DX to console. Message ends with '$' DOLMESS: PUSH AX MOV AH,'$' XCHG BX,DX CALL MESS1 XCHG BX,DX POP AX RET ;Send value in A (word, byte, or nibble) to console in hex HEXWORD: PUSH AX MOV AL,AH CALL HEXBYTE POP AX HEXBYTE: PUSH AX SLR AL,4 ;SHR AL,4 CALL HEXNIB POP AX HEXNIB: PUSH AX AND AL,0FH  CMP AL,10 JC HEX2 ADD AL,7 HEX2: ADD AL,'0' CALL CONOUT POP AX RET ; DECIMAL DISPLAY ; --------------- ;Display value in AX on console in decimal. XDECDISP: CALL XCALL DECDISP: PUSH AX ;Save registers. PUSH BX PUSH CX PUSH DX MOV BX,10 ;Divisor MOV CX,5 ;Number of digits DD0: MOV DX,0 DIV BX PUSH DX ;Remainder. LOOP DD0 MOV CX,5 DD1: POP AX CMP AX,0 LOOPZ DD1 ;Skip leading zeros INC CX DD2: ADD AL,'0' ;Binary to ascii CALL CONOUT ;Display digit. POP AX LOOP DD2 MOV DX,AX ;Restore registers POP CX POP BX POP AX RET ; ADDITIONAL DISPLAY ROUTINES ; --------------------------- ;These routines are terminal dependent. Parameters for these ;routines are stored in the CRT ram area. ; CRTTYPE contains bit flags on terminal type ; Bit 0: Column first ; Bit 1: Leading zeros ; Bit 2: 3 digits ; Bit 7: Address in ASCII decimal. ; CRTXOR1 bits in first address are flipped ; CRTADD1 added to first address ; CRTXOR2 bits in second address are flipped ; CRTADD2 added to second address ;Most terminals expect cursor position in binary with offset. ;ANSI terminals expect decimal ASCII. Usually row is sent first. ;If cursor position is sent in ASCII 2 or 3 digits and leading ;zeros can be selected. An offset is often required, usually 20H ;for cursor address. These routines assume 0,0 is in the upper ;right corner, if this corner is 1,0 or 1,1 on your terminal the ;adjusted can be made in CRTADD along with the offset. If you ;terminal has the origin at the bottom, the position can be ;inverted with CRTXOR. ; CRTLED 7 bytes lead in sequence ; CRTMID 7 bytes middle sequence ; CRTEND 7 bytes closing sequence ; CRTCLR 8 bytes clear screen sequence ;The first byte in each sequence holds the number of bytes ;to send, the rest hold the codes to send. The lead in sequence ;is usually two bytes long, with the first byte being ESC. The ;middle sequence if needed is usually a ','. The end sequence is ;usually not needed. The clear screen sequence is usually one ;byte, often control-L. Sometimes home and clear are separate ;functions, then multiple bytes are needed. ; CRTCRL - Send escape sequence to CRT ; Enter: BX-> escape sequence table, consisting of ; escape sequence count byte, followed by the bytes ; making up the sequence. CRTCRL: PUSH CX MOV CL,CS:BYTE PTR [BX] MOV CH,0 CMP CL,CH JZ CRTRET CRTLP: INC BX MOV AL,CS:BYTE PTR [BX] CALL CONOUT LOOP CRTLP CRTRET: POP CX RET ;   WRTADD - Send the cursor address in Reg. AL to CRT, convert ; to ASCII if necessary. WRTADD: MOV BH,CS:CRTTYPE TEST BH,80H ;Decimal? JZ CRTBIN MOV BL,10 MOV AH,0 DIV BL PUSH AX CBW DIV BL TEST BH,4 ;3 digits? JZ CRT3 CMP AL,0 JNZ CRT2 TEST BH,2 ;send zeros JZ CRT3 CRT2: ADD AL,'0' ;100s digit CALL CONOUT CRT3: CMP AH,0 JNZ CRT4 TEST BH,2 ;send zeros JZ CRT5 CRT4: MOV AL,AH ;10s digit ADD AL,'0' CALL CONOUT CRT5: POP AX MOV AL,AH ADD AL,'0' ;1s digit CRTBIN: CALL CONOUT ;or binary RET ; CLRSCR - Clear entire screen. CLRSCR: PUSH AX PUSH BX MOV BX,OFFSET CRTCLR CALL CRTCRL POP BX POP AX RET ; CRTSET - Address the cursor. ; Enter with DL = vertical row #. Top row = 0. ; DH = horizontal column #. Left column = 0. CRTSET: PUSH AX PUSH BX PUSH DX MOV BX,OFFSET CRTLED CALL CRTCRL ;Send lead in sequence TEST CS:CRTTYPE,1 ;Reverse row/column? JZ CRT1 XCHG DH,DL CRT1: MOV AL,DL XOR AL,CS:CRTXOR1 ;Adjust address ADD AL,CS:CRTADD1 CALL WRTADD ;Send first address MOV BX,OFFSET CRTMID CALL CRTCRL ;Send middle sequence MOV AL,DH XOR AL,CS:CRTXOR2 ;Adjust second address ADD AL,CS:CRTADD2 CALL WRTADD MOV BX,OFFSET CRTEND CALL CRTCRL ;Send closing sequence POP DX POP BX POP AX RET  ; 058D 0F ; 058E 8B ;in the even eprom, and ; 058C BF ; 058D 85 ; 058E F7 ;in the odd eprom. PATCH0: ;Pat; *** DISK INTERFACE *** ; ====================== ;Calculate address for DMA. ; DMA uses 4 bits + 16 bits format for big addresses, ; as opposed to segment + offset like the rest of ; the CPU. ;Segment/offset to upper/lower conversion is ;done and DMA address is set. ;IN: DX=DMA port. ;MEMADR sets RAM address, should have DX=DMADL for read, ;and DX=DMASL for write. ;DSKADR sets disk address, should have DX=DMASL for read, ;and DX=DMADL for write. MEMADR: PUSH CX MOV AX,DSKMEM MOV CX,DSKSEG JMPS ADR5 DSKADR: PUSH CX MOV AX,DATAADR[DI] MOV CX,DATAADR+2[DI] ADR5: PUSH BX MOV BX,CX SLL BX,4 SLR CX,12 ADD AX,BX POP BX OUT DX,AX MOV AX,CX ADC AX,0 ADD DX,2 OUT DX,AX SUB DX,2 POP CX RET ;Set DX to correct DMA port, DMA0 for floppy, or DMA1 ;for hard disk. ;OUT: DX=DMA port. DMAPORT: MOV DX,DMACH1 AND DL,DTYPE[DI] SHR DL,1 ADD DX,IPC+DMA0 RET ;Set up DMA for disk operation. ;OUT: DX=DMA command port DMASETUP: CALL DMAPORT MOV AX,SECLEN[DI] ADD DX,DMATC ;Set transfer count OUT DX,AX SUB DX,DMATC TEST DSKCMD,1 JNZ SET0 CALL DSKADR ;If read source=disk ADD DX,DMADST CALL MEMADR ;Dest=memory. MOV AX,RDCMD[DI] JMPS SET1 SET0: CALL MEMADR ;If write sorce=memory. ADD DX,4 CALL DSKADR ;Dest=disk. MOV AX,WRTCMD[DI] SET1: ADD DX,DMACTL-DMADST ;Set command. OUT DX,AX RET ;Check dma count for completed transfer. AL=0 if transfer ;complete, AL=-3 if not. Z set by AL. DMACHECK: CALL DMAPORT ADD DX,DMATC ;Get count port. IN AX,DX ;Get count. OR AX,AX JZ DMA2 MOV AL,-3 DMA2: RET ;Locate disk block for logical drive in DSKNUM. ;IN: DSKNUM=Logical disk ;OUT: BX=Pointer to disk block ; DI=Pointer to sector skew routine ;Carry set if dsknum does not make sense. LOCBLOCK: MOV BL,DSKNUM CMP BL,16 CMC JC LOC0 ;Bad number? MOV BH,0 SLL BX,2 ;Find table entry ADD BX,OFFSET DISKTABLE MOV DSKPTR,BX MOV DI,2[BX] ;Get sector routine MOV BX,[BX]   ;Get disk block CMP BX,1 ;No block? LOC0: RET ;Home disk. ; set LSTTRK to -1 so disk looks uncalibrated. ; next read or write will force a home. ; C set on exit if disk is undefined. HOME: CALL LOCBLOCK JC HOME0 MOV LSTTRK[BX],-1 HOME0: RET ;Set up for a disk operation. ; DSKNUM, DSKTRACK, DSKSECTOR are set up for ; a disk operation. ;IN: DSKNUM=Logical disk ; DSKTRACK=Logical track ; DSKSECTOR=Logical sector ;OUT: BX=Physical disk block ; DI=Disk type table ; TRACK[BX]=Track ; SECTOR[BX]=Sector ; SIDE[BX]=Side DSKOP: PUSH CX CALL LOCBLOCK JC DSK4 MOV AX,DSKTRACK MOV CL,DSKSECTOR MOV CH,SIDE[BX] CALL DI MOV TRACK[BX],AX MOV SECTOR[BX],CL MOV SIDE[BX],CH MOV DI,TYPEPTR[BX] CLC DSK4: POP CX RET EJECT ; *** FLOPPY ROUTINES *** ; ======================= ;Wait until FDC is not busy. ; A delay of up to 56 usec is required after a write to the ; command register, before the status may be read. ; Routine returns status in AL. ; Return not ready if no response after 3 seconds. FDCWAIT: MOV AL,COUNT ADD AL,FDELAY ;Wait for not busy FDC1: TEST BITS,FDRDY JNZ FDC2 CMP AL,COUNT JNZ FDC1 MOV AL,0D0H ;If time out then OUT FDCCMD,AL ;force interrupt MOV AL,80H ;not ready JMPS FDC0 FDC2: IN AL,FDCSTAT FDC0: RET RESTORE: MOV AL,STEPRATE[DI] ;///MAY WANT TO ADD STEP IN CASE HEAD IS POSITION OUTSIDE ;///OF TRACK ZERO SENSE AREA. AND BITS,NOT FDRDY OUT FDCCMD,AL CALL FDCWAIT AND AL,10010000B ;Not ready or seek error RET ;Select floppy disk. FLOPSEL: MOV AL,SECLOW ;Motor on for up MOV AH,DSTIME ;Set deselect time ADD AH,AL MOV DESELECT,AH ADD AL,FDTIME ;and shut off time MOV FDSTOP,AL MOV AL,FDMOTOR TEST AL,DUOUT JNZ FLOP6 CALL DUHIGH ;Turn drive on. MOV AL,COUNT ;Give it time ADD AL,FDELAY ;to get up to speed. FLOP5: CMP AL,COUNT JNZ FLOP5 FLOP6: MOV CX,4 MOV AL,DISK[BX] ;Select. MOV DX,SYSPORT+10 ;Drive 0. MOV AH,DL ;Compute lower part of SUB AH,AL ;address for selected SUB AH,AL ;drive FLOP0: MOV AL,0 ;Deselect all drives CMP AH,DL ;except the one that JNZ FLOP4 INC AL ;matches AH FLOP4: OUT DX,AL SUB DL,2 LOOP FLOP0 MOV DX,SYSPORT+12 ;Mini? MOV AL,DTYPE[DI] OUT DX,AL MOV DX,SYSPORT+14 ;Double density? SHR AL,1 XOR AL,1 OUT DX,AL RET FLOPSEEK: MOV AL,BYTE PTR LSTTRK[BX] ;Know track? CMP AL,-1 JNZ FLOP7 CALL RESTORE ;If not find zero. JNZ FLOP1 FLOP7: MOV AH,STEPRATE[DI] ;get step rate TEST DTYPE[DI],HALFTRK JZ FLOP2 ;check for halftrack PUSH AX ;if so remove verify AND AH,NOT 4 CALL FLOP2 ;move half way POP AX JNZ FLOP1 FLOP2: OUT FDCTRK,AL ;Set track register. SUB AL,BYTE PTR TRACK[BX] JZ FLOP1 ;already there? MOV AL,BYTE PTR TRACK[BX] MOV BYTE PTR LSTTRK[BX],AL ;update old track. MOV BYTE PTR LSTTRK+1[BX],0 OUT FDCDAT,AL MOV AL,AH OR AL,10H ;Seek AND BITS,NOT FDRDY OUT FDCCMD,AL CALL FDCWAIT AND AL,10010000B ;Not ready or seek error? FLOP1: RET ;Do floppy operation, read or write. FLOPOP: PUSH DX ;Save DMA command port CALL FLOPSEL ;Select drive. CALL FLOPSEEK ;Seek (if needed) POP DX JNZ FLOP3 IN AX,DX OR AL,DMASTRT+DMACHG ;Start DMA. OUT DX,AX MOV AL,SECTOR[BX] ;Set sector. OUT FDCSEC,AL MOV AL,DSKCMD ;Read or write? SLL AL,4 XOR AL,SIDE[BX] SHL AL,1 XOR AL,88H AND BITS,NOT FDRDY OUT FDCCMD,AL ;Do disk operation. CALL FDCWAIT AND AL,11111110B ;Write error test. JZ FLOP3 TEST DSKCMD,1 JNZ FLOP3 AND AL,10011110B ;Read error check. FLOP3: RET ;Translate routine for double sided disks. ;Bit 7 of sector set if second side. TWOSIDE: CLC SHR CH,1 SHL CX,1 SHR CL,1 RET EJECT ; *** HARD DISK ROUTINES *** ; ========================== ;Reset SASI controller. WINRST: MOV DX,SYSPORT+RST MOV AL,0 OUT DX,AL MOV AL,1 OUT DX,AL RET ;Wait for controller to become not busy. ;OUT: DX=SASI+1 ; AH=Time ; C set if time out. ;NOTE: By setting DX one more than expected, the stat  us ; shows up in AL instead of AH. Thus 8 bit input ; can be done and AH is freed up for some other ; use, in this case monitoring the time. WINWAIT: MOV DX,SASI+1 MOV AH,COUNT ADD AH,FDELAY WIN0: IN AL,DX TEST AL,WINBUSY/256 JZ WIN1 CMP AH,COUNT JNZ WIN0 CMC WIN1: RET ;Wait for request from SASI controller. ;OUT: AH=Time ; DX=SASI+ACK ; C set if time out. WINREQ: MOV DX,SASI+1 MOV AH,COUNT ADD AH,FDELAY WIN4: IN AL,DX TEST AL,REQ/256 JNZ WIN5 CMP AH,COUNT  JNZ WIN4 CMC WIN5: MOV DX,SASI+ACK RET ;Send command to controller. ; Six byte command assumed set up in WINTASK ;OUT: AX=Unknown ; CX=Bytes not sent (0 if no error) ; DX=SASI+ACK ; C set if error CMDOUT: PUSH BX MOV BX,OFFSET WINTASK MOV CX,6 CALL DATAOUT POP BX RET ;Send data to controller. ;IN: BX=Pointer to data ; CX=Number of bytes to send ;OUT: BX=Points to last byte sent + 1 ; CX=Number of bytes not sent ; DX=SASI+ACK ; C set if error DATAOUT: CALL WINREQ JC WIN6 MOV AL,[BX] OUT DX,AL INC BX LOOP DATAOUT WIN6: RET ;Get status after command. ;OUT: AL=Status ; DX=SASI+ACK ; C set if time out WINSTAT: CALL WINREQ JC WIN8 IN AL,DX PUSH AX CALL WINREQ IN AL,DX POP AX JC WIN8 TEST AL,WINERR JZ WIN8 CMC WIN8: RET ;Initialize Winchester. ; Set up for 5 Meg Tandon. There is currently no ; easy way to change this for other drives. (Other ; than burning new eproms.) ;OUT: AX,CX,DX=Unknown ; C set if error WININIT: PUSH BX PUSH WORD PTR WINTASK MOV WINTASK,0CH CALL CMDOUT JC WIN13 MOV BX,OFFSET WINDATA MOV CX,8 CALL DATAOUT JC WIN13 CALL WINSTAT JC WIN13 MOV LSTTRK[BX],0 WIN13: POP WORD PTR WINTASK POP BX RET WINROM DB 0,99H,4,0,80H,0,99H,0BH ;Select controller. ;IN: BX,DI=Set up for disk operation ;OUT: AX,CX,DX=Unknown ; C set if error. WINSEL0: MOV CL,DTYPE[DI] ;Controller number is AND CL,7 ;stored in lower three MOV AL,1 ;bits of DTYPE. SHL AL,CL MOV DX,SASI OUT DX,AL CALL WINWAIT JC WIN9 MOV DX,SYSPORT+SEL MOV AL,0 OUT DX,AL ADD AH,FDELAY ;Time MOV DX,SASI+1 WIN3: IN AL,DX TEST AL,WINBUSY/256 ;Wait for busy to make JNZ WIN2 ;controller is present. CMP AH,COUNT JNZ WIN3 CMC WIN2: MOV DX,SYSPORT+SEL MOV AL,1 OUT DX,AL WIN9: RET WINSEL: TEST BITS,WINON JNZ WIN14 CALL WINRST WIN14: CALL WINSEL0 JC WIN15 OR BITS,WINON CMP LSTTRK[BX],-1 JNZ WIN15 CALL WININIT JC WIN15 CALL WINSEL0 WIN15: RET ;Issue command to controller. Normally only read sector ; and write sector, however other commands may ; be hidden in SIDE[BX]. WINTASK+4 (block count) ; is assumed to be set up before calling this ; routine. ;IN: BX,DI=Set up for disk operation. ;OUT: CX=Unknown ; C set if error WINCMD: PUSH DX CALL WINSEL JC WIN7 MOV AL,DSKCMD ADD AL,AL ADD AL,8 XOR AL,SIDE[BX] MOV WINTASK,AL MOV AX,10200 CWD MOV CX,SECLEN[DI] ADD CX,60 DIV CX MOV DX,AX MOV AX,TRACK[BX] MUL DX ADD AL,SECTOR[BX] ADC AH,0 XCHG AH,AL MOV WORD PTR WINTASK+2,AX MOV AL,DISK[BX] SLL AL,5 ADD AL,DL MOV WINTASK+1,AL MOV AL,STEPRATE[DI] MOV WINTASK+5,AL CALL CMDOUT WIN7: POP DX RET ;Do winchester operation. ;IN: BX,DI=Set up for disk operation. ;OUT: CX,DX=Unknown. ; NZ set if error ; AL=error code ;NOTE: Current AL=80 (not ready) is returned for all errors. WINOP: CALL WINCMD JC WIN10 MOV CX,SASI+1 IN AX,DX OR AL,DMASTRT+DMACHG OUT DX,AX XCHG DX,CX WIN11: IN AL,DX TEST AL,CONTROL/256 JZ WIN11 XCHG CX,DX IN AX,DX AND AL,NOT DMASTRT OR AL,DMACHG OUT DX,AX CALL WINSTAT JNC WIN12 WIN10: MOV AL,80H OR AL,AL WIN12: RET EJECT ; *** DISK ROUTINES *** ; ====================== DISKREAD: MOV DSKCMD,0 ;Set command JMPS DSK0 DISKWRITE: MOV DSKCMD,1 ;Set command. DSK0: PUSH SI CALL DSKOP ;Set up disk block JNC DSK1 OR AL,-1 JMPS DSK2 DSK1: CALL DMASETUP ;and DMA. MOV AX,HARD+FLOPPY ;Get disk rou  tine. AND AL,DTYPE[DI] SLR AL,2 ADD AX,OFFSET DSKROUTS MOV SI,AX CALL WORD PTR [SI] ;and call it. JNZ DSK2 CALL DMACHECK DSK2: POP SI RET ;DISKREAD and DISKWRITE return an error code in AL. 0 indicates ;no error. Z is set by AL, so NZ indicates a error. ;General error codes, (all types of disks). ; FF Drive does not exist. ; FD Bad DMA count. ;Error codes for floppies. ; 80 Not ready. ; 40 Write protected. ; 20 Write fault. ; 10 Seek error or record not found. ; 8 CRC error. ; 4 Lost data. ; 2 Data request. (Disk expects more.) ;The above floppy error codes are ored if more than one error ;condition is present. EJECT ; DISK TYPE JUMP TABLE ; -------------------- DSKROUTS: DW OFFSET USER0 DW OFFSET FLOPOP DW OFFSET WINOP DW OFFSET USER1 USER0: JMP USR0 ;Operation JMP USR0+2 ;Check USER1: JMP USR1 ;Operation JMP USR1+2 ;Check SELFLOP: PUSH BX MOV BX,DSKPTR ;Set xlate to do nothing MOV WORD PTR 2[BX],OFFSET ROMRET POP BX AND DTYPE[DI],FLOPPY+MINI+DOUBLE CALL FLOPSEL ;///MAY NEED WAIT HERE IN AL,FDCSTAT TEST AL,80H JZ FD7 ;if not ready assume 5" MOV DTYPE[DI],FLOPPY+MINI FD7: PUSH WORD PTR STEPRATE[DI] ;remove verify AND STEPRATE[DI],NOT 4 MOV LSTTRK[BX],-1 ;calibrate MOV TRACK[BX],2 ;then seek track 2 MOV SIDE[BX],24H ;read address PUSH DSKSEG ;set disk memory PUSH DSKMEM ;to select buffer MOV DSKSEG,SEG SELBUF MOV DSKMEM,OFFSET SELBUF MOV SECLEN[DI],6 CALL DMASETUP CALL FLOPOP JZ FD8 ;did it work? XOR DTYPE[DI],DOUBLE ;if not flip density MOV LSTTRK[BX],-1 CALL DMASETUP CALL FLOPOP ;if this didn't work JNZ FD2 ;then give up. FD8: MOV AL,SELBUF ;get track number CMP AL,2 ;at track 2? (not sure JZ FD3 ;because verify is off) CMP AL,1 ;track 1? JNZ FD4 ;if not give up OR DTYPE[DI],HALFTRK ;try half track. MOV LSTTRK[BX],-1 CALL DMASETUP CALL FLOPOP JNZ FD4 ;give up if error CMP BYTE PTR SELBUF,2 JNZ FD4 ;or not track 2 FD3: MOV AL,SELBUF+3 ;have adr. info. PUSH AX MOV SIDE[BX],25H CALL DMASETUP ;Try side 2 CALL FLOPOP POP CX JNZ FD5 ;If error TEST SELBUF+1,1 ;or side 1 then SS JZ FD5 ;else set DS flag OR CL,4 PUSH BX MOV BX,DSKPTR ;and xlate routine MOV WORD PTR 2[BX],OFFSET TWOSIDE POP BX FD5: MOV CH,CL ;sector length code in CH AND CL,3 ;put length in AX MOV AX,128 SHL AX,CL MOV SECLEN[DI],AX ;and store it JMPS FD6 FD2: MOV DTYPE[DI],FLOPPY MOV CH,80H ;disk read error JMPS FD6 FD4: MOV CH,40H ;can't figure it out FD6: MOV SIDE[BX],0 POP DSKMEM ;restore disk pointers POP DSKSEG POP AX MOV STEPRATE[DI],AL ;and step rate MOV AL,CH ;length or error code RET DSKCHECK: PUSH SI MOV DSKCMD,0 ;set for read CALL DSKOP ;get pointers MOV AL,0C0H JC DSK13 ;disk exists? MOV AX,HARD+FLOPPY ;if so locate select routine AND AL,DTYPE[DI] SLR AL,2 ADD AX,OFFSET SELROUTS MOV SI,AX MOV AL,0 CALL WORD PTR [SI] ;and call it MOV AH,DTYPE[DI] ;type to AL DSK13: TEST AL,0C0H POP SI  RET ;Determine disk type routine for winchester SELWIN: CALL WINSEL MOV CL,80H JC SEL0 MOV CL,40H MOV AX,SECLEN[DI] SLR AX,7 JZ SEL0 MOV CL,0 SEL1: CMP AX,1 JZ SEL0 INC CL SHR AX,1 JMPS SEL1 SEL0: MOV AL,CL RET SELROUTS: DW OFFSET USER0+3 DW OFFSET SELFLOP DW OFFSET SELWIN DW OFFSET USER1+3 ; READ/WRITE A RANGE OF SECTORS ; ----------------------------- REPREAD: PUSH DI PUSH SI ;Put read routine in SI MOV SI,OFFSET DISKREAD JMPS REP3 REPWRITE: PUSH DI PUSH SI ;Put write routine in SI MOV SI,OFFSET DISKWRITE REP3: REP2: CALL SI ;Read or write JNZ REP0 ;Quit if error MOV AL,SECCNT DEC AL ;Or if done. JZ REP0 MOV SECCNT,AL MOV AX,SECLEN[DI] ;Update memory ADD DSKMEM,AX MOV AL,DSKSECTOR CMP AL,TRKSIZE JNZ REP1 INC DSKTRACK ;and track MOV AL,0 REP1: INC AL MOV DSKSECTOR,AL ;and sector. JMPS REP2 ;Then repeat REP0: POP SI POP DI RET    ;********************************************************** ;*** *** ;*** INTERRUPT SERVICE ROUTINES *** ;*** *** ;********************************************************** ; *** PRINTER INTERRUPT *** ; ========================= ;Buffered print interrupt routine LSTINT: ;Int. 61 PUSH DS ;Save DS MOV BX,CS:LSTPTR MOV DS,CS:LSTSEG MOV AL,[BX] ;Get next character. OUT SBDATA,AL ;Print it CMP BX,CS:LSTEND ;Done? JZ LST2 INC BX ;If not update pointer  MOV CS:LSTPTR,BX JMPS LST4 LST2: MOV AL,10H ;Else shut off interrupt. CALL DUOFF INT 60 ;Goto user clean up routine LST4: POP DS IRET ; *** CONSOLE INTERRUPT ROUTINES *** ; ================================== ;Start up interrupt, reset vector is made valid after ;first DUART interrupt. Thus two consecutive resets ;causes a cold start. STARTINT: MOV VINT0,OFFSET DUARTINT MOV VINT0+2,CS ;Switch vector to PUSH AX ;duartint, make reset MOV AX,CS:MEMSIZE ;valid then fall MOV CS:VRESET+4,AX ;into duartint. POP AX ;DUART interrupt routine. Source can be printer ;or console. DUARTINT: ;Int. 12 PUSH AX PUSH DX PUSH BX IN AL,DUART+10 TEST AL,2 ;Console interrupt? JZ NOTCONIN IN AL,SADATA CMP AL,CNTL+'C' ;Check for control-C JNZ DU0 CALL CONCLR ;If ^C then flush DU0: MOV BX,CS:CONPUT MOV DX,BX CALL CONINC CMP BX,CS:CONGET ;Check for room. JZ RETINT0 MOV CS:CONPUT,BX ;If enough room then MOV BX,DX ;then change pointer MOV CS:[BX],AL ;and put char. JMPS RETINT0 NOTCONIN: INT 61 ;Port B interrupt RETINT0: POP BX MOV AX,12 RETINT: MOV DX,IPC+EOI OUT DX,AX POP DX POP AX IRET ; *** TIMER INTERRUPTS *** ; ========================== ;One second interrupt. SECOND: ;Int. 58 MOV AL,CS:SECLOW ;Check if it is CMP CS:FDTIME,0 JZ FDT3 CMP AL,CS:FDSTOP ;time to shut off JZ FDT1 ;floppy motor FDT3: CMP CS:DSTIME,0 JZ FDT0 CMP AL,CS:DESELECT ;or deselect JZ FDT2 FDT0: IRET FDT1: MOV AL,FDMOTOR ;Motor shut off CALL DULOW FDT2: PUSH CX MOV CX,4 ;Deselect all. MOV DX,SYSPORT+10 MOV AL,0 FD1: OUT DX,AL DEC DX DEC DX LOOP FD1 POP CX IRET ;Enter here if automatic disk shut off is not wanted. TIME: PUSH AX PUSH DX INC CS:COUNT MOV AL,CS:COUNT CMP AL,CS:NXTSEC JNZ TIME0 INC CS:SECONDS ;Seconds count. ADD CS:NXTSEC,CPS INT 58 ;Second interrupt TIME0: MOV AX,8 JMP RETINT ; *** FLOPPY DISK INTERRUPT *** ; ============================= ;Interrupt generated by floppy disk controller when status is ready FDINT: PUSH AX PUSH DX OR CS:BITS,FDRDY MOV AX,13 JMP RETINT START: RET DSKMEM,AX MOV AL,DSKSECTOR CMP AL,TRKSIZE JNZ REP1 INC DSKTRACK ;and track MOV AL,0 REP1: INC AL MOV DSKSECTOR,AL ;and sector. JMPS REP2 ;Then repeat REP0: POP SI POP DI RET  ;*********************************************************** ;**** **** ;**** SLICER STAND ALONE LOADER **** ;**** ========================= **** ;**** **** ;*********************************************************** ; Version 3.1 ; by Earl Hinrichs ; for Slicer Computers Inc. ; started August 26, 1983 ; last update December 11 6,1984 ; copyright Slicer Computers Inc., 1983, 1984 ;GENCMD DATA[M10] ;Use DDT to patch into the SETUP program. ;Version 3.0 June 4,1984 elh ; Bug with hard disk control byte fixed. Loader would put ; control byte in the wrong place, and it would never get ; used. The default value, 0 ( 3ms steps) would be used. ; ; Order in which logical disks are put on the hard disk is ; changed. H: is now on the outside. For booting the hard ; disk, logical disk H: should have the system. ; ; Format assumptions for 40 track, double sided, double ; density, 5-1/4" drives changes. IBM PC format assumed. ; this means that all tracks   on the front side are allocated ; before any tracks on the back side. Loader needs to know ; this to locate the system file. ; ; If CPM.SYS is not found, then loader looks for, and loads ; CCPM.SYS. Some size restrictions removed. System files may ; now occupy more than one directory FCB. CPM.SYS must be ; less than 18K to avoid colliding with the loader. The 4F8Hs ; in BTABLE tell the bootstrap where to put the loader. Make ; these bigger if you want to load a larger CPM.SYS. CPM.SYS ; is always loaded at segment 80H. CCPM will be loaded where ; at the segment set by GENCCPM. The loader will move out of ; the way if necessary. The loader however will not move out ; of the first 128K, so if CCPM.SYS loads into this area it ; should be less than 120K. ; ; Currently some of the variables in the SETUP program apply ; only to CPM. (Hard disk size, memory disk size.) The loader ; ignores these variables when loading CCPM. ;Version 3.1 elh December 11, 1984 ; Made stack bigger. EJECT INCLUDE CODES1 ; *** DEFINITIONS *** ; ------------------- ;ASCII codes. CNTL EQU -40H BELL EQU CNTL+'G' LF EQU CNTL+'J' FF EQU CNTL+'L' CR EQU CNTL+'M' ;Monitor locations ESEG ORG 84A0H DSKTABLE RW 1 ORG 0 DSKBLOCK RW 1 ORG 7 TYPEPTR RW 1 ORG 1 STEPRATE RB 1 ORG 8500H WINTASK RB 6 WINDATA RB 8 ORG 850FH FDTIME RB 1 DSTIME RB 1 FDELAY RB 1 CRTTYPE RB 34 CSEG 0F800H ORG 840CH I2CONOUT: DSEG ORG 0 SPT RW 1 BSH RB 1 BLM RB 1 EXM RB 1 DSM RW 1 DRM RW 1 AL0 RB 1 AL1 RB 1 CKS RW 1 OFF RW 1 DPBLEN EQU OFFSET $ RW 4 DIR RW 1 DPB RW 1 CSV RW 1 ALV RW 1 TYP RW 1 SSZ RW 1 TSZ DB 1 DNO DB 1 DPHLEN EQU OFFSET $ - DPBLEN EJECT CSEG 0F800H ORG 0 INIT: ;Monitor start ;Data contained in CMD file header. DSEG 80H ORG 3 CBASE RW 1 ORG 0CH DBASE RW 1 ;DATA STRUCTURES ;Disk type tables DSEG ORG 0 DSKTYPE RW 1 XLATE RW 1 SECSIZE RW 1 TRKSIZE RW 1 BLKSIZE RB 1 ENTRIES RW 1 DBITS RB 1 TRKOFF RW 1 BLKWORD EQU 1 SECZERO EQU 2 ;Some values in the bios. ESEG ORG 253FH FDPH RW 1 DPHS RW 16 BMDSIZE RW 1 DIRBUFPT RW 1 TRKBUFPT RW 1 ;Loader image starts here. CSEG ORG 0 JMP SKIPNAME DB 'SLICER ' SKIPNAME: MOV BX,OFFSET BTABLE MOV AL,1 RET BTABLE DW 0,4F8H ;Load at 4F8:0 DW 80H,4F8H ;Execution starts at 4F8:80 DW 15 ;Loader sectors DW 128 ;Bytes per sector DB 26 ;Sectors per track. LDDATA EQU OFFSET $ RB 4 ;Step rates RW 6 ;Hard disk parameters RW 3 ;Times HDSIZE RW 1 ;Hard disk size MDSIZE RW 1 ;Memory disk size BAUD RB 1 PARITY RB 1 STOPS RB 1 BITS RB 1 CRT RB 34 CSEG 4F8H ORG 80H CLD MOV AX,0F800H MOV ES,AX MOV AX,CS ;Set segments MOV DS,AX MOV SS,AX ;Switch to local stack MOV SP,OFFSET STACK JMP HELLO ;For debugging. RB 20H ;Hello message. HELLO: MOV SI,OFFSET CRT MOV DI,OFFSET CRTTYPE MOV CX,LENGTH CRTTYPE REP MOVSB MON CLRSCR MON MESSAGE DB CR,LF,'SLICER loader program' DB CR,LF,' December 12,1984 Vers. 3.1' DB CR,LF,' Copyright Slicer Computers Inc., 1983, 1984',CR,LF,0 ;Disk set up. MOV DI,OFFSET DSKTABLE MOV SI,LDDATA MOV CX,4 STEPS: MOV BX,DSKBLOCK[DI] ADD DI,4 MOV BX,TYPEPTR[BX] LODSB OR AL,8 MOV STEPRATE[BX],AL LOOP STEPS LODSW MOV FDTIME,AL LODSW MOV DSTIME,AL LODSW MOV FDELAY,AL MOV BX,DSKBLOCK[DI] MOV BX,TYPEPTR[BX] LODSW MOV STEPRATE[BX],AL LODSW XCHG AL,AH MOV WORD PTR WINDATA,AX LODSW MOV WINDATA+2,AL LODSW XCHG AL,AH MOV WORD PTR WINDATA+3,AX LODSW XCHG AL,AH MOV WORD PTR WINDATA+5,AX LODSW MOV WINDATA+7,AL MOV AL,00010101B ;Rx and Tx on OUT 94H,AL MOV AL,PARITY MOV BX,PARTBL XLAT BX ADD AL,BITS OR AL,80H ;Rx controls RTS OUT 90H,AL MOV AL,STOPS MOV BX,STOPTBL XLAT BX ADD AL,10H ;CTS controls Tx OUT 90H,AL MOV AL,BAUD MOV BX,BAUDTBL XLAT BX OUT 92H,AL JMP LOADSYS BAUDTBL EQU OFFSET $ DB 44H,55H,66H,88H,99H,0BBH,0  CCH STOPTBL EQU OFFSET $ DB 7,8,15 PARTBL EQU OFFSET $ DB 16,0,4 EJECT ; SUBROUTINES ; ----------- ;Read a disk block. Block number is in the variable BLOCK. RDBLOCK: MOV AL,BLKSIZE[SI] CBW MOV CX,AX ;Sectors per block MUL BLOCK ;Get sector number. MOV LOGSEC,AX ;First sector of block BLKLP: MOV AX,LOGSEC ;Compute physical track/sector MOV DX,0 DIV TRKSIZE[SI] ADD AX,TRKOFF[SI] MOV DSKTRACK,AX MOV AL,DL MOV BX,XLATE[SI] ;Sector translate. XLAT BX TEST DBITS[SI],SECZERO JNZ BLK3 INC AL BLK3: TEST DSKTYPE[SI],4 ;Double sided? JZ BLK0 CMP SI,IBMDS ;Check for different double JNZ BLK4 ;sided track allocation on IBM PUSH CX MOV CX,DSKTRACK ADD CL,CL ;disks. CMP CL,79 JC BLK5 SUB CL,159 NEG CL BLK5: MOV DSKTRACK,CX POP CX BLK4: SHL AL,1 SHR DSKTRACK,1 RCR AL,1 BLK0: MOV DSKSECTOR,AL MON READ ;read sector. JNZ RDERR MOV AX,SECSIZE[SI] ;Set dskseg for next read. SLR AX,4 ADD DSKSEG,AX INC LOGSEC LOOP BLKLP ;Read next sector. RET RDERR: MON MESSAGE DB CR,LF,'Disk read error',0 JMPF INIT ;Locate CPM.SYS file LOCATE: MOV BLOCK,-1 MOV AX,SECSIZE[SI] ;Bytes/sector SLR AX,5 ;Dir ents./sector MUL BLKSIZE[SI] ;Dir ents/block MOV DIRBLK,AX MOV AX,ENTRIES[SI] ;Total dir. ents. SUB DX,DX DIV DIRBLK ;Number of dir blocks. MOV CX,AX LOC2: PUSH CX MOV DSKSEG,CS MOV DSKMEM,OFFSET DIRBUF INC BLOCK CALL RDBLOCK ;Read block. MOV CX,DIRBLK MOV BX,OFFSET DIRBUF-32 LOC1: PUSH CX ;Search for file ADD BX,32 MOV CX,12 MOV DI,-1 LOC0: INC DI MOV AL,[BX+DI] AND AL,7FH TEST CCPMLD,1 ;CPM or CCPM? JNZ LOC3 CMP AL,CPMSYS[DI] JMPS LOC4 LOC3: CMP AL,CCPMSYS[DI] LOC4: LOOPZ LOC0 JNZ NOTSYS CALL LOADENT NOTSYS: POP CX LOOP LOC1 POP CX LOOPNZ LOC2 ;Z set if found RET0: RET ;BX points to entry ;Load in one directory entry. LOADENT: PUSH BLOCK PUSH BX MOV BP,BX LD4: MOV DSKMEM,0 ;Load file. MOV AX,LDSEG MOV DSKSEG,AX MOV DI,16 LD1: SUB AH,AH MOV AL,[BP+DI] INC DI TEST DBITS[SI],BLKWORD JZ LD0 MOV AH,[BP+DI] INC DI LD0: OR AX,AX JZ LD2 MOV BLOCK,AX CALL RDBLOCK CMP CCPMLD,3 ;First CCPM block? JNZ LD3 CALL CMOVE ;If so move some stuff. MOV CCPMLD,1 JMPS LD4 LD3: CMP DI,32 JC LD1 LD2: MOV AX,DSKSEG MOV LDSEG,AX POP BX POP BLOCK RET ;Move program to segment AX. MOVEME: PUSH ES MOV ES,AX MOV AX,CS MOV DS,AX SUB SI,SI SUB DI,DI MOV CX,OFFSET LDEND / 2 + 1 REP MOVSW PUSH ES ;Change CS PUSH OFFSET HERE RETF HERE: MOV AX,CS MOV DS,AX MOV SS,AX POP ES RET ;Move things around for CCPM. If CCPM is to be loader above segment ;480H then the loader is moved to 80H. If CCPM is loaded below 480H then ;the loader is moved to 1C00H. CCPM normally loads at 80H. CMOVE: PUSH CX PUSH SI MOV AX,LDBASE ;Get file header data MOV DS,AX MOV AX,DBASE ;DS for CCPM MOV SYSDS,AX MOV AX,CBASE ;CS for CCPM. MOV LDBASE,AX MOV LDSEG,AX MOV CX,80H ;Move loader to 80H CMP AX,480H JNC CM0 MOV CX,1C00H ;or 1C00H. CM0: MOV AX,CX CALL MOVEME POP SI POP CX RET ; LOAD SYSTEM FILE ; ---------------- LOADSYS: MON DSKCHECK ;Determine disk format AND AX,1B07H MOV SI,OFFSET DISKTABLES-TYPELEN MOV CX,NUMTYPES TYPE0: ADD SI,TYPELEN CMP AX,DSKTYPE[SI] LOOPNZ TYPE0 JZ GOTTYPE MON MESSAGE DB 'Unknown disk format',CR,LF,0 JMPF INIT GOTTYPE: MOV AX,80H ;Try to load CPM MOV LDBASE,AX MOV LDSEG,AX MOV SYSDS,AX MOV SYSSTART,2500H MOV CCPMLD,0 CALL LOCATE ;Load CPM.SYS MOV AX,LDBASE CMP AX,LDSEG ;Found it? JNZ RELOC MOV CCPMLD,3 ;If not load CCPM.SYS MOV SYSSTART,0 CALL LOCATE MOV AX,LDBASE CMP AX,LDSEG ;Found it? JNZ RELOC MON MESSAGE DB 'No system file',CR,LF,0 JMPF INIT ;Remove the 128 system bytes RELOC: MOV CX,LDSEG MOV AX,LDBASE SUB CX,AX ;Number of segments to move PUSH CX SLR CX,12 ;64K blocks to move MOV ES,AX ADD AX,8 MOV DS,AX JCXZ REL0 RELLP: PUSH CX SUB SI,SI ;Move a 64K block SU  B DI,DI MOV CX,8000H REP MOVSW POP CX MOV AX,ES ADD AX,1000H MOV ES,AX ADD AX,8 MOV DS,AX LOOP RELLP REL0: POP CX ;Move remaining bytes SLL CX,4 SUB SI,SI SUB DI,DI REP MOVSB TEST CCPMLD,1 ;Do some more system set up. JNZ CCPM CALL CPMINIT JMPS GO CCPM: CALL CCPMINIT ;Exit to operating system. GO: PUSH LDBASE PUSH SYSSTART MOV AX,SYSDS MOV DS,AX RETF CCPMINIT: RET ;Initialize BIOS CPMINIT: MOV AX,CS ;Set initial DPH table MOV DS,AX ;to four floppies. MOV DI,OFFSET DPHS MOV AX,FDPH MOV CX,4 LP1: STOSW ADD AX,DPHLEN LOOP LP1 MOV AX,0 MOV CX,12 REP STOSW MOV AX,MDSIZE ;Add memory disk AND AX,0FFFEH STOSW JZ NOMDISK MOV DX,AX MOV AX,12 CALL ADDDISK NOMDISK: MOV AX,HDSIZE ;Add hard disks. SUB DX,DX ;Kbytes on disk MOV BX,17 DIV BX SHL AX,1 CMP DL,7 SBB AX,-1 ;Tracks MOV HTRACKS,AX MOV CX,AX SUB DX,DX MOV BX,963 ;Max tracks allowed by CPM DIV BX ;(=8 Mbytes). INC AX ;Number logical disks XCHG CX,AX SUB DX,DX DIV CX INC AX ;Tracks per logical disk MOV DX,AX ADD CX,6 MOV DSKNO,CL ;Disk number to add. HLP: MOV AX,HTRACKS OR AX,AX JZ NOHARD SUB AX,DX ;Add a hard disk JNC HD0 ADD DX,AX SUB AX,AX HD0: MOV HTRACKS,AX ;Tracks left INC AX MOV BX,AX MOV AL,DSKNO ;Disk number, skip M CMP AL,12 SBB AL,-1 PUSH DX IMUL DX,DX,17 ;Disk size SHR DX,1 CALL ADDDISK POP DX DEC DSKNO JMPS HLP NOHARD: RET ;Add a disk ;AL = disk number ;BX = track offset ;DX = disk size ADDDISK: MOV SI,HDPB ;SI points to DPB copy CMP AL,12 JNZ ADD0 MOV SI,MDPB MOV BX,0 ADD0: CMP AL,16 ;Only allow 16 disks JNC ADD1 MOV OFF[SI],BX ;Set track offset MOV BL,AL SUB BH,BH MOV CL,BSH[SI] ;Compute DSM SUB CL,3 MOV AX,DX SHR AX,CL DEC AX MOV DSM[SI],AX MOV CL,BSH[SI] ;Compute EXM CMP AH,1 ADC CL,-4 MOV AL,1 SHL AL,CL DEC AL MOV EXM[SI],AL MOV DI,TRKBUFPT ;Get end of bios. MOV ALV[SI],DI ;Set ALV MOV AX,DSM[SI] ;and reserve space SLR AX,3 INC AX ADD DI,AX MOV DPB[SI],DI ;Set DPB pointer MOV AX,DIRBUFPT MOV DIR[SI],AX ;And DIR pointer MOV CX,DPBLEN+DPHLEN ;Copy DPH REP MOVSB MOV TRKBUFPT,DI ;Mark new end of bios. ADD BX,BX SUB DI,DPHLEN MOV DPHS[BX],DI ;Set DPH pointer ADD1: RET MDPB EQU OFFSET $ DW 16 DB 4 DB 15 DB 0 DW 0 DW 63 DB 80H DB 0 DW 0 DW 0 MDPH EQU OFFSET $ DW 0,0,0,0,0,0,0,0 DW 0,128 DB 0,12 HDPB EQU OFFSET $ DW 68 DB 5 DB 31 DB 0 DW 0 DW 511 DB 0F0H DB 0 DW 0 DW 0 DW 0,0,0,0,0,0,0,0 DW 1001H,512 DB 91H,4 DISKTABLES: ;8 SD SS DW 800H DW XLT26 DW 128 DW 26 DB 8 DW 64 DB 0 DW 2 TYPELEN EQU OFFSET $ - OFFSET DISKTABLES ;8 SDD SS DW 0A03H DW XLT9 DW 1024 DW 9 DB 2 DW 128 DB 1 DW 2 ;8 DD SS DW 0A02H DW XLT16 DW 512 DW 16 DB 4 DW 128 DB 1 DW 2 ;8 SDD DS DW 0A07H DW NOXLT DW 1024 DW 9 DB 2 DW 256 DB 1 DW 1 ;8 SD DS DW 804H DW XLT26 DW 128 DW 26  DB 16 DW 128 DB 0 DW 4 ;8 DD DS DW 0A06H DW XLT16 DW 512 DW 16 DB 4 DW 256 DB 1 DW 4 ;5 SD SS DW 901H DW XLT10 DW 256 DW 10 DB 8 DW 64 DB 0 DW 3 ;5 DD SS DW 0B02H DW NOXLT DW 512 DW 8 DB 2 DW 64 DB 0 DW 1 IBMDS EQU OFFSET $ ;5 DD DS DW 0B06H DW NOXLT DW 512 DW 8 DB 4 DW 64 DB 0 DW 1 ;5 SDD SS DW 0B03H DW NOXLT DW 1024 DW 5 DB 2 DW 64 DB 0 DW 1 ;5 SDD DS DW 0B07H DW NOXLT DW 1024 DW 5 DB 2 DW 128 DB 1 DW 1 ;5 SD DS DW 905H DW XLT10 DW 256 DW 10 DB 8 DW 64 DB 0 DW 1 ;Hard disk DW 1002H DW NOXLT DW 512 DW 17 DB 8 DW 512 DB 3 DW 1 NUMTYPES EQU (OFFSET $ - OFFSET DISKTABLES) / TYPELEN XLT26 EQU OFFSET $ DB 0,6,12,18,24,4,10,16,22,2,8,14,20 DB 1,7,13,19,25,5,11,17,23,3,9,15,21 XLT10 EQU OFFSET $ DB 0,2,4,6,8,1,3,5,7,9 XLT16 EQU OFFSET $ DB 0,4,8,12,1,5,9,13,2,6,10,14,3,7,11,15 XLT9 EQU OFFSET $ DB 0,3,6,1,4,7,2,5,8 NOXLT EQU OFFSET $ D  B 0,1,2,3,4,5,6,7,8,9,10 DB 11,12,13,14,15,16 CPMSYS DB 0,'CPM SYS' CCPMSYS DB 0,'CCPM SYS' ; UNINITIALIZE DATA AREA CCPMLD RW 1 ;Flags for CCPM load. SYSSTART RW 1 ;System starting offset. SYSDS RW 1 ;System data segment. DIRBLK RW 1 ;Directory entries per block BLOCK RW 1 ;Disk block. LOGSEC RW 1 ;Logical disk sector LDBASE RW 1 ;System segment. LDSEG RW 1 ;Segment position for system load HTRACKS RW 1 ;Number of tracks on hard disk DSKNO RB 1 ;Current disk number RW 40h STACK RB 0 DIRBUF RS 256*32 ;Buffer for directory block LDEND RB 0  START: RET DSKMEM,AX MOV AL,DSKSECTOR CMP AL,TRKSIZE JNZ REP1 INC DSKTRACK ;and track MOV AL,0 REP1: INC AL MOV DSKSECTOR,AL ;and sector. JMPS REP2 ;Then repeat REP0: POP SI POP DI RET NOLIST EJECT ;********************************************************** ;*** *** ;*** NEW 80186 CODES *** ;*** *** ;********************************************************** ;Code macro definitions for 80168 instructions which are not ;on the 8086, but may be useful for this program. ;January 16,1984 elh ; Push immediate instructions fixed. Byte & word pushes ; were mixed up. ; *** PUSH AND POP INSTRUCTIONS *** ; ================================= CODEMACRO PUSH IMM:DW DB 68H DW IMM ENDM CODEMACRO PUSH IMM:DB DB 6AH DB IMM ENDM CODEMACRO PUSHA DB 60H ENDM CODEMACRO POPA DB 61H ENDM ; *** MULTIPLY *** ; ================ CODEMACRO IMUL DST:RW,SRC:EW,IMM:DW DB 69H MODRM DST,SRC DW IMM ENDM CODEMACRO IMUL DST:RW,SRC:EW,IMM:DB DB 6BH MODRM DST,SRC DB IMM ENDM ; *** SHIFT BY COUNT INSTRUCTIONS *** ; =================================== CODEMACRO ROL DST:EB,COUNT:DB DB 0C0H MODRM 0,DST DB COUNT ENDM CODEMACRO ROR DST:EB,COUNT:DB DB 0C0H MODRM 1,DST DB COUNT ENDM CODEMACRO RCL DST:EB,COUNT:DB DB 0C0H MODRM 2,DST DB COUNT ENDM CODEMACRO RCR DST:EB,COUNT:DB DB 0C0H MODRM 3,DST DB COUNT ENDM CODEMACRO SLL DST:EB,COUNT:DB DB 0C0H MODRM 4,DST DB COUNT ENDM ;Assembler uses SHR and SHL as operators, and so does ;not allow them as code macro instructions. Use SLR ;and SLL (Shift Logical Right or Left) CODEMACRO SLR DST:EB,COUNT:DB DB 0C0H MODRM 5,DST DB COUNT ENDM CODEMACRO SAL DST:EB,COUNT:DB DB 0C0H MODRM 4,DST DB COUNT ENDM CODEMACRO SAR DST:EB,COUNT:DB DB 0C0H MODRM 7,DST DB COUNT ENDM CODEMACRO ROL DST:EW,COUNT:DB DB 0C1H MODRM 0,DST DB COUNT ENDM CODEMACRO ROR DST:EW,COUNT:DB DB 0C1H MODRM 1,DST DB COUNT ENDM CODEMACRO RCL DST:EW,COUNT:DB DB 0C1H MODRM 2,DST DB COUNT ENDM CODEMACRO RCR DST:EW,COUNT:DB DB 0C1H MODRM 3,DST DB COUNT ENDM CODEMACRO SLL DST:EW,COUNT:DB DB 0C1H MODRM 4,DST DB COUNT ENDM CODEMACRO SLR DST:EW,COUNT:DB DB 0C1H MODRM 5,DST DB COUNT ENDM CODEMACRO SAL DST:EW,COUNT:DB DB 0C1H MODRM 4,DST DB COUNT ENDM CODEMACRO SAR DST:EW,COUNT:DB DB 0C1H MODRM 7,DST DB COUNT ENDM ; *** MONITOR ROUTINES *** ; ------------------------ CODEMACRO MON FCODE:DB DB 0B3H DB FCODE ;MOV BL,FCODE DB 0CDH DB 3BH ;INT 59 ENDM SETENT EQU 0 CONST EQU 1 CONIN EQU 2 CONOUT EQU 3 DUBIN EQU 4 DUBOUT EQU 5 LSTSPOOL EQU 6 HOME EQU 7 READ EQU 8 WRITE EQU 9 DUON EQU 10 DUOFF EQU 11 DUHIGH EQU 12 DULOW EQU 13 LSTOUT EQU 14 LSTST EQU 15 SETRESET EQU 16 DSKCHECK EQU 17 STOPSPOOL EQU 18 DOLMESS EQU 19 MESSAGE EQU 20 HEXWORD EQU 21 HEXBYTE EQU 22 DECDISP EQU 23 CLRSCR EQU 24 CRTSET EQU 25 ; *** MONITOR DISK PARAMETER LOCATIONS *** ; ---------------------------------------- ESEG ORG 84F3H DSKSEG RW 1 DSKMEM RW 1 DSKNUM RB 1 DSKTRACK RW   1 DSKSECTOR RB 1 LIST START: RET DSKMEM,AX MOV AL,DSKSECTOR CMP AL,TRKSIZE JNZ REP1 INC DSKTRACK ;and track MOV AL,0 REP1: INC AL MOV DSKSECTOR,AL ;and sector. JMPS REP2 ;Then repeat REP0: POP SI POP DI RET  ;********************************************************** ;********************************************************** ;********************************************************** ;*** *** ;*** *** ;*** SLICER DEBUGGER I.3 *** ;*** =================== *** ;*** *** ;*** *** ;********************************************************** ;********************************************************** ; *** INITIALIZATION *** ; ====================== MONINIT: MOV AX,CS MOV DS,AX MOV ES,AX MOV SS,AX MOV SP,OFFSET STACK STI CALL MESSAGE DB CR,LF,LF,LF,'SLICER Monitor I.3 October 28, 1983',CR,LF,' ',0 MOV AX,MEMSIZE CALL DECDISP CALL MESSAGE DB 'K RAM installed',0 JMP MONITOR EJECT ;********************************************************** ;*** *** ;*** MONITOR SUBROUTINE *** ;*** *** ;********************************************************** ; *** OUTPUT ROUTINES *** ; ======================= ;Output CR, LF combination to console CRLF: PUSH AX MOV AL,CR CALL CONOUT MOV AL,LF CALL CONOUT POP AX RET ;Output a space to the console SPACE: PUSH AX MOV AL,' ' CALL CONOUT POP AX RET ;Erase a character on the console BACKSP: PUSH AX MOV AL,BS CALL CONOUT CALL SPACE CALL CONOUT POP AX RET ;Display register name on console. ; AX contains register name, two bytes. ; A space is added. ;In REGOUT0, BX points to register save area REGOUT0: MOV AX,OFFSET REGNAMES-OFFSET AXSAVE[BX] REGOUT: PUSH AX CALL CONOUT MOV AL,AH CALL CONOUT CALL SPACE POP AX RET REGNAMES: DB 'AXBXCXDXBPSIDISPCSDSSSESIPF ' ;Get users register value. ;IN: AX=Register name ;OUT: BX=Pointer to register value. REGVALUE: PUSH CX MOV CX,14 MOV BX,OFFSET REGNAMES REG0: CMP AX,[BX] JZ REG1 ADD BX,2 LOOP REG0 STC JMPS REG2 REG1: ADD BX,OFFSET AXSAVE-OFFSET REGNAMES REG2: POP CX RET ;Print header for register display REGHEAD: CALL CRLF PUSH BX PUSH CX MOV CX,14 ;Number of registers MOV BX,OFFSET REGNAMES ;Names REG4: CALL SPACE ;Get name MOV AX,[BX] CALL REGOUT ;Print it. CALL SPACE ADD BX,2 LOOP REG4 ;And loop. POP CX POP BX RET ;Print register values. REGDISP: CALL CRLF PUSH BX PUSH CX MOV CX,14 ;Number of registers. MOV BX,OFFSET AXSAVE REG5: MOV AX,[BX] ;Display values. CALL HEXWORD CALL SPACE ADD BX,2 LOOP REG5 POP CX POP BX RET EJECT ; *** CONSOLE INPUT *** ; ===================== ;Check for user break ; If no character ready return AL=0,Z,NC ; If control-S then wait for another character ; If control-C then return AL=3,Z,C ; Otherwise return AL=ASCII,NZ,NC CNTLCHK: CALL CONST JZ CNT2 CALL CONIN CMP AL,CNTL+'S' ;Control S JNZ CNT0 CALL CONIN CNT0: CMP AL,CNTL+'C' ;Control-C JC CNT1 JNZ CNT2 AND BITS,NOT INLINE CNT1: CMC CNT2: RET ;Input a line of text from console. BS may be used   for ;editing. CR marks the end of the line. Other control ;characters are not allowed. Characters typed pass the ;Maximum line width are ignored. ;IN: CX=Max length (must be less than LEN LINBUF) ;OUT: CX=Length (including CR) ; SI=Pointer to start of line. ;Any routine that takes characters from input can assume ;that SI points to the next character. These routines ;must update SI after using an input character. LININ: AND BITS,NOT INLINE PUSH AX PUSH BX PUSH DI MOV DI,OFFSET LINBUF ;Set DI and SI MOV SI,DI ;to the start of the input ;buffer. MOV BX,CX ;BX holds max length ;CX holds current length LIN0: CALL CONIN CMP AL,BS ;Check for BS. JNZ LIN2 CMP CX,BX ;Empty line? JNZ LIN4 LIN1: MOV AL,7 ;If so, ignore it CALL CONOUT JMPS LIN0 LIN2: CMP AL,CR ;Check for end of line. JZ LIN3 CMP AL,' ' ;Ignore other controls JC LIN1 CALL CONOUT ;Echo character. LIN3: STOSB ;Put it in buffer LOOPNZ LIN0 JZ LIN5 ;Exit because of CR? MOV AL,7 ;If not, line too long CALL CONOUT LIN4: DEC DI ;Erase a character INC CX CALL BACKSP JMPS LIN0 LIN5: CALL CRLF ;All done SUB BX,CX ;Compute length MOV CX,BX POP DI POP BX POP AX RET EJECT ; *** INPUT PROCESSING *** ; ======================== ;These routines aid in the processing of the command line. ;SI always points to the next character to be processed. ;Registers which do not hold return values are saved. ;Syntax errors in the command line are flagged by setting ;C. ;Convert possible lower case in AL to upper case. UCONVERT: CMP AL,'a' JC UCON0 CMP AL,'z' JA UCON0 SUB AL,20H UCON0: RET ;Convert hex character in AL to binary. HEXCHR: CALL UCONVERT SUB AL,'0' JC HEX1 CMP AL,10 JC HEX0 SUB AL,7 CMP AL,10 JC HEX1 CMP AL,16 HEX0: CMC HEX1: RET ;Convert ascii hex string to binary. If string contains more ;than four digits then only the lowest four are used. String ;ends with comma or CR. Non-hex characters cause errors. ;(/// MAY WANT TO ALLOW SPACES) ;IN: AX=Default value ;OUT: AX=Conversion result HEXSTRING: PUSH BX PUSH DX MOV DX,AX ;Move default MOV BX,0 ;Start with 0 HEX4: SLL BX,4 LODSB ;Get next char in string CMP AL,',' ;End of string? JZ HEX6 CMP AL,CR JZ HEX5 CMP AL,' ' JZ HEX5 CALL HEXCHR ;Convert char JC HEX6 ADD BL,AL ;Move char into result MOV DX,BX JMPS HEX4 HEX5: DEC SI ;Do not swallow CR or space HEX6: MOV AX,DX POP DX POP BX RET ;Address strings are in the form SEGMENT:OFFSET where ;SEGMENT and OFFSET are 16 bit hex strings ;SEGMENT can be a segment register. ;IN: AX=Default offset ; BX=Default segment ;OUT: AX=Offset ; BX=Segment ADRSTRING: PUSH DX MOV DX,AX ;Save default offset CMP WORD PTR 1[SI],':S' ;Segment override. JNZ ADR2 LODSW CALL REGVALUE JC ADR4 MOV BX,[BX] INC SI JMPS ADR3 ADR2: CALL HEXSTRING ;Maybe, get value JNC ADR4 CMP BYTE PTR (-1)[SI],':' ;Then check for colon STC JNZ ADR4 ;If not then error exit MOV BX,AX ADR3: MOV AX,DX CALL HEXSTRING ;Get offset ADR4: POP DX RET ;Get code address. ;OUT: AX=Offset ; BX=Offset (same as AX) ; DX=Segment CODESTRING: MOV AX,IPSAVE MOV BX,CSSAVE JMPS DAT0 ;Get address in data segment, defaults in MEM1,DSSAVE ;OUT: AX=Offset ; BX=Offset (same as AX) ; DX=Segment DATASTRING: MOV AX,MEM1 MOV BX,DSSAVE DAT0: CALL ADRSTRING MOV DX,BX MOV BX,AX RET ;Pull a break point out of the input. ;IN: DS:[DI]=Break point area ;OUT: AX=Messed up ; BX=Offset ; DX=Segment ;Break point area is updated to show that the break point ;is active. The break point area consists of 6 bytes. ;0: ACTIVE If bit 7 is set the break point is set. ;1: OP CODE Op code that the break is replacing. ;2,3: OFFSET ;4,5: SEGMENT BRKSTRING: MOV AL,[SI] CMP AL,CR JZ BRK0 ;If CR then no break. CMP AL,' ' JZ BRK0 INC SI CMP AL,',' JZ BRK0 ;If , don't set break CMP AL,'.' JZ BRK2 ;  If . use defaults DEC SI ;Otherwise break in input BRK2: MOV AX,2[DI] MOV BX,CSSAVE CALL DAT0 ;Get break points from input. JC BRK0 MOV 2[DI],BX ;Store them. MOV 4[DI],DX MOV BYTE PTR [DI],80H ;Activate break. CALL GETDXBX MOV 1[DI],AL MOV AL,BRKCODE CALL PUTDXBX BRK0: RET ;Get parameters for disk operation. ;Get number of sectors, SECCNT, and sectors per ;track, TRKSIZE. Default for seccnt is 1. ;IN: NONE ;OUT: AX=TRKSIZE=Sectors/track ; SECCNT=Number of sectors.  DSKSTRING: MOV AL,1 ;Number of sectors CALL HEXSTRING JC DSK6 MOV SECCNT,AL MOV AL,TRKSIZE ;Sectors/track. CALL HEXSTRING JC DSK6 MOV TRKSIZE,AL DSK6: RET ;Get parameters for a from/to pair in the data segement ;(Ex. D(ump) from,to) ;IN: CX=Default length ;OUT: AX=To offset ; BX=From offset ; CX=Length (AX-BX) ; DX=Segment ; MEM3=To offset ; SEG1=Segment FROMTO: CALL DATASTRING JC FRM1 ADD AX,CX JNC FRM0 MOV AX,-1 FRM0: CALL HEXSTRING JC FRM1 MOV CX,AX SUB CX,BX JC FRM1 MOV MEM3,AX MOV SEG1,DX FRM1: RET ;Get from/to/with parameters. (Ex. C(ompare) from,to,with). ;From and with may be in different segments ;IN: CX=Default length ;OUT: AX=With offset ; BX=From offset ; CX=Length ; DX=With segment ; MEM1=From offset ; MEM3=To offset ; SEG1=From segment ; SEG3=With segment FRMTOTO: CALL FROMTO JC FRM2 MOV MEM1,BX MOV AX,MEM2 MOV BX,ESSAVE CALL ADRSTRING JC FRM2 MOV SEG2,BX MOV BX,MEM1 FRM2: RET EJECT  ; OTHER USEFUL SUBROUTINES ; ------------------------ ;Pretend that DX is a segment register GETDXBX: PUSH DS MOV DS,DX MOV AL,[BX] POP DS RET PUTDXBX: PUSH DS MOV DS,DX MOV [BX],AL POP DS RET ;Dump the next CX bytes at BX to the console in ascii. ;Convert controls and negatives to periods. ASCDMP: PUSH AX PUSH BX PUSH CX ASC0: MOV AL,[BX] CMP AL,' ' JC ASC1 OR AL,AL JNS ASC2 ASC1: MOV AL,'.' ASC2: CALL CONOUT INC BX LOOP ASC0 POP CX POP BX POP AX RET ;Dump the next CX bytes at BX to the console in hex. HEXDMP: PUSH AX PUSH BX PUSH CX HEX3: MOV AL,[BX] INC BX CALL HEXBYTE CALL SPACE LOOP HEX3 POP CX POP BX POP AX RET ;Execute user program. ;STEP does one step, GO goes until break. STEP: MOV VSS+2,CS ;Set single step vector MOV VSS,OFFSET RETURN OR FSAVE,100H ;and trace flag. GO: MOV VBRK+2,CS ;Set up break vector. MOV VBRK,OFFSET RETURN PUSHF ;Save my registers. PUSHA MOV MONSP,SP MOV SS,SSSAVE MOV SP,SPSAVE PUSH FSAVE PUSH CSSAVE PUSH IPSAVE PUSH DSSAVE MOV AX,AXSAVE ;Set user registers. MOV BX,BXSAVE MOV CX,CXSAVE MOV DX,DXSAVE MOV BP,BPSAVE MOV SI,SISAVE MOV DI,DISAVE MOV ES,ESSAVE POP DS IRET ;Return from user program. BOMB is for unexpected returns. BOMB: STC JMPS RET1 RETURN: CLC RET1: MOV CS:DSSAVE,DS MOV CS:AXSAVE,AX MOV AX,CS ;Set my DS. MOV DS,AX MOV BXSAVE,BX ;Save users registers MOV CXSAVE,CX MOV DXSAVE,DX MOV BPSAVE,BP MOV SISAVE,SI MOV DISAVE,DI MOV SSSAVE,SS MOV ESSAVE,ES POP IPSAVE POP CSSAVE POP FSAVE MOV SPSAVE,SP MOV AX,DS ;Set my segments MOV ES,AX MOV SS,AX JC RET2 MOV SP,MONSP ;And stack POPA ;And registers POPF RET RET2: MOV SP,OFFSET STACK ;Program bombed. CALL MESSAGE DB CR,LF,'Welcome to the Error Recovery Routine (Or Rats!)',0 JMP MONINIT EJECT ; *** COMMAND FLOW CONTROL *** ; ============================ ;Get command from command line and branch to proper routine. ;Pointer to branch table is at TOS. Grab a character from the ;command line, locate it in the table, and jump to the ;corresponding routine (note that its a jump, not a call). ;A 0 at the end of the table will catch everything that ;falls through. BRANCH: POP AX ;Get table pointer PUSH BX MOV BX,AX LODSB ;Get command letter. CALL UCONVERT BR0: MOV AH,[BX] ;Search. INC BX CMP AL,AH ;Found it? JZ BR1 CMP AH,0 JZ BR1 ;End of table? INC BX    INC BX JMPS BR0 BR1: MOV AX,[BX] ;Get routine. POP BX JMP AX ;A macro to help build branch tables. CODEMACRO BNCH BITE:DB,ROUTINE:CW DB BITE DW ROUTINE ENDM ; BRANCH TABLES ; ------------- ;Branch on first letter of command. MAINBRANCH: CALL BRANCH BNCH 'D',DBRANCH BNCH 'S',SBRANCH BNCH 'X',EXAMINE BNCH 'G',GOTO BNCH 'F',FILL BNCH 'M',MBRANCH BNCH 'R',RBRANCH BNCH 'C',COMPARE BNCH 'H',HEXMATH BNCH 'I',IBRANCH BNCH 'O',OUTPUT BNCH 'P',PUTTEXT BNCH 'B',BOOT BNCH 'T',TRACE BNCH 'U',UNTRACE BNCH 'W',WAIT BNCH 'Z',SLEEP BNCH ' ',MAINBRANCH BNCH ',',MAINBRANCH BNCH '&',REPEAT BNCH CR,ROMRET BNCH 0,WHAT ;These branch on second letter of command. DBRANCH: CALL BRANCH BNCH 'Q',DMPASC BNCH 'I',DMPIO BNCH 'M',DSKMEMORY BNCH 'N',SETDSKNUM BNCH 'T',SETDSKTRK BNCH 'S',SETDSKSEC BNCH 'R',DSKREAD BNCH 'W',DSKWRITE BNCH 'P',DSKPARAMS BNCH 'Z',DSKZERO BNCH '?',DISKSET BNCH 0,DMPHEX SBRANCH: CALL BRANCH BNCH 'M',SRCHBYTE BNCH 'W',SRCHWORD BNCH 'S',SHOWSEGS BNCH 0,SUBSTITUTE RBRANCH: CALL BRANCH BNCH 'M',REVMOVE BNCH 0,WHAT MBRANCH: CALL BRANCH BNCH 'T',MEMTEST BNCH 0,MOVE IBRANCH: CALL BRANCH BNCH 'S',SILENTIP BNCH 0,INPUT EJECT ;********************************************************** ;*** *** ;*** MONITOR COMMAND ROUTINES *** ;*** *** ;********************************************************** ;These routines save all registers except AX (which was destroyed ;by BRANCH anyway), and SI which is left pointing to the end of ;the command line, or after the character which caused an error. ;Since these routines are close to the top level, it is probably ;not necessary to save registers (although it is nice). ;Hex dump command ; Df,t ;Display memory from f to t. DMPHEX: DEC SI ;Back up one character PUSH BX PUSH CX PUSH DX MOV CX,319 ;Defalut is 320 bytes CALL FROMTO JC DMP3 PUSH DS MOV DS,DX ;Segment to DS. MOV DX,CX ;Length in DX. DMP0: MOV AX,BX ;Compute length of line AND AL,0F0H ;Line ends at the next ADD AX,10H ;multiple of 10H, SUB AX,BX MOV CX,AX MOV AX,DX ;or at DX. INC AX JZ DMP1 CMP AX,CX ;Whichever is less JNC DMP1 XCHG AX,CX DMP1: CALL CRLF MOV AX,BX CALL HEXWORD CALL SPACE CALL HEXDMP ;Have start in BX, CALL ASCDMP ;and length in CX. ADD BX,CX ;New starting point. SUB DX,CX JC DMP2 CALL CNTLCHK JNC DMP0 DMP2: POP DS JMP EXIT2 DMP3: JMP SAYWHAT ;ASCII dump routine ;DQf,t DMPASC: PUSH BX PUSH CX PUSH DX MOV CX,1279 ;Default is 1280 chars. CALL FROMTO JC DMP3 PUSH DS MOV DS,DX ;Data segment to DS. MOV DX,CX ;Length to DX DMP4: MOV CX,64 ;Length is either 64, MOV AX,DX ;or all the rest. INC AX JZ DMP5 CMP AX,CX ;Whichever is less JNC DMP5 XCHG AX,CX DMP5: CALL CRLF MOV AX,BX CALL HEXWORD CALL SPACE CALL ASCDMP ADD BX,CX ;New start SUB DX,CX JC DMP2 CALL CNTLCHK JC DMP2 JNC DMP4 ;Substitute memory values ;Sf,v1,v2,...,vn ;This command may extend over several lines. Replace ;one of the v's with a period to exit SUBSTITUTE: DEC SI ;Back up one character PUSH BX PUSH CX PUSH DX CALL DATASTRING ;Get memory location JC SUB3 CMP BYTE PTR [SI],' ' JA SUB1 MOV MEM1,BX MOV SEG1,DX SUB0: MOV AX,BX ;Start another line CALL HEXWORD ;Display current location. CALL SPACE CALL GETDXBX CALL HEXBYTE ;Display old value CALL SPACE MOV CX,64  CALL LININ ;Get new line SUB1: CMP BYTE PTR [SI],'.' ;Time to quit? JZ SUB2 CALL GETDXBX ;Get old value, and CALL HEXSTRING ;use as default JC SUB3 CALL PUTDXBX INC BX MOV MEM1,BX CMP BYTE PTR [SI],' ' ;End of line? JNA SUB0 JNZ SUB1 SUB2: JMP EXIT3 SUB3: JMP SAYWHAT ;Put ascii into memory ; Pf,text PUTTEXT: PUSH BX PUSH CX PUSH DX CALL DATASTRING JC PUT2 PUSH DI PUSH ES MOV DI,BX ;Set up destination MOV ES,DX ;Source already set PUT0: CMP BYTE PTR   [SI],CR ;(command line) JZ PUT1 MOVSB ;Move string JMPS PUT0 PUT1: JMP EXIT1 PUT2: JMP SAYWHAT ;Fill memory with byte ; Ff,t,b ;Default for t is 0FFFFH (rest of segment) FILL: PUSH BX PUSH CX PUSH DX MOV CX,-1 CALL FROMTO JC FILL0 MOV AL,0 ;Get byte to fill in CALL HEXSTRING JC FILL0 PUSH DI PUSH ES MOV DI,BX MOV ES,DX STOSB REP STOSB JMP EXIT1 FILL0: JMP SAYWHAT ;Move memory ; Mf,t1,t2 ;Move memory from f to t1 to t2. f and t1 are in the same ;segment, t2 may be in a different segment ; RMf,t1,t2 ;does the move from the top down. This may be needed to avoid ;destroying data during the move. It may also be used to ;repeat a pattern in memory. REVMOVE: PUSH BX PUSH CX PUSH DX MOV CX,-1 CALL FRMTOTO JC MOV1 STD ;Reverse direction ADD BX,CX ;Adjust pointers ADD AX,CX JMPS MOV0 MOVE: DEC SI PUSH BX PUSH CX PUSH DX MOV CX,-1 CALL FRMTOTO JC MOV1 MOV0: PUSH DI ;Set registers to PUSH ES ;use string instructions PUSH SI PUSH DS MOV DI,AX MOV ES,SEG2 MOV SI,BX MOV DS,SEG1 MOVSB REP MOVSB ;Move them JMP EXIT0 MOV1: JMP SAYWHAT ;Compare two memory areas. ; Cf,t1,t2 COMPARE: PUSH BX PUSH CX PUSH DX MOV CX,-1 CALL FRMTOTO JC CMP2 PUSH DI ;Set up registers for PUSH ES ;String compare PUSH SI PUSH DS MOV DI,AX MOV ES,SEG2 MOV SI,BX MOV DS,SEG1 CMPSB JNZ CMP3 CMP0: REPZ CMPSB ;Do string compare JZ CMP1 ;CX=0 means all done CMP3: CALL CRLF MOV AX,SI ;Otherwise show error DEC AX CALL HEXWORD CALL SPACE MOV AL,(-1)[SI] CALL HEXBYTE CALL SPACE MOV AL,ES:(-1)[DI] CALL HEXBYTE CALL SPACE MOV AX,DI DEC AX CALL HEXWORD POP DS CALL CNTLCHK PUSH DS MOV DS,SEG1 JNC CMP0 CMP1: JMP EXIT0 CMP2: JMP SAYWHAT ;Input command, displays input data ; Ip INPUT: DEC SI CALL CRLF PUSH BX PUSH CX PUSH DX MOV AX,PORT1 CALL HEXSTRING JC INP0 CALL HEXWORD CALL SPACE MOV DX,AX IN AX,DX  CALL HEXWORD JMP EXIT4 INP0: JMP SAYWHAT ;Silent input, does not display data ; ISp SILENTIP: PUSH BX PUSH CX PUSH DX MOV AX,PORT1 ;Get default value CALL HEXSTRING JC SIP0 MOV DX,AX IN AX,DX JMP EXIT4 SIP0: JMP SAYWHAT ;Output ; Op,w OUTPUT: PUSH BX PUSH CX PUSH DX MOV AX,PORT1 ;Get port CALL HEXSTRING JC OUT0 MOV DX,AX MOV AX,WORD1 ;Get word CALL HEXSTRING JC OUT0 MOV WORD1,AX OUT DX,AX JMP EXIT4 OUT0: JMP SAYWHAT ;Wait, gives a delay of n milliseconds ; Wn WAIT: PUSH BX PUSH CX PUSH DX MOV AX,1 CALL HEXSTRING JC WT0 DEC AX JZ WT1 WTLP1: PUSH AX MOV AX,494 WTLP2: DEC AX JNZ WTLP2 POP AX DEC AX JNZ WTLP1 WT1: PUSH AX MOV AX,120 ;Fill up routine overhead WTLP3: DEC AX ; to make up the last millisec JNZ WTLP3 POP AX JMP EXIT3 WT0: JMP SAYWHAT ;Hexmath ; Hw1,w2 HEXMATH: CALL CRLF PUSH BX PUSH CX PUSH DX XOR AX,AX CALL HEXSTRING ;Get first operand JC HEX7 MOV BX,AX XOR AX,AX CALL HEXSTRING ;Get second operand JC HEX7 XCHG AX,BX MOV WORD1,AX MOV WORD2,BX ADD AX,BX CALL HEXWORD ;Display sum MOV AL,'+' CALL CONOUT CALL SPACE MOV AX,WORD1 SUB AX,BX CALL HEXWORD ;Display difference MOV AL,'-' CALL CONOUT JMP EXIT3 HEX7: JMP SAYWHAT ;Examine and modify registers ;Xr ;X ;First form is examine & modify register ;Second is examine all. EXAMINE: PUSH BX PUSH CX PUSH DX LODSW CMP AL,'F' ;Have name in AX JNZ EXM0 MOV AH,' ' ;Only one letter for flags EXM0: CALL REGVALUE JC EXM2 ;Did not find it. EXM1: CALL CRLF EXM6: CALL REGOUT0 ;Display register name. MOV AX,[BX] CALL HEXWORD ;And value. CALL SPACE MOV CX,60 CALL LININ ;Get new value CMP BYTE PTR [SI],'.' JZ EXM4 CALL HEXSTRING JC EXM5 MOV [BX],AX ;And put it. ADD BX,2 CMP BX,OFFSET FSAVE JBE EXM6 JMPS EXM4 EXM2: SUB SI,2 CALL REGHEAD CALL REGDISP EXM4: JMP EXIT3 EXM5: JMP SAYWHAT ;Goto with breaks ;Gg,b  1,b2 GOTO: PUSH BX PUSH CX PUSH DX CALL CODESTRING ;Get goto address JC GT4 MOV IPSAVE,AX ;Put into user registers MOV CSSAVE,DX PUSH DI MOV DI, OFFSET BREAK1 MOV CX,2 GT0: CALL BRKSTRING ;Get break points JC GT1 ADD DI,6 LOOP GT0 GT1: POP DI JC GT4 AND FSAVE,NOT 100H ;Shut off single step CALL GO ;And go. DEC IPSAVE PUSH DI MOV CX,2 MOV DI,OFFSET BREAK2 GT2: TEST BYTE PTR [DI],80H ;Remove breaks JZ GT3 MOV AL,1[DI] MOV BX,2[DI] MOV DX,4[DI] CALL PUTDXBX MOV BYTE PTR [DI],0 GT3: SUB DI,6 LOOP GT2 POP DI JMP EXIT3 GT4: JMP SAYWHAT ;Untrace ;Uw ;Execute w steps, instructions which modify segment ;registers are not counted. UNTRACE: PUSH BX PUSH CX PUSH DX MOV AX,1 CALL HEXSTRING ;Get number. JC UN0 MOV CX,AX UN1: CALL STEP ;Do step. LOOP UN1 JMP EXIT3 UN0: JMP SAYWHAT ;Trace ;Tw ;Execute W steps, display registers after each step. ;A check is made for control-C or control-S after ;each step. ;Instructions which modify the segment registers are not ;counted as steps. TRACE: PUSH BX PUSH CX PUSH DX MOV AX,1 CALL HEXSTRING ;Get step count. JC TR0 MOV CX,AX CALL REGHEAD ;Print header. TR1: CALL STEP ;Do step. CALL REGDISP ;Display registers CALL CNTLCHK ;Check for exit or stop. JC TR2 LOOP TR1 TR2: JMP EXIT3 TR0: JMP SAYWHAT ;Set memory area for disk transfers. ;DMs:m DSKMEMORY: PUSH BX PUSH CX PUSH DX MOV AX,DSKMEM MOV BX,DSKSEG CALL DAT0  JC DSK5 MOV DSKSEG,DX MOV DSKMEM,AX JMP EXIT3 DSK5: JMP SAYWHAT ;Set sector for disk transfers. ;DSs SETDSKSEC: CMP WORD PTR [SI],':S' JNZ DS0 JMP DMPHEX DS0: PUSH BX PUSH CX PUSH DX MOV AL,DSKSECTOR CALL HEXSTRING JC DSK5 MOV DSKSECTOR,AL JMP EXIT3 ;Set drive number for disk transfer. ;DNn SETDSKNUM: PUSH BX PUSH CX PUSH DX MOV AL,DSKNUM CALL HEXSTRING JC DSK5 MOV DSKNUM,AL JMP EXIT3 ;Set track for disk transfer. ;DTn SETDSKTRK: PUSH BX PUSH CX PUSH DX MOV AX,DSKTRACK CALL HEXSTRING JC DSK5 MOV DSKTRACK,AX JMP EXIT3 ;Display current disk parameters. ;DP DSKPARAMS: PUSH BX PUSH CX PUSH DX CALL MESSAGE DB CR,LF,LF,' DISK PARAMETERS' DB CR,LF,LF,'MEMORY (DM) ',0 MOV AX,DSKSEG CALL HEXWORD MOV AL,':' CALL CONOUT MOV AX,DSKMEM CALL HEXWORD CALL MESSAGE DB CR,LF,'LOGICAL DISK (DN) ',0 MOV AL,DSKNUM CALL HEXBYTE CALL MESSAGE DB CR,LF,'TRACK (DT) ',0 MOV AX,DSKTRACK CALL HEXWORD CALL MESSAGE DB CR,LF,'LOGICAL SECTOR (DS) ',0 MOV AL,DSKSECTOR CALL HEXBYTE CALL MESSAGE DB CR,LF,'DISK BLOCK (D?) ',0 CALL LOCBLOCK JC DSK10 MOV AX,BX CALL HEXWORD DSK10: JMP EXIT3 ;Determine disk type. DISKSET: PUSH BX PUSH CX PUSH DX PUSH DI CALL DSKCHECK JZ DSK16 CALL SELERR DSK16: POP DI JMP EXIT3 ;Zero disk. ;Set lsttrk so that drive looks uncalibrated. ;DZ DSKZERO: PUSH BX PUSH CX PUSH DX PUSH DI CALL HOME POP DI JC DSK12 ;Disk exists? JMP EXIT3 DSK12: JMP DSK7 ;Boot DOS. ;B OLDBOOT: PUSH BX PUSH CX PUSH DX PUSH DI MOV DSKSEG,4F8H MOV DSKMEM,0 MOV DSKTRACK,0 MOV DSKNUM,0 CALL LOCBLOCK JC DSK12 MOV WORD PTR LSTTRK[BX],-1 PUSH WORD PTR TYPEPTR[BX] PUSH DISKTABLE+2 MOV TYPEPTR[BX],OFFSET BOOTTYPE MOV DISKTABLE+2,OFFSET BOOTXLATE CALL BOOT1 JNZ BOOT2 INC DSKTRACK MOV DSKMEM,26*128 CALL BOOT1 BOOT2: POP DISKTABLE+2 POP WORD PTR TYPEPTR[BX] POP DI MOV SIDE[BX],0 JNZ DSK9 JMPF OLDLOADER BOOT1: CALL DISKREAD TEST AL,10001001B JNZ BOOT3 CALL DMACHECK BOOT3: RET BOOTXLATE: MOV CX,801H RET BOOTTYPE: DB FLOPPY,0BH DW 26*128,6,0,0A240H,1680H ;Read disk sector. ;DRb1,b2 ;Read b1 sectors from disk, assume b2 sectors per track. DSKREAD: PUSH BX PUSH CX PUSH DX CALL DSKSTRING JC DSK11 CALL REPREAD JZ DSK8 DSK9: CALL DSKERR DSK8: JMP EXIT3 DSK7: CALL MESSAGE DB CR,LF,'BAD DISK SELECT',0    JMPS DSK8 DSK11: JMP SAYWHAT ;Write to disk. ;DWb1,b2 ;Write b1 setors to the disk, assume b2 sectors per track. DSKWRITE: PUSH BX PUSH CX PUSH DX CALL DSKSTRING JC DSK11 CALL REPWRITE JZ DSK8 JNZ DSK9 BOOT: CMP BYTE PTR [SI],'O' ;Check for old boot JNZ BOOT4 JMP OLDBOOT BOOT4: MOV AL,0 CALL HEXSTRING COLDBOOT: PUSH BX ;Save registers PUSH CX PUSH DX JC BERR6 PUSH DI PUSH SI MOV DSKNUM,AL CALL DSKCHECK ;Determine disk type JNZ BERR0 MOV DSKSEG,SEG LOADER ;Set disk parameters MOV DSKMEM,OFFSET LOADER MOV DSKTRACK,0 MOV DSKSECTOR,1 CALL READ ;to read first sector JNZ BERR1 MOV DI,8803H ;Check for SLICER disk MOV SI,OFFSET SLITEXT MOV CX,6 REP CMPSB JNZ BERR2 CALL LOADER ;Go to loader. CMP AL,1 ;If return is made then JZ BCODE1 ;loader is in ROM CMP AL,-1 ;or error code is returned JNZ BERR4 ;or something else. BERR3: CALL BOOTERR JMPS BERR BERR4: CALL MESSAGE DB CR,LF,'UNRECOGNIZED RETURN CODE ',0 JMPS BERR BERR6: JMP SAYWHAT BERR0: CALL SELERR JMPS BERR BERR1: CALL DSKERR JMPS BERR BERR2: CALL MESSAGE DB CR,LF,'NOT SLICER DISK ',0 JMPS BERR BERR5: CALL DSKERR JMPS BERR BERR: POP SI POP DI JMP EXIT3 BCODE1: ADD BX,8800H MOV DSKSECTOR,0 MOV AX,BLOAD+2[BX] ;Get load address MOV DSKSEG,AX MOV AX,BLOAD[BX] MOV DSKMEM,AX MOV CX,BLOADSIZE[BX] ;Load loop BOOT7: MOV AL,DSKSECTOR ;Next sector CMP AL,BTRKSIZE[BX] ;End of track? JNZ BOOT6 INC DSKTRACK ;If so go to next track MOV AL,0 BOOT6: INC AL MOV DSKSECTOR,AL ;and sector CALL READ ;then read. JNZ BERR5 MOV AX,BSECSIZE[BX] ;update memory pointer ADD DSKMEM,AX LOOP BOOT7 CALLF DWORD PTR BJUMP[BX] ;Go to loader JMP BERR4 ;don't expect return SLITEXT DB 'SLICER' ; DISK ERRORS ; =========== ;select error SELERR: AND AL,80H JNZ DSKERR MOV AL,0F9H ;disk error, code in al DSKERR: PUSH AX CALL MESSAGE DB CR,LF,'DISK ERROR CODE ',0 DSK15: POP AX JMP HEXBYTE ;boot error, code in ah BOOTERR: MOV AL,AH POP AX CALL MESSAGE DB CR,LF,'BOOT ERROR CODE ',0 JMPS DSK15 ;Show current default segments. ;SS SHOWSEGS: CMP WORD PTR [SI],':S' JNZ SS0 JMP SUBSTITUTE SS0: PUSH BX PUSH CX PUSH DX CALL MESSAGE DB CR,LF,LF,' SEGMENTS' DB CR,LF,LF,'DATA ',0 MOV AX,DSSAVE CALL HEXWORD CALL MESSAGE DB CR,LF,'EXTRA ',0 MOV AX,ESSAVE CALL HEXWORD CALL MESSAGE DB CR,LF,'CODE ',0 MOV AX,CSSAVE CALL HEXWORD CALL MESSAGE DB CR,LF,'STACK ',0 MOV AX,SSSAVE CALL HEXWORD CALL MESSAGE DB CR,LF,'GOTO ',0 MOV AX,IPSAVE CALL HEXWORD CALL MESSAGE DB CR,LF,'IO PORT ',0 MOV AX,PORT1 CALL HEXWORD JMP EXIT3 REPEAT: CALL CNTLCHK JC REP4 MOV SI,OFFSET LINBUF REP4: RET SLEEP: CALL CONIN CMP AL,'C'-40H JNZ SLP0 AND BITS,NOT INLINE SLP0: RET ; THINGS TO DO YET ; ---------------- DMPIO: SRCHBYTE: SRCHWORD: JMP WHAT ;Exits for the monitor routines all look pretty ;much the same, so they are grouped together here. ;The beginnings of these routines also have some ;similarities, maybe these could also be combined ;to save space (some other day). EXIT0: CLD ;Set string direction MOV MEM2,SI POP DS POP SI EXIT1: MOV BX,DI POP ES POP DI EXIT2: MOV MEM1,BX EXIT3: POP DX POP CX POP BX RET EXIT4: MOV PORT1,DX JMP EXIT3 ;These are for errors SAYWHAT: POP DX POP CX POP BX WHAT: AND BITS,NOT INLINE CALL MESSAGE DB ' what?',0 RET EJECT ; **** MAIN MONITOR LOOP *** ; ========================== MONITOR: CALL CRLF MOV AL,'+' ;Monitor prompt CALL CONOUT MOV CX,78 ;Maximum line length CALL LININ OR BITS,INLINE MON0: CALL MAINBRANCH CMP BYTE PTR[SI],CR JZ MONITOR TEST BITS,INLINE JNZ MON0 JMPS MONITOR and sector. JMPS REP2 ;Then repeat REP0: POP SI POP DI RET   LIST EJECT ; PATCHES. ;This file contains fixes for known bugs. It is set up so ;that the fixes can be hand patched into the eproms. When ;making patches remember that the even and odd addresses ;must be separated. Divide the program address by two to ;get the eprom address. For example if two program lines ;to patch are ; 0B19 BF0F85 ; 0B1C 8BF7 ;then patch ; 058D 0F ; 058E 8B ;in the even eprom, and ; 058C BF ; 058D 85 ; 058E F7 ;in the odd eprom. PATCH0: ;Patch ID ORG OFFSET MONINIT+38 DB 'P' ;'A' Patches ; Patch 0 November 1,1983 ; Patch 1 November 7,1983 ; November 10,1983 ;'B' Patch ; Patch 2 December 8,1983 ;'C' Patch December 28,1983 ;'D' Patch January 13,1984 ;'E' Patches ; Patch 1 January 20,1984 ; Patch 4 January 20,1984 ;'F' Patches ; Patch 5 January 30,1984 ; Patch 6 January 31,1984 ;'G' Patches ; Patch 7 Febuary 15,1984 ; Patch 5 Febuary 20,1984 ; Patch 8 Febuary 22,1984 ;'H' Patch ; Patch 6 March 12,1984 ;'I' Patches ; Patch 9 June 6,1984 ; Patch 10 June 6,1984 ; Patch 11 June 19,1984 ;'J' Patches ; Patch 12 July 5,1984 ; Patch 7 July 5,1984 ;'K' Patch ; Patch 13 August 22,1984 ;'L' Patches ; Patch 14 September 21,1984 ; October 21,1984 ;'M' Patch ; Patch 15 October 21,1984 ; Patch 16 ;'N' Patch ; Patch 17 Febuary 13, 1985 ;'O' Patch ; Patch 18 May 14, 1985 ;'P' Patch ; Patch 19  July 9, 1985 ;Disk check for hard disk does a select but does not ;issue a command. The hard disk then does not recognize ;selects, and the monitor does not issue a command until ;another select is acknowledged. This patch adds a ;'test drive ready' command to the check routine ORG OFFSET SELWIN CALL PATCH0 ORG OFFSET PATCH0 CALL WINSEL MOV WINTASK,0 CALL CMDOUT JMP WINSTAT ;There may be problems with recovering from errors. If the ;above situation occurs as the result of an error then the ;hard disk must be reset. The monitor provides no way of ;doing this except for the output command. PATCH1: ;November 7, 1983 ;The 'test drive ready' command above is replaced with ;'recalibrate'. It works better this way, ;January 20,1984 ;Above patch 1 removed ;November 10,1983 ;In the hard disk routine WININIT, LSTTRK is written ;into the wrong place. This value is not needed for seeks ;(as with floppies), but is used to determine whether the ;disk has been initialized. This error causes the hard disk ;to be initialized before every disk operation. ;January 20,1984 ;Following patch fixed. It did not pop wintask. ;March 13,1984 ;The home function did not actually home the hard disk. ORG OFFSET WIN13-5 JMP PATCH1 ORG OFFSET PATCH1 CALL WINSEL0 JC PAT1 MOV WINTASK,1 CALL CMDOUT JC PAT1 CALL WINSTAT JC PAT1 PAT1: POP WORD PTR WINTASK POP BX JC PAT2 MOV LSTTRK[BX],0 PAT2: RET ;Timer timing is incorrect.Constant never gets set, probably ;using 65536 as time constant. This patch sets the timer for ;20ms interrupts (on 8Mhz system). PATCH2: ORG OFFSET RES2+77H CALL PATCH2 ORG OFFSET PATCH2 OUT DX,AX MOV DX,IPC+TIMER2+TIMCMD RET ;December 28,1983 ;Most SLICERs are now being sold with 6Mhz CPUs. Three 6Mhz ;wait states with IO is too long for the SASI port. Waits ;on IO changed to 2. All devices seem to work well at 8Mhz ;with this shorter wait, so two wait states look like a good ;choice for both 6 and 8Mhz SLICERs PATCH3: ORG 0FH DB 3AH ORG 16H DB 0BAH ORG OFFSET PATCH3 ;January 13,1984 ;Monitor entry interrupt gets the address of the subroutine ;to call from the ROM image of the entry vector table. It ;should be taken from RAM so these vectors may be changed. ;Without this mod the setent call (#0) won't work. ORG OFFSET MONENT+4 PUSH CS:VECTAB+JTOFF[BX] ORG OFFSET PATCH3 ;January 20,1984 ;When winsel finds that the hard disk has been initialize  d ;(with cmp instruction), carry is left set. Carry signals ;an error to the caller. A cmc fixes this. PATCH4: ORG OFFSET WIN14+10 NOP CALL PATCH4 ORG OFFSET PATCH4 CMP LSTTRK[BX],-1 CMC RET ;The direction signal is not correct when a seek is ;done right after a restore. A verify is added to the ;restore to force a short pause between the restore ;and the seek. Errors during a restore are ignored, ;format is usually unknown at this time, errors are ;common. Changing directions between two seeks ;does not seem to cause problems, but it may be something ;to keep an eye on. ;2/20/84. Instead of verify, a 20-40 ms. pause is added. ;2/22/84. 2/20/84 change may not be needed. Patch 8 changes ;fixes problem that 2/20 change was supposed to fix. PATCH5: ORG OFFSET RESTORE+10 CALL PATCH5 AND AL,0 ;No errors reported ORG OFFSET PATCH5 CALL FDCWAIT MOV AL,COUNT ADD AL,2 PAT5: CMP AL,COUNT ;Wait approx. 30ms. JNS PAT5 ;Changed from JNZ to JNS 9/21/84 RET  ;It is possible that after a hard disk error the controller ;not be ready for another command. If this situation is ;detected the controller will be reset. After reset the ;each drive must be reinitialize, so this fix will not work ;with more than one drive on the controller. ;3/12/84 Reset flag was set the wrong way. PATCH6: ORG OFFSET WINSEL NOP NOP CALL PATCH6 ORG OFFSET PATCH6 MOV DX,SASI+1 ;Get status IN AL,DX AND AL,0F8H JZ PAT6 AND BITS,NOT WINON ;Not ready for command so MOV LSTTRK[BX],-1 ;mark as not reset. PAT6: TEST BITS,WINON RET ;In the first keyboard interrupt, startint, a memory write ;is done without setting the data segment. The write ;should be done to the code segment. ;5/5/84 Add check for rev. E board. PATCH7: ORG OFFSET STARTINT JMP PATCH7 ORG OFFSET PATCH7 CALL REVE JNZ PAT71 MOV CS:VINT3,OFFSET DUARTINT MOV CS:VINT3+2,CS JMPS PAT72 PAT71: MOV CS:VINT0,OFFSET DUARTINT MOV CS:VINT0+2,CS PAT72: JMP STARTINT+10 ;When a read or write sector command is issued, the sector ;address is read and checked before the read or write ;begins. This allows the head time to settle after a seek. ;In the select routines, the sector address is not checked, ;so read errors can occur. (Most often on old drives at ;fast step rates.) Thses patches cut down on seeks during ;select and add second tries to error prone reads. PATCH8: ORG 0D76H ;Remove home before DD test. NOP NOP NOP NOP NOP ORG 0D91H ;Remove home before double MOV LSTTRK[BX],1 ;step test. ORG 0D6EH ;Double check address reads. CALL PATCH8 ORG 0D99H CALL PATCH8 ORG OFFSET PATCH8 CALL FLOPOP ;First read. MOV AX,1500 ;Waste 3ms. PAT8: DEC AX JNZ PAT8 CALL DMASETUP ;Read again JMP FLOPOP ;Patch 9 June 6, 1984 elh ; Western Digital hard disk controller is nearly compatible ; with Xebec controller. Slicer software uses DMA for data ; transfers and the CPU for command/status tranfers. While ; data is being moved with DMA the CPU monitors the C/D line. ; When the controller puts C/D low, the CPU takes over from ; the DMA. While the Xebec controller is busy with something ; else it keeps C/D high. The Western Digital controller keeps ; C/D low. This causes the CPU to take control away from the ; DMA to early. C/D should not be used alone for this anyway. ; A low, low, high pattern on I/O, C/D, MSG indicates the end ; of the data transfer part of a command. ; ; The Western Digital controller needs about 300ms for a self ; test after reset. Both the Western Digital and the Xebec ask ; for an 100ns reset signal, but I have been told that some ; controllers require as much as 25us. So the SASI reset has ; been changed to provide for this timing. ; ; Also the DMA was programmed for source synch. Which means ; that it will try to pre-fetch, if given the chance. There is ; no problem with the current Slicer hardware, the DMA does not ; get a chance to pre-fetch. However problems may arise if DMA ; is used externa  lly, or if seemingly innocent changes are made ; to the Slicer hardware. So the DMA programming is changed to ; destination synch which guarentees at least 2 CPU clocks ; between transfers. ; ; Starting with rev E Slicers the Duart interrupt on interrupt ; 3 instead of interrupt 0. PATCH9: ORG OFFSET WINOP+5 CALL PATCH9 JMPS WIN11+7 SASISTAT EQU 0F0H SASIEND EQU 0E0H ORG OFFSET PATCH9 ADD DX,DMATC-DMACTL ;Start DMA if count <> 0 IN AX,DX SUB DX,DMATC-DMACTL OR AX,AX JZ PAT9 IN AX,DX OR AX,DMASTRT+DMACHG OUT DX,AX PAT9: PUSH DX MOV DX,SASI+1 MOV AH,SASISTAT ;Wait for SASI controller PAT91: IN AL,DX ;to signal the end of TEST AL,WINBUSY/256 ;the command JZ PAT92 AND AL,AH CMP AL,SASIEND JNZ PAT91 PAT92: POP DX RET PATCH10: ORG OFFSET WINRST + 6 CALL PATCH10 ORG OFFSET PATCH10 MOV AX,10 ;Change timing of SASI reset. PAT10: DEC AX ;25us reset pulse JNZ PAT10 MOV AL,1 OUT DX,AL MOV AL,COUNT ADD AL,20 ;400ms wait after reset. PAT101: CMP AL,COUNT JNS PAT101 ;Change from JNZ to JNS 9/21/84 RET PATCH11: ;Change DMA programming for destination synch on reads. ORG OFFSET ROMTYP + 8 DW 0A280H ORG OFFSET WINTYPE + 8 DW 0A280H ;DUART interrupts on different vector for new boards. ORG 0294H JMP PATCH11 ORG 02A5H PAT11RET: ORG OFFSET PATCH11 LEA BX,VINT0 ;Assume duart is on MOV DX,IPC+INT0 ;Int. 0 CALL REVE JNZ PAT11 LEA BX,VINT3 ;On Rev. E board the duart MOV DX,IPC+INT3 ;is int 3. PAT11: MOV [BX],OFFSET STARTINT ;Initialize appropiate MOV 2[BX],CS ;interrupt. MOV AX,17H OUT DX,AL JMP PAT11RET ;Returns Z if revision E board REVE: PUSH DX PUSH AX MOV DX,SASI+1 ;0. Check board version. IN AL,DX AND AL,3 CMP AL,2 POP AX POP DX RET ;Set AL to duart interrupt type. PATCH12: ORG OFFSET CON1 - 2 NOP NOP ORG OFFSET RETINT - 3 CALL PATCH12 ORG OFFSET PATCH12 CALL REVE JZ PAT12A MOV AL,12 JMPS PAT12B PAT12A: MOV AL,15 PAT12B: RET PATCH13: ;8/22/84 elh ;Re-direct some interrupts. MASM uses interrupt vector 58 for something. ;This interrupt is reserved for the Slicer one second timer interrupt. MASM ;puts something in this vector, then the one second interrupt visits some ;strange places, ending up at rats. Patch 13 provides an alternate set of ;system interrupts. Interrupts 58-62 are moved to 250-254. Initially ;interrupts at 250-254 do far jumps to 58-62. This way if anyone expects ;these the system interrupts at 58-62 they will still be there. If however ;one of these is needed for some other use, such as with MASM, it can be ;freed by copying the vector to the upper set. Software which use the ;system interrupts should use the upper set, since the is now no guarentee ;that the lower set is valid. ;Phase out monitor spooler. References to interrupts 252 eliminated ORG OFFSET 250*4+8000H V250 RW 2 V251 RW 2 V252 RW 2 V253 RW 2 V254 RW 2 ORG OFFSET AUTOBOOT - 2 INT 254 ; ORG OFFSET STOP0 - 2 ; INT 252 ; ORG OFFSET LST4 - 2 ; INT 252 ORG OFFSET NOTCONIN INT 253 ORG OFFSET TIME0 - 2 INT 250 ORG OFFSET RES3 JMP PATCH13 ORG OFFSET PATCH13 MOV V250,OFFSET I250 MOV V251,OFFSET I251 ; MOV V252,OFFSET I252 MOV V253,OFFSET I253 MOV V254,OFFSET I254 MOV AX,OFFSET AUTOBOOT JMP RES3 + 3 I250: JMPF CS:DWORD PTR VSECOND I251: JMPF CS:DWORD PTR VENTRY ;I252: JMPF CS:DWORD PTR VSPOOL I253: JMPF CS:DWORD PTR VLST I254: JMPF CS:DWORD PTR VRESET PATCH14: ;Change the way time outs are calculated. ;Make checks on S not Z ;Also side bit is saved on multiple sector disk operations ;For example, on a 9 sector format sector 9, side 1, track 0 ; is followed sector 1, side 1, track 1 (used to be ; sector 1, side 0, track 1. ;Carry to third byte used to be lost on track calculation ;on large hard disk. ;Also on move and compare monitor commands the second memory ;pointer is stored in user's move or compare segment, not ;debugger's data segment. This is fixed. ORG OFFSET   FDC1 + 11 JNS FDC1 ORG OFFSET FLOP5 + 4 JNS FLOP5 ORG OFFSET WIN0 + 9 JNS WIN0 ORG OFFSET WIN4 + 9 JNS WIN4 ORG OFFSET WIN3 + 9 JNS WIN3 ORG OFFSET REP1 - 2 ;Save side bit on multiple sector AND AL,80H ;read/write operations ORG 0C9AH CALL PATCH14 ORG OFFSET EXIT0 + 1 POP DS ;Restore data segment MOV MEM2,SI ;before saving memory pointer ORG OFFSET PATCH14 ADC AH,0 ;Used to lose carry to third byte ADC DL,0 ;of hard disk sector address RET PATCH15: ORG OFFSET RES2 NOP NOP NOP NOP NOP NOP ;Change way double reset works. Wait for about 1/2 ;second, if I'm still here continue with warm boot ORG OFFSET PAT11 ;Old way used keyboard int. MOV [BX],OFFSET DUARTINT ;Change it. ORG 294H JMP PATCH15 ORG OFFSET PATCH15 SUB AX,AX ;Make mem look uninitialized XCHG AX,CS:VRESET+4 SUB CX,CX ;waste some time. MOV BX,4 PAT15A: LOOP PAT15A ;This takes about 1/8 second DEC BX ;Do it BX times JNZ PAT15A MOV CS:VRESET+4,AX ;Continue with initialization. ;Init video board if present. If both serial and ;video are present then jumper on Slicer determines ;which is the default console. ;***** VIDEO **** VID_ACTIVE EQU 2 KBD_ACTIVE EQU 1 JUMPVID EQU 20H VID_INIT: CALL VID_CHECK ;Check video/kbd present PUSH AX ;init if so. IN AL,DUART+26 ;Absence of vid jumper says TEST AL,JUMPVID ;to use seial, even if video POP AX ;board is present. JZ NO_KBD TEST AL,VID_ACTIVE ;Have video? JZ NO_VID PUSH AX ;If so set console CALL VID_SET ;out to video board POP AX NO_VID: TEST AL,KBD_ACTIVE ;Keyboard? JZ NO_KBD CALL KBD_SET ;Console in = keyboard JMP PAT11RET NO_KBD: JMP PATCH11 ;Init serial OFFX0 EQU OFFSET $ DSEG ORG 0 BOARD_NAME RW 1 BOARD_REV RW 1 CSEG ROMSEG ORG OFFX0 VID_CHECK: PUSH DS MOV AX,0C800H MOV DS,AX CMP BOARD_NAME,'DV' JNZ VI_00 TEST BOARD_REV,1 JZ VI_00 db 9ah ! dw V_INIT, 0c800h VI_00: POP DS RET V_INIT EQU 4 VIDEO: PUSH AX MOV AH,-1 INT INT10 POP AX RET KBD_INPUT: MOV AH,-1 INT INT16 RET KBD_STAT: MOV AH,1 INT INT16 JNZ KS_00 SUB AL,AL JMPS KS_01 KS_00: MOV AL,-1 KS_01: OR AL,AL RET INT10 EQU 10H INT16 EQU 16H VID_SET: MOV AX,OFFSET VIDEO MOV DX,3 CALL SETENT RET KBD_SET: MOV AX,OFFSET KBD_STAT MOV DX,1 CALL SETENT MOV AX,OFFSET KBD_INPUT MOV DX,2 CALL SETENT RET CSTAT: JMP CSTATPTR CIN: JMP CINPTR COUT: JMP COUTPTR ;B19200: ; mov al,80h ; out duart+8,al ; mov al,0cch ; out duart+2,al ; jmp cold3 PATCH16: ORG OFFSET VECTAB+JTOFF+2 CSTATPTR RW 1 CINPTR RW 1 COUTPTR RW 1 ORG OFFSET GETBAUD - 3 ; jmp b19200 JMP COLD3 ;Skip serial sign on org 0236h mov fdelay,100 ORG OFFSET MESS2 - 5 CALL COUT ORG OFFSET HEX2 + 2 CALL COUT ORG OFFSET DD2 + 2 CALL COUT ORG OFFSET CRTLP + 6 CALL COUT ORG OFFSET CRT2 + 2 CALL COUT ORG OFFSET CRT4 + 4 CALL COUT ORG OFFSET CRTBIN CALL COUT ORG OFFSET CRLF + 3  CALL COUT ORG OFFSET CRLF + 8 CALL COUT ORG OFFSET SPACE + 3 CALL COUT ORG OFFSET BACKSP + 3 CALL COUT ORG OFFSET BACKSP + 9 CALL COUT ORG OFFSET REGOUT + 1 CALL COUT ORG OFFSET REGOUT + 6 CALL COUT ORG OFFSET CNTLCHK CALL CSTAT ORG OFFSET CNTLCHK + 5 CALL CIN ORG OFFSET CNTLCHK + 12 CALL CIN ORG OFFSET LIN0 CALL CIN ORG OFFSET LIN1 + 2 CALL COUT ORG OFFSET LIN3 - 3 CALL COUT ORG OFFSET LIN4 - 3 CALL COUT ORG OFFSET ASC2 CALL COUT ORG OFFSET HEXMATH + 37 CALL COUT ORG OFFSET HEX7 - 6 CALL COUT ORG OFFSET 1781H CALL COUT ORG OFFSET SLEEP CALL CIN ORG OFFSET MONITOR + 5 CALL COUT ;Check for software interrupt on interrupt 13H ;If so send it to int 252 ORG 2DEH MOV VTMR2,OFFSET NEWTIME ORG OFFSET PATCH16 NEWTIME: PUSH AX PUSH DX MOV DX,IPC+INTSERVR IN AX,DX TEST AX,1 JZ SOFT13 JMP TIME+2 SOFT13: POP DX POP AX INT 252 RETF 2 ;Improve on patch 14. PATCH17: ORG OFFSET WIN3 CALL PAT17A JMPS WIN2 ORG OFFSET   WIN4 CALL PAT17B JMPS WIN5 ORG OFFSET WIN0 CALL PAT17C JMPS WIN1 ORG OFFSET FDC1 CALL PAT17D JNC FDC2 JMPS FDC1 + 13 ORG OFFSET PATCH17 PAT17A: CLI IN AL,DX TEST AL,WINBUSY/256 JNZ P17RET CMP AH,COUNT STI JNS PAT17A P17C: STC P17RET: STI RET PAT17B: CLI IN AL,DX TEST AL,REQ/256 JNZ P17RET CMP AH,COUNT STI JNS PAT17B JS P17C PAT17C: CLI IN AL,DX TEST AL,WINBUSY/256 JZ P17RET CMP AH,COUNT STI JNS PAT17C JS P17C PAT17D: CLI TEST BITS,FDRDY JNZ P17RET CMP AL,COUNT STI JNS PAT17D JS P17C PATCH18: ;Make intial memory test non destructive. ORG OFFSET COLD3 JMP PATCH18 ORG OFFSET PATCH18 MOV DX,21AH ;INITIALIZE 2681 ON EXPANSION BD MOV AX,0AH OUT DX,AX MOV DX,21CH ;SET MAP1 (OP5) AND MAP2 (OP6) LOW MOV AX,60H OUT DX,AX MOV AX,0 MOV ES,AX SUB SI,SI SUB BX,BX PAT18: MOV AX,ES:[SI] MOV CX,ES:2[SI] MOV ES:2[SI],AX NOT AX MOV ES:[SI],AX NOT AX CMP AX,ES:2[SI] JNZ PAT18A NOT AX CMP AX,ES:[SI] JNZ PAT18A NOT AX MOV ES:2[SI],CX MOV ES:[SI],AX INC BX MOV ES,BX JMPS PAT18 PAT18A: JMP COLD1 PATCH19: ;implimenting sw1 on meg board to determine memsize ORG OFFSET COLD2 JMP PATCH19 ORG OFFSET PATCH19 MOV CX,AX MOV DX,261H ;CHECK SW1 STATUS IN AL,DX NOT AL AND AL,6 CMP AL,0 ;NO SLICER MEMORY - NO VIDEO BD JZ NOMEM CMP AL,0010B ;SLICER MEMORY - NO VIDEO BD JZ SLMEM CMP AL,0100B ;NO SLICER MEMORY - VIDEO BD JZ VMEM CMP AL,0110B ;SLICER MEMORY - VIDEO BD JZ VMEM NOMEM: MOV AX,3C0H ;F000H / 40H (960K) JMP PAT19A SLMEM: MOV AX,340H ;D000H / 40H (832K) JMP PAT19A VMEM: MOV AX,2C0H ;B000H / 40H (704K) PAT19A: CMP AX,CX JC PAT19B MOV AX,CX PAT19B: MOV DX,AX MOV AX,DS JMP COLD2 + 4 and sector. JMPS REP2 ;Then repeat REP0: POP SI POP DI RET {{TXَэ&PUVN]0102821100654321U]UF]Ð{.츀P5PPw>5t@("s P|&=0r -PP(s "PI5r* #)!"%(s *P>5w`P s PPO>+=t >+_tMPX> u?>t52 sP\P$P]@(5-P >u%> uPP#P!€>v PP0므>t!%s>+,t>+ t PP>+,t@%>u>u>u>r> w s PP>t">u">"'w P"u> uPz %sP7UPP]UPP]UPF$Px]U P P]U PvW]Uv]U4 P4P1]U PP"]U PP]UPv]UPv3]UPv3]U>3u]Ê3ˀ`:u]ðPP3]UPv3]UPP3]UPvo]UPv_3]UPvL3]UPv93]UPv&3]UPP]UPv3]U PP]U PFP]U6]U6]U6]U!Pv]U"Pv]U#Pv]U$Pvx]UFȈF3u PP#]UtP,Њ"s3>3u PP"-"."/"0"1"2P93PPPH]U#s%!  u]6:Pd' &'sP3t PP͠rP;sjP;t@3ta>3t PP:t >uPUТ& "s PP$6]Áj]U~ r>t:wgs PFP. v?PFPp-;rF6:ӈ ]U~ u>uva28r(*>t  P/~ u]U~t@"s F0P]UFPF$P]U8t@'''P66>u :P  P ]U젾s~ tg)sD~ t>>t"<u<:r  P>tP)~ uv~ u)]U~ar ~zwf_F]U~Ar ~ZwN F]U. PP*u;r"s>t 67PP* PP$ sCs **> t@ss2<u]ðPPis&s 6]às 6]à]U>tȢ<u/ ])>tƊ6]<u]Â>t%6Is맂>t6s ]]]UFFƊ6u 6:u]U+s;w@"$]À>+t@]U>:t#>us]ðPP6>u"s&>:u@P>u@Y"sWXM:P66}k>t ZRt PP?]U,0< w]à,A<v PP,A ]UP]UPY ]UPY ]U>t PP>t PP]UtP4 P>3u PPpP>3t}PsUsL>3Ju@P>3Nu@Y"sP"P3р>3JtPP]&&P+PPPPP" -" ." /" 0 " 1" 2 PsP]U-:P:X%-s)>@r]á]á;r]Us1-3u>3u%u뷰PPC]U Pdh\P >3u@ P; r@Y"s  ؀>3u>u P\Ps]á @ 3$@PPPPPPrts=2 s&s>uPW#]U< w(Ê t< u.P6u]U?P>3t33$@PPPs ]ư]U:u :u6]U젶:5r ]à6]U+< t]U>+ t]YQUG% + ,>,#s>, u+G$>wƇup,6+js#>,r]À>+*uPw+Ѐ>+:t>,u<G,A<v]6+s>+[uqG% ]>,t]> wi<v@֋P:t@Y"rȀ>uG%^<[u]Àu]À>+[uc^>,u],>+.u- +PDs>, r]À>+*u P{QӀ>+[uG%G ]]U> wF:uu]U,,Ɗ+?u ]U+?,:Fs]Uc++< t@+P]t@Z rAv>+ tİPP뾀>+St>+Qu1+<t@P>+ t@Y r+9+,0< v#+,0< w ݠ"  u<v PP'G$v+]EOZau!<Na (1/8/82) CP/M-86 PIP VERS 1.1 Lesen $ Schreiben$Prfen$ Ungltiges Ziel $ Unglt.Quelle$ Abgebrochen$ Argument $ Benutzernummer $ Format falsch$ HEX-Prfsumme $ keine Datei $ kein Starttext$ kein Endetext$ Hex-Ziffer $ Close Dat$ HEX-Datei Ende unerwartet$ Trennzeichen $ Inh.verz. voll $ Unglt. Format bei Lckendatei$ =.:;,<> _[]OUTPRNLSTAXOCONAXIINPNULEOFFehler:$ - $$$$Zieldatei ist R/O, Lschen (J/N)?$Nicht gelscht $Kopieren-$Bentigt CP/M-86$CP/M-86 PIP VERSION 1.1$#  $  %  &  '