Skip to content

PAL_44801A

Source: Verilog/PAL/PAL_44801A.v

Where it sits (Simulation): ND120_TOP > ND120_CORE > ND3202D > BIF_5 > BIF_BCTL_6 > PAL_44801A - instance path: CORE.CPU_BOARD.BIF.BCTL.PAL_44801_UBARB

Used in: BIF_BCTL_6 (all tops)

Contains: no other modules.

Module hierarchy - All modules

PAL_44801A symbol

Schematic

Drawn from the Verilog: the yosys netlist of the Simulation (Verilator) build, instance CORE.CPU_BOARD.BIF.BCTL.PAL_44801_UBARB. 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).

PAL_44801A schematic

Description

ND120 PALASM CODE CONVERTED TO VERILOG Component PAL 44801A Last reviewed: 22-MAR-2025 Ronny Hansen

Ports

Direction Width Name Description
input 1 CK Clock signal
input 1 OE_n (active low) OUTPUT ENABLE (active-low) for Q0-Q5
input 1 CRQ_n (active low) I0 - CRQ_n (CPU Request)
input 1 IORQ_n (active low) I1 - IORQ_n (IO Request)
input 1 MR_n (active low) I2 - MR_n (Master Reset)
input 1 BRQ50_n (active low) I3 - BRQ50_n (Bus Request (50ns delayed))
input 1 REFRQ50_n (active low) I4 - REFRQ50_n (Refresh Request (50ns delayed))
input 1 BDRY25_n (active low) I5 - BDRY25_n (Bus Data Ready (25ns delayed))
input 1 SEMRQ50_n (active low) I6 - SEMRQ50_n (Semaphore Request (50ns delayed))
input 1 MOFF_n (active low) I7 - MOFF_n (not used) (Memory OFF)
output 1 SEM_n (active low) Q0_n - SEM_n (SEMAPHORE GRANT SIGNAL)
output 1 ACT_n (active low) Q1_n - ACT_n (n.c.) (BUS IS ACTIVE)
output 1 DOREF_n (active low) Q2_n - DOREF_n (n.c.) (INDICATES THAT LAST BUS CYCLE WAS A REFRESH)
output 1 MEM_n (active low) Q3_n - MEM_n (n.c.) (MEM SIGNAL TO LAST FOR ENTIRE BUS CYCLE)
output 1 REF_n (active low) Q4_n - REF_n (REFRESH GRANT ON ND100 BUS)
output 1 IOD_n (active low) Q5_n - IOD_n (IO SIGNAL TO LAST FOR THE ENTIRE BUS CYCLE)
output 1 GNT_n (active low) Q6_n - GNT_n (GRANT ND100 BUS TO A DMA DEVICE OR EXTERNAL BUS CONTROLLER)
output 1 CACT_n (active low) Q7_n - CACT_n (CPU IS ACTIVE ON THE ND100 BUS)

Verilog source

Verilog/PAL/PAL_44801A.v on GitHub.

Show the Verilog of PAL_44801A (188 lines)
/**********************************************************************************************************
** ND120 PALASM CODE CONVERTED TO VERILOG                                                                **
**                                                                                                       **
** Component PAL 44801A                                                                                  **
**                                                                                                       **
** Last reviewed: 22-MAR-2025                                                                            **
** Ronny Hansen                                                                                          **
***********************************************************************************************************/

// PAL16R8
// JLB/CJTC 11AUG86
// 44801A,10D, BARB

//  CYCLE CONTROL STATE COUNTER. FAST VERSION (ND-120/CX).

// PAL16R8 FAMILY
// PAL16R6 has 6 flip-flips, 8 inputs, and 2 input OR output (B0 and B1)

// https://rocelec.widen.net/view/pdf/c6dwcslffz/VANTS00080-1.pdf



// PCB 3202D sheet 6:
//
// PAL input signal PD3 is connected to PAL OE_n pin
//     input signal OSC is connectec to PAL CK pin


