Add v0.7 source
This commit is contained in:
commit
3c253c2cf8
188 changed files with 52566 additions and 0 deletions
43
src/Makefile.mingw
Normal file
43
src/Makefile.mingw
Normal 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
33
src/acer386sx.c
Normal 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
1
src/acer386sx.h
Normal file
|
|
@ -0,0 +1 @@
|
|||
void acer386sx_init();
|
||||
187
src/adlib.c
Normal file
187
src/adlib.c
Normal 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
76
src/ali1429.c
Normal 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
1
src/ali1429.h
Normal file
|
|
@ -0,0 +1 @@
|
|||
void ali1429_init();
|
||||
84
src/amstrad.c
Normal file
84
src/amstrad.c
Normal 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
2
src/amstrad.h
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
void amstrad_init();
|
||||
|
||||
475
src/cdrom-ioctl.c
Normal file
475
src/cdrom-ioctl.c
Normal 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,<oc,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
9
src/cdrom-ioctl.h
Normal 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
141
src/cms.c
Normal 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
166
src/config.c
Normal 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
5
src/config.h
Normal 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
411
src/cpu.c
Normal 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
71
src/cpu.h
Normal 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
68
src/dac.c
Normal 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
490
src/dma.c
Normal 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
3
src/dma.h
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
void dma_init();
|
||||
void dma16_init();
|
||||
void dma_reset();
|
||||
298
src/ega.c
Normal file
298
src/ega.c
Normal 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
806
src/fdc.c
Normal 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
4
src/fdc.h
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
void fdc_init();
|
||||
void fdc_remove();
|
||||
void fdc_reset();
|
||||
void fdc_poll();
|
||||
178
src/filters.h
Normal file
178
src/filters.h
Normal 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
625
src/gus.c
Normal 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
155
src/harddisk.c
Normal 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
45
src/headland.c
Normal 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
1
src/headland.h
Normal file
|
|
@ -0,0 +1 @@
|
|||
void headland_init();
|
||||
468
src/ibm.h
Normal file
468
src/ibm.h
Normal 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;
|
||||
42
src/ide.h
Normal file
42
src/ide.h
Normal 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
196
src/io.c
Normal 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
17
src/io.h
Normal 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
78
src/jim.c
Normal 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
1
src/jim.h
Normal file
|
|
@ -0,0 +1 @@
|
|||
void jim_init();
|
||||
280
src/keyboard.c
Normal file
280
src/keyboard.c
Normal 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
3
src/keyboard.h
Normal 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
168
src/keyboard_amstrad.c
Normal 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
3
src/keyboard_amstrad.h
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
void keyboard_amstrad_init();
|
||||
void keyboard_amstrad_reset();
|
||||
void keyboard_amstrad_poll();
|
||||
436
src/keyboard_at.c
Normal file
436
src/keyboard_at.c
Normal 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
6
src/keyboard_at.h
Normal 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
285
src/keyboard_olim24.c
Normal 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
3
src/keyboard_olim24.h
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
void keyboard_olim24_init();
|
||||
void keyboard_olim24_reset();
|
||||
void keyboard_olim24_poll();
|
||||
163
src/keyboard_xt.c
Normal file
163
src/keyboard_xt.c
Normal 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
3
src/keyboard_xt.h
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
void keyboard_xt_init();
|
||||
void keyboard_xt_reset();
|
||||
void keyboard_xt_poll();
|
||||
66
src/lpt.c
Normal file
66
src/lpt.c
Normal 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
2
src/lpt.h
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
void lpt_init();
|
||||
void lpt2_remove();
|
||||
2613
src/mame/fmopl.c
Normal file
2613
src/mame/fmopl.c
Normal file
File diff suppressed because it is too large
Load diff
126
src/mame/fmopl.h
Normal file
126
src/mame/fmopl.h
Normal 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
2730
src/mame/ymf262.c
Normal file
File diff suppressed because it is too large
Load diff
62
src/mame/ymf262.h
Normal file
62
src/mame/ymf262.h
Normal 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
37
src/mcr.c
Normal 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;
|
||||
}
|
||||
|
||||
40
src/mem.h
Normal file
40
src/mem.h
Normal 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
200
src/model.c
Normal 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
16
src/model.h
Normal 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
4
src/mouse.c
Normal 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
5
src/mouse.h
Normal 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
152
src/mouse_ps2.c
Normal 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
1
src/mouse_ps2.h
Normal file
|
|
@ -0,0 +1 @@
|
|||
void mouse_ps2_init();
|
||||
66
src/mouse_serial.c
Normal file
66
src/mouse_serial.c
Normal 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
1
src/mouse_serial.h
Normal file
|
|
@ -0,0 +1 @@
|
|||
void mouse_serial_init();
|
||||
68
src/neat.c
Normal file
68
src/neat.c
Normal 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
1
src/neat.h
Normal file
|
|
@ -0,0 +1 @@
|
|||
void neat_init();
|
||||
204
src/nvr.c
Normal file
204
src/nvr.c
Normal 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
1
src/nvr.h
Normal file
|
|
@ -0,0 +1 @@
|
|||
void nvr_init();
|
||||
20
src/olivetti_m24.c
Normal file
20
src/olivetti_m24.c
Normal 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
1
src/olivetti_m24.h
Normal file
|
|
@ -0,0 +1 @@
|
|||
void olivetti_m24_init();
|
||||
284
src/opti.c
Normal file
284
src/opti.c
Normal 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
491
src/pc.c
Normal 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
158
src/pc.rc
Normal 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
99
src/pci.c
Normal 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
3
src/pci.h
Normal 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
313
src/pic.c
Normal 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
3
src/pic.h
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
void pic_init();
|
||||
void pic2_init();
|
||||
void pic_reset();
|
||||
305
src/pit.c
Normal file
305
src/pit.c
Normal 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
3
src/pit.h
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
extern double PITCONST;
|
||||
void pit_init();
|
||||
void pit_reset();
|
||||
1
src/plat-dinput.h
Normal file
1
src/plat-dinput.h
Normal file
|
|
@ -0,0 +1 @@
|
|||
extern LPDIRECTINPUT lpdi;
|
||||
15
src/plat-keyboard.h
Normal file
15
src/plat-keyboard.h
Normal 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
13
src/plat-mouse.h
Normal 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
19
src/ppi.c
Normal 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
1
src/ppi.h
Normal file
|
|
@ -0,0 +1 @@
|
|||
extern int wasgated;
|
||||
206
src/psg.c
Normal file
206
src/psg.c
Normal 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
1
src/psg.h
Normal file
|
|
@ -0,0 +1 @@
|
|||
void psg_init();
|
||||
62
src/resources.h
Normal file
62
src/resources.h
Normal 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
1104
src/sblaster.c
Normal file
File diff suppressed because it is too large
Load diff
210
src/serial.c
Normal file
210
src/serial.c
Normal 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
17
src/serial.h
Normal 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
180
src/sound.c
Normal 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
1
src/sound.h
Normal file
|
|
@ -0,0 +1 @@
|
|||
extern int wasgated;
|
||||
143
src/soundopenal.c
Normal file
143
src/soundopenal.c
Normal 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
70
src/um8881f.c
Normal 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
1
src/um8881f.h
Normal file
|
|
@ -0,0 +1 @@
|
|||
void um8881f_init();
|
||||
494
src/vid_cga.c
Normal file
494
src/vid_cga.c
Normal 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
7
src/vid_cga.h
Normal 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
720
src/vid_ega.c
Normal 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
7
src/vid_ega.h
Normal 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
141
src/vid_et4000.c
Normal 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
936
src/vid_et4000w32.c
Normal 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
407
src/vid_et4000w32i.c
Normal 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
Loading…
Reference in a new issue