Added support for Tandy 1000 HX and SL/2. As part of this commit :
- FDC now selects drive number from DOR (0x3f2) - FDC now fails seeks on drives > 1 - XT systems no longer have BIOS mapping at E0000-EFFFF - SN76489 now distinguishes between SN76496 (PCjr and early Tandy 1000), NCR8496 (later Tandy 1000 - different noise handling) and PSSJ - Removed redundant limits on memory configuration - allows selection of 768k for Tandy 1000 SL/2
This commit is contained in:
parent
79202cc5c0
commit
2ca86ba028
24 changed files with 1420 additions and 64 deletions
|
|
@ -10,14 +10,14 @@ OBJ = 386.o 386_dynarec.o 386_dynarec_ops.o 808x.o acer386sx.o ali1429.o amstrad
|
||||||
keyboard_olim24.o keyboard_pcjr.o keyboard_xt.o lpt.o mcr.o mem.o model.o mouse.o mouse_ps2.o \
|
keyboard_olim24.o keyboard_pcjr.o keyboard_xt.o lpt.o mcr.o mem.o model.o mouse.o mouse_ps2.o \
|
||||||
mouse_serial.o neat.o nmi.o nvr.o olivetti_m24.o opti.o pc.o pci.o pic.o piix.o pit.o ppi.o ps1.o rom.o \
|
mouse_serial.o neat.o nmi.o nvr.o olivetti_m24.o opti.o pc.o pci.o pic.o piix.o pit.o ppi.o ps1.o rom.o \
|
||||||
serial.o sis496.o sound.o sound_ad1848.o sound_adlib.o sound_adlibgold.o sound_cms.o sound_dbopl.o \
|
serial.o sis496.o sound.o sound_ad1848.o sound_adlib.o sound_adlibgold.o sound_cms.o sound_dbopl.o \
|
||||||
sound_emu8k.o sound_gus.o sound_mpu401_uart.o sound_opl.o sound_pas16.o sound_resid.o \
|
sound_emu8k.o sound_gus.o sound_mpu401_uart.o sound_opl.o sound_pas16.o sound_pssj.o sound_resid.o \
|
||||||
sound_sb.o sound_sb_dsp.o sound_sn76489.o sound_speaker.o sound_ssi2001.o sound_wss.o \
|
sound_sb.o sound_sb_dsp.o sound_sn76489.o sound_speaker.o sound_ssi2001.o sound_wss.o \
|
||||||
soundopenal.o timer.o um8881f.o um8669f.o vid_ati_eeprom.o vid_ati_mach64.o vid_ati18800.o \
|
soundopenal.o tandy_eeprom.o tandy_rom.o timer.o um8881f.o um8669f.o vid_ati_eeprom.o vid_ati_mach64.o vid_ati18800.o \
|
||||||
vid_ati28800.o vid_ati68860_ramdac.o vid_cga.o vid_cl5429.o vid_ega.o vid_et4000.o \
|
vid_ati28800.o vid_ati68860_ramdac.o vid_cga.o vid_cl5429.o vid_ega.o vid_et4000.o \
|
||||||
vid_et4000w32.o vid_et4000w32i.o vid_hercules.o vid_icd2061.o vid_ics2595.o vid_mda.o \
|
vid_et4000w32.o vid_et4000w32i.o vid_hercules.o vid_icd2061.o vid_ics2595.o vid_mda.o \
|
||||||
vid_olivetti_m24.o vid_oti067.o vid_paradise.o vid_pc1512.o vid_pc1640.o vid_pc200.o \
|
vid_olivetti_m24.o vid_oti067.o vid_paradise.o vid_pc1512.o vid_pc1640.o vid_pc200.o \
|
||||||
vid_pcjr.o vid_s3.o vid_s3_virge.o vid_sdac_ramdac.o vid_stg_ramdac.o vid_svga.o \
|
vid_pcjr.o vid_s3.o vid_s3_virge.o vid_sdac_ramdac.o vid_stg_ramdac.o vid_svga.o \
|
||||||
vid_svga_render.o vid_tandy.o vid_tgui9440.o vid_tkd8001_ramdac.o vid_tvga.o vid_unk_ramdac.o \
|
vid_svga_render.o vid_tandy.o vid_tandysl.o vid_tgui9440.o vid_tkd8001_ramdac.o vid_tvga.o vid_unk_ramdac.o \
|
||||||
vid_vga.o vid_voodoo.o video.o wd76c10.o win.o win-config.o win-d3d.o win-d3d-fs.o win-ddraw.o \
|
vid_vga.o vid_voodoo.o video.o wd76c10.o win.o win-config.o win-d3d.o win-d3d-fs.o win-ddraw.o \
|
||||||
win-ddraw-fs.o win-deviceconfig.o win-hdconf.o win-joystick.o win-keyboard.o win-midi.o win-mouse.o \
|
win-ddraw-fs.o win-deviceconfig.o win-hdconf.o win-joystick.o win-keyboard.o win-midi.o win-mouse.o \
|
||||||
win-status.o win-time.o win-video.o x86seg.o x87.o xtide.o pc.res
|
win-status.o win-time.o win-video.o x86seg.o x87.o xtide.o pc.res
|
||||||
|
|
|
||||||
11
src/cpu.c
11
src/cpu.c
|
|
@ -109,11 +109,12 @@ static struct
|
||||||
CPU cpus_8088[] =
|
CPU cpus_8088[] =
|
||||||
{
|
{
|
||||||
/*8088 standard*/
|
/*8088 standard*/
|
||||||
{"8088/4.77", CPU_8088, 0, 4772728, 1, 0, 0, 0, 0, 0},
|
{"8088/4.77", CPU_8088, 0, 4772728, 1, 0, 0, 0, 0, 0},
|
||||||
{"8088/8", CPU_8088, 1, 8000000, 1, 0, 0, 0, 0, 0},
|
{"8088/7.16", CPU_8088, 1, 14318184/2, 1, 0, 0, 0, 0, 0},
|
||||||
{"8088/10", CPU_8088, 2, 10000000, 1, 0, 0, 0, 0, 0},
|
{"8088/8", CPU_8088, 1, 8000000, 1, 0, 0, 0, 0, 0},
|
||||||
{"8088/12", CPU_8088, 3, 12000000, 1, 0, 0, 0, 0, 0},
|
{"8088/10", CPU_8088, 2, 10000000, 1, 0, 0, 0, 0, 0},
|
||||||
{"8088/16", CPU_8088, 4, 16000000, 1, 0, 0, 0, 0, 0},
|
{"8088/12", CPU_8088, 3, 12000000, 1, 0, 0, 0, 0, 0},
|
||||||
|
{"8088/16", CPU_8088, 4, 16000000, 1, 0, 0, 0, 0, 0},
|
||||||
{"", -1, 0, 0, 0, 0}
|
{"", -1, 0, 0, 0, 0}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
16
src/fdc.c
16
src/fdc.c
|
|
@ -120,6 +120,7 @@ void fdc_write(uint16_t addr, uint8_t val, void *priv)
|
||||||
fdc_reset();
|
fdc_reset();
|
||||||
}
|
}
|
||||||
motoron = val & 0x01;
|
motoron = val & 0x01;
|
||||||
|
fdc.drive = 0;
|
||||||
/* if (motoron)
|
/* if (motoron)
|
||||||
output = 3;
|
output = 3;
|
||||||
else
|
else
|
||||||
|
|
@ -143,6 +144,7 @@ void fdc_write(uint16_t addr, uint8_t val, void *priv)
|
||||||
timer_process();
|
timer_process();
|
||||||
motoron = (val & 0xf0) ? 1 : 0;
|
motoron = (val & 0xf0) ? 1 : 0;
|
||||||
timer_update_outstanding();
|
timer_update_outstanding();
|
||||||
|
fdc.drive = val & 3;
|
||||||
}
|
}
|
||||||
fdc.dor=val;
|
fdc.dor=val;
|
||||||
// printf("DOR now %02X\n",val);
|
// printf("DOR now %02X\n",val);
|
||||||
|
|
@ -299,7 +301,7 @@ void fdc_write(uint16_t addr, uint8_t val, void *priv)
|
||||||
timer_process();
|
timer_process();
|
||||||
disctime = 1024 * (1 << TIMER_SHIFT);
|
disctime = 1024 * (1 << TIMER_SHIFT);
|
||||||
timer_update_outstanding();
|
timer_update_outstanding();
|
||||||
fdc.drive = fdc.params[0] & 3;
|
// fdc.drive = fdc.params[0] & 3;
|
||||||
disc_drivesel = fdc.drive & 1;
|
disc_drivesel = fdc.drive & 1;
|
||||||
fdc_reset_stat = 0;
|
fdc_reset_stat = 0;
|
||||||
switch (discint)
|
switch (discint)
|
||||||
|
|
@ -456,7 +458,7 @@ uint8_t fdc_read(uint16_t addr, void *priv)
|
||||||
break;
|
break;
|
||||||
case 7: /*Disk change*/
|
case 7: /*Disk change*/
|
||||||
if (fdc.dor & (0x10 << (fdc.dor & 1)))
|
if (fdc.dor & (0x10 << (fdc.dor & 1)))
|
||||||
temp = (disc_changed[fdc.dor & 1] || drive_empty[fdc.dor & 1])?0x80:0;
|
temp = (disc_changed[fdc.drive] || drive_empty[fdc.drive]) ? 0x80 : 0;
|
||||||
else
|
else
|
||||||
temp = 0;
|
temp = 0;
|
||||||
if (fdc.dskchg_activelow) /*PC2086/3086 seem to reverse this bit*/
|
if (fdc.dskchg_activelow) /*PC2086/3086 seem to reverse this bit*/
|
||||||
|
|
@ -626,7 +628,10 @@ void fdc_callback()
|
||||||
case 7: /*Recalibrate*/
|
case 7: /*Recalibrate*/
|
||||||
fdc.track[fdc.drive]=0;
|
fdc.track[fdc.drive]=0;
|
||||||
// if (!driveempty[fdc.dor & 1]) discchanged[fdc.dor & 1] = 0;
|
// if (!driveempty[fdc.dor & 1]) discchanged[fdc.dor & 1] = 0;
|
||||||
fdc.st0 = 0x20 | (fdc.params[0] & 3) | (fdc.head?4:0);
|
if (fdc.drive <= 1)
|
||||||
|
fdc.st0 = 0x20 | (fdc.params[0] & 3) | (fdc.head?4:0);
|
||||||
|
else
|
||||||
|
fdc.st0 = 0x68 | (fdc.params[0] & 3) | (fdc.head?4:0);
|
||||||
discint=-3;
|
discint=-3;
|
||||||
timer_process();
|
timer_process();
|
||||||
disctime = 2048 * (1 << TIMER_SHIFT);
|
disctime = 2048 * (1 << TIMER_SHIFT);
|
||||||
|
|
@ -708,7 +713,10 @@ void fdc_callback()
|
||||||
fdc.track[fdc.drive]=fdc.params[1];
|
fdc.track[fdc.drive]=fdc.params[1];
|
||||||
// if (!driveempty[fdc.dor & 1]) discchanged[fdc.dor & 1] = 0;
|
// if (!driveempty[fdc.dor & 1]) discchanged[fdc.dor & 1] = 0;
|
||||||
// printf("Seeked to track %i %i\n",fdc.track[fdc.drive], fdc.drive);
|
// printf("Seeked to track %i %i\n",fdc.track[fdc.drive], fdc.drive);
|
||||||
fdc.st0 = 0x20 | (fdc.params[0] & 3) | (fdc.head?4:0);
|
if (fdc.drive <= 1)
|
||||||
|
fdc.st0 = 0x20 | (fdc.params[0] & 3) | (fdc.head?4:0);
|
||||||
|
else
|
||||||
|
fdc.st0 = 0x68 | (fdc.params[0] & 3) | (fdc.head?4:0);
|
||||||
discint=-3;
|
discint=-3;
|
||||||
timer_process();
|
timer_process();
|
||||||
disctime = 2048 * (1 << TIMER_SHIFT);
|
disctime = 2048 * (1 << TIMER_SHIFT);
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
void fdc_init();
|
void fdc_init();
|
||||||
void fdc_add();
|
void fdc_add();
|
||||||
void fdc_add_pcjr();
|
void fdc_add_pcjr();
|
||||||
|
void fdc_add_tandy();
|
||||||
void fdc_remove();
|
void fdc_remove();
|
||||||
void fdc_reset();
|
void fdc_reset();
|
||||||
void fdc_poll();
|
void fdc_poll();
|
||||||
|
|
|
||||||
|
|
@ -300,6 +300,8 @@ enum
|
||||||
ROM_DTK386,
|
ROM_DTK386,
|
||||||
ROM_PXXT,
|
ROM_PXXT,
|
||||||
ROM_JUKOPC,
|
ROM_JUKOPC,
|
||||||
|
ROM_TANDY1000HX,
|
||||||
|
ROM_TANDY1000SL2,
|
||||||
ROM_IBMAT,
|
ROM_IBMAT,
|
||||||
ROM_CMDPC30,
|
ROM_CMDPC30,
|
||||||
ROM_AMI286,
|
ROM_AMI286,
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,8 @@ struct
|
||||||
|
|
||||||
uint8_t pa;
|
uint8_t pa;
|
||||||
uint8_t pb;
|
uint8_t pb;
|
||||||
|
|
||||||
|
int tandy;
|
||||||
} keyboard_xt;
|
} keyboard_xt;
|
||||||
|
|
||||||
static uint8_t key_queue[16];
|
static uint8_t key_queue[16];
|
||||||
|
|
@ -59,7 +61,7 @@ void keyboard_xt_adddata(uint8_t val)
|
||||||
|
|
||||||
void keyboard_xt_write(uint16_t port, uint8_t val, void *priv)
|
void keyboard_xt_write(uint16_t port, uint8_t val, void *priv)
|
||||||
{
|
{
|
||||||
pclog("keyboard_xt : write %04X %02X %02X\n", port, val, keyboard_xt.pb);
|
// pclog("keyboard_xt : write %04X %02X %02X\n", port, val, keyboard_xt.pb);
|
||||||
/* if (ram[8] == 0xc3)
|
/* if (ram[8] == 0xc3)
|
||||||
{
|
{
|
||||||
output = 3;
|
output = 3;
|
||||||
|
|
@ -67,7 +69,7 @@ void keyboard_xt_write(uint16_t port, uint8_t val, void *priv)
|
||||||
switch (port)
|
switch (port)
|
||||||
{
|
{
|
||||||
case 0x61:
|
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));
|
// 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*/
|
if (!(keyboard_xt.pb & 0x40) && (val & 0x40)) /*Reset keyboard*/
|
||||||
{
|
{
|
||||||
pclog("keyboard_xt : reset keyboard\n");
|
pclog("keyboard_xt : reset keyboard\n");
|
||||||
|
|
@ -97,7 +99,7 @@ void keyboard_xt_write(uint16_t port, uint8_t val, void *priv)
|
||||||
uint8_t keyboard_xt_read(uint16_t port, void *priv)
|
uint8_t keyboard_xt_read(uint16_t port, void *priv)
|
||||||
{
|
{
|
||||||
uint8_t temp;
|
uint8_t temp;
|
||||||
pclog("keyboard_xt : read %04X ", port);
|
// pclog("keyboard_xt : read %04X ", port);
|
||||||
switch (port)
|
switch (port)
|
||||||
{
|
{
|
||||||
case 0x60:
|
case 0x60:
|
||||||
|
|
@ -153,6 +155,8 @@ uint8_t keyboard_xt_read(uint16_t port, void *priv)
|
||||||
temp = 0xD;
|
temp = 0xD;
|
||||||
}
|
}
|
||||||
temp |= (ppispeakon ? 0x20 : 0);
|
temp |= (ppispeakon ? 0x20 : 0);
|
||||||
|
if (keyboard_xt.tandy)
|
||||||
|
temp |= (tandy_eeprom_read() ? 0x10 : 0);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|
@ -160,7 +164,7 @@ uint8_t keyboard_xt_read(uint16_t port, void *priv)
|
||||||
//dumpregs();
|
//dumpregs();
|
||||||
//exit(-1);
|
//exit(-1);
|
||||||
}
|
}
|
||||||
pclog("%02X\n", temp);
|
// pclog("%02X\n", temp);
|
||||||
return temp;
|
return temp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -178,6 +182,19 @@ void keyboard_xt_init()
|
||||||
keyboard_xt_reset();
|
keyboard_xt_reset();
|
||||||
keyboard_send = keyboard_xt_adddata;
|
keyboard_send = keyboard_xt_adddata;
|
||||||
keyboard_poll = keyboard_xt_poll;
|
keyboard_poll = keyboard_xt_poll;
|
||||||
|
keyboard_xt.tandy = 0;
|
||||||
|
|
||||||
|
timer_add(keyboard_xt_poll, &keybsenddelay, TIMER_ALWAYS_ENABLED, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void keyboard_tandy_init()
|
||||||
|
{
|
||||||
|
//return;
|
||||||
|
io_sethandler(0x0060, 0x0004, keyboard_xt_read, NULL, NULL, keyboard_xt_write, NULL, NULL, NULL);
|
||||||
|
keyboard_xt_reset();
|
||||||
|
keyboard_send = keyboard_xt_adddata;
|
||||||
|
keyboard_poll = keyboard_xt_poll;
|
||||||
|
keyboard_xt.tandy = (romset != ROM_TANDY) ? 1 : 0;
|
||||||
|
|
||||||
timer_add(keyboard_xt_poll, &keybsenddelay, TIMER_ALWAYS_ENABLED, NULL);
|
timer_add(keyboard_xt_poll, &keybsenddelay, TIMER_ALWAYS_ENABLED, NULL);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
void keyboard_xt_init();
|
void keyboard_xt_init();
|
||||||
|
void keyboard_tandy_init();
|
||||||
void keyboard_xt_reset();
|
void keyboard_xt_reset();
|
||||||
void keyboard_xt_poll();
|
void keyboard_xt_poll();
|
||||||
|
|
|
||||||
34
src/mem.c
34
src/mem.c
|
|
@ -163,6 +163,29 @@ int loadbios()
|
||||||
fclose(f);
|
fclose(f);
|
||||||
mem_load_xtide_bios();
|
mem_load_xtide_bios();
|
||||||
return 1;
|
return 1;
|
||||||
|
case ROM_TANDY1000HX:
|
||||||
|
f = romfopen("roms/tandy1000hx/v020000.u12", "rb");
|
||||||
|
if (!f) break;
|
||||||
|
fread(rom, 0x20000, 1, f);
|
||||||
|
fclose(f);
|
||||||
|
biosmask = 0x1ffff;
|
||||||
|
mem_load_xtide_bios();
|
||||||
|
return 1;
|
||||||
|
case ROM_TANDY1000SL2:
|
||||||
|
f = romfopen("roms/tandy1000sl2/8079047.hu1" ,"rb");
|
||||||
|
ff = romfopen("roms/tandy1000sl2/8079048.hu2","rb");
|
||||||
|
if (!f || !ff) break;
|
||||||
|
fseek(f, 0x30000/2, SEEK_SET);
|
||||||
|
fseek(ff, 0x30000/2, SEEK_SET);
|
||||||
|
for (c = 0x0000; c < 0x10000; c += 2)
|
||||||
|
{
|
||||||
|
rom[c] = getc(f);
|
||||||
|
rom[c + 1] = getc(ff);
|
||||||
|
}
|
||||||
|
fclose(ff);
|
||||||
|
fclose(f);
|
||||||
|
mem_load_xtide_bios();
|
||||||
|
return 1;
|
||||||
/* case ROM_IBMPCJR:
|
/* case ROM_IBMPCJR:
|
||||||
f=fopen("pcjr/bios.rom","rb");
|
f=fopen("pcjr/bios.rom","rb");
|
||||||
fread(rom+0xE000,8192,1,f);
|
fread(rom+0xE000,8192,1,f);
|
||||||
|
|
@ -1723,10 +1746,13 @@ void mem_set_mem_state(uint32_t base, uint32_t size, int state)
|
||||||
|
|
||||||
void mem_add_bios()
|
void mem_add_bios()
|
||||||
{
|
{
|
||||||
mem_mapping_add(&bios_mapping[0], 0xe0000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom, MEM_MAPPING_EXTERNAL, 0);
|
if (AT)
|
||||||
mem_mapping_add(&bios_mapping[1], 0xe4000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (0x4000 & biosmask), MEM_MAPPING_EXTERNAL, 0);
|
{
|
||||||
mem_mapping_add(&bios_mapping[2], 0xe8000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (0x8000 & biosmask), MEM_MAPPING_EXTERNAL, 0);
|
mem_mapping_add(&bios_mapping[0], 0xe0000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom, MEM_MAPPING_EXTERNAL, 0);
|
||||||
mem_mapping_add(&bios_mapping[3], 0xec000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (0xc000 & biosmask), MEM_MAPPING_EXTERNAL, 0);
|
mem_mapping_add(&bios_mapping[1], 0xe4000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (0x4000 & biosmask), MEM_MAPPING_EXTERNAL, 0);
|
||||||
|
mem_mapping_add(&bios_mapping[2], 0xe8000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (0x8000 & biosmask), MEM_MAPPING_EXTERNAL, 0);
|
||||||
|
mem_mapping_add(&bios_mapping[3], 0xec000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (0xc000 & biosmask), MEM_MAPPING_EXTERNAL, 0);
|
||||||
|
}
|
||||||
mem_mapping_add(&bios_mapping[4], 0xf0000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (0x10000 & biosmask), MEM_MAPPING_EXTERNAL, 0);
|
mem_mapping_add(&bios_mapping[4], 0xf0000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (0x10000 & biosmask), MEM_MAPPING_EXTERNAL, 0);
|
||||||
mem_mapping_add(&bios_mapping[5], 0xf4000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (0x14000 & biosmask), MEM_MAPPING_EXTERNAL, 0);
|
mem_mapping_add(&bios_mapping[5], 0xf4000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (0x14000 & biosmask), MEM_MAPPING_EXTERNAL, 0);
|
||||||
mem_mapping_add(&bios_mapping[6], 0xf8000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (0x18000 & biosmask), MEM_MAPPING_EXTERNAL, 0);
|
mem_mapping_add(&bios_mapping[6], 0xf8000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (0x18000 & biosmask), MEM_MAPPING_EXTERNAL, 0);
|
||||||
|
|
|
||||||
27
src/model.c
27
src/model.c
|
|
@ -39,7 +39,10 @@
|
||||||
#include "ps1.h"
|
#include "ps1.h"
|
||||||
#include "serial.h"
|
#include "serial.h"
|
||||||
#include "sis496.h"
|
#include "sis496.h"
|
||||||
|
#include "sound_pssj.h"
|
||||||
#include "sound_sn76489.h"
|
#include "sound_sn76489.h"
|
||||||
|
#include "tandy_eeprom.h"
|
||||||
|
#include "tandy_rom.h"
|
||||||
#include "um8669f.h"
|
#include "um8669f.h"
|
||||||
#include "um8881f.h"
|
#include "um8881f.h"
|
||||||
#include "wd76c10.h"
|
#include "wd76c10.h"
|
||||||
|
|
@ -48,6 +51,7 @@
|
||||||
void xt_init();
|
void xt_init();
|
||||||
void pcjr_init();
|
void pcjr_init();
|
||||||
void tandy1k_init();
|
void tandy1k_init();
|
||||||
|
void tandy1ksl2_init();
|
||||||
void ams_init();
|
void ams_init();
|
||||||
void europc_init();
|
void europc_init();
|
||||||
void olim24_init();
|
void olim24_init();
|
||||||
|
|
@ -82,6 +86,8 @@ MODEL models[] =
|
||||||
{"Phoenix XT clone", ROM_PXXT, { "", cpus_8088, "", NULL, "", NULL}, 0, 0, 128, 640, 64, xt_init},
|
{"Phoenix XT clone", ROM_PXXT, { "", cpus_8088, "", NULL, "", NULL}, 0, 0, 128, 640, 64, xt_init},
|
||||||
{"Juko XT clone", ROM_JUKOPC, { "", cpus_8088, "", NULL, "", NULL}, 0, 0, 128, 640, 64, xt_init},
|
{"Juko XT clone", ROM_JUKOPC, { "", cpus_8088, "", NULL, "", NULL}, 0, 0, 128, 640, 64, xt_init},
|
||||||
{"Tandy 1000", ROM_TANDY, { "", cpus_8088, "", NULL, "", NULL}, 1, 0, 128, 640, 128, tandy1k_init},
|
{"Tandy 1000", ROM_TANDY, { "", cpus_8088, "", NULL, "", NULL}, 1, 0, 128, 640, 128, tandy1k_init},
|
||||||
|
{"Tandy 1000 HX", ROM_TANDY1000HX, { "", cpus_8088, "", NULL, "", NULL}, 1, 0, 256, 640, 128, tandy1k_init},
|
||||||
|
{"Tandy 1000 SL/2", ROM_TANDY1000SL2,{ "", cpus_8086, "", NULL, "", NULL}, 1, 0, 512, 768, 128, tandy1ksl2_init},
|
||||||
{"Amstrad PC1512", ROM_PC1512, { "", cpus_pc1512, "", NULL, "", NULL}, 1, 0, 512, 640, 128, ams_init},
|
{"Amstrad PC1512", ROM_PC1512, { "", cpus_pc1512, "", NULL, "", NULL}, 1, 0, 512, 640, 128, ams_init},
|
||||||
{"Sinclair PC200", ROM_PC200, { "", cpus_8086, "", NULL, "", NULL}, 1, 0, 512, 640, 128, ams_init},
|
{"Sinclair PC200", ROM_PC200, { "", cpus_8086, "", NULL, "", NULL}, 1, 0, 512, 640, 128, ams_init},
|
||||||
{"Euro PC", ROM_EUROPC, { "", cpus_8086, "", NULL, "", NULL}, 0, 0, 512, 640, 128, europc_init},
|
{"Euro PC", ROM_EUROPC, { "", cpus_8086, "", NULL, "", NULL}, 0, 0, 512, 640, 128, europc_init},
|
||||||
|
|
@ -177,11 +183,28 @@ void tandy1k_init()
|
||||||
{
|
{
|
||||||
TANDY = 1;
|
TANDY = 1;
|
||||||
common_init();
|
common_init();
|
||||||
keyboard_xt_init();
|
keyboard_tandy_init();
|
||||||
mouse_serial_init();
|
mouse_serial_init();
|
||||||
device_add(&sn76489_device);
|
if (romset == ROM_TANDY)
|
||||||
|
device_add(&sn76489_device);
|
||||||
|
else
|
||||||
|
device_add(&ncr8496_device);
|
||||||
xtide_init();
|
xtide_init();
|
||||||
nmi_init();
|
nmi_init();
|
||||||
|
if (romset != ROM_TANDY)
|
||||||
|
device_add(&tandy_eeprom_device);
|
||||||
|
}
|
||||||
|
void tandy1ksl2_init()
|
||||||
|
{
|
||||||
|
// TANDY = 1;
|
||||||
|
common_init();
|
||||||
|
keyboard_tandy_init();
|
||||||
|
mouse_serial_init();
|
||||||
|
device_add(&pssj_device);
|
||||||
|
xtide_init();
|
||||||
|
nmi_init();
|
||||||
|
device_add(&tandy_rom_device);
|
||||||
|
device_add(&tandy_eeprom_device);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ams_init()
|
void ams_init()
|
||||||
|
|
|
||||||
212
src/sound_pssj.c
Normal file
212
src/sound_pssj.c
Normal file
|
|
@ -0,0 +1,212 @@
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "ibm.h"
|
||||||
|
#include "device.h"
|
||||||
|
#include "io.h"
|
||||||
|
#include "sound.h"
|
||||||
|
#include "sound_pssj.h"
|
||||||
|
#include "sound_sn76489.h"
|
||||||
|
|
||||||
|
#include "dma.h"
|
||||||
|
#include "pic.h"
|
||||||
|
#include "timer.h"
|
||||||
|
|
||||||
|
typedef struct pssj_t
|
||||||
|
{
|
||||||
|
sn76489_t sn76489;
|
||||||
|
|
||||||
|
uint8_t ctrl;
|
||||||
|
uint8_t wave;
|
||||||
|
uint8_t dac_val;
|
||||||
|
uint16_t freq;
|
||||||
|
int amplitude;
|
||||||
|
|
||||||
|
int irq;
|
||||||
|
int timer_count;
|
||||||
|
int enable;
|
||||||
|
|
||||||
|
int wave_pos;
|
||||||
|
int pulse_width;
|
||||||
|
|
||||||
|
int16_t buffer[SOUNDBUFLEN];
|
||||||
|
int pos;
|
||||||
|
} pssj_t;
|
||||||
|
|
||||||
|
static void pssj_update_irq(pssj_t *pssj)
|
||||||
|
{
|
||||||
|
if (pssj->irq && (pssj->ctrl & 0x10) && (pssj->ctrl & 0x08))
|
||||||
|
picint(1 << 7);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pssj_write(uint16_t port, uint8_t val, void *p)
|
||||||
|
{
|
||||||
|
pssj_t *pssj = (pssj_t *)p;
|
||||||
|
|
||||||
|
// pclog("pssj_write: port=%04x val=%02x\n", port, val);
|
||||||
|
switch (port & 3)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
pssj->ctrl = val;
|
||||||
|
pssj->enable = (val & 4) && (pssj->ctrl & 3);
|
||||||
|
sn74689_set_extra_divide(&pssj->sn76489, val & 0x40);
|
||||||
|
if (!(val & 8))
|
||||||
|
pssj->irq = 0;
|
||||||
|
pssj_update_irq(pssj);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
switch (pssj->ctrl & 3)
|
||||||
|
{
|
||||||
|
case 1: /*Sound channel*/
|
||||||
|
pssj->wave = val;
|
||||||
|
pssj->pulse_width = val & 7;
|
||||||
|
break;
|
||||||
|
case 3: /*Direct DAC*/
|
||||||
|
pssj->dac_val = val;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
pssj->freq = (pssj->freq & 0xf00) | val;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
pssj->freq = (pssj->freq & 0x0ff) | ((val & 0xf) << 8);
|
||||||
|
pssj->amplitude = val >> 4;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static uint8_t pssj_read(uint16_t port, void *p)
|
||||||
|
{
|
||||||
|
pssj_t *pssj = (pssj_t *)p;
|
||||||
|
|
||||||
|
// pclog("pssj_read: port=%04x %02x\n", port, (pssj->ctrl & ~0x88) | (pssj->irq ? 8 : 0));
|
||||||
|
switch (port & 3)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
return (pssj->ctrl & ~0x88) | (pssj->irq ? 8 : 0);
|
||||||
|
case 1:
|
||||||
|
switch (pssj->ctrl & 3)
|
||||||
|
{
|
||||||
|
case 0: /*Joystick*/
|
||||||
|
return 0;
|
||||||
|
case 1: /*Sound channel*/
|
||||||
|
return pssj->wave;
|
||||||
|
case 2: /*Successive approximation*/
|
||||||
|
return 0x80;
|
||||||
|
case 3: /*Direct DAC*/
|
||||||
|
return pssj->dac_val;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
return pssj->freq & 0xff;
|
||||||
|
case 3:
|
||||||
|
return (pssj->freq >> 8) | (pssj->amplitude << 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pssj_callback(void *p)
|
||||||
|
{
|
||||||
|
pssj_t *pssj = (pssj_t *)p;
|
||||||
|
int data;
|
||||||
|
|
||||||
|
if (pssj->ctrl & 2)
|
||||||
|
{
|
||||||
|
if ((pssj->ctrl & 3) == 3)
|
||||||
|
{
|
||||||
|
data = dma_channel_read(1);
|
||||||
|
|
||||||
|
if (data != DMA_NODATA)
|
||||||
|
{
|
||||||
|
pssj->dac_val = data & 0xff;
|
||||||
|
// pclog("DAC_val=%02x\n", data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
data = dma_channel_write(1, 0x80);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((data & DMA_OVER) && data != DMA_NODATA)
|
||||||
|
{
|
||||||
|
// pclog("Check IRQ %i %02x\n", pssj->irq, pssj->ctrl);
|
||||||
|
if (pssj->ctrl & 0x08)
|
||||||
|
{
|
||||||
|
pssj->irq = 1;
|
||||||
|
pssj_update_irq(pssj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
switch (pssj->wave & 0xc0)
|
||||||
|
{
|
||||||
|
case 0x00: /*Pulse*/
|
||||||
|
pssj->dac_val = (pssj->wave_pos > (pssj->pulse_width << 1)) ? 0xff : 0;
|
||||||
|
break;
|
||||||
|
case 0x40: /*Ramp*/
|
||||||
|
pssj->dac_val = pssj->wave_pos << 3;
|
||||||
|
break;
|
||||||
|
case 0x80: /*Triangle*/
|
||||||
|
if (pssj->wave_pos & 16)
|
||||||
|
pssj->dac_val = (pssj->wave_pos ^ 31) << 4;
|
||||||
|
else
|
||||||
|
pssj->dac_val = pssj->wave_pos << 4;
|
||||||
|
break;
|
||||||
|
case 0xc0:
|
||||||
|
pssj->dac_val = 0x80;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
pssj->wave_pos = (pssj->wave_pos + 1) & 31;
|
||||||
|
}
|
||||||
|
|
||||||
|
pssj->timer_count += (int)(TIMER_USEC * (1000000.0 / 3579545.0) * (double)(pssj->freq ? pssj->freq : 0x400));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pssj_poll(void *p)
|
||||||
|
{
|
||||||
|
pssj_t *pssj = (pssj_t *)p;
|
||||||
|
|
||||||
|
pssj->buffer[pssj->pos++] = (((int8_t)(pssj->dac_val ^ 0x80) * 0x20) * pssj->amplitude) / 15;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pssj_get_buffer(int16_t *buffer, int len, void *p)
|
||||||
|
{
|
||||||
|
pssj_t *pssj = (pssj_t *)p;
|
||||||
|
int c;
|
||||||
|
|
||||||
|
for (c = 0; c < len * 2; c++)
|
||||||
|
buffer[c] += pssj->buffer[c >> 1];
|
||||||
|
|
||||||
|
pssj->pos = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *pssj_init()
|
||||||
|
{
|
||||||
|
pssj_t *pssj = malloc(sizeof(pssj_t));
|
||||||
|
memset(pssj, 0, sizeof(pssj_t));
|
||||||
|
|
||||||
|
sn76489_init(&pssj->sn76489, 0x00c0, 0x0004, PSSJ);
|
||||||
|
|
||||||
|
io_sethandler(0x00C4, 0x0004, pssj_read, NULL, NULL, pssj_write, NULL, NULL, pssj);
|
||||||
|
timer_add(pssj_callback, &pssj->timer_count, &pssj->enable, pssj);
|
||||||
|
sound_add_handler(pssj_poll, pssj_get_buffer, pssj);
|
||||||
|
|
||||||
|
return pssj;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pssj_close(void *p)
|
||||||
|
{
|
||||||
|
pssj_t *pssj = (pssj_t *)p;
|
||||||
|
|
||||||
|
free(pssj);
|
||||||
|
}
|
||||||
|
|
||||||
|
device_t pssj_device =
|
||||||
|
{
|
||||||
|
"Tandy PSSJ",
|
||||||
|
0,
|
||||||
|
pssj_init,
|
||||||
|
pssj_close,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL
|
||||||
|
};
|
||||||
1
src/sound_pssj.h
Normal file
1
src/sound_pssj.h
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
extern device_t pssj_device;
|
||||||
|
|
@ -15,21 +15,6 @@ static float volslog[16]=
|
||||||
7.51785f,9.46440f,11.9194f,15.0000f
|
7.51785f,9.46440f,11.9194f,15.0000f
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct sn76489_t
|
|
||||||
{
|
|
||||||
int stat[4];
|
|
||||||
int latch[4], count[4];
|
|
||||||
int freqlo[4], freqhi[4];
|
|
||||||
int vol[4];
|
|
||||||
uint32_t shift;
|
|
||||||
uint8_t noise;
|
|
||||||
int lasttone;
|
|
||||||
uint8_t firstdat;
|
|
||||||
|
|
||||||
int16_t buffer[SOUNDBUFLEN];
|
|
||||||
int pos;
|
|
||||||
} sn76489_t;
|
|
||||||
|
|
||||||
#define PSGCONST ((3579545.0 / 64.0) / 48000.0)
|
#define PSGCONST ((3579545.0 / 64.0) / 48000.0)
|
||||||
|
|
||||||
void sn76489_poll(void *p)
|
void sn76489_poll(void *p)
|
||||||
|
|
@ -104,8 +89,10 @@ void sn76489_write(uint16_t addr, uint8_t data, void *p)
|
||||||
case 0:
|
case 0:
|
||||||
sn76489->freqlo[3] = data & 0xf;
|
sn76489->freqlo[3] = data & 0xf;
|
||||||
sn76489->latch[3] = (sn76489->freqlo[3] | (sn76489->freqhi[3] << 4)) << 6;
|
sn76489->latch[3] = (sn76489->freqlo[3] | (sn76489->freqhi[3] << 4)) << 6;
|
||||||
|
if (sn76489->extra_divide)
|
||||||
|
sn76489->latch[3] &= 0x3ff;
|
||||||
if (!sn76489->latch[3])
|
if (!sn76489->latch[3])
|
||||||
sn76489->latch[3] = 1024 << 6;
|
sn76489->latch[3] = (sn76489->extra_divide ? 2048 : 1024) << 6;
|
||||||
sn76489->lasttone = 3;
|
sn76489->lasttone = 3;
|
||||||
break;
|
break;
|
||||||
case 0x10:
|
case 0x10:
|
||||||
|
|
@ -115,8 +102,10 @@ void sn76489_write(uint16_t addr, uint8_t data, void *p)
|
||||||
case 0x20:
|
case 0x20:
|
||||||
sn76489->freqlo[2] = data & 0xf;
|
sn76489->freqlo[2] = data & 0xf;
|
||||||
sn76489->latch[2] = (sn76489->freqlo[2] | (sn76489->freqhi[2] << 4)) << 6;
|
sn76489->latch[2] = (sn76489->freqlo[2] | (sn76489->freqhi[2] << 4)) << 6;
|
||||||
|
if (sn76489->extra_divide)
|
||||||
|
sn76489->latch[2] &= 0x3ff;
|
||||||
if (!sn76489->latch[2])
|
if (!sn76489->latch[2])
|
||||||
sn76489->latch[2] = 1024 << 6;
|
sn76489->latch[2] = (sn76489->extra_divide ? 2048 : 1024) << 6;
|
||||||
sn76489->lasttone = 2;
|
sn76489->lasttone = 2;
|
||||||
break;
|
break;
|
||||||
case 0x30:
|
case 0x30:
|
||||||
|
|
@ -126,8 +115,10 @@ void sn76489_write(uint16_t addr, uint8_t data, void *p)
|
||||||
case 0x40:
|
case 0x40:
|
||||||
sn76489->freqlo[1] = data & 0xf;
|
sn76489->freqlo[1] = data & 0xf;
|
||||||
sn76489->latch[1] = (sn76489->freqlo[1] | (sn76489->freqhi[1] << 4)) << 6;
|
sn76489->latch[1] = (sn76489->freqlo[1] | (sn76489->freqhi[1] << 4)) << 6;
|
||||||
|
if (sn76489->extra_divide)
|
||||||
|
sn76489->latch[1] &= 0x3ff;
|
||||||
if (!sn76489->latch[1])
|
if (!sn76489->latch[1])
|
||||||
sn76489->latch[1] = 1024 << 6;
|
sn76489->latch[1] = (sn76489->extra_divide ? 2048 : 1024) << 6;
|
||||||
sn76489->lasttone = 1;
|
sn76489->lasttone = 1;
|
||||||
break;
|
break;
|
||||||
case 0x50:
|
case 0x50:
|
||||||
|
|
@ -135,13 +126,15 @@ void sn76489_write(uint16_t addr, uint8_t data, void *p)
|
||||||
sn76489->vol[1] = 0xf - data;
|
sn76489->vol[1] = 0xf - data;
|
||||||
break;
|
break;
|
||||||
case 0x60:
|
case 0x60:
|
||||||
if ((data & 4) != (sn76489->noise & 4))
|
if ((data & 4) != (sn76489->noise & 4) || sn76489->type == SN76496)
|
||||||
sn76489->shift = 0x4000;
|
sn76489->shift = 0x4000;
|
||||||
sn76489->noise = data & 0xf;
|
sn76489->noise = data & 0xf;
|
||||||
if ((data & 3) == 3) sn76489->latch[0] = sn76489->latch[1];
|
if ((data & 3) == 3) sn76489->latch[0] = sn76489->latch[1];
|
||||||
else sn76489->latch[0] = 0x400 << (data & 3);
|
else sn76489->latch[0] = 0x400 << (data & 3);
|
||||||
|
if (sn76489->extra_divide)
|
||||||
|
sn76489->latch[0] &= 0x3ff;
|
||||||
if (!sn76489->latch[0])
|
if (!sn76489->latch[0])
|
||||||
sn76489->latch[0] = 1024 << 6;
|
sn76489->latch[0] = (sn76489->extra_divide ? 2048 : 1024) << 6;
|
||||||
break;
|
break;
|
||||||
case 0x70:
|
case 0x70:
|
||||||
data &= 0xf;
|
data &= 0xf;
|
||||||
|
|
@ -153,7 +146,7 @@ void sn76489_write(uint16_t addr, uint8_t data, void *p)
|
||||||
{
|
{
|
||||||
if ((sn76489->firstdat & 0x70) == 0x60)
|
if ((sn76489->firstdat & 0x70) == 0x60)
|
||||||
{
|
{
|
||||||
if ((data & 4) != (sn76489->noise & 4))
|
if ((data & 4) != (sn76489->noise & 4) || sn76489->type == SN76496)
|
||||||
sn76489->shift = 0x4000;
|
sn76489->shift = 0x4000;
|
||||||
sn76489->noise = data & 0xf;
|
sn76489->noise = data & 0xf;
|
||||||
if ((data & 3) == 3) sn76489->latch[0] = sn76489->latch[1];
|
if ((data & 3) == 3) sn76489->latch[0] = sn76489->latch[1];
|
||||||
|
|
@ -163,10 +156,12 @@ void sn76489_write(uint16_t addr, uint8_t data, void *p)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
sn76489->freqhi[sn76489->lasttone] = data & 0x3F;
|
sn76489->freqhi[sn76489->lasttone] = data & 0x7F;
|
||||||
freq = sn76489->freqlo[sn76489->lasttone] | (sn76489->freqhi[sn76489->lasttone] << 4);
|
freq = sn76489->freqlo[sn76489->lasttone] | (sn76489->freqhi[sn76489->lasttone] << 4);
|
||||||
|
if (sn76489->extra_divide)
|
||||||
|
freq &= 0x3ff;
|
||||||
if (!freq)
|
if (!freq)
|
||||||
freq = 1024;
|
freq = sn76489->extra_divide ? 2048 : 1024;
|
||||||
if ((sn76489->noise & 3) == 3 && sn76489->lasttone == 1)
|
if ((sn76489->noise & 3) == 3 && sn76489->lasttone == 1)
|
||||||
sn76489->latch[0] = freq << 6;
|
sn76489->latch[0] = freq << 6;
|
||||||
sn76489->latch[sn76489->lasttone] = freq << 6;
|
sn76489->latch[sn76489->lasttone] = freq << 6;
|
||||||
|
|
@ -174,13 +169,13 @@ void sn76489_write(uint16_t addr, uint8_t data, void *p)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void *sn76489_init()
|
void sn74689_set_extra_divide(sn76489_t *sn76489, int enable)
|
||||||
{
|
{
|
||||||
sn76489_t *sn76489 = malloc(sizeof(sn76489_t));
|
sn76489->extra_divide = enable;
|
||||||
memset(sn76489, 0, sizeof(sn76489_t));
|
}
|
||||||
|
|
||||||
io_sethandler(0x00C0, 0x0008, NULL, NULL, NULL, sn76489_write, NULL, NULL, sn76489);
|
|
||||||
|
|
||||||
|
void sn76489_init(sn76489_t *sn76489, uint16_t base, uint16_t size, int type)
|
||||||
|
{
|
||||||
sound_add_handler(sn76489_poll, sn76489_get_buffer, sn76489);
|
sound_add_handler(sn76489_poll, sn76489_get_buffer, sn76489);
|
||||||
|
|
||||||
sn76489->latch[0] = sn76489->latch[1] = sn76489->latch[2] = sn76489->latch[3] = 0x3FF << 6;
|
sn76489->latch[0] = sn76489->latch[1] = sn76489->latch[2] = sn76489->latch[3] = 0x3FF << 6;
|
||||||
|
|
@ -194,13 +189,33 @@ void *sn76489_init()
|
||||||
sn76489->count[3] = (rand()&0x3FF)<<6;
|
sn76489->count[3] = (rand()&0x3FF)<<6;
|
||||||
sn76489->noise = 3;
|
sn76489->noise = 3;
|
||||||
sn76489->shift = 0x4000;
|
sn76489->shift = 0x4000;
|
||||||
|
sn76489->type = type;
|
||||||
|
|
||||||
sn76489_mute = 0;
|
sn76489_mute = 0;
|
||||||
|
|
||||||
|
io_sethandler(base, size, NULL, NULL, NULL, sn76489_write, NULL, NULL, sn76489);
|
||||||
|
}
|
||||||
|
|
||||||
|
void *sn76489_device_init()
|
||||||
|
{
|
||||||
|
sn76489_t *sn76489 = malloc(sizeof(sn76489_t));
|
||||||
|
memset(sn76489, 0, sizeof(sn76489_t));
|
||||||
|
|
||||||
|
sn76489_init(sn76489, 0x00c0, 0x0008, SN76496);
|
||||||
|
|
||||||
|
return sn76489;
|
||||||
|
}
|
||||||
|
void *ncr8496_device_init()
|
||||||
|
{
|
||||||
|
sn76489_t *sn76489 = malloc(sizeof(sn76489_t));
|
||||||
|
memset(sn76489, 0, sizeof(sn76489_t));
|
||||||
|
|
||||||
|
sn76489_init(sn76489, 0x00c0, 0x0008, NCR8496);
|
||||||
|
|
||||||
return sn76489;
|
return sn76489;
|
||||||
}
|
}
|
||||||
|
|
||||||
void sn76489_close(void *p)
|
void sn76489_device_close(void *p)
|
||||||
{
|
{
|
||||||
sn76489_t *sn76489 = (sn76489_t *)p;
|
sn76489_t *sn76489 = (sn76489_t *)p;
|
||||||
|
|
||||||
|
|
@ -211,8 +226,19 @@ device_t sn76489_device =
|
||||||
{
|
{
|
||||||
"TI SN74689 PSG",
|
"TI SN74689 PSG",
|
||||||
0,
|
0,
|
||||||
sn76489_init,
|
sn76489_device_init,
|
||||||
sn76489_close,
|
sn76489_device_close,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
device_t ncr8496_device =
|
||||||
|
{
|
||||||
|
"NCR8496 PSG",
|
||||||
|
0,
|
||||||
|
ncr8496_device_init,
|
||||||
|
sn76489_device_close,
|
||||||
NULL,
|
NULL,
|
||||||
NULL,
|
NULL,
|
||||||
NULL,
|
NULL,
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,31 @@
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
SN76496,
|
||||||
|
NCR8496,
|
||||||
|
PSSJ
|
||||||
|
};
|
||||||
|
|
||||||
extern device_t sn76489_device;
|
extern device_t sn76489_device;
|
||||||
|
extern device_t ncr8496_device;
|
||||||
|
|
||||||
extern int sn76489_mute;
|
extern int sn76489_mute;
|
||||||
|
|
||||||
|
typedef struct sn76489_t
|
||||||
|
{
|
||||||
|
int stat[4];
|
||||||
|
int latch[4], count[4];
|
||||||
|
int freqlo[4], freqhi[4];
|
||||||
|
int vol[4];
|
||||||
|
uint32_t shift;
|
||||||
|
uint8_t noise;
|
||||||
|
int lasttone;
|
||||||
|
uint8_t firstdat;
|
||||||
|
int type;
|
||||||
|
int extra_divide;
|
||||||
|
|
||||||
|
int16_t buffer[SOUNDBUFLEN];
|
||||||
|
int pos;
|
||||||
|
} sn76489_t;
|
||||||
|
|
||||||
|
void sn76489_init(sn76489_t *sn76489, uint16_t base, uint16_t size, int type);
|
||||||
|
void sn74689_set_extra_divide(sn76489_t *sn76489, int enable);
|
||||||
|
|
|
||||||
178
src/tandy_eeprom.c
Normal file
178
src/tandy_eeprom.c
Normal file
|
|
@ -0,0 +1,178 @@
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "ibm.h"
|
||||||
|
#include "device.h"
|
||||||
|
#include "tandy_eeprom.h"
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
int state;
|
||||||
|
int count;
|
||||||
|
int addr;
|
||||||
|
int clock;
|
||||||
|
uint16_t data;
|
||||||
|
uint16_t store[64];
|
||||||
|
|
||||||
|
int romset;
|
||||||
|
} tandy_eeprom_t;
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
EEPROM_IDLE,
|
||||||
|
EEPROM_GET_OPERATION,
|
||||||
|
EEPROM_READ,
|
||||||
|
EEPROM_WRITE
|
||||||
|
};
|
||||||
|
|
||||||
|
static int eeprom_data_out;
|
||||||
|
|
||||||
|
void tandy_eeprom_write(uint16_t addr, uint8_t val, void *p)
|
||||||
|
{
|
||||||
|
tandy_eeprom_t *eeprom = (tandy_eeprom_t *)p;
|
||||||
|
|
||||||
|
if ((val & 4) && !eeprom->clock)
|
||||||
|
{
|
||||||
|
// pclog("eeprom_write %02x %i %i\n", val, eeprom->state, eeprom->count);
|
||||||
|
switch (eeprom->state)
|
||||||
|
{
|
||||||
|
case EEPROM_IDLE:
|
||||||
|
switch (eeprom->count)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
if (!(val & 3))
|
||||||
|
eeprom->count = 1;
|
||||||
|
else
|
||||||
|
eeprom->count = 0;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
if ((val & 3) == 2)
|
||||||
|
eeprom->count = 2;
|
||||||
|
else
|
||||||
|
eeprom->count = 0;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
if ((val & 3) == 3)
|
||||||
|
eeprom->state = EEPROM_GET_OPERATION;
|
||||||
|
eeprom->count = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case EEPROM_GET_OPERATION:
|
||||||
|
eeprom->data = (eeprom->data << 1) | (val & 1);
|
||||||
|
eeprom->count++;
|
||||||
|
if (eeprom->count == 8)
|
||||||
|
{
|
||||||
|
eeprom->count = 0;
|
||||||
|
// pclog("EEPROM get operation %02x\n", eeprom->data);
|
||||||
|
eeprom->addr = eeprom->data & 0x3f;
|
||||||
|
switch (eeprom->data & 0xc0)
|
||||||
|
{
|
||||||
|
case 0x40:
|
||||||
|
eeprom->state = EEPROM_WRITE;
|
||||||
|
break;
|
||||||
|
case 0x80:
|
||||||
|
eeprom->state = EEPROM_READ;
|
||||||
|
eeprom->data = eeprom->store[eeprom->addr];
|
||||||
|
// pclog("EEPROM read data %02x %04x\n", eeprom->addr, eeprom->data);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
eeprom->state = EEPROM_IDLE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case EEPROM_READ:
|
||||||
|
eeprom_data_out = eeprom->data & 0x8000;
|
||||||
|
eeprom->data <<= 1;
|
||||||
|
eeprom->count++;
|
||||||
|
if (eeprom->count == 16)
|
||||||
|
{
|
||||||
|
eeprom->count = 0;
|
||||||
|
eeprom->state = EEPROM_IDLE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case EEPROM_WRITE:
|
||||||
|
eeprom->data = (eeprom->data << 1) | (val & 1);
|
||||||
|
eeprom->count++;
|
||||||
|
if (eeprom->count == 16)
|
||||||
|
{
|
||||||
|
eeprom->count = 0;
|
||||||
|
eeprom->state = EEPROM_IDLE;
|
||||||
|
// pclog("EEPROM write %04x to %02x\n", eeprom->data, eeprom->addr);
|
||||||
|
eeprom->store[eeprom->addr] = eeprom->data;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
eeprom->clock = val & 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
int tandy_eeprom_read()
|
||||||
|
{
|
||||||
|
// pclog("tandy_eeprom_read: data_out=%x\n", eeprom_data_out);
|
||||||
|
return eeprom_data_out;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *tandy_eeprom_init()
|
||||||
|
{
|
||||||
|
tandy_eeprom_t *eeprom = malloc(sizeof(tandy_eeprom_t));
|
||||||
|
FILE *f;
|
||||||
|
|
||||||
|
memset(eeprom, 0, sizeof(tandy_eeprom_t));
|
||||||
|
|
||||||
|
eeprom->romset = romset;
|
||||||
|
switch (romset)
|
||||||
|
{
|
||||||
|
case ROM_TANDY1000HX:
|
||||||
|
f = romfopen("tandy1000hx.bin" ,"rb");
|
||||||
|
break;
|
||||||
|
case ROM_TANDY1000SL2:
|
||||||
|
f = romfopen("tandy1000sl2.bin" ,"rb");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (f)
|
||||||
|
{
|
||||||
|
fread(eeprom->store, 128, 1, f);
|
||||||
|
fclose(f);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
memset(eeprom->store, 0, 128);
|
||||||
|
|
||||||
|
io_sethandler(0x037c, 0x0001, NULL, NULL, NULL, tandy_eeprom_write, NULL, NULL, eeprom);
|
||||||
|
|
||||||
|
return eeprom;
|
||||||
|
}
|
||||||
|
|
||||||
|
void tandy_eeprom_close(void *p)
|
||||||
|
{
|
||||||
|
tandy_eeprom_t *eeprom = (tandy_eeprom_t *)p;
|
||||||
|
FILE *f;
|
||||||
|
|
||||||
|
switch (eeprom->romset)
|
||||||
|
{
|
||||||
|
case ROM_TANDY1000HX:
|
||||||
|
f = romfopen("tandy1000hx.bin" ,"wb");
|
||||||
|
break;
|
||||||
|
case ROM_TANDY1000SL2:
|
||||||
|
f = romfopen("tandy1000sl2.bin" ,"wb");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
fwrite(eeprom->store, 128, 1, f);
|
||||||
|
fclose(f);
|
||||||
|
|
||||||
|
free(eeprom);
|
||||||
|
}
|
||||||
|
|
||||||
|
device_t tandy_eeprom_device =
|
||||||
|
{
|
||||||
|
"Tandy EEPROM",
|
||||||
|
0,
|
||||||
|
tandy_eeprom_init,
|
||||||
|
tandy_eeprom_close,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL
|
||||||
|
};
|
||||||
2
src/tandy_eeprom.h
Normal file
2
src/tandy_eeprom.h
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
device_t tandy_eeprom_device;
|
||||||
|
int tandy_eeprom_read();
|
||||||
94
src/tandy_rom.c
Normal file
94
src/tandy_rom.c
Normal file
|
|
@ -0,0 +1,94 @@
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "ibm.h"
|
||||||
|
#include "device.h"
|
||||||
|
#include "mem.h"
|
||||||
|
#include "tandy_rom.h"
|
||||||
|
|
||||||
|
static uint8_t *tandy_rom;
|
||||||
|
static uint8_t tandy_rom_bank;
|
||||||
|
static int tandy_rom_offset;
|
||||||
|
static mem_mapping_t tandy_rom_mapping;
|
||||||
|
|
||||||
|
uint8_t tandy_read_rom(uint32_t addr, void *p)
|
||||||
|
{
|
||||||
|
uint32_t addr2 = (addr & 0xffff) + tandy_rom_offset;
|
||||||
|
// if (!nopageerrors) pclog("tandy_read_rom: %05x %05x %02x %04x:%04x\n", addr, addr2, tandy_rom[addr2], CS,pc);
|
||||||
|
return tandy_rom[addr2];
|
||||||
|
}
|
||||||
|
uint16_t tandy_read_romw(uint32_t addr, void *p)
|
||||||
|
{
|
||||||
|
uint32_t addr2 = (addr & 0xffff) + tandy_rom_offset;
|
||||||
|
// if (!nopageerrors) pclog("tandy_read_romw: %05x %05x %04x %04x:%04x\n", addr, addr2, *(uint16_t *)&tandy_rom[addr2], CS,pc);
|
||||||
|
return *(uint16_t *)&tandy_rom[addr2];
|
||||||
|
}
|
||||||
|
uint32_t tandy_read_roml(uint32_t addr, void *p)
|
||||||
|
{
|
||||||
|
uint32_t addr2 = (addr & 0xffff) + tandy_rom_offset;
|
||||||
|
// if (!nopageerrors) pclog("tandy_read_roml: %05x %05x %08x\n", addr, addr2, *(uint32_t *)&tandy_rom[addr2]);
|
||||||
|
return *(uint32_t *)&tandy_rom[addr];
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t tandy_rom_bank_read(uint16_t port, void *p)
|
||||||
|
{
|
||||||
|
if (port == 0xffea)
|
||||||
|
return tandy_rom_bank ^ 0x10;
|
||||||
|
else
|
||||||
|
return 0xff;
|
||||||
|
}
|
||||||
|
void tandy_rom_bank_write(uint16_t port, uint8_t val, void *p)
|
||||||
|
{
|
||||||
|
if (port == 0xffea)
|
||||||
|
{
|
||||||
|
tandy_rom_bank = val;
|
||||||
|
tandy_rom_offset = ((val ^ 4) & 7) * 0x10000;
|
||||||
|
mem_mapping_set_exec(&tandy_rom_mapping, &tandy_rom[tandy_rom_offset]);
|
||||||
|
// pclog("tandy_rom_bank_write: port=%04x val=%02x offset=%05x\n", port, val, tandy_rom_offset);
|
||||||
|
}
|
||||||
|
// else
|
||||||
|
// pclog("Bad tandy write port=%04x val=%02x\n", port, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
void *tandy_rom_init()
|
||||||
|
{
|
||||||
|
FILE *f, *ff;
|
||||||
|
int c;
|
||||||
|
|
||||||
|
tandy_rom = malloc(0x80000);
|
||||||
|
|
||||||
|
f = romfopen("roms/tandy1000sl2/8079047.hu1" ,"rb");
|
||||||
|
ff = romfopen("roms/tandy1000sl2/8079048.hu2","rb");
|
||||||
|
for (c = 0x0000; c < 0x80000; c += 2)
|
||||||
|
{
|
||||||
|
tandy_rom[c] = getc(f);
|
||||||
|
tandy_rom[c + 1] = getc(ff);
|
||||||
|
}
|
||||||
|
fclose(ff);
|
||||||
|
fclose(f);
|
||||||
|
|
||||||
|
mem_mapping_add(&tandy_rom_mapping, 0xe0000, 0x10000,
|
||||||
|
tandy_read_rom, tandy_read_romw, tandy_read_roml,
|
||||||
|
NULL, NULL, NULL,
|
||||||
|
tandy_rom, MEM_MAPPING_EXTERNAL, NULL);
|
||||||
|
|
||||||
|
io_sethandler(0xffe8, 0x0008, tandy_rom_bank_read, NULL, NULL, tandy_rom_bank_write, NULL, NULL, NULL);
|
||||||
|
|
||||||
|
return tandy_rom;
|
||||||
|
}
|
||||||
|
|
||||||
|
void tandy_rom_close(void *p)
|
||||||
|
{
|
||||||
|
free(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
device_t tandy_rom_device =
|
||||||
|
{
|
||||||
|
"Tandy 1000SL/2 ROM",
|
||||||
|
0,
|
||||||
|
tandy_rom_init,
|
||||||
|
tandy_rom_close,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL
|
||||||
|
};
|
||||||
1
src/tandy_rom.h
Normal file
1
src/tandy_rom.h
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
extern device_t tandy_rom_device;
|
||||||
|
|
@ -26,6 +26,7 @@ typedef struct tandy_t
|
||||||
uint8_t stat;
|
uint8_t stat;
|
||||||
|
|
||||||
uint8_t *vram, *b8000;
|
uint8_t *vram, *b8000;
|
||||||
|
uint32_t b8000_mask;
|
||||||
|
|
||||||
int linepos, displine;
|
int linepos, displine;
|
||||||
int sc, vc;
|
int sc, vc;
|
||||||
|
|
@ -116,12 +117,14 @@ void tandy_recalcaddress(tandy_t *tandy)
|
||||||
{
|
{
|
||||||
tandy->vram = &ram[((tandy->memctrl & 0x06) << 14) + tandy->base];
|
tandy->vram = &ram[((tandy->memctrl & 0x06) << 14) + tandy->base];
|
||||||
tandy->b8000 = &ram[((tandy->memctrl & 0x30) << 11) + tandy->base];
|
tandy->b8000 = &ram[((tandy->memctrl & 0x30) << 11) + tandy->base];
|
||||||
|
tandy->b8000_mask = 0x7fff;
|
||||||
// printf("VRAM at %05X B8000 at %05X\n",((tandy->memctrl&0x6)<<14)+tandy->base,((tandy->memctrl&0x30)<<11)+tandy->base);
|
// printf("VRAM at %05X B8000 at %05X\n",((tandy->memctrl&0x6)<<14)+tandy->base,((tandy->memctrl&0x30)<<11)+tandy->base);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
tandy->vram = &ram[((tandy->memctrl & 0x07) << 14) + tandy->base];
|
tandy->vram = &ram[((tandy->memctrl & 0x07) << 14) + tandy->base];
|
||||||
tandy->b8000 = &ram[((tandy->memctrl & 0x38) << 11) + tandy->base];
|
tandy->b8000 = &ram[((tandy->memctrl & 0x38) << 11) + tandy->base];
|
||||||
|
tandy->b8000_mask = 0x3fff;
|
||||||
// printf("VRAM at %05X B8000 at %05X\n",((tandy->memctrl&0x7)<<14)+tandy->base,((tandy->memctrl&0x38)<<11)+tandy->base);
|
// printf("VRAM at %05X B8000 at %05X\n",((tandy->memctrl&0x7)<<14)+tandy->base,((tandy->memctrl&0x38)<<11)+tandy->base);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -148,7 +151,7 @@ void tandy_write(uint32_t addr, uint8_t val, void *p)
|
||||||
|
|
||||||
egawrites++;
|
egawrites++;
|
||||||
// pclog("Tandy VRAM write %05X %02X %04X:%04X %04X:%04X\n",addr,val,CS,pc,DS,SI);
|
// pclog("Tandy VRAM write %05X %02X %04X:%04X %04X:%04X\n",addr,val,CS,pc,DS,SI);
|
||||||
tandy->b8000[addr & 0x7fff] = val;
|
tandy->b8000[addr & tandy->b8000_mask] = val;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t tandy_read(uint32_t addr, void *p)
|
uint8_t tandy_read(uint32_t addr, void *p)
|
||||||
|
|
@ -159,7 +162,7 @@ uint8_t tandy_read(uint32_t addr, void *p)
|
||||||
|
|
||||||
egareads++;
|
egareads++;
|
||||||
// pclog("Tandy VRAM read %05X %02X %04X:%04X\n",addr,tandy->b8000[addr&0x7FFF],CS,pc);
|
// pclog("Tandy VRAM read %05X %02X %04X:%04X\n",addr,tandy->b8000[addr&0x7FFF],CS,pc);
|
||||||
return tandy->b8000[addr & 0x7fff];
|
return tandy->b8000[addr & tandy->b8000_mask];
|
||||||
}
|
}
|
||||||
|
|
||||||
void tandy_recalctimings(tandy_t *tandy)
|
void tandy_recalctimings(tandy_t *tandy)
|
||||||
|
|
@ -689,6 +692,8 @@ void *tandy_init()
|
||||||
mem_mapping_set_addr(&ram_low_mapping, 0, (mem_size - 128) * 1024);
|
mem_mapping_set_addr(&ram_low_mapping, 0, (mem_size - 128) * 1024);
|
||||||
io_sethandler(0x03d0, 0x0010, tandy_in, NULL, NULL, tandy_out, NULL, NULL, tandy);
|
io_sethandler(0x03d0, 0x0010, tandy_in, NULL, NULL, tandy_out, NULL, NULL, tandy);
|
||||||
io_sethandler(0x00a0, 0x0001, tandy_in, NULL, NULL, tandy_out, NULL, NULL, tandy);
|
io_sethandler(0x00a0, 0x0001, tandy_in, NULL, NULL, tandy_out, NULL, NULL, tandy);
|
||||||
|
tandy->b8000_mask = 0x3fff;
|
||||||
|
|
||||||
return tandy;
|
return tandy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
732
src/vid_tandysl.c
Normal file
732
src/vid_tandysl.c
Normal file
|
|
@ -0,0 +1,732 @@
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include "ibm.h"
|
||||||
|
#include "device.h"
|
||||||
|
#include "io.h"
|
||||||
|
#include "mem.h"
|
||||||
|
#include "timer.h"
|
||||||
|
#include "video.h"
|
||||||
|
#include "vid_tandysl.h"
|
||||||
|
|
||||||
|
typedef struct tandysl_t
|
||||||
|
{
|
||||||
|
mem_mapping_t mapping;
|
||||||
|
mem_mapping_t ram_mapping;
|
||||||
|
mem_mapping_t vram_mapping;
|
||||||
|
|
||||||
|
uint8_t crtc[32];
|
||||||
|
int crtcreg;
|
||||||
|
|
||||||
|
int array_index;
|
||||||
|
uint8_t array[32];
|
||||||
|
int memctrl;//=-1;
|
||||||
|
uint32_t base;
|
||||||
|
uint8_t mode, col;
|
||||||
|
uint8_t stat;
|
||||||
|
|
||||||
|
uint8_t *vram, *b8000;
|
||||||
|
uint32_t b8000_limit;
|
||||||
|
uint8_t planar_ctrl;
|
||||||
|
|
||||||
|
int linepos, displine;
|
||||||
|
int sc, vc;
|
||||||
|
int dispon;
|
||||||
|
int con, coff, cursoron, blink;
|
||||||
|
int vsynctime, vadj;
|
||||||
|
uint16_t ma, maback;
|
||||||
|
|
||||||
|
int dispontime, dispofftime, vidtime;
|
||||||
|
int firstline, lastline;
|
||||||
|
} tandysl_t;
|
||||||
|
|
||||||
|
static uint8_t crtcmask[32] =
|
||||||
|
{
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xf3, 0x1f, 0x7f, 0x1f, 0x3f, 0xff, 0x3f, 0xff,
|
||||||
|
0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||||
|
};
|
||||||
|
|
||||||
|
static void tandysl_recalcaddress(tandysl_t *tandy);
|
||||||
|
static void tandysl_recalctimings(tandysl_t *tandy);
|
||||||
|
static void tandysl_recalcmapping(tandysl_t *tandy);
|
||||||
|
static uint8_t tandysl_in(uint16_t addr, void *p);
|
||||||
|
static void tandysl_ram_write(uint32_t addr, uint8_t val, void *p);
|
||||||
|
static void tandysl_write(uint32_t addr, uint8_t val, void *p);
|
||||||
|
|
||||||
|
static void tandysl_out(uint16_t addr, uint8_t val, void *p)
|
||||||
|
{
|
||||||
|
tandysl_t *tandy = (tandysl_t *)p;
|
||||||
|
uint8_t old;
|
||||||
|
// pclog("TandySL OUT %04X %02X\n",addr,val);
|
||||||
|
switch (addr)
|
||||||
|
{
|
||||||
|
case 0x3d4:
|
||||||
|
tandy->crtcreg = val & 0x1f;
|
||||||
|
return;
|
||||||
|
case 0x3d5:
|
||||||
|
// pclog("Write CRTC R%02x %02x ",tandy->crtcreg, val);
|
||||||
|
old = tandy->crtc[tandy->crtcreg];
|
||||||
|
tandy->crtc[tandy->crtcreg] = val & crtcmask[tandy->crtcreg];
|
||||||
|
// pclog("now %02x\n", tandy->crtc[tandy->crtcreg]);
|
||||||
|
if (old != val)
|
||||||
|
{
|
||||||
|
if (tandy->crtcreg < 0xe || tandy->crtcreg > 0x10)
|
||||||
|
{
|
||||||
|
fullchange = changeframecount;
|
||||||
|
tandysl_recalctimings(tandy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
case 0x3d8:
|
||||||
|
tandy->mode = val;
|
||||||
|
return;
|
||||||
|
case 0x3d9:
|
||||||
|
tandy->col = val;
|
||||||
|
return;
|
||||||
|
case 0x3da:
|
||||||
|
tandy->array_index = val & 0x1f;
|
||||||
|
break;
|
||||||
|
case 0x3de:
|
||||||
|
if (tandy->array_index & 16)
|
||||||
|
val &= 0xf;
|
||||||
|
tandy->array[tandy->array_index & 0x1f] = val;
|
||||||
|
if ((tandy->array_index & 0x1f) == 5)
|
||||||
|
{
|
||||||
|
tandysl_recalcmapping(tandy);
|
||||||
|
tandysl_recalcaddress(tandy);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 0x3df:
|
||||||
|
tandy->memctrl = val;
|
||||||
|
// pclog("tandy 3df write %02x\n", val);
|
||||||
|
tandysl_recalcaddress(tandy);
|
||||||
|
break;
|
||||||
|
case 0x65:
|
||||||
|
if (val == 8) /*Hack*/
|
||||||
|
return;
|
||||||
|
tandy->planar_ctrl = val;
|
||||||
|
tandysl_recalcmapping(tandy);
|
||||||
|
break;
|
||||||
|
case 0xffe8:
|
||||||
|
if ((val & 0xe) == 0xe)
|
||||||
|
mem_mapping_disable(&tandy->ram_mapping);
|
||||||
|
else
|
||||||
|
mem_mapping_set_addr(&tandy->ram_mapping, ((val >> 1) & 7) * 128 * 1024, 0x20000);
|
||||||
|
tandysl_recalcaddress(tandy);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t tandysl_in(uint16_t addr, void *p)
|
||||||
|
{
|
||||||
|
tandysl_t *tandy = (tandysl_t *)p;
|
||||||
|
// if (addr!=0x3DA) pclog("Tandy IN %04X\n",addr);
|
||||||
|
switch (addr)
|
||||||
|
{
|
||||||
|
case 0x3d4:
|
||||||
|
return tandy->crtcreg;
|
||||||
|
case 0x3d5:
|
||||||
|
return tandy->crtc[tandy->crtcreg];
|
||||||
|
case 0x3da:
|
||||||
|
return tandy->stat;
|
||||||
|
}
|
||||||
|
// pclog("Bad Tandy IN %04x\n", addr);
|
||||||
|
return 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tandysl_recalcaddress(tandysl_t *tandy)
|
||||||
|
{
|
||||||
|
tandy->b8000_limit = 0x8000;
|
||||||
|
if (tandy->array[5] & 1)
|
||||||
|
{
|
||||||
|
tandy->vram = &ram[((tandy->memctrl & 0x04) << 14) + tandy->base];
|
||||||
|
tandy->b8000 = &ram[((tandy->memctrl & 0x20) << 11) + tandy->base];
|
||||||
|
}
|
||||||
|
else if ((tandy->memctrl & 0xc0) == 0xc0)
|
||||||
|
{
|
||||||
|
tandy->vram = &ram[((tandy->memctrl & 0x06) << 14) + tandy->base];
|
||||||
|
tandy->b8000 = &ram[((tandy->memctrl & 0x30) << 11) + tandy->base];
|
||||||
|
// printf("VRAM at %05X B8000 at %05X\n",((tandy->memctrl&0x6)<<14)+tandy->base,((tandy->memctrl&0x30)<<11)+tandy->base);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
tandy->vram = &ram[((tandy->memctrl & 0x07) << 14) + tandy->base];
|
||||||
|
tandy->b8000 = &ram[((tandy->memctrl & 0x38) << 11) + tandy->base];
|
||||||
|
// printf("VRAM at %05X B8000 at %05X\n",((tandy->memctrl&0x7)<<14)+tandy->base,((tandy->memctrl&0x38)<<11)+tandy->base);
|
||||||
|
if ((tandy->memctrl & 0x38) == 0x38)
|
||||||
|
tandy->b8000_limit = 0x4000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tandysl_recalcmapping(tandysl_t *tandy)
|
||||||
|
{
|
||||||
|
mem_mapping_disable(&tandy->mapping);
|
||||||
|
io_removehandler(0x03d0, 0x0010, tandysl_in, NULL, NULL, tandysl_out, NULL, NULL, tandy);
|
||||||
|
if (tandy->planar_ctrl & 4)
|
||||||
|
{
|
||||||
|
// pclog("Enable VRAM mapping\n");
|
||||||
|
mem_mapping_enable(&tandy->mapping);
|
||||||
|
if (tandy->array[5] & 1)
|
||||||
|
{
|
||||||
|
// pclog("Tandy mapping at A0000 %p %p\n", tandy_ram_write, tandy_write);
|
||||||
|
mem_mapping_set_addr(&tandy->mapping, 0xa0000, 0x10000);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// pclog("Tandy mapping at B8000\n");
|
||||||
|
mem_mapping_set_addr(&tandy->mapping, 0xb8000, 0x8000);
|
||||||
|
}
|
||||||
|
// mem_mapping_enable(&tandy->vram_mapping);
|
||||||
|
io_sethandler(0x03d0, 0x0010, tandysl_in, NULL, NULL, tandysl_out, NULL, NULL, tandy);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// pclog("Disable VRAM mapping\n");
|
||||||
|
mem_mapping_disable(&tandy->mapping);
|
||||||
|
// mem_mapping_disable(&tandy->vram_mapping);
|
||||||
|
io_removehandler(0x03d0, 0x0010, tandysl_in, NULL, NULL, tandysl_out, NULL, NULL, tandy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static void tandysl_ram_write(uint32_t addr, uint8_t val, void *p)
|
||||||
|
{
|
||||||
|
tandysl_t *tandy = (tandysl_t *)p;
|
||||||
|
// pclog("Tandy RAM write %05X %02X %04X:%04X %08x\n",addr,val,CS,pc, tandy->base);
|
||||||
|
ram[tandy->base + (addr & 0x1ffff)] = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t tandysl_ram_read(uint32_t addr, void *p)
|
||||||
|
{
|
||||||
|
tandysl_t *tandy = (tandysl_t *)p;
|
||||||
|
// if (!nopageerrors) pclog("Tandy RAM read %05X %02X %04X:%04X\n",addr,ram[tandy->base + (addr & 0x1ffff)],CS,pc);
|
||||||
|
return ram[tandy->base + (addr & 0x1ffff)];
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tandysl_write(uint32_t addr, uint8_t val, void *p)
|
||||||
|
{
|
||||||
|
tandysl_t *tandy = (tandysl_t *)p;
|
||||||
|
if (tandy->memctrl == -1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
egawrites++;
|
||||||
|
// pclog("Tandy VRAM write %05X %02X %04X:%04X %02x %x\n",addr,val,CS,pc,tandy->array[5], (uintptr_t)&tandy->b8000[addr & 0xffff] - (uintptr_t)ram);
|
||||||
|
if (tandy->array[5] & 1)
|
||||||
|
tandy->b8000[addr & 0xffff] = val;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ((addr & 0x7fff) >= tandy->b8000_limit)
|
||||||
|
return;
|
||||||
|
tandy->b8000[addr & 0x7fff] = val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t tandysl_read(uint32_t addr, void *p)
|
||||||
|
{
|
||||||
|
tandysl_t *tandy = (tandysl_t *)p;
|
||||||
|
if (tandy->memctrl == -1)
|
||||||
|
return 0xff;
|
||||||
|
|
||||||
|
egareads++;
|
||||||
|
// if (!nopageerrors) pclog("Tandy VRAM read %05X %02X %04X:%04X\n",addr,tandy->b8000[addr&0x7FFF],CS,pc);
|
||||||
|
if (tandy->array[5] & 1)
|
||||||
|
return tandy->b8000[addr & 0xffff];
|
||||||
|
if ((addr & 0x7fff) >= tandy->b8000_limit)
|
||||||
|
return 0xff;
|
||||||
|
return tandy->b8000[addr & 0x7fff];
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tandysl_recalctimings(tandysl_t *tandy)
|
||||||
|
{
|
||||||
|
double _dispontime, _dispofftime, disptime;
|
||||||
|
if (tandy->mode & 1)
|
||||||
|
{
|
||||||
|
disptime = tandy->crtc[0] + 1;
|
||||||
|
_dispontime = tandy->crtc[1];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
disptime = (tandy->crtc[0] + 1) << 1;
|
||||||
|
_dispontime = tandy->crtc[1] << 1;
|
||||||
|
}
|
||||||
|
_dispofftime = disptime - _dispontime;
|
||||||
|
_dispontime *= CGACONST;
|
||||||
|
_dispofftime *= CGACONST;
|
||||||
|
tandy->dispontime = (int)(_dispontime * (1 << TIMER_SHIFT));
|
||||||
|
tandy->dispofftime = (int)(_dispofftime * (1 << TIMER_SHIFT));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void tandysl_poll(void *p)
|
||||||
|
{
|
||||||
|
tandysl_t *tandy = (tandysl_t *)p;
|
||||||
|
uint16_t ca = (tandy->crtc[15] | (tandy->crtc[14] << 8)) & 0x3fff;
|
||||||
|
int drawcursor;
|
||||||
|
int x, c;
|
||||||
|
int oldvc;
|
||||||
|
uint8_t chr, attr;
|
||||||
|
uint16_t dat;
|
||||||
|
int cols[4];
|
||||||
|
int col;
|
||||||
|
int oldsc;
|
||||||
|
|
||||||
|
if (!tandy->linepos)
|
||||||
|
{
|
||||||
|
// pclog("tandy_poll vc=%i sc=%i dispon=%i\n", tandy->vc, tandy->sc, tandy->dispon);
|
||||||
|
// cgapal[0]=tandy->col&15;
|
||||||
|
// printf("Firstline %i Lastline %i tandy->displine %i\n",firstline,lastline,tandy->displine);
|
||||||
|
tandy->vidtime += tandy->dispofftime;
|
||||||
|
tandy->stat |= 1;
|
||||||
|
tandy->linepos = 1;
|
||||||
|
oldsc = tandy->sc;
|
||||||
|
if ((tandy->crtc[8] & 3) == 3)
|
||||||
|
tandy->sc = (tandy->sc << 1) & 7;
|
||||||
|
if (tandy->dispon)
|
||||||
|
{
|
||||||
|
if (tandy->displine < tandy->firstline)
|
||||||
|
{
|
||||||
|
tandy->firstline = tandy->displine;
|
||||||
|
// printf("Firstline %i\n",firstline);
|
||||||
|
}
|
||||||
|
tandy->lastline = tandy->displine;
|
||||||
|
cols[0] = (tandy->array[2] & 0xf) + 16;
|
||||||
|
for (c = 0; c < 8; c++)
|
||||||
|
{
|
||||||
|
if (tandy->array[3] & 4)
|
||||||
|
{
|
||||||
|
buffer->line[tandy->displine][c] = cols[0];
|
||||||
|
if (tandy->mode & 1) buffer->line[tandy->displine][c + (tandy->crtc[1] << 3) + 8] = cols[0];
|
||||||
|
else buffer->line[tandy->displine][c + (tandy->crtc[1] << 4) + 8] = cols[0];
|
||||||
|
}
|
||||||
|
else if ((tandy->mode & 0x12) == 0x12)
|
||||||
|
{
|
||||||
|
buffer->line[tandy->displine][c] = 0;
|
||||||
|
if (tandy->mode & 1) buffer->line[tandy->displine][c + (tandy->crtc[1] << 3) + 8] = 0;
|
||||||
|
else buffer->line[tandy->displine][c + (tandy->crtc[1] << 4) + 8] = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
buffer->line[tandy->displine][c] = (tandy->col & 15) + 16;
|
||||||
|
if (tandy->mode & 1) buffer->line[tandy->displine][c + (tandy->crtc[1] << 3) + 8] = (tandy->col & 15) + 16;
|
||||||
|
else buffer->line[tandy->displine][c + (tandy->crtc[1] << 4) + 8] = (tandy->col & 15) + 16;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (tandy->array[5] & 1) /*640x200x16*/
|
||||||
|
{
|
||||||
|
for (x = 0; x < tandy->crtc[1]*2; x++)
|
||||||
|
{
|
||||||
|
dat = (tandy->vram[(tandy->ma << 1) & 0xffff] << 8) |
|
||||||
|
tandy->vram[((tandy->ma << 1) + 1) & 0xffff];
|
||||||
|
tandy->ma++;
|
||||||
|
buffer->line[tandy->displine][(x << 2) + 8] = tandy->array[((dat >> 12) & 0xf)/*tandy->array[1])*/ + 16] + 16;
|
||||||
|
buffer->line[tandy->displine][(x << 2) + 9] = tandy->array[((dat >> 8) & 0xf)/*tandy->array[1])*/ + 16] + 16;
|
||||||
|
buffer->line[tandy->displine][(x << 2) + 10] = tandy->array[((dat >> 4) & 0xf)/*tandy->array[1])*/ + 16] + 16;
|
||||||
|
buffer->line[tandy->displine][(x << 2) + 11] = tandy->array[(dat & 0xf)/*tandy->array[1])*/ + 16] + 16;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ((tandy->array[3] & 0x10) && (tandy->mode & 1)) /*320x200x16*/
|
||||||
|
{
|
||||||
|
for (x = 0; x < tandy->crtc[1]; x++)
|
||||||
|
{
|
||||||
|
dat = (tandy->vram[((tandy->ma << 1) & 0x1fff) + ((tandy->sc & 3) * 0x2000)] << 8) |
|
||||||
|
tandy->vram[((tandy->ma << 1) & 0x1fff) + ((tandy->sc & 3) * 0x2000) + 1];
|
||||||
|
tandy->ma++;
|
||||||
|
buffer->line[tandy->displine][(x << 3) + 8] =
|
||||||
|
buffer->line[tandy->displine][(x << 3) + 9] = tandy->array[((dat >> 12) & tandy->array[1]) + 16] + 16;
|
||||||
|
buffer->line[tandy->displine][(x << 3) + 10] =
|
||||||
|
buffer->line[tandy->displine][(x << 3) + 11] = tandy->array[((dat >> 8) & tandy->array[1]) + 16] + 16;
|
||||||
|
buffer->line[tandy->displine][(x << 3) + 12] =
|
||||||
|
buffer->line[tandy->displine][(x << 3) + 13] = tandy->array[((dat >> 4) & tandy->array[1]) + 16] + 16;
|
||||||
|
buffer->line[tandy->displine][(x << 3) + 14] =
|
||||||
|
buffer->line[tandy->displine][(x << 3) + 15] = tandy->array[(dat & tandy->array[1]) + 16] + 16;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (tandy->array[3] & 0x10) /*160x200x16*/
|
||||||
|
{
|
||||||
|
for (x = 0; x < tandy->crtc[1]; x++)
|
||||||
|
{
|
||||||
|
dat = (tandy->vram[((tandy->ma << 1) & 0x1fff) + ((tandy->sc & 1) * 0x2000)] << 8) |
|
||||||
|
tandy->vram[((tandy->ma << 1) & 0x1fff) + ((tandy->sc & 1) * 0x2000) + 1];
|
||||||
|
tandy->ma++;
|
||||||
|
buffer->line[tandy->displine][(x << 4) + 8] =
|
||||||
|
buffer->line[tandy->displine][(x << 4) + 9] =
|
||||||
|
buffer->line[tandy->displine][(x << 4) + 10] =
|
||||||
|
buffer->line[tandy->displine][(x << 4) + 11] = tandy->array[((dat >> 12) & tandy->array[1]) + 16] + 16;
|
||||||
|
buffer->line[tandy->displine][(x << 4) + 12] =
|
||||||
|
buffer->line[tandy->displine][(x << 4) + 13] =
|
||||||
|
buffer->line[tandy->displine][(x << 4) + 14] =
|
||||||
|
buffer->line[tandy->displine][(x << 4) + 15] = tandy->array[((dat >> 8) & tandy->array[1]) + 16] + 16;
|
||||||
|
buffer->line[tandy->displine][(x << 4) + 16] =
|
||||||
|
buffer->line[tandy->displine][(x << 4) + 17] =
|
||||||
|
buffer->line[tandy->displine][(x << 4) + 18] =
|
||||||
|
buffer->line[tandy->displine][(x << 4) + 19] = tandy->array[((dat >> 4) & tandy->array[1]) + 16] + 16;
|
||||||
|
buffer->line[tandy->displine][(x << 4) + 20] =
|
||||||
|
buffer->line[tandy->displine][(x << 4) + 21] =
|
||||||
|
buffer->line[tandy->displine][(x << 4) + 22] =
|
||||||
|
buffer->line[tandy->displine][(x << 4) + 23] = tandy->array[(dat & tandy->array[1]) + 16] + 16;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (tandy->array[3] & 0x08) /*640x200x4 - this implementation is a complete guess!*/
|
||||||
|
{
|
||||||
|
for (x = 0; x < tandy->crtc[1]; x++)
|
||||||
|
{
|
||||||
|
dat = (tandy->vram[((tandy->ma << 1) & 0x1fff) + ((tandy->sc & 3) * 0x2000)] << 8) |
|
||||||
|
tandy->vram[((tandy->ma << 1) & 0x1fff) + ((tandy->sc & 3) * 0x2000) + 1];
|
||||||
|
tandy->ma++;
|
||||||
|
for (c = 0; c < 8; c++)
|
||||||
|
{
|
||||||
|
chr = (dat >> 7) & 1;
|
||||||
|
chr |= ((dat >> 14) & 2);
|
||||||
|
buffer->line[tandy->displine][(x << 3) + 8 + c] = tandy->array[(chr & tandy->array[1]) + 16] + 16;
|
||||||
|
dat <<= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (tandy->mode & 1)
|
||||||
|
{
|
||||||
|
for (x = 0; x < tandy->crtc[1]; x++)
|
||||||
|
{
|
||||||
|
chr = tandy->vram[ (tandy->ma << 1) & 0x3fff];
|
||||||
|
attr = tandy->vram[((tandy->ma << 1) + 1) & 0x3fff];
|
||||||
|
drawcursor = ((tandy->ma == ca) && tandy->con && tandy->cursoron);
|
||||||
|
if (tandy->mode & 0x20)
|
||||||
|
{
|
||||||
|
cols[1] = tandy->array[ ((attr & 15) & tandy->array[1]) + 16] + 16;
|
||||||
|
cols[0] = tandy->array[(((attr >> 4) & 7) & tandy->array[1]) + 16] + 16;
|
||||||
|
if ((tandy->blink & 16) && (attr & 0x80) && !drawcursor)
|
||||||
|
cols[1] = cols[0];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cols[1] = tandy->array[((attr & 15) & tandy->array[1]) + 16] + 16;
|
||||||
|
cols[0] = tandy->array[((attr >> 4) & tandy->array[1]) + 16] + 16;
|
||||||
|
}
|
||||||
|
if (tandy->sc & 8)
|
||||||
|
{
|
||||||
|
for (c = 0; c < 8; c++)
|
||||||
|
buffer->line[tandy->displine][(x << 3) + c + 8] = cols[0];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (c = 0; c < 8; c++)
|
||||||
|
buffer->line[tandy->displine][(x << 3) + c + 8] = cols[(fontdat[chr][tandy->sc & 7] & (1 << (c ^ 7))) ? 1 : 0];
|
||||||
|
}
|
||||||
|
// if (!((ma^(crtc[15]|(crtc[14]<<8)))&0x3FFF)) printf("Cursor match! %04X\n",ma);
|
||||||
|
if (drawcursor)
|
||||||
|
{
|
||||||
|
for (c = 0; c < 8; c++)
|
||||||
|
buffer->line[tandy->displine][(x << 3) + c + 8] ^= 15;
|
||||||
|
}
|
||||||
|
tandy->ma++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (!(tandy->mode & 2))
|
||||||
|
{
|
||||||
|
for (x = 0; x < tandy->crtc[1]; x++)
|
||||||
|
{
|
||||||
|
chr = tandy->vram[ (tandy->ma << 1) & 0x3fff];
|
||||||
|
attr = tandy->vram[((tandy->ma << 1) + 1) & 0x3fff];
|
||||||
|
drawcursor = ((tandy->ma == ca) && tandy->con && tandy->cursoron);
|
||||||
|
if (tandy->mode & 0x20)
|
||||||
|
{
|
||||||
|
cols[1] = tandy->array[ ((attr & 15) & tandy->array[1]) + 16] + 16;
|
||||||
|
cols[0] = tandy->array[(((attr >> 4) & 7) & tandy->array[1]) + 16] + 16;
|
||||||
|
if ((tandy->blink & 16) && (attr & 0x80) && !drawcursor)
|
||||||
|
cols[1] = cols[0];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cols[1] = tandy->array[((attr & 15) & tandy->array[1]) + 16] + 16;
|
||||||
|
cols[0] = tandy->array[((attr >> 4) & tandy->array[1]) + 16] + 16;
|
||||||
|
}
|
||||||
|
tandy->ma++;
|
||||||
|
if (tandy->sc & 8)
|
||||||
|
{
|
||||||
|
for (c = 0; c < 8; c++)
|
||||||
|
buffer->line[tandy->displine][(x << 4) + (c << 1) + 8] =
|
||||||
|
buffer->line[tandy->displine][(x << 4) + (c << 1) + 1 + 8] = cols[0];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (c = 0; c < 8; c++)
|
||||||
|
buffer->line[tandy->displine][(x << 4) + (c << 1) + 8] =
|
||||||
|
buffer->line[tandy->displine][(x << 4) + (c << 1) + 1 + 8] = cols[(fontdat[chr][tandy->sc & 7] & (1 << (c ^ 7))) ? 1 : 0];
|
||||||
|
}
|
||||||
|
if (drawcursor)
|
||||||
|
{
|
||||||
|
for (c = 0; c < 16; c++)
|
||||||
|
buffer->line[tandy->displine][(x << 4) + c + 8] ^= 15;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (!(tandy->mode& 16))
|
||||||
|
{
|
||||||
|
cols[0] = (tandy->col & 15) | 16;
|
||||||
|
col = (tandy->col & 16) ? 24 : 16;
|
||||||
|
if (tandy->mode & 4)
|
||||||
|
{
|
||||||
|
cols[1] = col | 3;
|
||||||
|
cols[2] = col | 4;
|
||||||
|
cols[3] = col | 7;
|
||||||
|
}
|
||||||
|
else if (tandy->col & 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 < tandy->crtc[1]; x++)
|
||||||
|
{
|
||||||
|
dat = (tandy->vram[((tandy->ma << 1) & 0x1fff) + ((tandy->sc & 1) * 0x2000)] << 8) |
|
||||||
|
tandy->vram[((tandy->ma << 1) & 0x1fff) + ((tandy->sc & 1) * 0x2000) + 1];
|
||||||
|
tandy->ma++;
|
||||||
|
for (c = 0; c < 8; c++)
|
||||||
|
{
|
||||||
|
buffer->line[tandy->displine][(x << 4) + (c << 1) + 8] =
|
||||||
|
buffer->line[tandy->displine][(x << 4) + (c << 1) + 1 + 8] = cols[dat >> 14];
|
||||||
|
dat <<= 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cols[0] = 0;
|
||||||
|
cols[1] = tandy->array[(tandy->col & tandy->array[1]) + 16] + 16;
|
||||||
|
for (x = 0; x < tandy->crtc[1]; x++)
|
||||||
|
{
|
||||||
|
dat = (tandy->vram[((tandy->ma << 1) & 0x1fff) + ((tandy->sc & 1) * 0x2000)] << 8) |
|
||||||
|
tandy->vram[((tandy->ma << 1) & 0x1fff) + ((tandy->sc & 1) * 0x2000) + 1];
|
||||||
|
tandy->ma++;
|
||||||
|
for (c = 0; c < 16; c++)
|
||||||
|
{
|
||||||
|
buffer->line[tandy->displine][(x << 4) + c + 8] = cols[dat >> 15];
|
||||||
|
dat <<= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (tandy->array[3] & 4)
|
||||||
|
{
|
||||||
|
if (tandy->mode & 1) hline(buffer, 0, tandy->displine, (tandy->crtc[1] << 3) + 16, (tandy->array[2] & 0xf) + 16);
|
||||||
|
else hline(buffer, 0, tandy->displine, (tandy->crtc[1] << 4) + 16, (tandy->array[2] & 0xf) + 16);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cols[0] = ((tandy->mode & 0x12) == 0x12) ? 0 : (tandy->col & 0xf) + 16;
|
||||||
|
if (tandy->mode & 1) hline(buffer, 0, tandy->displine, (tandy->crtc[1] << 3) + 16, cols[0]);
|
||||||
|
else hline(buffer, 0, tandy->displine, (tandy->crtc[1] << 4) + 16, cols[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (tandy->mode & 1) x = (tandy->crtc[1] << 3) + 16;
|
||||||
|
else x = (tandy->crtc[1] << 4) + 16;
|
||||||
|
tandy->sc = oldsc;
|
||||||
|
if (tandy->vc == tandy->crtc[7] && !tandy->sc)
|
||||||
|
{
|
||||||
|
tandy->stat |= 8;
|
||||||
|
// printf("VSYNC on %i %i\n",vc,sc);
|
||||||
|
}
|
||||||
|
tandy->displine++;
|
||||||
|
if (tandy->displine >= 360)
|
||||||
|
tandy->displine = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
tandy->vidtime += tandy->dispontime;
|
||||||
|
if (tandy->dispon)
|
||||||
|
tandy->stat &= ~1;
|
||||||
|
tandy->linepos = 0;
|
||||||
|
if (tandy->vsynctime)
|
||||||
|
{
|
||||||
|
tandy->vsynctime--;
|
||||||
|
if (!tandy->vsynctime)
|
||||||
|
{
|
||||||
|
tandy->stat &= ~8;
|
||||||
|
// printf("VSYNC off %i %i\n",vc,sc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (tandy->sc == (tandy->crtc[11] & 31) || ((tandy->crtc[8] & 3) == 3 && tandy->sc == ((tandy->crtc[11] & 31) >> 1)))
|
||||||
|
{
|
||||||
|
tandy->con = 0;
|
||||||
|
tandy->coff = 1;
|
||||||
|
}
|
||||||
|
if (tandy->vadj)
|
||||||
|
{
|
||||||
|
tandy->sc++;
|
||||||
|
tandy->sc &= 31;
|
||||||
|
tandy->ma = tandy->maback;
|
||||||
|
tandy->vadj--;
|
||||||
|
if (!tandy->vadj)
|
||||||
|
{
|
||||||
|
tandy->dispon = 1;
|
||||||
|
if (tandy->array[5] & 1)
|
||||||
|
tandy->ma = tandy->maback = tandy->crtc[13] | (tandy->crtc[12] << 8);
|
||||||
|
else
|
||||||
|
tandy->ma = tandy->maback = (tandy->crtc[13] | (tandy->crtc[12] << 8)) & 0x3fff;
|
||||||
|
tandy->sc = 0;
|
||||||
|
// printf("Display on!\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (tandy->sc == tandy->crtc[9] || ((tandy->crtc[8] & 3) == 3 && tandy->sc == (tandy->crtc[9] >> 1)))
|
||||||
|
{
|
||||||
|
tandy->maback = tandy->ma;
|
||||||
|
// con=0;
|
||||||
|
// coff=0;
|
||||||
|
tandy->sc = 0;
|
||||||
|
oldvc = tandy->vc;
|
||||||
|
tandy->vc++;
|
||||||
|
tandy->vc &= 255;
|
||||||
|
// printf("VC %i %i %i %i %i\n",vc,crtc[4],crtc[6],crtc[7],tandy->dispon);
|
||||||
|
if (tandy->vc == tandy->crtc[6])
|
||||||
|
{
|
||||||
|
// pclog("Display off\n");
|
||||||
|
tandy->dispon = 0;
|
||||||
|
}
|
||||||
|
if (oldvc == tandy->crtc[4])
|
||||||
|
{
|
||||||
|
// pclog("Display over\n");
|
||||||
|
// printf("Display over at %i\n",tandy->displine);
|
||||||
|
tandy->vc = 0;
|
||||||
|
tandy->vadj = tandy->crtc[5];
|
||||||
|
if (!tandy->vadj)
|
||||||
|
tandy->dispon = 1;
|
||||||
|
if (!tandy->vadj)
|
||||||
|
{
|
||||||
|
if (tandy->array[5] & 1)
|
||||||
|
tandy->ma = tandy->maback = tandy->crtc[13] | (tandy->crtc[12] << 8);
|
||||||
|
else
|
||||||
|
tandy->ma = tandy->maback = (tandy->crtc[13] | (tandy->crtc[12] << 8)) & 0x3fff;
|
||||||
|
}
|
||||||
|
if ((tandy->crtc[10] & 0x60) == 0x20) tandy->cursoron = 0;
|
||||||
|
else tandy->cursoron = tandy->blink & 16;
|
||||||
|
// printf("CRTC10 %02X %i\n",crtc[10],cursoron);
|
||||||
|
}
|
||||||
|
if (tandy->vc == tandy->crtc[7])
|
||||||
|
{
|
||||||
|
tandy->dispon = 0;
|
||||||
|
tandy->displine = 0;
|
||||||
|
tandy->vsynctime = 16;//(crtc[3]>>4)+1;
|
||||||
|
// printf("tandy->vsynctime %i %02X\n",tandy->vsynctime,crtc[3]);
|
||||||
|
// tandy->stat|=8;
|
||||||
|
if (tandy->crtc[7])
|
||||||
|
{
|
||||||
|
// printf("Lastline %i Firstline %i %i %i %i\n",lastline,firstline,lastline-firstline,crtc[1],xsize);
|
||||||
|
if (tandy->mode & 1) x = (tandy->crtc[1] << 3) + 16;
|
||||||
|
else x = (tandy->crtc[1] << 4) + 16;
|
||||||
|
tandy->lastline++;
|
||||||
|
if (x != xsize || (tandy->lastline - tandy->firstline) != ysize)
|
||||||
|
{
|
||||||
|
xsize = x;
|
||||||
|
ysize = tandy->lastline - tandy->firstline;
|
||||||
|
// printf("Resize to %i,%i - R1 %i\n",xsize,ysize,crtc[1]);
|
||||||
|
if (xsize < 64) xsize = 656;
|
||||||
|
if (ysize < 32) ysize = 200;
|
||||||
|
updatewindowsize(xsize, (ysize << 1) + 16);
|
||||||
|
}
|
||||||
|
// printf("Blit %i %i\n",firstline,lastline);
|
||||||
|
//printf("Xsize is %i\n",xsize);
|
||||||
|
startblit();
|
||||||
|
video_blit_memtoscreen_8(0, tandy->firstline-4, xsize, (tandy->lastline - tandy->firstline) + 8);
|
||||||
|
endblit();
|
||||||
|
frames++;
|
||||||
|
video_res_x = xsize - 16;
|
||||||
|
video_res_y = ysize;
|
||||||
|
if ((tandy->array[3] & 0x10) && (tandy->mode & 1)) /*320x200x16*/
|
||||||
|
{
|
||||||
|
video_res_x /= 2;
|
||||||
|
video_bpp = 4;
|
||||||
|
}
|
||||||
|
else if (tandy->array[3] & 0x10) /*160x200x16*/
|
||||||
|
{
|
||||||
|
video_res_x /= 4;
|
||||||
|
video_bpp = 4;
|
||||||
|
}
|
||||||
|
else if (tandy->array[3] & 0x08) /*640x200x4 - this implementation is a complete guess!*/
|
||||||
|
video_bpp = 2;
|
||||||
|
else if (tandy->mode & 1)
|
||||||
|
{
|
||||||
|
video_res_x /= 8;
|
||||||
|
video_res_y /= tandy->crtc[9] + 1;
|
||||||
|
video_bpp = 0;
|
||||||
|
}
|
||||||
|
else if (!(tandy->mode & 2))
|
||||||
|
{
|
||||||
|
video_res_x /= 16;
|
||||||
|
video_res_y /= tandy->crtc[9] + 1;
|
||||||
|
video_bpp = 0;
|
||||||
|
}
|
||||||
|
else if (!(tandy->mode & 16))
|
||||||
|
{
|
||||||
|
video_res_x /= 2;
|
||||||
|
video_bpp = 2;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
video_bpp = 1;
|
||||||
|
}
|
||||||
|
tandy->firstline = 1000;
|
||||||
|
tandy->lastline = 0;
|
||||||
|
tandy->blink++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
tandy->sc++;
|
||||||
|
tandy->sc &= 31;
|
||||||
|
tandy->ma = tandy->maback;
|
||||||
|
}
|
||||||
|
if ((tandy->sc == (tandy->crtc[10] & 31) || ((tandy->crtc[8] & 3) == 3 && tandy->sc == ((tandy->crtc[10] & 31) >> 1))))
|
||||||
|
tandy->con = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *tandysl_init()
|
||||||
|
{
|
||||||
|
int c;
|
||||||
|
tandysl_t *tandy = malloc(sizeof(tandysl_t));
|
||||||
|
memset(tandy, 0, sizeof(tandysl_t));
|
||||||
|
|
||||||
|
tandy->memctrl = -1;
|
||||||
|
tandy->base = (mem_size - 128) * 1024;
|
||||||
|
tandy->b8000_limit = 0x8000;
|
||||||
|
tandy->planar_ctrl = 4;
|
||||||
|
|
||||||
|
timer_add(tandysl_poll, &tandy->vidtime, TIMER_ALWAYS_ENABLED, tandy);
|
||||||
|
mem_mapping_add(&tandy->mapping, 0xb8000, 0x08000, tandysl_read, NULL, NULL, tandysl_write, NULL, NULL, NULL, 0, tandy);
|
||||||
|
mem_mapping_add(&tandy->ram_mapping, 0x80000, 0x20000, tandysl_ram_read, NULL, NULL, tandysl_ram_write, NULL, NULL, NULL, 0, tandy);
|
||||||
|
/*Base 128k mapping is controlled via port 0xffe8, so we remove it from the main mapping*/
|
||||||
|
mem_mapping_set_addr(&ram_low_mapping, 0, (mem_size - 128) * 1024);
|
||||||
|
io_sethandler(0x03d0, 0x0010, tandysl_in, NULL, NULL, tandysl_out, NULL, NULL, tandy);
|
||||||
|
io_sethandler(0xffe8, 0x0001, tandysl_in, NULL, NULL, tandysl_out, NULL, NULL, tandy);
|
||||||
|
io_sethandler(0x0065, 0x0001, tandysl_in, NULL, NULL, tandysl_out, NULL, NULL, tandy);
|
||||||
|
return tandy;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tandysl_close(void *p)
|
||||||
|
{
|
||||||
|
tandysl_t *tandy = (tandysl_t *)p;
|
||||||
|
|
||||||
|
free(tandy);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tandysl_speed_changed(void *p)
|
||||||
|
{
|
||||||
|
tandysl_t *tandy = (tandysl_t *)p;
|
||||||
|
|
||||||
|
tandysl_recalctimings(tandy);
|
||||||
|
}
|
||||||
|
|
||||||
|
device_t tandysl_device =
|
||||||
|
{
|
||||||
|
"Tandy 1000SL (video)",
|
||||||
|
0,
|
||||||
|
tandysl_init,
|
||||||
|
tandysl_close,
|
||||||
|
NULL,
|
||||||
|
tandysl_speed_changed,
|
||||||
|
NULL,
|
||||||
|
NULL
|
||||||
|
};
|
||||||
1
src/vid_tandysl.h
Normal file
1
src/vid_tandysl.h
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
extern device_t tandysl_device;
|
||||||
|
|
@ -31,6 +31,7 @@
|
||||||
#include "vid_s3.h"
|
#include "vid_s3.h"
|
||||||
#include "vid_s3_virge.h"
|
#include "vid_s3_virge.h"
|
||||||
#include "vid_tandy.h"
|
#include "vid_tandy.h"
|
||||||
|
#include "vid_tandysl.h"
|
||||||
#include "vid_tgui9440.h"
|
#include "vid_tgui9440.h"
|
||||||
#include "vid_tvga.h"
|
#include "vid_tvga.h"
|
||||||
#include "vid_vga.h"
|
#include "vid_vga.h"
|
||||||
|
|
@ -223,9 +224,14 @@ void video_init()
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case ROM_TANDY:
|
case ROM_TANDY:
|
||||||
|
case ROM_TANDY1000HX:
|
||||||
device_add(&tandy_device);
|
device_add(&tandy_device);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
case ROM_TANDY1000SL2:
|
||||||
|
device_add(&tandysl_device);
|
||||||
|
return;
|
||||||
|
|
||||||
case ROM_PC1512:
|
case ROM_PC1512:
|
||||||
device_add(&pc1512_device);
|
device_add(&pc1512_device);
|
||||||
return;
|
return;
|
||||||
|
|
|
||||||
|
|
@ -220,15 +220,6 @@ static BOOL CALLBACK config_dlgproc(HWND hdlg, UINT message, WPARAM wParam, LPAR
|
||||||
mem = models[temp_model].min_ram;
|
mem = models[temp_model].min_ram;
|
||||||
else if (mem > models[temp_model].max_ram)
|
else if (mem > models[temp_model].max_ram)
|
||||||
mem = models[temp_model].max_ram;
|
mem = models[temp_model].max_ram;
|
||||||
if ((models[temp_model].is_at && (mem < 1 || mem > 256)) ||
|
|
||||||
(!models[temp_model].is_at && (mem < 64 || mem > 640)))
|
|
||||||
{
|
|
||||||
if (models[temp_model].is_at)
|
|
||||||
MessageBox(NULL, "Invalid memory size\nMemory must be between 1 and 256 MB", "PCem", MB_OK);
|
|
||||||
else
|
|
||||||
MessageBox(NULL, "Invalid memory size\nMemory must be between 64 and 640 kB", "PCem", MB_OK);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (models[temp_model].is_at)
|
if (models[temp_model].is_at)
|
||||||
mem *= 1024;
|
mem *= 1024;
|
||||||
|
|
||||||
|
|
|
||||||
BIN
tandy1000hx.bin
Normal file
BIN
tandy1000hx.bin
Normal file
Binary file not shown.
BIN
tandy1000sl2.bin
Normal file
BIN
tandy1000sl2.bin
Normal file
Binary file not shown.
Loading…
Reference in a new issue