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