; 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, 9 out PC, 7 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