mirror of
https://github.com/rdolbeau/NuBusFPGA.git
synced 2025-03-12 15:29:44 +00:00
split
This commit is contained in:
commit
4c2eb5f6d2
120
nubus-to-ztex-gateware/nubus_V1_0.py
Normal file
120
nubus-to-ztex-gateware/nubus_V1_0.py
Normal file
@ -0,0 +1,120 @@
|
||||
from migen import *
|
||||
from migen.genlib.fifo import *
|
||||
|
||||
import litex
|
||||
|
||||
class NuBus(Module):
|
||||
def __init__(self, platform, cd_nubus="nubus", cd_nubus90="nubus90"):
|
||||
# unused & unconnected
|
||||
# self.nubus_pwf_n = Signal(reset = 1)
|
||||
# self.nubus_sp_n = Signal(reset = 1)
|
||||
# self.nubus_spv_n = Signal(reset = 1)
|
||||
# self.nubus_tm2_n = platform.request("nubus_tm2_n"),
|
||||
|
||||
# memory
|
||||
self.mem_valid = Signal()
|
||||
self.mem_addr = Signal(32)
|
||||
self.mem_wdata = Signal(32)
|
||||
self.mem_write = Signal(4)
|
||||
self.mem_ready = Signal()
|
||||
self.mem_rdata = Signal(32)
|
||||
self.mem_error = Signal()
|
||||
self.mem_tryagain = Signal()
|
||||
|
||||
# cpu
|
||||
self.cpu_valid = Signal(reset = 0)
|
||||
self.cpu_addr = Signal(32)
|
||||
self.cpu_wdata = Signal(32)
|
||||
self.cpu_ready = Signal()
|
||||
self.cpu_write = Signal(4)
|
||||
self.cpu_rdata = Signal(32)
|
||||
self.cpu_lock = Signal()
|
||||
self.cpu_eclr = Signal()
|
||||
self.cpu_errors = Signal(4)
|
||||
|
||||
# utilities (unused)
|
||||
self.mem_stdslot = Signal()
|
||||
self.mem_super = Signal()
|
||||
self.mem_local = Signal()
|
||||
|
||||
self.add_sources(platform)
|
||||
|
||||
#arbcy_n = platform.request("arbcy_n")
|
||||
#grant = platform.request("grant")
|
||||
#pad_user_led_0 = platform.request("user_led", 0)
|
||||
#pad_user_led_1 = platform.request("user_led", 1)
|
||||
#arbcy_n_mem = Signal()
|
||||
#grant_mem = Signal()
|
||||
#self.sync.nubus += [ arbcy_n_mem.eq(~arbcy_n | arbcy_n_mem) ]
|
||||
#self.sync.nubus += [ grant_mem.eq(grant | grant_mem) ]
|
||||
#self.comb += pad_user_led_0.eq(arbcy_n_mem)
|
||||
#self.comb += pad_user_led_1.eq(grant_mem)
|
||||
|
||||
#fixme: parameters
|
||||
self.specials += Instance(self.get_netlist_name(),
|
||||
# master side
|
||||
#p_SIMPLE_MAP = 0x0,
|
||||
p_SLOTS_ADDRESS = 0xf,
|
||||
p_SUPERSLOTS_ADDRESS = 0x9,
|
||||
p_WDT_W = 0x8,
|
||||
p_LOCAL_SPACE_EXPOSED_TO_NUBUS = 0,
|
||||
i_nub_clkn = ClockSignal(cd_nubus),
|
||||
i_nub_resetn = ~ResetSignal(cd_nubus),
|
||||
i_nub_idn = platform.request("id_3v3_n"),
|
||||
# io_nub_pfwn = self.nubus_pwf_n,
|
||||
io_nub_adn = platform.request("ad_3v3_n"),
|
||||
io_nub_tm0n = platform.request("tm0_3v3_n"),
|
||||
io_nub_tm1n = platform.request("tm1_3v3_n"),
|
||||
io_nub_startn = platform.request("start_3v3_n"),
|
||||
io_nub_rqstn = platform.request("rqst_3v3_n"),
|
||||
io_nub_ackn = platform.request("ack_3v3_n"),
|
||||
# io_nub_arbn = platform.request("nubus_arb_n"),
|
||||
o_arbcy_n = platform.request("arbcy_n"),
|
||||
i_grant = platform.request("grant"),
|
||||
o_tmoen = platform.request("tmoen"),
|
||||
o_NUBUS_AD_DIR = platform.request("nubus_ad_dir"),
|
||||
o_nubus_master_dir = platform.request("nubus_master_dir"),
|
||||
# io_nub_nmrqn = platform.request("nmrq_3v3_n"),
|
||||
# io_nub_spn = self.nubus_sp_n,
|
||||
# io_nub_spvn = self.nubus_spv_n,
|
||||
o_mem_valid = self.mem_valid,
|
||||
o_mem_addr = self.mem_addr,
|
||||
o_mem_wdata = self.mem_wdata,
|
||||
o_mem_write = self.mem_write,
|
||||
i_mem_ready = self.mem_ready,
|
||||
i_mem_rdata = self.mem_rdata,
|
||||
i_mem_error = self.mem_error,
|
||||
i_mem_tryagain = self.mem_tryagain,
|
||||
i_cpu_valid = self.cpu_valid,
|
||||
i_cpu_addr = self.cpu_addr,
|
||||
i_cpu_wdata = self.cpu_wdata,
|
||||
o_cpu_ready = self.cpu_ready,
|
||||
i_cpu_write = self.cpu_write,
|
||||
o_cpu_rdata = self.cpu_rdata,
|
||||
i_cpu_lock = self.cpu_lock,
|
||||
i_cpu_eclr = self.cpu_eclr,
|
||||
o_cpu_errors = self.cpu_errors,
|
||||
o_mem_stdslot = self.mem_stdslot,
|
||||
o_mem_super = self.mem_super,
|
||||
o_mem_local = self.mem_local,
|
||||
|
||||
o_fpga_to_cpld_signal = platform.request("fpga_to_cpld_signal"),
|
||||
|
||||
i_nub_clk2xn = ClockSignal(cd_nubus90),
|
||||
io_nub_tm2n = platform.request("tm2_3v3_n"),
|
||||
)
|
||||
|
||||
def get_netlist_name(self):
|
||||
return "nubus"
|
||||
|
||||
def add_sources(self, platform):
|
||||
platform.add_source("nubus.v", "verilog")
|
||||
# XiBus is from my github, branch 'more_fixes'
|
||||
platform.add_source("/home/dolbeau/XiBus/nubus.svh", "verilog")
|
||||
#platform.add_source("/home/dolbeau/XiBus/nubus_arbiter.v", "verilog") # in the CPLD
|
||||
platform.add_source("/home/dolbeau/XiBus/nubus_cpubus.v", "verilog")
|
||||
platform.add_source("/home/dolbeau/XiBus/nubus_driver.v", "verilog")
|
||||
#platform.add_source("/home/dolbeau/XiBus/nubus_errors.v", "verilog") # unused
|
||||
platform.add_source("/home/dolbeau/XiBus/nubus_membus.v", "verilog")
|
||||
platform.add_source("/home/dolbeau/XiBus/nubus_master.v", "verilog")
|
||||
platform.add_source("/home/dolbeau/XiBus/nubus_slave.v", "verilog")
|
318
nubus-to-ztex-gateware/nubus_V1_0.v
Normal file
318
nubus-to-ztex-gateware/nubus_V1_0.v
Normal file
@ -0,0 +1,318 @@
|
||||
/*
|
||||
* NuBus controller
|
||||
*
|
||||
* Autor: Valeriya Pudova (hww.github.io)
|
||||
* Adapted by Romain Dolbeau <romain@dolbeau.org> for the NuBusFPGA
|
||||
* Copyright (c) 2021-2022
|
||||
*/
|
||||
|
||||
/* This module is running on the FPGA */
|
||||
|
||||
module nubus
|
||||
#(
|
||||
// All slots area starts with address $FXXX XXXX
|
||||
parameter SLOTS_ADDRESS = 'hF,
|
||||
// All superslots starts at $9000 0000
|
||||
parameter SUPERSLOTS_ADDRESS = 'h9,
|
||||
// Watch dog timer bits. Master controller will terminate transfer
|
||||
// after (2 ^ WDT_W) clocks
|
||||
parameter WDT_W = 8,
|
||||
// Local space of card start and end address. For example 0-5
|
||||
// makes local space address $00000000-$50000000
|
||||
// UNUSED in NuBusFPGA
|
||||
parameter LOCAL_SPACE_EXPOSED_TO_NUBUS = 0,
|
||||
parameter LOCAL_SPACE_START = 0,
|
||||
parameter LOCAL_SPACE_END = 5
|
||||
)
|
||||
|
||||
(
|
||||
/* *** NuBus signals *** */
|
||||
/* those are connected to the FPGA */
|
||||
/* connected via the CPLD */
|
||||
input nub_clkn, // Clock (rising is driving edge, faling is sampling)
|
||||
input nub_resetn, // Reset
|
||||
input [ 3:0] nub_idn, // Slot Identification
|
||||
inout nub_tm0n, // Transfer Mode
|
||||
inout nub_tm1n, // Transfer Mode
|
||||
inout nub_startn, // Start
|
||||
inout nub_rqstn, // Request
|
||||
inout nub_ackn, // Acknowledge
|
||||
|
||||
// connected via the CPLD but NuBus90 (unimplemented)
|
||||
input nub_clk2xn,
|
||||
inout nub_tm2n,
|
||||
|
||||
/* connected via the 74LVT245 */
|
||||
inout [31:0] nub_adn, // Address/Data
|
||||
|
||||
/* those are not used, and not even connected in the board */
|
||||
// inout nub_pfwn, // Power Fail Warning
|
||||
// inout nub_spn, // System Parity
|
||||
// inout nub_spvn, // System Parity Valid
|
||||
|
||||
/* those ared used but handled in directly in the Litex code */
|
||||
// output nub_nmrqn, // Non-Master Request, handled in the Litex code
|
||||
|
||||
/* those are used but connected only to the CPLD */
|
||||
/* we deal with the CPLD via 'arbcy_n' and 'grant' */
|
||||
// inout [ 3:0] nub_arbn, // Arbitration
|
||||
|
||||
/* *** CPLD <-> FPGA signals, not in NuBus */
|
||||
output arbcy_n, // request arbitration
|
||||
input grant, // arbitration won
|
||||
output tmoen, // output enable for tm0/1
|
||||
|
||||
/* *** CPLD <-> FPGA signals, spare, currently unused */
|
||||
output fpga_to_cpld_signal, // regular signal
|
||||
// inout fpga_to_cpld_signal_2, // regular signal
|
||||
// inout fpga_to_cpld_clk, // clk input on CPLD or regular signal
|
||||
|
||||
/* FPGA -> drivers */
|
||||
output NUBUS_AD_DIR, // direction for the LS245 (input/output for A/D lines)
|
||||
output nubus_master_dir, // are we in master mode (to drive the proper signals)
|
||||
|
||||
/* 'memory bus' signals; those are used to interface with the Wishbone to access the FPGA resources from NuBus */
|
||||
output mem_valid,
|
||||
output [31:0] mem_addr,
|
||||
output [31:0] mem_wdata,
|
||||
output [ 3:0] mem_write,
|
||||
input mem_ready,
|
||||
input [31:0] mem_rdata,
|
||||
input mem_error, // ignored
|
||||
input mem_tryagain, // ignored
|
||||
|
||||
/* 'processor bus' signals; those are used to interface with the Wishbone to access NuBus resources from the FPGA */
|
||||
input cpu_valid,
|
||||
input [31:0] cpu_addr,
|
||||
input [31:0] cpu_wdata,
|
||||
input [ 3:0] cpu_write,
|
||||
output cpu_ready,
|
||||
output [31:0] cpu_rdata,
|
||||
input cpu_lock,
|
||||
input cpu_eclr, // ignored
|
||||
output [3:0] cpu_errors, // ignored
|
||||
|
||||
/* utilities signal from the NuBus stuff, currently unused */
|
||||
// Access to slot area
|
||||
output mem_stdslot,
|
||||
// Access to superslot area ($sXXXXXXX where <s> is card id)
|
||||
output mem_super,
|
||||
// Access to local memory on the card
|
||||
output mem_local
|
||||
);
|
||||
|
||||
`include "nubus.svh"
|
||||
|
||||
// ==========================================================================
|
||||
// Colock and reset
|
||||
// ==========================================================================
|
||||
|
||||
wire nub_clk = ~nub_clkn;
|
||||
wire nub_reset = ~nub_resetn;
|
||||
|
||||
// ==========================================================================
|
||||
// Global signals
|
||||
// ==========================================================================
|
||||
|
||||
// ===== SLAVE =====
|
||||
//wire slv_master;
|
||||
wire slv_slave; // output nubus_slave module; input internal ; active during slave cycle
|
||||
wire slv_tm1n; // output nubus_slave module; input internal & nubus_membus
|
||||
wire slv_tm0n; // output nubus_slave module; input nubus_membus
|
||||
wire slv_ackcyn; // output nubus_slave module; input nubus_driver
|
||||
wire slv_myslotcy; // output nubus_slave module; input internal & nubus_driver
|
||||
wire unsigned [31:0] slv_addr;// output nubus_slave module; input nubus_membus
|
||||
|
||||
// ===== CPU ====
|
||||
wire unsigned [31:0] cpu_ad; // output nubus_master; input MUX to A/D lines 'nub_ad' (nub_ad then as an OE and an iverter to reach nub_adn)
|
||||
wire cpu_tm1n; // R(h)/W(l); output nubus_cpu; input nubus_driver & internal
|
||||
wire cpu_tm0n; // byte size(l); idem
|
||||
wire cpu_masterd; // ignored
|
||||
|
||||
// ===== DRIVER =====
|
||||
wire drv_tmoen; // output enable for tm0n/tm1n (== tmoen) by nubus_driver
|
||||
wire drv_mstdn; // ??? only connected to driver as an output
|
||||
|
||||
// ===== MASTER ===
|
||||
wire mst_timeout; // timeout???; output nubus_master; input nubus_driver & nubus_slave
|
||||
wire mst_arbcyn; // req. arb; output nubus_master; input internal & to CPLD & nubus_driver
|
||||
assign arbcy_n = mst_arbcyn;
|
||||
wire mst_adrcyn; // during the address cycle for master; output nubus_master; input nubus_driver & nubus_cpubus
|
||||
wire mst_lockedn; // for locked accesses (?); output nubus_master; input nubus_driver
|
||||
wire mst_arbdn; // delay during arbitration; output nubus_master; input [NULL] ???
|
||||
wire mst_busyn; // busy during transfer; output nubus_master; input [NULL] ???
|
||||
wire mst_ownern; // master is bus owner; output nubus_master; input nubus_driver & internal
|
||||
wire mst_dtacyn; // during the data cycle for master; output nubus_master; input nubus_driver & internal
|
||||
|
||||
// ==========================================================================
|
||||
// Drive NuBus address-data line
|
||||
// ==========================================================================
|
||||
|
||||
// Should we be putting the address (instead of data) on the bus [see also nub_adoe]
|
||||
// yes during address cycle, or if we're reading (not writing) data
|
||||
// actually during write the CPU puts data in cpu_ad so also when writing
|
||||
// nub_adoe takes care of the enablement
|
||||
wire cpu_adsel = ~mst_adrcyn | ~mst_dtacyn;// & ~cpu_tm1n;
|
||||
// Select nubus address or data signals
|
||||
wire [31:0] nub_ad = cpu_adsel ? cpu_ad : mem_rdata;
|
||||
|
||||
// Tri-state control for the A/D line
|
||||
// nub_adoe is the output enable, when 0 A/D lines are high-impedance
|
||||
// Slave: only drive the A/D lines to return data on a read (slave cycle with tm1n high)
|
||||
// Master: drives during (a) address cycle
|
||||
// (b) data cycle when writing
|
||||
wire nub_adoe = slv_slave & slv_tm1n /* SLAVE read of card */
|
||||
| cpu_valid & ~mst_adrcyn /* MASTER address cycle*/
|
||||
| ~mst_ownern & ~mst_dtacyn & ~cpu_tm1n /* MASTER data cycle, when writing*/
|
||||
;
|
||||
|
||||
assign nub_adn = nub_adoe ? ~nub_ad : 'bZ;
|
||||
/* for direction */
|
||||
assign NUBUS_AD_DIR = ~nub_adoe;
|
||||
//assign nubus_master_dir = grant | ~mst_adrcyn | ~mst_arbdn | ~mst_ownern | ~mst_dtacyn;
|
||||
assign nubus_master_dir = ~mst_ownern;
|
||||
|
||||
/* for slave access, enable the access during slv_myslotcy*/
|
||||
assign mem_valid = slv_myslotcy;
|
||||
|
||||
// ==========================================================================
|
||||
// Slave FSM
|
||||
// ==========================================================================
|
||||
|
||||
nubus_slave
|
||||
#(
|
||||
.SLOTS_ADDRESS (SLOTS_ADDRESS),
|
||||
.SUPERSLOTS_ADDRESS(SUPERSLOTS_ADDRESS),
|
||||
.SIMPLE_MAP(0),
|
||||
// UNUSED in NuBusFPGA
|
||||
.LOCAL_SPACE_EXPOSED_TO_NUBUS(LOCAL_SPACE_EXPOSED_TO_NUBUS),
|
||||
.LOCAL_SPACE_START(LOCAL_SPACE_START),
|
||||
.LOCAL_SPACE_END(LOCAL_SPACE_END)
|
||||
)
|
||||
USlave
|
||||
(
|
||||
.nub_clkn(nub_clkn), // Clock
|
||||
.nub_resetn(nub_resetn), // Reset
|
||||
.nub_idn(nub_idn), // Card ID
|
||||
.nub_adn(nub_adn), // Address Data
|
||||
.nub_startn(nub_startn), // Transfer start
|
||||
.nub_ackn(nub_ackn), // Transfer end
|
||||
.nub_tm1n(nub_tm1n), // Transition mode 1 (Read/Write)
|
||||
.nub_tm0n(nub_tm0n),
|
||||
.mem_ready(mem_ready),
|
||||
.mst_timeout(mst_timeout),
|
||||
|
||||
.slv_slave_o(slv_slave), // Slave mode
|
||||
.slv_tm1n_o(slv_tm1n), // Latched transition mode 1 (Read/Write)
|
||||
.slv_tm0n_o(slv_tm0n),
|
||||
.slv_ackcyn_o(slv_ackcyn), // Acknowlege
|
||||
.slv_addr_o(slv_addr), // Slave address
|
||||
.slv_stdslot_o(mem_stdslot), // Starndard slot
|
||||
.slv_super_o(mem_super), // Superslot
|
||||
.slv_local_o(mem_local), // Local area
|
||||
.slv_myslotcy_o(slv_myslotcy) // Any slot
|
||||
);
|
||||
|
||||
// ==========================================================================
|
||||
// Master FSM
|
||||
// ==========================================================================
|
||||
|
||||
nubus_master
|
||||
#(
|
||||
.WDT_W(WDT_W)
|
||||
)
|
||||
UMaster
|
||||
(
|
||||
.nub_clkn(nub_clkn), // Clock
|
||||
.nub_resetn(nub_resetn), // Reset
|
||||
.nub_rqstn(nub_rqstn), // Bus request
|
||||
.nub_startn(nub_startn), // Start transfer
|
||||
.nub_ackn(nub_ackn), // End of transfer
|
||||
.arb_grant(grant), // Grant access
|
||||
.cpu_lock(cpu_lock), // Address line
|
||||
.cpu_masterd(cpu_valid), // Master mode (delayed) // FIXME: ignoring cpu_masterd which is always 0 (see below)
|
||||
|
||||
.mst_lockedn_o(mst_lockedn), // Locked or not tranfer
|
||||
.mst_arbdn_o(mst_arbdn),
|
||||
.mst_busyn_o(mst_busyn),
|
||||
.mst_ownern_o(mst_ownern), // Address or data transfer
|
||||
.mst_dtacyn_o(mst_dtacyn), // Data strobe
|
||||
.mst_adrcyn_o(mst_adrcyn), // Address strobe
|
||||
.mst_arbcyn_o(mst_arbcyn), // Arbiter enabled
|
||||
.mst_timeout_o(mst_timeout)
|
||||
);
|
||||
|
||||
// ==========================================================================
|
||||
// Driver Nubus
|
||||
// ==========================================================================
|
||||
|
||||
assign tmoen = drv_tmoen;
|
||||
|
||||
nubus_driver UNDriver
|
||||
(
|
||||
.slv_ackcyn(slv_ackcyn), // Acknowlege
|
||||
.mst_arbcyn(mst_arbcyn), // Arbiter enabled
|
||||
.mst_adrcyn(mst_adrcyn), // Address strobe
|
||||
.mst_dtacyn(mst_dtacyn), // Data strobe
|
||||
.mst_ownern(mst_ownern), // Master is owner of the bus
|
||||
.mst_lockedn(mst_lockedn), // Locked or not transfer
|
||||
.mst_tm1n(cpu_tm1n), // Address lines
|
||||
.mst_tm0n(cpu_tm0n), // Address lines
|
||||
.mst_timeout(mst_timeout),
|
||||
.mis_errorn(TMN_COMPLETE),
|
||||
.nub_tm0n_o(nub_tm0n), // Transfer mode
|
||||
.nub_tm1n_o(nub_tm1n), // Transfer mode
|
||||
.nub_ackn_o(nub_ackn), // Achnowlege
|
||||
.nub_startn_o(nub_startn), // Transfer start
|
||||
.nub_rqstn_o(nub_rqstn), // Bus request
|
||||
.nub_rqstoen_o(fpga_to_cpld_signal), // Bus request enable
|
||||
.drv_tmoen_o(drv_tmoen), // Transfer mode enable
|
||||
.drv_mstdn_o(drv_mstdn) // Guess: Slave sends /ACK. Master responds with /MSTDN, which allows slave to clear /ACK and listen for next transaction.
|
||||
);
|
||||
|
||||
// ==========================================================================
|
||||
// CPU Interface
|
||||
// ==========================================================================
|
||||
|
||||
assign cpu_rdata = ~nub_adn;
|
||||
assign cpu_ready = ~nub_ackn & nub_startn & ~mst_ownern; // if mst_ownern is inactive (high), then we're seeing the ACK from the previous slave transaction that we were waiting on
|
||||
|
||||
nubus_cpubus UCPUBus
|
||||
(
|
||||
.nub_clkn(nub_clkn),
|
||||
.nub_resetn(nub_resetn),
|
||||
.mst_adrcyn(mst_adrcyn),
|
||||
.cpu_valid(cpu_valid),
|
||||
.cpu_write(cpu_write),
|
||||
.cpu_addr(cpu_addr),
|
||||
.cpu_wdata(cpu_wdata),
|
||||
.cpu_ad_o(cpu_ad),
|
||||
.cpu_tm1n_o(cpu_tm1n),
|
||||
.cpu_tm0n_o(cpu_tm0n),
|
||||
.cpu_error_o(cpu_errors),
|
||||
.cpu_masterd_o(cpu_masterd) // FIXME, set to 0 in Xibus nubus_cpubus
|
||||
);
|
||||
|
||||
// ==========================================================================
|
||||
// Memory Interface
|
||||
// ==========================================================================
|
||||
|
||||
nubus_membus UMemBus
|
||||
(
|
||||
.nub_clkn(nub_clkn), // Clock
|
||||
.nub_resetn(nub_resetn), // Reset
|
||||
.nub_adn(nub_adn),
|
||||
|
||||
.slv_tm1n(slv_tm1n),
|
||||
.slv_tm0n(slv_tm0n),
|
||||
.slv_myslotcy(slv_myslotcy),
|
||||
.slv_addr(slv_addr),
|
||||
|
||||
.mem_addr_o(mem_addr),
|
||||
.mem_write_o(mem_write),
|
||||
.mem_wdata_o(mem_wdata)
|
||||
);
|
||||
|
||||
|
||||
endmodule
|
||||
|
Loading…
x
Reference in New Issue
Block a user