;SAsmTemp.src by James Newton 
;Template for new programs for SXKey version of SASM

;Copyright 2000,2001,2002 James Newton <james@sxlist.com>
; This program is free software; you can redistribute it and/or modify
; it under the terms of the GNU General Public License version 2 as published
; by the Free Software Foundation.  Note that permission is not granted
; to redistribute this program under the terms of any other version of the
; General Public License.
;
; This program is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
; GNU General Public License for more details.
;
; You should have received a copy of the GNU General Public License
; along with this program; if not, write to the Free Software
; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

;Change these as required to reflect your target device
		CpuMhz = 50
		CpuPins = 28	;=18,28,48, or 52
		CpuLongDate = 1	;=0 for old 4 digit date code, =1 for new "A" 8 digit date code
		CpuMode = 0	;=0 for debug, =1 for full speed
		CpuCarry = 1	;carryx is on.

	IRC_CAL IRC_SLOW

IF CpuPins == 18
 IF CpuLongDate == 1
		device	SX18L, turbo
 ELSE
		device	SX18, pins18, pages8, banks8, turbo, stackx, optionx
  ENDIF
 ENDIF

IF CpuPins == 28
 IF CpuLongDate == 1
		device	SX28L, turbo
 ELSE
		device	SX28, pins28, pages8, banks8, turbo, stackx, optionx
  ENDIF
 ENDIF

IF CpuPins == 52 || CpuPins == 48
 IF CpuLongDate == 1
		error 'A longdate SX48/52 did not exist at the time this ap was written'
 ELSE
		device 	SX52, DRTOFF, TURBO, STACKX, OPTIONX
  ENDIF
 ENDIF

 IF CpuCarry == 1
		device carryx
  ENDIF


IF CpuMode == 1
 IF CpuLongDate == 1
		device	OSCXTMAX
 ELSE
		device	oschs			;full speed operation
  ENDIF
ELSE
		device	oscrc			;debug operation
 ENDIF

IF CpuMhz == 50
		freq	50_000_000
	ENDIF
IF CpuMhz == 75
		freq	75_000_000
	ENDIF
IF CpuMhz == 100
		freq	100_000_000
	ENDIF

IF CpuPins > 18
 IF CpuPins > 28
GPRegOrg	=	$0A	;$0A to $0F - limited to 6 bytes - global
 ELSE
GPRegOrg	=	8	;$08 to $0F - limited to 8 bytes - global
 ENDIF
ELSE
GPRegOrg	=	7	;$07 to $0F - limited to 9 bytes - global
ENDIF

;change YOURID to up to 8 characters that identify the project.
		id	'YOURID'
RESET reset_entry

;EQUATES *************************************************************************


OptRTCisW	=	%01111111	;And with Opts to make register 1 show W
OptRTCEnable	=	%10111111	;And with Opts to enable rtcc interrupt
OptRTCInternal	=	%11011111	;And with Opts to make rtcc internal
OptRTCIntLead	=	%11101111	;And with Opts to make rtcc inc on Leading edge
OptRTCPrescale	=	%11110111	;And with Opts to enable rtcc prescaler
Opts		=	%11111000	;base Options. Last 3 bits are the PreScale divider.

IF CpuMhz = 100	
OptPreScale 	= 	8
IntPeriod	=	217		;will be subtracted from 256 to inc RTCC
myOpts		=	Opts & OptRTCEnable & OptRTCInternal & OptRTCisW
;217*8=1736 cycles per interrupt. 
;57,604 Hz interrupt rate 0.000,017,36 seconds per interrupt
 ENDIF

IF CpuMhz = 75	
OptPreScale 	= 	8
IntPeriod	=	244		;will be subtracted from 256 to inc RTCC
myOpts		=	Opts & OptRTCEnable & OptRTCInternal & OptRTCisW
;244*8=1952 cycles per interrupt. 
;38,422 Hz interrupt rate 0.000,026 seconds per interrupt
 ENDIF

