Spin2: Get Specific Byte from Word or Long?
JonnyMac
Posts: 9,104
I'm attempting to port some P1 code to the P2. This line throws an error in PNut v34f:
if (checksum.byte[0] == buffer[BUF_LEN-1])The reference to .byte[0] causes a problem. I can code around this specific situation, but it would be nice to know that, as in Spin1, I can extract any byte from any word or long.
Comments
We have bitfields now, anyway. You could do this:
longvar.[0 addbits 7]
-or-
byte[@longvar]{[index]}
I could add in the old syntax, but there is more to support than before, in order to maintain compatibility with what already exists. This should be supported:
longvar[index].byte[index].[bitfield]
It gets hairy.
I'd like that, because it is very clean and obvious -- which is something I always strive for. The addbits version may be efficient underneath, but it's not obvious to someone reading the code unless they have a very deep knowledge of the P2. Another thing that I just though of -- and that I do quite a bit -- is treat an array of longs (e.g., in a method) as an array of bytes; the .byte[index] syntax makes this very easy.
Roy, I agree.
The 'addbits' seems to relate to how an arbitrary range of pins can be declared for some operations where you declare a base pin for the range.
While this formats makes it easy for the tool to determine what to encode, is there a reason that the range couldn't be represented as a range e.g. 7..0 ?
The fact that this addbits thing is not immediately obvious to some suggests that it isn't the best way to represent it.
I think the old syntax should be supported, even if it makes the job harder for the tool maker.
I actually liked a lot how inb and outb and dirb worked in P1 Spin where you could select bits...
To access a long variable as a byte variable, you currently need to do one of these:
BYTE[@longvar]
BYTE[@longvar[longindex]]
BYTE[@longvar][byteindex]
BYTE[@longvar[longindex]][byteindex]
I think I could support something like this:
longvar.byte[byteindex]
longvar[longindex].byte[byteindex]
For pins and bits, a span can be accessed at the two-clock/single-instruction level.
For a bitfield value, bits [4:0] select the base bit and bits [9:5] select how many more bits above the base bit to also select, wrapping around to bit 0 after bit 31. The ADDBITS operator does the masking, shifting, and OR'ing to make the composite bitfield value. This concept must flow to the high-level language for most-efficient code execution.
For a pinfield value, bits [5:0] select the base pin and bits [10:6] select how many additional pins are selected, starting at the base pin and wrapping within the A or B pin group. The ADDPINS operator does the composing of the pinfield value.
makemask(x,y) would at least be more clear what's happening. Maybe just mask(x,y)
But it's not a mask, actually.
x.[8] 'bit 8 of x
x.[8 addbits 7] 'bits 8..15 of x
It's a concept that is half-way unique, so that prior means of dealing with similar things don't exactly fit. It needs some new treatment.
It can be more than seven chrs. We need one for bits and one for pins.
Your own description does say it does masking... which is why I went there.
In Spin1, you could do DIRA[8..15] to me that is more readable than 8 addbits 7. I know it doesn't handle the wrapping, but why must the most common usage be made unclear for that?
Can I still do the Spin1 thing as well? Just for everything instead of only special registers? If I can do myLongVar[8..15] for normal cases and only use the addbits thing for wrap cases, then I'll be fine because I'd never use the wrap case unless forced to.
If we can't do the [x..y] range syntax for at least special registers, then a LOT of Spin1 code will not work in Spin2 without being changed to this unclear ugly syntax.
You had it working fine in Spin1, don't understand how it can't be done exactly the same in Spin2? Just add the new syntax so people can use it for cases the .. syntax doesn't cover.
I get that Spin2 is not compatible with Spin1, but basic stuff like this should be handled the same or it's not correct to even call it Spin. You are making people relearn basic syntax stuff for Spin2, not just new stuff that was added.
I'm surprised others are not joining in on this... because this probably breaks way more existing Spin code than any other change you made.
Maybe it doesn't matter anymore, maybe people don't care anymore about bringing Spin1 stuff over to Spin2 without having to fix a bunch of things that shouldn't need fixing.
I'm not even sure why I am fretting over this at all anymore, I am very unlikely to use Spin2 for P2 coding since it requires that I learn a new language now, and I can just use FlexC with a language I know well already.
Surely the DIR/IN/OUT syntax of [nn..mm] could be used to use the new instructions. If not, then at least implement it using the old instructions.
There will be enough problems with spin1 incompatibilities. We really need there to be as few as possible. I’ve been hanging out for pnut and spin as I am not wanting it to be a large hubexec program that fastspin gives.
We already have a major exercise in converting P1ASM to P2 with just about every jmp/call/ret requiring explicit fixing/translation. Now Spin2 is so different too.
Do you really want to alienate all the remaining P1 users??? Weve already lost most of them.
If longvar[8..15] can be made to work, would make things a lot better
Including the reversal of bits shown above.
I often used dirb outb etc. for this on p1 but can’t now that b registers are real...
Can't it, in addition, be also in these forms:
where you find addbits you alredy have the numbers, as opposite when "to" or ".." is found the compiler can do the math: 15-8 (=7)
I am not against the one or the other but for me:
- when the variable have a binary rappresentation eg flags, options, enables ... then addbits is more friendly
- but when you are extracting bits/bytes eg msb lsb from a higher container then x..y or x to y is more readable.
I think both can be supported as it eventually adds only one math operation more in the compiler.
BTW: with x..y or x to y wrapping around must be prevented ie [8..2] or [8 to 2] must be wrong
somevar{.byte|word|long}{[index]}{.[bitfield]}
Likewise, this syntax is cleaner than
Mike
If you are talking about constants defining the bitfield, it's easy to support any syntax. Variables make things more complicated.
I'd hate for anything to bust efficiencies like that in the name of backward compatibility.
Fine!
For most uses in P1 we use constants, so allow the syntax with constants and force addpins for variables.
Mike
It's a trade-off between run-time efficiencies and porting efficiencies.
I can see two approaches to the pin range extending beyond the bounds of a long:
1. Throw an error.
2. Render it in two instructions covering the full range, but taking four clocks.
I think most people would be accepting of the first approach as a limitation of the system, given how infrequently such a thing would be attempted intentionally.
It's optional, and doesn't break the old syntax, just adds something.
The issue being argued is perhaps misnamed. It's not impeding porting P1 to P2, but making you think a little when going from P2 back to P1.
You should be able to compile ANYTHING[8..15] to the exact same thing you compile ANYTHING[8 addbits 7] to, right? It means the exact same thing conceptually. It' just a tiny bit of compiler parsing work, I don't get the push back at all.
Even if the user wrote ANYTHING[15..8], that is trivially correctable by swapping the two operands, or you could just throw an error if you don't want to allow it. This is all super trivial compile time stuff that shouldn't matter at all to the end result byte code.
I'm confused why the syntax of this matters at all to the end result byte codes. What am I missing? I don't think it does...
The thing the old syntax does do is make the code significantly more readable and understandable at a glance.
Your bit range is constant. The problem is: ANYTHING[mypin addbits 7] where mypin is a variable, maybe passed as a parameter to a methode.
Edit:
Maybe ANYTHING[mypin+7 .. mypin] will work, the rule would be: It must be the same variable and a constant offset.