Attention
This documentation is a work in progress. Expect to see errors and unfinished things.
circle_buf Source File
1`timescale 1ns / 1ns
2
3module circle_buf #(
4 parameter dw=16,
5 parameter aw=13,
6 parameter stat_w=16, // Width of buffer statistics
7 // For each half of the double-buffered memory, the default is to use a read of the last
8 // memory location as acknowledgement that the buffer read is complete,
9 // and read cycles need the stb_out signal set high to register.
10 // Set this parameter to 0 to disable that feature, in which case you
11 // need to construct the stb_out signal as a simple explicit flip command.
12 parameter auto_flip = 1
13) (
14 // source side
15 input iclk,
16 input [dw-1:0] d_in,
17 input stb_in, // d_in is valid
18 input boundary, // between blocks of input strobes
19 input stop, // single-cycle
20 // assume stop happens a programmable number of samples
21 // after a fault event, and we will save 1024 samples
22 // before the stop signal
23 output buf_sync, // single-cycle when buffer starts/ends
24 output buf_transferred, // single-cycle when a buffer has been
25 // handed over for reading;
26 // one cycle delayed from buf_sync
27
28 // readout side
29 input oclk,
30 output enable,
31 input [aw-1:0] read_addr, // nominally 8192 locations
32 output [dw-1:0] d_out,
33 input stb_out,
34 output [stat_w-1:0] buf_count, // number of full buffer writes
35 output [aw-1:0] buf_stat2, // last valid location
36 output [stat_w-1:0] buf_stat, // includes fault bit, and (if set) the last valid location
37 output [aw+4:0] debug_stat // {stb_in, boundary, btest, wbank, rbank, wr_addr}
38);
39
40`define MIN(a,b) a < b ? a : b
41
42// parameterized to improve testability
43
44// 8192 words of 16 bits, double buffered
45// maybe subdivided into 1024 time samples of 4 RF waveforms,
46// each with an I and Q component
47
48// readout side state
49reg rbank=0; // really complement
50
51// source side control logic
52// Flow control is opposite that in decay_buf: the pacing happens
53// from the readout side
54wire flag_return; // buffer request from readout side
55wire flag_return_x; // and converted to the iclk domain
56reg_tech_cdc flag_return_cdc(.I(flag_return), .C(iclk), .O(flag_return_x));
57reg [aw-1:0] write_addr=0, save_addr=0, save_addr0=0;
58reg pend=0, run=1, wbank=0;
59wire change_req = wbank ^ flag_return_x;
60wire end_write_addr = &write_addr;
61reg record_type=1;
62reg boundary_ok=1;
63reg [1:0] done_read = 2'b0;
64wire stop_write=pend & boundary;
65wire eval_done_read = stb_in & boundary_ok & end_write_addr;
66wire eval_block=eval_done_read & change_req;
67reg buff_wrap=0;
68reg buf_transferred_r=0;
69wire btest= boundary | ( stb_in & end_write_addr );
70assign buf_transferred = buf_transferred_r;
71always @(posedge iclk) begin
72 if (eval_done_read) done_read[wbank] <= change_req;
73 //if (boundary|(stb_in&end_write_addr)) boundary_ok <= boundary;
74 if (btest) boundary_ok <= boundary;
75 if (stb_in & boundary_ok) write_addr <= write_addr+1; //wbank==rbank ? 0 : write_addr+1;
76 if (eval_block) begin
77 run <= 1;
78 wbank <= ~wbank;
79 record_type <= run; // fault (0) vs. comfort display (1)
80 save_addr0 <= run ? {aw{1'b0}} : save_addr;
81 end
82 buf_transferred_r <= eval_block;
83 if ((stop & run)| boundary) pend <= stop & run; // ignore double stops
84 if (stop_write) begin
85 run <= 0;
86 save_addr <= write_addr;
87 buff_wrap <= ~done_read[wbank];
88 end
89end
90wire flag_send=wbank; // says "I want to write bank foo"
91assign debug_stat={stb_in,boundary,btest,wbank,rbank,write_addr};
92// Handshake means "OK, I won't read bank foo"
93
94// readout side control logic
95wire flag_send_x;
96reg_tech_cdc flag_send_cdc(.I(flag_send), .C(oclk), .O(flag_send_x));
97wire [aw-1:0] read0_addr = read_addr; // cut down to current width
98wire end_read_addr = &read0_addr;
99assign enable = ~flag_send_x ^ rbank;
100wire flip_buffer = stb_out & enable & (end_read_addr | ~auto_flip);
101always @(posedge oclk) begin
102 if (flip_buffer) rbank <= ~rbank;
103end
104assign flag_return = rbank;
105
106// in iclk domain
107wire [stat_w-2-1:0] save_addr0_ext = save_addr0[`MIN(stat_w-2,aw)-1:0]; // truncate or pad MSBs
108assign buf_stat = {record_type, buff_wrap, save_addr0_ext};
109
110assign buf_stat2 = save_addr0;
111wire write_en= stb_in & boundary_ok & run;
112
113// Count of how many buffers we have acquired
114reg [stat_w-1:0] buf_count_r=0;
115always @(posedge iclk) if (eval_done_read) buf_count_r <= buf_count_r+1;
116assign buf_count=buf_count_r;
117assign buf_sync=eval_done_read;
118
119// data path is simply a dual-port RAM
120dpram #(.aw(aw+1), .dw(dw)) cbuf(.clka(iclk), .clkb(oclk),
121 .addra({wbank,write_addr}), .dina(d_in), .wena(write_en),
122 .addrb({~rbank,read0_addr}), .doutb(d_out)
123);
124
125endmodule