Skip to content

Commit

Permalink
feat: modify i2s module and testbench
Browse files Browse the repository at this point in the history
  • Loading branch information
Elizabeth-0 committed Feb 14, 2025
1 parent 288da21 commit fed60db
Show file tree
Hide file tree
Showing 2 changed files with 120 additions and 88 deletions.
125 changes: 67 additions & 58 deletions src/tt_um_waves.v
Original file line number Diff line number Diff line change
Expand Up @@ -179,19 +179,22 @@ module tt_um_waves (
);

// Apply ADSR Envelope
reg [15:0] temp_wave; // Full 16-bit calculation
reg [7:0] scaled_wave; // Final 8-bit result
reg [15:0] temp_wave; // Ensure full precision calculation
reg [7:0] scaled_wave; // Final 8-bit output

always @(posedge clk or negedge rst_n) begin
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
temp_wave <= 16'd0;
scaled_wave <= 8'd0;
end else begin
temp_wave <= selected_wave * adsr_amplitude; // Full precision
scaled_wave <= temp_wave[15:8] + {7'b0, temp_wave[7]}; // Ensure RHS is 8-bit
scaled_wave <= temp_wave[15:8] + {7'b0, temp_wave[7]}; // Convert temp_wave[7] to 8-bit

end
end



// I2S Output
wire i2s_sck, i2s_ws, i2s_sd;
i2s_transmitter i2s_out (
Expand Down Expand Up @@ -232,7 +235,7 @@ module uart_receiver (
reg receiving; // UART receiving flag
reg [1:0] state; // State machine: 0 = idle, 1 = receiving, 2 = processing

reg [7:0] temp_byte; // Temporary register for intermediate calculations
reg [7:0] temp_byte; // Ensure enough bits for calculation

// State machine states
localparam IDLE = 2'b00;
Expand Down Expand Up @@ -359,39 +362,49 @@ endmodule


module i2s_transmitter (
input wire clk, // System clock
input wire rst_n, // Reset, active low
input wire ena, // Enable signal
input wire [7:0] data, // 8-bit audio data
output reg sck, // Bit clock
output reg ws, // Word select
output reg sd // Serial data output
input wire clk, // System clock
input wire rst_n, // Reset (active low)
input wire ena, // Enable signal
input wire [7:0] data, // 8-bit audio data
output reg sck, // Serial clock (bit clock)
output reg ws, // Word select (left/right channel)
output reg sd // Serial data output
);

reg [3:0] bit_counter;
reg [15:0] audio_data;
reg [3:0] bit_counter; // Counts bits being sent
reg [15:0] shift_reg; // Shift register for transmitting data
reg [7:0] clk_div; // Clock divider for generating `sck`

// I2S transmission logic
always @(posedge clk or negedge rst_n) begin
parameter SCK_DIV = 16; // Adjust this based on your clock frequency

always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
bit_counter <= 4'd0;
audio_data <= 16'd0;
sck <= 0;
ws <= 0;
sd <= 0;
clk_div <= 0;
sck <= 0;
ws <= 0;
sd <= 0;
bit_counter <= 0;
shift_reg <= 16'd0;
end else if (ena) begin
// Bit clock generation
sck <= ~sck;
if (sck) begin
bit_counter <= bit_counter + 1;
if (bit_counter == 15) begin
bit_counter <= 0;
ws <= ~ws; // Toggle Word Select for I2S framing
// Load next audio sample
audio_data <= {data, data}; // Replicate 8-bit data for 16-bit transmission
// Generate I2S Serial Clock (sck) at the correct frequency
if (clk_div == (SCK_DIV - 1)) begin
clk_div <= 0;
sck <= ~sck; // Toggle sck
end else begin
clk_div <= clk_div + 1;
end

// Data Transmission Logic (Shift Register)
if (sck == 0) begin // Shift data on the falling edge of sck
if (bit_counter == 0) begin
ws <= ~ws; // Toggle word select every 16 bits
shift_reg <= {data, data}; // Duplicate 8-bit data for 16-bit format
end else begin
shift_reg <= shift_reg << 1; // Shift left to send MSB first
end
// Transmit audio data bit by bit
sd <= audio_data[15 - bit_counter];

sd <= shift_reg[15]; // Output MSB first
bit_counter <= (bit_counter == 15) ? 0 : bit_counter + 1;
end
end
end
Expand Down Expand Up @@ -496,7 +509,7 @@ endmodule


module adsr_generator (
input wire ena, // Enable signal
input wire ena, // Enable signal
input wire clk, // Clock
input wire rst_n, // Active-low reset
input wire [7:0] attack, // Attack value
Expand All @@ -506,68 +519,64 @@ module adsr_generator (
output reg [7:0] amplitude // Generated amplitude signal
);

reg [3:0] state;
(* fsm_encoding = "binary" *) reg [3:0] state;
reg [7:0] counter;

localparam STATE_IDLE = 4'd0;
localparam STATE_ATTACK = 4'd1;
localparam STATE_DECAY = 4'd2;
localparam STATE_SUSTAIN = 4'd3;
localparam STATE_RELEASE = 4'd4;
localparam STATE_IDLE = 4'b0000;
localparam STATE_ATTACK = 4'b0001;
localparam STATE_DECAY = 4'b0010;
localparam STATE_SUSTAIN = 4'b0011;
localparam STATE_RELEASE = 4'b0100;

always @(posedge clk or negedge rst_n) begin
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
state <= STATE_IDLE;
state <= STATE_IDLE;
amplitude <= 8'd0;
counter <= 8'd0;
counter <= 8'd0;
end else if (ena) begin
case (state)
STATE_IDLE: begin
if (counter == 8'd255) begin
state <= STATE_ATTACK;
state <= STATE_ATTACK;
counter <= 8'd0;
end else begin
counter <= counter + 1;
end
end
STATE_ATTACK: begin
if (amplitude < attack) begin
if (amplitude < attack)
amplitude <= amplitude + 1;
end else begin
else
state <= STATE_DECAY;
end
end
STATE_DECAY: begin
// Use the decay parameter to adjust the rate of decrease
if (amplitude > sustain) begin
if (amplitude > sustain)
amplitude <= amplitude - decay;
end else begin
else
state <= STATE_SUSTAIN;
end
end
STATE_SUSTAIN: begin
amplitude <= sustain;
if (counter == 8'd255) begin
state <= STATE_RELEASE;
state <= STATE_RELEASE;
counter <= 8'd0;
end else begin
counter <= counter + 1;
end
end
STATE_RELEASE: begin
if (amplitude > 0) begin
amplitude <= amplitude - rel;
end else begin
state <= STATE_IDLE;
end
end

if (amplitude > 0)
amplitude <= amplitude - rel;
else
state <= STATE_IDLE;
end
default: state <= STATE_IDLE;
endcase
end
end
endmodule


module triangular_wave_generator (
input wire ena, // Enable signal
input wire clk, // Clock
Expand Down
83 changes: 53 additions & 30 deletions test/tb.v
Original file line number Diff line number Diff line change
Expand Up @@ -26,17 +26,13 @@ module tb;
wire [7:0] uio_out;
wire [7:0] uio_oe;

`ifdef GL_TEST
wire VPWR = 1'b1;
wire VGND = 1'b0;
`endif
// I2S Signals
wire i2s_sck = uo_out[0];
wire i2s_ws = uo_out[1];
wire i2s_sd = uo_out[2];

// Instantiate the module under test
tt_um_waves dut (
`ifdef GL_TEST
.VPWR(VPWR),
.VGND(VGND),
`endif
.ui_in (ui_in),
.uo_out (uo_out),
.uio_in (uio_in),
Expand All @@ -47,72 +43,99 @@ module tb;
.rst_n (rst_n)
);

// Test sequence
// Load Sine Wave LUT from file
reg [7:0] sine_table [0:127]; // Adjust size based on file contents
initial begin
$readmemh("sine_table.mem", sine_table);
end

// Reset sequence
initial begin
#100;
rst_n = 1;
ena = 1;

#200;
ui_in = 8'h41;
ui_in = 8'h41; // Arbitrary input

#500000;
$finish;
end

// UART transmission simulation
task uart_send(input [7:0] data);
integer i;
reg [7:0] i; // Changed from integer to reg
begin
ui_in[0] = 0;
ui_in[0] = 0; // Start bit
#2604;

for (i = 0; i < 8; i = i + 1) begin
ui_in[0] = (data >> i) & 1;
#2604;
#2604; // 9600 baud bit time
end

ui_in[0] = 1;
ui_in[0] = 1; // Stop bit
#2604;
end
endtask

// Test sequence for UART commands
reg [3:0] j; // Replace integer j with reg [3:0] j
// Test sequence for UART commands & I2S validation
reg [3:0] j; // Frequency selection index
initial begin
#100;
uart_send(8'h54); // 'T' for Triangle

// Test wave selection
uart_send(8'h54); // 'T' for Triangle wave
#1000;
$display("Triangle: I2S SD: %b", uo_out[2]);
$display("Triangle Wave Selected - I2S SD: %b", i2s_sd);

uart_send(8'h53); // 'S' for Sawtooth
uart_send(8'h53); // 'S' for Sawtooth wave
#1000;
$display("Sawtooth: I2S SD: %b", uo_out[2]);
$display("Sawtooth Wave Selected - I2S SD: %b", i2s_sd);

uart_send(8'h51); // 'Q' for Square
uart_send(8'h51); // 'Q' for Square wave
#1000;
$display("Square: I2S SD: %b", uo_out[2]);
$display("Square Wave Selected - I2S SD: %b", i2s_sd);

uart_send(8'h57); // 'W' for Sine
uart_send(8'h57); // 'W' for Sine wave
#1000;
$display("Sine: I2S SD: %b", uo_out[2]);
$display("Sine Wave Selected - I2S SD: %b", i2s_sd);

// Iterate over frequencies using reg [3:0] j
// Test frequency selection
for (j = 0; j < 10; j = j + 1) begin
uart_send(8'h30 + j);
#1000;
$display("Freq %d: I2S SCK: %b", j, uo_out[0]);
$display("Freq %d Selected - I2S SCK: %b, WS: %b, SD: %b", j, i2s_sck, i2s_ws, i2s_sd);
end

// White Noise Test
uart_send(8'h4E); // Enable Noise
uart_send(8'h4E); // Enable White Noise
#1000;
$display("Noise On: I2S SD: %b", uo_out[2]);
$display("White Noise Enabled - I2S SD: %b", i2s_sd);

uart_send(8'h46); // Disable Noise
uart_send(8'h46); // Disable White Noise
#1000;
$display("Noise Off: I2S SD: %b", uo_out[2]);
$display("White Noise Disabled - I2S SD: %b", i2s_sd);

// Check sine wave LUT integrity
check_sine_wave_lut();

$finish;
end

// LUT Verification - Ensure sine wave table is correct
task check_sine_wave_lut;
reg [7:0] i; // Changed from integer to reg
begin
for (i = 0; i < 128; i = i + 1) begin
#100;
if (uo_out != sine_table[i]) begin
$display("ERROR: Sine LUT mismatch at index %d: Expected %h, Got %h", i, sine_table[i], uo_out);
end else begin
$display("Sine LUT check passed at index %d: %h", i, uo_out);
end
end
end
endtask

endmodule

0 comments on commit fed60db

Please sign in to comment.