diff --git a/Makefile b/Makefile index 9e25979..a05e1c8 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,8 @@ TARGET:=tme MUSASHI_GEN_SRC:=musashi/m68kops.c musashi/m68kopac.c musashi/m68kopdm.c musashi/m68kopnz.c -OBJ:=$(MUSASHI_GEN_SRC:%.x=%.o) musashi/m68kcpu.o main.o emu.o disp.o iwm.o via.o +OBJ:=$(MUSASHI_GEN_SRC:%.x=%.o) musashi/m68kcpu.o main.o emu.o disp.o iwm.o via.o rtc.o #musashi/m68kdasm.o -CFLAGS=-Wall -I. -I./musashi -ggdb `sdl2-config --cflags` +CFLAGS=-Wall -I. -I./musashi -Og -ggdb `sdl2-config --cflags` LDFLAGS=`sdl2-config --libs` $(TARGET): $(OBJ) diff --git a/emu.c b/emu.c index c4bd998..695276c 100644 --- a/emu.c +++ b/emu.c @@ -5,11 +5,13 @@ #include #include #include +#include #include "config.h" #include "m68k.h" #include "disp.h" #include "iwm.h" #include "via.h" +#include "rtc.h" unsigned char *macRom; unsigned char *macRam; @@ -33,7 +35,7 @@ unsigned int m68k_read_memory_8(unsigned int address) { ret=macRom[romAdr&(TME_ROMSIZE-1)]; // rom_remap=0; //HACK } else if (address >= 0xE80000 && address < 0xf00000) { - ret=viaRead((address>>8)&0xf); + ret=viaRead((address>>9)&0xf); } else if (address >= 0xc00000 && address < 0xe00000) { ret=iwmRead((address>>9)&0xf); } else { @@ -51,7 +53,7 @@ void m68k_write_memory_8(unsigned int address, unsigned int value) { } else if (address >= 0x600000 && address < 0xA00000) { macRam[address & (TME_RAMSIZE-1)]=value; } else if (address >= 0xE80000 && address < 0xf00000) { - viaWrite((address>>8)&0xf, value); + viaWrite((address>>9)&0xf, value); } else if (address >= 0xc00000 && address < 0xe00000) { iwmWrite((address>>9)&0xf, value); } else { @@ -59,24 +61,58 @@ void m68k_write_memory_8(unsigned int address, unsigned int value) { } } +//Should be called every second. +void printFps() { + struct timeval tv; + static struct timeval oldtv; + gettimeofday(&tv, NULL); + if (oldtv.tv_sec!=0) { + long msec=(tv.tv_sec-oldtv.tv_sec)*1000; + msec+=(tv.tv_usec-oldtv.tv_usec)/1000; + printf("Speed: %d%%\n", 100000/msec); + } + oldtv.tv_sec=tv.tv_sec; + oldtv.tv_usec=tv.tv_usec; +} + +#define GRAN 100 void tmeStartEmu(void *rom) { + int ca1=0, ca2=0; + int x, frame=0; macRom=rom; macRam=malloc(TME_RAMSIZE); for (int x=0; x=60) { + ca2^=1; + viaControlWrite(VIA_CA2, ca2); + rtcTick(); + frame=0; + printFps(); + } } } +void viaIrq(int req) { +// printf("IRQ %d\n", req); + m68k_set_irq(req?1:0); +} //Mac uses an 68008, which has an external 16-bit bus. Hence, it should be okay to do everything using 16-bit //reads/writes. @@ -104,6 +140,12 @@ void m68k_write_memory_16(unsigned int address, unsigned int value) { m68k_write_memory_8(address+1, value&0xff); } +void m68k_int_ack(int irq) { + //Mac has level interrupts; no ack. Fake by raising the irq as soon as + //it's serviced. + m68k_set_irq(irq); +} + void viaCbPortAWrite(unsigned int val) { video_remap=(val&(1<<6))?1:0; rom_remap=(val&(1<<4))?1:0; @@ -111,5 +153,8 @@ void viaCbPortAWrite(unsigned int val) { } void viaCbPortBWrite(unsigned int val) { + int b; + b=rtcCom(val&4, val&1, val&2); + if (b) viaSet(VIA_PORTB, 1); else viaClear(VIA_PORTB, 1); } diff --git a/m68kconf.h b/m68kconf.h old mode 100755 new mode 100644 index f384337..ca39562 --- a/m68kconf.h +++ b/m68kconf.h @@ -87,8 +87,8 @@ * If off, all interrupts will be autovectored and all interrupt requests will * auto-clear when the interrupt is serviced. */ -#define M68K_EMULATE_INT_ACK OPT_OFF -#define M68K_INT_ACK_CALLBACK(A) your_int_ack_handler_function(A) +#define M68K_EMULATE_INT_ACK OPT_ON +#define M68K_INT_ACK_CALLBACK(A) m68k_int_ack(A) /* If ON, CPU will call the breakpoint acknowledge callback when it encounters diff --git a/rtc.c b/rtc.c new file mode 100644 index 0000000..3cc6e70 --- /dev/null +++ b/rtc.c @@ -0,0 +1,48 @@ +#include +#include + + +typedef struct { + int lastClkVal; + int pos; + uint8_t cmd; + uint8_t mem[32]; +} Rtc; + +static Rtc rtc; + +void rtcTick() { + int x; + for (x=0; x<3; x++) { + rtc.mem[x]++; + if (rtc.mem[x]!=0) return; + } +} + +int rtcCom(int en, int dat, int clk) { + int ret=0; + clk=clk?1:0; + if (en) { + rtc.pos=0; + rtc.cmd=0; + } else { + if (clk!=rtc.lastClkVal && !clk) { + if (rtc.pos<8 || (rtc.pos<16 && ((rtc.cmd&0x8000)==0)) ) { + if (dat) rtc.cmd|=(1<<(15-rtc.pos)); + } else if (rtc.cmd&0x8000) { + if (rtc.pos==8) { + rtc.cmd|=rtc.mem[(rtc.cmd&0x7C00)>>10]; + } + 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; + printf("RTC/PRAM CMD %x\n", rtc.cmd); + } + rtc.pos++; + printf("RTC/PRAM pos %d CMD %x\n", rtc.pos, rtc.cmd); + } + } + rtc.lastClkVal=clk; + return ret; +} + diff --git a/rtc.h b/rtc.h new file mode 100644 index 0000000..fce4959 --- /dev/null +++ b/rtc.h @@ -0,0 +1,2 @@ +void rtcTick(); +int rtcCom(int en, int dat, int clk); diff --git a/via.c b/via.c index f5351aa..b29aff6 100644 --- a/via.c +++ b/via.c @@ -5,22 +5,124 @@ void viaCbPortAWrite(unsigned int val); void viaCbPortBWrite(unsigned int val); +void viaIrq(); +#define IFR_IRQ (1<<7) +#define IFR_T1 (1<<6) +#define IFR_T2 (1<<5) +#define IFR_CB1 (1<<4) +#define IFR_CB2 (1<<3) +#define IFR_SR (1<<2) +#define IFR_CA1 (1<<1) +#define IFR_CA2 (1<<0) + +#define PCR_NEG 0 +#define PCR_NEG_NOCLR 1 +#define PCR_POS 2 +#define PCR_POS_NOCLR 3 +#define PCR_HANDSHAKE 4 +#define PCR_PULSEOUT 5 +#define PCR_MAN_LO 6 +#define PCR_MAN_HI 7 typedef struct { - uint8_t ddra; - uint8_t ddrb; + uint8_t ddra, ddrb; + uint8_t ina, inb; + uint8_t outa, outb; + uint16_t timer1, timer2; + uint16_t latch1, latch2; + uint8_t ifr, ier; + uint8_t pcr, acr; + uint8_t controlin[2]; } Via; static Via via; +static const char* const viaRegNames[]={ + "ORB", "ORA", "DDRB", "DDRA", "T1C-L", "T1C-H", "T1L-L", "T1L-H", "T2L-L", + "T2C-H", "SR", "ACR", "PCR", "IFR", "IER", "ORA-NC" +}; + + +void viaSet(int no, int mask) { + if (no==VIA_PORTA) via.ina|=mask; else via.inb|=mask; +} + +void viaClear(int no, int mask) { + if (no==VIA_PORTA) via.ina&=~mask; else via.inb&=~mask; +} + +void viaStep(int clockcycles) { + while(clockcycles--) { + if ((via.timer2!=0) || (via.acr&(1<<6))) via.timer2--; + if (via.timer1==0) { + via.ifr|=IFR_T1; + via.timer1=via.latch1; + } + if ((via.timer2!=0) || (via.acr&(1<<5))) via.timer2--; + if (via.timer2==0) { + via.ifr|=IFR_T2; + } + } +} + +static void viaCheckIrq() { + static int oldmint=0; + int mint=(via.ifr&via.ier)&0x7F; + if (mint) { + via.ifr|=IFR_IRQ; + viaIrq(1); +// printf("VIA: Raised IRQ because masked if is %x\n", mint); + } else if (!mint) { + if (via.ifr&IFR_IRQ) viaIrq(0); + via.ifr&=~IFR_IRQ; + } +} + +static int pcrFor(int no) { + const int shift[]={0, 1, 4, 5}; + const int mask[]={1, 3, 1, 3}; + int pcr=(via.pcr>>shift[no])&mask[no]; + if (no&1) { + if (pcr) return PCR_NEG; else return PCR_POS; + } else { + return pcr; + } +} + +static void accessPort(int no) { + via.ifr&=~(no?IFR_CB1:IFR_CA1); + int pcrca2=pcrFor(no?VIA_CB2:VIA_CA2); + if (pcrca2==PCR_NEG || pcrca2==PCR_POS) { + via.ifr&=~(no?IFR_CB2:IFR_CA2); + } + viaCheckIrq(); +} + +void viaControlWrite(int no, int val) { + const int ifbits[]={IFR_CA1, IFR_CA2, IFR_CB1, IFR_CB2}; + int pcr=pcrFor(no); + if (val) val=1; + if (via.controlin[no]!=val) { + if ( ((pcr==PCR_NEG || pcr==PCR_NEG_NOCLR) && !val) || + ((pcr==PCR_POS || pcr==PCR_POS_NOCLR) && val) ) { + via.ifr|=ifbits[no]; + viaCheckIrq(); + } + } + via.controlin[no]=val; +} + void viaWrite(unsigned int addr, unsigned int val) { if (addr==0x0) { //ORB + viaCbPortBWrite(val); + accessPort(1); } else if (addr==0x1) { //ORA viaCbPortAWrite(val); + accessPort(0); } else if (addr==0x2) { //DDRB via.ddrb=val; @@ -29,30 +131,56 @@ void viaWrite(unsigned int addr, unsigned int val) { via.ddra=val; } else if (addr==0x4) { //T1L-L + via.latch1=(via.latch1&0xff00)|val; } else if (addr==0x5) { //T1C-H + via.latch1=(via.latch1&0x00ff)|(val<<8); + via.timer1=via.latch1; + via.ifr&=~IFR_T1; + viaCheckIrq(); } else if (addr==0x6) { //T1L-L + via.latch1=(via.latch1&0xff00)|val; } else if (addr==0x7) { //T1L-H + via.latch1=(via.latch1&0x00ff)|(val<<8); + via.ifr&=~IFR_T1; + viaCheckIrq(); } else if (addr==0x8) { //T2L-l + via.latch2=val; } else if (addr==0x9) { //T2C-H + via.timer2=via.latch2|(val<<8); + via.ifr&=~IFR_T2; + viaCheckIrq(); } else if (addr==0xa) { //SR + printf("6522: Unimplemented: Write %x to SR?\n", val); } else if (addr==0xb) { //ACR + via.acr=val; } else if (addr==0xc) { //PCR + via.pcr=val; } else if (addr==0xd) { //IFR + via.ifr&=~val; + viaCheckIrq(); } else if (addr==0xe) { //IER + if (val&0x80) { + via.ier|=val; + } else { + via.ier&=~val; + } + via.ier&=0x7f; + viaCheckIrq(); } else if (addr==0xf) { //ORA + viaCbPortAWrite(val); } - printf("VIA write %x val %x\n", addr, val); +// printf("VIA write %s val %x\n", viaRegNames[addr], val); } @@ -61,8 +189,12 @@ unsigned int viaRead(unsigned int addr) { unsigned int val=0; if (addr==0x0) { //ORB + val=via.inb; + accessPort(1); } else if (addr==0x1) { //ORA + val=via.ina; + accessPort(0); } else if (addr==0x2) { //DDRB val=via.ddrb; @@ -71,29 +203,45 @@ unsigned int viaRead(unsigned int addr) { val=via.ddra; } else if (addr==0x4) { //T1L-L + val=via.timer1&0xff; + via.ifr&=~IFR_T1; + viaCheckIrq(); } else if (addr==0x5) { //T1C-H + val=via.timer1>>8; } else if (addr==0x6) { //T1L-L + val=via.latch1&0xff; } else if (addr==0x7) { //T1L-H + val=via.latch1&0xff; } else if (addr==0x8) { //T2L-l + val=via.timer2&0xff; + via.ifr&=~IFR_T2; + viaCheckIrq(); } else if (addr==0x9) { //T2C-H + val=via.timer2>>8; } else if (addr==0xa) { //SR + printf("6522: Unimplemented: Read from SR?\n"); } else if (addr==0xb) { //ACR + val=via.acr; } else if (addr==0xc) { //PCR + val=via.pcr; } else if (addr==0xd) { //IFR + val=via.ifr; } else if (addr==0xe) { //IER + val=via.ier; } else if (addr==0xf) { //ORA + val=via.ina; } - printf("PC %x VIA read %x val %x\n", pc, addr, val); +// printf("PC %x VIA read %s val %x\n", pc, viaRegNames[addr], val); return val; } diff --git a/via.h b/via.h index 86d412f..0891e67 100644 --- a/via.h +++ b/via.h @@ -1,2 +1,15 @@ + +#define VIA_CA1 0 +#define VIA_CA2 1 +#define VIA_CB1 2 +#define VIA_CB2 3 + +#define VIA_PORTA 0 +#define VIA_PORTB 1 + void viaWrite(unsigned int addr, unsigned int val); unsigned int viaRead(unsigned int addr); +void viaControlWrite(int no, int val); +void viaStep(int clockcycles); +void viaSet(int no, int mask); +void viaClear(int no, int mask);