ND120_CORE¶
ND120 board-independent core (ND3202D + ND-BUS device chain)
Source: Verilog/ND120_CORE.v
ยท Author: Ronny Hansen
Where it sits (Simulation): ND120_TOP > ND120_CORE
- instance path: CORE
Used in: emu (MiSTer), nd120_mega65_machine (MEGA65 R6, MEGA65 R3), nd120_nexys4ddr_top (Nexys), nd120_qmtech_top (QMTECH), ND120_TANG20K_TOP (Tang), ND120_TOP (Simulation, Basys3, Cmod)
Contains: BACKWIRING_PROM, ND3202D, ND_BUS_SLAVE (only on Simulation, Tang, Nexys, MiSTer, MEGA65 R6, MEGA65 R3, QMTECH), ND_DMA_MASTER x3 (only on Simulation, Tang, Nexys, MiSTer, MEGA65 R6, MEGA65 R3, QMTECH), ND_FLOPPY_DMA (only on Simulation, Tang, Nexys, MiSTer, MEGA65 R6, MEGA65 R3, QMTECH), ND_SMD (only on Simulation), ND_TAPE_400 (only on Simulation, Tang, Nexys, MiSTer, MEGA65 R6, MEGA65 R3, QMTECH), ND_WINCHESTER (only on Tang, Nexys, MiSTer, MEGA65 R6, MEGA65 R3, QMTECH)
Module hierarchy - All modules

