TriOS-alt/zubehör/sphinx/spinx100225-ori/sphinx0/sxtv.spin

916 lines
37 KiB
Plaintext
Raw Normal View History

2010-11-26 23:58:06 +01:00
''***************************************
''* 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>
+------------------------------------------------------------------------------------------------------------------------------+
}}