;*****************************************************************************************
; Copyright (c) [01/26/1999] Scenix Semiconductor, Inc. All rights reserved.
;
; Scenix Semiconductor, Inc. assumes no responsibility or liability for
; the use of this [product, application, software, any of these products].
; Scenix Semiconductor conveys no license, implicitly or otherwise, under
; any intellectual property rights.
; Information contained in this publication regarding (e.g.: application,
; implementation) and the like is intended through suggestion only and may
; be superseded by updates. Scenix Semiconductor makes no representation
; or warranties with respect to the accuracy or use of these information,
; or infringement of patents arising from such use or otherwise.
;*****************************************************************************************
; 
; Filename: fft.src	
;
; Authors: unknown	
;		
;		
;
; Revision:	1.01
;
; Part:		SX28AC/DP AB9932AB
;		SX52BD/PQES AB9931AC
; Freq:		50Mhz
; Compiled using Parallax SX-Key software v1.07 and SASM 1.40
;
; Date Written: unknown 
;
; Last Revised: December 3, 1999
;
; Program Description:
;
;		A Cooley-Tukey Radix-2 DIF FFT
;
;	Radix-2 implementation
;	Decimation In Frequency
;	Single Butterfly
;	Table Lookup of Twiddle Factors 
;	Complex Input & Complex Output
;
;	All data is assumed to be 16 bits and the intermediate
;	results are stored in 32 bits
;
;	Length Of FFT must be a Power Of 2
;

;
;	
;
; Revision History:
; Revision 1.00: 	February 26, 1997 	Original version.
; Revision 1.01: 	December 3, 1999 	Converted to standard format. 
;						John Keenan, 
;						Consultant to Scenix Semiconductor, Inc.
;
;*****************************************************************************************

;*****************************************************************************************
; Target SX
; Uncomment one of the following lines to choose the SX18AC, SX20AC, SX28AC, SX48BD/ES,
; SX48BD, SX52BD/ES or SX52BD. For SX48BD/ES and SX52BD/ES, uncomment both defines,
; SX48_52 and SX48_52_ES.
;*****************************************************************************************
;SX18_20
SX28
;SX48_52
;SX48_52_ES

;*****************************************************************************************
; Assembler Used
; Uncomment the following line if using the Parallax SX-Key assembler. SASM assembler
; enabled by default.
;*****************************************************************************************
;SX_Key

	;*********************************************************************************
	; Assembler directives:
	;	high speed external osc, turbo mode, 8-level stack, and extended option reg.
	;
	;	SX18/20/28 - 4 pages of program memory and 8 banks of RAM enabled by default.
	;	SX48/52 - 8 pages of program memory and 16 banks of RAM enabled by default.
	;                
	;*********************************************************************************

IFDEF SX_Key 				;SX-Key Directives
  IFDEF SX18_20				;SX18AC or SX20AC device directives for SX-Key
		device	SX18L,oschs2,turbo,stackx_optionx
  ENDIF
  IFDEF SX28				;SX28AC device directives for SX-Key		
		device	SX28L,oschs2,turbo,stackx_optionx
  ENDIF
  IFDEF SX48_52_ES			;SX48BD/ES or SX52BD/ES device directives for SX-Key
		device	oschs,turbo,stackx,optionx
  ELSE
    IFDEF SX48_52				;SX48/52/BD device directives for SX-Key
		device	oschs2
    ENDIF
  ENDIF
		freq	50_000_000
ELSE  					;SASM Directives
  IFDEF SX18_20				;SX18AC or SX20AC device directives for SASM
		device	SX18,oschs2,turbo,stackx,optionx
  ENDIF
  IFDEF SX28				;SX28AC device directives for SASM
		device	SX28,oschs2,turbo,stackx,optionx
  ENDIF
  IFDEF SX48_52_ES			;SX48BD/ES or SX52BD/ES device directives for SASM
		device	SX52,oschs,turbo,stackx,optionx
  ELSE
    IFDEF SX48_52			;SX48BD or SX52BD device directives for SASM
		device	SX52,oschs2  
    ENDIF
  ENDIF
ENDIF
		id	'r2-fft'			; program id
		reset	reset_entry		; set reset vector

;*****************************************************************************************
; Macros
;*****************************************************************************************

	;*********************************************************************************
	; Macro: _bank
	; Sets the bank appropriately for all revisions of SX.
	;
	; This is required since the bank instruction has only a 3-bit operand, it cannot
	; be used to access all 16 banks of the SX48/52. For this reason FSR.4 (for SX48/52BD/ES)
	; or FSR.7 (SX48/52bd production release) needs to be set appropriately, depending
	; on the bank address being accessed. This macro fixes this.
	;
	; So, instead of using the bank instruction to switch between banks, use _bank instead.
	; 
	;*********************************************************************************
