- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I'm using an M9K BRAM in single clock, dual port mode. It is controlled by two state machines, one writing data, and one reading data. I'm looking at all of the signals in signal tap, and everything looks like it's operating correctly. However, assuming I'm writing data words {D1, D2, D3, D4} to adresses {A1, A2, A3, A4}, during readout I get {D1, D1, D2, D3} for addresses {A1, A2, A3, A4}. My first thought was that there was a setup time violation between data and the write clock, or address and the read clock. I can't find any documentation on timing requirements for the BRAM, but just to experiment, I increased the latency between data and write and address and read to 3 clock cycles. I still get the same error. Anyone know what's going on?
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Can you share the code for your write state machine? The most likely situation is that the address and data are out of step with each other...
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
So a little background. The purpose of the write module is to grab bits serially and put them into a shift register, and then write the contents of that shift register to the BRAM. This process is repeated for a programmable number of bits, depending on the amount of data in the shift register for a given cycle. New data is available to write as soon as the WAIT_READOUT state is done. You can see where I put some extra states between WAIT_READOUT and WRITE_MEM in to increase the latency between the address changing and the rising edge of the BRAM clock. This does not seem to have any effect. There is also at least one clock cycle of latency between the rising edge of the BRAM clock and the address being incremented.
Edit:
Forgot to include the block which assigns the address bits and the shift register. Those probably make the code more understandable. Also, the relevant signals for the BRAM are:
logic [20:0] timestampData - this is a module port which gets padded out to 32 bits and connected to the BRAM data input.
logic [3:0] timestampAddr - this is a module port, and gets directly connected to the BRAM write address.
logic timestampWriteClk - this is a module port, and gets ORed with the read clock before being connected to BRAM.
/************************************* State Machine *************************************/
// State transition block.
always_ff @ (posedge clk or negedge rst_n)
begin
if (!rst_n)
currentState <= IDLE;
else
currentState <= nextState;
end
// Next state block.
always_comb
begin
case (currentState)
// Waiting for startReadout.
IDLE:
begin
if ((startReadout == 1'b1) && (numSamplesReg > 0) && (numSamplesReg <= 12))
nextState = RESET_COUNTER;
else
nextState = IDLE;
end
// Reset the readout counter.
RESET_COUNTER:
begin
nextState = RESET_SYNC;
end
// De-assert counter reset.
RESET_SYNC:
begin
if (timestampAddr == '0)
nextState = SAMPLE_FIRST;
else
nextState = READOUT;
end
// Sample the first bit in the ROIC buffer.
SAMPLE_FIRST:
begin
nextState = SAMPLE_SYNC;
end
// De-assert the sample first bit signal.
//This state avoids errors due to ORing dataClk and the sample first bit signal.
SAMPLE_SYNC:
begin
nextState = READOUT;
end
// Read out the timestamp bits.
READOUT:
begin
if (readoutTimerDone == 1'b1)
nextState = WAIT_READOUT;
else
nextState = READOUT;
end
// Wait until the last readout clock cycle has been completed.
WAIT_READOUT:
begin
if (readoutCounterDone == 1'b1)
nextState = WRITE_SYNC1;
else
nextState = WAIT_READOUT;
end
// Wait one clock cycle to ensure fresh data for the memory write.
WRITE_SYNC1:
begin
nextState = WRITE_SYNC2;
end
WRITE_SYNC2:
begin
nextState = WRITE_SYNC3;
end
WRITE_SYNC3:
begin
nextState = WRITE_MEM;
end
// Assert write clock to write the timestamp bits to memory.
WRITE_MEM:
begin
nextState = WRITE_MEM_2;
end
// De-assert write clock.
WRITE_MEM_2:
begin
nextState = INC_ADDRESS;
end
// Increment the memory adress for the next write.
INC_ADDRESS:
begin
nextState = CHECK_DONE;
end
// Check if the readout cycle is complete.
CHECK_DONE:
begin
if (timestampAddr == numSamplesReg)
nextState = IDLE;
else
nextState = RESET_COUNTER;
end
default:
begin
nextState = IDLE;
end
endcase
end
// Output logic block.
always_comb
begin
case (currentState)
// Waiting to begin readout cycle.
IDLE:
begin
readoutCounterRst = 1'b0;
dataRdy = 1'b1;
sampleFirstBit = 1'b0;
dataClkEnQ = 1'b0;
resetAddr = 1'b1;
incrementAddr = 1'b0;
timestampWriteClk = 1'b0;
end
// Reset the readout counter to load the correct period value.
RESET_COUNTER:
begin
readoutCounterRst = 1'b1;
dataRdy = 1'b0;
sampleFirstBit = 1'b0;
dataClkEnQ = 1'b0;
resetAddr = 1'b0;
incrementAddr = 1'b0;
timestampWriteClk = 1'b0;
end
// De-assert counter reset.
RESET_SYNC:
begin
readoutCounterRst = 1'b0;
dataRdy = 1'b0;
sampleFirstBit = 1'b0;
dataClkEnQ = 1'b0;
resetAddr = 1'b0;
incrementAddr = 1'b0;
timestampWriteClk = 1'b0;
end
// Sample the first bit. The ROIC makes the first bit of the timestamps
// available before the first read clock cycle.
SAMPLE_FIRST:
begin
readoutCounterRst = 1'b0;
dataRdy = 1'b0;
sampleFirstBit = 1'b1;
dataClkEnQ = 1'b0;
resetAddr = 1'b0;
incrementAddr = 1'b0;
timestampWriteClk = 1'b0;
end
// De-assert the sample first bit signal.
SAMPLE_SYNC:
begin
readoutCounterRst = 1'b0;
dataRdy = 1'b0;
sampleFirstBit = 1'b0;
dataClkEnQ = 1'b0;
resetAddr = 1'b0;
incrementAddr = 1'b0;
timestampWriteClk = 1'b0;
end
// Read out the rest of the timestamp bits.
READOUT:
begin
readoutCounterRst = 1'b0;
dataRdy = 1'b0;
sampleFirstBit = 1'b0;
dataClkEnQ = 1'b1;
resetAddr = 1'b0;
incrementAddr = 1'b0;
timestampWriteClk = 1'b0;
end
// Wait for the last readout clock tick.
WAIT_READOUT:
begin
readoutCounterRst = 1'b0;
dataRdy = 1'b0;
sampleFirstBit = 1'b0;
dataClkEnQ = 1'b0;
resetAddr = 1'b0;
incrementAddr = 1'b0;
timestampWriteClk = 1'b0;
end
// Wait a clock cycle to ensure fresh data for the memory write.
WRITE_SYNC1:
begin
readoutCounterRst = 1'b0;
dataRdy = 1'b0;
sampleFirstBit = 1'b0;
dataClkEnQ = 1'b0;
resetAddr = 1'b0;
incrementAddr = 1'b0;
timestampWriteClk = 1'b0;
end
WRITE_SYNC2:
begin
readoutCounterRst = 1'b0;
dataRdy = 1'b0;
sampleFirstBit = 1'b0;
dataClkEnQ = 1'b0;
resetAddr = 1'b0;
incrementAddr = 1'b0;
timestampWriteClk = 1'b0;
end
WRITE_SYNC3:
begin
readoutCounterRst = 1'b0;
dataRdy = 1'b0;
sampleFirstBit = 1'b0;
dataClkEnQ = 1'b0;
resetAddr = 1'b0;
incrementAddr = 1'b0;
timestampWriteClk = 1'b0;
end
// Strobe the write clock to write the timestamp to memory.
WRITE_MEM:
begin
readoutCounterRst = 1'b0;
dataRdy = 1'b0;
sampleFirstBit = 1'b0;
dataClkEnQ = 1'b0;
resetAddr = 1'b0;
incrementAddr = 1'b0;
timestampWriteClk = 1'b1;
end
// De-assert the write clock.
WRITE_MEM_2:
begin
readoutCounterRst = 1'b0;
dataRdy = 1'b0;
sampleFirstBit = 1'b0;
dataClkEnQ = 1'b0;
resetAddr = 1'b0;
incrementAddr = 1'b0;
timestampWriteClk = 1'b0;
end
// Increment the memory address. This corresponds directly to the timestamp number.
INC_ADDRESS:
begin
readoutCounterRst = 1'b0;
dataRdy = 1'b0;
sampleFirstBit = 1'b0;
dataClkEnQ = 1'b0;
resetAddr = 1'b0;
incrementAddr = 1'b1;
timestampWriteClk = 1'b0;
end
// Check to see if all of the requested timestamps have been read out of the ROIC.
CHECK_DONE:
begin
readoutCounterRst = 1'b0;
dataRdy = 1'b0;
sampleFirstBit = 1'b0;
dataClkEnQ = 1'b0;
resetAddr = 1'b0;
incrementAddr = 1'b0;
timestampWriteClk = 1'b0;
end
default:
begin
readoutCounterRst = 1'b1;
dataRdy = 1'b0;
sampleFirstBit = 1'b0;
dataClkEnQ = 1'b0;
resetAddr = 1'b0;
incrementAddr = 1'b0;
end
endcase
end
// Timestamp data shift register.
always_ff @ (negedge sampleClk or negedge rst_n)
begin
if (!rst_n)
timestampData <= '0;
else
begin
timestampData <= {dataOut, timestampData[20:1]};
end
end
// Timestamp memory address block.
always_ff @ (posedge incrementAddr or posedge resetAddr)
begin
if (resetAddr)
timestampAddr <= '0;
else
timestampAddr <= timestampAddr + 1'b1;
end
- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page