Reference:
“Digital VLSI Design with Verilog”, John Williams, Springer, 2008.
Page 78 – 80.
1、Verilog Code
SerClock:a Serial Clock input;
ParValid: indicate when data on the parallel bus are stable and valid;
SerValidFlag: Clock out the data high-order bit (MSB) first, one bit per serial clock, setting a SerValidFlag when the first bit is on the serial bus and clearing it after the last bit is on the serial bus.
Done: use it to hold the state of the serialization.
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: SEU.IC
// Engineer: Ray
//
// Create Date: 15:27:50 04/03/2011
// Design Name:
// Module Name: par_to_ser_2
//////////////////////////////////////////////////////////////////////////////////
module ParToSerial #(parameter BusHi = 12)
(output SerOut, SerValidFlag
, input SerClock, ParValid
, input[BusHi:0] BusIn
);
//
// A clever way to declare the width of ix to agree with
// the parameterized width of BusHi would be to calculate
// the log using the C-like conditional expression operator.
//
// Note: A localparam is the same as a parameter,
// which would be OK here. A localparam can not be
// overridden; it gets a definite value, not just a default.
//
localparam ixHi = (BusHi < 2**2)? 1
: (BusHi < 2**3)? 2
: (BusHi < 2**4)? 3
: (BusHi < 2**5)? 4
: (BusHi < 2**6)? 5
: (BusHi < 2**7)? 6
: (BusHi < 2**8)? 7
: (BusHi < 2**9)? 8
: (BusHi < 2**10)? 9
: (BusHi < 2**11)? 10
: 'bx;
// Might as well stop at 10: That will handle
// BusIn up to 2**11 = 2048 bits wide.
//
reg[ixHi:0] ix;
//
reg SerValid, Done, SerBit;
reg SerValidFlag;
//////////////////////////////////////////////////////////////////////////////////
// Company: SEU.IC
// Engineer: Ray
//
// Create Date: 15:27:50 04/03/2011
// Design Name:
// Module Name: par_to_ser_2
//////////////////////////////////////////////////////////////////////////////////
module ParToSerial #(parameter BusHi = 12)
(output SerOut, SerValidFlag
, input SerClock, ParValid
, input[BusHi:0] BusIn
);
//
// A clever way to declare the width of ix to agree with
// the parameterized width of BusHi would be to calculate
// the log using the C-like conditional expression operator.
//
// Note: A localparam is the same as a parameter,
// which would be OK here. A localparam can not be
// overridden; it gets a definite value, not just a default.
//
localparam ixHi = (BusHi < 2**2)? 1
: (BusHi < 2**3)? 2
: (BusHi < 2**4)? 3
: (BusHi < 2**5)? 4
: (BusHi < 2**6)? 5
: (BusHi < 2**7)? 6
: (BusHi < 2**8)? 7
: (BusHi < 2**9)? 8
: (BusHi < 2**10)? 9
: (BusHi < 2**11)? 10
: 'bx;
// Might as well stop at 10: That will handle
// BusIn up to 2**11 = 2048 bits wide.
//
reg[ixHi:0] ix;
//
reg SerValid, Done, SerBit;
reg SerValidFlag;
assign SerOut = SerBit;
always @ (posedge SerClock)
SerValidFlag <= SerValid;
always@(posedge SerClock)
begin
// Reset everything unless ParValid:
if (ParValid==1'b1)
if (SerValid==1'b1)
begin
SerBit <= BusIn[ix]; // Current serial bit.
if (ix==0)
begin
SerValid <= 1'b0;
Done <= 1'b1;
end
else ix <= ix - 1;
end // SerValid was asserted.
else // No start yet:
begin
if (Done==1'b0)
begin
SerValid <= 1'b1; // Flag start on next SerClock.
ix <= BusHi ;
// Ready to start on next SerClock.
end
SerBit <= 1'b0; // Serial bit default.
end
else // ParValid not 1; reset everything:
begin
SerValid <= 1'b0;
Done <= 1'b0;
SerBit <= 1'b0; // Serial bit default.
end // if ParValid else
end // always
//
endmodule // ParToSerial
SerValidFlag <= SerValid;
always@(posedge SerClock)
begin
// Reset everything unless ParValid:
if (ParValid==1'b1)
if (SerValid==1'b1)
begin
SerBit <= BusIn[ix]; // Current serial bit.
if (ix==0)
begin
SerValid <= 1'b0;
Done <= 1'b1;
end
else ix <= ix - 1;
end // SerValid was asserted.
else // No start yet:
begin
if (Done==1'b0)
begin
SerValid <= 1'b1; // Flag start on next SerClock.
ix <= BusHi ;
// Ready to start on next SerClock.
end
SerBit <= 1'b0; // Serial bit default.
end
else // ParValid not 1; reset everything:
begin
SerValid <= 1'b0;
Done <= 1'b0;
SerBit <= 1'b0; // Serial bit default.
end // if ParValid else
end // always
//
endmodule // ParToSerial
testbench for the verilog code,
`timescale 1ns / 1ps
////////////////////////////////////////////////////////////////////////////////
// Company: SEU.IC
// Engineer:Ray
//
// Create Date: 15:47:35 04/03/2011
// Design Name: ParToSerial
// Module Name: E:/ray_study_verilog/parallel_to_serial/tb_par_to_sel_2_2.v
// Project Name: parallel_to_serial
////////////////////////////////////////////////////////////////////////////////
// Company: SEU.IC
// Engineer:Ray
//
// Create Date: 15:47:35 04/03/2011
// Design Name: ParToSerial
// Module Name: E:/ray_study_verilog/parallel_to_serial/tb_par_to_sel_2_2.v
// Project Name: parallel_to_serial
////////////////////////////////////////////////////////////////////////////////
module tb_par_to_sel;
// Inputs
reg SerClock;
reg ParValid;
reg [12:0] BusIn;
reg SerClock;
reg ParValid;
reg [12:0] BusIn;
// Outputs
wire SerOut;
wire SerValidFlag;
wire SerOut;
wire SerValidFlag;
// Instantiate the Unit Under Test (UUT)
ParToSerial uut (
.SerOut(SerOut),
.SerValidFlag(SerValidFlag),
.SerClock(SerClock),
.ParValid(ParValid),
.BusIn(BusIn)
);
always@(SerClock) // 100 MHz
#5 SerClock <= ~SerClock;
//
always@(BusIn) // 1 MHz
begin
#500 BusIn <= BusIn +16'h010f;
end
//
always@(BusIn)
begin
#14 ParValid = 1'b1;
#460 ParValid = 1'b0;
end
//
initial
begin
#0 SerClock = 1'b0;
#0 ParValid = 1'b0;
#21 BusIn = 16'hf000;
#5000 $finish;
end
endmodule
ParToSerial uut (
.SerOut(SerOut),
.SerValidFlag(SerValidFlag),
.SerClock(SerClock),
.ParValid(ParValid),
.BusIn(BusIn)
);
always@(SerClock) // 100 MHz
#5 SerClock <= ~SerClock;
//
always@(BusIn) // 1 MHz
begin
#500 BusIn <= BusIn +16'h010f;
end
//
always@(BusIn)
begin
#14 ParValid = 1'b1;
#460 ParValid = 1'b0;
end
//
initial
begin
#0 SerClock = 1'b0;
#0 ParValid = 1'b0;
#21 BusIn = 16'hf000;
#5000 $finish;
end
endmodule
Simulation Waves:
1、parallel data width is 13
2、parallel data width is 16
沒有留言:
張貼留言