💾 Archived View for uscoffings.net › retro-computing › systems › AppleII › IDE-adapter › lwlv-src.tx… captured on 2022-06-04 at 00:22:13.

View Raw

More Information

-=-=-=-=-=-=-

			;Prototype driver for IDE/ATA interface board
			;65C02 assembly (using Procode)
			;ATA PIO mode 1 protocol
			;(c) 2001 stephane.guillard@steria.com
			;Release 0.0.2 May-03-2001

			;############## Constant values
base	equ	$C0F0	;Base address for slot I/O 16 bytes (slot 7)
datmsb	equ	base+0	;Read / write latch MSB
altern	equ	base+6	;Alternate status byte (R)
devctrl	equ	base+6	;Device control reg (W)
drivad	equ	base+7	;Device selection (Master / Slave)
datlsb	equ	base+8	
error	equ	base+9	;Error code
feature	equ	base+9	
seccnt	equ	base+10	
secnr	equ	base+11	
cyllow	equ	base+12	
cylhig	equ	base+13	
drhead	equ	base+14	
status	equ	base+15	;Status (R)
command	equ	base+15	;Commande (W)

			;############## Screen holes used as RAM parameters for syscalls
ph	equ	$47E	;Head parameter
ps	equ	$4FE	; Sector parameter
pcl	equ	$57E	;Cyl (lsb) parameter
pch	equ	$5FE	;Cyl (msb) parameter

			;############## Apple ROM useful routines
home	equ	$FC58	;Clear screen
crout	equ	$FD8B	;Outputs a CR/LF
cout	equ	$FDED	;Outputs reg. A as char
strout	equ	$DB3A	;Outputs AY-pointed null-terminated string
prax	equ	$F941	;Outputs AX as 4 hex digits
pra	equ	$FDDA	;Outputs A as 2 hex digits
prspc	equ	$DB57	;Outputs 1 space char

			;############## Macros
	do	0	;No code generation

pr	mac		;Outputs string without CR/LF
	phy		
	pha		
	ldy	#>.0	
	lda	#<.0	
	jsr	strout	
	pla		
	ply		
	eom		

prln	mac		;Outputs string with CR/LF
	pr	.0	
	jsr	crout	
	eom		

	fin		;Revert to normal code generation

			;############## Start of code
	org	$4000	

init0	jmp	init	
			;############## Text messages
secbuf	ds	512	;RAM sector buffer (1 sector = 512 bytes in ATA world)
m_hello	asc	"A2IDE 2001 stephane.guillard@steria.com"
	dfb	0
m_done	asc	"ok"
	dfb	0
m_yes	asc	"yes"
	dfb	0
m_no	asc	"no"
	dfb	0
m_hd	asc	"Non-packet IDE HD signature..."
	dfb	0
m_reset	asc	"Init HD� "
	dfb	0
m_qry	asc	"Get HD info..."
	dfb	0
m_name	asc	"Name.....:"
	dfb	0
m_firm	asc	"Firmware.:"
	dfb	0
m_ser	asc	"Serial #.:"
	dfb	0
m_cyl	asc	"Cylinders:&H"
	dfb	0
m_head	asc	"Heads....:&H"
	dfb	0
m_sec	asc	"Sectors..:&H"
	dfb	0
m_lba	asc	"Lba......:"
	dfb	0
m_mbr	asc	"Read MBR..."
	dfb	0
m_chk	asc	"MBR signature..."
	dfb	0
m_part	asc	"Partition #"
	dfb	0
m_undef	asc	"undef'd"
	dfb	0
m_act	asc	">Active:"
	dfb	0
m_start	asc	">CHS start:"
	dfb	0
m_end	asc	", end :"
	dfb	0
m_type	asc	", type "
	dfb	0
m_res	asc	">Resvd secs:"
	dfb	0
m_seccnt	asc	">Total secs:"
	dfb	0
