// delayline2.v -- Delay line using external RAM resources of XS40 and XStend boards // Ed Doering // 07/24/2000 // // * Variable-length delay line, 8-bit data, single channel. // * 'I$Length' input sets delay line length; exact length is I$Length plus one // * I$Length is a 17-bit value, but the XS40/XStend combination provides RAM only // up to address 98,303 (three banks of 32Kx8 RAM, although the XStend RAMs // are optional -- they may not be installed on the board). // * Use separate input and output RAM data bus rather than bidirectional (keep // bidirectional part in top-level module). // /* DelayLine U? ( // Inputs: .I$Clock ( connect to master clock signal ), .I$Reset ( active high asynchronous reset ), .I$Data ( 8-bit data applied to delay line ), .I$DataValid ( indicates input data is valid, active high ), .I$Length ( 17-bit value indicating length of delay line ), .I$RAMData ( 8-bit value from RAM data bus ), // Outputs: .O$Data ( 8-bit output data from delay line), .O$DataValid ( active high, indicates that output data is valid), .O$_RAMCSXS40 ( chip select for RAM on XS40 board, active low), .O$_RAMCSXStendL ( chip select for left RAM bank on XStend board ), .O$_RAMCSXStendR ( chip select for right RAM bank on XStend board ), .O$_RAMOE ( RAM output enable (common to all RAMs), active low ), .O$_RAMWE ( RAM write enable (common to all RAMs), active low ), .O$RAMAddress ( 15-bit RAM address common to all RAMs ), .O$RAMData ( 8-bit value to RAM data bus ), .O$RAMDataBusIsOutput ( RAM data bus direction (1=>active output, 0=>hi-Z) ) ); */ //------------------------------------------------------------------------------- module DelayLine ( // Variable-length delay line using external RAM resources of XS40 and XSTend boards // Inputs: I$Clock // Master clock , I$Reset // Master reset, active high , I$Data // Input data value , I$DataValid // Input data value valid (active high) , I$Length // Length of delay line in samples (actual delay is the value // of I$Length plus one) , I$RAMData // 8-bit value from RAM data bus , // Outputs: O$Data // Output data value , O$DataValid // Indicates when data output is valid (active high) , O$_RAMCSXS40 // RAM chip select, XS40 , O$_RAMCSXStendL // RAM chip select, XStend board left bank , O$_RAMCSXStendR // RAM chip select, XStend board right bank , O$_RAMOE // RAM output enable , O$_RAMWE // RAM write enable , O$RAMAddress // RAM address , O$RAMData // 8-bit value to RAM data bus , O$RAMDataBusIsOutput // RAM data bus direction (1=>active output, 0=>hi-Z) ); // Constant parameter declarations: parameter p$DataWidth = 8; parameter p$RAMDataWidth = 8; // property of hardware... don't change parameter p$RAMAddressWidth = 15; // property of hardware... don't change // State machine declarations: parameter p$Idle = 8'b0000_0001, p$Wait = 8'b0000_0010, p$ReadCycle1 = 8'b0000_0100, p$ReadCycle2 = 8'b0000_1000, p$WriteCycle1 = 8'b0001_0000, p$WriteCycle2 = 8'b0010_0000, p$WriteCycle3 = 8'b0100_0000, p$BumpPointer = 8'b1000_0000; parameter p$NumStates = 8; // Port mode declarations: input I$Clock; input I$Reset; input [p$DataWidth-1:0] I$Data; input I$DataValid; input [16:0] I$Length; input [p$RAMDataWidth-1:0] I$RAMData; output [p$DataWidth-1:0] O$Data; output O$DataValid; output O$_RAMCSXS40; output O$_RAMCSXStendL; output O$_RAMCSXStendR; output O$_RAMOE; output O$_RAMWE; output [p$RAMAddressWidth-1:0] O$RAMAddress; output [p$RAMDataWidth-1:0] O$RAMData; output O$RAMDataBusIsOutput; // Registered variable declarations: reg [p$DataWidth-1:0] O$Data; reg O$DataValid; reg O$_RAMCSXS40; reg O$_RAMCSXStendL; reg O$_RAMCSXStendR; reg O$_RAMOE; reg O$_RAMWE; //reg [p$RAMAddressWidth-1:0] O$RAMAddress; //reg [p$RAMDataWidth-1:0] IO$RAMData; reg [16:0] r$Pointer; reg r$IncrementPointer; reg r$CaptureRAMData; reg O$RAMDataBusIsOutput; reg [p$NumStates-1:0] r$State; reg [p$NumStates-1:0] r$NextState; // // Connect RAM output data bus to delay line input data // assign O$RAMData = I$Data; // // RAM address and chip select decoding: // // Pointer (RAM address). Pointer increments when enabled by r$IncrementPointer // signal. Pointer is reset to zero when it reaches the value of I$Length. always @ (posedge I$Clock or posedge I$Reset) if (I$Reset == 1) r$Pointer <= 0; else if (r$IncrementPointer) r$Pointer <= (r$Pointer == I$Length) ? 0 : r$Pointer + 1; // RAM chip select decoding always @ (r$Pointer) begin // Nominal values are all high (deselected) O$_RAMCSXS40 <= 1; O$_RAMCSXStendL <= 1; O$_RAMCSXStendR <= 1; case (r$Pointer[16:15]) 2'b00: O$_RAMCSXS40 <= 0; 2'b01: O$_RAMCSXStendL <= 0; 2'b10: O$_RAMCSXStendR <= 0; endcase end // Connect lower 15 bits of pointer to RAM address bus assign O$RAMAddress = r$Pointer[14:0]; // // Output register: // always @ (posedge I$Clock or posedge I$Reset) if (I$Reset == 1) O$Data <= 0; else if (r$CaptureRAMData) O$Data <= I$RAMData; // // Controller: // // State register always @ (posedge I$Clock or posedge I$Reset) if (I$Reset == 1) r$State <= p$Idle; else r$State <= r$NextState; // Next-state and output decoder always @ (I$DataValid or r$State) begin // Nominal output values r$NextState <= p$Idle; O$DataValid <= 0; O$_RAMOE <= 1; r$CaptureRAMData <= 0; O$RAMDataBusIsOutput <= 0; O$_RAMWE <= 1; r$IncrementPointer <= 0; // State-dependent output values case (r$State) p$Idle: begin // Signal that present data output is valid O$DataValid <= 1; // Stay in idle state while input data is valid, otherwise // advance to the wait state r$NextState <= (I$DataValid) ? p$Idle : p$Wait; end p$Wait: begin // Stay in wait state while input data is invalid, then // advance to read cycle r$NextState <= (!I$DataValid) ? p$Wait : p$ReadCycle1; end p$ReadCycle1: begin // Assert the RAM output enable O$_RAMOE <= 0; // Enable the "capture data" (output data register will // latch RAM data at end of this state, so RAM output will // have been enabled for a full clock cycle before the // data is latched) r$CaptureRAMData <= 1; // Move to second part of read cycle r$NextState <= p$ReadCycle2; end p$ReadCycle2: begin // Maintain assertion of RAM output enable to guarantee // stable data during latching. (note... this state may // not be necessary, since the FPGA flip-flops have zero // hold time requirement). O$_RAMOE <= 0; // Move to write cycle r$NextState <= p$WriteCycle1; end p$WriteCycle1: begin // Set data bus direction to output O$RAMDataBusIsOutput <= 1; // Move to next write cycle r$NextState <= p$WriteCycle2; end p$WriteCycle2: begin // Maintain data bus direction as output O$RAMDataBusIsOutput <= 1; // Assert the RAM write enable for one state O$_RAMWE <= 0; // Move to next write cycle r$NextState <= p$WriteCycle3; end p$WriteCycle3: begin // Maintain data bus direction as output O$RAMDataBusIsOutput <= 1; // Move to next "bump pointer" state r$NextState <= p$BumpPointer; end p$BumpPointer: begin // Enable the RAM pointer to increment r$IncrementPointer <= 1; // All done, so go back to idle state r$NextState <= p$Idle; end endcase end // // End of description! // endmodule