TITLE 'CF cold boot loader' ; Port Address Equates include config.inc include z180reg.inc ; IDE Task File Register Definitions IDEDat equ IDEBASE+0 ; Data Register IDEErr equ IDEBASE+1 ; Error Register IDEFeat equ IDEBASE+1 ; Feature Register IDESCnt equ IDEBASE+2 ; Sector Count IDESNum equ IDEBASE+3 ; Sector Number IDECLo equ IDEBASE+4 ; Cylinder Low IDECHi equ IDEBASE+5 ; Cylinder High IDESDH equ IDEBASE+6 ; Drive and Head IDECmd equ IDEBASE+7 ; Command / Status ; IDE Hard disk commands: CmdNOP equ 00h ; NOP Command CmdHome equ 10h ; Recalibrate CmdRd equ 20h ; Read Sector CmdWr equ 30h ; Write Sector CmdId equ 0ECh ; Read ID CmdSF equ 0EFh ; Set Feature ; Partition Table Structures PTYPE equ 4 PSTART equ 8 PSIZE equ 12 ; Partition table id ; (see http://www.win.tue.nl/~aeb/partitions/partition_types-1.html) PARTID1_FAT16 equ 00EH PARTID2_FAT16 equ 006H PARTID_CPM equ 052H DEBUG equ false ; not used DO_WAIT_NBSY equ false RUN_TPA equ false if RUN_TPA base equ 0100h else base equ 0 endif ;------------------------------------------------------------------------------- aseg org base jr start para: equ $ loadaddr: dw base+100h sec_start: db 0 sec_cnt: db 7 part_id: db PARTID_CPM timeout: dw 10000 stages: db number_of_stages done: db 0 result: db 0 ide_result: db 0,0 o_part_id equ part_id - para o_stages equ stages - para o_done equ done - para o_result equ result - para ;------------------------------------------------------------------------------- start: ld sp,stack pop ix pop de loop: dec (ix+o_stages) jp m,stop pop hl push de push hl exx ld hl,(loadaddr) ret continue: exx ld (ix+o_result),a or a jr z,loop stop: in a,(Idecmd) ;2 ld l,a ;1 in a,(IdeErr) ;2 ld h,a ;1 ld (ide_result),hl ;3 9 dec (ix+o_done) halt ;------------------------------------------------------------------------------- chk_to: xor a ; to_l: dec a ex (sp),hl ex (sp),hl jr nz,to_l ; dec hl ; 4 ld a,h ; 4 or l ; 4 ret nz ; 10/5 ccf ; 3 ret ; 9 if base = 0 if 044h-$ > 0 rept 044h-$ db 0 endm endif endif part_start: ; dw 0 ; dw 0 ; part_start is 4 byte long, but stack gets free stack: dw para dw continue stage_table: if DO_WAIT_NBSY dw s_wait_not_bsy endif dw s_wait_rdy dw s_check_io dw s_set_xfermode8 dw s_read_parttbl dw s_check_signature dw s_find_partition dw s_read_sectors dw s_go number_of_stages equ ($-stage_table)/2 if DO_WAIT_NBSY ;------------------------------------------------------------------------------- ; Wait while device is busy with time out ; return: ; a = 0 if ok ; a = ff in timeout ; destroys hl s_wait_not_bsy: ld hl,(timeout) wnb_l: in a,(IdeCmd) rla jr nc,wnb_e call chk_to jr nc,wnb_l wnb_e: sbc a,a ret endif ;------------------------------------------------------------------------------- ; Wait for ready signal with time out ; return: ; a = 0 if ok ; a = ff in timeout ; destroys hl s_wait_rdy: wait_rdy_to: ld hl,(timeout) wrdy_l: in a,(IdeCmd) xor 01000000b and 11000000b ; clears carry jr z,wrdy_e call chk_to jr nc,wrdy_l wrdy_e: sbc a,a ret ;------------------------------------------------------------------------------- s_check_io: ld a,0E0h ; unit 0, lba mode out (IdeSDH),a ; xor a ; execute NOP command call do_ide_cmd ; should return error ret c xor 1 ret nz ld a,CmdHome ; execute RECALIBRATE command jr do_ide_cmd ;------------------------------------------------------------------------------- s_set_xfermode8: ld a,1 ; Enable 8-bit data transfer. out (IDEFeat),a ld a,CmdSF ; Set feature command ; fall thru ; jr do_ide_cmd ;------------------------------------------------------------------------------- do_ide_cmd: out (IdeCmd),a ; call wait_rdy_to ret c in a,(IdeCmd) and 10001001b ; ret ;------------------------------------------------------------------------------- s_check_signature: ; ld hl,(loadaddr) inc h ; Point to last byte of MBR inc h dec hl ld a,0aah cp (hl) ; Test, if it has a valid MBR ret nz dec hl cpl ; a=055h sub (hl) ; ret ; should be 0 ;------------------------------------------------------------------------------- ; Read partition table (lbr) s_read_parttbl: ; ld hl,(loadaddr) ld bc,1*256 + 0 ; sector 0 (lba) ld e,c ld d,c jr read_sectors ;------------------------------------------------------------------------------- ; Find CP/M paartition ; Look for first CP/M partition ; and save partition offset s_find_partition: ; ld hl,(loadaddr) ld de,512-2-64+PTYPE ; Point to partition type of first first partition table entry add hl,de ld de,16 ld b,4 ; Max # of partition table entries ploop: ld a,(ix+o_part_id) sub (HL) ; Test for CP/M Partition jr nz,pnext ld bc,4 add hl,bc ; Point to partition start (lba) ld de,part_start ldir ret ;a=0 pnext: add hl,de djnz ploop ret ;------------------------------------------------------------------------------- ; Read sec_count sectors, beginning at part_start+sec_start s_read_sectors: ; ld hl,(loadaddr) push hl ld bc,(sec_start) ;b=sec_count, c=sec_start ld e,c ld d,0 ld hl,(part_start) ;add partition offset to sector number add hl,de ld a,(part_start+2) adc a,d ;d=0 ld c,a ex de,hl pop hl ; fall thru ;------------------------------------------------------------------------------- ; Read a number of sectors ; hl: memory address ; cde: sector number (24 bit) ; b: sector count read_sectors: ld a,e ; lba 0..7 out (IdeSNum),a ld a,d ; lba 0..7 out (IdeClo),a ld a,c ; lba 0..7 out (IdeCHi),a ld a,b ; number of sectors to read out (IdeSCnt),a ; set sector count ld a,CmdRd out (IdeCmd),a ; command: read sector data ld d,b ld bc,IdeDat ; I/O address wdrq: in a,(IdeCmd) ; wait for DRQ to become active bit 3,a jr z,wdrq inir ; read 512 data bytes (2 x 256) inir wnb: ; wait while busy in a,(IdeCmd) ; rlca jr c,wnb rrca ; restore status bit 0,a jr nz,err_out dec d jr nz,wdrq err_out: and 10001001b ; Busy, DRQ, or Error? ret ; return 0, if everything is ok ;------------------------------------------------------------------------------- s_go: ; ld hl,(loadaddr) dec (ix+o_done) jp (hl) ;------------------------------------------------------------------------------- if base = 0 if $ > 100h .printx Error: Program to large to fit in page 0! db "Stop endif endif end