m_rdy	asc	"Boot sector in secbuf at $"	
	dfb	0	
m_rdsect	asc	"RDSect() syscall at $"	
	dfb	0	

			;############## init() : main init routine
init	jsr	home	;Clear screen
	prln	m_hello	
	jsr	hdinit	;Reset HD
	bcs	done	
	jsr	hdqry	;Query and display HD info
	bcs	done	
	jsr	hdmbr	;Analyze MBR and find 1st partition boot sector (leave CHS in RAM 
parameters)
	bcs	done	
	jsr	rdsect	;Read 1st partition boot sector into RAM sector D42buffer
	bcs	done	
	pr	m_rdy	;Print sector buffer address (for later use in other sw)
	ldx	#<secbuf	
	lda	#>secbuf	
	jsr	prax	
	jsr	crout	
	pr	m_rdsect	;Print RDSect() syscall address (for later use in other sw)
	ldx	#<rdsect	
	lda	#>rdsect	
	jsr	prax	
	jsr	crout	
done	clc		
	rts		;End

			;############## hdinit() : check IDE HDD signature and reset disk
signok	prln	m_no	
	sec		
	rts		
hdinit	pha		;Init master IDE peripheral
	stz	datmsb	;Clear interface MSB register (we are going to make a few 8 bit 
transfers)
	stz	drhead	;Select master

	pr	m_hd	;Check IDE non packet signature : seccnt=secnr=1,
	lda	#$1	;cyllow=cylhig=0
	cmp	seccnt	;If signature is different then peripheral may be an ATAPI (ATA 
w/packet
	bne	signok	;interface, like CD) or nothing
	cmp	secnr	
	bne	signok	
	lda	#$0	
	cmp	cyllow	
	bne	signok	
	cmp	cylhig	
	bne	signok	
	prln	m_yes	

	pr	m_reset	
	lda	#$06	;Start reset, no interrupts
	sta	devctrl	
	lda	#$02	;Stop reset, no interrupts
	sta	devctrl	
	jsr	waitBSY	;Wait for BUSY bit to go away
	prln	m_done	
	pla		
	clc		
	rts		

			;############## hdmbr() ; read disk Master Boot Record, check it and analyze 
partition entries
hdmbr	pha		;Analyze MBR and find 1st partition boot sector (leave CHS in RAM 
parameters)
	phx		
	phy		

	pr	m_mbr	;MBR = sector C=0, H=0, S=1
	lda	#$1	
	sta	ps	
	stz	ph	
	stz	pcl	
	stz	pch	
	jsr	rdsect	;Read sector
	prln	m_done	

	pr	m_chk	;Check signature MBR : offset 1FE=$55AA
	lda	secbuf+$1FE	
	cmp	#$55	
	beq	]55ok	
	jmp	]signok	
]55ok	lda	secbuf+$1FF	
	cmp	#$AA	
	beq	]AAok	
]signok	prln	m_no	
	sec		
	rts		
]AAok	prln	m_done	

			;Scan the 4 partition entries of MBR (starts at secbuf+446)
	ldy	#$0	;Y=offset beginning part from (secbuf + 446) (Y may be 0, 16, 32, 48)
]nextprt	pr	m_part	;Loop for 4 partition entries
	tya		;Store A in Y, and then A <- D272A/16
	phy		
	lsr		
	lsr		
	lsr		
	lsr		
	jsr	pra	;Output current partition number (may be 0, 1, 2, 3)

	pr	m_type	;Output partition type (as hex)
	ply		
	phy		
	lda	secbuf+446+4,y	
	bne	]defined	;If partition type is null then partition is not defined
	prln	m_undef	
	jmp	]undef	
]defined	jsr	pra	
	jsr	crout	

	pr	m_act	;Output partition active flag Y/N
	ply		
	phy		
	lda	secbuf+446+0,y	
	cmp	#$80	
	beq	]active	
	prln	m_no	
	jmp	]chs	
]active	prln	m_yes	

]chs	pr	m_start	;Output start / End CHS (note that start CHS is the boot sector 
of the partition)
	ply		
	phy		
	lda	secbuf+446+2+1,y	;A - Extract cyl# (10 bit) into AX
	and	#$C0	;A1 - Extract cyl# MSB which is in the 2 upper bits of sector#, into A
	lsr		
	lsr		
	lsr		
	lsr		
	lsr		
	lsr		
	ldx	secbuf+446+2,y	;A2 - Extract cyl# LSB into X
	sta	pch	;Store cyl# in RAM parameters for later RDSect() call by init() (to 
