Files
linguist/samples/Propeller Spin/VGA.spin

596 lines
25 KiB
Plaintext

''***************************************
''* VGA Driver v1.1 *
''* Author: Chip Gracey *
''* Copyright (c) 2006 Parallax, Inc. *
''* See end of file for terms of use. *
''***************************************
' v1.0 - 01 May 2006 - original version
' v1.1 - 15 May 2006 - pixel tile size can now be 16 x 32 to enable more efficient
' character displays utilizing the internal font - see 'vga_mode'
CON
paramcount = 21
colortable = $180 'start of colortable inside cog
VAR
long cog
PUB start(vgaptr) : okay
'' Start VGA driver - starts a cog
'' returns false if no cog available
''
'' vgaptr = pointer to VGA parameters
stop
okay := cog := cognew(@entry, vgaptr) + 1
PUB stop
'' Stop VGA driver - frees a cog
if cog
cogstop(cog~ - 1)
DAT
'********************************
'* Assembly language VGA driver *
'********************************
org
'
'
' Entry
'
entry mov taskptr,#tasks 'reset tasks
mov x,#8 'perform task sections initially
:init jmpret taskret,taskptr
djnz x,#:init
'
'
' Superfield
'
superfield mov hv,hvbase 'set hv
mov interlace,#0 'reset interlace
test _mode,#%0100 wz 'get interlace into nz
'
'
' Field
'
field wrlong visible,par 'set status to visible
tjz vb,#:nobl 'do any visible back porch lines
mov x,vb
movd bcolor,#colortable
call #blank_line
:nobl
mov screen,_screen 'point to first tile (upper-leftmost)
mov y,_vt 'set vertical tiles
:line mov vx,_vx 'set vertical expand
:vert if_nz xor interlace,#1 'interlace skip?
if_nz tjz interlace,#:skip
tjz hb,#:nobp 'do any visible back porch pixels
mov vscl,hb
waitvid colortable,#0
:nobp
mov x,_ht 'set horizontal tiles
mov vscl,hx 'set horizontal expand
:tile rdword tile,screen 'read tile
add tile,line 'set pointer bits into tile
rol tile,#6 'read tile pixels
rdlong pixels,tile '(8 clocks between reads)
shr tile,#10+6 'set tile colors
movd :color,tile
add screen,#2 'point to next tile
:color waitvid colortable,pixels 'pass colors and pixels to video
djnz x,#:tile 'another tile?
sub screen,hc2x 'repoint to first tile in same line
tjz hf,#:nofp 'do any visible front porch pixels
mov vscl,hf
waitvid colortable,#0
:nofp
mov x,#1 'do hsync
call #blank_hsync '(x=0)
:skip djnz vx,#:vert 'vertical expand?
ror line,linerot 'set next line
add line,lineadd wc
rol line,linerot
if_nc jmp #:line
add screen,hc2x 'point to first tile in next line
djnz y,#:line wc 'another tile line? (c=0)
tjz vf,#:nofl 'do any visible front porch lines
mov x,vf
movd bcolor,#colortable
call #blank_line
:nofl
if_nz xor interlace,#1 wc,wz 'get interlace and field1 into nz (c=0/?)
if_z wrlong invisible,par 'unless interlace and field1, set status to invisible
mov taskptr,#tasks 'reset tasks
addx x,_vf wc 'do invisible front porch lines (x=0 before, c=0 after)
call #blank_line
mov x,_vs 'do vsync lines
call #blank_vsync
mov x,_vb 'do invisible back porch lines, except last
call #blank_vsync
if_nz jmp #field 'if interlace and field1, display field2
jmp #superfield 'else, new superfield
'
'
' Blank line(s)
'
blank_vsync cmp interlace,#2 wc 'vsync (c=1)
blank_line mov vscl,h1 'blank line or vsync-interlace?
if_nc add vscl,h2
if_c_and_nz xor hv,#%01
if_c waitvid hv,#0
if_c mov vscl,h2 'blank line or vsync-normal?
if_c_and_z xor hv,#%01
bcolor waitvid hv,#0
if_nc jmpret taskret,taskptr 'call task section (z undisturbed)
blank_hsync mov vscl,_hf 'hsync, do invisible front porch pixels
waitvid hv,#0
mov vscl,_hs 'do invisble sync pixels
xor hv,#%10
waitvid hv,#0
mov vscl,_hb 'do invisible back porch pixels
xor hv,#%10
waitvid hv,#0
djnz x,#blank_line wc '(c=0)
movd bcolor,#hv
blank_hsync_ret
blank_line_ret
blank_vsync_ret ret
'
'
' Tasks - performed in sections during invisible back porch lines
'
tasks mov t1,par 'load parameters
movd :par,#_enable '(skip _status)
mov t2,#paramcount - 1
:load add t1,#4
:par rdlong 0,t1
add :par,d0
djnz t2,#:load '+164
mov t1,#2 'set video pins and directions
shl t1,_pins '(if video disabled, pins will drive low)
sub t1,#1
test _pins,#$20 wc
and _pins,#$38
shr t1,_pins
movs vcfg,t1
shl t1,_pins
shr _pins,#3
movd vcfg,_pins
if_nc mov dira,t1
if_nc mov dirb,#0
if_c mov dira,#0
if_c mov dirb,t1 '+14
tjz _enable,#disabled '+2, disabled?
jmpret taskptr,taskret '+1=181, break and return later
rdlong t1,#0 'make sure CLKFREQ => 16MHz
shr t1,#1
cmp t1,m8 wc
if_c jmp #disabled '+8
min _rate,pllmin 'limit _rate to pll range
max _rate,pllmax '+2
mov t1,#%00001_011 'set ctra configuration
:max cmp m8,_rate wc 'adjust rate to be within 4MHz-8MHz
if_c shr _rate,#1 '(vco will be within 64MHz-128MHz)
if_c add t1,#%00000_001
if_c jmp #:max
:min cmp _rate,m4 wc
if_c shl _rate,#1
if_c sub x,#%00000_001
if_c jmp #:min
movi ctra,t1 '+22
rdlong t1,#0 'divide _rate/CLKFREQ and set frqa
mov hvbase,#32+1
:div cmpsub _rate,t1 wc
rcl t2,#1
shl _rate,#1
djnz hvbase,#:div '(hvbase=0)
mov frqa,t2 '+136
test _mode,#%0001 wc 'make hvbase
muxnc hvbase,vmask
test _mode,#%0010 wc
muxnc hvbase,hmask '+4
jmpret taskptr,taskret '+1=173, break and return later
mov hx,_hx 'compute horizontal metrics
shl hx,#8
or hx,_hx
shl hx,#4
mov hc2x,_ht
shl hc2x,#1
mov h1,_hd
neg h2,_hf
sub h2,_hs
sub h2,_hb
sub h1,h2
shr h1,#1 wc
addx h2,h1
mov t1,_ht
mov t2,_hx
call #multiply
mov hf,_hd
sub hf,t1
shr hf,#1 wc
mov hb,_ho
addx hb,hf
sub hf,_ho '+59
mov t1,_vt 'compute vertical metrics
mov t2,_vx
call #multiply
test _mode,#%1000 wc 'consider tile size
muxc linerot,#1
mov lineadd,lineinc
if_c shr lineadd,#1
if_c shl t1,#1
test _mode,#%0100 wc 'consider interlace
if_c shr t1,#1
mov vf,_vd
sub vf,t1
shr vf,#1 wc
neg vb,_vo
addx vb,vf
add vf,_vo '+53
movi vcfg,#%01100_000 '+1, set video configuration
:colors jmpret taskptr,taskret '+1=114/160, break and return later
mov t1,#13 'load next 13 colors into colortable
:loop mov t2,:color '5 times = 65 (all 64 colors loaded)
shr t2,#9-2
and t2,#$FC
add t2,_colors
rdlong t2,t2
and t2,colormask
or t2,hvbase
:color mov colortable,t2
add :color,d0
andn :color,d6
djnz t1,#:loop '+158
jmp #:colors '+1, keep loading colors
'
'
' Multiply t1 * t2 * 16 (t1, t2 = bytes)
'
multiply shl t2,#8+4-1
mov tile,#8
:loop shr t1,#1 wc
if_c add t1,t2
djnz tile,#:loop
multiply_ret ret '+37
'
'
' Disabled - reset status, nap ~4ms, try again
'
disabled mov ctra,#0 'reset ctra
mov vcfg,#0 'reset video
wrlong outa,par 'set status to disabled
rdlong t1,#0 'get CLKFREQ
shr t1,#8 'nap for ~4ms
min t1,#3
add t1,cnt
waitcnt t1,#0
jmp #entry 'reload parameters
'
'
' Initialized data
'
pllmin long 500_000 'pll lowest output frequency
pllmax long 128_000_000 'pll highest output frequency
m8 long 8_000_000 '*16 = 128MHz (pll vco max)
m4 long 4_000_000 '*16 = 64MHz (pll vco min)
d0 long 1 << 9 << 0
d6 long 1 << 9 << 6
invisible long 1
visible long 2
line long $00060000
lineinc long $10000000
linerot long 0
vmask long $01010101
hmask long $02020202
colormask long $FCFCFCFC
'
'
' Uninitialized data
'
taskptr res 1 'tasks
taskret res 1
t1 res 1
t2 res 1
x res 1 'display
y res 1
hf res 1
hb res 1
vf res 1
vb res 1
hx res 1
vx res 1
hc2x res 1
screen res 1
tile res 1
pixels res 1
lineadd res 1
interlace res 1
hv res 1
hvbase res 1
h1 res 1
h2 res 1
'
'
' Parameter buffer
'
_enable res 1 '0/non-0 read-only
_pins res 1 '%pppttt read-only
_mode res 1 '%tihv read-only
_screen res 1 '@word read-only
_colors res 1 '@long read-only
_ht res 1 '1+ read-only
_vt res 1 '1+ read-only
_hx res 1 '1+ read-only
_vx res 1 '1+ read-only
_ho res 1 '0+- read-only
_vo res 1 '0+- read-only
_hd res 1 '1+ read-only
_hf res 1 '1+ read-only
_hs res 1 '1+ read-only
_hb res 1 '1+ read-only
_vd res 1 '1+ read-only
_vf res 1 '1+ read-only
_vs res 1 '1+ read-only
_vb res 1 '2+ read-only
_rate res 1 '500_000+ read-only
fit colortable 'fit underneath colortable ($180-$1BF)
''
''___
''VAR 'VGA parameters - 21 contiguous longs
''
'' long vga_status '0/1/2 = off/visible/invisible read-only
'' long vga_enable '0/non-0 = off/on write-only
'' long vga_pins '%pppttt = pins write-only
'' long vga_mode '%tihv = tile,interlace,hpol,vpol write-only
'' long vga_screen 'pointer to screen (words) write-only
'' long vga_colors 'pointer to colors (longs) write-only
'' long vga_ht 'horizontal tiles write-only
'' long vga_vt 'vertical tiles write-only
'' long vga_hx 'horizontal tile expansion write-only
'' long vga_vx 'vertical tile expansion write-only
'' long vga_ho 'horizontal offset write-only
'' long vga_vo 'vertical offset write-only
'' long vga_hd 'horizontal display ticks write-only
'' long vga_hf 'horizontal front porch ticks write-only
'' long vga_hs 'horizontal sync ticks write-only
'' long vga_hb 'horizontal back porch ticks write-only
'' long vga_vd 'vertical display lines write-only
'' long vga_vf 'vertical front porch lines write-only
'' long vga_vs 'vertical sync lines write-only
'' long vga_vb 'vertical back porch lines write-only
'' long vga_rate 'tick rate (Hz) write-only
''
''The preceding VAR section may be copied into your code.
''After setting variables, do start(@vga_status) to start driver.
''
''All parameters are reloaded each superframe, allowing you to make live
''changes. To minimize flicker, correlate changes with vga_status.
''
''Experimentation may be required to optimize some parameters.
''
''Parameter descriptions:
'' __________
'' vga_status
''
'' driver sets this to indicate status:
'' 0: driver disabled (vga_enable = 0 or CLKFREQ < 16MHz)
'' 1: currently outputting invisible sync data
'' 2: currently outputting visible screen data
'' __________
'' vga_enable
''
'' 0: disable (pins will be driven low, reduces power)
'' non-0: enable
'' ________
'' vga_pins
''
'' bits 5..3 select pin group:
'' %000: pins 7..0
'' %001: pins 15..8
'' %010: pins 23..16
'' %011: pins 31..24
'' %100: pins 39..32
'' %101: pins 47..40
'' %110: pins 55..48
'' %111: pins 63..56
''
'' bits 2..0 select top pin within group
'' for example: %01111 (15) will use pins %01000-%01111 (8-15)
'' ________
'' vga_mode
''
'' bit 3 selects between 16x16 and 16x32 pixel tiles:
'' 0: 16x16 pixel tiles (tileheight = 16)
'' 1: 16x32 pixel tiles (tileheight = 32)
''
'' bit 2 controls interlace:
'' 0: progressive scan (less flicker, good for motion, required for LCD monitors)
'' 1: interlaced scan (allows you to double vga_vt, good for text)
''
'' bits 1 and 0 select horizontal and vertical sync polarity, respectively
'' 0: active low
'' 1: active high
'' __________
'' vga_screen
''
'' pointer to words which define screen contents (left-to-right, top-to-bottom)
'' number of words must be vga_ht * vga_vt
'' each word has two bitfields: a 6-bit colorset ptr and a 10-bit pixelgroup ptr
'' bits 15..10: select the colorset* for the associated pixel tile
'' bits 9..0: select the pixelgroup** address %ppppppppppcccc00 (p=address, c=0..15)
''
'' * colorsets are longs which each define four 8-bit colors
''
'' ** pixelgroups are <tileheight> longs which define (left-to-right, top-to-bottom) the 2-bit
'' (four color) pixels that make up a 16x16 or a 16x32 pixel tile
'' __________
'' vga_colors
''
'' pointer to longs which define colorsets
'' number of longs must be 1..64
'' each long has four 8-bit fields which define colors for 2-bit (four color) pixels
'' first long's bottom color is also used as the screen background color
'' 8-bit color fields are as follows:
'' bits 7..2: actual state of pins 7..2 within pin group*
'' bits 1..0: don't care (used within driver for hsync and vsync)
''
'' * it is suggested that:
'' bits/pins 7..6 are used for red
'' bits/pins 5..4 are used for green
'' bits/pins 3..2 are used for blue
'' for each bit/pin set, sum 240 and 470-ohm resistors to form 75-ohm 1V signals
'' connect signal sets to RED, GREEN, and BLUE on VGA connector
'' always connect group pin 1 to HSYNC on VGA connector via 240-ohm resistor
'' always connect group pin 0 to VSYNC on VGA connector via 240-ohm resistor
'' ______
'' vga_ht
''
'' horizontal number of pixel tiles - must be at least 1
'' ______
'' vga_vt
''
'' vertical number of pixel tiles - must be at least 1
'' ______
'' vga_hx
''
'' horizontal tile expansion factor - must be at least 1
''
'' make sure 16 * vga_ht * vga_hx + ||vga_ho is equal to or at least 16 less than vga_hd
'' ______
'' vga_vx
''
'' vertical tile expansion factor - must be at least 1
''
'' make sure <tileheight> * vga_vt * vga_vx + ||vga_vo does not exceed vga_vd
'' (for interlace, use <tileheight> / 2 * vga_vt * vga_vx + ||vga_vo)
'' ______
'' vga_ho
''
'' horizontal offset in ticks - pos/neg value (0 recommended)
'' shifts the display right/left
'' ______
'' vga_vo
''
'' vertical offset in lines - pos/neg value (0 recommended)
'' shifts the display up/down
'' ______
'' vga_hd
''
'' horizontal display ticks
'' ______
'' vga_hf
''
'' horizontal front porch ticks
'' ______
'' vga_hs
''
'' horizontal sync ticks
'' ______
'' vga_hb
''
'' horizontal back porch ticks
'' ______
'' vga_vd
''
'' vertical display lines
'' ______
'' vga_vf
''
'' vertical front porch lines
'' ______
'' vga_vs
''
'' vertical sync lines
'' ______
'' vga_vb
''
'' vertical back porch lines
'' ________
'' vga_rate
''
'' tick rate in Hz
''
'' driver will limit value to be within 500KHz and 128MHz
'' pixel rate (vga_rate / vga_hx) should be no more than CLKFREQ / 4
{{
┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
│ TERMS OF USE: MIT License │
├──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation │
│files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, │
│modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software│
│is furnished to do so, subject to the following conditions: │
│ │
│The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.│
│ │
│THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE │
│WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR │
│COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, │
│ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. │
└──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
}}