;File name:	BORDER_1.S			Revised:	1993.07.01
;EXTRA_74.S by Alex Johnson
;
;This code was written using devpac ST version 2
;
	include	URAn_DOS.S
;
	opt	o+			;optimisations on
	opt	ow-			;warnings off
	opt	d+			;debug on
;
	output	.tos			;set tos output
;
;
;gemdos start up
;
start_up:
	move.l	4(sp),a0		
	move.l	bp_textlen(a0),d0		
	add.l	bp_datalen(a0),d0		
	add.l	bp_bss_len(a0),d0		
	add.l	#$1000,d0		
	add.l	#$100,d0		
	gemdos	Mshrink,!,(a0),d0
;
	gemdos	Super,!
	move.l	d0,entry_ssp
	lea	mstack,sp		;set my stack to avoid misshaps
;
;$ffff8240.w is the first colour palette register
;
	movem.l	$ffff8240.w,d0-d7	;save old palette
	movem.l	d0-d7,oldpal
;
	movem.l	blackout,d0-d7		;black out screen
	movem.l	d0-d7,$ffff8240.w
;
	move.b	#$12,(hw_kbdata).w	;mouse off
;	
	move.b	(conterm).w,old_conterm		;save key stats
	bclr 	#0,(conterm)			;no keyclick
	bclr 	#1,(conterm)			;no repeat key
;
;$ffff820a.w is the sync mode register (50hz or 60hz)
;$ffff8260.w is the resolution register
;
	move.b  $ffff820a.w,oldsync	;save sync mode
	move.b	$ffff8260.w,d0		;get old res
	and.l	#3,d0			;mask off unwanted bits
	move	d0,oldres		;save old res
;
	bsr     vsync_sub		;wait for the vbl
;
	move.b  #2,$ffff820a.w		;50HZ
	clr.b   $ffff8260.w		;Lowres
;
	move.w  #2,-(sp)		;get physbase
	trap    #14
	addq.l  #2,sp
	move.l  d0,physbase_p		;save it
;
	move.w  #3,-(sp)		;get logbase
	trap    #14
	addq.l  #2,sp
	move.l  d0,logbase_p		;save it
;
;now we come to reserving some screen memory
;this source only needs one screen but by changing
;number in d0 you can reserve two or more screens
;
;the normal screen is 32k but we are adding another
;74 lines to this screen so we need to make the area
;larger and this is how I work it out.
;
;one screen line = 160 bytes
;normal screen = 200 lines
;divide this number by 1024 (one kilobyte)
;and then ALWAYS round it up to the nearest whole number.
;for a normal screen you would use:
;
;200 * 160 = 32000
;32000/1024 = 31.25
;screen = 32k
;
;but for this screen we use:
;
;274 * 160 = 43840
;36640/1024 = 42.81
;screen = 43k
;
	move.l  #(43*1024),d0		;one 43k screen
	bsr     reservemem		;malloc the memory		
	move.l  d0,screenmem		;save memory address
	and.l   #-256,d0		;start on 256 byte boundary
	add.l   #256,d0			;just to make sure
	move.l  d0,viewscreen		;set screen address
;
	move.l	viewscreen,d0		;show the viewscreen
	lsr.l	#8,d0
	move.b	d0,$ffff8203.w		;set vdbase low
	lsr.w	#8,d0
	move.b	d0,$ffff8201.w		;set vdbase high
;
	bsr	fillscreen
	move	#$2700,sr		;switch off the interrupts
	bsr	set_ints		;put in our ones
	move	#$2300,sr		;switch them back on again
;
	move	#$777,$ffff8242.w	;show the screen
;
;now hopefully both borders should now be missing
;
.loop_1
	cmp.b	#$39,(hw_kbdata).w	;space?
	bne.s	.loop_1
;
	move	#$2700,sr		;switch off the interrupts
	bsr	restore_ints		;put back the old ones
	move	#$2300,sr		;switch them back on again
;
	movem.l	blackout,d0-d7		;black out colours
	movem.l	d0-d7,$ffff8240.w
