2
\$\begingroup\$

Hello EE StackExchange!

I have been trying to design a simple 8-bit CPU for several months now. However, I am experiencing a problem: The ALU outputs the result of the operation two clock cycles after it has been presented with valid data. Why is this happening, and, most importantly, is there a way I can rectify this behavior? The FPGA architecture I am simulating against is Spartan 3, and the ALU is written in verilog.

The code follows:

module alu  (input [7:0] a,b,
             input [3:0] opcode,
             input clk, reset,
             output reg [7:0] y,
             output reg cout);
        /* Decode the instruction */
        always @(posedge clk)
        if(reset == 1)
        begin
                y <= 8'b0;
                cout <= 0;
        end
        else if(reset == 0)
        begin
                case (opcode)
                        4'h00 /* OR */:   y <= a | b;
                        4'h01 /* AND */:   y <= a & b;
                        4'h02 /* NOTA */:   y <= ~a;
                        4'h03 /* XOR */:   y <= a ^ b;
                        4'h04 /* ADD */:   y <= a - b;
                        4'h05 /* SUB */:   y <= a - b;
                endcase
        end
endmodule //alu
\$\endgroup\$
  • 2
    \$\begingroup\$ In the first cycle you assert the data on opcode, a and b. In the second clock cycle it will be clocked onto y ready to be used on the third clock cycle. Without seeing your simulation results and more crucially test-bench code, that's all that can be said. I should also mention your 'ADD' implementation is wrong, and you don't do anything with cout. I would also add a default: case to capture opcode values of 6 and 7. \$\endgroup\$ – Tom Carpenter Jul 18 '15 at 16:32
  • \$\begingroup\$ @TomCarpenter: I understand. I assume there is no way to implement the ALU using a wire output, so, I suppose I am stuck with the two-cycle process. As for the problematic AND, it seems it was a slip of the hand (those + and - keys are so close to one another :-P) Anyway, thanks for the input! \$\endgroup\$ – infiniteNOP Jul 18 '15 at 17:18
  • 1
    \$\begingroup\$ Whay does our ALU need a clock at all? It's a purely combinatorial function. \$\endgroup\$ – Dave Tweed Jul 18 '15 at 17:39
  • \$\begingroup\$ @DaveTweed: It's that I am a beginner, so I didn't know that :-P That's why I ask, I seek to learn. \$\endgroup\$ – infiniteNOP Jul 18 '15 at 18:05
  • 1
    \$\begingroup\$ You can do a combination process, but be aware that in a larger system such as a CPU, it will slow down the maximum operating frequency by creating fairly long combinational paths, so the additional pipelining may be needed. \$\endgroup\$ – Tom Carpenter Jul 18 '15 at 18:12
5
\$\begingroup\$

If you want immediate results from your ALU, then don't use a clocked process at all:

module alu (
  input [7:0] a,
  input [7:0] b,
  input [3:0] opcode,
  output reg [7:0] y
);

  /* Decode the instruction */
  always @* begin
    case (opcode)
      4'h00 /* OR */:   y <= a | b;
      4'h01 /* AND */:   y <= a & b;
      4'h02 /* NOTA */:   y <= ~a;
      4'h03 /* XOR */:   y <= a ^ b;
      4'h04 /* ADD */:   y <= a + b;
      4'h05 /* SUB */:   y <= a - b;
    endcase
  end

endmodule
| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ Both answers given to me were equally good, but, unfortunately, I am only allowed to mark one of them... \$\endgroup\$ – infiniteNOP Jul 18 '15 at 18:24
2
\$\begingroup\$

Here is a small test bench I prepared for your design (Pl I'm a beginner as well):

`timescale 1 ns / 1 ns

module multiplierTest ( );

reg [7 : 0] a, b ;
reg clk , reset ;
reg [3:0] opcode  ;
wire [7 : 0] y ; 
wire [7 : 0] cout ; 


alu  multiplier_uut         (   .a(a),
                                .b(b),
                            .clk(clk),
                            .opcode(opcode), 
                            .reset(reset),
                            .y(y),
                            .cout(cout)
                        ) ;

//Initialise registers 
initial 
begin
clk = 1'b0 ;

a = 'h00 ;
b = 'h00 ;
opcode = 'h0 ;
reset = 1'b1 ;
end


initial
begin
repeat (4) @ (negedge clk) ;
reset = 0 ;
@ (negedge clk) ;
a = $random ;
b = $random ;
opcode = 'h3 ;
repeat (4) @ (negedge clk) ;
$stop ;
end

//clock
always #25 clk = ~clk ;

endmodule                                   

If you just copy- paste this and run, you will see that your output does come as expected. I would like to point a few things (which I have learnt from my short verilog experience ) :

  • If you want your output to appear on clock edge, make the input available before that. Otherwise timing constraints (setup and hold times) will not be met. I personally like to make the inputs available 1 clock edge in advance. So here in your alu, the output should be asserted on posedge ; so I have made available the inputs beforehand at negedge. Now I dont know whether this is good or bad, but this seems to work with me always.

  • You should give a default statement in your case always and include all the default values of outputs as well. Otherwise during synthesis, latches will be inferred.

  • You have also not made use of the variable cout ( as pointed by Tom Carpenter) and your variable sizes dont match. They should be 4'h1 not 4'h01 as 1 hex is 4 bits.

  • Another thing which I always run into while synthesizing my design is that reg connections are not allowed on inputs and outputs. Xilinx always complains and wants them to be wire. So you can make them wire, declare a reg for your always block and do

    assign output = output_reg

(Please do let me know if I seem to contradict anything)

| improve this answer | |
\$\endgroup\$
  • 1
    \$\begingroup\$ Thanks, but, I already have a testbench for the CPU that is using this ALU, so I do not do this. Thanks for your time and feedback, though! \$\endgroup\$ – infiniteNOP Jul 18 '15 at 17:51

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.