@ersmith said:
No, but you may be the first one to use a .h file instead of a .c file, or at least a function-only .h file. There's a compiler bug where the Spin object created for a .h file ends up with the wrong size if the variables are not declared in the .h (basically the object size is calculated too early, before all functions are resolved; since in B2M_Axes.h there are no variables, the Spin object is created with 0 bytes reserved for member variables).
This is actually going to be a tricky bug to fix, but in the current github source code there is at least a check for this and an error is printed.
Ah, good catch. So I think the main problem was that the "how to" is not clearly documented. I've only found the "Calling C standard library functions" section in the Spin manual but it doesn't say anything about .h vs. .c files. I have to admit that I don't really understand how header files work in C and especially with your compiler where those __fromfile declarations are necessary. Separating the interface from the implementation is basically a good idea. I always try to declare everything as local as possible to avoid unwanted accesses to internal variables (see "public" vs. "private" in C++ classes). That's why I declared the typedef AxisBuffEntry pulic (in the .h file) but the actual variable (memory) private (in the .c file).
But no inline assembler. And I think I would miss a source level debugger. I want my Oberon IDE back.
?
FlexBasic has the inline assembler. You can even write a driver in it. And then it has "print" which normally prints to the serial terminal but can be redirected to anything you want by simply reopen file channel #0. I used this to print to my HDMI driver.
Classes can be used as struct/union equivalent, both possible. And there is alias which can place 2 variables in one memory location (convenient for accessing int64 longs - I used it to have 8-bit access to 32-bit variable)
@JRoark said:
FlexBASIC supports assembly. I use it all the time. Check out _ASM and _ENDASM
I feel so stupid again. I searched for "_ASM" in the basic.pdf doc. No hit. There's an "asm" in the keyword section but no "endasm". "Inline assembler" is mentioned in both spin.pdf and c.pdf but not in basic.pdf. I don't want to guess and try out something blindly. We all see what can happen if we do this, above. Maybe there's something wrong with me. Call me pedantic but I expect at least the most common and essential features to be found in the documentation.
This is from Basic help called directly from Flexprop:
ASM
Introduces inline assembly. The block between asm and end asm is parsed slightly differently than usual; in particular, instruction names are treated as reserved identifiers. There are two kinds of asm blocks. A regular asm block introduces some assembly code to be executed when the block is reached. An asm shared block declares some assembly code and/or data that exists outside of any function. Such code is typically executed with a cpu directive. Another use for asm shared is to declare static data.
ASM
A normal ASM block specifies some code to be executed when the block is reached. If it is outside of any function or subroutine, then it Inside inline assembly any instructions may be used, but the only legal operands are integer constants, registers, and local variables (or parameters) to the function which contains the inline assembly. Labels may be defined, and may be used as the target for goto elsewhere in the function. Any attempt to leave the function, either by jumping out of it or returning, will cause undefined behavior. In other words, don't do that!
If you need temporary variables inside some inline assembly, dim them as locals in the enclosing function.
Example: to implement a wait (like the built-in waitcnt) on Propeller 1:
sub wait_until_cycle(x as uinteger)
asm
waitcnt x, #0
end asm
end sub
Example: to create a function that rotates an unsigned integer x left by y:
function rotleft(x as uinteger, y as uinteger)
asm
rol x, y
end asm
return x
end function
CONST ASM
If a const keyword appears before asm then the optimizer will leave untouched all code within the asm block. Normally this code is optimized along with the generated code, and this is usually what is desired, because often the compiler can make helpful changes like re-using registers for arguments and local variables. asm const should thus be avoided in general, but if there is some particular sequence that you need to have compiled exactly as-is, then you may use it.
CPU ASM
cpu asm is like const asm but as well as leaving the code unoptimized it will copy it to the internal FCACHE area (rather than executing it from HUB memory). This can be useful if precise timing is required for loops.
SHARED ASM
A shared asm block declares some static code and/or data which is not intended to be executed immediately, but may be invoked with cpu. In this respect it is like a Spin language DAT block.
The main difference between asm and shared asm is that the shared asm blocks are kept separate, outside of all functions and subroutines, whereas asm blocks are always part of a function or subroutine (or the main program). asm blocks are executed when control flow reaches them; code within shared asm must be explicitly invoked via cpu.
shared asm blocks, like const asm, are not optimized by the optimizer.
So you have full controll of your asm code. Yoiu can tell the compiler to place it in hub (normal way) inline, move it to a cog and then call or make a spin .dat equivalent using asm shared.
@ManAtWork Sorry. My bad. I keep switching between languages and I forgot FlexBASIC doesnt want that leading underscore.
But yeah, it is a nice feature to quickly deal with all the UI and string handling Smile in BASIC, and then drop down to the metal and wiggle bits. IMHO @ersmith and @Wuerfel_21 have really done a wonderful job with this compiler.
@ManAtWork said:
OK, thanks. It's in the "Alphabetical List of Keywords and Built In Functions" section.
I feel so old. I had a very bad week. I think I should go home and get myself a beer instead of complaining.
Dude, I remember the days, in your country, when factory floor vending machines served beer 👍😎👍
Those projects tended to take more time than necessary but we always solved the problem 😂🤣
The good news is that after Eric's fixes I see no more strange effects and all calculation results seem reasonable.
The bad news is that the 64 bit math is too slow. I've hoped that I can do the iterations through the motion profile buffer in almost pure C with only the Mul/Div functions in inline assembler. But with all the necessary shifts which are translated to call #__system___int64_shl and lots of call #pushregs_ and call #popregs_ a loop iteration takes ~3µs. My limit is 2µs. No big deal. I'll code the innermost loop in assembler.
Update: Yeah! I got it down to ~0.5µs per loop iteration. Pipelined CORDIC is the key. I can do all the shifts, pointer calculations and most of the other operations while waiting for the CORDIC which executes both multiplications overlapping..
I was chatting with my son the other day and I made the off-hand comment that a good assembly coder can drive a veritable bus between a pair of microseconds. He looked at me in complete disbelief. He’s a Python/server-guy, but after that discussion one of my x86 assembly books mysteriously disappeared. 👍
Comments
Ah, good catch. So I think the main problem was that the "how to" is not clearly documented. I've only found the "Calling C standard library functions" section in the Spin manual but it doesn't say anything about .h vs. .c files. I have to admit that I don't really understand how header files work in C and especially with your compiler where those __fromfile declarations are necessary. Separating the interface from the implementation is basically a good idea. I always try to declare everything as local as possible to avoid unwanted accesses to internal variables (see "public" vs. "private" in C++ classes). That's why I declared the typedef AxisBuffEntry pulic (in the .h file) but the actual variable (memory) private (in the .c file).
FlexBASIC supports assembly. I use it all the time. Check out _ASM and _ENDASM
?
FlexBasic has the inline assembler. You can even write a driver in it. And then it has "print" which normally prints to the serial terminal but can be redirected to anything you want by simply reopen file channel #0. I used this to print to my HDMI driver.
Classes can be used as struct/union equivalent, both possible. And there is alias which can place 2 variables in one memory location (convenient for accessing int64 longs - I used it to have 8-bit access to 32-bit variable)
I feel so stupid again. I searched for "_ASM" in the basic.pdf doc. No hit. There's an "asm" in the keyword section but no "endasm". "Inline assembler" is mentioned in both spin.pdf and c.pdf but not in basic.pdf. I don't want to guess and try out something blindly. We all see what can happen if we do this, above. Maybe there's something wrong with me. Call me pedantic but I expect at least the most common and essential features to be found in the documentation.
This is from Basic help called directly from Flexprop:
So you have full controll of your asm code. Yoiu can tell the compiler to place it in hub (normal way) inline, move it to a cog and then call or make a spin .dat equivalent using asm shared.
OK, thanks. It's in the "Alphabetical List of Keywords and Built In Functions" section.
I feel so old. I had a very bad week. I think I should go home and get myself a beer instead of complaining.
@ManAtWork Sorry. My bad. I keep switching between languages and I forgot FlexBASIC doesnt want that leading underscore.
But yeah, it is a nice feature to quickly deal with all the UI and string handling Smile in BASIC, and then drop down to the metal and wiggle bits. IMHO @ersmith and @Wuerfel_21 have really done a wonderful job with this compiler.
Dude, I remember the days, in your country, when factory floor vending machines served beer 👍😎👍
Those projects tended to take more time than necessary but we always solved the problem 😂🤣
beer vending machines? Wow, I moved to late to Cali.
Mike
The good news is that after Eric's fixes I see no more strange effects and all calculation results seem reasonable.
The bad news is that the 64 bit math is too slow. I've hoped that I can do the iterations through the motion profile buffer in almost pure C with only the Mul/Div functions in inline assembler. But with all the necessary shifts which are translated to
call #__system___int64_shl
and lots ofcall #pushregs_
andcall #popregs_
a loop iteration takes ~3µs. My limit is 2µs. No big deal. I'll code the innermost loop in assembler.Update: Yeah! I got it down to ~0.5µs per loop iteration. Pipelined CORDIC is the key. I can do all the shifts, pointer calculations and most of the other operations while waiting for the CORDIC which executes both multiplications overlapping..
These breakthroughs are sooo satisfying
Making use of the parallelisms is cool.
I was chatting with my son the other day and I made the off-hand comment that a good assembly coder can drive a veritable bus between a pair of microseconds. He looked at me in complete disbelief. He’s a Python/server-guy, but after that discussion one of my x86 assembly books mysteriously disappeared. 👍