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

Subversion Repositories wf3d

[/] [wf3d/] [trunk/] [implement/] [rtl/] [axi_cmn/] [fm_port_priority.v] - Rev 9

Compare with Previous | Blame | View Log

//=======================================================================
// Project Monophony
//   Wire-Frame 3D Graphics Accelerator IP Core
//
// File:
//   fm_port_priority.v
//
// Abstract:
//   Memory Interconnect port priority decision
//
// Author:
//   Kenji Ishimaru (info.info.wf3d@gmail.com)
//
//======================================================================
//
// Copyright (c) 2016, Kenji Ishimaru
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
//  -Redistributions of source code must retain the above copyright notice,
//   this list of conditions and the following disclaimer.
//  -Redistributions in binary form must reproduce the above copyright notice,
//   this list of conditions and the following disclaimer in the documentation
//   and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Revision History
 
//`define USE_THREAD
module fm_port_priority (
  clk_core,
  rst_x,
  // port0 side Read/Write
  i_req0,
  i_we0,
  i_add0,
  i_len0,
  i_be0,
  o_cack0,
  i_strw0,
  i_dbw0,
  i_wdata_read_end0,
  o_wdata_ack0,
  o_strr0,
  o_dbr0,
  // port1 side Read/Write
  i_req1,
  i_we1,
  i_add1,
  i_len1,
  i_be1,
  o_cack1,
  i_strw1,
  i_dbw1,
  i_wdata_read_end1,
  o_wdata_ack1,
  o_strr1,
  o_dbr1,
  // port2 side Read Only
  i_req2,
  i_add2,
  i_len2,
  o_cack2,
  o_strr2,
  o_dbr2,
  // port3 side Write Only
  i_req3,
  i_add3,
  i_len3,
  i_be3,
  o_cack3,
  i_strw3,
  i_dbw3,
  i_wdata_read_end3,
  o_wdata_ack3,
  // output to bus bridge or
  // memory bus arbiter far
  o_breq,
  o_bwe,
  o_bid,
  o_badd,
  o_blen,
  i_back,
  o_bstrw,
  o_bbe,
  o_bdbw,
  i_backw,
  i_bstrr,
  i_blast,
  i_brid,
  i_bdbr
);
`include "polyphony_params.v"
////////////////////////////
// Parameter definition
////////////////////////////
parameter P_SIDLE  = 1'b0;
parameter P_SDIN   = 1'b1;
////////////////////////////
// I/O definition
////////////////////////////
// port 0
input         i_req0;         // command request
input         i_we0;          // write/read flag
input  [P_IB_ADDR_WIDTH-1:0]
              i_add0;         // address
input  [P_IB_LEN_WIDTH-1:0]
              i_len0;         // burst length
input  [P_IB_BE_WIDTH-1:0]
              i_be0;          // byte enable
output        o_cack0;        // command acknowledge
input         i_strw0;        // write data strobe
input  [P_IB_DATA_WIDTH-1:0]
              i_dbw0;         // write data
input         i_wdata_read_end0;
                              // write data end flag
output        o_wdata_ack0;   // write data acknowledge
output        o_strr0;        // read data strobe
output [P_IB_DATA_WIDTH-1:0]
              o_dbr0;         // read data
// port 1
input         i_req1;         // command request
input         i_we1;          // write/read flag
input  [P_IB_ADDR_WIDTH-1:0]
              i_add1;         // address
input  [P_IB_LEN_WIDTH-1:0]
              i_len1;         // burst length
input  [P_IB_BE_WIDTH-1:0]
              i_be1;          // byte enable
output        o_cack1;        // command acknowledge
input         i_strw1;        // write data strobe
input  [P_IB_DATA_WIDTH-1:0]
              i_dbw1;         // write data
input         i_wdata_read_end1;
                              // write data end flag
output        o_wdata_ack1;   // write data acknowledge
output        o_strr1;        // read data strobe
output  [P_IB_DATA_WIDTH-1:0]
              o_dbr1;         // read data
// port 2
input         i_req2;         // command request
input  [P_IB_ADDR_WIDTH-1:0]
              i_add2;         // address
input  [P_IB_LEN_WIDTH-1:0]
              i_len2;         // burst length
output        o_cack2;        // command acknowledge
output        o_strr2;        // read data strobe
output [P_IB_DATA_WIDTH-1:0]
              o_dbr2;         // read data
// port 3
input         i_req3;         // command request
input  [P_IB_ADDR_WIDTH-1:0]
              i_add3;         // address
input  [P_IB_LEN_WIDTH-1:0]
              i_len3;         // burst length
input  [P_IB_BE_WIDTH-1:0]
              i_be3;          // byte enable
output        o_cack3;        // command acknowledge
input         i_strw3;        // write data strobe
input  [P_IB_DATA_WIDTH-1:0]
              i_dbw3;         // write data
input         i_wdata_read_end3;
                              // write data end flag
output        o_wdata_ack3;   // write data acknowledge
// output to bus bridge or
// memory bus arbiter far
output        o_breq;         // command request
output        o_bwe;          // write/read flag
output [1:0]  o_bid;
output [P_IB_ADDR_WIDTH-1:0]
              o_badd;         // address
output [P_IB_LEN_WIDTH-1:0]
              o_blen;         // burst length
output [P_IB_BE_WIDTH-1:0]
              o_bbe;          // byte enable
input         i_back;         // command acknowledge
output        o_bstrw;        // write data strobe
output [P_IB_DATA_WIDTH-1:0]
              o_bdbw;         // write data
input         i_backw;        // write data acknowledge
input         i_bstrr;        // read data strobe
input         i_blast;
input  [1:0]  i_brid;
input  [P_IB_DATA_WIDTH-1:0]
              i_bdbr;         // read data
 
input         clk_core;        // system clock
input         rst_x;          // system reset
 
/////////////////////////
//  register definition
/////////////////////////
reg        r_breq;
reg        r_bwe;
reg [1:0]  r_bid;
reg [P_IB_ADDR_WIDTH-1:0] r_badd;
reg [P_IB_LEN_WIDTH-1:0]  r_blen;
reg [P_IB_BE_WIDTH-1:0]   r_bbe;
reg        r_back;
reg        r_bstrw;
reg [P_IB_DATA_WIDTH-1:0] r_bdbw;
reg        r_backw;
reg        r_bstrr;
reg [1:0]  r_brid;
reg [P_IB_DATA_WIDTH-1:0] r_bdbr;
// current priority
reg [1:0]  r_current_priority;  // 0 - 3
 
// read data counter
reg [P_IB_LEN_WIDTH-1:0]  r_read_cnt;
 
// write data state machine
reg        r_wstate;
// read data final out
reg        r_strr2;
reg [P_IB_DATA_WIDTH-1:0] r_dbr2;
 
/////////////////////////
//  wire definition
/////////////////////////
// current port
wire        w_req;
wire        w_we;
wire [P_IB_ADDR_WIDTH-1:0] w_add;
wire [P_IB_LEN_WIDTH-1:0]  w_len;
wire [P_IB_BE_WIDTH-1:0]   w_be;
wire        w_strw;
wire [P_IB_DATA_WIDTH-1:0] w_dbw;
wire        w_wdata_read_end;
wire        w_wdata_read;
wire        w_write_burst;
wire        w_wdata_idle;
wire        w_rfifo_ok;
 
// masked back
wire      w_back;
 
// bridge port
wire      w_breq;
wire      w_bstrw;
 
wire [3:0] w_sreq;
wire [1:0] w_decide_port;
wire       w_wstate_idle;
wire       w_wstate_din;
// fifo port
wire       w_fifo_full;
wire [2+P_IB_LEN_WIDTH-1:0]
           w_fifo_din;
wire [2+P_IB_LEN_WIDTH-1:0]
           w_fifo_dout;
wire       w_fifo_write;
wire [P_IB_LEN_WIDTH-1:0]
           w_current_read_len;
wire [1:0] w_current_read_pr;
wire       w_read_end;
wire       w_set_priority;
wire [1:0] w_wdata_port;
 
// read data final out
wire        w_strr2;
wire [P_IB_DATA_WIDTH-1:0] w_dbr2;
 
/////////////////////////
//  assign statement
/////////////////////////
// masked back
assign w_back = r_back;
 
assign w_sreq = {i_req3,i_req2,i_req1,i_req0};
assign w_decide_port = f_decide_port(w_sreq,r_current_priority);
assign w_wstate_idle = (r_wstate == P_SIDLE);
assign w_wstate_din = (r_wstate == P_SDIN);
assign w_wdata_idle = (w_we) ?  r_backw & w_wstate_idle :  w_wstate_idle;
assign w_wdata_port = (w_wstate_idle) ? w_decide_port : r_current_priority;
assign w_wdata_read = w_wstate_din | (w_req & w_we & w_back);
`ifdef USE_THREAD
assign w_rfifo_ok = 1'b1;
`else
assign w_rfifo_ok = (!w_we) ?  !w_fifo_full :  1'b1;
`endif
// command end cycle flag
assign w_set_priority = w_req & w_back & w_wdata_idle;
 
