.origin 0                        // start of program in PRU memory
.entrypoint START                // program entry point for the debugger

//Copyright Doug Lewis Sept 2017

#include <./pruadc.h>


START:

//  Clear clock outputs to the ADS 1278 
        CLR    SPI_CLK_A_C_PIN 


// Clear all registers we are going to use, since we know that they can come up 
// with garbage in them 
        MOV     r0, 0 
        MOV     r1, 0
        MOV     CLOCK_COUNT, 0     // R2
        MOV     RUN_STATE, 0       // R3
        MOV     ADC_CNTRL_STR, 0   // R4 
        MOV     ADC_CHNG_FLG, 0    // R5 
        MOV     SMPL_BIT_CNTR, 0   // R6 
        MOV     CHAN_BITMASK, 0    // R7
        MOV     SHR_MEM_PTR, 0     // R8 
        MOV     SHR_MEM_SZ, 0      // R9
        MOV     COUNT, 0           // R10 
        MOV     HEAD, 0            // R11
        MOV     TAIL, 0            // R12
        MOV     PRU_DATA_STRT,  0 // R13
        MOV     CURRENT_SAMPLE, 0  // R14
        MOV     CURRENT_BUF, 0     // R15
        MOV     CUR_BUF_ADRS, 0    // R16
        MOV     CUR_BUF_LEFT, 0    // R17
        MOV     SHR_MEM_START, 0   // R18
        MOV     NUM_BLOCKS, 0      // R19
        MOV     BUFF_COUNT, 0      // R20
        MOV     SAMPLE1    , 0     // R21
	MOV     SAMPLE2    , 0     // R22
	MOV     SAMPLE3    , 0     // R23
	MOV     SAMPLE4    , 0     // R24
	MOV     SAMPLE5    , 0     // R25
	MOV     SAMPLE6    , 0     // R26
	MOV     SAMPLE7    , 0     // R27
	MOV     SAMPLE8    , 0     // R28
        MOV     WRAP_COUNT, 0      // R29

// Enable the OCP master port -- allows transfer of data to Linux userspace
        LBCO    r0, C4, 4, 4     // load PRU-ICSS CFG reg into r0 
        CLR     r0, r0, 4        // clear bit 4 (STANDBY_INIT)
        SBCO    r0, C4, 4, 4     // store the modified r0 back at the load addr
 
START_LOOP:                                    // This is an easy place to halt the debugger
	MOV	r1,ADC_STATE_ADDR	 
	LBBO	RUN_STATE, r1, 0, 4	       // the daq state is now loaded into r3. 
        QBEQ    START_LOOP, RUN_STATE, 0      // We hang out in a loop until told to read the adc

	MOV	r1,ADC_ADDR	 // 
	LBBO    SHR_MEM_PTR, r1, 0, 4     // load the Linux address that is passed into r8 -- to store sample values

        MOV     R1, PRU0_START_OFFSET
        ADD     PRU_DATA_STRT, SHR_MEM_START, R1
        MOV     SHR_MEM_PTR, PRU_DATA_STRT

	MOV	r1,ADC_SIZE	 //
	LBBO	SHR_MEM_SZ, r1, 0, 4	 // load the size that is passed into r9 -- the number of samples to take
 
	MOV	r1,PRU0_NUM_BLOCKS	 //
	LBBO	NUM_BLOCKS, r1, 0, 4	 // load the count of how many 128K blocks we are going to record 

MEM_BUF_ALLOCATED:        
        MOV    CUR_BUF_LEFT, BUFSIZE

	MOV	r1,ADC_CNTRL_CHANGE       // load the base address into r1
	LBBO	ADC_CHNG_FLG, r1, 0, 4	  // the ADC_CNTL_CHANGE is now loaded into R5 


        QBBS   CONFIG_CHANGE, ADC_CHNG_FLG.t0     // If bit 1 of ADC_CTRL_CHANGE is set, there is a config
                                        //change
        QBA    CONFIG_DONE              // Else no changes, goto CONFIG_DONE

