/**** * rom_sd.sv - reads audio data off a rom and feeds it to the audio buffer * * @author: Dilanthi Prentice, Waylon Cude * @date: 6/12/25 * * **/ module rom_sd( input logic clk, input logic reset, output logic ready, buffer_interface.driver buffer ); typedef enum logic [2:0]{ RESET, DELAY, WRITEBUF, ENDWRITE, WAIT } state_t; state_t current, next; // 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_addr; logic [7:0] rom_data; logic rom_enable; logic buffer_half; // 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_addr), // 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 //next state logic always_comb begin case (current) RESET: if (reset) next = RESET; else next = DELAY; DELAY: next = WRITEBUF; WRITEBUF: if (buffer.addra < 1023) next = WRITEBUF; else if (buffer.addra == 1023) next = ENDWRITE; ENDWRITE: next = WAIT; WAIT: if (buffer_half == buffer.address_half) next = WAIT; else next = DELAY; default: next = RESET; endcase end //sequential output logic always_ff @(posedge clock) begin case (current) RESET: begin buffer_half <= 0; rom_addr <= 0; rom_enable <= 1; buffer.addra <= 0; ready <= 0; end DELAY: rom_addr <= rom_addr + 1; WRITEBUF: begin buffer.ena <= 1; buffer.dina <= rom_data; buffer.addra <= buffer.addra + 1; rom_addr <= rom_addr + 1; end ENDWRITE: begin buffer.ena <= 1; buffer.data <= rom_data; buffer.addra <= buffer.addra + 1; ready <= 1; end WAIT: buffer.ena <= 0; default: begin buffer_half <= 0; rom_addr <= 0; rom_enable <= 0; buffer.addra <= 0; buffer.dina <= 0; ready <= 0; end endcase end //sequential clocking block always_ff @(posedge clock) begin if (reset) current <= RESET; else current <= next; end endmodule