_bank	macro	1
  noexpand
	bank	\1
	IFDEF SX48_52
	  IFDEF SX48_52_ES
	    IF \1 & %00010000		;SX48BD/ES and SX52BD/ES (engineering sample) bank instruction
  expand
		setb	fsr.4		;modifies FSR bits 5,6 and 7. FSR.4 needs to be set by software.
  noexpand
	    ENDIF
	  ELSE
	    IF \1 & %10000000		;SX48BD and SX52BD (production release) bank instruction 
  expand
		setb	fsr.7		;modifies FSR bits 4,5 and 6. FSR.7 needs to be set by software.
  noexpand
	    ELSE
  expand
		clrb	fsr.7
  noexpand
	    ENDIF
	  ENDIF
	ENDIF
	endm

	;*********************************************************************************
	; Macro: _mode
	; Sets the MODE register appropriately for all revisions of SX.
	;
	; This is required since the MODE (or MOV M,#) instruction has only a 4-bit operand. 
	; The SX18/20/28AC use only 4 bits of the MODE register, however the SX48/52BD have 
	; the added ability of reading or writing some of the MODE registers, and therefore use
	; 5-bits of the MODE register. The  MOV M,W instruction modifies all 8-bits of the 
	; MODE register, so this instruction must be used on the SX48/52BD to make sure the MODE
	; register is written with the correct value. This macro fixes this.
	;
	; So, instead of using the MODE or MOV M,# instructions to load the M register, use
	;  _mode instead.
	; 
	;*********************************************************************************
_mode	macro	1
  noexpand
	IFDEF SX48_52
  expand
		mov	w,#\1&$1F	;loads the M register correctly for the SX48BD and SX52BD
		mov	m,w
  noexpand
	ELSE
  expand
		mov	m,#\1&$0F	;loads the M register correctly for the SX18AC, SX20AC
					;and SX28AC
  noexpand
	ENDIF
	endm
	
	;*********************************************************************************
	; 16/32 bit Macros:	; 
	;*********************************************************************************

RRC16 	MACRO     1		; 16 bit signed rotate right (=/2)

	mov	w,<<\1+B1	; move sign into carry bit
	rr	\1+B1		; rotate MSByte first
	rr	\1+B0		; then LSByte to propagate carry
	
	ENDM

ADD16 	MACRO     2 			; 16 bit addition, result in second parameter

	add	\2+B0,\1+B0
	snc
	inc	\2+B1		
	add	\2+B1,\1+B1        

	ENDM

SUB16ACC MACRO  3		; 16 bit subtraction, result in the third parameter
				; \3=\2-\1
	mov	w,\1+B0	        ; get lowest byte of a into w
	mov	w,\2+B0-w	
	mov     \3+B0,w

	mov	w,\1+B1		; get 2nd byte of a into w
	sc			; propagate carry
	mov	w,++\1+B1
	mov	w,\2+B1-w
	mov	\3+B1,w
	
	ENDM

MOV32	MACRO   2

	mov	\2+B0,\1+B0               ; move A(B0) to B(B0)
	mov	\2+B1,\1+B1               ; move A(B1) to B(B1)
	mov	\2+B2,\1+B2               ; move A(B2) to B(B2)
	mov	\2+B3,\1+B3               ; move A(B3) to B(B3)

	ENDM

ADD32 	MACRO     2

	add	\2+B0,\1+B0 
	jnc	abyte1
	
	mov	w,#1			; propagate carry
	add	\2+B1,w
	jnc	abyte1
	add	\2+B2,w
	jnc	abyte1
	add	\2+B3,w


abyte1	add	\2+B1,\1+B1
	jnc	abyte2

	mov	w,#1			; propagate carry
	add	\2+B2,w
	jnc	abyte2
	add	\2+B3,w


abyte2	add	\2+B2,\1+B2
	jnc	abyte3

	mov	w,#1			; propagate carry
	add	\2+B3,w

abyte3	add	\2+B3,\1+B3
	           
	ENDM

SUB32 	MACRO     2		; 32 bit subtraction, result in second parameter

	sub	\2+B0,\1+B0
	jc	sbyte1

	mov	w,#1		; propagate carry
	mov	w,\2+B1-w
	mov	\2+B1,w
	jc	sbyte1

	mov	w,#1		
	mov	w,\2+B2-w
	mov	\2+B2,w
	jc	sbyte1

	mov	w,#1		
	mov	w,\2+B3-w
	mov	\2+B3,w
	jc	sbyte1

sbyte1	sub	\2+B1,\1+B1
	jc	sbyte2

	mov	w,#1		; propagate carry
	mov	w,\2+B2-w
	mov	\2+B2,w
	jc	sbyte2

	mov	w,#1		
	mov	w,\2+B3-w
	mov	\2+B3,w

sbyte2	sub	\2+B2,\1+B2
	jc	sbyte3

	mov	w,#1		; propagate carry
	mov	w,\2+B3-w
	mov	\2+B3,w

sbyte3	sub	\2+B3,\1+B3

	ENDM


;*****************************************************************************************
; Data Memory address definitions
; These definitions ensure the proper address is used for banks 0 - 7 for 2K SX devices
; (SX18/20/28) and 4K SX devices (SX48/52). 
;*****************************************************************************************
IFDEF SX48_52

global_org	=	$0A
bank0_org	=	$00
bank1_org	=	$10
bank2_org	=	$20
bank3_org	=	$30
bank4_org	=	$40
bank5_org	=	$50
bank6_org	=	$60
bank7_org	=	$70

ELSE

global_org	=	$08
bank0_org	=	$10
bank1_org	=	$30
bank2_org	=	$50
bank3_org	=	$70
bank4_org	=	$90
bank5_org	=	$B0
bank6_org	=	$D0
bank7_org	=	$F0

ENDIF
;*****************************************************************************************
; Global Register definitions
; NOTE: Global data memory starts at $0A on SX48/52 and $08 on SX18/20/28.
;*****************************************************************************************
		org     global_org


Cos		equ	global_org
ptr_low		equ	Cos
Cos1		equ	global_org+1
ptr_high	equ	Cos1
Sin		equ	global_org+2
rw_cnt		equ	Sin
Sin1		equ	global_org+3
w_temp		equ	global_org+4

;*****************************************************************************************
; RAM Bank Register definitions
;*****************************************************************************************

	;*********************************************************************************
	; Bank 0
	;*********************************************************************************
		org     bank0_org

bank0		=	$


	;*********************************************************************************
	; Bank 1
	;*********************************************************************************
		org     bank1_org

bank1		=	$
primary		=	$

Xi		ds	1
Xi1		ds	1

Yi		ds	1
Yi1		ds	1

Xl		ds	1
Xl1		ds	1

Yl		ds	1
Yl1		ds	1
				
Xt		ds	1
Xt1		ds	1

Yt		ds	1
Yt1		ds	1



	;*********************************************************************************
	; Bank 2
	;*********************************************************************************
		org     bank2_org

bank2		=	$
var		=	$

VarIloop	ds	1

VarJloop	ds	1
				;=30
VarKloop	ds	1

VarL		ds	1

temp		ds	1
TF_Addr		ds	1
TF_Addr1	ds	1
TF_Offset	ds	1		;twiddle factor offset


count1		ds	1	; N1
count2		ds	1	; N2
top		ds	1
bottom		ds	1
temp1		ds	1
temp2		ds	1
temp3		ds	1  	
temp4		ds	1
	;*********************************************************************************
	; Bank 3
	;*********************************************************************************
		org     bank3_org

bank3		=	$
arith		=	$ 		; for 16 bit x 16 bit multiplication

md16		ds	1
md16_hi		ds	1
mr16		ds	1
mr16_hi		ds	1
upper_prdt	ds	2
count		ds	1
sign		ds	1

AARG		=	mr16
AARG1		=	mr16+1		; 16 bit multiplier A

BARG		=	md16
BARG1		=	md16+1		; 16 bit multiplicand B

DPX		=	mr16		
DPX1		=	mr16+1
DPX2		=	upper_prdt
DPX3    	=	upper_prdt+1	; 32 bit multiplier result = A*B
	
	
ACC		ds	1
ACC1		ds	1
ACC2		ds	1
ACC3		ds	1		; 32 bit accumulator for computations




	;*********************************************************************************
	; Bank 4
	;*********************************************************************************
		org     bank4_org

bank4		=	$



	;*********************************************************************************
	; Bank 5
	;*********************************************************************************
		org     bank5_org

bank5		=	$


	;*********************************************************************************
	; Bank 6
	;*********************************************************************************
		org     bank6_org

bank6		=	$


	;*********************************************************************************
	; Bank 7
	;*********************************************************************************
		org     bank7_org

bank7		=	$


IFDEF SX48_52
	;*********************************************************************************
	; Bank 8
	;*********************************************************************************
		org	$80	;bank 8 address on SX52

bank8		=	$


	;*********************************************************************************
	; Bank 9
	;*********************************************************************************
		org	$90	;bank 9 address on SX52

bank9		=	$



	;*********************************************************************************
	; Bank A
	;*********************************************************************************
		org	$A0	;bank A address on SX52

bankA		=	$


	;*********************************************************************************
	; Bank B
	;*********************************************************************************
		org	$B0	;bank B address on SX52

bankB		=	$


	;*********************************************************************************
	; Bank C
	;*********************************************************************************
		org	$C0	;bank C address on SX52

bankC		=	$


	;*********************************************************************************
	; Bank D
	;*********************************************************************************
		org	$D0	;bank D address on SX52

bankD		=	$


	;*********************************************************************************
	; Bank E
	;*********************************************************************************
		org	$E0	;bank E address on SX52

bankE		=	$


	;*********************************************************************************
	; Bank F
	;*********************************************************************************
		org	$F0	;bank F address on SX52

bankF		=	$


ENDIF
;*****************************************************************************************
; Port Assignment
;*****************************************************************************************

RA_latch	equ	%00001000		;SX18/20/28/48/52 port A latch init
RA_DDIR		equ	%11110111		;SX18/20/28/48/52 port A DDIR value
RA_LVL		equ	%00000000		;SX18/20/28/48/52 port A LVL value
RA_PLP		equ	%11111111		;SX18/20/28/48/52 port A PLP value

RB_latch	equ	%00000000		;SX18/20/28/48/52 port B latch init
RB_DDIR		equ	%11111111		;SX18/20/28/48/52 port B DDIR value
RB_ST		equ	%11111111		;SX18/20/28/48/52 port B ST value
RB_LVL		equ	%00000000		;SX18/20/28/48/52 port B LVL value
RB_PLP		equ	%11111111		;SX18/20/28/48/52 port B PLP value

RC_latch	equ	%00000000		;SX18/20/28/48/52 port C latch init
RC_DDIR		equ	%11111010		;SX18/20/28/48/52 port C DDIR value
RC_ST		equ	%11111111		;SX18/20/28/48/52 port C ST value
RC_LVL		equ	%00000000		;SX18/20/28/48/52 port C LVL value
RC_PLP		equ	%11111111		;SX18/20/28/48/52 port C PLP value
		
IFDEF SX48_52	;SX48BD/52BD Port initialization values
RD_latch	equ	%00000000		;SX48/52 port D latch init
RD_DDIR		equ	%11111111		;SX48/52 port D DDIR value
RD_ST		equ	%11111111		;SX48/52 port D ST value
RD_LVL		equ	%00000000		;SX48/52 port D LVL value
RD_PLP		equ	%11111111		;SX48/52 port D PLP value

RE_latch	equ	%00000000		;SX48/52 port E latch init
RE_DDIR		equ	%11111111		;SX48/52 port E DDIR value
RE_ST		equ	%11111111		;SX48/52 port E ST value
RE_LVL		equ	%00000000		;SX48/52 port E LVL value
RE_PLP		equ	%11111111		;SX48/52 port E PLP value
ENDIF
	;*********************************************************************************
	; Pin Definitions
	;*********************************************************************************


;*****************************************************************************************
; Program constants
;*****************************************************************************************
RamAddr		= 	$90		; SX28 bank 4, SX48/52 bank 9	
SineTable	=	$600

BB0	=	0 			; RAM offset constants
B0	=	BB0
BB1	=	1
B1	=	BB1
BB2	=	2
B2	=	BB2
BB3	=	3	
B3	=	BB3

SCALE_BUTTERFLY	=	1		; intermediate scaling performed

FftLen	=	16			; FFT Length
Power	=	4			; (2**Power = FftLen)

int_period	equ	217		;RTCC Interrupt rate

IFDEF SX48_52
	;*********************************************************************************
	; SX48BD/52BD Mode addresses
	; *On SX48BD/52BD, most registers addressed via mode are read and write, with the
	; exception of CMP and WKPND which do an exchange with W.
	;*********************************************************************************
; Timer (read) addresses
TCPL_R		equ	$00		;Read Timer Capture register low byte
TCPH_R		equ	$01		;Read Timer Capture register high byte
TR2CML_R	equ	$02		;Read Timer R2 low byte
TR2CMH_R	equ	$03		;Read Timer R2 high byte
TR1CML_R	equ	$04		;Read Timer R1 low byte
TR1CMH_R	equ	$05 		;Read Timer R1 high byte
TCNTB_R		equ	$06		;Read Timer control register B
TCNTA_R		equ	$07		;Read Timer control register A

; Exchange addresses
CMP		equ	$08		;Exchange Comparator enable/status register with W
WKPND		equ	$09		;Exchange MIWU/RB Interrupts pending with W

; Port setup (read) addresses
WKED_R		equ	$0A		;Read MIWU/RB Interrupt edge setup, 0 = falling, 1 = rising
WKEN_R		equ	$0B		;Read MIWU/RB Interrupt edge setup, 0 = enabled, 1 = disabled
ST_R		equ	$0C		;Read Port Schmitt Trigger setup, 0 = enabled, 1 = disabled
LVL_R		equ	$0D		;Read Port Schmitt Trigger setup, 0 = enabled, 1 = disabled
PLP_R		equ	$0E		;Read Port Schmitt Trigger setup, 0 = enabled, 1 = disabled
DDIR_R		equ	$0F		;Read Port Direction

; Timer (write) addresses
CLR_TMR		equ	$10		;Resets 16-bit Timer
TR2CML_W	equ	$12		;Write Timer R2 low byte
TR2CMH_W	equ	$13		;Write Timer R2 high byte
TR1CML_W	equ	$14		;Write Timer R1 low byte
TR1CMH_W	equ	$15 		;Write Timer R1 high byte
TCNTB_W		equ	$16		;Write Timer control register B
TCNTA_W		equ	$17		;Write Timer control register A

; Port setup (write) addresses
WKED_W		equ	$1A		;Write MIWU/RB Interrupt edge setup, 0 = falling, 1 = rising
WKEN_W		equ	$1B		;Write MIWU/RB Interrupt edge setup, 0 = enabled, 1 = disabled
ST_W		equ	$1C		;Write Port Schmitt Trigger setup, 0 = enabled, 1 = disabled
LVL_W		equ	$1D		;Write Port Schmitt Trigger setup, 0 = enabled, 1 = disabled
PLP_W		equ	$1E		;Write Port Schmitt Trigger setup, 0 = enabled, 1 = disabled
DDIR_W		equ	$1F		;Write Port Direction

ELSE

	;*********************************************************************************
	; SX18AC/20AC/28AC Mode addresses
	; *On SX18/20/28, all registers addressed via mode are write only, with the exception of
	; CMP and WKPND which do an exchange with W.
	;*********************************************************************************
; Exchange addresses
CMP		equ	$08		;Exchange Comparator enable/status register with W
WKPND		equ	$09		;Exchange MIWU/RB Interrupts pending with W

; Port setup (read) addresses
WKED_W		equ	$0A		;Write MIWU/RB Interrupt edge setup, 0 = falling, 1 = rising
WKEN_W		equ	$0B		;Write MIWU/RB Interrupt edge setup, 0 = enabled, 1 = disabled
ST_W		equ	$0C		;Write Port Schmitt Trigger setup, 0 = enabled, 1 = disabled
LVL_W		equ	$0D		;Write Port Schmitt Trigger setup, 0 = enabled, 1 = disabled
PLP_W		equ	$0E		;Write Port Schmitt Trigger setup, 0 = enabled, 1 = disabled
DDIR_W		equ	$0F		;Write Port Direction
ENDIF

;*****************************************************************************************
; Interrupt Service Routine
;*****************************************************************************************
; Note: The interrupt code must always originate at address $0.
;
; Interrupt Frequency = (Cycle Frequency / -(retiw value))  For example:
; With a retiw value of -217 and an oscillator frequency of 50MHz, this
; code runs every 4.34us.
;*****************************************************************************************
		org     $0
interrupt					;3

	;*********************************************************************************
	; Virtual Peripheral: 
	;
	;
	;	Input variable(s): 
	;	Output variable(s): 
	;	Variable(s) affected: 
	;	Flag(s) affected: 
	;*********************************************************************************
label



	;*********************************************************************************
	; Virtual Peripheral: 
	;
	;
	;	Input variable(s): 
	;	Output variable(s): 
	;	Variable(s) affected: 
	;	Flag(s) affected: 
	;*********************************************************************************
label1

	;*********************************************************************************
	; Set Interrupt Rate
	;*********************************************************************************
isr_end		mov	w,#-int_period		;refresh RTCC on return
		retiw				;return from the interrupt
						; = 1/(int_period*RTCC prescaler*1/50MHz)
						; = 1/(217*1*20ns) = 1/4.34us
;*****************************************************************************************
; End of the Interrupt Service Routine
;*****************************************************************************************

;*****************************************************************************************
; RESET VECTOR 
;*****************************************************************************************

	;*********************************************************************************
	; Program execution begins here on power-up or after a reset
	;*********************************************************************************
reset_entry		
	;*********************************************************************************
	; Initialise all port configuration
	;*********************************************************************************

		_mode	ST_W			;point MODE to write ST register
		mov     w,#RB_ST            	;Setup RB Schmitt Trigger, 0 = enabled, 1 = disabled
		mov	!rb,w		
		mov     w,#RC_ST            	;Setup RC Schmitt Trigger, 0 = enabled, 1 = disabled
		mov	!rc,w	
IFDEF SX48_52
		mov     w,#RD_ST            	;Setup RD Schmitt Trigger, 0 = enabled, 1 = disabled
		mov	!rd,w		
		mov     w,#RE_ST            	;Setup RE Schmitt Trigger, 0 = enabled, 1 = disabled
		mov	!re,w		
ENDIF
		_mode	LVL_W			;point MODE to write LVL register
		mov     w,#RA_LVL            	;Setup RA CMOS or TTL levels, 0 = TTL, 1 = CMOS
		mov	!ra,w		 
		mov     w,#RB_LVL            	;Setup RB CMOS or TTL levels, 0 = TTL, 1 = CMOS
		mov	!rb,w		
		mov     w,#RC_LVL            	;Setup RC CMOS or TTL levels, 0 = TTL, 1 = CMOS
		mov	!rc,w	
IFDEF SX48_52
		mov     w,#RD_LVL            	;Setup RD CMOS or TTL levels, 0 = TTL, 1 = CMOS
		mov	!rd,w		
		mov     w,#RE_LVL            	;Setup RE CMOS or TTL levels, 0 = TTL, 1 = CMOS
		mov	!re,w		
ENDIF
		_mode	PLP_W			;point MODE to write PLP register
		mov     w,#RA_PLP            	;Setup RA Weak Pull-up, 0 = enabled, 1 = disabled
		mov	!ra,w		 
		mov     w,#RB_PLP            	;Setup RB Weak Pull-up, 0 = enabled, 1 = disabled
		mov	!rb,w		
		mov     w,#RC_PLP            	;Setup RC Weak Pull-up, 0 = enabled, 1 = disabled
		mov	!rc,w	
IFDEF SX48_52
		mov     w,#RD_PLP            	;Setup RD Weak Pull-up, 0 = enabled, 1 = disabled
		mov	!rd,w		
		mov     w,#RE_PLP            	;Setup RE Weak Pull-up, 0 = enabled, 1 = disabled
		mov	!re,w		
ENDIF
		_mode	DDIR_W			;point MODE to write DDIR register
		mov	w,#RA_DDIR		;Setup RA Direction register, 0 = output, 1 = input		
		mov	!ra,w	
		mov	w,#RB_DDIR		;Setup RB Direction register, 0 = output, 1 = input
		mov	!rb,w			
		mov	w,#RC_DDIR		;Setup RC Direction register, 0 = output, 1 = input
		mov	!rc,w			
IFDEF SX48_52
		mov	w,#RD_DDIR		;Setup RD Direction register, 0 = output, 1 = input
		mov	!rd,w			
		mov	w,#RE_DDIR		;Setup RE Direction register, 0 = output, 1 = input
		mov	!re,w			
ENDIF
		mov     w,#RA_latch          	;Initialize RA data latch
		mov     ra,w		
		mov     w,#RB_latch         	;Initialize RB data latch
		mov     rb,w		
		mov     w,#RC_latch          	;Initialize RC data latch
		mov     rc,w		
IFDEF SX48_52
		mov     w,#RD_latch         	;Initialize RD data latch
		mov     rd,w			
		mov     w,#RE_latch         	;Initialize RE data latch
		mov     re,w			
ENDIF

	;*********************************************************************************
	; Clear all Data RAM locations
	;*********************************************************************************
IFDEF SX48_52   				;SX48/52 RAM clear routine
		mov	w,#$0a			;reset all ram starting at $0A
		mov	fsr,w
:zero_ram	clr	ind			;clear using indirect addressing
		incsz	fsr			;repeat until done
		jmp	:zero_ram

		_bank	bank0			;clear bank 0 registers
		clr	$10
		clr	$11
		clr	$12
		clr	$13
		clr	$14
		clr	$15
		clr	$16
		clr	$17
		clr	$18
		clr	$19
		clr	$1a
		clr	$1b
		clr	$1c
		clr	$1d
		clr	$1e
		clr	$1f

ELSE     					;SX18/20/28 RAM clear routine
		clr	fsr			;reset all ram banks
:zero_ram	sb	fsr.4			;are we on low half of bank?
		setb	fsr.3			;If so, don't touch regs 0-7
		clr	ind			;clear using indirect addressing
		incsz	fsr			;repeat until done
		jmp	:zero_ram
ENDIF
	;*********************************************************************************
	; Initialize program/VP registers
	;*********************************************************************************


	;*********************************************************************************
	; Setup and enable RTCC interrupt, WREG register, RTCC/WDT prescaler
	;*********************************************************************************

RTCC_ON		=	%10000000	;Enables RTCC at address $01 (RTW hi)
					;*WREG at address $01 (RTW lo) by default
RTCC_ID		=	%01000000	;Disables RTCC edge interrupt (RTE_IE hi)
					;*RTCC edge interrupt (RTE_IE lo) enabled by default
RTCC_INC_EXT	=	%00100000	;Sets RTCC increment on RTCC pin transition (RTS hi)
					;*RTCC increment on internal instruction (RTS lo) is default
RTCC_FE		=	%00010000	;Sets RTCC to increment on falling edge (RTE_ES hi)
					;*RTCC to increment on rising edge (RTE_ES lo) is default
RTCC_PS_ON	=	%00000000	;Assigns prescaler to RTCC (PSA lo)
RTCC_PS_OFF	=	%00001000	;Assigns prescaler to WDT (PSA hi)
PS_000		=	%00000000	;RTCC = 1:2, WDT = 1:1
PS_001		=	%00000001	;RTCC = 1:4, WDT = 1:2
PS_010		=	%00000010	;RTCC = 1:8, WDT = 1:4
PS_011		=	%00000011	;RTCC = 1:16, WDT = 1:8
PS_100		=	%00000100	;RTCC = 1:32, WDT = 1:16
PS_101		=	%00000101	;RTCC = 1:64, WDT = 1:32
PS_110		=	%00000110	;RTCC = 1:128, WDT = 1:64
PS_111		=	%00000111	;RTCC = 1:256, WDT = 1:128

		mov	w,#RTCC_ID	;setup option register
		mov	!option,w
		jmp	@main

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

	;*********************************************************************************
	; Main
	;*********************************************************************************
main		


;*******************************************************************

; load test data into ram
;*******************************************************************

	_bank	var
	mov	ptr_low,#(testdata-((testdata/256)*256))	; low address byte
	mov	ptr_high,#testdata/256	; high address byte
	mov	fsr,#RamAddr		; load start address	
	mov	rw_cnt,#Fftlen		; how many times to write
loaddata
	mov	m,ptr_high
	mov	w,ptr_low
	iread				; read data
	mov	ind,w			; store lower byte of real data
	inc	ptr_low			; next
	mov	m,ptr_high
	mov	w,ptr_low
	iread				; read data
	inc	fsr			
	mov	ind,w			; store upper byte of real data
	clr	w			; imaginary data is always 0
	inc	fsr
	mov	ind,w
	inc	fsr
	mov	ind,w

	inc	ptr_low
	inc	fsr
	setb	fsr.4
	decsz	rw_cnt
	jmp	loaddata

					; test data now loaded

;*****************************************************************************************

	call	@R2FFT		; Compute Fourier Transform

		
	call	@Unscramble	; bit reverse the scrambled data



	;*********************************************************************************
	; Main Program Loop
	;*********************************************************************************
main_loop

	jmp	main_loop	; Fourier Transform Completed




org	$200
;*****************************************************************************************
; Jump table for page 1
; Enables CALLs to functions in the second half of the page 
;*****************************************************************************************
R2FFT		jmp	@R2FFT_ 
Unscramble	jmp	@Unscramble_
DblMult		jmp	@DblMult_

;*****************************************************************************************
; Subroutines
;*****************************************************************************************

	;*********************************************************************************
	; Function: R2FFT 
	;			RADIX-2 FFT
	;
	;	Decimation In Frequency 
	;
	; Input Data should be unscrambled
	; Output Data at the end is in scrambled form
        ;
	; 
	; Inputs: Rom: Sine/Cosine Table, Ram: banks 9x,Bx,Dx,Fx,
	;	
	; Outputs: 		Ram: banks 9x,Bx,Dx,Fx,
	;	
	; Registers affected: 	TF_Offset, TF_Addr, TF_Addr1, count1, count2, 
	;			VarL, VarIloop, VarJloop, VarKloop
	;			temp1, temp2, temp3, temp4, top, bottom 
	;			mr16, mr16+1, md16, md16+1
	;
	; Functions Called: 	DblMult
	;
	;*********************************************************************************


R2FFT_
	_bank	var
	mov	TF_Offset,#1		; Init TF_Offset = 1
	
	mov	count2,#FftLen		; count2 = N=16
	mov 	VarKloop,#Power		; Kloop
Kloop					; for K = 1 to Power-1
	mov	count1,count2		; count1 = count2

	clc
	rr	count2			; count2 = count2/2
	clr	VarJloop		; J = 0
	
	clr	TF_Addr
	clr	TF_Addr1

	

Jloop
;
; Read Twiddle factors from Sine/Cosine Table from Prog Mem
;
	mov	temp1,#(SineTable-((SineTable/256)*256))
	mov	temp2,#SineTable/256	; load sine table address to table pointers
	mov	w,TF_Addr
	add	temp1,w
	mov	w,TF_Addr1
	snc
	inc	temp2
	add	temp2,w
	
	mov	m,temp2			; load m first, since w will be used in doing it
	mov	w,temp1

	iread	
	mov	Sin,w			; get the sine value (low byte)

	inc	temp1			; no need to propagate carry since sine table is aligned to
					; X00
	
	; both m and w are altered by iread, thus the reload

	mov	m,temp2		; m should be loaded first
	mov	w,temp1		

	iread
	mov	Sin+BB1,w		; Read MSB of Sine Value from lookup table

	add	temp1,#(Fftlen/4)*2-1	; prepare to read cosine table, *2 because each
					; entry occupies two bytes, -1 because we have 
					; incremented once to read the high byte of sine
	
	mov	m,temp2
	mov	w,temp1
	
	iread
	
	mov	Cos,w

	inc	temp1
	; both m and w are altered by iread, thus the reload

	mov	m,temp2
	mov	w,temp1

	iread
	mov	Cos+BB1,w		; Read MSB of cosine Value from lookup table

	clc
	mov	w,<<TF_Offset 		; rotate left through carry into w
	snc
	inc	TF_Addr                 ; propagate carry
	add	TF_Addr,w 
	snc                		
	inc	TF_Addr1                ; propagate carry
		
	
	
	clc
	mov	w,<<VarJloop
	mov	VarIloop,w		; I = J*2 since Real followed by Imag Data
Iloop
	;compute for pointer address that can be used throughout the loop
	clc
	mov	w,<<VarIloop		; rotate left through carry into w	
	mov	temp1,w
	and	w,#%11110000		; mask off lsb
	; no overflow can happen, else we will be out of range of memory 
	snc
	or	w,#%00000001		; propagate carry
	add	w,temp1			; adjust for gap in register banks
	mov	top,w 
	snc
	inc	top			; propagate carry
	add	top,#RamAddr

	mov	w,<<count2		
	mov	VarL,w			; VarL = count2*2 
	snc	
	inc	VarL			; propagate carry
	add	VarL,VarIloop		; VarL = I+count2*2

	
	mov	w,<<VarL			
	mov	temp1,w
	and	w,#%11110000		; mask off lsb 
	snc
	or	w,#%00000001		; propagate carry
	add	w,temp1			; adjust for gap in register banks
	mov	bottom,w 
	snc	
	inc	bottom			; propagate carry
	add	bottom,#RamAddr

	mov	fsr,bottom		; read bottom data on the butterfly
	mov	w,ind
	_bank	var
	mov	temp1,w

	mov	fsr,bottom
	inc	fsr
	mov	w,ind
	_bank	var
	mov	temp2,w

	mov	fsr,bottom
	inc	fsr
	inc	fsr
	mov	w,ind
	_bank	var
	mov	temp3,w

	mov	fsr,bottom
	inc	fsr
	inc	fsr
	inc	fsr
	mov	w,ind
	_bank	var
	mov	temp4,w


	mov	w,temp1
	_bank	primary
	mov	Xl,w
	_bank	var
	mov	w,temp2
	_bank	primary
	mov	Xl+1,w
	_bank	var
	mov	w,temp3
	_bank	primary
	mov	Yl,w
	_bank	var
	mov	w,temp4
	_bank	primary
	mov	Yl+1,w
	_bank	var
	


					; read top data on the butterfly

	mov	fsr,top
	mov	w,ind
	_bank	var
	mov	temp1,w

	mov	fsr,top
	inc	fsr
	mov	w,ind
	_bank	var
	mov	temp2,w

	mov	fsr,top
	inc	fsr
	inc	fsr
	mov	w,ind
	_bank	var
	mov	temp3,w

	mov	fsr,top
	inc	fsr
	inc	fsr
	inc	fsr
	mov	w,ind
	_bank	var
	mov	temp4,w



	mov	w,temp1
	_bank	primary
	mov	Xi,w
	_bank	var
	mov	w,temp2
	_bank	primary
	mov	Xi+1,w
	_bank	var
	mov	w,temp3
	_bank	primary
	mov	Yi,w
	_bank	var
	mov	w,temp4
	_bank	primary
	mov	Yi+1,w





; Real & Imag Data is fetched
; Compute Butterfly 

	SUB16ACC	Xl,Xi,Xt	; Xt = Xi - Xl
	ADD16		Xl,Xi		; Xi = Xi + Xl
	SUB16ACC	Yl,Yi,Yt	; Yt = Yi - Yl
	ADD16		Yl,Yi		; Yi = Yi + Yl

IF SCALE_BUTTERFLY
		RRC16	Xi
		RRC16	Yi
		RRC16	Xt
		RRC16	Yt
ENDIF
	
	_bank	arith
	mov	mr16,Sin
	mov	mr16+1,Sin1		; multiplier=Cos value

	_bank 	primary
	mov	w,Xt
	_bank	arith
	mov	md16,w

	_bank	primary
	mov	w,Xt1
	_bank	arith
	mov	md16+1,w


	Call	@DblMult		; SIN*Xt

	MOV32	DPX,ACC

	mov	md16,Cos
	mov	md16+1,Cos1		; put COS in multiplicand since we want to preserve it

	_bank	primary
	mov	w,Yt
	_bank	arith
	mov	mr16,w

	_bank	primary
	mov	w,Yt1
	_bank	arith
	mov	mr16+1,w

	Call	@DblMult		; COS*Yt, Scale if necessary

	SUB32	ACC,DPX			
	
	clc
	mov	w,<<DPX+2		; scale decimal point
	_bank	primary
	mov	Yl,w
	_bank	arith
	mov	w,<<DPX+3
	_bank	primary
	mov	Yl+1,w			; Yl = COS*Yt - SIN*Xt


	mov	w,Xt
	_bank	arith
	mov	mr16,w
	_bank	primary
	mov	w,Xt+1
	_bank	arith
	mov	mr16+1,w

	mov	md16,Cos
	mov	md16+1,Cos1		; put COS in multiplicand since we want to preserve it

	Call	@DblMult		; COS*Xt
	MOV32	DPX,ACC


	mov	mr16,Sin
	mov	mr16+1,Sin1		; multiplier=Sin value

	_bank 	primary
	mov	w,Yt
	_bank	arith
	mov	md16,w

	_bank	primary
	mov	w,Yt1
	_bank	arith
	mov	md16+1,w

	Call	@DblMult		; Sin*Yt, Scale if necessary

	ADD32	ACC,DPX			; DPX = COS*Xt + SIN*Yt

	clc
	mov	w,<<DPX+2		;scale decimal point
	_bank	primary
	mov	Xl,w
	_bank	arith
	mov	w,<<DPX+3
	_bank	primary
	mov	Xl+1,w			; Xl = COS*Xt + SIN*Yt

	mov	w,Xi			; prepare to store
	_bank	var
	mov	temp1,w
	_bank	primary
	mov	w,Xi+1
	_bank	var
	mov	temp2,w
	_bank	primary
	mov	w,Yi
	_bank	var
	mov	temp3,w
	_bank	primary
	mov	w,Yi+1
	_bank	var
	mov	temp4,w

					; Store results of butterfly
					; store top result

	mov	w_temp,temp1
	mov	fsr,top
	mov	ind,w_temp

	_bank	var
	mov	w_temp,temp2
	mov	fsr,top
	inc	fsr
	mov	ind,w_temp

	_bank	var
	mov	w_temp,temp3
	mov	fsr,top
	inc	fsr
	inc	fsr
	mov	ind,w_temp

	_bank	var
	mov	w_temp,temp4
	mov	fsr,top
	inc	fsr
	inc	fsr
	inc	fsr
	mov	ind,w_temp

	
	_bank	primary			; prepare to store data (L)
	mov	w,Xl
	_bank	var
	mov	temp1,w
	_bank	primary
	mov	w,Xl+1
	_bank	var
	mov	temp2,w
	_bank	primary
	mov	w,Yl
	_bank	var
	mov	temp3,w
	_bank	primary
	mov	w,Yl+1
	_bank	var
	mov	temp4,w
	

	mov	w_temp,temp1		; store bottom result
	mov	fsr,bottom
	mov	ind,w_temp

	_bank	var
	mov	w_temp,temp2
	mov	fsr,bottom
	inc	fsr
	mov	ind,w_temp

	_bank	var
	mov	w_temp,temp3
	mov	fsr,bottom
	inc	fsr
	inc	fsr
	mov	ind,w_temp

	_bank	var
	mov	w_temp,temp4
	mov	fsr,bottom
	inc	fsr
	inc	fsr
	inc	fsr
	mov	ind,w_temp		; X(L) & Y(L) stored	

	_bank	var

; Increment for next Iloop
;
	clc
	mov	w,<<count1		; rotate left through carry into w
	snc
	inc	VarIloop		; propagate carry
	add	VarIloop,w		; I=I+count1*2

	mov	temp,#FftLen*2
	dec	temp
	sub	temp,VarIloop		; temp = 2*FftLen - I-1
	
	sb	temp.7	
	jmp	@Iloop			; while I < 2*FftLen

					; I Loop end
					; increment for next J Loop

	inc	VarJloop		; J = J + 1

	mov	temp,count2
	dec	temp
	sub	temp,VarJloop		; temp = count2 - J-1
	
	sb	temp.7		
	jmp	@Jloop			; while J < count2

					; J Loop end
					; increment for next K Loop

	clc
	rl	TF_Offset		; TF_Offset = 2 * TF_Offset
	decsz	VarKloop
	jmp	@Kloop			; while K < Power

	retp				; FFT complete

					; K Loop End
					; FFT Computation Over with data scrambled


org	$500
	;*********************************************************************************
	; Function: Unscramble
	;	
	;	Unscramble Data Order Sequence Of Radix-2 FFT
	;	Length (must be a power of 2) 
        ;
	; Inputs: ram banks: 	9x,Bx,Dx,Fx
	;	
	; Outputs: 		9x,Bx,Dx,Fx
	;	
	; Registers affected: 	VarIloop, VarL,
	;			temp, temp1, temp2, temp3, temp4
	;
	; Functions Called: 	none
	;
	;
	;*********************************************************************************

Unscramble_

	_bank	var
	clr	VarIloop		; i=0..15
reverse
	clr	VarL
	snb	VarIloop.3
	setb	VarL.0
	snb	VarIloop.2
	setb	VarL.1
	snb	VarIloop.1
	setb	VarL.2
	snb	VarIloop.0
	setb	VarL.3
	; L contains the bit reversed version of I
	
	cjb	VarIloop,VarL,swapdata	; I-L
					; swap only if I<L
					; carry=1 if no borrow, meaning I is >=L
rev_cont
	
	inc	VarIloop
	cjb	VarIloop,#12,reverse	; if I <=11, continue, else done
	retp

swapdata
	clc
	mov	temp,VarIloop
	rl	temp
	rl	temp
	mov	w,temp
	and	w,#%11110000		; mask off lsb
	; no overflow can happen, else we will be out of range of memory
	snc
	or	w,#%00000001		; propagate carry
	add	w,temp			; adjust for gap in register banks
	mov	top,w
	snc
	inc	top			; propagate carry
	add	top,#RamAddr

	clc
	mov	temp,VarL
	rl	temp
	rl	temp
	mov	w,temp
	and	w,#%11110000		; mask off lsb
	; no overflow can happen, else we will be out of range of memory
	snc
	or	w,#%00000001		; propagate carry
	add	w,temp			; adjust for gap in register banks
	mov	bottom,w 
	snc
	inc	bottom			; propagate carry
	add	bottom,#RamAddr


					; swap data
	mov	fsr,top
	mov	w,ind
	_bank	var
	mov	temp1,w

	mov	fsr,top
	inc	fsr
	mov	w,ind
	_bank	var
	mov	temp2,w

	mov	fsr,top
	inc	fsr
	inc	fsr
	mov	w,ind
	_bank	var
	mov	temp3,w

	mov	fsr,top
	inc	fsr
	inc	fsr
	inc	fsr
	mov	w,ind
	_bank	var
	mov	temp4,w



	mov	fsr,bottom
	mov	Cos,ind
	inc	fsr
	mov	Cos1,ind
	inc	fsr
	mov	Sin,ind
	inc	fsr
	mov	Sin1,ind
	
	_bank	var
	mov	fsr,top
	mov	ind,Cos
	inc	fsr
	mov	ind,Cos1
	inc	fsr
	mov	ind,Sin
	inc	fsr
	mov	ind,Sin1

	_bank	var
	mov	w_temp,temp1
	mov	fsr,bottom
	mov	ind,w_temp
	_bank	var
	mov	w_temp,temp2
	mov	fsr,bottom
	inc	fsr
	mov	ind,w_temp
	_bank	var
	mov	w_temp,temp3
	mov	fsr,bottom
	inc	fsr
	inc	fsr
	mov	ind,w_temp
	_bank	var
	mov	w_temp,temp4
	mov	fsr,bottom
	inc	fsr
	inc	fsr
	inc	fsr
	mov	ind,w_temp

	_bank	var
	jmp	rev_cont



	;*********************************************************************************
	; Function: DblMult
	; 
	; Inputs: multiplicand (md16+1, md16), multiplier (mr16+1, mr16)
	;	
	; Outputs: 32 bit product (upper_prdt+1, upper_prdt, mr16+1, mr16)
	;	
	; Registers affected: upper_prdt+1, upper_prdt, mr16+1, mr16, count, sign
	;
	; Functions Called: none
	; 
	;*********************************************************************************


DblMult_
	
	_bank	arith

	; process the sign first

	mov	w,md16+1		; test the sign
	xor	w,mr16+1		; same sign?		
	mov	sign,w			; save, so that we can bit test it at the end
	sb	md16_hi.7		; msb=1?
	jmp	check_mr		; no, check multiplier
					
	; msb of multiplicand=1, negate
	not	md16			; 1's complement
	inc	md16			; 2's complement=1's complement+1
	snz				; special case if =0
	dec	md16+1			; dec then complement = increment
	not	md16+1			; this will take care of the carry from lsb to msb
					

check_mr
	sb	mr16_hi.7		; msb=1?
	jmp	normal_mult		; sign check done
		
	; msb of multiplier=1, negate
	not	mr16			; 1's complement
	inc	mr16			; 2's complement=1's complement+1
	snz				; special case if =0
	dec	mr16+1			; dec then complement = increment
	not	mr16+1			; this will take care of the carry from lsb to msb
					

normal_mult	
	mov	count,#17		; set number of times to shift
	clr	upper_prdt		; clear upper product
	clr	upper_prdt+1		; higher byte of the 16 bit upeper product
	clc				; clear carry
					; the following are executed [count] times
m1616loop
	rr	upper_prdt+1		; rotate right the whole product
	rr	upper_prdt		; lower byte of the 16 bit upper product
	rr	mr16+1			; high byte of the multiplier
	rr	mr16			; check lsb
	sc				; skip addition if no carry
	jmp	@no_add			; no addition since lsb=0
	add	upper_prdt,md16		; add multiplicand to upper product 
	snc                             ; take account of carry
	inc	upper_prdt+1		
	add	upper_prdt+1,md16+1	; add the next 16 bit of multiplicand

no_add
	decsz	count			; loop [count] times to get proper product
	jmp	m1616loop		; jmp to rotate the next half of product


	sb	sign.7			; check sign
	retp				; positive, do nothing, just return

					; lower product
	not	mr16			; form 1's complement
	not	mr16+1			
	not	upper_prdt		
	not	upper_prdt+1		

	mov	w,#1			; add 1 to form 2's complement and propagate carry
	add	mr16,w				
	snc                             
	add	mr16+1,w			
	snc                             
	add	upper_prdt,w		
	snc                             
	add	upper_prdt+1,w		
	retp				

;
;*****************************************************************
;		Sine-Cosine Tables
;*****************************************************************
;
	org	$600
;
;*****************************************************************
;	FFT Input/Output Data Stored  with 2 bytes of
; Real Data followed by 2 bytes of Imaginary Data.
;*****************************************************************
;
;		16 Point FFT Sine Table
; coefficient table (size of table is 3n/4).

					;	radians		0.392699082		
					;		degrees	sin	16 bit form	pt.
dw	0	-((0/256)*256)		;	0	0	0	0	0
dw	0	/256			;	0	0	0	0	0
dw	12539	-((12539/256)*256)	;	0.392699082	22.5	0.382683432	12539	1
dw	12539	/256			;	0.392699082	22.5	0.382683432	12539	1
dw	23170	-((23170/256)*256)	;	0.785398163	45	0.707106781	23170	2
dw	23170	/256			;	0.785398163	45	0.707106781	23170	2
dw	30273	-((30273/256)*256)	;	1.178097245	67.5	0.923879533	30273	3
dw	30273	/256			;	1.178097245	67.5	0.923879533	30273	3

CosTable

dw	32767	-((32767/256)*256)	;	1.570796327	90	1	32767	4
dw	32767	/256			;	1.570796327	90	1	32767	4
dw	30273	-((30273/256)*256)	;	1.963495408	112.5	0.923879533	30273	5
dw	30273	/256			;	1.963495408	112.5	0.923879533	30273	5
dw	23170	-((23170/256)*256)	;	2.35619449	135	0.707106781	23170	6
dw	23170	/256			;	2.35619449	135	0.707106781	23170	6
dw	12539	-((12539/256)*256)	;	2.748893572	157.5	0.382683432	12539	7
dw	12539	/256			;	2.748893572	157.5	0.382683432	12539	7
dw	0	-((0/256)*256)		;	3.141592654	180	1.22515E-16	0	8
dw	0	/256			;	3.141592654	180	1.22515E-16	0	8
dw	-12539	-((-12539/256)*256)	;	3.534291735	202.5	-0.382683432	-12539	9
dw	-12539	/256	-1		;	3.534291735	202.5	-0.382683432	-12539	9
dw	-23170	-((-23170/256)*256)	;	3.926990817	225	-0.707106781	-23170	10
dw	-23170	/256	-1		;	3.926990817	225	-0.707106781	-23170	10
dw	-30273	-((-30273/256)*256)	;	4.319689899	247.5	-0.923879533	-30273	11
dw	-30273	/256	-1		;	4.319689899	247.5	-0.923879533	-30273	11
dw	-32767	-((-32767/256)*256)	;	4.71238898	270	-1	-32767	12
dw	-32767	/256	-1		;	4.71238898	270	-1	-32767	12
									
testdata
dw	0
dw	0
dw	$40
dw	$2d
dw	$ff
dw	$3f
dw	$40
dw	$2d
dw	0
dw	0
dw	$c0
dw	$d2
dw	1
dw	$c0
dw	$c0
dw	$d2
dw	0
dw	0
dw	$40
dw	$2d
dw	$ff
dw	$3f
dw	$40
dw	$2d
dw	0
dw	0
dw	$c0
dw	$d2
dw	1
dw	$c0
dw	$c0
dw	$d2
	

;*****************************************************************************************
END		;End of program code
;*****************************************************************************************

