The Improved Shift Register Fails

The length of the output from the previous test makes clear that it would be really nice if we could change the whole value of the register in one go. For that we need to add parallel input. Note that this is not strictly needed to make the system work but it will make our lives a lot easier as we run the tests.

I took a look at the kinds of thing that are available in the 74 series of logic chips and came up with the 74195 4-bit right-shift register. It actually offers a bit more than we need since it can shift in both directions and we only need to go to the right. It adds not only a parallel input but also two control inputs and an asynchrnous reset input. It is designed to cascade trivially so I am quite happy to produce the Verilog version of an 8-bit universal register register with four modes

S1 S0 Action
0
0
Hold previous value
0
1
Shift value to right
1
0
Shift value to left
1
1
Parallel load register

It is fairly easy to add these additional functions to our register to get a parallel/serial register. Here is my first try. Note that I have used a 2-bit mode input instead of separate S1 and S0 inputs.

PSRegister194.v
//
//	Parallel-in, parallel-out, serial out register with synchronous
//	load & shift and asynchronous clear (reset). Design based on the
//	74194 universal shift register but extended to arbitrary number
//	of bits.
//	pin[8] : parallel input
//	mode[2] : mode control 0 hold, 1 shl, 2 shr, 3 load
//	reset : asynchronous reset to zero (active low)
//	pout[8] : parallel output
//	sout : rightmost bit shifted out
//
module psregister(sin, pin, clk, mode, reset, pout, sout);
 parameter WIDTH = 8;
 output [WIDTH-1 : 0] pout;
           output sout;
           input [WIDTH-1:0] pin;
           input [1:0] mode;
           input  clk, sin, reset;
 reg [WIDTH-1 : 0]   pout;
           reg sout;
           wire sin,	pin, clk, mode, reset;
 always @(posedge clk)
    if (mode == 3)
        pout <= pin;
    else if (mode == 2) begin
           sout = pout[0];
           pout = {1'b0, pout[WIDTH-1:1]};
        end
    else if (mode == 1) begin
           sout = pout[WIDTH-1];
           pout = {pout[WIDTH-1],sin};
        end
 always @reset
    if (reset == 0) begin
           assign sout = 0;
           assign pout = 0;
        end
    else begin
           deassign sout;
           deassign pout;
        end
endmodule // psregister
 

I ran it with a slightly modified version of the previous test..

PSRegister194_tb.v
//
//	Test for parallel/serial in-out register modeled on 74194.
//	Register is defined as 
//   module psregister(pin, clk, load, shift, reset, pout, sout);
//
module test;
 /*	Make reg inputs and wire outputs for register */
 /*	We need input bus and clock, mode, serial in, and reset as inputs */
           reg [7:0] inbus = 0;
           reg clk = 0;
           reg [1:0] mode = 0;
           reg reset = 1;
           reg sin = 0;
 /* Make a reset that pulses once. */
           initial begin
           # 17 reset = 0;
           # 11 reset = 1;	/* Comes out of reset at time 28 */
           # 202 $stop;
           end
 /* Change the value on the input bus every so often */
           initial begin
           # 33 inbus = 8'hAA;
           #  5 inbus = 8'hAC;	// 38
           #  5 inbus = 8'h0A;	// 43
           #  9 inbus = 8'hF0;  // 52
           # 10 inbus = 8'h8A; // 62
           end
   
           /* Do loads for just two of the changes then start a shift at 69 */
           initial begin
           # 42 mode = 3;    // Load
           #  5 mode = 0;	// Hold
           # 14 mode = 3;	// Load
           #  5 mode = 0;	// Hold
           #  3 mode = 1;    // Shift right
           # 82 mode = 0;    // Hold
           end
   
 /* Make a regular pulsing clock. */
 always #5 clk = !clk;
 wire [7:0] value;
 wire sdata;
 psregister r1 (sin, inbus, clk, mode, reset, value, sdata);
 initial
    $monitor("At time %t, rst=%d, sin=%d, pin=%d, mode=%d -> 
                 value = %h (%0d), sout = %d",
             $time, reset, sin, inbus, mode, value, value, sdata);
endmodule // test

The result was NOT what I hoped for.

   At time   0, rst=1, sin=0, pin=  0, mode=0 -> value = xx (x), sout = x
   At time  17, rst=0, sin=0, pin=  0, mode=0 -> value = 00 (0), sout = 0
   At time  28, rst=1, sin=0, pin=  0, mode=0 -> value = 00 (0), sout = 0
   At time  33, rst=1, sin=0, pin=170, mode=0 -> value = 00 (0), sout = 0
   At time  38, rst=1, sin=0, pin=172, mode=0 -> value = 00 (0), sout = 0
   At time  42, rst=1, sin=0, pin=172, mode=3 -> value = 00 (0), sout = 0
   At time  43, rst=1, sin=0, pin= 10, mode=3 -> value = 00 (0), sout = 0
   At time  45, rst=1, sin=0, pin= 10, mode=3 -> value = 0a (10), sout = 0
   At time  47, rst=1, sin=0, pin= 10, mode=0 -> value = 0a (10), sout = 0
   At time  52, rst=1, sin=0, pin=240, mode=0 -> value = 0a (10), sout = 0
   At time  61, rst=1, sin=0, pin=240, mode=3 -> value = 0a (10), sout = 0
   At time  62, rst=1, sin=0, pin=138, mode=3 -> value = 0a (10), sout = 0
   At time  65, rst=1, sin=0, pin=138, mode=3 -> value = 8a (138), sout = 0
   At time  66, rst=1, sin=0, pin=138, mode=0 -> value = 8a (138), sout = 0
   At time  69, rst=1, sin=0, pin=138, mode=1 -> value = 8a (138), sout = 0
   At time  75, rst=1, sin=0, pin=138, mode=1 -> value = 02 (2), sout = 1
   At time  85, rst=1, sin=0, pin=138, mode=1 -> value = 00 (0), sout = 0
   At time 151, rst=1, sin=0, pin=138, mode=0 -> value = 00 (0), sout = 0
   ** VVP Stop(0) **
   ** Flushing output streams.
   ** Current simulation time is 230 ticks.

All went well until I set mode to 1. I meant to do a shift right but specified a shift left instead. At time 75, after asking for the shift, I got the correct sout but the value in the register should have been 0x14 and not 0x02.

Brian Collett