You can do it in one cog. The trick is to start an NCO counter that outputs on P8 to toggle the LSB of the RAM's address. That way, the program has to increment the rest of address only once for every two fetches. The other trick is to combine the bytes read into a long, so four bytes can be written to the hub at once:
Because of the additional instruction between the second and third read, the NCO timing is critical. You want the output on P8 to be settled when ina is fetched during the source read cycle.
Well that has me thinking about two more things (which may have applications for cache drivers for C as well). In addition to your counter trick -
1) read values into cog variables rather than to hub, and then do a burst write to hub using longs rather than bytes. ? 16 or 32 byte blocks
2) unroll the loop to, say, 16 or 32 bytes, and that saves the djnz.
Because of the additional instruction between the second and third read, the NCO timing is critical. You want the output on P8 to be settled when ina is fetched during the source read cycle.
In that case why not throw another counter at it? If anything we have enough of them.
While not strictly necessary let's make some more room for whatever may be required. The version below does what I know as "pulling a lonesock". I'm sure other clever people came up with the same thing, point is I know it under that name.
I am now looking into adding "saturation" to this circuit. With just a few more parts and no code changes this setup should produce 4 levels of saturation.
Please take a look at the schematic in the first spin file, did I get the diodes right !
P.S. I can now upload files so zip archive is included.
{{
16bit NTSC video modifications November 23 2011 Perry James Mole pjm@hey-hello.ca
┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
│ NTSC 8bpp bitmap TV driver demo (C) 2011-08-19 Eric Ball │
├──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ TERMS OF USE: Parallax Object Exchange 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. │
└──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
}}
CON
' Set up the processor clock in the standard way for 80MHz
_XINFREQ = 13_500_000 + 0000
_CLKMODE = XTAL1 + PLL8X
' _clkmode = xtal1 + pll16x
' _clkfreq = 80_000_000
' Demoboard TV output on pins 13 and 15
TV_PIN = 12
biWidth = 64 '92 '92 '98
biHeight = 128 '72
{
This driver's concept is to produce an HSL video circuit
hue ,saturation, luminance
hue 16 values
saturation 4 values
luminance 128 values
┌───────────────┐
│ 470Ω │
└────────┐ │
saturation0..... pin 12 ─────────────┘ │
470Ω │
hue............. pin 13 ──────────────┫
┌───────────────┫
│ 240Ω │
└────────┐ │
saturation1..... pin 14 ─────────────┘ │
 0.001µF
124Ω │
luminance....... pin 15 ──────────────┻──────┳───┳───── Composite Video output
191Ω   470pf
 
Notes from Grey TV driver:
This driver uses PWM to generate output so a low pass filter is recommended:
The resistor values (124Ω series, 191Ω to ground) have an output impedance of
75 ohms and will drive a 75-ohm load at 1V P-P. The cap is there to filter the
DUTY doody. - Phil Pilgrim
http://forums.parallax.com/forums/default.aspx?f=25&m=340731&g=342216
However, in my experience, the RC network is not required. I have tested
successfully using any of the Demoboard TV DAC resistors (although the higher
resistance yields darker text) and with no resistors at all (although this
is not recommended).
}
OBJ
tv : "Pixelator_II_NTSC" '"NTSC 8bpp"
VAR
' NTSC8bpp input parameters - 7 contiguous longs, reloaded each frame
' Note: NTSC8bpp input parameters not validated, minimum clockspeed 16.364MHz
LONG i_ptr ' pointer to screen (bytes, long aligned), 0 = inactive
LONG i_width ' number of columns, must be divisible by 4 (i_width*i_clocks < 3192-3894MHz/CLKFREQ)
LONG i_height ' number of rows (max i_lines)
LONG i_clocks ' pixel width in 16x colorburst clocks (256 => i_clocks > 515MHz/CLKFREQ)
LONG i_lines ' number of active lines (max 482, does not need to be integer multiple of i_height)
LONG i_pin ' must be divisible by 4, i_pin = 1.1kΩ, i_pin+1 = 560Ω, i_pin+2 = 270Ω
LONG i_frqa ' 0 = calculate FRQA using CLKFREQ=long[0], MSB set = mask of calculated value, MSB clear = value to use
long i_gain ' output video gain Added for Pixelator
long i_colors ' color video flags Added for Pixelator
long ix_colors
' For "square" pixels 3*i_height*i_clocks = 14*i_lines
' i_clocks < 10 and i_lines < 2*i_height will generate color artifacts instead of extra detail
' Due to overscan not all of the screen is visible on all TVs.
' "Action Safe" i_width*i_clocks < 2750, i_lines < 433; "Title Safe" i_width*i_clocks < 2444, i_lines < 385
word bitmap[biWidth*biHeight]
word hue, saturation, intensity
PUB start | color,i,j,ver
tv.start( @i_ptr )
i_width := biWidth
i_height := biHeight
i_lines := 480
i_clocks := 33 '34
i_pin := TV_PIN
i_frqa := 0
i_ptr := @bitmap
i_gain := 24
i_colors := $0_00
repeat j from 0 to biHeight-1 step 1
repeat i from 0 to biWidth-1 step 1
intensity := (j*2) & $7F
bitmap[i+j*biWidth] := intensity
case intensity&3
0: saturation := $0
1: saturation := $1
2: saturation := $4
3: saturation := $5
hue := (i/4 & $F )<<4
if j > 64
bitmap[i+j*biWidth] |= (hue | saturation | 8 ) << 8
' if j == 64
' bitmap[i+j*biWidth] := $0
if j > 118
bitmap[i+j*biWidth] := $d830
and the TV driver updated
{{
┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
│ NTSC 8bpp bitmap TV driver (C) 2011-06-16 Eric Ball │
├──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│
modifications for 16 bit November 23 Perry James Mole
most changes should be commented with ' PJM
added concept for saturation
│
│ The NTSC8bpp TV driver displays a i_width x i_height image on a TV using standard 3pin TV DAC. │
│ The bitmap is padded horizontally and scaled vertically to i_lines. │
│ Pixels are stored in display order (left to right, top to bottom). │
│ │ │
├──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ TERMS OF USE: Parallax Object Exchange 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. │
└──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
}}
VAR
' long cog
{{
' NTSC8bpp input parameters - 7 contiguous longs, reloaded each frame
' Note: NTSC8bpp input parameters not validated, minimum clockspeed 16.364MHz
LONG i_ptr ' pointer to screen (bytes, long aligned), 0 = inactive
LONG i_width ' number of columns, must be divisible by 4 (i_width*i_clocks < 3192-3894MHz/CLKFREQ)
LONG i_height ' number of rows (max i_lines) square pixel = (14*i_height)/(3*i_lines)
LONG i_clocks ' pixel width in 16x colorburst clocks (256 => i_clocks > 515MHz/CLKFREQ)
LONG i_lines ' number of active lines (max 482, does not need to be integer multiple of i_height)
LONG i_pin ' must be divisible by 4, i_pin = 1.1kΩ, i_pin+1 = 560Ω, i_pin+2 = 270Ω
LONG i_frqa ' 0 = calculate FRQA using CLKFREQ=long[0], MSB set = mask of calculated value, MSB clear = value to use
LONG l_Gain ' PJM added to control greyscale output dynamicaly ie contrast
' For "square" pixels 3*i_height*i_clocks = 14*i_lines
' i_clocks < 10 and i_lines < 2*i_height will generate color artifacts instead of extra detail
' Due to overscan not all of the screen is visible on all TVs.
' "Action Safe" i_width*i_clocks < 2750, i_lines < 433; "Title Safe" i_width*i_clocks < 2444, i_lines < 385
}}
PUB start( parmptr )
stop
RESULT := COGNEW( @cogstart, parmptr)
cog := RESULT + 1
RETURN
PUB stop
COGSTOP( cog~ - 1 )
DAT
{{
The purpose of this code is twofold. First, it can be used to display a
byte per pixel (TV color) bitmap. Second, this code is intended to be a
template which may be used by others to develop Propeller video drivers.
Note: this code creates an 29.97Hz 525 line interlaced display.
Rules for developing video drivers:
1. Start simple. Hardcode values and static display.
2. Add complexity and changes incrementally. Verify at each step.
3. If something doesn't work it's either because you have made an incorrect
assumption or made a coding error.
}}
ORG 0
cogstart RDLONG i_ptr, PAR WZ
IF_Z JMP #cogstart
MOV taskptr, #taskone
MOV numlines, #4
:dotasks JMPRET taskptr, taskptr
DJNZ numlines, #:dotasks
{{
An interlaced NTSC frame is made up of 525 lines:
9 lines vertical sync (6 equalizing pulses, 6 serration pulses, 6 equalizing pulses)
12 lines blank
241 lines active (top field / first line)
half line (with sync pulse)
9 lines vertical sync (6 equalizing pulses, 6 serration pulses, 6 equalizing pulses)
half line (without sync pulse)
12 lines blank
241 lines active (bottom field / last line)
A non-interlaced NTSC frame is made up of 262 lines:
9 lines vertical sync (6 equalizing pulses, 6 serration pulses, 6 equalizing pulses)
12 lines blank
241 lines active
}}
frame MOV numlines, numblank0 WZ ' overscan blank lines
MOV taskptr, #taskone ' reload parameters
IF_NZ CALL #blank
MOV nxtptr, i_ptr
MOV linenum, i_lines
MOV numlines, numodd
CALL #active
MOV numlines, numblank1 WZ ' overscan blank lines
IF_NZ CALL #blank
MOV VSCL, vscl_sync ' half line
WAITVID dblank, #0
MOV FRQB, #0 ' PJM
MOV VSCL, vscl_serr
WAITVID dblank, sblank
MOV FRQB, pwmlut ' PJM
CALL #vsync
MOV VSCL, vscl_half ' extend blank for 1/2 line
WAITVID dblank, sblank
MOV FRQB, #0 ' PJM
{
One of the limitations of TV.spin is it only allows integer vertical
scaling. This calculation (and the matching calculation inside the active
loop) scales a i_height bitmap to i_lines. Note: the first line is
always displayed on the top field.
}
MOV nxtptr, i_ptr
MOV linenum, i_lines
SUB linenum, i_height WZ,WC ' set scaling for 2nd line
IF_Z_OR_C ADD linenum, i_lines
IF_Z_OR_C ADD nxtptr, i_width ' go to next line (single line res)
IF_Z_OR_C ADD nxtptr, i_width ' go to next line (single line res)
MOV numlines, numblank2 WZ ' overscan blank lines
IF_NZ CALL #blank
MOV numlines, numeven
CALL #active
MOV numlines, numblank3 WZ ' overscan blank lines
IF_NZ CALL #blank
CALL #vsync ' moved here to reduce instructions
' from active to equalizing
JMP #frame
{{
As each pixel may be any color, the pixels are effectively the color values.
Therefor the code uses a "reverse WAITVID" which uses the pixel value for the
color (destination) parameter and #%%3210 to output the colors in LSB first
order. The downside of this method is it requires more RAM and the maximum
resolution is clockspeed limited (which isn't a problem for composite NTSC
which is bandwidth limited by the colorburst frequency).
}}
active MOV VSCL, vscl_sync ' 4.7usec @ -40 IRE (sync pulse)
WAITVID dblank, #0
MOV FRQB, #0 ' PJM
MOV pixptr, nxtptr ' precalculate pointer
SUB linenum, i_height WZ,WC ' vertical scaling calculations
IF_Z_OR_C ADD linenum, i_lines
IF_Z_OR_C ADD nxtptr, w_width ' go to next line
SUB linenum, i_height WZ,WC ' do twice for interlace
IF_Z_OR_C ADD linenum, i_lines
IF_Z_OR_C ADD nxtptr, w_width ' go to next line
MOV numpixels, i_width
MOV VSCL, vscl_s2cb ' 0.6usec @ 0 IRE (blank)
WAITVID dblank, sblank
MOV FRQB, pwmlut ' PJM
MOV VSCL, vscl_burst ' 9 cycles of colorburst
WAITVID dblank, sburst
MOV FRQB, pwmlut ' PJM
MOV VSCL, vscl_edge
WAITVID dblank, sblank
MOV FRQB, black ' PJM
mov vs4,vscl_active ' PJM
shr vs4,#2 ' PJM
MOV VSCL, vs4 'vscl_active ' PJM
' i_clocks PLLA per pixel, 4 pixels per frame
' WAITVID pixel, #%%0
:loop RDword pixel, pixptr ' PJM'RDLONG pixel, pixptr 7 - 22 ' 22 CLK
' WAITVID pixel, #%%3210
' ADD pixptr, #4
mov luminance,pixel ' PJM ' +4 CLK 26
rol luminance,l_Gain ' PJM ' +4 CLK 30
add luminance,black ' PJM ' +4 CLK 34
WAITVID pixel, #%%1 ' PJM ' +5 CLK 39
MOV FRQb,luminance ' PJM ' +4 CLK 43
ADD pixptr, #2 ' PJM ' +4 CLK 47
DJNZ numpixels, #:loop ' +4 CLK = 51 to 44 CLKs
MOV VSCL, vscl_edge
WAITVID dblank, sblank
MOV FRQB, black ' PJM
DJNZ numlines, #active ' next line
active_ret RET
{{
Video drivers are constrained by WAITVID to WAITVID timing. In the inner
active display loop, this determines the maximum resolution at a given clock
frequency. Other WAITVID to WAITVID intervals (e.g. front porch) determine
the minimum clock frequency.
For example the inner :loop in this code is 36 CLK and displays 4 pixels.
Therefore with an 80MHz clock the minimum VSCL.PixelClocks (i_width) is 7.
36 / 80MHz * 57.272727MHz / 4 = 6.44
Similar calculations should be used between each pair of WAITVIDs to determine
the minimum clock frequency (including initialization tasks).
Note: the first HUBOP after a WAITVID should be counted as 22 CLK as it cannot
be synchronized. WAITVID should be counted as 6 CLK as 5 CLK can cause
intermittent errors with very tight timing.
}}
vsync MOV numlines, #6
:equal1 MOV VSCL, vscl_eqlo ' equalizing pulse (sync/2)
WAITVID dblank, #0
mov frqb,#0 ' PJM
MOV VSCL, vscl_eqhi
WAITVID dblank, sblank
mov frqb,pwmlut ' PJM
DJNZ numlines, #:equal1
MOV numlines, #6
:serration MOV VSCL, vscl_serr ' serration pulse (sync)
WAITVID dblank, #0 ' PJM
mov frqb,#0
MOV VSCL, vscl_sync
WAITVID dblank, sblank
mov frqb,pwmlut ' PJM
DJNZ numlines, #:serration
MOV numlines, #6
:equal2 MOV VSCL, vscl_eqlo ' equalizing pulse (sync/2)
WAITVID dblank, #0
mov frqb,#0 ' PJM
MOV VSCL, vscl_eqhi
WAITVID dblank, sblank
mov frqb,pwmlut ' PJM
DJNZ numlines, #:equal2
vsync_ret RET
blank MOV VSCL, vscl_sync ' 4.7usec @ -40 IRE (sync pulse)
WAITVID dblank, #0 ' PJM
mov frqb,#0
MOV VSCL, vscl_s2cb ' 0.6usec @ 0 IRE (blank)
WAITVID dblank, sblank
mov frqb,pwmlut
MOV VSCL, vscl_burst ' 9 cycles of colorburst
WAITVID dblank, sburst
mov frqb,pwmlut ' PJM
MOV VSCL, vscl_half
WAITVID dblank, sblank
mov frqb,pwmlut ' PJM
JMPRET taskptr, taskptr
MOV VSCL, vscl_blank
WAITVID dblank, sblank
mov frqb,#0 ' PJM
DJNZ numlines, #blank ' next line
blank_ret RET
d1 LONG |<9 ' destination = 1
taskone MOV pixptr, PAR ' load input parameters
MOVD :i_loop, #i_ptr ' 242 CLK
MOV numpixels, #8 ' ' PJM #7 add l_Gain to inputs
:i_loop RDLONG i_ptr, pixptr
ADD pixptr, #4
ADD :i_loop, d1
DJNZ numpixels, #:i_loop
MOV W_width,i_width ' PJM now using words for pixel depth
shL W_width,#1
CMP i_ptr, #0 WZ ' 0 = blank
IF_Z JMP #standby ' 8 CLK
MOV vscl_active, i_clocks ' vscl_active = i_clocks<<12 + i_clocks*4
SHL vscl_active, #12 ' 16 CLK
ADD vscl_active, i_clocks
SHL vscl_active, #2
MOV vscl_edge, vscl_edge0 ' vscl_edge = 1<<12 + (3192 - i_clocks*i_width)/2
MOV numerator, i_width ' 120 CLK
MOV divisor, i_width
MAX numerator, i_clocks
MIN divisor, i_clocks
:mul SHR divisor, #1 WZ,WC ' maximum 6 iterations
IF_C SUB vscl_edge, numerator
SHL numerator, #1
IF_NZ JMP #:mul
SHR vscl_edge, #1
{
The calculations here accomplish two tasks: ensure the blank lines are
distributed correctly and add on the blank lines to the top of each field.
}
' numeven := rounddown(i_lines / 2)
MOV numeven, i_lines ' 60 CLK
SHR numeven, #1
' numodd := roundup(i_lines / 2)
MOV numodd, i_lines
SUB numodd, numeven
' numblank2 := numblank0 := int( (484-i_lines)/4 ) + 12
MOV numblank0, #484
SUB numblank0, i_lines
SHR numblank0, #2
ADD numblank0, #12
MOV numblank2, numblank0
' numblank1 := int( (482-i_lines)/4 )
MOV numblank1, #482
SUB numblank1, i_lines
SHR numblank1, #2
' numblank3 := numblank1 + i_lines // 2
MOV numblank3, i_lines
AND numblank3, #1
ADD numblank3, numblank1
JMPRET taskptr, taskptr ' 242+8+16+120+60 = 446 CLK
add i_pin,#3 ' ' PJM for Grey duty cycle
MOVS CTRb, i_pin
MOV pixel, #1
SHL pixel, i_pin
mov DIRA, pixel
sub i_pin,#3 ' PJM set pin back
MOVI CTRb, #%0_00110_111 ' PJM use PLL%1 was #%0_00110_000 ' turn on PWM
AND i_pin, #28 ' 16 CLK
MOV pixel, #%0010 'PJM use only color pin '7 summing network output
' PJM use origional value when saturation circuit is in place
SHL pixel, i_pin
or DIRA, pixel ' set pin mask
MOV pixel, i_pin ' 36 CLK
SHR pixel, #3
MOVD VCFG, pixel ' set VGroup
AND i_pin, #4 WZ
MOV pixel, #7
SHL pixel, i_pin
MOVS VCFG, pixel ' set VPins
IF_Z MOVI VCFG, #%0_10_1_0_1_000 ' composite baseband on VPins[2..0]
IF_NZ MOVI VCFG, #%0_11_1_0_1_000 ' composite baseband on VPins[6..4]
RDLONG divisor, #0 ' CLKFREQ
MOV quotient, l9090909 ' 306 CLK
MOV numerator, l7159090
:shlmax SHL quotient, #1 WC ' maximize the two values
RCL numerator, #1 ' maximum 17 iterations (based on minimum 16MHz CLK)
SHL divisor, #1 WC
IF_NC JMP #:shlmax
RCR divisor, #1 ' undo overshoot
JMPRET taskptr, taskptr ' 16+36+306 = 358 CLK
MOV numpixels, #16 ' do division (first half)
:div1 CMPSUB numerator, divisor WC ' 264 CLK
RCL quotient, #1
SHR divisor, #1 WZ
DJNZ numpixels, #:div1
JMPRET taskptr, taskptr ' 264 CLK
:div2 CMPSUB numerator, divisor WC ' complete division
RCL quotient, #1 ' 264 CLK
SHR divisor, #1 WZ
IF_NZ JMP #:div2
{
See http://www.linusakesson.net/programming/propeller/pllsync.php
for synchronizing multiple video output cogs
Otherwise just be aware that due to PLL startup time and the initial
value of the internal frame counter being unknown that the timing
and stability of the first frame is not predictable.
}
MOV VSCL, ivscl ' set VSCL to instant reload
MOVI CTRA, #%0_00001_110 ' PLL internal mode, x8 CTRA = 57.2727272MHz (colorburst * 16)
SHL i_frqa, #1 WC,WZ,NR ' test MSB/zero
IF_NZ_AND_NC MOV quotient, i_frqa
IF_C AND quotient, i_frqa
MOV FRQA, quotient ' set CTRA to 7.159MHz, start the counters
lasttask JMPRET taskptr, taskptr ' 256+24 = 280 CLK
JMP #lasttask
standby MOV DIRA, #0
MOV VCFG, #0
MOV CTRA, #0
MOV CTRb, #0
JMP #cogstart
l7159090 LONG $6D3D32 ' 7159090 Hz
l9090909 LONG $E8BA2E8B ' 0.909090909 Hz
ivscl LONG 1<<12+1 ' initial delay
vscl_sync LONG 1<<12+269 ' 4.7usec
vscl_s2cb LONG 1<<12+304-269 ' sync to colorburst
vscl_burst LONG 16<<12+16*9 ' 16 PLLA per cycle, 9 cycles of colorburst
vscl_eqlo LONG 1<<12+135 ' sync/2
vscl_eqhi LONG 1<<12+1685 ' H/2 - sync/2
vscl_serr LONG 1<<12+1551 ' H/2 - sync
vscl_half LONG 1<<12+1820 ' H/2
vscl_blank LONG 1<<12+1372
dblank LONG $8A0200
sblank LONG %%1111_1111_1111_1111 ' 16 pixels color 1
sburst LONG %%2222_2222_2222_2222 ' 16 pixels color 2
vscl_edge0 LONG 1<<13+3192 ' initial value (pre shifted)
pwmlut LONG $3fff_ffff '$3824_4924 '$45555555 '$3d249249 ' PJM
black LONG $4fff_ffff '$3daaaaaa '$3e93B84A ' PJM
'burst LONG $4e44ffff '$3f000000 ' PJM
'color_mask long $FFFFFFF0 ' PJM
cog long 0
luminance long
lum0 byte 0
lum1 byte 0
lum2 byte 0
lum3 byte 0
vscl_edge RES 1 ' border, 1 PLLA per pixel
vscl_active RES 1 ' 4 pixels @ i_clocks PLLA per pixel
i_ptr RES 1 ' pointer to screen (bytes) 0 = inactive
i_width RES 1 ' number of longs (4 pixels per long)
i_height RES 1 ' number of rows
i_clocks RES 1 ' pixel width
i_lines RES 1 ' number of active lines
i_pin RES 1 ' pin number
i_frqa RES 1 ' FRQA value / mask
l_gain res 1
W_width RES 1 ' number of longs (4 pixels per long)
numeven RES 1 ' number of even active lines
numodd RES 1 ' number of odd active lines
numblank0 RES 1
numblank1 RES 1
numblank2 RES 1
numblank3 RES 1
quotient RES 1
numerator RES 1
divisor RES 1
taskptr RES 1 ' initialization task jmpret pointer
numlines RES 1 ' overall line counter
linenum RES 1 ' line scaling counter
numpixels RES 1 ' pixel counter
pixptr RES 1 ' pointer to pixels
nxtptr RES 1 ' pointer to next line
pixel RES 1 ' pixel value
vs4 res 1
FIT 496
Comments
Because of the additional instruction between the second and third read, the NCO timing is critical. You want the output on P8 to be settled when ina is fetched during the source read cycle.
-Phil
Well that has me thinking about two more things (which may have applications for cache drivers for C as well). In addition to your counter trick -
1) read values into cog variables rather than to hub, and then do a burst write to hub using longs rather than bytes. ? 16 or 32 byte blocks
2) unroll the loop to, say, 16 or 32 bytes, and that saves the djnz.
Thanks for all the comments guys.
I am now looking into adding "saturation" to this circuit. With just a few more parts and no code changes this setup should produce 4 levels of saturation.
Please take a look at the schematic in the first spin file, did I get the diodes right !
P.S. I can now upload files so zip archive is included.
and the TV driver updated