From fc11fb4e85e179bf911fc264e8592935bda94fff Mon Sep 17 00:00:00 2001 From: Jeroen Domburg Date: Tue, 17 Oct 2017 21:43:20 +0800 Subject: [PATCH] Add sound, LocalTalk hackery --- components/tme-esp32/hexdump.c | 50 ++++++ components/tme/Makefile | 7 +- components/tme/component.mk | 2 +- components/tme/emu.c | 21 ++- components/tme/localtalk.c | 18 --- components/tme/localtalk.h | 7 - components/tme/ncr.c | 24 +-- components/tme/network/Makefile | 11 ++ components/tme/network/basiliskif.c | 67 ++++++++ components/tme/network/basiliskif.h | 11 ++ components/tme/network/ddp.c | 130 ++++++++++++++++ components/tme/network/ddp.h | 15 ++ components/tme/network/etalktst | Bin 0 -> 14168 bytes components/tme/network/ethertalk.c | 229 ++++++++++++++++++++++++++++ components/tme/network/ethertalk.h | 12 ++ components/tme/network/hexdump.c | 64 ++++++++ components/tme/network/hexdump.h | 7 + components/tme/network/localtalk.c | 109 +++++++++++++ components/tme/network/localtalk.h | 10 ++ components/tme/network/sniff.c | 56 +++++++ components/tme/network/sniff.h | 2 + components/tme/scc.c | 193 +++++++++++++++++------ components/tme/scc.h | 2 +- components/tme/sdl/disp.c | 2 +- components/tme/sdl/hd.c | 4 +- components/tme/sdl/main.c | 2 +- components/tme/sdl/snd.c | 55 +++++++ components/tme/snd.h | 5 + components/tme/tmeconfig.h | 5 +- sdkconfig | 12 +- 30 files changed, 1031 insertions(+), 101 deletions(-) create mode 100644 components/tme-esp32/hexdump.c delete mode 100644 components/tme/localtalk.c delete mode 100644 components/tme/localtalk.h create mode 100644 components/tme/network/Makefile create mode 100644 components/tme/network/basiliskif.c create mode 100644 components/tme/network/basiliskif.h create mode 100644 components/tme/network/ddp.c create mode 100644 components/tme/network/ddp.h create mode 100755 components/tme/network/etalktst create mode 100644 components/tme/network/ethertalk.c create mode 100644 components/tme/network/ethertalk.h create mode 100644 components/tme/network/hexdump.c create mode 100644 components/tme/network/hexdump.h create mode 100644 components/tme/network/localtalk.c create mode 100644 components/tme/network/localtalk.h create mode 100644 components/tme/network/sniff.c create mode 100644 components/tme/network/sniff.h create mode 100644 components/tme/sdl/snd.c create mode 100644 components/tme/snd.h diff --git a/components/tme-esp32/hexdump.c b/components/tme-esp32/hexdump.c new file mode 100644 index 0000000..89ce844 --- /dev/null +++ b/components/tme-esp32/hexdump.c @@ -0,0 +1,50 @@ +#include +#include + +#ifndef HEXDUMP_COLS +#define HEXDUMP_COLS 8 +#endif + +void hexdump(void *mem, unsigned int len) +{ + unsigned int i, j; + + for(i = 0; i < len + ((len % HEXDUMP_COLS) ? (HEXDUMP_COLS - len % HEXDUMP_COLS) : 0); i++) + { + /* print offset */ + if(i % HEXDUMP_COLS == 0) + { + printf("0x%06x: ", i); + } + /* print hex data */ + if(i < len) + { + printf("%02x ", 0xFF & ((char*)mem)[i]); + } + else /* end of block, just aligning for ASCII dump */ + { + printf(" "); + } + + /* print ASCII dump */ + if(i % HEXDUMP_COLS == (HEXDUMP_COLS - 1)) + { + for(j = i - (HEXDUMP_COLS - 1); j <= i; j++) + { + if(j >= len) /* end of block, not really printing */ + { + putchar(' '); + } + else if(isprint(((unsigned char*)mem)[j])) /* printable char */ + { + putchar(0xFF & ((unsigned char*)mem)[j]); + } + else /* other char */ + { + putchar('.'); + } + } + putchar('\n'); + } + } +} diff --git a/components/tme/Makefile b/components/tme/Makefile index 40ebd2d..e4639e4 100644 --- a/components/tme/Makefile +++ b/components/tme/Makefile @@ -3,10 +3,11 @@ TARGET:=tme MUSASHI_GEN_SRC:=musashi/m68kopac.c musashi/m68kopdm.c musashi/m68kopnz.c MUSASHI_OP_PREGEN_SRC:=musashi/m68kops_pre.c -OBJ:=$(MUSASHI_GEN_SRC:%.x=%.o) $(MUSASHI_OP_PREGEN_SRC:%.x=%.o) musashi/m68kcpu.o sdl/main.o sdl/disp.o sdl/hd.o \ - emu.o iwm.o via.o rtc.o ncr.o scc.o mouse.o hostbuild/espspiramemu.o hexdump.o localtalk.o +OBJ:=$(MUSASHI_GEN_SRC:%.x=%.o) $(MUSASHI_OP_PREGEN_SRC:%.x=%.o) musashi/m68kcpu.o sdl/main.o sdl/disp.o sdl/hd.o sdl/snd.o \ + emu.o iwm.o via.o rtc.o ncr.o scc.o mouse.o hostbuild/espspiramemu.o hexdump.o network/localtalk.o network/ddp.o \ + network/ethertalk.o network/basiliskif.o network/sniff.o #musashi/m68kdasm.o -CFLAGS=-Wall -I. -I./musashi -I./hostbuild -Og -ggdb `sdl2-config --cflags` +CFLAGS=-Wall -I. -I./musashi -I./hostbuild -Og -ggdb `sdl2-config --cflags` -DHOSTBUILD LDFLAGS=`sdl2-config --libs` $(TARGET): $(OBJ) diff --git a/components/tme/component.mk b/components/tme/component.mk index ef1bea5..d6a0b68 100644 --- a/components/tme/component.mk +++ b/components/tme/component.mk @@ -8,7 +8,7 @@ COMPONENT_SRCDIRS := . musashi MUSASHI_GEN_SRC := musashi/m68kops_pre.c musashi/m68kopac.c musashi/m68kopdm.c musashi/m68kopnz.c MUSASHI_GEN_OBJ := $(MUSASHI_GEN_SRC:%.c=%.o) COMPONENT_OBJS := musashi/m68kops_pre.o musashi/m68kopac.o musashi/m68kopdm-iram.o musashi/m68kopnz.o musashi/m68kcpu.o emu.o \ - iwm.o via.o rtc.o ncr.o scc.o mouse.o localtalk.o + iwm.o via.o rtc.o ncr.o scc.o mouse.o network/localtalk.o network/ddp.o network/ethertalk.o #nothing in iram: 16% #ac nz in iram: 19% diff --git a/components/tme/emu.c b/components/tme/emu.c index 39df375..53ba515 100644 --- a/components/tme/emu.c +++ b/components/tme/emu.c @@ -17,12 +17,13 @@ #include "rtc.h" #include "ncr.h" #include "hd.h" +#include "snd.h" #include "mouse.h" #include #include "esp_heap_caps.h" #include #include "esp_spiram.h" - +#include "network/localtalk.h" unsigned char *macRom; @@ -36,7 +37,7 @@ unsigned char *macRam; #define MEMADDR_DUMMY_CACHE (void*)1 -int rom_remap, video_remap=0, audio_remap=0; +int rom_remap, video_remap=0, audio_remap=0, audio_volume=0, audio_en=0; void m68k_instruction() { unsigned int pc=m68k_get_reg(NULL, M68K_REG_PC); @@ -193,7 +194,7 @@ static void regenMemmap(int remapRom) { } } -uint8_t *macFb[2]; +uint8_t *macFb[2], *macSnd[2]; #if (USE_EXTERNAL_RAM) @@ -330,6 +331,8 @@ static void ramInit() { assert(macRam); macFb[0]=&macRam[TME_SCREENBUF]; macFb[1]=&macRam[TME_SCREENBUF_ALT]; + macSnd[0]=&macRam[TME_SNDBUF]; + macSnd[1]=&macRam[TME_SNDBUF_ALT]; printf("Clearing ram...\n"); for (int x=0; x -#include -#include -#include "hexdump.h" -#include "scc.h" - -void localtalkSend(uint8_t *data, int len) { - uint8_t resp[128]; - if (data[2]==0x81) { - resp[0]=data[1]; - resp[1]=data[0]; - resp[2]=0x82; - sccRecv(1, resp, 3); - printf("LocalTalk: Sent ack\n"); - } else { - printf("LocalTalk... errm... dunno what to do with this (cmd=%x).\n", data[2]); - } -} diff --git a/components/tme/localtalk.h b/components/tme/localtalk.h deleted file mode 100644 index ecbd1f8..0000000 --- a/components/tme/localtalk.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef LOCALTALK_H -#define LOCALTALK_H - -void localtalkSend(uint8_t *data, int len); - - -#endif \ No newline at end of file diff --git a/components/tme/ncr.c b/components/tme/ncr.c index 84b0db0..29ff4ee 100644 --- a/components/tme/ncr.c +++ b/components/tme/ncr.c @@ -95,19 +95,19 @@ static void parseScsiCmd(int isRead) { len=buf[4]; if (len==0) len=256; ctrl=buf[5]; - for (int x=0; x<6; x++) printf("%02X ", buf[x]); - printf("\n"); +// for (int x=0; x<6; x++) printf("%02X ", buf[x]); +// printf("\n"); } else if (group==1 || group==2) { //10-byte command lba=buf[5]|(buf[4]<<8)|(buf[3]<<16)|(buf[2]<<24); len=buf[8]|(buf[7]<<8); ctrl=buf[9]; - for (int x=0; x<10; x++) printf("%02X ", buf[x]); - printf("\n"); +// for (int x=0; x<10; x++) printf("%02X ", buf[x]); +// printf("\n"); } else { printf("SCSI: UNSUPPORTED CMD %x\n", cmd); return; } - printf("SCSI: CMD %x LBA %x LEN %x CTRL %x %s\n", cmd, lba, len, ctrl, isRead?"*READ*":"*WRITE*"); +// printf("SCSI: CMD %x LBA %x LEN %x CTRL %x %s\n", cmd, lba, len, ctrl, isRead?"*READ*":"*WRITE*"); if (ncr.dev[ncr.selected]) { ncr.datalen=ncr.dev[ncr.selected]->scsiCmd(&ncr.data, cmd, len, lba, ncr.dev[ncr.selected]->arg); } @@ -160,7 +160,7 @@ unsigned int ncrRead(unsigned int addr, unsigned int dack) { if (ncr.mode&MODE_DMA) { ret|=BSR_DMARQ; if (ncr.bufpos>=ncr.datalen) { - printf("End of DMA reached: bufpos %d datalen %d\n", ncr.bufpos, ncr.datalen); +// printf("End of DMA reached: bufpos %d datalen %d\n", ncr.bufpos, ncr.datalen); ret|=BSR_EODMA; } } @@ -198,7 +198,7 @@ void ncrWrite(unsigned int addr, unsigned int dack, unsigned int val) { if (ncr.dout==0x90) ncr.selected=4; if (ncr.dout==0xA0) ncr.selected=5; if (ncr.dout==0xC0) ncr.selected=6; - printf("Selected dev: %d (val %x)\n", ncr.selected, ncr.dout); +// printf("Selected dev: %d (val %x)\n", ncr.selected, ncr.dout); } if (((val&INI_BSY)==0) && ncr.state==ST_SELECT) { ncr.state=ST_SELDONE; @@ -220,7 +220,7 @@ void ncrWrite(unsigned int addr, unsigned int dack, unsigned int val) { //Ack line goes low.. if (ncr.tcr&TCR_IO) { if (ncr.bufpos!=ncr.bufmax) ncr.din=ncr.buf[ncr.bufpos++]; - printf("Send byte non-dma\n"); +// printf("Send byte non-dma\n"); } } if (val&INI_RST) { @@ -244,21 +244,21 @@ void ncrWrite(unsigned int addr, unsigned int dack, unsigned int val) { parseScsiCmd(1); } if ((ncr.tcr&0x7)==TCR_IO) { - printf("Data Out finished: Host read %d/%d bytes.\n", ncr.bufpos, ncr.datalen); +// printf("Data Out finished: Host read %d/%d bytes.\n", ncr.bufpos, ncr.datalen); } ncr.bufpos=0; int type=val&(TCR_MSG|TCR_CD); if (type==0) { - printf("Sel data buf %s.\n", (newtcr&TCR_IO)?"IN":"OUT"); +// printf("Sel data buf %s.\n", (newtcr&TCR_IO)?"IN":"OUT"); ncr.buf=ncr.data.data; ncr.bufmax=sizeof(ncr.data.data); } else if (type==TCR_CD) { - printf("Sel cmd/status buf %s.\n", (newtcr&TCR_IO)?"IN":"OUT"); +// printf("Sel cmd/status buf %s.\n", (newtcr&TCR_IO)?"IN":"OUT"); ncr.buf=ncr.data.cmd; ncr.bufmax=sizeof(ncr.data.cmd); ncr.datalen=1; } else if (type==(TCR_CD|TCR_MSG)) { - printf("Sel msg buf %s.\n", (newtcr&TCR_IO)?"IN":"OUT"); +// printf("Sel msg buf %s.\n", (newtcr&TCR_IO)?"IN":"OUT"); ncr.buf=ncr.data.msg; ncr.bufmax=sizeof(ncr.data.msg); ncr.datalen=1; diff --git a/components/tme/network/Makefile b/components/tme/network/Makefile new file mode 100644 index 0000000..57f5ce7 --- /dev/null +++ b/components/tme/network/Makefile @@ -0,0 +1,11 @@ +#Makes test app. + +OBJS:=basiliskif.o ethertalk.o hexdump.o +TARGET:=etalktst +CFLAGS:=-DTESTAPP + +$(TARGET): $(OBJS) + $(CC) -o $@ $^ $(LDFLAGS) + +clean: + rm -f $(TARGET) $(OBJS) diff --git a/components/tme/network/basiliskif.c b/components/tme/network/basiliskif.c new file mode 100644 index 0000000..f90635e --- /dev/null +++ b/components/tme/network/basiliskif.c @@ -0,0 +1,67 @@ +#include +#include +#include +#include +#include +#include +#include +#include "basiliskif.h" + +#define PORT 6066 //default BasiliskII network poer + +int sock; + +int basiliskIfInit() { + //Make socket + sock=socket(AF_INET, SOCK_DGRAM, 0); + if (socket<0) { + printf("Couldn't create socket\n"); + return 0; + } + + int broadcastEnable=1; + setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &broadcastEnable, sizeof(broadcastEnable)); + int reuse=1; + setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)); + + struct sockaddr_in si; + memset((char *) &si, 0, sizeof(si)); + si.sin_family = AF_INET; + si.sin_port = htons(PORT); + si.sin_addr.s_addr = htonl(INADDR_ANY); + //bind socket to port + if (bind(sock, (struct sockaddr*)&si, sizeof(si)) == -1) { + printf("Error binding to port\n"); + return 0; + } + + return 1; +} + +int basiliskIfRecv(uint8_t *buf, int len) { + fd_set fds; + FD_ZERO(&fds); + FD_SET(sock, &fds); + struct timeval tout; + memset(&tout, 0, sizeof(tout)); + int r=select(sock+1, &fds, NULL, NULL, &tout); + if (r>0) { + int l=read(sock, buf, len); + return l; + } else { + return 0; + } +} + +int basiliskIfSend(uint8_t *buf, int len) { + struct sockaddr_in sin; + memset(&sin, 0, sizeof(struct sockaddr_in)); + sin.sin_family = AF_INET; + sin.sin_port = (in_port_t)htons(PORT); + sin.sin_addr.s_addr = htonl(INADDR_BROADCAST); + + int r=sendto(sock, buf, len, 0, (struct sockaddr *)&sin, sizeof(struct sockaddr_in)); + if (r<0) { + perror("sendto"); + } +} diff --git a/components/tme/network/basiliskif.h b/components/tme/network/basiliskif.h new file mode 100644 index 0000000..0b99bd4 --- /dev/null +++ b/components/tme/network/basiliskif.h @@ -0,0 +1,11 @@ +#ifndef BASILISKIF_H +#define BASILISKIF_H + +#include + +int basiliskIfInit(); +int basiliskIfRecv(uint8_t *buf, int len); +int basiliskIfSend(uint8_t *buf, int len); + + +#endif \ No newline at end of file diff --git a/components/tme/network/ddp.c b/components/tme/network/ddp.c new file mode 100644 index 0000000..2497fbc --- /dev/null +++ b/components/tme/network/ddp.c @@ -0,0 +1,130 @@ +#include +#include +#include +#include + +typedef struct { + uint16_t len; //Note: of DDP header plus payload + uint8_t dest_sock; + uint8_t src_sock; + uint8_t type; + uint8_t data[]; +} __attribute__((packed)) ddp_short_t; + +typedef struct { + uint16_t len; //Note: of DDP header plus payload + uint16_t chsum; + uint16_t dest_net; + uint16_t src_net; + uint8_t dest_node; + uint8_t src_node; + uint8_t dest_sock; + uint8_t src_sock; + uint8_t type; + uint8_t data[]; +} __attribute__((packed)) ddp_long_t; + +#define DDP_TYPE_NBP 2 + +int ddp_get_dest_node(void *ddp) { + ddp_long_t *p=(ddp_long_t*)ddp; + return p->dest_node; +} + +int ddp_get_src_node(void *ddp) { + ddp_long_t *p=(ddp_long_t*)ddp; + return p->src_node; +} + +int ddp_get_src_net(void *ddp) { + ddp_long_t *p=(ddp_long_t*)ddp; + return ntohs(p->src_net); +} + +typedef struct { + uint8_t fn_count; + uint8_t id; +} nbd_hdr_t; + +typedef struct { + uint16_t netno; + uint8_t nodeid; + uint8_t sockno; + uint8_t enumerator; +} nbd_tuple_hdr_t; + +void ddp_change_nbp_netid_to(uint8_t *nbppacket, int netno) { + nbd_hdr_t *hdr=(nbd_hdr_t*)nbppacket; + int ct=hdr->fn_count&0xf; + uint8_t *p=nbppacket+sizeof(nbd_hdr_t); + for (int i=0; inetno=htons(netno); //change net + p+=sizeof(nbd_tuple_hdr_t); + p+=*p+1; //object field len + p+=*p+1; //type field len + p+=*p+1; //zone field len + } +} + +int ddp_short_to_long(void *ddp_short, void *ddp_long, int buflen, uint8_t dest, int destnetno, uint8_t src, int srcnetno) { + ddp_long_t *l=(ddp_long_t*)ddp_long; + ddp_short_t *s=(ddp_short_t*)ddp_short; + if (buflen < ntohs(s->len)-sizeof(ddp_short)+sizeof(ddp_long)) return 0; + l->len=htons(ntohs(s->len)-sizeof(ddp_short_t)+sizeof(ddp_long_t)); + l->dest_sock=s->dest_sock; + l->src_sock=s->src_sock; + l->type=s->type; + memcpy(l->data, s->data, ntohs(s->len)); + l->dest_node=dest; + l->src_node=src; + l->dest_net=(dest==0xff)?0:htons(destnetno); + l->src_net=htons(srcnetno); + if (l->type==DDP_TYPE_NBP) { + ddp_change_nbp_netid_to(l->data, srcnetno); + } + l->chsum=0; //we don't perform checksum yet + return ntohs(l->len); +} + +int ddp_long_to_short(void *ddp_long, void *ddp_short, int buflen) { + ddp_long_t *l=(ddp_long_t*)ddp_long; + ddp_short_t *s=(ddp_short_t*)ddp_short; + if (buflen < ntohs(l->len)+sizeof(ddp_short)-sizeof(ddp_long)) return 0; + + s->len=htons(ntohs(l->len)-sizeof(ddp_long_t)+sizeof(ddp_short_t)); + s->dest_sock=l->dest_sock; + s->src_sock=l->src_sock; + s->type=l->type; + memcpy(s->data, l->data, ntohs(l->len)); + if (s->type==DDP_TYPE_NBP) { + ddp_change_nbp_netid_to(s->data, 0); + } + return ntohs(s->len); +} + +int ddp_print(void *ddp, int len, int isLong) { + if (isLong) { + ddp_long_t *l=(ddp_long_t*)ddp; + printf("DDP: type %d, net%d,node%d,sock%d -> net%d,node%d,sock%d\n", l->type, + ntohs(l->src_net), l->src_node, l->src_sock, + ntohs(l->dest_net), l->dest_node, l->dest_sock); + int plen=ntohs(l->len)&0x7FF; + if (len!=plen) { + printf("Len mismatch! Recved %d, packet says %d\n", len, plen); + } + } else { + ddp_short_t *s=(ddp_short_t*)ddp; + printf("DDP: type %d sock%d -> sock%d ", + s->type, s->src_sock, s->dest_sock); + int plen=ntohs(s->len)&0x3FF; + if (len!=plen) { + printf("Len mismatch! Recved %d, packet says %d\n", len, plen); + } else { + printf("DDP len (inc ddp hdr): %d\n", len); + } + } + return 1; +} + + diff --git a/components/tme/network/ddp.h b/components/tme/network/ddp.h new file mode 100644 index 0000000..61d8b02 --- /dev/null +++ b/components/tme/network/ddp.h @@ -0,0 +1,15 @@ +#ifndef DDP_H +#define DDP_H + +#define DDP_SHORT_HDR_LEN 5 +#define DDP_LONG_HDR_LEN 13 + +int ddp_get_dest_node(void *ddp); +int ddp_get_src_node(void *ddp); +int ddp_get_src_net(void *ddp); +int ddp_short_to_long(void *ddp_short, void *ddp_long, int buflen, uint8_t dest, int destnetno, uint8_t src, int srcnetno); +int ddp_long_to_short(void *ddp_long, void *ddp_short, int buflen); + +int ddp_print(void *ddp, int len, int isLong); + +#endif \ No newline at end of file diff --git a/components/tme/network/etalktst b/components/tme/network/etalktst new file mode 100755 index 0000000000000000000000000000000000000000..42a8036e7070ab8d565e4298243b881e90f79f4e GIT binary patch literal 14168 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 +#include +#include +#include +#include "basiliskif.h" +#include "hexdump.h" +#include "ddp.h" + +//Set to something random. Warning: be sure to initialize rand() first. +static uint8_t myMac[6]; +static int myNet=65289; +static int myAddr=0; + +//HACK! Officially, we should do stuff with aarp to figure out the address of the other... ahwell. +static uint8_t otherMac[6]; +static int otherNet=0; + +static const uint8_t snap_atalk[]={0x08, 0x00, 0x07, 0x80, 0x9B}; +static const uint8_t snap_aarp[]={0x00, 0x00, 0x00, 0x80, 0xF3}; + +static const uint8_t mac_atalk_bcast[]={0x09,0x00,0x07,0xFF,0xFF,0xFF}; + +#define ETH_HDR_LEN 14 + +typedef struct { + uint8_t dest[6]; + uint8_t src[6]; + uint16_t len; //of the rest of the packet, starting from dest_sap + uint8_t dest_sap; + uint8_t src_sap; + uint8_t ctrl; + uint8_t snap_proto[5]; + uint8_t data[]; +} __attribute__((packed)) elap_packet_t; + +#define AARP_FN_REQUEST 1 +#define AARP_FN_RESPONSE 2 +#define AARP_FN_PROBE 3 + +typedef struct { + uint16_t hw_type; + uint16_t proto_type; + uint8_t hw_addr_len; + uint8_t proto_addr_len; + uint16_t function; + uint8_t src_hw[6]; + uint8_t src_atalk[4]; + uint8_t dest_hw[6]; + uint8_t dest_atalk[4]; +} __attribute__((packed)) aarp_packet_t; + +static void print_mac(uint8_t *mac) { + printf("%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); +} + +static void print_atalk(uint8_t *atalk) { + if (atalk[0]!=0) { + printf("AtalkAdrCorrupt:%d!=0,", atalk[0]); + } + printf("NetID%dDev%d", (atalk[1]<<8)|atalk[2], atalk[3]); +} + +static void print_aarp(aarp_packet_t *aarp) { + printf("hw type %x proto %x ", ntohs(aarp->hw_type), ntohs(aarp->proto_type)); + + if (ntohs(aarp->function)==AARP_FN_REQUEST) { + printf("AARPRequest"); + } else if (ntohs(aarp->function)==AARP_FN_RESPONSE) { + printf("AARPResponse"); + } else if (ntohs(aarp->function)==AARP_FN_PROBE) { + printf("AARPProbe"); + } else { + printf("AARP Unknown fn (%d)", ntohs(aarp->function)); + } + printf(" Src "); + print_mac(aarp->src_hw); + printf(","); + print_atalk(aarp->src_atalk); + printf(", dst "); + print_mac(aarp->dest_hw); + printf(","); + print_atalk(aarp->dest_atalk); +} + +static void print_elap(elap_packet_t *e, int len) { + printf("ELAP packet, "); + print_mac(e->src); + printf("->"); + print_mac(e->dest); + printf(", datalen %d", ntohs(e->len)); + if (memcmp(e->snap_proto, snap_atalk, 5)==0) { + printf(", Atalk "); + ddp_print(e->data, len-sizeof(elap_packet_t), 1); + } else if (memcmp(e->snap_proto, snap_aarp, 5)==0) { + aarp_packet_t *aarp=(aarp_packet_t*)e->data; + printf(", "); + print_aarp(aarp); + } else { + printf(", unknown ("); + print_mac(e->snap_proto); + printf(")"); + } + int plen=ntohs(e->len)+ETH_HDR_LEN; + if (len!=plen) { + printf(" !! len mismatch! Packet says %d, we received %d !! ", plen, len); + } + printf("\n"); +} + +//len is size of data +static void create_elap_hdr(elap_packet_t *p, int srcnode, int dstnode, int len) { + memcpy(p->src, myMac, 6); + if (dstnode==0xff) { + memcpy(p->dest, mac_atalk_bcast, 6); + } else { + memcpy(p->dest, otherMac, 6); + } + p->dest_sap=0xaa; + p->src_sap=0xaa; + p->ctrl=0x3; + memcpy(p->snap_proto, snap_atalk, sizeof(snap_atalk)); + p->len=htons(len+sizeof(elap_packet_t)-ETH_HDR_LEN); +} + +int ethertalk_send_long_ddp(uint8_t *data, int size) { + int newlen=size+sizeof(elap_packet_t); + elap_packet_t *newp=alloca(newlen); + create_elap_hdr(newp, ddp_get_src_node(data), ddp_get_dest_node(data), size); + memcpy(newp->data, data, size); + printf("Sending ethertalk: "); + print_elap(newp, newlen); + basiliskIfSend((uint8_t*)newp, newlen); +} + +int ethertalk_send_short_ddp(uint8_t *data, int size, uint8_t srcnode, uint8_t dstnode) { + //Need to convert to long DDP first + int newlen=size-DDP_SHORT_HDR_LEN+DDP_LONG_HDR_LEN; + elap_packet_t *newp=alloca(newlen+sizeof(elap_packet_t)); + create_elap_hdr(newp, srcnode, dstnode, newlen); + ddp_short_to_long(data, newp->data, newlen, dstnode, otherNet, srcnode, myNet); + printf("Sending ethertalk: "); + print_elap(newp, newlen+sizeof(elap_packet_t)); + basiliskIfSend((uint8_t*)newp, newlen+sizeof(elap_packet_t)); + myAddr=srcnode; //assume it's sent from the localtalk seg, so we now know our address. +} + + +void ethertalk_send_probe(uint8_t id) { + //ToDo: send probe packet +} + +void ethertalkInit() { + //Generate random MAC for this station + myMac[0]=2; //locally administrated + for (int i=1; i<6; i++) myMac[i]=rand(); + basiliskIfInit(); + sniff_open("sniff.pcap"); +} + +void ethertalkTick() { + uint8_t buff[1400]; + int r=basiliskIfRecv(buff, sizeof(buff)); + if (r==0) return; + + sniff_write(buff, r); + +// hexdump(buff, r); + elap_packet_t *elap=(elap_packet_t*)&buff; + if (memcmp(elap->src, myMac, 6)==0) return; //ignore own packets + + printf("\n\nETHERTALK PACKET FROM BASILISKIF (%d bytes)\n", r); + print_elap(elap, r); + + //Try to sniff network ID if needed + if (otherNet==0 && (memcmp(elap->src, myMac, 6)!=0)) { + if (memcmp(elap->snap_proto, snap_aarp, 5)==0) { + aarp_packet_t *aarp=(aarp_packet_t*)elap->data; + otherNet=(aarp->src_atalk[1]<<8)|aarp->src_atalk[2]; + } else if (memcmp(elap->snap_proto, snap_atalk, 5)==0) { + otherNet=ddp_get_src_net(elap->data); + } + printf("Ethertalk: Sniffed NetID %d\n", otherNet); + myNet=otherNet; //because... dunno, doesn't work otherwise. + memcpy(otherMac, elap->src, 6); + } + + if (memcmp(elap->snap_proto, snap_aarp, 5)==0) { + aarp_packet_t *aarp=(aarp_packet_t*)elap->data; + if (ntohs(aarp->function)==AARP_FN_RESPONSE) { + localtalk_send_llap_resp(aarp->src_atalk[3]); + } else if (ntohs(aarp->function)==AARP_FN_REQUEST) { + //If the packet is a request for *our* net/addr, respond in kind. + int net=(aarp->dest_atalk[1]<<8)|aarp->dest_atalk[2]; + int node=aarp->dest_atalk[3]; + printf("Req is for net %d node %d, we are net %d node %d\n", net, node, myNet, myAddr); + if (net==myNet && node==myAddr) { + printf("AARP is for us, sending response...\n"); + elap_packet_t *resp=alloca(sizeof(elap_packet_t)+sizeof(aarp_packet_t)); + aarp_packet_t *ra=(aarp_packet_t*)resp->data; + create_elap_hdr(resp, myAddr, aarp->dest_atalk[3], sizeof(aarp_packet_t)); + //This actuaclly created a DDP packet. Restore to AARP + memcpy(resp->snap_proto, snap_aarp, sizeof(snap_aarp)); + //Copy rest of stuff. Crib from received aarp packet. + memcpy(ra, aarp, sizeof(aarp_packet_t)); + ra->function=htons(AARP_FN_RESPONSE); + memcpy(ra->src_hw, myMac, 6); + ra->src_atalk[0]=0; + ra->src_atalk[1]=(myNet>>8); + ra->src_atalk[2]=(myNet&0xff); + ra->src_atalk[3]=myAddr; + memcpy(ra->dest_hw, aarp->src_hw, 6); + memcpy(ra->dest_atalk, aarp->src_atalk, 6); + print_elap(resp, sizeof(elap_packet_t)+sizeof(aarp_packet_t)); + basiliskIfSend((uint8_t*)resp, sizeof(elap_packet_t)+sizeof(aarp_packet_t)); + } + } + } else if (memcmp(elap->snap_proto, snap_atalk, 5)==0) { + localtalk_send_ddp(elap->data, r-sizeof(elap_packet_t)); + } +} + +#ifdef TESTAPP +int main(int argc, char **argv) { + ethertalkInit(); + while(1) { + ethertalkTick(); + } +} +#endif \ No newline at end of file diff --git a/components/tme/network/ethertalk.h b/components/tme/network/ethertalk.h new file mode 100644 index 0000000..d8a4dca --- /dev/null +++ b/components/tme/network/ethertalk.h @@ -0,0 +1,12 @@ +#ifndef ETHERTALK_H +#define ETHERTALK_H + +void ethertalk_send_probe(uint8_t dest); +int ethertalk_send_long_ddp(uint8_t *data, int size); +int ethertalk_send_short_ddp(uint8_t *data, int size, uint8_t srcnode, uint8_t dstnode); +void ethertalkInit(); +void ethertalkTick(); + + + +#endif \ No newline at end of file diff --git a/components/tme/network/hexdump.c b/components/tme/network/hexdump.c new file mode 100644 index 0000000..daa5f29 --- /dev/null +++ b/components/tme/network/hexdump.c @@ -0,0 +1,64 @@ +//Utility function to perform hexdumps in the default format of the bsd hexdump utility +//(C) 2017 Jeroen Domburg +//This file is public domain where possible or CC0-licensed where not. +//CC0: https://creativecommons.org/share-your-work/public-domain/cc0/ + +#include +#include +#include + +void hexdumpFrom(void *mem, int len, int adrStart) { + uint8_t *data=(uint8_t*)mem; + int pos=0; + while (pos=len) break; + //Print if printable + if (isprint((int)data[pos+i])) { + printf("%c", data[pos+i]); + } else { + printf("."); + } + } + printf("|\n"); + pos+=16; + } + printf("%08x\n", adrStart+len); +} + + +void hexdump(void *mem, int len) { + hexdumpFrom(mem, len, 0); +} + + +//Uncomment the following line and compile 'gcc -o hexdump hexdump.c' to create a barebones hexdump utility that +//reads stdin and dumps the hex content of it to stdout +//#define TESTCASE + +#ifdef TESTCASE +#include +int main(int argc, char **argv) { + char buff[1024]; + int adr=0; + if (argc>1) adr=strtol(argv[1], NULL, 0); + int i=0; + int ch; + while ((ch=getchar())!=EOF) buff[i++]=ch; + hexdumpFrom(buff, i, adr); +} +#endif diff --git a/components/tme/network/hexdump.h b/components/tme/network/hexdump.h new file mode 100644 index 0000000..16c2494 --- /dev/null +++ b/components/tme/network/hexdump.h @@ -0,0 +1,7 @@ +#ifndef HEXDUMP_H +#define HEXDUMP_H + +void hexdump(void *mem, int len); +void hexdumpFrom(void *mem, int len, int addrFrom); + +#endif \ No newline at end of file diff --git a/components/tme/network/localtalk.c b/components/tme/network/localtalk.c new file mode 100644 index 0000000..4817c79 --- /dev/null +++ b/components/tme/network/localtalk.c @@ -0,0 +1,109 @@ +#include +#include +#include +#include "hexdump.h" +#include "scc.h" +#include "ddp.h" +#include "ethertalk.h" +#include + +//LLAP type 0x01-0x7F are for data +#define LLAP_TYPE_ENQ 0x81 +#define LLAP_TYPE_ACK 0x82 +#define LLAP_TYPE_RTS 0x84 +#define LLAP_TYPE_CTS 0x85 + +#define LLAP_TYPE_DDP_SHORT 1 +#define LLAP_TYPE_DDP_LONG 2 + +typedef struct { + uint8_t destid; //dest 255 is broadcast + uint8_t srcid; + uint8_t type; + uint8_t data[]; +} llap_packet_t; + +/* +llap plus short ddp example: +00000000 ff 48 01 00 06 01 01 05 01 |.H.......| +dest ff +src 48 +type 01 (ddp short) +ddp len 00 06 +dest sock 01 +src sock 01 +ddp type 5 +data 1 +*/ + + +void localtalkSend(uint8_t *data, int len) { + llap_packet_t *p=(llap_packet_t*)data; + printf("\n\nLOCALTALK PACKET FROM TME MAC\n"); + if (p->type==LLAP_TYPE_ENQ) { + ethertalk_send_probe(p->destid); + printf("LocalTalk: enq %hhu->%hhu\n", p->srcid, p->destid); + } else if (p->type==LLAP_TYPE_RTS) { + printf("LocalTalk: RTS %hhu->%hhu\n", p->srcid, p->destid); + if (p->destid!=0xff) { + printf("Sending CTS.\n"); + uint8_t resp[3]; + llap_packet_t *r=(llap_packet_t*)resp; + r->destid=p->srcid; + r->srcid=p->destid; + r->type=LLAP_TYPE_CTS; + sccRecv(1, r, sizeof(llap_packet_t), 3); + } + } 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); + ethertalk_send_short_ddp(p->data, len-sizeof(llap_packet_t), p->srcid, p->destid); +// hexdump(data, len); + } else if (p->type==LLAP_TYPE_DDP_LONG) { + printf("Localtalk: DDP long\n"); + ddp_print(p->data, len-sizeof(llap_packet_t), 1); + ethertalk_send_long_ddp(p->data, len-sizeof(llap_packet_t)); +// hexdump(data, len); + } else { + printf("LocalTalk... errm... dunno what to do with this (cmd=%x).\n", data[2]); + } +} + +void localtalk_send_ddp(uint8_t *data, int len) { + llap_packet_t rts; + rts.destid=ddp_get_dest_node(data); + rts.srcid=ddp_get_src_node(data); + rts.type=LLAP_TYPE_RTS; + sccRecv(1, &rts, 3, 3); + + //We assume this is a long ddp packet. +#if 0 + llap_packet_t *p=alloca(len+sizeof(llap_packet_t)); + 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); +#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)); + 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); +#endif +} + +void localtalk_send_llap_resp(uint8_t node) { + //ToDo +} + +//Called once every now and then. +void localtalkTick() { + ethertalkTick(); +} + +void localtalkInit() { + ethertalkInit(); +} diff --git a/components/tme/network/localtalk.h b/components/tme/network/localtalk.h new file mode 100644 index 0000000..09b393f --- /dev/null +++ b/components/tme/network/localtalk.h @@ -0,0 +1,10 @@ +#ifndef LOCALTALK_H +#define LOCALTALK_H + +void localtalkSend(uint8_t *data, int len); +void localtalkInit(); +void localtalkTick(); +void localtalk_send_llap_resp(uint8_t node); + + +#endif \ No newline at end of file diff --git a/components/tme/network/sniff.c b/components/tme/network/sniff.c new file mode 100644 index 0000000..15d45fa --- /dev/null +++ b/components/tme/network/sniff.c @@ -0,0 +1,56 @@ +#include +#include +#include + + +typedef struct pcap_hdr_s { + uint32_t magic_number; /* magic number */ + uint16_t version_major; /* major version number */ + uint16_t version_minor; /* minor version number */ + int32_t thiszone; /* GMT to local correction */ + uint32_t sigfigs; /* accuracy of timestamps */ + uint32_t snaplen; /* max length of captured packets, in octets */ + uint32_t network; /* data link type */ +} __attribute__((packed)) pcap_hdr_t; + +typedef struct pcaprec_hdr_s { + uint32_t ts_sec; /* timestamp seconds */ + uint32_t ts_usec; /* timestamp microseconds */ + uint32_t incl_len; /* number of octets of packet saved in file */ + uint32_t orig_len; /* actual length of packet */ +} __attribute__((packed)) pcaprec_hdr_t; + +static FILE *f=NULL; + +void sniff_open(char *name) { + f=fopen(name, "wb"); + if (f==NULL) { + perror(name); + exit(1); + } + pcap_hdr_t hdr={ + .magic_number=0xa1b2c3d4, + .version_major=2, + .version_minor=4, + .thiszone=0, + .sigfigs=0, + .snaplen=65535, + .network=1 + }; + fwrite(&hdr, sizeof(hdr), 1, f); +} + +void sniff_write(uint8_t *buff, int len) { + struct timeval tv; + gettimeofday(&tv, NULL); + pcaprec_hdr_t hdr={ + .ts_sec=tv.tv_sec, + .ts_usec=tv.tv_usec, + .incl_len=len, + .orig_len=len, + }; + fwrite(&hdr, sizeof(hdr), 1, f); + fwrite(buff, len, 1, f); + fflush(f); +} + diff --git a/components/tme/network/sniff.h b/components/tme/network/sniff.h new file mode 100644 index 0000000..848a540 --- /dev/null +++ b/components/tme/network/sniff.h @@ -0,0 +1,2 @@ +void sniff_open(char *name); +void sniff_write(uint8_t *buff, int len); diff --git a/components/tme/scc.c b/components/tme/scc.c index 4c9455d..0768ee3 100644 --- a/components/tme/scc.c +++ b/components/tme/scc.c @@ -3,31 +3,38 @@ #include "scc.h" #include "m68k.h" #include "hexdump.h" -#include "localtalk.h" - +#include "network/localtalk.h" +#include /* Emulation of the Zilog 8530 SCC. -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. +Supports basic mouse pins plus hacked in LocalTalk */ void sccIrq(int ena); #define BUFLEN 8192 +#define NO_RXBUF 4 + +typedef struct { + int delay; //-1 if buffer is free, + int len; + uint8_t data[BUFLEN]; +} RxBuf; typedef struct { int dcd; int cts; - int wr1; + int wr1, wr15; int sdlcaddr; - int wr15; int hunting; int txTimer; uint8_t txData[BUFLEN]; - uint8_t rxData[BUFLEN]; - int txPos, rxPos, rxLen; + RxBuf rx[NO_RXBUF]; + int txPos; + int rxPos; + int rxBufCur; int rxDelay; } SccChan; @@ -36,10 +43,57 @@ typedef struct { int intpending; int intpendingOld; SccChan chan[2]; + int wr2, wr9; } Scc; static Scc scc; + +static void triggerRx(int chan); + + +static int rxHasByte(int chan) { + return (scc.chan[chan].rx[scc.chan[chan].rxBufCur].delay==0); +} + + +static void rxBufIgnoreRest(int chan) { + 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; + scc.chan[chan].rxPos=0; +} + +static int rxByte(int chan, int *bytesLeftInBuf) { + int ret; + int curbuf=scc.chan[chan].rxBufCur; + printf("RxBuf: bufid %d byte %d/%d\n", curbuf, scc.chan[chan].rxPos, scc.chan[chan].rx[curbuf].len); + if (scc.chan[chan].rx[curbuf].delay!=0) return 0; + if (bytesLeftInBuf) *bytesLeftInBuf=scc.chan[chan].rx[curbuf].len-scc.chan[chan].rxPos-1; + ret=scc.chan[chan].rx[curbuf].data[scc.chan[chan].rxPos++]; + if (scc.chan[chan].rxPos==scc.chan[chan].rx[curbuf].len) { + rxBufIgnoreRest(chan); + } + return ret; +} + +static int rxBytesLeft(int chan) { + if (scc.chan[chan].rx[scc.chan[chan].rxBufCur].delay!=0) return 0; + return scc.chan[chan].rx[scc.chan[chan].rxBufCur].len-scc.chan[chan].rxPos; +} + +static int rxBufTick(int chan) { + 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); + return 1; + } + } + return 0; +} + + //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) @@ -59,9 +113,9 @@ static Scc scc; static void raiseInt(int chan) { - if ((scc.chan[chan].wr1&1) && (scc.intpending&(~scc.intpendingOld))) { + if ((scc.chan[chan].wr1&1) ){ //&& (scc.intpending&(~scc.intpendingOld))) { scc.intpendingOld=scc.intpending; -// printf("SCC int, pending %x\n", scc.intpending); + printf("SCC int, pending %x\n", scc.intpending); sccIrq(1); } } @@ -84,28 +138,51 @@ void sccSetDcd(int chan, int val) { scc.chan[chan].dcd=val; } +void sccRecv(int chan, uint8_t *data, int len, int delay) { + int bufid=scc.chan[chan].rxBufCur; + int n=0; + do { + if (scc.chan[chan].rx[bufid].delay==-1) break; + bufid++; + if (bufid>=NO_RXBUF) bufid=0; + n++; + } while(bufid!=scc.chan[chan].rxBufCur); + + //check if all buffers are full + if (scc.chan[chan].rx[bufid].delay!=-1) { + printf("Eek! Can't queue buffer: full!\n"); + return; + } + + printf("Serial transmit for chan %d queued; bufidx %d, len=%d delay=%d, %d other buffers in queue\n", chan, bufid, len, delay, n); + 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].delay=delay; +} + void sccTxFinished(int chan) { hexdump(scc.chan[chan].txData, scc.chan[chan].txPos); localtalkSend(scc.chan[chan].txData, scc.chan[chan].txPos); + //Echo back data over Rx of same channel +// sccRecv(chan, scc.chan[chan].txData, scc.chan[chan].txPos, 0); +// triggerRx(chan); + scc.chan[chan].txPos=0; scc.chan[chan].hunting=1; } -void sccRecv(int chan, uint8_t *data, int len) { - memcpy(scc.chan[chan].rxData, data, len); - scc.chan[chan].rxData[len]=0xA5; //crc1 - scc.chan[chan].rxData[len+1]=0xA5; //crc2 - scc.chan[chan].rxData[len+2]=0; //abort - scc.chan[chan].rxLen=len+3; - scc.chan[chan].rxDelay=30; -} static void triggerRx(int chan) { if (!scc.chan[chan].hunting) return; - printf("Receiving:\n"); - hexdump(scc.chan[chan].rxData, scc.chan[chan].rxLen); - if (scc.chan[chan].rxData[0]==0xFF || scc.chan[chan].rxData[0]==scc.chan[chan].sdlcaddr) { + 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); + if (scc.chan[chan].rx[bufid].data[0]==0xFF || scc.chan[chan].rx[bufid].data[0]==scc.chan[chan].sdlcaddr) { scc.chan[chan].rxPos=0; + 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_WR3_CHA_EXT:SCC_WR3_CHB_EXT); @@ -119,7 +196,8 @@ static void triggerRx(int chan) { } scc.chan[chan].hunting=0; } else { - scc.chan[chan].rxLen=0; + printf("...Not for us, ignoring.\n"); + rxBufIgnoreRest(chan); } } @@ -144,15 +222,19 @@ void sccWrite(unsigned int addr, unsigned int val) { } if ((val&0x38)==0x18) { //SCC abort: parse whatever we sent - printf("SCC ABORT: Sent data\n"); +// printf("SCC ABORT: Sent data\n"); sccTxFinished(chan); } if ((val&0xc0)==0xC0) { //reset tx underrun latch - if (scc.chan[chan].txTimer==0) scc.chan[chan].txTimer=-1; +// sccTxFinished(chan); + scc.chan[chan].txTimer=1; + //if (scc.chan[chan].txTimer==0) scc.chan[chan].txTimer=-1; } } else if (reg==1) { scc.chan[chan].wr1=val; + } else if (reg==2) { + scc.wr2=val; } else if (reg==3) { //bitsperchar1, bitsperchar0, autoenables, enterhuntmode, rxcrcen, addresssearch, synccharloadinh, rxena //autoenable: cts = tx ena, dcd = rx ena @@ -161,12 +243,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); +// printf("TX! Pos %d\n", scc.chan[chan].txPos); scc.chan[chan].txTimer+=30; + } else if (reg==9) { + scc.wr9=val; } else if (reg==15) { scc.chan[chan].wr15=val; + raiseInt(chan); } -// printf("SCC: write to addr %x chan %d reg %d val %x\n", addr, chan, reg, val); + printf("SCC: write to addr %x chan %d reg %d val %x\n", addr, chan, reg, val); } @@ -183,51 +268,66 @@ unsigned int sccRead(unsigned int addr) { } if (reg==0) { val=(1<<2); //tx buffer always empty - if (scc.chan[chan].rxLen && !scc.chan[chan].rxDelay) val|=(1<<0); + if (rxHasByte(chan)) val|=(1<<0); if (scc.chan[chan].txTimer==0) val|=(1<<6); if (scc.chan[chan].dcd) val|=(1<<3); if (scc.chan[chan].cts) val|=(1<<5); if (scc.chan[chan].hunting) val|=(1<<4); - if (scc.chan[chan].rxPos==scc.chan[chan].rxLen-1) val|=(1<<7); //abort + if (rxBytesLeft(chan)<=2) val|=(1<<7); //abort } 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 (scc.chan[chan].rxPos==scc.chan[chan].rxLen-2) val|=(1<<7); //end of frame + if (rxBytesLeft(chan)==1) val|=(1<<7); //end of frame } 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) { + } else if (scc.intpending & SCC_WR3_CHA_EXT) { rsn=5; scc.intpending&=~SCC_WR3_CHA_EXT; + } else if (scc.intpending&SCC_WR3_CHA_RX) { + rsn=6; + scc.intpending&=~SCC_WR3_CHA_RX; + } else if (scc.intpending&SCC_WR3_CHB_RX) { + rsn=2; + scc.intpending&=~SCC_WR3_CHA_RX; + } + + val=scc.wr2; + if (scc.wr9&0x10) { //hi/lo + val=(scc.wr2&~0x70)|rsn<<4; + } else { + val=(scc.wr2&~0xD)|rsn<<1; } - 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==8) { //rx buffer - if (scc.chan[chan].rxLen && !scc.chan[chan].rxDelay) { - val=scc.chan[chan].rxData[scc.chan[chan].rxPos++]; - if (scc.chan[chan].rxPos==scc.chan[chan].rxLen) { - scc.chan[chan].rxLen=0; - } else { + + 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_WR3_CHA_RX:SCC_WR3_CHB_RX); raiseInt(chan); } } - if (scc.chan[chan].rxPos==scc.chan[chan].rxLen-1) scc.chan[chan].hunting=1; - if (scc.chan[chan].rxPos==scc.chan[chan].rxLen-1 && scc.chan[chan].wr15&SCC_WR15_BREAK) { + if (left==1) scc.chan[chan].hunting=1; + if (left==1 && scc.chan[chan].wr15&SCC_WR15_BREAK) { scc.intpending|=(chan?SCC_WR3_CHA_EXT:SCC_WR3_CHB_EXT); raiseInt(chan); } } else { + printf("SCC READ but no data?\n"); val=0; } } else if (reg==10) { @@ -236,7 +336,7 @@ unsigned int sccRead(unsigned int addr) { } else if (reg==15) { val=scc.chan[chan].wr15; } -// printf("SCC: read from chan %d reg %d val %x\n", chan, reg, val); + printf("SCC: read from chan %d reg %d val %x\n", chan, reg, val); return val; } @@ -246,15 +346,12 @@ void sccTick() { if (scc.chan[n].txTimer>0) { scc.chan[n].txTimer--; if (scc.chan[n].txTimer==0) { - printf("Tx buffer empty: Sent data\n"); +// printf("Tx buffer empty: Sent data\n"); sccTxFinished(n); } } - if (scc.chan[n].rxDelay!=0) { - scc.chan[n].rxDelay--; - if (scc.chan[n].rxDelay==0) { - triggerRx(n); - } + if (rxBufTick(n)) { + triggerRx(n); } } } @@ -264,5 +361,9 @@ void sccInit() { sccSetDcd(2, 1); scc.chan[0].txTimer=-1; scc.chan[1].txTimer=-1; + for (int x=0; xf, lba*512, SEEK_SET); fread(data->data, 512, len, hd->f); - printf("HD: Read %d bytes.\n", len*512); +// printf("HD: Read %d bytes.\n", len*512); ret=len*512; } else if (cmd==0xA || cmd==0x2A) { //write fseek(hd->f, lba*512, SEEK_SET); fwrite(data->data, 512, len, hd->f); - printf("HD: Write %d bytes\n", len*512); +// printf("HD: Write %d bytes\n", len*512); ret=0; } else if (cmd==0x12) { //inquiry printf("HD: Inquery\n"); diff --git a/components/tme/sdl/main.c b/components/tme/sdl/main.c index 22ab1e7..5a9d330 100644 --- a/components/tme/sdl/main.c +++ b/components/tme/sdl/main.c @@ -7,7 +7,7 @@ #include #include #include "tmeconfig.h" - +#include "snd.h" static void *loadRom(char *file) { int i; diff --git a/components/tme/sdl/snd.c b/components/tme/sdl/snd.c new file mode 100644 index 0000000..53dc688 --- /dev/null +++ b/components/tme/sdl/snd.c @@ -0,0 +1,55 @@ +#include +#include +#include +#include + + + +static uint8_t buf[1024]; +static int wp=256, rp=0; + +static int bufLen() { + return (wp-rp)&1023; +} + +int sndDone() { + return (bufLen()<512); +} + +int sndPush(uint8_t *data, int volume) { + while(!sndDone()) usleep(1000); + for (int i=0; i<370; i++) { + int s=*data; + s=(s-128)>>(7-volume); + buf[wp++]=s+128; + if (wp==1024) wp=0; + data+=2; + } +} + +static void sndCb(void* userdata, Uint8* stream, int len) { + for (int i=0; i + +void sndInit(); +int sndDone(); +int sndPush(uint8_t *data, int volume); diff --git a/components/tme/tmeconfig.h b/components/tme/tmeconfig.h index dd40403..eb7c1d3 100644 --- a/components/tme/tmeconfig.h +++ b/components/tme/tmeconfig.h @@ -23,11 +23,14 @@ #else -#ifdef CONFIG_SPIRAM_USE_MEMMAP +#if defined(CONFIG_SPIRAM_USE_MEMMAP) || defined(HOSTBUILD) #define TME_RAMSIZE (4*1024*1024) #define TME_SCREENBUF 0x3FA700 #define TME_SCREENBUF_ALT 0x3F2700 +#define TME_SNDBUF 0x3FFD00 +#define TME_SNDBUF_ALT 0x3FA100 + #else diff --git a/sdkconfig b/sdkconfig index fa45967..7329830 100644 --- a/sdkconfig +++ b/sdkconfig @@ -270,8 +270,6 @@ CONFIG_FREERTOS_THREAD_LOCAL_STORAGE_POINTERS=1 CONFIG_FREERTOS_ASSERT_FAIL_ABORT=y CONFIG_FREERTOS_ASSERT_FAIL_PRINT_CONTINUE= CONFIG_FREERTOS_ASSERT_DISABLE= -CONFIG_FREERTOS_BREAK_ON_SCHEDULER_START_JTAG=y -CONFIG_ENABLE_MEMORY_DEBUG= CONFIG_FREERTOS_IDLE_TASK_STACKSIZE=1024 CONFIG_FREERTOS_ISR_STACKSIZE=2000 CONFIG_FREERTOS_LEGACY_HOOKS= @@ -290,6 +288,11 @@ CONFIG_HEAP_POISONING_LIGHT= CONFIG_HEAP_POISONING_COMPREHENSIVE= CONFIG_HEAP_TRACING= +# +# libsodium +# +CONFIG_LIBSODIUM_USE_MBEDTLS_SHA=y + # # Log output # @@ -316,6 +319,10 @@ CONFIG_LWIP_IP_REASSEMBLY= CONFIG_LWIP_STATS= CONFIG_LWIP_ETHARP_TRUST_IP_MAC=y CONFIG_TCPIP_RECVMBOX_SIZE=32 +CONFIG_LWIP_DHCP_DOES_ARP_CHECK= +CONFIG_LWIP_AUTOIP= +CONFIG_LWIP_NETIF_LOOPBACK=y +CONFIG_LWIP_LOOPBACK_MAX_PBUFS=8 # # TCP @@ -336,7 +343,6 @@ CONFIG_TCP_OVERSIZE_DISABLE= # UDP # CONFIG_UDP_RECVMBOX_SIZE=6 -CONFIG_LWIP_DHCP_DOES_ARP_CHECK= CONFIG_TCPIP_TASK_STACK_SIZE=2560 CONFIG_PPP_SUPPORT=