;*************************************************************************
; Some parts of this code, notably the start-up and table->xilinx encoder;
; code, and the include files are                                        ;
; Copyright (2000) CRC for Cochlear Implant and Hearing Aid              ;
; Innovation and HearWorks Pty. Ltd. Australia                           ;
;                                                                        ;
; Main code Originally Written by Andrew Vandali                         ;
;                                                                        ;
; Subsequently and severely modified by Dan Downs (in ways Andrew would  ;
; probably not want to be associated with) for the MRC-CBU.              ;
;                                                                        ;
; Source: sprtbl09.asm,   03 Apr  2005.                                  ;
;                                                                        ;
;*************************************************************************
; Changes from sprtbl08:
; 1) Add an attenuator and subtractor, per side. These are X_ATTEN, Y_ATTEN,
;    X_SUBTRACT, and Y_SUBTRACT. These are 8 bit values which 
;    operate on the pulse amplitude as follows (X/Right side shown only):
;    -- the amplitude value taken from the Stimulus Table is multiplied
;       by X_ATTEN, a value between 255 and 0, where 255 is a multiplication
;       factor of 1, 128 is a multipliction factor of 0.5, etc, then
;    -- Subtract from that product the value of X_SUBTRACT, and pass that
;       value as the amplitude of the pulse. Negative values are converted
;       to a zero amplitude.
;    On each RELOAD command, these values will be re-read.
; 2) Bumped the beginning of the Stimulus Tables from 2C to 34 to make 
;    room for variables. I should have done this from the beginning.
;*************************************************************************
;*************************************************************************
; To get the HTML verison of this, type:
; perl -e 'while(<>){if (/^;/) {$IN=1;} if (/<\/html>/) {$IN=0;} s/^;// ;print if $IN ;} print "<\/html>"' sprtbl09.asm > sprtbl.html
;*************************************************************************
;
;
;                Brief guide to the SPRTBL firmware
;
;
; 
;
;            SPRTBL Firmware
;
;
;
;            Introduction
;
;
;                This document describes the operation of the SPRTBL firmware. The SPRTBL
;                firmware runs on a SPEAR3 Speech Processor and translates compressed tabluar
;                data into output stimulus to its cochlear implant drivers. This firmware is
;                intended for research work only. The SPEAR3 Speech Processor is from 
;                HearWorks Pty Ltd.
;             This document is intended as a guide to anyone needing to understand the SPRTBL
;                firmware, presumably for "high level software" integration or modification of
;                the firmware itself.
;
             This HTML document itself is embedded in the SPRTBL firmware and is simply copied
;                out of the comments in the firmware with a single line of Perl code. This means
;                that there is only a single source of documentation. Any modifications to the 
;                document should be made as comments in the SPRTBL firmware and the HTML file
;                should then be regenerated.
;
             The SPRTBL firmware was written for the 
;                MRC-CBU
;                                              under the direction of Dr. Christopher Long.
;
;
;
;
;            Contents
;
;
;
;-             Objectives
;
 -             Memory Map
;
 -             Driving SPRTBL
;
 -             SPRTBL internal operation
;
 
;
;
;
;
;
;            Objectives
;
;
;                Briefly, the objectives are:
;               Whatever else, maximize precision of all timing aspects of the output stimulus
;               Minimize the delay between High Level Sofware to output stimulus
;             The name "SPRTBL" is derived from SPEAR3 TaBLe, and is intended to reflect the  
;                particular method applied to solve the particular problem(s) in using the 
;                SPEAR3 in psychoacoustic research, according to the objectives. Really, there
;                are a great deal of other concerns, but the SPRTBL firmware can only address the
;                two of them listed above.
;
             Attempts to reach the first objective are described in detail below, and center
;                around using the DSP56300's Fast Interrupt Mode.
;
             Attempts to reach the second objective, also described below, amount to minimizing
;                the volume of data to be transfered to the SPEAR3 device to get it to output
;                new stimulus. This resulted in implementing a compression scheme for the data which
;                must be preloaded, and moves many burdens to the High Level Software where memory and
;                time constraints are not an issue.
;
;
;
;
;            Memory Map
;
;
;                This is not a guide to the SPEAR3 hardware nor the Motorola DSP56309 which it contains.
;                This Memory Map section will only cover what the High Level Software, henceforth HLS,
;                needs to know. 
;
;
;
;| 
;
;                            P-Memory (Program Memory)
;
; | 
;
;                Once the firmware has been loaded there are NO
;             locations in P-Memory accessible to the HLS.
; | 
;
;
;
;
;
;
           Address ranges in the tables below are colour coded.
;
           This colour means these locations are RESERVED.
;
           This colour means that the values here are fixed per "run" (more on that below).
;
           This colour means that these locations are expected to be accessed during a test run by the HLS.
