2013年5月24日 星期五

通用型8bit計數器

介紹一個通用型8bit計數器。


TopModule

可以看見,一個這樣多要求(功能)的計數器,拆成三個部份。
`include "InitSel.v"
`include "Counter8combi.v"
`include "CircleStop.v"

module counter8uni2(clk, _areset, _aset, _load, preld_val, _updown, _wrapstop, dcout, overflow);
parameter countWidth = 8;

    input  clk,
          _areset,
          _aset,
          _load,
          _updown,
          _wrapstop;
    input [countWidth-1:0]  preld_val;

    output [countWidth-1:0] dcout;
    output overflow;

    wire [countWidth-1:0] tCount_M12, tCountM23;

    
    InitSel       M1( .oCountInitValue(tCount_M12), ._iReset(_areset), ._iSet(_aset), ._iLoad(_load), .iPreldVal(preld_val), .iCountValue(dcout) );
    Counter8combi M2( .oCount(tCountM23), .iClk(clk), ._iIsAddOut(_updown), .iCount(tCount_M12) );
    CircleStop    M3( .oCount(dcout), .iClk(clk), .iCount(tCountM23), ._iWrapstop(_wrapstop), .oOverflow(overflow) );
endmodule


下面我們就來詳細的解說,這三個部份怎麼滿足這些規格吧!

第一個部份處理_areset、_aset、_load

這個部份要滿足

  • _areset =1 counter非同步輸出全0, _aset =1 counter非同步輸出全1, 若這兩個都是0, count照常運作
  • _load = 1時, preld-val的值設定進counte
  • 訊號優先權_areset > _aset > _load

最重要的一件事就是「非同步」,這個電路,沒有clk。
再來是優先權_areset > _aset > _load,所以code 的排序也是要注意的
在此使用always+準位觸發,用Blocking的方式,做非同步電路。
module InitSel(oCountInitValue, _iReset, _iSet, _iLoad, iPreldVal, iCountValue);
parameter CountWidth = 8;

input _iReset, _iSet, _iLoad;
input [CountWidth-1:0] iCountValue, iPreldVal;
output [CountWidth-1:0] oCountInitValue;

reg [CountWidth-1:0] oCountInitValue;
    
    always@(_iReset, _iSet, _iLoad, iCountValue, iPreldVal)
    begin
        if (_iReset == 1)
            oCountInitValue = 8'b1111_1111;
        else if (_iSet == 1)
           oCountInitValue = 8'b0000_0000;
        else if (_iLoad == 1)
           oCountInitValue = iPreldVal;
        else
           oCountInitValue = iCountValue;
    end
    
endmodule

第二個部份處理_updown

這個部份是最重要的計數核心
滿足一個規格
  • _updown = 1, counter向上計數 counter = 0, counter向下計數
在此設計了兩個電路,正數和反數,獨立著,再使用開關的方式切換輸出和輸入的值。重點在於線路的設計,計數本身反而就是一般的計數,沒什麼特別的。

`include "coreCount8Add.v"
`include "coreCount8Sub.v"

module Counter8combi(iClk, _iIsAddOut, iCount, oCount);
parameter CountWidth = 8;

input iClk, _iIsAddOut;
input  [CountWidth-1:0] iCount;
output [CountWidth-1:0] oCount;

wire [CountWidth-1:0] out_Add, out_Sub;

assign oCount = (_iIsAddOut)? out_Add: out_Sub;

coreCount8Add CA(iClk, _iIsAddOut, iCount, out_Add);
coreCount8Sub CS(iClk, _iIsAddOut, iCount, out_Sub);

endmodule

正數和反數計數器

它們差異不大,在此貼出反數的code,正數就改一下就是了
正數修改處

  • _iEn改iEn
  • 運算符號-改+

module coreCount8Sub(iClk, _iEn, iCount, oCount);
parameter CountWidth = 8;

input iClk, _iEn;
input  [CountWidth-1:0] iCount;
output [CountWidth-1:0] oCount;

reg [CountWidth-1:0] oCount;

always@(posedge iClk)
begin
    if (!_iEn)
       oCount <= iCount - 8'd1;
    else
        oCount <= iCount;
end

endmodule


第三個部份處理_wrapstop、overflow

在此也可以使用state mechine,但是我沒這麼做!
規格如下
  • _wrapstop = 1, counter循環計數, _wrapstop = 1, counter計數到最大或最小就停止,並且有overflow
  • 承上,若計數超出範圍(超過最大值或低於最小值)則overflow = 1
module CircleStop(oCount, iClk, iCount, _iWrapstop, oOverflow);
parameter countWidth = 8;

input _iWrapstop, iClk;
input [countWidth-1:0] iCount;
output oOverflow;
output [countWidth-1:0] oCount;

reg [countWidth-1:0] oCount;
reg oOverflow;

always@(posedge iClk)
begin
    if ((_iWrapstop == 1) && ((oCount == 8'b0000_0000)))
    begin
        oCount    <= 8'b0000_0000;
        oOverflow <= 'b1;
    end
    else if ((_iWrapstop == 1) && (oCount == 8'b1111_1111))
    begin
        oCount    <= 8'b1111_1111;
        oOverflow <= 'b1;
    end
    else
    begin
        oCount    <= iCount;
        oOverflow <= 'b0;
    end
end

endmodule

這樣就組成了一個8bit的通用計數器。

沒有留言:

張貼留言