Demo commit
ci/woodpecker/push/test-workflow Pipeline was successful

The audio output is still messed up, but this commit gets everything as
ready as it can get. Fixed up all the testbenches and added state
machines for everything
This commit is contained in:
2025-06-10 13:26:35 -07:00
parent fe227d1b61
commit f840d27b8e
27 changed files with 1300 additions and 274 deletions
+9 -6
View File
@@ -31,11 +31,14 @@ module audio_buffer(
// Inputs for the memory buffer
audio_buffer_interface.receiver driver
);
logic [9:0] address;
// Size of samples, 8bit or 16bit supported
parameter SIZE=16;
(* MARK_DEBUG = "TRUE" *)
logic [11-(SIZE/8):0] address;
// State register
logic enb;
logic [15:0] doutb;
logic [(SIZE-1):0] doutb;
// A single bit counter, to avoid feeding samples given the 1 cycle read delay
logic delay;
@@ -44,7 +47,7 @@ logic delay;
// half of the 2KiB buffer
//
// The MSB of the address == higher/lower half address
assign driver.address_half = address[9];
assign driver.address_half = address[11-(SIZE/8)];
always_ff @(posedge clk) begin
enb <= 0;
@@ -75,7 +78,7 @@ always_ff @(posedge clk) begin
// NOTE: I really don't know a good way to generate the load
// signal. It maybe could be an inverted 48khz clock?
if (delay == 0) begin
sample <= doutb;
sample[15-:SIZE] <= doutb;
end
else begin
sample <= '0;
@@ -91,7 +94,7 @@ end
//) buffer ();
xpm_memory_sdpram #(
.ADDR_WIDTH_A(11), // DECIMAL
.ADDR_WIDTH_B(10), // DECIMAL
.ADDR_WIDTH_B(12-(SIZE/8)), // DECIMAL
.AUTO_SLEEP_TIME(0), // DECIMAL
.BYTE_WRITE_WIDTH_A(8), // DECIMAL
.CASCADE_HEIGHT(0), // DECIMAL
@@ -107,7 +110,7 @@ xpm_memory_sdpram #(
.MEMORY_SIZE(16*1024), // DECIMAL
.MESSAGE_CONTROL(0), // DECIMAL
.RAM_DECOMP("auto"), // String
.READ_DATA_WIDTH_B(16), // DECIMAL
.READ_DATA_WIDTH_B(SIZE), // DECIMAL
.READ_LATENCY_B(1), // DECIMAL
.READ_RESET_VALUE_B("0"), // String
.RST_MODE_A("SYNC"), // String
+1
View File
@@ -21,6 +21,7 @@ module pwm(
parameter DEPTH=11;
logic [DEPTH-1:0] pulse_counter;
(* MARK_DEBUG = "TRUE" *)
logic [15:0] sample_buffer;
logic should_output;
+30 -19
View File
@@ -88,54 +88,65 @@ end
display_anode_driver anodeDriver(clk_1khz,reset,AN,segment_mux_select);
seconds_display secondsSegment (seconds, segments[1], segments[0]);
seconds_display minutesSegment (minutes, segments[3], segments[2]);
seconds_display hoursSegment (hours, segments[5], segments[4]);
sixty_display secondsSegment (seconds, segments[1], segments[0]);
sixty_display minutesSegment (minutes, segments[3], segments[2]);
sixty_display hoursSegment (hours, segments[5], segments[4]);
// Run the playback speed state machine at a lower rate
// Gets rid of button bouncing
playback_controller playbackController (clk_10hz,reset,BTNC, BTNR, speed);
pwm audioOutput(CLK100MHZ, reset, clk_48khz, audio_sample, AUD_PWM);
audio_buffer audioBuffer(
clk_48khz,
reset,
sd_ready,
'0, // stop signal not used right now
speed,
playing,
audio_sample,
audio_interface.receiver
);
`ifdef ROM
rom_sd #("even_flow_16.mem") romSdPlayer(clk_1mhz,reset,sd_ready,audio_interface.driver);
assign {SD_RESET,SD_DAT,SD_CMD,SD_SCK} = 'z;
audio_buffer audioBuffer(
clk_48khz,
reset,
sd_ready,
'0, // stop signal not used right now
speed,
playing,
audio_sample,
audio_interface.receiver
);
pwm audioOutput(CLK100MHZ, reset, clk_48khz, audio_sample, AUD_PWM);
`else
// Power the sd slot
assign SD_RESET = 0;
// We don't use more than one dat line
assign SD_DAT[3:1] = 'z;
logic clk_100khz;
logic clk_25mhz;
// Actually 200khz now
// 200khz is slightly unstable??????
modular_clock_gen #(1000) slowSdClock(CLK100MHZ, reset, clk_100khz);
modular_clock_gen #(500) slowSdClock(CLK100MHZ, reset, clk_100khz);
// Try clocking this slower than max speed
// To see if that makes it actually work ...
modular_clock_gen #(1000) fastSdClock(CLK100MHZ, reset, clk_25mhz);
// If these are different speeds bad things happen :) oops
modular_clock_gen #(400) fastSdClock(CLK100MHZ, reset, clk_25mhz);
sd_controller realSdPlayer(
clk_100khz,
clk_25mhz,
CLK100MHZ,
reset,
SD_DAT[0],
SD_DAT,
SD_CMD,
sd_ready,
SD_SCK,
audio_interface.driver
);
audio_buffer #(.SIZE(8)) audioBuffer(
clk_48khz,
reset,
sd_ready,
'0, // stop signal not used right now
speed,
playing,
audio_sample,
audio_interface.receiver
);
pwm #(8) audioOutput(CLK100MHZ, reset, clk_48khz, audio_sample, AUD_PWM);
`endif
+19 -15
View File
@@ -4,8 +4,7 @@
module read_data(
input clk,
input reset,
input sd_data,
(* MARK_DEBUG = "TRUE" *)
input [3:0] sd_data,
audio_buffer_interface.driver buffer
);
// Block data is a start bit, 512 bytes sent msb first, then a CRC16 and end
@@ -16,7 +15,7 @@ module read_data(
// played. However, as long as the sd card controller doesn't request extra
// blocks this shouldn't be an issue
localparam BLOCK_SIZE=512*8+16+2;
localparam BLOCK_SIZE=512*2+16*4+2;
logic [$clog2(BLOCK_SIZE):0] counter;
logic [7:0] byte_shift;
@@ -28,36 +27,41 @@ assign buffer.clka = clk;
always_ff @(posedge clk) begin
if (reset) begin
buffer.ena <= 0;
buffer.addra <= '1;
// Start negative so adding bytes will get us to the right address
buffer.addra <= 0 - 512;
buffer.dina <= 0;
end
else begin
// We ignore the lower 17 bits of the block
if (counter > 16) begin
// We ignore the lower 16*4+1 bits of the block
// CRC is apparently sent on each line, back to back
if (counter > 16*4) begin
counter <= counter - 1;
byte_shift <= {byte_shift[6:0],sd_data};
byte_shift <= {byte_shift[3:0],sd_data};
byte_counter <= byte_counter - 1;
// Store received byte in audio buffer and reset counter
if (byte_counter == 0) begin
byte_counter <= 7;
buffer.dina <= byte_shift;//{byte_shift[6:0],sd_data};
byte_counter <= 1;
buffer.dina <= {byte_shift[3:0],sd_data};
buffer.ena <= 1;
end
// Turn the enable signal off so we don't accidentally write
// anything weird
if (byte_counter == 4) begin
buffer.ena <= 0;
buffer.addra <= buffer.addra + 1;
if (byte_counter == 1) begin
buffer.addra <= buffer.addra - 1;
end
end
else if (counter != 0)
else if (counter != 0) begin
counter<=counter-1;
buffer.ena <= 0;
end
else if (sd_data == 0) begin
counter <= BLOCK_SIZE-1;
byte_counter <= 8;
// In wide bus mode we read bytes in a descending order
buffer.addra <= buffer.addra + 1024;
counter <= BLOCK_SIZE;
byte_counter <= 3;
end
end
end
+64 -12
View File
@@ -14,7 +14,7 @@ module sd_controller(
input logic crc_clk,
input logic reset,
(* MARK_DEBUG = "TRUE" *)
input logic sd_data,
input logic [3:0] sd_data,
inout logic sd_cmd,
output logic ready,
output wire clk,
@@ -22,7 +22,6 @@ module sd_controller(
audio_buffer_interface.driver buffer
);
// NOTE: this gets encoded as one-hot, even if in here I set it as a logic[5:0]
(* MARK_DEBUG = "TRUE" *)
enum logic [5:0] {
INIT,WAIT,SEND_CMD0,WAIT_CMD0,DELAY_CMD0, // last 4
SEND_CMD8,WAIT_CMD8,LISTEN_RESPONSE_CMD8,WAIT_RESPONSE_CMD8, // last 8
@@ -31,13 +30,15 @@ enum logic [5:0] {
SEND_CMD2,WAIT_CMD2,LISTEN_RESPONSE_CMD2,WAIT_RESPONSE_CMD2, //21
SEND_CMD3,WAIT_CMD3,LISTEN_RESPONSE_CMD3,WAIT_RESPONSE_CMD3, //25
SEND_CMD7,WAIT_CMD7,LISTEN_RESPONSE_CMD7,WAIT_RESPONSE_CMD7, //29
SEND2_CMD55,WAIT2_CMD55,LISTEN_RESPONSE2_CMD55,WAIT_RESPONSE2_CMD55,
SEND_ACMD6,WAIT_ACMD6,LISTEN_RESPONSE_ACMD6,WAIT_RESPONSE_ACMD6,
READY_TO_TRANSMIT,
DELAY_CLOCK_SWITCH,
TRANSMIT,WAIT_TRANSMIT,WAIT_END,FINISH_TRANSMIT,
TRANSMIT2,WAIT_TRANSMIT2,WAIT_END2,FINISH_TRANSMIT2,
WAIT_FOR_BUFFER
} state, next_state;
(* MARK_DEBUG = "TRUE" *)
logic fast_clk_enable;
assign clk = fast_clk_enable ? fast_clk : slow_clk;
@@ -49,7 +50,6 @@ logic [31:0] address;
logic send_command_start;//, send_command_start_fast;
(* MARK_DEBUG = "TRUE" *)
logic [5:0] cmd;
(* MARK_DEBUG = "TRUE" *)
logic [31:0] arg;
(* MARK_DEBUG = "TRUE" *)
wire send_command_ready;//, send_command_ready_fast;
@@ -189,7 +189,7 @@ always_comb begin
next_state=WAIT_RESPONSE_CMD7;
WAIT_RESPONSE_CMD7:
if (read_command_received)
next_state=READY_TO_TRANSMIT;
next_state=SEND2_CMD55;
else
next_state=WAIT_RESPONSE_CMD7;
@@ -230,8 +230,42 @@ always_comb begin
else
next_state=ACMD41_DELAY;
SEND2_CMD55:
next_state=WAIT2_CMD55;
WAIT2_CMD55:
if (send_command_ready)
next_state=LISTEN_RESPONSE2_CMD55;
else
next_state=WAIT2_CMD55;
LISTEN_RESPONSE2_CMD55:
next_state=WAIT_RESPONSE2_CMD55;
WAIT_RESPONSE2_CMD55:
if (read_command_received)
next_state=SEND_ACMD6;
else
next_state=WAIT_RESPONSE2_CMD55;
SEND_ACMD6:
next_state=WAIT_ACMD6;
WAIT_ACMD6:
if (send_command_ready)
next_state=LISTEN_RESPONSE_ACMD6;
else
next_state=WAIT_ACMD6;
LISTEN_RESPONSE_ACMD6:
next_state=WAIT_RESPONSE_ACMD6;
WAIT_RESPONSE_ACMD6:
if (read_command_received)
next_state=READY_TO_TRANSMIT;
else
next_state=WAIT_RESPONSE_ACMD6;
READY_TO_TRANSMIT:
next_state=TRANSMIT;
next_state=DELAY_CLOCK_SWITCH;
DELAY_CLOCK_SWITCH:
if (counter == 0)
next_state = TRANSMIT;
else
next_state = DELAY_CLOCK_SWITCH;
TRANSMIT:
next_state=WAIT_TRANSMIT;
WAIT_TRANSMIT:
@@ -310,7 +344,14 @@ always_ff @(posedge clk) begin
arg <= 0;
send_command_start <=1;
end
LISTEN_RESPONSE_CMD55: begin
SEND2_CMD55: begin
cmd <= 55;
// the arg should be the same as the preceding command
// and otherwise we'll lose the RCA bits
//arg <= 0;
send_command_start <=1;
end
LISTEN_RESPONSE_CMD55,LISTEN_RESPONSE2_CMD55: begin
response_type <= 1;
read_command_listen <= 1;
end
@@ -327,6 +368,15 @@ always_ff @(posedge clk) begin
read_command_listen<=0;
counter<=100;
end
SEND_ACMD6: begin
cmd <= 6;
arg <= 'b10;
send_command_start <=1;
end
LISTEN_RESPONSE_ACMD6: begin
response_type <= 1;
read_command_listen <= 1;
end
SEND_CMD2: begin
cmd <= 2;
arg <= 0;
@@ -358,6 +408,8 @@ always_ff @(posedge clk) begin
fast_clk_enable <= 1;
address <= 0;
sd_buffer_half <= 0;
// Wait to actually transmit until clock is running and stable
counter <= 100;
end
TRANSMIT, TRANSMIT2: begin
cmd <= 17;
@@ -366,7 +418,7 @@ always_ff @(posedge clk) begin
end
WAIT_TRANSMIT, WAIT_TRANSMIT2: begin
send_command_start <= 0;
counter <= 411;
counter <= 512*2+16+1;
end
FINISH_TRANSMIT:
address <= address +1;
@@ -377,12 +429,12 @@ always_ff @(posedge clk) begin
WAIT_FOR_BUFFER:
ready <= 1;
// The logic is simple enough in these to group them
WAIT, DELAY_CMD0, ACMD41_DELAY, WAIT_END, WAIT_END2:
WAIT, DELAY_CMD0, ACMD41_DELAY, WAIT_END, WAIT_END2, DELAY_CLOCK_SWITCH:
counter <= counter - 1;
WAIT_CMD8,WAIT_CMD55,WAIT_ACMD41,WAIT_CMD2,WAIT_CMD3,WAIT_CMD7:
WAIT_CMD8,WAIT_CMD55,WAIT_ACMD41,WAIT2_CMD55,WAIT_ACMD6,WAIT_CMD2,WAIT_CMD3,WAIT_CMD7:
send_command_start<=0;
WAIT_RESPONSE_CMD8,WAIT_RESPONSE_CMD55,WAIT_RESPONSE_CMD2,WAIT_RESPONSE_CMD3,
WAIT_RESPONSE_CMD7:
WAIT_RESPONSE_CMD8,WAIT_RESPONSE_CMD55,WAIT_RESPONSE2_CMD55,WAIT_RESPONSE_ACMD6,
WAIT_RESPONSE_CMD2,WAIT_RESPONSE_CMD3,WAIT_RESPONSE_CMD7:
read_command_listen<=0;
default: ;
@@ -1,14 +1,14 @@
/***
* seconds_display.sv - converts a five bit seconds counter to its seven segement display equivalent.
* sixty_display.sv - converts a five bit seconds counter to its seven segement display equivalent.
*
* @author: Dilanthi Prentice, Waylon Cude
* @date: 6/12/25
*
*/
module seconds_display
module sixty_display
(
input [$clog2(60)-1:0] seconds,
input [$clog2(60)-1:0] number,
output [6:0] display_tens,
output [6:0] display_ones
);
@@ -18,8 +18,8 @@ logic [4:0] tens_digit;
always_comb
begin
ones_digit = seconds % 10;
tens_digit = seconds / 10;
ones_digit = number % 10;
tens_digit = number / 10;
end
//instantiate the display_converter to convert the counter