Attention

This documentation is a work in progress. Expect to see errors and unfinished things.

host_averager Source File

 1/* Host-side signal averager
 2
 3This module accepts (nominally) periodic measurements,
 4and accumulates them.  It also keeps count, and makes both results
 5accessible to a host, so the host can divide and find an average.
 6This process is resilient to timing (polling) jitter on the host side.
 7
 8The whole trick is that a read is "destructive", in that it clears
 9the accumulators.  The host can read at "any" interval it wants,
10and always gets a valid reading.
11
12If your host / bus infrastructure can only perform passive reads, I hope
13it can at least order operations; then the snapshot function can be
14triggered by a write, with the actual read following.
15
16This version is all static-sized -- emphasizing clarity over generality.
17The host has to read at least once for every 255 readings that come in,
18in order to avoid overflows.  That condition is easily checked: the
19sample counter saturates at 255, so that value flags the reading as invalid.
20
21Input (data_in) is unsigned, as my use case takes in (non-negative)
22values representing power.
23Output word (data_out) is { 24-bits data, 8-bits count }.
24Output appears the cycle after a single-cycle read_s strobe, and remains
25static until the next such strobe.  The claim is this is fast enough
26to generate an atomic-read-and-clear in the usual LBNL local bus structure,
27using the same cycle usually used to cycle block RAM.
28
29By necessity, the output and this logic are both in the _host_ clock domain.
30The instantiating module will typically have to move a DSP-clocked result
31into this domain before providing it as input to this module.
32
33*/
34module host_averager(
35     input clk,
36     input [23:0] data_in,
37     input data_s,
38     input read_s,
39     output [31:0] data_out
40);
41
42reg [31:0] accum=0;
43reg [7:0] count=0;
44reg [31:0] data_out_r=0;
45
46always @(posedge clk) begin
47     if (read_s) data_out_r <= {accum[31:8], count};
48     if (data_s | read_s) begin
49             count <= (read_s ? 8'd0 : count) + data_s;
50             accum <= (read_s ? 32'd0 : accum) + (data_s ? data_in : 24'b0);
51     end
52     if (data_s & ~read_s & (&count)) count <= 8'hff;
53end
54assign data_out = data_out_r;
55
56endmodule