mirror of
https://github.com/SEPPDROID/Digital-Research-Source-Code.git
synced 2025-10-25 09:24:19 +00:00
912 lines
22 KiB
Plaintext
912 lines
22 KiB
Plaintext
eject ; Dec 13, 1983
|
||
; INIT
|
||
; ----
|
||
|
||
;************************************************
|
||
;* *
|
||
;* IBM PC SOFTWARE INTERRUPT STRUCTURE *
|
||
;* *
|
||
;************************************************
|
||
|
||
divide_interrupt equ 00h
|
||
single_step_interrupt equ 01h
|
||
nmi_interrupt equ 02h
|
||
one_byte_interrupt equ 03h
|
||
overflow_interrupt equ 04h
|
||
clock_interrupt equ 08h
|
||
keyboard_interrupt equ 09h
|
||
hd_hard_interrupt equ 0Dh
|
||
disk_interrupt equ 0Eh
|
||
|
||
equip_int equ 11h ; ROS equipment check int
|
||
mem_int equ 12h ; ROS memory check int
|
||
disk_int equ 13h ; ROS disk int
|
||
async_int equ 14h ; ROS async port int
|
||
print_int equ 17h ; ROS printer int
|
||
|
||
tick_interrupt equ 1Ch ; user tick vector
|
||
hd_code_interrupt equ 40h ; pass along to floppy
|
||
hd_param_interrupt equ 41h ; hard disk param pointer
|
||
os_interrupt equ 224 ; normal CCP/M-86 entry
|
||
debugger_interrupt equ 225 ; debugger entry to O.S.
|
||
flag_interrupt equ 228 ; to get an unused flag
|
||
fidds_interrupt equ 229 ; for attachamatic drives
|
||
xios_interrupt equ 230 ; for ver 1.0 back door
|
||
|
||
|
||
;********************************************************
|
||
;* *
|
||
;* XIOS INITIALIZATION ROUTINE *
|
||
;* *
|
||
;********************************************************
|
||
|
||
; The following routine is used to initialize any required
|
||
; data areas, and alter any peripheral chip programming when
|
||
; starting up CCP/M-86. This code is called once from the
|
||
; SUP(ERVISOR) after the SUP has called the RTM, CIO, MEM and
|
||
; BDOS initialization routines, and before SUP has created
|
||
; the RSP processes. Tests indicate that the DL register is
|
||
; preserved from the boot until INIT is entered, and this is
|
||
; used to pass the ROS code for the boot disk, which lets the
|
||
; INIT routine know where to look for SETUP data. This is,
|
||
; however a very undocumented feature, and may at some later
|
||
; date change, leaving SETUP high and dry. So now you know.
|
||
|
||
reorg16 equ offset $
|
||
cseg
|
||
org reorg16
|
||
|
||
INIT:
|
||
cli
|
||
call set_sys_vars ; set up system variables
|
||
call equip_check ; see what we've got
|
||
call check_hi_mem ; from C000 up
|
||
call ndp_init ; check for an 8087
|
||
call compaq ; do before any video setup
|
||
call fix_crt ; mono/color vs_ variables
|
||
call fix_disk_tables ; match disk tables to equip
|
||
call printer_init ; reset the parallel printers
|
||
call do_video ; initial window setup
|
||
call hd_init ; get hard disk partitions
|
||
call do_setup ; customize XIOS
|
||
call flop_off ; turn off the floppy motors
|
||
call try_mdisk ; done after setup data read
|
||
call trim_memory ; fix up the partition list
|
||
call do_config ; initial serial port init
|
||
call do_interrupts ; do all of the int stuff
|
||
call sign_on ; print signon message
|
||
retf ; initializaiton done
|
||
|
||
|
||
; set up initial system variables
|
||
|
||
set_sys_vars:
|
||
cld ;Sup saves DS,ES on INIT call
|
||
mov sysdat,ds ;save System Data Segment
|
||
mov bx,offset supmod ;save Sup entry double word
|
||
mov ax,[bx] ;get offset out of Sys Data Seg
|
||
mov cs:supervisor_o,ax ;save it
|
||
mov ax,2[bx] ;get the segment
|
||
mov cs:supervisor_s,ax ;save it
|
||
mov tod_hour,0 ;start with zero time
|
||
mov tod_day,0890h ;Jan 1, 1984
|
||
mov boot_disk,dl ;ros code for booter
|
||
ret
|
||
|
||
|
||
; check IBM equipment word, set number variables
|
||
|
||
equip_check:
|
||
int equip_int ; return equip word
|
||
mov dx,ax
|
||
|
||
mov cl,4
|
||
shr dx,cl ; shift down init_video
|
||
mov al,dl
|
||
and al,03h
|
||
mov init_video_mode,al ; save for crt setup
|
||
|
||
mov cl,2
|
||
shr dx,cl ; shift down floppy bits
|
||
mov ax,dx
|
||
and ax,03h ; mask for floppy
|
||
inc ax ; correct 0 based code
|
||
mov num_flop,ax
|
||
|
||
mov cl,3
|
||
shr dx,cl ; shift down port bits
|
||
mov ax,dx
|
||
and ax,07h ; mask for serial ports
|
||
mov num_port,ax
|
||
|
||
mov cl,5
|
||
shr dx,cl ; shift down printer bits
|
||
mov ax,dx
|
||
and ax,03h ; mask for printer
|
||
mov num_print,ax
|
||
|
||
mov ah,08 ; XT param check
|
||
mov dl,80h ; first hard disk code
|
||
int disk_int
|
||
jnc equip_ch1 ; skip if dl good
|
||
mov dl,0 ; else no hard disks
|
||
equip_ch1:
|
||
mov dh,0
|
||
mov num_hard,dx
|
||
|
||
mov bx,0ffeh ; off the screen
|
||
mov ax,mono_seg
|
||
call crt_check ; is the monochrome there?
|
||
mov num_mono,ax ; store the count 0 or 1
|
||
|
||
mov ax,color_seg
|
||
call crt_check ; is the color card there?
|
||
mov num_color,ax ; store the count 0 or 1
|
||
|
||
int mem_int ; check total memory size
|
||
mov num_mmkb,ax ; save kilobytes
|
||
mov cl,6
|
||
shl ax,cl ; change to paragraph count
|
||
mov memory_top,ax ; save for memory trim
|
||
mov lo_mem_top,ax ; keep a permanent copy
|
||
ret
|
||
|
||
; do a memory check on the crt ram
|
||
|
||
crt_check:
|
||
mov es,ax ; crt segment
|
||
mov ax,0DDB2h ; bit pattern
|
||
mov es:[bx],ax ; store it
|
||
sub ax,es:[bx] ; check it
|
||
jnz crt_chk1 ; and skip if not there
|
||
|
||
mov ax,blank ; once more for
|
||
mov es:[bx],ax ; good measure
|
||
sub ax,es:[bx]
|
||
jnz crt_chk1
|
||
|
||
inc ax ; only one
|
||
ret
|
||
crt_chk1:
|
||
sub ax,ax ; nobody home
|
||
ret
|
||
|
||
|
||
; Check for memory at or above C000:0000
|
||
|
||
check_hi_mem:
|
||
mov dx,0C000h ; starting segment
|
||
mov cx,12 ; 16k block count
|
||
mov ax,0DDB2h ; check pattern
|
||
ch_hi_mem1:
|
||
call ch_hi_word ; is there RAM ?
|
||
jz ch_hi_mem2 ; if so, skip
|
||
add dx,400h ; check next 16k
|
||
loop ch_hi_mem1 ; up to F000
|
||
ret ; if none there, return
|
||
|
||
ch_hi_mem2:
|
||
mov hi_mem_start,dx ; there is some memory
|
||
ch_hi_mem3:
|
||
add dx,400h ; up 16k
|
||
call ch_hi_word ; as long as it's good
|
||
jz ch_hi_mem3 ; keep on going
|
||
mov hi_mem_top,dx ; and save the top
|
||
ret
|
||
|
||
ch_hi_word:
|
||
sub si,si ; zero index
|
||
mov es,dx ; set check segment
|
||
mov es:[si],ax ; store check pattern
|
||
cmp es:[si],ax ; and see if it matches
|
||
ret ; return with zf set
|
||
|
||
|
||
; 8087 Numeric Data Processor initiation routine
|
||
|
||
ndp_init:
|
||
FNINIT ; init and check for 8087
|
||
xor ax,ax ; stall for time
|
||
mov ndp_control,ax ; and clear control word
|
||
FNSTCW ndp_control ; get 8087 control word
|
||
or ax,ndp_control ; test for 8087 presence
|
||
jz ndp_init_done ; if not there, skip
|
||
|
||
mov num_ndp,1 ; we've got one!
|
||
mov owner_8087,0 ; tell the system about it
|
||
|
||
mov ndp_int_off,nmi_interrupt * 4
|
||
mov ndp_int_seg,0 ; save the vector location
|
||
mov ndp_vec_off,offset i_ndp
|
||
mov ndp_vec_seg,cs ; and the interrupt vector
|
||
ndp_init_done:
|
||
ret
|
||
|
||
|
||
; if this is the compaq, change cursor, sync and sl_attrib
|
||
|
||
compaq:
|
||
mov ax,0F000h
|
||
mov es,ax ; ROM segment
|
||
mov di,0FFEAh ; ID offset
|
||
mov si,offset compaq_name
|
||
mov cx,6
|
||
repz cmpsb ; look for a match
|
||
jnz compaq_done
|
||
|
||
mov var_cursor,compaq_cursor
|
||
mov var_sync,0 ; no retrace sync
|
||
mov sl_attrib,0Fh ; enhanced white
|
||
mov alpha_str,offset compaq_str
|
||
compaq_done:
|
||
ret ; all for now
|
||
|
||
compaq_name db 'COMPAQ'
|
||
|
||
|
||
; set up the mono/color vs_ variables
|
||
|
||
fix_crt:
|
||
mov si,offset set_mono ; assume monochrome
|
||
mov di,offset z_sl_mono ; for status line too
|
||
cmp init_video_mode,03h ; if mono switched on
|
||
jz fix_crt1 ; then skip
|
||
|
||
mov si,offset set_color ; else color
|
||
mov di,offset z_sl_color ; and color status
|
||
fix_crt1:
|
||
call di ; set status line
|
||
mov dl,0 ; first vc number
|
||
fix_crt2:
|
||
call point_vs ; bx -> structure
|
||
call si ; mono or color
|
||
inc dl ; next vc
|
||
cmp dl,num_vir_cons ; through the last
|
||
jb fix_crt2
|
||
ret
|
||
|
||
|
||
; correct the disk tables to match physical configuration
|
||
|
||
fix_disk_tables:
|
||
mov ax,num_flop ; actual number of floppies
|
||
dec ax
|
||
mov sys_disk,al ; system disk = top flop
|
||
mov temp_disk,al ; tempory disk too
|
||
inc ax
|
||
shl al,1 ; convert to word index
|
||
mov di,ax ; point to first non-floppy
|
||
|
||
cmp num_hard,0 ; if no hard disks
|
||
jz fix_disk1 ; then skip
|
||
|
||
mov ax,offset hd_dph0 ; first hard dph
|
||
call fix_one_disk ; fix dph and jump tables
|
||
|
||
cmp num_hard,1 ; if only one hard disk
|
||
jz fix_disk1 ; then skip
|
||
|
||
mov ax,offset hd_dph1 ; second hard dph
|
||
call fix_one_disk ; fix dph and jump tables
|
||
fix_disk1:
|
||
mov dph_tbl[di],0 ; zero the extra entries
|
||
mov select_tbl[di],offset sel_fid
|
||
mov read_tbl[di],offset read_fid
|
||
mov write_tbl[di],offset write_fid
|
||
|
||
inc di
|
||
inc di ; two bytes per entry
|
||
cmp di,12 ; zap up to F:
|
||
jb fix_disk1
|
||
ret
|
||
|
||
; correct table entries for one hard disk
|
||
|
||
fix_one_disk:
|
||
mov dph_tbl[di],ax ; set dph
|
||
mov select_tbl[di],offset select_hd
|
||
mov read_tbl[di],offset read_hd
|
||
mov write_tbl[di],offset write_hd
|
||
inc di
|
||
inc di ; to next entry
|
||
ret
|
||
|
||
|
||
; reset all parallel printer ports
|
||
; set up list_out and list_stat tables
|
||
|
||
printer_init:
|
||
mov cx,num_print ; get the count
|
||
jcxz pr_par_done
|
||
|
||
sub dx,dx ; first is zero
|
||
pr_par_loop1:
|
||
mov ah,1 ; reset code
|
||
int print_int
|
||
inc dx ; next printer
|
||
loop pr_par_loop1
|
||
|
||
mov ax,40h ; look into base page
|
||
mov es,ax
|
||
mov si,8 ; printer address list
|
||
mov cx,num_print ; printer count
|
||
pr_par_loop2:
|
||
push cx
|
||
mov ax,es:[si] ; fetch printer address
|
||
mov di,-2 ; pre decrement for scan
|
||
mov cx,3 ; max printer count
|
||
pr_par_loop3:
|
||
inc di ; to next list data
|
||
inc di
|
||
cmp ax,list_data[di] ; if no match
|
||
loopnz pr_par_loop3 ; then keep looking
|
||
jnz pr_par_next ; until exausted
|
||
|
||
mov list_out[di],offset parallel_out
|
||
mov list_stat[di],offset parallel_stat
|
||
pr_par_next:
|
||
inc si
|
||
inc si ; next list entry
|
||
pop cx
|
||
loop pr_par_loop2
|
||
|
||
pr_par_done:
|
||
mov cx,num_port ; number of serial ports
|
||
jcxz pr_init_done ; skip if none
|
||
|
||
mov si,6 ; first serial index
|
||
pr_ser_loop:
|
||
mov list_out[si],offset serial_init
|
||
inc si ; stat needs nothing
|
||
inc si
|
||
loop pr_ser_loop ; 1 or 2 times
|
||
pr_init_done:
|
||
ret
|
||
|
||
|
||
; get all of the window stuff rolling
|
||
|
||
do_video:
|
||
cmp init_video_mode,03h ; if initial crt is mono
|
||
jz do_color ; then skip port init
|
||
mov dx,mono_port ; get the video chip port
|
||
mov si,offset mono_table ; initialization commands
|
||
mov ax,0029h ; video mode / color sel
|
||
call video_init ; send commands to port
|
||
do_color:
|
||
cmp init_video_mode,03h ; if initial crt is color
|
||
jnz init_v0 ; then skip port init
|
||
mov dx,color_port
|
||
mov si,offset color_table
|
||
mov ax,0029h ; video mode / color sel
|
||
call video_init
|
||
|
||
; Set up the virtual screen structures (one per virtual console)
|
||
; and blank out their screen save areas.
|
||
init_v0:
|
||
mov ax,genccpm_buf ;paragraph address of buffer
|
||
;space allocated by GENCCPM.
|
||
mov bx,offset first_vs
|
||
mov cx,num_vir_cons
|
||
init_v1:
|
||
mov vs_vc_seg,ax ; tell each vs_ where to find
|
||
add bx,size_vs ; its buffer segment
|
||
add ax,((crt_size+15) shr 4) * 2 ; segment size
|
||
loop init_v1
|
||
mov vc_map_seg,ax ; ownership map segment
|
||
|
||
mov es,ax ; now set up the initial map
|
||
sub di,di ; top left corner
|
||
mov cx,crt_size
|
||
mov al,(1 shl num_vir_cons)-1 ; all bits on
|
||
cld
|
||
rep stosb ; fill the map
|
||
;
|
||
mov bx,offset first_vs
|
||
mov cx,num_vir_cons
|
||
init_v2:
|
||
push cx
|
||
mov es,vs_vc_seg ; point to image
|
||
sub di,di
|
||
mov cx,crt_size
|
||
mov ax,blank ; to erase virtual images
|
||
rep stosw ; fill with blanks
|
||
pop cx
|
||
add bx,size_vs ; next virtual structure
|
||
loop init_v2
|
||
|
||
push ds
|
||
pop es ; local extra segment
|
||
mov di,offset vc_priority ; vc priority list
|
||
mov al,num_vir_cons-1
|
||
init_v3:
|
||
stosb ; lowest priority first
|
||
dec al
|
||
jns init_v3 ; do through zero
|
||
jmp new_monitor ; set up initial windows
|
||
|
||
|
||
; Cold start setup for XT hard disk driver
|
||
; needs to do these things:
|
||
; 1) setup floppy interrupt trap
|
||
; 2) save disk interrupt vector for far call usage
|
||
; 3) initialize HDINF vectors about physical drive char.
|
||
; 4) try to login first hard disk
|
||
; 5) decide who will be system disk and temp disk
|
||
;
|
||
; this code assumes that it is running in XIOS codeseg and that
|
||
; the floppy initialization has already been done
|
||
;
|
||
; a stack switch has been deleted here
|
||
;
|
||
hd_init:
|
||
push ds
|
||
push es
|
||
xor ax,ax
|
||
mov es,ax ;point to vector seg
|
||
|
||
hd_patch_step_rate: ;step option bits off
|
||
and es:byte ptr .hd_control_byte,0F8h or (not SLOW_SEEK)
|
||
|
||
les ax,es:.HD_PTR ;get hard disk int ptr
|
||
mov hd_rom_seg,es
|
||
mov hd_rom_ofs,ax ;to local link address
|
||
mov disk_int_seg,es
|
||
mov disk_int_off,ax ; save in setup block
|
||
|
||
mov dl,byte ptr num_hard ;dl=number of drives
|
||
test dl,dl ;if no hard drives
|
||
jz hd_init_done ; then done
|
||
|
||
mov si,offset hd_info0
|
||
call hd_init_hdinf ;set its info vector
|
||
dec dl ! jz hd_init1 ;if no more drives,skip
|
||
|
||
mov dl,81h ;ask about 2nd drive
|
||
mov ah,8
|
||
pushf ! callf HD_ROM_ENTRY
|
||
jc hd_init1 ;if error now, continue
|
||
mov si,offset hd_info1
|
||
call hd_init_hdinf ;setup #2's info vector
|
||
hd_init1:
|
||
mov AUX_DRIVE,0 ;try to login 1st drive
|
||
mov si,offset hdinfo0
|
||
call hd_login
|
||
or al,al ! jz hd_init_done ;if can't login, forget rest!
|
||
|
||
; login is successful, correct the dpb pointers, sysdisk, and tempdisk
|
||
|
||
mov si,offset hd_dph0 + 8 ; point to dpb pointer
|
||
mov word ptr [si],offset HD_DPB0
|
||
mov word ptr .dph_size[si],offset HD_DPB1
|
||
inc SYS_DISK ; SYS and TEMP disks now
|
||
inc TEMP_DISK ; default to first hard disk
|
||
|
||
hd_init_done:
|
||
mov hd_init_flag,0ffh ;set XIOS initialized flag
|
||
pop es ;(which enables error handler)
|
||
pop ds
|
||
ret
|
||
|
||
; subroutine sets up physical information vector about a drive
|
||
hd_init_hdinf:
|
||
mov HDINF_exists[si],0ffh ;it at least exists
|
||
inc dh ;change last hd to # of hds
|
||
mov HDINF_heads[si],dh
|
||
mov al,3fh ! and al,cl ;sectors is already # of spt
|
||
mov HDINF_spt[si],al
|
||
rol cl,1 ! rol cl,1
|
||
and cl,3 ! xchg ch,cl ;unpack max cyl address
|
||
mov HDINF_cyl[si],cx ;and save it
|
||
ret
|
||
|
||
|
||
; Do the SETUP customizing of the XIOS
|
||
|
||
do_setup:
|
||
push ds
|
||
pop es ; for local read
|
||
mov dl,boot_disk ; from whence we came
|
||
mov dh,0 ; head zero
|
||
mov cx,0002h ; assume floppy tr 0 sct 2
|
||
mov bx,setup_buf ; local buf for setup
|
||
cmp dl,00h ; if floppy boot
|
||
jz setup_read ; then read it
|
||
|
||
cmp dl,80h ; if not hard disk
|
||
jnz setup_no_go ; then something's wrong
|
||
|
||
mov si,offset hd_label0 ; if hard disk, then
|
||
mov ax,HDLB_pstart[si] ; find our partition
|
||
mov ch,al ; cylinder lsb's
|
||
ror ah,1
|
||
ror ah,1 ; cylinder msb's
|
||
or ah,03h ; add in sector 3
|
||
mov cl,ah ; save the mashed code
|
||
setup_read:
|
||
mov ax,0201h ; read one sector
|
||
int disk_int ; through the ros
|
||
jnc setup_go ; if no error
|
||
dec su_retry
|
||
jnz setup_read ; try again
|
||
setup_no_go:
|
||
ret ; until exausted
|
||
|
||
setup_go:
|
||
cmp su_check,0DDB2h ; check for secret code
|
||
jnz setup_no_go ; if bad, bag it
|
||
|
||
; at this point, the SETUP sector is a winner
|
||
|
||
mov ax,su_md_start
|
||
mov mdisk_start,ax ; where to try for mdisk
|
||
mov al,su_verf
|
||
mov verify_flag,al ; whether to verf after write
|
||
|
||
mov al,su_hdst ; head step code
|
||
mov fdc_spec1_var,al ; save for specify
|
||
call flop_specify ; set head step speed
|
||
|
||
cmp su_cf,0 ; check the config flag
|
||
jz setup_pfks ; if not saved, skip
|
||
mov ax,su_config
|
||
mov config_data,ax ; save both codes
|
||
setup_pfks:
|
||
cmp su_pf,0 ; check the pfk flag
|
||
jz setup_done ; if not saved, finished
|
||
mov di,offset pfk_tbl0 ; first pfk (es is local)
|
||
mov bx,num_vir_cons ; number of pfk tables
|
||
setup_pfk_loop:
|
||
mov si,offset su_pfk_tbl ; the saved values
|
||
mov cx,180 ; words per pfk table
|
||
rep movsw ; copy 'em
|
||
dec bx
|
||
jnz setup_pfk_loop ; for each console
|
||
setup_done:
|
||
ret
|
||
|
||
|
||
; turn off the floppy motors before taking over interrupts
|
||
|
||
flop_off:
|
||
mov dx,FDC_PORT
|
||
mov al,FDC_ON ; turn off floppy motors
|
||
mov MOTOR_FLAGS,al ; or they may stay on forever
|
||
out dx,al
|
||
ret
|
||
|
||
|
||
; set up mdisk variables and clear the memory
|
||
|
||
try_mdisk:
|
||
mov ax,mdisk_start ; try to start it here
|
||
mov dx,lo_mem_top ; main mem ceiling
|
||
cmp ax,dx ; if start is below
|
||
jb yes_mdisk_lo ; then it's a winner
|
||
|
||
mov dx,hi_mem_start ; now look above video mem
|
||
test dx,dx ; if dx=0 there's none
|
||
jz no_mdisk
|
||
cmp ax,dx ; if mdisk is below
|
||
jb no_mdisk ; then forget it
|
||
mov dx,hi_mem_top ; high memory ceiling
|
||
cmp ax,dx ; if start is below
|
||
jb yes_mdisk ; yes, but no trimming
|
||
|
||
no_mdisk:
|
||
mov md_dph,0 ; zap the dph
|
||
ret ; and we're done
|
||
|
||
yes_mdisk_lo:
|
||
mov memory_top,ax ; save for memory trim
|
||
call yes_mdisk ; set it up
|
||
mov ax,num_mdkb ; get mdisk size
|
||
sub num_mmkb,ax ; and reduce main mem
|
||
ret
|
||
|
||
yes_mdisk:
|
||
mov temp_disk,'M'-'A'
|
||
xchg ax,dx ; dx = starting segment
|
||
sub ax,dx ; ax = paragraph length
|
||
mov cl,6
|
||
shr ax,cl ; ax = 1k chunks of mdisk
|
||
mov num_mdkb,ax ; save for signon
|
||
shr ax,1 ; ax = 2k chunks of mdisk
|
||
mov bx,ax ; save for fill count
|
||
dec ax
|
||
mov dsm_md,ax ; save in the dpb
|
||
|
||
mov ax,0E5E5h ; CP/M erase bytes
|
||
yes_mdisk_fill:
|
||
mov es,dx ; set up destination
|
||
sub di,di ; di = 0
|
||
mov cx,1024
|
||
rep stosw ; blast 2k bytes of E5's
|
||
add dx,80h ; up 2k
|
||
dec bx
|
||
jnz yes_mdisk_fill
|
||
ret ; that's it
|
||
|
||
|
||
; trim the memory partion list to match physical memory
|
||
|
||
trim_memory:
|
||
mov cx,memory_top ; top segment address
|
||
mov bx,offset mfl ; memory free list root
|
||
trim_mem1:
|
||
mov si,bx ; save previous link
|
||
mov bx,md_link[bx] ; link to next
|
||
test bx,bx
|
||
jz trim_mem3 ; 0 => end of list
|
||
|
||
mov ax,md_start[bx] ; memory block start seg
|
||
add ax,md_length[bx]
|
||
cmp ax,cx ; past physical ?
|
||
jbe trim_mem1 ; if not, link to next
|
||
|
||
mov md_link[si],0 ; previous is now the last
|
||
mov si,bx ; save start of severed list
|
||
trim_mem2:
|
||
mov di,bx ; save last link
|
||
mov bx,md_link[bx] ; look for the end of the
|
||
test bx,bx ; severed list
|
||
jnz trim_mem2
|
||
|
||
mov ax,mdul ; save md unused root
|
||
mov mdul,si ; redo the root
|
||
mov md_link[di],ax ; and re-attach original
|
||
trim_mem3:
|
||
ret
|
||
|
||
|
||
; set up the async ports
|
||
|
||
do_config:
|
||
sub dx,dx ; dx -> port 0
|
||
mov al,config0_data ; baud rate, etc.
|
||
mov ah,0 ; init code
|
||
int async_int ; through the ros
|
||
inc dx ; port 1
|
||
mov al,config1_data
|
||
mov ah,0
|
||
int async_int
|
||
ret
|
||
|
||
|
||
; take care of all of the interrupt stuff
|
||
|
||
do_interrupts:
|
||
cli ; an interrupt now would be bad
|
||
mov si,offset int_save_tbl ; list of ints to save
|
||
test debug,true ; if we are debugging
|
||
jnz xios_int_save ; under CP/M
|
||
|
||
mov si,offset int_no_save ; if we're running free
|
||
xios_int_save:
|
||
sub dx,dx ; interrupt number counter
|
||
mov es,dx ; int vector base address
|
||
mov di,dx ; and offset
|
||
mov cx,256 ; number of interrupts
|
||
mov ax,offset i_unexpected ; unexpected int entry
|
||
mov bx,cs ; and segment
|
||
cld
|
||
|
||
int_save_loop:
|
||
cmp dx,[si] ; if this is one to save
|
||
jz int_save_one ; then skip the store
|
||
|
||
stosw ! xchg ax,bx ; else store offset
|
||
stosw ! xchg ax,bx ; and segment
|
||
jmps int_save_cont
|
||
int_save_one:
|
||
add di,4 ; skip this vector
|
||
inc si ! inc si ; to next table entry
|
||
int_save_cont:
|
||
inc dx ; next int number
|
||
loop int_save_loop ; through the whole table
|
||
|
||
; now set up our particular interrupts
|
||
|
||
mov si,offset int_tbl ; offsets and vectors
|
||
mov cx,int_tbl_len ; number of entries
|
||
int_setup_loop:
|
||
lodsw ; get destination
|
||
mov di,ax ; and stash it
|
||
lodsw ; get vector
|
||
stosw ; and store it
|
||
mov ax,cs ; all vectors to sysdat
|
||
stosw
|
||
loop int_setup_loop ; through the table
|
||
|
||
; now set up timer interrupts
|
||
|
||
mov ax,timer_60_hz
|
||
out timer_0_reg,al
|
||
xchg ah,al
|
||
out timer_0_reg,al
|
||
|
||
mov al,beep_cmnd ; set up the beep frequency
|
||
out timer_cmnd_reg,al ; send the command
|
||
mov ax,timer_1000_hz ; get the constant
|
||
out timer_2_reg,al
|
||
xchg ah,al
|
||
out timer_2_reg,al
|
||
in al,21h
|
||
and al,0feh
|
||
out 21h,al
|
||
|
||
sti ; now we can handle ints
|
||
ret ; to main line
|
||
|
||
|
||
; print the sign on message with equipment configuration
|
||
|
||
sign_on:
|
||
mov si,offset banner
|
||
call print_msg ; name, copyright, etc.
|
||
sign_on_loop:
|
||
cmp word ptr [si],0 ; if next equip ptr = 0
|
||
jz sign_on_done ; then we're done
|
||
push si
|
||
call print_equip ; print one item
|
||
pop si
|
||
add si,equip_record_len
|
||
jmps sign_on_loop ; back for another
|
||
sign_on_done:
|
||
lodsw ; clear the pointer
|
||
jmp print_msg ; final cr,lf,lf
|
||
|
||
print_equip:
|
||
lodsw
|
||
xchg ax,bx ; bx -> equip count
|
||
mov ax,[bx] ; ax = equip count
|
||
test ax,ax ; if count = 0
|
||
jz pr_equip_done ; then don't print
|
||
push ax ; save the count
|
||
call print_msg ; print the name first
|
||
pop ax
|
||
call print_num ; and then the count
|
||
pr_equip_done:
|
||
ret
|
||
|
||
print_msg:
|
||
lodsb ; fetch a character
|
||
pr_msg_loop:
|
||
push si
|
||
call print_char ; print just one
|
||
pop si
|
||
lodsb ; fetch another
|
||
test al,al
|
||
jnz pr_msg_loop ; when char = 0, done
|
||
ret
|
||
|
||
print_num:
|
||
mov dh,0 ; skip 0's till dh > 0
|
||
div one_hundred ; al = hund's, ah = rem
|
||
call print_digit ; print hundred's place
|
||
mov al,ah
|
||
cbw ; ready for divide
|
||
div ten
|
||
call print_digit ; print ten's place
|
||
mov al,ah
|
||
; jmps print_digit ; print one's place
|
||
|
||
print_digit:
|
||
push ax ; save the number
|
||
or dh,al ; have we started printing
|
||
jz pr_digit_done ; skip if 0 and no
|
||
push dx
|
||
or al,'0' ; make into ascii
|
||
call print_char ; and print it
|
||
pop dx
|
||
pr_digit_done:
|
||
pop ax ; restore number
|
||
ret
|
||
|
||
print_char:
|
||
mov cl,al ; char to cl
|
||
mov dl,0
|
||
jmp io_conout ; print it
|
||
|
||
|
||
eject
|
||
|
||
;************************************************
|
||
;* *
|
||
;* INITIALIZATION DATA AREA *
|
||
;* *
|
||
;************************************************
|
||
|
||
reorg17 equ offset $
|
||
dseg
|
||
org reorg17
|
||
|
||
memory_top rw 1 ; for memory_trim
|
||
|
||
config0_data db 43h ; 300 baud, 1, none, 8
|
||
config1_data db 43h ; same here
|
||
config_data equ word ptr config0_data
|
||
|
||
init_video_mode rb 1 ; which crt to default
|
||
db 0 ; pad
|
||
|
||
banner db '---------------------------------------------------',cr,lf
|
||
db 'Concurrent CP/M for the IBM PC and PC XT 01/01/84',cr,lf
|
||
db 'Serial No. XXXX-0000-654321 All Rights Reserved',cr,lf
|
||
db 'Copyright (C) 1982,83,84 Digital Research Inc.',cr,lf
|
||
db '---------------------------------------------------',cr,lf,lf
|
||
db 'Hardware Supported :',cr,lf,0
|
||
|
||
dw num_flop
|
||
db cr,lf,' Diskette Drive(s) : ',0
|
||
dw num_hard
|
||
db cr,lf,' Hard Disk(s) : ',0
|
||
dw num_print
|
||
db cr,lf,' Parallel Printer Port(s) : ',0
|
||
dw num_port
|
||
db cr,lf,' Serial Port(s) : ',0
|
||
dw num_ndp
|
||
db cr,lf,' Numeric Data Processor : ',0
|
||
dw num_mmkb
|
||
db cr,lf,' Main Memory (Kb) : ',0
|
||
last_eq dw num_mdkb
|
||
db cr,lf,' MDisk (Kb) : ',0
|
||
|
||
equip_record_len equ offset $ - offset last_eq
|
||
dw 0 ; equipment end
|
||
db cr,lf,lf,0 ; last message
|
||
|
||
one_hundred db 100 ; for print_number divisions
|
||
ten db 10
|
||
|
||
su_retry db 3 ; for sector read retries
|
||
|
||
; SETUP buffer
|
||
|
||
setup_buf equ offset $
|
||
su_check rw 1 ; check code
|
||
su_md_start rw 1 ; mdisk start segment
|
||
su_verf rb 1 ; floppy verify flag
|
||
su_hdst rb 1 ; floppy head step
|
||
org setup_buf + 60h
|
||
su_cf rb 2 ; config flag (+ assign flag)
|
||
su_pf rb 2 ; pfk flag (+ one byte)
|
||
su_config rw 1 ; both async init bytes
|
||
org setup_buf + 70h
|
||
su_pfk_tbl rb 360 ; one console's pfk's
|
||
|
||
org setup_buf + 512 ; save room for a whole sector
|
||
|
||
|
||
; Interrupts to save for debug mode
|
||
; these must be in increasing number order
|
||
|
||
int_save_tbl dw single_step_interrupt
|
||
dw one_byte_interrupt
|
||
dw hd_hard_interrupt
|
||
dw async_int
|
||
dw print_int
|
||
dw hd_param_interrupt
|
||
dw debugger_interrupt
|
||
dw 0FFFFh
|
||
|
||
int_no_save dw hd_hard_interrupt
|
||
dw hd_param_interrupt
|
||
dw 0FFFFh ; impossible code
|
||
|
||
; Interrupt setup table
|
||
|
||
int_tbl dw divide_interrupt*4, i_divide
|
||
dw nmi_interrupt*4, i_nmi
|
||
dw overflow_interrupt*4, i_overflow
|
||
dw clock_interrupt*4, i_clock
|
||
dw tick_interrupt*4, i_tick
|
||
dw keyboard_interrupt*4, i_keyboard
|
||
dw disk_interrupt*4, i_disk
|
||
dw hd_code_interrupt*4, hd_dummy_int
|
||
dw flag_interrupt*4, i_fidds_flag
|
||
dw fidds_interrupt*4, i_dummy_fidds
|
||
dw xios_interrupt*4, xios_v1_entry
|
||
|
||
int_tbl_len equ (offset $ - offset int_tbl) / 4
|
||
|