Attention
This documentation is a work in progress. Expect to see errors and unfinished things.
multi_counter Source File
1// Single-clock-domain multi-channel counter
2// No restrictions on how often the "inc" port is high.
3// Reads go through dpram, so are delayed one cycle.
4// Reads are passive, so don't need an enable.
5`timescale 1ns / 1ns
6
7module multi_counter #(
8 parameter aw=4, // 2**aw counters, non-resettable
9 parameter dw=16 // bit-width of each counter
10) (
11 input clk,
12 input inc, // increment the counter specified by inc_addr
13 input [aw-1:0] inc_addr,
14 input [aw-1:0] read_addr, // local bus address
15 output [dw-1:0] read_data
16);
17
18// First dpram: increment on-demand
19// Start by creating one-cycle-delayed controls,
20// that will be time-aligned with old_plus_1.
21reg inc_r=0;
22always @(posedge clk) inc_r <= inc;
23reg [aw-1:0] inc_addr_r=0;
24always @(posedge clk) inc_addr_r <= inc_addr;
25// Logic for the add-one block
26wire [dw-1:0] old;
27wire [dw-1:0] old_plus_1 = old+1;
28// Actually instantiate dpram
29dpram #(.aw(aw), .dw(dw)) incr(
30 .clka(clk), .clkb(clk),
31 .addra(inc_addr_r), .dina(old_plus_1), .wena(inc_r),
32 .addrb(inc_addr), .doutb(old)
33);
34
35// Second dpram: mirror so host can read values
36dpram #(.aw(aw), .dw(dw)) mirror(
37 .clka(clk), .clkb(clk),
38 .addra(inc_addr_r), .dina(old_plus_1), .wena(inc_r),
39 .addrb(read_addr), .doutb(read_data)
40);
41
42// For simulation purposes, we have to assume both dpram instances
43// have their memory plane initialized to zero.
44
45endmodule