COMMENT *

This file is used to generate DSP code for the second generation 
	timing boards to operate one 1024 x 1024 pixel  
	a HAWAII-1RG array with one coadder board. 

   *

   PAGE    132     ; Printronix page width - 132 columns

; Define a section name so it doesn't conflict with other application programs
	SECTION TIM_HAWAII_1RG

; Include a header file that defines global parameters
        INCLUDE "../DSPlib/timhdr.asm"

APL_NUM	EQU	0		; Application number from 0 to 3
CC	EQU	TIMREV4+NGST+COADDER

SCR	EQU	$FFF0	; SCI Control Register
SSR	EQU	$FFF1	; SCI Status Register
SCCR	EQU	$FFF2	; SCI Clock Control Register
WRSCI	EQU	$FFF4	; Write least significant byte to SCI port
WRSCI0	EQU	$FFF4	; Write least significant byte to SCI port
WRSCI1	EQU	$FFF5	; Write middle significant byte to SCI port
WRSCI2	EQU	$FFF6	; Write most significant byte to SCI port
SRAM_AD	EQU	$B0B	; Address in timing board SRAM where coadder code is
P_COADD	EQU	$E001	; Start of coadder code in EEPROM
RST_CA	EQU	3	; Timing board resets coadder board (Rev 4B, which IDTL has)
			;    NOTE error in docs! should be 4B=3 3B=5

; Software status bit definitions for the program only
RST_MODE 	EQU	16	; 0 for global reset, 1 for row-by-row reset
CDS_MODE 	EQU	17	; 0 for single sampling, 1 for CDS
PTR_MODE 	EQU	18	; 0 for Coadder arithmetic, 1 for pass through mode
UTR_MODE 	EQU	19	; 0 for normal, 1 up-the-ramp readout
BO_MODE  	EQU	20	; 0 for normal, 1 Bright Object
WIN_MODE 	EQU	21	; 0 for normal, 1 Window Mode
RST_MODE1	EQU	22	; 1 for pixel-by-pixel reset, 0 for using the RST_MODE value (see above)



;******************************************************************************
;****  CLOCKING CODE IN SRAM PROGRAM SPACE  ****
;******************************************************************************
;  Specify execution and load addresses
	IF	@SCP("DOWNLOAD","HOST")
	ORG	P:APL_ADR,P:APL_ADR		; Download address
	ELSE
	ORG     P:APL_ADR,P:APL_NUM*N_W_APL	; EEPROM address
	ENDIF


