diff --git a/components/tme/Makefile b/components/tme/Makefile index c3980eb..40ebd2d 100644 --- a/components/tme/Makefile +++ b/components/tme/Makefile @@ -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` diff --git a/components/tme/emu.c b/components/tme/emu.c index 5b8fe9c..0883c93 100644 --- a/components/tme/emu.c +++ b/components/tme/emu.c @@ -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(); diff --git a/components/tme/hexdump.c b/components/tme/hexdump.c new file mode 100644 index 0000000..daa5f29 --- /dev/null +++ b/components/tme/hexdump.c @@ -0,0 +1,64 @@ +//Utility function to perform hexdumps in the default format of the bsd hexdump utility +//(C) 2017 Jeroen Domburg +//This file is public domain where possible or CC0-licensed where not. +//CC0: https://creativecommons.org/share-your-work/public-domain/cc0/ + +#include +#include +#include + +void hexdumpFrom(void *mem, int len, int adrStart) { + uint8_t *data=(uint8_t*)mem; + int pos=0; + while (pos=len) break; + //Print if printable + if (isprint((int)data[pos+i])) { + printf("%c", data[pos+i]); + } else { + printf("."); + } + } + printf("|\n"); + pos+=16; + } + printf("%08x\n", adrStart+len); +} + + +void hexdump(void *mem, int len) { + hexdumpFrom(mem, len, 0); +} + + +//Uncomment the following line and compile 'gcc -o hexdump hexdump.c' to create a barebones hexdump utility that +//reads stdin and dumps the hex content of it to stdout +//#define TESTCASE + +#ifdef TESTCASE +#include +int main(int argc, char **argv) { + char buff[1024]; + int adr=0; + if (argc>1) adr=strtol(argv[1], NULL, 0); + int i=0; + int ch; + while ((ch=getchar())!=EOF) buff[i++]=ch; + hexdumpFrom(buff, i, adr); +} +#endif diff --git a/components/tme/hexdump.h b/components/tme/hexdump.h new file mode 100644 index 0000000..16c2494 --- /dev/null +++ b/components/tme/hexdump.h @@ -0,0 +1,7 @@ +#ifndef HEXDUMP_H +#define HEXDUMP_H + +void hexdump(void *mem, int len); +void hexdumpFrom(void *mem, int len, int addrFrom); + +#endif \ No newline at end of file diff --git a/components/tme/localtalk.c b/components/tme/localtalk.c new file mode 100644 index 0000000..bbac8b5 --- /dev/null +++ b/components/tme/localtalk.c @@ -0,0 +1,18 @@ +#include +#include +#include +#include "hexdump.h" +#include "scc.h" + +void localtalkSend(uint8_t *data, int len) { + uint8_t resp[128]; + if (data[2]==0x81) { + resp[0]=data[1]; + resp[1]=data[0]; + resp[2]=0x82; + sccRecv(1, resp, 3); + printf("LocalTalk: Sent ack\n"); + } else { + printf("LocalTalk... errm... dunno what to do with this (cmd=%x).\n", data[2]); + } +} diff --git a/components/tme/localtalk.h b/components/tme/localtalk.h new file mode 100644 index 0000000..ecbd1f8 --- /dev/null +++ b/components/tme/localtalk.h @@ -0,0 +1,7 @@ +#ifndef LOCALTALK_H +#define LOCALTALK_H + +void localtalkSend(uint8_t *data, int len); + + +#endif \ No newline at end of file diff --git a/components/tme/rtc.c b/components/tme/rtc.c index e723dfe..3000378 100644 --- a/components/tme/rtc.c +++ b/components/tme/rtc.c @@ -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); +} diff --git a/components/tme/scc.c b/components/tme/scc.c index 5190aaa..aef5758 100644 --- a/components/tme/scc.c +++ b/components/tme/scc.c @@ -2,23 +2,40 @@ #include #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; +} + diff --git a/components/tme/scc.h b/components/tme/scc.h index 4836117..da1deaa 100644 --- a/components/tme/scc.h +++ b/components/tme/scc.h @@ -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); diff --git a/components/tme/sdl/main.c b/components/tme/sdl/main.c index 4d303b7..22ab1e7 100644 --- a/components/tme/sdl/main.c +++ b/components/tme/sdl/main.c @@ -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); }