145 lines
4.2 KiB
Verilog

// SPEECH 256
// Copyright (C) 2017 Niels Moseley / Moseley Instruments
// http://www.moseleyinstruments.com
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
//
// Second-order sigma-delta DAC
// The DAC has a pull interface.
//
// Number of input bits used: 12
//
// 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