//======================================================================
//
// 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
//======================================================================