
This project implements a custom 16-bit processing system, including hardware modules for program counter (PC), instruction fetch, branch logic, UART communication, and integration with the BittyEmulator for co-simulation. The provided system allows robust testing of a Verilog-based design using a Python-based cocotb testbench. The testbench orchestrates data transfer via UART, interacts with shared memory, and verifies execution against the emulator.
Program Counter (PC):
Instruction Fetch Unit:
Branch Logic:
UART Module:
Bitty Emulator:
instructions_for_em.txt, loaded by the testbench for execution.
Here’s the revised version written as a description of a fully implemented system:This document outlines the complete instruction set architecture (ISA) for a 16-bit processor, detailing its capabilities, operations, and encoding formats. The ISA is designed to deliver robust functionality for arithmetic, logical, control flow, and memory operations while maintaining a simple, efficient structure.
The processor's instruction set enables dynamic memory interactions, conditional branching, and a wide range of data manipulation tasks, providing the foundation for executing complex algorithms and software applications.
The processor supports both register-to-register and immediate operations, enabling developers to perform computations efficiently.
add rx, ry: Adds the value in ry to rx.
rx = rx + rysub rx, ry: Subtracts the value in ry from rx.
rx = rx - ryand rx, ry: Performs a bitwise AND between rx and ry.
rx = rx & ryor rx, ry: Performs a bitwise OR between rx and ry.
rx = rx | ryxor rx, ry: Performs a bitwise XOR between rx and ry.
rx = rx ^ ryshl rx, ry: Shifts the bits in rx left by the number of positions specified in ry.
rx = rx << ryshr rx, ry: Shifts the bits in rx right by the number of positions specified in ry.
rx = rx >> rycmp rx, ry: Compares the values in rx and ry.
rx = 0 if rx == ryrx = 1 if rx > ryrx = 2 if rx < ryaddi rx, #i: Adds the immediate value #i to rx.
rx = rx + #isubi rx, #i: Subtracts the immediate value #i from rx.
rx = rx - #iandi rx, #i: Performs a bitwise AND between rx and #i.
rx = rx & #iori rx, #i: Performs a bitwise OR between rx and #i.
rx = rx | #ixori rx, #i: Performs a bitwise XOR between rx and #i.
rx = rx ^ #ishli rx, #i: Shifts rx left by #i positions.
rx = rx << #ishri rx, #i: Shifts rx right by #i positions.
rx = rx >> #icmpi rx, #i: Compares the value in rx with the immediate value #i.
rx = 0 if rx == #irx = 1 if rx > #irx = 2 if rx < #ild rx, (ry): Loads the value from the memory address stored in ry into register rx.
rx = mem[ry]st rx, (ry): Stores the value in register rx into the memory address stored in ry.
mem[ry] = rxld or source register for st.0 for ld, 1 for st).11 for memory operations).The processor supports conditional branching with a dedicated encoding format for efficient control flow.
EQ is set).GT is set).LT is set).00: Equal01: Greater than10: Less than10 for conditional branching).Here’s a detailed step-by-step guide for users to set up and test their system with the assembler and testbench:
Before running the testbench, you must first prepare the assembly instructions or machine code. Here’s how:
Option 1: Generate machine code automatically
Run the CIG_run.py script to generate output.txt automatically with pre-defined assembly instructions.
python3 CIG_run.py
This will create output.txt containing machine code.
Option 2: Write custom assembly instructions
If you prefer to write your own instructions, directly create or modify the output.txt file. These instructions will later be disassembled for further testing.
Disassemble the output.txt file (machine code) to generate instructions_for_em.txt (assembly code):
./er_tool -d -i output.txt -o instructions_for_em.txt
This step ensures that the instructions in instructions_for_em.txt are ready for use in the testbench.
Once you have the instructions_for_em.txt file ready, navigate to the bitty-tt10/test directory and execute the testbench using make:
cd ~/bitty-tt10/test
make
The testbench will:
instructions_for_em.txt.uart_emulator_log.txt.To convert instructions_for_em.txt into machine code (if needed for testing):
./er_tool -a -i instructions_for_em.txt -o output.txt
To convert machine code (output.txt) back into assembly:
./er_tool -d -i output.txt -o instructions_for_em.txt
Generate Machine Code:
Run CIG_run.py to create machine code:
python3 CIG_run.py
Disassemble Code:
Use the er_tool to create instructions_for_em.txt:
./er_tool -d -i output.txt -o instructions_for_em.txt
Run Testbench:
Navigate to the test directory and run the testbench:
cd ~/bitty-tt10/test
make
uart_emulator_log.txt.Following these steps ensures smooth operation from writing or generating instructions to verifying the system’s functionality. If you encounter issues, double-check the prepared files or logs for guidance. Let me know if you need further clarification!
Prerequisites:
pip install -r requirements.txt
Input Files:
instructions_for_em.txt) in the working directory.Shared Libraries:
BittyEmulator.py and shared_memory.py are in the project directory.Execute the cocotb testbench:
make
Observe the test results in the terminal and logs:
uart_emulator_log.txt.This system does not require external hardware. UART communication is emulated within the testbench.
<module_name>.v: Contains the RTL design files for the system.tb_<module_name>.v: Top-level Verilog testbench wrapper.test_bitty.py: The cocotb testbench described above.BittyEmulator.py: Emulator for reference model validation.shared_memory.py: Utility for creating shared memory structures.Hardware Expansion:
Error Handling:
Scalability:
This project demonstrates a robust framework for RTL verification, combining software co-simulation with hardware modeling for high-fidelity testing and validation.
| # | Input | Output | Bidirectional |
|---|---|---|---|
| 0 | rx_data_bit | tx_data_bit | |
| 1 | sel_baude_rate[0] | ||
| 2 | sel_baude_rate[1] | ||
| 3 | |||
| 4 | |||
| 5 | |||
| 6 | |||
| 7 |