;
; This file contains all the standard dhc programs for trace.  These include the normal
; science data program, the jitter mode program, and the table load program.

; Addresses and register numbers are in hex unless otherwise noted. The dimension of regblk's,
; which are decimal unless otherwise noted.

; This first section handles Phase 0.  The standard CCD frame invokes the program whose vector
; is at 0.  Vector zero must be loaded with 100.  Regsiters 400-40f are reserved for phase 0
; activities.  Phase 0 gets the ccd temperatures, transfers them to the CC side of the Data
; Transfer buffer (DTB), asserts an interrupt with code 0, and ends.  
;

; Version 1.29 .... Fixed bug in register dump (missing endmac)

; See file dhc_que_RevisionSummary.txt for development summary

.ORG 0x100 0
.RORG  PARAM  0x400
REGBLK $PARAM  AVGT_PRM[3]
.RORG  ZERO   0
REGDEF $ZERO   ABS
REGBLK $ZERO   CCDTEMPS[20] 

REGEQU $ABS+0X1E NORMALMODE
REGEQU $ABS+0X1F TESTMODE
.RORG  TEST   0x90
REGDEF $TEST  AVGTESTFLAG

SETREGS  $AVGT_PRM 3 0x134L 0x0c
CCDADDR  $AVGT_PRM+1
AVGTEMPS $AVGT_PRM
DTBOUT   $CCDTEMPS 0x14
SETREG   $NEWFRAME 1		; Indicate a new frame has arrived
BRANCHNE $TESTMODE 0xFFF0 &P0_10  ; TestMode flag for phase 0 error (Vr1.21)
THROW    0xFFF0			    ; (Vr 1.21)
P0_10:
SETIRPT  0
ENDMAC

; Phase I results are in 12  registers starting at  28e.
REGBLK 0x028E P1_RESULTS[12]
;					Equates for readbility
REGEQU $P1_RESULTS P1_RESULT_FF
REGEQU $P1_RESULTS+1 P1_RESULT_SF
REGEQU $P1_RESULTS+2 P1_RESULT_TF
REGEQU $P1_RESULTS+3 P1_RESULT_AEF
REGEQU $P1_RESULTS+4 P1_RESULT_IMXV
REGEQU $P1_RESULTS+5 P1_RESULT_IMXL
REGEQU $P1_RESULTS+7 P1_RESULT_IMNV
REGEQU $P1_RESULTS+8 P1_RESULT_IMNL

; The status and control block from the CC begins at 103.  A Sync and type are inserted in the 3
; words before the IPB to make the Data Product Header, which thus begins at 100.
REGBLK 0x0100 DP_HDR[505]
;			These register equivalences are defined for make the code more
;			readable and less suspectable to typos.

REGEQU $DP_HDR+3 CC_INBLK		; the input block is 3 words down from header start
REGEQU $CC_INBLK CC_TIMEWORDS		; 
REGEQU $CC_INBLK+291 FDB 
REGEQU $FDB+1        FDB_CMMODEWORD	; FDB word containing the camera mode field (Vr 1.26)
REGEQU $FDB+3        FDB_SAFEFLAGWORD	; FDB word containing the safety flag bit   (Vr 1.26)
REGEQU $CC_INBLK+307 IPB 
REGEQU $IPB+1        IPB_BPT
REGEQU $IPB+2        IPB_BPYO
REGEQU $IPB+3        IPB_BPYL
REGEQU $IPB+4        IPB_P1SA
REGEQU $IPB+6        IPB_P1NC
REGEQU $IPB+7        IPB_P1NR
REGEQU $IPB+8        IPB_P1RL
REGEQU $IPB+9        IPB_P1BF
REGEQU $IPB+10       IPB_SF
REGEQU $IPB+11       IPB_SFHB
REGEQU $IPB+12       IPB_SFHC
REGEQU $IPB+14       IPB_FF
REGEQU $IPB+15       IPB_FHB
REGEQU $IPB+16       IPB_FHC
REGEQU $IPB+18       IPB_AECX
REGEQU $IPB+19       IPB_AEHB
REGEQU $IPB+20       IPB_AEHC
REGEQU $IPB+22       IPB_AELB
REGEQU $IPB+23       IPB_AELC
REGEQU $IPB+25       IPB_TF
REGEQU $IPB+26       IPB_TMUL
REGEQU $IPB+27       IPB_TPC
REGEQU $IPB+29       IPB_DT
REGEQU $IPB+30       IPB_TAI
REGEQU $IPB+31       IPB_T0
REGEQU $IPB+32       IPB_IMX
REGEQU $IPB+33       IPB_IMN
REGEQU $IPB+40       IPB_FCO
REGEQU $IPB+56       IPB_A1O
REGEQU $IPB+72       IPB_A2O
REGEQU $DP_HDR+417   PURGEBLOCK		; 8 word purge table block
REGEQU $DP_HDR+424   PURGENUMBER	; Number of blocks (8K) to purge 
REGEQU $DP_HDR+425   APID0_COUNT	; Counts APID0 Errors           (Vr1.23)
REGEQU $DP_HDR+426   SAFE_BLK           ; CCD_Safety Block              (Vr1.26)
REGEQU $SAFE_BLK     SAFE_SCOUNT        ; Safe Frame Counter            (Vr1.26)
REGEQU $SAFE_BLK+1   SAFE_DCOUNT        ; Danger Frame Counter          (Vr1.26)
REGEQU $SAFE_BLK+2   SAFE_STHRSH        ; Safe Frame Counter Threshold  (Vr1.26)
REGEQU $SAFE_BLK+3   SAFE_DTHRSH        ; Danger Frame Counter Threshold(Vr1.26)
REGEQU $SAFE_BLK+4   SAFE_1X1THR        ; safety check 1x1       thresh (Vr1.26)
REGEQU $SAFE_BLK+5   SAFE_2X2THR        ; safety check 2X2       thresh (Vr1.26)
REGEQU $SAFE_BLK+6   SAFE_4X4THR        ; safety check 4X4       thresh (Vr1.26)
REGEQU $SAFE_BLK+7   SAFE_8X8THR        ; safety check 8x8       thresh (Vr1.26)
REGEQU $SAFE_BLK+8   SAFE_1X1BIN        ; safety check 1x1       BIN    (Vr1.26)
REGEQU $SAFE_BLK+9   SAFE_2X2BIN        ; safety check 2X2       BIN    (Vr1.26)
REGEQU $SAFE_BLK+10  SAFE_4X4BIN        ; safety check 4X4       BIN    (Vr1.26)
REGEQU $SAFE_BLK+11  SAFE_8X8BIN        ; safety check 8x8       BIN    (Vr1.26)
REGEQU $SAFE_BLK+12  SAFE_HISTTHR       ; safety check Histogram thresh (Vr1.26)
REGEQU $SAFE_BLK+13  SAFE_PLACEH        ; Place holder since thr is long(Vr1.26)


; ********************* TEST vs. NORMAL MODE CONTROLS ****************************
; The normal and test flags are redundant control of testmode.  For testmode to execute, normal
; mode must be 0 and test mode must be non-zero.  Test mode outputs the source images page as a
; full 1033 by 1040 image with header regardless of the settings of the Image Processing Block.


;  ******************* Phase 1-2 common parameters ****************
;
;  The registers from 800-8ff are for parameters common to phase 1 and 2.  The ones defined here
;  are like globals in that there are used by multiple routines.  There are additional P1_P2
;  parameters that are used inside particular routines.  Those are defined within the routines.

.RORG P1_P2 0x800			; 256 registers are reserved for inter-phase parameters
REGDEF $P1_P2 CCDPAGE			; Holds the page number
REGBLK $P1_P2 DPLENGTH[2]		; Carries the data product length
REGBLK $P1_P2 XYRLEN[3]			; 3 length words for various instructions
REGBLK $P1_P2 TRANSDPL[2]		; Transient length (in case done in phase 1)
REGBLK $P1_P2 TRANSXYR[3]		; Tranient XYR lengths
REGDEF $P1_P2 TRANSDONE			; true if transient average completed in phase 1
REGBLK $P1_P2 BINEXTADD			; address of binext params for binextsub
REGDEF $P1_P2 AVGCOUNT			; Counts samples in an average
REGDEF $P1_P2 NEWFRAME			; set to 1 in phase 0 and cleared in phase 1
REGBLK $P1_P2 FLOGGER[11]		; for a scaledsum done for EMI testing
REGDEF $P1_P2 PURGECOUNT		; Counts number of 8K purgetabs done

;  ****************** Phase 1 parameters ************************
;
;  The registers from 420 - 5FF are for parameters used during phase 1.  The ones defined here 
;  Are like globals in that they are used by mulitple routines.  There are additional P1_PARAMS
;  parameters that are used within particular routines.  Those are defined within the routines.

.RORG P1_PARAMS 0x420		; Parameter Area for Phase I
REGDEF  $P1_PARAMS 	P1_BADFLAG
REGDEF  $P1_PARAMS 	P1_BADPIX
REGDEF  $P1_PARAMS 	P1_DOSOME
REGDEF  $P1_PARAMS 	P1_BINFLAG
REGDEF  $P1_PARAMS 	P1_HISTFLAG
REGDEF  $P1_PARAMS 	P1_TRANSFLAG
REGDEF  $P1_PARAMS 	P1_EVENTFLAG
REGDEF  $P1_PARAMS 	P1_EVENT
REGDEF  $P1_PARAMS 	P1_IMAXFLAG
REGBLK  $P1_PARAMS	P1_AVGMOVE[6]		; used to move the averaged data
REGBLK  $P1_PARAMS	P1_HISTOUT[262]		; the output from HIST128
REGEQU  $P1_HISTOUT+256 P1_HIMINVAL
REGEQU  $P1_HISTOUT+257 P1_HIMINLOC
REGEQU  $P1_HISTOUT+259 P1_HIMAXVAL
REGEQU  $P1_HISTOUT+260 P1_HIMAXLOC
REGDEF  $P1_PARAMS   	P1_FLAREVNT		; True if FF or SF detected
REGBLK  $P1_PARAMS   	P1_FINDIMIN[3]
REGEQU  $P1_FINDIMIN+1	P1_FINDIMINLOC
REGBLK  $P1_PARAMS   	P1_FINDIMAX[3]
REGEQU  $P1_FINDIMAX+1	P1_FINDIMAXLOC
REGBLK  $P1_PARAMS P1_TRANSCOUNT[2]		; Result from TRANSDETECT
REGDEF  $P1_PARAMS P1_TRANSFIRST		; 1 if this is the first transient
REGDEF  $P1_PARAMS P1_TEMP		; For timeword swap               (Vr1.21)
REGDEF  $P1_PARAMS      P1_SAFECHK    ; Set by FlagSub if FDB danger set(Vr1.26)


;  ******************* Phase I

; This is the main program invoked by the CC via a BeginMac using Vector 1.  The start address is 180,
; so vector 1 must be loaded with this value.  This section of the program is more or less like main.
; First, the CCD Page address is copied from the phase 0 location to a phase I-II location.  This 
; is to make sure we don't lose that address to a new frame.  The program then calls a phase I routine.
; Upon return, the phase I results are tranferred to the CC side of the DTB, and an interrupt is 
; asserted with code 1.  When the CC resumes the queue, the program calls the phase II routine.
; Upon return, it asserts an interrupt with code 2, and ends when the CC resumes the queue.  Most of
; the action happens in the phase I and II routines.

