Skip to content

Commit

Permalink
Refactor envelope to match Nuked OPL3 C++ implementation (#49)
Browse files Browse the repository at this point in the history
* initial refactor. Broken, getting some sound

* fixed attack

* fixed attack

* fix rate shift

* minor cleanup phase_gen

* remove env clamp, level gets clamped later

* reduced eg_timer to 13 bits, no need for nuke's 36

* rename env_rate_counter to calc_envelope_shift

* update readme
  • Loading branch information
gtaylormb authored Jun 19, 2024
1 parent ad3153f commit 5f0e3f6
Show file tree
Hide file tree
Showing 10 changed files with 384 additions and 441 deletions.
14 changes: 7 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,13 +95,13 @@ Close up of the attack phase:
+----------------------------+------+-------+------------+-----------+-------+
| Site Type | Used | Fixed | Prohibited | Available | Util% |
+----------------------------+------+-------+------------+-----------+-------+
| Slice LUTs | 1256 | 0 | 0 | 17600 | 7.14 |
| LUT as Logic | 1014 | 0 | 0 | 17600 | 5.76 |
| LUT as Memory | 242 | 0 | 0 | 6000 | 4.03 |
| LUT as Distributed RAM | 192 | 0 | | | |
| LUT as Shift Register | 50 | 0 | | | |
| Slice Registers | 1106 | 0 | 0 | 35200 | 3.14 |
| Register as Flip Flop | 1106 | 0 | 0 | 35200 | 3.14 |
| Slice LUTs | 1164 | 0 | 0 | 17600 | 6.61 |
| LUT as Logic | 967 | 0 | 0 | 17600 | 5.49 |
| LUT as Memory | 197 | 0 | 0 | 6000 | 3.28 |
| LUT as Distributed RAM | 144 | 0 | | | |
| LUT as Shift Register | 53 | 0 | | | |
| Slice Registers | 1102 | 0 | 0 | 35200 | 3.13 |
| Register as Flip Flop | 1102 | 0 | 0 | 35200 | 3.13 |
| Register as Latch | 0 | 0 | 0 | 35200 | 0.00 |
| F7 Muxes | 9 | 0 | 0 | 8800 | 0.10 |
| F8 Muxes | 1 | 0 | 0 | 4400 | 0.02 |
Expand Down
2 changes: 1 addition & 1 deletion fpga/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ RTL_SRC = \
modules/operator/src/vibrato.sv \
modules/operator/src/envelope_generator.sv \
modules/operator/src/ksl_add_rom.sv \
modules/operator/src/env_rate_counter.sv \
modules/operator/src/calc_envelope_shift.sv \
modules/operator/src/tremolo.sv \
modules/operator/src/opl3_log_sine_lut.sv \
modules/operator/src/opl3_exp_lut.sv \
Expand Down
2 changes: 1 addition & 1 deletion fpga/modules/operator/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ RTL_SRC = \
src/opl3_exp_lut.sv \
src/vibrato.sv \
src/envelope_generator.sv \
src/env_rate_counter.sv \
src/calc_envelope_shift.sv \
src/ksl_add_rom.sv \
src/tremolo.sv \
../clks/src/clk_div.sv \
Expand Down
6 changes: 3 additions & 3 deletions fpga/modules/operator/sim/operator_tb.sv
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ module operator_tb
bit [REG_MULT_WIDTH-1:0] mult = 5;
bit [REG_BLOCK_WIDTH-1:0] block = 4;

bit [REG_WS_WIDTH-1:0] ws = 7;
bit [REG_WS_WIDTH-1:0] ws = 0;
bit vib = 0;
bit dvb = 0;
bit kon = 0;
Expand Down Expand Up @@ -86,8 +86,8 @@ module operator_tb
bit [REG_FB_WIDTH-1:0] fb_p1 = 0;
bit signed [OP_OUT_WIDTH-1:0] modulation_p1 = 0;

bit [BANK_NUM_WIDTH-1:0] bank_num = 12;
bit [OP_NUM_WIDTH-1:0] op_num = 12;
bit [BANK_NUM_WIDTH-1:0] bank_num = 1;
bit [OP_NUM_WIDTH-1:0] op_num = 17;

always begin
#CLK_HALF_PERIOD clk = 0;
Expand Down
199 changes: 199 additions & 0 deletions fpga/modules/operator/src/calc_envelope_shift.sv
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
/*******************************************************************************
# +html+<pre>
#
# FILENAME: calc_envelope_shift.sv
# AUTHOR: Greg Taylor CREATION DATE: 2 Nov 2014
#
# DESCRIPTION:
#
# CHANGE HISTORY:
# 3 June 2024 Greg Taylor
# Renamed from env_rate_counter.sv and refactored to match implementation in
# https://github.com/nukeykt/Nuked-OPL3
#
# 2 Nov 2014 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) 2013-2020 Nuke.YKT
#
# 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 calc_envelope_shift
import opl3_pkg::*;
(
input wire clk,
input wire sample_clk_en,
input wire [BANK_NUM_WIDTH-1:0] bank_num,
input wire [OP_NUM_WIDTH-1:0] op_num,
input wire ksr, // key scale rate
input wire nts, // keyboard split selection
input wire [REG_FNUM_WIDTH-1:0] fnum,
input wire [REG_BLOCK_WIDTH-1:0] block,
input wire [REG_ENV_WIDTH-1:0] requested_rate_p0,
output logic [REG_ENV_WIDTH+1-1:0] rate_hi_p2 = 0,
output logic [ENV_SHIFT_WIDTH-1:0] env_shift_p2 = 0
);
localparam EG_TIMER_WIDTH = 13;
localparam PIPELINE_DELAY = 3;
localparam EG_ADD_WIDTH = $clog2(13);
localparam logic [3:0] EG_INC_STEP [4] = {
4'b0000,
4'b1000,
4'b1010,
4'b1110
};

logic [EG_TIMER_WIDTH-1:0] eg_timer = 0;
logic [1:0] timer = 0;
logic eg_timerrem = 0;
logic eg_state = 0;
logic [EG_ADD_WIDTH-1:0] eg_add = 0;
logic [REG_BLOCK_WIDTH:0] block_shifted;
logic [REG_BLOCK_WIDTH:0] ksv_p0;
logic [REG_BLOCK_WIDTH:0] ks_p0;
logic [REG_ENV_WIDTH+2-1:0] requested_rate_shifted_p0;
logic [REG_ENV_WIDTH+3-1:0] rate_p1 = 0;
logic [REG_ENV_WIDTH+1-1:0] rate_hi_pre_p1;
logic [REG_ENV_WIDTH+1-1:0] rate_hi_p1;
logic [1:0] rate_lo_p1;
logic [REG_ENV_WIDTH+2-1:0] eg_shift_p1;
logic requested_rate_not_zero_p1;
logic [ENV_SHIFT_WIDTH:0] env_shift_pre_p2;
logic [PIPELINE_DELAY:1] sample_clk_en_p;
logic [PIPELINE_DELAY:1] [BANK_NUM_WIDTH-1:0] bank_num_p;
logic [PIPELINE_DELAY:1] [OP_NUM_WIDTH-1:0] op_num_p;

pipeline_sr #(
.ENDING_CYCLE(PIPELINE_DELAY)
) sample_clk_en_sr (
.clk,
.in(sample_clk_en),
.out(sample_clk_en_p)
);

pipeline_sr #(
.DATA_WIDTH(BANK_NUM_WIDTH),
.ENDING_CYCLE(PIPELINE_DELAY)
) bank_num_sr (
.clk,
.in(bank_num),
.out(bank_num_p)
);

pipeline_sr #(
.DATA_WIDTH(OP_NUM_WIDTH),
.ENDING_CYCLE(PIPELINE_DELAY)
) op_num_sr (
.clk,
.in(op_num),
.out(op_num_p)
);

always_comb begin
block_shifted = block << 1;
ksv_p0 = block_shifted | (nts ? fnum[8] : fnum[9]);
ks_p0 = ksr ? ksv_p0 : ksv_p0 >> 2;
requested_rate_shifted_p0 = requested_rate_p0 << 2;
end

always_ff @(posedge clk)
rate_p1 <= ks_p0 + requested_rate_shifted_p0;

always_comb begin
rate_hi_pre_p1 = rate_p1 >> 2;
rate_hi_p1 = rate_hi_pre_p1[4] ? 'h0f : rate_hi_pre_p1;
rate_lo_p1 = rate_p1[1:0];
eg_shift_p1 = rate_hi_p1 + eg_add;

env_shift_pre_p2 = rate_hi_p1[1:0] + EG_INC_STEP[rate_lo_p1][timer];
end

always_ff @(posedge clk) begin
requested_rate_not_zero_p1 <= requested_rate_p0 != 0;
env_shift_p2 <= 0;
rate_hi_p2 <= rate_hi_p1;

if (requested_rate_not_zero_p1) begin
if (rate_hi_p1 < 12) begin
if (eg_state)
unique case (eg_shift_p1)
12: env_shift_p2 <= 1;
13: env_shift_p2 <= rate_lo_p1[1];
14: env_shift_p2 <= rate_lo_p1[0];
default:;
endcase
end
else begin
env_shift_p2 <= env_shift_pre_p2;
if (env_shift_pre_p2[ENV_SHIFT_WIDTH])
env_shift_p2 <= 'h3;
if (env_shift_pre_p2 == 0)
env_shift_p2 <= eg_state;
end
end
end

always_ff @(posedge clk)
// once per sample, after operators are done
if (sample_clk_en_p[3] && bank_num_p[3] == 1 && op_num_p[3] == 17) begin
priority casex (eg_timer)
'b0_0000_0000_0000: eg_add <= 0;
'b1_0000_0000_0000: eg_add <= 13;
'bx_1000_0000_0000: eg_add <= 12;
'bx_x100_0000_0000: eg_add <= 11;
'bx_xx10_0000_0000: eg_add <= 10;
'bx_xxx1_0000_0000: eg_add <= 9;
'bx_xxxx_1000_0000: eg_add <= 8;
'bx_xxxx_x100_0000: eg_add <= 7;
'bx_xxxx_xx10_0000: eg_add <= 6;
'bx_xxxx_xxx1_0000: eg_add <= 5;
'bx_xxxx_xxxx_1000: eg_add <= 4;
'bx_xxxx_xxxx_x100: eg_add <= 3;
'bx_xxxx_xxxx_xx10: eg_add <= 2;
'bx_xxxx_xxxx_xxx1: eg_add <= 1;
'bx_xxxx_xxxx_xxxx:;
endcase

if (eg_timerrem || eg_state) begin
if (eg_timer == '1) begin
eg_timer <= 0;
eg_timerrem <= 1;
end
else begin
eg_timer <= eg_timer + 1;
eg_timerrem <= 0;
end
end

eg_state <= !eg_state;
timer <= timer + 1;
end
endmodule
`default_nettype wire
Loading

0 comments on commit 5f0e3f6

Please sign in to comment.