Raw File
CTR.cpp
/****************************************************************************
 * CTR - INVOLUNTARY PRIORITY COUNTER subsystem
 *
 * AUTHOR: John Pultorak
 * DATE: 10/25/02
 * FILE: CTR.cpp
 *
 * NOTES: see header file.
 *
 *****************************************************************************
 */
#include "CTR.h"
#include "INT.h"
#include "BUS.h"
#include "SEQ.h"
regUpCELL CTR::register_UpCELL; // latches the selected priority counter cell (0-7 (decimal))
regDnCELL CTR::register_DnCELL; // latches the selected priority counter cell (0-7 (decimal))
unsigned CTR::pcUp[8];
unsigned CTR::pcDn[8];
// PRIORITY COUNTERS
// ****************************************************
// The interrupt priorities are stored in RPCELL as 1-5, but
// the priority counter priorities are stored as 0-7; this
// inconsistency should be fixed, probably. Also, the method
// of address determination for the priority counters needs work
void
CTR::resetAllpc()
{
  for (int i = 0; i < 8; i++)
    {
      pcUp[i] = 0;
      pcDn[i] = 0;
    }
}
// priority encoder; outputs 0-7; 0=highest priority (OVCTR), 1=TIME2, 2=TIME1, etc
static bool newPriority = true; // a simulator performance optimization; not in the hardware AGC
unsigned
getPriority()
{
  // simulator optimization; don't recompute priority if the priority inputs haven't changed
  static unsigned priority = 7; // default (lowest priority)
  if (!newPriority)
    return priority;
  priority = 7; // default (lowest priority)
  for (int i = 0; i < 8; i++)
    {
      if (CTR::register_UpCELL.readField(i + 1, i + 1)
          | CTR::register_DnCELL.readField(i + 1, i + 1))
        {
          priority = i;
          break;
        }
    }
  newPriority = false;
  return priority;
}
unsigned
CTR::getSubseq()
{
  unsigned pc = getPriority();
  unsigned upCell = CTR::register_UpCELL.readField(pc + 1, pc + 1);
  unsigned dnCell = CTR::register_DnCELL.readField(pc + 1, pc + 1);
  if (upCell == 1 && dnCell == 0)
    return PINCSEL;
  else if (upCell == 0 && dnCell == 1)
    return MINCSEL;
  else
    return NOPSEL;
}
void
CTR::execWP_GENRST()
{
  register_UpCELL.write(0);
  register_DnCELL.write(0);
  resetAllpc();
}
void
CTR::execWP_WPCTR()
{
  // transfer cell data into up and down synch registers
  for (int i = 0; i < 8; i++)
    {
      register_UpCELL.writeField(i + 1, i + 1, pcUp[i]);
      register_DnCELL.writeField(i + 1, i + 1, pcDn[i]);
    }
  newPriority = true; // a simulator performance optimization; not in hardware AGC
}
// Selected counter address is requested at TP1.
// Counter address is latched at TP12
void
CTR::execRP_RSCT()
{
  BUS::glbl_READ_BUS = 034 + getPriority();
}
void
CTR::execWP_WOVR()
{
  unsigned pc = getPriority();
  if (register_UpCELL.readField(pc + 1, pc + 1))
    {
      pcUp[pc] = 0;
    }
  if (register_DnCELL.readField(pc + 1, pc + 1))
    {
      pcDn[pc] = 0;
    }
  // generate various actions in response to counter overflows:
  switch (BUS::testOverflow(BUS::glbl_WRITE_BUS))
    {
  case POS_OVF: // positive overflow
    switch (getPriority())
      // get the counter
      {
    case TIME1:
      CTR::pcUp[TIME2] = 1;
      break; // overflow from TIME1 increments TIME2
    case TIME3:
      INT::rupt[T3RUPT] = 1;
      break; // overflow from TIME3 triggers T3RUPT
    case TIME4:
      INT::rupt[DSRUPT] = 1;
      break; // overflow from TIME4 triggers DSRUPT
      }
    break;
  case NEG_OVF:
    break; // no actions for negative counter overflow
    }
}
void
CTR::execWP_WOVC()
{
  switch (BUS::testOverflow(BUS::glbl_WRITE_BUS))
    {
  case POS_OVF:
    CTR::pcUp[OVCTR] = 1;
    break; // incr OVCTR (034)
  case NEG_OVF:
    CTR::pcDn[OVCTR] = 1;
    break; // decr OVCTR (034)
    }
}
// register_PCELL: Overflow from the selected counter appears
// on the bus when WOVR or WOVC is asserted;
// it could be used to trigger an interrupt
// or routed to increment another counter
back to top