]> cloudbase.mooo.com Git - z180-stamp-cpm3.git/blame - cbios/ldrbios.180
Add ldrbios.180 and generate cpmldr.com Load cpm3.sys from CF-IF device.
[z180-stamp-cpm3.git] / cbios / ldrbios.180
CommitLineData
88c783bb
L
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
11IDEDat equ IDEBASE+0 ; Data Register\r
12IDEErr equ IDEBASE+1 ; Error Register\r
13IDEFeat equ IDEBASE+1 ; Feature Register\r
14IDESCnt equ IDEBASE+2 ; Sector Count\r
15IDESNum equ IDEBASE+3 ; Sector Number\r
16IDECLo equ IDEBASE+4 ; Cylinder Low\r
17IDECHi equ IDEBASE+5 ; Cylinder High\r
18IDESDH equ IDEBASE+6 ; Drive and Head\r
19IDECmd equ IDEBASE+7 ; Command / Status\r
20\r
21 ; IDE Hard disk commands:\r
22\r
23CmdHome equ 10h ; Recalibrate\r
24CmdRd equ 20h ; Read Sector\r
25CmdWr equ 30h ; Write Sector\r
26CmdInit equ 91h ; Initialize Drive Params\r
27CmdId equ 0ECh ; Read ID\r
28CmdSF equ 0EFh ; Set Feature\r
29\r
30 ; Partition Table Structures\r
31\r
32PART_TYPE equ 4\r
33PART_START equ 8\r
34PART_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
39PARTID1_FAT16 equ 00EH\r
40PARTID2_FAT16 equ 006H\r
41PARTID_CPM equ 052H\r
42\r
43\r
44TIMEOUT equ 1000\r
45\r
46cr equ 13\r
47lf 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
98hwini_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
113hwini0_e:\r
114 db 0 ;stop mark\r
115 db 0,0,0,0,0,0,0,0 ;\r
116\r
117msg_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
128dphldr 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
176dph0:\r
177 dphldr 0,dpbsimhd512,0,0,bcb,bcb\r
178\r
179bcb:\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
194dpbsimhd512:\r
195 dpb 512,8,2048,4096,1024,6,8000h\r
196\r
197;-------------------------------------------------------------------------------\r
198\r
199wboot: ; jump vector locations not used\r
200const:\r
201conin:\r
202list:\r
203auxout:\r
204auxin:\r
205write:\r
206listst:\r
207conost:\r
208auxist:\r
209auxost:\r
210devtbl:\r
211cinit:\r
212getdrv:\r
213multio:\r
214flush:\r
215time:\r
216bnksel:\r
217setbnk:\r
218xmove:\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
229ioini1l:\r
230 push bc\r
231 jr io1_nxt\r
232io1_lp:\r
233 ld c,(hl) ;port address\r
234 inc hl\r
235 otim\r
236 jr nz,io1_lp\r
237io1_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
262boot:\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
291ploop:\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
301pnext:\r
302 add hl,de\r
303 djnz ploop\r
304\r
305boot_err:\r
306 ld hl,msg_boot\r
307 call ?pmsg\r
308halt_loop:\r
309 halt\r
310 jr halt_loop\r
311\r
312;-------------------------------------------------------------------------------\r
313\r
314conout:\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
324move:\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
334seldsk:\r
335 ld hl,dph0\r
336 ret\r
337\r
338; Home selected drive. Treated as SETTRK(0).\r
339\r
340home:\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
345settrk:\r
346 ld (@trk),bc\r
347 ret\r
348\r
349; Set Sector. Saves sector number from <BC> in @sect.\r
350\r
351setsec:\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
357setdma:\r
358 ld (@dma),bc\r
359 ret\r
360\r
361; Translate sector address. Not needed. Return physical=logical.\r
362\r
363sectrn:\r
364 ld l,c\r
365 ld h,b\r
366 ret\r
367\r
368;-----------------------------------------------------------------\r
369\r
370chk_to:\r
371 xor a ;\r
372to_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
388wait_rdy_to:\r
389 push hl\r
390 ld hl,TIMEOUT\r
391wrdy_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
398wrdy_e:\r
399 pop hl\r
400 sbc a,a\r
401 ret\r
402\r
403\r
404;-------------------------------------------------------------------------------\r
405\r
406do_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
418read_parttbl:\r
419 ld hl,ptab_start\r
420 ld b,8\r
421rp_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
439read:\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
476wdrq:\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
482wnb: ; 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
494ptab_start:\r
495 dw 0,0\r
496@trk: dw 0\r
497@sect: dw 0\r
498@dma: dw 0\r
499\r
500buffer:\r
501 end\r