Name | Input | Output | Use |
|---|---|---|---|
PISO (parallel-in, serial-out) | A whole word, loaded at once | One bit per clock | Transmitter / serializer |
SIPO (serial-in, parallel-out) | One bit per clock | A whole word, valid after W bits | Receiver / deserializer |
Bit order must match on both ends. This page uses LSB-first order, as in UART. I²C data bytes are sent MSB-first.
The PISO output is bit 0 and the register shifts right. New bits enter the SIPO at the top and shift down, so the first bit sent lands in bit 0 after W shifts.
The two modules are connected only by one wire (wire_bit) and a shared shift enable. A real link adds start/stop framing and a bit counter so the receiver knows where a byte begins; the UART transmitter is exactly that.
Each slot is one clock cycle, sampled just after its rising edge. A bit on wire_bit in slot k is captured by the receiver at the edge that opens slot k+1.
Slot 0: load is high; the edge that opens slot 1 copies 0011 into the transmitter, so wire_bit shows bit 0 = 1.
Slots 1 to 4: shift is high. wire_bit carries 1, 1, 0, 0, which is 0011 read from the right.
rx: each new bit enters at the MSB, so rx reads 8 (1000), c (1100), 6 (0110), then 3 (0011) in slot 5, equal to the source.
Slot 5: shift falls after four shifts and rx holds the word. 0011 is not a palindrome, so a reversed link would have shown c instead.
Parallel bus | Serial link |
|---|---|
W wires, one word per clock | 1 wire, one word per W clocks |
Fast, uses many pins/tracks | Slow per wire but cheap in pins and routing |
Timing skew between wires | Single signal; clock recovery needed at high speeds |
In bit 0 of pdata. Each new bit enters at the MSB and shifts down one position per clock, so the first bit has travelled the full length of the register by the eighth shift.
The serializer, deserializer and loopback test below move seven byte patterns across one wire, including non-palindromic 0x01 and 0x96. Each wire bit is checked independently against the source byte in LSB-first order, so matching reversal bugs in both endpoints cannot hide. Both modules require W >= 2 (with W = 1 the selects become the reversed sreg[0:1] and pdata[0:1], which are illegal); an elaboration-time guard reports a clear error, though some tools may still diagnose the invalid select.
module piso #(parameter int W = 8) ( // W >= 2
input logic clk, rst_n,
input logic load,
input logic [W-1:0] pdata,
input logic shift,
output logic sout
);
if (W < 2) begin : g_w_check
$error("piso: W must be at least 2");
end
logic [W-1:0] sreg;
always_ff @(posedge clk or negedge rst_n)
if (!rst_n) sreg <= '0;
else if (load) sreg <= pdata; // load wins over shift
else if (shift) sreg <= {1'b0, sreg[W-1:1]}; // LSB leaves first
assign sout = sreg[0];
endmodule
module sipo #(parameter int W = 8) ( // W >= 2
input logic clk, rst_n,
input logic shift,
input logic sin,
output logic [W-1:0] pdata
);
if (W < 2) begin : g_w_check
$error("sipo: W must be at least 2");
end
always_ff @(posedge clk or negedge rst_n)
if (!rst_n) pdata <= '0;
else if (shift) pdata <= {sin, pdata[W-1:1]}; // new bit enters at the MSB
endmodule