CONFIG_CHANGE:
	MOV	r1, CLOCK_CNTR_ADDR	 
	LBBO	CLOCK_COUNT, r1, 0, 4	         // the clock delay is now loaded into r2. 

	MOV	r1,ADC_CNTRL_STR_ADDR	
	LBBO	ADC_CNTRL_STR, r1, 0, 4	         // the ADC_CNTL_STR is now loaded into R4 

        CLR     ADC_CHNG_FLG.t1                    // Clear the change flag so we dont do the config every loop


CONFIG_DONE:
       

//We want to look at the first bit in the config bitmask.
READ_NEXT_SAMPLE:
	MOV	r1,ADC_STATE_ADDR    //Check to see if we are still need to be running	  
	LBBO	RUN_STATE, r1, 0, 4	       
        QBEQ    CONTINUE_DAQ, RUN_STATE, 1      
        HALT  // We've been told to stop.

CONTINUE_DAQ:
	MOV	SAMPLE1, 0
	MOV	SAMPLE2, 0
	MOV	SAMPLE3, 0
	MOV	SAMPLE4, 0
	MOV	SAMPLE5, 0
	MOV	SAMPLE6, 0
	MOV	SAMPLE7, 0
	MOV	SAMPLE8, 0

// We check data ready to make sure the ADC has had a chance to initialize and set dready high before sampling.
DATA_READY_HIGH:
        QBBS    DATA_READY_WAIT, SPI_DSR_A_C_PIN
        QBA     DATA_READY_HIGH

DATA_READY_WAIT:
        QBBC    DATA_READY, SPI_DSR_A_C_PIN  // If Data Ready line clear, read a sample
        QBA     DATA_READY_WAIT      // Else hang out in a tight loop ...

DATA_READY:
	MOV     SMPL_BIT_CNTR, SAMPLE_SIZE  // We're going to read 24 bits        
READ_CHANNEL1:
        MOV     r0, CLOCK_COUNT      // Reload the clock delay val into R0
	SET	SPI_CLK_A_C_PIN	 // set the clock line to be high

DELAYON1:
        SUB     r0, r0, 1        
        QBNE    DELAYON1, r0, 0   

	    
	CLR	SPI_CLK_A_C_PIN	 // set the clock to be low

	// Read Data In 
	QBBC	ZERO_BIT1, SPI_DATA_IN_A_C_PIN  // Check to see whether Data In is a 0 or 1
	OR	SAMPLE1, SAMPLE1, 0x00000001

ZERO_BIT1:	
        LSL     SAMPLE1, SAMPLE1, 1      // Shift current sample contents left by one

        
	MOV     r0, CLOCK_COUNT
DELAYOFF1:
        SUB     r0, r0, 1        
        QBNE    DELAYOFF1, r0, 0   // loop until the delay has expired (equals 0)
	SUB     SMPL_BIT_CNTR, SMPL_BIT_CNTR, 1            // See if we have read all 24 bits of the sample
	QBNE    READ_CHANNEL1, SMPL_BIT_CNTR, 0


//////////////////////////
	MOV     SMPL_BIT_CNTR, SAMPLE_SIZE  // We're going to read 24 bits        
READ_CHANNEL2:
        MOV     r0, CLOCK_COUNT      // Reload the clock delay val into R0
	SET	SPI_CLK_A_C_PIN	// set the clock to be high

DELAYON2:
        SUB     r0, r0, 1        
        QBNE    DELAYON2, r0, 0   

        // Reload the clock delay val into R0
	CLR	SPI_CLK_A_C_PIN	 // set the clock to be low

	// Read Data In 
	QBBC	ZERO_BIT2, SPI_DATA_IN_A_C_PIN  // Check to see whether Data In is a 0 or 1
	OR	SAMPLE2, SAMPLE2, 0x00000001

ZERO_BIT2:	
        LSL     SAMPLE2, SAMPLE2, 1      // Shift current sample contents left by one

        SUB     SMPL_BIT_CNTR, SMPL_BIT_CNTR, 1            // See if we have read all 24 bits of the sample
         
	MOV     r0, CLOCK_COUNT
DELAYOFF2:
        SUB     r0, r0, 1        
        QBNE    DELAYOFF2, r0, 0   // loop until the delay has expired (equals 0)
	QBNE    READ_CHANNEL2, SMPL_BIT_CNTR, 0

