OpenCores
URL https://opencores.org/ocsvn/open_free_list/open_free_list/trunk

Subversion Repositories open_free_list

[/] [open_free_list/] [trunk/] [hdl/] [open_free_list.v] - Rev 3

Compare with Previous | Blame | View Log

module open_free_list #(parameter RAM_W = 128, RAM_E = 0, RAM_S = 64, CNK_S = 128, RAM_TYPE = "MRAM", FL_AEMPTY_LVL=2) (
  input  wire                                 reset_n,
  input  wire                                 clk,
  // Write side
  output wire [clog2((RAM_S*1024)/CNK_S)-1:0] fl_q,
  output wire                                 fl_aempty,
  output wire                                 fl_empty,
  input  wire                                 wren,
  input  wire [RAM_W+RAM_E-1:0]               din,
  input  wire                                 eop,
  // Read side
  input  wire [clog2((RAM_S*1024)/CNK_S)-1:0] chunk_num,
  input  wire                                 load_req,
  input  wire                                 rel_req,
  output reg                                  load_rel_ack,
  input  wire                                 rden,
  output wire [RAM_W+RAM_E-1:0]               dout
);
 
localparam FL_S = (RAM_S*1024)/CNK_S;
localparam FL_W = clog2(FL_S);
localparam FL_ADDR_W = FL_W;
localparam LL_W = FL_W+1;
localparam RAM_ADDR_W = clog2((RAM_S*1024)/(RAM_W/8));
localparam LINES_IN_CNK = CNK_S/(RAM_W/8);
localparam IN_CNK_ADDR_W = clog2(LINES_IN_CNK);
 
 
wire [RAM_W+RAM_E-1:0]  ram_q;
reg  [RAM_ADDR_W-1:0]   ram_rd_addr;
wire [RAM_ADDR_W-1:0]   ram_wr_addr;
reg  [RAM_ADDR_W-1:0]   ram_wr_addr_lat;
reg                     wr_eop_while_ll;
reg  [FL_W-1:0]         fl_data;
wire [FL_ADDR_W-1:0]    fl_lvl;
reg                     fl_rden;
reg                     fl_wren;
wire [FL_W:0]           ll_data;
wire [FL_W:0]           ll_q;
reg  [FL_ADDR_W-1:0]    ll_rd_addr;
wire [FL_ADDR_W-1:0]    ll_wr_addr;
wire                    ll_wren;
wire                    ll_eop;
 
reg  [FL_ADDR_W-1:0]    fl_init_cnt;
reg                     fl_init;
reg                     fl_init_r1;
reg                     fl_init_r2;
reg                     fl_init_r3;
reg                     fl_init_wr;
 
reg                     int_sop;
reg                     rel_req_from_idle;
 
wire                    load_req_p;
wire [FL_ADDR_W-1:0]    nxt_chunk_ptr;
 
reg  [2:0]              ns_rd_sm;
reg  [2:0]              cs_rd_sm;
parameter               IDLE           = 3'd0,
                        PREFETCH       = 3'd1,
                        RD             = 3'd2,
                        WAIT_REL       = 3'd3,
                        REL_DELAY1     = 3'd4,
                        REL_DELAY2     = 3'd5,
                        REL_WR2FL      = 3'd6;
 
reg                     sm_rel_ctrl;
reg                     sm_rel_wren;
reg						sm_rel_ctrl_mask;
reg						sm_rel_ctrl_mask_clr;
reg						sm_rel_ctrl_mask_set;
 
reg                     int_rden;
reg                     load_req_r1;
reg  [RAM_ADDR_W-1:0]   usr_ram_rd_addr_r1;
 
