6 posts
• Page **1** of **1**

During application development I frequently encounter the need to do logic operations on bytes or numbers (AND, OR, XOR, NOT). For each of these, there are assembler instructions and most programming languages have these implemented in some form. Since I haven't found a better way, I currently get by with "shifting" and "odding" the numbers or running through other bitwise shifts. This is quite cumbersome and seems a waste of resources. Question: what would be the most efficient way to set up a "Logic" module that can run such operations? I would prefer to use available Oberon procs, but some inline assembly instructions seem like a good idea too.

- bscholte
**Posts:**8**Joined:**Sat Jan 24, 2015 6:15 pm**Location:**Austria

Read Niklaus Wirth's paper titled SET: A neglected data type, and its compilation for the ARM.

To perform these operations on INTEGERs you will need to type-cast INTEGERs to SETs and vice versa. The Oberon compilers for Cortex-M include a non-standard function BITS which type-casts an INTEGER to a SET.

The standard function ORD can be used to typecast a SET back to an INTEGER. There is no inefficiency introduced as no instructions are generated for these 'pseudo-functions'. It is just a mechanism used by Oberon to tell the compiler to switch off type-checking during the assignment.

To perform these operations on INTEGERs you will need to type-cast INTEGERs to SETs and vice versa. The Oberon compilers for Cortex-M include a non-standard function BITS which type-casts an INTEGER to a SET.

The standard function ORD can be used to typecast a SET back to an INTEGER. There is no inefficiency introduced as no instructions are generated for these 'pseudo-functions'. It is just a mechanism used by Oberon to tell the compiler to switch off type-checking during the assignment.

- cfbsoftware
- Site Admin
**Posts:**361**Joined:**Fri Dec 31, 2010 12:30 pm

Excellent! That works and is actually easier.

As suggested, I used the BITS() to cast from integer to set and ORD() to cast back. The rest is arithmetic on sets.

A small module to test the workings. Not tested thoroughly, but....

(Below are the "Out.Bits" and "Out.Bool" to show the results).

And the Out.Bool and Out.Bits Proc's to show the numbers:

As suggested, I used the BITS() to cast from integer to set and ORD() to cast back. The rest is arithmetic on sets.

A small module to test the workings. Not tested thoroughly, but....

(Below are the "Out.Bits" and "Out.Bool" to show the results).

- Code: Select all
`MODULE Logic;`

IMPORT Main, Out;

VAR I, K:INTEGER;

PROCEDURE ShowResult(J:INTEGER);

BEGIN

Out.Int(J, 4); Out.String(" = "); Out.Bits(J); Out.Ln;

END ShowResult;

BEGIN

Out.String("$FFFF = "); Out.Bits(0FFFFH);Out.Ln;

I:=32; K:=6;

Out.String("I = 32 = "); Out.Bits(I);Out.Ln;

Out.String("Bit 6 in I with I=32: "); Out.Bool(6 IN BITS(I)); Out.Ln;

K:=5;

Out.String("Bit 5 in I with I=32: "); Out.Bool(5 IN BITS(I)); Out.Ln;

K:=37;

Out.String("K = 37 = "); Out.Bits(K);Out.Ln;

Out.String("I = 32 = "); Out.Bits(I);Out.Ln;

Out.String("Logical K OR I with K=37 and I=32: ");

ShowResult(ORD(BITS(K) + BITS(I)));

Out.String("Logical I XOR K with K=37 and I=32: ");

ShowResult(ORD(BITS(I) - BITS(K)));

Out.String("Logical K AND I with K=37 and I=32: ");

ShowResult(ORD(BITS(K) * BITS(I)));

I:=32; K:=33;

Out.String("Logical K AND I with K=33 and I=32: ");

ShowResult(ORD(BITS(K) * BITS(I)));

I:=37; K:=33;

Out.String("Logical K AND I with K=33 and I=37: ");

ShowResult(ORD(BITS(K) * BITS(I)));

I:=32;

Out.String("Logical NOT I with I=32: ");

ShowResult(ORD(BITS(0FFFFFFFFH-I)));

END Logic.

And the Out.Bool and Out.Bits Proc's to show the numbers:

- Code: Select all
`PROCEDURE Bool*(B:BOOLEAN);`

BEGIN

IF B THEN String("TRUE")

ELSE String("FALSE")

END

END Bool;

PROCEDURE Bits*(I:INTEGER);

VAR n: BYTE;

s: ARRAY 34 OF CHAR;

S: SET;

BEGIN

S:=BITS(I);

s[0]:="B";

s[33]:=0X;

FOR n:=0 TO 31 DO

IF 31-n IN S THEN s[n+1]:="1"

ELSE s[n+1]:="0"

END

END;

String(s);

END Bits;

- bscholte
**Posts:**8**Joined:**Sat Jan 24, 2015 6:15 pm**Location:**Austria

To be (hopefully) complete, a short module to implement common logic ops.

- Code: Select all
`MODULE Logic;`

PROCEDURE* And*(A, B:INTEGER):INTEGER;

