;----------------------------------------------------------------------------
;File name:	CALLS.S				Revision date:	1999.11.05
;Revised by:	Ulf Ronald Andersson		Revision start:	1999.11.04
;Created by:	Peter Rottengatter		Creation date:	1997.09.28
;----------------------------------------------------------------------------
;Project:	Serial port driver for STinG
;Module:	Assembler subroutines
;----------------------------------------------------------------------------
	.export	sim_Bconstat		;Function for simulated Bconstat
	.export	sim_Bcostat		;Function for simulated Bconstat
	.export	sim_Fread		;Function for simulated Fread
	.export	sim_Fwrite		;Function for simulated Fwrite
	.export	execute			;Function to execute status calls
	.export	inq_cd			;Function for inquiring DCD status
	.export	set_dtr			;Function for setting DTR status
	.export	choose_magic		;Function for getting a random magic
;----------------------------------------------------------------------------
;prototype:	int32	sim_Bconstat(MAPTAB *map);
;-------------------------------------
sim_Bconstat:
	move.l	5*4(a0),a1		;a1 -> IOREC of port
	moveq	#0,d0			;clear high bits of d0
	move	$08(a1),d0		;d0 = Rx_tail_ix
	sub	$06(a1),d0		;d0 -= Rx_head_ix
	bcc.s	.valid_diff		;if tail>=head, keep positive d0
	add	$04(a1),d0		;else d0 += Rx_size_ix
.valid_diff:
	rts
;----------------------------------------------------------------------------
;prototype:	int32	sim_Bcostat(MAPTAB *map);
;-------------------------------------
sim_Bcostat:
	move.l	5*4(a0),a1		;a1 -> IOREC of port
	moveq	#0,d0			;clear high bits of d0
	move	$14(a1),d0		;d0 = Tx_head_ix
	sub	$16(a1),d0		;d0 -= Tx_tail_ix
	bhi.s	.valid_diff		;if head>tail, keep positive d0
	add	$12(a1),d0		;else d0 += Tx_size_ix
.valid_diff:
	subq	#2,d0			;d1 = safe_room
	bpl.s	.valid_room		;if positive, all is well
	moveq	#$00,d0			;else force d1 = 0
.valid_room:
	rts
;----------------------------------------------------------------------------
;prototype:	int32	sim_Fread(MAPTAB *map, uint32 cnt, char *buf);
;-------------------------------------
sim_Fread:
	movem.l	a2-a4,-(sp)		;push entry a2-a4
	move.l	a1,a3			;a3 = buf
	move.l	a0,a4			;a4 -> MAPTAB of port
	move.l	5*4(a4),a2		;a2 -> IOREC of port
	move	$04(a2),d2		;d2 = Rx_size_ix
	moveq	#$00,d1			;clear high bits of d1
	move	$08(a2),d1		;d1 = Rx_tail_ix
	sub	$06(a2),d1		;d1 -= Rx_head_ix
	bcc.s	.valid_diff		;if tail>=head, keep positive d1
	add	d2,d1			;else d1 += Rx_size_ix
.valid_diff:
	cmp.l	d0,d1			;available < wanted ?
	bcc.s	.valid_count		;else use wanted count
	move.l	d1,d0			;d0 = available byte count
.valid_count:
	move.l	d0,-(a7)		;push count
	beq.s	.exit			;exit if count==0
	subq.l	#2,d0			;d0 = dbra value for count-1
	bcs.s	.done_loop		;if count == 1, skip loop
	movea.l	(a2),a0			;a0 = Rx_buffer_p
	move	$06(a2),d1		;d1 = Rx_head_ix
.read_loop:
	addq	#1,d1			;d1 += 1
	cmp	d2,d1			;d1 >= Rx_size_ix ?
	bcs.s	.done_index_wrap
	moveq	#$00,d1			;d1 = zero index
.done_index_wrap:
	move.b	$00(a0,d1.l),(a3)+	;transfer byte to arg buffer
	dbra	d0,.read_loop		;loop for all but last char
	move	d1,$06(a2)		;Rx_head_ix = d1
.done_loop:
	move.l	1*4(a4),a1		;a1 -> Bconin code of port
	jsr	(a1)			;use Bconin for last char
	move.b	d0,(a3)			;store last char
.exit:
	movem.l	(sp)+,d0/a2-a4		;pull d0=count and entry a2-a4
	rts				;return to caller
;----------------------------------------------------------------------------
;prototype:	int32	hsm_dev_write(MAPTAB *map, uint32 cnt, char *buf);
;-------------------------------------
sim_Fwrite:
	movem.l	a2/a4,-(sp)		;push entry a2/a4
	move.l	a0,a4			;a4 -> MAPTAB of port
	move.l	5*4(a4),a2		;a2 -> IOREC of port
	move	$12(a2),d2		;d2 = Tx_io_size_ix
	moveq	#$00,d1			;clear high bits of d1
	move	$0014(a2),d1		;d1 = Tx_io_head_ix
	sub	$0016(a2),d1		;d1 -= Tx_io_tail_ix
	bhi.s	.valid_diff		;if head>tail, keep positive d1
	add	d2,d1			;d1 += Tx_io_size_ix
.valid_diff:
	subq.l	#2,d1			;d1 = safe_room
	bpl.s	.valid_room		;if positive, all is well
	moveq	#$00,d1			;else force d1 = 0
.valid_room:
	cmp.l	d0,d1			;safe_room < wanted ?
	bcc.s	.valid_count		;else use wanted count
	move.l	d1,d0			;d0 = safe_room count
.valid_count:
	move.l	d0,-(a7)		;push count
	beq.s	.exit			;exit if count == 0
	subq.l	#2,d0			;d0 = dbra value for count-1
	bcs.s	.done_loop		;if count==1, skip loop
	movea.l	$000E(a2),a0		;a0 = Tx_io_buffer_p
	move	$0016(a2),d1		;d1 = Tx_io_tail_ix
