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