From 8c0309aee103998e70fb91e27c4245e5728d5392 Mon Sep 17 00:00:00 2001 From: Jeroen Domburg Date: Thu, 19 Oct 2017 15:53:10 +0800 Subject: [PATCH] ...at least peek works now --- components/tme/network/localtalk.c | 24 +++- components/tme/scc.c | 215 ++++++++++++++++++++--------- 2 files changed, 167 insertions(+), 72 deletions(-) diff --git a/components/tme/network/localtalk.c b/components/tme/network/localtalk.c index 4817c79..0ef91d5 100644 --- a/components/tme/network/localtalk.c +++ b/components/tme/network/localtalk.c @@ -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); } diff --git a/components/tme/scc.c b/components/tme/scc.c index 4ec5cbf..5bf2ade 100644 --- a/components/tme/scc.c +++ b/components/tme/scc.c @@ -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