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_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
emu.o iwm.o via.o rtc.o ncr.o scc.o mouse.o hostbuild/espspiramemu.o hexdump.o localtalk.o
#musashi/m68kdasm.o
CFLAGS=-Wall -I. -I./musashi -I./hostbuild -Og -ggdb `sdl2-config --cflags`
LDFLAGS=`sdl2-config --libs`

View File

@ -458,11 +458,11 @@ void tmeStartEmu(void *rom) {
printf("Creating HD and registering it...\n");
SCSIDevice *hd=hdCreate("hd.img");
ncrRegisterDevice(6, hd);
printf("Initializing m68k...\n");
viaClear(VIA_PORTA, 0x7F);
viaSet(VIA_PORTA, 0x80);
viaClear(VIA_PORTA, 0xFF);
viaSet(VIA_PORTB, (1<<3));
sccInit();
printf("Initializing m68k...\n");
m68k_init();
printf("Setting CPU type and resetting...");
@ -475,6 +475,7 @@ void tmeStartEmu(void *rom) {
for (x=0; x<8000000/60; x+=10) {
m68k_execute(10);
viaStep(1); //should run at 783.36KHz
sccTick();
m++;
if (m>=1000) {
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 ret=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);
} 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);
}
rtc.pos++;
@ -45,3 +50,6 @@ int rtcCom(int en, int dat, int clk) {
return ret;
}
void rtcInit(char *mem) {
memcpy(rtc.mem, mem, 32);
}

View File

@ -2,23 +2,40 @@
#include <stdint.h>
#include "scc.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.
*/
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 {
int regptr;
int intpending;
int intpendingOld;
int dcd[2];
int cts[2];
int wr1[2];
int wr15[2];
SccChan chan[2];
} Scc;
static Scc scc;
@ -40,8 +57,9 @@ static Scc scc;
#define SCC_WR3_CHA_TX (1<<4)
#define SCC_WR3_CHA_RX (1<<5)
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;
// printf("SCC int, pending %x\n", scc.intpending);
sccIrq(1);
@ -50,18 +68,59 @@ static void raiseInt(int chan) {
void sccSetDcd(int chan, int val) {
val=val?1:0;
if (scc.dcd[chan]!=val) {
if (scc.chan[chan].dcd!=val) {
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 {
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);
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);
scc.dcd[chan]=val;
scc.chan[chan].dcd=val;
}
void sccTxFinished(int chan) {
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) {
@ -75,6 +134,7 @@ void sccWrite(unsigned int addr, unsigned int val) {
reg=scc.regptr;
scc.regptr=0;
}
if (reg==0) {
scc.regptr=val&0x7;
if ((val&0x38)==0x8) scc.regptr|=8;
@ -82,12 +142,31 @@ void sccWrite(unsigned int addr, unsigned int val) {
scc.intpending=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) {
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) {
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;
}
if (reg==0) {
val=(1<<2);
if (scc.dcd[chan]) val|=(1<<3);
if (scc.cts[chan]) val|=(1<<5);
val=(1<<2); //tx buffer always empty
if (scc.chan[chan].rxLen && !scc.chan[chan].rxDelay) 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
} 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) {
//We assume this also does an intack.
int rsn=0;
@ -124,10 +209,60 @@ unsigned int sccRead(unsigned int addr) {
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 {
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) {
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;
}
//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);
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);

View File

@ -21,7 +21,22 @@ static void *loadRom(char *file) {
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) {
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);
}