	TTL	fastVBR
	IDNT	fastVBR_0103
	SECTION fastVBR_code,CODE
;
;----------------------------------------------------------------------------
;
;   NAME:	fastVBR, (c)1991,1992 All Rights Reserved.
;
;   AUTHOR:	Mark C. Barnes
;		E-Mail Address:  Aurelius@cup.portal.com
;
;   VERSION:	v1.03
;
;   DATE:	June 10, 1991
;
;   DISCLAIMER:
;
;	fastVBR is FreeWare. The author accepts no responsibility for any
;	damages or loss of data that may be attributed to the use of this
;	program. This source is provided to show how fastVBR works. Please
;	contact the author, at the above EMail address, with any comments or
;	questions. Enjoy!
;
;   DESCRIPTION:
;
;	Program to move the 68000 Exeception Vector Table from CHIP RAM
;	to FAST RAM. The vector table normally begins at absolute address
;	0x00000000 for the Amiga's 68000. This memory is in SLOW CHIP RAM!
;	which affects the systems interrupt performace under heavy graphics,
;	or other DMA loads.
;
;	After the EVT has been moved to FAST RAM, the 68000 Exeception
;	Vector Table CHIP RAM memory is added to EXEC's MEMLIST. The
;	vector table normally begins at absolute address 0x00000000 for the
;	Amiga's 68000. The first two vectors are considered as in use, since
;	$00000004 contains the EXEC Library base address. The memory from
;	$00000008 to $000003FF is actually CHIP RAM that has never been added
;	the EXEC's MEMLIST, since it is reserved for the 68000.
;
;	For Amiga's with a 68010, 68020, 68030, or 68040 cpu, this program
;	will allocate 256 longwords of PUBLIC FAST RAM and safely copy the
;	the Exception Vector Table from 0x00000000 thru 0x000003ff to the
;	new FAST RAM location. Once this is done, the new location will be
;	written into the 68010 VBR (Vector Base Register). It will then
;	add the 254 longwords, from 0x00000008, to EXEC's MEMLIST as PUBLIC
;	CHIP RAM. A new MEMHEADER containing the particulars for this CHIP
;	RAM is created in FAST RAM. The MEMHEADER is initialized with:
;
;	    LN_TYPE	    :	NT_MEMORY
;	    LN_PRI	    :	-10
;	    LN_NAME	    :	"EVT Chip RAM"
;	    MH_ATTRIBUTES   :	MEMF_PUBLIC | MEMF_CHIP
;	    MH_FIRST	    :	$00000008
;	    MH_LOWER	    :	$00000008
;	    MH_UPPER	    :	$000003FF
;	    MH_FREE	    :	1016
;
;	Once this is done, the new CHIP RAM will be available to the system.
;
;   INPUTS:
;
;	None.
;
;   OUTPUTS:
;
;	SP	- 32 bit AmigaDOS status, 0 = Success, 5 = Warn, 10 = Fatal.
;
;   REGISTER VARIABLES:
;
;	D7  =	Exit Code
;	D5  =	Trap Status
;	D4  =	Allocated Flags
;
;	A6  =	Exec Base
;	A5  =	New MemHeader Address
;	A4  =	Old EVT Address
;	A3  =	New EVT Address
;
;   CALLING SEQUENCE:
;
;	From the CLI or SHELL:
;
;	fastVBR
;
;   EDIT HISTORY:
;
;	MCB03	January 24, 1992    Allow for SLOW FAST RAM, since these
;				    Amigas need the CHIP RAM the most.
;
;	MCB02	January 14, 1992    Incorporated code to add old EVT memory
;				    at 0x00000008 to system as CHIP RAM.
;
;	MCB01	January 14, 1992    Changed entry to Supervisor Mode from
;				    68000 TRAP to EXEC's SUPERVISOR function.
;
;----------------------------------------------------------------------------
	PAGE

