Eight Bit Computer¶
Welcome to the documentation for the 8 bit computer project!
Overview¶
Modules¶
Register¶
A register stores an 8 bit number. In the computer registers are connected to the bus and can read a value from the bus or assert a value onto the bus. They also provide an output which is the currently stored value.
As well as the data oriented ACC, A, B and C registers, the control oriented instruction register, stack pointer and memory address register are all just registers. The memory address register only needs to read from the bus and not assert values onto it so it’s slightly simpler.
Interface and Operation¶
This is the interface of a register:

This is how it operates:
Name | Bit width | Description |
---|---|---|
data | 8 | Reads bits from, or asserts bits onto this connection |
contents | 8 | Always outputs the current value held in the register |
clock | 1 | Clock signal from the clock module |
input_enable | 1 | While high, the register stores the value on data on a rising clock edge |
output_enable | 1 | While high, the register asserts it’s content onto data |
Implementation¶
- A 74HCT377 is used to store the contents of the register.
- A 74HCT245 is used to provide a tri-state output to allow asserting values onto the bus, or not.
- LEDs with current limiting resistors are used to display the current contents.
- A 74HCT04 is used to invert the incoming input_enable and output_enable signals to drive the active low inputs on the 74HCT377 and 74HCT245.
The electronics are laid out on the breadboard like so:

Due to the central bus in the layout of the computer it’s convenient to also have a version where the connection to the bus is on the right:

An input only register like the memory address register is simpler:

2:1 Selector¶
The 2:1 selector outputs one of two 8 bit inputs. Also known as a multiplexer.
Interface and Operation¶
This is the interface of a 2:1 selector:

This is how it operates:
Name | Bit width | Description |
---|---|---|
A | 8 | First input |
B | 8 | Second input |
out | 8 | Output, either A or B. |
A/B | 1 | When low, A is output, when high, B is output |
Implementation¶
- Two 74HCT157s are used to choose between the two inputs.
- LEDs with current limiting resistors are used to display the output.
Due to 2:1 selectors being required in different parts of the computer, the layout on the breadboard of A, B and out sometimes need to differ.
This is the A B out layout:

This is the out A B layout:

Different coloured wires are used in the Fritzing images above to help track the A, B and out bits. When creating the computer only green wire was available :(.
Program Counter¶
The program counter stores an eight bit number used to track the current position/instruction in program memory.
It’s similar to a regular register but has some extra functionality:
- It can add one to it’s current value.
- It’s value can be asynchronously reset to 0.
Interface and Operation¶
This is the interface to the program counter:

This is how it operates:
Name | Bit width | Description |
---|---|---|
data | 8 | Reads bits from, or asserts bits onto this connection. |
contents | 8 | Always outputs the current value held in the program counter. |
clock | 1 | Clock signal from the clock module. |
input_enable | 1 | While high, the program counter stores the value on data on a rising clock edge. |
count | 1 | While high, the program counter increments the stored value by one on a rising clock edge. |
output_enable | 1 | While high, the program counter asserts it’s content onto data. |
Implementation¶
- Two 74HCT161s are used to store, increment and clear the 8 bit value.
- A 74HCT245 is used to provide a tri-state output to allow asserting values onto the bus, or not.
- A 74HCT04 is used to invert the incoming input_enable, output_enable and count signals to drive the active low inputs on the 74HCT161s and 74HCT245.
- LEDs with current limiting resistors are used to display the current contents.
The electronics are laid out on the breadboard like so:

Clock¶
The clock produces signals that synchronise the operation of all the other modules in the computer.
It can drive the operation of the computer step by step for debugging or at an arbitrary speed.
Interface and Operation¶
This is the interface to the clock:

And this is how it operates:
Name | Bit width | Description |
---|---|---|
auto/manual | 1 | When low, the clock signals are advanced manually with manual_input. When high, clock singals are advanced automatically. |
manual_clock_input | 1 | High/low transitions here will advance the clock signals. |
halt | 1 | While high, bring both of the clock signals low and stop them advancing. |
reset | 1 | While high, bring both of the clock signals low and stop them advancing. |
data_clock | 1 | Alternates between high and low, driving the data transitions in the computer. |
control_clock | 1 | Alternates between high and low, driving the control signal transitions in the computer. |
Control and Data Clocks¶
Typically the clocks in other computers invert data_clock to create control_clock, like this:

This is not suitable for this computer due to some restrictions on the 74HCT161 used in the Program Counter. Here is the note from the datasheet:
Note
- The High-to-Low transition of PE or TE on the ’HC/HCT161 and the ’HC/HCT163 should only occur while CP is HIGH for conventional operation.
- The Low-to-High transition of SPE on the ’HC/HCT161 and SPE or MR on the ’HC/HCT163 should only occur while CP is HIGH for conventional operation.
This means:
- PE going from high to low (i.e. disabling counting) must happen while data_clock is high.
- SPE going from low to high (i.e. disabling parallel load mode) must happen while data_clock is high.
The inverted clock method doesn’t satisfy this constraint as control signal changes (which happen a short delay after the rising edge of control_clock) would occur after data_clock had gone low. The delay is introduced by the EEPROMs in the Control Unit settling after a new instruction/flag/micro-step value goes onto their address lines. This demonstrates the problem using the PE control (_SPE is the same):

To satisfy this constraint, the two clock signals proceed like this:

This means data_clock is still high when PE/count_enable changes:

Halt and reset¶
Once halt or reset go high, both data_clock and control_clock immediately go low. Once halt and reset go low again after either becomes high, data_clock should be the first to go high and the then sequence continues. This is to ensure correct timing gaps are left when operation of the computer resumes.
Implementation¶
Even duty cycle¶
The 555 astable circuit used does not always output a signal with an even duty cycle. To fix this, the output from the 555 is fed into the clock of a JK flip flop configured to toggle. This halves the frequency of the astable output but guarantees it’s at a 50% duty cycle.
Block diagram¶
Logically the clock is implemented as follows:

From left to right:
- Manual and 555 clock signals.
- Feed the 555 into a JK flip flop configured to toggle to achieve even duty cycle.
- Multiplex to choose the manual or auto clock.
- Halt and reset signals.
- Safe Clock Enable. This ensures correct timing of the clock after reset is released.
- Two JK flip flops configured to toggle, one fed with the inverse of the gated clock signal to be the delayed signal for the control clock.
However, in reality the layout is equivalent, but a little more complex due to implementation details in the other chips (active low inputs) and trying to make the best use of space and gates available on chips:

Hardware¶
There is also some debouncing that happens on the clock for the manual signals.
The following electronics are used:
- A 555 and accompanying resistors and capacitors to generate the auto clock signal.
- A 74HCT109 to get an even duty cycle from the 555.
- A 74HCT14 and accompanying resistors and capacitors to debounce the manual inputs.
- A 74HCT00 to create a multiplexer to select between the manual and auto clock signals.
- A 74HCT02 and 74HCT00 to create the safe clock gate and some additional signal inverting.
- Another 74HCT109 to provide the last 2 toggles for the clocks.
The components are laid out on the breadboard like so:

The clock module is the first in the list to be redesigned :).
RAM¶
The RAM provides 256 bytes of program memory (instruction bytes) and 256 bytes of data memory (global variables and the stack).
Interface and Operation¶
This is the interface of the RAM:

This is how it operates:
Name | Bit width | Description |
---|---|---|
input_enable | 1 | While high, the data on data_in will be stored at the currently selected address on a rising clock edge. |
output_enable | 1 | While high, the RAM asserts the data at the currently selected address onto data_out. |
data_clock | 1 | Clock signal from the clock module (data_clock). |
setup_clock | 1 | Clock signal from the manual setup switch. |
run_setup | 1 | When low, the RAM is in setup mode, when high, run mode. |
control_unit_select_data_memory | 1 | Program/data memory selection switch from the control unit. |
setup_select_data_memory | 1 | Program/data memory selection switch from the manual setup switch. |
data_in | 8 | Data to be stored is read from here. |
data_out | 8 | Data at current address is output here. |
address | 8 | Index in memory to read from or write to. |
Implementation¶
Combined Input/Output pins¶
Unlike the 74LS189 chip that Ben Eater uses for his RAM, the 6116SA used in this computer has combined input and output pins. This means that care is required not to apply signals to those pins at incorrect times. A tri state buffer is used on the input to achieve this. The connections from the input/output pins on the RAM chip and the 74HCT245 tri state buffers are arranged like this:

Timing for Safely Writing Data¶
Most of the time the RAM chip is in read mode. This means that the chip is asserting the data stored in the address currently specified on the address pins to the input/output pins. When it’s time to write, the chip needs to switch to write mode. To simplify control circuitry, only the write enable (active low) input on the 6116SA is used to control switching between read and write mode (output enable (active low) is available on the chip as well).
It takes time for the chip to switch modes and the pins to change from output to input. This time is referred to as tWHZ in the data-sheet and the following note applies:
Note
- During this period, the I/O pins are in the output state and the input signals must not be applied.
According to the data-sheet tWHZ is at most 7ns for the 6116SA15 being used.
As well as the time taken for the pins to change state, we need to ensure that the overall write pulse width is a certain length due to another note in the data-sheet (which applies because _OE will indeed be low):
Note
- _OE is continuously HIGH. If _OE is LOW during a _WE controlled write cycle, the write pulse width must be the larger of tWP or (tWHZ + tDW) to allow the I/O drivers to turn off and data to be placed on the bus for the required tDW. If _OE is HIGH during a _WE controlled write cycle, this requirement does not apply and the write pulse is the specified tWP. For a _CS controlled write cycle, _OE may be LOW with no degradation to tCW.
tWP is listed as 12ns, but tWHZ + tDW (7ns + 12ns) is greater at 19ns so the write pulse needs to be at least that long.
The chip is also not edge triggered - it will write data to the specified address as long as it is in write mode. This means that we need to do our own edge detection and keep the write pulse as short as possible. See the Edge Detection section for more details.
Once the write is finished, the chip can go instantly back into read mode (as tDH is 0ns).
So with all this in mind, this is how the desired control signals would look (assuming a write is to take place).

The output enable on the 74HCT245 and write enable on the 6116SA are active low so the final circuit looks like this:

(This can be seen in Falstad Circuit Simulator by loading the
saved session
)
From left to right:
- The capacitor, resistor and inverting Schmitt trigger on the bottom form the edge detector that produces a low pulse when a rising edge is detected.
- The three inverting Schmitt triggers on top serve to delay and invert the clock signal (using propagation delay).
- The two OR gates ensure that once the low pulse from the detected rising edge finishes, both control signals go high at the same time.
The propagation delay of the inverting Schmitt triggers (inside a 74HCT14) is approximately 20ns, to a maximum of approximately 40ns. With the 3 Schmitt triggers on top, the inversion of the now positive clock is delayed between 60ns and 120ns.
The resistor and capacitor values are chosen so that the time from the voltage between the capacitor and the resistor going high, to the voltage going below the negative going threshold of the Schmitt trigger is at least 112ns. That is:
- 120ns for the longest possible delay for the top three Schmitt triggers.
- Subtract 20ns for the shortest propagation delay from the edge detect Schmitt trigger.
- 12ns to satisfy tDW
The 7ns required for tWHZ is amply catered for by the chained Schmitt triggers.
The final control signals look like this:

