From 43ca6a49ff0d79f83358ad7cebc949a74e19cac2 Mon Sep 17 00:00:00 2001 From: Greg Taylor Date: Tue, 9 Apr 2024 21:31:56 -0400 Subject: [PATCH] More resource optimization, another 25% reduction (#25) * design working fully pipelined operator * cleanup * Fully pipeline operator (#23) (#24) * design working fully pipelined operator * cleanup * massive conversion from reg file to mems for operator channels, sounds good * fix channel addr * simplified use_feedback * simplified modulation assignment * op_type simplification, cleanup, comments * remove register file * remove unused file * fix inferred latch --- fpga/Makefile | 1 - fpga/modules/channels/src/channels.sv | 63 +- .../modules/channels/src/control_operators.sv | 751 ++++++++---------- fpga/modules/register_file/src/host_if.sv | 22 +- .../register_file/src/register_file.sv | 202 ----- fpga/modules/timers/src/timers.sv | 58 +- fpga/modules/top_level/pkg/opl3_pkg.sv | 7 + fpga/modules/top_level/src/opl3.sv | 60 +- 8 files changed, 411 insertions(+), 753 deletions(-) delete mode 100755 fpga/modules/register_file/src/register_file.sv diff --git a/fpga/Makefile b/fpga/Makefile index 5226711..28d6501 100755 --- a/fpga/Makefile +++ b/fpga/Makefile @@ -74,7 +74,6 @@ RTL_SRC = \ modules/misc/src/mem_multi_bank.sv \ modules/misc/src/pipeline_sr.sv \ modules/misc/src/synchronizer.sv \ - modules/register_file/src/register_file.sv \ modules/register_file/src/host_if.sv PKG_SRC = \ diff --git a/fpga/modules/channels/src/channels.sv b/fpga/modules/channels/src/channels.sv index d07216b..3fe9b2f 100755 --- a/fpga/modules/channels/src/channels.sv +++ b/fpga/modules/channels/src/channels.sv @@ -46,39 +46,8 @@ module channels ( input wire clk, input wire clk_host, + input var opl3_reg_wr_t opl3_reg_wr, input wire sample_clk_en, - input wire [REG_CONNECTION_SEL_WIDTH-1:0] connection_sel, - input wire is_new, - input wire nts, // keyboard split selection - input wire [REG_FNUM_WIDTH-1:0] fnum [2][9], - input wire [REG_MULT_WIDTH-1:0] mult [2][18], - input wire [REG_BLOCK_WIDTH-1:0] block [2][9], - input wire [REG_WS_WIDTH-1:0] ws [2][18], - input wire vib [2][18], - input wire dvb, - input wire kon [2][9], - input wire [REG_ENV_WIDTH-1:0] ar [2][18], // attack rate - input wire [REG_ENV_WIDTH-1:0] dr [2][18], // decay rate - input wire [REG_ENV_WIDTH-1:0] sl [2][18], // sustain level - input wire [REG_ENV_WIDTH-1:0] rr [2][18], // release rate - input wire [REG_TL_WIDTH-1:0] tl [2][18], // total level - input wire ksr [2][18], // key scale rate - input wire [REG_KSL_WIDTH-1:0] ksl [2][18], // key scale level - input wire egt [2][18], // envelope type - input wire am [2][18], // amplitude modulation (tremolo) - input wire dam, // depth of tremolo - input wire ryt, - input wire bd, - input wire sd, - input wire tom, - input wire tc, - input wire hh, - input wire cha [2][9], - input wire chb [2][9], - input wire chc [2][9], - input wire chd [2][9], - input wire [REG_FB_WIDTH-1:0] fb [2][9], - input wire cnt [2][9], output logic sample_valid, output logic signed [DAC_OUTPUT_WIDTH-1:0] sample_l, output logic signed [DAC_OUTPUT_WIDTH-1:0] sample_r @@ -109,6 +78,36 @@ module channels logic signed [SAMPLE_WIDTH-1:0] channel_d = 0; logic channel_valid = 0; logic ops_done_pulse; + logic [REG_CONNECTION_SEL_WIDTH-1:0] connection_sel = 0; + logic is_new = 0; + logic cha [2][9] = '{default: 0}; + logic chb [2][9] = '{default: 0}; + logic chc [2][9] = '{default: 0}; + logic chd [2][9] = '{default: 0}; + logic cnt [2][9] = '{default: 0}; + logic ryt = 0; // rhythm mode on/off + + always_ff @(posedge clk) + if (opl3_reg_wr.valid) begin + if (opl3_reg_wr.bank_num == 1 && opl3_reg_wr.address == 4) + connection_sel <= opl3_reg_wr.data[REG_CONNECTION_SEL_WIDTH-1:0]; + + if (opl3_reg_wr.bank_num == 1 && opl3_reg_wr.address == 5) + is_new <= opl3_reg_wr.data[0]; + + if (opl3_reg_wr.bank_num == 0 && opl3_reg_wr.address == 'hBD) + ryt <= opl3_reg_wr.data[5]; + end + + always_ff @(posedge clk) + if (opl3_reg_wr.valid && opl3_reg_wr.address >= 'hC0 && opl3_reg_wr.address <= 'hC8) begin + chd[opl3_reg_wr.bank_num][opl3_reg_wr.address - 'hC0] = opl3_reg_wr.data[7]; + chc[opl3_reg_wr.bank_num][opl3_reg_wr.address - 'hC0] = opl3_reg_wr.data[6]; + chb[opl3_reg_wr.bank_num][opl3_reg_wr.address - 'hC0] = opl3_reg_wr.data[5]; + cha[opl3_reg_wr.bank_num][opl3_reg_wr.address - 'hC0] = opl3_reg_wr.data[4]; + + cnt[opl3_reg_wr.bank_num][opl3_reg_wr.address - 'hC0] = opl3_reg_wr.data[0]; + end enum { IDLE, diff --git a/fpga/modules/channels/src/control_operators.sv b/fpga/modules/channels/src/control_operators.sv index 97abe32..ae5555e 100755 --- a/fpga/modules/channels/src/control_operators.sv +++ b/fpga/modules/channels/src/control_operators.sv @@ -48,44 +48,15 @@ module control_operators ( input wire clk, input wire sample_clk_en, + input var opl3_reg_wr_t opl3_reg_wr, input wire [REG_CONNECTION_SEL_WIDTH-1:0] connection_sel, input wire is_new, - input wire nts, // keyboard split selection - input wire [REG_FNUM_WIDTH-1:0] fnum [NUM_BANKS][NUM_CHANNELS_PER_BANK], - input wire [REG_MULT_WIDTH-1:0] mult [NUM_BANKS][NUM_OPERATORS_PER_BANK], - input wire [REG_BLOCK_WIDTH-1:0] block [NUM_BANKS][NUM_CHANNELS_PER_BANK], - input wire [REG_WS_WIDTH-1:0] ws [NUM_BANKS][NUM_OPERATORS_PER_BANK], - input wire vib [NUM_BANKS][NUM_OPERATORS_PER_BANK], - input wire dvb, - input wire kon [NUM_BANKS][NUM_CHANNELS_PER_BANK], - input wire [REG_ENV_WIDTH-1:0] ar [NUM_BANKS][NUM_OPERATORS_PER_BANK], // attack rate - input wire [REG_ENV_WIDTH-1:0] dr [NUM_BANKS][NUM_OPERATORS_PER_BANK], // decay rate - input wire [REG_ENV_WIDTH-1:0] sl [NUM_BANKS][NUM_OPERATORS_PER_BANK], // sustain level - input wire [REG_ENV_WIDTH-1:0] rr [NUM_BANKS][NUM_OPERATORS_PER_BANK], // release rate - input wire [REG_TL_WIDTH-1:0] tl [NUM_BANKS][NUM_OPERATORS_PER_BANK], // total level - input wire ksr [NUM_BANKS][NUM_OPERATORS_PER_BANK], // key scale rate - input wire [REG_KSL_WIDTH-1:0] ksl [NUM_BANKS][NUM_OPERATORS_PER_BANK], // key scale level - input wire egt [NUM_BANKS][NUM_OPERATORS_PER_BANK], // envelope type - input wire am [NUM_BANKS][NUM_OPERATORS_PER_BANK], // amplitude modulation (tremolo) - input wire dam, // depth of tremolo input wire ryt, - input wire bd, - input wire sd, - input wire tom, - input wire tc, - input wire hh, - input wire [REG_FB_WIDTH-1:0] fb [NUM_BANKS][NUM_CHANNELS_PER_BANK], - input wire cnt [NUM_BANKS][NUM_CHANNELS_PER_BANK], output logic signed [OP_OUT_WIDTH-1:0] operator_out [NUM_BANKS][NUM_OPERATORS_PER_BANK] = '{default: 0}, output logic ops_done_pulse = 0 ); - /* - * 256/36 operators gives us ~7.1 cycles per operator before next - * sample_clk_en - */ localparam PIPELINE_DELAY = 6; localparam NUM_OPERATOR_UPDATE_STATES = NUM_BANKS*NUM_OPERATORS_PER_BANK + 1; // 36 operators + idle state - logic [$clog2(PIPELINE_DELAY)-1:0] delay_counter = 0; logic [$clog2(NUM_OPERATOR_UPDATE_STATES)-1:0] state = 0; logic [$clog2(NUM_OPERATOR_UPDATE_STATES)-1:0] next_state; @@ -93,13 +64,9 @@ module control_operators logic [$clog2(NUM_BANKS)-1:0] bank_num; logic [$clog2(NUM_OPERATORS_PER_BANK)-1:0] op_num; - logic [REG_FNUM_WIDTH-1:0] fnum_tmp [NUM_BANKS][NUM_OPERATORS_PER_BANK]; - logic [REG_BLOCK_WIDTH-1:0] block_tmp [NUM_BANKS][NUM_OPERATORS_PER_BANK]; - logic kon_tmp [NUM_BANKS][NUM_OPERATORS_PER_BANK]; - logic [REG_FB_WIDTH-1:0] fb_tmp [NUM_BANKS][NUM_OPERATORS_PER_BANK]; - logic use_feedback [NUM_BANKS][NUM_OPERATORS_PER_BANK]; - logic signed [OP_OUT_WIDTH-1:0] modulation [NUM_BANKS][NUM_OPERATORS_PER_BANK]; - operator_t op_type_tmp [NUM_BANKS][NUM_OPERATORS_PER_BANK]; + logic use_feedback; + logic signed [OP_OUT_WIDTH-1:0] modulation; + operator_t op_type; logic signed [OP_OUT_WIDTH-1:0] out_p6; logic signed [OP_OUT_WIDTH-1:0] modulation_out_p0; logic [$clog2(NUM_OPERATORS_PER_BANK)-1:0] modulation_out_op_num; @@ -108,376 +75,319 @@ module control_operators logic [PIPELINE_DELAY:1] [BANK_NUM_WIDTH-1:0] bank_num_p; logic [PIPELINE_DELAY:1] [OP_NUM_WIDTH-1:0] op_num_p; - always_comb begin - op_type_tmp = '{default: OP_NORMAL}; - - /* - * Operator input mappings - * - * The first mappings are static whether the operator is configured - * in a 2 channel or a 4 channel mode. Next we start mapping connections - * for operators whose input varies depending on the mode. - */ - fnum_tmp[0][0] = fnum[0][0]; - block_tmp[0][0] = block[0][0]; - kon_tmp[0][0] = kon[0][0]; - fb_tmp[0][0] = fb[0][0]; - use_feedback[0][0] = 1; - modulation[0][0] = 0; - - fnum_tmp[0][3] = fnum[0][0]; - block_tmp[0][3] = block[0][0]; - kon_tmp[0][3] = kon[0][0]; - fb_tmp[0][3] = 0; - use_feedback[0][3] = 0; - modulation[0][3] = cnt[0][0] ? 0 : modulation_out_p0; - - fnum_tmp[0][1] = fnum[0][1]; - block_tmp[0][1] = block[0][1]; - kon_tmp[0][1] = kon[0][1]; - fb_tmp[0][1] = fb[0][1]; - use_feedback[0][1] = 1; - modulation[0][1] = 0; - - fnum_tmp[0][4] = fnum[0][1]; - block_tmp[0][4] = block[0][1]; - kon_tmp[0][4] = kon[0][1]; - fb_tmp[0][4] = 0; - use_feedback[0][4] = 0; - modulation[0][4] = cnt[0][1] ? 0 : modulation_out_p0; - - fnum_tmp[0][2] = fnum[0][2]; - block_tmp[0][2] = block[0][2]; - kon_tmp[0][2] = kon[0][2]; - fb_tmp[0][2] = fb[0][2]; - use_feedback[0][2] = 1; - modulation[0][2] = 0; - - fnum_tmp[0][5] = fnum[0][2]; - block_tmp[0][5] = block[0][2]; - kon_tmp[0][5] = kon[0][2]; - fb_tmp[0][5] = 0; - use_feedback[0][5] = 0; - modulation[0][5] = cnt[0][2] ? 0 : modulation_out_p0; - - fnum_tmp[1][0] = fnum[1][0]; - block_tmp[1][0] = block[1][0]; - kon_tmp[1][0] = kon[1][0]; - fb_tmp[1][0] = fb[1][0]; - use_feedback[1][0] = 1; - modulation[1][0] = 0; - - fnum_tmp[1][3] = fnum[1][0]; - block_tmp[1][3] = block[1][0]; - kon_tmp[1][3] = kon[1][0]; - fb_tmp[1][3] = 0; - use_feedback[1][3] = 0; - modulation[1][3] = cnt[1][0] ? 0 : modulation_out_p0; - - fnum_tmp[1][1] = fnum[1][1]; - block_tmp[1][1] = block[1][1]; - kon_tmp[1][1] = kon[1][1]; - fb_tmp[1][1] = fb[1][1]; - use_feedback[1][1] = 1; - modulation[1][1] = 0; - - fnum_tmp[1][4] = fnum[1][1]; - block_tmp[1][4] = block[1][1]; - kon_tmp[1][4] = kon[1][1]; - fb_tmp[1][4] = 0; - use_feedback[1][4] = 0; - modulation[1][4] = cnt[1][1] ? 0 : modulation_out_p0; - - fnum_tmp[1][2] = fnum[1][2]; - block_tmp[1][2] = block[1][2]; - kon_tmp[1][2] = kon[1][2]; - fb_tmp[1][2] = fb[1][2]; - use_feedback[1][2] = 1; - modulation[1][2] = 0; - - fnum_tmp[1][5] = fnum[1][2]; - block_tmp[1][5] = block[1][2]; - kon_tmp[1][5] = kon[1][2]; - fb_tmp[1][5] = 0; - use_feedback[1][5] = 0; - modulation[1][5] = cnt[1][2] ? 0 : modulation_out_p0; - - // aka bass drum operator 1 - fnum_tmp[0][12] = fnum[0][6]; - block_tmp[0][12] = block[0][6]; - kon_tmp[0][12] = kon[0][6]; - fb_tmp[0][12] = fb[0][6]; - op_type_tmp[0][12] = ryt ? OP_BASS_DRUM : OP_NORMAL; - use_feedback[0][12] = 1; - modulation[0][12] = 0; - - // aka bass drum operator 2 - fnum_tmp[0][15] = fnum[0][6]; - block_tmp[0][15] = block[0][6]; - kon_tmp[0][15] = kon[0][6]; - fb_tmp[0][15] = 0; - op_type_tmp[0][15] = ryt ? OP_BASS_DRUM : OP_NORMAL; - use_feedback[0][15] = 0; - modulation[0][15] = cnt[0][6] ? 0 : modulation_out_p0; - - // aka hi hat operator - fnum_tmp[0][13] = fnum[0][7]; - block_tmp[0][13] = block[0][7]; - kon_tmp[0][13] = kon[0][7]; - fb_tmp[0][13] = ryt ? 0 : fb[0][7]; - op_type_tmp[0][13] = ryt ? OP_HI_HAT : OP_NORMAL; - use_feedback[0][13] = ryt ? 0 : 1; - modulation[0][13] = 0; - - // aka snare drum operator - fnum_tmp[0][16] = fnum[0][7]; - block_tmp[0][16] = block[0][7]; - kon_tmp[0][16] = kon[0][7]; - fb_tmp[0][16] = 0; - op_type_tmp[0][16] = ryt ? OP_SNARE_DRUM : OP_NORMAL; - use_feedback[0][16] = 0; - modulation[0][16] = cnt[0][7] || ryt ? 0 : modulation_out_p0; - - // aka tom tom operator - fnum_tmp[0][14] = fnum[0][8]; - block_tmp[0][14] = block[0][8]; - kon_tmp[0][14] = kon[0][8]; - fb_tmp[0][14] = ryt ? 0 : fb[0][8]; - op_type_tmp[0][14] = ryt ? OP_TOM_TOM : OP_NORMAL; - use_feedback[0][14] = ryt ? 0 : 1; - modulation[0][14] = 0; - - // aka top cymbal operator - fnum_tmp[0][17] = fnum[0][8]; - block_tmp[0][17] = block[0][8]; - kon_tmp[0][17] = kon[0][8]; - fb_tmp[0][17] = 0; - op_type_tmp[0][17] = ryt ? OP_TOP_CYMBAL : OP_NORMAL; - use_feedback[0][17] = 0; - modulation[0][17] = cnt[0][8] || ryt ? 0 : modulation_out_p0; - - fnum_tmp[1][12] = fnum[1][6]; - block_tmp[1][12] = block[1][6]; - kon_tmp[1][12] = kon[1][6]; - fb_tmp[1][12] = fb[1][6]; - use_feedback[1][12] = 1; - modulation[1][12] = 0; - - fnum_tmp[1][15] = fnum[1][6]; - block_tmp[1][15] = block[1][6]; - kon_tmp[1][15] = kon[1][6]; - fb_tmp[1][15] = 0; - use_feedback[1][15] = 0; - modulation[1][15] = cnt[1][6] ? 0 : modulation_out_p0; - - fnum_tmp[1][13] = fnum[1][7]; - block_tmp[1][13] = block[1][7]; - kon_tmp[1][13] = kon[1][7]; - fb_tmp[1][13] = fb[1][7]; - use_feedback[1][13] = 1; - modulation[1][13] = 0; - - fnum_tmp[1][16] = fnum[1][7]; - block_tmp[1][16] = block[1][7]; - kon_tmp[1][16] = kon[1][7]; - fb_tmp[1][16] = 0; - use_feedback[1][16] = 0; - modulation[1][16] = cnt[1][7] ? 0 : modulation_out_p0; - - fnum_tmp[1][14] = fnum[1][8]; - block_tmp[1][14] = block[1][8]; - kon_tmp[1][14] = kon[1][8]; - fb_tmp[1][14] = fb[1][8]; - use_feedback[1][14] = 1; - modulation[1][14] = 0; - - fnum_tmp[1][17] = fnum[1][8]; - block_tmp[1][17] = block[1][8]; - kon_tmp[1][17] = kon[1][8]; - fb_tmp[1][17] = 0; - use_feedback[1][17] = 0; - modulation[1][17] = cnt[1][8] ? 0 : modulation_out_p0; - - if (connection_sel[0]) begin - fnum_tmp[0][6] = fnum[0][0]; - block_tmp[0][6] = block[0][0]; - kon_tmp[0][6] = kon[0][0]; - fb_tmp[0][6] = 0; - use_feedback[0][6] = 0; - modulation[0][6] = !cnt[0][0] && cnt[0][3] ? 0 : modulation_out_p0; - - fnum_tmp[0][9] = fnum[0][0]; - block_tmp[0][9] = block[0][0]; - kon_tmp[0][9] = kon[0][0]; - fb_tmp[0][9] = 0; - use_feedback[0][9] = 0; - modulation[0][9] = cnt[0][0] && cnt[0][3] ? 0 : modulation_out_p0; - end - else begin - fnum_tmp[0][6] = fnum[0][3]; - block_tmp[0][6] = block[0][3]; - kon_tmp[0][6] = kon[0][3]; - fb_tmp[0][6] = fb[0][3]; - use_feedback[0][6] = 1; - modulation[0][6] = 0; - - fnum_tmp[0][9] = fnum[0][3]; - block_tmp[0][9] = block[0][3]; - kon_tmp[0][9] = kon[0][3]; - fb_tmp[0][9] = 0; - use_feedback[0][9] = 0; - modulation[0][9] = cnt[0][3] ? 0 : modulation_out_p0; - end - if (connection_sel[1]) begin - fnum_tmp[0][7] = fnum[0][1]; - block_tmp[0][7] = block[0][1]; - kon_tmp[0][7] = kon[0][1]; - fb_tmp[0][7] = 0; - use_feedback[0][7] = 0; - modulation[0][7] = !cnt[0][1] && cnt[0][4] ? 0 : modulation_out_p0; - - fnum_tmp[0][10] = fnum[0][1]; - block_tmp[0][10] = block[0][1]; - kon_tmp[0][10] = kon[0][1]; - fb_tmp[0][10] = 0; - use_feedback[0][10] = 0; - modulation[0][10] = cnt[0][1] && cnt[0][4] ? 0 : modulation_out_p0; - end - else begin - fnum_tmp[0][7] = fnum[0][4]; - block_tmp[0][7] = block[0][4]; - kon_tmp[0][7] = kon[0][4]; - fb_tmp[0][7] = fb[0][4]; - use_feedback[0][7] = 1; - modulation[0][7] = 0; - - fnum_tmp[0][10] = fnum[0][4]; - block_tmp[0][10] = block[0][4]; - kon_tmp[0][10] = kon[0][4]; - fb_tmp[0][10] = 0; - use_feedback[0][10] = 0; - modulation[0][10] = cnt[0][4] ? 0 : modulation_out_p0; - end - if (connection_sel[2]) begin - fnum_tmp[0][8] = fnum[0][2]; - block_tmp[0][8] = block[0][2]; - kon_tmp[0][8] = kon[0][2]; - fb_tmp[0][8] = 0; - use_feedback[0][8] = 0; - modulation[0][8] = !cnt[0][2] && cnt[0][5] ? 0 : modulation_out_p0; - - fnum_tmp[0][11] = fnum[0][2]; - block_tmp[0][11] = block[0][2]; - kon_tmp[0][11] = kon[0][2]; - fb_tmp[0][11] = 0; - use_feedback[0][11] = 0; - modulation[0][11] = cnt[0][2] && cnt[0][5] ? 0 : modulation_out_p0; - end - else begin - fnum_tmp[0][8] = fnum[0][5]; - block_tmp[0][8] = block[0][5]; - kon_tmp[0][8] = kon[0][5]; - fb_tmp[0][8] = fb[0][5]; - use_feedback[0][8] = 1; - modulation[0][8] = 0; - - fnum_tmp[0][11] = fnum[0][5]; - block_tmp[0][11] = block[0][5]; - kon_tmp[0][11] = kon[0][5]; - fb_tmp[0][11] = 0; - use_feedback[0][11] = 0; - modulation[0][11] = cnt[0][5] ? 0 : modulation_out_p0; + logic am; // amplitude modulation (tremolo on/off) + logic vib; // vibrato on/off + logic egt; // envelope type (select sustain/decay) + logic ksr; // key scale rate + logic [REG_MULT_WIDTH-1:0] mult; // frequency data multiplier + logic [REG_KSL_WIDTH-1:0] ksl; // key scale level + logic [REG_TL_WIDTH-1:0] tl; // total level (modulation, volume setting) + logic [REG_ENV_WIDTH-1:0] ar; // attack rate + logic [REG_ENV_WIDTH-1:0] dr; // decay rate + logic [REG_ENV_WIDTH-1:0] sl; // sustain level + logic [REG_ENV_WIDTH-1:0] rr; // release rate + logic [REG_WS_WIDTH-1:0] ws; // waveform select + logic [$clog2('h16)-1:0] operator_mem_rd_address; + + logic [REG_FNUM_WIDTH-1:0] fnum; // f-number (scale data within the octave) + logic [REG_BLOCK_WIDTH-1:0] block; // octave data + logic kon; // key-on (sound generation on/off) + logic [REG_FB_WIDTH-1:0] fb; // feedback (modulation for slot 1 FM feedback) + logic cnt; // operator connection + logic [$clog2('h9)-1:0] kon_block_fnum_channel_mem_rd_address; + logic [$clog2('h9)-1:0] fb_cnt_channel_mem_rd_address; + + logic nts = 0; // keyboard split selection + logic dvb = 0; // vibrato depth + logic dam = 0; // depth of tremolo + logic bd = 0; // bass drum key-on + logic sd = 0; // snare drum key-on + logic tom = 0; // tom-tom key-on + logic tc = 0; // top-cymbal key-on + logic hh = 0; // hi-hat key-on + + always_ff @(posedge clk) + if (opl3_reg_wr.valid) begin + if (opl3_reg_wr.bank_num == 0 && opl3_reg_wr.address == 8) + nts <= opl3_reg_wr.data[6]; + + if (opl3_reg_wr.bank_num == 0 && opl3_reg_wr.address == 'hBD) begin + dam <= opl3_reg_wr.data[7]; + dvb <= opl3_reg_wr.data[6]; + bd <= opl3_reg_wr.data[4]; + sd <= opl3_reg_wr.data[3]; + tom <= opl3_reg_wr.data[2]; + tc <= opl3_reg_wr.data[1]; + hh <= opl3_reg_wr.data[0]; + end end - if (connection_sel[3]) begin - fnum_tmp[1][6] = fnum[1][0]; - block_tmp[1][6] = block[1][0]; - kon_tmp[1][6] = kon[1][0]; - fb_tmp[1][6] = 0; - use_feedback[1][6] = 0; - modulation[1][6] = !cnt[1][0] && cnt[1][3] ? 0 : modulation_out_p0; - - fnum_tmp[1][9] = fnum[1][0]; - block_tmp[1][9] = block[1][0]; - kon_tmp[1][9] = kon[1][0]; - fb_tmp[1][9] = 0; - use_feedback[1][9] = 0; - modulation[1][9] = cnt[1][0] && cnt[1][3] ? 0 : modulation_out_p0; + + always_comb + if (op_num < 6) + operator_mem_rd_address = op_num; + else if (op_num < 12) + operator_mem_rd_address = op_num + 2; + else + operator_mem_rd_address = op_num + 4; + + logic [$clog2('h16)-1:0] am_vib_egt_ksr_mult_mem_wr_address = opl3_reg_wr.address - 'h20; + + mem_multi_bank #( + .DATA_WIDTH(REG_FILE_DATA_WIDTH), + .DEPTH('h16), + .OUTPUT_DELAY(0), + .DEFAULT_VALUE(0), + .NUM_BANKS(NUM_BANKS) + ) am_vib_egt_ksr_mult_mem ( + .clk, + .wea(opl3_reg_wr.valid && opl3_reg_wr.address >= 'h20 && opl3_reg_wr.address <= 'h35), + .reb(op_sample_clk_en), + .banka(opl3_reg_wr.bank_num), + .addra(am_vib_egt_ksr_mult_mem_wr_address), + .bankb(bank_num), + .addrb(operator_mem_rd_address), + .dia(opl3_reg_wr.data), + .dob({am, vib, egt, ksr, mult}) + ); + + logic [$clog2('h16)-1:0] ksl_tl_mem_wr_address = opl3_reg_wr.address - 'h40; + + mem_multi_bank #( + .DATA_WIDTH(REG_FILE_DATA_WIDTH), + .DEPTH('h16), + .OUTPUT_DELAY(0), + .DEFAULT_VALUE(0), + .NUM_BANKS(NUM_BANKS) + ) ksl_tl_mem ( + .clk, + .wea(opl3_reg_wr.valid && opl3_reg_wr.address >= 'h40 && opl3_reg_wr.address <= 'h55), + .reb(op_sample_clk_en), + .banka(opl3_reg_wr.bank_num), + .addra(ksl_tl_mem_wr_address), + .bankb(bank_num), + .addrb(operator_mem_rd_address), + .dia(opl3_reg_wr.data), + .dob({ksl, tl}) + ); + + logic [$clog2('h16)-1:0] ar_dr_mem_wr_address = opl3_reg_wr.address - 'h60; + + mem_multi_bank #( + .DATA_WIDTH(REG_FILE_DATA_WIDTH), + .DEPTH('h16), + .OUTPUT_DELAY(0), + .DEFAULT_VALUE(0), + .NUM_BANKS(NUM_BANKS) + ) ar_dr_mem ( + .clk, + .wea(opl3_reg_wr.valid && opl3_reg_wr.address >= 'h60 && opl3_reg_wr.address <= 'h75), + .reb(op_sample_clk_en), + .banka(opl3_reg_wr.bank_num), + .addra(ar_dr_mem_wr_address), + .bankb(bank_num), + .addrb(operator_mem_rd_address), + .dia(opl3_reg_wr.data), + .dob({ar, dr}) + ); + + logic [$clog2('h16)-1:0] sl_rr_mem_wr_address = opl3_reg_wr.address - 'h80; + + mem_multi_bank #( + .DATA_WIDTH(REG_FILE_DATA_WIDTH), + .DEPTH('h16), + .OUTPUT_DELAY(0), + .DEFAULT_VALUE(0), + .NUM_BANKS(NUM_BANKS) + ) sl_rr_mem ( + .clk, + .wea(opl3_reg_wr.valid && opl3_reg_wr.address >= 'h80 && opl3_reg_wr.address <= 'h95), + .reb(op_sample_clk_en), + .banka(opl3_reg_wr.bank_num), + .addra(sl_rr_mem_wr_address), + .bankb(bank_num), + .addrb(operator_mem_rd_address), + .dia(opl3_reg_wr.data), + .dob({sl, rr}) + ); + + logic [$clog2('h16)-1:0] ws_mem_wr_address = opl3_reg_wr.address - 'hE0; + + mem_multi_bank #( + .DATA_WIDTH(REG_WS_WIDTH), + .DEPTH('h16), + .OUTPUT_DELAY(0), + .DEFAULT_VALUE(0), + .NUM_BANKS(NUM_BANKS) + ) ws_mem ( + .clk, + .wea(opl3_reg_wr.valid && opl3_reg_wr.address >= 'hE0 && opl3_reg_wr.address <= 'hF5), + .reb(op_sample_clk_en), + .banka(opl3_reg_wr.bank_num), + .addra(ws_mem_wr_address), + .bankb(bank_num), + .addrb(operator_mem_rd_address), + .dia(opl3_reg_wr.data[REG_WS_WIDTH-1:0]), + .dob(ws) + ); + + always_comb + unique case (op_num) + 0, 3: begin + kon_block_fnum_channel_mem_rd_address = 0; + fb_cnt_channel_mem_rd_address = 0; end - else begin - fnum_tmp[1][6] = fnum[1][3]; - block_tmp[1][6] = block[1][3]; - kon_tmp[1][6] = kon[1][3]; - fb_tmp[1][6] = fb[1][3]; - use_feedback[1][6] = 1; - modulation[1][6] = 0; - - fnum_tmp[1][9] = fnum[1][3]; - block_tmp[1][9] = block[1][3]; - kon_tmp[1][9] = kon[1][3]; - fb_tmp[1][9] = 0; - use_feedback[1][9] = 0; - modulation[1][9] = cnt[1][3] ? 0 : modulation_out_p0; + 1, 4: begin + kon_block_fnum_channel_mem_rd_address = 1; + fb_cnt_channel_mem_rd_address = 1; end - if (connection_sel[4]) begin - fnum_tmp[1][7] = fnum[1][1]; - block_tmp[1][7] = block[1][1]; - kon_tmp[1][7] = kon[1][1]; - fb_tmp[1][7] = 0; - use_feedback[1][7] = 0; - modulation[1][7] = !cnt[1][1] && cnt[1][4] ? 0 : modulation_out_p0; - - fnum_tmp[1][10] = fnum[1][1]; - block_tmp[1][10] = block[1][1]; - kon_tmp[1][10] = kon[1][1]; - fb_tmp[1][10] = 0; - use_feedback[1][10] = 0; - modulation[1][10] = cnt[1][1] && cnt[1][4] ? 0 : modulation_out_p0; + 2, 5: begin + kon_block_fnum_channel_mem_rd_address = 2; + fb_cnt_channel_mem_rd_address = 2; end - else begin - fnum_tmp[1][7] = fnum[1][4]; - block_tmp[1][7] = block[1][4]; - kon_tmp[1][7] = kon[1][4]; - fb_tmp[1][7] = fb[1][4]; - use_feedback[1][7] = 1; - modulation[1][7] = 0; - - fnum_tmp[1][10] = fnum[1][4]; - block_tmp[1][10] = block[1][4]; - kon_tmp[1][10] = kon[1][4]; - fb_tmp[1][10] = 0; - use_feedback[1][10] = 0; - modulation[1][10] = cnt[1][4] ? 0 : modulation_out_p0; + 6, 9: + if (bank_num == 0) begin + kon_block_fnum_channel_mem_rd_address = connection_sel[0] ? 0 : 3; + fb_cnt_channel_mem_rd_address = 3; + end + else begin + kon_block_fnum_channel_mem_rd_address = connection_sel[3] ? 0 : 3; + fb_cnt_channel_mem_rd_address = 3; + end + 7, 10: + if (bank_num == 0) begin + kon_block_fnum_channel_mem_rd_address = connection_sel[1] ? 1 : 4; + fb_cnt_channel_mem_rd_address = 4; + end + else begin + kon_block_fnum_channel_mem_rd_address = connection_sel[4] ? 1 : 4; + fb_cnt_channel_mem_rd_address = 4; + end + 8, 11: + if (bank_num == 0) begin + kon_block_fnum_channel_mem_rd_address = connection_sel[2] ? 2 : 5; + fb_cnt_channel_mem_rd_address = 5; + end + else begin + kon_block_fnum_channel_mem_rd_address = connection_sel[5] ? 2 : 5; + fb_cnt_channel_mem_rd_address = 5; + end + 12, 15: begin + kon_block_fnum_channel_mem_rd_address = 6; + fb_cnt_channel_mem_rd_address = 6; end - if (connection_sel[5]) begin - fnum_tmp[1][8] = fnum[1][2]; - block_tmp[1][8] = block[1][2]; - kon_tmp[1][8] = kon[1][2]; - fb_tmp[1][8] = 0; - use_feedback[1][8] = 0; - modulation[1][8] = !cnt[1][2] && cnt[1][5] ? 0 : modulation_out_p0; - - fnum_tmp[1][11] = fnum[1][2]; - block_tmp[1][11] = block[1][2]; - kon_tmp[1][11] = kon[1][2]; - fb_tmp[1][11] = 0; - use_feedback[1][11] = 0; - modulation[1][11] = cnt[1][2] && cnt[1][5] ? 0 : modulation_out_p0; + 13, 16: begin + kon_block_fnum_channel_mem_rd_address = 7; + fb_cnt_channel_mem_rd_address = 7; end - else begin - fnum_tmp[1][8] = fnum[1][5]; - block_tmp[1][8] = block[1][5]; - kon_tmp[1][8] = kon[1][5]; - fb_tmp[1][8] = fb[1][5]; - use_feedback[1][8] = 1; - modulation[1][8] = 0; - - fnum_tmp[1][11] = fnum[1][5]; - block_tmp[1][11] = block[1][5]; - kon_tmp[1][11] = kon[1][5]; - fb_tmp[1][11] = 0; - use_feedback[1][11] = 0; - modulation[1][11] = cnt[1][5] ? 0 : modulation_out_p0; + 14, 17: begin + kon_block_fnum_channel_mem_rd_address = 8; + fb_cnt_channel_mem_rd_address = 8; end + endcase + + logic [$clog2('h9)-1:0] fnum_low_mem_wr_address = opl3_reg_wr.address - 'hA0; + + mem_multi_bank #( + .DATA_WIDTH(REG_FILE_DATA_WIDTH), + .DEPTH('h9), + .OUTPUT_DELAY(0), + .DEFAULT_VALUE(0), + .NUM_BANKS(NUM_BANKS) + ) fnum_low_mem ( + .clk, + .wea(opl3_reg_wr.valid && opl3_reg_wr.address >= 'hA0 && opl3_reg_wr.address <= 'hA8), + .reb(op_sample_clk_en), + .banka(opl3_reg_wr.bank_num), + .addra(fnum_low_mem_wr_address), + .bankb(bank_num), + .addrb(kon_block_fnum_channel_mem_rd_address), + .dia(opl3_reg_wr.data), + .dob(fnum[7:0]) + ); + + logic [$clog2('h9)-1:0] kon_block_fnum_high_mem_wr_address = opl3_reg_wr.address - 'hB0; + localparam kon_block_fnum_high_mem_width = $bits(kon) + $bits(block) + $bits(fnum[9:8]); + + mem_multi_bank #( + .DATA_WIDTH(kon_block_fnum_high_mem_width), + .DEPTH('h9), + .OUTPUT_DELAY(0), + .DEFAULT_VALUE(0), + .NUM_BANKS(NUM_BANKS) + ) kon_block_fnum_high_mem ( + .clk, + .wea(opl3_reg_wr.valid && opl3_reg_wr.address >= 'hB0 && opl3_reg_wr.address <= 'hB8), + .reb(op_sample_clk_en), + .banka(opl3_reg_wr.bank_num), + .addra(kon_block_fnum_high_mem_wr_address), + .bankb(bank_num), + .addrb(kon_block_fnum_channel_mem_rd_address), + .dia(opl3_reg_wr.data[kon_block_fnum_high_mem_width-1:0]), + .dob({kon, block, fnum[9:8]}) + ); + + logic [$clog2('h9)-1:0] fb_cnt_mem_wr_address = opl3_reg_wr.address - 'hC0; + localparam fb_cnt_mem_width = $bits(fb) + $bits(cnt); + + mem_multi_bank #( + .DATA_WIDTH(fb_cnt_mem_width), + .DEPTH('h9), + .OUTPUT_DELAY(0), + .DEFAULT_VALUE(0), + .NUM_BANKS(NUM_BANKS) + ) fb_cnt_mem ( + .clk, + .wea(opl3_reg_wr.valid && opl3_reg_wr.address >= 'hC0 && opl3_reg_wr.address <= 'hC8), + .reb(op_sample_clk_en), + .banka(opl3_reg_wr.bank_num), + .addra(fb_cnt_mem_wr_address), + .bankb(bank_num), + .addrb(fb_cnt_channel_mem_rd_address), + .dia(opl3_reg_wr.data[fb_cnt_mem_width-1:0]), + .dob({fb, cnt}) + ); + + always_comb begin + op_type = OP_NORMAL; + if (bank_num == 0 && ryt) + unique case (op_num) + 12, 15: op_type = OP_BASS_DRUM; + 13: op_type = OP_HI_HAT; + 14: op_type = OP_TOM_TOM; + 16: op_type = OP_SNARE_DRUM; + 17: op_type = OP_TOP_CYMBAL; + default: op_type = OP_NORMAL; + endcase + + unique case (op_num) + 0, 1, 2, 12: use_feedback = 1; + 3, 4, 5, 9, 10, 11, + 15, 16, 17: use_feedback = 0; + 6: if (bank_num == 0) use_feedback = !connection_sel[0]; + else use_feedback = !connection_sel[3]; + 7: if (bank_num == 0) use_feedback = !connection_sel[1]; + else use_feedback = !connection_sel[4]; + 8: if (bank_num == 0) use_feedback = !connection_sel[2]; + else use_feedback = !connection_sel[5]; + 13: use_feedback = !(bank_num == 0 && ryt); // aka hi hat operator in bank 0 + 14: use_feedback = !(bank_num == 0 && ryt); // aka tom tom operator in bank 0 + endcase + + unique case (op_num) + 0, 1, 2, 12, 13, 14: modulation = 0; + 3, 4, 5, 9, 10, 11, 15: modulation = cnt ? 0 : modulation_out_p0; + 6: if ((bank_num == 0 && connection_sel[0]) || (bank_num == 1 && connection_sel[3])) + modulation = cnt ? 0 : modulation_out_p0; + else modulation = 0; + 7: if ((bank_num == 0 && connection_sel[1]) || (bank_num == 1 && connection_sel[4])) + modulation = cnt ? 0 : modulation_out_p0; + else modulation = 0; + 8: if ((bank_num == 0 && connection_sel[2]) || (bank_num == 1 && connection_sel[5])) + modulation = cnt ? 0 : modulation_out_p0; + else modulation = 0; + 16: modulation = cnt || (ryt && bank_num == 0) ? 0 : modulation_out_p0; // aka snare drum operator in bank 0 + 17: modulation = cnt || (ryt && bank_num == 0) ? 0 : modulation_out_p0; // aka top cymbal operator in bank 0 + endcase end always_ff @(posedge clk) @@ -491,14 +401,6 @@ module control_operators else next_state = state + 1; - always_ff @(posedge clk) - if (next_state != state) - delay_counter <= 0; - else if (delay_counter == PIPELINE_DELAY ) - delay_counter <= 0; - else - delay_counter <= delay_counter + 1; - always_comb bank_num = state > NUM_OPERATORS_PER_BANK; always_comb if (state == 0) @@ -515,39 +417,8 @@ module control_operators * cycle of that time slot */ operator operator ( - .clk, .sample_clk_en(op_sample_clk_en), - .is_new, - .bank_num, - .op_num, - .fnum(fnum_tmp[bank_num][op_num]), - .mult(mult[bank_num][op_num]), - .block(block_tmp[bank_num][op_num]), - .ws(ws[bank_num][op_num]), - .vib(vib[bank_num][op_num]), - .dvb, - .kon(kon_tmp[bank_num][op_num]), - .ar(ar[bank_num][op_num]), - .dr(dr[bank_num][op_num]), - .sl(sl[bank_num][op_num]), - .rr(rr[bank_num][op_num]), - .tl(tl[bank_num][op_num]), - .ksr(ksr[bank_num][op_num]), - .ksl(ksl[bank_num][op_num]), - .egt(egt[bank_num][op_num]), - .am(am[bank_num][op_num]), - .dam, - .nts, - .bd, - .sd, - .tom, - .tc, - .hh, - .use_feedback(use_feedback[bank_num][op_num]), - .fb(fb_tmp[bank_num][op_num]), - .modulation(modulation[bank_num][op_num]), - .op_type(op_type_tmp[bank_num][op_num]), - .out_p6 + .* ); pipeline_sr #( diff --git a/fpga/modules/register_file/src/host_if.sv b/fpga/modules/register_file/src/host_if.sv index 94383d1..43e5372 100755 --- a/fpga/modules/register_file/src/host_if.sv +++ b/fpga/modules/register_file/src/host_if.sv @@ -54,8 +54,8 @@ module host_if input wire [1:0] address, input wire [REG_FILE_DATA_WIDTH-1:0] din, output logic [REG_FILE_DATA_WIDTH-1:0] dout, - output logic [REG_FILE_DATA_WIDTH-1:0] opl3_reg [NUM_BANKS][NUM_REG_PER_BANK] = '{default: 0}, output logic ack_host_wr, + output opl3_reg_wr_t opl3_reg_wr = 0, input wire [REG_FILE_DATA_WIDTH-1:0] status ); logic cs_p1 = 0; @@ -75,8 +75,6 @@ module host_if logic wr_opl3 = 0; logic [1:0] address_opl3 = 0; logic [REG_FILE_DATA_WIDTH-1:0] din_opl3 = 0; - logic internal_bank = 0; - logic [REG_FILE_DATA_WIDTH-1:0] internal_address = 0; logic ack_transaction; /* @@ -133,24 +131,24 @@ module host_if wr_opl3 <= wr_latched; address_opl3 <= address_latched; din_opl3 <= din_latched; + opl3_reg_wr.valid <= 0; if (cs_opl3 && !cs_opl3_p1) unique case ({rd_opl3, wr_opl3, address_opl3[0]}) 'b010: begin // address write mode - internal_bank <= address_opl3[1]; - internal_address <= din_opl3; + opl3_reg_wr.bank_num <= address_opl3[1]; + opl3_reg_wr.address <= din_opl3; + end + 'b011: begin // data write mode + opl3_reg_wr.data <= din_opl3; + opl3_reg_wr.valid <= 1; end - 'b011: // data write mode - opl3_reg[internal_bank][internal_address] <= din_opl3; 'b100:; // status read mode default:; endcase - if (reset) begin - internal_bank <= 0; - internal_address <= 0; - opl3_reg <= '{default: 0}; - end + if (reset) + opl3_reg_wr <= 0; end // bits do not need to be coherant, can use synchronizers diff --git a/fpga/modules/register_file/src/register_file.sv b/fpga/modules/register_file/src/register_file.sv deleted file mode 100755 index 7c698fb..0000000 --- a/fpga/modules/register_file/src/register_file.sv +++ /dev/null @@ -1,202 +0,0 @@ -/******************************************************************************* -# +html+
-#
-#   FILENAME: register_file.sv
-#   AUTHOR: Greg Taylor     CREATION DATE: 2 Nov 2014
-#
-#   DESCRIPTION:
-#
-#   CHANGE HISTORY:
-#   2 Nov 2014    Greg Taylor
-#       Initial version
-#
-#   Copyright (C) 2014 Greg Taylor 
-#
-#   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 .
-#
-#   Original Java Code:
-#   Copyright (C) 2008 Robson Cozendey 
-#
-#   Original C++ Code:
-#   Copyright (C) 2012  Steffen Ohrendorf 
-#
-#   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 register_file
-    import opl3_pkg::*;
-(
-    input wire clk,
-    input wire [REG_FILE_DATA_WIDTH-1:0] opl3_reg [NUM_BANKS][NUM_REG_PER_BANK],
-    input wire irq,
-    input wire ft1,
-    input wire ft2,
-    output logic [REG_TIMER_WIDTH-1:0] timer1,
-    output logic [REG_TIMER_WIDTH-1:0] timer2,
-    output logic irq_rst,
-    output logic mt1,
-    output logic mt2,
-    output logic st1,
-    output logic st2,
-    output logic [REG_CONNECTION_SEL_WIDTH-1:0] connection_sel,
-    output logic is_new,
-    output logic nts,                     // keyboard split selection
-    output logic [REG_FNUM_WIDTH-1:0] fnum [2][9],
-    output logic [REG_MULT_WIDTH-1:0] mult [2][18],
-    output logic [REG_BLOCK_WIDTH-1:0] block [2][9],
-    output logic [REG_WS_WIDTH-1:0] ws [2][18],
-    output logic vib [2][18],
-    output logic dvb,
-    output logic kon [2][9],
-    output logic [REG_ENV_WIDTH-1:0] ar [2][18], // attack rate
-    output logic [REG_ENV_WIDTH-1:0] dr [2][18], // decay rate
-    output logic [REG_ENV_WIDTH-1:0] sl [2][18], // sustain level
-    output logic [REG_ENV_WIDTH-1:0] rr [2][18], // release rate
-    output logic [REG_TL_WIDTH-1:0] tl [2][18],  // total level
-    output logic ksr [2][18],                    // key scale rate
-    output logic [REG_KSL_WIDTH-1:0] ksl [2][18], // key scale level
-    output logic egt [2][18],                     // envelope type
-    output logic am [2][18],                      // amplitude modulation (tremolo)
-    output logic dam,                             // depth of tremolo
-    output logic ryt,
-    output logic bd,
-    output logic sd,
-    output logic tom,
-    output logic tc,
-    output logic hh,
-    output logic cha [2][9],
-    output logic chb [2][9],
-    output logic chc [2][9],
-    output logic chd [2][9],
-    output logic [REG_FB_WIDTH-1:0] fb [2][9],
-    output logic cnt [2][9],
-    output logic [REG_FILE_DATA_WIDTH-1:0] status
-);
-    /*
-     * Registers that are specific to a particular bank
-     */
-    always_comb begin
-        timer1 = opl3_reg[0][2];
-        timer2 = opl3_reg[0][3];
-        irq_rst = opl3_reg[0][4][7];
-        mt1 = opl3_reg[0][4][6];
-        mt2 = opl3_reg[0][4][5];
-        st2 = opl3_reg[0][4][1];
-        st1 = opl3_reg[0][4][0];
-        connection_sel = opl3_reg[1][4][REG_CONNECTION_SEL_WIDTH-1:0];
-        is_new = opl3_reg[1][5][0];
-        nts = opl3_reg[0][8][6];
-        dam = opl3_reg[0]['hBD][7];
-        dvb = opl3_reg[0]['hBD][6];
-        ryt = opl3_reg[0]['hBD][5];
-        bd  = opl3_reg[0]['hBD][4];
-        sd  = opl3_reg[0]['hBD][3];
-        tom = opl3_reg[0]['hBD][2];
-        tc  = opl3_reg[0]['hBD][1];
-        hh  = opl3_reg[0]['hBD][0];
-    end
-
-    for (genvar bank = 0; bank < 2; bank++) begin
-        for (genvar i = 0; i < 6; i++)
-            always_comb begin
-                am[bank][i]   = opl3_reg[bank]['h20+i][7];
-                vib[bank][i]  = opl3_reg[bank]['h20+i][6];
-                egt[bank][i]  = opl3_reg[bank]['h20+i][5];
-                ksr[bank][i]  = opl3_reg[bank]['h20+i][4];
-                mult[bank][i] = opl3_reg[bank]['h20+i][3:0];
-
-                ksl[bank][i] = opl3_reg[bank]['h40+i][7:6];
-                tl[bank][i]  = opl3_reg[bank]['h40+i][5:0];
-
-                ar[bank][i] = opl3_reg[bank]['h60+i][7:4];
-                dr[bank][i] = opl3_reg[bank]['h60+i][3:0];
-
-                sl[bank][i] = opl3_reg[bank]['h80+i][7:4];
-                rr[bank][i] = opl3_reg[bank]['h80+i][3:0];
-
-                ws[bank][i] = opl3_reg[bank]['hE0+i][2:0];
-            end
-
-        for (genvar i = 8; i < 14; i++)
-            always_comb begin
-                am[bank][i-2]   = opl3_reg[bank]['h20+i][7];
-                vib[bank][i-2]  = opl3_reg[bank]['h20+i][6];
-                egt[bank][i-2]  = opl3_reg[bank]['h20+i][5];
-                ksr[bank][i-2]  = opl3_reg[bank]['h20+i][4];
-                mult[bank][i-2] = opl3_reg[bank]['h20+i][3:0];
-
-                ksl[bank][i-2] = opl3_reg[bank]['h40+i][7:6];
-                tl[bank][i-2]  = opl3_reg[bank]['h40+i][5:0];
-
-                ar[bank][i-2] = opl3_reg[bank]['h60+i][7:4];
-                dr[bank][i-2] = opl3_reg[bank]['h60+i][3:0];
-
-                sl[bank][i-2] = opl3_reg[bank]['h80+i][7:4];
-                rr[bank][i-2] = opl3_reg[bank]['h80+i][3:0];
-
-                ws[bank][i-2] = opl3_reg[bank]['hE0+i][2:0];
-            end
-
-        for (genvar i = 16; i < 22; i++)
-            always_comb begin
-                am[bank][i-4]   = opl3_reg[bank]['h20+i][7];
-                vib[bank][i-4]  = opl3_reg[bank]['h20+i][6];
-                egt[bank][i-4]  = opl3_reg[bank]['h20+i][5];
-                ksr[bank][i-4]  = opl3_reg[bank]['h20+i][4];
-                mult[bank][i-4] = opl3_reg[bank]['h20+i][3:0];
-
-                ksl[bank][i-4] = opl3_reg[bank]['h40+i][7:6];
-                tl[bank][i-4]  = opl3_reg[bank]['h40+i][5:0];
-
-                ar[bank][i-4] = opl3_reg[bank]['h60+i][7:4];
-                dr[bank][i-4] = opl3_reg[bank]['h60+i][3:0];
-
-                sl[bank][i-4] = opl3_reg[bank]['h80+i][7:4];
-                rr[bank][i-4] = opl3_reg[bank]['h80+i][3:0];
-
-                ws[bank][i-4] = opl3_reg[bank]['hE0+i][2:0];
-            end
-
-        for (genvar i = 0; i < 9; i++)
-            always_comb begin
-                fnum[bank][i][7:0] = opl3_reg[bank]['hA0+i];
-
-                kon[bank][i]       = opl3_reg[bank]['hB0+i][5];
-                block[bank][i]     = opl3_reg[bank]['hB0+i][4:2];
-                fnum[bank][i][9:8] = opl3_reg[bank]['hB0+i][1:0];
-
-                chd[bank][i] = opl3_reg[bank]['hC0+i][7];
-                chc[bank][i] = opl3_reg[bank]['hC0+i][6];
-                chb[bank][i] = opl3_reg[bank]['hC0+i][5];
-                cha[bank][i] = opl3_reg[bank]['hC0+i][4];
-
-                fb[bank][i]  = opl3_reg[bank]['hC0+i][3:1];
-                cnt[bank][i] = opl3_reg[bank]['hC0+i][0];
-            end
-    end
-    always_comb begin
-        status = 0;
-        status[7] = irq;
-        status[6] = ft1;
-        status[5] = ft2;
-    end
-endmodule
-`default_nettype wire
\ No newline at end of file
diff --git a/fpga/modules/timers/src/timers.sv b/fpga/modules/timers/src/timers.sv
index 397cc3d..1ba8128 100755
--- a/fpga/modules/timers/src/timers.sv
+++ b/fpga/modules/timers/src/timers.sv
@@ -46,20 +46,50 @@ module timers
 (
     input wire clk,
     input wire reset,
-    input wire [REG_TIMER_WIDTH-1:0] timer1,
-    input wire [REG_TIMER_WIDTH-1:0] timer2,
-    input wire irq_rst,
-    input wire mt1, // mask timer
-    input wire mt2,
-    input wire st1, // start timer
-    input wire st2,
-    output logic ft1 = 0,
-    output logic ft2 = 0,
-    output logic irq,
-    output logic irq_n = 0
+    input var opl3_reg_wr_t opl3_reg_wr,
+    output logic irq_n = 0,
+    output logic [REG_FILE_DATA_WIDTH-1:0] status
 );
+    logic [REG_TIMER_WIDTH-1:0] timer1 = 0;
+    logic [REG_TIMER_WIDTH-1:0] timer2 = 0;
+    logic irq_rst = 0;
+    logic mt1 = 0; // mask timer
+    logic mt2 = 0;
+    logic st1 = 0; // start timer
+    logic st2 = 0;
     logic timer1_overflow_pulse;
     logic timer2_overflow_pulse;
+    logic ft1 = 0;
+    logic ft2 = 0;
+    logic irq;
+
+    always_ff @(posedge clk) begin
+        if (opl3_reg_wr.valid) begin
+            if (opl3_reg_wr.bank_num == 0 && opl3_reg_wr.address == 2)
+                timer1 <= opl3_reg_wr.data;
+
+            if (opl3_reg_wr.bank_num == 0 && opl3_reg_wr.address == 3)
+                timer2 <= opl3_reg_wr.data;
+
+            if (opl3_reg_wr.bank_num == 0 && opl3_reg_wr.address == 4) begin
+                irq_rst <= opl3_reg_wr.data[7];
+                mt1 <= opl3_reg_wr.data[6];
+                mt2 <= opl3_reg_wr.data[5];
+                st2 <= opl3_reg_wr.data[1];
+                st1 <= opl3_reg_wr.data[0];
+            end
+        end
+
+        if (reset) begin
+            timer1 <= 0;
+            timer2 <= 0;
+            irq_rst <= 0;
+            mt1 <= 0;
+            mt2 <= 0;
+            st2 <= 0;
+            st1 <= 0;
+        end
+    end
 
     timer #(
         .TIMER_TICK_INTERVAL(TIMER1_TICK_INTERVAL)
@@ -97,5 +127,11 @@ module timers
     always_ff @(posedge clk)
         irq_n <= !irq;
 
+    always_comb begin
+        status = 0;
+        status[7] = irq;
+        status[6] = ft1;
+        status[5] = ft2;
+    end
 endmodule
 `default_nettype wire
\ No newline at end of file
diff --git a/fpga/modules/top_level/pkg/opl3_pkg.sv b/fpga/modules/top_level/pkg/opl3_pkg.sv
index 431bbf4..99ab531 100755
--- a/fpga/modules/top_level/pkg/opl3_pkg.sv
+++ b/fpga/modules/top_level/pkg/opl3_pkg.sv
@@ -106,4 +106,11 @@ package opl3_pkg;
         OP_TOP_CYMBAL
     } operator_t;
 
+    typedef struct packed {
+        logic valid;
+        logic bank_num;
+        logic [REG_FILE_DATA_WIDTH-1:0] address;
+        logic [REG_FILE_DATA_WIDTH-1:0] data;
+    } opl3_reg_wr_t;
+
 endpackage
diff --git a/fpga/modules/top_level/src/opl3.sv b/fpga/modules/top_level/src/opl3.sv
index dfc37b5..c87e3df 100755
--- a/fpga/modules/top_level/src/opl3.sv
+++ b/fpga/modules/top_level/src/opl3.sv
@@ -63,53 +63,11 @@ module opl3
     logic reset;
     logic sample_clk_en;
 
-    logic [REG_FILE_DATA_WIDTH-1:0] opl3_reg [NUM_BANKS][NUM_REG_PER_BANK];
-    logic [REG_TIMER_WIDTH-1:0] timer1;
-    logic [REG_TIMER_WIDTH-1:0] timer2;
-    logic irq_rst;
-    logic mt1;
-    logic mt2;
-    logic st1;
-    logic st2;
-    logic [REG_CONNECTION_SEL_WIDTH-1:0] connection_sel;
-    logic is_new;
-    logic nts;                     // keyboard split selection
-    logic [REG_FNUM_WIDTH-1:0] fnum [NUM_BANKS][NUM_CHANNELS_PER_BANK];
-    logic [REG_MULT_WIDTH-1:0] mult [NUM_BANKS][NUM_OPERATORS_PER_BANK];
-    logic [REG_BLOCK_WIDTH-1:0] block [NUM_BANKS][NUM_CHANNELS_PER_BANK];
-    logic [REG_WS_WIDTH-1:0] ws [NUM_BANKS][NUM_OPERATORS_PER_BANK];
-    logic vib [NUM_BANKS][NUM_OPERATORS_PER_BANK];
-    logic dvb;
-    logic kon [NUM_BANKS][NUM_CHANNELS_PER_BANK];
-    logic [REG_ENV_WIDTH-1:0] ar [NUM_BANKS][NUM_OPERATORS_PER_BANK]; // attack rate
-    logic [REG_ENV_WIDTH-1:0] dr [NUM_BANKS][NUM_OPERATORS_PER_BANK]; // decay rate
-    logic [REG_ENV_WIDTH-1:0] sl [NUM_BANKS][NUM_OPERATORS_PER_BANK]; // sustain level
-    logic [REG_ENV_WIDTH-1:0] rr [NUM_BANKS][NUM_OPERATORS_PER_BANK]; // release rate
-    logic [REG_TL_WIDTH-1:0] tl [NUM_BANKS][NUM_OPERATORS_PER_BANK];  // total level
-    logic ksr [NUM_BANKS][NUM_OPERATORS_PER_BANK];                    // key scale rate
-    logic [REG_KSL_WIDTH-1:0] ksl [NUM_BANKS][NUM_OPERATORS_PER_BANK]; // key scale level
-    logic egt [NUM_BANKS][NUM_OPERATORS_PER_BANK];                     // envelope type
-    logic am [NUM_BANKS][NUM_OPERATORS_PER_BANK];                      // amplitude modulation (tremolo)
-    logic dam;                             // depth of tremolo
-    logic ryt;
-    logic bd;
-    logic sd;
-    logic tom;
-    logic tc;
-    logic hh;
-    logic cha [NUM_BANKS][NUM_CHANNELS_PER_BANK];
-    logic chb [NUM_BANKS][NUM_CHANNELS_PER_BANK];
-    logic chc [NUM_BANKS][NUM_CHANNELS_PER_BANK];
-    logic chd [NUM_BANKS][NUM_CHANNELS_PER_BANK];
-    logic [REG_FB_WIDTH-1:0] fb [NUM_BANKS][NUM_CHANNELS_PER_BANK];
-    logic cnt [NUM_BANKS][NUM_CHANNELS_PER_BANK];
+    opl3_reg_wr_t opl3_reg_wr;
     logic signed [SAMPLE_WIDTH-1:0] channel_a;
     logic signed [SAMPLE_WIDTH-1:0] channel_b;
     logic signed [SAMPLE_WIDTH-1:0] channel_c;
     logic signed [SAMPLE_WIDTH-1:0] channel_d;
-    logic ft1;
-    logic ft2;
-    logic irq;
     logic [REG_FILE_DATA_WIDTH-1:0] status;
     logic channel_valid;
 
@@ -130,18 +88,14 @@ module opl3
         .*
     );
 
-    for (genvar i = 0; i < NUM_LEDS; ++i)
-        always_ff @(posedge clk)
-            led[i] <= kon[0][i];
+    // for (genvar i = 0; i < NUM_LEDS; ++i)
+    //     always_ff @(posedge clk)
+    //         led[i] <= kon[0][i];
 
     host_if host_if (
         .*
     );
 
-    register_file register_file (
-        .*
-    );
-
     /*
      * If we don't need timers, don't instantiate to save area
      */
@@ -150,11 +104,7 @@ module opl3
             .*
         );
     else
-        always_comb begin
-            ft1 = 0;
-            ft2 = 0;
-            irq = 0;
+        always_comb
             irq_n = 1;
-        end
 endmodule
 `default_nettype wire