`timescale 1ns / 1ps module tdraudio #(DATA_WIDTH=32) ( input wire clk, input wire reset, input wire [3:0] reg_sel, output wire [DATA_WIDTH-1:0] rd_data, input wire [DATA_WIDTH-1:0] wr_data, input wire rd_en, input wire wr_en, output wire pdm_out, output wire gain_sel, output wire shutdown_n ); localparam CLOCK_DIV_WIDTH = 22; localparam AMP_WIDTH = 16; localparam TDRAU_REG_CTL = 0; /* control register */ localparam TDRAU_REG_CLK = 1; /* clock divider register */ localparam TDRAU_REG_AMP = 2; /* amplitude (volume) register */ wire audio_out; reg channel_enable; reg [CLOCK_DIV_WIDTH-1:0] clock_div; reg [CLOCK_DIV_WIDTH-1:0] div_count; reg amp_phase; reg [AMP_WIDTH-1:0] amp_start; reg [AMP_WIDTH-1:0] amp_out; reg [AMP_WIDTH:0] deltasigma_acc; assign pdm_out = audio_out; assign rd_data = {{DATA_WIDTH-8-CLOCK_DIV_WIDTH{1'b0}}, div_count, {7{1'b0}}, channel_enable}; assign gain_sel = 1; // gain select: 0 -> 12dB, 1 -> 6dB assign shutdown_n = channel_enable; /* channel enable flag */ always @(posedge clk) begin if(reset) channel_enable <= 0; else if (wr_en && (reg_sel == TDRAU_REG_CTL)) channel_enable <= wr_data[0]; end /* clock divider register */ always @(posedge clk) begin if(reset) clock_div <= 0; else if (wr_en && (reg_sel == TDRAU_REG_CLK)) clock_div <= wr_data; end /* amplitude register */ always @(posedge clk) begin if(reset) amp_start <= 0; else if (wr_en && (reg_sel == TDRAU_REG_AMP)) amp_start <= wr_data; end /* divider counter */ always @(posedge clk) begin if(channel_enable) begin if(div_count == 0) // reset counter if it reaches zero div_count <= clock_div; else div_count <= div_count - 1; // else just decrement it end else if (wr_en && (reg_sel == TDRAU_REG_CLK)) div_count <= 1; // start cycle in next clock tick end /* amplitude out */ always @(posedge clk) begin if (reset) begin amp_out <= 0; amp_phase <= 1; end else if (channel_enable && (div_count == 0)) // invert amplitude on clock tick begin amp_out <= amp_phase ? amp_start : ~amp_start; amp_phase <= ~amp_phase; end // reset phase bit when enabling the channel if (wr_en && (reg_sel == TDRAU_REG_CTL) && wr_data[0]) // when channel is enabled, phase will be flipped on next tick // because div_count will become zero amp_phase <= 1; end /* delta-sigma DAC */ always @(posedge clk) begin if(reset) deltasigma_acc <= 0; else if (channel_enable) deltasigma_acc <= deltasigma_acc[AMP_WIDTH-1:0] + amp_out; end /* 1-bit audio output */ assign audio_out = deltasigma_acc[AMP_WIDTH]; endmodule