/* * Internal signal capture module */ `define SIGCAP_WIDTH 64 `define SIGCAP_DEPTH 2048 `define SIGCAP_ADDRBITS 16 /* Capture RAM module, should infer a block RAM in ISE * * Based on XST example "Dual-Port Block RAM with Different Clocks" */ module capram ( input clka, input clkb, input wea, input [`SIGCAP_ADDRBITS-1:0] addra, input [`SIGCAP_ADDRBITS-1:0] addrb, input [`SIGCAP_WIDTH-1:0] dia, output [`SIGCAP_WIDTH-1:0] doa, output [`SIGCAP_WIDTH-1:0] dob ); reg [`SIGCAP_WIDTH-1:0] ram [`SIGCAP_DEPTH-1:0]; reg [`SIGCAP_ADDRBITS-1:0] addr_rega; reg [`SIGCAP_ADDRBITS-1:0] addr_regb; always @(posedge clka) begin if (wea) ram[addra] <= dia; addr_rega <= addra; end always @(posedge clkb) begin addr_regb <= addrb; end assign doa = ram[addr_rega]; assign dob = ram[addr_regb]; endmodule /* WO: Capture control register */ `define SIGCAP_REG_CTRL 0 `define SIGCAP_CTRL_RESET 0 /* 8'b00000001 */ `define SIGCAP_CTRL_RUN 1 /* 8'b00000002 */ /* RO: Total sample count in buffer */ `define SIGCAP_REG_COUNT_0 2 `define SIGCAP_REG_COUNT_1 3 /* RW: Read next sample. Write reset read address */ `define SIGCAP_REG_DATA 4 /* * Note about clock domains: * * sysclk is used for the register interface, capclk for the actual * capture. However, we don't use synchronizers when those domains * collide, as we know that both clocks derive from the same DLL * and shouldn't go metastable. Typically capclk is a multiple of * sysclk */ module scope ( /* System clock */ input sysclk, /* Capture clock */ input capclk, /* System reset */ input reset, /* Signals to capture */ input [`SIGCAP_WIDTH-1:0] sigs, /* Backbus interface */ input [5:0] bb_addr, input [7:0] bb_wdata, output [7:0] bb_rdata, input bb_strobe, input bb_wr ); reg capturing; reg [`SIGCAP_ADDRBITS-1:0] cap_addr; reg [`SIGCAP_ADDRBITS-1:0] read_addr; reg [2:0] read_byte; wire [`SIGCAP_WIDTH-1:0] cap_data; reg [7:0] cap_byte; wire [`SIGCAP_WIDTH-1:0] ram_ignore; reg do_reset; reg do_run; wire cap_full; wire do_reset_combo; /* Instanciate capture memory */ capram capram0(.clka(capclk), .clkb(sysclk), .wea(capturing && !cap_full), .addra(cap_addr), .addrb(read_addr), .dia(sigs), .doa(ram_ignore), .dob(cap_data)); /* Capture control logic */ always@(posedge capclk or posedge reset) begin if (reset) begin cap_addr <= 0; end else begin if (do_reset) begin capturing <= 0; cap_addr <= 0; end else if (!do_run) begin capturing <= 0; end else begin capturing <= 1; if (capturing && !cap_full) begin cap_addr <= cap_addr + 1; end end end end assign cap_full = cap_addr == (`SIGCAP_DEPTH - 1); /* Mux memory output */ always@(read_byte or cap_data) begin case (read_byte) 0: cap_byte = cap_data[63:56]; 1: cap_byte = cap_data[55:48]; 2: cap_byte = cap_data[47:40]; 3: cap_byte = cap_data[39:32]; 4: cap_byte = cap_data[31:24]; 5: cap_byte = cap_data[23:16]; 6: cap_byte = cap_data[15:8]; 7: cap_byte = cap_data[7:0]; default: cap_byte = cap_data[7:0]; endcase end /* Register read */ assign bb_rdata = (bb_addr[2:0] == `SIGCAP_REG_COUNT_0) ? cap_addr[`SIGCAP_ADDRBITS-1:8] : (bb_addr[2:0] == `SIGCAP_REG_COUNT_1) ? cap_addr[7:0] : cap_byte; /* Fifo address counter */ assign do_reset_combo = reset | do_reset; always@(posedge sysclk or posedge do_reset_combo) begin if (do_reset_combo) begin read_addr <= 0; read_byte <= 0; end else begin if (bb_strobe && bb_addr[2:0] == `SIGCAP_REG_DATA) begin if (bb_wr) begin read_byte <= 0; read_addr <= 0; end else begin read_byte <= read_byte + 1; if (read_byte == 3'b111) read_addr <= read_addr + 1; end end end end /* Control register write interface */ always@(posedge sysclk or posedge reset) begin if (reset) begin do_reset <= 1; do_run <= 0; end else begin if (bb_strobe && bb_wr && bb_addr[2:0] == `SIGCAP_REG_CTRL) begin do_reset <= bb_wdata[`SIGCAP_CTRL_RESET]; do_run <= bb_wdata[`SIGCAP_CTRL_RUN]; end end end endmodule