//////////////////////
	MOV     SMPL_BIT_CNTR, SAMPLE_SIZE  // We're going to read 24 bits        
READ_CHANNEL3:
        MOV     r0, CLOCK_COUNT      // Reload the clock delay val into R0
	SET	SPI_CLK_A_C_PIN	 // set the clock to be high

DELAYON3:
        SUB     r0, r0, 1        
        QBNE    DELAYON3, r0, 0   

        // Reload the clock delay val into R0
	CLR	SPI_CLK_A_C_PIN  // set the clock to be low

        // Read Data In 
	QBBC	ZERO_BIT3, SPI_DATA_IN_A_C_PIN  // Check to see whether Data In is a 0 or 1
	OR	SAMPLE3, SAMPLE3, 0x00000001

ZERO_BIT3:	
        LSL     SAMPLE3, SAMPLE3, 1      // Shift current sample contents left by one

        SUB     SMPL_BIT_CNTR, SMPL_BIT_CNTR, 1            // See if we have read all 24 bits of the sample
         
	MOV     r0, CLOCK_COUNT
DELAYOFF3:
        SUB     r0, r0, 1        
        QBNE    DELAYOFF3, r0, 0   // loop until the delay has expired (equals 0)
	QBNE    READ_CHANNEL3, SMPL_BIT_CNTR, 0

/////////////////////////

	MOV     SMPL_BIT_CNTR, SAMPLE_SIZE  // We're going to read 24 bits        
READ_CHANNEL4:
        MOV     r0, CLOCK_COUNT      // Reload the clock delay val into R0
	SET	 SPI_CLK_A_C_PIN	 // set the clock to be high

DELAYON4:
        SUB     r0, r0, 1        
        QBNE    DELAYON4, r0, 0   

        // Reload the clock delay val into R0
	CLR	SPI_CLK_A_C_PIN	 // set the clock to be low

	// Read Data In 
	QBBC	ZERO_BIT4, SPI_DATA_IN_A_C_PIN  // Check to see whether Data In is a 0 or 1
	OR	SAMPLE4, SAMPLE4, 0x00000001

ZERO_BIT4:	
        LSL     SAMPLE4, SAMPLE4, 1      // Shift current sample contents left by one

        SUB     SMPL_BIT_CNTR, SMPL_BIT_CNTR, 1            // See if we have read all 24 bits of the sample
         
	MOV     r0, CLOCK_COUNT
DELAYOFF4:
        SUB     r0, r0, 1        
        QBNE    DELAYOFF4, r0, 0   // loop until the delay has expired (equals 0)
	QBNE    READ_CHANNEL4, SMPL_BIT_CNTR, 0

/////////////////////////
	MOV     SMPL_BIT_CNTR, SAMPLE_SIZE  // We're going to read 24 bits        
READ_CHANNEL5:
        MOV     r0, CLOCK_COUNT      // Reload the clock delay val into R0
	SET	SPI_CLK_A_C_PIN	 // set the clock to be high

DELAYON5:
        SUB     r0, r0, 1        
        QBNE    DELAYON5, r0, 0   

        // Reload the clock delay val into R0
	CLR	SPI_CLK_A_C_PIN	 // set the clock to be low

	// Read Data In 
	QBBC	ZERO_BIT5, SPI_DATA_IN_A_C_PIN  // Check to see whether Data In is a 0 or 1
	OR	SAMPLE5, SAMPLE5, 0x00000001

ZERO_BIT5:	
        LSL     SAMPLE5, SAMPLE5, 1      // Shift current sample contents left by one

        SUB     SMPL_BIT_CNTR, SMPL_BIT_CNTR, 1            // See if we have read all 24 bits of the sample
         
	MOV     r0, CLOCK_COUNT
DELAYOFF5:
        SUB     r0, r0, 1        
        QBNE    DELAYOFF5, r0, 0   // loop until the delay has expired (equals 0)
	QBNE    READ_CHANNEL5, SMPL_BIT_CNTR, 0

/////////////////////////
	MOV     SMPL_BIT_CNTR, SAMPLE_SIZE  // We're going to read 24 bits        
