My wish is probably more of a driver/object thing but to be able to handle Modbus and BiSS-C would make the Prop very attractive to the process control world.
My wish is probably more of a driver/object thing but to be able to handle Modbus and BiSS-C would make the Prop very attractive to the process control world.
Yeah, that's definitely a driver/object issue. Are there already Spin drivers for these? If so my BASIC will be able to import them and you could use them directly.
@jmg: Thanks for the examples. I like the idea of having OPEN call a "driver" function that'll return a handle that can be used to re-vector the PRINT and INPUT routines. So something like:
OPEN SerialDriver(outpin, inpin, baud) AS #1
I guess ideally we would allow functions to return classes, so a SerialDriver that uses Spin FullDuplexSerial could be defined something like:
#include "propdriver.bi"
class fullduplexserial input "FullDuplexSerial.spin"
' the Spin object we will wrap
dim myser as fullduplexserial ptr
' the BASIC driver object
dim mydriver as IODriver ptr
' function to be called by Open
function SerialDriver(outpin, inpin, baud) as IODriver ptr
' create a new Spin object and start it up
myser = new fullduplexserial
myser.start(outpin, inpin, 0, baud)
' now create the BASIC driver to wrap it
mydriver = new Driver
' tell the driver which methods to use for input and output
mydriver.setoutputmethod(@myser.tx)
mydriver.setinputmethod(@myser.rx)
return mydriver
@jmg: Thanks for the examples. I like the idea of having OPEN call a "driver" function that'll return a handle that can be used to re-vector the PRINT and INPUT routines. So something like:
OPEN SerialDriver(outpin, inpin, baud) AS #1
FreeBASIC also allows this form too, be nice to support that as well ?
OPEN SerialDriver(outpin, inpin, baud) AS Const_Name
PRINT #Const_Name,"Text"
Attached below is more experiments with emulate/simulate of the Prop CNT & WAITCNT as Subroutines/Functions.
If you can tolerate that syntax, RdCNT(), WAITCNT(WayPoint) look to emulate quite well.
Addit - just checked and FreeBASIC seems to also tolerate no brackets RdCNT, WAITCNT WayPoint
I took 1.0000s wait code from Bean's SimpleFreqency Counter and coded a FreeBASIC precision version, that hopefully snaps to 80MHz SysCLKs, in uInt32
I found via experimenting that Windoze needs a round-down margin on the sleep, of around 21ms, as it likely is Sys Tick coarse.
Seems to work ok in Win10, 32b & 64b compilers. Be interesting to see if it works on Linux ?
Table at the end is the reported 1.000 second delay, and the PollCheck loop counter.
'http://www.freebasic.net/wiki/wikka.php?wakka=KeyPgOpenCom
' "COMn: [ baudrate ][ , [ parity ][ , [ data_bits ][ , [ stop_bits ][ , [ extended_options ]]]]]"
' where,
' n
' Com port to open. "1", "2", "3", "4", etc. Some platforms will support more serial ports depending on how the operating system is configured.
' Where n is not given, "COM:" will map to "COM1:", except on Linux where "COM:" maps to "/dev/modem"
'baudrate
' "300" (default), "1200", ..., etc.
'parity
' "N" (none), "E" (even, default), "O" (odd), "S" (space), "M" (mark), "PE" (QB-quirk: checked, even parity)
'data_bits
' "5", "6", "7" (default) or "8".
'stop_bits
' "1", "1.5" or "2". (default value depends on baud rate and data bits, see table below)
'extended_options Miscellaneous options. (See table below)
'
'Option Action
' 'CSn' Set the CTS duration (in ms) (n>=0), 0 = turn off, default = 1000
' 'DSn' Set the DSR duration (in ms) (n>=0), 0 = turn off, default = 1000
' 'CDn' Set the Carrier Detect duration (in ms) (n>=0), 0 = turn off
' 'OPn' Set the 'Open Timeout' (in ms) (n>=0), 0 = turn off
' 'TBn' Set the 'Transmit Buffer' size (n>=0), 0 = default, depends on platform
' 'RBn' Set the 'Receive Buffer' size (n>=0), 0 = default, depends on platform
' 'RS' Suppress RTS detection
' 'LF' Communicate in ASCII mode (add LF to every CR) - Win32 doesn't support this one
' 'ASC' same as 'LF'
' 'BIN' The opposite of LF and it'll always work
' 'PE' Enable 'Parity' check
' 'DT' Keep DTR enabled after CLOSE
' 'FE' Discard invalid character on error
' 'ME' Ignore all errors
' 'IRn' IRQ number for COM (only supported (?) on DOS)
#include "windows.bi"
#include "file.bi"
Declare Function RdCNT() As uinteger
Declare Sub WAITCNT (WaitForwardValue As uinteger)
dim as HANDLE h
dim as COMMPROP cp
dim as integer res,wb
Dim b As String
Dim n as Long
' COM4 is SiLabs CP2102N
' COM5 is Nuvoton VCP
Const AS Long cCom = 16
' If Open Com ("com1:9600,n,8,1,cs,rs,ds,bin" For Binary As #1) <> 0 Then
'If Open Com ("com5:3906,n,8,1,cs,rs,ds,bin" For Binary As #1) <> 0 Then '3906 is lowest baud for 16MHz/16/256
' if open com ( "COM5:9600,N,8,1,DS,TB32000,RB32000" for binary as #1 ) <> 0 then
' if open com ( "COM4:9600,N,8,1,DS,TB32000,RB32000" for binary as #1 ) <> 0 then
If Open Com ("COM16:115200,n,8,1,cs0,rs,ds0,cd0,bin,op2000,TB32000,RB32000" For Binary As cCom) <> 0 Then 'generic baud
n = Err()
Print "unable to open serial port, (press any key) Error Code: ";n
Sleep
End
else
n = Err()
Print "No error on Open Com, Error Code: "; n 'always 0 ?
End If
h = cast(HANDLE, FileAttr(cCom, fbFileAttrHandle))
if( GetCommProperties( h, @cp ) = 0 ) then
print "GetCommProperties(): Error "; GetLastError()
else
print "dwCurrentTxQueue: "; cp.dwCurrentTxQueue ' always reports 0, 16384 for Nuvoton or 0,640 for CP2102N ????
print "dwCurrentRxQueue: "; cp.dwCurrentRxQueue ' not quite how example http://www.freebasic.net/forum/viewtopic.php?t=6172&highlight=transmit+timeout claims ??
print "cp.dwMaxBaud: "; cp.dwMaxBaud
print "cp.dwSettableBaud: "; cp.dwSettableBaud
print "cp.wSettableData: "; cp.wSettableData
print "cp.dwMaxTxQueue: ";cp.dwMaxTxQueue
print "cp.dwMaxRxQueue: ";cp.dwMaxRxQueue
print "cp.dwSettableParams: ";cp.dwSettableParams
end if
res=PurgeComm(h,PURGE_TXCLEAR)'clear Write only
print "Purge res: ";res
Print "Sending command: AT+CrLf"
'Print #cCom, "AT" + Chr(13, 10);
Print #cCom, "UUUU"; ' 4 char ?
Print "Response: (queue.0) = ";LOC(cCom)
Sleep 500,1
Print "Response: (queue.500) = ";LOC(cCom)
While( LOC(cCom) > 0 )
Input #cCom, b
Print b;
Wend
Close #cCom
' If the processor has a precision timer (as the Performance Counter Pentium processors from Intel have) and the OS uses it,
' the precision is linked to the processor clock and microseconds can be expected.
' Var f = Cast(Double, 0.0) also supported
Const As Double tP1_CLK = 1/80.0e6 ' Period of PropSysCLK
Const As Uinteger FREQ = 80000000
Const As Uinteger ONESEC = FREQ + 4
Const As Uinteger t1ms = CUint(.001/(1/80.0e6)) ' Sysclks in 1ms
Dim Shared As Double StartD,EndD
Dim Shared as uinteger PollCheck
Var Start = Timer() ' Auto-selects double type ? (64b real)
Print "chars to screen ",(Timer-Start)/tP1_CLK ' delays in P1 sysclocks
Print "chars to screen ",(Timer-Start)/tP1_CLK
Print "chars to screen ",(Timer-Start)/tP1_CLK
Print "t1ms ",t1ms
Print "Start WAITCNT, ", ONESEC
Var LoopC = 0
WHILE LoopC < 60
Var WayPoint = RdCNT() + ONESEC ' Uinteger Prop CNT walk-ahead, for WAITCNT
Var StartT = Timer()
WAITCNT(WayPoint) ' Close to Prop WAITCNT
Var EndT = Timer()
Print " END WAITCNT",EndT-StartT, EndD-StartD, PollCheck
LoopC = LoopC +1
WEND
Sleep ' press any key to exit
Function RdCNT() As uinteger
return CUint(Timer/tP1_CLK)
end function
Sub WAITCNT (WaitForwardValue As uinteger)
VAR SleepRounded = ((WaitForwardValue-RdCNT())/t1ms)-21 ' 20ms OK, Experimental trim-down, need finite loops 16,18ms fail 19ms is marginal, choose 21ms - test on other PC's ?
if SleepRounded >= 0 then
Sleep(SleepRounded) 'round down, so most of time is Sleep,
end if
Var AbsDiff = ABS(WaitForwardValue-RdCNT() ) ' 99% of time this is small, but in rare cases, RdCNT will be MAX, and WaitForwardValue will have wrapped
PollCheck = 0
StartD = Timer()
While AbsDiff >= ABS(WaitForwardValue-RdCNT() ) ' look for reversal of setpoint diff, diff decreases until it hits match, then starts to increase.
AbsDiff = ABS(WaitForwardValue-RdCNT() )
PollCheck = PollCheck + 1
wend
EndD = Timer()
end Sub
' While (RdCNT() < WaitForwardValue ) ' finer timing for the last fractional bit ok in 32b, !BUT! this can exit early on wrap case, might not matter, as it's a few ms ?
' While (CDbl(RdCNT()) < CDbl(WaitForwardValue) ) ' finer timing for the last fractional bit , but also not wrap proof
' UUUUchars to screen 0.0003803819417953491 Timer resolves to fractional ms,
' chars to screen 0.0007216352969408035
' chars to screen 0.001131524331867695
' press any key
'
' UUUUchars to screen 11058.67326259613 scaled as P1_SysCLKs
' chars to screen 32123.99780750275
' chars to screen 98706.89362287521
' Sleep -20ms 1 Second Poll dT PollCheck
' END WAITCNT 1.0000019245781 0.0008463980630040169 5058
' END WAITCNT 1.000000320840627 0.001199839171022177 7155
' END WAITCNT 1.000003849156201 0.001386181451380253 7402
' END WAITCNT 1.000000641681254 0.0008810367435216904 5267
' END WAITCNT 1.000000320840627 0.0007209940813481808 4193
' END WAITCNT 1.000001282896847 0.0007909121923148632 3654
' END WAITCNT 1.000000641215593 0.001452892553061247 17501
' END WAITCNT 1.000000320840627 0.0008095144294202328 4838
' END WAITCNT 1.000000641215593 0.0005359346978366375 6005
' END WAITCNT 1.000000320840627 0.001278417184948921 7492
' END WAITCNT 1.000001924112439 0.0006940527819097042 4148
' END WAITCNT 1.000000320840627 0.0009403713047504425 5621
' END WAITCNT 1.00000096205622 0.001378804445266724 7303
' END WAITCNT 1.000000320840627 0.001177388243377209 14496
' Sleep -21ms - appears to have 1-2ms headroom.
' Start WAITCNT, 80000004
' END WAITCNT 1.000000320840627 0.002297687344253063 27818
' END WAITCNT 1.000000320374966 0.002082479186356068 25214
' END WAITCNT 1.000002565793693 0.002000694163143635 11840
' END WAITCNT 1 0.001514151692390442 18941
' END WAITCNT 1 0.002052330877631903 25466
' END WAITCNT 1 0.00162897165864706 19920
' END WAITCNT 1 0.002414110582321882 27283
' END WAITCNT 1.000000320840627 0.002109741326421499 23042
' END WAITCNT 1.000000320840627 0.001878176350146532 22379
' END WAITCNT 1 0.002435599453747273 22901
' END WAITCNT 1.000000641215593 0.002007750328630209 11925
' END WAITCNT 1.000001282896847 0.002022824250161648 24741
' END WAITCNT 1.000000641215593 0.001587918493896723 19425
' END WAITCNT 1.00000096205622 0.002033408265560865 12133
' END WAITCNT 1 0.002054576296359301 24889
' END WAITCNT 1.000000320840627 0.002412828151136637 14408
' END WAITCNT 1.000000320840627 0.002099157311022282 12525
' END WAITCNT 1.00000288663432 0.001507736742496491 16864
' END WAITCNT 1 0.001880421303212643 11226
' END WAITCNT 1 0.002069971058517695 25527
' END WAITCNT 1.000000320840627 0.002303139306604862 28354
' END WAITCNT 1.000000320840627 0.00224508810788393 21464
' END WAITCNT 1.000001282896847 0.002430467866361141 27165
' END WAITCNT 1.000000320840627 0.001630575396120548 19473
' END WAITCNT 1.000000320840627 0.001637310720980167 19703
' END WAITCNT 1.000001924112439 0.001506453845649958 8988
' END WAITCNT 1.000001282896847 0.002158171031624079 12899
' END WAITCNT 1 0.001809541136026382 10801
' END WAITCNT 1.000001924112439 0.001496831886470318 8867
' END WAITCNT 1.000002565793693 0.001582145225256681 9410
' END WAITCNT 1.000000641681254 0.002288706600666046 13382
' END WAITCNT 1.000001282896847 0.002237069886177778 13238
' END WAITCNT 1 0.001288359519094229 15476
' END WAITCNT 1.000000320374966 0.002285178750753403 25487
' END WAITCNT 1 0.001534357201308012 18901
' END WAITCNT 1 0.002390056382864714 14153
' END WAITCNT 1.000000320840627 0.002082800026983023 12427
' END WAITCNT 1 0.001740584615617991 21381
' END WAITCNT 1.000000320840627 0.002255672123283148 13461
' END WAITCNT 1.000001282896847 0.002162340562790632 23436
' END WAITCNT 1 0.002442976459860802 14312
' END WAITCNT 1.000000320840627 0.00232334528118372 13768
' END WAITCNT 1 0.002074782270938158 11472
' END WAITCNT 1.000001603737474 0.001473418902605772 7573
' END WAITCNT 1.000001282896847 0.001449364703148603 17849
' END WAITCNT 1.000000641681254 0.00186117785051465 10907
' END WAITCNT 1.000001603737474 0.002372095827013254 13954
' END WAITCNT 1 0.00146379740908742 8754
' END WAITCNT 1.000002245418727 0.002245408948510885 13275
' END WAITCNT 1.000000320840627 0.002404168248176575 29444
' END WAITCNT 1.000001282896847 0.001857329159975052 11083
' END WAITCNT 1.00000096205622 0.002300573512911797 28658
' END WAITCNT 1.000000641681254 0.001931417267769575 11456
' END WAITCNT 1.000001282896847 0.001985619775950909 11653
' END WAITCNT 1.000000320840627 0.002100440207868815 26394
' END WAITCNT 1.0000019245781 0.002055859193205833 25121
' END WAITCNT 1.00000096205622 0.002381717786192894 29307
' END WAITCNT 1.000000320840627 0.001577334478497505 19569
' END WAITCNT 1.000000320840627 0.002189281396567822 20885
' END WAITCNT 1 0.001560336444526911 19085
I've thought about it some more and I think we'll need the garbage collector after all -- if not for strings, then for driver objects (like the full duplex serial wrapper I posted earlier). It'll also simplify things immensely if strings are just pointers to character (as in Spin and C). The major annoyance with a mark-and-sweep collector is finding the references, so we'll have to guarantee that dynamic pointers are stored in HUB memory. If we're not optimizing at all this is trivial (all the local variables will end up on the stack in HUB memory) but this will require some work for the optimized case where pointers are in COG memory.
The tough part is that the failure mode (we run out of memory and garbage collect in the middle of some operation where a temporary is in a register but not stored in HUB yet) is going to be rare and hard to test.
I guess for the single COG case it wouldn't be too hard to scan COG memory for pointers, but for multi-threaded programs I don't know how we can do this. On P2 we could interrupt all the COGs and tell them to scan their own memory for pointers, but for P1 we'd have to somehow arrange for COGs running the BASIC code to poll periodically. Maybe the LMM loop could check for a flag, but that seems painful for such a rare case (and also precludes FCACHE).
@jmg thanks again for the sample code, it gives some good inspiration. I do want to warn that I don't regard FreeBasic compatibility as a firm requirement -- I want it to be compatible in a general sense, but there are going to be some things in my basic that don't exist in FreeBasic and vice-versa. You have shown that debugging code on the PC is feasible, so definitely I'd like to keep the ability to write useful code in a common subset of the languages.
A few differences that exist already:
(1) There are some Prop specific pseudo-arrays, input(), output(), and direction(), which correspond to the INA, OUTA, and DIRA registers (so you can say something like "output(1) = 1" to set pin 1 high). That's going to be platform specific no matter what, so I think it'll always be hidden by #ifdefs
(2) I think FreeBasic treats A$ and A as the same identifier. I'd rather not do that -- my parsing code treats the type flag at the end of an identifier as part of the name. That's the way I remember Microsoft BASIC working back in the day, and it seems more natural to me.
(3) Right now I ignore underscores in identifiers, to match the way they are ignored in numbers. I'm not sure if FreeBasic does that.
Having said all that, I think I've made progress towards getting useful code running. I was able to run a Fibonacci test today:
dim as integer r, t
print "hello, world"
function fibo(n)
if (n < 2) then
return n
else
return fibo(n-1) + fibo(n-2)
end if
end function
for i = 1 to 8
t = getcnt()
r = fibo(i)
t = getcnt() - t
print "fibo(", i, ") = ", r, " took ", t, " cycles"
next
this produced the output:
hello, world
fibo(1) = 1 took 576 cycles
fibo(2) = 1 took 1504 cycles
fibo(3) = 2 took 2432 cycles
fibo(4) = 3 took 4288 cycles
fibo(5) = 5 took 7072 cycles
fibo(6) = 8 took 11712 cycles
fibo(7) = 13 took 19136 cycles
fibo(8) = 21 took 31200 cycles
The fibo(8) time of 31200 cycles compares to 31072 cycles for fastspin, 10992 cycles for PropGCC LMM, 58800 cycles for PropGCC CMM, and 137360 cycles for regular Spin.
That timing is impressive. Can you show the amount of memory used (hub and/or cog) for each. I am particularly interested in comparisons with PropGCC LMM and CMM.
Is the code you showed compiled into PASM and fit into a cog? If so how would you treat large programs.
The BASIC compiler creates LMM code by default, just like fastspin and PropGCC (in LMM mode). It is possible to create COG code too. The COG version is 800 bytes long (total) and takes 9140 cycles for fibo(8).
Breaking the sizes down into hub/cog for all of these is a lot of work, and probably not too useful for such a small demo. But the total sizes for LMM are:
The size difference is almost all in the I/O libraries. The C version is pulling in printf, which adds a lot of overhead. Most of the size in the Spin and fastspin versions is associated with the FullDuplexSerial object. "fastbasic" (what I'm calling it for now, since it's based on fastspin) has a very tiny I/O library right now which saves space, but it's likely to grow as more features are added.
The actual recursive fibo function compiles to 100 bytes in both fastspin and fastbasic; this is also the same as Catalina C in LMM mode. PropGCC needs only 84 bytes in LMM, 26 bytes in CMM. In Spin it's 25 bytes.
I don't have a recursive version of fibo for PropBasic because PropBasic has very limited support for recursion (it has no local variables and quite a restrictive expression syntax). But I in general I expect it would generate pretty similar code to my BASIC for this kind of function, which is very straightforward. Spin's smaller size is due to its having a stack based bytecode interpreter, which is pretty much ideal for this kind of code. GCC has some fancy optimizations which reduce the recursion inside fibo(), and which also reduces the size needed. Otherwise I'd expect any straightforward LMM translation of the function to be about 100 bytes long.
I don't have a recursive version of fibo for PropBasic because PropBasic has very limited support for recursion (it has no local variables and quite a restrictive expression syntax). But I in general I expect it would generate pretty similar code to my BASIC for this kind of function, which is very straightforward. Spin's smaller size is due to its having a stack based bytecode interpreter, which is pretty much ideal for this kind of code. GCC has some fancy optimizations which reduce the recursion inside fibo(), and which also reduces the size needed. Otherwise I'd expect any straightforward LMM translation of the function to be about 100 bytes long.
An interesting PropBasic comparison, could be to port Bean's Frequency Counters (simple, and Reciprocal) ?
(1) There are some Prop specific pseudo-arrays, input(), output(), and direction(), which correspond to the INA, OUTA, and DIRA registers (so you can say something like "output(1) = 1" to set pin 1 high). That's going to be platform specific no matter what, so I think it'll always be hidden by #ifdefs
(2) I think FreeBasic treats A$ and A as the same identifier. I'd rather not do that -- my parsing code treats the type flag at the end of an identifier as part of the name. That's the way I remember Microsoft BASIC working back in the day, and it seems more natural to me.
Default FreeBASIC gives this error, as the suffix $ is deprecated, but I think you can tolerate it with a switch.
COM4_Test.bas(45) error 147: Suffixes are only valid in -lang deprecated or fblite or qb, found 'b' in 'Dim b$ As String'
(3) Right now I ignore underscores in identifiers, to match the way they are ignored in numbers. I'm not sure if FreeBasic does that.
FreeBASIC coughs on 80_000_000, but ignoring underscores inside names seems a little strange/risky to me, as it's a valid asciii char.
That said, I do not use underscores in VAR names much, but they are rather more common in file names.
(3) Right now I ignore underscores in identifiers, to match the way they are ignored in numbers. I'm not sure if FreeBasic does that.
FreeBASIC coughs on 80_000_000, but ignoring underscores inside names seems a little strange/risky to me, as it's a valid asciii char.
That said, I do not use underscores in VAR names much, but they are rather more common in file names.
Ah, I see. For now fastbasic accepts (and ignores) underscores inside numbers and inside variable names. In strings such as file names of course every character is kept and valid.
For example, SomeVar, Some_Var, somevar, and some_var all refer to the same variable name.
That's probably going to be the most controversial quirk, but I really think if your variables are case insensitive then ignoring underscores makes sense too. (The other logical alternative is to be like C and treat all characters as literal ASCII, so "A" and "a" are different variables.) If there's a lot of pushback I could change that (or make it an option).
Ignoring underscores inside numbers is a Spin feature I really like, and shouldn't break anything.
Making some more progress. I've got most integer features implemented now, although there's still some work to do on properly mixing unsigned and signed variables. I've added some pseudo-arrays for the input, output, and direction bits. For example, a program to toggle 3 pins is:
rem simple program to toggle a pin
const lopin = 16
const hipin = 18
let mscycles = clkfreq / 1000
direction(lopin,hipin) = output
do
output(lopin,hipin) = &b101
pausems 500
output(lopin,hipin) = &b010
loop
sub pausems ms
waitcnt(getcnt() + ms * mscycles)
end sub
@yeti has been able to get a mandelbrot program ported to the git version of fastspin/basic, which is pretty amazing given how sparse the documentation is so far -- kudos to him!
I'm still trying to figure out what to call this thing, which is a compiler that can handle both Spin and BASIC. Names I've toyed with:
(a) fastspin: that's what it's called now, but obviously that's kind of leaving out the BASIC part from the name, so not very good!
(b) multiprop: Multiple language compiler for Propeller. The various language dialects would be MultiSpin, MultiBASIC, etc. There was a MultiBASIC for the ZX Spectrum, but that was many years ago, so I don't think there'd be much confusion.
(c) guppy: short for "Grand Unified Propeller Programming sYstem". The dialects would be "Guppy BASIC", "Guppy Spin", etc. Seems a bit friendlier than "multiprop", but not as professional.
EDIT: Forget Baspin. The urban dictionary says it's slang for stinking, filthy, dirty or diseased. Also, there's a company named Baspin in a Spanish speaking country that makes protective gloves.
EDIT: Forget Baspin. The urban dictionary says it's slang for stinking, filthy, dirty or diseased. Also, there's a company named Baspin in a Spanish speaking country that makes protective gloves.
Heh heh... guess we'll cross that one off the list then . Thanks for checking though.
Also, I'd like to avoid restricting it to just the two languages BASIC and Spin. Over time there may be some more languages added. You'll notice that the "basic" branch has 3 directories inside "frontends/" .
EDIT: Forget Baspin. The urban dictionary says it's slang for stinking, filthy, dirty or diseased. Also, there's a company named Baspin in a Spanish speaking country that makes protective gloves.
Heh heh... guess we'll cross that one off the list then . Thanks for checking though.
Also, I'd like to avoid restricting it to just the two languages BASIC and Spin. Over time there may be some more languages added. You'll notice that the "basic" branch has 3 directories inside "frontends/" .
I'm still trying to figure out what to call this thing, which is a compiler that can handle both Spin and BASIC. Names I've toyed with:
(a) fastspin: that's what it's called now, but obviously that's kind of leaving out the BASIC part from the name, so not very good!
(b) multiprop: Multiple language compiler for Propeller. The various language dialects would be MultiSpin, MultiBASIC, etc. There was a MultiBASIC for the ZX Spectrum, but that was many years ago, so I don't think there'd be much confusion.
(c) guppy: short for "Grand Unified Propeller Programming sYstem". The dialects would be "Guppy BASIC", "Guppy Spin", etc. Seems a bit friendlier than "multiprop", but not as professional.
Any opinions? Other suggestions?
Guppy sounds good to me, unless folks are allergic to fish...
(c) guppy: short for "Grand Unified Propeller Programming sYstem". The dialects would be "Guppy BASIC", "Guppy Spin", etc. Seems a bit friendlier than "multiprop", but not as professional.
I find a quick run past urban dictionary can give a guide to how a name might come across in the wider world contexts... and guppy does not stack up well.
(b) multiprop: Multiple language compiler for Propeller. The various language dialects would be MultiSpin, MultiBASIC, etc. There was a MultiBASIC for the ZX Spectrum, but that was many years ago, so I don't think there'd be much confusion.
'Multi' is somewhat overused, but I think there is merit in what IEC61131 does, which is include multiple formal language arms. ( tho the core name of IEC61131-3 is the total opposite of snappy/cool the Any+Mix nature is great)
That could lead to
"Want to Mix Any Language on Any cores ? - use MixAny.BASIC, MixAny.Spin, MixAny.PASM ! " (Could you do MixAny .Blockly?)
The 'Spin' name itself I am still two minds over. Mind pollution crossover from the Corporate/Political/Media universes mean 'Spin' is more tarnished every year.
Spin also desperately needs a cleanse pass, but should the output result of that exercise still be called Spin, or should spin be deprecated ?
That would be an interesting challenge! I have no idea how to go about compiling Lisp to machine language. Handling eval, in particular, seems like it would be tricky. Obviously it's possible since there are native code Lisp compilers out there, like Chicken Scheme. Is compiling to C or PASM something you've looked at?
I'm still trying to figure out what to call this thing, which is a compiler that can handle both Spin and BASIC.
and also PASM & PASM2 ?
I thought PASM was defined as "the stuff in a DAT section inside a Spin file"? I guess there's some potential confusion, but yeah, fastspin+basic can handle everything in Spin, including the PASM/PASM2 inside DAT (and the somewhat limited PASM/PASM2 inside an ASM/ENDASM block).
I find a quick run past urban dictionary can give a guide to how a name might come across in the wider world contexts... and guppy does not stack up well.
There are certainly worse out there
That could lead to
"Want to Mix Any Language on Any cores ? - use MixAny.BASIC, MixAny.Spin, MixAny.PASM ! " (Could you do MixAny .Blockly?)
Intestesting idea. I hadn't thought of the "mix" angle of mixing languages, but something along those lines seems promising.
(Blockly is a whole other can of worms, but I think Blockly can be converted to Spin can't it?)
The 'Spin' name itself I am still two minds over. Mind pollution crossover from the Corporate/Political/Media universes mean 'Spin' is more tarnished every year.
Spin also desperately needs a cleanse pass, but should the output result of that exercise still be called Spin, or should spin be deprecated ?
Wow, you've given me a great idea -- the new compiler is not Spin, so perhaps it should be called PINS (recursively "PINS Is Not Spin"). Then we'd have PINS Basic, PINS Pascal, etc... not sure what to call the default Spin based dialect, "PINS Spin" doesn't really sound right. Maybe "PINS Original".
The naming problem:
Put Spin, PASM, BASIC, ... in your "blender" and run the resulting smoothie on your Propeller...
Ok... to avoid conflicts with the animation program "blender", "propblender" may be better?
Is there another compact word for a smoothie-maker?
The next generation of Propeller loaders should accept ".smoothie" as alternative to ".binary" too... ;-)
I thought PASM was defined as "the stuff in a DAT section inside a Spin file"? I guess there's some potential confusion...
hehe, Yes that's how it's 'managed' now, archaic & clunky, and which creates massive wider industry confusion amongst those who are well-used to the file-extension indicates file contents norm .C/.ASM/.LST/.MAP/.BAS/.PAS/.PY
That would be an interesting challenge! I have no idea how to go about compiling Lisp to machine language. Handling eval, in particular, seems like it would be tricky. Obviously it's possible since there are native code Lisp compilers out there, like Chicken Scheme. Is compiling to C or PASM something you've looked at?
I haven't really done anything other than compilers that target byte code VMs that I defined myself. I'm thinking of writing a PASM code generator for the C-like language I'm working on now though.
I have to agree with Mickster.
Put the word BASIC in the name of a language, and it is sure to be ignored by...Pretty much everyone.
Yes and no.
This is not just a single language, it is a development flow offering many flows into many cores (well, cores in one die, & I guess it could actually manage 2 die or 4 die projects ?)
The development flow needs the catchy name.
I think it's fine to keep BASIC, and 'can be compatible with FreeBASIC' is a solid enough cornerstone, it's not treated as a banner item.
No one thinks ASM is sexy, but everyone prefers a microcontroller system that can do it when they need it.
eg IEC61131 uses the totally deadpan LD FBD ST IL SFC internal language flow names
That could lead to
"Want to Mix Any Language on Any cores ? - use MixAny.BASIC, MixAny.Spin, MixAny.PASM ! " (Could you do MixAny .Blockly?)
Interesting idea. I hadn't thought of the "mix" angle of mixing languages, but something along those lines seems promising.
(Blockly is a whole other can of worms, but I think Blockly can be converted to Spin can't it?)
This raises a very good systems question
I don't know Blockly needs to be fully converted, just easily co-operated with.
eg Something like an include file 'rosterboard/table' for any CORE on the chip you link to. (usually this is 8, but it seems 2,3,4 dice here is actually just a bigger form)
What file needs to be downloaded-once eg 5 cores may enter the same file name, and a can-single-build project would have a single download file.
*Size & Where it goes if not already in file
*HUB resource it expects as own : Address and die#
*Interface rules : Named variables and FIFOs : address and die#
that becomes like a poor mans linker, you co-operate on the big resource pieces.
@jmg I dunno, I think that FreeBASIC appeals to those who already realise that BASIC has not been Beginners All-purpose Symbolic Instruction Code since QuickBASIC and TurboBASIC appeared, back in the 80's.
It seems to have picked up where PowerBASIC left off after the death of Bob Zale.
The problem is that we are stuck with the stigma of line numbers and GOTOs, resulting in spaghetti code due to ignorance.
Today I use:
QuickBASIC
PowerBASIC
RFO BASIC (Android interpreter)
B4A (BASIC for Android compiler)
Micromite
Bypic (BASIC/C hybrid)
PropBasic
The only GOTO that I have ever used is with PropBasic because it translates directly to jmp.
After 33 years of using this language which resulted in a 80-employee business, other programmers still attempt to ridicule my choice of programming language.
If I was using slow, clunky Python, I would be totally cool.
For me, PropBasic is high level PASM with a BASIC-like syntax.
....
After 33 years of using this language which resulted in a 80-employee business, other programmers still attempt to ridicule my choice of programming language.
..
Hehe yes, there are always reflex dinosaurs, but amongst the thinking programmers, many are at least basic aware.
Over in AVR land, someone was asking about his customer who was asking about adding a BASIC script, into their existing 'plc like' custom controller based on a MegaAVR and project developed in C.
Does not sound like cheap plant or equipment.
No one said the customer was nuts, they focused on what Basic's are out there, to allow a small interpreter.
Choices are to patch-in almost any assembler/binary BASIC and use that, or another path is to use Basic generates C, and then their C project links-in that.
One path is RAM limited, needs to be reloaded on power, and not easily tested without consuming costly plant, the other is flash limited, stays there over power cycles, but can be tested away from plant.
FreeBASIC shows code generation backends for gas|gcc|llvm - not sure how much road tested / proven those are
(Did someone mention a LLVM player in P2 ?
There is actually quite a large catchment of people exactly like this guys customer.
Someone whose day-job is not programming, but who needs to be able to code-together 'plc like' plant, resulting in systems that run some portion as BASIC like
The P2 actually makes that question simpler in many ways : you could give one CORE to the customer as a sandbox, with rules on HUB resource, whilst doing product-engine-room work, in the other 7 CORES.
Comments
Yeah, that's definitely a driver/object issue. Are there already Spin drivers for these? If so my BASIC will be able to import them and you could use them directly.
@jmg: Thanks for the examples. I like the idea of having OPEN call a "driver" function that'll return a handle that can be used to re-vector the PRINT and INPUT routines. So something like: I guess ideally we would allow functions to return classes, so a SerialDriver that uses Spin FullDuplexSerial could be defined something like:
FreeBASIC also allows this form too, be nice to support that as well ?
Attached below is more experiments with emulate/simulate of the Prop CNT & WAITCNT as Subroutines/Functions.
If you can tolerate that syntax, RdCNT(), WAITCNT(WayPoint) look to emulate quite well.
Addit - just checked and FreeBASIC seems to also tolerate no brackets RdCNT, WAITCNT WayPoint
I took 1.0000s wait code from Bean's SimpleFreqency Counter and coded a FreeBASIC precision version, that hopefully snaps to 80MHz SysCLKs, in uInt32
I found via experimenting that Windoze needs a round-down margin on the sleep, of around 21ms, as it likely is Sys Tick coarse.
Seems to work ok in Win10, 32b & 64b compilers. Be interesting to see if it works on Linux ?
Table at the end is the reported 1.000 second delay, and the PollCheck loop counter.
The tough part is that the failure mode (we run out of memory and garbage collect in the middle of some operation where a temporary is in a register but not stored in HUB yet) is going to be rare and hard to test.
I guess for the single COG case it wouldn't be too hard to scan COG memory for pointers, but for multi-threaded programs I don't know how we can do this. On P2 we could interrupt all the COGs and tell them to scan their own memory for pointers, but for P1 we'd have to somehow arrange for COGs running the BASIC code to poll periodically. Maybe the LMM loop could check for a flag, but that seems painful for such a rare case (and also precludes FCACHE).
Any ideas?
A few differences that exist already:
(1) There are some Prop specific pseudo-arrays, input(), output(), and direction(), which correspond to the INA, OUTA, and DIRA registers (so you can say something like "output(1) = 1" to set pin 1 high). That's going to be platform specific no matter what, so I think it'll always be hidden by #ifdefs
(2) I think FreeBasic treats A$ and A as the same identifier. I'd rather not do that -- my parsing code treats the type flag at the end of an identifier as part of the name. That's the way I remember Microsoft BASIC working back in the day, and it seems more natural to me.
(3) Right now I ignore underscores in identifiers, to match the way they are ignored in numbers. I'm not sure if FreeBasic does that.
Having said all that, I think I've made progress towards getting useful code running. I was able to run a Fibonacci test today:
this produced the output:
The fibo(8) time of 31200 cycles compares to 31072 cycles for fastspin, 10992 cycles for PropGCC LMM, 58800 cycles for PropGCC CMM, and 137360 cycles for regular Spin.
Is the code you showed compiled into PASM and fit into a cog? If so how would you treat large programs.
Thanks
Tom
Breaking the sizes down into hub/cog for all of these is a lot of work, and probably not too useful for such a small demo. But the total sizes for LMM are:
The size difference is almost all in the I/O libraries. The C version is pulling in printf, which adds a lot of overhead. Most of the size in the Spin and fastspin versions is associated with the FullDuplexSerial object. "fastbasic" (what I'm calling it for now, since it's based on fastspin) has a very tiny I/O library right now which saves space, but it's likely to grow as more features are added.
The actual recursive fibo function compiles to 100 bytes in both fastspin and fastbasic; this is also the same as Catalina C in LMM mode. PropGCC needs only 84 bytes in LMM, 26 bytes in CMM. In Spin it's 25 bytes.
I don't have a recursive version of fibo for PropBasic because PropBasic has very limited support for recursion (it has no local variables and quite a restrictive expression syntax). But I in general I expect it would generate pretty similar code to my BASIC for this kind of function, which is very straightforward. Spin's smaller size is due to its having a stack based bytecode interpreter, which is pretty much ideal for this kind of code. GCC has some fancy optimizations which reduce the recursion inside fibo(), and which also reduces the size needed. Otherwise I'd expect any straightforward LMM translation of the function to be about 100 bytes long.
An interesting PropBasic comparison, could be to port Bean's Frequency Counters (simple, and Reciprocal) ?
Default FreeBASIC gives this error, as the suffix $ is deprecated, but I think you can tolerate it with a switch. FreeBASIC coughs on 80_000_000, but ignoring underscores inside names seems a little strange/risky to me, as it's a valid asciii char.
That said, I do not use underscores in VAR names much, but they are rather more common in file names.
Ah, I see. For now fastbasic accepts (and ignores) underscores inside numbers and inside variable names. In strings such as file names of course every character is kept and valid.
For example, SomeVar, Some_Var, somevar, and some_var all refer to the same variable name.
That's probably going to be the most controversial quirk, but I really think if your variables are case insensitive then ignoring underscores makes sense too. (The other logical alternative is to be like C and treat all characters as literal ASCII, so "A" and "a" are different variables.) If there's a lot of pushback I could change that (or make it an option).
Ignoring underscores inside numbers is a Spin feature I really like, and shouldn't break anything.
Eric
Yes, a nice feature that's common in microcontroller space, and I've posted a Feature Request for underscores in numbers in the FB forum.
@yeti has been able to get a mandelbrot program ported to the git version of fastspin/basic, which is pretty amazing given how sparse the documentation is so far -- kudos to him!
(a) fastspin: that's what it's called now, but obviously that's kind of leaving out the BASIC part from the name, so not very good!
(b) multiprop: Multiple language compiler for Propeller. The various language dialects would be MultiSpin, MultiBASIC, etc. There was a MultiBASIC for the ZX Spectrum, but that was many years ago, so I don't think there'd be much confusion.
(c) guppy: short for "Grand Unified Propeller Programming sYstem". The dialects would be "Guppy BASIC", "Guppy Spin", etc. Seems a bit friendlier than "multiprop", but not as professional.
Any opinions? Other suggestions?
EDIT: Forget Baspin. The urban dictionary says it's slang for stinking, filthy, dirty or diseased. Also, there's a company named Baspin in a Spanish speaking country that makes protective gloves.
Heh heh... guess we'll cross that one off the list then . Thanks for checking though.
Also, I'd like to avoid restricting it to just the two languages BASIC and Spin. Over time there may be some more languages added. You'll notice that the "basic" branch has 3 directories inside "frontends/" .
Guppy sounds good to me, unless folks are allergic to fish...
yes, that leaves too much on the table
I find a quick run past urban dictionary can give a guide to how a name might come across in the wider world contexts... and guppy does not stack up well.
'Multi' is somewhat overused, but I think there is merit in what IEC61131 does, which is include multiple formal language arms. ( tho the core name of IEC61131-3 is the total opposite of snappy/cool the Any+Mix nature is great)
That could lead to
"Want to Mix Any Language on Any cores ? - use MixAny.BASIC, MixAny.Spin, MixAny.PASM ! " (Could you do MixAny .Blockly?)
The 'Spin' name itself I am still two minds over. Mind pollution crossover from the Corporate/Political/Media universes mean 'Spin' is more tarnished every year.
Spin also desperately needs a cleanse pass, but should the output result of that exercise still be called Spin, or should spin be deprecated ?
That would be an interesting challenge! I have no idea how to go about compiling Lisp to machine language. Handling eval, in particular, seems like it would be tricky. Obviously it's possible since there are native code Lisp compilers out there, like Chicken Scheme. Is compiling to C or PASM something you've looked at?
There are certainly worse out there
Intestesting idea. I hadn't thought of the "mix" angle of mixing languages, but something along those lines seems promising.
(Blockly is a whole other can of worms, but I think Blockly can be converted to Spin can't it?)
Wow, you've given me a great idea -- the new compiler is not Spin, so perhaps it should be called PINS (recursively "PINS Is Not Spin"). Then we'd have PINS Basic, PINS Pascal, etc... not sure what to call the default Spin based dialect, "PINS Spin" doesn't really sound right. Maybe "PINS Original".
Put Spin, PASM, BASIC, ... in your "blender" and run the resulting smoothie on your Propeller...
Ok... to avoid conflicts with the animation program "blender", "propblender" may be better?
Is there another compact word for a smoothie-maker?
The next generation of Propeller loaders should accept ".smoothie" as alternative to ".binary" too... ;-)
hehe, Yes that's how it's 'managed' now, archaic & clunky, and which creates massive wider industry confusion amongst those who are well-used to the file-extension indicates file contents norm .C/.ASM/.LST/.MAP/.BAS/.PAS/.PY
It seems that the very hint of the name BASIC, turns people off and today, the acronym no-longer applies.
I am sure that there would be many more adopters of PropBasic if it had been named PASM-RAD or something similar.
Put the word BASIC in the name of a language, and it is sure to be ignored by...Pretty much everyone.
Bean
Yes and no.
This is not just a single language, it is a development flow offering many flows into many cores (well, cores in one die, & I guess it could actually manage 2 die or 4 die projects ?)
The development flow needs the catchy name.
I think it's fine to keep BASIC, and 'can be compatible with FreeBASIC' is a solid enough cornerstone, it's not treated as a banner item.
No one thinks ASM is sexy, but everyone prefers a microcontroller system that can do it when they need it.
eg IEC61131 uses the totally deadpan LD FBD ST IL SFC internal language flow names
This raises a very good systems question
I don't know Blockly needs to be fully converted, just easily co-operated with.
eg Something like an include file 'rosterboard/table' for any CORE on the chip you link to. (usually this is 8, but it seems 2,3,4 dice here is actually just a bigger form)
What file needs to be downloaded-once eg 5 cores may enter the same file name, and a can-single-build project would have a single download file.
*Size & Where it goes if not already in file
*HUB resource it expects as own : Address and die#
*Interface rules : Named variables and FIFOs : address and die#
that becomes like a poor mans linker, you co-operate on the big resource pieces.
It seems to have picked up where PowerBASIC left off after the death of Bob Zale.
The problem is that we are stuck with the stigma of line numbers and GOTOs, resulting in spaghetti code due to ignorance.
Today I use:
QuickBASIC
PowerBASIC
RFO BASIC (Android interpreter)
B4A (BASIC for Android compiler)
Micromite
Bypic (BASIC/C hybrid)
PropBasic
The only GOTO that I have ever used is with PropBasic because it translates directly to jmp.
After 33 years of using this language which resulted in a 80-employee business, other programmers still attempt to ridicule my choice of programming language.
If I was using slow, clunky Python, I would be totally cool.
For me, PropBasic is high level PASM with a BASIC-like syntax.
Over in AVR land, someone was asking about his customer who was asking about adding a BASIC script, into their existing 'plc like' custom controller based on a MegaAVR and project developed in C.
Does not sound like cheap plant or equipment.
No one said the customer was nuts, they focused on what Basic's are out there, to allow a small interpreter.
Choices are to patch-in almost any assembler/binary BASIC and use that, or another path is to use Basic generates C, and then their C project links-in that.
One path is RAM limited, needs to be reloaded on power, and not easily tested without consuming costly plant, the other is flash limited, stays there over power cycles, but can be tested away from plant.
FreeBASIC shows code generation backends for gas|gcc|llvm - not sure how much road tested / proven those are
(Did someone mention a LLVM player in P2 ?
There is actually quite a large catchment of people exactly like this guys customer.
Someone whose day-job is not programming, but who needs to be able to code-together 'plc like' plant, resulting in systems that run some portion as BASIC like
The P2 actually makes that question simpler in many ways : you could give one CORE to the customer as a sandbox, with rules on HUB resource, whilst doing product-engine-room work, in the other 7 CORES.
They support more than just PICs now and you get a ton of extra features.