mirror of
https://github.com/Gehstock/Mist_FPGA.git
synced 2026-02-08 17:11:24 +00:00
483 lines
14 KiB
Systemverilog
483 lines
14 KiB
Systemverilog
`timescale 1ns / 1ps
|
|
//////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// This file is part of the Next186 Soc PC project
|
|
// http://opencores.org/project,next186
|
|
//
|
|
// Filename: opl3seq.v
|
|
// Description: Part of the Next186 SoC PC project, OPL3 Sequencer
|
|
// Version 1.0
|
|
// Creation date: 13:55:57 02/27/2017
|
|
//
|
|
// Author: Nicolae Dumitrache
|
|
// e-mail: ndumitrache@opencores.org
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Copyright (C) 2017 Nicolae Dumitrache
|
|
//
|
|
// This source file may be used and distributed without
|
|
// restriction provided that this copyright statement is not
|
|
// removed from the file and that any derivative work contains
|
|
// the original copyright notice and the associated disclaimer.
|
|
//
|
|
// This source file 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 2.1 of the License, or (at your option) any
|
|
// later version.
|
|
//
|
|
// This source 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 this source; if not, download it
|
|
// from http://www.opencores.org/lgpl.shtml
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////////////
|
|
// Additional Comments:
|
|
//
|
|
// It shares OPL3 structure (~1.7KB DP RAM) with the main processor. It drives 36 operators at 44100Hz, with at least 45Mhz clock
|
|
///////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// altera message_off 10030
|
|
|
|
|
|
`define LFO_AM_TAB_ELEMENTS 210
|
|
`define phase_modulation_o 0 // CH18
|
|
`define panA_o 6'd4 // CH18
|
|
`define panB_o 6'd8 // CH18
|
|
`define lfo_am_depth_o 12 // CH18
|
|
`define block_fnum_o 44 // SLOT0
|
|
`define chanout_o 6'd46 // SLOT0
|
|
|
|
`define Cnt_o 6'd4
|
|
`define Incr_o 6'd8
|
|
`define op1_out_o 6'd12
|
|
`define state_o 18
|
|
`define AMmask_o 20
|
|
`define volume_o 22
|
|
`define FB_o 24
|
|
`define mul_o 30
|
|
`define sl_o 32
|
|
`define vib_o 34
|
|
`define connect_o 36
|
|
`define eg_sh_ar_o 38
|
|
`define eg_sh_dr_o 40
|
|
`define eg_sh_rr_o 42
|
|
|
|
module opl3seq
|
|
(
|
|
input clk,
|
|
input reset,
|
|
input rd, // clk synchronous pulse, read only while <ready> == 1
|
|
output reg [15:0] A,
|
|
output reg [15:0] B,
|
|
output reg ready,
|
|
output reg ram_wr,
|
|
output [11:0] ram_addr,
|
|
input [15:0] ram_rdata,
|
|
output reg [15:0] ram_wdata
|
|
);
|
|
|
|
reg [13:0]lfo_am_cnt = 0;
|
|
reg [4:0]r_lfo_am_cnt = 0;
|
|
wire [13:0]lfo_am_cnt1 = lfo_am_cnt + 1'b1;
|
|
reg [9:0]lfo_pm_cnt = 0;
|
|
reg [4:0]LFO_AM; // unsigned
|
|
reg [3:0]LFO_PM = 0; // unsigned
|
|
|
|
reg [5:0]STATE = 0;
|
|
reg [5:0]nextSTATE;
|
|
reg [5:0]RET;
|
|
reg [5:0]ram_offset; // OPL3Struct_base + (CHindex*96 + OPindex*48 + offset)
|
|
reg [4:0]ram_CHindex;
|
|
reg [4:0]s_ram_CHindex;
|
|
wire s_ram_CHindex17 = s_ram_CHindex == 17;
|
|
wire s_ram_CHindex18 = s_ram_CHindex == 18;
|
|
wire [4:0]s_ram_CHindex1 = s_ram_CHindex + 1'b1;
|
|
reg ram_OPindex;
|
|
reg s_ram_OPindex;
|
|
reg [15:0]ram_rdata_lo;
|
|
reg [15:0]eg_cnt = 0;
|
|
// reg [22:0]noise_rng = 1;
|
|
reg [9:0]env;
|
|
reg [12:0]sinaddr;
|
|
reg [12:0]r_sinaddr;
|
|
wire [12:0]op_calc1;
|
|
wire signed [15:0]op_calc = {{3{op_calc1[12]}}, op_calc1};
|
|
reg [15:0]tmp1;
|
|
wire [13:0]outshift1 = $signed(tmp1[13:0]) >>> ram_rdata[3:0];
|
|
wire [9:0]outshift = |ram_rdata[3:0] ? outshift1[9:0] : 10'b0000000000;
|
|
reg [17:0]pan;
|
|
reg signed [18:0]rAcc;
|
|
wire [15:0]limAcc = rAcc > 32767 ? 16'h7fff : rAcc < -32768 ? 16'h8000 : rAcc[15:0]; // (~|rAcc[18:15] | &rAcc[18:15]) ? rAcc[15:0] : {rAcc[18], {15{!rAcc[18]}}};
|
|
reg [11:0]phmask;// = (1'b1 << ram_rdata[3:0]) - 1'b1;
|
|
wire phtest = ~|(eg_cnt & phmask);
|
|
reg cond;
|
|
wire [15:0]eg_inc1 = eg_cnt >> ram_rdata[3:0];
|
|
wire [6:0]eg_inc = ram_rdata[14:8] + eg_inc1[2:0];
|
|
reg [2:0]r_eg_inc;
|
|
wire [9:0]volume_attack1 = $signed(~ram_rdata[9:0]) >>> (~r_eg_inc[1:0]);
|
|
wire [9:0]volume_attack = {1'b0, ram_rdata[8:0]} + (r_eg_inc[2] ? 10'h000 : volume_attack1);
|
|
reg [9:0]r_volume;
|
|
wire [2:0]exp_r_eg_inc = 3'b1 << r_eg_inc;
|
|
wire [9:0]volume_dsr = ram_rdata[8:0] + exp_r_eg_inc; // new volume for decay/sustain/release
|
|
reg signed [3:0]lfo_fn_table_index_offset;
|
|
reg [11:0]inc_hi;
|
|
reg [15:0]inc_lo;
|
|
reg carry = 1'b0;
|
|
reg cy;
|
|
reg [2:0]phase;
|
|
wire [25:0]mul1 = tmp1[9:0] * ram_rdata_lo;
|
|
|
|
// tmp1 adder
|
|
reg [3:0]tmp1op;
|
|
reg [15:0]tmp1op1;
|
|
reg [15:0]tmp1op2;
|
|
|
|
// .addrb(OPL3Struct_offset + {1'b1, ram_CHindex, ram_OPindex, ram_offset[5:1]})
|
|
assign ram_addr = (ram_OPindex ? 12'd24 : 12'd0) + {ram_CHindex + {ram_CHindex, ram_offset[5]}, ram_offset[4:1]};
|
|
|
|
wire [4:0] lfo_am_table [`LFO_AM_TAB_ELEMENTS] = '{
|
|
0,0,0,0,0,0,0, 1,1,1,1, 2,2,2,2, 3,3,3,3, 4,4,4,4, 5,5,5,5, 6,6,6,6, 7,7,7,7, 8,8,8,8, 9,9,9,9, 10,10,10,10, 11,11,11,11, 12,12,12,12, 13,13,13,13, 14,14,14,14,
|
|
15,15,15,15, 16,16,16,16, 17,17,17,17, 18,18,18,18, 19,19,19,19, 20,20,20,20, 21,21,21,21, 22,22,22,22, 23,23,23,23, 24,24,24,24, 25,25,25,25, 26,26,26, 25,25,25,25,
|
|
24,24,24,24, 23,23,23,23, 22,22,22,22, 21,21,21,21, 20,20,20,20, 19,19,19,19, 18,18,18,18, 17,17,17,17, 16,16,16,16, 15,15,15,15, 14,14,14,14, 13,13,13,13, 12,12,12,12,
|
|
11,11,11,11, 10,10,10,10, 9,9,9,9, 8,8,8,8, 7,7,7,7, 6,6,6,6, 5,5,5,5, 4,4,4,4, 3,3,3,3, 2,2,2,2, 1,1,1,1
|
|
};
|
|
|
|
wire signed [3:0]lfo_pm_table[128] = '{
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,-1, 0, 0, 0, 1, 0, 0, 0,-1, 0, 0, 0, 2, 1, 0,-1,-2,-1, 0, 1, 1, 0, 0, 0,-1, 0, 0, 0, 3, 1, 0,-1,-3,-1, 0, 1,
|
|
2, 1, 0,-1,-2,-1, 0, 1, 4, 2, 0,-2,-4,-2, 0, 2, 2, 1, 0,-1,-2,-1, 0, 1, 5, 2, 0,-2,-5,-2, 0, 2, 3, 1, 0,-1,-3,-1, 0, 1, 6, 3, 0,-3,-6,-3, 0, 3, 3, 1, 0,-1,-3,-1, 0, 1, 7, 3, 0,-3,-7,-3, 0, 3
|
|
};
|
|
|
|
wire [2:0]eg_inc_tab[120] = '{
|
|
4,0, 4,0, 4,0, 4,0, 4,0, 4,0, 0,0, 4,0, 4,0, 0,0, 4,0, 0,0, 4,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,1, 0,0, 0,2, 0,1, 0,1, 0,1, 0,1,
|
|
0,1, 1,1, 0,1, 1,1, 1,1, 1,1, 1,1, 1,1, 1,1, 1,2, 1,1, 1,2, 1,2, 1,2, 1,2, 1,2, 1,2, 2,2, 1,2, 2,2, 2,2, 2,2, 2,2, 2,2, 3,3, 3,3, 3,3, 3,3, 4,4, 4,4, 4,4, 4,4
|
|
}; // log tablle, 4 = log(0)
|
|
|
|
|
|
sampler sampler_inst
|
|
(
|
|
.clk(clk),
|
|
.index(r_sinaddr),
|
|
.ampl(env[8:0]),
|
|
.sample(op_calc1)
|
|
);
|
|
|
|
always @(posedge clk) begin
|
|
STATE <= nextSTATE;
|
|
s_ram_CHindex <= ram_CHindex;
|
|
s_ram_OPindex <= ram_OPindex;
|
|
r_sinaddr <= sinaddr;
|
|
r_lfo_am_cnt <= lfo_am_table[lfo_am_cnt[13:6]];
|
|
ram_rdata_lo <= ram_rdata;
|
|
r_eg_inc <= eg_inc_tab[eg_inc];
|
|
lfo_fn_table_index_offset <= lfo_pm_table[{ram_rdata[9:7], LFO_PM}]; //34
|
|
{carry, tmp1} <= tmp1op1 + tmp1op2 + cy;
|
|
pan <= pan >> 1;
|
|
if(pan[0]) rAcc <= rAcc + {{3{ram_rdata[15]}}, ram_rdata};
|
|
|
|
if(reset) STATE <= 0;
|
|
else
|
|
case(STATE)
|
|
0: begin
|
|
if(lfo_am_cnt1[13:6] == `LFO_AM_TAB_ELEMENTS) lfo_am_cnt <= 14'h0000;
|
|
else lfo_am_cnt <= lfo_am_cnt1;
|
|
{LFO_PM[2:0], lfo_pm_cnt} <= {LFO_PM[2:0], lfo_pm_cnt} + 1'b1;
|
|
eg_cnt <= eg_cnt + 1'b1;
|
|
// noise_rng <= {noise_rng[0], noise_rng[22:1]} ^ (noise_rng[0] ? 9'h181 : 9'h000);
|
|
end
|
|
1: begin
|
|
LFO_AM <= r_lfo_am_cnt >> {!ram_rdata[0], 1'b0};
|
|
LFO_PM[3] <= ram_rdata[11];
|
|
RET <= 3;
|
|
end
|
|
2: s_ram_CHindex <= s_ram_CHindex17 ? 5'd0 : s_ram_CHindex1;
|
|
3: s_ram_CHindex <= s_ram_CHindex;
|
|
7: RET <= 8;
|
|
8: begin
|
|
s_ram_CHindex <= s_ram_CHindex;
|
|
RET <= 18;
|
|
end
|
|
10: s_ram_OPindex <= 1'b1;
|
|
13: env <= ram_rdata_lo[9:0] + ram_rdata[8:0] + (ram_rdata_lo[15] ? LFO_AM : 10'd0); // env = volume_calc(SLOT1);
|
|
15: {s_ram_CHindex, s_ram_OPindex} <= {s_ram_CHindex, s_ram_OPindex};
|
|
17: {s_ram_CHindex, s_ram_OPindex} <= {s_ram_CHindex, s_ram_OPindex};
|
|
18: s_ram_CHindex <= s_ram_CHindex1;
|
|
20: begin
|
|
pan <= {ram_rdata[1:0], ram_rdata_lo};
|
|
s_ram_CHindex <= 1;
|
|
rAcc <= 0;
|
|
end
|
|
21: s_ram_CHindex <= s_ram_CHindex18 ? s_ram_CHindex : s_ram_CHindex1;
|
|
22: A <= limAcc;
|
|
23: begin
|
|
pan <= {ram_rdata[1:0], ram_rdata_lo};
|
|
s_ram_CHindex <= 1;
|
|
rAcc <= 0;
|
|
end
|
|
24: s_ram_CHindex <= s_ram_CHindex18 ? 5'd0 : s_ram_CHindex1;
|
|
25: B <= limAcc;
|
|
|
|
// advance
|
|
27: cond <= phtest;
|
|
28: r_volume <= tmp1[2] ? volume_attack : volume_dsr;
|
|
29: if(r_volume[9]) r_volume <= (tmp1[2:0] < 3) ? 10'd511 : 10'd0;
|
|
|
|
// phase gen
|
|
32: inc_lo <= ram_rdata;
|
|
33: begin
|
|
inc_hi <= ram_rdata[11:0];
|
|
s_ram_OPindex <= s_ram_OPindex;
|
|
end
|
|
35: cond <= |lfo_fn_table_index_offset;
|
|
36: if(cond && ram_rdata[0]) {inc_hi, inc_lo} <= {mul1, 2'b00} >> ~tmp1[12:10];
|
|
37,38: inc_lo <= {4'b0000, inc_hi};
|
|
39: begin
|
|
s_ram_OPindex <= !s_ram_OPindex;
|
|
if(s_ram_OPindex) s_ram_CHindex <= s_ram_CHindex1;
|
|
end
|
|
endcase
|
|
end
|
|
|
|
always @(*) begin
|
|
ram_offset = 6'b000000;
|
|
ram_CHindex = s_ram_CHindex;
|
|
ram_OPindex = s_ram_OPindex;
|
|
ram_wdata = 16'h0000;
|
|
ram_wr = 1'b0;
|
|
nextSTATE = STATE + 1'b1;
|
|
sinaddr = r_sinaddr;
|
|
tmp1op = 4'b1111; // tmp1 <= tmp1, carry <= 0
|
|
cy = 1'b0;
|
|
ready = 1'b0;
|
|
|
|
case(STATE)
|
|
0: begin
|
|
ram_offset = `lfo_am_depth_o;
|
|
ram_CHindex = 18;
|
|
ram_OPindex = 0;
|
|
end
|
|
1: ram_CHindex = 0;
|
|
2: begin
|
|
ram_offset = `chanout_o;
|
|
ram_wr = 1'b1;
|
|
nextSTATE = s_ram_CHindex17 ? 6'd3 : 6'd2;
|
|
end
|
|
|
|
// chan_calc
|
|
3: begin // chip.phase_modulation = 0;
|
|
ram_CHindex = 18;
|
|
ram_offset = `phase_modulation_o;
|
|
ram_wr = 1'b1;
|
|
end
|
|
4: ram_offset = `op1_out_o; // op1_out[0]
|
|
5: ram_offset = `op1_out_o+6'd2; // op1_out[1]
|
|
6: begin
|
|
ram_offset = `FB_o; // read {FB, wavetable, x, x}
|
|
tmp1op = 4'b0000; // tmp1 <= ram_rdata + ram_rdata_lo; // out = SLOT1->op1_out[0] + SLOT1->op1_out[1];
|
|
end
|
|
7: begin // SLOT->op1_out[0] = SLOT->op1_out[1];
|
|
ram_offset = `op1_out_o;
|
|
ram_wdata = ram_rdata_lo;
|
|
ram_wr = 1'b1;
|
|
sinaddr = {ram_rdata[10:8], outshift}; // wavetable, out>>FB
|
|
nextSTATE = 11; // call
|
|
end
|
|
|
|
8: begin
|
|
ram_CHindex = 18;
|
|
ram_offset = `phase_modulation_o;
|
|
end
|
|
9: begin
|
|
ram_offset = `FB_o; // read {FB, wavetable, x, x}
|
|
ram_OPindex = 1;
|
|
end
|
|
10: begin // SLOT->op1_out[1] = op_calc
|
|
ram_offset = `op1_out_o+6'd2;
|
|
ram_OPindex = 0;
|
|
ram_wdata = tmp1;
|
|
ram_wr = 1'b1;
|
|
sinaddr = {ram_rdata[10:8], ram_rdata_lo[9:0]}; // wavetable, phase_modulation
|
|
end
|
|
11: ram_offset = `AMmask_o; // read {TLL, AMmask}
|
|
12: ram_offset = `volume_o; // read volume[15:0]
|
|
13: ram_offset = `Cnt_o+6'd2;
|
|
14: begin
|
|
ram_offset = `connect_o;
|
|
sinaddr[9:0] = sinaddr[9:0] + ram_rdata[9:0];
|
|
if(env >= 416) nextSTATE = RET;
|
|
end
|
|
15: {ram_CHindex, ram_OPindex, ram_offset} = ram_rdata[11:0];
|
|
16: ram_offset = `connect_o;
|
|
17: begin
|
|
{ram_CHindex, ram_OPindex, ram_offset} = ram_rdata[11:0];
|
|
ram_wdata = ram_rdata_lo + op_calc;//tmp1;
|
|
ram_wr = 1'b1;
|
|
nextSTATE = RET;
|
|
tmp1op = 4'b1110; // tmp1 <= op_calc;
|
|
end
|
|
18: begin
|
|
ram_offset = `panA_o;
|
|
ram_OPindex = 0;
|
|
ram_CHindex = 18;
|
|
nextSTATE = s_ram_CHindex17 ? 6'd19 : 6'd3;
|
|
end
|
|
|
|
19: ram_offset = `panA_o+6'd2;
|
|
20: begin
|
|
ram_offset = `chanout_o;
|
|
ram_CHindex = 0;
|
|
end
|
|
21: begin
|
|
ram_offset = s_ram_CHindex18 ? `panB_o : `chanout_o;
|
|
nextSTATE = s_ram_CHindex18 ? 6'd22 : 6'd21;
|
|
end
|
|
22: ram_offset = `panB_o+6'd2;
|
|
23: begin
|
|
ram_offset = `chanout_o;
|
|
ram_CHindex = 0;
|
|
end
|
|
24: begin
|
|
ram_offset = `chanout_o;
|
|
nextSTATE = s_ram_CHindex18 ? 6'd25 : 6'd24;
|
|
end
|
|
|
|
// envelope
|
|
25: ram_offset = `state_o;
|
|
26: begin
|
|
case(ram_rdata[2:0])
|
|
3'd1: ram_offset = `eg_sh_rr_o; // release phase
|
|
3'd2: begin // sustain phase
|
|
ram_offset = `eg_sh_rr_o;
|
|
if(ram_rdata[8]) nextSTATE = 31; // if (!op->eg_type)
|
|
end
|
|
3'd3: ram_offset = `eg_sh_dr_o; // decay phase
|
|
3'd4: ram_offset = `eg_sh_ar_o; // attack phase
|
|
default: nextSTATE = 31;
|
|
endcase
|
|
tmp1op = 4'b1100; // tmp1 <= ram_rdata; // {eg_type, state}
|
|
end
|
|
|
|
27: ram_offset = `volume_o;
|
|
28: ram_offset = `sl_o;
|
|
29: begin
|
|
ram_offset = `state_o;
|
|
ram_wdata = tmp1;
|
|
case(tmp1[1:0])
|
|
2'b00: if(r_volume[9]) ram_wdata[2:0] = 3'd3; // attack
|
|
2'b11: if(r_volume >= {1'b0, ram_rdata[8:0]}) ram_wdata[2:0] = 3'd2; // decay
|
|
2'b10:; // sustain
|
|
2'b01: if(r_volume[9]) ram_wdata[2:0] = 3'd0; // release
|
|
endcase
|
|
ram_wr = cond;
|
|
end
|
|
30: begin
|
|
ram_offset = `volume_o;
|
|
ram_wdata[9:0] = r_volume;
|
|
ram_wr = cond;
|
|
end
|
|
|
|
// phase gen
|
|
31: ram_offset = `Incr_o;
|
|
32: ram_offset = `Incr_o+6'd2;
|
|
|
|
33: begin
|
|
ram_offset = `block_fnum_o;
|
|
ram_OPindex = 0;
|
|
end
|
|
34: ram_offset = `mul_o;
|
|
35: begin
|
|
ram_offset = `vib_o;
|
|
tmp1op = 4'b0001; //tmp1 <= ram_rdata_lo + lfo_fn_table_index_offset;
|
|
end
|
|
36: ram_offset = `Cnt_o;
|
|
37: begin
|
|
ram_offset = `Cnt_o+6'd2;
|
|
tmp1op = 4'b0100; //{carry, tmp1} <= inc_lo + ram_rdata;
|
|
end
|
|
38: begin
|
|
ram_offset = `Cnt_o;
|
|
ram_wdata = tmp1;
|
|
ram_wr = 1'b1;
|
|
tmp1op = 4'b0100; //{carry, tmp1} <= inc_lo + ram_rdata + carry;
|
|
cy = carry;
|
|
end
|
|
39: begin
|
|
ram_offset = `Cnt_o+6'd2;
|
|
ram_wdata = tmp1;
|
|
ram_wr = 1'b1;
|
|
if(!(s_ram_CHindex17 && s_ram_OPindex)) nextSTATE = 6'd25;
|
|
end
|
|
|
|
default: begin
|
|
ready = 1'b1;
|
|
nextSTATE = rd ? 6'd0 : 6'd40;
|
|
end
|
|
|
|
endcase
|
|
|
|
case(tmp1op[1:0])
|
|
2'b00: tmp1op1 = ram_rdata;
|
|
2'b01: tmp1op1 = lfo_fn_table_index_offset;
|
|
2'b10: tmp1op1 = op_calc;
|
|
2'b11: tmp1op1 = tmp1;
|
|
endcase
|
|
|
|
case(tmp1op[3:2])
|
|
2'b00: tmp1op2 = ram_rdata_lo;
|
|
2'b01: tmp1op2 = inc_lo;
|
|
default: tmp1op2 = 16'h0000;
|
|
endcase
|
|
|
|
case(ram_rdata[3:0]) // ((1 << ram_rdata[3:0]) - 1)[11:0]
|
|
4'h0: phmask = 12'h000;
|
|
4'h1: phmask = 12'h001;
|
|
4'h2: phmask = 12'h003;
|
|
4'h3: phmask = 12'h007;
|
|
4'h4: phmask = 12'h00f;
|
|
4'h5: phmask = 12'h01f;
|
|
4'h6: phmask = 12'h03f;
|
|
4'h7: phmask = 12'h07f;
|
|
4'h8: phmask = 12'h0ff;
|
|
4'h9: phmask = 12'h1ff;
|
|
4'ha: phmask = 12'h3ff;
|
|
4'hb: phmask = 12'h7ff;
|
|
default: phmask = 12'hfff;
|
|
endcase
|
|
end
|
|
|
|
endmodule
|
|
|
|
module sampler
|
|
(
|
|
input clk,
|
|
input [12:0] index,
|
|
input [8:0] ampl,
|
|
output [12:0] sample
|
|
);
|
|
|
|
reg [15:0] sin_tab[8191:0];
|
|
initial $readmemh("sin_tab_full.mem", sin_tab);
|
|
|
|
reg [15:0] exp_tab[6655:0];
|
|
initial $readmemh("exp_tab.mem", exp_tab);
|
|
|
|
reg [15:0] logsin;
|
|
wire [13:0] ilog = logsin[13:0] + {ampl, 4'b0000};
|
|
reg log_rng;
|
|
reg [15:0] isample;
|
|
assign sample = log_rng ? isample[12:0] : 13'd0;
|
|
|
|
always @(posedge clk) begin
|
|
logsin <= sin_tab[index];
|
|
log_rng <= ilog < 6656;
|
|
isample <= exp_tab[ilog[12:0]];
|
|
end
|
|
|
|
endmodule
|