(*e.g. 5 AND 3 = 0101 AND 0011 = 0001 = 1*)

BEGIN

RETURN ORD(BITS(A) * BITS(B))

END And;

PROCEDURE* Or*(A, B:INTEGER):INTEGER;

(*e.g. 5 OR 3 = 0101 OR 0011 = 0111 = 7*)

BEGIN

RETURN ORD(BITS(A) + BITS(B))

END Or;

PROCEDURE Not*(A:INTEGER):INTEGER;

(*e.g. NOT 1 = 0*)

BEGIN

RETURN ORD(BITS(0FFFFFFFFH-A))

END Not;

PROCEDURE Nand*(A, B:INTEGER):INTEGER;

(*e.g. 5 NAND 3 = 0101 NAND 0011 = 1110 = 14*)

BEGIN

RETURN Not(And(A, B))

END Nand;

PROCEDURE Nor*(A, B:INTEGER):INTEGER;

(*e.g. 5 NOR 3 = 0101 NOR 0011 = 1000 = 8*)

BEGIN

RETURN Not(Or(A, B))

END Nor;

PROCEDURE Xor*(A, B:INTEGER):INTEGER;

(*e.g. 5 XOR 3 = 0101 XOR 0011 = 0110 = 6*)

BEGIN

RETURN ORD((BITS(A) - BITS(B))+(BITS(B)-BITS(A)))

END Xor;

PROCEDURE Xnor*(A, B:INTEGER):INTEGER;

(*e.g. 5 XNOR 3 = 0101 XNOR 0011 = 1001 = 9*)

BEGIN

RETURN Not(Xor(A, B))

END Xnor;

END Logic.

- bscholte
**Posts:**8**Joined:**Sat Jan 24, 2015 6:15 pm**Location:**Austria

Very good. However, just a couple of minor tweaks produces a code file which is more efficient and exactly half the size (108 bytes vs. 216).

Noting that Wirth says in his paper:

The code for Not

becomes more simply:

which generates 1 instruction instead of 2.

Additionally the availability of this unary minus operator for SETs makes the calls to Not in Nand, Nor etc. unnecessary, which in turn means those functions can also be made leaf procedures.

The complete tweaked version is:

I assumed that your original logic is correct. This version should be 100% functionally equivalent.

Noting that Wirth says in his paper:

There is set complementation (unary minus)

The code for Not

- Code: Select all
`ORD(BITS(0FFFFFFFFH-A))`

becomes more simply:

- Code: Select all
`ORD(-BITS(A))`

which generates 1 instruction instead of 2.

Additionally the availability of this unary minus operator for SETs makes the calls to Not in Nand, Nor etc. unnecessary, which in turn means those functions can also be made leaf procedures.

The complete tweaked version is:

- Code: Select all
`MODULE Logic;`

PROCEDURE* And*(A, B:INTEGER):INTEGER;

(*e.g. 5 AND 3 = 0101 AND 0011 = 0001 = 1*)

BEGIN

RETURN ORD(BITS(A) * BITS(B))

END And;

PROCEDURE* Or*(A, B:INTEGER):INTEGER;

(*e.g. 5 OR 3 = 0101 OR 0011 = 0111 = 7*)

BEGIN

RETURN ORD(BITS(A) + BITS(B))

END Or;

PROCEDURE* Not*(A:INTEGER):INTEGER;

(*e.g. NOT 1 = 0*)

BEGIN

RETURN ORD(-BITS(A))

END Not;

PROCEDURE* Nand*(A, B:INTEGER):INTEGER;

(*e.g. 5 AND 3 = 0101 AND 0011 = 0001 = 1*)

BEGIN

RETURN ORD(-(BITS(A) * BITS(B)))

END Nand;

PROCEDURE* Nor*(A, B:INTEGER):INTEGER;

(*e.g. 5 OR 3 = 0101 OR 0011 = 0111 = 7*)

BEGIN

RETURN ORD(-(BITS(A) + BITS(B)))

END Nor;

PROCEDURE* Xor*(A, B:INTEGER):INTEGER;

(*e.g. 5 XOR 3 = 0101 XOR 0011 = 0110 = 6*)

BEGIN

RETURN ORD((BITS(A) - BITS(B)) + (BITS(B) - BITS(A)))

END Xor;

PROCEDURE* Xnor*(A, B:INTEGER):INTEGER;

(*e.g. 5 XNOR 3 = 0101 XNOR 0011 = 1001 = 9*)

BEGIN

RETURN ORD(-((BITS(A) - BITS(B)) + (BITS(B) - BITS(A))))

END Xnor;

END Logic.

I assumed that your original logic is correct. This version should be 100% functionally equivalent.

- cfbsoftware
- Site Admin
**Posts:**361**Joined:**Fri Dec 31, 2010 12:30 pm

Wow. Very elegant! Thanks.

- bscholte
**Posts:**8**Joined:**Sat Jan 24, 2015 6:15 pm**Location:**Austria

6 posts
• Page **1** of **1**