.ORG 0x0180 1

OBSERVING_MAIN:

SETREG   $NEWFRAME 0
COPYREG  $AVGT_PRM+1 $CCDPAGE	; Save CCD frame address  
CALLQUE  &InitLiteralSub	; Initialize Literals
CALLQUE  &DoPhase1Sub		;Call the Phase I routine
BRANCHNE $TESTMODE 0xFFF1 &Main_10  ; TestMode flag for phase 1 error       (Vr1.21)
THROW    0xFFF1			    ;                                       (Vr1.21)
Main_10:
BRANCHNE $TESTMODE 0xFFFC &Main_20          ; Flag value to test safety mode(Vr1.22)
SETREG   $P1_RESULTS+11 1
THROW    0xCCD0                     ;                                       (Vr1.26) 
Main_20:
DTBOUT   $P1_RESULTS 0x0C	;transfer 12 words of phase I results to CC.
SETIRPT  1			;assert the phase I interrupt

CALLQUE &DoPhase2Sub		;Call the Phase II section
Main_80:			; top of emi test loop
BRANCHNE $NORMALMODE 1 &Main_90	; is this the special EMI testmode?
BRANCHNE $TESTMODE 0xFFFE &Main_90
;  We are in EMI testmode (flog it) .. execute a scaledsum until the next frame
BRANCHNE $NEWFRAME 0 &Main_99	; If a new frame is in, stop flogging
SETREGS  $FLOGGER 11 2:0 7:0 6:0 0 1 1 1 0x10	; flog is a 64K scalesum
SCALESUM $FLOGGER
GOTO     &Main_80
; Here we purge the tables page unless the testmode flag is 0xFFFD
; Purge 8k at a time until all is done or the next picture arrives
Main_90:
BRANCHNE $NORMALMODE 1 &Main_99		; skip if not normal mode
BRANCHEQ $TESTMODE 0xFFFD &Main_99	; or if testmode fffd
SETREG   $PURGECOUNT 96			; purge no more than a full page
Main_95:				; top of purge loop
SETREG   $PURGENUMBER 1			; purge 8K each time
PURGETAB $PURGEBLOCK			; this is the purge
BRANCHNE $NEWFRAME 0 &Main_99		; if there's a new picture, exit
ADDREGD  $PURGECOUNT -1			; decrease the count
BRANCHGT $PURGECOUNT 96 &Main_99	; bound check (limit to initial value)
BRANCHGT $PURGECOUNT 0  &Main_95	; repeat if page not alll swept
; Picture Processing is complete
Main_99:
BRANCHNE $TESTMODE 0xFFF2 &Main_100  ; TestMode flag for phase 2 error      (Vr1.21)
THROW    0xFFF2			    ; (Vr 1.21)
Main_100:
SETIRPT 2			;Assert the Phase II interrupt
ENDMAC				;That's it

;  This is the main Phase I routine.  It is invoked from TakePicture main via call queue.



.ORG 0x200
DoPhase1Sub:

DTBIN   $CC_INBLK 0x18A ;(394 words from add 259)	; read in the CC data block
COPYREG $CC_TIMEWORDS $P1_TEMP			; swap timewords 1 and 3  (VR 1.21)
COPYREG $CC_TIMEWORDS+2 $CC_TIMEWORDS
COPYREG $P1_TEMP $CC_TIMEWORDS+2

;     If the normal mode flag is 0 and the test mode flag is FFFF, branch to test mode.
;     This double check prevents the program from reverting to test mode by a single hit.
BRANCHNE $TESTMODE 0xFFFF &P1_NormalMode
BRANCHIF $NORMALMODE &P1_TestMode


;     This is the normal mode code

P1_NormalMode:
CALLQUE &P1_InitSub                ; Initialization (TBD)
CALLQUE &P1_FlagSub                ; Setup a few easily testable flags
BRANCHGT $IPB_BPT 7 &P1_BadDone       ; Bp value must be 0 - 7
BRANCHLT $IPB_BPT 0 &P1_BadDone
BRANCHEQ $TESTMODE 0xFFFD &P1_BadDone  ; Skip Bad is testMode is FFFD
CALLQUE  &P1_BadPixSub

P1_BadDone:
BRANCHIF $P1_SAFECHK &P1_SafetyDone         ; is safety check requested     (Vr1.26)
CALLQUE  &P1_SafetySub                      ; call the safety check routine (Vr1.26)
P1_SafetyDone:
BRANCHIF $P1_DOSOME &P1_AllDone	;If DOSOME is 0, there's no Further Phase I
SETREG   $BINEXTADD $IPB_P1SA	; set the address of the bin/ext params
CALLQUE  &BinExtSub		; call the P1-P2 common binext routine

BRANCHIF $P1_HISTFLAG &P1_HistDone  ; do the histogram routine if required
CALLQUE &P1_HistSub
BRANCHNE $P1_EVENTFLAG 0 &P1_AllDone      ; If there's an event, we're done

P1_HistDone:
BRANCHIF $P1_TRANSFLAG &P1_TransDone ;do the transient, if requested
CALLQUE &P1_TransSub
BRANCHNE $P1_EVENTFLAG 0 &P1_AllDone      ; If there's an event, we're done

P1_TransDone:
BRANCHNE $P1_HISTFLAG 0 &P1_AllDone	; if histogram, IMX already done
BRANCHIF $P1_IMAXFLAG &P1_AllDone   ; If there's IMAX request, do it
CALLQUE &P1_ImaxSub

P1_AllDone:                         ; That's it for Phase I
RTNQUE

; Phase I Normal Mode Subroutines

; 

Phase I Initialization

;  Phase IInitialization Subroutine ...  Clears various parameters

P1_InitSub:
SETREGS $P1_RESULTS 12 0 0 0 0 0 0 0 0 0 0 0 0	; Clear phase 1 results
BRANCHNE $TESTMODE 0xFFFC &P1_In05               ; Flag value to test safety mode (1.22)
SETREG  $P1_RESULTS+11 1
P1_In05:
SETREGS $P1_BADFLAG 9  0 0 0 0 0 0 0 0 0	; Clear Flags
SETREG  $TRANSDONE 0				; clear transient done flag
BRANCHIF $IPB_TF &P1_In20			; is transient requested?
BRANCHNE $IPB_T0 0 &P1_In10			; yes .. 1st sample?
BRANCHNE $AVGCOUNT  0 &P1_In20		; not first, is it a restart
SETREG   $P1_TRANSFIRST 0				; clear first sample flag
GOTO     &P1_In20
P1_In10: SETREG  $P1_TRANSFIRST 1		; 1st tran.  set the first flag
P1_In20: RTNQUE

; 

Phase I Flags Routine

; Flags Subroutine ...
;      Examine the IPB and set some simple testable flags to control the Phase I main

REGDEF   $P1_PARAMS P1_FLTEMP			; temp used by flag routine
P1_FlagSub:
SETREG   $P1_DOSOME 0				; clear the do something flag
BRANCHNE $IPB_SF 0 &P1_Fl10			; set histogram flag if sf,ff,or aecx
BRANCHNE $IPB_FF 0 &P1_Fl10
BRANCHIF $IPB_AECX &P1_Fl20
P1_Fl10: SETREG $P1_HISTFLAG 1
SETREG   $P1_DOSOME 1				; also set do something
GOTO     &P1_Fl40
P1_Fl20:
BRANCHNE $IPB_IMX 0 &P1_Fl30			; set imax flag if max or min set
BRANCHIF $IPB_IMN &P1_Fl40
P1_Fl30: SETREG $P1_IMAXFLAG 1
SETREG   $P1_DOSOME 1				; also set do something
P1_Fl40:
BRANCHIF $IPB_TF &P1_Fl50			; if transient requested   (Vr1.26)
REGSUB   $IPB_TAI $AVGCOUNT $P1_FLTEMP	; and the count will be up on this
BRANCHNE $P1_FLTEMP 1 &P1_Fl50			; sample                   (Vr1.26)
SETREG   $P1_TRANSFLAG 1			; set the transient 
SETREG   $P1_DOSOME 1				; and the do something flags
P1_Fl50:
REGAND   $FDB_SAFEFLAGWORD $LITERAL40 $P1_SAFECHK ; Mask all but the safety bit (Vr1.26)
P1_Fl99: RTNQUE


; Bad Pixel Subroutine
;      Correct bad pixels and columns

REGBLK  $P1_PARAMS   P1_BPTST[6]	; Test Register set for Verification
REGBLK  $P1_PARAMS   P1_BPCOR[6]	; register to both badcol and badpix
REGEQU  $P1_BPCOR    P1_BPPG		; set to the ccd page number
REGEQU  $P1_BPCOR+1  P1_BPRL		;            row length
REGEQU  $P1_BPCOR+2  P1_BPYO		;            Y offset
REGEQU  $P1_BPCOR+3  P1_BPYL		;            Y length
REGEQU  $P1_BPCOR+4  P1_BPADD	;            Badcol or badpix table
REGDEF  $P1_PARAMS   P1_BPTEMP		; temp for intermediate results

P1_BadPixSub:
NOOP		; ****** Replace with RTNQUE if there are problems

P1_BP10:
COPYREG  $IPB_BPT $P1_BPADD		; bad col tables are 4096 long
REGMULT  $P1_BPADD $LITERAL4096 $P1_BPADD	; mult by 4096
SETREG   $P1_BPADD+1 6			; set to seg 6
COPYREG  $IPB_BPYO $P1_BPYO		; transfer parameters from the cc block
COPYREG  $IPB_BPYL $P1_BPYL
COPYREG  $IPB_P1RL $P1_BPRL
COPYREG  $CCDPAGE  $P1_BPPG
BADCOL   $P1_BPCOR			; do the badcol correction
COPYRD2D $P1_BPCOR $P1_BPTST 6		; copy to temp for verification
REGAND   $IPB_BPT $LITERAL1 $P1_BPADD	 ; BP tables are 32K starting at seg 7
BRANCHIF $P1_BPADD &P1_BP20		; odds start at add 0x8000 and evens
SETREG   $P1_BPADD 0x8000		; start at add 0
P1_BP20:
COPYREG  $IPB_BPT $P1_BPADD+1		; table numbers 0 - 7 become segs 7 - A
SHIFT    $P1_BPADD+1 $P1_BPADD+1 $LITERALMINUS1 ; i.e. (tab >> 1) + 7
ADDREGD  $P1_BPADD+1 7			; bias the index by 7
BADPIX   $P1_BPCOR			; correct pixels
RTNQUE

; 

CCD Safety Check Routine

; Safety Check Routine ...                                                   (Vr1.26)
;      Creates a histogram of a full CCD image frame binned to 8x8.          (Vr1.26)
;      Tests a specific bin and if the counts in that bin exceed a threshold (Vr1.26)
;      increments the danger frame counter and clears the safe frame counter.(Vr1.26)
;      If the danger frame counter exceeds the danger counter threshold, set (Vr1.26)
;      the danger flag in the return block.  If the histogram bin does not    (Vr1.26)
;      exceed the threshold, increment the safe frame count. If the safe frame(Vr1.26)
;      count exceeds the safe frame threshold, clear danger frame counter.   (Vr1.26)

