1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
|
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
|