// http://neil.franklin.ch/Projects/PDP-10/pdp10.java
//   - PDP-10 clone microprocessor, main (and presently only) source file
// author Neil Franklin, last modification 2001.05.16


// ------ prerequisites section

// to understand this code you should
//   understand the basics of
//     designing logic circuits, such as with [74|74LS|74F]xx(x)
//     how a computer/processor executes machine code
//     basics of how programmable logic, particularly FPGA logic, works
//   have read the specifics from the
//     Xilinx Virtex data sheet http://www.xilinx.com/partinfo/ds003.pdf
//     Xilinx JBits docs (with software, mail jbits@xilinx.com for URL/passwd)
//     PDP-10 reference manual http://www.36bit.org/dec/manual/ad-h391a-t1.pdf


// ------ program status section

// finished implemented are so far:
// LUT logic and place-and-routing of
//   data path and control circuits and state machine for:
// memory (32 words 00..1F) and its address and data write muxes
// program counter and incrementer and its load mux
// instruction register and instruction load
// memory address register and E calculation consuming IR.X and IR.I
// arithmetic register and its load mux and write back to memory
// 100ffffmm boolean logic instructions, all 16 with with all 4 modes


// ------ import section

import java.lang.*;
import java.io.*;
import java.util.*;

import com.xilinx.JBits.Virtex.Bitstream;
import com.xilinx.JBits.Virtex.JBits;
import com.xilinx.JBits.Virtex.Devices;
import com.xilinx.JBits.Virtex.ConfigurationException;

import com.xilinx.JBits.Virtex.Bits.LUT;
import com.xilinx.JBits.Virtex.Bits.S0Control;
import com.xilinx.JBits.Virtex.Bits.S0Clk;
import com.xilinx.JBits.Virtex.Bits.S0RAM;

import com.xilinx.JBits.Virtex.Util;

import com.xilinx.JBits.CoreTemplate.Pin;
import com.xilinx.JBits.Virtex.RTPCore.Tags;
import com.xilinx.JRoute2.Virtex.JRoute;
import com.xilinx.JRoute2.Virtex.ResourceDB.CenterWires;
import com.xilinx.JRoute2.Virtex.RouteException;


// ------ Java/JBits startup/shutdown overhead section

public class pdp10 {

  public static JBits Fpga;

  public static JRoute Router;

  public static void main(String args[]) {

    // set up what we are going to do
    String DeviceName = "XCV300";
    String InFileName = "/usr/local/JBits/data/Bitstream/XCV300/null300.bit";
    String OutFileName = "pdp10.bit";

    // get the device type
    int DeviceType = Devices.getDeviceType(DeviceName);
    if (DeviceType == Devices.UNKNOWN_DEVICE) {
      System.out.println("Did not recognize device type " + DeviceName);
      System.exit(-2); }
    // test if the device is supported
    if (Devices.isSupported(DeviceType) == false) {
      System.out.println("Unsupported device type. Exiting");
      System.exit(-3); }
    // initialise device storage
    Fpga = new JBits(DeviceType);

    // and make using the router possible
    Router = new JRoute(Fpga);

    // read the bitstream
    System.out.println("reading in " + InFileName + " ...");
    try {
      Fpga.read(InFileName); }
    catch (FileNotFoundException Fe) {
      System.out.println("File " + InFileName + " not found");
      System.out.println(Fe); }
    catch (IOException Io) {
      System.out.println("Error reading the bitstream file");
      System.out.println(Io); }
    catch (ConfigurationException Ce) {
      System.out.println("Internal error detected in the Bitstream");
      System.out.println(Ce); }

    // modify the bitstream
    System.out.println("modifying bits ...");
    pdp10();

    // write the bitstream
    System.out.println("writing out " + OutFileName + " ...");
    try {
      Fpga.write(OutFileName); }
    catch (IOException Io) {
      System.out.println("Error writing the bitstream file");
      System.out.println(Io); } }


// ------ auxilary code section

  // set LUTs faster than com.xilinx.JBits.Virtex.Expr, as no run time parsing
  // also no parse errors to test and trap for, and not F/G dependant

  // bit patterns for out = in<n>, for n=1..4, use Java ~&|^ to combine them
  final public static int I1 = 0xAAAA, I2 = 0xCCCC, I3 = 0xF0F0, I4 = 0xFF00;

  // just to save code size and make source more readable
  public static int[] L(int Pattern) {
    return (Util.InvertIntArray(Util.IntToIntArray(Pattern, 16))); }


// ------ actual PDP-10 implementation sections from here on