;----------------------------------------------------------------------------
; include files
;----------------------------------------------------------------------------

	NOLIST

	INCLUDE "startup1.3/AStartup.i" ; "C" style AMIGA startup module

	INCLUDE "exec/execbase.i"       ; EXEC Library structure
	INCLUDE "exec/memory.i"         ; EXEC memory stuff

	LIST
	PAGE

;----------------------------------------------------------------------------
; global declarations
;----------------------------------------------------------------------------

	XDEF	_main			; main entry point for AStartup.obj

;
; global references provided by Amiga.lib
;

	XREF	_LVOAllocMem		; EXEC memory allocator
	XREF	_LVOEnqueue		; EXEC enqueue list function
	XREF	_LVOForbid		; EXEC forbid multi-tasking
	XREF	_LVOFreeMem		; EXEC memory deallocator
	XREF	_LVOPermit		; EXEC permit multi-tasking
	XREF	_LVOSupervisor		; EXEC Supervisor Mode function
	XREF	_LVOWrite		; DOS function to write a string

	XREF	_printf 		; "C" style DOS print function
	XREF	_puts			; "C" style DOS write function
;
; global references provided by AStartup.obj
;
	XREF	_DOSBase		; DOS Library base address
	XREF	_exit			; AStartup.obj "C" EXIT function
	XREF	_stderr 		; DOS file handles for CLI I/O
	XREF	_stdin			; they all send to CON: or NEWCON:
	XREF	_stdout 		; CLI window unless redirected.
;
; user written globals
;

	PAGE

;----------------------------------------------------------------------------
; global constants
;----------------------------------------------------------------------------

Fatal		EQU	10		; failure DOS exit code
Succ		EQU	0		; success DOS exit code
Warn		EQU	5		; warning DOS exit code

sizeofEVT	EQU	1024		; byte size of 68010 Exception Table
EVTTable	EQU	0		; Allocated FAST VBR memory

EVTChipRegion	EQU	$00000008	; Address of EVT CHIP RAM area
sizeofRegion	EQU	1016		; byte size of CHIP RAM area

MemHeader	EQU	1		; Allocated MemHeader structure
RegionPri	EQU	-10		; Priority of memory region

;
; symbols used to hand assemble 68010 MOVEC instruction
;

MOVEC		EQU	$4E7A0000	; dc.l MOVEC+VBR_TO_D0
D0_TO_VBR	EQU	$00010801
VBR_TO_D0	EQU	$00000801

;----------------------------------------------------------------------------
; local macros
;----------------------------------------------------------------------------

.LONG	MACRO	; macro to longword align the program counter (PC)
	NOLIST

	CNOP	0,4

	LIST
	ENDM

;============================================================================
; E X E C U T A B L E  C O D E
;============================================================================

	.LONG

;----------------------------------------------------------------------------
; local functions
;----------------------------------------------------------------------------

;
; function to perform a clean exit
;

cleanExit:
	btst.b	#EVTTable,d4		; IF  ( allocated memory )
	beq	10$			; THEN
	move.l	#sizeofEVT,d0		;  D0 = size in bytes
	movea.l a3,a1			;  A1 = address of memory
	jsr	_LVOFreeMem(a6)         ;  call EXEC FREEMEM function
					; ENDIF
10$:
	btst.b	#MemHeader,d4		; IF  ( allocated memory )
	beq	20$			; THEN
	move.l	#MH_SIZE,d0		;  D0 = size in bytes
	movea.l a5,a1			;  A1 = address of memory
	jsr	_LVOFreeMem(a6)         ;  call EXEC FREEMEM function
					; ENDIF
20$:
	move.l	d7,-(sp)                ; push DOS exit code
	jsr	_exit			; call ASTARTUP EXIT function
					; WILL NOT RETURN

;----------------------------------------------------------------------------
; MAIN entered from AStartup.obj
;
; File Handles: _stdin, _stdout and _stderr are open for use.
; Library Base: A6 contains address of Exec Library.
;----------------------------------------------------------------------------


_main:
	moveq	#0,d4			; nothing Allocated yet.
	moveq	#Succ,d7		; assume success

