SFUNC question - Page 9 — Parallax Forums

# SFUNC question

• Posts: 2,474
cgracey wrote: »
The WRx instructions are there.

I just realized that we can already do single-instruction boolean operations on register bits:
```if_nc   bitl    d,s     'and
if_c    bith    d,s     'or
if_c    bitn    d,s     'xor
```

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.

The results of what go into C/Z?
• Posts: 10,250
The bit State.

Instead of changing D, a flag state is changed instead of a register bit.
• Posts: 2,474
edited 2017-05-04 20:06
The bit State.

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 ]).
• Posts: 73
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.

Option 3
```Old			New

CLRB	D.S		CLR	D.S	{WC}
SETB	D.S		SET	D.S	{WC}
NOTB	D.S		NOT	D.S	{WC}
RNDB	D.S		RND	D.S	{WC}

MOVB	D.S,CF		MOVC	D.S
MOVB	D.S,!CF		MOVNC	D.S
MOVB	D.S,ZF		MOVZ	D.S
MOVB	D.S,!ZF		MOVNZ	D.S
MOVB	CF,D.S		MOV	F,D.S	WC
MOVB	CF,!D.S		MOVN	F,D.S	WC
MOVB	ZF,D.S		MOV	F,D.S	WZ
MOVB	ZF,!D.S		MOVN	F,D.S	WZ

ANDB	D.S,CF		ANDC	D.S
ANDB	D.S,!CF		ANDNC	D.S
ANDB	D.S,ZF		ANDZ	D.S
ANDB	D.S,!ZF		ANDNZ	D.S
ANDB	CF,D.S		AND	F,D.S	WC
ANDB	CF,!D.S		ANDN	F,D.S	WC
ANDB	ZF,D.S		AND	F,D.S	WZ
ANDB	ZF,!D.S		ANDN	F,D.S	WZ

ORB	D.S,CF		ORC	D.S
ORB	D.S,!CF		ORNC	D.S
ORB	D.S,ZF		ORZ	D.S
ORB	D.S,!ZF		ORNZ	D.S
ORB	CF,D.S		OR	F,D.S	WC
ORB	CF,!D.S		ORN	F,D.S	WC
ORB	ZF,D.S		OR	F,D.S	WZ
ORB	ZF,!D.S		ORN	F,D.S	WZ

XORB	D.S,CF		XORC	D.S
XORB	D.S,!CF		XORNC	D.S
XORB	D.S,ZF		XORZ	D.S
XORB	D.S,!ZF		XORNZ	D.S
XORB	CF,D.S		XOR	F,D.S	WC
XORB	CF,!D.S		XORN	F,D.S	WC
XORB	ZF,D.S		XOR	F,D.S	WZ
XORB	ZF,!D.S		XORN	F,D.S	WZ
```

