]>
Commit | Line | Data |
---|---|---|
1 | title 'LDRBIOS for CP/M 3.0'\r | |
2 | \r | |
3 | ; Port Address Equates\r | |
4 | \r | |
5 | include config.inc\r | |
6 | include z180reg.inc\r | |
7 | \r | |
8 | \r | |
9 | ; IDE Task File Register Definitions\r | |
10 | \r | |
11 | IDEDat equ IDEBASE+0 ; Data Register\r | |
12 | IDEErr equ IDEBASE+1 ; Error Register\r | |
13 | IDEFeat equ IDEBASE+1 ; Feature Register\r | |
14 | IDESCnt equ IDEBASE+2 ; Sector Count\r | |
15 | IDESNum equ IDEBASE+3 ; Sector Number\r | |
16 | IDECLo equ IDEBASE+4 ; Cylinder Low\r | |
17 | IDECHi equ IDEBASE+5 ; Cylinder High\r | |
18 | IDESDH equ IDEBASE+6 ; Drive and Head\r | |
19 | IDECmd equ IDEBASE+7 ; Command / Status\r | |
20 | \r | |
21 | ; IDE Hard disk commands:\r | |
22 | \r | |
23 | CmdHome equ 10h ; Recalibrate\r | |
24 | CmdRd equ 20h ; Read Sector\r | |
25 | CmdWr equ 30h ; Write Sector\r | |
26 | CmdInit equ 91h ; Initialize Drive Params\r | |
27 | CmdId equ 0ECh ; Read ID\r | |
28 | CmdSF equ 0EFh ; Set Feature\r | |
29 | \r | |
30 | ; Partition Table Structures\r | |
31 | \r | |
32 | PART_TYPE equ 4\r | |
33 | PART_START equ 8\r | |
34 | PART_SIZE equ 12\r | |
35 | \r | |
36 | ; Partition table id\r | |
37 | ; (see http://www.win.tue.nl/~aeb/partitions/partition_types-1.html)\r | |
38 | \r | |
39 | PARTID1_FAT16 equ 00EH\r | |
40 | PARTID2_FAT16 equ 006H\r | |
41 | PARTID_CPM equ 052H\r | |
42 | \r | |
43 | \r | |
44 | TIMEOUT equ 1000\r | |
45 | \r | |
46 | cr equ 13\r | |
47 | lf equ 10\r | |
48 | \r | |
49 | \r | |
50 | .z80\r | |
51 | cseg\r | |
52 | \r | |
53 | ; BIOS Jump vector.\r | |
54 | \r | |
55 | ?boot: jp boot ; initial entry on cold start\r | |
56 | ?wboot: jp wboot ; reentry on program exit, warm start\r | |
57 | \r | |
58 | ?const: jp const ; return console input status\r | |
59 | ?conin: jp conin ; return console input character\r | |
60 | ?cono: jp conout ; send console output character\r | |
61 | ?list: jp list ; send list output character\r | |
62 | ?auxo: jp auxout ; send auxilliary output character\r | |
63 | ?auxi: jp auxin ; return auxilliary input character\r | |
64 | \r | |
65 | ?home: jp home ; set disks to logical home\r | |
66 | ?sldsk: jp seldsk ; select disk drive, return disk parameter info\r | |
67 | ?sttrk: jp settrk ; set disk track\r | |
68 | ?stsec: jp setsec ; set disk sector\r | |
69 | ?stdma: jp setdma ; set disk I/O memory address\r | |
70 | ?read: jp read ; read physical block(s)\r | |
71 | ?write: jp write ; write physical block(s)\r | |
72 | \r | |
73 | ?lists: jp listst ; return list device status\r | |
74 | ?sctrn: jp sectrn ; translate logical to physical sector\r | |
75 | \r | |
76 | ?conos: jp conost ; return console output status\r | |
77 | ?auxis: jp auxist ; return aux input status\r | |
78 | ?auxos: jp auxost ; return aux output status\r | |
79 | ?dvtbl: jp devtbl ; return address of device def table\r | |
80 | ?devin: jp cinit ; change baud rate of device\r | |
81 | \r | |
82 | ?drtbl: jp getdrv ; return address of disk drive table\r | |
83 | ?mltio: jp multio ; set multiple record count for disk I/O\r | |
84 | ?flush: jp flush ; flush BIOS maintained disk caching\r | |
85 | \r | |
86 | ?mov: jp move ; block move memory to memory\r | |
87 | ?tim: jp time ; Signal Time and Date operation\r | |
88 | ?bnksl: jp bnksel ; select bank for code execution and default DMA\r | |
89 | ?stbnk: jp setbnk ; select different bank for disk I/O DMA operations.\r | |
90 | ?xmov: jp xmove ; set source and destination banks for one operation\r | |
91 | \r | |
92 | jp 0 ; reserved for future expansion\r | |
93 | jp 0 ; reserved for future expansion\r | |
94 | jp 0 ; reserved for future expansion\r | |
95 | \r | |
96 | ;----------------------------------------------------------------------\r | |
97 | \r | |
98 | hwini_tab:\r | |
99 | db (hwini0_e-$)/2 ;count\r | |
100 | db rcr,CREFSH ;configure DRAM refresh\r | |
101 | db dcntl,CWAITIO ;wait states\r | |
102 | db ccr,M_NCD ;No Clock Divide\r | |
103 | db cmr,PHI_X2 ;X2 Clock Multiplier\r | |
104 | db omcr,~M_IOC ;Operation Mode Control Register\r | |
105 | ;MMU\r | |
106 | db cbr,SYS$CBR ;Common Base Register\r | |
107 | db cbar,USR$CBAR ;Common Base Area Register\r | |
108 | ;ASCI0\r | |
109 | db asext1,0 ;disable BRG\r | |
110 | db stat1,00000000b ;disable RX, TX interrupt, disable CTS1\r | |
111 | db cntlb1,10000000b;PS:10 DR:16 Rate:1 --> BR = Phi/160\r | |
112 | db cntla1,01100101b;RE TE RTS:0 8N2\r | |
113 | hwini0_e:\r | |
114 | db 0 ;stop mark\r | |
115 | db 0,0,0,0,0,0,0,0 ;\r | |
116 | \r | |
117 | msg_boot:\r | |
118 | db cr,lf,'CPMLDR error: Unable to locate CP/M partition',cr,lf,0\r | |
119 | \r | |
120 | ;-------------------------------------------------------------------------------\r | |
121 | \r | |
122 | ; CP/M 3 Disk definition macros\r | |
123 | \r | |
124 | maclib cpm3slr.lib ; dpb mcaro\r | |
125 | \r | |
126 | ; The dph macro from the lib depends on GENCPM\r | |
127 | \r | |
128 | dphldr macro ?trans,?dpb,?csize,?asize,?dirbcb,?dtabcb\r | |
129 | local ?csv,?alv\r | |
130 | dw ?trans ; translate table address\r | |
131 | db 0,0,0,0,0,0,0,0,0 ; BDOS Scratch area\r | |
132 | db 0 ; media flag\r | |
133 | dw ?dpb ; disk parameter block\r | |
134 | if nul ?csize\r | |
135 | dw 0 ; permanently mounted, no checksum vector\r | |
136 | else\r | |
137 | if ?csize = 0\r | |
138 | dw 0\r | |
139 | else\r | |
140 | dw ?csv ; checksum vector\r | |
141 | endif\r | |
142 | endif\r | |
143 | if nul ?asize\r | |
144 | dw 0 ; no alloc vector\r | |
145 | else\r | |
146 | if ?asize = 0\r | |
147 | dw 0\r | |
148 | else\r | |
149 | dw ?alv ; allocation vector\r | |
150 | endif\r | |
151 | endif\r | |
152 | dw ?dirbcb\r | |
153 | dw ?dtabcb\r | |
154 | dw 0ffffh ; no hash\r | |
155 | db 0 ; hash bank\r | |
156 | if not nul ?csize\r | |
157 | if ?csize <> 0\r | |
158 | ?csv ds ?csize ; checksum vector\r | |
159 | endif\r | |
160 | endif\r | |
161 | if not nul ?asize\r | |
162 | if ?asize <> 0\r | |
163 | ?alv ds ?asize ; allocation vector\r | |
164 | endif\r | |
165 | endif\r | |
166 | endm\r | |
167 | \r | |
168 | ;-------------------------------------------------------------------------------\r | |
169 | \r | |
170 | ; dphldr translate$table, - disk parameter header\r | |
171 | ; disk$parameter$block,\r | |
172 | ; checksum$size, (optional)\r | |
173 | ; alloc$size (optional)\r | |
174 | ; dir$bcb\r | |
175 | ; data$bcb\r | |
176 | dph0:\r | |
177 | dphldr 0,dpbsimhd512,0,0,bcb,bcb\r | |
178 | \r | |
179 | bcb:\r | |
180 | db 0ffh\r | |
181 | rept 9\r | |
182 | db 0\r | |
183 | endm\r | |
184 | dw buffer\r | |
185 | \r | |
186 | ; dpb physical$sector$size, - disk parameter block\r | |
187 | ; physical$sectors$per$track,\r | |
188 | ; number$tracks,\r | |
189 | ; block$size,\r | |
190 | ; number$dir$entries,\r | |
191 | ; track$offset,\r | |
192 | ; checksum$vec$size (optional)\r | |
193 | \r | |
194 | dpbsimhd512:\r | |
195 | dpb 512,8,2048,4096,1024,6,8000h\r | |
196 | \r | |
197 | ;-------------------------------------------------------------------------------\r | |
198 | \r | |
199 | wboot: ; jump vector locations not used\r | |
200 | const:\r | |
201 | conin:\r | |
202 | list:\r | |
203 | auxout:\r | |
204 | auxin:\r | |
205 | write:\r | |
206 | listst:\r | |
207 | conost:\r | |
208 | auxist:\r | |
209 | auxost:\r | |
210 | devtbl:\r | |
211 | cinit:\r | |
212 | getdrv:\r | |
213 | multio:\r | |
214 | flush:\r | |
215 | time:\r | |
216 | bnksel:\r | |
217 | setbnk:\r | |
218 | xmove:\r | |
219 | ret\r | |
220 | \r | |
221 | ;-------------------------------------------------------------------------------\r | |
222 | ; output bytes to ports\r | |
223 | ;\r | |
224 | ; hl: tables of port,value pairs:\r | |
225 | ; db n, port1,val1, port2,val2,... portn,valn\r | |
226 | ; ...\r | |
227 | ; db 0 ; Terminate table\r | |
228 | \r | |
229 | ioini1l:\r | |
230 | push bc\r | |
231 | jr io1_nxt\r | |
232 | io1_lp:\r | |
233 | ld c,(hl) ;port address\r | |
234 | inc hl\r | |
235 | otim\r | |
236 | jr nz,io1_lp\r | |
237 | io1_nxt:\r | |
238 | ld b,(hl) ;count\r | |
239 | inc hl\r | |
240 | inc b\r | |
241 | djnz io1_lp\r | |
242 | \r | |
243 | pop bc\r | |
244 | ret\r | |
245 | \r | |
246 | ;-------------------------------------------------------------------------------\r | |
247 | ; print message @<HL> up to a null\r | |
248 | \r | |
249 | ?pmsg:\r | |
250 | ld a,(hl)\r | |
251 | or a\r | |
252 | ret z\r | |
253 | ld c,a\r | |
254 | push hl\r | |
255 | call ?cono\r | |
256 | pop hl\r | |
257 | inc hl\r | |
258 | jr ?pmsg\r | |
259 | \r | |
260 | ;-------------------------------------------------------------------------------\r | |
261 | \r | |
262 | boot:\r | |
263 | ; Init CPU, MMU, ASCI0\r | |
264 | \r | |
265 | ld hl,hwini_tab\r | |
266 | call ioini1l\r | |
267 | \r | |
268 | ; Init disk partition\r | |
269 | \r | |
270 | call read_parttbl\r | |
271 | or a\r | |
272 | jr nz,boot_err\r | |
273 | \r | |
274 | ; check_signature\r | |
275 | \r | |
276 | ld hl,buffer+512-1\r | |
277 | ld a,0aah\r | |
278 | cp (hl) ; Test, if it has a valid MBR\r | |
279 | jr nz,boot_err\r | |
280 | dec hl\r | |
281 | cpl ; a=055h\r | |
282 | cp (hl) ;\r | |
283 | jr nz,boot_err\r | |
284 | \r | |
285 | ; Find CP/M paartition\r | |
286 | ; Look for first CP/M partition and save partition offset\r | |
287 | \r | |
288 | ld hl,buffer+512-2-64+PART_TYPE ; Point to partition type of first first partition table entry\r | |
289 | ld de,16\r | |
290 | ld b,4 ; Max # of partition table entries\r | |
291 | ploop:\r | |
292 | ld a,PARTID_CPM\r | |
293 | sub (HL) ; Test for CP/M Partition\r | |
294 | jr nz,pnext\r | |
295 | ld bc,4\r | |
296 | add hl,bc ; Point to partition start (lba)\r | |
297 | ld de,ptab_start\r | |
298 | ldir\r | |
299 | ret ;a=0\r | |
300 | \r | |
301 | pnext:\r | |
302 | add hl,de\r | |
303 | djnz ploop\r | |
304 | \r | |
305 | boot_err:\r | |
306 | ld hl,msg_boot\r | |
307 | call ?pmsg\r | |
308 | halt_loop:\r | |
309 | halt\r | |
310 | jr halt_loop\r | |
311 | \r | |
312 | ;-------------------------------------------------------------------------------\r | |
313 | \r | |
314 | conout:\r | |
315 | in0 a,(stat1)\r | |
316 | and M_TDRE\r | |
317 | jr z,conout\r | |
318 | out0 (tdr1),c\r | |
319 | ld a,c\r | |
320 | ret\r | |
321 | \r | |
322 | ;-------------------------------------------------------------------------------\r | |
323 | \r | |
324 | move:\r | |
325 | ex de,hl ; we are passed source in DE and dest in HL\r | |
326 | ldir ; use Z80 block move instruction\r | |
327 | ex de,hl ; need next addresses in same regs\r | |
328 | ret\r | |
329 | \r | |
330 | ;-------------------------------------------------------------------------------\r | |
331 | ; Select Disk Drive.\r | |
332 | ; Return address of disk parameter header in <HL>\r | |
333 | \r | |
334 | seldsk:\r | |
335 | ld hl,dph0\r | |
336 | ret\r | |
337 | \r | |
338 | ; Home selected drive. Treated as SETTRK(0).\r | |
339 | \r | |
340 | home:\r | |
341 | ld bc,0 ; same as set track zero\r | |
342 | \r | |
343 | ; Set Track. Saves track address from <BC> in @trk.\r | |
344 | \r | |
345 | settrk:\r | |
346 | ld (@trk),bc\r | |
347 | ret\r | |
348 | \r | |
349 | ; Set Sector. Saves sector number from <BC> in @sect.\r | |
350 | \r | |
351 | setsec:\r | |
352 | ld (@sect),bc\r | |
353 | ret\r | |
354 | \r | |
355 | ; Set Disk Memory Address. Saves DMA address from <BC> in @dma.\r | |
356 | \r | |
357 | setdma:\r | |
358 | ld (@dma),bc\r | |
359 | ret\r | |
360 | \r | |
361 | ; Translate sector address. Not needed. Return physical=logical.\r | |
362 | \r | |
363 | sectrn:\r | |
364 | ld l,c\r | |
365 | ld h,b\r | |
366 | ret\r | |
367 | \r | |
368 | ;-----------------------------------------------------------------\r | |
369 | \r | |
370 | chk_to:\r | |
371 | xor a ;\r | |
372 | to_l:\r | |
373 | dec a\r | |
374 | jr nz,to_l ;\r | |
375 | dec hl ; 4\r | |
376 | ld a,h ; 4\r | |
377 | or l ; 4\r | |
378 | ret nz ; 10/5\r | |
379 | ccf ; 3\r | |
380 | ret ; 9\r | |
381 | \r | |
382 | ;-------------------------------------------------------------------------------\r | |
383 | ; Wait for ready signal with time out\r | |
384 | ; return:\r | |
385 | ; a = 0 if ok\r | |
386 | ; a = ff if timeout\r | |
387 | \r | |
388 | wait_rdy_to:\r | |
389 | push hl\r | |
390 | ld hl,TIMEOUT\r | |
391 | wrdy_l:\r | |
392 | in a,(IdeCmd)\r | |
393 | xor 01000000b\r | |
394 | and 11000000b ; clears carry\r | |
395 | jr z,wrdy_e\r | |
396 | call chk_to\r | |
397 | jr nc,wrdy_l\r | |
398 | wrdy_e:\r | |
399 | pop hl\r | |
400 | sbc a,a\r | |
401 | ret\r | |
402 | \r | |
403 | \r | |
404 | ;-------------------------------------------------------------------------------\r | |
405 | \r | |
406 | do_ide_cmd:\r | |
407 | out (IdeCmd),a ;\r | |
408 | call wait_rdy_to\r | |
409 | ret c\r | |
410 | in a,(IdeCmd)\r | |
411 | and 10001001b ;\r | |
412 | ret\r | |
413 | \r | |
414 | \r | |
415 | ;-------------------------------------------------------------------------------\r | |
416 | ; Read partition table\r | |
417 | \r | |
418 | read_parttbl:\r | |
419 | ld hl,ptab_start\r | |
420 | ld b,8\r | |
421 | rp_l:\r | |
422 | ld (hl),0\r | |
423 | inc hl\r | |
424 | djnz rp_l\r | |
425 | \r | |
426 | ld hl,buffer\r | |
427 | ld (@dma),hl\r | |
428 | \r | |
429 | ; fall thru\r | |
430 | \r | |
431 | ;-------------------------------------------------------------------------------\r | |
432 | ; Read a sector\r | |
433 | \r | |
434 | ; compute logical block number (lba) --> cf-controller\r | |
435 | \r | |
436 | ; TODO: sectors per track from dpb\r | |
437 | ; lba = track * 8 + sector\r | |
438 | \r | |
439 | read:\r | |
440 | ld iy,ptab_start\r | |
441 | xor a\r | |
442 | ld hl,(@trk)\r | |
443 | add hl,hl\r | |
444 | adc a,a ; *2\r | |
445 | add hl,hl\r | |
446 | adc a,a ; *4\r | |
447 | add hl,hl\r | |
448 | adc a,a ; *8\r | |
449 | ld de,(@sect)\r | |
450 | add hl,de\r | |
451 | adc a,0\r | |
452 | ld e,a\r | |
453 | call wait_rdy_to\r | |
454 | ld a,(iy+0) ; add partition start\r | |
455 | add a,l\r | |
456 | out (IdeSNum),a\r | |
457 | ld a,(iy+1)\r | |
458 | adc a,h\r | |
459 | out (IdeCLo),a\r | |
460 | ld a,(iy+2)\r | |
461 | adc a,e\r | |
462 | out (IdeCHi),a\r | |
463 | ld a,(iy+3)\r | |
464 | adc a,0\r | |
465 | and 00FH\r | |
466 | or 0E0H\r | |
467 | out (IdeSDH),a\r | |
468 | ld hl,(@dma)\r | |
469 | \r | |
470 | ld a,1 ; number of sectors to read\r | |
471 | out (IdeSCnt),a ; set sector count\r | |
472 | \r | |
473 | ld a,CmdRd\r | |
474 | out (IdeCmd),a ; command: read sector data\r | |
475 | ld bc,IdeDat ; I/O address\r | |
476 | wdrq:\r | |
477 | in a,(IdeCmd) ; wait for DRQ to become active\r | |
478 | bit 3,a\r | |
479 | jr z,wdrq\r | |
480 | inir ; read 512 data bytes (2 x 256)\r | |
481 | inir\r | |
482 | wnb: ; wait while busy\r | |
483 | in a,(IdeCmd) ;\r | |
484 | rlca\r | |
485 | jr c,wnb\r | |
486 | rrca ; restore status\r | |
487 | and 10001001b ; Busy, DRQ, or Error?\r | |
488 | ret z ; return 0, if everything is ok\r | |
489 | ld a,1\r | |
490 | ret\r | |
491 | \r | |
492 | ;-------------------------------------------------------------------------------\r | |
493 | \r | |
494 | ptab_start:\r | |
495 | dw 0,0\r | |
496 | @trk: dw 0\r | |
497 | @sect: dw 0\r | |
498 | @dma: dw 0\r | |
499 | \r | |
500 | buffer:\r | |
501 | end\r |