This post about the bit instructions is probably irrelevant now but here it is anyway.
By adding "F," to bit instructions that write a flag no conventions are broken. WC or WZ specify which flag is involved. F could still be used as a variable in other instructions.
If it is very useful what is one more day at this point.
And then there'll be the next very useful feature, and then the next one...
What's already in v18 gives everything needed to implement boolean flags; it's not like there's any missing functionality. The question is solely how many instructions it will take, and we're generally talking about a difference between 1 instruction (if jmg's proposal were implemented) and 1-3 instructions (if not).
The same thing applies to my earlier suggestion of a way to set a register to the value of C or Z. I thought it would be a nice convenience for C and for some interpreters, and would be easy to implement. But in retrospect, given the can of worms it's opened, I'm perfectly willing to go without those instructions. I'd much rather see silicon sooner. So Chip, if you haven't already implemented the WRx instructions please don't and focus on getting the hardware out the door.
Instead of changing D, a flag state is changed instead of a register bit.
Can you give me an example of how this would be used?
edit: okay, looking back at the earlier list, I guess the part that's missing is being able to do (C = C ^ D[ S ]).
Yeah, you got it. I don't program that way myself.
A similar discussion happens in SPIN when people learn they can do comparisons that contain assignments.
Suddenly, a structured if, then, case, can become a math expression doing the same sort of thing, but doing so in an obtuse, but sometimes efficient way.
I do actually use that, but not on a Propeller, other than the occasional curio.
I use it in parametric CAD systems to make responsive, conditional designs. It's an odd, but potent way to think.
Those systems can take standard programs and data, but that often requires a license, or is cumbersome to use and or distribute. Pack the same sort of thing into an expression containing Booleans, and there you go.
I'll end up with a model that changes features, sizes, shape, depending on where, how and what it is placed relative to other models.
It takes a long time, but once done and debugged, basically solves a class of problems, not just a particular instance of a problem.
We can actually do a lot more than that by using more complex if_?'s.
The only thing that is lacking is having results go into C/Z.
Seairth: The results of what go into C/Z?
Here, Chip is talking about now lacking the C/Z as a destination for booleon logic operations.
Those above examples give users a somewhat obtuse pathway to partial Boolean logic, but use a mandatory BitVar as the destination.
The serious weakness here, is that there are no P2 Conditionals on BitVar, but there are plenty of conditionals on C,Z, so much more useful is to use the C.Z as Boolean Accumulators, as in...
Here is an example (from earlier) of how an existing C Compiler, uses such opcodes, on an 8051.
Notice how C is used to 'collect the expression', before passing it to a pin in this case. Also notice there are no wasteful jumps here.
Chip's elegant and compact Verilog turned the P2 (briefly) into something with a nicely orthogonal Boolean Group, and smarter than an 8051 :
ie P2 could use both Z and C as Accumulators, and added a Boolean XOR, as well as C.Z.Bit as destinations.
Removing the elegant and compact and working Verilog has lobotomized the P2 back to something dumber than an 8051 in Bit memory space.
The P2 does still have Bit-memory, but only limited access to it.
The old opcodes BITL,BITH,BITC,BITNC,BITZ,BITNZ,BITN,BITRND allow SETB,CLRB,CPLB, MOV Bit,(!)C, MOV Bit,(!)Z, but missing are the AND.OR.XOR Boolean Logic operators, which the C compiler used above, to collect the expression.
A more common code variant of the above, is like a classic control statement of Value Compare with Boolean Enable.
HeaterPin := (Temp < SetPointC) AND HeaterON
8051 can do that in 4 lines, I think Smarter P2 was able to do that in 3 lines.
To me, the best test of any opcode is 'How can compilers and programmers use them', rather than worry over how they might look next to others...
Yeah, just struggled to put something representative.
Mobile is a PITA
I assumed a mask. To do that we need flags to bits too. It's 4 instructions otherwise, and with what chip put there and my write result to Flag suggestion, unless we have a flag to bit instruction already.
If we do, then it's three again. Will check later.
The point being, if we add writing results to flags to the core set of bit ops, duplicate them, we've got a lot of carry expression cases covered without a syntax clog.
It's a compromise. GOOD, but not fully inclusive coverage.
I'm thinking there are a ton of ways to get at these kinds of things. Reasonable coverage may well hit a sweet spot performance wise.
A more common code variant of the above, is like a classic control statement of Value Compare with Boolean Enable.
HeaterPin := (Temp < SetPointC) AND HeaterON
8051 can do that in 4 lines, I think Smarter P2 was able to do that in 3 lines.
As can old P2:
cmp Temp, SetPointC wc ' set C if Temp < SetPointC
if_c testb flagbits, #HeaterON wc ' C := C AND HeaterON
drvc #HeaterPin ' or use bitc flagbits, #HeaterPin to update a flag instead of driving the pin directly
It's a compromise. GOOD, but not fully inclusive coverage.
The sad thing is, there is no silicon reason for any need to compromise.
The better P2 design was Verilog proven, and worked better than I expected.
Compact, orthogonal, elegant - ticked all the 'good design boxes'.
Also, say someone does just dedicate a COG memory address to holding flags.
Isn't that minor league in terms of memory cost? And one gets a ton of flags. Seems very efficient to me.
Either way, can't we just use conditionals to nail a ton of these anyway? 65C02 and friends did it that way. Do bit ops, branch on product. Got rid of a bunch of flow instructions in a way similar to what we are discussing here.
CMP temp, set point wc, wz
If_nc_and_C BITH heater, heaterpin. 'On
[Other conditional] BITL heater, heaterpin 'off
That's three instructions, and probably not the best ones. Not where I can go through it in detail.
But three is compact. Again good enough coverage.
We have a lot of options. On that CPU you are showing us, perhaps that flow is more necessary?
You can get a Flag to a pin in one line, but an internal dummy boolean, to a pin, is 2-3 lines.
Move Carry to internal bit is two lines: conditional BITH and reverse conditional BITL
That's not many lines.
Seems we are again, very reasonably close given we add WRC, WRZ to the mix. Even without that, a lot of cases are well covered with the bit ops and conditionals.
I don't see a flag address as a kludge. gets done all the time. Easy, peasy.
cmp Temp, SetPointC wc ' set C if Temp < SetPointC
if_c testb flagbits, #HeaterON wc ' C := C AND HeaterON
drvc #HeaterPin ' or use bitc flagbits, #HeaterPin to update a flag instead of driving the pin directly
That's cool.
Now let's do some orthogonal tests...
HeaterPin := (Temp < SetPointC) AND NOT HeaterOFF
HeaterPin := (Temp < SetPointC) AND HeaterON AND NOT ThermalTrip
Maybe dig on the syntax more. Be creative. Forget the Intel stuff. What have we got and how can it flow, if...
Yes, if the problem was one of syntax, removing silicon ability is surely not the right way to solve that.
Personally, I liked Chip's syntax just fine, but then I'm well used to looking at clean Boolean Logic code already, so there is no culture shock this end...
I was excited at being able to do more than I can on a simple 8051...
We can currently use Z to bring in bit values for accumulation into C:
That works, in a round about way, but with the full bit instructions, both Z and C could operate as separate accumulators.
That was cool, allowing more complex and nested expressions to still boolean parse.
By sacrificing the ability to return the prior bit state, we could get more use from the BITx instructions.
The instructions ending in F will perform a logical operation on C and/or Z, based on WC/WZ, using the bit value. Instructions ending in FN will use the complement on the bit value. If WC/WZ is expressed, the register will not be modified, but the flag(s) will be, instead:
cmp Temp, SetPointC wc ' set C if Temp < SetPointC
if_c testb flagbits, #HeaterON wc ' C := C AND HeaterON
drvc #HeaterPin ' or use bitc flagbits, #HeaterPin to update a flag instead of driving the pin directly
That's cool.
Now let's do some orthogonal tests...
HeaterPin := (Temp < SetPointC) AND NOT HeaterOFF
HeaterPin := (Temp < SetPointC) AND HeaterON AND NOT ThermalTrip
Easy & compact with the full bit instructions...
And without:
'' HeaterPin := (Temp < SetPointC) AND NOT HeaterOFF
cmp Temp, SetPointC wc ' C := Temp < SetPointC
if_c testb flagbits, #HeaterOFF wz ' !Z := HeaterOFF
if_c_and_z cmpr $, #0 wc ' C := (Temp < SetPointC) AND !HeaterOFF
drvc #HeaterPin
'' HeaterPin := (Temp < SetPointC) AND HeaterON AND NOT ThermalTrip
cmp Temp, SetPointC wc
if_c testb flagbits, #HeaterON wc
if_c testb flagbits, #ThermalTrip wz ' Z := !ThermalTrip
if_c_and_z cmpr $, #0 wc
drvc #HeaterPin
Each sequence has the same number of instructions as operators. For the first one, :=, <, AND, NOT. For the second :=, <, AND, AND, NOT. With an optimized instruction set you might be able to save the NOT.
This would definitely be nicer/easier with some assembler macros (weren't you working on a macro assembler for P2)? But we can already in v18 do all the bit operations you'd want. It sounds like Chip has some nice proposals for small changes to improve that (I think the slowdown right now is that copying C to Z, and doing NOT, both can sometimes take 2 instructions).
'' HeaterPin := (Temp < SetPointC) AND NOT HeaterOFF
cmp Temp, SetPointC wc ' C := Temp < SetPointC
if_c testb flagbits, #HeaterOFF wz ' !Z := HeaterOFF
if_c_and_z cmpr $, #0 wc ' C := (Temp < SetPointC) AND !HeaterOFF
drvc #HeaterPin
'' HeaterPin := (Temp < SetPointC) AND HeaterON AND NOT ThermalTrip
cmp Temp, SetPointC wc
if_c testb flagbits, #HeaterON wc
if_c testb flagbits, #ThermalTrip wz ' Z := !ThermalTrip
if_c_and_z cmpr $, #0 wc
drvc #HeaterPin
Each sequence has the same number of instructions as operators. For the first one, :=, <, AND, NOT. For the second :=, <, AND, AND, NOT. With an optimized instruction set you might be able to save the NOT.
I'm impressed, so let's inspect :
- Comments are required, to follow just what the flags-dance is doing
- In line 2 Z only updates if C is true, but is used later, so an old Z may creep thru, but very careful reading shows that's actually ok in this case, as it is if_c qualified.
- Even after reading the opcode doc, I'm still not completely sure what if_c_and_z cmpr $, #0 wc does....
Certainly NOT what I'd call the easiest code to edit or maintain.
By sacrificing the ability to return the prior bit state, we could get more use from the BITx instructions.
The instructions ending in F will perform a logical operation on C and/or Z, based on WC/WZ, using the bit value. Instructions ending in FN will use the complement on the bit value. If WC/WZ is expressed, the register will not be modified, but the flag(s) will be, instead:
That does solve getting Booleans + Operators into flags, so that is a plus.
It is better than not having logic operators, but not yet verilog coded ?
A good litmus test, is can it turn Eric's code above, into something more readable ?
- but, it does violate the general rules around {WC.WZ}, and so fails the 'morph nicely with other opcodes' test ?
Of course, I think such a test is the wrong decision process, and the original, more powerful, full bit instructions were fine.
By sacrificing the ability to return the prior bit state, we could get more use from the BITx instructions.
The instructions ending in F will perform a logical operation on C and/or Z, based on WC/WZ, using the bit value. Instructions ending in FN will use the complement on the bit value. If WC/WZ is expressed, the register will not be modified, but the flag(s) will be, instead:
That does solve getting Booleans + Operators into flags, so that is a plus. Better than nothing, but not yet verilog coded ?
- but, it does violate the general rules around {WC.WZ}, and so fails the 'morph nicely with other opcodes' test ?
Of course, I think such a test is the wrong decision process, and the original, more powerful, full bit instructions were fine.
The biggest problem with the full set we had (temporarily) is that they totally violated the WC/WZ convention, removing the obviousness of when the flags were being affected. Remember, using conditionals we can always make register bits the targets of logic operations. The only thing we are missing is making C/Z the targets. What I've proposed is not as elegant, from the purist perspective, but it flows with PASM thinking quite well.
Remember, also, that we have not just BITx, but DIRx, OUTx, FLTx, and DRVx instructions that could be made to work the same. That would allow total bit logic through just a pin number.
not completely sure what if_c_and_z cmpr $, #0 wc does....
You can set C to a desired value by doing a < operation that you know to be true/false. Comparing an instruction (other than nop) to 0 is one way to do this. Having a register with a known value in it would be another way. Come to think of it "testb $, #18 wc" might be even clearer, since the immediate bit is always set in the instruction.
Certainly NOT what I'd call the easiest code to edit or maintain.
I forgot to add a final paragraph to my message above, and was in the process of editing it when you posted. But basically a macro assembler or compiler would go a long way towards making this kind of thing easier.
The instructions ending in F will perform a logical operation on C and/or Z, based on WC/WZ, using the bit value. Instructions ending in FN will use the complement on the bit value. If WC/WZ is expressed, the register will not be modified, but the flag(s) will be, instead:
Trying to follow the actual coverage of this.
I think the words are saying this can do
C = BitName AND C when WC is present or ANDB C,BitName in bASM
Z = BitName AND Z when WZ is present or ANDB Z,BitName in bASM
(maybe both for {wc,wz} ?)
If WC/WZ is expressed, the register will not be modified, but the flag(s) will be, instead:
The converse case of this, if WC/WZ is not expressed/present, how does it know which of
BitName := BinName and C ANDB BitName,C in bASM
BitName := BinName and Z ANDB BitName,Z in bASM
to do ? Or are those latter forms not supported. ANDF says FLAG, so some flag is implicit in the mnemonic.
I guess {} could do C, and {wc,wz} can do Z, in the binary encoding side at least ?
(wanting to update both C & Z would be rare?)
Comments
The results of what go into C/Z?
Instead of changing D, a flag state is changed instead of a register bit.
Can you give me an example of how this would be used?
edit: okay, looking back at the earlier list, I guess the part that's missing is being able to do (C = C ^ D[ S ]).
By adding "F," to bit instructions that write a flag no conventions are broken. WC or WZ specify which flag is involved. F could still be used as a variable in other instructions.
Option 3
{#} omitted from D.S for clarity.
I have deleted the CZ-only instructions (which were the hardest to do mnemonically-speaking) as they have been superseded by the new MODCZ.
Yeah, you got it. I don't program that way myself.
A similar discussion happens in SPIN when people learn they can do comparisons that contain assignments.
Suddenly, a structured if, then, case, can become a math expression doing the same sort of thing, but doing so in an obtuse, but sometimes efficient way.
I do actually use that, but not on a Propeller, other than the occasional curio.
I use it in parametric CAD systems to make responsive, conditional designs. It's an odd, but potent way to think.
Those systems can take standard programs and data, but that often requires a license, or is cumbersome to use and or distribute. Pack the same sort of thing into an expression containing Booleans, and there you go.
I'll end up with a model that changes features, sizes, shape, depending on where, how and what it is placed relative to other models.
It takes a long time, but once done and debugged, basically solves a class of problems, not just a particular instance of a problem.
Those above examples give users a somewhat obtuse pathway to partial Boolean logic, but use a mandatory BitVar as the destination.
The serious weakness here, is that there are no P2 Conditionals on BitVar, but there are plenty of conditionals on C,Z, so much more useful is to use the C.Z as Boolean Accumulators, as in...
Here is an example (from earlier) of how an existing C Compiler, uses such opcodes, on an 8051.
Notice how C is used to 'collect the expression', before passing it to a pin in this case. Also notice there are no wasteful jumps here.
Chip's elegant and compact Verilog turned the P2 (briefly) into something with a nicely orthogonal Boolean Group, and smarter than an 8051 :
ie P2 could use both Z and C as Accumulators, and added a Boolean XOR, as well as C.Z.Bit as destinations.
Removing the elegant and compact and working Verilog has lobotomized the P2 back to something dumber than an 8051 in Bit memory space.
The P2 does still have Bit-memory, but only limited access to it.
The old opcodes BITL,BITH,BITC,BITNC,BITZ,BITNZ,BITN,BITRND allow SETB,CLRB,CPLB, MOV Bit,(!)C, MOV Bit,(!)Z, but missing are the AND.OR.XOR Boolean Logic operators,
which the C compiler used above, to collect the expression.
A more common code variant of the above, is like a classic control statement of Value Compare with Boolean Enable.
8051 can do that in 4 lines, I think Smarter P2 was able to do that in 3 lines.
To me, the best test of any opcode is 'How can compilers and programmers use them', rather than worry over how they might look next to others...
Do the compare, set flags.
Conditionally do the bit operation, based on those flags, SET flags
Conditionally move a pin number?
I'm on mobile...
CMP temp, set point wc, wz
If_nz_and_c BIT heater, heaterbit WRZ, WRC
If_zc MOV heaterpin, heater on
Sorry. I'll format later.
Mobile is a PITA
I assumed a mask. To do that we need flags to bits too. It's 4 instructions otherwise, and with what chip put there and my write result to Flag suggestion, unless we have a flag to bit instruction already.
If we do, then it's three again. Will check later.
The point being, if we add writing results to flags to the core set of bit ops, duplicate them, we've got a lot of carry expression cases covered without a syntax clog.
It's a compromise. GOOD, but not fully inclusive coverage.
I'm thinking there are a ton of ways to get at these kinds of things. Reasonable coverage may well hit a sweet spot performance wise.
As can old P2:
The better P2 design was Verilog proven, and worked better than I expected.
Compact, orthogonal, elegant - ticked all the 'good design boxes'.
Isn't that minor league in terms of memory cost? And one gets a ton of flags. Seems very efficient to me.
Either way, can't we just use conditionals to nail a ton of these anyway? 65C02 and friends did it that way. Do bit ops, branch on product. Got rid of a bunch of flow instructions in a way similar to what we are discussing here.
CMP temp, set point wc, wz
If_nc_and_C BITH heater, heaterpin. 'On
[Other conditional] BITL heater, heaterpin 'off
That's three instructions, and probably not the best ones. Not where I can go through it in detail.
But three is compact. Again good enough coverage.
We have a lot of options. On that CPU you are showing us, perhaps that flow is more necessary?
Yes and no. It needs to be allocated and managed and surely is a bigger kludge than any syntax reflex ?
Sure, ... and more lines of code..
You can get a Flag to a pin in one line, but an internal dummy boolean, to a pin, is 2-3 lines.
That's not many lines.
Seems we are again, very reasonably close given we add WRC, WRZ to the mix. Even without that, a lot of cases are well covered with the bit ops and conditionals.
I don't see a flag address as a kludge. gets done all the time. Easy, peasy.
With full bit instructions, the TESTB+MODCZ sequences would each reduce to just one instruction.
Yup, smaller and easier to read.
Which is why I'm having such a hard time getting my head around why they are gone ?
Now let's do some orthogonal tests... Easy & compact with the full bit instructions...
Personally, I liked Chip's syntax just fine, but then I'm well used to looking at clean Boolean Logic code already, so there is no culture shock this end...
I was excited at being able to do more than I can on a simple 8051...
+1
That was cool, allowing more complex and nested expressions to still boolean parse.
By sacrificing the ability to return the prior bit state, we could get more use from the BITx instructions.
The instructions ending in F will perform a logical operation on C and/or Z, based on WC/WZ, using the bit value. Instructions ending in FN will use the complement on the bit value. If WC/WZ is expressed, the register will not be modified, but the flag(s) will be, instead:
And without:
Each sequence has the same number of instructions as operators. For the first one, :=, <, AND, NOT. For the second :=, <, AND, AND, NOT. With an optimized instruction set you might be able to save the NOT.
This would definitely be nicer/easier with some assembler macros (weren't you working on a macro assembler for P2)? But we can already in v18 do all the bit operations you'd want. It sounds like Chip has some nice proposals for small changes to improve that (I think the slowdown right now is that copying C to Z, and doing NOT, both can sometimes take 2 instructions).
I'm impressed, so let's inspect :
- Comments are required, to follow just what the flags-dance is doing
- In line 2 Z only updates if C is true, but is used later, so an old Z may creep thru, but very careful reading shows that's actually ok in this case, as it is if_c qualified.
- Even after reading the opcode doc, I'm still not completely sure what if_c_and_z cmpr $, #0 wc does....
Certainly NOT what I'd call the easiest code to edit or maintain.
could be realized as:
It couldn't get any smaller than that with fancier instructions.
That does solve getting Booleans + Operators into flags, so that is a plus.
It is better than not having logic operators, but not yet verilog coded ?
A good litmus test, is can it turn Eric's code above, into something more readable ?
- but, it does violate the general rules around {WC.WZ}, and so fails the 'morph nicely with other opcodes' test ?
Of course, I think such a test is the wrong decision process, and the original, more powerful, full bit instructions were fine.
The biggest problem with the full set we had (temporarily) is that they totally violated the WC/WZ convention, removing the obviousness of when the flags were being affected. Remember, using conditionals we can always make register bits the targets of logic operations. The only thing we are missing is making C/Z the targets. What I've proposed is not as elegant, from the purist perspective, but it flows with PASM thinking quite well.
Remember, also, that we have not just BITx, but DIRx, OUTx, FLTx, and DRVx instructions that could be made to work the same. That would allow total bit logic through just a pin number.
I forgot to add a final paragraph to my message above, and was in the process of editing it when you posted. But basically a macro assembler or compiler would go a long way towards making this kind of thing easier.
I think the words are saying this can do
If WC/WZ is expressed, the register will not be modified, but the flag(s) will be, instead:
The converse case of this, if WC/WZ is not expressed/present, how does it know which of
to do ? Or are those latter forms not supported. ANDF says FLAG, so some flag is implicit in the mnemonic.
I guess {} could do C, and {wc,wz} can do Z, in the binary encoding side at least ?
(wanting to update both C & Z would be rare?)