;****************************************************************************
;* Copyright 1994 MBARI							    *
;****************************************************************************
;* $Header: startup.s,v 4.4 2001/06/19 12:15:45 oasisa Exp $		    *
;* Summary  : Assembly language routines for OASIS Microcontroller          *
;* Filename : startup.s							    *
;* Author   : Robert Herlien						    *
;* Project  : OASIS Mooring Controller                                      *
;* $Revision: 4.4 $							    *
;* Created  : 02/06/91                                                      *
;*									    *
;* MBARI provides this documentation and code "as is", with no warranty,    *
;* express or implied, of its quality or consistency. It is provided without*
;* support and without obligation on the part of the Monterey Bay Aquarium  *
;* Research Institute to assist in its use, correction, modification, or    *
;* enhancement. This information should not be published or distributed to  *
;* third parties without specific written permission from MBARI.            *
;*									    *
;****************************************************************************
;
$TITLE("OASIS Microcontroller")
;
STARTUP		MODULE MAIN
;
$INCLUDE(..\C196\INCLUDE\8096.INC)
$INCLUDE(OASIS.INC)
;
;*****************************************************************************
;
EXTRN   _main:ENTRY		;The brain dead Intel Assembler treates MAIN
				;as a reserved keyword so I cannot call the
				;C main procedure MAIN!
EXTRN	MEMORY:WORD		;Linker symbol, start of free memory
EXTRN	?MEMORY_SIZE:WORD	;Linker symbol, length of free memory
EXTRN	sys_init:WORD		;Global initialization flag
EXTRN	bank_port:BYTE		;Bank select port in OASIS hardware
EXTRN	progRamChksum:WORD	;Program RAM checksum

PUBLIC	free_mem		;Start of free memory
PUBLIC	mem_size		;Length of free memory
PUBLIC	SP			;Stack pointer
PUBLIC	STACK			;Bottom of stack


;****************************************************************
;		CHIP CONFIGURATION BYTE
;****************************************************************
;
			CSEG at 2018H
ccb:		DCB	0d4H		;No pwrdown, 8 bit, ADV, 2 Wait states


;*****************************************************************************
; power up reset vector - software start location
;
			CSEG at 2080H

	di				;In case we got here from userif
	ld	sp, #100h		;Load init stack pointer
	ld	tmp0, #tmp0+2
clrRegs:				;Loop to clear register space
	st	R0, [tmp0]+
	cmp	tmp0, 200h
	jlt	clrRegs

	ld	tmp0, sys_init
	cmp	tmp0, #RAM_OK		;See if RAM initialized
IF EXEC_FROM_RAM
	jne	startColdInit		;If no, init RAM

	scall	chkProgRam		;Check program RAM checksum
	cmp	tmp0, progRamChksum	;If chksum bad, go to init code
ENDIF
	je	goMain

startColdInit:
	scall	initRam			;If failed, init data and prog RAM
	st	tmp0, progRamChksum	;store checksum
	st	R0, sys_init		;clear sys_init flag
goMain:
	ld	SP,#STACK		;Load real stack pointer
	ldb	zeroBank, #RAMSELBIT	;Select RAM for RAM/ROM area
	stb	zeroBank, bank_port
	lcall	_main			;start C main procedure
					;Returns after main() turns off power
	idlpd	#2			;To be safe, put CPU in pwrdown mode
	ld	tmp0, #8000h
pwrdown_wait:				;Loop to wait for CPU power down
	nop
	djnzw	tmp0, pwrdown_wait
	rst				;if STILL here, restart


;*****************************************************************************
;	Bank Switching and Copying code
;	Placed here because it needs to be in low memory (< 0x6000)
;

PUBLIC	chkProgRam		;Calculate checksum on program RAM
PUBLIC	zeroBank		;Byte to select bank zero
PUBLIC	bankCopy		;Copy to/from bank switched memory
PUBLIC	bankZero		;Zero bytes in bank switched memory



;*****************************************************************************
; chkProgRam - Calculate checksum on RAM/ROM area
;
; Nat16 chkProgRam( Void );
;

chkProgRam:
	ldb	dstBank, #RAMSELBIT	;Select RAM for RAM/ROM area
	stb	dstBank, bank_port
	ld	tmp0, R0		;Init checksum to zero
	ld	tmp2, #PROG_RAM		;Point to ROM/RAM area
	ld	tmp4, #RAM_CHKSUM_LEN	;Get length to checksum over
chkRam1:
	add	tmp0, [tmp2]+		;Add program word
	djnzw	tmp4, chkRam1		;Repeat until done

	ret


;*****************************************************************************
; initRam - Initialize program and data RAM
;
; Nat16 initRam( Void );
;
; Zeroes data RAM, copies program ROM to RAM, and returns program RAM checksum
;

initRam:
	stb	R0, bank_port		;Start in bank zero, ROM selected
	ld	tmp0, #INIT_RAM		;point tmp0 to init area
	ld	tmp2, tmp0
	st	R0, [tmp2]+		;zero first word
	ld	tmp4, #(INIT_LEN - 1)	;set remaining amount to init
	bmov	tmp0, tmp4		;copy the zero to rest of RAM

IF EXEC_FROM_RAM
	ldb	dstBank, #RAMSELBIT	;Select RAM for RAM/ROM area
	ld	tmp0, R0		;Init checksum to zero
	ld	tmp2, #PROG_RAM		;Point to ROM/RAM area
	ld	tmp4, #RAM_CHKSUM_LEN	;Get length to checksum over
