Add v0.7 source

This commit is contained in:
TomW 2013-04-21 14:54:35 +01:00
commit 3c253c2cf8
188 changed files with 52566 additions and 0 deletions

3787
src/286.c Normal file

File diff suppressed because it is too large Load diff

8377
src/386.c Normal file

File diff suppressed because it is too large Load diff

43
src/Makefile.mingw Normal file
View file

@ -0,0 +1,43 @@
VPATH = . mame
CPP = g++.exe
CC = gcc.exe
WINDRES = windres.exe
CFLAGS = -O3 -march=i686 -fomit-frame-pointer
OBJ = 286.o 386.o acer386sx.o adlib.o ali1429.o amstrad.o cdrom-ioctl.o cms.o \
config.o cpu.o dac.o dma.o ega.o fdc.o gus.o harddisk.o \
headland.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 \
mouse.o mouse_ps2.o mouse_serial.o neat.o nvr.o olivetti_m24.o \
opti.o pc.o pci.o pic.o pit.o \
ppi.o psg.o sblaster.o serial.o sound.o soundopenal.o um8881f.o \
vid_cga.o vid_ega.o vid_et4000.o vid_et4000w32.o \
vid_et4000w32i.o vid_hercules.o vid_icd2061.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_sdac_ramdac.o vid_stg_ramdac.o \
vid_svga.o vid_tandy.o vid_tkd8001_ramdac.o vid_tvga.o \
vid_unk_ramdac.o video.o wd76c10.o win.o win-ddraw.o \
win-keyboard.o win-mouse.o win-timer.o win-video.o x86.o \
x86seg.o x87.o xtide.o pc.res
FMOBJ = fmopl.o ymf262.o
LIBS = -mwindows -lwinmm -lalut -lopenal32 -lddraw -ldinput -ldxguid
PCem.exe: $(OBJ) $(FMOBJ)
$(CC) $(OBJ) $(FMOBJ) -o "PCem.exe" $(LIBS)
all : PCem.exe
clean :
del *.o
del *.exe
del *.res
%.o : %.c
$(CC) $(CFLAGS) -c $<
%.o : %.cc
$(CPP) $(CFLAGS) -c $<
pc.res: pc.rc
$(WINDRES) -i pc.rc --input-format=rc -o pc.res -O coff

33
src/acer386sx.c Normal file
View file

@ -0,0 +1,33 @@
#include "ibm.h"
#include "io.h"
#include "cpu.h"
#include "acer386sx.h"
static int acer_index = 0;
static uint8_t acer_regs[256];
void acer386sx_write(uint16_t addr, uint8_t val)
{
if (addr & 1)
acer_regs[acer_index] = val;
else
acer_index = val;
}
uint8_t acer386sx_read(uint16_t addr)
{
if (addr & 1)
{
if ((acer_index >= 0xc0 || acer_index == 0x20) && cpu_iscyrix)
return 0xff; /*Don't conflict with Cyrix config registers*/
return acer_regs[acer_index];
}
else
return acer_index;
}
void acer386sx_init()
{
io_sethandler(0x0022, 0x0002, acer386sx_read, NULL, NULL, acer386sx_write, NULL, NULL);
}

1
src/acer386sx.h Normal file
View file

@ -0,0 +1 @@
void acer386sx_init();

187
src/adlib.c Normal file
View file

@ -0,0 +1,187 @@
#include <stdint.h>
#include <stdlib.h>
#include "ibm.h"
#include "mame/fmopl.h"
#include "mame/ymf262.h"
/*Interfaces between PCem and the actual Adlib emulator*/
static int adlib_inited = 0;
int adlibpos=0;
void *YM3812[2];
void *YMF262;
int fm_timers[2][2],fm_timers_enable[2][2];
void adlib_write(uint16_t a, uint8_t v)
{
// printf("Adlib write %04X %02X %i\n",a,v,sbtype);
if (!sbtype) return;
if (sbtype<SBPRO && a<0x224) return;
switch (a)
{
case 0x220: case 0x221:
if (sbtype<SBPRO2) ym3812_write(YM3812[0],a,v);
else ymf262_write(YMF262,a,v);
break;
case 0x222: case 0x223:
if (sbtype<SBPRO2) ym3812_write(YM3812[1],a,v);
else ymf262_write(YMF262,a,v);
break;
case 0x228: case 0x229: case 0x388: case 0x389:
if (sbtype<SBPRO2)
{
ym3812_write(YM3812[0],a,v);
ym3812_write(YM3812[1],a,v);
}
else
ymf262_write(YMF262,a,v);
break;
}
}
uint8_t adlib_read(uint16_t a)
{
uint8_t temp;
// printf("Adlib read %04X\n",a);
if (sbtype>=SBPRO2)
{
switch (a)
{
case 0x220: case 0x221:
case 0x222: case 0x223:
case 0x228: case 0x229:
case 0x388: case 0x389:
temp=ymf262_read(YMF262,a);
// pclog("YMF262 read %03X %02X\n",a,temp);
cycles-=(int)(isa_timing * 8);
return temp;
}
}
if (!sbtype) return 0xFF;
switch (a)
{
case 0x220: case 0x221:
if (sbtype<SBPRO) return 0xFF;
case 0x228: case 0x229:
case 0x388: case 0x389:
cycles-=(int)(isa_timing * 8);
return ym3812_read(YM3812[0],a);
case 0x222: case 0x223:
if (sbtype<SBPRO) return 0xFF;
return ym3812_read(YM3812[1],a);
}
/* if (sbtype<SBPRO && a<0x224) return 0xFF;
if (a==0x222) return adlibstat2;
if (!(a&1)) return adlibstat;
return 0;*/
}
signed short *ad_bufs[4];
int16_t ad_filtbuf[2]={0,0};
void getadlib(signed short *bufl, signed short *bufr, int size)
{
int c;
if (sbtype>=SBPRO2)
{
ymf262_update_one(YMF262,ad_bufs,size);
for (c=0;c<size;c++)
{
ad_filtbuf[0]=bufl[c]=(ad_bufs[0][c]/4)+((ad_filtbuf[0]*11)/16);
ad_filtbuf[1]=bufr[c]=(ad_bufs[1][c]/4)+((ad_filtbuf[1]*11)/16);
}
if (fm_timers_enable[0][0])
{
fm_timers[0][0]--;
if (fm_timers[0][0]<0) ymf262_timer_over(YMF262,0);
}
if (fm_timers_enable[0][1])
{
fm_timers[0][1]--;
if (fm_timers[0][1]<0) ymf262_timer_over(YMF262,1);
}
}
else
{
ym3812_update_one(YM3812[0],bufl,size);
ym3812_update_one(YM3812[1],bufr,size);
for (c=0;c<size;c++)
{
ad_filtbuf[0]=bufl[c]=(bufl[c]/4)+((ad_filtbuf[0]*11)/16);
ad_filtbuf[1]=bufr[c]=(bufr[c]/4)+((ad_filtbuf[1]*11)/16);
}
if (fm_timers_enable[0][0])
{
fm_timers[0][0]--;
if (fm_timers[0][0]<0) ym3812_timer_over(YM3812[0],0);
}
if (fm_timers_enable[0][1])
{
fm_timers[0][1]--;
if (fm_timers[0][1]<0) ym3812_timer_over(YM3812[0],1);
}
if (fm_timers_enable[1][0])
{
fm_timers[1][0]--;
if (fm_timers[1][0]<0) ym3812_timer_over(YM3812[1],0);
}
if (fm_timers_enable[1][1])
{
fm_timers[1][1]--;
if (fm_timers[1][1]<0) ym3812_timer_over(YM3812[1],1);
}
}
// for (c=0;c<size;c++) buf[c]/=2;
}
void ym3812_timer_set_0(void *param,int timer,attotime period)
{
fm_timers[0][timer]=period/20833;
if (!fm_timers[0][timer]) fm_timers[0][timer]=1;
fm_timers_enable[0][timer]=(period)?1:0;
}
void ym3812_timer_set_1(void *param,int timer,attotime period)
{
fm_timers[1][timer]=period/20833;
if (!fm_timers[1][timer]) fm_timers[1][timer]=1;
fm_timers_enable[1][timer]=(period)?1:0;
}
void ymf262_timer_set(void *param,int timer,attotime period)
{
fm_timers[0][timer]=period/20833;
if (!fm_timers[0][timer]) fm_timers[0][timer]=1;
fm_timers_enable[0][timer]=(period)?1:0;
}
void adlib_init()
{
if (!adlib_inited)
{
ad_bufs[0]=(signed short *)malloc(48000);
ad_bufs[1]=(signed short *)malloc(48000);
ad_bufs[2]=(signed short *)malloc(48000);
ad_bufs[3]=(signed short *)malloc(48000);
YM3812[0]=ym3812_init((void *)NULL,3579545,48000);
ym3812_reset_chip(YM3812[0]);
ym3812_set_timer_handler(YM3812[0],ym3812_timer_set_0,NULL);
YM3812[1]=ym3812_init((void *)NULL,3579545,48000);
ym3812_reset_chip(YM3812[1]);
ym3812_set_timer_handler(YM3812[1],ym3812_timer_set_1,NULL);
YMF262=ymf262_init((void *)NULL,3579545*4,48000);
ymf262_reset_chip(YMF262);
ymf262_set_timer_handler(YMF262,ymf262_timer_set,NULL);
}
adlib_inited = 1;
io_sethandler(0x0388, 0x0002, adlib_read, NULL, NULL, adlib_write, NULL, NULL);
}
void adlib_reset()
{
ym3812_reset_chip(YM3812[0]);
ym3812_reset_chip(YM3812[1]);
ymf262_reset_chip(YMF262);
}

76
src/ali1429.c Normal file
View file

@ -0,0 +1,76 @@
#include <string.h>
#include "ibm.h"
#include "io.h"
#include "mem.h"
#include "cpu.h"
#include "ali1429.h"
static int ali1429_index;
static uint8_t ali1429_regs[256];
void ali1429_write(uint16_t port, uint8_t val)
{
// return;
if (!(port&1)) ali1429_index=val;
else
{
ali1429_regs[ali1429_index]=val;
// pclog("ALI1429 write %02X %02X %04X:%04X %i\n",ali1429_index,val,CS,pc,ins);
switch (ali1429_index)
{
case 0x13:
/* if (val == 1)
{
times = 1;
ins = 0;
output = 3;
}*/
// pclog("write 13 %02X %i\n",val,shadowbios);
if (!(val&0xC0))
{
shadowbios=0;
if (!shadowbios_write)
mem_sethandler(0xf0000, 0x10000, mem_read_bios, mem_read_biosw, mem_read_biosl, NULL, NULL, NULL );
else
mem_sethandler(0xf0000, 0x10000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_ram, mem_write_ramw, mem_write_raml);
flushmmucache();
}
break;
case 0x14:
shadowbios=val&1;//((val&3)==1);
shadowbios_write=val&2;
switch (val & 3)
{
case 0: mem_sethandler(0xf0000, 0x10000, mem_read_bios, mem_read_biosw, mem_read_biosl, NULL, NULL, NULL ); break;
case 1: mem_sethandler(0xf0000, 0x10000, mem_read_ram, mem_read_ramw, mem_read_raml, NULL, NULL, NULL ); break;
case 2: mem_sethandler(0xf0000, 0x10000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_ram, mem_write_ramw, mem_write_raml); break;
case 3: mem_sethandler(0xf0000, 0x10000, mem_read_ram, mem_read_ramw, mem_read_raml, mem_write_ram, mem_write_ramw, mem_write_raml); break;
}
// if (val==0x43) shadowbios=1;
// pclog("Shadow bios %i\n",shadowbios);
flushmmucache();
break;
}
}
}
uint8_t ali1429_read(uint16_t port)
{
if (!(port&1)) return ali1429_index;
if ((ali1429_index >= 0xc0 || ali1429_index == 0x20) && cpu_iscyrix)
return 0xff; /*Don't conflict with Cyrix config registers*/
return ali1429_regs[ali1429_index];
}
void ali1429_reset()
{
memset(ali1429_regs,0xFF,256);
}
void ali1429_init()
{
io_sethandler(0x0022, 0x0002, ali1429_read, NULL, NULL, ali1429_write, NULL, NULL);
}

1
src/ali1429.h Normal file
View file

@ -0,0 +1 @@
void ali1429_init();

84
src/amstrad.c Normal file
View file

@ -0,0 +1,84 @@
#include "ibm.h"
#include "io.h"
#include "keyboard.h"
#include "lpt.h"
#include "mouse.h"
#include "amstrad.h"
static uint8_t amstrad_dead;
uint8_t amstrad_read(uint16_t port)
{
pclog("amstrad_read : %04X\n",port);
switch (port)
{
case 0x379:
return 7 | readdacfifo();
case 0x37a:
if (romset == ROM_PC1512) return 0x20;
if (romset == ROM_PC200) return 0x80;
return 0;
case 0xdead:
return amstrad_dead;
}
return 0xff;
}
void amstrad_write(uint16_t port, uint8_t val)
{
switch (port)
{
case 0xdead:
amstrad_dead = val;
break;
}
}
static uint8_t mousex,mousey;
void amstrad_mouse_write(uint16_t addr, uint8_t val)
{
// pclog("Write mouse %04X %02X %04X:%04X\n", addr, val, CS, pc);
if (addr==0x78) mousex=0;
else mousey=0;
}
uint8_t amstrad_mouse_read(uint16_t addr)
{
uint8_t temp;
// printf("Read mouse %04X %04X:%04X %02X\n", addr, CS, pc, (addr == 0x78) ? mousex : mousey);
if (addr==0x78) return mousex;
return mousey;
}
static int oldb = 0;
void amstrad_mouse_poll(int x, int y, int b)
{
mousex += x;
mousey += y;
if ((b & 1) && !(oldb & 1))
keyboard_send(0x7e);
if ((b & 2) && !(oldb & 2))
keyboard_send(0x7d);
if (!(b & 1) && (oldb & 1))
keyboard_send(0xfe);
if (!(b & 2) && (oldb & 2))
keyboard_send(0xfd);
oldb = b;
}
void amstrad_init()
{
lpt2_remove();
io_sethandler(0x0078, 0x0001, amstrad_mouse_read, NULL, NULL, amstrad_mouse_write, NULL, NULL);
io_sethandler(0x007a, 0x0001, amstrad_mouse_read, NULL, NULL, amstrad_mouse_write, NULL, NULL);
io_sethandler(0x0379, 0x0002, amstrad_read, NULL, NULL, NULL, NULL, NULL);
io_sethandler(0xdead, 0x0001, amstrad_read, NULL, NULL, amstrad_write, NULL, NULL);
mouse_poll = amstrad_mouse_poll;
}

2
src/amstrad.h Normal file
View file

@ -0,0 +1,2 @@
void amstrad_init();

475
src/cdrom-ioctl.c Normal file
View file

@ -0,0 +1,475 @@
/*Win32 CD-ROM support via IOCTL*/
#include <windows.h>
#include <io.h>
#include "ddk/ntddcdrm.h"
//#include "ntddcdrm.h"
#include "ibm.h"
#include "ide.h"
#include "cdrom-ioctl.h"
int cdrom_drive;
typedef struct _CDROM_TOC_SESSION_DATA {
UCHAR Length[2];
UCHAR FirstCompleteSession;
UCHAR LastCompleteSession;
TRACK_DATA TrackData[1];
} CDROM_TOC_SESSION_DATA, *PCDROM_TOC_SESSION_DATA;
static ATAPI ioctl_atapi;
static int ioctl_inited = 0;
static char ioctl_path[8];
static void ioctl_close(void);
static HANDLE hIOCTL;
static CDROM_TOC toc;
static int tocvalid = 0;
#define MSFtoLBA(m,s,f) (((((m*60)+s)*75)+f)-150)
enum
{
CD_STOPPED = 0,
CD_PLAYING,
CD_PAUSED
};
static int ioctl_cd_state = CD_STOPPED;
static uint32_t ioctl_cd_pos = 0, ioctl_cd_end = 0;
#define BUF_SIZE 32768
static int16_t cd_buffer[BUF_SIZE];
static int cd_buflen = 0;
void ioctl_audio_callback(int16_t *output, int len)
{
RAW_READ_INFO in;
DWORD count;
int c;
// return;
// pclog("Audio callback %08X %08X %i %i %i %04X %i\n", ioctl_cd_pos, ioctl_cd_end, ioctl_cd_state, cd_buflen, len, cd_buffer[4], GetTickCount());
if (ioctl_cd_state != CD_PLAYING)
{
memset(output, 0, len * 2);
return;
}
while (cd_buflen < len)
{
if (ioctl_cd_pos < ioctl_cd_end)
{
in.DiskOffset.LowPart = ioctl_cd_pos * 2048;
in.DiskOffset.HighPart = 0;
in.SectorCount = 1;
in.TrackMode = CDDA;
ioctl_open(0);
// pclog("Read to %i\n", cd_buflen);
if (!DeviceIoControl(hIOCTL, IOCTL_CDROM_RAW_READ, &in, sizeof(in), &cd_buffer[cd_buflen], 2352, &count, NULL))
{
// pclog("DeviceIoControl returned false\n");
memset(&cd_buffer[cd_buflen], 0, (BUF_SIZE - cd_buflen) * 2);
ioctl_cd_state = CD_STOPPED;
cd_buflen = len;
}
else
{
// pclog("DeviceIoControl returned true\n");
ioctl_cd_pos++;
cd_buflen += (2352 / 2);
}
ioctl_close();
}
else
{
memset(&cd_buffer[cd_buflen], 0, (BUF_SIZE - cd_buflen) * 2);
ioctl_cd_state = CD_STOPPED;
cd_buflen = len;
}
}
memcpy(output, cd_buffer, len * 2);
// for (c = 0; c < BUF_SIZE - len; c++)
// cd_buffer[c] = cd_buffer[c + cd_buflen];
memcpy(&cd_buffer[0], &cd_buffer[len], (BUF_SIZE - len) * 2);
cd_buflen -= len;
// pclog("Done %i\n", GetTickCount());
}
void ioctl_audio_stop()
{
ioctl_cd_state = CD_STOPPED;
}
static void ioctl_playaudio(uint32_t pos, uint32_t len, int ismsf)
{
if (!cdrom_drive) return;
pclog("Play audio - %08X %08X %i\n", pos, len, ismsf);
if (ismsf)
{
pos = (pos & 0xff) + (((pos >> 8) & 0xff) * 75) + (((pos >> 16) & 0xff) * 75 * 60);
len = (len & 0xff) + (((len >> 8) & 0xff) * 75) + (((len >> 16) & 0xff) * 75 * 60);
pclog("MSF - pos = %08X len = %08X\n", pos, len);
}
else
len += pos;
ioctl_cd_pos = pos;// + 150;
ioctl_cd_end = len;// + 150;
ioctl_cd_state = CD_PLAYING;
pclog("Audio start %08X %08X %i %i %i\n", ioctl_cd_pos, ioctl_cd_end, ioctl_cd_state, cd_buflen, len);
/* CDROM_PLAY_AUDIO_MSF msf;
long size;
BOOL b;
if (ismsf)
{
msf.StartingF=pos&0xFF;
msf.StartingS=(pos>>8)&0xFF;
msf.StartingM=(pos>>16)&0xFF;
msf.EndingF=len&0xFF;
msf.EndingS=(len>>8)&0xFF;
msf.EndingM=(len>>16)&0xFF;
}
else
{
msf.StartingF=(uint8_t)(addr%75); addr/=75;
msf.StartingS=(uint8_t)(addr%60); addr/=60;
msf.StartingM=(uint8_t)(addr);
addr=pos+len+150;
msf.EndingF=(uint8_t)(addr%75); addr/=75;
msf.EndingS=(uint8_t)(addr%60); addr/=60;
msf.EndingM=(uint8_t)(addr);
}
ioctl_open(0);
b = DeviceIoControl(hIOCTL,IOCTL_CDROM_PLAY_AUDIO_MSF,&msf,sizeof(msf),NULL,0,&size,NULL);
pclog("DeviceIoControl returns %i\n", (int) b);
ioctl_close();*/
}
static void ioctl_pause(void)
{
long size;
if (!cdrom_drive) return;
if (ioctl_cd_state == CD_PLAYING)
ioctl_cd_state = CD_PAUSED;
// ioctl_open(0);
// DeviceIoControl(hIOCTL,IOCTL_CDROM_PAUSE_AUDIO,NULL,0,NULL,0,&size,NULL);
// ioctl_close();
}
static void ioctl_resume(void)
{
long size;
if (!cdrom_drive) return;
if (ioctl_cd_state == CD_PAUSED)
ioctl_cd_state = CD_PLAYING;
// ioctl_open(0);
// DeviceIoControl(hIOCTL,IOCTL_CDROM_RESUME_AUDIO,NULL,0,NULL,0,&size,NULL);
// ioctl_close();
}
static void ioctl_stop(void)
{
long size;
if (!cdrom_drive) return;
ioctl_cd_state = CD_STOPPED;
// ioctl_open(0);
// DeviceIoControl(hIOCTL,IOCTL_CDROM_STOP_AUDIO,NULL,0,NULL,0,&size,NULL);
// ioctl_close();
}
static void ioctl_seek(uint32_t pos)
{
long size;
if (!cdrom_drive) return;
// ioctl_cd_state = CD_STOPPED;
pclog("Seek %08X\n", pos);
ioctl_cd_pos = pos;
ioctl_cd_state = CD_STOPPED;
/* pos+=150;
CDROM_SEEK_AUDIO_MSF msf;
msf.F=(uint8_t)(pos%75); pos/=75;
msf.S=(uint8_t)(pos%60); pos/=60;
msf.M=(uint8_t)(pos);
// pclog("Seek to %02i:%02i:%02i\n",msf.M,msf.S,msf.F);
ioctl_open(0);
DeviceIoControl(hIOCTL,IOCTL_CDROM_SEEK_AUDIO_MSF,&msf,sizeof(msf),NULL,0,&size,NULL);
ioctl_close();*/
}
static int ioctl_ready(void)
{
long size;
int temp;
CDROM_TOC ltoc;
// pclog("Ready? %i\n",cdrom_drive);
if (!cdrom_drive) return 0;
ioctl_open(0);
temp=DeviceIoControl(hIOCTL,IOCTL_CDROM_READ_TOC, NULL,0,&ltoc,sizeof(ltoc),&size,NULL);
ioctl_close();
if ((ltoc.TrackData[ltoc.LastTrack].Address[1] != toc.TrackData[toc.LastTrack].Address[1]) ||
(ltoc.TrackData[ltoc.LastTrack].Address[2] != toc.TrackData[toc.LastTrack].Address[2]) ||
(ltoc.TrackData[ltoc.LastTrack].Address[3] != toc.TrackData[toc.LastTrack].Address[3]) ||
!tocvalid)
{
ioctl_cd_state = CD_STOPPED;
/* pclog("Not ready %02X %02X %02X %02X %02X %02X %i\n",ltoc.TrackData[ltoc.LastTrack].Address[1],ltoc.TrackData[ltoc.LastTrack].Address[2],ltoc.TrackData[ltoc.LastTrack].Address[3],
toc.TrackData[ltoc.LastTrack].Address[1], toc.TrackData[ltoc.LastTrack].Address[2], toc.TrackData[ltoc.LastTrack].Address[3],tocvalid);*/
// atapi_discchanged();
/* ioctl_open(0);
temp=DeviceIoControl(hIOCTL,IOCTL_CDROM_READ_TOC, NULL,0,&toc,sizeof(toc),&size,NULL);
ioctl_close();*/
toc=ltoc;
tocvalid=1;
return 0;
}
// pclog("IOCTL says ready\n");
return 1;
// return (temp)?1:0;
}
static uint8_t ioctl_getcurrentsubchannel(uint8_t *b, int msf)
{
CDROM_SUB_Q_DATA_FORMAT insub;
SUB_Q_CHANNEL_DATA sub;
long size;
int pos=0;
int c;
uint32_t temp, cdpos;
if (!cdrom_drive) return 0;
insub.Format = IOCTL_CDROM_CURRENT_POSITION;
ioctl_open(0);
DeviceIoControl(hIOCTL,IOCTL_CDROM_READ_Q_CHANNEL,&insub,sizeof(insub),&sub,sizeof(sub),&size,NULL);
ioctl_close();
b[pos++]=sub.CurrentPosition.Control;
b[pos++]=sub.CurrentPosition.TrackNumber;
b[pos++]=sub.CurrentPosition.IndexNumber;
/* pclog("Read subchannel %02X %02X %02X %02X%02X%02X%02X %02X%02X%02X%02X\n",sub.CurrentPosition.Control,sub.CurrentPosition.TrackNumber,sub.CurrentPosition.IndexNumber,
sub.CurrentPosition.AbsoluteAddress[0],sub.CurrentPosition.AbsoluteAddress[1],sub.CurrentPosition.AbsoluteAddress[2],sub.CurrentPosition.AbsoluteAddress[3],
sub.CurrentPosition.TrackRelativeAddress[0],sub.CurrentPosition.TrackRelativeAddress[1],sub.CurrentPosition.TrackRelativeAddress[2],sub.CurrentPosition.TrackRelativeAddress[3]);*/
cdpos = ioctl_cd_pos;
if (msf)
{
b[pos++] = (uint8_t)(cdpos % 75); cdpos /= 75;
b[pos++] = (uint8_t)(cdpos % 60); cdpos /= 60;
b[pos++] = (uint8_t)cdpos;
b[pos++] = 0;
b[pos++] = (uint8_t)(cdpos % 75); cdpos /= 75;
b[pos++] = (uint8_t)(cdpos % 60); cdpos /= 60;
b[pos++] = (uint8_t)cdpos;
b[pos++] = 0;
// for (c=0;c<4;c++) b[pos++]=sub.CurrentPosition.AbsoluteAddress[c];
// for (c=0;c<4;c++) b[pos++]=sub.CurrentPosition.TrackRelativeAddress[c];
}
else
{
b[pos++] = cdpos & 0xff;
b[pos++] = (cdpos >> 8) & 0xff;
b[pos++] = (cdpos >> 16) & 0xff;
b[pos++] = (cdpos >> 24) & 0xff;
b[pos++] = cdpos & 0xff;
b[pos++] = (cdpos >> 8) & 0xff;
b[pos++] = (cdpos >> 16) & 0xff;
b[pos++] = (cdpos >> 24) & 0xff;
/* temp=MSFtoLBA(sub.CurrentPosition.AbsoluteAddress[1],sub.CurrentPosition.AbsoluteAddress[2],sub.CurrentPosition.AbsoluteAddress[3]);
b[pos++]=temp>>24;
b[pos++]=temp>>16;
b[pos++]=temp>>8;
b[pos++]=temp;
temp=MSFtoLBA(sub.CurrentPosition.TrackRelativeAddress[1],sub.CurrentPosition.TrackRelativeAddress[2],sub.CurrentPosition.TrackRelativeAddress[3]);
b[pos++]=temp>>24;
b[pos++]=temp>>16;
b[pos++]=temp>>8;
b[pos++]=temp;*/
}
if (ioctl_cd_state == CD_PLAYING) return 0x11;
if (ioctl_cd_state == CD_PAUSED) return 0x12;
return 0x13;
// return sub.CurrentPosition.Header.AudioStatus;
}
static void ioctl_eject(void)
{
long size;
if (!cdrom_drive) return;
ioctl_cd_state = CD_STOPPED;
ioctl_open(0);
DeviceIoControl(hIOCTL,IOCTL_STORAGE_EJECT_MEDIA,NULL,0,NULL,0,&size,NULL);
ioctl_close();
}
static void ioctl_load(void)
{
long size;
if (!cdrom_drive) return;
ioctl_cd_state = CD_STOPPED;
ioctl_open(0);
DeviceIoControl(hIOCTL,IOCTL_STORAGE_LOAD_MEDIA,NULL,0,NULL,0,&size,NULL);
ioctl_close();
}
static void ioctl_readsector(uint8_t *b, int sector)
{
LARGE_INTEGER pos;
long size;
if (!cdrom_drive) return;
ioctl_cd_state = CD_STOPPED;
pos.QuadPart=sector*2048;
ioctl_open(0);
SetFilePointer(hIOCTL,pos.LowPart,&pos.HighPart,FILE_BEGIN);
ReadFile(hIOCTL,b,2048,&size,NULL);
ioctl_close();
}
static int ioctl_readtoc(unsigned char *b, unsigned char starttrack, int msf, int maxlen, int single)
{
int len=4;
long size;
int c,d;
uint32_t temp;
if (!cdrom_drive) return 0;
ioctl_cd_state = CD_STOPPED;
ioctl_open(0);
DeviceIoControl(hIOCTL,IOCTL_CDROM_READ_TOC, NULL,0,&toc,sizeof(toc),&size,NULL);
ioctl_close();
tocvalid=1;
// pclog("Read TOC done! %i\n",single);
b[2]=toc.FirstTrack;
b[3]=toc.LastTrack;
d=0;
for (c=0;c<=toc.LastTrack;c++)
{
if (toc.TrackData[c].TrackNumber>=starttrack)
{
d=c;
break;
}
}
b[2]=toc.TrackData[c].TrackNumber;
for (c=d;c<=toc.LastTrack;c++)
{
if ((len+8)>maxlen) break;
// pclog("Len %i max %i Track %02X - %02X %02X %i %i %i %i %08X\n",len,maxlen,toc.TrackData[c].TrackNumber,toc.TrackData[c].Adr,toc.TrackData[c].Control,toc.TrackData[c].Address[0],toc.TrackData[c].Address[1],toc.TrackData[c].Address[2],toc.TrackData[c].Address[3],MSFtoLBA(toc.TrackData[c].Address[1],toc.TrackData[c].Address[2],toc.TrackData[c].Address[3]));
b[len++]=0; /*Reserved*/
b[len++]=(toc.TrackData[c].Adr<<4)|toc.TrackData[c].Control;
b[len++]=toc.TrackData[c].TrackNumber;
b[len++]=0; /*Reserved*/
if (msf)
{
b[len++]=toc.TrackData[c].Address[0];
b[len++]=toc.TrackData[c].Address[1];
b[len++]=toc.TrackData[c].Address[2];
b[len++]=toc.TrackData[c].Address[3];
}
else
{
temp=MSFtoLBA(toc.TrackData[c].Address[1],toc.TrackData[c].Address[2],toc.TrackData[c].Address[3]);
b[len++]=temp>>24;
b[len++]=temp>>16;
b[len++]=temp>>8;
b[len++]=temp;
}
if (single) break;
}
b[0] = (uint8_t)(((len-2) >> 8) & 0xff);
b[1] = (uint8_t)((len-2) & 0xff);
/* pclog("Table of Contents (%i bytes) : \n",size);
pclog("First track - %02X\n",toc.FirstTrack);
pclog("Last track - %02X\n",toc.LastTrack);
for (c=0;c<=toc.LastTrack;c++)
pclog("Track %02X - number %02X control %02X adr %02X address %02X %02X %02X %02X\n",c,toc.TrackData[c].TrackNumber,toc.TrackData[c].Control,toc.TrackData[c].Adr,toc.TrackData[c].Address[0],toc.TrackData[c].Address[1],toc.TrackData[c].Address[2],toc.TrackData[c].Address[3]);
for (c=0;c<=toc.LastTrack;c++)
pclog("Track %02X - number %02X control %02X adr %02X address %06X\n",c,toc.TrackData[c].TrackNumber,toc.TrackData[c].Control,toc.TrackData[c].Adr,MSFtoLBA(toc.TrackData[c].Address[1],toc.TrackData[c].Address[2],toc.TrackData[c].Address[3]));*/
return len;
}
static void ioctl_readtoc_session(unsigned char *b, int msf, int maxlen)
{
int len=4;
int size;
uint32_t temp;
CDROM_READ_TOC_EX toc_ex;
CDROM_TOC_SESSION_DATA toc;
if (!cdrom_drive) return;
ioctl_cd_state = CD_STOPPED;
memset(&toc_ex,0,sizeof(toc_ex));
memset(&toc,0,sizeof(toc));
toc_ex.Format=CDROM_READ_TOC_EX_FORMAT_SESSION;
toc_ex.Msf=msf;
toc_ex.SessionTrack=0;
ioctl_open(0);
DeviceIoControl(hIOCTL,IOCTL_CDROM_READ_TOC_EX, &toc_ex,sizeof(toc_ex),&toc,sizeof(toc),(PDWORD)&size,NULL);
ioctl_close();
// pclog("Read TOC session - %i %02X %02X %i %i %02X %02X %02X\n",size,toc.Length[0],toc.Length[1],toc.FirstCompleteSession,toc.LastCompleteSession,toc.TrackData[0].Adr,toc.TrackData[0].Control,toc.TrackData[0].TrackNumber);
b[2]=toc.FirstCompleteSession;
b[3]=toc.LastCompleteSession;
b[len++]=0; /*Reserved*/
b[len++]=(toc.TrackData[0].Adr<<4)|toc.TrackData[0].Control;
b[len++]=toc.TrackData[0].TrackNumber;
b[len++]=0; /*Reserved*/
if (msf)
{
b[len++]=toc.TrackData[0].Address[0];
b[len++]=toc.TrackData[0].Address[1];
b[len++]=toc.TrackData[0].Address[2];
b[len++]=toc.TrackData[0].Address[3];
}
else
{
temp=MSFtoLBA(toc.TrackData[0].Address[1],toc.TrackData[0].Address[2],toc.TrackData[0].Address[3]);
b[len++]=temp>>24;
b[len++]=temp>>16;
b[len++]=temp>>8;
b[len++]=temp;
}
}
int ioctl_open(char d)
{
// char s[8];
if (!ioctl_inited)
{
sprintf(ioctl_path,"\\\\.\\%c:",d);
pclog("Path is %s\n",ioctl_path);
tocvalid=0;
}
// pclog("Opening %s\n",ioctl_path);
hIOCTL = CreateFile(/*"\\\\.\\g:"*/ioctl_path,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,0,NULL);
if (!hIOCTL)
{
//fatal("IOCTL");
}
atapi=&ioctl_atapi;
if (!ioctl_inited)
{
ioctl_inited=1;
CloseHandle(hIOCTL);
}
return 0;
}
static void ioctl_close(void)
{
CloseHandle(hIOCTL);
}
static void ioctl_exit(void)
{
ioctl_stop();
ioctl_inited=0;
tocvalid=0;
}
static ATAPI ioctl_atapi=
{
ioctl_ready,
ioctl_readtoc,
ioctl_readtoc_session,
ioctl_getcurrentsubchannel,
ioctl_readsector,
ioctl_playaudio,
ioctl_seek,
ioctl_load,
ioctl_eject,
ioctl_pause,
ioctl_resume,
ioctl_stop,
ioctl_exit
};

9
src/cdrom-ioctl.h Normal file
View file

@ -0,0 +1,9 @@
#ifndef CDROM_IOCTL_H
#define CDROM_IOCTL_H
/* this header file lists the functions provided by
various platform specific cdrom-ioctl files */
extern int ioctl_open(char d);
#endif /* ! CDROM_IOCTL_H */

141
src/cms.c Normal file
View file

@ -0,0 +1,141 @@
#include <stdio.h>
#include "ibm.h"
int cmsaddrs[2];
uint8_t cmsregs[2][32];
uint16_t cmslatch[12],cmsnoisefreq[12];
int cmsfreq[12];
float cmscount[12];
int cmsvol[12][2];
int cmsstat[12];
uint16_t cmsnoise[4];
int cmsnoisecount[4];
int cmsnoisetype[4];
#define CMSCONST (62500.0/44100.0)
void getcms(signed short *p, int size)
{
int c,d;
int ena[12],noiseena[12];
for (c=0;c<6;c++)
{
ena[c]=(cmsregs[0][0x14]&(1<<c));
ena[c+6]=(cmsregs[1][0x14]&(1<<c));
}
if (!(cmsregs[0][0x1C]&1))
{
for (c=0;c<6;c++) ena[c]=0;
}
if (!(cmsregs[1][0x1C]&1))
{
for (c=0;c<6;c++) ena[c+6]=0;
}
for (c=0;c<6;c++)
{
noiseena[c]=(cmsregs[0][0x15]&(1<<c));
noiseena[c+6]=(cmsregs[1][0x15]&(1<<c));
}
if (!(cmsregs[0][0x1C]&1))
{
for (c=0;c<6;c++) noiseena[c]=0;
}
if (!(cmsregs[1][0x1C]&1))
{
for (c=0;c<6;c++) noiseena[c+6]=0;
}
for (c=0;c<4;c++)
{
switch (cmsnoisetype[c])
{
case 0: cmsnoisefreq[c]=31250; break;
case 1: cmsnoisefreq[c]=15625; break;
case 2: cmsnoisefreq[c]=7812; break;
case 3: cmsnoisefreq[c]=cmsfreq[c*3]; break;
}
}
for (c=0;c<(size<<1);c+=2)
{
p[c]=0;
p[c+1]=0;
for (d=0;d<12;d++)
{
if (ena[d])
{
if (cmsstat[d]) p[c] +=(cmsvol[d][0]*90);
if (cmsstat[d]) p[c+1]+=(cmsvol[d][1]*90);
cmscount[d]+=cmsfreq[d];
if (cmscount[d]>=(22050))
{
cmscount[d]-=(22050);
cmsstat[d]^=1;
}
}
else if (noiseena[d])
{
if (cmsnoise[d/3]&1) p[c] +=(cmsvol[d][0]*90);
if (cmsnoise[d/3]&1) p[c+1]+=(cmsvol[d][0]*90);
}
}
for (d=0;d<4;d++)
{
cmsnoisecount[d]+=cmsnoisefreq[d];
while (cmsnoisecount[d]>=22050)
{
cmsnoisecount[d]-=22050;
cmsnoise[d]<<=1;
if (!(((cmsnoise[d]&0x4000)>>8)^(cmsnoise[d]&0x40))) cmsnoise[d]|=1;
}
}
}
}
void writecms(uint16_t addr, uint8_t val)
{
int voice;
int chip=(addr&2)>>1;
if (addr&1)
cmsaddrs[chip]=val&31;
else
{
cmsregs[chip][cmsaddrs[chip]&31]=val;
switch (cmsaddrs[chip]&31)
{
case 0x00: case 0x01: case 0x02: /*Volume*/
case 0x03: case 0x04: case 0x05:
voice=cmsaddrs[chip]&7;
if (chip) voice+=6;
cmsvol[voice][0]=val&0xF;//((val&0xF)+(val>>4))>>1;
cmsvol[voice][1]=val>>4;
break;
case 0x08: case 0x09: case 0x0A: /*Frequency*/
case 0x0B: case 0x0C: case 0x0D:
voice=cmsaddrs[chip]&7;
if (chip) voice+=6;
cmslatch[voice]=(cmslatch[voice]&0x700)|val;
cmsfreq[voice]=(15625<<(cmslatch[voice]>>8))/(511-(cmslatch[voice]&255));
break;
case 0x10: case 0x11: case 0x12: /*Octave*/
voice=(cmsaddrs[chip]&3)<<1;
if (chip) voice+=6;
cmslatch[voice]=(cmslatch[voice]&0xFF)|((val&7)<<8);
cmslatch[voice+1]=(cmslatch[voice+1]&0xFF)|((val&0x70)<<4);
cmsfreq[voice]=(15625<<(cmslatch[voice]>>8))/(511-(cmslatch[voice]&255));
cmsfreq[voice+1]=(15625<<(cmslatch[voice+1]>>8))/(511-(cmslatch[voice+1]&255));
break;
case 0x16: /*Noise*/
voice=chip*2;
cmsnoisetype[voice]=val&3;
cmsnoisetype[voice+1]=(val>>4)&3;
break;
}
}
}
uint8_t readcms(uint16_t addr)
{
int chip=(addr&2)>>1;
if (addr&1) return cmsaddrs[chip];
return cmsregs[chip][cmsaddrs[chip]&31];
}

166
src/config.c Normal file
View file

@ -0,0 +1,166 @@
#include <stdio.h>
#include <string.h>
#include "config.h"
static char config_file[256];
void set_config_file(char *s)
{
strcpy(config_file, s);
}
void config_new()
{
FILE *f = fopen(config_file, "wt");
fclose(f);
}
int get_config_int(char *head, char *name, int def)
{
char buffer[256];
char name2[256];
FILE *f = fopen(config_file, "rt");
int c, d;
int res = def;
if (!f)
return def;
pclog("Searching for %s\n", name);
while (1)
{
fgets(buffer, 255, f);
if (feof(f)) break;
c = d = 0;
while (buffer[c] == ' ' && buffer[c])
c++;
if (!buffer[c]) continue;
while (buffer[c] != '=' && buffer[c] != ' ' && buffer[c])
name2[d++] = buffer[c++];
if (!buffer[c]) continue;
name2[d] = 0;
pclog("Comparing %s and %s\n", name, name2);
if (strcmp(name, name2)) continue;
pclog("Found!\n");
while ((buffer[c] == '=' || buffer[c] == ' ') && buffer[c])
c++;
if (!buffer[c]) continue;
sscanf(&buffer[c], "%i", &res);
pclog("Reading value - %i\n", res);
break;
}
fclose(f);
return res;
}
char config_return_string[256];
char *get_config_string(char *head, char *name, char *def)
{
char buffer[256];
char name2[256];
FILE *f = fopen(config_file, "rt");
int c, d;
strcpy(config_return_string, def);
if (!f)
return config_return_string;
pclog("Searching for %s\n", name);
while (1)
{
fgets(buffer, 255, f);
if (feof(f)) break;
c = d = 0;
while (buffer[c] == ' ' && buffer[c])
c++;
if (!buffer[c]) continue;
while (buffer[c] != '=' && buffer[c] != ' ' && buffer[c])
name2[d++] = buffer[c++];
if (!buffer[c]) continue;
name2[d] = 0;
pclog("Comparing %s and %s\n", name, name2);
if (strcmp(name, name2)) continue;
pclog("Found!\n");
while ((buffer[c] == '=' || buffer[c] == ' ') && buffer[c])
c++;
if (!buffer[c]) continue;
strcpy(config_return_string, &buffer[c]);
c = strlen(config_return_string) - 1;
pclog("string len %i\n", c);
while (config_return_string[c] <= 32 && config_return_string[c])
config_return_string[c--] = 0;
pclog("Reading value - %s\n", config_return_string);
break;
}
fclose(f);
return config_return_string;
}
void set_config_int(char *head, char *name, int val)
{
FILE *f = fopen(config_file, "at");
if (!f) pclog("set_config_int - !f\n");
fprintf(f, "%s = %i\n", name, val);
pclog("Write %s = %i\n", name, val);
fclose(f);
pclog("fclose\n");
}
void set_config_string(char *head, char *name, char *val)
{
FILE *f = fopen(config_file, "at");
if (!f) pclog("set_config_string - !f\n");
fprintf(f, "%s = %s\n", name, val);
pclog("Write %s = %s\n", name, val);
fclose(f);
}
char *get_filename(char *s)
{
int c = strlen(s) - 1;
while (c > 0)
{
if (s[c] == '/' || s[c] == '\\')
return &s[c+1];
c--;
}
return s;
}
void append_filename(char *dest, char *s1, char *s2, int size)
{
sprintf(dest, "%s%s", s1, s2);
}
void put_backslash(char *s)
{
int c = strlen(s) - 1;
if (s[c] != '/' && s[c] != '\\')
s[c] = '/';
}

5
src/config.h Normal file
View file

@ -0,0 +1,5 @@
void set_config_file(char *s);
int get_config_int(char *head, char *name, int def);
char *get_config_string(char *head, char *name, char *def);
void set_config_int(char *head, char *name, int val);
void set_config_string(char *head, char *name, char *val);

411
src/cpu.c Normal file
View file

@ -0,0 +1,411 @@
#include "ibm.h"
#include "cpu.h"
#include "model.h"
#include "io.h"
int cpu = 3, cpu_manufacturer = 0;
CPU *cpu_s;
int cpu_multi;
int cpu_iscyrix;
int cpu_16bitbus;
int cpu_busspeed;
int timing_rr;
int timing_mr, timing_mrl;
int timing_rm, timing_rml;
int timing_mm, timing_mml;
int timing_bt, timing_bnt;
/*Available cpuspeeds :
0 = 16 MHz
1 = 20 MHz
2 = 25 MHz
3 = 33 MHz
4 = 40 MHz
5 = 50 MHz
6 = 66 MHz
7 = 75 MHz
8 = 80 MHz
9 = 90 MHz
10 = 100 MHz
11 = 120 MHz
12 = 133 MHz
13 = 150 MHz
14 = 160 MHz
*/
CPU cpus_8088[] =
{
/*8088 standard*/
{"8088/4.77", CPU_8088, 0, 4772727, 1, 0, 0, 0},
{"8088/8", CPU_8088, 1, 8000000, 1, 0, 0, 0},
{"8088/10", CPU_8088, 2, 10000000, 1, 0, 0, 0},
{"8088/12", CPU_8088, 3, 12000000, 1, 0, 0, 0},
{"8088/16", CPU_8088, 4, 16000000, 1, 0, 0, 0},
{"", -1, 0, 0, 0, 0}
};
CPU cpus_8086[] =
{
/*8086 standard*/
{"8086/7.16", CPU_8086, 1, 3579545*2, 1, 0, 0, 0},
{"8086/8", CPU_8086, 1, 8000000, 1, 0, 0, 0},
{"8086/9.54", CPU_8086, 1, (3579545*8)/3, 1, 0, 0, 0},
{"8086/10", CPU_8086, 2, 10000000, 1, 0, 0, 0},
{"8086/12", CPU_8086, 3, 12000000, 1, 0, 0, 0},
{"8086/16", CPU_8086, 4, 16000000, 1, 0, 0, 0},
{"", -1, 0, 0, 0, 0}
};
CPU cpus_pc1512[] =
{
/*8086 Amstrad*/
{"8086/8", CPU_8086, 1, 8000000, 1, 0, 0, 0},
{"", -1, 0, 0, 0, 0}
};
CPU cpus_286[] =
{
/*286*/
{"286/6", CPU_286, 0, 6000000, 1, 0, 0, 0},
{"286/8", CPU_286, 1, 8000000, 1, 0, 0, 0},
{"286/10", CPU_286, 2, 10000000, 1, 0, 0, 0},
{"286/12", CPU_286, 3, 12000000, 1, 0, 0, 0},
{"286/16", CPU_286, 4, 16000000, 1, 0, 0, 0},
{"286/20", CPU_286, 5, 20000000, 1, 0, 0, 0},
{"286/25", CPU_286, 6, 25000000, 1, 0, 0, 0},
{"", -1, 0, 0, 0, 0}
};
CPU cpus_ibmat[] =
{
/*286*/
{"286/6", CPU_286, 0, 6000000, 1, 0, 0, 0},
{"", -1, 0, 0, 0, 0}
};
CPU cpus_i386[] =
{
/*i386*/
{"i386SX/16", CPU_386SX, 0, 16000000, 1, 0x2308, 0, 0},
{"i386SX/20", CPU_386SX, 1, 20000000, 1, 0x2308, 0, 0},
{"i386SX/25", CPU_386SX, 2, 25000000, 1, 0x2308, 0, 0},
{"i386SX/33", CPU_386SX, 3, 33333333, 1, 0x2308, 0, 0},
{"i386DX/16", CPU_386DX, 0, 16000000, 1, 0x0308, 0, 0},
{"i386DX/20", CPU_386DX, 1, 20000000, 1, 0x0308, 0, 0},
{"i386DX/25", CPU_386DX, 2, 25000000, 1, 0x0308, 0, 0},
{"i386DX/33", CPU_386DX, 3, 33333333, 1, 0x0308, 0, 0},
{"", -1, 0, 0, 0}
};
CPU cpus_acer[] =
{
/*i386*/
{"i386SX/25", CPU_386SX, 2, 25000000, 1, 0x2308, 0, 0},
{"", -1, 0, 0, 0}
};
CPU cpus_Am386[] =
{
/*Am386*/
{"Am386SX/16", CPU_386SX, 0, 16000000, 1, 0x2308, 0, 0},
{"Am386SX/20", CPU_386SX, 1, 20000000, 1, 0x2308, 0, 0},
{"Am386SX/25", CPU_386SX, 2, 25000000, 1, 0x2308, 0, 0},
{"Am386SX/33", CPU_386SX, 3, 33333333, 1, 0x2308, 0, 0},
{"Am386SX/40", CPU_386SX, 4, 40000000, 1, 0x2308, 0, 0},
{"Am386DX/25", CPU_386DX, 2, 25000000, 1, 0x0308, 0, 0},
{"Am386DX/33", CPU_386DX, 3, 33333333, 1, 0x0308, 0, 0},
{"Am386DX/40", CPU_386DX, 4, 40000000, 1, 0x0308, 0, 0},
{"", -1, 0, 0, 0}
};
CPU cpus_486SDLC[] =
{
/*Cx486SLC/DLC*/
{"Cx486SLC/20", CPU_486SLC, 1, 20000000, 1, 0, 0, 0x0000},
{"Cx486SLC/25", CPU_486SLC, 2, 25000000, 1, 0, 0, 0x0000},
{"Cx486SLC/33", CPU_486SLC, 3, 33333333, 1, 0, 0, 0x0000},
{"Cx486SRx2/32", CPU_486SLC, 3, 32000000, 2, 0, 0, 0x0006},
{"Cx486SRx2/40", CPU_486SLC, 4, 40000000, 2, 0, 0, 0x0006},
{"Cx486SRx2/50", CPU_486SLC, 5, 50000000, 2, 0, 0, 0x0006},
{"Cx486DLC/25", CPU_486DLC, 2, 25000000, 1, 0, 0, 0x0001},
{"Cx486DLC/33", CPU_486DLC, 3, 33333333, 1, 0, 0, 0x0001},
{"Cx486DLC/40", CPU_486DLC, 4, 40000000, 1, 0, 0, 0x0001},
{"Cx486DRx2/32", CPU_486DLC, 3, 32000000, 2, 0, 0, 0x0007},
{"Cx486DRx2/40", CPU_486DLC, 4, 40000000, 2, 0, 0, 0x0007},
{"Cx486DRx2/50", CPU_486DLC, 5, 50000000, 2, 0, 0, 0x0007},
{"Cx486DRx2/66", CPU_486DLC, 6, 66666666, 2, 0, 0, 0x0007},
{"", -1, 0, 0, 0}
};
CPU cpus_i486[] =
{
/*i486*/
{"i486SX/16", CPU_i486SX, 0, 16000000, 1, 0x42a, 0, 0},
{"i486SX/20", CPU_i486SX, 1, 20000000, 1, 0x42a, 0, 0},
{"i486SX/25", CPU_i486SX, 2, 25000000, 1, 0x42a, 0, 0},
{"i486SX/33", CPU_i486SX, 3, 33333333, 1, 0x42a, 0, 0},
{"i486SX2/50", CPU_i486SX, 5, 50000000, 2, 0x45b, 0, 0},
{"i486DX/25", CPU_i486DX, 2, 25000000, 1, 0x404, 0, 0},
{"i486DX/33", CPU_i486DX, 3, 33333333, 1, 0x404, 0, 0},
{"i486DX/50", CPU_i486DX, 5, 50000000, 1, 0x404, 0, 0},
{"i486DX2/40", CPU_i486DX, 4, 40000000, 2, 0x430, 0, 0},
{"i486DX2/50", CPU_i486DX, 5, 50000000, 2, 0x430, 0, 0},
{"i486DX2/66", CPU_i486DX, 6, 66666666, 2, 0x430, 0, 0},
{"iDX4/75", CPU_i486DX, 7, 75000000, 3, 0x481, 0x481, 0}, /*CPUID available on DX4, >= 75 MHz*/
{"iDX4/100", CPU_i486DX,10, 100000000, 3, 0x481, 0x481, 0}, /*Is on some real Intel DX2s, limit here is pretty arbitary*/
{"", -1, 0, 0, 0}
};
CPU cpus_Am486[] =
{
/*Am486/5x86*/
{"Am486SX/33", CPU_Am486SX, 3, 33333333, 1, 0x42a, 0, 0},
{"Am486SX/40", CPU_Am486SX, 4, 40000000, 1, 0x42a, 0, 0},
{"Am486SX2/50", CPU_Am486SX, 5, 50000000, 2, 0x45b, 0x45b, 0}, /*CPUID available on SX2, DX2, DX4, 5x86, >= 50 MHz*/
{"Am486SX2/66", CPU_Am486SX, 6, 66666666, 2, 0x45b, 0x45b, 0}, /*Isn't on all real AMD SX2s and DX2s, availability here is pretty arbitary (and distinguishes them from the Intel chips)*/
{"Am486DX/33", CPU_Am486DX, 3, 33333333, 1, 0x430, 0, 0},
{"Am486DX/40", CPU_Am486DX, 4, 40000000, 1, 0x430, 0, 0},
{"Am486DX2/50", CPU_Am486DX, 5, 50000000, 2, 0x470, 0x470, 0},
{"Am486DX2/66", CPU_Am486DX, 6, 66666666, 2, 0x470, 0x470, 0},
{"Am486DX2/80", CPU_Am486DX, 8, 80000000, 2, 0x470, 0x470, 0},
{"Am486DX4/75", CPU_Am486DX, 7, 75000000, 3, 0x482, 0x482, 0},
{"Am486DX4/90", CPU_Am486DX, 9, 90000000, 3, 0x482, 0x482, 0},
{"Am486DX4/100", CPU_Am486DX, 10, 100000000, 3, 0x482, 0x482, 0},
{"Am486DX4/120", CPU_Am486DX, 11, 120000000, 3, 0x482, 0x482, 0},
{"Am5x86/P75", CPU_Am486DX, 12, 133333333, 4, 0x4e0, 0x4e0, 0},
{"Am5x86/P75+", CPU_Am486DX, 13, 150000000, 4, 0x4e0, 0x4e0, 0},
{"", -1, 0, 0, 0}
};
CPU cpus_Cx486[] =
{
/*Cx486/5x86*/
{"Cx486S/25", CPU_Cx486S, 2, 25000000, 1, 0x420, 0, 0x0010},
{"Cx486S/33", CPU_Cx486S, 3, 33333333, 1, 0x420, 0, 0x0010},
{"Cx486S/40", CPU_Cx486S, 4, 40000000, 1, 0x420, 0, 0x0010},
{"Cx486DX/33", CPU_Cx486DX, 3, 33333333, 1, 0x430, 0, 0x051a},
{"Cx486DX/40", CPU_Cx486DX, 4, 40000000, 1, 0x430, 0, 0x051a},
{"Cx486DX2/50", CPU_Cx486DX, 5, 50000000, 2, 0x430, 0, 0x081b},
{"Cx486DX2/66", CPU_Cx486DX, 6, 66666666, 2, 0x430, 0, 0x0b1b},
{"Cx486DX2/80", CPU_Cx486DX, 8, 80000000, 2, 0x430, 0, 0x311b},
{"Cx486DX4/75", CPU_Cx486DX, 7, 75000000, 3, 0x480, 0, 0x361f},
{"Cx486DX4/100", CPU_Cx486DX, 10, 100000000, 3, 0x480, 0, 0x361f},
{"Cx5x86/100", CPU_Cx5x86, 10, 100000000, 3, 0x480, 0, 0x002f},
{"Cx5x86/120", CPU_Cx5x86, 11, 120000000, 3, 0x480, 0, 0x002f},
{"Cx5x86/133", CPU_Cx5x86, 12, 133333333, 4, 0x480, 0, 0x002f},
{"", -1, 0, 0, 0}
};
void cpu_set_edx()
{
EDX = models[model].cpu[cpu_manufacturer].cpus[cpu].edx_reset;
}
void cpu_set()
{
CPU *cpu_s = &models[model].cpu[cpu_manufacturer].cpus[cpu];
CPUID = cpu_s->cpuid_model;
cpuspeed = cpu_s->speed;
is8086 = (cpu_s->cpu_type >= CPU_8088);
is486 = (cpu_s->cpu_type >= CPU_i486SX) || (cpu_s->cpu_type == CPU_486SLC || cpu_s->cpu_type == CPU_486DLC);
hasfpu = (cpu_s->cpu_type >= CPU_i486DX);
cpu_iscyrix = (cpu_s->cpu_type == CPU_486SLC || cpu_s->cpu_type == CPU_486DLC || cpu_s->cpu_type == CPU_Cx486S || cpu_s->cpu_type == CPU_Cx486DX || cpu_s->cpu_type == CPU_Cx5x86);
cpu_16bitbus = (cpu_s->cpu_type == CPU_386SX || cpu_s->cpu_type == CPU_486SLC);
if (cpu_s->multi)
cpu_busspeed = cpu_s->rspeed / cpu_s->multi;
cpu_multi = cpu_s->multi;
if (cpu_iscyrix)
io_sethandler(0x0022, 0x0002, cyrix_read, NULL, NULL, cyrix_write, NULL, NULL);
else
io_removehandler(0x0022, 0x0002, cyrix_read, NULL, NULL, cyrix_write, NULL, NULL);
pclog("hasfpu - %i\n",hasfpu);
pclog("is486 - %i %i\n",is486,cpu_s->cpu_type);
switch (cpu_s->cpu_type)
{
case CPU_386SX:
timing_rr = 2; /*register dest - register src*/
timing_rm = 6; /*register dest - memory src*/
timing_mr = 7; /*memory dest - register src*/
timing_mm = 6; /*memory dest - memory src*/
timing_rml = 8; /*register dest - memory src long*/
timing_mrl = 11; /*memory dest - register src long*/
timing_mml = 10; /*memory dest - memory src*/
timing_bt = 7-3; /*branch taken*/
timing_bnt = 3; /*branch not taken*/
break;
case CPU_386DX:
timing_rr = 2; /*register dest - register src*/
timing_rm = 6; /*register dest - memory src*/
timing_mr = 7; /*memory dest - register src*/
timing_mm = 6; /*memory dest - memory src*/
timing_rml = 6; /*register dest - memory src long*/
timing_mrl = 7; /*memory dest - register src long*/
timing_mml = 6; /*memory dest - memory src*/
timing_bt = 7-3; /*branch taken*/
timing_bnt = 3; /*branch not taken*/
break;
case CPU_486SLC:
timing_rr = 1; /*register dest - register src*/
timing_rm = 3; /*register dest - memory src*/
timing_mr = 5; /*memory dest - register src*/
timing_mm = 3;
timing_rml = 5; /*register dest - memory src long*/
timing_mrl = 7; /*memory dest - register src long*/
timing_mml = 7;
timing_bt = 6-1; /*branch taken*/
timing_bnt = 1; /*branch not taken*/
break;
case CPU_486DLC:
timing_rr = 1; /*register dest - register src*/
timing_rm = 3; /*register dest - memory src*/
timing_mr = 3; /*memory dest - register src*/
timing_mm = 3;
timing_rml = 3; /*register dest - memory src long*/
timing_mrl = 3; /*memory dest - register src long*/
timing_mml = 3;
timing_bt = 6-1; /*branch taken*/
timing_bnt = 1; /*branch not taken*/
break;
case CPU_i486SX:
case CPU_i486DX:
timing_rr = 1; /*register dest - register src*/
timing_rm = 2; /*register dest - memory src*/
timing_mr = 3; /*memory dest - register src*/
timing_mm = 3;
timing_rml = 2; /*register dest - memory src long*/
timing_mrl = 3; /*memory dest - register src long*/
timing_mml = 3;
timing_bt = 3-1; /*branch taken*/
timing_bnt = 1; /*branch not taken*/
break;
case CPU_Am486SX:
case CPU_Am486DX:
/*AMD timing identical to Intel*/
timing_rr = 1; /*register dest - register src*/
timing_rm = 2; /*register dest - memory src*/
timing_mr = 3; /*memory dest - register src*/
timing_mm = 3;
timing_rml = 2; /*register dest - memory src long*/
timing_mrl = 3; /*memory dest - register src long*/
timing_mml = 3;
timing_bt = 3-1; /*branch taken*/
timing_bnt = 1; /*branch not taken*/
break;
case CPU_Cx486S:
case CPU_Cx486DX:
timing_rr = 1; /*register dest - register src*/
timing_rm = 3; /*register dest - memory src*/
timing_mr = 3; /*memory dest - register src*/
timing_mm = 3;
timing_rml = 3; /*register dest - memory src long*/
timing_mrl = 3; /*memory dest - register src long*/
timing_mml = 3;
timing_bt = 4-1; /*branch taken*/
timing_bnt = 1; /*branch not taken*/
break;
case CPU_Cx5x86:
timing_rr = 1; /*register dest - register src*/
timing_rm = 1; /*register dest - memory src*/
timing_mr = 2; /*memory dest - register src*/
timing_mm = 2;
timing_rml = 1; /*register dest - memory src long*/
timing_mrl = 2; /*memory dest - register src long*/
timing_mml = 2;
timing_bt = 5-1; /*branch taken*/
timing_bnt = 1; /*branch not taken*/
break;
}
}
void cpu_CPUID()
{
switch (models[model].cpu[cpu_manufacturer].cpus[cpu].cpu_type)
{
case CPU_i486DX:
if (!EAX)
{
EAX = 0x00000001;
EBX = 0x756e6547;
EDX = 0x49656e69;
ECX = 0x6c65746e;
}
else if (EAX == 1)
{
EAX = CPUID;
EBX = ECX = 0;
EDX = 1; /*FPU*/
}
else
EAX = 0;
break;
case CPU_Am486SX:
if (!EAX)
{
EBX = 0x68747541;
ECX = 0x444D4163;
EDX = 0x69746E65;
}
else if (EAX == 1)
{
EAX = CPUID;
EBX = ECX = EDX = 0; /*No FPU*/
}
else
EAX = 0;
break;
case CPU_Am486DX:
if (!EAX)
{
EBX = 0x68747541;
ECX = 0x444D4163;
EDX = 0x69746E65;
}
else if (EAX == 1)
{
EAX = CPUID;
EBX = ECX = 0;
EDX = 1; /*FPU*/
}
else
EAX = 0;
break;
}
}
static int cyrix_addr;
void cyrix_write(uint16_t addr, uint8_t val)
{
if (!(addr & 1)) cyrix_addr = val;
// else pclog("Write Cyrix %02X %02X\n",cyrix_addr,val);
}
uint8_t cyrix_read(uint16_t addr)
{
if (addr & 1)
{
switch (cyrix_addr)
{
case 0xfe: return models[model].cpu[cpu_manufacturer].cpus[cpu].cyrix_id & 0xff;
case 0xff: return models[model].cpu[cpu_manufacturer].cpus[cpu].cyrix_id >> 8;
}
if ((cyrix_addr & ~0xf0) == 0xc0) return 0xff;
if (cyrix_addr == 0x20 && models[model].cpu[cpu_manufacturer].cpus[cpu].cpu_type == CPU_Cx5x86) return 0xff;
}
return 0xff;
}

71
src/cpu.h Normal file
View file

@ -0,0 +1,71 @@
extern int cpu, cpu_manufacturer;
/*808x class CPUs*/
#define CPU_8088 0
#define CPU_8086 1
/*286 class CPUs*/
#define CPU_286 2
/*386 class CPUs*/
#define CPU_386SX 3
#define CPU_386DX 4
#define CPU_486SLC 5
#define CPU_486DLC 6
/*486 class CPUs*/
#define CPU_i486SX 7
#define CPU_Am486SX 8
#define CPU_Cx486S 9
#define CPU_i486DX 10
#define CPU_Am486DX 11
#define CPU_Cx486DX 12
#define CPU_Cx5x86 13
#define MANU_INTEL 0
#define MANU_AMD 1
#define MANU_CYRIX 2
extern int timing_rr;
extern int timing_mr, timing_mrl;
extern int timing_rm, timing_rml;
extern int timing_mm, timing_mml;
extern int timing_bt, timing_bnt;
typedef struct
{
char name[16];
int cpu_type;
int speed;
int rspeed;
int multi;
uint32_t edx_reset;
uint32_t cpuid_model;
uint16_t cyrix_id;
} CPU;
extern CPU cpus_8088[];
extern CPU cpus_8086[];
extern CPU cpus_286[];
extern CPU cpus_i386[];
extern CPU cpus_Am386[];
extern CPU cpus_486SDLC[];
extern CPU cpus_i486[];
extern CPU cpus_Am486[];
extern CPU cpus_Cx486[];
extern CPU cpus_pc1512[];
extern CPU cpus_ibmat[];
extern CPU cpus_acer[];
extern int cpu_iscyrix;
extern int cpu_16bitbus;
extern int cpu_busspeed;
extern int cpu_multi;
void cyrix_write(uint16_t addr, uint8_t val);
uint8_t cyrix_read(uint16_t addr);
extern int is8086;

68
src/dac.c Normal file
View file

@ -0,0 +1,68 @@
#include "ibm.h"
uint8_t dac,dac2;
uint8_t dacctrl;
int lptfifo;
uint8_t dssbuffer[16];
int dssstart=0,dssend=0;
int dssmode=0;
void writedac(uint16_t addr, uint8_t val)
{
if (dssmode) dac2=val;
else dac=val;
}
void writedacctrl(uint16_t addr, uint8_t val)
{
// printf("Write DAC ctrl %02X %i\n",val,lptfifo);
if (dacctrl&8 && !(val&8) && (lptfifo!=16))
{
// dac=dac2;
dssbuffer[dssend++]=dac2;
dssend&=15;
lptfifo++;
}
dacctrl=val;
}
uint8_t readdacfifo()
{
if (lptfifo==16) return 0x40;
return 0;
}
void pollss()
{
if (lptfifo)
{
dac=dssbuffer[dssstart++];
dssstart&=15;
lptfifo--;
}
}
int16_t dacbuffer[SOUNDBUFLEN+20];
int dacbufferpos=0;
void getdacsamp()
{
if (dacbufferpos<SOUNDBUFLEN+20) dacbuffer[dacbufferpos++]=(((int)(unsigned int)dac)-0x80)*0x20;
}
void adddac(int16_t *p)
{
int c;
if (dacbufferpos>SOUNDBUFLEN) dacbufferpos=SOUNDBUFLEN;
for (c=0;c<dacbufferpos;c++)
{
p[c<<1]+=(dacbuffer[c]);
p[(c<<1)+1]+=(dacbuffer[c]);
}
for (;c<SOUNDBUFLEN;c++)
{
p[c<<1]+=(dacbuffer[dacbufferpos-1]);
p[(c<<1)+1]+=(dacbuffer[dacbufferpos-1]);
}
dacbufferpos=0;
}

490
src/dma.c Normal file
View file

@ -0,0 +1,490 @@
#include "ibm.h"
#include "video.h"
#include "io.h"
#include "dma.h"
extern int ins;
int output;
uint8_t dmaregs[16];
int dmaon[4];
uint8_t dma16regs[16];
int dma16on[4];
void dma_reset()
{
int c;
dma.wp=0;
for (c=0;c<16;c++) dmaregs[c]=0;
for (c=0;c<4;c++)
{
dma.mode[c]=0;
dma.ac[c]=0;
dma.cc[c]=0;
dma.ab[c]=0;
dma.cb[c]=0;
}
dma.m=0;
dma16.wp=0;
for (c=0;c<16;c++) dma16regs[c]=0;
for (c=0;c<4;c++)
{
dma16.mode[c]=0;
dma16.ac[c]=0;
dma16.cc[c]=0;
dma16.ab[c]=0;
dma16.cb[c]=0;
}
dma16.m=0;
}
uint8_t dma_read(uint16_t addr)
{
uint8_t temp;
// printf("Read DMA %04X %04X:%04X\n",addr,cs>>4,pc);
switch (addr&0xF)
{
case 0:
/* if (((dma.mode[0]>>2)&3)==2)
{
dma.ac[0]++;
dma.cc[0]--;
if (dma.cc[0]<0)
{
dma.ac[0]=dma.ab[0];
dma.cc[0]=dma.cb[0];
}
}*/
case 2: case 4: case 6: /*Address registers*/
dma.wp^=1;
if (dma.wp) return dma.ac[(addr>>1)&3]&0xFF;
return dma.ac[(addr>>1)&3]>>8;
case 1: case 3: case 5: case 7: /*Count registers*/
// printf("DMA count %i = %04X\n", (addr>>1)&3, dma.cc[(addr>>1)&3]);
dma.wp^=1;
if (dma.wp) temp=dma.cc[(addr>>1)&3]&0xFF;
else temp=dma.cc[(addr>>1)&3]>>8;
// printf("%02X\n",temp);
return temp;
case 8: /*Status register*/
temp=dma.stat;
dma.stat=0;
return temp|1;
case 0xD:
return 0;
}
// printf("Bad DMA read %04X %04X:%04X\n",addr,CS,pc);
return dmaregs[addr&0xF];
}
void dma_write(uint16_t addr, uint8_t val)
{
// printf("Write DMA %04X %02X %04X:%04X\n",addr,val,CS,pc);
dmaregs[addr&0xF]=val;
switch (addr&0xF)
{
case 0: case 2: case 4: case 6: /*Address registers*/
dma.wp^=1;
if (dma.wp) dma.ab[(addr>>1)&3]=(dma.ab[(addr>>1)&3]&0xFF00)|val;
else dma.ab[(addr>>1)&3]=(dma.ab[(addr>>1)&3]&0xFF)|(val<<8);
dma.ac[(addr>>1)&3]=dma.ab[(addr>>1)&3];
dmaon[(addr>>1)&3]=1;
// printf("DMA addr %i now %04X\n",(addr>>1)&3,dma.ac[(addr>>1)&3]);
return;
case 1: case 3: case 5: case 7: /*Count registers*/
dma.wp^=1;
if (dma.wp) dma.cb[(addr>>1)&3]=(dma.cb[(addr>>1)&3]&0xFF00)|val;
else dma.cb[(addr>>1)&3]=(dma.cb[(addr>>1)&3]&0xFF)|(val<<8);
dma.cc[(addr>>1)&3]=dma.cb[(addr>>1)&3];
dmaon[(addr>>1)&3]=1;
// printf("DMA count %i now %04X\n",(addr>>1)&3,dma.cc[(addr>>1)&3]);
return;
case 8: /*Control register*/
dma.command = val;
return;
case 0xA: /*Mask*/
if (val&4) dma.m|=(1<<(val&3));
else dma.m&=~(1<<(val&3));
return;
case 0xB: /*Mode*/
dma.mode[val&3]=val;
return;
case 0xC: /*Clear FF*/
dma.wp=0;
return;
case 0xD: /*Master clear*/
dma.wp=0;
dma.m=0xF;
return;
case 0xF: /*Mask write*/
dma.m=val&0xF;
return;
}
}
uint8_t dma16_read(uint16_t addr)
{
uint8_t temp;
// printf("Read DMA %04X %04X:%04X\n",addr,cs>>4,pc);
addr>>=1;
switch (addr&0xF)
{
case 0:
if (((dma16.mode[0]>>2)&3)==2)
{
dma16.ac[0]++;
dma16.cc[0]--;
if (dma16.cc[0]<0)
{
dma16.ac[0]=dma16.ab[0];
dma16.cc[0]=dma16.cb[0];
}
}
case 2: case 4: case 6: /*Address registers*/
dma16.wp^=1;
if (dma16.wp) return dma16.ac[(addr>>1)&3]&0xFF;
return dma16.ac[(addr>>1)&3]>>8;
case 1: case 3: case 5: case 7: /*Count registers*/
dma16.wp^=1;
// printf("Read %04X\n",dma16.cc[1]);
if (dma16.wp) temp=dma16.cc[(addr>>1)&3]&0xFF;
else temp=dma16.cc[(addr>>1)&3]>>8;
// printf("%02X\n",temp);
return temp;
case 8: /*Status register*/
temp=dma16.stat;
dma16.stat=0;
return temp|1;
}
return dma16regs[addr&0xF];
}
void dma16_write(uint16_t addr, uint8_t val)
{
// printf("Write dma16 %04X %02X %04X:%04X\n",addr,val,CS,pc);
addr>>=1;
dma16regs[addr&0xF]=val;
switch (addr&0xF)
{
case 0: case 2: case 4: case 6: /*Address registers*/
dma16.wp^=1;
if (dma16.wp) dma16.ab[(addr>>1)&3]=(dma16.ab[(addr>>1)&3]&0xFF00)|val;
else dma16.ab[(addr>>1)&3]=(dma16.ab[(addr>>1)&3]&0xFF)|(val<<8);
dma16.ac[(addr>>1)&3]=dma16.ab[(addr>>1)&3];
dma16on[(addr>>1)&3]=1;
// printf("dma16 addr %i now %04X\n",(addr>>1)&3,dma16.ac[(addr>>1)&3]);
return;
case 1: case 3: case 5: case 7: /*Count registers*/
dma16.wp^=1;
if (dma16.wp) dma16.cb[(addr>>1)&3]=(dma16.cb[(addr>>1)&3]&0xFF00)|val;
else dma16.cb[(addr>>1)&3]=(dma16.cb[(addr>>1)&3]&0xFF)|(val<<8);
dma16.cc[(addr>>1)&3]=dma16.cb[(addr>>1)&3];
dma16on[(addr>>1)&3]=1;
// printf("dma16 count %i now %04X\n",(addr>>1)&3,dma16.cc[(addr>>1)&3]);
return;
case 8: /*Control register*/
return;
case 0xA: /*Mask*/
if (val&4) dma16.m|=(1<<(val&3));
else dma16.m&=~(1<<(val&3));
return;
case 0xB: /*Mode*/
dma16.mode[val&3]=val;
return;
case 0xC: /*Clear FF*/
dma16.wp=0;
return;
case 0xD: /*Master clear*/
dma16.wp=0;
dma16.m=0xF;
return;
case 0xF: /*Mask write*/
dma16.m=val&0xF;
return;
}
}
uint8_t dmapages[16];
static int primed = 0;
void dma_page_write(uint16_t addr, uint8_t val)
{
if (!(addr&0xF))
{
// printf("Write page %03X %02X %04X:%04X\n",addr,val,CS,pc);
// if (val==0x29 && pc==0xD25) output=1;
}
dmapages[addr&0xF]=val;
switch (addr&0xF)
{
case 1:
dma.page[2]=(AT)?val:val&0xF;
break;
case 2:
dma.page[3]=(AT)?val:val&0xF;
break;
case 3:
dma.page[1]=(AT)?val:val&0xF;
// pclog("DMA1 page %02X\n",val);
break;
case 0xB:
dma16.page[1]=val;
break;
}
// printf("Page write %04X %02X\n",addr,val);
}
uint8_t dma_page_read(uint16_t addr)
{
return dmapages[addr&0xF];
}
void dma_init()
{
io_sethandler(0x0000, 0x0010, dma_read, NULL, NULL, dma_write, NULL, NULL);
io_sethandler(0x0080, 0x0008, dma_page_read, NULL, NULL, dma_page_write, NULL, NULL);
}
void dma16_init()
{
io_sethandler(0x00C0, 0x0020, dma16_read, NULL, NULL, dma16_write, NULL, NULL);
io_sethandler(0x0088, 0x0008, dma_page_read, NULL, NULL, dma_page_write, NULL, NULL);
}
uint8_t _dma_read(uint32_t addr)
{
switch (addr&0xFFFF8000)
{
case 0xA0000: case 0xA8000:
return video_read_a000(addr);
case 0xB0000:
return video_read_b000(addr);
case 0xB8000:
return video_read_b800(addr);
}
if (isram[addr>>16]) return ram[addr];
return 0xff;
}
void _dma_write(uint32_t addr, uint8_t val)
{
switch (addr&0xFFFF8000)
{
case 0xA0000: case 0xA8000:
video_write_a000(addr,val);
return;
case 0xB0000:
video_write_b000(addr,val);
return;
case 0xB8000:
video_write_b800(addr,val);
return;
case 0xC0000: case 0xC8000: case 0xD0000: case 0xD8000:
case 0xE0000: case 0xE8000: case 0xF0000: case 0xF8000:
return;
}
if (isram[addr>>16]) ram[addr]=val;
}
/*void writedma2(uint8_t val)
{
// printf("Write to %05X %02X %i\n",(dma.page[2]<<16)+dma.ac[2],val,dma.m&4);
if (!(dma.m&4))
{
ram[((dma.page[2]<<16)+dma.ac[2])&rammask]=val;
dma.ac[2]++;
dma.cc[2]--;
if (dma.cc[2]==-1)
{
dma.m|=4;
dma.stat|=4;
}
}
}*/
uint8_t readdma2()
{
uint8_t temp;
// pclog("Read DMA2 %02X %02X\n",dma.m,dma.mode[2]);
if (dma.m&4)
{
fdc_abort();
return 0xFF;
}
if ((dma.mode[2]&0xC)!=8)
{
fdc_abort();
return 0xFF;
}
temp=_dma_read((dma.ac[2]+(dma.page[2]<<16))&rammask); //ram[(dma.ac[2]+(dma.page[2]<<16))&rammask];
// pclog("DMA2 %02X %05X\n",temp,(dma.ac[2]+(dma.page[2]<<16))&rammask);
if (dma.mode[2]&0x20) dma.ac[2]--;
else dma.ac[2]++;
dma.cc[2]--;
if (!dma.cc[2] && (dma.mode[2]&0x10))
{
dma.cc[2]=dma.cb[2]+1;
dma.ac[2]=dma.ab[2];
}
else if (dma.cc[2]<=-1)
dma.m|=4;
return temp;
}
void writedma2(uint8_t temp)
{
// pclog("Write DMA2 %02X %02X %04X\n",dma.m,dma.mode[2],dma.cc[2]);
if (dma.m&4)
{
fdc_abort();
return;
}
if ((dma.mode[2]&0xC)!=4)
{
fdc_abort();
return;
}
// pclog("Write %05X %05X %02X\n",(dma.ac[2]+(dma.page[2]<<16)),rammask,temp);
// ram[(dma.ac[2]+(dma.page[2]<<16))&rammask]=temp;
_dma_write((dma.ac[2]+(dma.page[2]<<16))&rammask,temp);
if (dma.mode[2]&0x20) dma.ac[2]--;
else dma.ac[2]++;
dma.cc[2]--;
if (!dma.cc[2] && (dma.mode[2]&0x10))
{
dma.cc[2]=dma.cb[2]+1;
dma.ac[2]=dma.ab[2];
}
else if (dma.cc[2]<=-1)
{
// pclog("Reached TC\n");
fdc_abort();
dma.m|=4;
}
}
uint8_t readdma1()
{
uint8_t temp=0;
/*if ((dma.ac[1]+(dma.page[1]<<16))<0x800000) */temp=ram[(dma.ac[1]+(dma.page[1]<<16))&rammask];
// printf("Read DMA1 from %05X %02X %04X %02X %i\n",dma.ac[1]+(dma.page[1]<<16),dma.mode[1],dma.cc[1],temp,dmaon[1]);
if (!dmaon[1])
{
// printf("DMA off!\n");
return temp;
}
dma.ac[1]++;
dma.cc[1]--;
if (dma.cc[1]<=-1 && (dma.mode[1]&0x10))
{
dma.cc[1]=dma.cb[1];
dma.ac[1]=dma.ab[1];
}
else if (dma.cc[1]<=-1)
dmaon[1]=0;
return temp;
}
uint16_t readdma5()
{
uint16_t temp=0;
// pclog("Read DMA5 %i %04X\n",dma16on[1],dma16.cc[1]);
/*if ((dma16.ac[1]+(dma16.page[1]<<16))<0x800000) */temp=ram[((dma16.ac[1]<<1)+((dma16.page[1]&~1)<<16))&rammask]|(ram[((dma16.ac[1]<<1)+((dma16.page[1]&~1)<<16)+1)&rammask]<<8);
//readmemwl(dma16.ac[1]+(dma16.page[1]<<16));
// printf("Read DMA1 from %05X %05X %02X %04X\n",dma.ac[1]+(dma.page[1]<<16),(dma16.ac[1]<<1)+((dma16.page[1]&~1)<<16),dma16.mode[1],temp);
if (!dma16on[1])
{
// printf("DMA off!\n");
return temp;
}
dma16.ac[1]++;
dma16.cc[1]--;
if (dma16.cc[1]<=-1 && (dma16.mode[1]&0x10))
{
dma16.cc[1]=dma16.cb[1];
dma16.ac[1]=dma16.ab[1];
}
else if (dma16.cc[1]<=-1)
dma16on[1]=0;
return temp;
}
void writedma1(uint8_t temp)
{
if (!dmaon[1]) return;
ram[(dma.ac[1]+(dma.page[1]<<16))&rammask]=temp;
dma.ac[1]++;
dma.cc[1]--;
if (!dma.cc[1] && (dma.mode[1]&0x10))
{
dma.cc[1]=dma.cb[1]+1;
dma.ac[1]=dma.ab[1];
}
else if (dma.cc[1]<=-1)
dmaon[1]=0;
}
void writedma5(uint16_t temp)
{
if (!dma16on[1]) return;
ram[((dma16.ac[1]<<1)+((dma16.page[1]&~1)<<16))&rammask]=temp;
ram[((dma16.ac[1]<<1)+((dma16.page[1]&~1)<<16)+1)&rammask]=temp>>8;
dma16.ac[1]++;
dma16.cc[1]--;
if (dma16.cc[1]<=-1 && (dma16.mode[1]&0x10))
{
dma16.cc[1]=dma16.cb[1];
dma16.ac[1]=dma16.ab[1];
}
else if (dma16.cc[1]<=-1)
dma16on[1]=0;
}
int readdma3()
{
uint8_t temp=ram[((dma.page[3]<<16)+dma.ac[3])&rammask];
if (dma.m&8)
{
return -1;
}
// printf("Read DMA 3 - %02X %05X %i\n",temp,(dma.page[3]<<16)+dma.ac[3],dma.cc[3]);
if (!(dma.m&8))
{
dma.ac[3]++;
dma.cc[3]--;
if (dma.cc[3]==-1)
{
dma.m|=8;
dma.stat|=8;
}
}
return temp;
}
void readdma0()
{
if (AT) ppi.pb^=0x10;
if (dma.command & 4) return;
// if (AMSTRAD) return;
refreshread();
// pclog("Read refresh %02X %02X %04X %04X\n",dma.m,dma.mode[0],dma.ac[0],dma.cc[0]);
if (dma.m&1) return;
// readmembl((dma.page[0]<<16)+dma.ac[0]);
// if (!(dma.m&1))
// {
dma.ac[0]+=2;
dma.cc[0]--;
if (dma.cc[0]==-1)
{
dma.stat|=1;
dma.ac[0]=dma.ab[0];
dma.cc[0]=dma.cb[0];
}
// }
// ppi.pb^=0x10;
}
void dumpdma()
{
printf("Address : %04X %04X %04X %04X\n",dma.ac[0],dma.ac[1],dma.ac[2],dma.ac[3]);
printf("Count : %04X %04X %04X %04X\n",dma.cc[0],dma.cc[1],dma.cc[2],dma.cc[3]);
printf("Mask %02X Stat %02X\n",dma.m,dma.stat);
}

3
src/dma.h Normal file
View file

@ -0,0 +1,3 @@
void dma_init();
void dma16_init();
void dma_reset();

298
src/ega.c Normal file
View file

@ -0,0 +1,298 @@
#include "ibm.h"
#include "video.h"
void doblit();
int egareads=0,egawrites=0;
int framecount=0;
int changeframecount=2;
void redotextlookup();
int output;
int svgaon=0;
uint32_t svgarbank,svgawbank;
uint8_t svgaseg,svgaseg2;
uint8_t svga3d8;
uint8_t oldvram=0;
int frames;
int incga=1;
int hsync;
uint8_t cgastat;
uint8_t gdcreg[16];
int gdcaddr;
uint8_t attrregs[32];
int attraddr,attrff=0;
uint8_t ega3c2;
uint8_t rotatevga[8][256];
uint8_t writemask,charset;
int writemode,readmode,readplane,chain4;
uint8_t colourcompare,colournocare;
uint8_t la,lb,lc,ld;
uint8_t *vram;
int egares;
uint8_t seqregs[32];
int seqaddr;
uint8_t oak_regs[32];
int oak_index;
extern int egaswitchread,egaswitches;
/*For VGA non-interlace colour, ID bits should be 1 1 0 or 6*/
int vres=0;
PALETTE vgapal;
uint32_t *pallook,pallook16[256],pallook64[256],pallook256[256];
int dacread,dacwrite,dacpos=0;
int palchange=1;
int fullchange;
float dispontime,dispofftime,disptime;
int ega_vtotal,ega_dispend,ega_vsyncstart,ega_split,ega_hdisp,ega_rowoffset;
int vidclock;
float cpuclock;
int bpp;
uint32_t vrammask;
uint8_t changedvram[(8192*1024)/1024];
int charseta,charsetb;
int egapal[16];
int displine;
int rowdbl=0;
int scrblank=0;
uint8_t edatlookup[4][4];
uint32_t textlookup[256][2][16][16];
/*void redotextlookup()
{
int c,d,e;
uint32_t temp;
int coffset=(VGA)?0:64;
for (c=0;c<256;c++)
{
for (d=0;d<16;d++)
{
// printf("ATTR %i=%02X+%02X\n",d,attrregs[d],coffset);
for (e=0;e<16;e++)
{
temp=0;
if (c&0x80) temp|=(attrregs[d]+coffset);
else temp|=(attrregs[e]+coffset);
if (c&0x40) temp|=(attrregs[d]+coffset)<<8;
else temp|=(attrregs[e]+coffset)<<8;
if (c&0x20) temp|=(attrregs[d]+coffset)<<16;
else temp|=(attrregs[e]+coffset)<<16;
if (c&0x10) temp|=(attrregs[d]+coffset)<<24;
else temp|=(attrregs[e]+coffset)<<24;
// if (c==0x5) printf("%08X %i %i %02X %02X\n",temp,d,e,attrregs[d],attrregs[e]);
textlookup[c][0][d][e]=temp;
temp=0;
if (c&0x08) temp|=(attrregs[d]+coffset);
else temp|=(attrregs[e]+coffset);
if (c&0x04) temp|=(attrregs[d]+coffset)<<8;
else temp|=(attrregs[e]+coffset)<<8;
if (c&0x02) temp|=(attrregs[d]+coffset)<<16;
else temp|=(attrregs[e]+coffset)<<16;
if (c&0x01) temp|=(attrregs[d]+coffset)<<24;
else temp|=(attrregs[e]+coffset)<<24;
textlookup[c][1][d][e]=temp;
}
}
}
}*/
void initega()
{
int c,d,e;
bpp=8;
for (c=0;c<256;c++)
{
e=c;
for (d=0;d<8;d++)
{
rotatevga[d][c]=e;
e=(e>>1)|((e&1)?0x80:0);
}
}
crtc[0xC]=crtc[0xD]=0;
if (romset==ROM_PC1640 || romset==ROM_PC1512) incga=1;
else incga=0;
for (c=0;c<4;c++)
{
for (d=0;d<4;d++)
{
edatlookup[c][d]=0;
if (c&1) edatlookup[c][d]|=1;
if (d&1) edatlookup[c][d]|=2;
if (c&2) edatlookup[c][d]|=0x10;
if (d&2) edatlookup[c][d]|=0x20;
// printf("Edat %i,%i now %02X\n",c,d,edatlookup[c][d]);
}
}
/*redotextlookup();*/
for (c=0;c<256;c++)
{
pallook64[c]=makecol32(((c>>2)&1)*0xAA,((c>>1)&1)*0xAA,(c&1)*0xAA);
pallook64[c]+=makecol32(((c>>5)&1)*0x55,((c>>4)&1)*0x55,((c>>3)&1)*0x55);
pallook16[c]=makecol32(((c>>2)&1)*0xAA,((c>>1)&1)*0xAA,(c&1)*0xAA);
pallook16[c]+=makecol32(((c>>4)&1)*0x55,((c>>4)&1)*0x55,((c>>4)&1)*0x55);
if ((c&0x17)==6) pallook16[c]=makecol32(0xAA,0x55,0);
// printf("%03i %08X\n",c,pallook[c]);
}
pallook=pallook16;
seqregs[0xC]=0x20;
vrammask=(ET4000)?0xFFFFF:0x1FFFFF;
// writeega_func=writeega;
gdcreg[6]=8;
gdcreg[8]=0xFF;
writemode=0;
chain4=0;
writemask=3;
et4k_b8000=0;
svgarbank=svgawbank=0;
}
uint32_t egabase,egaoffset;
void cacheega()
{
egabase=(crtc[0xC]<<8)|crtc[0xD];
if (ET4000 || ET4000W32 || TRIDENT)
egabase|=((crtc[0x33]&3)<<18);
// printf("EGABASE %05X\n",egabase);
// egaoffset=8-((attrregs[0x13])&7);
// printf("Cache base!\n");
}
void cacheega2()
{
// egabase=(crtc[0xC]<<8)|crtc[0xD];
if (gdcreg[5]&0x40) egaoffset=8-(((attrregs[0x13])&7)>>1);
else egaoffset=8-((attrregs[0x13])&7);
// printf("Cache offset!\n");
}
int olddisplines,oldxsize;
int oldreadflash;
int oldegaaddr,oldegasplit;
int vc,sc;
int egadispon=0;
int linepos;
int displine;
uint32_t ma,maback,ca;
int firstline,lastline;
int xsize,ysize;
int scrollcache;
int con,cursoron,cgablink;
BITMAP *buffer,*vbuf,*buffer32;
int linecountff=0;
void dumpegaregs()
{
int c;
printf("CRTC :");
for (c=0;c<0x20;c++) printf(" %02X",crtc[c]);
printf("\n");
printf(" EXT :");
for (c=0;c<0x20;c++) printf(" %02X",crtc[c+32]);
printf("\n");
printf(" EXT2:");
for (c=0;c<0x20;c++) printf(" %02X",crtc[c+64]);
printf("\n");
printf("SEQ :");
for (c=0;c<0x10;c++) printf(" %02X",seqregs[c]);
printf("\n");
printf(" EXT :");
for (c=0;c<0x10;c++) printf(" %02X",seqregs[c + 0x10]);
printf("\n");
printf("ATTR :");
for (c=0;c<0x20;c++) printf(" %02X",attrregs[c]);
printf("\n");
printf("GDC :");
for (c=0;c<0x10;c++) printf(" %02X",gdcreg[c]);
printf("\n");
// printf("OLD CTRL2 = %02X NEW CTRL2 = %02X DAC = %02X 3C2 = %02X\n",tridentoldctrl2,tridentnewctrl2,tridentdac,ega3c2);
printf("BPP = %02X\n",bpp);
}
int oddeven;
int wx,wy;
int vslines;
int frames = 0;
void doblit()
{
startblit();
if ((wx!=xsize || wy!=ysize) && !vid_resize)
{
xsize=wx;
ysize=wy+1;
if (xsize<64) xsize=656;
if (ysize<32) ysize=200;
if (vres) updatewindowsize(xsize,ysize<<1);
else updatewindowsize(xsize,ysize);
}
video_blit_memtoscreen(32, 0, 0, ysize, xsize, ysize);
if (readflash) rectfill(screen,winsizex-40,8,winsizex-8,14,0xFFFFFFFF);
endblit();
frames++;
}
int ega_getdepth()
{
if (!(gdcreg[6]&1)) return 0;
switch (gdcreg[5]&0x60)
{
case 0x00:
return 4;
case 0x20:
return 2;
case 0x40: case 0x60:
if (TRIDENT || ET4000W32) return bpp;
return 8;
}
}
int ega_getx()
{
int x;
if (!(gdcreg[6]&1)) return (crtc[1]+1);
if ((attrregs[0x10]&0x40) && !(tridentoldctrl2&0x10)) x=(crtc[1]+1)*4;
else x=(crtc[1]+1)*8;
if (TRIDENT && (bpp==15 || bpp==16)) x>>=1;
if (TRIDENT && bpp==24) x=(x<<1)/3;
return x;
}
int ega_gety()
{
if (crtc[0x1E]&4) return (ega_dispend/((crtc[9]&31)+1))<<1;
if (crtc[9]&0x80) return (ega_dispend/((crtc[9]&31)+1))>>1;
return ega_dispend/((crtc[9]&31)+1);
}

806
src/fdc.c Normal file
View file

@ -0,0 +1,806 @@
#include <stdio.h>
#include <string.h>
#include "ibm.h"
void fdc_poll();
int timetolive;
int TRACKS[2] = {80, 80};
int SECTORS[2]={9,9};
int SIDES[2]={2,2};
//#define SECTORS 9
int output;
int lastbyte=0;
uint8_t disc[2][2][80][36][512];
uint8_t disc_3f7;
int discchanged[2];
int discmodified[2];
int discrate[2];
void loaddisc(int d, char *fn)
{
FILE *f=fopen(fn,"rb");
int h,t,s,b;
if (!f)
{
SECTORS[d]=9; SIDES[d]=1;
driveempty[d]=1; discrate[d]=4;
return;
}
driveempty[d]=0;
SIDES[d]=2;
fseek(f,-1,SEEK_END);
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)<(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*/
else if (ftell(f) == 1763327) { SECTORS[d]=21; TRACKS[d] = 82; discrate[d]=0; } /*XDF format - used by OS/2 Warp*/
else if (ftell(f)<(2048*1024)) { SECTORS[d]=21; TRACKS[d] = 80; discrate[d]=0; } /*DMF format - used by Windows 95*/
else { SECTORS[d]=36; TRACKS[d] = 80; discrate[d]=3; } /*E density (not supported by anything)*/
printf("Drive %c: has %i sectors and %i sides and is %i bytes long\n",'A'+d,SECTORS[0],SIDES[0],ftell(f));
fseek(f,0,SEEK_SET);
for (t=0;t<80;t++)
{
for (h=0;h<SIDES[d];h++)
{
for (s=0;s<SECTORS[d];s++)
{
for (b=0;b<512;b++)
{
disc[d][h][t][s][b]=getc(f);
}
}
}
}
fclose(f);
discmodified[d]=0;
strcpy(discfns[d],fn);
discchanged[d]=1;
}
void ejectdisc(int d)
{
discfns[d][0]=0;
SECTORS[d]=9; SIDES[d]=1;
driveempty[d]=1; discrate[d]=4;
}
void savedisc(int d)
{
FILE *f;
int h,t,s,b;
if (!discmodified[d]) return;
f=fopen(discfns[d],"wb");
if (!f) return;
printf("Save disc %c: %s %i %i\n",'A'+d,discfns[0],SIDES[0],SECTORS[0]);
for (t=0;t<80;t++)
{
for (h=0;h<SIDES[d];h++)
{
for (s=0;s<SECTORS[d];s++)
{
for (b=0;b<512;b++)
{
putc(disc[d][h][t][s][b],f);
}
}
}
}
fclose(f);
}
int discint;
void fdc_reset()
{
fdc.stat=0x80;
fdc.pnum=fdc.ptot=0;
fdc.st0=0xC0;
fdc.lock = 0;
fdc.head = 0;
if (!AT)
fdc.rate=2;
// pclog("Reset FDC\n");
}
int ins;
void fdc_write(uint16_t addr, uint8_t val)
{
int c;
// printf("Write FDC %04X %02X %04X:%04X %i %02X %i rate=%i\n",addr,val,cs>>4,pc,ins,fdc.st0,ins,fdc.rate);
switch (addr&7)
{
case 1: return;
case 2: /*DOR*/
// if (val == 0xD && (cs >> 4) == 0xFC81600 && ins > 769619936) output = 3;
// printf("DOR was %02X\n",fdc.dor);
if (val&4)
{
fdc.stat=0x80;
fdc.pnum=fdc.ptot=0;
}
if ((val&4) && !(fdc.dor&4))
{
disctime=128;
discint=-1;
fdc_reset();
}
fdc.dor=val;
// printf("DOR now %02X\n",val);
return;
case 4:
if (val & 0x80)
{
disctime=128;
discint=-1;
fdc_reset();
}
return;
case 5: /*Command register*/
// pclog("Write command reg %i %i\n",fdc.pnum, fdc.ptot);
if (fdc.pnum==fdc.ptot)
{
fdc.command=val;
// printf("Starting FDC command %02X\n",fdc.command);
switch (fdc.command&0x1F)
{
case 2: /*Read track*/
// printf("Read track!\n");
fdc.pnum=0;
fdc.ptot=8;
fdc.stat=0x90;
fdc.pos=0;
break;
case 3: /*Specify*/
fdc.pnum=0;
fdc.ptot=2;
fdc.stat=0x90;
break;
case 4: /*Sense drive status*/
fdc.pnum=0;
fdc.ptot=1;
fdc.stat=0x90;
break;
case 5: /*Write data*/
// printf("Write data!\n");
fdc.pnum=0;
fdc.ptot=8;
fdc.stat=0x90;
fdc.pos=0;
readflash=1;
break;
case 6: /*Read data*/
fullspeed();
fdc.pnum=0;
fdc.ptot=8;
fdc.stat=0x90;
fdc.pos=0;
readflash=1;
break;
case 7: /*Recalibrate*/
fdc.pnum=0;
fdc.ptot=1;
fdc.stat=0x90;
break;
case 8: /*Sense interrupt status*/
// printf("Sense interrupt status %i\n",fdc.drive);
fdc.lastdrive = fdc.drive;
// fdc.stat = 0x10 | (fdc.stat & 0xf);
// disctime=1024;
discint = 8;
fdc.pos = 0;
fdc_poll();
break;
case 10: /*Read sector ID*/
fdc.pnum=0;
fdc.ptot=1;
fdc.stat=0x90;
fdc.pos=0;
break;
case 15: /*Seek*/
fdc.pnum=0;
fdc.ptot=2;
fdc.stat=0x90;
break;
case 0x0e: /*Dump registers*/
fdc.lastdrive = fdc.drive;
discint = 0x0e;
fdc.pos = 0;
fdc_poll();
break;
case 0x10: /*Get version*/
fdc.lastdrive = fdc.drive;
discint = 0x10;
fdc.pos = 0;
fdc_poll();
break;
case 0x12: /*Set perpendicular mode*/
fdc.pnum=0;
fdc.ptot=1;
fdc.stat=0x90;
fdc.pos=0;
break;
case 0x13: /*Configure*/
fdc.pnum=0;
fdc.ptot=3;
fdc.stat=0x90;
fdc.pos=0;
break;
case 0x14: /*Unlock*/
case 0x94: /*Lock*/
fdc.lastdrive = fdc.drive;
discint = fdc.command;
fdc.pos = 0;
fdc_poll();
break;
case 0x18:
fdc.stat = 0x10;
discint = 0xfc;
fdc_poll();
break;
default:
pclog("Bad FDC command %02X\n",val);
// dumpregs();
// exit(-1);
fdc.stat=0x10;
discint=0xfc;
disctime=200;
break;
}
}
else
{
fdc.params[fdc.pnum++]=val;
if (fdc.pnum==fdc.ptot)
{
// pclog("Got all params\n");
fdc.stat=0x30;
discint=fdc.command&0x1F;
disctime=1024;
fdc.drive=fdc.params[0]&1;
if (discint==2 || discint==5 || discint==6)
{
fdc.track[fdc.drive]=fdc.params[1];
fdc.head=fdc.params[2];
fdc.sector=fdc.params[3];
fdc.eot[fdc.drive] = fdc.params[4];
if (!fdc.params[5])
{
fdc.params[5]=fdc.sector;
}
if (fdc.params[5]>SECTORS[fdc.drive]) fdc.params[5]=SECTORS[fdc.drive];
if (driveempty[fdc.drive])
{
// pclog("Drive empty\n");
discint=0xFE;
}
}
if (discint==2 || discint==5 || discint==6 || discint==10)
{
// pclog("Rate %i %i %i\n",fdc.rate,discrate[fdc.drive],driveempty[fdc.drive]);
if (fdc.rate!=discrate[fdc.drive])
{
// pclog("Wrong rate %i %i\n",fdc.rate,discrate[fdc.drive]);
discint=0xFF;
disctime=1024;
}
if (driveempty[fdc.drive])
{
// pclog("Drive empty\n");
discint=0xFE;
disctime=1024;
}
}
if (discint == 7 || discint == 0xf)
{
fdc.stat = 1 << fdc.drive;
// disctime = 8000000;
}
if (discint == 0xf)
{
fdc.head = (fdc.params[0] & 4) ? 1 : 0;
}
// if (discint==5) fdc.pos=512;
}
}
return;
case 7:
if (!AT) return;
fdc.rate=val&3;
disc_3f7=val;
return;
}
// printf("Write FDC %04X %02X\n",addr,val);
// dumpregs();
// exit(-1);
}
int paramstogo=0;
uint8_t fdc_read(uint16_t addr)
{
uint8_t temp;
// /*if (addr!=0x3f4) */printf("Read FDC %04X %04X:%04X %04X %i %02X %i ",addr,cs>>4,pc,BX,fdc.pos,fdc.st0,ins);
switch (addr&7)
{
case 1: /*???*/
temp=0x50;
break;
case 3:
temp = 0x20;
break;
case 4: /*Status*/
temp=fdc.stat;
break;
case 5: /*Data*/
fdc.stat&=~0x80;
if (paramstogo)
{
paramstogo--;
temp=fdc.res[10 - paramstogo];
// printf("Read param %i %02X\n",6-paramstogo,temp);
if (!paramstogo)
{
fdc.stat=0x80;
// fdc.st0=0;
}
else
{
fdc.stat|=0xC0;
// fdc_poll();
}
}
else
{
if (lastbyte)
fdc.stat=0x80;
lastbyte=0;
temp=fdc.dat;
}
if (discint==0xA) disctime=1024;
fdc.stat &= 0xf0;
break;
case 7: /*Disk change*/
if (fdc.dor & (0x10 << (fdc.dor & 1)))
temp = (discchanged[fdc.dor & 1] || driveempty[fdc.dor & 1])?0x80:0;
else
temp = 0;
if (AMSTRADIO) /*PC2086/3086 seem to reverse this bit*/
temp ^= 0x80;
// printf("- DC %i %02X %02X %i %i - ",fdc.dor & 1, fdc.dor, 0x10 << (fdc.dor & 1), discchanged[fdc.dor & 1], driveempty[fdc.dor & 1]);
// discchanged[fdc.dor&1]=0;
break;
default:
temp=0xFF;
// printf("Bad read FDC %04X\n",addr);
// dumpregs();
// exit(-1);
}
// /*if (addr!=0x3f4) */printf("%02X rate=%i\n",temp,fdc.rate);
return temp;
}
int fdc_abort_f = 0;
void fdc_abort()
{
fdc_abort_f = 1;
// pclog("FDC ABORT\n");
}
static int fdc_reset_stat = 0;
void fdc_poll()
{
int temp;
// pclog("fdc_poll %08X %i %02X\n", discint, fdc.drive, fdc.st0);
switch (discint)
{
case -3: /*End of command with interrupt*/
// if (output) printf("EOC - interrupt!\n");
//pclog("EOC\n");
picint(0x40);
case -2: /*End of command*/
fdc.stat = (fdc.stat & 0xf) | 0x80;
return;
case -1: /*Reset*/
//pclog("Reset\n");
picint(0x40);
fdc_reset_stat = 4;
return;
case 2: /*Read track*/
if (!fdc.pos)
{
// printf("Read Track Side %i Track %i Sector %02X sector size %i end sector %02X %05X\n",fdc.head,fdc.track,fdc.sector,fdc.params[4],fdc.params[5],(dma.page[2]<<16)+dma.ac[2]);
}
if (fdc.pos<512)
{
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);
writedma2(fdc.dat);
disctime=60;
}
else
{
disctime=0;
discint=-2;
// pclog("RT\n");
picint(0x40);
fdc.stat=0xD0;
fdc.res[4]=(fdc.head?4:0)|fdc.drive;
fdc.res[5]=fdc.res[2]=0;
fdc.res[6]=fdc.track[fdc.drive];
fdc.res[7]=fdc.head;
fdc.res[8]=fdc.sector;
fdc.res[9]=fdc.params[4];
paramstogo=7;
return;
disctime=1024;
picint(0x40);
fdc.stat=0xD0;
switch (fdc.pos-512)
{
case 0: case 1: case 2: fdc.dat=0; break;
case 3: fdc.dat=fdc.track[fdc.drive]; break;
case 4: fdc.dat=fdc.head; break;
case 5: fdc.dat=fdc.sector; break;
case 6: fdc.dat=fdc.params[4]; discint=-2; lastbyte=1; break;
}
}
fdc.pos++;
if (fdc.pos==512 && fdc.params[5]!=1)
{
fdc.pos=0;
fdc.sector++;
if (fdc.sector==SECTORS[fdc.drive]+1)
{
fdc.sector=1;
}
fdc.params[5]--;
}
return;
case 3: /*Specify*/
fdc.stat=0x80;
fdc.specify[0] = fdc.params[0];
fdc.specify[1] = fdc.params[1];
return;
case 4: /*Sense drive status*/
fdc.res[10] = (fdc.params[0] & 7) | 0x28;
if (!fdc.track[fdc.drive]) fdc.res[10] |= 0x10;
fdc.stat = (fdc.stat & 0xf) | 0xd0;
paramstogo = 1;
discint = 0;
disctime = 0;
return;
case 5: /*Write data*/
discmodified[fdc.drive]=1;
// printf("Write data %i\n",fdc.pos);
if (!fdc.pos)
{
// printf("Write data Side %i Track %i Sector %02X sector size %i end sector %02X\n",fdc.params[2],fdc.params[1],fdc.params[3],fdc.params[4],fdc.params[5]);
// dumpregs();
// exit(-1);
}
if (fdc.pos<512)
{
temp=readdma2();
if (fdc_abort_f)
{
fdc_abort_f=0;
discint=0xFD;
disctime=50;
return;
}
else
{
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);
disctime=60;
}
}
else
{
disctime=0;
discint=-2;
// pclog("WD\n");
picint(0x40);
fdc.stat=0xD0;
fdc.res[4]=(fdc.head?4:0)|fdc.drive;
fdc.res[5]=0;
fdc.res[6]=0;
fdc.res[7]=fdc.track[fdc.drive];
fdc.res[8]=fdc.head;
fdc.res[9]=fdc.sector;
fdc.res[10]=fdc.params[4];
paramstogo=7;
return;
disctime=1024;
picint(0x40);
fdc.stat=0xD0;
switch (fdc.pos-512)
{
case 0: fdc.dat=0x40; break;
case 1: fdc.dat=2; break;
case 2: fdc.dat=0; break;
case 3: fdc.dat=fdc.track[fdc.drive]; break;
case 4: fdc.dat=fdc.head; break;
case 5: fdc.dat=fdc.sector; break;
case 6: fdc.dat=fdc.params[4]; discint=-2; break;
}
}
fdc.pos++;
if (fdc.pos==512 && fdc.sector!=fdc.params[5])
{
fdc.pos=0;
fdc.sector++;
}
return;
case 6: /*Read data*/
if (!fdc.pos)
{
// printf("Reading sector %i track %i side %i drive %i %02X to %05X\n",fdc.sector,fdc.track[fdc.drive],fdc.head,fdc.drive,fdc.params[5],(dma.ac[2]+(dma.page[2]<<16))&rammask);
}
if (fdc.pos<512)
{
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);
writedma2(fdc.dat);
disctime=60;
}
else
{
// printf("End of command - params to go!\n");
fdc_abort_f = 0;
disctime=0;
discint=-2;
picint(0x40);
// pclog("RD\n");
fdc.stat=0xD0;
fdc.res[4]=(fdc.head?4:0)|fdc.drive;
fdc.res[5]=fdc.res[6]=0;
fdc.res[7]=fdc.track[fdc.drive];
fdc.res[8]=fdc.head;
fdc.res[9]=fdc.sector;
fdc.res[10]=fdc.params[4];
paramstogo=7;
return;
switch (fdc.pos-512)
{
case 0: case 1: case 2: fdc.dat=0; break;
case 3: fdc.dat=fdc.track[fdc.drive]; break;
case 4: fdc.dat=fdc.head; break;
case 5: fdc.dat=fdc.sector; break;
case 6: fdc.dat=fdc.params[4]; discint=-2; lastbyte=1; break;
}
}
fdc.pos++;
if (fdc.pos==512)// && fdc.sector!=fdc.params[5])
{
// printf("Sector complete! %02X\n",fdc.params[5]);
fdc.pos=0;
fdc.sector++;
if (fdc.sector > fdc.params[5])
{
// printf("Overrunnit!\n");
// dumpregs();
// exit(-1);
fdc.sector=1;
if (fdc.command & 0x80)
{
fdc.head ^= 1;
if (!fdc.head)
{
fdc.track[fdc.drive]++;
if (fdc.track[fdc.drive] >= TRACKS[fdc.drive])
{
fdc.track[fdc.drive] = TRACKS[fdc.drive];
fdc.pos = 512;
}
}
}
else
fdc.pos = 512;
}
if (fdc_abort_f)
fdc.pos = 512;
}
return;
/* printf("Read data\n");
printf("Side %i Track %i Sector %i sector size %i\n",fdc.params[1],fdc.params[2],fdc.params[3],fdc.params[4]);
dumpregs();
exit(-1);*/
case 7: /*Recalibrate*/
fdc.track[fdc.drive]=0;
if (!driveempty[fdc.dor & 1]) discchanged[fdc.dor & 1] = 0;
fdc.st0=0x20|fdc.drive|(fdc.head?4:0);
discint=-3;
disctime=2048;
// printf("Recalibrate complete!\n");
fdc.stat = 0x80 | (1 << fdc.drive);
return;
case 8: /*Sense interrupt status*/
// pclog("Sense interrupt status %i\n", fdc_reset_stat);
fdc.dat = fdc.st0;
if (fdc_reset_stat)
{
fdc.st0 = (fdc.st0 & 0xf8) | (4 - fdc_reset_stat) | (fdc.head ? 4 : 0);
fdc_reset_stat--;
}
fdc.stat = (fdc.stat & 0xf) | 0xd0;
fdc.res[9] = fdc.st0;
fdc.res[10] = fdc.track[fdc.drive];
if (!fdc_reset_stat) fdc.st0 = 0x80;
paramstogo = 2;
discint = 0;
disctime = 0;
return;
case 10: /*Read sector ID*/
disctime=0;
discint=-2;
picint(0x40);
fdc.stat=0xD0;
fdc.res[4]=(fdc.head?4:0)|fdc.drive;
fdc.res[5]=0;
fdc.res[6]=0;
fdc.res[7]=fdc.track[fdc.drive];
fdc.res[8]=fdc.head;
fdc.res[9]=fdc.sector;
fdc.res[10]=fdc.params[4];
paramstogo=7;
fdc.sector++;
if (fdc.sector==SECTORS[fdc.drive]+1)
fdc.sector=1;
return;
case 15: /*Seek*/
fdc.track[fdc.drive]=fdc.params[1];
if (!driveempty[fdc.dor & 1]) discchanged[fdc.dor & 1] = 0;
// printf("Seeked to track %i %i\n",fdc.track[fdc.drive], fdc.drive);
fdc.st0=0x20|fdc.drive|(fdc.head?4:0);
discint=-3;
disctime=2048;
fdc.stat = 0x80 | (1 << fdc.drive);
// pclog("Stat %02X ST0 %02X\n", fdc.stat, fdc.st0);
return;
case 0x0e: /*Dump registers*/
fdc.stat = (fdc.stat & 0xf) | 0xd0;
fdc.res[3] = fdc.track[0];
fdc.res[4] = fdc.track[1];
fdc.res[5] = 0;
fdc.res[6] = 0;
fdc.res[7] = fdc.specify[0];
fdc.res[8] = fdc.specify[1];
fdc.res[9] = fdc.eot[fdc.drive];
fdc.res[10] = (fdc.perp & 0x7f) | ((fdc.lock) ? 0x80 : 0);
paramstogo=10;
discint=0;
disctime=0;
return;
case 0x10: /*Version*/
fdc.stat = (fdc.stat & 0xf) | 0xd0;
fdc.res[10] = 0x90;
paramstogo=1;
discint=0;
disctime=0;
return;
case 0x12:
fdc.perp = fdc.params[0];
fdc.stat = 0x80;
disctime = 0;
// picint(0x40);
return;
case 0x13: /*Configure*/
fdc.config = fdc.params[1];
fdc.pretrk = fdc.params[2];
fdc.stat = 0x80;
disctime = 0;
// picint(0x40);
return;
case 0x14: /*Unlock*/
fdc.lock = 0;
fdc.stat = (fdc.stat & 0xf) | 0xd0;
fdc.res[10] = 0;
paramstogo=1;
discint=0;
disctime=0;
return;
case 0x94: /*Lock*/
fdc.lock = 1;
fdc.stat = (fdc.stat & 0xf) | 0xd0;
fdc.res[10] = 0x10;
paramstogo=1;
discint=0;
disctime=0;
return;
case 0xfc: /*Invalid*/
fdc.dat = fdc.st0 = 0x80;
// pclog("Inv!\n");
//picint(0x40);
fdc.stat = (fdc.stat & 0xf) | 0xd0;
// fdc.stat|=0xC0;
fdc.res[10] = fdc.st0;
paramstogo=1;
discint=0;
disctime=0;
return;
case 0xFD: /*DMA aborted (PC1512)*/
/*In the absence of other information, lie and claim the command completed successfully.
The PC1512 BIOS likes to program the FDC to write to all sectors on the track, but
program the DMA length to the number of sectors actually transferred. Not aborting
correctly causes disc corruption.
This only matters on writes, on reads the DMA controller will ignore excess data.
*/
pclog("DMA Aborted\n");
disctime=0;
discint=-2;
picint(0x40);
fdc.stat=0xD0;
fdc.res[4]=(fdc.head?4:0)|fdc.drive;
fdc.res[5]=0;
fdc.res[6]=0;
fdc.res[7]=fdc.track[fdc.drive];
fdc.res[8]=fdc.head;
fdc.res[9]=fdc.sector;
fdc.res[10]=fdc.params[4];
paramstogo=7;
return;
case 0xFE: /*Drive empty*/
pclog("Drive empty\n");
fdc.stat = 0x10;
disctime = 0;
/* disctime=0;
discint=-2;
picint(0x40);
fdc.stat=0xD0;
fdc.res[4]=0xC8|(fdc.head?4:0)|fdc.drive;
fdc.res[5]=0;
fdc.res[6]=0;
fdc.res[7]=0;
fdc.res[8]=0;
fdc.res[9]=0;
fdc.res[10]=0;
paramstogo=7;*/
return;
case 0xFF: /*Wrong rate*/
pclog("Wrong rate\n");
disctime=0;
discint=-2;
picint(0x40);
fdc.stat=0xD0;
fdc.res[4]=0x40|(fdc.head?4:0)|fdc.drive;
fdc.res[5]=5;
fdc.res[6]=0;
fdc.res[7]=0;
fdc.res[8]=0;
fdc.res[9]=0;
fdc.res[10]=0;
paramstogo=7;
return;
}
// printf("Bad FDC disc int %i\n",discint);
// dumpregs();
// exit(-1);
}
void fdc_init()
{
io_sethandler(0x03f0, 0x0006, fdc_read, NULL, NULL, fdc_write, NULL, NULL);
io_sethandler(0x03f7, 0x0001, fdc_read, NULL, NULL, fdc_write, NULL, NULL);
}
void fdc_remove()
{
io_removehandler(0x03f0, 0x0006, fdc_read, NULL, NULL, fdc_write, NULL, NULL);
io_removehandler(0x03f7, 0x0001, fdc_read, NULL, NULL, fdc_write, NULL, NULL);
}

4
src/fdc.h Normal file
View file

@ -0,0 +1,4 @@
void fdc_init();
void fdc_remove();
void fdc_reset();
void fdc_poll();

178
src/filters.h Normal file
View file

@ -0,0 +1,178 @@
#define NCoef 2
//fc=350Hz
static inline float low_iir(int i, float NewSample) {
float ACoef[NCoef+1] = {
0.00049713569693400649,
0.00099427139386801299,
0.00049713569693400649
};
float BCoef[NCoef+1] = {
1.00000000000000000000,
-1.93522955470669530000,
0.93726236021404663000
};
static float y[2][NCoef+1]; //output samples
static float x[2][NCoef+1]; //input samples
int n;
//shift the old samples
for(n=NCoef; n>0; n--) {
x[i][n] = x[i][n-1];
y[i][n] = y[i][n-1];
}
//Calculate the new output
x[i][0] = NewSample;
y[i][0] = ACoef[0] * x[i][0];
for(n=1; n<=NCoef; n++)
y[i][0] += ACoef[n] * x[i][n] - BCoef[n] * y[i][n];
return y[i][0];
}
//fc=350Hz
static inline float low_cut_iir(int i, float NewSample) {
float ACoef[NCoef+1] = {
0.96839970114733542000,
-1.93679940229467080000,
0.96839970114733542000
};
float BCoef[NCoef+1] = {
1.00000000000000000000,
-1.93522955471202770000,
0.93726236021916731000
};
static float y[2][NCoef+1]; //output samples
static float x[2][NCoef+1]; //input samples
int n;
//shift the old samples
for(n=NCoef; n>0; n--) {
x[i][n] = x[i][n-1];
y[i][n] = y[i][n-1];
}
//Calculate the new output
x[i][0] = NewSample;
y[i][0] = ACoef[0] * x[i][0];
for(n=1; n<=NCoef; n++)
y[i][0] += ACoef[n] * x[i][n] - BCoef[n] * y[i][n];
return y[i][0];
}
//fc=3.5kHz
static inline float high_iir(int i, float NewSample) {
float ACoef[NCoef+1] = {
0.72248704753064896000,
-1.44497409506129790000,
0.72248704753064896000
};
float BCoef[NCoef+1] = {
1.00000000000000000000,
-1.36640781670578510000,
0.52352474706139873000
};
static float y[2][NCoef+1]; //output samples
static float x[2][NCoef+1]; //input samples
int n;
//shift the old samples
for(n=NCoef; n>0; n--) {
x[i][n] = x[i][n-1];
y[i][n] = y[i][n-1];
}
//Calculate the new output
x[i][0] = NewSample;
y[i][0] = ACoef[0] * x[i][0];
for(n=1; n<=NCoef; n++)
y[i][0] += ACoef[n] * x[i][n] - BCoef[n] * y[i][n];
return y[i][0];
}
//fc=3.5kHz
static inline float high_cut_iir(int i, float NewSample) {
float ACoef[NCoef+1] = {
0.03927726802250377400,
0.07855453604500754700,
0.03927726802250377400
};
float BCoef[NCoef+1] = {
1.00000000000000000000,
-1.36640781666419950000,
0.52352474703279628000
};
static float y[2][NCoef+1]; //output samples
static float x[2][NCoef+1]; //input samples
int n;
//shift the old samples
for(n=NCoef; n>0; n--) {
x[i][n] = x[i][n-1];
y[i][n] = y[i][n-1];
}
//Calculate the new output
x[i][0] = NewSample;
y[i][0] = ACoef[0] * x[i][0];
for(n=1; n<=NCoef; n++)
y[i][0] += ACoef[n] * x[i][n] - BCoef[n] * y[i][n];
return y[i][0];
}
#undef NCoef
#define NCoef 1
//fc=3.2kHz
static inline float sb_iir(int i, float NewSample) {
/* float ACoef[NCoef+1] = {
0.03356837051492005100,
0.06713674102984010200,
0.03356837051492005100
};
float BCoef[NCoef+1] = {
1.00000000000000000000,
-1.41898265221812010000,
0.55326988968868285000
};*/
float ACoef[NCoef+1] = {
0.17529642630084405000,
0.17529642630084405000
};
float BCoef[NCoef+1] = {
1.00000000000000000000,
-0.64940759319751051000
};
static float y[2][NCoef+1]; //output samples
static float x[2][NCoef+1]; //input samples
int n;
//shift the old samples
for(n=NCoef; n>0; n--) {
x[i][n] = x[i][n-1];
y[i][n] = y[i][n-1];
}
//Calculate the new output
x[i][0] = NewSample;
y[i][0] = ACoef[0] * x[i][0];
for(n=1; n<=NCoef; n++)
y[i][0] += ACoef[n] * x[i][n] - BCoef[n] * y[i][n];
return y[i][0];
}

625
src/gus.c Normal file
View file

@ -0,0 +1,625 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "ibm.h"
extern int ins;
extern int timetolive;
int output;
//#define GUSRATECONST (44100.0/48000.0)
uint8_t *gusram;
struct
{
int global;
uint32_t addr,dmaaddr;
int voice;
uint32_t start[32],end[32],cur[32];
uint32_t startx[32],endx[32],curx[32];
uint32_t rstart[32],rend[32],rcur[32];
uint16_t freq[32];
uint16_t rfreq[32];
uint8_t ctrl[32];
uint8_t rctrl[32];
int curvol[32];
int t1on,t2on;
uint8_t tctrl;
uint16_t t1,t2,t1l,t2l;
uint8_t irqstatus,irqstatus2;
uint8_t adcommand;
int waveirqs[32],rampirqs[32];
int voices;
uint8_t dmactrl;
} gus;
double vol16bit[4096];
void initgus()
{
int c;
for (c=0;c<32;c++)
{
gus.ctrl[c]=1;
gus.rctrl[c]=1;
gus.rfreq[c]=63*512;
}
gusram=malloc(1024*1024);
double out = 1.0;
for (c=4095;c>=0;c--) {
vol16bit[c]=out;//(float)c/4095.0;//out;
out/=1.002709201; /* 0.0235 dB Steps */
}
printf("Top volume %f %f %f %f\n",vol16bit[4095],vol16bit[3800],vol16bit[3000],vol16bit[2048]);
gus.voices=14;
}
void dumpgus()
{
/* FILE *f=fopen("gusram.dmp","wb");
fwrite(gusram,1024*1024,1,f);
fclose(f);*/
}
void pollgusirqs()
{
int c;
gus.irqstatus&=~0x60;
for (c=0;c<32;c++)
{
if (gus.waveirqs[c])
{
// gus.waveirqs[c]=0;
gus.irqstatus2=0x60|c;
gus.irqstatus|=0x20;
// printf("Voice IRQ %i %02X %i\n",c,gus.irqstatus2,ins);
picintlevel(0x20);
// output=3;
// timetolive=5000;
return;
}
if (gus.rampirqs[c])
{
// gus.rampirqs[c]=0;
gus.irqstatus2=0xA0|c;
gus.irqstatus|=0x40;
// printf("Ramp IRQ %i %02X %i\n",c,gus.irqstatus2,ins);
picintlevel(0x20);
return;
}
}
gus.irqstatus2=0xE0;
// gus.irqstatus&=~0x20;
if (!gus.irqstatus) picintc(0x20);
}
int gusirqnext=0;
void writegus(uint16_t addr, uint8_t val)
{
int c,d;
// printf("Write GUS %04X %02X %04X:%04X\n",addr,val,CS,pc);
switch (addr)
{
case 0x342: /*Voice select*/
gus.voice=val&31;
break;
case 0x343: /*Global select*/
gus.global=val;
break;
case 0x344: /*Global low*/
// if (gus.global!=0x43 && gus.global!=0x44) printf("Writing register %02X %02X %02X\n",gus.global,gus.voice,val);
switch (gus.global)
{
case 0: /*Voice control*/
// if (val&1 && !(gus.ctrl[gus.voice]&1)) printf("Voice on %i\n",gus.voice);
gus.ctrl[gus.voice]=val;
break;
case 1: /*Frequency control*/
gus.freq[gus.voice]=(gus.freq[gus.voice]&0xFF00)|val;
break;
case 2: /*Start addr high*/
gus.startx[gus.voice]=(gus.startx[gus.voice]&0xF807F)|(val<<7);
gus.start[gus.voice]=(gus.start[gus.voice]&0x1F00FFFF)|(val<<16);
// printf("Write %i start %08X %08X\n",gus.voice,gus.start[gus.voice],gus.startx[gus.voice]);
break;
case 3: /*Start addr low*/
gus.start[gus.voice]=(gus.start[gus.voice]&0x1FFFFF00)|val;
// printf("Write %i start %08X %08X\n",gus.voice,gus.start[gus.voice],gus.startx[gus.voice]);
break;
case 4: /*End addr high*/
gus.endx[gus.voice]=(gus.endx[gus.voice]&0xF807F)|(val<<7);
gus.end[gus.voice]=(gus.end[gus.voice]&0x1F00FFFF)|(val<<16);
// printf("Write %i end %08X %08X\n",gus.voice,gus.end[gus.voice],gus.endx[gus.voice]);
break;
case 5: /*End addr low*/
gus.end[gus.voice]=(gus.end[gus.voice]&0x1FFFFF00)|val;
// printf("Write %i end %08X %08X\n",gus.voice,gus.end[gus.voice],gus.endx[gus.voice]);
break;
case 0x6: /*Ramp frequency*/
gus.rfreq[gus.voice] = (int)( (double)((val & 63)*512)/(double)(1 << (3*(val >> 6))));
// printf("RFREQ %02X %i %i %f\n",val,gus.voice,gus.rfreq[gus.voice],(double)(val & 63)/(double)(1 << (3*(val >> 6))));
break;
case 0x9: /*Current volume*/
gus.curvol[gus.voice]=gus.rcur[gus.voice]=(gus.rcur[gus.voice]&0x1FE0000)|(val<<9);
// printf("Vol %i is %04X\n",gus.voice,gus.curvol[gus.voice]);
break;
case 0xA: /*Current addr high*/
gus.cur[gus.voice]=(gus.cur[gus.voice]&0x1F00FFFF)|(val<<16);
gus.curx[gus.voice]=(gus.curx[gus.voice]&0xF807F00)|((val<<7)<<8);
// gus.cur[gus.voice]=(gus.cur[gus.voice]&0x0F807F00)|((val<<7)<<8);
// printf("Write %i cur %08X\n",gus.voice,gus.cur[gus.voice],gus.curx[gus.voice]);
break;
case 0xB: /*Current addr low*/
gus.cur[gus.voice]=(gus.cur[gus.voice]&0x1FFFFF00)|val;
// printf("Write %i cur %08X\n",gus.voice,gus.cur[gus.voice],gus.curx[gus.voice]);
break;
case 0x42: /*DMA address low*/
gus.dmaaddr=(gus.dmaaddr&0xFF000)|(val<<4);
break;
case 0x43: /*Address low*/
gus.addr=(gus.addr&0xFFF00)|val;
break;
case 0x45: /*Timer control*/
// printf("Timer control %02X\n",val);
gus.tctrl=val;
break;
}
break;
case 0x345: /*Global high*/
// if (gus.global!=0x43 && gus.global!=0x44) printf("HWriting register %02X %02X %02X %04X:%04X\n",gus.global,gus.voice,val,CS,pc);
switch (gus.global)
{
case 0: /*Voice control*/
if (!(val&1) && gus.ctrl[gus.voice]&1)
{
// printf("Voice on %i - start %05X end %05X freq %04X\n",gus.voice,gus.start[gus.voice],gus.end[gus.voice],gus.freq[gus.voice]);
// if (val&0x40) gus.cur[gus.voice]=gus.end[gus.voice]<<8;
// else gus.cur[gus.voice]=gus.start[gus.voice]<<8;
}
if (val&2) val|=1;
gus.waveirqs[gus.voice]=val&0x80;
gus.ctrl[gus.voice]=val&0x7F;
pollgusirqs();
break;
case 1: /*Frequency control*/
gus.freq[gus.voice]=(gus.freq[gus.voice]&0xFF)|(val<<8);
break;
case 2: /*Start addr high*/
gus.startx[gus.voice]=(gus.startx[gus.voice]&0x07FFF)|(val<<15);
gus.start[gus.voice]=(gus.start[gus.voice]&0x00FFFFFF)|((val&0x1F)<<24);
// printf("Write %i start %08X %08X %02X\n",gus.voice,gus.start[gus.voice],gus.startx[gus.voice],val);
break;
case 3: /*Start addr low*/
gus.startx[gus.voice]=(gus.startx[gus.voice]&0xFFF80)|(val&0x7F);
gus.start[gus.voice]=(gus.start[gus.voice]&0x1FFF00FF)|(val<<8);
// printf("Write %i start %08X %08X\n",gus.voice,gus.start[gus.voice],gus.startx[gus.voice]);
break;
case 4: /*End addr high*/
gus.endx[gus.voice]=(gus.endx[gus.voice]&0x07FFF)|(val<<15);
gus.end[gus.voice]=(gus.end[gus.voice]&0x00FFFFFF)|((val&0x1F)<<24);
// printf("Write %i end %08X %08X %02X\n",gus.voice,gus.end[gus.voice],gus.endx[gus.voice],val);
break;
case 5: /*End addr low*/
gus.endx[gus.voice]=(gus.endx[gus.voice]&0xFFF80)|(val&0x7F);
gus.end[gus.voice]=(gus.end[gus.voice]&0x1FFF00FF)|(val<<8);
// printf("Write %i end %08X %08X\n",gus.voice,gus.end[gus.voice],gus.endx[gus.voice]);
break;
case 0x6: /*Ramp frequency*/
gus.rfreq[gus.voice] = (int)( (double)((val & 63)*512)/(double)(1 << (3*(val >> 6))));
// printf("RFREQ %02X %i %i %f %i\n",val,gus.voice,gus.rfreq[gus.voice],(double)(val & 63)/(double)(1 << (3*(val >> 6))),ins);
break;
case 0x7: /*Ramp start*/
gus.rstart[gus.voice]=val<<17;
break;
case 0x8: /*Ramp end*/
gus.rend[gus.voice]=val<<17;
break;
case 0x9: /*Current volume*/
gus.curvol[gus.voice]=gus.rcur[gus.voice]=(gus.rcur[gus.voice]&0x1FE00)|(val<<17);
// printf("Vol %i is %04X\n",gus.voice,gus.curvol[gus.voice]);
break;
case 0xA: /*Current addr high*/
gus.cur[gus.voice]=(gus.cur[gus.voice]&0x00FFFFFF)|((val&0x1F)<<24);
gus.curx[gus.voice]=(gus.curx[gus.voice]&0x07FFF00)|((val<<15)<<8);
// printf("Write %i cur %08X %08X %02X\n",gus.voice,gus.cur[gus.voice],gus.curx[gus.voice],val);
// gus.cur[gus.voice]=(gus.cur[gus.voice]&0x007FFF00)|((val<<15)<<8);
break;
case 0xB: /*Current addr low*/
gus.cur[gus.voice]=(gus.cur[gus.voice]&0x1FFF00FF)|(val<<8);
gus.curx[gus.voice]=(gus.curx[gus.voice]&0xFFF8000)|((val&0x7F)<<8);
// gus.cur[gus.voice]=(gus.cur[gus.voice]&0x0FFF8000)|((val&0x7F)<<8);
// printf("Write %i cur %08X %08X\n",gus.voice,gus.cur[gus.voice],gus.curx[gus.voice]);
break;
case 0xD: /*Ramp control*/
if (val&2) val|=1;
gus.rampirqs[gus.voice]=val&0x80;
gus.rctrl[gus.voice]=val&0x7F;
pollgusirqs();
// printf("Ramp control %02i %02X %02X %i\n",gus.voice,val,gus.rampirqs[gus.voice],ins);
break;
case 0xE:
gus.voices=(val&63)+1;
if (gus.voices>32) gus.voices=32;
if (gus.voices<14) gus.voices=14;
gus.global=val;
// printf("GUS voices %i\n",val&31);
break;
case 0x41: /*DMA*/
if (val&1)
{
// printf("DMA start! %05X %02X\n",gus.dmaaddr,val);
c=0;
while (c<65536)
{
d=readdma3();
if (d==-1) break;
if (val&0x80) d^=0x80;
gusram[gus.dmaaddr]=d;
gus.dmaaddr++;
gus.dmaaddr&=0xFFFFF;
c++;
}
// printf("Transferred %i bytes\n",c);
gus.dmactrl=val&~0x40;
if (val&0x20) gusirqnext=1;
// exit(-1);
}
break;
case 0x42: /*DMA address low*/
gus.dmaaddr=(gus.dmaaddr&0xFF0)|(val<<12);
break;
case 0x43: /*Address low*/
gus.addr=(gus.addr&0xF00FF)|(val<<8);
break;
case 0x44: /*Address high*/
gus.addr=(gus.addr&0xFFFF)|((val<<16)&0xF0000);
break;
case 0x45: /*Timer control*/
if (!(val&4)) gus.irqstatus&=~4;
if (!(val&8)) gus.irqstatus&=~8;
// printf("Timer control %02X\n",val);
/* if ((val&4) && !(gus.tctrl&4))
{
gus.t1=gus.t1l;
gus.t1on=1;
}*/
gus.tctrl=val;
break;
case 0x46: /*Timer 1*/
gus.t1=gus.t1l=val;
gus.t1on=1;
// printf("GUS timer 1 %i\n",val);
break;
case 0x47: /*Timer 2*/
gus.t2=gus.t2l=val<<2;
gus.t2on=1;
// printf("GUS timer 2 %i\n",val);
break;
}
break;
case 0x347: /*DRAM access*/
gusram[gus.addr]=val;
// pclog("GUS RAM write %05X %02X\n",gus.addr,val);
gus.addr&=0xFFFFF;
break;
case 0x248: case 0x388: gus.adcommand=val; break;
}
}
uint8_t readgus(uint16_t addr)
{
uint8_t val;
// /*if (addr!=0x246) */printf("Read GUS %04X %04X(%06X):%04X %02X\n",addr,CS,cs,pc,gus.global);
// output=3;
switch (addr)
{
case 0x240: return 0;
case 0x246: /*IRQ status*/
val=gus.irqstatus;
// printf("246 status %02X\n",val);
// gus.irqstatus=0;
// if (gus.irqstatus2==0xE0) picintc(0x20);
return val;
case 0x24A:
return gus.adcommand;
case 0x24B: case 0x24F: return 0;
case 0x340: /*MIDI status*/
case 0x341: /*MIDI data*/
return 0;
case 0x342: return gus.voice;
case 0x343: return gus.global;
case 0x344: /*Global low*/
// /*if (gus.global!=0x43 && gus.global!=0x44) */printf("Reading register %02X %02X\n",gus.global,gus.voice);
switch (gus.global)
{
case 0x82: /*Start addr high*/
return gus.start[gus.voice]>>16;
case 0x83: /*Start addr low*/
return gus.start[gus.voice]&0xFF;
case 0x89: /*Current volume*/
return gus.rcur[gus.voice]>>9;
case 0x8A: /*Current addr high*/
return gus.cur[gus.voice]>>16;
case 0x8B: /*Current addr low*/
return gus.cur[gus.voice]&0xFF;
case 0x8F: /*IRQ status*/
val=gus.irqstatus2;
// pclog("Read IRQ status - %02X\n",val);
gus.rampirqs[gus.irqstatus2&0x1F]=0;
gus.waveirqs[gus.irqstatus2&0x1F]=0;
pollgusirqs();
return val;
}
//fatal("Bad GUS global low read %02X\n",gus.global);
break;
case 0x345: /*Global high*/
// /*if (gus.global!=0x43 && gus.global!=0x44) */printf("HReading register %02X %02X\n",gus.global,gus.voice);
switch (gus.global)
{
case 0x80: /*Voice control*/
return gus.ctrl[gus.voice]|(gus.waveirqs[gus.voice]?0x80:0);
case 0x82: /*Start addr high*/
return gus.start[gus.voice]>>24;
case 0x83: /*Start addr low*/
return gus.start[gus.voice]>>8;
case 0x89: /*Current volume*/
return gus.rcur[gus.voice]>>17;
case 0x8A: /*Current addr high*/
return gus.cur[gus.voice]>>24;
case 0x8B: /*Current addr low*/
return gus.cur[gus.voice]>>8;
case 0x8D:
// pclog("Read ramp control %02X %08X %08X %08X %08X\n",gus.rctrl[gus.voice]|(gus.rampirqs[gus.voice]?0x80:0),gus.rcur[gus.voice],gus.rfreq[gus.voice],gus.rstart[gus.voice],gus.rend[gus.voice]);
return gus.rctrl[gus.voice]|(gus.rampirqs[gus.voice]?0x80:0);
case 0x8F: /*IRQ status*/
val=gus.irqstatus2;
// pclog("Read IRQ status - %02X\n",val);
gus.rampirqs[gus.irqstatus2&0x1F]=0;
gus.waveirqs[gus.irqstatus2&0x1F]=0;
pollgusirqs();
return val;
case 0x41: /*DMA control*/
val=gus.dmactrl|((gus.irqstatus&0x80)?0x40:0);
gus.irqstatus&=~0x80;
return val;
case 0x45: /*Timer control*/
return gus.tctrl;
case 0x49: /*Sampling control*/
return 0;
}
//fatal("Bad GUS global high read %02X\n",gus.global);
break;
case 0x346: return 0;
case 0x347: /*DRAM access*/
val=gusram[gus.addr];
// pclog("GUS RAM read %05X %02X\n",gus.addr,val);
// output=3;
gus.addr&=0xFFFFF;
return val;
case 0x349: return 0;
}
// printf("Bad GUS read %04X! %02X\n",addr,gus.global);
// exit(-1);
return 0;
}
void pollgus()
{
if (gus.t1on)
{
gus.t1++;
if (gus.t1>=0xFF)
{
// gus.t1on=0;
gus.t1=gus.t1l;
if (gus.tctrl&4)
{
picintlevel(0x20);
gus.irqstatus|=4;
// printf("GUS T1 IRQ!\n");
}
}
}
if (gusirqnext)
{
gusirqnext=0;
gus.irqstatus|=0x80;
picintlevel(0x20);
}
}
void pollgus2()
{
if (gus.t2on)
{
gus.t2++;
if (gus.t2>=(0xFF<<2))
{
// gus.t2on=0;
gus.t2=gus.t2l;
if (gus.tctrl&8)
{
picintlevel(0x20);
gus.irqstatus|=8;
// printf("GUS T2 IRQ!\n");
}
}
}
if (gusirqnext)
{
gusirqnext=0;
gus.irqstatus|=0x80;
picintlevel(0x20);
}
}
float gusfreqs[]=
{
44100,41160,38587,36317,34300,32494,30870,29400,28063,26843,25725,24696,
23746,22866,22050,21289,20580,19916,19293
};
int16_t gusbufferx[65536];
int guspos=0;
void getgus(int16_t *p, int count)
{
memcpy(p,gusbufferx,count*4);
// printf("Get %i samples %i\n",guspos,count);
guspos=0;
pollgusirqs();
}
void pollgussamp()
{
uint32_t addr;
int c,d;
int16_t v;
int32_t vl;
int16_t p[2];
float GUSRATECONST;
if (guspos>65500) return;
// return;
if (gus.voices<14) GUSRATECONST=44100.0/48000.0;
else GUSRATECONST=gusfreqs[gus.voices-14]/48000.0;
// printf("Voices %i freq %f\n",gus.voices,GUSRATECONST*48000.0);
// for (c=0;c<count;c++)
// {
p[0]=p[1]=0;
for (d=0;d<32;d++)
{
if (!(gus.ctrl[d]&1))
{
if (gus.ctrl[d]&4)
{
addr=gus.cur[d]>>9;
addr=(addr&0xC0000)|((addr<<1)&0x3FFFE);
if (!(gus.freq[d]>>10)) /*Interpolate*/
{
vl=(int16_t)(int8_t)((gusram[(addr+1)&0xFFFFF]^0x80)-0x80)*(511-(gus.cur[d]&511));
vl+=(int16_t)(int8_t)((gusram[(addr+3)&0xFFFFF]^0x80)-0x80)*(gus.cur[d]&511);
v=vl>>9;
}
else
v=(int16_t)(int8_t)((gusram[(addr+1)&0xFFFFF]^0x80)-0x80);
}
else
{
if (!(gus.freq[d]>>10)) /*Interpolate*/
{
vl=((int8_t)((gusram[(gus.cur[d]>>9)&0xFFFFF]^0x80)-0x80))*(511-(gus.cur[d]&511));
vl+=((int8_t)((gusram[((gus.cur[d]>>9)+1)&0xFFFFF]^0x80)-0x80))*(gus.cur[d]&511);
v=vl>>9;
}
else
v=(int16_t)(int8_t)((gusram[(gus.cur[d]>>9)&0xFFFFF]^0x80)-0x80);
}
// v=(int16_t)((float)((gusram[(gus.cur[d]>>9)&0xFFFFF]^0x80)-0x80)*32.0*vol16bit[(gus.rcur[d]>>13)&4095]);
if ((gus.rcur[d]>>13)>4095) v=(int16_t)(float)(v)*24.0*vol16bit[4095];
else v=(int16_t)(float)(v)*24.0*vol16bit[(gus.rcur[d]>>13)&4095];
// if (!d) printf("%08X %08X %08X %05X %08X %08X %04X %f %04X %08X %i\n",gus.cur[d],gus.start[d],gus.end[d],gus.cur[d]>>9,gus.startx[d],gus.endx[d],gus.rcur[d],vol16bit[0],v,gus.freq[d],ins);
// if (!d)
// {
p[0]+=v;
p[1]+=v;
// }
// printf("Data from %08X\n",gus.cur[d]>>8);
if (gus.ctrl[d]&0x40)
{
gus.cur[d]-=(gus.freq[d]>>1)*GUSRATECONST;
if (gus.cur[d]<=gus.start[d])
{
if (!(gus.rctrl[d]&4))
{
if (!(gus.ctrl[d]&8)) gus.ctrl[d]|=1;
else if (gus.ctrl[d]&0x10) gus.ctrl[d]^=0x40;
gus.cur[d]=(gus.ctrl[d]&0x40)?gus.end[d]:gus.start[d];
}
if (gus.ctrl[d]&0x20) gus.waveirqs[d]=1;
}
}
else
{
gus.cur[d]+=(gus.freq[d]>>1)*GUSRATECONST;
// pclog("GUS add %08X %f\n",gus.freq[d],GUSRATECONST);
if (gus.cur[d]>=gus.end[d])
{
if (!(gus.rctrl[d]&4))
{
// gus.ctrl[d]|=1;
if (!(gus.ctrl[d]&8)) gus.ctrl[d]|=1;
else if (gus.ctrl[d]&0x10) gus.ctrl[d]^=0x40;
gus.cur[d]=(gus.ctrl[d]&0x40)?gus.end[d]:gus.start[d];
}
if (gus.ctrl[d]&0x20) gus.waveirqs[d]=1;
}
}
}
if (!(gus.rctrl[d]&1))
{
if (gus.rctrl[d]&0x40)
{
gus.rcur[d]-=gus.rfreq[d]*GUSRATECONST*16;
// printf("RCUR- %i %i %i %i %i\n",d,gus.rfreq[d],gus.rcur[d],gus.rstart[d],gus.rend[d]);
if (gus.rcur[d]<=gus.rstart[d])
{
if (gus.rctrl[d]&8) gus.rcur[d]=gus.rend[d]<<8;
else gus.rctrl[d]|=1;
if (gus.rctrl[d]&0x20)
{
gus.rampirqs[d]=1;
// pclog("Causing ramp IRQ %02X\n",gus.rctrl[d]);
}
}
}
else
{
gus.rcur[d]+=gus.rfreq[d]*GUSRATECONST*16;
// printf("RCUR+ %i %08X %08X %08X %08X\n",d,gus.rfreq[d],gus.rcur[d],gus.rstart[d],gus.rend[d]);
if (gus.rcur[d]>=gus.rend[d])
{
if (gus.rctrl[d]&8) gus.rcur[d]=gus.rstart[d]<<8;
else gus.rctrl[d]|=1;
if (gus.rctrl[d]&0x20)
{
gus.rampirqs[d]=1;
// pclog("Causing ramp IRQ %02X\n",gus.rctrl[d]);
}
}
}
}
}
gusbufferx[guspos++]=p[0];
gusbufferx[guspos++]=p[1];
if (guspos==65536) guspos=0;
// }
pollgusirqs();
}
void gus_init()
{
io_sethandler(0x0240, 0x0010, readgus, NULL, NULL, writegus, NULL, NULL);
io_sethandler(0x0340, 0x0010, readgus, NULL, NULL, writegus, NULL, NULL);
io_sethandler(0x0388, 0x0001, NULL, NULL, NULL, writegus, NULL, NULL);
}

155
src/harddisk.c Normal file
View file

@ -0,0 +1,155 @@
/*Due to the lack of a real hard disc BIOS (other than the WD ST-506 one in MESS),
I wrote this. It's better as it can handle bigger discs, but is (potentially)
less compatible.*/
#include <stdio.h>
#include <string.h>
#include "ibm.h"
extern int output;
void inithdc()
{
return;
hdc[0].f=romfopen("hdc.img","rb+");
if (!hdc[0].f)
{
hdc[0].f=romfopen("hdc.img","wb");
putc(0,hdc[0].f);
fclose(hdc[0].f);
hdc[0].f=romfopen("hdc.img","rb+");
}
// hdc[0].spt=16;
// hdc[0].hpc=5;
// hdc[0].tracks=977;
hdc[1].f=romfopen("hdd.img","rb+");
if (!hdc[1].f)
{
hdc[1].f=romfopen("hdd.img","wb");
putc(0,hdc[1].f);
fclose(hdc[1].f);
hdc[1].f=romfopen("hdd.img","rb+");
}
// hdc[1].spt=32;
// hdc[1].hpc=16;
// hdc[1].tracks=447;
}
void int13hdc()
{
int drv=DL&1;
int track,head,sector;
uint32_t addr;
int c,d;
uint8_t buf[512];
fullspeed();
// ram[0x475]=2;
// printf("INT 13 HDC %04X %04X %04X %04X %04X:%04X\n",AX,BX,CX,DX,CS,pc);
switch (AH)
{
case 0: /*Reset disk system*/
AH=0;
flags&=~C_FLAG;
break;
case 2: /*Read sectors into memory*/
// printf("Read %i sectors to %04X:%04X\n",AL,es>>4,BX);
// if (es==0xf940) output=3;
track=CH|((CL&0xC0)<<2);
sector=(CL&63)-1;
head=DH;
addr=((((track*hdc[drv].hpc)+head)*hdc[drv].spt)+sector)*512;
// printf("Read track %i head %i sector %i addr %08X HPC %i SPT %i %08X\n",track,head,sector,addr,hdc[drv].hpc,hdc[drv].spt,old8);
fseek(hdc[drv].f,addr,SEEK_SET);
for (c=0;c<AL;c++)
{
fread(buf,512,1,hdc[drv].f);
for (d=0;d<512;d++)
{
writemembl(es+BX+(c*512)+d,buf[d]/*getc(hdc[drv].f)*/);
}
}
AH=0;
flags&=~C_FLAG;
readflash=1;
break;
case 3: /*Write sectors*/
track=CH|((CL&0xC0)<<2);
sector=(CL&63)-1;
head=DH;
addr=((((track*hdc[drv].hpc)+head)*hdc[drv].spt)+sector)*512;
fseek(hdc[drv].f,addr,SEEK_SET);
for (c=0;c<AL;c++)
{
for (d=0;d<512;d++)
{
putc(readmembl(es+BX+(c*512)+d),hdc[drv].f);
}
}
AH=0;
flags&=~C_FLAG;
readflash=1;
break;
case 4: /*Verify sectors*/
AH=0; /*We don't actually do anything here*/
flags&=~C_FLAG;
break;
case 8: /*Get drive parameters*/
AH=0;
CH=hdc[drv].tracks&255;
CL=hdc[drv].spt;
CL|=((hdc[drv].tracks>>2)&0xC0);
// printf("Drive params - %02X %02X %i %i\n",CL,CH,hdc[drv].tracks,hdc[drv].spt);
DH=hdc[drv].hpc-1;
DL=2;
flags&=~C_FLAG;
break;
case 0x10: /*Check drive ready*/
AH=0;
flags&=~C_FLAG;
break;
case 0x18: /*Set media type*/
AH=1;
flags|=C_FLAG;
break;
default:
AH=1;
flags|=C_FLAG;
// printf("Bad HDC int 13 %04X\n",AX);
// dumpregs();
// exit(-1);
}
}
char tempbuf[512*63];
void resizedrive(int drv)
{
FILE *f;
int c,d,e;
// char temp[512*63];
if (!drv)
{
fflush(hdc[0].f);
if (hdc[0].f) fclose(hdc[0].f);
f=romfopen("hdc.img","wb");
}
else
{
fflush(hdc[1].f);
if (hdc[1].f) fclose(hdc[1].f);
f=romfopen("hdd.img","wb");
}
memset(tempbuf,0,512*63);
for (c=0;c<hdc[drv].tracks;c++)
{
for (d=0;d<hdc[drv].hpc;d++)
{
// for (e=0;e<hdc[drv].spt;e++)
// {
fwrite(tempbuf,512*hdc[drv].spt,1,f);
// }
}
}
fclose(f);
if (!drv) hdc[0].f=romfopen("hdc.img","rb+");
else hdc[1].f=romfopen("hdd.img","rb+");
}

45
src/headland.c Normal file
View file

@ -0,0 +1,45 @@
#include "ibm.h"
#include "io.h"
#include "mem.h"
#include "cpu.h"
#include "headland.h"
static int headland_index;
static uint8_t headland_regs[256];
void headland_write(uint16_t addr, uint8_t val)
{
if (addr & 1)
{
if (headland_index == 0xc1 && !is486) val = 0;
headland_regs[headland_index] = val;
pclog("Headland write %02X %02X\n",headland_index,val);
if (headland_index == 0x82)
{
shadowbios = val & 0x10;
shadowbios_write = !(val & 0x10);
if (shadowbios)
mem_sethandler(0xf0000, 0x10000, mem_read_ram, mem_read_ramw, mem_read_raml, NULL, NULL, NULL );
else
mem_sethandler(0xf0000, 0x10000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_ram, mem_write_ramw, mem_write_raml);
}
}
else headland_index = val;
}
uint8_t headland_read(uint16_t addr)
{
if (addr & 1)
{
if ((headland_index >= 0xc0 || headland_index == 0x20) && cpu_iscyrix)
return 0xff; /*Don't conflict with Cyrix config registers*/
return headland_regs[headland_index];
}
return headland_index;
}
void headland_init()
{
io_sethandler(0x0022, 0x0002, headland_read, NULL, NULL, headland_write, NULL, NULL);
}

1
src/headland.h Normal file
View file

@ -0,0 +1 @@
void headland_init();

468
src/ibm.h Normal file
View file

@ -0,0 +1,468 @@
#include <stdio.h>
#include <stdint.h>
#define printf pclog
/*Memory*/
uint8_t *ram,*vram;
unsigned char isram[0x10000];
uint32_t rammask;
int readlookup[256],readlookupp[256];
uint32_t *readlookup2;
int readlnext;
int writelookup[256],writelookupp[256];
uint32_t *writelookup2;
int writelnext;
extern int mmu_perm;
#define readmemb(a) ((readlookup2[(a)>>12]==0xFFFFFFFF)?readmembl(a):ram[readlookup2[(a)>>12]+((a)&0xFFF)])
#define readmemw(s,a) ((readlookup2[((s)+(a))>>12]==0xFFFFFFFF || (s)==0xFFFFFFFF || (((s)+(a))&0xFFF)>0xFFE)?readmemwl(s,a):*((uint16_t *)(&ram[readlookup2[((s)+(a))>>12]+(((s)+(a))&0xFFF)])))
#define readmeml(s,a) ((readlookup2[((s)+(a))>>12]==0xFFFFFFFF || (s)==0xFFFFFFFF || (((s)+(a))&0xFFF)>0xFFC)?readmemll(s,a):*((uint32_t *)(&ram[readlookup2[((s)+(a))>>12]+(((s)+(a))&0xFFF)])))
//#define writememb(a,v) if (writelookup2[(a)>>12]==0xFFFFFFFF) writemembl(a,v); else ram[writelookup2[(a)>>12]+((a)&0xFFF)]=v
//#define writememw(s,a,v) if (writelookup2[((s)+(a))>>12]==0xFFFFFFFF || (s)==0xFFFFFFFF) writememwl(s,a,v); else *((uint16_t *)(&ram[writelookup2[((s)+(a))>>12]+(((s)+(a))&0xFFF)]))=v
//#define writememl(s,a,v) if (writelookup2[((s)+(a))>>12]==0xFFFFFFFF || (s)==0xFFFFFFFF) writememll(s,a,v); else *((uint32_t *)(&ram[writelookup2[((s)+(a))>>12]+(((s)+(a))&0xFFF)]))=v
//#define readmemb(a) ((isram[((a)>>16)&255] && !(cr0>>31))?ram[a&0xFFFFFF]:readmembl(a))
//#define writememb(a,v) if (isram[((a)>>16)&255] && !(cr0>>31)) ram[a&0xFFFFFF]=v; else writemembl(a,v)
//void writememb(uint32_t addr, uint8_t val);
uint8_t readmembl(uint32_t addr);
void writemembl(uint32_t addr, uint8_t val);
uint8_t readmemb386l(uint32_t seg, uint32_t addr);
void writememb386l(uint32_t seg, uint32_t addr, uint8_t val);
uint16_t readmemwl(uint32_t seg, uint32_t addr);
void writememwl(uint32_t seg, uint32_t addr, uint16_t val);
uint32_t readmemll(uint32_t seg, uint32_t addr);
void writememll(uint32_t seg, uint32_t addr, uint32_t val);
uint8_t *getpccache(uint32_t a);
uint32_t mmutranslatereal(uint32_t addr, int rw);
void addreadlookup(uint32_t virt, uint32_t phys);
void addwritelookup(uint32_t virt, uint32_t phys);
/*IO*/
uint8_t inb(uint16_t port);
void outb(uint16_t port, uint8_t val);
uint16_t inw(uint16_t port);
void outw(uint16_t port, uint16_t val);
uint32_t inl(uint16_t port);
void outl(uint16_t port, uint32_t val);
FILE *romfopen(char *fn, char *mode);
extern int shadowbios,shadowbios_write;
extern int cache;
extern int mem_size;
extern int readlnum,writelnum;
extern int memwaitstate;
/*Processor*/
#define EAX regs[0].l
#define ECX regs[1].l
#define EDX regs[2].l
#define EBX regs[3].l
#define ESP regs[4].l
#define EBP regs[5].l
#define ESI regs[6].l
#define EDI regs[7].l
#define AX regs[0].w
#define CX regs[1].w
#define DX regs[2].w
#define BX regs[3].w
#define SP regs[4].w
#define BP regs[5].w
#define SI regs[6].w
#define DI regs[7].w
#define AL regs[0].b.l
#define AH regs[0].b.h
#define CL regs[1].b.l
#define CH regs[1].b.h
#define DL regs[2].b.l
#define DH regs[2].b.h
#define BL regs[3].b.l
#define BH regs[3].b.h
typedef union
{
uint32_t l;
uint16_t w;
struct
{
uint8_t l,h;
} b;
} x86reg;
x86reg regs[8];
uint16_t flags,eflags;
uint32_t /*cs,ds,es,ss,*/oldds,oldss,pc,olddslimit,oldsslimit,olddslimitw,oldsslimitw;
//uint16_t msw;
extern int ins,output;
extern int cycdiff;
typedef struct
{
uint32_t base;
uint32_t limit,limitw;
uint8_t access;
uint16_t seg;
} x86seg;
x86seg gdt,ldt,idt,tr;
x86seg _cs,_ds,_es,_ss,_fs,_gs;
x86seg _oldds;
uint32_t pccache;
uint8_t *pccache2;
/*Segments -
_cs,_ds,_es,_ss are the segment structures
CS,DS,ES,SS is the 16-bit data
cs,ds,es,ss are defines to the bases*/
//uint16_t CS,DS,ES,SS;
#define CS _cs.seg
#define DS _ds.seg
#define ES _es.seg
#define SS _ss.seg
#define FS _fs.seg
#define GS _gs.seg
#define cs _cs.base
#define ds _ds.base
#define es _es.base
#define ss _ss.base
#define fs _fs.base
#define gs _gs.base
#define CPL ((_cs.access>>5)&3)
void loadseg(uint16_t seg, x86seg *s);
void loadcs(uint16_t seg);
union
{
uint32_t l;
uint16_t w;
} CR0;
#define cr0 CR0.l
#define msw CR0.w
uint32_t cr2,cr3;
#define C_FLAG 0x0001
#define P_FLAG 0x0004
#define A_FLAG 0x0010
#define Z_FLAG 0x0040
#define N_FLAG 0x0080
#define T_FLAG 0x0100
#define I_FLAG 0x0200
#define D_FLAG 0x0400
#define V_FLAG 0x0800
#define NT_FLAG 0x4000
#define VM_FLAG 0x0002 /*In EFLAGS*/
#define WP_FLAG 0x10000 /*In CR0*/
#define IOPL ((flags>>12)&3)
#define IOPLp ((!(msw&1)) || (CPL<=IOPL))
//#define IOPLp 1
//#define IOPLV86 ((!(msw&1)) || (CPL<=IOPL))
extern int cycles;
extern int cycles_lost;
extern int is486;
extern uint8_t opcode;
extern int insc;
extern int fpucount;
extern float mips,flops;
extern int clockrate;
extern int cgate16;
extern int CPUID;
extern int cpl_override;
/*Timer*/
typedef struct PIT
{
uint32_t l[3];
double c[3];
uint8_t m[3];
uint8_t ctrl,ctrls[2];
int wp,rm[3],wm[3];
uint16_t rl[3];
int thit[3];
int delay[3];
int rereadlatch[3];
} PIT;
PIT pit;
void setpitclock(float clock);
int pitcount;
float pit_timer0_freq();
/*DMA*/
typedef struct DMA
{
uint16_t ab[4],ac[4];
uint16_t cb[4];
int cc[4];
int wp;
uint8_t m,mode[4];
uint8_t page[4];
uint8_t stat;
uint8_t command;
} DMA;
DMA dma,dma16;
/*PPI*/
typedef struct PPI
{
int s2;
uint8_t pa,pb;
} PPI;
PPI ppi;
extern int key_inhibit;
/*PIC*/
typedef struct PIC
{
uint8_t icw1,mask,ins,pend,mask2;
int icw;
uint8_t vector;
int read;
} PIC;
PIC pic,pic2;
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;
} FDC;
FDC fdc;
int disctime;
char discfns[2][256];
int driveempty[2];
/*Config stuff*/
#define MDA ((gfxcard==GFX_MDA || gfxcard==GFX_HERCULES) && (romset<ROM_TANDY || romset>=ROM_IBMAT))
#define HERCULES (gfxcard==GFX_HERCULES && (romset<ROM_TANDY || romset>=ROM_IBMAT))
#define AMSTRAD (romset==ROM_PC1512 || romset==ROM_PC1640 || romset==ROM_PC3086)
#define AMSTRADIO (romset==ROM_PC1512 || romset==ROM_PC1640 || romset==ROM_PC200 || romset==ROM_PC2086 || romset == ROM_PC3086)
#define TANDY (romset==ROM_TANDY/* || romset==ROM_IBMPCJR*/)
#define VID_EGA (gfxcard==GFX_EGA)
#define EGA (romset==ROM_PC1640 || VID_EGA || VGA)
#define VGA ((gfxcard>=GFX_TVGA || romset==ROM_ACER386) && romset!=ROM_PC1640 && romset!=ROM_PC1512 && romset!=ROM_TANDY && romset!=ROM_PC200)
#define SVGA (gfxcard==GFX_ET4000 && VGA)
#define TRIDENT (gfxcard==GFX_TVGA && !OTI067)
#define OTI067 (romset==ROM_ACER386)
#define ET4000 (gfxcard==GFX_ET4000 && VGA)
#define ET4000W32 (gfxcard==GFX_ET4000W32 && VGA)
#define AT (romset>=ROM_IBMAT)
#define PCI (romset == ROM_PCI486)
#define AMIBIOS (romset==ROM_AMI386 || romset==ROM_AMI486 || romset == ROM_WIN486)
int FASTDISC;
int ADLIB;
int GAMEBLASTER;
enum
{
ROM_IBMPC = 0, /*301 keyboard error, 131 cassette (!!!) error*/
ROM_IBMXT, /*301 keyboard error*/
ROM_GENXT, /*'Generic XT BIOS'*/
ROM_DTKXT,
ROM_EUROPC,
ROM_OLIM24,
ROM_TANDY,
ROM_PC1512,
ROM_PC200,
ROM_PC1640,
ROM_PC2086,
ROM_PC3086,
ROM_IBMAT,
ROM_CMDPC30,
ROM_AMI286,
ROM_DELL200,
ROM_MISC286,
ROM_IBMAT386,
ROM_ACER386,
ROM_MEGAPC,
ROM_AMI386,
ROM_AMI486,
ROM_WIN486,
ROM_PCI486
};
//#define ROM_IBMPCJR 5 /*Not working! ROMs are corrupt*/
#define is386 (romset>=ROM_IBMAT386)
#define is386sx 0
int hasfpu;
int romset;
#define GFX_CGA 0
#define GFX_MDA 1
#define GFX_HERCULES 2
#define GFX_EGA 3 /*Using IBM EGA BIOS*/
//#define GFX_OTI067 3 /*Using BIOS from Acer 386SX/25N - edit - only works with Acer BIOS! Stupid integrated systems*/
#define GFX_TVGA 4 /*Using Trident 8900D BIOS*/
#define GFX_ET4000 5 /*Tseng ET4000*/
#define GFX_ET4000W32 6 /*Tseng ET4000/W32p (Diamond Stealth 32)*/
#define GFX_BAHAMAS64 7 /*S3 Vision864 (Paradise Bahamas 64)*/
#define GFX_N9_9FX 8 /*S3 764/Trio64 (Number Nine 9FX)*/
#define GFX_STEALTH64 9 /*S3 Vision964 (Diamond Stealth 64 VRAM PCI)*/
int gfxcard;
int cpuspeed;
/*Video*/
void (*pollvideo)();
void pollega();
int readflash;
uint8_t hercctrl;
int slowega,egacycles,egacycles2;
extern uint8_t gdcreg[16];
extern int incga;
extern int egareads,egawrites;
extern int cga_comp;
extern int vid_resize;
extern int winsizex,winsizey;
extern int chain4;
uint8_t readvram(uint16_t addr);
void writevram(uint16_t addr, uint8_t val);
void writevramgen(uint16_t addr, uint8_t val);
uint8_t readtandyvram(uint16_t addr);
void writetandy(uint16_t addr, uint8_t val);
void writetandyvram(uint16_t addr, uint8_t val);
extern int et4k_b8000;
extern int changeframecount;
extern uint8_t changedvram[(8192*1024)/1024];
void writeega_chain4(uint32_t addr, uint8_t val);
extern uint32_t svgarbank,svgawbank;
/*Serial*/
extern int mousedelay;
/*Sound*/
uint8_t spkstat;
float spktime,soundtime,gustime,gustime2,vidtime,rtctime;
int ppispeakon;
//#define SPKCONST (8000000.0/44100.0)
float SPKCONST;
float SOUNDCONST;
float CASCONST;
float GUSCONST,GUSCONST2;
float CGACONST;
float MDACONST;
float VGACONST1,VGACONST2;
float RTCCONST;
int gated,speakval,speakon;
#define SOUNDBUFLEN (48000/10)
/*Sound Blaster*/
int sbenable,sblatchi,sblatcho,sbcount,sb_enable_i,sb_count_i;
int16_t sbdat;
void setsbclock(float clock);
#define SADLIB 1 /*No DSP*/
#define SB1 2 /*DSP v1.05*/
#define SB15 3 /*DSP v2.00*/
#define SB2 4 /*DSP v2.01 - needed for high-speed DMA*/
#define SBPRO 5 /*DSP v3.00*/
#define SBPRO2 6 /*DSP v3.02 + OPL3*/
#define SB16 7 /*DSP v4.05 + OPL3*/
int sbtype;
struct
{
int vocl,vocr,voc;
int midl,midr,mid;
int masl,masr,mas;
} sbpmixer;
extern int sb_freq;
struct
{
int master_l,master_r;
int voice_l,voice_r;
int fm_l,fm_r;
int bass_l,bass_r;
int treble_l,treble_r;
int filter;
} mixer;
int clocks[3][12][4];
int at70hz;
char pcempath[512];
/*Hard disc*/
typedef struct
{
FILE *f;
int spt,hpc; /*Sectors per track, heads per cylinder*/
int tracks;
} PcemHDC;
PcemHDC hdc[2];
/*Keyboard*/
int keybsenddelay;
extern int kb_win;
/*CD-ROM*/
extern int cdrom_drive;
extern int idecallback[2];
extern int cdrom_enabled;
void pclog(const char *format, ...);
extern int nmi;
extern int times;
extern float isa_timing, bus_timing;

1757
src/ide.c Normal file

File diff suppressed because it is too large Load diff

42
src/ide.h Normal file
View file

@ -0,0 +1,42 @@
#ifndef __IDE__
#define __IDE__
struct IDE;
extern void writeide(int ide_board, uint16_t addr, uint8_t val);
extern void writeidew(int ide_board, uint16_t val);
extern uint8_t readide(int ide_board, uint16_t addr);
extern uint16_t readidew(int ide_board);
extern void callbackide(int ide_board);
extern void resetide(void);
extern void ide_init();
/*ATAPI stuff*/
typedef struct ATAPI
{
int (*ready)(void);
int (*readtoc)(uint8_t *b, uint8_t starttrack, int msf, int maxlen, int single);
void (*readtoc_session)(uint8_t *b, int msf, int maxlen);
uint8_t (*getcurrentsubchannel)(uint8_t *b, int msf);
void (*readsector)(uint8_t *b, int sector);
void (*playaudio)(uint32_t pos, uint32_t len, int ismsf);
void (*seek)(uint32_t pos);
void (*load)(void);
void (*eject)(void);
void (*pause)(void);
void (*resume)(void);
void (*stop)(void);
void (*exit)(void);
} ATAPI;
extern ATAPI *atapi;
void atapi_discchanged();
extern int ideboard;
extern int idecallback[2];
extern char ide_fn[2][512];
#endif //__IDE__

196
src/io.c Normal file
View file

@ -0,0 +1,196 @@
#include "ibm.h"
#include "ide.h"
#include "video.h"
#include "cpu.h"
uint8_t (*port_inb[0x10000][2])(uint16_t addr);
uint16_t (*port_inw[0x10000][2])(uint16_t addr);
uint32_t (*port_inl[0x10000][2])(uint16_t addr);
void (*port_outb[0x10000][2])(uint16_t addr, uint8_t val);
void (*port_outw[0x10000][2])(uint16_t addr, uint16_t val);
void (*port_outl[0x10000][2])(uint16_t addr, uint32_t val);
void io_init()
{
int c;
for (c = 0; c < 0x10000; c++)
{
port_inb[c][0] = port_inw[c][0] = port_inl[c][0] = NULL;
port_outb[c][0] = port_outw[c][0] = port_outl[c][0] = NULL;
port_inb[c][1] = port_inw[c][1] = port_inl[c][1] = NULL;
port_outb[c][1] = port_outw[c][1] = port_outl[c][1] = NULL;
}
}
void io_sethandler(uint16_t base, int size,
uint8_t (*inb)(uint16_t addr),
uint16_t (*inw)(uint16_t addr),
uint32_t (*inl)(uint16_t addr),
void (*outb)(uint16_t addr, uint8_t val),
void (*outw)(uint16_t addr, uint16_t val),
void (*outl)(uint16_t addr, uint32_t val))
{
int c;
for (c = 0; c < size; c++)
{
if (!port_inb[ base + c][0]) port_inb[ base + c][0] = inb;
else if (!port_inb[ base + c][1]) port_inb[ base + c][1] = inb;
if (!port_inw[ base + c][0]) port_inw[ base + c][0] = inw;
else if (!port_inw[ base + c][1]) port_inw[ base + c][1] = inw;
if (!port_inl[ base + c][0]) port_inl[ base + c][0] = inl;
else if (!port_inl[ base + c][1]) port_inl[ base + c][1] = inl;
if (!port_outb[base + c][0]) port_outb[base + c][0] = outb;
else if (!port_outb[base + c][1]) port_outb[base + c][1] = outb;
if (!port_outw[base + c][0]) port_outw[base + c][0] = outw;
else if (!port_outw[base + c][1]) port_outw[base + c][1] = outw;
if (!port_outl[base + c][0]) port_outl[base + c][0] = outl;
else if (!port_outl[base + c][1]) port_outl[base + c][1] = outl;
}
}
void io_removehandler(uint16_t base, int size,
uint8_t (*inb)(uint16_t addr),
uint16_t (*inw)(uint16_t addr),
uint32_t (*inl)(uint16_t addr),
void (*outb)(uint16_t addr, uint8_t val),
void (*outw)(uint16_t addr, uint16_t val),
void (*outl)(uint16_t addr, uint32_t val))
{
int c;
for (c = 0; c < size; c++)
{
if (port_inb[ base + c][0] == inb)
port_inb[ base + c][0] = NULL;
if (port_inb[ base + c][1] == inb)
port_inb[ base + c][1] = NULL;
if (port_inw[ base + c][0] == inw)
port_inw[ base + c][0] = NULL;
if (port_inw[ base + c][1] == inw)
port_inw[ base + c][1] = NULL;
if (port_inl[ base + c][0] == inl)
port_inl[ base + c][0] = NULL;
if (port_inl[ base + c][1] == inl)
port_inl[ base + c][1] = NULL;
if (port_outb[ base + c][0] == outb)
port_outb[ base + c][0] = NULL;
if (port_outb[ base + c][1] == outb)
port_outb[ base + c][1] = NULL;
if (port_outw[ base + c][0] == outw)
port_outw[ base + c][0] = NULL;
if (port_outw[ base + c][1] == outw)
port_outw[ base + c][1] = NULL;
if (port_outl[ base + c][0] == outl)
port_outl[ base + c][0] = NULL;
if (port_outl[ base + c][1] == outl)
port_outl[ base + c][1] = NULL;
}
}
uint8_t cgamode,cgastat=0,cgacol;
int hsync;
uint8_t lpt2dat;
int sw9;
int t237=0;
uint8_t inb(uint16_t port)
{
uint8_t temp = 0xff;
int tempi;
if (port_inb[port][0])
temp &= port_inb[port][0](port);
if (port_inb[port][1])
temp &= port_inb[port][1](port);
return temp;
if (port&0x80) sw9=2;
// if ((port&0x3F0)==0x3D0) printf("Video access read %03X %04X:%04X\n",port,cs>>4,pc);
// if (cs<0xF0000 || cs>0x100000) printf("IN %04X %04X(%06X):%08X\n",port,CS,cs,pc);
// /*if (output==3) */printf("IN %04X %04X:%04X\n",port,CS,pc);
// if (port == 0x23) pclog("IN %04X %04X:%08X\n", port, CS, pc);
switch (port)
{
case 0x220: case 0x221: case 0x222: case 0x223: /*Gameblaster*/
if (sbtype>=SBPRO) return readsb(port);
if (GAMEBLASTER) return readcms(port);
return 0xFF;
}
// printf("Bad IN port %04X %04X:%04X\n",port,cs>>4,pc);
return 0xff;
/*dumpregs();
exit(-1);*/
}
/*uint8_t inb(uint16_t port)
{
uint8_t temp = _inb(port);
// if (port != 0x61) pclog("IN %04X %02X %04X(%08X):%08X %f %04X %i %i\n", port, temp, CS, cs, pc, pit.c[1], CX, keybsenddelay, GetTickCount());
return temp;
}*/
uint8_t cpu_readport(uint32_t port) { return inb(port); }
void outb(uint16_t port, uint8_t val)
{
// /*if (output==3) */printf("OUT %04X %02X %04X(%08X):%08X %i %i\n", port, val, CS, cs, pc, ins, GetTickCount());
if (port_outb[port][0])
port_outb[port][0](port, val);
if (port_outb[port][1])
port_outb[port][1](port, val);
return;
switch (port)
{
case 0x220: case 0x221: case 0x222: case 0x223: /*Gameblaster*/
if (GAMEBLASTER) writecms(port,val);
return;
}
pclog("OUT %04X %02X %04X:%08X\n",port,val,CS,pc);
}
uint16_t inw(uint16_t port)
{
if (port_inw[port][0])
return port_inw[port][0](port);
if (port_inw[port][1])
return port_inw[port][1](port);
return inb(port) | (inb(port + 1) << 8);
}
void outw(uint16_t port, uint16_t val)
{
// printf("OUTW %04X %04X %04X:%08X\n",port,val, CS, pc);
if (port_outw[port][0])
port_outw[port][0](port, val);
if (port_outw[port][1])
port_outw[port][1](port, val);
if (port_outw[port][0] || port_outw[port][1])
return;
outb(port,val);
outb(port+1,val>>8);
}
uint32_t inl(uint16_t port)
{
if (port_inl[port][0])
return port_inl[port][0](port);
if (port_inl[port][1])
return port_inl[port][1](port);
return inw(port) | (inw(port + 2) << 16);
}
void outl(uint16_t port, uint32_t val)
{
if (port_outl[port][0])
port_outl[port][0](port, val);
if (port_outl[port][1])
port_outl[port][1](port, val);
if (port_outl[port][0] || port_outl[port][1])
return;
outw(port, val);
outw(port + 2, val >> 16);
}

17
src/io.h Normal file
View file

@ -0,0 +1,17 @@
void io_init();
void io_sethandler(uint16_t base, int size,
uint8_t (*inb)(uint16_t addr),
uint16_t (*inw)(uint16_t addr),
uint32_t (*inl)(uint16_t addr),
void (*outb)(uint16_t addr, uint8_t val),
void (*outw)(uint16_t addr, uint16_t val),
void (*outl)(uint16_t addr, uint32_t val));
void io_removehandler(uint16_t base, int size,
uint8_t (*inb)(uint16_t addr),
uint16_t (*inw)(uint16_t addr),
uint32_t (*inl)(uint16_t addr),
void (*outb)(uint16_t addr, uint8_t val),
void (*outw)(uint16_t addr, uint16_t val),
void (*outl)(uint16_t addr, uint32_t val));

78
src/jim.c Normal file
View file

@ -0,0 +1,78 @@
#include <stdio.h>
#include <string.h>
#include "ibm.h"
uint8_t europcdat[16];
struct
{
uint8_t dat[16];
int stat;
int addr;
} europc_rtc;
void writejim(uint16_t addr, uint8_t val)
{
if ((addr&0xFF0)==0x250) europcdat[addr&0xF]=val;
switch (addr)
{
case 0x25A:
// printf("Write RTC stat %i val %02X\n",europc_rtc.stat,val);
switch (europc_rtc.stat)
{
case 0:
europc_rtc.addr=val&0xF;
europc_rtc.stat++;
// printf("RTC addr now %02X - contents %02X\n",val&0xF,europc_rtc.dat[europc_rtc.addr]);
break;
case 1:
europc_rtc.dat[europc_rtc.addr]=(europc_rtc.dat[europc_rtc.addr]&0xF)|(val<<4);
europc_rtc.stat++;
break;
case 2:
europc_rtc.dat[europc_rtc.addr]=(europc_rtc.dat[europc_rtc.addr]&0xF0)|(val&0xF);
europc_rtc.stat=0;
break;
}
break;
}
// printf("Write JIM %04X %02X\n",addr,val);
}
uint8_t readjim(uint16_t addr)
{
// printf("Read JIM %04X\n",addr);
switch (addr)
{
case 0x250: case 0x251: case 0x252: case 0x253: return 0;
case 0x254: case 0x255: case 0x256: case 0x257: return europcdat[addr&0xF];
case 0x25A:
if (europc_rtc.stat==1)
{
europc_rtc.stat=2;
return europc_rtc.dat[europc_rtc.addr]>>4;
}
if (europc_rtc.stat==2)
{
europc_rtc.stat=0;
return europc_rtc.dat[europc_rtc.addr]&0xF;
}
return 0;
}
return 0;
}
void jim_init()
{
uint8_t viddat;
memset(europc_rtc.dat,0,16);
europc_rtc.dat[0xF]=1;
europc_rtc.dat[3]=1;
europc_rtc.dat[4]=1;
europc_rtc.dat[5]=0x88;
if (gfxcard==GFX_CGA) viddat=0x12;
else if (gfxcard==GFX_MDA || gfxcard==GFX_HERCULES) viddat=3;
else viddat=0x10;
europc_rtc.dat[0xB]=viddat;
europc_rtc.dat[0xD]=viddat; /*Checksum*/
io_sethandler(0x250, 0x10, readjim, NULL, NULL, writejim, NULL, NULL);
}

1
src/jim.h Normal file
View file

@ -0,0 +1 @@
void jim_init();

280
src/keyboard.c Normal file
View file

@ -0,0 +1,280 @@
#include "ibm.h"
#include "plat-keyboard.h"
#include "keyboard.h"
int keybsendcallback = 0;
typedef struct
{
int scancodes_make[8];
int scancodes_break[8];
} scancode;
static scancode scancode_set1[256] =
{
{ {-1}, {-1} }, { {0x01, -1}, {0x81, -1} }, { {0x02, -1}, {0x82, -1} }, { {0x03, -1}, {0x83, -1} },
{ {0x04, -1}, {0x84, -1} }, { {0x05, -1}, {0x85, -1} }, { {0x06, -1}, {0x86, -1} }, { {0x07, -1}, {0x87, -1} },
{ {0x08, -1}, {0x88, -1} }, { {0x09, -1}, {0x89, -1} }, { {0x0a, -1}, {0x8a, -1} }, { {0x0b, -1}, {0x8b, -1} },
{ {0x0c, -1}, {0x8c, -1} }, { {0x0d, -1}, {0x8d, -1} }, { {0x0e, -1}, {0x8e, -1} }, { {0x0f, -1}, {0x8f, -1} },
{ {0x10, -1}, {0x90, -1} }, { {0x11, -1}, {0x91, -1} }, { {0x12, -1}, {0x92, -1} }, { {0x13, -1}, {0x93, -1} },
{ {0x14, -1}, {0x94, -1} }, { {0x15, -1}, {0x95, -1} }, { {0x16, -1}, {0x96, -1} }, { {0x17, -1}, {0x97, -1} },
{ {0x18, -1}, {0x98, -1} }, { {0x19, -1}, {0x99, -1} }, { {0x1a, -1}, {0x9a, -1} }, { {0x1b, -1}, {0x9b, -1} },
{ {0x1c, -1}, {0x9c, -1} }, { {0x1d, -1}, {0x9d, -1} }, { {0x1e, -1}, {0x9e, -1} }, { {0x1f, -1}, {0x9f, -1} },
{ {0x20, -1}, {0xa0, -1} }, { {0x21, -1}, {0xa1, -1} }, { {0x22, -1}, {0xa2, -1} }, { {0x23, -1}, {0xa3, -1} },
{ {0x24, -1}, {0xa4, -1} }, { {0x25, -1}, {0xa5, -1} }, { {0x26, -1}, {0xa6, -1} }, { {0x27, -1}, {0xa7, -1} },
{ {0x28, -1}, {0xa8, -1} }, { {0x29, -1}, {0xa9, -1} }, { {0x2a, -1}, {0xaa, -1} }, { {0x2b, -1}, {0xab, -1} },
{ {0x2c, -1}, {0xac, -1} }, { {0x2d, -1}, {0xad, -1} }, { {0x2e, -1}, {0xae, -1} }, { {0x2f, -1}, {0xaf, -1} },
{ {0x30, -1}, {0xb0, -1} }, { {0x31, -1}, {0xb1, -1} }, { {0x32, -1}, {0xb2, -1} }, { {0x33, -1}, {0xb3, -1} },
{ {0x34, -1}, {0xb4, -1} }, { {0x35, -1}, {0xb5, -1} }, { {0x36, -1}, {0xb6, -1} }, { {0x37, -1}, {0xb7, -1} },
{ {0x38, -1}, {0xb8, -1} }, { {0x39, -1}, {0xb9, -1} }, { {0x3a, -1}, {0xba, -1} }, { {0x3b, -1}, {0xbb, -1} },
{ {0x3c, -1}, {0xbc, -1} }, { {0x3d, -1}, {0xbd, -1} }, { {0x3e, -1}, {0xbe, -1} }, { {0x3f, -1}, {0xbf, -1} },
{ {0x40, -1}, {0xc0, -1} }, { {0x41, -1}, {0xc1, -1} }, { {0x42, -1}, {0xc2, -1} }, { {0x43, -1}, {0xc3, -1} },
{ {0x44, -1}, {0xc4, -1} }, { {0x45, -1}, {0xc5, -1} }, { {0x46, -1}, {0xc6, -1} }, { {0x47, -1}, {0xc7, -1} },
{ {0x48, -1}, {0xc8, -1} }, { {0x49, -1}, {0xc9, -1} }, { {0x4a, -1}, {0xca, -1} }, { {0x4b, -1}, {0xcb, -1} },
{ {0x4c, -1}, {0xcc, -1} }, { {0x4d, -1}, {0xcd, -1} }, { {0x4e, -1}, {0xce, -1} }, { {0x4f, -1}, {0xcf, -1} },
{ {0x50, -1}, {0xd0, -1} }, { {0x51, -1}, {0xd1, -1} }, { {0x52, -1}, {0xd2, -1} }, { {0x53, -1}, {0xd3, -1} },
{ {0x54, -1}, {0xd4, -1} }, { {0x55, -1}, {0xd5, -1} }, { {0x56, -1}, {0xd6, -1} }, { {0x57, -1}, {0xd7, -1} },
{ {0x58, -1}, {0xd8, -1} }, { {0x59, -1}, {0xd9, -1} }, { {0x5a, -1}, {0xda, -1} }, { {0x5b, -1}, {0xdb, -1} },
{ {0x5c, -1}, {0xdc, -1} }, { {0x5d, -1}, {0xdd, -1} }, { {0x5e, -1}, {0xde, -1} }, { {0x5f, -1}, {0xdf, -1} },
{ {0x60, -1}, {0xe0, -1} }, { {0x61, -1}, {0xe1, -1} }, { {0x62, -1}, {0xe2, -1} }, { {0x63, -1}, {0xe3, -1} },
{ {0x64, -1}, {0xe4, -1} }, { {0x65, -1}, {0xe5, -1} }, { {0x66, -1}, {0xe6, -1} }, { {0x67, -1}, {0xe7, -1} },
{ {0x68, -1}, {0xe8, -1} }, { {0x69, -1}, {0xe9, -1} }, { {0x6a, -1}, {0xea, -1} }, { {0x6b, -1}, {0xeb, -1} },
{ {0x6c, -1}, {0xec, -1} }, { {0x6d, -1}, {0xed, -1} }, { {0x6e, -1}, {0xee, -1} }, { {0x6f, -1}, {0xef, -1} },
{ {0x70, -1}, {0xf0, -1} }, { {0x71, -1}, {0xf1, -1} }, { {0x72, -1}, {0xf2, -1} }, { {0x73, -1}, {0xf3, -1} },
{ {0x74, -1}, {0xf4, -1} }, { {0x75, -1}, {0xf5, -1} }, { {0x76, -1}, {0xf6, -1} }, { {0x77, -1}, {0xf7, -1} },
{ {0x78, -1}, {0xf8, -1} }, { {0x79, -1}, {0xf9, -1} }, { {0x7a, -1}, {0xfa, -1} }, { {0x7b, -1}, {0xfb, -1} },
{ {0x7c, -1}, {0xfc, -1} }, { {0x7d, -1}, {0xfd, -1} }, { {0x7e, -1}, {0xfe, -1} }, { {0x7f, -1}, {0xff, -1} },
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*80*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*84*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*88*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*8c*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*90*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*94*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*98*/
{ {0xe0, 0x1c, -1}, {0xe0, 0x9c, -1} }, { {0xe0, 0x1d, -1}, {0xe0, 0x9d, -1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*9c*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*a0*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*a4*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {0xe0, 0x2a, -1}, {0xe0, 0x8a, -1} }, { {-1}, {-1} }, /*a8*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*ac*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*b0*/
{ {-1}, {-1} }, { {0xe0, 0x35, -1}, {0xe0, 0xb5, -1} }, { {0xe0, 0x36, -1}, {0xe0, 0xb6, -1} }, { {0xe0, 0x37, -1}, {0xe0, 0xb7, -1} }, /*b4*/
{ {0xe0, 0x38, -1}, {0xe0, 0xb8, -1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*b8*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*bc*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*c0*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {0xe0, 0x46, -1}, {0xe0, 0xc6, -1} }, { {0xe0, 0x47, -1}, {0xe0, 0xc7, -1} }, /*c4*/
{ {0xe0, 0x48, -1}, {0xe0, 0xc8, -1} }, { {0xe0, 0x49, -1}, {0xe0, 0xc9, -1} }, { {-1}, {-1} }, { {0xe0, 0x4b, -1}, {0xe0, 0xcb, -1} }, /*c8*/
{ {-1}, {-1} }, { {0xe0, 0x4d, -1}, {0xe0, 0xcd, -1} }, { {-1}, {-1} }, { {0xe0, 0x4f, -1}, {0xe0, 0xcf, -1} }, /*cc*/
{ {0xe0, 0x50, -1}, {0xe0, 0xd0, -1} }, { {0xe0, 0x51, -1}, {0xe0, 0xd1, -1} }, { {0xe0, 0x52, -1}, {0xe0, 0xd2, -1} }, { {0xe0, 0x53, -1}, {0xe0, 0xd3, -1} }, /*d0*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*d4*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*d8*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*dc*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*e0*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*e4*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*e8*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*ec*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*f0*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*f4*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*f8*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {0xe1, 0x1d, 0x45, 0xe1, 0x9d, 0xc5, -1}, {-1} } /*fc*/
};
/*XT keyboard has no escape scancodes, and no scancodes beyond 53*/
static scancode scancode_xt[256] =
{
{ {-1}, {-1} }, { {0x01, -1}, {0x81, -1} }, { {0x02, -1}, {0x82, -1} }, { {0x03, -1}, {0x83, -1} },
{ {0x04, -1}, {0x84, -1} }, { {0x05, -1}, {0x85, -1} }, { {0x06, -1}, {0x86, -1} }, { {0x07, -1}, {0x87, -1} },
{ {0x08, -1}, {0x88, -1} }, { {0x09, -1}, {0x89, -1} }, { {0x0a, -1}, {0x8a, -1} }, { {0x0b, -1}, {0x8b, -1} },
{ {0x0c, -1}, {0x8c, -1} }, { {0x0d, -1}, {0x8d, -1} }, { {0x0e, -1}, {0x8e, -1} }, { {0x0f, -1}, {0x8f, -1} },
{ {0x10, -1}, {0x90, -1} }, { {0x11, -1}, {0x91, -1} }, { {0x12, -1}, {0x92, -1} }, { {0x13, -1}, {0x93, -1} },
{ {0x14, -1}, {0x94, -1} }, { {0x15, -1}, {0x95, -1} }, { {0x16, -1}, {0x96, -1} }, { {0x17, -1}, {0x97, -1} },
{ {0x18, -1}, {0x98, -1} }, { {0x19, -1}, {0x99, -1} }, { {0x1a, -1}, {0x9a, -1} }, { {0x1b, -1}, {0x9b, -1} },
{ {0x1c, -1}, {0x9c, -1} }, { {0x1d, -1}, {0x9d, -1} }, { {0x1e, -1}, {0x9e, -1} }, { {0x1f, -1}, {0x9f, -1} },
{ {0x20, -1}, {0xa0, -1} }, { {0x21, -1}, {0xa1, -1} }, { {0x22, -1}, {0xa2, -1} }, { {0x23, -1}, {0xa3, -1} },
{ {0x24, -1}, {0xa4, -1} }, { {0x25, -1}, {0xa5, -1} }, { {0x26, -1}, {0xa6, -1} }, { {0x27, -1}, {0xa7, -1} },
{ {0x28, -1}, {0xa8, -1} }, { {0x29, -1}, {0xa9, -1} }, { {0x2a, -1}, {0xaa, -1} }, { {0x2b, -1}, {0xab, -1} },
{ {0x2c, -1}, {0xac, -1} }, { {0x2d, -1}, {0xad, -1} }, { {0x2e, -1}, {0xae, -1} }, { {0x2f, -1}, {0xaf, -1} },
{ {0x30, -1}, {0xb0, -1} }, { {0x31, -1}, {0xb1, -1} }, { {0x32, -1}, {0xb2, -1} }, { {0x33, -1}, {0xb3, -1} },
{ {0x34, -1}, {0xb4, -1} }, { {0x35, -1}, {0xb5, -1} }, { {0x36, -1}, {0xb6, -1} }, { {0x37, -1}, {0xb7, -1} },
{ {0x38, -1}, {0xb8, -1} }, { {0x39, -1}, {0xb9, -1} }, { {0x3a, -1}, {0xba, -1} }, { {0x3b, -1}, {0xbb, -1} },
{ {0x3c, -1}, {0xbc, -1} }, { {0x3d, -1}, {0xbd, -1} }, { {0x3e, -1}, {0xbe, -1} }, { {0x3f, -1}, {0xbf, -1} },
{ {0x40, -1}, {0xc0, -1} }, { {0x41, -1}, {0xc1, -1} }, { {0x42, -1}, {0xc2, -1} }, { {0x43, -1}, {0xc3, -1} },
{ {0x44, -1}, {0xc4, -1} }, { {0x45, -1}, {0xc5, -1} }, { {0x46, -1}, {0xc6, -1} }, { {0x47, -1}, {0xc7, -1} },
{ {0x48, -1}, {0xc8, -1} }, { {0x49, -1}, {0xc9, -1} }, { {0x4a, -1}, {0xca, -1} }, { {0x4b, -1}, {0xcb, -1} },
{ {0x4c, -1}, {0xcc, -1} }, { {0x4d, -1}, {0xcd, -1} }, { {0x4e, -1}, {0xce, -1} }, { {0x4f, -1}, {0xcf, -1} },
{ {0x50, -1}, {0xd0, -1} }, { {0x51, -1}, {0xd1, -1} }, { {0x52, -1}, {0xd2, -1} }, { {0x53, -1}, {0xd3, -1} },
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*54*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*58*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*5c*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*60*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*64*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*68*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*6c*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*70*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*74*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*78*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*7c*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*80*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*84*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*88*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*8c*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*90*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*94*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*98*/
{ {0x1c, -1}, {0x9c, -1} }, { {0x1d, -1}, {0x9d, -1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*9c*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*a0*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*a4*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {0x2a, -1}, {0x8a, -1} }, { {-1}, {-1} }, /*a8*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*ac*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*b0*/
{ {-1}, {-1} }, { {0x35, -1}, {0xb5, -1} }, { {0x36, -1}, {0xb6, -1} }, { {0x37, -1}, {0xb7, -1} }, /*b4*/
{ {0x38, -1}, {0xb8, -1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*b8*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*bc*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*c0*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {0x46, -1}, {0xc6, -1} }, { {0x47, -1}, {0xc7, -1} }, /*c4*/
{ {0x48, -1}, {0xc8, -1} }, { {0x49, -1}, {0xc9, -1} }, { {-1}, {-1} }, { {0x4b, -1}, {0xcb, -1} }, /*c8*/
{ {-1}, {-1} }, { {0x4d, -1}, {0xcd, -1} }, { {-1}, {-1} }, { {0x4f, -1}, {0xcf, -1} }, /*cc*/
{ {0x50, -1}, {0xd0, -1} }, { {0x51, -1}, {0xd1, -1} }, { {0x52, -1}, {0xd2, -1} }, { {0x53, -1}, {0xd3, -1} }, /*d0*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*d4*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*d8*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*dc*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*e0*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*e4*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*e8*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*ec*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*f0*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*f4*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*f8*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*fc*/
};
/*Tandy keyboard has slightly different scancodes to XT*/
static scancode scancode_tandy[256] =
{
{ {-1}, {-1} }, { {0x01, -1}, {0x81, -1} }, { {0x02, -1}, {0x82, -1} }, { {0x03, -1}, {0x83, -1} },
{ {0x04, -1}, {0x84, -1} }, { {0x05, -1}, {0x85, -1} }, { {0x06, -1}, {0x86, -1} }, { {0x07, -1}, {0x87, -1} },
{ {0x08, -1}, {0x88, -1} }, { {0x09, -1}, {0x89, -1} }, { {0x0a, -1}, {0x8a, -1} }, { {0x0b, -1}, {0x8b, -1} },
{ {0x0c, -1}, {0x8c, -1} }, { {0x0d, -1}, {0x8d, -1} }, { {0x0e, -1}, {0x8e, -1} }, { {0x0f, -1}, {0x8f, -1} },
{ {0x10, -1}, {0x90, -1} }, { {0x11, -1}, {0x91, -1} }, { {0x12, -1}, {0x92, -1} }, { {0x13, -1}, {0x93, -1} },
{ {0x14, -1}, {0x94, -1} }, { {0x15, -1}, {0x95, -1} }, { {0x16, -1}, {0x96, -1} }, { {0x17, -1}, {0x97, -1} },
{ {0x18, -1}, {0x98, -1} }, { {0x19, -1}, {0x99, -1} }, { {0x1a, -1}, {0x9a, -1} }, { {0x1b, -1}, {0x9b, -1} },
{ {0x1c, -1}, {0x9c, -1} }, { {0x1d, -1}, {0x9d, -1} }, { {0x1e, -1}, {0x9e, -1} }, { {0x1f, -1}, {0x9f, -1} },
{ {0x20, -1}, {0xa0, -1} }, { {0x21, -1}, {0xa1, -1} }, { {0x22, -1}, {0xa2, -1} }, { {0x23, -1}, {0xa3, -1} },
{ {0x24, -1}, {0xa4, -1} }, { {0x25, -1}, {0xa5, -1} }, { {0x26, -1}, {0xa6, -1} }, { {0x27, -1}, {0xa7, -1} },
{ {0x28, -1}, {0xa8, -1} }, { {0x29, -1}, {0xa9, -1} }, { {0x2a, -1}, {0xaa, -1} }, { {0x47, -1}, {0xc7, -1} },
{ {0x2c, -1}, {0xac, -1} }, { {0x2d, -1}, {0xad, -1} }, { {0x2e, -1}, {0xae, -1} }, { {0x2f, -1}, {0xaf, -1} },
{ {0x30, -1}, {0xb0, -1} }, { {0x31, -1}, {0xb1, -1} }, { {0x32, -1}, {0xb2, -1} }, { {0x33, -1}, {0xb3, -1} },
{ {0x34, -1}, {0xb4, -1} }, { {0x35, -1}, {0xb5, -1} }, { {0x36, -1}, {0xb6, -1} }, { {0x37, -1}, {0xb7, -1} },
{ {0x38, -1}, {0xb8, -1} }, { {0x39, -1}, {0xb9, -1} }, { {0x3a, -1}, {0xba, -1} }, { {0x3b, -1}, {0xbb, -1} },
{ {0x3c, -1}, {0xbc, -1} }, { {0x3d, -1}, {0xbd, -1} }, { {0x3e, -1}, {0xbe, -1} }, { {0x3f, -1}, {0xbf, -1} },
{ {0x40, -1}, {0xc0, -1} }, { {0x41, -1}, {0xc1, -1} }, { {0x42, -1}, {0xc2, -1} }, { {0x43, -1}, {0xc3, -1} },
{ {0x44, -1}, {0xc4, -1} }, { {0x45, -1}, {0xc5, -1} }, { {0x46, -1}, {0xc6, -1} }, { {0x47, -1}, {0xc7, -1} },
{ {0x48, -1}, {0xc8, -1} }, { {0x49, -1}, {0xc9, -1} }, { {0x4a, -1}, {0xca, -1} }, { {0x4b, -1}, {0xcb, -1} },
{ {0x4c, -1}, {0xcc, -1} }, { {0x4d, -1}, {0xcd, -1} }, { {0x4e, -1}, {0xce, -1} }, { {0x4f, -1}, {0xcf, -1} },
{ {0x50, -1}, {0xd0, -1} }, { {0x51, -1}, {0xd1, -1} }, { {0x52, -1}, {0xd2, -1} }, { {0x56, -1}, {0xd6, -1} },
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*54*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*58*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*5c*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*60*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*64*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*68*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*6c*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*70*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*74*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*78*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*7c*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*80*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*84*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*88*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*8c*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*90*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*94*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*98*/
{ {0x57, -1}, {0xd7, -1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*9c*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*a0*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*a4*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {0x2a, -1}, {0x8a, -1} }, { {-1}, {-1} }, /*a8*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*ac*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*b0*/
{ {-1}, {-1} }, { {0x35, -1}, {0xb5, -1} }, { {0x36, -1}, {0xb6, -1} }, { {0x37, -1}, {0xb7, -1} }, /*b4*/
{ {0x38, -1}, {0xb8, -1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*b8*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*bc*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*c0*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {0x46, -1}, {0xc6, -1} }, { {0x47, -1}, {0xc7, -1} }, /*c4*/
{ {0x29, -1}, {0xa9, -1} }, { {0x49, -1}, {0xc9, -1} }, { {-1}, {-1} }, { {0x2b, -1}, {0xab, -1} }, /*c8*/
{ {-1}, {-1} }, { {0x4e, -1}, {0xce, -1} }, { {-1}, {-1} }, { {0x4f, -1}, {0xcf, -1} }, /*cc*/
{ {0x4a, -1}, {0xca, -1} }, { {0x51, -1}, {0xd1, -1} }, { {0x52, -1}, {0xd2, -1} }, { {0x53, -1}, {0xd3, -1} }, /*d0*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*d4*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*d8*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*dc*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*e0*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*e4*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*e8*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*ec*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*f0*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*f4*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*f8*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*fc*/
};
static int oldkey[256];
static int keydelay[256];
void (*keyboard_send)(uint8_t val);
void (*keyboard_poll)();
int keyboard_scan = 1;
void keyboard_process()
{
int c;
int d;
scancode *scancodes = (AT) ? scancode_set1 : scancode_xt;
if (!keyboard_scan) return;
if (TANDY) scancodes = scancode_tandy;
for (c = 0; c < 256; c++)
{
if (key[c]) keydelay[c]++;
else keydelay[c] = 0;
}
for (c = 0; c < 256; c++)
{
if (key[c] != oldkey[c])
{
oldkey[c] = key[c];
if ( key[c] && scancodes[c].scancodes_make[0] == -1)
continue;
if (!key[c] && scancodes[c].scancodes_break[0] == -1)
continue;
pclog("Key %02X start\n", c);
d = 0;
if (key[c])
{
while (scancodes[c].scancodes_make[d] != -1)
keyboard_send(scancodes[c].scancodes_make[d++]);
}
else
{
while (scancodes[c].scancodes_break[d] != -1)
keyboard_send(scancodes[c].scancodes_break[d++]);
}
}
}
for (c = 0; c < 256; c++)
{
if (keydelay[c] >= 30)
{
keydelay[c] -= 10;
if (scancode_set1[c].scancodes_make[0] == -1)
continue;
d = 0;
while (scancode_set1[c].scancodes_make[d] != -1)
keyboard_send(scancode_set1[c].scancodes_make[d++]);
}
}
}

3
src/keyboard.h Normal file
View file

@ -0,0 +1,3 @@
extern void (*keyboard_send)(uint8_t val);
extern void (*keyboard_poll)();
extern int keyboard_scan;

168
src/keyboard_amstrad.c Normal file
View file

@ -0,0 +1,168 @@
#include "ibm.h"
#include "io.h"
#include "mem.h"
#include "sound.h"
#include "keyboard.h"
#include "keyboard_amstrad.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 wantirq;
uint8_t pa;
uint8_t pb;
} keyboard_amstrad;
static uint8_t key_queue[16];
static int key_queue_start = 0, key_queue_end = 0;
static uint8_t amstrad_systemstat_1, amstrad_systemstat_2;
void keyboard_amstrad_poll()
{
if (keyboard_amstrad.wantirq)
{
keyboard_amstrad.wantirq = 0;
picint(2);
pclog("keyboard_amstrad : take IRQ\n");
}
if (key_queue_start != key_queue_end)
{
keyboard_amstrad.pa = key_queue[key_queue_start];
pclog("Reading %02X from the key queue at %i\n", keyboard_amstrad.pa, key_queue_start);
key_queue_start = (key_queue_start + 1) & 0xf;
keyboard_amstrad.wantirq = 1;
}
}
void keyboard_amstrad_adddata(uint8_t val)
{
key_queue[key_queue_end] = val;
pclog("keyboard_amstrad : %02X added to key queue at %i\n", val, key_queue_end);
key_queue_end = (key_queue_end + 1) & 0xf;
return;
}
void keyboard_amstrad_write(uint16_t port, uint8_t val)
{
pclog("keyboard_amstrad : write %04X %02X %02X\n", port, val, keyboard_amstrad.pb);
/* if (ram[8] == 0xc3)
{
output = 3;
}*/
switch (port)
{
case 0x61:
pclog("keyboard_amstrad : pb write %02X %02X %i %02X %i\n", val, keyboard_amstrad.pb, !(keyboard_amstrad.pb & 0x40), keyboard_amstrad.pb & 0x40, (val & 0x40));
if (!(keyboard_amstrad.pb & 0x40) && (val & 0x40)) /*Reset keyboard*/
{
pclog("keyboard_amstrad : reset keyboard\n");
keyboard_amstrad_adddata(0xaa);
}
keyboard_amstrad.pb = val;
ppi.pb = val;
/* if (AMSTRADIO)
keyboard_amstrad.s2 = val & 4;
else
keyboard_amstrad.s2 = val & 8;*/
gated = ((val & 3) == 3);
if (gated)
wasgated = 1;
if (val & 0x80)
keyboard_amstrad.pa = 0;
break;
case 0x63:
break;
case 0x64:
amstrad_systemstat_1 = val;
break;
case 0x65:
amstrad_systemstat_2 = val;
break;
default:
pclog("\nBad XT keyboard write %04X %02X\n", port, val);
// dumpregs();
// exit(-1);
}
}
uint8_t keyboard_amstrad_read(uint16_t port)
{
uint8_t temp;
// pclog("keyboard_amstrad : read %04X ", port);
switch (port)
{
case 0x60:
if (keyboard_amstrad.pb & 0x80)
{
temp = (amstrad_systemstat_1 | 0xd) & 0x7f;
}
else
{
temp = keyboard_amstrad.pa;
if (key_queue_start == key_queue_end)
{
keyboard_amstrad.wantirq = 0;
}
else
{
keyboard_amstrad.pa = key_queue[key_queue_start];
key_queue_start = (key_queue_start + 1) & 0xf;
keyboard_amstrad.wantirq = 1;
}
}
break;
case 0x61:
temp = keyboard_amstrad.pb;
break;
case 0x62:
if (keyboard_amstrad.pb & 0x04)
temp = amstrad_systemstat_2 & 0xf;
else
temp = amstrad_systemstat_2 >> 4;
temp |= (ppispeakon ? 0x20 : 0);
break;
default:
pclog("\nBad XT keyboard read %04X\n", port);
// dumpregs();
// exit(-1);
}
// pclog("%02X %04X:%04X\n", temp, CS, pc);
return temp;
}
void keyboard_amstrad_reset()
{
keyboard_amstrad.wantirq = 0;
keyboard_scan = 1;
}
void keyboard_amstrad_init()
{
//return;
pclog("keyboard_amstrad_init\n");
io_sethandler(0x0060, 0x0006, keyboard_amstrad_read, NULL, NULL, keyboard_amstrad_write, NULL, NULL);
keyboard_amstrad_reset();
keyboard_send = keyboard_amstrad_adddata;
keyboard_poll = keyboard_amstrad_poll;
}

3
src/keyboard_amstrad.h Normal file
View file

@ -0,0 +1,3 @@
void keyboard_amstrad_init();
void keyboard_amstrad_reset();
void keyboard_amstrad_poll();

436
src/keyboard_at.c Normal file
View file

@ -0,0 +1,436 @@
#include "ibm.h"
#include "io.h"
#include "mem.h"
#include "sound.h"
#include "keyboard.h"
#include "keyboard_at.h"
#define STAT_PARITY 0x80
#define STAT_RTIMEOUT 0x40
#define STAT_TTIMEOUT 0x20
#define STAT_MFULL 0x20
#define STAT_LOCK 0x10
#define STAT_CD 0x08
#define STAT_SYSFLAG 0x04
#define STAT_IFULL 0x02
#define STAT_OFULL 0x01
struct
{
int initialised;
int want60;
int wantirq, wantirq12;
uint8_t command;
uint8_t status;
uint8_t mem[0x20];
uint8_t out;
uint8_t input_port;
uint8_t output_port;
uint8_t key_command;
int key_wantdata;
} keyboard_at;
static uint8_t key_ctrl_queue[16];
static int key_ctrl_queue_start = 0, key_ctrl_queue_end = 0;
static uint8_t key_queue[16];
static int key_queue_start = 0, key_queue_end = 0;
static uint8_t mouse_queue[16];
int mouse_queue_start = 0, mouse_queue_end = 0;
void keyboard_at_poll()
{
if (keyboard_at.wantirq)
{
keyboard_at.wantirq = 0;
picint(2);
pclog("keyboard_at : take IRQ\n");
}
else if (keyboard_at.wantirq12)
{
keyboard_at.wantirq12 = 0;
picint(0x1000);
pclog("keyboard_at : take IRQ 12\n");
}
if (!(keyboard_at.status & STAT_OFULL) && !(keyboard_at.mem[0] & 0x10) &&
mouse_queue_start != mouse_queue_end)
{
pclog("Reading %02X from the mouse queue at %i\n", keyboard_at.out, key_queue_start);
keyboard_at.out = mouse_queue[mouse_queue_start];
mouse_queue_start = (mouse_queue_start + 1) & 0xf;
keyboard_at.status |= STAT_OFULL | STAT_MFULL;
keyboard_at.status &= ~STAT_IFULL;
if (keyboard_at.mem[0] & 0x02)
keyboard_at.wantirq12 = 1;
}
else if (!(keyboard_at.status & STAT_OFULL) && !(keyboard_at.mem[0] & 0x10) &&
key_queue_start != key_queue_end)
{
pclog("Reading %02X from the key queue at %i\n", keyboard_at.out, key_queue_start);
keyboard_at.out = key_queue[key_queue_start];
key_queue_start = (key_queue_start + 1) & 0xf;
keyboard_at.status |= STAT_OFULL;
keyboard_at.status &= ~STAT_IFULL;
if (keyboard_at.mem[0] & 0x01)
keyboard_at.wantirq = 1;
}
else if (!(keyboard_at.status & STAT_OFULL) &&
key_ctrl_queue_start != key_ctrl_queue_end)
{
pclog("Reading %02X from the key ctrl_queue at %i\n", keyboard_at.out, key_ctrl_queue_start);
keyboard_at.out = key_ctrl_queue[key_ctrl_queue_start];
key_ctrl_queue_start = (key_ctrl_queue_start + 1) & 0xf;
keyboard_at.status |= STAT_OFULL;
keyboard_at.status &= ~STAT_IFULL;
if (keyboard_at.mem[0] & 0x01)
keyboard_at.wantirq = 1;
}
}
void keyboard_at_adddata(uint8_t val)
{
// if (keyboard_at.status & STAT_OFULL)
// {
key_ctrl_queue[key_ctrl_queue_end] = val;
key_ctrl_queue_end = (key_ctrl_queue_end + 1) & 0xf;
pclog("keyboard_at : %02X added to queue\n", val);
/* return;
}
keyboard_at.out = val;
keyboard_at.status |= STAT_OFULL;
keyboard_at.status &= ~STAT_IFULL;
if (keyboard_at.mem[0] & 0x01)
keyboard_at.wantirq = 1;
pclog("keyboard_at : output %02X (IRQ %i)\n", val, keyboard_at.wantirq);*/
}
void keyboard_at_adddata_keyboard(uint8_t val)
{
key_queue[key_queue_end] = val;
key_queue_end = (key_queue_end + 1) & 0xf;
pclog("keyboard_at : %02X added to key queue\n", val);
return;
}
void keyboard_at_adddata_mouse(uint8_t val)
{
mouse_queue[mouse_queue_end] = val;
mouse_queue_end = (mouse_queue_end + 1) & 0xf;
pclog("keyboard_at : %02X added to mouse queue\n", val);
return;
}
void keyboard_at_write(uint16_t port, uint8_t val)
{
pclog("keyboard_at : write %04X %02X %i %02X\n", port, val, keyboard_at.key_wantdata, ram[8]);
/* if (ram[8] == 0xc3)
{
output = 3;
}*/
switch (port)
{
case 0x60:
if (keyboard_at.want60)
{
/*Write to controller*/
keyboard_at.want60 = 0;
switch (keyboard_at.command)
{
case 0x60: case 0x61: case 0x62: case 0x63:
case 0x64: case 0x65: case 0x66: case 0x67:
case 0x68: case 0x69: case 0x6a: case 0x6b:
case 0x6c: case 0x6d: case 0x6e: case 0x6f:
case 0x70: case 0x71: case 0x72: case 0x73:
case 0x74: case 0x75: case 0x76: case 0x77:
case 0x78: case 0x79: case 0x7a: case 0x7b:
case 0x7c: case 0x7d: case 0x7e: case 0x7f:
keyboard_at.mem[keyboard_at.command & 0x1f] = val;
if (keyboard_at.command == 0x60)
{
if ((val & 1) && (keyboard_at.status & STAT_OFULL))
keyboard_at.wantirq = 1;
if (!(val & 1) && keyboard_at.wantirq)
keyboard_at.wantirq = 0;
}
break;
case 0xcb: /*AMI - set keyboard mode*/
break;
case 0xcf: /*??? - sent by MegaPC BIOS*/
break;
case 0xd1: /*Write output port*/
pclog("Write output port - %02X %02X %04X:%04X\n", keyboard_at.output_port, val, CS, pc);
if ((keyboard_at.output_port ^ val) & 0x02) /*A20 enable change*/
{
mem_a20_key = val & 0x02;
mem_a20_recalc();
// pclog("Rammask change to %08X %02X\n", rammask, val & 0x02);
flushmmucache();
}
keyboard_at.output_port = val;
break;
case 0xd3: /*Write to mouse output buffer*/
keyboard_at_adddata_mouse(val);
break;
case 0xd4: /*Write to mouse*/
if (mouse_write)
mouse_write(val);
break;
default:
pclog("Bad AT keyboard controller 0060 write %02X command %02X\n", val, keyboard_at.command);
// dumpregs();
// exit(-1);
}
}
else
{
/*Write to keyboard*/
keyboard_at.mem[0] &= ~0x10;
if (keyboard_at.key_wantdata)
{
keyboard_at.key_wantdata = 0;
switch (keyboard_at.key_command)
{
case 0xed: /*Set/reset LEDs*/
keyboard_at_adddata_keyboard(0xfa);
break;
case 0xf3: /*Set typematic rate/delay*/
keyboard_at_adddata_keyboard(0xfa);
break;
default:
pclog("Bad AT keyboard 0060 write %02X command %02X\n", val, keyboard_at.key_command);
// dumpregs();
// exit(-1);
}
}
else
{
keyboard_at.key_command = val;
switch (val)
{
case 0x05: /*??? - sent by NT 4.0*/
keyboard_at_adddata_keyboard(0xfe);
break;
case 0xed: /*Set/reset LEDs*/
keyboard_at.key_wantdata = 1;
keyboard_at_adddata_keyboard(0xfa);
break;
case 0xf2: /*Read ID*/
keyboard_at_adddata_keyboard(0xfa);
keyboard_at_adddata_keyboard(0xab);
keyboard_at_adddata_keyboard(0x41);
break;
case 0xf3: /*Set typematic rate/delay*/
keyboard_at.key_wantdata = 1;
keyboard_at_adddata_keyboard(0xfa);
break;
case 0xf4: /*Enable keyboard*/
keyboard_scan = 1;
break;
case 0xff: /*Reset*/
keyboard_at_adddata_keyboard(0xfa);
keyboard_at_adddata_keyboard(0xaa);
break;
default:
pclog("Bad AT keyboard command %02X\n", val);
keyboard_at_adddata_keyboard(0xfe);
// dumpregs();
// exit(-1);
}
}
}
break;
case 0x61:
ppi.pb=val;
gated=((val&3)==3);
if (gated) wasgated=1;
break;
case 0x64:
keyboard_at.want60 = 0;
keyboard_at.command = val;
/*New controller command*/
switch (val)
{
case 0x20: case 0x21: case 0x22: case 0x23:
case 0x24: case 0x25: case 0x26: case 0x27:
case 0x28: case 0x29: case 0x2a: case 0x2b:
case 0x2c: case 0x2d: case 0x2e: case 0x2f:
case 0x30: case 0x31: case 0x32: case 0x33:
case 0x34: case 0x35: case 0x36: case 0x37:
case 0x38: case 0x39: case 0x3a: case 0x3b:
case 0x3c: case 0x3d: case 0x3e: case 0x3f:
keyboard_at_adddata(keyboard_at.mem[val & 0x1f]);
break;
case 0x60: case 0x61: case 0x62: case 0x63:
case 0x64: case 0x65: case 0x66: case 0x67:
case 0x68: case 0x69: case 0x6a: case 0x6b:
case 0x6c: case 0x6d: case 0x6e: case 0x6f:
case 0x70: case 0x71: case 0x72: case 0x73:
case 0x74: case 0x75: case 0x76: case 0x77:
case 0x78: case 0x79: case 0x7a: case 0x7b:
case 0x7c: case 0x7d: case 0x7e: case 0x7f:
keyboard_at.want60 = 1;
break;
case 0xa1: /*AMI - get controlled version*/
break;
case 0xa7: /*Disable mouse port*/
break;
case 0xa9: /*Test mouse port*/
keyboard_at_adddata(0x00); /*no error*/
break;
case 0xaa: /*Self-test*/
if (!keyboard_at.initialised)
{
keyboard_at.initialised = 1;
key_ctrl_queue_start = key_ctrl_queue_end = 0;
keyboard_at.status &= ~STAT_OFULL;
}
keyboard_at.status |= STAT_SYSFLAG;
keyboard_at.mem[0] |= 0x04;
keyboard_at_adddata(0x55);
break;
case 0xab: /*Interface test*/
keyboard_at_adddata(0x00); /*no error*/
break;
case 0xad: /*Disable keyboard*/
keyboard_at.mem[0] |= 0x10;
break;
case 0xae: /*Enable keyboard*/
keyboard_at.mem[0] &= ~0x10;
break;
case 0xc0: /*Read input port*/
keyboard_at_adddata(keyboard_at.input_port);
keyboard_at.input_port = ((keyboard_at.input_port + 1) & 3) | (keyboard_at.input_port & 0xfc);
break;
case 0xc9: /*AMI - block P22 and P23 ??? */
break;
case 0xca: /*AMI - read keyboard mode*/
keyboard_at_adddata(0x00); /*ISA mode*/
break;
case 0xcb: /*AMI - set keyboard mode*/
keyboard_at.want60 = 1;
break;
case 0xcf: /*??? - sent by MegaPC BIOS*/
keyboard_at.want60 = 1;
break;
case 0xd0: /*Read output port*/
keyboard_at_adddata(keyboard_at.output_port);
break;
case 0xd1: /*Write output port*/
keyboard_at.want60 = 1;
break;
case 0xd3: /*Write mouse output buffer*/
keyboard_at.want60 = 1;
break;
case 0xd4: /*Write to mouse*/
keyboard_at.want60 = 1;
break;
case 0xe0: /*Read test inputs*/
keyboard_at_adddata(0x00);
break;
case 0xef: /*??? - sent by AMI486*/
break;
case 0xfe: /*Pulse output port - pin 0 selected - x86 reset*/
softresetx86(); /*Pulse reset!*/
break;
case 0xff: /*Pulse output port - but no pins selected - sent by MegaPC BIOS*/
break;
default:
pclog("Bad AT keyboard controller command %02X\n", val);
// dumpregs();
// exit(-1);
}
}
}
uint8_t keyboard_at_read(uint16_t port)
{
uint8_t temp = 0xff;
cycles -= 4;
// if (port != 0x61) pclog("keyboard_at : read %04X ", port);
switch (port)
{
case 0x60:
temp = keyboard_at.out;
keyboard_at.status &= ~(STAT_OFULL | STAT_MFULL);
keyboard_at.wantirq = keyboard_at.wantirq12 = 0;
break;
case 0x61:
if (ppispeakon) return (ppi.pb&~0xC0)|0x20;
return ppi.pb&~0xC0;
break;
case 0x64:
temp = keyboard_at.status;
keyboard_at.status &= ~(STAT_RTIMEOUT | STAT_TTIMEOUT);
break;
}
// if (port != 0x61) pclog("%02X %08X\n", temp, rammask);
return temp;
}
void keyboard_at_reset()
{
keyboard_at.initialised = 0;
keyboard_at.status = STAT_LOCK | STAT_CD;
keyboard_at.mem[0] = 0x11;
keyboard_at.wantirq = 0;
keyboard_at.output_port = 0;
keyboard_at.input_port = 0xb0;
keyboard_at.key_wantdata = 0;
keyboard_scan = 1;
}
void keyboard_at_init()
{
//return;
io_sethandler(0x0060, 0x0005, keyboard_at_read, NULL, NULL, keyboard_at_write, NULL, NULL);
keyboard_at_reset();
keyboard_send = keyboard_at_adddata_keyboard;
keyboard_poll = keyboard_at_poll;
mouse_write = NULL;
}

6
src/keyboard_at.h Normal file
View file

@ -0,0 +1,6 @@
void keyboard_at_init();
void keyboard_at_reset();
void keyboard_at_poll();
void (*mouse_write)(uint8_t val);
extern int mouse_queue_start, mouse_queue_end;

285
src/keyboard_olim24.c Normal file
View file

@ -0,0 +1,285 @@
#include "ibm.h"
#include "io.h"
#include "mem.h"
#include "mouse.h"
#include "keyboard.h"
#include "keyboard_olim24.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 wantirq;
uint8_t command;
uint8_t status;
uint8_t out;
uint8_t output_port;
int param, param_total;
uint8_t params[16];
int mouse_mode;
} keyboard_olim24;
static uint8_t key_queue[16];
static int key_queue_start = 0, key_queue_end = 0;
static uint8_t mouse_scancodes[7];
void keyboard_olim24_poll()
{
//pclog("poll %i\n", keyboard_olim24.wantirq);
if (keyboard_olim24.wantirq)
{
keyboard_olim24.wantirq = 0;
picint(2);
pclog("keyboard_olim24 : take IRQ\n");
}
if (!(keyboard_olim24.status & STAT_OFULL) && key_queue_start != key_queue_end)
{
pclog("Reading %02X from the key queue at %i\n", keyboard_olim24.out, key_queue_start);
keyboard_olim24.out = key_queue[key_queue_start];
key_queue_start = (key_queue_start + 1) & 0xf;
keyboard_olim24.status |= STAT_OFULL;
keyboard_olim24.status &= ~STAT_IFULL;
keyboard_olim24.wantirq = 1;
}
}
void keyboard_olim24_adddata(uint8_t val)
{
key_queue[key_queue_end] = val;
key_queue_end = (key_queue_end + 1) & 0xf;
pclog("keyboard_olim24 : %02X added to key queue %02X\n", val, keyboard_olim24.status);
return;
}
void keyboard_olim24_write(uint16_t port, uint8_t val)
{
pclog("keyboard_olim24 : write %04X %02X\n", port, val);
/* if (ram[8] == 0xc3)
{
output = 3;
}*/
switch (port)
{
case 0x60:
if (keyboard_olim24.param != keyboard_olim24.param_total)
{
keyboard_olim24.params[keyboard_olim24.param++] = val;
if (keyboard_olim24.param == keyboard_olim24.param_total)
{
switch (keyboard_olim24.command)
{
case 0x11:
keyboard_olim24.mouse_mode = 0;
mouse_scancodes[0] = keyboard_olim24.params[0];
mouse_scancodes[1] = keyboard_olim24.params[1];
mouse_scancodes[2] = keyboard_olim24.params[2];
mouse_scancodes[3] = keyboard_olim24.params[3];
mouse_scancodes[4] = keyboard_olim24.params[4];
mouse_scancodes[5] = keyboard_olim24.params[5];
mouse_scancodes[6] = keyboard_olim24.params[6];
break;
case 0x12:
keyboard_olim24.mouse_mode = 1;
mouse_scancodes[0] = keyboard_olim24.params[0];
mouse_scancodes[1] = keyboard_olim24.params[1];
mouse_scancodes[2] = keyboard_olim24.params[2];
break;
default:
pclog("Bad keyboard command complete %02X\n", keyboard_olim24.command);
// dumpregs();
// exit(-1);
}
}
}
else
{
keyboard_olim24.command = val;
switch (val)
{
case 0x01: /*Self-test*/
break;
case 0x05: /*Read ID*/
keyboard_olim24_adddata(0x00);
break;
case 0x11:
keyboard_olim24.param = 0;
keyboard_olim24.param_total = 9;
break;
case 0x12:
keyboard_olim24.param = 0;
keyboard_olim24.param_total = 4;
break;
default:
pclog("Bad keyboard command %02X\n", val);
// dumpregs();
// exit(-1);
}
}
break;
}
}
uint8_t keyboard_olim24_read(uint16_t port)
{
uint8_t temp;
// pclog("keyboard_olim24 : read %04X ", port);
switch (port)
{
case 0x60:
temp = keyboard_olim24.out;
if (key_queue_start == key_queue_end)
{
keyboard_olim24.status &= ~STAT_OFULL;
keyboard_olim24.wantirq = 0;
}
else
{
keyboard_olim24.out = key_queue[key_queue_start];
key_queue_start = (key_queue_start + 1) & 0xf;
keyboard_olim24.status |= STAT_OFULL;
keyboard_olim24.status &= ~STAT_IFULL;
keyboard_olim24.wantirq = 1;
}
break;
case 0x64:
temp = keyboard_olim24.status;
keyboard_olim24.status &= ~(STAT_RTIMEOUT | STAT_TTIMEOUT);
break;
default:
pclog("\nBad olim24 keyboard read %04X\n", port);
// dumpregs();
// exit(-1);
}
// pclog("%02X\n", temp);
return temp;
}
void keyboard_olim24_reset()
{
keyboard_olim24.status = STAT_LOCK | STAT_CD;
keyboard_olim24.wantirq = 0;
keyboard_scan = 1;
keyboard_olim24.param = keyboard_olim24.param_total = 0;
keyboard_olim24.mouse_mode = 0;
mouse_scancodes[0] = 0x1c;
mouse_scancodes[1] = 0x53;
mouse_scancodes[2] = 0x01;
mouse_scancodes[3] = 0x4b;
mouse_scancodes[4] = 0x4d;
mouse_scancodes[5] = 0x48;
mouse_scancodes[6] = 0x50;
}
static int mouse_x = 0, mouse_y = 0, mouse_b = 0;
void mouse_olim24_poll(int x, int y, int b)
{
mouse_x += x;
mouse_y += y;
pclog("mouse_poll - %i, %i %i, %i\n", x, y, mouse_x, mouse_y);
if (((key_queue_end - key_queue_start) & 0xf) > 14) return;
if ((b & 1) && !(mouse_b & 1))
keyboard_olim24_adddata(mouse_scancodes[0]);
if (!(b & 1) && (mouse_b & 1))
keyboard_olim24_adddata(mouse_scancodes[0] | 0x80);
mouse_b = (mouse_b & ~1) | (b & 1);
if (((key_queue_end - key_queue_start) & 0xf) > 14) return;
if ((b & 2) && !(mouse_b & 2))
keyboard_olim24_adddata(mouse_scancodes[2]);
if (!(b & 2) && (mouse_b & 2))
keyboard_olim24_adddata(mouse_scancodes[2] | 0x80);
mouse_b = (mouse_b & ~2) | (b & 2);
if (((key_queue_end - key_queue_start) & 0xf) > 14) return;
if ((b & 4) && !(mouse_b & 4))
keyboard_olim24_adddata(mouse_scancodes[1]);
if (!(b & 4) && (mouse_b & 4))
keyboard_olim24_adddata(mouse_scancodes[1] | 0x80);
mouse_b = (mouse_b & ~4) | (b & 4);
if (keyboard_olim24.mouse_mode)
{
if (((key_queue_end - key_queue_start) & 0xf) > 12) return;
if (!mouse_x && !mouse_y) return;
mouse_y = -mouse_y;
if (mouse_x < -127) mouse_x = -127;
if (mouse_x > 127) mouse_x = 127;
if (mouse_x < -127) mouse_x = 0x80 | ((-mouse_x) & 0x7f);
if (mouse_y < -127) mouse_y = -127;
if (mouse_y > 127) mouse_y = 127;
if (mouse_y < -127) mouse_y = 0x80 | ((-mouse_y) & 0x7f);
keyboard_olim24_adddata(0xfe);
keyboard_olim24_adddata(mouse_x);
keyboard_olim24_adddata(mouse_y);
mouse_x = mouse_y = 0;
}
else
{
while (mouse_x < -4)
{
if (((key_queue_end - key_queue_start) & 0xf) > 14) return;
mouse_x+=4;
keyboard_olim24_adddata(mouse_scancodes[3]);
}
while (mouse_x > 4)
{
if (((key_queue_end - key_queue_start) & 0xf) > 14) return;
mouse_x-=4;
keyboard_olim24_adddata(mouse_scancodes[4]);
}
while (mouse_y < -4)
{
if (((key_queue_end - key_queue_start) & 0xf) > 14) return;
mouse_y+=4;
keyboard_olim24_adddata(mouse_scancodes[5]);
}
while (mouse_y > 4)
{
if (((key_queue_end - key_queue_start) & 0xf) > 14) return;
mouse_y-=4;
keyboard_olim24_adddata(mouse_scancodes[6]);
}
}
}
void keyboard_olim24_init()
{
//return;
io_sethandler(0x0060, 0x0001, keyboard_olim24_read, NULL, NULL, keyboard_olim24_write, NULL, NULL);
io_sethandler(0x0064, 0x0001, keyboard_olim24_read, NULL, NULL, keyboard_olim24_write, NULL, NULL);
keyboard_olim24_reset();
keyboard_send = keyboard_olim24_adddata;
keyboard_poll = keyboard_olim24_poll;
mouse_poll = mouse_olim24_poll;
}

3
src/keyboard_olim24.h Normal file
View file

@ -0,0 +1,3 @@
void keyboard_olim24_init();
void keyboard_olim24_reset();
void keyboard_olim24_poll();

163
src/keyboard_xt.c Normal file
View file

@ -0,0 +1,163 @@
#include "ibm.h"
#include "io.h"
#include "mem.h"
#include "sound.h"
#include "keyboard.h"
#include "keyboard_xt.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 wantirq;
uint8_t pa;
uint8_t pb;
} keyboard_xt;
static uint8_t key_queue[16];
static int key_queue_start = 0, key_queue_end = 0;
void keyboard_xt_poll()
{
if (keyboard_xt.wantirq)
{
keyboard_xt.wantirq = 0;
picint(2);
pclog("keyboard_xt : take IRQ\n");
}
if (key_queue_start != key_queue_end)
{
keyboard_xt.pa = key_queue[key_queue_start];
pclog("Reading %02X from the key queue at %i\n", keyboard_xt.pa, key_queue_start);
key_queue_start = (key_queue_start + 1) & 0xf;
keyboard_xt.wantirq = 1;
}
}
void keyboard_xt_adddata(uint8_t val)
{
key_queue[key_queue_end] = val;
pclog("keyboard_xt : %02X added to key queue at %i\n", val, key_queue_end);
key_queue_end = (key_queue_end + 1) & 0xf;
return;
}
void keyboard_xt_write(uint16_t port, uint8_t val)
{
pclog("keyboard_xt : write %04X %02X %02X\n", port, val, keyboard_xt.pb);
/* if (ram[8] == 0xc3)
{
output = 3;
}*/
switch (port)
{
case 0x61:
pclog("keyboard_xt : pb write %02X %02X %i %02X %i\n", val, keyboard_xt.pb, !(keyboard_xt.pb & 0x40), keyboard_xt.pb & 0x40, (val & 0x40));
if (!(keyboard_xt.pb & 0x40) && (val & 0x40)) /*Reset keyboard*/
{
pclog("keyboard_xt : reset keyboard\n");
keyboard_xt_adddata(0xaa);
}
keyboard_xt.pb = val;
ppi.pb = val;
/* if (AMSTRADIO)
keyboard_xt.s2 = val & 4;
else
keyboard_xt.s2 = val & 8;*/
gated = ((val & 3) == 3);
if (gated)
wasgated = 1;
if (val & 0x80)
{
keyboard_xt.pa = 0;
picintc(2);
}
break;
}
}
uint8_t keyboard_xt_read(uint16_t port)
{
uint8_t temp;
// pclog("keyboard_xt : read %04X ", port);
switch (port)
{
case 0x60:
if (keyboard_xt.pb & 0x80)
{
if (VGA)
temp = 0x4D;
else if (MDA)
temp = 0x7D;
else
temp = 0x6D;
}
else
{
temp = keyboard_xt.pa;
if (key_queue_start == key_queue_end)
{
keyboard_xt.wantirq = 0;
}
else
{
keyboard_xt.pa = key_queue[key_queue_start];
key_queue_start = (key_queue_start + 1) & 0xf;
keyboard_xt.wantirq = 1;
}
}
break;
case 0x61:
temp = keyboard_xt.pb;
break;
case 0x62:
if (keyboard_xt.pb & 0x08)
{
if (VGA)
temp = 4;
else if (MDA)
temp = 7;
else
temp = 6;
}
else
temp = 0xD;
temp |= (ppispeakon ? 0x20 : 0);
break;
default:
pclog("\nBad XT keyboard read %04X\n", port);
//dumpregs();
//exit(-1);
}
// pclog("%02X\n", temp);
return temp;
}
void keyboard_xt_reset()
{
keyboard_xt.wantirq = 0;
keyboard_scan = 1;
}
void keyboard_xt_init()
{
//return;
io_sethandler(0x0060, 0x0004, keyboard_xt_read, NULL, NULL, keyboard_xt_write, NULL, NULL);
keyboard_xt_reset();
keyboard_send = keyboard_xt_adddata;
keyboard_poll = keyboard_xt_poll;
}

3
src/keyboard_xt.h Normal file
View file

@ -0,0 +1,3 @@
void keyboard_xt_init();
void keyboard_xt_reset();
void keyboard_xt_poll();

66
src/lpt.c Normal file
View file

@ -0,0 +1,66 @@
#include "ibm.h"
#include "io.h"
#include "lpt.h"
static uint8_t lpt1_dat, lpt2_dat;
void lpt1_write(uint16_t port, uint8_t val)
{
switch (port & 3)
{
case 0:
writedac(val);
lpt1_dat = val;
break;
case 2:
writedacctrl(val);
break;
}
}
uint8_t lpt1_read(uint16_t port)
{
switch (port & 3)
{
case 0:
return lpt1_dat;
case 1:
return readdacfifo();
}
return 0xff;
}
void lpt2_write(uint16_t port, uint8_t val)
{
switch (port & 3)
{
case 0:
writedac(val);
lpt2_dat = val;
break;
case 2:
writedacctrl(val);
break;
}
}
uint8_t lpt2_read(uint16_t port)
{
switch (port & 3)
{
case 0:
return lpt2_dat;
case 1:
return readdacfifo();
}
return 0xff;
}
void lpt_init()
{
io_sethandler(0x0278, 0x0003, lpt1_read, NULL, NULL, lpt1_write, NULL, NULL);
io_sethandler(0x0378, 0x0003, lpt2_read, NULL, NULL, lpt2_write, NULL, NULL);
}
void lpt2_remove()
{
io_removehandler(0x0379, 0x0002, lpt2_read, NULL, NULL, lpt2_write, NULL, NULL);
}

2
src/lpt.h Normal file
View file

@ -0,0 +1,2 @@
void lpt_init();
void lpt2_remove();

2613
src/mame/fmopl.c Normal file

File diff suppressed because it is too large Load diff

126
src/mame/fmopl.h Normal file
View file

@ -0,0 +1,126 @@
#pragma once
#ifndef __FMOPL_H__
#define __FMOPL_H__
#ifndef STUFF
#define STUFF
typedef int64_t attotime;
#define ATTOTIME_IN_HZ(x) (1000000000/(x))
#define attotime_mul(x,y) ((x)*(y))
#define attotime_to_double(x) ((double)(x)/1000000000.0)
#define attotime_zero 0
#define running_device void
#define INLINE static
//#define M_PI 3.142
#endif
/* --- select emulation chips --- */
#define BUILD_YM3812 (1)
#define BUILD_YM3526 (0)
#define BUILD_Y8950 (0)
/* select output bits size of output : 8 or 16 */
#define OPL_SAMPLE_BITS 16
/* compiler dependence */
#ifndef __OSDCOMM_H__
#define __OSDCOMM_H__
typedef unsigned char UINT8; /* unsigned 8bit */
typedef unsigned short UINT16; /* unsigned 16bit */
typedef unsigned int UINT32; /* unsigned 32bit */
typedef signed char INT8; /* signed 8bit */
typedef signed short INT16; /* signed 16bit */
typedef signed int INT32; /* signed 32bit */
#endif /* __OSDCOMM_H__ */
typedef signed short OPLSAMPLE;
/*
#if (OPL_SAMPLE_BITS==16)
typedef INT16 OPLSAMPLE;
#endif
#if (OPL_SAMPLE_BITS==8)
typedef INT8 OPLSAMPLE;
#endif
*/
typedef void (*OPL_TIMERHANDLER)(void *param,int timer,attotime period);
typedef void (*OPL_IRQHANDLER)(void *param,int irq);
typedef void (*OPL_UPDATEHANDLER)(void *param,int min_interval_us);
typedef void (*OPL_PORTHANDLER_W)(void *param,unsigned char data);
typedef unsigned char (*OPL_PORTHANDLER_R)(void *param);
#if BUILD_YM3812
void *ym3812_init(running_device *device, UINT32 clock, UINT32 rate);
void ym3812_shutdown(void *chip);
void ym3812_reset_chip(void *chip);
int ym3812_write(void *chip, int a, int v);
unsigned char ym3812_read(void *chip, int a);
int ym3812_timer_over(void *chip, int c);
void ym3812_update_one(void *chip, OPLSAMPLE *buffer, int length);
void ym3812_set_timer_handler(void *chip, OPL_TIMERHANDLER TimerHandler, void *param);
void ym3812_set_irq_handler(void *chip, OPL_IRQHANDLER IRQHandler, void *param);
void ym3812_set_update_handler(void *chip, OPL_UPDATEHANDLER UpdateHandler, void *param);
#endif /* BUILD_YM3812 */
#if BUILD_YM3526
/*
** Initialize YM3526 emulator(s).
**
** 'num' is the number of virtual YM3526's to allocate
** 'clock' is the chip clock in Hz
** 'rate' is sampling rate
*/
void *ym3526_init(running_device *device, UINT32 clock, UINT32 rate);
/* shutdown the YM3526 emulators*/
void ym3526_shutdown(void *chip);
void ym3526_reset_chip(void *chip);
int ym3526_write(void *chip, int a, int v);
unsigned char ym3526_read(void *chip, int a);
int ym3526_timer_over(void *chip, int c);
/*
** Generate samples for one of the YM3526's
**
** 'which' is the virtual YM3526 number
** '*buffer' is the output buffer pointer
** 'length' is the number of samples that should be generated
*/
void ym3526_update_one(void *chip, OPLSAMPLE *buffer, int length);
void ym3526_set_timer_handler(void *chip, OPL_TIMERHANDLER TimerHandler, void *param);
void ym3526_set_irq_handler(void *chip, OPL_IRQHANDLER IRQHandler, void *param);
void ym3526_set_update_handler(void *chip, OPL_UPDATEHANDLER UpdateHandler, void *param);
#endif /* BUILD_YM3526 */
#if BUILD_Y8950
/* Y8950 port handlers */
void y8950_set_port_handler(void *chip, OPL_PORTHANDLER_W PortHandler_w, OPL_PORTHANDLER_R PortHandler_r, void *param);
void y8950_set_keyboard_handler(void *chip, OPL_PORTHANDLER_W KeyboardHandler_w, OPL_PORTHANDLER_R KeyboardHandler_r, void *param);
void y8950_set_delta_t_memory(void *chip, void * deltat_mem_ptr, int deltat_mem_size );
void * y8950_init(running_device *device, UINT32 clock, UINT32 rate);
void y8950_shutdown(void *chip);
void y8950_reset_chip(void *chip);
int y8950_write(void *chip, int a, int v);
unsigned char y8950_read (void *chip, int a);
int y8950_timer_over(void *chip, int c);
void y8950_update_one(void *chip, OPLSAMPLE *buffer, int length);
void y8950_set_timer_handler(void *chip, OPL_TIMERHANDLER TimerHandler, void *param);
void y8950_set_irq_handler(void *chip, OPL_IRQHANDLER IRQHandler, void *param);
void y8950_set_update_handler(void *chip, OPL_UPDATEHANDLER UpdateHandler, void *param);
#endif /* BUILD_Y8950 */
#endif /* __FMOPL_H__ */

2730
src/mame/ymf262.c Normal file

File diff suppressed because it is too large Load diff

62
src/mame/ymf262.h Normal file
View file

@ -0,0 +1,62 @@
#pragma once
#ifndef __YMF262_H__
#define __YMF262_H__
#ifndef STUFF
#define STUFF
typedef int64_t attotime;
#define ATTOTIME_IN_HZ(x) (1000000000/(x))
#define attotime_mul(x,y) ((x)*(y))
#define attotime_to_double(x) ((double)(x)/1000000000.0)
#define attotime_zero 0
#define running_device void
#define INLINE static
//#define M_PI 3.142
#endif
/* select number of output bits: 8 or 16 */
#define OPL3_SAMPLE_BITS 16
/* compiler dependence */
#ifndef __OSDCOMM_H__
#define __OSDCOMM_H__
typedef unsigned char UINT8; /* unsigned 8bit */
typedef unsigned short UINT16; /* unsigned 16bit */
typedef unsigned int UINT32; /* unsigned 32bit */
typedef signed char INT8; /* signed 8bit */
typedef signed short INT16; /* signed 16bit */
typedef signed int INT32; /* signed 32bit */
#endif
typedef signed short OPL3SAMPLE;
//typedef stream_sample_t OPL3SAMPLE;
/*
#if (OPL3_SAMPLE_BITS==16)
typedef INT16 OPL3SAMPLE;
#endif
#if (OPL3_SAMPLE_BITS==8)
typedef INT8 OPL3SAMPLE;
#endif
*/
typedef void (*OPL3_TIMERHANDLER)(void *param,int timer,attotime period);
typedef void (*OPL3_IRQHANDLER)(void *param,int irq);
typedef void (*OPL3_UPDATEHANDLER)(void *param,int min_interval_us);
void *ymf262_init(running_device *device, int clock, int rate);
void ymf262_shutdown(void *chip);
void ymf262_reset_chip(void *chip);
int ymf262_write(void *chip, int a, int v);
unsigned char ymf262_read(void *chip, int a);
int ymf262_timer_over(void *chip, int c);
void ymf262_update_one(void *chip, OPL3SAMPLE **buffers, int length);
void ymf262_set_timer_handler(void *chip, OPL3_TIMERHANDLER TimerHandler, void *param);
void ymf262_set_irq_handler(void *chip, OPL3_IRQHANDLER IRQHandler, void *param);
void ymf262_set_update_handler(void *chip, OPL3_UPDATEHANDLER UpdateHandler, void *param);
#endif /* __YMF262_H__ */

37
src/mcr.c Normal file
View file

@ -0,0 +1,37 @@
/*INTEL 82355 MCR emulation
This chip was used as part of many 386 chipsets
It controls memory addressing and shadowing*/
#include "ibm.h"
int nextreg6;
uint8_t mcr22;
int mcrlock,mcrfirst;
void resetmcr()
{
mcrlock=0;
mcrfirst=1;
shadowbios=0;
}
void writemcr(uint16_t addr, uint8_t val)
{
printf("Write MCR %04X %02X %04X:%04X\n",addr,val,CS,pc);
switch (addr)
{
case 0x22:
if (val==6 && mcr22==6) nextreg6=1;
else nextreg6=0;
// if ((val&1) && (mcr22&1)) shadowbios=1;
// if (!(val&1) && !(mcr22&1)) shadowbios=0;
// if (!mcrfirst) shadowbios=val&1;
// mcrfirst=0;
// dumpregs();
// exit(-1);
break;
case 0x23:
if (nextreg6) shadowbios=!val;
break;
}
mcr22=val;
}

1358
src/mem.c Normal file

File diff suppressed because it is too large Load diff

40
src/mem.h Normal file
View file

@ -0,0 +1,40 @@
extern uint8_t *ram,*rom,*vram,*vrom;
extern uint8_t romext[32768];
extern int readlnum,writelnum;
extern int memspeed[11];
extern int nopageerrors;
extern int cache;
extern int memwaitstate;
void mem_sethandler(uint32_t base, uint32_t size,
uint8_t (*read_b)(uint32_t addr),
uint16_t (*read_w)(uint32_t addr),
uint32_t (*read_l)(uint32_t addr),
void (*write_b)(uint32_t addr, uint8_t val),
void (*write_w)(uint32_t addr, uint16_t val),
void (*write_l)(uint32_t addr, uint32_t val));
void mem_removehandler(uint32_t base, uint32_t size,
uint8_t (*read_b)(uint32_t addr),
uint16_t (*read_w)(uint32_t addr),
uint32_t (*read_l)(uint32_t addr),
void (*write_b)(uint32_t addr, uint8_t val),
void (*write_w)(uint32_t addr, uint16_t val),
void (*write_l)(uint32_t addr, uint32_t val));
extern int mem_a20_alt;
extern int mem_a20_key;
void mem_a20_recalc();
uint8_t mem_read_ram(uint32_t addr);
uint16_t mem_read_ramw(uint32_t addr);
uint32_t mem_read_raml(uint32_t addr);
void mem_write_ram(uint32_t addr, uint8_t val);
void mem_write_ramw(uint32_t addr, uint16_t val);
void mem_write_raml(uint32_t addr, uint32_t val);
uint8_t mem_read_bios(uint32_t addr);
uint16_t mem_read_biosw(uint32_t addr);
uint32_t mem_read_biosl(uint32_t addr);
FILE *romfopen(char *fn, char *mode);

200
src/model.c Normal file
View file

@ -0,0 +1,200 @@
#include "ibm.h"
#include "cpu.h"
#include "model.h"
#include "io.h"
#include "acer386sx.h"
#include "ali1429.h"
#include "amstrad.h"
#include "dma.h"
#include "fdc.h"
#include "headland.h"
#include "ide.h"
#include "jim.h"
#include "keyboard_xt.h"
#include "keyboard_at.h"
#include "keyboard_olim24.h"
#include "lpt.h"
#include "mouse_ps2.h"
#include "mouse_serial.h"
#include "neat.h"
#include "nvr.h"
#include "olivetti_m24.h"
#include "pci.h"
#include "pic.h"
#include "pit.h"
#include "psg.h"
#include "serial.h"
#include "um8881f.h"
#include "wd76c10.h"
#include "xtide.h"
void xt_init();
void tandy1k_init();
void ams_init();
void europc_init();
void olim24_init();
void at_init();
void at_neat_init();
void at_acer386sx_init();
void at_wd76c10_init();
void at_ali1429_init();
void at_headland_init();
void at_um8881f_init();
int model;
MODEL models[] =
{
{"IBM PC", ROM_IBMPC, { "", cpus_8088, "", NULL, "", NULL}, 0, xt_init},
{"IBM XT", ROM_IBMXT, { "", cpus_8088, "", NULL, "", NULL}, 0, xt_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},
{"Amstrad PC1512", ROM_PC1512, { "", cpus_pc1512,"", NULL, "", NULL}, 1, ams_init},
{"Sinclair PC200", ROM_PC200, { "", cpus_8086, "", NULL, "", NULL}, 1, ams_init},
{"Euro PC", ROM_EUROPC, { "", cpus_8086, "", NULL, "", NULL}, 0, europc_init},
{"Olivetti M24", ROM_OLIM24, { "", cpus_8086, "", NULL, "", NULL}, 1, olim24_init},
{"Amstrad PC1640", ROM_PC1640, { "", cpus_8086, "", NULL, "", NULL}, 1, ams_init},
{"Amstrad PC2086", ROM_PC2086, { "", cpus_8086, "", NULL, "", NULL}, 1, ams_init},
{"Amstrad PC3086", ROM_PC3086, { "", cpus_8086, "", NULL, "", NULL}, 1, ams_init},
{"IBM AT", ROM_IBMAT, { "", cpus_ibmat, "", NULL, "", NULL}, 0, at_init},
{"Commodore PC 30 III", ROM_CMDPC30, { "", cpus_286, "", NULL, "", NULL}, 0, at_init},
{"AMI 286 clone", ROM_AMI286, { "", cpus_286, "", NULL, "", NULL}, 0, at_neat_init},
{"DELL System 200", ROM_DELL200, { "", cpus_286, "", NULL, "", NULL}, 0, at_init},
{"Acer 386SX25/N", ROM_ACER386, { "Intel", cpus_acer, "", NULL, "", NULL}, 1, at_acer386sx_init},
{"Amstrad MegaPC", ROM_MEGAPC, { "Intel", cpus_i386, "AMD", cpus_Am386, "Cyrix", cpus_486SDLC}, 1, at_wd76c10_init},
{"AMI 386 clone", ROM_AMI386, { "Intel", cpus_i386, "AMD", cpus_Am386, "Cyrix", cpus_486SDLC}, 0, at_headland_init},
{"AMI 486 clone", ROM_AMI486, { "Intel", cpus_i486, "AMD", cpus_Am486, "Cyrix", cpus_Cx486}, 0, at_ali1429_init},
{"AMI WinBIOS 486", ROM_WIN486, { "Intel", cpus_i486, "AMD", cpus_Am486, "Cyrix", cpus_Cx486}, 0, at_ali1429_init},
{"AMI WinBIOS 486 PCI", ROM_PCI486, { "Intel", cpus_i486, "AMD", cpus_Am486, "Cyrix", cpus_Cx486}, 0, at_um8881f_init},
{"", -1, {"", 0, "", 0, "", 0}, 0}
};
int model_getromset()
{
return models[model].id;
}
char *model_getname()
{
return models[model].name;
}
void common_init()
{
dma_init();
fdc_init();
lpt_init();
pic_init();
pit_init();
serial1_init(0x3f8);
serial2_init(0x2f8);
}
void xt_init()
{
common_init();
keyboard_xt_init();
mouse_serial_init();
xtide_init();
}
void tandy1k_init()
{
common_init();
keyboard_xt_init();
mouse_serial_init();
psg_init();
xtide_init();
}
void ams_init()
{
common_init();
amstrad_init();
keyboard_amstrad_init();
nvr_init();
xtide_init();
}
void europc_init()
{
common_init();
jim_init();
keyboard_xt_init();
mouse_serial_init();
xtide_init();
}
void olim24_init()
{
common_init();
keyboard_olim24_init();
nvr_init();
olivetti_m24_init();
xtide_init();
}
void at_init()
{
common_init();
dma16_init();
ide_init();
keyboard_at_init();
if (models[model].init == at_init)
mouse_serial_init();
nvr_init();
pic2_init();
}
void at_neat_init()
{
at_init();
mouse_serial_init();
neat_init();
}
void at_acer386sx_init()
{
at_init();
mouse_ps2_init();
acer386sx_init();
}
void at_wd76c10_init()
{
at_init();
mouse_ps2_init();
wd76c10_init();
}
void at_headland_init()
{
at_init();
headland_init();
mouse_serial_init();
}
void at_ali1429_init()
{
at_init();
ali1429_init();
mouse_serial_init();
}
void at_um8881f_init()
{
at_init();
mouse_serial_init();
pci_init();
um8881f_init();
}
void model_init()
{
pclog("Initting as %s\n", model_getname());
io_init();
models[model].init();
}

16
src/model.h Normal file
View file

@ -0,0 +1,16 @@
typedef struct
{
char name[24];
int id;
struct
{
char name[8];
CPU *cpus;
} cpu[3];
int fixed_gfxcard;
void (*init)();
} MODEL;
extern MODEL models[];
extern int model;

4
src/mouse.c Normal file
View file

@ -0,0 +1,4 @@
#include "ibm.h"
#include "mouse.h"
void (*mouse_poll)(int x, int y, int b);

5
src/mouse.h Normal file
View file

@ -0,0 +1,5 @@
extern void (*mouse_poll)(int x, int y, int b);
extern int mousepos;
extern int mousedelay;

152
src/mouse_ps2.c Normal file
View file

@ -0,0 +1,152 @@
#include "ibm.h"
#include "keyboard_at.h"
#include "mouse.h"
#include "mouse_ps2.h"
#include "plat-mouse.h"
enum
{
MOUSE_STREAM,
MOUSE_REMOTE,
MOUSE_ECHO
};
#define MOUSE_ENABLE 0x20
#define MOUSE_SCALE 0x10
static struct
{
int mode;
uint8_t flags;
uint8_t resolution;
uint8_t command;
int cd;
} mouse_ps2;
void mouse_ps2_write(uint8_t val)
{
if (mouse_ps2.cd)
{
mouse_ps2.cd = 0;
switch (mouse_ps2.command)
{
case 0xe8: /*Set mouse resolution*/
mouse_ps2.resolution = val;
keyboard_at_adddata_mouse(0xfa);
break;
case 0xf3: /*Set sample rate*/
keyboard_at_adddata_mouse(0xfa);
break;
// default:
// fatal("mouse_ps2 : Bad data write %02X for command %02X\n", val, mouse_ps2.command);
}
}
else
{
mouse_ps2.command = val;
switch (mouse_ps2.command)
{
case 0xe6: /*Set scaling to 1:1*/
mouse_ps2.flags &= ~MOUSE_SCALE;
keyboard_at_adddata_mouse(0xfa);
break;
case 0xe7: /*Set scaling to 2:1*/
mouse_ps2.flags |= MOUSE_SCALE;
keyboard_at_adddata_mouse(0xfa);
break;
case 0xe8: /*Set mouse resolution*/
mouse_ps2.cd = 1;
keyboard_at_adddata_mouse(0xfa);
break;
case 0xf2: /*Read ID*/
keyboard_at_adddata_mouse(0xfa);
keyboard_at_adddata_mouse(0x00);
break;
case 0xf3: /*Set sample rate*/
mouse_ps2.cd = 1;
keyboard_at_adddata_mouse(0xfa);
break;
case 0xf4: /*Enable*/
mouse_ps2.flags |= MOUSE_ENABLE;
keyboard_at_adddata_mouse(0xfa);
break;
case 0xf5: /*Disable*/
mouse_ps2.flags &= ~MOUSE_ENABLE;
keyboard_at_adddata_mouse(0xfa);
break;
case 0xff: /*Reset*/
mouse_ps2.mode = MOUSE_STREAM;
mouse_ps2.flags = 0;
keyboard_at_adddata_mouse(0xfa);
keyboard_at_adddata_mouse(0xaa);
keyboard_at_adddata_mouse(0x00);
break;
// default:
// fatal("mouse_ps2 : Bad command %02X\n", val, mouse_ps2.command);
}
}
}
static int ps2_x = 0, ps2_y = 0, ps2_b = 0;
void mouse_ps2_poll(int x, int y, int b)
{
uint8_t packet[3] = {0x08, 0, 0};
if (!x && !y && b == ps2_b) return;
ps2_x += x;
ps2_y -= y;
if (mouse_ps2.mode == MOUSE_STREAM && (mouse_ps2.flags & MOUSE_ENABLE) &&
((mouse_queue_end - mouse_queue_start) & 0xf) < 13)
{
ps2_b = b;
// pclog("Send packet : %i %i\n", ps2_x, ps2_y);
if (ps2_x > 255)
ps2_x = 255;
if (ps2_x < -256)
ps2_x = -256;
if (ps2_y > 255)
ps2_y = 255;
if (ps2_y < -256)
ps2_y = -256;
if (ps2_x < 0)
packet[0] |= 0x10;
if (ps2_y < 0)
packet[0] |= 0x20;
if (mouse_b & 1)
packet[0] |= 1;
if (mouse_b & 2)
packet[0] |= 2;
if (mouse_b & 4)
packet[0] |= 4;
packet[1] = ps2_x & 0xff;
packet[2] = ps2_y & 0xff;
ps2_x = ps2_y = 0;
keyboard_at_adddata_mouse(packet[0]);
keyboard_at_adddata_mouse(packet[1]);
keyboard_at_adddata_mouse(packet[2]);
}
}
void mouse_ps2_init()
{
mouse_poll = mouse_ps2_poll;
mouse_write = mouse_ps2_write;
mouse_ps2.cd = 0;
mouse_ps2.flags = 0;
mouse_ps2.mode = MOUSE_STREAM;
}

1
src/mouse_ps2.h Normal file
View file

@ -0,0 +1 @@
void mouse_ps2_init();

66
src/mouse_serial.c Normal file
View file

@ -0,0 +1,66 @@
#include "ibm.h"
#include "mouse.h"
#include "serial.h"
static int oldb=0;
void mouse_serial_poll(int x, int y, int b)
{
uint8_t mousedat[3];
if (!(serial.ier&1)) return;
if (!x && !y && b==oldb) return;
oldb=b;
if (x>127) x=127;
if (y>127) y=127;
if (x<-128) x=-128;
if (y<-128) y=-128;
/*Use Microsoft format*/
mousedat[0]=0x40;
mousedat[0]|=(((y>>6)&3)<<2);
mousedat[0]|=((x>>6)&3);
if (b&1) mousedat[0]|=0x20;
if (b&2) mousedat[0]|=0x10;
mousedat[1]=x&0x3F;
mousedat[2]=y&0x3F;
if (!(serial.mctrl&0x10))
{
serial_write_fifo(mousedat[0]);
serial_write_fifo(mousedat[1]);
serial_write_fifo(mousedat[2]);
}
}
void mouse_serial_rcr()
{
mousepos=-1;
mousedelay=1000;
}
void mousecallback()
{
if (mousepos == -1)
{
mousepos = 0;
serial_fifo_read = serial_fifo_write = 0;
serial.linestat &= ~1;
serial_write_fifo('M');
}
else if (serial_fifo_read != serial_fifo_write)
{
serial.iir=4;
serial.linestat|=1;
if (serial.mctrl&8) picint(0x10);
}
// printf("Mouse callback\n");
}
void mouse_serial_init()
{
mouse_poll = mouse_serial_poll;
serial_rcr = mouse_serial_rcr;
}

1
src/mouse_serial.h Normal file
View file

@ -0,0 +1 @@
void mouse_serial_init();

68
src/neat.c Normal file
View file

@ -0,0 +1,68 @@
/*This is the chipset used in the AMI 286 clone model*/
#include "ibm.h"
#include "io.h"
#include "neat.h"
static uint8_t neat_regs[256];
static int neat_index;
static int neat_emspage[4];
void neat_write(uint16_t port, uint8_t val)
{
switch (port)
{
case 0x22:
neat_index = val;
break;
case 0x23:
neat_regs[neat_index] = val;
switch (neat_index)
{
case 0x6E: /*EMS page extension*/
neat_emspage[3] = (neat_emspage[3] & 0x7F) | (( val & 3) << 7);
neat_emspage[2] = (neat_emspage[2] & 0x7F) | (((val >> 2) & 3) << 7);
neat_emspage[1] = (neat_emspage[1] & 0x7F) | (((val >> 4) & 3) << 7);
neat_emspage[0] = (neat_emspage[0] & 0x7F) | (((val >> 6) & 3) << 7);
break;
}
break;
case 0x0208: case 0x0209: case 0x4208: case 0x4209:
case 0x8208: case 0x8209: case 0xC208: case 0xC209:
neat_emspage[port >> 14] = (neat_emspage[port >> 14] & 0x180) | (val & 0x7F);
break;
}
}
uint8_t neat_read(uint16_t port)
{
switch (port)
{
case 0x22:
return neat_index;
case 0x23:
return neat_regs[neat_index];
}
return 0xff;
}
void neat_writeems(uint32_t addr, uint8_t val)
{
ram[(neat_emspage[(addr >> 14) & 3] << 14) + (addr & 0x3FFF)] = val;
}
uint8_t neat_readems(uint32_t addr)
{
return ram[(neat_emspage[(addr >> 14) & 3] << 14) + (addr & 0x3FFF)];
}
void neat_init()
{
io_sethandler(0x0022, 0x0002, neat_read, NULL, NULL, neat_write, NULL, NULL);
io_sethandler(0x0208, 0x0002, neat_read, NULL, NULL, neat_write, NULL, NULL);
io_sethandler(0x4208, 0x0002, neat_read, NULL, NULL, neat_write, NULL, NULL);
io_sethandler(0x8208, 0x0002, neat_read, NULL, NULL, neat_write, NULL, NULL);
io_sethandler(0xc208, 0x0002, neat_read, NULL, NULL, neat_write, NULL, NULL);
}

1
src/neat.h Normal file
View file

@ -0,0 +1 @@
void neat_init();

204
src/nvr.c Normal file
View file

@ -0,0 +1,204 @@
#include <stdio.h>
#include <windows.h>
#include "ibm.h"
#include "nvr.h"
int oldromset;
int nvrmask=63;
uint8_t nvrram[128];
int nvraddr;
SYSTEMTIME systemtime;
void getnvrtime()
{
int c,d;
uint8_t baknvr[10];
// memset(nvrram,0,10);
// return;
memcpy(baknvr,nvrram,10);
GetLocalTime(&systemtime);
d=systemtime.wSecond%10;
c=systemtime.wSecond/10;
nvrram[0]=d|(c<<4);
d=systemtime.wMinute%10;
c=systemtime.wMinute/10;
nvrram[2]=d|(c<<4);
d=systemtime.wHour%10;
c=systemtime.wHour/10;
nvrram[4]=d|(c<<4);
d=systemtime.wDayOfWeek%10;
c=systemtime.wDayOfWeek/10;
nvrram[6]=d|(c<<4);
d=systemtime.wDay%10;
c=systemtime.wDay/10;
nvrram[7]=d|(c<<4);
d=systemtime.wMonth%10;
c=systemtime.wMonth/10;
nvrram[8]=d|(c<<4);
d=systemtime.wYear%10;
c=(systemtime.wYear/10)%10;
nvrram[9]=d|(c<<4);
if (baknvr[0]!=nvrram[0] ||
baknvr[2]!=nvrram[2] ||
baknvr[4]!=nvrram[4] ||
baknvr[6]!=nvrram[6] ||
baknvr[7]!=nvrram[7] ||
baknvr[8]!=nvrram[8] ||
baknvr[9]!=nvrram[9]) nvrram[0xA]|=0x80;
}
void nvr_recalc()
{
int c;
float newrtctime;
c=1<<((nvrram[0xA]&0xF)-1);
newrtctime=RTCCONST*(float)c;
if (rtctime>newrtctime) rtctime=newrtctime;
}
void nvr_rtc()
{
int c;
if (!(nvrram[0xA]&0xF))
{
rtctime=99999999;
return;
}
c=1<<((nvrram[0xA]&0xF)-1);
rtctime+=RTCCONST*(float)c;
// pclog("RTCtime now %f\n",rtctime);
nvrram[0xC]=0x40;
if (nvrram[0xB]&0x40)
{
nvrram[0xC]|=0x80;
if (AMSTRAD) picint(2);
else picint(0x100);
// pclog("RTC int\n");
}
}
void writenvr(uint16_t addr, uint8_t val)
{
int c;
// printf("Write NVR %03X %02X %02X %04X:%04X %i\n",addr,nvraddr,val,cs>>4,pc,ins);
if (addr&1)
{
// if (nvraddr == 0x33) pclog("NVRWRITE33 %02X %04X:%04X %i\n",val,CS,pc,ins);
if (nvraddr >= 0xe && nvrram[nvraddr] != val)
savenvr();
if (nvraddr!=0xC && nvraddr!=0xD) nvrram[nvraddr]=val;
if (nvraddr==0xA)
{
// pclog("NVR rate %i\n",val&0xF);
if (val&0xF)
{
c=1<<((val&0xF)-1);
rtctime+=RTCCONST*(float)c;
}
else
rtctime=99999999;
}
}
else nvraddr=val&nvrmask;
}
uint8_t readnvr(uint16_t addr)
{
uint8_t temp;
// printf("Read NVR %03X %02X %02X %04X:%04X\n",addr,nvraddr,nvrram[nvraddr],cs>>4,pc);
if (addr&1)
{
if (nvraddr<=0xA) getnvrtime();
if (nvraddr==0xD) nvrram[0xD]|=0x80;
if (nvraddr==0xA)
{
temp=nvrram[0xA];
nvrram[0xA]&=~0x80;
return temp;
}
if (nvraddr==0xC)
{
if (AMSTRAD) picintc(2);
else picintc(0x100);
temp=nvrram[0xC];
nvrram[0xC]=0;
return temp;
}
// if (AMIBIOS && nvraddr==0x36) return 0;
// if (nvraddr==0xA) nvrram[0xA]^=0x80;
return nvrram[nvraddr];
}
return nvraddr;
}
void loadnvr()
{
FILE *f;
int c;
nvrmask=63;
oldromset=romset;
switch (romset)
{
case ROM_PC1512: f = romfopen("pc1512.nvr", "rb"); break;
case ROM_PC1640: f = romfopen("pc1640.nvr", "rb"); break;
case ROM_PC200: f = romfopen("pc200.nvr", "rb"); break;
case ROM_PC2086: f = romfopen("pc2086.nvr", "rb"); break;
case ROM_PC3086: f = romfopen("pc3086.nvr", "rb"); break;
case ROM_IBMAT: f = romfopen("at.nvr" , "rb"); break;
case ROM_CMDPC30: f = romfopen("cmdpc30.nvr", "rb"); nvrmask = 127; break;
case ROM_AMI286: f = romfopen("ami286.nvr", "rb"); nvrmask = 127; break;
case ROM_DELL200: f = romfopen("dell200.nvr", "rb"); nvrmask = 127; break;
case ROM_IBMAT386: f = romfopen("at386.nvr" , "rb"); nvrmask = 127; break;
case ROM_ACER386: f = romfopen("acer386.nvr", "rb"); nvrmask = 127; break;
case ROM_MEGAPC: f = romfopen("megapc.nvr", "rb"); nvrmask = 127; break;
case ROM_AMI386: f = romfopen("ami386.nvr", "rb"); nvrmask = 127; break;
case ROM_AMI486: f = romfopen("ami486.nvr", "rb"); nvrmask = 127; break;
case ROM_WIN486: f = romfopen("win486.nvr", "rb"); nvrmask = 127; break;
case ROM_PCI486: f = romfopen("hot-433.nvr", "rb"); nvrmask = 127; break;
default: return;
}
if (!f)
{
memset(nvrram,0xFF,128);
return;
}
fread(nvrram,128,1,f);
fclose(f);
nvrram[0xA]=6;
nvrram[0xB]=0;
c=1<<((6&0xF)-1);
rtctime+=RTCCONST*(float)c;
}
void savenvr()
{
FILE *f;
switch (oldromset)
{
case ROM_PC1512: f = romfopen("pc1512.nvr" , "wb"); break;
case ROM_PC1640: f = romfopen("pc1640.nvr" , "wb"); break;
case ROM_PC200: f = romfopen("pc200.nvr" , "wb"); break;
case ROM_PC2086: f = romfopen("pc2086.nvr" , "wb"); break;
case ROM_PC3086: f = romfopen("pc3086.nvr" , "wb"); break;
case ROM_IBMAT: f = romfopen("at.nvr" , "wb"); break;
case ROM_CMDPC30: f = romfopen("cmdpc30.nvr", "wb"); break;
case ROM_AMI286: f = romfopen("ami286.nvr" , "wb"); break;
case ROM_DELL200: f = romfopen("dell200.nvr", "wb"); break;
case ROM_IBMAT386: f = romfopen("at386.nvr" , "wb"); break;
case ROM_ACER386: f = romfopen("acer386.nvr", "wb"); break;
case ROM_MEGAPC: f = romfopen("megapc.nvr" , "wb"); break;
case ROM_AMI386: f = romfopen("ami386.nvr" , "wb"); break;
case ROM_AMI486: f = romfopen("ami486.nvr" , "wb"); break;
case ROM_WIN486: f = romfopen("win486.nvr" , "wb"); break;
case ROM_PCI486: f = romfopen("hot-433.nvr", "wb"); break;
default: return;
}
fwrite(nvrram,128,1,f);
fclose(f);
}
void nvr_init()
{
io_sethandler(0x0070, 0x0002, readnvr, NULL, NULL, writenvr, NULL, NULL);
}

1
src/nvr.h Normal file
View file

@ -0,0 +1 @@
void nvr_init();

20
src/olivetti_m24.c Normal file
View file

@ -0,0 +1,20 @@
#include "ibm.h"
#include "io.h"
#include "olivetti_m24.h"
uint8_t olivetti_m24_read(uint16_t port)
{
switch (port)
{
case 0x66:
return 0x00;
case 0x67:
return 0x20 | 0x40 | 0x0C;
}
return 0xff;
}
void olivetti_m24_init()
{
io_sethandler(0x0066, 0x0002, olivetti_m24_read, NULL, NULL, NULL, NULL, NULL);
}

1
src/olivetti_m24.h Normal file
View file

@ -0,0 +1 @@
void olivetti_m24_init();

284
src/opti.c Normal file
View file

@ -0,0 +1,284 @@
/*OPTi 82C495 emulation
This is the chipset used in the AMI386 model*/
#include "ibm.h"
uint8_t optiregs[0x10];
int optireg;
void writeopti(uint16_t addr, uint8_t val)
{
switch (addr)
{
case 0x22:
optireg=val;
break;
case 0x24:
printf("Writing OPTI reg %02X %02X\n",optireg,val);
if (optireg>=0x20 && optireg<=0x2C) optiregs[optireg-0x20]=val;
break;
}
}
uint8_t readopti(uint16_t addr)
{
switch (addr)
{
case 0x24:
printf("Read OPTI reg %02X\n",optireg);
if (optireg>=0x20 && optireg<=0x2C) return optiregs[optireg-0x20];
break;
}
return 0xFF;
}
/*Details for the chipset from Ralph Brown's interrupt list
This describes the OPTi 82C493, the 82C495 seems similar except there is one
more register (2C)
----------P00220024--------------------------
PORT 0022-0024 - OPTi 82C493 System Controller (SYSC) - CONFIGURATION REGISTERS
Desc: The OPTi 486SXWB contains three chips and is designed for systems
running at 20, 25 and 33MHz. The chipset includes an 82C493 System
Controller (SYSC), the 82C392 Data Buffer Controller, and the
82C206 Integrated peripheral Controller (IPC).
Note: every access to PORT 0024h must be preceded by a write to PORT 0022h,
even if the same register is being accessed a second time
SeeAlso: PORT 0022h"82C206"
0022 ?W configuration register index (see #P0178)
0024 RW configuration register data
(Table P0178)
Values for OPTi 82C493 System Controller configuration register index:
20h Control Register 1 (see #P0179)
21h Control Register 2 (see #P0180)
22h Shadow RAM Control Register 1 (see #P0181)
23h Shadow RAM Control Register 2 (see #P0182)
24h DRAM Control Register 1 (see #P0183)
25h DRAM Control Register 2 (see #P0184)
26h Shadow RAM Control Register 3 (see #P0185)
27h Control Register 3 (see #P0186)
28h Non-cachable Block 1 Register 1 (see #P0187)
29h Non-cachable Block 1 Register 2 (see #P0188)
2Ah Non-cachable Block 2 Register 1 (see #P0187)
2Bh Non-cachable Block 2 Register 2 (see #P0188)
Bitfields for OPTi-82C493 Control Register 1:
Bit(s) Description (Table P0179)
7-6 Revision of 82C493 (readonly) (default=01)
5 Burst wait state control
1 = Secondary cache read hit cycle is 3-2-2-2 or 2-2-2-2
0 = Secondary cache read hit cycle is 3-1-1-1 or 2-1-1-1 (default)
(if bit 5 is set to 1, bit 4 must be set to 0)
4 Cache memory data buffer output enable control
0 = disable (default)
1 = enable
(must be disabled for frequency <= 33Mhz)
3 Single Address Latch Enable (ALE)
0 = disable (default)
1 = enable
(if enabled, SYSC will activate single ALE rather than multiples
during bus conversion cycles)
2 enable Extra AT Cycle Wait State (default is 0 = disabled)
1 Emulation keyboard Reset Control
0 = disable (default)
1 = enable
Note: This bit must be enabled in BIOS default value; enabling this
bit requires HALT instruction to be executed before SYSC
generates processor reset (CPURST)
0 enable Alternative Fast Reset (default is 0 = disabled)
SeeAlso: #P0180,#P0186
Bitfields for OPTi-82C493 Control Register 2:
Bit(s) Description (Table P0180)
7 Master Mode Byte Swap Enable
0 = disable (default)
1 = enable
6 Emulation Keyboard Reset Delay Control
0 = Generate reset pulse 2us later (default)
1 = Generate reset pulse immediately
5 disable Parity Check (default is 0 = enabled)
4 Cache Enable
0 = Cache disabled and DRAM burst mode enabled (default)
1 = Cache enabled and DRAM burst mode disabled
3-2 Cache Size
00 64KB (default)
01 128KB
10 256KB
11 512KB
1 Secondary Cache Read Burst Cycles Control
0 = 3-1-1-1 cycle (default)
1 = 2-1-1-1 cycle
0 Cache Write Wait State Control
0 = 1 wait state (default)
1 = 0 wait state
SeeAlso: #P0179,#P0186
Bitfields for OPTi-82C493 Shadow RAM Control Register 1:
Bit(s) Description (Table P0181)
7 ROM(F0000h - FFFFFh) Enable
0 = read/write on write-protected DRAM
1 = read from ROM, write to DRAM (default)
6 Shadow RAM at D0000h - EFFFFh Area
0 = disable (default)
1 = enable
5 Shadow RAM at E0000h - EFFFFh Area
0 = disable shadow RAM (default)
E0000h - EFFFFh ROM is defaulted to reside on XD bus
1 = enable shadow RAM
4 enable write-protect for Shadow RAM at D0000h - DFFFFh Area
0 = disable (default)
1 = enable
3 enable write-protect for Shadow RAM at E0000h - EFFFFh Area
0 = disable (default)
1 = enable
2 Hidden refresh enable (with holding CPU)
(Hidden refresh must be disabled if 4Mx1 or 1M x4 bit DRAM are used)
1 = disable (default)
0 = enable
1 unused
0 enable Slow Refresh (four times slower than normal refresh)
(default is 0 = disable)
SeeAlso: #P0182
Bitfields for OPTi-82C493 Shadow RAM Control Register 2:
Bit(s) Description (Table P0182)
7 enable Shadow RAM at EC000h - EFFFFh area
6 enable Shadow RAM at E8000h - EBFFFh area
5 enable Shadow RAM at E4000h - E7FFFh area
4 enable Shadow RAM at E0000h - E3FFFh area
3 enable Shadow RAM at DC000h - DFFFFh area
2 enable Shadow RAM at D8000h - DBFFFh area
1 enable Shadow RAM at D4000h - D7FFFh area
0 enable Shadow RAM at D0000h - D3FFFh area
Note: the default is disabled (0) for all areas
Bitfields for OPTi-82C493 DRAM Control Register 1:
Bit(s) Description (Table P0183)
7 DRAM size
0 = 256K DRAM mode
1 = 1M and 4M DRAM mode
6-4 DRAM types used for bank0 and bank1
bits 7-4 Bank0 Bank1
0000 256K x
0001 256K 256K
0010 256K 1M
0011 x x
01xx x x
1000 1M x (default)
1001 1M 1M
1010 1M 4M
1011 4M 1M
1100 4M x
1101 4M 4M
111x x x
3 unused
2-0 DRAM types used for bank2 and bank3
bits 7,2-0 Bank2 Bank3
x000 1M x
x001 1M 1M
x010 x x
x011 4M 1M
x100 4M x
x101 4M 4M
x11x x x (default)
SeeAlso: #P0184
Bitfields for OPTi-82C493 DRAM Control Register 2:
Bit(s) Description (Table P0184)
7-6 Read cycle additional wait states
00 not used
01 = 0
10 = 1
11 = 2 (default)
5-4 Write cycle additional wait states
00 = 0
01 = 1
10 = 2
11 = 3 (default)
3 Fast decode enable
0 = disable fast decode. DRAM base wait states not changed (default)
1 = enable fast decode. DRAM base wait state is decreased by 1
Note: This function may be enabled in 20/25Mhz operation to speed up
DRAM access. If bit 4 of index register 21h (cache enable
bit) is enabled, this bit is automatically disabled--even if
set to 1
2 unused
1-0 ATCLK selection
00 ATCLK = CLKI/6 (default)
01 ATCLK = CLKI/4 (default)
10 ATCLK = CLKI/3
11 ATCLK = CLK2I/5 (CLKI * 2 /5)
Note: bit 0 will reflect the BCLKS (pin 142) status and bit 1 will be
set to 0 when 82C493 is reset.
SeeAlso: #P0183,#P0185
Bitfields for OPTi-82C493 Shadow RAM Control Register 3:
Bit(s) Description (Table P0185)
7 unused
6 Shadow RAM copy enable for address C0000h - CFFFFh
0 = Read/write at AT bus (default)
1 = Read from AT bus and write into shadow RAM
5 Shadow write protect at address C0000h - CFFFFh
0 = Write protect disable (default)
1 = Write protect enable
4 enable Shadow RAM at C0000h - CFFFFh
3 enable Shadow RAM at CC000h - CFFFFh
2 enable Shadow RAM at C8000h - CBFFFh
1 enable Shadow RAM at C4000h - C7FFFh
0 enable Shadow RAM at C0000h - C3FFFh
Note: the default is disabled (0) for bits 4-0
SeeAlso: #P0183,#P0184
Bitfields for OPTi-82C493 Control Register 3:
Bit(s) Description (Table P0186)
7 enable NCA# pin to low state (default is 1 = enabled)
6-5 unused
4 Video BIOS at C0000h - C8000h non-cacheable
0 = cacheable
1 = non-cacheable (default)
3-0 Cacheable address range for local memory
0000 0 - 64MB
0001 0 - 4MB (default)
0010 0 - 8MB
0011 0 - 12MB
0100 0 - 16MB
0101 0 - 20MB
0110 0 - 24MB
0111 0 - 28MB
1000 0 - 32MB
1001 0 - 36MB
1010 0 - 40MB
1011 0 - 44MB
1100 0 - 48MB
1101 0 - 52MB
1110 0 - 56MB
1111 0 - 60MB
Note: If total memory is 1MB or 2MB the cacheable range is 0-1 MB or
0-2 MB and independent of the value of bits 3-0
SeeAlso: #P0179,#P0180
Bitfields for OPTi-82C493 Non-cacheable Block Register 1:
Bit(s) Description (Table P0187)
7-5 Size of non-cachable memory block
000 64K
001 128K
010 256K
011 512K
1xx disabled (default)
4-2 unused
1-0 Address bits 25 and 24 of non-cachable memory block (default = 00)
Note: this register is used together with configuration register 29h
(non-cacheable block 1) or register 2Bh (block 2) (see #P0188) to
define a non-cacheable block. The starting address must be a
multiple of the block size
SeeAlso: #P0178,#P0188
Bitfields for OPTi-82C493 Non-cacheable Block Register 2:
Bit(s) Description (Table P0188)
7-0 Address bits 23-16 of non-cachable memory block (default = 0001xxxx)
Note: the block address is forced to be a multiple of the block size by
ignoring the appropriate number of the least-significant bits
SeeAlso: #P0178,#P0187
*/

491
src/pc.c Normal file
View file

@ -0,0 +1,491 @@
#include <stdio.h>
#include <stdarg.h>
#include "ibm.h"
#include "video.h"
#include "amstrad.h"
#include "dma.h"
#include "mem.h"
#include "ide.h"
#include "mouse.h"
#include "pic.h"
#include "pit.h"
#include "serial.h"
#include "cdrom-ioctl.h"
#include "cpu.h"
#include "model.h"
#include "plat-mouse.h"
int cdrom_enabled;
int CPUID;
int kb_win;
int vid_resize;
int cycles_lost = 0;
int clockrate;
int insc=0;
float mips,flops;
extern int mmuflush;
extern int readlnum,writelnum;
void fullspeed();
int framecount,fps;
int pitsec;
int intcount;
int wakeups,wokeups;
int output;
int atfullspeed;
void loadconfig();
void saveconfig();
int infocus;
int mousecapture;
FILE *pclogf;
void pclog(const char *format, ...)
{
char buf[256];
return;
if (!pclogf)
pclogf=fopen("pclog.txt","wt");
//return;
va_list ap;
va_start(ap, format);
vsprintf(buf, format, ap);
va_end(ap);
fputs(buf,pclogf);
fflush(pclogf);
}
void fatal(const char *format, ...)
{
char buf[256];
// return;
if (!pclogf)
pclogf=fopen("pclog.txt","wt");
//return;
va_list ap;
va_start(ap, format);
vsprintf(buf, format, ap);
va_end(ap);
fputs(buf,pclogf);
fflush(pclogf);
dumpregs();
exit(-1);
}
uint8_t cgastat;
int drawit=0;
int pollmouse_delay = 2;
void pollmouse()
{
int x,y;
pollmouse_delay--;
if (pollmouse_delay) return;
pollmouse_delay = 2;
poll_mouse();
get_mouse_mickeys(&x,&y);
if (mouse_poll)
mouse_poll(x, y, mouse_b);
if (mousecapture) position_mouse(64,64);
}
/*PC1512 languages -
7=English
6=German
5=French
4=Spanish
3=Danish
2=Swedish
1=Italian
3,2,1 all cause the self test to fail for some reason
*/
int cpuspeed2;
int clocks[3][12][4]=
{
{
{4772728,13920,59660,5965}, /*4.77MHz*/
{8000000,23333,110000,0}, /*8MHz*/
{10000000,29166,137500,0}, /*10MHz*/
{12000000,35000,165000,0}, /*12MHz*/
{16000000,46666,220000,0}, /*16MHz*/
},
{
{8000000,23333,110000,0}, /*8MHz*/
{12000000,35000,165000,0}, /*12MHz*/
{16000000,46666,220000,0}, /*16MHz*/
{20000000,58333,275000,0}, /*20MHz*/
{25000000,72916,343751,0}, /*25MHz*/
},
{
{16000000, 46666,220000,0}, /*16MHz*/
{20000000, 58333,275000,0}, /*20MHz*/
{25000000, 72916,343751,0}, /*25MHz*/
{33000000, 96000,454000,0}, /*33MHz*/
{40000000,116666,550000,0}, /*40MHz*/
{50000000, 72916*2,343751*2,0}, /*50MHz*/
{33000000*2, 96000*2,454000*2,0}, /*66MHz*/
{75000000, 72916*3,343751*3,0}, /*75MHz*/
{80000000,116666*2,550000*2,0}, /*80MHz*/
{100000000, 72916*4,343751*4,0}, /*100MHz*/
{120000000,116666*3,550000*3,0}, /*120MHz*/
{133000000, 96000*4,454000*4,0}, /*133MHz*/
}
};
int updatestatus;
int win_title_update=0;
void onesec()
{
fps=framecount;
framecount=0;
win_title_update=1;
}
void pc_reset()
{
resetx86();
cpu_set();
dma_reset();
fdc_reset();
pic_reset();
pit_reset();
serial_reset();
setpitclock(models[model].cpu[cpu_manufacturer].cpus[cpu].rspeed);
adlib_reset();
sb_reset();
ali1429_reset();
et4000w32_reset();
// video_init();
}
void initpc()
{
char *p;
// allegro_init();
get_executable_name(pcempath,511);
pclog("executable_name = %s\n", pcempath);
p=get_filename(pcempath);
*p=0;
pclog("path = %s\n", pcempath);
keyboard_init();
mouse_init();
loadconfig();
pclog("Config loaded\n");
cpuspeed2=(AT)?2:1;
// cpuspeed2=cpuspeed;
atfullspeed=0;
pclog("Initvideo\n");
initvideo();
mem_init();
loadbios();
loaddisc(0,discfns[0]);
loaddisc(1,discfns[1]);
//loadfont();
loadnvr();
resetvideo();
initsound();
initpsg();
inithdc();
initega();
initgus();
resetide();
ioctl_open(cdrom_drive);
model_init();
video_init();
adlib_init();
sb_init();
gus_init();
pc_reset();
pit_reset();
install_int_ex(onesec,BPS_TO_TIMER(1));
// install_int_ex(vsyncint,BPS_TO_TIMER(60));
/* if (romset==ROM_AMI386 || romset==ROM_AMI486) */fullspeed();
mem_updatecache();
ali1429_reset();
et4000w32_reset();
// CPUID=(is486 && (cpuspeed==7 || cpuspeed>=9));
// pclog("Init - CPUID %i %i\n",CPUID,cpuspeed);
shadowbios=0;
}
void resetpc()
{
pc_reset();
// cpuspeed2=(AT)?2:1;
// atfullspeed=0;
///* if (romset==ROM_AMI386 || romset==ROM_AMI486) */fullspeed();
shadowbios=0;
}
void resetpchard()
{
mem_resize();
model_init();
pclog("Video_init\n");
video_init();
adlib_init();
sb_init();
gus_init();
pc_reset();
resetide();
loadnvr();
// cpuspeed2 = (AT)?2:1;
// atfullspeed = 0;
// setpitclock(models[model].cpu[cpu_manufacturer].cpus[cpu].rspeed);
shadowbios = 0;
ali1429_reset();
keyboard_at_reset();
// output=3;
}
char romsets[17][40]={"IBM PC","IBM XT","Generic Turbo XT","Euro PC","Tandy 1000","Amstrad PC1512","Sinclair PC200","Amstrad PC1640","IBM AT","AMI 286 clone","Dell System 200","Misc 286","IBM AT 386","Misc 386","386 clone","486 clone","486 clone 2"};
char clockspeeds[3][12][16]=
{
{"4.77MHz","8MHz","10MHz","12MHz","16MHz"},
{"8MHz","12MHz","16MHz","20MHz","25MHz"},
{"16MHz","20MHz","25MHz","33MHz","40MHz","50MHz","66MHz","75MHz","80MHz","100MHz","120MHz","133MHz"},
};
int framecountx=0;
int sndcount=0;
int oldat70hz;
int sreadlnum,swritelnum,segareads,segawrites, scycles_lost;
int serial_fifo_read, serial_fifo_write;
int emu_fps = 0;
void runpc()
{
char s[200];
int done=0;
clockrate = models[model].cpu[cpu_manufacturer].cpus[cpu].rspeed;
if (is386) exec386(models[model].cpu[cpu_manufacturer].cpus[cpu].rspeed / 100);
else if (AT) exec286(models[model].cpu[cpu_manufacturer].cpus[cpu].rspeed / 100);
else execx86(models[model].cpu[cpu_manufacturer].cpus[cpu].rspeed / 100);
keyboard_poll_host();
keyboard_process();
// checkkeys();
pollmouse();
framecountx++;
framecount++;
if (framecountx>=100)
{
framecountx=0;
mips=(float)insc/1000000.0f;
insc=0;
flops=(float)fpucount/1000000.0f;
fpucount=0;
sreadlnum=readlnum;
swritelnum=writelnum;
segareads=egareads;
segawrites=egawrites;
scycles_lost = cycles_lost;
updatestatus=1;
readlnum=writelnum=0;
egareads=egawrites=0;
cycles_lost = 0;
mmuflush=0;
pitsec=0;
intcount=0;
wakeups=wokeups=0;
intcount=pitcount=0;
emu_fps = frames;
frames = 0;
}
if (win_title_update)
{
win_title_update=0;
sprintf(s, "PCem v0.7 - %s - %s - %s - %i%% %i %04X %i", model_getname(), models[model].cpu[cpu_manufacturer].cpus[cpu].name, (!mousecapture) ? "Click to capture mouse" : "Press CTRL-END to release mouse", fps, et4000w32p_getclock(), ECX, ins);
set_window_title(s);
}
done++;
/* if ((at70hz && VGA)!=oldat70hz)
{
oldat70hz=(at70hz && VGA);
if (oldat70hz) setrefresh(70); //install_int_ex(vsyncint,BPS_TO_TIMER(70));
else setrefresh(60); //install_int_ex(vsyncint,BPS_TO_TIMER(60));
drawit=0;
done=0;
}*/
// printf("End of run!\n");
// }
}
void fullspeed()
{
cpuspeed2=cpuspeed;
if (!atfullspeed)
{
printf("Set fullspeed - %i %i %i\n",is386,AT,cpuspeed2);
setpitclock(models[model].cpu[cpu_manufacturer].cpus[cpu].rspeed);
// if (is386) setpitclock(clocks[2][cpuspeed2][0]);
// else setpitclock(clocks[AT?1:0][cpuspeed2][0]);
}
atfullspeed=1;
nvr_recalc();
}
void speedchanged()
{
if (atfullspeed)
{
cpuspeed2=cpuspeed;
setpitclock(models[model].cpu[cpu_manufacturer].cpus[cpu].rspeed);
// if (is386) setpitclock(clocks[2][cpuspeed2][0]);
// else setpitclock(clocks[AT?1:0][cpuspeed2][0]);
}
mem_updatecache();
nvr_recalc();
}
void closepc()
{
atapi->exit();
// ioctl_close();
dumpegaregs();
dumppic();
dumpgus();
// output=7;
// setpitclock(clocks[0][0][0]);
// while (1) runpc();
savedisc(0);
savedisc(1);
dumpregs();
closevideo();
}
/*int main()
{
initpc();
while (!key[KEY_F11])
{
runpc();
}
closepc();
return 0;
}
END_OF_MAIN();*/
int cga_comp=0;
void loadconfig()
{
char s[512];
char *p;
append_filename(s,pcempath,"pcem.cfg",511);
set_config_file(s);
ADLIB=get_config_int(NULL,"adlib",1);
GAMEBLASTER=get_config_int(NULL,"gameblaster",0);
FASTDISC=get_config_int(NULL,"fast_disc",1);
model = get_config_int(NULL, "model", 14);
pclog("Model %i\n", model);
romset = model_getromset();
cpu_manufacturer = get_config_int(NULL, "cpu_manufacturer", 0);
cpu = get_config_int(NULL, "cpu", 0);
gfxcard=get_config_int(NULL,"gfxcard",0);
video_speed = get_config_int(NULL, "video_speed", 3);
sbtype=get_config_int(NULL,"sndcard",SB2);
pclog("Model1 %i\n", model);
p=(char *)get_config_string(NULL,"disc_a","");
if (p) strcpy(discfns[0],p);
else strcpy(discfns[0],"");
pclog("Model2 %i\n", model);
p=(char *)get_config_string(NULL,"disc_b","");
if (p) strcpy(discfns[1],p);
else strcpy(discfns[1],"");
pclog("Model3 %i\n", model);
mem_size=get_config_int(NULL,"mem_size",4);
cdrom_drive=get_config_int(NULL,"cdrom_drive",0);
cdrom_enabled=get_config_int(NULL,"cdrom_enabled",0);
slowega=get_config_int(NULL,"slow_video",1);
cache=get_config_int(NULL,"cache",3);
cga_comp=get_config_int(NULL,"cga_composite",0);
kb_win=get_config_int(NULL,"kb_win",0);
vid_resize=get_config_int(NULL,"vid_resize",0);
// cpuspeed=2;
hdc[0].spt=get_config_int(NULL,"hdc_sectors",0);
hdc[0].hpc=get_config_int(NULL,"hdc_heads",0);
hdc[0].tracks=get_config_int(NULL,"hdc_cylinders",0);
p = (char *)get_config_string(NULL, "hdc_fn", "");
if (p) strcpy(ide_fn[0], p);
else strcpy(ide_fn[0], "");
hdc[1].spt=get_config_int(NULL,"hdd_sectors",0);
hdc[1].hpc=get_config_int(NULL,"hdd_heads",0);
hdc[1].tracks=get_config_int(NULL,"hdd_cylinders",0);
p = (char *)get_config_string(NULL, "hdd_fn", "");
if (p) strcpy(ide_fn[1], p);
else strcpy(ide_fn[1], "");
pclog("Model4 %i\n", model);
}
void saveconfig()
{
pclog("saveconfig\n");
config_new();
pclog("config_new\n");
set_config_int(NULL,"adlib",ADLIB);
pclog("sci 1\n");
set_config_int(NULL,"gameblaster",GAMEBLASTER);
set_config_int(NULL,"fast_disc",FASTDISC);
set_config_int(NULL, "model", model);
set_config_int(NULL, "cpu_manufacturer", cpu_manufacturer);
set_config_int(NULL, "cpu", cpu);
set_config_int(NULL,"gfxcard",gfxcard);
set_config_int(NULL,"video_speed", video_speed);
set_config_int(NULL,"sndcard",sbtype);
set_config_int(NULL,"cpu_speed",cpuspeed);
set_config_int(NULL,"has_fpu",hasfpu);
set_config_int(NULL,"slow_video",slowega);
set_config_int(NULL,"cache",cache);
set_config_int(NULL,"cga_composite",cga_comp);
set_config_string(NULL,"disc_a",discfns[0]);
set_config_string(NULL,"disc_b",discfns[1]);
set_config_int(NULL,"mem_size",mem_size);
set_config_int(NULL,"cdrom_drive",cdrom_drive);
set_config_int(NULL,"cdrom_enabled",cdrom_enabled);
set_config_int(NULL,"kb_win",kb_win);
set_config_int(NULL,"vid_resize",vid_resize);
set_config_int(NULL,"hdc_sectors",hdc[0].spt);
set_config_int(NULL,"hdc_heads",hdc[0].hpc);
set_config_int(NULL,"hdc_cylinders",hdc[0].tracks);
set_config_string(NULL, "hdc_fn", ide_fn[0]);
set_config_int(NULL,"hdd_sectors",hdc[1].spt);
set_config_int(NULL,"hdd_heads",hdc[1].hpc);
set_config_int(NULL,"hdd_cylinders",hdc[1].tracks);
set_config_string(NULL, "hdd_fn", ide_fn[1]);
pclog("saveconfig done\n");
}

158
src/pc.rc Normal file
View file

@ -0,0 +1,158 @@
#include <windows.h>
#include "resources.h"
MainMenu MENU DISCARDABLE
BEGIN
POPUP "&File"
BEGIN
MENUITEM "&Hard Reset", IDM_FILE_HRESET
MENUITEM "E&xit", IDM_FILE_EXIT
END
POPUP "&Disc"
BEGIN
MENUITEM "Change drive &A:...", IDM_DISC_A
MENUITEM "Change drive &B:...", IDM_DISC_B
MENUITEM "&Eject drive A:", IDM_EJECT_A
MENUITEM "Eject drive B:", IDM_EJECT_B
MENUITEM "&Configure hard discs...",IDM_HDCONF
END
POPUP "&Settings"
BEGIN
MENUITEM "&Configure...", IDM_CONFIG
POPUP "&CD-ROM"
BEGIN
MENUITEM "&Disabled", IDM_CDROM_DISABLED
MENUITEM "&Empty",IDM_CDROM_EMPTY
END
POPUP "&Video"
BEGIN
MENUITEM "&Resizeable window",IDM_VID_RESIZE
END
END
POPUP "&Misc"
BEGIN
MENUITEM "&Status", IDM_STATUS
END
END
ConfigureDlg DIALOGEX 0, 0, 182, 240
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Configure PCem"
FONT 8, "MS Sans Serif"
BEGIN
DEFPUSHBUTTON "OK",IDOK,17,216,50,14, WS_TABSTOP
PUSHBUTTON "Cancel",IDCANCEL,71,216,50,14, WS_TABSTOP
COMBOBOX IDC_COMBO1,62,16,107,120,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP
COMBOBOX IDC_COMBO2,62,36,107,120,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP
COMBOBOX IDC_COMBOCPUM,62,56,107,120,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP
COMBOBOX IDC_COMBO3,62,76,107,120,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP
COMBOBOX IDC_COMBOCHC,62,96,107,120,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP
COMBOBOX IDC_COMBOSPD,62,116,107,120,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP
COMBOBOX IDC_COMBOSND,62,136,107,120,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP
COMBOBOX IDC_COMBOMEM,62,152,107,120,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP
CONTROL "Game Blaster",IDC_CHECK3,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,172,118,10
CONTROL "Composite CGA",IDC_CHECK4,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,188,118,10
LTEXT "Machine :",IDC_STATIC,15,16,40,10
LTEXT "Video :",IDC_STATIC,15,36,34,10
LTEXT "CPU type :",IDC_STATIC,15,56,34,10
LTEXT "CPU :",IDC_STATIC,15,76,34,10
LTEXT "Cache :",IDC_STATIC,15,96,40,10
LTEXT "Video speed :",IDC_STATIC,15,116,40,10
LTEXT "Soundcard :",IDC_STATIC,15,136,40,10
LTEXT "Memory :",IDC_STATIC,15,156,40,10
END
HdConfDlg DIALOGEX 0, 0, 186, 172
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Configure Hard Discs"
FONT 8, "MS Sans Serif"
BEGIN
DEFPUSHBUTTON "OK",IDOK,31,152,50,14
PUSHBUTTON "Cancel",IDCANCEL,101,152,50,14
LTEXT "C:",IDC_STATIC,7,6,27,10
EDITTEXT IDC_EDITC, 7, 22, 136, 12, WS_DISABLED
PUSHBUTTON "...",IDC_CFILE,7 + 136, 22, 16, 14
PUSHBUTTON "New",IDC_CNEW,7 + 136 + 16, 22, 24, 14
EDITTEXT IDC_EDIT1,36,38,16,12, WS_DISABLED
EDITTEXT IDC_EDIT2,94,38,16,12, WS_DISABLED
EDITTEXT IDC_EDIT3,152,38,28,12, WS_DISABLED
LTEXT "Sectors:",IDC_STATIC,7,38,27,10
LTEXT "Heads:",IDC_STATIC,63,38,29,8
LTEXT "Cylinders:",IDC_STATIC,120,38,32,12
LTEXT "", IDC_TEXT1, 7, 54, 136, 12
LTEXT "D:",IDC_STATIC,7,76,27,10
EDITTEXT IDC_EDITD, 7, 92, 136, 12, WS_DISABLED
PUSHBUTTON "...",IDC_DFILE,7 + 136, 92, 16, 14
PUSHBUTTON "New",IDC_DNEW,7 + 136 + 16, 92, 24, 14
EDITTEXT IDC_EDIT4,36,108,16,12, WS_DISABLED
EDITTEXT IDC_EDIT5,94,108,16,12, WS_DISABLED
EDITTEXT IDC_EDIT6,152,108,28,12, WS_DISABLED
LTEXT "Sectors:",IDC_STATIC,7,108,27,10
LTEXT "Heads:",IDC_STATIC,63,108,29,8
LTEXT "Cylinders:",IDC_STATIC,120,108,32,12
LTEXT "", IDC_TEXT2, 7, 124, 136, 12
END
HdNewDlg DIALOGEX 0, 0, 186, 86
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "New Hard Disc"
FONT 8, "MS Sans Serif"
BEGIN
DEFPUSHBUTTON "OK",IDOK,31,66,50,14
PUSHBUTTON "Cancel",IDCANCEL,101,66,50,14
EDITTEXT IDC_EDITC, 7, 6, 136, 12
PUSHBUTTON "...",IDC_CFILE,7 + 136, 6, 16, 14
EDITTEXT IDC_EDIT1,36,22,16,12
EDITTEXT IDC_EDIT2,94,22,16,12
EDITTEXT IDC_EDIT3,152,22,28,12
LTEXT "Sectors:",IDC_STATIC,7,22,27,10
LTEXT "Heads:",IDC_STATIC,63,22,29,8
LTEXT "Cylinders:",IDC_STATIC,120,22,32,12
LTEXT "", IDC_TEXT1, 7, 38, 136, 12
END
HdSizeDlg DIALOGEX 0, 0, 186, 86
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Hard disc parameters"
FONT 8, "MS Sans Serif"
BEGIN
DEFPUSHBUTTON "OK",IDOK,31,66,50,14
PUSHBUTTON "Cancel",IDCANCEL,101,66,50,14
LTEXT "Initial settings are based on file size",IDC_STATIC,7,6,170,10
EDITTEXT IDC_EDIT1,36,22,16,12
EDITTEXT IDC_EDIT2,94,22,16,12
EDITTEXT IDC_EDIT3,152,22,28,12
LTEXT "Sectors:",IDC_STATIC,7,22,27,10
LTEXT "Heads:",IDC_STATIC,63,22,29,8
LTEXT "Cylinders:",IDC_STATIC,120,22,32,12
LTEXT "", IDC_TEXT1, 7, 38, 136, 12
END
StatusDlg DIALOGEX 0,0,186,186
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Status"
FONT 8, "MS Sans Serif"
BEGIN
LTEXT "1",IDC_STEXT1,16,16,180,10
LTEXT "2",IDC_STEXT2,16,28,180,10
LTEXT "3",IDC_STEXT3,16,40,180,10
LTEXT "4",IDC_STEXT4,16,52,180,10
LTEXT "5",IDC_STEXT5,16,64,180,10
LTEXT "6",IDC_STEXT6,16,76,180,10
LTEXT "7",IDC_STEXT7,16,88,180,10
LTEXT "8",IDC_STEXT8,16,100,180,10
LTEXT "9",IDC_STEXT9,16,112,180,10
LTEXT "10",IDC_STEXT10,16,124,180,10
LTEXT "11",IDC_STEXT11,16,136,180,10
LTEXT "12",IDC_STEXT12,16,148,180,10
LTEXT "13",IDC_STEXT13,16,160,180,10
END

99
src/pci.c Normal file
View file

@ -0,0 +1,99 @@
#include "ibm.h"
#include "io.h"
#include "mem.h"
#include "pci.h"
void (*pci_card_write[32])(int func, int addr, uint8_t val);
uint8_t (*pci_card_read[32])(int func, int addr);
static int pci_index, pci_func, pci_card, pci_bus, pci_enable;
static uint8_t card_16[256];
static uint8_t card_18[256];
void pci_write(uint16_t port, uint8_t val)
{
switch (port)
{
case 0xcf8:
pci_index = val;
break;
case 0xcf9:
pci_func = val & 7;
pci_card = val >> 3;
break;
case 0xcfa:
pci_bus = val;
break;
case 0xcfb:
pci_enable = val & 0x80;
break;
case 0xcfc: case 0xcfd: case 0xcfe: case 0xcff:
if (!pci_enable)
return;
pclog("PCI write bus %i card %i index %02X val %02X %04X:%04X\n", pci_bus, pci_card, pci_index | (port & 3), val, CS, pc);
if (!pci_bus && pci_card_write[pci_card])
pci_card_write[pci_card](pci_func, pci_index | (port & 3), val);
break;
}
}
uint8_t pci_read(uint16_t port)
{
switch (port)
{
case 0xcf8:
return pci_index;
case 0xcf9:
return pci_card << 3;
case 0xcfa:
return pci_bus;
case 0xcfb:
return pci_enable;
case 0xcfc: case 0xcfd: case 0xcfe: case 0xcff:
if (!pci_enable)
return 0xff;
pclog("PCI read bus %i card %i index %02X\n", pci_bus, pci_card, pci_index | (port & 3));
if (!pci_bus && pci_card_read[pci_card])
return pci_card_read[pci_card](pci_func, pci_index | (port & 3));
return 0xff;
}
}
void pci_init()
{
int c;
io_sethandler(0x0cf8, 0x0008, pci_read, NULL, NULL, pci_write, NULL, NULL);
for (c = 0; c < 32; c++)
pci_card_read[c] = pci_card_write[c] = NULL;
}
void pci_add_specific(int card, uint8_t (*read)(int func, int addr), void (*write)(int func, int addr, uint8_t val))
{
pci_card_read[card] = read;
pci_card_write[card] = write;
}
void pci_add(uint8_t (*read)(int func, int addr), void (*write)(int func, int addr, uint8_t val))
{
int c;
for (c = 0; c < 32; c++)
{
if (!pci_card_read[c] && !pci_card_write[c])
{
pci_card_read[c] = read;
pci_card_write[c] = write;
return;
}
}
}

3
src/pci.h Normal file
View file

@ -0,0 +1,3 @@
void pci_init();
void pci_add_specific(int card, uint8_t (*read)(int func, int addr), void (*write)(int func, int addr, uint8_t val));
void pci_add(uint8_t (*read)(int func, int addr), void (*write)(int func, int addr, uint8_t val));

313
src/pic.c Normal file
View file

@ -0,0 +1,313 @@
#include "ibm.h"
int output;
int intclear;
int keywaiting=0;
int pit0;
int pic_intpending;
void pic_updatepending()
{
pic_intpending = (((pic.pend&~pic.mask)&~pic.mask2) || ((pic2.pend&~pic2.mask)&~pic2.mask2));
}
void pic_reset()
{
pic.icw=0;
pic.mask=0xFF;
pic.mask2=0;
pic.pend=pic.ins=0;
pic.vector=8;
pic.read=1;
pic2.icw=0;
pic2.mask=0xFF;
pic.mask2=0;
pic2.pend=pic2.ins=0;
pic_intpending = 0;
}
void pic_write(uint16_t addr, uint8_t val)
{
int c;
// pclog("Write PIC %04X %02X %04X(%06X):%04X\n",addr,val,CS,cs,pc);
if (addr&1)
{
switch (pic.icw)
{
case 0: /*OCW1*/
// printf("Write mask %02X %04X:%04X\n",val,CS,pc);
pic.mask=val;
pic_updatepending();
break;
case 1: /*ICW2*/
pic.vector=val&0xF8;
// printf("PIC vector now %02X\n",pic.vector);
// output=1;
if (pic.icw1&2) pic.icw=3;
else pic.icw=2;
break;
case 2: /*ICW3*/
if (pic.icw1&1) pic.icw=3;
else pic.icw=0;
break;
case 3: /*ICW4*/
pic.icw=0;
break;
}
}
else
{
if (val&16) /*ICW1*/
{
pic.mask=0xFF;
pic.mask2=0;
pic.icw=1;
pic.icw1=val;
pic_updatepending();
}
else if (!(val&8)) /*OCW2*/
{
// printf("Clear ints - %02X %02X\n",pic.ins,val);
if ((val&0xE0)==0x60)
{
// pclog("Specific EOI - %02X %i\n",pic.ins,1<<(val&7));
pic.ins&=~(1<<(val&7));
pic.mask2&=~(1<<(val&7));
// pic.pend&=(1<<(val&7));
// if ((val&7)==1) pollkeywaiting();
pic_updatepending();
}
else
{
for (c=0;c<8;c++)
{
if (pic.ins&(1<<c))
{
pic.ins&=~(1<<c);
pic.mask2&=~(1<<c);
// pic.pend&=~(1<<c);
if (c==0) pit0=1;
if (c==1 && keywaiting)
{
intclear&=~1;
// pollkeywaiting();
}
pic_updatepending();
// pclog("Generic EOI - Cleared int %i\n",c);
return;
}
}
}
}
else /*OCW3*/
{
// if (val&4) fatal("PIC1 write OCW3 4 %02X\n",val);
if (val&2) pic.read=(val&1);
if (val&0x40) { } //fatal("PIC 1 write OCW3 40 %02X\n",val);
}
}
}
uint8_t pic_read(uint16_t addr)
{
if (addr&1) { /*pclog("Read PIC mask %02X\n",pic.mask);*/ return pic.mask; }
if (pic.read) { /*pclog("Read PIC ins %02X\n",pic.ins);*/ return pic.ins; }
// pclog("Read PIC pend %02X %08X\n",pic.pend,EDX);
return pic.pend;
}
void pic_init()
{
io_sethandler(0x0020, 0x0002, pic_read, NULL, NULL, pic_write, NULL, NULL);
}
void pic2_write(uint16_t addr, uint8_t val)
{
int c;
// pclog("Write PIC2 %04X %02X %04X:%04X %i\n",addr,val,CS,pc,ins);
if (addr&1)
{
switch (pic2.icw)
{
case 0: /*OCW1*/
// printf("PIC2 Write mask %02X %04X:%04X\n",val,CS,pc);
pic2.mask=val;
pic_updatepending();
break;
case 1: /*ICW2*/
pic2.vector=val&0xF8;
if (pic2.icw1&2) pic2.icw=3;
else pic2.icw=2;
break;
case 2: /*ICW3*/
if (pic2.icw1&1) pic2.icw=3;
else pic2.icw=0;
break;
case 3: /*ICW4*/
pic2.icw=0;
break;
}
}
else
{
if (val&16) /*ICW1*/
{
pic2.mask=0xFF;
pic2.mask2=0;
pic2.icw=1;
pic2.icw1=val;
pic_updatepending();
}
else if (!(val&8)) /*OCW2*/
{
if ((val&0xE0)==0x60)
{
pic2.ins&=~(1<<(val&7));
pic2.mask2&=~(1<<(val&7));
pic_updatepending();
}
else
{
for (c=0;c<8;c++)
{
if (pic2.ins&(1<<c))
{
pic2.ins&=~(1<<c);
pic2.mask2&=~(1<<c);
pic_updatepending();
return;
}
}
}
}
else /*OCW3*/
{
if (val&2) pic2.read=(val&1);
}
}
}
uint8_t pic2_read(uint16_t addr)
{
if (addr&1) { /*pclog("Read PIC2 mask %02X %04X:%08X\n",pic2.mask,CS,pc); */return pic2.mask; }
if (pic2.read) { /*pclog("Read PIC2 ins %02X %04X:%08X\n",pic2.ins,CS,pc); */return pic2.ins; }
// pclog("Read PIC2 pend %02X %04X:%08X\n",pic2.pend,CS,pc);
return pic2.pend;
}
void pic2_init()
{
io_sethandler(0x00a0, 0x0002, pic2_read, NULL, NULL, pic2_write, NULL, NULL);
}
void clearpic()
{
pic.pend=pic.ins=0;
pic_updatepending();
// pclog("Clear PIC\n");
}
int pic_current[16];
void picint(uint16_t num)
{
// if (num == 0x10) pclog("PICINT 10\n");
if (num>0xFF)
{
pic2.pend|=(num>>8);
}
else
{
pic.pend|=num;
}
pic_updatepending();
}
void picintlevel(uint16_t num)
{
int c = 0;
while (!(num & (1 << c))) c++;
// pclog("INTLEVEL %04X %i\n", num, c);
if (!pic_current[c])
{
pic_current[c]=1;
if (num>0xFF)
{
pic2.pend|=(num>>8);
}
else
{
pic.pend|=num;
}
}
pic_updatepending();
}
void picintc(uint16_t num)
{
int c = 0;
while (!(num & (1 << c))) c++;
// pclog("INTC %04X %i\n", num, c);
pic_current[c]=0;
if (num>0xFF) pic2.pend&=~(num>>8);
else
{
pic.pend&=~num;
}
}
uint8_t picinterrupt()
{
uint8_t temp=pic.pend&~pic.mask;
int c;
for (c=0;c<8;c++)
{
if (temp&(1<<c))
{
pic.pend&=~(1<<c);
pic.ins|=(1<<c);
pic.mask2|=(1<<c);
pic_updatepending();
// if (!c) pclog("Taking timer int\n");
// if (c==5) printf("GUS IRQ!\n");
// if (c==1) printf("Keyboard int!\n");
// if (c==0) pic.ins&=~1;
return c+pic.vector;
}
}
temp=pic2.pend&~pic2.mask;
for (c=0;c<8;c++)
{
if (temp&(1<<c))
{
pic2.pend&=~(1<<c);
pic2.ins|=(1<<c);
pic2.mask2|=(1<<c);
pic_updatepending();
// if (c==(14-8)) pclog("Taking IRQ 14 %02X\n",c+pic2.vector);
// printf("Taking high IRQ! %i\n",c);
// if (c==1) printf("Keyboard int!\n");
// if (c==0) pic.ins&=~1;
return c+pic2.vector;
}
}
return 0xFF;
}
void picclear(int num)
{
// printf("Pic clear %02X\n",num);
pic.pend&=~num;
pic.ins&=~num;
if (num==1) pit0=1;
pic_updatepending();
}
void dumppic()
{
pclog("PIC1 : MASK %02X PEND %02X INS %02X VECTOR %02X\n",pic.mask,pic.pend,pic.ins,pic.vector);
pclog("PIC2 : MASK %02X PEND %02X INS %02X VECTOR %02X\n",pic2.mask,pic2.pend,pic2.ins,pic2.vector);
}

3
src/pic.h Normal file
View file

@ -0,0 +1,3 @@
void pic_init();
void pic2_init();
void pic_reset();

305
src/pit.c Normal file
View file

@ -0,0 +1,305 @@
/*IBM AT -
Write B0
Write aa55
Expects aa55 back*/
#include <string.h>
#include "ibm.h"
#include "pit.h"
#include "video.h"
#include "cpu.h"
/*B0 to 40, two writes to 43, then two reads - value does not change!*/
/*B4 to 40, two writes to 43, then two reads - value _does_ change!*/
//Tyrian writes 4300 or 17512
int displine;
int pitsec=0;
double PITCONST;
float cpuclock;
float isa_timing, bus_timing;
int firsttime=1;
void setpitclock(float clock)
{
float temp;
// printf("PIT clock %f\n",clock);
cpuclock=clock;
PITCONST=clock/1193182.0;
SPKCONST=clock/48000.0;
CGACONST=(clock/(19687500.0/11.0));
MDACONST=(clock/1813000.0);
VGACONST1=(clock/25175000.0);
VGACONST2=(clock/28322000.0);
setsbclock(clock);
SOUNDCONST=clock/200.0;
CASCONST=PITCONST*1192;
isa_timing = clock/8000000.0;
bus_timing = clock/(double)cpu_busspeed;
video_updatetiming();
// pclog("egacycles %i egacycles2 %i temp %f clock %f\n",egacycles,egacycles2,temp,clock);
GUSCONST=(clock/3125.0)/4.0;
GUSCONST2=(clock/3125.0)/4.0; //Timer 2 at different rate to 1?
video_recalctimings();
RTCCONST=clock/32768.0;
}
//#define PITCONST (8000000.0/1193000.0)
//#define PITCONST (cpuclock/1193000.0)
int pit0;
void pit_reset()
{
memset(&pit,0,sizeof(PIT));
pit.l[0]=0xFFFF; pit.c[0]=0xFFFF*PITCONST;
pit.l[1]=0xFFFF; pit.c[1]=0xFFFF*PITCONST;
pit.l[2]=0xFFFF; pit.c[2]=0xFFFF*PITCONST;
pit.m[0]=pit.m[1]=pit.m[2]=0;
pit.ctrls[0]=pit.ctrls[1]=pit.ctrls[2]=0;
pit.thit[0]=1;
spkstat=0;
}
void clearpit()
{
pit.c[0]=(pit.l[0]<<2);
}
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];
}
extern int ins;
void pit_write(uint16_t addr, uint8_t val)
{
int t;
uint8_t oldctrl=pit.ctrl;
cycles -= (int)PITCONST;
pit0=1;
// printf("Write PIT %04X %02X %04X:%08X %i %i\n",addr,val,CS,pc,ins);
switch (addr&3)
{
case 3: /*CTRL*/
if ((val&0xC0)==0xC0)
{
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;
}
return;
}
pit.ctrls[val>>6]=pit.ctrl=val;
if ((val>>7)==3)
{
printf("Bad PIT reg select\n");
return;
// dumpregs();
// exit(-1);
}
// 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;
// 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;
}
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;
// pclog("ppispeakon %i\n",ppispeakon);
}
pit.wp=0;
pit.thit[pit.ctrl>>6]=0;
break;
case 0: case 1: case 2: /*Timers*/
t=addr&3;
// if (t==2) ppispeakon=speakon=0;
// pclog("Write timer %02X %i\n",pit.ctrls[t],pit.wm[t]);
switch (pit.wm[t])
{
case 1:
pit.l[t]=val;
pit.thit[t]=0;
pit.c[t]=pit.l[t]*PITCONST;
picintc(1);
break;
case 2:
pit.l[t]=(val<<8);
pit.thit[t]=0;
pit.c[t]=pit.l[t]*PITCONST;
picintc(1);
break;
case 0:
pit.l[t]&=0xFF;
pit.l[t]|=(val<<8);
pit.c[t]=pit.l[t]*PITCONST;
// pclog("%04X %f\n",pit.l[t],pit.c[t]);
pit.thit[t]=0;
pit.wm[t]=3;
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])
{
pit.l[t]|=0x10000;
pit.c[t]=pit.l[t]*PITCONST;
}
break;
}
}
uint8_t pit_read(uint16_t addr)
{
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))
{
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;
}
switch (pit.rm[addr&3])
{
case 0:
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;
break;
case 2:
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;
break;
}
break;
case 3: /*Control*/
temp=pit.ctrl;
}
// 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);
// 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;
pit0=0;
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");
readdma0();
}
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;
}
}
void pit_init()
{
io_sethandler(0x0040, 0x0004, pit_read, NULL, NULL, pit_write, NULL, NULL);
}

3
src/pit.h Normal file
View file

@ -0,0 +1,3 @@
extern double PITCONST;
void pit_init();
void pit_reset();

1
src/plat-dinput.h Normal file
View file

@ -0,0 +1 @@
extern LPDIRECTINPUT lpdi;

15
src/plat-keyboard.h Normal file
View file

@ -0,0 +1,15 @@
#ifdef __cplusplus
extern "C" {
#endif
void keyboard_init();
void keyboard_close();
void keyboard_poll_host();
int key[256];
#define KEY_LCONTROL 0x1d
#define KEY_RCONTROL (0x1d | 0x80)
#define KEY_END (0x4f | 0x80)
#ifdef __cplusplus
}
#endif

13
src/plat-mouse.h Normal file
View file

@ -0,0 +1,13 @@
#ifdef __cplusplus
extern "C" {
#endif
void mouse_init();
void mouse_remove();
extern int mouse_b;
void poll_mouse();
void position_mouse(int x, int y);
void get_mouse_mickeys(int *x, int *y);
#ifdef __cplusplus
}
#endif

19
src/ppi.c Normal file
View file

@ -0,0 +1,19 @@
/*IBM 5150 cassette nonsense
Calls F979 twice
Expects CX to be nonzero, BX >$410 and <$540
CX is loops between bit 4 of $62 changing
BX is timer difference between calls
*/
#include "ibm.h"
#include "pit.h"
#include "plat-keyboard.h"
#include "plat-mouse.h"
void ppi_reset()
{
ppi.pa=0x0;//0x1D;
ppi.pb=0x40;
}

1
src/ppi.h Normal file
View file

@ -0,0 +1 @@
extern int wasgated;

206
src/psg.c Normal file
View file

@ -0,0 +1,206 @@
#include "ibm.h"
float volslog[16]=
{
0.00000f,0.59715f,0.75180f,0.94650f,
1.19145f,1.50000f,1.88835f,2.37735f,
2.99295f,3.76785f,4.74345f,5.97165f,
7.51785f,9.46440f,11.9194f,15.0000f
};
float psgcount[4],psglatch[4];
int psgstat[4];
int snlatch[4],sncount[4];
int snfreqlo[4],snfreqhi[4];
int snvol[4];
int curfreq[4];
uint32_t snshift[2]={0x8000,0x8000};
#define SNCLOCK (2386360>>5)
uint8_t snnoise;
void initpsg()
{
int c;
for (c=0;c<4;c++)
{
psgcount[c]=psglatch[c]=100000;
psgstat[c]=0;
}
}
#define PSGCONST (32000.0/48000.0)
void getpsg(signed short *p, int size)
{
// printf("Getpsg %08X %i\n",p,size);
// return;
int c,d;
for (c=0;c<size;c++)
{
p[c]=0;
for (d=1;d<4;d++)
{
if (psgstat[d]) p[c]+=volslog[snvol[d]]*170;
else p[c]-=volslog[snvol[d]]*170;
psgcount[d]-=(512*PSGCONST);
while (psgcount[d]<=0.0 && psglatch[d]>1.0)
{
psgcount[d]+=psglatch[d];
psgstat[d]^=1;
}
if (psgcount[d]<=0.0) psgcount[d]=1.0;
}
d=(snnoise&4)?0:1;
if (snshift[d]&1) p[c]+=volslog[snvol[0]]*170;
psgcount[0]-=(512*PSGCONST);
while (psgcount[0]<=0.0 && psglatch[0]>1.0)
{
psgcount[0]+=psglatch[0];
snshift[1]>>=1;
if (!snshift[1]) snshift[1]=0x4000;
if ((snshift[0]&1)^((snshift[0]&4)?1:0)^((snshift[0]&0x8000)?1:0))
snshift[0]|=0x10000;
snshift[0]>>=1;
}
if (psgcount[0]<=0.0) psgcount[0]=1.0;
}
}
int lasttone;
uint8_t firstdat;
void writepsg(uint16_t addr, uint8_t data)
{
int c;
int freq;
pclog("Write PSG %02X\n", data);
if (data&0x80)
{
firstdat=data;
switch (data&0x70)
{
case 0:
snfreqlo[3]=data&0xF;
lasttone=3;
break;
case 0x10:
data&=0xF;
snvol[3]=0xF-data;
break;
case 0x20:
snfreqlo[2]=data&0xF;
lasttone=2;
break;
case 0x30:
data&=0xF;
snvol[2]=0xF-data;
break;
case 0x40:
snfreqlo[1]=data&0xF;
lasttone=1;
break;
case 0x50:
data&=0xF;
snvol[1]=0xF-data;
break;
case 0x60:
if ((data&3)!=(snnoise&3)) sncount[0]=0;
snnoise=data&0xF;
if ((data&3)==3)
{
curfreq[0]=curfreq[1]>>4;
snlatch[0]=snlatch[1];
}
else
{
switch (data&3)
{
case 0:
snlatch[0]=128<<7;
curfreq[0]=SNCLOCK/256;
snlatch[0]=0x400;
sncount[0]=0;
break;
case 1:
snlatch[0]=256<<7;
curfreq[0]=SNCLOCK/512;
snlatch[0]=0x800;
sncount[0]=0;
break;
case 2:
snlatch[0]=512<<7;
curfreq[0]=SNCLOCK/1024;
snlatch[0]=0x1000;
sncount[0]=0;
break;
case 3:
snlatch[0]=snlatch[1];
sncount[0]=0;
}
if (snnoise&4) snlatch[0]<<=1;
}
break;
case 0x70:
data&=0xF;
snvol[0]=0xF-data;
break;
}
}
else
{
if ((firstdat&0x70)==0x60)
{
if ((data&3)!=(snnoise&3)) sncount[0]=0;
snnoise=data&0xF;
if ((data&3)==3)
{
curfreq[0]=curfreq[1]>>4;
snlatch[0]=snlatch[1];
// printf("SN 0 latch %04X\n",snlatch[0]);
}
else
{
switch (data&3)
{
case 0:
snlatch[0]=128<<7;
curfreq[0]=SNCLOCK/256;
snlatch[0]=0x400;
sncount[0]=0;
break;
case 1:
snlatch[0]=256<<7;
curfreq[0]=SNCLOCK/512;
snlatch[0]=0x800;
sncount[0]=0;
break;
case 2:
snlatch[0]=512<<7;
curfreq[0]=SNCLOCK/1024;
snlatch[0]=0x1000;
sncount[0]=0;
break;
case 3:
snlatch[0]=snlatch[1];
// printf("SN 0 latch %04X\n",snlatch[0]);
sncount[0]=0;
}
if (snnoise&4) snlatch[0]<<=1;
}
return;
}
else
{
snfreqhi[lasttone]=data&0x3F;
freq=snfreqlo[lasttone]|(snfreqhi[lasttone]<<4);
snlatch[lasttone]=freq<<6;
}
}
for (c=0;c<4;c++) psglatch[c]=(float)snlatch[c];
}
void psg_init()
{
pclog("psg_init\n");
io_sethandler(0x00C0, 0x0001, NULL, NULL, NULL, writepsg, NULL, NULL);
}

1
src/psg.h Normal file
View file

@ -0,0 +1 @@
void psg_init();

62
src/resources.h Normal file
View file

@ -0,0 +1,62 @@
#define IDM_FILE_RESET 40000
#define IDM_FILE_HRESET 40001
#define IDM_FILE_EXIT 40002
#define IDM_DISC_A 40010
#define IDM_DISC_B 40011
#define IDM_EJECT_A 40012
#define IDM_EJECT_B 40013
#define IDM_HDCONF 40014
#define IDM_CONFIG 40020
#define IDM_STATUS 40030
#define IDM_KEY_ALLEGRO 40040
#define IDM_KEY_WINDOWS 40041
#define IDM_VID_RESIZE 40050
#define IDM_CDROM_EMPTY 40100
#define IDM_CDROM_REAL 40100
#define IDM_CDROM_DISABLED 40200
#define IDC_COMBO1 1000
#define IDC_COMBO2 1001
#define IDC_COMBO3 1002
#define IDC_COMBO4 1003
#define IDC_COMBO5 1004
#define IDC_COMBO386 1005
#define IDC_COMBO486 1006
#define IDC_COMBOSND 1007
#define IDC_COMBOCHC 1008
#define IDC_COMBOMEM 1009
#define IDC_COMBOCPUM 1060
#define IDC_COMBOSPD 1061
#define IDC_CHECK1 1010
#define IDC_CHECK2 1011
#define IDC_CHECK3 1012
#define IDC_CHECK4 1013
#define IDC_STATIC 1020
#define IDC_EDIT1 1030
#define IDC_EDIT2 1031
#define IDC_EDIT3 1032
#define IDC_EDIT4 1033
#define IDC_EDIT5 1034
#define IDC_EDIT6 1035
#define IDC_TEXT1 1040
#define IDC_TEXT2 1041
#define IDC_EDITC 1050
#define IDC_CFILE 1051
#define IDC_CNEW 1052
#define IDC_EDITD 1053
#define IDC_DFILE 1054
#define IDC_DNEW 1055
#define IDC_STEXT1 1100
#define IDC_STEXT2 1101
#define IDC_STEXT3 1102
#define IDC_STEXT4 1103
#define IDC_STEXT5 1104
#define IDC_STEXT6 1105
#define IDC_STEXT7 1106
#define IDC_STEXT8 1107
#define IDC_STEXT9 1108
#define IDC_STEXT10 1109
#define IDC_STEXT11 1110
#define IDC_STEXT12 1111
#define IDC_STEXT13 1112

1104
src/sblaster.c Normal file

File diff suppressed because it is too large Load diff

210
src/serial.c Normal file
View file

@ -0,0 +1,210 @@
#include "ibm.h"
#include "io.h"
#include "mouse.h"
#include "serial.h"
SERIAL serial,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;
}
void serial_write_fifo(uint8_t dat)
{
serial_fifo[serial_fifo_write] = dat;
serial_fifo_write = (serial_fifo_write + 1) & 0xFF;
if (!(serial.linestat & 1))
{
serial.linestat|=1;
if (serial.mctrl&8) picint(0x10);
serial.iir=4;
}
}
uint8_t serial_read_fifo()
{
uint8_t temp = serial_fifo[serial_fifo_read];
if (serial_fifo_read != serial_fifo_write)
serial_fifo_read = (serial_fifo_read + 1) & 0xFF;
return temp;
}
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)
{
// printf("Write serial %03X %02X %04X:%04X\n",addr,val,CS,pc);
switch (addr&7)
{
case 0:
if (serial.lcr&0x80 && !AMSTRADIO)
{
serial.dlab1=val;
return;
}
serial.thr=val;
serial.linestat|=0x20;
if (serial.mctrl&0x10)
{
serial_write_fifo(val);
// serial.rcr=val;
// serial.linestat|=1;
}
break;
case 1:
if (serial.lcr&0x80 && !AMSTRADIO)
{
serial.dlab2=val;
return;
}
serial.ier=val;
break;
case 3: serial.lcr=val; break;
case 4:
if ((val&2) && !(serial.mctrl&2))
{
if (serial_rcr)
serial_rcr();
// printf("RCR raised! sending M\n");
}
serial.mctrl=val;
break;
}
}
uint8_t serial_read(uint16_t addr)
{
uint8_t temp;
// printf("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 = 1000;
// pclog("Next FIFO\n");
}
break;
case 1:
if (serial.lcr&0x80 && !AMSTRADIO) temp = serial.dlab2;
else temp = 0;
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;
}
// printf("%02X\n",temp);
return temp;
}
void serial2_write(uint16_t addr, uint8_t val)
{
// printf("Write serial2 %03X %02X %04X:%04X\n",addr,val,cs>>4,pc);
switch (addr&7)
{
case 0:
if (serial2.lcr&0x80 && !AMSTRADIO)
{
serial2.dlab1=val;
return;
}
serial2.thr=val;
serial2.linestat|=0x20;
if (serial2.mctrl&0x10)
{
serial2.rcr=val;
serial2.linestat|=1;
}
break;
case 1:
if (serial2.lcr&0x80 && !AMSTRADIO)
{
serial2.dlab2=val;
return;
}
serial2.ier=val;
break;
case 3: serial2.lcr=val; break;
case 4:
serial2.mctrl=val;
break;
}
}
uint8_t serial2_read(uint16_t addr)
{
uint8_t temp;
// printf("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;
break;
case 1:
if (serial2.lcr&0x80 && !AMSTRADIO) return serial2.dlab2;
temp=0;
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;
}
// printf("%02X\n",temp);
return temp;
}
/*Tandy might need COM1 at 2f8*/
void serial1_init(uint16_t addr)
{
io_sethandler(addr, 0x0008, serial_read, NULL, NULL, serial_write, NULL, NULL);
serial_rcr = NULL;
}
void serial1_remove()
{
io_removehandler(0x2e8, 0x0008, serial_read, NULL, NULL, serial_write, NULL, NULL);
io_removehandler(0x2f8, 0x0008, serial_read, NULL, NULL, serial_write, NULL, NULL);
io_removehandler(0x3e8, 0x0008, serial_read, NULL, NULL, serial_write, NULL, NULL);
io_removehandler(0x3f8, 0x0008, serial_read, NULL, NULL, serial_write, NULL, NULL);
}
void serial2_init(uint16_t addr)
{
io_sethandler(addr, 0x0008, serial2_read, NULL, NULL, serial2_write, NULL, NULL);
}
void serial2_remove()
{
io_removehandler(0x2e8, 0x0008, serial2_read, NULL, NULL, serial2_write, NULL, NULL);
io_removehandler(0x2f8, 0x0008, serial2_read, NULL, NULL, serial2_write, NULL, NULL);
io_removehandler(0x3e8, 0x0008, serial2_read, NULL, NULL, serial2_write, NULL, NULL);
io_removehandler(0x3f8, 0x0008, serial2_read, NULL, NULL, serial2_write, NULL, NULL);
}

17
src/serial.h Normal file
View file

@ -0,0 +1,17 @@
void serial1_init(uint16_t addr);
void serial2_init(uint16_t addr);
void serial1_remove();
void serial2_remove();
void serial_reset();
typedef struct
{
uint8_t linestat,thr,mctrl,rcr,iir,ier,lcr;
uint8_t dlab1,dlab2;
} SERIAL;
extern SERIAL serial,serial2;
extern int serial_fifo_read, serial_fifo_write;
extern void (*serial_rcr)();

180
src/sound.c Normal file
View file

@ -0,0 +1,180 @@
#include <stdio.h>
#include "ibm.h"
#include "filters.h"
int soundon = 1;
int16_t *adbuffer,*adbuffer2;
int16_t *psgbuffer;
uint16_t *cmsbuffer;
int16_t *spkbuffer;
int16_t *outbuffer;
uint16_t *gusbuffer;
void initsound()
{
initalmain(0,NULL);
inital();
// install_sound(DIGI_AUTODETECT,MIDI_NONE,0);
// as=play_audio_stream(SOUNDBUFLEN,16,1,48000,255,128);
adbuffer=malloc((SOUNDBUFLEN)*2);
adbuffer2=malloc((SOUNDBUFLEN)*2);
psgbuffer=malloc((SOUNDBUFLEN)*2);
cmsbuffer=malloc((SOUNDBUFLEN)*2*2);
gusbuffer=malloc((SOUNDBUFLEN)*2*2);
spkbuffer=malloc(((SOUNDBUFLEN)*2)+32);
outbuffer=malloc((SOUNDBUFLEN)*2*2);
}
int adpoll=0;
void pollad()
{
/* if (adpoll>=20) return;
getadlibl(adbuffer+(adpoll*(48000/200)),48000/200);
getadlibr(adbuffer2+(adpoll*(48000/200)),48000/200);
adpoll++;*/
// printf("ADPOLL %i\n",adpoll);
}
void polladlib()
{
getadlib(adbuffer+(adpoll),adbuffer2+(adpoll),1);
adpoll++;
}
int psgpoll=0;
void pollpsg()
{
if (psgpoll>=20) return;
getpsg(psgbuffer+(psgpoll*(48000/200)),48000/200);
psgpoll++;
}
int cmspoll=0;
void pollcms()
{
if (cmspoll>=20) return;
getcms(cmsbuffer+(cmspoll*(48000/200)*2),48000/200);
cmspoll++;
}
int guspoll=0;
void pollgussnd()
{
if (guspoll>=20) return;
getgus(gusbuffer+(guspoll*(48000/200)*2),48000/200);
guspoll++;
}
int spkpos=0;
int wasgated = 0;
void pollspk()
{
if (spkpos>=SOUNDBUFLEN) return;
// printf("SPeaker - %i %i %i %02X\n",speakval,gated,speakon,pit.m[2]);
if (gated)
{
if (!pit.m[2] || pit.m[2]==4)
spkbuffer[spkpos]=speakval;
else
spkbuffer[spkpos]=(speakon)?0x1400:0;
}
else
spkbuffer[spkpos]=(wasgated)?0x1400:0;
spkpos++;
wasgated=0;
}
FILE *soundf;
static int16_t cd_buffer[(SOUNDBUFLEN) * 2];
void pollsound()
{
int c;
int16_t t[4];
uint32_t pos;
// printf("Pollsound! %i\n",soundon);
// if (soundon)
// {
for (c=0;c<(SOUNDBUFLEN);c++) outbuffer[c<<1]=outbuffer[(c<<1)+1]=0;
for (c=0;c<(SOUNDBUFLEN);c++)
{
outbuffer[c<<1]+=((adbuffer[c]*mixer.fm_l)>>16);
outbuffer[(c<<1)+1]+=((adbuffer[c]*mixer.fm_r)>>16);
// if (!c) pclog("F %04X %04X %04X\n",adbuffer[c],outbuffer[c<<1],mixer.fm_l);
}
addsb(outbuffer);
for (c=0;c<(SOUNDBUFLEN);c++)
{
// if (!c) pclog("M %04X ",outbuffer[c<<1]);
outbuffer[c<<1]=(outbuffer[c<<1]*mixer.master_l)>>16;
outbuffer[(c<<1)+1]=(outbuffer[(c<<1)+1]*mixer.master_r)>>16;
// if (!c) pclog("%04X %04X\n",outbuffer[c<<1],mixer.master_l);
}
if (mixer.bass_l!=8 || mixer.bass_r!=8 || mixer.treble_l!=8 || mixer.treble_r!=8)
{
for (c=0;c<(SOUNDBUFLEN);c++)
{
if (mixer.bass_l>8) outbuffer[c<<1] =(outbuffer[c<<1] +(((int16_t)low_iir(0,(float)outbuffer[c<<1]) *(mixer.bass_l-8))>>1))*((15-mixer.bass_l)+16)>>5;
if (mixer.bass_r>8) outbuffer[(c<<1)+1]=(outbuffer[(c<<1)+1]+(((int16_t)low_iir(1,(float)outbuffer[(c<<1)+1]) *(mixer.bass_r-8))>>1))*((15-mixer.bass_r)+16)>>5;
if (mixer.treble_l>8) outbuffer[c<<1] =(outbuffer[c<<1] +(((int16_t)high_iir(0,(float)outbuffer[c<<1]) *(mixer.treble_l-8))>>1))*((15-mixer.treble_l)+16)>>5;
if (mixer.treble_r>8) outbuffer[(c<<1)+1]=(outbuffer[(c<<1)+1]+(((int16_t)high_iir(1,(float)outbuffer[(c<<1)+1]) *(mixer.treble_r-8))>>1))*((15-mixer.treble_r)+16)>>5;
if (mixer.bass_l<8) outbuffer[c<<1] =(outbuffer[c<<1] +(((int16_t)low_cut_iir(0,(float)outbuffer[c<<1]) *(8-mixer.bass_l))>>1))*(mixer.bass_l+16)>>5;
if (mixer.bass_r<8) outbuffer[(c<<1)+1]=(outbuffer[(c<<1)+1]+(((int16_t)low_cut_iir(1,(float)outbuffer[(c<<1)+1]) *(8-mixer.bass_r))>>1))*(mixer.bass_r+16)>>5;
if (mixer.treble_l<8) outbuffer[c<<1] =(outbuffer[c<<1] +(((int16_t)high_cut_iir(0,(float)outbuffer[c<<1]) *(8-mixer.treble_l))>>1))*(mixer.treble_l+16)>>5;
if (mixer.treble_r<8) outbuffer[(c<<1)+1]=(outbuffer[(c<<1)+1]+(((int16_t)high_cut_iir(1,(float)outbuffer[(c<<1)+1])*(8-mixer.treble_r))>>1))*(mixer.treble_r+16)>>5;
}
}
for (c=0;c<(SOUNDBUFLEN);c++)
{
outbuffer[c<<1]+=(spkbuffer[c]/2);
outbuffer[(c<<1)+1]+=(spkbuffer[c]/2);
}
for (c=0;c<(SOUNDBUFLEN);c++)
{
outbuffer[c<<1]+=(psgbuffer[c]/2);
outbuffer[(c<<1)+1]+=(psgbuffer[c]/2);
}
for (c=0;c<((SOUNDBUFLEN)*2);c++)
outbuffer[c]+=(cmsbuffer[c]/2);
for (c=0;c<((SOUNDBUFLEN)*2);c++)
outbuffer[c]+=(gusbuffer[c]);
adddac(outbuffer);
ioctl_audio_callback(cd_buffer, ((SOUNDBUFLEN) * 2 * 441) / 480);
pos = 0;
for (c = 0; c < (SOUNDBUFLEN) * 2; c+=2)
{
outbuffer[c] += cd_buffer[((pos >> 16) << 1)] / 2;
outbuffer[c + 1] += cd_buffer[((pos >> 16) << 1) + 1] / 2;
// outbuffer[c] += (int16_t)((int32_t)cd_buffer[pos >> 16] * (65536 - (pos & 0xffff))) / 65536;
// outbuffer[c] += (int16_t)((int32_t)cd_buffer[(pos >> 16) + 1] * (pos & 0xffff)) / 65536;
pos += 60211; //(44100 * 65536) / 48000;
}
// if (!soundf) soundf=fopen("sound.pcm","wb");
// fwrite(outbuffer,(SOUNDBUFLEN)*2*2,1,soundf);
if (soundon) givealbuffer(outbuffer);
// }
// addsb(outbuffer);
// adddac(outbuffer);
adpoll=0;
psgpoll=0;
cmspoll=0;
spkpos=0;
guspoll=0;
}
int sndcount;
void pollsound60hz()
{
// printf("Poll sound %i\n",sndcount);
// pollad();
pollpsg();
pollcms();
pollgussnd();
sndcount++;
if (sndcount==20)
{
sndcount=0;
pollsound();
}
}

1
src/sound.h Normal file
View file

@ -0,0 +1 @@
extern int wasgated;

143
src/soundopenal.c Normal file
View file

@ -0,0 +1,143 @@
#define USE_OPENAL
#include <stdio.h>
#include <string.h>
#ifdef USE_OPENAL
#include <AL/al.h>
#include <AL/alut.h>
#endif
#include "ibm.h"
FILE *allog;
#ifdef USE_OPENAL
ALuint buffers[4]; // front and back buffers
ALuint source; // audio source
ALenum format; // internal format
#endif
#define FREQ 48000
#define BUFLEN SOUNDBUFLEN
void closeal();
void initalmain(int argc, char *argv[])
{
#ifdef USE_OPENAL
alutInit(0,0);
// printf("AlutInit\n");
atexit(closeal);
// printf("AlutInit\n");
#endif
}
void closeal()
{
#ifdef USE_OPENAL
alutExit();
#endif
}
void check()
{
#ifdef USE_OPENAL
ALenum error;
if ((error = alGetError()) != AL_NO_ERROR)
{
// printf("Error : %08X\n", error);
// exit(-1);
}
#endif
}
void inital()
{
#ifdef USE_OPENAL
int c;
int16_t buf[BUFLEN*2];
format = AL_FORMAT_STEREO16;
// printf("1\n");
check();
// printf("2\n");
alGenBuffers(4, buffers);
check();
// printf("3\n");
alGenSources(1, &source);
check();
// printf("4\n");
alSource3f(source, AL_POSITION, 0.0, 0.0, 0.0);
alSource3f(source, AL_VELOCITY, 0.0, 0.0, 0.0);
alSource3f(source, AL_DIRECTION, 0.0, 0.0, 0.0);
alSourcef (source, AL_ROLLOFF_FACTOR, 0.0 );
alSourcei (source, AL_SOURCE_RELATIVE, AL_TRUE );
check();
memset(buf,0,BUFLEN*4);
// printf("5\n");
for (c=0;c<4;c++)
alBufferData(buffers[c], AL_FORMAT_STEREO16, buf, BUFLEN*2*2, FREQ);
alSourceQueueBuffers(source, 4, buffers);
check();
// printf("6 %08X\n",source);
alSourcePlay(source);
check();
// printf("InitAL!!! %08X\n",source);
#endif
}
void givealbuffer(int16_t *buf)
{
#ifdef USE_OPENAL
int processed;
int state;
int c;
//return;
// printf("Start\n");
check();
// printf("GiveALBuffer %08X\n",source);
alGetSourcei(source, AL_SOURCE_STATE, &state);
check();
if (state==0x1014)
{
alSourcePlay(source);
// printf("Resetting sound\n");
}
// printf("State - %i %08X\n",state,state);
alGetSourcei(source, AL_BUFFERS_PROCESSED, &processed);
// printf("P ");
check();
// printf("Processed - %i\n",processed);
if (processed>=1)
{
ALuint buffer;
alSourceUnqueueBuffers(source, 1, &buffer);
// printf("U ");
check();
// for (c=0;c<BUFLEN*2;c++) buf[c]^=0x8000;
alBufferData(buffer, AL_FORMAT_STEREO16, buf, BUFLEN*2*2, FREQ);
// printf("B ");
check();
alSourceQueueBuffers(source, 1, &buffer);
// printf("Q ");
check();
// printf("\n");
// if (!allog) allog=fopen("al.pcm","wb");
// fwrite(buf,BUFLEN*2,1,allog);
}
// printf("\n");
#endif
}

70
src/um8881f.c Normal file
View file

@ -0,0 +1,70 @@
#include "ibm.h"
#include "io.h"
#include "mem.h"
#include "um8881f.h"
static uint8_t card_16[256];
static uint8_t card_18[256];
void um8881f_write(int func, int addr, uint8_t val)
{
if (addr == 0x54)
{
if ((card_16[0x54] ^ val) & 0x01)
{
if (val & 1)
mem_sethandler(0xe0000, 0x10000, mem_read_ram, mem_read_ramw, mem_read_raml, mem_write_ram, mem_write_ramw, mem_write_raml);
else
mem_sethandler(0xf0000, 0x10000, mem_read_bios, mem_read_biosw, mem_read_biosl, NULL, NULL, NULL );
}
flushmmucache_nopc();
}
if (addr == 0x55)
{
if ((card_16[0x55] ^ val) & 0xc0)
{
switch (val & 0xc0)
{
case 0x00: mem_sethandler(0xf0000, 0x10000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_ram, mem_write_ramw, mem_write_raml); break;
case 0x40: mem_sethandler(0xf0000, 0x10000, mem_read_bios, mem_read_biosw, mem_read_biosl, NULL, NULL, NULL ); break;
case 0x80: mem_sethandler(0xf0000, 0x10000, mem_read_ram, mem_read_ramw, mem_read_raml, mem_write_ram, mem_write_ramw, mem_write_raml); break;
case 0xc0: mem_sethandler(0xf0000, 0x10000, mem_read_ram, mem_read_ramw, mem_read_raml, NULL, NULL, NULL ); break;
}
shadowbios = val & 0x80;
shadowbios_write = !(val & 0x40);
flushmmucache_nopc();
}
}
if (addr >= 4)
card_16[addr] = val;
}
uint8_t um8881f_read(int func, int addr)
{
return card_16[addr];
}
void um8886f_write(int func, int addr, uint8_t val)
{
if (addr >= 4)
card_18[addr] = val;
}
uint8_t um8886f_read(int func, int addr)
{
return card_18[addr];
}
void um8881f_init()
{
pci_add_specific(16, um8881f_read, um8881f_write);
pci_add_specific(18, um8886f_read, um8886f_write);
card_16[0] = card_18[0] = 0x60; /*UMC*/
card_16[1] = card_18[1] = 0x10;
card_16[2] = 0x81; card_16[3] = 0x88; /*UM8881 Host - PCI bridge*/
card_18[2] = 0x86; card_18[3] = 0x88; /*UM8886 PCI - ISA bridge*/
}

1
src/um8881f.h Normal file
View file

@ -0,0 +1 @@
void um8881f_init();

494
src/vid_cga.c Normal file
View file

@ -0,0 +1,494 @@
/*CGA emulation*/
#include "ibm.h"
#include "video.h"
void cga_out(uint16_t addr, uint8_t val)
{
uint8_t old;
// pclog("CGA_OUT %04X %02X\n", addr, val);
switch (addr)
{
case 0x3D4:
crtcreg=val&31;
return;
case 0x3D5:
old=crtc[crtcreg];
crtc[crtcreg]=val&crtcmask[crtcreg];
if (old!=val)
{
if (crtcreg<0xE || crtcreg>0x10)
{
fullchange=changeframecount;
cga_recalctimings();
}
}
return;
case 0x3D8:
cgamode=val;
return;
case 0x3D9:
cgacol=val;
return;
}
}
uint8_t cga_in(uint16_t addr)
{
// pclog("CGA_IN %04X\n", addr);
switch (addr)
{
case 0x3D4:
return crtcreg;
case 0x3D5:
return crtc[crtcreg];
case 0x3DA:
return cgastat;
}
return 0xFF;
}
extern uint8_t charbuffer[256];
void cga_write(uint32_t addr, uint8_t val)
{
// pclog("CGA_WRITE %04X %02X\n", addr, val);
vram[addr&0x3FFF]=val;
charbuffer[ ((int)(((dispontime - vidtime) * 2) / CGACONST)) & 0xfc] = val;
charbuffer[(((int)(((dispontime - vidtime) * 2) / CGACONST)) & 0xfc) | 1] = val;
cycles -= 4;
}
uint8_t cga_read(uint32_t addr)
{
cycles -= 4;
charbuffer[ ((int)(((dispontime - vidtime) * 2) / CGACONST)) & 0xfc] = vram[addr&0x3FFF];
charbuffer[(((int)(((dispontime - vidtime) * 2) / CGACONST)) & 0xfc) | 1] = vram[addr&0x3FFF];
// pclog("CGA_READ %04X\n", addr);
return vram[addr&0x3FFF];
}
void cga_recalctimings()
{
pclog("Recalc - %i %i %i\n", crtc[0], crtc[1], cgamode & 1);
if (cgamode&1)
{
disptime=crtc[0]+1;
dispontime=crtc[1];
}
else
{
disptime=(crtc[0]+1)<<1;
dispontime=crtc[1]<<1;
}
dispofftime=disptime-dispontime;
// printf("%i %f %f %f %i %i\n",cgamode&1,disptime,dispontime,dispofftime,crtc[0],crtc[1]);
dispontime*=CGACONST;
dispofftime*=CGACONST;
// printf("Timings - on %f off %f frame %f second %f\n",dispontime,dispofftime,(dispontime+dispofftime)*262.0,(dispontime+dispofftime)*262.0*59.92);
}
static int linepos,displine;
static int sc,vc;
static int cgadispon;
static int con,coff,cursoron,cgablink;
static int vsynctime,vadj;
static uint16_t ma,maback,ca;
static int oddeven = 0;
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*/
};
int i_filt[8],q_filt[8];
void cga_poll()
{
uint16_t ca=(crtc[15]|(crtc[14]<<8))&0x3FFF;
int drawcursor;
int x,c;
int oldvc;
uint8_t chr,attr;
uint16_t dat,dat2,dat3,dat4;
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 (!linepos)
{
vidtime+=dispofftime;
cgastat|=1;
linepos=1;
oldsc=sc;
if ((crtc[8] & 3) == 3)
sc = ((sc << 1) + oddeven) & 7;
if (cgadispon)
{
if (displine<firstline)
{
firstline=displine;
// printf("Firstline %i\n",firstline);
}
lastline=displine;
for (c=0;c<8;c++)
{
if ((cgamode&0x12)==0x12)
{
buffer->line[displine][c]=0;
if (cgamode&1) buffer->line[displine][c+(crtc[1]<<3)+8]=0;
else buffer->line[displine][c+(crtc[1]<<4)+8]=0;
}
else
{
buffer->line[displine][c]=(cgacol&15)+16;
if (cgamode&1) buffer->line[displine][c+(crtc[1]<<3)+8]=(cgacol&15)+16;
else buffer->line[displine][c+(crtc[1]<<4)+8]=(cgacol&15)+16;
}
}
if (cgamode&1)
{
for (x=0;x<crtc[1];x++)
{
chr=charbuffer[x<<1];
attr=charbuffer[(x<<1)+1];
drawcursor=((ma==ca) && con && cursoron);
if (cgamode&0x20)
{
cols[1]=(attr&15)+16;
cols[0]=((attr>>4)&7)+16;
if ((cgablink&8) && (attr&0x80) && !drawcursor) cols[1]=cols[0];
}
else
{
cols[1]=(attr&15)+16;
cols[0]=(attr>>4)+16;
}
if (drawcursor)
{
for (c=0;c<8;c++)
buffer->line[displine][(x<<3)+c+8]=cols[(fontdat[chr][sc&7]&(1<<(c^7)))?1:0]^15;
}
else
{
for (c=0;c<8;c++)
buffer->line[displine][(x<<3)+c+8]=cols[(fontdat[chr][sc&7]&(1<<(c^7)))?1:0];
}
ma++;
}
}
else if (!(cgamode&2))
{
for (x=0;x<crtc[1];x++)
{
chr=vram[((ma<<1)&0x3FFF)];
attr=vram[(((ma<<1)+1)&0x3FFF)];
drawcursor=((ma==ca) && con && cursoron);
if (cgamode&0x20)
{
cols[1]=(attr&15)+16;
cols[0]=((attr>>4)&7)+16;
if ((cgablink&8) && (attr&0x80)) cols[1]=cols[0];
}
else
{
cols[1]=(attr&15)+16;
cols[0]=(attr>>4)+16;
}
ma++;
if (drawcursor)
{
for (c=0;c<8;c++)
buffer->line[displine][(x<<4)+(c<<1)+8]=buffer->line[displine][(x<<4)+(c<<1)+1+8]=cols[(fontdat[chr][sc&7]&(1<<(c^7)))?1:0]^15;
}
else
{
for (c=0;c<8;c++)
buffer->line[displine][(x<<4)+(c<<1)+8]=buffer->line[displine][(x<<4)+(c<<1)+1+8]=cols[(fontdat[chr][sc&7]&(1<<(c^7)))?1:0];
}
}
}
else if (!(cgamode&16))
{
cols[0]=(cgacol&15)|16;
col=(cgacol&16)?24:16;
if (cgamode&4)
{
cols[1]=col|3;
cols[2]=col|4;
cols[3]=col|7;
}
else if (cgacol&32)
{
cols[1]=col|3;
cols[2]=col|5;
cols[3]=col|7;
}
else
{
cols[1]=col|2;
cols[2]=col|4;
cols[3]=col|6;
}
for (x=0;x<crtc[1];x++)
{
dat=(vram[((ma<<1)&0x1FFF)+((sc&1)*0x2000)]<<8)|vram[((ma<<1)&0x1FFF)+((sc&1)*0x2000)+1];
ma++;
for (c=0;c<8;c++)
{
buffer->line[displine][(x<<4)+(c<<1)+8]=
buffer->line[displine][(x<<4)+(c<<1)+1+8]=cols[dat>>14];
dat<<=2;
}
}
}
else
{
cols[0]=0; cols[1]=(cgacol&15)+16;
for (x=0;x<crtc[1];x++)
{
dat=(vram[((ma<<1)&0x1FFF)+((sc&1)*0x2000)]<<8)|vram[((ma<<1)&0x1FFF)+((sc&1)*0x2000)+1];
ma++;
for (c=0;c<16;c++)
{
buffer->line[displine][(x<<4)+c+8]=cols[dat>>15];
dat<<=1;
}
}
}
}
else
{
cols[0]=((cgamode&0x12)==0x12)?0:(cgacol&15)+16;
if (cgamode&1) hline(buffer,0,displine,(crtc[1]<<3)+16,cols[0]);
else hline(buffer,0,displine,(crtc[1]<<4)+16,cols[0]);
}
if (cgamode&1) x=(crtc[1]<<3)+16;
else x=(crtc[1]<<4)+16;
if (cga_comp)
{
for (c=0;c<x;c++)
{
y_buf[(c<<1)&6]=ntsc_col[buffer->line[displine][c]&7][(c<<1)&6]?0x6000:0;
y_buf[(c<<1)&6]+=(buffer->line[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[displine][c]&7][((c<<1)&6)+1]?0x6000:0;
y_buf[((c<<1)&6)+1]+=(buffer->line[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[displine])[c]=makecol32(r/2,g/2,b/2);
}
}
sc=oldsc;
if (vc==crtc[7] && !sc)
cgastat|=8;
displine++;
if (displine>=360) displine=0;
}
else
{
vidtime+=dispontime;
if (cgadispon) cgastat&=~1;
linepos=0;
if (vsynctime)
{
vsynctime--;
if (!vsynctime)
cgastat&=~8;
}
if (sc==(crtc[11]&31) || ((crtc[8]&3)==3 && sc==((crtc[11]&31)>>1))) { con=0; coff=1; }
if ((crtc[8] & 3) == 3 && sc == (crtc[9] >> 1))
maback = ma;
if (vadj)
{
sc++;
sc&=31;
ma=maback;
vadj--;
if (!vadj)
{
cgadispon=1;
ma=maback=(crtc[13]|(crtc[12]<<8))&0x3FFF;
sc=0;
}
}
else if (sc==crtc[9])
{
maback=ma;
sc=0;
oldvc=vc;
vc++;
vc&=127;
if (vc==crtc[6]) cgadispon=0;
if (oldvc==crtc[4])
{
vc=0;
vadj=crtc[5];
if (!vadj) cgadispon=1;
if (!vadj) ma=maback=(crtc[13]|(crtc[12]<<8))&0x3FFF;
if ((crtc[10]&0x60)==0x20) cursoron=0;
else cursoron=cgablink&8;
}
if (vc==crtc[7])
{
cgadispon=0;
displine=0;
vsynctime=(crtc[3]>>4)+1;
if (crtc[7])
{
if (cgamode&1) x=(crtc[1]<<3)+16;
else x=(crtc[1]<<4)+16;
lastline++;
if (x!=xsize || (lastline-firstline)!=ysize)
{
xsize=x;
ysize=lastline-firstline;
if (xsize<64) xsize=656;
if (ysize<32) ysize=200;
updatewindowsize(xsize,(ysize<<1)+16);
}
startblit();
if (cga_comp)
video_blit_memtoscreen(0, firstline-4, 0, (lastline-firstline)+8, xsize, (lastline-firstline)+8);
else
video_blit_memtoscreen_8(0, firstline-4, xsize, (lastline-firstline)+8);
if (readflash) rectfill(screen,winsizex-40,8,winsizex-8,14,0xFFFFFFFF);
readflash=0;
frames++;
endblit();
video_res_x = xsize - 16;
video_res_y = ysize;
if (cgamode & 1)
{
video_res_x /= 8;
video_res_y /= crtc[9] + 1;
video_bpp = 0;
}
else if (!(cgamode & 2))
{
video_res_x /= 16;
video_res_y /= crtc[9] + 1;
video_bpp = 0;
}
else if (!(cgamode&16))
{
video_res_x /= 2;
video_bpp = 2;
}
else
{
video_bpp = 1;
}
}
firstline=1000;
lastline=0;
cgablink++;
oddeven ^= 1;
}
}
else
{
sc++;
sc&=31;
ma=maback;
}
if ((sc==(crtc[10]&31) || ((crtc[8]&3)==3 && sc==((crtc[10]&31)>>1)))) con=1;
if (cgadispon && (cgamode&1))
{
for (x=0;x<(crtc[1]<<1);x++)
charbuffer[x]=vram[(((ma<<1)+x)&0x3FFF)];
}
}
}
int cga_init()
{
int c;
int cga_tint = -2;
for (c=0;c<8;c++)
{
i_filt[c]=512.0*cos((3.14*(cga_tint+c*4)/16.0) - 33.0/180.0);
q_filt[c]=512.0*sin((3.14*(cga_tint+c*4)/16.0) - 33.0/180.0);
}
mem_sethandler(0xb8000, 0x08000, cga_read, NULL, NULL, cga_write, NULL, NULL);
return 0;
}
GFXCARD vid_cga =
{
cga_init,
/*IO at 3Cx/3Dx*/
cga_out,
cga_in,
/*IO at 3Ax/3Bx*/
video_out_null,
video_in_null,
cga_poll,
cga_recalctimings,
video_write_null,
video_write_null,
cga_write,
video_read_null,
video_read_null,
cga_read
};

7
src/vid_cga.h Normal file
View file

@ -0,0 +1,7 @@
int cga_init();
void cga_out(uint16_t addr, uint8_t val);
uint8_t cga_in(uint16_t addr);
void cga_poll();
void cga_write(uint32_t addr, uint8_t val);
uint8_t cga_read(uint32_t addr);
void cga_recalctimings();

720
src/vid_ega.c Normal file
View file

@ -0,0 +1,720 @@
/*EGA emulation*/
#include "ibm.h"
#include "video.h"
void ega_recalctimings();
void ega_write(uint32_t addr, uint8_t val);
uint8_t ega_read(uint32_t addr);
extern uint8_t edatlookup[4][4];
uint8_t ega_3c2;
static uint8_t la, lb, lc, ld;
static uint8_t ega_rotate[8][256];
/*3C2 controls default mode on EGA. On VGA, it determines monitor type (mono or colour)*/
int egaswitchread,egaswitches=9; /*7=CGA mode (200 lines), 9=EGA mode (350 lines), 8=EGA mode (200 lines)*/
void ega_out(uint16_t addr, uint8_t val)
{
int c;
uint8_t o,old;
if ((addr&0xFFF0) == 0x3B0) addr |= 0x20;
switch (addr)
{
case 0x3C0:
if (!attrff)
attraddr=val&31;
else
{
attrregs[attraddr&31]=val;
if (attraddr<16) fullchange=changeframecount;
if (attraddr==0x10 || attraddr==0x14 || attraddr<0x10)
{
for (c=0;c<16;c++)
{
if (attrregs[0x10]&0x80) egapal[c]=(attrregs[c]&0xF)|((attrregs[0x14]&0xF)<<4);
else egapal[c]=(attrregs[c]&0x3F)|((attrregs[0x14]&0xC)<<4);
}
}
}
attrff^=1;
break;
case 0x3C2:
egaswitchread=val&0xC;
vres=!(val&0x80);
pallook=(vres)?pallook16:pallook64;
vidclock=val&4; /*printf("3C2 write %02X\n",val);*/
ega_3c2=val;
break;
case 0x3C4: seqaddr=val; break;
case 0x3C5:
o=seqregs[seqaddr&0xF];
seqregs[seqaddr&0xF]=val;
if (o!=val && (seqaddr&0xF)==1) ega_recalctimings();
switch (seqaddr&0xF)
{
case 1: if (scrblank && !(val&0x20)) fullchange=3; scrblank=(scrblank&~0x20)|(val&0x20); break;
case 2: writemask=val&0xF; break;
case 3:
charset=val&0xF;
charseta=((charset>>2)*0x10000)+2;
charsetb=((charset&3) *0x10000)+2;
break;
}
break;
case 0x3CE: gdcaddr=val; break;
case 0x3CF:
gdcreg[gdcaddr&15]=val;
switch (gdcaddr&15)
{
case 2: colourcompare=val; break;
case 4: readplane=val&3; break;
case 5: writemode=val&3; readmode=val&8; break;
case 6:
mem_removehandler(0xa0000, 0x20000, ega_read, NULL, NULL, ega_write, NULL, NULL);
// pclog("Write mapping %02X\n", val);
switch (val&0xC)
{
case 0x0: /*128k at A0000*/
mem_sethandler(0xa0000, 0x20000, ega_read, NULL, NULL, ega_write, NULL, NULL);
break;
case 0x4: /*64k at A0000*/
mem_sethandler(0xa0000, 0x10000, ega_read, NULL, NULL, ega_write, NULL, NULL);
break;
case 0x8: /*32k at B0000*/
mem_sethandler(0xb0000, 0x08000, ega_read, NULL, NULL, ega_write, NULL, NULL);
break;
case 0xC: /*32k at B8000*/
mem_sethandler(0xb8000, 0x08000, ega_read, NULL, NULL, ega_write, NULL, NULL);
break;
}
break;
case 7: colournocare=val; break;
}
break;
case 0x3D4:
crtcreg=val;
return;
case 0x3D5:
if (crtcreg <= 7 && crtc[0x11] & 0x80) return;
old=crtc[crtcreg];
crtc[crtcreg]=val;
if (old!=val)
{
if (crtcreg<0xE || crtcreg>0x10)
{
fullchange=changeframecount;
ega_recalctimings();
}
}
break;
}
}
uint8_t ega_in(uint16_t addr)
{
uint8_t temp;
if ((addr&0xFFF0) == 0x3B0) addr |= 0x20;
switch (addr)
{
case 0x3C0: return attraddr;
case 0x3C1: return attrregs[attraddr];
case 0x3C2:
// printf("Read egaswitch %02X %02X %i\n",egaswitchread,egaswitches,VGA);
switch (egaswitchread)
{
case 0xC: return (egaswitches&1)?0x10:0;
case 0x8: return (egaswitches&2)?0x10:0;
case 0x4: return (egaswitches&4)?0x10:0;
case 0x0: return (egaswitches&8)?0x10:0;
}
break;
case 0x3C4: return seqaddr;
case 0x3C5:
return seqregs[seqaddr&0xF];
case 0x3CE: return gdcaddr;
case 0x3CF:
return gdcreg[gdcaddr&0xF];
case 0x3D4:
return crtcreg;
case 0x3D5:
return crtc[crtcreg];
case 0x3DA:
attrff=0;
cgastat^=0x30; /*Fools IBM EGA video BIOS self-test*/
return cgastat;
}
// printf("Bad EGA read %04X %04X:%04X\n",addr,cs>>4,pc);
return 0xFF;
}
static int linepos,displine,vslines;
static int egadispon;
static uint32_t ma,ca,maback;
static int vc,sc;
static int con,cursoron,cgablink;
static int scrollcache;
#define vrammask 0x3FFFF
void ega_recalctimings()
{
float crtcconst;
int temp;
ega_vtotal=crtc[6];
ega_dispend=crtc[0x12];
ega_vsyncstart=crtc[0x10];
ega_split=crtc[0x18];
if (crtc[7]&1) ega_vtotal|=0x100;
if (crtc[7]&32) ega_vtotal|=0x200;
ega_vtotal++;
if (crtc[7]&2) ega_dispend|=0x100;
if (crtc[7]&64) ega_dispend|=0x200;
ega_dispend++;
if (crtc[7]&4) ega_vsyncstart|=0x100;
if (crtc[7]&128) ega_vsyncstart|=0x200;
ega_vsyncstart++;
if (crtc[7]&0x10) ega_split|=0x100;
if (crtc[9]&0x40) ega_split|=0x200;
ega_split+=2;
ega_hdisp=crtc[1];
ega_hdisp++;
ega_rowoffset=crtc[0x13];
printf("Recalc! %i %i %i %i %i %02X\n",ega_vtotal,ega_dispend,ega_vsyncstart,ega_split,ega_hdisp,attrregs[0x16]);
if (vidclock) crtcconst=(seqregs[1]&1)?(MDACONST*(8.0/9.0)):MDACONST;
else crtcconst=(seqregs[1]&1)?(CGACONST*(8.0/9.0)):CGACONST;
disptime=crtc[0]+2;
dispontime=crtc[1]+1;
printf("Disptime %f dispontime %f hdisp %i\n",disptime,dispontime,crtc[1]*8);
if (seqregs[1]&8) { disptime*=2; dispontime*=2; }
dispofftime=disptime-dispontime;
dispontime*=crtcconst;
dispofftime*=crtcconst;
// printf("EGA horiz total %i display end %i clock rate %i vidclock %i %i\n",crtc[0],crtc[1],egaswitchread,vidclock,((ega3c2>>2)&3) | ((tridentnewctrl2<<2)&4));
// printf("EGA vert total %i display end %i max row %i vsync %i\n",ega_vtotal,ega_dispend,(crtc[9]&31)+1,ega_vsyncstart);
// printf("total %f on %f cycles off %f cycles frame %f sec %f %02X\n",disptime*crtcconst,dispontime,dispofftime,(dispontime+dispofftime)*ega_vtotal,(dispontime+dispofftime)*ega_vtotal*70,seqregs[1]);
}
void ega_poll()
{
uint8_t chr,dat,attr;
uint32_t charaddr;
int x,xx;
uint32_t fg,bg;
int offset;
uint8_t edat[4];
int drawcursor=0;
if (!linepos)
{
vidtime+=dispofftime;
cgastat|=1;
linepos=1;
if (egadispon)
{
if (firstline==2000) firstline=displine;
if (scrblank)
{
for (x=0;x<ega_hdisp;x++)
{
switch (seqregs[1]&9)
{
case 0:
for (xx=0;xx<9;xx++) ((uint32_t *)buffer32->line[displine])[(x*9)+xx+32]=0;
break;
case 1:
for (xx=0;xx<8;xx++) ((uint32_t *)buffer32->line[displine])[(x*8)+xx+32]=0;
break;
case 8:
for (xx=0;xx<18;xx++) ((uint32_t *)buffer32->line[displine])[(x*18)+xx+32]=0;
break;
case 9:
for (xx=0;xx<16;xx++) ((uint32_t *)buffer32->line[displine])[(x*16)+xx+32]=0;
break;
}
}
}
else if (!(gdcreg[6]&1))
{
if (fullchange)
{
for (x=0;x<ega_hdisp;x++)
{
drawcursor=((ma==ca) && con && cursoron);
chr=vram[(ma<<1)];
attr=vram[(ma<<1)+4];
if (attr&8) charaddr=charsetb+(chr*128);
else charaddr=charseta+(chr*128);
if (drawcursor) { bg=pallook[egapal[attr&15]]; fg=pallook[egapal[attr>>4]]; }
else
{
fg=pallook[egapal[attr&15]];
bg=pallook[egapal[attr>>4]];
if (attr&0x80 && attrregs[0x10]&8)
{
bg=pallook[egapal[(attr>>4)&7]];
if (cgablink&16) fg=bg;
}
}
dat=vram[charaddr+(sc<<2)];
if (seqregs[1]&8)
{
if (seqregs[1]&1) { for (xx=0;xx<8;xx++) ((uint32_t *)buffer32->line[displine])[((x<<4)+32+(xx<<1))&2047]=((uint32_t *)buffer32->line[displine])[((x<<4)+33+(xx<<1))&2047]=(dat&(0x80>>xx))?fg:bg; }
else
{
for (xx=0;xx<8;xx++) ((uint32_t *)buffer32->line[displine])[((x*18)+32+(xx<<1))&2047]=((uint32_t *)buffer32->line[displine])[((x*18)+33+(xx<<1))&2047]=(dat&(0x80>>xx))?fg:bg;
if ((chr&~0x1F)!=0xC0 || !(attrregs[0x10]&4)) ((uint32_t *)buffer32->line[displine])[((x*18)+32+16)&2047]=((uint32_t *)buffer32->line[displine])[((x*18)+32+17)&2047]=bg;
else ((uint32_t *)buffer32->line[displine])[((x*18)+32+16)&2047]=((uint32_t *)buffer32->line[displine])[((x*18)+32+17)&2047]=(dat&1)?fg:bg;
}
}
else
{
if (seqregs[1]&1) { for (xx=0;xx<8;xx++) ((uint32_t *)buffer32->line[displine])[((x<<3)+32+xx)&2047]=(dat&(0x80>>xx))?fg:bg; }
else
{
for (xx=0;xx<8;xx++) ((uint32_t *)buffer32->line[displine])[((x*9)+32+xx)&2047]=(dat&(0x80>>xx))?fg:bg;
if ((chr&~0x1F)!=0xC0 || !(attrregs[0x10]&4)) ((uint32_t *)buffer32->line[displine])[((x*9)+32+8)&2047]=bg;
else ((uint32_t *)buffer32->line[displine])[((x*9)+32+8)&2047]=(dat&1)?fg:bg;
}
}
ma+=4; ma&=vrammask;
}
}
}
else
{
switch (gdcreg[5]&0x20)
{
case 0x00:
if (seqregs[1]&8)
{
offset=((8-scrollcache)<<1)+16;
for (x=0;x<=ega_hdisp;x++)
{
if (sc&1 && !(crtc[0x17]&1))
{
edat[0] = vram[ma | 0x8000];
edat[1] = vram[ma | 0x8001];
edat[2] = vram[ma | 0x8002];
edat[3] = vram[ma | 0x8003];
}
else
{
edat[0] = vram[ma];
edat[1] = vram[ma | 0x1];
edat[2] = vram[ma | 0x2];
edat[3] = vram[ma | 0x3];
}
ma+=4; ma&=vrammask;
dat=edatlookup[edat[0]&3][edat[1]&3]|(edatlookup[edat[2]&3][edat[3]&3]<<2);
((uint32_t *)buffer32->line[displine])[(x<<4)+14+offset]=((uint32_t *)buffer32->line[displine])[(x<<4)+15+offset]=pallook[egapal[(dat & 0xF) & attrregs[0x12]]];
((uint32_t *)buffer32->line[displine])[(x<<4)+12+offset]=((uint32_t *)buffer32->line[displine])[(x<<4)+13+offset]=pallook[egapal[(dat >> 4) & attrregs[0x12]]];
dat=edatlookup[(edat[0]>>2)&3][(edat[1]>>2)&3]|(edatlookup[(edat[2]>>2)&3][(edat[3]>>2)&3]<<2);
((uint32_t *)buffer32->line[displine])[(x<<4)+10+offset]=((uint32_t *)buffer32->line[displine])[(x<<4)+11+offset]=pallook[egapal[(dat & 0xF) & attrregs[0x12]]];
((uint32_t *)buffer32->line[displine])[(x<<4)+8+offset]= ((uint32_t *)buffer32->line[displine])[(x<<4)+9+offset]=pallook[egapal[(dat >> 4) & attrregs[0x12]]];
dat=edatlookup[(edat[0]>>4)&3][(edat[1]>>4)&3]|(edatlookup[(edat[2]>>4)&3][(edat[3]>>4)&3]<<2);
((uint32_t *)buffer32->line[displine])[(x<<4)+6+offset]= ((uint32_t *)buffer32->line[displine])[(x<<4)+7+offset]=pallook[egapal[(dat & 0xF) & attrregs[0x12]]];
((uint32_t *)buffer32->line[displine])[(x<<4)+4+offset]= ((uint32_t *)buffer32->line[displine])[(x<<4)+5+offset]=pallook[egapal[(dat >> 4) & attrregs[0x12]]];
dat=edatlookup[edat[0]>>6][edat[1]>>6]|(edatlookup[edat[2]>>6][edat[3]>>6]<<2);
((uint32_t *)buffer32->line[displine])[(x<<4)+2+offset]= ((uint32_t *)buffer32->line[displine])[(x<<4)+3+offset]=pallook[egapal[(dat & 0xF) & attrregs[0x12]]];
((uint32_t *)buffer32->line[displine])[(x<<4)+offset]= ((uint32_t *)buffer32->line[displine])[(x<<4)+1+offset]=pallook[egapal[(dat >> 4) & attrregs[0x12]]];
}
}
else
{
offset=(8-scrollcache)+24;
for (x=0;x<=ega_hdisp;x++)
{
if (sc&1 && !(crtc[0x17]&1))
{
edat[0] = vram[ma | 0x8000];
edat[1] = vram[ma | 0x8001];
edat[2] = vram[ma | 0x8002];
edat[3] = vram[ma | 0x8003];
}
else
{
edat[0] = vram[ma];
edat[1] = vram[ma | 0x1];
edat[2] = vram[ma | 0x2];
edat[3] = vram[ma | 0x3];
}
ma+=4; ma&=vrammask;
dat=edatlookup[edat[0]&3][edat[1]&3]|(edatlookup[edat[2]&3][edat[3]&3]<<2);
((uint32_t *)buffer32->line[displine])[(x<<3)+7+offset]=pallook[egapal[(dat & 0xF) & attrregs[0x12]]];
((uint32_t *)buffer32->line[displine])[(x<<3)+6+offset]=pallook[egapal[(dat >> 4) & attrregs[0x12]]];
dat=edatlookup[(edat[0]>>2)&3][(edat[1]>>2)&3]|(edatlookup[(edat[2]>>2)&3][(edat[3]>>2)&3]<<2);
((uint32_t *)buffer32->line[displine])[(x<<3)+5+offset]=pallook[egapal[(dat & 0xF) & attrregs[0x12]]];
((uint32_t *)buffer32->line[displine])[(x<<3)+4+offset]=pallook[egapal[(dat >> 4) & attrregs[0x12]]];
dat=edatlookup[(edat[0]>>4)&3][(edat[1]>>4)&3]|(edatlookup[(edat[2]>>4)&3][(edat[3]>>4)&3]<<2);
((uint32_t *)buffer32->line[displine])[(x<<3)+3+offset]=pallook[egapal[(dat & 0xF) & attrregs[0x12]]];
((uint32_t *)buffer32->line[displine])[(x<<3)+2+offset]=pallook[egapal[(dat >> 4) & attrregs[0x12]]];
dat=edatlookup[edat[0]>>6][edat[1]>>6]|(edatlookup[edat[2]>>6][edat[3]>>6]<<2);
((uint32_t *)buffer32->line[displine])[(x<<3)+1+offset]=pallook[egapal[(dat & 0xF) & attrregs[0x12]]];
((uint32_t *)buffer32->line[displine])[(x<<3)+offset]= pallook[egapal[(dat >> 4) & attrregs[0x12]]];
}
}
break;
case 0x20:
offset=((8-scrollcache)<<1)+16;
for (x=0;x<=ega_hdisp;x++)
{
if (sc&1 && !(crtc[0x17]&1))
{
edat[0]=vram[(ma<<1)+0x8000];
edat[1]=vram[(ma<<1)+0x8004];
}
else
{
edat[0]=vram[(ma<<1)];
edat[1]=vram[(ma<<1)+4];
}
ma+=4; ma&=vrammask;
((uint32_t *)buffer32->line[displine])[(x<<4)+14+offset]=((uint32_t *)buffer32->line[displine])[(x<<4)+15+offset]=pallook[egapal[edat[1]&3]];
((uint32_t *)buffer32->line[displine])[(x<<4)+12+offset]=((uint32_t *)buffer32->line[displine])[(x<<4)+13+offset]=pallook[egapal[(edat[1]>>2)&3]];
dat=edatlookup[(edat[0]>>2)&3][(edat[1]>>2)&3]|(edatlookup[(edat[2]>>2)&3][(edat[3]>>2)&3]<<2);
((uint32_t *)buffer32->line[displine])[(x<<4)+10+offset]=((uint32_t *)buffer32->line[displine])[(x<<4)+11+offset]=pallook[egapal[(edat[1]>>4)&3]];
((uint32_t *)buffer32->line[displine])[(x<<4)+8+offset]= ((uint32_t *)buffer32->line[displine])[(x<<4)+9+offset]=pallook[egapal[(edat[1]>>6)&3]];
dat=edatlookup[(edat[0]>>4)&3][(edat[1]>>4)&3]|(edatlookup[(edat[2]>>4)&3][(edat[3]>>4)&3]<<2);
((uint32_t *)buffer32->line[displine])[(x<<4)+6+offset]= ((uint32_t *)buffer32->line[displine])[(x<<4)+7+offset]=pallook[egapal[(edat[0]>>0)&3]];
((uint32_t *)buffer32->line[displine])[(x<<4)+4+offset]= ((uint32_t *)buffer32->line[displine])[(x<<4)+5+offset]=pallook[egapal[(edat[0]>>2)&3]];
dat=edatlookup[edat[0]>>6][edat[1]>>6]|(edatlookup[edat[2]>>6][edat[3]>>6]<<2);
((uint32_t *)buffer32->line[displine])[(x<<4)+2+offset]= ((uint32_t *)buffer32->line[displine])[(x<<4)+3+offset]=pallook[egapal[(edat[0]>>4)&3]];
((uint32_t *)buffer32->line[displine])[(x<<4)+offset]= ((uint32_t *)buffer32->line[displine])[(x<<4)+1+offset]=pallook[egapal[(edat[0]>>6)&3]];
}
break;
}
}
if (lastline<displine) lastline=displine;
}
displine++;
if ((cgastat&8) && ((displine&15)==(crtc[0x11]&15)) && vslines)
cgastat&=~8;
vslines++;
if (displine>500) displine=0;
}
else
{
vidtime+=dispontime;
// if (output) printf("Display on %f\n",vidtime);
if (egadispon) cgastat&=~1;
linepos=0;
if (sc==(crtc[11]&31))
con=0;
if (egadispon)
{
if (sc==(crtc[9]&31))
{
sc=0;
maback+=(ega_rowoffset<<3);
maback&=vrammask;
ma=maback;
}
else
{
sc++;
sc&=31;
ma=maback;
}
}
vc++;
vc&=1023;
// printf("Line now %i %i ma %05X\n",vc,displine,ma);
if (vc==ega_split)
{
// printf("Split at line %i %i\n",displine,vc);
ma=maback=0;
if (attrregs[0x10]&0x20) scrollcache=0;
}
if (vc==ega_dispend)
{
// printf("Display over at line %i %i\n",displine,vc);
egadispon=0;
if (crtc[10] & 0x20) cursoron=0;
else cursoron=cgablink&16;
if (!(gdcreg[6]&1) && !(cgablink&15)) fullchange=2;
cgablink++;
for (x=0;x<2048;x++) if (changedvram[x]) changedvram[x]--;
// memset(changedvram,0,2048);
if (fullchange) fullchange--;
}
if (vc==ega_vsyncstart)
{
egadispon=0;
// printf("Vsync on at line %i %i\n",displine,vc);
cgastat|=8;
if (seqregs[1]&8) x=ega_hdisp*((seqregs[1]&1)?8:9)*2;
else x=ega_hdisp*((seqregs[1]&1)?8:9);
wx=x;
wy=lastline-firstline;
// pclog("Cursor %02X %02X\n",crtc[10],crtc[11]);
// pclog("Firstline %i Lastline %i wx %i %i\n",firstline,lastline,wx,oddeven);
// doblit();
svga_doblit(firstline, lastline + 1);
video_res_x = wx;
video_res_y = wy + 1;
if (!(gdcreg[6]&1)) /*Text mode*/
{
video_res_x /= (seqregs[1] & 1) ? 8 : 9;
video_res_y /= (crtc[9] & 31) + 1;
video_bpp = 0;
}
else
{
if (crtc[9] & 0x80)
video_res_y /= 2;
if (!(crtc[0x17] & 1))
video_res_y *= 2;
video_res_y /= (crtc[9] & 31) + 1;
if (seqregs[1] & 8)
video_res_x /= 2;
video_bpp = (gdcreg[5] & 0x20) ? 2 : 4;
}
// wakeupblit();
readflash=0;
//framecount++;
firstline=2000;
lastline=0;
maback=ma=(crtc[0xC]<<8)|crtc[0xD];
ca=(crtc[0xE]<<8)|crtc[0xF];
ma<<=2;
maback<<=2;
ca<<=2;
changeframecount=2;
vslines=0;
}
if (vc==ega_vtotal)
{
vc=0;
sc=0;
egadispon=1;
displine=0;
scrollcache=attrregs[0x13]&7;
}
if (sc == (crtc[10] & 31)) con=1;
}
}
void ega_write(uint32_t addr, uint8_t val)
{
int x,y;
char s[2]={0,0};
uint8_t vala,valb,valc,vald,wm=writemask;
egawrites++;
cycles -= video_timing_b;
cycles_lost += video_timing_b;
if (addr>=0xB0000) addr &= 0x7fff;
else addr &= 0xffff;
if (!(gdcreg[6]&1)) fullchange=2;
addr <<= 2;
// pclog("%i %08X %i %i %02X %02X %02X %02X %02X\n",chain4,addr,writemode,writemask,gdcreg[8],vram[0],vram[1],vram[2],vram[3]);
switch (writemode)
{
case 1:
if (writemask&1) vram[addr]=la;
if (writemask&2) vram[addr|0x1]=lb;
if (writemask&4) vram[addr|0x2]=lc;
if (writemask&8) vram[addr|0x3]=ld;
break;
case 0:
if (gdcreg[3]&7) val=ega_rotate[gdcreg[3]&7][val];
if (gdcreg[8]==0xFF && !(gdcreg[3]&0x18) && !gdcreg[1])
{
// pclog("Easy write %05X %02X\n",addr,val);
if (writemask&1) vram[addr]=val;
if (writemask&2) vram[addr|0x1]=val;
if (writemask&4) vram[addr|0x2]=val;
if (writemask&8) vram[addr|0x3]=val;
}
else
{
if (gdcreg[1]&1) vala=(gdcreg[0]&1)?0xFF:0;
else vala=val;
if (gdcreg[1]&2) valb=(gdcreg[0]&2)?0xFF:0;
else valb=val;
if (gdcreg[1]&4) valc=(gdcreg[0]&4)?0xFF:0;
else valc=val;
if (gdcreg[1]&8) vald=(gdcreg[0]&8)?0xFF:0;
else vald=val;
// pclog("Write %02X %01X %02X %02X %02X %02X %02X\n",gdcreg[3]&0x18,writemask,vala,valb,valc,vald,gdcreg[8]);
switch (gdcreg[3]&0x18)
{
case 0: /*Set*/
if (writemask&1) vram[addr]=(vala&gdcreg[8])|(la&~gdcreg[8]);
if (writemask&2) vram[addr|0x1]=(valb&gdcreg[8])|(lb&~gdcreg[8]);
if (writemask&4) vram[addr|0x2]=(valc&gdcreg[8])|(lc&~gdcreg[8]);
if (writemask&8) vram[addr|0x3]=(vald&gdcreg[8])|(ld&~gdcreg[8]);
break;
case 8: /*AND*/
if (writemask&1) vram[addr]=(vala|~gdcreg[8])&la;
if (writemask&2) vram[addr|0x1]=(valb|~gdcreg[8])&lb;
if (writemask&4) vram[addr|0x2]=(valc|~gdcreg[8])&lc;
if (writemask&8) vram[addr|0x3]=(vald|~gdcreg[8])&ld;
break;
case 0x10: /*OR*/
if (writemask&1) vram[addr]=(vala&gdcreg[8])|la;
if (writemask&2) vram[addr|0x1]=(valb&gdcreg[8])|lb;
if (writemask&4) vram[addr|0x2]=(valc&gdcreg[8])|lc;
if (writemask&8) vram[addr|0x3]=(vald&gdcreg[8])|ld;
break;
case 0x18: /*XOR*/
if (writemask&1) vram[addr]=(vala&gdcreg[8])^la;
if (writemask&2) vram[addr|0x1]=(valb&gdcreg[8])^lb;
if (writemask&4) vram[addr|0x2]=(valc&gdcreg[8])^lc;
if (writemask&8) vram[addr|0x3]=(vald&gdcreg[8])^ld;
break;
}
// pclog("- %02X %02X %02X %02X %08X\n",vram[addr],vram[addr|0x1],vram[addr|0x2],vram[addr|0x3],addr);
}
break;
case 2:
if (!(gdcreg[3]&0x18) && !gdcreg[1])
{
if (writemask&1) vram[addr]=(((val&1)?0xFF:0)&gdcreg[8])|(la&~gdcreg[8]);
if (writemask&2) vram[addr|0x1]=(((val&2)?0xFF:0)&gdcreg[8])|(lb&~gdcreg[8]);
if (writemask&4) vram[addr|0x2]=(((val&4)?0xFF:0)&gdcreg[8])|(lc&~gdcreg[8]);
if (writemask&8) vram[addr|0x3]=(((val&8)?0xFF:0)&gdcreg[8])|(ld&~gdcreg[8]);
}
else
{
vala=((val&1)?0xFF:0);
valb=((val&2)?0xFF:0);
valc=((val&4)?0xFF:0);
vald=((val&8)?0xFF:0);
switch (gdcreg[3]&0x18)
{
case 0: /*Set*/
if (writemask&1) vram[addr]=(vala&gdcreg[8])|(la&~gdcreg[8]);
if (writemask&2) vram[addr|0x1]=(valb&gdcreg[8])|(lb&~gdcreg[8]);
if (writemask&4) vram[addr|0x2]=(valc&gdcreg[8])|(lc&~gdcreg[8]);
if (writemask&8) vram[addr|0x3]=(vald&gdcreg[8])|(ld&~gdcreg[8]);
break;
case 8: /*AND*/
if (writemask&1) vram[addr]=(vala|~gdcreg[8])&la;
if (writemask&2) vram[addr|0x1]=(valb|~gdcreg[8])&lb;
if (writemask&4) vram[addr|0x2]=(valc|~gdcreg[8])&lc;
if (writemask&8) vram[addr|0x3]=(vald|~gdcreg[8])&ld;
break;
case 0x10: /*OR*/
if (writemask&1) vram[addr]=(vala&gdcreg[8])|la;
if (writemask&2) vram[addr|0x1]=(valb&gdcreg[8])|lb;
if (writemask&4) vram[addr|0x2]=(valc&gdcreg[8])|lc;
if (writemask&8) vram[addr|0x3]=(vald&gdcreg[8])|ld;
break;
case 0x18: /*XOR*/
if (writemask&1) vram[addr]=(vala&gdcreg[8])^la;
if (writemask&2) vram[addr|0x1]=(valb&gdcreg[8])^lb;
if (writemask&4) vram[addr|0x2]=(valc&gdcreg[8])^lc;
if (writemask&8) vram[addr|0x3]=(vald&gdcreg[8])^ld;
break;
}
}
break;
}
}
uint8_t ega_read(uint32_t addr)
{
uint8_t temp,temp2,temp3,temp4;
uint32_t addr2;
egareads++;
cycles -= video_timing_b;
cycles_lost += video_timing_b;
// pclog("Readega %06X ",addr);
if (addr>=0xB0000) addr &= 0x7fff;
else addr &= 0xffff;
addr<<=2;
la=vram[addr];
lb=vram[addr|0x1];
lc=vram[addr|0x2];
ld=vram[addr|0x3];
if (readmode)
{
temp= (colournocare&1) ?0xFF:0;
temp&=la;
temp^=(colourcompare&1)?0xFF:0;
temp2= (colournocare&2) ?0xFF:0;
temp2&=lb;
temp2^=(colourcompare&2)?0xFF:0;
temp3= (colournocare&4) ?0xFF:0;
temp3&=lc;
temp3^=(colourcompare&4)?0xFF:0;
temp4= (colournocare&8) ?0xFF:0;
temp4&=ld;
temp4^=(colourcompare&8)?0xFF:0;
return ~(temp|temp2|temp3|temp4);
}
return vram[addr|readplane];
}
int ega_init()
{
int c, d, e;
for (c = 0; c < 256; c++)
{
e = c;
for (d = 0; d < 8; d++)
{
ega_rotate[d][c] = e;
e = (e >> 1) | ((e & 1) ? 0x80 : 0);
}
}
return 0;
}
GFXCARD vid_ega =
{
ega_init,
/*IO at 3Cx/3Dx*/
ega_out,
ega_in,
/*IO at 3Ax/3Bx*/
video_out_null,
video_in_null,
ega_poll,
ega_recalctimings,
ega_write,
video_write_null,
video_write_null,
ega_read,
video_read_null,
video_read_null
};

7
src/vid_ega.h Normal file
View file

@ -0,0 +1,7 @@
int ega_init();
void ega_out(uint16_t addr, uint8_t val);
uint8_t ega_in(uint16_t addr);
void ega_poll();
void ega_recalctimings();
void ega_write(uint32_t addr, uint8_t val);
uint8_t ega_read(uint32_t addr);

141
src/vid_et4000.c Normal file
View file

@ -0,0 +1,141 @@
/*ET4000 emulation*/
#include "ibm.h"
#include "video.h"
#include "vid_svga.h"
#include "vid_unk_ramdac.h"
int et4k_b8000;
void et4000_out(uint16_t addr, uint8_t val)
{
uint8_t old;
if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga_miscout&1)) addr ^= 0x60;
pclog("ET4000 out %04X %02X\n", addr, val);
switch (addr)
{
case 0x3C6: case 0x3C7: case 0x3C8: case 0x3C9:
unk_ramdac_out(addr,val);
return;
case 0x3CD: /*Banking*/
svgawbank=(val&0xF)*65536;
svgarbank=((val>>4)&0xF)*65536;
svgaseg=val;
pclog("Banking write %08X %08X %02X\n", svgawbank, svgarbank, val);
return;
case 0x3CF:
switch (gdcaddr&15)
{
case 6:
et4k_b8000=((crtc[0x36]&0x38)==0x28) && ((gdcreg[6]&0xC)==4);
break;
}
break;
case 0x3D4:
crtcreg = val & 0x3f;
return;
case 0x3D5:
if (crtcreg <= 7 && crtc[0x11] & 0x80) return;
old=crtc[crtcreg];
crtc[crtcreg]=val;
et4k_b8000=((crtc[0x36]&0x38)==0x28) && ((gdcreg[6]&0xC)==4);
if (old!=val)
{
if (crtcreg<0xE || crtcreg>0x10)
{
fullchange=changeframecount;
svga_recalctimings();
}
}
break;
case 0x3D8:
if (val==0xA0) svgaon=1;
if (val==0x29) svgaon=0;
break;
}
svga_out(addr,val);
}
uint8_t et4000_in(uint16_t addr)
{
uint8_t temp;
if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga_miscout&1)) addr ^= 0x60;
if (addr != 0x3da) pclog("IN ET4000 %04X\n", addr);
switch (addr)
{
case 0x3C5:
if ((seqaddr&0xF)==7) return seqregs[seqaddr&0xF]|4;
break;
case 0x3C6: case 0x3C7: case 0x3C8: case 0x3C9:
return unk_ramdac_in(addr);
case 0x3CD: /*Banking*/
return svgaseg;
case 0x3D4:
return crtcreg;
case 0x3D5:
return crtc[crtcreg];
}
return svga_in(addr);
}
void et4000_recalctimings()
{
svga_ma|=(crtc[0x33]&3)<<16;
if (crtc[0x35]&2) svga_vtotal+=0x400;
if (crtc[0x35]&4) svga_dispend+=0x400;
if (crtc[0x35]&8) svga_vsyncstart+=0x400;
if (crtc[0x35]&0x10) svga_split+=0x400;
if (!svga_rowoffset) svga_rowoffset=0x100;
// if (crtc[0x3F]&0x80) svga_rowoffset+=0x100;
if (crtc[0x3F]&1) svga_htotal+=256;
if (attrregs[0x16]&0x20) svga_hdisp<<=1;
// pclog("Rowoffset %i\n",svga_rowoffset);
switch (((svga_miscout >> 2) & 3) | ((crtc[0x34] << 1) & 4))
{
case 0: case 1: break;
case 3: svga_clock = cpuclock/40000000.0; break;
case 5: svga_clock = cpuclock/65000000.0; break;
default: svga_clock = cpuclock/36000000.0; break;
}
}
int et4000_init()
{
svga_recalctimings_ex = et4000_recalctimings;
svga_vram_limit = 1 << 20; /*1mb*/
vrammask = 0xfffff;
return svga_init();
}
GFXCARD vid_et4000 =
{
et4000_init,
/*IO at 3Cx/3Dx*/
et4000_out,
et4000_in,
/*IO at 3Ax/3Bx*/
video_out_null,
video_in_null,
svga_poll,
svga_recalctimings,
svga_write,
video_write_null,
video_write_null,
svga_read,
video_read_null,
video_read_null
};

936
src/vid_et4000w32.c Normal file
View file

@ -0,0 +1,936 @@
/*ET4000/W32p emulation (Diamond Stealth 32)*/
/*Known bugs :
- Accelerator doesn't work in planar modes
*/
#include "ibm.h"
#include "video.h"
#include "vid_svga.h"
#include "vid_icd2061.h"
#include "vid_stg_ramdac.h"
#include "mem.h"
int et4k_b8000;
void et4000w32p_recalcmapping();
uint8_t et4000w32p_mmu_read(uint32_t addr);
void et4000w32p_mmu_write(uint32_t addr, uint8_t val);
static int et4000w32p_index;
static uint8_t et4000w32p_regs[256];
static uint32_t et4000w32p_linearbase, et4000w32p_linearbase_old;
void et4000w32p_out(uint16_t addr, uint8_t val)
{
uint8_t old;
// if (!(addr==0x3D4 && (val&~1)==0xE) && !(addr==0x3D5 && (crtcreg&~1)==0xE)) pclog("ET4000W32p out %04X %02X %04X:%04X ",addr,val,CS,pc);
if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga_miscout&1)) addr ^= 0x60;
// if (!(addr==0x3D4 && (val&~1)==0xE) && !(addr==0x3D5 && (crtcreg&~1)==0xE)) pclog("%04X\n",addr);
switch (addr)
{
case 0x3c2:
icd2061_write((val >> 2) & 3);
break;
case 0x3C6: case 0x3C7: case 0x3C8: case 0x3C9:
stg_ramdac_out(addr,val);
return;
case 0x3CB: /*Banking extension*/
svgawbank=(svgawbank&0xFFFFF)|((val&1)<<20);
svgarbank=(svgarbank&0xFFFFF)|((val&0x10)<<16);
svgaseg2=val;
return;
case 0x3CD: /*Banking*/
svgawbank=(svgawbank&0x100000)|((val&0xF)*65536);
svgarbank=(svgarbank&0x100000)|(((val>>4)&0xF)*65536);
svgaseg=val;
return;
case 0x3CF:
switch (gdcaddr&15)
{
case 6:
gdcreg[gdcaddr&15]=val;
//et4k_b8000=((crtc[0x36]&0x38)==0x28) && ((gdcreg[6]&0xC)==4);
et4000w32p_recalcmapping();
return;
}
break;
case 0x3D4:
crtcreg=val&63;
return;
case 0x3D5:
// pclog("Write CRTC R%02X %02X\n", crtcreg, val);
if (crtcreg <= 7 && crtc[0x11] & 0x80) return;
old=crtc[crtcreg];
crtc[crtcreg]=val;
et4k_b8000=((crtc[0x36]&0x38)==0x28) && ((gdcreg[6]&0xC)==4);
// if (crtcreg!=0xE && crtcreg!=0xF) pclog("CRTC R%02X = %02X\n",crtcreg,val);
if (old!=val)
{
if (crtcreg<0xE || crtcreg>0x10)
{
fullchange=changeframecount;
svga_recalctimings();
}
}
if (crtcreg == 0x30)
{
et4000w32p_linearbase = val * 0x400000;
// pclog("Linear base now at %08X %02X\n", et4000w32p_linearbase, val);
et4000w32p_recalcmapping();
}
if (crtcreg == 0x36) et4000w32p_recalcmapping();
break;
case 0x3D8:
if (val==0xA0) svgaon=1;
if (val==0x29) svgaon=0;
break;
case 0x210A: case 0x211A: case 0x212A: case 0x213A:
case 0x214A: case 0x215A: case 0x216A: case 0x217A:
et4000w32p_index=val;
return;
case 0x210B: case 0x211B: case 0x212B: case 0x213B:
case 0x214B: case 0x215B: case 0x216B: case 0x217B:
et4000w32p_regs[et4000w32p_index] = val;
svga_hwcursor.x = et4000w32p_regs[0xE0] | ((et4000w32p_regs[0xE1] & 7) << 8);
svga_hwcursor.y = et4000w32p_regs[0xE4] | ((et4000w32p_regs[0xE5] & 7) << 8);
svga_hwcursor.addr = (et4000w32p_regs[0xE8] | (et4000w32p_regs[0xE9] << 8) | ((et4000w32p_regs[0xEA] & 7) << 16)) << 2;
svga_hwcursor.addr += (et4000w32p_regs[0xE6] & 63) * 16;
svga_hwcursor.ena = et4000w32p_regs[0xF7] & 0x80;
svga_hwcursor.xoff = et4000w32p_regs[0xE2] & 63;
svga_hwcursor.yoff = et4000w32p_regs[0xE6] & 63;
// pclog("HWCURSOR X %i Y %i\n",svga_hwcursor_x,svga_hwcursor_y);
return;
}
svga_out(addr,val);
}
uint8_t et4000w32p_in(uint16_t addr)
{
uint8_t temp;
// if (addr==0x3DA) pclog("In 3DA %04X(%06X):%04X\n",CS,cs,pc);
// pclog("ET4000W32p in %04X %04X:%04X ",addr,CS,pc);
if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga_miscout&1)) addr ^= 0x60;
// pclog("%04X\n",addr);
switch (addr)
{
case 0x3C5:
if ((seqaddr&0xF)==7) return seqregs[seqaddr&0xF]|4;
break;
case 0x3C6: case 0x3C7: case 0x3C8: case 0x3C9:
return stg_ramdac_in(addr);
case 0x3CB:
return svgaseg2;
case 0x3CD:
return svgaseg;
case 0x3D4:
return crtcreg;
case 0x3D5:
// pclog("Read CRTC R%02X %02X\n", crtcreg, crtc[crtcreg]);
return crtc[crtcreg];
case 0x3DA:
attrff=0;
cgastat^=0x30;
temp = cgastat & 0x39;
if (svga_hdisp_on) temp |= 2;
if (!(cgastat & 8)) temp |= 0x80;
// pclog("3DA in %02X\n",temp);
return temp;
case 0x210A: case 0x211A: case 0x212A: case 0x213A:
case 0x214A: case 0x215A: case 0x216A: case 0x217A:
return et4000w32p_index;
case 0x210B: case 0x211B: case 0x212B: case 0x213B:
case 0x214B: case 0x215B: case 0x216B: case 0x217B:
if (et4000w32p_index==0xEC) return (et4000w32p_regs[0xEC]&0xF)|0x60; /*ET4000/W32p rev D*/
if (et4000w32p_index == 0xEF)
{
if (PCI) return et4000w32p_regs[0xEF] | 0xe0; /*PCI*/
else return et4000w32p_regs[0xEF] | 0x60; /*VESA local bus*/
}
return et4000w32p_regs[et4000w32p_index];
}
return svga_in(addr);
}
void et4000w32p_recalctimings()
{
double clk;
// pclog("Recalc %08X ",svga_ma);
svga_ma|=(crtc[0x33]&0x7)<<16;
pclog("SVGA_MA %08X %i\n", svga_ma, (svga_miscout >> 2) & 3);
if (crtc[0x35]&2) svga_vtotal+=0x400;
if (crtc[0x35]&4) svga_dispend+=0x400;
if (crtc[0x35]&8) svga_vsyncstart+=0x400;
if (crtc[0x35]&0x10) svga_split+=0x400;
if (crtc[0x3F]&0x80) svga_rowoffset+=0x100;
if (crtc[0x3F]&1) svga_htotal+=256;
if (attrregs[0x16]&0x20) svga_hdisp<<=1;
switch ((svga_miscout >> 2) & 3)
{
case 0: case 1: break;
case 2: case 3: svga_clock = cpuclock/icd2061_getfreq(2); break;
/* default:
pclog("Unknown clock %i\n", ((svga_miscout >> 2) & 3) | ((crtc[0x34] << 1) & 4) | ((crtc[0x31] & 0xc0) >> 3));
svga_clock = cpuclock/36000000.0; break;*/
}
// pclog("Recalctimings - %02X %02X %02X\n", crtc[6], crtc[7], crtc[0x35]);
}
int et4000w32p_getclock()
{
return ((svga_miscout >> 2) & 3) | ((crtc[0x34] << 1) & 4) | ((crtc[0x31] & 0xc0) >> 3);
}
void et4000w32p_recalcmapping()
{
int map;
mem_removehandler(et4000w32p_linearbase_old, 0x200000, svga_read_linear, svga_readw_linear, svga_readl_linear, svga_write_linear, svga_writew_linear, svga_writel_linear);
mem_removehandler(0xa0000, 0x20000, svga_read, svga_readw, svga_readl, svga_write, svga_writew, svga_writel);
mem_removehandler(0xb0000, 0x10000, et4000w32p_mmu_read, NULL, NULL, et4000w32p_mmu_write, NULL, NULL);
if (crtc[0x36] & 0x10) /*Linear frame buffer*/
{
mem_sethandler(et4000w32p_linearbase, 0x200000, svga_read_linear, svga_readw_linear, svga_readl_linear, svga_write_linear, svga_writew_linear, svga_writel_linear);
}
else
{
map = (gdcreg[6] & 0xC) >> 2;
if (crtc[0x36] & 0x20) map |= 4;
if (crtc[0x36] & 0x08) map |= 8;
switch (map)
{
case 0x0: case 0x4: case 0x8: case 0xC: /*128k at A0000*/
mem_sethandler(0xa0000, 0x20000, svga_read, svga_readw, svga_readl, svga_write, svga_writew, svga_writel);
break;
case 0x1: /*64k at A0000*/
mem_sethandler(0xa0000, 0x10000, svga_read, svga_readw, svga_readl, svga_write, svga_writew, svga_writel);
break;
case 0x2: /*32k at B0000*/
mem_sethandler(0xb0000, 0x08000, svga_read, svga_readw, svga_readl, svga_write, svga_writew, svga_writel);
break;
case 0x3: /*32k at B8000*/
mem_sethandler(0xb8000, 0x08000, svga_read, svga_readw, svga_readl, svga_write, svga_writew, svga_writel);
break;
case 0x5: case 0x9: case 0xD: /*64k at A0000, MMU at B8000*/
mem_sethandler(0xa0000, 0x10000, svga_read, svga_readw, svga_readl, svga_write, svga_writew, svga_writel);
mem_sethandler(0xb8000, 0x08000, et4000w32p_mmu_read, NULL, NULL, et4000w32p_mmu_write, NULL, NULL);
break;
case 0x6: case 0xA: case 0xE: /*32k at B0000, MMU at A8000*/
mem_sethandler(0xa8000, 0x08000, et4000w32p_mmu_read, NULL, NULL, et4000w32p_mmu_write, NULL, NULL);
mem_sethandler(0xb0000, 0x08000, svga_read, svga_readw, svga_readl, svga_write, svga_writew, svga_writel);
break;
case 0x7: case 0xB: case 0xF: /*32k at B8000, MMU at A8000*/
mem_sethandler(0xa8000, 0x08000, et4000w32p_mmu_read, NULL, NULL, et4000w32p_mmu_write, NULL, NULL);
mem_sethandler(0xb8000, 0x08000, svga_read, svga_readw, svga_readl, svga_write, svga_writew, svga_writel);
break;
}
// pclog("ET4K map %02X\n", map);
}
et4000w32p_linearbase_old = et4000w32p_linearbase;
}
/*Accelerator*/
struct
{
struct
{
uint32_t pattern_addr,source_addr,dest_addr,mix_addr;
uint16_t pattern_off,source_off,dest_off,mix_off;
uint8_t pixel_depth,xy_dir;
uint8_t pattern_wrap,source_wrap;
uint16_t count_x,count_y;
uint8_t ctrl_routing,ctrl_reload;
uint8_t rop_fg,rop_bg;
uint16_t pos_x,pos_y;
uint16_t error;
uint16_t dmin,dmaj;
} queued,internal;
uint32_t pattern_addr,source_addr,dest_addr,mix_addr;
uint32_t pattern_back,source_back,dest_back,mix_back;
int pattern_x,source_x;
int pattern_x_back,source_x_back;
int pattern_y,source_y;
uint8_t status;
uint64_t cpu_dat;
int cpu_dat_pos;
int pix_pos;
} acl;
#define ACL_WRST 1
#define ACL_RDST 2
#define ACL_XYST 4
#define ACL_SSO 8
struct
{
uint32_t base[3];
uint8_t ctrl;
} mmu;
void et4000w32_reset()
{
acl.status=0;
}
void et4000w32_blit_start();
void et4000w32_blit(int count, uint32_t mix, uint32_t sdat, int cpu_input);
void et4000w32p_mmu_write(uint32_t addr, uint8_t val)
{
int bank;
// pclog("ET4K write %08X %02X %02X %04X(%08X):%08X\n",addr,val,acl.status,acl.internal.ctrl_routing,CS,cs,pc);
switch (addr&0x6000)
{
case 0x0000: /*MMU 0*/
case 0x2000: /*MMU 1*/
case 0x4000: /*MMU 2*/
bank=(addr>>13)&3;
if (mmu.ctrl&(1<<bank))
{
if (!(acl.status&ACL_XYST)) return;
if (acl.internal.ctrl_routing&3)
{
if ((acl.internal.ctrl_routing&3)==2)
{
if (acl.mix_addr&7)
et4000w32_blit(8-(acl.mix_addr&7), val>>(acl.mix_addr&7), 0, 1);
else
et4000w32_blit(8, val, 0, 1);
}
else if ((acl.internal.ctrl_routing&3)==1)
et4000w32_blit(1, ~0, val, 2);
// else
// pclog("Bad ET4K routing %i\n",acl.internal.ctrl_routing&7);
}
}
else
{
vram[(addr&0x1FFF)+mmu.base[bank]]=val;
changedvram[((addr&0x1FFF)+mmu.base[bank])>>10]=changeframecount;
}
break;
case 0x6000:
switch (addr&0x7FFF)
{
case 0x7F00: mmu.base[0]=(mmu.base[0]&0xFFFFFF00)|val; break;
case 0x7F01: mmu.base[0]=(mmu.base[0]&0xFFFF00FF)|(val<<8); break;
case 0x7F02: mmu.base[0]=(mmu.base[0]&0xFF00FFFF)|(val<<16); break;
case 0x7F03: mmu.base[0]=(mmu.base[0]&0x00FFFFFF)|(val<<24); break;
case 0x7F04: mmu.base[1]=(mmu.base[1]&0xFFFFFF00)|val; break;
case 0x7F05: mmu.base[1]=(mmu.base[1]&0xFFFF00FF)|(val<<8); break;
case 0x7F06: mmu.base[1]=(mmu.base[1]&0xFF00FFFF)|(val<<16); break;
case 0x7F07: mmu.base[1]=(mmu.base[1]&0x00FFFFFF)|(val<<24); break;
case 0x7F08: mmu.base[2]=(mmu.base[2]&0xFFFFFF00)|val; break;
case 0x7F09: mmu.base[2]=(mmu.base[2]&0xFFFF00FF)|(val<<8); break;
case 0x7F0A: mmu.base[2]=(mmu.base[2]&0xFF00FFFF)|(val<<16); break;
case 0x7F0B: mmu.base[2]=(mmu.base[2]&0x00FFFFFF)|(val<<24); break;
case 0x7F13: mmu.ctrl=val; break;
case 0x7F80: acl.queued.pattern_addr=(acl.queued.pattern_addr&0xFFFFFF00)|val; break;
case 0x7F81: acl.queued.pattern_addr=(acl.queued.pattern_addr&0xFFFF00FF)|(val<<8); break;
case 0x7F82: acl.queued.pattern_addr=(acl.queued.pattern_addr&0xFF00FFFF)|(val<<16); break;
case 0x7F83: acl.queued.pattern_addr=(acl.queued.pattern_addr&0x00FFFFFF)|(val<<24); break;
case 0x7F84: acl.queued.source_addr =(acl.queued.source_addr &0xFFFFFF00)|val; break;
case 0x7F85: acl.queued.source_addr =(acl.queued.source_addr &0xFFFF00FF)|(val<<8); break;
case 0x7F86: acl.queued.source_addr =(acl.queued.source_addr &0xFF00FFFF)|(val<<16); break;
case 0x7F87: acl.queued.source_addr =(acl.queued.source_addr &0x00FFFFFF)|(val<<24); break;
case 0x7F88: acl.queued.pattern_off=(acl.queued.pattern_off&0xFF00)|val; break;
case 0x7F89: acl.queued.pattern_off=(acl.queued.pattern_off&0x00FF)|(val<<8); break;
case 0x7F8A: acl.queued.source_off =(acl.queued.source_off &0xFF00)|val; break;
case 0x7F8B: acl.queued.source_off =(acl.queued.source_off &0x00FF)|(val<<8); break;
case 0x7F8C: acl.queued.dest_off =(acl.queued.dest_off &0xFF00)|val; break;
case 0x7F8D: acl.queued.dest_off =(acl.queued.dest_off &0x00FF)|(val<<8); break;
case 0x7F8E: acl.queued.pixel_depth=val; break;
case 0x7F8F: acl.queued.xy_dir=val; break;
case 0x7F90: acl.queued.pattern_wrap=val; break;
case 0x7F92: acl.queued.source_wrap=val; break;
case 0x7F98: acl.queued.count_x =(acl.queued.count_x &0xFF00)|val; break;
case 0x7F99: acl.queued.count_x =(acl.queued.count_x &0x00FF)|(val<<8); break;
case 0x7F9A: acl.queued.count_y =(acl.queued.count_y &0xFF00)|val; break;
case 0x7F9B: acl.queued.count_y =(acl.queued.count_y &0x00FF)|(val<<8); break;
case 0x7F9C: acl.queued.ctrl_routing=val; break;
case 0x7F9D: acl.queued.ctrl_reload =val; break;
case 0x7F9E: acl.queued.rop_bg =val; break;
case 0x7F9F: acl.queued.rop_fg =val; break;
case 0x7FA0: acl.queued.dest_addr =(acl.queued.dest_addr &0xFFFFFF00)|val; break;
case 0x7FA1: acl.queued.dest_addr =(acl.queued.dest_addr &0xFFFF00FF)|(val<<8); break;
case 0x7FA2: acl.queued.dest_addr =(acl.queued.dest_addr &0xFF00FFFF)|(val<<16); break;
case 0x7FA3: acl.queued.dest_addr =(acl.queued.dest_addr &0x00FFFFFF)|(val<<24);
acl.internal=acl.queued;
et4000w32_blit_start();
if (!(acl.queued.ctrl_routing&0x43))
{
et4000w32_blit(0xFFFFFF, ~0, 0, 0);
}
if ((acl.queued.ctrl_routing&0x40) && !(acl.internal.ctrl_routing&3))
et4000w32_blit(4, ~0, 0, 0);
break;
case 0x7FA4: acl.queued.mix_addr=(acl.queued.mix_addr&0xFFFFFF00)|val; break;
case 0x7FA5: acl.queued.mix_addr=(acl.queued.mix_addr&0xFFFF00FF)|(val<<8); break;
case 0x7FA6: acl.queued.mix_addr=(acl.queued.mix_addr&0xFF00FFFF)|(val<<16); break;
case 0x7FA7: acl.queued.mix_addr=(acl.queued.mix_addr&0x00FFFFFF)|(val<<24); break;
case 0x7FA8: acl.queued.mix_off =(acl.queued.mix_off &0xFF00)|val; break;
case 0x7FA9: acl.queued.mix_off =(acl.queued.mix_off &0x00FF)|(val<<8); break;
case 0x7FAA: acl.queued.error =(acl.queued.error &0xFF00)|val; break;
case 0x7FAB: acl.queued.error =(acl.queued.error &0x00FF)|(val<<8); break;
case 0x7FAC: acl.queued.dmin =(acl.queued.dmin &0xFF00)|val; break;
case 0x7FAD: acl.queued.dmin =(acl.queued.dmin &0x00FF)|(val<<8); break;
case 0x7FAE: acl.queued.dmaj =(acl.queued.dmaj &0xFF00)|val; break;
case 0x7FAF: acl.queued.dmaj =(acl.queued.dmaj &0x00FF)|(val<<8); break;
}
break;
}
}
uint8_t et4000w32p_mmu_read(uint32_t addr)
{
int bank;
uint8_t temp;
// pclog("ET4K read %08X %04X(%08X):%08X\n",addr,CS,cs,pc);
switch (addr&0x6000)
{
case 0x0000: /*MMU 0*/
case 0x2000: /*MMU 1*/
case 0x4000: /*MMU 2*/
bank=(addr>>13)&3;
if (mmu.ctrl&(1<<bank))
{
temp=0xFF;
if (acl.cpu_dat_pos)
{
acl.cpu_dat_pos--;
temp=acl.cpu_dat&0xFF;
acl.cpu_dat>>=8;
}
if ((acl.queued.ctrl_routing&0x40) && !acl.cpu_dat_pos && !(acl.internal.ctrl_routing&3))
et4000w32_blit(4, ~0, 0, 0);
/*???*/
return temp;
}
return vram[(addr&0x1FFF)+mmu.base[bank]];
case 0x6000:
switch (addr&0x7FFF)
{
case 0x7F00: return mmu.base[0];
case 0x7F01: return mmu.base[0]>>8;
case 0x7F02: return mmu.base[0]>>16;
case 0x7F03: return mmu.base[0]>>24;
case 0x7F04: return mmu.base[1];
case 0x7F05: return mmu.base[1]>>8;
case 0x7F06: return mmu.base[1]>>16;
case 0x7F07: return mmu.base[1]>>24;
case 0x7F08: return mmu.base[2];
case 0x7F09: return mmu.base[2]>>8;
case 0x7F0A: return mmu.base[2]>>16;
case 0x7F0B: return mmu.base[2]>>24;
case 0x7F13: return mmu.ctrl;
case 0x7F36:
// pclog("Read ACL status %02X\n",acl.status);
// if (acl.internal.pos_x!=acl.internal.count_x || acl.internal.pos_y!=acl.internal.count_y) return acl.status | ACL_XYST;
return acl.status;
case 0x7F80: return acl.internal.pattern_addr;
case 0x7F81: return acl.internal.pattern_addr>>8;
case 0x7F82: return acl.internal.pattern_addr>>16;
case 0x7F83: return acl.internal.pattern_addr>>24;
case 0x7F84: return acl.internal.source_addr;
case 0x7F85: return acl.internal.source_addr>>8;
case 0x7F86: return acl.internal.source_addr>>16;
case 0x7F87: return acl.internal.source_addr>>24;
case 0x7F88: return acl.internal.pattern_off;
case 0x7F89: return acl.internal.pattern_off>>8;
case 0x7F8A: return acl.internal.source_off;
case 0x7F8B: return acl.internal.source_off>>8;
case 0x7F8C: return acl.internal.dest_off;
case 0x7F8D: return acl.internal.dest_off>>8;
case 0x7F8E: return acl.internal.pixel_depth;
case 0x7F8F: return acl.internal.xy_dir;
case 0x7F90: return acl.internal.pattern_wrap;
case 0x7F92: return acl.internal.source_wrap;
case 0x7F98: return acl.internal.count_x;
case 0x7F99: return acl.internal.count_x>>8;
case 0x7F9A: return acl.internal.count_y;
case 0x7F9B: return acl.internal.count_y>>8;
case 0x7F9C: return acl.internal.ctrl_routing;
case 0x7F9D: return acl.internal.ctrl_reload;
case 0x7F9E: return acl.internal.rop_bg;
case 0x7F9F: return acl.internal.rop_fg;
case 0x7FA0: return acl.internal.dest_addr;
case 0x7FA1: return acl.internal.dest_addr>>8;
case 0x7FA2: return acl.internal.dest_addr>>16;
case 0x7FA3: return acl.internal.dest_addr>>24;
}
return 0xFF;
}
}
int et4000w32_max_x[8]={0,0,4,8,16,32,64,0x70000000};
int et4000w32_wrap_x[8]={0,0,3,7,15,31,63,0xFFFFFFFF};
int et4000w32_wrap_y[8]={1,2,4,8,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF};
int bltout=0;
void et4000w32_blit_start()
{
// if (acl.queued.xy_dir&0x80)
// pclog("Blit - %02X %08X (%i,%i) %08X (%i,%i) %08X (%i,%i) %i %i %i %02X %02X %02X\n",acl.queued.xy_dir,acl.internal.pattern_addr,(acl.internal.pattern_addr/3)%640,(acl.internal.pattern_addr/3)/640,acl.internal.source_addr,(acl.internal.source_addr/3)%640,(acl.internal.source_addr/3)/640,acl.internal.dest_addr,(acl.internal.dest_addr/3)%640,(acl.internal.dest_addr/3)/640,acl.internal.xy_dir,acl.internal.count_x,acl.internal.count_y,acl.internal.rop_fg,acl.internal.rop_bg, acl.internal.ctrl_routing);
// bltout=1;
// bltout=(acl.internal.count_x==1541);
if (!(acl.queued.xy_dir&0x20))
acl.internal.error = acl.internal.dmaj/2;
acl.pattern_addr=acl.internal.pattern_addr;
acl.source_addr =acl.internal.source_addr;
acl.mix_addr =acl.internal.mix_addr;
acl.mix_back =acl.mix_addr;
acl.dest_addr =acl.internal.dest_addr;
acl.dest_back =acl.dest_addr;
acl.internal.pos_x=acl.internal.pos_y=0;
acl.pattern_x=acl.source_x=acl.pattern_y=acl.source_y=0;
acl.status = ACL_XYST;
if ((!(acl.internal.ctrl_routing&7) || (acl.internal.ctrl_routing&4)) && !(acl.internal.ctrl_routing&0x40)) acl.status |= ACL_SSO;
if (et4000w32_wrap_x[acl.internal.pattern_wrap&7])
{
acl.pattern_x=acl.pattern_addr&et4000w32_wrap_x[acl.internal.pattern_wrap&7];
acl.pattern_addr&=~et4000w32_wrap_x[acl.internal.pattern_wrap&7];
}
acl.pattern_back=acl.pattern_addr;
if (!(acl.internal.pattern_wrap&0x40))
{
acl.pattern_y=(acl.pattern_addr/(et4000w32_wrap_x[acl.internal.pattern_wrap&7]+1))&(et4000w32_wrap_y[(acl.internal.pattern_wrap>>4)&7]-1);
acl.pattern_back&=~(((et4000w32_wrap_x[acl.internal.pattern_wrap&7]+1)*et4000w32_wrap_y[(acl.internal.pattern_wrap>>4)&7])-1);
}
acl.pattern_x_back=acl.pattern_x;
if (et4000w32_wrap_x[acl.internal.source_wrap&7])
{
acl.source_x=acl.source_addr&et4000w32_wrap_x[acl.internal.source_wrap&7];
acl.source_addr&=~et4000w32_wrap_x[acl.internal.source_wrap&7];
}
acl.source_back=acl.source_addr;
if (!(acl.internal.source_wrap&0x40))
{
acl.source_y=(acl.source_addr/(et4000w32_wrap_x[acl.internal.source_wrap&7]+1))&(et4000w32_wrap_y[(acl.internal.source_wrap>>4)&7]-1);
acl.source_back&=~(((et4000w32_wrap_x[acl.internal.source_wrap&7]+1)*et4000w32_wrap_y[(acl.internal.source_wrap>>4)&7])-1);
}
acl.source_x_back=acl.source_x;
et4000w32_max_x[2]=((acl.internal.pixel_depth&0x30)==0x20)?3:4;
acl.internal.count_x += (acl.internal.pixel_depth>>4)&3;
acl.cpu_dat_pos=0;
acl.cpu_dat=0;
acl.pix_pos=0;
}
void et4000w32_incx(int c)
{
acl.dest_addr+=c;
acl.pattern_x+=c;
acl.source_x +=c;
acl.mix_addr +=c;
if (acl.pattern_x>=et4000w32_max_x[acl.internal.pattern_wrap&7])
acl.pattern_x -=et4000w32_max_x[acl.internal.pattern_wrap&7];
if (acl.source_x >=et4000w32_max_x[acl.internal.source_wrap &7])
acl.source_x -=et4000w32_max_x[acl.internal.source_wrap &7];
}
void et4000w32_decx(int c)
{
acl.dest_addr-=c;
acl.pattern_x-=c;
acl.source_x -=c;
acl.mix_addr -=c;
if (acl.pattern_x<0)
acl.pattern_x +=et4000w32_max_x[acl.internal.pattern_wrap&7];
if (acl.source_x <0)
acl.source_x +=et4000w32_max_x[acl.internal.source_wrap &7];
}
void et4000w32_incy()
{
acl.pattern_addr+=acl.internal.pattern_off+1;
acl.source_addr +=acl.internal.source_off +1;
acl.mix_addr +=acl.internal.mix_off +1;
acl.dest_addr +=acl.internal.dest_off +1;
acl.pattern_y++;
if (acl.pattern_y == et4000w32_wrap_y[(acl.internal.pattern_wrap>>4)&7])
{
acl.pattern_y = 0;
acl.pattern_addr = acl.pattern_back;
}
acl.source_y++;
if (acl.source_y == et4000w32_wrap_y[(acl.internal.source_wrap >>4)&7])
{
acl.source_y = 0;
acl.source_addr = acl.source_back;
}
}
void et4000w32_decy()
{
acl.pattern_addr-=acl.internal.pattern_off+1;
acl.source_addr -=acl.internal.source_off +1;
acl.mix_addr -=acl.internal.mix_off +1;
acl.dest_addr -=acl.internal.dest_off +1;
acl.pattern_y--;
if (acl.pattern_y<0 && !(acl.internal.pattern_wrap&0x40))
{
acl.pattern_y=et4000w32_wrap_y[(acl.internal.pattern_wrap>>4)&7]-1;
acl.pattern_addr=acl.pattern_back+(et4000w32_wrap_x[acl.internal.pattern_wrap&7]*(et4000w32_wrap_y[(acl.internal.pattern_wrap>>4)&7]-1));
}
acl.source_y--;
if (acl.source_y<0 && !(acl.internal.source_wrap&0x40))
{
acl.source_y =et4000w32_wrap_y[(acl.internal.source_wrap >>4)&7]-1;
acl.source_addr =acl.source_back +(et4000w32_wrap_x[acl.internal.source_wrap&7] *(et4000w32_wrap_y[(acl.internal.source_wrap>>4)&7]-1));;
}
}
void et4000w32_blit(int count, uint32_t mix, uint32_t sdat, int cpu_input)
{
int c,d;
uint8_t pattern,source,dest,out;
uint8_t rop;
int mixdat;
if (!(acl.status & ACL_XYST)) return;
// if (count>400) pclog("New blit - %i,%i %06X (%i,%i) %06X %06X\n",acl.internal.count_x,acl.internal.count_y,acl.dest_addr,acl.dest_addr%640,acl.dest_addr/640,acl.source_addr,acl.pattern_addr);
//pclog("Blit exec - %i %i %i\n",count,acl.internal.pos_x,acl.internal.pos_y);
if (acl.internal.xy_dir&0x80) /*Line draw*/
{
while (count--)
{
if (bltout) pclog("%i,%i : ",acl.internal.pos_x,acl.internal.pos_y);
pattern=vram[(acl.pattern_addr+acl.pattern_x)&0x1FFFFF];
source =vram[(acl.source_addr +acl.source_x) &0x1FFFFF];
if (bltout) pclog("%06X %06X ",(acl.pattern_addr+acl.pattern_x)&0x1FFFFF,(acl.source_addr +acl.source_x) &0x1FFFFF);
if (cpu_input==2)
{
source=sdat&0xFF;
sdat>>=8;
}
dest=vram[acl.dest_addr &0x1FFFFF];
out=0;
if (bltout) pclog("%06X ",acl.dest_addr);
if ((acl.internal.ctrl_routing&0xA)==8)
{
mixdat = vram[(acl.mix_addr>>3)&0x1FFFFF] & (1<<(acl.mix_addr&7));
if (bltout) pclog("%06X %02X ",acl.mix_addr,vram[(acl.mix_addr>>3)&0x1FFFFF]);
}
else
{
mixdat = mix & 1;
mix>>=1; mix|=0x80000000;
}
acl.mix_addr++;
rop = (mixdat) ? acl.internal.rop_fg:acl.internal.rop_bg;
for (c=0;c<8;c++)
{
d=(dest & (1<<c)) ? 1:0;
if (source & (1<<c)) d|=2;
if (pattern & (1<<c)) d|=4;
if (rop & (1<<d)) out|=(1<<c);
}
if (bltout) pclog("%06X = %02X\n",acl.dest_addr&0x1FFFFF,out);
if (!(acl.internal.ctrl_routing&0x40))
{
vram[acl.dest_addr&0x1FFFFF]=out;
changedvram[(acl.dest_addr&0x1FFFFF)>>10]=changeframecount;
}
else
{
acl.cpu_dat|=((uint64_t)out<<(acl.cpu_dat_pos*8));
acl.cpu_dat_pos++;
}
// pclog("%i %i\n",acl.pix_pos,(acl.internal.pixel_depth>>4)&3);
acl.pix_pos++;
acl.internal.pos_x++;
if (acl.pix_pos<=((acl.internal.pixel_depth>>4)&3))
{
if (acl.internal.xy_dir&1) et4000w32_decx(1);
else et4000w32_incx(1);
}
else
{
if (acl.internal.xy_dir&1) et4000w32_incx((acl.internal.pixel_depth>>4)&3);
else et4000w32_decx((acl.internal.pixel_depth>>4)&3);
acl.pix_pos=0;
/*Next pixel*/
switch (acl.internal.xy_dir&7)
{
case 0: case 1: /*Y+*/
et4000w32_incy();
acl.internal.pos_y++;
acl.internal.pos_x-=((acl.internal.pixel_depth>>4)&3)+1;
break;
case 2: case 3: /*Y-*/
et4000w32_decy();
acl.internal.pos_y++;
acl.internal.pos_x-=((acl.internal.pixel_depth>>4)&3)+1;
break;
case 4: case 6: /*X+*/
et4000w32_incx(((acl.internal.pixel_depth>>4)&3)+1);
//acl.internal.pos_x++;
break;
case 5: case 7: /*X-*/
et4000w32_decx(((acl.internal.pixel_depth>>4)&3)+1);
//acl.internal.pos_x++;
break;
}
acl.internal.error+=acl.internal.dmin;
if (acl.internal.error > acl.internal.dmaj)
{
acl.internal.error-=acl.internal.dmaj;
switch (acl.internal.xy_dir&7)
{
case 0: case 2: /*X+*/
et4000w32_incx(((acl.internal.pixel_depth>>4)&3)+1);
acl.internal.pos_x++;
break;
case 1: case 3: /*X-*/
et4000w32_decx(((acl.internal.pixel_depth>>4)&3)+1);
acl.internal.pos_x++;
break;
case 4: case 5: /*Y+*/
et4000w32_incy();
acl.internal.pos_y++;
break;
case 6: case 7: /*Y-*/
et4000w32_decy();
acl.internal.pos_y++;
break;
}
}
if (acl.internal.pos_x > acl.internal.count_x ||
acl.internal.pos_y > acl.internal.count_y)
{
acl.status = 0;
// pclog("Blit line over\n");
return;
}
}
}
}
else
{
while (count--)
{
if (bltout) pclog("%i,%i : ",acl.internal.pos_x,acl.internal.pos_y);
pattern=vram[(acl.pattern_addr+acl.pattern_x)&0x1FFFFF];
source =vram[(acl.source_addr +acl.source_x) &0x1FFFFF];
if (bltout) pclog("%i %06X %06X %02X %02X ",acl.pattern_y,(acl.pattern_addr+acl.pattern_x)&0x1FFFFF,(acl.source_addr +acl.source_x) &0x1FFFFF,pattern,source);
if (cpu_input==2)
{
source=sdat&0xFF;
sdat>>=8;
}
dest=vram[acl.dest_addr &0x1FFFFF];
out=0;
if (bltout) pclog("%06X %02X %i %08X %08X ",dest,acl.dest_addr,mix&1,mix,acl.mix_addr);
if ((acl.internal.ctrl_routing&0xA)==8)
{
mixdat = vram[(acl.mix_addr>>3)&0x1FFFFF] & (1<<(acl.mix_addr&7));
if (bltout) pclog("%06X %02X ",acl.mix_addr,vram[(acl.mix_addr>>3)&0x1FFFFF]);
}
else
{
mixdat = mix & 1;
mix>>=1; mix|=0x80000000;
}
rop = (mixdat) ? acl.internal.rop_fg:acl.internal.rop_bg;
for (c=0;c<8;c++)
{
d=(dest & (1<<c)) ? 1:0;
if (source & (1<<c)) d|=2;
if (pattern & (1<<c)) d|=4;
if (rop & (1<<d)) out|=(1<<c);
}
if (bltout) pclog("%06X = %02X\n",acl.dest_addr&0x1FFFFF,out);
if (!(acl.internal.ctrl_routing&0x40))
{
vram[acl.dest_addr&0x1FFFFF]=out;
changedvram[(acl.dest_addr&0x1FFFFF)>>10]=changeframecount;
}
else
{
acl.cpu_dat|=((uint64_t)out<<(acl.cpu_dat_pos*8));
acl.cpu_dat_pos++;
}
if (acl.internal.xy_dir&1) et4000w32_decx(1);
else et4000w32_incx(1);
acl.internal.pos_x++;
if (acl.internal.pos_x>acl.internal.count_x)
{
if (acl.internal.xy_dir&2)
{
et4000w32_decy();
acl.mix_back =acl.mix_addr =acl.mix_back -(acl.internal.mix_off +1);
acl.dest_back=acl.dest_addr=acl.dest_back-(acl.internal.dest_off+1);
}
else
{
et4000w32_incy();
acl.mix_back =acl.mix_addr =acl.mix_back +acl.internal.mix_off +1;
acl.dest_back=acl.dest_addr=acl.dest_back+acl.internal.dest_off+1;
}
acl.pattern_x = acl.pattern_x_back;
acl.source_x = acl.source_x_back;
acl.internal.pos_y++;
acl.internal.pos_x=0;
if (acl.internal.pos_y>acl.internal.count_y)
{
acl.status = 0;
// pclog("Blit over\n");
return;
}
if (cpu_input) return;
if (acl.internal.ctrl_routing&0x40)
{
if (acl.cpu_dat_pos&3) acl.cpu_dat_pos+=4-(acl.cpu_dat_pos&3);
return;
}
}
}
}
}
void et4000w32p_cursor_draw(int displine)
{
int x, offset;
uint8_t dat;
offset = svga_hwcursor_latch.xoff;
for (x = 0; x < 64 - svga_hwcursor_latch.xoff; x += 4)
{
dat = vram[svga_hwcursor_latch.addr + (offset >> 2)];
if (!(dat & 2)) ((uint32_t *)buffer32->line[displine])[svga_hwcursor_latch.x + x + 32] = (dat & 1) ? 0xFFFFFF : 0;
else if ((dat & 3) == 3) ((uint32_t *)buffer32->line[displine])[svga_hwcursor_latch.x + x + 32] ^= 0xFFFFFF;
dat >>= 2;
if (!(dat & 2)) ((uint32_t *)buffer32->line[displine])[svga_hwcursor_latch.x + x + 33] = (dat & 1) ? 0xFFFFFF : 0;
else if ((dat & 3) == 3) ((uint32_t *)buffer32->line[displine])[svga_hwcursor_latch.x + x + 33] ^= 0xFFFFFF;
dat >>= 2;
if (!(dat & 2)) ((uint32_t *)buffer32->line[displine])[svga_hwcursor_latch.x + x + 34] = (dat & 1) ? 0xFFFFFF : 0;
else if ((dat & 3) == 3) ((uint32_t *)buffer32->line[displine])[svga_hwcursor_latch.x + x + 34] ^= 0xFFFFFF;
dat >>= 2;
if (!(dat & 2)) ((uint32_t *)buffer32->line[displine])[svga_hwcursor_latch.x + x + 35] = (dat & 1) ? 0xFFFFFF : 0;
else if ((dat & 3) == 3) ((uint32_t *)buffer32->line[displine])[svga_hwcursor_latch.x + x + 35] ^= 0xFFFFFF;
dat >>= 2;
offset += 4;
}
svga_hwcursor_latch.addr += 16;
}
uint8_t et4000w32p_pci_read(int func, int addr)
{
pclog("ET4000 PCI read %08X\n", addr);
switch (addr)
{
case 0x00: return 0x0c; /*Tseng Labs*/
case 0x01: return 0x10;
case 0x02: return 0x06; /*ET4000W32p Rev D*/
case 0x03: return 0x32;
case 0x04: return 0x03; /*Respond to IO and memory accesses*/
case 0x07: return 1 << 1; /*Medium DEVSEL timing*/
case 0x08: return 0; /*Revision ID*/
case 0x09: return 0; /*Programming interface*/
case 0x0a: return 0x01; /*Supports VGA interface, XGA compatible*/
case 0x0b: return 0x03;
case 0x10: return 0x00; /*Linear frame buffer address*/
case 0x11: return 0x00;
case 0x12: return crtc[0x5a] & 0x80;
case 0x13: return crtc[0x59];
case 0x30: return 0x01; /*BIOS ROM address*/
case 0x31: return 0x00;
case 0x32: return 0x0C;
case 0x33: return 0x00;
}
return 0;
}
void et4000w32p_pci_write(int func, int addr, uint8_t val)
{
switch (addr)
{
case 0x13: et4000w32p_linearbase = val << 24; et4000w32p_recalcmapping(); break;
}
}
int et4000w32p_init()
{
svga_recalctimings_ex = et4000w32p_recalctimings;
svga_hwcursor_draw = et4000w32p_cursor_draw;
io_sethandler(0x210A, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL);
io_sethandler(0x211A, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL);
io_sethandler(0x212A, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL);
io_sethandler(0x213A, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL);
io_sethandler(0x214A, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL);
io_sethandler(0x215A, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL);
io_sethandler(0x216A, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL);
io_sethandler(0x217A, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL);
pci_add(et4000w32p_pci_read, et4000w32p_pci_write);
svga_vram_limit = 2 << 20; /*2mb - chip supports 4mb but can't map both 4mb linear frame buffer and accelerator registers*/
vrammask = 0x1fffff;
return svga_init();
}
GFXCARD vid_et4000w32p =
{
et4000w32p_init,
/*IO at 3Cx/3Dx*/
et4000w32p_out,
et4000w32p_in,
/*IO at 3Ax/3Bx*/
video_out_null,
video_in_null,
svga_poll,
svga_recalctimings,
svga_write,
video_write_null,
video_write_null,
svga_read,
video_read_null,
video_read_null
};

407
src/vid_et4000w32i.c Normal file
View file

@ -0,0 +1,407 @@
/*The below is (with some removals) a reasonable emulation of the ET4000/W32i blitter.
Unfortunately the Diamond Stealth 32 is actually an ET4000/W32p! Which has a different
blitter. If only I'd dug out and looked at the card before trying to emulate it.
This might be of use for an attempt at emulating an ET4000/W32i.
*/
#if 0
#include "ibm.h"
int et4k_b8000;
struct
{
struct
{
uint32_t pattern_addr,source_addr,dest_addr;
uint16_t pattern_off,source_off,dest_off;
uint8_t vbus,xy_dir;
uint8_t pattern_wrap,source_wrap;
uint16_t count_x,count_y;
uint8_t ctrl_routing,ctrl_reload;
uint8_t rop_fg,rop_bg;
uint16_t pos_x,pos_y;
} queued,internal;
uint32_t pattern_addr,source_addr,dest_addr;
uint32_t pattern_back,dest_back;
int pattern_x,source_x;
int pattern_x_back;
int pattern_y,source_y;
uint8_t status;
uint32_t cpu_input;
int cpu_input_num;
} acl;
#define ACL_WRST 1
#define ACL_RDST 2
#define ACL_XYST 4
#define ACL_SSO 8
struct
{
uint32_t base[3];
uint8_t ctrl;
} mmu;
void et4000w32_reset()
{
acl.status=0;
acl.cpu_input_num=0;
}
void et4000w32_blit_start();
void et4000w32_blit(int count, uint32_t mix, uint32_t sdat, int cpu_input);
int et4000w32_vbus[4]={1,2,4,4};
void et4000w32_mmu_write(uint32_t addr, uint8_t val)
{
int bank;
pclog("ET4K write %08X %02X %i %02X %02X %04X(%08X):%08X %04X %04X %02X %08X\n",addr,val,acl.cpu_input_num,acl.status,acl.internal.ctrl_routing,CS,cs,pc,CS,DI,mmu.ctrl,mmu.base[2]);
switch (addr&0x6000)
{
case 0x0000: /*MMU 0*/
case 0x2000: /*MMU 1*/
case 0x4000: /*MMU 2*/
bank=(addr>>13)&3;
if (mmu.ctrl&(1<<bank))
{
if (!(acl.status&ACL_XYST))
{
// pclog("!ACL_XYST\n");
/*if ((acl.internal.ctrl_routing&0x30)==0x10) */acl.queued.dest_addr=(addr&0x1FFF)+mmu.base[bank];
acl.internal=acl.queued;
et4000w32_blit_start();
if (!(acl.internal.ctrl_routing&0x37)) et4000w32_blit(0xFFFFFF, ~0, 0, 0);
acl.cpu_input_num=0;
}
// else if (!(acl.internal.ctrl_routing&7)) pclog("ACL_XYST\n");
if (acl.internal.ctrl_routing&7)
{
acl.cpu_input=(acl.cpu_input&~(0xFF<<(acl.cpu_input_num*8)))|(val<<(acl.cpu_input_num*8));
acl.cpu_input_num++;
if (acl.cpu_input_num == et4000w32_vbus[acl.internal.vbus & 3])
{
if ((acl.internal.ctrl_routing&7)==2)
et4000w32_blit(acl.cpu_input_num << 3, acl.cpu_input, 0, 1);
else if ((acl.internal.ctrl_routing&7)==1)
et4000w32_blit(acl.cpu_input_num, ~0, acl.cpu_input, 2);
else
pclog("Bad ET4K routing %i\n",acl.internal.ctrl_routing&7);
acl.cpu_input_num=0;
}
}
// else
// pclog("Not ctrl_routing\n");
}
else
{
vram[(addr&0x1FFF)+mmu.base[bank]]=val;
changedvram[((addr&0x1FFF)+mmu.base[bank])>>10]=changeframecount;
}
break;
case 0x6000:
switch (addr&0x7FFF)
{
case 0x7F00: mmu.base[0]=(mmu.base[0]&0xFFFFFF00)|val; break;
case 0x7F01: mmu.base[0]=(mmu.base[0]&0xFFFF00FF)|(val<<8); break;
case 0x7F02: mmu.base[0]=(mmu.base[0]&0xFF00FFFF)|(val<<16); break;
case 0x7F03: mmu.base[0]=(mmu.base[0]&0x00FFFFFF)|(val<<24); break;
case 0x7F04: mmu.base[1]=(mmu.base[1]&0xFFFFFF00)|val; break;
case 0x7F05: mmu.base[1]=(mmu.base[1]&0xFFFF00FF)|(val<<8); break;
case 0x7F06: mmu.base[1]=(mmu.base[1]&0xFF00FFFF)|(val<<16); break;
case 0x7F07: mmu.base[1]=(mmu.base[1]&0x00FFFFFF)|(val<<24); break;
case 0x7F08: mmu.base[2]=(mmu.base[2]&0xFFFFFF00)|val; break;
case 0x7F09: mmu.base[2]=(mmu.base[2]&0xFFFF00FF)|(val<<8); break;
case 0x7F0A: mmu.base[2]=(mmu.base[2]&0xFF00FFFF)|(val<<16); break;
case 0x7F0B: mmu.base[2]=(mmu.base[2]&0x00FFFFFF)|(val<<24); break;
case 0x7F13: mmu.ctrl=val; break;
case 0x7F80: acl.queued.pattern_addr=(acl.queued.pattern_addr&0xFFFFFF00)|val; break;
case 0x7F81: acl.queued.pattern_addr=(acl.queued.pattern_addr&0xFFFF00FF)|(val<<8); break;
case 0x7F82: acl.queued.pattern_addr=(acl.queued.pattern_addr&0xFF00FFFF)|(val<<16); break;
case 0x7F83: acl.queued.pattern_addr=(acl.queued.pattern_addr&0x00FFFFFF)|(val<<24); break;
case 0x7F84: acl.queued.source_addr =(acl.queued.source_addr &0xFFFFFF00)|val; break;
case 0x7F85: acl.queued.source_addr =(acl.queued.source_addr &0xFFFF00FF)|(val<<8); break;
case 0x7F86: acl.queued.source_addr =(acl.queued.source_addr &0xFF00FFFF)|(val<<16); break;
case 0x7F87: acl.queued.source_addr =(acl.queued.source_addr &0x00FFFFFF)|(val<<24); break;
case 0x7F88: acl.queued.pattern_off=(acl.queued.pattern_off&0xFF00)|val; break;
case 0x7F89: acl.queued.pattern_off=(acl.queued.pattern_off&0x00FF)|(val<<8); break;
case 0x7F8A: acl.queued.source_off =(acl.queued.source_off &0xFF00)|val; break;
case 0x7F8B: acl.queued.source_off =(acl.queued.source_off &0x00FF)|(val<<8); break;
case 0x7F8C: acl.queued.dest_off =(acl.queued.dest_off &0xFF00)|val; break;
case 0x7F8D: acl.queued.dest_off =(acl.queued.dest_off &0x00FF)|(val<<8); break;
case 0x7F8E: acl.queued.vbus=val; break;
case 0x7F8F: acl.queued.xy_dir=val; break;
case 0x7F90: acl.queued.pattern_wrap=val; break;
case 0x7F92: acl.queued.source_wrap=val; break;
case 0x7F98: acl.queued.count_x =(acl.queued.count_x &0xFF00)|val; break;
case 0x7F99: acl.queued.count_x =(acl.queued.count_x &0x00FF)|(val<<8); break;
case 0x7F9A: acl.queued.count_y =(acl.queued.count_y &0xFF00)|val; break;
case 0x7F9B: acl.queued.count_y =(acl.queued.count_y &0x00FF)|(val<<8); break;
case 0x7F9C: acl.queued.ctrl_routing=val; break;
case 0x7F9D: acl.queued.ctrl_reload =val; break;
case 0x7F9E: acl.queued.rop_bg =val; break;
case 0x7F9F: acl.queued.rop_fg =val; break;
case 0x7FA0: acl.queued.dest_addr =(acl.queued.dest_addr &0xFFFFFF00)|val; break;
case 0x7FA1: acl.queued.dest_addr =(acl.queued.dest_addr &0xFFFF00FF)|(val<<8); break;
case 0x7FA2: acl.queued.dest_addr =(acl.queued.dest_addr &0xFF00FFFF)|(val<<16); break;
case 0x7FA3: acl.queued.dest_addr =(acl.queued.dest_addr &0x00FFFFFF)|(val<<24);
acl.internal=acl.queued;
et4000w32_blit_start();
acl.cpu_input_num=0;
if (!(acl.queued.ctrl_routing&0x37))
{
et4000w32_blit(0xFFFFFF, ~0, 0, 0);
}
break;
}
break;
}
}
uint8_t et4000w32_mmu_read(uint32_t addr)
{
int bank;
pclog("ET4K read %08X %04X(%08X):%08X\n",addr,CS,cs,pc);
switch (addr&0x6000)
{
case 0x0000: /*MMU 0*/
case 0x2000: /*MMU 1*/
case 0x4000: /*MMU 2*/
bank=(addr>>13)&3;
if (mmu.ctrl&(1<<bank))
{
/*???*/
return 0xFF;
}
return vram[(addr&0x1FFF)+mmu.base[bank]];
case 0x6000:
switch (addr&0x7FFF)
{
case 0x7F00: return mmu.base[0];
case 0x7F01: return mmu.base[0]>>8;
case 0x7F02: return mmu.base[0]>>16;
case 0x7F03: return mmu.base[0]>>24;
case 0x7F04: return mmu.base[1];
case 0x7F05: return mmu.base[1]>>8;
case 0x7F06: return mmu.base[1]>>16;
case 0x7F07: return mmu.base[1]>>24;
case 0x7F08: return mmu.base[2];
case 0x7F09: return mmu.base[2]>>8;
case 0x7F0A: return mmu.base[2]>>16;
case 0x7F0B: return mmu.base[2]>>24;
case 0x7F13: return mmu.ctrl;
case 0x7F36:
// if (acl.internal.pos_x!=acl.internal.count_x || acl.internal.pos_y!=acl.internal.count_y) return acl.status | ACL_XYST;
return acl.status & ~(ACL_XYST | ACL_SSO);
case 0x7F80: return acl.internal.pattern_addr;
case 0x7F81: return acl.internal.pattern_addr>>8;
case 0x7F82: return acl.internal.pattern_addr>>16;
case 0x7F83: return acl.internal.pattern_addr>>24;
case 0x7F84: return acl.internal.source_addr;
case 0x7F85: return acl.internal.source_addr>>8;
case 0x7F86: return acl.internal.source_addr>>16;
case 0x7F87: return acl.internal.source_addr>>24;
case 0x7F88: return acl.internal.pattern_off;
case 0x7F89: return acl.internal.pattern_off>>8;
case 0x7F8A: return acl.internal.source_off;
case 0x7F8B: return acl.internal.source_off>>8;
case 0x7F8C: return acl.internal.dest_off;
case 0x7F8D: return acl.internal.dest_off>>8;
case 0x7F8E: return acl.internal.vbus;
case 0x7F8F: return acl.internal.xy_dir;
case 0x7F90: return acl.internal.pattern_wrap;
case 0x7F92: return acl.internal.source_wrap;
case 0x7F98: return acl.internal.count_x;
case 0x7F99: return acl.internal.count_x>>8;
case 0x7F9A: return acl.internal.count_y;
case 0x7F9B: return acl.internal.count_y>>8;
case 0x7F9C: return acl.internal.ctrl_routing;
case 0x7F9D: return acl.internal.ctrl_reload;
case 0x7F9E: return acl.internal.rop_bg;
case 0x7F9F: return acl.internal.rop_fg;
case 0x7FA0: return acl.internal.dest_addr;
case 0x7FA1: return acl.internal.dest_addr>>8;
case 0x7FA2: return acl.internal.dest_addr>>16;
case 0x7FA3: return acl.internal.dest_addr>>24;
}
return 0xFF;
}
}
int et4000w32_wrap_x[8]={0,0,3,7,15,31,63,0xFFFFFFFF};
int et4000w32_wrap_y[8]={1,2,4,8,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF};
void et4000w32_blit_start()
{
pclog("Blit - %08X %08X %08X (%i,%i) %i %i %i %02X %02X %02X\n",acl.internal.pattern_addr,acl.internal.source_addr,acl.internal.dest_addr,acl.internal.dest_addr%640,acl.internal.dest_addr/640,acl.internal.xy_dir,acl.internal.count_x,acl.internal.count_y,acl.internal.rop_fg,acl.internal.rop_bg, acl.internal.ctrl_routing);
acl.pattern_addr=acl.internal.pattern_addr;
acl.source_addr =acl.internal.source_addr;
acl.dest_addr =acl.internal.dest_addr;
acl.dest_back =acl.dest_addr;
acl.internal.pos_x=acl.internal.pos_y=0;
acl.pattern_x=acl.source_x=acl.pattern_y=acl.source_y=0;
acl.status = ACL_XYST;
if (!(acl.internal.ctrl_routing&7) || (acl.internal.ctrl_routing&4)) acl.status |= ACL_SSO;
if (et4000w32_wrap_x[acl.internal.pattern_wrap&7])
{
acl.pattern_x=acl.pattern_addr&et4000w32_wrap_x[acl.internal.pattern_wrap&7];
acl.pattern_addr&=~et4000w32_wrap_x[acl.internal.pattern_wrap&7];
}
if (!(acl.internal.pattern_wrap&0x80))
{
acl.pattern_y=(acl.pattern_addr/(et4000w32_wrap_x[acl.internal.pattern_wrap&7]+1))&(et4000w32_wrap_y[(acl.internal.pattern_wrap>>4)&7]-1);
acl.pattern_addr&=~(((et4000w32_wrap_x[acl.internal.pattern_wrap&7]+1)*et4000w32_wrap_y[(acl.internal.pattern_wrap>>4)&7])-1);
}
acl.pattern_x_back=acl.pattern_x;
acl.pattern_back=acl.pattern_addr;
}
void et4000w32_blit(int count, uint32_t mix, uint32_t sdat, int cpu_input)
{
int c,d;
uint8_t pattern,source,dest,out;
uint8_t rop;
// if (count>400) pclog("New blit - %i,%i %06X (%i,%i) %06X %06X\n",acl.internal.count_x,acl.internal.count_y,acl.dest_addr,acl.dest_addr%640,acl.dest_addr/640,acl.source_addr,acl.pattern_addr);
// pclog("Blit exec - %i %i %i\n",count,acl.internal.pos_x,acl.internal.pos_y);
while (count--)
{
pclog("%i,%i : ",acl.internal.pos_x,acl.internal.pos_y);
if (acl.internal.xy_dir&1)
{
pattern=vram[(acl.pattern_addr-acl.pattern_x)&0x1FFFFF];
source =vram[(acl.source_addr -acl.source_x) &0x1FFFFF];
pclog("%06X %06X ",(acl.pattern_addr-acl.pattern_x)&0x1FFFFF,(acl.source_addr -acl.source_x) &0x1FFFFF);
}
else
{
pattern=vram[(acl.pattern_addr+acl.pattern_x)&0x1FFFFF];
source =vram[(acl.source_addr +acl.source_x) &0x1FFFFF];
pclog("%06X %06X ",(acl.pattern_addr+acl.pattern_x)&0x1FFFFF,(acl.source_addr +acl.source_x) &0x1FFFFF);
}
if (cpu_input==2)
{
source=sdat&0xFF;
sdat>>=8;
}
dest=vram[acl.dest_addr &0x1FFFFF];
out=0;
pclog("%06X %i %08X ",acl.dest_addr,mix&1,mix);
rop = (mix & 1) ? acl.internal.rop_fg:acl.internal.rop_bg;
mix>>=1; mix|=0x80000000;
for (c=0;c<8;c++)
{
d=(dest & (1<<c)) ? 1:0;
if (source & (1<<c)) d|=2;
if (pattern & (1<<c)) d|=4;
if (rop & (1<<d)) out|=(1<<c);
}
pclog("%06X = %02X\n",acl.dest_addr&0x1FFFFF,out);
vram[acl.dest_addr&0x1FFFFF]=out;
changedvram[(acl.dest_addr&0x1FFFFF)>>10]=changeframecount;
acl.pattern_x++;
acl.pattern_x&=et4000w32_wrap_x[acl.internal.pattern_wrap&7];
acl.source_x++;
acl.source_x &=et4000w32_wrap_x[acl.internal.source_wrap&7];
if (acl.internal.xy_dir&1) acl.dest_addr--;
else acl.dest_addr++;
acl.internal.pos_x++;
if (acl.internal.pos_x>acl.internal.count_x)
{
if (acl.internal.xy_dir&2)
{
acl.pattern_addr-=(acl.internal.pattern_off+1);
acl.source_addr -=(acl.internal.source_off +1);
acl.dest_back=acl.dest_addr=acl.dest_back-(acl.internal.dest_off+1);
}
else
{
acl.pattern_addr+=acl.internal.pattern_off+1;
acl.source_addr +=acl.internal.source_off +1;
acl.dest_back=acl.dest_addr=acl.dest_back+acl.internal.dest_off+1;
}
acl.pattern_x = acl.pattern_x_back;
acl.source_x = 0;
acl.pattern_y++;
if (acl.pattern_y==et4000w32_wrap_y[(acl.internal.pattern_wrap>>4)&7])
{
acl.pattern_y=0;
acl.pattern_addr=acl.pattern_back;
}
acl.source_y++;
if (acl.source_y ==et4000w32_wrap_y[(acl.internal.source_wrap >>4)&7])
{
acl.source_y=0;
acl.source_addr=acl.internal.source_addr;
}
acl.internal.pos_y++;
if (acl.internal.pos_y>acl.internal.count_y)
{
acl.status = 0;
return;
}
acl.internal.pos_x=0;
if (cpu_input) return;
}
}
}
/* for (y=0;y<=acl.internal.count_y;y++)
{
dest_back=acl.dest_addr;
for (x=0;x<=acl.internal.count_x;x++)
{
if (acl.internal.xy_dir&1)
{
pattern=vram[(acl.pattern_addr-pattern_x)&0x1FFFFF];
source =vram[(acl.source_addr -source_x) &0x1FFFFF];
}
else
{
pattern=vram[(acl.pattern_addr+pattern_x)&0x1FFFFF];
source =vram[(acl.source_addr +source_x) &0x1FFFFF];
}
dest=vram[acl.dest_addr &0x1FFFFF];
out=0;
for (c=0;c<8;c++)
{
d=(dest&(1<<c))?1:0;
if (source&(1<<c)) d|=2;
if (pattern&(1<<c)) d|=4;
if (acl.internal.rop_bg&(1<<d)) out|=(1<<c);
}
vram[acl.dest_addr&0x1FFFFF]=out;
changedvram[(acl.dest_addr&0x1FFFFF)>>10]=changeframecount;
pattern_x++;
pattern_x&=et4000w32_wrap_x[acl.internal.pattern_wrap&7];
source_x++;
source_x &=et4000w32_wrap_x[acl.internal.source_wrap&7];
if (acl.internal.xy_dir&1) acl.dest_addr--;
else acl.dest_addr++;
}
acl.pattern_addr+=acl.internal.pattern_off+1;
acl.source_addr +=acl.internal.source_off+1;
acl.dest_addr=dest_back+acl.internal.dest_off+1;
pattern_y++;
if (pattern_y==et4000w32_wrap_y[(acl.internal.pattern_wrap>>4)&7])
{
pattern_y=0;
acl.pattern_addr=acl.internal.pattern_addr;
}
source_y++;
if (source_y ==et4000w32_wrap_y[(acl.internal.source_wrap >>4)&7])
{
source_y=0;
acl.source_addr=acl.internal.source_addr;
}
}*/
#endif

Some files were not shown because too many files have changed in this diff Show more