REGBLK $P1_PARAMS P1_SAFBINEXT[8]        ; for bin or extract                (Vr1.26)
REGBLK $P1_PARAMS P1_SAFHIST[6]          ; for histogram                     (Vr1.26)
REGDEF $P1_PARAMS P1_SAFCMMODE           ; camera Mode                       (Vr1.26)
REGDEF $P1_PARAMS P1_SAFTEMP             ; Temp for count threshold tests    (Vr1.26)

P1_SafetySub:                            ;                                   (Vr1.26)
SHIFT    $FDB_CMMODEWORD $P1_SAFCMMODE $LITERALMINUS13 ;                     (Vr1.26)
REGAND   $P1_SAFCMMODE $LITERAL7 $P1_SAFCMMODE     ;                         (Vr1.26)
BRANCHGT $P1_SAFCMMODE 3 &P1_Safe99 ; Works only for full camera readout     (Vr1.26)
COPYRD2D $IPB_FCO+3 $P1_SAFBINEXT 2 ; Get the full camera parameters         (Vr1.26)
COPYRD2D $IPB_FCO+5 $P1_SAFBINEXT+4 3 ;                                      (Vr1.26)
REGADD   $P1_SAFBINEXT+1 $CCDPAGE $P1_SAFBINEXT ; insert page number         (Vr1.26)
SETREGS  $P1_SAFBINEXT+2 2 7:0      ; set output to page 7                   (Vr1.26)
SETREG   $SAFE_HISTTHR+1 0          ;                                        (Vr1.26)
BRANCHNE $P1_SAFCMMODE 3 &P1_Safe20 ; if it's already 8x8 ....               (Vr1.26)
EXTRACT  $P1_SAFBINEXT              ; Extract                                (Vr1.26)
GOTO     &P1_Safe60                 ;                                        (Vr1.26)

P1_Safe20:                          ;                                        (Vr1.26)
SETREG   $P1_SAFBINEXT+7 8          ; set the bin mode                       (Vr1.26)
BRANCHIF $P1_SAFCMMODE &P1_Safe40   ;                                        (Vr1.26)
SETREG   $P1_SAFBINEXT+7 4          ;                                        (Vr1.26)
BRANCHEQ $P1_SAFCMMODE 1 &P1_Safe40 ;                                        (Vr1.26)
SETREG   $P1_SAFBINEXT+7 2          ;                                        (Vr1.26)
P1_Safe40:                          ;                                        (Vr1.26)
BINNXN   $P1_SAFBINEXT              ; bin images that are < 8x8 to 8x8       (Vr1.26)

