// vxi_if.v
// VXI bus second level gateway
// $Id$
// Larry Doolittle, LBNL
// llc-suite Copyright (c) 2004, The Regents of the University of
// California, through Lawrence Berkeley National Laboratory (subject
// to receipt of any required approvals from the U.S. Dept. of Energy).
// All rights reserved.
// Your use of this software is pursuant to a "BSD-style" open
// source license agreement, the text of which is in license.txt
// (md5sum a1e0e81c78f6eba050b0e96996f49fd5) that should accompany
// this file. If the license agreement is not there, or if you
// have questions about the license, please contact Berkeley Lab's
// Technology Transfer Department at TTD@lbl.gov referring to
// "llc-suite (LBNL Ref CR-1988)"
// Takes pins from Matt Stettler VXI bus interface, and communicates
// with the on-chip bus meta-implemented in intercon.pl.
// Reverse-engineered from Craig Swanson's vxi_lbus_int.vhd.
// Nominally works in simulation as of 2/27/2004. Woo-hoo!
//
// This copy is missing all the LB stuff (used when on a PCI carrier)
// and is approximately one cycle quicker to respond to reads and writes
// (because I took out hc_meta).
//
// Contrast with nanoengine_if.v
`timescale 1ns / 1ns
module vxi_if
(
// ports on the LANL DFE XC2V1500
inout [15:0] QB, // pin a
input [3:0] HC, // pin c
input RESET, // pin e
input [13:0] PCI_AD, // pin f
input CLK40X, // pin g
output PCI_INTA_N, // pin h
output VHOLD, // pin i
// Debug signals to Mictor connectors
output [15:0] IA, // pin J11-msb
output [15:0] QA, // pin J11-lsb
output [15:0] IB, // pin J12-msb
output [15:0] QC, // pin J12-lsb
// buffered clock output
output clk40, // interconnect
// magic interconnect names implement the local (on-chip) bus master
output host_clk, // interconnect
output reg [13:0] host_addr, // interconnect
output reg [15:0] host_data, // interconnect
input [15:0] host_read, // interconnect
output reg host_we, // interconnect
output reg host_re, // interconnect
output rst, // interconnect
input host_interrupt, // interconnect
// we are our own client for this register
output [15:0] int_status, // register INT_STATUS
input int_status_en // select INT_STATUS
);
assign rst = ~RESET;
//assign IA = 16'hdead;
//assign QA = 16'hbeef;
//assign IB = 16'hcafe;
//assign QC = 16'hfeed;
// buffer the clock
BUFG u3( host_clk, CLK40X);
assign clk40 = host_clk; // Single clock domain. Hurray!
reg [3:0] hc_sync, hc_prev;
reg host_re_mature, bus_drive;
reg [15:0] read_result;
assign IA = {12'b0,CLK40X,host_re,host_we,bus_drive};
assign QA = {9'b0,host_interrupt,host_we,host_re,HC[3:0]};
assign IB = {2'b0,PCI_AD[13:0]};
assign QC = QB[15:0];
// Mapping from HC control bus signals to VXI bus names:
// HC[0] = VXI_WRSTB
// HC[1] = VXI_EXTENAn
// HC[2] = VXI_AS (address strobe?)
// HC[3] = VXI_WRn
//
// Tracing wires on the DFE and FCM schematics yields the following map:
// WRSTR <-> hc(0)
// EXTENA <-> hc(1)
// AS <-> hc(2)
// WR* <-> hc(3)
// PCI_AD <-> vxi_addr (but only pins 0-22)
// QB <-> VXI_D
//
// Reverse engineering notes:
// falling edge of HC[1] latches address bus
// rising edge of HC[0] latches data bus, when HC[2]=1
// falling edge of HC[1] starts write cycle, when HC[3]=0 and HC[2]=1
// falling edge of HC[1] starts read cycle, when HC[3]=1 and HC[2]=1
//
// That write cycle design starts too soon for my single-cycle
// paradigm. I changed it to:
// rising edge of HC[0] starts write cycle, when HC[3]=0 and HC[2]=1
wire ale = ~HC[1];
always @(posedge ale or posedge rst) if (rst) begin
host_addr <= 0;
end else begin
host_addr <= PCI_AD[13:0];
end
always @(posedge HC[0] or posedge rst) if (rst) begin
host_data <= 0;
end else begin
if (HC[2]) host_data <= QB;
end
always @(posedge host_clk or posedge rst) if (rst) begin
hc_sync <= 4'b1010;
hc_prev <= 4'b1010;
host_we <= 0;
host_re <= 0;
host_re_mature <= 0;
bus_drive <= 0;
read_result <= 0;
end else begin
hc_sync <= HC;
hc_prev <= hc_sync;
host_we <= hc_sync[0] & hc_sync[2] & ~hc_sync[3] & ~hc_prev[0]; // single cycle only
host_re <= ~hc_sync[1] & hc_sync[2] & hc_sync[3] & hc_prev[1]; // single cycle only
host_re_mature <= host_re;
if (host_re) read_result <= host_read;
bus_drive <= (host_re_mature | bus_drive) & ~hc_sync[1];
end
// Three-state bus
assign QB = bus_drive ? read_result : 16'hZZZZ;
// Interrupt latch logic
// set by positive edge of host_interrupt interconnect
// cleared by software reading the INT_STATUS register
reg int_latch, host_interrupt_prev;
assign int_status = int_latch;
wire host_interrupt_edge = host_interrupt & ~host_interrupt_prev;
always @(posedge host_clk or posedge rst) if (rst) begin
int_latch <= 0;
host_interrupt_prev <= 0;
end else begin
host_interrupt_prev <= host_interrupt;
if ((int_status_en & host_re) | host_interrupt_edge) int_latch <= host_interrupt_edge;
end
assign PCI_INTA_N = int_latch;
assign VHOLD = 0;
endmodule