;---------------------------------------------------------------------
; IBMCPM.A86 version 2.1 for LSI M-FOUR and CAL-PC computers
; 23-MAR-88
; Stephen Hunt
;---------------------------------------------------------------------
;
; 
;	configure drive C, D or E to IBM CP/M ss dd format.
;
;       Will be of no use if 8" floppy drives are fitted.
;
;
;---------------------------------------------------------------------

; prom related equates

label_seg	equ	0ffffh		; label segment
label_ofst	equ	05h		; label offset
prom_seg	equ	0fc00h		; prom segment
get_switch	equ	03055h		; get switch function (prom call)

; character equates

cr		equ	0dh		; carriage return
lf		equ	0ah		; line feed
eof		equ	01ah		; end of file
esc		equ	01bh		; escape

bit0		equ	00000001b
bit1		equ	00000010b
bit2		equ	00000100b
bit3		equ	00001000b
bit4		equ	00010000b
bit5		equ	00100000b
bit6		equ	01000000b
bit7		equ	10000000b

cpm		equ	0e0h

; macro to CALLF to prom (asm86 does not understand 'CALLF SEG:OFST')

codemacro call_prom func_call:dw
	db	09ah
	dw	func_call
	dw	0fc00h
endm

;---------------------------------------------------------------------
; CODE SEGMENT
;---------------------------------------------------------------------

	cseg
	org	0000h

;---------------------------------------------------------------------
; jump past my copywrite message
;---------------------------------------------------------------------

start:
;
	jmp	check_os

vers	db	'(C) STEPHEN HUNT 23-MAR-88, Disk Patch Version 2.1',eof

;---------------------------------------------------------------------
; check that the operating system is BDOS version 2.x
;---------------------------------------------------------------------

check_os:
;
	mov	cl,0ch		; get o/s version number
	int	cpm
	and	al,0f0h		; mask of lower nybble
	cmp 	al,020h		; check version 2.x
	jz	get_machine_type; if ok jump forward

;---------------------------------------------------------------------
; incorrect BDOS version, so print error & terminate
;---------------------------------------------------------------------

wrong_bdos_version:
;
	mov	dx,offset wrong_version
	jmp	exit_msg	; print message & exit

;---------------------------------------------------------------------
; check that the machine is a CAL-PC or LSI-M4
;---------------------------------------------------------------------

get_machine_type:
;
	mov	ax,label_seg
	mov	es,ax
	mov	si,offset m4_label
	mov	di,label_ofst
	mov	cx,06h
	cld
	rep	cmpsb
	mov	bl,00h			; 0 = LSI-M4
	jz	set_mc_type

	mov	si,offset cal_label
	mov	di,label_ofst
	mov	cx,06h
	rep	cmpsb
	mov	bl,01h			; 1 = CAL-PC
	jz	set_mc_type

	mov	bl,02h			; 2 = UNKNOWN

;---------------------------------------------------------------------
; print machine type, and exit if not CAL-PC or LSI-M4
;---------------------------------------------------------------------

set_mc_type:
;
	mov	mc_type,bl
	xor	bh,bh
	add	bx,bx
	add	bx,offset machines
	mov	dx,[bx]
	call	print_string
	cmp	mc_type,02h
	jb	valid_hware
	jmp	reset

;---------------------------------------------------------------------
; print signon message
;---------------------------------------------------------------------

valid_hware:
;
	mov	dx,offset signon
	call	print_string

;---------------------------------------------------------------------
; get system dip switch setting
;---------------------------------------------------------------------
; settings returned in AL as follows:
;
;	bit 0      -  double sided drives
;	bit 1      -  quad density drives
;	bit 2      -  8 inch drives
;	bit 3      -  hard disk present
;	bit 4      -  2 floppy drives present (else only 1)
;	bit 5 & 6  -  hard disk type:
;	      0 0  -  5  Mb  ST-412 (M4) or Rodime RO201 (CAL)
;	      0 1  -  10 Mb  Rodime RO202
;	      1 0  -  15 Mb  Rodime RO203
;	      1 1  -  20 Mb  Rodime RO204
;	bit 7      -  half height 5 inch floppy drives fitted
;---------------------------------------------------------------------