module PAL_44801A (
    input CK,   //! Clock signal
    input OE_n, //! OUTPUT ENABLE (active-low) for Q0-Q5 

    input CRQ_n,      //! I0 - CRQ_n (CPU Request)
    input IORQ_n,     //! I1 - IORQ_n (IO Request)
    input MR_n,       //! I2 - MR_n (Master Reset)
    input BRQ50_n,    //! I3 - BRQ50_n (Bus Request (50ns delayed))
    input REFRQ50_n,  //! I4 - REFRQ50_n (Refresh Request (50ns delayed))
    input BDRY25_n,   //! I5 - BDRY25_n (Bus Data Ready (25ns delayed))
    input SEMRQ50_n,  //! I6 - SEMRQ50_n (Semaphore Request (50ns delayed))
    input MOFF_n,     //! I7 - MOFF_n  (not used) (Memory OFF)

    output SEM_n,    //! Q0_n - SEM_n  (SEMAPHORE GRANT SIGNAL)
    output ACT_n,    //! Q1_n - ACT_n (n.c.) (BUS IS ACTIVE)
    output DOREF_n,  //! Q2_n - DOREF_n (n.c.) (INDICATES THAT LAST BUS CYCLE WAS A REFRESH)
    output MEM_n,    //! Q3_n - MEM_n (n.c.) (MEM SIGNAL TO LAST FOR ENTIRE BUS CYCLE)
    output REF_n,    //! Q4_n - REF_n  (REFRESH GRANT ON ND100 BUS)
    output IOD_n,    //! Q5_n - IOD_n  (IO SIGNAL TO LAST FOR THE ENTIRE BUS CYCLE)
    output GNT_n,    //! Q6_n - GNT_n  (GRANT ND100 BUS TO A DMA DEVICE OR EXTERNAL BUS CONTROLLER)
    output CACT_n    //! Q7_n - CACT_n (CPU IS ACTIVE ON THE ND100 BUS)

);

  // Internal registers
  reg  SEM_reg;
  reg  ACT_reg;
  reg  DOREF_reg;
  reg  MEM_reg;
  reg  REF_reg;
  reg  IOD_reg;
  reg  GNT_reg;
  reg  CACT_reg;

  // negated input signals
  wire CRQ = ~CRQ_n;
  wire IORQ = ~IORQ_n;
  wire MR = ~MR_n;
  wire BRQ50 = ~BRQ50_n;
  wire REFRQ50 = ~REFRQ50_n;
  wire BDRY25 = ~BDRY25_n;
  wire SEMRQ50 = ~SEMRQ50_n;

  // Negated reg signals as wires

  wire SEM = SEM_reg;
  wire DOREF = DOREF_reg;
  wire MEM = MEM_reg;
  wire REF = REF_reg;
  wire IOD = IOD_reg;
  wire GNT = GNT_reg;
  wire CACT = CACT_reg;


  //**** Sequential logic triggered on the rising edge of CLK ****
  always @(posedge CK) begin

    // CACT - CPU IS ACTIVE ON THE ND100 BUS
    // Priority-2 term ("CPU request AFTER a refresh") uses DOREF (active-high),
    // NOT DOREF_n. This is the toggled-priority tie-breaker for a simultaneous
    // CPU + DMA request: CACT term 2 fires on DOREF (last cycle was refresh) and
    // GNT term 2 fires on /DOREF (below), so the two are COMPLEMENTARY and
    // exactly one master wins - the bus can never be granted to both at once.
    // FIXED 20-JUL-2026: this term was transcribed as DOREF_n, which made it
    // identical to GNT's /DOREF term, so on DOREF=0 BOTH CACT and GNT set and
    // the CPU ran an IOX cycle on top of a held external DMA grant. Corrected to
    // match the original PALASM: DesignDocuments/PAL-Code/SRC/44801A.txt:11
    // (`CRQ * /REFRQ50 * DOREF * /REF * /GNT * /SEM * /BDRY25 * /MR ; 2`).
    CACT_reg <=
                    (CRQ  & REFRQ50_n & BRQ50_n & REF_n & GNT_n & SEM_n & BDRY25_n & MR_n)  // 4
                  | (CRQ  & REFRQ50_n & DOREF   & REF_n & GNT_n & SEM_n & BDRY25_n & MR_n)  // 2
                  | (CACT & BDRY25_n & MR_n)  // HOLD
                  | (CRQ  & SEM & GNT_n & BDRY25_n & MR_n);  // SEMAPHORE

    // REF - REFRESH GRANT ON ND100 BUS
    REF_reg <= (REFRQ50 & CACT_n & GNT_n & SEM_n & BDRY25_n)  // 1
    | (REF & BDRY25_n)  // HOLD
    | (REFRQ50 & MR);  // ALWAYS GRANT REFRESH DURING MR

    // GNT - GRANT ND100 BUS TO A DMA DEVICE OR EXTERNAL BUS CONTROLLER
    GNT_reg <= (BRQ50 & REFRQ50_n & CRQ_n & REF_n & CACT_n & SEM_n & BDRY25_n & MR_n)  // 3
    | (BRQ50 & REFRQ50_n & DOREF_n & REF_n & CACT_n & SEM_n & BDRY25_n & MR_n)  // 3
    | (GNT & BDRY25_n & MR_n)  // HOLD
    | (BRQ50 & SEM & GNT & MR_n);  // SEMAPHORE

    // IOD - IO SIGNAL TO LAST FOR THE ENTIRE BUS CYCLE
    // FIXED 20-JUL-2026: term 2 ("IOX after a refresh") had TWO transcription
    // errors vs the original PALASM (44801A.txt:31,
    // `IORQ * CRQ * /REFRQ50 * DOREF * /REF * /GNT * /SEM * /BDRY25 * /MR ; 2`):
    // DOREF_n should be DOREF (same inversion as the CACT double-grant bug), and
    // the final term was ~MR_n where PALASM has /MR = MR_n. As written the term
    // could only fire during master reset (MR active) - i.e. it was dead in
    // normal operation, so an IOX right after a refresh never latched IOD via
    // this path. Restored to match PALASM.
    IOD_reg <= (IORQ & CRQ & REFRQ50_n & BRQ50_n & REF_n & GNT_n & SEM_n & BDRY25_n & MR_n)  // 4
    | (IORQ & CRQ & REFRQ50_n & DOREF   & REF_n & GNT_n & SEM_n & BDRY25_n & MR_n)  // 2
    | (IOD & BDRY25_n & MR_n)  // HOLD
    | (IORQ & CRQ & SEM & GNT_n & BDRY25_n & MR_n);  // SEMAPHORE

    // MEM - MEM SIGNAL TO LAST FOR ENTIRE BUS CYCLE
    // GENERATES BMEM WHICH IS PRESENT ON REFRESH, CPU MEMORY AND DMA CYCLES
    MEM_reg <=
     (BRQ50 & IORQ_n   & IOD_n & BDRY25_n & MR_n)
             | (BRQ50 & CRQ_n    & IOD_n & BDRY25_n & MR_n)
             | (BRQ50 & DOREF_n  & IOD_n & BDRY25_n & MR_n)
             | (CRQ   & IORQ_n   & IOD_n & BDRY25_n & MR_n)
             | (REFRQ50          & IOD_n & BDRY25_n)
             | (REFRQ50 & MR)
             | (MEM & BDRY25_n & MR_n);

    // SEM - SEMAPHORE GRANT SIGNAL
    SEM_reg <= (SEMRQ50 & MR_n & BDRY25) | (SEM & MR_n & ACT_n);

    // ACT - BUS IS ACTIVE
    ACT_reg <= (CACT & BDRY25_n & MR_n) | (GNT & BDRY25_n & MR_n) | (REF & BDRY25_n & MR_n);

    // DOREF - INDICATES THAT LAST BUS CYCLE WAS A REFRESH
    // FIXED 20-JUL-2026: the HOLD term was inverted. PALASM (44801A.txt:60,
    // `DOREF * /MR * /CACT * /GNT * /REF`) holds DOREF while CACT, GNT and REF
    // are all INACTIVE (i.e. between the refresh and the next real cycle), so
    // the "last cycle was refresh" flag survives until the CPU/DMA takes its
    // turn - that is what carries the toggled-priority tie-break. The Verilog
    // used ~CACT_n & ~GNT_n & ~REF_n = CACT & GNT & REF (all ACTIVE at once),
    // which is impossible, so the term was always 0 and DOREF never held -
    // it only pulsed for one cycle after a refresh. Restored to /CACT /GNT /REF
    // = CACT_n & GNT_n & REF_n.
    DOREF_reg <= (REF & ~MR & BDRY25) | (DOREF & ~MR & CACT_n & GNT_n & REF_n);

  end

  // Tri-state control for Q outputs
  // Assigning outputs with three-state logic controlled by OE_n
  assign SEM_n   = OE_n ? 1'b0 : ~SEM_reg;
  assign ACT_n   = OE_n ? 1'b0 : ~ACT_reg;
  assign DOREF_n = OE_n ? 1'b0 : ~DOREF_reg;
  assign MEM_n   = OE_n ? 1'b0 : ~MEM_reg;
  assign REF_n   = OE_n ? 1'b0 : ~REF_reg;
  assign IOD_n   = OE_n ? 1'b0 : ~IOD_reg;
  assign GNT_n   = OE_n ? 1'b0 : ~GNT_reg;
  assign CACT_n  = OE_n ? 1'b0 : ~CACT_reg;


endmodule

/*

DESCRIPTION

; PRIORITY:
;           1. REFRESH
:           2. CPU REQUEST AFTER A REFRESH
;           3. BUS REQUEST
;           4. CPU REQUEST

; 26/2-87JLB: WRONG HOLD TERM IN IOD.
;
; 180587 M3202B

*/