;
	move.b	oldsync,$ffff820a.w	;restore old sync
	gemdos	Setscreen|_ind,logbase_p(pc),physbase_p(pc),oldres(pc)
;
	move.b	#8,(hw_kbdata).w	;mouse on
	move.b	old_conterm,(conterm).w		;restore key stats
;
	move.l	screenmem,d0		;free screen memory
	bsr	freemem
;
	movem.l	oldpal,d0-d7		;restore old pal
	movem.l	d0-d7,$ffff8240.w
;
	gemdos	Super|_ind,entry_ssp(pc)
	gemdos	Pterm,!
;
;
;sync with the electron beam
;to do this we check the fr clock register
;which is incremented every 50th second and wait
;for a different value
;
vsync_sub:
	move.l	d0,-(sp)
	move.l	(_frclock).w,d0		;fr clock
.loop_1
	cmp.l	(_frclock).w,d0		;check value
	beq.s	.loop_1			;is it the same?
	move.l	(sp)+,d0
	rts
;
;
;use MALLOC to reserve some memory
;amount of memory needed is in d0
;	
reservemem:
	move.l	d0,-(sp)		;area of memory
	move	#$48,-(sp)		;malloc
	trap	#1
	addq.l	#6,sp
	rts
;
;
;free the memory previously reserved with reserve mem
;address of memory is in d0
;
freemem:
	move.l	d0,-(sp)		;address of memory
	move	#$49,-(sp)		;free mem
	trap	#1
	addq.l	#6,sp
	rts
;
;
;this fills the screen with a line pattern
;one bitplane only
;274 lines
;
fillscreen:
	movem.l	d0-d2/a0,-(sp)
	move.l	viewscreen,a0		;screen address
	move	#(274-1),d2		;screen lines to do
	clr	d0
.loop_1:
	btst	#2,d0
	sne	d1
	ror	#1,d1
	and	#$8000,d1
	or	#1,d1
	add	d0,d1
	add	d0,d1
	add	d0,d1
	add	d0,d1
	rept	160/8
	move	d1,(a0)+
	clr	(a0)+
	clr.l	(a0)+
	endr
	addq	#1,d0
	dbra	d2,.loop_1			;do all screen lines
	movem.l	(sp)+,d0-d2/a0
	rts
;
;
;initialise timer b interrupt to
;remove the bottom border and
;switch off timer c to avoid any
;interference.
;it also initialises our vbl interrupt
set_ints:
	move.l	$70.w,old_vbl		;save old vbl
	move.l	$120.w,old_hbl		;save old timer b vector
	move.b	$fffffa07.w,olda07	;save old mfp registers
	move.b	$fffffa09.w,olda09
	move.b	$fffffa13.w,olda13
	move.b	$fffffa15.w,olda15
	move.b	$fffffa17.w,olda17
	move.b	$fffffa1b.w,olda1b
	move.b	$fffffa21.w,olda21
	andi.b	#$df,$fffffa09.w	;timer c off
	andi.b	#$fe,$fffffa07.w	;timer b off
	ori.b	#1,$fffffa07.w		;init timer b
	ori.b	#1,$fffffa13.w
	bclr	#3,$fffffa17.w		;set automatic end of interrupt
	bset	#6,$fffffa09.w
	bset	#6,$fffffa15.w
	move.l	#ourvbl,$70.w		;set up our vbl
	rts
;
;
;restore all system interrupts
;
restore_ints:
	move.l	old_vbl,$70.w		;restore old vbl
	move.l	old_hbl,$120.w		;restore old timer b vector
	move.b	olda07,$fffffa07.w	;restore old mfp registers
	move.b	olda09,$fffffa09.w
	move.b	olda13,$fffffa13.w
	move.b	olda15,$fffffa15.w
	move.b	olda17,$fffffa17.w
	move.b	olda1b,$fffffa1b.w
	move.b	olda21,$fffffa21.w
	rts
