CP/M ASM86 1.1 SOURCE: LOAD.A86 CCP/M-86 Loader Program and BI PAGE 1 1 2 title 'CCP/M-86 Loader Program and BIOS' 3 ;***************************************************** 4 ; The Loader consists of the three modules: 5 ; Loader BDOS (the file LBDOS.H86), the Loader 6 ; Program and the Loader BIOS. This 7 ; module contains both the Loader Program 8 ; and the Loader BIOS. 9 ; 10 ; The Loader resides in sectors 2-8 on the first track 11 ; of an IBM PC floppy diskette. The Loader is 12 ; is brought into memory by the Boot Sector which 13 ; resides in sector 1 of track 0. The Boot Sector 14 ; is brought into memory by the IBM PC's ROM 15 ; monitor. 16 ; 17 ; The Loader Program opens the file 'CCPM.SYS' using the 18 ; Loader BDOS and Loader BIOS, 19 ; and then reads it into memory. The DS register is set 20 ; to the start of the CCPM DATA area, and a JMPF to the 21 ; first byte of the CCPM code is executed. 22 ; 23 ; The first 128 byte record of the CCPM.SYS file is a header 24 ; with the following format: 25 ; 26 ; +----+----+----+----+----+----+----+----+----+ 27 ; |TYPE| LEN | ABS | MIN | MAX | 28 ; +----+----+----+----+----+----+----+----+----+ 29 ; 30 ; type rb 1 ;seg type 31 ; len rw 1 ;length 32 ; abs dw 1 ;absolute segment address for LOADER 33 ; min rw 1 ;minimum mem 34 ; max rw 1 ;max mem needed 35 ; 36 ; The code is expected first and then the data within CCPM.SYS 37 ; This header record is constructed automatically by the 38 ; GENCCPM utility. See the variables declared at 'SEC1:' 39 ; where the first sector of CCPM.SYS will be read. 40 ; 41 ; Loader may be read into any segment by the Boot 42 ; Sector that does not overlap the area of memory 43 ; the system image in CCPM.SYS will occupy. 44 ; 45 ;***************************************************** 46 47 0000 false equ 0 48 FFFF true equ not false 49 50 000D cr equ 0dh 51 000A lf equ 0ah 52 53 0000 ldbdos_offset equ 0000H ;offset of Loader BDOS CP/M ASM86 1.1 SOURCE: LOAD.A86 CCP/M-86 Loader Program and BI PAGE 2 54 55 0900 ldr_offset equ 0900h ;offset of Loader BIOS 56 57 0001 codetype equ 1 ; code type CMD header 58 0002 datatype equ 2 ; data type CMD header 59 60 ; bdos function numbers 61 62 000E seldskf equ 14 63 000F openf equ 15 64 0014 readsf equ 20 65 001A setdmaf equ 26 66 0020 setuserf equ 32 67 002C setmultcntf equ 44 68 0033 setdmabf equ 51 69 70 71 ;***************************************************** 72 ;* 73 ;* CCPMLDR starts here 74 ;* 75 ;***************************************************** 76 77 cseg 78 org ldr_offset 79 80 0900 E96303 0C66 jmp init 81 0903 E9D700 09DD jmp entry 82 0906 E90100 090A jmp loadp 83 84 0909 00 ldusr db 0 ;load user is 0 85 86 87 loadp: ; loader entry from BDOS init 88 ;----- 89 ; entry: CH = boot user number 90 ; CL = boot disk number 91 ; DS,ES,SS = CS 92 93 090A BA540D mov dx,offset signon 94 090D E8BB00 09CB call msg 95 96 0910 2E8A160909 mov dl,ldusr 97 0915 B120CDE0 mov cl,setuserf ! int 224 ;set user number 98 99 0919 BAC70D mov dx,offset ccpmfcb 100 091C B10FCDE0 mov cl,openf ! int 224 ;open CCPM.SYS file 101 0920 3CFF7506 092A cmp al,255 ! jne perr ;insure good file 102 0924 BA680D mov dx,offset nofile 103 0927 E97500 099F jmp stop 104 perr: 105 092A 8CDA mov dx,ds 106 092C B133CDE0 mov cl,setdmabf ! int 224 ;set DMA segment address CP/M ASM86 1.1 SOURCE: LOAD.A86 CCP/M-86 Loader Program and BI PAGE 3 107 108 109 0930 BAE80D mov dx,offset sec1 110 0933 B11ACDE0 mov cl,setdmaf ! int 224 ;set DMA offset address 111 112 0937 B201 mov dl,1 113 0939 B12CCDE0 mov cl,setmultcntf ! int 224 ;set Multi-sector count to 1 114 115 093D BAC70D mov dx,offset ccpmfcb 116 0940 B114CDE0 mov cl,readsf ! int 224 ; read first record 117 118 ; the following 119 ; "commented out" code 120 ; can be used to 121 ; perform error checking 122 123 ; cmp ctype,codetype ; code should be first 124 ; jnz badhdr 125 ; cmp dtype,datatype ; then data 126 ; jnz badhdr 127 ; mov ax,cldseg ; code abs + code length 128 ; add ax,clen ; should be = to data abs 129 ; cmp ax,dldseg ! jnz badhdr 130 ; add ax,dlen ! cmp ax,cldseg ; check for wrap around 131 ; ja hdrok 132 ;badhdr: 133 ; mov dx,offset rerr 134 ; jmp stop 135 ;hdrok: 136 0944 BA9C0D mov dx,offset csegment 137 0947 E88100 09CB call msg ; put memory map on console 138 094A A1EB0D mov ax,cldseg 139 094D E85400 09A4 call phex ; print base code segment 140 0950 BAB00D mov dx,offset dsegment 141 0953 E87500 09CB call msg ; print base data segment 142 0956 A1F40D mov ax,dldseg 143 0959 E84800 09A4 call phex 144 145 095C BA8000 mov dx,128 146 095F B12CCDE0 mov cl,setmultcntf ! int 224 ; set multi-sector count to 128 147 0963 BA0000 mov dx,0 148 0966 B11ACDE0 mov cl,setdmaf ! int 224 ; set DMA offset to 0 149 096A 8B16EB0D mov dx,cldseg ; initial DMA segment 150 readit1: 151 096E 52 push dx ; save dma segment 152 096F B133CDE0 mov cl,setdmabf ! int 224 ; set DMA segment for disk IO 153 0973 BAC70D mov dx,offset ccpmfcb 154 0976 B114CDE0 mov cl,readsf ! int 224 ; next 128 sector read 155 097A 5A pop dx ; restore dma segment 156 097B 81C20004 add dx,8*128 ; increment dma segment 157 097F 3C01740A 098D cmp al,01H ! je done ; check for EOF 158 0983 3C0074E7 096E cmp al,0 ! je readit1 ; check for good write 159 0987 BA830D mov dx,offset rerr ; print READ ERROR message CP/M ASM86 1.1 SOURCE: LOAD.A86 CCP/M-86 Loader Program and BI PAGE 4 160 161 098A E91200 099F jmp stop 162 done: 163 098D E83800 09C8 call pcrlf ; and a crlf 164 165 0990 C706E90D0000 mov clen,0 ; set CCPM offset to 0 166 167 0996 8E1EF40D mov ds,dldseg ; CCP/M data segment 168 099A 2EFF2EE90D jmpf cs:dword ptr clen ; leap to CCPM initialization 169 170 ;***************************** 171 ;* 172 ;* subroutines 173 ;* 174 ;***************************** 175 176 stop: 177 ;---- 178 099F E82900 09CB call msg 179 09A2 FAF4 cli ! hlt 180 181 182 phex: ;print 4 hex characters from ax 183 ;---- 184 09A4 B90404 mov cx,0404h ; 4 in both CH and CL 185 lhex: 186 09A7 D3C0 rol ax,cl ; rotate left 4 187 09A9 5150 push cx ! push ax ; save crucial registers 188 09AB E80700 09B5 call pnib ; print hex nibble 189 09AE 5859 pop ax ! pop cx ; restore registers 190 09B0 FECD75F3 09A7 dec ch ! jnz lhex ; and loop four times 191 09B4 C3 ret 192 pnib: ;print low nibble in AL as hex char 193 09B5 240F3C09 and al,0fh ! cmp al,9 194 09B9 7704 09BF ja p10 ;above 9 ? 195 09BB 0430 add al,'0' ;digit 196 09BD EB02 09C1 jmps prn 197 09BF 0437 p10: add al,'A'-10 ;char a-e 198 09C1 8AD0 prn: mov dl,al 199 200 putchar: 201 ;------- 202 09C3 8ACA mov cl,dl 203 09C5 E92900 09F1 jmp io_conout 204 205 pcrlf: 206 ;----- 207 09C8 BAC40D mov dx,offset crlf ;print carriage return, line feed 208 209 msg: ;print msg starting at dx until $ 210 ;--- 211 09CB 8BDA mov bx,dx 212 msg1: CP/M ASM86 1.1 SOURCE: LOAD.A86 CCP/M-86 Loader Program and BI PAGE 5 213 214 09CD 8A17 mov dl,[bx] 215 09CF 80FA247408 09DC cmp dl,'$' ! je msg2 216 09D4 53 push bx 217 09D5 E8EBFF 09C3 call putchar 218 09D8 5B pop bx 219 09D9 43 inc bx 220 09DA EBF1 09CD jmps msg1 221 msg2: 222 09DC C3 ret 223 CP/M ASM86 1.1 SOURCE: LOAD.A86 CCP/M-86 Loader Program and BI PAGE 6 224 225 eject 226 ;************************************************************************ 227 ;* 228 ;* 229 ;* L O A D E R 230 ;* 231 ;* B I O S - 8 6 232 ;* ============= 233 ;* 234 ;* CP/M-86 3.0 or Concurrent CP/M-86 2.0 235 ;* 236 ;* Boot Loader I/O System 237 ;* for the 238 ;* IBM Personal Computer 239 ;* 240 ;* Copyright (c) 1982 241 ;* Digital Research, Inc. 242 ;* box 579, Pacific Grove 243 ;* California, 93950 244 ;* 245 ;* (Permission is hereby granted to use or 246 ;* abstract the following program in the 247 ;* implementation of Concurrent CP/M-86, 248 ;* CP/M, MP/M or CP/Net for the 8086 or 8088 249 ;* micro-processor.) 250 ;* 251 ;************************************************************************ 252 ;* 253 ;* Register usage for BIOS interface routines: 254 ;* 255 ;* Entry: AL = function # (in entry) 256 ;* CX = entry parameter 257 ;* DX = entry parameter 258 ;* DS = LDBDOS data segment 259 ;* 260 ;* Exit: AX = return 261 ;* BX = AX (in exit) 262 ;* ALL SEGMENT REGISTERS PRESERVED: 263 ;* CS,DS,ES,SS must be preserved though call 264 ;* 265 ;* Notes: flag set and the far jump to the dispatcher are 266 ;* the only legal Operating System "entry" points 267 ;* for an interrupt routine) 268 ;* 269 ;* changes have been made in the 270 ;* register conventions from 271 ;* the CP/M-86 BIOS and the MP/M-86 BIOS. 272 ;* 273 ;************************************************************************ 274 275 ;************************************************************************ 276 ;* * CP/M ASM86 1.1 SOURCE: LOAD.A86 CCP/M-86 Loader Program and BI PAGE 7 277 278 ;* IBM PC SOFTWARE INTERRUPT STRUCTURE * 279 ;* * 280 ;************************************************************************ 281 282 0008 tick_interrupt equ 08h 283 0009 keyboard_interrupt equ 09h 284 000E disk_interrupt equ 0Eh 285 00E0 os_interrupt equ 224 ;Loader BDOS entry 286 00E1 debugger_interrupt equ 225 ;debugger entry to O.S. 287 288 ;************************************************************************ 289 ;* * 290 ;* INTERFACE TO LOADER BDOS * 291 ;* * 292 ;************************************************************************ 293 294 ;===== 295 ;===== 296 entry: ;arrive here from JMP at 297 ;===== ;03H in BIOS code segment 298 ;===== 299 300 ; entry: AL = function number 301 ; CX, DX parameters 302 ; exit: AX = BX = return 303 ; ALL SEGMENT REGISTERS PRESERVED: 304 ; CS,DS,ES,SS must be preserved though call 305 306 ; Note: no alteration of stack is allowed during entry except 307 ; for the return address caused by the "call function_table[bx]" 308 ; instruction. 309 310 09DD FC cld ;set the direction flag 311 09DE 32E4 xor ah,ah 312 09E0 D0E0 shl al,1 ;multiply by 2 313 09E2 8BD8 mov bx,ax ;put in indirect register 314 09E4 FF97C50C call function_table[bx] ;no range checking needed 315 09E8 8BD8 mov bx,ax ;only called by loader BDOS 316 09EA CB retf ;return to loader BDOS 317 318 io_ret: 319 09EB C3 ret 320 321 ;------ 322 i_disk: 323 ;------ 324 09EC B020 mov al,pic_nseoi ;signal end of interrupt 325 09EE E620 out pic_even_port,al ;to 8259 326 09F0 CF iret ;note we destroyed AL 327 328 ;========= 329 io_conout: CP/M ASM86 1.1 SOURCE: LOAD.A86 CCP/M-86 Loader Program and BI PAGE 8 330 331 ;========= 332 ; entry: CL = character to output 333 ; DL = device number 334 ; exit: None 335 ; ALL SEGMENT REGISTERS PRESERVED: 336 ; CS,DS,ES,SS must be preserved though call 337 338 ; Put character in screen and update cursor position 339 ; BX = screen structure 340 341 09F1 BBE10C mov bx,offset ss0 342 09F4 8B3F mov di,ss_cursor[bx] ;cursor offset in bytes 343 09F6 80F90D cmp cl,cr 344 09F9 7423 0A1E je carriage_return 345 09FB 80F90A cmp cl,lf 346 09FE 7428 0A28 je linefeed 347 0A00 06 push es 348 0A01 B800B0 mov ax,bw_video_seg 349 0A04 8EC0 mov es,ax ;segment of foreground screen 350 0A06 8AC1 mov al,cl 351 0A08 B407 mov ah,07h ;default attribute 352 0A0A AB stosw ;update and don't touch the attribute 353 0A0B 07 pop es ;DI incremented by 2 354 0A0C 807F074F cmp ss_column[bx],columns_per_screen - 1 355 0A10 7506 0A18 jne inc_col 356 0A12 E80900 0A1E call carriage_return 357 0A15 E91000 0A28 jmp line_feed 358 inc_col: 359 0A18 FE4707 inc ss_column[bx] ;DI = next data, attribute 360 0A1B 893F mov ss_cursor[bx],di ;save new cursor position 361 0A1D C3 ret 362 363 ;--------------- 364 carriage_return: 365 ;--------------- 366 ; entry: BX = screen structure 367 ; exit: BX preserved 368 369 0A1E 33D2 xor dx,dx ;AX = 0 370 0A20 865707 xchg dl,ss_column[bx] ;set cursor position to begining of 371 0A23 D1E2 shl dx,1 ;times 2 for data and attribute 372 0A25 2917 sub ss_cursor[bx],dx ;set new cursor position 373 0A27 C3 ret 374 375 ;--------- 376 line_feed: 377 ;--------- 378 ; entry: BX = screen structure 379 ; exit: BX preserved 380 381 ; This routine assumes the loader will never 382 ; need to scroll the screen CP/M ASM86 1.1 SOURCE: LOAD.A86 CCP/M-86 Loader Program and BI PAGE 9 383 384 385 0A28 FE4706 inc ss_row[bx] 386 0A2B 8107A000 add ss_cursor[bx],columns_per_screen*2 387 0A2F C3 ret 388 389 390 ;************************************************************************ 391 ;* * 392 ;* 6845 CRT CONTROLLER PORT AND COMMAND EQUATES * 393 ;* * 394 ;************************************************************************ 395 396 397 ; The IBM PC's monochrome memory mapped video display begins 398 ; at paragraph 0B000H. It represents a screen 80 X 25. 399 ; Each video character requires a word value, the low byte 400 ; is the ASCII code (characters codes > 128 are also displayed) 401 ; and the high byte is an attribute byte. The 25th line 402 ; is reserved by this BIOS as a status line. 403 404 405 03B4 bw_card equ 003b4h 406 407 0029 video_on equ 00029h 408 0021 video_off equ 00021h 409 410 000A cursor_start equ 10 411 000B cursor_end equ 11 412 000C display_start_hi equ 12 413 000D display_start_low equ 13 414 000E cursor_hi equ 14 415 000F cursor_low equ 15 416 0010 light_pen_hi equ 16 417 0011 light_pen_low equ 17 418 419 420 ;************************************************************************ 421 ;* * 422 ;* SCREEN PARAMETERS * 423 ;* * 424 ;************************************************************************ 425 426 0018 rows_per_screen equ 24 427 0050 columns_per_screen equ 80 428 0780 screen_siz equ rows_per_screen * columns_per_screen 429 ;in words 430 B000 bw_video_seg equ 0b000h ;segment address of 431 ;start of video ram 432 0F00 bw_video_status_line equ screen_siz * 2 433 ;byte offset of status line 434 435 ;************************************************************************ CP/M ASM86 1.1 SOURCE: LOAD.A86 CCP/M-86 Loader Program and BI PAGE 10 436 437 ;* * 438 ;* SCREEN STRUCTURES * 439 ;* * 440 ;************************************************************************ 441 442 ; Each virtual console has a structure of the following 443 ; format associated with it. (SS = Screen Structure) 444 ; The data in this structure is dependent on the type of screen 445 ; supported and any escape sequence handling in io_conout. 446 ; Note: ss_cursor, ss_row, ss_column are relative to 0 and are 447 ; word pointers, i.e., if ss_cursor is 1 then it refers to 448 ; bytes 2 and 3 in the video RAM or a background screen's 449 ; data area. 450 451 0000 ss_cursor equ word ptr 0 ;points at data/attrib 452 0002 ss_escape equ word ptr ss_cursor + word ;escape routine to return to 453 0004 ss_screen_seg equ word ptr ss_escape + word ;data for screen image 454 0006 ss_row equ byte ptr ss_screen_seg + word ;current row 455 0007 ss_column equ byte ptr ss_row + byte ;current col 456 457 ; DISK I/O 458 ; -------- 459 460 ;************************************************************************ 461 ;* * 462 ;* 8237 DIRECT MEMORY ACCESS CONTROLLER PORT AND COMMANDS * 463 ;* * 464 ;************************************************************************ 465 466 0000 dma_c0_address equ 000h ;8237 channel 0 address rw 467 0001 dma_c0_count equ 001h ;8237 channel 0 transfer count rw 468 0002 dma_c1_address equ 002h ;8237 channel 1 address rw 469 0003 dma_c1_count equ 003h ;8237 channel 1 transfer count rw 470 0004 dma_c2_address equ 004h ;8237 channel 2 address rw 471 0005 dma_c2_count equ 005h ;8237 channel 2 transfer count rw 472 0006 dma_c3_address equ 006h ;8237 channel 3 address rw 473 0007 dma_c3_count equ 007h ;8237 channel 3 transfer count rw 474 0008 dma_stat_reg equ 008h ;8237 status register ro 475 0008 dma_cmd_reg equ dma_stat_reg ;8237 command register wo 476 0009 dma_requ_reg equ dma_stat_reg+1 ;8237 software dma request wo 477 000A dma_bmsk_reg equ dma_stat_reg+2 ;8237 binary channel mask wo 478 000B dma_mode_reg equ dma_stat_reg+3 ;8237 mode register wo 479 000C dma_cbpf equ dma_stat_reg+4 ;8237 clear byte pointer f/f wo 480 000D dma_temp_reg equ dma_stat_reg+5 ;8237 temporary register ro 481 000D dma_clear equ dma_stat_reg+5 ;8237 master clear wo 482 000F dma_mask_reg equ dma_stat_reg+7 ;8237 linear channel mask wo 483 484 0080 dma_page_c1 equ 080h ;a16 to a20 for channel 1 485 0081 dma_page_fdc equ 081h ;a16 to a20 for channel 2 486 0082 dma_page_c3 equ 082h ;a16 to a20 for channel 3 487 488 CP/M ASM86 1.1 SOURCE: LOAD.A86 CCP/M-86 Loader Program and BI PAGE 11 489 490 ; The following labels define single mode, address increment 491 ; auto-initialization disable, read or write using channel 2 492 493 004A dma_mode_write_fdc equ 01001010b 494 0046 dma_mode_read_fdc equ 01000110b 495 496 0002 dma_bmsk_fdc equ 00000010b ;binary channel mask for disk 497 498 499 ; DMA channel assignments 500 501 ;channel 0 dynamic memory refresh 502 ;channel 1 503 ;channel 2 floppy disk controller 504 ;channel 3 505 506 507 ;************************************************************************ 508 ;* * 509 ;* FLOPPY DISK DRIVER EQUATES * 510 ;* * 511 ;************************************************************************ 512 513 514 ; The following equates are set to the size of a double density, 515 ; single sided 5 & 1/4" floppy. 516 517 0200 bytes_per_sector equ 512 518 0008 sectors_per_track equ 8 ;1 to 8 519 1000 bytes_per_track equ sectors_per_track * bytes_per_sector 520 0028 tracks_per_disk equ 40 ;0 to 39 521 8000 bytes_per_disk equ tracks_per_disk * bytes_per_track 522 523 524 ; The following equates are for the INTEL 8272 Floppy Disk 525 ; Controller. 526 527 03F4 fdc_stat equ 03f4h ;status port for the disk controller 528 03F5 fdc_data equ fdc_stat+1 ;data port for the disk controller 529 03F2 fdc_port equ 03f2h ;all bits clear on channel reset 530 531 ;7 6 5 4 3 2 1 0 532 ;| | | | | | \_/ 533 ;| | | | | | | 534 ;| | | | | | drive select 00=a,01=b,10=c,11=d 535 ;| | | | | fdc reset* 536 ;| | | | int & dmarq enable 537 ;d c b a motor on 538 539 000C fdc_on equ 00001100b ;mask to keep the 8272 unreset 540 00FC fdc_no_motor equ 11111100b ;mask for no motors 541 0066 fdc_read_cmd equ 01100110b ;mfm, skip deleted data, read CP/M ASM86 1.1 SOURCE: LOAD.A86 CCP/M-86 Loader Program and BI PAGE 12 542 543 0045 fdc_write_cmd equ 01000101b ;mfm, write 544 004D fdc_format_cmd equ 01001101b ;mfm, format 545 000F fdc_seek_cmd equ 00001111b ;seek 546 0007 fdc_recal_cmd equ 00000111b ;home to track 0 547 0008 fdc_si_cmd equ 00001000b ;sense interupt status 548 0003 fdc_spec_cmd equ 00000011b ;specify 549 550 0080 fdc_ready equ 10000000b ;mask for transfer ready 551 552 00CF fdc_spec_1 equ 11001111b ;srt=0c, hd unload=0f first specify byte 553 0003 fdc_spec_2 equ 00000011b ;hd load=1, mode=DMA second specify byte 554 555 0002 f_bytes equ 2 ;magic number for 512 bytes per sector 556 0008 f_sectors equ 8 ;sectors per track 557 003A f_gap equ 03ah ;magic number for format gap 558 00E5 f_filler equ 0e5h ;fill character 559 560 0002 r_bytes equ 2 ;magic number for 512 bytes 561 0008 r_sectors equ 8 562 002A r_gap equ 02ah 563 00FF r_dtl equ 0ffh 564 565 ; Equates for paramter passing for read and write from the 566 ; BDOS. 567 568 ; At the disk read and write function entries, 569 ; all disk I/O parameters are on the stack. 570 ; The stack at these entries appears as 571 ; follows: 572 ; 573 ; +-------+-------+ 574 ; +14 | DRV | MCNT | Drive and Multi sector count 575 ; +-------+-------+ 576 ; +12 | TRACK | Track number 577 ; +-------+-------+ 578 ; +10 | SECTOR | Physical sector number 579 ; +-------+-------+ 580 ; +8 | DMA_SEG | DMA segment 581 ; +-------+-------+ 582 ; +6 | DMA_OFF | DMA offset 583 ; +-------+-------+ 584 ; +4 | RET_SEG | BDOS return segment 585 ; +-------+-------+ 586 ; +2 | RET_OFF | BDOS return offset 587 ; +-------+-------+ 588 ; SP+0 | RET_ADR | Return address to BIOS ENTRY routine 589 ; +-------+-------+ 590 ; 591 ; These parameters may be indexed and modifided 592 ; directly on the stack by the BIOS read and write rotines 593 ; They will be removed by the BDOS when the BIOS completes 594 ; the read/write function and returns to the BDOS. CP/M ASM86 1.1 SOURCE: LOAD.A86 CCP/M-86 Loader Program and BI PAGE 13 595 596 597 598 000E drive equ byte ptr 14[bp] 599 000F mcnt equ byte ptr 15[bp] 600 000C track equ word ptr 12[bp] 601 000A sector equ word ptr 10[bp] 602 0008 dma_seg equ word ptr 8[bp] 603 0006 dma_off equ word ptr 6[bp] 604 605 606 ; Some equtes in the Disk Parameter Header (DPH) 607 ; and the Disk Parameter Block. 608 609 0000 xlt equ 0 ;translation table offset in DPH 610 0008 dpb equ 8 ;disk parameter block offset in DPH 611 0000 spt equ 0 ;sectors per track offset in DPB 612 000F psh equ 15 ;physical shift factor offset in DPB 613 614 615 ;************************************************************************ 616 ;* * 617 ;* DISK DRIVER ROUTINES * 618 ;* * 619 ;************************************************************************ 620 621 622 ;========= 623 io_seldsk: ; Function 7: Select Disk 624 ;========= 625 ; entry: CL = disk to be selected 626 ; DL = 00h if disk has not been previously selected 627 ; = 01h if disk has been previously selected 628 ; exit: AX = 0 if illegal disk 629 ; = offset of DPH relative from 630 ; BIOS Data Segment 631 ; ALL SEGMENT REGISTERS PRESERVED: 632 ; CS,DS,ES,SS must be preserved though call 633 634 0A30 33C0 xor ax,ax ;get ready for error(s) 635 0A32 80F900 cmp cl,0 ;is it a A: ? 636 0A35 7503 0A3A jne sel_ret ;if not just exit 637 0A37 B8090D mov ax,offset dph0 638 sel_ret: 639 0A3A C3 ret 640 641 ;======= 642 io_read: ; Function 11: Read sector 643 ;======= 644 ; Reads the sector on the current disk, track and 645 ; sector into the current DMA buffer. 646 647 ; entry: parameters on stack CP/M ASM86 1.1 SOURCE: LOAD.A86 CCP/M-86 Loader Program and BI PAGE 14 648 649 ; exit: AL = 00 if no error occured 650 ; AL = 01 if an error occured 651 ; AL = 0ffh if density change detected 652 ; ALL SEGMENT REGISTERS PRESERVED: 653 ; CS,DS,ES,SS must be preserved though call 654 655 0A3B 8BEC mov bp,sp ;set BP for indexing into IOPB 656 ; mov dma_mode_storage,dma_mode_read_fdc 657 ; mov fdc_rw_cmd,fdc_read_cmd ;loader always reads 658 0A3D E80700 0A47 call flp_io 659 0A40 B001 mov al,1 660 0A42 7502 0A46 jnz i_read_ret ;zero flag is set with successful 661 0A44 FEC8 dec al ;I/O 662 i_read_ret: 663 0A46 C3 ret 664 665 flp_io: 666 ;------ 667 ; entry: parameters on stack 668 ; exit: zero flag set if no error 669 670 0A47 B80800 mov ax,sectors_per_track;max sectors - starting sector = 671 0A4A 2B460A sub ax,sector ;sectors left on track 672 0A4D 32FF xor bh,bh 673 0A4F 8A5E0F mov bl,mcnt ;multi sector count is byte variable 674 0A52 3BC3 cmp ax,bx ;sectors left on track, sectors requested 675 0A54 7603 0A59 jbe flp_track ;transfer to end of track 676 0A56 8A460F mov al,mcnt ;transfer to before end of track 677 678 flp_track: 679 0A59 28460F sub mcnt,al ;AL = # sectors to R/W on this iteration 680 ;through FLP_IO, 681 0A5C A2040D mov track_mcnt,al ;sectors to R/W on current track 682 683 ;check for 64K page overlap 684 0A5F 8AE0 mov ah,al ;shl al,8 (* 256) 685 0A61 32C0 xor al,al 686 0A63 D0E4 shl ah,1 ;* 512 687 0A65 50 push ax ;how many bytes to R/W on cur trk 688 689 0A66 8B4608 mov ax,dma_seg ;compute new 20 bit DMA addr 690 0A69 8B5E06 mov bx,dma_off 691 0A6C E89400 0B03 call comp_dma ;returns AX = low 16 bits of 20 bit adr 692 0A6F F7D0 not ax ;how many bytes left in this 64K page 693 694 0A71 5B pop bx ;BX=bytes to R/W on current track 695 0A72 3BC3 cmp ax,bx ;does this transfer fit in 64K page 696 0A74 7203 0A79 jb flp_end_64K 697 0A76 E95D00 0AD6 jmp flp_pg_ok 698 699 flp_end_64K: 700 ;read to end of 64K page and then CP/M ASM86 1.1 SOURCE: LOAD.A86 CCP/M-86 Loader Program and BI PAGE 15 701 702 ;read spanning sector locally 703 0A79 8AC4 mov al,ah ;how many sectors fit in this page ? 704 0A7B 32E4 xor ah,ah ;bytes left in 64K page 705 0A7D D1E8 shr ax,1 ;divided by 512 706 0A7F 85C0 test ax,ax ;if 0, no sectors fit 707 0A81 741E 0AA1 jz flp_rwlocal ;in the rest of this 64K page 708 709 0A83 A2030D mov num_sec,al ;sectors that fit in end 64K page 710 0A86 2806040D sub track_mcnt,al ;track_mcnt always > AL 711 0A8A E88E00 0B1B call flp_phys_io ;read/write them, DMA already computed 712 0A8D 7403 0A92 jz flp_end64k_ok 713 0A8F E97000 0B02 jmp flp_ret ;return if zero reset on error 714 715 flp_end64K_ok: 716 0A92 33C0 xor ax,ax 717 0A94 A0030D mov al,num_sec ;compute new DMA offset 718 0A97 01460A add sector,ax ;still on the same track 719 0A9A 86E0 xchg ah,al ;shl ax,8 (* 256) 720 0A9C D0E4 shl ah,1 ;* bytes_per_sector (512) 721 0A9E 014606 add dma_off,ax ;64K wrap around is legal 722 723 flp_rwlocal: ;read into BIOS data segment the spanning 724 0AA1 BB7010 mov bx,local_buf ;sector 725 0AA4 8CD8 mov ax,ds ;compute 20 bit local DMA addr 726 0AA6 E85A00 0B03 call comp_dma 727 ; cmp fdc_rw_cmd,fdc_read_cmd ;loader always reads 728 ; ;only need this for writes 729 730 ; ;reading or writing ? 731 ; je flp_local 732 ; mov si,dma_off ;get the sector to write from local 733 ; mov di,local_buf ;buffer 734 ; push es ! push ds ! push ds ! pop es 735 ; mov ax,dma_seg ! mov ds,ax 736 ; mov cx,bytes_per_sector/2 737 ; rep movsw 738 ; pop ds ! pop es 739 ; mov dma_off,si ;update DMA offset 740 ; 741 ;flp_local: 742 743 0AA9 C606030D01 mov num_sec,1 ;read/write one sector 744 0AAE E86A00 0B1B call flp_phys_io 745 0AB1 754F 0B02 jnz flp_ret ;return zero flag reset 746 0AB3 FF460AFE0E04 inc sector ! dec track_mcnt 747 0D 748 749 ; cmp fdc_rw_cmd,fdc_read_cmd ;loader always reads 750 ; jne flp_local_done 751 752 0ABA 8B7E06 mov di,dma_off ;move the sector to user's area 753 0ABD BE7010 mov si,local_buf ;if reading CP/M ASM86 1.1 SOURCE: LOAD.A86 CCP/M-86 Loader Program and BI PAGE 16 754 755 0AC0 068E4608 push es ! mov es,dma_seg 756 0AC4 B90001 mov cx,bytes_per_sector/2 757 0AC7 F3A5 rep movsw 758 0AC9 897E06 mov dma_off,di ;update DMA offset 759 0ACC 07 pop es 760 761 flp_local_done: 762 0ACD 8B4608 mov ax,dma_seg ;compute new 20 bit DMA addr 763 0AD0 8B5E06 mov bx,dma_off ;for next FDC read/write 764 0AD3 E82D00 0B03 call comp_dma 765 766 flp_pg_ok: ;read will not cross 64K boundary 767 0AD6 A0040D mov al,track_mcnt ;could be 0 if we just read locally 768 0AD9 84C07413 0AF0 test al,al ! jz nxt_track 769 0ADD A2030D mov num_sec,al ;read the rest from this track 770 0AE0 E83800 0B1B call flp_phys_io ;DMA is already computed 771 0AE3 751D 0B02 jnz flp_ret ;return zero flag reset on error 772 0AE5 33C0 xor ax,ax 773 0AE7 8A26030D mov ah,num_sec ;shl num_sec,8 (* 256) 774 0AEB D0E4 shl ah,1 ;* 512 775 0AED 014606 add dma_off,ax 776 777 nxt_track: 778 0AF0 32C0 xor al,al 779 0AF2 38460F cmp mcnt,al 780 0AF5 740B 0B02 jz flp_ret ;return successful with zero flag set 781 0AF7 FF460C inc track 782 0AFA C7460A0000 mov sector,0 783 0AFF E945FF 0A47 jmp flp_io 784 flp_ret: 785 0B02 C3 ret 786 787 comp_dma: ;Compute 20 bit address from offset, segment 788 ;-------- 789 790 ; entry: AX = segment 791 ; BX = offset 792 ; exit: AX = low 16 bits 793 ; CH = highest 4 bits of address, always less then 16 - 794 ; no megabyte wrap around 795 ; 796 ; The BIOS variables DMA_LOW16 and DMA_HIGH4 are 797 ; set by this routine. These variables are transferred 798 ; to the floppy disk controller by the routine DMA_SET_UP. 799 800 0B03 B104D3C0 mov cl,4 ! rol ax,cl ;make paragraphs into bytes 801 0B07 8AE824F0 mov ch,al ! and al,0f0h ;save high 4 bits, 0 low 4 bits 802 0B0B 03C3 add ax,bx ;add byte offset 803 0B0D 80D50080E50F adc ch,0 ! and ch,0fh ;add in the carry, page is less than 804 0B13 A3050D mov dma_low16,ax ;16 805 0B16 882E070D mov dma_high4,ch 806 0B1A C3 ret CP/M ASM86 1.1 SOURCE: LOAD.A86 CCP/M-86 Loader Program and BI PAGE 17 807 808 809 flp_phys_io: 810 ;----------- 811 ; entry: num_sec = number of sectors to read in this 812 ; operation 813 ; disk parameters on the stack 814 ; exit: zero flag set if ok 815 816 ; Perform physical actions to read/write floppy diskette 817 818 0B1B C606F10C02 mov d_a_number,r_bytes 819 0B20 C606F20C08 mov d_a_eot,r_sectors 820 0B25 C606F30C2A mov d_a_gpl,r_gap 821 0B2A C606F40CFF mov d_a_dtl,r_dtl 822 823 0B2F E82700 0B59 call motor_and_recal ;make sure motor is on 824 0B32 C606EA0C05 mov recals,max_recals 825 recal_loop: 826 0B37 C606E90C03 mov retries,max_retries 827 retry_loop: 828 0B3C E85000 0B8F call seek 829 0B3F E89100 0BD3 call dma_setup 830 0B42 E8B700 0BFC call fdc_read_write 831 0B45 7411 0B58 jz phys_ret ;if errors 832 0B47 FE0EE90C dec retries ;attempt retries 833 0B4B 75EF 0B3C jnz retry_loop 834 0B4D E82800 0B78 call recal 835 0B50 FE0EEA0C dec recals 836 0B54 75E1 0B37 jnz recal_loop 837 0B56 0C01 or al,1 ;reset zero flag 838 phys_ret: ;and return error 839 0B58 C3 ret 840 841 motor_and_recal: 842 ;--------------- 843 ; entry: none 844 ; exit: none 845 846 ; Turn on the motor if off. Also do RECAL operation if 847 ; motor is off. Note: loader does not turn off the motor. 848 849 0B59 B010 mov al,010h ;pick up a bit for motor a 850 0B5B 8A4E0E mov cl,drive ;fetch the binary drive code 851 0B5E D2E0 shl al,cl ;make it a bit for motor x 852 0B60 8A26080D mov ah,motor_flags ;fetch the motor bits 853 0B64 84E0 test ah,al ;check to see if its on 854 0B66 750F 0B77 jnz motor_on_done ;yes then leap 855 0B68 0C0C or al,fdc_on ;mask in the no reset,enable interupt 856 0B6A 0A460E or al,drive ;mask in the drive 857 0B6D A2080D mov motor_flags,al ;save for later 858 0B70 BAF203 mov dx,fdc_port ;point to the port number 859 0B73 EE out dx,al ;select & motor on CP/M ASM86 1.1 SOURCE: LOAD.A86 CCP/M-86 Loader Program and BI PAGE 18 860 861 0B74 E80100 0B78 call recal ;back to track zero 862 motor_on_done: ;when we first turn on the motor 863 0B77 C3 ret 864 865 recal: 866 ;----- 867 ; entry: none 868 ; exit: none 869 870 ; Move the head to home on the selected disk drive. 871 872 0B78 C606EB0C02 mov disk_arguments,2 ;specify number of arguments 873 0B7D C606EC0C07 mov d_a_command,fdc_recal_cmd 874 0B82 8A460E mov al,drive ;get current disk 875 0B85 A2ED0C mov d_a_drive,al ;set up the command block 876 0B88 E8A400 0C2F call fdc_command_put ;go send the command block 877 0B8B F4 hlt ;wait for FDC interrupt 878 0B8C E98A00 0C19 jmp sense_interrupt ;required after RECAL command 879 ;ret 880 881 seek: 882 ;---- 883 ; entry: TRACK to seek to on the stack relative to BP 884 ; exit: none 885 886 0B8F C606EB0C03 mov disk_arguments,3 ;request 3 byte command transfer 887 0B94 C606EC0C0F mov d_a_command,fdc_seek_cmd 888 0B99 32DB xor bl,bl ;select head 0 889 0B9B 8B460C mov ax,track ;get track off stack 890 0B9E 3C28 cmp al,40 ;test for off side 1 891 0BA0 7208 0BAA jb side_ok ;if single sided then leap 892 0BA2 B301 mov bl,1 ;else get a head 1 893 0BA4 B44F mov ah,79 ;else get back track bias 894 0BA6 2AE0 sub ah,al ;compute new track number 895 0BA8 86E0 xchg ah,al ;and get it into al 896 side_ok: 897 0BAA 881EEF0C mov d_a_head,bl ;set up the head 898 0BAE 02DB add bl,bl ;multiply by 2 899 0BB0 02DB add bl,bl ;multiply by 4 900 0BB2 A2EE0C mov d_a_cylinder,al ;set up the track number 901 0BB5 0A5E0E or bl,drive ;bits 0,1 are drive number 902 0BB8 881EED0C mov d_a_drive,bl ;set up disk number 903 0BBC 8B460A mov ax,sector ;get sector off stack 904 0BBF 40 inc ax ;sectors are relative to 1 905 0BC0 A2F00C mov d_a_record,al ;and set it up 906 0BC3 0206030D add al,num_sec ;compute new end of track 907 0BC7 FEC8 dec al 908 0BC9 A2F20C mov d_a_eot,al ;save it 909 0BCC E86000 0C2F call fdc_command_put ;send the command block 910 0BCF F4 hlt ;wait for FDC interrupt 911 0BD0 E94600 0C19 jmp sense_interrupt ;required after SEEK command 912 ;ret CP/M ASM86 1.1 SOURCE: LOAD.A86 CCP/M-86 Loader Program and BI PAGE 19 913 914 915 dma_setup: 916 ;--------- 917 ; entry: DMA_MODE_STORAGE, DMA_LOW16, DMA_HIGH4 set up 918 ; exit: none 919 920 ; Set the DMA device up for a read/write operation. 921 ; The current DMA command word must in DMA_MODE_STORAGE. 922 ; DMA_LOW16 and DMA_HIGH4 are the twenty bit starting address. 923 ; The read/write operation cannot cross a physical 64K boundary. 924 925 0BD3 E60C out dma_cbpf,al ;reset the byte pointer 926 927 0BD5 A0020D mov al,dma_mode_storage ;get the mode byte 928 0BD8 E60B out dma_mode_reg,al ;set the mode 929 0BDA A1050D mov ax,dma_low16 ;low 16 bits of 20 bit DMA address 930 0BDD E604 out dma_c2_address,al ;send low 8 bits 931 0BDF 8AC4 mov al,ah 932 0BE1 E604 out dma_c2_address,al ;send next 8 bits 933 0BE3 A0070D mov al,dma_high4 ;high 4 bits of 20 bit DMA address 934 0BE6 E681 out dma_page_fdc,al 935 0BE8 33C0 xor ax,ax 936 0BEA 8A26030D mov ah,num_sec ;shl num_sec,8 (* 256) 937 0BEE D0E4 shl ah,1 ;*512 938 0BF0 48 dec ax ;0 relative 939 0BF1 E605 out dma_c2_count,al ;set up the low byte 940 0BF3 8AC4 mov al,ah ;get the low byte 941 0BF5 E605 out dma_c2_count,al ;and the high byte 942 0BF7 B002 mov al,dma_bmsk_fdc ;get the binary channel mask 943 0BF9 E60A out dma_bmsk_reg,al ;enable the disk channel 944 0BFB C3 ret 945 946 fdc_read_write: 947 ;-------------- 948 949 ; entry: DMA device set up, head positioned on correct 950 ; track 951 ; exit: zero flag set if successful 952 953 ; Send read or write command to 8272 FDC 954 955 0BFC C606EB0C09 mov disk_arguments,9 ;9 byte command for read or write 956 0C01 A0010D mov al,fdc_rw_cmd ;get read or write command 957 0C04 A2EC0C mov d_a_command,al ;put it in the command string 958 0C07 E82500 0C2F call fdc_command_put ;send the command to the FDC 959 0C0A F4 hlt ;wait for FDC interrupt 960 0C0B C606F50C07 mov disk_results,7 ;7 byte result transfer 961 0C10 E83400 0C47 call fdc_status_get ;get the result bytes 962 0C13 F606F60CC0 test d_r_st0,0C0H ;test status register 0 963 0C18 C3 ret ;return zero flag set on success 964 965 sense_interrupt: CP/M ASM86 1.1 SOURCE: LOAD.A86 CCP/M-86 Loader Program and BI PAGE 20 966 967 ;--------------- 968 ; Sense interrupt command on the FDC. It is called 969 ; after a recal or a seek to test for seek complete. 970 971 0C19 C606EB0C01 mov disk_arguments,1 ;only one byte of command 972 0C1E C606EC0C08 mov d_a_command,fdc_si_cmd ;sense interrupt commmand 973 0C23 E80900 0C2F call fdc_command_put ;send the command to the FDC 974 0C26 C606F50C02 mov disk_results,2 ;2 bytes are returned 975 0C2B E81900 0C47 call fdc_status_get ;get the 2 result bytes 976 0C2E C3 ret 977 978 fdc_command_put: 979 ;--------------- 980 ; entry: DISK_ARGUMENT array set up 981 ; exit: none 982 983 ; Send the command block in the DISK_ARGUMENTS table to 984 ; the 8272 FDC. 985 ; The number of commands to write to the FDC is the 986 ; first item in the table. 987 988 0C2F BAF403 mov dx,fdc_stat ;point to the i/o port 989 0C32 BEEB0C mov si,offset disk_arguments ;point to the table of arguments 990 0C35 FC cld ;make sure we go forward 991 0C36 AC lodsb ;get the length of the arguments table 992 0C37 8AC8 mov cl,al ;get it into the count register 993 0C39 2AED sub ch,ch ;zero the high byte 994 995 fdc_command_loop: 996 0C3B EC in al,dx ;get the current control byte 997 0C3C A880 test al,fdc_ready ;if not ok to send next byte 998 0C3E 74FB 0C3B jz fdc_command_loop ;then loop waiting 999 0C40 42 inc dx ;point at the data port 1000 0C41 AC lodsb ;else get the byte to send 1001 0C42 EE out dx,al ;send it 1002 0C43 4A dec dx ;point back at the status port 1003 0C44 E2F5 0C3B loop fdc_command_loop ;if not last byte then loop 1004 0C46 C3 ret ;else were all done 1005 1006 fdc_status_get: 1007 ;-------------- 1008 ; entry: number of results in 1st byte of DISK_RESULTS array 1009 ; exit: none 1010 1011 ; Get the status information from the 8272 1012 ; FDC and place them in the table at DISK_RESULTS. 1013 ; The first byte in the table is the number of results 1014 ; to read from the FDC 1015 1016 0C47 06 push es ;save UDA 1017 0C48 BAF403 mov dx,fdc_stat ;point at the status port 1018 0C4B 8CD8 mov ax,ds ;get our data segment CP/M ASM86 1.1 SOURCE: LOAD.A86 CCP/M-86 Loader Program and BI PAGE 21 1019 1020 0C4D 8EC0 mov es,ax ;into the extra segment 1021 0C4F BFF60C mov di,offset disk_results + 1 ;point to where to put the data 1022 0C52 FC cld ;make sure we go forward 1023 0C53 8A0EF50C mov cl,disk_results ;fetch the number of expected results 1024 0C57 2AED sub ch,ch ;zero the high byte 1025 1026 fdc_status_loop: 1027 0C59 EC in al,dx ;get the current control byte 1028 0C5A A880 test al,fdc_ready ;if not ok to read next byte 1029 0C5C 74FB 0C59 jz fdc_status_loop ;then loop waiting 1030 0C5E 42 inc dx ;point at the data port 1031 0C5F EC in al,dx ;get the byte 1032 0C60 AA stosb ;put it in the structure 1033 0C61 4A dec dx ;point back at the status port 1034 0C62 E2F5 0C59 loop fdc_status_loop ;if not last then loop 1035 0C64 07 pop es ;restore UDA 1036 0C65 C3 ret ;else return 1037 1038 1039 1040 ; INIT ROUTINE 1041 1042 ;************************************************************************ 1043 ;* * 1044 ;* 8259 PROGRAMMABLE INTERRUPT CONTROLLER COMMANDS * 1045 ;* AND PORTS * 1046 ;* * 1047 ;************************************************************************ 1048 1049 0020 pic_even_port equ 020h ;port 0 1050 0021 pic_odd_port equ 021h ;bit 0 is A0 of 8259 instructions 1051 1052 0020 pic_nseoi equ 020h ;non specific end of interupt 1053 1054 ;************************************************************************ 1055 ;* * 1056 ;* BIOS INITIALIZATION ROUTINE * 1057 ;* * 1058 ;************************************************************************ 1059 1060 ;track buffer 1061 0012 memory_size equ 12h ;ROM interrupt to get memory size 1062 0011 equipment equ 11h ;ROM interrupt to get equipment word 1063 1064 ; The following routine is used to initialize any required 1065 ; data areas and alter any peripheral chip programming when 1066 ; starting up CCP/M-86. This code is called once from the 1067 ; SUP(ERVISOR) after calling the SUP has called the RTM, 1068 ; RTM, CIO, MEM, BDOS initialization routines and before the 1069 ; SUP has created the RSP processes. 1070 ; This code can be placed in an BIOS data area if the BIOS is 1071 ; 8080 model (mixed code and data). Usually, overlaying the CP/M ASM86 1.1 SOURCE: LOAD.A86 CCP/M-86 Loader Program and BI PAGE 22 1072 1073 ; initialization code with a data area is done after the BIOS 1074 ; has been debugged. 1075 1076 1077 ;==== 1078 ;==== 1079 init: ;arrive here from the JMP 1080 ;==== ;at 0 in BIOS code segment 1081 ;==== 1082 1083 0C66 FAFC cli ! cld ;Supervisor restores DS,ES and int 1084 ;224 after on INIT call 1085 1086 ; Disk I/O initialization 1087 1088 1089 set_up_interrupts: 1090 0C68 B0BD mov al,10111101b ;enable diskette and keyboard 1091 0C6A E621 out pic_odd_port,al ;interrupts only 1092 ;and mask off the rest 1093 1094 ; mov disk_arguments,3 ;send specify command to the 1095 ; mov d_a_command,fdc_spec_cmd ;FDC (Intel 8272 or NEC 765) 1096 ; mov d_a_drive,0d0h ;step rate=3ms, head unload=0ms 1097 ; mov d_a_cylinder,20h ;head load=2ms, DMA mode true 1098 ; call fdc_command_put ;head unload and head load times 1099 ;are meaningless on mini floppies 1100 ;where the head is loaded 1101 ;when the motor is turned on 1102 1103 0C6C 8CD8 mov ax,ds 1104 0C6E 01064E0D add data_buf_seg,ax ;fix up data buffer segment 1105 1106 0C72 0633C0 push es ! xor ax,ax 1107 0C75 8EC0 mov es,ax 1108 0C77 BF3800 mov di,disk_interrupt*4 ;point at vector location 1109 0C7A B8EC09 mov ax,offset i_disk 1110 0C7D AB stosw ;save and inc DI 1111 0C7E 8CC8 mov ax,cs 1112 0C80 AB stosw 1113 0C81 07 pop es 1114 1115 set_up_video: 1116 0C82 BAB403 mov dx,bw_card ;get the video chip port 1117 0C85 BEB50C mov si,offset bw_table ;initialization commands 1118 0C88 B91000 mov cx,length bw_table ;how many commands 1119 0C8B E81300 0CA1 call video_init ;send commands to port 1120 ;color board is similar ... 1121 0C8E 06 push es 1122 0C8F BF00B0 mov di,bw_video_seg ;clear the video RAM 1123 0C92 8EC7 mov es,di 1124 0C94 33FF xor di,di CP/M ASM86 1.1 SOURCE: LOAD.A86 CCP/M-86 Loader Program and BI PAGE 23 1125 1126 0C96 B9D007 mov cx,screen_siz + columns_per_screen 1127 ;screen length in words plus 1128 ;status line 1129 0C99 B82007 mov ax,0720h ;7 = default attribute 1130 ;20 = ASCII space 1131 0C9C F3AB rep stosw 1132 0C9E 07 pop es 1133 1134 0C9F FB sti 1135 0CA0 CB retf ;initializaiton done 1136 1137 ;---------- 1138 video_init: 1139 ;---------- 1140 0CA1 32DB xor bl,bl 1141 video_init_l: 1142 0CA3 8AC3FEC3 mov al,bl ! inc bl 1143 0CA7 EE42 out dx,al ! inc dx 1144 0CA9 ACEE lodsb ! out dx,al 1145 0CAB 4A dec dx ! 1146 0CAC E2F5 0CA3 loop video_init_l 1147 0CAE 83C204 add dx,4 1148 0CB1 B029 mov al,video_on 1149 0CB3 EE out dx,al 1150 0CB4 C3 ret 1151 1152 1153 0CB5 last_code_offset equ offset $ 1154 DSEG 1155 ORG last_code_offset 1156 1157 ; Loader BIOS data 1158 1159 0CB5 6150520F1906 bw_table db 61h,50h,52h,0fh,19h,06h,19h,19h,02h,0dh,0bh,0ch,0,0,0,0 1160 1919020D0B0C 1161 00000000 1162 1163 function_table: 1164 0CC5 EB09 dw io_ret ; 0 console status 1165 0CC7 EB09 dw io_ret ; 1 console input 1166 0CC9 F109 dw io_conout ; 2 console output 1167 0CCB EB09 dw io_ret ; 3 list status 1168 0CCD EB09 dw io_ret ; 4 list output 1169 0CCF EB09 dw io_ret ; 5 auxillary input 1170 0CD1 EB09 dw io_ret ; 6 auxillary out 1171 0CD3 EB09 dw io_ret ; 7 switch screen 1172 0CD5 EB09 dw io_ret ; 8 update or print new status 1173 0CD7 300A dw io_seldsk ; 9 select disk 1174 0CD9 3B0A dw io_read ;10 read logical sector 1175 0CDB EB09 dw io_ret ;11 write logical sector 1176 0CDD EB09 dw io_ret ;12 flush buffers 1177 0CDF EB09 dw io_ret ;13 poll device CP/M ASM86 1.1 SOURCE: LOAD.A86 CCP/M-86 Loader Program and BI PAGE 24 1178 1179 1180 1181 ;short screen structure 1182 ;for IO_CONOUT 1183 1184 0CE1 000000000000 ss0 dw 0,0,0 ;cursor, escape, screen_seg 1185 0CE7 0000 db 0,0 ;row,column 1186 1187 1188 ; Floppy Disk Driver data 1189 1190 1191 0003 max_retries equ 3 1192 0CE9 00 retries db 0 ;retry counter 1193 0005 max_recals equ 5 1194 0CEA 00 recals db 0 1195 1196 ; The following 2 tables are used to issue commands to, 1197 ; and read results from the 8272 FDC. The first entry 1198 ; in each table is the number of bytes to send or receive 1199 ; from the device 1200 1201 0CEB 00 disk_arguments db 0 ;number of arguments to send 1202 0CEC 00 d_a_command db 0 ;command read/write 1203 0CED 00 d_a_drive db 0 ;drive select & head select 1204 0CEE 00 d_a_cylinder db 0 ;cylinder to read/write 1205 0CEF 00 d_a_head db 0 ;head 1206 0CF0 00 d_a_record db 0 ;sector 1207 0CF1 02 d_a_number db 2 ;magic number for 512 bytes/sector 1208 0CF2 08 d_a_eot db sectors_per_track ;end of track sector number 1209 0CF3 2A d_a_gpl db 02ah ;inter sector gap length 1210 0CF4 FF d_a_dtl db 0ffh ;data length 1211 1212 0CF5 00 disk_results db 0 ;number of bytes to read 1213 0CF6 00 d_r_st0 db 0 ;status byte 0 1214 0CF7 00 d_r_st1 db 0 ;status byte 1 1215 0CF8 00 d_r_st2 db 0 ;status byte 2 1216 0CF9 00 d_r_cylinder db 0 ;cylinder we are on now 1217 0CFA 00 d_r_head db 0 1218 0CFB 00 d_r_record db 0 1219 0CFC 00 d_r_number db 0 ;number of sectors read 1220 1221 0CFD 00 f_a_bytes db 0 1222 0CFE 00 f_a_sectors db 0 1223 0CFF 00 f_a_gap db 0 1224 0D00 00 f_a_filler db 0 1225 1226 0D01 66 fdc_rw_cmd db fdc_read_cmd ;read or write command 1227 0D02 46 dma_mode_storage db dma_mode_read_fdc 1228 1229 0D03 01 num_sec db 1 ;num sectors to read/write 1230 ;in one call to controller CP/M ASM86 1.1 SOURCE: LOAD.A86 CCP/M-86 Loader Program and BI PAGE 25 1231 1232 1233 0D04 track_mcnt rb 1 ;multi sector count on 1234 ;current track 1235 0D05 dma_low16 rw 1 ;20 bit address storage 1236 0D07 dma_high4 rb 1 1237 1238 0D08 00 motor_flags db 0 ;last state of the motor bits 1239 1240 ; Disk Parameter Header 1241 1242 0D09 0000 dph0 dw 0 ;translate table 1243 0D0B 000000000000 dw 0,0,0 ;scratch area 1244 0D11 1D0D dw dpb0 ;dsk parm block 1245 0D13 0000 dw 0 ;check 1246 0D15 0000 dw 0 ;alloc vectors 1247 0D17 2E0D dw dir_bcb_hdr ;dir buff cntrl blk 1248 0D19 410D dw data_bcb_hdr ;data buff cntrl blk 1249 0D1B 0000 dw 0 ;hash table segment 1250 1251 ; Disk Parameter Block 1252 1253 0D1D 0800 dpb0 dw 8 ;sectors per track 1254 0D1F 03 db 3 ;block shift 1255 0D20 07 db 7 ;block mask 1256 0D21 00 db 0 ;extnt mask 1257 0D22 9B00 dw 155 ;disk size in 1k blocks 1258 ;less offset track(s) 1259 0D24 3F00 dw 63 ;directory max 1260 0D26 C0 db 11000000b ;alloc0 1261 0D27 00 db 0 ;alloc1 1262 0D28 1000 dw 16 ;check size 1263 0D2A 0100 dw 1 ;offset 1264 0D2C 02 db 2 ;phys sec shift 1265 0D2D 03 db 3 ;phys sec mask 1266 1267 0D2E 310D dir_bcb_hdr dw dir_bcb 1268 0D30 01 db 1 1269 1270 0D31 FF dir_bcb db 0ffh ;drive 1271 0D32 000000 db 0,0,0 ;record 1272 0D35 0000 db 0,0 ;wflg,seg 1273 0D37 00000000 dw 0,0 ;track,sector 1274 0D3B 700E dir_buf_off dw dir_buf ;buffer offset 1275 0D3D 00000000 dw 0,0 ;link,pdadr 1276 1277 0D41 440D data_bcb_hdr dw data_bcb 1278 0D43 01 db 1 1279 1280 0D44 FF data_bcb db 0ffh ;drive 1281 0D45 000000 db 0,0,0 ;record 1282 0D48 0000 db 0,0 ;wflg,seg 1283 0D4A 00000000 dw 0,0 ;track,sector CP/M ASM86 1.1 SOURCE: LOAD.A86 CCP/M-86 Loader Program and BI PAGE 26 1284 1285 0D4E 2701 data_buf_seg dw data_buf;buffer segment, fixed up by LBIOS init: 1286 0D50 00000000 dw 0,0 ;link,pdadr 1287 1288 1289 ; Loader Program data 1290 1291 0D54 4343502F4D2D signon db 'CCP/M-86 Loader 2.0$' 1292 3836204C6F61 1293 64657220322E 1294 3024 1295 0D68 0D0A4E6F2043 nofile db cr,lf,'No CCPM.SYS File On Disk$' 1296 43504D2E5359 1297 532046696C65 1298 204F6E204469 1299 736B24 1300 0D83 0D0A4572726F rerr db cr,lf,'Error Reading CCPM.SYS$' 1301 722052656164 1302 696E67204343 1303 504D2E535953 1304 24 1305 0D9C 0D0A436F6465 csegment db cr,lf,'Code Paragraph = $' 1306 205061726167 1307 72617068203D 1308 2024 1309 0DB0 0D0A44617461 dsegment db cr,lf,'Data Paragraph = $' 1310 205061726167 1311 72617068203D 1312 2024 1313 0DC4 0D0A24 crlf db cr,lf,'$' 1314 1315 0DC7 014343504D20 ccpmfcb db 1,'CCPM ','SYS',0,0,0,0 1316 202020535953 1317 00000000 1318 0DD7 000000000000 db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 1319 000000000000 1320 00000000 1321 1322 0DE7 00 db 0 1323 1324 1325 ; Note the Loader Program and Loader BIOS uninitialized 1326 ; data areas are combined to save space. 1327 1328 ; Unitialized data for Loader Program 1329 1330 ;read first CMD header of 1331 ;CCPM.SYS file here 1332 0DE8 ctype rb 1 ;type 1333 0DE9 clen rw 1 ;length 1334 0DEB cldseg rw 1 ;abs 1335 0DED cmin rw 1 ;minimum 1336 0DEF cmax rw 1 ;maximum CP/M ASM86 1.1 SOURCE: LOAD.A86 CCP/M-86 Loader Program and BI PAGE 27 1337 1338 0DF1 dtype rb 1 1339 0DF2 dlen rw 1 1340 0DF4 dldseg rw 1 1341 0DF6 dmin rw 1 1342 0DF8 dmax rw 1 1343 1344 org offset ctype 1345 0DE8 sec1 rb 128 ;reserve space for the sector 1346 1347 1348 ; Unitialized data for Loader BIOS 1349 1350 1351 0E70 dir_buf equ ((offset $) + 15) and 0fff0h 1352 1353 ; Sector for reads that span 64K boundaries; 1354 ; this sector can not cross a 64K boundary 1355 1356 1070 local_buf equ dir_buf + 512 1357 1358 0127 data_buf equ (local_buf + 512)/16 1359 1360 1361 END OF ASSEMBLY. NUMBER OF ERRORS: 0. USE FACTOR: 16% CP/M ASM86 1.1 SOURCE: LOAD.A86 CCP/M-86 Loader Program and BI PAGE 028 BWCARD 03B4 N 405# 1116 BWTABLE 0CB5 V 1117 1118 1159# BWVIDEOSEG B000 N 348 430# 1122 BWVIDEOSTATUSLIN 0F00 N 432# BYTESPERDISK 8000 N 521# BYTESPERSECTOR 0200 N 517# 519 756 BYTESPERTRACK 1000 N 519# 521 CARRIAGERETURN 0A1E L 344 356 364# CCPMFCB 0DC7 V 99 115 153 1315# CLDSEG 0DEB V 138 149 1334# CLEN 0DE9 V 165 168 1333# CMAX 0DEF V 1336# CMIN 0DED V 1335# CODETYPE 0001 N 57# COLUMNSPERSCREEN 0050 N 354 386 427# 428 1126 COMPDMA 0B03 L 691 726 764 787# CR 000D N 50# 343 1295 1300 1305 1309 1313 CRLF 0DC4 V 207 1313# CS SREG V 168 1111 CSEGMENT 0D9C V 136 1305# CTYPE 0DE8 V 1332# 1344 CURSOREND 000B N 411# CURSORHI 000E N 414# CURSORLOW 000F N 415# CURSORSTART 000A N 410# DACOMMAND 0CEC V 873 887 957 972 1202# DACYLINDER 0CEE V 900 1204# DADRIVE 0CED V 875 902 1203# DADTL 0CF4 V 821 1210# DAEOT 0CF2 V 819 908 1208# DAGPL 0CF3 V 820 1209# DAHEAD 0CEF V 897 1205# DANUMBER 0CF1 V 818 1207# DARECORD 0CF0 V 905 1206# DATABCB 0D44 V 1277 1280# DATABCBHDR 0D41 V 1248 1277# DATABUF 0127 N 1285 1358# DATABUFSEG 0D4E V 1104 1285# DATATYPE 0002 N 58# DEBUGGERINTERRUP 00E1 N 286# DIRBCB 0D31 V 1267 1270# DIRBCBHDR 0D2E V 1247 1267# DIRBUF 0E70 N 1274 1351# 1356 DIRBUFOFF 0D3B V 1274# DISKARGUMENTS 0CEB V 872 886 955 971 989 1201# DISKINTERRUPT 000E N 284# 1108 DISKRESULTS 0CF5 V 960 974 1021 1023 1212# DISPLAYSTARTHI 000C N 412# DISPLAYSTARTLOW 000D N 413# DLDSEG 0DF4 V 142 167 1340# DLEN 0DF2 V 1339# DMABMSKFDC 0002 N 496# 942 DMABMSKREG 000A N 477# 943 CP/M ASM86 1.1 SOURCE: LOAD.A86 CCP/M-86 Loader Program and BI PAGE 029 DMAC0ADDRESS 0000 N 466# DMAC0COUNT 0001 N 467# DMAC1ADDRESS 0002 N 468# DMAC1COUNT 0003 N 469# DMAC2ADDRESS 0004 N 470# 930 932 DMAC2COUNT 0005 N 471# 939 941 DMAC3ADDRESS 0006 N 472# DMAC3COUNT 0007 N 473# DMACBPF 000C N 479# 925 DMACLEAR 000D N 481# DMACMDREG 0008 N 475# DMAHIGH4 0D07 V 805 933 1236# DMALOW16 0D05 V 804 929 1235# DMAMASKREG 000F N 482# DMAMODEREADFDC 0046 N 494# 1227 DMAMODEREG 000B N 478# 928 DMAMODESTORAGE 0D02 V 927 1227# DMAMODEWRITEFDC 004A N 493# DMAOFF 0006 V 603# 690 721 752 758 763 775 DMAPAGEC1 0080 N 484# DMAPAGEC3 0082 N 486# DMAPAGEFDC 0081 N 485# 934 DMAREQUREG 0009 N 476# DMASEG 0008 V 602# 689 755 762 DMASETUP 0BD3 L 829 915# DMASTATREG 0008 N 474# 475 476 477 478 479 480 481 482 DMATEMPREG 000D N 480# DMAX 0DF8 V 1342# DMIN 0DF6 V 1341# DONE 098D L 157 162# DPB 0008 N 610# DPB0 0D1D V 1244 1253# DPH0 0D09 V 637 1242# DRCYLINDER 0CF9 V 1216# DRHEAD 0CFA V 1217# DRIVE 000E V 598# 850 856 874 901 DRNUMBER 0CFC V 1219# DRRECORD 0CFB V 1218# DRST0 0CF6 V 962 1213# DRST1 0CF7 V 1214# DRST2 0CF8 V 1215# DS SREG V 105 167 725 1018 1103 DSEGMENT 0DB0 V 140 1309# DTYPE 0DF1 V 1338# ENTRY 09DD L 81 296# EQUIPMENT 0011 N 1062# ES SREG V 347 349 353 755 755 759 1016 1020 1035 1106 1107 1113 1121 1123 1132 FABYTES 0CFD V 1221# FAFILLER 0D00 V 1224# FAGAP 0CFF V 1223# FALSE 0000 N 47# 48 FASECTORS 0CFE V 1222# CP/M ASM86 1.1 SOURCE: LOAD.A86 CCP/M-86 Loader Program and BI PAGE 030 FBYTES 0002 N 555# FDCCOMMANDLOOP 0C3B L 995# 998 1003 FDCCOMMANDPUT 0C2F L 876 909 958 973 978# FDCDATA 03F5 N 528# FDCFORMATCMD 004D N 544# FDCNOMOTOR 00FC N 540# FDCON 000C N 539# 855 FDCPORT 03F2 N 529# 858 FDCREADCMD 0066 N 541# 1226 FDCREADWRITE 0BFC L 830 946# FDCREADY 0080 N 550# 997 1028 FDCRECALCMD 0007 N 546# 873 FDCRWCMD 0D01 V 956 1226# FDCSEEKCMD 000F N 545# 887 FDCSICMD 0008 N 547# 972 FDCSPEC1 00CF N 552# FDCSPEC2 0003 N 553# FDCSPECCMD 0003 N 548# FDCSTAT 03F4 N 527# 528 988 1017 FDCSTATUSGET 0C47 L 961 975 1006# FDCSTATUSLOOP 0C59 L 1026# 1029 1034 FDCWRITECMD 0045 N 543# FFILLER 00E5 N 558# FGAP 003A N 557# FLPEND64K 0A79 L 696 699# FLPEND64KOK 0A92 L 712 715# FLPIO 0A47 L 658 665# 783 FLPLOCALDONE 0ACD L 761# FLPPGOK 0AD6 L 697 766# FLPPHYSIO 0B1B L 711 744 770 809# FLPRET 0B02 L 713 745 771 780 784# FLPRWLOCAL 0AA1 L 707 723# FLPTRACK 0A59 L 675 678# FSECTORS 0008 N 556# FUNCTIONTABLE 0CC5 L 314 1163# IDISK 09EC L 322# 1109 INCCOL 0A18 L 355 358# INIT 0C66 L 80 1079# IOCONOUT 09F1 L 203 329# 1166 IOREAD 0A3B L 642# 1174 IORET 09EB L 318# 1164 1165 1167 1168 1169 1170 1171 1172 1175 1176 1177 IOSELDSK 0A30 L 623# 1173 IREADRET 0A46 L 660 662# KEYBOARDINTERRUP 0009 N 283# LASTCODEOFFSET 0CB5 N 1153# 1155 LDBDOSOFFSET 0000 N 53# LDROFFSET 0900 N 55# 78 LDUSR 0909 V 84# 96 LF 000A N 51# 345 1295 1300 1305 1309 1313 LHEX 09A7 L 185# 190 LIGHTPENHI 0010 N 416# LIGHTPENLOW 0011 N 417# CP/M ASM86 1.1 SOURCE: LOAD.A86 CCP/M-86 Loader Program and BI PAGE 031 LINEFEED 0A28 L 346 357 376# LOADP 090A L 82 87# LOCALBUF 1070 N 724 753 1356# 1358 MAXRECALS 0005 N 824 1193# MAXRETRIES 0003 N 826 1191# MCNT 000F V 599# 673 676 679 779 MEMORYSIZE 0012 N 1061# MOTORANDRECAL 0B59 L 823 841# MOTORFLAGS 0D08 V 852 857 1238# MOTORONDONE 0B77 L 854 862# MSG 09CB L 94 137 141 178 209# MSG1 09CD L 212# 220 MSG2 09DC L 215 221# NOFILE 0D68 V 102 1295# NUMSEC 0D03 V 709 717 743 769 773 906 936 1229# NXTTRACK 0AF0 L 768 777# OPENF 000F N 63# 100 OSINTERRUPT 00E0 N 285# P10 09BF L 194 197# PCRLF 09C8 L 163 205# PERR 092A L 101 104# PHEX 09A4 L 139 143 182# PHYSRET 0B58 L 831 838# PICEVENPORT 0020 N 325 1049# PICNSEOI 0020 N 324 1052# PICODDPORT 0021 N 1050# 1091 PNIB 09B5 L 188 192# PRN 09C1 L 196 198# PSH 000F N 612# PUTCHAR 09C3 L 200# 217 RBYTES 0002 N 560# 818 RDTL 00FF N 563# 821 READIT1 096E L 150# 158 READSF 0014 N 64# 116 154 RECAL 0B78 L 834 861 865# RECALLOOP 0B37 L 825# 836 RECALS 0CEA V 824 835 1194# RERR 0D83 V 159 1300# RETRIES 0CE9 V 826 832 1192# RETRYLOOP 0B3C L 827# 833 RGAP 002A N 562# 820 ROWSPERSCREEN 0018 N 426# 428 RSECTORS 0008 N 561# 819 SCREENSIZ 0780 N 428# 432 1126 SEC1 0DE8 V 109 1345# SECTOR 000A V 601# 671 718 746 782 903 SECTORSPERTRACK 0008 N 518# 519 670 1208 SEEK 0B8F L 828 881# SELDSKF 000E N 62# SELRET 0A3A L 636 638# SENSEINTERRUPT 0C19 L 878 911 965# SETDMABF 0033 N 68# 106 152 SETDMAF 001A N 65# 110 148 CP/M ASM86 1.1 SOURCE: LOAD.A86 CCP/M-86 Loader Program and BI PAGE 032 SETMULTCNTF 002C N 67# 113 146 SETUPINTERRUPTS 0C68 L 1089# SETUPVIDEO 0C82 L 1115# SETUSERF 0020 N 66# 97 SIDEOK 0BAA L 891 896# SIGNON 0D54 V 93 1291# SPT 0000 N 611# SS SREG V SS0 0CE1 V 341 1184# SSCOLUMN 0007 N 354 359 370 455# SSCURSOR 0000 N 342 360 372 386 451# 452 SSESCAPE 0002 N 452# 453 SSROW 0006 N 385 454# 455 SSSCREENSEG 0004 N 453# 454 STOP 099F L 103 161 176# TICKINTERRUPT 0008 N 282# TRACK 000C V 600# 781 889 TRACKMCNT 0D04 V 681 710 746 767 1233# TRACKSPERDISK 0028 N 520# 521 TRUE FFFF N 48# VIDEOINIT 0CA1 L 1119 1138# VIDEOINITL 0CA3 L 1141# 1146 VIDEOOFF 0021 N 408# VIDEOON 0029 N 407# 1148 XLT 0000 N 609#