【随笔】“真OO无双”前辈提供的SEG7_Controller模块的问题改进

  首先,非常感谢“真OO无双”前辈,在学习FPGA过程中给与了极大帮助。在此记录一些问题,希望能帮助别人,也给自己留点记录,方便以后查找。

      前辈在(原創) 如何設計一個七段顯示器Controller? 中给了出了一个例子,如下:

我的板子是DE3—150,上面有两颗数码管。将其作为自定义组建加入到SOPC Builder中(具体参考(原創) 如何設計一個七段顯示器Controller? ),其参数修改为:

 

1 module SEG7_Controller (
2 // Avalon clock interface siganals
3   input csi_clockreset_clk,
4 input csi_clockreset_reset_n,
5 // Signals for Avalon-MM slave port
6   input [ADDR_WIDTH-1:0] avs_s1_address,
7 input avs_s1_write,
8 input [DATA_WIDTH-1:0] avs_s1_writedata,
9 // user logic inputs and outputs
10   output [SEG7_NUM*8-1:0] avs_s1_export_oHEX
11 );
12
13 parameter DATA_WIDTH = 32; // data bus width
14  parameter SEG7_NUM = 8; // specify the number of seg7 unit
15  parameter ADDR_WIDTH = 3; // log2(SEG7_NUM)
16  
17 reg [SEG7_NUM-1:0] base_index;
18 reg [DATA_WIDTH-1:0] write_data;
19 reg [(SEG7_NUM*8-1):0] reg_file;
20
21 assign avs_s1_export_oHEX = ~reg_file;
22
23 always@(posedge csi_clockreset_clk, negedge csi_clockreset_reset_n) begin
24 if (!csi_clockreset_reset_n) begin
25 integer i;
26 base_index <= 8'h00;
27 write_data <= 8'h00;
28
29 for(i = 0; i < SEG7_NUM * 8; i = i + 1)
30 reg_file[i] <= 1'b1;
31 end
32 else begin
33 if (avs_s1_write) begin
34 integer j;
35 write_data <= avs_s1_writedata;
36 base_index <= (avs_s1_address << 3);
37
38 for(j = 0; j < 8; j = j + 1)
39 reg_file[base_index+j] <= write_data[j];
40 end
41 end
42 end
43
44 endmodule

 

 

 

SEG7_NUM = 2

ADDR_WIDTH
= 1

 

编译下载到板子上,然后在Nios II中运行测试程序,在低位向高位进位时出现错误现象:

...08—>09—>00—>11—>12...19—>10—>21...

也就是说,低位向高位进位时,低位清零,高位没变化,下一次更新时,高低位一起更新。

  分析代码33~39行,由于使用阻塞赋值,reg_file,base_index以及write_data中的数据其实都是前一时钟周期的,那么其中数值变化如下:

 

修改代码如下,问题解决。

 

1 module SEG7_Controller (
2 // Avalon clock interface siganals
3 input csi_clockreset_clk,
4 input csi_clockreset_reset_n,
5 // Signals for Avalon-MM slave port
6 input [ADDR_WIDTH-1:0] avs_s1_address,
7 input avs_s1_write,
8 input [31:0] avs_s1_writedata,
9 // user logic inputs and outputs
10 output [SEG7_NUM*8-1:0] avs_s1_export_oHEX
11 );
12
13 parameter SEG7_NUM = 8; // specify the number of seg7 unit
14 parameter ADDR_WIDTH = 3; // log2(SEG7_NUM)
15 parameter DEFAULT_ACTIVE = 1;
16 parameter LOW_ACTIVE = 1;
17
18 reg [(SEG7_NUM*8-1):0] reg_file;
19
20 assign avs_s1_export_oHEX = (LOW_ACTIVE)?~reg_file:reg_file;
21
22 always@(posedge csi_clockreset_clk, negedge csi_clockreset_reset_n) begin
23 if (!csi_clockreset_reset_n) begin
24 reg_file[(SEG7_NUM*8-1):0] <= (DEFAULT_ACTIVE)?8'hFF:8'h00; // trun on or off
25 end
26 else begin
27 if (avs_s1_write) begin
28 integer j;
29 for(j = 0; j < 8; j = j + 1)
30 reg_file[(avs_s1_address << 3) + j] <= avs_s1_writedata[j];
31 // reg_file[((avs_s1_address << 3) + 7 ):(avs_s1_address << 3)] <= avs_s1_writedata[7:0];
32 end
33 end
34 end
35
36 endmodule

 

 

方法二,还可以在起另外一个always块,在其中完成write_data对reg_file的赋值,因为clk非常快,不受avs_s1_write信号控制,可以避免此情况。

 

总结:

  • reg变量,相当于触发器,若采用阻塞赋值,传递出去的其实是其存放的前一时钟周期的值。
  • 制作自定义组建时,对寄存器的读写,应该与寄存器功能实现分开,如方法2. 

 

 

 

 

 

 

 

 

 

posted on 2010-11-03 20:35  stone_xiyi  阅读(419)  评论(0编辑  收藏  举报

导航