Preliminary PCjr emulation.

Improvements to PIT and serial emulation.
This commit is contained in:
TomW 2014-01-12 11:37:09 +00:00
commit f18f10574a
27 changed files with 1659 additions and 377 deletions

View file

@ -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++;

View file

@ -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 \

View file

@ -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

View file

@ -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[];

166
src/fdc.c
View file

@ -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()

View file

@ -1,5 +1,6 @@
void fdc_init();
void fdc_add();
void fdc_add_pcjr();
void fdc_remove();
void fdc_reset();
void fdc_poll();

View file

@ -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,

202
src/keyboard_pcjr.c Normal file
View file

@ -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);
}

3
src/keyboard_pcjr.h Normal file
View file

@ -0,0 +1,3 @@
void keyboard_pcjr_init();
void keyboard_pcjr_reset();
void keyboard_pcjr_poll();

View file

@ -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;

View file

@ -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();

View file

@ -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);
}

View file

@ -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;

487
src/pit.c
View file

@ -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);
}

View file

@ -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);

View file

@ -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);
}

View file

@ -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;

View file

@ -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;
}

View file

@ -1 +1,3 @@
extern device_t sn76489_device;
extern int sn76489_mute;

View file

@ -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;
}

View file

@ -1 +1,3 @@
void speaker_init();
extern int speaker_mute;

View file

@ -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;
}
}

647
src/vid_pcjr.c Normal file
View file

@ -0,0 +1,647 @@
#include <stdlib.h>
#include <math.h>
#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
};

1
src/vid_pcjr.h Normal file
View file

@ -0,0 +1 @@
extern device_t pcjr_video_device;

View file

@ -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;

View file

@ -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;

View file

@ -3,6 +3,8 @@ uint32_t oldpc;
extern uint32_t rmdat32;
int oldcpl;
extern int nmi_enable;
int tempc;
int cycles,output;
int ssegs;