IF CpuMhz = 50	
OptPreScale	= 	4
IntPeriod	=	217		;will be subtracted from 256 to inc RTCC
myOpts		=	Opts & OptRTCEnable & OptRTCInternal & OptRTCisW
;217*4=868 cycles per interrupt. 
;57,604 Hz interrupt rate 0.000,017,36 seconds per interrupt

 ENDIF
;217 is a magic number that "just works" at 50 or 100Mhz for RS232 irrespective 
;of the Pre Scale. See
;http://www.sxlist.com/techref/scenix/isrcalc.asp 
;to calculate other options


;PreScaleBits 000=1:2, 001=1:4, 010=1:8, 011=1:16, 100=1:32, 101=1:64, 110=1:128, 111=1:256
OptPreScaleBits = ((OptPreScale>3)&1) + ((OptPreScale>7)&1) + ((OptPreScale>15)&1)
OptPreScaleBits = OptPreScaleBits + ((OptPreScale>31)&1) + ((OptPreScale>63)&1)
OptPreScaleBits = OptPreScaleBits + ((OptPreScale>127)&1) + ((OptPreScale>255)&1)
IF OptPreScale > 1
 IF OptPreScale != 2<<OptPreScaleBits	
  ;Just incase an invalid PreScale was selected
  ERROR 'invalid Prescale value'
 ELSE
myOpts		=	myOpts & OptRTCPrescale | OptPreScaleBits
  ENDIF
ELSE
myOpts		= 	myOpts | (255^OptRTCPreScale)
 ENDIF

ISRRate = 0
IF myOpts & OptRTCEnable && myOpts & OptRTCInternal
 MaxISRCycles = OptPreScale * IntPeriod
 ISRRate = cpuMHz*1000000 / MaxISRCycles
 ENDIF

; The following three values determine the UART baud rate.
;  Baud rate = cpuMHz/(RS232ISRDiv * MaxISRCycles)
;            = cpuMHz/(RS232ISRDiv * OptPreScale * IntPeriod)
;
RS232BaudRate	=	9600
RS232ISRDiv 	= 	ISRRate / RS232BaudRate
IF RS232ISRDiv < 1 || RS232ISRDiv > 255
 ERROR 'RS232BaudRate incompatible with cpuMhz and OptPreScale'
 ENDIF
; The start delay value must be set equal to RS232ISRDiv * 1.5 + 1
RS232StartDelay	=	RS232ISRDiv + (RS232ISRDiv>>1) + 1

WKPND_B		=	$09
WKED_B		=	$0A
WKEN_B		=	$0B
TRIS		=	$0F


;MACROS -------------------------------------------------------
include 'sasmcond.src'	;Conditionals: IF, ELSEIF, ELSE, ENDIF / REPEAT, WHILE, UNTIL / SELECT CASE
include 'sasmmem.src'	;Memory management, tables, automatic paging
include 'sasmdel.src';Delay and timers
include 'sasmport.src'	;Port setup and Control

;PORTS --------------------------------------------------------

IF CpuPins > 28 ;CPUPins = 48 or 52
 IF CpuPins > 48 
;CPUPins = 52

 ELSE
;CPUPins = 48

  ENDIF
ELSE	;CPUPins = 18 or 28
 IF CpuPins > 18 
;CPUPins = 28

 ELSE
;CPUPins = 18

  ENDIF
 ENDIF
rbIntMask = 0

;VARIABLES ****************************************************
;ds allocates registers starting from the register number 
; specifed by the org address which does not relate to a 
; program memory address
;GLOBAL VARIABLES ---------------------------------------------
			org	GPRegOrg
Temp			ds	1
flags			ds	1	;general flag register
RS232Rx_flag         	=	flags.0
RS232RxFrameErr		=	flags.1
TimerFlag		=	flags.2	;timer rollover flag
Timers			=	$	;timer
TimerAccL		ds	1	;timer accumulator low
TimerAccH		ds	1	;timer accumulator high
TimerAccT		ds	1	;timer accumulator top
			watch TimerFlag, 1, ubin
			watch TimerAccL, 24, uhex
