Add sound, LocalTalk hackery
This commit is contained in:
parent
cb147908ee
commit
fc11fb4e85
|
@ -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');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,10 +3,11 @@
|
||||||
TARGET:=tme
|
TARGET:=tme
|
||||||
MUSASHI_GEN_SRC:=musashi/m68kopac.c musashi/m68kopdm.c musashi/m68kopnz.c
|
MUSASHI_GEN_SRC:=musashi/m68kopac.c musashi/m68kopdm.c musashi/m68kopnz.c
|
||||||
MUSASHI_OP_PREGEN_SRC:=musashi/m68kops_pre.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 \
|
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 localtalk.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
|
#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`
|
LDFLAGS=`sdl2-config --libs`
|
||||||
|
|
||||||
$(TARGET): $(OBJ)
|
$(TARGET): $(OBJ)
|
||||||
|
|
|
@ -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_SRC := musashi/m68kops_pre.c musashi/m68kopac.c musashi/m68kopdm.c musashi/m68kopnz.c
|
||||||
MUSASHI_GEN_OBJ := $(MUSASHI_GEN_SRC:%.c=%.o)
|
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 \
|
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%
|
#nothing in iram: 16%
|
||||||
#ac nz in iram: 19%
|
#ac nz in iram: 19%
|
||||||
|
|
|
@ -17,12 +17,13 @@
|
||||||
#include "rtc.h"
|
#include "rtc.h"
|
||||||
#include "ncr.h"
|
#include "ncr.h"
|
||||||
#include "hd.h"
|
#include "hd.h"
|
||||||
|
#include "snd.h"
|
||||||
#include "mouse.h"
|
#include "mouse.h"
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include "esp_heap_caps.h"
|
#include "esp_heap_caps.h"
|
||||||
#include <byteswap.h>
|
#include <byteswap.h>
|
||||||
#include "esp_spiram.h"
|
#include "esp_spiram.h"
|
||||||
|
#include "network/localtalk.h"
|
||||||
|
|
||||||
|
|
||||||
unsigned char *macRom;
|
unsigned char *macRom;
|
||||||
|
@ -36,7 +37,7 @@ unsigned char *macRam;
|
||||||
|
|
||||||
#define MEMADDR_DUMMY_CACHE (void*)1
|
#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() {
|
void m68k_instruction() {
|
||||||
unsigned int pc=m68k_get_reg(NULL, M68K_REG_PC);
|
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)
|
#if (USE_EXTERNAL_RAM)
|
||||||
|
@ -330,6 +331,8 @@ static void ramInit() {
|
||||||
assert(macRam);
|
assert(macRam);
|
||||||
macFb[0]=&macRam[TME_SCREENBUF];
|
macFb[0]=&macRam[TME_SCREENBUF];
|
||||||
macFb[1]=&macRam[TME_SCREENBUF_ALT];
|
macFb[1]=&macRam[TME_SCREENBUF_ALT];
|
||||||
|
macSnd[0]=&macRam[TME_SNDBUF];
|
||||||
|
macSnd[1]=&macRam[TME_SNDBUF_ALT];
|
||||||
printf("Clearing ram...\n");
|
printf("Clearing ram...\n");
|
||||||
for (int x=0; x<TME_RAMSIZE; x++) macRam[x]=rand();
|
for (int x=0; x<TME_RAMSIZE; x++) macRam[x]=rand();
|
||||||
}
|
}
|
||||||
|
@ -446,7 +449,7 @@ void printFps() {
|
||||||
if (oldtv.tv_sec!=0) {
|
if (oldtv.tv_sec!=0) {
|
||||||
long msec=(tv.tv_sec-oldtv.tv_sec)*1000;
|
long msec=(tv.tv_sec-oldtv.tv_sec)*1000;
|
||||||
msec+=(tv.tv_usec-oldtv.tv_usec)/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);
|
// 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;
|
oldtv.tv_sec=tv.tv_sec;
|
||||||
|
@ -475,6 +478,8 @@ void tmeStartEmu(void *rom) {
|
||||||
m68k_pulse_reset();
|
m68k_pulse_reset();
|
||||||
printf("Display init...\n");
|
printf("Display init...\n");
|
||||||
dispInit();
|
dispInit();
|
||||||
|
sndInit();
|
||||||
|
localtalkInit();
|
||||||
printf("Done! Running.\n");
|
printf("Done! Running.\n");
|
||||||
while(1) {
|
while(1) {
|
||||||
for (x=0; x<8000000/60; x+=10) {
|
for (x=0; x<8000000/60; x+=10) {
|
||||||
|
@ -491,8 +496,12 @@ void tmeStartEmu(void *rom) {
|
||||||
sccSetDcd(SCC_CHANB, r&MOUSE_QYA);
|
sccSetDcd(SCC_CHANB, r&MOUSE_QYA);
|
||||||
m=0;
|
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]);
|
dispDraw(macFb[video_remap?1:0]);
|
||||||
|
sndPush(macSnd[audio_remap?1:0], audio_en?audio_volume:0);
|
||||||
|
localtalkTick();
|
||||||
frame++;
|
frame++;
|
||||||
ca1^=1;
|
ca1^=1;
|
||||||
viaControlWrite(VIA_CA1, ca1);
|
viaControlWrite(VIA_CA1, ca1);
|
||||||
|
@ -522,14 +531,16 @@ void viaCbPortAWrite(unsigned int val) {
|
||||||
video_remap=(val&(1<<6))?1:0;
|
video_remap=(val&(1<<6))?1:0;
|
||||||
rom_remap=(val&(1<<4))?1:0;
|
rom_remap=(val&(1<<4))?1:0;
|
||||||
regenMemmap(rom_remap);
|
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);
|
if (oldRomRemap!=rom_remap) printf("ROM REMAP %d\n", rom_remap);
|
||||||
iwmSetHeadSel(val&(1<<5));
|
iwmSetHeadSel(val&(1<<5));
|
||||||
|
audio_volume=(val&7);
|
||||||
}
|
}
|
||||||
|
|
||||||
void viaCbPortBWrite(unsigned int val) {
|
void viaCbPortBWrite(unsigned int val) {
|
||||||
int b;
|
int b;
|
||||||
b=rtcCom(val&4, val&1, val&2);
|
b=rtcCom(val&4, val&1, val&2);
|
||||||
if (b) viaSet(VIA_PORTB, 1); else viaClear(VIA_PORTB, 1);
|
if (b) viaSet(VIA_PORTB, 1); else viaClear(VIA_PORTB, 1);
|
||||||
|
audio_en=!(val&(1<<7));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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]);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,7 +0,0 @@
|
||||||
#ifndef LOCALTALK_H
|
|
||||||
#define LOCALTALK_H
|
|
||||||
|
|
||||||
void localtalkSend(uint8_t *data, int len);
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -95,19 +95,19 @@ static void parseScsiCmd(int isRead) {
|
||||||
len=buf[4];
|
len=buf[4];
|
||||||
if (len==0) len=256;
|
if (len==0) len=256;
|
||||||
ctrl=buf[5];
|
ctrl=buf[5];
|
||||||
for (int x=0; x<6; x++) printf("%02X ", buf[x]);
|
// for (int x=0; x<6; x++) printf("%02X ", buf[x]);
|
||||||
printf("\n");
|
// printf("\n");
|
||||||
} else if (group==1 || group==2) { //10-byte command
|
} else if (group==1 || group==2) { //10-byte command
|
||||||
lba=buf[5]|(buf[4]<<8)|(buf[3]<<16)|(buf[2]<<24);
|
lba=buf[5]|(buf[4]<<8)|(buf[3]<<16)|(buf[2]<<24);
|
||||||
len=buf[8]|(buf[7]<<8);
|
len=buf[8]|(buf[7]<<8);
|
||||||
ctrl=buf[9];
|
ctrl=buf[9];
|
||||||
for (int x=0; x<10; x++) printf("%02X ", buf[x]);
|
// for (int x=0; x<10; x++) printf("%02X ", buf[x]);
|
||||||
printf("\n");
|
// printf("\n");
|
||||||
} else {
|
} else {
|
||||||
printf("SCSI: UNSUPPORTED CMD %x\n", cmd);
|
printf("SCSI: UNSUPPORTED CMD %x\n", cmd);
|
||||||
return;
|
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]) {
|
if (ncr.dev[ncr.selected]) {
|
||||||
ncr.datalen=ncr.dev[ncr.selected]->scsiCmd(&ncr.data, cmd, len, lba, ncr.dev[ncr.selected]->arg);
|
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) {
|
if (ncr.mode&MODE_DMA) {
|
||||||
ret|=BSR_DMARQ;
|
ret|=BSR_DMARQ;
|
||||||
if (ncr.bufpos>=ncr.datalen) {
|
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;
|
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==0x90) ncr.selected=4;
|
||||||
if (ncr.dout==0xA0) ncr.selected=5;
|
if (ncr.dout==0xA0) ncr.selected=5;
|
||||||
if (ncr.dout==0xC0) ncr.selected=6;
|
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) {
|
if (((val&INI_BSY)==0) && ncr.state==ST_SELECT) {
|
||||||
ncr.state=ST_SELDONE;
|
ncr.state=ST_SELDONE;
|
||||||
|
@ -220,7 +220,7 @@ void ncrWrite(unsigned int addr, unsigned int dack, unsigned int val) {
|
||||||
//Ack line goes low..
|
//Ack line goes low..
|
||||||
if (ncr.tcr&TCR_IO) {
|
if (ncr.tcr&TCR_IO) {
|
||||||
if (ncr.bufpos!=ncr.bufmax) ncr.din=ncr.buf[ncr.bufpos++];
|
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) {
|
if (val&INI_RST) {
|
||||||
|
@ -244,21 +244,21 @@ void ncrWrite(unsigned int addr, unsigned int dack, unsigned int val) {
|
||||||
parseScsiCmd(1);
|
parseScsiCmd(1);
|
||||||
}
|
}
|
||||||
if ((ncr.tcr&0x7)==TCR_IO) {
|
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;
|
ncr.bufpos=0;
|
||||||
int type=val&(TCR_MSG|TCR_CD);
|
int type=val&(TCR_MSG|TCR_CD);
|
||||||
if (type==0) {
|
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.buf=ncr.data.data;
|
||||||
ncr.bufmax=sizeof(ncr.data.data);
|
ncr.bufmax=sizeof(ncr.data.data);
|
||||||
} else if (type==TCR_CD) {
|
} 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.buf=ncr.data.cmd;
|
||||||
ncr.bufmax=sizeof(ncr.data.cmd);
|
ncr.bufmax=sizeof(ncr.data.cmd);
|
||||||
ncr.datalen=1;
|
ncr.datalen=1;
|
||||||
} else if (type==(TCR_CD|TCR_MSG)) {
|
} 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.buf=ncr.data.msg;
|
||||||
ncr.bufmax=sizeof(ncr.data.msg);
|
ncr.bufmax=sizeof(ncr.data.msg);
|
||||||
ncr.datalen=1;
|
ncr.datalen=1;
|
||||||
|
|
|
@ -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)
|
|
@ -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");
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
Binary file not shown.
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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();
|
||||||
|
}
|
|
@ -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
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
void sniff_open(char *name);
|
||||||
|
void sniff_write(uint8_t *buff, int len);
|
|
@ -3,31 +3,38 @@
|
||||||
#include "scc.h"
|
#include "scc.h"
|
||||||
#include "m68k.h"
|
#include "m68k.h"
|
||||||
#include "hexdump.h"
|
#include "hexdump.h"
|
||||||
#include "localtalk.h"
|
#include "network/localtalk.h"
|
||||||
|
#include <string.h>
|
||||||
/*
|
/*
|
||||||
Emulation of the Zilog 8530 SCC.
|
Emulation of the Zilog 8530 SCC.
|
||||||
|
|
||||||
This is an extremely minimal SCC implementation: it only somewhat implements the interrupt mechanism for the
|
Supports basic mouse pins plus hacked in LocalTalk
|
||||||
DCD pins because that is what is needed for the mouse to work.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
void sccIrq(int ena);
|
void sccIrq(int ena);
|
||||||
|
|
||||||
#define BUFLEN 8192
|
#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 {
|
typedef struct {
|
||||||
int dcd;
|
int dcd;
|
||||||
int cts;
|
int cts;
|
||||||
int wr1;
|
int wr1, wr15;
|
||||||
int sdlcaddr;
|
int sdlcaddr;
|
||||||
int wr15;
|
|
||||||
int hunting;
|
int hunting;
|
||||||
int txTimer;
|
int txTimer;
|
||||||
uint8_t txData[BUFLEN];
|
uint8_t txData[BUFLEN];
|
||||||
uint8_t rxData[BUFLEN];
|
RxBuf rx[NO_RXBUF];
|
||||||
int txPos, rxPos, rxLen;
|
int txPos;
|
||||||
|
int rxPos;
|
||||||
|
int rxBufCur;
|
||||||
int rxDelay;
|
int rxDelay;
|
||||||
} SccChan;
|
} SccChan;
|
||||||
|
|
||||||
|
@ -36,10 +43,57 @@ typedef struct {
|
||||||
int intpending;
|
int intpending;
|
||||||
int intpendingOld;
|
int intpendingOld;
|
||||||
SccChan chan[2];
|
SccChan chan[2];
|
||||||
|
int wr2, wr9;
|
||||||
} Scc;
|
} Scc;
|
||||||
|
|
||||||
static Scc 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.
|
//WR15 is the External/Status Interrupt Control and has the interrupt enable bits.
|
||||||
#define SCC_WR15_BREAK (1<<7)
|
#define SCC_WR15_BREAK (1<<7)
|
||||||
#define SCC_WR15_TXU (1<<6)
|
#define SCC_WR15_TXU (1<<6)
|
||||||
|
@ -59,9 +113,9 @@ static Scc scc;
|
||||||
|
|
||||||
|
|
||||||
static void raiseInt(int chan) {
|
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;
|
scc.intpendingOld=scc.intpending;
|
||||||
// printf("SCC int, pending %x\n", scc.intpending);
|
printf("SCC int, pending %x\n", scc.intpending);
|
||||||
sccIrq(1);
|
sccIrq(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -84,28 +138,51 @@ void sccSetDcd(int chan, int val) {
|
||||||
scc.chan[chan].dcd=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) {
|
void sccTxFinished(int chan) {
|
||||||
hexdump(scc.chan[chan].txData, scc.chan[chan].txPos);
|
hexdump(scc.chan[chan].txData, scc.chan[chan].txPos);
|
||||||
localtalkSend(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].txPos=0;
|
||||||
scc.chan[chan].hunting=1;
|
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) {
|
static void triggerRx(int chan) {
|
||||||
if (!scc.chan[chan].hunting) return;
|
if (!scc.chan[chan].hunting) return;
|
||||||
printf("Receiving:\n");
|
int bufid=scc.chan[chan].rxBufCur;
|
||||||
hexdump(scc.chan[chan].rxData, scc.chan[chan].rxLen);
|
printf("SCC: Receiving bufid %d:\n", bufid);
|
||||||
if (scc.chan[chan].rxData[0]==0xFF || scc.chan[chan].rxData[0]==scc.chan[chan].sdlcaddr) {
|
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;
|
scc.chan[chan].rxPos=0;
|
||||||
|
printf("WR15: 0x%X WR1: %X\n", scc.chan[chan].wr15, scc.chan[chan].wr1);
|
||||||
//Sync int
|
//Sync int
|
||||||
if (scc.chan[chan].wr15&SCC_WR15_SYNC) {
|
if (scc.chan[chan].wr15&SCC_WR15_SYNC) {
|
||||||
scc.intpending|=(chan?SCC_WR3_CHA_EXT:SCC_WR3_CHB_EXT);
|
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;
|
scc.chan[chan].hunting=0;
|
||||||
} else {
|
} 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) {
|
if ((val&0x38)==0x18) {
|
||||||
//SCC abort: parse whatever we sent
|
//SCC abort: parse whatever we sent
|
||||||
printf("SCC ABORT: Sent data\n");
|
// printf("SCC ABORT: Sent data\n");
|
||||||
sccTxFinished(chan);
|
sccTxFinished(chan);
|
||||||
}
|
}
|
||||||
if ((val&0xc0)==0xC0) {
|
if ((val&0xc0)==0xC0) {
|
||||||
//reset tx underrun latch
|
//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) {
|
} else if (reg==1) {
|
||||||
scc.chan[chan].wr1=val;
|
scc.chan[chan].wr1=val;
|
||||||
|
} else if (reg==2) {
|
||||||
|
scc.wr2=val;
|
||||||
} else if (reg==3) {
|
} else if (reg==3) {
|
||||||
//bitsperchar1, bitsperchar0, autoenables, enterhuntmode, rxcrcen, addresssearch, synccharloadinh, rxena
|
//bitsperchar1, bitsperchar0, autoenables, enterhuntmode, rxcrcen, addresssearch, synccharloadinh, rxena
|
||||||
//autoenable: cts = tx ena, dcd = rx ena
|
//autoenable: cts = tx ena, dcd = rx ena
|
||||||
|
@ -161,12 +243,15 @@ void sccWrite(unsigned int addr, unsigned int val) {
|
||||||
scc.chan[chan].sdlcaddr=val;
|
scc.chan[chan].sdlcaddr=val;
|
||||||
} else if (reg==8) {
|
} else if (reg==8) {
|
||||||
scc.chan[chan].txData[scc.chan[chan].txPos++]=val;
|
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;
|
scc.chan[chan].txTimer+=30;
|
||||||
|
} else if (reg==9) {
|
||||||
|
scc.wr9=val;
|
||||||
} else if (reg==15) {
|
} else if (reg==15) {
|
||||||
scc.chan[chan].wr15=val;
|
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) {
|
if (reg==0) {
|
||||||
val=(1<<2); //tx buffer always empty
|
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].txTimer==0) val|=(1<<6);
|
||||||
if (scc.chan[chan].dcd) val|=(1<<3);
|
if (scc.chan[chan].dcd) val|=(1<<3);
|
||||||
if (scc.chan[chan].cts) val|=(1<<5);
|
if (scc.chan[chan].cts) val|=(1<<5);
|
||||||
if (scc.chan[chan].hunting) val|=(1<<4);
|
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) {
|
} 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
|
//EndOfFrame, CRCErr, RXOverrun, ParityErr, Residue0, Residue1, Residue2, AllSent
|
||||||
val=0x7; //residue code 011, all sent
|
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) {
|
} else if (reg==2 && chan==SCC_CHANB) {
|
||||||
//We assume this also does an intack.
|
//We assume this also does an intack.
|
||||||
int rsn=0;
|
int rsn=0;
|
||||||
if (scc.intpending & SCC_WR3_CHB_EXT) {
|
if (scc.intpending & SCC_WR3_CHB_EXT) {
|
||||||
rsn=1;
|
rsn=1;
|
||||||
scc.intpending&=~SCC_WR3_CHB_EXT;
|
scc.intpending&=~SCC_WR3_CHB_EXT;
|
||||||
}
|
} else if (scc.intpending & SCC_WR3_CHA_EXT) {
|
||||||
if (scc.intpending & SCC_WR3_CHA_EXT) {
|
|
||||||
rsn=5;
|
rsn=5;
|
||||||
scc.intpending&=~SCC_WR3_CHA_EXT;
|
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&0x38) raiseInt(SCC_CHANA);
|
||||||
if (scc.intpending&0x07) raiseInt(SCC_CHANB);
|
if (scc.intpending&0x07) raiseInt(SCC_CHANB);
|
||||||
} else if (reg==3) {
|
} else if (reg==3) {
|
||||||
if (chan==SCC_CHANA) val=scc.intpending; else val=0;
|
if (chan==SCC_CHANA) val=scc.intpending; else val=0;
|
||||||
} else if (reg==8) {
|
} else if (reg==8) {
|
||||||
//rx buffer
|
//rx buffer
|
||||||
if (scc.chan[chan].rxLen && !scc.chan[chan].rxDelay) {
|
|
||||||
val=scc.chan[chan].rxData[scc.chan[chan].rxPos++];
|
if (rxHasByte(chan)) {
|
||||||
if (scc.chan[chan].rxPos==scc.chan[chan].rxLen) {
|
int left;
|
||||||
scc.chan[chan].rxLen=0;
|
val=rxByte(chan, &left);
|
||||||
} else {
|
printf("SCC READ val %x, %d bytes left\n", val, left);
|
||||||
|
if (left!=0) {
|
||||||
int rxintena=scc.chan[chan].wr1&0x18;
|
int rxintena=scc.chan[chan].wr1&0x18;
|
||||||
if (rxintena==0x10) {
|
if (rxintena==0x10) {
|
||||||
scc.intpending|=(chan?SCC_WR3_CHA_RX:SCC_WR3_CHB_RX);
|
scc.intpending|=(chan?SCC_WR3_CHA_RX:SCC_WR3_CHB_RX);
|
||||||
raiseInt(chan);
|
raiseInt(chan);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (scc.chan[chan].rxPos==scc.chan[chan].rxLen-1) scc.chan[chan].hunting=1;
|
if (left==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].wr15&SCC_WR15_BREAK) {
|
||||||
scc.intpending|=(chan?SCC_WR3_CHA_EXT:SCC_WR3_CHB_EXT);
|
scc.intpending|=(chan?SCC_WR3_CHA_EXT:SCC_WR3_CHB_EXT);
|
||||||
raiseInt(chan);
|
raiseInt(chan);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
printf("SCC READ but no data?\n");
|
||||||
val=0;
|
val=0;
|
||||||
}
|
}
|
||||||
} else if (reg==10) {
|
} else if (reg==10) {
|
||||||
|
@ -236,7 +336,7 @@ unsigned int sccRead(unsigned int addr) {
|
||||||
} else if (reg==15) {
|
} else if (reg==15) {
|
||||||
val=scc.chan[chan].wr15;
|
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;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -246,15 +346,12 @@ void sccTick() {
|
||||||
if (scc.chan[n].txTimer>0) {
|
if (scc.chan[n].txTimer>0) {
|
||||||
scc.chan[n].txTimer--;
|
scc.chan[n].txTimer--;
|
||||||
if (scc.chan[n].txTimer==0) {
|
if (scc.chan[n].txTimer==0) {
|
||||||
printf("Tx buffer empty: Sent data\n");
|
// printf("Tx buffer empty: Sent data\n");
|
||||||
sccTxFinished(n);
|
sccTxFinished(n);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (scc.chan[n].rxDelay!=0) {
|
if (rxBufTick(n)) {
|
||||||
scc.chan[n].rxDelay--;
|
triggerRx(n);
|
||||||
if (scc.chan[n].rxDelay==0) {
|
|
||||||
triggerRx(n);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -264,5 +361,9 @@ void sccInit() {
|
||||||
sccSetDcd(2, 1);
|
sccSetDcd(2, 1);
|
||||||
scc.chan[0].txTimer=-1;
|
scc.chan[0].txTimer=-1;
|
||||||
scc.chan[1].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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,5 +7,5 @@ unsigned int sccRead(unsigned int addr);
|
||||||
void sccSetDcd(int chan, int val);
|
void sccSetDcd(int chan, int val);
|
||||||
void sccInit();
|
void sccInit();
|
||||||
void sccTick();
|
void sccTick();
|
||||||
void sccRecv(int chan, uint8_t *data, int len);
|
void sccRecv(int chan, uint8_t *data, int len, int delay);
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@ void sdlDie() {
|
||||||
|
|
||||||
|
|
||||||
void dispInit() {
|
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 );
|
win=SDL_CreateWindow( "TME", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN );
|
||||||
if (win==0) sdlDie();
|
if (win==0) sdlDie();
|
||||||
surf=SDL_GetWindowSurface(win);
|
surf=SDL_GetWindowSurface(win);
|
||||||
|
|
|
@ -31,12 +31,12 @@ static int hdScsiCmd(SCSITransferData *data, unsigned int cmd, unsigned int len,
|
||||||
if (cmd==0x8 || cmd==0x28) { //read
|
if (cmd==0x8 || cmd==0x28) { //read
|
||||||
fseek(hd->f, lba*512, SEEK_SET);
|
fseek(hd->f, lba*512, SEEK_SET);
|
||||||
fread(data->data, 512, len, hd->f);
|
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;
|
ret=len*512;
|
||||||
} else if (cmd==0xA || cmd==0x2A) { //write
|
} else if (cmd==0xA || cmd==0x2A) { //write
|
||||||
fseek(hd->f, lba*512, SEEK_SET);
|
fseek(hd->f, lba*512, SEEK_SET);
|
||||||
fwrite(data->data, 512, len, hd->f);
|
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;
|
ret=0;
|
||||||
} else if (cmd==0x12) { //inquiry
|
} else if (cmd==0x12) { //inquiry
|
||||||
printf("HD: Inquery\n");
|
printf("HD: Inquery\n");
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include "tmeconfig.h"
|
#include "tmeconfig.h"
|
||||||
|
#include "snd.h"
|
||||||
|
|
||||||
static void *loadRom(char *file) {
|
static void *loadRom(char *file) {
|
||||||
int i;
|
int i;
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
void sndInit();
|
||||||
|
int sndDone();
|
||||||
|
int sndPush(uint8_t *data, int volume);
|
|
@ -23,11 +23,14 @@
|
||||||
#else
|
#else
|
||||||
|
|
||||||
|
|
||||||
#ifdef CONFIG_SPIRAM_USE_MEMMAP
|
#if defined(CONFIG_SPIRAM_USE_MEMMAP) || defined(HOSTBUILD)
|
||||||
|
|
||||||
#define TME_RAMSIZE (4*1024*1024)
|
#define TME_RAMSIZE (4*1024*1024)
|
||||||
#define TME_SCREENBUF 0x3FA700
|
#define TME_SCREENBUF 0x3FA700
|
||||||
#define TME_SCREENBUF_ALT 0x3F2700
|
#define TME_SCREENBUF_ALT 0x3F2700
|
||||||
|
#define TME_SNDBUF 0x3FFD00
|
||||||
|
#define TME_SNDBUF_ALT 0x3FA100
|
||||||
|
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
|
|
12
sdkconfig
12
sdkconfig
|
@ -270,8 +270,6 @@ CONFIG_FREERTOS_THREAD_LOCAL_STORAGE_POINTERS=1
|
||||||
CONFIG_FREERTOS_ASSERT_FAIL_ABORT=y
|
CONFIG_FREERTOS_ASSERT_FAIL_ABORT=y
|
||||||
CONFIG_FREERTOS_ASSERT_FAIL_PRINT_CONTINUE=
|
CONFIG_FREERTOS_ASSERT_FAIL_PRINT_CONTINUE=
|
||||||
CONFIG_FREERTOS_ASSERT_DISABLE=
|
CONFIG_FREERTOS_ASSERT_DISABLE=
|
||||||
CONFIG_FREERTOS_BREAK_ON_SCHEDULER_START_JTAG=y
|
|
||||||
CONFIG_ENABLE_MEMORY_DEBUG=
|
|
||||||
CONFIG_FREERTOS_IDLE_TASK_STACKSIZE=1024
|
CONFIG_FREERTOS_IDLE_TASK_STACKSIZE=1024
|
||||||
CONFIG_FREERTOS_ISR_STACKSIZE=2000
|
CONFIG_FREERTOS_ISR_STACKSIZE=2000
|
||||||
CONFIG_FREERTOS_LEGACY_HOOKS=
|
CONFIG_FREERTOS_LEGACY_HOOKS=
|
||||||
|
@ -290,6 +288,11 @@ CONFIG_HEAP_POISONING_LIGHT=
|
||||||
CONFIG_HEAP_POISONING_COMPREHENSIVE=
|
CONFIG_HEAP_POISONING_COMPREHENSIVE=
|
||||||
CONFIG_HEAP_TRACING=
|
CONFIG_HEAP_TRACING=
|
||||||
|
|
||||||
|
#
|
||||||
|
# libsodium
|
||||||
|
#
|
||||||
|
CONFIG_LIBSODIUM_USE_MBEDTLS_SHA=y
|
||||||
|
|
||||||
#
|
#
|
||||||
# Log output
|
# Log output
|
||||||
#
|
#
|
||||||
|
@ -316,6 +319,10 @@ CONFIG_LWIP_IP_REASSEMBLY=
|
||||||
CONFIG_LWIP_STATS=
|
CONFIG_LWIP_STATS=
|
||||||
CONFIG_LWIP_ETHARP_TRUST_IP_MAC=y
|
CONFIG_LWIP_ETHARP_TRUST_IP_MAC=y
|
||||||
CONFIG_TCPIP_RECVMBOX_SIZE=32
|
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
|
# TCP
|
||||||
|
@ -336,7 +343,6 @@ CONFIG_TCP_OVERSIZE_DISABLE=
|
||||||
# UDP
|
# UDP
|
||||||
#
|
#
|
||||||
CONFIG_UDP_RECVMBOX_SIZE=6
|
CONFIG_UDP_RECVMBOX_SIZE=6
|
||||||
CONFIG_LWIP_DHCP_DOES_ARP_CHECK=
|
|
||||||
CONFIG_TCPIP_TASK_STACK_SIZE=2560
|
CONFIG_TCPIP_TASK_STACK_SIZE=2560
|
||||||
CONFIG_PPP_SUPPORT=
|
CONFIG_PPP_SUPPORT=
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue