Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 89 additions & 0 deletions rtl/audio/audio_dma.sv
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
module audio_dma #(
parameter int unsigned ADDR_W = 32,
parameter int unsigned DATA_W = 32, //assumming 32 bit axi for right now
parameter int unsigned SIZE_W = 16,
parameter int unsigned SAMPLE_W = 16,
parameter int unsigned BURST_LEN = 8,
parameter int unsigned FIFO_DEPTH = 64,
)(
input logic clk_i, //system clock
input logic rst_ni, //system reset
input logic enable_i, //enable input to begin operation
input logic [ADDR_W-1:0] buf_base_i, //base address of audio ring buffer in system memory
input logic [SIZE_W-1:0] buf_size_i, //total size of ring buffer
input logic [ADDR_W-1:0] rd_offset_i, //byte offset from buf_bas_i oringally named rd_ptr_i


//AXI4 AR channel master to fabric
//when we are taking in data?
output logic [1:0] arburst_o, //what type of burst we are sending; i beleive there are 3 burst types
output logic [ADDR_W-1:0] araddr_o, //the starting address of burst
output logic [7:0] arlen_o, //beats - 1
output logic [2:0] arsize_o, //how many bytes are in each transfer
input logic arready_i, //this is gonna be asserted when the memory is ready to receive a new burst
output logic arvalid_o, //this is gonna be asserted when the user (this module?) is ready to issue a new burst
/*When both arready and arvalid are high (reading a value of one)
a new burst is starting, and the memory is gonna start serving this burst */

//AXI R channel fabric to master stuff
//aka when we are streaming out chunks of data
input logic [DATA_W-1:0] rdata_i, //contains the actually data
input logic [1:0] rresp_i, //tells use whether the burst was succesfully or not
input logic rlast_i, //tells us the last piece of data
output logic rready_o, //when the reciever is ready to receive data, this value gets set to high
input logic rvalid_i, //when a chunk of data is ready to be sent out from the memory this value we be set to high
/*when both rready and rvalid high the chunk of data has been acknowledge and it will service the next chunk of data or finish*/

output logic [SAMPLE_W-1:0] sample_o,
output logic sample_valid_o,
input logic sample_ready_i,

output logic underrun_o,
output logic irq_o
);

localparam int unsigned BYTES_PER_BEAT = DATA_W/8; //4
localparam int unsigned ARSIZE_VAL = $clog2(BYTES_PER_BEAT); //2
localparam int unsigned ARLEN_VAL = BURST_LEN - 1;
localparam int unsigned SAMPLES_PER_BEAT = DATA_W / SAMPLE_W; // = 2


always_ff @(posedge clk_i or negedge rst_ni) begin
if (~rst_ni) begin


end
end


always_ff @(posedge clk_i or negedge rst_ni) begin
if (~rst_ni) begin





end
end
always_ff @(posedge clk_i or negedge rst_ni) begin
if (~rst_ni) begin





end
end
always_ff @(posedge clk_i or negedge rst_ni) begin
if (~rst_ni) begin





end
end



endmodule
81 changes: 81 additions & 0 deletions rtl/audio/fifo.sv
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
module fifo #(
//Parameters
parameter WIDTH = 32,
parameter DEPTH = 16
)(
//Ports
input logic clk_i,
input logic rst_ni,

//Write
input logic [WIDTH-1:0] wdata_i,
input logic wr_en_i,
output logic full_o,

//Read
output logic [WIDTH-1:0] rdata_o,
input logic rd_en_i,
output logic empty_o
);

timeunit 1ns; timeprecision 100ps;

//local parameters
localparam ADDR_W = $clog2(DEPTH);

//local signals
logic [ADDR_W-1:0] rptr, wptr;
logic full, empty;
logic last_was_read;

//Register Array
logic [WIDTH-1:0] mem [0:DEPTH-1];

//Write operation
always_ff @(posedge clk_i or negedge rst_ni) begin
if (!rst_ni) begin
wptr <= 0;
end else begin
if (wr_en_i && !full) begin
mem[wptr] <= wdata_i;
wptr <= wptr + 1'b1;
end
end
end

//Read operation
always_ff @(posedge clk_i or negedge rst_ni) begin
if (!rst_ni) begin
rptr <= 0;
end else begin
if (rd_en_i && !empty) begin
rptr <= rptr + 1'b1;
rdata_o <= mem[rptr];
end
end
end
//Last operation tracker
always_ff @(posedge clk_i or negedge rst_ni) begin
if (!rst_ni) begin
last_was_read <= 1;
end else begin
if (rd_en_i && !empty) begin
last_was_read <= 1;
end else if (wr_en_i && !full) begin
last_was_read <= 0;
end else begin
last_was_read <= last_was_read;
end
end
end

//Full and empty flags

assign full = (wptr == rptr) && !last_was_read;
assign empty = (wptr == rptr) && last_was_read;