;               Note that there are only 3 such locations, 2 in Y-Memory and 1 in X-Memory.
;
;
;
;
;
;| 
;
;                            Y-Memory / Left Side Encoder Data
;
; | 
;
;  
; Address(es)      Default value       Name                   Description
;-----------------------------------------------------------------------------------------------------
; $000000             000000           Y_RELOAD              Write a 1 to start.
;
; $000001                                                    Internal. Don't touch.
;
; $000002               2000           Y_STptr               Pointer to Y/Left  Stimuli Table
;
; $000003 - $000004                                          Internal. Don't touch.
;
; ------------------ Y-fixed beginning ----------------------------------
; This section sets Active El, Ref El, Amplitude of pulse N
; $000005                 20           Y_ActE                Active electrode
; $000006                 30           Y_RefE                Reference elec (MP1+2)
; $000007 - $000008      0,1                                 Phase 1 duration (25 us)
; $000009 - $00000A    188,0                                 Inter-phase gap (45us)
; $00000B                  0           Y_AmpAE               Amplitude (0)
; $00000C - $00000D      0,0                                 Phase 2 duration (25 us)
; $00000E - $00000F      5,0                                 Inter-frame gap (8 us)
;
; This second section Sets Phase and IPG of pulse N (sets Active, Ref, Amp of N+1)
; $000010                 24                                 Active electrode (MP1)
; $000011                 25                                 Reference elec (MP2)
; $000012 - $000013      0,0                                 Phase 1 duration (25 us)
; $000014 - $000015    188,0                                 Inter-phase gap (8 us)
; $000016                  0                                 Amplitude (0) -- THIS SHOULD ALWAYS BE ZERO
; $000017 - $000018      0,0                                 Phase 2 duration (25 us)
; $000019 - $00001A      5,0                                 Inter-frame gap (8 us)
; $00001B                $80                                 Encoder Halt bit, loaded in Active Elec location
;
; This section sets describes a null pulse, a Power pulses only
; $00001C                 20                                 Active electrode (electrode #20)
; $00001D                 30                                 Reference elec (MP1+2)
; $00001E - $00001F      0,0                                 Phase 1 duration (25 us)
; $000020 - $000021    188,0                                 Inter-phase gap (45 us)
; $000022                  0                                 Amplitude (0) -- THIS SHOULD ALWAYS BE ZERO
; $000023 - $000024      0,0                                 Phase 2 duration (25 us)
; $000025 - $000026      5,0                                 Inter-frame gap (8 us)
; $000027                $80                                 Encoder Halt bit, loaded in Active Elec location
; ------------------ Y-fixed end ----------------------------------
;
; $000028 - $00002B                                          Internal. Don't touch.
;
; ------------------ Y-table beginning ----------------------------------
; Beginning of the Y/Left side Stimuli Table
; $000034            $14C81E           Eword 0               |elect #A|  AMP    |elec #R |
; $000035            $011000           Tword 0               |TTNP (Time Till Next Pulse)|
; $0000bobobobo      $14B81E           Eword 1                  ...
; $00002F            $010000           Tword 1                  ...
; $000030            $14A81E           Eword 2                  ...
; $000031            $00f000           Tword 2
; $000032            $14981E           Eword 3                  ...
; $000033            $00e000           Tword 3
; $000034            $14881E           Eword 4                  ...
; $000035            $00d000           Tword 4
; $000036            $14781E           Eword 5                  ...
; $000037            $00c000           Tword 5
; $000038            $14681E           Eword 6                  ...
; $000039            $00b000           Tword 6
; $00003A            $14581E           Eword                    ...
; $00003B            $00a000           Tword
; $00003C            $14481E           Eword                    ...
; $00003D            $009000           Tword
; $00003E            $14581E           Eword                    ...
; $00003F            $008000           Tword
; $000040            $14681E           Eword                    ...
; $000041            $007000           Tword
; $000042            $14781E           Eword                    ...
; $000043            $006000           Tword
; $000044            $14881E           Eword                    ...
; $000045            $005000           Tword
; $000046            $14981E           Eword                    ...
; $000047            $004000           Tword
; $000048            $14A81E           Eword                    ...
; $000049            $003000           Tword
; $00004A            $14B81E           Eword                    ...
; $00004B            $002000           Tword
; $00004C            $14C81E           Eword                    ...
; $00004D            $001000           Tword
; $00004E            $ffffff           Eword N               electrode = FF means end of table.
; $00004F - $FEFFFF                                          Available for table data             
; ------------------ Y-table end ----------------------------------
;
; $FF0000 - $FFFFFF                                          Reserved. Don't touch.
;
; 
; | 
;
;
;
;
;
;
;| 
;
;                            X-Memory / Right Side Encoder Data
;
; | 
;
;  
; Address(es)      Default value       Name                   Description
;-----------------------------------------------------------------------------------------------------
;
; $000000 - $000001                                          Internal. Don't touch.
;
; $000002               2000           X_STptr               Pointer to X/Right Stimuli Table
;
; $000003 - $000004                                          Internal. Don't touch.
;
; ------------------ X-fixed beginning ----------------------------------
; This section sets Active El, Ref El, Amplitude of pulse N
; $000005                 20           X_ActE                Active electrode (electrode #20)
; $000006                 30           X_RefE                Reference elec (MP1+2)
; $000007 - $000008      0,0                                 Phase 1 duration (25 us)
; $000009 - $00000A    188,0                                 Inter-phase gap (45us)
; $00000B                  0           X_AmpAE               Amplitude (0)
; $00000C - $00000D      0,0                                 Phase 2 duration (25 us)
; $00000E - $00000F      5,0                                 Inter-frame gap (8 us)
;
; This second section Sets Phase and IPG of pulse N (sets Active, Ref, Amp of N+1)
; $000010                 24                                 Active electrode (MP1)
; $000011                 25                                 Reference elec (MP2)
; $000012 - $000013      0,0                                 Phase 1 duration (25 us)
; $000014 - $000015    188,0                                 Inter-phase gap (8 us)
; $000016                  0                                 Amplitude (0) -- THIS SHOULD ALWAYS BE ZERO
; $000017                0,0                                 Phase 2 duration (25 us)
; $000018 - $000019      5,0                                 Inter-frame gap (8 us)
; $00001A - $00001B      $80                                 Encoder Halt bit, loaded in Active Elec location
;
; This section sets describes a null pulse, a Power pulses only
; $00001C                 20                                 Active electrode (electrode #20)
; $00001D                 30                                 Reference elec (MP1+2)
; $00001E - $00001F      0,0                                 Phase 1 duration (25 us)
; $000020 - $000021    188,0                                 Inter-phase gap (45 us)
; $000022                  0                                 Amplitude (0) -- THIS SHOULD ALWAYS BE ZERO
; $000023 - $000024      0,0                                 Phase 2 duration (25 us)
; $000025 - $000026      5,0                                 Inter-frame gap (8 us)
; $000027                $80                                 Encoder Halt bit, loaded in
; ------------------ X-fixed end ----------------------------------
;
; $000028 - $00002B                                          Internal. Don't touch.
;
; ------------------ X-table beginning ----------------------------------
; Beginning of the Y/Right side Stimuli Table
; $000034            $14C81E           Eword 0               |elect #A|  AMP    |elec #R |
; $000035            $009000           Tword 0               |TTNP (Time Till Next Pulse)|
; $0000bobobobo      $14C81E           Eword 1                  ...
; $00002F            $009000           Tword 1                  ...
; $000030            $14C81E           Eword 2                  ...
; $000031            $009000           Tword 2
; $000032            $14C81E           Eword 3
; $000033            $009000           Tword 3
; $000034            $14C81E           Eword 4
; $000035            $009000           Tword 4
; $000036            $14C81E           Eword 5
; $000037            $009000           Tword 5
; $000038            $14C81E           Eword 6
; $000039            $009000           Tword 6
; $00003A            $ffffff           Eword N               electrode = FF means end of table.
; $00003B - $FEFFFF                                          Available for table data             
; ------------------ X-table end ----------------------------------
;
; $FF0000 - $FFFFFF                                          Reserved. Don't touch.
;
;
; 
; | 
;
;
;
;
;
;
;            Driving SPRTBL
;
;
;            Basic Operation
;
;                The process begins with the High Level Software (HLS) loading the SPRTBL "in the usual
;                way" via the serial port interface with Womera or a similar program. Once loaded and started,
;                SPRTBL is idle until given a command to start, which for historical reasons is called
;                "Y_RELOAD", or "RELOAD". The "usual way" of downloading the program is not covered here.
;
;                During the idle time, the HLS is expected to load stimulus data into the SPEAR3's
;                internal X and Y Memories. There are four separate regions of memory, two for each
;                side. The X-Fixed and Y-Fixed sections (see the tables above) are stimulus parameters
;                which do not change during the course of a "run", while the X-table and Y-table
;                sections are the stimulus parameters which vary (can vary) between output pulses,
;                and these sections are compressed/encoded. Here is an example of a table entry, copied
;                from the Y-Memory Memory Map above:
;
; $00002C            $14C81E           Eword 0               |elect #A|  AMP    |elec #R |
; $00002D            $011000           Tword 0               |TTNP (Time Till Next Pulse)|
;
;                Which is decoded as:
;
            The active electrode will be 14 hex, or 20 decimal,
;
            The amplitude of the active electrode will be C8 hex, or 200 decimal,
;
            The reference electrode will be 1E hex, or 30 decimal, and 
;
            The time this pulse will be output is 011000  hex, or 69632
;
;
;
;
;
;                When the stimulus has been loaded, the RELOAD command can be issued. The RELOAD
;                command is a "1" written to location 0x000000 of X-Memory. The other (highest) 23
;                bits of this location are reserved for future use and should be written as zeros.
;
;                Following this RELOAD command SPRTBL reads data from tables in internal X
;                and Y memories and converts them to stimuli (sends commands to the encoders).
;                Data in the X-Memory area is for the Right side output and data in the Y-Memory is
;                for the Left side output. SPRTBL reads the X-Memory/Right side data table from the
;                address given in the X_STptr variable until a stop code is reached. Likewise, SPRTBL
;                reads the Y-Memory/Left side data table from the address given in the Y_STptr variable
;                until a stop code is reached.
;
;
            After both the sides have stopped, SPRTBL needs another "RELOAD" to begin again.
;                In a way then, SPRTBL is ballistic. There are no provisions for stopping it until
;                it is done reading/converting/outputing. 
;
;
            In order the output a purst of pulses,
;
;
;                Since there is only one simple command, all the complexity is in creating (and
;                writing) the data tables. In order to understand the form of these tables it is
;                important to understand the data which the encoders need.
;
;
            The Stimulus Parameters
;
;                There are two encoders which drive the cochlear implants, one per side. Only one will
;                be discussed here. The implants accept information to control the following parameters: 
;
;
;
;
;
;                
;
;
;
;
;
;            SPRTBL internal operation
;
;                
;
;
;
;Keep out of this memory space:
; X data memory ($FFFF80-$FFFFFF in
;and this space too:
;Y data 
;memory ($FFFF80-$FFFFFF
;
;and here:
;The Y memory space at locations $FF0000 to $FFEFFF is reserved and should not be 
;accessed by the programmer.
;and here:
;The X memory space at locations $FF0000 to $FFEFFF is reserved and should not be 
;accessed by the programmer.
;
; 7168 is 0x1c00.
; 3584 Eword/Tword pairs.
;
; NOTES on variable naming
; ---------------------------
; Y_thingy means the variable is stored in Y mem,
; X_thingy means the variable is stored in X mem,
; thingy   means the variable is stored in P (program) mem,
; X <==> Right <==> R,
; Y <==> Left  <==> L,
; BUT,
; registers x0, x1, y0, and y1 are not fixed to X or Y, R or L.
; but x0 and x1 are dedicated as flags for noting that an interrupt
; occured on the right and left sides.
; 
; There are a few variables not specific to either side, and they
; happen to be in the Y memory space.
;
;========================================================
;     Picture of the memory map (and other stuff too):
;  X is RIGHT side                   Y is the LEFT side
; +---------------+                  +---------------+
; |  static and   |                  |  static and   |
; | pseudo-static |                  | pseudo-static |
; |  parameters   |                  |  parameters   |
; +---------------+                  +---------------+     +-------------+
; | Encoder Table |                  | Encoder Table |<----|decompression|
; |    active     |                  |    active     |     |             |
; +---------------+                  +---------------+     | 0 1 2 ... N |
; | Encoder Table |                  | Encoder Table |     +-------------+
; |  null pulses  |                  |  null pulses  |      / / /     /
; +---------------+                  +---------------+     / / /     /
; |    unused     |                  |  other vars   |    / / /     /
; +---------------+                  +---------------+   / / /     /
; |   Eword(0)    |<--beginning of-->|   Eword(0)    | \/ / /     /  One at a time, decompress
; |   Tword(0)    |   Stimuli Table  |   Tword(0)    | / / /     /  from the Stimuli Table and
; |   Eword(1)    |                  |   Eword(1)    | \/ /     /  place in the Encoder Table,
; |   Tword(1)    |                  |   Tword(1)    | / /     /  using the  Eword for Electrode
; |   Eword(2)    |                  |   Eword(2)    | \/     /  data and the Tword for Timing
; |   Tword(2)    |                  |   Tword(2)    | /     /  data (the Time Till Next Pulse).
; ~     ...       ~                  ~     ...       ~      /
; |   Eword(N)    |   Stimuli Table  |   Eword(N)    |\____/
; |   Tword(N)    |<------end------->|   Tword(N)    |/
; +---------------+                  +---------------+
; 
;-------------------------------------------------------
; This code uses fixed locations for the Right and Left side
; Encoder Tables and a fixed location for the beginning of the 
; Stimuli Tables, but no limit on the length of the Stimuli
; Table until the end of memory is reached. It is important 
; to note ALL changes to this memory map since the high level
; SW writes to these addresses to set up stimuli, start and
; control the generation of stimuli.
;
; The way it works is that the contents of the fixed (fixed
; in memory location, not content) Encoder Table is copied to
; xilinx encoders on a RELOAD command (see below). That data
; is sent to the implant.
; One pass through an Encoder Table is a single pulse of a
; single electrode. The Right side tables, stimuli and
; null/power pulses, are in the space between the labels:
; X_CI24beginActive
; X_CI24endActive
; and 
; X_CI24beginNull
; X_CI24endNull
;
; and the Left side tables, stimuli and
; null/power pulses, are in the space between the labels:
; Y_CI24beginActive
; Y_CI24endActive
; and 
; Y_CI24beginNull
; Y_CI24endNull
;
; 
; As one can see, unless the contents of the Encoder Table change,
; this will result in only a single pulse of unchanging characteristics
; being delivered.
; 
; To drive more interesting stimuli, a compressed Stimuli Table is
; written before the RELOAD is triggered. One block of
; this compressed Stimuli Table is decompressed and replaces the 
; contents of the Encoder Table, and this is "fired off" to the
; encoder on interrupt. An attempt to capture this pictorially is
; shown above to the right of the picture of the memory map.
;
; The ability to compress the stimuli results from the fact that
; not every parameter changes during a stimulus sequence, so these
; values do not get stored in the compressed Stimuli Table (and if
; there was a lot more on chip memory, none of this would be necessary.
; Compression is only to simulate a long sample table).
; The fixed stimuli are marked in the Encoder Table below with "FIXED":
; 
; Encoder Table for CI24, Right, X
;                         Sets Active El, Ref El, Amplitude of pulse N	;
;X_CI24beginActive				;
;variab dc	20				; Active electrode (#20)   ; elect #
;variab dc	30			 	; Reference elec (MP1+2)   ; ref elec
;FIXED  dc	0,0				; Phase 1 duration (25 us) ; phase-1a phase-1b
;FIXED  dc	5,0				; Inter-phase gap (8 us)   ; inter-1a inter-1b
;variab dc	200				; Amplitude (200)          ; AMP
;FIXED  dc	0,0				; Phase 2 duration (25 us) ; phase-2a phase-2b
;FIXED  dc	5,0				; Inter-frame gap (8 us)   ; inter-2a inter-2b
;
;                         Sets Phase and IPG of pulse N (sets Active, Ref, Amp of N+1)
;variab	dc	24				; Active electrode (MP1)
;variab	dc	25				; Reference elec (MP2)
;FIXED	dc	0,0				; Phase 1 duration (25 us)
;FIXED	dc	5,0				; Inter-phase gap (8 us)
;FIXED	dc	0				; Amplitude (0)
;FIXED	dc	0,0				; Phase 2 duration (25 us)
;FIXED	dc	5,0				; Inter-frame gap (8 us)
;						; 
;FIXED	dc	$80				; Encoder Halt bit, loaded in Active Elec location
;X_CI24endActive				;
;						;
;X_CI24beginNull				; Power pulses only, Right.
;FIXED	dc	20				; Active electrode (electrode #20)
;FIXED	dc	30				; Reference elec (MP1+2)
;FIXED	dc	0,0				; Phase 1 duration (25 us)
;FIXED	dc	5,0				; Inter-phase gap (8 us)
;FIXED	dc	75				; Amplitude (75)
;FIXED	dc	0,0				; Phase 2 duration (25 us)
;FIXED	dc	5,0				; Inter-frame gap (8 us)
;FIXED	dc	$80				; Encoder Halt bit, loaded in Active Elec location
; X_CI24endNull
;
;
; As each of the lines above with "variab" is only a byte value, 
; these three can be compressed into a single 24 bit word.
;
; In addition to these three values, it is also needed to 
; allow for the possibility of varying the time between pulses.
; This can be done with a single 24bit word which is stored as
; the next value to be loaded into the interrupt controller.
; This means that each stimulus pulse takes up 2 24bit words
; in either X or Y memory, and will be organized like so:
;   |elect #A|  AMP    |elec #R |        Eword
;   |TTNP (Time Till Next Pulse)|        Tword
;
; X and Y MEMORY MAP at the time of this writing (please
; always refer to the code for the actual map):
; X is RIGHT side  	Y is the LEFT  side
;-------------------------------------------------------
;    unused		Y_RELOAD
; X_TTNP		Y_TTNP
; X_Groups		Y_Groups
; X_Delay		Y_Delay
; X_TrainCount		Y_TrainCount
;    unused		X_Delay_AMBI
; X_DONE		Y_DONE
; 
; X_CI24beginActive	Y_CI24beginActive
; X_CI24endActive	Y_CI24endActive
; X_CI24beginNull	Y_CI24beginNull
; X_CI24endNull		Y_CI24endNull
;    unused		save_x0	
;    unused		save_y0	
;    unused		save_aa	
;    unused		ExtInputState
;       M words of HEADROOM
;
; X_StimHead 		Y_StimHead 		; Beginning of compressed Stimuli Tables
;    Eword(0)		   Eword(0)
;    Tword(0)		   Tword(0)
;    Eword(1)		   Eword(1)
;    Tword(1)		   Tword(1)
;    Eword(2)		   Eword(2)
;    Tword(2)		   Tword(2)
;      ...		    ...
;    Eword(N)		   Eword(N)		; Table terminates when elect#A == 255.
;    Tword(N)		   Tword(N)
;
;------------------------------------------------------------------------------;
; THIS SECTION OBSOLETE FROM HERE TO .......
;------------------------------------------------------------------------------;
;                               WHAT THIS CODE DOES
;                               ===================
; This code outputs trains of pulse groups to the right and left channels of the
; cochlear implant drivers according to pre-specified parameters. The goal is to
; provide pulse amplitude, width, and period control per channel; but especially
; to provide control of right vs left time delays, the Interaural Time Difference
; or ITD. 
; The parameters are loaded from a host computer through the serial interface.
; The host computer then issues a RELOAD command, also through the serial 
; interface, and the SPEAR3 then outputs pulse groups according to those
; parameters to the right, left or both channels.  The RELOAD command consists
; simply of writing a "1" to location 0 in the Y memory space, which is cleared
; immediately by this firmware after detecting the "1".
;
; This code will do some setup, enable interrupts, and, while keeping count of
; the number of requested pulses, trigger the right and/or left side Xilinx
; encoders to output the contents of the encoder table at the specified rate.
; The encoder table could specify 0 to 22 electrodes, but whatever it is, that
; is what I am calling a pulse "group".  The stimulus of 0 to 22 electrodes can
; be in any number or order, provided that an electrode is specified only once.
; A pulse train is defined as a periodic repeat of a pulse group, though a train
; length of 0 or 1 is allowed.
;
; The pulse train can consist of 0 to (2^32)-1 groups as specified prior to the
; RELOAD command. The pulse train will be transmitted with a specified period,
; a specified number of times, but parameters assigned to each electrode cannot
; change during the pulse train. The period between consecutive pulses in any
; given train can differ from channel to channel from
; ICPPDIFF_MIN to ICPPDIFF_MAX, and either side can be made to lead the other by
; ICPCDIFF_MIN to ICPCDIFF_MAX counts or by a time of ITDMIN to ITDMAX . The
; limits on those last six parameters are governed by the power storage
; capability of the implants. This is detailed below.
;
; Perhaps the most important thing to note for anyone wishing to edit this code
; is that in an effort to reduce the unpredictabiity associated with responding to
; interrupts, the Fast Interrput Mode has been used. An unfortunate consequence
; of this is that, given the existing hardware and the limits of instruction
; word size to use this mode, there is essentially only a single instruction that
; will accomplish the task. The reason for this is that two things must occur on
; that instruction, namely 1) Start the encoder to transmit, thus reducing the
; time and indeterminacy from interrupt to pulse output, and 2) making a note
; that this interrupt occured. In the code, that is:
;
;       move    b,x0            a,y:ENCSTRT24R  ; Start Encoder and
;                                               ; note that this interrupt happened.
;
; Most of the apparently peculiar coding is here merely to support that single
; instruction. Things like using the entirety of r4, x0, and y0 as flags so as
; to avoid condition code changes on interrput response. I have noted all these
; things in the code where I could.
;
; Another peculiarity is the inclusion of the entire encoder tables within
; the Y memory space. This was done because writing to the P memory space causes
; the device to reset, a behaviour mediated by the serial interface download code.
; This reset is unacceptable if one wishes to modify the electrode parameters during 
; an experiment.
;
;                               OPERATING NOTES
;                               ===============
;--------------------------------------------------------
; Do not write to the device while it is transmitting.
; The green LED will be ON when it is safe to transmit.
; But the user program also ought to know how long the
; pulse trains it is requesting are, so the LED is just
; an extra.
;
;--------------------------------------------------------
; In order to start the device transmitting, write a 1
; to bit zero of the zeroth location of Y memory.
; 	0x000000 Y_RELOAD
; The other bits of this memory location are unused.
;
;--------------------------------------------------------
; To change the period between groups in a train of either
; side, write new values to the two locations in Y memory:
; 	0x000001 Y_RightPeriod
; 	0x000002 Y_Left_Period
; where the period is a number of 0.13605 usec counts.
; 
;--------------------------------------------------------
; To set the number of pulses in a pulse train of either
; side, write new values to the two location in Y memory:
; 	0x000003 Y_GroupsRight
; 	0x000004 Y_Groups_Left
; These are unsigned ints, and zero is okay.
;
;--------------------------------------------------------
; To delay the start of the right side pulse train with
; respect to the left, write a non-zero value to:
; 	0x000005 Y_DelayRight
; where the time is a number of 0.13605 usec counts.
;
;--------------------------------------------------------
; To delay the start of the left side pulse train with
; respect to the right, write ZERO to:
; 	0x000006 Y_DelayRight
; AND write a non-zero value to:
; 	0x000007 Y_Delay_Left
; where the time is a number of 0.13605 usec counts.
;
;--------------------------------------------------------
; The values in the counters are related to time by the
; CLK half frequency which drives the timers. The CLK is
; 14.7MHz, so CLK/2 is 7.35MHz, or 0.13605 usec period.
;
;--------------------------------------------------------
; To decrease the ISR time and use the fast interrupt mode,
; entire registers are used as flags. This keeps the
; condition code register unchanged during the interrput.
; x0, is the flag for noting a right side, Timer0, interrupt occured.
; x1, is the flag for noting a left  side, Timer1, interrupt occured.
; r4, is the flag for noting the ITD, Delay, is done.
;--------------------------------------------------------
;
;
;
;                               TIMING ANALYSIS
;                               ===============
; There are several scales of time to be concerned with. The discussion below 
; starts from the most coarse grain to the finest grain. The coarse timing involves
; user/Host computer operations and the finest relates to the interrupt
; response of the DSP which ultimately determines the resolution and jitter of
; pulses issued from the SPEAR3 device.
;
;                               TOP LEVEL TIMING
;                               ================
; This is a diagram of the overall operation (not to scale):
;
; |~~~~~~~~~~~~~~~~~|~~~~~|--------------XXXXXXXXXXXXXXXXXXXXXX-----------------
; |                 |     |              \________  __________/
; |                 |     |              |        \/          |
; T0                T1    T2             T3       PT          T0
;
;
; T0 to T1: This time is of arbitrary length. It is the time it takes the high
; level software on the host computer to write the parameters. T1 is the time at
; which the RELOAD command is *apparently* written BY THE HOST COMPUTER.
; This is not really something that can be measured.
;
; T1 to T2: The delay from the *apparent* write to the firmware's detection of
; the RELOAD command. T2 is the first time that can be referenced to within the
; SPEAR3.
;
; T2 to T3: The time it takes the DSP code to respond with the first pusle
; following a RELOAD. This is computable and is based only on the number of 
; instructions required.
; T2 to T3 is ________________________________.
;
; IMPORTANT NOTE: The device must not be written to from T1 untill the next T0.
; The green LED is on when it is safe to write to the device. Writing to the
; device within this period will lead to unpredictable behaviour since there
; are NO interrupt disable provisions.
;
;
;
;                               PULSE TRAIN TIMING, PART 1
;                               ==========================
; All timing is dependent on the CPU clock rate. This is set at 14.7456MHz, the
; crystal oscillator frequency, which is then divided by two giving 7.35MHz.
; This means that the minimum time resolution for any event is 0.13605 usec. For
; example, there are 4 parameters the user can set which use this clock, 
; and all of these take effect in the XXXXXX bit above, from T3 to the next T0,
; namely the pulse train PT. The right and left pulse trains can differ. And 
; just to be clear here, a pulse train for a given side is the collection of
; all the pulse groups generated from a RELOAD command until that side has output
; the pre-specified number of groups. These parameters are: 
; 	Y_GroupsRight
; 	Y_Groups_Left	
;
; So expanding on PT above, these parameters are as shown:
; 
; 
;             |<--------tR------->|
;             |                   |
; Right ______|RRRRR______________|RRRRR_______________RRRRR_______________RRR
;             |RRRRR              |RRRRR               RRRRR               RRR 
;             |     |
;             |     |<---------tL--------->|
;             |     |                      |
;  Left ______|_____|LLLLL_________________|LLLLL__________________LLLLL______
;             |     |LLLLL                 |LLLLL                  LLLLL     
;             |     |
;             ^_ITD_^
; 
; Where RRRRR is the output pulse group on the right side and LLLLL is the output
; pulse group on the left side.
; The time between pulses for a given side are tR and tL.
; The delay between the beginning of one side's pulse train and the other side's
; is ITD. The Right side is shown leading the left but it could be the other
; way around just as well. The IDT is set with the parameters:
;    Y_DelayRight	; Number of counts to delay the right side pulse train
;    Y_Delay_Left	; Number of counts to delay the left  side pulse train
; 
; 
; 
;                               PULSE TRAIN TIMING, PART 2
;                               ==========================
; Expanding on the RRRRR and LLLLL above, the simplest pulse groups to discuss
; consist of a single electrode being stimulated as shown below. There is
; currently no provision to change the electrode number(s) once a pulse train
; has begun. While the Encoder Table can be changed prior to a PT, it is static
; for the duration of a PT. This code includes the Encoder tables beginning at
; address Y_CI24beginActiveR and Y_CI24beginActiveL.
; 
;             ----RRRRRRRRRRRRRRRRRR----
; 
;                |<-------tR------->|
; A single       |   _              |   _                   _                 
; Right side ____|  | \_____________|  | \______________|  | \______________ 
; Electrode      |\_|               |\_|                |\_|  |             
;                |                                      |     |
;                |                                      |-tgR-|
;                |      
;                |  ----LLLLLLLLLLLLLLLLLLLLLL----
;                |      
;                |     |<---------tL--------->|
; A single       |     |   _                  |   _                       _  
;  Left side ____|_____|  | \_________________|  | \__________________   | \__
; Electrode      |     |\_|                   |\_|                    |\_|  |
;                |     |                                              |     |
;                ^_ITD_^                                              |     |
;                                                                     |-tgL-|
;
; The Time tR is set by:
; 	Y_RightPeriod
; and the time tL is set by:
; 	Y_Left_Period
; Note that the only thing the DSP can do is count, so the notion of "period"
; must be given as 
; tR = Y_RightPeriod counts /( counts/0.13605 usec)
;
; The parmeters tgR and tgL ad discussed below.
; 
; 
; 
; 
;                               PULSE TRAIN TIMING, PART 3
;                               ==========================
; Here, the notation tG refers to tgR and/or tgL, and tS refers to tR and/or tL.
; More than one electrode can be stimulated per channel per Pulse Train. This
; makes a pulse group. The selection depends entirely on the length/content of
; the Encoder Table. A longer table (basically, more electrodes)
; means a longer delay from T2 to T3 and a longer RRRRR and/or LLLLL. The min is
; a single electrode programmed with minimum values shown here:
;	dc	24		; Active electrode (MP1)
;	dc	25		; Reference elec (MP2)
;	dc	0,0		; Phase 1 duration (25 us)
;	dc	5,0		; Inter-phase gap (8 us)
;	dc	0		; Amplitude (0)
;	dc	0,0		; Phase 2 duration (25 us)
;	dc	5,0		; Inter-frame gap (8 us)
; and the maximum is all the electrodes programmed with the values shown here:
;	dc	24		; Active electrode (MP1)
;	dc	25		; Reference elec (MP2)
;	dc	0,0		; Phase 1 duration (25 us)
;	dc	5,0		; Inter-phase gap (8 us)
;	dc	0		; Amplitude (0)
;	dc	0,0		; Phase 2 duration (25 us)
;	dc	5,0		; Inter-frame gap (8 us)
;
; The diagram below shows electrodes 9, 1, 3, and 5 being used. One thing to
; note is that the order of the electrodes is dependent on the order given in
; the table and that the total width of the group must be considered to be the 
; width of all the pulses in the group plus their inter-phase gaps plus their
; inter-frame gaps. Note that tG must always be smaller than tS or bad things
; will happen. That is because interrupts will arrive to issue new pulse trains
; before the previous one finishes. And as a consequence of using the Fast
; Interrput mode no interrupt masks are set to catch this.
;
;
;                 
;                  |<-------tS-------->|
; Multiple         |                   |
; electrodes for __9135________________9135________________9135______________
; side S         ->|  |<-
;                   tG  
;                
;
; IMPORTANT NOTE: If the electrode number and/or order and the Phase 1, Phase 2,
; Inter-phase gap, Inter-frame gap for each channel are not identical then, 
; although each pulse train will *begin* with the desired ITD, the actual 
; electrode pulses will have different delays with respect to the other side.
;
; IMPORTANT NOTE II: Re-read the important note above.
;
;
;                               TIMING RESOLUTION
;                               GENERAL
;                               =================
; The timing of a group onset is interrupt driven. The timer module is in a
; mode where it needs no overhead to restart. If the interrupt timer is loaded
; with the value of 0x008F8E, for example, it will issue an interrupt every
; 5 miliseconds independent of any other event until it is turned off (by another
; part of the code which is counting pulse groups). This means that
; the times to be concerned with are:
; 1) the time to start the encoder from receiving an interrupt,
; 2) what happens with simultaneous interrupts on both sides,
; 3) the initial itd.
; These three are detailed below, but the important timing is related to the
; timer running at the cpu clk resolution, the interrupt priority scheme, and
; the CPU pipeline behaviour during interrupt.
;
; The interrput priorities with the triple timer itself are set as a block.
; There is no way to set different timers at different levels. Timer 0 is used
; for the Right channel, Timer 1 for the Left channel and Timer 2 to set the
; ITD.
;
; The fixed-priority structure within the Timer Module Interrput Priority Level
; (IPL) is:
; highest
; ...
; Timer0 Overflow
; Timer0 Compare
; Timer1 Overflow
; Timer1 Compare
; Timer1 Overflow
; Timer1 Compare
; ...
; lowest
;
;                 CPU pipeline on Fast Interrupt
; When the interrupt occurs the following sequence follows:
; interrupt ->
;    sync to clk ->
;        arbitrate ->
;            put instr at head of pipe->
;                wait for other instructions to complete.
;
; In the traditional diagram, interrput instruction words i1 and i2 
; are loaded following arbitration as shown:
; Operation   Instruction cycle
; ---------------------------------------------
;            1   2   3   4   5   6   7   8   9   10  11  12
; PF1       n1  n2  i1  i2  n3  n4 
; PF2           n1  n2  i1  i2  n3  n4
; Decode            n1  n2  i1  i2  n3  n4
; AG1                   n1  n2  i1  i2  n3  n4
; AG2                       n1  n2  i1  i2  n3  n4
; Ex1                           n1  n2  i1  i2  n3  n4
; Ex2                               n1  n2  i1  i2  n3  n4
; 
;
; Testing has shown that the Fast interrupt ...
;
; 
; Note: A fast interrupt is not interruptable.
; Sadly, the ITD using Timer 2 is not using the Fast Interrput Mode.
; I am thinking of fixing that.
;
;
;
;                               TIMING RESOLUTION
;                               INTERRUPT TO ENCODER START
;                               ==========================
;
; From interrupt to starting the encoder:
; 
; -~~~~~~~~~~~~~~~~|-|-|-|-|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~|-|-|-...
;                  I A B C |                                I A B 
;                          |
;                          S
; I: interrupt occurs
; I to A: current instruction completes: gg to pp,
; A to B: loading two words in the pipeline,
; B to C: Executing the instruction, writing to the Encoder,
; C to S: Encoder response time.
;
; 
; -----------------|-|-|-|-|---------------------------------------
;                          |
;
; Do not make the itd > tp (period?) of the other channel.
;
; one channel begins till the itd of the other:
;
;
;                               TIMING RESOLUTION
;                               SIMULTANEOUS PULSE TRAIN INTERRUPTS
;                               ===================================
;
; Interrupt to starting the encoder as above:
; 
; Right ~~~~~~~~~~~|-|-|-|-|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~|-|-|-...
;                  I A B C |                                I A B 
;                          |
;                          S
; 
; Left  ~~~~~~~~~~~|-|-|-|-|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~|-|-|-...
;                  I A B C |                                I A B 
;                          |
;                          S
; As Timer 0 has priority over Timer 1, simultaneous events will put
; the Right side one cycle ahead of the Left.
;
;
;
;
;                               TIMING RESOLUTION
;                               SIMULTANEOUS INTERRUPTS WITH ITD
;                               ================================
; Interrupt to starting the encoder as above:
; 
; Right or Left ~~~|-|-|-|-|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~|-|-|-...
;                  I A B C |                                I A B 
;                          |
;                          S
; Interrupt to starting the timer following initial ITD:
; 
; Timer 2, ITD ~~~~|-|-|-|-|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~|-|-|-...
;                  I A B C |                                I A B 
;                          |
;                          S
; As Timers 0 and 1 have priority over Timer 2, simultaneous events or
; receiving a timer 0 or 1 interrupt while the Timer 2 ISR is running
; will cause 
;
;
;
;
;------------------------------------------------------------------------------;
;           ... TO HERE AND WILL BE REWRITTEN LATER.
;------------------------------------------------------------------------------;
SpearLib	IDENT	1,3
	cobj	'7/10/02 SpearLib'
	OPT	FC	;fold comments
	OPT	MU	;memory utilization listing
	OPT	RC	;float comments
;***********************************************;
;-------------------------------		;
; Include files for DSP56302/DSP56309 		;
						;
	include	'equ_io.a56'			;
	include	'intequ.a56'			;
						;
;-------------------------------		;
; Spear Rev3 specfic Equates			;
						;
	include 'Spear3eq.a56'			;
						;
;-----------------------------------------------;
;
;***********************************************;
;						;
; User Program Equates & Macros			;	
;						;
						; Flags for:
RELOAD 		equ 	0 			; RELOADing data and starting the pulse trains.
INTFLAG		equ 	0 			; bit for noting that an interrupt occured
DONE		equ 	0 			; bit for noting that a given side is done.
FIRSTTIME 	equ	1 			; noting that a given side has done the reload portion
STOPNOW 	equ	2 			; noting that a given side shuld stop immediately.
TERMINALCOUNT	equ	$F42400			; This, F42400, is 16,000,000.
;   						;
;-------------------------------		;
; DSP Core Frequency 				;
CF14_7M		equ	$0E0000			; fc=14.7 MHz (Codec Sampling Freq = 14.4Kz/ch)
						;
;-------------------------------		;
; ESSI equates for CODEC Initialisation 	;
ESSI_SCI0	equ	$101801			; fc=14.7MHz. fs = 28800Hz (14400Hz per channel)
ESSI_SCI1	equ	$10180F			;
						;
;-------------------------------		;
; Wait States for off-chip access		;
WAITSTATES	equ	$014861			; fc=14.7MHz, default = 1, and 
                                                ; AAR0=1, AAR1=3, AAR2=2, AAR3=2
						;
;-------------------------------		;
; Implant Type for Left and Right Side		;
;						;
; Set to 1 for CI24, or 0 for CI22		;
;						;
CI24L		equ	1			; Left  Implant = CI24
CI24R		equ	1			; Right Implant = CI24
						;
;---------------------------------------	;
; Delay macro in 50us steps			;
;  make sure to adjust FIFTY_MS_COUNT 		;
;  if DSP Core freq is modified			;
						;
FIFTY_MS_COUNT	equ	733			; Fifty Micro Sec Count for 14.7MHz
						;
delay50us macro   time				;
	do	#time,_delay50us		;
	rep	#FIFTY_MS_COUNT			;
	nop					;
_delay50us					;
	nop					;
        endm					;
						;
;-----------------------------------------------;
;
;***********************************************;
;						;
;  Assemble time switches			;
;						;
;-------------------------------		;
; Enable CODEC output				;
;  Set to 1 to Enable switch, 0 to disable	;
						;
ENABLEDAC	equ	0			; Codec Output Disabled
						;
;-----------------------------------------------;
;
;***********************************************;
;						;
; MEMORY ALLOCATIOM				;
;						;
;***********************************************;
;						;
; Y: RAM ALLOCATION 				;
;						;
		org	y:0			;
Y_RELOAD	dc 	0 			; Reload flag location.
Y_FLAGS		dc 	0 			; address of flag to note Y/Left side done, firsttime through, stop.
Y_STptr		dc 	2000 			; Pointer to Y/Left Stimuli Table
Y_ATTEN		dc 	9999 			; 
Y_SUBTRACT	dc	9999			; 
						;
; Sets Active El, Ref El, Amplitude of pulse N	;
Y_CI24beginActive				; Encoder Table for CI24, Left
Y_ActE	dc	20				; Active electrode (electrode #20)
Y_RefE	dc	30				; Reference elec (MP1+2)
	dc	0,0				; Phase 1 duration (25 us)
	dc	188,0				; Inter-phase gap (45us)
Y_AmpAE	dc	0				; Amplitude (0)
	dc	0,0				; Phase 2 duration (25 us)
	dc	5,0				; Inter-frame gap (8 us)
; This second section Sets Phase and IPG of pulse N (sets Active, Ref, Amp of N+1)
	dc	24				; Active electrode (MP1)
	dc	25				; Reference elec (MP2)
	dc	0,0				; Phase 1 duration (25 us)
	dc	188,0				; Inter-phase gap (8 us)
	dc	0				; Amplitude (0) -- THIS SHOULD ALWAYS BE ZERO
	dc	0,0				; Phase 2 duration (25 us)
	dc	5,0				; Inter-frame gap (8 us)
	dc	$80				; Encoder Halt bit, loaded in Active Elec location
Y_CI24endActive					;
						;
Y_CI24beginNull					; Power pulses only, Left.
	dc	20				; Active electrode (electrode #20)
	dc	30				; Reference elec (MP1+2)
	dc	0,0				; Phase 1 duration (25 us)
	dc	188,0				; Inter-phase gap (45 us)
	dc	0				; Amplitude (0) -- THIS SHOULD ALWAYS BE ZERO
	dc	0,0				; Phase 2 duration (25 us)
	dc	5,0				; Inter-frame gap (8 us)
	dc	$80				; Encoder Halt bit, loaded in Active Elec location
Y_CI24endNull					;
;-----------------------------------------------;
; Save save locations for registers used	;
; during interrupt service rtns			;
save_x0		ds	1		 	;
save_y0		ds	1		 	;
save_aa		ds	1			;
save_bb		ds	1			;
Y_ATTEN24BIT	ds	1			;
Y_SUBTRACT24BIT	ds	1			;
Y_reserved2	ds	1			;
Y_reserved3	ds	1			;
Y_reserved4	ds	1			;
Y_reserved5	ds	1			;
Y_reserved6	ds	1			;
Y_temp7		ds	1			;
;-----------------------------------------------;
; This location is a pointer to the beginning	;
; of the table which the code will output. It	;
; begins set to Y_StimHead, but the user can	;
; rewrite this value to any location between	;
; Y_StimHead and the end of usable Y memory.	;
Y_StimBegin	ds	1			;
;-----------------------------------------------;
Y_StimHead 					; Beginning of the Y/Left side Stimuli Table
	dc	$14C81E		          	;  Eword 0 |elect #A|  AMP    |elec #R |
	dc	$011000				;  Tword 0 |TTNP (Time Till Next Pulse)|
	dc	$14B81E		          	;  Eword 1             ...
	dc	$010000				;  Tword 1             ...
	dc	$14A81E		          	;  Eword 2             ...
	dc	$00f000				;  Tword 2
	dc	$14981E		          	;  Eword 3             ...
	dc	$00e000				;  Tword 3
	dc	$14881E		          	;  Eword 4             ...
	dc	$00d000				;  Tword 4
	dc	$14781E		          	;  Eword 5             ...
	dc	$00c000				;  Tword 5
	dc	$14681E		          	;  Eword 6             ...
	dc	$00b000				;  Tword 6
	dc	$14581E		          	;  Eword               ...
	dc	$00a000				;  Tword  
	dc	$14481E		          	;  Eword               ...
	dc	$009000				;  Tword  
	dc	$14581E		          	;  Eword               ...
	dc	$008000				;  Tword  
	dc	$14681E		          	;  Eword               ...
	dc	$007000				;  Tword  
	dc	$14781E		          	;  Eword               ...
	dc	$006000				;  Tword  
	dc	$14881E		          	;  Eword               ...
	dc	$005000				;  Tword  
	dc	$14981E		          	;  Eword               ...
	dc	$004000				;  Tword  
	dc	$14A81E		          	;  Eword               ...
	dc	$003000				;  Tword  
	dc	$14B81E		          	;  Eword               ...
	dc	$002000				;  Tword  
	dc	$14C81E		          	;  Eword               ...
	dc	$001000				;  Tword  
						;
	dc	$ffffff 			;  Eword N  |electrode = FF means end of table.
	dc	$000000				;  Tword N          unused really
;***********************************************;
;
;
;***********************************************;
;						;
; X: RAM ALLOCATION 				;
;						;
		org	x:0			;
X_BOTHDONE	dc 	0 			; Only have to load the encoders with the null table once per train.
X_FLAGS		dc 	0 			; address of flag to note R/Right side done, firsttime through, stop.
X_STptr		dc 	2000 			; Pointer to X/Right Stimuli Table
X_ATTEN		dc 	0 			; address of flag for noting first time through following reload
X_SUBTRACT	dc	0			; 
						;
; Sets Active El, Ref El, Amplitude of pulse N	;
X_CI24beginActive				; Encoder Table for CI24, Right
X_ActE	dc	20				; Active electrode (electrode #20)
X_RefE	dc	30				; Reference elec (MP1+2)
	dc	0,0				; Phase 1 duration (25 us)
	dc	188,0				; Inter-phase gap (45us)
X_AmpAE	dc	0				; Amplitude (0)
	dc	0,0				; Phase 2 duration (25 us)
	dc	5,0				; Inter-frame gap (8 us)
; This second section Sets Phase and IPG of pulse N (sets Active, Ref, Amp of N+1)
	dc	24				; Active electrode (MP1)
	dc	25				; Reference elec (MP2)
	dc	0,0				; Phase 1 duration (25 us)
	dc	188,0				; Inter-phase gap (8 us)
	dc	0				; Amplitude (0) -- THIS SHOULD ALWAYS BE ZERO
	dc	0,0				; Phase 2 duration (25 us)
	dc	5,0				; Inter-frame gap (8 us)
	dc	$80				; Encoder Halt bit, loaded in Active Elec location
X_CI24endActive					;
						;
X_CI24beginNull					; Power pulses only, Right.
	dc	20				; Active electrode (electrode #20)
	dc	30				; Reference elec (MP1+2)
	dc	0,0				; Phase 1 duration (25 us)
	dc	188,0				; Inter-phase gap (45 us)
	dc	0				; Amplitude (0) -- THIS SHOULD ALWAYS BE ZERO
	dc	0,0				; Phase 2 duration (25 us)
	dc	5,0				; Inter-frame gap (8 us)
	dc	$80				; Encoder Halt bit, loaded in Active Elec location
X_CI24endNull					;
;-----------------------------------------------;
temp_x0		ds	1			;
temp_x1		ds	1			;
temp_y1		ds	1			;
;-----------------------------------------------;
; Front Panel Knob parameters			;
; External Jack Input State			;
ExtInputState	dc	0			; Bit0 set for ring shorted to gnd
						; Bit0 cleared for ring open
;-----------------------------------------------;
						;
X_ATTEN24BIT	ds	1			;
X_SUBTRACT24BIT	ds	1			;
X_reserved2	ds	1			;
X_reserved3	ds	1			;
X_reserved4	ds	1			;
X_reserved5	ds	1			;
X_reserved6	ds	1			;
X_temp7		ds	1			;
;-----------------------------------------------;
; This location is a pointer to the beginning	;
; of the table which the code will output. It	;
; begins set to X_StimHead, but the user can	;
; rewrite this value to any location between	;
; X_StimHead and the end of usable X memory.	;
X_StimBegin	ds	1			;
;-----------------------------------------------;
X_StimHead 					;  Beginning of the X/Right side Stimuli Table
	dc	$14C81E				;  Eword 0 |elect #A|  AMP    |elec #R |
	dc	$009000				;  Tword 0 |TTNP (Time Till Next Pulse)|
	dc	$14C81E				;  Eword 1             ...
	dc	$009000				;  Tword 1             ...
	dc	$14C81E				;  Eword 2             ...
	dc	$009000				;  Tword 2
	dc	$14C81E				;  Eword 3
	dc	$009000				;  Tword 3
	dc	$14C81E				;  Eword 4
	dc	$009000				;  Tword 4
	dc	$14C81E				;  Eword 5
	dc	$009000				;  Tword 5
	dc	$14C81E				;  Eword 6
	dc	$009000				;  Tword 6
						;
	dc	$ffffff				;  Eword N
	dc	$000000				;  Tword N   unused really
;***********************************************;
;
;***********************************************;
;						;
; P: RAM ALLOCATION 				;
  						;
;-------------------------------		;
; Xilinx configuration data, including headers 	;
; and dummy bits.				;
						;
	org	p:$1000				; 
						;
;-------------------------------		;
XILDATACI24					;
        include 'Ci3p.a56'			;
XILDATACI24END					;
	dc	$FFFFFF				;
						;
XILDATACI22					;
	include 'Ci1p.a56'			;
XILDATACI22END					;
	dc	$FFFFFF				;
						;
;-------------------------------		;
; CI22 Encoder Initialisation Data 		;
	include	'Ci22init.a56'			;
						;
;-----------------------------------------------;
;
;
;***********************************************;
;						;
; Hardware reset vector				;
;						;
;***********************************************;
						;
	org     p:0		 		; RESET Vector
	jmp     Initialise_system		;
						;
	org	p:I_STACK			;
	nop					;
	nop					;
						;
	org	p:I_ILL				;
	nop					;
	nop					;
						;
	org	p:I_DBG				;
	nop					;
	nop					;
						;
	org	p:I_TRAP			;
	nop					;
	nop					;
						;
	org	p:I_NMI				;
	nop					;
	nop					;
						;
	org 	p:I_TIM0C			; Timer0 compare interrupt vector address
	move	b,x0		a,y:ENCSTRT24R	; Start Encoder and a
	             		  		; note that this interrupt happened.
 	org 	p:I_TIM0OF			; Timer0 overflow interrupt vector address
	move	b,x0		a,y:ENCSTRT24R	; Start Encoder and a
	             		  		; note that this interrupt happened.
						;
	org 	p:I_TIM1C			; Timer1 compare interrupt vector address
	move	b,x1		a,y:ENCSTRT24L	; Start Encoder and a
	             		  		; note that this interrupt happened.
 	org 	p:I_TIM1OF			; Timer1 overflow interrupt vector address
	move	b,x1		a,y:ENCSTRT24L	; Start Encoder and a
	             		  		; note that this interrupt happened.
						;
	org 	p:I_TIM2C			; Timer2 compare interrupt vector address
	jsr 	Timer2IntDelay			; 
						;
 	org 	p:I_TIM2OF			; Timer2 overflow interrupt vector address
 	jsr 	Timer2IntDelay			;
						;
	org	p:I_SI1RD			;
	jsr	CodecIntt			; SC1/Codec interrupt vector
						;
	org	p:I_SI1RDE			;
	jsr	CodecIntt			; SC1/Codec interrupt vector
						;
	org	p:I_SI1RLS			;
	jsr	CodecIntt			; SC1/Codec interrupt vector
						;
;-----------------------------------------------;
;
;***********************************************;
; Program Identification Name 			;
; Null terminated ascii string (12 characeters)	;
						;
	org	p:$100				;
; P:$100-$103 reserved for ProgramName		;
						;
ProgramName	dcb	'exp-0020',0,0,0,0	; 4 words (12 char) long	
						;
;-----------------------------------------------;
;
;***********************************************;
;						;
; Interrupt Service Routines			;
;						;
;-----------------------------------------------;
	org	p:$104				;
						;
; Codec Recieve/Transmitt int service routine	;
						;
CodecIntt					;
	move	a,y:save_aa  			; Save regs
	move	x0,y:save_x0  			;
	move	y0,y:save_y0  			;
						;
	movep	x:M_RX1,x0			; Get Codec Input
	if 	ENABLEDAC			;
	movep	x0,x:M_TX1			; send sample back to CODEC
	endif					;
						;
	jclr	#M_RFS,x:M_SSISR1,Right_Side	; use Frame Sync to determine which channel present
						;
;Left_Side					;
	; x0 = left input			;
	move	y:save_x0,x0			; Restore regs
	move	y:save_y0,y0			;
	move	y:save_aa,a			;
	rti					;
						;
Right_Side 					;
	; x0 = right input			;
	move	y:save_x0,x0			; Restore regs
	move	y:save_y0,y0			;
	move	y:save_aa,a			;
	rti					;
						;
;--------------------------------		;
Timer2IntDelay 					;
	bclr	#M_TE,x:M_TCSR2			; Disable timer2, but this is not
	move	#$FFFF,r4			; used in this code anyway.
	rti					; 
;-----------------------------------------------;
;
;
;***********************************************;
;						;
; Main entry point				;
;						;
;***********************************************;
						;
Initialise_system				;
						;
;-------------------------------		;
; Reset Mode regsiters				;
	move	#-1,m0 				; linear
	move	#-1,m1				;
	move	#-1,m2				;
	move	#-1,m3				;
	move	#-1,m4				;
	move	#-1,m5				;
	move	#-1,m6				;
	move	#-1,m7				;
						;
;-----------------------------------------------;
; Initialise DSP Core Frequency			;
; This is the PLL control register, PCTL, shown ;
; with the value 0E0000:                        ;
; +--------------------------------------------------+
; |23  22  21  20  19  18   17   16   15  14  13  12 |
; +--------------------------------------------------+
; |PD3|PD2|PD1|PD0|COD|PEN|PSTP|XTLD|XTLR|DF2|DF1|DF0|
; +--------------------------------------------------+
;   0   0   0   0   1   1   1    0    0    0   0   0   PD3-0 all zero means a predivide factor of 1.
; +--------------------------------------------------+
; | 11    10  9   8   7   6   5   4   3   2   1   0  |
; +--------------------------------------------------+
; |MF11|MF10|MF9|MF8|MF7|MF6|MF5|MF4|MF3|MF2|MF1|MF0 |
; +--------------------------------------------------+
;   0     0   0   0   0   0   0   0   0   0   0   0    All zeros means a multiplication factor of 1.
;-----------------------------------------------;
	movep	#CF14_7M,x:M_PCTL  		; Set DSP Core Freq, 14.7MHz
						; Not required as ShaLo sets Fc=14.7MHz
						;
	delay50us	1000			; Delay for 50ms while PLL settles
						;
;-------------------------------		;
; Set wait states in ext. mem, PEROM, etc	;
	movep	#WAITSTATES,x:M_BCR		; 
						;
;-------------------------------		;
; Setup ESSI0 and ESSI1 (SC0, SC1) for CODEC	;
;  sampling frequency				;
        movep   #ESSI_SCI0,x:M_CRA0		; Serial Clock
        movep   #ESSI_SCI1,x:M_CRA1		; Data Clock
						;
;-------------------------------		;
;Flash Bottom LED 3 times to indicate user	;
;program running in Spear Rev3			;
	do	#6,end_flash_led		; flash the led 3 times 
	bchg	#LEDBIT,x:M_HDR			;
	nop					;
	delay50us      2000			; 100ms delay
	nop					;
end_flash_led					;
	bset	#LEDBIT,x:M_HDR			;
						;
						;
						;
; Put in initial values.                        ;
;-----------------------------------------------;
						;
	bclr	#RELOAD,y:Y_RELOAD		; Clear so as to not pop into doRELOAD on startup.
	bset	#DONE,x:X_FLAGS			; Set 1 to be done.
	bset	#DONE,y:Y_FLAGS			; Set 1 to be done.
	bclr	#DONE,x:X_BOTHDONE		; Set 1 to be done.
						;
;-----------------------------------------------;
; X_STptr and Y_STptr are pointers to the stimulus tables. These are the pointers used at run time.
; In order to allow the host SW to select sections of the table to be output, effectively treating
; the tables as multiple smaller tables, the code must read the values of X_STptr and Y_STptr
; from host SW programmable locations. The locations X_StimBegin and Y_StimBegin are where
; X_STptr and Y_STptr are loaded from. The code initializes X_STptr and Y_STptr to X_StimHead
; and Y_StimHead.
						;
	move	#>X_StimHead,a			; Initially begin at the head of the table.
	nop					;
	move	a,x:X_StimBegin			;
	nop					;
	move	a,x:X_STptr			;
	nop					;
	move	#>Y_StimHead,a			; Initially begin at the head of the table.
	nop					;
	move	a,y:Y_StimBegin			;
	nop					;
	move	a,y:Y_STptr			;
;-----------------------------------------------;
	move	#0,x0				; 
	move	#0,x1				; 
	move	#0,r2				;
	move	#0,r4				;
;-----------------------------------------------;
; Code for attenuator and subtractor		;
; NOTE on the values. The values below correspond to the user view, not the ALU view. These will
; be converted in the right and left initialization blocks (;iR; and ;iL;) to the ALU's format
; of fractional data representation. Notes (from section 3.3 of the DSP56300 Family Manuali):
; The 56300 only knows one kind of data in the Data ALU
;
;
;
;
;-----------------------------------------------;
	move	#0,a				; 
	nop					;
	move	a,x:X_SUBTRACT			; Begin subtracting Zero by default
	move	a,y:Y_SUBTRACT			;
	move	a,x:X_SUBTRACT24BIT		; Begin subtracting Zero by default
	move	a,y:Y_SUBTRACT24BIT		;
	move	#255,a				;
	nop					;
	move	a,x:X_ATTEN			; Begin with a multiplication factor of 1 by default
	move	a,y:Y_ATTEN			;
	move	a,x:X_ATTEN24BIT		; Begin with a multiplication factor of 1 by default
	move	a,y:Y_ATTEN24BIT		;
;-----------------------------------------------;
; TIMER MODEL  TIMER MODEL  TIMER MODEL  TIMER MODEL  TIMER MODEL  TIMER MODEL  ;
; Two registers COMMON to all three timers:
; M_TPLR   EQU     $FFFF83         ; TIMER Prescaler Load Register
; +-----------------------------------------------------------------------------+
; |0|PS1|PS0|                      PL20-PL0                                     |
; +-+---+---+-------------------------------------------------------------------+
;   Prescaler                 This is the value loaded into the prescaler.
;     Clock
;    Source
;   | 0 | 0 | Internal CLK/2. Power up default.
;   | 0 | 1 | TIO0
;   | 1 | 0 | TIO1
;   | 1 | 1 | TIO2
;
; M_TPCR   EQU     $FFFF82         ; TIMER Prescalar Count Register ; READ ONLY
; +-----------------------------------------------------------------------------+
; |0|0|0|                          PC20-PC0                                     |
; +-----------------------------------------------------------------------------+
;
; TIMERx:
; M_TCSRx  EQU     --------        ; TIMERx Control/Status Register
; 002a04 is:
;  __________  _______   _________   ___________   _____________  _____________
;  0 0  0   0  0 0 0 0   0  0  1 0   1  0  1   0   0   0   0   0  0   1   0   0
;  | |  |   |  | | | |   |  |  | |   |  |  |   |   |   |   |   |  |   |   |   | 
; +-----------------------------------------------------------------------------+
; |0|0|TCF|TOF|0|0|0|0||PCE|0|DO|DI|DIR|0|TRM|INV|TC3|TC2|TC1|TC0|0|TCIE|TOIE|TE|
; +-----------------------------------------------------------------------------+
;       |   |            |     | |   |     |   | |   |   |   |   |    |   |   | 
;       |   |            |     | |   |     |   | |   |   |   |   |    |   |   +-Timer Enable
;       |   |            |     | |   |     |   | |   |   |   |   |    |   |     Clear Timer count and
;       |   |            |     | |   |     |   | |   |   |   |   |    |   |     count accd to TC[3:0]
;       |   |            |     | |   |     |   | |   |   |   |   |    |   +-Timer Overflow Interrupt Enable
;       |   |            |     | |   |     |   | |   |   |   |   |    +-Timer Compare Interrupt Enable.
;       |   |            |     | |   |     |   | |   |   |   |   |      If TCPR=N and TLR=M, generate an
;       |   |            |     | |   |     |   | |   |   |   |   |      interrupt after N-M+1 counts.
;       |   |            |     | |   |     |   | |   |   |   |   |
;       |   |            |     | |   |     |   | +---+---+---+---+-Timer Control Bits
;       |   |            |     | |   |     |   | | 0 | 0 | 0 | 0 +-mode0. Timer and GPIO, internal clock
;       |   |            |     | |   |     |   | | 0 | 0 | 0 | 1 +-mode1. Timer pulse,    internal clock
;       |   |            |     | |   |     |   | | - | - | - | - +-mode-. remainder not shown
;       |   |            |     | |   |     |   | ~~~~~~~~~~~~~~~~~
;       |   |            |     | |   |     |   | 
;       |   |            |     | |   |     |   +-Input polarity on TIO input. See DIR. 
;       |   |            |     | |   |     +-Timer Reload Mode. In mode0-3 et al, the counter is preloaded
;       |   |            |     | |   |       with TLR after TE set and first clock. If TRM, automatically 
;       |   |            |     | |   |       If TRM set, auto reload counter when TCR==TCPR, else freerun.
;       |   |            |     | |   +-O/I
;       |   |            |     | +-TIO
;       |   |            |     +-TIO
;       |   |            +-1/0, Prescaler/(CLK/2 or external TIO)
;       |   +-Timer Overflow Flag
;       +-Timer Compare Flag
; 
; M_TLRx   EQU     --------        ; TIMERx Load Reg
; +-----------------------------------------------------------------------------+
; |                                TLR23-TLR0                                   |
; +-----------------------------------------------------------------------------+
; 
; M_TCPRx  EQU     --------        ; TIMERx Compare Register
; +-----------------------------------------------------------------------------+
; |                               TCPR23-TCPR0                                  |
; +-----------------------------------------------------------------------------+
; 
; M_TCRx   EQU     --------        ; TIMERx Count Register
; +-----------------------------------------------------------------------------+
; |                                TCR23-TCR0                                   |
; +-----------------------------------------------------------------------------+
;
; The CPU clock rate is 14.7MHz, or 0.06803 usec period.
; CLK/2 is 7.35MHz, or 0.13605 usec period.
; 200 Hz is a divide down of 36750, and
; 201 Hz is a divide down of 36567.16. Going for 36567 gives 201.00090, so that
; ought to do.
; 
; If TCPR=N and TLR=M, generate an interrupt after N-M+1 counts.
; Count up from M to N.
; 
; 7.35e6/36750 = 200Hz.  36750 is 0x08F8E.
; 7.35e6/36567 = 201Hz.  36567 is 0x08ED7.
;
; Stoph argues proper time is 0.13563368 per tick
; 250 Hz is 29491 is 0x07333
;
; 100 Hz is 73728 is 0x12000
;-----------------------------------------------;
						;
	        				; #$249F0 is 150,000 base 10. Subtract desired TTNP from this
;-------------------------------		; to get the Tword value.
; Initialise Timer0, Right Side			; provide a periodic interrupt
	movep	#$000A04,x:M_TCSR0		; disable timer0, enable compare intt
	movep	#0,x:M_TLR0			; reset timer0 reload register
	movep   #$249F0,x:M_TCPR0		; this is driven by a clk/2 prescaler
;	movep   #TERMINALCOUNT,x:M_TCPR0	; this is driven by a clk/2 prescaler
						;
; Initialise Timer1, Left side			; provide a periodic interrupt
	movep	#$000A04,x:M_TCSR1		; disable timer1, enable compare intt
	movep	#0,x:M_TLR1			; reset timer1 reload register
	movep   #$249F0,x:M_TCPR1		; this is driven by a clk/2 prescaler
;	movep   #TERMINALCOUNT,x:M_TCPR1	; this is driven by a clk/2 prescaler
						;
 	movep	#$000A04,x:M_TCSR2		; disable timer2, enable compare intt
;-------------------------------		;
; Xilinx Configuration				;
						;
; Configure Xilinx with Encoder configurations	;
	jsr	ConfigureEncoders		;
						;
;-------------------------------		;
; Setup AAR registers for Xilinx Chip Enable	;
;  (via A14)					;
	movep	#$100431,x:M_AAR2		; map Left  Xilinx Encoder from addr X or Y:$100000 upwards
	movep	#$200431,x:M_AAR3		; map Right Xilinx Encoder from addr X or Y:$200000 upwards
						;
;-------------------------------		;
; Set Digital Pot Gain to minimum (-24dB),	;
;  64 Gain steps available, maximum 0dB 	;	
						;
	do	#80,DPotLoop			; 80 loops to be sure min gain set
	jsr	DPotDown			;
DPotLoop					;
						;
;-------------------------------		;
; Initialise Encoder RAM for test stimulation	;
	jsr	InitEncoderL			;
	jsr	InitEncoderR			;
	move	#0,x0				; 
	move	#0,x1				; 
						;
;-------------------------------		;
; Set Interrupt Priority,    			;
; this will Unmask interrupts			;
; Interrupt Priority Levels bits in the		;
;Interrupt Priority Register P(eripheral).	;
;  IPL1 IPL0					;
;   0    0   disabled				;
;   0    1   IPL = 1				;
;   1    0   IPL = 2				;
;   1    1   IPL = 3				;
;						;
; +----------------------------------------------------------+
; | 23-10  | 9  | 8  | 7  | 6  | 5  | 4  | 3  | 2  | 1  | 0  |
; |reserved|T0L1|T0L0|SCL1|SCL0|S1L1|S1L0|S0L1|S0L0|HPL1|HPL0|
; +----------------------------------------------------------+
	movep	#>$0001E0,x:M_IPRP		; set IPL's (SCI=2,ESSI1=1,Timer=0,ESSIO=NE,HOST=NE)
						;
;-------------------------------		;
	jsr	LedOff 				; Turn Bottom LED off
;-----------------------------------------------;
;
;***********************************************;
;						;
; MAIN Main main				;
;						;
;***********************************************;
; Go around MainLoop forever ....		;
;						;
;						;
; The code in the MainLoop is about interrupt 	;
; enable management. Functionally, actions 	;
; depend on interrupts from timers previously 	;
; set up, and set up with TTNP values from the	;
; Stimuli Tables				;
;						;
; MainLoop checks the RELOAD bit each loop.	;
; This code can only clear the RELOAD bit.	;
; The process from RELOAD set is ...		;
; Load X/Right Eword. If Active electrode == $ff, disable Right.
; Load Y/Left  Eword. If Active electrode == $ff, disable Left.
; While either side is not done, load the TTNP 	;
; into the timer interrupt count reg and start	;
; the timer, "prefetch" the next TTNP and wait.	;
;						;
; When both sides make thier final pass and are	;
; DONE, the code waits for the next RELAOD.	;
;						;
;
; Actually, I'm going to draw anothr picture. This code has the same control structure as the
; sprcbuxx code and since I wrote it and had to go back and decipher it by drawing out the 
; flow chart I lost, I'll not lose it again. Here it is. I've put the labels on the far left
; to match the actual labels in the code:
;  
;  
;                        _______________________________________
;                       /                                       \
;                       |                                        |
;                       v                                        |
;  MainLoop     Time to RELOAD?                                  |
;                 |      \                                       |
;                 N       Y                                      |
;                 |        \                                     ^
;                 |         \                                    |
;                 |      +--------------------------------+      |
;                 |      | reinit, rewite, reload         |      |
;                 |      +--------------------------------+      |
;                 |         /                                    |
;                 |        /                                     |
;                 |       /                                      |
;                 |      /                                       |
;  NoReload   Is the Right side done?                            |
;                 |      \                                       ^
;                 Y       N                                      |
;                 |        \                                     |
;                 |         \                                    |
;                 |      +--------------------------------+      |
;                 |      | Do right side stuff, like check|      |
;                 |      | if a Right side int happened   |      |
;                 |      +--------------------------------+      |
;                 |         /                                    |
;                 |        /                                     |
;                 |       /                                      |
;                 |      /                                       |
;  go_Left    Is the Left  side done?                            |
;                 |      \                                       |
;                 Y       N                                      ^
;                 |        \                                     |
;                 |         \                                    |
;                 |      +--------------------------------+      |
;                 |      | Do left side stuff, like check |      |
;                 |      | if a Left side int happened    |      |
;                 |      +--------------------------------+      |
;                 |         /                                    |
;                 |        /                                     |
;                 |       /                                      |
;                 |      /                                       |
;  go_on      Is the Right side done?                            |
;                 |     \                                        |
;                 N      Y                                       |
;                 |       \                                      |
;                 |  Is the Left side done?                      |
;                 |     |   \                                    ^
;                 |     N    Y                                   |
;                 |     |     \                                  |
;                 |     |      \                                 |
;                 |     |    +----------------------------+      |
;                 |     |    | Produce some Null Pulses   |      |
;                 |     |    +----------------------------+      |
;                 |     |      |                                 |
;                 |     |      |                                 |
;                 |     |      |                                 |
;                 |     |      |                                 |
;  here            \_____\_____\________________________________/
;  
;  
;-----------------------------------------------;
	bclr	#LEDBIT,x:M_HDR			; Turn on the LED as a "done" indicator
	bclr	#M_TE,x:M_TCSR2			; Disable timer2 interrupt because it is not used.
	bset	#FIRSTTIME,x:X_FLAGS		; just to know the values
	bset	#FIRSTTIME,y:Y_FLAGS		; just to know the values
	bset	#E3RESETBitLeft,x:M_HDR		; Release Reset Left  encoder
	bset	#E3RESETBitRight,x:M_HDR	; Release Reset Right encoder
	jsr	EncBusyLeft			; Wait while Left  encoder is busy
	jsr	LoadEncLeftNull			; Load Stimulus Params into Left  encoder
	jsr	EncBusyRight			; Wait while Left  encoder is busy
	jsr	LoadEncRightNull		; Load Stimulus Params into Left  encoder
MainLoop					;
	jclr	#RELOAD,y:Y_RELOAD,NoRELOAD 	;i; If !clr, the SW from above has written to the RELOAD bit.
						;i; This will cause a reload of timer count values, a reload
						;i; of the xilinx encoders, etc,
	bclr	#RELOAD,y:Y_RELOAD		;i; Do this code once per RELOAD, so clear this flag right away.
	bset	#LEDBIT,x:M_HDR			;i; Turn LED off.
	bclr	#DONE,x:X_BOTHDONE		;i; Set internal flag to note done.
						;i;
	bclr	#STOPNOW,x:X_FLAGS		;i; Set 0, neither side done, as it is just starting (over).
	bclr	#STOPNOW,y:Y_FLAGS		;i; 
	bset	#FIRSTTIME,x:X_FLAGS		;i;
	bset	#FIRSTTIME,y:Y_FLAGS		;i;
						;i;
	bclr	#DONE,x:X_FLAGS			;i; Set 0, neither side done, as it is just starting (over).
	bclr	#DONE,y:Y_FLAGS			;i; 
						;i;
	move	#$FFFFFF,b			;i; Initialize flags.
 	;-------------------------;		;i;
 	; NOTE: Don't touch acc B ;		;i;
 	;        E V E R          ;		;i;
 	;-------------------------;		;i;
	move	x:X_StimBegin,a			;i; Begin at whatever address was loaded in X_StimBegin.
	nop					;i;
	move	a,x:X_STptr			;i;
	nop					;i;
	move	y:Y_StimBegin,a			;i; Begin at whatever address was loaded in Y_StimBegin.
	nop					;i;
	move	a,y:Y_STptr			;i;
	move	#0,x0				;i; flag for noting a right side, Timer0, interrupt occured.
	move	#0,x1				;i; flag for noting a left  side, Timer1, interrupt occured.
;-----------------------------------------------;i;
						;i; This section is for the first prefetch from the Stimuli
						;i; tables. Load the TTNP so that the next value it loaded 
						;i; automatically after the timer counts down, and load the
						;i; Encoder Table data so that there is no delay getting it
						;i; in place when it is needed.
						;i; The X-prefetch sequence ...
						;i;
; setup for the X/right side following RELOAD.	;iR;
	move	x:X_STptr,r1			;iR; get XEWord: contents of X_STptr to r1, 
	nop					;iR;
	nop					;iR;
	nop					;iR;
	nop					;iR;
	move 	x:(r1),a			;iR; and what is pointer to into acc a
	nop					;iR;
	jclr	#23,a,xInitloadET		;iR; see if Active electrode is 1xxxxxxx (invalid)
	bset	#DONE,x:X_FLAGS			;iR; then this side won't even start.
	jmp	>dont_even_startX		;iR;
xInitloadET					;iR;
	move	a,x:X_temp7			;iR; just to hold Eword temporarly
	nop					;iR;
	lsr	#16,a				;iR; Shift the upper byte to the bottom
	nop					;iR; (lsr left fills with zeros).
	move	a,x:X_ActE			;iR; Store it as the Active electrode in the ETable
;-----------					;iR;
	move	x:X_temp7,a			;iR; Get back the Eword
	nop					;iR;
	lsr	#8,a				;iR; Shift the middle byte to the bottom.
	nop					;iR;
	and     #$0000FF,a                      ;iR; Mask off middle (and upper, while I'm at it).
	nop					;iR;
;-----------------------------------------------;iR;
; Code for attenuator and subtractor		;iR;
;-----------------------------------------------;iR;
	move	a,x:X_AmpAE			;iR; Store it as the Active electrode amplitude in the ETable
						;iR;
;-----------					;iR;
	move	x:X_temp7,a			;iR; Get back the Eword
	nop					;iR;
	and     #$0000FF,a                      ;iR; Mask off middle and upper bytes
	nop					;iR;
	move	a,x:X_RefE			;iR; Store it as the reference electrode.
;-----------					;iR;
	move	r1,a				;iR; time to increment to TTNP
	nop					;iR;
	add	#1,a				;iR; acc apoints to TTNP
	nop					;iR;
	move 	a,r1				;iR; now r1 points to TTNP
	nop					;iR;
	add	#1,a				;iR; now a points to next Eword, and should be stored away
	nop					;iR;
	move	a,x:X_STptr			;iR;
	nop					;iR;
	move 	x:(r1),a			;iR; Get the TTNP
	movep   a,x:M_TLR0			;iR; and into timer (but don't start it yet)
	jsr	EncBusyRight			;iR; Wait while Right encoder is busy
	jsr	LoadEncRightActive		;iR; Load Stimulus Params into Right encoder (but don't start it yet)
						;iR; Destroys contents of registers r0, r1, x1
	bset	#FIRSTTIME,x:X_FLAGS		;iR; note that this is the first time for this pulse train.
dont_even_startX				;iR;
;-----------------------------------------------;i;
; setup for the Y/left side following RELOAD.	;iL;
	move	y:Y_STptr,r1			;iL; get YEWord: contents of Y_STptr to r1, 
	nop					;iL;
	nop					;iL;
	nop					;iL;
	nop					;iL;
	move 	y:(r1),a			;iL; and what is pointer to into acc a
	nop					;iL;
	jclr	#23,a,yInitloadET		;iL; see if Active electrode is 1xxxxxxx (invalid)
	bset	#DONE,y:Y_FLAGS			;iL; then this side won't even start.
	jmp	>dont_even_startY		;iL;
yInitloadET					;iL;
	move	a,y:Y_temp7			;iL; just to hold Eword temporarly
	nop					;iL;
	lsr	#16,a				;iL; Shift the upper byte to the bottom
	nop					;iL; (lsr left fills with zeros).
	move	a,y:Y_ActE			;iL; Store it as the Active electrode in the ETable
;-----------					;iL;
	move	y:Y_temp7,a			;iL; Get back the Eword
	nop					;iL;
	lsr	#8,a				;iL; Shift the middle byte to the bottom.
	nop					;iL;
	and     #$0000FF,a                      ;iL; Mask off middle (and upper, while I'm at it).
	nop					;iL;
;-----------------------------------------------;iL;
; Code for attenuator and subtractor		;iL;
;-----------------------------------------------;iL;
	move	a,y:Y_AmpAE			;iL; Store it as the Active electrode amplitude in the ETable
						;iL;
;-----------					;iL;
	move	y:Y_temp7,a			;iL; Get back the Eword
	nop					;iL;
	and     #$0000FF,a                      ;iL; Mask off middle and upper bytes
	nop					;iL;
	move	a,y:Y_RefE			;iL; Store it as the reference electrode.
;-----------					;iL;
	move	r1,a				;iL; time to increment to TTNP
	nop					;iL;
	add	#1,a				;iL; acc apoints to TTNP
	nop					;iL;
	move 	a,r1				;iL; now r1 points to TTNP
	nop					;iL;
	add	#1,a				;iL; now a points to next Eword, and should be stored away
	nop					;iL;
	move	a,y:Y_STptr			;iL;
	nop					;iL;
	move 	y:(r1),a			;iL; Get the TTNP
	movep   a,x:M_TLR1			;iL; and into timer (but don't start it yet)
	jsr	EncBusyLeft 			;iL; Wait while Right encoder is busy
	jsr	LoadEncLeftActive		;iL; Load Stimulus Params into Left encoder (but don't start it yet)
						;iL; Destroys contents of registers r0, r1, x1
	bset	#FIRSTTIME,y:Y_FLAGS		;iL; note that this is the first time for this pulse train.
        bset    #M_TE,x:M_TCSR1                 ;iL; enable timer1, Left  side interrupt
dont_even_startY				;iL;
	jset	#DONE,x:X_FLAGS,NoRELOAD	;iR; and finally, if to be done at all, 
        bset    #M_TE,x:M_TCSR0                 ;iR; enable timer0, Right side interrupt
						;i;
;-----------------------------------------------;
NoRELOAD					;
						;
	jset	#DONE,x:X_FLAGS,go_Left		; If set then Right side has detected a 0xFF as an electrode number
	jset	#FIRSTTIME,x:X_FLAGS,fakeXint	; 
						; and now should be doing Null pulses.
	jclr	#INTFLAG,x0,go_Left		; Has the ISR set the INTFLAG bit?
	move	#0,x0				; ISR has indeed set the INTFLAG bit. Clear Flag.
	jsr	EncBusyRight			; Wait while Right encoder is busy
	jsr	LoadEncRightActive		; Load Stimulus Params into Right encoder (but don't start it yet)
	jclr	#STOPNOW,x:X_FLAGS,dont_stop_yetR	; 
						; shutdown Right side, stop interrupt timer, set done.
	bclr	#M_TE,x:M_TCSR0			; disable timer0, as a 0xFF electrode number is detected.
	bset	#DONE,x:X_FLAGS			;
	jmp	>go_Left			;
dont_stop_yetR					;
						; The X-prefetch sequence ...
fakeXint					;
	bclr	#FIRSTTIME,x:X_FLAGS		;
; setup for the X/right side.			;
	move	x:X_STptr,r1			; get XEWord: contents of X_STptr to r1, 
	nop					;
	nop					;
	nop					;
	nop					;
	move 	x:(r1),a			; and what is pointer to into acc a
	nop					;
	jclr	#23,a,xloadET			; see if Active electrode is 1xxxxxxx (invalid)
	bset	#STOPNOW,x:X_FLAGS		; If this is the marker to stop, and because the values are preloaded,
						; the timer is running now for the last valid pulse. So the timer cannot 
						; be stopped at this time. There must be a flag in place to note that the timer
						; should be stopped and it should be checked when the interrput is detected.
						; That flag is is called X/Y_STOPNOW
	jmp	>dont_continue_preload_X	;
xloadET						;
	move	a,x:X_temp7			; just to hold Eword temporarly
						;
	nop					;
	lsr	#16,a				; Shift the upper byte to the bottom
	nop					; (lsr left fills with zeros).
	move	a,x:X_ActE			; Store it as the Active electrode in the ETable
;-----------					;
	move	x:X_temp7,a			; Get back the Eword
	nop					;
	lsr	#8,a				; Shift the middle byte to the bottom.
	nop					;
	and     #$0000FF,a                      ; Mask off middle (and upper, while I'm at it).
	nop					;
;-----------------------------------------------;
; Code for attenuator and subtractor		;
;-----------------------------------------------;
	move	a,y0				; The amplitude from the table into y0,
	move	x:X_ATTEN24BIT,y1		; Operate on X_ATTEN24BIT and
	move	x:X_SUBTRACT24BIT,a		; X_SUBTRACT24BIT, setup for MAC
	mac	y0,y1,a				;
	bsge	a_not_negative_X			; check for negative value
	move	#0,a				;
a_not_negative_X					;
	nop					;
	move	y0,x:X_AmpAE			; Store it as the Active electrode amplitude in the ETable
	nop					;
;-----------					;
	move	x:X_temp7,a			; Get back the Eword
	nop					;
	and     #$0000FF,a                      ; Mask off middle and upper bytes
	nop					;
	move	a,x:X_RefE			; Store it as the reference electrode.
;-----------					;
	move	r1,a				; time to increment to TTNP
	nop					;
	add	#1,a				; acc apoints to TTNP
	nop					;
	move 	a,r1				; now r1 points to TTNP
	nop					;
	add	#1,a				; now a points to next Eword, and should be stored away
	nop					;
	move	a,x:X_STptr			;
	nop					;
	move 	x:(r1),a			; Get the TTNP
	movep   a,x:M_TLR0			; 
						; Destroys contents of registers r0, r1, x1
dont_continue_preload_X				;
;-----------------------------------------------;
go_Left						;
						; The Y-prefetch sequence ...
	jset	#DONE,y:Y_FLAGS,go_on		; If set then Left side has detected a 0xFF as an electrode number
	jset	#FIRSTTIME,y:Y_FLAGS,fakeYint	; 
						; and now should be doing Null pulses.
	jclr	#INTFLAG,x1,go_on		; Has the ISR set the INTFLAG bit?
	move	#0,x1				; ISR has indeed set the INTFLAG bit. Clear Flag.
	jsr	EncBusyLeft			; Wait while Left  encoder is busy
	jsr	LoadEncLeftActive		; Load Stimulus Params into Left  encoder (but don't start it yet)
	jclr	#STOPNOW,y:Y_FLAGS,dont_stop_yetL	; 
						; shutdown Left side, stop interrupt timer, set done.
	bclr	#M_TE,x:M_TCSR1			; disable timer1, as a 0xFF electrode number is detected.
	bset	#DONE,y:Y_FLAGS			;
	jmp	>go_on				;
dont_stop_yetL					;
						; The X-prefetch sequence ...
fakeYint					;
	bclr	#FIRSTTIME,y:Y_FLAGS		;
; setup for the Y/left side.			;
	move	y:Y_STptr,r1			; get YEWord: contents of Y_STptr to r1, 
	nop					;
	nop					;
	nop					;
	nop					;
	move 	y:(r1),a			; and what is pointer to into acc a
	nop					;
	jclr	#23,a,yloadET			; see if Active electrode is 1xxxxxxx (invalid)
	bset	#STOPNOW,y:Y_FLAGS		; If this is the marker to stop, and because the values are preloaded,
						; the timer is running now for the last valid pulse. So the timer cannot 
						; be stopped at this time. There must be a flag in place to note that the timer
						; should be stopped and it should be checked when the interrput is detected.
						; That flag is is called X/Y_STOPNOW
	jmp	>dont_continue_preload_Y	;
yloadET						;
	move	a,y:Y_temp7			; just to hold Eword temporarly
						;
	nop					;
	lsr	#16,a				; Shift the upper byte to the bottom
	nop					; (lsr left fills with zeros).
	move	a,y:Y_ActE			; Store it as the Active electrode in the ETable
;-----------					;
	move	y:Y_temp7,a			; Get back the Eword
	nop					;
	lsr	#8,a				; Shift the middle byte to the bottom.
	nop					;
	and     #$0000FF,a                      ; Mask off middle (and upper, while I'm at it).
	nop					;
;-----------------------------------------------;
; Code for attenuator and subtractor		;
;-----------------------------------------------;
	move	a,y0				; The amplitude from the table into y0,
	move	y:Y_ATTEN24BIT,y1		; Operate on X_ATTEN24BIT and
	move	x:X_SUBTRACT24BIT,a		; X_SUBTRACT24BIT, setup for MAC
	mac	y0,y1,a				;
	bsge	a_not_negative_Y		; check for negative value
	move	#0,a				;
a_not_negative_Y				;
	nop					;
	move	y0,y:Y_AmpAE			; Store it as the Active electrode amplitude in the ETable
	nop					;
;-----------					;
	move	y:Y_temp7,a			; Get back the Eword
	nop					;
	and     #$0000FF,a                      ; Mask off middle and upper bytes
	nop					;
	move	a,y:Y_RefE			; Store it as the reference electrode.
;-----------					;
	move	r1,a				; time to increment to TTNP
	nop					;
	add	#1,a				; acc apoints to TTNP
	nop					;
	move 	a,r1				; now r1 points to TTNP
	nop					;
	add	#1,a				; now a points to next Eword, and should be stored away
	nop					;
	move	a,y:Y_STptr			;
	nop					;
	move 	y:(r1),a			; Get the TTNP
	movep   a,x:M_TLR1			; 
						; Destroys contents of registers r0, r1, x1
dont_continue_preload_Y				;
;-----------------------------------------------;
go_on						;
	jclr	#DONE,x:X_FLAGS,here		; That is, jump if the X/R side is NOT done yet.
	jclr	#DONE,y:Y_FLAGS,here		; That is, jump if the Y/L side is NOT done yet.
	jsr	EncBusyLeft			; Right and Left are both done.
	jsr	EncBusyRight			; 
        jset    #DONE,x:X_BOTHDONE,btdt		; Load the Null stuff, once. Changed by STOPH CJL
	jsr	LoadEncRightNull		; Load Stimulus Params into Right encoder. Destroys contents of r0, r1, x1
	jsr	LoadEncLeftNull			; Load Stimulus Params into Left  encoder. Destroys contents of r0, r1, x1
	bclr	#LEDBIT,x:M_HDR			; Turn on the LED as a "done" indicator
	bset	#DONE,x:X_BOTHDONE		; 
btdt						;
						; Here doing Null pulses
	move	a,y:ENCSTRT24R			; Write any value to Start Encoder
	move	a,y:ENCSTRT24L			; Write any value to Start Encoder
here						;
	jmp	>MainLoop			;
						;
						;
;***********************************************;
;
;
;
;***********************************************;
; SubRoutines 					;
;***********************************************;
; Cheap Debug LED blinkers  			;
;						;
;-------------------------------		;
; Led subroutine (Bottom LED M)			;  
;  Note,top LED controlled by ShaLo 		;
						;
FlashFast					;
	bclr	#LEDBIT,x:M_HDR			;
	delay50us	200			;
	bset	#LEDBIT,x:M_HDR			;
	delay50us	200			;
	bclr	#LEDBIT,x:M_HDR			;
	delay50us	200			;
	bset	#LEDBIT,x:M_HDR			;
	delay50us	200			;
	bclr	#LEDBIT,x:M_HDR			;
	delay50us	200			;
	bset	#LEDBIT,x:M_HDR			;
	delay50us	200			;
	bclr	#LEDBIT,x:M_HDR			;
	delay50us	200			;
	bset	#LEDBIT,x:M_HDR			;
	delay50us	200			;
	bclr	#LEDBIT,x:M_HDR			;
	delay50us	200			;
	bset	#LEDBIT,x:M_HDR			;
	delay50us	200			;
	rts					;
						;
;-------------------------------		;
FlashSlow					;
	bclr	#LEDBIT,x:M_HDR			;
	delay50us	2000			;
	bset	#LEDBIT,x:M_HDR			;
	delay50us	2000			;
	bclr	#LEDBIT,x:M_HDR			;
	delay50us	2000			;
	bset	#LEDBIT,x:M_HDR			;
	delay50us	2000			;
	bclr	#LEDBIT,x:M_HDR			;
	delay50us	2000			;
	bset	#LEDBIT,x:M_HDR			;
	delay50us	2000			;
	rts					;
						;
;-------------------------------		;
; Front Panel SubRoutines 			;
;						;
						;
;-------------------------------		;
; Led subroutine (Bottom LED M)			;  
;  Note,top LED controlled by ShaLo 		;
						;
LedOn						;
	bclr	#LEDBIT,x:M_HDR			;
	rts					;
						;
LedOff						;
	bset	#LEDBIT,x:M_HDR			;
	rts					;
						;
						;
;-------------------------------		;
; Steps Digital Pot Gain Down by one step	;
DPotDown					;
	bset	#GAIN_UP,x:M_PDRC  		; keep input digital POT step-up-gain pin high
	bclr	#GAIN_DN,x:M_PDRC		; make input digital POT step downp in gain
	delay50us	20			; 1 ms delay 
	bset	#GAIN_DN,x:M_PDRC	 	;
	delay50us	20			; 1 ms delay 
	rts					;
						;
;-----------------------------------------------;
;
;***********************************************;
; Encoder Subroutines 				;
;						;
						;
;-------------------------------		;
ConfigureEncoders				;
						;
	movep	#(E3CLK),x:M_HDR		; preset CLK as a 1, already done by ShaLo 
	delay50us	800			; 40ms delay
						;
	movep	#(E3CLK|E3PDOWNLeft|E3PDOWNRight),x:M_HDR ;preset CLK as a 1, already done by ShaLo 
						;
; Wait 40ms					;
	delay50us	800    			; Wait 40ms delay						
						;
; Reset Xilinx device				;
; ( /RESET line already set low above )		;
						;
	movep	#(E3CLK|E3PDOWNLeft|E3PDOWNRight|E3RESETLeft|E3RESETRight),x:M_HDR ;release reset Xilinx 
						;
	delay50us	2			; 0.1ms delay
						;
; Send an initial reset pulse with P/Done low in;
; case the Xilinx is still in a confused powerup;
; initialisation state...			;
; Pulse reset low then high again for 6ms each  ;
; while holding P/Done low			;
;		   				;	
; First take P/Done line low to initiate Xilinx	;
;  configuration mode				;
	movep	#$7FFD,x:M_HDDR			; Make P/D an output, state=0. 
; Wait 6ms					;
	delay50us	120    			; 6ms delay
						;
; Now Reset both Xilinx				;
	movep	#(E3CLK|E3PDOWNLeft|E3PDOWNRight),x:M_HDR ; reset both Xilinx 
; Wait 6ms					;
	delay50us	120    			; 6ms delay
		       				;
; Finally, release Xilinx Reset			;
	movep	#(E3CLK|E3PDOWNLeft|E3PDOWNRight|E3RESETLeft|E3RESETRight),x:M_HDR ;release reset on Xilinx again
; Wait 6ms					;
	delay50us	120    			; 6ms delay
						;
; Make sure P/Done is low			;
TestPDone1					;
	brclr	#E3PDONEBit,x:<$FFF000,a			; Mask out Length field
	or	#>$00000A,a			; Adjust Length field
	move	a1,p:(r0)+			; Overwrite 1st word with new Length
	move	p:(r0),a			; Get 2nd word of header
	and 	#>$000FFF,a			; Mask out Length field
	or	#>$D70000,a			; Adjust Length field
	move	a1,p:(r0)+n0			; Overwrite 2nd word with new Length
; Next adjust last data byte for second encoder	;
	move	p:(r0),a			; Get Last word (which includes 1st data byte for 2nd encoder)
	and	#>$FFFF00,a			; Mask out bits 9-23 of Last word
	move	p:(r1),b			; Get 2nd word of header
	and	#>$0000FF,b			; Mask 1st data byte
	add	b,a				; Add 1st data byte to Last word
	nop					;
	move	a1,p:(r0)			; Overwrite Last word
	move	#$FFFFFF,b			; Keep acc b non-zero
	rts					;
	       					;
RestoreLastByte					;
; Restore last byte of config data to FF	;
;						;
; Input params:					;
; r0 = Addr of last word for 1st encoder	;
	move	p:(r0),a			;
	or 	#>$0000FF,a			;
	move	a1,p:(r0)			;
	rts					;
						;
;-----------------------------------------------;
; Initialise Encoder State and Set 		;
;  Encoder RAM to test stimulation parameters	;
;						;
; Destroys contents of registers r0, r1, y1	;
						;
;-------------------------------		;
InitEncoderL					;
						;
; Reset the state of the Encoder,		;
; usally only required after configuring Xilinx ;
;  unless low battery occurs			;
	clr	a				;
	move	#ENCBATT24L,r0			;
	move	#ENCSTOP24L,r1			;
        move    a,x:(r0)	        	; Clear low batt latch
	nop					;
	move    a,x:(r1)	        	; Stop immediately
						;
; Make sure Encoder is not busy			;
	move	#ENCSTAT24L,r0			;
	jsr	WaitCI24			; Wait for Encoder finished
						;
; Load stimulus data into Encoder RAM		;
	move	#ENCRAM24L,r0			; Address of EncoderRAM
	jmp	LoadParamsCI24NullL		;
						;
	rts					;
						;
;-------------------------------		;
InitEncoderR					;
						;
; Reset the state of the Encoder		;
; usally only required after configuring Xilinx	;
; unless low battery occurs			;
; Destroys contents of registers r0, r1    	;
	clr	a				;
	move	#ENCBATT24R,r0			;
	move	#ENCSTOP24R,r1			;
        move    a,x:(r0)	        	; Clear low batt latch
	nop					;
	move    a,x:(r1)	        	; Stop immediately
						;
; Make sure Encoder is not busy			;
	move	#ENCSTAT24R,r0			;
	jsr	WaitCI24			; Wait for Encoder finished
						;
; Load stimulus data into Encoder		;
	move	#ENCRAM24R,r0			; Address of EncoderRAM
	jmp	LoadParamsCI24NullR		;
						;
						;
;-----------------------------------------------;
; Copies Test Stimulus Params into Encoder RAM	;
						;
LoadParamsCI24ActiveR				;
; Copy X_CI24beginActive to Encoder Ram		;
	move	#>X_CI24beginActive,r1		; Default stim data to encRAM
	do	#(X_CI24endActive-X_CI24beginActive),InitCI24ActiveR ; for table length
	move 	x:(r1)+,y1			; Get X_CI24beginActive byte
	move	y1,x:(r0)+			; Load into Encoder Ram
InitCI24ActiveR					;
	rts					;
						;
;-------------------------------		;
LoadParamsCI24NullR				;
; Copy X_CI24beginNullR to Encoder Ram		;
	move	#>X_CI24beginNull,r1		; Default stim data to encRAM
	do	#(X_CI24endNull-X_CI24beginNull),InitCI24NullR 	; for table length
	move 	x:(r1)+,y1			; Get X_CI24beginNull byte
	move	y1,x:(r0)+			; Load into Encoder Ram
InitCI24NullR					;
	rts					;
						;
;-------------------------------		;
						;
LoadParamsCI24ActiveL				;
; Copy Y_CI24beginActive to Encoder Ram		;
	move	#>Y_CI24beginActive,r1		; Default stim data to encRAM
	do	#(Y_CI24endActive-Y_CI24beginActive),InitCI24ActiveL ; for table length
	move 	y:(r1)+,y1			; Get Y_CI24beginActive byte
	move	y1,y:(r0)+			; Load into Encoder Ram
InitCI24ActiveL					;
	rts					;
						;
;-------------------------------		;
LoadParamsCI24NullL				;
; Copy Y_CI24beginNull to Encoder Ram		;
	move	#>Y_CI24beginNull,r1		; Default stim data to encRAM
	do	#(Y_CI24endNull-Y_CI24beginNull),InitCI24NullL 	; for table length
	move 	y:(r1)+,y1			; Get Y_CI24beginNull byte
	move	y1,y:(r0)+			; Load into Encoder Ram
InitCI24NullL					;
	rts					;
						;
;-----------------------------------------------;
;
;
;-----------------------------------------------;
; Loads Test Stimulus Params into Encoder    	;
;						;
; Notes.					;
;  1. The stimulus parameters can be modified	;
;     during run time but in this example they	;
;     are static.				;
;  2. The stimulus parameters do not need to be ;
;     written to every stimulation period if	;
;     they are unchanged. 			;
;  3. Not all stimulus parameters need to be    ;
;     written to, only those that need to be 	;
;     modified. EG if phase duration, IPG and   ;
;     IFG are constant then they do not need to ;
;     be written to.				;
;  4. The less params written to Encoder RAM	;
;     the sooner the Encoder can be started and ;
;     thus the higher the stimulation rate	; 
						;
;-----------------------------------------------;
; Load stimulus data into Encoders		;
;						;
; These destroy contents of  r0 		;
;						;
LoadEncLeftActive				;
	move	#ENCRAM24L,r0			; Address of CI24L EncoderRAM
	jmp	LoadParamsCI24ActiveL		;
	rts					;
						;
;-------------------------------		;
LoadEncRightActive				;
	move	#ENCRAM24R,r0			; Address of CI24R EncoderRAM
	jmp	LoadParamsCI24ActiveR		;
	rts					;
						;
;-------------------------------		;
LoadEncLeftNull					;
	move	#ENCRAM24L,r0			; Address of CI24L EncoderRAM
	jmp	LoadParamsCI24NullL		;
	rts					;
						;
;-------------------------------		;
LoadEncRightNull				;
	move	#ENCRAM24R,r0			; Address of CI24R EncoderRAM
	jmp	LoadParamsCI24NullR		;
	rts					;
						;
;-------------------------------		;
EncBusyLeft					; Wait While Left Encoder is busy
	move	#ENCSTAT24L,r0			;
	jsr	WaitCI24			; Wait for Encoder finished
	rts					;
						;
;-------------------------------		;
EncBusyRight					; Wait While Right Encoder is busy
	move	#ENCSTAT24R,r0			;
	jsr	WaitCI24			; Wait for Encoder finished
	rts					;
						;
;-----------------------------------------------;
WaitCI24					; Waits for Encoder Finished status
;						;
; Requires r0 = Address of Right or Left	;
; Encoder Status Register	 		;
;						;
enc_busy24					;
	jclr    #RUNBIT,x:(r0),enc_free24 	; check status and wait till done
	jmp	enc_busy24			;
enc_free24					;
	rts					;
						;
;-----------------------------------------------;
;
;-----------------------------------------------;
	end					;
;-----------------------------------------------;