Schematic¶
Drawn from the Verilog: the yosys netlist of the Simulation (Verilator) build, instance CORE. Sub-modules are boxes (click the picture to open it full size; there every sub-module box links to its page, and every wire shows its Verilog name).
Description¶
ND120 BOARD-INDEPENDENT CORE ND3202D CPU board + the optional ND-BUS Verilog device chain. Contains NO board-specific logic: no PLL/MMCM, no power-on reset, no LED mapping, no 7-segment, no SDRAM primitive, no heartbeat counter. Every board (Basys3/sim ND120_TOP, Tang Nano 20K, future boards) instantiates this and supplies its own clock, reset and I/O. Behaviour-preserving extraction of ND120_TOP.v (14-JUL-2026): the device chain and the ND3202D instance are moved verbatim; the `ifdef ND120_VERILOG_DEVICES gate becomes the INCLUDE_* parameters. Clocking: clk_cpu is the ONE net that fed ND3202D.sysclk, CLOCK_1, CLOCK_2 and the device chain's s_dev_clk in BOTH the sim and the FPGA branch of ND120_TOP, so it collapses to a single core input. The board decides what drives it (sim: sysclk; Basys3: clk_cpu from the MMCM; Tang: clk_cpu from the rPLL). Storage seam: the core exposes the byte/disk SOURCE ports and knows nothing of SD-FAT or of the C harness. The board supplies the implementation (sim: forwarded to ND120_TOP ports, served by the C model; hardware: nd_storage / nd_storage_devices). Ronny Hansen
Parameters¶
| Parameter | Default |
|---|---|
INCLUDE_TAPE |
0 |
INCLUDE_FLOPPY |
0 |
INCLUDE_SMD |
0 |
INCLUDE_WD |
0 |
SMD_HAS_FLIPFLOP |
1 |
SMD_HAS_FLIPFLOP |
0 |
SMD_WCNT_FLIPFLOP |
0 |
SMD_WCNT_FLIPFLOP |
SMD_HAS_FLIPFLOP |
SYSNO |
`ND120_SYSNO |
HWINFO2 |
`ND120_HWINFO2 |
NLEGU |
`ND120_NLEGU //! legal users (8'o377 = "not present" |
Ports¶
| Direction | Width | Name | Description |
|---|---|---|---|
| input | 1 |
ERRFA_CONTX |
console TX line in (probe arming) |
| output | 1 |
ERRFA_TXD |
SINTRAN ERRFATAL evidence probe TX (MEM RAM probe) |
| output | [15:0] |
ERRFA_IOX_ADDR |
|
| output | 1 |
ERRFA_IOX_RD |
|
| output | 1 |
ERRFA_IOX_WR |
|
| output | [15:0] |
ERRFA_IOX_WDATA |
|
| output | [15:0] |
ERRFA_IOX_RDATA |
|
| input | 1 |
clk_cpu |
CPU + bus + device domain (ND3202D sysclk/CLOCK_1/CLOCK_2) |
| input | 1 |
BAUD_9600 |
runtime console baud select: 1 = 9600, 0 = build default (115200). Tie 1'b0 on boards without a baud switch. |
| input | 1 |
sys_rst_n (active low) |
Active-low reset, from the board's power-on reset |
| input | 1 |
CACHE_SW |
|
| input | 1 |
BREQ_n (active low) |
Bus Request C-C12 |
| input | 1 |
BINT10_n (active low) |
Bus Interrupt 10 C-A15 |
| input | 1 |
BINT11_n (active low) |
Bus Interrupt 11 C-C15 |
| input | 1 |
BINT12_n (active low) |
Bus Interrupt 12 C-A16 |
| input | 1 |
BINT13_n (active low) |
Bus Interrupt 13 C-C16 |
| input | 1 |
BINT15_n (active low) |
Bus Interrupt 15 C-C17 |
| input | 1 |
POWSENSE_n (active low) |
Power Sense |
| input | [23:0] |
BD_23_0_n_IN |
Bus address/data in (active low, pulled high) |
| output | [23:0] |
BD_23_0_n_OUT |
Bus address/data out |
| input | 1 |
SEMRQ_n_IN |
C-PLUG A17 SEMREQ~ in |
| output | 1 |
SEMRQ_n_OUT |
C-PLUG A17 SEMREQ~ out |
| input | 1 |
BINPUT_n_IN |
C-PLUG A18 BINPUT~ in |
| output | 1 |
BINPUT_n_OUT |
C-PLUG A18 BINPUT~ out |
| input | 1 |
BDAP_n_IN |
C-PLUG C18 BDAP~ in |
| output | 1 |
BDAP_n_OUT |
C-PLUG C18 BDAP~ out |
| input | 1 |
BDRY_n_IN |
C-PLUG A19 BDRY~ in |
| output | 1 |
BDRY_n_OUT |
C-PLUG A19 BDRY~ out |
| input | 1 |
BAPR_n_IN |
C-PLUG A20 BAPR~ in |
| output | 1 |
BAPR_n_OUT |
C-PLUG A20 BAPR~ out |
| output | 1 |
BREF_n (active low) |
C-PLUG B12 BREF~ |
| output | 1 |
BERROR_n (active low) |
C-PLUG B21 BERROR~ |
| output | 1 |
BINACK_n (active low) |
C-PLUG B19 BINACK~ |
| output | 1 |
BIOXE_n (active low) |
C-PLUG C19 BIOXE~ |
| output | 1 |
BMEM_n (active low) |
C-PLUG C28 BMEM~ |
| output | 1 |
OUTGRANT_n (active low) |
C-PLUG C23 OUTGRANT~ (DMA grant chain head) |
| output | 1 |
OUTIDENT_n (active low) |
C-PLUG C22 OUTIDENT~ |
| output | 1 |
MCL |
C-PLUG B20 MCL~ (after negation) |
| input | 1 |
RXD |
UART Receive A-C8 |
| output | 1 |
TXD |
UART Transmit A-C7 |
| output | 1 |
TAPE_BYTE_REQ |
pulse: fetch next tape byte |
| input | 1 |
TAPE_BYTE_VALID |
pulse: TAPE_BYTE_DATA is the byte |
| input | [7:0] |
TAPE_BYTE_DATA |
|
| output | 1 |
TAPE_REWIND |
pulse: rewind the tape source |
| input | 1 |
DMA_REQ |
pulse: one word transfer |
| input | 1 |
DMA_WR |
0 = memory read, 1 = memory write |
| input | [23:0] |
DMA_ADDR |
physical memory address |
| input | [15:0] |
DMA_WDATA |
|
| output | [15:0] |
DMA_RDATA |
|
| output | 1 |
DMA_ACK |
|
| output | 1 |
DMA_ERR |
|
| output | 1 |
DMA_BUSY |
|
| output | 1 |
FDISK_REQ |
|
| output | 1 |
FDISK_WR |
|
| output | [15:0] |
FDISK_LSECT |
|
| output | [1:0] |
FDISK_FORMAT |
|
| output | [1:0] |
FDISK_DRIVE |
|
| output | [10:0] |
FDISK_WORDCOUNT |
|
| input | 1 |
FDISK_DONE |
|
| input | 1 |
FDISK_ERR |
|
| input | [3:0] |
FDISK_ERR_CODE |
|
| input | [3:0] |
FDISK_MEDIA_FMT |
|
| input | [9:0] |
FDBUF_ADDR |
|
| input | [15:0] |
FDBUF_WDATA |
|
| input | 1 |
FDBUF_WE |
|
| output | [15:0] |
FDBUF_RDATA |
|
| output | 1 |
SDISK_START |
|
| output | 1 |
SDISK_REQ |
|
| output | 1 |
SDISK_WR |
|
| output | [15:0] |
SDISK_BLKADDR1 |
|
| output | [15:0] |
SDISK_BLKADDR2 |
|
| output | [2:0] |
SDISK_UNIT |
|
| output | [10:0] |
SDISK_WORDCOUNT |
|
| input | 1 |
SDISK_DONE |
|
| input | 1 |
SDISK_ERR |
|
| input | [3:0] |
SDISK_ERR_CODE |
|
| input | [9:0] |
SDBUF_ADDR |
|
| input | [15:0] |
SDBUF_WDATA |
|
| input | 1 |
SDBUF_WE |
|
| output | [15:0] |
SDBUF_RDATA |
|
| output | 1 |
WDISK_START |
|
| output | 1 |
WDISK_REQ |
|
| output | 1 |
WDISK_WR |
|
| output | [15:0] |
WDISK_BLKADDR1 |
|
| output | [15:0] |
WDISK_BLKADDR2 |
|
| output | [2:0] |
WDISK_UNIT |
|
| output | [10:0] |
WDISK_WORDCOUNT |
|
| input | 1 |
WDISK_DONE |
|
| input | 1 |
WDISK_ERR |
|
| input | [3:0] |
WDISK_ERR_CODE |
|
| input | [9:0] |
WDBUF_ADDR |
|
| input | [15:0] |
WDBUF_WDATA |
|
| input | 1 |
WDBUF_WE |
|
| output | [15:0] |
WDBUF_RDATA |
|
| output | [6:0] |
LED |
ND3202D LED bundle (see ND3202D.v port comment) |
| output | 1 |
RUN_n (active low) |
low while the CPU is running |
| output | [12:0] |
CSA_12_0 |
Microcode address |
| output | [3:0] |
PIL |
Processor interrupt level (for debug capture) |
| output | [13:0] |
LA_23_10 |
MAC upper address (XLA 23:10) |
| output | [9:0] |
CA_9_0 |
MAC lower address (XCA 9:0) |
| output | [4:0] |
DEBUG_CC_TERM |
{TERM_n, CC3_n, CC2_n, CC1_n, CC0_n} |
| output | 1 |
DEBUG_MCLK |
Microcycle clock |
| output | 1 |
DEBUG_LCS_n (active low) |
0 = loading microcode, 1 = loaded |
| output | 1 |
DEBUG_FETCH |
|
| output | 1 |
DEBUG_MAP_n (active low) |
one falling edge per macro instruction (see ND3202D) |
| output | 1 |
DEBUG_CFETCH |
one rise per macro instruction (CGA CFETCH) - the MIPS event |
| output | 1 |
DEBUG_MR_n (active low) |
Master Reset |
| output | 1 |
DEBUG_CLEAR_n (active low) |
|
| output | 1 |
DEBUG_REFRQ_n (active low) |
Refresh Request |
| output | 1 |
DEBUG_INTRQ_n (active low) |
Interrupt Request |
| output | 1 |
DEBUG_POWFAIL_n (active low) |
Power Fail |
| output | [15:0] |
DEBUG_FIDBO_15_0 |
FIDBO internal data bus |
| output | [15:0] |
DEBUG_IREQ_15_0_N (active low) |
DEBUG: raw interrupt-request vector (active low) |
| output | [15:0] |
XMIC_DBG_15_0 |
DEBUG: microsequencer address-advance probe (Tang 06000-hang) |
| output | [19:0] |
XWRFB_DBG_19_0 |
|
| output | [11:0] |
XCYC_DBG_7_0 |
|
| output | 1 |
DBG_PTW_LVL |
live PT write-strobe level (~EPT_n & ~WMAP_n, 27-AUG overlap probe) - unconditional: every backend has PT chips |
| output | [7:0] |
DBG_PANEL |
|
| output | [15:0] |
PANEL_ACTLV |
ACTIVE LEVEL word from the panel processor |
| output | [7:0] |
DBG_CACHE |
|
| input | 1 |
clk2x |
2x clk_cpu, same PLL, edge-aligned |
| input | 1 |
clk2x_sdram |
180 degrees from clk2x, to the SDRAM chip |
| output | 1 |
O_sdram_clk |
|
| output | 1 |
O_sdram_cke |
|
| output | 1 |
O_sdram_cs_n (active low) |
|
| output | 1 |
O_sdram_cas_n (active low) |
|
| output | 1 |
O_sdram_ras_n (active low) |
|
| output | 1 |
O_sdram_wen_n (active low) |
|
| inout | [31:0] |
IO_sdram_dq |
|
| output | [10:0] |
O_sdram_addr |
|
| output | [1:0] |
O_sdram_ba |
|
| output | [3:0] |
O_sdram_dqm |
|
| output | [15:0] |
DBG_MEMW |
write-path debug bus from MEM_43 |
| output | [15:0] |
DBG_PTW |
page-table write stream from CPU_MMU_24 (23-AUG, zero-read campaign) |
| output | [20:0] |
PF_CAPTURED |
ND120_PF_CAPTURE freeze flag (23-AUG) |
| output | [1:0] |
DBG_WDSTAGE |
|
| output | [13:0] |
DBG_PPN |
physical page number PPN[23:10] (24-AUG) |
| output | [15:0] |
DBG_PGW |
SDRAM-bridge page-write watch (24-AUG) |
| input | 1 |
stor_clk |
27 MHz crystal (pin 4) (from ND120_TANG20K_TOP.sys_clk) |
| input | 1 |
stor_rst_n (active low) |
|
| input | 1 |
mem_start |
|
| input | 1 |
mem_we |
|
| input | [19:0] |
mem_addr |
|
| input | [31:0] |
mem_wdata |
|
| output | [31:0] |
mem_rdata |
|
| output | 1 |
mem_busy |
|
| output | 1 |
mem_done |
|
| input | 1 |
ui_clk |
|
| input | 1 |
ui_rst |
|
| output | 1 |
mm_req_valid |
|
| output | 1 |
mm_req_we |
|
| output | [26:0] |
mm_req_addr |
|
| output | [127:0] |
mm_req_wdata |
|
| output | [15:0] |
mm_req_wmask |
|
| input | 1 |
mm_req_ready |
|
| input | 1 |
mm_rsp_valid |
|
| input | [127:0] |
mm_rsp_rdata |
|
| output | [7:0] |
DBG_DDR2_BRIDGE |
|
| output | [19:0] |
wd_trace_rec |
|
| output | 1 |
wd_trace_we |
|
| output | 1 |
wd_trace_done |
Verilog source¶
Verilog/ND120_CORE.v on GitHub.
Show the Verilog of ND120_CORE (1303 lines)
/**************************************************************************
** ND120 BOARD-INDEPENDENT CORE **
** **
** ND3202D CPU board + the optional ND-BUS Verilog device chain. **
** Contains NO board-specific logic: no PLL/MMCM, no power-on reset, no **
** LED mapping, no 7-segment, no SDRAM primitive, no heartbeat counter. **
** Every board (Basys3/sim ND120_TOP, Tang Nano 20K, future boards) **
** instantiates this and supplies its own clock, reset and I/O. **
** **
** Behaviour-preserving extraction of ND120_TOP.v (14-JUL-2026): **
** the device chain and the ND3202D instance are moved verbatim; the **
** `ifdef ND120_VERILOG_DEVICES gate becomes the INCLUDE_* parameters. **
** **
** Clocking: clk_cpu is the ONE net that fed ND3202D.sysclk, CLOCK_1, **
** CLOCK_2 and the device chain's s_dev_clk in BOTH the sim and the FPGA **
** branch of ND120_TOP, so it collapses to a single core input. The **
** board decides what drives it (sim: sysclk; Basys3: clk_cpu from the **
** MMCM; Tang: clk_cpu from the rPLL). **
** **
** Storage seam: the core exposes the byte/disk SOURCE ports and knows **
** nothing of SD-FAT or of the C harness. The board supplies the **
** implementation (sim: forwarded to ND120_TOP ports, served by the C **
** model; hardware: nd_storage / nd_storage_devices). **
** **
** Ronny Hansen **
***************************************************************************/
//! @title ND120 board-independent core (ND3202D + ND-BUS device chain)
//! @author Ronny Hansen
// Back-wiring PROM defaults (ND120_SYSNO / ND120_HWINFO2 / ND120_NLEGU and the
// "not present" sentinels). Included here as well as in BACKWIRING_PROM.v so
// the macros are defined no matter which of the two files the toolchain reads
// first - the file is `ifndef-guarded, so including it twice is harmless.
`include "nd120_backwiring_defaults.vh"
module ND120_CORE #(
// Device chain population. Each device is instantiated in a generate
// block; when absent its shared-net contributions are tied inactive so
// the OR-buses, the IDENT chain, the DMA grant chain and the bus
// wired-AND all stay valid expressions (graceful degradation).
parameter INCLUDE_TAPE = 0, //! ND_TAPE_400 papertape at 400
parameter INCLUDE_FLOPPY = 0, //! ND_FLOPPY_DMA floppy 1560 (DMA flavor)
parameter INCLUDE_SMD = 0, //! ND_SMD disk at 1540
parameter INCLUDE_WD = 0, //! ND_WINCHESTER disk at 500 (ST506/8 inch)
// SMD controller type (passed straight to ND_SMD's HAS_WC_FLIPFLOP strap;
// see docs/design/SMD-CONTROLLER-TYPE-SEAM.md). 0 = ECC / BIG-DISC card
// (core-address / word-count registers load in a SINGLE write) - THE DEFAULT,
// because this is the card that BOOTS: the mass-storage microcode writes the
// word counter ONCE with 002000, which loads 1024 words only on a single-
// write card. On a flip-flop card that single write lands in the HI byte and
// the count stays 0, so the boot would transfer nothing. 1 = 15/10 MHz card
// (24-bit registers loaded HI-then-LO by TWO writes).
//
// Default is define-driven so a plain build boots with NO file edit, exactly
// like BOARD_CLK_FREQ / ND120_SYSNO. The 15 MHz two-write card is the opt-in:
// build with EXTRA_VDEFINES="-DND120_SMD_15MHZ" (or set the parameter from a
// higher instance) to select it. Absent the define it stays 0 = the ECC
// single-write card that boots the image.
`ifdef ND120_SMD_15MHZ
parameter SMD_HAS_FLIPFLOP = 1,
`else
parameter SMD_HAS_FLIPFLOP = 0,
`endif
// WORD-COUNTER protocol. Follows the card type. A card with a
// single-access word counter is NOT a documented controller - I built one
// briefly to reconcile DISC-TEMA with the mass-load microcode, before the
// PROM listing showed the microcode is simply written for a single-access
// card. Override only for experiments, never as a shipping configuration.
`ifdef ND120_SMD_WCNT_SINGLE
parameter SMD_WCNT_FLIPFLOP = 0,
`else
parameter SMD_WCNT_FLIPFLOP = SMD_HAS_FLIPFLOP,
`endif
// Back-wiring PROM (installation number) contents. These are what SINTRAN's
// GCPUNR reads with VERSN through IDBS,INR=35, and they are meant to be
// fixed into a bitstream at synthesis time. Defaults (and the -D override
// macros ND120_SYSNO / ND120_HWINFO2 / ND120_NLEGU) live in
// Shared/support/nd120_backwiring_defaults.vh; the PROM model and the full
// signal-path citations are in Shared/support/BACKWIRING_PROM.v; the whole
// mechanism is written up in docs/backwiring-prom-installation-number.md.
parameter [15:0] SYSNO = `ND120_SYSNO, //! CPU NUMBER (16'hFFFF = "not present")
parameter [15:0] HWINFO2 = `ND120_HWINFO2, //! CPU TYPE (16'hFFFF = "not present")
parameter [ 7:0] NLEGU = `ND120_NLEGU //! legal users (8'o377 = "not present")
) (
`ifdef ND120_ERRFA_PROBE
input wire ERRFA_CONTX, // console TX line in (probe arming)
output wire ERRFA_TXD, // SINTRAN ERRFATAL evidence probe TX (MEM RAM probe)
// device-chain IOX seam, exported for the board-level WD-IOX ring
output wire [15:0] ERRFA_IOX_ADDR,
output wire ERRFA_IOX_RD,
output wire ERRFA_IOX_WR,
output wire [15:0] ERRFA_IOX_WDATA,
output wire [15:0] ERRFA_IOX_RDATA,
`endif
/***************************************************
* (a) CLOCK / RESET *
***************************************************/
input wire clk_cpu, //! CPU + bus + device domain (ND3202D sysclk/CLOCK_1/CLOCK_2)
input wire BAUD_9600, //! runtime console baud select: 1 = 9600, 0 = build default (115200). Tie 1'b0 on boards without a baud switch.
input wire sys_rst_n, //! Active-low reset, from the board's power-on reset
/***************************************************
* (b) CONSOLE SWITCHES *
***************************************************/
//! The ND-100 console's SW1, the cache on/off switch (sheet 25 CON):
//! 1 = cache on, 0 = every access goes to main memory and the CSR
//! reports the cache disabled. Until 29-AUG-2026 this was tied high
//! inside the core; now the board decides. Nexys 4 DDR: slide switch
//! sw[4]. Tang / Verilator: tied high (the Tang builds with
//! ND120_NO_CACHE anyway, which overrides this to off).
//! Already synchronised by the board top; treat it as slow-changing
//! but not glitch-free - the real switch was a toggle on the console.
input wire CACHE_SW,
/***************************************************
* (e) ND-100 C-PLUG BUS *
* Always present on the core; the board either *
* drives it (sim harness) or ties it off (FPGA). *
***************************************************/
input wire BREQ_n, //! Bus Request C-C12
input wire BINT10_n, //! Bus Interrupt 10 C-A15
input wire BINT11_n, //! Bus Interrupt 11 C-C15
input wire BINT12_n, //! Bus Interrupt 12 C-A16
input wire BINT13_n, //! Bus Interrupt 13 C-C16
input wire BINT15_n, //! Bus Interrupt 15 C-C17
input wire POWSENSE_n, //! Power Sense
input wire [23:0] BD_23_0_n_IN, //! Bus address/data in (active low, pulled high)
output wire [23:0] BD_23_0_n_OUT, //! Bus address/data out
input wire SEMRQ_n_IN, //! C-PLUG A17 SEMREQ~ in
output wire SEMRQ_n_OUT, //! C-PLUG A17 SEMREQ~ out
input wire BINPUT_n_IN, //! C-PLUG A18 BINPUT~ in
output wire BINPUT_n_OUT, //! C-PLUG A18 BINPUT~ out
input wire BDAP_n_IN, //! C-PLUG C18 BDAP~ in
output wire BDAP_n_OUT, //! C-PLUG C18 BDAP~ out
input wire BDRY_n_IN, //! C-PLUG A19 BDRY~ in
output wire BDRY_n_OUT, //! C-PLUG A19 BDRY~ out
input wire BAPR_n_IN, //! C-PLUG A20 BAPR~ in
output wire BAPR_n_OUT, //! C-PLUG A20 BAPR~ out
output wire BREF_n, //! C-PLUG B12 BREF~
output wire BERROR_n, //! C-PLUG B21 BERROR~
output wire BINACK_n, //! C-PLUG B19 BINACK~
output wire BIOXE_n, //! C-PLUG C19 BIOXE~
output wire BMEM_n, //! C-PLUG C28 BMEM~
output wire OUTGRANT_n, //! C-PLUG C23 OUTGRANT~ (DMA grant chain head)
output wire OUTIDENT_n, //! C-PLUG C22 OUTIDENT~
output wire MCL, //! C-PLUG B20 MCL~ (after negation)
/***************************************************
* (d) UART (A-PLUG console) *
***************************************************/
input wire RXD, //! UART Receive A-C8
output wire TXD, //! UART Transmit A-C7
/***************************************************
* (c) STORAGE BACKEND SOURCE PORTS *
* Meaningful only for the devices the INCLUDE_* *
* parameters populate; the rest read as tied-off *
* outputs and ignored inputs. (Verilog cannot *
* make a port list depend on a parameter, so the *
* ports are declared unconditionally and the *
* generate-else drives the outputs inactive.) *
***************************************************/
// Papertape byte source (INCLUDE_TAPE)
output wire TAPE_BYTE_REQ, //! pulse: fetch next tape byte
input wire TAPE_BYTE_VALID, //! pulse: TAPE_BYTE_DATA is the byte
input wire [7:0] TAPE_BYTE_DATA,
output wire TAPE_REWIND, //! pulse: rewind the tape source
// DMA test client (INCLUDE_FLOPPY || INCLUDE_SMD: it is the grant-chain head)
input wire DMA_REQ, //! pulse: one word transfer
input wire DMA_WR, //! 0 = memory read, 1 = memory write
input wire [23:0] DMA_ADDR, //! physical memory address
input wire [15:0] DMA_WDATA,
output wire [15:0] DMA_RDATA,
output wire DMA_ACK,
output wire DMA_ERR,
output wire DMA_BUSY,
// Floppy disk-image backend (INCLUDE_FLOPPY)
output wire FDISK_REQ,
output wire FDISK_WR,
output wire [15:0] FDISK_LSECT,
output wire [1:0] FDISK_FORMAT,
output wire [1:0] FDISK_DRIVE,
output wire [10:0] FDISK_WORDCOUNT,
input wire FDISK_DONE,
input wire FDISK_ERR,
input wire [ 3:0] FDISK_ERR_CODE,
//! media format from the image size (deviceFloppyDMA.c READ FORMAT):
//! {doubleDensity, doubleSided, bytesPerSector[1:0]}
input wire [3:0] FDISK_MEDIA_FMT,
input wire [9:0] FDBUF_ADDR,
input wire [15:0] FDBUF_WDATA,
input wire FDBUF_WE,
output wire [15:0] FDBUF_RDATA,
// SMD disk backend (INCLUDE_SMD)
output wire SDISK_START,
output wire SDISK_REQ,
output wire SDISK_WR,
output wire [15:0] SDISK_BLKADDR1,
output wire [15:0] SDISK_BLKADDR2,
output wire [2:0] SDISK_UNIT,
output wire [10:0] SDISK_WORDCOUNT,
input wire SDISK_DONE,
input wire SDISK_ERR,
input wire [ 3:0] SDISK_ERR_CODE,
input wire [9:0] SDBUF_ADDR,
input wire [15:0] SDBUF_WDATA,
input wire SDBUF_WE,
output wire [15:0] SDBUF_RDATA,
// Winchester disk backend (INCLUDE_WD). Same port shape as the SMD one:
// the card reuses nd_storage_disc_adapter with Winchester geometry, since
// that adapter has nothing SMD-specific in it (see the adapter header and
// ND-BUS-DEVICES/WINCHESTER/sim/nd_winchester_adapter_tb.v).
output wire WDISK_START,
output wire WDISK_REQ,
output wire WDISK_WR,
output wire [15:0] WDISK_BLKADDR1,
output wire [15:0] WDISK_BLKADDR2,
output wire [2:0] WDISK_UNIT,
output wire [10:0] WDISK_WORDCOUNT,
input wire WDISK_DONE,
input wire WDISK_ERR,
input wire [ 3:0] WDISK_ERR_CODE,
input wire [9:0] WDBUF_ADDR,
input wire [15:0] WDBUF_WDATA,
input wire WDBUF_WE,
output wire [15:0] WDBUF_RDATA,
/***************************************************
* (f) DEBUG / STATUS (all outputs) *
***************************************************/
output wire [6:0] LED, //! ND3202D LED bundle (see ND3202D.v port comment)
output wire RUN_n, //! low while the CPU is running
output wire [12:0] CSA_12_0, //! Microcode address
output wire [ 3:0] PIL, //! Processor interrupt level (for debug capture)
output wire [13:0] LA_23_10, //! MAC upper address (XLA 23:10)
output wire [9:0] CA_9_0, //! MAC lower address (XCA 9:0)
output wire [4:0] DEBUG_CC_TERM, //! {TERM_n, CC3_n, CC2_n, CC1_n, CC0_n}
output wire DEBUG_MCLK, //! Microcycle clock
output wire DEBUG_LCS_n, //! 0 = loading microcode, 1 = loaded
output wire DEBUG_FETCH,
output wire DEBUG_MAP_n, //! one falling edge per macro instruction (see ND3202D)
output wire DEBUG_CFETCH, //! one rise per macro instruction (CGA CFETCH) - the MIPS event
output wire DEBUG_MR_n, //! Master Reset
output wire DEBUG_CLEAR_n,
output wire DEBUG_REFRQ_n, //! Refresh Request
output wire DEBUG_INTRQ_n, //! Interrupt Request
output wire DEBUG_POWFAIL_n, //! Power Fail
output wire [15:0] DEBUG_FIDBO_15_0, //! FIDBO internal data bus
output wire [15:0] DEBUG_IREQ_15_0_N, //! DEBUG: raw interrupt-request vector (active low)
output wire [15:0] XMIC_DBG_15_0, //! DEBUG: microsequencer address-advance probe (Tang 06000-hang)
//! DEBUG: register-file B port as {LBA_3_0, B_15_0}. At microcode address
//! 002156 (STERR) the microcode does "B,R2 ALUF,PASSB", so this carries the
//! self-test error number that STERR exists to display.
output wire [19:0] XWRFB_DBG_19_0,
//! DEBUG: cycle-controller terminate-plane inputs, see CYC_36.v.
//! [0] SHORT_n [1] SLOW_n [2] HIT [3] BRK_n [4] DLY0_n [5] DLY1_n [7:6] CSDELAY
output wire [11:0] XCYC_DBG_7_0,
output wire DBG_PTW_LVL, //! live PT write-strobe level (~EPT_n & ~WMAP_n, 27-AUG overlap probe) - unconditional: every backend has PT chips
//! Operator-panel status in MC68705 Port-D order - see the port comment in
//! ND3202D.v. Unconditional for the same reason DBG_PTW_LVL is: a debug
//! signal that anything outside a conditional touches must be declared
//! outside every conditional, or it vanishes on some builds and not others.
output wire [7:0] DBG_PANEL,
output wire [15:0] PANEL_ACTLV, //! ACTIVE LEVEL word from the panel processor
//! DEBUG: cache-write gating bus, straight through from ND3202D. Bit
//! layout and the reason are in CPU_MMU_24.v's DBG_CACHE port comment.
output wire [7:0] DBG_CACHE
`ifdef MAIN_RAM_SDRAM
/***************************************************
* (b) RAM BACKEND - SDRAM PHY pass-through only *
* RAM lives INSIDE ND3202D (MEM_43 -> MEM_RAM_49);*
* under MAIN_RAM_SDRAM the PHY pins are threaded *
* up through ND3202D and out to the board. *
* Absent entirely on sim/Basys3 (on-chip BRAM). *
***************************************************/
,
input wire clk2x, //! 2x clk_cpu, same PLL, edge-aligned
input wire clk2x_sdram, //! 180 degrees from clk2x, to the SDRAM chip
output wire O_sdram_clk,
output wire O_sdram_cke,
output wire O_sdram_cs_n,
output wire O_sdram_cas_n,
output wire O_sdram_ras_n,
output wire O_sdram_wen_n,
inout wire [31:0] IO_sdram_dq,
output wire [10:0] O_sdram_addr,
output wire [ 1:0] O_sdram_ba,
output wire [ 3:0] O_sdram_dqm,
output wire [15:0] DBG_MEMW, //! write-path debug bus from MEM_43
output wire [15:0] DBG_PTW, //! page-table write stream from CPU_MMU_24 (23-AUG, zero-read campaign)
output wire [20:0] PF_CAPTURED, //! ND120_PF_CAPTURE freeze flag (23-AUG)
//! DEBUG stage timer (24-AUG-2026): [0] Winchester controller active,
//! [1] the Winchester's DMA master busy. Used to find where a disc
//! operation's ~1 s of wall clock actually goes.
output wire [1:0] DBG_WDSTAGE,
output wire [13:0] DBG_PPN, //! physical page number PPN[23:10] (24-AUG)
output wire [15:0] DBG_PGW //! SDRAM-bridge page-write watch (24-AUG)
`ifdef ND_STORAGE_PORT
/***************************************************
* (c) STORAGE seam into the SDRAM device port *
* The board's storage stack (nd_storage_devices)*
* reaches MEM_RAM_49_SDRAM's upper-half region *
* through here. The backend forces the leading *
* address 1, so device traffic physically cannot *
* touch the CPU's half of the chip. *
* stor_clk is an INDEPENDENT domain (the SD stack *
* needs 27 MHz for a spec-legal identification *
* clock, whatever VARIANT the CPU runs at); the *
* backend toggle-CDCs it into clk2x. *
***************************************************/
,
input wire stor_clk, //! 27 MHz crystal (pin 4) (from ND120_TANG20K_TOP.sys_clk)
input wire stor_rst_n,
input wire mem_start,
input wire mem_we,
input wire [19:0] mem_addr,
input wire [31:0] mem_wdata,
output wire [31:0] mem_rdata,
output wire mem_busy,
output wire mem_done
`endif
`endif
`ifdef MAIN_RAM_DDR2
/***************************************************
* (b2) RAM BACKEND - DDR2 client pass-through *
* RAM lives INSIDE ND3202D (MEM_43 -> *
* MEM_RAM_49_DDR2); the ui_clk-domain client *
* port is threaded up to the board top, where *
* nd_ddr2_arb shares the MIG with the storage *
* region. Absent in every other build. *
***************************************************/
,
input wire ui_clk,
input wire ui_rst,
output wire mm_req_valid,
output wire mm_req_we,
output wire [ 26:0] mm_req_addr,
output wire [127:0] mm_req_wdata,
output wire [ 15:0] mm_req_wmask,
input wire mm_req_ready,
input wire mm_rsp_valid,
input wire [127:0] mm_rsp_rdata,
output wire [ 7:0] DBG_DDR2_BRIDGE
`endif
`ifdef TANG_WD_TRACE_DUMP
,
// Winchester IOX trace tap, brought out for the board-level capture and
// UART dump. Present ONLY under TANG_WD_TRACE_DUMP - the normal build
// never carries it.
output wire [19:0] wd_trace_rec,
output wire wd_trace_we,
output wire wd_trace_done
`endif
);
/**********************************************
* Constants that used to live in ND120_TOP *
***********************************************/
// Installation number (read using IDB Source = 035)
//
// Was a single hardwired 8'd123 for EVERY PIL value, which made SINTRAN's
// GCPUNR signature check (bytes 6/7 must read 0x55/0xAA) fail, so the CPU
// NUMBER / CPU TYPE / NLEGU in the PROM could never be reported. It is now a
// real 16-byte back-wiring PROM addressed by PIL[3:0] - see the instance of
// BACKWIRING_PROM further down and docs/backwiring-prom-installation-number.md.
wire [7:0] installation_number;
wire s_high = 1'b1;
wire s_low = 1'b0;
wire [1:0] oc_select = 2'b11; // 11 = clock input XTAL1 (full speed)
wire [2:0] s_SEL_TESTMUX = 3'b000; // 000 = TESTMUX = 0
// 8 = 9600 baud (ref BAUDV page 158 in microcode)
wire [3:0] s_baud_rate_switch = 4'b1000;
/**********************************************
* CPU-board debug wires kept alive *
* (Run120.cpp reads s_csbits hierarchically) *
***********************************************/
(* keep = "true", DONT_TOUCH = "true" *) wire [4:0] s_test_4_0; // Test pads
(* keep = "true", DONT_TOUCH = "true" *) wire [4:0] s_dp_5_1_n; // Datapath 5-1
(* keep = "true", DONT_TOUCH = "true" *) wire s_tp1_intrq_n; // TP1 INTRQ_n
(* keep = "true", DONT_TOUCH = "true" *) wire [63:0] s_csbits; // Microcode CPU BITS
/**********************************************
* Verilog external-bus devices (optional) *
* ND-BUS-DEVICES: bus slave + papertape 400 *
* + floppy 1560 + SMD 1540 and their DMA *
* masters. Wired-AND onto the active-low bus *
* inputs of the CPU board. *
***********************************************/
localparam ANY_DEVICE = (INCLUDE_TAPE != 0) || (INCLUDE_FLOPPY != 0) || (INCLUDE_SMD != 0) || (INCLUDE_WD != 0);
// The DMA test master is the head of the DMA grant chain (its INGRANT_n is
// the CPU's OUTGRANT_n), so it must exist whenever any bus master exists.
localparam ANY_DMA_MASTER = (INCLUDE_FLOPPY != 0) || (INCLUDE_SMD != 0) || (INCLUDE_WD != 0);
// Every device shares this one clock with the CPU board.
wire s_dev_clk = clk_cpu;
// ---- device timing expressed as TIME, converted here to clk_cpu cycles ---
// BOARD_CLK_FREQ is the actual clk_cpu frequency in Hz. The Tang defines it
// in fpga/tang-nano-20k/src/tang20k_defines.v: 6_750_000 for the default
// slow bring-up (the PLL gives CLKOUT 13.5 MHz and clk_cpu = CLKOUT/2),
// 27_000_000 full speed, 3_375_000 crawl. Builds that do not define it
// (the Verilator sim) fall back to the same 100 MHz DECODE_DGA_POW uses,
// so the macro's meaning stays identical everywhere.
`ifdef BOARD_CLK_FREQ
localparam integer DEV_CLK_HZ = `BOARD_CLK_FREQ;
`else
localparam integer DEV_CLK_HZ = 100_000_000;
`endif
// SMD: how long the controller holds ACTIVE after a GO before reporting
// completion. This is a mechanical time on a real drive - a 75 MB SMD at
// 3600 rpm averages 8.3 ms of rotational latency alone, and a seek is tens
// of milliseconds - and diagnostics rely on it: DISC-TEMA reads the status
// a few thousand clocks after activating and reports "Controller not active
// after activate" if the operation has already finished. 8 ms is close to
// the real rotational figure and leaves a wide margin over that check at
// every clock variant (54,000 cycles at 6.75 MHz, 216,000 at 27 MHz).
localparam integer SMD_DELAY_MS = 8;
// The delay is a WALL-CLOCK time, so the CYCLE count it becomes depends on
// DEV_CLK_HZ: 216,000 cycles on the Tang (27 MHz) but 800,000 in Verilator,
// which falls back to 100 MHz. The CPU executes per CYCLE, so the sim gives
// a spinning driver 3.7x MORE instructions before the card completes - and
// DISC-TEMA's wait for the seek is a software loop with a bounded count.
// ND120_DEV_DELAY_TICKS overrides the cycle count directly so a sim run can
// be made cycle-identical to silicon. Overriding is a DIAGNOSTIC lever, not
// a fix: it changes what the drive models, so leave it undefined unless a
// specific experiment needs it.
`ifdef ND120_DEV_DELAY_TICKS
localparam [31:0] SMD_DELAY_TICKS = `ND120_DEV_DELAY_TICKS;
`else
localparam [31:0] SMD_DELAY_TICKS = (DEV_CLK_HZ / 1000) * SMD_DELAY_MS;
`endif
// TESTED AND EXONERATED 05-AUG-2026, confirmed 06-AUG: the completion
// latency was never the cause of DISC-TEMA's "Memory address Register not
// as expected". The real fault was the CPU zeroing the A register at the
// end of every IOX WRITE (the CDLBD 74646's bidirectional LBD pin was
// transcribed as separate in/out nets, so the DSTB_n-rise capture read a
// dead bus and the microcode's unconditional A := DBR loaded 0). Fixed
// 06-AUG-2026 in CPU-BOARD-3202/circuit/BIF_DPATH_9.v (one OR-term restores
// the pin node); verified clean on silicon and in simulation.
`ifndef MAIN_RAM_SDRAM
// DBG_WDSTAGE is an output port only in the MAIN_RAM_SDRAM section of the
// port list, but the Winchester generate below drives it unconditionally.
// Without this fallback the non-SDRAM builds (Verilator, DDR2) create an
// IMPLICIT 1-bit net - which Verilator -Wall treats as a hard error
// (found 30-AUG-2026 when runSim stopped verilating). Same rule as the
// DBG_CACHE port comment: a debug wire touched outside a conditional must
// exist in every build.
wire [1:0] DBG_WDSTAGE;
`endif
// Bus-slave contributions onto the CPU's bus inputs (active low)
wire [23:0] s_dev_bd_n;
wire s_dev_binput_n, s_dev_bdap_n, s_dev_bdry_n;
wire s_dev_bint10_n, s_dev_bint11_n, s_dev_bint12_n, s_dev_bint13_n;
// IOX fan-out from the bus slave to the device cores
// ND120_ILA_MARK_DEBUG (Nexys build.tcl -tclargs ila): keep the device
// IOX seam nets for the JTAG ILA - which register the CPU polls during
// the LIST-FILE-NAMES runaway and what the device answers (24-AUG).
// No functional effect; the define is set only by that build flag.
`ifdef ND120_ILA_MARK_DEBUG
(* mark_debug = "true" *)
`endif
wire [15:0] s_dev_iox_addr;
wire [15:0] s_dev_iox_wdata;
`ifdef ND120_ILA_MARK_DEBUG
(* mark_debug = "true" *)
`endif
wire s_dev_iox_wr;
`ifdef ND120_ILA_MARK_DEBUG
(* mark_debug = "true" *)
`endif
wire s_dev_iox_rd;
`ifdef ND120_ILA_MARK_DEBUG
(* mark_debug = "true" *)
`endif
wire s_dev_ident_strobe;
`ifdef ND120_ILA_MARK_DEBUG
(* mark_debug = "true" *)
`endif
wire [3:0] s_dev_ident_level;
// OR-bus contributions per device core (tape, floppy, SMD)
wire [15:0] s_tape_rdata, s_flp_rdata, s_smd_rdata, s_wd_rdata;
wire [3:0] s_tape_intp, s_flp_intp, s_smd_intp, s_wd_intp;
wire s_tape_hit, s_flp_hit, s_smd_hit, s_wd_hit;
wire [15:0] s_tape_code, s_flp_code, s_smd_code, s_wd_code;
// Per-core IOX address-match. When NO core owns the captured IOX address the
// slave must answer nothing (no BDRY) so the CPU bus-times-out into the
// level-14 IOX error, instead of the slave answering every address.
wire s_tape_sel, s_flp_sel, s_smd_sel, s_wd_sel;
// IDENT daisy chain: head -> tape -> floppy -> SMD (absent stage = pass-through)
`ifdef ND120_ILA_MARK_DEBUG
(* mark_debug = "true" *)
`endif
wire s_grant_tape_flp; // ident chain: tape -> floppy
wire s_grant_flp_smd; // ident chain: floppy -> SMD
wire s_grant_smd_wd; // ident chain: SMD -> Winchester
`ifdef ND120_ILA_MARK_DEBUG
(* mark_debug = "true" *)
`endif
wire [15:0] s_dev_iox_rdata = s_tape_rdata | s_flp_rdata | s_smd_rdata | s_wd_rdata;
`ifdef ND120_ILA_MARK_DEBUG
(* mark_debug = "true" *)
`endif
wire [3:0] s_dev_int_pending = s_tape_intp | s_flp_intp | s_smd_intp | s_wd_intp;
`ifdef ND120_ILA_MARK_DEBUG
(* mark_debug = "true" *)
`endif
wire s_dev_ident_hit = s_tape_hit | s_flp_hit | s_smd_hit | s_wd_hit;
`ifdef ND120_ILA_MARK_DEBUG
(* mark_debug = "true" *)
`endif
wire [15:0] s_dev_ident_code = s_tape_code | s_flp_code | s_smd_code | s_wd_code;
wire s_dev_iox_hit = s_tape_sel | s_flp_sel | s_smd_sel | s_wd_sel;
`ifdef ND120_ERRFA_PROBE
assign ERRFA_IOX_ADDR = s_dev_iox_addr;
assign ERRFA_IOX_RD = s_dev_iox_rd;
assign ERRFA_IOX_WR = s_dev_iox_wr;
assign ERRFA_IOX_WDATA = s_dev_iox_wdata;
assign ERRFA_IOX_RDATA = s_dev_iox_rdata;
`endif
// DMA grant chain (active low): CPU OUTGRANT_n -> test master -> floppy
// master -> SMD master. Declared up front: s_grant_fdma_smdm_n is used by
// the floppy master before the SMD master is instantiated.
wire s_grant_dma_fdma_n; // grant chain: test DMA master -> floppy master
wire s_grant_fdma_smdm_n; // grant chain: floppy master -> SMD master
wire s_grant_smdm_wdm_n; // grant chain: SMD master -> Winchester master
// Per-master bus contributions (active low; tied high when the master is absent)
wire [23:0] s_dma_bd_n, s_fdmam_bd_n, s_smdm_bd_n, s_wdm_bd_n;
wire s_dma_breq_n, s_fdmam_breq_n, s_smdm_breq_n, s_wdm_breq_n;
wire s_dma_bapr_n, s_fdmam_bapr_n, s_smdm_bapr_n, s_wdm_bapr_n;
wire s_dma_binput_n, s_fdmam_binput_n, s_smdm_binput_n, s_wdm_binput_n;
wire s_dma_bdap_n, s_fdmam_bdap_n, s_smdm_bdap_n, s_wdm_bdap_n;
/*---------------------------------------------
* ND-BUS slave shell (present with any device)
*--------------------------------------------*/
generate
if (ANY_DEVICE) begin : gen_bus_slave
ND_BUS_SLAVE BUS_SLAVE (
.sysclk(s_dev_clk),
.sys_rst_n(sys_rst_n),
.BD_23_0_n_OUT(BD_23_0_n_OUT),
.BD_23_0_n_IN(s_dev_bd_n),
.BAPR_n(BAPR_n_OUT),
.BIOXE_n(BIOXE_n),
.BINACK_n(BINACK_n),
.OUTIDENT_n(OUTIDENT_n),
.BINPUT_n(s_dev_binput_n),
.BDAP_n(s_dev_bdap_n),
.BDRY_n(s_dev_bdry_n),
.BINT10_n(s_dev_bint10_n),
.BINT11_n(s_dev_bint11_n),
.BINT12_n(s_dev_bint12_n),
.BINT13_n(s_dev_bint13_n),
.iox_addr(s_dev_iox_addr),
.iox_wr(s_dev_iox_wr),
.iox_wdata(s_dev_iox_wdata),
.iox_rd(s_dev_iox_rd),
.iox_rdata(s_dev_iox_rdata),
.iox_hit(s_dev_iox_hit),
.int_pending(s_dev_int_pending),
.ident_strobe(s_dev_ident_strobe),
.ident_level(s_dev_ident_level),
.ident_hit(s_dev_ident_hit),
.ident_code(s_dev_ident_code)
);
end else begin : gen_no_bus_slave
// No devices: contribute nothing to the wired-AND, drive no IOX.
assign s_dev_bd_n = 24'hFFFFFF;
assign s_dev_binput_n = 1'b1;
assign s_dev_bdap_n = 1'b1;
assign s_dev_bdry_n = 1'b1;
assign s_dev_bint10_n = 1'b1;
assign s_dev_bint11_n = 1'b1;
assign s_dev_bint12_n = 1'b1;
assign s_dev_bint13_n = 1'b1;
assign s_dev_iox_addr = 16'd0;
assign s_dev_iox_wdata = 16'd0;
assign s_dev_iox_wr = 1'b0;
assign s_dev_iox_rd = 1'b0;
assign s_dev_ident_strobe = 1'b0;
assign s_dev_ident_level = 4'd0;
end
endgenerate
/*---------------------------------------------
* Papertape reader 400 (byte source on board)
*--------------------------------------------*/
generate
if (INCLUDE_TAPE != 0) begin : gen_tape
ND_TAPE_400 #(
.BASE_ADDR (16'o000400),
.IDENT_CODE(16'o000002),
.INT_LEVEL (4'd12)
) TAPE_400 (
.sysclk(s_dev_clk),
.sys_rst_n(sys_rst_n),
.iox_addr(s_dev_iox_addr),
.iox_wr(s_dev_iox_wr),
.iox_wdata(s_dev_iox_wdata),
.iox_rd(s_dev_iox_rd),
.iox_rdata(s_tape_rdata),
.iox_sel(s_tape_sel),
.int_pending(s_tape_intp),
.ident_strobe(s_dev_ident_strobe),
.ident_level(s_dev_ident_level),
.ident_grant_in(1'b1), // chain head
.ident_grant_out(s_grant_tape_flp),
.ident_hit(s_tape_hit),
.ident_code(s_tape_code),
.byte_req(TAPE_BYTE_REQ),
.byte_valid(TAPE_BYTE_VALID),
.byte_data(TAPE_BYTE_DATA),
.source_rewind(TAPE_REWIND)
);
end else begin : gen_no_tape
assign s_tape_rdata = 16'd0;
assign s_tape_sel = 1'b0;
assign s_tape_intp = 4'd0;
assign s_tape_hit = 1'b0;
assign s_tape_code = 16'd0;
assign s_grant_tape_flp = 1'b1; // pass the chain head through
assign TAPE_BYTE_REQ = 1'b0;
assign TAPE_REWIND = 1'b0;
end
endgenerate
/*---------------------------------------------
* Floppy 1560, DMA flavor (Ronny's choice
* 11-JUL): the controller masters the bus
* through its own ND_DMA_MASTER, second in the
* grant chain behind the DMA test master.
*--------------------------------------------*/
generate
if (INCLUDE_FLOPPY != 0) begin : gen_floppy
wire s_fdma_req, s_fdma_wr;
wire [23:0] s_fdma_addr;
wire [15:0] s_fdma_wdata, s_fdma_rdata;
wire s_fdma_ack, s_fdma_err, s_fdma_busy;
ND_FLOPPY_DMA #(
.BASE_ADDR (16'o001560),
.IDENT_CODE(16'o000021),
.INT_LEVEL (4'd11)
) FLOPPY_1560 (
.sysclk(s_dev_clk),
.sys_rst_n(sys_rst_n),
.iox_addr(s_dev_iox_addr),
.iox_wr(s_dev_iox_wr),
.iox_wdata(s_dev_iox_wdata),
.iox_rd(s_dev_iox_rd),
.iox_rdata(s_flp_rdata),
.iox_sel(s_flp_sel),
.int_pending(s_flp_intp),
.ident_strobe(s_dev_ident_strobe),
.ident_level(s_dev_ident_level),
.ident_grant_in(s_grant_tape_flp),
.ident_grant_out(s_grant_flp_smd),
.ident_hit(s_flp_hit),
.ident_code(s_flp_code),
.dma_req(s_fdma_req),
.dma_wr(s_fdma_wr),
.dma_addr(s_fdma_addr),
.dma_wdata(s_fdma_wdata),
.dma_rdata(s_fdma_rdata),
.dma_ack(s_fdma_ack),
.dma_err(s_fdma_err),
.dma_busy(s_fdma_busy),
.disk_req(FDISK_REQ),
.disk_wr(FDISK_WR),
.disk_lsect(FDISK_LSECT),
.disk_format(FDISK_FORMAT),
.disk_drive(FDISK_DRIVE),
.disk_wordcount(FDISK_WORDCOUNT),
.disk_done(FDISK_DONE),
.disk_err_in(FDISK_ERR),
.disk_err_code(FDISK_ERR_CODE),
.disk_media_fmt(FDISK_MEDIA_FMT),
.dbuf_addr(FDBUF_ADDR),
.dbuf_wdata(FDBUF_WDATA),
.dbuf_we(FDBUF_WE),
.dbuf_rdata(FDBUF_RDATA)
);
ND_DMA_MASTER #(
.TIMEOUT_TICKS(16'd8192)
) FLOPPY_DMA_MASTER (
.sysclk(s_dev_clk),
.sys_rst_n(sys_rst_n),
.dma_req(s_fdma_req),
.dma_wr(s_fdma_wr),
.dma_addr(s_fdma_addr),
.dma_wdata(s_fdma_wdata),
.dma_rdata(s_fdma_rdata),
.dma_ack(s_fdma_ack),
.dma_err(s_fdma_err),
.dma_busy(s_fdma_busy),
.BREQ_n(s_fdmam_breq_n),
.INGRANT_n(s_grant_dma_fdma_n),
.OUTGRANT_n(s_grant_fdma_smdm_n),
.BMEM_n(BMEM_n),
.BD_23_0_n_OUT(s_fdmam_bd_n),
.BD_23_0_n_IN(BD_23_0_n_OUT),
.BAPR_n(s_fdmam_bapr_n),
.BINPUT_n(s_fdmam_binput_n),
.BDAP_n(s_fdmam_bdap_n),
.BDRY_n(BDRY_n_OUT)
);
end else begin : gen_no_floppy
assign s_flp_rdata = 16'd0;
assign s_flp_sel = 1'b0;
assign s_flp_intp = 4'd0;
assign s_flp_hit = 1'b0;
assign s_flp_code = 16'd0;
assign s_grant_flp_smd = s_grant_tape_flp; // ident chain pass-through
assign s_grant_fdma_smdm_n = s_grant_dma_fdma_n; // DMA grant pass-through
assign s_fdmam_bd_n = 24'hFFFFFF;
assign s_fdmam_breq_n = 1'b1;
assign s_fdmam_bapr_n = 1'b1;
assign s_fdmam_binput_n = 1'b1;
assign s_fdmam_bdap_n = 1'b1;
assign FDISK_REQ = 1'b0;
assign FDISK_WR = 1'b0;
assign FDISK_LSECT = 16'd0;
assign FDISK_FORMAT = 2'd0;
assign FDISK_DRIVE = 2'd0;
assign FDISK_WORDCOUNT = 11'd0;
assign FDBUF_RDATA = 16'd0;
end
endgenerate
/*---------------------------------------------
* SMD disk controller at 1540 with its own bus
* master, third in the grant chain
* (test master -> floppy master -> SMD master)
*--------------------------------------------*/
generate
if (INCLUDE_SMD != 0) begin : gen_smd
wire s_smd_req, s_smd_wr;
wire [23:0] s_smd_addr;
wire [15:0] s_smd_wdata, s_smd_rdata_dma;
wire s_smd_ack, s_smd_err, s_smd_busy;
ND_SMD #(
.BASE_ADDR (16'o001540),
.IDENT_CODE (16'o000017),
.INT_LEVEL (4'd11),
.DELAY_TICKS(SMD_DELAY_TICKS),
// Controller-type strap: default ECC single-write (boots the SMD
// image). Override the top-level SMD_HAS_FLIPFLOP to 1 (or build with
// -DND120_SMD_15MHZ) for the 15 MHz two-write card.
.HAS_WC_FLIPFLOP(SMD_HAS_FLIPFLOP),
.HAS_WCNT_FLIPFLOP(SMD_WCNT_FLIPFLOP)
) SMD_1540 (
.sysclk(s_dev_clk),
.sys_rst_n(sys_rst_n),
.iox_addr(s_dev_iox_addr),
.iox_wr(s_dev_iox_wr),
.iox_wdata(s_dev_iox_wdata),
.iox_rd(s_dev_iox_rd),
.iox_rdata(s_smd_rdata),
.iox_sel(s_smd_sel),
.int_pending(s_smd_intp),
.ident_strobe(s_dev_ident_strobe),
.ident_level(s_dev_ident_level),
.ident_grant_in(s_grant_flp_smd),
.ident_grant_out(s_grant_smd_wd),
.ident_hit(s_smd_hit),
.ident_code(s_smd_code),
.dma_req(s_smd_req),
.dma_wr(s_smd_wr),
.dma_addr(s_smd_addr),
.dma_wdata(s_smd_wdata),
.dma_rdata(s_smd_rdata_dma),
.dma_ack(s_smd_ack),
.dma_err(s_smd_err),
.dma_busy(s_smd_busy),
.disk_start(SDISK_START),
.disk_req(SDISK_REQ),
.disk_wr(SDISK_WR),
.disk_blkaddr1(SDISK_BLKADDR1),
.disk_blkaddr2(SDISK_BLKADDR2),
.disk_unit(SDISK_UNIT),
.disk_wordcount(SDISK_WORDCOUNT),
.disk_done(SDISK_DONE),
.disk_err_in(SDISK_ERR),
.disk_err_code(SDISK_ERR_CODE),
.dbuf_addr(SDBUF_ADDR),
.dbuf_wdata(SDBUF_WDATA),
.dbuf_we(SDBUF_WE),
.dbuf_rdata(SDBUF_RDATA)
);
ND_DMA_MASTER #(
.TIMEOUT_TICKS(16'd8192)
) SMD_DMA_MASTER (
.sysclk(s_dev_clk),
.sys_rst_n(sys_rst_n),
.dma_req(s_smd_req),
.dma_wr(s_smd_wr),
.dma_addr(s_smd_addr),
.dma_wdata(s_smd_wdata),
.dma_rdata(s_smd_rdata_dma),
.dma_ack(s_smd_ack),
.dma_err(s_smd_err),
.dma_busy(s_smd_busy),
.BREQ_n(s_smdm_breq_n),
.INGRANT_n(s_grant_fdma_smdm_n),
.OUTGRANT_n(s_grant_smdm_wdm_n),
.BMEM_n(BMEM_n),
.BD_23_0_n_OUT(s_smdm_bd_n),
.BD_23_0_n_IN(BD_23_0_n_OUT),
.BAPR_n(s_smdm_bapr_n),
.BINPUT_n(s_smdm_binput_n),
.BDAP_n(s_smdm_bdap_n),
.BDRY_n(BDRY_n_OUT)
);
end else begin : gen_no_smd
assign s_grant_smd_wd = s_grant_flp_smd; // ident chain pass-through
assign s_grant_smdm_wdm_n = s_grant_fdma_smdm_n; // DMA grant pass-through
assign s_smd_rdata = 16'd0;
assign s_smd_sel = 1'b0;
assign s_smd_intp = 4'd0;
assign s_smd_hit = 1'b0;
assign s_smd_code = 16'd0;
assign s_smdm_bd_n = 24'hFFFFFF;
assign s_smdm_breq_n = 1'b1;
assign s_smdm_bapr_n = 1'b1;
assign s_smdm_binput_n = 1'b1;
assign s_smdm_bdap_n = 1'b1;
assign SDISK_START = 1'b0;
assign SDISK_REQ = 1'b0;
assign SDISK_WR = 1'b0;
assign SDISK_BLKADDR1 = 16'd0;
assign SDISK_BLKADDR2 = 16'd0;
assign SDISK_UNIT = 3'd0;
assign SDISK_WORDCOUNT = 11'd0;
assign SDBUF_RDATA = 16'd0;
end
endgenerate
/*---------------------------------------------
* Winchester disc controller at 500 (ST506
* card 3041 / 8 inch card 3038) with its own
* bus master, fourth in the grant chain
* (test -> floppy -> SMD -> Winchester).
*
* NOTE 500-507 is the SAME IOX block as the
* CDC cartridge disc: a machine has one card
* or the other, never both.
*--------------------------------------------*/
generate
if (INCLUDE_WD != 0) begin : gen_wd
wire s_wd_req, s_wd_wr;
wire [23:0] s_wd_addr;
wire [15:0] s_wd_wdata, s_wd_rdata_dma;
wire s_wd_ack, s_wd_err, s_wd_busy;
wire s_wd_dbg_active;
ND_WINCHESTER #(
.BASE_ADDR (16'o000500),
.IDENT_CODE (16'o000001),
.INT_LEVEL (4'd11),
.DELAY_TICKS(SMD_DELAY_TICKS),
// Micropolis 1325 (the DISC-74-1) - the drive SINTRAN boots from,
// and the default in both C models. MUST match the GEO_* the
// storage adapter in front of the backend is given.
.GEO_HEADS (16'd8),
.GEO_SPT (16'd9),
.GEO_MAX_CYL(16'd1024)
) WD_500 (
.sysclk(s_dev_clk),
.sys_rst_n(sys_rst_n),
.iox_addr(s_dev_iox_addr),
.iox_wr(s_dev_iox_wr),
.iox_wdata(s_dev_iox_wdata),
.iox_rd(s_dev_iox_rd),
.iox_rdata(s_wd_rdata),
.iox_sel(s_wd_sel),
`ifdef TANG_WD_TRACE_DUMP
.trace_rec(wd_trace_rec),
.trace_we(wd_trace_we),
.trace_done(wd_trace_done),
`else
.trace_rec(),
.trace_we(),
.trace_done(),
`endif
.int_pending(s_wd_intp),
.ident_strobe(s_dev_ident_strobe),
.ident_level(s_dev_ident_level),
.ident_grant_in(s_grant_smd_wd),
.ident_grant_out(),
.ident_hit(s_wd_hit),
.ident_code(s_wd_code),
.dma_req(s_wd_req),
.dma_wr(s_wd_wr),
.dma_addr(s_wd_addr),
.dma_wdata(s_wd_wdata),
.dma_rdata(s_wd_rdata_dma),
.dma_ack(s_wd_ack),
.dma_err(s_wd_err),
.dma_busy(s_wd_busy),
.dbg_active(s_wd_dbg_active),
.disk_start(WDISK_START),
.disk_req(WDISK_REQ),
.disk_wr(WDISK_WR),
.disk_blkaddr1(WDISK_BLKADDR1),
.disk_blkaddr2(WDISK_BLKADDR2),
.disk_unit(WDISK_UNIT),
.disk_wordcount(WDISK_WORDCOUNT),
.disk_done(WDISK_DONE),
.disk_err_in(WDISK_ERR),
.disk_err_code(WDISK_ERR_CODE),
.dbuf_addr(WDBUF_ADDR),
.dbuf_wdata(WDBUF_WDATA),
.dbuf_we(WDBUF_WE),
.dbuf_rdata(WDBUF_RDATA)
);
// stage timer: [0] controller active, [1] its DMA master busy
assign DBG_WDSTAGE = {s_wd_busy, s_wd_dbg_active};
ND_DMA_MASTER #(
.TIMEOUT_TICKS(16'd8192)
) WD_DMA_MASTER (
.sysclk(s_dev_clk),
.sys_rst_n(sys_rst_n),
.dma_req(s_wd_req),
.dma_wr(s_wd_wr),
.dma_addr(s_wd_addr),
.dma_wdata(s_wd_wdata),
.dma_rdata(s_wd_rdata_dma),
.dma_ack(s_wd_ack),
.dma_err(s_wd_err),
.dma_busy(s_wd_busy),
.BREQ_n(s_wdm_breq_n),
.INGRANT_n(s_grant_smdm_wdm_n),
.OUTGRANT_n(),
.BMEM_n(BMEM_n),
.BD_23_0_n_OUT(s_wdm_bd_n),
.BD_23_0_n_IN(BD_23_0_n_OUT),
.BAPR_n(s_wdm_bapr_n),
.BINPUT_n(s_wdm_binput_n),
.BDAP_n(s_wdm_bdap_n),
.BDRY_n(BDRY_n_OUT)
);
`ifdef ND120_DMA_STALL_DBG
// ------------------------------------------------------------------
// WINCHESTER DMA STALL PROBE (inert unless -DND120_DMA_STALL_DBG).
//
// The SINTRAN boot stops with the DISC side finished - every disk read
// reported done - and the controller still reporting ACTIVE (status
// 060005 instead of the oracle's 060011). A bench replaying the exact
// IOX sequence completes, a word-count sweep completes, and the real
// ND_DMA_MASTER driving the real SD card completes. The one thing no
// bench reproduces is the CPU competing for the same bus, so the
// question is whether this master ever WINS a grant once the CPU is
// spinning in its IOX poll loop.
//
// Reports a request that stays outstanding far longer than a memory
// cycle can take, and prints the bus lines that decide it: our own
// BREQ, the grant coming in, BMEM from the bus control unit, and BDRY
// from memory. Whichever of those is stuck names the culprit - it is
// not inferred from the absence of an acknowledge.
integer r_wdstall;
reg r_wdstall_said;
initial begin r_wdstall = 0; r_wdstall_said = 1'b0; end
always @(posedge s_dev_clk) begin
if (s_wd_busy || s_wd_req) begin
r_wdstall <= r_wdstall + 1;
if (r_wdstall == 20000 && !r_wdstall_said) begin
r_wdstall_said <= 1'b1;
$display("[wddma] STALLED %0d cycles: req=%b busy=%b ack=%b err=%b BREQ_n=%b INGRANT_n=%b BMEM_n=%b BDRY_n=%b addr=%o",
r_wdstall, s_wd_req, s_wd_busy, s_wd_ack, s_wd_err,
s_wdm_breq_n, s_grant_smdm_wdm_n, BMEM_n, BDRY_n_OUT,
s_wd_addr);
end
end else begin
r_wdstall <= 0;
r_wdstall_said <= 1'b0;
end
end
`endif
end else begin : gen_no_wd
assign s_wd_rdata = 16'd0;
assign s_wd_sel = 1'b0;
`ifdef TANG_WD_TRACE_DUMP
assign wd_trace_rec = 20'd0;
assign wd_trace_we = 1'b0;
assign wd_trace_done = 1'b0;
`endif
assign s_wd_intp = 4'd0;
assign s_wd_hit = 1'b0;
assign s_wd_code = 16'd0;
assign s_wdm_bd_n = 24'hFFFFFF;
assign s_wdm_breq_n = 1'b1;
assign s_wdm_bapr_n = 1'b1;
assign s_wdm_binput_n = 1'b1;
assign s_wdm_bdap_n = 1'b1;
assign WDISK_START = 1'b0;
assign DBG_WDSTAGE = 2'b00;
assign WDISK_REQ = 1'b0;
assign WDISK_WR = 1'b0;
assign WDISK_BLKADDR1 = 16'd0;
assign WDISK_BLKADDR2 = 16'd0;
assign WDISK_UNIT = 3'd0;
assign WDISK_WORDCOUNT = 11'd0;
assign WDBUF_RDATA = 16'd0;
end
endgenerate
/*---------------------------------------------
* DMA bus master (full-RTL DMA validation):
* requests the bus from the REAL arbiter
* (PAL_44801A via BIF) and runs real memory
* cycles. Chain head is the CPU's OUTGRANT.
* Present whenever any master exists, since it
* is the head of the grant chain.
*--------------------------------------------*/
generate
if (ANY_DMA_MASTER) begin : gen_dma_master
ND_DMA_MASTER #(
.TIMEOUT_TICKS(16'd8192)
) DMA_MASTER (
.sysclk(s_dev_clk),
.sys_rst_n(sys_rst_n),
.dma_req(DMA_REQ),
.dma_wr(DMA_WR),
.dma_addr(DMA_ADDR),
.dma_wdata(DMA_WDATA),
.dma_rdata(DMA_RDATA),
.dma_ack(DMA_ACK),
.dma_err(DMA_ERR),
.dma_busy(DMA_BUSY),
.BREQ_n(s_dma_breq_n),
.INGRANT_n(OUTGRANT_n),
.OUTGRANT_n(s_grant_dma_fdma_n),
.BMEM_n(BMEM_n),
.BD_23_0_n_OUT(s_dma_bd_n),
.BD_23_0_n_IN(BD_23_0_n_OUT),
.BAPR_n(s_dma_bapr_n),
.BINPUT_n(s_dma_binput_n),
.BDAP_n(s_dma_bdap_n),
.BDRY_n(BDRY_n_OUT)
);
end else begin : gen_no_dma_master
assign s_grant_dma_fdma_n = OUTGRANT_n; // grant chain pass-through
assign s_dma_bd_n = 24'hFFFFFF;
assign s_dma_breq_n = 1'b1;
assign s_dma_bapr_n = 1'b1;
assign s_dma_binput_n = 1'b1;
assign s_dma_bdap_n = 1'b1;
assign DMA_RDATA = 16'd0;
assign DMA_ACK = 1'b0;
assign DMA_ERR = 1'b0;
assign DMA_BUSY = 1'b0;
end
endgenerate
/*---------------------------------------------
* Wired-AND with the external (C-harness /
* board tie-off) bus inputs. Absent devices
* contribute all-ones, so the AND is exactly
* the ND120_TOP no-device pass-through.
*--------------------------------------------*/
wire [23:0] s_bus_bd_in_n = BD_23_0_n_IN & s_dev_bd_n & s_dma_bd_n & s_fdmam_bd_n & s_smdm_bd_n & s_wdm_bd_n;
wire s_bus_breq_n = BREQ_n & s_dma_breq_n & s_fdmam_breq_n & s_smdm_breq_n & s_wdm_breq_n;
wire s_bus_bapr_in_n = BAPR_n_IN & s_dma_bapr_n & s_fdmam_bapr_n & s_smdm_bapr_n & s_wdm_bapr_n;
wire s_bus_binput_in_n = BINPUT_n_IN & s_dev_binput_n & s_dma_binput_n & s_fdmam_binput_n & s_smdm_binput_n & s_wdm_binput_n;
wire s_bus_bdap_in_n = BDAP_n_IN & s_dev_bdap_n & s_dma_bdap_n & s_fdmam_bdap_n & s_smdm_bdap_n & s_wdm_bdap_n;
wire s_bus_bdry_in_n = BDRY_n_IN & s_dev_bdry_n;
wire s_bus_bint10_n = BINT10_n & s_dev_bint10_n;
wire s_bus_bint11_n = BINT11_n & s_dev_bint11_n;
wire s_bus_bint12_n = BINT12_n & s_dev_bint12_n;
wire s_bus_bint13_n = BINT13_n & s_dev_bint13_n;
/**********************************************
* The BACKPLANE back-wiring PROM *
***********************************************/
// Deliberately placed HERE, on the backplane side of the B-plug, not inside
// ND3202D: on the real machine the PROM is part of the back wiring, the CPU
// board only drives PIL[3:0] OUT to the B-plug and takes the byte back IN on
// INR_7_0. ND120_CORE is the first level above the CPU board and already
// owns the other B-plug constants (EBUS, SEL5MS_n), so this is the exact
// level the PROM belongs at. Nothing inside CPU-BOARD-3202 changes.
//
// The address is PIL[3:0] - STRONG INFERENCE, not read from a backplane
// schematic (none was found). Reasoning in BACKWIRING_PROM.v's header and in
// docs/backwiring-prom-installation-number.md.
BACKWIRING_PROM #(
.SYSNO (SYSNO), // bytes 0/1 - CPU NUMBER
.HWINFO2(HWINFO2), // bytes 2/3 - CPU TYPE
.NLEGU (NLEGU) // byte 4 - number of legal users
) BACKPLANE_INR_PROM (
.PIL_3_0(PIL), // the same nibble the CPU board drives to the B-plug
.INR_7_0(installation_number) // back in on INR 7:0
);
/**********************************************
* The CPU board *
***********************************************/
ND3202D CPU_BOARD (
`ifdef ND120_ERRFA_PROBE
.ERRFA_CONTX(ERRFA_CONTX),
.ERRFA_TXD(ERRFA_TXD),
`endif
.sysclk(clk_cpu), // CPU core, OSC and bus all share one domain
.sys_rst_n(sys_rst_n),
.CLOCK_1(clk_cpu), // XTAL1 = 39.3216MHZ on the real board
.CLOCK_2(clk_cpu), // XTAL2 = 35 MHZ (for slow operations?)
// Signal from C-PLUG to CPU Board (and some signals duplicated on A-PLUG)
.LOAD_n(s_high), // Load button C-B12, A-C15
.BREQ_n(s_bus_breq_n), // Bus Request C-C12 (wired-AND with DMA masters)
.CONTINUE_n(s_high), // Continue button C-B15
.STOP_n(s_high), // Stop button C-B16, A-C17
.BINT10_n(s_bus_bint10_n), // Bus Interrupt 10 C-A15 (wired-AND with Verilog devices)
.BINT11_n(s_bus_bint11_n), // Bus Interrupt 11 C-C15
.BINT12_n(s_bus_bint12_n), // Bus Interrupt 12 C-A16
.BINT13_n(s_bus_bint13_n), // Bus Interrupt 13 C-C16
.BINT15_n(BINT15_n), // Bus Interrupt 15 C-C17
.POWSENSE_n(POWSENSE_n), // Power Sense
.BD_23_0_n_IN(s_bus_bd_in_n), // Bus address and data from bus (wired-AND with Verilog devices)
.BD_23_0_n_OUT(BD_23_0_n_OUT),
// Bidirectional signals
.SEMRQ_n_IN(SEMRQ_n_IN), //! Input-signal from "C PLUG", signal A17 SEMREQ~ (SEMaphore REQest)
.SEMRQ_n_OUT(SEMRQ_n_OUT), //! Output-signal to "C PLUG", signal A17 SEMREQ~ (SEMaphore REQest)
.BINPUT_n_IN(s_bus_binput_in_n), //! Input-signal from "C PLUG", signal A18 BINPUT~ (Bus INPUT)
.BINPUT_n_OUT(BINPUT_n_OUT), //! Output-signal to "C PLUG", signal A18 BINPUT~ (Bus INPUT)
.BDAP_n_IN(s_bus_bdap_in_n), //! Input-signal from "C PLUG", signal C18 BDAP~ (Bus DAta Present)
.BDAP_n_OUT(BDAP_n_OUT), //! Output-signal to "C PLUG", signal C18 BDAP~ (Bus DAta Present)
.BDRY_n_IN(s_bus_bdry_in_n), //! Input-signal from "C PLUG", signal A19 BDRY~ (Bus Data ReadY)
.BDRY_n_OUT(BDRY_n_OUT), //! Output-signal to "C PLUG", signal A19 BDRY~ (Bus Data ReadY)
.BAPR_n_IN(s_bus_bapr_in_n), //! Input-signal from "C PLUG", signal A20 BAPR~ (Bus Address PResent)
.BAPR_n_OUT(BAPR_n_OUT), //! Output-signal to "C PLUG", signal A20 BAPR~ (Bus Address PResent)
// Signals from CPU board to C-PLUG
.BREF_n(BREF_n), // Output-signal to "C PLUG", signal B12 BREF~
.BERROR_n(BERROR_n), // Output-signal to "C PLUG", signal B21 BERROR~
.BINACK_n(BINACK_n), // Output-signal to "C PLUG", signal B19 BINACK~
.BIOXE_n(BIOXE_n), // Output-signal to "C PLUG", signal C19 BIOXE~
.BMEM_n(BMEM_n), // Output-signal to "C PLUG", signal C28 BMEM~
.OUTGRANT_n(OUTGRANT_n), // Output-signal to "C PLUG", signal C23 OUTGRANT~
.OUTIDENT_n(OUTIDENT_n), // Output-signal to "C PLUG", signal C22 OUTIDENT~
.MCL(MCL), // Output-signal to "C PLUG", signal B20 MCL~ (after negation)
// Signals from B-PLUG to CPU Board
.INR_7_0(installation_number), // INR 7:0, signal B-> B15, B4, B5, B17, B8, B7, B13, B6. (Installation number, read using IDB Source = 035)
// Driven by BACKPLANE_INR_PROM above (16-byte back-wiring PROM addressed by PIL 3:0)
.EBUS(1'b1), // EBUS, signal B-B3 (Pulled high with through resistor network RN13)
.SEL5MS_n(1'b1), // SEL 5ms, signal B-B14 (Pulled high with 1kohm resistor R4)
// Signals from CPU to B-PLUG
.PIL(PIL), // XPIL3=B-C8, PIL2=B-B12. PIL1=B-B10, PIL0=B-B9
.LUA_12_0(), // XLUA 12:0
.IDB_15_0(), // XIDB 15:0
.CSCOMM_4_0(), //
.MIS_1_0(), // MIS1=B-C14, MIS0=B-A14
.CD_15_0(), // CD 15:0
.LBD_15_0(), // LBD 15:0
.LA_23_10(LA_23_10), // XLA 23:10 (MAC upper address)
.CA_9_0(CA_9_0), // CA 9:0 (MAC lower address)
// Signals from A-PLUG to CPU board
.OSCCL_n (s_high), // Oscillator Clock
.OC_1_0 (oc_select), // Oscillator Clock Select
.XTR (s_low), // External Transmit/Receive Clock (not used)
.LOCK_n (s_high), // Lock signal (from key)
.CONSOLE_n(s_high), // Console signal (from key)
.SWMCL_n (s_high), // Software Master Clear (MCL)
.EAUTO_n (s_high), // External Auto
.RXD (RXD), // UART Receive A-C8
// Signals from CPU Board to C-PLUG
.RUN_n (RUN_n), // Run C-B14 (driven by Stop flip-flop: low while CPU is running)
// Signals from CPU Board to A-PLUG
.TXD (TXD), // UART Transmit TXD A-C7
.DP_5_1_n (s_dp_5_1_n), // Data Path 5-1 A-> 1=C25, 2=C26, 3=C27, 4=C28, 5=C29
/* Configuration switches (input to ND3202D board) */
.SW1_CONSOLE (CACHE_SW), // Console SW1 = cache on/off, from the board top
.SEL_TESTMUX (s_SEL_TESTMUX), // Test MUX (select signals to test pads)
.BAUD_RATE_SWITCH(s_baud_rate_switch), // Baud rate switch (microcode thumbwheel, fixed 9600)
.BAUD_9600(BAUD_9600), // runtime SC2661 line-speed select
// outputs
.CSBITS (s_csbits), // Microcode CPU BITS
.TEST_4_0 (s_test_4_0), // Test pads
.TP1_INTRQ_n(s_tp1_intrq_n), // TP1 Interrupt
.CSA_12_0 (CSA_12_0), // Microcode Address (for debugging)
.LED (LED[6:0]), // 7 bit LED signals
.DEBUG_CC_TERM(DEBUG_CC_TERM), // {TERM_n, CC3_n, CC2_n, CC1_n, CC0_n}
.DEBUG_MCLK(DEBUG_MCLK), // Microcycle clock
.DEBUG_LCS_n(DEBUG_LCS_n), // LCS_n: 0=loading, 1=loaded
.DEBUG_FETCH(DEBUG_FETCH),
.DEBUG_MAP_n(DEBUG_MAP_n),
.DEBUG_CFETCH(DEBUG_CFETCH),
.DEBUG_MR_n(DEBUG_MR_n),
.DEBUG_CLEAR_n(DEBUG_CLEAR_n),
.DEBUG_REFRQ_n(DEBUG_REFRQ_n),
.DEBUG_INTRQ_n(DEBUG_INTRQ_n),
.DEBUG_POWFAIL_n(DEBUG_POWFAIL_n),
.DEBUG_FIDBO_15_0(DEBUG_FIDBO_15_0),
.DEBUG_IREQ_15_0_N(DEBUG_IREQ_15_0_N),
.XMIC_DBG_15_0(XMIC_DBG_15_0),
.XWRFB_DBG_19_0(XWRFB_DBG_19_0),
.XCYC_DBG_7_0(XCYC_DBG_7_0),
.DBG_PTW_LVL(DBG_PTW_LVL),
.DBG_PANEL (DBG_PANEL),
.PANEL_ACTLV(PANEL_ACTLV),
.DBG_CACHE (DBG_CACHE)
`ifdef MAIN_RAM_SDRAM
// SDRAM main memory (threaded down to MEM_43 -> MEM_RAM_49_SDRAM)
,
.clk2x(clk2x),
.clk2x_sdram(clk2x_sdram),
.O_sdram_clk(O_sdram_clk),
.O_sdram_cke(O_sdram_cke),
.O_sdram_cs_n(O_sdram_cs_n),
.O_sdram_cas_n(O_sdram_cas_n),
.O_sdram_ras_n(O_sdram_ras_n),
.O_sdram_wen_n(O_sdram_wen_n),
.IO_sdram_dq(IO_sdram_dq),
.O_sdram_addr(O_sdram_addr),
.O_sdram_ba(O_sdram_ba),
.O_sdram_dqm(O_sdram_dqm),
.DBG_MEMW(DBG_MEMW),
.DBG_PTW(DBG_PTW),
.PF_CAPTURED(PF_CAPTURED),
.DBG_PPN(DBG_PPN),
.DBG_PGW(DBG_PGW)
`ifdef ND_STORAGE_PORT
,
.stor_clk (stor_clk),
.stor_rst_n(stor_rst_n),
.mem_start (mem_start),
.mem_we (mem_we),
.mem_addr (mem_addr),
.mem_wdata (mem_wdata),
.mem_rdata (mem_rdata),
.mem_busy (mem_busy),
.mem_done (mem_done)
`endif
`endif
`ifdef MAIN_RAM_DDR2
,
.ui_clk(ui_clk),
.ui_rst(ui_rst),
.mm_req_valid(mm_req_valid),
.mm_req_we(mm_req_we),
.mm_req_addr(mm_req_addr),
.mm_req_wdata(mm_req_wdata),
.mm_req_wmask(mm_req_wmask),
.mm_req_ready(mm_req_ready),
.mm_rsp_valid(mm_rsp_valid),
.mm_rsp_rdata(mm_rsp_rdata),
.DBG_DDR2_BRIDGE(DBG_DDR2_BRIDGE)
`endif
);
endmodule