Cogjects - load cog code from SD and save hub ram

Attached is an early version of a Cogject loader. Take a typical object from the Obex, split it into its Spin and PASM components, compile the PASM part, rename the binary file as a .cog file, copy it to an SD card and then load it through a common location in hub ram.
Why bother? Well, normally every cog that is loaded leaves its image in hub ram. In a worst case scenario, you might load 7 cogs each with 2k of code making a total of 14k. That is a significant part of the total 32k in hub.
With the advent of many boards with sd cards, as well as fast sd card code, it is now possible to load cogs from the sd card.
It ends up pretty easy to use once the code has been written. Just two lines of spin code:
The first line reads the file into a cog array. And the second line starts the cog using parameters from the standard Start method.
Attached is some demo code. I have the keyboard and the serial driver working - so you just need to copy serial.cog and keyboard.cog to the sd card.
At the moment this is using the VGA driver from Kyedos as the display. The next challenge is to put the video driver into a cog as well. And a TV driver. And a graphics driver, so you can boot up with text and then change to graphics on the fly...
The underlying SD driver is Kye's SD driver from a few months back.
We can save a lot of space on this program. Compile it on BST with the "remove unused methods" checkbox ticked and it is a lot smaller as almost all the sd driver code is not used.
Also, it may be possible to recycle the SD cog code space as the generic cog array.
Building .cog files depends on the style of the original author. Chip Gracey's original objects tend to group variables and pass a pointer to the start of the first variable. Kye uses a method of poking new values into the hex code, and we can do this too after the .cog file has been loaded off the sd card, thanks to an idea from Ariba where you create a variable length dummy array in the middle of the cog code so that the program fills from the bottom up and the variables fill from the top down.
Another advantage of cogjects is you can use the same ones for other languages, eg Basic and C. Indeed, these two cogjects were originally written and tested in Catalina before being used here in Spin.
I hope others might find this useful. I'd like to think we could add some more cogjects to the library fairly quickly.
My next one to do is the standard VGA driver and then the mouse.
Addit April 10th, including a demo program that loads and unloads the following:
1) Serial
2) Keyboard
3) Mouse
4) VGA 80x40 text
5) VGA 100x50 text
6) VGA 128x64 text
7) VGA 160x120 with 64 color graphics
8) VGA 320x240 with 4 color graphics
9) External ram driver
Addit - the April 10th zip still was running the cog from the .DAT section. Deleted this in the April 11 version and fixed a minor bug in the .cog code (my apologies to the 2 people who have downloaded the April 10th version)
Why bother? Well, normally every cog that is loaded leaves its image in hub ram. In a worst case scenario, you might load 7 cogs each with 2k of code making a total of 14k. That is a significant part of the total 32k in hub.
With the advent of many boards with sd cards, as well as fast sd card code, it is now possible to load cogs from the sd card.
It ends up pretty easy to use once the code has been written. Just two lines of spin code:
ReadCogFile(string("Serial.Cog"))
cognew(@cogarray+24, serial.start(31,30,0,115200))
The first line reads the file into a cog array. And the second line starts the cog using parameters from the standard Start method.
Attached is some demo code. I have the keyboard and the serial driver working - so you just need to copy serial.cog and keyboard.cog to the sd card.
At the moment this is using the VGA driver from Kyedos as the display. The next challenge is to put the video driver into a cog as well. And a TV driver. And a graphics driver, so you can boot up with text and then change to graphics on the fly...
The underlying SD driver is Kye's SD driver from a few months back.
We can save a lot of space on this program. Compile it on BST with the "remove unused methods" checkbox ticked and it is a lot smaller as almost all the sd driver code is not used.
Also, it may be possible to recycle the SD cog code space as the generic cog array.
Building .cog files depends on the style of the original author. Chip Gracey's original objects tend to group variables and pass a pointer to the start of the first variable. Kye uses a method of poking new values into the hex code, and we can do this too after the .cog file has been loaded off the sd card, thanks to an idea from Ariba where you create a variable length dummy array in the middle of the cog code so that the program fills from the bottom up and the variables fill from the top down.
Another advantage of cogjects is you can use the same ones for other languages, eg Basic and C. Indeed, these two cogjects were originally written and tested in Catalina before being used here in Spin.
I hope others might find this useful. I'd like to think we could add some more cogjects to the library fairly quickly.
My next one to do is the standard VGA driver and then the mouse.
Addit April 10th, including a demo program that loads and unloads the following:
1) Serial
2) Keyboard
3) Mouse
4) VGA 80x40 text
5) VGA 100x50 text
6) VGA 128x64 text
7) VGA 160x120 with 64 color graphics
8) VGA 320x240 with 4 color graphics
9) External ram driver
Addit - the April 10th zip still was running the cog from the .DAT section. Deleted this in the April 11 version and fixed a minor bug in the .cog code (my apologies to the 2 people who have downloaded the April 10th version)
Comments
Though nice code.
Yes, once all the cogs are loaded you can overwrite the Hub Mem their code used. But there are two problems with this:
1. The memory is not necessary contiguous - you could be left with 2k block sprinkled throughout your memory map.
2. You cannot easily re-use the space freed up for more code. This means you are effectively limited to 16k of code space.
Ross.
The 2k blocks of code left over from loading cogs end up scattered all over hub memory. As far as I know, recycling that memory has only ever really been done with the CP/M emulation, and even then it only used some of the potential memory.
And as Ross says, you can't put any program code in that memory. Only data.
So in practice, you are coding away, compiling from time to time and getting more stressed as you can see the available memory running out. What do you do when it does run out? Move to "Big Spin"? (almost ready but not quite). Move to C or Basic running from external memory?
And I'll add a third scenario where you have a nifty program with an SD card driver, video text driver (3 cogs), mouse, keyboard, serial driver and all the cogs are now used up. And you want to boot up with that, have the user enter some command "run my cool game", and then run a graphics intensive program that uses a 5 cog video driver. And you are almost out of RAM.
BTW david, you are a legend for taking on the challenge of better TV graphics using external memory!
I second what RossH said.
I just had an idea for poking data and knowing where to poke without placing all the data at the beginning. If the first instruction is a nop with the start of the variables/constants to be poked, then it is easy to pick up.
I am not sure if this works correctly...
org 0 entry nop variables 'variables is the cog address of the first variable to be poked .....
Also there is something Kye mentioned that is very interesting - if you take some pasm code and hit F8 or F9 and then place the cursor over a variable, down the bottom of the screen it tells you in "OBJ" where that variable ends up.
This assumes that a piece of pasm code is 'stable' and unlikely to change, but there are many objects around where that would be true.
I've been deep inside Chip's VGA driver code and he uses the term "implant" to describe changing a variable that is somewhere in the middle of code. I may end up noting where the 4 variables end up and adjusting those locations directly.
I suspect that a variety of techniques will be useful depending on the style of the original obex code.
It would be much simpler to modify an object if all that was required was a single nop instruction at the start.
However, one has to be careful that the codespace is not all used, and also that the position of the start of the code is not used. I say that because in my 1pin TV driver, the font is stored at cog $000. I have a temporary jump instruction to the code which then replaces the first font long with the correct value. I did it this way because it reduced the instructions in the font renderer to give more chars/line for each clock frequency.
Another advantage to separating the pasm code is the ability to then have the various interfaces (e.g. spin, basic, c, and of course pasm) held separately and compiled within the main program.
Yes, it is cunning things like that where maybe we might have to go back to the original author for advice.
In the process of looking at the VGA driver code there is this
'implant pin settings reg_vcfg := $200000FF + (BasePin & %111000) << 6 i := $FF << (BasePin & %011000)
and I realise that if you are going to be 'implanting' values (Chip's term, and used by Kye and I'm sure others as well), then the object is going to need access to the cog data.
As such, I have changed the start routines, so that instead of the cognew being in the Main routine it is now in the object routine. So startup is this
ReadCogFile(string("Serial.Cog")) serial.start(@cogarray,31,30,0,115200) ' start the cog ReadCogFile(string("Keyboard.Cog")) kb.start(@cogarray,26,27) 'start the keyboard
and an example of the cog load routine
PUB start(cogarray, rxpin, txpin, mode, baudrate) : okay '' Start serial driver - starts a cog '' returns false if no cog available '' '' mode bit 0 = invert rx '' mode bit 1 = invert tx '' mode bit 2 = open-drain/source tx '' mode bit 3 = ignore tx echo on rx stop longfill(@rx_head, 0, 4) longmove(@rx_pin, @rxpin, 3) bit_ticks := clkfreq / baudrate buffer_ptr := @rx_buffer okay := @rx_head ' return the location of the parameter list okay := cog := cognew(cogarray, @rx_head) + 1
which ends up fairly similar to the original code, just that every "start" method is now going to need one variable added = cogarray.
I think that the VGA startup routine now has enough information to modify the cog code prior to loading.
@cluso99, I took a look at BST but I could not see how to get the printout of the variable locations. Is that in a compile menu or something?
Addit: another little edit, now discarding the first 24 bytes so that the array is the same as the one used in C, ie the first cog element is the first one.
PRI ReadCogFile(Filename) result := \fat.openFile(Filename, "R") ' create file and open file result := \fat.readdata(@cogarray,24) ' read first 24 bytes and discard result := \fat.readdata(@cogarray,fat.filesize-24) ' read the data into cogarray result := \fat.closefile
This brings up the next question as to what those variables at the bottom of the screen mean.
Take this little bit of code
org 0 'set origin to $000 for start of program myvariable long $AAAAAAAA
If I do an F9 on that and put the cursor on myvariable, I get
DAT myvariable = OBJ[$0008] COG[$000]
from that I would assume that COG is the location of the variable, not OBJ.
Further down the program though, OBJ increments a lot faster than COG. OBJ seems to be incrementing too fast (it is $0008 even on the first long) but OBJ seems to be incrementing too slow. Which one is pointing to the location of that variable in the compiled code?
More experiments, the location of a variable seems to be OBJ + $10. This seems a bit odd as I would have expected either no offset, or an offset of $18 (24).
Any advice here would be most appreciated!
Out of curiosity, would it be easier to have 2 seperate programs. The first one with all the drivers to load the cogs and then bootstrap the second program with the actual program code... (Maybe reserving space at beginning or end of memory for cog communications.)
As for your example above, cog $000 would be the resulting address in cog.
I will leave others to comment about the object locations after compile.
Rather than requiring a spin stub to 'implant' the values, I wonder if
long variables | varlength << 9
may be better. This way you would know the length to be copied. In your example above, obviously the array would have to be preset. Your loader would then copy the required variables before performing the cognew function.
Just trying to find a simple way where the pasm object is the only portion required. This way, the pasm object would be stored identically on the SD card no matter what high level code is used. Then we could just have a whole set of standard objects on the sd card. Perhaps these could then be in a subdirectory called PASMOBJ or something similar.
You are definately on to a good thing here
A simpler approach would be to just group all the cog startup objects together in memory. The top object would call all the start routines, which would re-use this chunk of memory. A simple memory allocation scheme could be used, which uses two pointers -- one that points to the beginning of the first startup object, and a second pointer that points to the end of the last startup object. This way all of the object's memory could be re-used including the Spin code and method table. The cogs would need to wait for a start signal before they write into their hub memory so they don't overwrite code that hadn't been executed yet.
Dave
I'd need to think about that some more. It depends on the style of the programmer who wrote the object. If they used the PAR method, and all the variables are contiguous, and there are not many variables, then you could allocate fixed areas in hub at the top - x bytes for a keyboard buffer, y bytes for serial etc. If you allocated them in the same order then the second program would know where these buffers are and would be able to use them.
What I have some reservations about is saying "hub memory area x is always to be allocated for keyboard" because everyones program is going to be different. But what you could have is a starter program that loads keyboard first, then serial and if you start at the top and work down then the second program knows where they are. Your program might load keyboard first then serial, and mine might load serial then keyboard, so this keeps it flexible.
Another idea is to strip down the sd card code to the absolute minimum. There is a lot of functionality in Kye's code, but also a lot of things can be done in several ways and maybe all that code is not needed.
One thing I would like to do is to be able to present a shell of a program that has all the basics - display, keyboard, mouse, serial, sd card, but still has plenty of room free for whatever the user wants to code.
Also I want to document some of the technical aspects of translating objects because I think these techniques are likely to be able to be reused.
In Spin, all one needs is an external memory driver, and these are fairly straightforward for the Dracblade, C3 and Jazzed's external ram.
If this system becomes more popular, one could also think about storing cogjects in eeprom.
I think I have cracked the code for working out the offsets for storing bytes. Let's talk in hex for a bit!
Compile some typical cog code and put the cursor over a variable and you might get a value of 0x8C. Look at the source code using F8 and it actually is 0x10 higher than this, at 0x9C. But the first 0x18 bytes are discarded, so this is the same as adding 0x10 and then subtracting 0x18, which is the same as subtracting 0x8.
We discard the first 0x18 bytes of all cogs when loading them. So the answer to locating variables is to do an F9, place the cursor over the variable and then subtract 0x8 from that value. This gives the real location in a piece of cog code that starts at ORG 0.
And to test this is correct, take a dummy piece of code:
ORG 0
myvariable long $AAAAAAAA
hit F9, you get a value of 0008, subtract 8 and this gives zero which fits with it being the first long.
Would some kind soul be able to please explain what this line does?
'implant unique settings and launch first COG vf_lines.byte := vf
The only place vf_lines is referenced is in the cog code, but it is a line of code, not a variable viz
vf_lines mov x,#vf 'do vertical front porch lines (# set at runtime) call #blank jmp #vsync 'new field, loop to vsync
entire program
''*************************************** ''* VGA High-Res Text Driver v1.0 * ''* Author: Chip Gracey * ''* Copyright (c) 2006 Parallax, Inc. * ''* See end of file for terms of use. * ''*************************************** '' '' This object generates a 1024x768 VGA signal which contains 128 columns x 64 '' rows of 8x12 characters. Each row can have a unique forground/background '' color combination and each character can be inversed. There are also two '' cursors which can be independently controlled (ie. mouse and keyboard). A '' sync indicator signals each time the screen is refreshed (you may ignore). '' '' You must provide buffers for the screen, colors, cursors, and sync. Once '' started, all interfacing is done via memory. To this object, all buffers are '' read-only, with the exception of the sync indicator which gets written with '' -1. You may freely write all buffers to affect screen appearance. Have fun! '' CON { ' 1024 x 768 @ 57Hz settings: 128 x 64 characters hp = 1024 'horizontal pixels vp = 768 'vertical pixels hf = 16 'horizontal front porch pixels hs = 96 'horizontal sync pixels hb = 176 'horizontal back porch pixels vf = 1 'vertical front porch lines vs = 3 'vertical sync lines vb = 28 'vertical back porch lines hn = 1 'horizontal normal sync state (0|1) vn = 1 'vertical normal sync state (0|1) pr = 60 'pixel rate in MHz at 80MHz system clock (5MHz granularity) } { ' 800 x 600 @ 75Hz settings: 100 x 50 characters hp = 800 'horizontal pixels vp = 600 'vertical pixels hf = 40 'horizontal front porch pixels hs = 128 'horizontal sync pixels hb = 88 'horizontal back porch pixels vf = 1 'vertical front porch lines vs = 4 'vertical sync lines vb = 23 'vertical back porch lines hn = 0 'horizontal normal sync state (0|1) vn = 0 'vertical normal sync state (0|1) pr = 50 'pixel rate in MHz at 80MHz system clock (5MHz granularity) } '{ ' 640 x 480 @ 69Hz settings: 80 x 40 characters hp = 640 'horizontal pixels vp = 480 'vertical pixels hf = 24 'horizontal front porch pixels hs = 40 'horizontal sync pixels hb = 128 'horizontal back porch pixels vf = 9 'vertical front porch lines vs = 3 'vertical sync lines vb = 28 'vertical back porch lines hn = 1 'horizontal normal sync state (0|1) vn = 1 'vertical normal sync state (0|1) pr = 30 'pixel rate in MHz at 80MHz system clock (5MHz granularity) '} ' columns and rows cols = hp / 8 rows = vp / 12 VAR long cog[2] PUB start(BasePin, ScreenPtr, ColorPtr, CursorPtr, SyncPtr) : okay | i, j '' Start VGA driver - starts two COGs '' returns false if two COGs not available '' '' BasePin = VGA starting pin (0, 8, 16, 24, etc.) '' '' ScreenPtr = Pointer to 8,192 bytes containing ASCII codes for each of the '' 128x64 screen characters. Each byte's top bit controls color '' inversion while the lower seven bits provide the ASCII code. '' Screen memory is arranged left-to-right, top-to-bottom. '' '' screen byte example: %1_1000001 = inverse "A" '' '' ColorPtr = Pointer to 64 words which define the foreground and background '' colors for each row. The lower byte of each word contains the '' foreground RGB data for that row, while the upper byte '' contains the background RGB data. The RGB data in each byte is '' arranged as %RRGGBB00 (4 levels each). '' '' color word example: %%0020_3300 = gold on blue '' '' CursorPtr = Pointer to 6 bytes which control the cursors: '' '' bytes 0,1,2: X, Y, and MODE of cursor 0 '' bytes 3,4,5: X, Y, and MODE of cursor 1 '' '' X and Y are in terms of screen characters '' (left-to-right, top-to-bottom) '' '' MODE uses three bottom bits: '' '' %x00 = cursor off '' %x01 = cursor on '' %x10 = cursor on, blink slow '' %x11 = cursor on, blink fast '' %0xx = cursor is solid block '' %1xx = cursor is underscore '' '' cursor example: 127, 63, %010 = blinking block in lower-right '' '' SyncPtr = Pointer to long which gets written with -1 upon each screen '' refresh. May be used to time writes/scrolls, so that chopiness '' can be avoided. You must clear it each time if you want to see '' it re-trigger. 'if driver is already running, stop it stop 'implant pin settings reg_vcfg := $200000FF + (BasePin & %111000) << 6 i := $FF << (BasePin & %011000) j := BasePin & %100000 == 0 reg_dira := i & j reg_dirb := i & !j 'implant CNT value to sync COGs to sync_cnt := cnt + $10000 'implant pointers longmove(@screen_base, @ScreenPtr, 3) font_base := @font 'implant unique settings and launch first COG vf_lines.byte := vf vb_lines.byte := vb font_third := 1 cog[1] := cognew(@d0, SyncPtr) + 1 'allow time for first COG to launch waitcnt($2000 + cnt) 'differentiate settings and launch second COG vf_lines.byte := vf+4 vb_lines.byte := vb-4 font_third := 0 cog[0] := cognew(@d0, SyncPtr) + 1 'if both COGs launched, return true if cog[0] and cog[1] return true 'else, stop any launched COG and return false else stop PUB stop | i '' Stop VGA driver - frees two COGs repeat i from 0 to 1 if cog[i] cogstop(cog[i]~ - 1) CON #1, scanbuff[128], scancode[128*2-1+3], maincode 'enumerate COG RAM usage main_size = $1F0 - maincode 'size of main program hv_inactive = (hn << 1 + vn) * $0101 'H,V inactive states DAT '***************************************************** '* Assembly language VGA high-resolution text driver * '***************************************************** ' This program runs concurrently in two different COGs. ' ' Each COG's program has different values implanted for front-porch lines and ' back-porch lines which surround the vertical sync pulse lines. This allows ' timed interleaving of their active display signals during the visible portion ' of the field scan. Also, they are differentiated so that one COG displays ' even four-line groups while the other COG displays odd four-line groups. ' ' These COGs are launched in the PUB 'start' and are programmed to synchronize ' their PLL-driven video circuits so that they can alternately prepare sets of ' four scan lines and then display them. The COG-to-COG switchover is seemless ' due to two things: exact synchronization of the two video circuits and the ' fact that all COGs' driven output states get OR'd together, allowing one COG ' to output lows during its preparatory state while the other COG effectively ' drives the pins to create the visible and sync portions of its scan lines. ' During non-visible scan lines, both COGs output together in unison. ' ' COG RAM usage: $000 = d0 - used to inc destination fields for indirection ' $001-$080 = scanbuff - longs which hold 4 scan lines ' $081-$182 = scancode - stacked WAITVID/SHR for fast display ' $183-$1EF = maincode - main program loop which drives display org 0 'set origin to $000 for start of program d0 long 1 << 9 'd0 always resides here at $000, executes as NOP ' Initialization code and data - after execution, space gets reused as scanbuff 'Move main program into maincode area :move mov $1EF,main_begin+main_size-1 sub :move,d0s0 '(do reverse move to avoid overwrite) djnz main_ctr,#:move 'Build scanbuff display routine into scancode :waitvid mov scancode+0,i0 'org scancode :shr mov scancode+1,i1 'waitvid color,scanbuff+0 add :waitvid,d1 'shr scanbuff+0,#8 add :shr,d1 'waitvid color,scanbuff+1 add i0,#1 'shr scanbuff+1,#8 add i1,d0 '... djnz scan_ctr,#:waitvid 'waitvid color,scanbuff+cols-1 mov scancode+cols*2-1,i2 'mov vscl,#hf mov scancode+cols*2+0,i3 'waitvid hvsync,#0 mov scancode+cols*2+1,i4 'jmp #scanret 'Init I/O registers and sync COGs' video circuits mov dira,reg_dira 'set pin directions mov dirb,reg_dirb movi frqa,#(pr / 5) << 2 'set pixel rate mov vcfg,reg_vcfg 'set video configuration mov vscl,#1 'set video to reload on every pixel waitcnt sync_cnt,colormask 'wait for start value in cnt, add ~1ms movi ctra,#%00001_110 'COGs in sync! enable PLLs now - NCOs locked! waitcnt sync_cnt,#0 'wait ~1ms for PLLs to stabilize - PLLs locked! mov vscl,#100 'insure initial WAITVIDs lock cleanly 'Jump to main loop jmp #vsync 'jump to vsync - WAITVIDs will now be locked! 'Data d0s0 long 1 << 9 + 1 d1 long 1 << 10 main_ctr long main_size scan_ctr long cols i0 waitvid x,scanbuff+0 i1 shr scanbuff+0,#8 i2 mov vscl,#hf i3 waitvid hvsync,#0 i4 jmp #scanret reg_dira long 0 'set at runtime reg_dirb long 0 'set at runtime reg_vcfg long 0 'set at runtime sync_cnt long 0 'set at runtime 'Directives fit scancode 'make sure initialization code and data fit main_begin org maincode 'main code follows (gets moved into maincode) ' Main loop, display field - each COG alternately builds and displays four scan lines vsync mov x,#vs 'do vertical sync lines call #blank_vsync vb_lines mov x,#vb 'do vertical back porch lines (# set at runtime) call #blank_vsync mov screen_ptr,screen_base 'reset screen pointer to upper-left character mov color_ptr,color_base 'reset color pointer to first row mov row,#0 'reset row counter for cursor insertion mov fours,#rows * 3 / 2 'set number of 4-line builds for whole screen 'Build four scan lines into scanbuff fourline mov font_ptr,font_third 'get address of appropriate font section shl font_ptr,#7+2 add font_ptr,font_base movd :pixa,#scanbuff-1 'reset scanbuff address (pre-decremented) movd :pixb,#scanbuff-1 mov y,#2 'must build scanbuff in two sections because mov vscl,vscl_line2x '..pixel counter is limited to twelve bits :halfrow waitvid underscore,#0 'output lows to let other COG drive VGA pins mov x,#cols/2 '..for 2 scan lines, ready for half a row :column rdbyte z,screen_ptr 'get character from screen memory ror z,#7 'get inverse flag into bit 0, keep chr high shr z,#32-7-2 wc 'get inverse flag into c, chr into bits 8..2 add z,font_ptr 'add font section address to point to 8*4 pixels add :pixa,d0 'increment scanbuff destination addresses add :pixb,d0 add screen_ptr,#1 'increment screen memory address :pixa rdlong scanbuff,z 'read pixel long (8*4) into scanbuff :pixb if_nc xor scanbuff,longmask 'invert pixels according to inverse flag djnz x,#:column 'another character in this half-row? djnz y,#:halfrow 'loop to do 2nd half-row, time for 2nd WAITVID sub screen_ptr,#cols 'back up to start of same row in screen memory 'Insert cursors into scanbuff mov z,#2 'ready for two cursors :cursor rdbyte x,cursor_base 'x in range? add cursor_base,#1 cmp x,#cols wc rdbyte y,cursor_base 'y match? add cursor_base,#1 cmp y,row wz rdbyte y,cursor_base 'get cursor mode add cursor_base,#1 if_nc_or_nz jmp #:nocursor 'if cursor not in scanbuff, no cursor add x,#scanbuff 'cursor in scanbuff, set scanbuff address movd :xor,x test y,#%010 wc 'get mode bits into flags test y,#%001 wz if_nc_and_z jmp #:nocursor 'if cursor disabled, no cursor if_c_and_z test slowbit,cnt wc 'if blink mode, get blink state if_c_and_nz test fastbit,cnt wc test y,#%100 wz 'get box or underscore cursor piece if_z mov x,longmask if_nz mov x,underscore if_nz cmp font_third,#2 wz 'if underscore, must be last font section :xor if_nc_and_z xor scanbuff,x 'conditionally xor cursor into scanbuff :nocursor djnz z,#:cursor 'second cursor? sub cursor_base,#3*2 'restore cursor base 'Display four scan lines from scanbuff rdword x,color_ptr 'get color pattern for current row and x,colormask 'mask away hsync and vsync signal states or x,hv 'insert inactive hsync and vsync states mov y,#4 'ready for four scan lines scanline mov vscl,vscl_chr 'set pixel rate for characters jmp #scancode 'jump to scanbuff display routine in scancode scanret mov vscl,#hs 'do horizontal sync pixels waitvid hvsync,#1 '#1 makes hsync active mov vscl,#hb 'do horizontal back porch pixels waitvid hvsync,#0 '#0 makes hsync inactive shr scanbuff+cols-1,#8 'shift last column's pixels right by 8 djnz y,#scanline 'another scan line? 'Next group of four scan lines add font_third,#2 'if font_third + 2 => 3, subtract 3 (new row) cmpsub font_third,#3 wc 'c=0 for same row, c=1 for new row if_c add screen_ptr,#cols 'if new row, advance screen pointer if_c add color_ptr,#2 'if new row, advance color pointer if_c add row,#1 'if new row, increment row counter djnz fours,#fourline 'another 4-line build/display? 'Visible section done, do vertical sync front porch lines wrlong longmask,par 'write -1 to refresh indicator vf_lines mov x,#vf 'do vertical front porch lines (# set at runtime) call #blank jmp #vsync 'new field, loop to vsync 'Subroutine - do blank lines blank_vsync xor hvsync,#$101 'flip vertical sync bits blank mov vscl,hx 'do blank pixels waitvid hvsync,#0 mov vscl,#hf 'do horizontal front porch pixels waitvid hvsync,#0 mov vscl,#hs 'do horizontal sync pixels waitvid hvsync,#1 mov vscl,#hb 'do horizontal back porch pixels waitvid hvsync,#0 djnz x,#blank 'another line? blank_ret blank_vsync_ret ret 'Data screen_base long 0 'set at runtime (3 contiguous longs) color_base long 0 'set at runtime cursor_base long 0 'set at runtime font_base long 0 'set at runtime font_third long 0 'set at runtime hx long hp 'visible pixels per scan line vscl_line2x long (hp + hf + hs + hb) * 2 'total number of pixels per 2 scan lines vscl_chr long 1 << 12 + 8 '1 clock per pixel and 8 pixels per set colormask long $FCFC 'mask to isolate R,G,B bits from H,V longmask long $FFFFFFFF 'all bits set slowbit long 1 << 25 'cnt mask for slow cursor blink fastbit long 1 << 24 'cnt mask for fast cursor blink underscore long $FFFF0000 'underscore cursor pattern hv long hv_inactive '-H,-V states hvsync long hv_inactive ^ $200 '+/-H,-V states 'Uninitialized data screen_ptr res 1 color_ptr res 1 font_ptr res 1 x res 1 y res 1 z res 1 row res 1 fours res 1 ' 8 x 12 font - characters 0..127 ' ' Each long holds four scan lines of a single character. The longs are arranged into ' groups of 128 which represent all characters (0..127). There are three groups which ' each contain a vertical third of all characters. They are ordered top, middle, and ' bottom. font long long $0C080000,$30100000,$7E3C1800,$18181800,$81423C00,$99423C00,$8181FF00,$E7C3FF00 'top ascii 0-7 long $1E0E0602,$1C000000,$00000000,$00000000,$18181818,$18181818,$00000000,$18181818 long $00000000,$18181818,$18181818,$18181818,$18181818,$00FFFF00,$CC993366,$66666666 long $AA55AA55,$0F0F0F0F,$0F0F0F0F,$0F0F0F0F,$0F0F0F0F,$00000000,$00000000,$00000000 ' ascii 24 to 31 long $00000000,$3C3C1800,$66666600,$7F363600,$667C1818,$46000000,$1B1B0E00,$1C181800 ' 77666600 to 66666600 for the " character (ascii 32 long $0C183000,$180C0600,$66000000,$18000000,$00000000,$00000000,$00000000,$60400000 long $73633E00,$1E181000,$66663C00,$60663C00,$3C383000,$06067E00,$060C3800,$63637F00 long $66663C00,$66663C00,$1C000000,$00000000,$18306000,$00000000,$180C0600,$60663C00 long $63673E00,$66663C00,$66663F00,$63663C00,$66361F00,$06467F00,$06467F00,$63663C00 long $63636300,$18183C00,$30307800,$36666700,$06060F00,$7F776300,$67636300,$63361C00 long $66663F00,$63361C00,$66663F00,$66663C00,$185A7E00,$66666600,$66666600,$63636300 long $66666600,$66666600,$31637F00,$0C0C3C00,$03010000,$30303C00,$361C0800,$00000000 long $0C000000,$00000000,$06060700,$00000000,$30303800,$00000000,$0C6C3800,$00000000 long $06060700,$00181800,$00606000,$06060700,$18181E00,$00000000,$00000000,$00000000 long $00000000,$00000000,$00000000,$00000000,$0C080000,$00000000,$00000000,$00000000 long $00000000,$00000000,$00000000,$18187000,$18181800,$18180E00,$73DBCE00,$18180000 long $080C7E7E,$10307E7E,$18181818,$7E181818,$81818181,$99BDBDBD,$81818181,$E7BD99BD 'middle long $1E3E7E3E,$1C3E3E3E,$30F0C000,$0C0F0300,$00C0F030,$00030F0C,$00FFFF00,$18181818 long $18FFFF00,$00FFFF18,$18F8F818,$181F1F18,$18FFFF18,$00FFFF00,$CC993366,$66666666 long $AA55AA55,$FFFF0F0F,$F0F00F0F,$0F0F0F0F,$00000F0F,$FFFF0000,$F0F00000,$0F0F0000 ' 00000033 to 00000066 for the " character long $00000000,$0018183C,$00000066,$7F363636,$66603C06,$0C183066,$337B5B0E,$0000000C long $0C060606,$18303030,$663CFF3C,$18187E18,$00000000,$00007E00,$00000000,$060C1830 long $676F6B7B,$18181818,$0C183060,$60603860,$307F3336,$60603E06,$66663E06,$0C183060 long $66763C6E,$60607C66,$1C00001C,$00001C1C,$180C060C,$007E007E,$18306030,$00181830 long $033B7B7B,$66667E66,$66663E66,$63030303,$66666666,$06263E26,$06263E26,$63730303 long $63637F63,$18181818,$33333030,$36361E36,$66460606,$63636B7F,$737B7F6F,$63636363 long $06063E66,$7B636363,$66363E66,$66301C06,$18181818,$66666666,$66666666,$366B6B63 long $663C183C,$18183C66,$43060C18,$0C0C0C0C,$30180C06,$30303030,$00000063,$00000000 long $0030381C,$333E301E,$6666663E,$0606663C,$3333333E,$067E663C,$0C0C3E0C,$3333336E long $66666E36,$1818181C,$60606070,$361E3666,$18181818,$6B6B6B3F,$6666663E,$6666663C long $6666663B,$3333336E,$066E7637,$300C663C,$0C0C0C7E,$33333333,$66666666,$6B6B6363 long $1C1C3663,$66666666,$0C30627E,$180C060C,$18181818,$18306030,$00000000,$0018187E long $00000000,$00000000,$00001818,$0000183C,$00003C42,$00003C42,$0000FF81,$0000FFC3 'bottom long $0002060E,$00000000,$18181818,$18181818,$00000000,$00000000,$00000000,$18181818 long $18181818,$00000000,$18181818,$18181818,$18181818,$00FFFF00,$CC993366,$66666666 long $AA55AA55,$FFFFFFFF,$F0F0F0F0,$0F0F0F0F,$00000000,$FFFFFFFF,$F0F0F0F0,$0F0F0F0F long $00000000,$00001818,$00000000,$00003636,$0018183E,$00006266,$00006E3B,$00000000 long $00003018,$0000060C,$00000000,$00000000,$0C181C1C,$00000000,$00001C1C,$00000103 long $00003E63,$00007E18,$00007E66,$00003C66,$00007830,$00003C66,$00003C66,$00000C0C long $00003C66,$00001C30,$0000001C,$0C181C1C,$00006030,$00000000,$0000060C,$00001818 long $00003E07,$00006666,$00003F66,$00003C66,$00001F36,$00007F46,$00000F06,$00007C66 long $00006363,$00003C18,$00001E33,$00006766,$00007F66,$00006363,$00006363,$00001C36 long $00000F06,$00603C36,$00006766,$00003C66,$00003C18,$00003C66,$0000183C,$00003636 long $00006666,$00003C18,$00007F63,$00003C0C,$00004060,$00003C30,$00000000,$FFFF0000 long $00000000,$00006E33,$00003B66,$00003C66,$00006E33,$00003C66,$00001E0C,$1E33303E long $00006766,$00007E18,$3C666660,$00006766,$00007E18,$00006B6B,$00006666,$00003C66 long $0F063E66,$78303E33,$00000F06,$00003C66,$0000386C,$00006E33,$0000183C,$00003636 long $00006336,$1C30607C,$00007E46,$00007018,$00001818,$00000E18,$00000000,$0000007E {{ ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ 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. │ └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ }}
p.s. You cannot see the forest for the trees haha.
pps I will be out your way at Easter, so will see if we can catch up. Must be time for ano Oz UPE
yes, I am so deep inside this code and I know that only one mistake and the whole thing won't work. Is this going to be some sort of "bytemove" taking into account the little endian thing?
Comparing with the original code, do you think this is on the right track?
in the main
VAR byte CogArray[2048] ' reserve space for cogs to be loaded
the calling routine from main
serial.start(@cogarray,other variables...) ' start the cog
and in the object
PUB start(cogarray, BasePin, ScreenPtr, ColorPtr, CursorPtr, SyncPtr) : okay | i, j, reg_dira, reg_dirb, reg_vcfg, sync_cnt 'implant pin settings reg_vcfg := $200000FF + (BasePin & %111000) << 6 ' need to move reg_vcfg to the hub memory location of cogarray plus $8C longmove(cogarray+$8C,@reg_vcfg,1) i := $FF << (BasePin & %011000) j := BasePin & %100000 == 0 reg_dira := i & j ' need to move reg_dira to the hub memory location of cogarray plus $84 longmove(cogarray+$84,@reg_dira,1) reg_dirb := i & !j ' need to move reg_dirb to the hub memory location of cogarray plus $88 longmove(cogarray+$88,@reg_dirb,1) 'implant CNT value to sync COGs to sync_cnt := cnt + $10000 ' need to move reg_dira to the hub memory location of cogarray plus $90 longmove(cogarray+$90,@sync_cnt,1) ' screen_base is at $01F4 using F9 so subtract $8 gives $1EC ' screenptr is passed to this startup routine (don't confuse with screen_ptr) 'implant pointers 'longmove(@screen_base, @ScreenPtr, 3) longmove(cogarray+$1EC,@ScreenPtr,3) ' replaces line above font_base := @font ' ************* got to here *************** 'implant unique settings and launch first COG vf_lines.byte := vf vb_lines.byte := vb
I am wondering if you can do something like this...
' screen_base is at $01F4 using F9 so subtract $8 gives $1EC ' screenptr is passed to this startup routine (don't confuse with screen_ptr) 'implant pointers 'longmove(@screen_base, @ScreenPtr, 3) longmove(cogarray+$1EC,@ScreenPtr,3) ' replaces line above replace with... ' screen_base is at $01F4 using F9 so subtract $8 gives $1EC 'implant pointers 'longmove(@screen_base, @ScreenPtr, 3) longmove(@d0 - @screen_base - $8 + @cogarray,@ScreenPtr,3) ' replaces line above or... addr := @d0 - @screen_base - $8 + @cogarrya 'order is important to prevent overflow/truncation longmove(addr,@ScreenPtr,3)
longmove(@d0 - @screen_base - $8 + @cogarray,@ScreenPtr,3)
You don't have access to any variable names in the cog file any more. All you have is a hex file with a couple of thousand bytes, and that you know they start at "cogarray".
This vga one is pretty messy as there is data being poked to all sorts of locations within the file. Not as simple as the ones that use PAR.
PUB start(cogarray, BasePin, ScreenPtr, ColorPtr, CursorPtr, SyncPtr) : okay | i, j, reg_dira[4], font_base[2] 'implant reg_dira, reg_dirb, reg_vcfg, sync_cnt i := $FF << (BasePin & %011000) j := BasePin & %100000 == 0 reg_dira[0] := i & j reg_dira[1] := i & !j 'reg_dirb reg_dira[2] := $200000FF + (BasePin & %111000) << 6 'reg_vcfg reg_dira[3] := cnt + $10000 'sync_cnt to sync cogs ' now move block reg_dira, reg_dirb, reg_vcfg, sync_cnt into cogarray +$84 longmove(cogarray+$84,reg_dira,4) '??? are the @ correct ??? ' screen_base is at $01F4 using F9 so subtract $8 gives $1EC ' screenptr is passed to this startup routine (don't confuse with screen_ptr) 'implant pointers 'longmove(@screen_base, @ScreenPtr, 3) longmove(cogarray+$1EC,@ScreenPtr,3) ' replaces line above 'implant unique settings and launch first COG font_base[0] := @font 'font_base: same for both font_base[1] := 1 'font_third: longmove(cogarray+$1EC+$00C,font_base[0],2) 'implant bytemove(cogarray+$???,vf,1) 'vf_lines bytemove(cogarray+$???,vb,1) 'vb_lines cog[1] := cognew(@d0, SyncPtr) + 1 'allow time for first COG to launch waitcnt($2000 + cnt) 'differentiate settings and launch second COG (note font_base is screen_base +$00C) font_base[0] := @font 'font_base: same for both font_base[1] := 0 'font_third: longmove(cogarray+$1EC+$00C,font_base[0],2) 'implant bytemove(cogarray+$???,vf+4,1) 'vf_lines bytemove(cogarray+$???,vb-4,1) 'vb_lines cog[0] := cognew(@d0, SyncPtr) + 1
I would think you could insert these two lines at the beginning of the cog code after the d0 line without problems. Then collect these as the offsets into the cogarray rather than using fixed values.
org 0 'set origin to $000 for start of program d0 long 1 << 9 'd0 always resides here at $000, executes as NOP long (d0 - reg_dira << 9) | (d0 - screen_base) 'NOP - used to find offsets for implant long (d0 - vf_lines << 9) | (do - vb_lines) 'NOP - used to find offsets for implant ' Initialization code and data - after execution, space gets reused as scanbuff
PRI Hexdump | i,j,k' print out all the cogject in hex, 32 bytes per line k :=0 repeat i from 0 to 63 ' 2048 bytes is 64 rows x 32 bytes. vt100.hex(k,4) vt100.out(32) repeat j from 0 to 31 vt100.hex(cogarray[k],2) k +=1 if k == 1024 crlf printstringcr(string("Hit a key")) ' 2 pages kb.getkey crlf
Yes that is what it is. No OBJ, only one PUB with a dummy load of the cog. This is just the bare minimum to get it to compile.
You can compile it with the Proptool or with BSTC.
CON _clkfreq = 80_000_000 ' 5Mhz Crystal _clkmode = xtal1 + pll16x ' x 16 PUB Main coginit(1,@entry,0) DAT org entry pasm code goes here
Yes, that is a great idea. You can store cogjects anywhere you like. External ram. SD card. Maybe even put them in the unused part of an EEPROM.
It is done in the spinc.c module included in Catalina.
bytemove(cogarray + $9C, vb-4,1) 'replaces 'vb_lines.byte := vb-4
It seems to be copying random data (to the correct place). vb is a constant, not a variable - maybe this is the issue.
I'm tracing this through by doing a hex dump of the cog memory after it values have been implanted (after being implanted by the second cog load), then comparing this with a screen dump from a working vga driver. There are quite a few differences that I'll need to work on.
Code is below, and near the bottom is a comment section with the cogject code above the correct code.
I wonder if I should do something like this instead
'vf_lines.byte := vf ' original code i := vf bytemove(cogarray + $1B4, @i,1)
Any help would be most appreciated!
addit - that does seem to improve things- now have garbage on the screen instead of a blank screen.
I now realise that these 3 bytes will be different as they point to different locations in each demo program
longmove(cogarray + $1EC,@ScreenPtr,3) ' replaces line above, screen_base, color_base, cursor_base
Getting close here
''*************************************** ''* VGA High-Res Text Driver v1.0 * ''* Author: Chip Gracey * ''* Copyright (c) 2006 Parallax, Inc. * ''* See end of file for terms of use. * ''*************************************** '' '' This object generates a 1024x768 VGA signal which contains 128 columns x 64 '' rows of 8x12 characters. Each row can have a unique forground/background '' color combination and each character can be inversed. There are also two '' cursors which can be independently controlled (ie. mouse and keyboard). A '' sync indicator signals each time the screen is refreshed (you may ignore). '' '' You must provide buffers for the screen, colors, cursors, and sync. Once '' started, all interfacing is done via memory. To this object, all buffers are '' read-only, with the exception of the sync indicator which gets written with '' -1. You may freely write all buffers to affect screen appearance. Have fun! ' move font to spin code ' move 4 variables regdira regdirb etc to a VAR section ' these are going to need to be passed with PAR and replace the 4 variables in the code ' also variables like screenbase are inside the cog code. ' or, compile the cog code with F8 or F9, then put cursor on a variable and look at the OBJ value ' at the bottom of the screen. then poke to these directly ' added 4 variables to the start routine ' calculated the offsets (subtract $8 from whatever value F9 gives) ' longmove to copy these to the cogarray and implant them '' CON { ' 1024 x 768 @ 57Hz settings: 128 x 64 characters hp = 1024 'horizontal pixels vp = 768 'vertical pixels hf = 16 'horizontal front porch pixels hs = 96 'horizontal sync pixels hb = 176 'horizontal back porch pixels vf = 1 'vertical front porch lines vs = 3 'vertical sync lines vb = 28 'vertical back porch lines hn = 1 'horizontal normal sync state (0|1) vn = 1 'vertical normal sync state (0|1) pr = 60 'pixel rate in MHz at 80MHz system clock (5MHz granularity) } { ' 800 x 600 @ 75Hz settings: 100 x 50 characters hp = 800 'horizontal pixels vp = 600 'vertical pixels hf = 40 'horizontal front porch pixels hs = 128 'horizontal sync pixels hb = 88 'horizontal back porch pixels vf = 1 'vertical front porch lines vs = 4 'vertical sync lines vb = 23 'vertical back porch lines hn = 0 'horizontal normal sync state (0|1) vn = 0 'vertical normal sync state (0|1) pr = 50 'pixel rate in MHz at 80MHz system clock (5MHz granularity) } '{ ' 640 x 480 @ 69Hz settings: 80 x 40 characters hp = 640 'horizontal pixels vp = 480 'vertical pixels hf = 24 'horizontal front porch pixels hs = 40 'horizontal sync pixels hb = 128 'horizontal back porch pixels vf = 9 'vertical front porch lines vs = 3 'vertical sync lines vb = 28 'vertical back porch lines hn = 1 'horizontal normal sync state (0|1) vn = 1 'vertical normal sync state (0|1) pr = 30 'pixel rate in MHz at 80MHz system clock (5MHz granularity) '} ' columns and rows cols = hp / 8 rows = vp / 12 VAR long cog[2] PUB start(cogarray, BasePin, ScreenPtr, ColorPtr, CursorPtr, SyncPtr) : okay | i, j, reg_dira, reg_dirb, reg_vcfg, sync_cnt '' Start VGA driver - starts two COGs '' returns false if two COGs not available '' '' BasePin = VGA starting pin (0, 8, 16, 24, etc.) '' '' ScreenPtr = Pointer to 8,192 bytes containing ASCII codes for each of the '' 128x64 screen characters. Each byte's top bit controls color '' inversion while the lower seven bits provide the ASCII code. '' Screen memory is arranged left-to-right, top-to-bottom. '' '' screen byte example: %1_1000001 = inverse "A" '' '' ColorPtr = Pointer to 64 words which define the foreground and background '' colors for each row. The lower byte of each word contains the '' foreground RGB data for that row, while the upper byte '' contains the background RGB data. The RGB data in each byte is '' arranged as %RRGGBB00 (4 levels each). '' '' color word example: %%0020_3300 = gold on blue '' '' CursorPtr = Pointer to 6 bytes which control the cursors: '' '' bytes 0,1,2: X, Y, and MODE of cursor 0 '' bytes 3,4,5: X, Y, and MODE of cursor 1 '' '' X and Y are in terms of screen characters '' (left-to-right, top-to-bottom) '' '' MODE uses three bottom bits: '' '' %x00 = cursor off '' %x01 = cursor on '' %x10 = cursor on, blink slow '' %x11 = cursor on, blink fast '' %0xx = cursor is solid block '' %1xx = cursor is underscore '' '' cursor example: 127, 63, %010 = blinking block in lower-right '' '' SyncPtr = Pointer to long which gets written with -1 upon each screen '' refresh. May be used to time writes/scrolls, so that chopiness '' can be avoided. You must clear it each time if you want to see '' it re-trigger. 'if driver is already running, stop it stop 'implant pin settings reg_vcfg := $200000FF + (BasePin & %111000) << 6 ' need to move reg_vcfg to the hub memory location of cogarray plus $8C longmove(cogarray+$8C,@reg_vcfg,1) i := $FF << (BasePin & %011000) j := BasePin & %100000 == 0 reg_dira := i & j ' need to move reg_dira to the hub memory location of cogarray plus $84 longmove(cogarray+$84,@reg_dira,1) reg_dirb := i & !j ' need to move reg_dirb to the hub memory location of cogarray plus $88 longmove(cogarray+$88,@reg_dirb,1) 'implant CNT value to sync COGs to sync_cnt := cnt + $10000 ' need to move reg_dira to the hub memory location of cogarray plus $90 longmove(cogarray+$90,@sync_cnt,1) ' screen_base is at $01F4 using F9 so subtract $8 gives $1EC ' screenptr is passed to this startup routine (don't confuse with screen_ptr) 'implant pointers 'longmove(@screen_base, @ScreenPtr, 3) longmove(cogarray + $1EC,@ScreenPtr,3) ' replaces line above, screen_base, color_base, cursor_base 'font_base := @font longmove(cogarray + $1F8,@font,1) ' replaces line above. Location = $200-8 = $1F8 'implant unique settings and launch first COG 'vf_lines.byte := vf bytemove(cogarray + $1B4, vf,1) ' replaces line above, location $1BC - 8 = 1B4, LSB at beginning 'vb_lines.byte := vb bytemove(cogarray + $9C, vb,1) ' replaces line above $A4-8 = $9C, LSB first 'font_third := 1 longmove(cogarray + $1FC,1,1) ' replaces line above, $204-8=$1FC, put in value of 1 'cog[1] := cognew(@d0, SyncPtr) + 1 cog[1] := cognew(cogarray, SyncPtr) + 1 ' replaces line above 'allow time for first COG to launch waitcnt($2000 + cnt) 'differentiate settings and launch second COG 'vf_lines.byte := vf+4 bytemove(cogarray + $1B4, vf+4,1) ' replaces line above, location $1BC - 8 = 1B4, LSB at beginning 'vb_lines.byte := vb-4 bytemove(cogarray + $9C, vb-4,1) ' replaces line above $A4-8 = $9C, LSB first 'font_third := 0 longmove(cogarray + $1FC,0,1) ' replaces line above, $204-8=$1FC, put in value of 0 'cog[0] := cognew(@d0, SyncPtr) + 1 cog[0] := cognew(cogarray, SyncPtr) + 1 ' replaces line above 'if both COGs launched, return true if cog[0] and cog[1] return true 'else, stop any launched COG and return false else stop { for debugging this is a hex dump after values have been implanted in this program ' second row is the original (correct) one from chips code. ' both of these are the values after the second cog is launched, so vf and vb are different 0000 0002000091DEBFA01802BC840134FCE41C02BDA01D04BDA01908BC80190ABC80 0000 0002000091DEBFA01802BC840134FCE41C02BDA01D04BDA01908BC80190ABC80 0020 0138FC80003ABC800436FCE41E40BEA01F42BEA02044BEA021ECBFA022EEBFA0 0020 0138FC80003ABC800436FCE41E40BEA01F42BEA02044BEA021ECBFA022EEBFA0 0040 18F4FF5823FCBFA001FEFFA0E149BCF80EF0FF580048FCF864FEFFA083017C5C 0040 18F4FF5823FCBFA001FEFFA0E149BCF80EF0FF580048FCF864FEFFA083017C5C 0060 01020000000400006D0000005000000001D63FFC0802FC2818FEFFA000CE7FFC 0060 01020000000400006D0000005000000001D63FFC0802FC2818FEFFA000CE7FFC 0080 BE017C5C 0000FF00 00000000 FF040020 4AD21351 03D6FFA0 CEB1FF5C 56D6FFA0 ' lots of diffs here $90 0080 BE017C5C 0000FF00 00000000 FF040020 C28C030B 03D6FFA0 CEB1FF5C 18D6FFA0 ' this is ok as this is sync_cnt with diff cnt value ' but at 9C there is a difference too, this is vb -4 which should be $18 00A0 CEB1FF5CD9D1BFA0DAD3BFA000DCFFA03CDEFFA0DDD5BFA009D4FF2CDCD5BF80 00A0 CEB1FF5CD9D1BFA0DAD3BFA000DCFFA03CDEFFA0DDD5BFA009D4FF2CDCD5BF80 00C0 0036FF540038FF5402D8FFA0DFFFBFA000CA7FFC28D6FFA0E8DBBF0007DAFF20 00C0 0036FF540038FF5402D8FFA0DFFFBFA000CA7FFC28D6FFA0E8DBBF0007DAFF20 00E0 17DAFF29EADBBF800036BF800038BF8001D0FF80ED03BC08E2038C6C94D7FFE4 00E0 17DAFF29EADBBF800036BF800038BF8001D0FF80ED03BC08E2038C6C94D7FFE4 0100 92D9FFE450D0FF8402DAFFA0DBD7BF0001B6FF8050D67F85DBD9BF0001B6FF80 0100 92D9FFE450D0FF8402DAFFA0DBD7BF0001B6FF8050D67F85DBD9BF0001B6FF80 0120 EED93F86DBD9BF0001B6FF80B6015C5C01D6FF80EB6BBF5402D87F6101D87F62 0120 EED93F86DBD9BF0001B6FF80B6015C5C01D6FF80EB6BBF5402D87F6101D87F62 0140 B601485CF1C72361F1C9136104D87F62E2D7ABA0E5D797A002BA5786EB03886C 0140 B601485CF1C72361F1C9136104D87F62E2D7ABA0E5D797A002BA5786EB03886C 0160 A1DBFFE406B6FF84E9D7BF04E1D7BF60E6D7BF6804D8FFA0E0FFBFA081007C5C 0160 A1DBFFE406B6FF84E9D7BF04E1D7BF60E6D7BF6804D8FFA0E0FFBFA081007C5C 0180 28FEFFA001CE7FFC80FEFFA000CE7FFC08A0FC28BCD9FFE402BAFF8003BAFFE1 0180 28FEFFA001CE7FFC80FEFFA000CE7FFC08A0FC28BCD9FFE402BAFF8003BAFFE1 01A0 50D0F380 02D2F380 01DCF380 8BDFFFE4 F0C53F08 00D6FFA0CFB1FF5C83017C5C ' error 1B4 supposed to implant 13 01A0 50D0F380 02D2F380 01DCF380 8BDFFFE4 F0C53F08 0DD6FFA0CFB1FF5C83017C5C ' 2/3 along diff here 00 vs 0D 01C0 01CFFF6CDEFFBFA000CE7FFC18FEFFA000CE7FFC28FEFFA001CE7FFC80FEFFA0 01C0 01CFFF6CDEFFBFA000CE7FFC18FEFFA000CE7FFC28FEFFA001CE7FFC80FEFFA0 01E0 00CE7FFCCFD7FFE400007C5C 283B0000A8470000F74F00000000080C00B4C404 ' differences here 01E0 00CE7FFCCFD7FFE400007C5C 8C0C00000C1900005C1900001C03000000000000 0200 800200008006000008100000FCFC0000FFFFFFFF00000002000000010000FFFF 0200 800200008006000008100000FCFC0000FFFFFFFF00000002000000010000FFFF 0220 030300000301000036C708352C3200009C68FD5C3F61BEA00760FE600378FE2C 0220 03030000030100000000080C0000103000183C7E00181818003C4281003C4299 ' many diffs here onwards 0240 3079BE680378FE200168FEA01E007C5C025EFE202F33BD50DA32FD801B5EFE28 0260 2F61BEA0005EBEA0305FBE28C3007C5C2DEDBF680DA6FD50D2AEFD5C2CEDBF68 0280 12A6FD50D2AEFD5C2DEDBF6CFF5E7E61005FFE74D85EBE680A60FEA0C59AFD5C 02A0 015EFE292CEDBF74CF96BDA0C69AFD5CA760FEE4D096BDA0C69AFD5CD196BDA0 02C0 C69AFD5CB788FD5CFA5E7E861600545C00007C5C207C7E612D5B3EF40B60FEA0 02E0 C59AFD5C10A6FD50D2AEFD5CF2593E61015EFE30CF96BDA0C69AFD5CB860FEE4 0300 165EFE28FF5F7E6116004C5CFF5EFE6000007C5CCE96BDA0D962BEA012A6FD50 0320 D2AEFD5CF25B3E61F2593E62C762C2E416627EEC00007C5CC762F2E4C762CEE4 0340 C762F6E4C762EEE40064FE080064FE280364FE48F165BE800064FEF800007C5C 0360 00020000C40900000000D8000000D400D200D000D100DB000000D900D700D500 0380 D3000900600000000000F4F5F0000000F2F3710031000000000000007A007300 03A0 61007700320000F6000063007800640065003400330000F70000200076006600 03C0 74007200350000CC00006E006200680067007900360000CD000000006D006A00 03E0 75003700380000CE00002C006B0069006F0030003900000000002E002FEF6C00 } { memory dump from the original vga object - also after values implanted 0000 0002000091DEBFA01802BC840134FCE41C02BDA01D04BDA01908BC80190ABC80 0020 0138FC80003ABC800436FCE41E40BEA01F42BEA02044BEA021ECBFA022EEBFA0 0040 18F4FF5823FCBFA001FEFFA0E149BCF80EF0FF580048FCF864FEFFA083017C5C 0060 01020000000400006D0000005000000001D63FFC0802FC2818FEFFA000CE7FFC 0080 BE017C5C0000FF0000000000FF040020C28C030B03D6FFA0CEB1FF5C18D6FFA0 00A0 CEB1FF5CD9D1BFA0DAD3BFA000DCFFA03CDEFFA0DDD5BFA009D4FF2CDCD5BF80 00C0 0036FF540038FF5402D8FFA0DFFFBFA000CA7FFC28D6FFA0E8DBBF0007DAFF20 00E0 17DAFF29EADBBF800036BF800038BF8001D0FF80ED03BC08E2038C6C94D7FFE4 0100 92D9FFE450D0FF8402DAFFA0DBD7BF0001B6FF8050D67F85DBD9BF0001B6FF80 0120 EED93F86DBD9BF0001B6FF80B6015C5C01D6FF80EB6BBF5402D87F6101D87F62 0140 B601485CF1C72361F1C9136104D87F62E2D7ABA0E5D797A002BA5786EB03886C 0160 A1DBFFE406B6FF84E9D7BF04E1D7BF60E6D7BF6804D8FFA0E0FFBFA081007C5C 0180 28FEFFA001CE7FFC80FEFFA000CE7FFC08A0FC28BCD9FFE402BAFF8003BAFFE1 01A0 50D0F38002D2F38001DCF3808BDFFFE4F0C53F080DD6FFA0CFB1FF5C83017C5C 01C0 01CFFF6CDEFFBFA000CE7FFC18FEFFA000CE7FFC28FEFFA001CE7FFC80FEFFA0 01E0 00CE7FFCCFD7FFE400007C5C8C0C00000C1900005C1900001C03000000000000 0200 800200008006000008100000FCFC0000FFFFFFFF00000002000000010000FFFF 0220 03030000030100000000080C0000103000183C7E00181818003C4281003C4299 0240 00FF818100FFC3E702060E1E0000001C00000000000000001818181818181818 0260 0000000018181818000000001818181818181818181818181818181800FFFF00 0280 663399CC6666666655AA55AA0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F00000000 02A0 00000000000000000000000000183C3C006666770036367F18187C6600000046 02C0 000E1B1B0018181C0030180C00060C1800000066000000180000000000000000 02E0 0000000000004060003E63730010181E003C6666003C66600030383C007E0606 0300 00380C06007F6363003C6666003C66660000001C000000000060301800000000 0320 00060C18003C6660003E6763003C6666003F6666003C6663001F3666007F4606 0340 007F4606003C666300636363003C18180078303000676636000F06060063777F 0360 00636367001C3663003F6666001C3663003F6666003C6666007E5A1800666666 0380 00666666006363630066666600666666007F6331003C0C0C00000103003C3030 03A0 00081C36000000000000000C0000000000070606000000000038303000000000 03C0 00386C0C0000000000070606001818000060600000070606001E181800000000 03E0 0000000000000000000000000000000000000000000000000000080C00000000 0400 00000000000000000000000000000000000000000070181800181818000E1818 0420 00CEDB73000018187E7E0C087E7E3010181818181818187E81818181BDBDBD99 0440 81818181BD99BDE73E7E3E1E3E3E3E1C00C0F03000030F0C30F0C0000C0F0300 0460 00FFFF001818181800FFFF1818FFFF0018F8F818181F1F1818FFFF1800FFFF00 0480 663399CC6666666655AA55AA0F0FFFFF0F0FF0F00F0F0F0F0F0F00000000FFFF 04A0 0000F0F000000F0F000000003C181800330000003636367F063C60666630180C 04C0 0E5B7B330C0000000606060C303030183CFF3C66187E181800000000007E0000 04E0 0000000030180C067B6B6F67181818186030180C6038606036337F30063E6060 0500 063E66666030180C6E3C7666667C60601C00001C1C1C00000C060C187E007E00 0520 30603018301818007B7B3B03667E6666663E66660303036366666666263E2606 0540 263E260603037363637F63631818181830303333361E3636060646667F6B6363 0560 6F7F7B7363636363663E06066363637B663E3666061C30661818181866666666 0580 66666666636B6B363C183C66663C1818180C06430C0C0C0C060C183030303030 05A0 63000000000000001C3830001E303E333E6666663C6606063E3333333C667E06 05C0 0C3E0C0C6E333333366E66661C1818187060606066361E36181818183F6B6B6B 05E0 3E6666663C6666663B6666666E33333337766E063C660C307E0C0C0C33333333 0600 6666666663636B6B63361C1C666666667E62300C0C060C181818181830603018 0620 000000007E1818000000000000000000181800003C180000423C0000423C0000 0640 81FF0000C3FF00000E0602000000000018181818181818180000000000000000 } PUB stop | i '' Stop VGA driver - frees two COGs ' repeat i from 0 to 1 ' if cog[i] ' cogstop(cog[i]~ - 1) CON #1, scanbuff[128], scancode[128*2-1+3], maincode 'enumerate COG RAM usage main_size = $1F0 - maincode 'size of main program hv_inactive = (hn << 1 + vn) * $0101 'H,V inactive states DAT font long long $0C080000,$30100000,$7E3C1800,$18181800,$81423C00,$99423C00,$8181FF00,$E7C3FF00 'top ascii 0-7 long $1E0E0602,$1C000000,$00000000,$00000000,$18181818,$18181818,$00000000,$18181818 long $00000000,$18181818,$18181818,$18181818,$18181818,$00FFFF00,$CC993366,$66666666 long $AA55AA55,$0F0F0F0F,$0F0F0F0F,$0F0F0F0F,$0F0F0F0F,$00000000,$00000000,$00000000 ' ascii 24 to 31 long $00000000,$3C3C1800,$66666600,$7F363600,$667C1818,$46000000,$1B1B0E00,$1C181800 ' 77666600 to 66666600 for the " character (ascii 32 long $0C183000,$180C0600,$66000000,$18000000,$00000000,$00000000,$00000000,$60400000 long $73633E00,$1E181000,$66663C00,$60663C00,$3C383000,$06067E00,$060C3800,$63637F00 long $66663C00,$66663C00,$1C000000,$00000000,$18306000,$00000000,$180C0600,$60663C00 long $63673E00,$66663C00,$66663F00,$63663C00,$66361F00,$06467F00,$06467F00,$63663C00 long $63636300,$18183C00,$30307800,$36666700,$06060F00,$7F776300,$67636300,$63361C00 long $66663F00,$63361C00,$66663F00,$66663C00,$185A7E00,$66666600,$66666600,$63636300 long $66666600,$66666600,$31637F00,$0C0C3C00,$03010000,$30303C00,$361C0800,$00000000 long $0C000000,$00000000,$06060700,$00000000,$30303800,$00000000,$0C6C3800,$00000000 long $06060700,$00181800,$00606000,$06060700,$18181E00,$00000000,$00000000,$00000000 long $00000000,$00000000,$00000000,$00000000,$0C080000,$00000000,$00000000,$00000000 long $00000000,$00000000,$00000000,$18187000,$18181800,$18180E00,$73DBCE00,$18180000 long $080C7E7E,$10307E7E,$18181818,$7E181818,$81818181,$99BDBDBD,$81818181,$E7BD99BD 'middle long $1E3E7E3E,$1C3E3E3E,$30F0C000,$0C0F0300,$00C0F030,$00030F0C,$00FFFF00,$18181818 long $18FFFF00,$00FFFF18,$18F8F818,$181F1F18,$18FFFF18,$00FFFF00,$CC993366,$66666666 long $AA55AA55,$FFFF0F0F,$F0F00F0F,$0F0F0F0F,$00000F0F,$FFFF0000,$F0F00000,$0F0F0000 ' 00000033 to 00000066 for the " character long $00000000,$0018183C,$00000066,$7F363636,$66603C06,$0C183066,$337B5B0E,$0000000C long $0C060606,$18303030,$663CFF3C,$18187E18,$00000000,$00007E00,$00000000,$060C1830 long $676F6B7B,$18181818,$0C183060,$60603860,$307F3336,$60603E06,$66663E06,$0C183060 long $66763C6E,$60607C66,$1C00001C,$00001C1C,$180C060C,$007E007E,$18306030,$00181830 long $033B7B7B,$66667E66,$66663E66,$63030303,$66666666,$06263E26,$06263E26,$63730303 long $63637F63,$18181818,$33333030,$36361E36,$66460606,$63636B7F,$737B7F6F,$63636363 long $06063E66,$7B636363,$66363E66,$66301C06,$18181818,$66666666,$66666666,$366B6B63 long $663C183C,$18183C66,$43060C18,$0C0C0C0C,$30180C06,$30303030,$00000063,$00000000 long $0030381C,$333E301E,$6666663E,$0606663C,$3333333E,$067E663C,$0C0C3E0C,$3333336E long $66666E36,$1818181C,$60606070,$361E3666,$18181818,$6B6B6B3F,$6666663E,$6666663C long $6666663B,$3333336E,$066E7637,$300C663C,$0C0C0C7E,$33333333,$66666666,$6B6B6363 long $1C1C3663,$66666666,$0C30627E,$180C060C,$18181818,$18306030,$00000000,$0018187E long $00000000,$00000000,$00001818,$0000183C,$00003C42,$00003C42,$0000FF81,$0000FFC3 'bottom long $0002060E,$00000000,$18181818,$18181818,$00000000,$00000000,$00000000,$18181818 long $18181818,$00000000,$18181818,$18181818,$18181818,$00FFFF00,$CC993366,$66666666 long $AA55AA55,$FFFFFFFF,$F0F0F0F0,$0F0F0F0F,$00000000,$FFFFFFFF,$F0F0F0F0,$0F0F0F0F long $00000000,$00001818,$00000000,$00003636,$0018183E,$00006266,$00006E3B,$00000000 long $00003018,$0000060C,$00000000,$00000000,$0C181C1C,$00000000,$00001C1C,$00000103 long $00003E63,$00007E18,$00007E66,$00003C66,$00007830,$00003C66,$00003C66,$00000C0C long $00003C66,$00001C30,$0000001C,$0C181C1C,$00006030,$00000000,$0000060C,$00001818 long $00003E07,$00006666,$00003F66,$00003C66,$00001F36,$00007F46,$00000F06,$00007C66 long $00006363,$00003C18,$00001E33,$00006766,$00007F66,$00006363,$00006363,$00001C36 long $00000F06,$00603C36,$00006766,$00003C66,$00003C18,$00003C66,$0000183C,$00003636 long $00006666,$00003C18,$00007F63,$00003C0C,$00004060,$00003C30,$00000000,$FFFF0000 long $00000000,$00006E33,$00003B66,$00003C66,$00006E33,$00003C66,$00001E0C,$1E33303E long $00006766,$00007E18,$3C666660,$00006766,$00007E18,$00006B6B,$00006666,$00003C66 long $0F063E66,$78303E33,$00000F06,$00003C66,$0000386C,$00006E33,$0000183C,$00003636 long $00006336,$1C30607C,$00007E46,$00007018,$00001818,$00000E18,$00000000,$0000007E {{ ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ 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. │ └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ }}
Addit: fixed a few lines with the font implants.
'implant pin settings reg_vcfg := $200000FF + (BasePin & %111000) << 6 ' need to move reg_vcfg to the hub memory location of cogarray plus $8C longmove(cogarray+$8C,@reg_vcfg,1) i := $FF << (BasePin & %011000) j := BasePin & %100000 == 0 reg_dira := i & j ' need to move reg_dira to the hub memory location of cogarray plus $84 longmove(cogarray+$84,@reg_dira,1) reg_dirb := i & !j ' need to move reg_dirb to the hub memory location of cogarray plus $88 longmove(cogarray+$88,@reg_dirb,1) 'implant CNT value to sync COGs to sync_cnt := cnt + $10000 ' need to move reg_dira to the hub memory location of cogarray plus $90 longmove(cogarray+$90,@sync_cnt,1) ' screen_base is at $01F4 using F9 so subtract $8 gives $1EC ' screenptr is passed to this startup routine (don't confuse with screen_ptr) 'implant pointers 'longmove(@screen_base, @ScreenPtr, 3) longmove(cogarray + $1EC,@ScreenPtr,3) ' replaces line above, screen_base, color_base, cursor_base 'font_base := @font longmove(cogarray + $1F8,@font,1) ' replaces line above. Location = $200-8 = $1F8 'implant unique settings and launch first COG 'vf_lines.byte := vf i := vf bytemove(cogarray + $1B4, @i,1) ' replaces line above, location $1BC - 8 = 1B4, LSB at beginning 'vb_lines.byte := vb i := vb bytemove(cogarray + $9C, @i,1) ' replaces line above $A4-8 = $9C, LSB first 'font_third := 1 i :=1 longmove(cogarray + $1FC,@i,1) ' replaces line above, $204-8=$1FC, put in value of 1 'cog[1] := cognew(@d0, SyncPtr) + 1 cog[1] := cognew(cogarray, SyncPtr) + 1 ' replaces line above 'allow time for first COG to launch waitcnt($2000 + cnt) 'differentiate settings and launch second COG 'vf_lines.byte := vf+4 i := vf+4 bytemove(cogarray + $1B4, @i,1) ' replaces line above, location $1BC - 8 = 1B4, LSB at beginning 'vb_lines.byte := vb-4 i := vb-4 bytemove(cogarray + $9C, @i,1) ' replaces line above $A4-8 = $9C, LSB first 'font_third := 0 i := 0 longmove(cogarray + $1FC,@i,1) ' replaces line above, $204-8=$1FC, put in value of 0 'cog[0] := cognew(@d0, SyncPtr) + 1 cog[0] := cognew(cogarray, SyncPtr) + 1 ' replaces line above 'if both COGs launched, return true if cog[0] and cog[1] return true 'else, stop any launched COG and return false else stop
Now the screen is the correct color, it is steady but the font data appears to be corrupt
Very close now!
How are you managing to isolate each spin object? I need to check out that code and see how it works.
Meanwhile, I have finally cracked the vga code.
This program now loads up Kye's SD driver, which happens to have cog code that I think takes 494 longs. I need to check if it can be padded to 496. It then recycles this cog space to load the keyboad driver, serial driver and the two cogs driving the vga. So already this is saving 8k of hub ram compared with the standard approach.
See attached.