for循环的硬件电路转化

以按行写按列读的交织器为例:

//按C语言写法
always@(posedge clk or negedge rstn)
begin
	if(!rstn)
	begin
	rdata<=0;
	end else if (!w_r)begin//写入
		for (Line=0;Line<=ROM_DEPTH;Line=Line+1)
			for(Column=0;Column<=ROM_WIDTH;Column=Column+1)
				memory[Line][Column]<=wdata;
	end else if (w_r) begin//读出
		for(Column=0;Column<=ROM_WIDTH;Column=Column+1)
			for (Line=0;Line<=ROM_DEPTH;Line=Line+1)
				rdata<=memory[Line][Column];
	end else begin
			rdata<=1'bx;
	end
end

但以上语句是不可综合的。
拆解思路一:硬件电路要时刻考虑时序,我们用一个时钟驱动计数器累加,由计数器的不同数值来触发事件,可综合语句case语句来做触发,例如

always@(posedge clk)
begin
	if(addr==2'b11)begin
		addr	<= 2'b00;
	end else else begin
		addr	<= addr + 1'b1;
	end
end

case(addr)
00:		rdata	<= memory[00][7:0];
01:		rdata	<= memory[01][7:0];
10:		rdata	<= memory[10][7:0];
11:		rdata	<= memory[11][7:0];

//以上代码就等效于
for(addr=0;addr<=3;addr++)
	rdata=memory[addr][7:0];

拆解思路二:如果情况很多时,case语句的劣势在于必须一一列举,例如有嵌套语句时,列举所有情况太过冗长。在存储器的例子中,实际上地址还是可以作为变量

always@(posedge clk or negedge rstn)
begin
	if(!rstn)begin
		Column <= 3'b0;
		Line   <= 3'b0;
	end else if(~w_r) begin//写入数据
		if (Column==ROM_WIDTH-1)begin
		//完成一次内层嵌套的循环
		//此时写完了一行,Line++ 
			Column <= 3'b0;
			if(Line==ROM_DEPTH-1)begin
			Line  <= 3'b0;
			end else begin
			Line  <= Line + 3'b001;
			end
		end else begin
			Column <= Column + 3'b001;
		end	
		memory[Line][Column] <= wdata;
	end else if (w_r) begin
		//读出数据
		if (Line==ROM_DEPTH-1)begin
		//完成一次内层嵌套的循环
		//读完了一列,Column++
			Line <= 3'b0;
			if(Column==ROM_WIDTH-1)begin
			Column  <= 3'b0;
			end else begin
			Column  <= Column + 3'b001;
			end
		end else begin
			Line <= Line + 3'b001;
		end	
		rdata <= memory[Line][Column];
	end
end

写for循环注意的要点
(1)从最大的不同点进行分类:本例子特点为按行写按列读,写入时先固定一行,扫描列写入,因此外层循环变量为行,内层嵌套为列;读出时按列读出,先固定一列,扫描行读出,因此外层循环变量为列,内层为行。
若行宽=列深,则行列是对称的,可以对其进行降维,也就是说不以读写行为作为分类,将行列互换即可。

if(~w_r) begin
	//write
		memory[Line][Column]<=wdata;
	end else if(w_r)  begin
	//read
		rdata<=memory[Column][Line];
	end

(2)注意边界:例如[7:0]Line,Line最大值为255,实际上Line==255 保持了一个时钟周期;
若约束条件为 if (Line= =256),要分情况讨论
Line位宽为[8:0]时,Line= =256会保持一个周期,但存储器实际上没有这个地址,导致写入失效,读出为高阻;
Line位宽为[7:0]时,Line++会回0,if (Line= =256)内的语句永远不会被执行。

(3)先判断后加/先加后判断:由于(2)所述的边界问题,会有不同的情形
一般情况下,由于变量的位宽限制,会先判断后自加

if (Line==ROM_DEPTH-1)begin
			Line <= 3'b0;
end else begin
			Line <= Line +1'b1;
end

但有些情况下,可能会先加后判断,例如在连续读写数据时,地址的跳位要求

begin
	Line <= Line + 9'h20;
	if(Line==256)begin
		Line <= 9'h0;
	end
end

上例中,连续读32位,第一次为读取地址为[31:0],下一次Line为32,64,96,128,160,196,224,256,Line=224时,整个Memory的数据已经读完了,因此要再加一次32使之回0。如果先判断后自加,则Line==256会保持一个时钟周期,导致读出为高阻。为消除这种状况,应使Line= =256后立即回0(仍在一个时钟周期之内)。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值