#line 1 "cstart.asm"
; @(#)cstart.asm	1.53
;*****************************************************************************
;*
;* MODULE	: cstart.asm
;*
;* DESCRIPTION	: C startup code for SAB 80C166/C167 microcontroller.
;*
;*		- Processor initialization.
;*		- Initialization of static variables in internal or external
;*		  ram. C variables which have to be initialized are specified
;*		  in ROM section C166_INIT. C variables which must
;*		  be cleared are specified in ROM section C166_BSS.
;*		- Set user stack pointer.
;*		- Call the user program: main().
;*		- On exit cpu is set in idle mode.
;*
;* COPYRIGHTS	: 1994 Tasking Software B.V.
;*
;*****************************************************************************

; Following defines can be set on the command line of the macro pre-processor,
; with the DEFINE() control. ( Syntax:  DEFINE( identifier [, replacement] )

; Example:			       
;	m166 cstart.asm DEFINE(MODEL, LARGE) DEFINE(MUXBUS) DEFINE(FLOAT)
;



  		; set to 1 for fuzzy-166 evaluation kit


  		; set to 1 for PXROS support


  		; set to 1 when execution environment is ertec
				; EVA166/EVA167 or EPC166. Needed to:
				;  1)	force tiny model to execute with
				;	segmentation enabled.
				;  2)	do not clear monitor data in
				;	bit-addressable area.
				;  3)	run application with interrupts
				;	enabled, allowing the monitor to
				;	break it (not needed for EPC166).
				;  4)   define symbols that can be used by
				;       a debugger to initialize the EVA167 
				;       before monitor or user program is
				;       downloaded.
				; By default the hardware is expected to be
				; configured for non-multiplexed bus mode to 
				; get the maximum performance.


  		; enable EX_AB if the function 'exit()' or
				; 'abort()' is used else it can be disabled.




  		; enable initialization of bit variables at
				; startup. Only needed if "bit b = 1;" is used.


  		; select non-multiplexed bus


  $EXTEND			; enable all SAB C167 extensions
  $NOMOD166			; disable the internal set of SAB 80C166 SFRs
  $STDNAMES(reg167b.def)	; load set of SAB C167 SFRs from reg167b.def



				; set assembler controls.
      $MODEL(small)
    $NONSEGMENTED
  
  
  
  


; The macro _BFWDNOP() expands to two NOP instructions when FIX_BFWD 
; is defined. This is used for a software bypass for the Erroneous Byte 
; Forwarding problem of older steps of the CPU. 




$CASE
$GENONLY
$DEBUG
$NOLOCALS

	NAME	CSTART			; module name.
	
  
	EXTERN	_main:FAR		; start label user program.


	PUBLIC	__IDLE			; cstart end
	PUBLIC	__EXIT			; address to jump to on 'exit()'.





	; Value definitions for System Configuration Register : SYSCON/BUSCON0

	; Memory Cycle Time is extended by a number of additional State Times.
	; in a range from 0 through 15. BUSCON0[3..0]
				; Reset value MCTC = 15 additional state times
  	__MCTC          LIT     '0'     ; *** INSERTED ***
; 	__MCTC		LIT	'1'	; Memory wait states is 1 (MCTC = 0EH).
  

	; The Read/Write Signal Delay is 0.5 or 0 State Times. BUSCON0.4
	__RWDC0         LIT     '0'     ; *** INSERTED ***
; 	__RWDC0		LIT	'1'	; 0 = Delay Time (Reset value)
					; 1 = No Delay Time
	; Memory Tri-state is extended by either 1 or 0 State Times. BUSCON0.5
	__MTTC0         LIT     '1'     ; *** INSERTED ***
; 	__MTTC0		LIT	'0'	; 0 = Delay Time (Reset value)
					; 1 = No Delay Time

	; External bus configurations. BUSCON0[7..6]
					; After reset determined by the state 
					; of the port pins P0L.7 and P0L.6.
					; Note: coding changed in the SAB C167
					
	; ALE Signal is lengthened by either 1 or 0 State Times. BUSCON0.9
	; Do not disable the ALE lengthening option for a multiplexed bus
	; configuration. See problem 17 in errata sheet SAB-C167A-LM,ES-AC,1.1
	; on page 4/9.

  	__ALECTL0       LIT     '0'     ; *** INSERTED ***
