analog-firmware/vga/vga12.pio

111 lines
4.3 KiB
Plaintext

; This program consists of 3 state machines communicating using state machine IRQs
; - hsync generates the hsync signal and drives the vsync and data state machines
; - vsync generates the vsync signal and drives the data state machine
; - data generates the pixel data stream, synchronized with the hsync and vsync IRQs
; generated by their respective timing state machine
;
; Overall timing (in pixel times)
;
; Time | hsync action | vsync action | data action
; ------------------------------------------------------------------------------------------------
; 0 | assert lineclk IRQ | |
; 8 | | wait & reset lineclk IRQ |
; 16 | set hsync signal low | set vsync signal high/low |
; 112 | set hsync signal high | |
; 144 | | assert vsync IRQ |
; 144.5 | | | 'wait irq vsync' completes
; 152 | assert hsync IRQ | |
; 152.5 | | | 'wait irq hsync' completes
; 160 | deassert hsync IRQ | | first pixel RGB data out
; 161 | | | second pixel RGB data out
; 216 | | deassert vsync IRQ |
.define LINECLK_IRQ_NUM 4
.define HSYNC_IRQ_NUM 5
.define VSYNC_IRQ_NUM 6
; Run at 4 * pixel frequency
.program vga_data
.origin 0
.wrap_target
pixel_out:
out PINS, 12
out PC, 4
public wait_vsync:
wait 0 irq VSYNC_IRQ_NUM
public wait_hsync:
wait 0 irq HSYNC_IRQ_NUM [1]
public extend_7: ; 8 pixels / an extra 14 clocks (2+6+4+2)
nop [1]
public extend_6: ; 7 pixels / an extra 12 clocks (6+4+2)
nop [5]
public extend_3: ; 4 pixels / an extra 6 clocks (4+2)
nop [3]
public extend_1: ; 2 pixels / an extra 2 clocks
nop [1]
.wrap
; Run at pixel frequency / 8
.program vga_hsync
pull ; load timing loop count from the CPU
.wrap_target
irq set LINECLK_IRQ_NUM [1] ; (0) assert lineclk IRQ
set PINS, 0 [11] ; (16) set hsync signal low
set PINS, 1 [4] ; (112) set hsync signal high
irq clear HSYNC_IRQ_NUM ; (152) assert hsync IRQ
irq set HSYNC_IRQ_NUM ; (160) deassert hsync IRQ
; Wait until the next hsync should be generated
mov X, OSR
skip_loop:
jmp X--, skip_loop
.wrap
; Run at pixel frequency / 8
.program vga_vsync
pull ; load timing loop count from the CPU
.wrap_target
wait 1 irq LINECLK_IRQ_NUM ; (8) wait & reset lineclk IRQ
set pins, 0 [15] ; (16) set vsync signal low
irq clear VSYNC_IRQ_NUM [8] ; (144) assert vsync IRQ
irq set VSYNC_IRQ_NUM ; (216) deassert vsync IRQ
wait 1 irq LINECLK_IRQ_NUM
wait 1 irq LINECLK_IRQ_NUM ; (8) wait for lineclk & reset
set pins, 1 ; (16) set vsync signal high
; Skip the remaining scanlines
mov X, OSR
skip_loop:
wait 1 irq LINECLK_IRQ_NUM
jmp X--, skip_loop
.wrap
; Pixel Frequency: 25.175MHz
;
; Horizontal timing
;
; 640x480@60Hz and 640x400@70Hz (pulse low)
; Scanline part | Pixels | Time [µs]
; ------------------------------------------
; Visible area | 640 | 25.422045680238
; Front porch | 16 | 0.63555114200596
; Sync pulse | 96 | 3.8133068520357
; Back porch | 48 | 1.9066534260179
; Whole line | 800 | 31.777557100298
;
; Vertical timing
;
; [640x480@60Hz (pulse low)] || [640x400@70Hz (pulse high)]
; Frame part | Lines | Time [ms] || Lines | Time [ms]
;------------------------------------------------------------------------
; Visible area | 480 | 15.253227408143 || 400 | 12.711022840119
; Front porch | 10 | 0.31777557100298 || 12 | 0.38133068520357
; Sync pulse | 2 | 0.063555114200596 || 2 | 0.063555114200596
; Back porch | 33 | 1.0486593843098 || 35 | 1.1122144985104
; Whole frame | 525 | 16.683217477656 || 449 | 14.268123138034