Skip to content

Commit

Permalink
Fix waveform 6, add reset to envelope state, drop out fixes in ao486 (#…
Browse files Browse the repository at this point in the history
…40)

* change ip for make program

* upgrade command in make program

* add make program to top level makefile

* fix for waveform 6

* reset env state so music stops after reset

* fixed ws6, re-added edge detection to writes

* add to gitignore

* backport fixes from ao486
  • Loading branch information
gtaylormb authored May 17, 2024
1 parent 3e15de8 commit b18113a
Show file tree
Hide file tree
Showing 17 changed files with 238 additions and 47 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,4 @@ fpga/NA/ps7_summary.html
.vscode/
.project
fpga/vsim.wlf
fpga/modules/operator/vsim.wlf
3 changes: 3 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -75,3 +75,6 @@ clean:

BOOT.bin:
bootgen -image software/bif/imfplay_port.bif -arch zynq -o BOOT.bin -w on

program:
cd fpga && make program
1 change: 1 addition & 0 deletions fpga/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ RTL_SRC = \
modules/misc/src/edge_detector.sv \
modules/misc/src/mem_simple_dual_port.sv \
modules/misc/src/mem_multi_bank.sv \
modules/misc/src/mem_multi_bank_reset.sv \
modules/misc/src/pipeline_sr.sv \
modules/misc/src/synchronizer.sv \
modules/misc/src/leds.sv \
Expand Down
1 change: 1 addition & 0 deletions fpga/modules/channels/src/channels.sv
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ module channels
import opl3_pkg::*;
(
input wire clk,
input wire reset,
input wire clk_dac,
input var opl3_reg_wr_t opl3_reg_wr,
input wire sample_clk_en,
Expand Down
1 change: 1 addition & 0 deletions fpga/modules/channels/src/control_operators.sv
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ module control_operators
import opl3_pkg::*;
(
input wire clk,
input wire reset,
input wire sample_clk_en,
input var opl3_reg_wr_t opl3_reg_wr,
input wire [REG_CONNECTION_SEL_WIDTH-1:0] connection_sel,
Expand Down
12 changes: 9 additions & 3 deletions fpga/modules/host_if/src/host_if.sv
Original file line number Diff line number Diff line change
Expand Up @@ -66,14 +66,17 @@ module host_if
logic [1:0] opl3_address;
logic [REG_FILE_DATA_WIDTH-1:0] opl3_data;
logic wr_p1;
logic wr_p2 = 0;
logic [REG_FILE_DATA_WIDTH-1:0] host_status;
logic [REG_FILE_DATA_WIDTH-1:0] host_status_p1 = 0;

// relax timing on clk_host
always_ff @(posedge clk_host) begin
cs_p1_n <= cs_n;
wr_p1_n <= wr_n;
address_p1 <= address;
din_p1 <= din;
wr_p2 <= wr_p1;
end

always_comb wr_p1 = !cs_p1_n && !wr_p1_n;
Expand All @@ -84,7 +87,7 @@ module host_if
) afifo (
.i_wclk(clk_host),
.i_wr_reset_n(ic_n),
.i_wr(wr_p1),
.i_wr(wr_p1 && !wr_p2),
.i_wr_data({address_p1, din_p1}),
.o_wr_full(),
.i_rclk(clk),
Expand Down Expand Up @@ -120,10 +123,13 @@ module host_if
.out(host_status)
);

always_ff @(posedge clk_host)
host_status_p1 <= host_status;

// Doom DMXOPTION=-opl3-phase detection routine specifically reads address 'b10 to see if it's all ones
// Decompiled routine provided by Never_Again at https://www.vogons.org/viewtopic.php?f=7&t=100285
always_ff @(posedge clk_host)
dout <= address_p1 == 0 ? host_status : '1;
always_comb
dout = address_p1 == 0 ? host_status_p1 : '1;

generate
if (INSTANTIATE_TIMERS)
Expand Down
4 changes: 3 additions & 1 deletion fpga/modules/host_if/src/trick_sw_detection.sv
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ module trick_sw_detection
logic [1:0] address_p1 = 0;
logic [REG_FILE_DATA_WIDTH-1:0] din_p1 = 0;
logic wr_p1;
logic wr_p2 = 0;
logic [$clog2(NUM_READS_TO_TRIGGER_OVERFLOW)-1:0] host_rd_counter = 0;
opl3_reg_wr_t host_reg_wr;
logic rd_p1;
Expand All @@ -100,14 +101,15 @@ module trick_sw_detection
rd_p1_n <= rd_n;
address_p1 <= address;
din_p1 <= din;
wr_p2 <= wr_p1;
end

always_comb wr_p1 = !cs_p1_n && !wr_p1_n;

always_ff @(posedge clk_host) begin
host_reg_wr.valid <= 0;

if (wr_p1)
if (wr_p1 && !wr_p2)
if (!address_p1[0]) begin // address write mode
host_reg_wr.bank_num <= address_p1[1];
host_reg_wr.address <= din_p1;
Expand Down
165 changes: 165 additions & 0 deletions fpga/modules/misc/src/mem_multi_bank_reset.sv
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
/*******************************************************************************
# +html+<pre>
#
# FILENAME: mem_multi_bank_reset.sv
# AUTHOR: Greg Taylor CREATION DATE: 16 May 2024
#
# DESCRIPTION:
#
# CHANGE HISTORY:
# 16 May 2024 Greg Taylor
# Initial version
#
# Copyright (C) 2014 Greg Taylor <[email protected]>
#
# This file is part of OPL3 FPGA.
#
# OPL3 FPGA is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# OPL3 FPGA 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with OPL3 FPGA. If not, see <http://www.gnu.org/licenses/>.
#
# Original Java Code:
# Copyright (C) 2008 Robson Cozendey <[email protected]>
#
# Original C++ Code:
# Copyright (C) 2012 Steffen Ohrendorf <[email protected]>
#
# Some code based on forum posts in:
# http://forums.submarine.org.uk/phpBB/viewforum.php?f=9,
# Copyright (C) 2010-2013 by carbon14 and opl3
#
#******************************************************************************/
`timescale 1ns / 1ps
`default_nettype none

module mem_multi_bank_reset #(
parameter DATA_WIDTH = 0,
parameter DEPTH = 0,
parameter OUTPUT_DELAY = 0, // 0, 1, or 2
parameter DEFAULT_VALUE = '0,
parameter NUM_BANKS = 0,
parameter BANK_WIDTH = $clog2(NUM_BANKS)
) (
input wire clk,
input wire reset,
input wire reset_mem,
input wire wea,
input wire reb, // only used if OUTPUT_DELAY >0
input wire [BANK_WIDTH-1:0] banka,
input wire [$clog2(DEPTH)-1:0] addra,
input wire [BANK_WIDTH-1:0] bankb,
input wire [$clog2(DEPTH)-1:0] addrb,
input wire [DATA_WIDTH-1:0] dia,
output logic [DATA_WIDTH-1:0] dob,
output logic reset_mem_done_pulse
);
localparam PIPELINE_DELAY = 2;