;
;
ourvbl:
;first thing we do is remove the top border
;we need to wait 17218 clock cycles before opening
;the top border. Don`t ask me why this is because i
;don't know
;
;URAn:  Well I know that the time given above is inaccurate (but works)
;URAn:  Better formulas are given below
;
;DO NOT CHANGE THE FOLLOWING PIECE OF CODE

;if you do the hertz changes may occur in the wrong
;places and the desired effect will not be achieved
;
kh	= 0
kt	= 1024*kh
mindel_1	= 16818-kt 		;clock cycles == 1051.125 us == 16.42 t(H)
maxdel_1	= mindel_1+416		;maxdel_1-mindel_1 == 26 us
avgdel_1	= (mindel_1+maxdel_1)/2
dbra_c_1	= ((avgdel_1-156)-14)/12
usedel_1	= dbra_c_1*12+14+156	;delay before switching to 60Hz
;
mindel_2	= maxdel_1+12-usedel_1
maxdel_2	= mindel_2+36		;maxdel_2-mindel_2 == 2.25 us
avgdel_2	= (mindel_2+maxdel_2)/2	;delay time before switching back
nopcnt_2	= (avgdel_2+2)/4
;
	move.w	#$2700,sr			;16 \
	movem.l	d0-d7/a0-a6,regis		;132 > 156
	move	#dbra_c_1,d0	;8  /
.vbl_loop_1
	dbra	d0,.vbl_loop_1			;(1420*12)+14 = 17054
;
;60Hz/50Hz switch opens border so fast that is isn`t noticed
;
	move.b	#0,$ffff820a.w		;60hz
	rept	nopcnt_2
	nop
	endr
	move.b	#2,$ffff820a.w		;back to 50hz
;
;if all has gone well the top border has now been removed
;now we have to set up timer b to remove the bottom border.
;
	clr.b	$fffffa1b.w		;stop timer b
	move.b	#228+kh,$fffffa21.w	;set it to occur on line 228
	move.l	#ourtb,$120.w		;set up our timer b vector
	move.b	#8,$fffffa1b.w		;start timer b
	movem.l	regis,d0-d7/a0-a6	;restore registers
	st	vblflag			;signal we have finished
	rte				;finish
;
;
;this is the timer b interrupt that removes
;the bottom screen border
ourtb:
	clr.b	$fffffa1b.w		;stop timer b
	movem.l	a0/d0,-(sp)		;save a0 and d0
	lea	$fffffa21.w,a0		;timer b data register
	move.b	#255,(a0)		;set it to occur below screen bottom
	move.b	#8,$fffffa1b.w		;start timer b
	moveq	#0,d0			;clear d0
	move.b	(a0),d0			;get timer b data
.1
	cmp.b	(a0),d0			;compare timer b data
	beq.s	.1			;is it the same?
;
;here is another 60hz/50hz switch
;
	clr.b	$ffff820a.w		;60hz
	moveq	#3,d0			;we need to
.2
	nop				;wait a little while
	dbra	d0,.2			;for the switch to take effect
	move.b	#2,$ffff820a.w		;back to 50hz
;
;the bottom border is now history
;
	movem.l	(sp)+,a0/d0		;restore a0 and d0
	clr.b	$fffffa1b.w		;stop timer b
	rte				;finish
;
;
	section	bss
;
entry_ssp	ds.l	1
		ds.l	512		;my stack
mstack		ds.l	1		;stacks go backwards
oldpal		ds.w	16		;old palette
blackout	ds.w	16		;black out colours
old_conterm	ds.b	1		;old key status
oldsync		ds.b	1		;old sync mode
oldres		ds.w	1		;old resolution
logbase_p	ds.l	1		;logical screen
physbase_p	ds.l	1		;physical screen
screenmem	ds.l	1		;screen memory address
viewscreen	ds.l	1		;new screen
;
old_vbl		ds.l	1		;old vbl ($70.w)
old_hbl		ds.l	1		;old timer b ($120.w)
;
olda07		ds.b	1		;old mfp registers
olda09		ds.b	1
olda13		ds.b	1
olda15		ds.b	1
olda17		ds.b	1
olda1b		ds.b	1
olda21		ds.b	1
vblflag		ds.b	1		;vbl flag
;
		even
;
regis		ds.l	16		;store for the 16 registers
;
;
;End of file:	BORDER_1.S