get_system_type_switch:
;
	call_prom	get_switch
	mov	dip_sw,al

;---------------------------------------------------------------------
; if 8 inch floppy drives fitted print message & exit
;---------------------------------------------------------------------

test_drive_size:
;
	test	al,bit2		; test for 8" drives
	jz	test_number_drives
	mov	dx,offset eight_inch ; error message
	jmp	exit_msg	; print message & exit

;---------------------------------------------------------------------
; test if 1 or 2 floppies, if only 1 drive test also for hard disk
; if 2 drives set drive C, right hand drive
;---------------------------------------------------------------------

test_number_drives:
;
	test	al,bit4		; test for 1 or 2 floppy drives
	jz	test_winchester ; if 1 drive, test for winchester
	mov	drive,02h	; set initially to drive C:
	mov	drvpos,01h	; set to right hand drive
	jmp	test_number_sides

;---------------------------------------------------------------------
; test for hard disk, if no hard disk print message & exit
;---------------------------------------------------------------------

test_winchester:
;
	test	al,bit3		; test for winchester
	jnz	winchester_exists ; if there is a winchester jump forward
	mov	dx,offset one_drive
	jmp	exit_msg	; print message & exit

;---------------------------------------------------------------------
; hard disk present so set to drive D, left hand drive
;---------------------------------------------------------------------

winchester_exists:
;
	mov	drive,03h	; set initially to drive D:
	mov	drvpos,0h	; set to left hand drive

;---------------------------------------------------------------------
; if single sided floppy drives, abort with error (see below)
;---------------------------------------------------------------------
; NOTE: There should never be single sided 5.25" drives on the CAL-PC
;       or LSI-M4. If the machine is booted from a single sided disk
;       with the appropriate dip switch set to single sided drives the
;       operating system always display the message:
;
;		System not recognised
;
;	The machine then halts and has to be reset.
;
;	I have encountered the above when using the following versions
;	of CP/M :
;
;		CP/M-86/80                     level 17
;		    "	                       level 21
;		    "                          level 22
;		Concurrent CP/M-86/80 vers 2.0 level 1
;
;	The program will therefore stop with an error message, simply
;	because I don't know how single sided drives are configured.
;
;  23-03-88  only single sided 8" drives may exists on this system !
;
;---------------------------------------------------------------------

test_number_sides:
 
 	test	al,bit0		; test for single or double sided
 	jnz	test_density	; if double sided jump forward
 	mov	dx,offset single_sided
	jmp	exit_msg	; print message & exit

;---------------------------------------------------------------------
; if quad density floppy drive, increment the drive reference letter
;---------------------------------------------------------------------
; NOTE: If the disk drive is quad density, the disk is treated as read
;	only by the BIOS.
;---------------------------------------------------------------------
; 

test_density:
;
	test	al,bit2		; test for double or quad density drives
	jz	select_drive	; if double, jump forward
	inc	drive		; quad density, so change patch drive

;---------------------------------------------------------------------
; select required drive via a direct bios call,
; returns the following in this configuration:
;	ax = dpb offset
;	bx = dpe offset
;	es = segment address
;---------------------------------------------------------------------

select_drive:
;
	mov	dx,offset bios_code
	mov	cl,032h
	int	cpm

;---------------------------------------------------------------------
; if invalid drive (dpb or dpe = 0), print message and exit
;---------------------------------------------------------------------

test_valid_dpb:
;
	test	ax,ax
	jz	drive_select_error
	test	bx,bx
	jnz	set_new_format

drive_select_error:
;
	mov	dx,offset select_error
	jmp	exit_msg	; print message & exit

;---------------------------------------------------------------------
; overwrite the old disk parameters with the new parameters
;---------------------------------------------------------------------

