// Raspberry Pi Pico PIO program to output 18 bit data to a TFT
// controller via a SPI output data path.

//"Set" set: 1 output pin, TFT_DC
// Side set: 1 output pin, TFT_SCLK
// Data set: 1 output pin, TFT_MOSI

.program tft_io
.side_set 1 opt ;  The TFT_SCLK output.

// The C++ code switches between the 8 bits and 16 bits loops
// by waiting for the SM to be idle and setting its PC.
//

// 8 bit transfer
public start_8:
   // Pull the next 32 bit value from the TX FIFO. 
   pull side 0
   // Lose the top 24 bits, send 1st bit
   out pins, 25
   // Now send remaining bits
   jmp spi_out side 1

public set_addr_window:
   // Loop count in x for caset, paset and ramwr
   set x, 2 side 0
pull_cmd:
   // Set DC low
   set pins, 0
   // Fetch and output LS byte (caset, paset or ramwr), discarding top 24 bits, set WR low
   pull side 0
   out pins, 25
   nop side 1
next_cmd_bit:
   out pins, 1 side 0
   jmp !osre, next_cmd_bit side 1
   // Set DC high
   set pins, 1 side 0
   // Finish if 3rd cmd byte ramwr sent (x == 0)
   jmp !x, start_tx
   pull
next_xy:
   // send 32 bit start and end coordinates
   out pins, 1 side 0
   jmp !osre, next_xy side 1
   // Loop back for next command
   jmp x--, pull_cmd side 0
   // End
   jmp start_tx

public block_fill:
   // Fetch colour value
   pull side 0
   // Move colour to x
   mov x, osr
   // Fetch pixel count
   pull
   // Move pixel count to y
   mov y, osr
next_16:
   // Copy colour value back into osr
   mov osr, x side 0
   // Lose the top 8 bits, send 1st bit
   out pins, 9 side 0
   nop side 1
next_bit:
   // Output next remaining bits
   out pins, 1 side 0
   // Set TFT_SCLK high and jump for next bit
   jmp !osre, next_bit side 1
   // Decrement count and loop
   jmp y--, next_16 side 0
   // Now drop back to 16 bit output

.wrap_target
public start_tx:
   // Pull the next 32 bit value from the TX FIFO. 
   // Send the bottom 24 bits
   pull side 0
   // Drop the first 8 bits, write first bit
   out pins, 9 side 0
   nop side 1
spi_out:
   // Output the remaining bits
   out pins, 1 side 0
   // Set TFT_SCLK high and jump for next bit
   jmp !osre, spi_out side 1
   // Return to start
.wrap