read in boot sector)
	stx	pcl	
	jsr	prax	
	jsr	prspc	
	ply		
	phy		
	lda	secbuf+446+1,y	;B - Extract head#
	sta	ph	;Store head# in RAM parameters for later RDSect() call by init() (to 
read in boot sector)
	jsr	pra	
	jsr	prspc	
	ply		
	phy		
	lda	secbuf+446+2+1,y	;C - Extract sector# (and mask out the 2 upper bits which 
are part of cyl#, see A above)
	and	#$3F	
	sta	ps	;Store sector# in RAM parameters for later RDSect() call by init() (to 
read in boot sector)
	jsr	pra	
	pr	m_end	;Do the same for partition end CHS
	ply		
	phy		
	lda	secbuf+446+6+1,y	;MSB C
	and	#$C0	
	lsr		
	lsr		
	lsr		
	lsr		
	lsr		
	lsr		
	ldx	secbuf+446+6,y	;LSB C
	jsr	prax	
	jsr	prspc	
	ply		
	phy		
	lda	secbuf+446+5,y	;H
	jsr	pra	
	jsr	prspc	
	ply		
	phy		
	lda	secbuf+446+6+1,y	;S
	and	#$3F	
	jsr	pra	
	jsr	crout	

	pr	m_res	;Reserved sectors (not implemented yet)
	jsr	crout	

	pr	m_seccnt	;Total sectors (not implemented yet)
	jsr	crout	

]undef	ply		;Next partition : Y <- Y + 16
	tya		
	clc		
	adc	#16	
	tay		
	cmp	#64	
	beq	]done	
	jmp	]nextprt	

]done	ply		
	plx		
	pla		
	clc		
	rts		

			;############## hdqry() : inquiry disk properties and display them
hdqry	pha		
	phx		
	pr	m_qry	
	stz	datmsb	
	lda	#$EC	;Send ATA Inquiry command
	sta	command	
	jsr	waitBSY	
	jsr	waitDATA	
	jsr	rd512byt	
	prln	m_done	
	pr	m_name	;Output disk name
	ldx	#54	
]nextc	lda	secbuf,x	
	jsr	cout	
	inx		
	cpx	#94	
	bne	]nextc	
	jsr	crout	
	pr	m_firm	;Output disk firmware rev.
	ldx	#46	
]nextf	lda	secbuf,x	
	jsr	cout	
	inx		
	cpx	#54	
	bne	]nextf	
	jsr	crout	
	pr	m_ser	;Output disk serial #
	ldx	#20	
]nexts	lda	secbuf,x	
	jsr	cout	
	inx		
	cpx	#40	
	bne	]nexts	
	jsr	crout	
	pr	m_cyl	;Output cylinder count
	lda	secbuf+2	
	ldx	secbuf+3	
	jsr	prax	
	jsr	crout	
	pr	m_head	;Output head count
	lda	secbuf+6	
	ldx	secbuf+7	
	jsr	prax	
	jsr	crout	
	pr	m_sec	;Output sector per track count
	lda	secbuf+12	
	ldx	secbuf+13	
	jsr	prax	
	jsr	crout	
	pr	m_lba	;Output LBA accepted flag (yes / no)
	lda	secbuf+98	
	bit	#8	
	beq	]nolba	
	prln	m_yes	
	jmp	]done	
]nolba	prln	m_no	
]done	plx		
	pla		
	clc		
	rts		

			;############## rdsect() : read a sector pointed by pch/pcl, ph, ps into 
