Deep Dive into the Code: Analyzing a 4-bit Microprocessor

Ibrahim Bin Mansur
8 min readSep 30, 2024

--

In our previous post, we gave an overview of a 4-bit number crunching machine implemented in Verilog HDL. Now, let’s take a closer look at each module, analyzing the code and explaining its functionality in detail.

D2_register.v

The D2_register module is a dual 4-bit register unit. It instantiates two D_register modules, effectively creating two independent 4-bit registers.

module D2_register(clk,reseta,resetb,Ra,Rb,ena,enb,A,B);
input clk,reseta,resetb;
input [3:0] Ra,Rb;
input ena,enb;
output [3:0] A,B;

D_register RA (clk,reseta,ena,Ra,A);
D_register RB (clk,resetb,enb,Rb,B);

endmodule

Inputs:

  • clk: Clock signal
  • reseta, resetb: Reset signals for each register
  • Ra, Rb: 4-bit input data for each register
  • ena, enb: Enable signals for each register

Outputs:

  • A, B: 4-bit output data from each register

This module is useful when you need two separate but identical registers in your design, such as for storing two operands for an ALU.

D_register.v

The D_register module implements a basic 4-bit register with synchronous reset and enable functionality.


module D_register(clk,reset,en,din,dout);
input clk, en, reset;
input[3:0] din;
output reg[3:0] dout;


always @(posedge clk,posedge reset)
begin
if (reset == 1)
dout <= 4'b0000;
else if (en)
dout <= din;

end

endmodule

Inputs:

  • clk: Clock signal
  • reset: Asynchronous reset signal
  • en: Enable signal
  • din: 4-bit input data

Output:

  • dout: 4-bit registered output

The register updates its output on the positive edge of the clock. If reset is high, dout is set to 0. If en is high and reset is low, dout takes the value of din.

alu.v

The alu (Arithmetic Logic Unit) module performs addition or subtraction on two 4-bit inputs based on a select signal.

module alu(A,B,s,Out,C);
input [3:0]A,B;
input s;
output reg C;
output reg [3:0]Out;


always@(*)
begin
if (s==1)
{C,Out}=A+(~B)+1;
if(s==0)
{C,Out}=A+B;
end

endmodule

Inputs:

  • A, B: 4-bit input operands
  • s: Operation select (0 for addition, 1 for subtraction)

Outputs:

  • Out: 4-bit result
  • C: Carry/borrow output

When s is 0, it performs A + B. When s is 1, it performs A - B using two's complement (A + (~B) + 1).

counter.v

The counter module implements a 4-bit counter with reset, load, and increment functionality.

module counter(reset,clk,J,C,Cout,custom_input,count);
input reset,clk,J,C,Cout;
input [2:0] custom_input;
output reg [3:0] count;
wire [3:0] w;
wire load;

assign w[2:0] = custom_input;
assign w[3] = 0;
assign load = J | (C & Cout);

always @(posedge clk, posedge reset)
begin
if(reset == 1)
count <= 4'b0000;
else if(load)
count <= w;
else
count <= count + 4'b0001;
end

endmodule

Inputs:

  • reset: Asynchronous reset signal
  • clk: Clock signal
  • J, C, Cout: Control signals
  • custom_input: 3-bit input for loading custom values

Output:

  • count: 4-bit counter value

The counter increments on each clock cycle unless reset or load conditions are met. The load signal is active when either J is high or both C and Cout are high.

decoder.v

The decoder module is a 2-to-4 decoder, converting a 2-bit input into a one-hot 4-bit output.

module decoder(a,b,O);
input a,b;
output reg [3:0] O;

always @(*)
begin
case({a,b})
2'b00 : O = 4'b0001;
2'b01 : O = 4'b0010;
2'b10 : O = 4'b0100;
2'b11: O = 4'b1000;
default : O = 4'b0000;
endcase
end


endmodule

Inputs:

  • a, b: 2-bit input

Output:

  • O: 4-bit one-hot encoded output

