Oh, boy! I just looked at TvText.bas. You know I thought this whole procedure was going to be as simple as doing the conversion and then you would have access to the commands that were in the spin file, just like in Spin you would call an object file and use all the commands within that program. So, basically you have to do the defs for all the commands that are in the spin file. I don't get it, how is this a selling point for using spin files with xBasic? It seems like you are better off, and not duplicating efforts, if you just take the PASM part of the spin program, and just use PASM.exe to come up with the byte code, am I missing something here? I guess with inline assembly you could almost cut/paste asm below the dat and insert in xBasic, and there you would have the base code. Maybe some effort should be put into inline asm, and not this very cumbersome ordeal of trying to convert an existing spin file.
If I understand correctly when you extract the PASM from a Spin object using open Spin you are getting the binary blob that results from assembling the PASM part. All the Spin stuff is thrown away as this is not doing a Spin xbasic translation. It would be a lot of work for someone to create such a translator. There is one for Spin to C though.
So you have the blob and you can start it in your basic program, but then you have to provide all those access functions and logic that was in Spin before.
This is a recurring theme with people creating or using odd languages on the Prop. and wanting to reuse PASM code.
Oh, boy! I just looked at TvText.bas. You know I thought this whole procedure was going to be as simple as doing the conversion and then you would have access to the commands that were in the spin file, just like in Spin you would call an object file and use all the commands within that program. So, basically you have to do the defs for all the commands that are in the spin file. I don't get it, how is this a selling point for using spin files with xBasic? It seems like you are better off, and not duplicating efforts, if you just take the PASM part of the spin program, and just use PASM.exe to come up with the byte code, am I missing something here? I guess with inline assembly you could almost cut/paste asm below the dat and insert in xBasic, and there you would have the base code. Maybe some effort should be put into inline asm, and not this very cumbersome ordeal of trying to convert an existing spin file.
Ray
I'm afraid people are still misunderstanding the ASM and NATIVE statements in xbasic. There is no way that you could cut the PASM out of a Spin object and just convert it to NATIVE instructions and have it work. I only added the NATIVE bytecode to xbasic so that I could include a few PASM instructions in otherwise xbasic code. This was for PASM instructions like waitcnt, coginit, etc that are impossible to implement in xbasic. Coding anything else using NATIVE will not result in faster code since every NATIVE instruction is also a bytecode. The way to run PASM code fast is to bundle it into a blob that gets loaded into a COG. This is exactly what happens all the time in Spin objects except that the PASM blobs are inline in the Spin source. There is no inline assembly in Spin (although there probably will be in Spin2!). Even if I extend NATIVE to allow more than one instruction to be coded at a time and if I merge in the simple pasm.exe assembler, it still won't be good for more than a handful of PASM instructions at a time. My guess is that I can probably spare up to 16 COG locations for these PASM sequences which I don't believe will be enough to run any of the PASM code that is in OBEX. I'm happy that some of you have expressed an interest in xbasic and I'm willing to support it to do what it was originally intended for but it was never supposed to be a replacement for Spin or C. If you need a language with those capabilities I suggest you use one of those instead of xbasic. On the other hand, if you're interested in a version of Basic that is pretty fast and can execute code out of external memory, then xbasic may be good for you.
I guess the selling point for XBasic is the ability to use HUB, FLASH, or RAM space with the limited command set of xBasic. And the use of COGs is even more difficult, not standard issue in xBasic. Now the question is how do you expand the command set which would allow you to create something like FullDuplexSerial library? It seems like I am going in circles with this, I need to create a new mindset for myself as it pertains to xBasic, if that would help any.
I hope my experiments in NATIVE coding haven't annoyed you, David. I think I understand the limitations -- I'm just trying to learn to exploit NATIVE opcodes where I can.
As I have all my basic IO working (please have look at the attached when you can -- I may be fooling myself), I decided to port elements of my Spin template to xBasic. I'm able to get freqout working, but I can't seem to pass a character as a parameter (small issue, but I'd like to understand why).
This works, expecting 0 for ctra or 1 for ctrb:
def freqout(ctrx, pin, freq, ms)
if (ctrx = 0) then
if (freq > 0) then
ctra = ((0b00100) << 26) | pin
frqa = (0x8000_0000 / (clkfreq / freq)) << 1
else
ctra = 0
end if
low(pin)
if (ms > 0) then
pause(ms)
ctra = 0
end if
else if (ctrx = 1) then
if (freq > 0) then
ctrb = ((0b00100) << 26) | pin
frqb = (0x8000_0000 / (clkfreq / freq)) << 1
else
ctrb = 0
end if
low(pin)
if (ms > 0) then
pause(ms)
ctrb = 0
end if
end if
end def
I tested the free-run and timed modes of the function with this snippet running on the PAB:
And it works! The 0 and 1 versus "A" and "B" isn't a big bother; I just try to keep my code friendly and want to better understand passing parameters in xbasic.
I hope my experiments in NATIVE coding haven't annoyed you, David. I think I understand the limitations -- I'm just trying to learn to exploit NATIVE opcodes where I can.
No, they didn't annoy me. I'm happy to see people using xbasic. I just want to set reasonable expectations. Using NATIVE is fine when you need to access some underlying Propeller functionality but it isn't a way to make your code run faster at least in its current form. Thanks for taking the time to try xbasic!
Whoops... rookie error on my part. Thanks, Steve, that fixed it.
def freqout(ctrx, pin, freq, ms)
select ctrx
case 1, 'A', 'a'
if (freq > 0) then
ctra = ((0b00100) << 26) | pin
frqa = (0x8000_0000 / (clkfreq / freq)) << 1
else
ctra = 0
end if
low(pin)
if (ms > 0) then
pause(ms)
ctra = 0
end if
case 2, 'B', 'b'
if (freq > 0) then
ctrb = ((0b00100) << 26) | pin
frqb = (0x8000_0000 / (clkfreq / freq)) << 1
else
ctrb = 0
end if
low(pin)
if (ms > 0) then
pause(ms)
ctrb = 0
end if
end select
end def
On another topic... any chance of getting line numbers in the edit panel and line:column in the status line? I think that will help locating errors flagged by the compiler.
Oh, boy! I just looked at TvText.bas. You know I thought this whole procedure was going to be as simple as doing the conversion and then you would have access to the commands that were in the spin file, just like in Spin you would call an object file and use all the commands within that program. So, basically you have to do the defs for all the commands that are in the spin file. I don't get it, how is this a selling point for using spin files with xBasic? It seems like you are better off, and not duplicating efforts, if you just take the PASM part of the spin program, and just use PASM.exe to come up with the byte code, am I missing something here? I guess with inline assembly you could almost cut/paste asm below the dat and insert in xBasic, and there you would have the base code. Maybe some effort should be put into inline asm, and not this very cumbersome ordeal of trying to convert an existing spin file.
Ray
Well, let's take a real example and work through it.
First point - most of the time when someone has written pasm in spin, it is for code that ends up running in a cog. Running in some sort of emulation, eg LMM or NATIVE will not work, because the timing will be wrong, and it probably won't run fast enough.
So for converting an object, the pasm has to stay the same.
I'm going to use the TV Text object, because the code is fairly simple. This is one of the original objects created by Chip back in 2008 http://obex.parallax.com/object/618
There are three Spin files. Let's ignore the Demo file for the moment and get into the core of the program - TV.spin
CON
fntsc = 3_579_545 'NTSC color frequency
lntsc = 3640 'NTSC color cycles per line * 16
sntsc = 624 'NTSC color cycles per sync * 16
fpal = 4_433_618 'PAL color frequency
lpal = 4540 'PAL color cycles per line * 16
spal = 848 'PAL color cycles per sync * 16
paramcount = 14
colortable = $180 'start of colortable inside cog
VAR
long cog
PUB start(tvptr) : okay
'' Start TV driver - starts a cog
'' returns false if no cog available
''
'' tvptr = pointer to TV parameters
stop
okay := cog := cognew(@entry, tvptr) + 1
PUB stop
'' Stop TV driver - frees a cog
if cog
cogstop(cog~ - 1)
DAT
'*******************************
'* Assembly language TV driver *
'*******************************
...
The first part is some constants. They should translate to xbasic easily.
Then there is some code to start a cog and to stop a cog. I think that is in xbasic.
And then there is the DAT section. This is the part that needs to be separated out and compiled to a binary array.
At this point, we need to note that the PAR value sent to the cog has the variable name tvptr. But there are two parts to this spin program, and what that really points to is an array in the file tv_text, down the bottom, called tv_params.
So this is a bit complicated, because we need to follow through that value to what it really points to. It helps to have both tv.spin and tv_params.spin open at the same time in the propeller IDE.
Now it gets a bit complicated. xbasic does not have objects (though I think we can create them very easily, just by having a compiler add the object name to the beginning of all variables). So we will need to do this manually, and first merge all the spin files into one big file. That can be as simple as just copying and pasting the text together, but then you need to go through and check there are no variable names the same in each file. tv.spin only has one variable called "cog", so the process is to go through the tv_text.spin and check there are no variables also called "cog". A text search makes this easier. So the VAR sections of each spin file can be merged.
Now we have another problem - both spin files have PUBs called "start" and "stop". So we need unique names for those. So lets see how "object oriented xbasic" could work in practice. For the PUB start in tv.spin, we rename that as "tv_start" and for the PUB start in tv_text.spin, we rename that "tv_text_start". This means these PUBs have unique names in the merged text file. We would also need to rename the calling routines in the "tv_text_demo.spin" program as well. One thing that can be seen is that authors of objects have already been using underscores in names, so maybe we could look at another naming convention to show where the object part of the file is. I think C++ uses a double colon. My personal preference would be a period, but that would be up to the authors of xbasic. So we could have something like "tv.start" and "tv_text.start" And for a really cool IDE, if you added an include for tv_text.bas at the beginning of the program, the IDE would search through this file, create a list of all the subroutines, and when you type "tv_text." it would bring up a dropdown menu of all the subroutines available in that object. But I digress...
Ok, so now we have merged everything into one object file. Now it is a matter of translating each line one at a time into xbasic.
I guess this is where we might find a need for new keywords and instructions. How would this code be translated to xbasic for instance? Is there an equivalent for lookupz? Do we need to expand out everything in brackets and put them on separate lines, and possibly create a few extra variables to do this?
PUB hex(value, digits)
'' Print a hexadecimal number
value <<= (8 - digits) << 2
repeat digits
out(lookupz((value <-= 4) & $F : "0".."9", "A".."F"))
This is the one object that has already been translated so, this is what it looks like in xbasic
REM===================================================
REM Print a hexidecimal number to current text position
REM @param value - decimal number
REM @param digits - number of digits to print
REM
def TvText_hex(value, digits)
dim n = 0
dim mask = 0xf // faster than using constants
dim one = 1 // faster than using constants
do while digits > 0
digits = digits - one
n = (value >> (digits<<2)) & mask
TvText_putchar(TvText_hexarray(n))
loop
end def
On another topic... any chance of getting line numbers in the edit panel and line:column in the status line? I think that will help locating errors flagged by the compiler.
Yes. This was one of my initial UGH reactions having not messed with the IDE in a while. I know what needs to be done, it's just a matter of having half a day to do it.
It's award season in Hollywood (and I've only watched a couple screeners...) -- we like to say, "For your consideration..."
On that note, this is a possible implementation of pulsout(). Just like the BASIC Stamp, it blocks until finished.
def pulsout(ctrx, pin, us)
select ctrx
case 1, 'A', 'a'
low(pin)
ctra = (0b00100 << 26) | pin
frqa = 1
phsa = -us * (clkfreq / 1_000_000)
do while (phsa < 0)
loop
ctra = 0
case 2, 'B', 'b'
low(pin)
ctrb = (0b00100 << 26) | pin
frqb = 1
phsb = -us * (clkfreq / 1_000_000)
do while (phsb < 0)
loop
ctrb = 0
end select
end def
Yes. This was one of my initial UGH reactions having not messed with the IDE in a while. I know what needs to be done, it's just a matter of having half a day to do it.
I've blown way past my alloted play time with xbasic today -- but I'm thinking about including a blurb in my March column so I'd like to have a few things sussed out.
I can do this in Spin, and it works as expected (using PAB):
I've blown way past my alloted play time with xbasic today -- but I'm thinking about including a blurb in my March column so I'd like to have a few things sussed out.
I can do this in Spin, and it works as expected (using PAB):
The LED on P26 flashes (via the counter) and the LED on 27 tracks it via the code loop.
If I translate that to xbasic like this:
dim mask = 1 << 26
freqout('A', 26, 1, 0)
do
waitpeq(mask, mask)
high(27)
waitpne(mask, mask)
low(27)
loop
...P27 never lights. Am I missing something with waitpeq and waitpne?
I'm wondering if maybe I hand-assembled them wrong. I seem to remember some problem with one of those when I moved it over to ebasic3. I'll look into it tonight.
I've blown way past my alloted play time with xbasic today -- but I'm thinking about including a blurb in my March column so I'd like to have a few things sussed out.
I can do this in Spin, and it works as expected (using PAB):
The LED on P26 flashes (via the counter) and the LED on 27 tracks it via the code loop.
If I translate that to xbasic like this:
dim mask = 1 << 26
freqout('A', 26, 1, 0)
do
waitpeq(mask, mask)
high(27)
waitpne(mask, mask)
low(27)
loop
...P27 never lights. Am I missing something with waitpeq and waitpne?
Didn't you determine a few days ago that t1 was not safe to use? It looks like the code in propeller.bas uses t1 a lot. I wonder if changing it to use t4 might make waitpeq and waitpne start working? If so I may have to do something to guarantee that t1-t4 are actually available to NATIVE instructions.
I'm afraid people are still misunderstanding the ASM and NATIVE statements in xbasic. There is no way that you could cut the PASM out of a Spin object and just convert it to NATIVE instructions and have it work. I only added the NATIVE bytecode to xbasic so that I could include a few PASM instructions in otherwise xbasic code. This was for PASM instructions like waitcnt, coginit, etc that are impossible to implement in xbasic. Coding anything else using NATIVE will not result in faster code since every NATIVE instruction is also a bytecode. The way to run PASM code fast is to bundle it into a blob that gets loaded into a COG. This is exactly what happens all the time in Spin objects except that the PASM blobs are inline in the Spin source. There is no inline assembly in Spin (although there probably will be in Spin2!). Even if I extend NATIVE to allow more than one instruction to be coded at a time and if I merge in the simple pasm.exe assembler, it still won't be good for more than a handful of PASM instructions at a time. My guess is that I can probably spare up to 16 COG locations for these PASM sequences which I don't believe will be enough to run any of the PASM code that is in OBEX. I'm happy that some of you have expressed an interest in xbasic and I'm willing to support it to do what it was originally intended for but it was never supposed to be a replacement for Spin or C. If you need a language with those capabilities I suggest you use one of those instead of xbasic. On the other hand, if you're interested in a version of Basic that is pretty fast and can execute code out of external memory, then xbasic may be good for you.
David,
If you do go down the path of letting a cog run some inline PASM code, then I would urge for the 16 long, or possibly a couple more. I would like to experiment with xBasic, knitting it together with my multi threading realtime kernel. Among other things, it has the capability of loading short (16 long) PASM snippets. So, while I'm not yet sure of the way this may all work, having the 16 longs available would likely be of considerable help.
My intent would be to have multiple selections from a library of real time threads running simultaneous in a single cog under control of xBasic.
Didn't you determine a few days ago that t1 was not safe to use? It looks like the code in propeller.bas uses t1 a lot. I wonder if changing it to use t4 might make waitpeq and waitpne start working? If so I may have to do something to guarantee that t1-t4 are actually available to NATIVE instructions.
I still don't quite understand the mechanics of the VM interface, but I did change to t4 and added drop -- these versions [seem to] work.
def waitpeq(state, mask)
asm
lref 1 // get mask
native 0xa0bc0805 // mov t4, tos
drop
lref 0 // get state
native 0xf03c0a04 // waitpeq tos, t4
returnx
end asm
end def
def waitpne(state, mask)
asm
lref 1 // get mask
native 0xa0bc0805 // mov t4, tos
drop
lref 0 // get state
native 0xf43c0a04 // waitpne tos, t4
returnx
end asm
end def
If you do go down the path of letting a cog run some inline PASM code, then I would urge for the 16 long, or possibly a couple more.
One thing that xbasic would be able to do that spin cannot is to be able to run cogs, then discard the code. This would only be applicable when running from external memory. With spin, there is a cost to running cog code as the code ends up taking up hub memory. But with xbasic running from external memory, you can fire off a cog, pass some parameters, set a flag when the cog has finished, then overwrite that cog with new code. You could be reloading a cog hundreds of times a second with different code each time. This would work with code we have now. You would just need to keep one cog free.
I started writing an internals document for xbasic which I've attached to this message. Once you read this I hope you'll understand why DROP is required in this code:
lref 1 // get mask
native 0xa0bc0805 // mov t4, tos
drop
Basically, LREF 1 pushes a value onto the stack. The NATIVE instruction doesn't change the stack at all so to clean up the stack after the NATIVE instruction completes you need to add DROP. If you neglect to add DROP you'll end up restoring the PC incorrectly when you execute the RETURN instruction at the end of the function.
Obviously, I forgot to do that when I wrote the waitpeq function. I need to go through and check to see if there are any other instances of this type of omission. Thanks for catching it! Also, I think I'm going to add new temporaries that are used by the VM opcodes themselves so I can guarantee that t1-t4 are always available to NATIVE instructions.
I thought that I would try some IO things, the snippet below compiles, but does not work as expected. When I run it in the debug screen, I see the > char, but when I key something in, it shows up on the edit screen. In the simple form of the program, without the 'ELSE IF', when I key in 'quit' it would not jump out of the loop. For some reason the GOTO is not working as expected in this format. The 'inputStr()' , not sure what the '0' refers too, but at one point when I changed it to a '1', I was getting an IO session on the debug screen, but in this instance, that is not working at the moment.
Ray
include "propeller.bas"
include "print.bas"
include "input.bas"
include "string.bas"
dim a(40) as byte
do
print "> ";
inputStr(0,a)
if strcpy(a,"quit")then
GOTO gbye
ELSE IF strcpy(a,"help") then
help
ELSE
print "??"
END IF
loop
gbye:
print "The END"
END
def help
print "Menu - help, quit, "
end def
I thought that I would try some IO things, the snippet below compiles, but does not work as expected. When I run it in the debug screen, I see the > char, but when I key something in, it shows up on the edit screen. In the simple form of the program, without the 'ELSE IF', when I key in 'quit' it would not jump out of the loop. For some reason the GOTO is not working as expected in this format. The 'inputStr()' , not sure what the '0' refers too, but at one point when I changed it to a '1', I was getting an IO session on the debug screen, but in this instance, that is not working at the moment.
Ray
include "propeller.bas"
include "print.bas"
include "input.bas"
include "string.bas"
dim a(40) as byte
do
print "> ";
inputStr(0,a)
if strcpy(a,"quit")then
GOTO gbye
ELSE IF strcpy(a,"help") then
help
ELSE
print "??"
END IF
loop
gbye:
print "The END"
END
def help
print "Menu - help, quit, "
end def
I think you want "strcmp" to compare two strings not "strcpy".
Thanks, I could of swore I saw strcmp() and not strcpy(), wishful thinking on my part. So I guess I have to try coding a strcmp() command. I was thinking of doing a straight forward 'if str1 AND str2 = 0', but it looks like AND only deals with numerical values. I guess I have to come up with a loop that compares each element of the string to see if they are the same, if they are, then it would designated as '0' if not then '1'. Now how do I convert each string element too its numeric value for comparison?
Thanks, I could of swore I saw strcmp() and not strcpy(), wishful thinking on my part. So I guess I have to try coding a strcmp() command. I was thinking of doing a straight forward 'if str1 AND str2 = 0', but it looks like AND only deals with numerical values. I guess I have to come up with a loop that compares each element of the string to see if they are the same, if they are, then it would designated as '0' if not then '1'. Now how do I convert each string element too its numeric value for comparison?
Ray
strcmp should be a simple variant on strcpy. It's left as an exercise to the reader! :-)
The more I get into xBasic the more I am starting to realize that it is a "barebones" language, just enough to get you started. Here is another quick and dirty user IO session, gives you enough of an idea to expand on the theme. You have to be careful with the input, it only excepts numerical values, if you put in a character it treats it like a 0 value. So, there is an opportunity for some one to improve on this theme, or not.
Ray
REM ==========
REM testQS4.bas
REM ==========
include "print.bas"
include "extra.bas"
include "propeller.bas"
include "input.bas"
include "string.bas"
/*
* Using the QuickStart Board.
*/
print "Hello, World!"
high(17) // Turn on LED
waitMS(1000) // Wait one second.
low(17) // Turn off LED
help // Show menu
/* User IO loop. */
do
print "> ";
a = inputInt(0) // Get a number.
if a = 0 then
GOTO lend // If 0 break out of loop.
else if a = 1 then
help // If 1 show Menu.
else
print "??" // Number not listed.
end if
loop
lend:
print "The END"
END
/* Menu */
def help
print "Menu 0 - Quit"
print " 1 - Help"
end def
The more I get into xBasic the more I am starting to realize that it is a "barebones" language, just enough to get you started. Here is another quick and dirty user IO session, gives you enough of an idea to expand on the theme. You have to be careful with the input, it only excepts numerical values, if you put in a character it treats it like a 0 value. So, there is an opportunity for some one to improve on this theme, or not.
Ray
REM ==========
REM testQS4.bas
REM ==========
include "print.bas"
include "extra.bas"
include "propeller.bas"
include "input.bas"
include "string.bas"
/*
* Using the QuickStart Board.
*/
print "Hello, World!"
high(17) // Turn on LED
waitMS(1000) // Wait one second.
low(17) // Turn off LED
help // Show menu
/* User IO loop. */
do
print "> ";
a = inputInt(0) // Get a number.
if a = 0 then
GOTO lend // If 0 break out of loop.
else if a = 1 then
help // If 1 show Menu.
else
print "??" // Number not listed.
end if
loop
lend:
print "The END"
END
/* Menu */
def help
print "Menu 0 - Quit"
print " 1 - Help"
end def
By the way, the "inputInt" function isn't really intended to be called directly. The xbasic compiler automatically generates calls to it when you use the INPUT statement. I think you should be able to do this:
Here is a list of statements that stand by themselves:
INCLUDE
REM
DEF3
DIM
IF4
LET
GOTO
PRINT
STOP
END
I usually go to the include folder and use what ever defs are in there, I did not see 'input' in the docs or the defs, as a stand alone statement. Is there an updated list of stand alone statements, and other things that are not in the docs?
I usually go to the include folder and use what ever defs are in there, I did not see 'input' in the docs or the defs, as a stand alone statement. Is there an updated list of stand alone statements, and other things that are not in the docs?
Ray
I'm sorry to say that my friend Kenn Goutal who wrote the xbasic manual died a few years ago. I guess I need to update it to include newer features.
I'm sorry to say that my friend Kenn Goutal who wrote the xbasic manual died a few years ago. I guess I need to update it to include newer features.
Its great to hear that you are going to add the newer features to a great program that you and Steve are willing to continue to support.
I also thank Jon for posting a link to the XBasic site in the EFX-TEK support forums where I learned about this XBasic program to the Propeller chip, which is the brains for the EFX-TEK's HC-8 and would be fun hack (program) with XBasic since it has shift registers for the 8 TTL inputs.
I will continue to follow this thread to keep up to date of what is going on with XBasic.
Comments
Program bin2xbasic.exe doesn't magically give you spin functions. You have to make your own versions. That's what TvText.bas does..
Ray
If I understand correctly when you extract the PASM from a Spin object using open Spin you are getting the binary blob that results from assembling the PASM part. All the Spin stuff is thrown away as this is not doing a Spin xbasic translation. It would be a lot of work for someone to create such a translator. There is one for Spin to C though.
So you have the blob and you can start it in your basic program, but then you have to provide all those access functions and logic that was in Spin before.
This is a recurring theme with people creating or using odd languages on the Prop. and wanting to reuse PASM code.
Ray
As I have all my basic IO working (please have look at the attached when you can -- I may be fooling myself), I decided to port elements of my Spin template to xBasic. I'm able to get freqout working, but I can't seem to pass a character as a parameter (small issue, but I'd like to understand why).
This works, expecting 0 for ctra or 1 for ctrb:
I tested the free-run and timed modes of the function with this snippet running on the PAB:
And it works! The 0 and 1 versus "A" and "B" isn't a big bother; I just try to keep my code friendly and want to better understand passing parameters in xbasic.
Did you try 'A' and 'B' instead of "A" and "B" ?
Whoops... rookie error on my part. Thanks, Steve, that fixed it.
On another topic... any chance of getting line numbers in the edit panel and line:column in the status line? I think that will help locating errors flagged by the compiler.
Well, let's take a real example and work through it.
First point - most of the time when someone has written pasm in spin, it is for code that ends up running in a cog. Running in some sort of emulation, eg LMM or NATIVE will not work, because the timing will be wrong, and it probably won't run fast enough.
So for converting an object, the pasm has to stay the same.
I'm going to use the TV Text object, because the code is fairly simple. This is one of the original objects created by Chip back in 2008 http://obex.parallax.com/object/618
There are three Spin files. Let's ignore the Demo file for the moment and get into the core of the program - TV.spin
The first part is some constants. They should translate to xbasic easily.
Then there is some code to start a cog and to stop a cog. I think that is in xbasic.
And then there is the DAT section. This is the part that needs to be separated out and compiled to a binary array.
At this point, we need to note that the PAR value sent to the cog has the variable name tvptr. But there are two parts to this spin program, and what that really points to is an array in the file tv_text, down the bottom, called tv_params.
So this is a bit complicated, because we need to follow through that value to what it really points to. It helps to have both tv.spin and tv_params.spin open at the same time in the propeller IDE.
Now it gets a bit complicated. xbasic does not have objects (though I think we can create them very easily, just by having a compiler add the object name to the beginning of all variables). So we will need to do this manually, and first merge all the spin files into one big file. That can be as simple as just copying and pasting the text together, but then you need to go through and check there are no variable names the same in each file. tv.spin only has one variable called "cog", so the process is to go through the tv_text.spin and check there are no variables also called "cog". A text search makes this easier. So the VAR sections of each spin file can be merged.
Now we have another problem - both spin files have PUBs called "start" and "stop". So we need unique names for those. So lets see how "object oriented xbasic" could work in practice. For the PUB start in tv.spin, we rename that as "tv_start" and for the PUB start in tv_text.spin, we rename that "tv_text_start". This means these PUBs have unique names in the merged text file. We would also need to rename the calling routines in the "tv_text_demo.spin" program as well. One thing that can be seen is that authors of objects have already been using underscores in names, so maybe we could look at another naming convention to show where the object part of the file is. I think C++ uses a double colon. My personal preference would be a period, but that would be up to the authors of xbasic. So we could have something like "tv.start" and "tv_text.start" And for a really cool IDE, if you added an include for tv_text.bas at the beginning of the program, the IDE would search through this file, create a list of all the subroutines, and when you type "tv_text." it would bring up a dropdown menu of all the subroutines available in that object. But I digress...
Ok, so now we have merged everything into one object file. Now it is a matter of translating each line one at a time into xbasic.
I guess this is where we might find a need for new keywords and instructions. How would this code be translated to xbasic for instance? Is there an equivalent for lookupz? Do we need to expand out everything in brackets and put them on separate lines, and possibly create a few extra variables to do this?
This is the one object that has already been translated so, this is what it looks like in xbasic
Great.
Yes. This was one of my initial UGH reactions having not messed with the IDE in a while. I know what needs to be done, it's just a matter of having half a day to do it.
On that note, this is a possible implementation of pulsout(). Just like the BASIC Stamp, it blocks until finished.
Thanks, Steve.
I can do this in Spin, and it works as expected (using PAB):
The LED on P26 flashes (via the counter) and the LED on 27 tracks it via the code loop.
If I translate that to xbasic like this:
...P27 never lights. Am I missing something with waitpeq and waitpne?
David,
If you do go down the path of letting a cog run some inline PASM code, then I would urge for the 16 long, or possibly a couple more. I would like to experiment with xBasic, knitting it together with my multi threading realtime kernel. Among other things, it has the capability of loading short (16 long) PASM snippets. So, while I'm not yet sure of the way this may all work, having the 16 longs available would likely be of considerable help.
My intent would be to have multiple selections from a library of real time threads running simultaneous in a single cog under control of xBasic.
Cheers,
Peter (pjv)
I still don't quite understand the mechanics of the VM interface, but I did change to t4 and added drop -- these versions [seem to] work.
One thing that xbasic would be able to do that spin cannot is to be able to run cogs, then discard the code. This would only be applicable when running from external memory. With spin, there is a cost to running cog code as the code ends up taking up hub memory. But with xbasic running from external memory, you can fire off a cog, pass some parameters, set a flag when the cog has finished, then overwrite that cog with new code. You could be reloading a cog hundreds of times a second with different code each time. This would work with code we have now. You would just need to keep one cog free.
Obviously, I forgot to do that when I wrote the waitpeq function. I need to go through and check to see if there are any other instances of this type of omission. Thanks for catching it! Also, I think I'm going to add new temporaries that are used by the VM opcodes themselves so I can guarantee that t1-t4 are always available to NATIVE instructions.
internals.pdf
Ray
Ray
Ray
Ray
I also thank Jon for posting a link to the XBasic site in the EFX-TEK support forums where I learned about this XBasic program to the Propeller chip, which is the brains for the EFX-TEK's HC-8 and would be fun hack (program) with XBasic since it has shift registers for the 8 TTL inputs.
I will continue to follow this thread to keep up to date of what is going on with XBasic.