assign full_o = full;
assign empty_o = empty;


endmodule
176 changes: 176 additions & 0 deletions rtl/audio/i2s_tx.sv
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
module i2s_tx #(
parameter int unsigned CLK_HZ = 100_000_000,
parameter int unsigned SAMPLE_HZ = 48_000,
parameter int unsigned SAMPLE_W = 16,
parameter int unsigned CHNL_CNT = 2
)(
input logic clk_i,
input logic rst_ni,
input logic enable_i,

//Sample steam input (from audio_dma)
input logic [SAMPLE_W-1:0] sample_i,
input logic sample_valid_i,
output logic sample_ready_o,

//I2S output
output logic i2s_sdata_o,
output logic i2s_bclk_o,
output logic i2s_lrclk_o,


//Status / interrupts
output logic underrun_o,
output logic irq_o
);

localparam int unsigned BCLK_HZ = SAMPLE_HZ * CHNL_CNT * SAMPLE_W;
localparam int unsigned LRCLK_HZ = SAMPLE_HZ;
localparam int unsigned BCLK_TOGGLE = 2 * BCLK_HZ;
localparam int unsigned DIV = CLK_HZ / (2 * BCLK_HZ);

//clock generation and timing
logic bclk_q;
logic lrclk_q;
logic [8:0] div_cnt_q;
logic bclk_rise;
logic bclk_fall;
logic bclk_fall_q;
logic [3:0] bit_idx_q;
logic channel_q;

//sample bufferinf (valid/ready)
logic [SAMPLE_W-1:0] samp_buf_q;
logic have_buf_q;

//shift engine
logic [SAMPLE_W-1:0] shreg_q;
logic sdata_q;

//staus / interrupts
logic underrun_q;
logic irq_q;

//state machine logic
typedef enum logic [2:0] {
IDLE,
LOAD,
SHIFT,
ERROR
} state_e;

state_e state_q, state_d;
//state variable reset and initalization
always_ff @(posedge clk_i or negedge rst_ni) begin
if (!rst_ni) begin
state_q <= IDLE;
end else begin
state_q <= state_d;
end
end

always_comb begin
state_d = state_q;
case (state_q)
IDLE: begin
if (enable_i) begin

state_d = LOAD;
end
end
LOAD: begin
if (bclk_fall) begin
state_d = SHIFT;
end
end
SHIFT: begin
if (bclk_fall && (bit_idx_q == SAMPLE_W - 1)) begin
state_d = LOAD;
end
end
ERROR: begin
state_d = IDLE;
end
default: state_d = IDLE;
endcase
end

assign sample_ready_o = enable_i && !have_buf_q;

always_ff @(posedge clk_i or negedge rst_ni) begin
if (!rst_ni) begin
channel_q <= 0;
have_buf_q <= 0;
samp_buf_q <= 0;
bit_idx_q <= 0;
underrun_q <= 0;
irq_q <= 0;
lrclk_q <= 0;
shreg_q <= 0;
sdata_q <= 0;
end else begin

if (sample_valid_i && sample_ready_o) begin
samp_buf_q <= sample_i;
have_buf_q <= 1'b1;
end

if (bclk_fall) begin
case (state_q)
LOAD: begin
bit_idx_q <= 0;
if (have_buf_q) begin
shreg_q <= samp_buf_q;
have_buf_q <= 0;
end else begin
shreg_q <= 0;
underrun_q <= 1;
irq_q <= 1;
end
lrclk_q <= channel_q;
sdata_q <= 0;

end
SHIFT: begin
// if (bclk_fall) begin
if (bit_idx_q == SAMPLE_W-1) begin
bit_idx_q <= 0; //reset to zero when the max value it should hold is reach ...
channel_q <= ~channel_q; //switch channels when the word is complete
end else begin
bit_idx_q <= bit_idx_q + 1; //... keep climbing till it reaches max value
end
//end
sdata_q <= shreg_q[SAMPLE_W-1];
shreg_q <= {shreg_q[SAMPLE_W-2:0], 1'b0};
end
endcase
end
end
end

//clock stuff
always_ff @(posedge clk_i or negedge rst_ni) begin
if (!rst_ni) begin
bclk_q <= 0;
bclk_fall_q <= 0;
div_cnt_q <= 0;
end else begin
if (div_cnt_q == DIV-1) begin
bclk_fall_q <= bclk_q;
bclk_q <= ~bclk_q;
div_cnt_q <= 0;
end else begin
div_cnt_q <= div_cnt_q + 1;
bclk_fall_q <= 0;
end
end
end

assign bclk_fall = bclk_fall_q;
assign i2s_lrclk_o = lrclk_q;
assign i2s_bclk_o = bclk_q;
assign i2s_sdata_o = sdata_q;
assign underrun_o = underrun_q;
assign irq_o = irq_q;

endmodule
Loading