;PUTUSR.ASM v1.00 as of 12-15-83 ;Written by S. Kluger and placed into the public domain. ;Please see PUTUSR.DOC for description ; dcomof equ 16*3 ;offset to BIOS DCOM routine bios equ 1 ;BIOS vector location bdos equ 5 ;BDOS entry point usero equ 700h ;user offset from BIOS dbuf equ 80h ;default buffer conin equ 1 ;BDOS console in print equ 9 ;BDOS print string fopen equ 15 ;BDOS open file fread equ 20 ;BDOS read sequential stdma equ 26 ;BDOS set DMA ; cr equ 0dh lf equ 0ah ; org 100h ; ; Program entry point. Set up local stack. ; start: lxi sp,stack call banner ;say who we are call ckcpm ;check CP/M, ret only if ok call getidr ;ask for input drive call loadhx ;load hex file call xlhex ;translate HEX to binary next: call savusr ;write user to disk jz next ;yes, more rst 0 ;fast way out ; ; BANNER routine. Announce our presence. ; banner: lxi d,baner string: mvi c,print jmp bdos ; ; CKCPM routine. Set up pointers and check for N* CP/M ; ckcpm: lhld bdos+1 ;get BDOS pointer mvi l,0 ;point to OEM code mov a,m ;get first byte cpi 0e3h jnz barfc ;complain if not N* inx h mov a,m cpi 16h jz cpmok ;continue if ok barfc: lxi d,mbarfc call string rst 0 ;warm boot ; cpmok: lhld bios ;get BIOS vector lxi d,dcomof ;DCOM vector offset dad d ;DCOM addr now in HL shld dcom+1 ;set address mov a,m ;let's see if the... cpi 0c3h ;...BIOS is still ok jnz barfc ;no, complain ret ; ; GETIDR routine - get input drive letter A..P ; getidr: lxi d,mindr ;display prompt call getdr ;get A..P ani 0fh ;make 1..16 sta fcb ;save drive in FCB ret ; ; LOADHX routine. Does the following: ; 1. open USER.HEX ; 2. load file into RAM, translate to binary ; loadhx: call ack ;acknowledge lxi d,fcb ;let's open the file push d ;save fcb mvi c,fopen call bdos inr a jz nofile ;complain of error lxi h,hbuf ;set dma buffer shld hptr ;save buffer ptr xchg mvi c,stdma call bdos pop d ;get fcb push d mvi c,fread call bdos ;read a sector ora a jnz inerr ;initial read error lloop: lxi d,80h ;increment hex buffer lhld hptr dad d shld hptr xchg mvi c,stdma call bdos pop d ;get fcb push d ;save it mvi c,fread call bdos ;read next ora a ;if no error... jz lloop ;...then decode and load next pop d ;clean up stack ret ;else done (hopefully) ; ; XLHEX - translate ASCII chars into binary ; xlhex: lxi h,buffer ;hl=binary buffer push h ;save it lxi b,200h ;512 bytes to zero zerbuf: mvi m,0 inx h dcx b mov a,b ora c jnz zerbuf xchg pop h newln: ldax d ;get next byte cpi ':' ;separator? inx d ;point ot next jnz newln ;loop until : found push d lxi d,hbuf mov a,h cmp d jnc toobig pop d mvi c,0 ;zero checksum call get2 ;get 2 nybbles ora a ;if zero rz ;then done. mov b,a ;save count push h ;save buffer mvi h,3 ;6 bytes to skip adsk: call get2 ;get byte dcr h jnz adsk pop h ;now we get serious... code: call get2 ;get next mov m,a inx h dcr b jnz code call get2 ;get checksum mov a,c ora a jz newln ;loop if ok lxi d,mcksm ;checksum error call string rst 0 ; ; SAVUSR routine - save user to disk and ; ask for more saves. ; savusr: lxi d,modrv ;display prompt call getdr ;get A..P ani 0fh ori 80h ;specify double density push psw call ack pop psw ; ; The following is register preparation for the DCOM ; routine. I call it DCOM because it is very similar to ; the N* DOS DCOM routine. the parameters are: ; B=track C=density/drive ; D=sector E=command ; A=# of sect HL=buffer addr ; For more info, read the comments in DIRDUMP.ASM ; mov c,a ;place drive/density in C mvi a,1 ;1 (one) N* sector mvi e,0 ;write command mvi d,8 ;sector mvi b,0 ;track lxi h,buffer ;binary code buffer dcom: call 0 ;filled at startup lxi d,mfcom ;say finished call string mvi c,conin ;get response call bdos ani 5fh ;make caps cpi 'Y' ret ; ; UTILITY SUBROUTINES ; ; GETDR - get drive letter in A, complain if invalid. ; getdr: call string agn: mvi c,conin call bdos ;get response character ani 5fh ;make caps cpi 'A' jc invdr ;invalid drive cpi 'P' rc ;return if ok invdr: lxi d,minvdr call string jmp agn ; ; GET2 - get 2 nybbles into A ; DE=pointer, save all reg ; ret with DE advanced and cksum updated ; get2: push b ;save checksum & count ldax d ;get hi nybble cpi 'A' jc nhx1 sui 7 nhx1: ani 0fh ral ral ral ral mov b,a inx d ldax d cpi 'A' jc nhx2 sui 7 nhx2: ani 0fh ora b inx d pop b push psw add c mov c,a pop psw ret ; ; ACK routine - wait for RETURN ; ack: lxi d,mack call string ackl: mvi c,conin call bdos cpi cr jnz ackl ret ; ; NOFILE - file not found ; nofile: lxi d,mnofil call string rst 0 ; ; INERR - empty file maybe? ; inerr: lxi d,minerr call string rst 0 ; ; TOOBIG - USER area is over 512 bytes ; toobig: lxi d,mbig call string rst 0 ; ; MESSAGES FOLLOW ; baner: db cr,lf db 'PUTUSR v1.00 by S. Kluger',cr,lf db 'Any response of CONTROL-C aborts.',cr,lf,lf,'$' ; mbarfc: db cr,lf,7 db 'ERROR - CP/M cannot be identified as ' db 'North Star CP/M - ABORTING',cr,lf,lf,'$' ; mindr: db cr,lf db 'Please enter drive letter of the drive containing',cr,lf db 'the file USER.HEX (A..P) :$' ; modrv: db cr,lf db 'USER file in RAM now, please enter drive letter',cr,lf db 'of the output drive (A..P):$' ; mfcom: db cr,lf,lf db 'SAVE COMPLETED.',cr,lf db 'Do you wish to save USER to another disk (Y/N) ? $' ; minvdr: db cr,lf,lf,7 db 'Invalid drive. Drive letter must be A..P.',cr,lf db 'Please try again (A..P) :$' ; mnofil: db cr,lf,lf,7 db 'ERROR - file USER.HEX not found on disk!',cr,lf,lf,'$' ; minerr: db cr,lf,lf,7 db 'ERROR while reading USER.HEX - file empty?',cr,lf,lf,'$' ; mcksm: db cr,lf,lf,7 db 'CHECKSUM error in USER.HEX',cr,lf,lf,'$' ; mbig: db cr,lf,lf,7 db 'ERROR - USER area > 512 bytes!',cr,lf,lf,'$' ; mack: db cr,lf db 'MOUNT DISK AND PRESS RETURN WHEN READY$' ; hptr: dw 0 ; fcb: db 0,'USER HEX',0,0,0,0,0,0,0,0,0 db 0,0,0,0,0,0,0,0,0,0,0,0,0 ; ds 48 ;some stack space stack equ $ buffer equ $ hbuf equ $+512 end