secbuf
rdsect	pha		
	lda	#$1	
	sta	seccnt	;We want to read 1 sector (multiple sector transfer is also 
possible)
	lda	ps	
	sta	secnr	;Sector # in track
	lda	pcl	
	sta	cyllow	;Cylinder # LSB
	lda	pch	
	sta	cylhig	;Cylinder # MSB
	lda	ph	
	sta	drhead	;Head #
	stz	datmsb	
	lda	#$20	
	sta	command	;Send ATA Read Sector command
	jsr	waitBSY	;Wait for BUSY to go away
	jsr	waitDATA	;Wait for DRQ to come (DRQ is Data ReQuest)
	jsr	rd256wrd	;Read 256 16 bit words into RAM sector buffer
	pla		
	clc		
	rts		

			;############## rd256wrd() : read 256 16 bit words into RAM sector buffer
rd256wrd	phx		;The trick is simple : we read the interface LSB first.
	pha		;This latches the drive's MSB at the same time into the interface MSB 
latch.
	ldx	#$0	;Then we read the interface's MSB latch and we have read the full 16 
bits from the drive.
]next1	lda	datlsb	
	sta	secbuf,X	
	lda	datmsb	
	sta	secbuf+1,X	
	inx		
	inx		
	bne	]next1	
]next2	lda	datlsb	
	sta	secbuf+$100,X	
	lda	datmsb	
	sta	secbuf+$101,X	
	inx		
	inx		
	bne	]next2	
	pla		
	plx		
	rts		

			;############## rd512byt() : read 512 8 bit words into RAM sector buffer
rd512byt	phx		;Same as above. But as this is a 8 bit transfer, the order of the 
bytes come reversed.
	pha		
	ldx	#$0	
]next1	lda	datlsb
	sta	secbuf+1,X
	lda	datmsb
	sta	secbuf,X
	inx	
	inx	
	bne	]next1
]next2	lda	datlsb
	sta	secbuf+$101,X
	lda	datmsb
	sta	secbuf+$100,X
	inx	
	inx	
	bne	]next2
	pla	
	plx	
	rts		

			;############## waitDATA() : wait for DRQ bit to come
waitDATA	pha		
]wait	lda	status	
	bit	#$8	;Loop until DRQ == 1
	beq	]wait	
	pla		
	rts		

			;############## waitBSY() : wait for BUSY bit to go
waitBSY	pha		
]wait	lda	status	
	bit	#$80	;Loop until BUSY == 0
	bne	]wait	
	pla		
	rts		

			;############## dumpsec() : dump current sector in secbuf to screen (first as 

chars then as hex)
dumpsec	pha		
	phx		
	phy		

	ldx	#$0	
]next1	lda	secbuf,x	
	cmp	#$20	
	bmi	]notasc1	
	cmp	#$7E	
	bmi	]done1	
]notasc1	lda	#32	
]done1	jsr	cout	
	inx		
	bne	]next1

]next2	lda	secbuf+$100,x
	cmp	#$20
	bmi	]notasc2
	cmp	#$7E
	bmi	]done2
]notasc2	lda	#32
]done2	jsr	cout
	inx	
	bne	]next2

	jsr	crout

	ldy	#0
]next3	lda	secbuf+1,y
	tax	
	lda	secbuf,y
	phy	
	jsr	prax
	ply	
	iny	
	iny	
	bne	]next3

]next4	lda	secbuf+$101,y
	tax	
	lda	secbuf+$100,y
	phy	
	jsr	prax
	ply	
	iny	
	iny	
	bne	]next4

	jsr	crout

	ply	
	plx	
	pla	
	rts