IMD 1.16: 8/06/2007 19:19:41                    BACK2DDTASM-BANNER ASMN BLOCKREFASM) DIF2 C x CAT SUBFDCAT DOCBISHOW16ASMaVLIST DOC BKSWITCHDOC" !"VLIST COM #CASM MSG $CASM SUB%CLS ASM&DEFF2-01CRL.'()SAMPLE CSM*CASM C +,-./01234RAMDISK ASM?rstuvwxyz{|}RAMDISK DOC~CAT COMCAT2 COMFMAP COMUCAT COMCASM COMtCASM COMtCASM COMtD COM* back2ddt.asm Version 1 September 5, 1981 * * Enables exiting from DDT via "G18" and returning via control-B. * * (C) 1981 by Roy Lipscomb, Logic Associates, Chicago * Copying for non-profit distribution is permitted. * * *********************************************************************** * * This module is useful when debugging a program for which you * have a .PRN file on disk. You can exit from DDT; display the * .PRN listing; then return to DDT and the program being tested. * * NotesCASM DOCC56789DEFF2-01CSM*:;<=>?@ABCDDEFF2A01CSMVEFGHIJCRYPT C KFINDVAR BAS LMLCHECK C NOEDTEXT ASC0PQRFINDBAD COM SGENHEX COMTFIND ASMcUVWXYZ[FMHARD ASM=\]^_GO ASM `MBASIC HLP&abcdefghijkMEMMAP ASMlmLISTT COMnLISTT DOC(opq: * * 1) As supplied, BACK2DDT uses restart locations 3-6 (18h-37h). * * 2) The CCP must be protected from being overlaid. (This * requirement is met if DDT is loaded via DDTX, a public- * domain program by Ken Barbier available on many RCPM * systems.) * * 3) The program being debugged will be preserved during * CCP resident commands--ERA, DIR, TYPE, REN, or SAVE. Any * other (transient) commands will overlay the program. * * 4) The CCP resets the dma to 80h, and alters 80h-ffh. Thus, *    * a) Be sure you have nothing critical in this area * (such as the program stack) when exiting with "G18". * * b) If your program uses a different dma, be sure to * reset the dma after typing control-B. * * 5) Registers A, PSW, and PC are not restored by control-B. * ******************************************************************** org 100h jmp begin ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; initial variables ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;return via control-B.' db cr,lf,eom notdone db cr,lf,'Back2ddt already loaded: no action',cr,lf,eom ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; mainline ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; begin push h push d push b ;test if already loaded call testit jz return ;yes, already loaded ;move module into place loadit lxi h,module lxi d,trubase lxi b,length call move ;divert cp/m jmp-addresses to trap call patchit ;exit to t+1 ;print "done" message lxi h,done call message ret ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; test if already loaded ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;test if bios jump table already points to trap ;address conin table entry testit lhld 1 mvi l,cindisp mov c,m inx h mov b,m ;compare jump-table entry with trap entry lxi d,trpentr-adjust mov a,c sub e mov a,b sbb d rnz ;if not equal, assume not already loade;;;;;;;;;;;;;;;;;;;;;;;;;; message mov a,m inx h cpi eom rz ;return if message completed mov e,a mvi c,display push h call bdos pop h jmp message ********************************************************* ********************************************************* * conin-trap module * ********************************************************* ********************************************************* module equ $ adjust equ module-trubase ;fudge factor, to compute  trapchr ;go to ddt? rnz ;no, back to CCP lxi sp,0 ;restore stack address stksav equ $-2 ;(filled at ddt-exit time) ;next two instructions are used to test for already-loaded module testlod pop h ;restore ddt trap address shld 6 pop h ;restore registers pop d pop b ;must use actual RST 7 instruction, to preserve stack pointer. rst 7 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;get length of relocatable routines length equ $-module ;must equal 38h, ;;;;;;;;;;;;; ; change trap char, if so desired trapchr equ 2 ;control-b means "back to ddt" ;do not change these trubase equ 18h ;actual load point of trap bdos equ 5 cindisp equ 10 ;displacement of conin addr in jmptable display equ 2 cr equ 13 lf equ 10 poph equ 0e1h ;one of the test instructions ; "done" message eom equ '$' done db cr,lf,'Back2ddt version 1, Sept 81' db cr,lf db cr,lf,'After protecting the CCP and loading DDT,' db cr,lf,'exit DDT via "G18" and cpm return pop b pop d pop h ret ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; patch bios to trap conin ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;address conin entry in bios jump-table patchit lhld 1 mvi l,cindisp ;insert offset for conin ;remove true conin jmp-address mov e,m inx h mov d,m ;insert trap address into jmp table lxi b,trpentr-adjust mov m,b dcx h mov m,c ;insert true conin address into trap xchg shld trpentr-adjusd ;already loaded, so output message lxi h,notdone call message ;turn on zero flag xra a ret ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; move block of data ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;source in hl, destination in de, length in bc. move mov a,b ora c rz mov a,m stax d inx d inx h dcx b jmp move ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; print signoff mess ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;true address ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; exit from ddt (save important values) (takes 15 bytes) ddtexit push b ;save registers push d push h lhld 6 ;save ddt trap address push h lxi h,0 ;save stack pointer dad sp shld stksav-adjust rst 0 ;reboot ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; if trapchr found, jmp to ddt; else return (takes 17 bytes) trpentr call 0 ;perform conin (0 changed at run time) cpiin orig version. end  ;next two instructions are used to test for already-loaded module testlod pop h ;restore ddt trap address shld 6 pop h ;restore registers pop d pop b ;must use actual RST 7 instruction, to preserve stack pointer. rst 7 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;get length of relocatable routines length equ $-module ;must equal 38h,    * PROGRAM: BANNER * AUTHOR: SCOTT HOLTZMAN * VERSION: 1.0 * DATE: 07/09/83 * PREVIOUS VERSIONS: None VERS EQU 10 ;VERSION NUMBER ********************************* * * * B A N N E R P R I N T * * * ********************************* * * BANNER is a program which prints large (5x7) block letters * on the LST: Device in response to user input from the * keyboard. BANNER is invoked in several ways: * BANNER * -- is printed on the LST: device; ex: * BANNER  EQU 0005H FCB EQU 005CH BUFF EQU 0080H CTRLC EQU 03H CR EQU 0DH LF EQU 0AH TAB EQU 09H READLN EQU 10 ;Input Line Editor OUTL EQU 5 ;OUTPUT TO LST: OUTC EQU 2 ;OUTPUT TO CON: ORG 100H START: LXI H,0 ;SAVE STACK PTR DAD SP ;HL=OLD SP SHLD STACK LXI SP,STACK ;NEW STACK CALL PMSG DB 'BANNER Version ' DB VERS/10+'0','.',(VERS MOD 10)+'0' DB CR,LF DB 0 LDA FCB+1 ;CHECK FOR OPTION CPI '/' ;OPTION CAUGHT? JNZ ONE$LINE ;IF NO OPTION, PROCESS ONLY 1 LINE ay enter several sequential ' DB CR,LF,'Banner Lines to be printed. Any other option ' DB CR,LF,'prints this Help Message and Exits.' DB 0 * * Exit BANNER * EXIT: LHLD STACK ;GET OLD STACK PTR SPHL ;LOAD SP RET * * PRINT BANNER WHEN CONTAINED IN COMMAND LINE * ONE$LINE: LXI H,BUFF ;PT TO INPUT LINE MOV A,M ;GET CHAR COUNT ORA A ;PRINT HELP MESSAGE IF NO CHARS JZ HELP MOV B,A ;CHAR COUNT IN B DCR B ;COUNT DOWN BY 1 TO ELIMINATE LEADING SPACE JZ HELP LXI D,BLINE ;PT TO CALL PMSG DB 'BANNER? ',0 LXI D,INLINE ;INPUT LINE MVI C,READLN ;BDOS READLN FUNCTION CALL BDOS CALL PMSG ;NEW LINE DB CR,LF,0 CALL BANNER ;PRINT BANNER LINE JMP BTEXTL ;CONTINUE * * PRINT BANNER CONTAINED IN BLINE BUFFER (BLINE=CHAR CNT) * BANNER: LXI H,BLINE ;STORE ENDING MOV A,M ;GET CHAR COUNT CPI MCHARS+1 ;BEYOND CHAR LIMIT? JC BANNER1 ;CONTINUE IF NOT CALL PMSG DB CR,LF,'Truncation Error -- Line too long',CR,LF DB 0 JMP EXIT ;RETURN TO CALLER BANNER1: O NEXT LINE IF SO CALL CONV ;GET ADDRESS OF DATA IN HL JC CB1 ;SKIP IF ERROR CALL PRINT ;PRINT 5 CHARS FOLLOWED BY TWO SPACES JMP CB1 ;CONTINUE CB4: CALL CRLF ;4 CALL CRLF CALL CRLF CB2: CALL CRLF ;1 CRLF RET * * COMPUTE POINTER TO TABLE ENTRY OF CHAR IN REG A * ON INPUT, A=CHAR; ON OUTPUT, HL=PTR TO TABLE ENTRY (1ST BYTE) * CONV: PUSH B ;SAVE BC PUSH D ;SAVE DE SUI ' ' ;CONVERT TO 0 RC ;INVALID CHAR CPI 7BH-' ' ;IN RANGE? JNC CNVER ;INVALID CHELLO * BANNER /T * -- Multi-Text Line Input Mode; the user may * type several successive lines to be printed; * the user exits by typing ^C * BANNER /? * -- Built-In HELP Information is printed * ********************************* * User-Customized Parameters * ********************************* TEXT EQU 'T' ;OPTION CHAR TO INVOKE TEXT ENTRY MODE MCHARS EQU 16 ;MAX NUMBER OF CHARS/LINE ********************************* * Constants * ********************************* BDOSLDA FCB+2 ;CHECK FOR TEXT INPUT CPI TEXT ;TEXT CHAR? JZ BTEXT ;INPUT TEXT LINES ; ; Print BANNER Help Message ; HELP: CALL PMSG ;PRINT MESSAGE TO USER DB CR,LF,'BANNER is invoked by a command line like:' DB CR,LF,' BANNER ' DB CR,LF,'In which case will be printed and control ' DB CR,LF,'returned to CP/M, like "BANNER HELLO" to print' DB CR,LF,'"HELLO", or' DB CR,LF,' BANNER /o' DB CR,LF,'where ''/o'' is ''/T'' to invoke Text Entry' DB CR,LF,'Mode in which the user mBANNER LINE BUFFER MOV A,B ;GET CHAR COUNT STAX D ;STORE CHAR COUNT INX H ;PT TO FIRST CHAR (SPACE) INX H ;PT TO CHAR AFTER SPACE INX D ;PT TO NEXT POSITION IN BUFFER OL1: MOV A,M ;GET NEXT CHAR STAX D ;PUT IT INX H ;PT TO NEXT INX D DCR B ;COUNT DOWN JNZ OL1 CALL BANNER ;PRINT BANNER JMP EXIT ;EXIT TO CP/M * * Process Multiple Line Input * BTEXT: CALL PMSG DB CR,LF,'BANNER Multiple Line Input' DB CR,LF,' Input Line or ^C to Return to CP/M' DB CR,LF DB 0 BTEXTL: INX H ;PT TO FIRST CHAR ADD L ;ADD TO LOW-ORDER BYTE MOV L,A ;PT TO BYTE MVI M,0 ;STORE MVI D,80H ;PT TO MSB+1 CBAN: LXI H,BLINE+1 ;SET PTR TO FIRST CHAR MOV A,M ;CHECK FOR NO CHARS ORA A ;ENDING ZERO? JZ CB4 ;4 CRLF'S IF SO SHLD NEXTCH CALL CRLF ;NEW LINE MOV A,D ;GET BIT PTR RRC ;ROTATE ANI 7FH ;MASK OUT MSB MOV D,A ;SET BIT PTR JZ CB2 ;NEW LINE AND THEN EXIT CB1: CALL CONIN ;GET NEXT CHAR CALL CAPS ;CAPITALIZE MOV C,A ;CHAR IN C ORA A ;DONE? JZ CBAN ;DHAR MOV E,A ;VALUE IN E MVI D,0 ;VALUE IN DE MOV H,D ;VALUE IN HL MOV L,E DAD H ;VALUE * 2 DAD H ;VALUE * 4 DAD D ;HL = VALUE * 5 LXI D,CHARS ;POINT TO BEGINNING OF TABLE DAD D ;HL PTS TO ELEMENT IN TABLE POP D ;RESTORE DE POP B ;RESTORE BC ORA A ;CLEAR CARRY RET CNVER: STC ;SET CARRY FOR INVALID CHAR POP D ;RESTORE DE POP B ;RESTORE BC RET * * CAPITALIZE CHAR IN A * CAPS: CPI 61H ;LOWER CASE? RC ANI 5FH ;MASK OUT BIT 5 RET * * PRINT CHAR I   N C ACCORDING TO THE ENTRY PTED TO BY HL * BIT MASK IS IN D * PRINT: PUSH B ;SAVE BC (C=CHAR) MVI B,5 ;5 BYTES/CHAR PRINT1: MOV A,M ;GET BIT SET ANA D ;MASK FOR BIT IN QUESTION JZ PRINT3 ;IF ZERO, PRINT CALL LSTOUT ;PRINT CHAR IN C PRINT2: INX H ;PT TO NEXT BYTE DCR B ;COUNT DOWN JNZ PRINT1 MVI C,' ' ;PRINT THREE SPACES CALL LSTOUT CALL LSTOUT CALL LSTOUT POP B ;RESTORE BC RET PRINT3: MOV E,C ;SAVE CHAR MVI C,' ' ;PRINT CALL LSTOUT MOV C,ET CRLF: MVI C,CR CALL LSTOUT MVI C,LF JMP LSTOUT LSTOUT: PUSH H ! PUSH B ! PUSH D MOV E,C MVI C,OUTL ;OUTPUT TO LST: CALL BDOS POP D ! POP B ! POP H RET CONOUT: PUSH H ! PUSH B ! PUSH D MOV E,C MVI C,OUTC ;OUTPUT TO CON: CALL BDOS POP D ! POP B ! POP H RET CONIN: PUSH H ! PUSH D ! PUSH B LHLD NEXTCH ;GET NEXT CHAR PTR MOV A,M ;GET CHAR INX H ;PT TO NEXT SHLD NEXTCH ANI 7FH ;MASK MSB IF ANY POP B ! POP D ! POP H RET * * CHARACTER TABLE * THE CHARAC0H,00H,7DH,00H,00H ;EXCLAMATION MARK DB 00H,70H,00H,70H,00H ;" DB 14H,7FH,14H,7FH,14H ;# DB 12H,2AH,7FH,2AH,24H ;$ DB 62H,64H,08H,13H,23H ;% DB 36H,49H,35H,02H,05H ;& DB 00H,00H,70H,00H,00H ;' DB 1CH,22H,41H,00H,00H ;( DB 00H,00H,41H,22H,1CH ;) DB 22H,14H,7FH,14H,22H ;* DB 08H,08H,3EH,08H,08H ;+ DB 00H,01H,06H,00H,00H ;, DB 08H,08H,08H,08H,08H ;- DB 00H,03H,03H,00H,00H ;. DB 02H,04H,08H,10H,20H ;/ DB 3EH,45H,49H,51H,3EH ;0 DB 11H,31H,7FH,01H,01H ;1 DB 21H,43H,45H,49H,31H ;2H,49H,49H,49H,41H ;E DB 7FH,48H,48H,48H,40H ;F DB 7FH,41H,41H,49H,4FH ;G DB 7FH,08H,08H,08H,7FH ;H DB 41H,7FH,41H,80H,80H ;I DB 03H,01H,01H,01H,7FH ;J DB 7FH,08H,14H,22H,41H ;K DB 7FH,01H,01H,01H,01H ;L DB 7FH,20H,10H,20H,7FH ;M DB 7FH,30H,08H,06H,7FH ;N DB 7FH,41H,41H,41H,7FH ;O DB 7FH,48H,48H,48H,78H ;P DB 7FH,41H,45H,43H,7FH ;Q DB 7FH,48H,4CH,4AH,79H ;R DB 32H,49H,49H,49H,26H ;S DB 40H,40H,7FH,40H,40H ;T DB 7FH,01H,01H,01H,7FH ;U DB 70H,0CH,03H,0CH,70H ;V DB 7FH,02H,04H ;I DB 03H,01H,01H,01H,7FH ;J DB 7FH,08H,14H,22H,41H ;K DB 7FH,01H,01H,01H,01H ;L DB 7FH,20H,10H,20H,7FH ;M DB 7FH,30H,08H,06H,7FH ;N DB 7FH,41H,41H,41H,7FH ;O DB 7FH,48H,48H,48H,78H ;P DB 7FH,41H,45H,43H,7FH ;Q DB 7FH,48H,4CH,4AH,79H ;R DB 32H,49H,49H,49H,26H ;S DB 40H,40H,7FH,40H,40H ;T DB 7FH,01H,01H,01H,7FH ;U DB 70H,0CH,03H,0CH,70H ;V DB 7FH,02H,04H,02H,7FH ;W DB 63H,14H,08H,14H,63H ;X DB 60H,10H,0FH,10H,60H ;Y DB 43H,45H,49H,51H,61H ;Z * * BUFFERS * DS 40 ;20 ;GET CHAR JMP PRINT2 * * SUPPORT ROUTINES * PMSG: XTHL ;GET PTR TO STRING MVI B,0 ;SET TAB COUNTER PMSG1: MOV A,M ;GET NEXT BYTE INX H ;PT TO NEXT ORA A ;DONE? JZ PMSG2 CPI TAB ;TABULATE? JZ PMSG$TAB MOV C,A ;CHAR IN C CALL CONOUT ;PRINT CHAR INR B ;INCR CHAR COUNT JMP PMSG1 PMSG$TAB: MVI C,' ' ;PRINT CALL CONOUT ;PRINT INR B ;INCR POSITION COUNT MOV A,B ;GET IT ANI 7 ;DONE? JNZ PMSG$TAB JMP PMSG1 ;PROCESS NEXT CHAR PMSG2: XTHL ;RESTORE HL, PTR RETERS REPRESENTED IN THIS TABLE ARE IN A 5X7 FORMAT * THE FIRST BYTE IN EACH ENTRY REPRESENTS THE FIRST CHAR TO PRINT, ETC * THE BITS 6 TO 0 REPRESENT LINES (SUCCESSIVE) TO PRINT FOR THE CHAR * * FOR EXAMPLE, THE ENTRY FOR '*' IS 22H,14H,7FH,14H,22H; THIS GENERATES: * * * 00100 R 6 * * * * 10101 E 5 * *** 01110 A 4 * * 00100 D 3 * *** 01110 2 * * * * 10101 D 1 * * 00100 O 0 * ^^^^^ W * 21712 N ^ * 24F42 B * HHHHH I * T * CHARS: DB 00H,00H,00H,00H,00H ; DB 0 DB 22H,41H,49H,49H,36H ;3 DB 0CH,14H,24H,7FH,04H ;4 DB 7AH,49H,49H,49H,46H ;5 DB 3EH,49H,49H,49H,26H ;6 DB 43H,44H,48H,50H,60H ;7 DB 36H,49H,49H,49H,36H ;8 DB 30H,49H,49H,49H,3EH ;9 DB 00H,00H,36H,00H,00H ;: DB 00H,01H,16H,00H,00H ;; DB 08H,14H,22H,41H,00H ;< DB 14H,14H,14H,14H,14H ;= DB 00H,41H,22H,14H,08H ;> DB 20H,40H,4DH,50H,20H ;? DB 7EH,41H,5DH,4DH,39H ;@ DB 3FH,48H,48H,48H,3FH ;A DB 7FH,49H,49H,49H,36H ;B DB 7FH,41H,41H,41H,41H ;C DB 7FH,41H,41H,41H,3EH ;D DB 7FH,02H,7FH ;W DB 63H,14H,08H,14H,63H ;X DB 60H,10H,0FH,10H,60H ;Y DB 43H,45H,49H,51H,61H ;Z DB 7FH,41H,41H,41H,00H ;[ DB 20H,10H,08H,04H,02H ;\ DB 00H,41H,41H,41H,7FH ;] DB 04H,08H,10H,08H,04H ;^ DB 01H,01H,01H,01H,01H ;_ DB 00H,40H,20H,10H,00H ;' DB 3FH,48H,48H,48H,3FH ;A DB 7FH,49H,49H,49H,36H ;B DB 7FH,41H,41H,41H,41H ;C DB 7FH,41H,41H,41H,3EH ;D DB 7FH,49H,49H,49H,41H ;E DB 7FH,48H,48H,48H,40H ;F DB 7FH,41H,41H,49H,4FH ;G DB 7FH,08H,08H,08H,7FH ;H DB 41H,7FH,41H,80H,80-ELT STACK STACK: DS 2 ;TOP OF BANNER STACK; CP/M STACK NEXTCH: DS 2 LLEN EQU 80 ;NUMBER OF CHARS IN LINE, MAX INLINE: DB LLEN ;CHAR COUNT FOR INLINE BLINE: DS LLEN+1 ;NUMBER OF BYTES IN LINE  DB 32H,49H,49H,49H,26H ;S DB 40H,40H,7FH,40H,40H ;T DB 7FH,01H,01H,01H,7FH ;U DB 70H,0CH,03H,0CH,70H ;V DB 7FH,02H,04H,02H,7FH ;W DB 63H,14H,08H,14H,63H ;X DB 60H,10H,0FH,10H,60H ;Y DB 43H,45H,49H,51H,61H ;Z * * BUFFERS * DS 40 ;20   * PRINT A CP/M BLOCK VERSUS TRACK-SECTOR * CROSS REFERENCE TABLE FOR ANY SYSTEM * CONFIGURATION. 8/4/81 * * SET THE DISK PARAMETERS TO MATCH YOUR * SYSTEM CONFIGURATION. IF YOU NEED A * DIFFERENT LACE TABLE, IT MUST REPLACE * THE ONE AT THE END OF THE PROGRAM. * THE PARAMETERS ARE PRESET TO THE * STANDARD VALUES FOR AN 8" DISK. * FALSE EQU 0 TRUE EQU NOT FALSE * * DISK PARAMETERS * SECTRK EQU 26 ;SECTORS PER TRACK TRKDSK EQU 77 ;TRACKS PER DISK SECBLK EQU 8 ;SECTORS PER CP/M BLOCK SYST FOR DATA SUB-HEADING? JNZ LOOP1 ;NO * * PRINT DATA SUB-HEADING * LXI D,MSG3 ;YES MVI C,PRSTR CALL BDOS ;PRINT DATA SUB-HEADING LOOP1: LDA BLOCK ;GET CURRENT BLOCK NUMBER MOV L,A MVI H,0 MVI A,SECBLK ;GET SECTORS/BLOCK DCR A ;CONVERT TO MASK LOOP2: DAD H ;DOUBLE VALUE STC ;SET CARRY CMC ;CLEAR CARRY RAR ;SHIFT MASK ORA A ;SHIFT COMPLETE? JNZ LOOP2 ;NO PUSH H ;YES, SAVE BLOCK*SECBLK MVI C,0 LXI D,-SECTRK DIV: DAD D INR C JC DIV DCR C MOV A,C ADI SYSTRK STAUMN COUNTER STA COL COLOP: LDA TEMP ;GET SEQUENTIAL INR A STA TEMP CPI SECTRK ;END OF TRACK? JNZ SKIP ;NO MVI A,0 ;YES STA TEMP LXI H,TRACK INR M SKIP: CALL SPC2 ;PRINT 2 SPACES LDA TRACK CALL HEXPRN ;PRINT TRACK CALL DASH ;PRINT A DASH LDA TEMP ;GET SEQUENTIAL CALL XLATE ;CONVERT TO ACTUAL CALL HEXPRN ;PRINT IT LXI H,COL ;POINT TO COLUMN COUNT DCR M ;DONE? JZ COLDN ;YES MOV A,M ;NO, NEW LINE REQD? ANI 7 JNZ COLOP ;NO LXI D,CRLF ;YES MVI C,PRSTR CALL BDOS E ;ACTUAL SECTOR CALL HEXPRN ;PRINT IT MVI A,UNUSED-1 ;SET COLUMN COUNTER STA COL COLOP1: LXI H,TEMP ;STEP SEQUENTIAL SECTOR INR M CALL SPC2 ;PRINT 2 SPACES LDA TRACK CALL HEXPRN ;PRINT TRACK CALL DASH ;PRINT A DASH LDA TEMP ;GET SEQUENTIAL CALL XLATE ;CONVERT TO ACTUAL CALL HEXPRN ;PRINT IT LXI H,COL ;POINT TO COLUMN COUNT DCR M ;DONE? JNZ COLOP1 ;NO LXI D,CRLF ;YES, NEW LINE MVI C,PRSTR CALL BDOS RET ;BACK TO CCP * * TRANSLATE SEQUENTIAL TO ACTUAL SECTOR * IF LAC SPACES JMP SPC SPC4: LXI D,MSG4SP ;4 SPACES SPC: MVI C,PRSTR JMP BDOS * * PRINT A DASH * DASH: MVI E,'-' MVI C,PRCHAR JMP BDOS * * MESSAGES * MSG1: DB FF,' CP/M BLOCK NUMBERS VERSUS ' DB 'TRACK-SECTOR',CR,LF,CR,LF,'$' MSG2: DB CR,LF,' BLOCK TRACK-SECTOR' DB ' (DIRECTORY)',CR,LF,'$' MSG3: DB CR,LF,' BLOCK TRACK-SECTOR' DB ' (DATA AREA)',CR,LF,'$' MSG4: DB CR,LF,' BLOCK TRACK-SECTOR' DB ' (UNUSED)' CRLF: DB CR,LF,'$' MSG4SP: DB ' $' ;4 SPACES IF LACE * RK EQU 2 ;SYSTEM TRACKS DIRSIZ EQU 64 ;DIRECTORY SIZE LACE EQU TRUE ;LACE TABLE REQUIRED FIRST EQU 1 ;FIRST SECTOR NUMBER * ORG 100H * * PRINT HEADING * START: LXI D,MSG1 MVI C,PRSTR CALL BDOS * * PRINT DIRECTORY SUB-HEADING * LXI D,MSG2 MVI C,PRSTR CALL BDOS * * INIT VARIABLES * XRA A STA BLOCK ;CP/M BLOCK NUMBER STA TRACK ;ACTUAL TRACK NUMBER INR A STA SECTOR ;SEQUENTIAL SECTOR NUMBER * * MAIN LOOP POINT * LOOP: LDA BLOCK ;GET CURRENT BLOCK NUMBER CPI DIRBLK ;TIME TRACK ;TRACK NUMBER MVI B,SECTRK XRA A INR C MUL: DCR C JZ MULD ADD B JMP MUL MULD: CMA MOV C,A MVI B,0FFH INX B POP H DAD B MOV A,L STA TEMP ;SAVE SEQUENTIAL SECTOR CALL XLATE ;GET ACTUAL SECTOR NUMBER PUSH PSW ;SAVE RESULT CALL SPC2 ;PRINT 2 SPACES LDA BLOCK ;GET BLOCK NUMBER CALL HEXPRN ;PRINT IT CALL SPC4 ;PRINT 4 SPACES LDA TRACK ;GET TRACK CALL HEXPRN ;PRINT IT CALL DASH ;PRINT A DASH POP PSW ;GET SECTOR CALL HEXPRN ;PRINT IT MVI A,SECBLK-1 ;SET COLCALL SPC4 ;BYPASS BLOCK COLUMN CALL SPC2 JMP COLOP COLDN: LXI D,CRLF ;NEW LINE MVI C,PRSTR CALL BDOS LDA BLOCK ;GET CP/M BLOCK INR A STA BLOCK CPI MAXBLK ;END OF DISK? JNZ LOOP ;NO * * PRINT UNUSED SUB-HEADING * LXI D,MSG4 ;YES MVI C,PRSTR CALL BDOS ;PRINT UNUSED SUB-HD LXI H,TEMP INR M CALL SPC2 ;PRINT 2 SPACES LDA BLOCK CALL HEXPRN CALL SPC4 ;PRINT 4 SPACES LDA TRACK CALL HEXPRN ;PRINT TRACK CALL DASH ;PRINT A DASH LDA TEMP ;GET SEQUENTIAL SECTOR CALL XLATE XLATE: MOV E,A MVI D,0 LXI H,LACETB ;BASE OF TABLE DAD D ;POINT TO ACTUAL SECTOR MOV A,M ;GET ACTUAL SECTOR ENDIF IF NOT LACE XLATE: ADI FIRST ENDIF RET * * PRINT ACCUMULATOR IN HEX * HEXPRN: PUSH PSW ;SAVE FOR 2ND DIGIT RRC RRC RRC RRC CALL PRDGIT ;PRINT HEX DIGIT POP PSW ;GET 2ND DIGIT PRDGIT: ANI 0FH ;HEX VALUE ADI 90H ;CONVERT TO ASCII DAA ACI 40H DAA MOV E,A MVI C,PRCHAR CALL BDOS ;PRINT DIGIT RET * * PRINT 2 OR 4 SPACES * SPC2: LXI D,MSG4SP+2 ;2* LACE TABLE * LACETB: DB 1,7,13,19,25,5,11,17,23,3,9,15,21 DB 2,8,14,20,26,6,12,18,24,4,10,16,22 ENDIF * * EQUATES * BDOS EQU 5 ;BDOS ENTRY POINT PRCHAR EQU 2 ;PRINT CHARACTER PRSTR EQU 9 ;PRINT STRING FUNCTION FF EQU 0CH ;FORM FEED CR EQU 0DH ;CARRIAGE RETURN LF EQU 0AH ;LINE FEED MAXBLK EQU ((TRKDSK-SYSTRK)*SECTRK)/SECBLK UNUSED EQU ((TRKDSK-SYSTRK)*SECTRK)-(MAXBLK*SECBLK) DIRBLK EQU DIRSIZ/(SECBLK*4) * * BUFFERS * BLOCK: DS 1 ;CURRENT BLOCK NUMBER TRACK: DS 1 ;CURRENT TRACK SECTO   R: DS 1 ;CURRENT SECTOR (UNTRANSLATED) COL: DS 1 ;COLUMN COUNTER TEMP: DS 1 ;TEMPORARY SECTOR END START RRENT TRACK SECTOBDOS EQU 5 ;BDOS ENTRY POINT PRCHAR EQU 2 ;PRINT CHARACTER PRSTR EQU 9 ;PRINT STRING FUNCTION FF EQU 0CH ;FORM FEED CR EQU 0DH ;CARRIAGE RETURN LF EQU 0AH ;LINE FEED MAXBLK EQU ((TRKDSK-SYSTRK)*SECTRK)/SECBLK UNUSED EQU ((TRKDSK-SYSTRK)*SECTRK)-(MAXBLK*SECBLK) DIRBLK EQU DIRSIZ/(SECBLK*4) * * BUFFERS * BLOCK: DS 1 ;CURRENT BLOCK NUMBER TRACK: DS 1 ;CURRENT TRACK SECTO#define VERSION "dif.c 2.00 (dif 2.0) 11-17-81" /* * Differential file comparision program * * Chuck Forsberg * Computer Development Inc * 6700 S. W. 105th * Beaverton OR 97005 * 503/646-1599 RCP/M 503/621-3193 300,450,1200 baud * cc1 dif.c -e 4000 -o * clink dif yam8 -f dio -s (ndio may be used instead or dio) * * 1.10 added crc information for use by ssed 1.10 in verifying antecedent * file is correct 11-4-81 CAF */ /* system dependent stuff */ #include "a:bdscio.shed value of text special case EOF=0 */ char f; /* 0 or 1 which file it came from */ int num; /* number of line or LAST_TOKE if EOF */ struct line *next; /* pointer to next line, or null if last in buffer, or to itself if EOF */ char text[0]; /* asciz line of text */ } *bottom[2], /* bottom of each file's buffer */ *top[2], /* top of each buffer */ *thislna, *thislnb, /* line just fetched from buf */ cdq[2]; /* reader from each file */ struct line *getnext(); /* forwaror unsqueezer function */ #define RECOGNIZE 0xFF76 /* unlikely pattern */ /* External declarations for USQ feature */ #define NUMVALS 257 /* 256 data values plus SPEOF*/ /* Decoding tree */ struct { int children[2]; /* left, right */ } dnode[NUMVALS - 1]; int bpos; /* last bit position read */ int curin; /* last byte value read */ /* Variables associated with repetition decoding */ int repct; /*Number of times to return value*/ int value; /*current byte value or EOF */ int inch; /* * htbl /* get output pathname if one was given */ patho=NULL; #ifndef UNIX for(ac=argc, av=argv; --ac;) if(**++av == '>' || **av == '+') patho= *av +1; dioinit(&argc, argv); #endif Different=Edit=Unsqueeze=Display=Verbose=FALSE; getit[0]=getc1; getit[1]=getc2; while (--argc && *(cp = *++argv)=='-') { while( *++cp) { switch(tolower(*cp)) { case 'd': Display++; break; case 'e': Edit++; break; case 'u': getit[0]=getcr; Unsqueeze++; break; cash" #include "a:dio.h" struct _buf fin[2]; struct _buf *in0, *in1; #define stdin 0 #define stdout 1 #define stderr 4 char *patho; /* null or name of output file */ /* E-O-F indicator */ #define LAST_TOKE 32765 /* at least 1 less than max positive int */ #define MAXLEN 255 #define HUNKSIZE 8192 /* Size of each circular buffer */ int linno[2]; char *patha, *pathb; /* names of each file */ /* data in the circular buffers is stored in linked form */ struct line { unsigned hash; /* had declarations */ int getchar(); int getc1(); int getc2(); int getcr(); char Different, Verbose, Edit, Display, Unsqueeze; unsigned crc; /* accumulated crc of common lines */ int fudge; char ineof[2]; /* EOF (cpmeof) seen on file input */ /* following really should be automatics, but then that would slow things */ int (*getit[2])(); /* getchar function for each file */ int (*getthis)(); /* getchar function for current file */ char *p, *q, *qq, *qqq, count; /* Definitions and externals f stores pointers to a buncha lines which are sorted when looking * for a match */ #define HASHCHUNK 16 /* # lines of each file to search for initial match */ #define HSIZE 2048 /* total # of lines that the hash table can hold */ struct line *missm[2]; /* last line fetched for htbl */ struct line *htbl[HSIZE]; char bfx[2][HUNKSIZE]; /* circular buffers */ getc1() { return getc(in0); } getc2() { return getc(in1); } main(argc, argv) char **argv; { char i, *cp, **av; int ac; e 'v': Verbose++; break; default: goto usage; } } } if(argc < 1 || argc > 2) { usage: fprintf(stderr,VERSION); fprintf(stderr, "Usage: dif [-dev] filea {fileb,outfile]\n"); fprintf(stderr,"\t-d display lines that match\n"); fprintf(stderr,"\t-e generate Editor script\n"); fprintf(stderr,"\t-u Unsqueeze filea\n"); fprintf(stderr,"\t-v Verbose\n"); exit(1); } if(fopen( patha=argv[0], fin[0]) == ERROR) { fprintf(stderr, "Can't open %s"   , argv[0]); exit(128); } else in0=fin[0]; if(argc==2) { if(fopen( pathb=argv[1], fin[1]) == ERROR) { fprintf(stderr, "Can't open %s", argv[1]); exit(128); } else in1=fin[1]; } else { getit[1]=getchar; pathb= "Standard Input"; } if(Unsqueeze) { getit[0]=getcr; /* switch getchar function */ init_usq(); /* initialize unpacking */ } crc=linno[0]=linno[1]=0; ineof[0]=ineof[1]=FALSE; cdq[0].next=p=bottom[0] = bfx[0]; cdq[1].next=bottom[1]TOKE) { if(strcmp(thislna->text, thislnb->text)) dodiff(); else { crc += thislna->hash; if(Display) printf(" %s", thislna->text); thislna=getnext(thislna); thislnb=getnext(thislnb); } } if(Edit) printf("$a %u\n.\n", crc); if(Different) fprintf(stderr,"Files are different\n"); else { fprintf(stderr,"No differences encountered\n"); if(patho) { unlink(patho); fprintf(stderr,"'%s' Unlinked\n", patho); } } dioflush(); } /* getnext returnlnb:thislna; qqq = qq - (MAXLEN + 4 + sizeof(*fp)); p=fp->next; if(p==NULL) { p=fp; p += sizeof(*fp)+1+strlen(fp->text); #ifdef UNIX p += p % sizeof(int); #endif } if(Verbose) fprintf(stderr,"File %d line %d q=%x qq=%x qqq=%x p=%x\n", n, *number, q, qq, qqq, p ); if(ineof[n]) { fprintf(stderr, "Getline called after E-O-F\n"); fprintf(stderr, "%d %3d fp=%x hash=%04x next=%x p=%x ", n, *number, fp, fp->hash, fp->next, p); fputs(fp->text, stderr); return; itch(*p++ = (*getthis)() ) { case CPMEOF: case 0377: if(Verbose) fprintf(stderr, "EOF on file %d at line %d\n", n, *number); ineof[n]=TRUE; gp->hash = ~0; gp->next = gp; /* link to self */ gp->num = LAST_TOKE; strcpy(gp->text, "**EOF**\n"); fp->next=gp; return; case 012: ++*number; goto gotline; case 015: --p; } fprintf(stderr,"Line %d is too long\n", *number); gotline: *p=0; if(len=p - gp->text return 1; if( (*a)->hash < (*b)->hash) return -1; return (*a)->f - (*b)->f; } dodiff() { register struct line **lp; int quantity, m, l; char keepatit, n, wanta, wantb; Different=TRUE; if(Verbose) fprintf(stderr,"Difference at %d:%d\n", thislna->num, thislnb->num); wanta=wantb=TRUE; lp=htbl; *lp++ =missm[0]=thislna; *lp++ =missm[1]=thislnb; /* * To minimize time in locating the matching lines after small * sections of text, start out by looking at just a =top[0]= bfx[1]; top[1]= bfx[2]; /* not in pascal! */ if(Verbose) for(i=0; i<2; ++i ) fprintf(stderr,"bottom[%d]=%x top=%x\n", i, bottom[i], top[i]); fudge=0; /* initialize magic editing offset */ /* initialize thisln so it won't get in the way of filling buffer */ thislna=thislnb=0; /* get the first line from each and start chain */ getline(0, cdq[0]); thislna=bottom[0]; getline(1, cdq[1]); thislnb=bottom[1]; while( thislna->num != LAST_TOKE | thislnb->num != LAST_s next line unless: eof: return current (its chained to itself); no room in buffer: return NULL; */ struct line *getnext(fp) register struct line *fp; { if(fp->next) return fp->next; /* link to next line */ getline(fp->f, fp); /* end of buffer -get more */ return fp->next; } getline(n, fp) struct line *fp; char n; { struct line *gp; int *number, len; unsigned crck(); number= &linno[n]; getthis=getit[n]; q=top[n]; q -= (MAXLEN + 4 + sizeof(*fp)); qq=n?this} for(;;) { /* check if we need to wrap at end of buffer */ if(p > q) { p=bottom[n]; if(Verbose) fprintf(stderr,"Wrapped: p=%x\n", p); if(qq==0) goto yumyum; /* special case first time */ } /* is the buffer filled up ? */ if(p <= qq && p >= qqq) { /* before thislin ? */ yumyum: if(Verbose) fprintf(stderr,"Buffer Filled\n"); return; } #ifdef UNIX p += p % sizeof(int); #endif gp=p; gp->f=n; for(p=gp->text, count=MAXLEN; --count; ) sw) gp->hash=crck(gp->text, len, 0); else gp->hash = 0; gp->num = *number; fp->next=gp; if(Verbose>3) { fprintf(stderr, "%d %3d gp=%x hash=%04x len=%3d p=%x ", n, *number, gp, gp->hash, len, p); fputs(gp->text, stderr); } fp=gp; /* advance along new chain */ fp->next=NULL; ++p; /* bump pointer past trailing null */ } } /* * Sort htbl first by hashvalue, then by file number */ comp(a,b) struct line **a, **b; { if( (*a)->hash > (*b)->hash) few lines. * If that doesn't work, enlarge the search. */ for(quantity=2,l=HASHCHUNK, keepatit=TRUE; keepatit && (wanta||wantb); l+=l) { if(wanta) for(m=l; --m>=0; ) { if((*lp = getnext(missm[0]))==NULL) { wanta=FALSE; break; } missm[0]= *lp++; /* quit n-o-w if table filled */ if(++quantity==HSIZE) { keepatit=FALSE; goto nowlook; } /* Don't fill up the table with eof's */ if(missm[0]->num==LAST_TOKE) { wanta=FALSE; break; }     } if(wantb) for(m=l; --m>=0; ) { if((*lp = getnext(missm[1]))==NULL) { wantb=FALSE; break; } missm[1]= *lp++; if(++quantity==HSIZE) { keepatit=FALSE; goto nowlook; } if(missm[1]->num==LAST_TOKE) { wantb=FALSE; break; } } nowlook: if(Verbose) fprintf(stderr, "Dodiff Quantity=%d k't=%d w'a=%d w'b=%d\n", quantity, keepatit, wanta, wantb); if(Verbose>2) for(m=0; mf) continue; for(pb=pa+1; pb < pe; ++pb) { if((*pb)->f == 0) continue; if((*pa)->hash != (*pb)->hash) continue; if((*pa)->num > lowa || (*pb)->num > lowb) continue; if((*pa)->next==NULL |num; skipb= lowb - (fp=thislnb)->num; if(Verbose) fprintf(stderr,"Fudge=%d skipa=%d skipb=%d\n", fudge, skipa, skipb); if(skipa) { printf("%d", fudge+thislna->num); if(skipa != 1) { putchar(','); if(lowa==LAST_TOKE) putchar('$'); else printf("%d", fudge + thislna->num + skipa - 1); } fudge -= skipa; } if(skipb) { if(skipa==0 || thislna->num==LAST_TOKE) /* append if no lines to remove */ printf("%da %u\n", thisln printf("+%s", fp->text); } /* advance pointers to matched lines */ thislna= loa; thislnb= lob; return TRUE; } /* *** Stuff for first translation module *** */ #define DLE 0x90 /* *** Stuff for second translation module *** */ #define SPEOF 256 /* special endfile token */ #define LARGE 30000 init_usq() { int i, c; char cc; char *p; int numnodes; /* size of decoding tree */ char origname[14]; /* Original file name without drive */ /* Initialization */ init_cr(); iitialize for possible empty tree (SPEOF only) */ dnode[0].children[0] = -(SPEOF + 1); dnode[0].children[1] = -(SPEOF + 1); /* Get decoding tree from file */ for(i = 0; i < numnodes; ++i) { dnode[i].children[0] = getw(in0); dnode[i].children[1] = getw(in0); } } /* initialize decoding functions */ init_cr() { repct = 0; } init_huff() { bpos = 99; /* force initial read */ } /* Get bytes with decoding - this decodes repetition, * calls getuhuff to decode file stream inddr=%x f=%d h=%4x l=%3d nxt=%x\n", m, htbl[m], htbl[m]->f, htbl[m]->hash, htbl[m]->num, htbl[m]->next); qsort(htbl, quantity, sizeof(p), comp); if(lookferit(quantity)) { return; } } fprintf(stderr,"Can't find match at a:line %d b:line %d\n", thislna->num, thislnb->num); if(Verbose) for(m=0; mf, htbl[m]->hash, htbl[m]->num, htbl[m]->text); exit(1);| (*pb)->next==NULL) continue; if((*pa)->next->hash != (*pb)->next->hash) continue; if(strcmp((*pa)->text, (*pb)->text)) continue; if(strcmp((*pa)->next->text, (*pb)->next->text)) continue; lowa=(*pa)->num; lowb=(*pb)->num; loa= *pa; lob= *pb; } } if(lowa > LAST_TOKE) { return FALSE; } if(Verbose){ fprintf(stderr, "Found match at %d:%d\n", lowa, lowb); fputs(loa->text, stderr); fputs(lob->text, stderr); } if(Edit) { skipa= lowa - thislna->b->num -1, crc); else /* change if old lines gotta go */ printf("c %u\n", crc); for(; fp->num < lowb; fp=getnext(fp)) puts(fp->text); printf(".\n"); fudge += skipb; } else printf("d %u\n", crc); } else { printf("-------- Line %4d of '%s' ----\n",thislna->num, patha); for(fp=thislna; fp->num < lowa; fp=getnext(fp)) printf("---%s", fp->text); printf("++++++++ Line %4d of '%s' ++++\n",thislnb->num, pathb); for(fp=thislnb; fp->num < lowb; fp=getnext(fp)) nit_huff(); if(getw(in0)!=RECOGNIZE) { fprintf(stderr,"%s Not Squeezed\n", patha); exit(1); } /* Process rest of header */ getw(in0); /* ignore checksum ... */ /* Get original file name */ p = origname; /* send it to array */ do { *p = getc(in0); } while(*p++ != '\0'); fprintf(stderr, "(%s -> %s)\n", patha, origname); numnodes = getw(in0); if(numnodes < 0 || numnodes >= NUMVALS) { fprintf(stderr, "%s has invalid decode tree size\n", patha); exit(1); } /* Into byte * level code with only repetition encoding. * * The code is simple passing through of bytes except * that DLE is encoded as DLE-zero and other values * repeated more than twice are encoded as value-DLE-count. */ int getcr() { int c; if(repct > 0) { /* Expanding a repeated char */ --repct; return value; } else { /* Nothing unusual */ if((c = getuhuff()) != DLE) { /* It's not the special delimiter */ value = c; if(value == EOF) repct = LARGE;     return value; } else { /* Special token */ if((repct = getuhuff()) == 0) /* DLE, zero represents DLE */ return DLE; else { /* Begin expanding repetition */ repct -= 2; /* 2nd time */ return value; } } } } /* Decode file stream into a byte level code with only * repetition encoding remaining. */ int getuhuff() { /* Follow bit stream in tree to a leaf*/ inch = 0; /* Start at root of tree */ do { if(++bpos > 7) { if((curin = getc(inFMAP $1*.* F UCAT  FILE CATALOG SYSTEM described by Frank Davidoff 5 Aug 1982 This system is based on files written by Ward Christensen for CPM U/G, Vol. 40. See file CATALOG.DOC for more information. A Submit file has been added by Bob Kowitt of LICA to simplify operation. This system uses files: MAST.CAT (Created by user) RUN.COM (Same as SUBMIT.COM supplied with CPM) CAT.SUB FMAP.COM UCAT.COM CAT.COM CAT2.COM PROCEDURE FOR USE. 1. Using ED, crea0)) == ERROR) return ERROR; bpos = 0; /* move a level deeper in tree */ inch = dnode[inch].children[1 & curin]; } else inch = dnode[inch].children[1 & (curin >>= 1)]; } while(inch >= 0); /* Decode fake node index to original data value */ inch = -(inch + 1); /* Decode special endfile token to normal EOF */ return (inch == SPEOF) ? EOF : inch; } te a MAST.CAT file. Initially, the MAST.CAT file should consist just of those files that are common to many disks and which you do not want repeated in the catalog listing. List these files alphabetically between parentheses, one file to a line. Do not indent any line. Example: (D.COM PIP.COM) 2. Assign each disk to be cataloged, a name and number such as -UTILITY.503. This is best done by typing ED -UTILITY.503 and then le   aving ED by the Q command. The - sign puts the file name at the top of a sorted list. 3. Put the disk containing the 6 files listed above in the A drive(logged on). Put the disk to be cataloged in, say, the B drive. Type RUN CAT B:. If the drive letter is omitted, the A drive disk will be cataloged. This command uses CAT.SUB to run FMAP.COM which creates an alphabetical file list and then runs UCAT.COM which updates MAST.CAT. Subsequent repeats of this para; title 'BISHOW v1.06 - buffered bidirectional file scroll utility' ; ; Ver 1.06 2 Jul 83, Chuck Forsberg ; - added commands for more, mince, vi familiarity. Bad cmd gives help ; ; Ver 1.051, 26 June 83, Dick Mead ; - added "?" for help on commands. ; ; Ver 1.05, 31 May 83, Bruce Ratoff ; - added 'N' (next line) and 'P' (previous line) cmds ; - decreased buffer from 8k to 4k (8k takes too long) ; ; Ver 1.04, 15 May 83, Keith Petersen, W8SDZ ; - fixed bug which caused display past end-of-file ; works on 8080 too) ; ; Ver 1.02, 06 May 83, Lucien Pan, Toronto, Canada ; - fixed some minor bugs ; - returns to ccp w/o warm boot ; - filters form-feeds (useful in .PRN files) ; - scrolls foward/backwards by same number of lines ; - disable/enable cursor during scroll for H-19 ; ; Ver 1.01, 30 Mar 83 - added BDOS function 6. W.F.Mcgee ; ; Ver 1.00, 23 Aug 82 Phil Cary, 748 Kenilworth Parkway, Baton ; Rouge, LA 70808 ; ; BISHOW is a buffered, bidirectional version of SHOW.ASM ; graph will update MAST.CAT by adding and/or deleting files as required by the new contents of the disk. 4. To use the catalog, type: CAT Wildcards can be used to get any desired selection of files and disks. The optional message will be printed at the top of a hard copy printout. Running file CAT2.COM will list all the files in MAST.CAT in alphabetical order in a single column display.  and added bugus eof in case none at file end ; - added strip of high-order bit in line count routine ; - added exit clear of any left-over keyboard character ; ; Ver 1.03, 11 May 83, Keith Petersen, W8SDZ ; - fixed to allow assembly with ASM.COM ; - fixed screen clear bug when crossing read boundries ; - added strip for high-order bit in character before ; printing (needed for WordStar files) ; - improved stack routines ; - fixed bug in console input routine ; - removed Z80 dependant code (nowwhich first appeared in Interface Age, November, 1981. That ; program could only scroll forward in a file, and read ; sectors from disk one at a time as they were sent to the ; console. I used SHOW frequently to take a quick look at a ; file without loading a big text editor, and to examine ; another file with the RUN command while in Wordstar. TYPE ; does not work since it is not a file that Wordstar can load ; and run. ; ; It was annoying when I went past the point I was    looking for ; in a file with SHOW, and could not go backwards. Thus, this ; bidirectional version which uses random access reads. In ; addition, buffering was added so that the number of disk ; reads would be reduced, and moving back and forth in a ; moderate sized file would be speeded up. There is a trade ; off between the size of the buffer and the length of time it ; takes to refill the buffer which should be set to the user's ; preference. ; ; There are two customizing ids to the console as the CP/M ; write console function does. ; ; Just a small contribution to the public domain software as ; partial payment for the many fine and educational programs ; the system has given me. Phil Cary. ; ;Define version number for help message vers equ 1 revs equ 60 ; false equ 0 true equ not false ; ; Operational equates ; maxsec equ 32 ;number of sectors in buffer scroln equ 24 ;number of lines per scroll fulbuf set dskbuf+(maxsec*128) ;need to know end of bufcrr equ fcb+33 ;current record number, random access tpa equ wboot+100h ;transient program area ; ; ASCII equates ; endmsg equ 0 ;null bell equ 7 ;bell lf equ 0ah ;line feed cr equ 0dh ;carriage return eof equ 1ah ;end of file esc equ 1bh ;escape ; org tpa ; jmp start ;skip over next subroutine ; clrscr: if not heath call cdisp db 7eh,1ch,endmsg ;put your screen clear string here endif ; if heath call cdisp ;command to erase screen and home cursor db esc,'E',endmsg ;__both bytes sta fcbcrr+2 ;__and the overflow call clrscr ;erase the screen ; wrtfw0: call filbuf ;fill the disk buffer lxi h,dskbuf ;point to beginning of buffer ; wrtfw1: mov a,m ;get a character cpi eof ;see if eof jz getcmd ;yes, wait for command inx h ;bump pointer ani 7fh ;strip high bit cpi 'L'-40h ;filter form-feeds jz filter ;__commonly found in .PRN files call co ;put it on console cpi cr ;see if end of line jz fwdcnt ;yes, adjust line count ; wrtfw2: lxi dar ; fwdcnt: lda lincnt ;get number of lines displayed inr a ;bump it sta lincnt ;__and store it xchg ;save the buffer pointer lxi h,linmax ;point to max number of line for this pass cmp m ;compare with line count xchg ;restore pointer jnz wrtfw2 ;if not there, continue, else get command xra a ;zero the sta lincnt ;__line count ; getcmd: push h push d push b ; if heath call cdisp db esc,'x5',endmsg ;disable cursor endif ; getcm1: mvi c,6 ;direct console I/O tems in this program. One is ; the equate "maxsec" which sets the buffer size. The other ; is the string in the subroutine "clrscr" just after the org ; statement. This should be changed to the erase screen and ; home cursor sequence for the user's terminal. The program is ; presently set up for an ADM-3A. The program, as written, ; does require a 24 X 80 screen with an erase screen and home ; cursor function. Finally, direct I/O to the console is used ; to avoid echoing the commanfer ; heath equ true ;assemble for H-19 terminal base equ 0 ;standard zero base CP/M ; ; BDOS functions ; conout equ 2 ;console write open equ 15 ;open file readr equ 33 ;read file random access stdma equ 26 ;set dma address ; ; Page zero equates ; wboot equ base ;warm boot entry point bdos equ wboot+5 ;BDOS entry point fcb equ wboot+5ch ;default fcb drive number fcbfn equ fcb+1 ;start of filename fcbft equ fcb+9 ;start of filetype fcbex equ fcb+12 ;current extent number fcb_for H/Z-19 terminal. change as required wait: mvi b,0 ;waste time (may or may not be necessary) ; wait1: xthl ;good time gobbeler! xthl dcr b jnz wait1 endif ; ret ;return from clrscr ; start: lxi h,0 ;get ccp's stack dad sp shld stack ;save old stack for later lxi sp,stack ;set new stack call opnfil ;open file in default fcb ; wrtfwd: xra a ;get a 0 sta lincnt ;store in line count sta fcbex ;zero current extent sta fcbcrr ;zero current record sta fcbcrr+1 ;_,fulbuf ;get end of buffer address mov a,d ;compare high cmp h ;__order bytes jnz wrtfw1 ;if not equal, continuee Hc htt Prufwrtd ptuuuuut, uuuuuuuuuuuuuuuuuuuuuuuu l l l l l l l l l l l l l l l l l l l l l l l l l l l l l l l l l l l l l l l l l l l l l l l l l l l l l l l l l l l l l l l l l l l l l l l l l l l l l l l l l l l l l l l l l l l l l l Hleet call co ;__of control character pop psw ;restore status adi 40h ;mask into displayable char call co ;display filtered control ch mvi e,0ffh ;__set up for input call bdos ora a ;loop till char avail jz getcm1 pop b pop d pop h cpi '1' ; 1 means goto 1st line jz wrtfwd cpi '?' ;help request jz help2 cpi ' ' ; more uses space jz wrtfw1 cpi 'F' ;scroll forward? jz wrtfw1 ;br if yes cpi 'f' jz wrtfw1 ;br if yes cpi 06 ;vi uses ^F jz wrtfw1 cpi 026Q ; mince uses ^V jz wrtfw1 cpi 'B' ;scroll backward? jz wrtbak cpi 'b' jz wrtbak cpi 02 ;vi uses ^B jz wrtbak cpi 'N' ;scroll    next line? jz wrtnxt cpi 'n' jz wrtnxt cpi '+' jz wrtnxt cpi cr ;scroll next line? jz wrtnxt cpi lf jz wrtnxt cpi 'P' ;scroll prev line? jz wrtprv cpi 'p' jz wrtprv cpi '-' jz wrtprv cpi 'C'-40h ;must be exit jz exit ;return control to CCP if yes or cpi 'q' jz exit ;more uses q for quit cpi 'Q' jz exit jmp help2 ;else give a hint ; wrtnxt: lda linmax dcr a ;fool wrtfw1 to only write one line sta lincnt jmp wrtfw1 ; wrtprv: lda linmax ;back up oharacter ani 7fh ;strip high bit dcx h ;decrement buffer cpi cr ;see if end of line jz bakcnt ;__or form-feed cpi 'L'-40h ;__and adjust line count if so jnz wrtbk1 ;else, loop if not ; bakcnt: lda lincnt ;else, get number of lines to move back dcr a ;__and decrement it sta lincnt ;__store it jnz wrtbk1 ;__and loop if not there inx h ;else bump pointer inx h ;__to account for dcx jmp wrtfw1 ;and go write a screen ; filbak: lxi d,maxsec ;get the buffer size lhld seccontinue moving back in file ; filbuf: lxi d,dskbuf ;load start of disk buffer mvi b,maxsec ;number of sectors to resd lxi h,0 ;zero out the shld seccnt ;__number of sectors in buffer ; filbu1: push h ;save all push d ;__registers from push b ;__BDOS clobber mvi c,stdma ;set dma to call bdos ;__disk buffer lxi d,fcb ;set up to read mvi c,readr ;__a record call bdos ;do it ora a ;read OK? lhld fcbcrr ;get current record number inx h ;__bump it shld fcbcrr ;__and : lda fcbfn ;point to first letter of filename cpi ' ' ;anything there? jz help ;no, give help message lxi d,fcb ;file name in default fcb mvi c,open ;set up to open call bdos ;do it cpi 0ffh ;open OK? rnz ;yes call cdisp ;else, give error msg and quit db 'file not found ',endmsg jmp exit1 ;leave msg on screen on exit ; help: call cdisp db 'BISHOW version ' db (vers mod 10)+'0','.' db revs/10+'0',(revs mod 10)+'0',cr,lf db 'Usage: d:bishow d:fn.ft ',cr,lf db endmsg ret ;__and return ; co: push b ;Save the registers push d ;__from bdos push h ;__clobber push psw mov e,a ;set up character mvi c,conout ;__to send to console call bdos ;do it pop psw pop h ;restore pop d ;__the registers pop b ret ; exit: mvi c,11 ;console status call bdos ;--check for any waiting characters ora a ;character waiting? mvi c,1 ;console input cnz bdos ;if so, gobble it up call clrscr ;clear the screen ; if heath call cdisp ;re-enablene screen + 1 line inr a jmp wrtbk0 ; wrtbak: lda linmax ;get screen line count add a ;__multiply by 2 wrtbk0: inr a ;__and add 1 sta lincnt ;__to backup to previous page call clrscr ;clear the screen ; wrtbk1: lxi d,dskbuf ;get address of buffer start mov a,d ;compare high cmp h ;__order bytes jnz wrtbk2 ;continue if not equal mov a,e ;else, compare low cmp l ;__order bytes jnz wrtbk2 ;continue if not equal jmp filbak ;__and go write it ; wrtbk2: mov a,m ;get a cnt ;__and number of sectors last read dad d ;add them xchg ;__and put them in DE lda fcbcrr ;subtract low order byte sub e ;__from current record count sta fcbcrr ;__and store in current record count lda fcbcrr+1 ;same with high order byte sbb d ;__but with borrow jm wrtfwd ;if beyond beginning of file, start over sta fcbcrr+1 ;else, store high order byte call filbuf ;fill the buffer lxi h,fulbuf ;__and point to end of buffer call clrscr ;clear the screen jmp wrtbk2 ;csave it lhld seccnt ;get sectors in buffer inx h ;bump it shld seccnt ;store it pop b pop d pop h jnz rderr ;no, last sector read dcr b ;decrement it rz ;if done return lxi h,128 ;else, add 128 to dad d ;__dma address xchg ;put it in de jmp filbu1 ;read another sector ; ;We only get here if end of file ; rderr: mvi a,eof ;get bogus eof stax d ;save at buffer end in case no eof in file xra a ;get a zero to direct to start of buffer ret ;__on ret ; opnfil jmp exit1 help2: call cdisp db cr,lf,'Commands:',cr,lf db '^F,F,^V,sp=forward page, ^B,B=back page',cr,lf db 'CR,+,N=next line, ' db '-,P=back line, 1=1st line, ^C,Q=exit',cr,lf,endmsg jmp getcmd ; cdisp: xthl ;exchange top of stack and HL ; cdis1: mov a,m ;HL now pointing to db message ora a ;see if 0 at end of message inx h jz cdis2 ;yes, restore stack and return call co ;no, print the character jmp cdis1 ;__and loop ; cdis2: xthl ;get return address on top of stack  cursor db esc,'y5',endmsg endif ; lxi d,fcb ;close file mvi c,16 ;--in case this is MP/M call bdos ; exit1: lhld stack ;get old stack sphl ret ;return to CCP ; ; Memory allocation ; seccnt: dw 0 ;number of sectors read into buffer linmax: db scroln ;number of to write lines on console lincnt: db 0 ;line number on write or move back in buffer ds 60 ;stack area stack: ds 2 ;old stack saved here dskbuf: equ $ ;disk buffer area above the program ; end tpa f stack     ret ;__and return ; co: pusht dcx h ;decrement buffer cpi cr ;see if end of line jz bakcnt ;__or form-feed cpi stack ;get old stack sphl ret ;return to CCP ; ; Memory allocation ; seccnt: dw 0 ;number of sectors read into buffer linmax: db scroln ;number of to write lines on console lincnt: db 0 ;line number on write or move back in buffer ds 60 ;stack area stack: ds 2 ;old stack saved here dskbuf: equ $ ;disk buffer area above the program ; end tpa f stack  ----------------------------------------------------------------- VLIST.DOC 11/10/81 VLIST.COM is a version of MLIST.COM (see MLIST.DOC) which provides for varying the speed of display on the CRT. This is useful because you can skip past the unwanted parts of readable files such as .DOC files, and slow down to a comfortable reading speed when desired. This is much more relaxing to use than CTRL-S to stop start the display. How to use. A>VLIST f-------------------------------  display speed you get from MLIST or TYPE. ----------------------------------edal" to go slowly or speed up. CONTROL - L is the lowest speed display. CONTROL - K is twice as fast as CONTROL - L. CONTROL - J is twice as fast as CONTROL - K. ..or four times as fast as CONTROL - L. CONTROL - H is "high" speed, the normally fast display speed you get from MLIST or TYPE. ---------------------------------- BANK SWITCHING - Tony Drake 1/83 Bank switching is a hardware/software technique used in the Kaypro (and other microcomputers) to allow additional memory to be accessible. Under usual conditions, the Z80 microprocessor can directly address 64K (65,536) bytes of memory. When the bank-switch capability has been built in to the computer, as it has in the Kaypro, new segments of memory, called "banks", can be switched in ovilename.typ ...or wildcards as in MLIST ...then when the program signs on, you may begin using the "accelerator pedal" to go slowly or speed up. CONTROL - L is the lowest speed display. CONTROL - K is twice as fast as CONTROL - L. CONTROL - J is twice as fast as CONTROL - K. ..or four times as fast as CONTROL - L. CONTROL - H is "high" speed, the normally fast display speed you get from MLIST or TYPE. ----------------------------------er the top of old segemnts, used for a while, then the old segments can be returned without "forgetting" anything. The Kaypro has one bank of 16K bytes that can be switched in and out. The normal, unswitched bank is called BANK 0. The optional, switched bank is called BANK 1. Non-Linear Systems (NLS) did not put user memory in BANK 1. The first 2K bytes consists of preprogrammed, permanent memory (ROM) containing special system routines    that are used to control the keyboard, the screen, the disk drives, and the serial and parallel ports. The CP/M operating system uses these routines extensively in running the computer. A programmer can use these routines to his advantage if he wishes to learn how. NLS did not put any memory in the next 10K of this bank. A program written to "read" any of this 10K would find it empty. The last 4K of this bank contains the video displ by turning on bit 7 of the system port. Bits are numbered from right to left, starting with bit 0, so the bank-switch bit is the "highest", or most significant bit (MSB) of the system port. The other bits of the system port are unrelated to bank switching and must not be altered when making the switch. The system port is found at port address 1C (hexidecimal). Using INTEL 8080 Assembly language, the switch to BANK 1 can be made with three mbly language: IN 1CH ;INPUT CURRENT SYSTEM PORT DATA ANI 7FH ;TURN OFF HIGH BIT OUT 1CH ;OUTPUT NEW SYSTEM PORT DATA To switch back to "normal" BANK 0 using ZILOG Z80 Assembly language: IN A,(1CH) ;INPUT CURRENT SYSTEM PORT DATA RES 7,A ;TURN OFF HIGH BIT OUT (1CH),A ;OUTPUT NEW SYSTEM PORT DATA The programmeritching to write directly to the video memory. All hexidecimal codes from 00 to 7F are written to demonstrate the entire displayable character set. to BANK 0.) The program SYSCOPY uses bank switching to copy the system ROM routines out of BANK 1 into normal memory. Here they can more easily be studied by disassembling with DDT. The program VIDEO uses bank sway memory. Any character codes written in this memory automatically show up on the screen in a corresponding position. This is called memory-mapped video. Normally, system routines (in BANK 1) are used to control screen displays, but again, a programmer can write directly to the screen memory if he wishes. Switching BANK 1 with BANK 0 is easy to do, but the programmer must not forget which bank is currently "on". The switch is made  instructions: IN 1CH ;INPUT CURRENT SYSTEM PORT DATA ORI 80H ;TURN ON HIGH BIT OUT 1CH ;OUTPUT NEW SYSTEM PORT DATA Similarily, in ZILOG Z80 Assembly language: IN A,(1CH) ;INPUT CURRENT SYSTEM PORT DATA SET 7,A ;TURN ON HIGH BIT OUT (1CH),A ;OUTPUT NEW SYSTEM PORT DATA To switch back to "normal" BANK 0 using INTEL 8080 Asse must be sure that his bank switch instructions are not in the first 16K of memory, since this memory is switched "out" when BANK 1 is switched "in". (With the instructions switched out, the machine won't know how to get back to BANK 0.) The program SYSCOPY uses bank switching to copy the system ROM routines out of BANK 1 into normal memory. Here they can more easily be studied by disassembling with DDT. The program VIDEO uses bank sw   VLIST.COM ver 1.1 10/16/80!9"J1J*""VLIST ver 1.1 CTL-S pauses, CTL-C aborts Type ^H,^J,^K,^L to vary speed:] ¬++NO FILE NAME SPECIFIED++;S:++FILE NOT FOUND++;DONE;!]!e  --> FILE: XXXXXXXX.XXX ~# !\- T""LIST ver 1.1 CTL-S L@es*P*R}|ڭ!"R*P{zҟ*N-™*R"Rk*R"P!"R*N*P}>*R#"Rɯ292M!@"P"R-<  NO DISKIN FILE$!g~  Ćq>ö §>ö ±>ö >2 > > ~#~> > :    _  ++ABORTED++ *J2h2|:ʒ!\ :\2!\ \ú!\ \!\ \<7=Ɓo& ] 2h2|2~# x Date: 28 February 1982 04:15-EST From: Leor Zolman To: All Re: New BDS C Program to replace CMAC.LIB available BDS C users who write assembly language functions to be linked in with C programs should check out the CASM package I just left. The files are: CASM.C CASM.DOC CASM.SUB With CASM, you no longer need MAC.COM and CMAC.LIB...new versions of DEFF2.ASM and DEFF2A.ASM, using the new .CSM format, will be available soon (the new versions will be shorter). Date: 3 March 1982(squeezed) SAMPLE.CSM CRC = 91 11 The new CASM handles labels more intelligently; undefined labels and multiple definitions are caught by CASM instead of requiring the assembler to stop them. DOC CRC = 1A A1 (normal) CASM.DQC CRC = 7F 63 (squeezed) CASM.COM CRC = EE D1 CASM.SUB CRC = D8 48 DEFF2.CRL CRC = 5E 51 DEFF2.CSM CRC = 82 8B (normal) DEFF2.CQM CRC = 07 B1 (squeezed) DEFF2A.CSM CRC = 00 45 (normal) DEFF2A.CQM CRC = D3 91 xsub casm $1 asm $1 $$pzsz sid $1.hex g0 ; now say "SAVE nnnn $1.crl", where nnnn is the decimal equivalent of the ; hex value printed out next to the "S" error in the above assembly...  M8+~Oq+~Cq++CAN'T LIST A .COM FILE++ìJq+~Bq+~Oq++CAN'T LIST AN .OBJ FILE++ìWʬͺĆq>ö §>ö ±>ö >2 > > ~#~> > :    _  ++ABORTED++ *J2h2|:ʒ!\ :\2!\ \ú!\ \!\ \<7=Ɓo& ] 2h2|2~# x 03:51-EST From: Leor Zolman To: All Re: New BDS C CASM I've uploaded a new version of CASM, and new sources for the BDS C machine language library. The new files are: CASM.C CRC = AD 5A (normal) CASM.CQ CRC = 39 41 (squeezed) CASM.DOC CRC = 1A A1 (normal) CASM.DQC CRC = 7F 63 (squeezed) CASM.COM CRC = EE D1 CASM.SUB CRC = D8 48 DEFF2.CRL CRC = 5E 51 DEFF2.CSM CRC = 82 8B (normal) DEFF2.CQM CRC = 07 B1 (squeezed) DEFF2A.CSM CRC = 00 45 (normal) DEFF2A.CQM CRC = D3 91     ; ; clear screen on kaypro ii ; 24 june 1983 ; Gary K. Berkheiser ; Ergo Software, Inc. ; org 0100h ; start: mvi c,9 ;print string command lxi d,clsmsg ;point to message call 5 ;do bdos ret ;clean exit ; clsmsg: db 1ah,'$' ;message with delimiter ; end ; Plenty Of Files On Line ****** ----> SEE NOTE ON USER COMMAND <---- GETCHAKBHICUNGETC^PUTCHArPUTCȪGETRANSRAN6SRANDNRANCSSETMEMOVME$CAL̄CALLINOUTPEEPOKSLEEPAUSNSETFCaREAĊWRIT OPE΂CLOSCREAUNLINSEE7TEL̷RENAMFABORN FCBADDb EXIw BDO BIOӕ CODEN EXTERN ENDEX TOPOFME EXE EXEC EXECQ SBRˢ RSVST RREA RWRITň RSEE RTEL_ RSREy RCFSIڝ SETJM LONGJM SETPLO CLRPLO-LINEPLOTXTPLO:INDEzGETLINſF == '*' || c == '?') return TRUE; return FALSE; } int match*"*"|O*!Z ##7""":2!6#\! ~W!~w# uzҖ!w# Œn f!?/w#©+~g:oŇ#*1BEHKPUZagp{o&7**:Ozq#Q7*|DM**/><#~# x# > _ #  _    1 !j96  #F#x,~#"*(*>H7*|g}o"zg{o"|g i |""E ! ###""  Wait a few seconds, and type a CR: $(PUT( !xV ###"" PUT7*|&*" 7*:w0 #+| 'z  .   7*~#  +*&! v7:)~:,"s!"u*|V**s[! ~V6*u*+"*"*u#"u"(HRth7:)~:,"s!"u*|*uf*~#="*s*uf#"u*+"*3CVdD7,2q*&:q):<=<=r:qo&.4#UNLINOPE1 7*\   !*, !\&!TELk7:,*:*(}|2q YO:qwJ! {w%9H]& , FNxg>Goy$$!_7*!*&*!:&*!&="&! BL<"e=L=  )6! ) , 7:O*$7*+++:G_*DM!o&****:!+EXEC :,"s!"u*|*u/**s!ѷfUO! ! ~a6*u*+"*"*u#"u*s! N#Fp+q"+EJ]v7:)~:,"s!"u*|*u7*~#?"*s"*u#"u*+"*s! N#Fp+q*3EtG7:,?*:4="4#?*!s#r!^#V .7:,!^#V7:,$!~#fo7:,#!~#fo q#p#!9s#r#s#r! N#F#^#V#"*~#fo7!&:_!og(2;DMV]͌̀m.mv.ḿ.m.]ͫ*!6#]]*!6#]*]:2!! ­2!)!5:!4+3:!! !]! :!B/< !:!]:!G8!d+B!d822!d!d!=͌4+~q374!f!U!:@w#>5!]́!47~/w# ɯ# !ɧ~w# *ɧ~w+ 4ɧw# >ɧ# J6# Uw# ]:2x!!:w:!ffffP "),/$WZ369<?BEHKNQTbjnu}  !$),/369<@DGJMPSVY^aknsw| $),/7:=@EIMRUZ]adgjmru; ; A sample function in CSM format. This is "getchar", out of the std ; library: ; maclib function getchar lda ungetl ;any character pushed back? ora a mov l,a jz gch2 xra a ;yes. return it and clear the pushback sta ungetl ;byte in C.CCC. mvi h,0 ret gch2: push b mvi c,conin call bdos pop b cpi cntrlc ;control-C ? jz base ;if so, reboot. cpi 1ah ;control-Z ? lxi h,-1 ;if so, return -1. rz mov l,a cpi cr ;carriage return? jnz gch3 push b mvi7*!9& 6C#6O#6M/*|E!\&W!\&*|W!!l&!9~#foʇ> +#~u##ixSڱ *EXECL: Too much text $!p!*w#½*:1*!!a{ ѷ!(5CRpvEXEC;7*^#V#zx2:+V+^+*::o&9!$+.1 *&+*|/g}/o#9*&#"z{  "7:)~  7*"*"*"k"**6 #z7:O:GPY|:O:G|`i#z͚8{͚8K|PY##|^|]^%}o}no-|G}Ox**<=ʏÇY:wɷ/<&+059<BFRW[chl"7:**<=:_:w57**k***:'~.ɰ#'#*367**!ɾ #~,*  /46O!j9q  #F#Hx/~#"i&%- w! !Uf! U>2!:G~!~!=!]!6!)͆!4H!36>2!~p!>0*w#"!5ʹ͆U!5! c2c2!]!)!)!=!)*6E#:/<26-#: 2 >0w#:0w#6!]́!z $',147;>CFKNSV\adhknquz}  %0:EQZcgjnqvy|SV\adhknquznu}  !$),/369<@DGJMPSVY^aknsw| $),/7:=@EIMRUZ]adgjmru c,conout ;if so, also echo linefeed mvi e,lf call bdos pop b mvi l,newlin ;and return newline (linefeed).. gch3: mvi h,0 ret endfunc getchar byte in C.CCC. mvi h,0 ret gch2: push b mvi c,conin call bdos pop b cpi cntrlc ;control-C ? jz base ;if so, reboot. cpi 1ah ;control-Z ? lxi h,-1 ;if so, return -1. rz mov l,a cpi cr ;carriage return? jnz gch3 push b mvi    /* CASM.C -- written by Leor Zolman, 2/82 CP/M ASM preprocessor: renders MAC.COM and CMAC.LIB unnecessary. See CASM.DOC for info. Compile and link with: cc casm.c -o -e4800 l2 casm usercode (or) clink casm -f usercode (you can skip linking in 'usercode' if you don't care about being able to specify user areas in filenames for the INCLUDE op, but in that case be sure to comment out the USERAREAS define.) */ #include #define USERAREAS 1 /* comment this ouon */ #define DEFUSER "2/" /* default user area for include files */ #define DEFDISK "C:" /* default disk for include files */ #define CASMEXT ".CSM" /* extension on input files */ #define ASMEXT ".ASM" /* extension on output files */ #define DIRSIZE 512 /* max # of byte in CRL directory */ /* Global data used throughout processing of the intput file: */ char fbuf[BUFSIZ]; /* I/O buffer for main input file */ char incbuf[BUFSIZ]; /* I/O buffer for included file */ char obuf[; /* line number values used for error */ /* reporting. */ char doingfunc; /* true if currently processing a function */ char errf; /* true if an error has been detected */ /* Global data used during the processing of a single function in the source file: */ char *nflist[NFMAX]; /* list of needed functions for a function */ int nfcount; /* number of entries in nflist */ struct { char *labnam; /* name of function label */ char defined; /* whether it has been defiexternal" pseudo ops) */ int argcnt; /* values set by the "parse_line" function */ char *label, *op, *argsp, *args[40]; char *gpcptr; /* general-purpose text pointer */ /* * Open main input file, open output file, initialize needed globals * and process the file: */ main(aarghc,aarghv) char **aarghv; { int i,j,k; char c; puts("BD Software CRL-format ASM Preprocessor v1.46\n"); initequ(); /* initialize EQU table with reserved words */ fcount = 0; /* haven't t if you don't care about */ /* default user areas for included files */ #define TPALOC 0x100 /* base of TPA in your system */ #define EQUMAX 500 /* maximum number of EQU ops */ #define FUNCMAX 100 /* maximum number of functions */ #define NFMAX 100 /* maximum number of external functions in one function */ #define LABMAX 150 /* max number of local labels in one func */ #define TXTBUFSIZE 2000 /* max # of chars for labels and needed function names for a single functiBUFSIZ]; /* I/O buffer for output file */ char *cbufp; /* pointer to currently active input buf */ char *cfilnam; /* pointer to name of current input file */ char nambuf[30], /* filenames for current intput */ nambuf2[30], /* and output files. */ onambuf[30]; char *equtab[EQUMAX]; /* table of absolute symbols */ int equcount; /* # of entries in equtab */ char *fnames[FUNCMAX]; /* list of functions in the source file */ int fcount; /* # of entries in fnames */ int lino,savlinoned yet */ } lablist[LABMAX]; int labcount; /* number of local labels in a function */ char txtbuf[TXTBUFSIZE], /* where text of needed function names */ *txtbufp; /* and function labels go */ char linbuf[150], /* text line buffers */ linsav[150], workbuf[150], pbuf[150], *pbufp; char *cfunam; /* pointer to name of current function */ int relblc; /* relocation object count for a function */ char pastnfs; /* true if we've passed all needed function */ /* declarations ("seen any functions yet */ doingfunc = 0; /* not currently processing a function */ errf = 0; /* no errors yet */ if (aarghc != 2) exit(puts("Usage:\ncasm \n")); /* set up filenames with proper extensions: */ for (i = 0; (c = aarghv[1][i]) && c != '.'; i++) nambuf[i] = c; nambuf[i] = '\0'; strcpy(onambuf,nambuf); strcat(nambuf,CASMEXT); /* input filename */ cbufp = fbuf; /* buffer pointer */ cfilnam = nambuf; /* current filename pointer */ if (fopen(cfilna   m,cbufp) == ERROR) exit(printf("Can't open %s\n",cfilnam)); strcat(onambuf,ASMEXT); /* output filename */ if (fcreat(onambuf,obuf) == ERROR) exit(printf("Can't open %s\n",onambuf)); /* begin writing output file */ fprintf(obuf,"\nTPALOC\t\tEQU\t%04xH\n",TPALOC); lino = 1; /* initialize line count */ while (get_line()) { /* main loop */ process_line(); /* process lines till EOF */ lino++; } if (doingfunc) /* if ends inside a function, error */ abort("File e("\n%s is ready to be assembled.\n",onambuf); } /* * Get a line of text from input stream, and process * "include" ops on the fly: */ int get_line() { int i; if (!fgets(linbuf,cbufp)) {"ny!t" +}}}tljf XX+"ttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttXXXXXXXXXXXXXtt=enent! D eelt soXX}r/g rXXXXXXXXXXXXD f l et=+}eljf XX}"a"XXXXXXXXXXXXXhru u u u u u u u u u u u u u u u u u u u u u u u u u u u u u anino = savlino +  ; /* filename */ argsp[i] = '\0'; *nambuf2 = '\0'; if (*argsp == '<') { /* look for magic delimiters */ #ifdef USERAREAS strcpy(nambuf2,DEFUSER); #endif if (argsp[2] != ':') /* if no explicit disk given */ strcat(nambuf2,DEFDISK); /* then use default */ strcat(nambuf2,argsp+1); if (nambuf2[i = strlen(nambuf2) - 1] == '>') nambuf2[i] = '\0'; } else if (*argsp == '"') { strcpy(nambuf2,argsp+1); if (nambuf2[i = strlen(nambuf2) - 1] == '"') nambunbuf); pbufp = pbuf; if (!isspace(c = *pbufp)) { if (c == ';') return; /* totally ignore comment lines */ label = pbufp; /* set pointer to label */ while (isidchr(*pbufp)) /* pass over the label identifier */ pbufp++; *pbufp++ = '\0'; /* place null after the identifier */ } skip_wsp(&pbufp); if (!*pbufp || *pbufp == ';') return; op = pbufp; /* set pointer to operation mnemonic */ while (isalpha(*pbufp)) pbufp++; /* skip over the op */ if (*pbufp) *pbufpufp; while (isidchr(*pbufp)) pbufp++; if (*pbufp) *pbufp++ = '\0'; } error("Too many operands in this instruction for me to handle\n"); } process_line() { char *cptr, c; int i,j; if (op) { /* check for definitions of global data that will be exempt from relocation when encountered in the argument field of assembly instructions: */ if (streq(op,"EQU") || streq(op,"SET") || (!doingfunc && (streq(op,"DS") || streq(op,"DB") || streq(op,"DW")))) nds, but last function is unterminated\n"); fputs("\nEND$CRL\t\tEQU\t$-TPALOC\n",obuf); /* end of functions */ fputs("SECTORS$ EQU ($-TPALOC)/256+1 ;USE FOR \"SAVE\" !.\n",obuf); putdir(); /* now spit out CRL directory */ fputs("\t\tEND\n",obuf); /* end of file */ putc(CPMEOF,obuf); /* CP/M EOF character */ fclose(cbufp); /* close input file */ fflush(obuf); /* flush and close output file */ fclose(obuf); if (errf) printf("Fix those errors and try again...\n"); else printf1; return get_line(); } else return NULL; } parse_line(); /* not EOF. Parse line */ if (streq(op,"INCLUDE") || /* check for file inclusion */ streq(op,"MACLIB")) { if (cbufp == incbuf) /* if already in an include, */ abort("Only one level of inclusion is supported"); /* error */ if (!argsp) abort("No filename specified"); cbufp = incbuf; /* set up for inclusion */ savlino = lino; lino = 1; for (i = 0; !isspace(argsp[i]); i++) /* put null after */ f2[i] = '\0'; } else strcpy(nambuf2,argsp); if (fopen(nambuf2,cbufp) == ERROR) { if (nambuf2[strlen(nambuf2) - 1] != '.') { strcat(nambuf2,".LIB"); if (fopen(nambuf2,cbufp) != ERROR) goto ok; } printf("Can't open %s\n",nambuf2); abort("Missing include file"); } ok: cfilnam = nambuf2; return get_line(); } return 1; } parse_line() { int i; char c; label = op = argsp = NULL; argcnt = 0; strcpy2(pbuf,linbuf); strcpy2(linsav,li++ = '\0'; /* place null after the op */ /* now process arguments */ skip_wsp(&pbufp); if (!*pbufp || *pbufp == ';') return; argsp = linsav + (pbufp - pbuf); /* set pointer to arg list */ /* create vector of ptrs to all args that are possibly relocatable */ for (argcnt = 0; argcnt < 40;) { while (!isidstrt(c = *pbufp)) if (!c || c == ';') return; else pbufp++; if (isidchr(*(pbufp - 1))) { pbufp++; continue; } args[argcnt++] = pb{ fputs(linbuf,obuf); cptr = sbrk2(strlen(label) + 1); strcpy(cptr,label); equtab[equcount++] = cptr; if (equcount >= EQUMAX) abort( "Too many EQU lines...increase 'EQUMAX' and recompile CASM"); return; } if (streq(op,"EXTERNAL")) { if (!doingfunc) abort( "'External's for a function must appear inside the function"); if (pastnfs) error( "Externals must all be together at start of function\n"); for (i = 0; i < argcnt; i++) { nflist[nfcount++] = txtb    ufp; strcpy(txtbufp,args[i]); bumptxtp(args[i]); } if (nfcount >= NFMAX) { printf("Too many external functions in function \"%s\"\n", cfunam); abort("Change the NFMAX constant and recompile CASM"); } return; } if (streq(op,"FUNCTION")) { if (!fcount) { fputs("\n; dummy external data information:\n",obuf); fputs("\t\tORG\tTPALOC+200H\n",obuf); fputs("\t\tDB\t0,0,0,0,0\n",obuf); } if (doingfunc) { printf("'Function' op encountered in a } if (streq(op,"ENDFUNC") || streq(op,"ENDFUNCTION")) { if (!doingfunc) abort("'Endfunc' op encountered while not in a function"); if (!pastnfs) flushnfs(); /* flush needed function list */ fprintf(obuf,"%s$END\tEQU\t$\n",cfunam); doreloc(); /* flush relocation parameters */ for (i = 0; i < labcount; i++) /* detect undefined labels */ if (!lablist[i].defined) { printf("The label %s in function %s is undefined\n", lablist[i].labnam,cfunam); errf =(!label && !op)) /* if nothing interesting on */ return fputs(linbuf,obuf); /* line, ignore it */ if (!pastnfs) /* if haven't flushed needed */ flushnfs(); /* function list yet, do it */ /* check for possible label */ if (label) { fprintf(obuf,"%s$L$%s\t\tEQU\t$-%s$STRT\n", cfunam, label, cfunam); for (i=0; linbuf[i]; i++) if (isspace(linbuf[i]) || linbuf[i] == ':') break; else linbuf[i] = ' '; if (linbuf[i] == ':') linbuf[i] = ' '; for (i = 0; i } out: if (!op) return fputs(linbuf,obuf); /* if label only, all done */ /* if a non-relocatable op, */ if (norelop(op)) return fputs(linbuf,obuf); /* then we're done */ if (argcnt && doingfunc) for (i = 0; i < argcnt; i++) { if (norel(args[i])) continue; if (gpcptr = isef(args[i])) sprintf(workbuf,"%s$EF$%s-%s$STRT", cfunam,gpcptr,cfunam); else { sprintf(workbuf,"%s$L$%s",cfunam,args[i]); for (j = 0; j < labcount; j++) if (streq(args[i],lablist[tEQU\t$+1-%s$STRT\n", cfunam, relblc++, cfunam); break; } fputs(linbuf,obuf); } /* Test for ops in which there is guanranteed to be no need for generation of relocation parameters. Note that the list of non-relocatable ops doesn't necessarily have to be complete, because for any op that doesn't match, an argument must still pass other tests before it is deemed relocatable. This only speeds things up by telling the program not to bother checking the arguments. */ norelop function.\n"); abort("Did you forget an 'endfunc' op?"); } if (!argcnt) abort("A name is required for the 'function' op"); cfunam = sbrk2(strlen(args[0]) + 1); fnames[fcount++] = cfunam; strcpy(cfunam,args[0]); printf("Processing the %s function... \r",cfunam); doingfunc = 1; txtbufp = txtbuf; labcount = 0; nfcount = 0; pastnfs = 0; fprintf(obuf,"\n\n; The \"%s\" function:\n",cfunam); fprintf(obuf,"%s$BEG\tEQU\t$-TPALOC\n",cfunam); return;  1; } doingfunc = 0; return; } } if (streq(op,"RELOC") || streq(op,"DWREL") || streq(op,"DIRECT") || streq(op,"ENDDIR") || streq(op,"EXREL") || streq(op,"EXDWREL") || streq(op,"PRELUDE") || streq(op,"POSTLUDE") || streq(op,"DEFINE")) error("Old macro leftover from \"CMAC.LIB\" days...\n"); /* No special pseudo ops, so now process the line as a line of assemby code: */ if (streq(op,"END")) return; /* don't allow "end" yet */ if (!doingfunc ||  < labcount; i++) /* check if in label table */ if (streq(label,lablist[i].labnam)) { /* if found, */ if (lablist[i].defined) { /* check for redefinition */ error("Re-defined label:"); printf("%s, in function %s\n", lablist[i].labnam,cfunam); } else lablist[i].defined = 1; goto out; } lablist[i].labnam = txtbufp; /* add new entry to */ lablist[i].defined = 1; /* label list */ strcpy(txtbufp,label); bumptxtp(label); labcount++; j].labnam)) goto out2; lablist[j].labnam = txtbufp; /* add new entry to */ lablist[j].defined = 0; /* label list */ strcpy(txtbufp,args[i]); bumptxtp(txtbufp); labcount++; } out2: replstr(linbuf, workbuf, args[i] - pbuf, strlen(args[i])); if (streq(op,"DW")) { fprintf(obuf,"%s$R%03d\tEQU\t$-%s$STRT\n", cfunam, relblc++, cfunam); if (argcnt > 1) error("Only one relocatable value allowed per DW\n"); } else fprintf(obuf,"%s$R%03d\(op) char *op; { if (streq(op,"MOV")) return 1; if (streq(op,"INR")) return 1; if (streq(op,"DCR")) return 1; if (streq(op,"INX")) return 1; if (streq(op,"DCX")) return 1; if (streq(op,"DAD")) return 1; if (streq(op,"MVI")) return 1; if (streq(op,"DB")) return 1; if (streq(op,"DS")) return 1; if (op[2] == 'I') { if (streq(op,"CPI")) return 1; if (streq(op,"ORI")) return 1; if (streq(op,"ANI")) return 1; if (streq(op,"ADI")) return 1; if (streq(op,"SUI")) return 1; if    (streq(op,"SBI")) return 1; if (streq(op,"XRI")) return 1; if (streq(op,"ACI")) return 1; } if (streq(op,"ORG")) return 1; if (streq(op,"TITLE")) return 1; if (streq(op,"PAGE")) return 1; if (streq(op,"IF")) return 1; if (streq(op,"EJECT")) return 1; if (streq(op,"MACRO")) return 1; return 0; } flushnfs() { int i,j, length; pastnfs = 1; relblc = 0; fputs("\n\n; List of needed functions:\n",obuf); for (i=0; i < nfcount; i++) { strcpy(workbuf,"\t\tDB\t'"); lengf,"\t\tJMP\t%s$STRTC-%s$STRT\n",cfunam,cfunam); } fprintf(obuf,"%s$EF$%s\tEQU\t%s$STRT\n",cfunam,cfunam,cfunam); for (i=0; i < nfcount; i++) fprintf(obuf,"%s$EF$%s\tJMP\t0\n",cfunam,nflist[i]); fprintf(obuf,"\n%s$STRTC\tEQU\t$\n",cfunam); } doreloc() { int i; fputs("\n; Relocation parameters:\n",obuf); fprintf(obuf,"\t\tDW\t%d\n",relblc); for(i = 0; i < relblc; i++) fprintf(obuf,"\t\tDW\t%s$R%03d\n",cfunam,i); fputs("\n",obuf); } putdir() { int i,j, length; int byte if (bytecount > DIRSIZE) { printf("CRL Directory size will exceed 512 bytes;\n"); printf("Break the file up into smaller chunks, please!\n"); exit(-1); } } initequ() { equtab[0] = "A"; equtab[1] = "B"; equtab[2] = "C"; equtab[3] = "D"; equtab[4] = "E"; equtab[5] = "H"; equtab[6] = "L"; equtab[7] = "M"; equtab[8] = "SP"; equtab[9] = "PSW"; equtab[10]= "AND"; equtab[11]= "OR"; equtab[12]= "MOD"; equtab[13]= "NOT"; equtab[14]= "XOR"; equtab[15]= "SHL"; equt: 1; } skip_wsp(strptr) /* skip white space at *strptr and modify the ptr */ char **strptr; { while (isspace(**strptr)) (*strptr)++; } strcpy2(s1,s2) /* copy s2 to s1, converting to upper case as we go */ char *s1, *s2; { while (*s2) *s1++ = toupper(*s2++); *s1 = '\0'; } /* General-purpose string-replacement function: 'string' is pointer to entire string, 'insstr' is pointer to string to be inserted, 'pos' is the position in 'string' where 'insstr' is to bort(msg) char *msg; { error(msg); putchar('\n'); if (cbufp == incbuf) fclose(incbuf); fclose(fbuf); exit(-1); } sbrk2(n) /* allocate storage and check for out of space condition */ { int i; if ((i = sbrk(n)) == ERROR) abort("Out of storage allocation space\n"); return i; } bumptxtp(str) /* bump txtbufp by size of given string + 1 */ char *str; { txtbufp += strlen(str) + 1; if (txtbufp >= txtbuf + (TXTBUFSIZE - 8)) abort("Out of text space. Increase TXTBUFSIZE and recth = strlen(nflist[i]); length = length < 8 ? length : 8; for (j = 0; j < length - 1; j++) workbuf[6+j] = nflist[i][j]; workbuf[6+j] = '\0'; fprintf(obuf,"%s','%c'+80H\n",workbuf,nflist[i][j]); } fputs("\t\tDB\t0\n",obuf); fputs("\n; Length of body:\n",obuf); fprintf(obuf,"\t\tDW\t%s$END-$-2\n",cfunam); fputs("\n; Body:\n",obuf); fprintf(obuf,"%s$STRT\tEQU\t$\n",cfunam); if (nfcount) { fprintf(obuf,"%s$R%03d\tEQU\t$+1-%s$STRT\n", cfunam,relblc++,cfunam); fprintf(obucount; bytecount = 0; fputs("\n\t\tORG\tTPALOC\n\n; Directory:\n",obuf); for (i = 0; i < fcount; i++) { strcpy(workbuf,"\t\tDB\t'"); length = strlen(fnames[i]); length = length < 8 ? length : 8; for (j = 0; j < length - 1; j++) workbuf[6+j] = fnames[i][j]; workbuf[6+j] = '\0'; fprintf(obuf,"%s','%c'+80H\n",workbuf,fnames[i][j]); fprintf(obuf,"\t\tDW\t%s$BEG\n",fnames[i]); bytecount += (length + 2); } fputs("\t\tDB\t80H\n\t\tDW\tEND$CRL\n",obuf); bytecount += 3; ab[16]= "SHR"; equcount = 14; } int isidchr(c) /* return true if c is legal character in identifier */ char c; { return isalpha(c) || c == '$' || isdigit(c) || c == '.'; } int isidstrt(c) /* return true if c is legal as first char of idenfitier */ char c; { return isalpha(c); } int streq(s1, s2) /* return true if the two strings are equal */ char *s1, *s2; { if (*s1 != *s2) return 0; /* special case for speed */ while (*s1) if (*s1++ != *s2++) return 0; return (*s2) ? 0 e inserted 'lenold' is the length of the substring in 'string' that is being replaced. */ replstr(string, insstr, pos, lenold) char *string, *insstr; { int length, i, j, k, x; length = strlen(string); x = strlen(insstr); k = x - lenold; i = string + pos + lenold; if (k) movmem(i, i+k, length - (pos + lenold) + 1); for (i = 0, j = pos; i < x; i++, j++) string[j] = insstr[i]; } error(msg) char *msg; { printf("\n\7%s: %d: %s ",cfilnam,lino,msg); errf = 1; } abompile CASM"); } int norel(id) /* return true if identifier is exempt from relocatetion */ char *id; { if (isequ(id)) return 1; return 0; } int isequ(str) /* return true if given string is in the EQU table */ char *str; { int i; for (i = 0; i < equcount; i++) if (streq(str,equtab[i])) return 1; return 0; } char *isef(str) /* return nflist entry if given string is an external */ char *str; /* function name */ { int i; for (i = 0; i < nfcount; i++) if (streq(str    ,nflist[i])) return nflist[i]; return 0; } nam,cfunam,cfunam); for (i=0;return 1; return 0; } int isequ(str) /* return true if given string is in the EQU table */ char *str; { int i; for (i = 0; i < equcount; i++) if (streq(str,equtab[i])) return 1; return 0; } char *isef(str) /* return nflist entry if given string is an external */ char *str; /* function name */ { int i; for (i = 0; i < nfcount; i++) if (streq(str The CASM.C Assembly-language-to-CRL-Format Preprocessor For BDS C v1.46 March 3, 1982 Leor Zolman BD Software 33 Lothrop st. Brighton, Massachussetts 02135 The files making up the CASM package are as follows: CASM.C Source file for CASM program CASM.SUB Submit file for p Research's macro assembler (MAC.COM) in order to work. This was especially bad because MAC, if not already owned, cost almost as much as BDS C to purchase. This document describes the program "CASM", which I am placing in the public domain. CASM is a preprocessor that takes, as input, an assembly language source file of type ".CSM" (mnemonic for C aSseMbly language) in a format much closer to "vanilla" assembly language than the bizarre craziness of CMAC.LIB, and writes out an ".ASMsimilarly-named labels to exist in different functions. The pseudo-operations that CASM recognizes as special control commands within a .CSM file are as follows: FUNCTION There is no need to specify a directory of included functions at the start of a .CSM file. Each function must begin with "function" pseudo-op, where is the name that will be used for the functiod the list may be spread over as many "external" lines as necessary. Note that for the current version of BDS C, only function names may appear in "external" lines; data names (e.g. for external variables defined in C programs) cannot be placed in "external" statements. ENDFUNC (or) ENDFUNCTION This op (both forms are equivalenerforming entire conversion of CSM file to CRL CASM.DOC This file USERCODE.C, Library for taking user area prefixes on filenames USERCODE.CRL for input files (optional). Also needed: ASM.COM DDT.COM (or SID.COM) Description: ------------ The only means previously provided to BDS C users for creating relocatable object modules (CRL files) from assembly language programs was a painfully obscure macro package (CMAC.LIB) that required Digital" file which may then be assembled by the standard, FREE, CP/M assembler (ASM.COM). CASM automatically recognizes which assembly language instructions require relocation parameters and inserts the appropriate pseudo-operations and extra opcodes into the output file to cause that file to properly assemble directly into CRL format. In addition, some rudimentary logic checks are performed; doubly-defined and/or undefined labels are detected and reported, with the feature of allowing n in the .CRL file directory. No other information should appear on this line. EXTERNAL If a function calls other C or assembly-coded functions, an "external" pseudo-op naming these other functions must follow immediately after the "function" 1 op. One or more names may appear in the list, ant) must appear after the end of the code for a particular function. The name of the function need not be given as an operand. The three pseudo-ops just listed are the ONLY pseudo-ops that need to appear among the assembly language instructions of a ".CSM" file, and at no time do the assembly instruction themselves need to be     altered for relocation, as was the case with CMAC.LIB. INCLUDE (or) INCLUDE "filename" This op causes the named file to be inserted at the current line of the output file. If the filename is enclosed in angle brackets (i.e., ) then a default user area and logical drive are assumed to contain the named file (the specific de recognized by CASM and not interpreted as undefined local forward references, which would cause CASM to generate relocation parameters for those instructions having run-time package routine names as operands. Note that the pseudo-op MACLIB is equivalent to INCLUDE and may be used instead. Additional notes and bugs: 0. If a label ction, CASM assumes that symbol is relocatable and generates a relocation parameter for the instruction. 2. INCLUDE and MACLIB only work for one level of inclusion. 3. When a relocatable value needs to be specified in a "DW" op, then it must be the ONLY value given in that particular DW statement, or else relocation will not be properly handled. 4. Characters used in symbol names should be restricted to alphanumeric characters; the dollar sign ($) is uence "!.", specifically so that the line will be flagged as an error. The user may then look at the value printed out at the left margin to see exactly how many 256-byte blocks need to be saved; this is the value to be used with the "SAVE" command. The reason that "LOAD" cannot be used is that CASM puts out the code to generate the CRL File directory at the END of the ASM file, using ORG to set the location counter back to the base of the TPA, and the "LOAD" comM file to a .CRL file. For a file named "FOO.CSM", just say: submit casm foo and enter the "SAVE" command just the way says when all is done. 3 t were LOADed, right? 6. The CASM.SUB submit file may be used to perform the entire procedure of converting a .CSfaults for your system may be custimzed by changing the appropriate defines in CASM.C). If the name is enclosed in quotes, than the current drive and user area are searched. Note that you'll usually want to include the file BDS.LIB at the start of your .CSM file, so that names of routines in the run-time package are appears on an instruction, it MUST begin in column one of the line. If a label does not begin in column one, CASM will not recognize it as a label and relocation will not be handled correctly. 1. Forward references to EQUated symbols in executable instructions are not allowed, although forward references to relocatable symbols are OK. The reason for this is that CASM is a one-pass preprocessor, and any time a previously unknown symbol is encountered in an instrualso allowed, but might lead to a conflict with labels generated by CASM. 2 5. The .HEX file produced by ASM after assembling the output of CASM cannot be converted into a binary file by using the LOAD.COM command; instead, DDT or SID must be used to read the file into memory, and then the CP/M "SAVE" command must be issued to save the file as a .CRL file. CASM inserts a line into the ASM file ending in the character seqmand aborts with the cryptic message "INVERTED LOAD ADDRESS" when out-of-sequence data like that is encountered. Rather than require CASM to write out the directory into a new file and append the entire previous output onto the end of the directory, I require the user to have to enter a SAVE command. What the heck; you'd have to rename the file anyway if it were LOADed, right? 6. The CASM.SUB submit file may be used to perform the entire procedure of converting a .CS    ; ; BD Software C Standard Library Machine Language Functions ; Written by Leor Zolman ; v1.46, 3/15/82 ; ; This file is in "CSM" format; to convert to CRL format, ; use CASM.SUB in conjunction with CASM.COM, ASM.COM and DDT.COM. ; ; Functions appearing in this file: ; ; getchar kbhit ungetch putchar putch gets rand srand ; srand1 nrand csw setmem movmem call calla inp ; outp peek poke sleep pause setfcb read write ; open close creat unlink seek tell rename fabort ; fcbaddr exit bdos bios coinefeed mvi e,lf call bdos pop b mvi l,newlin ;and return newline (linefeed).. gch3: mvi h,0 ret ENDFUNC FUNCTION kbhit lda ungetl ;any character ungotten? mvi h,0 mov l,a ora a rnz ;if so, return true push b mvi c,cstat ;else interrogate console status call bdos pop b ora a ;0 returned by BDOS if no character ready lxi h,0 rz ;return 0 in HL if no character ready inr l ;otherwise return 1 in HL ret ENDFUNC kbhit FUNCTION ungetch lda ungetl mov ho the call bdos ; character to the screen, alas) cpi cntrlc ;is it control-C? jz base ;if so, abort and reboot pop b ;else ignore it. ret ENDFUNC FUNCTION putch call ma1toh push b mvi c,conout mov e,a cpi newlin jnz putch1 ;if not newline, just put it out mvi e,cr ;else put out CR-LF call bdos mvi c,conout mvi e,lf putch1: call bdos pop b ret ENDFUNC FUNCTION gets call ma1toh ;get destination address push b ;save BC push h push h lxi h,-150 ;use spacv a,m stax d inx h inx d dcr b jmp copyl gets2: xra a ;store terminating null stax d pop h ;return buffer address in HL pop b ret ENDFUNC FUNCTION rand lhld rseed xchg mvi a,48h ana e jz rand1 jpe rand1 stc rand1: lhld rseed+2 mov a,h ral mov h,a mov a,l ral mov l,a shld rseed+2 mov a,d ral mov h,a mov a,e ral mov l,a shld rseed mov a,h ani 7fh mov h,a ret ENDFUNC FUNCTION srand call ma1toh mov a,h ora l jz srand2dend externs endext topofmem ; exec execl execv sbrk rsvstk ; maclib bds FUNCTION getchar lda ungetl ;any character pushed back? ora a mov l,a jz gch2 xra a ;yes. return it and clear the pushback sta ungetl ;byte in C.CCC. mvi h,0 ret gch2: push b mvi c,conin call bdos pop b cpi cntrlc ;control-C ? jz base ;if so, reboot. cpi 1ah ;control-Z ? lxi h,-1 ;if so, return -1. rz mov l,a cpi cr ;carriage return? jnz gch3 push b mvi c,conout ;if so, also echo ll,a push h call ma2toh sta ungetl pop h mvi h,0 ret ENDFUNC ungetch FUNCTION putchar call ma1toh ;get character in A push b mvi c,conout cpi newlin ;newline? jnz put1 ;if not, just go put out the character mvi e,cr ;else...put out CR-LF call bdos mvi c,conout mvi a,lf put1: mov e,a call bdos put2: mvi c,cstat ;now, is input present at the console? call bdos ora a jnz put3 pop b ;no...all done. ret put3: mvi c,conin ;yes. sample it (this will always ece below stack for reading line dad sp push h ;save buffer address mvi m,88h ;Allow a max of about 135 characters mvi c,getlin xchg ;put buffer addr in DE call bdos ;get the input line mvi c,conout mvi e,lf ;put out a LF call bdos pop h ;get back buffer address inx h ;point to returned char count mov b,m ;set B equal to char count inx h ;HL points to first char of line pop d ;DE points to start destination area copyl: mov a,b ;copy line to start of buffer ora a jz gets2 mo shld rseed shld rseed+2 ret srand2: lxi d,stg1 push b mvi c,9 call bdos lxi h,0bdbdh srand3: push h mvi c,11 call bdos pop h inx h inx h inx h ani 1 jz srand3 shld rseed shld rseed+2 mvi c,conout mvi e,cr call bdos mvi c,conout mvi e,lf call bdos mvi c,conin ;clear the character call bdos pop b ret stg1: db 'Wait a few seconds, and type a CR: $' ENDFUNC FUNCTION srand1 EXTERNAL puts call ma1toh push h call puts ;print prompt string     pop h push b lxi h,5678h sr1a: push h mvi c,cstat call bdos pop h inx h inx h inx h ora a jz sr1a shld rseed shld rseed+2 pop b ret ENDFUNC FUNCTION nrand EXTERNAL puts call arghak lhld arg1 ;get n (1st arg) mov a,h ana l cpi 255 ;was it -1 (set seed) ? jnz nrand1 lhld arg2 ;copy seed shld seed lhld arg3 shld seed+2 lhld arg4 shld seed+4 ret ;all done nrand1: push b mov a,h ;look at first arg again ora l jnz nrand3 ;is it 0 (randomi sta seed ;lsb of SEED must be 1 mvi b,6 ;clear 6 PROD bytes to 0 lxi h,prod randm1: mvi m,0 inx h dcr b jnz randm1 lxi b,6 ;set byte counter randm2: lxi h,plier-1 dad b ;make addr of lsb of PLIER mov a,m ;PLIER byte push b ;save byte counter mvi b,8 ;set bit counter randm3: mov d,a ;save PLIER byte lxi h,prod ;shift whole PROD left one bit mvi c,6 xra a randm4: mov a,m ;get byte ral ;shift left mov m,a ;put byte inx h dcr c jnz randm4 mov a,d ;recover Pcma aci 0 mov m,a inx h inx d dcr b jnz randm7 dcx h ;put the two high order bytes mov a,m ;into HL for return to C, not ani 7fh ;neglecting to zero the high mov h,a ;order bit so a positive int lda seed+4 ;is returned mov l,a pop b ret plier: db 0c5h,87h,1 db 0eh,9ah,0e0h seed: db 1,0,0,0,0,0 prod: db 0,0,0,0,0,0 ENDFUNC FUNCTION csw in 255 mov l,a mvi h,0 ret ENDFUNC FUNCTION setmem call arghak push b lhld arg2 xchg lhld arg1 lda ar0edh,0b0h ;yes. do block move. pop b ret ;and done. m8080h: mov a,m stax d inx h inx d dcx b mov a,b ora c jnz m8080h pop b ret tailf: dcx b ;tail first. Compute new source dad b ;and destination addresses xchg dad b xchg inx b mvi a,2 ;test for Z80 inr a jpe m8080t ;Z80? db 0edh,0b8h ;yes. do block move. pop b ret m8080t: mov a,m stax d dcx h dcx d dcx b mov a,b ora c jnz m8080t pop b ret cmphd: mov a,h cmp d rnz mov a,l cmpcalla2: mov l,a ;put A value in HL mvi h,0 ;clear high byte pop b ret ENDFUNC FUNCTION inp call ma1toh sta iohack+1 ;store as arg to ram area input subroutine call iohack ;call the subroutine to get value mov l,a ;and put into HL mvi h,0 ret ENDFUNC FUNCTION outp call ma1toh ;get port number sta iohack+4 ;store as arg to ram area output subroutine call ma2toh ;get data byte call iohack+3 ;output it ret ENDFUNC FUNCTION peek peek: call ma1toh mov l,m mvize)? lhld arg2 push h ;yes. print out string call puts ;call puts pop d lxi h,5a97h ;yes. start w/something odd nrand2: push h mvi c,cstat ;interrogate console status call bdos pop h inx h ;and keep it odd inx h ;and growing ora a jz nrand2 ;until user types something. shld seed ;then plaster the value all over the shld seed+2 ;seed. shld seed+4 pop b ret nrand3: lda seed ;now compute next random number. from this ori 1 ; point on, the code is that of Prof. Paul Gans LIER byte ral ;look at current high bit jnc randm6 ;0 means no add cycle push psw ;add SEED to PROD xra a mvi c,6 lxi h,prod lxi d,seed randm5: ldax d adc m mov m,a inx h inx d dcr c jnz randm5 pop psw randm6: dcr b ;test bit counter jnz randm3 ;go cycle more bits pop b ;recover byte counter dcr c ;test it jnz randm2 ;go process more bytes mvi b,6 ;complement PROD, add 1 to it, lxi h,seed ;and transfer it to SEED. lxi d,prod xra a cmc randm7: ldax d g3 mov c,a inx d setm2: dcx d mov a,d ora e jnz setm3 pop b ret setm3: mov m,c inx h jmp setm2 ENDFUNC FUNCTION movmem call arghak lhld arg3 ;get block length mov a,h ora l rz ;do nothing if zero length push b mov b,h mov c,l ;set BC to length lhld arg2 ;get dest addr xchg ;put in DE lhld arg1 ;get source addr in HL call cmphd ;if source < dest, do tail-first jc tailf ;else do head-first headf: mvi a,2 ;test for Z-80 inr a jpe m8080h ;Z80? db  e ret ENDFUNC FUNCTION call call arghak push b lhld arg5 xchg lhld arg4 mov b,h mov c,l lda arg2 lxi h,call2 push h lhld arg1 push h lhld arg3 ret call2: pop b ret ENDFUNC FUNCTION calla call arghak push b lhld arg5 ;get de value xchg lhld arg4 ;get bc value mov b,h mov c,l lda arg2 ;get a value lxi h,calla2 ;get return address push h ;push it lhld arg1 ;get address of routine push h lhld arg3 ;get hl value ret ;call routine  h,0 ret ENDFUNC peek FUNCTION poke call arghak lhld arg1 lda arg2 mov m,a ret ENDFUNC FUNCTION sleep call ma1toh push b inx h sl1: dcx h mov a,h ora l jnz sl1a pop b ret sl1a: lxi d,10000 sl2: dcx d mov a,d ora e jnz sl2 push h mvi c,cstat call bdos ora a pop h jz sl1 push h mvi c,conin call bdos cpi cntrlc jz base pop h jmp sl1 ENDFUNC FUNCTION pause push b paus1: mvi c,cstat call bdos ora a jz paus1 pop b re   t ENDFUNC FUNCTION setfcb call arghak push b lhld arg2 ;get pointer to name text igsp: mov a,m inx h cpi ' ' jz igsp cpi tab jz igsp dcx h xchg ;set DE pointing to 1st non-space char lhld arg1 ;get --> fcb area call setfcb ; do it lxi h,0 ;all OK. pop b ret ENDFUNC FUNCTION read call arghak lda arg1 call fgfd jc error ;error if illegal fd mov a,m ani 2 ;open for read? jz error ;error if not push b lda arg1 call fgfcb shld tmp2 ;tmp2 will hod3: lxi h,32 ;yes. are we on extent boundary? dad d ;if so, adjust for CP/M's stupidity here mov a,m ;by turning an 80h sector count into 00h. cpi 80h jnz read4 mvi m,0 ;yes. reset nr to 0...CP/M leaves it at 80h! read4: lhld tmp2a read5: pop b ret read6: lhld arg3 dcx h shld arg3 lhld arg2 lxi d,128 dad d shld arg2 lhld tmp2a inx h shld tmp2a jmp read2 ENDFUNC FUNCTION write call arghak lda arg1 call fgfd jc error mov a,m ani 4 jz error push b ldror? lhld tmp2a ;if so, return # of successfully written jnz writ3 ; sectors. inx h ; else bump successful sector count, shld tmp2a lhld arg3 ; debump countdown, dcx h shld arg3 jmp writ1 ; and go try next sector writ3: pop b ret ENDFUNC FUNCTION open call arghak xra a call fgfcb ;any fcb's free? jc error ;if not, error sta tmp xchg lhld arg1 xchg push b call setfcb mvi c,openc call bdos cpi errorv ;successful open? pop b jz error ;if not, error i d,fcb call bdos cpi errorv pop b jz error lxi h,2 push h lhld arg1 push h call open pop d pop d ret ENDFUNC creat FUNCTION unlink call ma1toh push b xchg lxi h,fcb call setfcb mvi c,delc call bdos lxi h,0 pop b ret ENDFUNC FUNCTION seek EXTERNAL tell call arghak ;copy arguments to args area lda arg1 call fgfcb jc error ;error if file not open push b push h ;save fcb address lhld arg1 push h call tell ;get r/w pointer positi3: pop d pop b jmp error seek4: lda tmp mov m,a push d mvi c,openc ;and open new one. call bdos seek5: pop d cpi errorv jz seek3 lxi h,32 ;and set nr field dad d pop d mov a,e ani 7fh mov m,a xchg ;return new sector # in HL pop b ret ENDFUNC FUNCTION tell call ma1toh ;get fd value in A call fgfcb jc error push b lxi d,12 dad d mov b,m ;put extent # in B lxi d,20 dad d mov c,m ;put sector # in C xra a ;rotate extent right one bit, old b0 --> ld dma addr lxi h,0 ;count of # of successful sectors read shld tmp2a ; will be kept at tmp2a read2: lhld arg3 ;done? mov a,h ora l jz read4 read2a: lhld arg2 ;else read another sector xchg ;DE is dma addr mvi c,sdma call bdos ;set DMA lhld tmp2 xchg ;DE is fcb addr mvi c,reads push d ;save de so we can fudge nr field if call bdos ;we stop reading on extent boundary... pop d ; CP/M sucks! cpi 2 pop b jz error ;if error, abort push b cpi 1 jnz read6 ;EOF? reaa arg1 call fgfcb shld tmp2 lxi h,0 shld tmp2a lxi d,tbuff ;80 for normal CP/M, else 4280 mvi c,sdma call bdos writ1: lhld arg3 ;done yet? mov a,h ora l lhld tmp2a ;if so, return count jz writ3 lhld arg2 ;else copy next 128 bytes down to tbuff lxi d,tbuff ;80 for normal CP/M, else 4280 mvi b,128 writ2: mov a,m stax d inx h inx d dcr b jnz writ2 shld arg2 ;save -> to next 128 bytes lhld tmp2 ;get addr of fcb xchg mvi c,writs ;go write call bdos ora a ;erlda tmp call fgfd ;get HL pointing to fd table entry lda arg2 ora a ;open for read? mvi d,3 jz open1 dcr a mvi d,5 jz open1 ;write? dcr a jnz error ;else must be both or bad mode. mvi d,7 open1: mov m,d lda tmp mov l,a mvi h,0 ret ENDFUNC FUNCTION close jmp close ;jump to the close routine in C.CCC ENDFUNC FUNCTION creat EXTERNAL unlink,open call arghak lhld arg1 push b push h call unlink ;erase any old versions of file pop d mvi c,creatc lxon for the file pop d xchg ;put present pos in DE lda arg3 lhld arg2 ;get offset in HL ora a ;absolute offset? jz seek2 ;if so, offset is new position dad d ;else add offset to current position seek2: mov a,l ;convert to extent and sector values rlc mov a,h ral ani 7fh sta tmp xthl lxi d,12 push h dad d cmp m ;jumping over extent boundary? jz seek5 xthl ;yes. xchg mvi c,closec ;close old extent push d call bdos pop d pop h cpi errorv jnz seek4 seekCarry mov a,b rar mov h,a ;rotated value becomes high byte of tell position mvi a,0 ;rotate b0 of extent into A rar mov b,a ;save rotated extent number in B add c ;add rotated extent number to sector number mov l,a ;and result becomes low byte of tell position mov a,c ;if both rotated extent # and sector # has bit 7 hi, ana b ;then the sum had an overflow, so... jp tell2 inr h ;bump position number by 256 tell2: pop b ;and all done. ret ENDFUNC FUNCTION rename call arghak     push b renam: lhld arg1 xchg lxi h,wfcb call setfcb lhld arg2 xchg lxi h,wfcb+16 call setfcb lxi d,wfcb mvi c,renc call bdos pop b cpi errorv jz error lxi h,0 ret wfcb: ds 53 ENDFUNC FUNCTION fabort call ma1toh call fgfd jc error mvi m,0 ;clear entry in fd table lxi h,0 ret ENDFUNC FUNCTION fcbaddr call ma1toh call fgfd ;is it an open file? jc error call ma1toh call fgfcb ;get fcb addr in HL ret ENDFUNC FUNCTION exit jmp exit ENter lhld arg2 ;get value to be put in BC mov b,h ;and put it there mov c,l lxi h,retadd ;where call to bios will return to xthl ;get address of vector in HL pchl ;and go to it... retadd: mov l,a ;all done. now put return value in HL mvi h,0 pop b ret ;and return to caller ENDFUNC FUNCTION codend lhld codend ret ENDFUNC FUNCTION externs lhld extrns ret ENDFUNC FUNCTION endext lhld freram ret ENDFUNC FUNCTION topofmem lhld base+6 lda tpa ;check f ;clean up stack pop d ret ENDFUNC FUNCTION execl call arghak push b lhld arg1 xchg lxi h,-60 ;compute &nfcb for use here dad sp push h ; save for much later (will pop into BC) push h ;make a few copies for local use below push h call setfcb ;set up COM file for execl-ing pop h ;get new fcb addr lxi b,9 ;set extension to COM dad b mvi m,'C' inx h mvi m,'O' inx h mvi m,'M' pop d ;get new fcb addr again mvi c,openc ;open the file for reading call bdos  call setfcb lxi d,tbuff+1 ;now construct command line: xra a ; zero tbuff+1 just in case there stax d ; are no arg strings lxi h,8 ;get pointer to 1st arg string in HL dad sp ; by offsetting 4 objects from the current SP mvi b,0 ;char count for com. line buf. excl1: push h ;and construct command line mov a,m ;get addr of next arg string pointer inx h mov h,m mov l,a ;0000 indicates end of list. ora h ;end of list? jz excl3 mvi a,' ' ;no. install next string dcx h exclof command line mov m,b ;at location tbuff excl3a: lxi d,code0 ;copy loader down to end of tbuff lxi h,tpa-42 mvi b,42 ;length of loader excl4: ldax d mov m,a inx d inx h dcr b jnz excl4 pop b ;get fcb pointer in BC ;reset the SP: lhld base+6 ;get BDOS pointer in HL lda tpa ;look at first op byte of run-time pkg cpi 31h ;begin with "lxi sp,"? jnz go0 ;if so, use the same value now... lhld tpa+1 ;else get special SP value jmp go1 go0: cpi 21h ;begin with "lxi h" (thDFUNC FUNCTION bdos call arghak push b lda arg1 ;get C value mov c,a lhld arg2 ;get DE value xchg ;put in DE call bdos ;make the bdos call pop b ret ;and return to caller ENDFUNC FUNCTION bios call arghak push b lhld base+1 ;get addr of jump table + 3 dcx h ;set to addr of first jump dcx h dcx h lda arg1 ;get function number (1-85) mov b,a ;multiply by 3 add a add b mov e,a ;put in DE mvi d,0 dad d ;add to base of jump table push h ;and save for laor "NOBOOT" hackery cpi 21h ; "lxi h" at start of C.CCC (as inserted by NOBOOT)? dcx h ;if CCC doesn't begin with "lxi h," then top of rnz ;memory is just below the base of the bdos lxi d,-2100 ;else subtract CCP size (plus little more for good dad d ;measure) and return that as top of memory. ret ENDFUNC FUNCTION exec EXTERNAL execl call ma1toh ;get filename lxi d,0 ;load null parameter in DE push d ;push null parameter push h ;push filename call execl ;do an execl pop d cpi errorv jnz noerrr err: pop h pop b jmp error noerrr: lhld arg2 ;any first parameter? mov a,h ora l jnz excl0 lxi d,arg2 ;no...null out first default fcb slot push d lxi h,fcb call setfcb pop h jmp excl0a ;and go null out 2nd fcb slot excl0: xchg ;yes.. place into first default fcb slot lxi h,fcb call setfcb lhld arg3 ;any second parameter given? mov a,h ora l jnz excl0a lxi h,arg3 excl0a: xchg ;yes: stick it into second default fcb slot lxi h,fcb+16 2: call mpuc ;convert to upper case for command line buffer stax d inx d inr b inx h mov a,m ora a ;end of string? jnz excl2 pop h ;yes. inx h ;bump param pointer inx h jmp excl1 ;and go do next string excl3: pop h ;clean up stack mov a,b ;check for command buffer overflow cpi 53h jc excl30 ;if no overflow, go load file lxi d,errmsg mvi c,9 ;else comlain and abort... call bdos jmp err errmsg: db 7,'EXECL: Too much text',cr,lf,'$' excl30: lxi h,tbuff ;set length e NOBOOT sequence?) jnz go1 ;if not, just use the BDOS addr as top of memory lxi d,-2050 ;for NOBOOT, subtract 2100 from BDOS addr dad d ;and make that the new SP go1: sphl lxi h,base push h ;set base of ram as return addr jmp tpa-42 ;(go to `code0:') mpuc: cpi 61h ;convert character in A to upper case rc cpi 7bh rnc sui 32 ret ; ; This loader code is now: 42 bytes long. ; code0: lxi d,tpa ;destination address of new program code1: push d ;push dma addr push b ;push fc   b pointer mvi c,sdma ;set DMA address for new sector call bdos pop d ;get pointer to working fcb in DE push d ;and re-push it mvi c,reads ;read a sector call bdos pop b ;restore fcb pointer into BC pop d ;and dma address into DE ora a ;end of file? jz tpa-8 ;if not, get next sector (goto `code2:') mvi c,sdma ;reset DMA pointer lxi d,tbuff call bdos jmp tpa ;and go invoke the program code2: lxi h,80h ;bump dma address dad d xchg jmp tpa-39 ;and go loop (at code1) ENDFU execl call execl ;go do it; shouldn't come back. lda savcnt ;woops, we're back. Must've been an error... add a mov l,a ;put size of passed parameter list mvi h,0 ;into HL, and adjust stack dad sp sphl lxi h,-1 ;return error value ret savcnt: ds 1 ;save arg count here ENDFUNC FUNCTION sbrk call ma1toh ;get # of bytes needed in HL xchg ;put into DE lhld allocp ;get current allocation pointer push h ;save it dad d ;get tentative last address of new segment jc brke with -1 to indicate can't allocate. cmpdh: mov a,d cmp h rc rnz mov a,e cmp l ret ENDFUNC FUNCTION rsvstk call ma1toh ;get the value to reserve shld alocmx ;and set new safety factor ret ENDFUNC ? jnc brkerr ;if not, can't provide the needed memory. xchg ;else OK. inx h shld allocp ;save start of next area to be allocated pop h ;get pointer to this area ret ;and return with it. brkerr: pop h ;clean up stack jmp error ;and return; ; BD Software C Standard Library Machine Language Functions ; Written by Leor Zolman ; v1.46, 3/15/82 ; ; This file is in "CSM" format; to convert to CRL format, ; use CASM.SUB in conjunction with CASM.COM, ASM.COM and DDT.COM. ; ; Functions appearing in this file: ; ; rread rwrite rtell rseek rsrec rcfsiz ; setjmp longjmp ; setplot clrplot line plot txtplot ; index getline ; ; ; ; The random-record file I/O function contained here are NOT documented ; in the User's Guide, because the; ; The Random Record Field is incremented following each successful ; sector is read, just as if the normal (sequentail) read function ; were being used. Rseek must be used to go back to a previous ; sector. ; FUNCTION rread call arghak lda arg1 call fgfd jc error mov a,m ani 2 jz error push b lda arg1 call fgfcb shld tmp2 lxi h,0 shld tmp2a r2: lhld arg3 mov a,h ora l lhld tmp2a jnz r2a pop b ret r2a: lhld arg2 xchg mvi c,sdma call bdos lhld tNC FUNCTION execv EXTERNAL execl call arghak lhld arg2 ;get -> arg list mvi b,0 ;clear arg count execv1: inr b ;bump arg count mov e,m inx h mov d,m inx h mov a,d ora e ;last arg? jnz execv1 ;if not, keep looking for last one mov a,b ;save arg count in case of error sta savcnt dcx h ;HL -> next to last arg execv2: mov d,m ;now push args on stack dcx h mov e,m dcx h dcr b push d jnz execv2 execv3: lhld arg1 ;get program name push h ;save as first arg torr ;better not allow it to go over the top! dcx h xchg ; now last addr is in DE lhld alocmx ;get safety factor mov a,h ;negate cma mov h,a mov a,l cma mov l,a inx h dad sp ;get HL = (SP - alocmx) call cmpdh ;is DE less than HL? jnc brkerr ;if not, can't provide the needed memory. xchg ;else OK. inx h shld allocp ;save start of next area to be allocated pop h ;get pointer to this area ret ;and return with it. brkerr: pop h ;clean up stack jmp error ;and returny are non-portable to pre-2.0 CP/M ; Systems. ; maclib bds ; ; Here are the new random-access file I/O routines ; for use with CP/M version 2.x ONLY...these functions ; will NOT work under pre-2.x CP/M's. ; ; The new functions are: rread, rwrite, rtell, rseek, ; rsrec, rcfsiz ; ; ; Rread: ; ; Read a number of sectors randomly. ; Usage: ; ; i = rread(fd, buf, n); ; ; The return value is either the number of sectors successfully ; read, 0 for EOF, or 1000 + (BDOS ERROR CODE) mp2 xchg mvi c,readr ;code for BDOS random read push d ;save de so we can fudge nr field if call bdos ;we stop reading on extent boundary... pop d ; CP/M sucks! ora a jz r4 ;go to r4 if no problem cpi 1 jz r2b ;EOF? mov c,a ;put return error code in BC mvi b,0 lxi h,1000 ;add to 1000 dad b pop b ret r2b: lxi h,32 ;yes. are we on extent boundary? dad d mov a,m cpi 80h jnz r3 mvi m,0 ;yes. reset nr to 0...CP/M leaves it at 80! r3: lhld tmp2a ;(note: the above "bug"    in CP/M was supposedly fixed pop b ; for 2.x, but one can never be sure...) ret r4: lhld arg3 dcx h shld arg3 lhld arg2 lxi d,128 dad d shld arg2 lhld tmp2a inx h shld tmp2a lhld tmp2 ;get address of fcb lxi b,33 ;get addr of random record field dad b mov c,m ;bump inx h ; value mov b,m ; of inx b ; random mov m,b ; field dcx h ; by one mov m,c jmp r2 ENDFUNC ; ; Rwrite: ; ; The random "write" routine, which always copies the sector ; top b ret nwr2a: lhld arg2 ;else copy next 128 bytes down to tbuff lxi d,tbuff ;80 for normal CP/M, else 4280 mvi b,128 nwr3: mov a,m stax d inx h inx d dcr b jnz nwr3 shld arg2 ;save -> to next 128 bytes lhld tmp2 ;get addr of fcb xchg mvi c,writr ;go write randomly call bdos ora a ;error? lhld tmp2a ;if so, return # of successfully written pop b ; sectors. rnz push b inx h ; else bump successful sector count, shld tmp2a lhld arg3 ; debump countdown, dcx he offset must be non-positive) ; FUNCTION rseek call arghak lda arg1 call fgfcb jc error push h call rtell2 lhld arg2 lda arg3 ;is origin == 0? ora a jz rseek2 ;if so, HL holds new position dcr a ;no. is origin == 1? jnz rseek1 dad d ;yes. add offset to current position jmp rseek2 ;and result is in HL rseek1: pop d ;else origin must be 2... push d push b mvi c,cfsizc ;compute end of file position call bdos pop b pop h ;get back fcb push h call rtell2 ;geo to random record field dad d mov e,m ;get value into DE inx h mov d,m xchg ;put into HL ret ENDFUNC ; ; Rsrec: ; ; Set random field from serial access mode: ; FUNCTION rsrec call arghak lda arg1 call fgfcb jc error push h xchg push b mvi c,srrecc call bdos pop b pop h lxi d,33 dad d mov a,m inx h mov h,m mov l,a ret ENDFUNC ; ; Rcfsiz: ; ; set random record field to end-of-file: ; FUNCTION rcfsiz call arghak lda arg1 call fgf inx h mov e,m ;restore SP...first put it in DE inx h mov d,m inx h shld temp ;save pointer to return address call ma2toh ;get return value xchg ;put return val in DE, old SP in HL sphl ;restore SP with old value pop h ;pop retur address off stack lhld temp ;get back ptr to return address mov a,m inx h mov h,m mov l,a ;HL holds return address xchg ;put ret addr in DE, get return value in HL push d ;push return address on stack ret ;and return... temp: ds 2 ENDFUNC  be written down to tbuff before writing. Returns ; the # of sectors successfully written, or -1 on hard error. ; (the "1000 + error code" business is not used for rwrite) ; FUNCTION rwrite call arghak lda arg1 call fgfd jc error mov a,m ani 4 jz error push b lda arg1 call fgfcb shld tmp2 lxi h,0 shld tmp2a lxi d,tbuff ;80 for normal CP/M, else 4280 mvi c,sdma call bdos nwr2: lhld arg3 ;done yet? mov a,h ora l lhld tmp2a ;if so, return count jnz nwr2a po shld arg3 lhld tmp2 ; get address of fcb lxi b,33 ; get address of random field dad b mov c,m ; bump 16-bit value at random inx h ; record mov b,m ; field inx b ; of mov m,b ; fcb dcx h ; by one mov m,c jmp nwr2 ; and go try next sector ENDFUNC ; ; rseek: ; ; rseek(fd, offset, origin) ; seeks to offset records if origin == 0, ; to present position + offset if origin == 1, ; or to end of file + offset if origin == 2. ; (note that in the last case, tht DE = position lhld arg2 ;add offset dad d ;and HL holds new position rseek2: xthl ;get fcb, push new position lxi d,33 dad d ;HL points to random field of fcb pop d ;get new position in DE mov m,e ;and put into fcb inx h mov m,d xchg ;and return the position value ret rtell2: lxi d,33 dad d mov e,m inx h mov d,m ret ENDFUNC ; ; Rtell: ; ; Return random record position of file: ; FUNCTION rtell call arghak lda arg1 call fgfcb jc error lxi d,33 ;gcb jc error push h xchg push b mvi c,cfsizc call bdos pop b pop h lxi d,33 dad d mov a,m inx h mov h,m mov l,a ret ENDFUNC FUNCTION setjmp call ma1toh mov m,c ;save BC inx h mov m,b inx h xchg lxi h,0 dad sp xchg mov m,e ;save SP inx h mov m,d inx h pop d ;save return address push d mov m,e inx h mov m,d lxi h,0 ;and return 0 ret ENDFUNC FUNCTION longjmp call ma1toh ;get buffer address mov c,m ;restore BC inx h mov b,m FUNCTION setplot call arghak push b lhld arg1 ;get base address shld pbase ; initialize lhld arg3 ;get y size shld ysize ; initialize xchg ;leave it in DE lhld arg2 ;get x size shld xsize ; initialize call usmul ;figure out screen size shld psize ; initialize pop b ret ENDFUNC FUNCTION clrplot lhld psize ;put screen size xchg ; in DE lhld pbase ;get screen base in HL clr2: mvi m,' ' ;and inx h ; clear dcx d ; each mov a,d ; location ora e ; (all    DE of 'em) jnz clr2 ret ENDFUNC FUNCTION line call arghak ;get args push b lda arg2 ;put one set of endpoint data in DE in mov c,a ;format: D = x = arg2, E = y = arg3 lda arg3 mov b,a mov d,b mov e,c call put ; put up one endpoint at BC lda arg4 ;put other endpoint data in HL mov c,a lda arg5 mov b,a call put ;(but first put up the point from BC) mov h,b mov l,c call liner ;now connect them... pop b ret ;all done. liner: mov a,d sub h call abs cpi 2 jz mid4 mov a,l cmp e jc mid3a inr e jmp mid4 mid3a: dcr l mid4: mov a,h add d ora a rrc mov b,a mov a,l add e ora a rrc mov c,a pop d pop h ret put: push h push d mov a,b lhld ysize xchg lhld pbase inr a put1: dcr a jz put2 dad d jmp put1 put2: mov e,c mvi d,0 dad d lda arg1 mov m,a pop d pop h ret abs: ora a rp cma inr a ret ENDFUNC FUNCTION plot call arghak lda arg1 lhld ysize xchg lhld pbase  Returns index of substr in str, or -1 if not found. ; FUNCTION index call arghak lhld arg1 xchg ;main str ptr in DE lhld arg2 ;substr ptr in HL dcx d index1: inx d ldax d ;end of str? ora a jnz index2 lxi h,-1 ;yes. not found. ret index2: cmp m ;quick check for dissimilarity jnz index1 ;loop if not same right here push d ;else do long compare push h index3: inx h inx d mov a,m ;end of substr? ora a jnz index4 ;if not, go on testing pop d ;else matches pop d ;gpush h push h lxi h,-150 ;use space below stack for reading line dad sp push h ;save buffer address mov m,c ;Set max # of characters mvi c,getlin xchg ;put buffer addr in DE call bdos ;get the input line mvi c,conout mvi e,lf ;put out a LF call bdos pop h ;get back buffer address inx h ;point to returned char count mov b,m ;set B equal to char count inx h ;HL points to first char of line pop d ;DE points to start destination area copyl: mov a,b ;copy line to start of buffer jnc line2 ;are points far enough apart ;in both dimensions to warrant mov a,e ;drawing a line? sub l call abs cpi 2 jnc line2 ret ;if not, return. line2: call midp ;find midpoint call put ;put it up push d ;set up recursive calls mov d,b mov e,c call liner xthl call liner xchg pop h ret ;and we are done! midp: push h push d mov a,h sub d ani 1 jz mid3 mov a,h cmp d jc mid2a inr d jmp mid3 mid2a: dcr h mid3: mov a,l sub e ani 1 inr a plot1: dcr a jz plotc dad d jmp plot1 plotc: lda arg2 mov e,a mvi d,0 dad d lda arg3 mov m,a ret ENDFUNC FUNCTION txtplot call arghak push b lhld arg2 xchg lhld ysize call usmul xchg lhld arg3 dad d xchg lhld pbase dad d xchg lhld arg1 mvi b,0 lda arg4 ora a jz txt2 mvi b,80h txt2: mov a,m ora a jnz txt3 pop b ret txt3: ora b stax d inx h inx d jmp txt2 ENDFUNC ; ; Index(str,substr) ; char *str, *substr; ; ;et starting address of substr in DE lhld arg1 ;subtract beginning of str call cmh dad d ;and return the result ret index4: ldax d ;current char match? cmp m jz index3 ;if so, keep testing pop h ;else go on to next char in str pop d jmp index1 ENDFUNC ; ; Getline(str,lim) ; char *str; ; ; Gets a line of text from the console, up to 'lim' characters. ; FUNCTION getline push b call ma3toh ;get max no. of chars mov c,a ;save in C call ma2toh ;get destination address  ora a jz gets2 mov a,m stax d inx h inx d dcr b jmp copyl gets2: xra a ;store terminating null stax d pop h ;return buffer address in HL pop b ret ENDFUNC a LF call bdos pop h ;get back buffer address inx h ;point to returned char count mov b,m ;set B equal to char count inx h ;HL points to first char of line pop d ;DE points to start destination area copyl: mov a,b ;copy line to start of buffer   /* * crypt: a file encryption utility * * by Andrew Scott Beals * 9178 Centerway Rd. * Gaithersburg MD 20879 * (301) 926-0911 * last update->26 June 1982 * */ #include "a:bdscio.h" #ifndef FILE #define FILE struct _buf #endif main(argc,argv) int argc; char *argv[]; { char rotor[128]; char rotsiz; int byte; char rotptr; char filout; FILE input,output; if(argc == 2 && argv[1][0] == '-') { printf("crypt is a program designed to provide\n"); printf("the user tf("key? "); scanf("%s",rotor); argc--; argv++; } if(fopen(argv[0],input) == ERROR) { printf("can't open %s for input",argv[0]); exit(1); } if(argc == 2) { /* open up the output file */ filout=1; if(fcreat(argv[1],output) == ERROR) { printf("can't open %s for output",argv[1]); exit(1); } } else filout=0; rotsiz=strlen(rotor); if(!rotsiz) { printf("funny guy...the key must be at least 1 character"); exit(1); } rotptr=1; printf("%sWorking10 REM **** F I N D V A R **** 20 REM 30 REM 40 REM This program lists all the variables used in a 50 REM MBASIC Ascii program. It does not cross-reference them 60 REM to any line numbers. 70 REM 80 REM cml 90 REM 100 REM ----------------------------------------------------------- 110 REM 120 REM 130 DIM IN$(100),VAR$(400),V$(401) 140 DEF FNEQ(X,X$)=INSTR(X,X$,"=") 150 WIDTH 80 160 WIDTH LPRINT 80 170 FOR I = 1 TO 25 180 PRINT 190 NEXT I 200 INPUT "SOURCE FILE NAME ? ",W---------------------------- 400 REM 410 MAX=I-1 420 M=-1 430 M=M+1 440 L$ = IN$(M) 450 EQ = FNEQ(1,L$) 460 IF EQ=0 THEN 580 470 IF INSTR(L$," IF ") > 0 THEN 580 480 IF INSTR(L$," FOR ") > 0 THEN 580 490 IF INSTR(L$," REM ") > 0 THEN 580 500 IF INSTR(L$," DEF ") > 0 THEN 580 510 E = EQ-1 520 GOSUB 1040 530 S=E-1 540 GOSUB 1210 550 N=N+1 560 S=S+1 570 VAR$(N) = MID$(L$,S,E-S+1) 580 IF M 1 THEN with a means to protect his data\n"); printf("from the perusal of others, even if they\n"); printf("can get their hands on his file\n"); exit(1); } if(argc > 5 || argc < 2) { printf("usage: crypt [ -K ] [ ]\nfor more information, enter: crypt -"); exit(1); } if(argv[1][0] == '-' && argv[1][1] == 'K') { strcpy(rotor,argv[2]); argc-=3; /* make argc == # of files spec */ argv+=3; /* argv now points to the first file name */ } else { prin...",CLEARS); while((byte=getc(input)) != EOF) { byte ^= rotor[rotptr++]; rotptr %= rotsiz; if(filout) putc(byte,output); else putchar(byte); } if(filout) { fflush(output); fclose(output); } exit(0); } == ERROR) { printf("can't open %s for output",argv[1]); exit(1); } } else filout=0; rotsiz=strlen(rotor); if(!rotsiz) { printf("funny guy...the key must be at least 1 character"); exit(1); } rotptr=1; printf("%sWorking$ 210 INPUT "WOULD YOU LIKE THE OUPUT TO GO TO THE PRINTER ? ",ANS$ 220 IF LEFT$(ANS$,1)="Y" THEN LST=1 ELSE LST=0 230 PRINT 240 OPEN "I",1,W$ 250 N=-1 260 PRINT "READING ";W$; 270 MAX = 100 280 PRINT "."; 290 FOR I = 0 TO MAX 300 IF EOF(1)= -1 THEN 370 310 LINE INPUT #1,IN$(I) 320 IF IN$(I)="" THEN 300 330 NEXT I 340 GOTO 410 350 REM -------------------------------------------------------------- 360 REM 370 ENDS=1 380 PRINT 390 REM ----------------------------------NATING DUPLICATES..." 620 K=-1 630 FOR I=0 TO N-1 640 IF VAR$(I)="" THEN 710 650 FOR J=I+1 TO N 660 IF VAR$(J)="" THEN 680 670 IF VAR$(J)=VAR$(I) THEN VAR$(J)="" 680 NEXT J 690 K=K+1 700 V$(K)=VAR$(I) 710 NEXT I 720 GOSUB 1320 730 IF LST=1 THEN 780 740 PRINT TAB(24)"VARIABLE LIST FOR ";W$ 750 PRINT 760 PRINT 770 GOTO 810 780 LPRINT TAB(24)"VARIABLE LIST FOR ";W$ 790 LPRINT 800 LPRINT 810 K1=INT((K+1)/2) 820 IF 2*K1 = K+1 THEN K1=INT(K/2) 830 FOR I = 0 TO K1 270 980 CLOSE 990 PRINT 1000 PRINT 1010 END 1020 REM -------------------------------------------------------------- 1030 REM 1040 REM THIS RTN. BACK-SCANS TO THE NEXT NON-BLANK FOLLOWED BY A SPACE 1050 IF MID$(L$,E,1) = " " THEN 1060 ELSE 1110 1060 E=E-1 1070 IF E=0 THEN 1080 ELSE 1050 1080 PRINT "NO SPACE DELIMITER FOUND IN LAST CHAR. RTN." 1090 PRINT 1100 STOP 1110 IF MID$(L$,E,1)=")" THEN 1120 ELSE 1180 1120 IF MID$(L$,E,1)<> "(" THEN 1130 ELSE 1180 1130 E=E-1 1140 IF    E=0 THEN 1150 ELSE 1120 1150 PRINT "NO MATCHING '(' FOR ')' FOUND." 1160 PRINT 1170 STOP 1180 RETURN 1190 REM -------------------------------------------------------------- 1200 REM 1210 REM THIS RTN. BACK-SCANS TO FIRST NON-BLANK FOLLOWING A SPACE 1220 IF MID$(L$,S,1) = " " THEN 1280 ELSE 1230 1230 S = S-1 1240 IF S = 0 THEN 1250 ELSE 1220 1250 PRINT "NO SPACE DELIMITER FOUND IN FIRST CHAR. RTN. 1260 PRINT 1270 STOP 1280 RETURN 1290 REM ----------------------------------------------/* LCHECK by Richard Conn LCHECK displays to the user the nesting level number of each BEGIN/END ({/}) group, thereby helping him to identify problem areas in his C programs. It recognizes quoted material and comments and ignores { and } within these. */ #define vers 12 /* Version Number */ #include "a:bdscio.h" #define SSCROLL TRUE /* Set TRUE for Smooth Scrolling on TVI 950 */ #define quote 0x27 /* Single Quote */ #define dquote 0x22 /* Double Quote */ #define BS 0x08 /* Back Spa exit(FALSE); } if (fopen(argv[1],iobuf) == ERROR) { printf("Cannot Find File %s\n",argv[1]); exit(FALSE); } if (SSCROLL) printf("%c%c",ESC,'8'); /* Smooth Scroll */ printf("LCHECK, Version %d.%d -- File: %s\n",vers/10, vers%10,argv[1]); level = 0; nroutines = 0; /* Init nesting level, routine count */ prlevel(); /* Print level number */ do { getit(); /* Get next char */ if (chval == quote) do { /* If quote, flush to end quote */ getit(); } while (chval !== '}') { /* END */ level--; if (level == 0) { nroutines++; printf("\n** Routine %d **", nroutines); } } } while ((chval != CPMEOF) && (chval != ERROR)); printf("\nProgram Level Check is "); if (level == 0) printf("OK"); else printf("NOT OK"); printf("\nNumber of Routines Encountered: %d",--nroutines); if (SSCROLL) printf("%c%c",ESC,'9'); /* Hard Scroll */ } getit() /* Get and Echo Character */ { chval = getc(iobuf); if ((pos >= TWIDTH) & (chval != CR)) pel(ovfl_flag) /* Print Level Number and Set Col Count */ char ovfl_flag; { putchar(LF); if (level < 10) printf(" %d",level); else printf("%d",level); if (ovfl_flag == YES) putchar('-'); else putchar(':'); putchar(' '); pos = 5; } se BS : putchar(BS); pos--; break; case LF : prlevel(noovfl); break; case CR : putchar(CR); pos = 0; break; default : if (chval >= ' ') { putchar(chval); pos++; } break; } } prlev---------------- 1300 REM 1310 REM THIS RTN. SORTS THE VARIABLE LIST 1320 PRINT 1330 PRINT "SORTING...";K+1;" VARIABLES READ" 1340 PRINT 1350 PRINT 1360 FOR I=0 TO K 1370 FOR J=I+1 TO K 1380 IF V$(J) < V$(I) THEN 1390 ELSE 1410 1390 SWAP V$(J),V$(I) 1400 SWP=SWP+1 1410 NEXT J 1420 NEXT I 1430 RETURN 1440 REM -------------------------------------------------------------- 1450 REM  1410 NEXT J 1420 NEXT I 1430 RETURN 1440 REM -----------------------------------ce Char */ #define TAB 0x09 /* Tab Char */ #define LF 0x0a /* Line Feed Char */ #define CR 0x0d /* Carriage Return Char */ #define YES 'Y' #define NO 'N' #define ovfl YES /* Line Overflow */ #define noovfl NO /* No Line Overflow */ char iobuf[BUFSIZ]; int level, chval, pos, nroutines; main(argc,argv) int argc; char **argv; { int done; if (argc == 1) { printf("LCHECK, Version %d.%d\n",vers/10,vers%10); printf("Format of Command Line is --\n"); printf(" LCHECK filename.typ");  quote); if (chval == dquote) do { /* If dquote, flush to dquote */ getit(); } while (chval != dquote); if (chval == '/') { /* Possible comment */ getit(); if (chval == '*') { /* Yes, it is a comment */ getit(); done = FALSE; do { if (chval == '*') { /* End comment? */ getit(); if (chval == '/') /* Yes */ done = TRUE; } else getit(); } while (!done); } } if (chval == '{') level++; /* BEGIN */ if (chval =rlevel(ovfl); if (chval != CPMEOF) echo(chval); } echo(chval) /* Echo Char with tabulation */ char chval; { switch (chval) { case TAB : putchar(' '); pos++; while (pos%9 != 0) { putchar(' '); pos++; } break; case BS : putchar(BS); pos--; break; case LF : prlevel(noovfl); break; case CR : putchar(CR); pos = 0; break; default : if (chval >= ' ') { putchar(chval); pos++; } break; } } prlev    10 REM **** TEXT EDITOR 70 GOTO 300 99 REM *** WRITE SECTION 100 CLEAR 8000 110 DIM A$(100) 111 INPUT"SET TAB AT NUMBER ";T 112 T=T-1 120 PRINT "READY":WAIT 0, 1, 1 130 PRINT:PRINT:PRINT:PRINT 140 FOR I=1 TO 1000 150 K=0 160 WAIT 0,1,1 170 A=INP(1):A=A AND 127 171 IF A=92 THEN 202 180 IF A=13 THEN 280 190 IF A=95 THEN 260 200 IF A=64 THEN A$(I)="":PRINT:GOTO 150 201 GOTO 210 202 B$="": IF K>=T THEN PRINT"":GOTO 160 203 FOR TAB =1 TO T-K:B$=B$+" ":NEXT TAB 204 PRINTB$; 205 K=K+T-1 207ECTION 1000 C$=A$(I) 1005 IF K=0 THEN PRINT CHR$(7):RETURN 1010 IF K=1 THEN A$(I)="":PRINT CHR$(7):K=0:RETURN 1020 K=K-1:A$(I)=LEFT$(C$,K) 1030 PRINT:PRINT A$(I) 1040 RETURN 1499 REM *** PRINT SECTION 1500 PRINT:PRINT:PRINT:PRINT 1510 FOR I=1 TO 1000 1520 IF A$(I)="END" THEN 1590 1530 PRINT A$(I) 1540 NEXT I 1560 FOR T=1 TO 5000: NEXT T 1590 PRINT:PRINT:PRINT:PRINT:GOTO 300 2000 GOTO 2050 2001 REM *** EDIT LIST SECTION 2002 PRINT:PRINTTAB(5):FOR I=1 TO 6:PRINT"1234567890";:NEXT 2003 PRINT139 REM *** EDIT CHANGE SECTION 2140 INPUT "WHICH LINE ";LN 2150 PRINT A$(LN) 2160 INPUT "CORRECT LINE ";CL$ 2170 IF LEFT$(CL$,1)<>"Y" THEN 2140 2180 GOTO 3000 3000 INPUT "WHICH CHARACTER ";C 3010 PRINTMID$(A$(LN),C,1) 3020 INPUT "CORRECT CHARACTER ";CC$ 3030 IF LEFT$(CC$,1)<>"Y" THEN 3000 3040 INPUT "CHANGE HOW MANY ";N 3050 IF N<0 OR (N+C)>LEN(A$(LN)) THEN 3040 3060 T1$=LEFT$(A$(LN),(C-1)) 3070 T=LEN(A$(LN))-(C-1)-N 3080 T2$=RIGHT$(A$(LN),T) 3090 T$="":PRINT T1$; 3100 FOR I2=1 TO N 3110 WN)) THEN 4100 4111 IF LE=0 THEN PRINT"INSERT STARTS AT FIRST POSITION":T1$="":GOTO4143 4120 PRINT MID$(A$(LN),LE,1):INPUT"CORRECT CHARACTER ";CC$ 4130 IF LEFT$(CC$,1)<>"Y" THEN 4100 4140 T1$=LEFT$(A$(LN),LE) 4143 T2$=MID$(A$(LN),(LE+1)) 4145 T$="" 4150 PRINT T1$ 4160 WAIT 0,1,1 4170 A=INP(1):A=A AND 127 4180 IF A=13 THEN 4210 4190 T$=T$+CHR$(A):PRINT CHR$(A); 4200 IF LEN(A$(LN))+LEN(T$)=69 THEN PRINT ""; 4205 GOTO 4160 4210 A$(LN)=T1$+T$+T2$:PRINT T2$ 4220 GOTO 300 4399 REM *** LINE INSERT SIF K=1 THEN K=0:A$(LN)="":PRINT"":GOTO 4480 4803 A$(LN)=LEFT$(A$(LN),K-1):K=K-1 4810 PRINT:PRINT A$(LN); 4820 GOTO 4480 4999 REM *** DELETE SECTION 5000 INPUT"CHARACTER OR LINE ";CL$ 5010 IF LEFT$(CL$,2)="CH" THEN 5100 5020 IF LEFT$(CL$,2)="LI" THEN 5400 5030 GOTO 5000 5099 REM *** CHARACTER DELETE SECTION 5100 INPUT "WHICH LINE ";LN 5110 PRINT A$(LN):INPUT "CORRECT LINE ";CL$ 5120 IF LEFT$(CL$,1)<>"Y" THEN 5100 5130 INPUT "AFTER WHICH CHARACTER ";N 5140 IF N=0 THEN PRINT"DELETE STARTS WITH CH GOTO 220 210 B$=CHR$(A):PRINT B$; 220 A$(I)=A$(I) + B$:K=K+1 230 IF A$(I)="END"THEN K2=I:GOTO 1500 240 IF LEN(A$(I))>69 THEN 280 250 GOTO 160 260 GOSUB 1000 270 GOTO 160 280 PRINT:NEXT I 299 REM *** PROGRAM CONTROL SECTION 300 INPUT "FUNCTION";F$ 310 IF LEFT$(F$,2)="WR" THEN 100 320 IF LEFT$(F$,2)="PR" THEN 1500 330 IF LEFT$(F$,2)="ED" THEN 2000 340 IF LEFT$(F$,2)="EN" THEN END 400 PRINT "FUNCTIONS ARE:" 410 PRINT "WRITE","PRINT","EDIT","END" 500 GOTO 300 999 REM *** LAST CHARACTER EDIT S 2004 FOR I=1 TO 1000 2010 IF A$(I)="END" THEN 2050 2020 PRINT I;TAB(5);A$(I) 2030 NEXT I:PRINT:PRINT 2049 REM *** EDIT CONTROL SECTION 2050 INPUT"TYPE OF EDIT ";TE$ 2060 E$=LEFT$(TE$,2) 2070 IF E$<>"CH"AND E$<>"IN"AND E$<>"DE"AND E$<>"LI"ANDE$<>"SE"THEN 2090 2080 GOTO 2120 2090 PRINT"TYPES OF EDITING ARE:" 2100 PRINT "CHANGE","INSERT","DELETE" 2105 PRINT "SEARCH","LIST" 2110 GOTO 2050 2120 IF E$="DE" THEN 5000 2125 IF E$="SE" THEN 5600 2130 IF E$="IN" THEN 4000 2134 IF E$="LI" THEN 2002 2AIT 0,1,1 3120 Q=INP(1) 3130 Q=Q AND 127 3140 T$=T$+CHR$(Q):PRINT CHR$(Q); 3150 NEXT I2 3160 PRINT T2$ 3170 A$(LN)=T1$+T$+T2$ 3180 GOTO 300 3999 REM *** EDIT INSERT SECTION 4000 INPUT "LETTER OR LINE ";LL$ 4010 IF LEFT$(LL$,2)="LE" THEN 4050 4020 IF LEFT$(LL$,2)="LI" THEN 4400 4030 GOTO 4000 4049 REM *** LETTER INSERT SECTION 4050 INPUT "WHICH LINE ";LN 4060 PRINT A$(LN):INPUT "CORRECT LINE ";CL$ 4070 IF LEFT$(CL$,1)<>"Y" THEN 4050 4100 INPUT "AFTER WHICH CHARACTER ";LE 4110 IF LE>LEN(A$(LECTION 4400 INPUT"AFTER WHICH LINE ";LN 4410 PRINT A$(LN):INPUT"CORRECT LINE ";CL$ 4420 IF LEFT$(CL$,1)<>"Y" THEN 4400 4430 LN=LN+1 4440 FOR L=K2 TO LN STEP -1 4450 A$(L+1)=A$(L) 4460 NEXT L:K2=K2+1 4470 PRINT"READY ":A$(LN)="":K=0 4480 WAIT 0,1,1 4490 A=INP(1):A=A AND 127 4500 IF A=13 THEN 4560 4510 IF A=95 THEN 4800 4520 IF A=64 THEN A$(LN)="":PRINT:GOTO 4480 4530 B$=CHR$(A):PRINT B$;:K=K+1 4540 A$(LN)=A$(LN)+B$ 4550 GOTO 4480 4560 PRINT:GOTO 300 4800 IF K=0 THEN PRINT"":GOTO 4480 4802 ARACTER 1":GOTO 5170 5145 PRINT MID$(A$(LN),N,1) 5150 INPUT "CORRECT CHARACTER ";CC$ 5160 IF LEFT$(CC$,1)<>"Y" THEN 5130 5170 INPUT"DELETE HOW MANY ";N2 5180 IF LEN(A$(LN))-N"Y" THEN 5170 5260 A$(LN)=T1$+T2$ 5270 PRINT A$(LN) 5280 GOTO 300 5399 REM *** LINE DELETE    SECTION 5400 INPUT "DELETE WHICHH LINE ";WL 5410 IF WL=<0 OR WL>=K2 THEN 5400 5420 PRINT A$(WL):INPUT"CORRECT LINE ";CL$ 5430 IF LEFT$(CL$,1)<>"Y" THEN 5400 5440 IF A$(WL)="END" THEN 300 5450 FOR J=WL TO K2-1 5460 A$(J)=A$(J+1) 5470 NEXT J:K2=K2-1 5480 INPUT "NEXT LINE ALSO ";NL$ 5490 IF LEFT$(NL$,1)="Y" THEN 5440 5500 GOTO 300 5599 REM *** EDIT SEARCH SECTION 5600 PRINT "WHAT PHRASE "; 5605 A1$="":Y=0 5610 WAIT 0,1,1 5620 A=INP(1):A=A AND 127 5630 IF A=13 THEN PRINT:GOTO 5700 5640 IF A=641dg FINDBAD - ver 5.4 Bad sector lockout program Universal version Type CTL-C to abort $ ͥ@|5ͭ> ʹ*|ʕ͋Ú  *" "w"o"z " |2*.":\O ʹ> _*.*.   Test aborted by control-C $*dDM6# x }o|g}/o|/g#~#%7Ɛ'@'ô:W:Wi&"^ Yɷ|g}o:{%*.:^#"^#"~#2~#2^#"^#"^"> _[UNUSED]BAD  TesNo$ bad blocks found $1l' COPYRIGHT (C) 1980, DIGITAL RESEARCH , 7 :2!q: ʊ *M8 :œ *M8 :12!:!m~ ʕ0 ڈҚ))))o#t"ͻ BAD HEX DIGIT IN BASE$ !^!w4~6\\ͻ DISK IS FULL$> >  !0#7l]\ѷK!0=Xͻ͔!}O|G{Ozv>yy_ >:{͹!*|͹}͹͹~#͹§͹aW >:͹ :>\fier out of range$ +++ Warning...System tracks bad +++ $BÝ Bad directory area, try reformatting$oÝ Can't create [UNUSED].BAD$ ڔ |ċ{0ʹ> ʹ> _*.*.   Test aborted by control-C $*dDM6# x }o|g}/o|/g#~#%7Ɛ'@'ô:W:Wi&"^ Yɷ|g}o:{%*.:^#"^#"~#2~#2^#"^#"^"> _[UNUSED]BAD  TesNo$ bad blocks found $ OR A=95 THEN A1$="":GOTO 5600 5650 B$=CHR$(A):PRINT B$;:A1$=A1$+B$ 5655 GOTO 5610 5700 L=LEN(A1$) 5710 FOR I=1 TO 1000 5720 IF LEN(A$(I))*ʹ!"**DM ;:ºg" Bad block: $ x.y.ͭ*:<_"*#"* q#:p#" i:2!d" :W!yP)=K:GcU}2*DMڐxʅ`i͐" e͐" !:<22|ʻک|».:22}2:G* !w#:w##Ý Drive specid total sectors read $NUSED].BAD$ ڔ |ċ{0ʹ> ʹ> _*.*.   Test aborted by control-C $*dDM6# x }o|g}/o|/g#~#%7Ɛ'@'ô:W:Wi&"^ Yɷ|g}o:{%*.:^#"^#"~#2~#2^#"^#"^"> _[UNUSED]BAD  TesNo$ bad blocks found $ͻ HEX FILE WRITTEN$$ͻ CANNOT CLOSE FILE, CHECK WRITE PROTECT$!ew#R6M\yͻ NO INPUT FILE PRESENT$COM2M\ͻ NO DIRECTORY SPACE$HEX2| DISK READ ERROR$K IS FULL$> >  !0#7l]\ѷK!0=Xͻ͔!}O|G{Ozv>yy_ >:{͹!*|͹}͹͹~#͹§͹aW >:͹ :>\d total sectors read $NUSED].BAD$ ڔ |ċ{0ʹ> ʹ> _*.*.   Test aborted by control-C $*dDM6# x }o|g}/o|/g#~#%7Ɛ'@'ô:W:Wi&"^ Yɷ|g}o:{%*.:^#"^#"~#2~#2^#"^#"^"> _[UNUSED]BAD  TesNo$ bad blocks found $   *; FIND.ASM VERSION 2.0 10/05/82 *; *; Requires MAC for Assembly *; *; ORIGINALLY WRITTEN BY WARD CHRISTENSEN *; ENHANCED AND REWRITTEN BY RICH ANGELO - 10-05-82 *; *; 'FIND's ASCII, character strings in a file. *; May take a generic file name, thus may search all *.ASM files *; on a disk. Also very useful for finding things in MAST.CAT - *; for example if you are looking for all MODEM or BYE Programs *; you could FIND MAST.CAT MOD|BYE TO see them all. *; *; Another useful function is for Docat direction. *; *; Any comments use, *; One of the Popular Chicago area RBBS or CBBS Systems. *; *; Rich Angelo *; *; Used with LIST.COM which takes a starting line number, *; you can: 1) use find to find a particular part of the code, *; then 2) use LIST specifying a starting line number just before *; the part of the code you wanted to see. *; *; Note that FIND now has a DEFAULT File Name and the ability *; to PROMPT for SEARCH STRING. This feature is handy if you want to *; sen.ft <--- Prompt for Search String. *; *; FIND fn.ft str <--- Will Display Upper & Lower Case of string *; Using File specified. *; *; fn.ft may be Ambiguous, *.ASM OR CBBS*.ASM *; *;---------------------------------------------------------------------- *; ;THE USUAL EQUATES RDCON EQU 1 WRCON EQU 2 PRINT EQU 9 RSTRING EQU 10 CONST EQU 11 OPEN EQU 15 CLOSE EQU 16 SRCHF EQU 17 SRCHN EQU 18 ERASE EQU 19 READ EQU 20 WRITE EQU 21 MAKE EQU 22 REN EQU 23 STDMA EQU 26 BDOS EQU 5 FCM ENDM IF ?Q EQ '''' LOCAL ?B,?Z CALL ?Z ?B DB ?F ?Z POP H ;GET FROM LXI B,?Z-?B ;GET LEN ELSE LXI H,?F ENDIF ENDIF IF NOT NUL ?T LXI D,?T ENDIF IF NOT NUL ?L LXI B,?L ENDIF CALL ?MOVE ENDM SKIP: MOVE FROM,TO,LEN ENDM ******M>DEFINE COMPARE MACRO: COMPAR from,to,length ******M>from may be addr, or quoted string. ******M> COMPAR MACRO FROM,TO,LEN LOCAL SKIP JMP SKIP ?COMPAR:MOV A,B ORA C RZ LDAX D CMP M RNZ INX D INX H DCX B JMP ?COMPAR P PUSH B PUSH D PUSH H IF NOT NUL ?F MVI C,?F ENDIF IF NOT NUL ?P LXI D,?P ENDIF CALL BDOS POP H POP D POP B ENDM ******M> ******M> END OF MACRO DEFINITIONS ******M> ORG 100H *******>PROGRAM - FIND - JMP START *++++++> Data Area PGMID: DB 'FIND - Version 2.0 10/05/82' ;*>Rich Angelo DB CR,LF,'$' DB EOF DFLTNAM:DB 'MAST CAT' ;DEFAULT FILE NAME ABORT: DB CR,LF,'++FIND ABORTED++$' NOFILE: DB CR,LF,'++CANNOT FIND' FILMSG: DB '----> FILE ' FNAME: umentation. For example; *; *; Print all of this, enter: FIND FIND.ASM *; *; *; Print Mainline comments, FIND FIND.ASM *> *; *; Print Subroutines, FIND FIND.ASM *S> *; *; Or try this, FIND FIND.ASM *>|*S> *; *; Print Macros used, FIND FIND.ASM *M> *; *; Documenting a Program in this fashion is an easy way to seperate *; comments from code. There are many ways to Identify a portion of *; a Program. Maybe a standard can be established, that we all can *; share. This is the first step in tharch for specific characters only, whereas entering the search *; string on the command line will display both upper and lower case. *; *; Special Search features of FIND are; *; *; 1. Make "_" match a Tab *; 2. Make "|" AN "OR" *; AS IN: FIND B:*.ASM _IN_|_OUT_ *; *; *; COMMAND FORMATS; *; *; FIND <--- Defaults to Filename In DFLTNAM. *; Will Prompt for Search String Lower Case Valid. *; Also will search for any character seq. passed *; thru CPM Read String Function. *; *; FIND fB EQU 5CH FCB2 EQU 6CH FCBEXT EQU FCB+12 FCBRNO EQU FCB+32 TBUFF EQU 80H CR EQU 0DH LF EQU 0AH EOF EQU 1AH TAB EQU 09H ******M> START OF MACRO DEFINITIONS ******M> ******M>DEFINE DATA MOVE MACRO: MOVE from,to,length ******M>from may be addr, or quoted string ******M> MOVE MACRO FROM,TO,LEN LOCAL SKIP JMP SKIP ?MOVE: MOV A,B ORA C RZ MOV A,M STAX D INX H INX D DCX B JMP ?MOVE MOVE MACRO ?F,?T,?L IF NOT NUL ?F IRPC ?C,?F ?Q SET '&?C&?C' ;;TEST FOR QUOTE EXIT COMPAR MACRO ?F,?T,?L IF NOT NUL ?F IRPC ?C,?F ?Q SET '&?C&?C' ;;TEST FOR QUOTE EXITM ENDM IF ?Q EQ '''' LOCAL ?B,?Z CALL ?Z ?B DB ?F ?Z POP H ;GET FROM LXI B,?Z-?B ;GET LEN ELSE LXI H,?F ENDIF ENDIF IF NOT NUL ?T LXI D,?T ENDIF IF NOT NUL ?L LXI B,?L ENDIF IF NOT NUL ?I LOCAL ?B,?Z CALL ?Z ?B DB ?I ?Z POP D ;GET TO LXI B,?Z-?B ENDIF CALL COMPARR ENDM SKIP: COMPAR FROM,TO,LEN ENDM ******M>DEFINE CP/M MACRO - CPM fnc,parm ******M> CPM MACRO ?F,?DB 'XXXXXXXX.XXX' DB CR,LF CRLF: DB CR,LF,'$' PROMPT: DB CR,LF,'Enter String>$' ;RDBYTE FIELDS EFCB: DW BUFF ;BUFFER ADDR EFCBCT: DW 0 ;BYTES LEFT DB 20 ;BUFFER SIZE (IN PAGES) DW FCB ;FCB ADDRESS ;MFNAME FIELDS MFFLG1: DB 0 ;1ST TIME SW MFREQ: DS 12 ;REQ NAME MFCUR: DS 12 ;CURR NAME CONBUF: DB CONLEN ;LENGTH OF CONSOLE BUFFER CONSIZ: DS 1 ;RESULTING SIZE AFTER READ STRING: DS 30 ;WHAT TO SEARCH FOR CONLEN EQU $-CONSIZ LINENO: DB ' ',TAB,'$' ;LINE NUMBER DS 32 ;   STACK AREA STACK: DS 2 STRPTR: DS 2 ;SETSTR - Set String pointers, and e BC=LENGTH CALL FRSTFI ;SEE IF FILE EXISTS JMP OPFILE ;GO PROCESS IT *******>GETSTR - Accept String from console. GETSTR: CALL FRSTFI ;LOOK FOR FILE CPM PRINT,PROMPT ;DISPLAY PROMPT CPM RSTRING,CONBUF ;GET STRING LDA CONSIZ ORA A JZ EXIT MOV L,A ;STORE DELIMITER MVI H,0 LXI D,STRING DAD D MVI M,0 CPM PRINT,CRLF JMP OPFILE ;PROCESS FILE *******>FRSTFI - Search for Initial file and print it's name. FRSTFI: CALL MFNAME ;IF FILE DOES NOT EXIST RNC ; TELL THEM AND EX ASCII INR A MOV M,A CPI '9'+1 ;CARRY? JNZ NEXTNC MVI M,'0' DCX H JMP NEXT01 *******>NEXTNC - Read a line from file. NEXTNC: LXI H,LINE MVI B,0FFH ;SO LONG LINE WON'T BLOW NEXT02: INR B JM LONG ;TOO LONG A LINE PUSH B PUSH H LXI H,EFCB CALL RDBYTE POP H POP B MOV M,A INX H CPI EOF JZ NEXTFL ;NEXT FILE CPI LF JNZ NEXT02 JMP EOL *******>LONG - Got a long line, chop it off. LONG: MVI M,CR INX H MVI M,LF *******>EOL - Check for operator abort, poin B,A ;SAVE CHAR MOV A,C ;GET CHAR CPI 61H ;LOWER? JC NOTEQ ;NO, SO NO MATCH CPI 7BH JNC NOTEQ ANI 5FH ;MAKE UPPER CASE CMP B JZ NEXTC ;MATCHED NOTEQ: POP H ;RESTORE ADDR INX H MOV A,M CPI CR JNZ NEXTST LHLD STRPTR *******>FINDOR - If an "OR" (|) is in the line, Scan for it. FINDOR: MOV A,M INX H CPI '|' JZ ORLINE ORA A JNZ FINDOR JMP NEXTLN *******>MATCHED - Got a match print it. MATCHED:POP H ;KILL STACKED ADDR CPM PRINT,LINENO ;PRINT LINE NUMBER TE BUFFER SIZE (IN PAGES) ******S> 2 BYTE FCB ADDRESS ******S> RDBYTE: MOV E,M ;DE = BUFFER ADDR INX H ;X MOV D,M ;X INX H ;BC = BYTES LEFT MOV C,M ;X INX H ;X MOV B,M ;X MOV A,B ;IF BYTE-COUNT NOT = ZERO ORA C ; GO READ NEXT BYTE JNZ RDGETB ; ELSE INX H ; READ ANOTHER SECTOR. MOV A,M ;GET COUNT ADD A ;MULTIPLY BY 2 MOV B,A ;SECTOR COUNT IN B INX H ;TO FCB PUSH H ;SAVE FCB POINTER MOV A,M ;GET.. INX H ;..FCB.. MOV H,M ;..ADDR.. MOV L,A ;.nd delimiter. SETSTR: LXI D,TBUFF ;DE=TBUFF LDAX D ;LENGTH MOV C,A ;SAVE LENGTH MVI B,0 ;SETUP BC FOR MOVE INX D ;PAST LENGTH MOV L,A ;L=LENGTH MVI H,0 ;HL=LENGTH DAD D ;HL=LAST CHAR MVI M,0 ;STORE END DELIM XCHG ;START TO HL *******>SCAN - Look for String, If found save it. SCAN: INX H ;TO NEXT CHAR MOV A,M ;LOOK FOR ' ' ORA A ;END? JZ GETSTR ;..YES, THEN GET IT FROM THE CONSOLE CPI ' ' ; JNZ SCAN ;NOT AT ' ' INX H ;TO STRING MOVE ,STRING, ;HL = FROM,IT. MOVE FCB+1,FNAME,8 MOVE FCB+9,FNAME+9,3 CPM PRINT,NOFILE JMP EXIT *******>NEXTFL - Look for another file, If none then exit. NEXTFL: CPM PRINT,CRLF CALL MFNAME JC EXIT *******>OPFILE - Open file and print name. OPFILE: CPM OPEN,FCB INR A JZ EXIT MOVE ' 0',LINENO MOVE FCB+1,FNAME,8 MOVE FCB+9,FNAME+9,3 CPM PRINT,FILMSG ;SAY WHICH FILE LXI H,0 SHLD EFCBCT *******>NEXTLN - Set up next line number. NEXTLN: LXI H,LINENO+3 NEXT01: MOV A,M ;GET DIGIT ORI '0' ;MAKEt to String. EOL: CPM CONST ;TEST FOR ABORT ORA A JNZ CHRXIT ;ABORT REQUESTED LXI H,STRING *******>XXXXXX - We have a line, now Scan for the String. ORLINE: SHLD STRPTR LXI H,LINE NEXTST: XCHG LHLD STRPTR XCHG ;(HL)->LINE - (DE)->STRING PUSH H *******>NEXTC - Replace '_' with a TAB. NEXTC: LDAX D CPI '_' JNZ NOTAB MVI A,TAB NOTAB: INX D ORA A ;END OF STRING? JZ MATCHED CPI '|' JZ MATCHED ;FIRST PART MOV C,M ;FOR LOWER CASE TEST CMP M INX H JZ NEXTC MOV LXI H,LINE MATCHLP:MOV A,M MOV E,A CPM WRCON MOV A,M INX H CPI LF JNZ MATCHLP JMP NEXTLN *******>CHRXIT - Read Keyboard, Print Abort message. CHRXIT: CPM RDCON CPM PRINT,ABORT *******>EXIT - Restore Stack and Return to CP/M. EXIT: LHLD STACK SPHL RET ;TO CCP ******S> SUBROUTINES ******S> ******S>RDBYTE - READ BYTE FROM FILE. ******S> HL POINTS TO EFCB: ******S> EFCB; ******S> 2 BYTE BUFFER ADDR ******S> 2 BYTE "BYTES LEFT" (INIT TO 0) ******S> 1 BY.TO HL RDBLP: MVI A,EOF ;PUT EOF CHAR IN BUF STAX D ; IN CASE OF EOF. PUSH D ;SAVE DMA ADDR PUSH H ;SAVE FCB ADDR CPM STDMA ;SET DMA ADDR POP D ;GET FCB CPM READ ;READ SECTOR ORA A ;CHECK FOR EOF POP H ;HL=DMA, DE=FCB JNZ RDBRET ;GOT EOF MOV A,L ;BUMP BUFFER POINTER ADI 80H ;TO NEXT BUFF MOV L,A ;X MOV A,H ;X ACI 0 ;X MOV H,A ;X XCHG ;DMA TO DE, FCB TO HL DCR B ;MORE SECTORS? JNZ RDBLP ;YES, MORE RDBRET: POP H ;GET FCB POINTER DCX H ;TO LENGTH    MOV A,M ;GET LENGTH DCX H ;TO COUNT MOV M,A ;SET PAGE COUNT DCX H ;TO LO COUNT DCX H ;TO HI FCB DCX H ;TO EFCB START JMP RDBYTE ;LOOP THRU AGAIN RDGETB: INX H ;POINT TO BUFFER SIZE MOV A,M ;GET LENGTH (PAGES) XCHG ;BUFF TO HL ADD H ;HL = END OF BUFF MOV H,A ;X MOV A,L ;X SUB C ;HL = DATA POINTER MOV L,A ;X MOV A,H ;X SBB B ;X MOV H,A ;X MOV A,M ;GET BYTE XCHG ;EFCB POINTER BACK TO HL CPI EOF ;EOF? RZ ;YES, LEAVE POINTERS DCX B ;DECR CC IN WHICH YOU WANT TO PROCESS SINGLE OR ******S> MULTIPLE FILES. ******S> ******S> JUST CALL "MFNAME" (Multiple File NAME) AND THE FCB ******S> WILL BE SET UP WITH THE NEXT NAME, READY TO ******S> DO NORMAL PROCESSING (OPEN, READ, ETC.) ******S> ******S> CARRY IS SET IF NO MORE NAMES CAN BE FOUND ******S> ******S> THE ROUTINE IS COMMENTED IN PSEUDO CODE, ******S> EACH PSEUDO CODE STATEMENT IS IN <<...>> ******S> MFNAME: CPM STDMA,80H ;<> XRA A STA FCBEXT STA FCBRNADD A ADD A ADD A ADD A ADD A ADI 81H MOV L,A MVI H,0 PUSH H MOVE ,MFCUR+1,11 POP H ;<> MOVE ,FCB+1,11 XRA A ;<> STA FCBEXT RET ;<> BUFF EQU $ ;DISK READ BUFER END FINDOR FCB ;<> MFN02: INR A ;<> STC RZ DCR A ;<> ANI 3 C IN WHICH YOU WANT TO PROCESS SINGLE OR ******S> MULTIPLE FILES. ******S> ******S> JUST CALL "MFNAME" (Multiple File NAME) AND THE FCB ******S> WILL BE SET UP WITH THE NEXT NAME, READY TO ******S> DO NORMAL PROCESSING (OPEN, READ, ETC.) ******S> ******S> CARRY IS SET IF NO MORE NAMES CAN BE FOUND ******S> ******S> THE ROUTINE IS COMMENTED IN PSEUDO CODE, ******S> EACH PSEUDO CODE STATEMENT IS IN <<...>> ******S> MFNAME: CPM STDMA,80H ;<> XRA A STA FCBEXT STA FCBRN; ; FROMHARD.ASM ver 1.2 ; by Keith Petersen, W8SDZ ; (revised 9/26/80) ; ;This program will transfer files from CP/M on hard disk ;to CP/M on floppy disk. (It can also be used for transfers ;from 8" floppy to 5-1/4" minifloppy.) ; ;To do this you must bring up the floppy CP/M as a small ;system (say 24k). The system location isn't important so ;long as it does not overwrite the larger system in use by ;the hard disk. It is assumed that the user's system allows ;both disk cOUNT DCX H ;POINT BACK TO "BYTES LEFT" MOV M,B ;STORE BACK COUNT DCX H ;X MOV M,C ;X RET ;RETURN TO CALLER ******S> ******S> ******S> ******S>MFNAME - MULT-FILE ACCESS SUBROUTINE. ******S> ******S> MULTI-FILE ACCESS SUBROUTINE. ALLOWS PROCESSING ******S> OF MULTIPLE FILES (I.E. *.ASM) FROM DISK. THIS ******S> ROUTINE BUILDS THE PROPER NAME IN THE FCB EACH ******S> TIME IT IS CALLED. THIS COMMAND WOULD BE USED ******S> IN SUCH PROGRAMS AS MODEM TRANSFER, TAPE SAVE, ******S> ETO LDA MFFLG1 ;<> ORA A JNZ MFN01 MVI A,1 ; <> STA MFFLG1 MOVE FCB,MFREQ,12 ; <> LDA FCB STA MFCUR MOVE MFREQ,FCB,12 ; <> CPM SRCHF,FCB JMP MFN02 ;<> MFN01: MOVE MFCUR,FCB,12 ; <> CPM SRCHF,FCB MOVE MFREQ,FCB,12 ; <> CPM SRCHN,FCB ;<> MFN02: INR A ;<> STC RZ DCR A ;<> ANI 3 OUNT DCX H ;POINT BACK TO "BYTES LEFT" MOV M,B ;STORE BACK COUNT DCX H ;X MOV M,C ;X RET ;RETURN TO CALLER ******S> ******S> ******S> ******S>MFNAME - MULT-FILE ACCESS SUBROUTINE. ******S> ******S> MULTI-FILE ACCESS SUBROUTINE. ALLOWS PROCESSING ******S> OF MULTIPLE FILES (I.E. *.ASM) FROM DISK. THIS ******S> ROUTINE BUILDS THE PROPER NAME IN THE FCB EACH ******S> TIME IT IS CALLED. THIS COMMAND WOULD BE USED ******S> IN SUCH PROGRAMS AS MODEM TRANSFER, TAPE SAVE, ******S> ETO LDA MFFLG1 ;<> ORA A JNZ MFN01 MVI A,1 ; <> STA MFFLG1 MOVE FCB,MFREQ,12 ; <> LDA FCB STA MFCUR MOVE MFREQ,FCB,12 ; <> CPM SRCHF,FCB JMP MFN02 ;<> MFN01: MOVE MFCUR,FCB,12 ; <> CPM SRCHF,FCB MOVE MFREQ,FCB,12 ; <> CPM SRCHN,FCB ;<> MFN02: INR A ;<> STC RZ DCR A ;<> ANI 3 ontroller boards to be used without conflict. ; ; ; USING THIS PROGRAM ; ; 1 - Bring up the hard disk CP/M as a large system (eg. 56k). ; 2 - Cold boot the floppy CP/M. Log into the drive you will ; be transferring files to, then run this program. ; ;COMMANDS: ; FROMHARD filename.type ;gets file from default drive ; FROMHARD B:filename.type ;gets file from B: ; FROMHARD *.* ;gets all files ; FROMHARD B:*.* ;gets all files from B: ; ;All normal ambiguous file names are allowed. File   s written to ;the floppy disk will go to the default drive. ; FALSE EQU 0 TRUE EQU NOT FALSE ; ;CONDITIONAL ASSEMBLY SWITCHES FOR CP/M VERSION ; (only one should be true) ; CPM14 EQU FALSE ;CP/M VERSION 1.4 CPM2 EQU TRUE ;CP/M VERSION 2.x ; ;OTHER CONDITIONAL ASSEMBLY SWITCHES ; DJ2D EQU FALSE ;TRUE IF BIG SYSTEM IS DISCUS 2D FLOPPY REPORT EQU FALSE ;TRUE TO REPORT READS AND WRITES ;(nice, but slows down transfers) ; ;EQUATES ; MSIZE EQU 56 ;PUT BIG SYSTEM MEMORY SIZE HERE ; IF CPMQU 0 ;WARM BOOT ENTRY ADRS WRCON EQU 2 ;WRITE CHARACTER TO CONSOLE BDOS EQU 0005H ;THE RECEIVING BDOS VECTOR PRINT EQU 9 ;PRINT STRING (DE) UNTIL '$' OPEN EQU 15 ;OPEN FILE CLOSE EQU 16 ;CLOSE FILE SRCHF EQU 17 ;SEARCH DIR FOR FIRST OCCUR. SRCHN EQU 18 ;SEARCH DIR FOR NEXT OCCUR. DELETE EQU 19 ;ERASE FILE READ EQU 20 ;READ RECORD WRITE EQU 21 ;WRITE RECORD MAKE EQU 22 ;MAKE FILE STDMA EQU 26 ;SET DMA ADRS FCB EQU 5CH ;DEFAULT FILE CONTROL BLOCK FCBEXT EQU FCB+12 ;EXTENT BYTE IN FCB FCBRNO EQUgram',CR,LF,0 MORE: CALL MFNAME ;SEE IF FILE IS IN DIRECTORY JNC MOVNAM ;ANOTHER FILE FOUND, GET IT LDA MFFLG1 ;NOTHING FOUND, CHECK... ORA A ;... FIRST TIME FLAG JZ DONE ;AT LEAST ONE WAS FOUND CALL EXIT DB '++FILE NOT FOUND++$' ; DONE: CALL EXIT DB CR,LF,'DONE$' ; ;MOVE FILENAME FROM FCB TO FNAME AND PRINT IT ; MOVNAM: LXI H,FCB+1 LXI D,FNAME MVI B,8 ;8 CHARS IN FILE NAME CALL MOVER LXI H,FCB+9 LXI D,FNAME+9 MVI B,3 ;3 CHARS IN FILE TYPE CALL MOVER CALL ILPRT ;PRINT: file on destination disk',0 LXI D,NEWFCB MVI C,DELETE ;ERASE ANY OLD FILE CALL BDOS LXI D,NEWFCB MVI C,MAKE ;MAKE THE NEW ONE CALL BDOS CPI NOMAKE JNZ RDLOOP CALL EXIT DB BELL DB '++CANNOT CREATE FILE ON DESTINATION DISK++$' ; ;READ A SECTOR FROM BIG DISK ; RDLOOP: EQU $ ; IF REPORT CALL ILPRT ;PRINT: DB TAB,'Reading sector from source disk',0 ENDIF ;REPORT ; LXI D,80H MVI C,STDMA ;SET DMA TO 80H CALL SRC$BDOS LXI D,FCB MVI C,READ ;READ A RECORD CALL SRC$BDISK++$' ; TDONE: CALL ILPRT ;PRINT: DB 'Closing file on destination disk now',0 LXI D,NEWFCB MVI C,CLOSE ;CLOSE DESTINATION FILE CALL BDOS CPI BDCLOS JNZ MORE ;ANOTHER FILE? CALL EXIT DB BELL DB '++BAD CLOSE ON DESTINATION DISK++$' ; ;PRINT MESSAGE THEN EXIT TO CP/M WARM BOOT ; EXIT: POP D MVI C,PRINT CALL BDOS JMP WBOOT ; ;INLINE PRINT ROUTINE ; ILPRT XTHL ;SAVE HL, GET MSG ; ILPLP MOV A,M ;GET CHAR CALL TYPE ;OUTPUT IT INX H ;POINT TO NEXT MOV A,M ;TEST ORA A14 BIAS EQU (MSIZE-16)*1024 CCP EQU BIAS+2900H ;BASE OF CCP ENDIF ;CP/M 1.4 ; IF CPM2 AND (NOT DJ2D) BIAS EQU (MSIZE-20)*1024 CCP EQU BIAS+3400H ;BASE OF CCP ENDIF ;STANDARD CP/M 2.x ; IF CPM2 AND DJ2D BIAS EQU (MSIZE-20)*1024 CCP EQU BIAS+2D00H ;BASE DISCUS 2D CCP ENDIF ;CP/M 2.x ON DISCUS 2D ; SRC$BDOS EQU CCP+806H ;SENDING BDOS VECTOR ; BELL EQU 7 ;BELL CHARACTER TAB EQU 9 ;TAB CHARACTER CR EQU 0DH ;CARRIAGE RETURN LF EQU 0AH ;LINE FEED ; ;BDOS/CBIOS EQUATES ; WBOOT E FCB+32 ;RECORD NUMBER IN FCB ; NOERR EQU 0 ;NO ERROR EOF EQU 1 ;END OF FILE NTFND EQU 255 ;NOT FOUND NOMAKE EQU 255 ;CAN'T MAKE FILE BDCLOS EQU 255 ;BAD FILE CLOSE ; ; THIS IS THE START OF THE PROGRAM. ; ORG 100H ; START LDA FCB+1 CPI ' ' ;SEE IF FILENAME THERE JNZ SIGNON CALL ILPRT ;PRINT: DB CR,LF,'++NO FILE NAME SPECIFIED++',0 RET ;EXIT TO CP/M ; SIGNON: LXI SP,STACK ;SET STACK POINTER CALL ILPRT ;PRINT: DB CR,LF,'HARD DISK to FLOPPY',CR,LF DB 'multiple file transfer pro DB CR,LF,'--> FILE: ' FNAME: DB 'XXXXXXXX.XXX' DB CR,LF,0 ; ;SAVE FIRST FCB FOR USE LATER AS DESTINATION FILE NAME MVI B,11 ;NUMBER OF CHARACTERS TO MOVE LXI H,FCB+1 ;...FROM FIRST FCB LXI D,NEWFCB+1 ;...TO NEWFCB (USE DEFAULT DRIVE) CALL MOVER ; ;OPEN THE SOURCE FILE LXI D,FCB MVI C,OPEN CALL SRC$BDOS CPI NTFND ;NOT FOUND? JNZ OPENOK CALL EXIT DB BELL DB '++CAN''T OPEN FILE ON SOURCE DISK++$' ; ;OPEN THE DESTINATION FILE ; OPENOK: CALL ILPRT ;PRINT: DB 'OpeningOS CPI NOERR JZ WRLOOP ;NO ERROR, GO WRITE SECTOR CPI EOF JZ TDONE ;END OF FILE, GO CLOSE IT CALL EXIT DB BELL DB '++READ ERROR ON SOURCE DISK++$' ; ;WRITE A SECTOR TO SMALL DISK ; WRLOOP: EQU $ ; IF REPORT CALL ILPRT ;PRINT: DB TAB,'Writing sector to destination disk',0 ENDIF ;REPORT ; LXI D,80H MVI C,STDMA ;SET DMA TO 80H CALL BDOS LXI D,NEWFCB MVI C,WRITE ;WRITE A RECORD CALL BDOS CPI NOERR JZ RDLOOP CALL EXIT DB BELL DB '++WRITE ERROR ON DESTINATION D ;..FOR END JNZ ILPLP MVI A,CR ;CARRIAGE RETURN CALL TYPE MVI A,LF ;LINE FEED CALL TYPE XTHL ;RESTORE HL, RET ADDR RET ;RET PAST MSG ; TYPE PUSH B PUSH D PUSH H MOV E,A ;CHAR TO E FOR CP/M MVI C,WRCON ;WRITE TO CONSOLE CALL BDOS POP H POP D POP B RET ; ;MULTI-FILE ACCESS SUBROUTINE. ALLOWS PROCESSING ;OF MULTIPLE FILES (I.E. *.ASM) FROM DISK. THIS ;ROUTINE BUILDS THE PROPER NAME IN THE FCB EACH ;TIME IT IS CALLED. CARRY IS SET IF NO MORE NAMES ;CAN BE FOUND. THE R   OUTINE IS COMMENTED IN PSEUDO ;CODE, EACH PSEUDO CODE STATEMENT IS IN <<...>> ; MFNAME: ;<> MVI C,STDMA LXI D,80H CALL SRC$BDOS XRA A STA FCBEXT STA FCBRNO ;<> LDA MFFLG1 ORA A JZ MFN01 ;<> ;SAVE ORIG REQ LXI H,FCB LXI D,MFREQ MVI B,12 CALL MOVER LDA FCB STA MFCUR ;SAVE DISK IN CURR FCB ;<> LXI H,MFREQ LXI D,FCB MVI B,12 CALL MOVER MVI C,SRCHF LXI D,FCB CALL SRC$BDOS ;<> JM FOUND TO FCB>> POP H LXI D,FCB+1 MVI B,11 CALL MOVER ;<> XRA A STA FCBEXT STA FCBRNO STA NEWFCB STA NEWFCB+12 STA NEWFCB+32 STA MFFLG1 ;TURN OFF 1ST TIME SW ;<> RET ;------------------------------------------------ ; ;MOVE SUBROUTINE MOVE (B) BYTES FROM (HL) TO (DE) ; MOVER MOV A,M ANI 7FH ;STRIP CP/M 2.x ATTRIBUTES STAX D INX H INX D DCR B JNZ MOVER RET ; ;MULTI-FILE ACCESS WORK AREA ; MFFLG1 DB 1 ;1ST TIME SW MFREQ DS 12 ;REQ NAME MFC; ; GO: Autility command under CP/M by Anthony Skjellum ; ; September 14, 1979 ; ; ; This command performs the following function: ; ; GO (hex address) executes the address specified ; ; ; org 100h ;tpa start ; tbuff equ 80h fcb equ 5ch ; ; lxi d,0 ; initial hex value to zero lxi h,fcb+1 ; point to fcb created by ; the CCP (i.e. has hex address) ; ; mvi b,4 ; digit count go: mov a,m ; get digit cpi 20h ; check for space jnz go1 ; if not then use data fetched mvi a,30h ; 0Ah cmc rnc sui 7H cpi 0AH rc cpi 10H cmc ret ; ; ; ; end location dcr b ; decrement digit count jnz go ; if non-zero then continue xchg ; get address value in HL pchl ; after accumulation, execute address ; ; ; support routines: ; hexin: xchg call check rc dad h dad h dad h dad h ora l mov l,a xchg ret ; ; ; check: sui 30h ; check for valid hex digit ; return with carry set if invalid rc cpiIntroduction to the Microsoft BASIC Interpreter Special Characters Variable Type Declaration Chars Commands Edit Mode Subcommands Program Statements (except I/O) PRINT USING Format Field Specifiers Input/Output Statements Operators Arithmetic Functions String Functions I/O and Special Functions Interpreter Error Codes Introduction to the Microsoft BASIC Compiler Compiler Commands and Switches Compiler Error Messages :Introduction to the Microsoft BASIC Interpreter Thi HEL Fil i P MFN02 ; MFN01: ;<> LXI H,MFCUR LXI D,FCB MVI B,12 CALL MOVER MVI C,SRCHF LXI D,FCB CALL SRC$BDOS ;<> LXI H,MFREQ LXI D,FCB MVI B,12 CALL MOVER MVI C,SRCHN LXI D,FCB CALL SRC$BDOS ;<> MFN02: ;<> INR A STC RZ ;<> DCR A ANI 3 ADD A ADD A ADD A ADD A ADD A ADI 81H MOV L,A MVI H,0 PUSH H ;SAVE NAME POINTER LXI D,MFCUR+1 MVI B,11 CALL MOVER ;<> RET ;------------------------------------------------ ; ;MOVE SUBROUTINE MOVE (B) BYTES FROM (HL) TO (DE) ; MOVER MOV A,M ANI 7FH ;STRIP CP/M 2.x ATTRIBUTES STAX D INX H INX D DCR B JNZ MOVER RET ; ;MULTI-FILE ACCESS WORK AREA ; MFFLG1 DB 1 ;1ST TIME SW MFREQ DS 12 ;REQ NAME MFC equate a space with an entry of zero go1: call hexin ; accumulate value rc ; return to CCP if error inx h ; look at next location dcr b ; decrement digit count jnz go ; if non-zero then continue xchg ; get address value in HL pchl ; after accumulation, execute address ; ; ; support routines: ; hexin: xchg call check rc dad h dad h dad h dad h ora l mov l,a xchg ret ; ; ; check: sui 30h ; check for valid hex digit ; return with carry set if invalid rc cpiUR DS 12 ;CURR NAME ; NEWFCB DS 33 STACK EQU $+100 ; END TA NEWFCB+12 STA NEWFCB+32 STA MFFLG1 ;TURN OFF 1ST TIME SW ;<> RET ;------------------------------------------------ ; ;MOVE SUBROUTINE MOVE (B) BYTES FROM (HL) TO (DE) ; MOVER MOV A,M ANI 7FH ;STRIP CP/M 2.x ATTRIBUTES STAX D INX H INX D DCR B JNZ MOVER RET ; ;MULTI-FILE ACCESS WORK AREA ; MFFLG1 DB 1 ;1ST TIME SW MFREQ DS 12 ;REQ NAME MFCderive fro th "Microsof BASI Referenc Book" an i i divide int tw part -- on coverin th Interprete an th othe coverin th Compiler Thes program proces program writte i almos exactl th sam languag -- Microsof BASIC ther ar mino difference betwee th two however an thes ar discusse i th fil under the Compiler Introduction. The MBASIC (Microsoft BASIC) Interpreter is invoked as follows -- MBASIC [][/F:<#    files>][/M:] I Deletes last char typed Escapes Edit Mode Subcommands . Current line for EDIT, RENUM, DELETE, LIST, LLIST commands &O,& Prefix for Octal Constant &H Prefix for Hex Constant : Separates statements typed on the same line ? Equivalent to PRINT statement :Variable Type Declaration Characters $ String 0 to 255 chars % Integer -32768 to 32767 ! Single Precision 7.1 digit f Delete program lines EDIT EDIT line Edit a program line FILES FILES [filename] Directory LIST LIST [line[-[line]]] List program line(s) LLIST LLIST [line[-[line]]] List program line(s) on printer LOAD LOAD filename[,R] Load program; ,R means RUN MERGE MERGE filename Merge prog on disk with that in mem NAME NAME old AS new Change the name of a disk file NEW NEW sk , save pro in ASCII and ,P protects file SYSTEM SYSTEM Return to CP/M TROFF TROFF Turn trace off TRON TRON Turn trace on WIDT WIDT [LPRINT ex Se ter o printe carriag width default is 80 (term) and 132 (prin) :Edit Mode Subcommands A Abort -- restore original line and restart Edit nCc Change, delete chars End edit and save changes :Program Statements (except I/O) Statement Syntax Function CALL CALL variable [(arg list)] Call assembly or FORTRAN routine CHAIN CHAIN [MERGE] filename [,[line exp][,ALL][,DELETE range]] Cal progra an pas variable t it MERG wit ASCI file allow overlays star a lin ex i given AL mean al variable wil b passe (otherwis COMMO only) DELET. :Special Characters ^A Enters Edit Mode on line being typed or last line typed ^C Interrupts program execution and returns to MBASIC ^G Rings at terminal ^H Deletes last char typed ^I Tab (every 8) ^O Halts/resumes program output ^R Retypes the line currently being typed ^S Suspends program execution ^Q Resumes execution after ^S ^U,^X Deletes line being typed Ends every line being typed in Breaks a loating point # Double Precision 17.8 digit floating point :Commands Command Syntax Function AUTO AUTO [line][,inc] Generate line numbers CLEA CLEA [,[exp1][,exp2] Clea progra variables Exp set en o memor an Exp set amoun of stack space CONT CONT Continue program execution DELETE DELETE [[start][-[end]]]  Delete current prog and vars NULL NULL exp Set num of s after each line RENUM RENUM [[new][,[old][,inc]]] Renumber program lines RESET RESET Init CP/M; use after disk change Command Syntax Function RUN RUN [line number] Run a prog (from a particular line) RUN filename[,R] Run a prog on disk SAV SAV filename[, o ,P Sav pro ont die n characters nD Delete n characters E End edit and save changes; don't type rest of line Hstr Delete rest of line and insert string Istr Insert string at current pos nKc Kill all chars up to the nth occurrance of c L Print the rest of the line and go to the start of the line Q Quit edit and restore original line nSc Search for nth occurrance of c Xstr Goto the end of the line and insert string Backspace over chars; in insert mod allows deletion of an overlay before CHAIN is executed COMMON COMMON list of vars Pass vars to a CHAINed prog DEF DEF FNx[(arg list)]=exp Arith or String Function DEF USRn=address Define adr for nth assembly routine DEFINT range(s) of letters Define default var type INTeger DEFSNG " " " " " " " Single DEFDBL " " " " " " " Double     DEFSTR " " " " " " " String DIM DIM list of subscripted vars Allocate arrays END END Stop prog and close files ERASE ERASE var [,var ... ] Release space and var names ERROR ERROR code Generate error code/message FOR FOR var=exp TO exp [STEP exp] FOR loop Statement Syntax Function GOSUB GOSUB line number Call BASIC subroutine GOTO GOTO li ... ] End FOR ON ERROR ON ERROR GOTO line Error trap subroutine GOTO ON/GOSUB ON exp GOSUB line[,line] Computed GOSUB ON/GOTO ON exp GOTO line[,line] Computed GOTO Statement Syntax Function OPTION OPTION BASE n Min val for subscripts (n=0,1) BASE OUT OUT port,byte Output byte to port POKE POKE address,byte Memory put RANDOMIZE RANDOMIZE [exp] Reseed random nu Paus unti inpu por [XO select AND mask <> 0 WHILE/ WHILE exp stmts ... WEND Execute stmts as long as exp is T WEND :PRINT USING Format Field Specifiers Numeric Specifiers Specifier Digits Chars Definition # 1 1 Numeric field . 0 1 Decimal point + 0 1 Print leading or trailing sign - 0 1 Trailing sign (- if neg, otherwise) haracter // Character field; width=2+number of & Variable length field :Input/Output Statements Statement Syntax/Function CLOSE CLOSE [[#]f[,[#]f ... ]] Close disk files; if no arg, close all DATA DATA constant list List data for READ statement FIELD FIELD [#]f,n AS string var [,n AS string var ...] Define fields in random file buffer GET GET [#]f[,record number] Reat string;] string var INPU Rea a entir lin fro terminal leadin semicolo suppresse echo of / LINE INPUT #f,string var Read an entire line from a disk file LSET LSET field var=string exp Stor dat i rando fil buffe left-justifie o left-justif a non-disk string in a given field OPEN OPEN mode,[#] f,filename Open a disk file; mode must be one of -- I = sequential input file ne number Branch to specified line IF/GOTO IF exp GOTO line [ELSE stmt ... ] IF exp <> 0 then GOTO IF/THEN IF exp THEN stmt[:stmt] [ELSE stmt ... ] IF exp <> 0 then ... else ... LET [LET] var=exp Assignment MID MID$(string,n[,m])=string Replac portio o strin wit string2; start at pos n for m chars NEXT NEXT var[,varmber generator REM REM any text Remark -- comment RESTORE RESTORE [line] Reset DATA pointer RESUME RESUME or RESUME 0 Return from ON ERROR GOTO RESUME NEXT Return to stmt after error line RESUME line Return to specified line RETURN RETURN Return from subroutine STOP STOP Stop prog and print BREAK msg WAI WAI prot,mask[,select ** 2 2 Leading asterisk $ Floatin dolla sign place i fron o leading digit **$ 2 3 Asterisk fill and floating dollar sign , 1 1 Use comma every three digits ^^^^ 0 4 Exponential format _ 0 1 Next character is literal String Specifiers Specifier Definition ! Single cd a record from a random disk file INPUT INPUT [;] [prompt string;] var [,var ...] INPUT [;] [prompt string,] var [,var ...] Rea dat fro th terminal leadin semicolo suppresse ech o /,<, Relational tests (TRUE=-1, FALSE=0) <=,=<, >=,=>, <> The precedence of operators is -- 1. Expressions in parentheses 8. Relational Operators 2. Exponentiation 9. NOT 3. Negation (Unary -) 10. AND 4. *,/ 11. OR 5. \ 12. XOR 6. MOD 13. IMP 7. +,- 14. EQV :Arithmetic Functions Function Action ABS(exp) Absolexp) Evaluates the expression for the largest integer LOG(exp) Gives the natural log of the expression RND[(exp)] Generates a random number exp <0 seeds new sequence exp =0 returns previous number exp >0 or omitted returns new random number Function Action SGN(exp) 1 if exp >0 0 if exp =0 -1 if exp <0 SIN(exp) Sine of the expression (in radians) SQR(exp) Square root of eSTR([exp,]str1,str2) Return th firs positio o th firs occurrenc o str in str1 starting at position exp LEFT$(str,len) Returns leftmost length chars of the string expression LEN(str) Returns the length of a string MID$(string,start[,length]) Return char fro th middl o th strin startin a th positio specifie t th en o th strin o fo lengt characters Function Action OCT$(nvert th strin representatio o numbe t it numeric value :I/O and Special Functions Function Action CVI(str) Converts a 2-char string to an integer CVS(str) Converts a 4-char string to a single precision number CVD(str) Converts an 8-char string to a double precision number EOF(f) Returns TRUE (-1) if file is positioned at its end ERL Error Line Number ERR Error Code Number INP(port) Inputs a byte from ament or equality test - Negation or subtraction + Addition or string concatenation * Multiplication / Division (floating point result) ^ Exponentiation \ Integer division (integer result) MOD Integer modulus (integer result) NOT One's complement (integer) AND Bitwise AND (integer) OR Bitwise OR (integer) XOR Bitwise exclusive OR (integer) EQV Bitwise equivalence (integer) IMP Bitwise implication (integer)ute value of expression ATN(exp) Arctangent of expression (in radians) CDBL(exp) Convert the expression to a double precision number CINT(exp) Convert the expression to an integer COS(exp) Cosine of the expression (in radians) CSNG(exp) Convert the expression to a single precision number EXP(exp) Raises the constant E to the power of the expression FIX(exp) Returns truncated integer of expression FRE(exp) Gives memory free space not used by MBASIC INT(xpression TAN(exp) Tangent of the expression (in radians) :String Functions Function Action ASC(str) Returns ASCII value of first char in string CHR$(exp) Returns a 1-char string whose char has ASCII code of exp FRE(str) Returns remaining memory free space HEX$(exp) Converts a number to a hexadecimal string INPUT$(length [,[#]f]) Return strin o lengt char rea fro consol o fro disk file; characters are not echoed INexp) Converts an expression to an Octal string RIGHT$(str,len) Returns rightmost length chars of the string expression SPACE$(exp) Returns a string of exp spaces STR$(exp) Converts a numeric expression to a string STRING$(length,str) Return strin lengt lon containin th firs cha o the str STRING$(length,exp) Return strin lengt lon containin char wit numeri value exp VAL(str Con input port LOC(f Return nex recor numbe t rea o writ (rando file o number of sectors read or written (sequential file) LPOS(n) Returns carriage position of line printer (n is dummy) MKI$(value) Converts an integer to a 2-char string MKS$(value) Converts a single precision values to a 4-char string MKD$(value) Converts a double precision value to an 8-char string Function Action PEEK(exp) Reads a byte from memory location speci   fied by exp POS(n) Returns carriage position of terminal (n is dummy) SPC(exp) Used in PRINT statements to print spaces TAB(exp) Used in PRINT statements to tab to specified position USR[n](arg) Calls the user's machine language subroutine with the arg VARPTR(var Return addres o va i memor o zer i va ha no bee assigned a value VARPTR(#f Return th addres o th dis I/ buffe assigne t fil number :Interpreter  21 Unprintable error 9 Subscript out of range 22 Missing operand 10 Redimensioned array 23 Line buffer overflow 11 Division by zero 26 FOR without NEXT 12 Illegal direct 29 WHILE without WEND 13 Type mismatch 30 WEND without WHILE Disk Errors -- Code Error Code Error 50 Field overflow 58 File already exists 51 Internal error 61 Disk full 52 BONT DELETE EDIT LIST LLIST RENUM COMMON SAVE LOAD MERGE NEW ERASE Th followin statement ar use differentl wit th compile tha with the interpreter (refer to the manual for details) -- CALL DEFINT DEFSNG DEFDBL DEFSTR DIM ERASE END ON ERROR GOTO RESUME STOP TRON TROFF USRn :BASIC Compiler Commands and Switches The NEX is used /N Do not list generated object code /D Generate debug/checking code at runtime /S Write quoted strings of more than 4 chars as they are encountered /4 Recognize Microsoft 4.51 BASIC Interpreter conventions /à Rela lin numberin constraints line nee no b numbere sequentially; /4 and /C may not be used together /Z Use Z80 opcodes :BASIC Compiler Error Messages Compile-Time Fatal Errors SN Syntax error OM Ou ND Array not dimensioned SI Statement ignored Run-Time Error Messages 2 Syntax error 52 Bad file number 3 RETURN without GOSUB 53 File not found 4 Out of data 54 Bad file mode 5 Illegal function call 55 File already open 6 Floating/Integer ovfl 57 Disk I/O error 9 Subscript out of range 58 File already exists 11 Division by zero 61 Disk full 14 Out of strError Codes Code Error Code Error 1 NEXT without FOR 14 Out of string space 2 Syntax error 15 String too long 3 RETURN without GOSUB 16 String formula too complex 4 Out of data 17 Can't continue 5 Illegal function call 18 Undefined user function 6 Overflow 19 No RESUME 7 Out of memory 20 RESUME without error 8 Undefined line ad file number 62 Input past end 53 File not found 63 Bad record number 54 Bad file mode 64 Bad file name 55 File already open 66 Direct statement in file 57 Disk I/O error 67 Too many files :Introduction to the Microsoft BASIC Compiler Th followin direc mod command ar NO implemente o th compile and will generate an error message -- AUTO CLEAR CLOAD CSAVE C compiler is invoked by the BASCOM command; it may be called by -- BASCOM or BASCOM command line where "command line" is -- [dev:][obj file][,[dev:][lst file]]=[dev:]source file[/switch ...] I jus BASCO i used th use wil b prompte wit a asterisk after which he should enter the command line. Switches -- /E Use this switch if ON ERROR GOTO with RESUME is used / Us thi switc i O ERRO GOT wit RESUME RESUM 0 o RESUMt of memory SQ Sequence error TM Type mismatch TC Too complex BS Bad subscript LL Line too long UC Unrecognizable command OV Math overflow /0 Division by zero DD Array already dim'ed FN FOR/NEXT error FD Function already def UF Function not defined WE WHILE/WEND error /E Missing /E switch /X Missing /X switch Compile-Time Warning Errorsing space 62 Input past end 20 RESUME without error 63 Bad record number 21 Unprintable error 64 Bad filename 50 Field overflow 67 Too many files 51 Internal error  mode 5 Illegal function call 55 File already open 6 Floating/Integer ovfl 57 Disk I/O error 9 Subscript out of range 58 File already exists 11 Division by zero 61 Disk full 14 Out of str    NEX is used /N Do not list generated object code /D Generate debug/checking code at runtime /S Write quoted strings of more than 4 chars as they are encountered /4 Recognize Microsoft 4.51 BASIC Interpreter conventions /à Rela lin numberin constraints line nee no b numbere sequentially; /4 and /C may not be used together /Z Use Z80 opcodes :BASIC Compiler Error Messages Compile-Time Fatal Errors SN Syntax error OM Ou; Display cpm memory locations ; org 100h mvi c,12 ;check 1.4 or 2.2 call 5 mov a,l ora a lxi h,3328-6 ;length of 1.4 bdos jz mmp1 ;if version 1.4 ; lxi h,3584-6 ;length of 2.2 bdos mvi a,'2' ;change message sta mmpk sta mmpk+2 mmp1: shld mmpa ; lhld 6 ;get bdos entry address shld bdose lxi b,-806h ;calculate ccp fwa dad b shld ccpfwa ; dcx h ;calculate tpa lwa shld tpalwa inx h ; lxi b,800h ;calculate bdos fwa dad b shld bdfwa lxi b,6 ;calculate bpe call msg ; lxi h,0 ;display bdos fwa bdfwa equ $-2 call dhw lxi d,mmpf call msg ; lxi h,0 ;display bdos entry address bdose equ $-2 call dhw lxi d,mmpg call msg ; lxi h,0 ;display cbios fwa cbfwa equ $-2 call dhw lxi d,mmph call msg ; lxi h,0 ;display cbios warmboot entry wrmbt equ $-2 call dhw lxi d,mmpi call msg ; lxi d,mmpb ;display a line of dashes call msg jmp 0000 ;exit ; cr equ 0dh lf equ 0ah ; mmpb: db cr,lf,'---------------------------- CP/M version ' mmpk: db '1.4',cr,lf,'$' ; msg: mvi c,9 call 5 ret ; ; display hex word ; ; hl= word to display ; dhw: push h mov a,h call dhb pop h mov a,l ; ; display hex byte in a ; dhb: push psw rrc !rrc !rrc !rrc call dhd pop psw ; ; display hex digit ; ; digit in a.low ; dhd: ani 0fh cpi 10 jnc dhd1 adi '0' jmp dch ; dhd1: adi 'A'-10 ; ; display one character ; ; a= character ; dch: mov e,a mvi c,2 call 5 ret ; end ; pe call msg ; lxi h,0 ;display bdos fwa bdfwa equ $-2 call dhw lxi d,mmpf call msg ; lxi h,0 ;display bdos entry address bdose equ $-2 call dhw lxi d,mmpg call msg ; lxi h,0 ;display cbios fwa cbfwa equ $-2 call dhw lxi d,mmph call msg ; lxi h,0 ;display cbios warmboot entry wrmbt equ $-2 call dhw lxi d,mmpi call msg ; lxi d,mmpb ;display a line of dashes call msg jmp 0000 ;exit ; cr equ 0dh lf equ 0ah ; mmpb: db cr,lf,'----------------------------t of memory SQ Sequence error TM Type mismatch TC Too complex BS Bad subscript LL Line too long UC Unrecognizable command OV Math overflow /0 Division by zero DD Array already dim'ed FN FOR/NEXT error FD Function already def UF Function not defined WE WHILE/WEND error /E Missing /E switch /X Missing /X switch Compile-Time Warning Errorsdos entry address dad b shld bdose ; lxi b,0 ;calculate cbios fwa mmpa: equ $-2 dad b shld cbfwa ; lxi b,3 ;calculate cbios "warmboot" entry dad b shld wrmbt ; ; display memory locations ; lxi d,mmpb ;display line of dashes call msg lxi d,mmpj ;display system version number call msg lxi d,mmpc ;"warmboot", etc. call msg ; lxi h,0 ;display tpa lwa tpalwa equ $-2 call dhw lxi d,mmpd call msg ; lxi h,0 ;display ccp fwa ccpfwa equ $-2 call dhw lxi d,mm-----------' db cr,lf,'$' mmpc: db '0000 "warmboot" vector',cr,lf db '0005 BDOS vector',cr,lf db '005C default file control block (FCB)',cr,lf db '0080 CP/M record buffer',cr,lf db '0100 first word address (fwa) of user area',cr,lf,'$' mmpd: db ' last word address (lwa) of user area',cr,lf,'$' mmpe: db ' CCP fwa',cr,lf,'$' mmpf: db ' BDOS fwa',cr,lf,'$' mmpg: db ' BDOS entry point',cr,lf,'$' mmph: db ' CBIOS fwa',cr,lf,'$' mmpi: db ' CBIOS warmboot entry point',cr,lf,'$' mmpj: db 'System:dos entry address dad b shld bdose ; lxi b,0 ;calculate cbios fwa mmpa: equ $-2 dad b shld cbfwa ; lxi b,3 ;calculate cbios "warmboot" entry dad b shld wrmbt ; ; display memory locations ; lxi d,mmpb ;display line of dashes call msg lxi d,mmpj ;display system version number call msg lxi d,mmpc ;"warmboot", etc. call msg ; lxi h,0 ;display tpa lwa tpalwa equ $-2 call dhw lxi d,mmpd call msg ; lxi h,0 ;display ccp fwa ccpfwa equ $-2 call dhw lxi d,mm-----------' db cr,lf,'$' mmpc: db '0000 "warmboot" vector',cr,lf db '0005 BDOS vector',cr,lf db '005C default file control block (FCB)',cr,lf db '0080 CP/M record buffer',cr,lf db '0100 first word address (fwa) of user area',cr,lf,'$' mmpd: db ' last word address (lwa) of user area',cr,lf,'$' mmpe: db ' CCP fwa',cr,lf,'$' mmpf: db ' BDOS fwa',cr,lf,'$' mmpg: db ' BDOS entry point',cr,lf,'$' mmph: db ' CBIOS fwa',cr,lf,'$' mmpi: db ' CBIOS warmboot entry point',cr,lf,'$' mmpj: db 'System:   ßAN  Page 1 1  == No file by that name on this disk == $== No file requested == $== No "*" or "?" please == $ LISTT Pgm v1.3 02/22/83 Do you want tear tabs to use roll paper? (Y/N): Number of spaces to augment left margin (0-99): Accept FF (Y/N): Heading/date is: StartHx> +> wͯ>ͯ!#~ #+>+ 0!#~ H+{+ U2 > ;: \!4>z* *}|!"* {z* *"Ó*" !"* * }>*#" 6!;R2ɯ22: B!~ NP>0> ͋:G:z!>!H!8 ³à ڠw#0:xڠà;!9~ +~ 0G> +~1 0GLISTT -- File utility program for printers -- 02/22/83 Irvin M. Hoff Los Altos Hills, CA 94022 "LISTT" is a printer utility program that lists any requested file on your printer. (The CRT also displays what is being printed). The name was selected so it would be easy to type, easy to remember and be illus- trative of its capabilities. Include the name of the file (and its extent) that is to be listed when asking for  1) A "Y" gives tear tabs for roll paper. Any other reply (including RET) defaults to fanfold with no tear tabs. 2) Ability to include 0-99 spaces at the left margin for those printers without adjustable margins. A RET de- faults to no spaces (normal left margin). Rejects any non-numeric characters except RET. 3) Ignores feeds unless a 'Y' is typed. Outputs an approp- riate number of line feeds enabling printers without form feed tey may be set with "DDT", "SID" or by editing and reassembling: 0103H 1) PAGCOL -- sets the column the Page number starts at. Some printers have 72 columns total, some 80, some 132, etc. (Byte 0103) 0104H 2) TTABN -- Sets the space between tear tabs for roll paper. Some printers have 72 columns, some 80, some 132, etc.  at page : Quit at page : HIGHEST PAGE IS: "1!SH!~!~:!#4#~ !\ #~? :g2o|g"!\ 5223*" "<͒-4  ?͋, V ^ | ʶ> 9:,:<29ғ> ;^:<29ғ> ͡,\>!4>z-4> ͋:¶,>^͋@͋# : !R!R! >  !4H!H_Y&2!4H!H!B \J7w#x}77!4H!H! ʒ€mw#xmm!4H!H! ¶ãw#xڣã!4H: _> ;:<29> ;\: !R!qH_Y<2 !4H    ~# 5~͋#>~ͯ#H~;#R: t!>>-͡:G> ͡r>-͋!>2 ʡ ʡ:<2ͨ;_: {__: the program: A>LISTT HELLO.ASM A menu then appears asking several questions: Do you want tear tabs to use roll paper? (Y/N): (1) Number of spaces to augment left margin (0-99): (2) Accept FF (Y/N): (3) Heading/date is: (4) Start at page : (5) Quit at page : (6) o paginate correctly. 4) Heading desired (such as current date, etc.) Up to 124 characters may be used. The name of the file plus cur- rent page number near the right margin are both automatic. A RET defaults to file name and page number. 5) Asks for starting page (defaults to page 1). 6) Asks for page to stop at (defaults to end of file). NOTE: There are two options which may be user-set. These are locations 0103 and 0104. Th (Byte 0104) Thus you can compensate for various printers and also print any portion of the file you wish. FEATURES: a) Shows on the CRT what is being printed. b) Optional fanfold or roll paper. Adds tear tabs if roll paper is selected. c) Can abort at any time with CTL-C, but finishes the cur- rent line first. d) Can change the location of the Page number for use with printers of 72 columns, 80 columns, 13   2 columns, etc. (Byte at location 0103, via DDT.) e) Can change the spacing between the tear tabs for use with printers of 72 columns, 80 columns, 132 columns, etc. (Byte at location 0104, via DDT.) f) Can indent up to 99 spaces to effectively provide an ad- justable left margin (many printers do not permit changing the margin). This allows you to easily center any printing. g) Can start on any page desired, saving paper (and time!) if for the heading/date. k) An option on the menu allows you to ignore form feed chars. It automatically paginates without form feeds in the text. l) Works equally well on printers without form feed since it inserts the correct number of line feeds to paginate. m) Visually prints control characters imbedded in the text other than CR, LF, form feed or tab. You can thus dis- cover any unknown characters that normally do not print. COMMENT: Line n2 columns, etc. (Byte at location 0103, via DDT.) e) Can change the spacing between the tear tabs for use with printers of 72 columns, 80 columns, 132 columns, etc. (Byte at location 0104, via DDT.) f) Can indent up to 99 spaces to effectively provide an ad- justable left margin (many printers do not permit changing the margin). This allows you to easily center any printing. g) Can start on any page desired, saving paper (and time!) if ;************************************************************** ; MICRO RESOURCES CP/M RAM DISK ADDON MODULE ;************************************************************** ; ; ; THIS PROGRAM IS A SMALL TRANSIENT PROGRAM BASED BIOS SUBSTITURE ; THAT ALLOWS FILE TRANSFER UTILITY BETWEEN THE NORMAL CP/M SYSTEM ; DISKS AND AN MEMORY RESIDENT "RAM DISK". THIS TRANSIENT PROGRAM IS ; SETUP FOR ANY VERSION 2.2 CP/M SYSTEM. ; ; THIS PROGRAM PRESENTS A SMALL DISK DEMONSTRATION VERSION THAT USES ; 20 K BYOULD EASILY BE EXPANDED TO AS MUCH ; AS A MEGABYTE OF MORE. ; ; THE SUPPORTED RAM DISK FORMAT IS AS FOLLOWS: ; ; 10 TRACKS MAPPED INTO RAM ; 8 PHYSICAL SECTORS FER TRACK ; 256 BYTES/PER SECTOR ; SECTORS ACCESSED FROM RAM THROUGH THE STANDARD BEBLOCKING ; TECHNIQUES. RAM RESIDENT "HOST SECTORS" MAPPED TO ; 256 BYTES IN SIZE SO EXPANSION OF THIS PROGRAM TO ; BANK SWITCHED MEMORY CAN BE MADE EASILY. ; ; PROGRAM ACCESS TO THE RAM DRIVE IS DONE IN 256 BYTE SECTORS ; THAT ARE DEBLOCKED WITyou only wish to reproduce certain portions of a file. h) Can stop at any page desired, allowing the operator to do other things when only part of the file is needed. i) Shows the total number of pages in the file if you intion- ally (or otherwise) ask for a page number that is too high for the file. j) If a heading/date is longer than normal spacing for the page number, it is automatically moved further along. Up to 124 characters may be used umbers can be added to any ASCII file with PIP.COM and the [N] option: A>PIP HELLO1.ASM=HELLO.ASM[N] Form feeds can be removed with PIP.COM and the [F] option. You can edit CTL-L (form feed char.) into the file to force a new page wherever desired. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * you only wish to reproduce certain portions of a file. h) Can stop at any page desired, allowing the operator to do other things when only part of the file is needed. i) Shows the total number of pages in the file if you intion- ally (or otherwise) ask for a page number that is too high for the file. j) If a heading/date is longer than normal spacing for the page number, it is automatically moved further along. Up to 124 characters may be used TES OF THE HOST SYSTEM TPA TO DEMONSTRATE THE "RAM DISK" ; ADDON MODULE TECHNIQUE. THE DEMO VERSION USES 1K BYTE ALLOCATION ; GROUPS (BLOCKS) AND ALLOWS FOR A TOTAL OF 32 DIRECTORY ENTRIES AS ; DEFINED BY THE DISKDEF MACRO CALLS. PLEASE NOTE THAT WHILE THIS MAY ; NOT APPEAR TO BE A VERY PRACTICAL IMPLEMENTATION OF A RAM DISK ; IT DOES DEMONSTRATE THE FRIVER TECHNIQUES. A GREATLY EXPANDED VERSION ; WOULD USE ADDITIONAL BANK SWITCHED RAM BOARDS TO STORE THE DISK DATA ; SUCH THAT THE DISK STORAGE AREA CHIN A BUFFER CONTAINED INSIDE OF THIS SOFTWARE ; PACKAGE. THE INITIAL LOADING OF THIS SOFTWARE SWAPS OUT THE NORMAL ; CP/M DISK I/O ENTERY POINTS TO THE BIOS WITH A NEW SET OF ENTRY POINTS ; TO THIS MODULE. THIS MODULE THEN CHECKS ALL SELECT DISK ACCESSES FOR ; LOGICAL UNIT P: AND WILL STEER I/O REQUESTS FOR THIS DRIVE THROUGH ; DRIVERS CONTAINED WITHIN THIS PROGRAM. NOTE THAT THIS PROGRAM STILL ; DEPENDS UPON THE HOST CP/M SYSTEM BDOS AS THE FILE INTERFACE MEDIUM. ; ; OPERATION OF THE PROGRAM IS DO   NE TO MOVE THE MODULE UP TO A WORKSPACE ; BELOW THE MEMORY RESIDENT CCP. THE WARM BOOT VECTOR AT THE SYSTEM ; WARM BOOT ENTRY POINT IS SWAPPED TO A NEW ENTRY POINT WITHIN THE ; RELOCATED I/O MODULE. THE NEW WARMBOOT FUNCTION SIMPLY RE-ENTERS ; THE ALREADY PRESENT CCP FOR FURTHER OPERATOR COMMAND PROCESSING. ; THE BDOS ENTRY VECTOR IS ALSO MODIFIED TO PERMIT THE DYNAMIC ; MODIFICATION OF THE USER PROGRAM AREA SIZE SUCH THAT THE CCP AND ; THE RELOCATED I/O MODULE DO NOT GET OVERLAYED BY THE TRANSIENT BYTE IN THE (A) REGISTER IF THE MODULE IS PRESENT. ; IF THE ADDRESS BYTE IN THE FIRST BYTE OF THE FCB IS NOT RECOGNIZED, ; THEN THE MODULE PASSES THE OPEN FILE REQUEST ON TO THE NEXT HIGHER ; LEVEL BDOS CALL. IN ANY CASE THE NON PRESENCE OF A FILE BY THE NAME ; OF "A,,,,,,,.,,," IS VIRTUALLY ASSURED TO CAUSE THE BDOS TO RETURN ; A NOT FOUND "0FFH" ERROR CODE IN THE (A) REGISTER. THIS WOULD INDICATE ; THE ABSENSE OF THE MODULE BEING CHECKED FOR. ; ; ; THIS RAM DISK DRIVER PACKAGE ; PROGRAM IS COPYRXED BOOT ADDRESS BDOS EQU 0005H ;FIXED BDOS ADDRESS DEFFCB EQU 005CH ;DEFAULT FCB LOCATION DEFBUF EQU 0080H ;DEFAULT SYSTEM BUFFER RESET EQU 13 ;RESET DISK SYSTEM OPEN EQU 15 ;OPEN FILE STDMA EQU 26 ;SET DMA ADDRESS ; ; ;ASCII CHARACTER DEFINITIONS ; LF EQU 00AH ;ASCII LINE FEED CHARACTER CR EQU 00DH ;ASCII CARRIAGE RETURN CHARAVTER ; ; ;SECTOR DEBLOCKING ALGORITHMS FOR CP/M 2.2 ; MACLIB DISKDEF ; SMASK MACRO HBLK ;UTILITY MACRO TO COMPUTE SECTOR MASK ; ; COMPUTE LOG2(HBLK), R ;HOST DISK SECTOR SIZE ; HDSPT EQU 32 ;HOST HARD DISK 256 BYTE SECTORS/TRACK HSTBLK EQU HSTSIZ/128 ;CP/M SECTS/HOST BUFF ; SECMSK EQU HSTBLK-1 ;SECTOR MASK SMASK HSTBLK ;COMPUTE SECTOR MASK SECSHF EQU @X ;LOG2(HSTBLK) ; ;SECTOR SKEW INTERLACE FACTOR ; SKEW EQU 00 ;SECTOR SKEW FACTOR ; SECSIZ EQU 256 ;NUMBER OF BYTES IN DISK RECORD ; ; ;**************************************************************************** ; ; CSEG ;SET ORIGIN TO ZERO FOR RELOCATABLE ;ASSEMBLY BY RMACON ADDRESS IS PLACED HERE ;FROM LOCATION 6 & 7 BY THE START UP MODULE PROVIDED THIS ;MODULE IS DETERMINED TO NOT ALREADY PR DEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEO;T"A,,,,,,,.,,," LXI D,CHKFCB ;POINT AT THE CHECK FCB CALL BDOS ;CALL NORMAL BDOS ADDRESS ORA A JNZ NOT$PRES ;NON ZERO RETUR; PROGRAM AREA'S BUFFER SPACES. THE UTILITY, WHEN LOADED PERFORMS ; A CHECK TO VERIFY WHETHER A RELOCATED MODULE IS ALREADY PRESENT ; IN MEMORY. THE ALREADY PRESENT CHECK IS DONE VIA A SPECIALLY DEFINED ; BDOS CALL THAT REQUESTS THE OPENING OF A FILE WITH THE SPECIALLY ; DEFINED NAME SEQUENCE OF "A,,,,,,,,.,,," AS THE FILE NAME WHARE (A) ; IS A REQUEST NUMBER FOR PRESENCE CHECKING. AS THIS CHARACTER SEQUENCE ; IS AN ILLEGAL FILE NAME SEQUENCE, THE CHECK PROGRAM WILL TRAP THE NAME ; AND RETURN A ZERO IGHT PROTECTED BY: ; ; COPYRIGHT (C) 1982 ; ; MICRO RESOURCES ; 2468 HANSEN COURT ; SIMI VALLEY, CALIFORNIA 93065 ; (805) 527-7922 ; ;***************************************************************************** ; ; ; ;DEFINE TRUE AND FALSE ASSEMBLY PARAMETERS ; TRUE EQU -1 ;DEFINE TRUE FALSE EQU NOT TRUE ;DEFINE FALSE ; ; ;DEFINE RAMSISK MODULE SELECT ADDRESS AS SPECIAL VALUE ; MODADDR EQU 08AH ;ADDRESS OF THIS MODULE ; ; ;CP/M BDOS INTERFACE EQUATES ; ASEG BOOT EQU 0000H ;FIETURN @X AS RESULT ; (2 ** @X = HBLK ON RETURN) ; @Y SET HBLK @X SET 0 ; ; COUNT RIGHT SHIFTS OF @Y UNTIL = 1 ; REPT 8 IF @Y = 1 EXITM ENDIF ; ; @Y IS NOT 1, SHIFT RIGHT ONE POSITION ; @Y SET @Y SHR 1 @X SET @X + 1 ENDM ENDM ; ; ;BDOS CONSTANTS ON ENTRY TO "WRITE" ; WRALL EQU 0 ;WRITE TO ALLOCATED BLOCK WRDIR EQU 1 ;WRITE TO DIRECTORY WRUAL EQU 2 ;WRITE TO UNALLOCATED BLOCK ; ; ; ;CP/M 2.2 TO HOST DISK CONSTANTS ; BLKSIZ EQU 2048 ;CP/M ALLOCATION SIZE HSTSIZ EQU 256 ; ; ;SETUP STORAGE FOR THE RAM DISK DRIVE DATA BUFFER BELOW THE RELOCATED ;ADDON MODULE. ; RAMBUF EQU $-(10*8*SECSIZ) ;SIZE SET AT 10 TRACKS OF EIGHT 256 ;BYTE SECTORS PER TRACK BUFSIZ EQU $-RAMBUF ;SIZE OF FUFFER FOR INIT CLEAR ; ; ;FIRST TIME START UP ENTRY POINT FOR THE RAM DISK AUTO RELOCATING ;I/O MODULE. ENTRY HERE ASSURES PRESENSE OF CP/M 2.2. ; JMP CHKPRES ;GO CHECK IF A MODULE OF ;SAME FUNCTION ADDRESS IS PRESENT ;IN SYSTEM ; ; ;SUBSTITURE BDOS ENTRY POINT. EXECUTIN MOFULE IS NOT ;..PRESENT LXI D,PRESMSG ;POINT TO PRESENT MESSAGE MVI C,9 ;PRINT FUNCTION CODE CALL BDOS ;PRINT ALREADY PRESENT MESSAGE RET ;SIMPLE RETURN TO THE CCP ; CHKFCB: DB 0,MODADDR,',,,,,,,,,,',0,0,0,0 DS 16 DB 0 ; PRESMSG: DB CR,LF,'Micro Resources Ram Disk Already Active','$' ; ; ;HERE IF THIS RELOCATED MODULE IS NOT PRESENT IN MEMORY ; NOT$PRES: POP H ;COMPUTE CCP RE-ENTRY POINT PUSH H ; WITH STANDARD CPM 2.2 LXI D,075CH ;NEGATIVE OFFSET TO CCP ENTRY ;    ; FOR USE WITH ZCPR CPM OR USE 0765H ABOVE ; LXI D,0806H-003H ;LOAD OFFSET OF CCP TO BDOS LHLD 006H ;GET BDOS ENTRY POINT ; ;END OF ZCPR ; MOV A,L SUB E MOV L,A MOV A,H SBB D MOV H,A LDA BDOS+2 SUI 8 MOV H,A MVI L,3 SHLD CCP$ENT ;SAVE THAT ENTRY ADDRESS ; LHLD BDOS+1 ;GET PREVIOUS BDOS ADDRESS SHLD TO$BDOS+1 ;SET TO LOCAL REFERENCE VECTOR ; ; ;COMPUTE THE NEW RAM TOP OF TPA TO SET IN A JUMP ONE PAGE BELOW ;FOR PLACEMENT OF BASE OF THE RAM DISK DRIVE FOR BDOS REFER JNZ ZLP ; ; ;INITIALIZE THE RAM BUFFER TO LOOK LIKE FRESH FORMATTED DRIVE ; LXI B,BUFSIZ ;RAM DRIVE SIZE LXI H,RAMBUF ;DRIVE BASE ADDRESS E5LP: MVI M,0E5H ;STORE AN E5 BYTE INX H ;BUMP POINTER DCX B ;DEC BYTE COUNT MOV A,B ORA C JNZ E5LP ; LXI H,RAMSEL ;DISABLE DRIVE SELECT FOR RAM DISK MVI M,00H ; CALL MOVDN ;MOVE DOWN THE BIOS VECTOR TABLE LXI H,BOOTENT ;SET MOVED DOWN TABLE TO LOCAL BOOT HANDLER SHLD BWBOOT+1 ; CALL PRTMSG ;PRINT SIGNON MESSAGE ; DB CR,LF,'MiCP$ENT ;GET THE CCP ENTRY POINT LDA 004H ;GET CURRENTLY LODDED DRIVE MOV C,A PCHL ; ; ;NEW WARM BOOT ENTRY LOCATION THAT RESETS THE DISK SYSTEM ;AND TRANSFERS CONTROL BACK TO THE ALREADY PRESENT CCP ; BOOTENT: JMP CCPGO ;NO GO BACK TO THE CCP ; ; ;HERE FROM A BDOS ENTRY TO TRAP FILE OPEN I/O TO CHECK FOR ;MODULE PRESENT CHECK. ; BDOS$SCAN: PUSH D ;SAVE CALLERS PARAMETERS PUSH B MOV A,C ;GET FUNCTION CODE TO A CPI OPEN ;SEE IF THIS IS AN OPEN FUNCTION JNZ CHKFAIL INX D  B ;PROPER OPEN CHECK FAIL POP D JMP TO$BDOS ;OFF TO THE NORMAL BDOS ROUTINE ; ; ; XFRTAB: ; ;SUBSTITURE BIOS VECTOR TABLE. THIS JUMP TABLE VECTORS ALL CP/M ;DISK I/O TO THIS TRANSIENT MODULE FIRST. TABLE IS PUT INTO THE ;BIOS VECTOR TABLE POSITION BY A CALL TO THE SUBROUTINE "MOVDN" ; ; JMP BCBOOT ;TO NORMAL BIOS COLD BOOT ROUTINE JMP BOOTENT ;TO LOCAL WARM BOOT HANDLER JMP BCSTAT ;TO NORMAL BIOS CONSOLE STATUS CHECK JMP BCIN ;TO NORMAL BIOS CONSOLE INPUT JMP BCOUT ;TO NORMALE ORIGINAL BIOS DISK I/O VECTOR TABLE ;INITIALIZED BY CALLING THE "MOVDN" SUBROUTINE. ; BCBOOT: JMP $-$ ;TO BIOS COLD BOOT ROUTINE BWBOOT: JMP $-$ ;TO BIOS WARM BOOT ROUTINE BCSTAT: JMP $-$ ;TO BIOS CONSOLE STATUS CHECK BCIN: JMP $-$ ;TO BIOS CONSOLE INPUT BCOUT: JMP $-$ ;TO BIOS CONSOLE OUTPUT BLOUT: JMP $-$ ;TO BIOS LPT OUTPUT BPUN: JMP $-$ ;TO BIOS PUNCH OUTPUT BRDR: JMP $-$ ;TO BIOS READER INPUT BHOME: JMP $-$ ;TO BIOS HOME DISK ROUTINE BSELDSK: JMP $-$ ;TO BIOSENCE ; LXI H,RAMBUF DCR H ;ONE PAGE DOWN MVI L,06H ;AT CP/M'S BDOS LOOK ALIKE SHLD BDOS+1 ;BASE+6 LXI D,BDOS$SCAN MVI M,0C3H ;SET A JUMP AT TPA TOP INX H MOV M,E ;LOW BYTE OF ENTRY POINT INX H MOV M,D ;HIGH BYTE OF ENTRY POINT ; ; ;INITIALIZE ALL ITEMS FOR USE IN THIS I/O HANDLER ; MVI B,ENDZ-STARTZ ;ZERO DATA AREA IN PARAMETER TABLE LXI H,STARTZ ZLP: MVI M,00H ;PUT IN A ZERO PARM BYTE INX H ;POINT TO NEXT BYTE TO BE ZEROED DCR B ;CHECK BYTE COUNT TO SEE IF DONE cro Resources RAM Disk Demonstration' DB CR,LF,'Add-on Access Module Version 1.0 6/14/82' DB CR,LF,'Copyright (C) 1982 Micro Resources' DB CR,LF,0 ; ; ; ;HAVE THIS UTILITY QUEUE BOTH BIOS AND THIS DRIVER TO THE SAME ;CP/M DATA BUFFER ADDRESS ; LXI D,DEFBUF ;USE DEFAULT BUFFER MVI C,STDMA ;SET DMA CODE CALL TO$BDOS ; ; ;RETURN TO CCP VIA THE OLD DEFINED REENTRY POINT ; CCPGO: LXI H,RAMBUF DCR H ;ONE PAGE DOWN MVI L,06H ;AT CP/M'S BDOS LOOK ALIKE SHLD BDOS+1 ;BASE+6 LHLD C;POINT TO FCB CHECK BYTE LXI H,10 ;SET SCAN COUNTER TO FAKE FILE NAME END DAD D MVI B,10 ;NUMBER OF "," TO CHECK FOR SCAN$LOOP: MOV A,M ;GET FILE NAME CHARACTER CPI ',' JNZ CHKFAIL ;PASS ON IF CHECK FAIL DCX H ;DECREASE BUFFER POINTER DCR B JNZ SCAN$LOOP ;CHECKED ALL PASSIBLE CHARS YET MOV A,M ;CHECK IF ADDRESS BYTE IS OURS CPI MODADDR JNZ CHKFAIL ;BALE OUT IF NOT XRA A ;RETURN ZERO BYTE IF ALL CHECK VALID POP B POP D RET ;BACK TO PRESENT CHECKER ; CHKFAIL: POP BIOS CONSOLE OUTPUT JMP BLOUT ;TO NORMAL BIOS LPT OUTPUT JMP BPUN ;TO NORMAL BIOS PUNCH OUTPUT JMP BRDR ;TO NORMAL BIOS READER INPUT JMP HOME ;MOVE DISK TO TRACK ZERO JMP SELDSK ;SELECT DISK DRIVE JMP SETTRK ;SEEK TO TRACK IN REG A JMP SETSEC ;SET SECTOR NUMBER JMP SETDMA ;SET DISK STARTING ADR JMP READ ;READ SELECTED SECTOR JMP WRITE ;WRITE SELECTED SECTOR JMP BLSTST ;GO RIGHT TO NORMAL BIOS FOR THIS I/O JMP SECTRAN ;SECTOR TRANSLATE ; ; LOCTAB: ; ;LOCAL COPY OF TH SELECT DISK ROUTINE BSETTRK: JMP $-$ ;TO BIOS SET TRACK ROUTINE BSETSEC: JMP $-$ ;TO BIOS SET SECTOR ROUTINE BSETDMA: JMP $-$ ;TO BIOS SET DMA ROUTINE BREAD: JMP $-$ ;TO BIOS SECTOR RAD ROUTINE BWRITE: JMP $-$ ;TO BIOS SECTOR WRITE ROUTINE BLSTST: JMP $-$ ;TO BIOS LIST STATUS ROUTINE BSTRAN: JMP $-$ ;TO BIOS SECTOR TRANSLATE ROUTINE ; ; ;SUBROUTINE TO INTERCHANGE BIOS DISK I/O VECTOR TABLE ENTRIES WITH ;THOSE CONTAINED LOCALLY. ; TABSIZ EQU 17*3 ;TABLE SIZE TO INITIALIZE    WITH 17 JMP'S ; ; MOVDN: LHLD BOOT+1 ;GET ORIGINAL WARM BOOT VECTOR POINTER DCX H ;ADJUST TO BASE OF COLD BOOT VECTOR DCX H DCX H MVI A,TABSIZ ;SET BYTE COUNT TO MOVE STA BYTCNT LXI D,LOCTAB ;POINT TO LOCAL TABLE FILL FROM ABOVE LXI B,XFRTAB ;POINT TO TABLE TO MOVE UP MDLP: MOV A,M ;GET A BIOS TABLE BYTE STAX D ;PUT IN LOCAL COPY TABLE LDAX B ;GET BYTE OF PATCH TABLE MOV M,A ;PUT PATCH BYTE INTO BIOS POSITION INX H ;MOVE UP TO NEXT BYTE INX D INX B LDA BYTCNT ;SEOBEX DRIVE SELECT FLAG STA RAMSEL JMP BSELDSK ;IF NOT FOR US THEN LET BIOS HAVE SELECT ; ; ;HERE IF DRIVE SELECT WAS FOR THIS PIECE OF SOFTWARE ; SDSK1: SUI 'D'-041H ;SET SEKDSK TO THE HEAD SELECT CODE FOR STA SEKDSK ;..RAM DISK DRIVE ; PUSH PSW MVI A,0FFH ;SET THE RAM DRIVE SELECT FLAG STA RAMSEL POP PSW ; LXI H,DPBASE ;PASS BACK DISK PARAMETER BASE XRA A ;SET A REG. = 00 RET ;RETURN FROM SELDSK ; ; ;DO DIGITAL RESEARCH BUFFER PURGE IF NEED BE AND BALE OUT ;NO RESTORE NOT NEED TO TRANSLATE ; RAM DISK SECTOR BECAUSE RAM HAS NO ROTATIONAL LATENCY ; SECTRAN: LDA RAMSEL ;SEE IF SECTRAN FOR US ORA A JZ BSTRAN ;TO BIOS IF NOT LOCAL ; MOV H,B MOV L,C RET ;RETURN FROM SECTRAN ; ; ;SET DISK SECTOR NUMBER ; SETSEC: LDA RAMSEL ;SEE IF SECTOR FOR US ORA A JZ BSETSEC ;TO PROM IF NOT LOCAL ; MOV A,C ;GET SECTOR NUMBER STA SEKSEC ;SECTOR TO EMULATE RET ;RETURN FROM SETSEC ; ; ;SET DISK DMA ADDRESS ; SETDMA: PUSH H MOV H,B ;MOVE B&C LDA RAMSEL ;IS THIS WRITE FOR HERE ORA A JZ BWRITE ;TO BIAS IF NOT SO ; XRA A ;0 TO A REG. STA READOP ;NOT A READ OPERATION MOV A,C ;WRITE TYPE IN C STA WRTYPE CPI WRUAL ;WRITE UNALLACATED? JNZ CHKUNA ;CHECK FOR UNALLOCATED ; ; ;WRITE TO UNALLOCATED, SET PARAMETERS ; MVI A,BLKSIZ/128 ;NEXT UNALLOCATED RECORDS STA UNACNT LDA SEKDSK ;DISK TO SEEK STA UNADSK ;UNADSK = SEKDSK LHLD SEKTRK SHLD UNATRK ;UNATRK = SECTRK LDA SEKSEC STA UNASEC ;UNASEC = SEKSEC ; ; ;JNZ ALLOC ;SKIP IF NOT ; ; ;MATCH, MOVE TO NEXT SECTOR FOR FUTURE REFERENCE ; INR M ;UNASEC = UNASEC+1 MOV A,M ;END OF TRACK? PUSH B MVI B,HDSPT ;USE HARD DISK SPT CMP H POP B JC NOOVF ;SKIP IF NO OVERFLOW ; ; ;OVERLFOW TO NEXT TRACK ; MVI M,0 ;UNASEC = 0 LHLD UNATRK INX H SHLD UNATRK ;UNATRK = UNATRK+ ; ; ;MATCH FOUND, MARK AS UNNECESSARY READ ; NOOVF: XRA A ;0 TO A REG. STA RSFLAG ;REFLAG = 0 JMP RWOPER ;TO PERFORM THE WRITE ; ; ;NOT AN UNALLOCATED RECE IF DONE YET DCR A STA BYTCNT JNZ MDLP ;CONTINUE IF NOT DONE YET RET ; BYTCNT: DB 0 ;LOCAL MOVE BYTE COUNTER ; ; ;*************************************************************************** ; ;PARAMETER TABLE FOR TPA REASIDEN RAM DRIVER ; DISKS 1 ;ONE LOGICAL DRIVES SUPPORTED DISKDEF 0,1,16,,1024,20,32,0,0 ;P: RAM DRIVE ; SELDSK: MOV A,C ;GET NEW UNIT NUMBER CPI 'D'-041H ;IS THIS OUR DRIVE? JZ SDSK1 ;IF SO THEN GIVE THEM A PARAMETER POINTER ; XRA A ;IF NOT CLEAR THE Z MEMORY IS RANDOM ACCESS ; HOME: LDA RAMSEL ;SEE IF RESTORE FOR US ORA A JZ BHOME ;NO MUST BE FOR BIOS DRIVE ; LDA HSTWRT ;CHECK HOST ACTIVE WRITE FLAG ORA A JNZ HOMEIT STA HSTACT HOMEIT: RET ; ; ;SET TRACK NUMBER SPECIFIED BY B&C REGS. ; SETTRK: LDA RAMSEL ;SEE IF TRACK FOR US ORA A JZ BSETTRK ;TO PROM IF NOT LOCAL ; MOV H,B MOV L,C SHLD SEKTRK ;TRACK TO EMULATE RET ; ; ; ;TRANSLATE THE SECTOR GIVEN BY B&C REGS. ; ; NO TRANSLATE DONE AT THIS TIME. WE WILL TO H&L MOV L,C SHLD DMAADR ;PUT AT DMA ADR ADDRESS POP H JMP BSETDMA ;TELL BIOS DMA ADDRESS ; ; ;READ THE SELECTED CP/M 2.2 SECTOR ; READ: LDA RAMSEL ;SEE IF OPERATION FOR US ORA A JZ BREAD ;GO READ IN BIOS IF NOT FOR US LOCAL ; XRA A ;CLEAR UNALLOCATED COUNT STA UNACNT MVI A,1 STA READOP ;READ OPERATION STA RSFLAG ;MUST READ DATA MVI A,WRUAL STA WRTYPE ;TREAT AS UNALLOCCATED JMP RWOPER ;TO PERFORM THE READ ; ; ;WRITE THE SELECTED CP/M 2.2 SECTOR ; WRITE: CHECK FOR WRITE TO UNALLOCATED SECTOR ; CHKUNA: LDA UNACNT ;ANY UNALLOCATED REMAINING? ORA A JZ ALLOC ;SKIP IF NOT ; ; ;MORE UNALLOCATED RECORDS REMAIN ; DCR A ;UNACNT = UNACNT-1 STA UNACNT LDA SEKDSK ;SAME DISK? LXI H,UNADSK CMP M ;SEKDSK = UNADSK? JNZ ALLOC ;SKIP IF NOT ; ; ;DISKS ARE THE SAME ; LXI H,UNATRK CALL SEKTRKCMP ;SEKTRK = UNATRK? JNZ ALLOC ;SKIP IF NOT ; ; ;TRACKS ARE THE SAME ; LDA SEKSEC ;SAME SECTOR? LXI H,UNASEC CMP M ;SEKSEC = UNASEC? ORD, REQUIRES PRE-READ ; ALLOC: XRA A ;0 TO A REG. STA UNACNT ;UNACNT = 0 INR A ;1 TO A REG. STA RSFLAG ;RSFLAG = 1 ; ; ;COMMON CODE FOR READ AND WRITE FOLLOWS: ; RWOPER: ;ENTER HERE TO PERFORM THE READ/WRITE XRA A ;ZERO TO A REG. STA ERFLAG ;NO ERRORS (YET) LDA SEKSEC ;COMPUTE HOST SECTOR ; REPT SECSHF ORA A ;CARRY = 0 RAR ;SHIFT RIGHT ENDM ; ; ;LET BIOS PRETEND THAT SECTORS ARE NUMBERED FROM 1 TO AVOID ;OTHER PROBLEMS IN THE "SEKHST" SECTOR NUMBER VALUE. ;     INR A STA SEKHST ;HOST SECTOR TO SEEK ; ; ;ACTIVE HOST SECTOR? ; LXI H,HSTACT ;HOST ACTIVE FLAG MOV A,M MVI M,1 ;ALWAYS BECOMES 1 ORA A ;WAS IT ALREADY? JZ FILHST ;FILL HOST IF NOT ; ; ;HOST BUFFER ACTIVE, SAME AS SEEK BUFFER? ; LDA SEKDSK LXI H,HSTDSK ;SAME DISK? CMP M ;SEKDSK = HSTDSK? JNZ NOMATCH ; ; ;SAME DISK, SAME TRACK? ; LXI H,HSTTRK CALL SEKTRKCMP ;SEKTRK = HSTTRK? JNZ NOMATCH ; ; ;SAME DISK, SAME TRACK, SAME BUFFER? ; LDA SEKHST LXI H,HSTSEC ;SEKSECMSK ;LEAST SIGNIF BITS MOV L,A ;READY TO SHIFT MVI H,0 ;DOUBLE COUNT ; REPT 7 ;SHIFT LEFT 7 DAD H ENDM ; ; ;HL HAS RELATIVE HOST BUFFER ADDRESS ; LXI D,HSTBUF DAD D ;HL = HOST ADDRESS XCHG ;NOW IN DE LHLD DMAADR ;GET/PUT CP/M DATA MVI C,128 ;LENGTH OF MOVE; CP/M SECTOR SIZE LDA READOP ;WHICH WAY? ORA A JNZ RWMOVE ;SKIP IF READ ; ; ;WRITE OPERATION, MARK AND SWITCH DIRECTION ; MVI A,1 STA HSTWRT ;HSTWRT = 1 XCHG ;SOURCE/DESTINATION SWAP ; ; ;C INIT ;UTILITY SUBROUTINE FOR 16-BIT COMPARE ; SEKTRKCMP: ;HL = .UNATRK OR .HSTTRK, COMPARE ;..WITH SEKTRK XCHG LXI H,SEKTRK LDAX D ;LOW BYTE COMPARE CMP M ;SAME? RNZ ;RETURN IF NOT ; ; ;LOW BYTES EQUAL, TEST HIGH FIRST ; INX D INX H LDAX D CMP M ;SETS FLAGS RET ; ; WRITEHST: ;PERFORMS THE PHYSICAL WRITE ;TO THE HST DISK ; ;HSTDSK = HOST DISK NUMBER, HSTTRK = HOST TRACK NUMBER, ;HSTSEC = HOST SECT NUMBER. WRITE "HSTSIZ" BYTES ;FROM HSTBUF AND RETURN ERROR FLAGK IOPB CALL RREAD ;GO READ SECTOR XRA A STA ERFLAG RET ; ; ;ROUTINE TO SETUP THE RAM DISK SOFTWARE ADDRESS VALUES. VALUES ;BASED UPON THE CP/M LOGICAL VALUES ; RIOPB: LXI H,HSTBUF ;POINT TO HOST BUFFER ADDRESS SHLD XFRPNT LDA HSTTRK ;CONVERT CP/M TRACK AND SECTOR TO ADD A ; 256 BYTE RAM PAGE ADDRESS INDEX ADD A ADD A ;TRACK BOUNDARY INDEX MOV B,A ;SAVE TO GET SECTOR LDA HSTSEC DCR A ;HOST BIOS ABOVE THINKS SECTORS START AT 1 ADD B ;SECTOR 256 BYTE INDEX TO RAM DISK BCOUT POP H POP D POP B ; POP PSW RET ; ; ; PMXIT: XTHL ;RESTORE HL, RET ADDR RET ;RET PAST MSG ; ; ;*************************************************************************** ;*************************************************************************** ; ; MICRO RESOURCES TPA RESIDENT RAM DRIVE I/O ROUTINES ; ;*************************************************************************** ;*************************************************************************** ; ; ;WRITE ONHST = HSTSEC? CMP M JZ MATCH ;SKIP IF MATCH ; ; ;PROPER DISK, BUT NOT CORRECT SECTOR ; NOMATCH: LDA HSTWRT ;HST WRITTEN? ORA A CNZ WRITEHST ;CLEAR HAST BUFF ; ; ;MAY HAVE TO FILL THE HOST BUFFER ; FILHST: LDA SEKDSK STA HSTDSK LHLD SEKTRK SHLD HSTTRK LDA SEKHST STA HSTSEC LDA RSFLAG ;NEED TO READ? ORA A CNZ READHST ;YES, IF 1 XRA A ;0 TO A REG. STA HSTWRT ;NO PENDING WRITE ; ; ;COPY DATA TO OR FROM BUFFER ; MATCH: LDA SEKSEC ;MASK BUFFER NUMBER ANI IALLY 128, DE IS SOURCE, HL IS DESTINATION ; RWMOVE: LDAX D ;SOURCE CHARACTER INX D MOV M,A ;TO DESTINATION INX H DCR C ;LOOP 128 TIMES JNZ RWMOVE ; ; ;DATA HAS BEEN MOVED TO/FROM HOST BUFFER ; LDA WRTYPE ;WRITE TYPE CPI WRDIR ;TO DIRECTORY? LDA ERFLAG ;IN CASE OF ERRORS RNZ ;NO FURTHER PROCESSING ; ; ;CLEAR HOST BUFFER FOR DIRECTORY WRITE ; ORA A ;ERRORS? RNZ ;SKIP IF SO XRA A ;0 TO A REG. STA HSTWRT ;BUFFER WRITTEN CALL WRITEHST LDA ERFLAG RET ; ; IN ERFLAG. ;RETURN ERFLAG NON-ZERO IF ERROR ; WRTSEC: CALL RIOPB ;SETUP RAM DISK IOPB ;..FROM BIOS VARIABLES CALL RWRITE ;GO WRITE RAM DISK SECTOR XRA A STA ERFLAG ;RESET ERROR FLAG RET ;RETURN FROM "WRITEHST", IF O.K. ; ; READHST: ;PERFORMS THE PHYSICAL READ FROM ;.. THE HOST DISK ; ;HSTDSK = HOST DISK NUMBER, HSTTRK = HOST TRACK NUMBER, ;HSTSEC = HOST SECT NUMBER. READ "HSTSIZ" BYTES ;INTO HSTBUF AND RETURN ERROR FLAG IN ERFLAG. ; READSEC: CALL RIOPB ;SET RAM DIS MOV D,A MVI E,00H LXI H,RAMBUF ;POINT TO RAM BUFFER FOR DISK DAD D ;(HL) IS RAM ADDRESS FOR MOVE SHLD RAMADDR RET ; ; ;INLINE PRINT OF MESSAGE TILL A ZERO ; PRTMSG: XTHL ;SAVE HL, GET MSG POINTER ; PRTMLP: MOV C,M ;GET CHARACTER INX H ;INCREMENT POINTER TO HEXT CHAR ;.. OR RETURN ADDRESS MOV A,C ;CHECK IF ZERO END ORA A JZ PMXIT ;EXIT IF ZERO ; CALL CTYPE ;OUTPUT IT JMP PRTMLP ;GO CHECK/DO NEXT CHAR ; CTYPE: ; PUSH PSW PUSH B PUSH D PUSH H CALL  256 BYTE RECORD FROM THE HSTBUF TO THE RAM DRIVE ; RWRITE: LHLD RAMADDR ;POINT AT THE RAM DRIVE ADDRESS XCHG ;TO (DE) AS "TO" ADDRESS LHLD XFRPNT ;GET (HL) AS "FROM" ADDRESS LXI B,SECSIZ ;PHYSICAL HOST SECTOR SIZE ; RWXFR: MOV A,M ;GET A DATA BYTE STAX D ;PUT AT DESTINATION INX H ;BUMP POINTERS INX D DCX B ;DECREMENT BUFFER SIZE COUNTER MOV A,B ORA C ;CHECK IF ALL MOVED YET JNZ RWXFR RET ;DONE WITH READ ALREADY ; ; ;READ ONE 256 BYTE RECORD FROM THE RAM DRIVE TO    THE HOST BUFFER ; RREAD: LHLD XFRPNT ;POINT AT THE HOST BUFFER AS XCHG ;..(DE) AS "TO" ADDRESS LHLD RAMADDR ;GET (HL) READ ADDRESS AS "FROM" ADDRESS LXI B,SECSIZ ;BYTES PER SECTOR COUNTER JMP RWXFR ;GO DO THE TRANSTER ; ; ;*************************************************************************** ; ; STORAGE AREA FOR VARIABLES BEGINS HERE.. ; ; ;RELOCATION POINTER STORAGE AREA ; CCP$ENT DS 2 ;STORE CCP RE-ENTRY POINTER HERE ;TABLE POINTER HERE ; ; ;RAM DISK DRIVE ACCESHOST SECTOR NUMBER SEKHST: DS 1 ;SEEK SHR SECSHF HSTACT: DS 1 ;HOST ACTIVE FLAG HSTWRT: DS 1 ;HOST WRITTEN FLAG UNACNT: DS 1 ;UNALLOCATED RECORD COUNT UNADSK: DS 1 ;LAST UNALLOCATED DISK UNATRK: DS 2 ;LAST UNALLOCATED TRACK UNASEC: DS 1 ;LAST UNALLOCATED SECTOR ERFLAG: DS 1 ;ERROR REPORTING RSFLAG: DS 1 ;READ SECTOR FLAG READOP: DS 1 ;1 IF READ OPERATION WRTYPE: DS 1 ;WRITE OPERATION TYPE DMAADR: DS 2 ;DISK DMA TRANSFER ADDRESS RAMSEL: DS 1 ;LOCAL DISK SEL A MEMORY RESIDENT FLOPPY DISK PROGRAM by Michail J. Karas This is from the Lifelines/The Software Magazine, September1982 issue, about ADD-ON MODULE Construction. An add-on module is designed for use under single user CP/M-80 2.2. The next several paragraphs, from the previous articles, January, and February 1982, show the procedure to get a version up any process the DISKDEF macros. An additional implementation requirement is the availability of the assembler output as a .REL file. The Digital Research Relocating Macro Assembler RMAC is just the tichet to generate the appropriate .REL file and process the DISKDEF.LIB macro includes. The command structure below shows how to assemble an ADD-ON MODULE program like the RAM disk demo listing on the disk as RAMDISK.ASM. The following is an example on the assembly. A>oduce the required .HEX file from PRLMOVE. A>MAC PRLMOVE $+S PZ The command structure below shows how to produce the .PRL file from the RMAC output. A>LINK RAMDISK[OP] where [OP] directs LINK to generate the desired .PRL file. The program PRLMOVE.HEX and the page relocatable RAMDISK.PRL must be combined into a single executable command file as follows: A>DDT DDT Vers. 2.2 -IRAMDISK.PRL -R <-Load of .PRL file to RAM to address S PARAMETER BLOCK ; RAMADDR: DS 2 ;RAM DRIVE POINTER ADDRESS XFRPNT: DS 2 ;READ/WRITE ROUTINE DATA BUFFER POINTER ; ; ;THE NEXT SEVERAL BYTES, BETWEEN STARTZ AND ;ENDZ, ARE SET TO ZERO AT MODULE INITIALIZATION ; STARTZ EQU $ ;START OF ZEROED AREA ; ; ;HOST DISK BLOCKING/DE-BLOCKING DATA AREA ; SEKDSK: DS 1 ;SEEK DISK NUMBER SEKTRK: DS 2 ;SEEK TRACK NUMBER SEKSEC: DS 1 ;SEEK SECTOR NUMBER HSTDSK: DS 1 ;HOST DISK NUMBER HSTTRK: DS 2 ;HOST TRACK NUMBER HSTSEC: DS 1 ;ECTED FLAG ; ENDZ EQU $ ;END OF ZEROED AREA ; ; ;HOST DATA BUFFER MEMORY AREA ; ; HSTBUF: DS HSTSIZ ;HOST BUFFER ; ; ; ; ;SCRATCH RAM AREA FOR BDOS USE ; ENDEF ;LET DISKDEF FIXUP BDOS BUFFERS ; END ; ; ;+++...END OF FILE  ;.. THE HOST DISK ; ;HSTDSK = HOST DISK NUMBER, HSTTRK = HOST TRACK NUMBER, ;HSTSEAD OPERATION WRTYPE: DS 1 ;WRITE OPERATION TYPE DMAADR: DS 2 ;DISK DMA TRANSFER ADDRESS RAMSEL: DS 1 ;LOCAL DISK SELd running. The source file, RAMDISK.ASM, being very similar to a BIOS for CP/M-80 2.2, requires the extension disk definitions to have disk parameter tables, check vector and allocation vectors. In addition, a directory buffer must be allocated. An ADD-ON MODULE generates the appropriate tables through the use of the macro library DISKDEF.LIB provided by Digital Research on the CP/M-80 2.2 distribution diskette. This macro capability requires a macro assembler to properlRMAC RAMDISK $+S PZ The resulting .REL file has to be converted to a page relocatable format. After agonizing over the problem of easily making a "BIT MAP", I found that the Digital Research Link program distributed with RMAC and PL/I-80 can generate page relocatable files (.PRL type) which are compatible with MP/M-80. After reviewing the LINK output format of a .PRL file, I designed the PRLMOVE program to relocate the LINK output files. The command structure below shows how to pr 0100H with code image starting at address 0200H. MEXT PC nnmm 0000 <-Convert nn to decimal and remember value. -IPRLMOVE.HEX -R <-Read PRLMOVE program in over the .PRL file at load address of 0100H. -G0 <-Exit DDT to CP/M-80. A>SAVE dd RAMDISK.COM <-Save dd pages of memory to get command     file. dd = converted nn from above! This results in the .COM command file necessary to make an executable module out of the ADD-ON MODULE. The present design of the ADD-ON MODULE with the negative offset pointer calculation reentry to CCP requires that the BDOS and CCP combination be genuine (REAL Digital Research CP/M-80 Ver 2.2 of total length 01600H bytes. If your system uses a modified BDOS or CP/M-80 system look-alike, then the negative offset to the stack pointer will requCAT.COM 2/2/80 $ !9"212]!4m!?J!] !_G6$\<•͊++UNABLE TO OPEN MAST.CAT$ *2͈)•͈͈ë>  Y >2 =ʐ!4?0?0!??0?0!~#:V<2V0:<2:06æ6͈ 6͈R#?͈.r,r r~?G> #g7~?} g> #r*W|=¿\ʼ͊++READ ERROR OR EARLY EOF$!~#"W> > _ w#6?#͊ $ file. dd = converted nn from above! This results in the .COM command file necessary to make an executable module out of the ADD-ON MODULE. The present design of the ADD-ON MODULE with the negative offset pointer calculation reentry to CCP requires that the BDOS and CCP combination be genuine (REAL Digital Research CP/M-80 Ver 2.2 of total length 01600H bytes. If your system uses a modified BDOS or CP/M-80 system look-alike, then the negative offset to the stack pointer will requCAT2.ASM 1/20/80 $ !9"1e͠!1#!/ A!?#!1? ͬ;!?1 ͡5sMAST CAT ]͡\<++NO MAST.CAT++$ʻ) ʻ ­++EARLY EOF++$!(͸#.,7w#6 #ɯ2M^ 3##:M~:M<2Mʻ l_P, 2M $~# x¡# x¬^#V#N#Fx#~G#~#fo>}ƀo|g+~+ire a different value. See NOT$PRES: in listing. Also, for non-genuine CP/M-80 systems, if the CCP is a different size (not 0800H) bytes, the program PRLMOVE will have to be modified to set down the relocation load address calculation by an amount equal to the difference in the alien CCP size. . If your system uses a modified BDOS or CP/M-80 system look-alike, then the negative offset to the stack pointer will requ!~#:V<2V0:<2:06æ6͈ 6͈R#MAST CAT NAME DISK NAME DISK $............ ............ FILES:ire a different value. See NOT$PRES: in listing. Also, for non-genuine CP/M-80 systems, if the CCP is a different size (not 0800H) bytes, the program PRLMOVE will have to be modified to set down the relocation load address calculation by an amount equal to the difference in the alien CCP size. . If your system uses a modified BDOS or CP/M-80 system look-alike, then the negative offset to the stack pointer will requw+++ø#~g}o|g~ +p+q *ɴ\ . .    (FMAP 6/12/80)!9"1:m2!]~ 3 6?#,\<2WK1++NOT FOUND$f:ÔFILENAME TYP RC -----GROUPS------$\<=!o* w#§w#³":<2È:!!!s#r# =:2=2:=22!!͒##:=2:!!":FM6U1FILES$ 0_"11MAST CATv;:0w  á*-*/}|ڊ!"/*-{z|*+ v*/"/H*/"-!"/*+*-}>*/#"/ɯ22*!"-"/ <  NO MASTIN FILE$NAMES SUBH USE FACTOR !/w "s**}|\!"*{zN*H*"*"!"**}>*#"ɯ22!""<ª  NO NAMES FILE$NEW CAT  NO Mw4N Y**}|I!"*{z;*OR IGNORE NAMES. MAY BE MISSING ) AFTER LAST NAME.$4 4JW:[:B!88ڝ E!,8ʋ8!Q/J!8JDEL: $!Q/!MADD: $8!Q/G! 6.# 6,v! ~ ) #:J .B BJw# 26 #B6#J>2!8d6,#dr6.#r:µ4 {,ʭ.ʭ ʭʵw#r426 #­6#µ2!~ >0 >  !9"y4K͞+@:I^'+FÎr*y*w#w#w^#V#*~#fo^#*~#fo^#V#*n^#*n^#V# ~#fo^#& ~#fo!+!#!+!#!+!+}|z{|}|z7||7zZZ)|/g}/o#|͉k|/g}/o#ɯ2qZZk:q|/g}/o#|/g}/o#:q<2qqDM!xxGyO҃)v|͔`i|)Öxڷz/W{/_ѯzW{_=yOxGæ2qZZ͉M|}ȯ|g}o)|/g}/o ~6#>    .* :FS*w#"|=Ut&++WRITE ERROR$!">.6> 6> 6^#V#N#F #ʛ>2N#F#^q#Vpr+s!NAMES SUB1FILES$##:=2:!!":FM6U1FILES$ 0_*" & DISK FULL: MASTOUT$!"**#"ɯ22!"!"<£  NO DIR SPACE: MASTOUT$MAST BAK CAT  !j8:-b:]-&:g ++SERIAL MUST BE 3 DIGITS$^!,/e!5/x++NO "-NAME.NNN" IN NAMES.SUB ++REISSUE: UCAT -name.nnn$ !,/(!5/4(!v4w#)4 xŒ++TOO MANY IGNORE NAMES FOR TABLE$++NO IGNORE NAMES IN MAST.CAT$++EOF READING F ~ _#> _> _w#/#8>*}S">G<‹ tË CANNOT CLOSE MASTOUT$ò w# £! ͞! ͞MAST.CAT HAS ENTRIES.$ > >   ~ _#> XXXXXXXX.YYY, . XXXXXXXX.YYY,XXXXXXXX.YYYXXXXXXXX.YYY,XXXXXXXX.YYY$$$ .SUB)#z/W{/_!9~#fo! ! ! ! ! ! !9~#A"s!`*"!"!Y">2>2>22!"!"!@"!" ʞ!F#x±~#±!b2r~# "2r+}|~#G:rx"2r+w# +6#!6#2w2x*s!>r<o&F=-/` r'~h6!+`W?_!~7z?` :>ª@w#G.¶ww#?*>?w#> w#.7:77   !a{   `OE!y6$ -7rBo&))T])))!y NN OOPQSTU@V1mai/ I,W!!H!a I,!H!ͭ,*L-!H.!H-*/Q}P !h ͤ+] !XL! ͤ+!9BD Software CRL-format ASM Preprocessor v1.46 Usage: casm .CSMCan't open %s .ASMCan't open %s TPALOC EQU %04xH File ends, but last function is unterminated END$CRL EQU $-TPALOC SECTORS$ EQU ($-TPALOC)/256+1 ;USE FOR "SAVE" !. END Fix those errors and try again... %s is ready to be assembled. !9DM*L![C/| *L! D *L~#fo 8@"LL"L*,Q#"*Qͪ  ! is supportedNo filename specified2/C:.LIBCan't open %s Missing include file!9DM!"]"]"]!"]![!R]0%![!&\0%R]"]*]n! s70| ! n};² *]"]*]n&4$| *]#"]ø *]#"]+6!]%*]n} *]n}; *]"]*]n&ͧ0|*]#"]*]n}-*]#"]+6!]%*]n}H*]n};K*]!R]!&\"]!"]*]|*]n! ś$|­! n}ʝ! n};£ê*]#"]r*]+n&4$|*]#"] *]#"]+)]*]s#r*]n&4$|*]#"]*]n} I,!H!~I,!H!I,*.Q}9!ͤ+!͟&*]|I!͟&*]j0#&"]*(Q#"(Q+)`P*]s#r*]*]ͺ**]!ͤ+>2.QS"[!"S!"Q>2]*]!=!H,*]!U!H,(!j*]͙$|!r*]͙$|ʋ*.Q}!~͟&*]} Ͷ*]!!H,ͬ ! w#w͐*S҃͐kQ##n}u*]͐kQ~#fo!ͤ+>2/Q! ^#Vr+s*>2.Q(!*]͙$|-!*]͙$|-!*]͙$|-!*]͙$|-!*]͙$|-!*]͙$|-!*]![I,(*]|)!H![I,(*]|*.Q}! w#w͐*]͐)]~#foͣ'|j ͐)]~#fo ("G^|ʣ*]*G^*]!!\0f͐)]~#fo*]!!\0! w#w͐*S͐kQ~#fo͐)]~#fo͙$| f! ^#Vr+s͐kQ*[s#r͐kQ##6͐)]~#fo*[ͺ**[6'*S#"S͐)]~#foj0͐)]~#fo!R]!\![r%!*]͙$|*]*]#"]+*]!!H,*]|!j& *]*]#"]+*]!!8put9initeq:exi;strcp<strca=fope>print?fcrea@fprintAget_linBprocessCaborDfputEputdiFputGfclosHfflusIget_linKfgetLfabor!9DM!f ͎*͓#!"(Q>2.Q>2/Q͐ ++|! ͎*8`iw#w! ~#fo##~#fo͐n! s{(! n}.(͐L! ns`i^#Vr+s͐L6!L!XLͺ*! !L+@"LL"L*L*Ld+#|*L! ͤ+8! !XL+!H!XL+#|±!XL! ͤ+8!! !H,!"*Qͪ |W**Q#"*Q*.Q}! ͟&!H! I,!H! S ! *]͙$|) ! *]͙$| *L! D? ! ͟&*]|O ! ͟& D"L**Q",Q!"*Q`iw#w!]~#fo͐n&70| `i^#Vr+sh !]~#fo͐6>2:L*]n}< !$ !:Lͺ*!]~#fo##n}: !' !:L+*]#!:L+!:Lj0+`is#r:Ln}> ͐:L6[ *]n}"N *]#!:Lͺ*!:Lj0+`is#r:Ln}"K ͐:L6[ *]!:Lͺ**L!:Ld+#|º !:Lj0+:Ln}.ʥ !* !:L+*L!:Ld+#|ʥ ú !:L!/ ͤ+!> ͟&:L"Lͪ ! !9INCLUDEMACLIBOnly one level of inclusion*]#"]+6f!j&!9Too many operands in this instruction for me to handle !9DM*]|ʋ!1*]͙$|!5*]͙$|*.Q}&!9*]͙$|!<*]͙$|!?*]͙$|&!H![I,*]j0#&`is#r*]͐ͺ**^P#"^P+)vL͐s#r*^P |#!B͟&(!|*]͙$|*.Q}H!͟&*]}X!j&! w#w͐*]Ҽ*Q#"Q+)0Q*[s#r͐)]~#fo*[ͺ*͐)]~#fo6'! ^#Vr+s`*Q|*]!ͤ+!#͟&(!P*]͙$|*(Q|!!H!Y$|-!*]͙$|-! *]͙$|5!'j&!S*]͙$|J(*.Q}b*]|r*]|r!H![I,(*]}}Ͷ*]|*]*]*]!W!H,! w#w͐[n}͐[n&70|͐[n}:͐[6 ! ^#Vr+sé͐[n}:͐[6 ! w#w͐*Sү͐kQ~#fo*]͙$|ʡ͐kQ##n}ʌ!oj&*]͐kQ~#fo!ͤ+Þ͐kQ##6! ^#Vr+s͐kQ*[s#r͐kQ##6*]*[ͺ**]6'*S#"S*]| !HH,! ^#Vr+sA!H![I,!9EQUSETDSDBDWToo many EQU lines...increase 'EQUMAX' and recompile CASMEXTERNAL'External's for a function must appear inside the functionExternals must all be together at start of function Too many external functions in function "%s" Change the NFMAX constant and recompile CASMFUNCTION ; dummy external data information: ORG TPALOC+200H DB 0,0,0,0,0 'Function' op encountered in a function. Did you forget an 'endfunc' op?A name is required fo   r the 'function' opProcessing the %s function... ; The "%s" function: %s$BEG EQU $-TPALOC ENDFUNCENDFUNCTION'Endfunc' op encountered while not in a function%s$END EQU $ The label %s in function %s is undefined RELOCDWRELDIRECTENDDIREXRELEXDWRELPRELUDEPOSTLUDEDEFINEOld macro leftover from "CMAC.LIB" days... END%s$L$%s EQU $-%s$STRT Re-defined label:%s, in function %s %s$EF$%s-%s$STRT%s$L$%sDW%s$R%03d EQU $-%s$STRT Only one relocatable value allowed per DW %s$R%03d EQU!!͙͐$|!!͙͐$|7!!͙͐$|O!!MOVINRDCRINXDCXDADMVIDBDSCPIORIANIADISUISBIXRIACIORGTITLEPAGEIFEJECTMACRO!9DM>2]!"]!H!I,`iw#w͐*Q!!\ͺ*͐)0Q~#foj0! s#r͐|ͩ)͐,!! s#r! w#w͐͐+Ҁ͐\͐)0Q~#fo͐ns! ^#Vr+s<͐\6͐)0Q~#fo͐n&!\!!H,`i^#Vr+s!H!I,!H! I,*]! !H,!H!* I,*`i^#Vr+s !H!U!I,!9 ; Relocation parameters: DW %d DW %s$R%03d !9DM! w#w!H!"I,`iw#w͐*(QҖ"!"!\ͺ*͐)`P~#foj0! s#r͐|ͩ!͐!!! s#r! w#w͐͐+"͐\͐)`P~#fo͐ns! ^#Vr+s!͐\6͐)`P~#fo͐n&!\!#!H,͐)`P~#fo!#!H,! ~#fo͐##s#r`i^#Vr+sz!!H!!#I,! ~#fo###s#r͐|"!8#ͤ+!c#ͤ+!8!9 ORG TPALOC ; Directory: !9DM͐~#fon&70|.%͐^#Vr+s %!9DM͐n}j%! ^#Vr+s! ^#Vr+sn& 1s8%͐6!9DM͐j0`is#r͐j0! s#r͐͐! s#r͐͐͐! s#r͐|&͐͐͐#͐͐͐8! w#w͐! s#r͐͐a&! ~#fo͐! ~#fo͐ns! ^#Vr+s! ^#Vr+s&! 9!9DM͐**Q*L!&ͤ+>2/Q %s: %d: %s !9DM͐j&! j8*L! D&! D-!@-!8!9DM͙͐8`is#rz'!'͐! s#r͐n&0|?)͐ ͐͐!9)!9~#fo*!! 8! s#r͐R1! s#r! ^#Vr+sn&0|ʁ)e)͐n}/™)͐|ڻ)͐ ͐͐!)!9~#fo*͐! 8͐ ͐͐#!)!9~#fo`is#r͐! 8͐*!97,2q*&:q):I*=I*=r:qo&7*Ϳ(\!*ͅ( !\&!!9DM͐n}ʸ*! ^#Vr+sn&j8Ö*!9DM͐`is#r! ^#Vr+s! ^#Vr+sns{**͐*!9 $+1-%s$STRT !9DM!V͙͐$|.!!Z͙͐$|F!!^͙͐$|^!!b͙͐$|v!!f͙͐$|ʎ!!j͙͐$|ʦ!!n͙͐$|ʾ!!r͙͐$|!!u͙͐$|!! ~#fo##n}I¿!x͙͐$|!!|͙͐$|/!!͙͐$|G!!͙͐$|_!!͙͐$|w!!͙͐$|ʏ!!͙͐$|ʧ!!͙͐$|ʿ!!͙͐$|!!͙͐$|!!͙͐$|]!4 !H,*Q|P*]*]#"]+*]!C !H,*]*]!] !H,*]*]*]!u !H,`iw#w͐*QҮ͐)0Q~#fo*]! !H,`i^#Vr+sr*]! !H,!9 ; List of needed functions: DB '%s','%c'+80H DB 0 ; Length of body: DW %s$END-$-2 ; Body: %s$STRT EQU $ %s$R%03d EQU $+1-%s$STRT JMP %s$STRTC-%s$STRT %s$EF$%s EQU %s$STRT %s$EF$%s JMP 0 %s$STRTC EQU $ !9DM!H!"!I,*]!=!!H,`iw#w͐*] !͐*]!F!!H, DB '%s','%c'+80H DW %s$BEG DB 80H DW END$CRL CRL Directory size will exceed 512 bytes; Break the file up into smaller chunks, please! !$"vL!$"xL!$"zL!$"|L! $"~L! $"L!$"L!$"L!$"L!$"L!$"L!$"L! $"L!$$"L!($"L!,$"L!0$"L!"^PABCDEHLMSPPSWANDORMODNOTXORSHLSHR!9DM! n&ͧ0|ͣ}$! n}$͝}$! n&0|ͣ}$! n}.͝!9DM! n&ͧ0!9DM͐n͐n}ʷ$!͐n}$! ^#Vr+sn! ^#Vr+sn}$!÷$͐n}$!$!͟&͐ '!9Out of storage allocation space !9DM*[͐j0#"[*[![g'!i'͟&Out of text space. Increase TXTBUFSIZE and recompile CASM!9DM͐'|ʾ'!!!9DM`iw#w͐*^P(͐)vL~#fo͙͐$|(!(`i^#Vr+s'!(!9!9DM`iw#w͐*Qv(͐)0Q~#fo͙͐$|j(͐)0Q~#fo|(`i^#Vr+s.(!|(!9!9DM͐͐! *(!9DM͐!Q*(!9DM͐!y*(!9DM͐n&70|)! ^#Vr+s(!9DM͐`is#r͐n},+! ^#Vr+s+! ^#Vr+s͐ns! ^#Vr+sn},+͐[+!9!9DM͐!͐ͅ(s#rz+!͐##w#w͐~#fo!y9DM! `i 2`i͎*!9!9DM͐͐ͥ(s#rz+!͐͐s#r͐##6#6͐~#fo!y9DM! `i 2͐`iI,@,!9!9DM! ^#Vr+sn`is{ʞ,`in} ,͐! ͭ,͐`in&ͭ,#|›,!ä,Q,!ä,!9!9DM͐X-͐>,>,>,>->,>->,>--X-! n&   j8! n&!8! n&!8! n} E-! !8! n&!8͐##^#Vr+s|·-!͐͐~#fo8ʖ-!͐##6#6͐͐s#r͐^#Vr+s! ns&!9DM͐-!͐~#foC9!9DM͐.!:/͐##~#fo6.!:/͐##~#fo`is#r͐͐͐~#fo8͐ʃ.!:/͐+?`is#r͐##~#fo|/!͐͐͐8͐##~#fo͐s#r͐~#fo͐s#r!!0ͯ1! n&9ͯ!9DM! n&6|G1! n&L1! n&!9DM`iw#w! 6#6͐ n! s{ ʅ1! n} “1! ^#Vr+si1! n}-²1! 6#6! ^#Vr+s! ^#Vr+sn! s0|1͐ ?! nѯg`is#rò1͐͐?2!9!h9DM! ^#Vr+s~#fo! s#r͐! s#r! ^#Vr+sn`is{]5`in}%G5! ! s#r! 6#6! s! s! s͐n}-œ2! ^#Vr+s! 4͐n}0¬2! 4͐n&0}2! ͪ72!! s#r! ^#Vr+sn`is{.3! ͪ7! s#r! n}.5! ^#Vr+s!.5! ^#Vr+s6 5D5! ^#Vr+s`insZ5! ^#Vr+s`ins;2͐6!9!9DM͐|ƒ5ͫ9/6͐+++|š5!8/6͐##^#Vr+s|6!͐͐~#fo9`is#r!5͐##^#Vr+s/6͐##͐?+s#r͐͐s#r͐^#Vr+sn&/6!9!9DM͐|W6! n&V:͐w6͐##~#fo|6!͐^#Vr+s! ns͐##^#Vr+s!!9DM! n&Aͯ6! n&Zͯ!9DM! n&aͯ7! n&z*|*uA9*~#9"*s*uA9#"u*+"9#7:,*e::*h9}|2q ʙ99:qwʊ9! {w:woʺ92w&!o 9 . &7:)~:,"s!"u*|6:**s;:! ~6:6*u*+"*"*u#"u::wo2w& , FNxg>Goy:$Ʌȅ҅܅慨&n7U^ #sLx n}.5! ^#Vr+s!.5! ^#Vr+s6 5D5! ^#Vr+s`insZ5! ^#Vr+s`ins;2͐6!9!9DM͐|ƒ5ͫ9/6͐+++|š5!8/6͐##^#Vr+s|6!͐͐~#fo9`is#r!5͐##^#Vr+s/6͐##͐?+s#r͐͐s#r͐^#Vr+sn&/6!9!9DM͐|W6! n&V:͐w6͐##~#fo|6!͐^#Vr+s! ns͐##^#Vr+s!!9DM! n&Aͯ6! n&Zͯ!9DM! n&aͯ7! n&z͐~#foF9:/͐##6#6͐͐s#r!:/!9!9DM`i6#6͐ ! s#r͐ l5! s#r!ʂ/͐#|ˆ/!.0! ^#Vr+s͐s{ /͐͐ #/͐++n} /! ^#Vr+s6 0`i^#Vr+sz0͐ l5! s#rz0͐ˆ/͐!0͐ ͐86͐6͐ .0!9!9DM! n} ͝f0! n} ͝f0! n} ͝!9DM`iw#w! ^#Vr+sn}ʗ0`i^#Vr+sx0͐Þ0!9!9DM! n&ͨ6|ͣ0! n&6|ͣ!9DM! ͐ 2!9DM! n& 4! ^#Vr+sn`is`in& 1}D@3U|3Xʅ3Oʎ3C3S415͐~#fo||3! ^#Vr+s6-͐͐~#fos#r! ^#Vr+s! 6 Ô3! 6Ô3! 6! ~#fo! n&! ^#Vr+s~#fo! 7ѯgs#r}4! ^#Vr+s! ^#Vr+s~#fos! ^#Vr+s}4! n}4! 6#6! ^#Vr+s~#fo! s#r͐n}}4͐|}4! ^#Vr+s! ^#Vr+sns! ^#Vr+s! ^#Vr+s34͐6! ! s#r! n}4! ^#Vr+s!4! ^#Vr+s! n}4!04! sÙ4͐! ^#Vr+sns{4! ^#Vr+s4!!9DM͐͐ V7͐^#Vr+s͐ C7͐0K7͐7s!&á7͐ ͐͐ ͉͐7`is͐ ͐͐ )͐7`in&#&á7!9!9DM`iw#w͐~#fon&0}7͐ ?͐^#Vr+snѯg`is#rø7͐7!9  )6!7*|DM**d8H8><<8~# x<8 > _ 8 *ڿ8+*|/g}/o#98ҿ8#"z{7:O*7:)~:,"s!"u 4! ^#Vr+sn`is`in& 1}D@3U|3Xʅ3Oʎ3C3S415͐~#fo||3! ^#Vr+s6-͐͐~#fos#r! ^#Vr+s! 6 Ô3! 6Ô3! 6! ~#fo! n&! ^#Vr+s~#fo! 7ѯgs#r}4! ^#Vr+s! ^#Vr+s~#fos! ^#Vr+s}4! n}4! 6#6! ^#Vr+s~#fo! s#r͐n}}4͐|}4! ^#Vr+s! ^#Vr+sns! ^#Vr+s! ^#Vr+s34͐6! ! s#r! n}4! ^#Vr+s!4! ^#Vr+s! n}4!04! sÙ4͐! ^#Vr+sns{4! ^#Vr+s4!!9DM͐͐ V7͐^#Vr+s͐ C7͐0K7͐7s!&á7͐ ͐͐ ͉͐7`is͐ ͐͐ )͐7`in&#&á7!9!9DM`iw#w͐~#fon&0}7͐ ?͐^#Vr+snѯg`is#rø7͐7!9  )6!7*|DM**d8H8><<8~# x<8 > _ 8 *ڿ8+*|/g}/o#98ҿ8#"z{7:O*7:)~:,"s!"u   *|*uA9*~#9"*s*uA9#"u*+"9#7:,*e::*h9}|2q ʙ99:qwʊ9! {w:woʺ92w&!o 9 . &7:)~:,"s!"u*|6:**s;:! ~6:6*u*+"*"*u#"u::wo2w& , FNxg>Goy:$Ʌȅ҅܅慨&n7U^ #sLx Hit SPACEName Ext Bytes UN At ! File(s), occupying K of K total capacity directory entries and K bytes remain on 1 !9" ! J> # ->! . *ͪe> # < * v K  K  K !B r+s+p+qA ?  p*A *? :]$Ž l]Q !]6 !E 6!C 6 :C *C &l ~2D U¼:E 2 :D S:E 2:D F:E 2:D V:E 2:D P:E 2 :D N2E !M "I *K  )*= ^#V"O I G  *G )*= N#F*O ? J*G #"G (*I )*= ^#V*O DM? m*I +"I JI G  *G )*= ^#V"Q *I )*= *G )*= N#Fq#p*I )*= *Q s#r*G #"G *I +"I K I  G M   !M G  :S <2S O!T *G s#r*S &l ) *M s#r*I "M ^I K  X:S <2S O!T *K s#r*S &l ) *I s#r*G "K û!" "    #* #" )*= * #" )*= N#Fq#p   * )*= * ) *= ^#VN#F? H * #" )*= ^#V";  *; ^#V" * )*= *( * " 3*1 #" " " *5 " > # R : B * +" ! +s#r( ! 6: " * ~2 * #" * +" > ʶ : 2 Ғ * +" : <2 O>ҳ ! 6* #" * ~2 p K* DMf = * *% DMf = * *% DMf = *( #"( K*# DMf = * *% DMf = : AOK :K . g S -A >>!  ~?l W >#^ : /!:' —  ʑ #‹  W ʢ #™ i`N#FogDM!>))덑o|g =¼ DM!>)) = ^#V) ^#V|g}o C 4Ø:!4:!5(  ! I3= : [= t:\a:\=_: :] t ?]\ : ҃! 6?Î : 2   ]Q  ?\\ : DM, Q ! "= *3 ##)*= "; */ &# "! *3 #"#  !! "% >!1 . 2' \: 2 : ʩ: ƀo&"* ~ʛ*# +"# ** DMY қ** DM  *; q#p* " . ** #DM*; -e**  *; w* #" )*= *; s#r*; "; : 2 !S 6!"V * "n >!S d*S &T ) ^#V"K O!l ^#V"M :S =2S M K  a*K "G *^#V"; *;  ͪ  *; q#pÝn* " ! p+q* )*= ^#V"; ! 6> ! i* &*; >OK : <2 E:/ *; ^#V*% DMf KK : *; Nf E*; ~ڻWK þE *; ~SK E = ! 6:! '= :/ = : = !: = : <2 * " !" >! .  * *&͵ "( * *&͵ > j*( #"( *DM*( V"( !" (   K!" }2 : <2 O:* * * "    >! = * DM** +" *( * " Ø* #" *& _{ozgO{ozgi`N#Fogo&og_{_z#W OK = Y -S {-_ ! s+p+q*  ͼ 2 <2 : ! ڗ  K ! 4Á ! 6: =! ڻ * & NK ! 4œ >3  03} Z; { ) #                 !   !   "   "   #   #   $   $   %   %   &   &   '   '