常见的RTL代码布局布线时转成的电路是什么样的?因为不知道实际电路直接写代码可以实现功能,却不一定是节省面积的写法,因此,我想花些功夫去看一下代码转成的电路,希望有助于加深理解。
模块一:一个计数模块,复位清零,计到6清零
always @(posedge Clk or negedge Rst_n) begin
if (!Rst_n) begin
Clk_cnt <= 3'd0;
end
else if (Clk_cnt == 3'd6) begin
Clk_cnt <= 3'd0;
end
else begin
Clk_cnt <= Clk_cnt + 1'b1;
end
end
观察到三个触发器,时钟和清零很好理解,三个触发器的输入分别是三个LUT的输出,三个LUT都是三输入LUT,三个输入分别连的三个触发器的输出。
写出状态转移表就明白了
初态Q1 Q2 Q3 | 次态 Q1* Q2* Q3* |
000 | 001 |
001 | 010 |
010 | 011 |
011 | 100 |
100 | 101 |
101 | 110 |
110 | 000 |
也就是说,下一个输入取决于上一个输出的状态,如,当Q1=0,Q2=0,Q3=0时,Q1*=0,所以将Q1Q2Q3作为LUT的输入,当三个都为0时,LUT输出0,并送到Q1。Q2Q3类似。
当位数变多,超出器件的单个LUT输入端时,会在LUT前级联一个LUT,以扩展输入,如我的器件中LUT是6输入的,当我的位数有9位时,我需要9输入的LUT,此时会用6输入LUT的其中一个输入连一个4输入的LUT,这样就能做到9输入LUT。
模块二:一个判断条件,判断某个变量值为多少时进行寄存器数据变化,
always @ ( posedge Clk or negedge Rst_n) begin
if ( !Rst_n )
scl_r <= 1'b1;
else if(Clk_cnt == 9'd3 || Clk_cnt == 9'd2)
scl_r <= ~scl_r;
else
scl_r <= scl_r;
end
always @(posedge Clk or negedge Rst_n) begin
if (!Rst_n) begin
Clk_cnt <= 8'd0;
end
else if (Clk_cnt == 8'd5) begin
Clk_cnt <= 8'd0;
end
else begin
Clk_cnt <= Clk_cnt + 1'b1;
end
end
同样也是列出真值表,当值为某个值时令输出变化,由于此处变化为对原来值取反,所以将寄存器输入也送入LUT共同参与输出值的决定(图中蓝线)
模块三:状态机
module state_mechine(
input Clk,
input Rst_n,
output reg data_o1,
output reg data_o2
);
parameter
STATE1 =0,
STATE2 =1,
STATE3 =2;
reg [2:0] Clk_cnt;
reg [1:0] cstate;
reg [1:0] nstate;
always @(posedge Clk or negedge Rst_n) begin
if (!Rst_n)
Clk_cnt <= 9'd0;
else if (Clk_cnt == 9'd4)
Clk_cnt <= 9'd0;
else
Clk_cnt <= Clk_cnt + 1'b1;
end
//------------------------状态机------------------------------//
always @ ( posedge Clk or negedge Rst_n) begin
if ( !Rst_n )
cstate <= STATE1;
else
cstate <= nstate;
end
always @ ( * ) begin
nstate = STATE1;
case (cstate)
STATE1:begin
if(Clk_cnt == 9'd4)
nstate = STATE2;
else
nstate = STATE1;
end
STATE2:begin
if (Clk_cnt == 9'd4)
nstate = STATE3 ;
else
nstate = STATE2;
end
STATE3 :begin
if (Clk_cnt == 9'd4)
nstate = STATE1;
else
nstate = STATE3 ;
end
endcase
end
always @ ( posedge Clk or negedge Rst_n) begin
if ( !Rst_n )begin
data_o1 <= 1'b0;
data_o2 <= 1'b0;
end
else begin
case(cstate)
STATE1:begin
data_o1 <= 1'b0;
data_o2 <= 1'b1;
end
STATE2: begin
data_o1 <= 1'b0;
if (Clk_cnt == 9'd2)
data_o2 <= 0;
else
data_o2 <= 1;
end
STATE3:begin
data_o1 <= 1'b1;
if(Clk_cnt == 9'd2)
data_o2 <= 1;
else
data_o2 <= 0;
end
endcase
end
end
endmodule
对于cstate和nstate,其输出取决于状态和clk_cnt,因此,其前的LUT连着状态和clk_cnt。data_o1和data_o2同理。
模块四:移位寄存器
always @(posedge Clk or negedge Rst_n) begin
if (!Rst_n)
addr <= 4'b1001;
else begin
data_o <= addr[0];
addr <= addr >> 1;
end
end
上面的LUT可以看到真值表,就是不知道为什么和我自己化简的不一样,所以对于为什么有时候可以少一两个输入还不太明白。