.write_loop:
	addq	#1,d1			;d1 += 1
	cmp	d2,d1			;d1 >= Tx_io_size_ix ?
	bcs.s	.done_index_wrap
	moveq	#$00,d1			;d1 = zero index
.done_index_wrap:
	move.b	(a1)+,$00(a0,d1.l)	;transfer byte from arg buffer
	dbra	d0,.write_loop		;loop for all but last char
	move	d1,$0016(a2)		;Tx_io_tail_ix = d1
.done_loop:
	move.b	(a1),d0			;d0 = last char
	move.l	d0,-(a7)		;push last char as arg
	move.l	3*4(a4),a1		;a1 -> Bconout code of port
	jsr	(a1)			;use Bconout for last char
	addq.l	#4,a7			;clean stack
.exit:
	movem.l	(sp)+,d0/a2/a4		;pull d0=count and entry a2/a4
	rts				;return to caller
;----------------------------------------------------------------------------
;prototype:	int	execute (int status());
;-------------------------------------
execute:
	movem.l	d3-d7/a2-a6,cpu_state	;Save CPU register
	jsr	(a0)			;Call status code
	movem.l	cpu_state,a2-a6/d3-d7	;Restore CPU register
	rts
;-------------------------------------------------------------------------------------)
;prototype:	int	inq_cd (void *hsm_code);
;-------------------------------------
inq_cd:
	move.l	#$5482,d0		;Do a Fcntl (...,TIOCCTLGET);
	move.l	#$0010,status		;Inquire Carrier Detect
	bsr	exec_hsm		;Call HSMODEM code
	move.w	#$0010,d0		;Preset return to DCD = TRUE
	tst.l	d0			;Error occured ?
	bmi	cd_set			;Yes, return TRUE
	move.l	status,d0		;Otherwise get status
cd_set:
	and.w	#$0010,d0		;And isolate DCD
	rts
;-------------------------------------------------------------------------------------)
;prototype:	void	set_dtr (void *hsm_code, int new_dtr);
;-------------------------------------
set_dtr:
	clr.l	status+4		;Preset status to DTR = FALSE
	tst.w	d0			;Was that intended ?
	beq	dtr_ok			;Yes, OK
	move.l	#$0002,status+4		;Otherwise set DTR = TRUE
dtr_ok:
	move.l	#$5483,d0		;Do a Fcntl (..., TIOCCTLSET);
	move.l	#$0002,status		;Data Terminal Ready is meant
	bsr	exec_hsm		;Call HSMODEM code
	rts
;-------------------------------------------------------------------------------------)
;prototype:	long	exec_hsm(uint16 Fcntl_opcode, void *Fcntl_arg)
;-------------------------------------
exec_hsm:
	movem.l	d3-d7/a2-a6,cpu_state	;Save CPU register
	move.l	a0,a2			;Command code
	lea	status,a1		;Pointer for return value
	clr.l	a0			;No file descriptor
	jsr	(a2)			;Call HSMODEM code
	movem.l	cpu_state,a2-a6/d3-d7	;Restore CPU register
	rts
;-------------------------------------------------------------------------------------)
bus_vec		=	$08
_vblqueue	=	$456
_frclock	=	$466
vid_c_hi	=	$ffff8205
vid_c_med	=	$ffff8207
vid_c_low	=	$ffff8209
;-------------------------------------
;prototype:	long	choose_magic (void);
;-------------------------------------
choose_magic:
	movem.l	d1-d2,-(sp)		;Save D1 and D2
	move.w	sr,status		;Save status word
	or.w	#$0700,sr		;Disable all interrupts
	move.l	sp,stack		;Save stack pointer
	move.l	bus_vec,saved_bus	;Save bus error vector
	move.l	#failure,bus_vec	;Enable our bus error handler
;-------
	move.b	vid_c_low,d0		;Video counter low byte
	asl.l	#8,d0			;In bits 8 bis 15
	move.b	vid_c_med,d0		;Video counter medium byte
	asl.l	#8,d0			;In bits 8 bis 15
	move.b	vid_c_hi,d0		;Video counter high byte
	asl.l	#8,d0			;Whole counter in D0
skip_it:	move.l	_vblqueue,d1	;Queue pointer, little random
	eor.l	d1,d0			;Exclusive or'd
	move.l	_frclock,d1		;Number of screen refreshs
	move.w	d1,d2			;Is pretty random
	mulu.w	d2,d1			;Now squared
	and.l	#$1f,d1			;But only between 0 and 31
	rol.l	d1,d0			;Rotate as many times
;-------
	move.l	saved_bus,bus_vec	;Restore bus error vector
	move.l	stack,sp		;Restore stack pointer
	move.w	status,sr		;Restore status word
	movem.l	(sp)+,d1-d2		;Restore D1 and D2
	rts
;-------------------------------------
failure:
	move.l	stack,sp		;Restore stack pointer
	bra		skip_it		;Continue
;-------------------------------------------------------------------------------------)
walk:		ds.l	1		;Pointer into buffer
remain:		ds.w	1		;Remaining bytes
mark:		ds.w	1		;End-of-data mark
code:		ds.l	1		;Pointer to code to be called
status:		ds.l	2		;Pointer to check function
stack:		ds.l	1		;Saved stack pointer
saved_bus:	ds.l	1		;Saved bus error vector
;-------------------------------------
cpu_state:	ds.l	10		;Save area for CPU registers
;-------------------------------------------------------------------------------------)
	.end
;----------------------------------------------------------------------------
;End of file:	CALLS.S
;----------------------------------------------------------------------------
