// Raspberry Pi Pico PIO program to output data to a TFT
// controller via a 8 bit 8080 style data path.

// Original sourced from:
// https://github.com/zapta/pio_tft

// Side set: 1 output pin, TFT_WR. Active low.
// Data set: 8 consecutive output pins, TFT_D0 .. TFT_D7

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

// The C++ code switches between the different SM routines
// by waiting for the SM to be idle and setting its PC.
// The default SM routine is a 16 bit transfer

// Do a block fill of N+1 pixels.
public block_fill:
   // Fetch colour value.
   pull side 1
   // Move colour to x.
   mov x, osr
   // Fetch pixel count N (sends N+1 pixels).
   pull
   // Move pixel count to y.
   mov y, osr
next:
   // Copy colour value into osr, colour in LS 16 bits.
   mov osr, x side 1
   // Output colour 8 MS bits, unwanted top 16 bits shifted through.
   out pins, 24 side 0 [1]
   // Write first colour byte.
   nop side 1 [1]
   // Write second colour byte.
   out pins, 8 side 0 [1]
   // Decrement pixel count and loop.
   jmp y--, next side 1

.wrap_target
// Transmit a 16 bit value (LS 16 bits of 32 bits).
public start_tx:
   // Fetch the next 32 bit value from the TX FIFO and set TFT_WR high.
   pull side 1
   // Write the first byte (MSB) and set WR low. This also
   // shifts the unused top 16 bits through.
   out pins, 24 side 0 [1]       
   // Set WR high and delay to next byte.
   nop side 1 [1]
   // Output the second byte and set TFT_WRITE low.
   out pins, 8 side 0 [1]
   // Set WR high and jump back to start.
   jmp start_tx side 1

// Transmit an 8 bit value (LS 8 bits of 32 bits).
public start_8:
   // Fetch the next 32 bit value from the TX FIFO and set TFT_WR high.
   pull side 1
   // Write the first byte (LSB) and sets WR low. This also 
   // shifts the unused top 24 bits through.
   out pins, 32 side 0 [1]     
   // Jump to start
   jmp start_tx side 1

// Transmit a set window command sequence.
public set_addr_window:
   // Loop count in x (to send caset, paset and ramwr commands).
   set x, 2 side 1
pull_cmd:
   // Set TFT_DC low.
   set pins, 0
   // Fetch caset, paset or ramwr.
   pull
   // Output LS byte (caset, paset or ramwr), discarding top 24 bits, set TFT_WR low.
   out pins, 32 side 0
   // Jump to end if 3rd cmd byte ramwr sent (x == 0)
   jmp !x, end_set_addr
   // pull next start and end coordinates, TFT_WR high.
   pull side 1
   // Set TFT_DC high.
   set pins, 1
send_xy:
   // Output byte, TFT_WR low.
   out pins, 8 side 0 [1]
   // Loop until 4 bytes sent, TFT_WR high.
   jmp !osre, send_xy side 1 [1]
end_set_addr:
   // Loop back for next command and write last command.
   jmp x--, pull_cmd side 1
   // Set DC high.
   set pins, 1
   // Auto-wrap back to start_tx.
.wrap