Introduction to Kenbak-1 Bitwise Instructions
The Kenbak-1 Bitwise instructions include AND, OR, and LNEG. With these instructions, think of the individual bits within an 8 bit word. With “AND”, a particular bit must be high in both the source and compare words to get the value of 1 in the destination. On the other hand, with “OR”, only one of the two bits must be high. On the other hand, we have LNEG, which will load the compliment. In other words, it will reverse the bits in a word. Although we don’t have an XOR instruction, we can build XOR logic using the existing Kenbak-1 instructions.
For more detailed information, take a loo at pages 7 and 8 of the Kenbak-1 Programming Reference Manual
You can try these demonstrations on the Kenbak-1 Web Emulator. Keep in mind that you can always add a delay loop for “debounce” if you need it. A debounce loop would just add enough delay so if the contacts make two different times on a single key press, we only register a single key press.
Kenbak-1 “AND” Instruction
In the Kenbak-1, we are a bit limited on how we can use the AND instruction. Nevertheless, it’s very useful for manipulating bits. Let’s take a look at the truth table for this instruction. Basically, we can “AND” the A register with another word. In this case, the “B” Register. We can use any of the addressing modes available to other instructions. The Kenbak-1 stores the result of the AND back to the A register.
For a practical example, think of the B register as being the buttons for operator input. The A register contains “permissives” that the Kenbak sets. When the operator presses a button, they must have permission from the Kenbak-1 before we can energize an output. The Kenbak-1 can inhibit or permit an output. We might do this to prevent the operator from starting a system unless a lube pump or cooling system is running first.
Kenbak-1 “OR” Instruction
Next, let’s take a look at an “OR” Instruction. The operation is similar to the AND instruction, except that only one bit needs to be high in either the source or destination. If one of the two bits are high (or both), then the destination bit goes high. Let’s look at our truth tables for the OR instruction.
For a practical example, we can think of starting a motor either locally or remotely. Consider the A register to contain the value for a remote start. The B register contains our buttons for a local start. If we get a start request either locally or remotely, then the output energizes.
How XOR Works with Kenbak-1 Bitwise Instructions
With the XOR (Exclusive OR) logic, either the bit in our source or compare word can be true to get a 1 in the result, but not both bits. Keep in mind that we don’t have an XOR instruction. However, we can build one. We can take the OR result of our two words, and then subtract the AND result. Let’s look at the truth table for an XOR.
A practical example for the XOR would be with “Masking”. As you can see, wherever we have a 1 in the B register, the value of the A register is reversed. We might do this depending on the fail safe state of the field device. For some devices, a 0 might represent the ON state. Let’s say we have a cooling system, and normally we want the cooling system to run. Even if our Kenbak looses power, we want the cooling system to be on. In this case, a 1 will inhibit the cooling system, while a 0 allows it to run.
Kenbak-1 LNEG Instruction
The LNEG instruction simply reverses the values of a memory cell. This loads the compliment into the A register. In other words, it subtracts from zero. This instruction does not directly affect the memory cell that we are complimenting, unless it was the contents of the A register itself.
Here, the original value of the “A” register is irrelevant. We simply load the compliment of the operand. Basically, if we turn on a single bit, the bit that is true, and all of the higher bits will be set on in the result. This is useful for selecting power levels.
Try out this code as a demonstration of the LNEG iinstruction.
INIT: 000: 000 000 000 004 RESET: 004: 023 000 LDA 000 006: 123 000 LDB 000 010: 223 000 LDX 000 012: 234 377 STX BUTTONS (CLEAR BUTTONS) START: 014: 124 377 LDB BUTTONS (LOAD A WITH BUTTONS) 016: 144 014 JPD A=0 014 (WAIT FOR BUTTONS) 020: 234 377 STX BUTTONS (CLEAR BUTTONS) 022: 334 001 LNEG B 024: 034 200 STA DISPLAY 026: 344 014
For this demonstration of the LNEG on the Kenbakuino, use this octal dump:
Putting It all Together
At this point, we’ll put together a program that will demonstrate the Kenbak “AND” and “OR” instructions. We’ll also build our own XOR in logic.
Basically, on this program, the user can energize or de-energize any output. However, they must have permission from the Kenbak-1 to be able to turn the output on. The memory cell that grants permission is cell #100. In this case, cell #100 contains an 017. this means that the operator only has permission to energize bits 3, 2, 1, and 0. If the user hits a button once, the output comes on. If they hit the button again (while the light is still energized), the light shuts off.
Initialize the Registers for Kenbak-1 Bitwise Instructions
First, we’ll initialize the Kenbak-1 by setting all the registers to zero. Additionally, we’ll clear our button latches.
INIT: 000: 000 000 000 004 RESET: 004: 023 000 LDA 000 006: 123 000 LDB 000 010: 223 000 LDX 000 012: 034 377 STA BUTTONS (CLEAR BUTTONS)
In 014, and 016, we’ll check for user input. If there is no user input, then we wait. In 020, we have some NOOP instructions which perform no operation. This is free to add some code for debugging if we need to.
In 022, and 024, we have a couple of “subroutines” that we execute. In 022, the Kenbak-1 will set permissions. It can prevent us from energizing certain outputs. We’ll discuss this in the next section.
At 024, we will handle the I/O. Basically, if the user presses a button, it will change the state of the output. If the output was on, then the button will shut the output off. Likewise, if the output was off, the button generates a request to turn the light on.
In 026, we will “AND” register A with the contents of register 100. This means that if the user requests an output to come on, AND the Kenbak has given us permission to turn the light on, then we will set that bit to a 1 in the A register. At this point, the “A” register contains our output image.
At memory cells 030, and 032, we simply store this output image to the display, reset our registers again, and wait for user input.
START: 014: 124 377 LDB BUTTONS (LOAD A WITH BUTTONS) 016: 144 014 JPD A=0 014 (WAIT FOR BUTTONS) 020: 200 200 NOOP 022: 344 050 JPD PHAND (HANDLE PERMISSIONS) 024: 344 060 JPD IOHAND (HANDLE I/O) 026: 324 100 AND A 100 (AND "A" WITH CONTENTS OF 100) 030: 034 200 STA DISPLAY (STORE "A" TO DISPLAY) 032: 344 004 JPD RESET
This logic is very simple. To demonstrate, I’m simply setting register 100 to “017”. In your own programs, though, you can have other logic that decides how to set this register up. After setting the value of memory cell 100, we simply resume where we left off in the “Main routine”.
PHAND: (HANDLE PERMISSIONS) 050: 123 017 LDB 017 (LOAD B WITH 017 (FOUR LSB'S HIGH)) 052: 134 100 STB 100 [PERMISSIONS] 054: 344 024 JPD 024 (RETURN)
This routine is a bit more complex. Since there is no Exclusive OR statement in the Kenbak-1, we have to derive that function ourselves to generate our output requests. Remember that just because we request that a light energizes doesn’t mean it will. Keep in mind that cell 026 will “AND” register A with memory cell 100. If we request a light, the output will only energize if the Kenbak-1 has given us permission to do so.
To develop our own XOR, we will first “AND” the buttons and lights together. We’ll store the result to cell 101, because we need that later on. In order to accomplish this, we load the A register with our lights in cell 060. In 062, we and the buttons with the lights, and in 064, we store the result to cell 101.
At 066, we re-load our A register with the lights, and we OR the lights with the buttons in cell 070. The problem with that is that if a light was already on, we need to shut that light off. Keep in mind though, that in cell 101, we know when this is the case. Cell 101 contains a bit pattern where we hit a button, and the light was already on.
Therefore, if we hit a button and a light was already on, we want to have an end result of 0. This means that whatever bits are set in cell 101 need to be a 0 in our A register. We do this by simply subtracting the contents of cell 101 from the A register. The A register now contains the desired state of our outputs. After that we return back to the Main Routine where we left off.
XOR LIGHTS AND BUTTONS 060: 024 200 LDA LIGHTS 062: 324 377 ANDA BUTTONS 064: 034 101 STA 101 (AND PRODUCT) 066: 024 200 LDA LIGHTS 070: 304 377 ORA BUTTONS (A IS NOW OR PRODUCT) 072: 014 101 SUBA 101 (XOR PRODUCT) A IS NOW DESIRED STATE 074: 344 026 JPD 026 (RETURN)
Full Code for Kenbak-1 Bitwise Instructions
Using the Kenbak-1 Web emulator, you can simply paste this code into the memory loader to see it run.
INIT: 000: 000 000 000 004 RESET: 004: 023 000 LDA 000 006: 123 000 LDB 000 010: 223 000 LDX 000 012: 034 377 STA BUTTONS (CLEAR BUTTONS) START: 014: 124 377 LDB BUTTONS (LOAD A WITH BUTTONS) 016: 144 014 JPD A=0 014 (WAIT FOR BUTTONS) 020: 200 200 NOOP 022: 344 050 JPD PHAND (HANDLE PERMISSIONS) 024: 344 060 JPD IOHAND (HANDLE I/O) 026: 324 100 AND A 100 (AND "A" WITH CONTENTS OF 100) 030: 034 200 STA DISPLAY (STORE "A" TO DISPLAY) 032: 344 004 JPD RESET PHAND: (HANDLE PERMISSIONS) 050: 123 017 LDB 017 (LOAD B WITH 017 (FOUR LSB'S HIGH)) 052: 134 100 STB 100 [PERMISSIONS] 054: 344 024 JPD 024 (RETURN) XOR LIGHTS AND BUTTONS 060: 024 200 LDA LIGHTS 062: 324 377 ANDA BUTTONS 064: 034 101 STA 101 (AND PRODUCT) 066: 024 200 LDA LIGHTS 070: 304 377 ORA BUTTONS (A IS NOW OR PRODUCT) 072: 014 101 SUBA 101 (XOR PRODUCT) A IS NOW DESIRED STATE 074: 344 026 JPD 026 (RETURN)
Octal Dump for Kenbakuino
If you wish to try this on the Kenbakuino, use this octal dump:
For more information, visit the Kenbak-1 Category Page!
— Ricky Bryce