// DMisc-Proms.bcpl -- Dicentra Miscellaneous board Proms
// Last modified January 18, 1984  8:56 PM by Boggs

// To make a new .MB file:
//	Edit this file; then FTP it to the "Dicentra Proms" disk
//	type "BCPL DMiscProms.bcpl" to compile it
//	type "BLDR DMiscProms" to load it
//	type "DMiscProms" to run it and produce DMiscProms.mb

external [ Ws; OpenFile; Puts; Closes; Allocate; Free; sysZone ]

static [ memory; mbFile ]

structure String [ length byte; char↑1,1 byte ]

manifest [ high = 1; low = 0 ]

//-----------------------------------------------------------------------------------------
let DMiscProms() be
//-----------------------------------------------------------------------------------------
[
mbFile = OpenFile("DMisc-Proms.mb")

DoMemory("Cmd", 512, 8, Cmd)
DoMemory("Int", 32, 8, Int)
DoMemory("ZBus", 512, 24, ZBus)

Puts(mbFile, 0)  //0 = end of file
Closes(mbFile)
]

//-----------------------------------------------------------------------------------------
and DoMemory(name, nAddr, nData, Proc) be
//-----------------------------------------------------------------------------------------
// nAddr is number of addresses
// nData is number of output bits
[
Ws("*N"); Ws(name)

Puts(mbFile, 4)  //4 = define memory
memory = memory +1
Puts(mbFile, memory)
Puts(mbFile, nData)
if name>>String.length gr 1 then
   for i = 1 to name>>String.length-1 by 2 do
      Puts(mbFile, name>>String.char↑i lshift 8 + name>>String.char↑(i+1))
Puts(mbFile, (name>>String.length & 1) eq 0? 0,
 name>>String.char↑(name>>String.length) lshift 8)

Puts(mbFile, 2)  //2 = set current memory
Puts(mbFile, memory)
Puts(mbFile, 0)  //location counter

let data = Allocate(sysZone, (nData+15)/16)
for addr = 0 to nAddr-1 do
   [
   Puts(mbFile, 1)  //1 = memory contents
   Puts(mbFile, 0)  //source line number
   Proc(addr, data)
   for i = 0 to (nData+15)/16 -1 do Puts(mbFile, data!i)
   ]
Free(sysZone, data)
]

//-----------------------------------------------------------------------------------------
and Cmd(addr, data) be
//-----------------------------------------------------------------------------------------
[
manifest   // zCmd values
   [
   noCmd = 0
   byteRead = 1
   byteWrite = 2
   wordRead = 3
   wordWrite = 4
   intAck = 5
   init = 6
   ]

structure Addr:
   [
   blank bit 7
   BdSel bit
   IORC bit	//low true
   IOWC bit	//low true
   Adr bit 4	//low true
   INIT bit	//low true
   blank bit
   ]

structure Data:
   [
   zCmd bit 3
   blank bit 3
   ReadHigh bit
   ReadLow bit
   blank bit 8
   ]

let BdSel = addr<<Addr.BdSel eq high
let IORC = addr<<Addr.IORC eq low
let IOWC = addr<<Addr.IOWC eq low
let Adr = addr<<Addr.Adr xor 17b
let INIT = addr<<Addr.INIT eq low

let zCmd = noCmd
let ReadHigh = IORC & BdSel & Adr eq 15
let ReadLow = IORC & BdSel

if (IORC % IOWC) & BdSel then zCmd = selecton Adr into
   [
   case 0:  IORC? intAck, noCmd		//IntAck
   case 1:  IORC? byteRead, byteWrite	//SCC0
   case 2:  noCmd			//Spare
   case 3:  IORC? byteRead, byteWrite	//SCC1
   case 4:  IORC? byteRead, byteWrite	//Modem
   case 5:  IORC? byteRead, byteWrite	//SCC2
   case 6:  noCmd			//Spare
   case 7:  IORC? byteRead, byteWrite	//SCC3
   case 8:  IORC? byteRead, byteWrite	//Dialer0
   case 9:  IORC? byteRead, byteWrite	//Misc
   case 10: IORC? byteRead, byteWrite	//Dialer1
   case 11: IORC? byteRead, byteWrite	//EProm
   case 12: IORC? byteRead, byteWrite	//Dialer2
   case 13: IORC? byteRead, byteWrite	//DESByte
   case 14: noCmd			//Spare
   case 15: IORC? wordRead, wordWrite	//DESWord
   ]
if INIT then zCmd = init  //overrides everything

data>>Data.zCmd = zCmd
data>>Data.ReadHigh = ReadHigh? high, low
data>>Data.ReadLow = ReadLow? high, low
]

