;--------------------------------------------------------------------- ; LOADCPM.ASM (FOR CAL-PC MSDOS 2.11 - ASSEMBLE USING A86.COM) ; 28-10-88 ; STEPHEN HUNT ;--------------------------------------------------------------------- ; 28-12-89 ; Modified to attempt to open the CPM.SYS file in the root directory ; if it could not be found in the current directory ;--------------------------------------------------------------------- ; cr equ 0dh ; carriage return lf equ 0ah ; line feed eof equ 01ah ; end of file marker ; dos equ 21h ; ;--------------------------------------------------------------------- ; jump to start of code ;--------------------------------------------------------------------- ; loadcpm: ; jmp start ; db 'LOADCPM version 1.1 Copyright (C) Stephen Hunt' db eof ; ;--------------------------------------------------------------------- ; tell 'em what were up to ;--------------------------------------------------------------------- ; start: ; mov dx,offset loading call print_string ; ;--------------------------------------------------------------------- ; open the CPM.SYS file ;--------------------------------------------------------------------- ; mov dx,offset cpm_sys+1 ; assume 'CPM.SYS' call open_cpm ; open file jnc read_cpm_sys ; ok - continue ; mov dx,offset cpm_sys ; assume '\CPM.SYS' call open_cpm ; open file jnc read_cpm_sys ; ok - continue ; mov dx,offset err_open ; 'cannot find CPM.SYS' jmp error_exit ; exit with error ;--------------------------------------------------------------------- ; read the CPM.SYS file (upto 32k bytes, usually only 16k bytes) ;--------------------------------------------------------------------- ; read_cpm_sys: ; mov bx,word ptr cpm_hnd mov dx,offset cpm_buf mov cx,32768 mov ah,03fh int dos ; read 32768 bytes of CPM.SYS ; mov word ptr cpm_siz,ax ; store number of bytes read ; pushf ; save read error status call closecpm ; close CPM.SYS file popf ; restore read error status ; jnc check_header ; continue if read successful ; mov dx,offset err_read ; 'error reading CPM.SYS' jmp error_exit ; exit with error ;--------------------------------------------------------------------- ; check that the CPM.SYS header record is valid ;--------------------------------------------------------------------- ; check_header: ; cmp word ptr cpm_siz,0 ; q. was anything read ? jz check_header_err ; no - error ; mov si,offset cpm_buf cmp byte ptr 0[si],1 ; q. code segment group type present ? jnz check_header_err ; no - error ; mov ax,word ptr 1[si] ; get group length in paragraphs mov dx,010h mul dx ; convert to length in bytes mov word ptr cpm_len,ax ; and store it ; mov bx,word ptr cpm_siz cmp bx,ax ; q. file size greater than code length ? jb check_header_err ; no - error ; sub bx,080h ; subtract length of header record sub bx,ax ; then the code length cmp bx,080h ; q. (file size less header) more than ; ; 128 bytes larger than code length ? jae check_header_err ; yes - error ; cmp word ptr 3[si],0 ; q. base segment defined ? jz check_header_err ; no - error ; mov ax,word ptr 1[si] cmp ax,word ptr 5[si] ; q. code length equal minimum length ? jnz check_header_err ; no - error ; cmp word ptr 7[si],0 ; q. maximum length defined ? jnz check_header_err ; yes - error ; add si,9 ; point to next group descriptor mov cx,128 -9 cld ; check_header_loop: ; cmp byte ptr 0[si],0 ; q. any more descriptors defined ? jnz check_header_err ; yes - error loop check_header_loop ; loop until finished ; jmp reset_int3 ; reset int 3 vector ; check_header_err: ; mov dx,offset err_head ; 'invalid CPM.SYS header' jmp error_exit ; exit with error ;--------------------------------------------------------------------- ; reset interrupt 3 to use the prom interrupt 3 routine (FC00:32BE). ;--------------------------------------------------------------------- ; reset_int3: ; push ds mov dx,0fc00h ; segment FC00h mov ds,dx mov dx,032beh ; offset 32BEh mov al,3 mov ah,025h int dos ; reset int 3 pop ds ;--------------------------------------------------------------------- ; relocate cpm image, set segment registers and jump to it. ;--------------------------------------------------------------------- ; move_cpm: ; mov ax,word ptr cpm_buf +3 mov es,ax ; es points to cpm segment ; mov si,offset cpm_buf +080h xor di,di ; set source + destination pointers ; mov cx,word ptr cpm_len ; set length of code to move ; cld ; clear the direction flag cli ; plus the interrupt flag ; rep movsb ; move it !!!! ; mov ds,ax push ax ; push cpm segment address on stack mov ax,02500h push ax ; push bios cold boot address on stack ; retf ; return far to CPM-86 !!! ;--------------------------------------------------------------------- ; Subroutines ;--------------------------------------------------------------------- ; Open CPM.SYS file ;--------------------------------------------------------------------- ; open_cpm: ; xor al,al mov ah,03dh int dos ; open CPM.SYS file mov word ptr cpm_hnd,ax ; save file handle ; ret ;--------------------------------------------------------------------- ; Close CPM.SYS file ;--------------------------------------------------------------------- ; close_cpm: ; mov bx,word ptr cpm_hnd mov ah,03eh int dos ; close CPM.SYS file ; ret ;--------------------------------------------------------------------- ; print string at offset dx ;--------------------------------------------------------------------- ; print_string: ; mov ah,09h int dos ; print string ; ret ;--------------------------------------------------------------------- ; print string and exit ;--------------------------------------------------------------------- ; error_exit: ; call print_string mov ah,04ch xor al,al int dos ; return to dos ; ;--------------------------------------------------------------------- ; data ;--------------------------------------------------------------------- ; loading db cr,lf,'Loading CP/M-86 $' ; err_open db cr,lf,lf,'Unable to open CPM.SYS',cr,lf,'$' err_read db cr,lf,lf,'Error reading CPM.SYS',cr,lf,'$' err_head db cr,lf,lf,'Invalid CPM.SYS header',cr,lf,'$' ; cpm_sys db '\CPM.SYS',0 ; asciiz file name cpm_hnd dw 0 ; file handle cpm_siz dw 0 ; file size cpm_len dw 0 ; code length ; cpm_buf db 32768 dup (0) ; cpm.sys load buffer ; db 0 ; spare ; ;--------------------------------------------------------------------- ; ;--------------------------------------------------------------------- ; end