Since the operators are pretty much nailed down, I was able to code them up, along with their EXECF tables for use with the fast bytecode executor (XBYTE). I've got the random memory R/W, the constants, and the unary and binary operators in there, and I've used a little over 1/4th of the cog's total memory. That's good, because I think I have about half the interpreter written now. At least, all the big stuff is done. Next comes all the housekeeping details.
Here it is, so far. It doesn't run, yet, but contains the major sections so I can assemble it and check the size:
''' Bytecode lookup constants'CON offset_byte = %110 << 10'SKIPF patterns for mem_rw
offset_word = %101 << 10
offset_long = %011 << 10
base_pbase = %110 << 13
base_vbase = %101 << 13
base_dbase = %011 << 13
read_byte = %0000_0110_1111 << 16
read_byte_indx = %0000_0110_0110 << 16
read_word = %0000_0101_1111 << 16
read_word_indx = %0000_0101_0100 << 16
read_long = %0000_0011_1111 << 16
read_long_indx = %0000_0011_0010 << 16
write_byte = %0000_1111_1111 << 16
write_byte_indx = %0000_1111_0110 << 16
write_word = %0010_1111_1111 << 16
write_word_indx = %0010_1111_0100 << 16
write_long = %0110_1111_1111 << 16
write_long_indx = %0110_1111_0010 << 16DATorg''' Memory read/write'
mem_rw rfbyte m 'ob | | offsetrfword m '| ow |rflong m '| | oladd m,pbase 'bp | | baseadd m,vbase '| bv |add m,dbase '| | bdpopa y '| ib iw il indexshl y,#1'| | iw |shl y,#2'| | | iladd m,y '| ib iw ilrdbyte y,m 'rb | | readrdword y,m '| rw |rdlong y,m '| | rl_ret_pusha y 'rb rw rlpopa y 'wb ww wl write_ret_wrbyte y,m 'wb | |_ret_wrword y,m ' ww |_ret_wrlong y,m ' wl''' Constants'
con_low pusha x 'push a b c d e f g a: 0_ret_mov x,#0' a | | | | | | b: 1_ret_mov x,#1' b | | | | | c: 2_ret_mov x,#2' c | | | | d: 3_ret_mov x,#3' d | | | e: 4_ret_mov x,#4' e | | f: 5_ret_mov x,#5' f | g: 6_ret_mov x,#6' g
con_high pusha x 'push a b c d e f g a: 7_ret_mov x,#7' a | | | | | | b: 8_ret_mov x,#8' b | | | | | c: 15_ret_mov x,#15' c | | | | d: 16_ret_mov x,#16' d | | | e: 31_ret_mov x,#31' e | | f: 32_ret_mov x,#32' f | g: -1_ret_mov x,_FFFFFFFF ' g
con_data pusha x 'push a b c d e f g h i a: byte_ret_rfbyte x ' a | | | | | | | | b: !byterfbyte x ' b | | | f g h i c: word_ret_rfword x ' | c | | | | | | d: !wordrfword x ' | d | | | | | e: long_ret_rflong x ' | | e | | | | f: byte + decode_ret_decod x ' | | f | | | g: byte + decode + notdecod x ' | | g h i h: byte + decode + decrement_ret_not x ' b d g | | i: byte + decode + negate_ret_sub x,#1' h |_ret_neg x ' i''' Math operators'
op_notb test x wz'NOT_ret_muxz x,_FFFFFFFF
op_not _ret_not x '!
op_neg _ret_neg x '-
op_abs _ret_abs x 'ABS
op_ncod _ret_ topone x 'NCOD
op_dcod _ret_decod x 'DCOD
op_sqrt qsqrt x,#0' a a: SQRT
op_log2 qlog x ' | b b: LOG2
op_exp2 qexp x ' | | c c: EXP2_ret_getqx x ' a b c
op_shift mov y,x 'swap a b c d e f a: >>popa x 'pop a b c d e f b: <<_ret_shr x,y ' a | | | | | c: SAR_ret_shl x,y ' b | | | | d: ROR_ret_sar x,y ' c | | | e: ROL_ret_ror x,y ' d | | f: REV_ret_rol x,y ' e |rev x ' frol x,y ' frol x,#1' f_ret_ triml x,y ' f
op_logic popa y wz'pop a b c d e f a: ANDmuxnz y,_FFFFFFFF ' a b c | | | b: XORtest x wz' a b c | | | c: ORmuxnz x,_FFFFFFFF ' a b c | | | d: &_ret_and x,y ' a | | d | | e: ^_ret_xor x,y ' b | e | f: |_ret_or x,y ' c f
op_muldiv popa y wc'pop a b c d e a: *testb x,#31wz'c=ys a b c | | b: /abs y '!z=xs a b c | | c: MODabs x ' a b c | | d: SCALqmul y,x ' a | | d | e: FRACqdiv y,x ' | b c | |qfrac y,x ' | | | | egetqx x ' a b | | eif_c_eq_zneg x ' a b | | |getqy x ' | | c d |if_cneg x ' | | c | |ret' a b c d e
op_addsub mov y,x 'swap a b c d e a: +popa x 'pop a b c d e b: -_ret_add x,y ' a | | | | c: #>_ret_sub x,y ' b | | | d: <#_ret_ mins x,y ' c | | e: SIGNX_ret_ maxs x,y ' d |not y ' eshl x,y ' e_ret_sar x,y ' e
op_equal popa y 'pop a b c d e f a: <cmps y,x wc,wz' a | c d e | b: <=cmps x,y wc,wz' | b | | | f c: ==_ret_muxc x,_FFFFFFFF ' a | | | | f d: <>_ret_muxnc x,_FFFFFFFF ' b | | e e: >=_ret_muxz x,_FFFFFFFF ' c | f: >_ret_muxnz x,_FFFFFFFF ' d''' Data'
_FFFFFFFF long$FFFFFFFF
x res1
y res1
m res1
pbase res1
vbase res1
dbase res1''' Bytecode lookup table'org$200'lut space
table
long mem_rw |offset_byte|base_pbase|read_byte
long mem_rw |offset_word|base_pbase|read_byte
long mem_rw |offset_long|base_pbase|read_byte
long mem_rw |offset_byte|base_vbase|read_byte
long mem_rw |offset_word|base_vbase|read_byte
long mem_rw |offset_long|base_vbase|read_byte
long mem_rw |offset_byte|base_dbase|read_byte
long mem_rw |offset_word|base_dbase|read_byte
long mem_rw |offset_long|base_dbase|read_byte
long mem_rw |offset_byte|base_pbase|read_byte_indx
long mem_rw |offset_word|base_pbase|read_byte_indx
long mem_rw |offset_long|base_pbase|read_byte_indx
long mem_rw |offset_byte|base_vbase|read_byte_indx
long mem_rw |offset_word|base_vbase|read_byte_indx
long mem_rw |offset_long|base_vbase|read_byte_indx
long mem_rw |offset_byte|base_dbase|read_byte_indx
long mem_rw |offset_word|base_dbase|read_byte_indx
long mem_rw |offset_long|base_dbase|read_byte_indx
long mem_rw |offset_byte|base_pbase|read_word
long mem_rw |offset_word|base_pbase|read_word
long mem_rw |offset_long|base_pbase|read_word
long mem_rw |offset_byte|base_vbase|read_word
long mem_rw |offset_word|base_vbase|read_word
long mem_rw |offset_long|base_vbase|read_word
long mem_rw |offset_byte|base_dbase|read_word
long mem_rw |offset_word|base_dbase|read_word
long mem_rw |offset_long|base_dbase|read_word
long mem_rw |offset_byte|base_pbase|read_word_indx
long mem_rw |offset_word|base_pbase|read_word_indx
long mem_rw |offset_long|base_pbase|read_word_indx
long mem_rw |offset_byte|base_vbase|read_word_indx
long mem_rw |offset_word|base_vbase|read_word_indx
long mem_rw |offset_long|base_vbase|read_word_indx
long mem_rw |offset_byte|base_dbase|read_word_indx
long mem_rw |offset_word|base_dbase|read_word_indx
long mem_rw |offset_long|base_dbase|read_word_indx
long mem_rw |offset_byte|base_pbase|read_long
long mem_rw |offset_word|base_pbase|read_long
long mem_rw |offset_long|base_pbase|read_long
long mem_rw |offset_byte|base_vbase|read_long
long mem_rw |offset_word|base_vbase|read_long
long mem_rw |offset_long|base_vbase|read_long
long mem_rw |offset_byte|base_dbase|read_long
long mem_rw |offset_word|base_dbase|read_long
long mem_rw |offset_long|base_dbase|read_long
long mem_rw |offset_byte|base_pbase|read_long_indx
long mem_rw |offset_word|base_pbase|read_long_indx
long mem_rw |offset_long|base_pbase|read_long_indx
long mem_rw |offset_byte|base_vbase|read_long_indx
long mem_rw |offset_word|base_vbase|read_long_indx
long mem_rw |offset_long|base_vbase|read_long_indx
long mem_rw |offset_byte|base_dbase|read_long_indx
long mem_rw |offset_word|base_dbase|read_long_indx
long mem_rw |offset_long|base_dbase|read_long_indx
long mem_rw |offset_byte|base_pbase|write_byte
long mem_rw |offset_word|base_pbase|write_byte
long mem_rw |offset_long|base_pbase|write_byte
long mem_rw |offset_byte|base_vbase|write_byte
long mem_rw |offset_word|base_vbase|write_byte
long mem_rw |offset_long|base_vbase|write_byte
long mem_rw |offset_byte|base_dbase|write_byte
long mem_rw |offset_word|base_dbase|write_byte
long mem_rw |offset_long|base_dbase|write_byte
long mem_rw |offset_byte|base_pbase|write_byte_indx
long mem_rw |offset_word|base_pbase|write_byte_indx
long mem_rw |offset_long|base_pbase|write_byte_indx
long mem_rw |offset_byte|base_vbase|write_byte_indx
long mem_rw |offset_word|base_vbase|write_byte_indx
long mem_rw |offset_long|base_vbase|write_byte_indx
long mem_rw |offset_byte|base_dbase|write_byte_indx
long mem_rw |offset_word|base_dbase|write_byte_indx
long mem_rw |offset_long|base_dbase|write_byte_indx
long mem_rw |offset_byte|base_pbase|write_word
long mem_rw |offset_word|base_pbase|write_word
long mem_rw |offset_long|base_pbase|write_word
long mem_rw |offset_byte|base_vbase|write_word
long mem_rw |offset_word|base_vbase|write_word
long mem_rw |offset_long|base_vbase|write_word
long mem_rw |offset_byte|base_dbase|write_word
long mem_rw |offset_word|base_dbase|write_word
long mem_rw |offset_long|base_dbase|write_word
long mem_rw |offset_byte|base_pbase|write_word_indx
long mem_rw |offset_word|base_pbase|write_word_indx
long mem_rw |offset_long|base_pbase|write_word_indx
long mem_rw |offset_byte|base_vbase|write_word_indx
long mem_rw |offset_word|base_vbase|write_word_indx
long mem_rw |offset_long|base_vbase|write_word_indx
long mem_rw |offset_byte|base_dbase|write_word_indx
long mem_rw |offset_word|base_dbase|write_word_indx
long mem_rw |offset_long|base_dbase|write_word_indx
long mem_rw |offset_byte|base_pbase|write_long
long mem_rw |offset_word|base_pbase|write_long
long mem_rw |offset_long|base_pbase|write_long
long mem_rw |offset_byte|base_vbase|write_long
long mem_rw |offset_word|base_vbase|write_long
long mem_rw |offset_long|base_vbase|write_long
long mem_rw |offset_byte|base_dbase|write_long
long mem_rw |offset_word|base_dbase|write_long
long mem_rw |offset_long|base_dbase|write_long
long mem_rw |offset_byte|base_pbase|write_long_indx
long mem_rw |offset_word|base_pbase|write_long_indx
long mem_rw |offset_long|base_pbase|write_long_indx
long mem_rw |offset_byte|base_vbase|write_long_indx
long mem_rw |offset_word|base_vbase|write_long_indx
long mem_rw |offset_long|base_vbase|write_long_indx
long mem_rw |offset_byte|base_dbase|write_long_indx
long mem_rw |offset_word|base_dbase|write_long_indx
long mem_rw |offset_long|base_dbase|write_long_indx
long con_low | %00 << 10'constant 0long con_low | %010 << 10'constant 1long con_low | %0110 << 10'constant 2long con_low | %01110 << 10'constant 3long con_low | %011110 << 10'constant 4long con_low | %0111110 << 10'constant 5long con_low | %01111110 << 10'constant 6long con_high | %00 << 10'constant 7long con_high | %010 << 10'constant 8long con_high | %0110 << 10'constant 15long con_high | %01110 << 10'constant 16long con_high | %011110 << 10'constant 31long con_high | %0111110 << 10'constant 32long con_high | %01111110 << 10'constant -1long con_data | %00 << 10'constant bytelong con_data | %011111010 << 10'constant byte!long con_data | %0110 << 10'constant wordlong con_data | %011101110 << 10'constant word!long con_data | %011110 << 10'constant longlong con_data | %0111010 << 10'constant byte+decodelong con_data | %001111010 << 10'constant byte+decode+notlong con_data | %0101111010 << 10'constant byte+decode+declong con_data | %01101111010 << 10'constant byte+decode+neglong op_notb 'operator unary NOTlong op_not 'operator unary !long op_neg 'operator unary -long op_abs 'operator unary ABSlong op_ncod 'operator unary NCODlong op_dcod 'operator unary DCODlong op_sqrt | %0110 << 10'operator unary SQRTlong op_log2 | %010 << 10'operator unary LOG2long op_exp2 | %00 << 10'operator unary EXP2long op_shift | %000 << 10'operator binary >>long op_shift | %0100 << 10'operator binary <<long op_shift | %01100 << 10'operator binary SARlong op_shift | %011100 << 10'operator binary RORlong op_shift | %0111100 << 10'operator binary ROLlong op_shift | %00001111100 << 10'operator binary REVlong op_addsub | %000111100 << 10'operator binary SIGNXlong op_logic | %00000 << 10'operator binary ANDlong op_logic | %010000 << 10'operator binary XORlong op_logic | %0110000 << 10'operator binary ORlong op_logic | %01110 << 10'operator binary &long op_logic | %011110 << 10'operator binary ^long op_logic | %0111110 << 10'operator binary |long op_muldiv | %011001100000 << 10'operator binary *long op_muldiv | %011001010000 << 10'operator binary /long op_muldiv | %000111010000 << 10'operator binary MODlong op_muldiv | %010111101110 << 10'operator binary SCALlong op_muldiv | %011100111110 << 10'operator binary FRAClong op_addsub | %000 << 10'operator binary +long op_addsub | %0100 << 10'operator binary -long op_addsub | %01100 << 10'operator binary #>long op_addsub | %011100 << 10'operator binary <#long op_equal | %0100 << 10'operator binary <long op_equal | %01010 << 10'operator binary <=long op_equal | %011100 << 10'operator binary ==long op_equal | %0111100 << 10'operator binary <>long op_equal | %01100 << 10'operator binary >=long op_equal | %0010 << 10'operator binary >
Tomorrow, I'll add the XBYTE stuff in and execute some bytecodes on I/O pins to see how the speed compares to Prop1. With this new setup of XBYTE, which includes EXECF, there's about zero clock cycles wasted on anything. It's all business. I'm anxious to see what it does.
Tomorrow, I'll add the XBYTE stuff in and execute some bytecodes on I/O pins to see how the speed compares to Prop1. With this new setup of XBYTE, which includes EXECF, there's about zero clock cycles wasted on anything. It's all business. I'm anxious to see what it does.
Tomorrow, I'll add the XBYTE stuff in and execute some bytecodes on I/O pins to see how the speed compares to Prop1. With this new setup of XBYTE, which includes EXECF, there's about zero clock cycles wasted on anything. It's all business. I'm anxious to see what it does.
Since the operators are pretty much nailed down, I was able to code them up, along with their EXECF tables for use with the fast bytecode executor (XBYTE). I've got the random memory R/W, the constants, and the unary and binary operators in there, and I've used a little over 1/4th of the cog's total memory. That's good, because I think I have about half the interpreter written now. At least, all the big stuff is done. Next comes all the housekeeping details.
If this comes in compact, is there room to add
? Scaled operator, that does (32b*32b/32b), with a 64b intermediate result, and maybe returns remainder too.
? Boolean Types, as the P2 now has bit-level instructions ?
? Floating point
Since the operators are pretty much nailed down, I was able to code them up, along with their EXECF tables for use with the fast bytecode executor (XBYTE). I've got the random memory R/W, the constants, and the unary and binary operators in there, and I've used a little over 1/4th of the cog's total memory. That's good, because I think I have about half the interpreter written now. At least, all the big stuff is done. Next comes all the housekeeping details.
If this comes in compact, is there room to add
? Scaled operator, that does (32b*32b/32b), with a 64b intermediate result, and maybe returns remainder too.
? Boolean Types, as the P2 now has bit-level instructions ?
? Floating point
The floating point is the only thing that would take much code to realize. Adding types, though, would complicate the language quite a bit.
Since the operators are pretty much nailed down, I was able to code them up, along with their EXECF tables for use with the fast bytecode executor (XBYTE). I've got the random memory R/W, the constants, and the unary and binary operators in there, and I've used a little over 1/4th of the cog's total memory. That's good, because I think I have about half the interpreter written now. At least, all the big stuff is done. Next comes all the housekeeping details.
If this comes in compact, is there room to add
? Scaled operator, that does (32b*32b/32b), with a 64b intermediate result, and maybe returns remainder too.
? Boolean Types, as the P2 now has bit-level instructions ?
? Floating point
The floating point is the only thing that would take much code to realize. Adding types, though, would complicate the language quite a bit.
I think that floating point should have a built-in support. Perhaps the routines can execute from LUT or hubexec if there is no space in the cog memory. Perhaps the compiler could add the code only if used in the hub.
But it would be nice to avoid the syntax that is now forced by the float32 object in favour of clean expressions used with integers.
Since the operators are pretty much nailed down, I was able to code them up, along with their EXECF tables for use with the fast bytecode executor (XBYTE). I've got the random memory R/W, the constants, and the unary and binary operators in there, and I've used a little over 1/4th of the cog's total memory. That's good, because I think I have about half the interpreter written now. At least, all the big stuff is done. Next comes all the housekeeping details.
If this comes in compact, is there room to add
? Scaled operator, that does (32b*32b/32b), with a 64b intermediate result, and maybe returns remainder too.
? Boolean Types, as the P2 now has bit-level instructions ?
? Floating point
The floating point is the only thing that would take much code to realize. Adding types, though, would complicate the language quite a bit.
I think that floating point should have a built-in support. Perhaps the routines can execute from LUT or hubexec if there is no space in the cog memory. Perhaps the compiler could add the code only if used in the hub.
But it would be nice to avoid the syntax that is now forced by the float32 object in favour of clean expressions used with integers.
I agree. This will take some thought, since we don't yet have variable types beyond byte/word/long/register.
As a start point you could introduce a FLOAT or REAL type but I think it is enough to just introduce a few more operators/bytecodes:
*R x *R y x *R= y binary 7, 16 Real Multiply
/R x /R y x /R= y binary 7, 16 Real Divide
+R x +R y x +R= y binary 8, 16Add
-R x -R y x -R= y binary 8, 16 Subtract
If you have dedicated math operators for floating numbers than you do not need to identify variable types, the operator will expect the right type
And a few conversion functions more:
ITR Integer To Real
RTI Real to Integer
As a start point you could introduce a FLOAT or REAL type but I think it is enough to just introduce a few more operators/bytecodes:
*R x *R y x *R= y binary 7, 16 Real Multiply
/R x /R y x /R= y binary 7, 16 Real Divide
+R x +R y x +R= y binary 8, 16Add
-R x -R y x -R= y binary 8, 16 Subtract
If you have dedicated math operators for floating numbers than you do not need to identify variable types, the operator will expect the right type
And a few conversion functions more:
ITR Integer To Real
RTI Real to Integer
Yes! That's way simpler, for sure. Good thinking! That eliminates all the contextual issues. Wow!
Worth mentioning that only the compiler itself is required to know types, and you could set the syntax up such that leaving out the type implies an integer, so it'd still be somewhat noob friendly. It does complicate the implementation, but the resulting code would be FAR easier to read than having R's littered all over your equations.
We would have to have R operators for the following, at least:
==r
<>r
>=r
<=r
>r
<r
*r
/r
%r
+r
-r
maybe a dot, instead of an R:
==.
<>.
>=.
<=.
>.
<.
*.
/.
%.
+.
-.
That doesn't stand out too much, almost gets lost, but is easier to read. I thought about putting the dot on the front, but that would cause parsing problems.
Worth mentioning that only the compiler itself is required to know types, and you could set the syntax up such that leaving out the type implies an integer, so it'd still be somewhat noob friendly. It does complicate the implementation, but the resulting code would be FAR easier to read than having R's littered all over your equations.
I agree, R's is a total kludge.
If there is a lot of work for Reals, this could be shifted to when P2 is in the FAB flows.
There is enough test coverage in P2 Spin already to be useful.
C/C++ for P2 should also be functional before P2 final signoff.
Having r's in there is also going to pooch the parser. It won't be legal any more to use if x>=result, for example, because that could parse to >=r esult, or >= result. There's a reason most operators don't use any legal label character. That said, I agree with JMG - this is the kind of thing that can be added later and it won't affect silicon. Get V1.0 out the door and then start complicating it.
@Chip
%(MOD) is not needed because the result of float division is a floating number. the result will eventually be converted to integer and the fractional part be lost.
BTW: yes, i've forgot the equity operators, these also needs R
PS: R is clearer than dot
@All
The idea of R comes from PLCs where floating point math is supported but operands cannot be mixed, they must be of the same type and the type is determined by the operator
L 1.0e1//real
L 5.0e0//real
+R
T destination //real (1.5e1)
L 10//integer
ITR // conversion
L 5.0e0//real
+R
T destination //real (1.5e1)
L 10//integer
ITR //conversion
L 5.0e0//real
+R
RTI //conversion
T destination //integer (15)
1. I still prefer the R operators rather than the actual float32 object syntax
2. I will still prefer R if the "autodetection" means variable type declaration (I am not against it) which complicates the interpreter and forces the move of floating point and other routines to hubexec rather than cogexec which will increase execution times.
Perhaps CORDIC engine can be used, I've read something about doing float-math with CORDIC with +/- 1/16777216 precision.
Ugh, I hate the idea of another set of operators with the R or dot tagged on for float operations.
I think it's cleaner and probably easier in the long run to just add the FLOAT var type.
The issue then becomes locals and params (which currently are always LONGs) would need to be able to have type tags (which we have already talked about wanting/needing for structs). I think that's easier that this operator junk (so gross).
How hard would it be to declare a block of variables as "real" and let the compiler handle the choice of operator while we use the standard math symbols in the source. Something like:
[code]
declare real
var1
var2
var3
.
.
.
var3 := var1 + var2
How hard would it be to declare a block of variables as "real" and let the compiler handle the choice of operator while we use the standard math symbols in the source.
That is certainly possible, as other Compilers can do that, however Chip said above P2Spin supports just 4 types now :
"This will take some thought, since we don't yet have variable types beyond byte/word/long/register."
So far I have not needed floats with the Propeller but that may be due to the type and small number of projects I have done, so I am more or less neutral to the idea. I do think that not having floats in Spin while they are available in C will be a disincentive for anyone not already familiar with Spin to learn it.
The 0.001% left don't understand that they don't need floats.
There are some rare people working with kalman filters or quaternions that probably do need floats, and know how they work.
I don't know. Either you have to add types to Spin. Which makes the whole language a lot more complex. Or you have to add weird float operators, which is an ugly kludge.
Spent about 45 minutes on this, writing some stuff, gave up.
Spin is too tied to the actual assembly instructions to do anything abstract like floating point.
To deal with floats, the spin interpreter would need a context switch to something like a 64-bit accumulator and only have a small subset of the operators be legal (++, --, +-*/, ABS, negate(-), etc.) but definitely no rotation, and no left and right shifts unless it was by 10's which would be awesomely bizarre.
The reason you'd want a 64-bit float accumulator is because it could hold an exact copy of every value of a 32-bit long signed integer, which is what would be converted back when going from float->long. To convert to an unsigned long would require a specific type coercion operator.
The reason you'd want a 64-bit float accumulator is because it could hold an exact copy of every value of a 32-bit long signed integer, which is what would be converted back when going from float->long. To convert to an unsigned long would require a specific type coercion operator.
I'm not sure where you are going with that but that is just what Javascript does. In JS all numbers are 64 bit floats, but it knows how to handle them as 32 bit ints.
Operators like "+", "-", "*", "/", etc work as if the numbers were floats.
Bitwise operators treat the numbers as 32 bit ints.
It's kind of weird but it has the magical result that you can compile C code to Javascript and have it run pretty damn quick.
Comments
AUGS can be used to either provide a 20-bit constant address, or invoke PTRA/PTRB with a 20-bit unscaled index:
#s 00000000000000000000000_0aaaaaaaa = hub address $00000..$000FF #s 00000000000000000000000_1supiiiii = hub address PTRA/PTRB with 5-bit scaled index #s+augs xxxxxxxxxxxxaaaaaaaaaaa_aaaaaaaaa = hub address $00000..$FFFFF (x != 000000001???) #s+augs 000000001supiiiiiiiiiii_iiiiiiiii = hub address PTRA/PTRB with 20-bit unscaled index
I'm recompiling now. It's going to take 8 hours to get all the FPGA images done, with a lot of interstitial monkey motion.
I think the other thing that we need to nail down is how to interoperate between bytecodes and PASM. But I'll start a new thread for that.
Eric
Here it is, so far. It doesn't run, yet, but contains the major sections so I can assemble it and check the size:
' ' ' Bytecode lookup constants ' CON offset_byte = %110 << 10 'SKIPF patterns for mem_rw offset_word = %101 << 10 offset_long = %011 << 10 base_pbase = %110 << 13 base_vbase = %101 << 13 base_dbase = %011 << 13 read_byte = %0000_0110_1111 << 16 read_byte_indx = %0000_0110_0110 << 16 read_word = %0000_0101_1111 << 16 read_word_indx = %0000_0101_0100 << 16 read_long = %0000_0011_1111 << 16 read_long_indx = %0000_0011_0010 << 16 write_byte = %0000_1111_1111 << 16 write_byte_indx = %0000_1111_0110 << 16 write_word = %0010_1111_1111 << 16 write_word_indx = %0010_1111_0100 << 16 write_long = %0110_1111_1111 << 16 write_long_indx = %0110_1111_0010 << 16 DAT org ' ' ' Memory read/write ' mem_rw rfbyte m 'ob | | offset rfword m '| ow | rflong m '| | ol add m,pbase 'bp | | base add m,vbase '| bv | add m,dbase '| | bd popa y '| ib iw il index shl y,#1 '| | iw | shl y,#2 '| | | il add m,y '| ib iw il rdbyte y,m 'rb | | read rdword y,m '| rw | rdlong y,m '| | rl _ret_ pusha y 'rb rw rl popa y 'wb ww wl write _ret_ wrbyte y,m 'wb | | _ret_ wrword y,m ' ww | _ret_ wrlong y,m ' wl ' ' ' Constants ' con_low pusha x 'push a b c d e f g a: 0 _ret_ mov x,#0 ' a | | | | | | b: 1 _ret_ mov x,#1 ' b | | | | | c: 2 _ret_ mov x,#2 ' c | | | | d: 3 _ret_ mov x,#3 ' d | | | e: 4 _ret_ mov x,#4 ' e | | f: 5 _ret_ mov x,#5 ' f | g: 6 _ret_ mov x,#6 ' g con_high pusha x 'push a b c d e f g a: 7 _ret_ mov x,#7 ' a | | | | | | b: 8 _ret_ mov x,#8 ' b | | | | | c: 15 _ret_ mov x,#15 ' c | | | | d: 16 _ret_ mov x,#16 ' d | | | e: 31 _ret_ mov x,#31 ' e | | f: 32 _ret_ mov x,#32 ' f | g: -1 _ret_ mov x,_FFFFFFFF ' g con_data pusha x 'push a b c d e f g h i a: byte _ret_ rfbyte x ' a | | | | | | | | b: !byte rfbyte x ' b | | | f g h i c: word _ret_ rfword x ' | c | | | | | | d: !word rfword x ' | d | | | | | e: long _ret_ rflong x ' | | e | | | | f: byte + decode _ret_ decod x ' | | f | | | g: byte + decode + not decod x ' | | g h i h: byte + decode + decrement _ret_ not x ' b d g | | i: byte + decode + negate _ret_ sub x,#1 ' h | _ret_ neg x ' i ' ' ' Math operators ' op_notb test x wz 'NOT _ret_ muxz x,_FFFFFFFF op_not _ret_ not x '! op_neg _ret_ neg x '- op_abs _ret_ abs x 'ABS op_ncod _ret_ topone x 'NCOD op_dcod _ret_ decod x 'DCOD op_sqrt qsqrt x,#0 ' a a: SQRT op_log2 qlog x ' | b b: LOG2 op_exp2 qexp x ' | | c c: EXP2 _ret_ getqx x ' a b c op_shift mov y,x 'swap a b c d e f a: >> popa x 'pop a b c d e f b: << _ret_ shr x,y ' a | | | | | c: SAR _ret_ shl x,y ' b | | | | d: ROR _ret_ sar x,y ' c | | | e: ROL _ret_ ror x,y ' d | | f: REV _ret_ rol x,y ' e | rev x ' f rol x,y ' f rol x,#1 ' f _ret_ triml x,y ' f op_logic popa y wz 'pop a b c d e f a: AND muxnz y,_FFFFFFFF ' a b c | | | b: XOR test x wz ' a b c | | | c: OR muxnz x,_FFFFFFFF ' a b c | | | d: & _ret_ and x,y ' a | | d | | e: ^ _ret_ xor x,y ' b | e | f: | _ret_ or x,y ' c f op_muldiv popa y wc 'pop a b c d e a: * testb x,#31 wz 'c=ys a b c | | b: / abs y '!z=xs a b c | | c: MOD abs x ' a b c | | d: SCAL qmul y,x ' a | | d | e: FRAC qdiv y,x ' | b c | | qfrac y,x ' | | | | e getqx x ' a b | | e if_c_eq_z neg x ' a b | | | getqy x ' | | c d | if_c neg x ' | | c | | ret ' a b c d e op_addsub mov y,x 'swap a b c d e a: + popa x 'pop a b c d e b: - _ret_ add x,y ' a | | | | c: #> _ret_ sub x,y ' b | | | d: <# _ret_ mins x,y ' c | | e: SIGNX _ret_ maxs x,y ' d | not y ' e shl x,y ' e _ret_ sar x,y ' e op_equal popa y 'pop a b c d e f a: < cmps y,x wc,wz ' a | c d e | b: <= cmps x,y wc,wz ' | b | | | f c: == _ret_ muxc x,_FFFFFFFF ' a | | | | f d: <> _ret_ muxnc x,_FFFFFFFF ' b | | e e: >= _ret_ muxz x,_FFFFFFFF ' c | f: > _ret_ muxnz x,_FFFFFFFF ' d ' ' ' Data ' _FFFFFFFF long $FFFFFFFF x res 1 y res 1 m res 1 pbase res 1 vbase res 1 dbase res 1 ' ' ' Bytecode lookup table ' org $200 'lut space table long mem_rw |offset_byte|base_pbase|read_byte long mem_rw |offset_word|base_pbase|read_byte long mem_rw |offset_long|base_pbase|read_byte long mem_rw |offset_byte|base_vbase|read_byte long mem_rw |offset_word|base_vbase|read_byte long mem_rw |offset_long|base_vbase|read_byte long mem_rw |offset_byte|base_dbase|read_byte long mem_rw |offset_word|base_dbase|read_byte long mem_rw |offset_long|base_dbase|read_byte long mem_rw |offset_byte|base_pbase|read_byte_indx long mem_rw |offset_word|base_pbase|read_byte_indx long mem_rw |offset_long|base_pbase|read_byte_indx long mem_rw |offset_byte|base_vbase|read_byte_indx long mem_rw |offset_word|base_vbase|read_byte_indx long mem_rw |offset_long|base_vbase|read_byte_indx long mem_rw |offset_byte|base_dbase|read_byte_indx long mem_rw |offset_word|base_dbase|read_byte_indx long mem_rw |offset_long|base_dbase|read_byte_indx long mem_rw |offset_byte|base_pbase|read_word long mem_rw |offset_word|base_pbase|read_word long mem_rw |offset_long|base_pbase|read_word long mem_rw |offset_byte|base_vbase|read_word long mem_rw |offset_word|base_vbase|read_word long mem_rw |offset_long|base_vbase|read_word long mem_rw |offset_byte|base_dbase|read_word long mem_rw |offset_word|base_dbase|read_word long mem_rw |offset_long|base_dbase|read_word long mem_rw |offset_byte|base_pbase|read_word_indx long mem_rw |offset_word|base_pbase|read_word_indx long mem_rw |offset_long|base_pbase|read_word_indx long mem_rw |offset_byte|base_vbase|read_word_indx long mem_rw |offset_word|base_vbase|read_word_indx long mem_rw |offset_long|base_vbase|read_word_indx long mem_rw |offset_byte|base_dbase|read_word_indx long mem_rw |offset_word|base_dbase|read_word_indx long mem_rw |offset_long|base_dbase|read_word_indx long mem_rw |offset_byte|base_pbase|read_long long mem_rw |offset_word|base_pbase|read_long long mem_rw |offset_long|base_pbase|read_long long mem_rw |offset_byte|base_vbase|read_long long mem_rw |offset_word|base_vbase|read_long long mem_rw |offset_long|base_vbase|read_long long mem_rw |offset_byte|base_dbase|read_long long mem_rw |offset_word|base_dbase|read_long long mem_rw |offset_long|base_dbase|read_long long mem_rw |offset_byte|base_pbase|read_long_indx long mem_rw |offset_word|base_pbase|read_long_indx long mem_rw |offset_long|base_pbase|read_long_indx long mem_rw |offset_byte|base_vbase|read_long_indx long mem_rw |offset_word|base_vbase|read_long_indx long mem_rw |offset_long|base_vbase|read_long_indx long mem_rw |offset_byte|base_dbase|read_long_indx long mem_rw |offset_word|base_dbase|read_long_indx long mem_rw |offset_long|base_dbase|read_long_indx long mem_rw |offset_byte|base_pbase|write_byte long mem_rw |offset_word|base_pbase|write_byte long mem_rw |offset_long|base_pbase|write_byte long mem_rw |offset_byte|base_vbase|write_byte long mem_rw |offset_word|base_vbase|write_byte long mem_rw |offset_long|base_vbase|write_byte long mem_rw |offset_byte|base_dbase|write_byte long mem_rw |offset_word|base_dbase|write_byte long mem_rw |offset_long|base_dbase|write_byte long mem_rw |offset_byte|base_pbase|write_byte_indx long mem_rw |offset_word|base_pbase|write_byte_indx long mem_rw |offset_long|base_pbase|write_byte_indx long mem_rw |offset_byte|base_vbase|write_byte_indx long mem_rw |offset_word|base_vbase|write_byte_indx long mem_rw |offset_long|base_vbase|write_byte_indx long mem_rw |offset_byte|base_dbase|write_byte_indx long mem_rw |offset_word|base_dbase|write_byte_indx long mem_rw |offset_long|base_dbase|write_byte_indx long mem_rw |offset_byte|base_pbase|write_word long mem_rw |offset_word|base_pbase|write_word long mem_rw |offset_long|base_pbase|write_word long mem_rw |offset_byte|base_vbase|write_word long mem_rw |offset_word|base_vbase|write_word long mem_rw |offset_long|base_vbase|write_word long mem_rw |offset_byte|base_dbase|write_word long mem_rw |offset_word|base_dbase|write_word long mem_rw |offset_long|base_dbase|write_word long mem_rw |offset_byte|base_pbase|write_word_indx long mem_rw |offset_word|base_pbase|write_word_indx long mem_rw |offset_long|base_pbase|write_word_indx long mem_rw |offset_byte|base_vbase|write_word_indx long mem_rw |offset_word|base_vbase|write_word_indx long mem_rw |offset_long|base_vbase|write_word_indx long mem_rw |offset_byte|base_dbase|write_word_indx long mem_rw |offset_word|base_dbase|write_word_indx long mem_rw |offset_long|base_dbase|write_word_indx long mem_rw |offset_byte|base_pbase|write_long long mem_rw |offset_word|base_pbase|write_long long mem_rw |offset_long|base_pbase|write_long long mem_rw |offset_byte|base_vbase|write_long long mem_rw |offset_word|base_vbase|write_long long mem_rw |offset_long|base_vbase|write_long long mem_rw |offset_byte|base_dbase|write_long long mem_rw |offset_word|base_dbase|write_long long mem_rw |offset_long|base_dbase|write_long long mem_rw |offset_byte|base_pbase|write_long_indx long mem_rw |offset_word|base_pbase|write_long_indx long mem_rw |offset_long|base_pbase|write_long_indx long mem_rw |offset_byte|base_vbase|write_long_indx long mem_rw |offset_word|base_vbase|write_long_indx long mem_rw |offset_long|base_vbase|write_long_indx long mem_rw |offset_byte|base_dbase|write_long_indx long mem_rw |offset_word|base_dbase|write_long_indx long mem_rw |offset_long|base_dbase|write_long_indx long con_low | %00 << 10 'constant 0 long con_low | %010 << 10 'constant 1 long con_low | %0110 << 10 'constant 2 long con_low | %01110 << 10 'constant 3 long con_low | %011110 << 10 'constant 4 long con_low | %0111110 << 10 'constant 5 long con_low | %01111110 << 10 'constant 6 long con_high | %00 << 10 'constant 7 long con_high | %010 << 10 'constant 8 long con_high | %0110 << 10 'constant 15 long con_high | %01110 << 10 'constant 16 long con_high | %011110 << 10 'constant 31 long con_high | %0111110 << 10 'constant 32 long con_high | %01111110 << 10 'constant -1 long con_data | %00 << 10 'constant byte long con_data | %011111010 << 10 'constant byte! long con_data | %0110 << 10 'constant word long con_data | %011101110 << 10 'constant word! long con_data | %011110 << 10 'constant long long con_data | %0111010 << 10 'constant byte+decode long con_data | %001111010 << 10 'constant byte+decode+not long con_data | %0101111010 << 10 'constant byte+decode+dec long con_data | %01101111010 << 10 'constant byte+decode+neg long op_notb 'operator unary NOT long op_not 'operator unary ! long op_neg 'operator unary - long op_abs 'operator unary ABS long op_ncod 'operator unary NCOD long op_dcod 'operator unary DCOD long op_sqrt | %0110 << 10 'operator unary SQRT long op_log2 | %010 << 10 'operator unary LOG2 long op_exp2 | %00 << 10 'operator unary EXP2 long op_shift | %000 << 10 'operator binary >> long op_shift | %0100 << 10 'operator binary << long op_shift | %01100 << 10 'operator binary SAR long op_shift | %011100 << 10 'operator binary ROR long op_shift | %0111100 << 10 'operator binary ROL long op_shift | %00001111100 << 10 'operator binary REV long op_addsub | %000111100 << 10 'operator binary SIGNX long op_logic | %00000 << 10 'operator binary AND long op_logic | %010000 << 10 'operator binary XOR long op_logic | %0110000 << 10 'operator binary OR long op_logic | %01110 << 10 'operator binary & long op_logic | %011110 << 10 'operator binary ^ long op_logic | %0111110 << 10 'operator binary | long op_muldiv | %011001100000 << 10 'operator binary * long op_muldiv | %011001010000 << 10 'operator binary / long op_muldiv | %000111010000 << 10 'operator binary MOD long op_muldiv | %010111101110 << 10 'operator binary SCAL long op_muldiv | %011100111110 << 10 'operator binary FRAC long op_addsub | %000 << 10 'operator binary + long op_addsub | %0100 << 10 'operator binary - long op_addsub | %01100 << 10 'operator binary #> long op_addsub | %011100 << 10 'operator binary <# long op_equal | %0100 << 10 'operator binary < long op_equal | %01010 << 10 'operator binary <= long op_equal | %011100 << 10 'operator binary == long op_equal | %0111100 << 10 'operator binary <> long op_equal | %01100 << 10 'operator binary >= long op_equal | %0010 << 10 'operator binary >
Tomorrow, I'll add the XBYTE stuff in and execute some bytecodes on I/O pins to see how the speed compares to Prop1. With this new setup of XBYTE, which includes EXECF, there's about zero clock cycles wasted on anything. It's all business. I'm anxious to see what it does.
https://forums.parallax.com/discussion/comment/1407770/#Comment_1407770
Those are Prop1 numbers, of course. And I think a more comprehensive benchmark thread is:
http://forums.parallax.com/discussion/142803/some-multi-language-benchmarks/p1
? Scaled operator, that does (32b*32b/32b), with a 64b intermediate result, and maybe returns remainder too.
? Boolean Types, as the P2 now has bit-level instructions ?
? Floating point
The floating point is the only thing that would take much code to realize. Adding types, though, would complicate the language quite a bit.
I think that floating point should have a built-in support. Perhaps the routines can execute from LUT or hubexec if there is no space in the cog memory. Perhaps the compiler could add the code only if used in the hub.
But it would be nice to avoid the syntax that is now forced by the float32 object in favour of clean expressions used with integers.
I agree. This will take some thought, since we don't yet have variable types beyond byte/word/long/register.
*R x *R y x *R= y binary 7, 16 Real Multiply /R x /R y x /R= y binary 7, 16 Real Divide +R x +R y x +R= y binary 8, 16 Add -R x -R y x -R= y binary 8, 16 Subtract
If you have dedicated math operators for floating numbers than you do not need to identify variable types, the operator will expect the right typeAnd a few conversion functions more:
ITR Integer To Real
RTI Real to Integer
Yes! That's way simpler, for sure. Good thinking! That eliminates all the contextual issues. Wow!
==r
<>r
>=r
<=r
>r
<r
*r
/r
%r
+r
-r
maybe a dot, instead of an R:
==.
<>.
>=.
<=.
>.
<.
*.
/.
%.
+.
-.
That doesn't stand out too much, almost gets lost, but is easier to read. I thought about putting the dot on the front, but that would cause parsing problems.
Well, perhaps, but it screams kludge... and the exercise is to try to clean up Spin, not add ever-more-strange-operators...
Worse, if someone does use the wrong type, a system that has no type checking, gives no error message.
The risk of short term workarounds, is they tend to become entrenched and never get around to being properly fixed.
I agree, R's is a total kludge.
If there is a lot of work for Reals, this could be shifted to when P2 is in the FAB flows.
There is enough test coverage in P2 Spin already to be useful.
C/C++ for P2 should also be functional before P2 final signoff.
%(MOD) is not needed because the result of float division is a floating number. the result will eventually be converted to integer and the fractional part be lost.
BTW: yes, i've forgot the equity operators, these also needs R
PS: R is clearer than dot
@All
The idea of R comes from PLCs where floating point math is supported but operands cannot be mixed, they must be of the same type and the type is determined by the operator
L 1.0e1 //real L 5.0e0 //real +R T destination //real (1.5e1)
L 10 //integer ITR // conversion L 5.0e0 //real +R T destination //real (1.5e1)
L 10 //integer ITR //conversion L 5.0e0 //real +R RTI //conversion T destination //integer (15)
1. I still prefer the R operators rather than the actual float32 object syntax
2. I will still prefer R if the "autodetection" means variable type declaration (I am not against it) which complicates the interpreter and forces the move of floating point and other routines to hubexec rather than cogexec which will increase execution times.
Perhaps CORDIC engine can be used, I've read something about doing float-math with CORDIC with +/- 1/16777216 precision.
I think it's cleaner and probably easier in the long run to just add the FLOAT var type.
The issue then becomes locals and params (which currently are always LONGs) would need to be able to have type tags (which we have already talked about wanting/needing for structs). I think that's easier that this operator junk (so gross).
[code]
declare real
var1
var2
var3
.
.
.
var3 := var1 + var2
"This will take some thought, since we don't yet have variable types beyond byte/word/long/register."
So far I have not needed floats with the Propeller but that may be due to the type and small number of projects I have done, so I am more or less neutral to the idea. I do think that not having floats in Spin while they are available in C will be a disincentive for anyone not already familiar with Spin to learn it.
The 0.001% left don't understand that they don't need floats.
There are some rare people working with kalman filters or quaternions that probably do need floats, and know how they work.
I don't know. Either you have to add types to Spin. Which makes the whole language a lot more complex. Or you have to add weird float operators, which is an ugly kludge.
Spin is too tied to the actual assembly instructions to do anything abstract like floating point.
To deal with floats, the spin interpreter would need a context switch to something like a 64-bit accumulator and only have a small subset of the operators be legal (++, --, +-*/, ABS, negate(-), etc.) but definitely no rotation, and no left and right shifts unless it was by 10's which would be awesomely bizarre.
The reason you'd want a 64-bit float accumulator is because it could hold an exact copy of every value of a 32-bit long signed integer, which is what would be converted back when going from float->long. To convert to an unsigned long would require a specific type coercion operator.
Operators like "+", "-", "*", "/", etc work as if the numbers were floats.
Bitwise operators treat the numbers as 32 bit ints.
It's kind of weird but it has the magical result that you can compile C code to Javascript and have it run pretty damn quick.
Or, let's keep this SPIN simple and lean. It can be the native tool at some point.
Extend later.
I'm not sure about the "extend later" part. I can't see how it's possible without turning Spin into a pigs ear like C++.
But, my vision is limited.
Lots of users ready for that.
And I think they deserve that SPIN too. Should exist.