Shift register, connecting wired inputs to internal register

Viewed 82

Here is my module

module shift(
input clk,
input rstn,
input load, 
input dir,
input [7:0] LD,
output cout
);

reg [7:0] mem;

assign cout = dir?mem[0]:mem[7] ;


always @(posedge clk or negedge rstn)
begin
 if(!rstn)
  mem <= 8'h00;
 else begin
  if(load) 
   mem <= LD ;
  else mem <= mem ;
  case(dir)
   0 : mem <= mem<<1 ;
   1 : mem <= mem>>1 ;
  endcase
 end
end

endmodule   

and here is my testbench.

module shift_tb();

reg clk;
reg rstn;
reg load;
reg dir;
reg[7:0] LD ;
wire cout;

shift UUT(.clk(clk), .rstn(rstn), .load(load), .dir(dir), .LD(LD), .cout(cout));

initial begin

$dumpfile("shift_out.vcd");
$dumpvars(2,shift_tb);

 clk = 0 ;
 rstn = 0 ;
 load = 0;
 dir = 0 ;
 LD = 8'h00;
 
 #10;
 rstn = 1;

 LD = 8'h55 ;
 load = 1;
 dir = 0 ;

 #100;

 LD = 8'hAA ;
 load = 1;
 dir = 1;

 #100;
 
 LD = 8'hFF;
 load = 1;
 rstn = 0 ;
 
 #20 ;
 $finish;
end 

always 
 #5 clk = ~clk ;

endmodule

In the above code, my internal register "mem" does not take in the values from "LD" (parallel i/p ).

It stays at 0. The code does shift if mem is initialized with a random value say 8'h22 but still doesn't take in LD.

This contains the waveform enter image description here

2 Answers

The problem is that you have multiple active nonblocking assignments to mem; only one should be active at any given time. After reset, you have load=1 and dir=0. This means your code first assigns mem <= LD then immediately assigns mem <= mem<<1. You must not do that. Your code has the case in parallel with the if statement. Perhaps you intended the case to be inside the else clause.

always @(posedge clk or negedge rstn) begin
    if(!rstn)
        mem <= 8'h00;
    else begin
        if(load) 
            mem <= LD ;
        else
            case(dir)
                0 : mem <= mem<<1;
                1 : mem <= mem>>1;
            endcase
    end
end

When I run the sim, I see mem change to 'h55, as expected.

In this case, you just need to pulse LD high for one cycle in your testbench, instead of keeping it high all the time:

 LD = 8'h55 ;
 load = 1;
 dir = 0 ;

 #10;
 load = 0;

 #100;

You have used a very verbose logic. Try this..

always @(posedge clk or negedge rstn)
begin
if(!rstn)
  mem <= 8'h00;
else 
 mem <= (load)?LD:( dir ? mem>>1 : mem<<1 ); 
end

In your tb use this. Transition rst as 1->0->1. Keep LD and load stable for 1 clock cycle. Then de-assert load.

initial
begin
 clk = 1'd0;
 rst = 1'd1;
 load = 1'd0;
 dir = 1'd0;
 LD  = 'd0;

 #10  rst = 1'd0;
 #100 rst = 1'd1;
    load = 1'd1;
    LD = 8'h55;
 #10 load = 1'd0;

 end
Related