  public static void pdp10() {

    try {


// ------ debugging

      // drive various FFs, for debugging display in BoardScope/DeviceSimulator
      // do not drive them in production systems, to reduce heat generation
      final int DebugDisp = 1;

      // prevent writing of RAM, making it ROM, so no tracking changes
      final int DebugMemROM = 0;


// ------ setting up the basics section

      // some usefull index variables for computing placing
      int Bit = 0, Row = 0, Col = 0;
      // cut&paste the next line (without //) for debugging output
      //System.out.println("Bit " + Bit + " Col " + Col + " Row " + Row);

      // index variable for tagging parts of the chip
      int Tag = Tags.USER_TAG_START;

      // PDP-10 system constants
      // data and address bus widths
      int DataBits = 36, AddrBits = 18;
      // PDP-10 is big endian, so data bits are numbered MSB as 0 and LSB as 35
      int DataMSB = 0, DataLSB = DataBits-1;
      // operators console panel shows address numbered MSB as 18 and LSB as 35
      int AddrMSB = DataMSB+(DataBits-AddrBits), AddrLSB = DataLSB;

      // entire system, placing starts at bottom/left point of FPGA
      // each section reserves space by calculating new Col/Row
      int SysCol = 0; int SysRow = 0;
      System.out.println("system base at " + SysCol + "|" + SysRow);

      // processor, place in device, all proc circuits rel to this point
      int ProcCol = SysCol; int ProcRow = SysRow;
      System.out.println("processor base at " + ProcCol + "|" + ProcRow);

      // data path, place in proc, all data path circuits rel to this
      // Xilinx south->north carry chains and my south->north row allocation
      //   result in building data bath LSB->MSB, Bit 35->0, decrementing
      // uses 36/2=18 CLB rows, Row 0 bit 35 and 34 .. Row 17 bit 1 and 0
      int PathCol = ProcCol; int PathRow = ProcRow;
      System.out.println("data path base at " + PathCol + "|" + PathRow);
      // reserve space for data path, 1 CLB row per 2 bits
      ProcRow += DataBits/2;

      // control logic, place in proc, all control elements rel to this
      int CtrlCol = ProcCol; int CtrlRow = ProcRow;
      System.out.println("control logic base at " + CtrlCol + "|" + CtrlRow);
      // unknown hight, use rest of device, so no space reservation here


// ------ memory section

      // 32 words, 36 x 2 LUT-RAMs, so Col 0 bit 35/33/.., Col 1 bit 34/32/..
      //   2 columns and NOT 2 slices, because only 1 TBUF readback per CLB
      //   this may change if I give up entirely on using TBUFs, likely
      Col = PathCol; Row = PathRow;
      PathCol += 2;
      System.out.print("memory at " + Col + "|" + Row);

      // duplicate 35..32 address definitions because actually 2* 16word memory
      Pin MemAddr35F[] = new Pin[DataBits], MemAddr35G[] = new Pin[DataBits],
          MemAddr34F[] = new Pin[DataBits], MemAddr34G[] = new Pin[DataBits],
          MemAddr33F[] = new Pin[DataBits], MemAddr33G[] = new Pin[DataBits],
          MemAddr32F[] = new Pin[DataBits], MemAddr32G[] = new Pin[DataBits],
          MemAddr31[] = new Pin[DataBits], MemIn[] = new Pin[DataBits],
          MemWrEn[] = new Pin[DataBits], MemOut[] = new Pin[DataBits];
      String MemFileName = "pdp10.mem";
      String MemWord[] = new String[32];
      int MemLUT;

      // load program and data into memory, from file pdp10.mem
      // containing 32 lines of 1 word per line, as 36 char 0/1 ASCII string
      try {
        BufferedReader MemFile =
          new BufferedReader(new FileReader(MemFileName));
        for (int Line = 0; Line < 32; Line++) {
          // defend against too short file
          MemWord[Line] = "000000000000000000000000000000000000";
          String MemLine;
          if ((MemLine = MemFile.readLine()) != null) {
            // defend against too short line
            MemLine = MemLine+"000000000000000000000000000000000000";
            MemLine = MemLine.substring(0, DataBits);
            MemWord[Line] = MemLine; } }
        MemFile.close(); }
      catch (FileNotFoundException Fe) {
        System.out.println("File " + MemFileName + " not found");
        System.out.println(Fe); }
      catch (IOException Io) {
        System.out.println("Error reading the memory file");
        System.out.println(Io); }

      for (Bit = DataLSB; Bit >= DataMSB; Bit--) {
        MemAddr35F[Bit] = new Pin(Pin.CLB, Row, Col, CenterWires.S0_F1);
        MemAddr35G[Bit] = new Pin(Pin.CLB, Row, Col, CenterWires.S0_G1);
        MemAddr34F[Bit] = new Pin(Pin.CLB, Row, Col, CenterWires.S0_F2);
        MemAddr34G[Bit] = new Pin(Pin.CLB, Row, Col, CenterWires.S0_G2);
        MemAddr33F[Bit] = new Pin(Pin.CLB, Row, Col, CenterWires.S0_F3);
        MemAddr33G[Bit] = new Pin(Pin.CLB, Row, Col, CenterWires.S0_G3);
        MemAddr32F[Bit] = new Pin(Pin.CLB, Row, Col, CenterWires.S0_F4);
        MemAddr32G[Bit] = new Pin(Pin.CLB, Row, Col, CenterWires.S0_G4);
        MemAddr31[Bit] = new Pin(Pin.CLB, Row, Col, CenterWires.S0_BX);
        MemIn[Bit] = new Pin(Pin.CLB, Row, Col, CenterWires.S0_BY);
        MemWrEn[Bit] = new Pin(Pin.CLB, Row, Col, CenterWires.S0_CE);
        Fpga.set(Row, Col, S0Clk.S0Clk, S0Clk.GCLK1);
        // convert memory words to memory LUTs
        MemLUT = 0;
        for (int Line = 15; Line >= 0; Line--) {
          char MemBitChar = MemWord[Line].charAt(Bit);
          int MemBit = (MemBitChar == '1') ? 1 : 0;
          // shift in bit from LSB of LUT
          MemLUT = MemLUT*2+MemBit; }
        Fpga.set(Row, Col, LUT.SLICE0_F, L(MemLUT));
        MemLUT = 0;
        for (int Line = 31; Line >= 16; Line--) {
          char MemBitChar = MemWord[Line].charAt(Bit);
          int MemBit = (MemBitChar == '1') ? 1 : 0;
          MemLUT = MemLUT*2+MemBit; }
        Fpga.set(Row, Col, LUT.SLICE0_G, L(MemLUT));
        // switch LUT pairs to be 32bit LUT-RAMs, writable, BX selected
        Fpga.set(Row, Col, S0RAM.DUAL_MODE, S0RAM.ON);
        Fpga.set(Row, Col, S0RAM.F_LUT_RAM, S0RAM.ON);
        Fpga.set(Row, Col, S0RAM.G_LUT_RAM, S0RAM.ON);
        Fpga.set(Row, Col, S0RAM.LUT_MODE, S0RAM.OFF);
        Fpga.set(Row, Col, S0RAM.RAM_32_X_1, S0RAM.ON);
        Fpga.set(Row, Col, S0Control.X.X, S0Control.X.F5);
        // invert BX, because F5-Mux is 0/1:G/F
        Fpga.set(Row, Col, S0Control.BxInvert, S0Control.ON);
        if (DebugDisp == 1) {
          // XQ shows old memory content, YQ shows MemIn
          Fpga.set(Row, Col, S0Control.YDin.YDin, S0Control.YDin.BY); }
        MemOut[Bit] = new Pin(Pin.CLB, Row, Col, CenterWires.S0_X);
        // allways tag after defining each LUT
        Fpga.setTag(Row, Col, Tag);
        // zigzag placing, first time to next Col, then Col back and next Row
        Col = Bit%2==1 ? Col+1 : Col-1; Row = Bit%2==1 ? Row : Row+1; }

      // and use next tag number for control circuits
      Tag += 1;
      System.out.print(".." + (Row-1));

      // control names and logic equations are derived from ../Time-States
      // control ClkE-Mem = logac|logmem
      //   this will grow with other instruction groups adding states
      Pin MemClkELogAc = new Pin(Pin.CLB, Row, Col, CenterWires.S0_F1);
      Pin MemClkELogMem = new Pin(Pin.CLB, Row, Col, CenterWires.S0_F2);
      if (DebugMemROM == 1) {
        Fpga.set(Row, Col, LUT.SLICE0_F, L(0x0000)); }
      else {
        Fpga.set(Row, Col, LUT.SLICE0_F, L(I1|I2)); }
      Pin MemClkE = new Pin(Pin.CLB, Row, Col, CenterWires.S0_X);
      Router.route(MemClkE, MemWrEn);
      Fpga.setTag(Row, Col, Tag);
      Row++;

      Tag += 1;
      System.out.println(",c.." + (Row-1));


// ------ memory data mux section

      // not yet needed, memory momentally only written from AR, so no circuits
      //Col = PathCol; Row = PathRow;
      //PathCol += 0;
      //System.out.print("memory data write mux at " + Col + "|" + Row);

      // control MD-Mux=AR = logac|logmem
      //   this will grow with other instruction groups adding states

      //Tag += 1;
      //System.out.print(".." + (Row-1));

      //Tag += 1;
      //System.out.println(",c.." + (Row-1));


// ------ memory address mux section

      // in from PC or MA or IR.X or IR.AC - 4:1-Mux with 4 separate enables
      // wideOR of 2 LUTs 2AND+OR, so Col 0 bit 35/33/.., Col 1 bit 34/32/..
      Col = PathCol; Row = PathRow;
      PathCol += 2;
      System.out.print("memory address mux at " + Col + "|" + Row);

      Pin MamIRX[] = new Pin[DataBits], MamIRXEn[] = new Pin[DataBits],
          MamIRAC[] = new Pin[DataBits], MamIRACEn[] = new Pin[DataBits],
          MamPC[] = new Pin[DataBits], MamPCEn[] = new Pin[DataBits],
          MamMA[] = new Pin[DataBits], MamMAEn[] = new Pin[DataBits],
          MamOut[] = new Pin[DataBits];

      for (Bit = DataLSB; Bit >= DataMSB; Bit--) {
        // for lowest 4 bits all 4 inputs, addressable by AC or X fields
        if (Bit >= AddrLSB-3) {
          MamIRX[Bit] = new Pin(Pin.CLB, Row, Col, CenterWires.S0_F1);
          MamIRAC[Bit] = new Pin(Pin.CLB, Row, Col, CenterWires.S0_F3); }
        // rest of address bits only 2:1-Mux PC or MA, if IR.X or IR.AC: zero
        // allocating all Pins would eliminate error checking on non-addr bits
        if (Bit >= AddrMSB) {
          MamPC[Bit] = new Pin(Pin.CLB, Row, Col, CenterWires.S0_G1);
          MamMA[Bit] = new Pin(Pin.CLB, Row, Col, CenterWires.S0_G3); }
        // rest of bits, only connect the enables, useless, but easier so
        // do so because Java array 0..n limit workaround, else Bit-AddrBits
        MamIRXEn[Bit] = new Pin(Pin.CLB, Row, Col, CenterWires.S0_F2);
        MamIRACEn[Bit] = new Pin(Pin.CLB, Row, Col, CenterWires.S0_F4);
        MamPCEn[Bit] = new Pin(Pin.CLB, Row, Col, CenterWires.S0_G2);
        MamMAEn[Bit] = new Pin(Pin.CLB, Row, Col, CenterWires.S0_G4);
        if (Bit >= AddrLSB-3) {
          Fpga.set(Row, Col, LUT.SLICE0_F, L(~(I1&I2|I3&I4)));
          Fpga.set(Row, Col, LUT.SLICE0_G, L(~(I1&I2|I3&I4)));
          // wideOR with LUT=0 -> !BX (=0) and LUT=1 -> AndMux.ONE (=1)
          Fpga.set(Row, Col, S0Control.XCarrySelect.XCarrySelect,
            S0Control.XCarrySelect.LUT_CONTROL);
          Fpga.set(Row, Col, S0Control.YCarrySelect.YCarrySelect,
            S0Control.YCarrySelect.LUT_CONTROL);
          Fpga.set(Row, Col, S0Control.AndMux.AndMux, S0Control.AndMux.ONE);
          Fpga.set(Row, Col, S0Control.Cin.Cin, S0Control.Cin.BX);
          Fpga.set(Row, Col, S0Control.BxInvert, S0Control.ON);
          if (DebugDisp == 1) {
            // XQ blank from !BX
            Fpga.set(Row, Col, S0Control.XDin.XDin, S0Control.XDin.BX);
            // YQ shows MamOut, from YB via BY to Y/YQ
            Router.route(new Pin(Pin.CLB, Row, Col, CenterWires.S0_YB),
              new Pin(Pin.CLB, Row, Col, CenterWires.S0_BY));
            Fpga.set(Row, Col, S0Control.YDin.YDin, S0Control.YDin.BY);
            Fpga.set(Row, Col, S0Clk.S0Clk, S0Clk.GCLK1); }
          MamOut[Bit] = new Pin(Pin.CLB, Row, Col, CenterWires.S0_YB); }
        else {
          if (Bit >= AddrMSB) {
            Fpga.set(Row, Col, LUT.SLICE0_G, L(I1&I2|I3&I4));
            if (DebugDisp == 1) {
              // XQ blank, YQ shows MamOut
              Fpga.set(Row, Col, S0Clk.S0Clk, S0Clk.GCLK1); }
            MamOut[Bit] = new Pin(Pin.CLB, Row, Col, CenterWires.S0_Y); } }
        if (Bit >= AddrMSB) {
          Fpga.setTag(Row, Col, Tag); }
        Col = Bit%2==1 ? Col+1 : Col-1; Row = Bit%2==1 ? Row : Row+1; }

      // connect address mux outputs to memory address inputs
      Router.route(MamOut[31], MemAddr31);
      Router.route(MamOut[32], MemAddr32F);
      Router.route(MamOut[32], MemAddr32G);
      Router.route(MamOut[33], MemAddr33F);
      Router.route(MamOut[33], MemAddr33G);
      Router.route(MamOut[34], MemAddr34F);
      Router.route(MamOut[34], MemAddr34G);
      Router.route(MamOut[35], MemAddr35F);
      Router.route(MamOut[35], MemAddr35G);

      Tag += 1;
      System.out.print(".." + (Row-1));

      // control MAM-Mux=IR.X = insidx
      Pin MamEnIRXInsidx = new Pin(Pin.CLB, Row, Col, CenterWires.S0_F1);
      Fpga.set(Row, Col, LUT.SLICE0_F, L(I1));
      Pin MamEnIRX = new Pin(Pin.CLB, Row, Col, CenterWires.S0_X);
      Router.route(MamEnIRX, MamIRXEn);
      Fpga.setTag(Row, Col, Tag);
      Row++;
      // control MAM-Mux=IR.AC = log2nd|logac
      //   this will grow with other instruction groups adding states
      Pin MamEnIRACLog2nd = new Pin(Pin.CLB, Row, Col, CenterWires.S0_F1);
      Pin MamEnIRACLogAc = new Pin(Pin.CLB, Row, Col, CenterWires.S0_F2);
      Fpga.set(Row, Col, LUT.SLICE0_F, L(I1|I2));
      Pin MamEnIRAC = new Pin(Pin.CLB, Row, Col, CenterWires.S0_X);
      Router.route(MamEnIRAC, MamIRACEn);
      Fpga.setTag(Row, Col, Tag);
      Row++;
      // control MAM-Mux=PC = insget
      Pin MamEnPCInsget = new Pin(Pin.CLB, Row, Col, CenterWires.S0_F1);
      Fpga.set(Row, Col, LUT.SLICE0_F, L(I1));
      Pin MamEnPC = new Pin(Pin.CLB, Row, Col, CenterWires.S0_X);
      Router.route(MamEnPC, MamPCEn);
      Fpga.setTag(Row, Col, Tag);
      Row++;
      // control MAM-Mux=MA = insind|log1st|logmem
      //   this will grow with other instruction groups adding states
      Pin MamEnMAInsind = new Pin(Pin.CLB, Row, Col, CenterWires.S0_F1);
      Pin MamEnMALog1st = new Pin(Pin.CLB, Row, Col, CenterWires.S0_F2);
      Pin MamEnMALogMem = new Pin(Pin.CLB, Row, Col, CenterWires.S0_F3);
      Fpga.set(Row, Col, LUT.SLICE0_F, L(I1|I2|I3));
      Pin MamEnMA = new Pin(Pin.CLB, Row, Col, CenterWires.S0_X);
      Router.route(MamEnMA, MamMAEn);
      Fpga.setTag(Row, Col, Tag);
      Row++;

      Tag += 1;
      System.out.println(",c.." + (Row-1));


// ------ program counter section

      // program counter register and incrementer and jump load mux
      // PC in FFs, in from E (jump) or PC+1 (incr) - 2:1-Mux w common select
      // incrementer done with carry Cin=1 and add/xor 0 so no constant 1 input
      Col = PathCol; Row = PathRow;
      PathCol += 1;
      System.out.print("program counter at " + Col + "|" + Row);

      Pin ProgMux[] = new Pin[DataBits], ProgOldPC[] = new Pin[DataBits],
          ProgJump[] = new Pin[DataBits], ProgOut[] = new Pin[DataBits],
          ProgWrEn[] = new Pin[DataBits/2];

      for (Bit = DataLSB; Bit >= DataMSB; Bit--) {
        if (Bit == DataLSB) {
          // seed incrementer carry-in, BX is 1 if not connected, for Cin=1
          Fpga.set(Row, Col, S0Control.Cin.Cin, S0Control.Cin.BX); }
        if (Bit%2 == 1) {
          // mux incr with F1=1 and old PC F2 because of using mult-and gate
          ProgMux[Bit] = new Pin(Pin.CLB, Row, Col, CenterWires.S0_F1);
          if (Bit >= AddrMSB) {
            ProgOldPC[Bit] = new Pin(Pin.CLB, Row, Col, CenterWires.S0_F2);
            ProgJump[Bit] = new Pin(Pin.CLB, Row, Col, CenterWires.S0_F3);
            Fpga.set(Row, Col, LUT.SLICE0_F, L(I1&I2|(~I1)&I3));
            // carry conditional on F/G1 add Cin=1, from BX=1
            Fpga.set(Row, Col, S0Control.XCarrySelect.XCarrySelect,
              S0Control.XCarrySelect.LUT_CONTROL);
            Fpga.set(Row, Col, S0Control.AndMux.AndMux,
              S0Control.AndMux.IN1_AND_IN2);
            // and use carry adder result
            Fpga.set(Row, Col, S0Control.X.X, S0Control.X.FOUT_XOR_CARRY); }
          ProgWrEn[Bit/2] = new Pin(Pin.CLB, Row, Col, CenterWires.S0_CE);
          if (Bit >= AddrMSB) {
            Fpga.set(Row, Col, S0Clk.S0Clk, S0Clk.GCLK1);
            ProgOut[Bit] = new Pin(Pin.CLB, Row, Col, CenterWires.S0_XQ);
            Router.route(ProgOut[Bit], ProgOldPC[Bit]); } }
        else {
          ProgMux[Bit] = new Pin(Pin.CLB, Row, Col, CenterWires.S0_G1);
          if (Bit >= AddrMSB) {
            ProgOldPC[Bit] = new Pin(Pin.CLB, Row, Col, CenterWires.S0_G2);
            ProgJump[Bit] = new Pin(Pin.CLB, Row, Col, CenterWires.S0_G3);
            Fpga.set(Row, Col, LUT.SLICE0_G, L(I1&I2|(~I1)&I3));
            Fpga.set(Row, Col, S0Control.YCarrySelect.YCarrySelect,
              S0Control.YCarrySelect.LUT_CONTROL);
            // S0Control.AndMux.IN1_AND_IN2 for G/Y is same setting as for F/X
            Fpga.set(Row, Col, S0Control.Y.Y, S0Control.Y.GOUT_XOR_CARRY); }
          // ProgWrEn CenterWires.S0_CE for G/Y uses same setting as for F/X
          if (Bit >= AddrMSB) {
            ProgOut[Bit] = new Pin(Pin.CLB, Row, Col, CenterWires.S0_YQ);
            Router.route(ProgOut[Bit], ProgOldPC[Bit]); }
          Row++; }
        // reset program counter to start at address 000000000020, bit 31 = 1
        // properly this should be set to last word of read-in or from console
        //   but we have no read-in yet, nor console, nor jump instructions
        if (Bit == 31) {
          Fpga.set(Row, Col, S0Control.XffSetResetSelect, S0Control.ON); }
        if (Bit >= AddrMSB) {
          Router.route(ProgOut[Bit], MamPC[Bit]); }
        Fpga.setTag(Row, Col, Tag); }

      Tag += 1;
      System.out.print(".." + (Row-1));

      // control PC-Mux=PC+1 = insget
      Pin ProcMuxIncrInsget = new Pin(Pin.CLB, Row, Col, CenterWires.S0_F1);
      Fpga.set(Row, Col, LUT.SLICE0_F, L(I1));
      Pin ProcMuxIncr = new Pin(Pin.CLB, Row, Col, CenterWires.S0_X);
      Router.route(ProcMuxIncr, ProgMux);
      Fpga.setTag(Row, Col, Tag);
      Row++;
      // control PC-Mux=MA = ??? (jump)
      //   no jump instructions implemented presently
      // control ClkE-PC = insget
      //   this will grow when jump instructions added
      Pin ProcClkEInsget = new Pin(Pin.CLB, Row, Col, CenterWires.S0_F1);
      Fpga.set(Row, Col, LUT.SLICE0_F, L(I1));
      Pin ProcCLkE = new Pin(Pin.CLB, Row, Col, CenterWires.S0_X);
      Router.route(ProcCLkE, ProgWrEn);
      Fpga.setTag(Row, Col, Tag);
      Row++;

      Tag += 1;
      System.out.println(",c.." + (Row-1));


// ------ instruction and memory address section

      // instruction and memory address registers and index adder and load mux
      // IR in FFs bits 0..17, in from MD or IR/0 - 2:1-Mux w separ enables
      // MA in FFs bits 18..35, in from MD or MA+MD - 2:1-Mux w separ enables
      Col = PathCol; Row = PathRow;
      PathCol += 1;
      System.out.print("instruction and mem addr regs at " + Col + "|" + Row);

      // split these for separate mux control of variable and fixed part
      Pin IrMaIdxEn[] = new Pin[DataBits-13], IrMaOldEn[] = new Pin[13],
          IrMaGetEn[] = new Pin[DataBits-13], IrMaMemEn[] = new Pin[13],
          IrMaOld[] = new Pin[DataBits], IrMaMem[] = new Pin[DataBits],
          IrMaOut[] = new Pin[DataBits], IrMaWrEn[] = new Pin[DataBits/2];

      for (Bit = DataLSB; Bit >= DataMSB; Bit--) {
        if (Bit == DataLSB) {
          // clear index add carry-in, BX is 1 not connect, so invert for Cin=0
          Fpga.set(Row, Col, S0Control.Cin.Cin, S0Control.Cin.BX);
          Fpga.set(Row, Col, S0Control.BxInvert, S0Control.ON); }
        if (Bit%2 == 1) {
          // index enable F1 and old MA F2 because of MA using mult-and gate
          IrMaOld[Bit] = new Pin(Pin.CLB, Row, Col, CenterWires.S0_F2);
          IrMaMem[Bit] = new Pin(Pin.CLB, Row, Col, CenterWires.S0_F4);
          if (Bit >= DataMSB+13) {
            // MA          insget/indir mem data load, index add
            // IR.X and .I insget/indir mem data load, index zero X or keep I
            // Bit-13 so that Bit runs 22..0, not 35..13, because Java arrays
            IrMaIdxEn[Bit-13] = new Pin(Pin.CLB, Row, Col, CenterWires.S0_F1);
            IrMaGetEn[Bit-13] = new Pin(Pin.CLB, Row, Col, CenterWires.S0_F3);}
          else {
            // IR.AC and .OP insget mem data load, index/indir keep
            IrMaOldEn[Bit] = new Pin(Pin.CLB, Row, Col, CenterWires.S0_F1);
            IrMaMemEn[Bit] = new Pin(Pin.CLB, Row, Col, CenterWires.S0_F3); }
          Router.route(MemOut[Bit], IrMaMem[Bit]);
          if (Bit >= AddrMSB) {
            Fpga.set(Row, Col, LUT.SLICE0_F, L(I1&(I2^I4)|I3&I4));
            // carry add Cin=0 with !BX=0
            Fpga.set(Row, Col, S0Control.XCarrySelect.XCarrySelect,
              S0Control.XCarrySelect.LUT_CONTROL);
            Fpga.set(Row, Col, S0Control.AndMux.AndMux,
              S0Control.AndMux.IN1_AND_IN2);
            // and use carry adder result
            Fpga.set(Row, Col, S0Control.X.X, S0Control.X.FOUT_XOR_CARRY); }
          else {
            if (Bit >= DataMSB+14) {
              // for IR.X on index load zero, not self, so no I1&I2| mux part
              Fpga.set(Row, Col, LUT.SLICE0_F, L(I3&I4)); }
            else {
              Fpga.set(Row, Col, LUT.SLICE0_F, L(I1&I2|I3&I4)); } }
          IrMaWrEn[Bit/2] = new Pin(Pin.CLB, Row, Col, CenterWires.S0_CE);
          Fpga.set(Row, Col, S0Clk.S0Clk, S0Clk.GCLK1);
          IrMaOut[Bit] = new Pin(Pin.CLB, Row, Col, CenterWires.S0_XQ);
          Router.route(IrMaOut[Bit], IrMaOld[Bit]); }
        else {
          IrMaOld[Bit] = new Pin(Pin.CLB, Row, Col, CenterWires.S0_G2);
          IrMaMem[Bit] = new Pin(Pin.CLB, Row, Col, CenterWires.S0_G4);
          if (Bit >= DataMSB+13) {
            IrMaIdxEn[Bit-13] = new Pin(Pin.CLB, Row, Col, CenterWires.S0_G1);
            IrMaGetEn[Bit-13] = new Pin(Pin.CLB, Row, Col, CenterWires.S0_G3);}
          else {
            IrMaOldEn[Bit] = new Pin(Pin.CLB, Row, Col, CenterWires.S0_G1);
            IrMaMemEn[Bit] = new Pin(Pin.CLB, Row, Col, CenterWires.S0_G3); }
          Router.route(MemOut[Bit], IrMaMem[Bit]);
          if (Bit >= AddrMSB) {
            Fpga.set(Row, Col, LUT.SLICE0_G, L(I1&(I2^I4)|I3&I4));
            Fpga.set(Row, Col, S0Control.YCarrySelect.YCarrySelect,
              S0Control.YCarrySelect.LUT_CONTROL);
            Fpga.set(Row, Col, S0Control.Y.Y, S0Control.Y.GOUT_XOR_CARRY); }
          else {
            if (Bit >= DataMSB+14) {
              Fpga.set(Row, Col, LUT.SLICE0_G, L(I3&I4)); }
            else {
              Fpga.set(Row, Col, LUT.SLICE0_G, L(I1&I2|I3&I4)); } }
          IrMaOut[Bit] = new Pin(Pin.CLB, Row, Col, CenterWires.S0_YQ);
          Router.route(IrMaOut[Bit], IrMaOld[Bit]);
          Row++; }
        if (Bit >= AddrMSB) {
          Router.route(IrMaOut[Bit], MamMA[Bit]); }
        if (AddrMSB > Bit && Bit >= DataMSB+14) {
          Router.route(IrMaOut[Bit], MamIRX[Bit+AddrBits]); }
        if (DataMSB+12 >= Bit && Bit >= DataMSB+9) {
          Router.route(IrMaOut[Bit], MamIRAC[Bit+5+AddrBits]); }
        Fpga.setTag(Row, Col, Tag); }

      Tag += 1;
      System.out.print(".." + (Row-1));

      // control IR.I-Mux=MD + IR.X-Mux=MD + MA-Mux=MD = insget|insind
      Pin IrMaEnGetInsget = new Pin(Pin.CLB, Row, Col, CenterWires.S0_F1);
      Pin IrMaEnGetInsind = new Pin(Pin.CLB, Row, Col, CenterWires.S0_F2);
      Fpga.set(Row, Col, LUT.SLICE0_F, L(I1|I2));
      Pin IrMaEnGet = new Pin(Pin.CLB, Row, Col, CenterWires.S0_X);
      Router.route(IrMaEnGet, IrMaGetEn);
      Fpga.setTag(Row, Col, Tag);
      Row++;
      // control IR.I-Mux=IR + IR.X-Mux=0 + MA-Mux=MA+MD = insidx
      Pin IrMaEnIdxInsidx = new Pin(Pin.CLB, Row, Col, CenterWires.S0_F1);
      Fpga.set(Row, Col, LUT.SLICE0_F, L(I1));
      Pin IrMaEnIdx = new Pin(Pin.CLB, Row, Col, CenterWires.S0_X);
      Router.route(IrMaEnIdx, IrMaIdxEn);
      Fpga.setTag(Row, Col, Tag);
      Row++;
      // control IR.OP-Mux=MD + IR.AC-Mux=MD = insget
      Pin IrMaEnMemInsget = new Pin(Pin.CLB, Row, Col, CenterWires.S0_F1);
      Fpga.set(Row, Col, LUT.SLICE0_F, L(I1));
      Pin IrMaEnMem = new Pin(Pin.CLB, Row, Col, CenterWires.S0_X);
      Router.route(IrMaEnMem, IrMaMemEn);
      Fpga.setTag(Row, Col, Tag);
      Row++;
      // control IR.OP-Mux=IR + IR.AC-Mux=IR = insidx|insind
      Pin IrMaEnOldInsidx = new Pin(Pin.CLB, Row, Col, CenterWires.S0_F1);
      Pin IrMaEnOldInsind = new Pin(Pin.CLB, Row, Col, CenterWires.S0_F2);
      Fpga.set(Row, Col, LUT.SLICE0_F, L(I1|I2));
      Pin IrMaEnOld = new Pin(Pin.CLB, Row, Col, CenterWires.S0_X);
      Router.route(IrMaEnOld, IrMaOldEn);
      Fpga.setTag(Row, Col, Tag);
      Row++;
      // control ClkE-IR+MA = insget|insidx|insind
      Pin IrMaClkEInsget = new Pin(Pin.CLB, Row, Col, CenterWires.S0_F1);
      Pin IrMaClkEInsidx = new Pin(Pin.CLB, Row, Col, CenterWires.S0_F2);
      Pin IrMaClkEInsind = new Pin(Pin.CLB, Row, Col, CenterWires.S0_F3);
      Fpga.set(Row, Col, LUT.SLICE0_F, L(I1|I2|I3));
      Pin IrMaCLkE = new Pin(Pin.CLB, Row, Col, CenterWires.S0_X);
      Router.route(IrMaCLkE, IrMaWrEn);
      Fpga.setTag(Row, Col, Tag);
      Row++;

      // separate tags for the state machine from normal control circuits
      Tag += 1;
      System.out.print(",c.." + (Row-1));

      // central instruction execution FSM, extended in various instr groups
      //   state names are derived from ../Time-States state diagram
      // state insget = logfinish
      //   we have just finished an instruction, so get the next one
      //     this equation is "test for last state of an previous instruction"
      //   this will grow with other instruction groups adding states
      Pin IrMaInsgetLogfinish = new Pin(Pin.CLB, Row, Col, CenterWires.S0_F1);
      Fpga.set(Row, Col, LUT.SLICE0_F, L(I1));
      // set execution FSM to start with insget state
      Fpga.set(Row, Col, S0Control.XffSetResetSelect, S0Control.ON);
      Fpga.set(Row, Col, S0Clk.S0Clk, S0Clk.GCLK1);
      // using CenterWires.S0_XQ for Flip-Flop as FSM bit for this state
      Pin IrMaInsget = new Pin(Pin.CLB, Row, Col, CenterWires.S0_XQ);
      Router.route(IrMaInsget, MamEnPCInsget);
      Router.route(IrMaInsget, ProcMuxIncrInsget);
      Router.route(IrMaInsget, ProcClkEInsget);
      Router.route(IrMaInsget, IrMaEnGetInsget);
      Router.route(IrMaInsget, IrMaEnMemInsget);
      Router.route(IrMaInsget, IrMaClkEInsget);
      Fpga.setTag(Row, Col, Tag);
      Row++;
      // state insexec = insget|insidx|insind
      //   we have got an instruction, trigger decoder to execute it
      Pin IrMaInsexecGet = new Pin(Pin.CLB, Row, Col, CenterWires.S0_F1);
      Router.route(IrMaInsget, IrMaInsexecGet);
      Pin IrMaInsexecIdx = new Pin(Pin.CLB, Row, Col, CenterWires.S0_F2);
      Pin IrMaInsexecInd = new Pin(Pin.CLB, Row, Col, CenterWires.S0_F3);
      Fpga.set(Row, Col, LUT.SLICE0_F, L(I1|I2|I3));
      Fpga.set(Row, Col, S0Clk.S0Clk, S0Clk.GCLK1);
      Pin IrMaInsexec = new Pin(Pin.CLB, Row, Col, CenterWires.S0_XQ);
      Fpga.setTag(Row, Col, Tag);
      Row++;
      // decode insxnot0 = IR.X.0|IR.X.1|IR.X.2|IR.X.3
      //   do we have index register bits set in the instruction?
      Pin IrMaInsXNotZero0 = new Pin(Pin.CLB, Row, Col, CenterWires.S0_F1);
      Router.route(IrMaOut[14], IrMaInsXNotZero0);
      Pin IrMaInsXNotZero1 = new Pin(Pin.CLB, Row, Col, CenterWires.S0_F2);
      Router.route(IrMaOut[15], IrMaInsXNotZero1);
      Pin IrMaInsXNotZero2 = new Pin(Pin.CLB, Row, Col, CenterWires.S0_F3);
      Router.route(IrMaOut[16], IrMaInsXNotZero2);
      Pin IrMaInsXNotZero3 = new Pin(Pin.CLB, Row, Col, CenterWires.S0_F4);
      Router.route(IrMaOut[17], IrMaInsXNotZero3);
      Fpga.set(Row, Col, LUT.SLICE0_F, L(I1|I2|I3|I4));
      Pin IrMaInsXNotZero = new Pin(Pin.CLB, Row, Col, CenterWires.S0_X);
      Fpga.setTag(Row, Col, Tag);
      Row++;
      // decode insidx = insexec&insxnot0
      //   we are decoding an instruction and index set -> dereference index
      Pin IrMaInsidxExec = new Pin(Pin.CLB, Row, Col, CenterWires.S0_F1);
      Router.route(IrMaInsexec, IrMaInsidxExec);
      Pin IrMaInsidxNotX = new Pin(Pin.CLB, Row, Col, CenterWires.S0_F2);
      Router.route(IrMaInsXNotZero, IrMaInsidxNotX);
      Fpga.set(Row, Col, LUT.SLICE0_F, L(I1&I2));
      Pin IrMaInsidx = new Pin(Pin.CLB, Row, Col, CenterWires.S0_X);
      Router.route(IrMaInsidx, MamEnIRXInsidx);
      Router.route(IrMaInsidx, IrMaEnIdxInsidx);
      Router.route(IrMaInsidx, IrMaEnOldInsidx);
      Router.route(IrMaInsidx, IrMaClkEInsidx);
      Router.route(IrMaInsidx, IrMaInsexecIdx);
      Fpga.setTag(Row, Col, Tag);
      Row++;
      // decode insind = insexec&(!insxnot0)&IR.I.0
      //   we are decoding, no index, but indirect -> dereference indirect
      Pin IrMaInsindExec = new Pin(Pin.CLB, Row, Col, CenterWires.S0_F1);
      Router.route(IrMaInsexec, IrMaInsindExec);
      Pin IrMaInsindNotX = new Pin(Pin.CLB, Row, Col, CenterWires.S0_F2);
      Router.route(IrMaInsXNotZero, IrMaInsindNotX);
      Pin IrMaInsindI = new Pin(Pin.CLB, Row, Col, CenterWires.S0_F3);
      Router.route(IrMaOut[13], IrMaInsindI);
      Fpga.set(Row, Col, LUT.SLICE0_F, L(I1&(~I2)&I3));
      Pin IrMaInsind = new Pin(Pin.CLB, Row, Col, CenterWires.S0_X);
      Router.route(IrMaInsind, MamEnMAInsind);
      Router.route(IrMaInsind, IrMaEnGetInsind);
      Router.route(IrMaInsind, IrMaEnOldInsind);
      Router.route(IrMaInsind, IrMaClkEInsind);
      Router.route(IrMaInsind, IrMaInsexecInd);
      Fpga.setTag(Row, Col, Tag);
      Row++;
      // decode insready = insexec&(!insxnot0)&(!IR.I.0)
      //   we are decoding, no index, nor indirect -> ready to execute instr
      //   actual decoding will be completed in actual execution units below
      Pin IrMaInsreadyExec = new Pin(Pin.CLB, Row, Col, CenterWires.S0_F1);
      Router.route(IrMaInsexec, IrMaInsreadyExec);
      Pin IrMaInsreadyNotX = new Pin(Pin.CLB, Row, Col, CenterWires.S0_F2);
      Router.route(IrMaInsXNotZero, IrMaInsreadyNotX);
      Pin IrMaInsreadyI = new Pin(Pin.CLB, Row, Col, CenterWires.S0_F3);
      Router.route(IrMaOut[13], IrMaInsreadyI);
      Fpga.set(Row, Col, LUT.SLICE0_F, L(I1&(~I2)&(~I3)));
      Pin IrMaInsready = new Pin(Pin.CLB, Row, Col, CenterWires.S0_X);
      Fpga.setTag(Row, Col, Tag);
      Row++;

      Tag += 1;
      System.out.println(",s.." + (Row-1));


// ------ arithmetic register section

      // arithmetic register and load mux
      // AR in FFs, in from MA (0,,E) or mem data or log unit - 3:1-Mux sep ena
      Col = PathCol; Row = PathRow;
      PathCol += 2;
      System.out.print("arithmetic unit at " + Col + "|" + Row);

      Pin ArithMA[] = new Pin[DataBits], ArithMAEn[] = new Pin[DataBits],
          ArithMD[] = new Pin[DataBits], ArithMDEn[] = new Pin[DataBits],
          ArithLog[] = new Pin[DataBits], ArithLogEn[] = new Pin[DataBits],
          ArithOut[] = new Pin[DataBits], ArithWrEn[] = new Pin[DataBits];

      for (Bit = DataLSB; Bit >= DataMSB; Bit--) {
        if (Bit >= AddrMSB) {
          ArithMA[Bit] = new Pin(Pin.CLB, Row, Col, CenterWires.S0_F1); }
        ArithMD[Bit] = new Pin(Pin.CLB, Row, Col, CenterWires.S0_G1);
        ArithLog[Bit] = new Pin(Pin.CLB, Row, Col, CenterWires.S0_G3);
        ArithMAEn[Bit] = new Pin(Pin.CLB, Row, Col, CenterWires.S0_F2);
        ArithMDEn[Bit] = new Pin(Pin.CLB, Row, Col, CenterWires.S0_G2);
        ArithLogEn[Bit] = new Pin(Pin.CLB, Row, Col, CenterWires.S0_G4);
        if (Bit >= AddrMSB) {
          Router.route(IrMaOut[Bit], ArithMA[Bit]); }
        Router.route(MemOut[Bit], ArithMD[Bit]);
        if (Bit >= AddrMSB) {
          Fpga.set(Row, Col, LUT.SLICE0_F, L(~(I1&I2)));
          Fpga.set(Row, Col, LUT.SLICE0_G, L(~(I1&I2|I3&I4)));
          // wideOR with LUT=0 -> !BX (=0) and LUT=1 -> AndMux.ONE (=1)
          Fpga.set(Row, Col, S0Control.XCarrySelect.XCarrySelect,
            S0Control.XCarrySelect.LUT_CONTROL);
          Fpga.set(Row, Col, S0Control.YCarrySelect.YCarrySelect,
            S0Control.YCarrySelect.LUT_CONTROL);
          Fpga.set(Row, Col, S0Control.AndMux.AndMux, S0Control.AndMux.ONE);
          Fpga.set(Row, Col, S0Control.Cin.Cin, S0Control.Cin.BX);
          Fpga.set(Row, Col, S0Control.BxInvert, S0Control.ON);
          // wideOR comes to YB out, not to Y and YQ, from YB via BY to Y/YQ
          Router.route(new Pin(Pin.CLB, Row, Col, CenterWires.S0_YB),
            new Pin(Pin.CLB, Row, Col, CenterWires.S0_BY));
          Fpga.set(Row, Col, S0Control.YDin.YDin, S0Control.YDin.BY);
          if (DebugDisp == 1) {
            // silence XQ, as YQ shows AR data
            Fpga.set(Row, Col, S0Control.XDin.XDin, S0Control.XDin.BX); } }
        else {
          // only 2:1-Mux for rest of bits, zero when 0,,E selected
          Fpga.set(Row, Col, LUT.SLICE0_G, L(I1&I2|I3&I4)); }
        ArithWrEn[Bit] = new Pin(Pin.CLB, Row, Col, CenterWires.S0_CE);
        Fpga.set(Row, Col, S0Clk.S0Clk, S0Clk.GCLK1);
        ArithOut[Bit] = new Pin(Pin.CLB, Row, Col, CenterWires.S0_YQ);
        Router.route(ArithOut[Bit], MemIn[Bit]);
        Fpga.setTag(Row, Col, Tag);
        Col = Bit%2==1 ? Col+1 : Col-1; Row = Bit%2==1 ? Row : Row+1; }

      Tag += 1;
      System.out.print(".." + (Row-1));

      // control AR-Mux=MA = logimm
      //   this will grow with other instruction groups adding states
      Pin ArithEnMALogImm = new Pin(Pin.CLB, Row, Col, CenterWires.S0_F1);
      Fpga.set(Row, Col, LUT.SLICE0_F, L(I1));
      Pin ArithEnMA = new Pin(Pin.CLB, Row, Col, CenterWires.S0_X);
      Router.route(ArithEnMA, ArithMAEn);
      Fpga.setTag(Row, Col, Tag);
      Row++;
      // control AR-Mux=MD = log1st
      //   this will grow with other instruction groups adding states
      Pin ArithEnMDLog1st = new Pin(Pin.CLB, Row, Col, CenterWires.S0_F1);
      Fpga.set(Row, Col, LUT.SLICE0_F, L(I1));
      Pin ArithEnMD = new Pin(Pin.CLB, Row, Col, CenterWires.S0_X);
      Router.route(ArithEnMD, ArithMDEn);
      Fpga.setTag(Row, Col, Tag);
      Row++;
      // control AR-Mux=logout = AR-Mux=log2nd
      //   this will grow with other instruction groups adding states
      Pin ArithEnLogoutLog2nd = new Pin(Pin.CLB, Row, Col, CenterWires.S0_F1);
      Fpga.set(Row, Col, LUT.SLICE0_F, L(I1));
      Pin ArithEnLog = new Pin(Pin.CLB, Row, Col, CenterWires.S0_X);
      Router.route(ArithEnLog, ArithLogEn);
      Fpga.setTag(Row, Col, Tag);
      Row++;
      // control ClkE-AR = AR-Mux=MA|AR-Mux=MD|AR-Mux=logout
      Pin ArithCLkEMA = new Pin(Pin.CLB, Row, Col, CenterWires.S0_F1);
      Router.route(ArithEnMA, ArithCLkEMA);
      Pin ArithCLkEMD = new Pin(Pin.CLB, Row, Col, CenterWires.S0_F2);
      Router.route(ArithEnMD, ArithCLkEMD);
      Pin ArithCLkELog = new Pin(Pin.CLB, Row, Col, CenterWires.S0_F3);
      Router.route(ArithEnLog, ArithCLkELog);
      Fpga.set(Row, Col, LUT.SLICE0_F, L(I1|I2|I3));
      Pin ArithCLkE = new Pin(Pin.CLB, Row, Col, CenterWires.S0_X);
      Router.route(ArithCLkE, ArithWrEn);
      Fpga.setTag(Row, Col, Tag);
      Row++;

      Tag += 1;
      System.out.println(",c.." + (Row-1));


// ------ 100ffffmm boolean logic instruction unit section

      // data bit output table from PDP-10 Reference Manual, page 2-38
      // C(AC)     0 1 0 1
      // C(E)/0,,E 0 0 1 1
      // -----------------
      // IR bit    3 4 5 6
      // SETZ      0 0 0 0
      // AND       0 0 0 1
      // ANDCA     0 0 1 0
      // SETM      0 0 1 1
      // ANDCM     0 1 0 0
      // SETA      0 1 0 1
      // XOR       0 1 1 0
      // IOR       0 1 1 1
      // ANDCB     1 0 0 0
      // EQV       1 0 0 1
      // SETCA     1 0 1 0
      // ORCA      1 0 1 1
      // SETCM     1 1 0 0
      // ORCM      1 1 0 1
      // ORCB      1 1 1 0
      // SETO      1 1 1 1
      // is 4:1-Mux of instr bits 3..6, select by high=C(E)=AR and low=C(AC)=MD
      // 2:1-Mux (F5) of 2 2:1-Muxes (2 LUTs), Col 0 bit 35/.., Col 1 bit 34/..
      Col = PathCol; Row = PathRow;
      PathCol += 2;
      System.out.print("boolean logic unit at " + Col + "|" + Row);

      Pin LogicBit3[] = new Pin[DataBits], LogicBit4[] = new Pin[DataBits],
          LogicBit5[] = new Pin[DataBits], LogicBit6[] = new Pin[DataBits],
          LogicSelMDF[] = new Pin[DataBits], LogicSelMDG[] = new Pin[DataBits],
          LogicSelAR[] = new Pin[DataBits], LogicOut[] = new Pin[DataBits];

      for (Bit = DataLSB; Bit >= DataMSB; Bit--) {
        // F1..2 instruction bits 3..4, G1..2 instruction bits 5..6
        // F3 and G3 from C(E) = AR, BX from C(AC) = MD
        LogicBit3[Bit] = new Pin(Pin.CLB, Row, Col, CenterWires.S0_F1);
        LogicBit4[Bit] = new Pin(Pin.CLB, Row, Col, CenterWires.S0_F2);
        LogicBit5[Bit] = new Pin(Pin.CLB, Row, Col, CenterWires.S0_G1);
        LogicBit6[Bit] = new Pin(Pin.CLB, Row, Col, CenterWires.S0_G2);
        LogicSelMDF[Bit] = new Pin(Pin.CLB, Row, Col, CenterWires.S0_F3);
        LogicSelMDG[Bit] = new Pin(Pin.CLB, Row, Col, CenterWires.S0_G3);
        LogicSelAR[Bit] = new Pin(Pin.CLB, Row, Col, CenterWires.S0_BX);
        Router.route(MemOut[Bit], LogicSelMDF[Bit]);
        Router.route(MemOut[Bit], LogicSelMDG[Bit]);
        Router.route(ArithOut[Bit], LogicSelAR[Bit]);
        Fpga.set(Row, Col, LUT.SLICE0_F, L(I1&(~I3)|I2&I3));
        Fpga.set(Row, Col, LUT.SLICE0_G, L(I1&(~I3)|I2&I3));
        Fpga.set(Row, Col, S0Control.X.X, S0Control.X.F5);
        // invert BX, because F5-Mux is 0/1:G/F
        Fpga.set(Row, Col, S0Control.BxInvert, S0Control.ON);
        LogicOut[Bit] = new Pin(Pin.CLB, Row, Col, CenterWires.S0_X);
        Router.route(LogicOut[Bit], ArithLog[Bit]);
        Fpga.setTag(Row, Col, Tag);
        Col = Bit%2==1 ? Col+1 : Col-1; Row = Bit%2==1 ? Row : Row+1; }

      // connect instruction function selection bits to unit
      Router.route(IrMaOut[3], LogicBit3);
      Router.route(IrMaOut[4], LogicBit4);
      Router.route(IrMaOut[5], LogicBit5);
      Router.route(IrMaOut[6], LogicBit6);

      Tag += 1;
      System.out.print(".." + (Row-1));

      // no control circuits here, as logic unit has no enables or FFs

      // separate tags for the state machine from normal control circuits
      Tag += 1;
      System.out.print(",c.." + (Row-1));

      // boolean logic extension to instruction execution FSM
      // mode table from PDP-10 Reference Manual, page 2-32
      // IR bit     7 8    Suffix Sources         Destination
      // Basic      0 0    -      C(E) and C(AC)  AC
      // Immediate  0 1    I      0,,E and C(AC)  AC
      // Memory     1 0    M      C(E) and C(AC)  E
      // Both       1 1    B      C(E) and C(AC)  AC and E
      // decode loginstr = insready&IR.OP.0&(!IR.OP.1)&(!IR.OP.2)
      //   we are decoding an instruction and we have an 100ffffmm opcode
      Pin LogicInstrInsready = new Pin(Pin.CLB, Row, Col, CenterWires.S0_F1);
      Router.route(IrMaInsready, LogicInstrInsready);
      Pin LogicInstrOp0 = new Pin(Pin.CLB, Row, Col, CenterWires.S0_F2);
      Router.route(IrMaOut[0], LogicInstrOp0);
      Pin LogicInstrOp1 = new Pin(Pin.CLB, Row, Col, CenterWires.S0_F3);
      Router.route(IrMaOut[1], LogicInstrOp1);
      Pin LogicInstrOp2 = new Pin(Pin.CLB, Row, Col, CenterWires.S0_F4);
      Router.route(IrMaOut[2], LogicInstrOp2);
      Fpga.set(Row, Col, LUT.SLICE0_F, L(I1&I2&(~I3)&(~I4)));
      Pin LogicInstr = new Pin(Pin.CLB, Row, Col, CenterWires.S0_X);
      Fpga.setTag(Row, Col, Tag);
      Row++;
      // decode logimm = loginstr&(!IR.OP.7)&IR.OP.8
      //   it is 100ffff01 move 0,,MA directly to AR, no fetch from memory
      Pin LogicImmInstr = new Pin(Pin.CLB, Row, Col, CenterWires.S0_F1);
      Router.route(LogicInstr,LogicImmInstr);
      Pin LogicImmOp7 = new Pin(Pin.CLB, Row, Col, CenterWires.S0_F2);
      Router.route(IrMaOut[7], LogicImmOp7);
      Pin LogicImmOp8 = new Pin(Pin.CLB, Row, Col, CenterWires.S0_F3);
      Router.route(IrMaOut[8], LogicImmOp8);
      Fpga.set(Row, Col, LUT.SLICE0_F, L(I1&(~I2)&I3));
      Pin LogicImm = new Pin(Pin.CLB, Row, Col, CenterWires.S0_X);
      Router.route(LogicImm, ArithEnMALogImm);
      Fpga.setTag(Row, Col, Tag);
      Row++;
      // decode log1st = loginstr&(!((!IR.OP.7)&IR.OP.8))
      //   it is 100ffff[not-01] fetch operand from memory addr by MA, to AR
      Pin Logic1stInstr = new Pin(Pin.CLB, Row, Col, CenterWires.S0_F1);
      Router.route(LogicInstr, Logic1stInstr);
      Pin Logic1stOp7 = new Pin(Pin.CLB, Row, Col, CenterWires.S0_F2);
      Router.route(IrMaOut[7], Logic1stOp7);
      Pin Logic1stOp8 = new Pin(Pin.CLB, Row, Col, CenterWires.S0_F3);
      Router.route(IrMaOut[8], Logic1stOp8);
      Fpga.set(Row, Col, LUT.SLICE0_F, L(I1&(~((~I2)&I3))));
      Pin Logic1st = new Pin(Pin.CLB, Row, Col, CenterWires.S0_X);
      Router.route(Logic1st, MamEnMALog1st);
      Router.route(Logic1st, ArithEnMDLog1st);
      Fpga.setTag(Row, Col, Tag);
      Row++;
      // state log2nd = logimm|log1st
      //   fetch 2nd opr from mem addr by IR.AC, apply ffff to AR and it, to AR
      Pin Logic2ndImm = new Pin(Pin.CLB, Row, Col, CenterWires.S0_F1);
      Router.route(LogicImm, Logic2ndImm);
      Pin Logic2nd1st = new Pin(Pin.CLB, Row, Col, CenterWires.S0_F2);
      Router.route(Logic1st, Logic2nd1st);
      Fpga.set(Row, Col, LUT.SLICE0_F, L(I1|I2));
      Fpga.set(Row, Col, S0Clk.S0Clk, S0Clk.GCLK1);
      Pin Logic2nd = new Pin(Pin.CLB, Row, Col, CenterWires.S0_XQ);
      Router.route(Logic2nd, MamEnIRACLog2nd);
      Router.route(Logic2nd, ArithEnLogoutLog2nd);
      Fpga.setTag(Row, Col, Tag);
      Row++;
      // state logac = log2nd&((!IR.OP.7)|(IR.OP.7&IR.OP.8))
      //   100ffff0m or 100ffff11 store AR to memory addr by IR.AC
      Pin LogicAc2nd = new Pin(Pin.CLB, Row, Col, CenterWires.S0_F1);
      Router.route(Logic2nd, LogicAc2nd);
      Pin LogicAcOp7 = new Pin(Pin.CLB, Row, Col, CenterWires.S0_F2);
      Router.route(IrMaOut[7], LogicAcOp7);
      Pin LogicAcOp8 = new Pin(Pin.CLB, Row, Col, CenterWires.S0_F3);
      Router.route(IrMaOut[8], LogicAcOp8);
      Fpga.set(Row, Col, LUT.SLICE0_F, L(I1&((~I2)|(I2&I3))));
      Fpga.set(Row, Col, S0Clk.S0Clk, S0Clk.GCLK1);
      Pin LogicAc = new Pin(Pin.CLB, Row, Col, CenterWires.S0_XQ);
      Router.route(LogicAc, MemClkELogAc);
      Router.route(LogicAc, MamEnIRACLogAc);
      Fpga.setTag(Row, Col, Tag);
      Row++;
      // state logmem = (log2nd&IR.OP.7&(!IR.OP.8))|(logac&IR.OP.7&IR.OP.8)
      //   100ffff10 (or 100ffff11 after 1st store) store AR to mem addr by MA
      Pin LogicMem2nd = new Pin(Pin.CLB, Row, Col, CenterWires.S0_F1);
      Router.route(Logic2nd, LogicMem2nd);
      Pin LogicMemOp7 = new Pin(Pin.CLB, Row, Col, CenterWires.S0_F2);
      Router.route(IrMaOut[7], LogicMemOp7);
      Pin LogicMemOp8 = new Pin(Pin.CLB, Row, Col, CenterWires.S0_F3);
      Router.route(IrMaOut[8], LogicMemOp8);
      Pin LogicMemAc = new Pin(Pin.CLB, Row, Col, CenterWires.S0_F4);
      Router.route(LogicAc, LogicMemAc);
      Fpga.set(Row, Col, LUT.SLICE0_F, L((I1&I2&(~I3))|(I4&I2&I3)));
      Fpga.set(Row, Col, S0Clk.S0Clk, S0Clk.GCLK1);
      Pin LogicMem = new Pin(Pin.CLB, Row, Col, CenterWires.S0_XQ);
      Router.route(LogicMem, MemClkELogMem);
      Router.route(LogicMem, MamEnMALogMem);
      Fpga.setTag(Row, Col, Tag);
      Row++;
      // decode logfinish = logac&(!(IR.OP.7&IR.OP.8))|logmem
      //   100ffff0m after storing addr IR.AC, or allways after storing addr MA
      Pin LogicFinishAc = new Pin(Pin.CLB, Row, Col, CenterWires.S0_F1);
      Router.route(LogicAc, LogicFinishAc);
      Pin LogicFinishOp7 = new Pin(Pin.CLB, Row, Col, CenterWires.S0_F2);
      Router.route(IrMaOut[7], LogicFinishOp7);
      Pin LogicFinishOp8 = new Pin(Pin.CLB, Row, Col, CenterWires.S0_F3);
      Router.route(IrMaOut[8], LogicFinishOp8);
      Pin LogicFinishMem = new Pin(Pin.CLB, Row, Col, CenterWires.S0_F4);
      Router.route(LogicMem, LogicFinishMem);
      Fpga.set(Row, Col, LUT.SLICE0_F, L(I1&(~(I2&I3))|I4));
      Pin LogicFinish = new Pin(Pin.CLB, Row, Col, CenterWires.S0_X);
      Router.route(LogicFinish, IrMaInsgetLogfinish);
      Fpga.setTag(Row, Col, Tag);
      Row++;

      Tag += 1;
      System.out.println(",s.." + (Row-1));


// ------ finishing off section

      System.out.println("space unused from " + PathCol + "," + PathRow); }

    catch (RouteException Re) {
      System.out.println("Problem modifiying Bitstream");
      System.out.println(Re); }
    catch (ConfigurationException Ce) {
      System.out.println("Problem modifiying Bitstream");
      System.out.println(Ce); } } }

