经常用的信号开关的两个问题,1.dff得加上reset 2.结束信号来得太早,比开始信号还早
100 wire rdata_valid_next;
101
102 assign rdata_valid_next = (rdata_valid | ar_enter) & (~m_rready);
103
104 dff_s #(1) rdata_valid_reg (
105 .din (rdata_valid_next),
106 .clk (aclk),
107 .q (rdata_valid),
108 .se(), .si(), .so());
这里有个问题,如果ar_enter如果不为1,或者m_rready没有为1过,这时候rdata_valid是x。
所以这段代码在刚reset以后,rdata_valid可能会有一段x的时候。
所以这个dff得用带reset的。
100 wire rdata_valid_next;
101
102 assign rdata_valid_next = (rdata_valid | ar_enter) & (~m_rready);
103
104 dffrl_s #(1) rdata_valid_reg (
105 .din (rdata_valid_next),
106 .clk (aclk),
107 .rst_l (aresetn),
108 .q (rdata_valid),
109 .se(), .si(), .so());
assign rdata_valid_next = (rdata_valid | ar_enter) & (~m_rready);
dffrl_s #(1) rdata_valid_reg (
.din (rdata_valid_next),
.clk (aclk),
.rst_l (aresetn),
.q (rdata_valid),
.se(), .si(), .so());
开始信号是ar_enter,结束信号是m_rready。
ar_enter __--______________
m_rready ______________--__
rdata_valid ____------------__
rdata_valid_next __------------____
选择用rdata_valid还是rdata_valid_next,效果会有一些差别。
但现在遇到了一个新问题,就是m_rready给出的比ar_enter还要早。
m_rready是master给出的,表示随时可以接收slave的数据,可以比rvalid给出的早,以为R和AR是不同的两个channel,所以没说rready不能比ar_valid早。
虽然图上看着这两个箭头rvalid是不能比arvalid或arready早的,但同时给出arvalid和rready也许是可以的。
In the dependency diagrams: • Single-headed arrows point to signals that can be asserted before or after the signal at the start of the arrow. • Double-headed arrows point to signals that must be asserted only after assertion of the signal at the start of the arrow.
从图上看rready是不能比arreday早的,而arready是slave给出的,这个可以给的很早。
而rready是不能比arvalid早,但没说要晚一个cycle以后。
就是下面这种情况:
rready和arvalid在tb里是同时给出来的。也可以让rready稍微晚一点,还是在下个rising edge之前,这样手册字面上就没问题了。
还是直接说问题,因为之前的写操作(WR W B)还没完成,所以busy一直是1,导致后面的AR操作要等busy为0,所以ar_enter是比arvalid和rready还要晚。
因为结束信号比开始信号来的还早,这就导致了上面rdata_valid,也就是控制rvalid的信号无法变成1了。
所以这种情况,就需要,即使结束信号比开始信号还要早,或者同时来,当开始信号来的时候,至少要让rdata_valid high一个cycle。
解决方法就是rdata_valid | ar_enter; 这样ar_enter来了,至少能high一个cycle。 |
128 assign rdata_valid_next = (rdata_valid_tmp | ar_enter) & (~m_rready); 129 //assign rdata_valid_next = (rdata_valid | ar_enter) & (~rready);
130
131 dffrl_s #(1) rdata_valid_reg (
132 .din (rdata_valid_next),
133 .clk (aclk),
134 .rst_l (aresetn),
135 .q (rdata_valid_tmp),
136 .se(), .si(), .so());
137
138
139 wire ar_enter_delay1;
140
141 dffrl_s #(1) ar_enter_delay1_reg (
142 .din (ar_enter),
143 .clk (aclk),
144 .rst_l (aresetn),
145 .q (ar_enter_delay1),
146 .se(), .si(), .so());
147
148 // rdata_valid show up at lease one cycle
149 assign rdata_valid = rdata_valid_tmp | ar_enter_delay1;
这里给ar_enter一个dff,是因为当ar_enter为1时,刚读到addr,要到下一个cycle,数据才能读出来,所以ar_enter要延时一个cycle,和rdata一起给出。
上面代码还有一个地方要注意,ar_enter_delay1_reg的输入是另一个dff的输出,这种在reset的时候会有一个cycle的x。这个x还会传递。
所以要加reset。
自己还没总结出什么样的dff要带reset,但至少今天试的情况来看,如果要延时几个cycle,这样的dff都应该带reset。