minimacplus/components/tme/scc.c

134 lines
3.2 KiB
C

#include <stdio.h>
#include <stdint.h>
#include "scc.h"
#include "m68k.h"
/*
THis is an extremely minimal SCC implementation: it only somewhat implements the interrupt mechanism for the
DCD pins because that is what is needed for the mouse to work.
*/
void sccIrq(int ena);
typedef struct {
int regptr;
int intpending;
int intpendingOld;
int dcd[2];
int cts[2];
int wr1[2];
int wr15[2];
} Scc;
static Scc scc;
//WR15 is the External/Status Interrupt Control and has the interrupt enable bits.
#define SCC_WR15_BREAK (1<<7)
#define SCC_WR15_TXU (1<<6)
#define SCC_WR15_CTS (1<<5)
#define SCC_WR15_SYNC (1<<4)
#define SCC_WR15_DCD (1<<3)
#define SCC_WR15_ZCOUNT (1<<1)
//WR3, when read, gives the Interrupt Pending status.
//This is reflected in scc.intpending.
#define SCC_WR3_CHB_EXT (1<<0)
#define SCC_WR3_CHB_TX (1<<1)
#define SCC_WR3_CHB_RX (1<<2)
#define SCC_WR3_CHA_EXT (1<<3)
#define SCC_WR3_CHA_TX (1<<4)
#define SCC_WR3_CHA_RX (1<<5)
static void raiseInt(int chan) {
if ((scc.wr1[chan]&1) && (scc.intpending&(~scc.intpendingOld))) {
scc.intpendingOld=scc.intpending;
printf("SCC int, pending %x\n", scc.intpending);
sccIrq(1);
}
}
void sccSetDcd(int chan, int val) {
val=val?1:0;
if (scc.dcd[chan]!=val) {
if (chan==SCC_CHANA) {
scc.intpending|=SCC_WR3_CHA_EXT;
} else {
scc.intpending|=SCC_WR3_CHB_EXT;
}
}
if ((scc.intpending&SCC_WR3_CHA_EXT) && (scc.wr15[SCC_CHANA]&SCC_WR15_DCD)) raiseInt(SCC_CHANA);
if ((scc.intpending&SCC_WR3_CHB_EXT) && (scc.wr15[SCC_CHANB]&SCC_WR15_DCD)) raiseInt(SCC_CHANB);
if ((scc.intpending&SCC_WR3_CHA_EXT) && (scc.wr15[SCC_CHANA]&SCC_WR15_CTS)) raiseInt(SCC_CHANA);
if ((scc.intpending&SCC_WR3_CHB_EXT) && (scc.wr15[SCC_CHANB]&SCC_WR15_CTS)) raiseInt(SCC_CHANB);
scc.dcd[chan]=val;
}
void sccWrite(unsigned int addr, unsigned int val) {
int chan, reg;
if (addr & (1<<1)) chan=SCC_CHANA; else chan=SCC_CHANB;
if (addr & (1<<2)) {
//Data
reg=8;
} else {
//Control
reg=scc.regptr;
scc.regptr=0;
}
if (reg==0) {
scc.regptr=val&0x7;
if ((val&0x38)==0x8) scc.regptr|=8;
if ((val&0x38)==0x10) {
scc.intpending=0;
scc.intpendingOld=0;
}
} else if (reg==1) {
scc.wr1[chan]=val;
} else if (reg==15) {
scc.wr15[chan]=val;
}
// printf("SCC: write to addr %x chan %d reg %d val %x\n", addr, chan, reg, val);
}
unsigned int sccRead(unsigned int addr) {
int chan, reg, val=0xff;
if (addr & (1<<1)) chan=SCC_CHANA; else chan=SCC_CHANB;
if (addr & (1<<2)) {
//Data
reg=8;
} else {
//Control
reg=scc.regptr;
scc.regptr=0;
}
if (reg==0) {
val=(1<<2);
if (scc.dcd[chan]) val|=(1<<3);
if (scc.cts[chan]) val|=(1<<5);
} else if (reg==1) {
val=scc.wr1[chan];
} else if (reg==2 && chan==SCC_CHANB) {
//We assume this also does an intack.
int rsn=0;
if (scc.intpending & SCC_WR3_CHB_EXT) {
rsn=1;
scc.intpending&=~SCC_WR3_CHB_EXT;
}
if (scc.intpending & SCC_WR3_CHA_EXT) {
rsn=5;
scc.intpending&=~SCC_WR3_CHA_EXT;
}
val=rsn<<1;
if (scc.intpending&0x38) raiseInt(SCC_CHANA);
if (scc.intpending&0x07) raiseInt(SCC_CHANB);
} else if (reg==3) {
if (chan==SCC_CHANA) val=scc.intpending; else val=0;
} else if (reg==15) {
val=scc.wr15[chan];
}
printf("SCC: read from chan %d reg %d val %x\n", chan, reg, val);
return val;
}