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