串并转换是FPGA设计的一个重要技巧,是数据流出来的常用手段,也是面积与速度互换思想的直接体现。串并转换的实现方法多种多样,根据数据的排序和数量的要求,可以选用寄存器、ram等实现。
并行转串行数据输出:采用计数方法,将并行的数据总数先表示出来,然后发送一位数据减一。
module p2s(
input clk,
input rst_n,
input load,
input [7:0] pdata,
output sdata
);
reg [2:0]bit_cnt;
reg [7:0] temp_data;
reg en;
always @ (posedge clk or negedge rst_n) begin
if(!rst_n) begin
en <= 'b0;
end
else if(load) begin
en <= 1'b1;
end
else if(bit_cnt==3'd7) begin
en <= 1'b0;
end
end
always @ (posedge clk or negedge rst_n) begin
if(!rst_n) begin
bit_cnt <= 3'b0;
end
else if(en) begin
bit_cnt <= bit_cnt + 1'b1;
end
else begin
bit_cnt <= 3'b0;
end
end
always @ (posedge clk or negedge rst_n) begin
if(!rst_n) begin
temp_data <= 8'b0;
end
else if(load) begin
temp_data <= pdata;
end
else if(en) begin
temp_data <= temp_data << 1;
end
end
assign sdata = temp_data[7];
endmodule
/* module p2s (
input clk,
input rst_n,
input load,
input [7:0] pdata,
output sclk,
output sdata
);
reg [3:0] bit_cnt;
reg en;
reg [7:0] shuff;
always @ (posedge clk or negedge rst_n) begin
if(!rst_n) begin
en <= 1'b0;
end
else if(load) begin
en <= 1'b1;
end
else if(bit_cnt==4'hf) begin
en <= 1'b0;
end
end
always @ (posedge clk or negedge rst_n) begin
if(!rst_n) begin
bit_cnt <= 'b0;
end
else if(en) begin
bit_cnt <= bit_cnt + 1'b1;
end
else begin
bit_cnt <= 'b0;
end
end
assign sclk = bit_cnt[0];
always @ (posedge clk or negedge rst_n) begin
if(!rst_n) begin
shuff <= 8'b0;
end
else if(load) begin
shuff <= pdata;
end
else if(sclk) begin
shuff <= shuff << 1;
end
end
assign sdata = shuff[7];
endmodule */
测试代码:
`timescale 1ps/1ps
module p2s_tb();
reg clk;
reg rst_n;
reg load;
reg [7:0] pdata;
wire sdata;
wire sclk;
initial begin
clk = 0;
pdata=8'h0;
rst_n = 0;
load = 0;
#14;
rst_n = 1;
#32;
load = 1;
pdata = 8'haa;
#10;
load = 0;
pdata = 8'h12;
#100;
load = 1;
pdata=8'h55;
#10;
load = 0;
pdata = 8'h34;
#100;
load = 1;
pdata=8'hff;
#10;
load = 0;
pdata = 8'h34;
end
always #5 clk = ~clk;
p2s p2s_inst(
.clk(clk),
.rst_n(rst_n),
.load(load),
.pdata(pdata),
.sdata(sdata)
//.sclk(sclk)
);
endmodule
在这个代码中,最后的输出数据就刚好和en使能信号是完全对齐的那8个数据。
串行转并行数据输出:采用位拼接结束,将串行的数据总数先表示出来,然后发送一位数据加一。
module p2s(
input clk,
input datain,
input rst_n,
input valid,
output [7:0] dataout,
output reg done
);
reg [2:0] cnt;
reg [7:0] tempdata;
always @ (posedge clk or negedge rst_n) begin
if(!rst_n) begin
tempdata <= 8'b0;
cnt <= 3'b0;
done <= 1'b0;
end
else if(valid) begin
case(cnt)
3'd0 : begin
tempdata[0] <= datain;
cnt <= cnt + 1'b1;
done <= 1'b0;
end
3'd1 : begin
tempdata[1] <= datain;
cnt <= cnt + 1'b1;
end
3'd2 : begin
tempdata[2] <= datain;
cnt <= cnt + 1'b1;
end
3'd3 : begin
tempdata[3] <= datain;
cnt <= cnt + 1'b1;
end
3'd4 : begin
tempdata[4] <= datain;
cnt <= cnt + 1'b1;
end
3'd5 : begin
tempdata[5] <= datain;
cnt <= cnt + 1'b1;
end
3'd6 : begin
tempdata[6] <= datain;
cnt <= cnt + 1'b1;
end
3'd7 : begin
tempdata[7] <= datain;
cnt <= 3'd0;
done <= 1'b1;
end
endcase
end
else begin
tempdata <= 8'b0;
cnt <= 3'b0;
done <= 1'b0;
end
end
assign dataout = done ? tempdata : 8'b0;
endmodule
测试代码
`timescale 1ps/1ps
module p2s_tb();
reg clk;
reg datain;
reg rst_n;
reg valid;
wire [7:0] dataout;
wire done;
p2s p2s_inst(
.clk(clk),
.datain(datain),
.rst_n(rst_n),
.valid(valid),
.dataout(dataout),
.done(done)
);
initial begin
rst_n = 0;
clk = 0;
#13;
rst_n = 1;
end
always #5 clk = ~clk;
initial begin
valid = 0;
#30;
valid = 1;
#170;
valid = 0;
end
initial begin
datain = 0;
#5;
datain = 1;
#10;
datain = 1;
#10;
datain= 0;
#10;
datain = 1;
#10;
datain = 1;
#10;
datain = 0;
#10;
datain =1;
#10;
datain = 1;
#10;
datain = 1;
#10;
datain= 0;
#10;
datain = 1;
#10;
datain = 1;
#10;
datain = 0;
#10;
datain =1;
#10;
datain = 1;
#10;
datain = 0;
#10;
datain =1;
#10;
datain = 1;
#10;
datain = 1;
#10;
datain= 0;
#10;
datain = 1;
#10;
datain = 0;
#10;
datain =1;
#10;
datain = 1;
#10;
datain = 1;
#10;
datain= 0;
#10;
datain = 1;
#10;
datain = 0;
#10;
datain =1;
#10;
datain = 1;
#10;
datain = 1;
#10;
datain= 0;
#10;
end
endmodule
流水线操作设计思想
流水线处理是高速设计中的一个常用设计手段。如果某个设计的处理流程分为若干步骤,而且整个数据处理是“单流向”的,即没有反馈或者迭代运算,前一个步骤的输出是下一个步骤的输入,就可以考虑流水线设计方法来提高系统的工作频率。
流水线设计的结构如下图所示,将适当划分的n个操作步骤单流向串联起来。流水线操作的最大特点和要求是,数据流在各个步骤的处理从时间上看是连续的,如果每个操作步骤简化假设为通过一个D触发器(就是用寄存器打一个节拍),那么流水线操作就类似一个移位寄存器组,数据流依次流经D触发器,完成每个步骤的操作。流水线设计时序如下图:
流水线设计的一个关键在于整个设计时序的合理安排,要求每个操作步骤的划分合理。如果前级操作时间恰好等于后级的操作时间,设计最为简单,前级的输出直接汇入后级的输入即可;如果前级的操作时间大于后级的操作时间,则需要对前级的输出数据适当缓存才能汇入到后级输入端;如果前级操作时间恰好小于后级的 操作时间,则必须通过复制逻辑,将数据流分流,或者在前级对数据采用存储、后处理方式,否则会造成后级数据溢出。