aboutsummaryrefslogblamecommitdiff
path: root/src/rtl/fmc_arbiter.v
blob: 037d6401024605109064d5b928694edaed2050bd (plain) (tree)
1
2
3
4
5
6
7
8
9








                                                                        
                                                             































                                                                           























                                                






















                                                          

                                                                   







                                                                               

                        


                                                                          





































































































































































                                                                                                                                  







                                                                        
//======================================================================
//
// fmc_arbiter.v
// -------------
// Port arbiter for the FMC interface for the Cryptech
// Novena FPGA + STM32 Bridge Board framework.
//
//
// Author: Pavel Shatov
// Copyright (c) 2015, 2018 NORDUnet A/S 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.
//
// - Neither the name of the NORDUnet nor the names of its contributors may
//   be used to endorse or promote products derived from this software
//   without specific prior written permission.
//
// 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.
//
//======================================================================

module fmc_arbiter
  (
   // fmc bus
   fmc_a, fmc_d,
   fmc_ne1, fmc_nl, fmc_nwe, fmc_noe, fmc_nwait,

   // system clock
   sys_clk,

   // user bus
   sys_addr,
   sys_wr_en,
   sys_data_out,
   sys_rd_en,
   sys_data_in
   );


   //
   // Parameters
   //
   parameter NUM_ADDR_BITS = 22;


   //
   // Ports
   //
   input        wire [NUM_ADDR_BITS-1:0] fmc_a;
   inout        wire [             31:0] fmc_d;
   input        wire                     fmc_ne1;
   input        wire                     fmc_nl;
   input        wire                     fmc_nwe;
   input        wire                     fmc_noe;
   output       wire                     fmc_nwait;

   input        wire                     sys_clk;

   output       wire [NUM_ADDR_BITS-1:0] sys_addr;
   output       wire                     sys_wr_en;
   output       wire [             31:0] sys_data_out;
   output       wire                     sys_rd_en;
   input        wire [             31:0] sys_data_in;


   //
   // Data Bus PHY
   //

   /* PHY is needed to control bi-directional data bus. */

   wire [31: 0] fmc_d_ro; // value read from pins (receiver output)
   wire [31: 0] fmc_d_di; // value drives onto pins (driver input)

   fmc_d_phy #
     (
      .BUS_WIDTH(32)
      )
   d_phy
     (
      .buf_io(fmc_d),          // <-- connect directly to top-level bi-dir port
      .buf_di(fmc_d_di),
      .buf_ro(fmc_d_ro),
      .buf_t(fmc_noe)          // <-- bus direction is controlled by STM32
      );

    //
    // Two-Stage Synchronizer
    //
    (* SHREG_EXTRACT="NO" *) (* IOB="FALSE" *) reg [23: 0] fmc_a_ff1;
    (* SHREG_EXTRACT="NO" *)                   reg [23: 0] fmc_a_ff2;

    (* SHREG_EXTRACT="NO" *) (* IOB="TRUE" *)  reg [31: 0] fmc_d_ro_ff1;
    (* SHREG_EXTRACT="NO" *)                   reg [31: 0] fmc_d_ro_ff2;

    (* SHREG_EXTRACT="NO" *) (* IOB="FALSE" *) reg fmc_ne1_ff1;
    (* SHREG_EXTRACT="NO" *)                   reg fmc_ne1_ff2;

    (* SHREG_EXTRACT="NO" *) (* IOB="FALSE" *) reg fmc_nwe_ff1;
    (* SHREG_EXTRACT="NO" *)                   reg fmc_nwe_ff2;

    (* SHREG_EXTRACT="NO" *) (* IOB="FALSE" *) reg fmc_nl_ff1;
    (* SHREG_EXTRACT="NO" *)                   reg fmc_nl_ff2;

    wire [23: 0] fmc_a_sync    = fmc_a_ff2;
    wire [31: 0] fmc_d_ro_sync = fmc_d_ro_ff2;
    wire         fmc_ne1_sync  = fmc_ne1_ff2;
    wire         fmc_nwe_sync  = fmc_nwe_ff2;
    wire         fmc_nl_sync   = fmc_nl_ff2;
		
	always @(posedge sys_clk) begin
		fmc_a_ff1    <= fmc_a;
		fmc_a_ff2    <= fmc_a_ff1;
		
		fmc_d_ro_ff1 <= fmc_d_ro;
		fmc_d_ro_ff2 <= fmc_d_ro_ff1;
		
		fmc_ne1_ff1  <= fmc_ne1;
		fmc_ne1_ff2  <= fmc_ne1_ff1;
				
		fmc_nwe_ff1  <= fmc_nwe;
		fmc_nwe_ff2  <= fmc_nwe_ff1;
		
		fmc_nl_ff1   <= fmc_nl;
		fmc_nl_ff2   <= fmc_nl_ff1;
	end


		//
		// FSM
		//
	localparam	FSM_STATE_IDLE              = 4'd0;
	
	localparam	FSM_STATE_WRITE_START       = 4'd1;
	localparam	FSM_STATE_WRITE_LATENCY_1   = 4'd2;
	localparam	FSM_STATE_WRITE_LATENCY_2   = 4'd3;
	localparam	FSM_STATE_WRITE_LATENCY_3   = 4'd4;
	localparam	FSM_STATE_WRITE_LATENCY_4   = 4'd5;
	localparam	FSM_STATE_WRITE_STOP        = 4'd6;
	
	localparam	FSM_STATE_READ_START        = 4'd7;
	localparam	FSM_STATE_READ_LATENCY_1    = 4'd8;
	localparam	FSM_STATE_READ_STOP         = 4'd9;

	reg	[ 3: 0]	fsm_state = FSM_STATE_IDLE;
	reg	[ 3: 0]	fsm_state_next;
	
	always @(posedge sys_clk)
		//
		fsm_state <= fsm_state_next;

	
		//
		// FSM Transition Logic
		//
	always @*
		//
		if (fmc_ne1_sync)               fsm_state_next = FSM_STATE_IDLE;
		else case (fsm_state)
			FSM_STATE_IDLE:             fsm_state_next = !fmc_nwe_sync ? FSM_STATE_WRITE_START : FSM_STATE_READ_START;
			FSM_STATE_WRITE_START:      fsm_state_next = FSM_STATE_WRITE_LATENCY_1;
			FSM_STATE_WRITE_LATENCY_1:  fsm_state_next = FSM_STATE_WRITE_LATENCY_2;
			FSM_STATE_WRITE_LATENCY_2:  fsm_state_next = FSM_STATE_WRITE_LATENCY_3;
			FSM_STATE_WRITE_LATENCY_3:  fsm_state_next = FSM_STATE_WRITE_LATENCY_4;
			FSM_STATE_WRITE_LATENCY_4,
			FSM_STATE_WRITE_STOP:       fsm_state_next = FSM_STATE_WRITE_STOP;
			FSM_STATE_READ_START:       fsm_state_next = FSM_STATE_READ_LATENCY_1;
			FSM_STATE_READ_LATENCY_1,
			FSM_STATE_READ_STOP:        fsm_state_next = FSM_STATE_READ_STOP;
			default:                    fsm_state_next = FSM_STATE_IDLE;
		endcase


    //
    // Output Data Latch
    //
    (* IOB="TRUE" *)
	reg	[31:0] sys_data_in_latch;
    
	assign fmc_d_di = sys_data_in_latch;
	
    
    //
    // Address Latch
    //
	always @(posedge sys_clk)
		//
		if (!fmc_ne1_sync && !fmc_nl_sync)
			//
			sys_addr_reg <= fmc_a_sync;


    //
    // System Interface
    //
    reg [NUM_ADDR_BITS-1:0] sys_addr_reg;
    reg                     sys_wr_en_reg = 1'b0;
    reg [             31:0] sys_data_out_reg;
    reg                     sys_rd_en_reg = 1'b0;

    assign sys_addr     = sys_addr_reg;
    assign sys_wr_en    = sys_wr_en_reg;
    assign sys_data_out = sys_data_out_reg;
    assign sys_rd_en    = sys_rd_en_reg;


    //
    // Write Enable Logic
    //
	always @(posedge sys_clk)
		//
		case (fsm_state)
			FSM_STATE_WRITE_LATENCY_4:  sys_wr_en_reg <= 1'b1;
			default:                    sys_wr_en_reg <= 1'b0;
		endcase

    
    //
    // Read Enable Logic
    //
	always @(posedge sys_clk)
		//
		case (fsm_state_next)
			FSM_STATE_READ_START:   sys_rd_en_reg <= 1'b1;
			default:                sys_rd_en_reg <= 1'b0;
		endcase


    //
    // Output Data Latch
    //
	always @(posedge sys_clk)
		//
		case (fsm_state)
			FSM_STATE_READ_LATENCY_1:   sys_data_in_latch <= sys_data_in;
		endcase


    //
    // Input Data Latch
    //
	always @(posedge sys_clk)
		//
		case (fsm_state)
			FSM_STATE_WRITE_LATENCY_4:  sys_data_out_reg <= fmc_d_ro_sync;
		endcase


    //
    // Unused NWAIT tieoff
    //
	assign fmc_nwait = 1'b0;


endmodule


//======================================================================
// EOF fmc_arbiter.v
//======================================================================