Run/Setup Mode¶
The RAM needs to accessed by the computer while running (run mode) and by the user during setup (setup mode). To achieve this, the follwing inputs to the RAM all need to be driven by either the computer itself, or the user:
- data_in
- address
- input_enable
- select_data_memory
- clock
The run_setup switch decides which input will be fed to the RAM.
data_in and address are connected to 2:1 Selectors.
The remaining input_enable, prog_data_mem_select and clock are all connected to a 74HCT157 Quad 2 to 1 line data selector. They are set up as follows:

From left to right:
- Multiplexers to select between run and setup control signals
- Safe Clock Enable
- Outputs to the rest of the RAM.
When in run mode:
- data_in - connected to the bus.
- address - connected to the output of the memory address register.
- input_enable - connected to ram_in from the Control Unit.
- select_data_memory - connected to ram_sel_data_mem from the Control Unit.
- clock - connected to data_clock from the Clock.
When in setup mode, all of the above are connected to switches that the user controls, apart from input_enable which is held high.
Hardware¶
The following electronics are used:
- A 6166SA15 RAM chip to hold all the data.
- 2 x 74HCT245 for controlling input and output to and from the RAMs IO pins.
- A 74HCT157 to choose between the inputs in run and setup mode.
- A 74HCT02 containing NOR gates to build the Safe Clock Enable.
- A 74HCT08 containing AND gates to build the Safe Clock Enable and isolate the resistor and capacitor circuit from the other logic gates.
- A 74HCT14 containing Schmitt triggers to edge detect and delay the clock.
- A 74HCT32 for the OR gates that are used in the edge detection and delay circuit.
They are laid out on the breadboards as follows:

Control Unit¶
The control unit interprets the instruction byte and flag bits. It sets control signals in the correct sequence to operate the other modules in the computer to complete the current instruction. Steps in the sequence are kept in order with an internal microcode step counter.
Interface and Operation¶
This is the interface of the Control Unit:

This is how it operates:
Name | Bit width | Description |
---|---|---|
instruction_byte | 8 | Specifies the current instruction. |
flags | 4 | The flag bits from the ALU, control conditional instructions. |
clock | 1 | The control_clock from the clock module. |
reset | 1 | While high, sets the microcode step count to 0. |
acc_in | 1 | Instructs the accumulator register to store the value on the bus. |
acc_out | 1 | Instructs the accumulator register to assert it’s content onto the bus. |
a_in | 1 | Instructs the A register to store the value on the bus. |
a_out | 1 | Instructs the A register to assert it’s content onto the bus. |
b_in | 1 | Instructs the B register to store the value on the bus. |
b_out | 1 | Instructs the B register to assert it’s content onto the bus. |
c_in | 1 | Instructs the C register to store the value on the bus. |
c_out | 1 | Instructs the C register to assert it’s content onto the bus. |
alu_store_result | 1 | Instructs the ALU to store the current result. |
alu_store_flags | 1 | Instructs the ALU to store the current flags. |
alu_out | 1 | Instructs the ALU register to assert it’s stored result onto the bus. |
alu_a_is_bus | 1 | When low, the A input to the ALU is the accumulator register, when high, its the bus. |
alu_s0 | 1 | The S0 input for selecting ALU operations. |
alu_s1 | 1 | The S1 input for selecting ALU operations. |
alu_s2 | 1 | The S2 input for selecting ALU operations. |
alu_s3 | 1 | The S3 input for selecting ALU operations. |
alu_m | 1 | The M input for the ALU. |
alu_c_in | 1 | The carry in input for the ALU. |
mar_in | 1 | Instructs the memory address register to store the value on the bus. |
ram_in | 1 | Instructs the RAM to store the value on the bus. |
ram_out | 1 | Instructs the RAM to assert it’s content onto the bus. |
ram_sel_data_mem | 1 | When low, the RAM will operate on program memory, when high, data memory. |
sp_in | 1 | Instructs the stack pointer to store the value on the bus. |
sp_out | 1 | Instructs the stack pointer to assert it’s content onto the bus. |
pc_in | 1 | Instructs the program counter to store the value on the bus. |
pc_out | 1 | Instructs the program counter to assert it’s content onto the bus. |
pc_count | 1 | Instructs the program counter to increment it’s value by one. |
ir_in | 1 | Instructs the instruction register to store the value on the bus. |
cu_step_reset | 1 | Resets the microcode step counter to 0. |
clock_halt | 1 | Halts the clock module (and thus the entire computer). |
A single instruction needs multiple steps (data transfers between modules, or operations on data by a module) to complete. See the Micro Code section for more details.
Implementation¶
EEPROMs¶
The control signals to set are decided by a large combinatorial logic setup. The instruction byte, flag bits and microcode step bits form the input and the varying control signals are the output.
There are 4 EEPROM chips, they are all fed the same input as an address. Each EEPROM is programmed so that at the address corresponding to the input bits, 8 of the control signals are stored as data. Each EEPROM holds an 8 bit wide “slice” of the output control signals.
This is visible in the logic block diagram:

The EEPROMs are in a vertical line, all fed the same inputs and each EEPROM outputs it’s own slice.
Mirror Registers¶
As per the video by James Bates, mirror registers are used to store the instruction byte and flag bits on a rising control_clock. This is so that the control signals remain constant when the data_clock rises.
The instruction byte and flags bits partly determine the control signals, having the control signals change while the clock is rising could lead to unpredictable results.
The circled area below demonstrates the problem. The rising data clock and control signals change at almost same time. The EEPROM outputs settling and whatever propagation delay happens to have accumulated elsewhere in the computer affect the exact timing:

With the mirror register we can control the time that the control signals change to be at a safe distance from the rising data_clock edge:

Microcode Steps¶
A 4 bit counter is used to keep track of the microcode steps in each instruction. There are a maximum of 8 steps in any one instruction so only 3 bits are used. The count is increased on each rising control_clock. The control unit can reset the count before the 8th step is reached to save executing “empty” micro cycles. This is achieved synchronously enabling the parallel load functionality of the 74HCT161. For more details about the microcode steps see the Micro Code section.
Hardware¶
The following electronics are used:
- A 74HCT377 is used for the mirror instruction register.
- A 74HCT173 is used for the mirror flag bits.
- A 74HCT04 is used to invert the incoming control signal that causes the counter to reset and the master reset signal.
- A 74HCT161 is used to provide the counting, loading, and resetting behaviour (much like the program counter).
- A 74HCT138 is used to convert the 3 bit binary number of the microcode step to an individual signal for each step (purely for aesthetic/blinky blinky reasons :))
- 4 x AT28C256 EEPROM chips are used to hold the combinational logic/microcode.
- LEDs and resistors are used to provide display of the data.
They are laid out as follows:
- Step counter, mirror flags and mirror instruction byte.
- Display of the above and microcode step format conversion.
- EEPROMs 2 and 3
- EEPROMs 0 and 1
- Control signal output and display.

Arithmetic Logic Unit¶
The Arithmetic Logic Unit (ALU) performs arithmetical and logical operations using one or both of it’s inputs. The result is stored internally when desired and the value of that internal storage is also output when desired.
As well as calculating the result, pieces of information (flags) about the result or the two inputs are also stored internally when desired and the state of that internal storage is always output.
Interface and Operation¶
This is the interface of the ALU:

This is how it operates:
Name | Bit width | Description |
---|---|---|
carry_in | 1 | If high, supply a carry in to the arithmetical operation. For subtraction operations this becomes an active low borrow_in. |
M | 1 | Choose between arithmetical and logical operations. |
S0-3 | 4 | Specify which arithmetical or logical operation. |
store_result | 1 | While high, the result of the operation will be stored internally on a rising clock egde. |
store_flags | 1 | While high, flags resulting from the current operation/inputs/result will be stored internally on a rising clock egde. |
output_stored_result | 1 | Assert the value of the stored result onto the result_stored connection. |
clock | 1 | A rising edge triggers result and flag storage if enabled. |
A | 8 | The A input to the operation. |
B | 8 | The B input to the operation. |
result_live | 8 | The result of the current operation with the current inputs. |
result_stored | 8 | The value of the stored result while output_stored_result is high, not connected otherwise. |
flags_live | 4 | Flags resulting from the current operation/inputs/result. |
flags_stored | 4 | The value of the stored flags. |
carry_in, M, and S0-3 are used to select from the available operations (from the datasheet).:

Not all of the operations are available for use in the computer, see the Language section for more details on which are available.
The output flags are:
Name | Description |
---|---|
zero | The output of the ALU is zero (All bits 0) |
negative | The output of the ALU is negative (when the 8 bits are read in 2’s compliment form. Also the same as the most significant bit being 1) |
carry_borrow | If the operation was an addition and the value is high, there was a carry bit, if low, no carry. If the operation was a subtraction and the value is low, there was a borrow, if high, no borrow. |
equality | When the ALU is in the appropriate mode, this flag indicates the A and B inputs are equal. |
Implementation¶
The logical arrangement of the ALU is like this:

A Safe Clock Enable circuit is only required in the Logisim version. It’s natively implemented in the 74HCT377 and 74HCT173 chips.
OR gates are used to OR all the bits together and then the result inverted to calculate the zero flag.
The most significant bit of the output is the negative flag.
The carry_borrow flag and the equality flag are output from the ALU (the carryborrow flag is inverted).
The following electronics are used:
- 2 x 74LS181 are used for the arithmetic and logic operations.
- A 74CHT00 is used to AND the two A=B outputs and invert carry_borrow_out.
- A 74HCT173 is used to store the flags.
- 2 x 74HCT32s are used to OR all the bits to check if it’s zero.
- A 74HCT04 is used to invert the result of the OR zero check, the store_flags control signal and the carry_borrow input signal.
- A 74HCT245 is used to provide tri-state buffering for result_stored to go onto the bus.
- A 74HCT377 stores the result of the operation from result_live.
- Another 74HCT04 is used to invert the store_result and output_stored_result signals as this inputs are active low.
The ALU resides on three breadboards. From top to bottom:
- ALU chips
- Zero checking and flag storage
- Result storage and output

