; video_dma.pio ; ; Composite video generator: ; - SM1: sync timing + line start IRQ ; - SM0: pixel output during active video ; ; NTSC-compatible progressive timing using the same coarse 2us timing grid as ; the original PAL implementation: ; - 64us line period ; - 4us hsync ; - 6us back porch ; - 52us active video + front porch tail ; - 240 active lines, 262 total lines per frame (~59.64Hz) .define DATA_DELAY 4 .define LINE_IRQ 0 .define DMA_IRQ 1 .define PUBLIC CLOCKS_PER_BIT DATA_DELAY + 2 .program cvsync .side_set 1 ; OSR = active_lines_per_frame - 1 .wrap_target frame_start: ; 3 lines of broad vertical sync. set x, 2 side 1 vsync_lines: nop side 0 [14] nop side 0 nop side 1 [14] jmp x-- vsync_lines side 1 ; 19 blank lines before active video. set x, 18 side 1 blank_lines: irq set DMA_IRQ side 0 [1] nop side 1 [14] jmp x-- blank_lines side 1 [14] ; 240 active video lines. mov x, osr side 1 active_lines: irq set DMA_IRQ side 0 [1] ; 4us hsync, ask CPU to arm DMA nop side 1 [2] ; 6us back porch irq set LINE_IRQ side 1 [13] ; 28us visible video jmp x-- active_lines side 1 [12] jmp frame_start side 1 [12] .wrap .program cvdata ; X = pixels_per_line - 1, preloaded once from C ; Each line: ; clear output ; reload Y from X ; wait for sync SM to raise LINE_IRQ ; shift out one bit per loop .wrap_target set pins, 0 mov y, x wait 1 irq LINE_IRQ irq clear LINE_IRQ data_out: out pins, 1 [DATA_DELAY] jmp y-- data_out .wrap .program cvdata_diag ; Diagnostic program: ; waits for each active line, then emits wide black/white bars without DMA. ; This isolates the analog output path from the framebuffer/DMA path. .wrap_target wait 1 irq LINE_IRQ irq clear LINE_IRQ set x, 3 diag_bars: set pins, 1 [15] nop [15] nop [15] set pins, 0 [15] nop [15] nop [15] jmp x-- diag_bars [15] set pins, 0 .wrap