;
; print introductory message
;

	pea	Welcome 		; push first part of string
	jsr	_printf 		; write it
	addq.l	#4,sp			; pop string
	tst.l	d0			; IF  ( status <= 0 )
	bgt	05$			; THEN
	move.l	#Fatal,d7		;  set DOS exit code
	bra	cleanExit		;  abort
					; ENDIF

05$:
	pea	Welcome1		; push second part of string
	jsr	_puts			; write it
	addq.l	#4,sp			; pop string
	tst.l	d0			; IF  ( status <= 0 )
	bgt	08$			; THEN
	move.l	#Fatal,d7		;  set DOS exit code
	bra	cleanExit		;  abort
					; ENDIF

08$:
	pea	Welcome2		; push third part of string
	jsr	_puts			; write it
	addq.l	#4,sp			; pop string
	tst.l	d0			; IF  ( status <= 0 )
	bgt	10$			; THEN
	move.l	#Fatal,d7		;  set DOS exit code
	bra	cleanExit		;  abort
					; ENDIF

;
; 1. check for 68010 or higher processor
;

10$:
	move.w	AttnFlags(a6),d0        ; D0 = EXEC Special attention flags
	andi.w	#(AFF_68010!AFF_68020),d0 ; IF ( cpu < 68010 )
	bne	20$			; THEN
	pea	ErrCPU			;  push string
	jsr	_puts			;  tell user not supported
	addq.l	#4,sp			;  pop string
	move.l	#Fatal,d7		;  set DOS exit code
	bra	cleanExit		;  abort
					; ENDIF

;
; 2. try to allocate 1024 bytes of FAST PUBLIC RAM for EVT.
;

20$:
	move.l	#sizeofEVT,d0		; D0 = number of bytes to allocate
	move.l	#(MEMF_FAST!MEMF_PUBLIC),d1 ; D1 = type of memory
	jsr	_LVOAllocMem(a6)        ; call EXEC ALLOCMEM function
	movea.l d0,a3			; IF  ( ! EVT address )
	bne	30$			; THEN
	pea	ErrNoMem		;  push string
	jsr	_puts			;  tell user no FAST memory
	addq.l	#4,sp			;  pop string
	move.l	#Fatal,d7		;  set DOS exit code
	bra	cleanExit		;  abort
					; ENDIF
30$:
	bset.b	#EVTTable,d4		; remember memory is Allocated

;
; 3. warn user if it is only SLOW FAST RAM ( 0x00c00000 )
;

	cmpi.l	#$00c00000,d0		; IF ( address > 16bit FAST MEM )
	blt	40$			; AND
	cmpi.l	#$00d80000,d0		;  IF ( address < 32bit FAST MEM )
	bgt	40$			;  THEN
	pea	ErrSlMem		;   push string
	jsr	_puts			;   tell user not true FAST memory
	addq.l	#4,sp			;   pop string
	move.l	#Warn,d7		;   set DOS exit code
					;  ENDIF
					; ENDIF

;
; 4. copy Vector table to FAST RAM location.
;

40$:
	lea	VBRTrapCode,a5		; A5 = Supervisor function address
	jsr	_LVOSupervisor(a6)      ; call EXEC Supervisor mode

;
; 5. if that was successfull, add the memory as CHIP RAM
;
	tst.l	d5			; SWITCH ( Trap Status )
	ble	Failed			; DEFAULT:
	bclr.b	#EVTTable,d4		;  forget memory Allocated
	move.l	a3,-(sp)                ;  push EVT address
	pea	SuccessEVT		;  push string
	jsr	_printf 		;  tell user successfull
	addq.l	#8,sp			;  pop arguments

;
; 6. try to allocate a MemHeader structure from PUBLIC FAST RAM
;