logic [NUM_BANKS-1:0] wea_array;
logic [NUM_BANKS-1:0] reb_array;
logic [DATA_WIDTH-1:0] dob_array [NUM_BANKS];
logic [PIPELINE_DELAY:1] [BANK_WIDTH-1:0] bankb_p;

enum {
IDLE,
RESETTING
} state = IDLE, next_state;

struct packed {
logic [BANK_WIDTH-1:0] bank;
logic [$clog2(DEPTH)-1:0] addr;
logic reset_mem_done;
} self = 0, next_self;

pipeline_sr #(
.DATA_WIDTH(BANK_WIDTH),
.ENDING_CYCLE(PIPELINE_DELAY)
) bankb_sr (
.clk,
.in(bankb),
.out(bankb_p)
);

always_ff @(posedge clk) begin
state <= next_state;
self <= next_self;

if (reset) begin
state <= IDLE;
self <= 0;
end
end

always_comb begin
next_state = state;
next_self = self;

unique case (state)
IDLE: begin
if (reset_mem)
next_state = RESETTING;
next_self = 0;
end
RESETTING: begin
if (self.addr == DEPTH - 1) begin
next_self.addr = 0;
if (self.bank == NUM_BANKS - 1) begin
next_state = IDLE;
next_self.reset_mem_done = 1;
end
else
next_self.bank = self.bank + 1;
end
else
next_self.addr = self.addr + 1;
end
endcase
end

always_comb reset_mem_done_pulse = self.reset_mem_done;

generate
genvar i;
for (i = 0; i < NUM_BANKS; ++i) begin: bankgen
always_comb begin
if (state == RESETTING)
wea_array[i] = self.bank == i;
else
wea_array[i] = wea && banka == i;

reb_array[i] = reb && bankb == i;
end

mem_simple_dual_port #(
.DATA_WIDTH(DATA_WIDTH),
.DEPTH(DEPTH),
.OUTPUT_DELAY(OUTPUT_DELAY),
.DEFAULT_VALUE(DEFAULT_VALUE)
) mem_bank (
.clka(clk),
.clkb(clk),
.wea(wea_array[i]),
.reb(reb_array[i]),
.addra(state == RESETTING ? self.addr : addra),
.addrb,
.dia(state == RESETTING ? DEFAULT_VALUE : dia),
.dob(dob_array[i])
);
end