//-----------------------------------------------------------------------------------------
and Int(addr, data) be
//-----------------------------------------------------------------------------------------
// This needs work before it is suitable for multiple Misc boards.
// IntChan bits are currently ignored.
[
structure Addr:
   [
   blank bit 11
   Int0 bit		//low true
   SCCInt bit		//low true
   CIOInt bit		//low true
   IntChan bit 2
   ]

structure Data:
   [
   IntOut0 bit		//low true
   IntOut1 bit		//low true
   IntOut2 bit		//low true
   IntOut3 bit		//low true
   IntOut4 bit		//low true
   IntOut5 bit		//low true
   IntOut6 bit		//low true
   IntOut7 bit		//low true
   blank bit 8
   ]

let Int0 = addr<<Addr.Int0 eq low
let SCCInt = addr<<Addr.SCCInt eq low
let CIOInt = addr<<Addr.CIOInt eq low
let IntChan = addr<<Addr.IntChan

data>>Data.IntOut0 = Int0? low, high
data>>Data.IntOut1 = high
data>>Data.IntOut2 = high
data>>Data.IntOut3 = high
data>>Data.IntOut4 = SCCInt? low, high
data>>Data.IntOut5 = high
data>>Data.IntOut6 = high
data>>Data.IntOut7 = CIOInt? low, high
]

