Attention

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

banyan_mem Source File

  1`timescale 1ns / 1ns
  2
  3// Single-buffered capture of raw ADC data
  4// Hard-code number of ADCs at 8, at least for now
  5
  6module banyan_mem #(
  7     parameter aw=10,
  8     parameter dw=16
  9) (
 10     input clk,  // timespec 6.1 ns
 11     input [8*dw-1:0] adc_data,
 12     input [7:0] banyan_mask,  // must be valid in clk domain
 13
 14     // API in clk domain for controlling acquisition
 15     // See additional comments below
 16     input reset,  // resets pointer and full
 17     input run,  // set to enable writes to memory; Modulate to take valid adc_data (See TB)
 18     output [aw+3-1:0] pointer,  // write location
 19     output rollover,
 20     output full,
 21     // Note that writes are pipelined, and after clearing the run
 22     // bit, about four more clk cycles are required before the last
 23     // data actually shows up in RAM and can be read out.
 24     // The output status (full, pointer) are all immediately but
 25     // provisionally valid, pending completion of the pipelined writes.
 26
 27     // Peek into the data stream between switch and memory.
 28     // Valid in clk domain.
 29     output [8*dw-1:0] permuted_data,
 30
 31     // readout port, separate clock domain
 32     // recommend only using this when run is low
 33     input ro_clk,
 34     input [aw+3-1:0] ro_addr,
 35     output [dw-1:0] ro_data,
 36     output [dw-1:0] ro_data2
 37     // ro_data2 is based on ro_addr xored with 1<<aw
 38     // You don't have to use it, but if you have a 32 bit bus, 16-bit ADCs,
 39     // and are trying to pack things efficiently, it's yours for the taking.
 40);
 41
 42// We expect banyan_mask to be set by software, and is therefore not
 43// time-critical.  Other uses should be aware of this extra cycle of latency,
 44// motivated by the "long" time needed to count the number of bits set.
 45reg [7:0] mask_d=0;
 46reg [3:0] bit_cnt=0;
 47always @(posedge clk) begin
 48     mask_d <= banyan_mask;  // time-aligned with bit_cnt and therefore done_mask
 49     bit_cnt <= banyan_mask[0] + banyan_mask[1] + banyan_mask[2] + banyan_mask[3]
 50              + banyan_mask[4] + banyan_mask[5] + banyan_mask[6] + banyan_mask[7];
 51end
 52
 53//  8 bits set: count to 2^(aw)
 54//  4 bits set: count to 2^(aw+1)
 55//  2 bits set: count to 2^(aw+2)
 56//  1 bit  set: count to 2^(aw+3)
 57reg [2:0] done_mask;
 58always @(*) begin
 59     done_mask = 0;
 60     if (bit_cnt[1]) done_mask = 4;
 61     if (bit_cnt[2]) done_mask = 6;
 62     if (bit_cnt[3]) done_mask = 7;
 63end
 64
 65// Simple control logic, put the user in control.  Should support
 66// options like one-shot fill, or circular roll until fault.
 67// Expect logic like
 68//    if (trig | rollover) run <= trig;
 69//    assign reset = trig;
 70// for a one-shot, or
 71//    if (reset | fault) run <= reset;
 72// for fault capture.
 73// No hidden state!
 74// No double-buffering/circular readout, sorry; this is meant for
 75// wideband snapshotting, where the software can't possibly keep up.
 76reg full_r=0;
 77reg [aw+2:0] addr_count=0;
 78assign rollover = run & &(addr_count|{done_mask,{aw{1'b0}}});
 79always @(posedge clk) begin
 80     if (run) addr_count <= addr_count+1;
 81     if (rollover | reset) addr_count <= 0;
 82     if (rollover | reset) full_r <= rollover;
 83end
 84assign full = full_r;
 85assign pointer = addr_count;
 86
 87// Split and time-align write-side addresses
 88wire [2:0] time_state = addr_count[aw+2:aw];
 89wire [aw-1:0] wr_addr;
 90reg_delay #(.dw(aw), .len(4)) addr_pipe(.clk(clk), .reset(1'b0), .gate(1'b1),
 91     .din(addr_count[aw-1:0]), .dout(wr_addr));
 92wire run_d;
 93reg_delay #(.dw(1), .len(3)) run_pipe(.clk(clk), .reset(1'b0), .gate(1'b1),
 94     .din(run), .dout(run_d));
 95
 96// Banyan switch itself
 97wire [7:0] mask_out;
 98wire [dw*8-1:0] banyan_out;
 99banyan #(.dw(dw), .np(8), .rl(3)) banyan(.clk(clk),
100     .time_state(time_state), .mask_in(mask_d), .data_in(adc_data),
101     .mask_out(mask_out), .data_out(banyan_out));
102assign permuted_data = banyan_out;
103
104// A new value propagates to mask_out 3 cycles after time_state changes,
105// compared to 4 for the data in banyan_out
106reg [7:0] mask_out_d=0;
107always @(posedge clk) mask_out_d <= mask_out & {8{run_d}};
108
109// Bank of 8 RAM, pretty simple
110wire [8*dw-1:0] ram_out;
111genvar ix;
112generate for (ix=0; ix<8; ix=ix+1) begin: ram_bank
113     dpram #(.dw(dw), .aw(aw)) ram(.clka(clk), .clkb(ro_clk),
114             .dina( banyan_out[(ix+1)*dw-1 -: dw]), .addra(wr_addr), .wena(mask_out_d[ix]),
115             .doutb(   ram_out[(ix+1)*dw-1 -: dw]), .addrb(ro_addr[aw-1:0])
116     );
117end endgenerate
118
119// Second stage of readout decoding is one cycle delayed from the RAM addressing
120reg [2:0] stage2_addr=0;
121always @(posedge ro_clk) stage2_addr <= ro_addr[aw+3-1:aw];
122assign ro_data  = ram_out[((stage2_addr       )+1)*dw-1 -: dw];
123assign ro_data2 = ram_out[((stage2_addr ^ 3'b1)+1)*dw-1 -: dw];
124// So ro_data* are one cycle (plus some combinatorial time) delayed from the address provided
125// Reads are purely passive, no side effects, hence no read-enable control is provided
126
127endmodule