Files
picovga-cmake/src/vga.pio
Wayne Venables 49a948cdfc Refactor paths
2023-02-24 21:15:35 -08:00

278 lines
9.8 KiB
Plaintext

; ============================================================================
; VGA output - base layer (15 instructions)
; ============================================================================
; Control word of "dark" command (left shift):
; - bit 0..7 (8 bits) output color (set to 0 if not used)
; - bit 8..26 (19 bits) loop counter N
; - bit 27..31 (5 bits) jump address
; Control word of other commands (left shift):
; - bit 0..27 (27 bits) loop counter N
; - bit 27..31 (5 bits) jump address
; Clocks per pixel: minimum 2, maximum 17.
.program vga
.side_set 1 ; SYNC output (no opt, wait can be max. 15)
.origin 17 ; must load at offset 17 (BASE_OFF)
; ===== [3 instructions] SYNC pulse, N=delay in clock cycles - 3
public sync:
out x,27 side 1 ; [1] get length of SYNC pulse - 3, start of SYNC pulse
sync_loop:
jmp x--,sync_loop side 1 ; [N+1] loop
public entry:
out pc,5 side 1 ; [1] get next control word and jump to function
; ===== [4 instructions] DARK (or color) pulse, N=delay in clock cycles - 4
; Sets color output at time +1
public dark:
out x,19 side 0 ; [1] get length of delay pulse - 4, start of delay pulse
out pins,8 side 0 ; [1] dark output (or color)
dark_loop:
jmp x--,dark_loop side 0 ; [N+1] loop
out pc,5 side 0 ; [1] get next control word and jump to function
; ===== [4 instructions] layer synchronisation (delay 9 clock cycles)
; Output first pixel at time +9 after IRQ
public irqset:
irq clear 4 side 0 ; [1] clear IRQ4 flag
out null,27 side 0 ; [1] destroy command parameter
irq set 4 side 0 [5] ; [6] set IRQ flag
.wrap_target
out pc,5 side 0 ; [1] get next control word and jump to function
; ===== [4 instructions] output pixels at CPP clock, N=number of pixels-2 (number of pixels must be multiple of 4)
; Output first pixel at time +1
; Missing 2 clock cycles after last pixel
public output:
out x,27 side 0 ; [1] get number of pixels-2
output_loop:
public extra1:
out pins,8 side 0 [0] ; [1+CPP-2] output pixels (set extra wait CPP-2)
jmp x--,output_loop side 0 ; [1] loop
public extra2:
out pins,8 side 0 [0] ; [1+CPP-2] output pixels (set extra wait CPP-2)
; missing 1 extra clock cycles - add it to front porch
; wrap jump to instruction out pc,5
.wrap
; ============================================================================
; VGA output - layer with key color (13 instructions)
; ============================================================================
; Control word (left shift):
; - bit 0..10 (11 bits) number of pixels - 1 (number of pixels must be multiple of 4)
; - bit 11..18 (8 bits) key color
; - bit 19..31 (13 bits) start delay D = clock cycles - 7 between irq and first pixel
; Clocks per pixel: minimum 6, maximum 37.
.program keylayer
.origin 0 ; must load at offset 0 (LAYER_OFF)
; idle wait
.wrap_target
public idle:
pull block ; [1] idle wait
public entry:
wait 0 irq 4 ; [1] wait for IRQ sync goes 0
out x,13 ; [1] get length of delay - 7
layer_wait:
jmp x--,layer_wait ; [1] delay loop
out y,8 ; [1] get key color
out x,11 ; [1] get number of pixels-1
layer_loop:
mov isr,x ; [1] save pixel counter into ISR
out x,8 ; [1] get output pixel
jmp x!=y,layer_2 ; [1] jump if pixel is not transparent
jmp layer_3 ; [1] jump to end of loop
layer_2:
mov pins,x ; [1] output pixel to pins
layer_3:
public extra1:
mov x,isr [0] ; [1+CPP-6] return pixel counter (set extra wait CPP-6)
jmp x--,layer_loop ; [1] loop next pixel
; wrap jump to idle
.wrap
; ============================================================================
; VGA output - layer with black key color (11 instructions)
; ============================================================================
; Control word (left shift):
; - bit 0..15 (16 bits) number of pixels - 1 (number of pixels must be multiple of 4)
; - bit 16..31 (16 bits) start delay D = clock cycles - 5 between irq and first pixel
; Cannot display black pixel (it is used as transparency)
; Clocks per pixel: minimum 4, maximum 34.
.program blacklayer
.origin 0 ; must load at offset 0 (LAYER_OFF)
; idle wait
.wrap_target
public idle:
pull block ; [1] idle wait
public entry:
wait 0 irq 4 ; [1] wait for IRQ sync goes 0
out x,16 ; [1] get length of delay - 5
layer_wait:
jmp x--,layer_wait ; [1] delay loop
out x,16 ; [1] get number of pixels-1
layer_loop:
out y,8 ; [1] get output pixel
jmp !y,layer_2 ; [1] jump if pixel is transparent (color = 0)
mov pins,y ; [1] output pixel to pins
public extra1:
jmp x--,layer_loop [0] ; [1+CPP-4] loop next pixel (set extra wait CPP-4)
jmp idle ; [1] go idle
layer_2:
public extra2:
jmp x--,layer_loop [0] ; [1+CPP-3] loop next pixel (set extra wait CPP-3)
; wrap jump to idle
.wrap
; ============================================================================
; VGA output - layer with white key color (10 instructions)
; ============================================================================
; Control word (left shift):
; - bit 0..15 (16 bits) number of pixels - 1 (number of pixels must be multiple of 4)
; - bit 16..31 (16 bits) start delay D = clock cycles - 5 between irq and first pixel
; Cannot display white pixel (it is used as transparency). Source pixels must be incremented + 1.
; Clocks per pixel: minimum 4, maximum 35.
.program whitelayer
.origin 0 ; must load at offset 0 (LAYER_OFF)
; idle wait
.wrap_target
public idle:
pull block ; [1] idle wait
public entry:
wait 0 irq 4 ; [1] wait for IRQ sync goes 0
out x,16 ; [1] get length of delay - 7
layer_wait:
jmp x--,layer_wait ; [1] delay loop
out x,16 ; [1] get number of pixels-1
layer_loop:
out y,8 ; [1] get output pixel
jmp y--,layer_2 ; [1] jump if pixel is not transparent (color != 0)
jmp layer_3 ; [1] jump to end of loop
layer_2:
mov pins,y ; [1] output pixel to pins
public extra1:
layer_3:
jmp x--,layer_loop [0] ; [1+CPP-4] loop next pixel (set extra wait CPP-4)
; wrap jump to idle
.wrap
; ============================================================================
; VGA output - layer with mono or color pattern (16 instructions)
; ============================================================================
; Control word (left shift):
; - bit 0 (1 bit) flag 0=use color opaque mode, 1=use mono transparent mode
; - bit 1..11 (11 bits) number of pixels - 1 (number of pixels must be multiple of 32 in mono, or 4 in color)
; - bit 12..19 (8 bits) key color
; - bit 20..31 (12 bits) start delay D = clock cycles - 8 between irq and first mono pixel, or 6 for color pixel
; Mono, clocks per pixel: minimum 4, maximum 35.
; Color, clocks per pixel: minimum 2, maximum 33.
.program monolayer
.origin 0 ; must load at offset 0 (LAYER_OFF)
.wrap_target
public idle:
pull block ; [1] idle wait
public entry:
wait 0 irq 4 ; [1] wait for IRQ sync goes 0
out x,12 ; [1] get length of delay - 8 (or 6 in color)
layer_wait:
jmp x--,layer_wait ; [1] delay loop
out isr,8 ; [1] get key color
out y,11 ; [1] get number of pixels-1
out x,1 ; [1] get mode flag
jmp !x,layer_color ; [1] 0=use color mode
layer_loop:
out x,1 ; [1] get one bit
jmp !x,layer_out ; [1] bit=0, output pixel
jmp layer_skip ; [1] jump to end of loop
layer_out:
mov pins,isr ; [1] output pixel
layer_skip:
public extra1:
jmp y--,layer_loop [0] ; [1+CPP-4] loop next pixel (set extra wait CPP-4)
jmp idle
layer_color:
out pins,8
public extra2:
jmp y--,layer_color [0] ; [1+CPP-2] loop next pixel (set extra wait CPP-2)
; wrap jump to idle
.wrap
; ============================================================================
; VGA output - layer with RLE compression (17 instructions)
; ============================================================================
; Input is left shifted with byte-swap (lower byte comes first)
; Requires 3 clock cycles per pixel.
; Clocks per pixel: minimum 3, maximum 32.
.program rlelayer
.origin 0 ; must load at offset 0 (LAYER_OFF)
; [1 instruction] idle wait (tokens: {8} ignored, {8} 'idle' command)
public idle:
out pc,8 ; [1] idle wait
; [4 instructions] start
public entry:
wait 0 irq 4 ; [1] wait for IRQ sync goes 0
out x,32 [2] ; [3] get length of delay - 7
entry_wait:
jmp x--,entry_wait ; [1] delay
jmp raw_next ; [1]
; [1 instruction] skip N+2 (2..257) pixels (tokens: {8} N = number of pixels - 2, {8} 'skip' command)
public skip:
public extra1:
jmp x--,skip [0] ; [1+CPP-1] wait (set extra wait CPP-1)
; [1 instruction] skip 1 pixel (tokens: {8} ignored, {8} 'skip1' command)
public skip1:
public extra2:
jmp raw_next [0] ; [1+CPP-3] jump (set extra wait CPP-3)
; [4 instructions] repeat N+3 (3..258) pixels (tokens: {8} pixel to repeat, {8} 'run' command, {8} N = number of pixels - 3)
public run:
public extra3:
mov pins,x [0] ; [1+CPP-2] output pixel (set extra wait CPP-2)
out y,8 ; [1] get counter N
run_loop:
public extra4:
mov pins,x [0] ; [1+CPP-2] output pixel (set extra wait CPP-2)
jmp y--,run_loop ; [1] next pixel
; [1 instruction] output 1 RAW pixel (tokens: {8} pixel, {8} 'raw1' command)
public raw1:
public extra5:
mov pins,x [0] ; [1+CPP-3] output pixel (set extra wait CPP-3)
.wrap_target
raw_next:
out x,8 ; [1] get counter N
out pc,8 ; [1] jump
; [5 instructions] output N+2 (2..257) RAW pixels (tokens: {8} N = number of pixels - 2, {8} 'raw' command, {(N+2)*8} pixels)
public raw: ; 14:
raw_loop:
public extra6:
out pins,8 [0] ; [1+CPP-2] output pixel (set extra wait CPP-2)
jmp x--,raw_loop ; [1] loop next pixel
public extra7:
out pins,8 [0] ; [1+CPP-3] output pixel (set extra wait CPP-3)
; wrap jump to raw_next
.wrap