StackPtr		ds	1	;Stack
watch StackPtr,8,UHEX


IF $ > $10
 ERROR 'out of gobal variable space'
 ENDIF
;BANK 0 VARIABLES ---------------------------------------------
		org $10	;$10 to $1F - limit 16 bytes - bank 0
bank0			=	$
;place variables and watches here
VPSSlice		ds	1
VPSCount		ds	1

IntI			ds 	1
watch IntI,8,UHEX
IntJ			ds 	1
watch IntJ,8,UHEX
errat			ds 	1
watch errat,8,UHEX

IF $ > $20
 ERROR 'out of variable space'
 ENDIF

;BANK 1 VARIABLES ---------------------------------------------

		org $30	;$30 to $3F - limit 16 bytes - bank 1
bank1			=	$
;place variables here

IF $ > $40
 ERROR 'out of variable space'
 ENDIF


;BANK 2 VARIABLES ---------------------------------------------
		org $50	;$50 to $5F - limit 16 bytes - bank 2
bank2			=	$
;place variables here

IF $ > $60
 ERROR 'out of variable space'
 ENDIF

;BANK 3 VARIABLES ---------------------------------------------
		org $70	;$70 to $7F - limit 16 bytes - bank 3
bank3			=	$
;place variables here

IF $ > $80
 ERROR 'out of variable space'
 ENDIF


;BANK 4 VARIABLES ---------------------------------------------
		org $90	;$90 to $9F - limit 16 bytes - bank 4
bank4		=	$
;place variables here

IF $ > $A0
 ERROR 'out of variable space'
 ENDIF

;BANK 5 VARIABLES ---------------------------------------------
		org $B0	;$B0 to $BF - limit 16 bytes - bank 5
bank5			=	$
;place variables here

IF $ > $C0
 ERROR 'out of variable space'
 ENDIF

;BANK 6 VARIABLES ---------------------------------------------
		org $D0	;$D0 to $DF - limit 16 bytes - bank 6
bank6		=	$
;place variables here

IF $ > $E0
 ERROR 'out of variable space'
 ENDIF

;BANK 7 VARIABLES ---------------------------------------------
		org $E0	;$E0 to $EF - limit 16 bytes - bank 7
bank7		=	$
Stack			ds	16	;Stack
;place variables here

IF $ > $100
 ERROR 'out of variable space'
 ENDIF


ISR ;(Interrupt Service Routine) ******************************
;put your ISR (or just a jump to it) here.
;org is now being used to set the starting point in code memory
		org $0
        jmp @VPS

:Out ;---------------------------------------------------------
;The Virtual Peripherals are expected to jump back
; to @ISR:Out when done
 IF CpuLongDate != 1
        ; << added to correct bug in 9818 chips
                mov m,#WKEN_B   ;Enable Port B interrupts
                mov !rb,#rbIntMask
                mov m,#TRIS     ;Point mode back to ports
        ; end bug fix >>
  ENDIF
                mov !option, #myOpts
                mov     w,#(256-IntPeriod)           ;1
                retiw                           ;3
;retiw adds w to RTCC which avoids
;jitter due to variations in ISR path or latency.

TABLES ;*******************************************************
;Jump tables are assembled here by the SUBROUTINE,
; and GOTOW macros.
LowHalfPage = $
HighHalfPage = $100
        org HighHalfPage        ;Leave space in the first LowHalfpage

;STARTUP ******************************************************
reset_entry		;must be in the first page
	jmp @SETUP

	org $+2		;leave room for the debugger


;Virtual Peripherals ******************************************
;The Virtual Peripherals are expected to jump back to @ISR:Out
; when done

UART ;Universal Asynchronous Receiver Transmitter
;(UART) Virtual Peripheral-------------------------------------
;etc
        jmp @ISR:Out

PWM ;Pulse Width Modulation Virtual Peripheral ----------------
;etc
        jmp @ISR:Out

