# HG changeset patch # User Paul Boddie # Date 1555337888 -7200 # Node ID 778b12fc3ea540dd94c6b2b186f2b418322ac636 # Parent 879e71f6a3a3670fcd674fb7a7042c3e41ba409a Added some documentation about VGA signal generation. diff -r 879e71f6a3a3 -r 778b12fc3ea5 docs/wiki/SignalOutput --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/docs/wiki/SignalOutput Mon Apr 15 16:18:08 2019 +0200 @@ -0,0 +1,347 @@ += Signal Output = + +There are two principal mechanisms for generating a VGA signal demonstrated in +this project: + + * Using the CPU to "copy" pixel data to an output port + * Using DMA transfers to "copy" pixel data to an output port + +Within the latter, there are a number of variations in the mechanism employed: + + * Use of general-purpose output pins versus parallel mode outputs + * Use of large transfer cells containing each entire pixel line versus small + transfer cells containing fragments of each line + * Use of a single transfer-initiating event versus separate line-initiating + and transfer-initiating events + +== Using the CPU for Transfers == + +{{{#!graphviz +//format=svg +//transform=notugly +digraph cpu { + node [shape=box,fontsize="13.0",fontname="Helvetica"]; + rankdir=TD; + + subgraph { + rank=same; + + timer [label="Display line\ntimer",style=filled,fillcolor=gold]; + t_0 [label="0",shape=ellipse]; + t_hsync [label="hsync",shape=ellipse]; + t_limit [label="limit",shape=ellipse]; + } + + oc1 [label="Output compare",style=filled,fillcolor=gold]; + + subgraph { + rank=same; + + lineirq [label="Display line\ninterrupt handler"]; + pixelirq [label="Pixel output\ninterrupt handler"]; + } + + subgraph { + rank=same; + + pixels [label="Pixel output\nBlack/reset output",style=filled,fillcolor=green,shape=parallelogram]; + hsync [label="Horizontal sync",shape=house,style=filled,fillcolor=red]; + vsync [label="Vertical sync",shape=house,style=filled,fillcolor=red]; + } + + /* The timer starts at 0 and wraps around at limit. */ + + timer -> t_0 [arrowhead=none]; + t_0 -> t_hsync -> t_limit -> t_0 [style=dashed]; + + /* The timer initiates the interrupt request for pixel production. */ + + t_0 -> pixelirq; + + /* The interrupt handler generates the pixel output. */ + + pixelirq -> pixels; + + /* The timer feeds the output compare unit, driving hsync. */ + + t_hsync -> oc1; + oc1 -> hsync; + + /* The output compare unit initiates the interrupt request for each line, + driving vsync. */ + + oc1 -> lineirq; + lineirq -> vsync; +} +}}} + +== Using DMA for Transfers == + +{{{#!graphviz +//format=svg +//transform=notugly +digraph dma { + node [shape=box,fontsize="13.0",fontname="Helvetica"]; + rankdir=TD; + + subgraph { + rank=same; + + timer [label="Display line\ntimer",style=filled,fillcolor=gold]; + t_0 [label="0",shape=ellipse]; + t_hsync [label="hsync",shape=ellipse]; + t_limit [label="limit",shape=ellipse]; + } + + oc1 [label="Output compare",style=filled,fillcolor=gold]; + + subgraph { + rank=same; + + dma_line [label="Pixel output\nDMA channel",style=filled,fillcolor=lightblue]; + dma_reset [label="Pixel reset\nDMA channel",style=filled,fillcolor=lightblue]; + lineirq [label="Display line\ninterrupt handler"]; + } + + subgraph { + rank=same; + + pixels [label="Pixel output",style=filled,fillcolor=green,shape=parallelogram]; + black [label="Black/reset output",style=filled,fillcolor=black,fontcolor=white,shape=parallelogram]; + hsync [label="Horizontal sync",shape=house,style=filled,fillcolor=red]; + vsync [label="Vertical sync",shape=house,style=filled,fillcolor=red]; + } + + /* The timer starts at 0 and wraps around at limit. */ + + timer -> t_0 [arrowhead=none]; + t_0 -> t_hsync -> t_limit -> t_0 [style=dashed]; + + /* The timer initiates the DMA transfer for pixel production. */ + + t_0 -> dma_line; + + /* The line channel generates the pixel output. */ + + dma_line -> pixels; + + /* The completion of the line channel initiates the reset channel. */ + + dma_line -> dma_reset; + + /* The reset channel generates black/reset output. */ + + dma_reset -> black; + + /* The black/reset value follows the visible pixels. */ + + pixels -> black [style=dashed]; + + /* The timer feeds the output compare unit, driving hsync. */ + + t_hsync -> oc1; + oc1 -> hsync; + + /* The output compare unit initiates the interrupt request for each line, + driving vsync. */ + + oc1 -> lineirq; + lineirq -> vsync; +} +}}} + +== Using DMA and Timed Transfers == + +{{{#!graphviz +//format=svg +//transform=notugly +digraph dma { + node [shape=box,fontsize="13.0",fontname="Helvetica"]; + rankdir=TD; + + subgraph { + rank=same; + + timer [label="Display line\ntimer",style=filled,fillcolor=gold]; + t_0 [label="0",shape=ellipse]; + t_hsync [label="hsync",shape=ellipse]; + t_limit [label="limit",shape=ellipse]; + } + + oc1 [label="Output compare",style=filled,fillcolor=gold]; + + subgraph { + rank=same; + + trtimer [label="Transfer timer",style=filled,fillcolor=gold]; + tr_0 [label="0",shape=ellipse]; + tr_limit [label="limit",shape=ellipse]; + } + + subgraph { + rank=same; + + dma_init [label="Initiator\nDMA channel",style=filled,fillcolor=lightblue]; + dma_line [label="Pixel output\nDMA channel",style=filled,fillcolor=lightblue]; + dma_reset [label="Pixel reset\nDMA channel",style=filled,fillcolor=lightblue]; + lineirq [label="Display line\ninterrupt handler"]; + } + + subgraph { + rank=same; + + pixels [label="Pixel output",style=filled,fillcolor=green,shape=parallelogram]; + black [label="Black/reset output",style=filled,fillcolor=black,fontcolor=white,shape=parallelogram]; + hsync [label="Horizontal sync",shape=house,style=filled,fillcolor=red]; + vsync [label="Vertical sync",shape=house,style=filled,fillcolor=red]; + } + + /* The line timer starts at 0 and wraps around at limit. */ + + timer -> t_0 [arrowhead=none]; + t_0 -> t_hsync -> t_limit -> t_0 [style=dashed]; + + /* The transfer timer starts at 0 and wraps around at limit. */ + + trtimer -> tr_0 [arrowhead=none]; + tr_0 -> tr_limit -> tr_0 [style=dashed]; + + /* The line timer initiates the DMA transfers for the display line. */ + + t_0 -> dma_init; + + /* The completion of the initiating channel enables the line channel. */ + + dma_init -> dma_line; + + /* Each cell transfer in the line channel is initiated by the transfer + timer. */ + + tr_0 -> dma_line; + + /* The line channel generates the pixel output. */ + + dma_line -> pixels; + + /* The completion of the line channel initiates the reset channel. */ + + dma_line -> dma_reset; + + /* The reset channel generates black/reset output. */ + + dma_reset -> black; + + /* The black/reset value follows the visible pixels. */ + + pixels -> black [style=dashed]; + + /* The timer feeds the output compare unit, driving hsync. */ + + t_hsync -> oc1; + oc1 -> hsync; + + /* The output compare unit initiates the interrupt request for each line, + driving vsync. */ + + oc1 -> lineirq; + lineirq -> vsync; +} +}}} + +== Using DMA and Timed Dual-Channel Transfers == + +{{{#!graphviz +//format=svg +//transform=notugly +digraph dma { + node [shape=box,fontsize="13.0",fontname="Helvetica"]; + rankdir=TD; + + subgraph { + rank=same; + + timer [label="Display line\ntimer",style=filled,fillcolor=gold]; + t_0 [label="0",shape=ellipse]; + t_hsync [label="hsync",shape=ellipse]; + t_limit [label="limit",shape=ellipse]; + } + + oc1 [label="Output compare",style=filled,fillcolor=gold]; + + subgraph { + rank=same; + + trtimer [label="Transfer timer",style=filled,fillcolor=gold]; + tr_0 [label="0",shape=ellipse]; + tr_limit [label="limit",shape=ellipse]; + } + + subgraph { + rank=same; + + dma_init [label="Initiator\nDMA channel",style=filled,fillcolor=lightblue]; + dma_line [label="{Pixel output\nDMA channel #1 | Pixel output\nDMA channel #2}",style=filled,fillcolor=lightblue,shape=record]; + dma_reset [label="Pixel reset\nDMA channel",style=filled,fillcolor=lightblue]; + lineirq [label="Display line\ninterrupt handler"]; + } + + subgraph { + rank=same; + + pixels [label="Pixel output",style=filled,fillcolor=green,shape=parallelogram]; + black [label="Black/reset output",style=filled,fillcolor=black,fontcolor=white,shape=parallelogram]; + hsync [label="Horizontal sync",shape=house,style=filled,fillcolor=red]; + vsync [label="Vertical sync",shape=house,style=filled,fillcolor=red]; + } + + /* The line timer starts at 0 and wraps around at limit. */ + + timer -> t_0 [arrowhead=none]; + t_0 -> t_hsync -> t_limit -> t_0 [style=dashed]; + + /* The transfer timer starts at 0 and wraps around at limit. */ + + trtimer -> tr_0 [arrowhead=none]; + tr_0 -> tr_limit -> tr_0 [style=dashed]; + + /* The line timer initiates the DMA transfers for the display line. */ + + t_0 -> dma_init; + + /* The completion of the initiating channel enables the line channels. */ + + dma_init -> dma_line; + + /* Each cell transfer in the line channels is initiated by the transfer + timer. */ + + tr_0 -> dma_line; + + /* The line channels generate the pixel output. */ + + dma_line -> pixels; + + /* The completion of the line channels initiates the reset channel. */ + + dma_line -> dma_reset; + + /* The reset channel generates black/reset output. */ + + dma_reset -> black; + + /* The black/reset value follows the visible pixels. */ + + pixels -> black [style=dashed]; + + /* The timer feeds the output compare unit, driving hsync. */ + + t_hsync -> oc1; + oc1 -> hsync; + + /* The output compare unit initiates the interrupt request for each line, + driving vsync. */ + + oc1 -> lineirq; + lineirq -> vsync; +} +}}}