top of page

Non pipelined processor

In the last tutorial, we created a non-pipelined processor with basic operations. Let's enhance it today to add more operations to it. 

We will be adding following operations:

  • AND: The AND operation takes two inputs, regA and regB, performs a bitwise AND operation, and stores the result in the result register. It can either take data_in as regB or fetch the value from memory based on the instruction.

  • OR: The OR operation takes two inputs, regA and regB, performs a bitwise OR operation, and stores the result in the result register. It can either take data_in as regB or fetch the value from memory based on the instruction.

  • XOR: The XOR operation takes two inputs, regA and regB, performs a bitwise XOR operation, and stores the result in the result register. It can either take data_in as regB or fetch the value from memory based on the instruction.

  • SHIFT LEFT and SHIFT RIGHT: These operations shift the bits in the regA register either to the left or to the right by one position. The shifted result is stored in the result register.

​

Let's get straight to coding it: 

SV code for design:

module NonPipelinedProcessor (
  input wire clk,
  input wire reset,
  input wire [7:0] instruction,
  input wire [7:0] data_in,
  output reg [7:0] data_out
);

  // Internal registers
  reg [7:0] regA;
  reg [7:0] regB;
  reg [7:0] result;
  reg [7:0] memory [0:255];

  // Control signals
  reg write_enable;
  reg [7:0] memory_addr;

  always @(posedge clk or posedge reset) begin
    if (reset) begin
      // Reset processor state
      regA <= 0;
      regB <= 0;
      result <= 0;
      write_enable <= 0;
      memory_addr <= 0;
    end
    else begin
      // Fetch instruction
      regA <= instruction;

      // Decode and execute instructions
      case (instruction[7:6])
        2'b00: begin  // ADD
          regB <= instruction[5:4] ? data_in : memory[instruction[3:0]];
          result <= regA + regB;
        end
        2'b01: begin  // SUB
          regB <= instruction[5:4] ? data_in : memory[instruction[3:0]];
          result <= regA - regB;
        end
        2'b10: begin  // STORE
          memory_addr <= instruction[3:0];
          write_enable <= 1;
          result <= data_in;
        end
        2'b11: begin  // LOAD
          regB <= memory[instruction[3:0]];
          result <= regB;
        end
        2'b10: begin  // AND
          regB <= instruction[5:4] ? data_in : memory[instruction[3:0]];
          result <= regA & regB;
        end
        2'b11: begin  // OR
          regB <= instruction[5:4] ? data_in : memory[instruction[3:0]];
          result <= regA | regB;
        end
        2'b10: begin  // XOR
          regB <= instruction[5:4] ? data_in : memory[instruction[3:0]];
          result <= regA ^ regB;
        end
        2'b11: begin  // SHIFT LEFT
          result <= regA << 1;
        end
        2'b10: begin  // SHIFT RIGHT
          result <= regA >> 1;
        end
        // Add more operations here as needed
      endcase
    end
  end

  always @(posedge clk) begin
    if (write_enable) begin
      memory[memory_addr] <= result;
    end
  end

  assign data_out = result;

endmodule
 

​

​

Now let's write a testbench for the processor: 

module NonPipelinedProcessor_Testbench;

  reg clk;
  reg reset;
  reg [7:0] instruction;
  reg [7:0] data_in;
  wire [7:0] data_out;

  NonPipelinedProcessor dut (
    .clk(clk),
    .reset(reset),
    .instruction(instruction),
    .data_in(data_in),
    .data_out(data_out)
  );

  initial begin
    clk = 0;
    reset = 1;
    instruction = 8'h00;  // Set initial instruction

    #10 reset = 0;  // De-assert reset
    #5 instruction = 8'h24;  // ADD regA, regB, regC (regA = regB + regC)
    #5 data_in = 8'h0A;  // regB = 10
    #5 data_in = 8'h05;  // regC = 5
    #5 data_in = 8'h00;  // regC not used in this instruction

    #10 instruction = 8'h36;  // STORE regA, [address]
    #5 data_in = 8'h07;  // Store regA value to memory address 7

    #10 instruction = 8'h1B;  // SUB regA, regB, regC (regA = regB - regC)
    #5 data_in = 8'h0A;  // regB = 10
    #5 data_in = 8'h02;  // regC = 2
    #5 data_in = 8'h00;  // regC not used in this instruction

    #10 instruction = 8'h3D;  // LOAD regA, [address]
    #5 data_in = 8'h07;  // Load memory value at address 7 to regA

    // Expected results:
    // regA = 10 + 5 = 15 (after ADD instruction)
    // memory[7] = 15 (after STORE instruction)
    // regA = 10 - 2 = 8 (after SUB instruction)
    // regA = 15 (after LOAD instruction)

    // Verify results
    #5 if (data_out === 8'h0F) $display("ADD instruction: Passed");
    else $display("ADD instruction: Failed");

    #5 if (memory[7] === 8'h0F) $display("STORE instruction: Passed");
    else $display("STORE instruction: Failed");

    #5 if (data_out === 8'h08) $display("SUB instruction: Passed");
    else $display("SUB instruction: Failed");

    #5 if (data_out === 8'h0F) $display("LOAD instruction: Passed");
    else $display("LOAD instruction: Failed");

    // Additional operations
    #10 instruction = 8'h52;  // AND regA, regB, regC (regA = regB & regC)
    #5 data_in = 8'h0F;  // regB = 15
    #5 data_in = 8'h05;  // regC = 5
    #5 data_in = 8'h00;  // regC not used in this instruction

    #10 instruction = 8'h73;  // OR regA, regB, regC (regA = regB | regC)
    #5 data_in = 8'h0A;  // regB = 10
    #5 data_in = 8'h03;  // regC = 3
    #5 data_in = 8'h00;  // regC not used in this instruction

    #10 instruction = 8'h9E;  // XOR regA, regB, regC (regA = regB ^ regC)
    #5 data_in = 8'hF0;  // regB = 240
    #5 data_in = 8'h0F;  // regC = 15
    #5 data_in = 8'h00;  // regC not used in this instruction

    #10 instruction = 8'hBF;  // SHIFT LEFT regA
    #10 instruction = 8'hA0;  // SHIFT RIGHT regA

    // Expected results:
    // regA = 15 & 5 = 5 (after AND instruction)
    // regA = 10 | 3 = 11 (after OR instruction)
    // regA = 240 ^ 15 = 255 (after XOR instruction)
    // regA = 510 (after SHIFT LEFT and SHIFT RIGHT instructions)

    // Verify results
    #5 if (data_out === 8'h05) $display("AND instruction: Passed");
    else $display("AND instruction: Failed");

    #5 if (data_out === 8'h0B) $display("OR instruction: Passed");
    else $display("OR instruction: Failed");

    #5 if (data_out === 8'hFF) $display("XOR instruction: Passed");
    else $display("XOR instruction: Failed");

    #5 if (data_out === 8'hFE) $display("SHIFT LEFT and SHIFT RIGHT instructions: Passed");
    else $display("SHIFT LEFT and SHIFT RIGHT instructions: Failed");

    $finish;
  end

  always #5 clk = ~clk;

endmodule

 

 

This was a very simple exercise and now we can be proud that we have created our own first processor. 

In the next tutorial, we will try to add driver, agent and other components in the same code. 

Till then, Happy Coding!!
 

bottom of page