diff --git a/src/808x.c b/src/808x.c index a02136a..b6f19df 100644 --- a/src/808x.c +++ b/src/808x.c @@ -804,14 +804,16 @@ void clockhardware() int diff = cycdiff - cycles - current_diff; current_diff += diff; - pit.c[0] -= diff; - pit.c[1] -= diff; - if (pit.gate[2]) pit.c[2] -= diff; + if (pit.running[0]) pit.c[0] -= diff; + if (pit.running[1]) pit.c[1] -= diff; + if (pit.running[2]) pit.c[2] -= diff; if ((pit.c[0] < 1) || (pit.c[1] < 1) || (pit.c[2] < 1)) pit_poll(); timer_clock(diff); } +static int takeint = 0; + int firstrepcycle=1; @@ -826,6 +828,7 @@ void rep(int fv) uint32_t oldds; startrep: temp=FETCH(); + // if (firstrepcycle && temp==0xA5) printf("REP MOVSW %06X:%04X %06X:%04X\n",ds,SI,es,DI); // if (output) printf("REP %02X %04X\n",temp,ipc); switch (temp) @@ -1047,6 +1050,8 @@ void rep(int fv) } CX=c; if (changeds) ds=oldds; + if (IRQTEST) + takeint = 1; // if (pc==ipc) FETCHCLEAR(); } @@ -1056,7 +1061,6 @@ uint16_t lastpc,lastcs; int firstrepcycle; int skipnextprint=0; - int instime=0; //#if 0 void execx86(int cycs) @@ -1102,7 +1106,7 @@ void execx86(int cycs) { // if ((opcode!=0xF2 && opcode!=0xF3) || firstrepcycle) // { - if (!skipnextprint) printf("%04X:%04X : %04X %04X %04X %04X %04X %04X %04X %04X %04X %04X %04X %04X %02X %04X %02X %02X %02X %02X\n",cs,pc,AX,BX,CX,DX,CS,DS,ES,SS,DI,SI,BP,SP,opcode,flags, ram[0x413], ram[0x414], ram[0x415], ram[0x416]); + if (!skipnextprint) printf("%04X:%04X : %04X %04X %04X %04X %04X %04X %04X %04X %04X %04X %04X %04X %02X %04X %i %p %02X\n",cs,pc,AX,BX,CX,DX,CS,DS,ES,SS,DI,SI,BP,SP,opcode,flags, ins, ram, ram[0x1a925]); skipnextprint=0; // ins++; // } @@ -2373,7 +2377,7 @@ void execx86(int cycs) lastpc=pc; lastcs=CS; temp=FETCH(); - + if (ssegs) ss=oldss; writememw(ss,((SP-2)&0xFFFF),flags|0xF000); writememw(ss,((SP-4)&0xFFFF),CS); @@ -2399,6 +2403,7 @@ void execx86(int cycs) SP+=6; cycles-=44; FETCHCLEAR(); + nmi_enable = 1; break; case 0xD0: fetchea(); @@ -3427,7 +3432,22 @@ void execx86(int cycs) loadcs(readmemw(0,addr+2)); FETCHCLEAR(); } - else if ((flags&I_FLAG) && (pic.pend&~pic.mask) && !ssegs && !noint) + else if (nmi && nmi_enable) + { +// output = 3; + writememw(ss,(SP-2)&0xFFFF,flags|0xF000); + writememw(ss,(SP-4)&0xFFFF,CS); + writememw(ss,(SP-6)&0xFFFF,pc); + SP-=6; + addr=2<<2; + flags&=~I_FLAG; + flags&=~T_FLAG; + pc=readmemw(0,addr); + loadcs(readmemw(0,addr+2)); + FETCHCLEAR(); + nmi_enable = 0; + } + else if (takeint && !ssegs && !noint) { temp=picinterrupt(); if (temp!=0xFF) @@ -3447,6 +3467,7 @@ void execx86(int cycs) // printf("INTERRUPT\n"); } } + takeint = (flags&I_FLAG) && (pic.pend&~pic.mask); if (noint) noint=0; ins++; diff --git a/src/Makefile.mingw b/src/Makefile.mingw index afa24e3..e520740 100644 --- a/src/Makefile.mingw +++ b/src/Makefile.mingw @@ -6,7 +6,7 @@ CFLAGS = -O3 -march=i686 -fomit-frame-pointer OBJ = 386.o 808x.o acer386sx.o ali1429.o amstrad.o cdrom-ioctl.o \ config.o cpu.o dac.o device.o dma.o ega.o fdc.o \ headland.o i430vx.o ide.o io.o jim.o keyboard.o keyboard_amstrad.o keyboard_at.o \ - keyboard_olim24.o keyboard_xt.o lpt.o mcr.o mem.o model.o \ + keyboard_olim24.o keyboard_pcjr.o keyboard_xt.o lpt.o mcr.o mem.o model.o \ mouse.o mouse_ps2.o mouse_serial.o neat.o nvr.o olivetti_m24.o \ opti.o pc.o pci.o pic.o piix.o pit.o ppi.o rom.o serial.o sis496.o sound.o sound_ad1848.o sound_adlib.o \ sound_adlibgold.o sound_cms.o sound_emu8k.o sound_gus.o sound_mpu401_uart.o sound_opl.o \ @@ -15,7 +15,7 @@ OBJ = 386.o 808x.o acer386sx.o ali1429.o amstrad.o cdrom-ioctl.o \ vid_ati_mach64.o vid_ati18800.o vid_ati28800.o vid_ati68860_ramdac.o vid_cga.o \ vid_cl5429.o vid_ega.o vid_et4000.o vid_et4000w32.o vid_et4000w32i.o \ vid_hercules.o vid_icd2061.o vid_ics2595.o vid_mda.o vid_olivetti_m24.o \ - vid_oti067.o vid_paradise.o vid_pc1512.o vid_pc1640.o vid_pc200.o vid_s3.o \ + vid_oti067.o vid_paradise.o vid_pc1512.o vid_pc1640.o vid_pc200.o vid_pcjr.o vid_s3.o \ vid_s3_virge.o vid_sdac_ramdac.o vid_stg_ramdac.o vid_svga.o vid_svga_render.o \ vid_tandy.o vid_tgui9440.o vid_tkd8001_ramdac.o vid_tvga.o vid_unk_ramdac.o vid_vga.o \ vid_voodoo.o video.o wd76c10.o win.o win-d3d.o win-d3d-fs.o win-ddraw.o win-ddraw-fs.o win-keyboard.o win-midi.o \ diff --git a/src/cpu.c b/src/cpu.c index d0de431..2586c79 100644 --- a/src/cpu.c +++ b/src/cpu.c @@ -68,6 +68,13 @@ CPU cpus_8088[] = {"", -1, 0, 0, 0, 0} }; +CPU cpus_pcjr[] = +{ + /*8088 PCjr*/ + {"8088/4.77", CPU_8088, 0, 4772727, 1, 0, 0, 0}, + {"", -1, 0, 0, 0, 0} +}; + CPU cpus_8086[] = { /*8086 standard*/ @@ -259,7 +266,7 @@ void cpu_set() cpu_hasrdtsc = 0; cpu_hasMMX = 0; cpu_hasMSR = 0; - + if (cpu_iscyrix) io_sethandler(0x0022, 0x0002, cyrix_read, NULL, NULL, cyrix_write, NULL, NULL, NULL); else diff --git a/src/cpu.h b/src/cpu.h index 51e651f..564691b 100644 --- a/src/cpu.h +++ b/src/cpu.h @@ -61,6 +61,7 @@ extern CPU cpus_Am486[]; extern CPU cpus_Cx486[]; extern CPU cpus_WinChip[]; +extern CPU cpus_pcjr[]; extern CPU cpus_pc1512[]; extern CPU cpus_ibmat[]; extern CPU cpus_acer[]; diff --git a/src/fdc.c b/src/fdc.c index d5b2a0f..e99b805 100644 --- a/src/fdc.c +++ b/src/fdc.c @@ -7,6 +7,31 @@ #include "pic.h" #include "timer.h" +/*FDC*/ +typedef struct FDC +{ + uint8_t dor,stat,command,dat,st0; + int head,track[256],sector,drive,lastdrive; + int pos; + uint8_t params[256]; + uint8_t res[256]; + int pnum,ptot; + int rate; + uint8_t specify[256]; + int eot[256]; + int lock; + int perp; + uint8_t config, pretrk; + int abort; + + int pcjr; + + int watchdog_timer; + int watchdog_count; +} FDC; + +static FDC fdc; + void fdc_poll(); int timetolive; int TRACKS[2] = {80, 80}; @@ -38,6 +63,7 @@ void loaddisc(int d, char *fn) if (ftell(f)<=(160*1024)) { SECTORS[d]=8; TRACKS[d] = 40; SIDES[d]=1; discrate[d]=2; } else if (ftell(f)<=(180*1024)) { SECTORS[d]=9; TRACKS[d] = 40; SIDES[d]=1; discrate[d]=2; } else if (ftell(f)<=(320*1024)) { SECTORS[d]=8; TRACKS[d] = 40; discrate[d]=2; } + else if (ftell(f)<=(360*1024)) { SECTORS[d]=9; TRACKS[d] = 40; discrate[d]=2; } /*Double density*/ else if (ftell(f)<(1024*1024)) { SECTORS[d]=9; TRACKS[d] = 80; discrate[d]=2; } /*Double density*/ else if (ftell(f)<(0x1A4000-1)) { SECTORS[d]=18; TRACKS[d] = 80; discrate[d]=0; } /*High density (not supported by Tandy 1000)*/ else if (ftell(f) == 1884159) { SECTORS[d]=23; TRACKS[d] = 80; discrate[d]=0; } /*XDF format - used by OS/2 Warp*/ @@ -111,6 +137,29 @@ void fdc_reset() } int ins; +static void fdc_int() +{ + if (!fdc.pcjr) + picint(1 << 6); +} + +static void fdc_watchdog_poll(void *p) +{ + FDC *fdc = (FDC *)p; + + fdc->watchdog_count--; + if (fdc->watchdog_count) + fdc->watchdog_timer += 1000 * TIMER_USEC; + else + { +// pclog("Watchdog timed out\n"); + + fdc->watchdog_timer = 0; + if (fdc->dor & 0x20) + picint(1 << 6); + } +} + void fdc_write(uint16_t addr, uint8_t val, void *priv) { // printf("Write FDC %04X %02X %04X:%04X %i %02X %i rate=%i\n",addr,val,cs>>4,pc,ins,fdc.st0,ins,fdc.rate); @@ -120,18 +169,39 @@ void fdc_write(uint16_t addr, uint8_t val, void *priv) case 2: /*DOR*/ // if (val == 0xD && (cs >> 4) == 0xFC81600 && ins > 769619936) output = 3; // printf("DOR was %02X\n",fdc.dor); - if (val&4) + if (fdc.pcjr) { - fdc.stat=0x80; - fdc.pnum=fdc.ptot=0; + if ((fdc.dor & 0x40) && !(val & 0x40)) + { + fdc.watchdog_timer = 1000 * TIMER_USEC; + fdc.watchdog_count = 1000; + picintc(1 << 6); +// pclog("watchdog set %i %i\n", fdc.watchdog_timer, TIMER_USEC); + } + if ((val & 0x80) && !(fdc.dor & 0x80)) + { + timer_process(); + disctime = 128 * (1 << TIMER_SHIFT); + timer_update_outstanding(); + discint=-1; + fdc_reset(); + } } - if ((val&4) && !(fdc.dor&4)) + else { - timer_process(); - disctime = 128 * (1 << TIMER_SHIFT); - timer_update_outstanding(); - discint=-1; - fdc_reset(); + if (val&4) + { + fdc.stat=0x80; + fdc.pnum=fdc.ptot=0; + } + if ((val&4) && !(fdc.dor&4)) + { + timer_process(); + disctime = 128 * (1 << TIMER_SHIFT); + timer_update_outstanding(); + discint=-1; + fdc_reset(); + } } fdc.dor=val; // printf("DOR now %02X\n",val); @@ -147,6 +217,12 @@ void fdc_write(uint16_t addr, uint8_t val, void *priv) } return; case 5: /*Command register*/ + if ((fdc.stat & 0xf0) == 0xb0) + { + fdc.dat = val; + fdc.stat &= ~0x80; + break; + } // pclog("Write command reg %i %i\n",fdc.pnum, fdc.ptot); if (fdc.pnum==fdc.ptot) { @@ -315,6 +391,8 @@ void fdc_write(uint16_t addr, uint8_t val, void *priv) { fdc.head = (fdc.params[0] & 4) ? 1 : 0; } + if (discint == 5 && fdc.pcjr) + fdc.stat = 0xb0; timer_update_outstanding(); // if (discint==5) fdc.pos=512; } @@ -350,6 +428,11 @@ uint8_t fdc_read(uint16_t addr, void *priv) break; case 5: /*Data*/ fdc.stat&=~0x80; + if ((fdc.stat & 0xf0) == 0xf0) + { + temp = fdc.dat; + break; + } if (paramstogo) { paramstogo--; @@ -412,13 +495,13 @@ void fdc_poll() case -3: /*End of command with interrupt*/ // if (output) printf("EOC - interrupt!\n"); //pclog("EOC\n"); - picint(0x40); + fdc_int(); case -2: /*End of command*/ fdc.stat = (fdc.stat & 0xf) | 0x80; return; case -1: /*Reset*/ //pclog("Reset\n"); - picint(0x40); + fdc_int(); fdc_reset_stat = 4; return; case 2: /*Read track*/ @@ -430,7 +513,10 @@ void fdc_poll() { fdc.dat=disc[fdc.drive][fdc.head][fdc.track[fdc.drive]][fdc.sector-1][fdc.pos]; // pclog("Read %i %i %i %i %02X\n",fdc.head,fdc.track,fdc.sector,fdc.pos,fdc.dat); - dma_channel_write(2, fdc.dat); + if (fdc.pcjr) + fdc.stat = 0xf0; + else + dma_channel_write(2, fdc.dat); timer_process(); disctime = 60 * (1 << TIMER_SHIFT); timer_update_outstanding(); @@ -440,7 +526,7 @@ void fdc_poll() disctime=0; discint=-2; // pclog("RT\n"); - picint(0x40); + fdc_int(); fdc.stat=0xD0; fdc.res[4]=(fdc.head?4:0)|fdc.drive; fdc.res[5]=fdc.res[2]=0; @@ -488,7 +574,10 @@ void fdc_poll() } if (fdc.pos<512) { - temp = dma_channel_read(2); + if (fdc.pcjr) + temp = fdc.dat; + else + temp = dma_channel_read(2); if (temp == DMA_NODATA) { discint=0xFD; @@ -502,8 +591,10 @@ void fdc_poll() fdc.dat=disc[fdc.drive][fdc.head][fdc.track[fdc.drive]][fdc.sector-1][fdc.pos]=temp; // printf("Write data %i %i %02X %i:%i:%i:%i\n",fdc.sector-1,fdc.pos,fdc.dat,fdc.head,fdc.track[fdc.drive],fdc.sector-1,fdc.pos); timer_process(); - disctime = 60 * (1 << TIMER_SHIFT); + disctime = 600 * (1 << TIMER_SHIFT); timer_update_outstanding(); + if (fdc.pcjr && fdc.pos != 512) + fdc.stat = 0xb0; } } else @@ -511,7 +602,7 @@ void fdc_poll() disctime=0; discint=-2; // pclog("WD\n"); - picint(0x40); + fdc_int(); fdc.stat=0xD0; fdc.res[4]=(fdc.head?4:0)|fdc.drive; fdc.res[5]=0; @@ -528,6 +619,8 @@ void fdc_poll() { fdc.pos=0; fdc.sector++; + if (fdc.pcjr) + fdc.stat = 0xb0; } return; case 6: /*Read data*/ @@ -537,12 +630,19 @@ void fdc_poll() } if (fdc.pos<512) { - fdc.dat=disc[fdc.drive][fdc.head][fdc.track[fdc.drive]][fdc.sector-1][fdc.pos]; + fdc.dat = disc[fdc.drive][fdc.head][fdc.track[fdc.drive]][fdc.sector - 1][fdc.pos]; // printf("Read disc %i %i %i %i %02X\n",fdc.head,fdc.track,fdc.sector,fdc.pos,fdc.dat); - if (dma_channel_write(2, fdc.dat) & DMA_OVER) - fdc.abort = 1; + if (fdc.pcjr) + { + fdc.stat = 0xf0; + } + else + { + if (dma_channel_write(2, fdc.dat) & DMA_OVER) + fdc.abort = 1; + } timer_process(); - disctime = 60 * (1 << TIMER_SHIFT); + disctime = 256 * (1 << TIMER_SHIFT); timer_update_outstanding(); } else @@ -551,7 +651,7 @@ void fdc_poll() fdc.abort = 0; disctime=0; discint=-2; - picint(0x40); + fdc_int(); // pclog("RD\n"); fdc.stat=0xD0; fdc.res[4]=(fdc.head?4:0)|fdc.drive; @@ -640,7 +740,7 @@ void fdc_poll() case 10: /*Read sector ID*/ disctime=0; discint=-2; - picint(0x40); + fdc_int(); fdc.stat=0xD0; fdc.res[4]=(fdc.head?4:0)|fdc.drive; fdc.res[5]=0; @@ -693,14 +793,14 @@ void fdc_poll() fdc.perp = fdc.params[0]; fdc.stat = 0x80; disctime = 0; -// picint(0x40); +// fdc_int(); return; case 0x13: /*Configure*/ fdc.config = fdc.params[1]; fdc.pretrk = fdc.params[2]; fdc.stat = 0x80; disctime = 0; -// picint(0x40); +// fdc_int(); return; case 0x14: /*Unlock*/ fdc.lock = 0; @@ -723,7 +823,7 @@ void fdc_poll() case 0xfc: /*Invalid*/ fdc.dat = fdc.st0 = 0x80; // pclog("Inv!\n"); - //picint(0x40); + //fdc_int(); fdc.stat = (fdc.stat & 0xf) | 0xd0; // fdc.stat|=0xC0; fdc.res[10] = fdc.st0; @@ -742,7 +842,7 @@ void fdc_poll() pclog("DMA Aborted\n"); disctime=0; discint=-2; - picint(0x40); + fdc_int(); fdc.stat=0xD0; fdc.res[4]=(fdc.head?4:0)|fdc.drive; fdc.res[5]=0; @@ -759,7 +859,7 @@ void fdc_poll() disctime = 0; /* disctime=0; discint=-2; - picint(0x40); + fdc_int(); fdc.stat=0xD0; fdc.res[4]=0xC8|(fdc.head?4:0)|fdc.drive; fdc.res[5]=0; @@ -774,7 +874,7 @@ void fdc_poll() pclog("Wrong rate\n"); disctime=0; discint=-2; - picint(0x40); + fdc_int(); fdc.stat=0xD0; fdc.res[4]=0x40|(fdc.head?4:0)|fdc.drive; fdc.res[5]=5; @@ -799,7 +899,15 @@ void fdc_init() void fdc_add() { io_sethandler(0x03f0, 0x0006, fdc_read, NULL, NULL, fdc_write, NULL, NULL, NULL); - io_sethandler(0x03f7, 0x0001, fdc_read, NULL, NULL, fdc_write, NULL, NULL, NULL); + io_sethandler(0x03f7, 0x0001, fdc_read, NULL, NULL, fdc_write, NULL, NULL, NULL); + fdc.pcjr = 0; +} + +void fdc_add_pcjr() +{ + io_sethandler(0x00f0, 0x0006, fdc_read, NULL, NULL, fdc_write, NULL, NULL, NULL); + timer_add(fdc_watchdog_poll, &fdc.watchdog_timer, &fdc.watchdog_timer, &fdc); + fdc.pcjr = 1; } void fdc_remove() diff --git a/src/fdc.h b/src/fdc.h index 4458155..1f6fb28 100644 --- a/src/fdc.h +++ b/src/fdc.h @@ -1,5 +1,6 @@ void fdc_init(); void fdc_add(); +void fdc_add_pcjr(); void fdc_remove(); void fdc_reset(); void fdc_poll(); diff --git a/src/ibm.h b/src/ibm.h index 93e4c57..e15dc5b 100644 --- a/src/ibm.h +++ b/src/ibm.h @@ -199,6 +199,13 @@ typedef struct PIT int delay[3]; int rereadlatch[3]; int gate[3]; + int out[3]; + int running[3]; + int enabled[3]; + int newcount[3]; + int count[3]; + int using_timer[3]; + int initial[3]; } PIT; PIT pit; @@ -250,25 +257,6 @@ extern int pic_intpending; int intcount; -/*FDC*/ -typedef struct FDC -{ - uint8_t dor,stat,command,dat,st0; - int head,track[256],sector,drive,lastdrive; - int pos; - uint8_t params[256]; - uint8_t res[256]; - int pnum,ptot; - int rate; - uint8_t specify[256]; - int eot[256]; - int lock; - int perp; - uint8_t config, pretrk; - int abort; -} FDC; - -FDC fdc; int disctime; char discfns[2][256]; int driveempty[2]; @@ -290,6 +278,7 @@ int driveempty[2]; #define ET4000W32 (gfxcard==GFX_ET4000W32 && VGA) #define AT (romset>=ROM_IBMAT) #define PCI (romset >= ROM_PCI486) +#define PCJR (romset == ROM_IBMPCJR) #define AMIBIOS (romset==ROM_AMI386 || romset==ROM_AMI486 || romset == ROM_WIN486) @@ -299,6 +288,7 @@ enum { ROM_IBMPC = 0, /*301 keyboard error, 131 cassette (!!!) error*/ ROM_IBMXT, /*301 keyboard error*/ + ROM_IBMPCJR, ROM_GENXT, /*'Generic XT BIOS'*/ ROM_DTKXT, ROM_EUROPC, diff --git a/src/keyboard_pcjr.c b/src/keyboard_pcjr.c new file mode 100644 index 0000000..d6afd76 --- /dev/null +++ b/src/keyboard_pcjr.c @@ -0,0 +1,202 @@ +#include "ibm.h" +#include "device.h" +#include "io.h" +#include "mem.h" +#include "pic.h" +#include "sound.h" +#include "sound_sn76489.h" +#include "sound_speaker.h" +#include "timer.h" + +#include "keyboard.h" +#include "keyboard_pcjr.h" + +#define STAT_PARITY 0x80 +#define STAT_RTIMEOUT 0x40 +#define STAT_TTIMEOUT 0x20 +#define STAT_LOCK 0x10 +#define STAT_CD 0x08 +#define STAT_SYSFLAG 0x04 +#define STAT_IFULL 0x02 +#define STAT_OFULL 0x01 + +struct +{ + int latched; + int data; + int nmi_enabled; + + int serial_data[44]; + int serial_pos; + + uint8_t pa; + uint8_t pb; +} keyboard_pcjr; + +static uint8_t key_queue[16]; +static int key_queue_start = 0, key_queue_end = 0; + +void keyboard_pcjr_poll() +{ + keybsenddelay += (220 * TIMER_USEC); + + + if (key_queue_start != key_queue_end && !keyboard_pcjr.serial_pos && !keyboard_pcjr.latched) + { + int c; + int p = 0; + uint8_t key = key_queue[key_queue_start]; + +// pclog("Reading %02X from the key queue at %i\n", key, key_queue_start); + key_queue_start = (key_queue_start + 1) & 0xf; + + keyboard_pcjr.latched = 1; + + keyboard_pcjr.serial_data[0] = 1; /*Start bit*/ + keyboard_pcjr.serial_data[1] = 0; + + for (c = 0; c < 8; c++) + { + if (key & (1 << c)) + { + keyboard_pcjr.serial_data[(c + 1) * 2] = 1; + keyboard_pcjr.serial_data[(c + 1) * 2 + 1] = 0; + p++; + } + else + { + keyboard_pcjr.serial_data[(c + 1) * 2] = 0; + keyboard_pcjr.serial_data[(c + 1) * 2 + 1] = 1; + } + } + + if (p & 1) /*Parity*/ + { + keyboard_pcjr.serial_data[9 * 2] = 1; + keyboard_pcjr.serial_data[9 * 2 + 1] = 0; + } + else + { + keyboard_pcjr.serial_data[9 * 2] = 0; + keyboard_pcjr.serial_data[9 * 2 + 1] = 1; + } + + for (c = 0; c < 11; c++) /*11 stop bits*/ + { + keyboard_pcjr.serial_data[(c + 10) * 2] = 0; + keyboard_pcjr.serial_data[(c + 10) * 2 + 1] = 0; + } + + keyboard_pcjr.serial_pos++; + } + + if (keyboard_pcjr.serial_pos) + { + keyboard_pcjr.data = keyboard_pcjr.serial_data[keyboard_pcjr.serial_pos - 1]; + nmi = keyboard_pcjr.data; + keyboard_pcjr.serial_pos++; + if (keyboard_pcjr.serial_pos == 42+1) + keyboard_pcjr.serial_pos = 0; +// pclog("Keyboard poll %i %i\n", keyboard_pcjr.data, keyboard_pcjr.serial_pos); + } +} + +void keyboard_pcjr_adddata(uint8_t val) +{ + key_queue[key_queue_end] = val; +// pclog("keyboard_pcjr : %02X added to key queue at %i\n", val, key_queue_end); + key_queue_end = (key_queue_end + 1) & 0xf; + return; +} + +void keyboard_pcjr_write(uint16_t port, uint8_t val, void *priv) +{ +// pclog("keyboard_pcjr : write %04X %02X %02X\n", port, val, keyboard_pcjr.pb); +/* if (ram[8] == 0xc3) + { + output = 3; + }*/ + switch (port) + { + case 0x60: + keyboard_pcjr.pa = val; + break; + + case 0x61: + keyboard_pcjr.pb = val; + gated = ((val & 3) == 3); + if (gated) + wasgated = 1; + pit_set_gate(2, val & 1); + sn76489_mute = speaker_mute = 1; + switch (val & 0x60) + { + case 0x00: + speaker_mute = 0; + break; + case 0x60: + sn76489_mute = 0; + break; + } + break; + + case 0xa0: + keyboard_pcjr.nmi_enabled = val & 0x80; + pit_set_using_timer(1, !(val & 0x20)); + break; + } +} + +uint8_t keyboard_pcjr_read(uint16_t port, void *priv) +{ + uint8_t temp; +// pclog("keyboard_pcjr : read %04X ", port); + switch (port) + { + case 0x60: + temp = keyboard_pcjr.pa; + break; + + case 0x61: + temp = keyboard_pcjr.pb; + break; + + case 0x62: + temp = (keyboard_pcjr.latched ? 1 : 0); + temp |= 0x02; /*Modem card not installed*/ + temp |= (ppispeakon ? 0x10 : 0); + temp |= (ppispeakon ? 0x20 : 0); + temp |= (keyboard_pcjr.data ? 0x40: 0); +// temp |= 0x04; + if (keyboard_pcjr.data) + temp |= 0x40; + break; + + case 0xa0: + keyboard_pcjr.latched = 0; + break; + + default: + pclog("\nBad XT keyboard read %04X\n", port); + //dumpregs(); + //exit(-1); + } +// pclog("%02X\n", temp); + return temp; +} + +void keyboard_pcjr_reset() +{ +} + +void keyboard_pcjr_init() +{ + //return; + io_sethandler(0x0060, 0x0004, keyboard_pcjr_read, NULL, NULL, keyboard_pcjr_write, NULL, NULL, NULL); + io_sethandler(0x00a0, 0x0008, keyboard_pcjr_read, NULL, NULL, keyboard_pcjr_write, NULL, NULL, NULL); + keyboard_pcjr_reset(); + keyboard_send = keyboard_pcjr_adddata; + keyboard_poll = keyboard_pcjr_poll; + + timer_add(keyboard_pcjr_poll, &keybsenddelay, TIMER_ALWAYS_ENABLED, NULL); +} diff --git a/src/keyboard_pcjr.h b/src/keyboard_pcjr.h new file mode 100644 index 0000000..4652092 --- /dev/null +++ b/src/keyboard_pcjr.h @@ -0,0 +1,3 @@ +void keyboard_pcjr_init(); +void keyboard_pcjr_reset(); +void keyboard_pcjr_poll(); diff --git a/src/mem.c b/src/mem.c index 68ac278..15fe5c6 100644 --- a/src/mem.c +++ b/src/mem.c @@ -344,6 +344,15 @@ int loadbios() return 1; } break; + + case ROM_IBMPCJR: + f = romfopen("roms/ibmpcjr/bios.rom","rb"); + if (!f) break; + fread(rom, 0x10000, 1, f); + fclose(f); + memset(vrom,0x63,0x8000); + return 1; + case ROM_GENXT: f=romfopen("roms/genxt/pcxt.rom","rb"); if (!f) break; diff --git a/src/model.c b/src/model.c index c96108c..eb20bfb 100644 --- a/src/model.c +++ b/src/model.c @@ -16,6 +16,7 @@ #include "keyboard_amstrad.h" #include "keyboard_at.h" #include "keyboard_olim24.h" +#include "keyboard_pcjr.h" #include "keyboard_xt.h" #include "lpt.h" #include "mouse_ps2.h" @@ -36,6 +37,7 @@ #include "xtide.h" void xt_init(); +void pcjr_init(); void tandy1k_init(); void ams_init(); void europc_init(); @@ -56,6 +58,7 @@ MODEL models[] = { {"IBM PC", ROM_IBMPC, { "", cpus_8088, "", NULL, "", NULL}, 0, xt_init}, {"IBM XT", ROM_IBMXT, { "", cpus_8088, "", NULL, "", NULL}, 0, xt_init}, + {"IBM PCjr", ROM_IBMPCJR, { "", cpus_pcjr, "", NULL, "", NULL}, 1, pcjr_init}, {"Generic XT clone", ROM_GENXT, { "", cpus_8088, "", NULL, "", NULL}, 0, xt_init}, {"DTK XT clone", ROM_DTKXT, { "", cpus_8088, "", NULL, "", NULL}, 0, xt_init}, {"Tandy 1000", ROM_TANDY, { "", cpus_8088, "", NULL, "", NULL}, 1, tandy1k_init}, @@ -112,18 +115,30 @@ void common_init() lpt_init(); pic_init(); pit_init(); - serial1_init(0x3f8); - serial2_init(0x2f8); + serial1_init(0x3f8, 4); + serial2_init(0x2f8, 3); } void xt_init() { common_init(); + pit_set_out_func(1, pit_refresh_timer_xt); keyboard_xt_init(); mouse_serial_init(); xtide_init(); } +void pcjr_init() +{ + fdc_add_pcjr(); + pic_init(); + pit_init(); + pit_set_out_func(0, pit_irq0_timer_pcjr); + serial1_init(0x2f8, 3); + keyboard_pcjr_init(); + device_add(&sn76489_device); +} + void tandy1k_init() { common_init(); @@ -163,6 +178,7 @@ void olim24_init() void at_init() { common_init(); + pit_set_out_func(1, pit_refresh_timer_at); dma16_init(); ide_init(); keyboard_at_init(); diff --git a/src/mouse_serial.c b/src/mouse_serial.c index 4f75a83..36221c1 100644 --- a/src/mouse_serial.c +++ b/src/mouse_serial.c @@ -10,7 +10,8 @@ void mouse_serial_poll(int x, int y, int b) { uint8_t mousedat[3]; - if (!(serial.ier&1)) return; + if (!(serial1.ier & 1)) + return; if (!x && !y && b==oldb) return; oldb=b; @@ -28,42 +29,44 @@ void mouse_serial_poll(int x, int y, int b) mousedat[1]=x&0x3F; mousedat[2]=y&0x3F; - if (!(serial.mctrl&0x10)) + if (!(serial1.mctrl&0x10)) { - serial_write_fifo(mousedat[0]); - serial_write_fifo(mousedat[1]); - serial_write_fifo(mousedat[2]); + pclog("Serial data %02X %02X %02X\n", mousedat[0], mousedat[1], mousedat[2]); + serial_write_fifo(&serial1, mousedat[0]); + serial_write_fifo(&serial1, mousedat[1]); + serial_write_fifo(&serial1, mousedat[2]); } } -void mouse_serial_rcr() +void mouse_serial_rcr(void *p) { mousepos=-1; mousedelay=5000 * (1 << TIMER_SHIFT); } -void mousecallback() +void mousecallback(void *p) { + SERIAL *serial = (SERIAL *)p; mousedelay = 0; if (mousepos == -1) { mousepos = 0; - serial_fifo_read = serial_fifo_write = 0; - serial.linestat &= ~1; - serial_write_fifo('M'); +/* serial_fifo_read = serial_fifo_write = 0; + serial.lsr &= ~1;*/ + serial_write_fifo(serial, 'M'); } - else if (serial_fifo_read != serial_fifo_write) +/* else if (serial_fifo_read != serial_fifo_write) { serial.iir=4; - serial.linestat|=1; + serial.lsr|=1; if (serial.mctrl&8) picint(0x10); - } + }*/ } void mouse_serial_init() { mouse_poll = mouse_serial_poll; - serial_rcr = mouse_serial_rcr; - timer_add(mousecallback, &mousedelay, &mousedelay, NULL); + serial1.rcr_callback = mouse_serial_rcr; + timer_add(mousecallback, &mousedelay, &mousedelay, &serial1); } diff --git a/src/pc.c b/src/pc.c index 949362d..4ed0f4d 100644 --- a/src/pc.c +++ b/src/pc.c @@ -46,7 +46,6 @@ extern int readlnum,writelnum; void fullspeed(); int framecount,fps; -int pitsec; int intcount; int wakeups,wokeups; int output; @@ -343,7 +342,6 @@ void runpc() egareads=egawrites=0; cycles_lost = 0; mmuflush=0; - pitsec=0; intcount=0; wakeups=wokeups=0; intcount=pitcount=0; diff --git a/src/pit.c b/src/pit.c index 446c6d2..293a746 100644 --- a/src/pit.c +++ b/src/pit.c @@ -19,7 +19,6 @@ //Tyrian writes 4300 or 17512 int displine; -int pitsec=0; double PITCONST; float cpuclock; float isa_timing, bus_timing; @@ -30,7 +29,7 @@ void setpitclock(float clock) // printf("PIT clock %f\n",clock); cpuclock=clock; PITCONST=clock/1193182.0; - CGACONST=(clock/(19687500.0/11.0)); + CGACONST=(clock/(19687503.0/11.0)); MDACONST=(clock/2032125.0); VGACONST1=(clock/25175000.0); VGACONST2=(clock/28322000.0); @@ -57,6 +56,9 @@ void pit_reset() pit.ctrls[0]=pit.ctrls[1]=pit.ctrls[2]=0; pit.thit[0]=1; spkstat=0; + pit.gate[0] = pit.gate[1] = 1; + pit.gate[2] = 0; + pit.using_timer[0] = pit.using_timer[1] = pit.using_timer[2] = 1; } void clearpit() @@ -69,12 +71,209 @@ float pit_timer0_freq() // pclog("PIT timer 0 freq %04X %f %f\n",pit.l[0],(float)pit.l[0],1193182.0f/(float)pit.l[0]); return 1193182.0f/(float)pit.l[0]; } + +static void (*pit_set_out_funcs[3])(int new_out, int old_out); + +static void pit_set_out(int t, int out) +{ + pit_set_out_funcs[t](out, pit.out[t]); + pit.out[t] = out; +} + +static void pit_load(int t) +{ + int l = pit.l[t] ? pit.l[t] : 0x10000; + pit.newcount[t] = 0; + switch (pit.m[t]) + { + case 0: /*Interrupt on terminal count*/ + pit.count[t] = l; + pit.c[t] = l * PITCONST; + pit_set_out(t, 0); + pit.thit[t] = 0; + pit.enabled[t] = pit.gate[t]; + break; + case 1: /*Hardware retriggerable one-shot*/ + pit.enabled[t] = 1; + break; + case 2: /*Rate generator*/ + if (pit.initial[t]) + { + pit.count[t] = l - 1; + pit.c[t] = (l - 1) * PITCONST; + pit_set_out(t, 1); + pit.thit[t] = 0; + } + pit.enabled[t] = pit.gate[t]; + break; + case 3: /*Square wave mode*/ + if (pit.initial[t]) + { + pit.count[t] = l; + pit.c[t] = ((l + 1) >> 1) * PITCONST; + pit_set_out(t, 1); + pit.thit[t] = 0; + } + pit.enabled[t] = pit.gate[t]; + break; + case 4: /*Software triggered stobe*/ + if (!pit.thit[t] && !pit.initial[t]) + pit.newcount[t] = 1; + else + { + pit.count[t] = l; + pit.c[t] = l * PITCONST; + pit_set_out(t, 0); + pit.thit[t] = 0; + } + pit.enabled[t] = pit.gate[t]; + break; + case 5: /*Hardware triggered stobe*/ + pit.enabled[t] = 1; + break; + } + pit.initial[t] = 0; + pit.running[t] = pit.enabled[t] && pit.using_timer[t]; +// pclog("pit_load: t=%i running=%i thit=%i enabled=%i m=%i l=%x c=%g gate=%i\n", t, pit.running[t], pit.thit[t], pit.enabled[t], pit.m[t], pit.l[t], pit.c[t], pit.gate[t]); +} + +void pit_set_gate(int t, int gate) +{ + int l = pit.l[t] ? pit.l[t] : 0x10000; + switch (pit.m[t]) + { + case 0: /*Interrupt on terminal count*/ + case 4: /*Software triggered stobe*/ + pit.enabled[t] = gate; + break; + case 1: /*Hardware retriggerable one-shot*/ + case 5: /*Hardware triggered stobe*/ + if (gate && !pit.gate[t]) + { + pit.count[t] = l; + pit.c[t] = l * PITCONST; + pit_set_out(t, 0); + pit.thit[t] = 0; + pit.enabled[t] = 1; + } + break; + case 2: /*Rate generator*/ + if (gate && !pit.gate[t]) + { + pit.count[t] = l - 1; + pit.c[t] = (l - 1) * PITCONST; + pit_set_out(t, 1); + pit.thit[t] = 0; + } + pit.enabled[t] = gate; + break; + case 3: /*Square wave mode*/ + if (gate && !pit.gate[t]) + { + pit.count[t] = l; + pit.c[t] = ((l + 1) >> 1) * PITCONST; + pit_set_out(t, 1); + pit.thit[t] = 0; + } + pit.enabled[t] = gate; + break; + } + pit.gate[t] = gate; + pit.running[t] = pit.enabled[t] && pit.using_timer[t]; +// pclog("pit_set_gate: t=%i gate=%i\n", t, gate); +} + +static void pit_over(int t) +{ + int l = pit.l[t] ? pit.l[t] : 0x10000; + switch (pit.m[t]) + { + case 0: /*Interrupt on terminal count*/ + case 1: /*Hardware retriggerable one-shot*/ + if (!pit.thit[t]) + pit_set_out(t, 1); + pit.thit[t] = 1; + pit.count[t] += 0xffff; + pit.c[t] += 0xffff * PITCONST; + break; + case 2: /*Rate generator*/ + pit.count[t] += l; + pit.c[t] += l * PITCONST; + pit_set_out(t, 0); + pit_set_out(t, 1); + break; + case 3: /*Square wave mode*/ + if (pit.out[t]) + { + pit_set_out(t, 0); + pit.count[t] += (l >> 1); + pit.c[t] += (l >> 1) * PITCONST; + } + else + { + pit_set_out(t, 1); + pit.count[t] += ((l + 1) >> 1); + pit.c[t] = ((l + 1) >> 1) * PITCONST; + } + break; + case 4: /*Software triggered strove*/ + if (!pit.thit[t]) + { + pit_set_out(t, 0); + pit_set_out(t, 1); + } + if (pit.newcount[t]) + { + pit.newcount[t] = 0; + pit.count[t] += l; + pit.c[t] += l * PITCONST; + } + else + { + pit.thit[t] = 1; + pit.count[t] += 0xffff; + pit.c[t] += 0xffff * PITCONST; + } + break; + case 5: /*Hardware triggered strove*/ + if (!pit.thit[t]) + { + pit_set_out(t, 0); + pit_set_out(t, 1); + } + pit.thit[t] = 1; + break; + } + pit.running[t] = pit.enabled[t] && pit.using_timer[t]; +} + +static int pit_read_timer(int t) +{ +// pclog("pit_read_timer: t=%i using_timer=%i m=%i\n", t, pit.using_timer[t], pit.m[t]); + if (pit.using_timer[t]) + { + int read = pit.c[t] / PITCONST; + if (pit.m[t] == 2) + read++; + if (read < 0) + read = 0; + if (read > 0x10000) + read = 0x10000; + if (pit.m[t] == 3) + read <<= 1; + return read; + } + if (pit.m[t] == 2) + return pit.count[t] + 1; + return pit.count[t]; +} + extern int ins; void pit_write(uint16_t addr, uint8_t val, void *priv) { int t; cycles -= (int)PITCONST; -// printf("Write PIT %04X %02X %04X:%08X %i %i\n",addr,val,CS,pc,ins); +// if (val != 0x40) pclog("Write PIT %04X %02X %04X:%08X %i %i\n",addr,val,CS,pc,ins, pit.gate[0]); switch (addr&3) { case 3: /*CTRL*/ @@ -82,12 +281,16 @@ void pit_write(uint16_t addr, uint8_t val, void *priv) { if (!(val&0x20)) { - if (val&2) pit.rl[0]=pit.c[0]/PITCONST; - if (val&4) pit.rl[1]=pit.c[1]/PITCONST; - if (val&8) pit.rl[2]=pit.c[2]/PITCONST; + if (val & 2) + pit.rl[0] = pit.using_timer[0] ? (pit.c[0] / PITCONST) : pit.count[0]; + if (val & 4) + pit.rl[1] = pit.using_timer[1] ? (pit.c[1] / PITCONST) : pit.count[1]; + if (val & 8) + pit.rl[2] = pit.using_timer[2] ? (pit.c[2] / PITCONST) : pit.count[2]; } return; } + t = val >> 6; pit.ctrls[val>>6]=pit.ctrl=val; if ((val>>7)==3) { @@ -99,26 +302,26 @@ void pit_write(uint16_t addr, uint8_t val, void *priv) // printf("CTRL write %02X\n",val); if (!(pit.ctrl&0x30)) { - pit.rl[val>>6]=pit.c[val>>6]/PITCONST; - if (pit.c[val>>6]<0) pit.rl[val>>6]=0; + pit.rl[t] = pit_read_timer(t); // pclog("Timer latch %f %04X %04X\n",pit.c[0],pit.rl[0],pit.l[0]); - pit.ctrl|=0x30; - pit.rereadlatch[val>>6]=0; - pit.rm[val>>6]=3; + pit.ctrl |= 0x30; + pit.rereadlatch[t] = 0; + pit.rm[t] = 3; } else { - pit.rm[val>>6]=pit.wm[val>>6]=(pit.ctrl>>4)&3; - pit.m[val>>6]=(val>>1)&7; - if (pit.m[val>>6]>5) - pit.m[val>>6]&=3; - if (!(pit.rm[val>>6])) - { - pit.rm[val>>6]=3; - pit.rl[val>>6]=pit.c[val>>6]/PITCONST; - } - pit.rereadlatch[val>>6]=1; - if ((val>>6)==2) ppispeakon=speakon=(pit.m[2]==0)?0:1; + pit.rm[val>>6]=pit.wm[val>>6]=(pit.ctrl>>4)&3; + pit.m[val>>6]=(val>>1)&7; + if (pit.m[val>>6]>5) + pit.m[val>>6]&=3; + if (!(pit.rm[val>>6])) + { + pit.rm[val>>6]=3; + pit.rl[t] = pit_read_timer(t); + } + pit.rereadlatch[val>>6]=1; + if ((val>>6)==2) ppispeakon=speakon=(pit.m[2]==0)?0:1; + pit.initial[t] = 1; // pclog("ppispeakon %i\n",ppispeakon); } pit.wp=0; @@ -132,196 +335,188 @@ void pit_write(uint16_t addr, uint8_t val, void *priv) { case 1: pit.l[t]=val; - pit.thit[t]=0; - pit.c[t]=pit.l[t]*PITCONST; - if (!t) - picintc(1); +// pit.thit[t]=0; + pit_load(t); +// pit.c[t]=pit.l[t]*PITCONST; +// if (!t) +// picintc(1); break; case 2: pit.l[t]=(val<<8); - pit.thit[t]=0; - pit.c[t]=pit.l[t]*PITCONST; - if (!t) - picintc(1); +// pit.thit[t]=0; + pit_load(t); +// pit.c[t]=pit.l[t]*PITCONST; +// if (!t) +// picintc(1); break; case 0: pit.l[t]&=0xFF; pit.l[t]|=(val<<8); - pit.c[t]=pit.l[t]*PITCONST; + pit_load(t); +// pit.c[t]=pit.l[t]*PITCONST; // pclog("%04X %f\n",pit.l[t],pit.c[t]); - pit.thit[t]=0; +// pit.thit[t]=0; pit.wm[t]=3; - if (!t) - picintc(1); +// if (!t) +// picintc(1); break; case 3: pit.l[t]&=0xFF00; pit.l[t]|=val; pit.wm[t]=0; break; -/* - if (pit.wp) - { - pit.l[t]&=0xFF; - pit.l[t]|=(val<<8); - pit.c[t]=pit.l[t]*PITCONST; - pit.thit[t]=0; - } - else - { - pit.l[t]&=0xFF00; - pit.l[t]|=val; - } - pit.rl[t]=pit.l[t]; - pit.wp^=1; - pit.rm[t]=3; - pit.rereadlatch[t]=1; - break;*/ } speakval=(((float)pit.l[2]/(float)pit.l[0])*0x4000)-0x2000; // printf("Speakval now %i\n",speakval); // if (speakval>0x2000) // printf("Speaker overflow - %i %i %04X %04X\n",pit.l[0],pit.l[2],pit.l[0],pit.l[2]); if (speakval>0x2000) speakval=0x2000; - if (!pit.l[t]) +/* if (!pit.l[t]) { pit.l[t]|=0x10000; pit.c[t]=pit.l[t]*PITCONST; - } + }*/ break; } } uint8_t pit_read(uint16_t addr, void *priv) { + int t; uint8_t temp; cycles -= (int)PITCONST; // printf("Read PIT %04X ",addr); switch (addr&3) { case 0: case 1: case 2: /*Timers*/ - if (pit.rereadlatch[addr&3])// || !(pit.ctrls[addr&3]&0x30)) + t = addr & 3; + if (pit.rereadlatch[addr & 3]) { - pit.rereadlatch[addr&3]=0; - pit.rl[addr&3]=pit.c[addr&3]/PITCONST; - if ((pit.c[addr&3]/PITCONST)>65536) pit.rl[addr&3]=0xFFFF; + pit.rereadlatch[addr & 3] = 0; + pit.rl[t] = pit_read_timer(t); } - switch (pit.rm[addr&3]) + switch (pit.rm[addr & 3]) { case 0: - temp=pit.rl[addr&3]>>8; - pit.rm[addr&3]=3; - pit.rereadlatch[addr&3]=1; + temp = pit.rl[addr & 3] >> 8; + pit.rm[addr & 3] = 3; + pit.rereadlatch[addr & 3] = 1; break; case 1: - temp=(pit.rl[addr&3])&0xFF; - pit.rereadlatch[addr&3]=1; + temp = (pit.rl[addr & 3]) & 0xFF; + pit.rereadlatch[addr & 3] = 1; break; case 2: - temp=(pit.rl[addr&3])>>8; - pit.rereadlatch[addr&3]=1; + temp = (pit.rl[addr & 3]) >> 8; + pit.rereadlatch[addr & 3] = 1; break; case 3: - temp=(pit.rl[addr&3])&0xFF; - if (pit.m[addr&3]&0x80) pit.m[addr&3]&=7; - else pit.rm[addr&3]=0; + temp = (pit.rl[addr & 3]) & 0xFF; + if (pit.m[addr & 3] & 0x80) + pit.m[addr & 3] &= 7; + else + pit.rm[addr & 3] = 0; break; } break; case 3: /*Control*/ - temp=pit.ctrl; + temp = pit.ctrl; + break; } +// pclog("%02X\n", temp); // printf("%02X %i %i %04X:%04X\n",temp,pit.rm[addr&3],pit.wp,cs>>4,pc); return temp; } void pit_poll() { - pitsec++; // printf("Poll pit %f %f %f\n",pit.c[0],pit.c[1],pit.c[2]); - if (pit.c[0]<1) - { - if (pit.m[0]==0 || pit.m[0]==4) - { -// pit.c[0]&=0xFFFF; - pit.c[0]+=(0x10000*PITCONST); - } - else if (pit.m[0]==3 || pit.m[0]==2) - { - if (pit.l[0]) pit.c[0]+=((float)(pit.l[0]*PITCONST)); - else pit.c[0]+=((float)(0x10000*PITCONST)); - } -// pit.c[0]+=(pit.l[0]*PITCONST); -// if (output) printf("PIT over! %f %i\n",pit.c[0],pit.m[0]); - if (!pit.thit[0])// && (pit.l[0]>0x14)) - { -// printf("PIT int!\n"); -/// printf("%05X %05X %02X\n",pit.c[0],pit.l[0],pit.ctrls[0]); - picint(1); - } - if (!pit.m[0] || pit.m[0]==4) pit.thit[0]=1; -// if ((pit.ctrls[0]&0xE)==2) pit.thit[0]=1; - pitcount++; - } - if (pit.c[1]<1) - { - // if (output) printf("PIT1 over %02X\n",pit.m[1]); - if (pit.m[1]==0 || pit.m[1]==4) - { - pit.c[1]=0xFFFFFF*PITCONST; - } - else - { - pit.c[1]+=(pit.l[1]*PITCONST); - } -// if (output) pclog("%f %04X %02X\n",pit.c[1],pit.l[1],pit.ctrls[1]); -// printf("DMA0!\n"); - dma_channel_read(0); - if (AT) - ppi.pb ^= 0x10; - } - if (pit.c[2]<1) - { -// printf("PIT 2 over %i\n",pit.m[2]); - if (!pit.m[2] || pit.m[2]==4) - { - pit.c[2]+=(0x10000*PITCONST); - speakon^=1; - ppispeakon^=1; - } - else - { - pit.c[2]+=((pit.l[2]*PITCONST)/2); - if (pit.l[2]>0x30) /*Some games use very high frequencies as 'speaker off'. This stops them from generating noise*/ - speakon^=1; - ppispeakon^=1; -// printf("Speakon %i %04X %i\n",speakon,pit.l[2],pit.c[2]); - } -// if (pit.ctrls[2]&0xE) pit.c[2]+=(pit.l[2]*PITCONST); -// spkstat^=0x20; - } + if (pit.c[0] < 1 && pit.running[0]) + pit_over(0); + if (pit.c[1] < 1 && pit.running[1]) + pit_over(1); + if (pit.c[2] < 1 && pit.running[2]) + pit_over(2); } -void pit_set_gate(int channel, int gate) +void pit_clock(int t) { - if (gate && !pit.gate[channel]) - { - switch (pit.m[channel]) - { - case 1: /*Hardware retriggerable one-shot*/ - case 2: /*Rate generator*/ - case 3: /*Square wave mode*/ - case 5: /*Hardware triggered strobe (retriggerable)*/ - pit.c[channel] = pit.l[2] * PITCONST; - break; - } - } - pit.gate[channel] = gate; + if (pit.thit[t] || !pit.enabled[t]) + return; + + if (pit.using_timer[t]) + return; + + pit.count[t] -= (pit.m[t] == 3) ? 2 : 1; + if (!pit.count[t]) + pit_over(t); } +void pit_set_using_timer(int t, int using_timer) +{ +// pclog("pit_set_using_timer: t=%i using_timer=%i\n", t, using_timer); + if (pit.using_timer[t] && !using_timer) + pit.count[t] = pit_read_timer(t); + if (!pit.using_timer[t] && using_timer) + pit.c[t] = pit.count[t] * PITCONST; + pit.using_timer[t] = using_timer; + pit.running[t] = pit.enabled[t] && pit.using_timer[t]; +} + +void pit_set_out_func(int t, void (*func)(int new_out, int old_out)) +{ + pit_set_out_funcs[t] = func; +} + +void pit_null_timer(int new_out, int old_out) +{ +} + +void pit_irq0_timer(int new_out, int old_out) +{ + if (new_out && !old_out) + picint(1); + if (!new_out) + picintc(1); +} + +void pit_irq0_timer_pcjr(int new_out, int old_out) +{ + if (new_out && !old_out) + { + picint(1); + pit_clock(1); + } + if (!new_out) + picintc(1); +} + +void pit_refresh_timer_xt(int new_out, int old_out) +{ + if (new_out && !old_out) + dma_channel_read(0); +} + +void pit_refresh_timer_at(int new_out, int old_out) +{ + if (new_out && !old_out) + ppi.pb ^= 0x10; +} + +void pit_speaker_timer(int new_out, int old_out) +{ + speakon = ppispeakon = new_out; +} + + void pit_init() { io_sethandler(0x0040, 0x0004, pit_read, NULL, NULL, pit_write, NULL, NULL, NULL); pit.gate[0] = pit.gate[1] = 1; pit.gate[2] = 0; + pit.using_timer[0] = pit.using_timer[1] = pit.using_timer[2] = 1; + + pit_set_out_func(0, pit_irq0_timer); + pit_set_out_func(1, pit_null_timer); + pit_set_out_func(2, pit_speaker_timer); } diff --git a/src/pit.h b/src/pit.h index 79a0790..bbb3f5b 100644 --- a/src/pit.h +++ b/src/pit.h @@ -2,3 +2,14 @@ extern double PITCONST; void pit_init(); void pit_reset(); void pit_set_gate(int channel, int gate); +void pit_set_using_timer(int t, int using_timer); +void pit_set_out_func(int t, void (*func)(int new_out, int old_out)); +void pit_clock(int t); + + +void pit_null_timer(int new_out, int old_out); +void pit_irq0_timer(int new_out, int old_out); +void pit_irq0_timer_pcjr(int new_out, int old_out); +void pit_refresh_timer_xt(int new_out, int old_out); +void pit_refresh_timer_at(int new_out, int old_out); +void pit_speaker_timer(int new_out, int old_out); diff --git a/src/serial.c b/src/serial.c index 467ef1f..f5088a8 100644 --- a/src/serial.c +++ b/src/serial.c @@ -5,211 +5,251 @@ #include "serial.h" #include "timer.h" -SERIAL serial,serial2; +enum +{ + SERIAL_INT_LSR = 1, + SERIAL_INT_RECEIVE = 2, + SERIAL_INT_TRANSMIT = 4, + SERIAL_INT_MSR = 8 +}; + +SERIAL serial1, serial2; int mousepos=-1; int mousedelay; -uint8_t serial_fifo[256]; -int serial_fifo_read, serial_fifo_write; - -void (*serial_rcr)(); void serial_reset() { - serial.iir=serial.ier=serial.lcr=0; - serial2.iir=serial2.ier=serial2.lcr=0; - mousedelay=0; - serial_fifo_read = serial_fifo_write = 0; + serial1.iir = serial1.ier = serial1.lcr = 0; + serial2.iir = serial2.ier = serial2.lcr = 0; + mousedelay = 0; + serial1.fifo_read = serial1.fifo_write = 0; + serial2.fifo_read = serial2.fifo_write = 0; } -void serial_write_fifo(uint8_t dat) +void serial_update_ints(SERIAL *serial) { - serial_fifo[serial_fifo_write] = dat; - serial_fifo_write = (serial_fifo_write + 1) & 0xFF; - if (!(serial.linestat & 1)) + int stat = 0; + + serial->iir = 1; + + if ((serial->ier & 4) && (serial->int_status & SERIAL_INT_LSR)) /*Line status interrupt*/ { - serial.linestat|=1; - if ((serial.mctrl & 8) && (serial.ier & 1)) - picint(0x10); - serial.iir=4; + stat = 1; + serial->iir = 6; + } + else if ((serial->ier & 1) && (serial->int_status & SERIAL_INT_RECEIVE)) /*Recieved data available*/ + { + stat = 1; + serial->iir = 4; + } + else if ((serial->ier & 2) && (serial->int_status & SERIAL_INT_TRANSMIT)) /*Transmit data empty*/ + { + stat = 1; + serial->iir = 2; + } + else if ((serial->ier & 8) && (serial->int_status & SERIAL_INT_MSR)) /*Modem status interrupt*/ + { + stat = 1; + serial->iir = 0; + } + + if (stat && ((serial->mctrl & 8) || PCJR)) + picintlevel(1 << serial->irq); + else + picintc(1 << serial->irq); +} + +void serial_write_fifo(SERIAL *serial, uint8_t dat) +{ +// pclog("serial_write_fifo %02X\n", serial->lsr); + serial->fifo[serial->fifo_write] = dat; + serial->fifo_write = (serial->fifo_write + 1) & 0xFF; + if (!(serial->lsr & 1)) + { + serial->lsr |= 1; + serial->int_status |= SERIAL_INT_RECEIVE; + serial_update_ints(serial); } } -uint8_t serial_read_fifo() +uint8_t serial_read_fifo(SERIAL *serial) { - if (serial_fifo_read != serial_fifo_write) + if (serial->fifo_read != serial->fifo_write) { - serial.dat = serial_fifo[serial_fifo_read]; - serial_fifo_read = (serial_fifo_read + 1) & 0xFF; + serial->dat = serial->fifo[serial->fifo_read]; + serial->fifo_read = (serial->fifo_read + 1) & 0xFF; } - return serial.dat; + return serial->dat; } -void sendserial(uint8_t dat) -{ - serial.rcr=dat; - serial.linestat|=1; - if (serial.mctrl&8) picint(0x10); - serial.iir=4; -} - -void serial_write(uint16_t addr, uint8_t val, void *priv) +void serial_write(uint16_t addr, uint8_t val, void *p) { + SERIAL *serial = (SERIAL *)p; // pclog("Write serial %03X %02X %04X:%04X\n",addr,val,CS,pc); switch (addr&7) { case 0: - if (serial.lcr&0x80 && !AMSTRADIO) + if (serial->lcr & 0x80 && !AMSTRADIO) { - serial.dlab1=val; + serial->dlab1 = val; return; } - serial.thr=val; - serial.linestat|=0x20; - if (serial.mctrl&0x10) + serial->thr = val; + serial->lsr |= 0x20; + serial->int_status |= SERIAL_INT_TRANSMIT; + serial_update_ints(serial); + if (serial->mctrl & 0x10) { - serial_write_fifo(val); -// serial.rcr=val; -// serial.linestat|=1; + serial_write_fifo(serial, val); } break; case 1: - if (serial.lcr&0x80 && !AMSTRADIO) + if (serial->lcr & 0x80 && !AMSTRADIO) { - serial.dlab2=val; + serial->dlab2 = val; return; } - serial.ier=val; + serial->ier = val; + serial_update_ints(serial); + break; + case 3: + serial->lcr = val; break; - case 3: serial.lcr=val; break; case 4: - if ((val&2) && !(serial.mctrl&2)) + if ((val & 2) && !(serial->mctrl & 2)) { - if (serial_rcr) - serial_rcr(); + if (serial->rcr_callback) + serial->rcr_callback(serial); // pclog("RCR raised! sending M\n"); } - serial.mctrl=val; + serial->mctrl = val; + if (val & 0x10) + { + uint8_t new_msr; + + new_msr = (val & 0x0c) << 4; + new_msr |= (val & 0x02) ? 0x10: 0; + new_msr |= (val & 0x01) ? 0x20: 0; + + if ((serial->msr ^ new_msr) & 0x10) + new_msr |= 0x01; + if ((serial->msr ^ new_msr) & 0x20) + new_msr |= 0x02; + if ((serial->msr ^ new_msr) & 0x80) + new_msr |= 0x08; + if ((serial->msr & 0x40) && !(new_msr & 0x40)) + new_msr |= 0x04; + + serial->msr = new_msr; + } + break; + case 5: + serial->lsr = val; + if (serial->lsr & 0x01) + serial->int_status |= SERIAL_INT_RECEIVE; + if (serial->lsr & 0x1e) + serial->int_status |= SERIAL_INT_LSR; + if (serial->lsr & 0x20) + serial->int_status |= SERIAL_INT_TRANSMIT; + serial_update_ints(serial); + break; + case 6: + serial->msr = val; + if (serial->msr & 0x0f) + serial->int_status |= SERIAL_INT_MSR; + serial_update_ints(serial); break; } } -uint8_t serial_read(uint16_t addr, void *priv) +uint8_t serial_read(uint16_t addr, void *p) { - uint8_t temp; + SERIAL *serial = (SERIAL *)p; + uint8_t temp = 0; // pclog("Read serial %03X %04X(%08X):%04X %i %i ", addr, CS, cs, pc, mousedelay, ins); switch (addr&7) { case 0: - if (serial.lcr&0x80 && !AMSTRADIO) return serial.dlab1; -// picintc(0x10); - serial.iir=1; - serial.linestat&=~1; - temp=serial_read_fifo(); - if (serial_fifo_read != serial_fifo_write) - { - mousepos = 0; - mousedelay = 5000 * (1 << TIMER_SHIFT); -// pclog("Next FIFO\n"); - } - break; - case 1: - if (serial.lcr&0x80 && !AMSTRADIO) temp = serial.dlab2; - else temp = serial.ier; - break; - case 2: temp=serial.iir; break; - case 3: temp=serial.lcr; break; - case 4: temp=serial.mctrl; break; - case 5: temp=serial.linestat; serial.linestat|=0x60; break; - default: temp=0; - } -// pclog("%02X\n",temp); - return temp; -} + if (serial->lcr & 0x80 && !AMSTRADIO) + return serial->dlab1; -void serial2_write(uint16_t addr, uint8_t val, void *priv) -{ -// pclog("Write serial2 %03X %02X %04X:%04X\n",addr,val,cs>>4,pc); - switch (addr&7) - { - case 0: - if (serial2.lcr&0x80 && !AMSTRADIO) + serial->lsr &= ~1; + serial->int_status &= ~SERIAL_INT_RECEIVE; + serial_update_ints(serial); + temp = serial_read_fifo(serial); + if (serial->fifo_read != serial->fifo_write) { - serial2.dlab1=val; - return; - } - serial2.thr=val; - serial2.linestat|=0x20; - if (serial2.mctrl&0x10) - { - serial2.rcr=val; - serial2.linestat|=1; + serial->lsr |= 1; + serial->int_status |= SERIAL_INT_RECEIVE; + serial_update_ints(serial); } break; case 1: - if (serial2.lcr&0x80 && !AMSTRADIO) - { - serial2.dlab2=val; - return; - } - serial2.ier=val; + if (serial->lcr & 0x80 && !AMSTRADIO) + temp = serial->dlab2; + else + temp = serial->ier; + break; + case 2: + temp = serial->iir; + if ((temp & 0xe) == 2) + { + serial->int_status &= ~SERIAL_INT_TRANSMIT; + serial_update_ints(serial); + } + break; + case 3: + temp = serial->lcr; break; - case 3: serial2.lcr=val; break; case 4: - serial2.mctrl=val; + temp = serial->mctrl; break; - } -} - -uint8_t serial2_read(uint16_t addr, void *priv) -{ - uint8_t temp; -// pclog("Read serial2 %03X %04X:%04X\n",addr,cs>>4,pc); - switch (addr&7) - { - case 0: - if (serial2.lcr&0x80 && !AMSTRADIO) return serial2.dlab1; - serial2.iir=1; - serial2.linestat&=~1; - temp=serial2.rcr; + case 5: + serial->lsr |= 0x20; + temp = serial->lsr; + if (serial->lsr & 0x1f) + serial->lsr &= ~0x1e; +// serial.lsr |= 0x60; + serial->int_status &= ~SERIAL_INT_LSR; + serial_update_ints(serial); break; - case 1: - if (serial2.lcr&0x80 && !AMSTRADIO) return serial2.dlab2; - temp=0; + case 6: + temp = serial->msr; + serial->msr &= ~0x0f; + serial->int_status &= ~SERIAL_INT_MSR; + serial_update_ints(serial); break; - case 2: temp=serial2.iir; break; - case 3: temp=serial2.lcr; break; - case 4: temp=serial2.mctrl; break; - case 5: temp=serial2.linestat; break; - default: temp=0; } // pclog("%02X\n",temp); return temp; } - /*Tandy might need COM1 at 2f8*/ -void serial1_init(uint16_t addr) +void serial1_init(uint16_t addr, int irq) { - io_sethandler(addr, 0x0008, serial_read, NULL, NULL, serial_write, NULL, NULL, NULL); - serial_rcr = NULL; + io_sethandler(addr, 0x0008, serial_read, NULL, NULL, serial_write, NULL, NULL, &serial1); + serial1.irq = irq; + serial1.rcr_callback = NULL; } void serial1_remove() { - io_removehandler(0x2e8, 0x0008, serial_read, NULL, NULL, serial_write, NULL, NULL, NULL); - io_removehandler(0x2f8, 0x0008, serial_read, NULL, NULL, serial_write, NULL, NULL, NULL); - io_removehandler(0x3e8, 0x0008, serial_read, NULL, NULL, serial_write, NULL, NULL, NULL); - io_removehandler(0x3f8, 0x0008, serial_read, NULL, NULL, serial_write, NULL, NULL, NULL); + io_removehandler(0x2e8, 0x0008, serial_read, NULL, NULL, serial_write, NULL, NULL, &serial1); + io_removehandler(0x2f8, 0x0008, serial_read, NULL, NULL, serial_write, NULL, NULL, &serial1); + io_removehandler(0x3e8, 0x0008, serial_read, NULL, NULL, serial_write, NULL, NULL, &serial1); + io_removehandler(0x3f8, 0x0008, serial_read, NULL, NULL, serial_write, NULL, NULL, &serial1); } -void serial2_init(uint16_t addr) +void serial2_init(uint16_t addr, int irq) { - io_sethandler(addr, 0x0008, serial2_read, NULL, NULL, serial2_write, NULL, NULL, NULL); + io_sethandler(addr, 0x0008, serial_read, NULL, NULL, serial_write, NULL, NULL, &serial2); + serial2.irq = irq; + serial2.rcr_callback = NULL; } void serial2_remove() { - io_removehandler(0x2e8, 0x0008, serial2_read, NULL, NULL, serial2_write, NULL, NULL, NULL); - io_removehandler(0x2f8, 0x0008, serial2_read, NULL, NULL, serial2_write, NULL, NULL, NULL); - io_removehandler(0x3e8, 0x0008, serial2_read, NULL, NULL, serial2_write, NULL, NULL, NULL); - io_removehandler(0x3f8, 0x0008, serial2_read, NULL, NULL, serial2_write, NULL, NULL, NULL); + io_removehandler(0x2e8, 0x0008, serial_read, NULL, NULL, serial_write, NULL, NULL, &serial2); + io_removehandler(0x2f8, 0x0008, serial_read, NULL, NULL, serial_write, NULL, NULL, &serial2); + io_removehandler(0x3e8, 0x0008, serial_read, NULL, NULL, serial_write, NULL, NULL, &serial2); + io_removehandler(0x3f8, 0x0008, serial_read, NULL, NULL, serial_write, NULL, NULL, &serial2); } diff --git a/src/serial.h b/src/serial.h index 058a15d..63bff12 100644 --- a/src/serial.h +++ b/src/serial.h @@ -1,18 +1,23 @@ -void serial1_init(uint16_t addr); -void serial2_init(uint16_t addr); +void serial1_init(uint16_t addr, int irq); +void serial2_init(uint16_t addr, int irq); void serial1_remove(); void serial2_remove(); void serial_reset(); +struct SERIAL; + typedef struct { - uint8_t linestat,thr,mctrl,rcr,iir,ier,lcr; + uint8_t lsr,thr,mctrl,rcr,iir,ier,lcr,msr; uint8_t dlab1,dlab2; uint8_t dat; + uint8_t int_status; + + int irq; + + void (*rcr_callback)(void *p); + uint8_t fifo[256]; + int fifo_read, fifo_write; } SERIAL; -extern SERIAL serial,serial2; - -extern int serial_fifo_read, serial_fifo_write; - -extern void (*serial_rcr)(); +extern SERIAL serial1, serial2; diff --git a/src/sound_sn76489.c b/src/sound_sn76489.c index c027240..a5d75e7 100644 --- a/src/sound_sn76489.c +++ b/src/sound_sn76489.c @@ -5,6 +5,8 @@ #include "sound.h" #include "sound_sn76489.h" +int sn76489_mute; + static float volslog[16]= { 0.00000f,0.59715f,0.75180f,0.94650f, @@ -79,9 +81,12 @@ void sn76489_get_buffer(int16_t *buffer, int len, void *p) sn76489_t *sn76489 = (sn76489_t *)p; int c; - - for (c = 0; c < len * 2; c++) - buffer[c] += sn76489->buffer[c >> 1]; + + if (!sn76489_mute) + { + for (c = 0; c < len * 2; c++) + buffer[c] += sn76489->buffer[c >> 1]; + } sn76489->pos = 0; } @@ -179,6 +184,8 @@ void *sn76489_init() sn76489->noise = 3; sn76489->shift = 0x4000; + sn76489_mute = 0; + return sn76489; } diff --git a/src/sound_sn76489.h b/src/sound_sn76489.h index 89e2d93..5a7ff15 100644 --- a/src/sound_sn76489.h +++ b/src/sound_sn76489.h @@ -1 +1,3 @@ extern device_t sn76489_device; + +extern int sn76489_mute; diff --git a/src/sound_speaker.c b/src/sound_speaker.c index 87efb4e..32c66a6 100644 --- a/src/sound_speaker.c +++ b/src/sound_speaker.c @@ -2,6 +2,8 @@ #include "sound.h" #include "sound_speaker.h" +int speaker_mute = 0; + static int16_t speaker_buffer[SOUNDBUFLEN]; static int speaker_pos = 0; @@ -30,8 +32,11 @@ static void speaker_get_buffer(int16_t *buffer, int len, void *p) { int c; - for (c = 0; c < len * 2; c++) - buffer[c] += speaker_buffer[c >> 1]; + if (!speaker_mute) + { + for (c = 0; c < len * 2; c++) + buffer[c] += speaker_buffer[c >> 1]; + } speaker_pos = 0; } @@ -39,4 +44,5 @@ static void speaker_get_buffer(int16_t *buffer, int len, void *p) void speaker_init() { sound_add_handler(speaker_poll, speaker_get_buffer, NULL); + speaker_mute = 0; } diff --git a/src/sound_speaker.h b/src/sound_speaker.h index 5b25efb..a55bfd8 100644 --- a/src/sound_speaker.h +++ b/src/sound_speaker.h @@ -1 +1,3 @@ void speaker_init(); + +extern int speaker_mute; diff --git a/src/um8669f.c b/src/um8669f.c index 30e55e6..2ba6f37 100644 --- a/src/um8669f.c +++ b/src/um8669f.c @@ -83,10 +83,10 @@ void um8669f_write(uint16_t port, uint8_t val, void *priv) temp |= 2; switch (temp) { - case 0: serial1_init(0x3f8); break; - case 1: serial1_init(0x2f8); break; - case 2: serial1_init(0x3e8); break; - case 3: serial1_init(0x2e8); break; + case 0: serial1_init(0x3f8, 4); break; + case 1: serial1_init(0x2f8, 4); break; + case 2: serial1_init(0x3e8, 4); break; + case 3: serial1_init(0x2e8, 4); break; } } @@ -98,10 +98,10 @@ void um8669f_write(uint16_t port, uint8_t val, void *priv) temp |= 2; switch (temp) { - case 0: serial2_init(0x3f8); break; - case 1: serial2_init(0x2f8); break; - case 2: serial2_init(0x3e8); break; - case 3: serial2_init(0x2e8); break; + case 0: serial2_init(0x3f8, 3); break; + case 1: serial2_init(0x2f8, 3); break; + case 2: serial2_init(0x3e8, 3); break; + case 3: serial2_init(0x2e8, 3); break; } } diff --git a/src/vid_pcjr.c b/src/vid_pcjr.c new file mode 100644 index 0000000..8e39d02 --- /dev/null +++ b/src/vid_pcjr.c @@ -0,0 +1,647 @@ +#include +#include +#include "ibm.h" +#include "device.h" +#include "io.h" +#include "mem.h" +#include "timer.h" +#include "video.h" +#include "vid_pcjr.h" + +static int i_filt[8],q_filt[8]; + +typedef struct pcjr_t +{ + mem_mapping_t mapping; + + uint8_t crtc[32]; + int crtcreg; + + int array_index; + uint8_t array[32]; + int array_ff; + int memctrl;//=-1; + uint8_t stat; + int addr_mode; + + uint8_t *vram, *b8000; + + int linepos, displine; + int sc, vc; + int dispon; + int con, coff, cursoron, blink; + int vsynctime, vadj; + uint16_t ma, maback; + + int dispontime, dispofftime, vidtime; + int firstline, lastline; +} pcjr_t; + +static uint8_t crtcmask[32] = +{ + 0xff, 0xff, 0xff, 0xff, 0x7f, 0x1f, 0x7f, 0x7f, 0xf3, 0x1f, 0x7f, 0x1f, 0x3f, 0xff, 0x3f, 0xff, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +void pcjr_recalcaddress(pcjr_t *pcjr); +void pcjr_recalctimings(pcjr_t *pcjr); + +void pcjr_out(uint16_t addr, uint8_t val, void *p) +{ + pcjr_t *pcjr = (pcjr_t *)p; + uint8_t old; +// pclog("pcjr OUT %04X %02X\n",addr,val); + switch (addr) + { + case 0x3d4: + pcjr->crtcreg = val & 0x1f; + return; + case 0x3d5: +// pclog("CRTC write %02X %02x\n", pcjr->crtcreg, val); + old = pcjr->crtc[pcjr->crtcreg]; + pcjr->crtc[pcjr->crtcreg] = val & crtcmask[pcjr->crtcreg]; + if (old != val) + { + if (pcjr->crtcreg < 0xe || pcjr->crtcreg > 0x10) + { + fullchange = changeframecount; + pcjr_recalctimings(pcjr); + } + } + return; + case 0x3da: +// pclog("Array write %02X %02X\n", pcjr->array_index, val); + if (!pcjr->array_ff) + pcjr->array_index = val & 0x1f; + else + { + if (pcjr->array_index & 0x10) + val &= 0x0f; + pcjr->array[pcjr->array_index & 0x1f] = val; + } + pcjr->array_ff = !pcjr->array_ff; + break; + case 0x3df: + pcjr->memctrl = val; + pcjr->addr_mode = val >> 6; + pcjr_recalcaddress(pcjr); + break; + } +} + +uint8_t pcjr_in(uint16_t addr, void *p) +{ + pcjr_t *pcjr = (pcjr_t *)p; +// if (addr!=0x3DA) pclog("pcjr IN %04X\n",addr); + switch (addr) + { + case 0x3d4: + return pcjr->crtcreg; + case 0x3d5: + return pcjr->crtc[pcjr->crtcreg]; + case 0x3da: + pcjr->array_ff = 0; + pcjr->stat ^= 0x10; + return pcjr->stat; + } + return 0xFF; +} + +void pcjr_recalcaddress(pcjr_t *pcjr) +{ + if ((pcjr->memctrl & 0xc0) == 0xc0) + { + pcjr->vram = &ram[(pcjr->memctrl & 0x06) << 14]; + pcjr->b8000 = &ram[(pcjr->memctrl & 0x30) << 11]; +// printf("VRAM at %05X B8000 at %05X\n",((pcjr->memctrl&0x6)<<14)+pcjr->base,((pcjr->memctrl&0x30)<<11)+pcjr->base); + } + else + { + pcjr->vram = &ram[(pcjr->memctrl & 0x07) << 14]; + pcjr->b8000 = &ram[(pcjr->memctrl & 0x38) << 11]; +// printf("VRAM at %05X B8000 at %05X\n",((pcjr->memctrl&0x7)<<14)+pcjr->base,((pcjr->memctrl&0x38)<<11)+pcjr->base); + } +} + +void pcjr_write(uint32_t addr, uint8_t val, void *p) +{ + pcjr_t *pcjr = (pcjr_t *)p; + if (pcjr->memctrl == -1) + return; + + egawrites++; +// pclog("pcjr VRAM write %05X %02X %04X:%04X %04X:%04X\n",addr,val,CS,pc,DS,SI); + pcjr->b8000[addr & 0x3fff] = val; +} + +uint8_t pcjr_read(uint32_t addr, void *p) +{ + pcjr_t *pcjr = (pcjr_t *)p; + if (pcjr->memctrl == -1) + return 0xff; + + egareads++; +// pclog("pcjr VRAM read %05X %02X %04X:%04X\n",addr,pcjr->b8000[addr&0x7FFF],CS,pc); + return pcjr->b8000[addr & 0x3fff]; +} + +void pcjr_recalctimings(pcjr_t *pcjr) +{ + double _dispontime, _dispofftime, disptime; + if (pcjr->array[0] & 1) + { + disptime = pcjr->crtc[0] + 1; + _dispontime = pcjr->crtc[1]; + } + else + { + disptime = (pcjr->crtc[0] + 1) << 1; + _dispontime = pcjr->crtc[1] << 1; + } + _dispofftime = disptime - _dispontime; + _dispontime *= CGACONST; + _dispofftime *= CGACONST; + pcjr->dispontime = (int)(_dispontime * (1 << TIMER_SHIFT)); + pcjr->dispofftime = (int)(_dispofftime * (1 << TIMER_SHIFT)); +} + + +static int ntsc_col[8][8]= +{ + {0,0,0,0,0,0,0,0}, /*Black*/ + {0,0,1,1,1,1,0,0}, /*Blue*/ + {1,0,0,0,0,1,1,1}, /*Green*/ + {0,0,0,0,1,1,1,1}, /*Cyan*/ + {1,1,1,1,0,0,0,0}, /*Red*/ + {0,1,1,1,1,0,0,0}, /*Magenta*/ + {1,1,0,0,0,0,1,1}, /*Yellow*/ + {1,1,1,1,1,1,1,1} /*White*/ +}; + +/*static int cga4pal[8][4]= +{ + {0,2,4,6},{0,3,5,7},{0,3,4,7},{0,3,4,7}, + {0,10,12,14},{0,11,13,15},{0,11,12,15},{0,11,12,15} +};*/ + +void pcjr_poll(void *p) +{ +// int *cgapal=cga4pal[((pcjr->col&0x10)>>2)|((cgamode&4)>>1)|((cgacol&0x20)>>5)]; + pcjr_t *pcjr = (pcjr_t *)p; + uint16_t ca = (pcjr->crtc[15] | (pcjr->crtc[14] << 8)) & 0x3fff; + int drawcursor; + int x, c; + int oldvc; + uint8_t chr, attr; + uint16_t dat; + int cols[4]; + int col; + int oldsc; + int y_buf[8] = {0, 0, 0, 0, 0, 0, 0, 0}, y_val, y_tot; + int i_buf[8] = {0, 0, 0, 0, 0, 0, 0, 0}, i_val, i_tot; + int q_buf[8] = {0, 0, 0, 0, 0, 0, 0, 0}, q_val, q_tot; + int r, g, b; + if (!pcjr->linepos) + { +// cgapal[0]=pcjr->col&15; +// printf("Firstline %i Lastline %i pcjr->displine %i\n",firstline,lastline,pcjr->displine); + pcjr->vidtime += pcjr->dispofftime; + pcjr->stat &= ~1; + pcjr->linepos = 1; + oldsc = pcjr->sc; + if ((pcjr->crtc[8] & 3) == 3) + pcjr->sc = (pcjr->sc << 1) & 7; + if (pcjr->dispon) + { + uint16_t offset = 0; + uint16_t mask = 0x1fff; + + if (pcjr->displine < pcjr->firstline) + pcjr->firstline = pcjr->displine; + pcjr->lastline = pcjr->displine; + cols[0] = (pcjr->array[2] & 0xf) + 16; + for (c = 0; c < 8; c++) + { + buffer->line[pcjr->displine][c] = cols[0]; + if (pcjr->array[0] & 1) buffer->line[pcjr->displine][c + (pcjr->crtc[1] << 3) + 8] = cols[0]; + else buffer->line[pcjr->displine][c + (pcjr->crtc[1] << 4) + 8] = cols[0]; + } + + switch (pcjr->addr_mode) + { + case 0: /*Alpha*/ + offset = 0; + mask = 0x3fff; + break; + case 1: /*Low resolution graphics*/ + offset = (pcjr->sc & 1) * 0x2000; + break; + case 3: /*High resolution graphics*/ + offset = (pcjr->sc & 3) * 0x2000; + break; + } + + switch ((pcjr->array[0] & 0x13) | ((pcjr->array[3] & 0x10) << 4)) + { + case 0x13: /*320x200x16*/ + for (x = 0; x < pcjr->crtc[1]; x++) + { + dat = (pcjr->vram[((pcjr->ma << 1) & mask) + offset] << 8) | + pcjr->vram[((pcjr->ma << 1) & mask) + offset + 1]; + pcjr->ma++; + buffer->line[pcjr->displine][(x << 3) + 8] = + buffer->line[pcjr->displine][(x << 3) + 9] = pcjr->array[((dat >> 12) & pcjr->array[1]) + 16] + 16; + buffer->line[pcjr->displine][(x << 3) + 10] = + buffer->line[pcjr->displine][(x << 3) + 11] = pcjr->array[((dat >> 8) & pcjr->array[1]) + 16] + 16; + buffer->line[pcjr->displine][(x << 3) + 12] = + buffer->line[pcjr->displine][(x << 3) + 13] = pcjr->array[((dat >> 4) & pcjr->array[1]) + 16] + 16; + buffer->line[pcjr->displine][(x << 3) + 14] = + buffer->line[pcjr->displine][(x << 3) + 15] = pcjr->array[(dat & pcjr->array[1]) + 16] + 16; + } + break; + case 0x12: /*160x200x16*/ + for (x = 0; x < pcjr->crtc[1]; x++) + { + dat = (pcjr->vram[((pcjr->ma << 1) & mask) + offset] << 8) | + pcjr->vram[((pcjr->ma << 1) & mask) + offset + 1]; + pcjr->ma++; + buffer->line[pcjr->displine][(x << 4) + 8] = + buffer->line[pcjr->displine][(x << 4) + 9] = + buffer->line[pcjr->displine][(x << 4) + 10] = + buffer->line[pcjr->displine][(x << 4) + 11] = pcjr->array[((dat >> 12) & pcjr->array[1]) + 16] + 16; + buffer->line[pcjr->displine][(x << 4) + 12] = + buffer->line[pcjr->displine][(x << 4) + 13] = + buffer->line[pcjr->displine][(x << 4) + 14] = + buffer->line[pcjr->displine][(x << 4) + 15] = pcjr->array[((dat >> 8) & pcjr->array[1]) + 16] + 16; + buffer->line[pcjr->displine][(x << 4) + 16] = + buffer->line[pcjr->displine][(x << 4) + 17] = + buffer->line[pcjr->displine][(x << 4) + 18] = + buffer->line[pcjr->displine][(x << 4) + 19] = pcjr->array[((dat >> 4) & pcjr->array[1]) + 16] + 16; + buffer->line[pcjr->displine][(x << 4) + 20] = + buffer->line[pcjr->displine][(x << 4) + 21] = + buffer->line[pcjr->displine][(x << 4) + 22] = + buffer->line[pcjr->displine][(x << 4) + 23] = pcjr->array[(dat & pcjr->array[1]) + 16] + 16; + } + break; + case 0x03: /*640x200x4*/ + for (x = 0; x < pcjr->crtc[1]; x++) + { + dat = (pcjr->vram[((pcjr->ma << 1) & mask) + offset] << 8) | + pcjr->vram[((pcjr->ma << 1) & mask) + offset + 1]; + pcjr->ma++; + for (c = 0; c < 8; c++) + { + chr = (dat >> 7) & 1; + chr |= ((dat >> 14) & 2); + buffer->line[pcjr->displine][(x << 3) + 8 + c] = pcjr->array[(chr & pcjr->array[1]) + 16] + 16; + dat <<= 1; + } + } + break; + case 0x01: /*80 column text*/ + for (x = 0; x < pcjr->crtc[1]; x++) + { + chr = pcjr->vram[((pcjr->ma << 1) & mask) + offset]; + attr = pcjr->vram[((pcjr->ma << 1) & mask) + offset + 1]; + drawcursor = ((pcjr->ma == ca) && pcjr->con && pcjr->cursoron); + if (pcjr->array[3] & 4) + { + cols[1] = pcjr->array[ ((attr & 15) & pcjr->array[1]) + 16] + 16; + cols[0] = pcjr->array[(((attr >> 4) & 7) & pcjr->array[1]) + 16] + 16; + if ((pcjr->blink & 16) && (attr & 0x80) && !drawcursor) + cols[1] = cols[0]; + } + else + { + cols[1] = pcjr->array[((attr & 15) & pcjr->array[1]) + 16] + 16; + cols[0] = pcjr->array[((attr >> 4) & pcjr->array[1]) + 16] + 16; + } + if (pcjr->sc & 8) + { + for (c = 0; c < 8; c++) + buffer->line[pcjr->displine][(x << 3) + c + 8] = cols[0]; + } + else + { + for (c = 0; c < 8; c++) + buffer->line[pcjr->displine][(x << 3) + c + 8] = cols[(fontdat[chr][pcjr->sc & 7] & (1 << (c ^ 7))) ? 1 : 0]; + } +// if (!((ma^(crtc[15]|(crtc[14]<<8)))&0x3FFF)) printf("Cursor match! %04X\n",ma); + if (drawcursor) + { + for (c = 0; c < 8; c++) + buffer->line[pcjr->displine][(x << 3) + c + 8] ^= 15; + } + pcjr->ma++; + } + break; + case 0x00: /*40 column text*/ + for (x = 0; x < pcjr->crtc[1]; x++) + { + chr = pcjr->vram[((pcjr->ma << 1) & mask) + offset]; + attr = pcjr->vram[((pcjr->ma << 1) & mask) + offset + 1]; + drawcursor = ((pcjr->ma == ca) && pcjr->con && pcjr->cursoron); + if (pcjr->array[3] & 4) + { + cols[1] = pcjr->array[ ((attr & 15) & pcjr->array[1]) + 16] + 16; + cols[0] = pcjr->array[(((attr >> 4) & 7) & pcjr->array[1]) + 16] + 16; + if ((pcjr->blink & 16) && (attr & 0x80) && !drawcursor) + cols[1] = cols[0]; + } + else + { + cols[1] = pcjr->array[((attr & 15) & pcjr->array[1]) + 16] + 16; + cols[0] = pcjr->array[((attr >> 4) & pcjr->array[1]) + 16] + 16; + } + pcjr->ma++; + if (pcjr->sc & 8) + { + for (c = 0; c < 8; c++) + buffer->line[pcjr->displine][(x << 4) + (c << 1) + 8] = + buffer->line[pcjr->displine][(x << 4) + (c << 1) + 1 + 8] = cols[0]; + } + else + { + for (c = 0; c < 8; c++) + buffer->line[pcjr->displine][(x << 4) + (c << 1) + 8] = + buffer->line[pcjr->displine][(x << 4) + (c << 1) + 1 + 8] = cols[(fontdat[chr][pcjr->sc & 7] & (1 << (c ^ 7))) ? 1 : 0]; + } + if (drawcursor) + { + for (c = 0; c < 16; c++) + buffer->line[pcjr->displine][(x << 4) + c + 8] ^= 15; + } + } + break; + case 0x02: /*320x200x4*/ + cols[0] = pcjr->array[0 + 16] + 16; + cols[1] = pcjr->array[1 + 16] + 16; + cols[2] = pcjr->array[2 + 16] + 16; + cols[3] = pcjr->array[3 + 16] + 16; + for (x = 0; x < pcjr->crtc[1]; x++) + { + dat = (pcjr->vram[((pcjr->ma << 1) & mask) + offset] << 8) | + pcjr->vram[((pcjr->ma << 1) & mask) + offset + 1]; + pcjr->ma++; + for (c = 0; c < 8; c++) + { + buffer->line[pcjr->displine][(x << 4) + (c << 1) + 8] = + buffer->line[pcjr->displine][(x << 4) + (c << 1) + 1 + 8] = cols[dat >> 14]; + dat <<= 2; + } + } + break; + case 0x102: /*640x200x2*/ + cols[0] = 0; + cols[1] = pcjr->array[0 + 16] + 16; + for (x = 0; x < pcjr->crtc[1]; x++) + { + dat = (pcjr->vram[((pcjr->ma << 1) & mask) + offset] << 8) | + pcjr->vram[((pcjr->ma << 1) & mask) + offset + 1]; + pcjr->ma++; + for (c = 0; c < 16; c++) + { + buffer->line[pcjr->displine][(x << 4) + c + 8] = cols[dat >> 15]; + dat <<= 1; + } + } + break; + } + } + else + { + if (pcjr->array[3] & 4) + { + if (pcjr->array[0] & 1) hline(buffer, 0, pcjr->displine, (pcjr->crtc[1] << 3) + 16, (pcjr->array[2] & 0xf) + 16); + else hline(buffer, 0, pcjr->displine, (pcjr->crtc[1] << 4) + 16, (pcjr->array[2] & 0xf) + 16); + } + else + { +// cols[0] = ((pcjr->mode & 0x12) == 0x12) ? 0 : (pcjr->col & 0xf) + 16; + cols[0] = pcjr->array[0 + 16] + 16; + if (pcjr->array[0] & 1) hline(buffer, 0, pcjr->displine, (pcjr->crtc[1] << 3) + 16, cols[0]); + else hline(buffer, 0, pcjr->displine, (pcjr->crtc[1] << 4) + 16, cols[0]); + } + } + if (pcjr->array[0] & 1) x = (pcjr->crtc[1] << 3) + 16; + else x = (pcjr->crtc[1] << 4) + 16; + if (cga_comp) + { + for (c = 0; c < x; c++) + { + y_buf[(c << 1) & 6] = ntsc_col[buffer->line[pcjr->displine][c] & 7][(c << 1) & 6] ? 0x6000 : 0; + y_buf[(c << 1) & 6] += (buffer->line[pcjr->displine][c] & 8) ? 0x3000 : 0; + i_buf[(c << 1) & 6] = y_buf[(c << 1) & 6] * i_filt[(c << 1) & 6]; + q_buf[(c << 1) & 6] = y_buf[(c << 1) & 6] * q_filt[(c << 1) & 6]; + y_tot = y_buf[0] + y_buf[1] + y_buf[2] + y_buf[3] + y_buf[4] + y_buf[5] + y_buf[6] + y_buf[7]; + i_tot = i_buf[0] + i_buf[1] + i_buf[2] + i_buf[3] + i_buf[4] + i_buf[5] + i_buf[6] + i_buf[7]; + q_tot = q_buf[0] + q_buf[1] + q_buf[2] + q_buf[3] + q_buf[4] + q_buf[5] + q_buf[6] + q_buf[7]; + + y_val = y_tot >> 10; + if (y_val > 255) y_val = 255; + y_val <<= 16; + i_val = i_tot >> 12; + if (i_val > 39041) i_val = 39041; + if (i_val < -39041) i_val = -39041; + q_val = q_tot >> 12; + if (q_val > 34249) q_val = 34249; + if (q_val < -34249) q_val = -34249; + + r = (y_val + 249*i_val + 159*q_val) >> 16; + g = (y_val - 70*i_val - 166*q_val) >> 16; + b = (y_val - 283*i_val + 436*q_val) >> 16; + + y_buf[((c << 1) & 6) + 1] = ntsc_col[buffer->line[pcjr->displine][c] & 7][((c << 1) & 6) + 1] ? 0x6000 : 0; + y_buf[((c << 1) & 6) + 1] += (buffer->line[pcjr->displine][c] & 8) ? 0x3000 : 0; + i_buf[((c << 1) & 6) + 1] = y_buf[((c << 1) & 6) + 1] * i_filt[((c << 1) & 6) + 1]; + q_buf[((c << 1) & 6) + 1] = y_buf[((c << 1) & 6) + 1] * q_filt[((c << 1) & 6) + 1]; + y_tot = y_buf[0] + y_buf[1] + y_buf[2] + y_buf[3] + y_buf[4] + y_buf[5] + y_buf[6] + y_buf[7]; + i_tot = i_buf[0] + i_buf[1] + i_buf[2] + i_buf[3] + i_buf[4] + i_buf[5] + i_buf[6] + i_buf[7]; + q_tot = q_buf[0] + q_buf[1] + q_buf[2] + q_buf[3] + q_buf[4] + q_buf[5] + q_buf[6] + q_buf[7]; + + y_val = y_tot >> 10; + if (y_val > 255) y_val = 255; + y_val <<= 16; + i_val = i_tot >> 12; + if (i_val > 39041) i_val = 39041; + if (i_val < -39041) i_val = -39041; + q_val = q_tot >> 12; + if (q_val > 34249) q_val = 34249; + if (q_val < -34249) q_val = -34249; + + r = (y_val + 249*i_val + 159*q_val) >> 16; + g = (y_val - 70*i_val - 166*q_val) >> 16; + b = (y_val - 283*i_val + 436*q_val) >> 16; + if (r > 511) r = 511; + if (g > 511) g = 511; + if (b > 511) b = 511; + + ((uint32_t *)buffer32->line[pcjr->displine])[c] = makecol32(r / 2, g / 2, b / 2); + } + } + pcjr->sc = oldsc; + if (pcjr->vc == pcjr->crtc[7] && !pcjr->sc) + { + pcjr->stat |= 8; +// printf("VSYNC on %i %i\n",vc,sc); + } + pcjr->displine++; + if (pcjr->displine >= 360) + pcjr->displine = 0; + } + else + { + pcjr->vidtime += pcjr->dispontime; + if (pcjr->dispon) + pcjr->stat |= 1; + pcjr->linepos = 0; + if (pcjr->vsynctime) + { + pcjr->vsynctime--; + if (!pcjr->vsynctime) + { + pcjr->stat &= ~8; +// printf("VSYNC off %i %i\n",vc,sc); + } + } + if (pcjr->sc == (pcjr->crtc[11] & 31) || ((pcjr->crtc[8] & 3) == 3 && pcjr->sc == ((pcjr->crtc[11] & 31) >> 1))) + { + pcjr->con = 0; + pcjr->coff = 1; + } + if (pcjr->vadj) + { + pcjr->sc++; + pcjr->sc &= 31; + pcjr->ma = pcjr->maback; + pcjr->vadj--; + if (!pcjr->vadj) + { + pcjr->dispon = 1; + pcjr->ma = pcjr->maback = (pcjr->crtc[13] | (pcjr->crtc[12] << 8)) & 0x3fff; + pcjr->sc = 0; +// printf("Display on!\n"); + } + } + else if (pcjr->sc == pcjr->crtc[9] || ((pcjr->crtc[8] & 3) == 3 && pcjr->sc == (pcjr->crtc[9] >> 1))) + { + pcjr->maback = pcjr->ma; +// con=0; +// coff=0; + pcjr->sc = 0; + oldvc = pcjr->vc; + pcjr->vc++; + pcjr->vc &= 127; +// pclog("VC %i %i\n", pcjr->vc, pcjr->crtc[7]); +// printf("VC %i %i %i %i %i\n",vc,crtc[4],crtc[6],crtc[7],pcjr->dispon); + if (pcjr->vc == pcjr->crtc[6]) + pcjr->dispon = 0; + if (oldvc == pcjr->crtc[4]) + { +// printf("Display over at %i\n",pcjr->displine); + pcjr->vc = 0; + pcjr->vadj = pcjr->crtc[5]; + if (!pcjr->vadj) + pcjr->dispon = 1; + if (!pcjr->vadj) + pcjr->ma = pcjr->maback = (pcjr->crtc[13] | (pcjr->crtc[12] << 8)) & 0x3fff; + if ((pcjr->crtc[10] & 0x60) == 0x20) pcjr->cursoron = 0; + else pcjr->cursoron = pcjr->blink & 16; +// printf("CRTC10 %02X %i\n",crtc[10],cursoron); + } + if (pcjr->vc == pcjr->crtc[7]) + { + pcjr->dispon = 0; + pcjr->displine = 0; + pcjr->vsynctime = 16;//(crtc[3]>>4)+1; + picint(1 << 5); +// printf("pcjr->vsynctime %i %02X\n",pcjr->vsynctime,crtc[3]); +// pcjr->stat|=8; + if (pcjr->crtc[7]) + { +// printf("Lastline %i Firstline %i %i %i %i\n",lastline,firstline,lastline-firstline,crtc[1],xsize); + if (pcjr->array[0] & 1) x = (pcjr->crtc[1] << 3) + 16; + else x = (pcjr->crtc[1] << 4) + 16; + pcjr->lastline++; + if (x != xsize || (pcjr->lastline - pcjr->firstline) != ysize) + { + xsize = x; + ysize = pcjr->lastline - pcjr->firstline; +// printf("Resize to %i,%i - R1 %i\n",xsize,ysize,crtc[1]); + if (xsize < 64) xsize = 656; + if (ysize < 32) ysize = 200; + updatewindowsize(xsize, (ysize << 1) + 16); + } +// printf("Blit %i %i\n",firstline,lastline); +//printf("Xsize is %i\n",xsize); + startblit(); + if (cga_comp) + video_blit_memtoscreen(0, pcjr->firstline-4, 0, (pcjr->lastline - pcjr->firstline) + 8, xsize, (pcjr->lastline - pcjr->firstline) + 8); + else + video_blit_memtoscreen_8(0, pcjr->firstline-4, xsize, (pcjr->lastline - pcjr->firstline) + 8); + endblit(); + frames++; + video_res_x = xsize - 16; + video_res_y = ysize; + } + pcjr->firstline = 1000; + pcjr->lastline = 0; + pcjr->blink++; + } + } + else + { + pcjr->sc++; + pcjr->sc &= 31; + pcjr->ma = pcjr->maback; + } + if ((pcjr->sc == (pcjr->crtc[10] & 31) || ((pcjr->crtc[8] & 3) == 3 && pcjr->sc == ((pcjr->crtc[10] & 31) >> 1)))) + pcjr->con = 1; + } +} + +static void *pcjr_video_init() +{ + int c; + int pcjr_tint = -2; + pcjr_t *pcjr = malloc(sizeof(pcjr_t)); + memset(pcjr, 0, sizeof(pcjr_t)); + + pcjr->memctrl = -1; + + for (c = 0; c < 8; c++) + { + i_filt[c] = 512.0 * cos((3.14 * (pcjr_tint + c * 4) / 16.0) - 33.0 / 180.0); + q_filt[c] = 512.0 * sin((3.14 * (pcjr_tint + c * 4) / 16.0) - 33.0 / 180.0); + } + timer_add(pcjr_poll, &pcjr->vidtime, TIMER_ALWAYS_ENABLED, pcjr); + mem_mapping_add(&pcjr->mapping, 0xb8000, 0x08000, pcjr_read, NULL, NULL, pcjr_write, NULL, NULL, pcjr); + io_sethandler(0x03d0, 0x0010, pcjr_in, NULL, NULL, pcjr_out, NULL, NULL, pcjr); + return pcjr; +} + +static void pcjr_video_close(void *p) +{ + pcjr_t *pcjr = (pcjr_t *)p; + + free(pcjr); +} + +static void pcjr_speed_changed(void *p) +{ + pcjr_t *pcjr = (pcjr_t *)p; + + pcjr_recalctimings(pcjr); +} + +device_t pcjr_video_device = +{ + "IBM PCjr (video)", + 0, + pcjr_video_init, + pcjr_video_close, + NULL, + pcjr_speed_changed, + NULL, + NULL +}; diff --git a/src/vid_pcjr.h b/src/vid_pcjr.h new file mode 100644 index 0000000..21655c6 --- /dev/null +++ b/src/vid_pcjr.h @@ -0,0 +1 @@ +extern device_t pcjr_video_device; diff --git a/src/video.c b/src/video.c index a397010..bb8ec69 100644 --- a/src/video.c +++ b/src/video.c @@ -26,6 +26,7 @@ #include "vid_pc1512.h" #include "vid_pc1640.h" #include "vid_pc200.h" +#include "vid_pcjr.h" #include "vid_s3.h" #include "vid_s3_virge.h" #include "vid_tandy.h" @@ -203,6 +204,10 @@ void video_init() switch (romset) { + case ROM_IBMPCJR: + device_add(&pcjr_video_device); + return; + case ROM_TANDY: device_add(&tandy_device); return; diff --git a/src/wd76c10.c b/src/wd76c10.c index 75bd78f..c3859f1 100644 --- a/src/wd76c10.c +++ b/src/wd76c10.c @@ -49,17 +49,17 @@ void wd76c10_write(uint16_t port, uint16_t val, void *priv) switch ((val >> 5) & 7) { - case 1: serial1_init(0x3f8); break; - case 2: serial1_init(0x2f8); break; - case 3: serial1_init(0x3e8); break; - case 4: serial1_init(0x2e8); break; + case 1: serial1_init(0x3f8, 4); break; + case 2: serial1_init(0x2f8, 4); break; + case 3: serial1_init(0x3e8, 4); break; + case 4: serial1_init(0x2e8, 4); break; } switch ((val >> 1) & 7) { - case 1: serial2_init(0x3f8); break; - case 2: serial2_init(0x2f8); break; - case 3: serial2_init(0x3e8); break; - case 4: serial2_init(0x2e8); break; + case 1: serial2_init(0x3f8, 3); break; + case 2: serial2_init(0x2f8, 3); break; + case 3: serial2_init(0x3e8, 3); break; + case 4: serial2_init(0x2e8, 3); break; } break; diff --git a/src/x86.h b/src/x86.h index 6c8cef9..e02c7c0 100644 --- a/src/x86.h +++ b/src/x86.h @@ -3,6 +3,8 @@ uint32_t oldpc; extern uint32_t rmdat32; int oldcpl; +extern int nmi_enable; + int tempc; int cycles,output; int ssegs;