set_new_format:
;
	mov	si,offset new_dpb
	mov	di,ax
	mov	cx,24
	cld
	rep	movsb

;---------------------------------------------------------------------
; get & display the drive that has been patched, and to what format
; before terminating
;---------------------------------------------------------------------

finished_message:
;
	mov	ax,drive
	add	al,'A'
	mov	drv_letter,al
	mov	dx,offset complete
	;jmp	exit_msg	; print message & exit

;---------------------------------------------------------------------
; print message at DX, reset all drives, and exit back to CP/M-86
;---------------------------------------------------------------------

exit_msg:
;
	call	print_string

reset:		; reset drives even if errors occur
;
	mov	cl,0dh
	int	cpm

exit:
;
	xor	cl,cl
	xor	dl,dl
	int	cpm

;---------------------------------------------------------------------
; subroutine: print string at offset DX
;---------------------------------------------------------------------

print_string:
;
	mov	cl,09h
	int	cpm
	ret
;---------------------------------------------------------------------
; END OF CODE SEGMENT
;---------------------------------------------------------------------
;---------------------------------------------------------------------
; DATA SEGMENT
;---------------------------------------------------------------------

	dseg
	org	0100h

signon		db	' Disk Patch  Version 2.1  (C) S.Hunt 23-Mar-88',cr,lf,'$'

complete	db	cr,lf,'Drive '
drv_letter	db	'X'
		db	': set to IBM CP/M SS DD format',cr,lf,'$'

machines	dw	offset m_four
		dw	offset cal_pc
		dw	offset unknown

m_four		db	cr,lf,'LSI M-FOUR$'
cal_pc		db	cr,lf,'CAL-PC$'
unknown		db	cr,lf,'Disk Patch only runs on the LSI M-FOUR or CAL-PC$'

wrong_version	db	cr,lf,'Disk Patch Requires CP/M-86 version 2.x$'

eight_inch	db	cr,lf,'Aborting - not configured for 8" drives$'
one_drive	db	cr,lf,'Aborting - not configured for single drive machine$'
single_sided	db	cr,lf,'Aborting - configuration not known for single sided drives$'
select_error	db	cr,lf,'Aborting - Unable to access disk parameters$'

dip_sw		db	00h	; dip switch setting
mc_type		db	02h	; machine type

m4_label	db	'Lsi_M4' ; machine label in prom at FFFF:0005
cal_label	db	'Cal_PC' ;    "      "   "   "   "   "    "

bios_code	db	09h	; select drive function
drive		dw	00h	; drive code [CX]
		dw	00h	;   "   "    [DX]

;---------------------------------------------------------------------
; parameters for IBM CP/M single sided double density format.
;
; NOTE: each track has 8 x 512 byte sectors. However, this system
; expects each sector to be 128 bytes long. So as far as this system
; is concerned, each track has 32 x 128 byte sectors per track.
; (i.e  8 x 512  =  32 x 128)
;---------------------------------------------------------------------

new_dpb		dw	020h	; spt
		db	03h	; bsh
		db	07h	; blm
		db	0h	; exm
		dw	09bh	; dsm
		dw	03fh	; drm
		db	0c0h	; al0
		db	0h	; al1
		dw	010h	; cks
		dw	01h	; off

;---------------------------------------------------------------------
; parameters used by the firmware when accessing the disk controller.
; MUST follow on directly after the Disk Parameter Block.
;---------------------------------------------------------------------

flags		db	00h	; parameter flags (initially SS DD)
		db	0ah	; number of retries
		db	08h	; physical sectors per track
drvpos		db	01h	; right hand drive
		db	00h	; ? don't know ?
		dw	320	; total sectors per disk
		dw	512	; bytes per sector

		db	0	; just padding !!

;---------------------------------------------------------------------
; END OF DATA SEGMENT
;---------------------------------------------------------------------

		end

;---------------------------------------------------------------------
; end of Disk Patch v2.10
;---------------------------------------------------------------------
