.Z80 ;*************************************************************** ;File: IDEGEN.MAC ;Purp: Utility to write OS image to hard disk on Davidge DSB ; 4/6 machines with RehDesign GIDE interface ;Auth: John D. Baker ; ; Revision History: ; ; 26 January 1996 (JDB) ; Completed additions to read system image from reserved ; tracks of IDE hard disk. ; ; 24 January 1996 (JDB) ; Completed functions to read in a system image from file ; and select which "disk" is to have image written to it. ; ; 19 January 1996 (JDB) ; Created. ; Definition of used I/O addresses: GIDE equ 20h ; base address of GIDE board IdeDOR equ GIDE+6 ; Digital Output Register IdeDat equ GIDE+8 ; Data Register IdeErr equ GIDE+9 ; Error Register IdeWrPc equ IdeErr ; Write Precomp REgister IdeSCnt equ GIDE+0Ah ; Sector Count IdeSNum equ GIDE+0Bh ; Sector Number IdeCLo equ GIDE+0Ch ; Cylinder Low IdeCHi equ GIDE+0Dh ; Cylinder High IdeSDH equ GIDE+0Eh ; Drive and Head IdeCmd equ GIDE+0Fh ; Command IdeStat equ IdeCmd ; Status ; Commands for IDE hard disk drives: CmdRd equ 20h ; Read Sector CmdWr equ 30h ; Write Sector ; CP/M equates: bdos equ 5 ;call here... fcb0 equ 5ch ;first file control block fcb1 equ fcb0+10h ;second file control block currec equ fcb0+20h ;current record r0 equ currec+1 ;random 0 r1 equ r0+1 ;random 1 r2 equ r1+1 ;random 2 tbuff equ 80h ;default dma/command tail buffer ;CP/M functions: boot equ 0 ;total system reset (warm boot) conin equ 1 ;console input conout equ 2 ;console output prntstr equ 9 ;CP/M print string constat equ 11 ;console status openf equ 15 ;open file closef equ 16 ;close file srchf equ 17 ;search for first srchn equ 18 ;search for next rdseq equ 20 ;read sequential setdma equ 26 ;set dma buffer ; host disk params: hstsiz equ 512 ;bytes per host sector offset equ 2 ;number of reserved tracks stktop equ 0780h ;this is as large as we can be hstbuf equ stktop ;if we want to allow a 512-byte boot sector aseg org 0100h ld sp,stktop ;can't get bigger than this ; ld hl,hstbuf ;start host buffer here ld (adrhst),hl ;set it up ld hl,0000 ld (hsttrk),hl ;cylinder 0 ld a,1 ld (hstsec),a ;sector 1 xor a ;0 in A cnthds: ld (hstdsk),a ;start at head 0 call ReadHst ;read a sector jr nz,cnterr ;jrif an error ld a,(hstdsk) ;get head inc a ;bump to next jr cnthds ;and go to next ; cnterr: ;actually, we don't care about error type ld a,(hstdsk) ;get disk number dec a ;normalize to 0 cp 0ah ;bigger than 9? jr c,cnter1 ;skip if <=9 add a,7 ;bump to letters cnter1: add a,'0' ;make ASCII ld (srcmxh),a ;store in source message ld (dstmxh),a ;and in destination message ; ; ld de,signon ;point at message ld c,prntstr ;print it call bdos ; ld a,(tbuff) ;check for command tail or a ;set flags jr z,plain ;jump if no system file specified ; ld de,fcb0 ;point at first fcb ld c,openf ;open the file call bdos ;do it inc a ;check return code jr nz,openok ;jump if file found ; ld de,nofilmsg ;point at message ld c,prntstr call bdos ;print ld hl,tbuff ;point at buffer ld a,(hl) ;get byte count inc hl ;bump past space add a,l ;point to end inc hl ;to first char ld e,l ld d,h ;pointer in DE ld l,a ;point at end ld (hl),'$' ;mark end ld c,prntstr call bdos ;print file name jr plain ; and jump to standard ; openok: ld a,0dh ;start at record 13 ld (currec),a ;put it there ld de,hstbuf ;start reading here readlp: ld hl,80h ;sector size add hl,de ;make next transfer push hl ;save on stack ld c,setdma call bdos ;and tell bdos about it ld de,fcb0 ;get FCB again ld c,rdseq ;read a sector call bdos ;do it! pop de ;get next dma address back or a ;set flags jr z,readlp ;jump if more sectors ; plain: ld de,srcprmt ld c,prntstr call bdos ;print source disk prompt ; call getkey ;get keypress jr z,havsys ;jump if OS image already in memory call asc2bin ;convert to binary jr c,plain ;jump if bad selection ld b,a ;save in B ld a,(srcmxh) ;get max head number call asc2bin ;make binary cp b ;check range jr c,plain ;jump if head out of range ; ld a,b ;head in range, put in A ; call ReadSys ;read the OS from system tracks ;and fall through to write operation ; havsys: ld de,dstprmt ld c,prntstr call bdos ;print destination disk prompt ; call getkey jp z,exit ;jump if carriage return call asc2bin ;convert to binary jr c,havsys ;jump if bad selection ld b,a ;save in B ld a,(dstmxh) ;get max head number call asc2bin ;make binary cp b ;check range jr c,havsys ;jump if head out of range ; ld a,b ;get selected head back call WrtSys ;write the OS jr havsys ;and go again. ; ReadSys: call RdWrInit ;set up data areas RdLoop: call ReadHst ;read a sector call nz,RdWrErr ;handle error call bumpsec ;call if no error jr nz,RdLoop ;jump if more sectors ret ;and go back ; WrtSys: call RdWrInit ;set up data areas wrloop: call WriteHst ;write a sector call nz,RdWrErr ;handle error call bumpsec ;call if no error jr nz,wrloop ;jump if more sectors ret ;return if finished ;*************************************************************** ;Function: bumpsec ;Purpose: increment host sector number, decrement sector count ;Entry: data areas set up ;Exit: host sector number incremented, sector count decremented ;Uses: HL bumpsec: ld (adrhst),hl ;save new transfer address ex de,hl ;save in DE in case of error ld hl,hstsec ;point at host sector inc (hl) ;bump to next host sector inc hl ;bump to sector count dec (hl) ;--sctrcnt ret ;and go back ;*************************************************************** ;Function: RdWrErr ;Purpose: Handle errors on read or write ;Entry: Error reading or writing IDE sector ;Exit: if was a NOT FOUND error, host sector number reset, ; host track incremented ; otherwise, error message displayed and operation ; aborted ;Uses: All RdWrErr: call chknf ;check if was sector ID not found jr z,nxpct ;jrif not end of track ; ld hl,hstsec ;point at hstsec ld (hl),0ffh ;-1 in host sector (sort of) inc hl ;bump to sector count inc (hl) ;back up the sector count ld hl,(hsttrk) ;get current track inc hl ;bump to next ld (hsttrk),hl ;and put it back ld c,l ld b,h ;current track in BC ld hl,(maxtrk) ;get last track to write or a ;clear carry sbc hl,bc ;subtract jr c,sysfull ;jump out if system tracks full ex de,hl ;else get old transfer address back ret ;and go back ;*************************************************************** ;Function: sysfull ;Purpose: print message if OS image longer than system tracks ;Entry: jump from RdWrErr if next track is past system tracks ;Exit: top of stack discarded, error message printed, control ; returned to instruction following the call to ReadSys ; or WrtSys. ;Uses: All sysfull: pop de ;throw away previous return address ld de,fullmsg ;point at message ld c,prntstr call bdos ld hl,sctrcnt ;get count of remaining sectors ld h,0 ;0 in H ld b,9 ttpolp: add hl,hl ;*2^B djnz ttpolp ;loop to make byte count call prword ;say how many bytes remain ret ;and go back ;*************************************************************** ;Function: nxpct ;Purpose: print message if Read/Write error was other than IDNF ;Entry: jump from RdWrErr if error was other than ID NOT FOUND ;Exit: top of stack discarded, error message printed, control ; returned to instruction following the call to ReadSys ; or WrtSys. ;Uses: All nxpct: pop de ;throw away old return address ld de,nxpctmsg ;point at message ld c,prntstr ;function in C push af ;save error register call bdos ;do it pop af ;get error register back call prbyte ;print it ret ;and go back ; exit: ld c,boot ;get out! jp bdos ;like right now! ;*************************************************************** RdWrInit: ld (hstdsk),a ;set up drive (really head number) ; ld hl,frsttrk ld de,hsttrk ld bc,3 ldir ;initialize track and sector ; ld hl,(syslen) ;get # of bytes to read/write ld de,hstsiz ;get host sector size ; xor a ;0 in A and clear carry cpl ;-1 divlp: inc a ;bump up quotient sbc hl,de ;subtract jr nc,divlp ;until carry ; add hl,de ;restore HL to positive ; ld (sctrcnt),a ;save sector count ld a,h ;get remainder or l ;check if non 0 jr z,hvcnt ;jrif no fractional sector ld hl,sctrcnt ;else point at sector count inc (hl) ;and bump up by one. hvcnt: ld hl,(nrsrvd) ;get number of reserved tracks ld h,0 ;0 in H ex de,hl ; count in DE ld hl,(frsttrk) ;get starting track add hl,de ;add in reserved track count dec hl ;normalize to maximum track number ld (maxtrk),hl ;save it here. ; ld hl,(sysbuf) ;get start of system ld (adrhst),hl ;put it here ex de,hl ;and save in DE in case of error ret ;end of initiliazation ;*************************************************************** ;Function: WriteHst ;Purpose: Do physical write to IDE drive ;Entry: hstdsk, hsttrk, hstdsk set up ;Exit: sector in hstbuf written to disk ;Used: all Writehst: call tfsetup ;set up Task File ld a,CmdWr ;get a write command out (IdeCmd),a ;send it to Task File call WaitDrq ;wait for data otir otir ;write 512 bytes jr chkerr ;check for/report errors ;*************************************************************** ;Function: ReadHst ;Purpose: Do physical read of IDE drive ;Entry: hstdsk, hsttrk, hstdsk set up ;Exit: sector read into hstbuf ;Used: all Readhst: call tfsetup ;set up Task File ld a,CmdRd ;get a read command out (IdeCmd),a ;send to task file call WaitDrq ;wait for data inir inir ;read 512 bytes chkerr: in a,(IdeStat) ;get status and 1 ;check error bit ret ;return error/no error ;*************************************************************** ;Function: TFsetup ;Purpose: send host parms to IDE Task File registers ;Entry: hstdsk, hsttrk, hstsec set up ;Exit: Task file registers set up. HL points to hstbuf, ; BC has count, data port address tfsetup: in a,(IdeStat) ;get status rla ;BSY bit to Carry jr c,tfsetup ;loop until not BUSY ; ld a,1 ;1-sector transfer out (IdeSCnt),a ;tell IDE drive ld a,(hstsec) ;get host sector number inc a ;bump up to 1 out (IdeSNum),a ;send to Task File ld hl,(hsttrk) ;get host track ld a,l ;get low order byte out (IdeCLo),a ;send to Task File ld a,h ;get high-order byte out (IdeCHi),a ;send to task file ld a,(hstdsk) ;get host disk number or 0a0h ;make into SDH byte out (IdeSDH),a ;send to drive! ; ld hl,(ADRHST) ;HL points to host buffer ld bc,IdeDat ;BC has count, port ret ;and go back ;*************************************************************** ;Function: WaitDrq ;Purpose: Wait until data available or ready for data ;Entry: None ;Exit: None ;Uses: AF WaitDrq: in a,(IdeCmd) bit 3,a jr z,WaitDrq ret ;*************************************************************** ;Function: getkey ;Purpose: Wait for, echo and return keypress ;Entry: none ;Exit: character in A, Z set if was carriage return. ;Uses: All getkey: ld c,constat call bdos or a ;set flags jr z,getkey ;wait until key pressed ld c,conin call bdos ;fetch cp 0dh ;carriage return? ret ;and go back ;*************************************************************** ;Function: asc2bin ;Purpose: convert ASCII hex numeric character to binary value ;Entry: A = ASCII char ;Exit: Carry set if not valid hex digit, Carry clear and ; A = binary value if valid hex digit. ;Uses: AF asc2bin: sub 30h ;normalize ret c ;return if less than '0' cp 0ah ;bigger than '9'? jr c,asc2b1 ;jrif <= 9 sub 7 ;bump down to A-F cp 10h ;is bigger than F? asc2b1: ccf ;make Carry reflect error condition ret ;and go back ;*************************************************************** ;Function: chknf ;Purpose: detect ID Not Found error ;Entry: Status register error bit set ;Exit: Z clear if ID not found, Z set if other error ;Uses: AF chknf: in a,(IdeErr) ;error, find out which bit 4,a ;did we run off the end of the track? ret ;and go back ;*************************************************************** ;Routine: PRWORD ;Purpose: Print 16-bit value to console ;Entry: HL = word ;Exit: 16-bit value displayed as 4 hex digits on console ;Uses: ALL prword: ld a,h ;get high byte call prbyte ;print it ld a,l ;get low byte and fall through to ;prbyte to print it ;*************************************************************** ;Routine: PRBYTE ;Purpose: Print 8-bit value to console ;Entry: A = byte ;Exit: 8-bit value displayed as 2 hex digits on console ;Uses: ALL prbyte: push af ;save byte for later rrca rrca ;move upper nybble rrca ;to lower rrca call prnyb ;print it pop af ;get byte back and fall through ;to prnyb to print lower nybble ;*************************************************************** ;Routine: PRNYB ;Purpose: Print 4-bit value to console ;Entry: A(0:3) = nybble of interest ;Exit: 4-bit value displayed as 1 hex digit on console ;Uses: ALL prnyb: and 0fh ;mask lower nybble cp 0ah ;bigger than 9? jr c,prnyb1 ;no, jump around add a,7 ;else bump to letters prnyb1: add a,30h ;make into hex digit ;and fall through to pchar ;*************************************************************** ;Routine: pchar ;Purpose: print character in A on the console ;Entry: A has ASCII character ;Exit: character in A printed to console ;Uses: BC, DE, AF ; pchar: push hl ld e,a ld c,conout call bdos pop hl ret ;*************************************************************** ;Fixed data area ; ; Patch the following two words with the starting address and ; length (in bytes) of the buffer holding the OS image. Values ; below are for the DRI standard MOVCPM. sysbuf: defw 0980h ;MOVCPM leaves OS image here syslen: defw 1600h ;bios-ccp is this many bytes ; Patch the following word with the starting host track. Patch ; the next byte with the starting 0-relative host sector of the ; starting track. Patch the next byte with the number of system ; tracks. Values below are for GIDE BIOS extension for Davidge ; DSB 4/6. frsttrk: defw 0 ;start on track (cylinder) 0 frstsec: defb 1 ;skip boot sector on track 0 nrsrvd: defb offset ;2 reserved tracks. ;*************************************************************** ; Messages.... ; signon: defb 0dh,0ah,'IDEGEN v0.9 -- John D. Baker, ' defb '26 January 1996$' fullmsg: defb 0dh,0ah,0ah,'System tracks full! ' defb 'Bytes unwritten: 0x$' nxpctmsg: defb 0dh,0ah,0ah,'Unexpected error from IDE drive! ' defb 0dh,0ah,'Error register: 0x$' nofilmsg: defb 0dh,0ah,0ah,'No file: $' srcprmt: defb 0dh,0ah,0ah,'Source head [0-' srcmxh: defb 'F] or to skip: $' dstprmt: defb 0dh,0ah,0ah,'Destination head [0-' dstmxh: defb 'F] or to abort: $' ;*************************************************************** ;Ram Variables and uninitialized data ; hstdsk: defs 1 ;host disk number hsttrk: defs 2 ;host track number hstsec: defs 1 ;host sector number sctrcnt: defs 1 ;count of sectors to write maxtrk: defs 2 ;max reserved track number adrhst: defs 2 ;address of host transfer buffer ; defs 24 ;reserve at least this much for stack ;must end by 0780h to allow a 512-byte boot sector... if $ gt 0780h .printx " *** IDEGEN TOO LARGE!!! *** " endif end