From 2ca86ba0280e261c75509bb1d10d1808e8dcd0c9 Mon Sep 17 00:00:00 2001 From: TomW Date: Thu, 3 Dec 2015 21:48:10 +0000 Subject: [PATCH] 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 --- src/Makefile.mingw | 6 +- src/cpu.c | 11 +- src/fdc.c | 16 +- src/fdc.h | 1 + src/ibm.h | 2 + src/keyboard_xt.c | 25 +- src/keyboard_xt.h | 1 + src/mem.c | 34 +- src/model.c | 27 +- src/sound_pssj.c | 212 +++++++++++++ src/sound_pssj.h | 1 + src/sound_sn76489.c | 88 ++++-- src/sound_sn76489.h | 28 ++ src/tandy_eeprom.c | 178 +++++++++++ src/tandy_eeprom.h | 2 + src/tandy_rom.c | 94 ++++++ src/tandy_rom.h | 1 + src/vid_tandy.c | 9 +- src/vid_tandysl.c | 732 ++++++++++++++++++++++++++++++++++++++++++++ src/vid_tandysl.h | 1 + src/video.c | 6 + src/win-config.c | 9 - tandy1000hx.bin | Bin 0 -> 128 bytes tandy1000sl2.bin | Bin 0 -> 128 bytes 24 files changed, 1420 insertions(+), 64 deletions(-) create mode 100644 src/sound_pssj.c create mode 100644 src/sound_pssj.h create mode 100644 src/tandy_eeprom.c create mode 100644 src/tandy_eeprom.h create mode 100644 src/tandy_rom.c create mode 100644 src/tandy_rom.h create mode 100644 src/vid_tandysl.c create mode 100644 src/vid_tandysl.h create mode 100644 tandy1000hx.bin create mode 100644 tandy1000sl2.bin diff --git a/src/Makefile.mingw b/src/Makefile.mingw index 7033fbd..60cfbf4 100644 --- a/src/Makefile.mingw +++ b/src/Makefile.mingw @@ -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 \ 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 \ - 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 \ - 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_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_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 \ 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 diff --git a/src/cpu.c b/src/cpu.c index 43636cc..a8a1db2 100644 --- a/src/cpu.c +++ b/src/cpu.c @@ -109,11 +109,12 @@ static struct CPU cpus_8088[] = { /*8088 standard*/ - {"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/10", CPU_8088, 2, 10000000, 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}, + {"8088/4.77", CPU_8088, 0, 4772728, 1, 0, 0, 0, 0, 0}, + {"8088/7.16", CPU_8088, 1, 14318184/2, 1, 0, 0, 0, 0, 0}, + {"8088/8", CPU_8088, 1, 8000000, 1, 0, 0, 0, 0, 0}, + {"8088/10", CPU_8088, 2, 10000000, 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} }; diff --git a/src/fdc.c b/src/fdc.c index 14d24bf..3128865 100644 --- a/src/fdc.c +++ b/src/fdc.c @@ -120,6 +120,7 @@ void fdc_write(uint16_t addr, uint8_t val, void *priv) fdc_reset(); } motoron = val & 0x01; + fdc.drive = 0; /* if (motoron) output = 3; else @@ -143,6 +144,7 @@ void fdc_write(uint16_t addr, uint8_t val, void *priv) timer_process(); motoron = (val & 0xf0) ? 1 : 0; timer_update_outstanding(); + fdc.drive = val & 3; } fdc.dor=val; // printf("DOR now %02X\n",val); @@ -299,7 +301,7 @@ void fdc_write(uint16_t addr, uint8_t val, void *priv) timer_process(); disctime = 1024 * (1 << TIMER_SHIFT); timer_update_outstanding(); - fdc.drive = fdc.params[0] & 3; +// fdc.drive = fdc.params[0] & 3; disc_drivesel = fdc.drive & 1; fdc_reset_stat = 0; switch (discint) @@ -456,7 +458,7 @@ uint8_t fdc_read(uint16_t addr, void *priv) break; case 7: /*Disk change*/ 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 temp = 0; if (fdc.dskchg_activelow) /*PC2086/3086 seem to reverse this bit*/ @@ -626,7 +628,10 @@ void fdc_callback() case 7: /*Recalibrate*/ fdc.track[fdc.drive]=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; timer_process(); disctime = 2048 * (1 << TIMER_SHIFT); @@ -708,7 +713,10 @@ void fdc_callback() 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.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; timer_process(); disctime = 2048 * (1 << TIMER_SHIFT); diff --git a/src/fdc.h b/src/fdc.h index 8c5fdc3..15d63fa 100644 --- a/src/fdc.h +++ b/src/fdc.h @@ -1,6 +1,7 @@ void fdc_init(); void fdc_add(); void fdc_add_pcjr(); +void fdc_add_tandy(); void fdc_remove(); void fdc_reset(); void fdc_poll(); diff --git a/src/ibm.h b/src/ibm.h index 66f0703..2addd87 100644 --- a/src/ibm.h +++ b/src/ibm.h @@ -300,6 +300,8 @@ enum ROM_DTK386, ROM_PXXT, ROM_JUKOPC, + ROM_TANDY1000HX, + ROM_TANDY1000SL2, ROM_IBMAT, ROM_CMDPC30, ROM_AMI286, diff --git a/src/keyboard_xt.c b/src/keyboard_xt.c index ac914f8..8ff395f 100644 --- a/src/keyboard_xt.c +++ b/src/keyboard_xt.c @@ -25,6 +25,8 @@ struct uint8_t pa; uint8_t pb; + + int tandy; } keyboard_xt; 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) { - 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) { output = 3; @@ -67,7 +69,7 @@ void keyboard_xt_write(uint16_t port, uint8_t val, void *priv) 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)); +// 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"); @@ -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 temp; - pclog("keyboard_xt : read %04X ", port); +// pclog("keyboard_xt : read %04X ", port); switch (port) { case 0x60: @@ -153,6 +155,8 @@ uint8_t keyboard_xt_read(uint16_t port, void *priv) temp = 0xD; } temp |= (ppispeakon ? 0x20 : 0); + if (keyboard_xt.tandy) + temp |= (tandy_eeprom_read() ? 0x10 : 0); break; default: @@ -160,7 +164,7 @@ uint8_t keyboard_xt_read(uint16_t port, void *priv) //dumpregs(); //exit(-1); } - pclog("%02X\n", temp); +// pclog("%02X\n", temp); return temp; } @@ -178,6 +182,19 @@ void keyboard_xt_init() keyboard_xt_reset(); keyboard_send = keyboard_xt_adddata; 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); +} diff --git a/src/keyboard_xt.h b/src/keyboard_xt.h index 5da623a..14f4faa 100644 --- a/src/keyboard_xt.h +++ b/src/keyboard_xt.h @@ -1,3 +1,4 @@ void keyboard_xt_init(); +void keyboard_tandy_init(); void keyboard_xt_reset(); void keyboard_xt_poll(); diff --git a/src/mem.c b/src/mem.c index d9838a7..991d199 100644 --- a/src/mem.c +++ b/src/mem.c @@ -163,6 +163,29 @@ int loadbios() fclose(f); mem_load_xtide_bios(); 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: f=fopen("pcjr/bios.rom","rb"); 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() { - 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[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); + if (AT) + { + 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[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[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); diff --git a/src/model.c b/src/model.c index fcbcb53..f984bda 100644 --- a/src/model.c +++ b/src/model.c @@ -39,7 +39,10 @@ #include "ps1.h" #include "serial.h" #include "sis496.h" +#include "sound_pssj.h" #include "sound_sn76489.h" +#include "tandy_eeprom.h" +#include "tandy_rom.h" #include "um8669f.h" #include "um8881f.h" #include "wd76c10.h" @@ -48,6 +51,7 @@ void xt_init(); void pcjr_init(); void tandy1k_init(); +void tandy1ksl2_init(); void ams_init(); void europc_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}, {"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 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}, {"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}, @@ -177,11 +183,28 @@ void tandy1k_init() { TANDY = 1; common_init(); - keyboard_xt_init(); + keyboard_tandy_init(); mouse_serial_init(); - device_add(&sn76489_device); + if (romset == ROM_TANDY) + device_add(&sn76489_device); + else + device_add(&ncr8496_device); xtide_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() diff --git a/src/sound_pssj.c b/src/sound_pssj.c new file mode 100644 index 0000000..2e6064d --- /dev/null +++ b/src/sound_pssj.c @@ -0,0 +1,212 @@ +#include +#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 +}; diff --git a/src/sound_pssj.h b/src/sound_pssj.h new file mode 100644 index 0000000..36b2fda --- /dev/null +++ b/src/sound_pssj.h @@ -0,0 +1 @@ +extern device_t pssj_device; diff --git a/src/sound_sn76489.c b/src/sound_sn76489.c index 63006aa..ee7542e 100644 --- a/src/sound_sn76489.c +++ b/src/sound_sn76489.c @@ -15,21 +15,6 @@ static float volslog[16]= 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) void sn76489_poll(void *p) @@ -104,8 +89,10 @@ void sn76489_write(uint16_t addr, uint8_t data, void *p) case 0: sn76489->freqlo[3] = data & 0xf; sn76489->latch[3] = (sn76489->freqlo[3] | (sn76489->freqhi[3] << 4)) << 6; + if (sn76489->extra_divide) + sn76489->latch[3] &= 0x3ff; if (!sn76489->latch[3]) - sn76489->latch[3] = 1024 << 6; + sn76489->latch[3] = (sn76489->extra_divide ? 2048 : 1024) << 6; sn76489->lasttone = 3; break; case 0x10: @@ -115,8 +102,10 @@ void sn76489_write(uint16_t addr, uint8_t data, void *p) case 0x20: sn76489->freqlo[2] = data & 0xf; sn76489->latch[2] = (sn76489->freqlo[2] | (sn76489->freqhi[2] << 4)) << 6; + if (sn76489->extra_divide) + sn76489->latch[2] &= 0x3ff; if (!sn76489->latch[2]) - sn76489->latch[2] = 1024 << 6; + sn76489->latch[2] = (sn76489->extra_divide ? 2048 : 1024) << 6; sn76489->lasttone = 2; break; case 0x30: @@ -126,8 +115,10 @@ void sn76489_write(uint16_t addr, uint8_t data, void *p) case 0x40: sn76489->freqlo[1] = data & 0xf; sn76489->latch[1] = (sn76489->freqlo[1] | (sn76489->freqhi[1] << 4)) << 6; + if (sn76489->extra_divide) + sn76489->latch[1] &= 0x3ff; if (!sn76489->latch[1]) - sn76489->latch[1] = 1024 << 6; + sn76489->latch[1] = (sn76489->extra_divide ? 2048 : 1024) << 6; sn76489->lasttone = 1; break; case 0x50: @@ -135,13 +126,15 @@ void sn76489_write(uint16_t addr, uint8_t data, void *p) sn76489->vol[1] = 0xf - data; break; case 0x60: - if ((data & 4) != (sn76489->noise & 4)) + if ((data & 4) != (sn76489->noise & 4) || sn76489->type == SN76496) sn76489->shift = 0x4000; sn76489->noise = data & 0xf; if ((data & 3) == 3) sn76489->latch[0] = sn76489->latch[1]; else sn76489->latch[0] = 0x400 << (data & 3); + if (sn76489->extra_divide) + sn76489->latch[0] &= 0x3ff; if (!sn76489->latch[0]) - sn76489->latch[0] = 1024 << 6; + sn76489->latch[0] = (sn76489->extra_divide ? 2048 : 1024) << 6; break; case 0x70: data &= 0xf; @@ -153,7 +146,7 @@ void sn76489_write(uint16_t addr, uint8_t data, void *p) { if ((sn76489->firstdat & 0x70) == 0x60) { - if ((data & 4) != (sn76489->noise & 4)) + if ((data & 4) != (sn76489->noise & 4) || sn76489->type == SN76496) sn76489->shift = 0x4000; sn76489->noise = data & 0xf; 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 { - sn76489->freqhi[sn76489->lasttone] = data & 0x3F; + sn76489->freqhi[sn76489->lasttone] = data & 0x7F; freq = sn76489->freqlo[sn76489->lasttone] | (sn76489->freqhi[sn76489->lasttone] << 4); + if (sn76489->extra_divide) + freq &= 0x3ff; if (!freq) - freq = 1024; + freq = sn76489->extra_divide ? 2048 : 1024; if ((sn76489->noise & 3) == 3 && sn76489->lasttone == 1) sn76489->latch[0] = 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)); - memset(sn76489, 0, sizeof(sn76489_t)); - - io_sethandler(0x00C0, 0x0008, NULL, NULL, NULL, sn76489_write, NULL, NULL, sn76489); + sn76489->extra_divide = enable; +} +void sn76489_init(sn76489_t *sn76489, uint16_t base, uint16_t size, int type) +{ sound_add_handler(sn76489_poll, sn76489_get_buffer, sn76489); 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->noise = 3; sn76489->shift = 0x4000; + sn76489->type = type; 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; } -void sn76489_close(void *p) +void sn76489_device_close(void *p) { sn76489_t *sn76489 = (sn76489_t *)p; @@ -211,8 +226,19 @@ device_t sn76489_device = { "TI SN74689 PSG", 0, - sn76489_init, - sn76489_close, + sn76489_device_init, + sn76489_device_close, + NULL, + NULL, + NULL, + NULL +}; +device_t ncr8496_device = +{ + "NCR8496 PSG", + 0, + ncr8496_device_init, + sn76489_device_close, NULL, NULL, NULL, diff --git a/src/sound_sn76489.h b/src/sound_sn76489.h index 5a7ff15..b311e0f 100644 --- a/src/sound_sn76489.h +++ b/src/sound_sn76489.h @@ -1,3 +1,31 @@ +enum +{ + SN76496, + NCR8496, + PSSJ +}; + extern device_t sn76489_device; +extern device_t ncr8496_device; 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); diff --git a/src/tandy_eeprom.c b/src/tandy_eeprom.c new file mode 100644 index 0000000..690f375 --- /dev/null +++ b/src/tandy_eeprom.c @@ -0,0 +1,178 @@ +#include +#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 +}; diff --git a/src/tandy_eeprom.h b/src/tandy_eeprom.h new file mode 100644 index 0000000..2619988 --- /dev/null +++ b/src/tandy_eeprom.h @@ -0,0 +1,2 @@ +device_t tandy_eeprom_device; +int tandy_eeprom_read(); diff --git a/src/tandy_rom.c b/src/tandy_rom.c new file mode 100644 index 0000000..f1fc9cf --- /dev/null +++ b/src/tandy_rom.c @@ -0,0 +1,94 @@ +#include +#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 +}; diff --git a/src/tandy_rom.h b/src/tandy_rom.h new file mode 100644 index 0000000..a48e0c2 --- /dev/null +++ b/src/tandy_rom.h @@ -0,0 +1 @@ +extern device_t tandy_rom_device; diff --git a/src/vid_tandy.c b/src/vid_tandy.c index 282c050..87b618a 100644 --- a/src/vid_tandy.c +++ b/src/vid_tandy.c @@ -26,6 +26,7 @@ typedef struct tandy_t uint8_t stat; uint8_t *vram, *b8000; + uint32_t b8000_mask; int linepos, displine; int sc, vc; @@ -116,12 +117,14 @@ void tandy_recalcaddress(tandy_t *tandy) { tandy->vram = &ram[((tandy->memctrl & 0x06) << 14) + 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); } else { tandy->vram = &ram[((tandy->memctrl & 0x07) << 14) + 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); } } @@ -148,7 +151,7 @@ void tandy_write(uint32_t addr, uint8_t val, void *p) egawrites++; // 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) @@ -159,7 +162,7 @@ uint8_t tandy_read(uint32_t addr, void *p) egareads++; // 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) @@ -689,6 +692,8 @@ void *tandy_init() 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(0x00a0, 0x0001, tandy_in, NULL, NULL, tandy_out, NULL, NULL, tandy); + tandy->b8000_mask = 0x3fff; + return tandy; } diff --git a/src/vid_tandysl.c b/src/vid_tandysl.c new file mode 100644 index 0000000..cacc20b --- /dev/null +++ b/src/vid_tandysl.c @@ -0,0 +1,732 @@ +#include +#include +#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 +}; diff --git a/src/vid_tandysl.h b/src/vid_tandysl.h new file mode 100644 index 0000000..930458c --- /dev/null +++ b/src/vid_tandysl.h @@ -0,0 +1 @@ +extern device_t tandysl_device; diff --git a/src/video.c b/src/video.c index c089c34..eda8cef 100644 --- a/src/video.c +++ b/src/video.c @@ -31,6 +31,7 @@ #include "vid_s3.h" #include "vid_s3_virge.h" #include "vid_tandy.h" +#include "vid_tandysl.h" #include "vid_tgui9440.h" #include "vid_tvga.h" #include "vid_vga.h" @@ -223,9 +224,14 @@ void video_init() return; case ROM_TANDY: + case ROM_TANDY1000HX: device_add(&tandy_device); return; + case ROM_TANDY1000SL2: + device_add(&tandysl_device); + return; + case ROM_PC1512: device_add(&pc1512_device); return; diff --git a/src/win-config.c b/src/win-config.c index caf6787..bba6bca 100644 --- a/src/win-config.c +++ b/src/win-config.c @@ -220,15 +220,6 @@ static BOOL CALLBACK config_dlgproc(HWND hdlg, UINT message, WPARAM wParam, LPAR mem = models[temp_model].min_ram; else if (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) mem *= 1024; diff --git a/tandy1000hx.bin b/tandy1000hx.bin new file mode 100644 index 0000000000000000000000000000000000000000..e69de4f70c501f509338dbd84801ec54367ceb4f GIT binary patch literal 128 TcmZQzU|=w0W?*0e(gOhi8;t-t literal 0 HcmV?d00001 diff --git a/tandy1000sl2.bin b/tandy1000sl2.bin new file mode 100644 index 0000000000000000000000000000000000000000..e69de4f70c501f509338dbd84801ec54367ceb4f GIT binary patch literal 128 TcmZQzU|=w0W?*0e(gOhi8;t-t literal 0 HcmV?d00001