READ_CHANNEL6:
        MOV     r0, CLOCK_COUNT      // Reload the clock delay val into R0
	SET	SPI_CLK_A_C_PIN	 // set the clock to be high

DELAYON6:
        SUB     r0, r0, 1        
        QBNE    DELAYON6, r0, 0   

        // Reload the clock delay val into R0
	CLR	SPI_CLK_A_C_PIN	 // set the clock to be low

	// Read Data In 
	QBBC	ZERO_BIT6, SPI_DATA_IN_A_C_PIN  // Check to see whether Data In is a 0 or 1
	OR	SAMPLE6, SAMPLE6, 0x00000001

ZERO_BIT6:	
        LSL     SAMPLE6, SAMPLE6, 1      // Shift current sample contents left by one

        SUB     SMPL_BIT_CNTR, SMPL_BIT_CNTR, 1            // See if we have read all 24 bits of the sample
         
	MOV     r0, CLOCK_COUNT
DELAYOFF6:
        SUB     r0, r0, 1        
        QBNE    DELAYOFF6, r0, 0   // loop until the delay has expired (equals 0)
	QBNE    READ_CHANNEL6, SMPL_BIT_CNTR, 0

/////////////////////////
	MOV     SMPL_BIT_CNTR, SAMPLE_SIZE  // We're going to read 24 bits        
READ_CHANNEL7:
        MOV     r0, CLOCK_COUNT      // Reload the clock delay val into R0
	SET	SPI_CLK_A_C_PIN	 // set the clock to be high

DELAYON7:
        SUB     r0, r0, 1        
        QBNE    DELAYON7, r0, 0   

        // Reload the clock delay val into R0
	CLR	SPI_CLK_A_C_PIN // set the clock to be low

	// Read Data In 
	QBBC	ZERO_BIT7, SPI_DATA_IN_A_C_PIN  // Check to see whether Data In is a 0 or 1
	OR	SAMPLE7, SAMPLE7, 0x00000001

ZERO_BIT7:	
        LSL     SAMPLE7, SAMPLE7, 1      // Shift current sample contents left by one

        SUB     SMPL_BIT_CNTR, SMPL_BIT_CNTR, 1            // See if we have read all 24 bits of the sample
         
	MOV     r0, CLOCK_COUNT
DELAYOFF7:
        SUB     r0, r0, 1        
        QBNE    DELAYOFF7, r0, 0   // loop until the delay has expired (equals 0)
	QBNE    READ_CHANNEL7, SMPL_BIT_CNTR, 0

/////////////////////////
	MOV     SMPL_BIT_CNTR, SAMPLE_SIZE  // We're going to read 24 bits        
READ_CHANNEL8:
        MOV     r0, CLOCK_COUNT      // Reload the clock delay val into R0
	SET	SPI_CLK_A_C_PIN	 // set the clock to be high

DELAYON8:
        SUB     r0, r0, 1        
        QBNE    DELAYON8, r0, 0   

       // Reload the clock delay val into R0
	CLR	SPI_CLK_A_C_PIN // set the clock to be low

	// Read Data In 
	QBBC	ZERO_BIT8, SPI_DATA_IN_A_C_PIN  // Check to see whether Data In is a 0 or 1
	OR	SAMPLE8, SAMPLE8, 0x00000001

ZERO_BIT8:	
        LSL     SAMPLE8, SAMPLE8, 1     // Shift current sample contents left by one

        SUB     SMPL_BIT_CNTR, SMPL_BIT_CNTR, 1            // See if we have read all 24 bits of the sample
         
	MOV     r0, CLOCK_COUNT
DELAYOFF8:
        SUB     r0, r0, 1        
        QBNE    DELAYOFF8, r0, 0   // loop until the delay has expired (equals 0)
	QBNE    READ_CHANNEL8, SMPL_BIT_CNTR, 0

