mirror of
https://github.com/mrehkopf/sd2snes.git
synced 2026-01-11 14:29:25 +01:00
292 lines
7.1 KiB
Verilog
292 lines
7.1 KiB
Verilog
`timescale 1ns / 1ps
|
|
//////////////////////////////////////////////////////////////////////////////////
|
|
// Company:
|
|
// Engineer:
|
|
//
|
|
// Create Date: 19:26:11 07/23/2010
|
|
// Design Name:
|
|
// Module Name: dac_test
|
|
// Project Name:
|
|
// Target Devices:
|
|
// Tool versions:
|
|
// Description:
|
|
//
|
|
// Dependencies:
|
|
//
|
|
// Revision:
|
|
// Revision 0.01 - File Created
|
|
// Additional Comments:
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////////
|
|
`include "config.vh"
|
|
|
|
module dac(
|
|
input clkin,
|
|
input sysclk,
|
|
input we,
|
|
input[10:0] pgm_address,
|
|
input[7:0] pgm_data,
|
|
input[7:0] volume,
|
|
input vol_latch,
|
|
input [2:0] vol_select,
|
|
input [8:0] dac_address_ext,
|
|
input play,
|
|
input reset,
|
|
input palmode,
|
|
output sdout,
|
|
output mclk_out,
|
|
output lrck_out,
|
|
output sclk_out,
|
|
output DAC_STATUS
|
|
);
|
|
|
|
reg[8:0] dac_address_r;
|
|
reg[8:0] dac_address_r_sync;
|
|
wire[8:0] dac_address = dac_address_r_sync;
|
|
|
|
wire[31:0] dac_data;
|
|
assign DAC_STATUS = dac_address_r[8];
|
|
reg[10:0] vol_reg;
|
|
reg[10:0] vol_target_reg;
|
|
reg[1:0] vol_latch_reg;
|
|
reg vol_valid;
|
|
reg[2:0] sysclk_sreg;
|
|
wire sysclk_rising = (sysclk_sreg[2:1] == 2'b01);
|
|
|
|
always @(posedge clkin) begin
|
|
sysclk_sreg <= {sysclk_sreg[1:0], sysclk};
|
|
end
|
|
|
|
`ifdef MK2
|
|
`ifndef DEBUG
|
|
dac_buf snes_dac_buf (
|
|
.clka(clkin),
|
|
.wea(~we), // Bus [0 : 0]
|
|
.addra(pgm_address), // Bus [10 : 0]
|
|
.dina(pgm_data), // Bus [7 : 0]
|
|
.clkb(clkin),
|
|
.addrb(dac_address), // Bus [8 : 0]
|
|
.doutb(dac_data)); // Bus [31 : 0]
|
|
`endif
|
|
`endif
|
|
|
|
`ifdef MK3
|
|
dac_buf snes_dac_buf (
|
|
.clock(clkin),
|
|
.wren(~we), // Bus [0 : 0]
|
|
.wraddress(pgm_address), // Bus [10 : 0]
|
|
.data(pgm_data), // Bus [7 : 0]
|
|
.rdaddress(dac_address), // Bus [8 : 0]
|
|
.q(dac_data)); // Bus [31 : 0]
|
|
`endif
|
|
|
|
reg [10:0] cnt;
|
|
reg [15:0] smpcnt;
|
|
reg [1:0] samples;
|
|
reg [15:0] smpshift;
|
|
|
|
wire mclk = cnt[2]; // mclk = clk/8
|
|
wire lrck = cnt[8]; // lrck = mclk/64
|
|
wire sclk = cnt[3]; // sclk = lrck*32
|
|
|
|
reg [2:0] mclk_sreg;
|
|
reg [2:0] lrck_sreg;
|
|
reg [1:0] sclk_sreg;
|
|
|
|
assign mclk_out = ~mclk_sreg[2];
|
|
assign lrck_out = lrck_sreg[2];
|
|
assign sclk_out = sclk_sreg[1];
|
|
|
|
wire lrck_rising = ({lrck_sreg[0],lrck} == 2'b01);
|
|
wire lrck_falling = ({lrck_sreg[0],lrck} == 2'b10);
|
|
|
|
wire sclk_rising = ({sclk_sreg[0],sclk} == 2'b01);
|
|
wire sclk_falling = ({sclk_sreg[0],sclk} == 2'b10);
|
|
|
|
wire vol_latch_rising = (vol_latch_reg[1:0] == 2'b01);
|
|
reg sdout_reg;
|
|
assign sdout = sdout_reg;
|
|
|
|
reg play_r;
|
|
|
|
initial begin
|
|
cnt = 9'h100;
|
|
smpcnt = 16'b0;
|
|
lrck_sreg = 2'b00;
|
|
sclk_sreg = 2'b00;
|
|
mclk_sreg = 2'b00;
|
|
dac_address_r = 9'b0;
|
|
vol_valid = 1'b0;
|
|
vol_latch_reg = 1'b0;
|
|
vol_reg = 9'h000;
|
|
vol_target_reg = 9'h000;
|
|
samples <= 2'b00;
|
|
end
|
|
|
|
/*
|
|
21477272.727272... / 37500 * 1232 = 44100 * 16
|
|
21281370 / 709379 * 23520 = 44100 * 16
|
|
*/
|
|
reg [19:0] phaseacc = 0;
|
|
wire [14:0] phasemul = (palmode ? 23520 : 1232);
|
|
wire [19:0] phasediv = (palmode ? 709379 : 37500);
|
|
reg [3:0] subcount = 0;
|
|
|
|
reg int_strobe = 0, comb_strobe = 0;
|
|
|
|
always @(posedge clkin) begin
|
|
int_strobe <= 0;
|
|
comb_strobe <= 0;
|
|
if(reset) begin
|
|
dac_address_r <= dac_address_ext;
|
|
phaseacc <= 0;
|
|
subcount <= 0;
|
|
end else if(sysclk_rising) begin
|
|
if(phaseacc >= phasediv) begin
|
|
phaseacc <= phaseacc - phasediv + phasemul;
|
|
subcount <= subcount + 1;
|
|
int_strobe <= 1;
|
|
if (subcount == 0) begin
|
|
comb_strobe <= 1;
|
|
dac_address_r <= dac_address_r + play_r;
|
|
end
|
|
end else begin
|
|
phaseacc <= phaseacc + phasemul;
|
|
end
|
|
end
|
|
end
|
|
|
|
parameter ST0_IDLE = 10'b1000000000;
|
|
parameter ST1_COMB1 = 10'b0000000001;
|
|
parameter ST2_COMB2 = 10'b0000000010;
|
|
parameter ST3_COMB3 = 10'b0000000100;
|
|
parameter ST4_INT1 = 10'b0000010000;
|
|
parameter ST5_INT2 = 10'b0000100000;
|
|
parameter ST6_INT3 = 10'b0001000000;
|
|
|
|
reg [63:0] ci[2:0], co[2:0], io[2:0];
|
|
reg [9:0] cicstate = 10'h200;
|
|
wire [63:0] bufi = {{16{dac_data[31]}}, dac_data[31:16], {16{dac_data[15]}}, dac_data[15:0]};
|
|
|
|
always @(posedge clkin) begin
|
|
if(reset) begin
|
|
cicstate <= ST0_IDLE;
|
|
{ci[2], ci[1], ci[0]} <= 192'h0;
|
|
{co[2], co[1], co[0]} <= 192'h0;
|
|
{io[2], io[1], io[0]} <= 192'h0;
|
|
end else if(int_strobe) begin
|
|
if(comb_strobe) cicstate <= ST1_COMB1;
|
|
else cicstate <= ST4_INT1;
|
|
end else begin
|
|
case(cicstate)
|
|
/****** COMB STAGES ******/
|
|
ST1_COMB1: begin
|
|
cicstate <= ST2_COMB2;
|
|
ci[0] <= bufi;
|
|
co[0][63:32] <= bufi[63:32] - ci[0][63:32];
|
|
co[0][31:0] <= bufi[31:0] - ci[0][31:0];
|
|
end
|
|
ST2_COMB2: begin
|
|
cicstate <= ST3_COMB3;
|
|
ci[1] <= co[0];
|
|
co[1][63:32] <= co[0][63:32] - ci[1][63:32];
|
|
co[1][31:0] <= co[0][31:0] - ci[1][31:0];
|
|
end
|
|
ST3_COMB3: begin
|
|
cicstate <= ST4_INT1;
|
|
ci[2] <= co[1];
|
|
co[2][63:32] <= co[1][63:32] - ci[2][63:32];
|
|
co[2][31:0] <= co[1][31:0] - ci[2][31:0];
|
|
end
|
|
/****** INTEGRATOR STAGES ******/
|
|
ST4_INT1: begin
|
|
io[0][63:32] <= co[2][63:32] + io[0][63:32];
|
|
io[0][31:0] <= co[2][31:0] + io[0][31:0];
|
|
cicstate <= ST5_INT2;
|
|
end
|
|
ST5_INT2: begin
|
|
io[1][63:32] <= io[0][63:32] + io[1][63:32];
|
|
io[1][31:0] <= io[0][31:0] + io[1][31:0];
|
|
cicstate <= ST6_INT3;
|
|
end
|
|
ST6_INT3: begin
|
|
io[2][63:32] <= io[1][63:32] + io[2][63:32];
|
|
io[2][31:0] <= io[1][31:0] + io[2][31:0];
|
|
cicstate <= ST0_IDLE;
|
|
end
|
|
default: begin
|
|
cicstate <= ST0_IDLE;
|
|
end
|
|
endcase
|
|
end
|
|
end
|
|
|
|
always @(posedge clkin) begin
|
|
cnt <= cnt + 1;
|
|
mclk_sreg <= {mclk_sreg[1:0], mclk};
|
|
lrck_sreg <= {lrck_sreg[1:0], lrck};
|
|
sclk_sreg <= {sclk_sreg[0], sclk};
|
|
vol_latch_reg <= {vol_latch_reg[0], vol_latch};
|
|
play_r <= play;
|
|
end
|
|
|
|
wire [9:0] vol_orig = volume + volume[7];
|
|
wire [9:0] vol_3db = volume + volume[7:1] + volume[7];
|
|
wire [9:0] vol_6db = {1'b0, volume, volume[7]} + volume[7];
|
|
wire [9:0] vol_9db = {1'b0, volume, 1'b0} + volume + volume[7:6];
|
|
wire [9:0] vol_12db = {volume, volume[7:6]};
|
|
|
|
reg [9:0] vol_scaled;
|
|
always @* begin
|
|
case(vol_select)
|
|
3'b000: vol_scaled = vol_orig;
|
|
3'b001: vol_scaled = vol_3db;
|
|
3'b010: vol_scaled = vol_6db;
|
|
3'b011: vol_scaled = vol_9db;
|
|
3'b100: vol_scaled = vol_12db;
|
|
default: vol_scaled = vol_orig;
|
|
endcase
|
|
end
|
|
|
|
always @(posedge clkin) begin
|
|
vol_target_reg <= vol_scaled;
|
|
end
|
|
|
|
always @(posedge clkin) begin
|
|
if (lrck_rising) begin
|
|
dac_address_r_sync <= dac_address_r;
|
|
end
|
|
end
|
|
|
|
// ramp volume only on sample boundaries
|
|
always @(posedge clkin) begin
|
|
if (lrck_rising) begin
|
|
if(vol_reg > vol_target_reg)
|
|
vol_reg <= vol_reg - 1;
|
|
else if(vol_reg < vol_target_reg)
|
|
vol_reg <= vol_reg + 1;
|
|
end
|
|
end
|
|
|
|
wire signed [15:0] dac_data_ch = lrck ? io[2][59:44] : io[2][27:12];
|
|
wire signed [25:0] vol_sample;
|
|
wire signed [15:0] vol_sample_sat;
|
|
assign vol_sample = dac_data_ch * $signed({1'b0, vol_reg});
|
|
assign vol_sample_sat = ((vol_sample[25:23] == 3'b000 || vol_sample[25:23] == 3'b111) ? vol_sample[23:8]
|
|
: vol_sample[25] ? 16'sh8000
|
|
: 16'sh7fff);
|
|
|
|
always @(posedge clkin) begin
|
|
if (sclk_falling) begin
|
|
smpcnt <= smpcnt + 1;
|
|
sdout_reg <= smpshift[15];
|
|
if (lrck_rising | lrck_falling) begin
|
|
smpshift <= vol_sample_sat;
|
|
end else begin
|
|
smpshift <= {smpshift[14:0], 1'b0};
|
|
end
|
|
end
|
|
end
|
|
|
|
endmodule
|