; 	__ALECTL0	LIT	'0'	; 0 = No Delay Time (Reset value if pin
					;      #EA is high)
  
	
	; READY# Input Enable control bit. BUSCON0.12
	__RDYEN0        LIT     '0'     ; *** INSERTED ***
; 	__RDYEN0	LIT	'0'	; 0 = disabled (Reset value)
					; 1 = enabled

	; Process BUSCON0 low byte and high byte values
	BUSC0_L		EQU	((__MTTC0<<5) | (__RWDC0<<4) | ((~__MCTC)&000Fh))
	BUSC0_H		EQU	((__RDYEN0<<4) | (__ALECTL0<<1))
	BUSC0_M_L	EQU	03Fh	; Mask low byte BUSCON0
	BUSC0_M_H	EQU	012h	; Mask high byte BUSCON0
	
	; Write Configuration Mode Control Bit (CLKOUT) Enable bit. SYSCON.7
	__WRCFG         LIT     '1'     ; *** INSERTED ***
; 	__WRCFG 	LIT	'0'	; 0 = Normal operation of WR# and 
					; BHE# (Reset value)			
					; 1 = WR# acts as WRL#. 
					; BHE# acts as WRH#
					
	; System Clock Output (CLKOUT) Enable bit. SYSCON.8
	__CLKEN         LIT     '0'     ; *** INSERTED ***
; 	__CLKEN		LIT	'0'	; 0 = disabled (Reset value)
					; 1 = enabled

	; Byte High Enable (BHE#) pin control bit. SYSCON.9
	__BYTDIS        LIT     '0'     ; *** INSERTED ***
; 	__BYTDIS	LIT	'0'	; 0 = enabled (Reset value)
					; 1 = disabled

	; Internal ROM Access Enable (Read Only). SYSCON.10
					; After reset determined by the state
					; of the #EA pin.

	; Segmentation Disable control bit. SYSCON.11
  	__SGTDIS        LIT     '0'     ; *** INSERTED ***
; 	__SGTDIS	LIT	'0'	; Reset value is segmentation enabled
  

	; ROM Segment Mapping control bit. SYSCON.12
	__ROMS1         LIT     '0'     ; *** INSERTED ***
; 	__ROMS1		LIT 	'0'	; 0 = Internal ROM mapped to 
					; segment 0 (Reset value)
					; 1 = Internal ROM mapped to segment 1

	; Stack Size selection of between 32 and 512 words. SYSCON[15..13]
	__STKSZ		LIT	'0'	; System stack sizes
					; 0 = 256 words (Reset value)
					; 1 = 128 words
					; 2 =  64 words
					; 3 =  32 words
					; 4 = 512 words
					; 7 = No wrapping

	; Process SYSCON low byte and high byte values.
	SYSC_L  	EQU	(__WRCFG << 7)
	SYSC_H  	EQU  	((__STKSZ << 5) | (__ROMS1 << 4) | (__SGTDIS<<3) | (__BYTDIS<<1) | __CLKEN)
	SYSC_M_L	EQU	080H	; Mask low byte SYSCON.
	SYSC_M_H	EQU	0FBH	; Mask high byte SYSCON.
  	; Symbols __EVA_SYSCON and __EVA_MEMSZ should be defined when the 
	; XVW166 debugger uses the EVA167 target board as its execution
	; environment.
	; They let the debugger configure the target environment correctly 
	; before the boot program downloads the monitor program MON167.
	; 
	__MEMSZ		LIT	'0'	; EVA167 Memory configuration
					; 0 =  1 MBit RAM (Reset value)
					; 1 =  2 MBit RAM
					; 2 =  4 MBit RAM

	__EVA_SYSCON	EQU	((SYSC_H << 8) | SYSC_L)
	__EVA_MEMSZ	EQU	__MEMSZ
	PUBLIC	__EVA_SYSCON,__EVA_MEMSZ
  

	
	; Predefined functions for register R1, R2 and R3.
	POF_RAM		LIT	'R1'	; Page offset address ram data.
	SOF_RAM		LIT	'R1'	; Segment offset address ram data.
	SOF_RAM_H	LIT	'RH1'	; Segment address high byte.
	POF_ROM		LIT	'R2'	; Page offset address rom data.
	SOF_ROM		LIT	'R2'	; Segment offset address rom data.
	SOF_ROM_H	LIT	'RH2'	; Segment address high byte.
	BP_RAM		LIT	'R3'	; Bit position ram data

;*****************************************************************************
;* __CSTART
;*****************************************************************************
__CSTART_PR	SECTION CODE WORD PUBLIC 'CPROGRAM'
__CSTART 	PROC TASK __CSTART_TASK INTNO __CSTART_INUM = 00H

	DISWDT				; Disable watchdog timer.

						; Set SYSCON register.
	BFLDL	SYSCON, #SYSC_M_L, #(SYSC_L AND SYSC_M_L)
	BFLDH	SYSCON, #SYSC_M_H, #(SYSC_H AND SYSC_M_H)
	BSET    SYSCON.2                    ; Set XPEN *** INSERTED ***
; 	BFLDH	SYSCON, #SYSC_M_H, #(SYSC_H AND SYSC_M_H)
						; Set BUSCON0 register.
	BFLDL	BUSCON0, #BUSC0_M_L, #(BUSC0_L AND BUSC0_M_L)
	BFLDH	BUSCON0, #BUSC0_M_H, #(BUSC0_H AND BUSC0_M_H)

	MOV	STKOV,	#?SYSSTACK_BOTTOM + 6*2	; Set stack underflow pointer.
	MOV	STKUN,	#?SYSSTACK_TOP		; Set stack overflow pointer.
	MOV	SP,	#?SYSSTACK_TOP		; Set stack pointer.

	MOV	CP, 	#RBANK		; Set context pointer.

;------------------------------------inserted by Wilhelm, 29.1.1998
	MOV     ADDRSEL1,#0404H   ; Adressfenster einstellen
	MOV     BUSCON1,#04AFH    ; Adressfenster aktivieren

;------------------------------------------------------------------

	EINIT				; End of initialization

	BOTTOM_BITRAM	LIT  '0FD4CH'	; 0FD00H - 0FD4BH is monitor data area

					; Clear bit addressable memory
	MOV	R0, #0FDFEH		; R0 = top of bit addressable area
loop:	CMP	R0, #RBANK		; if( R0 in bit addressable area )
	JMP	CC_EQ, cbclr		; then continue next (bit) word clear.
	MOV	[R0], zeros		; clear
cbclr:	CMPD2	R0, # BOTTOM_BITRAM	; if( not bottom bit addressable area )
	JMP	CC_NE, loop		; then continue next (bit) word clear

	; The following code is needed for initialization of static variables
	MOV	DPP0, #PAG ?BASE_DPP0	; Set data page pointer.
	MOV	DPP1, #PAG ?BASE_DPP1	;
	MOV	DPP2, #PAG ?BASE_DPP2	;

					 ; C166_INIT
	MOV	R4,  #POF ?C166_INIT_HEAD ; move intra-page offset address rom
					 ; data section C166_INIT to R4
INIT_DPP0:				 ;
	MOV	DPP0,#PAG ?C166_INIT_HEAD ; load data page pointer register DPP0
					 ; with data page of rom data C166_INIT
	NOP				 ; delay for pipeline effect


INIT:					;
	MOV	R5, [R4+]		; INIT block header code -> R5
	CMP	R5, #01H		; check if header code 1 (bit)
	JMP	CC_EQ, INIT_01		;

	CMP	R5, #05H		; check if header code is 5 (near)
  	JMP	CC_EQ, INIT_05		;
  

	CMP	R5, #06H		; check if header code 6 (far)
	JMP	CC_EQ, INIT_06		;
	CMP	R5, #07H		; check if header code 7 (huge)
	JMP	CC_NE, INIT_END		; if(no header code) end initialization

INIT_07:				; initialize huge ram data. (data > 64K)
	MOV	SOF_RAM, [R4+]		; move intra-segment offset address ram
					; data block to SOF_RAM=R1
	MOV	R3, [R4+]		; move segment address ram data block 
					; to register R3
					; process data page number ram data
	MOV	RH3, SOF_RAM_H		; R3.15, R3.14: low bits of page number
				; 2 NOPs for fix of CPU byte forw. probl.
	ROL	R3, #2			; shift R3.15, R3.14 to R3.1 and R3.0
	AND	R3, #03FFH		; mask page number
	MOV	DPP1, R3		; load data page pointer register DPP1
					; with data page of ram data block
	BFLDH	SOF_RAM, #0C0H, #040H	; DPP1:POF_RAM ->SOF_RAM=R1
					;
	MOV	SOF_ROM, [R4+]		; move intra-segment offset address rom
					; data block to SOF_ROM=R2
	MOV	R3, [R4+]		; move segment address rom data block
					; to R3
					; process data page number rom data
	MOV	RH3, SOF_ROM_H		; R3.15, R3.14=low bits of page number
				; 2 NOPs for fix of CPU byte forw. probl.
	ROL	R3, #2			; shift R3.15, R3.14 to R3.1 and R3.0
	AND	R3, #03FFH		; mask page number
	MOV	DPP2, R3		; load data page pointer register DPP2
					; with data page of rom data block
	BFLDH	SOF_ROM, #0C0H, #080H	; DPP2:POF_ROM ->SOF_ROM=R2
					;
	MOV	R5, [R4+]		; number of bytes (R6:R5) to move from
	MOV	R6, [R4+]		; rom to ram. MSW=R6, LSW=R5 (long word)
					;
MB07_3:	CMPD1	R5, #0			; test if all bytes are moved and
	JMP	CC_NE, MB07_1 		; decrement number of bytes to move.
	CMPD1	R6, #0			;
  	JMP	CC_EQ, MB07_4		;
  
MB07_1:	MOVB	[SOF_RAM], [SOF_ROM]	; move byte from rom to ram
	CMPI1	SOF_RAM, #07FFFH	; test end of data page and inc SOF_RAM
	JMP	CC_NE, MB07_2		; if(no page end) cont init current page
	MOV	SOF_RAM, #04000H	; preset offset address ram data
	ADD	DPP1, #1		; next page of ram data; increment DPP1
MB07_2:	CMPI1	SOF_ROM, #0BFFFH	; test end of page and inc SOF_ROM
	JMP	CC_NE, MB07_3		; if(no page end) cont init current page
	MOV	SOF_ROM, #08000H	; preset offset address rom data
	ADD	DPP2, #1		; next page of rom data; increment DPP2
	JMP	CC_UC, MB07_3		; jump for next byte move
  MB07_4:	MOV 	DPP1, #PAG ?BASE_DPP1	; restore data page register DPP1 and
	MOV 	DPP2, #PAG ?BASE_DPP2	; DPP2 to their default values.
	JMP	CC_UC, INIT		; next initialization
  

INIT_06:				; initialize far ram data. (CPU mode 
					; is segmented with DPP usage linear
					; or paged.)
	MOV	POF_RAM, [R4+]		; move intra-page offset address ram
					; data block to POF_RAM=R1
	BFLDH	SOF_RAM, #0C0H, #040H	; DPP1:POF_RAM ->SOF_RAM=R1
	MOV	DPP1, [R4]		; load data page pointer register DPP1
					; with data page of ram data block
	ADD	R4, #2			; inc offset address to ram data section
					; C166_INIT and also insure a delay for
					; pipeline effect.(DPP1 set)
					;
	MOV	POF_ROM, [R4+]		; move intra-page offset address rom
					; data block to POF_ROM=R2
	BFLDH	SOF_ROM, #0C0H, #080H	; DPP2:POF_ROM ->SOF_ROM=R2
	MOV	DPP2, [R4]		; load data page pointer register DPP2
					; with data page of rom data block
	ADD	R4, #2			; inc offset address to rom data section
					; C166_INIT and also insure a delay for
					; pipeline effect.(DPP2 set)
					;
	MOV	R5, [R4+]		; number of bytes to move from rom to
					; ram for specified data block.
					;
MB06_1:	CMPD1	R5, #0			; test on data block end
  	JMP	CC_EQ, MB06_2		;
	MOVB	[SOF_RAM], [SOF_ROM+]	; move byte from rom to ram, inc SOF_ROM
	CMPI1	SOF_RAM, #07FFFH	; test end of data page and inc SOF_RAM
	JMP	CC_NE, MB06_1		; if(no page end) cont init current page
	MOV	SOF_RAM, #04000H	; preset offset address ram data
	ADD	DPP1, #1		; next page of ram data; increment DPP1
	JMP	cc_UC, MB06_1		; jump for next byte move
MB06_2:	MOV 	DPP1, #PAG ?BASE_DPP1	; restore data page register DPP1 and
	MOV 	DPP2, #PAG ?BASE_DPP2	; DPP2 to their default values.
	JMP	CC_UC, INIT		; next initialization
  


INIT_05:				; initialize near ram data. (DPP usage
					; is linear, CPU mode is segmented
					; for SMALL memory model and not
					; segmented for TINY memory model.)
	MOV	SOF_RAM, [R4+]		; move intra-segment offset address ram
					; data block to SOF_RAM=R1
					;
	MOV	SOF_ROM, [R4+]		; move intra-segment offset address rom
					; data block to SOF_ROM=R2
					;
	MOV	R5, [R4+]		; number of bytes to move from rom to
					; ram for specified data block.
  	MOV	DPP0, #PAG ?BASE_DPP0	; restore DPP0 to its default value
  
MB05_1:	CMPD1	R5, #0			; test on data block end, and delay
					; for pipeline effect if DPP0 is
					; restored for SMALL memory model.
  	JMP	CC_EQ, INIT_DPP0	; if( block end ) reload data page
					; pointer register DPP0 with data page
					; of rom data C166_INIT and start next
					; initialization.
  
	MOVB	[SOF_RAM], [SOF_ROM+]	; byte move rom to ram, inc SOF_ROM
	ADD	SOF_RAM, #1		; inc SOF_RAM
	JMP	CC_UC, MB05_1		; jump for next byte move


; NO BIT INITIALIZATION
					;
INIT_01:
	ADD	R4,#0CH			; skip DBPTR, DPTR and DW
	JMP	CC_UC, INIT		; continue with next initialization

INIT_END:				;


					; C166_BSS
	MOV	R4, #POF ?C166_BSS_HEAD	; move intra-page offset address rom
					; data section C166_BSS to R4
BSS_DPP0:				;
	MOV	DPP0,#PAG ?C166_BSS_HEAD ; load data page pointer register DPP0
					; with data page of rom data C166_BSS
	NOP				; delay for pipeline effect


BSS:					;
	MOV	R5, [R4+]		; BSS block header code -> R5
	CMP	R5, #05H		; check if header code 5 (near)
  	JMP	CC_EQ, BSS_05		;
  

	CMP	R5, #06H		; check if header code 6 (far)
	JMP	CC_EQ, BSS_06		;
	CMP	R5, #07H		; check if header code 7 (huge)
	JMP	CC_NE, BSS_END		; if(no header code) end initialization

BSS_07:					; clear huge ram data (data > 64 K)
	MOV	SOF_RAM, [R4+]		; move intra-segment offset address ram
					; data block to SOF_RAM=R1
	MOV	R3, [R4+]		; move segment address ram data block
					; to R3
					; process data page number ram data 
	MOV	RH3, SOF_RAM_H		; R3.15, R3.14=low bits of page number
				; 2 NOPs for fix of CPU byte forw. probl.
	ROL	R3, #2			; shift R3.15, R3.14 to R3.1 and R3.0
	AND	R3, #03FFH		; mask page number
	MOV	DPP1, R3		; load data page pointer register DPP1
					; with data page of ram data block
	BFLDH	SOF_RAM, #0C0H, #040H	; DPP1:POF_RAM ->SOF_RAM=R1
					;
	MOV	R5, [R4+]		; number of bytes (R6:R5) to clear in
	MOV	R6, [R4+]		; specified ram data block. 
					; MSW=R6, LSW=R5 (long word)
					;
CB07_2:	CMPD1	R5, #0			; test if all bytes are cleared and
	JMP	CC_NE, CB07_1 		; decrement number of bytes to clear.
	CMPD1	R6, #0			;
  	JMP	CC_EQ, CB07_3		;
  
CB07_1:	MOVB	[SOF_RAM], ZEROS	; clear byte
	CMPI1	SOF_RAM, #07FFFH	; test end of data page and inc SOF_RAM
	JMP	CC_NE, CB07_2		; if(no page end) next byte clear
	MOV	SOF_RAM, #04000H	; preset offset address ram data
	ADD	DPP1, #1		; next page ram data; increment DPP1
	JMP	CC_UC, CB07_2		; jump for next byte clear
  CB07_3:	MOV 	DPP1, #PAG ?BASE_DPP1	; restore data page register DPP1.
	JMP	CC_UC, BSS		; next initialization
  

BSS_06:					; clear far ram data. (CPU mode is
					; segmented with DPP usage linear or
					; paged.)
	MOV	POF_RAM, [R4+]		; move intra-page offset address ram
					; data block to POF_RAM=R1
	BFLDH	SOF_RAM, #0C0H, #040H	; DPP1:POF_RAM ->SOF_RAM=R1
	MOV	DPP1, [R4]		; load data page pointer register DPP1
					; with data page of ram data block
	ADD	R4, #2			; inc offset address to ram data section
					; C166_BSS and also insure a delay for 
					; pipeline effect. (DPP1 set)
					;
	MOV	R5, [R4+]		; number of bytes to clear in specified
					; ram data block
					;
CB06_1:	CMPD1	R5, #0			; test on data block end
  	JMP	CC_EQ, CB06_2 		;
  
	MOVB	[SOF_RAM], ZEROS	; clear byte
	ADD	SOF_RAM, #1		; inc SOF_RAM
	JMP	CC_UC, CB06_1		; jump for next byte clear
  CB06_2:	MOV 	DPP1, #PAG ?BASE_DPP1	; restore data page register DPP1
	JMP	CC_UC, BSS		; next initialization
  


BSS_05:					; clear near ram data. (DPP usage
					; is linear, CPU mode is segmented
					; for SMALL memory model and not
					; segmented for TINY memory model.)
	MOV	SOF_RAM, [R4+]		; move intra-segment offset address ram
					; data block to SOF_RAM=R1
					;
	MOV	R5, [R4+]		; number of bytes to clear in specified
					; ram data block
  	MOV	DPP0, #PAG ?BASE_DPP0	; restore DPP0 to its default value
  
CB05_1:	CMPD1	R5, #0			; test on data block end, and delay for
					; pipeline effect if DPP0 is restored
					; for SMALL memory model
  	JMP	CC_EQ, BSS_DPP0		; if( block end ) reload data page
					; pointer register DPP0 with data page
					; of rom data C166_BSS and start next
					; initialization
  
	MOVB	[SOF_RAM], ZEROS	; clear byte
	ADD	SOF_RAM, #1		; inc SOF_RAM
	JMP	CC_UC, CB05_1		; jump for next byte clear

BSS_END:

	MOV	DPP0, #PAG ?BASE_DPP0	; restore DPP0 to its default value




	MOV	R0, #?USRSTACK_TOP	; set user stack pointer


	BSET	IEN			; allow monitor to break application


	MOV	R12, #0			; set argc to 0
	MOV	R13, #0			;
	MOV	R14, #0			; set argv[] to 0
  
	CALL	_main			; call reset task main()



; The exit() function causes normal program termination to occur. First, all 
; functions registered by the atexit() function are called in the reverse 
; order. Next, all open streams with unwritten buffered data are flushed, all 
; open streams are closed and all files created by the tmpfile() function are 
; removed. The status value passed to exit is returned in R4.
__EXIT: LABEL FAR			; the exit() or abort() function jumps
					; to this entry.


__IDLE: IDLE				; Power down CPU until peripheral inter-
					; rupt or external interrupt occurs.
	JMPR	CC_UC, __IDLE		; set idle mode again.
	RETV				; Virtual return.
__CSTART	ENDP
__CSTART_PR	ENDS

C166_US	SECTION	LDAT WORD GLBUSRSTACK 'CUSTACK'


	DS	2		; Allocate a user stack of at least 2 bytes

C166_US	ENDS



RBANK	REGDEF R0-R15			; Register usage
	SSKDEF	__STKSZ			; System stack size
	
	END