// port0
assign o_cack0 = w_set_priority & w_rfifo_ok & (w_decide_port == 2'd0);
assign o_wdata_ack0 = r_backw & w_wdata_read & (w_wdata_port == 2'd0);
`ifdef USE_THREAD
assign o_strr0 = r_bstrr & (r_brid == 2'd0);
`else
assign o_strr0 = r_bstrr & (w_current_read_pr == 2'd0);
`endif
assign o_dbr0 = r_bdbr;
 
// port1
assign o_cack1 = w_set_priority & w_rfifo_ok & (w_decide_port == 2'd1);
assign o_wdata_ack1 = r_backw & w_wdata_read & (w_wdata_port == 2'd1);
`ifdef USE_THREAD
assign o_strr1 = r_bstrr & (r_brid == 2'd1);
`else
assign o_strr1 = r_bstrr & (w_current_read_pr == 2'd1);
`endif
assign o_dbr1 = r_bdbr;
 
// port2
assign o_cack2 = w_set_priority & w_rfifo_ok & (w_decide_port == 2'd2);
`ifdef USE_THREAD
assign w_strr2 = r_bstrr & (r_brid == 2'd2);
`else
assign w_strr2 = r_bstrr & (w_current_read_pr == 2'd2);
`endif
assign w_dbr2 = r_bdbr;
assign o_strr2 = r_strr2;
assign o_dbr2 = r_dbr2;
 
// port3
assign o_cack3 = w_set_priority & w_rfifo_ok & (w_decide_port == 2'd3);
assign o_wdata_ack3 = r_backw & w_wdata_read & (w_wdata_port == 2'd3);
 
// current port
assign w_req = (w_decide_port == 2'd0) ? i_req0 :
               (w_decide_port == 2'd1) ? i_req1 :
               (w_decide_port == 2'd2) ? i_req2 : i_req3;
assign w_we  = (w_decide_port == 2'd0) ? i_we0 :
               (w_decide_port == 2'd1) ? i_we1 :
               (w_decide_port == 2'd2) ? 1'b0 : 1'b1;
assign w_add = (w_decide_port == 2'd0) ? i_add0 :
               (w_decide_port == 2'd1) ? i_add1 :
               (w_decide_port == 2'd2) ? i_add2 :i_add3;
assign w_len = (w_decide_port == 2'd0) ? i_len0 :
               (w_decide_port == 2'd1) ? i_len1 :
               (w_decide_port == 2'd2) ? i_len2 : i_len3;
assign w_be  = (w_wdata_port == 2'd0) ? i_be0 :
               (w_wdata_port == 2'd1) ? i_be1 :
               (w_wdata_port == 2'd2) ? 8'h00 : i_be3;
assign w_dbw = (w_wdata_port == 2'd0) ? i_dbw0 :
               (w_wdata_port == 2'd1) ? i_dbw1 :
               (w_wdata_port == 2'd2) ?  32'h0000_0000 : i_dbw3;
assign w_strw = (w_wdata_port == 2'd0) ? i_strw0 :
                (w_wdata_port == 2'd1) ? i_strw1 :
                (w_wdata_port == 2'd2) ? 1'b0 : i_strw3;
assign w_wdata_read_end = (w_wdata_port == 2'd0) ? (i_wdata_read_end0 & r_backw) :
                          (w_wdata_port == 2'd1) ? (i_wdata_read_end1 & r_backw) :
                          (w_wdata_port == 2'd3) ? (i_wdata_read_end3 & r_backw) : 1'b0;
 
assign w_write_burst = w_req & w_we & (w_len != 1) & w_back & r_backw;
 
 
// bridge port
//assign w_breq = w_req & w_back & w_wdata_idle;
// 2004/11/27
  assign w_breq = w_req & w_back & w_wdata_idle & w_rfifo_ok;
 
assign w_bstrw =  w_strw & w_wdata_read & r_backw;
// bridge port output connection
assign o_breq = r_breq;
assign o_bwe = r_bwe;
assign o_bid = r_bid;
assign o_badd = r_badd;
assign o_blen = r_blen;
assign o_bstrw = r_bstrw;
assign o_bbe = r_bbe;
assign o_bdbw = r_bdbw;
 
// fifo port
assign w_fifo_din = {w_decide_port,w_len};
assign w_fifo_write = w_req & w_back & !w_we & w_set_priority;
assign {w_current_read_pr,w_current_read_len} = w_fifo_dout;
assign w_read_end = (r_read_cnt == w_current_read_len) & r_bstrr;
 
// debug
wire w_wrong_id;
assign w_wrong_id = r_bstrr & (w_current_read_pr != r_brid);
 
/////////////////////////
//  function statement
/////////////////////////
function [1:0] f_decide_port;
  input [3:0] req;
  input [1:0] cp;
  begin
    case (req)
      4'b0000: begin
        // no request
        f_decide_port = cp;
      end
      4'b0001: begin
        // only port0 request
        f_decide_port = 2'd0;
      end
      4'b0010: begin
        // only port1 request
        f_decide_port = 2'b1;
      end
      4'b0011: begin
        // simultaneous request port 1 & 0
        case (cp)
          2'b00 : f_decide_port = 2'd1;
          default : f_decide_port = 2'd0;
        endcase
      end
      4'b0100: begin
        // only port2 request
        f_decide_port = 2'd2;
      end
      4'b0101: begin
        // simultaneous request port 2 & 0
        case (cp)
          2'b00,
          2'b01 : f_decide_port = 2'd2;
          default : f_decide_port = 2'd0;
        endcase
      end
      4'b0110: begin
        // simultaneous request port 2 & 1
        case (cp)
          2'b01 : f_decide_port = 2'd2;
          default : f_decide_port = 2'd1;
        endcase
      end
      4'b0111: begin
        // simultaneous request port 2 & 1 & 0
        case (cp)
          2'b00 : f_decide_port = 2'd1;
          2'b01 : f_decide_port = 2'd2;
          default : f_decide_port = 2'd0;
        endcase
      end
      4'b1000: begin
        // port 3 request
        f_decide_port = 2'd3;
      end
      4'b1001: begin
        // only port3&0 request
        case (cp)
          2'd0,
          2'd1,
          2'd2 : f_decide_port = 2'd3;
          default : f_decide_port = 2'd0;
        endcase
      end
      4'b1010: begin
        // only port 3 & 1 request
        case (cp)
          2'd1,
          2'd2 : f_decide_port = 2'd3;
          default : f_decide_port = 2'd1;
        endcase
      end
      4'b1011: begin
        // simultaneous request port 3 & 1 & 0
        case (cp)
          2'd0 : f_decide_port = 2'd1;
          2'd1,
          2'd2 : f_decide_port = 2'd3;
          default : f_decide_port = 2'd0;
        endcase
      end
      4'b1100: begin
        // simultaneous request port 3 & 2
        case (cp)
          2'd2 : f_decide_port = 2'd3;
          default : f_decide_port = 2'd2;
        endcase
      end
      4'b1101: begin
        // simultaneous request port 3 & 2 & 0
        case (cp)
          2'd0,
          2'd1 : f_decide_port = 2'd2;
          2'd2 : f_decide_port = 2'd3;
          default : f_decide_port = 2'd0;
        endcase
      end
      4'b1110: begin
        // simultaneous request port 3 & 2 & 1
        case (cp)
          2'd1 : f_decide_port = 2'd2;
          2'd2 : f_decide_port = 2'd3;
          default : f_decide_port = 2'd1;
        endcase
      end
      4'b1111: begin
        // simultaneous request port 3 & 2 & 1 & 0
        case (cp)
          2'd0 : f_decide_port = 2'd1;
          2'd1 : f_decide_port = 2'd2;
          2'd2 : f_decide_port = 2'd3;
          2'd3 : f_decide_port = 2'd0;
          default : f_decide_port = 2'd0;
        endcase
      end
      default : f_decide_port = 2'd0;
    endcase
    // test : port2 always has top priority
    if (req[2]) f_decide_port = 2'd2;
  end
endfunction
 
/////////////////////////
//  always statement
/////////////////////////
// write data state machine
always @(posedge clk_core or negedge rst_x) begin
  if (~rst_x) begin
    r_wstate <= P_SIDLE;
  end else begin
    case (r_wstate)
      P_SIDLE :  // Idle
        begin
          if (w_write_burst) begin
            r_wstate <= P_SDIN;
          end
        end
      P_SDIN :   // Getting write data & be
        begin
          if (w_wdata_read_end) begin
            r_wstate <= P_SIDLE;
          end
        end
      default : r_wstate <= r_wstate;
    endcase
  end
end
 
 
// current priority
always @(posedge clk_core or negedge rst_x) begin
  if (~rst_x) begin
    r_current_priority <= 2'd3;   // lowest priority port number
  end else begin
    if (w_set_priority) begin
      r_current_priority <= w_decide_port;
    end
  end
end
// read data counter
always @(posedge clk_core or negedge rst_x) begin
  if (~rst_x) begin
    r_read_cnt <= 1;
  end else begin
    if (w_read_end) begin
      r_read_cnt <= 1;
    end else if (r_bstrr) begin
      r_read_cnt <= r_read_cnt + 1'b1;
    end
  end
end
 
// bus bridge (or memory arbiter far) port
always @(posedge clk_core or negedge rst_x) begin
  if (~rst_x) begin
    r_breq <= 1'b0;
  end else begin
    r_breq <= w_breq;
  end
end
 
always @(posedge clk_core or negedge rst_x) begin
  if (~rst_x) begin
    r_bstrw <= 1'b0;
  end else begin
    r_bstrw <= w_bstrw;
  end
end
 
always @(posedge clk_core) begin
`ifdef USE_THREAD
  r_bid <= (w_decide_port == 2'd0) ? 2'd0 :
           (w_decide_port == 2'd1) ? 2'd1 :
           (w_decide_port == 2'd2) ? 2'd2 : 2'd3;
`else
  r_bid <= 2'd0;
`endif
  r_bwe <= w_we;
  r_badd <= w_add;
  r_blen <= w_len;
  r_bbe <= w_be;
  r_bdbw <= w_dbw;
end
 
always @(posedge clk_core or negedge rst_x) begin
  if (~rst_x) begin
    r_bstrr <= 1'b0;
  end else begin
    r_bstrr <= i_bstrr;
  end
end
 
always @(posedge clk_core) begin
  r_brid <= i_brid;
  r_bdbr <= i_bdbr;
end
 
always @(posedge clk_core or negedge rst_x) begin
  if (~rst_x) begin
    r_back <= 1'b0;
    r_backw <= 1'b0;
  end else begin
    r_back <= i_back;
    r_backw <= i_backw;
  end
end
 
// read data strobe & outout (Read Only Port)
always @(posedge clk_core or negedge rst_x) begin
  if (~rst_x) begin
    r_strr2 <= 1'b0;
  end else begin
    r_strr2 <= w_strr2;
  end
end
 
always @(posedge clk_core) begin
  r_dbr2 <= w_dbr2;
end
 
/////////////////////////
//  module instantiation
/////////////////////////
// read data priority fifo
// contain port number + burst length
wire [7:0] w_dnum;
wire       w_empty;
`ifdef USE_THREAD
`else
fm_cmn_bfifo #(2+P_IB_LEN_WIDTH,7) fifo (
  .clk_core(clk_core),
  .rst_x(rst_x),
  .i_wstrobe(w_fifo_write),
  .i_dt(w_fifo_din),
  .o_full(w_fifo_full),
  .i_renable(w_read_end),
  .o_dt(w_fifo_dout),
  .o_empty(w_empty),
  .o_dnum(w_dnum)
);
`endif
 
 
wire    w_error;
assign w_error = w_empty & r_bstrr;
 
reg [15:0]    r_req_cnt;
reg [15:0]    r_acc_cnt;
 
always @(posedge clk_core or negedge rst_x) begin
  if (~rst_x) begin
    r_req_cnt <= 'd0;
    r_acc_cnt <= 'd0;
  end else begin
    if (w_fifo_write) r_req_cnt <= r_req_cnt + w_len;
   if (i_bstrr) r_acc_cnt <= r_acc_cnt + 1'b1;
 
  end
end
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.