Add sound, LocalTalk hackery

This commit is contained in:
Jeroen Domburg 2017-10-17 21:43:20 +08:00
parent cb147908ee
commit fc11fb4e85
30 changed files with 1031 additions and 101 deletions

View File

@ -0,0 +1,50 @@
#include <stdio.h>
#include <ctype.h>
#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');
}
}
}

View File

@ -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)

View File

@ -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%

View File

@ -17,12 +17,13 @@
#include "rtc.h"
#include "ncr.h"
#include "hd.h"
#include "snd.h"
#include "mouse.h"
#include <stdbool.h>
#include "esp_heap_caps.h"
#include <byteswap.h>
#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<TME_RAMSIZE; x++) macRam[x]=rand();
}
@ -446,7 +449,7 @@ void printFps() {
if (oldtv.tv_sec!=0) {
long msec=(tv.tv_sec-oldtv.tv_sec)*1000;
msec+=(tv.tv_usec-oldtv.tv_usec)/1000;
printf("Speed: %d%%\n", (int)(100000/msec));
// printf("Speed: %d%%\n", (int)(100000/msec));
// printf("Mem free: %dKiB 8-bit, %dKiB 32-bit\n", xPortGetFreeHeapSizeCaps(MALLOC_CAP_8BIT)/1024, xPortGetFreeHeapSizeCaps(MALLOC_CAP_32BIT)/1024);
}
oldtv.tv_sec=tv.tv_sec;
@ -475,6 +478,8 @@ void tmeStartEmu(void *rom) {
m68k_pulse_reset();
printf("Display init...\n");
dispInit();
sndInit();
localtalkInit();
printf("Done! Running.\n");
while(1) {
for (x=0; x<8000000/60; x+=10) {
@ -491,8 +496,12 @@ void tmeStartEmu(void *rom) {
sccSetDcd(SCC_CHANB, r&MOUSE_QYA);
m=0;
}
//Sound handler keeps track of real time, if its buffer is empty we should be done with the video frame.
if (sndDone()) break;
}
dispDraw(macFb[video_remap?1:0]);
sndPush(macSnd[audio_remap?1:0], audio_en?audio_volume:0);
localtalkTick();
frame++;
ca1^=1;
viaControlWrite(VIA_CA1, ca1);
@ -522,14 +531,16 @@ void viaCbPortAWrite(unsigned int val) {
video_remap=(val&(1<<6))?1:0;
rom_remap=(val&(1<<4))?1:0;
regenMemmap(rom_remap);
audio_remap=(val&(1<<3))?1:0;
audio_remap=(val&(1<<3))?0:1;
if (oldRomRemap!=rom_remap) printf("ROM REMAP %d\n", rom_remap);
iwmSetHeadSel(val&(1<<5));
audio_volume=(val&7);
}
void viaCbPortBWrite(unsigned int val) {
int b;
b=rtcCom(val&4, val&1, val&2);
if (b) viaSet(VIA_PORTB, 1); else viaClear(VIA_PORTB, 1);
audio_en=!(val&(1<<7));
}

View File

@ -1,18 +0,0 @@
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#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]);
}
}

View File

@ -1,7 +0,0 @@
#ifndef LOCALTALK_H
#define LOCALTALK_H
void localtalkSend(uint8_t *data, int len);
#endif

View File

@ -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;

View File

@ -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)

View File

@ -0,0 +1,67 @@
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/select.h>
#include<arpa/inet.h>
#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");
}
}

View File

@ -0,0 +1,11 @@
#ifndef BASILISKIF_H
#define BASILISKIF_H
#include <stdint.h>
int basiliskIfInit();
int basiliskIfRecv(uint8_t *buf, int len);
int basiliskIfSend(uint8_t *buf, int len);
#endif

View File

@ -0,0 +1,130 @@
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <arpa/inet.h>
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; i<ct; i++) {
nbd_tuple_hdr_t *th=(nbd_tuple_hdr_t*)p;
th->netno=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;
}

View File

@ -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

BIN
components/tme/network/etalktst Executable file

Binary file not shown.

View File

@ -0,0 +1,229 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
#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