altsyncram3 ram (
  .data       (din),
  .rd_aclr    (~reset_n),
  .rdaddress  (ram_rd_addr),
  .rdclock    (clk),
  .rdclocken  (int_rden | rden),
  .wraddress  (ram_wr_addr),
  .wrclock    (clk),
  .wrclocken  (1'b1),
  .wren       (wren),
  .q          (dout)
);
defparam
  ram.A_WIDTH   = RAM_W+RAM_E,
  ram.A_WIDTHAD = RAM_ADDR_W,
  ram.RAM_TYPE  = RAM_TYPE,
  ram.USE_RDEN  = 0;
 
alt_scfifo free_list(
  .aclr          (~reset_n),
  .clock         (clk),
  .data          (fl_init_wr ? fl_init_cnt : fl_data),
  .rdreq         (fl_rden),
  .sclr          (1'b0),
  .wrreq         (fl_init_wr | fl_wren),
  .almost_empty  (fl_aempty),
  .almost_full   (),
  .empty         (fl_empty),
  .full          (),
  .q             (fl_q),
  .usedw         (fl_lvl)
);
defparam
   free_list.FIFO_WIDTH    = FL_W,
   free_list.FIFO_DEPTH    = FL_ADDR_W,
   free_list.FIFO_TYPE     = "M4K",
   free_list.FIFO_SHOW     = "ON",
   free_list.FIFO_AEMPTY   = FL_AEMPTY_LVL;
 
 
altsyncram3 link_list(
  .data       (ll_data),
  .rd_aclr    (~reset_n),
  .rdaddress  (sm_rel_ctrl ? nxt_chunk_ptr : ll_rd_addr),
  .rdclock    (clk),
  .rdclocken  (1'b1),
  .wraddress  (ll_wr_addr),
  .wrclock    (clk),
  .wrclocken  (1'b1),
  .wren       (ll_wren),
  .q          (ll_q)
);
defparam
  link_list.A_WIDTH   = LL_W,
  link_list.A_WIDTHAD = FL_ADDR_W,
  link_list.RAM_TYPE  = "M4K",
  link_list.USE_RDEN  = 0;
 
 
// Free list init
 
always @ (posedge clk, negedge reset_n)
begin
  if (reset_n==1'b0)
  begin
    fl_init_cnt <= {FL_ADDR_W{1'b0}};
    fl_init     <= 1'b0;
    fl_init_r1  <= 1'b0;
    fl_init_r2  <= 1'b0;
    fl_init_r3  <= 1'b0;
    fl_init_wr  <= 1'b0;
  end
  else
  begin
    fl_init_cnt <= fl_init_wr ? fl_init_cnt + 1'b1 : {FL_ADDR_W{1'b0}};
    fl_init     <= 1'b1;
    fl_init_r1  <= fl_init;
    fl_init_r2  <= fl_init_r1;
    fl_init_r3  <= fl_init_r2;
    fl_init_wr  <= !fl_init_r3 && fl_init_r2 ? 1'b1 : fl_init_cnt=={FL_ADDR_W{1'b1}} ?  1'b0 : fl_init_wr;
  end
end
 
 
// Write side
 
assign ram_wr_addr = int_sop || (wren && ram_wr_addr_lat[IN_CNK_ADDR_W-1:0]==(LINES_IN_CNK-1)) ? {fl_q, {IN_CNK_ADDR_W{1'b0}}}
                                                                                               : wren ? ram_wr_addr_lat + 1'b1
                                                                                                      : ram_wr_addr_lat;
assign ll_eop      = wren && ram_wr_addr[IN_CNK_ADDR_W-1:0]==0 && eop ? 1'b0 : eop | wr_eop_while_ll;
assign ll_wr_addr  = ram_wr_addr_lat[RAM_ADDR_W-1:IN_CNK_ADDR_W];
assign ll_data     = {fl_q, ll_eop};
assign ll_wren     = (wren && ((ram_wr_addr[IN_CNK_ADDR_W-1:0]==0) || eop)) || wr_eop_while_ll ? 1'b1 : 1'b0;
 
 
always @ (posedge clk, negedge reset_n)
begin
  if (reset_n==1'b0)
  begin
    fl_rden         <= 1'b0;
    int_sop         <= 1'b1;
    ram_wr_addr_lat <= {RAM_ADDR_W{1'b0}};
    wr_eop_while_ll <= 1'b0;
  end
  else
  begin
    fl_rden         <= wren && (ram_wr_addr[IN_CNK_ADDR_W-1:0]==0) ? 1'b1 : 1'b0;
    int_sop         <= wren && eop ? 1'b1 :
                       wren        ? 1'b0 :
                                     int_sop;
    ram_wr_addr_lat <= ram_wr_addr;
    wr_eop_while_ll <= wren && ram_wr_addr[IN_CNK_ADDR_W-1:0]==0 && eop ? 1'b1 : 1'b0;
  end
end
 
// Read side
assign load_req_p    = ~load_req_r1 & load_req;
assign nxt_chunk_ptr = ll_q[FL_W:1]; //can be sampled
 
always @*
begin
  case(cs_rd_sm)
    IDLE:
      ns_rd_sm = fl_init_wr ? IDLE       :
                 rel_req    ? REL_DELAY1 :
                 load_req   ? PREFETCH   :
                              IDLE;
    PREFETCH:
      ns_rd_sm = RD;
    RD:
      ns_rd_sm = load_req                                                                     ? PREFETCH  :
                 rden && (usr_ram_rd_addr_r1[IN_CNK_ADDR_W-1:0]==(LINES_IN_CNK-1)) && ll_q[0] ? WAIT_REL  : // true if the current chunk is the last chunk and was reached to its end and is released now                                                                                           : REL_WR2FL // true if the current chunk was reached to its end and is released now and is the last one
                 rel_req                                                                      ? REL_WR2FL :
                 																				RD;
    WAIT_REL:
      ns_rd_sm = rel_req ? IDLE : WAIT_REL;
    REL_DELAY1:
      ns_rd_sm = REL_DELAY2;
    REL_DELAY2:
      ns_rd_sm = REL_WR2FL;
    REL_WR2FL:
      ns_rd_sm = ll_q[0] ? IDLE : REL_DELAY2;
  endcase
end
 
always @*
begin
  rel_req_from_idle    = 1'b0;
  int_rden             = 1'b0;
  load_rel_ack         = 1'b0;
  sm_rel_ctrl_mask_set = 1'b0;
  sm_rel_ctrl_mask_clr = 1'b0;
  sm_rel_ctrl          = 1'b1;
  sm_rel_wren          = 1'b0;
  case(cs_rd_sm)
    IDLE:
    begin
      rel_req_from_idle    = rel_req;
      sm_rel_ctrl_mask_set = rel_req;
      sm_rel_ctrl          = 1'b0;
    end
    PREFETCH:
    begin
      int_rden      = 1'b1;
      load_rel_ack  = 1'b1;
      sm_rel_ctrl   = 1'b0;
    end
    RD:
    begin
      sm_rel_ctrl   = 1'b0;
    end
    WAIT_REL:
    begin
      load_rel_ack = rel_req;
    end
    REL_DELAY1:
    begin
      sm_rel_ctrl = ~sm_rel_ctrl_mask;
    end
    REL_DELAY2:
    begin
      sm_rel_ctrl = ~sm_rel_ctrl_mask;
    end
    REL_WR2FL:
    begin
      sm_rel_wren  = 1'b1;
      load_rel_ack = ll_q[0];
      sm_rel_ctrl_mask_clr = 1'b1;
    end
  endcase
end
 
always @ (posedge clk, negedge reset_n)
begin
  if (reset_n==1'b0)
  begin
    cs_rd_sm           <= 3'd0;
    load_req_r1        <= 1'b0;
    sm_rel_ctrl_mask   <= 1'b0;
    ll_rd_addr         <= {FL_ADDR_W{1'b0}};
    ram_rd_addr        <= {RAM_ADDR_W{1'b0}};
    usr_ram_rd_addr_r1 <= {RAM_ADDR_W{1'b0}};
    fl_wren            <= 1'b0;
    fl_data            <= {FL_W{1'b0}};
  end
  else
  begin
    cs_rd_sm           <= ns_rd_sm;
    load_req_r1        <= load_req;
    sm_rel_ctrl_mask   <= sm_rel_ctrl_mask_set ? 1'b1 :
                          sm_rel_ctrl_mask_clr ? 1'b0 :
                                                 sm_rel_ctrl_mask;
 
    ll_rd_addr         <= load_req_p  || rel_req_from_idle                                                                     ? chunk_num     :
                          sm_rel_wren || ((!sm_rel_ctrl && rden && (usr_ram_rd_addr_r1[IN_CNK_ADDR_W-1:0]==(LINES_IN_CNK-1)))) ? nxt_chunk_ptr :
                                                                                                                                 ll_rd_addr;
    ram_rd_addr        <= load_req_p                                                 ? {chunk_num,  {IN_CNK_ADDR_W{1'b0}}}     :
                          rden && (ram_rd_addr[IN_CNK_ADDR_W-1:0]==(LINES_IN_CNK-1)) ? {nxt_chunk_ptr,  {IN_CNK_ADDR_W{1'b0}}} :
                          rden || int_rden                                           ? ram_rd_addr + 1'b1                      :
                                                                                       ram_rd_addr;
    usr_ram_rd_addr_r1 <= !sm_rel_ctrl && (rden || int_rden) ? ram_rd_addr : usr_ram_rd_addr_r1;
    fl_wren            <= (!sm_rel_ctrl && rden && (usr_ram_rd_addr_r1[IN_CNK_ADDR_W-1:0]==(LINES_IN_CNK-1))) || sm_rel_wren ? 1'b1 : 1'b0;
    fl_data            <= rel_req_from_idle ? chunk_num  :
                          sm_rel_wren       ? ll_rd_addr :
                                              usr_ram_rd_addr_r1[RAM_ADDR_W-1:IN_CNK_ADDR_W];
 
  end
end
 
/********************************************************
  clog2 - function that returns log2 of a value rounded up
        - min return value is 1 (in case of clog2(1)=1)
 ********************************************************/
function integer clog2(input integer value);
begin
  value = value-1;
  for (clog2=0; value>0; clog2=clog2+1)
    value = value>>1;
  if (clog2 == 0)
    clog2 = 1;
end
endfunction
 
endmodule
 

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.