Bitwise operations manipulate individual bits of bytes.
Manipulating bits can be useful for a variety of reasons. One good example is speed. Bit operations are primitive to the processor and are typically very fast. On older processors like the 6502 in the Atari, bit shifting to do division and multiplication can be significantly quicker than the arithmetic counterparts.
Another good example is storing flags. This can be especially useful if memory is tight. In a single byte 8 flags can be stored as opposed to storing them in individual bytes, a space saving of 7 bytes.
Action! provides the following bitwise operators:
- AND (&) : Compares two bits. Both bits must be set (on) for the return value to be set (on)
- OR (%) : Compares two bits. Either bit, or both, can be set (on) for the return value to be set (on)
- XOR (!) : Compare two bits. When both bits are set (on) or not set (off) the return value is not set (off). When either bit is set (on) the return value is set (on).
- LSH : Shift bits of a byte to the left. With Action! the shift occurs across both bytes of CARD and INT types. The number of shifts can be specified as well. Left shifting by one bit is the equivalent of multiplying by 2.
- RSH : Shift bits of a byte to the right. With Action! the shift occurs across both bytes of CARD and INT types. The number of shifts can be specified as well. Right shifting by one bit is the equivalent of dividing by 2 (for positive values).
Sample Program
Here is a quick program to demonstrate a few of the operators. Comments to explain are again inline:
MODULE ; Define bitmask flags ; These are each bits respective value (right to left) DEFINE FDISK = "$01" DEFINE FTAPE = "$02" DEFINE FMEXP = "$04" DEFINE FMODM = "$08" ; Declare byte to store flags BYTE bFlags=[0] ; Procedure to print each bits/flags status PROC PrBits() ; If the bit in flag and bit in mask are both on, then yes if bFlags AND FDISK then PrintE("Flag: Disk YES") else ; Otherwise they are both off, so no PrintE("Flag: Disk NO") fi if bFlags AND FTAPE then PrintE("Flag: Tape YES") else PrintE("Flag: Tape NO") fi if bFlags AND FMEXP then PrintE("Flag: Memory YES") else PrintE("Flag: Memory NO") fi if bFlags AND FMODM then PrintE("Flag: Modem YES") else PrintE("Flag: Modem NO") fi RETURN ; Main routine PROC Main() ; Explain the bits PrintE("M=Modem E=Memory Expansion") PrintE("T=Tape Drive D=Disk Drive") ; For test set bits 4,3,1 to on: 8+4+1=13 ; This is a short way to set many bits at once. bFlags=13 ; Show bit legend PrintE("Bit Positions: ....METD") ; Show which bits are set PrintE("Bits Set : 00001101 (13)") ; Call PrBits to print each flag PrBits() ; Flip all the flag bits bFlags = bFlags XOR FMODM bFlags = bFlags XOR FMEXP bFlags = bFlags XOR FTAPE bFlags = bFlags XOR FDISK PrintE("Flipped") ; Show which bits are set ; Only the TAPE bit now PrintE("Bits Set : 00000010 (2)") ; Call PrBits to print each flag PrBits() ; Pause for keystroke to read output ; Grab byte from device 7 (keyboard) GetD(7) ; Right shift 1 bit ; Turns the TAPE bit off and the DISK bit on bFlags = bFlags RSH 1 PrintE("Right Shifted 1") PrintE("Bits Set : 00000001 (1)") ; Call PrBits to print each flag PrBits() ; Left shift 1 bit ; Turns the TAPE bit on and the DISK bit off bFlags = bFlags LSH 1 PrintE("Left Shifted 1") PrintE("Bits Set : 00000010 (2)") ; Call PrBits to print each flag PrBits() RETURN
Results
The first part of the output showing the AND and XOR operations. Notice the flags are opposite once the bits are all flipped:
The second part of the output showing the RSH and LSH operations. Notice the TAPE and DISK flags get switched when the bit is shifted:
OK, I’ve covered pretty much all the basics of Action!. Now I’m ready to present something useful.