/*
|
/*
|
SQmusic
|
SQmusic
|
|
|
(c) Jose Tejada Gomez, 9th May 2013
|
(c) Jose Tejada Gomez, 9th May 2013
|
You can use this file following the GNU GENERAL PUBLIC LICENSE version 3
|
You can use this file following the GNU GENERAL PUBLIC LICENSE version 3
|
Read the details of the license in:
|
Read the details of the license in:
|
http://www.gnu.org/licenses/gpl.txt
|
http://www.gnu.org/licenses/gpl.txt
|
|
|
Send comments to: jose.tejada@ieee.org
|
Send comments to: jose.tejada@ieee.org
|
|
|
*/
|
*/
|
|
|
`timescale 1ns/1ps
|
`timescale 1ns/1ps
|
|
|
module sq_slot(
|
module sq_slot(
|
input clk,
|
input clk,
|
input reset_n,
|
input reset_n,
|
input [10:0] fnumber,
|
input [10:0] fnumber,
|
input [2:0] block,
|
input [2:0] block,
|
input [3:0] multiple
|
input [3:0] multiple,
|
|
output [12:0] linear
|
);
|
);
|
|
|
wire [9:0]phase;
|
wire [9:0]phase;
|
wire [12:0] sin_log, sin_linear;
|
wire [12:0] sin_log, sin_linear;
|
|
|
sq_pg pg(
|
sq_pg pg(
|
.clk (clk),
|
.clk (clk),
|
.reset_n (reset_n),
|
.reset_n (reset_n),
|
.fnumber (fnumber),
|
.fnumber (fnumber),
|
.block (block),
|
.block (block),
|
.multiple(multiple),
|
.multiple(multiple),
|
.phase (phase) );
|
.phase (phase) );
|
|
|
sq_sin sin(
|
sq_sin sin(
|
.clk (clk),
|
.clk (clk),
|
.reset_n (reset_n),
|
.reset_n (reset_n),
|
.phase (phase),
|
.phase (phase),
|
.val (sin_log) );
|
.val (sin_log) );
|
|
|
sq_pow pow(
|
sq_pow pow(
|
.clk (clk),
|
.clk (clk),
|
.reset_n (reset_n),
|
.reset_n (reset_n),
|
.x (sin_log),
|
.x (sin_log),
|
.y (sin_linear) );
|
.y (linear) );
|
|
|
endmodule
|
endmodule
|
|
|
module sq_pg(
|
module sq_pg(
|
input clk,
|
input clk,
|
input reset_n,
|
input reset_n,
|
input [10:0] fnumber,
|
input [10:0] fnumber,
|
input [2:0] block,
|
input [2:0] block,
|
input [3:0] multiple,
|
input [3:0] multiple,
|
output [9:0]phase );
|
output [9:0]phase );
|
|
|
reg [19:0] count;
|
reg [19:0] count;
|
assign phase = count[19:10];
|
assign phase = count[19:10];
|
|
|
wire [19:0]fmult = fnumber << block;
|
wire [19:0]fmult = fnumber << block;
|
|
|
always @(posedge clk or negedge reset_n ) begin
|
always @(posedge clk or negedge reset_n ) begin
|
if( !reset_n )
|
if( !reset_n )
|
count <= 20'b0;
|
count <= 20'b0;
|
else begin
|
else begin
|
count <= count + ( multiple==4'b0 ? fmult>> 1 : fmult*multiple);
|
count <= count + ( multiple==4'b0 ? fmult>> 1 : fmult*multiple);
|
end
|
end
|
end
|
end
|
|
|
endmodule
|
endmodule
|
|
|
///////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////
|
module sq_sin(
|
module sq_sin(
|
input clk,
|
input clk,
|
input reset_n,
|
input reset_n,
|
input [9:0]phase,
|
input [9:0]phase,
|
output [12:0] val // LSB is the sign. 0=positive, 1=negative
|
output [12:0] val // LSB is the sign. 0=positive, 1=negative
|
);
|
);
|
|
|
reg [12:0] sin_table[1023:0];
|
reg [12:0] sin_table[1023:0];
|
|
|
initial begin
|
initial begin
|
$readmemh("../tables/sin_table.hex", sin_table);
|
$readmemh("../tables/sin_table.hex", sin_table);
|
end
|
end
|
reg [9:0]last_phase;
|
reg [9:0]last_phase;
|
assign val = sin_table[last_phase];
|
assign val = sin_table[last_phase];
|
|
|
always @(posedge clk or negedge reset_n ) begin
|
always @(posedge clk or negedge reset_n ) begin
|
if( !reset_n )
|
if( !reset_n )
|
last_phase <= 10'b0;
|
last_phase <= 10'b0;
|
else begin
|
else begin
|
last_phase <= phase;
|
last_phase <= phase;
|
end
|
end
|
end
|
end
|
endmodule
|
endmodule
|
///////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////
|
// sq_pow => reverse the log2 conversion
|
// sq_pow => reverse the log2 conversion
|
module sq_pow(
|
module sq_pow(
|
input clk,
|
input clk,
|
input reset_n,
|
input reset_n,
|
input [12:0]x,
|
input rd_n, // read enable, active low
|
output [12:0]y // LSB is the sign. 0=positive, 1=negative
|
input [12:0]x, // LSB is the sign. 0=positive, 1=negative
|
|
output reg [12:0]y
|
);
|
);
|
|
|
|
parameter st_input = 3'b000;
|
|
parameter st_lut_read = 3'b001;
|
|
parameter st_shift = 3'b010;
|
|
parameter st_sign = 3'b011;
|
|
parameter st_output = 3'b100;
|
|
|
|
reg [2:0] state;
|
reg [12:0] pow_table[255:0];
|
reg [12:0] pow_table[255:0];
|
|
|
initial begin
|
initial begin
|
$readmemh("../tables/pow_table.hex", pow_table);
|
$readmemh("../tables/pow_table.hex", pow_table);
|
end
|
end
|
reg [7:0]index;
|
reg [7:0]index;
|
reg [2:0]exp;
|
reg [3:0]exp;
|
reg sign;
|
reg sign;
|
|
|
wire [12:0] raw = pow_table[index] >> exp;
|
reg [12:0] raw, shifted, final;
|
assign y = sign ? ~raw+13'b1 : raw; // regular 2's complement
|
|
|
|
always @(posedge clk or negedge reset_n ) begin
|
always @(posedge clk or negedge reset_n ) begin
|
if( !reset_n ) begin
|
if( !reset_n ) begin
|
index <= 8'b0;
|
index <= 8'b0;
|
exp <= 3'b0;
|
exp <= 3'b0;
|
sign <= 1'b0;
|
sign <= 1'b0;
|
|
raw <= 13'b0;
|
|
shifted <= 13'b0;
|
|
y <= 12'b0;
|
|
state <= st_input;
|
end
|
end
|
else begin
|
else begin
|
exp <= x[12:10];
|
case ( state )
|
index <= x[9:1];
|
st_input: begin
|
|
if( !rd_n ) begin
|
|
exp <= x[12:9];
|
|
index <= x[8:1];
|
sign <= x[0];
|
sign <= x[0];
|
|
state <= st_lut_read;
|
|
end
|
|
else state <= st_lut_read;
|
|
end
|
|
st_lut_read: begin
|
|
raw <= pow_table[index];
|
|
state <= st_shift;
|
|
end
|
|
st_shift: begin
|
|
shifted <= raw >> exp;
|
|
state <= st_sign;
|
|
end
|
|
st_sign: begin
|
|
final <= sign ? ~shifted + 1'b1 : shifted;
|
|
state <= st_output;
|
|
end
|
|
st_output: begin
|
|
y <= final;
|
|
state <= st_input;
|
|
end
|
|
endcase
|
end
|
end
|
end
|
end
|
|
|
|
always @(posedge clk or negedge reset_n ) begin
|
|
if( !reset_n )
|
|
raw <= 13'b0;
|
|
else
|
|
raw <= pow_table[index];
|
|
end
|
|
|
|
always @(posedge clk or negedge reset_n ) begin
|
|
if( !reset_n )
|
|
shifted <= 13'b0;
|
|
else
|
|
shifted <= raw >> exp;
|
|
end
|
|
|
endmodule
|
endmodule
|
|
|