It uses a case statement to determine the output based on the input combination.

display.v

The display module is a complex circuit for driving a two-digit seven-segment display.

module display(a,b,c);
input [3:0] a;
output [6:0] b,c;
wire [3:0] w1,w2,w3;

compare c1(a,w1);

cct ct(a,w2);

mux m(a,w2,w1[0],w3);

seg s0(w3,c);
seg s1(w1,b);



endmodule


module seg(x,y);
input [3:0] x;
output reg [6:0] y;

always@(*)
case(x)
4'b0000: y = 7'b1000000;
4'b0001: y = 7'b1111001;
4'b0010: y = 7'b0100100;
4'b0011: y = 7'b0110000;
4'b0100: y = 7'b0011001;
4'b0101: y = 7'b0010010;
4'b0110: y = 7'b0000010;
4'b0111: y = 7'b1111000;
4'b1000: y = 7'b0000000;
4'b1001: y = 7'b0010000;
endcase
endmodule


module compare(a,b);
input [3:0] a;
output reg [3:0] b;
always@(*)
begin
if(a > 4'b1001)
b = 4'b0001;
else
b = 4'b0000;
end
endmodule

module mux(x,y,s,o);
input [3:0] x,y;
input s;
output reg [3:0] o;

always@(*)
begin
if(s==1)
o = y;
else
o = x;
end
endmodule


module cct(a,b);
input [3:0] a;
output reg [3:0] b;
always@(*)
b = a - 4'b1010;

endmodule

Inputs:

  • a: 4-bit input value

Outputs:

  • b, c: Two 7-bit outputs for seven-segment displays

This module includes several submodules:

  • compare: Checks if the input is greater than 9
  • cct: Subtracts 10 from the input
  • mux: Selects between original and adjusted input
  • seg: Converts 4-bit values to seven-segment display patterns

The circuit handles values from 0 to 15, displaying them as two digits (0–9 and 0–5) on seven-segment displays.

register_out.v

The register_out module is a wrapper for a single 4-bit D_register, likely used for output buffering.

module register_out(clk,Ro,reseto,eno,O);
input clk,eno,reseto;
input [3:0] Ro;
output [3:0] O;

D_register RO (clk,reseto,eno,Ro,O);

endmodule

Inputs:

  • clk: Clock signal
  • Ro: 4-bit input data
  • reseto: Reset signal
  • eno: Enable signal

Output:

  • O: 4-bit registered output

This module instantiates a single D_register to create a 4-bit output register.

fourbit.v

The fourbit module implements a 4-bit ripple carry adder using four full adder stages.

module fourbit(X,Y,Cin,Cout,Sum);
input [3:0] X,Y;
input Cin;
output [3:0] Sum;
output Cout;
wire [3:1] C;

fulladder stage0 (X[0],Y[0],Cin,C[1],Sum[0]);
fulladder stage1 (X[1],Y[1],C[1],C[2],Sum[1]);
fulladder stage2 (X[2],Y[2],C[2],C[3],Sum[2]);
fulladder stage3 (X[3],Y[3],C[3],Cout,Sum[3]);

endmodule

Inputs:

  • X, Y: 4-bit input operands
  • Cin: Carry input

Outputs:

  • Sum: 4-bit sum output
  • Cout: Carry output

This module chains together four fulladder instances, passing the carry output of each stage to the carry input of the next stage. This creates a simple but functional 4-bit adder.

fulladder.v

The fulladder module implements a single-bit full adder.


module fulladder(x,y,cin,cout,sum);
input x,y,cin;
output sum,cout;

assign sum = x^y^cin;
assign cout = (x&y)|(x&cin)|(y&cin);

endmodule

Inputs:

  • x, y: 1-bit inputs to be added
  • cin: Carry input

Outputs:

  • sum: Sum output
  • cout: Carry output

The module uses combinational logic to calculate the sum and carry. The sum is the XOR of all inputs, while the carry is generated if any two or more inputs are high.

initialmux.v

The initialmux module is a 4-bit multiplexer that selects between ALU output and a custom input.

module initialmux(alu_out,custom_input,s,m_out);
input [3:0] alu_out;
input [2:0] custom_input;
input s;
output reg [3:0] m_out;
wire [3:0] w;

assign w[2:0] = custom_input;
assign w[3] = 0;

always @(*)
begin
if(s==0)
m_out = alu_out;
else
m_out = w;
end

endmodule

Inputs:

  • alu_out: 4-bit input from ALU
  • custom_input: 3-bit custom input
  • s: Select signal

Output:

  • m_out: 4-bit multiplexer output

When s is 0, it outputs alu_out. When s is 1, it outputs custom_input padded with a leading 0.

operation_alu.v

The operation_alu module is a simple 4-bit flip-flop that captures the carry output from an ALU operation.

module operation_alu(clk,in,C); //side ff for cout
input clk;
input [3:0] in;
output reg [3:0] C;

always @(posedge clk)
begin
C <= in;
end

endmodule

Input:

  • clk: Clock signal
  • in: 4-bit input (likely from ALU carry)

Output:

  • C: 4-bit registered output

This module captures the input on the positive edge of the clock, likely used to store the carry/status from ALU operations.

eeprom.v

The eeprom module simulates a read-only memory (ROM) for storing instructions or data.

// Quartus Prime Verilog Template
// Single Port ROM

module eeprom
#(parameter DATA_WIDTH=8, parameter ADDR_WIDTH=8)
(
input [(ADDR_WIDTH-1):0] addr,
input clk,
output reg [(DATA_WIDTH-1):0] q
);

// Declare the ROM variable
reg [DATA_WIDTH-1:0] rom[2**ADDR_WIDTH-1:0];

// Initialize the ROM with $readmemb. Put the memory contents
// in the file single_port_rom_init.txt. Without this file,
// this design will not compile.

// See Verilog LRM 1364-2001 Section 17.2.8 for details on the
// format of this file, or see the "Using $readmemb and $readmemh"
// template later in this section.

initial
begin
$readmemb("instructions.txt", rom);
end

always @ (negedge clk)
begin
q <= rom[addr];
end

endmodule

Inputs:

  • addr: Address input (width parameterizable)
  • clk: Clock signal

Output:

  • q: Data output (width parameterizable)

This module reads its contents from a file named “instructions.txt” at initialization. It then outputs the data at the specified address on each negative edge of the clock.

main.v

The main module appears to be the top-level module of a digital system, possibly a simple processor or controller.

//module main(KEY,SW,O);
module main(KEY,SW,HEX1,HEX0);
input [1:0] KEY;
input [1:0] SW;
wire [7:0] q; //eeprom outputs
wire [3:0] w1,w2,w3,w4,w5,w6,w7,w8; //4 bit wires
wire R;
wire w9,w10; //ff
//output [3:0] O;
output [6:0] HEX1,HEX0;

assign R = SW[0];
eeprom e1(w7,KEY[0],q);

initialmux m1(w4,q[2:0],q[3],w1);

decoder d1(q[5],q[4],w6);

D_register RA (KEY[0],R,w6[0],w1,w2);
D_register RB (KEY[0],R,w6[1],w1,w3);
D_register RO (KEY[0],R,w6[2],w2,w8);

display(w8,HEX1,HEX0);

alu a1(w2,w3,q[2],w4,w9);

operation_alu f1(KEY[0],w9,w10);

counter c1(R,KEY[0],q[7],q[6],w10,q[2:0],w7);

//assign O = w8;

endmodule

Inputs:

  • KEY: 2-bit input (likely from push buttons)
  • SW: 2-bit input (likely from switches)

Outputs:

  • HEX1, HEX0: 7-bit outputs for seven-segment displays

This module integrates various submodules including an EEPROM, ALU, registers, counter, and display driver. It implements a simple instruction execution cycle, fetching instructions from EEPROM and manipulating data through registers and the ALU.

Hardware Results

References

--

--

No responses yet