This project involves designing an 8-bit microprocessor using Verilog HDL, optimized with a 4-stage pipeline and a 16-bit instruction set. The microprocessor features a Harvard architecture and RISC design, offering an efficient execution of instructions through stages: Instruction Fetch (IF), Instruction Decode (ID), Execute (EX), and Writeback (WB). With a data width of 8 bits and a clock frequency of 500MHz, the processor supports various addressing modes, including Register Direct and Absolute Addressing, and a wide range of operations such as arithmetic, logical, and control instructions.
The project includes detailed modules for each stage, a robust hazard mitigation strategy to handle data, control, and structural hazards, and comprehensive testing to ensure functionality and efficiency. By integrating all components, the microprocessor ensures smooth data flow and control signal propagation across the pipeline, making it a versatile and powerful processor design.
- Microprocessor-Architecture: RISC
- Memory-Architecture: Harvard Architecture
- Data Width: 8 bits
- Instruction Width: 16 bits
- Instruction Memory: 64 x 16 bits
- Data Memory: 16 x 8 bits
- Register File: 8 x 8 bits
- Program Counter: 6 bits
- Clock Frequency: 500MHz
- Register Direct Addressing
- Absolute Addressing
- Instruction Fetch (IF)
- Instruction Decode (ID)
- Execute (EX)
- Writeback (WB)
Please install Icarus Verilog (Iverilog- commonly used in interface with vscode to code and simulate in verilog ) along with gtkwave
(used for waveform simulation and analysis) in your system to begin with.
Icarus verilog is available at : https://bleyer.org/icarus/
Further interface your VSCODE with run time environment (if it's not default from environment variables in the settings).
Install necessary extensions for verilog formatting into VS CODE from https://marketplace.visualstudio.com/items?itemName=mshr-h.VerilogHDL
Run the following in the terminal of VS CODE
iverilog -o processor.vvp processortb.v
vvp processor.vvp
gtkwave
The microprocessor supports a variety of operations through its 16-bit instructions. Below are the opcodes for different operations:
Opcode | Operation |
---|---|
00000 | MOVE |
00001 | ADD |
00010 | SUBTRACT |
00011 | MULTIPLY |
00100 | DIVIDE |
00101 | INCREMENT |
00110 | DECREMENT |
00111 | AND |
01000 | OR |
01001 | NOT |
01010 | XOR |
01011 | LOAD |
01100 | STORE |
01101 | JUMP |
01110 | BRANCH (ZERO FLAG) |
10000 | ARITHMETIC LEFT SHIFT |
10001 | ARITHMETIC RIGHT SHIFT |
10010 | LOGICAL LEFT SHIFT |
10011 | LOGICAL RIGHT SHIFT |
10100 | ROTATE LEFT |
10101 | ROTATE RIGHT |
10110 | BRANCH (CARRY FLAG) |
10111 | BRANCH (AUXILIARY FLAG) |
11000 | BRANCH (PARITY FLAG) |
11111 | HALT |
- MOVE:
- AM = 0:
opcode(5) | 0 | rd(3) | rs(3) | 0000 |
---|
- AM = 1:
opcode(5) | 1 | rd(3) | mem_add(4) | 000 |
---|
- ADD,SUB,MUL,DIV,AND,OR,XOR,COMP:
- AM = 0:
opcode(5) | 0 | rd(3) | rs1(3) | rs2(3) | 0 |
---|
- AM = 1:
opcode(5) | 1 | rd(3) | rs1(3) | mem_add(4) |
---|
- INCR,DEC,NOT,all shift and rotate:
- AM = 0:
opcode(5) | 0 | rd(3) | s_r_amount(3) | 0000 |
---|
- AM = 1:
opcode(5) | 1 | data_mem(4) | s_r_amount(3) | 000 |
---|
- LOAD(mem -> reg):
opcode(5) | X | rd(3) | data_mem(4) | 000 |
---|
- LOAD(reg -> mem):
opcode(5) | X | data_mem(4) | rd(3) | 000 |
---|
JUMP AND BRANCH:
opcode(5) | X | instr_mem(6) | 0000 |
---|
HALT:
opcode(5) | X | 0000000000 |
---|
- Description: This module increments the program counter after each instruction fetch, enabling sequential instruction execution and branching when needed.
- Description: This module supports reading from and writing to multiple registers simultaneously, essential for efficient instruction execution.
- Description: This module interfaces with both the data memory and the control unit to handle memory read/write operations during the execute and memory access stages.
- Description: This module stores the program's instructions and supports fast access to facilitate the instruction fetch stage.
- Description: This module fetches instructions from instruction memory based on the program counter, passing them to the decode stage.
- Description: This module decodes the fetched instructions, determining the operation type and identifying the required operands and control signals.
- Description: This module performs the actual computation, utilizing the arithmetic logic unit (ALU) and handling operations like addition, subtraction, logical operations, and branching.
- Description: This module takes the results from the execute stage or memory access stage and writes them back to the appropriate register in the register file.
- Description: This module holds the fetched instruction between the instruction fetch and decode stages, ensuring smooth transition and synchronization in the pipeline.
- Description: This module stores data between the instruction decode and execute stages, ensuring smooth transition and synchronization in the pipeline.
- Description: This module temporarily holds data between the execution stage and the write-back stage, maintaining pipeline flow and data integrity.
- Description: This module generates control signals based on the decoded instruction, ensuring the correct operation of each pipeline stage and coordinating hazard detection and resolution.
- Description: This top-level module integrates all the individual components, orchestrating their interactions to ensure smooth data flow and control signal propagation across the pipeline.
The microprocessor's datapath includes the following stages:
- Fetches the instruction from memory.
- This stage retrieves the instruction located at the address specified by the program counter (PC). The PC is then incremented to point to the next instruction. This stage is crucial for ensuring that instructions are sequentially accessed and prepared for decoding.
- Decodes the fetched instruction to determine the operation, operands, destination register,memory address,addressing mode etc..
- In this stage, the fetched instruction is decoded to identify the opcode, which specifies the operation to be performed. It also determines the source operands and the destination register.
- Performs the required operation on the operands.
- This stage utilizes the arithmetic logic unit (ALU) to execute arithmetic and logical operations on the source operands. It also calculates memory addresses for load and store instructions and evaluates branch conditions. The results of these operations are then prepared for the next stage.
- Writes the result back to the register file or memory as per opcode.
- In this final stage, the results of the execution stage are written back to the destination register specified during the decode stage. If the instruction involves memory operations, the data is written to or read from the memory. This stage ensures that the results of the executed instruction are properly stored and made available for future instructions.
The control system manages the following states:
-
S0: Initial State (Everything off)
-
S1: Reset State
-
S2: Clock Signal State
-
S3: Halt State
- Description: Everything is off.
- Purpose: Represents the initial state where the microprocessor and all its components are turned off.
- Actions: No operations are performed; the system is in standby mode.
- Description: Reset all stages and enable all pipeline latches.
- Purpose: Prepares the microprocessor for operation.
- Actions: Resets all pipeline stages and enables pipeline latches.
- Description: Clock signals to latches will be sent.
- Purpose: Sends clock signals to synchronize operations across different stages.
- Actions: Distributes clock signals to latches and checks the Halt signal.
- Description: Halt = 1
- Purpose: Pauses microprocessor operations when the Halt signal is set.
- Actions: Halts operations and waits for an external interrupt or resume signal.
- S0 to S1: Microprocessor is turned on or initialized.
- S1 to S2: After resetting stages and enabling latches.
- S2 to S3: If the Halt signal is set to 1.
- S3 to S1: If a resume interrupt is received.
Pipelining introduces several types of hazards, which can impede the smooth execution of instructions:
- Data Hazards: Occur when an instruction depends on the result of a previous instruction that is not yet complete.
- RAW hazard: A Read After Write (RAW) hazard occurs when an instruction attempts to read a register before a preceding instruction has finished writing to that register. This can lead to the reading instruction obtaining an incorrect or stale value, affecting the correctness of the program.
- WAR hazard: A Write After Read (WAR) hazard occurs when an instruction writes to a register before a preceding instruction has finished reading from that register. This can lead to the previous instruction reading an incorrect value or the write operation causing unintended side effects.
- WAW hazard: A Write After Write (WAW) hazard occurs when two instructions write to the same register in a pipeline, and the order of writes can affect the final value of that register. If the second write completes before the first write, the final value written to the register might be incorrect.
- Control Hazards: Occur due to jump or branch instructions that change the flow of execution.
- Structural Hazards: Occur when two or more instructions require the same hardware resource simultaneously.
-
Data Hazards Mitigation:
- RAW hazard: The Read After Write (RAW) hazard is mitigated by making the pipeline stages level-triggered. This ensures that if the register value changes in the middle of execution, the result in the stages gets updated accordingly.
- WAR hazard: Write After Read (WAR) hazards do not occur in this processor because of sequential flow of instruction in the pipeline, which means that if instruction 1 is in the pipeline before instruction 2 then instruction 1 will write the regFile and memoryBank first then only instruction 2 can write it so, no chances of these files being written by any instruction occuring after the present instruction.
- WAW hazard: Write After Write (WAW) hazards do not occur in this processor as data is written in register bank and memory only in the writeback stage which takes one instruction at a time so no two instruction can write the registers and memory simultaneously.
-
Control Hazards Mitigation:
- Pipeline Flushing: Implemented pipeline flushing to mitigate control hazard, the jump and branch instructions with true condition sends signal to controller from writeback stage to flush the pipeline, controller then resets the IF_ID_Latch, Decode stage, ID_EX_Latch, Execute stage and EX_WB_Latch to flush the wrong instructions from the pipeline.
-
Structural Hazards Mitigation:
- Isolation of read and write signals: Mitigated the structural hazard caused by regFile and memoryBank by isolating the read and write signals from each other. In our processor the read operation is done only in execute stage and write operation in writeback stage, both the stages works at different clock signals, so we enable read signal only when execute stage is given clock and write signal is enabled when writeback stage is given clock and instruction that require write operation is present in writeback stage.
The total format has been clearly described in the file named instrmean.txt in the same repo. These are the output waveforms observed correspondingly.
Hazard Detection |
---|
0000100010100110 |
0000111000010010 |
1001101110010000 |
1011000010000000 |
1111100000000000 |
1111100000000000 |
1111100000000000 |
1111100000000000 |
1001101110010000 |
1111100000000000 |
Arthimetic and logical operations |
---|
0000001001011110 |
0101001000101110 |
0000111001010000 |
Shift and Flag Instructions |
---|
1000001110010000 |
1000011111001000 |
1001101110100000 |
1001111111010000 |
0001111101101111 |
1001001110010000 |
1011000100010000 |
Jump Instructions: |
---|
0000001011000000 |
0000001111010000 |
0101101101110000 |
1100000111000000 |
0000001011000000 |
0000001111010000 |
0000001011000000 |
0110011110100000 |
0110100011000000 |
0000001111010000 |
0000101011100000 |
0000101011100000 |
1111100000000000 |