VPS ;Virtual Peripheral Sequencer------------------------------
;Time slice kernal goes here
;Positioned after the Virtual Peripherals so the GotoW avoids
; forward references.
        mov w, --VPSSlice
        snz
        mov w, #VPSCount
        mov VPSSlice, w
        GotoW UART, PWM	;,etc...

SETUP ;********************************************************
; IO PORTS ----------------------------------------------------
		bank 0

;mode (m) defaults to $0F or $1F - !r{a,b,c} is the data 
;direction register. Ports default to input, no pullup, ttl, 
;on all pins

IF CPUPins > 28
;   SX52 Port setup
;  
		PortMode TRIS

ELSE
;   SX28 Port setup
;  
		PortMode TRIS
ENDIF

; RAM - reset all ram banks
; GLOBAL RAM --------------------------------------------------
		mov	fsr,#GPRegOrg
:gloop
		clr	ind	;clear register pointed to by fsr
		inc	fsr
		sb	fsr.4
		jmp	@:gloop	;until fsr rolls over from $0F

; RAM BANKS ---------------------------------------------------
:loop
IF CpuPins <= 28
		setb	fsr.4	;avoid control registers on smaller chips
ENDIF
		clr	ind	;set register pointed to by fsr to zero
		ijnz	fsr,@:loop	;until fsr rolls over from $FF

;SUBROUTINES **************************************************
;with luck, the ISR and VPS will push this into a new 
; LowHalfPage. Subroutines can be rearranged manually to help
; the macros save memory.

SUB1 Subroutine ;==============================================
:Entry = SubEntryAddr
        nop
;do stuff
        jc @:Out
:test
        djnz $10,@:test
:Out


MAIN ;PROGRAM *************************************************

	noexpand
:ONE
	mmov intI, intJ, 3

	LookupW Main,intI,:done

	call @SUB1:Entry	;global call to subroutine
;	call SUB1		;local call to subroutine


	clr IntI
:zeroloop
	test IntI
	jnz :notzero
:zero
	mov errat,#($ & $FF)
	Skz IntI,IsZero
	jmp :bogus
	mov errat,#($ & $FF)
	Skz IntI,IsNotZero
	skip
	jmp :bogus
	djnz IntI, :zeroloop
	jmp :done
:notzero
	mov errat,#($ & $FF)
	Skz IntI,IsZero
	skip
	jmp :bogus
	mov errat,#($ & $FF)
	Skz IntI,IsNotZero
	jmp :bogus
	djnz intI,:zeroloop
:done	
	clr IntI
:outsideloop
	clr IntJ
:insideloop

	mov w, IntI
	mov w, IntJ-w
	snc
	jmp :ILTJOut 
:ILTJ
;yess
	mov errat,#($ & $FF)
	Skc IntI,NE,IntJ
	jmp :bogus

	mov errat,#($ & $FF)
	Skc IntI,Lt,IntJ
	jmp :bogus

	mov errat,#($ & $FF)
	Skc IntI,LE,IntJ
	jmp :bogus

;nos
	mov errat,#($ & $FF)
	Skc IntI,Eq,IntJ
	skip
	jmp :bogus

	mov errat,#($ & $FF)
	Skc IntI,Gt,IntJ
	skip
	jmp :bogus

	mov errat,#($ & $FF)
	Skc IntI,GE,IntJ
	skip
	jmp :bogus

:ILTJOut
	mov w, IntJ
	mov w, IntI-w
	sz
	jmp :IEQJOut
;IEQJ
;yess
	mov errat,#($ & $FF)
	Skc IntI,Eq,IntJ
	jmp :bogus

	mov errat,#($ & $FF)
	Skc IntI,LE,IntJ
	jmp :bogus

	mov errat,#($ & $FF)
	Skc IntI,GE,IntJ
	jmp :bogus


;nos
	mov errat,#($ & $FF)
	Skc IntI,NE,IntJ
	skip
	jmp :bogus

	mov errat,#($ & $FF)
	Skc IntI,Lt,IntJ
	skip
	jmp :bogus

	mov errat,#($ & $FF)
	Skc IntI,Gt,IntJ
	skip
	jmp :bogus


