WINDOW COUNTER MODULE
(Last Modified: 04 November 2010 06:09:20 PM )
wire WC_TC;
WindowCounter16 MCNT (
.Q(BFE_X), .TC(WC_TC), .CE1(HI), .CE2(HI), .LoadB(~WC_TC),
.D(BFE_D), .A(BFE_A), .ID(6'b000000), .WS(BFE_WS),
.DefStart(16'd0), .DefStop(16'd50),
.ClkR(MclkRise), .PrstB(~rst), .Pclk(clk)
);
The Window Counter is a simple counter that runs between a Start value and a
Stop value. The counter contains four 8-bit internal registers that are used to
store the Start and Stop values. Upon a global reset, the default values (DefStart
and DefStop
) are loaded into the registers. These may be
overwritten using the register interface. The address of the registers are
obtained by taking the 6-bit ID
value and appending the
local register value. The register map is thus:
The register map is interlaced to improve the compatibility of the map between window counters of various depths, such as 8-bit, 16-bit, 24-bit, and 32-bit.
Note, however, that upon a global reset, the counter is reset to a state of
zero and not the Start value. The Start value is only applied in response to an
explicit Load (LoadB
being LO) command.
The number of states in each cycle of the counter is ((Stop - Start) + 1)
since the counter will be placed in both the Start and the Stop states. The
Terminal Count output (TC
) is asserted whenever the present
state of the counter is equal to the Stop value.
There are two Count Enable inputs (CE1
and CE2
)
used to interrupt the counting process. Both must be HI in order for the counter
to increment.
There is also a Clock Rising Edge input (ClkR
) which is
used to enable the counter only on those system clock rising edges that are
coincident with the rising edge of a generated master clock. This is a feature
that is not on the ASIC version of the counter and is there to accommodate the
desire to have programmatic control over the clock speed while avoiding gated
clocks in an FPGA.
module
WindowCounter16(
Q, TC, CE1, CE2, LoadB,
D, A, ID, WS,
DefStart, DefStop,
ClkR, PrstB, Pclk);
output [15:0] Q;
output TC;
input CE1, CE2, LoadB;
input [ 7:0] D, A;
input [ 7:2] ID;
input WS;
input [15:0] DefStart, DefStop;
input ClkR, PrstB, Pclk;
parameter HI = 1'b1, LO = 1'b0;
// Control Register Interface
wire [15:0] Start, Stop;
RegBank4 REG (
.D(D), .A(A), .ID(ID), .WS(WS),
.Q3(Stop[15:8]),
.V3(DefStop[15:8]),
.Q2(Start[15:8]),
.V2(DefStart[15:8]),
.Q1(Stop[7:0]),
.V1(DefStop[7:0]),
.Q0(Start[7:0]),
.V0(DefStart[7:0]),
.PrstB(PrstB), .Pclk(Pclk)
);
// Control Signals
reg [15:0] Q_reg;
assign Q = Q_reg;
wire TC_int;
assign TC = TC_int;
assign TC_int = (Q_reg == Stop)? HI : LO;
wire CE, Load, LoadTCB;
assign CE = (CE1 & CE2)? HI : LO;
assign LoadTCB = ~((TC_int & CE)? HI : LO);
assign Load = ~((LoadB & LoadTCB)? HI : LO);
// State Machine
always @(posedge Pclk or negedge PrstB)
begin
if (PrstB == LO)
Q_reg <=
16'd0;
else if (ClkR == HI)
begin
if (Load == HI)
Q_reg <= Start;
else if (CE == HI)
Q_reg <= Q_reg + 1;
else
Q_reg <= Q_reg;
end
else
Q_reg <=
Q_reg;
end
endmodule
The counter contains a 4-byte register that is used to store the Start and Stop values.
// Control Register Interface
wire [15:0] Start, Stop;
RegBank4 REG (
.D(D), .A(A), .ID(ID), .WS(WS),
.Q3(Stop[15:8]),
.V3(DefStop[15:8]),
.Q2(Start[15:8]),
.V2(DefStart[15:8]),
.Q1(Stop[7:0]),
.V1(DefStop[7:0]),
.Q0(Start[7:0]),
.V0(DefStart[7:0]),
.PrstB(PrstB), .Pclk(Pclk)
);
The default values, which are applied to the DefStart and DefStop inputs to the module, are loaded into the counter whenever PrstB is taken LO. The user may program different values into the register via the 8-bit register bus. The address is obtained by using the 6-bit ID input to the module and appending the 2-bit internal address of the desired register. After placing the address and data on the bus, the values are loaded into the register by strobing the Write Strobe (WS) input.
// Control Signals
reg [15:0] Q_reg;
assign Q = Q_reg;
wire TC_int;
assign TC = TC_int;
assign TC_int = (Q_reg == Stop)? HI : LO;
wire CE;
assign CE = (CE1 & CE2)? HI : LO;
wire LoadTCB, Load;
assign LoadTCB = ~((TC_int & CE)? HI : LO);
assign Load = ~((LoadB & LoadTCB)? HI : LO);
The control signals are structural implementations of the logic
on the BFE297 and, as such, are not the most readable statements. The first pair
of statements above simply creates an internal register variable, Q_reg
,
that the state machine can use and statically assigns its value to the module
output. The next block of statements generates the Terminal Count output,
TC
, in a similar fashion. Instead of instantiating a digital
comparator, as is done on the ASIC, this code used an equivalent behavioral
statement. The third block of statements simply says that the internal Count
Enable, CE
, signal is the logical-AND of the two externally
applied signals (CE1
and CE2
). The final
block of statements is the most cryptic, but all it says is that the
Load
signal is asserted whenever either the external LoadB
signal (which is active-LO) is asserted or the counter is in its terminal count
state and counting is enabled.
// State Machine
always @(posedge Pclk or negedge PrstB)
begin
if (PrstB == LO)
Q_reg <=
16'd0;
else if (ClkR == HI)
begin
if (Load == HI)
Q_reg <= Start;
else if (CE == HI)
Q_reg <= Q_reg + 1;
else
Q_reg <= Q_reg;
end
else
Q_reg <=
Q_reg;
end
The actual state machine is very straight-forward. First, if the
PrstB
signal, which is active-LO, is asserted then the
counter is immediately set to the all-zero state. Otherwise, things only happen
on the positive edge of the system clock (Pclk
) and then
only if the master clock is about to rise (ClkR
signal is
asserted). If these conditions are met, then if the Load
signal is asserted (either due to an explicit load command or as a result of the
counter reaching the Stop
value) then the Start
value is loaded. If the Load
signal is not asserted, then
the counter will increment, but only if both count enable inputs are asserted;
otherwise, the present state of the counter will be retained..