initRam1:
	stb	R0, bank_port		;select ROM
	ld	tmp6, [tmp2]		;Get word from ROM
	stb	dstBank, bank_port
	st	tmp6, [tmp2]+		;Copy word to RAM
	add	tmp0, tmp6		;Calc checksum
	djnzw	tmp4, initRam1		;Repeat until done
ENDIF
	ret


;*****************************************************************************
; bankCopySub - Subroutine for bank copier
;
; Performs one copy "block" for bankCopy, turns on/off ints and bank switch
; Assumes calling routine has done test for tmp1b != 0
;
; Inputs:  tmp1b = bytes to copy
;	   tmp4 = src ptr
;	   tmp6 = dst ptr
;	   dstBank = destination bank
;
; tmp0b used as scratch
; tmp2 must be untouched
;

bankCopySub:
	di				;Ints off while in "wrong" bank
	stb	dstBank, bank_port	;Select destination bank
bCpySub1:
	ldb	tmp0b, [tmp4]+		;Move bytes
	stb	tmp0b, [tmp6]+
	djnz	tmp1b, bCpySub1

	stb	zeroBank, bank_port	;Go back to bank 0
	ei				;Allow interrupt window while bank=0
	ret


;*****************************************************************************
; bankCopy - Copy bytes to/from bank switched memory
;
; Void bankCopy( Nat16 bank, const Byte *src, Byte *dst, Nat16 len )
;
; Comment:  Assumes one of src or dst is in non-banked memory, and hence
;           in context even when bank 0 is switched out.  This is true since
;	    0xe000 to 0xffff in bank 0 is used only for permanently malloced
;	    structs (driver headers, etc), and are not are not declared as
;	    available to the linker.
;
;	    Takes approx 6 usec/byte.  2 Kbytes -> 12 ms.
;	    Transfers 32 bytes/loop.  Interrupts are off for approx 200 usec.
;
; Register usage:  tmp0b = byte to copy
;		   tmp1b = inner loop counter
;		   tmp2 = outer loop counter
; 		   tmp4 = src ptr
;		   tmp6 = dst ptr
;

bankCopy:
	ldb	dstBank, 2[SP]		;Get destination bank
	orb	dstBank, zeroBank
	ld	tmp4, 4[SP]		;Get source address
	ld	tmp6, 6[SP]		;Get destination address
	ld	tmp2, 8[SP]		;Get length to copy

	andb	tmp1b, tmp2b, #1fh	;Get odd 0 - 31 bytes
	be	bCpy1			;Skip if 0

	scall	bankCopySub		;Copy first 0 - 31 bytes
bCpy1:
	shr	tmp2, #5		;Do 32 bytes at a time
	be	bCpyDone		;If zero, skip
bCpy2:
	ldb	tmp1b, #32		;Do 32 bytes at a time
	scall	bankCopySub		;Copy them
	djnzw	tmp2, bCpy2		;Repeat until done
bCpyDone:
	ret


;*****************************************************************************
; bankZeroSub - Subroutine for bank zero function
;
; Zeroes one block of 1 - 32 bytes for bankZero, turns off ints and bank switch
; Assumes calling routine has done test for tmp1b != 0
;
; Inputs:  tmp1b = bytes to zero
;	   tmp4 = destination ptr
;	   tmp5b = bank to zero
;
; tmp2 must be untouched
;

bankZeroSub:
	di				;Ints off while in "wrong" bank
	stb	tmp5b, bank_port	;Select destination bank
bZeroSub1:
	stb	R0, [tmp4]+		;Zero the bytes
	djnz	tmp1b, bZeroSub1

	stb	zeroBank, bank_port	;Go back to bank 0
	ei				;Allow interrupt window while bank=0
	ret


;*****************************************************************************
; bankZero - Zero bytes in bank switched memory
;
; Void bankZero( Nat16 bank, Byte *dst, Nat16 len )
;
;	Takes approx 4 usec/byte.  8 Kbytes -> 33 ms.
;	Zeroes 32 bytes/loop.  Interrupts are off for approx 140 usec.
;
; Register usage:  tmp0b = byte to copy
;		   tmp1b = inner loop counter
;		   tmp2 = outer loop counter
; 		   tmp4 = destination ptr
;		   tmp5b = bank
;

bankZero:
	ldb	tmp5b, 2[SP]		;Get destination bank
	orb	tmp5b, zeroBank
	ld	tmp4, 4[SP]		;Get destination address
	ld	tmp2, 6[SP]		;Get length to zero

	andb	tmp1b, tmp2b, #1fh	;Get odd 0 - 31 bytes
	be	bZero1			;If zero, skip

	scall	bankZeroSub		;Zero first 1 - 31 bytes
bZero1:
	shr	tmp2, #5		;Do 32 bytes at a time
	be	bZeroDone		;If zero, skip
bZero2:
	ldb	tmp1b, #32		;Do 32 bytes at a time
	scall	bankZeroSub		;Zero the bytes
	djnzw	tmp2, bZero2		;Repeat until done
bZeroDone:
	ret

	
;*****************************************************************************
		KSEG
; Data Constants
;
free_mem:	dcw	MEMORY		;Linker free memory address

mem_size:	dcw	?MEMORY_SIZE	;Linker free memory size


;*****************************************************************************
;  Registers for bankCopy, etc
;
		RSEG
					;Register segment
zeroBank:	dsb	1		;How to select bank 0
dstBank:	dsb	1		;Bank to copy to


	END
