`timescale 1ns/1ps `define BITS 8 module sc_decoder_fsm #(parameter BITS=8, N=11'd32)( input clk, rst, input in_valid, input signed [N-1:0][BITS-1:0] y, input [N-1:0] f, output wire [N-1:0] u_cap, output wire [N-1:0] v_final, output wire out_valid ); //function for fminsum calculation function void fminsum_calc; input signed [`BITS-1:0] a; input signed [`BITS-1:0] b; output signed [`BITS-1:0] c; logic [`BITS-2:0] abs_a; logic [`BITS-2:0] abs_b; logic [`BITS-2:0] abs_c; abs_a = (a[`BITS-1]) ? ~a[`BITS-2:0] + 1'b1 : a[`BITS-2:0]; abs_b = (b[`BITS-1]) ? ~b[`BITS-2:0] + 1'b1 : b[`BITS-2:0]; abs_c = (abs_b < abs_a) ? abs_b : abs_a; c[`BITS-1] = a[`BITS-1] ^ b[`BITS-1]; c[`BITS-2:0] = (c[`BITS-1]) ? ~abs_c + 1'b1 : abs_c; endfunction //function for g-value calculation function void g_calc; input signed [`BITS-1:0] a; input signed [`BITS-1:0] b; input u; output signed [`BITS:0] c; c = (u == 0) ? (b + a) : (b + (~a+1'b1)); endfunction // Parameter localparam d = $clog2(N); // Internal Signals logic [N-1:0][BITS-1:0] L_in, L_out; logic [d :0] temp_index_f,temp_index_g; logic [N-1:0] v_in, v_out; logic [11 :0] jL1,jL2, jU1,jU2, jR1,jR2,jR3; logic ena_v,enb_v,wea_v; logic ena_L,enb_L,wea_L; logic [N-1:0]u; reg signed [BITS-1:0] LRU[2]; reg [N-1:0]v; // State Variables logic [4:0] c_state, n_state; //Auxiliary registers declarations logic [d:0] depth,depth_reg; logic [d:0] node,node_reg; logic [11:0] tmp_L, tmp_L_reg, tmp_R, tmp_R_reg, tmp_U, tmp_U_reg; //FSM States localparam idle = 5'd0 , root = 5'd1 , wait_L_logic = 5'd2, wait_L = 5'd3 , state_L = 5'd4 , wait_R_logic = 5'd5, wait_R = 5'd6 , state_R = 5'd7 , wait_U_logic = 5'd8, wait_U = 5'd9 , state_U = 5'd10, wait_LRU_logic = 5'd11, wait_LRU = 5'd12, state_LRU = 5'd13, wait_lnode_logic = 5'd14, wait_lnode = 5'd15, state_lnode = 5'd16, wait_lstate_logic = 5'd17, wait_lstate = 5'd18, state_last = 5'd19; //BlockRAM Instantiations bram_v #( .ADDR_WIDTH(d-1), .DATA_WIDTH(N), .DEPTH(2**(d-1))) bram_v_i ( .clk(clk),.ena(ena_v),.enb(enb_v), .addra(depth_reg-1'b1), .addrb(depth_reg), .wea(wea_v), .dia(v_in), .dob(v_out)); bram_L #( .ADDR_WIDTH(d-1), .DATA_WIDTH(N*BITS), .DEPTH(2**(d-1)), .N(N)) bram_L_i ( .clk(clk),.ena(ena_L),.enb(enb_L), .addra(depth_reg), .addrb(depth_reg-1'b1), .wea(wea_L), .dia(L_in), .dob(L_out)); //output assignment for(genvar i=0; i> 1; tmp_U = 0; u = u; v = v; n_state = wait_U; end wait_U: begin // depth = depth_reg; ena_L = 0; wea_L = 0; enb_L = 0; ena_v = 0; wea_v = 0; enb_v = 1'b1; n_state = state_U; end state_U: begin // depth = depth_reg; ena_L = 0; ena_v =1'b1; enb_L = 0; wea_L = 0; wea_v =1'b1; enb_v = 0; u = u; v = v; tmp_U = tmp_U_reg+1'b1; temp_index_f = ((N/(2**(depth))) * ((2*node + 1'b1) - ((2**(depth)) - 1'b1))); jU1 = (tmp_U_reg) + temp_index_f; jU2 = (tmp_U_reg) + temp_index_f + (N/(2**(depth))); v_in[jU1] = v_out[jU1] ^ v_out[jU2]; v_in[jU2] = v_out[jU2]; if(tmp_U < (N/(2**(depth)))) n_state = state_U; else if(depth > 0 && ~node[0]) n_state = wait_U_logic; else if(depth > 0 && node!=0) n_state = wait_R_logic; else n_state = wait_lstate_logic; end wait_LRU_logic: begin u = u; v = v; // depth = depth_reg; node = (node_reg - 1'b1) >> 1; n_state = wait_LRU; end wait_LRU: begin // depth = depth_reg; u = u; v = v; ena_L = 0; wea_L = 0; enb_L = 1'b1; ena_v = 0; wea_v = 0; enb_v = 0; n_state = state_LRU; end state_LRU: begin // depth = depth_reg; ena_L = 0; ena_v = 1'b1; enb_v = 0; wea_v = 1'b1; wea_L = 0; enb_L = 0; v = v; temp_index_f = ((N/(2**(depth))) * ((2*node + 1'b1) - ((2**(depth)) - 1'b1))); fminsum_calc(L_out[temp_index_f],L_out[temp_index_f + 1],LRU[0]); u[(2*node)+2-N] = (f[(2*node)+2-N]) ? 0 : ((LRU[0][BITS-1]) ? 1 : 0); g_calc(L_out[temp_index_f],L_out[temp_index_f+1],u[(2*node)+2-N],LRU[1]); u[(2*node)+3-N] = (f[(2*node)+3-N]) ? 0 : ((LRU[1][BITS-1]) ? 1 : 0); v_in[temp_index_f] = u[(2*node)+2-N] ^ u[(2*node)+3-N]; v_in[temp_index_f+1] = u[(2*node)+3-N]; if(node[0]) n_state = wait_R_logic; else n_state = wait_U_logic; end wait_lnode_logic: begin u = u; v = v; depth = depth_reg + 1'b1; node = node_reg; n_state = wait_lnode; end wait_lnode: begin // depth = depth_reg; u = u; v = v; ena_L = 0; wea_L = 0; enb_L = 1'b1; ena_v = 0; wea_v = 0; enb_v = 0; n_state = state_lnode; end state_lnode: begin // depth = depth_reg; u = u; v = v; ena_L = 0; wea_L = 0; enb_L = 0; ena_v = 1'b1; wea_v = 1'b1; enb_v = 0; temp_index_f = ((N/(2**(depth))) * ((2*node + 1'b1) - ((2**(depth)) - 1'b1))); fminsum_calc(L_out[temp_index_f],L_out[temp_index_f+1],LRU[0]); u[(2*node)+2-N] = (f[(2*node)+2-N]) ? 0 : ((LRU[0][BITS-1]) ? 1'b1 : 0); g_calc(L_out[temp_index_f],L_out[temp_index_f+1],u[(2*node)+2-N],LRU[1]); u[(2*node)+3-N] = (f[(2*node)+3-N]) ? 0 : ((LRU[1][BITS-1]) ? 1'b1 : 0); v_in[temp_index_f] = u[(2*node)+2-N] ^ u[(2*node)+3-N]; v_in[temp_index_f+1] = u[(2*node)+3-N]; n_state = wait_U_logic; end wait_lstate_logic: begin u = u; v = v; // depth = depth_reg; node = node_reg; n_state = wait_lstate; end wait_lstate: begin // depth = depth_reg; u = u; v = v; ena_L = 0; wea_L = 0; enb_L = 1'b1; ena_v = 0; wea_v = 0; enb_v = 0; n_state = state_last; end state_last: begin // depth = depth_reg; u = u; ena_L = 0; wea_L = 0; enb_L = 0; ena_v = 1'b1; wea_v = 1'b1; enb_v = 0; v = v_out; n_state = idle; end default: begin u = 0; v = 0; depth = 0; node = 0; tmp_L = 0; tmp_R = 0; tmp_U = 0; ena_L = 0; wea_L = 0; enb_L = 0; ena_v = 0; wea_v = 0; enb_v = 0; n_state = idle; end endcase else begin u = 0; v = 0; depth = 0; node = 0; tmp_L = 0; tmp_R = 0; tmp_U = 0; ena_L = 0; wea_L = 0; enb_L = 0; ena_v = 0; wea_v = 0; enb_v = 0; n_state = idle; end end endmodule