View File

@ -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

View File

@ -0,0 +1,64 @@
//Utility function to perform hexdumps in the default format of the bsd hexdump utility
//(C) 2017 Jeroen Domburg <jeroen at spritesmods dot com>
//This file is public domain where possible or CC0-licensed where not.
//CC0: https://creativecommons.org/share-your-work/public-domain/cc0/
#include <stdio.h>
#include <ctype.h>
#include <stdint.h>
void hexdumpFrom(void *mem, int len, int adrStart) {
uint8_t *data=(uint8_t*)mem;
int pos=0;
while (pos<len) {
//Print address
printf("%08x", pos+adrStart);
//Print hex bytes
for (int i=0; i<16; i++) {
if ((i&7)==0) printf(" ");
if (pos+i<len) {
printf(" %02x", data[pos+i]);
} else {
printf(" ");
}
}
//Print ASCII bytes
printf(" |");
for (int i=0; i<16; i++) {
//Abort if at end
if (pos+i>=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 <stdlib.h>
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

View File

@ -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

View File

@ -0,0 +1,109 @@
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include "hexdump.h"
#include "scc.h"
#include "ddp.h"
#include "ethertalk.h"
#include <alloca.h>
//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();
}

View File

@ -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

View File

@ -0,0 +1,56 @@
#include <stdio.h>
#include <stdint.h>
#include <sys/time.h>
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);
}

View File

@ -0,0 +1,2 @@
void sniff_open(char *name);
void sniff_write(uint8_t *buff, int len);

View File

@ -3,31 +3,38 @@
#include "scc.h"
#include "m68k.h"
#include "hexdump.h"
#include "localtalk.h"
#include "network/localtalk.h"
#include <string.h>
/*
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; x<NO_RXBUF; x++) {
scc.chan[0].rx[x].delay=-1;
scc.chan[1].rx[x].delay=-1;
}
}

View File

@ -7,5 +7,5 @@ unsigned int sccRead(unsigned int addr);
void sccSetDcd(int chan, int val);
void sccInit();
void sccTick();
void sccRecv(int chan, uint8_t *data, int len);
void sccRecv(int chan, uint8_t *data, int len, int delay);

View File

@ -17,7 +17,7 @@ void sdlDie() {
void dispInit() {
if (SDL_Init( SDL_INIT_VIDEO ) < 0 ) sdlDie();
if (SDL_Init( SDL_INIT_VIDEO|SDL_INIT_AUDIO ) < 0 ) sdlDie();
win=SDL_CreateWindow( "TME", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN );
if (win==0) sdlDie();
surf=SDL_GetWindowSurface(win);

View File

@ -31,12 +31,12 @@ static int hdScsiCmd(SCSITransferData *data, unsigned int cmd, unsigned int len,
if (cmd==0x8 || cmd==0x28) { //read
fseek(hd->f, 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");

View File

@ -7,7 +7,7 @@
#include <fcntl.h>
#include <unistd.h>
#include "tmeconfig.h"
#include "snd.h"
static void *loadRom(char *file) {
int i;

55
components/tme/sdl/snd.c Normal file
View File

@ -0,0 +1,55 @@
#include <stdio.h>
#include <stdint.h>
#include <SDL2/SDL.h>
#include <unistd.h>
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<len; i++) {
stream[i]=buf[rp++];
if (rp==1024) rp=0;
}
}
void sndInit() {
SDL_AudioSpec want, have;
SDL_AudioDeviceID dev;
SDL_memset(&want, 0, sizeof(want));
want.freq = 22000;
want.format = AUDIO_U8;
want.channels = 1;
want.samples = 256;
want.callback = sndCb;
dev = SDL_OpenAudioDevice(NULL, 0, &want, &have, 0);
if (dev == 0) {
SDL_Log("Failed to open audio: %s", SDL_GetError());
}
SDL_PauseAudioDevice(dev, 0);
}

5
components/tme/snd.h Normal file
View File

@ -0,0 +1,5 @@
#include <stdint.h>
void sndInit();
int sndDone();
int sndPush(uint8_t *data, int volume);

View File

@ -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

View File

@ -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=