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