I have been looking at the code for the video controller. The idea is
that this code is generated and loaded based on the X modeline or
similar specifications. Following is a generic progressive scan program
that should handle any timing we support. It is pretty well commented,
though it will not compile with the compiler I wrote because there is a
fair amount of math in some of the arguments that the compiler doesn't
support yet. The macros at the top set the timing at compile time.
;; Progressive scan output program. This program should support all
;; resolutions and timings of which the hardware is capable. The
;; following macro definings will control the display timing,
;; framebuffer location, and panning. No other program changes are
;; necessary.
.define fb_width 640
.define fb_height 480
.define vp_width 640
.define vp_height 480
.define hfp 8
.define hsync 8
.define hbp 8
.define vfp 3
.define vsync 3
.define vbp 3
;; fb_offset is the difference between framebuffer width and
viewport width
.define fb_offset fb_width-vp_width
;; viewport is the offset of the first pixel of the viewport
.define viewport 0
.polarity v=-,h=-, d+
;; Entry point
.addr = 0
begin:
;; We will start out with the vertical blanking cycle. We will special
;; case the first line of the horizontal front port and insert the
;; address reset, panning offset and the initial fetch for the next
;; frame
;; We clock out four pixels per instruction and we need to wait one
;; less instruction cycle than really needed since the following
;; address reset will be part of the HBP timing. We also reset the
;; cursor counters to their initial values here since we are
;; begginning a new frame
wait (hfp/4)-1 [xy]
addr viewport
;; Assert the horizontal sync.
wait hsync [h]
;; Now insert the vertical back porch and line width delays. We delay
;; one instruction cycle less than necessary on HBP as the following
;; fetch is part of the timing.
wait vp_width
wait (hbp/4)-1
;; pre-fetch the first line of the frame so that the data is ready
;; when we start displaying the pixel data
fetch vp_width
;; start with the remaining vertical blanking front porch. We execute
;; one line less than specified because of the above special case.
call vporch vfp-1
;; now, start the vertical sync signal. We make the call with the
;; vsync flag set since by the time we get here we have completed
;; the front porch and need to start the sync pulse NOW.
call vsync [v]
;; And finally, send the vertical blanking back porch. We output one
;; line less than is called for in the vbp so that we can special case
;; the last line of the back porch to prefetch the first line of the
;; next frame
call vporch vbp
;; Output <vertical res> lines of pixels and horizontal sync. We
;; output one line less than necessary so that we can special case
;; the last line. The last line is a jump instead of a call so that
;; the subroutine return puts us back at the start of the program.
;; Otherwise we would have to completely special case the last line
;; so that we could factor the jump back to the beginning in the
;; timing
call scanline vp_height-1
;; We could also make this a one instruction cycle wait and just
;; let the execution fall through to the next instruction. That
;; would required the line ouput routine to alway immediately
;; follow. Since the instruction count would be the same, this
;; allows a bit more flexibility in the layout of the source code.
jump scanline
;; This will output a single horizontal line including the sync
;; information. The line output starts with the front porch
;; and ends with the back porch
scanline:
;; start with the horizontal front porch. HFP is specified in number
;; of pixels. We clock out four pixels per instruction. We also
;; need to remove one delay cycle since the front porch was actually
;; started in the call to this routine. This means that out minimum
;; horizontal front porch is 8 pixels. This matches the special case
;; in the first line of the vertical front porch described above
wait (hfp/4)-1
;; If we are panning the screen, we need to move to the start of the
;; next pixel data. Assert the hsync flag as this command is part
;; of the hsync period from a timing perspective
inc fb_offset [h]
;; output the horizontal sync pulse. When we do, we want to reset the
;; cursor x counter to the beginning of the line.
;; Minimum width for HSYNC is 8 pixels.
wait hsync-1 [hx]
;; output the horizontal back porch. We will delay one instruction
;; (4 pixels) less than the actual back porch width since the next
;; instruction (fetch) is part of the back porch as well making the
;; HBP minimum 8 pixels
wait (hbp/4)-1
;; Fetch line n+1 of pixel data. We are about to display line n.
;; In order to have the data ready when we need it for the next
;; line, we have to start the fetch now. On the last line of the
;; frame, we will fetch a data line that we don't need. Since
;; the address will be reset and the initial line re-fetched,
;; this is ok.
fetch vp_width
;; Finally, lets ouput the video data. Assert the data enable flag
;; and the subroutine return flag since this is the final line
;; in the subroutine. If we are at the last line of the frame the
;; return will start us back at the beginning of the program.
send vp_width [dr]
;; This routine is used for both the front and back vertical porches
;; It is really the same code as is used for scanline output without
;; the actual pixel send instruction, using a wait instead for timing
;; See the scanline notes for explinations of the timing values
vporch:
wait (hfp/4)-1 ;
wait hsync [h]
wait (hbp/4)
wait vp_width [r]
;; This routine outputs the vertical sync signal. It is also another
;; special case of the scanline code, in this case it is executed with
;; the hsync flag asserted. See the scanline comments for explination.
vsync:
wait (hfp/4)-1 [v]
wait hsync [hv]
wait (hbp/4) [v]
wait vp_width [vr]
Ok, now that we are done with the program, I want to point some things
out. If you want to change the timing of the program after it is
compiled you would need to change almost every single line. And, you
would need to know every single offset. Rearranging the video
controller code would necessitate updating the video driver code too.
So, to change the video mode would require having a copy of the video
controller source, updating the macros at the beginning, recompiling the
program, and uploading it. This would have to be done by the video bios
code since we have to be able to change modes without a video driver for
VGA. The other option is to precompile all the various video modes we
want to support and include the binary programs in the driver and BIOS.
Not the most elegant or efficient, but it would work. This would of
course limit driver support for video modes to those that we had already
compiled.
Here is another though. Rather than include immediate values in the
opcodes, use a register bank. Something like this:
[31] video data enable
[30] vertical sync
[29] horizontal sync
[28:27] cursor control:
00 = do nothing
01 = increment cursor_y and reset cursor_x
10 = reset cursor_y
11 = reset cursor_x and cursor_y
[cursor_x is incremented implicitly when transmitting video words]
[26] return from subroutine
[25] raise video interrupt signal
[24] unassigned
[23:21] instruction opcode
[20:16] register
This allows for 32 registers. All the values in the program can be
precomputed and stored in the registers. The program is loaded and
run. To change video modes simply requires updating the register set
with the appropriate values. For VGA emulation this isn't any more
elegant, we have to predefine a number of modes and save their timing
values in the BIOS, however once you have a driver running (like running
X), you can dynamically support any video mode that the hardware can
generate timing for. All you need to do is feed the driver your timing
numbers (X modeline for example). So far, it looks like 32 registers
would be more than sufficient to hold all the precomputed values for
progressive and interlaced modes, though I'm still working on "TV" mode
(interlaced plus serration pulses).
What are everyone's thoughts?
Patrick M
_______________________________________________
Open-graphics mailing list
[email protected]
http://lists.duskglow.com/mailman/listinfo/open-graphics
List service provided by Duskglow Consulting, LLC (www.duskglow.com)