Language¶
The language of the computer is broadly defined with the following terms:
Name | Description |
---|---|
Assembly / Assembly code | Collective name for operations in sequence to form a program. The input to the assembler. |
Token | A set of characters separated from other characters by spaces at the beginning and end. E.g the assembly line LOAD [#123] B has 3 tokens: LOAD [#123] and B . |
Operation | A specific, simple step that the computer can perform. E.g. add the value in a given register to the accumulator, or copy a value in one register to another. |
Operation code / Op code | A unique code used to identify an operation, e.g. AND , JUMP , or ADD . |
Operation Argument | A value passed to an operation to specify it’s behaviour. E.g. passing B to the ADD operation to specify that the value in register B should be added to the accumulator register. |
Instruction | A fully specified operation, e.g. a copy from B to C or setting the A register to a value. Effectively a line of assembly. |
Instruction byte | A byte that uniquely identifies an instruction. |
Machine code | Collective name for the bytes in program memory that form the instructions and constants of a program. The assembler generates machine code. |
Machine code byte | A byte that makes up machine code. Could be an instruction or an constant value. |
Microcode | The pattern of bits that determine the control signals to operate the computer to complete an instruction. The Control Unit contains microcode. |
Microcode Step | A single transfer of data via the bus or action of a module occurring on a rising clock edge. The smallest, most specific level of control. An instruction is completed by doing a number of microcode steps. |
See the language table (or
download it
) for a complete listing
of all the machine code and operations with their arguments. The table is
sortable by clicking on the headers (but it’s a little slow).
Assembly¶
Assembly code provides a way to specify instructions for the computer to perform in a more human readable from than machine code
Assembly operations and arguments to specify their behaviour can be saved in an assembly file and passed to an assembler to convert them to machine code that the computer can then execute.
These are the operations and other assembly constructs that can be used to create a valid assembly file.
Arithmetic Operations¶
ADD¶
The ADD
operation adds the value held in the specified module (or a
constant) to the accumulator. The ALU flags generated by this operation are
stored.
The possible usages are:
ADD A
ADD B
ADD C
ADD CONST
ADDC¶
SUB¶
SUBB¶
LSHIFT¶
LSHIFTC¶
INCR¶
DECR¶
Data Operations¶
COPY¶
The COPY
operation copies the value from a source module to a destination
module. This overwrites the current value of the destination register. It
requires a single machine code byte in program memory.
It is used by specifying the source module as the first argument and the destination module as the second.
The possible usages are:
COPY ACC A
COPY ACC B
COPY ACC C
COPY ACC SP
COPY A ACC
COPY A B
COPY A C
COPY A SP
COPY B ACC
COPY B A
COPY B C
COPY B SP
COPY C ACC
COPY C A
COPY C B
COPY C SP
COPY PC ACC
COPY PC A
COPY PC B
COPY PC C
COPY PC SP
COPY SP ACC
COPY SP A
COPY SP B
COPY SP C
LOAD¶
The LOAD
operation loads a value from data memory into a module.
It is used by specifying the position in memory as the first argument and the destination module as the second. The position in memory can be a module or a constant and is encased in square parentheses.
The possible usages are:
LOAD [ACC] ACC
LOAD [ACC] A
LOAD [ACC] B
LOAD [ACC] C
LOAD [A] ACC
LOAD [A] A
LOAD [A] B
LOAD [A] C
LOAD [B] ACC
LOAD [B] A
LOAD [B] B
LOAD [B] C
LOAD [C] ACC
LOAD [C] A
LOAD [C] B
LOAD [C] C
LOAD [PC] ACC
LOAD [PC] A
LOAD [PC] B
LOAD [PC] C
LOAD [SP] ACC
LOAD [SP] A
LOAD [SP] B
LOAD [SP] C
LOAD [CONST] ACC
LOAD [CONST] A
LOAD [CONST] B
LOAD [CONST] C
STORE¶
PROGLOAD¶
PROGSTORE¶
PUSH¶
POP¶
SET¶
The SET
operation will set a module in the computer to a given
constant value.
It is used by specifying a module as the first argument, then the value to set it to as a constant.
It requires two machine code bytes in program memory. Consider the SETZERO operation if the constant is zero.
The possible usages are:
SET ACC CONST
SET A CONST
SET B CONST
SET C CONST
SET SP CONST
SETZERO¶
Program Control Operations¶
NOOP¶
JUMP¶
The JUMP
operation will set the program counter to a value.
The possible usages are:
JUMP ACC
JUMP A
JUMP B
JUMP C
JUMP SP
JUMP CONST
JUMP [ACC]
JUMP [A]
JUMP [B]
JUMP [C]
JUMP [SP]
JUMP [PC]
JUMP [CONST]
JUMP_IF_LT_ACC¶
JUMP_IF_LTE_ACC¶
JUMP_IF_EQ_ACC¶
JUMP_IF_GTEQ_ACC¶
JUMP_IF_GT_ACC¶
JUMP_IF_EQ_ZERO¶
JUMP_IF_POSITIVE_FLAG¶
JUMP_IF_NEGATIVE_FLAG¶
JUMP_IF_OVERFLOW_FLAG¶
The JUMP_IF_OVERFLOW_FLAG
operation will set the program counter to the
value of a given constant if the overflow flag is high.
The possible usages are:
JUMP_IF_OVERFLOW_FLAG CONST
JUMP_IF_NOT_OVERFLOW_FLAG¶
JUMP_IF_UNDERFLOW_FLAG¶
JUMP_IF_NOT_UNDERFLOW_FLAG¶
JUMP_IF_ZERO_FLAG¶
JUMP_IF_NOT_ZERO_FLAG¶
CALL¶
RETURN¶
HALT¶
Constants¶
Constants are values that the assembler will convert to machine code bytes for operations that require data in the machine code. For example, a jump to an explicit index in program memory, or setting a register to an explicit value.
Labels¶
A label binds to the line of assembly that follows it. Once assembly is complete the label’s value is the index in program memory of the instruction byte that followed the label definition. E.g. If an assembly file looked like this:
LOAD [#123] A
ADD A
@label
SET B #42
The value of @label
would be 3. The instruction byte corresponding to SET
B #42
is at program memory index 3. LOAD [#123] A
takes 2 bytes, ADD A
one, and SET B #42
is the byte after that.
Labels are typically used by jump operations.
A label is a token that starts with the @
character followed by any letter or
an underscore, then any alphanumeric or an underscore. E.g.:
@label
@label_1
@_other_label
Labels must be unique.
A label is defined by putting it on a line by itself.
Variables¶
Variables are named aliases for indexes into data memory. They can be predeclared by putting them by themselves on a line or declared as they are used by using them as an argument.
The index for a given variable is determined by the assembler. As it parses assembly lines from the start of the file to the end, addresses are assigned to variables as they are encountered in the file. E.g. for the following assembly:
$variable1
COPY A ACC
LOAD [$variable2] A
variable1 is predeclared, variable2 is declared as it’s used. Once assembled, variable1 is an alias for 0, variable2 is an alias for 2.
A variable is a token that starts with the $
character followed by any letter or
an underscore, then any alphanumeric or an underscore. E.g.:
$variable
$variable1
$_other_variable
Numbers¶
Numbers are integer values. In most cases they within the range -127 to 255 (inclusive). This range comes from the minimum and maximum values that 8 bits, or 8 bits with 2’s compliment encoding can hold.
A number is a token that starts with the #
character and is followed by any
valid Python integer definition. E.g.
#123
(decimal)#-5
(decimal)#0b00010010
(binary)#-0b0101
(binary)#0xA2
(hex)#0o107
(octal)
Comments¶
Comments are parts of the assembly file ignored by the assembler.
A comment is anything after and including //
on a line until the end of the
line.
Machine Code¶
The computer is directly controlled by machine code. It is stored in program memory. The machine code is stored as 8 bit bytes.
Machine code consists of instruction bytes and constant bytes. Instruction bytes encode a particular instruction (e.g. copying the value in register A to register B), constant bytes encode a value that an operation may require (e.g. setting the A register to 42).
There are 256 possible instruction bytes, most of these are occupied by the instruction set. They are organised using the grouping described below. This is very much inspired by how James Bates organised his machine code.
See the language table (or
download it
) for a complete listing
of all the machine code and operations with their arguments. The table is
sortable by clicking on the headers (but it’s a little slow).
Instruction Groups¶
The first two bytes of an instruction byte always represent the instruction group. There are 4 groups:
Bit value | Group Name |
---|---|
00...... |
Copy |
01...... |
Load |
10...... |
Store |
11...... |
ALU |
Sources and destinations¶
For copy, load and store instructions, the third to fifth, and sixth to eighth bytes are the source and destination respectively.
The table below only shows the source codes for brevity. The destination bits
are the last 3 bits, e.g.: .....000
and have the same name and meaning.
Bit value | Name | Meaning |
---|---|---|
..000... |
ACC | The accumulator register. |
..001... |
A | The A register. |
..010... |
B | The B register. |
..011... |
C | The C register. |
..100... |
SP | The stack pointer. |
..101... |
PC | The program counter |
..110... |
SP+/- | The stack pointer, preceded or followed by incrementing or decrementing it. |
..111... |
CONST | A constant value. |
ALU Operations¶
There are 16 ALU operations and they are identified with bits 3-6 of the instruction byte when the operation group is ALU. The operations and codes are:
Bit value | Name | Meaning |
---|---|---|
110000.. |
ZERO | The ALU will output zero. |
110001.. |
INCR | The argument supplied will be incremented by 1. |
110010.. |
DECR | The argument supplied will be decremented by 1. |
110011.. |
ADD | The argument will be added to the accumulator. |
110100.. |
ADDC | The argument will be added to the accumulator and one will be added if the last add resulted in a carry. |
110101.. |
SUB | The argument will be subtracted from the accumulator. |
110110.. |
SUBB | The argument will be subtracted from the accumulator and one will be subtracted if the last subtraction resulted in a borrow. |
110111.. |
AND | The argument will be ANDed with the accumulator. |
111000.. |
NAND | The argument will be NANDed with the accumulator. |
111001.. |
OR | The argument will be ORed with the accumulator. |
111010.. |
NOR | The argument will be NORed with the accumulator. |
111011.. |
XOR | The argument will be XORed with the accumulator. |
111100.. |
NXOR | The argument will be NXORed with the accumulator. |
111101.. |
NOT | The argument will have all it’s bits inverted |
111110.. |
LSHIFT | All the bits in the argument will move one place to the left (toward the most significant bit) |
111111.. |
LSHIFTC | All the bits in the argument will move one place to the left (toward the most significant bit). If the last shift resulted in a carry then the least significant bit is set to 1. |
ALU Arguments¶
ALU operations work on an argument. This is specified with bits 7 and 8 of the instruction byte when the operation group is ALU. The arguments and codes are:
Bit value | Argument |
---|---|
11....00 |
ACC |
11....01 |
A |
11....10 |
B |
11....11 |
C |
Instruction byte gaps¶
Not all source and destination combinations are valid or make sense. For example, copying the value in Register A to Register A has no purpose. In these cases, those instructions are re purposed for other instructions.
These “instruction byte gaps” are:
Instruction byte(s) | Explanation | Used by |
---|---|---|
|
Copying a register to itself. | JUMP_IF_XXX_FLAG |
00110... |
Copy from SP+/-. Ambiguous. | JUMP_IF_LT_ACC |
00...110 |
Copy to SP+/-. Ambiguous. | JUMP_IF_LTE_ACC |
00...111 |
Copy to a constant. Constants cannot be written to. | JUMP_IF_EQ_ACC |
01...100 |
Loading into SP. SP has a dedicated register, instead a load to a register then copy. | JUMP_IF_GTE_ACC |
01...110 |
Loading into SP+/-. SP+/- cannot be written to. | CALL |
01...111 |
Loading into a constant. Constants cannot be written to. | PROGRAM_LOAD |
10110... |
Storing SP+/-. Ambiguous. | JUMP_IF_GT_ACC |
10100... |
Storing SP. SP has a dedicated register, instead copy to a register and store. | JUMP_IF_EQ_ZERO |
10111... |
Storing a constant value. Instead Set a register and store. | PROGRAM_STORE |
Fetch¶
To execute an instruction, the instruction byte must be loaded from program memory into the instruction register.
This is handled by the first two steps of every instruction which:
- Load the program counter into the memory address register.
- Load the instruction register with the data from program memory at increment the program counter ready for the next instruction.
Micro Code¶
Microcode is the encoding of what specific steps the computer should take to complete an instruction.
It is effectively a large combinational logic circuit where the inputs are the instruction byte, microcode step and flag bits and the outputs are the control signals to drive the modules. EEPROM chips are programmed and used to implement this combinational logic circuit. The same address is fed into 4 chips, differently programmed to get the 30 output bits.
Every instruction is comprised of up to six micro code steps. There are eight available but the first two are reserved for fetching the instruction byte itself. The steps are executed sequentially to perform the instruction. The microcode step counter controls the order of the sequence. The flags bits allow conditional operation based on a given instruction byte and step. An instruction can “surrender” it’s remaining steps and move onto the next instruction if it has completed all it’s necessary steps.
Address bits¶
The address bits for the EEPROM and their meanings are:
Bits | Meaning |
---|---|
xxxxxxxx....... |
Instruction byte |
........xxxx... |
Flags |
............xxx |
Microcode step |
Output bits¶
The output bits for the EEPROMs and their meanings (which will typically occur on the next rising data clock edge) are:
Bits | Name | Description |
---|---|---|
1....... ........ ........ ........ |
ACC_IN | Enable input for the accumulator register. |
.1...... ........ ........ ........ |
ACC_OUT | Enable output for the accumulator register. |
..1..... ........ ........ ........ |
A_IN | Enable input for the A register. |
...1.... ........ ........ ........ |
A_OUT | Enable output for the A register. |
....1... ........ ........ ........ |
B_IN | Enable input for the B register. |
.....1.. ........ ........ ........ |
B_OUT | Enable output for the B register. |
......1. ........ ........ ........ |
C_IN | Enable input for the C register. |
.......1 ........ ........ ........ |
C_OUT | Enable output for the C register. |
........ 1....... ........ ........ |
ALU_STORE_RESULT | Store the current output of the ALU. |
........ .1...... ........ ........ |
ALU_STORE_FLAGS | Store the current flags of the ALU.. |
........ ..1..... ........ ........ |
ALU_OUT | Enable output for the ALU. |
........ ...1.... ........ ........ |
ALU_A_IS_BUS | Set the A input of the ALU to be the bus (otherwise it is the content of the accumulator register). |
........ ....1... ........ ........ |
ALU_S0 | Set the S0 function select input on the ALU. |
........ .....1.. ........ ........ |
ALU_S1 | Set the S1 function select input on the ALU. |
........ ......1. ........ ........ |
ALU_S2 | Set the S2 function select input on the ALU. |
........ .......1 ........ ........ |
ALU_S3 | Set the S3 function select input on the ALU. |
........ ........ 1....... ........ |
ALU_M | Set the M input on the ALU. |
........ ........ .1...... ........ |
ALU_C_IN | Set the carry in input on the ALU. |
........ ........ ..1..... ........ |
MAR_IN | Enable input for the memory address register. |
........ ........ ...1.... ........ |
RAM_IN | Enable input for the RAM. |
........ ........ ....1... ........ |
RAM_OUT | Enable output for the RAM. |
........ ........ .....1.. ........ |
RAM_SEL_PROG_MEM | Retrieve data from program memory rather than data memory. |
........ ........ ......1. ........ |
SP_IN | Enable input for the stack pointer. |
........ ........ .......1 ........ |
SP_OUT | Enable output for the stack pointer. |
........ ........ ........ 1....... |
PC_IN | Enable input for the program counter. |
........ ........ ........ .1...... |
PC_OUT | Enable output for the program counter. |
........ ........ ........ ..1..... |
PC_COUNT | Increment the value stored in the program counter. |
........ ........ ........ ...1.... |
IR_IN | Enable input for the instruction register. |
........ ........ ........ ....1... |
CU_STEP_RESET | Reset the step counter in the control unit. |
........ ........ ........ .....1.. |
CLOCK_HALT | Halt the computer. |
Hardware¶
HCT vs. LS¶
Fanout¶
Materials and Tools¶
Edge Detection¶
Debouncing¶
EEPROM Programmer¶
Safe Clock Enable¶
Makes sure that when reset is released, only the next rising clock edge is passed on. If only an AND gate was used, a rising edge would pass through if the clock was already high, and (an inverted) reset signal went low.
Open Collector Outputs¶
Software¶
Assembler¶
The assembler
module is responsible for taking lines
of assembly code and processing it to generate equivalent machine code.
It is passed a list of strings which are the lines of the assembly file. Each
line is then processed and the information about the line stored in a
dictionary
.
During processing each line is checked to see if it’s a constant definition, if
not, it’s treated as an assembly line and
parsed into machine code bytes
.
The line is passed to each operation
to attempt to
generate the machine code bytes. The operations can expect certain tokens on the
line to be constants and are identified as such and returned to the assembler.
The constants are then validated and identified
and the machine code bytes added to the
dictionary of information about the line of assembly.
With all the lines processed, machine code bytes generated and constants
identified, the assembler checks for overall validity and structure
The assembler then performs global operations that
need to take the entire assembly code into account:
Assigning indexes to the machine code bytes
Assigning labels to machine code bytes
Resolving labels to indexes in program memory
Resolving number constants to bytes
Resolving variable constants to indexes in data memory
With these checks, assignments and resolutions complete, the final assembly line dictionaries are returned.
Command Line Tools¶
ebc-assemble¶
Assemble eight bit computer assembly files to machine code.
usage: ebc-assemble [-h] [-o OUTPUT_FILEPATH] [-s VARIABLE_START_OFFSET]
[-f {logisim,cpp}]
asm_filepath
Positional Arguments¶
asm_filepath | Path to the assembly file to assemble. |
Named Arguments¶
-o, --output_filepath | |
Filepath to write the machine code to. E.g. “../machine_code.mc”. Including ./ for a file in the current directory is optional. | |
-s, --variable_start_offset | |
Index in data memory to start assigning automatically assigned variables at. Default: 0 | |
-f, --output_format | |
Possible choices: logisim, cpp Format to write the machine code in. Default: “logisim” |
ebc-gen-roms¶
Generate ROMs that contain the microcode.
usage: ebc-gen-roms [-h] [-o OUTPUT_DIR] [-p ROM_PREFIX] [-f {logisim,cpp}]
Named Arguments¶
-o, --output_dir | |
Directory to write the ROMs into. Default: “.” | |
-p, --rom_prefix | |
Prefix for the ROM files. Default: “rom” | |
-f, --output_format | |
Possible choices: logisim, cpp Format to write the ROMs in. Default: “logisim” |
eight_bit_computer package¶
Subpackages¶
eight_bit_computer.operations package¶
Submodules¶
ADD Operation
-
eight_bit_computer.operations.add.
generate_microcode_templates
()[source]¶ Generate microcode for all the ADD instructions.
Returns: DataTemplates for all the ADD instructions. Return type: list(DataTemplate)
-
eight_bit_computer.operations.add.
parse_line
(line)[source]¶ Parse a line of assembly code to create machine code byte templates.
If a line is not identifiably a ADD assembly line, return an empty list instead.
Parameters: line (str) – Assembly line to be parsed. Returns: List of machine code byte template dictionaries or an empty list. Return type: list(dict)
The COPY operation.
Copies a value from one module into another.
-
eight_bit_computer.operations.copy_op.
generate_signatures
()[source]¶ Generate the definitions of all possible arguments passable.
Returns: All possible arguments. See get_arg_def_template()
for more information.Return type: list(list(dict))
-
eight_bit_computer.operations.copy_op.
generate_microcode_templates
()[source]¶ Generate microcode for all the COPY operations.
Returns: DataTemplates for all the COPY microcode. Return type: list(DataTemplate)
-
eight_bit_computer.operations.copy_op.
generate_operation_templates
(signature)[source]¶ Create the DataTemplates to define a copy with the given args.
Parameters: signature (list(dict)) – List of argument definitions that specify which particular copy operation to generate templates for. Returns: Datatemplates that define this copy. Return type: list(DataTemplate)
-
eight_bit_computer.operations.copy_op.
generate_instruction_byte_bitdefs
(signature)[source]¶ Generate bitdefs to specify the instruction byte for these args.
Parameters: signature (list(dict)) – List of argument definitions that specify which particular copy operation to generate the instruction byte bitdefs for. Returns: Bitdefs that make up the instruction_byte Return type: list(str)
-
eight_bit_computer.operations.copy_op.
parse_line
(line)[source]¶ Parse a line of assembly code to create machine code byte templates.
If a line is not identifiably a COPY assembly line, return an empty list instead.
Parameters: line (str) – Assembly line to be parsed. Returns: List of instruction byte template dictionaries or an empty list. Return type: list(dict)
The fetch steps added to the start of all operations.
-
eight_bit_computer.operations.fetch.
generate_microcode_templates
()[source]¶ Generate datatemplates for all the fetch steps.
Returns: Datatemplates that represent the fetch steps. Return type: list(DataTemplate)
-
eight_bit_computer.operations.fetch.
fetch_step_0
()[source]¶ Create template for the first fetch step.
Returns: The first fetch step. Return type: DataTemplate
-
eight_bit_computer.operations.fetch.
fetch_step_1
()[source]¶ Create template for the second fetch step.
Returns: The second fetch step. Return type: DataTemplate
JUMP Operation
-
eight_bit_computer.operations.jump.
generate_microcode_templates
()[source]¶ Generate microcode for all the JUMP instructions.
Returns: DataTemplates for all the JUMP instructions. Return type: list(DataTemplate)
-
eight_bit_computer.operations.jump.
generate_signatures
()[source]¶ Generate all the argument signatures for the jump operation.
Returns: All possible signatures, See get_arg_def_template()
for more information on an argument definition dictionary.Return type: list(list(dict))
-
eight_bit_computer.operations.jump.
generate_operation_templates
(signature)[source]¶ Create the DataTemplates to define a JUMP with the given signature.
Parameters: signature (list(dict)) – List of argument definitions that specify which particular JUMP operation to generate templates for. Returns: Datatemplates that define this JUMP. Return type: list(DataTemplate)
-
eight_bit_computer.operations.jump.
generate_instruction_byte_bitdefs
(signature)[source]¶ Generate bitdefs to specify the instruction byte for this signature.
Parameters: signature (list(dict)) – List of argument definitions that specify which particular JUMP operation to generate the instruction byte bitdefs for. Returns: Bitdefs that make up the instruction_byte Return type: list(str)
-
eight_bit_computer.operations.jump.
generate_control_steps
(signature)[source]¶ Generate control steps for this signature.
Parameters: signature (list(dict)) – List of argument definitions that specify which particular JUMP operation to generate the control steps for. Returns: List of list of bitdefs that specify the control steps. Return type: list(list(str))
-
eight_bit_computer.operations.jump.
parse_line
(line)[source]¶ Parse a line of assembly code to create machine code byte templates.
If a line is not identifiably a LOAD assembly line, return an empty list instead.
Parameters: line (str) – Assembly line to be parsed. Returns: List of machine code byte template dictionaries or an empty list. Return type: list(dict)
-
eight_bit_computer.operations.jump_if_flag_base.
generate_microcode_templates
(src_dest, true_flag_bitdef, false_flag_bitdef)[source]¶ Generate microcode for all the JUMP_IF_XXX_FLAG instructions.
Parameters: - src_dest (str) – Name of the module used for both the source and destination.
- true_flag_bitdef (str) – Bitdef that represents the state of the flags if the condition is true, i.e. the operation should jump.
- false_flag_bitdef (str) – Bitdef that represents the state of the flags if the condition is false, i.e. the operation should not jump and just execute the next instruction instead.
Returns: DataTemplates for all the JUMP_IF_XXX_FLAG instructions.
Return type: list(DataTemplate)
-
eight_bit_computer.operations.jump_if_flag_base.
generate_instruction_byte_bitdefs
(src_dest)[source]¶ Generate bitdefs to specify the instruction byte
Parameters: src_dest (str) – Name of the module used for both the source and destination. Returns: Bitdefs that make up the instruction_byte Return type: list(str)
-
eight_bit_computer.operations.jump_if_flag_base.
generate_true_control_steps
()[source]¶ Generate control steps to carry out the jump.
Returns: List of list of bitdefs that specify the control steps. Return type: list(list(str))
-
eight_bit_computer.operations.jump_if_flag_base.
parse_line
(line, src_dest, name)[source]¶ Parse a line of assembly code to create machine code byte templates.
If a line is not identifiably a JUMP_IF_XXX_FLAG assembly line, return an empty list instead.
Parameters: - line (str) – Assembly line to be parsed.
- src_dest (str) – Name of the module used for both the source and destination.
- name (str) – Name of the Operation.
Returns: List of machine code byte template dictionaries or an empty list.
Return type: list(dict)
-
eight_bit_computer.operations.jump_if_flag_base.
generate_signatures
()[source]¶ Generate all the argument signatures for the JUMP_IF_XXX_FLAG operation.
Returns: All possible signatures, See get_arg_def_template()
for more information on an argument definition dictionary.Return type: list(list(dict))
JUMP_IF_OVERFLOW_FLAG operation
-
eight_bit_computer.operations.jump_if_overflow_flag.
generate_microcode_templates
()[source]¶ Generate microcode for all the JUMP_IF_OVERFLOW_FLAG instructions.
Returns: DataTemplates for all the JUMP_IF_OVERFLOW_FLAG instructions. Return type: list(DataTemplate)
-
eight_bit_computer.operations.jump_if_overflow_flag.
parse_line
(line)[source]¶ Parse a line of assembly code to create machine code byte templates.
If a line is not identifiably a JUMP_IF_OVERFLOW_FLAG assembly line, return an empty list instead.
Parameters: line (str) – Assembly line to be parsed. Returns: List of machine code byte template dictionaries or an empty list. Return type: list(dict)
The LOAD operation.
Loads a value from data memory into a module.
-
eight_bit_computer.operations.load.
generate_microcode_templates
()[source]¶ Generate microcode for all the LOAD instructions.
Returns: DataTemplates for all the LOAD instructions. Return type: list(DataTemplate)
-
eight_bit_computer.operations.load.
generate_signatures
()[source]¶ Generate the definitions of all possible arguments passable.
Returns: All possible arguments. See get_arg_def_template()
for more information.Return type: list(list(dict))
-
eight_bit_computer.operations.load.
generate_operation_templates
(signature)[source]¶ Create the DataTemplates to define a load with the given args.
Parameters: signature (list(dict)) – List of argument definitions that specify which particular load operation to generate templates for. Returns: Datatemplates that define this load. Return type: list(DataTemplate)
-
eight_bit_computer.operations.load.
generate_instruction_byte_bitdefs
(signature)[source]¶ Generate bitdefs to specify the instruction byte for these args.
Parameters: signature (list(dict)) – List of argument definitions that specify which particular LOAD operation to generate the instruction byte bitdefs for. Returns: Bitdefs that make up the instruction_byte Return type: list(str)
-
eight_bit_computer.operations.load.
generate_control_steps
(signature)[source]¶ Generate control steps for these args.
Parameters: signature (list(dict)) – List of argument definitions that specify which particular load operation to generate the control steps for. Returns: List of list of bitdefs that specify the control steps. Return type: list(list(str))
-
eight_bit_computer.operations.load.
parse_line
(line)[source]¶ Parse a line of assembly code to create machine code byte templates.
If a line is not identifiably a LOAD assembly line, return an empty list instead.
Parameters: line (str) – Assembly line to be parsed. Returns: List of machine code byte template dictionaries or an empty list. Return type: list(dict)
Template for operation module
-
eight_bit_computer.operations.operation_template.
generate_microcode_templates
()[source]¶ Generate microcode for all the OP_TEMPLATE instructions.
Returns: DataTemplates for all the OP_TEMPLATE instructions. Return type: list(DataTemplate)
-
eight_bit_computer.operations.operation_template.
generate_signatures
()[source]¶ Generate all the argument signatures for the OP_TEMPLATE operation.
Returns: All possible signatures, See get_arg_def_template()
for more information on an argument definition dictionary.Return type: list(list(dict))
-
eight_bit_computer.operations.operation_template.
generate_operation_templates
(signature)[source]¶ Create the DataTemplates to define a OP_TEMPLATE with the given signature.
Parameters: signature (list(dict)) – List of argument definitions that specify which particular OP_TEMPLATE operation to generate templates for. Returns: DataTemplates that define this OP_TEMPLATE. Return type: list(DataTemplate)
-
eight_bit_computer.operations.operation_template.
generate_instruction_byte_bitdefs
(signature)[source]¶ Generate bitdefs to specify the instruction byte for this signature.
Parameters: signature (list(dict)) – List of argument definitions that specify which particular OP_TEMPLATE operation to generate the instruction byte bitdefs for. Returns: Bitdefs that make up the instruction_byte Return type: list(str)
-
eight_bit_computer.operations.operation_template.
generate_control_steps
(signature)[source]¶ Generate control steps for this signature.
Parameters: signature (list(dict)) – List of argument definitions that specify which particular OP_TEMPLATE operation to generate the control steps for. Returns: List of list of bitdefs that specify the control steps. Return type: list(list(str))
-
eight_bit_computer.operations.operation_template.
parse_line
(line)[source]¶ Parse a line of assembly code to create machine code byte templates.
If a line is not identifiably a OP_TEMPLATE assembly line, return an empty list instead.
Parameters: line (str) – Assembly line to be parsed. Returns: List of machine code byte template dictionaries or an empty list. Return type: list(dict)
The set operation.
Sets a module to a certain value.
-
eight_bit_computer.operations.set_op.
generate_signatures
()[source]¶ Generate the definitions of all possible arguments passable.
Returns: All possible arguments. See get_arg_def_template()
for more information.Return type: list(list(dict))
-
eight_bit_computer.operations.set_op.
generate_microcode_templates
()[source]¶ Generate datatemplates for all the SET operations.
Returns: All the datatemplates that make up the SET operation. Return type: list(DataTemplate)
-
eight_bit_computer.operations.set_op.
generate_instruction_byte_bitdefs
(signature)[source]¶ Generate bitdefs to specify the instruction byte for these args.
Parameters: signature (list(dict)) – List of argument definitions that specify which particular set operation to generate the instruction byte bitdefs for. Returns: Bitdefs that make up the instruction byte. Return type: list(str)
-
eight_bit_computer.operations.set_op.
parse_line
(line)[source]¶ Parse a line of assembly code to create machine code byte templates.
If a line is not identifiably a SET assembly line, return an empty list instead.
Parameters: line (str) – Assembly line to be parsed. Returns: List of instruction byte template dictionaries or an empty list. Return type: list(dict) Raises: OperationParsingError
– If the line was identifiably a SET operation but incorrectly specified.
Base for simple ALU operations
-
eight_bit_computer.operations.simple_alu_op_base.
generate_microcode_templates
(alu_op, control_flags)[source]¶ Generate microcode for all the ADD instructions.
Parameters: - alu_op (str) – The ALU operation to perform - one of the ALU_OPERATIONS.
- control_flags (list(str)) – List of ALU control flags for this ALU operation. One of the ALU_CONTROL_FLAGS.
Returns: DataTemplates for all the ADD instructions.
Return type: list(DataTemplate)
-
eight_bit_computer.operations.simple_alu_op_base.
generate_signatures
()[source]¶ Generate all the argument signatures for the ADD operation.
Returns: All possible signatures, See get_arg_def_template()
for more information on an argument definition dictionary.Return type: list(list(dict))
-
eight_bit_computer.operations.simple_alu_op_base.
generate_operation_templates
(signature, alu_op, control_flags)[source]¶ Create the DataTemplates to define a ADD with the given signature.
Parameters: - signature (list(dict)) – List of argument definitions that specify which particular ADD operation to generate templates for.
- alu_op (str) – The ALU operation to perform - one of the ALU_OPERATIONS.
- control_flags (list(str)) – List of ALU control flags for this ALU operation. One of the ALU_CONTROL_FLAGS.
Returns: DataTemplates that define this ADD.
Return type: list(DataTemplate)
-
eight_bit_computer.operations.simple_alu_op_base.
generate_instruction_byte_bitdefs
(signature, alu_op)[source]¶ Generate bitdefs to specify the instruction byte for this signature.
Parameters: - signature (list(dict)) – List of argument definitions that specify which particular ADD operation to generate the instruction byte bitdefs for.
- alu_op (str) – The ALU operation to perform - one of the ALU_OPERATIONS.
Returns: Bitdefs that make up the instruction_byte
Return type: list(str)
-
eight_bit_computer.operations.simple_alu_op_base.
generate_control_steps
(signature, control_flags)[source]¶ Generate control steps for this signature.
Parameters: - signature (list(dict)) – List of argument definitions that specify which particular ADD operation to generate the control steps for.
- control_flags (list(str)) – List of ALU control flags for this ALU operation. One of the ALU_CONTROL_FLAGS.
Returns: List of list of bitdefs that specify the control steps.
Return type: list(list(str))
-
eight_bit_computer.operations.simple_alu_op_base.
parse_line
(line, name, alu_op)[source]¶ Parse a line of assembly code to create machine code byte templates.
If a line is not identifiably a ADD assembly line, return an empty list instead.
Parameters: - line (str) – Assembly line to be parsed.
- name (str) – Name of the Operation.
- alu_op (str) – The ALU operation to perform - one of the ALU_OPERATIONS.
Returns: List of machine code byte template dictionaries or an empty list.
Return type: list(dict)
Module contents¶
Operations in the assembly language
-
eight_bit_computer.operations.
get_all_operations
()[source]¶ Get a list of all the operations in the assembly language
Deferring the import to the function so that importing the operations module doesn’t mean automatically importing all the operations.
Returns: All the modules that represent operations in the assembly language Return type: list(module)
Submodules¶
eight_bit_computer.assembler module¶
Process assembly code and output machine code.
-
eight_bit_computer.assembler.
process_assembly_lines
(lines, variable_start_offset=0)[source]¶ Parse, assemble and generate machine code.
Parameters: - lines (list(str)) – The lines that made up the assembly file to be assembled.
- variable_start_offset (int) (optional) – How far to offset the first variable in data memory from 0.
Returns: The assembly file converted to an equivalent list of dictionaries with information about what each line was resolved to.
Return type: list(dict)
Raises: AssemblyError
– If there was an error assembling the machine code.
-
eight_bit_computer.assembler.
process_line
(line)[source]¶ Process a single line of assembly.
Parameters: line (str) – The line of assembly to process. This line has already been cleaned (excess whitespace and comments removed). Returns: A dictionary of information about this line. See the get_assembly_line_template()
documentation for more information about what is in the dictionary.Return type: dict
-
eight_bit_computer.assembler.
clean_line
(line)[source]¶ Clean a line of assembly ready for further processing.
Removes leading and trailing whitespace, comments, and excess whitespace between tokens.
Parameters: line (str) – The line to clean. Returns: The cleaned line. Return type: str
-
eight_bit_computer.assembler.
remove_comments
(line)[source]¶ Remove comments from a line.
A comment is anything on the line after and including an occurrence of
//
.Parameters: line (str) – line to remove comments from. Returns: The line with comments removed. Return type: str
-
eight_bit_computer.assembler.
remove_excess_whitespace
(line)[source]¶ Remove excess whitespace from a line.
Parameters: line (str) – line to remove excess whitespace from. Returns: The line with excess whitespace removed. Return type: str
-
eight_bit_computer.assembler.
machine_code_bytes_from_line
(line)[source]¶ Get machine code bytes that describe this line.
Uses all the defined instructions and defers the work of parsing to them. See
get_machine_code_byte_template()
for information on machine code dictionaries from instructions.Expects the passed in line to be a valid line of machine code. That is, the passed in line should be translatable to valid machine code.
Parameters: line (str) – Line to parse.
Returns: Machine code byte information dictionaries.
Return type: list(dict)
Raises: LineProcessingError
– Failure to extract machine code or matching- multiple operations.
-
eight_bit_computer.assembler.
validate_and_identify_constants
(machine_code_bytes)[source]¶ Validate and identify constants from assembly code.
Assumed constants are returned from the instruction parsers. This function then validates them to make sure they are correct and determines what kind of constant they are.
See
get_mc_byte_template()
for information on machine code dictionaries from instructions.This function modifies the passed in machine code templates list in place.
Parameters: machine_code_bytes (list(dict)) – The machine code byte dicts as returned by an instruction line parser. Raises: LineProcessingError
– Invalid constants were specified.
-
eight_bit_computer.assembler.
assign_machine_code_byte_indexes
(assembly_lines)[source]¶ Assign indexes to the machine code bytes.
This modifies the passed in list of assembly lines, adding data to it.
Parameters: - assembly_lines (list(dict)) – Lines of assembly to add label
- to. (information) –
-
eight_bit_computer.assembler.
assign_labels
(assembly_lines)[source]¶ Assign labels to the lines for later reference
This modifies the passed in list of assembly lines, adding data to it.
Parameters: - assembly_lines (list(dict)) – Lines of assembly to add label
- to. (information) –
-
eight_bit_computer.assembler.
resolve_labels
(assembly_lines)[source]¶ Resolve labels to indexes in the machine code bytes.
This modifies the passed in list of assembly line dictionaries.
Parameters: assembly_lines (list(dict)) – List of assembly lines to resolve label references in.
-
eight_bit_computer.assembler.
create_label_map
(assembly_lines)[source]¶ Create a map of labels to machine code byte indexes.
Parameters: assembly_lines (list(dict)) – List of assembly lines to create a label map for. Returns: str): Dictionary of label names to machine code indexes. Return type: dict(str
-
eight_bit_computer.assembler.
resolve_numbers
(assembly_lines)[source]¶ Resolve number constants to machine code byte values.
This modifies the passed in list of assembly line dictionaries.
Parameters: assembly_lines (list(dict)) – List of assembly lines to resolve numbers for.
-
eight_bit_computer.assembler.
resolve_variables
(assembly_lines, variable_start_offset)[source]¶ Resolve variable constants to indexes in data memory.
This modifies the passed in list of assembly line dictionaries.
Parameters: - assembly_lines (list(dict)) – List of assembly lines to resolve variables in.
- variable_start_offset (int) – An offset into data memory for where to start storing the variables.
-
eight_bit_computer.assembler.
create_variable_map
(assembly_lines, variable_start_offset)[source]¶ Create a map of variables to indexes in data memory.
Parameters: - assembly_lines (list(dict)) – List of assembly lines to create a variable map for.
- variable_start_offset (int) – An offset into data memory for where to start storing the variables.
Returns: str): Dictionary of variable names to machine code indexes.
Return type: dict(str
eight_bit_computer.assembly_summary module¶
Extract information from a list of assembly line info dictionaries.
-
eight_bit_computer.assembly_summary.
generate_assembly_summary
(asm_line_infos)[source]¶ Produce a summary that combines assembly and machine code.
The summary will be like this:
1 $variable0 | 2 @label1 | 3 LOAD [$variable1] A | 0 00 00000000 - @label1 255 FF 11111111 | 1 01 00000001 - 1 01 00000001 $variable1 4 | 5 @label2 | 6 LOAD [$variable2] A | 2 02 00000010 - @label2 255 FF 11111111 | 3 03 00000011 - 2 02 00000010 $variable2 7 JUMP @label1 | 4 04 00000100 - 255 FF 11111111 | 5 05 00000101 - 0 00 00000000 @label1 8 | 9 STORE A [#123] | 6 06 00000110 - 255 FF 11111111 | 7 07 00000111 - 123 7B 01111011 #123 10 @label3 | 11 LOAD [$variable3] B | 8 08 00001000 - @label3 255 FF 11111111 | 9 09 00001001 - 3 03 00000011 $variable3 12 LOAD [$variable0] C | 10 0A 00001010 - 255 FF 11111111 | 11 0B 00001011 - 0 00 00000000 $variable0 13 $variable4 | 14 // comment
Parameters: asm_line_infos (list(dict)) – List of dictionaries of information about the parsed assembly. Returns: Printable summary. Return type: str
-
eight_bit_computer.assembly_summary.
generate_assembly_summary_lines
(asm_line_infos)[source]¶ Generate list of lines for an assembly summary
Parameters: asm_line_infos (list(dict)) – List of dictionaries of information about the parsed assembly. Returns: List of lines for the summary. Return type: list(str)
-
eight_bit_computer.assembly_summary.
get_assembly_summary_data
(asm_line_infos)[source]¶ Process assembly data to make formatting easier for the summary.
Parameters: asm_line_infos (list(dict)) – List of line info dictionaries as returned by process_assembly_lines()
.Returns: List of entries for the assembly summary print out Return type: list
-
eight_bit_computer.assembly_summary.
get_widest_column_values
(assembly_summary_data)[source]¶ Find widest values in the columns of the output.
Required for the eventual printed table to line up correctly.
Parameters: assembly_summary_data (list(dict)) – List of dictionaries (as returned by get_assembly_summary_data()
) with all the summary information data.Returns: Mapping of columns for widest values. Return type: dict
eight_bit_computer.assembly_validity module¶
Validity checks on the processed assembly lines
-
eight_bit_computer.assembly_validity.
check_structure_validity
(asm_line_infos, variable_start_offset)[source]¶ Check the processed assembly lines for consistency/correctness.
Parameters: asm_line_infos (list(dict)) – List of dictionaries (conforming to get_assembly_line_template()
) with information about all the lines in the assembly file.
-
eight_bit_computer.assembly_validity.
check_multiple_label_defs
(asm_line_infos)[source]¶ Check if the same label been defined more than once.
Parameters: asm_line_infos (list(dict)) – List of dictionaries (conforming to get_assembly_line_template()
) with information about all the lines in the assembly file.Raises: AssemblyError
– If the same label been defined more than once.
-
eight_bit_computer.assembly_validity.
check_multiple_label_assignment
(asm_line_infos)[source]¶ Check if a single line been assigned more than one label.
Parameters: asm_line_infos (list(dict)) – List of dictionaries (conforming to get_assembly_line_template()
) with information about all the lines in the assembly file.Raises: AssemblyError
– If a single line been assigned more than one label.
-
eight_bit_computer.assembly_validity.
check_undefined_label_ref
(asm_line_infos)[source]¶ Check if an operation is using a label that hasn’t been defined.
Parameters: asm_line_infos (list(dict)) – List of dictionaries (conforming to get_assembly_line_template()
) with information about all the lines in the assembly file.Raises: AssemblyError
– If an operation is using a label that hasn’t been defined.
-
eight_bit_computer.assembly_validity.
check_multiple_variable_def
(asm_line_infos)[source]¶ Has the same variable been defined multiple times.
Parameters: asm_line_infos (list(dict)) – List of dictionaries (conforming to get_assembly_line_template()
) with information about all the lines in the assembly file.Raises: AssemblyError
– If a variable has been defined more than once.
-
eight_bit_computer.assembly_validity.
check_num_variables
(asm_line_infos, variable_start_offset)[source]¶ Check there are more variables defined than will fit in data mem.
There are 255 bytes of data memory available and the start offset may eat into this.
Parameters: - asm_line_infos (list(dict)) – List of dictionaries (conforming to
get_assembly_line_template()
) with information about all the lines in the assembly file. - variable_start_offset (int) – How far in memory to offset when defining the first variable.
Raises: AssemblyError
– If there are more variables defined than will fit in data memory.- asm_line_infos (list(dict)) – List of dictionaries (conforming to
-
eight_bit_computer.assembly_validity.
check_num_instruction_bytes
(assembly_lines)[source]¶ Check there aren’t too many instruction_bytes.
Parameters: asm_line_infos (list(dict)) – List of dictionaries (conforming to get_assembly_line_template()
) with information about all the lines in the assembly file.Raises: AssemblyError
– If there are more instruction bytes than will fit in program memory.
eight_bit_computer.bitdef module¶
The bitdef and associated functions.
A bitdef is a string made up of .
s, 0
s, and 1
s.
.
means that the bit at this position could be a 0 or a 1.0
means that the bit at this position is a 0.1
means that the bit at this position is a 1.
When indexing into a bitdef, indexes start at 0 and begin at the right hand side or least significant bit of the value. E.g.:
Index: 76543210
Bitdef: 010.1..1
-
eight_bit_computer.bitdef.
same_length
(bitdefs)[source]¶ Check if the passed in bitdefs are all the same length.
Parameters: list (bitdefs) – Bitdefs to check length of. Returns: True if all the bitdefs are the same length, False otherwise Return type: bool
-
eight_bit_computer.bitdef.
length
(bitdef)[source]¶ Calculate length of a bitdef.
Parameters: bitdef (str) – The bitdef to find the length of. Returns: The length of the bitdef. Return type: int
-
eight_bit_computer.bitdef.
have_overlapping_bits
(bitdefs)[source]¶ Check if the bitdefs have any bits set in the same position.
Example with overlap (bits at index 2 and 6 overlap):
0...101.
11...1..
Example with no overlap:
11010...
......11
Parameters: bitdefs (list(str)) – Bitdefs to check for overlaps. Returns: Whether or not there were overlaps. Return type: bool
-
eight_bit_computer.bitdef.
merge
(bitdefs)[source]¶ Merge the bitdefs to a single bitdef.
Bitdefs must
- All be the same length.
- Not have any bits defined in the same position.
Parameters: bitdefs (list(str)) – Bitdefs to merge.
Returns: The merged bitdef.
Return type: str
Raises: ValueError
– If the bitdefs are not all the same length or have- overlapping bits.
-
eight_bit_computer.bitdef.
collapse
(bitdef)[source]¶ Collapse undefined bits into real bits to make new bitdefs.
The undefined bits are expanded in order, from left to right, with 0 first, then 1.
For example,
10.0.
becomes:10000
10001
10100
10101
Parameters: bitdef (str) – The bitdef to collapse. Returns: The list of bitdefs the original bitdef has collapsed to. Return type: list(str)
-
eight_bit_computer.bitdef.
fill
(bitdef, value)[source]¶ Fill undefined bits with a value.
For example
1..0100.1
becomes111010011
when filled with 1s.Parameters: - bitdef (str) – The bitdef to fill.
- value (str) – The value to fill with, “0” or “1”.
Returns: The filled bitdef.
Return type: str
-
eight_bit_computer.bitdef.
extract_bits
(bitdef, end, start)[source]¶ Extract a region from the bitdef.
Indexes for start and end start at zero from the right or least significant bit.
For example, if the bitdef was
00101011
and the extraction end was 4 and start was 1 the result would be0101
:Extracted bits: xxxx Index: 76543210 Bitdef: 00101011 Result: 0101
Parameters: - bitdef (str) – The bitdef to extract bits from.
- end (int) – Index of the leftmost bit of the portion to extract.
- start (int) – Index of the rightmost bit of the portion to extract.
Returns: The extracted portion of the bitdef.
Return type: str
Raises: ValueError
– If:- Extraction region is larger than bitdef.
- Extraction end index is before extraction start index.
- Extraction start index is less than 0.
-
eight_bit_computer.bitdef.
remove_whitespace
(input_string)[source]¶ Remove the whitespace from a string.
Parameters: input_string (str) – The string to remove whitespace from. Returns: The string with the whitespace removed. Return type: str
-
eight_bit_computer.bitdef.
reverse_index
(index, length)[source]¶ Reverse the passed in index as if the index direction was flipped.
Taking the string “hello” as an example the regular indexes for each letter are:
01234 hello
Reversing the indexes yields:
43210 hello
This allows easily indexing into a bitdef on bitdef indexing terms.
Parameters: - index (int) – The index position to reverse.
- length (int) – The length of the array being indexed into.
Returns: The reversed index.
Return type: int
eight_bit_computer.cli module¶
-
eight_bit_computer.cli.
get_assemble_parser
()[source]¶ Generate arg parser for the ebc_assemble command line script.
Returns: The argument parser. Return type: argparse.ArgumentParser
-
eight_bit_computer.cli.
positive_int
(value)[source]¶ Validate a string is an int greater than or equal to zero.
Used for the type argument in an argparse.ArgumentParser.add_argument call.
Parameters: value (str) – Value to be tested. Returns: Value as an integer if it was >= 0. Return type: int Raises: argparse.ArgumentTypeError
– If the value was not greater than or equal to zero.
eight_bit_computer.data_structures module¶
Data structures use to pass information between functions.
-
class
eight_bit_computer.data_structures.
DataTemplate
(address_range, data)¶ Bases:
tuple
Some data and a range of addresses to store that data in
-
address_range
¶ The range of addresses to store the data in. 0 and 1 are absolute values, X is either a 0 or 1 and the expectation is that the data will expand out to the parts of the address marked with an X. and example could be “0010XX001”.
Type: str
-
data
¶ The data to be stored at the given addresses.
Type: str
-
address_range
Alias for field number 0
-
data
Alias for field number 1
-
-
class
eight_bit_computer.data_structures.
RomData
(address, data)¶ Bases:
tuple
Some data and an address to store it in
-
address
¶ The address to store the data in.
Type: str
-
data
¶ The data to be stored at the given address.
Type: int
-
address
Alias for field number 0
-
data
Alias for field number 1
-
-
eight_bit_computer.data_structures.
get_summary_entry_template
()[source]¶ Get a template to describe each line in an assembly summary
Keys have the following meanings:
- has_assembly: Does this line of the summary have assembly code.
- assembly: Information about the assembly in this summary line.
- assembly/info: The assembly line information dictionary (as
returned by
get_assembly_line_template()
) and filled in by the assembler. - has_mc_byte: Does this line of the summary have a machine code byte.
- mc_byte: Information about the machine code byte on this line.
- mc_byte/info: Machine code byte information dictionary (as
returned by
get_machine_code_byte_template()
and filled by the assembly process). - mc_byte/has_label: Whether of not this machine code byte has an associated label.
- mc_byte/label: The label of this machine code byte.
Returns: Summary entry template. Return type: dict
-
eight_bit_computer.data_structures.
get_assembly_line_template
()[source]¶ Get a template for the assembly line information bundle.
Template for a dictionary that contains information about this line of assembly code. The keys have the following meanings:
- line_no: The line in the assembly file that this line was on.
- raw: The line as it was in the assembly file.
- clean: The cleaned up line, ready for parsing.
- defines_label: Whether or not this line is a label definition.
- defined_label: The label that this line defined.
- has_label_assigned: Whether or not this line has a label assigned to it.
- assigned_label: The label that has been assigned to the first line of the machine code generated for this line.
- defines_variable: Whether or not this line is a variable definition.
- defined_variable: The variable that this line defines.
- has_machine_code: Whether or not this line results in machine code. E.g. a comment has no machine code.
- mc_bytes: List of machine code byte templates (with constant expansion information) for this assembly line.
Returns: Assembly line description template. Return type: dict
-
eight_bit_computer.data_structures.
get_arg_def_template
()[source]¶ Get a definition template for an assembly operation argument.
This is a set of information that describes an argument used in a line of assembly.
The keys have the following meaning:
- value_type: What kind of argument this is.
constant
ormodule_name
. - is_memory_location: Whether this argument is referring to a location in memory.
- value: The permitted value of the argument if it’s a module.
These dictionaries will be grouped in a list of lists that describe the possible arguments for an assembly operation. E.g. if the possible arguments for an assembly operation were:
ACC
A
B
C
A
[#123]
The data structure would be as follows:
[ [ { "value_type": "module_name", "is_memory_location": False, "value": "ACC", }, { "value_type": "module_name", "is_memory_location": False, "value": "A", }, ], [ { "value_type": "module_name", "is_memory_location": False, "value": "B", }, { "value_type": "module_name", "is_memory_location": True, "value": "C", }, ], [ { "value_type": "module_name", "is_memory_location": False, "value": "A", }, { "value_type": "constant", "is_memory_location": True, "value": "", }, ], ]
Returns: Machine code byte description template. Return type: dict - value_type: What kind of argument this is.
-
eight_bit_computer.data_structures.
get_machine_code_byte_template
()[source]¶ Get the template used to describe a machine code byte.
This is a set of information that describes the byte (of which there could be many) of machine code that an operation (e.g. LOAD [$variable] A) results in.
The keys have the following meaning:
- bitstring: A byte bitstring of the final byte that will make up the machine code.
- byte_type: The type of machine code byte. Will be instruction or constant.
- constant_type: The type of the constant. Could be a label, variable or number.
- constant: The constant that this byte will need to become. The resolution of the constant to a real machine code byte is done by the assembler.
- number_value: The value of the constant as an int if it’s a number.
- index: The index of this byte in program data.
Returns: Machine code byte description template. Return type: dict
eight_bit_computer.exceptions module¶
Custom exceptions used in this project.
-
exception
eight_bit_computer.exceptions.
EightBitComputerError
[source]¶ Bases:
exceptions.Exception
Base class for exceptions in the computer
-
exception
eight_bit_computer.exceptions.
OperationParsingError
[source]¶ Bases:
eight_bit_computer.exceptions.EightBitComputerError
Raised when parsing an operation fails.
E.g. An incorrect argument is used with the LOAD operation.
-
exception
eight_bit_computer.exceptions.
LineProcessingError
[source]¶ Bases:
eight_bit_computer.exceptions.EightBitComputerError
Raised when processing a line fails.
E.g. The line was not a constant declaration and no operations matched.
-
exception
eight_bit_computer.exceptions.
AssemblyError
[source]¶ Bases:
eight_bit_computer.exceptions.EightBitComputerError
Raised when the assembly could not be converted to machine code.
eight_bit_computer.export module¶
Functionality to convert data other package friendly formats.
-
eight_bit_computer.export.
bitstrings_to_logisim
(bitstrings)[source]¶ Convert bitstrigs to a logising RAM/ROM file format.
Used to convert ROMs and machine code.
Parameters: bitstrings (list(str)) – List of bitstrings to convert to a logisim friendly format. Returns: String ready to be written to a file. Return type: str
-
eight_bit_computer.export.
chunker
(seq, chunk_size)[source]¶ Take a larger sequence and split it into smaller chunks.
E.g.:
chunker([0,1,2,3,4,5], 4) -> [0,1,2,3], [4,5]
Parameters: - seq (list) – List of things to chunk up
- chunk_size (int) – How big each chunk should be.
Returns: Generator that yields each chunk.
Return type: generator
eight_bit_computer.language_defs module¶
Defnitions for the machine code and microcode.
-
eight_bit_computer.language_defs.
instruction_byte_from_bitdefs
(bitdefs)[source]¶ Extract an instruction byte from the bitdefs that make it up.
If more than one bitdef is passed it will be merged with the others prior to extraction.
Parameters: list (bitdefs) – List of bitdefs to potentially merge and extract Returns: Bitstring of the instruction byte Return type: str
eight_bit_computer.main module¶
Top level interface for the module
-
eight_bit_computer.main.
assemble
(input_filepath, output_filepath=None, variable_start_offset=0, output_format='logisim')[source]¶ Read an assembly file and write out equivalent machine code.
Parameters: - input_filepath (str) – The location of the assembly file.
- output_filepath (str) (optional) – The location to write out the machine code. If nothing is passed, the output path will be the input path with the extension changed to mc.
- variable_start_offset (int) (optional) – How far to offset the first variable in data memory from 0.
- output_format (str) (optional) – How to format the output.
logisim
orcpp
.
-
eight_bit_computer.main.
filepath_to_lines
(input_filepath)[source]¶ Take a filepath and get all the lines of the file.
The lines returned have the newline stripped.
Parameters: input_filepath (str) – Path to the file of disk to read. Returns: Lines of the file. Return type: list(str)
-
eight_bit_computer.main.
get_mc_filepath
(asm_path)[source]¶ Get the filepath for the machine code.
This is the assembly filepath with .asm replaced with .mc
Parameters: asm_path (str) – Path to the assembly file. Returns: Path to the machine code file. Return type: str
-
eight_bit_computer.main.
extract_machine_code
(assembly_lines)[source]¶ Extract machine code from assembly line dictionaries.
Parameters: assembly_lines (list(dict)) – List of assembly line info dictionaries to extract machine code from. See get_assembly_line_template()
for details on what those dictionaries contain.Returns: List of bit strings for the machine code. Return type: list(str)
-
eight_bit_computer.main.
gen_roms
(output_dir='.', rom_prefix='rom', output_format='logisim')[source]¶ Write files containing microcode for drive the roms.
Parameters: - output_dir (str) (optional) – The directory to write the roms into.
- rom_prefix (str) (optional) – The prefix for the rom files.
- output_format (str) (optional) – How to foramt the output.
logisim
orcpp
.
eight_bit_computer.number_utils module¶
Functions for working with, checking and converting numbers.
All numbers are stored within the computer as the positive equivalent. They may be interpreted as negative.
-
eight_bit_computer.number_utils.
number_to_bitstring
(number, bit_width=8)[source]¶ Convert a number to an equivalent bitstring of the given width.
Raises: ValueError
– If number doesn’t fit in the bit width.
-
eight_bit_computer.number_utils.
number_is_within_bit_limit
(number, bit_width=8)[source]¶ Check if a number can be stored in the number of bits given.
Negative numbers are stored in 2’s compliment binary.
Parameters: - number (int) – The number to check.
- bit_width (int, optional) – The number of bits available.
Returns: True if within limits, False if not.
Return type: bool
-
eight_bit_computer.number_utils.
get_positive_equivalent
(number)[source]¶ Read the 2’s compliment equivalent of this number as positive.
With a 3 bit number, the positive equivalent of -2 is 5. E.g.:
-4 4 100 -3 5 101 -2 6 110 -1 7 111 0 0 000 1 1 001 2 2 010 3 3 011
Parameters: number (int) – The number to convert to a positive quivalent Returns: The positive equivalent of the number. Return type: int
eight_bit_computer.operation_utils module¶
Common functions for operations.
-
eight_bit_computer.operation_utils.
assemble_instruction
(instruction_bitdefs, flags_bitdefs, control_steps)[source]¶ Create templates for all steps to form a complete instruction.
Parameters: - instruction_bitdefs (list(str)) – List of the bitdefs that make up the instruction byte.
- flags_bitdefs – list(str): List of the bitdefs that make up the flags for this instruction.
- control_steps – list(list(str): List of list of bitdefs that make up the control signals for each step.
Returns: All the steps for this instruction.
Return type: list(DataTemplate)
Raises: ValueError
– If too many steps were provided.
-
eight_bit_computer.operation_utils.
add_quotes_to_strings
(strings)[source]¶ Add double quotes strings in a list then join with commas.
Parameters: strings (list(str)) – List of strings to add parentheses to. Returns: The strings with quotes added and joined with commas. Return type: str
-
eight_bit_computer.operation_utils.
match_and_parse_line
(line, opcode, signatures=None)[source]¶ Examine assembly code to see if it is valid and parse the arguments.
This is a common function used by most of the assembly operations.
Parameters: - line (str) – The line of assembly code.
- opcode (str) – The opcode this line is being tested to match.
- signatures (list(list(dict)), optional) – Data structure that
defines the different combinations of arguments. See
get_arg_def_template()
for more details.
Returns: Whether or not the line matched, and if it did, the parsed arguments.
Return type: (bool, list(dict))
Raises: OperationParsingError
– If multiple op_args defs matched. Or- if no op_args defs matched if the opcode matched (i.e. the
- arguments weren’t valid for that assembly operation).
-
eight_bit_computer.operation_utils.
generate_possible_signatures_list
(signatures)[source]¶ Create a readable list of all possible signatures.
Parameters: signatures (list(list(dict))) – Data structure that defines the different combinations of arguments. See get_arg_def_template()
for more details.Returns: All possible argument combinations. Return type: list(str)
-
eight_bit_computer.operation_utils.
match_and_parse_args
(line_args, signature)[source]¶ Parse assembly operation args if they match the definition.
Take arguments supplied for the assembly operation and see if they match this arguments definition.
Parameters: - line_args – (list(str)): The arguments supplied for this assembly operation.
- signature (list(dict)) – Definition of a set of arguments. See
get_arg_def_template()
for more details.
Returns: Whether or not the arguments matched, and if they did, the parsed values.
Return type: (bool, list(dict))
Raises: OperationParsingError
– If a single argument managed to match different kinds of argument definitions.
eight_bit_computer.rom module¶
Create and export roms for the computer
-
eight_bit_computer.rom.
get_rom
()[source]¶ Get complete representation of the rom.
Returns: All the defined microcode. Return type: list(RomData)
-
eight_bit_computer.rom.
collect_language_datatemplates
()[source]¶ Get all the datatemplates from all the defined operations.
Returns: - All the data templates from the defined
- operations
Return type: list(DataTemplate)
-
eight_bit_computer.rom.
collapse_datatemplates_to_romdatas
(datatemplates)[source]¶ Collapse any addresses in datatemplates to real values.
If an address does need collapsing the original data is copied out to all the collapsed addresses.
Parameters: list (datatemplates) – A list of templates to collapse. Returns: The expanded datatemplates Return type: list(RomData)
-
eight_bit_computer.rom.
populate_empty_addresses
(romdatas, all_addresses, default_data)[source]¶ Form a complete set of rom data by filling any undefined addresses.
Parameters: - list (romdatas) – The romdatas defined by the instructions.
- all_addresses (list(str)) – List of bitdefs representing every address in the rom
- default_data (str) – The value to set for any address that isn’t in romdatas.
Returns: - List of RomDatas representing a completely full
rom
Return type: list(RomData)
-
eight_bit_computer.rom.
romdatas_have_duplicate_addresses
(romdatas)[source]¶ Check if any of the romdatas have duplicate addresses.
Parameters: list (romdatas) – List of romdatas to check. Returns: Whether or not there were any duplicated addresses. Return type: Bool
-
eight_bit_computer.rom.
slice_rom
(rom)[source]¶ Slice a rom into chunks 8 bits wide.
This is to prepare the data to write into the roms. To take a single RomData as an example, if it looked like this (spaces added for clarity):
RomData( address="0000000 0000 000", data="10101010 111111111 00000000 11001100" )
We would end up with:
{ 0: RomData( address="0000000 0000 000", data="11001100" ), 1: RomData( address="0000000 0000 000", data="00000000" ), 2: RomData( address="0000000 0000 000", data="11111111" ), 3: RomData( address="0000000 0000 000", data="10101010" ) }
Parameters: rom (list(RomData)) – The complete ROM Returns: list(RomData)) Dictionary of ROM slices Return type: dict(int
-
eight_bit_computer.rom.
get_num_bytes
(bitstring)[source]¶ Get the number of bytes needed to store this bitdef.
Parameters: bitstring (str) – Bitstring representing the bits to store. Returns: The number of bytes needed to store the bitstring. Return type: int
-
eight_bit_computer.rom.
get_romdata_slice
(romdatas, end, start)[source]¶ Get a slice of the data in the romdatas.
Parameters: - romdatas (list(RomData)) – The romdatas to get a slice from
- end (int) – The index for the end of the slice. Starts at zero at the rightmost (least significant) bit.
- start (int) – The index for the start of the slice. Starts at zero at the rightmost (least significant) bit.
Returns: The sliced list of romdatas
Return type: list(RomData)
eight_bit_computer.token_utils module¶
Functionality for working with string tokens on assembly lines
-
eight_bit_computer.token_utils.
is_label
(test_string)[source]¶ Test if a string is a valid label.
Parameters: test_string (str) – The string to test Returns: True if the string is a valid label, false otherwise. Return type: bool
-
eight_bit_computer.token_utils.
is_variable
(test_string)[source]¶ Test if a string is a valid variable.
Parameters: test_string (str) – The string to test Returns: True if the string is a valid variable, false otherwise. Return type: bool
-
eight_bit_computer.token_utils.
is_number
(test_string)[source]¶ Test if a string is a valid number.
Parameters: test_string (str) – The string to test Returns: True if the string is a valid number, false otherwise. Return type: bool
-
eight_bit_computer.token_utils.
number_constant_value
(number_constant)[source]¶ Get the value that a number constant represents.
Parameters: number_constant (str) – The constant to extract the value from. Returns: The value of the constant. Return type: int
-
eight_bit_computer.token_utils.
is_memory_index
(argument)[source]¶ Determine whether this argument is a memory index.
Memory indexes can be module names or constants with a
[
at the start and a]
at the end. e.g.:[A]
[#42]
[$variable]
Parameters: argument (str) – The argument being used for the assembly operation. Returns: True if the argument is a memory index, false if not. Return type: bool
-
eight_bit_computer.token_utils.
represent_as_memory_index
(argument)[source]¶ Format the argument so it appears as a memory index.
See
is_memory_index()
for details on what a memory index is.Parameters: argument (str) – The argument to represent as a memory index. Returns: The formatted argument. Return type: str
-
eight_bit_computer.token_utils.
extract_memory_position
(argument)[source]¶ Extract a memory position from a memory index argument.
See
is_memory_index()
for details of what a memory index is.Parameters: argument (str) – The argument to extract a memory position from. Returns: The location in memory being referenced. Return type: str
-
eight_bit_computer.token_utils.
get_tokens_from_line
(line)[source]¶ Given a line split it into tokens and return them.
Tokens are runs of characters separated by spaces. If there are no tokens return an empty list.
Parameters: line (str) – line to convert to tokens Returns: The tokens Return type: list(str)