From 7cc9ee807ddf9739e4db5769b8875bc8906a9826 Mon Sep 17 00:00:00 2001 From: slederer Date: Sat, 4 Oct 2025 00:09:10 +0200 Subject: [PATCH] tdraudio: remove pulse/noise waves, add sample buffer and irq --- tridoracpu/tridoracpu.srcs/irqctrl.v | 2 +- tridoracpu/tridoracpu.srcs/tdraudio.v | 167 ++++++++++++-------------- tridoracpu/tridoracpu.srcs/top.v | 22 ++-- tridoracpu/tridoracpu.xpr | 14 +-- 4 files changed, 98 insertions(+), 107 deletions(-) diff --git a/tridoracpu/tridoracpu.srcs/irqctrl.v b/tridoracpu/tridoracpu.srcs/irqctrl.v index 1a079bf..b71df60 100644 --- a/tridoracpu/tridoracpu.srcs/irqctrl.v +++ b/tridoracpu/tridoracpu.srcs/irqctrl.v @@ -1,6 +1,6 @@ `timescale 1ns / 1ps -module irqctrl #(IRQ_LINES = 2, IRQ_DELAY_WIDTH = 4) ( +module irqctrl #(IRQ_LINES = 3, IRQ_DELAY_WIDTH = 4) ( input wire clk, input wire [IRQ_LINES-1:0] irq_in, input wire cs, diff --git a/tridoracpu/tridoracpu.srcs/tdraudio.v b/tridoracpu/tridoracpu.srcs/tdraudio.v index cef16da..b9ecc94 100644 --- a/tridoracpu/tridoracpu.srcs/tdraudio.v +++ b/tridoracpu/tridoracpu.srcs/tdraudio.v @@ -1,6 +1,6 @@ `timescale 1ns / 1ps -// waveform generator module (pulse wave or noise) +// waveform generator module (PCM) module wavegen #(DATA_WIDTH=32, CLOCK_DIV_WIDTH=22, AMP_WIDTH=16, AMP_BIAS=32768) ( input wire clk, @@ -12,42 +12,78 @@ module wavegen #(DATA_WIDTH=32, CLOCK_DIV_WIDTH=22, input wire wr_en, output wire [AMP_WIDTH-1:0] amp_val, - output wire running + output wire running, + output wire irq ); localparam TDRAU_REG_CTL = 0; /* control register */ localparam TDRAU_REG_CLK = 1; /* clock divider register */ localparam TDRAU_REG_AMP = 2; /* amplitude (volume) register */ -// localparam LFSR_WIDTH = 18; -// localparam LFSR_TAP_IDX_1 = 17; -// localparam LFSR_TAP_IDX_2 = 10; -// localparam LFSR_INIT = 'h3CBE6; - - localparam LFSR_WIDTH = 23; - localparam LFSR_INIT = 'h1; - 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 noise_enable; - reg [LFSR_WIDTH-1:0] lfsr; - wire [AMP_WIDTH-1:0] noise_out; - reg direct_amp_enable; + wire fifo_wr_en; + wire fifo_rd_en, fifo_full, fifo_empty; + wire [DATA_WIDTH-1:0] fifo_rd_data; - //assign rd_data = {{DATA_WIDTH-8-CLOCK_DIV_WIDTH{1'b0}}, div_count, {7{1'b0}}, channel_enable}; - assign rd_data = {8'b0, amp_start, - {6{1'b0}}, amp_phase, channel_enable}; + fifo #(.ADDR_WIDTH(4), .DATA_WIDTH(16)) sample_buf( + clk, reset, + fifo_wr_en, fifo_rd_en, + wr_data, fifo_rd_data, + fifo_full, + fifo_empty + ); + + assign fifo_rd_en = (div_count == 0) && channel_enable && ~fifo_empty; + assign fifo_wr_en = wr_en && (reg_sel == TDRAU_REG_AMP); + + reg irq_buf, irq_done; + assign irq = irq_buf; + + reg [DATA_WIDTH-1:0] rd_data_buf; + assign rd_data = rd_data_buf; + // assign rd_data = {{DATA_WIDTH-8{1'b0}}, {4{1'b0}}, fifo_full, fifo_empty, amp_phase, channel_enable}; assign amp_val = amp_out; assign running = channel_enable; wire ctl_reg_write = wr_en && (reg_sel == TDRAU_REG_CTL); + /* update read data buffer */ + always @(posedge clk) + begin + rd_data_buf <= {{DATA_WIDTH-8{1'b0}}, {4{1'b0}}, fifo_full, fifo_empty, amp_phase, channel_enable}; + end + + /* irq signal to interrupt controller */ + always @(posedge clk) + begin + if(reset) + irq_buf <= 0; + else + if(fifo_empty && ~irq_done) + irq_buf <= 1; + else + irq_buf <= 0; + end + + /* interrupt done flag, used to ensure the irq signal is set for just one clock tick */ + always @(posedge clk) + begin + if(reset) + irq_done <= 0; + else + if(rd_en) // reset irq done flag on any register read + irq_done <= 0; + else + if(irq_buf) + irq_done <= 1; + end + /* channel enable flag */ always @(posedge clk) begin @@ -67,16 +103,6 @@ module wavegen #(DATA_WIDTH=32, CLOCK_DIV_WIDTH=22, 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 @@ -92,43 +118,6 @@ module wavegen #(DATA_WIDTH=32, CLOCK_DIV_WIDTH=22, div_count <= 1; // start cycle on next clock tick end - - /* noise enable flag */ - always @(posedge clk) - begin - if(reset) - noise_enable <= 0; - else if (ctl_reg_write) - noise_enable <= wr_data[1]; - end - - /* noise generator (Linear Feedback Shift Register) */ - always @(posedge clk) - begin - if (reset) - lfsr <= LFSR_INIT; - else - if (ctl_reg_write && wr_data[1]) - lfsr <= LFSR_INIT; - else - if (channel_enable && noise_enable) - if (div_count == 0) - //lfsr <= { lfsr[LFSR_TAP_IDX_1] ^ lfsr[LFSR_TAP_IDX_2], lfsr[LFSR_WIDTH-1:1] }; - // shift width and tap bits taken from https://github.com/jotego/jtopl - lfsr <= { lfsr[LFSR_WIDTH-2:0], lfsr[22] ^ lfsr[9] ^ lfsr[8] ^ lfsr[0]}; - end - - assign noise_out = lfsr[0] ? amp_start : ~amp_start; - - /* direct amplitude enable flag */ - always @(posedge clk) - begin - if(reset) - direct_amp_enable <= 0; - else if (ctl_reg_write) - direct_amp_enable <= wr_data[2]; - end - /* amplitude out */ always @(posedge clk) begin @@ -142,9 +131,7 @@ module wavegen #(DATA_WIDTH=32, CLOCK_DIV_WIDTH=22, begin if (div_count == 0) // invert amplitude on clock tick begin - amp_out <= direct_amp_enable ? amp_start : - noise_enable ? noise_out : - amp_phase ? amp_start : ~amp_start; + amp_out <= fifo_rd_data; amp_phase <= ~amp_phase; end end @@ -167,7 +154,7 @@ module tdraudio #(DATA_WIDTH=32) ( input wire [DATA_WIDTH-1:0] wr_data, input wire rd_en, input wire wr_en, - + output wire irq_out, output wire pdm_out, output wire gain_sel, output wire shutdown_n @@ -175,6 +162,7 @@ module tdraudio #(DATA_WIDTH=32) ( localparam CLOCK_DIV_WIDTH = 22; localparam AMP_WIDTH = 16; + localparam AMP_BIAS = 32768; localparam DAC_WIDTH = 18; wire [4:0] chan_sel = io_addr[6:2]; @@ -183,6 +171,7 @@ module tdraudio #(DATA_WIDTH=32) ( wire [AMP_WIDTH-1:0] chan0_amp; wire [DATA_WIDTH-1:0] chan0_rd_data; wire chan0_running; + wire chan0_irq; wire chan0_sel = chan_sel == 5'd0; wire chan0_rd_en = chan0_sel && rd_en; wire chan0_wr_en = chan0_sel && wr_en; @@ -190,6 +179,7 @@ module tdraudio #(DATA_WIDTH=32) ( wire [AMP_WIDTH-1:0] chan1_amp; wire [DATA_WIDTH-1:0] chan1_rd_data; wire chan1_running; + wire chan1_irq; wire chan1_sel = chan_sel == 5'd1; wire chan1_rd_en = chan1_sel && rd_en; wire chan1_wr_en = chan1_sel && wr_en; @@ -197,6 +187,7 @@ module tdraudio #(DATA_WIDTH=32) ( wire [AMP_WIDTH-1:0] chan2_amp; wire [DATA_WIDTH-1:0] chan2_rd_data; wire chan2_running; + wire chan2_irq; wire chan2_sel = chan_sel == 5'd2; wire chan2_rd_en = chan2_sel && rd_en; wire chan2_wr_en = chan2_sel && wr_en; @@ -204,14 +195,13 @@ module tdraudio #(DATA_WIDTH=32) ( wire [AMP_WIDTH-1:0] chan3_amp; wire [DATA_WIDTH-1:0] chan3_rd_data; wire chan3_running; + wire chan3_irq; wire chan3_sel = chan_sel == 5'd3; wire chan3_rd_en = chan3_sel && rd_en; wire chan3_wr_en = chan3_sel && wr_en; wire running = chan0_running || chan1_running || chan2_running || chan3_running; - reg was_running; - assign rd_data = chan0_sel ? chan0_rd_data : chan1_sel ? chan1_rd_data : chan2_sel ? chan2_rd_data : @@ -221,38 +211,38 @@ module tdraudio #(DATA_WIDTH=32) ( wavegen chan0(clk, reset, reg_sel, chan0_rd_data, wr_data, chan0_rd_en, chan0_wr_en, - chan0_amp, chan0_running); + chan0_amp, + chan0_running, chan0_irq); wavegen chan1(clk, reset, reg_sel, chan1_rd_data, wr_data, chan1_rd_en, chan1_wr_en, - chan1_amp, chan1_running); + chan1_amp, + chan1_running, chan1_irq); wavegen chan2(clk, reset, reg_sel, chan2_rd_data, wr_data, chan2_rd_en, chan2_wr_en, - chan2_amp, chan2_running); + chan2_amp, + chan2_irq, chan2_running); wavegen chan3(clk, reset, reg_sel, chan3_rd_data, wr_data, chan3_rd_en, chan3_wr_en, - chan3_amp, chan3_running); + chan3_amp, + chan3_running, chan3_irq); + + reg irq_out_buf; + assign irq_out = irq_out_buf; reg [DAC_WIDTH:0] deltasigma_acc; // one extra bit wire [DAC_WIDTH:0] amp_sum = chan0_amp + chan1_amp + chan2_amp + chan3_amp; // also one overflow bit here - //wire [AMP_WIDTH-1:0] amp_sum_scaled = amp_sum[DAC_WIDTH-2:2]; // shifted right to scale down assign gain_sel = 1; // gain select: 0 -> 12dB, 1 -> 6dB - assign shutdown_n = running; + // assign shutdown_n = running; + assign shutdown_n = 1; /* don't enable shutdown mode, it creates a mains hum */ - /* detect shutdown */ - always @(posedge clk) - begin - if (reset) - was_running <= 0; - else - was_running <= running; - end + always @(posedge clk) irq_out_buf <= chan0_irq || chan1_irq || chan2_irq || chan3_irq; /* delta-sigma DAC */ always @(posedge clk) @@ -260,11 +250,10 @@ module tdraudio #(DATA_WIDTH=32) ( if(reset) deltasigma_acc <= 0; else - if (running) +// if (running) deltasigma_acc <= deltasigma_acc[DAC_WIDTH-1:0] + amp_sum; - else - if (!running && was_running) // clear accumulator on shutdown - deltasigma_acc <= 0; +// else +// deltasigma_acc <= deltasigma_acc[DAC_WIDTH-1:0] + (4*AMP_BIAS); end /* 1-bit audio output */ diff --git a/tridoracpu/tridoracpu.srcs/top.v b/tridoracpu/tridoracpu.srcs/top.v index 4d0135e..6a70ef0 100644 --- a/tridoracpu/tridoracpu.srcs/top.v +++ b/tridoracpu/tridoracpu.srcs/top.v @@ -228,19 +228,12 @@ module top( assign uart_tx_data = mem_write_data[7:0]; assign uart_rd_data = { {WIDTH-10{1'b1}}, uart_rx_avail, uart_tx_busy, uart_rx_data }; - // interrupt controller - reg timer_tick; - reg[23:0] tick_count; - wire [1:0] irq_in = { timer_tick, uart_rx_avail }; - wire [1:0] irqc_rd_data0; - wire [WIDTH-1:0] irqc_rd_data = { tick_count, 6'b0, irqc_rd_data0 }; - wire irqc_seten = mem_write_data[7]; - wire irqc_cs = io_enable && (io_slot == 3); - + wire audio_irq; `ifdef ENABLE_TDRAUDIO wire [WIDTH-1:0] tdraudio_wr_data; wire [WIDTH-1:0] tdraudio_rd_data; wire tdraudio_rd_en, tdraudio_wr_en; + wire tdraudio_irq; wire tdraudio_cs_en = io_enable && (io_slot == 4); assign tdraudio_rd_en = tdraudio_cs_en && mem_read_enable; @@ -253,9 +246,20 @@ module top( tdraudio_wr_data, tdraudio_rd_en, tdraudio_wr_en, + tdraudio_irq, amp2_ain, amp2_gain, amp2_shutdown_n); + assign audio_irq = tdraudio_irq; `endif + // interrupt controller + reg timer_tick; + reg[23:0] tick_count; + wire [2:0] irq_in = { audio_irq, timer_tick, uart_rx_avail }; + wire [2:0] irqc_rd_data0; + wire [WIDTH-1:0] irqc_rd_data = { tick_count, 5'b0, irqc_rd_data0 }; + wire irqc_seten = mem_write_data[7]; + wire irqc_cs = io_enable && (io_slot == 3); + assign io_rd_data = (io_slot == 0) ? uart_rd_data : `ifdef ENABLE_MICROSD (io_slot == 1) ? spi_rd_data : diff --git a/tridoracpu/tridoracpu.xpr b/tridoracpu/tridoracpu.xpr index 15b43f2..3b60ca9 100644 --- a/tridoracpu/tridoracpu.xpr +++ b/tridoracpu/tridoracpu.xpr @@ -378,25 +378,23 @@ - + - - Uses multiple algorithms for optimization, placement, and routing to get potentially better results. + + Includes alternate algorithms for timing-driven optimization - - - + - + - +