{#} 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.

• Posts: 6,347
ersmith wrote: »
T Chap wrote: »
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.

Eric
+1
• Posts: 10,250
edited 2017-05-04 20:51
Seairth wrote: »
The bit State.

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.

• Posts: 15,135
edited 2017-05-04 20:52
Seairth wrote: »
cgracey: I just realized that we can already do single-instruction boolean operations on register bits:
```if_nc   bitl    d,s     'and
if_c    bith    d,s     'or
if_c    bitn    d,s     'xor
```

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.
```            LED0 = !LED0;        //   P2 Version?         Alternate P2 code?
00000041:   CPL     P1.4              NOTB    OUTA.4
79             LED0 = ~LED0;
00000043:   CPL     P1.4
80             LED1 = LED2 & !LED1;
00000045:   MOV     C, P1.6           MOVB    C,INA.6
00000047:   ANL     C, /P1.5          ANDB    C,!INA.5
00000049:   MOV     P1.5, C           MOVB    OUTA.5,C    OUTC    OUTA.5
81             LED2 = LED2 | !LED1;
0000004b:   MOV     C, P1.6           MOVB    C,INA.6
0000004d:   ORL     C, /P1.5          ORB     C,~INA.5    ORB     C,NOT INA.5
0000004f:   MOV     P1.6, C           MOVB    OUTA.6,C
```

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...

• Posts: 10,250
edited 2017-05-04 21:29
With the ones chip just put out there, and my WRC, WRZ options, would that line not be three instructions?

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.

• Posts: 15,135
... would that line not be three instructions?
Care to show them ? (in the above, there is no conditionally move a pin number, the pin is always updated T/F )

• Posts: 10,250
edited 2017-05-04 21:33
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.

• Posts: 5,878
jmg wrote: »

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
```
• Posts: 15,135
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'.

• Posts: 10,250
edited 2017-05-04 21:48
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?

• Posts: 15,135
edited 2017-05-04 21:52
Also, say someone does just dedicate a COG memory address to holding flags.

Isn't that minor league in terms of memory cost?

Yes and no. It needs to be allocated and managed and surely is a bigger kludge than any syntax reflex ?

Either way, can't we just use conditionals to nail a ton of these anyway?
Sure, ... and more lines of code..
[Other conditional] BITL heater, heaterpin 'off
You can get a Flag to a pin in one line, but an internal dummy boolean, to a pin, is 2-3 lines.

• Posts: 10,250
edited 2017-05-04 21:52
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.
• Posts: 10,250
Maybe dig on the syntax more. Be creative. Forget the Intel stuff. What have we got and how can it flow, if...
• Posts: 14,021
edited 2017-05-04 22:00
We can currently use Z to bring in bit values for accumulation into C:
```' C = C ^ D[S]

TESTB	D,S		WZ
MODCZ	C_EQ_Z,0	WC

' HeaterPin := (Temp < SetPointC) AND HeaterON

CMP	Temp,SetPointC	WC
TESTB	Flags,#HeaterOn	WZ
MODCZ	C_AND_NZ,0	WC
DRVC	#HeaterPin
```

With full bit instructions, the TESTB+MODCZ sequences would each reduce to just one instruction.
• Posts: 15,135
edited 2017-05-04 22:42
cgracey wrote: »
..
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 ?

• Posts: 15,135
edited 2017-05-04 22:33
ersmith wrote: »

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
```
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...

• Posts: 15,135
edited 2017-05-04 22:45
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...
• Posts: 508
jmg wrote: »
cgracey wrote: »
..
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 ?

+1
• Posts: 15,135
edited 2017-05-04 22:46
cgracey wrote: »
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.

• Posts: 14,021
edited 2017-05-04 23:13
What do you think of this...?

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:
```EEEE 0100000 00I DDDDDDDDD SSSSSSSSS        BITL    D,S/#
EEEE 0100000 CZI DDDDDDDDD SSSSSSSSS        ANDF    D,S/#       {WC,WZ}
EEEE 0100001 00I DDDDDDDDD SSSSSSSSS        BITH    D,S/#
EEEE 0100001 CZI DDDDDDDDD SSSSSSSSS        ANDFN   D,S/#       {WC,WZ}
EEEE 0100010 00I DDDDDDDDD SSSSSSSSS        BITC    D,S/#
EEEE 0100010 CZI DDDDDDDDD SSSSSSSSS        ORF     D,S/#       {WC,WZ}
EEEE 0100011 00I DDDDDDDDD SSSSSSSSS        BITNC   D,S/#
EEEE 0100011 CZI DDDDDDDDD SSSSSSSSS        ORFN    D,S/#       {WC,WZ}
EEEE 0100100 00I DDDDDDDDD SSSSSSSSS        BITZ    D,S/#
EEEE 0100100 CZI DDDDDDDDD SSSSSSSSS        XORF    D,S/#       {WC,WZ}
EEEE 0100101 00I DDDDDDDDD SSSSSSSSS        BITNZ   D,S/#
EEEE 0100101 CZI DDDDDDDDD SSSSSSSSS        XORFN   D,S/#       {WC,WZ}
EEEE 0100110 00I DDDDDDDDD SSSSSSSSS        BITN    D,S/#
EEEE 0100110 CZI DDDDDDDDD SSSSSSSSS        GETF    D,S/#       {WC,WZ}
EEEE 0100111 00I DDDDDDDDD SSSSSSSSS        BITRND  D,S/#
EEEE 0100111 CZI DDDDDDDDD SSSSSSSSS        GETFN   D,S/#       {WC,WZ}
```
• Posts: 5,878
edited 2017-05-04 23:34
jmg wrote: »
ersmith wrote: »

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
```
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).
• Posts: 15,135
ersmith wrote: »

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.

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.
• Posts: 14,021
edited 2017-05-04 23:29
With the proposed ANDF/ANDFN instructions, this:
```HeaterPin := (Temp < SetPointC) AND HeaterON AND NOT ThermalTrip
```

could be realized as:
```		CMP	Temp,SetPointC		WC
ANDF	Flags,#HeaterOn		WC
ANDFN	Flags,#ThermalTrip	WC
DRVC	#HeaterPin
```

It couldn't get any smaller than that with fancier instructions.
• Posts: 15,135
edited 2017-05-04 23:33
cgracey wrote: »
What do you think of this...?
I prefer the full bit instructions, not to mention they are done and tested.
cgracey wrote: »
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.

• Posts: 14,021
jmg wrote: »
cgracey wrote: »
What do you think of this...?
I prefer the full bit instructions, not to mention they are done and tested.
cgracey wrote: »
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.
• Posts: 5,878
jmg wrote: »
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.
• Posts: 15,135
edited 2017-05-04 23:50
cgracey wrote: »
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:
```EEEE 0100000 CZI DDDDDDDDD SSSSSSSSS        ANDF    D,S/#       {WC,WZ}
```
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?)