AdvSys2 Development - RIP

I've decided to move the discussion of AdvSys2 for the WordFire platform to a new thread to avoid cluttering up Jim's thread with my implementation issues. I'm still having trouble getting text to display on all four screens. I've verified that I haven't changed anything in vga.driver.spin and I've only added functions to vga.spin to support my scrolling text based game. I would attach my code but I'm not sure I'm allowed to given the licensing of the code for WordFire but I'll include a small piece since it is pretty much the same code that Jim already posted in the other thread. Here is what I'm doing to try to display text on all four screens:
'configure video pins
lock := ((cnt >> 16 + 2) | 1) << 16
repeat s from 0 to 3
vga[s].init(lock|vconfig[s]) 'initialize vid drv with vgrp/vpins
waitf(4) 'let voltage to screens stablize?
' write something on each screen
repeat s from 0 to 3
write(s, 10, 3, WB, string("Hello, world!"))
The text appears fine on screen 0 but it is shifted on screens 1-3. Also, I don't understand the purpose of the reference to cnt.
Comments
Okay, I took a look, and for that repeat loop for locking the screens together in sync, you don't want that waitf(4) line in that loop. It almost for sure is preventing kuroneko's driver from establishing sync lock of the instances properly. You only want the vga[ s ].init() line in that loop, nothing more. That is, it should be a tight/fast loop, so don't consolidate those two repeat loops from my example just because it appears that they could work as one loop (and be more compact). Make them back-to-back. Although I sometimes use separate repeat loops just to make the code clearer to read (even though it's less compact/efficient), in this case, the loops must be separate, as the first one has to be fast.
Meanwhile, in the second repeat loop that I've suggested for the waitf() line, I'd probably put the following two lines before it. Again, the second repeat loop gets the waitf(4) line, if it's even necessary (I think I put it in just to be safe, and it only delays things by a second in total).
repeat s from 0 to 3 vga[s].str(string($1B, "s")) 'page mode vga[s].setn(1, constant(NEGX|$8000)) 'use the ROM font for chars 0..31 waitf(4) 'let voltage to screens stablize?
I'm assuming that you don't want to redefine any font characters at this time.All of the code is checked into GitHub except the video and keyboard drivers which are not open source but you get the source if you purchase the WordFire console.
Game code:
var initialLocation = livingroom; include "game.adi"; actor northActor { name: "North"; index: 0; loc: livingroom; } actor westActor { name: "West"; index: 1; loc: closet; } actor southActor { name: "South"; index: 2; loc: pantry; } actor eastActor { name: "East"; index: 3; loc: kitchen; } location storage_room { description: "You are in the storage room."; west: hallway; } location hallway { description: "You are in the hallway."; east: storage_room; north: kitchen; south: livingroom; } location kitchen { description: "You are in the kitchen."; south: hallway; west: pantry; } location pantry { description: "You are in the pantry."; east: kitchen; } location livingroom { description: "You are in the livingroom."; north: hallway; west: closet; south: outside; } location closet { description: "You are in the closet."; east: livingroom; } location outside { description: "You are outside."; north: livingroom; }
Game runtime code:
object location { } object actor { } property north, south, east, west; property loc, description; def getp(obj, prop) { var value; try { value = obj.(prop); } catch (e) { value = 0; } return value; } def getc() { asm { TRAP 0 RETURN } } def screen(n) { asm { LADDR 0 LOAD TRAP 7 } } var actors[] = { northActor, westActor, southActor, eastActor }; def main() { var curloc, newloc, ch, s; for (s = 0; s < 4; ++s) { screen(s); print #actors[s].loc.description; } while (1) { for (s = 0; s < 4; ++s) { screen(s); curloc = actors[s].loc; if ((ch = getc()) != 0 && ch != '\n') { if (ch == 'n') newloc = getp(curloc, north); else if (ch == 's') newloc = getp(curloc, south); else if (ch == 'e') newloc = getp(curloc, east); else if (ch == 'w') newloc = getp(curloc, west); else if (ch == 'l') { print #curloc.description; newloc = curloc; } else newloc = -1; if (newloc == -1) print "Huh?"; else if (newloc == 0) print "You can't go that way."; else if (newloc != curloc) { actors[s].loc = newloc; print #newloc.description; } } } } }
This is about as far as I can go until I resolve a major omission in my new adventure writing system. The two main components of an adventure game are the game map and the command parser. I've implemented the game map but I only allow single character commands. To go any further I have to write a parser. The parser for my old system was written in C and I had to remove it when I implemented the interpreter in PASM on the Propeller. My plan is to write a new parser in the adventure language itself. That's my next project and it will likely take a while to complete.
def main() { while (1) { pinOn(26); pinOff(27); waitcnt(40000000); pinOff(26); pinOn(27); waitcnt(40000000); } }
However, pinOn, pinOff, and waitcnt are not native to AdvSys2. They are defined as follows. The "asm" statement probably requires a bit of explanation. What appears in the "asm" statement are AdvSys2 byte code opcodes. The "LADDR 0" instruction loads the address of the first local variable onto the stack. The first local variable happens to be the first function parameter, in this case, "n". The "LOAD" instruction just loads a long from the address on the top of the stack. Then the "NATIVE" instructions execute native Propeller instructions. This is how AdvSys2 code gets at the Propeller hardware. The "RETURN" instruction simply returns from the function.
def waitcnt(n) { asm { LADDR 0 LOAD NATIVE mov t1, cnt NATIVE add t1, tos NATIVE waitcnt t1, #0 RETURN } } def pinOn(pin) { asm { LADDR 0 LOAD NATIVE mov t1, #1 NATIVE shl t1, tos NATIVE or dira, t1 NATIVE or outa, t1 RETURN } } def pinOff(pin) { asm { LADDR 0 LOAD NATIVE mov t1, #1 NATIVE shl t1, tos NATIVE or dira, t1 NATIVE andn outa, t1 RETURN } }
I don't pretend that AdvSys2 will become a popular programming language for the Propeller but it is another entry in the long list of languages you have to choose from.
Here is some sample code:
var myArray[] = { 1, 2, 3, 4, 5 }; var myArray2[] = { [1, 2], [3, 4, 5], [6] }; def main() { var i, j, k; println myArray2[0][-1]; for (i = 0; i < myArray[-1]; ++i) println myArray[i]; for (j = 0; j < myArray2[-1]; ++j) { println "size=", myArray[j][-1]; for (i = 0; i < myArray2[j][-1]; ++i) print myArray2[j][i], " "; println; } }
And here is the output that it generates when you run it:
2 1 2 3 4 5 size=2 1 2 size=3 3 4 5 size=1 6
It's not very exciting but it proves that nested arrays work. The compiler puts the size of the array at offset -1. That is the reason for the references to myArray[-1].The binary file format is really simple (as I'm sure you know). I guess your problem is that you need to include your interpreter code (written in Spin/PASM) with the bytecode binary? For my Risc-V interpreter I solved this by pre-compiling the interpreter and padding it out to a fixed boundary (say 4K, I can't remember now what it was exactly). The interpreter always assumed the code started after the boundary. Then producing the binary was just a matter of concatenating the interpreter binary and bytecode binary, then fixing up the checksum.
var myArray[10]; def main() { myArray[3] = 1; }
The compiler assumes myArray is a data address and it adds 3*4 to it to get the address of the target 32 bit value. In order to do byte addressing instead of long addressing I guess I need some kind of type casting. I could use the Spin approach and do something like this:byte[myArray][3]
However, that looks like double indexing which I already support for accessing nested arrays so there would be ambiguity. I'm thinking of something like this:myArray.byte[3]
Does that seem like a good syntax for this? Any other suggestions?but it would restrict youi byte-arrays to start at a long address and be 4 byte boundary long.
wasting space for each string used.
having every var being 32 bit might not be useful on a MC, so maybe add types for byte and word?
Mike
myArray.byte[321] or myArray.word[12]
could work with any Array using the start address of the array, but getting to the index number needed one has to skip your size field on nested Arrays, seems complicated.
myArray[2][5].byte[0..3]
would allow access to each byte per index but just for one long. How about
myArray[2].byte[0..(Size of nestedArray *4)-1]
that would take the size of the one dimensional array stored at index-1 as bound check.
But then byteArrays aka strings start at a long address and are long so wasting up to 3 bytes.
a optimizing compiler could use those spare bytes for something
just some thoughts
Mike
var myArray[] = { [1, 2], [3, 4, 5], [6] }; myArray[2].byte[0] ' 1. byte of 6 myArray[2].byte[1] ' 2. byte of 6 myArray[2].byte[2] ' 3. byte of 6 myArray[2].byte[3] ' 4. byte of 6 BUT myArray[1].byte[0] ' 1. byte of 3 myArray[1].byte[1] ' 2. byte of 3 myArray[1].byte[2] ' 3. byte of 3 myArray[1].byte[3] ' 4. byte of 3 myArray[1].byte[4] ' 1. byte of 4 myArray[1].byte[5] ' 2. byte of 4 myArray[1].byte[6] ' 3. byte of 4 myArray[1].byte[7] ' 4. byte of 4 myArray[1].byte[8] ' 1. byte of 5 myArray[1].byte[9] ' 2. byte of 5 myArray[1].byte[10] ' 3. byte of 5 myArray[1].byte[11] ' 4. byte of 5
is possible and useful
Mike
var long myLongArray[10]; byte myByteArray[20];
Maybe I could also accept this and default the type to long:var myLongArray[10]; byte myByteArray[20];