P1_Safe60:                          ;                                        (Vr1.26)
SETREGS  $P1_SAFHIST 6 7:0 128 128 128 $P1_HISTOUT ; setup histogram         (Vr1.26)
REGMULT  $P1_SAFHIST+2 $P1_SAFHIST+3 $DPLENGTH     ; 128x128 to dplength     (Vr1.28)
HIST128  $P1_SAFHIST                               ; do the histogram        (Vr1.26)
SETREG   $P1_SAFTEMP $SAFE_1X1BIN   ; Get the right threshold                (Vr1.26)
REGADD   $P1_SAFTEMP $P1_SAFCMMODE $P1_SAFTEMP     ;                         (Vr1.26)
COPYRI2D $P1_SAFTEMP $P1_HISTBIN 1 ;                                         (Vr1.26)
CALLQUE  &P1_GetHistBinSub          ; determine if this is an s or a d       (Vr1.26)
BRANCHIF $P1_HISTBINOK &P1_Safe99   ; (this out is the bin # is bad          (Vr1.26)
SETREG   $P1_SAFTEMP $SAFE_1X1THR   ; Get the right threshold                (Vr1.26)
REGADD   $P1_SAFTEMP $P1_SAFCMMODE $P1_SAFTEMP     ;                         (Vr1.26)
COPYRI2D $P1_SAFTEMP $SAFE_HISTTHR 1 ;                                       (Vr1.26)
COMPLONG $SAFE_HISTTHR $P1_COMPTEST &P1_Safe80 &P1_Safe70 &P1_Safe70 ;       (Vr1.26)


P1_Safe70:                                                           ;       (Vr1.26)
SETREG   $SAFE_SCOUNT 0             ;   Dangerous frame... test threshold    (Vr1.26)
ADDREGD  $SAFE_DCOUNT 1             ;   clear s counts,alert CC as required  (Vr1.26)
REGSUB   $SAFE_DTHRSH $SAFE_DCOUNT $P1_SAFTEMP ;                             (Vr1.26)
BRANCHGT $P1_SAFTEMP 0 &P1_Safe99               ;                            (Vr1.26)
SETREG   $P1_RESULTS+11 1           ;                                        (Vr1.26)
THROW    0xCCD0                     ;                                        (Vr1.26) 
GOTO     &P1_Safe99                 ;                                        (Vr1.26)

P1_Safe80:                          ;  Safe frame ... test threshold and     (Vr1.26)
ADDREGD  $SAFE_SCOUNT 1             ;  Reset d counts as required            (Vr1.26)
REGSUB   $SAFE_STHRSH $SAFE_SCOUNT $P1_SAFTEMP ;                             (Vr1.26)
BRANCHGT $P1_SAFTEMP 0 &P1_Safe99               ;                            (Vr1.26)
SETREG   $SAFE_DCOUNT 0                         ;                            (Vr1.26)

P1_Safe99:                          ;                                        (Vr1.26)
RTNQUE                              ;                                        (Vr1.26)

; Histogram Subroutine ...
;      Create a histogram, test for events, and set the event flag if any have happened
;      Serious changes in VR1.20 .... Add General Purpose Routine to get the
;      histogram bin value and check the bin for 0-127.  Also, divide AEC High pixel
;      count by 8.

REGBLK  $P1_PARAMS  P1_HIST[6]		; for doing the histogram
REGBLK  $P1_PARAMS P1_COMPREF[2]
REGBLK  $P1_PARAMS P1_COMPTEST[2]
REGBLK  $P1_PARAMS P1_COMPTESTADD[2]
REGBLK  $P1_PARAMS P1_AECTEMP[2]	; for shift the high count -3 (VR1.20)
REGDEF  $P1_PARAMS P1_HISTBIN		; The histogram bin Number    (VR1.20)
REGDEF  $P1_PARAMS P1_HISTBINOK		; Set if histogram bin is okay (VR1.20)
;				*** Create the histogram ***
P1_HistSub:
SETREGS  $P1_HIST 2 7:0 		; Source data always is in Page 7
COPYRD2D $XYRLEN   $P1_HIST+2 3		; Copy in the length parameters
SETREG   $P1_HIST+5 $P1_HISTOUT		; Set the histogram address
HIST128  $P1_HIST			; do a 128 bin histogram
SETREG   $P1_EVENTFLAG 0		; clear the event flag
SETREG   $P1_FLAREVNT 0			; clear the flare event flag
;				*** Test for superflare ***
BRANCHIF $IPB_SF         &P1_Hi20	; is there a superflare request
COPYREG  $IPB_SFHB       $P1_HISTBIN    ; get the bin value
CALLQUE  $P1_GetHistBinSub
BRANCHIF $P1_HISTBINOK   $P1_Hi20       ; Make sure it's Okay
COMPLONG $IPB_SFHC $P1_COMPTEST &P1_Hi20 $P1_Hi10 &P1_Hi10
P1_Hi10:	SETREG $P1_EVENTFLAG 1
		SETREG $P1_RESULT_SF 1
		SETREG $P1_FLAREVNT 1
;				*** Test for flare ***
P1_Hi20:
BRANCHIF $IPB_FF        &P1_Hi40		; is there a flare request
COPYREG  $IPB_FHB       $P1_HISTBIN
CALLQUE  $P1_GetHistBinSub
BRANCHIF $P1_HISTBINOK   $P1_Hi40 
COMPLONG $IPB_FHC $P1_COMPTEST &P1_Hi40 $P1_Hi30 &P1_Hi30
P1_Hi30:        SETREG $P1_EVENTFLAG 1
                SETREG $P1_RESULT_FF 1
		SETREG $P1_FLAREVNT 1
;				*** Test for AEC ***
P1_Hi40:
BRANCHIF $IPB_AECX    &P1_Hi80		; is there an AEC request
;					**** Overexposure test ****
COPYREG  $IPB_AEHB    $P1_HISTBIN
CALLQUE  $P1_GetHistBinSub
BRANCHIF $P1_HISTBINOK $P1_Hi80 

;  Added code to shift the AEC High Pixel count 3 right (divide by 8)  (VR1.20)

SHIFT    $IPB_AEHC     $P1_AECTEMP   $LITERALMINUS3
REGAND   $P1_AECTEMP   $P1_AECTEMP   $LITERAL1FFF
REGAND   $IPB_AEHC+1   $P1_AECTEMP+1 7
SHIFT    $P1_AECTEMP+1 $P1_AECTEMP+1 13
REGOR    $P1_AECTEMP+1 $P1_AECTEMP   $P1_AECTEMP
SHIFT    $IPB_AEHC+1   $P1_AECTEMP+1 $LITERALMINUS3
REGAND   $P1_AECTEMP+1 $P1_AECTEMP+1 $LITERAL1FFF

COMPLONG $P1_AECTEMP   $P1_COMPTEST &P1_Hi60 &P1_Hi50 &P1_Hi50 
P1_Hi50:        SETREG $P1_EVENTFLAG 1	; Overexposure
                SETREG $P1_RESULT_AEF 0xFFFF	; Indicate exp goes down
		GOTO   $P1_Hi80		; skip the underexposure test
P1_Hi60: 				;**** Underexposure test ****
COPYREG  $IPB_AELB    $P1_HISTBIN
CALLQUE  $P1_GetHistBinSub
BRANCHIF $P1_HISTBINOK $P1_Hi80 
COMPLONG $IPB_AELC $P1_COMPTEST &P1_Hi70 $P1_Hi80 &P1_Hi80
P1_Hi70:        SETREG $P1_EVENTFLAG 1
                SETREG $P1_RESULT_AEF 1
P1_Hi80:
BRANCHNE $IPB_IMX 0 &P1_Hi90		; peek at the imx flag
BRANCHIF $P1_FLAREVNT $P1_Hi95		; Not set, was there a flare?
P1_Hi90:				; Flare or Imax requested
SETREG   $P1_RESULT_IMXV 1		; set the validity flag
COPYRD2D $P1_HIMAXLOC $P1_RESULT_IMXL 2	; and location
P1_Hi95:
BRANCHEQ $IPB_IMN 0 &P1_Hi99		; peek at the imn flag (Vr1.20)
SETREG   $P1_RESULT_IMNV 1		; Imn requested, set validity
COPYRD2D $P1_HIMINLOC $P1_RESULT_IMNL 2	; and location
P1_Hi99: RTNQUE

;
; Invert Histogram ...   Routine removed in 1.20 ... replaced with GetHistBinSub

; Get Histogram Bin Value ...                                  added (VR1.20)
; This routine retrieves the value in the designated histogram Bin
; Makes sure the histogram bin is between 0 and 127
; Doubles the bin number and adds it to histogram start address
; Retreives the value and inverts it (i.e., subtracts the count from the
; dat product length).
; 
P1_GetHistBinSub:
SETREG    $P1_HISTBINOK   0
BRANCHLT  $P1_HISTBIN     0            &P1_GetHistBin99
BRANCHGT  $P1_HISTBIN     127          &P1_GetHistBin99
SETREG    $P1_HISTBINOK   1
SETREG    $P1_COMPTESTADD $P1_HISTOUT	; set test to the histogram start add
REGADD    $P1_COMPTESTADD $P1_HISTBIN  $P1_COMPTESTADD	; and add the SF bin number
REGADD    $P1_COMPTESTADD $P1_HISTBIN  $P1_COMPTESTADD	; add again (hist is 32 bit)
COPYRI2D  $P1_COMPTESTADD $P1_COMPTEST 2
COPYRD2D  $DPLENGTH $SUB32IN 2			; Invert the histogram value
COPYRD2D  $P1_COMPTEST $SUB32IN+2 2
CALLQUE   &Sub32Sub
COPYRD2D  $SUB32OUT $P1_COMPTEST 2
P1_GetHistBin99: RTNQUE

; Transient Subroutine ...
;     Apply the transient detection algorithm and set the event flag if a transient has happened
;     Note: This routine is called only if the averaging interval is complete with this sample.

REGBLK   $P1_PARAMS P1_TRANSBUF[10]
REGEQU   $P1_TRANSBUF P1_TRANSSOURCE
REGEQU   $P1_TRANSBUF+2 P1_TRANSLENGTHS
REGEQU   $P1_TRANSBUF+5 P1_TRANSREF
REGEQU   $P1_TRANSBUF+7 P1_TRANSREG
REGEQU   $P1_TRANSBUF+8 P1_TRANSSF1
REGEQU   $P1_TRANSBUF+9 P1_TRANSSF2
REGBLK   $P1_PARAMS P1_TRANSSCALE[11]
REGBLK   $P1_PARAMS P1_TRANSMIN[6]
REGBLK   $P1_PARAMS P1_TRANSMOVE[6]
REGBLK   $P1_PARAMS P1_TRANSVLOC[3]

P1_TransSub:
COPYREG  $IPB_TAI $AVGMAX		; Set the average max 
BRANCHNE $AVGMAX 1 &P1_Tr10		; if it's just a one sample transient
SETREGS  $P1_TRANSMOVE 4 7:0 7:0x90000	; skip the sum and scale and just
COPYRD2D $DPLENGTH $P1_TRANSMOVE+4 2	; move the data
MOVSBLKI $P1_TRANSMOVE
GOTO &P1_Tr20

P1_Tr10:
CALLQUE  &SumSub			; add in this image
SETREGS  $AVGDEST 2 7:0x90000		; set dest to upper half page of 7
CALLQUE  &AvgSub			; Finalize the new average
SETREG   $AVGCOUNT  0                   ; Reset count for next pass  (Vr 1.25)

P1_Tr20:
COPYRD2D $XYRLEN $TRANSXYR 3		; save parameters for use during phase 2
COPYRD2D $DPLENGTH $TRANSDPL 2
SETREG   $TRANSDONE 1
BRANCHNE $P1_TRANSFIRST 0 &P1_Fl99		; 1st result

COPYRD2D $XYRLEN $P1_TRANSLENGTHS 3	; set the lengths
SETREGS  $P1_TRANSREG 2 $P1_TRANSCOUNT -100	; set outreg (2) and source mult (-100)
COPYREG  $IPB_TMUL $P1_TRANSSF2		; the second is from the info block      (Vr 1.23)
BRANCHIF $IPB_DT &P1_Tr30		; check for dark or bright
;			*** Dark Transient ***
SETREGS  $P1_TRANSSOURCE 2 2:0x90000	; dark is -100*old + tmul*new
SETREGS  $P1_TRANSREF    2 7:0x90000
GOTO     &P1_Tr40
P1_Tr30:	;       *** Bright Transient ***
SETREGS  $P1_TRANSSOURCE 2 7:0x90000      ; bright is -100*new + tmul*old
SETREGS  $P1_TRANSREF    2 2:0x90000
P1_Tr40: TRDETECT $P1_TRANSBUF		; test for transient
COMPLONG $IPB_TPC $P1_TRANSCOUNT &P1_Tr99 &P1_Tr50 &P1_Tr50  ;                   (Vr 1.23)
P1_Tr50: SETREG $P1_RESULT_TF 1		; set trans flag
         SETREG $P1_EVENTFLAG 1		; set event flag
; *** Transient detected ... now the fun begins ... redo the process to get the location
SETREGS  $P1_TRANSSCALE 6 2:0x90000 7:0x90000 6:0	; set up scaled sum into page 6
COPYRD2D $DPLENGTH $P1_TRANSSCALE+6 2		; page 2 must be s1 
BRANCHIF $IPB_DT &P1_Tr60			; set up dark or bright scale factors
SETREG  $P1_TRANSSCALE+9 -100
COPYREG  $IPB_TMUL $P1_TRANSSCALE+8
GOTO     &P1_Tr70
P1_Tr60:
SETREG  $P1_TRANSSCALE+8 -100
COPYREG  $IPB_TMUL $P1_TRANSSCALE+9
P1_Tr70:
SETREG   $P1_TRANSSCALE+10 13		; I think shift gets best significance
SCALESUM $P1_TRANSSCALE			; scale the data

SETREGS  $P1_TRANSMIN 2 6:0		; set up a findmin
COPYRD2D $XYRLEN $P1_TRANSMIN+2 3
SETREG   $P1_TRANSMIN+5 $P1_TRANSVLOC	; register to receive min v and loc
FINDMIN  $P1_TRANSMIN			; find the min
COPYRD2D $P1_TRANSVLOC+1 $P1_RESULT_IMXL 2	; save loc in max loc
SETREG   $P1_RESULT_IMXV 1		; declare max location valid

P1_Tr99: RTNQUE

; IMAX Subroutine ...
;     Locate the IMAX and/or IMIN in cases where it has not yet been done but is requested.
REGBLK   $P1_PARAMS P1_IMAXMIN[6]	; reg block for max/min 
REGEQU   $P1_IMAXMIN   P1_IMAXSOURCE	; equ's for readability
REGEQU   $P1_IMAXMIN+2 P1_IMAXXYR
REGEQU   $P1_IMAXMIN+5 P1_IMAXOUT

P1_ImaxSub:
SETREGS  $P1_IMAXSOURCE 2 7:0		; source has always bin binned/extract to 7
COPYRD2D $XYRLEN $P1_IMAXXYR 3		; set the length words
BRANCHIF $IPB_IMX &P1_Im10		; If max is set, 
SETREG   $P1_IMAXOUT $P1_FINDIMAX		; set register for result
FINDMAX  $P1_IMAXMIN				; do max instructio
SETREG   $P1_RESULT_IMXV 1			; set validity flag and
COPYRD2D $P1_FINDIMAXLOC $P1_RESULT_IMXL 2	; location
P1_Im10:
BRANCHIF $IPB_IMN &P1_Im99		; if min is set,
SETREG   $P1_IMAXOUT $P1_FINDIMIN		; set register for result
FINDMIN  $P1_IMAXMIN				; find min
SETREG   $P1_RESULT_IMNV 1			; set validity flag
COPYRD2D $P1_FINDIMINLOC $P1_RESULT_IMNL 2	; and location
P1_Im99: RTNQUE


;    Test mode for phase I Plases a fixed pattern in the phase I results area and returns

P1_TestMode:
SETREGS $P1_RESULTS   4 0 1 2 3 ; (3 setregs to initialize phaseI results)
SETREGS $P1_RESULTS+4 4 4 5 6 7 ; (3 setregs to initialize phaseI results)
SETREGS $P1_RESULTS+8 4 8 9 10 11 ; (3 setregs to initialize phaseI results)
RTNQUE
;
;
;  Phase II main routine
;
.RORG P2_PARAMS 0x600                           ; Register 600-7FF reserved for phase II
REGBLK $P2_PARAMS P2_OUTPARAMS[16]              ; this block contains the 16 output parameters
REGEQU $P2_OUTPARAMS+1 P2_AVGREQ		; Averaging request flag
REGEQU $P2_OUTPARAMS+3 P2_AREASTART		; Area Start Address
REGBLK $P2_PARAMS P2_MEMFILL[5]                 ; Used for memory fills 
REGDEF $P2_PARAMS P2_AVGMAX			; Number of Images to Average	
REGBLK $P2_PARAMS P2_AVGTIME0[3]		; Time of the First Sample
REGBLK $P2_PARAMS P2_TEMP[11]			; reglist for a variety of instructions
REGDEF $P2_PARAMS P2_FIELDCODE			; FC,A1, or A2 code for the output block
REGBLK $P2_PARAMS P2_DPLASTADD[2]		; last add of dp (Used to test for que full)
REGBLK $P2_PARAMS P2_DPL505[2]			; Length of DP plus header
REGDEF $P2_PARAMS P2_HSSQUESTART[2]		; Next add in output queue
REGDEF $P2_PARAMS P2_QUETIMER			; used to see if swap has timed out
REGDEF $P2_PARAMS P2_HSSTIMEOUT			; set to one if a swap times out
REGBLK $P2_PARAMS P2_MOVBLK[6]			; Used for move blocks
REGBLK $P2_PARAMS P2_TABCOPY[5]			; reglist for table copies
REGBLK $P2_PARAMS P2_JPEG[8]			; reg list for the jpeg
REGBLK $P2_PARAMS P2_SOURCEDEST[4]		; Source/Destination array
REGBLK $P2_PARAMS P2_MULT[2]			; Results of multiply when needed as a temp

DoPhase2Sub:                                    ; first main split is test vs. normal mode
SETREGS $DP_HDR 2  0x352e 0xf853		; set sync directly into the output buffer
BRANCHNE $TESTMODE 0xFFFF &P2_NormalMode
BRANCHIF $NORMALMODE &P2_TestMode
;
;
P2_NormalMode:                                  ; Normal Mode code
CALLQUE  &P2_InitSub                            ; Initialize (Place holder for now)
SETREG   $P2_FIELDCODE 0			; Set the Field Code to FC
COPYRD2D $DP_HDR+0x15E $P2_OUTPARAMS 0x10	; Copy parameters to standard area
CALLQUE  &P2_OutSub				; Call the output routine 
BRANCHIF $P2_HSSTIMEOUT &P2_FCODone		; if there's a timeout
THROW    0xF001					; throw f001 and rtn
RTNQUE

P2_FCODone:
SETREG   $P2_FIELDCODE 1			; Set the Field Code to A1
COPYRD2D $DP_HDR+0x16E $P2_OUTPARAMS 0x10	; Copy parameters to standard area
CALLQUE  &P2_OutSub				; Call the output routine
BRANCHIF $P2_HSSTIMEOUT &P2_A1Done		; If there's a timeout
THROW    0xF002					; throw f001 and rtn
RTNQUE

P2_A1Done:
SETREG   $P2_FIELDCODE 2			; Set the Field Code to A2
COPYRD2D $DP_HDR+0x17E $P2_OUTPARAMS 0x10	; Copy parameters to standard area
CALLQUE  &P2_OutSub				; Call the output routine
BRANCHIF $P2_HSSTIMEOUT &P2_A2Done		; If there's a timeout
THROW    0xF003					; throw f001 and rtn
RTNQUE
P2_A2Done:
RTNQUE

;  This section contains phase II subroutines

P2_InitSub:			; Phase II initialization routine (Place Holder)
BRANCHIF $TRANSDONE &P2_Is10	; see if transient done in phase 1
COPYRD2D $TRANSDPL $P2_MOVBLK+4	2 ; yes, move result (at 7:90000 back to Page 2)
SETREGS  $P2_MOVBLK 4 7:0x90000 2:0x90000
MOVBLKI  $P2_MOVBLK
P2_Is10:
RTNQUE

;                           This is the output management routine
P2_OutSub:

SETREG   $P2_HSSTIMEOUT 0		; Clear the Hss error flag
SETREG   $P2_SOURCEDEST+1 0		; Initialize the source and dest to 7,6
CALLQUE  &P2_SwapSub

BRANCHIF  $P2_AVGREQ &P2_Out05		; if the field is averaged
BRANCHIF  $TRANSDONE &P2_Out10		; and the average has been done
BRANCHIF  $P2_OUTPARAMS &P2_Out20	; Unless there's not ouput request..
SETREGS   $P2_MOVBLK 4  2:0x90000 7:0	; move from page 2 to 7
COPYRD2D  $TRANSDPL $P2_MOVBLK+4 2	; Fixed typo in dest address             (Vr 1.2a)
MOVBLKI   $P2_MOVBLK
COPYRD2D  $TRANSXYR $XYRLEN 3
COPYRD2D  $TRANSDPL $DPLENGTH 2
GOTO      &P2_Out30

P2_Out05:
BRANCHIF  $P2_OUTPARAMS &P2_Out20	; No avg, no out ... return
P2_Out10:
SETREG   $BINEXTADD $P2_AREASTART
CALLQUE  &BinExtSub				; first do a bin or extract

BRANCHIF $P2_AVGREQ &P2_Out30			; Is this subfield averaged
CALLQUE  &P2_AvgSub				; otherwise call the averaging routine
BRANCHIF $AVGCOUNT &P2_Out30			; is the average complete
P2_Out20:
RTNQUE			; no... return (no output yet)

;   At this point, the uncompressed data product is in page 7 at address 0
;   The Data Product header is still in registers start at 100(Hex).

P2_Out30:
BRANCHIF  $P2_OUTPARAMS &P2_Out20	; once last peek at output flag

; Added code here in Vr 1.23 to bypass output if APID is 0          (Vr 1.23)
; If the APID0_COUNT is 0, throw error A000.  Increment count in    (Vr 1.23)
; any case                                                          (Vr 1.23)

BRANCHNE $P2_OUTPARAMS+9 0 $P2_Out35      ;                         (Vr 1.23)
BRANCHNE $APID0_COUNT    0 $P2_Out32      ;                         (Vr 1.23)
THROW    0xA000                           ;                         (Vr 1.23)
P2_Out32:                                 ;                         (Vr 1,23)
ADDREGD  $APID0_COUNT    1                ;                         (Vr 1.23)
RTNQUE					  ; No output               (Vr 1.23)

P2_Out35:                                 ;                         (Vr 1.23)
SETREG   $DP_HDR+2 0				; Initialize type to Raw
BRANCHIF $P2_OUTPARAMS+10 &P2_Out40		; Is JPEG requested?
CALLQUE  &P2_JpegSub				; Yes call JPEG Routine
GOTO     &P2_Out60				; Skip Lut and Pack checks

P2_Out40:
BRANCHIF $P2_OUTPARAMS+12 &P2_Out50		; Is lookup requested
CALLQUE  &P2_LutSub				; Yes, call the LUT Routine

P2_Out50:
BRANCHIF $P2_OUTPARAMS+11 &P2_Out60		; is Packing requested?
CALLQUE  &P2_PackSub				; Yes, call the packing routine

P2_Out60:
CALLQUE  &P2_HSSInitSub				; Initialize the HSS output
BRANCHIF $P2_HSSTIMEOUT &P2_Out70		; Return if there was a timeout
RTNQUE
P2_Out70:
COPYRD2D $P2_DPL505 $DP_HDR+410	2	; Put the length in the header
COPYREG  $EXTRAWORD $DP_HDR+412	; Put in the extra word flag
COPYREG  $P2_FIELDCODE $DP_HDR+413
COPYRD2D $P2_AVGTIME0 $DP_HDR+414 2	; Put in the Time 0 Time word

SETREGS  $P2_MOVBLK 2 $DP_HDR 505
COPYRD2D $P2_HSSQUESTART $P2_MOVBLK+2 2
SAVERLSI $P2_MOVBLK

COPYRD2D $P2_SOURCEDEST $P2_MOVBLK 2	;Move the data product
COPYRD2D $DPLENGTH $P2_MOVBLK+4 2
ADDADR   $P2_MOVBLK+2 $LITERAL505L $P2_MOVBLK+2
MOVBLKI  $P2_MOVBLK

COPYREG  $P2_OUTPARAMS+9 $HSSAPID		; setup the HSS enter (APID first)
COPYRD2D $P2_HSSQUESTART $HSSADR 2		; address (From the hssaddr)
COPYRD2D $P2_DPL505 $HSSCOUNT 2			; The total length including header
COPYRD2D $DP_HDR+3 $HSSTIME 3			; the time words
CALLQUE  &HssOutSub 				; call the output subroutine
P2_Out99:
RTNQUE						; the phase 2 output phase is done

; Averaging Routine

P2_AvgSub:

BRANCHEQ $P2_OUTPARAMS+2 0  &P2_Avg10		; check for first sample
SETREG   $AVGCOUNT 0				; set the counter to 0
P2_Avg10:
BRANCHNE $AVGCOUNT 0 &P2_Avg20 
CALLQUE  &P2_AvgInitSub				; Initialize averaging
SETREGS  $P2_MOVBLK 2 7:0			; just move data to 2
SETREG   $AVGCOUNT 1				; set the counter to 0
GOTO     &P2_Avg25
P2_Avg20:
SETREGS  $P2_MOVBLK 2 6:0 			; it's not, data to page 2
CALLQUE  $SumSub				; do the Intermediate sum
P2_Avg25:
REGSUB   $P2_AVGMAX $AVGCOUNT &P2_TEMP		; see if the average is done
BRANCHIF $P2_TEMP &P2_Avg30			; see if the average is done
SETREGS  $P2_MOVBLK+2 2 2:0
COPYRD2D $DPLENGTH $P2_MOVBLK+4 2
MOVBLKI  $P2_MOVBLK
RTNQUE					; since average not ready, there's no output

P2_Avg30:
BRANCHEQ $P2_AVGMAX 1 &P2_Avg40		; guard against stupidity (Avg 1 sample)
SETREGS  $AVGDEST 2 7:0			; set destination for done routine
COPYREG  $P2_AVGMAX $AVGMAX		; set the max value for the scale factor routine
CALLQUE  &AvgSub			; finalize the average
P2_Avg40:				; reset the counter
SETREG   $AVGCOUNT 0
RTNQUE

; Jpeg Subroutine

P2_JpegSub:
REGMULT  $LITERAL544 $P2_OUTPARAMS+12 $P2_TABCOPY	; Copy tables
SETREGS  $P2_TABCOPY+1 4 3 0 2 512			; First, copy the huffman tables 
COPYTAB  $P2_TABCOPY
ADDREGD  $P2_TABCOPY 512
SETREGS  $P2_TABCOPY+1 4 3 0x200 2 16
COPYTAB  $P2_TABCOPY
ADDREGD  $P2_TABCOPY 16
SETREGS  $P2_TABCOPY+1 4 3 0x300 2 16
COPYTAB  $P2_TABCOPY

REGMULT  $LITERAL1024 $P2_OUTPARAMS+11 $P2_TABCOPY	; Then copy the qualtization table
;           Subtract 1 removed in vr 1.1A
REGAND   $P2_OUTPARAMS+13 $LITERALF $P2_MULT
REGMULT  $P2_MULT $LITERAL64 $P2_MULT
REGADD   $P2_MULT $P2_TABCOPY $P2_TABCOPY
SETREGS  $P2_TABCOPY+1 4 4 0x400 2 64
COPYTAB  $P2_TABCOPY
COPYRD2D $P2_SOURCEDEST $P2_JPEG 4			; setup the jpeg instruction
COPYRD2D $XYRLEN $P2_JPEG+4 3
SETREG   $P2_JPEG+7 0x4000			; initalize quality to unity
P2_Jpeg90:
JPEGCOMP $P2_JPEG					; do the jpeg
COPYRD2D R64 $DPLENGTH 2				; transfer the length to the normal place
CALLQUE  &P2_SwapSub					; swap source and dest
SETREG   $DP_HDR+2 1					; Set data type to jpeg
RTNQUE

;  Lut Subroutine

P2_LutSub:
REGMULT  $LITERAL4096 $P2_OUTPARAMS+12 $P2_TABCOPY	; copy Lut to bottom of seg 5
SETREGS  $P2_TABCOPY+1 4 5 0 5 4096			; (all lut's are 4096)
COPYTAB  $P2_TABCOPY
COPYRD2D $P2_SOURCEDEST $P2_TEMP 4			; set up the lookup instruction
COPYRD2D $DPLENGTH $P2_TEMP+4 2
SETREGS  $P2_TEMP+6 2 0 5
LOOKUP   $P2_TEMP					; do the lookup
CALLQUE  &P2_SwapSub					; swap source and dest
RTNQUE

;  Pack Subroutine -   PlaceHolder for now
P2_PackSub:
COPYRD2D $P2_SOURCEDEST $P2_TEMP 4			; Get the source and dest addresses
COPYRD2D $XYRLEN $P2_TEMP+4 3				; Set up packls instruction
COPYREG  $P2_OUTPARAMS+11 $P2_TEMP+7
PACKLS   $P2_TEMP					; do the pack
CALLQUE  &P2_SwapSub					; Swap source and dest
COPYRD2D R66 $DPLENGTH 2				; copy pack length to the normal place
COPYREG  $P2_OUTPARAMS+11 $DP_HDR+2			; set the type to the pack size
RTNQUE

; HSS Initialization Routine

P2_HSSInitSub:
HSSADDR  $P2_HSSQUESTART			; Get the HSS Address
ADDADR   $DPLENGTH $LITERAL505L $P2_DPL505 	; generate total length
COPYRD2D $P2_DPL505 $HSSLEN 2
CALLQUE  $HssExtraSub				; add extraword as needed
BRANCHIF $EXTRAWORD $P2_HSSInit10
ADDADR   $EXTRAWORD $P2_DPL505 $P2_DPL505
ADDADR   $EXTRAWORD $DPLENGTH $DPLENGTH
P2_HSSInit10:
ADDADR   $P2_DPL505 $P2_HSSQUESTART $P2_DPLASTADD	; add the length to the hss address
REGAND   $P2_DPLASTADD+1 $LITERAL7FF $P2_DPLASTADD+1	; and see if it overflows a page
BRANCHLT $P2_DPLASTADD+1 0x12  &P2_HssInit20	; There's room, move ahead

SETREG   $P2_QUETIMER 22000		;*** NOT ENOUGH QUE SPACE
P2_QueSwap:				; Retry swap for 22 seconds
HSSSWAP  &P2_HSSInit15 &P2_QueBusy	; If que is busy all that time,
P2_QueBusy:
ADDREGD  $P2_QUETIMER -1
BRANCHIF $P2_QUETIMER &P2_QueTimeOut
WAIT     1000
GOTO     $P2_QueSwap
P2_QueTimeOut:
SETREG   $P2_HSSTIMEOUT 1		; Return an error
RTNQUE
P2_HSSInit15:
HSSADDR  $P2_HSSQUESTART		; Queue was busy, get new address
P2_HssInit20:
RTNQUE


;  P2_AvgInitSub -
;  This Phase II routine initializes various parameters 

P2_AvgInitSub:
COPYREG  $P2_OUTPARAMS+1 $P2_AVGMAX		; Init the total expected for the average
BRANCHLT $P2_AVGMAX 17 &P2_AvgI10		; Force a legal value
SETREG   $P2_AVGMAX 16
P2_AvgI10:
BRANCHGT $P2_AVGMAX 0 &P2_AvgI20
SETREG   $P2_AVGMAX 1
P2_AvgI20:
COPYRD2D $DP_HDR+3 $P2_AVGTIME0 3		; save the time words
RTNQUE


; P2_SwapSub -
;            Little routine for swapping source and dest between pg 6 and 7

P2_SwapSub:
BRANCHNE  $P2_SOURCEDEST+1 0x3800 &P2_Swap7
SETREGS   $P2_SOURCEDEST 4 6:0 7:0
RTNQUE
P2_Swap7:
SETREGS   $P2_SOURCEDEST 4 7:0 6:0
RTNQUE

;  This is the TESTMODE Phase II Routine.
;  This is the mode simple mind program that output a full camera image from the current CCD page.
;  It tests for nothing.

;  Registers from 340 - 3FF are reserved for Phase II test mode
;  NOTE:  Revised slightly in VR 1.1C to use the generalized output utility to
;         get the timewords swapped.

.RORG P2_TESTMODEREG 0x340
REGBLK $P2_TESTMODEREG P2T_HDR[6]	; for moving the header register to page 7
REGBLK $P2_TESTMODEREG P2T_IMG[8]	; for moving the image data and doing an addadr
REGBLK $P2_TESTMODEREG P2T_HSS[8]	; for queing the HSS Data

P2_TestMode:
SETREG $DP_HDR+2 0xffff			; set type to test mode image
SETREGS $DP_HDR+410 4 0x106785L 0 0	;( set the word count for the output)
HSSADDR $P2T_HDR+2			; first get the HSS Queue address

SAVERLST $DP_HDR 505 7:0x0000		; save 505 words starting a r100

SETREGS $P2T_HDR 2 7:0x00000		; Set up Source and the count
SETREGS $P2T_HDR+4 2 505L 
MOVBLKI $P2T_HDR			; Do the Move

SETREGS $P2T_IMG+4 4 0x10658CL 505L  ; setup image move length and prep an address add

ADDADR $P2T_HDR+2 $P2T_IMG+6 $P2T_IMG+2   ; Add 505 to the hss addr and put in dest of image move

SETREG $P2T_IMG 0
COPYREG $CCDPAGE $P2T_IMG+1

; at P2T_IMG is the image address, the hssaddress + 1f9 (505), and the image data length (658C,10)

MOVBLKI $P2T_IMG                     ; move the image data

SETREG $HSSAPID 0x3c                ; set the appid to 60
COPYRD2D $P2T_HDR+2 $HSSADR 2    ; get the HSS address for where it was used to copy the header
ADDADR $P2T_IMG+4 $P2T_IMG+6 $HSSCOUNT  ; add 505 to image length to account for DP Header
COPYRD2D $DP_HDR+3 $HSSTIME 3          ; finally get the time word
CALLQUE  &HssOutSub
DONE:
RTNQUE

;********************************* Phase 1-2 common routines **********

; BinExt Subroutine
;     Called with the adress of a bin/extract parameter in BINEXTADD
;     Extracts or bins into page 7
;     Returns length of data product in DPLENGTH
;             X,Y, and Row Length in XYRLEN

REGDEF  $P1_P2  BINSHIFT			; for computing the output sizes
REGBLK  $P1_P2  BINEXTPARAMS[6]			; for the input parameters
REGBLK  $P1_P2  BINEXT[8]			; for the bin or extract instruction

BinExtSub:
COPYRI2D $BINEXTADD $BINEXTPARAMS 6			; copy the parameters
COPYRD2D $BINEXTPARAMS $BINEXT 2		; Initialize parameters for extract or Bin
REGADD   $BINEXT+1 $CCDPAGE $BINEXT+1	; use the actual page as determined by the DHC
SETREGS  $BINEXT+2 2 7:0 			; temp output goes to page 7
COPYRD2D $BINEXTPARAMS+2 $BINEXT+4 4		; x,y,row, and bin factor

BRANCHIF $BINEXTPARAMS+5 &BinExt_20		; See if it's a bin or an extract
BINNXN   $BINEXT				;   Binning.... do it, then
SETREG   $BINSHIFT -1				; Change binning numbers (2,4,8)
BRANCHEQ $BINEXTPARAMS+5 2 &BinExt_10		; to shift counts (-1,-2,-3)
ADDREGD  $BINSHIFT -1
BRANCHEQ $BINEXTPARAMS+5 4 &BinExt_10
ADDREGD  $BINSHIFT -1
BinExt_10:
SHIFT    $BINEXT+4 $BINEXT+4 $BINSHIFT	;adjust the row and column
SHIFT    $BINEXT+5 $BINEXT+5 $BINSHIFT	;sizes by the binning factor
GOTO     &BinExt_30

BinExt_20:
EXTRACT  $BINEXT				; Extract the selected field

BinExt_30:
REGMULT  $BINEXT+4 $BINEXT+5 $DPLENGTH	; set the length to col times rows
COPYRD2D $BINEXT+4 $XYRLEN 2		; Copy the x and y lengths
COPYREG  $BINEXT+4 $XYRLEN+2		; Set row length to x length
RTNQUE

; InitLiterals Routine
; This routines sets up literals.  Through this is called only once from phase 1, it is considered a phase 1-2 routine
; because the literals are used in both phases.
;					Changed literal block to 24 in Vr1.20
REGBLK   $P1_P2 LITERALS[24]		; block for 24 literals (Equ's follow for readability)
REGEQU $LITERALS LITERAL6
REGEQU $LITERALS+1 LITERAL1
REGEQU $LITERALS+2 LITERAL7FF
REGEQU $LITERALS+3 LITERALx12
REGEQU $LITERALS+4 LITERAL505L		; Long word 505 so takes up this word and next
REGEQU $LITERALS+6 LITERAL4096
REGEQU $LITERALS+7 LITERAL1024
REGEQU $LITERALS+8 LITERAL64
REGEQU $LITERALS+9 LITERAL10
REGEQU $LITERALS+10 LITERAL544		; this obscure number is to access huffman tables
REGEQU $LITERALS+11 LITERALF
REGEQU $LITERALS+12 LITERALMINUS1
REGEQU $LITERALS+13 LITERALMINUS3	; Added 4 literals in VR1.20
REGEQU $LITERALS+14 LITERAL13
REGEQU $LITERALS+15 LITERAL1FFF
REGEQU $LITERALS+16 LITERAL7
REGEQU $LITERALS+17 LITERAL40           ; Safety check bit mask                      (Vr1.26)
REGEQU $LITERALS+18 LITERALMINUS13      ; camera mode mask for safety check          (Vr1.26)

InitLiteralSub:
SETREGS $LITERALS    8 		6    1     0x7FF    0x12     505     0      4096    1024
SETREGS $LITERALS+8  8     	64   10    544      0xF      0xFFFF  -3     13      0x1FFF ; (Vr1.26)
SETREGS $LITERALS+16 8          7    0x40  -13      0        0       0      0       0      ; (Vr1.26)
RTNQUE

;  SumSub -
;  This routine adds page 2 to page 7 and leaves result in page 6.  Number of
;  words is in DPLENGTH.  Done using scalesum with unity multipliers and no shift.
;  The summing is an intermediate result of the averaging process.

REGBLK   $P1_P2 AVGTEMP[11]
REGEQU   $AVGTEMP AVGSOURCE
REGEQU   $AVGTEMP+2 AVGDEST
REGEQU   $AVGTEMP+6 AVGSCALESHIFT

SumSub:
SETREGS  $AVGTEMP 11 2:0 7:0 6:0 0 0 1 1 0x10	; setup a unity scalesum
COPYRD2D $DPLENGTH $AVGTEMP+6 2		; Copy length to scalesum instruction 
SCALESUM $AVGTEMP				; do the scalesum
ADDREGD  $AVGCOUNT 1
RTNQUE

;  AvgSub -
;  This routine finalizes the averaging process by doing a uscale into the caller
;  specified destination.  Call set AVGMAX to the sample count and AVGDEST to the
;  destination page and address.  Source must be page 6:address 0.

REGDEF  $P1_P2 AVGMAX			; Caller puts averaging maximum here

AvgSub:
SETREGS  $AVGSOURCE 2 6:0			; Set source and Length
COPYRD2D $DPLENGTH  $AVGTEMP+4 2
CALLQUE  $AvgSetScaleSub		; set scale and shift
USCALE   $AVGTEMP			; do the USCALE
RTNQUE

;  AvgSetScaleSub -
;  This routine sets scalefactors for averaging.
;
;  Method ...  
;  The input data is the sum of 1 to 16 images.  The USCALE instruction then shifts the result
;  right 1 place then mulitplier by a scale factor then shift the result of the multiple.  This 
;  uses the number of images in the sum to generate a branch address, i.e., a computed goto.  Each
;  GOTO branch set the pair of registers labeled AVGSCALESHIFT to a shift count and mulitplier
;  that will return the summed data to 12 bit resolution.  If you are reviewing this routine, remember
;  that USCALE first shifts right 1, then mulitplies, and finally shift the result 16-shift count
;  places right.  All shift counts, except those for integer powers of 2 are 1, i.e., 15 bit right
;  shift.  The multiplier was determined by by rounding 65536/Nimages.  The results are within
;  1 of the result of a true integer divide.


REGDEF  $P1_P2 SCALEBRANCH[2]		; Temp for address computation

AvgSetScaleSub:
BRANCHLT $AVGMAX 17 &AvgScale10		; Screen the count value
SETREG  $AVGMAX 16
AvgScale10:
BRANCHGT $AVGMAX 0 &AvgScale20
SETREG  $AVGMAX 1
AvgScale20:
REGMULT $LITERAL6 $AVGMAX $SCALEBRANCH	; a set regs and rtn require 6 words, so mulitply the
ADDREGD $SCALEBRANCH &AvgScale30	; number in the sum by six, add the address of the
REGSUB  $SCALEBRANCH $LITERAL6 $SCALEBRANCH	; 1st branch, and subtract (since there's no 0)
GOTOREG $SCALEBRANCH			; goto the right address.
AvgScale30:
SETREGS $AVGSCALESHIFT 2 2 16		; 1 sample
RTNQUE
SETREGS $AVGSCALESHIFT 2 1 16		; 2 samples
RTNQUE
SETREGS $AVGSCALESHIFT 2 21845 1 	; 3
RTNQUE
SETREGS $AVGSCALESHIFT 2 1 15		; 4
RTNQUE
SETREGS $AVGSCALESHIFT 2 13107 1	; 5
RTNQUE
SETREGS $AVGSCALESHIFT 2 10923 1	; 6
RTNQUE
SETREGS $AVGSCALESHIFT 2 9362 1		; 7
RTNQUE
SETREGS $AVGSCALESHIFT 2 1 14		; 8
RTNQUE
SETREGS $AVGSCALESHIFT 2  7282 1	; 9
RTNQUE
SETREGS $AVGSCALESHIFT 2 6554 1		; 10
RTNQUE
SETREGS $AVGSCALESHIFT 2 5958 1		; 11
RTNQUE
SETREGS $AVGSCALESHIFT 2 5461 1		; 12
RTNQUE
SETREGS $AVGSCALESHIFT 2 5041 1		; 13
RTNQUE
SETREGS $AVGSCALESHIFT 2 4681 1		; 14
RTNQUE
SETREGS $AVGSCALESHIFT 2 4369 1		; 15
RTNQUE
SETREGS $AVGSCALESHIFT 2 1 13		; 16
RTNQUE

; **********************************  Jitter Mode ******************************************

;  Jitter mode program.
;  The CC sends 1 seconds worth of jitter data starting at address 2000 (hex) in the
;  Data transfer buffer.  The data length is in (DTB copy of) Regisiter 50 (hex)
;  This program blocks up 64 samples of this data and outputs the block using apid 48 (hex)
;
;  The output format is  FRAMESYNC DATATYPE SAMPLECOUNT WORDCOUNT DATASAMPLES
;  FRAMESYNC		2 words containing 352E F853
;  DATATYPE		1 word  containing FFF0
;  SAMPLECOUNT		1 word containing the number of samples in this block
;			(should be 64)
;  WORDCOUNT		2 words containing the number of additional words in the block
;			i.e., total length not counting the first 6 words.
;  DATASAMPLES		Up to 64 data samples in the form:
;			SAMPLESYNC LENGTH SAMPLEDATA
;  SAMPLESYNC		2 words containing F0F0 E0E0
;  LENGTH		1 word containg the number of remaining words in the sample
;  SAMPLEDATA		a 1 seconds jitter mode data sample as defined in 
;			TRACE FLIGHT SOFTWARE GUIDE TELESCOPE & IMAGE STABLIZATION
;			REQUIREMENTS  (TRA-231002)
; The time word passed to the HSSENTER and thus the time word on all packets in the block
; is the time of the first sample.  There is no special checking of the output process, i.e., 
; once the output is entered, the program swaps the queue and takes no action if the swap
; does not occur.

.RORG    JM_CCINFO 0x50			; the cc sends the length to reg 50
REGBLK   $JM_CCINFO JM_INFOBLK[16]
REGEQU   $JM_INFOBLK JM_SAMPLEN

.RORG    JM_DATA   0x2000		; the data is at DTB 2000 (hex)
REGBLK   $JM_DATA  JM_SAMPLE[2000]	; Leave space for up to 2000 (dec) words
REGEQU   $JM_SAMPLE+1 JM_SAMPLETIME 	; The time is in words 1-3
REGEQU   $JM_SAMPLE+4 JM_SAMPLENUMBER	; the sample number is in word 4

.RORG    JM_REGS   0x900		; jitter mode working registers
REGBLK   $JM_REGS JM_FRAMESTART[3]	; 3 words for the frame sync and type
REGBLK   $JM_REGS JM_SAMPLESTART[3]	; 3 words for sample start and length
REGBLK   $JM_REGS JM_TOTALS[3]		; this counts samples and length
REGEQU   $JM_TOTALS JM_TOTALSAMP		; this counts samples
REGEQU   $JM_TOTALS+1 JM_TOTALLENGTH	; total length accumulated here
REGBLK   $JM_REGS JM_OUTPUT[9]		; used for movblk and hss enter
REGBLK   $JM_REGS JM_COPYSAMP[4]	; used to copy the sample (reg to mem)
REGBLK   $JM_REGS JM_SAMPLEN32[2]	; 32 bit version of the length
REGBLK   $JM_REGS JM_LITERALS[10]	; 10 jitter mode literals
REGEQU   $JM_LITERALS JM_LITERAL3L	; used to add 3 to addresses and lengths
REGEQU   $JM_LITERALS+2 JM_LITERAL6L	; added to total length for the hssenter
REGEQU   $JM_LITERALS+4 JM_LITERAL3F	; used to test for the 64th sample
REGDEF   $JM_REGS JM_RESTART		; indicates restart at the next sample
REGDEF   $JM_REGS JM_TEMP		; used for output test

.ORG  0x1000 2

;  Jitter mode starts at 0x1000 got this address must be laoded into que vecotr 2
JITTER_MODE:
DTBIN   $JM_INFOBLK 16	; get 16 words from cc (really only 1 is used)
DTBIN   $JM_SAMPLE 2000			; get the data block

BRANCHIF $JM_SAMPLENUMBER &Jm_10	; if this is the first JM sample
BRANCHIF $JM_RESTART &Jm_15		;  or if this is a restart
Jm_10:
SETREGS  $JM_FRAMESTART 3 0x352E 0xF853 0xFFF0	;setup frame sync
SAVERLST $JM_FRAMESTART 3 7:0			; in page 7
SETREGS  $JM_SAMPLESTART 2 0xF0F0 0xE0E0	; init the sample sync
SETREGS  $JM_LITERALS 5 3 0 6 0 0x3F		; init Literals
SETREG   $JM_RESTART 1				; set the restart flag

SETREG   $JM_RESTART 0				; clear the restart flag
SETREGS  $JM_OUTPUT 9 0 0 0 0 0 0 0 0 0		; init the output block
SETREGS   $JM_TOTALS 3 0 0 0			; init the sample counter
SETREGS  $JM_SAMPLEN32 2 0 0			; init the length counter
SETREGS  $JM_COPYSAMP 4 0x2000 0 7:6		; init the buffer pointer
COPYRD2D $JM_SAMPLETIME $HSSTIME 3		; Save the timewords
Jm_15:
SETREGS  $JM_COPYSAMP 2 $JM_SAMPLESTART 3	; Copy sample sync and length
COPYREG  $JM_SAMPLEN $JM_SAMPLESTART+2		; to memory
SAVERLSI $JM_COPYSAMP
ADDADR   $JM_LITERAL3L $JM_COPYSAMP+2 $JM_COPYSAMP+2	; add 3 to the pointer
SETREG   $JM_COPYSAMP 0x2000			; set up data copy
COPYREG  $JM_SAMPLEN $JM_COPYSAMP+1
SAVERLSI $JM_COPYSAMP				; copy the new data block
COPYREG  $JM_SAMPLEN $JM_SAMPLEN32			; add sample length
ADDADR   $JM_SAMPLEN32 $JM_COPYSAMP+2 $JM_COPYSAMP+2 	;to buffer pointer
ADDREGD  $JM_TOTALSAMP 1					; increment the sample count
ADDADR   $JM_SAMPLEN32 $JM_TOTALLENGTH $JM_TOTALLENGTH	; add sample length plus
ADDADR   $JM_LITERAL3L $JM_TOTALLENGTH $JM_TOTALLENGTH	; 3 to total length

REGAND   $JM_LITERAL3F $JM_SAMPLENUMBER $JM_TEMP	; do the output if
BRANCHEQ $JM_TEMP 0x3F &Jm_20		; the low 6 bits of sample number
BRANCHGT $JM_TOTALSAMP 63 &Jm_20		; are all 1's or this is the 64th sample
ENDMAC					; if not, ENDOFMACRO

Jm_20:
SETREG   $JM_RESTART 1			; set the restart flag
ADDADR   $JM_TOTALLENGTH $JM_LITERAL6L $HSSLEN ; add the 6 for the hdr
CALLQUE  &HssExtraSub			; see if extra word is needed
ADDADR   $EXTRAWORD $JM_TOTALLENGTH $JM_TOTALLENGTH
SAVERLST $JM_TOTALS 3 7:3		; save sample count and length
ADDADR   $JM_TOTALLENGTH $JM_LITERAL6L $JM_TOTALLENGTH ; set the length
COPYRD2D $JM_TOTALLENGTH $JM_OUTPUT+4 2
COPYRD2D $JM_TOTALLENGTH $HSSCOUNT 2

HSSADDR  $HSSADR			; get the output queue address
COPYRD2D $HSSENTERBLK+1 $JM_OUTPUT+2 2
SETREGS  $JM_OUTPUT 2 7:0
MOVBLKI  $JM_OUTPUT			; move the data to the output queue

SETREG   $HSSAPID 0x3C 			 ; 3c for now  ; the apid is 48 (72 decimal)
CALLQUE  &HssOutSub			; call the output subroutine
Jm_99:   ENDMAC				; ENDOFMACRO

;*********************** DHC MEMORY DUMP *****************

; Memory Dump Program
; This program dumps data from a memory page to the high speed serial (HSS) output.  It
; is invoked by interrupt vector 3.  Upon call, Register 50,51 contain a main memory
; address (page and offset), registers 52,53 contain the number of words.  The word order
; is the usual low,high.  The program issues an int 3 to the CC in order to get timewords
; to label the packets.  It then transfer the data to the HSS by the normal sequence 
; HSSENTER... HSSSWAP.

;  The output format is  FRAMESYNC DATATYPE ADDRESS WORDCOUNT DATA
;  FRAMESYNC            2 words containing 352E F853
;  DATATYPE             1 word  containing FFF2
;  ADDRESS       	2 words containing the starting address
;  WORDCOUNT            2 words containing the number of words of dump data
;
;  Note: the dump may contain one more word than the request if the requested data length
;        does not satisfy the criterion that packets always end on a double word boundary.

.RORG    DMP_IN 0x50			; dump parametrs arrive here
REGBLK   $DMP_IN DMP_INADD[2]		; The input address
REGBLK   $DMP_IN DMP_INCOUNT[2]		; The input word count
.RORG    DMP_PARAMS 0x980		; DUMP Program paramters area
REGBLK   $DMP_PARAMS DMP_HEADER[7]	; 7 header words
REGEQU   $DMP_HEADER DMP_FRAMESTART	; equates for readability
REGEQU   $DMP_HEADER+3 DMP_OUTADD
REGEQU   $DMP_HEADER+5 DMP_OUTCOUNT
REGBLK   $DMP_PARAMS DMP_MOVBLK[6]	; for move regs and data to hss queue
REGBLK   $DMP_PARAMS DMP_LITERAL7L[2]	; the length of the header

.ORG     0x1100 3

DumpMem:
SETREG   $DMP_FRAMESTART+2 0xFFF2
CALLQUE  &DumpSub
ENDMAC

;
; The Dump Subroutine does all the word.  Caller sets framestart+2 to the dumpid
; id's are:  fff2 for memory and FFF6 for DTB and FFF4 for register.
;
DumpSub:
SETREGS  $DMP_LITERAL7L 2 7 0		; long word 7
SETREG   $LOBTADD $HSSTIME		; timewords go directly to hssenter block
CALLQUE  &Int3Sub			; get the timewords
COPYRD2D $DMP_INCOUNT $HSSLEN 2		; determine if an extra word is needed
ADDADR   $HSSLEN $DMP_LITERAL7L $HSSLEN	;account for header
CALLQUE  &HssExtraSub			; the sub does it
COPYRD2D $DMP_INADD $DMP_OUTADD 4	; copy input address and count to header
ADDADR   $DMP_OUTCOUNT $EXTRAWORD $DMP_OUTCOUNT	; add extra word flag as needed
SETREGS  $DMP_FRAMESTART 2 0x352E 0xF853 	; setup sync and type
HSSADDR  $HSSADR				; get the hss address
COPYRD2D $HSSADR $DMP_MOVBLK+2 2		; setup to move header for
SETREGS  $DMP_MOVBLK 2 $DMP_FRAMESTART 7		; register space directly to hss
SAVERLSI $DMP_MOVBLK				; done
ADDADR   $HSSADR $DMP_LITERAL7L $DMP_MOVBLK+2	; add header length to hss address
COPYRD2D $DMP_INADD $DMP_MOVBLK	 2		; setup data move
COPYRD2D $DMP_OUTCOUNT $DMP_MOVBLK+4 2
MOVBLKI   $DMP_MOVBLK				; move directly to hss area

SETREG   $HSSAPID 0x3C 		; for now  0x49 eventuaslly dumps go out under 73 (dec)
ADDADR   $DMP_OUTCOUNT $DMP_LITERAL7L $HSSCOUNT	; add header length to outcount
CALLQUE  &HssOutSub
Dm_99:   RTNQUE					; ENDOFMACRO

; ********************* Catch-up Program ***************
;
; This tiny program forces an HSS buffer swap.  To be used if the image(s) currently
; queued must be sent out now.
;
.ORG     0x1200 4
HssOutProg:
HSSSWAP  &Hso_10 &Hso_10
Hso_10:  ENDMAC


; ********************** Initialization Program **********
;
; This program does an HSSADDR and a swap, which are needed to initialize the
; DHC output queing.  Also initializes CC copy of queu version and patch by
; invoking an interrupt 3
;
.RORG    INIT_PARAMS 0x9C0
REGBLK   $INIT_PARAMS INIT_TW[3]
.ORG     0x1300 5
InitProg:
CALLQUE  &InitLiteralSub
SETREG   $LOBTADD $INIT_TW
CALLQUE  &Int3Sub
ENDMAC

; ********************** DTB Dump Program **********
;
; This program dumps 8192 words from the DTB starting at address 2000 .  The
; length of the dump is specified in regsiter is always 8191.
; **** What I do for now is copy the data to the upper area of page 7, set
; up 50-53 for a dump and go to the dump program.

.RORG    DTBD_DATA 0x2000
REGBLK   $DTBD_DATA DTBD_SAMPLE[8192]
.RORG    DTBD_PARAMS 0x9D0
REGBLK   $DTBD_PARAMS DTBD_SYNC[3]
.ORG     0x1400 6
DtbdProg:
DTBIN    $DTBD_SAMPLE 0x1FFF
SAVERLST $DTBD_SAMPLE 0x2000 3 0x3811
SETREGS  $DTBD_SYNC 0xFFF6 0x2000 0x1FFF
SAVERLST $DTBD_SYNC 3 0 0x3811
SETREG   $DMP_FRAMESTART+2 0xFFF6
SETREGS  0x50 4 0 0x3811 8195 0
CALLQUE  &DumpSub

ENDMAC

; ********************** Register Dump Program **********
;
; This program dumps registers.  Start register and number of registers
; are in registers 91 and 92 (hex). This program also uses 90, 93 and 94.
; A sync word (FFF4), the start register, count, and the requested 
; registers are transferred to the upper part of page 7.  Then the general
; purpose dump subroutine is called to do the output.

.RORG    REGD_INPUT 0x90
REGBLK   $REGD_INPUT REGD_CALL[5]
.RORG    REGD_PARAMS 0x9E0
REGBLK   $REGD_PARAMS REGD_SYNC[3]
.ORG     0x1500 7
RegProg:
SETREGS  $REGD_CALL+3 2 3 0x3811
SAVERLSI $REGD_CALL+1
SETREG   $REGD_CALL 0xFFF4
SAVERLST $REGD_CALL 3 0 0x3811
SETREG   $DMP_FRAMESTART+2 0xFFF4
SETREGS  0x50 4 0 0x3811 8195 0
COPYREG  $REGD_CALL+2 0X52
ADDREGD  0x52 3

CALLQUE  &DumpSub
ENDMAC

; ********************** ErrorLog Dump Program **********
;
; Copies the error log and dumps it.
; A sync word (FFF8), constant (3811) , count, and the error log 
; are transferred to the upper part of page 7.  Then the general
; purpose dump subroutine is called to do the output.  This is all
; new in version 1.27.  This uses the memory dump registers (50-53)


.ORG     0x1600 8
RegProg:                         ;                           (Vr1.27)
SETREGS  $DMP_INADD 2 3 0x3811   ; Set up errlog call        (Vr1.27)
COPYELOG $DMP_INADD              ;                           (Vr1.27)
SETREG   $DMP_INADD 0xFFF8       ; Set sync word in Page 7   (Vr1.27)
SAVERLST $DMP_INADD 3 0 0x3811   ; sync,3811, count to p7    (Vr1.27)
SETREG   $DMP_FRAMESTART+2 0xFFF8 ; sync mark for dumpsub    (Vr1.27)
SETREG   $DMP_INADD 0            ; 0 to low address          (Vr1.27)
SETREG   $DMP_INADD+3 0          ; 0 to high count           (Vr1.27)
ADDREGD  $DMP_INADD+2 3          ; count the 3 xtra wrds     (Vr1.27)
CALLQUE  &DumpSub                ;                           (Vr1.27)
ENDMAC                           ;                           (Vr1.27)

; ********************** General Utilities for all Programs
.RORG    UTIL 0x1800			; register space at 1800

.ORG     0x1E00

; HssExtraSub -
; This routine determines if an extra word is needed for an HSS data product
; Caller sets HSSLEN (2 words) to the desired length
; Routines sets the double word, extra word to 0,0 (extra not needed)
;                                           or 1,0 (extra word needed)
; The double word allows the caller to do an addadr with the result

REGBLK   $UTIL  HSSLEN[2]
REGBLK   $UTIL  EXTRAWORD[2]

HssExtraSub:
HSSMOD   $HSSLEN $EXTRAWORD			; get len mod 505
BRANCHIF $EXTRAWORD &Hse_20			; 0 is okay
BRANCHGT $EXTRAWORD 0 &Hse_10			; if negative
ADDREGD  $EXTRAWORD 505				; make if positive
Hse_10:
REGAND   $EXTRAWORD $LITERAL1 $EXTRAWORD	; as are all odd numbers
REGXOR   $EXTRAWORD $LITERAL1 $EXTRAWORD	; evens require extra word
Hse_20:  SETREG $EXTRAWORD+1 0		; make sure MSW is 0
RTNQUE

; Sub32Sub -
; This routine performs a 32 bit subraction.  The caller places the minuend and
; subtrahend in SUB32IN. The routine places the result in SUB32OUT.
; .... that is  SUB32OUT = SUB32IN - SUB32IN+2.  32 bit arguments are in the usual
; dhc order: low, high.

REGBLK   $UTIL SUB32IN[4]		; source input buffer
REGEQU   $SUB32IN SUB32MIN		; minuend
REGEQU   $SUB32IN+2 SUB32SUBT		; subtrahend
REGBLK   $UTIL SUB32OUT[2]		; result
REGBLK   $UTIL SUB32TEMP[5]		; temps for 32 bit compare and borrow
REGEQU   $SUB32TEMP+4  SUB32BORROW	; equate for the borrow flag

Sub32Sub:
SETREGS  $SUB32TEMP 5 0 0 0 0 0		; initialize registers
COPYREG  $SUB32IN $SUB32TEMP		; do 32 compare of lower 16 to
COPYREG  $SUB32IN+2 $SUB32TEMP+2	; determine id borrow required
COMPLONG $SUB32TEMP $SUB32TEMP+2 &Sub32_20 &Sub32_20 &Sub32_10
Sub32_10:
SETREG   $SUB32BORROW 1			; need a borrow
Sub32_20:
REGSUB   $SUB32IN   $SUB32IN+2 $SUB32OUT	; subtract low then high
REGSUB   $SUB32IN+1 $SUB32IN+3 $SUB32OUT+1
REGSUB   $SUB32OUT+1 $SUB32BORROW $SUB32OUT+1	; borrow as needed
RTNQUE

; HssOutSub-
; This routine handles the final stages of an output. Does and
; HSSENTER and and HSSSWAP.  (For VR 1.1F-1.20 timeword was swapped
; here.  From VR1.21 on, caller must pass in correct timewords).
; Caller must place hssenter parameters in HSSENTERB


REGBLK   $UTIL HSSENTERBLK[8]		; Caller builds the call here
REGEQU   $HSSENTERBLK HSSAPID		; Equivalences for readability
REGEQU   $HSSENTERBLK+1 HSSADR
REGEQU   $HSSENTERBLK+3 HSSCOUNT
REGEQU   $HSSENTERBLK+5 HSSTIME

HssOutSub:
HSSENTER $HSSENTERBLK
HSSSWAP  &HssOut99 &HssOut99
HssOut99:
RTNQUE

; Int3Sub -
; This routine handles the interrupt 3 processing.  It executes a DTBOUT of
; REG 70-7F. Does an Int3 and transfers the (3) timewords to the callers location
; which is specified in LOBTADD.
; Added timewords swap in version 1.21

.RORG    INT3_IN 0x60			; where the cc puts lobt
REGBLK   $INT3_IN INT3_LOBT[3]
.RORG    INT3_OUT 0x70			; DHC-CC communications area
REGBLK   $INT3_OUT INT3_OUTPUTBLOCK[16]
REGEQU   $INT3_OUTPUTBLOCK INT3_VRPN

REGDEF   $UTIL LOBTADD			; caller supplied register number
REGDEF   $UTIL LOBT_TEMP		; For timeword swap (VR1.21)

Int3Sub:
SETREG   $INT3_VRPN 0x012A		; Version 1.2A
DTBOUT   $INT3_OUTPUTBLOCK 16		; output 70-7f
SETIRPT  3				; interrupt the cc for timewords
DTBIN    $INT3_LOBT 3			; get timewords
COPYREG  $INT3_LOBT $LOBT_TEMP		; swap timewords 1 and 3  (VR 1.21)
COPYREG  $INT3_LOBT+2 $INT3_LOBT
COPYREG  $LOBT_TEMP $INT3_LOBT+2

COPYRD2I $INT3_LOBT $LOBTADD 3		; return to caller
RTNQUE
;