LocalTalk LLAP now works. Implemented this as a dummy network which responds with an ack to each enq, which coincidentally makes the Mac hang...

This commit is contained in:
Jeroen Domburg 2017-09-04 09:25:24 +08:00
parent 6d04d3b857
commit c59ce7fbb0
10 changed files with 284 additions and 26 deletions

View File

@ -4,7 +4,7 @@ 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 \
emu.o iwm.o via.o rtc.o ncr.o scc.o mouse.o hostbuild/espspiramemu.o emu.o iwm.o via.o rtc.o ncr.o scc.o mouse.o hostbuild/espspiramemu.o hexdump.o localtalk.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`
LDFLAGS=`sdl2-config --libs` LDFLAGS=`sdl2-config --libs`

View File

@ -458,11 +458,11 @@ void tmeStartEmu(void *rom) {
printf("Creating HD and registering it...\n"); printf("Creating HD and registering it...\n");
SCSIDevice *hd=hdCreate("hd.img"); SCSIDevice *hd=hdCreate("hd.img");
ncrRegisterDevice(6, hd); ncrRegisterDevice(6, hd);
printf("Initializing m68k...\n");
viaClear(VIA_PORTA, 0x7F); viaClear(VIA_PORTA, 0x7F);
viaSet(VIA_PORTA, 0x80); viaSet(VIA_PORTA, 0x80);
viaClear(VIA_PORTA, 0xFF); viaClear(VIA_PORTA, 0xFF);
viaSet(VIA_PORTB, (1<<3)); viaSet(VIA_PORTB, (1<<3));
sccInit();
printf("Initializing m68k...\n"); printf("Initializing m68k...\n");
m68k_init(); m68k_init();
printf("Setting CPU type and resetting..."); printf("Setting CPU type and resetting...");
@ -475,6 +475,7 @@ void tmeStartEmu(void *rom) {
for (x=0; x<8000000/60; x+=10) { for (x=0; x<8000000/60; x+=10) {
m68k_execute(10); m68k_execute(10);
viaStep(1); //should run at 783.36KHz viaStep(1); //should run at 783.36KHz
sccTick();
m++; m++;
if (m>=1000) { if (m>=1000) {
int r=mouseTick(); int r=mouseTick();

64
components/tme/hexdump.c Normal file
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

7
components/tme/hexdump.h Normal file
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,18 @@
#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

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

View File

@ -19,6 +19,8 @@ void rtcTick() {
} }
} }
extern void saveRtcMem(char *mem);
int rtcCom(int en, int dat, int clk) { int rtcCom(int en, int dat, int clk) {
int ret=0; int ret=0;
clk=clk?1:0; clk=clk?1:0;
@ -35,7 +37,10 @@ int rtcCom(int en, int dat, int clk) {
} }
ret=((rtc.cmd&(1<<(15-rtc.pos)))?1:0); ret=((rtc.cmd&(1<<(15-rtc.pos)))?1:0);
} else if (rtc.pos==15) { } else if (rtc.pos==15) {
if ((rtc.cmd&0x8000)==0) rtc.mem[(rtc.cmd&0x7C00)>>10]=rtc.cmd&0xff; if ((rtc.cmd&0x8000)==0) {
rtc.mem[(rtc.cmd&0x7C00)>>10]=rtc.cmd&0xff;
saveRtcMem(rtc.mem);
}
printf("RTC/PRAM CMD %x\n", rtc.cmd); printf("RTC/PRAM CMD %x\n", rtc.cmd);
} }
rtc.pos++; rtc.pos++;
@ -45,3 +50,6 @@ int rtcCom(int en, int dat, int clk) {
return ret; return ret;
} }
void rtcInit(char *mem) {
memcpy(rtc.mem, mem, 32);
}

View File

@ -2,23 +2,40 @@
#include <stdint.h> #include <stdint.h>
#include "scc.h" #include "scc.h"
#include "m68k.h" #include "m68k.h"
#include "hexdump.h"
#include "localtalk.h"
/* /*
THis is an extremely minimal SCC implementation: it only somewhat implements the interrupt mechanism for the 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. DCD pins because that is what is needed for the mouse to work.
*/ */
void sccIrq(int ena); void sccIrq(int ena);
#define BUFLEN 8192
typedef struct {
int dcd;
int cts;
int wr1;
int sdlcaddr;
int wr15;
int hunting;
int txTimer;
uint8_t txData[BUFLEN];
uint8_t rxData[BUFLEN];
int txPos, rxPos, rxLen;
int rxDelay;
} SccChan;
typedef struct { typedef struct {
int regptr; int regptr;
int intpending; int intpending;
int intpendingOld; int intpendingOld;
int dcd[2]; SccChan chan[2];
int cts[2];
int wr1[2];
int wr15[2];
} Scc; } Scc;
static Scc scc; static Scc scc;
@ -40,8 +57,9 @@ static Scc scc;
#define SCC_WR3_CHA_TX (1<<4) #define SCC_WR3_CHA_TX (1<<4)
#define SCC_WR3_CHA_RX (1<<5) #define SCC_WR3_CHA_RX (1<<5)
static void raiseInt(int chan) { static void raiseInt(int chan) {
if ((scc.wr1[chan]&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);
@ -50,18 +68,59 @@ static void raiseInt(int chan) {
void sccSetDcd(int chan, int val) { void sccSetDcd(int chan, int val) {
val=val?1:0; val=val?1:0;
if (scc.dcd[chan]!=val) { if (scc.chan[chan].dcd!=val) {
if (chan==SCC_CHANA) { if (chan==SCC_CHANA) {
scc.intpending|=SCC_WR3_CHA_EXT; if (scc.chan[SCC_CHANA].wr15&SCC_WR15_DCD) {
scc.intpending|=SCC_WR3_CHA_EXT;
raiseInt(SCC_CHANA);
}
} else { } else {
scc.intpending|=SCC_WR3_CHB_EXT; if (scc.chan[SCC_CHANB].wr15&SCC_WR15_DCD) {
scc.intpending|=SCC_WR3_CHB_EXT;
raiseInt(SCC_CHANB);
}
} }
} }
if ((scc.intpending&SCC_WR3_CHA_EXT) && (scc.wr15[SCC_CHANA]&SCC_WR15_DCD)) raiseInt(SCC_CHANA); scc.chan[chan].dcd=val;
if ((scc.intpending&SCC_WR3_CHB_EXT) && (scc.wr15[SCC_CHANB]&SCC_WR15_DCD)) raiseInt(SCC_CHANB); }
if ((scc.intpending&SCC_WR3_CHA_EXT) && (scc.wr15[SCC_CHANA]&SCC_WR15_CTS)) raiseInt(SCC_CHANA);
if ((scc.intpending&SCC_WR3_CHB_EXT) && (scc.wr15[SCC_CHANB]&SCC_WR15_CTS)) raiseInt(SCC_CHANB); void sccTxFinished(int chan) {
scc.dcd[chan]=val; hexdump(scc.chan[chan].txData, scc.chan[chan].txPos);
localtalkSend(scc.chan[chan].txData, scc.chan[chan].txPos);
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) {
scc.chan[chan].rxPos=0;
//Sync int
if (scc.chan[chan].wr15&SCC_WR15_SYNC) {
scc.intpending|=(chan?SCC_WR3_CHA_EXT:SCC_WR3_CHB_EXT);
raiseInt(chan);
}
//RxD int
int rxintena=scc.chan[chan].wr1&0x18;
if (rxintena==0x10 || rxintena==0x08) {
scc.intpending|=(chan?SCC_WR3_CHA_RX:SCC_WR3_CHB_RX);
raiseInt(chan);
}
scc.chan[chan].hunting=0;
} else {
scc.chan[chan].rxLen=0;
}
} }
void sccWrite(unsigned int addr, unsigned int val) { void sccWrite(unsigned int addr, unsigned int val) {
@ -75,6 +134,7 @@ void sccWrite(unsigned int addr, unsigned int val) {
reg=scc.regptr; reg=scc.regptr;
scc.regptr=0; scc.regptr=0;
} }
if (reg==0) { if (reg==0) {
scc.regptr=val&0x7; scc.regptr=val&0x7;
if ((val&0x38)==0x8) scc.regptr|=8; if ((val&0x38)==0x8) scc.regptr|=8;
@ -82,12 +142,31 @@ void sccWrite(unsigned int addr, unsigned int val) {
scc.intpending=0; scc.intpending=0;
scc.intpendingOld=0; scc.intpendingOld=0;
} }
if ((val&0x38)==0x18) {
//SCC abort: parse whatever we sent
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;
}
} else if (reg==1) { } else if (reg==1) {
scc.wr1[chan]=val; scc.chan[chan].wr1=val;
} else if (reg==3) {
//bitsperchar1, bitsperchar0, autoenables, enterhuntmode, rxcrcen, addresssearch, synccharloadinh, rxena
//autoenable: cts = tx ena, dcd = rx ena
if (val&0x10) scc.chan[chan].hunting=1;
} else if (reg==6) {
scc.chan[chan].sdlcaddr=val;
} else if (reg==8) {
scc.chan[chan].txData[scc.chan[chan].txPos++]=val;
printf("TX! Pos %d\n", scc.chan[chan].txPos);
scc.chan[chan].txTimer+=30;
} else if (reg==15) { } else if (reg==15) {
scc.wr15[chan]=val; scc.chan[chan].wr15=val;
} }
// 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);
} }
@ -103,11 +182,17 @@ unsigned int sccRead(unsigned int addr) {
scc.regptr=0; scc.regptr=0;
} }
if (reg==0) { if (reg==0) {
val=(1<<2); val=(1<<2); //tx buffer always empty
if (scc.dcd[chan]) val|=(1<<3); if (scc.chan[chan].rxLen && !scc.chan[chan].rxDelay) val|=(1<<0);
if (scc.cts[chan]) val|=(1<<5); 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
} else if (reg==1) { } else if (reg==1) {
val=scc.wr1[chan]; //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
} 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;
@ -124,10 +209,60 @@ unsigned int sccRead(unsigned int addr) {
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) {
//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 {
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) {
scc.intpending|=(chan?SCC_WR3_CHA_EXT:SCC_WR3_CHB_EXT);
raiseInt(chan);
}
} else {
val=0;
}
} else if (reg==10) {
//Misc status (mostly SDLC)
val=0;
} else if (reg==15) { } else if (reg==15) {
val=scc.wr15[chan]; 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;
} }
//Called at about 800KHz
void sccTick() {
for (int n=0; n<2; n++) {
if (scc.chan[n].txTimer>0) {
scc.chan[n].txTimer--;
if (scc.chan[n].txTimer==0) {
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);
}
}
}
}
void sccInit() {
sccSetDcd(1, 1);
sccSetDcd(2, 1);
scc.chan[0].txTimer=-1;
scc.chan[1].txTimer=-1;
}

View File

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

View File

@ -21,7 +21,22 @@ static void *loadRom(char *file) {
return ret; return ret;
} }
void saveRtcMem(char *data) {
FILE *f=fopen("pram.dat", "wb");
if (f!=NULL) {
fwrite(data, 32, 1, f);
fclose(f);
}
}
int main(int argc, char **argv) { int main(int argc, char **argv) {
void *rom=loadRom("rom.bin"); void *rom=loadRom("rom.bin");
FILE *f=fopen("pram.dat", "r");
if (f!=NULL) {
char data[32];
fread(data, 32, 1, f);
rtcInit(data);
fclose(f);
}
tmeStartEmu(rom); tmeStartEmu(rom);
} }