50$:
	move.l	#MH_SIZE+sizeofName,d0	;  D0 = number of bytes to allocate
	move.l	#(MEMF_FAST!MEMF_PUBLIC),d1 ; D1 = type of memory
	jsr	_LVOAllocMem(a6)        ;  call EXEC ALLOCMEM function
	movea.l d0,a5			;  IF  ( ! MemHeader address )
	bne	60$			;  THEN
	pea	ErrNoMem		;   push string
	jsr	_puts			;   tell user no FAST memory
	addq.l	#4,sp			;   pop string
	move.l	#Fatal,d7		;   set DOS exit code
	bra	cleanExit		;   abort
					;  ENDIF
60$:
	bset.b	#MemHeader,d4		;  remember memory is Allocated

;
; 7. build a MemChunk at the beginning of the EVT CHIP RAM
;

	movea.l #EVTChipRegion,a0	;  A0 = address of CHIP Region
	move.l	#0,MC_NEXT(a0)          ;  only one chunk in region
	move.l	#sizeofRegion,MC_BYTES(a0) ; region is 1016 bytes

;
; 8. initialize the MemHeader information
;

	move.b	#NT_MEMORY,LN_TYPE(a5)  ;  node type is memory
	move.b	#RegionPri,LN_PRI(a5)   ;  node (region) priority

	lea	RegionName,a0		;  A0 = local regions's name
	movea.l a5,a1			;  A1 = MemHeader's address
	adda.l	#MH_SIZE,a1		;  A1 = PUBLIC region's name
	move.l	a1,LN_NAME(a5)          ;  node (region) name (in PUBLIC RAM)

	move.l	#sizeofName,d0		;  D0 = length to copy
65$:					;  FOR ( length of name )
	move.b	(a0)+,(a1)+             ;   copy a byte
	dbeq	d0,65$			;  ENDFOR

	move.w	#(MEMF_CHIP!MEMF_PUBLIC),MH_ATTRIBUTES(a5) ; type of memory
	move.l	#EVTChipRegion,MH_FIRST(a5) ; load first memory chunk
	move.l	#EVTChipRegion,MH_LOWER(a5) ; load first address
	move.l	#EVTChipRegion+sizeofRegion,MH_UPPER(a5) ; load last address
	move.l	#sizeofRegion,MH_FREE(a5) ; load free memory bytes

;
; 9. add MemHeader to EXEC's MEMLIST
;

	jsr	_LVOForbid(a6)          ;  forbid multi-tasking
	movea.l MemList(a6),a0          ;  A0 = EXEC's memory list
	movea.l a5,a1			;  A1 = new MemHeader
	jsr	_LVOEnqueue(a6)         ;  call EXEC ENQUEUE list function
	jsr	_LVOPermit(a6)          ;  permit multi-tasking
	bclr.b	#MemHeader,d4		;  forget memory Allocated

	pea	SuccessMEM		;  push string
	jsr	_puts			;  tell user successfull
	addq.l	#4,sp			;  pop arguments
	bra	cleanExit		;  exit

Failed:
	blt	AlreadyDone		; CASE 0:
	pea	Failure1		;  push string
	jsr	_puts			;  tell user couldn't do it
	addq.l	#4,sp			;  pop string
	move.l	#Fatal,d7		;  set DOS exit code
	bra	cleanExit		;  exit

AlreadyDone:				; CASE -1:
	move.l	a4,-(sp)                ;  push EVT address
	pea	Failure2		;  push string
	jsr	_printf 		;  tell user already done
	addq.l	#4,sp			;  pop string
	moveq	#Warn,d7		;  set DOS exit code
	bra	cleanExit		;  exit
					; ENDSWITCH
	PAGE


;----------------------------------------------------------------------------
; 68010 Vector Base Register Handler
; NOTE: this subroutine runs in SUPERVISOR mode, with the following stack:
;
;	SSP+12	680x0 specific exception stack frame
;	SSP+8	we saved A0
;	SSP+4	we saved A1
;	SSP	we saved D0
;----------------------------------------------------------------------------


VBRTrapCode:
	move.l	a0,-(sp)                ; push A0 onto SSP
	move.l	a1,-(sp)                ; push A1 onto SSP
	move.l	d0,-(sp)                ; push D0 onto SSP

