This module needs way reworked to just be a state machine. I was trying to get way too tricky with it so I went back to the drawing board and made a state machine diagram for it. The diagram is included with this commit. I also moved the current collection of documentation to a doc/ folder, and added a second-long audio rom to test everything out once the rom_sd is working.
104 lines
3.4 KiB
Systemverilog
104 lines
3.4 KiB
Systemverilog
// A dummy sdcard module for testing the audio port
|
|
|
|
module sd(
|
|
input logic clk,
|
|
input logic reset,
|
|
output logic ready,
|
|
|
|
audio_buffer_interface.driver audio_buffer
|
|
);
|
|
|
|
// First we write 2048B into the memory buffer, then signal to play it and
|
|
// wait for half signal to avoid overwriting memory
|
|
logic initializing;
|
|
logic [16:0] rom_address;
|
|
logic [7:0] rom_data;
|
|
logic rom_enable;
|
|
// Keep track of pipeline delay so we don't write garbage into the buffer
|
|
logic delay;
|
|
|
|
// Keep track of if we are caught up to the buffer or not
|
|
logic waiting;
|
|
//TODO: This probably could be an assign, not sure
|
|
|
|
assign ready = '1;
|
|
|
|
always_ff @(posedge clk) begin
|
|
if (reset) begin
|
|
delay <= 1;
|
|
rom_address <= 0;
|
|
initializing <= 1;
|
|
audio_buffer.addra <= 0;
|
|
audio_buffer.ena <= 0;
|
|
end
|
|
else if (initializing) begin
|
|
rom_enable <= 1;
|
|
case (delay)
|
|
1: delay <= 0;
|
|
0: begin
|
|
rom_address <= 1;
|
|
delay <= 0;
|
|
initializing <= 0;
|
|
end
|
|
endcase
|
|
end
|
|
else begin
|
|
if (!waiting) begin
|
|
audio_buffer.ena <= 1;
|
|
audio_buffer.dina <= rom_data;
|
|
audio_buffer.addra <= audio_buffer.addra + 1;
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
end
|
|
|
|
|
|
// xpm_memory_sprom: Single Port ROM
|
|
// Xilinx Parameterized Macro, version 2024.2
|
|
|
|
// The ROM has 17 address bits and 8 data bits to store 128KiB, more than
|
|
// enough for one second of 48khz audio
|
|
xpm_memory_sprom #(
|
|
.ADDR_WIDTH_A(17), // DECIMAL
|
|
.AUTO_SLEEP_TIME(0), // DECIMAL
|
|
.CASCADE_HEIGHT(0), // DECIMAL
|
|
.ECC_BIT_RANGE("7:0"), // String
|
|
.ECC_MODE("no_ecc"), // String
|
|
.ECC_TYPE("none"), // String
|
|
.IGNORE_INIT_SYNTH(0), // DECIMAL
|
|
.MEMORY_INIT_FILE("roundabout.mem"), // String
|
|
.MEMORY_INIT_PARAM("0"), // String
|
|
.MEMORY_OPTIMIZATION("true"), // String
|
|
.MEMORY_PRIMITIVE("auto"), // String
|
|
.MEMORY_SIZE(131072*8), // DECIMAL
|
|
.MESSAGE_CONTROL(0), // DECIMAL
|
|
.RAM_DECOMP("auto"), // String
|
|
.READ_DATA_WIDTH_A(8), // DECIMAL
|
|
.READ_LATENCY_A(2), // DECIMAL
|
|
.READ_RESET_VALUE_A("0"), // String
|
|
.RST_MODE_A("SYNC"), // String
|
|
.SIM_ASSERT_CHK(0), // DECIMAL; 0=disable simulation messages, 1=enable simulation messages
|
|
.USE_MEM_INIT(1), // DECIMAL
|
|
.USE_MEM_INIT_MMI(0), // DECIMAL
|
|
.WAKEUP_TIME("disable_sleep") // String
|
|
)
|
|
xpm_memory_sprom_inst (
|
|
.douta(rom_data), // READ_DATA_WIDTH_A-bit output: Data output for port A read operations.
|
|
.addra(rom_address), // ADDR_WIDTH_A-bit input: Address for port A read operations.
|
|
.clka(clk), // 1-bit input: Clock signal for port A.
|
|
.ena(rom_enable), // 1-bit input: Memory enable signal for port A. Must be high on clock
|
|
// cycles when read operations are initiated. Pipelined internally.
|
|
|
|
.rsta(reset) // 1-bit input: Reset signal for the final port A output register stage.
|
|
// Synchronously resets output port douta to the value specified by
|
|
// parameter READ_RESET_VALUE_A.
|
|
);
|
|
|
|
// End of xpm_memory_sprom_inst instantiation
|
|
|
|
|
|
endmodule
|