:IEQJOut
	mov w, IntI
	mov w, IntJ-w
	sc
	jmp :IGTJOut
	
:IGTJ
;yess
	mov errat,#($ & $FF)
	Skc IntI,NE,IntJ
	jmp :bogus

	mov errat,#($ & $FF)
	Skc IntI,Gt,IntJ
	jmp :bogus

	mov errat,#($ & $FF)
	Skc IntI,GE,IntJ
	jmp :bogus

;nos
	mov errat,#($ & $FF)
	Skc IntI,Eq,IntJ
	skip
	jmp :bogus

	mov errat,#($ & $FF)
	Skc IntI,Lt,IntJ
	skip
	jmp :bogus

	mov errat,#($ & $FF)
	Skc IntI,LE,IntJ
	skip
	jmp :bogus


:IGTJOut

	djnz IntJ,:insideloop

	djnz IntI,:outsideloop



	DoIf 1,lt,0	
;1=WReg or RTCC. RTCC is only going to get used in ISRs so just assume its W
	  clr 1
	  doendif	
	clr 2

	doif 2,eq,0	;Bank 0 registers so no bank but do load W.
	  clr 3
	  doendif
	clr 4

	doif 5,IsZero
	  clr 6
	  doendif
	clr 7

	repeat
	  clr 8
	  repeat
	    xor 8, 8
	    until 9, LEN, 8
	  until 9,IsNotZero

	repeat
	  clr 10
	  while 11,IsZero

	repeat
	  clr 12
	  forever

	doif 16,eq,17	;two registers in same (non zero) bank. One bank needed.
	  clr 18
	  doendif
	clr 19

	doif 20,eq,$30	;two registers in two different banks.
	  clr 21
	  doendif
	clr 22

	doif 23,eq,24
	  clr 25
	doelseif 26,lt,27
	  clr 28
	doelse
	  clr 28
	  doendif
	clr 29

;	push WReg
;	push 30
;	pop 31
;	pop PC

	doif 32,ltN,33
	  clr 34
	doelseif 35,gtN,36
	  clr 37
	doelseif 37,gtN,38
	  doendif

	clr errat

	doif 1, LtN, 0
		clr 32
	 doif 2, Lt, 33
		clr 33
	  doendif
	 doendif


		org 2<<9 - 2
	LookupW Main,intI,:done

:TWO
	nop
		org 2<<9 + 100
;And now, lets KICK IT UP A BIT!!!

	DoSelect
	DoCase 23,eq,24
	  clr 25
	DoCase 26,eq,27
	  clr 28
	  DoSelect
	  DoCase 29,eq,30
	   clr 31
	   DoIf 32,EqN,32
	    clr 33
	   DoElseIf 34,Lt,35
	    clr 36
	   DoElse
	    clr 37
	    DoEndIf
	  DoCase 27,eq,25
	   clr 25
	  DoCaseElse
	   clr 25
	   DoCaseEnd
	DoCaseElse
	 clr 25
	 DoCaseEnd

:THREE
	nop
		org 2<<9 + 250
	gotow :ONE, :TWO, :THREE, :ONE, :TWO, :THREE
	cyclefor 2
	delay 2, cycles
	delay 2, usec
	delay 2, msec
	delay 2, sec
	delay 999, sec

		org 3<<9
:FOUR
	nop
	gotow :ONE, :TWO, :THREE, :FOUR
	gotow :ONE, :TWO, :THREE, :FOUR, :ONE, :TWO, :THREE, :FOUR
		org 3<<9 + 259
	gotow :ONE, :TWO, :THREE, :FOUR, :ONE, :TWO, :THREE, :FOUR


	binjump intI,:zero, :notzero, :done, :outsideloop, :bogus 

	GotoW :zero, :notzero, :done, :outsideloop, :insideloop 

	Push intI
	Pop intI
	


:bogus
	break

	end
