weird behaviour of fitter in quartus for SDRAM project
I've been working on SDRAM controller project using verilog using cyclone v 5cefa5f23i7.
The SDRAM have four bank , 3 cas latency and 166 Mhz clock.
I start design with a goal of having lowest possible latency for controller but as i expect timing failure start appearing at first compile , so i start debugging and change the hdl code
I also use compile at aggressive performance setting,
the main problem is the io is far from other so the routing delay is huge (up to 5ns) leaving small roam for logic delay.
here is the code it not complete and i still beginner
module controller( input clk,clk_2,rst, inout wire [31:0] data_bus, output reg [12:0] addr_out, output reg [1:0] bank_out, output reg [3:0] DQ, output reg cke,cas,ras,we,cs, output wire clk_out, //control_port input wire [23:0] addr_in, input wire [31:0] data_w_in, output reg [31:0] data_r_in, input wire write_in,read_in, output reg ready, output reg [3:0] busy ); integer i,j,k,h; integer num [3:0]; integer num_2 [3:0]; clock_out clock_out_inst ( .datain_h (1'b1), .datain_l (1'b0), .outclock (clk_2), .dataout (clk_out) ); ///////////////////sync always_ff @(posedge clk or negedge rst) if(~rst) data_r_in <= 0; else data_r_in <= data_bus; reg act_write = 0; reg [1:0] read_delay = 3; always_ff @(negedge clk_2 or negedge rst)//output enable if(~rst) act_write <= 0; else act_write <= (read_delay<2) ? 0 : 1 ; reg [31:0] data_out = 0; assign data_bus = act_write ? data_out : 32'bz; ////////////////end_sync ////////////////////////////////////main_state_machine reg [1:0] main_s = 0; parameter initial_ = 0 ,work = 2'h1 ,refresh = 2'h2; reg [1:0] counter = 0; reg [3:0] ref_delay = 0; reg [11:0] ref_counter = 0; reg [3:0] ref_act = 0; initial begin addr_out = 0; bank_out = 0; data_r_in = 0; ready = 0; cke = 1; cas = 1; ras = 1; we = 1; cs = 1; DQ = 4'hf; end ///////////////////////////////////comb_logic_registers reg [1:0] main_s_wire; reg [1:0] counter_wire; reg [3:0] ref_delay_wire; reg [11:0] ref_counter_wire; reg [3:0] ref_act_wire; reg [12:0] addr_out_wire; reg [1:0] bank_out_wire; reg [3:0] DQ_wire; reg [31:0] data_out_wire; reg [1:0] read_delay_wire; reg ready_wire; reg cke_wire; reg cas_wire; reg ras_wire; reg we_wire; reg cs_wire; /* counter_wire = counter_wire; ref_delay_wire = ref_delay; addr_out_wire = addr_out; bank_out_wire = bank_out; DQ_wire = DQ; cke_wire = cke; cas_wire = cas; ras_wire = ras; we_wire = we; cs_wire = cs; */ ///////////////////////////////////bank_state_machine reg [1:0] state [3:0]; parameter idle = 2'h0 ,active = 2'h1 ,read_write = 2'h2 ,precharge = 2'h3; //////////////////////instructure coder reg [1:0] ins [3:0]; parameter active_i = 2'h0 ,read_i = 2'h1 ,write_i = 2'h2 ,pre_charge_i = 2'h3; reg [3:0] ins_r [3:0]; //////////////////////delay control reg [3:0] delay [3:0];//active to write or read to precharge reg delay_pre [3:0]; //write to precharge //////////////////////data_latch reg [31:0] data [3:0]; reg [21:0] addr [3:0]; parameter read_con = 0 , write_con = 1'b1; reg r_w [3:0]; /////////////////////globa_variables reg [3:0] delay_ab = 0; //delay from read or write in different bank reg [1:0] global_act = 0;//delay from active to active in diffrent bank reg [3:0] run = 0; //reg to control "chip select" always_comb begin if(ref_counter >= 1200)begin ref_counter_wire = 0; ref_act_wire = ref_act+1; end else begin ref_counter_wire = ref_counter+1; ref_act_wire = ref_act; end if(read_delay == 0)begin ready_wire = 1; read_delay_wire = 3; end else begin ready_wire = 0; if(read_delay < 3) read_delay_wire = read_delay-1; else read_delay_wire = read_delay; end case(main_s) initial_:begin counter_wire[0] = 1; counter_wire[1] = counter[0]; ras_wire = 0;//precharge all banks we_wire = 0; bank_out_wire = 0;//mode register set if(counter[0])begin cas_wire = 0; addr_out_wire = 13'b0001000110000;//refer to mode register table end else begin cas_wire = 1'b1; addr_out_wire = 13'b0010000000000;//bank precharge end if(counter[1])begin ref_act_wire = 8; main_s_wire = refresh; cs_wire = 1; end else begin main_s_wire = main_s; ref_act_wire = ref_act; cs_wire = 0; end data_out_wire = data_out; ref_delay_wire = ref_delay; DQ_wire = DQ; cke_wire = cke; end work:begin/////normal_operatoin counter_wire = counter; ref_delay_wire = ref_delay; DQ_wire = DQ; cke_wire = cke; addr_out_wire = addr_out;//should be removed if(ins_r[0][2] == 1)begin // here is the problem data_out_wire = data[0]; end else if(ins_r[1][2] == 1)begin data_out_wire = data[1]; end else if(ins_r[2][2] == 1)begin data_out_wire = data[2]; end else data_out_wire = data[3]; if((ins_r[0][0] == 1)|(ins_r[1][0] == 1)|(ins_r[2][0] == 1)|(ins_r[3][0] == 1)|(ins_r[0][2] == 1)|(ins_r[1][2] == 1)|(ins_r[2][2] == 1)|(ins_r[3][2] == 1))begin//active we_wire = 1; end else we_wire = 0; //////////////////// /* if((ins[0] == active_i)&(run[0])) addr_out_wire = addr[0][12:0]; else if((ins[1] == active_i)&(run[1])) addr_out_wire = addr[1][12:0]; else if((ins[2] == active_i)&(run[2])) addr_out_wire = addr[2][12:0]; else if((ins[3] == active_i)&(run[3])) addr_out_wire = addr[3][12:0]; else if((ins[0] == write_i)&(run[0])) addr_out_wire = addr[0][12:0]; else if((ins[1] == write_i)&(run[1])) addr_out_wire = addr[1][12:0]; else if((ins[2] == write_i)&(run[2])) addr_out_wire = addr[2][12:0]; else if((ins[3] == write_i)&(run[3])) addr_out_wire = addr[3][12:0]; else if((ins[0] == read_i)&(run[0])) addr_out_wire = addr[0][12:0]; else if((ins[1] == read_i)&(run[1])) addr_out_wire = addr[1][12:0]; else if((ins[2] == read_i)&(run[2])) addr_out_wire = addr[2][12:0]; else if((ins[3] == read_i)&(run[3])) addr_out_wire = addr[3][12:0]; else if((ins[0] == pre_charge_i)&(run[0])) addr_out_wire = addr[0][12:0]; else if((ins[1] == pre_charge_i)&(run[1])) addr_out_wire = addr[1][12:0]; else if((ins[2] == pre_charge_i)&(run[2])) addr_out_wire = addr[2][12:0]; else if((ins[3] == pre_charge_i)&(run[3])) addr_out_wire = addr[3][12:0]; */ //////////////////// if((ins_r[0][0] == 1)|(ins_r[1][0] == 1)|(ins_r[2][0] == 1)|(ins_r[3][0] == 1))begin//active main_s_wire = main_s; cas_wire = 1'b1; ras_wire = 0; if(ins_r[0][0] == 1)begin bank_out_wire = 0; end else if(ins_r[1][0] == 1)begin bank_out_wire = 1; end else if(ins_r[2][0] == 1)begin bank_out_wire = 2; end else bank_out_wire = 3; end else if((ins_r[0][2] == 1)|(ins_r[1][2] == 1)|(ins_r[2][2] == 1)|(ins_r[3][2] == 1))begin//write main_s_wire = main_s; ras_wire = 1'b1; cas_wire = 0; if(ins_r[0][2] == 1)begin bank_out_wire = 0; end else if(ins_r[1][2] == 1)begin bank_out_wire = 1; end else if(ins_r[2][2] == 1)begin bank_out_wire = 2; end else bank_out_wire = 3; end else if((ins_r[0][1] == 1)|(ins_r[1][1] == 1)|(ins_r[2][1] == 1)|(ins_r[3][1] == 1))begin main_s_wire = main_s; ras_wire = 1'b1; cas_wire = 0; read_delay_wire = 2'd2; if(ins_r[0][1] == 1)begin bank_out_wire = 0; end else if(ins_r[1][1] == 1)begin bank_out_wire = 1; end else if(ins_r[2][1] == 1)begin bank_out_wire = 2; end else bank_out_wire = 3; end else if((ins_r[0][3] == 1)|(ins_r[0][3] == 1)|(ins_r[0][3] == 1)|(ins_r[0][3] == 1))begin main_s_wire = main_s; ras_wire = 0; cas_wire = 1'b1; if(ins_r[0][3] == 1) bank_out_wire = 0; else if(ins_r[1][3] == 1) bank_out_wire = 1; else if(ins_r[2][3] == 1) bank_out_wire = 2; else bank_out_wire = 3; end else begin ras_wire = ras; cas_wire = cas; bank_out_wire = bank_out; if(ref_act!=0) main_s_wire = refresh; else main_s_wire = main_s; end if(run[0]|run[1]|run[2]|run[3]) cs_wire = 0; else cs_wire = 1; end refresh: begin///////////////////////refresh_part cas_wire = 0; ras_wire = 0; we_wire = 1; if(ref_delay == 0)begin if(ref_act!=0)begin main_s_wire = main_s; ref_delay_wire = 9; ref_act_wire = ref_act-1'd1; cs_wire = 0; end else begin main_s_wire = work; ref_delay_wire = ref_delay; ref_act_wire = ref_act; cs_wire = 1; end end else begin main_s_wire = main_s; ref_act_wire = ref_act; ref_delay_wire = ref_delay-1; cs_wire = 1; end data_out_wire = data_out; counter_wire = counter; addr_out_wire = addr_out; bank_out_wire = bank_out; DQ_wire = DQ; cke_wire = cke; end default: main_s_wire = initial_; endcase end always_ff @(negedge clk_2 or negedge rst) if(~rst)begin/////////////////reset main_s <= initial_; counter <= 0; cs <= 1; ras <= 1; cas <= 1; we <= 1; bank_out <= 0; ref_act <= 0; ref_delay <= 0; read_delay <= 3; ref_counter <= 0; addr_out <= 0; data_out <= 0; ready <= 0; DQ <= 4'hf; end else begin////////////end_reset main_s <= main_s_wire; counter <= counter_wire; cs <= cs_wire; ras <= ras_wire; cas <= cas_wire; we <= we_wire; bank_out <= bank_out_wire; ref_act <= ref_act_wire; ref_delay <= ref_delay_wire; read_delay <= read_delay_wire; ref_counter <= ref_counter_wire; addr_out <= addr_out_wire; data_out <= data_out_wire; ready <= ready_wire; DQ <= DQ_wire; end ////////////////////////////////////////////////////////banks///////////////////////////////////// initial for(i = 0; i <= 3; i = i+1)begin state [i] = idle; ins [i] = active_i; delay [i] = 4'd9; delay_pre [i] = 0;//fix data[i] = 0; addr[i] = 0; r_w[i] = read_con; busy[i] = 1; ins_r[i] = 4'h0; end wire [8:0] colum = addr_in [8:0]; wire [12:0] row = addr_in [21:9]; wire [1:0] bank = addr_in [23:22]; always_ff @(negedge clk or negedge rst) for(i = 0; i <= 3; i = i+1)begin for(j = 0; j <= 3; j = j+1)begin k = j; if (k == i) k = k+1; if(k == 4) k = 32'd0; num[j]=k; end if (~rst) begin state[i] <= idle; ins[i] <= active_i; data[i] <= 0; addr[i] <= 0; r_w[i] <= read_con; busy[i] <= 1; ins_r[i] <= 0; ///////////////delays delay[i] <= 4'd9; delay_pre[i] <= 0; ///////////////global global_act <= 0; delay_ab[i] <= 0; run[i] <= 0; end/////////////////////end reset else begin if((read_in|write_in)&(ref_act == 0))//fix fix global_act <= 2'd3; else if(global_act!=0) global_act <= global_act-1; else global_act <= global_act;//i don't know why it give error when i delete this line case(state[i]) idle:begin //idle ////////////////////////////////counter_part if(delay[i]!=0) delay[i] <= delay[i]-1'd1; if(delay_pre[i]!=0) delay_pre[i] <= 0; if(delay_ab[i]!=0) delay_ab[i] <= 0; ////////////////////////////////counters_end if (( bank == i ) & ( read_in | write_in ) & ( ref_act == 0 ))begin data[i] <= data_w_in; addr[i] <= {colum,row}; r_w[i] <= ~read_in; state[i] <= active; busy[i] <= 1; end else begin if(ref_act == 0) busy[i] <= 0; end run[i] <= 0; end active:begin //active ////////////////////////////////counter_part if(delay_pre[i] != 0) delay_pre[i] <= 0; if(delay_ab[i] != 0) delay_ab[i] <= 0; ////////////////////////////////counters_end if((delay[i] == 0)&(global_act == 0))begin delay[i] <= 4'd9; ins[i] <= active_i; ins_r[i] <= 4'b0001; run[i] <= 1; addr[i][12:0] <= {4'h0,addr[i][21:13]}; state[i] <= read_write; end else begin run[i] <= 0; if(delay[i] != 0) delay[i] <= delay[i]-1; end end read_write: if (r_w[i] == read_con) begin //read ////////////////////////////////counter_part if(delay[i] != 0) delay[i] <= delay[i]-1'd1; if(delay_pre[i]!=0) delay_pre[i] <= 0; ////////////////////////////////counters_end if((delay[i] <= 4'd7)&({delay_ab[num[0]],delay_ab[num[1]],delay_ab[num[2]],delay_ab[num[3]]} == 0))begin ins[i] <= read_i; ins_r[i] <= 4'b0010; state[i] <= precharge; delay_ab[i] <= 1'b1; run[i] <= 1; end else begin run[i] <= 0; delay_ab[i] <= 0; end end else begin //write ////////////////////////////////counter_part if(delay[i]!=0) delay[i] <= delay[i]-1'd1; ////////////////////////////////counters_end if((delay[i] <= 4'd7)&({delay_ab[num[0]],delay_ab[num[1]],delay_ab[num[2]],delay_ab[num[3]]} == 0)&(read_delay!=1))begin ins[i] <= write_i; ins_r[i] <= 4'b0100; state[i] <= precharge; delay_pre[i] <= 1'b1; delay_ab[i] <= 1'b1; run[i] <= 1; end else begin run[i] <= 0; delay_pre[i] <= 0; delay_ab[i] <= 0; end end precharge:begin //pre_charge ////////////////////////////////counter_part delay_pre[i] <= 0; delay_ab[i] <= 0; ////////////////////////////////counters_end run[i] <= 0; if((delay[i] <= 2)&(~delay_pre[i]))begin ins[i] <= pre_charge_i; ins_r[i] <= 4'b1000; delay[i] <= 4'd2; state[i] <= idle; run[i] <= 1; end else begin run[i] <= 0; if(delay[i]!=0) delay[i] <= delay[i]-1'd1; end end default:state[i] <= idle; endcase end end endmodule
the problem in data_out register at line 189 the fitter have two option to do that
first is to use 7 input alm to read 3 ins_r register and four data register.
second is use 5 input with help of multiplexer at input of data_out register.
the second option is better and this what fitter choose but for some reason the fitter use another alm to making the multiplexer which lead to bigger delay and timing failaure
Iam using io reg so iam sure the multiplexer is free to use
Thanks in advance and sorry for any error in typing