/////////////////////////
STORE_SAMPLE:                     
 
        LSR	SAMPLE1, SAMPLE1, 1      // Need to shift the sample word back to the right by one
	LSR	SAMPLE2, SAMPLE2, 1
	LSR	SAMPLE3, SAMPLE3, 1
	LSR	SAMPLE4, SAMPLE4, 1
	LSR	SAMPLE5, SAMPLE5, 1
	LSR	SAMPLE6, SAMPLE6, 1
	LSR	SAMPLE7, SAMPLE7, 1
	LSR	SAMPLE8, SAMPLE8, 1

        MOV     SAMPLE1.b3, 0x01    // Stash the channel bitmask in the upper byte used to store the sample  
	MOV     SAMPLE2.b3, 0x02
	MOV     SAMPLE3.b3, 0x04
	MOV     SAMPLE4.b3, 0x08
	MOV     SAMPLE5.b3, 0x10
	MOV     SAMPLE6.b3, 0x20
	MOV     SAMPLE7.b3, 0x40
	MOV     SAMPLE8.b3, 0x80

	SBBO	SAMPLE1, SHR_MEM_PTR, 0, 4 // store the sample value into shared  memory space
	ADD	SHR_MEM_PTR, SHR_MEM_PTR, 4	 // Add 4  bytes per sample to the address pointer
		
	SBBO	SAMPLE2, SHR_MEM_PTR, 0, 4 // store the sample value into shared  memory space
	ADD	SHR_MEM_PTR, SHR_MEM_PTR, 4	 // Add 4  bytes per sample to the address pointer

	SBBO	SAMPLE3, SHR_MEM_PTR, 0, 4 // store the sample value into shared  memory space
	ADD	SHR_MEM_PTR, SHR_MEM_PTR, 4	 // Add 4  bytes per sample to the address pointer
		 
	SBBO	SAMPLE4, SHR_MEM_PTR, 0, 4 // store the sample value into shared  memory space
	ADD	SHR_MEM_PTR, SHR_MEM_PTR, 4	 // Add 4  bytes per sample to the address pointer

	SBBO	SAMPLE5, SHR_MEM_PTR, 0, 4 // store the sample value into shared  memory space
	ADD	SHR_MEM_PTR, SHR_MEM_PTR, 4	 // Add 4  bytes per sample to the address pointer

	SBBO	SAMPLE6, SHR_MEM_PTR, 0, 4 // store the sample value into shared  memory space
	ADD	SHR_MEM_PTR, SHR_MEM_PTR, 4	 // Add 4  bytes per sample to the address pointer

	SBBO	SAMPLE7, SHR_MEM_PTR, 0, 4 // store the sample value into shared  memory space
	ADD	SHR_MEM_PTR, SHR_MEM_PTR, 4	 // Add 4  bytes per sample to the address pointer

	SBBO	SAMPLE8, SHR_MEM_PTR, 0, 4 // store the sample value into shared  memory space
	ADD	SHR_MEM_PTR, SHR_MEM_PTR, 4	 // Add 4  bytes per sample to the address pointer

	SUB	CUR_BUF_LEFT, CUR_BUF_LEFT, 32	 // reducing the number of samples - 4 bytes per sample, 8 channels
	
	QBEQ	BUFFER_DONE, CUR_BUF_LEFT, 0       // See if we have taken 128kb of samples
 
        QBA     READ_NEXT_SAMPLE  // If we've looped thru all channels in the sample. wait for the next sample


BUFFER_DONE:				 

        MOV     CUR_BUF_LEFT, BUFSIZE

        // If we have recorded all of the buffers that we need to, then halt.
        SUB     NUM_BLOCKS, NUM_BLOCKS, 1
        QBEQ    END, NUM_BLOCKS, 0  

        MOV     R1, BUFSIZE
        ADD     CUR_BUF_ADRS, CUR_BUF_ADRS, R1
        MOV     r1, SHARED_MEM_SIZE       
        QBEQ    WRAP_TIME, CUR_BUF_ADRS, r1 
        QBA     READ_NEXT_SAMPLE

WRAP_TIME:
        // Always wanted to be a rapper ;-0)
        // We have used all the shared memory to write samples, wrap back to the beginning.
        MOV	CUR_BUF_ADRS, 0
        MOV     r31.b0, PRU0_R31_VEC_VALID | PRU_EVTOUT_0
HALT  //DEBUG
        QBA     READ_NEXT_SAMPLE

// halt the pru program -- we reach here when the file is full. 
END:
	HALT                  