//-----------------------------------------------------------------------------------------
and ZBus(addr, data) be
//-----------------------------------------------------------------------------------------
[
manifest
   [
   // zCmd values
   noCmd = 0
   byteRead = 1
   byteWrite = 2
   wordRead = 3
   wordWrite = 4
   intAck = 5
   init = 6

   // FSM states; 12 free: 52-63.
   idle0 = 0; idle1 = 1; idle2 = 2; idle3 = 3
   init0 = 4; init1 = 5; init2 = 6; init3 = 7
   byte0 = 8; byte1 = 9; byte2 = 10; byte3 = 11; byte4 = 12; byte5 = 13
   byteEnd = 14; byteEnd0 = 15; byteEnd1 = 16; byteEnd2 = 17; byteEnd3 = 18
   intAck0 = 19; intAck1 = 20; intAck2 = 21; intAck3 = 22
   word0 = 23; word1 = 24; word2 = 25; word3 = 26
   wordEnd = 27; wordEnd0 = 28; wordEnd1 = 29; wordEnd2 = 30; wordEnd3 = 31

   // 20 dally states implies 5 zClk cycles.
   // The sixth + 200 ns is in the idle loop and the AS part of the next ref.
   dallyFirst = 32; dallyLast = dallyFirst+19
   ]

structure Addr:
   [
   blank bit 7
   CurState bit 6
   zCmd bit 3
   ]

structure Data:
   [
   NextState bit 6
   ReadDatH bit		//low true
   ReadDatL bit		//low true
   WriteDatH bit	//low true
   zXACK bit		//low true
   zIntA bit		//low true
   zCS bit		//low true
   zClk bit		//voltage
   zRW bit		//voltage
   zAS bit		//low true
   zDS bit		//low true
   ]

let CurState = addr<<Addr.CurState
let zCmd = addr<<Addr.zCmd

let NextState = CurState
let ReadDatH, ReadDatL, WriteDatH = false, false, false
let zXACK, zIntA, zClk = false, false, nil
let zCS, zAS, zDS = false, false, false
let zRW = zCmd eq byteWrite % zCmd eq wordWrite? low, high

switchon CurState into
   [
   case idle0:
      [
      zClk = high
      NextState = idle1
      endcase
      ]
   case idle1:
      [
      zClk = high
      NextState = idle2
      endcase
      ]
   case idle2:
      [
      zClk = low
      NextState = idle3
      endcase
      ]
   case idle3:
      [
      zClk = low
      zAS = true
      switchon zCmd into
         [
         case noCmd: [ NextState = idle0; endcase ]
         case intAck: zIntA = true
         case byteRead: case byteWrite:
         case wordRead: case wordWrite:
            [
            zCS = true
            NextState = byte0
            endcase
            ]
         case init: [ NextState = init0; endcase ]
         default: docase noCmd
         ]
      endcase
      ]

   case init0:
      [
      zClk = high
      zAS, zDS = true, true
      NextState = init1
      endcase
      ]
   case init1:
      [
      zClk = high
      zAS, zDS = true, true
      NextState = init2
      endcase
      ]
   case init2:
      [
      zClk = low
      zAS, zDS = true, true
      NextState = init3
      endcase
      ]
   case init3:
      [
      zClk = low
      zAS, zDS = true, true
      NextState = zCmd eq init? init0, idle0
      endcase
      ]

   case byte0:
      [
      zClk = high
      zCS = true
      if zCmd eq intAck then zIntA = true
      NextState = byte1
      endcase
      ]
   case byte1:
      [
      zClk = high
      if zCmd eq intAck then zIntA = true
      if zCmd eq byteWrite then ReadDatL = true
      if zCmd eq wordWrite then ReadDatH = true
      NextState = byte2
      endcase
      ]
   case byte2:
      [
      zClk = low
      if zCmd ne intAck then zDS = true
      if zCmd eq intAck then zIntA = true
      if zCmd eq byteWrite then ReadDatL = true
      if zCmd eq wordWrite then ReadDatH = true
      NextState = byte3
      endcase
      ]
   case byte3:
      [
      zClk = low
      if zCmd ne intAck then zDS = true
      if zCmd eq byteWrite then ReadDatL = true
      if zCmd eq wordWrite then ReadDatH = true
      NextState = byte4
      endcase
      ]
   case byte4:
      [
      zClk = high
      if zCmd ne intAck then zDS = true
      if zCmd eq byteWrite then ReadDatL = true
      if zCmd eq wordWrite then ReadDatH = true
      NextState = byte5
      endcase
      ]
   case byte5:
      [
      zClk = high
      if zCmd ne intAck then zDS = true
      if zCmd eq byteWrite then ReadDatL = true
      if zCmd eq wordWrite then ReadDatH = true
      if zCmd eq wordRead then WriteDatH = true
      NextState = (zCmd eq wordRead % zCmd eq wordWrite)? word0, (zCmd eq intAck? intAck0, byteEnd)
      endcase
      ]

   case byteEnd:
      [
      zClk = low
      zXACK = true
      if zCmd eq byteWrite then ReadDatL = true
      NextState = byteEnd1
      endcase
      ]
   case byteEnd0:
      [
      zClk = low
      NextState = zCmd eq noCmd? dallyFirst+1, byteEnd1
      endcase
      ]
   case byteEnd1:
      [
      zClk = low
      zAS = true
      NextState = zCmd eq noCmd? dallyFirst+2, byteEnd2
      endcase
      ]
   case byteEnd2:
      [
      zClk = high
      NextState = zCmd eq noCmd? dallyFirst+3, byteEnd3
      endcase
      ]
   case byteEnd3:
      [
      zClk = high
      NextState = (zCmd eq noCmd % zCmd eq init)? dallyFirst, byteEnd0
      endcase
      ]

   case dallyFirst to dallyLast:  //dallyFirst is state 100000 binary
      [
      zClk = (CurState & 2) eq 2? high, low
      zAS = (CurState & 3) eq 1
      NextState = CurState eq dallyLast? idle2, CurState+1
      endcase
      ]


   case intAck0:
      [
      zClk = low
      NextState = intAck1
      endcase
      ]
   case intAck1:
      [
      zClk = low
      NextState = intAck2
      endcase
      ]
   case intAck2:
      [
      zClk = high
      NextState = intAck3
      endcase
      ]
   case intAck3:
      [
      zClk = high
      NextState = word0
      endcase
      ]

   case word0:
      [
      zClk = low
      if zCmd eq intAck then zDS = true
      if zCmd eq wordWrite then ReadDatH = true
      NextState = word1
      endcase
      ]
   case word1:
      [
      zClk = low
      if zCmd eq intAck then zDS = true
      if zCmd eq wordWrite then ReadDatL = true
      NextState = word2
      endcase
      ]
   case word2:
      [
      zClk = high
      zDS = true
      if zCmd eq wordWrite then ReadDatL = true
      NextState = word3
      endcase
      ]
   case word3:
      [
      zClk = high
      zDS = true
      if zCmd eq wordWrite then ReadDatL = true
      NextState = zCmd eq intAck? byteEnd, wordEnd
      endcase
      ]

   case wordEnd:
      [
      zClk = low
      zXACK = true
      if zCmd eq wordWrite then ReadDatL = true
      NextState = wordEnd1
      endcase
      ]
   case wordEnd0:
      [
      zClk = low
      NextState = zCmd eq noCmd? idle3, wordEnd1
      endcase
      ]
   case wordEnd1:
      [
      zClk = low
      zAS = true
      NextState = zCmd eq noCmd? idle0, wordEnd2
      endcase
      ]
   case wordEnd2:
      [
      zClk = high
      NextState = zCmd eq noCmd? idle1, wordEnd3
      endcase
      ]
   case wordEnd3:
      [
      zClk = high
      NextState = (zCmd eq noCmd % zCmd eq init)? idle2, wordEnd0
      endcase
      ]

   default: NextState = idle0
   ]

data>>Data.NextState = NextState
data>>Data.ReadDatH = ReadDatH? low, high
data>>Data.ReadDatL = ReadDatL? low, high
data>>Data.WriteDatH = WriteDatH? low, high
data>>Data.zXACK = zXACK? low, high
data>>Data.zIntA = zIntA? low, high
data>>Data.zCS = zCS? low, high
data>>Data.zClk = zClk
data>>Data.zRW = zRW
data>>Data.zAS = zAS? low, high
data>>Data.zDS = zDS? low, high
]