/* di8274.c
   interrupt driver for 8274
   Stewart, November 8, 1982  2:56 PM
   November 8, 1982  5:09 PM osstatics, add nbPutChar()
   February 23, 1983  10:32 AM remove wdc
   February 23, 1983  12:53 PM remove osstatics
   February 23, 1983  2:56 PM new EnableInt, FlushInput,
	CallSwat -> CallDebug, flush Set8274
   February 26, 1983  3:33 PM EOI fixes
 */

#include	"ec.h"
#include	"Lark.h"
#include	"env.h"
#include	"RingBuffer.h"

/* context */
extern Block();

/* interrupts */
extern EnableInt();

/* runtime */
extern CallDebugger();

/* ringbuffer */
extern InitRingBuffer();
extern WriteRingBuffer();
extern RingBufferEmpty();
extern ReadRingBuffer();

/* machine code */
extern OutByte();
extern InByte();

extern /* FORWARD */ mySIOInt();

static struct CBuf rb[2];
static struct CBuf tb[2];
static int busy[2];

Init8274()
  {
  FlushInput(0);
  FlushInput(1);
  InitRingBuffer(&tb[0], tb[0].abuf, CBS-2);
  InitRingBuffer(&tb[1], tb[1].abuf, CBS-2);
  busy[0] = busy[1] = false;
  Baud(1200, 0);
  Baud(1200, 1);
  EnableInt(&mySIOInt, SIOTyp);
  };

FlushInput(ch)
  int ch;
  {
  if (ch) InitRingBuffer(&rb[1], rb[1].abuf, CBS-2);
  else InitRingBuffer(&rb[0], rb[0].abuf, CBS-2);
  };

nbPutChar(c)
  char c;
  {
  struct CBuf *p;
  p = &tb[0];
  while (!WriteRingBuffer(p, c));
  if (!busy[0] && !RingBufferEmpty(p)) {
    busy[0] = 1;
    SIOPutC(0, ReadRingBuffer(p));
    };
  };

PutChar(c)
  char c;
  {
  PutC(0, c);
  };

PutCRChar(c)
  char c;
  {
  PutChar(c);
  if (c=='\r') PutChar('\n');
  };

PutC(ch, c)
  int ch;
  char c;
  {
  struct CBuf *p;
  p = &tb[ch];
  while (!WriteRingBuffer(p, c)) Block();
  if (!busy[ch] && !RingBufferEmpty(p)) {
    busy[ch] = 1;
    SIOPutC(ch, ReadRingBuffer(p));
    };
  };

int GetChar()
  {
  return(GetC(0));
  };

int GetC(ch)
  int ch;
  {
  struct CBuf *p;
  p = &rb[ch];
  while (RingBufferEmpty(p)) Block();
  return(ReadRingBuffer(p) & 0177);
  };

int Chav()
  {
  return(AvC(0));
  };

int AvC(ch)
  int ch;
  {
  return(!RingBufferEmpty(&rb[ch]));
  };

Baud(mbr, ch)
  int mbr, ch;
  {
  int dr, load, hold;
  if (ch == 0) {  /* use 9513 channel 0 (FOUT) */
    if (mbr == 300) { MM(0x0ac0); WR4(ch, 0x008c); };
    else WR4(ch, 0x4c);
    if (mbr==600) MM(0x0ac0);
    if (mbr==1200) MM(0x088c0);
    if (mbr==2400) MM(0x084c0);
    if (mbr==4800) MM(0x082c0);
    if (mbr==9600) MM(0x08a00);
    if (mbr==19200) MM(0x08500);
    };
  if (ch==1) {  /* use 9513 channel 4 */
    WR4(ch, 0x4c);  /* always use /16 mode */
    mbr = mbr/100;
    dr = 960/mbr;  /* 960 = 15360/16 (16 for 8274 division ratio)  */
    hold = dr/2;
    load = dr-hold;
    OutByte(TimCtl, 0xc8);  /* disarm ch 4 */
    OutByte(TimCtl, 0x04);  /* set data pointer for ch 4 */
    OutWord(TimData, 0x1b62);  /* Mode J, src F1, toggle, count up, binary */
    OutWord(TimData, load);
    OutWord(TimData, hold);
    OutByte(TimCtl, 0x48);  /* load ch 4 */
    OutByte(TimCtl, 0x28);  /* arm ch 4 */
    };
  };

static int iretCode;

static mySIOInt()
  {
  int type;
  /* read RR2 of ch. B to get modified vector */
  type = RR2(1) & 07;
  switch (type) {
    case 0: txe(1); break;
    case 1: CallD(ecInt+2); break;
    case 2: rxa(1); break;
    case 3: sprx(1); break;
    case 4: txe(0); break;
    case 5: CallD(ecInt+3); break;
    case 6: rxa(0); break;
    case 7: sprx(0); break;
    default: CallD(ecInt+1);
    };
  if (iretCode) WR0(0, 0x38);  /* eoi */
  return(iretCode);
  };

CallD(n)
  int n;
  {
  WR0(0, 0x38);  /* eoi */
  DoEOI();
  iretCode = false;
  CallDebugger(n);
  };

static rxa(ch)
  int ch;
  {
  char c;
  iretCode = true;
  c = SIOGetC(ch);
  if (c == 0) CallD(0);
  else WriteRingBuffer(&rb[ch], c);
  };

static txe(ch)
  int ch;
  {
  struct CBuf *p;
  iretCode = true;
  p = &tb[ch];
  if (RingBufferEmpty(p)) {
    WR0(ch, 0x28);
    busy[ch] = 0;
    };
  else SIOPutC(ch, ReadRingBuffer(p));
  };

static sprx(ch)
  int ch;
  {
  iretCode = true;
  WR0(ch, 0xf0);	/* forget it */
  };

static WR0(ch, rv)
  int ch, rv;
  {
  ch = SIOCmdP(ch);
  OutByte(ch, rv&0xff);
  };

static int RR2(ch)
  int ch;
  {
  ch = SIOCmdP(ch);
  OutByte(ch, 2);
  return(InByte(ch) & 0xff);
  };

static SIOGetC(ch)
  int ch;
  {
  ch = SIODataP(ch);
  return(InByte(ch)&0177);
  };

static SIOPutC(ch, v)
  int ch;
  char v;
  {
  ch = SIODataP(ch);
  OutByte(ch, v);
  };

static SIOCmdP(ch)
  int ch;
  {
  if (ch==0) ch = sioctla;
  else ch = sioctlb;
  return(ch);
  };

static SIODataP(ch)
  int ch;
  {
  if (ch==0) ch = siodata;
  else ch = siodatb;
  return(ch);
  };

static MM(rv)
  int rv;
  {
  OutByte(TimCtl, 0x17);
  OutWord(TimData, rv);
  };

static WR4(ch, rv)
  int ch, rv;
  {
  ch = SIOCmdP(ch);
  OutByte(ch, 0x04);
  OutByte(ch, rv&0xff);
  };

static OutWord(port, val)
  int port, val;
  {
  OutByte(port, val&0xff);
  OutByte(port, (val >> 8)&0xff);
  };