916 lines
37 KiB
Plaintext
916 lines
37 KiB
Plaintext
|
''***************************************
|
|||
|
''* TV Driver v1.1 *
|
|||
|
''* Author: Chip Gracey *
|
|||
|
''* Copyright (c) 2004 Parallax, Inc. *
|
|||
|
''* See end of file for terms of use. *
|
|||
|
''***************************************
|
|||
|
|
|||
|
' v1.0 - 01 May 2006 - original version
|
|||
|
' v1.1 - 17 May 2006 - pixel tile size can now be 16 x 32 to enable more efficient
|
|||
|
' character displays utilizing the internal font - see 'tv_mode'
|
|||
|
{
|
|||
|
2009
|
|||
|
May
|
|||
|
11 Moved blank line tasks into one-time initialization section.
|
|||
|
Difficulty: one task was flipping the interlace bit of _mode, necessitating a reload of _mode
|
|||
|
every superfield. Removed the flip and changed the sense of the Z tests that depended on _mode<1>
|
|||
|
being flipped.
|
|||
|
12 Implemented simple scrolling terminal output in background task.
|
|||
|
Difficulty: have to keep Z clear so that mainline interlaced code works properly.
|
|||
|
June
|
|||
|
9 Added "D"isable and "E"nable commands.
|
|||
|
20 Changing ping response to include basepin.
|
|||
|
}
|
|||
|
|
|||
|
CON
|
|||
|
|
|||
|
fntsc = 3_579_545 'NTSC color frequency
|
|||
|
lntsc = 3640 'NTSC color cycles per line * 16
|
|||
|
sntsc = 624 'NTSC color cycles per sync * 16
|
|||
|
|
|||
|
fpal = 4_433_618 'PAL color frequency
|
|||
|
lpal = 4540 'PAL color cycles per line * 16
|
|||
|
spal = 848 'PAL color cycles per sync * 16
|
|||
|
|
|||
|
paramcount = 14
|
|||
|
' colortable = $180 'start of colortable inside cog
|
|||
|
|
|||
|
cols = 40
|
|||
|
rows = 13
|
|||
|
|
|||
|
VAR
|
|||
|
long cog
|
|||
|
long rendezvous
|
|||
|
|
|||
|
PUB start(basepin, rv) | okay
|
|||
|
|
|||
|
'' Start TV driver - starts a cog if necessary
|
|||
|
'' returns true if it had to start a cog, false if cog was already running.
|
|||
|
''
|
|||
|
_basepin := basepin
|
|||
|
rendezvous := rv
|
|||
|
long[rendezvous]~~ ' ping the sxtv cog (send -1)
|
|||
|
waitcnt( clkfreq/10 + cnt )
|
|||
|
if long[rendezvous] <> -1 ' if the cog is alive it'll set this to _basepin<<8
|
|||
|
long[rendezvous]~
|
|||
|
return false
|
|||
|
|
|||
|
_pins := (basepin & $38) << 1 | (basepin & 4 == 4) & %0101
|
|||
|
|
|||
|
if cog := cognew(@entry, rendezvous) + 1
|
|||
|
return true
|
|||
|
else
|
|||
|
abort string("Couldn't start sxtv cog")
|
|||
|
|
|||
|
PUB stop
|
|||
|
|
|||
|
'' Stop TV driver - frees a cog
|
|||
|
|
|||
|
if cog
|
|||
|
cogstop(cog~ - 1)
|
|||
|
|
|||
|
PUB GetBasepin
|
|||
|
repeat while long[rendezvous]
|
|||
|
long[rendezvous]~~ ' ping the sxtv cog (send -1)
|
|||
|
repeat while long[rendezvous] == -1
|
|||
|
return long[rendezvous]~ >> 8
|
|||
|
|
|||
|
PUB str(stringptr)
|
|||
|
|
|||
|
'' Print a zero-terminated string
|
|||
|
|
|||
|
repeat strsize(stringptr)
|
|||
|
out(byte[stringptr++])
|
|||
|
|
|||
|
|
|||
|
PUB dec(value) | _i
|
|||
|
|
|||
|
'' Print a decimal number
|
|||
|
|
|||
|
if value < 0
|
|||
|
-value
|
|||
|
out("-")
|
|||
|
|
|||
|
_i := 1_000_000_000
|
|||
|
|
|||
|
repeat 10
|
|||
|
if value => _i
|
|||
|
out(value / _i + "0")
|
|||
|
value //= _i
|
|||
|
result~~
|
|||
|
elseif result or _i == 1
|
|||
|
out("0")
|
|||
|
_i /= 10
|
|||
|
|
|||
|
|
|||
|
PUB hex(value, digits)
|
|||
|
|
|||
|
'' Print a hexadecimal number
|
|||
|
|
|||
|
value <<= (8 - digits) << 2
|
|||
|
repeat digits
|
|||
|
out(lookupz((value <-= 4) & $F : "0".."9", "A".."F"))
|
|||
|
|
|||
|
|
|||
|
PUB bin(value, digits)
|
|||
|
|
|||
|
'' Print a binary number
|
|||
|
|
|||
|
value <<= 32 - digits
|
|||
|
repeat digits
|
|||
|
out((value <-= 1) & 1 + "0")
|
|||
|
|
|||
|
|
|||
|
pub out( c )
|
|||
|
repeat while byte[rendezvous]
|
|||
|
byte[rendezvous] := c
|
|||
|
|
|||
|
DAT
|
|||
|
|
|||
|
'*******************************
|
|||
|
'* Assembly language TV driver *
|
|||
|
'*******************************
|
|||
|
|
|||
|
org
|
|||
|
'
|
|||
|
'
|
|||
|
' Entry
|
|||
|
'
|
|||
|
entry
|
|||
|
call #init
|
|||
|
mov taskptr,#tasks 'reset tasks
|
|||
|
|
|||
|
'
|
|||
|
'
|
|||
|
' Superfield
|
|||
|
'
|
|||
|
superfield
|
|||
|
|
|||
|
test _mode,#%0001 wc 'if ntsc, set phaseflip
|
|||
|
if_nc mov phaseflip,phasemask
|
|||
|
|
|||
|
test _mode,#%0010 wz 'get interlace into nz
|
|||
|
mov temp, #0 wz ''' I messed something up and now Z has to be set, not clear.
|
|||
|
'
|
|||
|
'
|
|||
|
' Field
|
|||
|
'
|
|||
|
field mov x,vinv 'do invisible back porch lines
|
|||
|
:black call #hsync 'do hsync
|
|||
|
waitvid burst,sync_high2 'do black
|
|||
|
jmpret taskret,taskptr 'call task section (z undisturbed)
|
|||
|
djnz x,#:black 'another black line?
|
|||
|
|
|||
|
' wrlong visible,par 'set status to visible
|
|||
|
|
|||
|
mov x,vb 'do visible back porch lines
|
|||
|
call #blank_lines
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
mov y,_vt 'set vertical tiles
|
|||
|
movs :getchars4, #text '<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
|||
|
:line
|
|||
|
mov vx,_vx 'set vertical expand
|
|||
|
mov t1,#32
|
|||
|
mov chset, chset0
|
|||
|
:vert
|
|||
|
if_z xor interlace,#1 'interlace skip?
|
|||
|
if_z tjz interlace,#:skip
|
|||
|
|
|||
|
call #hsync 'do hsync
|
|||
|
|
|||
|
mov vscl,hb 'do visible back porch pixels
|
|||
|
xor tile,colortable
|
|||
|
waitvid tile,#0
|
|||
|
|
|||
|
mov x,_ht 'set horizontal tiles
|
|||
|
shr x, #2 'divide by 4
|
|||
|
|
|||
|
mov vscl,hx 'set horizontal expand
|
|||
|
|
|||
|
:getchars4 mov chars4, 0-0
|
|||
|
mov t3, #4
|
|||
|
:loop4
|
|||
|
mov char, chars4
|
|||
|
ror chars4, #8
|
|||
|
and char, #$ff
|
|||
|
shr char, #1 wc
|
|||
|
shl char, #7
|
|||
|
add char, chset
|
|||
|
rdlong pixels16, char
|
|||
|
' xor colors4, phaseflip
|
|||
|
if_nc waitvid colortable, pixels16
|
|||
|
if_c waitvid colortable+1, pixels16
|
|||
|
djnz t3, #:loop4
|
|||
|
add :getchars4, #1
|
|||
|
djnz x, #:getchars4
|
|||
|
|
|||
|
mov vscl,hf 'do visible front porch pixels
|
|||
|
mov tile,colortable'phaseflip
|
|||
|
' xor tile,colortable
|
|||
|
waitvid tile,#0
|
|||
|
sub :getchars4, #10
|
|||
|
|
|||
|
:skip
|
|||
|
add chset, #4
|
|||
|
djnz t1, #:vert
|
|||
|
|
|||
|
add :getchars4, #10
|
|||
|
djnz y,#:line 'another tile line?
|
|||
|
|
|||
|
if_z xor interlace,#1 wz 'get interlace and field1 into z
|
|||
|
|
|||
|
test _mode,#%0001 wc 'do visible front porch lines
|
|||
|
mov x,vf
|
|||
|
if_nz_and_c add x,#1
|
|||
|
call #blank_lines
|
|||
|
|
|||
|
' if_z wrlong invisible,par 'unless interlace and field1, set status to invisible
|
|||
|
|
|||
|
if_z_eq_c call #hsync 'if required, do short line
|
|||
|
if_z_eq_c mov vscl,hrest
|
|||
|
if_z_eq_c waitvid burst,sync_high2
|
|||
|
if_z_eq_c xor phaseflip,phasemask
|
|||
|
|
|||
|
call #vsync_high 'do high vsync pulses
|
|||
|
|
|||
|
movs vsync1,#sync_low1 'do low vsync pulses
|
|||
|
movs vsync2,#sync_low2
|
|||
|
call #vsync_low
|
|||
|
|
|||
|
call #vsync_high 'do high vsync pulses
|
|||
|
|
|||
|
if_nz mov vscl,hhalf 'if odd frame, do half line
|
|||
|
if_nz waitvid burst,sync_high2
|
|||
|
|
|||
|
if_z jmp #field 'if interlace and field1, display field2
|
|||
|
jmp #superfield 'else, new superfield
|
|||
|
'
|
|||
|
'
|
|||
|
' Blank lines
|
|||
|
'
|
|||
|
blank_lines call #hsync 'do hsync
|
|||
|
|
|||
|
xor tile,colortable 'do background
|
|||
|
waitvid tile,#0
|
|||
|
|
|||
|
djnz x,#blank_lines
|
|||
|
|
|||
|
blank_lines_ret ret
|
|||
|
'
|
|||
|
'
|
|||
|
' Horizontal sync
|
|||
|
'
|
|||
|
hsync test _mode,#%0001 wc 'if pal, toggle phaseflip
|
|||
|
' if_c xor phaseflip,phasemask
|
|||
|
|
|||
|
mov vscl,sync_scale1 'do hsync
|
|||
|
mov tile,burst'phaseflip
|
|||
|
' xor tile,burst
|
|||
|
waitvid tile,sync_normal
|
|||
|
|
|||
|
mov vscl,hvis 'setup in case blank line
|
|||
|
mov tile,#0'phaseflip
|
|||
|
|
|||
|
hsync_ret ret
|
|||
|
'
|
|||
|
'
|
|||
|
' Vertical sync
|
|||
|
'
|
|||
|
vsync_high movs vsync1,#sync_high1 'vertical sync
|
|||
|
movs vsync2,#sync_high2
|
|||
|
|
|||
|
vsync_low mov x,vrep
|
|||
|
|
|||
|
vsyncx mov vscl,sync_scale1
|
|||
|
vsync1 waitvid burst,sync_high1
|
|||
|
|
|||
|
mov vscl,sync_scale2
|
|||
|
vsync2 waitvid burst,sync_high2
|
|||
|
|
|||
|
djnz x,#vsyncx
|
|||
|
vsync_low_ret
|
|||
|
vsync_high_ret ret
|
|||
|
'
|
|||
|
'
|
|||
|
' Tasks - performed in sections during invisible back porch lines
|
|||
|
'
|
|||
|
tasks
|
|||
|
|
|||
|
clearscreen
|
|||
|
mov i, #14 ' clear 13 lines + 1 extra to make scrolling easier
|
|||
|
:lines
|
|||
|
mov j, #40/4 ' 40 columns, 4 chars at a time
|
|||
|
:chars
|
|||
|
:storem mov text, x20202020
|
|||
|
add :storem, d0 ' inc dst
|
|||
|
djnz j, #:chars
|
|||
|
jmpret taskptr,taskret
|
|||
|
djnz i, #:lines
|
|||
|
|
|||
|
waitforchar
|
|||
|
mov temp, #0 ' clear buffer: ready to accept next byte
|
|||
|
wrlong temp, par
|
|||
|
waitnoclear
|
|||
|
:wait
|
|||
|
jmpret taskptr,taskret
|
|||
|
|
|||
|
rdlong ch, par
|
|||
|
tjz ch, #:wait
|
|||
|
' got a byte
|
|||
|
|
|||
|
mov temp, cmdPing ' roundabout comparisons to avoid changing Z.
|
|||
|
sub temp, ch ' ch = -1 is just a ping to see if this cog is alive.
|
|||
|
tjz temp, #ping
|
|||
|
mov temp, cmdDisable
|
|||
|
sub temp, ch
|
|||
|
tjz temp, #disable
|
|||
|
mov temp, cmdEnable
|
|||
|
sub temp, ch
|
|||
|
tjz temp, #enable
|
|||
|
neg temp, #256 ' at this point, if ch is > 255, it must be _basepin<<8
|
|||
|
and temp, ch ' as set by a previous ping, so we just ignore it
|
|||
|
tjnz temp, #waitnoclear ' (leave the long pointed to by par undisturbed).
|
|||
|
|
|||
|
:char
|
|||
|
mov temp, #8
|
|||
|
sub temp, ch
|
|||
|
tjz temp, #:bksp
|
|||
|
mov temp, #13
|
|||
|
sub temp, ch
|
|||
|
tjnz temp, #:printchar
|
|||
|
call #cr
|
|||
|
jmp #waitforchar
|
|||
|
|
|||
|
:bksp
|
|||
|
sub col, #1 ' warning: no error-checking
|
|||
|
jmp #waitforchar
|
|||
|
|
|||
|
:printchar
|
|||
|
mov temp, #40
|
|||
|
sub temp, col
|
|||
|
tjnz temp, #:nocr
|
|||
|
call #cr
|
|||
|
:nocr
|
|||
|
mov temp, col
|
|||
|
shr temp, #2
|
|||
|
add temp, #text+12*40/4
|
|||
|
movs :get4chars, temp
|
|||
|
movd :put4chars, temp
|
|||
|
|
|||
|
mov i, col
|
|||
|
and i, #3
|
|||
|
shl i, #3 ' col&3 => 0, 8, 16, 24
|
|||
|
:get4chars mov temp, 0-0
|
|||
|
ror temp, i
|
|||
|
andn temp, #$ff
|
|||
|
or temp, ch
|
|||
|
rol temp, i
|
|||
|
:put4chars mov 0-0, temp
|
|||
|
|
|||
|
add col, #1
|
|||
|
|
|||
|
|
|||
|
jmp #waitforchar
|
|||
|
|
|||
|
cr
|
|||
|
movs :move4chars, #text + 40 / 4
|
|||
|
movd :move4chars, #text
|
|||
|
|
|||
|
mov i, #13 ' copy 13 lines up. Since we have an extra blank line at the bottom
|
|||
|
' (see clearscreen) the last visible line is automatically cleared.
|
|||
|
:copyline
|
|||
|
mov j, #40/4
|
|||
|
:move4chars mov 0-0, 0-0
|
|||
|
add :move4chars, d0s0
|
|||
|
djnz j, #:move4chars
|
|||
|
jmpret taskptr,taskret
|
|||
|
djnz i, #:copyline
|
|||
|
|
|||
|
mov col, #0
|
|||
|
|
|||
|
cr_ret ret
|
|||
|
|
|||
|
|
|||
|
|
|||
|
ping
|
|||
|
mov temp, _basepin
|
|||
|
shl temp, #8
|
|||
|
wrlong temp, par
|
|||
|
jmp #waitnoclear
|
|||
|
|
|||
|
enable
|
|||
|
mov dira, saveDira
|
|||
|
mov dirb, saveDirb
|
|||
|
jmp #waitforchar
|
|||
|
disable
|
|||
|
mov dira, #0
|
|||
|
mov dirb, #0
|
|||
|
jmp #waitforchar
|
|||
|
|
|||
|
|
|||
|
'
|
|||
|
'
|
|||
|
' Initialized data
|
|||
|
'
|
|||
|
x20202020 long $20202020
|
|||
|
chset0 long $8000
|
|||
|
m8 long 8_000_000
|
|||
|
m128 long 128_000_000
|
|||
|
d0 long 1 << 9 << 0
|
|||
|
d6 long 1 << 9 << 6
|
|||
|
d0s0 long 1 << 9 << 0 + 1 << 0
|
|||
|
d0s1 long 1 << 9 << 0 + 1 << 1
|
|||
|
interlace long 0
|
|||
|
invisible long 1
|
|||
|
visible long 2
|
|||
|
phaseflip long $00000000
|
|||
|
phasemask long $F0F0F0F0
|
|||
|
line long $00060000
|
|||
|
lineinc long $10000000
|
|||
|
linerot long 0
|
|||
|
pins0 long %11110000_01110000_00001111_00000111
|
|||
|
pins1 long %11111111_11110111_01111111_01110111
|
|||
|
sync_high1 long %0101010101010101010101_101010_0101
|
|||
|
sync_high2 long %01010101010101010101010101010101 'used for black
|
|||
|
sync_low1 long %1010101010101010101010101010_0101
|
|||
|
sync_low2 long %01_101010101010101010101010101010
|
|||
|
colortable
|
|||
|
' long $07_0a_07_0a ' white on blue
|
|||
|
' long $07_07_0a_0a
|
|||
|
' long $bc_02_bc_02 ' green on black
|
|||
|
' long $bc_bc_02_02
|
|||
|
' long $05_02_05_02 ' white on black
|
|||
|
' long $05_05_02_02
|
|||
|
long $02_05_02_05 ' black on white
|
|||
|
long $02_02_05_05
|
|||
|
' long $8a_8c_8a_8c ' black on yellow
|
|||
|
' long $8a_8a_8c_8c
|
|||
|
|
|||
|
|
|||
|
'
|
|||
|
'
|
|||
|
' NTSC/PAL metrics tables
|
|||
|
' ntsc pal
|
|||
|
' ----------------------------------------------
|
|||
|
wtab word lntsc - sntsc, lpal - spal 'hvis
|
|||
|
word lntsc / 2 - sntsc, lpal / 2 - spal 'hrest
|
|||
|
word lntsc / 2, lpal / 2 'hhalf
|
|||
|
word 243, 286 'vvis
|
|||
|
word 10, 18 'vinv
|
|||
|
word 6, 5 'vrep
|
|||
|
word $02_8A, $02_AA 'burst
|
|||
|
wtabx
|
|||
|
ltab long fntsc 'fcolor
|
|||
|
long fpal
|
|||
|
long sntsc >> 4 << 12 + sntsc 'sync_scale1
|
|||
|
long spal >> 4 << 12 + spal
|
|||
|
long 67 << 12 + lntsc / 2 - sntsc 'sync_scale2
|
|||
|
long 79 << 12 + lpal / 2 - spal
|
|||
|
long %0101_00000000_01_10101010101010_0101 'sync_normal
|
|||
|
long %010101_00000000_01_101010101010_0101
|
|||
|
ltabx
|
|||
|
|
|||
|
cmdPing long -1
|
|||
|
cmdEnable long "E"<<8
|
|||
|
cmdDisable long "D"<<8
|
|||
|
_basepin long 0
|
|||
|
'
|
|||
|
'
|
|||
|
' Parameter buffer
|
|||
|
'
|
|||
|
_enable long 1 'enable
|
|||
|
_pins long 0 'pins
|
|||
|
_mode long %10010 'mode
|
|||
|
_screen long 0 'screen
|
|||
|
_colors long 0 'colors
|
|||
|
_ht long cols 'hc
|
|||
|
_vt long rows 'vc
|
|||
|
_hx long 4 'hx
|
|||
|
_vx long 1 'vx
|
|||
|
_ho long 0 'ho
|
|||
|
_vo long 0 'vo
|
|||
|
_broadcast long 0 'broadcast
|
|||
|
_auralcog long 0 'auralcog
|
|||
|
|
|||
|
|
|||
|
'
|
|||
|
'
|
|||
|
' Uninitialized data
|
|||
|
'
|
|||
|
i long 0
|
|||
|
j long 0
|
|||
|
col long 0
|
|||
|
ch long 0
|
|||
|
temp long 0
|
|||
|
|
|||
|
char long 0
|
|||
|
chset long 0
|
|||
|
chars4 long 0
|
|||
|
pixels16 long 0
|
|||
|
taskptr long 0 'tasks
|
|||
|
taskret long 0
|
|||
|
t1 long 0
|
|||
|
t2 long 0
|
|||
|
t3 long 0
|
|||
|
m1 long 0
|
|||
|
m2 long 0
|
|||
|
|
|||
|
x long 0 'display
|
|||
|
y long 0
|
|||
|
hf long 0
|
|||
|
hb long 0
|
|||
|
vf long 0
|
|||
|
vb long 0
|
|||
|
hx long 0
|
|||
|
vx long 0
|
|||
|
hc2x long 0
|
|||
|
screen long 0
|
|||
|
tile long 0
|
|||
|
pixels long 0
|
|||
|
lineadd long 0
|
|||
|
|
|||
|
hvis long 0 'loaded from word table
|
|||
|
hrest long 0
|
|||
|
hhalf long 0
|
|||
|
vvis long 0
|
|||
|
vinv long 0
|
|||
|
vrep long 0
|
|||
|
burst long 0
|
|||
|
|
|||
|
fcolor long 0 'loaded from long table
|
|||
|
sync_scale1 long 0
|
|||
|
sync_scale2 long 0
|
|||
|
sync_normal long 0
|
|||
|
|
|||
|
saveDira long 0
|
|||
|
saveDirb long 0
|
|||
|
|
|||
|
|
|||
|
text ' Cog memory from this point on will be reclaimed as text buffer.
|
|||
|
|
|||
|
init
|
|||
|
mov t1,_pins 'set video pins and directions
|
|||
|
test t1,#$08 wc
|
|||
|
if_nc mov t2,pins0
|
|||
|
if_c mov t2,pins1
|
|||
|
test t1,#$40 wc
|
|||
|
shr t1,#1
|
|||
|
shl t1,#3
|
|||
|
shr t2,t1
|
|||
|
movs vcfg,t2
|
|||
|
shr t1,#6
|
|||
|
movd vcfg,t1
|
|||
|
shl t1,#3
|
|||
|
and t2,#$FF
|
|||
|
shl t2,t1
|
|||
|
if_nc mov dira,t2
|
|||
|
if_nc mov saveDira, t2
|
|||
|
if_nc mov dirb,#0
|
|||
|
if_nc mov saveDirb, #0
|
|||
|
if_c mov dira,#0
|
|||
|
if_c mov saveDira, #0
|
|||
|
if_c mov dirb,t2 '+18
|
|||
|
if_c mov saveDirb, t2
|
|||
|
|
|||
|
|
|||
|
|
|||
|
movs :rd,#wtab 'load ntsc/pal metrics from word table
|
|||
|
movd :wr,#hvis
|
|||
|
mov t1,#wtabx - wtab
|
|||
|
test _mode,#%0001 wc
|
|||
|
:rd mov t2,0
|
|||
|
add :rd,#1
|
|||
|
if_nc shl t2,#16
|
|||
|
shr t2,#16
|
|||
|
:wr mov 0,t2
|
|||
|
add :wr,d0
|
|||
|
djnz t1,#:rd '+54
|
|||
|
|
|||
|
if_nc movs :ltab,#ltab 'load ntsc/pal metrics from long table
|
|||
|
if_c movs :ltab,#ltab+1
|
|||
|
movd :ltab,#fcolor
|
|||
|
mov t1,#(ltabx - ltab) >> 1
|
|||
|
:ltab mov 0,0
|
|||
|
add :ltab,d0s1
|
|||
|
djnz t1,#:ltab '+17
|
|||
|
|
|||
|
rdlong t1,#0 'get CLKFREQ
|
|||
|
shr t1,#1 'if CLKFREQ < 16MHz, cancel _broadcast
|
|||
|
cmp t1,m8 wc
|
|||
|
if_c mov _broadcast,#0
|
|||
|
shr t1,#1 'if CLKFREQ < color frequency * 4, disable
|
|||
|
' cmp t1,fcolor wc
|
|||
|
' if_c jmp #disabled '+11
|
|||
|
|
|||
|
|
|||
|
mov t1,fcolor 'set ctra pll to fcolor * 16
|
|||
|
call #divide 'if ntsc, set vco to fcolor * 32 (114.5454 MHz)
|
|||
|
test _mode,#%0001 wc 'if pal, set vco to fcolor * 16 (70.9379 MHz)
|
|||
|
if_c movi ctra,#%00001_111 'select fcolor * 16 output (ntsc=/2, pal=/1)
|
|||
|
if_nc movi ctra,#%00001_110
|
|||
|
if_nc shl t2,#1
|
|||
|
mov frqa,t2 '+147
|
|||
|
|
|||
|
mov t1,_broadcast 'set ctrb pll to _broadcast
|
|||
|
mov t2,#0 'if 0, turn off ctrb
|
|||
|
tjz t1,#:off
|
|||
|
min t1,m8 'limit from 8MHz to 128MHz
|
|||
|
max t1,m128
|
|||
|
mov t2,#%00001_100 'adjust _broadcast to be within 4MHz-8MHz
|
|||
|
:scale shr t1,#1 '(vco will be within 64MHz-128MHz)
|
|||
|
cmp m8,t1 wc
|
|||
|
if_c add t2,#%00000_001
|
|||
|
if_c jmp #:scale
|
|||
|
:off movi ctrb,t2
|
|||
|
call #divide
|
|||
|
mov frqb,t2 '+165
|
|||
|
|
|||
|
mov t1,#%10100_000 'set video configuration
|
|||
|
test _pins,#$01 wc '(swap broadcast/baseband output bits?)
|
|||
|
if_c or t1,#%01000_000
|
|||
|
test _mode,#%1000 wc '(strip chroma from broadcast?)
|
|||
|
if_nc or t1,#%00010_000
|
|||
|
test _mode,#%0100 wc '(strip chroma from baseband?)
|
|||
|
if_nc or t1,#%00001_000
|
|||
|
and _auralcog,#%111 '(set aural cog)
|
|||
|
or t1,_auralcog
|
|||
|
movi vcfg,t1 '+10
|
|||
|
|
|||
|
mov hx,_hx 'compute horizontal metrics
|
|||
|
shl hx,#8
|
|||
|
or hx,_hx
|
|||
|
shl hx,#4
|
|||
|
|
|||
|
mov hc2x,_ht
|
|||
|
shl hc2x,#1
|
|||
|
|
|||
|
mov t1,_ht
|
|||
|
mov t2,_hx
|
|||
|
call #multiply
|
|||
|
mov hf,hvis
|
|||
|
sub hf,t1
|
|||
|
shr hf,#1 wc
|
|||
|
mov hb,_ho
|
|||
|
addx hb,hf
|
|||
|
sub hf,_ho '+52
|
|||
|
|
|||
|
mov t1,_vt 'compute vertical metrics
|
|||
|
mov t2,_vx
|
|||
|
call #multiply
|
|||
|
test _mode,#%10000 wc 'consider tile size
|
|||
|
muxc linerot,#1
|
|||
|
mov lineadd,lineinc
|
|||
|
if_c shr lineadd,#1
|
|||
|
if_c shl t1,#1
|
|||
|
test _mode,#%0010 wc 'consider interlace
|
|||
|
if_c shr t1,#1
|
|||
|
mov vf,vvis
|
|||
|
sub vf,t1
|
|||
|
shr vf,#1 wc
|
|||
|
neg vb,_vo
|
|||
|
addx vb,vf
|
|||
|
add vf,_vo '+53
|
|||
|
|
|||
|
|
|||
|
init_ret ret
|
|||
|
|
|||
|
'
|
|||
|
'
|
|||
|
' Divide t1/CLKFREQ to get frqa or frqb value into t2
|
|||
|
'
|
|||
|
divide rdlong m1,#0 'get CLKFREQ
|
|||
|
|
|||
|
mov m2,#32+1
|
|||
|
:loop cmpsub t1,m1 wc
|
|||
|
rcl t2,#1
|
|||
|
shl t1,#1
|
|||
|
djnz m2,#:loop
|
|||
|
|
|||
|
divide_ret ret '+140
|
|||
|
'
|
|||
|
'
|
|||
|
' Multiply t1 * t2 * 16 (t1, t2 = bytes)
|
|||
|
'
|
|||
|
multiply shl t2,#8+4-1
|
|||
|
|
|||
|
mov m1,#8
|
|||
|
:loop shr t1,#1 wc
|
|||
|
if_c add t1,t2
|
|||
|
djnz m1,#:loop
|
|||
|
|
|||
|
multiply_ret ret '+37
|
|||
|
|
|||
|
|
|||
|
''
|
|||
|
''___
|
|||
|
''VAR 'TV parameters - 14 contiguous longs
|
|||
|
''
|
|||
|
'' long tv_status '0/1/2 = off/invisible/visible read-only
|
|||
|
'' long tv_enable '0/non-0 = off/on write-only
|
|||
|
'' long tv_pins '%pppmmmm = pin group, pin group mode write-only
|
|||
|
'' long tv_mode '%tccip = tile,chroma,interlace,ntsc/pal write-only
|
|||
|
'' long tv_screen 'pointer to screen (words) write-only
|
|||
|
'' long tv_colors 'pointer to colors (longs) write-only
|
|||
|
'' long tv_ht 'horizontal tiles write-only
|
|||
|
'' long tv_vt 'vertical tiles write-only
|
|||
|
'' long tv_hx 'horizontal tile expansion write-only
|
|||
|
'' long tv_vx 'vertical tile expansion write-only
|
|||
|
'' long tv_ho 'horizontal offset write-only
|
|||
|
'' long tv_vo 'vertical offset write-only
|
|||
|
'' long tv_broadcast 'broadcast frequency (Hz) write-only
|
|||
|
'' long tv_auralcog 'aural fm cog write-only
|
|||
|
''
|
|||
|
''The preceding VAR section may be copied into your code.
|
|||
|
''After setting variables, do start(@tv_status) to start driver.
|
|||
|
''
|
|||
|
''All parameters are reloaded each superframe, allowing you to make live
|
|||
|
''changes. To minimize flicker, correlate changes with tv_status.
|
|||
|
''
|
|||
|
''Experimentation may be required to optimize some parameters.
|
|||
|
''
|
|||
|
''Parameter descriptions:
|
|||
|
'' _________
|
|||
|
'' tv_status
|
|||
|
''
|
|||
|
'' driver sets this to indicate status:
|
|||
|
'' 0: driver disabled (tv_enable = 0 or CLKFREQ < requirement)
|
|||
|
'' 1: currently outputting invisible sync data
|
|||
|
'' 2: currently outputting visible screen data
|
|||
|
'' _________
|
|||
|
'' tv_enable
|
|||
|
''
|
|||
|
'' 0: disable (pins will be driven low, reduces power)
|
|||
|
'' non-0: enable
|
|||
|
'' _______
|
|||
|
'' tv_pins
|
|||
|
''
|
|||
|
'' bits 6..4 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 3..0 select pin group mode:
|
|||
|
'' %0000: %0000_0111 - baseband
|
|||
|
'' %0001: %0000_0111 - broadcast
|
|||
|
'' %0010: %0000_1111 - baseband + chroma
|
|||
|
'' %0011: %0000_1111 - broadcast + aural
|
|||
|
'' %0100: %0111_0000 broadcast -
|
|||
|
'' %0101: %0111_0000 baseband -
|
|||
|
'' %0110: %1111_0000 broadcast + aural -
|
|||
|
'' %0111: %1111_0000 baseband + chroma -
|
|||
|
'' %1000: %0111_0111 broadcast baseband
|
|||
|
'' %1001: %0111_0111 baseband broadcast
|
|||
|
'' %1010: %0111_1111 broadcast baseband + chroma
|
|||
|
'' %1011: %0111_1111 baseband broadcast + aural
|
|||
|
'' %1100: %1111_0111 broadcast + aural baseband
|
|||
|
'' %1101: %1111_0111 baseband + chroma broadcast
|
|||
|
'' %1110: %1111_1111 broadcast + aural baseband + chroma
|
|||
|
'' %1111: %1111_1111 baseband + chroma broadcast + aural
|
|||
|
'' -----------------------------------------------------------
|
|||
|
'' active pins top nibble bottom nibble
|
|||
|
''
|
|||
|
'' the baseband signal nibble is arranged as:
|
|||
|
'' bit 3: chroma signal for s-video (attach via 560-ohm resistor)
|
|||
|
'' bits 2..0: baseband video (sum 270/560/1100-ohm resistors to form 75-ohm 1V signal)
|
|||
|
''
|
|||
|
'' the broadcast signal nibble is arranged as:
|
|||
|
'' bit 3: aural subcarrier (sum 560-ohm resistor into network below)
|
|||
|
'' bits 2..0: visual carrier (sum 270/560/1100-ohm resistors to form 75-ohm 1V signal)
|
|||
|
'' _______
|
|||
|
'' tv_mode
|
|||
|
''
|
|||
|
'' bit 4 selects between 16x16 and 16x32 pixel tiles:
|
|||
|
'' 0: 16x16 pixel tiles (tileheight = 16)
|
|||
|
'' 1: 16x32 pixel tiles (tileheight = 32)
|
|||
|
''
|
|||
|
'' bit 3 controls chroma mixing into broadcast:
|
|||
|
'' 0: mix chroma into broadcast (color)
|
|||
|
'' 1: strip chroma from broadcast (black/white)
|
|||
|
''
|
|||
|
'' bit 2 controls chroma mixing into baseband:
|
|||
|
'' 0: mix chroma into baseband (composite color)
|
|||
|
'' 1: strip chroma from baseband (black/white or s-video)
|
|||
|
''
|
|||
|
'' bit 1 controls interlace:
|
|||
|
'' 0: progressive scan (243 display lines for NTSC, 286 for PAL)
|
|||
|
'' less flicker, good for motion
|
|||
|
'' 1: interlaced scan (486 display lines for NTSC, 572 for PAL)
|
|||
|
'' doubles the vertical display lines, good for text
|
|||
|
''
|
|||
|
'' bit 0 selects NTSC or PAL format
|
|||
|
'' 0: NTSC
|
|||
|
'' 3016 horizontal display ticks
|
|||
|
'' 243 or 486 (interlaced) vertical display lines
|
|||
|
'' CLKFREQ must be at least 14_318_180 (4 * 3_579_545 Hz)*
|
|||
|
'' 1: PAL
|
|||
|
'' 3692 horizontal display ticks
|
|||
|
'' 286 or 572 (interlaced) vertical display lines
|
|||
|
'' CLKFREQ must be at least 17_734_472 (4 * 4_433_618 Hz)*
|
|||
|
''
|
|||
|
'' * driver will disable itself while CLKFREQ is below requirement
|
|||
|
'' _________
|
|||
|
'' tv_screen
|
|||
|
''
|
|||
|
'' pointer to words which define screen contents (left-to-right, top-to-bottom)
|
|||
|
'' number of words must be tv_ht * tv_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 32x32 pixel tile
|
|||
|
'' _________
|
|||
|
'' tv_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..4: chroma data (0..15 = blue..green..red..)*
|
|||
|
'' bit 3: controls chroma modulation (0=off, 1=on)
|
|||
|
'' bits 2..0: 3-bit luminance level:
|
|||
|
'' values 0..1: reserved for sync - don't use
|
|||
|
'' values 2..7: valid luminance range, modulation adds/subtracts 1 (beware of 7)
|
|||
|
'' value 0 may be modulated to produce a saturated color toggling between levels 1 and 7
|
|||
|
''
|
|||
|
'' * because of TV's limitations, it doesn't look good when chroma changes abruptly -
|
|||
|
'' rather, use luminance - change chroma only against a black or white background for
|
|||
|
'' best appearance
|
|||
|
'' _____
|
|||
|
'' tv_ht
|
|||
|
''
|
|||
|
'' horizontal number pixel tiles - must be at least 1
|
|||
|
'' practical limit is 40 for NTSC, 50 for PAL
|
|||
|
'' _____
|
|||
|
'' tv_vt
|
|||
|
''
|
|||
|
'' vertical number of pixel tiles - must be at least 1
|
|||
|
'' practical limit is 13 for NTSC, 15 for PAL (26/30 max for interlaced NTSC/PAL)
|
|||
|
'' _____
|
|||
|
'' tv_hx
|
|||
|
''
|
|||
|
'' horizontal tile expansion factor - must be at least 3 for NTSC, 4 for PAL
|
|||
|
''
|
|||
|
'' make sure 16 * tv_ht * tv_hx + ||tv_ho + 32 is less than the horizontal display ticks
|
|||
|
'' _____
|
|||
|
'' tv_vx
|
|||
|
''
|
|||
|
'' vertical tile expansion factor - must be at least 1
|
|||
|
''
|
|||
|
'' make sure <tileheight> * tv_vt * tv_vx + ||tv_vo + 1 is less than the display lines
|
|||
|
'' _____
|
|||
|
'' tv_ho
|
|||
|
''
|
|||
|
'' horizontal offset in ticks - pos/neg value (0 for centered image)
|
|||
|
'' shifts the display right/left
|
|||
|
'' _____
|
|||
|
'' tv_vo
|
|||
|
''
|
|||
|
'' vertical offset in lines - pos/neg value (0 for centered image)
|
|||
|
'' shifts the display up/down
|
|||
|
'' ____________
|
|||
|
'' tv_broadcast
|
|||
|
''
|
|||
|
'' broadcast frequency expressed in Hz (ie channel 2 is 55_250_000)
|
|||
|
'' if 0, modulator is turned off - saves power
|
|||
|
''
|
|||
|
'' broadcasting requires CLKFREQ to be at least 16_000_000
|
|||
|
'' while CLKFREQ is below 16_000_000, modulator will be turned off
|
|||
|
'' ___________
|
|||
|
'' tv_auralcog
|
|||
|
''
|
|||
|
'' selects cog to supply aural fm signal - 0..7
|
|||
|
'' uses ctra pll output from selected cog
|
|||
|
''
|
|||
|
'' in NTSC, the offset frequency must be 4.5MHz and the max bandwidth +-25KHz
|
|||
|
'' in PAL, the offset frequency and max bandwidth vary by PAL type
|
|||
|
|
|||
|
{{
|
|||
|
|
|||
|
+------------------------------------------------------------------------------------------------------------------------------+
|
|||
|
<EFBFBD> TERMS OF USE: MIT License <20>
|
|||
|
+------------------------------------------------------------------------------------------------------------------------------<2D>
|
|||
|
<EFBFBD>Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation <20>
|
|||
|
<EFBFBD>files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, <20>
|
|||
|
<EFBFBD>modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software<72>
|
|||
|
<EFBFBD>is furnished to do so, subject to the following conditions: <20>
|
|||
|
<EFBFBD> <20>
|
|||
|
<EFBFBD>The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.<2E>
|
|||
|
<EFBFBD> <20>
|
|||
|
<EFBFBD>THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE <20>
|
|||
|
<EFBFBD>WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR <20>
|
|||
|
<EFBFBD>COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, <20>
|
|||
|
<EFBFBD>ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. <20>
|
|||
|
+------------------------------------------------------------------------------------------------------------------------------+
|
|||
|
}}
|