...at least peek works now

This commit is contained in:
Jeroen Domburg 2017-10-19 15:53:10 +08:00
parent 931d5ef33c
commit 8c0309aee1
2 changed files with 167 additions and 72 deletions

View File

@ -36,6 +36,9 @@ ddp type 5
data 1
*/
llap_packet_t *bufferedPacket;
int bufferedPacketLen;
void localtalkSend(uint8_t *data, int len) {
llap_packet_t *p=(llap_packet_t*)data;
@ -54,6 +57,12 @@ void localtalkSend(uint8_t *data, int len) {
r->type=LLAP_TYPE_CTS;
sccRecv(1, r, sizeof(llap_packet_t), 3);
}
} else if (p->type==LLAP_TYPE_CTS) {
printf("LocalTalk: CTS %hhu->%hhu\n", p->srcid, p->destid);
if (bufferedPacketLen>0 && p->destid==bufferedPacket->srcid) {
sccRecv(1, bufferedPacket, bufferedPacketLen, 3);
}
bufferedPacketLen=0;
} else if (p->type==LLAP_TYPE_DDP_SHORT) {
printf("Localtalk: DDP short %hhu->%hhu\n", p->srcid, p->destid);
ddp_print(p->data, len-sizeof(llap_packet_t), 0);
@ -74,24 +83,23 @@ void localtalk_send_ddp(uint8_t *data, int len) {
rts.destid=ddp_get_dest_node(data);
rts.srcid=ddp_get_src_node(data);
rts.type=LLAP_TYPE_RTS;
sccRecv(1, &rts, 3, 3);
sccRecv(1, &rts, 3, 60);
//We assume this is a long ddp packet.
#if 0
llap_packet_t *p=alloca(len+sizeof(llap_packet_t));
#if 1
llap_packet_t *p=bufferedPacket;
p->destid=ddp_get_dest_node(data);
p->srcid=ddp_get_src_node(data);
p->type=LLAP_TYPE_DDP_SHORT;
int plen=ddp_long_to_short(data, p->data, len);
sccRecv(1, p, plen+sizeof(llap_packet_t), 2);
bufferedPacketLen=ddp_long_to_short(data, p->data, len);
#else
printf("Localtalk: Sending ddp of len %d for a total of %d\n", len, len+sizeof(llap_packet_t));
llap_packet_t *p=alloca(len+sizeof(llap_packet_t));
llap_packet_t *p=bufferedPacket;
p->destid=ddp_get_dest_node(data);
p->srcid=ddp_get_src_node(data);
p->type=LLAP_TYPE_DDP_LONG;
memcpy(p->data, data, len);
sccRecv(1, p, len+sizeof(llap_packet_t), 2);
bufferedPacketLen=len+sizeof(llap_packet_t);
#endif
}
@ -106,4 +114,6 @@ void localtalkTick() {
void localtalkInit() {
ethertalkInit();
bufferedPacketLen=0;
bufferedPacket=malloc(8192);
}

View File

@ -38,6 +38,10 @@ typedef struct {
int rxDelay;
int eofDelay;
int eofIntPending;
int rr0Latched;
int rr0Prev;
int rxAbrtTimer;
int rxEom;
} SccChan;
typedef struct {
@ -65,11 +69,13 @@ static void triggerRx(int chan);
static int rxHasByte(int chan) {
return (scc.chan[chan].rx[scc.chan[chan].rxBufCur].delay==0);
return (scc.chan[chan].rx[scc.chan[chan].rxBufCur].delay==0)?1:0;
}
static void rxBufIgnoreRest(int chan) {
if (scc.chan[chan].rxPos==0) return; //already at new buff
printf("RxBuff: Skipping to next buff\n");
scc.chan[chan].rx[scc.chan[chan].rxBufCur].delay=-1;
scc.chan[chan].rxBufCur++;
if (scc.chan[chan].rxBufCur>=NO_RXBUF) scc.chan[chan].rxBufCur=0;
@ -95,7 +101,7 @@ static int rxBytesLeft(int chan) {
}
static int rxBufTick(int chan) {
if (scc.chan[chan].rx[scc.chan[chan].rxBufCur].delay>0) {
if (scc.chan[chan].rx[scc.chan[chan].rxBufCur].delay > 0) {
scc.chan[chan].rx[scc.chan[chan].rxBufCur].delay--;
if (scc.chan[chan].rx[scc.chan[chan].rxBufCur].delay==0) {
printf("Feeding buffer %d into SCC\n", scc.chan[chan].rxBufCur);
@ -123,13 +129,22 @@ static int rxBufTick(int chan) {
#define SCC_RR3_CHA_TX (1<<4)
#define SCC_RR3_CHA_RX (1<<5)
#define SCC_R0_RX (1<<0)
#define SCC_R0_ZEROCOUNT (1<<1)
#define SCC_R0_TXE (1<<2)
#define SCC_R0_DCD (1<<3)
#define SCC_R0_SYNCHUNT (1<<4)
#define SCC_R0_CTS (1<<5)
#define SCC_R0_EOM (1<<6)
#define SCC_R0_BREAKABRT (1<<7)
static void explainWrite(int reg, int chan, int val) {
const static char *cmdLo[]={"null", "point_high", "reset_ext_status_int", "send_ABORT",
"ena_int_on_next_char", "reset_tx_pending", "error_reset", "reset_highest_ius"};
const static char *cmdHi[]={"null", "reset_rx_crc", "reset_tx_crc", "reset_tx_underrun_EOM_latch"};
const static char *intEna[]={"RxIntDisabled", "RxInt1stCharOrSpecial", "RxIntAllCharOrSpecial", "RxIntSpecial"};
const static char *rstDesc[]={"NoReset", "ResetChB", "ResetChA", "HwReset"};
if (reg==0 && ((val&0xF8)!=0)) {
if (reg==0) {
if (((val&0xF8)!=0) && ((val&0xF8)!=0x08)) {
printf("Write reg 0; CmdHi=%s CmdLo=%s\n", cmdHi[(val>>6)&3], cmdLo[(val>>3)&7]);
}
@ -165,6 +180,30 @@ static void explainWrite(int reg, int chan, int val) {
}
}
void explainRead(int reg, int chan, int val) {
const static char *intRsn[]={
"ChBTxBufEmpty", "ChBExtOrStatusChange", "ChBRecvCharAvail", "ChBSpecRecvCond",
"ChATxBufEmpty", "ChAExtOrStatusChange", "ChARecvCharAvail", "ChASpecRecvCond",
};
if (reg==0) {
printf("Read chan %d reg 0:", chan);
if (val&0x01) printf("RxCharAvailable ");
if (val&0x02) printf("ZeroCount ");
if (val&0x04) printf("TxBufEmpty ");
if (val&0x08) printf("DCD ");
if (val&0x10) printf("SyncHunt ");
if (val&0x20) printf("CTS ");
if (val&0x40) printf("TxUnderrunEOM ");
if (val&0x80) printf("BreakAbort ");
printf("\n");
} else if (reg==2) {
printf("Read reg 2: ");
printf("IntRsn=%s\n", intRsn[(val>>1)&7]);
} else {
printf("Read chan %d reg %d val 0x%X\n", chan, reg, val);
}
}
//Raises an interrupt if needed, specifically when intpending indicates so. Need to
//change intpending beforehand.
static void raiseInt(int chan) {
@ -180,22 +219,53 @@ static void raiseInt(int chan) {
}
}
void sccSetDcd(int chan, int val) {
val=val?1:0;
if (scc.chan[chan].dcd!=val) {
if (chan==SCC_CHANA) {
if (scc.chan[SCC_CHANA].wr15&SCC_WR15_DCD) {
scc.intpending|=SCC_RR3_CHA_EXT;
raiseInt(SCC_CHANA);
}
} else {
if (scc.chan[SCC_CHANB].wr15&SCC_WR15_DCD) {
scc.intpending|=SCC_RR3_CHB_EXT;
raiseInt(SCC_CHANB);
}
static int calcRr0(int chan) {
int val=0;
if (rxHasByte(chan)) val|=SCC_R0_RX;
//Bit 1 is zero count - never set
val|=SCC_R0_TXE; //tx buffer always empty
val|=SCC_R0_CTS;
if (scc.chan[chan].dcd) val|=SCC_R0_DCD;
if (scc.chan[chan].hunting) val|=SCC_R0_SYNCHUNT;
if (scc.chan[chan].cts) val|=SCC_R0_CTS;
if (scc.chan[chan].txTimer==0) val|=SCC_R0_EOM;
if (scc.chan[chan].rxAbrtTimer>0 && scc.chan[chan].rxAbrtTimer<20) val|=SCC_R0_BREAKABRT; //abort
//if (rxBytesLeft(chan)==1) val|=SCC_R0_BREAKABRT; //abort
//if (scc.chan[chan].rxEom) val|=SCC_R0_BREAKABRT; //abort
return val;
}
static void checkExtInt(int chan) {
int rr0=calcRr0(chan);
int dif=(rr0^scc.chan[chan].rr0Prev);
int wr15=scc.chan[chan].wr15;
int triggered=0;
if ((dif&SCC_R0_BREAKABRT) && (wr15&SCC_WR15_BREAK)) triggered=1;
if ((dif&SCC_R0_CTS) && (wr15&SCC_WR15_CTS)) triggered=1;
if ((dif&SCC_R0_DCD) && (wr15&SCC_WR15_DCD)) triggered=1;
if ((dif&SCC_R0_SYNCHUNT) && (wr15&SCC_WR15_SYNC)) triggered=1;
if ((dif&SCC_R0_EOM) && (wr15&SCC_WR15_TXU)) triggered=1;
if (triggered) {
if (chan==0 && ((scc.intpending&SCC_RR3_CHA_EXT)==0)) {
scc.chan[chan].rr0Latched=rr0;
scc.intpending|=SCC_RR3_CHA_EXT;
raiseInt(chan);
}
if (chan==1 && ((scc.intpending&SCC_RR3_CHB_EXT)==0)) {
scc.chan[chan].rr0Latched=rr0;
scc.intpending|=SCC_RR3_CHB_EXT;
raiseInt(chan);
}
}
scc.chan[chan].rr0Prev=rr0;
}
void sccSetDcd(int chan, int val) {
val=val?1:0;
scc.chan[chan].dcd=val;
checkExtInt(chan);
}
void sccRecv(int chan, uint8_t *data, int len, int delay) {
@ -218,8 +288,9 @@ void sccRecv(int chan, uint8_t *data, int len, int delay) {
memcpy(scc.chan[chan].rx[bufid].data, data, len);
scc.chan[chan].rx[bufid].data[len]=0xA5; //crc1
scc.chan[chan].rx[bufid].data[len+1]=0xA5; //crc2
scc.chan[chan].rx[bufid].data[len+2]=0; //abort
scc.chan[chan].rx[bufid].len=len+3;
// scc.chan[chan].rx[bufid].data[len+2]=0; //end flag
// scc.chan[chan].rx[bufid].data[len+3]=0; //dummy
scc.chan[chan].rx[bufid].len=len+2;
scc.chan[chan].rx[bufid].delay=delay;
}
@ -231,12 +302,22 @@ void sccTxFinished(int chan) {
// triggerRx(chan);
scc.chan[chan].txPos=0;
scc.chan[chan].hunting=1;
//scc.chan[chan].hunting=1;
}
static void checkRxIntPending(int chan) {
int rxintena=scc.chan[chan].wr1&0x18;
if (!rxHasByte(chan) || rxintena==0) { //todo: better rxintena handling
scc.intpending&=~((chan==0)?SCC_RR3_CHA_RX:SCC_RR3_CHB_RX);
printf("Resetting int pending for channel %d\n", chan);
} else {
scc.intpending|=((chan==0)?SCC_RR3_CHA_RX:SCC_RR3_CHB_RX);
}
raiseInt(chan);
}
static void triggerRx(int chan) {
if (!scc.chan[chan].hunting) return;
// if (!scc.chan[chan].hunting) return;
int bufid=scc.chan[chan].rxBufCur;
printf("SCC: Receiving bufid %d:\n", bufid);
hexdump(scc.chan[chan].rx[bufid].data, scc.chan[chan].rx[bufid].len);
@ -245,15 +326,11 @@ static void triggerRx(int chan) {
printf("WR15: 0x%X WR1: %X\n", scc.chan[chan].wr15, scc.chan[chan].wr1);
//Sync int
if (scc.chan[chan].wr15&SCC_WR15_SYNC) {
scc.intpending|=(chan?SCC_RR3_CHA_EXT:SCC_RR3_CHB_EXT);
scc.intpending|=((chan==0)?SCC_RR3_CHA_EXT:SCC_RR3_CHB_EXT);
raiseInt(chan);
}
//RxD int
int rxintena=scc.chan[chan].wr1&0x18;
if (rxintena==0x10 || rxintena==0x08) {
scc.intpending|=(chan?SCC_RR3_CHA_RX:SCC_RR3_CHB_RX);
raiseInt(chan);
}
checkRxIntPending(chan);
scc.chan[chan].hunting=0;
scc.chan[chan].eofDelay=scc.chan[chan].rx[bufid].len*3;
} else {
@ -278,18 +355,25 @@ void sccWrite(unsigned int addr, unsigned int val) {
scc.regptr=val&0x7;
if ((val&0x38)==0x8) scc.regptr|=8;
if ((val&0x38)==0x10) {
scc.intpending=0;
scc.intpendingOld=0;
//Reset ext/status int latch
scc.chan[chan].rr0Latched=-1;
}
if ((val&0x38)==0x18) {
//SCC abort: parse whatever we sent
// printf("SCC ABORT: Sent data\n");
sccTxFinished(chan);
checkRxIntPending(chan);
}
if ((val&0x38)==0x30) {
//Error Reset: kills special condition bytes from fifo
rxBufIgnoreRest(chan);
checkRxIntPending(chan);
printf("Error Reset Finished, pending=%x\n", scc.intpending);
}
if ((val&0xc0)==0xC0) {
//reset tx underrun latch
// sccTxFinished(chan);
scc.chan[chan].txTimer=1;
scc.chan[chan].txTimer=10;
//if (scc.chan[chan].txTimer==0) scc.chan[chan].txTimer=-1;
}
} else if (reg==1) {
@ -304,14 +388,15 @@ void sccWrite(unsigned int addr, unsigned int val) {
scc.chan[chan].sdlcaddr=val;
} else if (reg==8) {
scc.chan[chan].txData[scc.chan[chan].txPos++]=val;
// printf("TX! Pos %d\n", scc.chan[chan].txPos);
scc.chan[chan].txTimer+=30;
printf("TX! Pos %d timer set to %d\n", scc.chan[chan].txPos, scc.chan[chan].txTimer);
} else if (reg==9) {
scc.wr9=val;
} else if (reg==15) {
scc.chan[chan].wr15=val;
raiseInt(chan);
}
checkExtInt(chan);
// printf("SCC: write to addr %x chan %d reg %d val %x\n", addr, chan, reg, val);
}
@ -328,44 +413,44 @@ unsigned int sccRead(unsigned int addr) {
scc.regptr=0;
}
if (reg==0) {
//Actually, the bits in this register that have an associated external/status int will be
//latched when that int is triggered. Yah...
if (rxHasByte(chan)) val|=(1<<0);
//Bit 1 is zero count - never set
val=(1<<2); //tx buffer always empty
if (scc.chan[chan].dcd) val|=(1<<3);
if (scc.chan[chan].hunting) val|=(1<<4);
if (scc.chan[chan].cts) val|=(1<<5);
if (scc.chan[chan].txTimer==0) val|=(1<<6);
if (rxBytesLeft(chan)<=2) val|=(1<<7); //abort
if (scc.chan[chan].rr0Latched==-1) {
val=calcRr0(chan);
} else {
val=scc.chan[chan].rr0Latched;
scc.chan[chan].rr0Latched=-1;
}
} else if (reg==1) {
//Actually, these come out of the same fifo as the data, so this status should be for the fifo
//val available.
//EndOfFrame, CRCErr, RXOverrun, ParityErr, Residue0, Residue1, Residue2, AllSent
val=0x7; //residue code 011, all sent
if (rxBytesLeft(chan)==1) val|=(1<<7); //end of frame
//if (rxBytesLeft(chan)==1) val|=(1<<7); //end of frame
if (scc.chan[chan].rxEom) val|=(1<<7); //end of frame
} else if (reg==2 && chan==SCC_CHANB) {
//We assume this also does an intack.
int rsn=0;
printf("Pending: 0x%X\n", scc.intpending);
if (scc.intpending & SCC_RR3_CHB_EXT) {
rsn=1;
scc.intpending&=~SCC_RR3_CHB_EXT;
} else if (scc.intpending & SCC_RR3_CHA_EXT) {
rsn=5;
scc.intpending&=~SCC_RR3_CHA_EXT;
} else if (scc.intpending&SCC_RR3_CHA_RX) {
} else if (scc.intpending & SCC_RR3_CHA_RX) {
rsn=6;
scc.intpending&=~SCC_RR3_CHA_RX;
} else if (scc.intpending&SCC_RR3_CHB_RX) {
checkRxIntPending(0);
} else if (scc.intpending & SCC_RR3_CHB_RX) {
rsn=2;
scc.intpending&=~SCC_RR3_CHA_RX;
checkRxIntPending(1);
}
printf("Rsn: %d\n", rsn);
val=scc.wr2;
if (scc.wr9&0x10) { //hi/lo
val=(scc.wr2&~0x70)|rsn<<4;
} else {
val=(scc.wr2&~0xD)|rsn<<1;
val=(scc.wr2&~0xE)|rsn<<1;
}
if (scc.intpending&0x38) raiseInt(SCC_CHANA);
if (scc.intpending&0x07) raiseInt(SCC_CHANB);
@ -377,30 +462,29 @@ unsigned int sccRead(unsigned int addr) {
if (rxHasByte(chan)) {
int left;
val=rxByte(chan, &left);
printf("SCC READ val %x, %d bytes left\n", val, left);
if (left!=0) {
int rxintena=scc.chan[chan].wr1&0x18;
if (rxintena==0x10) {
scc.intpending|=(chan?SCC_RR3_CHA_RX:SCC_RR3_CHB_RX);
raiseInt(chan);
}
}
if (left==1) scc.chan[chan].hunting=1;
if (left==1 && scc.chan[chan].wr15&SCC_WR15_BREAK) {
scc.intpending|=(chan?SCC_RR3_CHA_EXT:SCC_RR3_CHB_EXT);
raiseInt(chan);
printf("SCC READ DATA val %x, %d bytes left\n", val, left);
if (left==1) { //because status goes with byte *to be read*, the last byte here is the EOM byte
printf("Setting EOM\n");
scc.chan[chan].rxEom=1;
scc.chan[chan].rxAbrtTimer=20;
} else {
scc.chan[chan].rxEom=0;
}
// if (left==1) scc.chan[chan].hunting=1;
} else {
printf("SCC READ but no data?\n");
scc.chan[chan].rxEom=0;
val=0;
}
checkRxIntPending(chan);
} else if (reg==10) {
//Misc status (mostly SDLC)
val=0;
} else if (reg==15) {
val=scc.chan[chan].wr15;
}
printf("SCC: read from chan %d reg %d val %x\n", chan, reg, val);
checkExtInt(chan);
explainRead(reg, chan, val);
return val;
}
@ -426,18 +510,19 @@ void sccTick() {
scc.intpending|=((n==0)?SCC_RR3_CHA_RX:SCC_RR3_CHB_RX);
raiseInt(n);
}
//Break/Abort
scc.intpending|=(n?SCC_RR3_CHA_EXT:SCC_RR3_CHB_EXT);
raiseInt(n);
}
if (scc.chan[n].rxAbrtTimer>0) scc.chan[n].rxAbrtTimer--;
checkExtInt(n);
}
}
void sccInit() {
sccSetDcd(0, 1);
sccSetDcd(1, 1);
sccSetDcd(2, 1);
scc.chan[0].txTimer=-1;
scc.chan[1].txTimer=-1;
// scc.chan[0].txTimer=-1;
// scc.chan[1].txTimer=-1;
scc.chan[0].rr0Latched=-1;
scc.chan[1].rr0Latched=-1;
for (int x=0; x<NO_RXBUF; x++) {
scc.chan[0].rx[x].delay=-1;
scc.chan[1].rx[x].delay=-1;