;
; check to see if the 68010 VBR register is zero.
;

	dc.l	MOVEC+VBR_TO_D0 	; D0 = VBR (hand assembled)
	tst.l	d0			; IF ( VBR != 0 )
	bne	VBR_is_Fast		; THEN report already done

;
; copy Exception Table to FAST memory using 68010 LOOP mode
;

	movea.l d0,a0			; A0 = old exception table
	movea.l a3,a1			; A1 = new exception table

	move.l	#255,d0 		; FOR ( count = 255 )
Loop:	move.l	(a0)+,(a1)+             ;  copy longword
	dbra	d0,Loop 		; UNTIL ( --count == -1 )

;
; write new Exception Table address to 68010 Vector Base Register
;

	move.l	a3,d0			; D0 = new VBR
	dc.l	MOVEC+D0_TO_VBR 	; write it (hand assembled)

;
; return new Exception Table address into Trap Status
;

	move.l	d0,d5			; Trap Status = TRUE

;
; ? update any EXEC structures that may be necessary ?
;

;
; all done
;

EndTrap:
	move.l	(sp)+,d0                ; pop D0 from SSP
	movea.l (sp)+,a1                ; pop A1 from SSP
	movea.l (sp)+,a0                ; pop A0 from SSP
	rte				; return from exception

;
; VBR already relocated, so we must tell caller to deallocate memory
;

VBR_is_Fast:
	movea.l d0,a4			; old EVT address = 68010 VBR
	move.l	#-1,d5			; Trap Status = ERROR
	bra	EndTrap 		; and return

;----------------------------------------------------------------------------
; local constants
;----------------------------------------------------------------------------

	SECTION Pure_data,DATA

;
; NOTE: the WELCOME text is split up because the v1.3 AMIGA.LIB __DOPRNT
;	function only allocates 140 bytes on the stack for workspace ... ;-(
;

Welcome:
	dc.b	10,10,'FASTVBR v1.03 (c)1992, Mark C. Barnes, All Rights Reserved.',13,10,10
	dc.b	'    Attempting to relocate the 68010 Exception Vector Table',13,10,0

Welcome1:
	dc.b	'from CHIP RAM, at address 0x00000000, to true FAST RAM.',0

Welcome2:
	dc.b	'If successfull, the low CHIP RAM, from address range',13,10
	dc.b	'0x00000008 to 0x000003FF will be added to EXEC Memory List.',13,10,0

Failure1:
	dc.b	10,'%FASTVBR-F-MAIN, could not move 68010 Exception Vector Table.',0

Failure2:
	dc.b	10,'%%FASTVBR-W-MAIN, 68010 Exception Vector Table already FAST.',13,10
	dc.b	'                 It is located at address $%08lx',13,10,10,0

SuccessEVT:
	dc.b	10,'%%FASTVBR-I-MAIN, 68010 Exception Vector Table is now',13,10
	dc.b	'                 located at address $%08lx',13,10,10,0

SuccessMEM:
	dc.b	10,'%FASTVBR-I-MAIN, 68000 Exception Vector Table is now',13,10
	dc.b	'                 configured as PUBLIC CHIP RAM.',13,10,10,0

ErrCPU:
	dc.b	10,'%FASTVBR-F-CPU, only 68000 processor installed.',0

ErrNoMem:
	dc.b	10,'%FASTVBR-F-NOMEM, unable to allocate any FAST RAM.',0

ErrSlMem:
	dc.b	10,'%FASTVBR-W-SLMEM, memory allocated is SLOW FAST RAM.',0

RegionName:
	dc.b	'EVT Chip RAM',0
sizeofName	EQU *-RegionName

	.LONG

;----------------------------------------------------------------------------
; local variables
;----------------------------------------------------------------------------

	SECTION Impure_data,BSS

	.LONG


;----------------------------------------------------------------------------
; E N D  O F  A S S E M B L Y
;----------------------------------------------------------------------------

	END