;**************************************************
; BO mode settling time delay loop. Leave this here at the top of P mem,
; otherwise the calibration will be off

        ; settling time delay here (~10 us) (#200 = 8.5 us on 8/21/02)
        ;
SETDLY  DO      #200,SETTLE_DLY               ; Each step of this loop is 50 ns
        NOP
SETTLE_DLY
	RTS	


;**************************************************
; BO mode exposure time delay loop. Leave this here at the top of P mem,
; otherwise the calibration will be off

        ; delay loop goes here for exptime in BO mode
        ; this is the number to delay by -  X:<EXP_TIM
        ; in BO mode, this is assumed to be microseconds, not
        ; milliseconds as in NORMAL mode.
        ;
        ; the number in the do loop should be:
        ;
	; n = ((time - 3) * 25) + 18
	; where time is an integer number of microseconds between 3 and 2600

EXPDLY  DO      Y0,EXPOSURE_DLY		; this loop takes 40ns for each Y0
        NOP
EXPOSURE_DLY
	RTS

;****************************************************************
; use this block for ROW skipping (this is burst-mode subarray)

ROWSKIP_BURST
        MOVE    Y:<STARTROW,A
        MOVE    X:ONE,X0
        CMP     X0,A                            ;   if # of rows to skip is zero, then don't
        JEQ     <NOROWSKIP
        DEC     A
        DO      A,ROWSKIP
        MOVE    #CLOCK_ROW_FAST,R0
        JSR     <CLOCK
        NOP
ROWSKIP
        NOP
NOROWSKIP
	RTS

;****************************************************************
; use this block for COL skipping (this is burst-mode subarray)
; this is done once here for the special first row, then 
; again inside the column loop 

COLSKIP_BURST
        MOVE    Y:<STARTCOL,A
        MOVE    X:ONE,X0
        CMP     X0,A                            ;   if # of cols to skip is zero, then don't
        JEQ     <NOCOLSKIP
        DEC     A
        DO      A,COLSKIP
        MOVE    #CLOCK_ONLY_FAST,R0
        JSR     <CLOCK
        NOP
COLSKIP
        NOP
NOCOLSKIP
	RTS

;*********************************************************************************
; for 1RG, need 2 HCLK pulses before the first real pixel in each row
; This affects the relative start col of each row the same in all reads
; It looks like 2 HCLKs is correct.

SKIP_2_HCLKS
	DO	#2,SKIP_2
	MOVE	#CLOCK_ONLY,R0
	JSR	<CLOCK
	NOP			
SKIP_2
	RTS

;************************************************************************
;  delay needed at start of readout - not sure why
READ_START_DELAY
        DO      #2000,DLY_ON
        JSR     <PAL_DLY
        NOP
DLY_ON
	RTS

; ******************************************************************************************
; Normal mode read of the array
RD_ARRAY			
	; first, calculate some numbers					
	MOVE	Y:<NCOLS,A1		; Get total number of cols, 
	JSET    #WIN_MODE,X:STATUS,DOWIN  ; if WIN mode selected, don't divide cols by 2
	ASR	A			; Divide by two (2 quads wide)
DOWIN	MOVE	A1,Y:<TEMP		; store temporarily

        ;   This delay needs to be here - not sure why
	JSR	<READ_START_DELAY

        BSET    #WW,X:PBD               ; Set WW to 1 for 16-bit image data

	MOVE    #VSOURCE_ON,R0            ; Turn VSOURCE ON
        JSR     <CLOCK                 

        MOVE    #FRAME_INIT,R0         ; Initialize the frame for readout
        JSR     <CLOCK

	; if burst-mode subarray, skip some rows
	JSR	<ROWSKIP_BURST

; The first two pix reads have no XFER or SXMIT because the A/D data are not valid
; (pipeline delay in the ADS937 A/D converter)

L_READ_FIRST_TWO			; clock (no read) first 2 pix of first row

        MOVE    #READ_ON,R0            ; Turn Read ON
        JSR     <CLOCK                 

	MOVE    #CLOCK_ROW,R0 		; clock to first row
        JSR     <CLOCK

;        JSET    #RST_MODE,X:STATUS,RR_RD1
;	MOVE    #CLOCK_ROW,R0 		; if not row-by-row reset
;        JSR     <CLOCK
;	JMP     <RR_RD2
;RR_RD1  MOVE    #CLOCK_ROW_RESET,R0     ; if row-by-row reset
;	JSR     <CLOCK
;RR_RD2  NOP

	; for 1RG, need 2 HCLK pulses before the first real pixel in each row
	JSR	<SKIP_2_HCLKS

	; if burst-mode subarray, skip some cols
	JSR	<COLSKIP_BURST

	; 2 pix, so do this twice
	DO	#2,FIRST_TWO_PIX	;Loop two times
	MOVE	Y:<CLK_COL_AND_READ_NO_XFER,R0	;load waveform to fill A to D pipeline 
	JSR	<CLOCK		; clock it
	NOP
FIRST_TWO_PIX
	;; Read the rest of row One
	MOVE	Y:<TEMP,A1	;total number of cols/2
	MOVE	X:<TWO,X1
	SUB	X1,A		; subtract two
	DO	A1,L_READ_THE_REST	; clock-and-read the remaining (510) pix in the first row (one at a time)
	MOVE	Y:<CLK_COL_AND_READ,R0
	JSR	<CLOCK
	NOP
L_READ_THE_REST
	;; Workaround to clear out A/D buffer at the end of row one. Remove when we fix this problem.
	; 2 pix, do this twice
	DO	#2,LAST_TWO_PIXB	; load two
	MOVE	Y:<LAST_TWO_PIXELS,R0 ; put in R0
	JSR	<CLOCK		; clock it
	NOP
LAST_TWO_PIXB

 
;        MOVE    #READ_OFF,R0            ; Turn Read OFF
;        JSR     <CLOCK		

	;; Now read the rest of the array.
	CLR	A
	CLR	B
	MOVE	B1,Y:<TEST1	; zero out test1 used for debugging
	MOVE	B1,Y:<TEST2	; zero out test2 used for debugging
	MOVE	Y:<NROWS,A1	
	DEC	A			; NROWS - 1 since we alread read out row one.
	DO	A1,FRAME		; clock-and-read the remaining (1023) rows per half

	;; TEST1 is a row counter. I just have it in here for debugging. It's value can
	;; be retrieved with a RDM of 40000F command.
	MOVE	Y:<TEST1,A1
	MOVE    X:<ONE,X1	
	ADD     X1,A		; Increment row counter
	MOVE	A1,Y:<TEST1	; save row counter

	;; Set HCLK low at the end of each row before the next row is clocked
	;; This is what is shown in the Rockwell timing diagram.
	MOVE	#HCLOCK_LOW,R0
	JSR	<CLOCK
	
	MOVE    #CLOCK_ROW,R0 		; 
        JSR     <CLOCK

        MOVE    #READ_ON,R0            ; Turn Read ON
        JSR     <CLOCK                 
 
	; for 1RG, need 2 HCLK pulses before the first real pixel in each row
	JSR	<SKIP_2_HCLKS

	; if burst-mode subarray, skip some cols
	JSR	<COLSKIP_BURST

	;; Workaround to fill A/D buffer at the beginning of the row. Once we stop
	;; emptying the buffer at the end of the row this should be removed.
	DO	#2,FIRST_TWO_PIX_ROW	;Loop two times
	MOVE	Y:<CLK_COL_AND_READ_NO_XFER,R0	;load waveform to fill A to D pipeline 
	JSR	<CLOCK		; clock it
	NOP

FIRST_TWO_PIX_ROW
	;; Read 510 (should be 512 when we fix FIFO problem) pixels in the row
	MOVE	Y:<TEMP,A1		; total cols/2
	MOVE	X:<TWO,X1
	SUB	X1,A		; subtract two
	DO	A1,L_READ_LAST_TWO_PIXELS ; clock-and-read (512) pix per row, 1 at a time
	MOVE	Y:<CLK_COL_AND_READ,R0
	JSR	<CLOCK
	NOP
L_READ_LAST_TWO_PIXELS
	;; This is a workaround to not read the last two pixels of each read. This "fixes"
	;; the two column shift between reads problem.

	;MOVE	#1023,X1
        MOVE    Y:<NROWS,A1
        DEC     A                
        MOVE    A1,X1            
	MOVE    Y:<TEST1,A

	CMP	X1,A
	JGE	LAST_TWO_PIXC
	; 2 pix, do this twice. This empties the A/D FIFO at the end of the row. Once we
	;; figure out what is going on this should be removed.
	DO	#2,LAST_TWO_PIXC	; load two
	MOVE	Y:<LAST_TWO_PIXELS,R0 ; put in R0
	JSR	<CLOCK		; clock it
	NOP
LAST_TWO_PIXC


        MOVE    #READ_OFF,R0            ; Turn Read OFF
        JSR     <CLOCK		; clock it

	NOP
FRAME
	MOVE    #CLOCK_ROW,R0 		; extra one at end of frame
        JSR     <CLOCK		; clock it see page 33 of 1RG manual
 
        MOVE    #VSOURCE_OFF,R0         ; Turn VSOURCE OFF
        JSR     <CLOCK                 

	; 2 pix, do this twice
;	DO	#2,LAST_TWO_PIX	; load two
;	MOVE	Y:<LAST_TWO_PIXELS,R0 ; put in R0
;	JSR	<CLOCK		; clock it
;	NOP			; nop
LAST_TWO_PIX

	; this seems to work better then the above block for the 1R to get the last two pix.
	;; This is commented out for now to get the columns to line up because we seem to be getting
	;; two extra pixels/read.
        MOVE    Y:<CLK_COL_AND_READ,R0	; comment
        JSR     <CLOCK			; comment
        MOVE    Y:<CLK_COL_AND_READ,R0 ; comment
        JSR     <CLOCK		; comment

        JSR     <PAL_DLY                ; Wait for serial data transmission
        BCLR    #WW,X:PBD               ; Clear WW to 0 for non-image data
        RTS

;******************************************************************************
; BO mode readout of array
RD_BO_ARRAY
	JSR	<PCI_READ_IMAGE	; Tell the PCI card the number of pixels to expect
	; first, calculate some numbers					
	MOVE	Y:<NCOLS,A1		; Get total number of cols, 
	JSET    #WIN_MODE,X:STATUS,DOWIN1  ; if WIN mode selected, don't divide cols by 2
	ASR	A			; Divide by two (2 quads wide)
DOWIN1	MOVE	A1,Y:<TEMP		; store temporarily



; ####################################################################
; first thing to do in BO mode is calculate the number of iterations for
; each of the delay loops

; n = ((time - 3) * 25) + 18
; where time is an integer number of microseconds between 3 and 2600

        CLR     A
        MOVE    X:<EXP_TIM,A1
        MOVE    X:<THREE,X1
        SUB     X1,A
        MOVE    A1,Y0                           ; store result in Y0 for MICROSEC_LOOP
        CLR     A

ADD_TEN MOVE    X:<ONE,X0                       ; exp delay latency is 2.28us
        REP     #18				; add 18 loops to get to the min exptime of 3.0 us (18 * 40ns)
        ADD     X0,A                            ; A1 now contains 10

        CLR     B
        MOVE    Y0,B0                           ; num microsecs above 3 into B0
        MOVE    X:<ZERO,X0
        CMP     X0,B                            
        JEQ     MICROSEC_LOOP                   ; if zero, we're done - delay number is 11

        CLR     B
        MOVE    #$19,B1                         ; for each microsec over 3, add this many loops
        MOVE    B1,X1
        DO      Y0,MICROSEC_LOOP                ; 25 loops ($19) = 1 us  (40e-9 * 25)
        ADD     X1,A
        NOP
MICROSEC_LOOP

        MOVE    A1,Y0                    ; this is n for the exposure delay loop
; ####################################################################


        ;   This delay needs to be here - not sure why
	JSR	<READ_START_DELAY

        BSET    #WW,X:PBD               ; Set WW to 1 for 16-bit image data

	MOVE    #VSOURCE_ON,R0            ; Turn VSOURCE ON
        JSR     <CLOCK                 

        MOVE    #FRAME_INIT,R0         ; Initialize the frame for readout
        JSR     <CLOCK

; The first two pix reads have no XFER or SXMIT because the A/D data are not valid
; (pipeline delay in the ADS937 A/D converter)

        MOVE    #READ_ON,R0            ; Turn Read ON
        JSR     <CLOCK                 

	MOVE    #CLOCK_ROW,R0	; clock to the first row
        JSR     <CLOCK

	; if burst-mode subarray, skip some rows
	JSR	<ROWSKIP_BURST

	; for 1RG, need 2 HCLK pulses before the first real pixel in each row
	JSR	<SKIP_2_HCLKS

	; if burst-mode subarray, skip some cols
	JSR	<COLSKIP_BURST

; *******************************************************************************************************
; This is BO mode. Since BO reads twice per pix, do this once with NO_XFER, then once with XFER to get 2 REAL pix

; pix 1  #########################################################
        MOVE    #CLOCK_ONLY,R0     ; clock to pixel
        JSR     <CLOCK
        NOP
        MOVE    #PULSE_RESET,R0         ; strobe the reset on this row
        JSR     <CLOCK
        NOP

	; settling time delay
	JSR	SETDLY

        JCLR    #CDS_MODE,X:STATUS,BO_RD_END_1
        CLR     B
        DO      Y:<NFS,BO_RD_END_1                           ; Fowler sampling

        ; first BO read(s)
        ; first 2 reads get no XFER (pipeline delay)
        MOVE    X:<TWO,Y1
        CMP     Y1,B
        JGE     W_XFER                  ; if two reads already done, go to W_XFER
        MOVE    #A2D_ONLY_NO_XFER,R0
        JSR     <CLOCK
        MOVE    X:<ONE,X0
        ADD     X0,B
        JMP     <RDONE
        ; Any reads (fowlers) beyond  2 here get XFERed
W_XFER  MOVE    #A2D_ONLY,R0
        JSR     <CLOCK
RDONE
        NOP
BO_RD_END_1

; Implement up-the-ramp readout
        DO      Y:<IUTR,BO_L_UP_THE_RAMP_1

	; exposure time delay - X:<EXP_TIM
	JSR	EXPDLY

; Sample the signal level NFS times
        DO      Y:<NFS,BO_RD_EXP_1                           ; Fowler sampling

        ; second BO read
        ; first 2 reads get no XFER (pipeline delay), so continue to check
        MOVE    X:<TWO,Y1
        CMP     Y1,B
        JGE     W_XFER1         ; if two reads already done, go to W_XFER
        MOVE    #A2D_ONLY_NO_XFER,R0
        JSR     <CLOCK
        MOVE    X:<ONE,X0
        ADD     X0,B
        JMP     <RDONE1
        ; Any reads (fowlers) beyond  2 here get XFERed
W_XFER1 MOVE    #A2D_ONLY,R0
        JSR     <CLOCK
RDONE1


        NOP
BO_RD_EXP_1
        NOP
BO_L_UP_THE_RAMP_1
        NOP


; pix 2  #########################################################
        MOVE    #CLOCK_ONLY,R0     ; clock to pixel
        JSR     <CLOCK
        NOP
        MOVE    #PULSE_RESET,R0         ; strobe the reset on this row
        JSR     <CLOCK
        NOP

	; settling time delay
	JSR	SETDLY

        JCLR    #CDS_MODE,X:STATUS,BO_RD_END_2
        DO      Y:<NFS,BO_RD_END_2                           ; Fowler sampling

        ; first BO read(s)
        MOVE    #A2D_ONLY,R0
        JSR     <CLOCK

        NOP
BO_RD_END_2

; Implement up-the-ramp readout
        DO      Y:<IUTR,BO_L_UP_THE_RAMP_2

	; exposure time delay - X:<EXP_TIM
	JSR	EXPDLY

; Sample the signal level NFS times
        DO      Y:<NFS,BO_RD_EXP_2                           ; Fowler sampling

        ; second BO read
        MOVE    #A2D_ONLY,R0
        JSR     <CLOCK

        NOP
BO_RD_EXP_2
        NOP
BO_L_UP_THE_RAMP_2
        NOP

REMAIN	MOVE	Y:<TEMP,A1	;total number of cols/2
	MOVE	X:<TWO,X1
	SUB	X1,A		; subtract two
	DO	A1,L_READ_THE_REST_BO	; clock-and-read the remaining (510) pix in the first row (one at a time)

	MOVE    #CLOCK_ONLY,R0     ; clock to pixel
        JSR     <CLOCK

        MOVE    #PULSE_RESET,R0         ; strobe the reset on this row
        JSR     <CLOCK


	; settling time delay
	JSR	SETDLY

        JCLR    #CDS_MODE,X:STATUS,BO_RD_END_3
        DO      Y:<NFS,BO_RD_END_3                           ; Fowler sampling

        ; first BO read(s)
        MOVE    #A2D_ONLY,R0
        JSR     <CLOCK

        NOP
BO_RD_END_3

; Implement up-the-ramp readout
        DO      Y:<IUTR,BO_L_UP_THE_RAMP_3

	; exposure time delay - X:<EXP_TIM
	JSR	EXPDLY

; Sample the signal level NFS times
        DO      Y:<NFS,BO_RD_EXP_3                           ; Fowler sampling

        ; second BO read
        MOVE    #A2D_ONLY,R0
        JSR     <CLOCK
        NOP
BO_RD_EXP_3
        NOP

BO_L_UP_THE_RAMP_3
        NOP

L_READ_THE_REST_BO

;        MOVE    #READ_OFF,R0            ; Turn Read OFF
;        JSR     <CLOCK		
	;; Now read the rest of the array.
	CLR	A
	CLR	B
	MOVE	B1,Y:<TEST1
	MOVE	B1,Y:<TEST2
	MOVE	Y:<NROWS,A1	
	DEC	A			; NROWS - 1 Since we alread read row one
	DO	A1,FRAME_BO		; clock-and-read the remaining (1023) rows per half

	MOVE	Y:<TEST1,A1
	MOVE    X:<ONE,X1	
	ADD     X1,A		; Increment row counter
	MOVE	A1,Y:<TEST1	; save row counter

	;; Set HCLK low at the end of each row before the next row is clocked
	;; This is what is shown in the Rockwell timing diagram.
	MOVE	#HCLOCK_LOW,R0
	JSR	<CLOCK
	
	MOVE    #CLOCK_ROW,R0 		; 
        JSR     <CLOCK

        MOVE    #READ_ON,R0            ; Turn Read ON
        JSR     <CLOCK                 
 
	; for 1RG, need 2 HCLK pulses before the first real pixel in each row
	JSR	<SKIP_2_HCLKS

	; if burst-mode subarray, skip some cols
	JSR	<COLSKIP_BURST

	MOVE	Y:<TEMP,A1		; total cols/2
	DO	A1,L_READ_LAST_TWO_PIXELS_BO ; clock-and-read (512) pix per row, 1 at a time

	MOVE    #CLOCK_ONLY,R0     ; clock to pixel
        JSR     <CLOCK
        NOP

        MOVE    #PULSE_RESET,R0         ; strobe the reset on this row
        JSR     <CLOCK
        NOP
	;; Section for row counter of BO mode. Only for debugging.
	MOVE	Y:<TEST2,A1
	MOVE    X:<ONE,X1		
	ADD     X1,A		; Increment pixel counter
	MOVE	A1,Y:<TEST2	; save row counter


	; settling time delay
	JSR	SETDLY

        JCLR    #CDS_MODE,X:STATUS,BO_RD_END_4
        DO      Y:<NFS,BO_RD_END_4                           ; Fowler sampling

        ; first BO read(s)
        MOVE    #A2D_ONLY,R0
        JSR     <CLOCK

        NOP
BO_RD_END_4



; Implement up-the-ramp readout
        DO      Y:<IUTR,BO_L_UP_THE_RAMP_4

	; exposure time delay - X:<EXP_TIM
	JSR	EXPDLY

; Sample the signal level NFS times
        DO      Y:<NFS,BO_RD_EXP_4                           ; Fowler sampling

        ; second BO read
        MOVE    #A2D_ONLY,R0
        JSR     <CLOCK

        NOP
BO_RD_EXP_4
        NOP
BO_L_UP_THE_RAMP_4
        NOP

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

L_READ_LAST_TWO_PIXELS_BO
	NOP
	
        MOVE    #READ_OFF,R0            ; Turn Read OFF
        JSR     <CLOCK		; clock it

	NOP
FRAME_BO
	MOVE    #CLOCK_ROW,R0 		; extra one at end of frame
        JSR     <CLOCK		; clock it see page 33 of 1RG manual
 
        MOVE    #VSOURCE_OFF,R0         ; Turn VSOURCE OFF
        JSR     <CLOCK                 

	; 2 pix, do this twice
	DO	#2,LAST_TWO_PIX_BO	; load two
	MOVE	Y:<LAST_TWO_PIXELS,R0 ; put in R0
	JSR	<CLOCK		; clock it
	NOP			; nop
LAST_TWO_PIX_BO

;        MOVE    Y:<CLK_COL_AND_READ,R0
;        JSR     <CLOCK
;        MOVE    Y:<CLK_COL_AND_READ,R0
;        JSR     <CLOCK
;        MOVE    #CLOCK_VCLK,R0
;        JSR     <CLOCK


        JSR     <PAL_DLY                ; Wait for serial data transmission
        BCLR    #WW,X:PBD               ; Clear WW to 0 for non-image data
        RTS

;******************************************************************************
; decide which reset mode is selected and do it
RESET_ARRAY
	JSET    #RST_MODE,X:STATUS,RBR	; if RST_MODE bit set, then use row-by-row reset
	JSET    #RST_MODE1,X:STATUS,PBP	; if RST_MODE1 bit set, then use pixel-by-pixel reset
	JSR	<RESET_ARRAY_GLOBAL	; otherwise (if RST_MODE bit is 0 AND RST_MODE1 0), then use global reset
	JMP	RST_DONE
RBR	JSR	<RESET_ARRAY_ROW_BY_ROW
	JMP	RST_DONE
PBP	JSR	<RESET_ARRAY_PIXEL_BY_PIXEL
RST_DONE

	RTS 

;******************************************************************************
; Row-by-Row reset (default)
RESET_ARRAY_ROW_BY_ROW
        MOVE    #VSOURCE_OFF,R0            ; Turn VSOURCE OFF
        JSR     <CLOCK                 
	MOVE	#FRAME_INIT,R0
	JSR	<CLOCK
	DO	#1024,L_RESET_ARRAY_ROW_BY_ROW
	MOVE    #CLOCK_ROW_RESET,R0
        JSR     <CLOCK
	NOP
L_RESET_ARRAY_ROW_BY_ROW
	RTS

;******************************************************************************
; Pixel-by-Pixel reset
RESET_ARRAY_PIXEL_BY_PIXEL

	; Must be in enhanced hclock clockimg mode for this to work.
	; Set bit HMODE and HMODWM in NormalModeReg and WindowModeReg. 

	BSET    #1,Y:<SERJUMP			; serial reset (1RG bug)
	MOVE	X:<ZERO,Y0 
	MOVE    X:<ZERO,Y1
	JSR	<SERIAL_JUMP_IN

	BSET    #1,Y:<SERJUMP			; HMODE to 1
	MOVE	#$5,A1
	MOVE	A1,Y0
	MOVE	#$2,A1
	MOVE	A1,Y1
	JSR	<SERIAL_JUMP_IN

        MOVE    #VSOURCE_OFF,R0            	; Turn VSOURCE OFF
        JSR     <CLOCK                 
	MOVE	#FRAME_INIT,R0
	JSR	<CLOCK
	MOVE	#RESET_ON,R0		   	; set RESETEN HI for the whole cycle
	JSR     <CLOCK
	DO	#1024,L_ROWS_PIXEL_BY_PIXEL	; clock through rows
	MOVE    #PULSE_VCLK,R0
        JSR     <CLOCK
	MOVE    #LSYNC_LOW,R0
        JSR     <CLOCK
	DO	#514,L_COLS_PIXEL_BY_PIXEL	; clock through pixels
	MOVE	#CLOCK_ONLY,R0
	JSR     <CLOCK
	NOP
L_COLS_PIXEL_BY_PIXEL
	MOVE    #LSYNC_HI,R0
        JSR     <CLOCK
	NOP
L_ROWS_PIXEL_BY_PIXEL
	MOVE	#RESET_OFF,R0		   	; set RESETEN LO
	JSR     <CLOCK

	BSET    #1,Y:<SERJUMP			; serial reset (1RG bug) to exit enhanced mode
	MOVE	X:<ZERO,Y0 
	MOVE    X:<ZERO,Y1
	JSR	<SERIAL_JUMP_IN

	RTS

;******************************************************************************
; Global reset
RESET_ARRAY_GLOBAL
	; note that the GLOBAL bit of the NormalModeReg or the GLOBWM bit of the WindowModeReg must 
	; be explicitly set in order for this to work. It is not set here because other bits in those
	; registers may also need to be set, and also because of the current H1RG mux "register reset" bug.
        MOVE    #VSOURCE_OFF,R0            ; Turn VSOURCE OFF
        JSR     <CLOCK                 
	MOVE    #PULSE_RESET,R0
        JSR     <CLOCK
	RTS

;******************************************************************************
; Continuously reset array
CONT_RST
        MOVE    #VSOURCE_OFF,R0         ; Turn VSOURCE OFF  (default for autoflush)
        JSR     <CLOCK                 

	CLR	B
        MOVE    Y:<FLUSH,X0
	CMP	X0,B
	JEQ	<NO_RST			; no resets if 0
	CLR	B
	MOVE	#'AFL',B
        MOVE    Y:<FLUSH,X0		; set for N resets
        CMP     X0,B
        JNE     <SRL
	MOVE	X:<ONE,X0		; set for autoflush (once through the loop, then check again)

SRL
	DO	X0,ERL			; reset the array N times
	JSR	<RESET_ARRAY
	NOP
ERL

	MOVE	#'AFL',B
        MOVE    Y:<FLUSH,X0
        CMP     X0,B
	JEQ	<NO_RST			; if AFL, then keep looping
	MOVE    X:<ZERO,X0
	MOVE	X0,Y:<FLUSH		; otherwise, after loop finishes N resets, set N to 0 so no more resets

NO_RST  JSR	<GET_RCV		; check for a command after each full-array reset
	JCC	<NO_COM			; If none, then stay here
	JMP	<CHK_SSI
NO_COM	NOP

	JMP	<CONT_RST


;******************************************************************************
;****************************    SUBROUTINE    ***********************
;  Core subroutine for clocking out array charge
CLOCK	MOVE	Y:(R0)+,X0      	; # of waveform entries 
	MOVE	Y:(R0)+,A       	; Start the pipeline
	DO	X0,CLK1         	; Repeat X0 times
	MOVE	A,X:(R6) Y:(R0)+,A      ; Send out the waveform
CLK1
	MOVE	A,X:(R6)        	; Flush out the pipeline
	RTS                     	; Return from subroutine
;**************************  END  OF  SUBROUTINE  ********************
;******************************************************************************



;******************************************************************************
;****  END OF CLOCKING CODE  *************
;******************************************************************************

; Check for program overflow
	IF	@CVS(N,*)>=$330
	WARN	'Application P: program is too large!'  ; Make sure program
	ENDIF                                           ;  will not overflow







;******************************************************************************
;  ****************  PROGRAM CODE IN SRAM PROGRAM SPACE    *******************
;******************************************************************************
; Put all the following code in SRAM, starting at P:$330.
	IF	@SCP("DOWNLOAD","HOST")
	ORG	P:$330,P:$330	; Download address
	ELSE
	ORG	P:$330,P:APL_NUM*N_W_APL+APL_LEN ; ROM address
	ENDIF

;******************************************************************************
START_EXPOSURE

	MOVE	X:<ONE,X0			; If up-the-ramp is selected
	MOVE	Y:<NUTR,A			;   then pass-through and    
	CMP	X0,A				;   correlated double sample
	JEQ	<ADR_SEL			;   are both required
	SUB	X0,A
	MOVE	A,Y:<IUTR			; Subtract 1 from NUTR because
	BSET	#PTR_MODE,X:STATUS		;   one frame will be done by
	BSET	#CDS_MODE,X:STATUS		;   CDS = 1

ADR_SEL	MOVE	#CLOCK_COL_AND_READ,X0		; Coadder values
	MOVE	#READ_LAST_TWO_PIXELS,X1
	MOVE	#CLOCK_COL_AND_READ_NO_XFER,Y0
	JCLR	#PTR_MODE,X:STATUS,INIT_CA
	MOVE	#CLOCK_COL_AND_READ_PT,X0	; Pass through values
	MOVE	#SXMIT_LAST_TWO_PIXELS,X1
	MOVE	#CLOCK_COL_AND_READ_PT_NO_XFER,Y0

; Initialize the coadder board - clear the FIFOs and zero the SRAM
INIT_CA	MOVE	X0,Y:<CLK_COL_AND_READ
	MOVE	X1,Y:<LAST_TWO_PIXELS
	MOVE	Y0,Y:<CLK_COL_AND_READ_NO_XFER
	MOVE	#$020F02,X0		; Header for all coadder boards
	JSR	<XMT_CA
	MOVE	#'ICA',X0		; Initialize
	JSR	<XMT_CA

; Start the coadder board accumulating A/D image data or passing it through
	MOVE	#$020F06,X0		; Header for all coadder boards
	JSR	<XMT_CA

	; select coadd or pass-through mode here
	MOVE	#'RDC',X0		; Read frames in coadd mode
	JCLR	#PTR_MODE,X:STATUS,S_COADD
	MOVE	#'RPT',X0		; Read frames in pass-through mode
S_COADD	JSR	<XMT_CA

	MOVE	Y:<NCOADDS,X0		; Send the number of coadded frames
	JSR	<XMT_CA
	MOVE	Y:<NUTR,X0		; Send the number of up-the-ramp frames
	JSR	<XMT_CA
	CLR	A
	JCLR	#CDS_MODE,X:STATUS,CDS_NOT
	BSET	#0,A
CDS_NOT	MOVE	A,X0			; Send CDS value, 0 or 1
	JSR	<XMT_CA
	MOVE	Y:<NFS,X0		; Send the number of Fowler samples
	JSR	<XMT_CA
;	MOVE	Y:<NCOLS,X0		; Send the number of Columns
;	JSR	<XMT_CA
;	MOVE	Y:<NROWS,X0		; Send the number of Rows
;	JSR	<XMT_CA

        CLR     B
        MOVE    Y:<NCOLS,X0
        MOVE    Y:<NROWS,Y0
        MPY     X0,Y0,B                 ; NCOLS * NROWS = npix per read
;        ASR     B
        MOVE    Y:<NAMPS,X0
        REP     #25
        DIV     X0,B                    ; then divide by the number of amps containing Image pix

        MOVE    B0,X0                   ; Send the number of A/D converts (NCONVERTS) per read

	JSR	<XMT_CA
	MOVE	Y:<NREADS,X0		; Send the number of reads
	JSR	<XMT_CA


; Transmit 'DON' back to host computer to indicate exposure start
	MOVE	#$020102,X0
	JSR	<XMT_FO
	MOVE	#'IIA',X0
	JSR	<XMT_FO

        JCLR    #BO_MODE,X:STATUS,COADD      ; if BO mode selected, jump over all other reads since
					     ; BO mode implements them inside of the RD_ARRAY
	JSR	<RESET_ARRAY	
		;; 			Should not need this but it seems to help timing. Without it
		;;			I get a ROUT response or readout in progress. It looks like you need to
		;;		        slow down the timing board so that the PCI board has time to get ready
		;;			for the exposure.
	JSR	<RD_BO_ARRAY	; Do a BO exposure
	JMP	<BO_END		; skip over the normal exposure logic
; Start the big coadd loop
COADD	DO	Y:<NCOADDS,L_COADD

; Reset the array once for each coadd
	JSR	<RESET_ARRAY
	;; Tell the PCI card how many pixel to expect
	JSR	<PCI_READ_IMAGE	; Tell the PCI card the number of pixels to expect

; Sample the reset level NFS times if in CDS mode
	JCLR	#CDS_MODE,X:STATUS,RD_END
	DO	Y:<NFS,RD_END				; Fowler sampling
	JSR	<RD_ARRAY     				; Read the array
	NOP
RD_END

; Implement up-the-ramp readout
	DO	Y:<IUTR,L_UP_THE_RAMP

; Expose the array
	MOVE	#ST_COAD,R7		; Jump to ST_COAD after exposure
	JMP	<EXPOSE			; Start exposure countdown

; Sample the signal level NFS times
ST_COAD	DO	Y:<NFS,RD_EXP				; Fowler sampling
	JSR	<RD_ARRAY     				; Read the array
	NOP
RD_EXP
	NOP
L_UP_THE_RAMP				; Up the ramp loop

BO_SKIP NOP
	NOP
L_COADD					; Main coadd loop
;	;; This is a total hack workaround to get the number of pixels to
;	;; be right in the image. For some reason getting the reads to
;	;; line up ends up with too few pixels. This should be removed
;	;; when we figure out what is going on.
	MOVE	Y:<NREADS,X0		; number of reads
	DO	X0,EXTRA_READS ; Read a few times to finish up the image
        MOVE    Y:<CLK_COL_AND_READ,R0	; comment
        JSR     <CLOCK			; comment
        MOVE    Y:<CLK_COL_AND_READ,R0	; comment
        JSR     <CLOCK			; comment
	NOP			; 
EXTRA_READS
	NOP
BO_END
	NOP


	
; In coadder mode jump to the transmit routine in SRAM
	JCLR	#PTR_MODE,X:STATUS,TRANSMIT_COADDED_IMAGE

; In PT mode, finish up and return to START
	JSR	<PAL_DLY		; Wait for the last serial data
	BCLR	#WW,X:PBD		; Clear WW to 0 for 32-bit commands
	JMP	<START			; Wait for a new host computer command

; Transmit the coadded image from the coadder board to the host computer
TRANSMIT_COADDED_IMAGE
	MOVE	#$020F02,X0		; Header for all coadder boards
	JSR	<XMT_CA
	MOVE	#'TCA',X0		; Transmit the coadded frame
	JSR	<XMT_CA
	JSR	<PAL_DLY		; Wait for coadder to start

; Alert the PCI interface board that images are coming soon
	MOVEP	#$020002,Y:WRFO		; Send header word to the FO transmitter
	REP	#20			; Delay a bit for the transmission
	NOP
	MOVEP	#'RDA',Y:WRFO
	REP	#20			; Delay a bit for the transmission
	NOP
	BSET	#WW,X:PBD		; Set WW = 1 for 16-bit image data

XMT_DLY	EQU	$4A0000			; Delay for serial transmitter

; This is for a single 512x512 quad assuming all 8 outputs are on that quad (aka Aladdin) ************
; Transmit the coadded 512x512 pixel frame to the host computer, 32-bits/pixel
	MOVE	#>8,A			; Not-CDS value = (512 x 512) / 8       (loop 8 times)
	JCLR	#CDS_MODE,X:STATUS,XMIT
	MOVE	#>16,A			; CDS value = 2 x (512 x 512) / 8       (loop 16 times)
XMIT	DO	A,L_XTIM1		;   32-bits per pixel
	MOVE	#$1000,X0		; For two coadder boards transmit       (loop 4096 times)
	DO	X0,L_TXIM2		;   eight pixels per loop
	MOVE	#$00F060,A 		; Write SXMIT out
	MOVE	A,X:(R6)		;     send 4 16-bit pix, board 1
	MOVE	#XMT_DLY,X0		; Delay for pixel transmission
	MOVE	X0,X:(R6)
	MOVE	#$00F060,A 
	MOVE	A,X:(R6)		;     send 4 16-bit pix, board 1
	MOVE	#XMT_DLY,X0
	MOVE	X0,X:(R6)
	MOVE	#$00F0E4,A 
	MOVE	A,X:(R6)		;     send 4 16-bit pix, board 2
	MOVE	#XMT_DLY,X0
	MOVE	X0,X:(R6)
	MOVE	#$00F0E4,A 
	MOVE	A,X:(R6)		;     send 4 16-bit pix, board 2
	MOVE	#XMT_DLY,X0
	MOVE	X0,X:(R6)
L_TXIM2	NOP
L_XTIM1
	JSR	<PAL_DLY		; Wait for the last serial data
	BCLR	#WW,X:PBD		; Clear WW to 0 for 32-bit commands
	JMP	<START			; Wait for a new host computer command


 
;******************************************************************************
; Send a serial command to an H1RG register
;   SER  #REGISTER  #DATA  
;                               #REGISTER is from 1 to 13 (1-D)
;                               #DATA (up to 12 bits)
SERIAL_COMMAND

        MOVE    X:(R4)+,Y0      ; First argument is REGISTER NUMBER
        MOVE    X:(R4)+,Y1      ; Second argument is DATA
	BCLR	#1,Y:<SERJUMP	; this bit should be clear because this is an external call

SERIAL_JUMP_IN
        CLR     A
        MOVE    Y0,A1
        REP     #12
        LSL     A		; shift register number 12 bits left
        MOVE    A1,X0

        CLR	B			; if register # is 0, this means reset them all (pulse MAINRESETB)
        CMP     Y0,B			;
        JEQ     <RESET_REGISTERS	; jump to reset section
	
        MOVE    Y1,A1
        OR      X0,A1           ; OR REG # with DATA to build 16-bit command word
        MOVE    A1,Y:<TEMP

        MOVE    #CSB_OFF,R0     ; Set CSB LO
        JSR     <CLOCK

        MOVE    Y:<TEMP,A1              ; X0 now contains the command word

        ; now loop over all 16 bits and send out 1's or 0's
        DO      #16,SENDBITS

        MOVE    Y:<TEMP,A1
        LSL     A
        MOVE    A1,Y:<TEMP
        MOVE    A1,B1
        MOVE    #$010000,Y0
        AND     Y0,B
        MOVE    B1,X0
        MOVE    X:<ZERO,Y0
        CMP     Y0,B
        JGT     <SET_1
        MOVE    #CLOCK_SERIAL_ZERO,R0   ; Send a 0
        JSR     <CLOCK
        JMP     NEXT_BT
SET_1   MOVE    #CLOCK_SERIAL_ONE,R0    ; Send a 1
        JSR     <CLOCK
NEXT_BT
        NOP
SENDBITS

        MOVE    #CSB_ON,R0     ; Set CSB HI - all bits are in...this latches the value
        JSR     <CLOCK

	JMP	<NO_RESET_REGISTERS 	; jump over the reset

RESET_REGISTERS	
	MOVE	#PULSE_MAINRESETB,R0
	JSR	<CLOCK
        MOVE    #IFCTRL_TO_ONE,R0 ; reset the H1RG serial interface from talking on the
        JSR     <CLOCK		  ; shared lines to talk over the dedicated lines instead

NO_RESET_REGISTERS
	JCLR	#1,Y:<SERJUMP,JUST_FINISH	; if this has been called externally, then just finish
	BCLR	#1,Y:<SERJUMP
	RTS					; otherwise, clear the bit and return to the place that called it

JUST_FINISH
        JMP     <FINISH

;******************************************************************************
;  Update the DACs
SET_DAC	DO      Y:(R0)+,SET_L0		; Repeat X0 times
	MOVEP   Y:(R0)+,X:SSITX         ; Send out the waveform
	JSR     <PAL_DLY                ; Wait for SSI and PAL to be empty
	NOP                             ; Do loop restriction
SET_L0
	RTS                             ; Return from subroutine

;******************************************************************************
; Set the exposure time
SET_EXT	MOVE	X:(R4)+,X0	; Get third word of command = exposure time
	MOVE	X0,X:<EXP_TIM	; Write to magic address
	MOVE	X0,X:<TGT_TIM
	JMP	<FINISH		; Send out 'DON' reply

;******************************************************************************
; Set the pixel clock time (DLY1 in waveforms.asm)
SET_PIX MOVE    X:(R4)+,A1 	; hold the new delay in a temp location
	REP     #12		; commanded delay is just the left 12 bits of a 24-bit number
        LSL     A1
	MOVE 	A1,Y:<TEMP	; (its the third word of command)

	MOVE #WAVE_START,R0 	; Loop over the entire wave table
	JSR	<NEW_DLY		

; Set the new delay time
	MOVE	Y:<TEMP,X0	; move the new delay time from the temp location
	MOVE	X0,Y:PIX_TIM	; Write to magic address
	JMP	<FINISH		; Send out 'DON' reply


; A subroutine to subtract the old delay, and add the new delay
NEW_DLY MOVE    Y:(R0)+,A               ; # of waveform entries
	INC 	A			; plus 1
	MOVE	A,X0
        DO      X0,L1                 	; Repeat X0 times
	MOVE	Y:(R0),A  		; move wave into A
	MOVE	Y:PIX_TIM,B		; move old delay into B

	REP	#16			; Compare the delay in the waveform to the 
	LSR	A			; stored old delay. If not equal, then just 
	REP	#16			; skip this wave and go to the next. This is for
	LSR	B			; the video delays and such, which have a different 
	CMP 	B,A			; timing
	MOVE	Y:(R0),A  		; move clean wave back into A
	MOVE	Y:PIX_TIM,X1		; move old delay back into X1
	JNE	<NOSUB

        SUB     X1,A			; subtract old delay
	MOVE	Y:<TEMP,X1		; move new delay into X1
	ADD	X1,A			; add new delay
NOSUB   MOVE    A,Y:(R0)+		; move result into wave and point to next wave
	NOP
L1
        RTS                             ; Return from subroutine

;******************************************************************************
; Abort exposure - not implemented
ABORT_EXP
	JMP	<FINISH		; Issue a 'DON' reply

;******************************************************************************
; Abort readout - not implemented
ABORT_READOUT
	JMP	<START		; Do not issue a 'DON' reply

;******************************************************************************
; Delay for serial writes to the PALs and DACs by 8 microsec
PAL_DLY	DO	#300,PAL_DLY_END	; Wait 8 usec for serial data transmission
	NOP
PAL_DLY_END
	RTS

;******************************************************************************
; 1 us delay - this is a utility for BO mode mainly
US_DLY	DO	#37,US_DLY_END
	NOP
US_DLY_END
	RTS

;******************************************************************************
; Transmit a word to the coadder board over the SSI link
XMT_CA	JCLR    #SSI_TDE,X:SSISR,*	; Continue if SSI XMT register is empty
        MOVEP	X0,X:SSITX		; Write to SSI buffer 
	RTS

;******************************************************************************
; Wait for a 'DON' reply from the coadder board
WT_DON	JCLR	#SSI_RDF,X:SSISR,*
	MOVEP   X:SSIRX,A
	MOVE	Y:<CA_HDR,X0
	CMP	X0,A
	JNE	<WT_DON
	JCLR	#SSI_RDF,X:SSISR,*
	MOVEP   X:SSIRX,A
	MOVE	X:<DON,X0
	CMP	X0,A
	JNE	<WT_DON
	RTS

;******************************************************************************
; Set a particular bias or video offset value
;    SBN  #BOARD  #DAC  "type of board" voltage
;				#BOARD is from 0 to 15
;				#DAC_number is from 0 to 47
;				'type of board' is 'CLK' or 'VID'
;				#voltage is from 0 to 4095
SET_BIAS_NUMBER			; Set bias number
	JSR	<SER_ANA	; Set SSI to analog board communication
	MOVE	X:(R4)+,Y0	; First argument is board number, 0 to 15
	MOVE	Y0,A	
	REP	#20
	LSL	A
	MOVE	A,X0
	MOVE	X:(R4)+,Y1	; Second argument is DAC number
	MOVE	Y1,Y:<TEMP	; also store temporarily
	MOVE	Y1,A
	REP	#14
	LSL	A
	OR	X0,A
	MOVE	X:(R4)+,B	; Third argument is 'VID' or 'CLK' string
	MOVE	#'VID',X0
	CMP	X0,B
	JNE	<CLK_DRV
	BSET	#19,A1		; Set bits to mean video processor DAC
	BSET	#18,A1
	JMP	<VID_BRD
CLK_DRV	MOVE	#'CLK',X0
	CMP	X0,B
	JNE	<ERR_SBN
VID_BRD	MOVE	A,X0
	MOVE	X:(R4)+,A	; Fourth argument is voltage value, 0 to $fff
	MOVE	#$000FFF,X1	; Mask off just 12 bits to be sure
	AND	X1,A
	OR	X0,A

; Update DAC table in memory with new value
	MOVE    #'CLK',X0
	CMP     X0,B
	JNE 	VB

CB	MOVE	X:<TWO,X0	; check to be sure board # is ge 2, otherwise exit with err
	MOVE 	Y0,B1
	CMP	X0,B
	JLT	<ERROR

	MOVE 	Y0,B1
	ASR	B		; divide board# by 2
	MOVE	X:<ONE,X0
	SUB	X0,B		; minus one - now CLK2 is 0 and CLK4 is 1

	MOVE	B1,X0
	MOVE	#$30,B1
	MOVE	B1,Y0
	MOVE	#0,B
	MPY	X0,Y0,B
	ASR	B
	MOVE 	B0,X0
	MOVE	#0,B
	MOVE	Y:<TEMP,Y1	
	ADD	X0,B		; add mem offset for given board
	ADD	Y1,B		; add DAC #
	MOVE    #DACS,X1	
	ADD	X1,B		; add first CLK board DAC value, which is stored in 
	MOVE	X:<ONE,X1	;   DACS+1
	ADD	X1,B		
	MOVE	B,R2		; move mem pointer into R2
	JMP	<WRDAC

VB	MOVE	#OFFSETS,X1	; first VID board DAC value is stored here 
	MOVE	Y0,B		; Jump ahead to the selected offset
	LSL	B		; (board# * 4) for VID
	LSL	B
	ADD	X1,B		;   + OFFSETS
	ADD	Y1,B		;   + DAC number for this board (0-3)
	MOVE	B,R2
	NOP
WRDAC	MOVE	A,Y:(R2)	; Write the number to the DAC table in memory	

; Write the number to the DAC itself
	MOVEP	A,X:SSITX	; Write the number to the DAC itself
	JSR	<PAL_DLY	; Wait for the number to be sent
	JSR	<SER_CA		; Return SSI to coadder board communication
	JMP	<FINISH

; If invalid board type, then return wth error
ERR_SBN	MOVE	X:(R4)+,A	; Read and discard the fourth argument
	JSR	<SER_CA		; Return SSI to coadder board communication
	JMP	<ERROR



;******************************************************************************
; Get a particular bias or video offset value
;    GBN  #BOARD  #DAC  "type of board" voltage
;				#BOARD is from 0 to 15
;				#DAC_number is from 0 to 47
;				'type of board' is 'CLK' or 'VID'
GET_BIAS_NUMBER			; Get bias number
	MOVE	X:(R4)+,Y0	; First argument is board number, 0 to 15
	MOVE	Y0,A	
	REP	#20
	LSL	A
	MOVE	A,X0
	MOVE	X:(R4)+,Y1	; Second argument is DAC number
	MOVE	Y1,Y:<TEMP	; also store temporarily
	MOVE	Y1,A
	REP	#14
	LSL	A
	OR	X0,A
	MOVE	X:(R4)+,B	; Third argument is 'VID' or 'CLK' string

; get value from DAC table in memory
	MOVE    #'CLK',X0
	CMP     X0,B
	JNE 	GVB

	MOVE	X:<TWO,X0	; check to be sure board # is ge 2, otherwise exit with err
	MOVE 	Y0,B1
	CMP	X0,B
	JLT	<ERROR

GCB	MOVE 	Y0,B1
	ASR	B		; divide board# by 2
	MOVE	X:<ONE,X0
	SUB	X0,B		; minus one - now CLK2 is 0 and CLK4 is 1

	MOVE	B1,X0
	MOVE	#$30,B1
	MOVE	B1,Y0
	MOVE	#0,B
	MPY	X0,Y0,B
	ASR	B
	MOVE 	B0,X0
	MOVE	#0,B
	MOVE	Y:<TEMP,Y1	
	ADD	X0,B		; add mem offset for given board
	ADD	Y1,B		; add DAC #
	MOVE    #DACS,X1	
	ADD	X1,B		; add first CLK board DAC value, which is stored in 
	MOVE	X:<ONE,X1	;   DACS+1
	ADD	X1,B		
	MOVE	B,R2		; move mem pointer into R2
	JMP	<RDDAC

GVB	MOVE	#OFFSETS,X1	; first VID board DAC value is stored here 
	MOVE	Y0,B		; Jump ahead to the selected offset
	LSL	B		; (board# * 4) for VID
	LSL	B
	ADD	X1,B		;   + OFFSETS
	ADD	Y1,B		;   + DAC number for this board (0-3)
	MOVE	B,R2
	NOP
RDDAC	MOVE	Y:(R2),B	; retrieve value from DAC table
        MOVE    #$000FFF,X1     ; Mask off just the 12 bits containing the $000-$FFF value
        AND     X1,B
	MOVE	B,X0		; X0 now holds the requested value
                                ; Send a reply of value in X0 - header and reply - to host
        MOVE    X:<HDR,A        ; Get header of incoming command
        MOVE    X:<SMASK,Y0     ; This was the source byte, and is to
        AND     Y0,A  X:<TWO,Y0 ;    become the destination byte
        REP     #8              ; Shift right one byte, add it to the
        LSR     A  Y0,X:<NWORDS ;     header, and put 2 as the number
        ADD     Y0,A  X:<SBRD,Y0 ;    of words in the string
        ADD     Y0,A            ; Add source board's header, set X1 for above
        MOVE    A,X:(R3)+       ; Put header on the transmitter stack
        MOVE    X0,X:(R3)+      ; Put value of XO on the transmitter stack
        JMP     <PRC_RCV        ; Go transmit these words

;******************************************************************************
; Test coadder memory
TEST_CA_MEMORY
	MOVE	X:SSIRX,A		; Dummy read to clear SSI receiver
	MOVE	#$020F02,X0		; Header for all coadder boards
	JSR	<XMT_CA			; Transmit command to coadder boards
	MOVE	#'TCM',X0		; Test Coadder Memory
	JSR	<XMT_CA

;******************************************************************************
; Power off
PWR_OFF	BCLR	#CDAC,X:<LATCH		; Clear all DACs
	BCLR	#ENCK,X:<LATCH		; Disable DAC output switches
	MOVEP	X:LATCH,Y:WRLATCH
	BSET	#LVEN,X:PBD		; LVEN = HVEN = 1 => Power reset
	BSET	#PWRST,X:PBD		; PWRST = 1 => Power reset
	BSET	#HVEN,X:PBD
	MOVE	#TST_RCV,X0
	MOVE	X0,X:<IDL_ADR
	JMP	<FINISH

;******************************************************************************
; Power on sequence. This gives nice RC turn-on times of 0.5 milliseconds
;	Open output switches (ENCK)
;	Power ON, delay
;	Zero DACs and switches, delay
;	Close output switch (ENCK) 
;	Load correct voltages into DACs
; Power on 
PWR_ON	JSR	<SER_ANA		; Enable SSI for analog boards
	BSET	#CDAC,X:<LATCH		; Disable clearing of all DACs
	BCLR	#DUALCLK,X:<LATCH	; Each half of clk drv is independent
	BCLR	#ENCK,X:<LATCH		; Open DAC output switches
	MOVEP	X:LATCH,Y:WRLATCH
	BSET	#LVEN,X:PBD		; LVEN = HVEN = 1 => Power reset
	BSET	#PWRST,X:PBD		; PWRST = 1 => Power reset
	BSET	#HVEN,X:PBD

; Now ramp up the low voltages (+/- 6.5V, 16.5V) 
	BCLR	#LVEN,X:PBD		; LVEN = Low => Turn on +/- 6.5V, 
	BCLR	#PWRST,X:PBD		;    +/- 16.5V
	MOVE	X:<THREE,A		; Delay three milliseconds to settle
	JSR	<CON_DELAY

; First, zero all clock driver switches and DACs
	MOVE	#$002000,X0	; bottom of clock board
	MOVE	X0,X:(R6)
	MOVE	#$003000,X0	; top of clock board
	MOVE	X0,X:(R6)
	MOVE	#$004000,X0	; bottom of bias board
	MOVE	X0,X:(R6)
	MOVE	#$005000,X0	; top of bias board
	MOVE	X0,X:(R6)
	MOVE    #ZERO_BIASES,R0
	JSR     <SET_DAC
	MOVE	X:<THREE,A
	JSR	<CON_DELAY

; Close output switch before writing correct voltages to DACs to the voltages 
;   turn on with the RC time constant of the RC filters on the DAC outputs
	BSET	#ENCK,X:<LATCH		; Enable DAC output switches
	MOVEP	X:LATCH,Y:WRLATCH

; Turn on the DACS
	MOVE	#DACS,R0		; Get starting address
	JSR	<SET_DAC
	MOVE	X:<THREE,A		; Delay three milliseconds to settle
	JSR	<CON_DELAY

; Send out a special waveform to change the H1RG serial interface from talking on the
; shared lines to talk over the dedicated lines instead

        MOVE    #IFCTRL_TO_ONE,R0         
        JSR     <CLOCK

; Enable continuous reset mode
	MOVE	#CONT_RST,X0		; Put array in continuous reset mode
	MOVE	X0,X:<IDL_ADR

; Enable the SSI for coadder board communication 
	JSR	<SER_CA			; Enable SSI for the coadder board
	JMP	<FINISH 

;******************************************************************************
; Move Coadder code from timing board ROM to coadder DSP memory over the SCI
LOAD_COADDER
	JSR	<CA_RST

; Configure SCI port for a baud rate of 50 MHz / 64 / 2 = 390 kbaud	
	MOVEP   #$0007,X:PCC	; Enable SCI pins RXD, TXD and SCLK
	MOVEP	#$0302,X:SCR	; Enable RXD and TXD
	MOVEP	#$1001,X:SCCR	; SCI clock = 16 x baud rate
	JSR	<PAL_DLY

; Send the boot code to the coadder
	MOVE    #P_COADD,R0 	; Starting P: address in EEPROM
	DO	#3,L_COADDER
        MOVE    P:(R0)+,A2	; Get one byte from EEPROM
	REP	#8
        ASR     A  		; Shift right 8 bits
	NOP
L_COADDER
	MOVE	X:<TWO,X0
	ADD	X0,A		; A1 = Number of words + 2
	MOVE    #P_COADD,R0 	; Starting P: address in EEPROM
	DO      A1,P_MOVE	; Loop over A1 words
        DO      #3,P_LOOP	; Write 3 bytes per word
	JCLR	#0,X:SSR,*	; Wait for transmitter to be empty
        MOVEP	P:(R0)+,X:WRSCI	; Transfer one byte from EEPROM to SCI port
P_LOOP	NOP
P_MOVE
	DO	#2400,*+3	; Wait for the last word to transmit
	NOP
	JSR	<SER_CA		; Enable SSI for the coadder board 
	JMP	<FINISH

;******************************************************************************
; Move Coadder code from timing board SRAM to coadder DSP memory over the SCI
DOWNLOAD_COADDER
	JSR	<CA_RST

; Configure SCI port for a baud rate of 50 MHz / 64 / 2 = 390 kbaud	
	MOVEP   #$0007,X:PCC	; Enable SCI pins RXD, TXD and SCLK
	MOVEP	#$0302,X:SCR	; Enable RXD and TXD
	MOVEP	#$1001,X:SCCR	; SCI clock = 16 x baud rate
	JSR	<PAL_DLY

; Send the boot code to the coadder
	MOVE    #SRAM_AD,R0 	; Starting P: address in SRAM = $B0B
	MOVE	X:<TWO,X0
        MOVE    P:(R0),A	; Get number of words from SRAM
	ADD	X0,A		; A1 = Number of words + 2
	DO      A1,PROGRAM_MOVE	; Loop over number of words
	JCLR	#0,X:SSR,*	; Wait for transmitter to be empty
        MOVEP	P:(R0),X:WRSCI0	; Transfer one byte from SRAM to SCI port
	JCLR	#0,X:SSR,*	; Wait for transmitter to be empty
        MOVEP	P:(R0),X:WRSCI1	; Transfer one byte from SRAM to SCI port
	JCLR	#0,X:SSR,*	; Wait for transmitter to be empty
        MOVEP	P:(R0)+,X:WRSCI2 ; Transfer one byte from SRAM to SCI port
PROGRAM_MOVE
	DO	#2400,*+3	; Wait for the last word to transmit
	NOP
	JSR	<SER_CA		; Enable SSI for the coadder board 
	JMP	<FINISH

;******************************************************************************
; Reset the coadder board to force it to re-boot
CA_RST	BCLR	#RST_CA,X:<LATCH	
	MOVEP	X:LATCH,Y:WRLATCH 	; Clear reset coadder bit
	DO	#600,*+3		; Delay by RESET* time = 100 microsec
	NOP
	BSET	#RST_CA,X:<LATCH	
	MOVEP	X:LATCH,Y:WRLATCH 	; Set reset coadder bit
	RTS

;******************************************************************************
; Enable serial communication to the analog boards
SER_ANA	BSET	#0,X:PBD	; Set H0 for analog boards SSI
	MOVEP	#$0000,X:PCC	; Software reset of SSI
	BCLR	#10,X:CRB	; Change SSI to continuous clock for analog 
	MOVEP   #$0160,X:PCC	; Re-enable the SSI
	RTS

;******************************************************************************
; Enable serial communication to the coadder board
SER_CA	MOVEP	#$0000,X:PCC	; Software reset of SSI
	BSET	#10,X:CRB	; Change SSI to gated clock for utility board 
	MOVEP   #$01E8,X:PCC	; Enable the SSI
	MOVEP	#$0003,X:PCDDR	; Disable PC2 = SCLK output
	BCLR	#0,X:PBD	; Clear H0 for utility board SSI
	RTS

;******************************************************************************
; Simple, do nothing command to exit RUN mode
STP	JMP	<FINISH

;******************************************************************************
; Short delay for settling times
CON_DELAY				; Alternate entry for camera on delay
	MOVE	A,X:<TGT_TIM
	CLR	A                       ; Zero out elapsed time
	MOVE	A,X:<EL_TIM
	BSET	#0,X:TCSR               ; Enable DSP timer
CNT_DWN	JSET	#0,X:TCSR,CNT_DWN       ; Wait here for timer to count down
	RTS

;******************************************************************************
; Let the host computer read the controller configuration
READ_CONTROLLER_CONFIGURATION
	MOVE	Y:<CONFIG,X0		; Just transmit the configuration
	JMP	<FINISH1

;******************************************************************************
COADDER_TDL
	MOVE	X:SSIRX,A		; Dummy read to clear SSI receiver
	MOVE	#$020F03,X0		; Header for all coadder boards
	JSR	<XMT_CA			; Transmit command to coadder boards
	MOVE	#'TDL',X0		; Test Coadder Memory
	JSR	<XMT_CA
	MOVE	X:(R4)+,X0		; Argument
	JSR	<XMT_CA
	JCLR	#SSI_RDF,X:SSISR,*	; Wait for a reply from the coadder
	MOVE	X:SSIRX,A		; Read the SSI word
	MOVE	#$040002,X0		; Desired header from the timing board
	CMP	X0,A
	JNE	<ERROR
	JCLR	#SSI_RDF,X:SSISR,*	; Wait for a reply from the coadder
	MOVE	X:SSIRX,X0		; Read the SSI word
	JMP	<FINISH1		

;******************************************************************************
INIT_COADDER
	MOVE	X:SSIRX,A		; Dummy read to clear SSI receiver
	MOVE	#$020F02,X0		; Header for all coadder boards
	JSR	<XMT_CA			; Transmit command to coadder boards
	MOVE	#'ICA',X0		; Test Coadder Initialization
	JSR	<XMT_CA
	JCLR	#SSI_RDF,X:SSISR,*	; Wait for a reply from the coadder
	MOVE	X:SSIRX,A		; Read the SSI word
	MOVE	#$040202,X0		; Desired header from the timing board
	CMP	X0,A
	JNE	<ERROR
	JCLR	#SSI_RDF,X:SSISR,*	; Wait for a reply from the coadder
	MOVE	X:SSIRX,X0		; Read the SSI word
	JMP	<FINISH1		

;******************************************************************************
; Specify global, row-by-row or pixel-by-pixel reset
SELECT_RESET_MODE
	MOVE	X:(R4)+,X0			; Get the command argument
	JSET	#0,X0,SRM_ROW_BY_ROW		; if bit 0 is 1, then row-by-row
	JSET	#1,X0,SRM_PIXEL_BY_PIXEL	; if bit 1 is 1, then pixel-by-pixel, otherwise, must be global
SRM_GLOBAL
	BCLR	#RST_MODE,X:STATUS	; Global reset is in effect
	JMP	<FINISH
SRM_ROW_BY_ROW	
	BSET	#RST_MODE,X:STATUS	; Row-by-row reset is in effect
	BCLR	#RST_MODE1,X:STATUS	; 	NOT pixel-by-pixel
	JMP	<FINISH
SRM_PIXEL_BY_PIXEL
	BSET	#RST_MODE1,X:STATUS	; Pixel-by-Pixel reset is in effect
	BCLR	#RST_MODE,X:STATUS	; 	NOT row-by-row
	JMP	<FINISH

;*****************************************************************************
; Specify either normal or Bright Object (BO) mode
SELECT_BO_MODE
	MOVE	X:(R4)+,X0		; Get the command argument
	JSET	#0,X0,SBO_SET
	BCLR	#BO_MODE,X:STATUS	; NORMAL mode is in effect
	JMP	<FINISH
SBO_SET	BSET	#BO_MODE,X:STATUS	; BO mode is in effect
	JMP	<FINISH

;******************************************************************************
; Specify either normal or Window mode
SELECT_WIN_MODE
	MOVE	X:(R4)+,X0		; Get the command argument
	JSET	#0,X0,WIN_SET
	BCLR	#WIN_MODE,X:STATUS	; NORMAL mode is in effect
	JMP	<FINISH
WIN_SET	BSET	#WIN_MODE,X:STATUS	; BO mode is in effect
	JMP	<FINISH

;******************************************************************************
; Set number of Fowler samples per frame
SET_NUMBER_OF_FOWLER_SAMPLES
	MOVE	X:(R4)+,X0
	MOVE	X0,Y:<NFS		; Number of Fowler samples
	JMP	<FINISH

;******************************************************************************
; Set number of resets to do in autoflush
SET_AUTO_FLUSH
	MOVE	X:(R4)+,X0
	MOVE	X0,Y:<FLUSH		; 'AFL' for autoflush, 0 for none, N for the number
					; of resets you want.
	JMP	<FINISH

;******************************************************************************
; Specify readout either before and after exposure (CDS) or only after
SELECT_SAMPLING_MODE
	MOVE	X:(R4)+,X0		; Get the command argument
	JSET	#0,X0,CDS_SET
	BCLR	#CDS_MODE,X:STATUS	; Single sampling is in effect 
	JMP	<FINISH	
CDS_SET	BSET	#CDS_MODE,X:STATUS	; Double correlated sampling is
	JMP	<FINISH			;  in effect

;******************************************************************************
; Specify whether the coadder board does arithmetic (PTR = 0) or whether
;   it just passes the data right through
SELECT_PASS_THROUGH_READOUT
	MOVE	X:(R4)+,X0		; Get the command argument
	JSET	#0,X0,PTR_SET
	BCLR	#PTR_MODE,X:STATUS	; Coadder board arithmetic is  
	JMP	<FINISH			;  in effect
PTR_SET	BSET	#PTR_MODE,X:STATUS	; Pass through readout mode is
	JMP	<FINISH			;  in effect

;******************************************************************************
; Set number of coadds per frame
SET_NUMBER_OF_COADDS
	MOVE	X:(R4)+,X0
	MOVE	X0,Y:<NCOADDS
	JMP	<FINISH

;******************************************************************************
; Set number of exposures for up-the-ramp readout mode; also, pass-through
;   mode is always implemented in up-the-ramp. 
SET_UP_THE_RAMP
	MOVE	X:(R4)+,X0
	MOVE	X0,Y:<NUTR
	MOVE	X:<ONE,X0	; load one into X0
	MOVE    X0,Y:<IUTR	; reset this so that Fowler and CDS work after UTR
	JMP	<FINISH

; Alert the PCI interface board that images are coming soon
PCI_READ_IMAGE
	MOVE	#$020104,X0
	JSR	<XMT_FO
	MOVE	#'RDA',X0
	JSR	<XMT_FO
	CLR	A
	MOVE	Y:<NCOLS,A0	; load ncols into A
	ASL	A		; first shift left to account for the extra reads of temp and analog
	;;				outputs

;;; kludge for WIN mode
;        JSET    #WIN_MODE,X:STATUS,KLUDGE  ; if WIN mode selected, don't divide by 2
;	ASR	A			; Now shift right twice to divide by 4
;KLUDGE  ASR	A			; Note that the PCI card will multiply ncol
;;					by eight so we are really passing ncols*nreads*2
;;					to account for the extra reads of temp and analog
	;;				outputs.
	MOVE	A0,X0
	JSR	<XMT_FO
	MOVE	Y:<NROWS,X0	; load nrows
	JSR	<XMT_FO
	MOVE	Y:<NREADS,X0	; load nreads
	JSR	<XMT_FO
	RTS

XMT_FO	MOVE	X0,Y:WRFO
	REP	#15
	NOP
	RTS

;******************************************************************************
; Send the device type back to the PCI/VOODOO
GET_DEVICE_TYPE
	MOVE    X:<ONE,X0	; X0 now holds the requested value (0=H1R, 1=H1RG)
                                ; Send a reply of value in X0 - header and reply - to host
        MOVE    X:<HDR,A        ; Get header of incoming command
        MOVE    X:<SMASK,Y0     ; This was the source byte, and is to
        AND     Y0,A  X:<TWO,Y0 ;    become the destination byte
        REP     #8              ; Shift right one byte, add it to the
        LSR     A  Y0,X:<NWORDS ;     header, and put 2 as the number
        ADD     Y0,A  X:<SBRD,Y0 ;    of words in the string
        ADD     Y0,A            ; Add source board's header, set X1 for above
        MOVE    A,X:(R3)+       ; Put header on the transmitter stack
        MOVE    X0,X:(R3)+      ; Put value of XO on the transmitter stack
        JMP     <PRC_RCV        ; Go transmit these words

;******************************************************************************
; this is just for testing purposes.
CALC_SOME_NUMBERS

        CLR     B
        MOVE    Y:<NCOLS,X0
        MOVE    Y:<NROWS,Y0
        MPY     X0,Y0,B                 ; NCOLS * NROWS = npix per read
        ASR     B

        REP     #3
        ASR     B                       ; divide by 8

        MOVE    B0,Y0

        MOVE    #$4,B0
        MOVE    Y:<NAMPS,X0
        REP     #25
        DIV     X0,B                    ; then divide by the number of amps containing Image pix

        MOVE    B0,X0                   ; NCOLS * NROWS * (4/NAMPS)
        MPY     X0,Y0,B                 ;                   (pixel_factor)
        ASR     B


        MOVE    B0,X0           ; X0 now contains the result to send back
                                ; Send a reply of value in X0 - header and reply - to host
        MOVE    X:<HDR,A        ; Get header of incoming command
        MOVE    X:<SMASK,Y0     ; This was the source byte, and is to
        AND     Y0,A  X:<TWO,Y0 ;    become the destination byte
        REP     #8              ; Shift right one byte, add it to the
        LSR     A  Y0,X:<NWORDS ;     header, and put 2 as the number
        ADD     Y0,A  X:<SBRD,Y0 ;    of words in the string
        ADD     Y0,A            ; Add source board's header, set X1 for above
        MOVE    A,X:(R3)+       ; Put header on the transmitter stack
        MOVE    X0,X:(R3)+      ; Put value of XO on the transmitter stack
        JMP     <PRC_RCV        ; Go transmit these words

;******************************************************************************
;*** Command table. There MUST be exactly 32 commands entered here. ***
;******************************************************************************
	IF	@SCP("DOWNLOAD","HOST")
	ORG	X:COM_TBL,X:COM_TBL			; Download address
	ELSE			
        ORG     P:COM_TBL,P:APL_NUM*N_W_APL+APL_LEN+$200 ; EEPROM address
	ENDIF
	DC	'SEX',START_EXPOSURE	; Voodoo and CCDTool start exposure
	DC      'STP',STP		; Exit continuous RUN mode
	DC      'PON',PWR_ON		; Turn on all camera biases and clocks
	DC      'POF',PWR_OFF		; Turn +/- 15V power supplies off
	DC	'LCA',LOAD_COADDER	; Coadder code comes from timing ROM
	DC	'DCA',DOWNLOAD_COADDER	; Coadder code comes from timing SRAM
	DC	'SBN',SET_BIAS_NUMBER
	DC	'GBN',GET_BIAS_NUMBER
	DC      'DON',START		; Nothing special
	DC	'SET',SET_EXT	 	; Set exposure time
	DC	'AEX',ABORT_EXP		; Abort exposure
	DC	'ABR',ABORT_READOUT
	DC	'RCC',READ_CONTROLLER_CONFIGURATION 
	DC	'TCM',TEST_CA_MEMORY	; Test coadder memory
	DC	'CAT',COADDER_TDL	; Test coadder data link
	DC	'ICA',INIT_COADDER

; Special NGST commands
	DC	'SRM',SELECT_RESET_MODE
	DC	'CDS',SELECT_SAMPLING_MODE
	DC	'SFS',SET_NUMBER_OF_FOWLER_SAMPLES
	DC	'SPT',SELECT_PASS_THROUGH_READOUT
	DC	'SNC',SET_NUMBER_OF_COADDS
	DC	'SUR',SET_UP_THE_RAMP
	DC	'SBO',SELECT_BO_MODE
	DC	'TYP',GET_DEVICE_TYPE
	DC	'SER',SERIAL_COMMAND
	DC	'WIN',SELECT_WIN_MODE
	DC	'SPC',SET_PIX		; Set the pixel clock time 
	DC	'CAL',CALC_SOME_NUMBERS
	DC	'SAF',SET_AUTO_FLUSH

	DC      0,START,0,START,0,START,0,START

; the remaining commands (40 total) are in ../DSPlib/timboot.asm
;******************************************************************************
;*** End of Command table ***
;******************************************************************************


;******************************************************************************
;  ****************  END OF PROGRAM CODE  *******************
;******************************************************************************


	IF	@SCP("DOWNLOAD","HOST")
	ORG	Y:0,Y:0		; Download address
	ELSE
	ORG	Y:0,P:		; EEPROM address continues from P: above
	ENDIF

TEMP	DC	0		; Any temporary storage
NCOLS	DC	$400		; Number of columns 
NROWS	DC	$400		; Number of rows 
NREADS	DC	0		; Number of reads 
STARTCOL	DC	1		; Starting col of readout
STARTROW	DC	1		; starting row of readout
NAMPS	DC	4		; Number of amps containg image data (i.e. video channels being used for a given readout)
NCOADDS	DC	1		; Number of frames to coadd, set in SNC 
NUTR	DC	1		; Number of up-the-ramp frames
IUTR	DC	1		; Number of up-the-ramp frames, minus 1
NFS	DC	1		; Number of Fowler samples
CLK_COL_AND_READ DC	0	; Address of clock and read waveform
LAST_TWO_PIXELS DC 0		; Address of last two pixels waveform
CLK_COL_AND_READ_NO_XFER DC 0	; Address of special first waveform
CA_HDR	DC	$040202		; Coadder header for replies
CONFIG	DC	CC		; Controller configuration
TEST1   DC      0		; For Debugging
TEST2	DC      0		; For Debugging
SERJUMP DC	0		; holds flag for jumping into SER routine internally
FLUSH	DC	'AFL'		; holds number of resets or AF for autoflush

; Put all the waveform and DC bias definitions in a separate file 
	INCLUDE	"waveforms.asm"

	ENDSEC			; End of section TIM_HAWAII_1RG


; Check for program overflow before coadd inclusion at $B0B
        IF      @CVS(N,*)>=$B0B
        WARN    'Application P: program is too large! coadd.asm will not fit!'  ; Make sure program
        ENDIF                                           ;  will not overflow

; Include the coadder source
        INCLUDE "coadd.asm"

;  End of program
	END