mirror of
https://github.com/trcwm/Speech256.git
synced 2025-06-07 16:48:32 +02:00
Added 2nd order sigma-delta DAC. Added changes suggested by Clifford Wolf.
This commit is contained in:
parent
45afdd3500
commit
a2432a5e55
@ -75,16 +75,6 @@ set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SW[3]
|
||||
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SW[4]
|
||||
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SW[5]
|
||||
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to UART_TXD
|
||||
set_global_assignment -name PIN_FILE Speech256_de0.pin
|
||||
set_global_assignment -name VERILOG_FILE speech256_de0.v
|
||||
set_global_assignment -name VERILOG_FILE ../../verilog/controller/xlat.v
|
||||
set_global_assignment -name VERILOG_FILE ../../verilog/controller/ctrlrom.v
|
||||
set_global_assignment -name VERILOG_FILE ../../verilog/controller/controller.v
|
||||
set_global_assignment -name VERILOG_FILE ../../verilog/filter/filter.v
|
||||
set_global_assignment -name VERILOG_FILE ../../verilog/pwmdac/pwmdac.v
|
||||
set_global_assignment -name VERILOG_FILE ../../verilog/source/source.v
|
||||
set_global_assignment -name VERILOG_FILE ../../verilog/spmul/spmul.v
|
||||
set_global_assignment -name VERILOG_FILE ../../verilog/speech256_top/speech256_top.v
|
||||
set_location_assignment PIN_B1 -to LEDG[9]
|
||||
set_location_assignment PIN_B2 -to LEDG[8]
|
||||
set_location_assignment PIN_C2 -to LEDG[7]
|
||||
@ -337,4 +327,15 @@ set_location_assignment PIN_C3 -to DRAM_ADDR[3]
|
||||
set_location_assignment PIN_B3 -to DRAM_ADDR[2]
|
||||
set_location_assignment PIN_A3 -to DRAM_ADDR[1]
|
||||
set_location_assignment PIN_C4 -to DRAM_ADDR[0]
|
||||
set_global_assignment -name PIN_FILE Speech256_de0.pin
|
||||
set_global_assignment -name VERILOG_FILE speech256_de0.v
|
||||
set_global_assignment -name VERILOG_FILE ../../verilog/controller/xlat.v
|
||||
set_global_assignment -name VERILOG_FILE ../../verilog/controller/ctrlrom.v
|
||||
set_global_assignment -name VERILOG_FILE ../../verilog/controller/controller.v
|
||||
set_global_assignment -name VERILOG_FILE ../../verilog/filter/filter.v
|
||||
set_global_assignment -name VERILOG_FILE ../../verilog/pwmdac/pwmdac.v
|
||||
set_global_assignment -name VERILOG_FILE ../../verilog/source/source.v
|
||||
set_global_assignment -name VERILOG_FILE ../../verilog/spmul/spmul.v
|
||||
set_global_assignment -name VERILOG_FILE ../../verilog/sd2dac/sd2dac.v
|
||||
set_global_assignment -name VERILOG_FILE ../../verilog/speech256_top/speech256_top.v
|
||||
set_instance_assignment -name PARTITION_HIERARCHY root_partition -to | -section_id Top
|
@ -5,6 +5,8 @@
|
||||
// http://www.moseleyinstruments.com
|
||||
//
|
||||
|
||||
`define USE_SDDAC
|
||||
|
||||
module Speech256_DE0 (
|
||||
CLOCK_50,
|
||||
SW,
|
||||
@ -25,6 +27,10 @@ module Speech256_DE0 (
|
||||
reg [3:0] divcnt; // clock divider counter
|
||||
reg [2:0] cur_state, next_state;
|
||||
|
||||
reg [2:0] rom_addr;
|
||||
reg [5:0] rom_data;
|
||||
reg inc_rom_addr;
|
||||
|
||||
// debug signals for 16-bit DAC
|
||||
wire sample_stb;
|
||||
wire signed [15:0] sample_out;
|
||||
@ -36,7 +42,7 @@ module Speech256_DE0 (
|
||||
.clk (clk),
|
||||
.rst_an (rst_an),
|
||||
.ldq (ldq),
|
||||
.data_in (SW),
|
||||
.data_in (rom_data),
|
||||
.data_stb (data_stb),
|
||||
.pwm_out (UART_TXD),
|
||||
.sample_out (sample_out),
|
||||
@ -67,6 +73,8 @@ module Speech256_DE0 (
|
||||
always @(posedge clk)
|
||||
begin
|
||||
cur_state <= next_state;
|
||||
if (inc_rom_addr == 1)
|
||||
rom_addr <= rom_addr + 1;
|
||||
end
|
||||
|
||||
//assign LEDG[9:0] = sample_out[15:6];
|
||||
@ -74,18 +82,23 @@ module Speech256_DE0 (
|
||||
assign LEDG[1] = ldq;
|
||||
assign LEDG[2] = SW[2];
|
||||
assign LEDG[3] = SW[3];
|
||||
assign LEDG[4] = 0;
|
||||
|
||||
always @(*)
|
||||
begin
|
||||
// FSM defaults
|
||||
data_stb <= 0;
|
||||
inc_rom_addr <= 0;
|
||||
next_state <= cur_state;
|
||||
|
||||
case(cur_state)
|
||||
S_IDLE:
|
||||
begin
|
||||
if ((ldq == 1) && (BUTTON[0] == 1))
|
||||
begin
|
||||
inc_rom_addr <= 1;
|
||||
next_state <= S_ALLOPHONE;
|
||||
end
|
||||
else
|
||||
next_state <= S_IDLE;
|
||||
end
|
||||
@ -97,13 +110,45 @@ module Speech256_DE0 (
|
||||
S_WAITDONE:
|
||||
begin
|
||||
if (ldq == 0)
|
||||
begin
|
||||
inc_rom_addr <= 1;
|
||||
next_state <= S_IDLE;
|
||||
end
|
||||
end
|
||||
default:
|
||||
begin
|
||||
next_state <= S_IDLE;
|
||||
end
|
||||
endcase
|
||||
|
||||
// allophone ROM
|
||||
// hello, world
|
||||
case (rom_addr)
|
||||
3'd0:
|
||||
rom_data <= 6'h1B;
|
||||
3'd1:
|
||||
rom_data <= 6'h07;
|
||||
3'd2:
|
||||
rom_data <= 6'h2D;
|
||||
3'd3:
|
||||
rom_data <= 6'h35;
|
||||
3'd4:
|
||||
rom_data <= 6'h03;
|
||||
3'd5:
|
||||
rom_data <= 6'h2E;
|
||||
3'd6:
|
||||
rom_data <= 6'h1E;
|
||||
3'd7:
|
||||
rom_data <= 6'h33;
|
||||
3'd8:
|
||||
rom_data <= 6'h2D;
|
||||
3'd9:
|
||||
rom_data <= 6'h15;
|
||||
3'd10:
|
||||
rom_data <= 6'h03;
|
||||
default:
|
||||
rom_data <= 6'h00;
|
||||
endcase
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
@ -89,13 +89,13 @@ module CONTROLLER (
|
||||
.en (rom_en)
|
||||
);
|
||||
|
||||
parameter ROM_ADDR_ZERO = 3'b000, // zero the ROM address
|
||||
localparam ROM_ADDR_ZERO = 3'b000, // zero the ROM address
|
||||
ROM_ADDR_INC = 3'b001, // increment the ROM address
|
||||
ROM_ADDR_JMP = 3'b010, // jump to code
|
||||
ROM_ADDR_ALLO = 3'b011, // read allophone jump address
|
||||
ROM_ADDR_NOP = 3'b100;
|
||||
|
||||
parameter COEFF_CNT_ZERO = 2'b00, // zero coefficient counter
|
||||
localparam COEFF_CNT_ZERO = 2'b00, // zero coefficient counter
|
||||
COEFF_CNT_NOP = 2'b01, // do nothing
|
||||
COEFF_CNT_INC = 2'b10; // increment coefficient counter
|
||||
|
||||
@ -192,7 +192,7 @@ module CONTROLLER (
|
||||
|
||||
assign serve_next_allo_data = (dur_cnt == duration) ? 1 : 0;
|
||||
|
||||
parameter S_IDLE = 4'd0,
|
||||
localparam S_IDLE = 4'd0,
|
||||
S_JMPADDR1 = 4'd1,
|
||||
S_JMPADDR2 = 4'd2,
|
||||
S_JMPADDR3 = 4'd3,
|
||||
|
@ -20,6 +20,7 @@ module FILTER (
|
||||
start, // trigger processing of the input signal
|
||||
done // goes to '1' when sig_out has valid data
|
||||
);
|
||||
|
||||
parameter DEBUG = 0; //defult value
|
||||
|
||||
//////////// CLOCK //////////
|
||||
@ -179,7 +180,7 @@ module FILTER (
|
||||
end
|
||||
|
||||
// FSM states
|
||||
parameter S_IDLE = 4'b0000,
|
||||
localparam S_IDLE = 4'b0000,
|
||||
S_DUMMY1 = 4'b0001,
|
||||
S_WAITMUL1 = 4'b0010,
|
||||
S_UPDATEC1 = 4'b0011,
|
||||
|
6
verilog/sd2dac/run_tb.bat
Normal file
6
verilog/sd2dac/run_tb.bat
Normal file
@ -0,0 +1,6 @@
|
||||
mkdir bin
|
||||
del bin\sd2dac.vvp
|
||||
C:\iverilog\bin\iverilog -o bin\sd2dac.vvp -m va_math -g2005 -s SD2DAC_TB sd2dac.v sd2dac_tb.v
|
||||
cd bin
|
||||
C:\iverilog\bin\vvp sd2dac.vvp
|
||||
cd ..
|
132
verilog/sd2dac/sd2dac.v
Normal file
132
verilog/sd2dac/sd2dac.v
Normal file
@ -0,0 +1,132 @@
|
||||
//
|
||||
// Second-order sigma-delta DAC
|
||||
// The DAC has a pull interface.
|
||||
//
|
||||
// Number of input bits used: 12
|
||||
//
|
||||
// Niels Moseley - Moseley Instruments 2017
|
||||
// http://www.moseleyinstruments.com
|
||||
//
|
||||
//
|
||||
// Designed for a clock rate of 2.5 MHz
|
||||
//
|
||||
|
||||
module SD2DAC (
|
||||
clk,
|
||||
rst_an,
|
||||
din, // 16 bit signed data input
|
||||
din_ack, // is high for 1 clock cycle after reading the din signal
|
||||
dacout // 1-bit SD output signal
|
||||
);
|
||||
|
||||
|
||||
input signed [15:0] din;
|
||||
input rst_an, clk;
|
||||
output reg din_ack;
|
||||
output reg dacout;
|
||||
|
||||
reg [15:0] din_reg; // data input register
|
||||
reg [15:0] last_din; // previous input sample
|
||||
//reg [15:0] delta;
|
||||
|
||||
reg [7:0] counter; // sample counter
|
||||
reg signed [15:0] state1, state2; // integrator states
|
||||
reg signed [15:0] new_state1, new_state2;
|
||||
reg signed [15:0] state1_in, state2_in; // input to integrators
|
||||
wire signed [15:0] state1_a, state2_a; // output of integrator adders
|
||||
wire signed [16:0] quant_in;
|
||||
|
||||
reg quant_out;
|
||||
|
||||
always @(posedge clk or negedge rst_an)
|
||||
begin
|
||||
if (rst_an == 0)
|
||||
begin
|
||||
state1 <= 0;
|
||||
state2 <= 0;
|
||||
counter <= 0;
|
||||
din_reg <= 0;
|
||||
end
|
||||
else
|
||||
begin
|
||||
// clocked process
|
||||
state1 <= new_state1;
|
||||
state2 <= new_state2;
|
||||
dacout <= quant_out;
|
||||
counter <= counter + 1;
|
||||
if (din_ack == 1)
|
||||
begin
|
||||
last_din <= din_reg;
|
||||
din_reg <= {din[15], din[15:1]}; // div by 2!
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
assign state1_a = state1 + state1_in;
|
||||
assign state2_a = state2 + state2_in;
|
||||
assign quant_in = $signed( { {3{din_reg[15]}}, din_reg[15:2]} ) + state2;
|
||||
|
||||
always @(*)
|
||||
begin
|
||||
// ------------------------------
|
||||
// calculate new state 1
|
||||
// ------------------------------
|
||||
|
||||
if (quant_out == 1)
|
||||
// (din >> 2) - (quant_out >> 2)
|
||||
state1_in <= $signed( { {2{din_reg[15]}}, din_reg[15:2]} ) - $signed(16'h1FFF);
|
||||
else
|
||||
state1_in <= $signed( { {2{din_reg[15]}}, din_reg[15:2]} ) + $signed(16'h1FFF);
|
||||
|
||||
// check for saturation:
|
||||
// if operand sign bits are the same
|
||||
// the result should have the same
|
||||
// sign bit, if not, we need to
|
||||
// saturate.
|
||||
//
|
||||
// 1000 + 1111 => 1000 (-8 + -1 saturates at -8)
|
||||
// 0111 + 0001 => 0111 (7 + 1 saturates at 7)
|
||||
//
|
||||
if (state1[15] == state1_in[15])
|
||||
begin
|
||||
if (state1[15] != state1_a[15])
|
||||
new_state1 <= state1[15] ? 16'h8000 : 16'h7FFF;
|
||||
else
|
||||
new_state1 <= state1_a;
|
||||
end
|
||||
else
|
||||
new_state1 <= state1_a;
|
||||
|
||||
// ------------------------------
|
||||
// calculate new state 2
|
||||
// ------------------------------
|
||||
|
||||
if (quant_out == 1)
|
||||
// state1 - (quant_out >> 1)
|
||||
state2_in <= state1 - $signed(16'h3FFF);
|
||||
else
|
||||
state2_in <= state1 + $signed(16'h3FFF);
|
||||
|
||||
if (state2[15] == state2_in[15])
|
||||
begin
|
||||
if (state2[15] != state2_a[15])
|
||||
new_state2 <= state2[15] ? 16'h8000 : 16'h7FFF;
|
||||
else
|
||||
new_state2 <= state2_a;
|
||||
end
|
||||
else
|
||||
new_state2 <= state2_a;
|
||||
|
||||
// ------------------------------
|
||||
// calculate quantizer
|
||||
// ------------------------------
|
||||
|
||||
quant_out <= !quant_in[16];
|
||||
|
||||
if (counter == 8'h0)
|
||||
din_ack <= 1;
|
||||
else
|
||||
din_ack <= 0;
|
||||
end
|
||||
|
||||
endmodule
|
59
verilog/sd2dac/sd2dac_tb.v
Normal file
59
verilog/sd2dac/sd2dac_tb.v
Normal file
@ -0,0 +1,59 @@
|
||||
//
|
||||
// PWMDAC testbench
|
||||
//
|
||||
// Niels Moseley - Moseley Instruments 2017
|
||||
// http://www.moseleyinstruments.com
|
||||
//
|
||||
|
||||
module SD2DAC_TB;
|
||||
reg clk, rst_an;
|
||||
reg signed [15:0] din;
|
||||
wire dacout, din_ack;
|
||||
|
||||
real accu;
|
||||
|
||||
SD2DAC u_sd2dac (
|
||||
.clk (clk),
|
||||
.rst_an (rst_an),
|
||||
.din (din),
|
||||
.din_ack (din_ack),
|
||||
.dacout (dacout)
|
||||
);
|
||||
|
||||
integer fd;
|
||||
|
||||
initial
|
||||
begin
|
||||
fd = $fopen("dacout.sw","wb");
|
||||
$dumpfile ("sd2dac.vcd");
|
||||
$dumpvars;
|
||||
clk = 0;
|
||||
rst_an = 0;
|
||||
din = 0;
|
||||
accu = 0;
|
||||
#3
|
||||
rst_an = 1;
|
||||
#1048576
|
||||
$fclose(fd);
|
||||
$finish;
|
||||
end
|
||||
|
||||
always @(posedge clk)
|
||||
begin
|
||||
if (din_ack)
|
||||
begin
|
||||
accu = accu + 1.0/256.0;
|
||||
if (accu > 1.0)
|
||||
accu = -1.0;
|
||||
din = $rtoi($sin(2.0*3.1415927*accu)*10000.0);
|
||||
end
|
||||
if (dacout == 1)
|
||||
$fwrite(fd,"%u", 32'h7000_0000);
|
||||
else
|
||||
$fwrite(fd,"%u", 32'h9000_0000);
|
||||
end
|
||||
|
||||
always
|
||||
#5 clk = !clk;
|
||||
|
||||
endmodule
|
19
verilog/sd2dac/show_tb_results.m
Normal file
19
verilog/sd2dac/show_tb_results.m
Normal file
@ -0,0 +1,19 @@
|
||||
%
|
||||
% Show testbench results for sd2dac
|
||||
%
|
||||
% This is a MATLAB file
|
||||
%
|
||||
|
||||
fileID = fopen('bin/dacout.sw');
|
||||
A = fread(fileID,'*int32')';
|
||||
fclose(fileID);
|
||||
|
||||
A = single(A)/2^31;
|
||||
|
||||
clf;
|
||||
figure(1);
|
||||
X = fft(A.*blackman(length(A))') / (length(A)/4);
|
||||
semilogx(20*log10(abs(X)));
|
||||
grid on;
|
||||
axis([0 length(X)/2 -140 10]);
|
||||
|
@ -72,14 +72,23 @@ module SPEECH256_TOP (
|
||||
.done (src_strobe)
|
||||
);
|
||||
|
||||
`ifdef USE_SDDAC
|
||||
SD2DAC u_sd2dac (
|
||||
.clk (clk),
|
||||
.rst_an (rst_an),
|
||||
.din ($signed({sig_filter[11:0],4'h0})), // add +24dB gain .. FIXME: add saturation ??
|
||||
.din_ack (pwmdac_ack),
|
||||
.dacout (pwm_out)
|
||||
);
|
||||
`else
|
||||
PWMDAC u_pwmdac (
|
||||
.clk (clk),
|
||||
.rst_an (rst_an),
|
||||
//.din (sig_filter[15:8]),
|
||||
.din (sig_filter[11:4]), // add +24dB gain .. FIXME: add saturation ??
|
||||
.din_ack (pwmdac_ack),
|
||||
.dacout (pwm_out)
|
||||
);
|
||||
`endif
|
||||
|
||||
CONTROLLER u_controller (
|
||||
.clk (clk),
|
||||
|
Loading…
x
Reference in New Issue
Block a user