基于FPGA的设计思想之串并转换与流水线

串并转换是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触发器,完成每个步骤的操作。流水线设计时序如下图:
在这里插入图片描述
流水线设计的一个关键在于整个设计时序的合理安排,要求每个操作步骤的划分合理。如果前级操作时间恰好等于后级的操作时间,设计最为简单,前级的输出直接汇入后级的输入即可;如果前级的操作时间大于后级的操作时间,则需要对前级的输出数据适当缓存才能汇入到后级输入端;如果前级操作时间恰好小于后级的 操作时间,则必须通过复制逻辑,将数据流分流,或者在前级对数据采用存储、后处理方式,否则会造成后级数据溢出。

猜你喜欢

转载自blog.csdn.net/weixin_43727437/article/details/106695660