Ready-to-run snippets

Code Examples

Ready-to-run Verilog, SystemVerilog, and UVM examples. Click any to open it live in the IDE.

← All examples

Parallel vs Serial Transfer

Verilog Bus Protocols

One byte sent over an 8-bit parallel link and over a 1-bit serial line, LSB first.

Open in IDE
design.v
// The same byte moved two ways: over an 8-bit parallel bus in one cycle,
// and over a 1-bit serial line in eight cycles (LSB first), framed by sframe.

// Parallel: the receiver registers all 8 bits at once
module par_link (
  input            clk,
  input            rst,
  input            load,
  input      [7:0] din,
  output reg [7:0] dout,
  output reg       done
);
  always @(posedge clk) begin
    if (rst) begin
      dout <= 8'h00;
      done <= 1'b0;
    end
    else begin
      done <= load;
      if (load)
        dout <= din;
    end
  end
endmodule

// Serial transmitter: shifts the byte out one bit per clock, LSB first
module ser_tx (
  input            clk,
  input            rst,
  input            load,
  input      [7:0] din,
  output           sd,
  output reg       sframe
);
  reg [7:0] sh;
  reg [3:0] n;

  assign sd = sh[0];

  always @(posedge clk) begin
    if (rst) begin
      n      <= 4'd0;
      sframe <= 1'b0;
    end
    else if (load) begin
      sh     <= din;
      n      <= 4'd8;
      sframe <= 1'b1;
    end
    else if (n != 0) begin
      sh <= sh >> 1;
      n  <= n - 4'd1;
      if (n == 4'd1)
        sframe <= 1'b0;
    end
  end
endmodule

// Serial receiver: shifts bits in from the top, so bit 0 ends up at the right
module ser_rx (
  input            clk,
  input            rst,
  input            sd,
  input            sframe,
  output reg [7:0] dout,
  output reg       done
);
  reg [7:0] sh;
  reg       sframe_d;

  always @(posedge clk) begin
    if (rst) begin
      done     <= 1'b0;
      sframe_d <= 1'b0;
    end
    else begin
      sframe_d <= sframe;
      if (sframe)
        sh <= {sd, sh[7:1]};
      done <= sframe_d && !sframe;     // the frame just ended
      if (sframe_d && !sframe)
        dout <= sh;
    end
  end
endmodule
testbench.v
module tb;
  reg        clk  = 0;
  reg        rst  = 1;
  reg        load = 0;
  reg  [7:0] din  = 8'h00;
  wire [7:0] pdout, sdout;
  wire       pdone, sdone, sd, sframe;

  par_link u_par (
    .clk  (clk),
    .rst  (rst),
    .load (load),
    .din  (din),
    .dout (pdout),
    .done (pdone)
  );

  ser_tx u_tx (
    .clk    (clk),
    .rst    (rst),
    .load   (load),
    .din    (din),
    .sd     (sd),
    .sframe (sframe)
  );

  ser_rx u_rx (
    .clk    (clk),
    .rst    (rst),
    .sd     (sd),
    .sframe (sframe),
    .dout   (sdout),
    .done   (sdone)
  );

  always #5 clk = ~clk;

  always @(posedge clk) begin
    if (pdone)
      $display("%0t  parallel received %h", $time, pdout);
    if (sdone)
      $display("%0t  serial   received %h", $time, sdout);
  end

  initial begin
    $dumpfile("dump.vcd");
    $dumpvars(0, tb);
    #12 rst = 0;
    @(negedge clk);
    din  = 8'hB4;                    // 1011_0100
    load = 1;
    @(negedge clk);
    load = 0;
    #150 $finish;
  end
endmodule
Admin mode — edit and delete controls are visible on each row. Use the IDE to add new snippets via File → Save as Snippet.