URL
https://opencores.org/ocsvn/two_dimensional_fast_hartley_transform/two_dimensional_fast_hartley_transform/trunk
Subversion Repositories two_dimensional_fast_hartley_transform
Compare Revisions
- This comparison shows the changes necessary to convert path
/two_dimensional_fast_hartley_transform/trunk
- from Rev 1 to Rev 2
- ↔ Reverse comparison
Rev 1 → Rev 2
/fht_bfly.v
0,0 → 1,115
// |
// File: fht_8x8_core.v |
// Author: Ivan Rezki |
// Topic: RTL Core |
// 2-Dimensional Fast Hartley Transform |
// |
|
// Fast Hartley Transform ButterFly Unit |
|
module fht_bfly( |
rstn, |
clk, |
valid, |
a, |
b, |
c, |
d |
); |
|
parameter N = 8; |
|
input rstn; |
input clk; |
|
input valid; |
|
input [N-1:0] a; // input |
input [N-1:0] b; // input |
|
output [N :0] c; // additive output |
output [N :0] d; // subtractive output |
|
reg [N-1:0] a_FF; |
always @(posedge clk) |
if (!rstn) a_FF <= #1 0; |
else if (valid) a_FF <= #1 a; |
|
reg [N-1:0] b_FF; |
always @(posedge clk) |
if (!rstn) b_FF <= #1 0; |
else if (valid) b_FF <= #1 b; |
|
assign c = rca_N(a_FF,b_FF); |
assign d = rca_N(a_FF,twos_complement(b_FF)); |
|
// +--------------------------------------------------+ \\ |
// +----------- Function's Description Part ----------+ \\ |
// +--------------------------------------------------+ \\ |
// Full Adder |
function [1:0] full_adder; |
input a, b, ci; |
reg co, s; |
begin |
s = (a ^ b ^ ci); |
co = (a & b) | (ci & (a ^ b)); |
full_adder = {co,s}; |
end |
endfunction |
|
// Half Adder, i.e. without carry in |
function [1:0] half_adder; |
input a, b; |
reg co, s; |
begin |
s = (a ^ b); |
co = (a & b); |
half_adder = {co,s}; |
end |
endfunction |
|
// Ripple Carry Adder - rca |
// Input vector = N bits |
// Output vector = N + 1 bits |
function [N:0] rca_N; |
|
// parameter N = 8; |
input [N-1:0] a; |
input [N-1:0] b; |
|
reg [N-1:0] co,sum; |
|
begin : RCA // RIPPLE_CARRY_ADDER |
integer i; |
//for (i = 0; i <= N; i = i + 1) |
for (i = 0; i < N; i = i + 1) |
if (i == 0) |
{co[i],sum[i]} = half_adder(a[i],b[i]); |
else |
{co[i],sum[i]} = full_adder(a[i],b[i],co[i-1]); |
|
rca_N[N-1:0] = sum; |
// MSB is a sign bit |
rca_N[N] = (a[N-1]==b[N-1]) ? co[N-1] : sum[N-1]; |
end |
endfunction |
|
|
function [N-1:0] twos_complement; |
input [N-1:0] a; |
reg [N-1:0] ainv; |
reg [N:0] plus1; |
begin |
ainv = ~a; |
plus1 = rca_N(ainv,{{N-1{1'b0}},1'b1}); |
|
// synopsys translate_off |
// The only problem is absolute minumum negative value |
if (a == {1'b1, {N-1{1'b0}}}) $display("--->>> 2's complement ERROR - absolute minumum negative value"); |
// synopsys translate_on |
|
twos_complement = plus1[N-1:0]; |
end |
endfunction |
|
endmodule |
/mtx_trps_8x8_dpsram.v
0,0 → 1,128
// |
// File: mtx_trps_8x8_dpsram.v |
// Author: Ivan Rezki |
// Topic: RTL Core |
// 2-Dimensional Fast Hartley Transform |
// |
|
// Matrix Transpose 8x8 |
// DPSRAM-based Double Buffer |
// Buffer size is 64*2 words, each word is 16 bits |
|
// Matrix Transpose -> 64 clk delay |
// - Double Buffer Solution: |
|
|
module mtx_trps_8x8_dpsram ( |
rstn, |
sclk, |
|
// Input |
inp_valid, |
inp_data, |
|
// Output |
mem_data, |
mem_valid |
); |
parameter N = 8; |
|
input rstn; |
input sclk; |
|
input inp_valid; |
input [N-1:0] inp_data; |
|
output [N-1:0] mem_data; |
output mem_valid; |
|
reg [6:0] cnt128d_wr; // Write Mode Counter |
wire indicator; // 64 words written - Indication(pos. or neg. edge) |
reg indicator_1d; // Indication 1 clock delay |
wire indicator_pos_edge; // positive edge |
wire indicator_neg_edge; // negative edge |
reg [6:0] cnt128d_rd; // Read Counter |
wire cnt128d_rd_valid_start; // Counter start increment |
wire cnt128d_rd_valid_stop; // Counter stop increment |
reg cnt128d_rd_valid; // valid time for cnt128d_rd counter |
reg mem_valid; // 1 clock delay after reading |
|
// DPSRAM Memory Signal Description |
wire [15:0] wr_DATA; |
wire [ 6:0] wr_ADDR; |
wire wr_CSN; |
wire wr_WEN; |
|
wire [15:0] rd_DATA; |
wire [ 6:0] rd_ADDR; |
wire rd_CSN; |
|
dpsram_128x16 u_dpsram( |
.addra (wr_ADDR), |
.addrb (rd_ADDR), |
.clka (sclk), |
.clkb (sclk), |
.dina (wr_DATA), |
.dinb ({16{1'b0}}), |
.douta (/* OPEN */), |
.doutb (rd_DATA), |
.ena (wr_CSN), |
.enb (rd_CSN), |
.wea (wr_WEN), |
.web (1'b1) |
); |
|
always @(posedge sclk or negedge rstn) |
if (!rstn) cnt128d_wr <= #1 0; |
else if (inp_valid) cnt128d_wr <= #1 cnt128d_wr + 1; |
|
assign wr_DATA = {{16-N{1'b0}},inp_data}; |
assign wr_ADDR = cnt128d_wr; |
assign wr_CSN = ~inp_valid; |
assign wr_WEN = ~inp_valid; |
|
// Start Reading After fisrt 64 words had been written |
assign indicator = cnt128d_wr[6]; |
always @(posedge sclk or negedge rstn) |
if (!rstn) indicator_1d <= #1 1'b0; |
else indicator_1d <= #1 indicator; |
|
assign indicator_pos_edge = indicator & ~indicator_1d; |
assign indicator_neg_edge = ~indicator & indicator_1d; |
|
assign cnt128d_rd_valid_start = indicator_pos_edge | indicator_neg_edge; |
assign cnt128d_rd_valid_stop = (cnt128d_rd[5:0] == 63) ? 1'b1 : 1'b0; |
|
always @(posedge sclk or negedge rstn) |
if (!rstn) cnt128d_rd_valid <= #1 1'b0; |
else if (cnt128d_rd_valid_start)cnt128d_rd_valid <= #1 1'b1; |
else if (cnt128d_rd_valid_stop) cnt128d_rd_valid <= #1 1'b0; |
|
// Read Mode Counter |
always @(posedge sclk or negedge rstn) |
if (!rstn) cnt128d_rd <= #1 1'b0; |
else if (cnt128d_rd_valid) cnt128d_rd <= #1 cnt128d_rd + 1; |
|
assign rd_ADDR = {cnt128d_rd[6],cnt128d_rd[2:0],cnt128d_rd[5:3]}; |
assign rd_CSN = ~cnt128d_rd_valid; |
|
// Output |
always @(posedge sclk or negedge rstn) |
if (!rstn) mem_valid <= #1 1'b0; |
else mem_valid <= #1 cnt128d_rd_valid; |
|
assign #1 mem_data = rd_DATA[N-1:0]; |
|
// synopsys translate_off |
// <<<------------- DUMP Section |
|
// 2D FHT OUTPUT DUMP DATA |
parameter MEM_TRPS_DPSRAM_FILE = "./result/mem_trps_dpsram.txt"; |
integer mem_trps_dpsram_dump; |
initial mem_trps_dpsram_dump = $fopen(MEM_TRPS_DPSRAM_FILE); |
|
always @(posedge sclk) |
if (mem_valid) $fdisplay(mem_trps_dpsram_dump,"%h",mem_data); |
|
// synopsys translate_on |
endmodule |
/signed_mult_const_fpga.v
0,0 → 1,57
// |
// File: signed_mult_const_fpga.v |
// Author: Ivan Rezki |
// Topic: RTL Core |
// 2-Dimensional Fast Hartley Transform |
// |
|
// Signed Multiplier - constant sqrt(2) = 1.41421 |
|
// 8 bit accuracy: |
// 1.41421*a = (256*1.41421)*a/256 = 362.03776*a/256 = 362*a/256 |
// product = 362*a/2^8 |
// wire [8:0] mult_constant = 9'd362; |
|
// 15 bit accuracy: |
// 1.41421*a = (32768*1.41421)*a/32768 = 46340.95*a/32768 |
// product = 46341*a/2^15 |
// wire [15:0] mult_constant = 16'd46341; |
|
// 16 bit accuracy: |
// 1.41421*a = (65536*1.41421)*a/65536 = 92681*a/65536 |
// product = 92681*a/2^16 |
// wire [16:0] mult_constant = 17'd92681; |
|
module signed_mult_const_fpga ( |
rstn, |
clk, |
valid, |
a, |
p |
); |
|
parameter N = 8; |
input rstn; |
input clk; |
input valid; |
input signed [N-1:0] a; // variable - positive/negative |
output signed [N :0] p; // product output |
|
// FHT constant |
// wire [8:0] mult_constant; // always positive |
// assign mult_constant = 9'd362; |
|
wire signed [17:0] mult_constant; // always positive |
assign mult_constant = {1'b0, 17'd92681}; |
|
reg signed [N-1:0] a_FF; |
always @(posedge clk) |
if (!rstn) a_FF <= #1 0; |
else if (valid) a_FF <= #1 a; |
|
wire signed [(16+1)+N-1:0] p_tmp = $signed(a_FF) * $signed(mult_constant); |
|
//assign p = p_tmp[(16+1)+N-1:16];// >> 16; |
assign p = p_tmp >> 16; |
|
endmodule |
/signed_mult_const_asic.v
0,0 → 1,58
// |
// File: signed_mult_const_asic.v |
// Author: Ivan Rezki |
// Topic: RTL Core |
// 2-Dimensional Fast Hartley Transform |
// |
|
// Signed Multiplier - constant sqrt(2) = 1.41421 |
// 1.41421*a = (256*1.41421)*a/256 = 362.03776*a/256 = 362*a/256 |
// product = 362*a/2^8 |
|
module signed_mult_const_asic ( |
rstn, |
clk, |
valid, |
a, |
p |
); |
|
parameter N = 8; |
input rstn; |
input clk; |
input valid; |
input [N-1:0] a; // variable - positive/negative |
output [N :0] p; // product output |
|
// FHT constant |
wire [8:0] mult_constant; // always positive |
assign mult_constant = 9'd362; |
|
reg [N-1:0] a_FF; |
always @(posedge clk) |
if (!rstn) a_FF <= #1 0; |
else if (valid) a_FF <= #1 a; |
|
// Convert into 2's complement if (a_FF) is negative |
wire [N-1:0] b; |
assign b = a_FF[N-1] ? {~a_FF[N-1:0] + {{N-1{1'b0}},1'b1} } : a_FF[N-1:0]; |
|
// Multiply 2 positive numbers |
// b[N-2:0] * mult_constant[8:0] |
// output result mult_wo_sign |
// N-2+1 - number of (b) bits |
// 8+1 - number of mult_constant bits |
// N-2+1+8+1 - number of bits on the output |
// = N+8 = [N+7:0] |
wire [N+7:0] mult_wo_sign; // mult without sign |
assign mult_wo_sign = b[N-2:0]*mult_constant; |
|
// Divide on 256 - [N+7-8:0] = [N-1:0] |
wire [N-1:0] div256; // divided 256 |
assign div256 = mult_wo_sign >> 8; |
|
assign p = a_FF[N-1] ? |
{1'b1,{~div256[N-1:0] + {{N-1{1'b0}},1'b1}} } : |
{1'b0, div256[N-1:0]} |
; |
endmodule |
/fht_8x8_core.v
0,0 → 1,130
// |
// File: fht_8x8_core.v |
// Author: Ivan Rezki |
// Topic: RTL Core |
// 2-Dimensional Fast Hartley Transform |
// |
|
// TOP Level |
// 2D FHT 64 points -> ... clk delay |
// |
// +------------------------+ |
// | | |
// --->| 2D FHT/64 Points |---> |
// | | |
// +------------------------+ |
// |<---- .. clk delay ---->| |
// |
|
// Data is coming from somewhere (e.g. memory) with sclk one by one. |
// 1st step 1D FHT by rows: |
// - Shift Register for 8 points -> ... clk delay |
// - Alligner |
// - Calculate 1D FHT for 8 points. -> ... clk delay |
// - FF is used on the each input of the butterfly |
// - FF is used on the input of the multiplier |
// 2nd Step: |
// Matrix Transpose -> 64+1 clk delay |
// - Collecting data until 1st buffer is full as 64 points. |
// - Read 64 points right away after 1st buffer is full. |
// - At the same time 2nd buffer is ready to receive data. |
// - Collecting data until 2nd buffer is full as 64 points. |
// - Read 64 points right away after 2nd buffer is full. |
// - At the same time 1st buffer is ready to receive data once again. |
// - ... |
// 3rd Step 1D FHT by columns. |
// - Combine data to make 8 points in parallel. -> ... clk delay |
// - Calculate 1D FHT for 8 points. -> ... clk delay |
|
// NOTES: |
// 1. Matrix Transposition maximum data width is 16 bits. |
|
// ----->>> Define Multiplier Type |
//`define USE_ASIC_MULT |
//`define USE_FPGA_MULT |
|
// ----->>> Define Memory Type |
//`define USE_FPGA_SPSRAM |
//`define USE_ASIC_SPSRAM |
|
module fht_8x8_core ( |
rstn, |
sclk, |
|
x_valid, |
x_data, |
|
fht_2d_valid, |
fht_2d_data |
); |
// Number of input bits |
parameter N = 8; |
|
input rstn; |
input sclk; |
|
input x_valid; |
input [N-1:0] x_data; |
|
output fht_2d_valid; |
output [N+5:0] fht_2d_data; |
|
// +++--->>> One-Dimensional Fast Hartley Transform - 1st Stage |
// Data input [N-1:0] = N bits |
// |
wire fht_1d_valid; |
wire [N+2:0] fht_1d_data; |
|
fht_1d_x8 #(N) u1_fht_1d_x8_1st( |
.rstn (rstn), |
.sclk (sclk), |
|
// input data |
.x_valid (x_valid), |
.x_data (x_data), |
|
// output data |
.fht_valid (fht_1d_valid), |
.fht_data (fht_1d_data) |
); |
|
// +++--->>> Matrix Transposition <<<---+++ \\ |
wire mem_valid; |
wire [N+2:0] mem_data; |
//mtx_trps_8x8_spsram #(N+3) u2_mtx_ts ( |
// .rstn (rstn), |
// .sclk (sclk), |
// |
// .inp_valid (fht_1d_valid), |
// .inp_data (fht_1d_data), |
// |
// .mem_mux_data (mem_data), |
// .mem_mux_valid (mem_valid) |
//); |
|
mtx_trps_8x8_dpsram #(N+3) u2_mtx_ts ( |
.rstn (rstn), |
.sclk (sclk), |
|
.inp_valid (fht_1d_valid), |
.inp_data (fht_1d_data), |
|
.mem_data (mem_data), |
.mem_valid (mem_valid) |
); |
|
// +++--->>> One-Dimensional Fast Hartley Transform - 2nd Stage |
fht_1d_x8 #(N+3) u3_fht_1d_x8_2nd( |
.rstn (rstn), |
.sclk (sclk), |
|
// input data |
.x_valid (mem_valid), |
.x_data (mem_data), |
|
// output data |
.fht_valid (fht_2d_valid), |
.fht_data (fht_2d_data) |
); |
|
endmodule |
/fht_mtx_tm_8x8.v
0,0 → 1,177
// |
// File: fht_8x8_core.v |
// Author: Ivan Rezki |
// Topic: RTL Core |
// 2-Dimensional Fast Hartley Transform |
// |
|
// Matrix Transpose 8x8 |
// Double Buffer |
// Buffer size is 64 words, each word is 16 bits |
|
// Matrix Transpose -> 64 clk delay |
// - Double Buffer Solution: |
// - 1st Step: |
// - Write 64 points into the 1st Buffer |
// - No Read from the 2nd Buffer |
// - 2nd Step: |
// - Read 64 points back from the 1st Buffer |
// - Write 64 points into the 2nd Buffer |
// - 3rd Step: |
// - Write 64 points into the 1st Buffer |
// - Read 64 points back from the 2nd Buffer |
// - Repeat 2nd and 3rd as much as necessary |
// - Last Step: |
// - No Write into the 1st Buffer |
// - Read 64 points back from the 2nd Buffer |
// |
// - It requires ... |
|
|
module fht_mtx_tm_8x8 ( |
rstn, |
sclk, |
|
// Input |
inp_valid, |
inp_data, |
|
// Output |
mem_mux_data, |
mem_mux_valid |
); |
parameter N = 8; |
|
input rstn; |
input sclk; |
|
input inp_valid; |
input [N-1:0] inp_data; |
|
output [N-1:0] mem_mux_data; |
output mem_mux_valid; |
|
// 1st Buffer wire Interface |
wire mxtr_ram_1_WEN; |
wire mxtr_ram_1_CSN; |
wire [ 5:0] mxtr_ram_1_A; |
wire [15:0] mxtr_ram_1_D; |
|
// 2nd Buffer wire Interface |
wire mxtr_ram_2_WEN; |
wire mxtr_ram_2_CSN; |
wire [ 5:0] mxtr_ram_2_A; |
wire [15:0] mxtr_ram_2_D; |
|
// Notice: 1 |
|
`ifdef USE_FPGA_SPSRAM |
wire [15:0] mxtr_ram_1_Q; |
wire [15:0] mxtr_ram_2_Q; |
spsram_64x16 u_mxtr_ram_1( |
.addr (mxtr_ram_1_A), |
.clk (sclk), |
.din (mxtr_ram_1_D), |
.dout (mxtr_ram_1_Q), |
.en (mxtr_ram_1_CSN), |
.we (mxtr_ram_1_WEN) |
); |
|
spsram_64x16 u_mxtr_ram_2( |
.addr (mxtr_ram_2_A), |
.clk (sclk), |
.din (mxtr_ram_2_D), |
.dout (mxtr_ram_2_Q), |
.en (mxtr_ram_2_CSN), |
.we (mxtr_ram_2_WEN) |
); |
`endif |
|
`ifdef USE_ASIC_SPSRAM |
reg [15:0] mxtr_ram_1_Q; |
reg [15:0] mxtr_ram_2_Q; |
reg [15:0] spsram_1[63:0]; |
always @(posedge sclk) |
if (~mxtr_ram_1_WEN && ~mxtr_ram_1_CSN) spsram_1[mxtr_ram_1_A] <= mxtr_ram_1_D; // Write |
always @(posedge sclk) |
if ( mxtr_ram_1_WEN && ~mxtr_ram_1_CSN) mxtr_ram_1_Q <= spsram_1[mxtr_ram_1_A]; // Read |
|
reg [15:0] spsram_2[63:0]; |
always @(posedge sclk) |
if (~mxtr_ram_2_WEN && ~mxtr_ram_2_CSN) spsram_2[mxtr_ram_2_A] <= mxtr_ram_2_D; // Write |
always @(posedge sclk) |
if ( mxtr_ram_2_WEN && ~mxtr_ram_2_CSN) mxtr_ram_2_Q <= spsram_2[mxtr_ram_2_A]; // Read |
`endif |
|
// <<<------------------------- 1st Buffer Signal Description -------------------------->>> \\ |
assign mxtr_ram_1_CSN = ~inp_valid; |
assign tr_mem_1_valid = inp_valid; |
|
reg [6:0] cnt128d_1; |
always @(posedge sclk or negedge rstn) |
if (!rstn) cnt128d_1 <= #1 0; |
else if (tr_mem_1_valid) cnt128d_1 <= #1 cnt128d_1 + 1; |
|
assign mem_1_sel = cnt128d_1[6]; |
|
assign mxtr_ram_1_WEN = ~(tr_mem_1_valid & ~mem_1_sel); |
|
assign mxtr_ram_1_A = |
(tr_mem_1_valid && ~mem_1_sel) ? {cnt128d_1[5:3],cnt128d_1[2:0]} : |
(tr_mem_1_valid && mem_1_sel) ? {cnt128d_1[2:0],cnt128d_1[5:3]} : |
6'b000_000; |
|
assign mxtr_ram_1_D = {{16-N{1'b0}},inp_data}; |
// <<<----------------------------------------------------------------------------------->>> // |
|
// <<<------------------------- 2nd Buffer Signal Description -------------------------->>> \\ |
reg [63:0] inp_valid_r; |
always @(posedge sclk or negedge rstn) |
if (!rstn) inp_valid_r[63:0] <= #1 0; |
else inp_valid_r[63:0] <= #1 {inp_valid_r[62:0],inp_valid}; |
|
assign mxtr_ram_2_CSN = ~inp_valid_r[63]; |
assign tr_mem_2_valid = inp_valid_r[63]; |
|
reg [6:0] cnt128d_2; |
always @(posedge sclk or negedge rstn) |
if (!rstn) cnt128d_2 <= #1 0; |
else if (tr_mem_2_valid) cnt128d_2 <= #1 cnt128d_2 + 1; |
|
assign mem_2_sel = cnt128d_2[6]; |
|
assign mxtr_ram_2_WEN = ~(tr_mem_2_valid & ~mem_2_sel); |
|
assign mxtr_ram_2_A = |
(tr_mem_2_valid && ~mem_2_sel) ? {cnt128d_2[5:3],cnt128d_2[2:0]} : |
(tr_mem_2_valid && mem_2_sel) ? {cnt128d_2[2:0],cnt128d_2[5:3]} : |
6'b000_000; |
|
assign mxtr_ram_2_D = {{16-N{1'b0}},inp_data}; |
// <<<---------------------------------------------------------------------------------->>> // |
|
wire read_ram_1; |
wire read_ram_2; |
|
assign read_ram_1 = (mxtr_ram_1_WEN && ~mxtr_ram_1_CSN) ? 1'b1 : 1'b0; |
assign read_ram_2 = (mxtr_ram_2_WEN && ~mxtr_ram_2_CSN) ? 1'b1 : 1'b0; |
|
reg [1:0] read_ram_1_r; |
reg [1:0] read_ram_2_r; |
|
always @(posedge sclk or negedge rstn) |
if (!rstn) read_ram_1_r <= #1 0; |
else read_ram_1_r <= #1 {read_ram_1_r[0],read_ram_1}; |
|
always @(posedge sclk or negedge rstn) |
if (!rstn) read_ram_2_r <= #1 0; |
else read_ram_2_r <= #1 {read_ram_2_r[0],read_ram_2}; |
|
assign mem_mux_data = (read_ram_1_r[0]) ? mxtr_ram_1_Q[N-1:0] : |
(read_ram_2_r[0]) ? mxtr_ram_2_Q[N-1:0] : |
16'h0000; |
|
assign mem_mux_valid = (read_ram_1_r[0] | read_ram_2_r[0]); |
|
|
endmodule |
/fht_1d_x8.v
0,0 → 1,248
// |
// File: fht_1d_x8.v |
// Author: Ivan Rezki |
// Topic: RTL Core |
// 2-Dimensional Fast Hartley Transform |
// |
|
// Fast Hartley Transform 1 Dimension for 8 Points |
// Decimation in Frequency Domain |
|
// |
// +-----------+ +-----------+ +-----------+ |
// | Serial | | 1D FHT | | Parallel | |
// --->| to |--->| |--->| to |---> |
// | Parallel | | 8 Points | | Serial | |
// +-----------+ +-----------+ +-----------+ |
// |
|
module fht_1d_x8( |
rstn, |
sclk, |
|
// input data - x0,x1,x2,x3,x4,x5,x6,x7,x0,x1... |
x_valid, |
x_data, |
|
// 1D FHT output data - h0,h1,h2,h3,h4,h5,h6,h7,h0,h1... |
fht_valid, |
fht_data |
|
); |
|
parameter N = 8; |
|
input rstn; |
input sclk; |
|
input x_valid; |
input [N-1:0] x_data; |
|
output fht_valid; |
output [N+2:0] fht_data; |
// +++---------------------------------+++\\ |
|
// +++ Data Preparation Step Start +++ \\ |
// +++ - Aligning - +++ \\ |
reg [N-1:0] x0,x1,x2,x3,x4,x5,x6,x7; |
always @(posedge sclk or negedge rstn) |
if (!rstn) begin |
x0 <= #1 0; |
x1 <= #1 0; |
x2 <= #1 0; |
x3 <= #1 0; |
x4 <= #1 0; |
x5 <= #1 0; |
x6 <= #1 0; |
x7 <= #1 0; |
end |
else if (x_valid) begin |
x0 <= #1 x_data; |
x1 <= #1 x0; |
x2 <= #1 x1; |
x3 <= #1 x2; |
x4 <= #1 x3; |
x5 <= #1 x4; |
x6 <= #1 x5; |
x7 <= #1 x6; |
end |
|
reg x_valid_1d; |
always @(posedge sclk or negedge rstn) |
if (!rstn) x_valid_1d <= #1 0; |
else x_valid_1d <= #1 x_valid; |
|
wire xi_ready; |
|
reg [2:0] cnt; |
always @(posedge sclk or negedge rstn) |
if (!rstn) cnt <= #1 0; |
else if (x_valid_1d) cnt <= #1 cnt + 1; |
|
assign xi_ready = (cnt == 7 && x_valid_1d) ? 1'b1 : 1'b0; |
|
// at the ready time aligned and reversed |
reg [N-1:0] x0_FF,x1_FF,x2_FF,x3_FF,x4_FF,x5_FF,x6_FF,x7_FF; |
always @(posedge sclk or negedge rstn) |
if (!rstn) begin |
x0_FF <= #1 0; |
x1_FF <= #1 0; |
x2_FF <= #1 0; |
x3_FF <= #1 0; |
x4_FF <= #1 0; |
x5_FF <= #1 0; |
x6_FF <= #1 0; |
x7_FF <= #1 0; |
end |
else if (xi_ready) begin |
x0_FF <= #1 x7; |
x1_FF <= #1 x6; |
x2_FF <= #1 x5; |
x3_FF <= #1 x4; |
x4_FF <= #1 x3; |
x5_FF <= #1 x2; |
x6_FF <= #1 x1; |
x7_FF <= #1 x0; |
end |
// +++ Data Preparation Step Finish +++ // |
|
// delay for ... clocks to provide timing requirements |
reg [13:0] xi_ready_d; |
always @(posedge sclk or negedge rstn) |
if (!rstn) xi_ready_d[13:0] <= #1 0; |
else xi_ready_d[13:0] <= #1 {xi_ready_d[12:0],xi_ready}; |
|
// 1D Fast Hartley Transform - Decimation-in-Frequency Algorithm |
|
// Butterfly Stage N1 |
// Data input [N-1:0] = N bits |
// On the output of the 1st bfly is [N:0] = N+1 bits |
|
// <<<--------- Butterfly Stage N1 |
wire [N:0] stg1_sum1; |
wire [N:0] stg1_sum2; |
wire [N:0] stg1_sum3; |
wire [N:0] stg1_sum4; |
|
wire [N:0] stg1_sub1; |
wire [N:0] stg1_sub2; |
wire [N:0] stg1_sub3; |
wire [N:0] stg1_sub4; |
|
fht_bfly_noFF #(N) u11_fht_bfly ({x0_FF},{x4_FF},stg1_sum1,stg1_sub1); |
fht_bfly_noFF #(N) u12_fht_bfly ({x1_FF},{x5_FF},stg1_sum2,stg1_sub2); |
fht_bfly_noFF #(N) u13_fht_bfly ({x2_FF},{x6_FF},stg1_sum3,stg1_sub3); |
fht_bfly_noFF #(N) u14_fht_bfly ({x3_FF},{x7_FF},stg1_sum4,stg1_sub4); |
|
// <<<--------- Butterfly Stage N2 |
wire [N+1:0] stg2_sum1; |
wire [N+1:0] stg2_sum2; |
wire [N+1:0] stg2_sum3; |
|
wire [N+1:0] stg2_sub1; |
wire [N+1:0] stg2_sub2; |
wire [N+1:0] stg2_sub3; |
|
fht_bfly #(N+1) u21_fht_bfly (rstn,sclk,xi_ready_d[1],stg1_sum1,stg1_sum3,stg2_sum1,stg2_sub1); |
fht_bfly #(N+1) u22_fht_bfly (rstn,sclk,xi_ready_d[1],stg1_sum2,stg1_sum4,stg2_sum2,stg2_sub2); |
fht_bfly #(N+1) u23_fht_bfly (rstn,sclk,xi_ready_d[1],stg1_sub1,stg1_sub3,stg2_sum3,stg2_sub3); |
|
// Multiplier on the 2nd Stage |
wire [N:0] mult_dat_1; |
wire [N:0] mult_dat_2; |
assign mult_dat_1 = stg1_sub2; |
assign mult_dat_2 = stg1_sub4; |
|
wire [N+1:0] mult_res1; |
wire [N+1:0] mult_res2; |
|
`ifdef USE_ASIC_MULT |
signed_mult_const_asic #(N+1) u_mult_1_fht (rstn,sclk,xi_ready_d[1],mult_dat_1,mult_res1); |
signed_mult_const_asic #(N+1) u_mult_2_fht (rstn,sclk,xi_ready_d[1],mult_dat_2,mult_res2); |
`elsif USE_FPGA_MULT |
signed_mult_const_fpga #(N+1) u_mult_1_fht (rstn,sclk,xi_ready_d[1],mult_dat_1,mult_res1); |
signed_mult_const_fpga #(N+1) u_mult_2_fht (rstn,sclk,xi_ready_d[1],mult_dat_2,mult_res2); |
`endif |
|
// <<<--------- Butterfly Stage N3 |
wire [N+2:0] stg3_sum1; |
wire [N+2:0] stg3_sum2; |
wire [N+2:0] stg3_sum3; |
wire [N+2:0] stg3_sum4; |
|
wire [N+2:0] stg3_sub1; |
wire [N+2:0] stg3_sub2; |
wire [N+2:0] stg3_sub3; |
wire [N+2:0] stg3_sub4; |
|
fht_bfly #(N+2) u31_fht_bfly (rstn,sclk,xi_ready_d[3],stg2_sum1,stg2_sum2,stg3_sum1,stg3_sub1); |
fht_bfly #(N+2) u32_fht_bfly (rstn,sclk,xi_ready_d[3],stg2_sub1,stg2_sub2,stg3_sum2,stg3_sub2); |
fht_bfly #(N+2) u33_fht_bfly (rstn,sclk,xi_ready_d[3],stg2_sum3,mult_res1,stg3_sum3,stg3_sub3); |
fht_bfly #(N+2) u34_fht_bfly (rstn,sclk,xi_ready_d[3],stg2_sub3,mult_res2,stg3_sum4,stg3_sub4); |
|
// <<<--------- FHT Result |
reg [N+2:0] h0_FF,h1_FF,h2_FF,h3_FF,h4_FF,h5_FF,h6_FF,h7_FF; |
always @(posedge sclk or negedge rstn) |
if (!rstn) begin |
h0_FF <= #1 0; |
h4_FF <= #1 0; |
h2_FF <= #1 0; |
h6_FF <= #1 0; |
h1_FF <= #1 0; |
h5_FF <= #1 0; |
h3_FF <= #1 0; |
h7_FF <= #1 0; |
end |
else if (xi_ready_d[5]) begin |
h0_FF <= #1 stg3_sum1; |
h4_FF <= #1 stg3_sub1; |
h2_FF <= #1 stg3_sum2; |
h6_FF <= #1 stg3_sub2; |
h1_FF <= #1 stg3_sum3; |
h5_FF <= #1 stg3_sub3; |
h3_FF <= #1 stg3_sum4; |
h7_FF <= #1 stg3_sub4; |
end |
|
assign h0_valid = xi_ready_d[6]; |
assign h1_valid = xi_ready_d[7]; |
assign h2_valid = xi_ready_d[8]; |
assign h3_valid = xi_ready_d[9]; |
assign h4_valid = xi_ready_d[10]; |
assign h5_valid = xi_ready_d[11]; |
assign h6_valid = xi_ready_d[12]; |
assign h7_valid = xi_ready_d[13]; |
|
wire fht_valid_or; |
assign fht_valid_or = h0_valid | |
h1_valid | |
h2_valid | |
h3_valid | |
h4_valid | |
h5_valid | |
h6_valid | |
h7_valid ; |
|
wire [N+2:0] h_or_data; |
assign h_or_data = |
(h0_FF & {N+3{h0_valid}}) | |
(h1_FF & {N+3{h1_valid}}) | |
(h2_FF & {N+3{h2_valid}}) | |
(h3_FF & {N+3{h3_valid}}) | |
(h4_FF & {N+3{h4_valid}}) | |
(h5_FF & {N+3{h5_valid}}) | |
(h6_FF & {N+3{h6_valid}}) | |
(h7_FF & {N+3{h7_valid}}) ; |
|
reg [N+2:0] fht_data; |
reg fht_valid; |
|
always @(posedge sclk or negedge rstn) |
if (!rstn) fht_valid <= #1 0; |
else fht_valid <= #1 fht_valid_or; |
|
always @(posedge sclk or negedge rstn) |
if (!rstn) fht_data <= #1 0; |
else fht_data <= #1 h_or_data; |
|
endmodule |
/fht_bfly_noFF.v
0,0 → 1,97
// |
// File: fht_8x8_core.v |
// Author: Ivan Rezki |
// Topic: RTL Core |
// 2-Dimensional Fast Hartley Transform |
// |
|
// Fast Hartley Transform ButterFly Unit without input FF |
|
module fht_bfly_noFF( |
a, |
b, |
c, |
d |
); |
|
parameter N = 8; |
|
input [N-1:0] a; // input |
input [N-1:0] b; // input |
|
output [N :0] c; // additive output |
output [N :0] d; // subtractive output |
|
assign c = rca_N(a,b); |
assign d = rca_N(a,twos_complement(b)); |
|
// +--------------------------------------------------+ \\ |
// +----------- Function's Description Part ----------+ \\ |
// +--------------------------------------------------+ \\ |
// Full Adder |
function [1:0] full_adder; |
input a, b, ci; |
reg co, s; |
begin |
s = (a ^ b ^ ci); |
co = (a & b) | (ci & (a ^ b)); |
full_adder = {co,s}; |
end |
endfunction |
|
// Half Adder, i.e. without carry in |
function [1:0] half_adder; |
input a, b; |
reg co, s; |
begin |
s = (a ^ b); |
co = (a & b); |
half_adder = {co,s}; |
end |
endfunction |
|
// Ripple Carry Adder - rca |
// Input vector = N bits |
// Output vector = N + 1 bits |
function [N:0] rca_N; |
|
// parameter N = 8; |
input [N-1:0] a; |
input [N-1:0] b; |
|
reg [N-1:0] co,sum; |
|
begin : RCA // RIPPLE CARRY ADDER |
integer i; |
//for (i = 0; i <= N; i = i + 1) |
for (i = 0; i < N; i = i + 1) |
if (i == 0) |
{co[i],sum[i]} = half_adder(a[i],b[i]); |
else |
{co[i],sum[i]} = full_adder(a[i],b[i],co[i-1]); |
|
rca_N[N-1:0] = sum; |
// MSB is a sign bit |
rca_N[N] = (a[N-1]==b[N-1]) ? co[N-1] : sum[N-1]; |
end |
endfunction |
|
|
function [N-1:0] twos_complement; |
input [N-1:0] a; |
reg [N-1:0] ainv; |
reg [N:0] plus1; |
begin |
ainv = ~a; |
plus1 = rca_N(ainv,{{N-1{1'b0}},1'b1}); |
|
// synopsys translate_off |
// The only problem is absolute minumum negative value |
if (a == {1'b1, {N-1{1'b0}}}) $display("--->>> 2's complement ERROR - absolute minumum negative value"); |
// synopsys translate_on |
|
twos_complement = plus1[N-1:0]; |
end |
endfunction |
|
endmodule |