if (OUTPUT_DELAY == 0)
always_comb dob = dob_array[bankb];
else
always_comb dob = dob_array[bankb_p[OUTPUT_DELAY]];
endgenerate
endmodule
`default_nettype wire
3 changes: 2 additions & 1 deletion fpga/modules/operator/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ RTL_SRC = \
../misc/src/edge_detector.sv \
../misc/src/mem_simple_dual_port.sv \
../misc/src/mem_multi_bank.sv \
../misc/src/mem_multi_bank_reset.sv \
../misc/src/pipeline_sr.sv

SIM_SRC = \
Expand All @@ -26,7 +27,7 @@ compile:
vlog -incr $(SIM_SRC) $(RTL_SRC)

sim: compile
vsim -c operator_tb -do "run all"
vsim -c operator_tb -do "run -a"

sim-debug: compile
vsim operator_tb -voptargs=+acc
Expand Down
46 changes: 23 additions & 23 deletions fpga/modules/operator/analysis/dac_input_analysis.m
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
if (max(code)>2^numbit-1) | (min(code)<0)
disp('Warning: ADC may be clipping!!!');
end

code = typecast(uint16(code), 'int16');

%Plot results in the time domain
Expand Down Expand Up @@ -73,7 +73,7 @@
%Find DC offset power
Pdc=sum(spectP(1:span));
%Extract overall signal power
Ps=sum(spectP(fin-span:fin+span));
%Ps=sum(spectP(fin-span:fin+span));
%Vector/matrix to store both frequency and power of signal and harmonics
Fh=[];
%The 1st element in the vector/matrix represents the signal, the next element represents
Expand All @@ -91,47 +91,47 @@
Fh=[Fh tone];
%For this procedure to work, ensure the folded back high order harmonics do not overlap
%with DC or signal or lower order harmonics
har_peak=max(spectP(round(tone*numpt)-spanh:round(tone*numpt)+spanh));
har_bin=find(spectP(round(tone*numpt)-spanh:round(tone*numpt)+spanh)==har_peak);
har_bin=har_bin+round(tone*numpt)-spanh-1;
Ph=[Ph sum(spectP(har_bin-1:har_bin+1))];
%har_peak=max(spectP(round(tone*numpt)-spanh:round(tone*numpt)+spanh));
%har_bin=find(spectP(round(tone*numpt)-spanh:round(tone*numpt)+spanh)==har_peak);
%har_bin=har_bin+round(tone*numpt)-spanh-1;
%Ph=[Ph sum(spectP(har_bin-1:har_bin+1))];
end

%Determine the total distortion power
Pd=sum(Ph(2:5));
%Pd=sum(Ph(2:5));
%Determine the noise power
Pn=sum(spectP(1:numpt/2))-Pdc-Ps-Pd;
%Pn=sum(spectP(1:numpt/2))-Pdc-Ps-Pd;

format;
A=(max(code)-min(code))/2^numbit
AdB=20*log10(A)
SINAD=10*log10(Ps/(Pn+Pd))
SNR=10*log10(Ps/Pn)
%SINAD=10*log10(Ps/(Pn+Pd))
%SNR=10*log10(Ps/Pn)
disp('THD is calculated from 2nd through 5th order harmonics');
THD=10*log10(Pd/Ph(1))
%THD=10*log10(Pd/Ph(1))

%SFDR=10*log10(Ph(1)/max(Ph(2:10)))
% GHT: this doesn't capture all spurs, so it isn't accurate

% Instead subtract the highest spur from the fundamental frequency
%[pks, locs] = findpeaks(Dout_dB(1:numpt/2), 'NPEAKS', 10, 'SORTSTR', 'descend');

% Octave findpeaks function doesn't match Matlabs, must rewrite
[pks, locs] = findpeaks(Dout_dB(1:numpt/2), "MinPeakHeight", 80);
pks = sort(pks, "descend");
%[pks, locs] = findpeaks(Dout_dB(1:numpt/2), "MinPeakHeight", 80);
%pks = sort(pks, "descend");

% pks = -(pks(1) - pks(1:10));
% locs = locs/numpt*fclk;
fundamental = pks(1);
first_spur = pks(2);
SFDR = fundamental - first_spur
%fundamental = pks(1);
%first_spur = pks(2);
%SFDR = fundamental - first_spur
%peaks = [pks, locs]
disp('Signal & Harmonic Power Components:');
HD=10*log10(Ph(1:10)/Ph(1))

%disp('Signal & Harmonic Power Components:');
%HD=10*log10(Ph(1:10)/Ph(1))

%Distinguish all harmonics locations within the FFT plot
hold on;
plot(Fh(2)*fclk,0,'mo',Fh(3)*fclk,0,'cx',Fh(4)*fclk,0,'r+',Fh(5)*fclk,0,'g*',Fh(6)*fclk,0,'bs',Fh(7)*fclk,0,'bd',Fh(8)*fclk,0,'kv',Fh(9)*fclk,0,'y^');
legend('1st','2nd','3rd','4th','5th','6th','7th','8th','9th');
hold off;
hold off;
Loading

0 comments on commit b18113a

Please sign in to comment.