Add read-only cassette emulation to IBM 5150 PC. Patch from JohnElliott.
This commit is contained in:
parent
750d7021e4
commit
84a098bc98
18 changed files with 1891 additions and 1136 deletions
|
|
@ -3484,14 +3484,6 @@ void execx86(int cycs)
|
|||
// if (instime) printf("%i %i %i %i\n",cycdiff,cycles,memcycs,fetchclocks);
|
||||
FETCHADD(((cycdiff-cycles)-memcycs)-fetchclocks);
|
||||
if ((cycdiff-cycles)<memcycs) cycles-=(memcycs-(cycdiff-cycles));
|
||||
if (romset==ROM_IBMPC)
|
||||
{
|
||||
if ((cs+cpu_state.pc)==0xFE4A7) /*You didn't seriously think I was going to emulate the cassette, did you?*/
|
||||
{
|
||||
CX=1;
|
||||
BX=0x500;
|
||||
}
|
||||
}
|
||||
memcycs=0;
|
||||
|
||||
insc++;
|
||||
|
|
|
|||
|
|
@ -23,13 +23,13 @@ wx-resources.cpp : pc.xrc
|
|||
-wxrc -c pc.xrc -o wx-resources.cpp
|
||||
|
||||
# PCem
|
||||
pcem_SOURCES = 386.c 386_dynarec.c 386_dynarec_ops.c 808x.c acc2036.c acc2168.c acc3221.c acer386sx.c ali1429.c amstrad.c cbm_io.c cdrom-image.cc cdrom-null.c \
|
||||
pcem_SOURCES = 386.c 386_dynarec.c 386_dynarec_ops.c 808x.c acc2036.c acc2168.c acc3221.c acer386sx.c ali1429.c amstrad.c cassette.c cbm_io.c cdrom-image.cc cdrom-null.c \
|
||||
cmd640.c codegen.c codegen_ops.c codegen_timing_486.c codegen_timing_686.c codegen_timing_common.c codegen_timing_pentium.c codegen_timing_winchip.c compaq.c config.c cpu.c \
|
||||
dells200.c device.c disc.c disc_fdi.c disc_img.c disc_sector.c dma.c esdi_at.c fdc.c fdc37c665.c fdd.c fdi2raw.c gameport.c \
|
||||
hdd.c hdd_esdi.c hdd_file.c headland.c i430hx.c i430lx.c i430fx.c i430vx.c ide.c ide_atapi.c intel.c intel_flash.c io.c jim.c joystick_ch_flightstick_pro.c joystick_standard.c joystick_sw_pad.c \
|
||||
joystick_tm_fcs.c keyboard.c keyboard_amstrad.c keyboard_at.c keyboard_olim24.c keyboard_pcjr.c keyboard_xt.c \
|
||||
laserxt.c lpt.c lpt_dac.c lpt_dss.c mca.c mcr.c mem.c mem_bios.c mfm_at.c mfm_xebec.c model.c mouse.c mouse_msystems.c mouse_ps2.c mouse_serial.c neat.c nmi.c nvr.c olivetti_m24.c \
|
||||
opti495.c paths.c pc.c pc87306.c pci.c pic.c piix.c pit.c ppi.c ps1.c ps2.c ps2_mca.c ps2_nvr.c nvr_tc8521.c rom.c rtc.c rtc_tc8521.c scat.c scsi.c scsi_53c400.c scsi_aha1540.c scsi_cd.c scsi_hd.c scsi_zip.c \
|
||||
opti495.c paths.c pc.c pc87306.c pci.c pic.c piix.c pit.c ppi.c ps1.c ps2.c ps2_mca.c ps2_nvr.c nvr_tc8521.c pzx.c rom.c rtc.c rtc_tc8521.c scat.c scsi.c scsi_53c400.c scsi_aha1540.c scsi_cd.c scsi_hd.c scsi_zip.c \
|
||||
serial.c sio.c sis496.c sl82c460.c sound.c sound_ad1848.c sound_adlib.c sound_adlibgold.c sound_audiopci.c sound_cms.c sound_emu8k.c sound_gus.c \
|
||||
sound_mpu401_uart.c sound_opl.c sound_pas16.c sound_ps1.c sound_pssj.c sound_sb.c sound_sb_dsp.c sound_sn76489.c \
|
||||
sound_speaker.c sound_ssi2001.c sound_wss.c sound_ym7128.c soundopenal.c tandy_eeprom.c tandy_rom.c \
|
||||
|
|
|
|||
|
|
@ -4,13 +4,13 @@ CC = gcc
|
|||
WXRC = wxrc
|
||||
CFLAGS = -O3 -fomit-frame-pointer -msse2 -m32 $(shell wx-config --cxxflags) $(shell sdl2-config --cflags)
|
||||
CXXFLAGS = $(CFLAGS)
|
||||
OBJ = 386.o 386_dynarec.o 386_dynarec_ops.o 808x.o acc2036.o acc2168.o acc3221.o acer386sx.o ali1429.o amstrad.o cbm_io.o cdrom-ioctl-linux.o cdrom-image.o cdrom-null.o \
|
||||
OBJ = 386.o 386_dynarec.o 386_dynarec_ops.o 808x.o acc2036.o acc2168.o acc3221.o acer386sx.o ali1429.o amstrad.o cassette.o cbm_io.o cdrom-ioctl-linux.o cdrom-image.o cdrom-null.o \
|
||||
cmd640.o codegen.o codegen_ops.o codegen_timing_486.o codegen_timing_686.o codegen_timing_common.o codegen_timing_pentium.o codegen_timing_winchip.o codegen_x86.c compaq.o config.o cpu.o \
|
||||
dells200.o device.o disc.o disc_fdi.o disc_img.o disc_sector.o dma.o esdi_at.o fdc.o fdc37c665.o fdd.o fdi2raw.o gameport.o \
|
||||
hdd.o hdd_esdi.o hdd_file.o headland.o i430hx.o i430lx.o i430fx.o i430vx.o ide.o ide_atapi.o intel.o intel_flash.o io.o jim.o joystick_ch_flightstick_pro.o joystick_standard.o joystick_sw_pad.o \
|
||||
joystick_tm_fcs.o keyboard.o keyboard_amstrad.o keyboard_at.o keyboard_olim24.o keyboard_pcjr.o keyboard_xt.o \
|
||||
laserxt.o lpt.o lpt_dac.o lpt_dss.o mca.o mcr.o mem.o mem_bios.o mfm_at.o mfm_xebec.o model.o mouse.o mouse_msystems.o mouse_ps2.o mouse_serial.o neat.o nmi.o nvr.o nvr_tc8521.o olivetti_m24.o \
|
||||
opti495.o paths.o pc.o pc87306.o pci.o pic.o piix.o pit.o ppi.o ps1.o ps2.o ps2_mca.o ps2_nvr.o rom.o rtc.o rtc_tc8521.o scat.o scsi.o scsi_53c400.o scsi_aha1540.o scsi_cd.o scsi_hd.o scsi_zip.o \
|
||||
opti495.o paths.o pc.o pc87306.o pci.o pic.o piix.o pit.o ppi.o ps1.o ps2.o ps2_mca.o ps2_nvr.o pzx.o rom.o rtc.o rtc_tc8521.o scat.o scsi.o scsi_53c400.o scsi_aha1540.o scsi_cd.o scsi_hd.o scsi_zip.o \
|
||||
serial.o sio.o sis496.o sl82c460.o sound.o sound_ad1848.o sound_adlib.o sound_adlibgold.o sound_audiopci.o sound_cms.o sound_emu8k.o sound_gus.o \
|
||||
sound_mpu401_uart.o sound_opl.o sound_pas16.o sound_ps1.o sound_pssj.o sound_sb.o sound_sb_dsp.o sound_sn76489.o \
|
||||
sound_speaker.o sound_ssi2001.o sound_wss.o sound_ym7128.o soundopenal.o t1000.o t3100e.o tandy_eeprom.o tandy_rom.o \
|
||||
|
|
|
|||
|
|
@ -4,13 +4,13 @@ CC = gcc
|
|||
WXRC = wxrc
|
||||
CFLAGS = -O3 -fomit-frame-pointer -msse2 -m64 $(shell wx-config --cxxflags) $(shell sdl2-config --cflags)
|
||||
CXXFLAGS = $(CFLAGS)
|
||||
OBJ = 386.o 386_dynarec.o 386_dynarec_ops.o 808x.o acc2036.o acc2168.o acc3221.o acer386sx.o ali1429.o amstrad.o cbm_io.o cdrom-ioctl-linux.o cdrom-image.o cdrom-null.o \
|
||||
OBJ = 386.o 386_dynarec.o 386_dynarec_ops.o 808x.o acc2036.o acc2168.o acc3221.o acer386sx.o ali1429.o amstrad.o cassette.o cbm_io.o cdrom-ioctl-linux.o cdrom-image.o cdrom-null.o \
|
||||
cmd640.o codegen.o codegen_ops.o codegen_timing_486.o codegen_timing_686.o codegen_timing_common.o codegen_timing_pentium.o codegen_timing_winchip.o codegen_x86-64.c compaq.o config.o cpu.o \
|
||||
dells200.o device.o disc.o disc_fdi.o disc_img.o disc_sector.o dma.o esdi_at.o fdc.o fdc37c665.o fdd.o fdi2raw.o gameport.o \
|
||||
hdd.o hdd_esdi.o hdd_file.o headland.o i430hx.o i430lx.o i430fx.o i430vx.o ide.o ide_atapi.o intel.o intel_flash.o io.o jim.o joystick_ch_flightstick_pro.o joystick_standard.o joystick_sw_pad.o \
|
||||
joystick_tm_fcs.o keyboard.o keyboard_amstrad.o keyboard_at.o keyboard_olim24.o keyboard_pcjr.o keyboard_xt.o \
|
||||
laserxt.o lpt.o lpt_dac.o lpt_dss.o mca.o mcr.o mem.o mem_bios.o mfm_at.o mfm_xebec.o model.o mouse.o mouse_msystems.o mouse_ps2.o mouse_serial.o neat.o nmi.o nvr.o nvr_tc8521.o olivetti_m24.o \
|
||||
opti495.o paths.o pc.o pc87306.o pci.o pic.o piix.o pit.o ppi.o ps1.o ps2.o ps2_mca.o ps2_nvr.o rom.o rtc.o rtc_tc8521.o scat.o scsi.o scsi_53c400.o scsi_aha1540.o scsi_cd.o scsi_hd.o scsi_zip.o \
|
||||
opti495.o paths.o pc.o pc87306.o pci.o pic.o piix.o pit.o ppi.o ps1.o ps2.o ps2_mca.o ps2_nvr.o pzx.o rom.o rtc.o rtc_tc8521.o scat.o scsi.o scsi_53c400.o scsi_aha1540.o scsi_cd.o scsi_hd.o scsi_zip.o \
|
||||
serial.o sio.o sis496.o sl82c460.o sound.o sound_ad1848.o sound_adlib.o sound_adlibgold.o sound_audiopci.o sound_cms.o sound_emu8k.o sound_gus.o \
|
||||
sound_mpu401_uart.o sound_opl.o sound_pas16.o sound_ps1.o sound_pssj.o sound_sb.o sound_sb_dsp.o sound_sn76489.o \
|
||||
sound_speaker.o sound_ssi2001.o sound_wss.o sound_ym7128.o soundopenal.o t1000.o t3100e.o tandy_eeprom.o tandy_rom.o \
|
||||
|
|
|
|||
|
|
@ -6,12 +6,12 @@ WXVERSION = 31
|
|||
WXINCLUDE = e:/MinGWget/include/wx/
|
||||
CFLAGS = -O3 -march=i686 -fomit-frame-pointer -msse2 -mstackrealign -Werror -fno-strict-aliasing
|
||||
CXXFLAGS = $(CFLAGS)
|
||||
OBJ = 386.o 386_dynarec.o 386_dynarec_ops.o 808x.o acc2036.o acc2168.o acc3221.o acer386sx.o ali1429.o amstrad.o cbm_io.o cdrom-ioctl.o cdrom-image.o \
|
||||
OBJ = 386.o 386_dynarec.o 386_dynarec_ops.o 808x.o acc2036.o acc2168.o acc3221.o acer386sx.o ali1429.o amstrad.o cassette.o cbm_io.o cdrom-ioctl.o cdrom-image.o \
|
||||
cmd640.o codegen.o codegen_ops.o codegen_timing_486.o codegen_timing_686.o codegen_timing_common.o codegen_timing_pentium.o codegen_timing_winchip.o codegen_x86.o compaq.o config.o cpu.o \
|
||||
device.o dells200.o disc.o disc_fdi.o disc_img.o disc_sector.o dma.o esdi_at.o fdc.o fdc37c665.o fdd.o fdi2raw.o gameport.o hdd.o hdd_esdi.o hdd_file.o headland.o i430hx.o i430lx.o i430fx.o \
|
||||
i430vx.o ide.o ide_atapi.o intel.o intel_flash.o io.o jim.o joystick_ch_flightstick_pro.o joystick_standard.o joystick_sw_pad.o joystick_tm_fcs.o keyboard.o keyboard_amstrad.o keyboard_at.o \
|
||||
keyboard_olim24.o keyboard_pcjr.o keyboard_xt.o laserxt.o lpt.o lpt_dac.o lpt_dss.o mca.o mcr.o mem.o mem_bios.o mfm_at.o mfm_xebec.o model.o mouse.o mouse_msystems.o mouse_ps2.o \
|
||||
mouse_serial.o neat.o nmi.o nvr.o nvr_tc8521.o olivetti_m24.o opti495.o paths.o pc.o pc87306.o pci.o pic.o piix.o pit.o ppi.o ps1.o ps2.o ps2_mca.o ps2_nvr.o rom.o rtc.o rtc_tc8521.o \
|
||||
mouse_serial.o neat.o nmi.o nvr.o nvr_tc8521.o olivetti_m24.o opti495.o paths.o pc.o pc87306.o pci.o pic.o piix.o pit.o ppi.o ps1.o ps2.o ps2_mca.o ps2_nvr.o pzx.o rom.o rtc.o rtc_tc8521.o \
|
||||
scat.o scsi.o scsi_53c400.o scsi_aha1540.o scsi_cd.o scsi_hd.o scsi_zip.o serial.o sio.o sis496.o sl82c460.o sound.o sound_ad1848.o sound_adlib.o sound_adlibgold.o sound_audiopci.o sound_cms.o sound_dbopl.o \
|
||||
sound_emu8k.o sound_gus.o sound_mpu401_uart.o sound_opl.o sound_pas16.o sound_ps1.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 \
|
||||
|
|
|
|||
|
|
@ -6,12 +6,12 @@ WXVERSION = 31
|
|||
WXINCLUDE = e:/mingwget/include/wx/
|
||||
CFLAGS = -O3 -march=i686 -fomit-frame-pointer -msse2 -mstackrealign -Werror -fno-strict-aliasing -DUSE_NETWORKING
|
||||
CXXFLAGS = $(CFLAGS)
|
||||
OBJ = 386.o 386_dynarec.o 386_dynarec_ops.o 808x.o acc2036.o acc2168.o acc3221.o acer386sx.o ali1429.o amstrad.o cbm_io.o cdrom-ioctl.o cdrom-image.o \
|
||||
OBJ = 386.o 386_dynarec.o 386_dynarec_ops.o 808x.o acc2036.o acc2168.o acc3221.o acer386sx.o ali1429.o amstrad.o cassette.o cbm_io.o cdrom-ioctl.o cdrom-image.o \
|
||||
cmd640.o codegen.o codegen_ops.o codegen_timing_486.o codegen_timing_686.o codegen_timing_common.o codegen_timing_pentium.o codegen_timing_winchip.o codegen_x86.o compaq.o config.o cpu.o \
|
||||
device.o dells200.o disc.o disc_fdi.o disc_img.o disc_sector.o dma.o esdi_at.o fdc.o fdc37c665.o fdd.o fdi2raw.o gameport.o hdd.o hdd_esdi.o hdd_file.o headland.o i430hx.o i430lx.o i430fx.o \
|
||||
i430vx.o ide.o ide_atapi.o intel.o intel_flash.o io.o jim.o joystick_ch_flightstick_pro.o joystick_standard.o joystick_sw_pad.o joystick_tm_fcs.o keyboard.o keyboard_amstrad.o keyboard_at.o \
|
||||
keyboard_olim24.o keyboard_pcjr.o keyboard_xt.o laserxt.o lpt.o lpt_dac.o lpt_dss.o mca.o mcr.o mem.o mem_bios.o mfm_at.o mfm_xebec.o model.o mouse.o mouse_msystems.o mouse_ps2.o \
|
||||
mouse_serial.o neat.o nmi.o nvr.o nvr_tc8521.o olivetti_m24.o opti495.o paths.o pc.o pc87306.o pci.o pic.o piix.o pit.o ppi.o ps1.o ps2.o ps2_mca.o ps2_nvr.o rom.o rtc.o rtc_tc8521.o \
|
||||
mouse_serial.o neat.o nmi.o nvr.o nvr_tc8521.o olivetti_m24.o opti495.o paths.o pc.o pc87306.o pci.o pic.o piix.o pit.o ppi.o ps1.o ps2.o ps2_mca.o ps2_nvr.o pzx.o rom.o rtc.o rtc_tc8521.o \
|
||||
scat.o scsi.o scsi_53c400.o scsi_aha1540.o scsi_cd.o scsi_hd.o scsi_zip.o serial.o sio.o sis496.o sl82c460.o sound.o sound_ad1848.o sound_adlib.o sound_adlibgold.o sound_audiopci.o sound_cms.o sound_dbopl.o \
|
||||
sound_emu8k.o sound_gus.o sound_mpu401_uart.o sound_opl.o sound_pas16.o sound_ps1.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 \
|
||||
|
|
|
|||
|
|
@ -3,13 +3,13 @@ CPP = g++
|
|||
CC = gcc
|
||||
WXRC = wxrc
|
||||
CFLAGS = -D__unix=1 -DPCEM_RENDER_WITH_TIMER -DPCEM_RENDER_TIMER_LOOP -Dfopen64=fopen -Dfseeko64=fseeko -Dftello64=ftello -Doff64_t=off_t -O3 -fomit-frame-pointer -msse2 -m64 $(shell wx-config --cxxflags) $(shell sdl2-config --cflags) -I/usr/local/opt/openal-soft/include -I/usr/local/include
|
||||
OBJ = 386.o 386_dynarec.o 386_dynarec_ops.o 808x.o acc2036.o acc2168.o acc3221.o acer386sx.o ali1429.o amstrad.o cbm_io.o cdrom-ioctl-osx.o cdrom-image.o cdrom-null.o \
|
||||
OBJ = 386.o 386_dynarec.o 386_dynarec_ops.o 808x.o acc2036.o acc2168.o acc3221.o acer386sx.o ali1429.o amstrad.o cassette.o cbm_io.o cdrom-ioctl-osx.o cdrom-image.o cdrom-null.o \
|
||||
cmd640.o codegen.o codegen_ops.o codegen_timing_486.o codegen_timing_686.o codegen_timing_common.o codegen_timing_pentium.o codegen_timing_winchip.o codegen_x86-64.c compaq.o config.o cpu.o \
|
||||
device.o dells200.o disc.o disc_fdi.o disc_img.o disc_sector.o dma.o esdi_at.o fdc.o fdc37c665.o fdd.o fdi2raw.o gameport.o \
|
||||
hdd.o hdd_esdi.o hdd_file.o headland.o i430hx.o i430lx.o i430fx.o i430vx.o ide.o ide_atapi.o intel.o intel_flash.o io.o jim.o joystick_ch_flightstick_pro.o joystick_standard.o joystick_sw_pad.o \
|
||||
joystick_tm_fcs.o keyboard.o keyboard_amstrad.o keyboard_at.o keyboard_olim24.o keyboard_pcjr.o keyboard_xt.o \
|
||||
laserxt.o lpt.o lpt_dac.o lpt_dss.o mca.o mcr.o mem.o mem_bios.o mfm_at.o mfm_xebec.o model.o mouse.o mouse_msystems.o mouse_ps2.o mouse_serial.o neat.o nmi.o nvr.o nvr_tc8521.o olivetti_m24.o \
|
||||
opti495.o paths.o pc.o pc87306.o pci.o pic.o piix.o pit.o ppi.o ps1.o ps2.o ps2_mca.o ps2_nvr.o rom.o rtc.o rtc_tc8521.o scat.o scsi.o scsi_53c400.o scsi_aha1540.o scsi_cd.o scsi_hd.o scsi_zip.o \
|
||||
opti495.o paths.o pc.o pc87306.o pci.o pic.o piix.o pit.o ppi.o ps1.o ps2.o ps2_mca.o ps2_nvr.o pzx.o rom.o rtc.o rtc_tc8521.o scat.o scsi.o scsi_53c400.o scsi_aha1540.o scsi_cd.o scsi_hd.o scsi_zip.o \
|
||||
serial.o sio.o sis496.o sl82c460.o sound.o sound_ad1848.o sound_adlib.o sound_adlibgold.o sound_audiopci.o sound_cms.o sound_emu8k.o sound_gus.o \
|
||||
sound_mpu401_uart.o sound_opl.o sound_pas16.o sound_ps1.o sound_pssj.o sound_sb.o sound_sb_dsp.o sound_sn76489.o \
|
||||
sound_speaker.o sound_ssi2001.o sound_wss.o sound_ym7128.o soundopenal.o t1000.o t3100e.o tandy_eeprom.o tandy_rom.o \
|
||||
|
|
|
|||
186
src/cassette.c
Normal file
186
src/cassette.c
Normal file
|
|
@ -0,0 +1,186 @@
|
|||
/************************************************************************
|
||||
|
||||
PCem: IBM 5150 Cassette support
|
||||
|
||||
Copyright (C) 2019 John Elliott <seasip.webmaster@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
*************************************************************************/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "ibm.h"
|
||||
#include "cpu.h"
|
||||
#include "device.h"
|
||||
#include "pzx.h"
|
||||
|
||||
char cassettefn[256];
|
||||
|
||||
typedef struct cassette_t
|
||||
{
|
||||
uint8_t motor; /* Motor status */
|
||||
pzxfile_t pzx;
|
||||
int cycles_last; /* Cycle count at last cassette poll */
|
||||
|
||||
} cassette_t;
|
||||
|
||||
extern device_t cassette_device;
|
||||
|
||||
|
||||
static cassette_t *st_cas;
|
||||
|
||||
|
||||
|
||||
#define CAS_LOG(x) pclog x
|
||||
// #define CAS_LOG(x)
|
||||
|
||||
|
||||
/* The PCem CPU uses IBM cycles (4.77MHz). PZX uses Spectrum cycles (3.5MHz)
|
||||
* so scale accordingly. */
|
||||
static int32_t pzx_cycles(int32_t pc)
|
||||
{
|
||||
double d = pc;
|
||||
|
||||
return (int32_t)(((d * 3.5) / 4.772728) + 0.5);
|
||||
}
|
||||
|
||||
void cassette_eject(void)
|
||||
{
|
||||
if (st_cas->pzx.input)
|
||||
{
|
||||
pzx_close(&st_cas->pzx);
|
||||
}
|
||||
cassettefn[0] = 0;
|
||||
}
|
||||
|
||||
void cassette_load(const char *filename)
|
||||
{
|
||||
FILE *fp;
|
||||
unsigned char magic[8];
|
||||
|
||||
if (!filename) return;
|
||||
|
||||
fp = fopen(filename, "rb");
|
||||
if (!fp)
|
||||
{
|
||||
/* Warn user? */
|
||||
CAS_LOG(("Failed to open cassette input %s\n", filename));
|
||||
return;
|
||||
}
|
||||
memset(magic, 0, sizeof(magic));
|
||||
fread(magic, 1, sizeof(magic), fp);
|
||||
|
||||
/* Check for PZX signature. In due course support could be added for
|
||||
* other formats like TZX */
|
||||
if (!memcmp(magic, "PZXT", 4))
|
||||
{
|
||||
const char *result;
|
||||
|
||||
result = pzx_open(&st_cas->pzx, fp);
|
||||
|
||||
if (result)
|
||||
{
|
||||
CAS_LOG(("Failed to open %s as PZX: %s\n",
|
||||
filename, result));
|
||||
fclose(fp);
|
||||
return;
|
||||
}
|
||||
strcpy(cassettefn, filename);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uint8_t cassette_input(void)
|
||||
{
|
||||
int ticks;
|
||||
|
||||
/* While motor is off, result is loopback */
|
||||
if (!st_cas->motor)
|
||||
{
|
||||
return ppispeakon;
|
||||
}
|
||||
/* If there is no tapefile open don't try to extract data */
|
||||
if (st_cas->pzx.input == NULL) return 0;
|
||||
/* Otherwise see how many ticks there have been since the last input */
|
||||
if (st_cas->cycles_last == -1)
|
||||
{
|
||||
st_cas->cycles_last = cycles;
|
||||
}
|
||||
if (cycles <= st_cas->cycles_last)
|
||||
{
|
||||
ticks = (st_cas->cycles_last - cycles);
|
||||
}
|
||||
else
|
||||
{
|
||||
ticks = (st_cas->cycles_last + (cpu_get_speed() / 100) - cycles);
|
||||
}
|
||||
st_cas->cycles_last = cycles;
|
||||
|
||||
return pzx_advance(&st_cas->pzx, pzx_cycles(ticks));
|
||||
}
|
||||
|
||||
|
||||
|
||||
void cassette_set_motor(uint8_t on)
|
||||
{
|
||||
if (on && !st_cas->motor)
|
||||
{
|
||||
CAS_LOG(("Start cassette motor\n"));
|
||||
st_cas->cycles_last = -1;
|
||||
}
|
||||
if (st_cas->motor && !on)
|
||||
{
|
||||
CAS_LOG(("Stop cassette motor\n"));
|
||||
st_cas->cycles_last = -1;
|
||||
}
|
||||
st_cas->motor = on;
|
||||
}
|
||||
|
||||
|
||||
static void *cassette_init(void)
|
||||
{
|
||||
cassette_t *cas = malloc(sizeof(cassette_t));
|
||||
|
||||
memset(cas, 0, sizeof(cassette_t));
|
||||
pzx_init(&cas->pzx);
|
||||
|
||||
st_cas = cas;
|
||||
return cas;
|
||||
}
|
||||
|
||||
|
||||
static void cassette_close(void *p)
|
||||
{
|
||||
cassette_t *cas = (cassette_t *)p;
|
||||
|
||||
pzx_close(&cas->pzx);
|
||||
|
||||
free(cas);
|
||||
}
|
||||
|
||||
|
||||
device_t cassette_device =
|
||||
{
|
||||
"Cassette",
|
||||
0,
|
||||
cassette_init,
|
||||
cassette_close,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
30
src/cassette.h
Normal file
30
src/cassette.h
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
/************************************************************************
|
||||
|
||||
PCem: IBM 5150 cassette support
|
||||
|
||||
Copyright (C) 2019 John Elliott <seasip.webmaster@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
*************************************************************************/
|
||||
|
||||
extern device_t cassette_device;
|
||||
|
||||
uint8_t cassette_input(void);
|
||||
void cassette_set_motor(uint8_t on);
|
||||
void cassette_eject(void);
|
||||
void cassette_load(const char *filename);
|
||||
|
||||
extern char cassettefn[256];
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
#include "ibm.h"
|
||||
#include "device.h"
|
||||
#include "cassette.h"
|
||||
#include "fdd.h"
|
||||
#include "io.h"
|
||||
#include "mem.h"
|
||||
|
|
@ -126,7 +127,9 @@ void keyboard_xt_write(uint16_t port, uint8_t val, void *priv)
|
|||
timer_process();
|
||||
timer_update_outstanding();
|
||||
|
||||
if (keyboard_xt.pb2_turbo)
|
||||
if (romset == ROM_IBMPC)
|
||||
cassette_set_motor((val & 8) ? 0 : 1);
|
||||
else if (keyboard_xt.pb2_turbo)
|
||||
cpu_set_turbo((val & 4) ? 0 : 1);
|
||||
|
||||
speaker_update();
|
||||
|
|
@ -183,6 +186,8 @@ uint8_t keyboard_xt_read(uint16_t port, void *priv)
|
|||
temp = ((mem_size-64) / 32) & 0xf;
|
||||
else
|
||||
temp = ((mem_size-64) / 32) >> 4;
|
||||
|
||||
temp |= (cassette_input()) ? 0x10 : 0;
|
||||
}
|
||||
else if (romset == ROM_ATARIPC3)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@
|
|||
#include "compaq.h"
|
||||
#include "dells200.h"
|
||||
#include "device.h"
|
||||
#include "cassette.h"
|
||||
#include "dma.h"
|
||||
#include "fdc.h"
|
||||
#include "fdc37c665.h"
|
||||
|
|
@ -301,6 +302,8 @@ void xt_init()
|
|||
keyboard_xt_init();
|
||||
nmi_init();
|
||||
device_add(&gameport_device);
|
||||
if (romset == ROM_IBMPC)
|
||||
device_add(&cassette_device);
|
||||
}
|
||||
|
||||
void compaq_pip_init()
|
||||
|
|
|
|||
|
|
@ -24,6 +24,11 @@ BEGIN
|
|||
MENUITEM SEPARATOR
|
||||
MENUITEM "&Configure hard discs...",IDM_HDCONF
|
||||
END
|
||||
POPUP "C&assette"
|
||||
BEGIN
|
||||
MENUITEM "&Load tapefile...", IDM_CASSETTE_LOAD
|
||||
MENUITEM "&Eject tape", IDM_CASSETTE_EJECT
|
||||
END
|
||||
POPUP "&Settings"
|
||||
BEGIN
|
||||
MENUITEM "&Configure...", IDM_CONFIG
|
||||
|
|
|
|||
|
|
@ -137,6 +137,15 @@
|
|||
<radio>1</radio>
|
||||
</object>
|
||||
</object>
|
||||
<object class="wxMenu" name="IDM_CASSETTE">
|
||||
<label>C_assette</label>
|
||||
<object class="wxMenuItem" name="IDM_CASSETTE_LOAD">
|
||||
<label>_Load tapefile...</label>
|
||||
</object>
|
||||
<object class="wxMenuItem" name="IDM_CASSETTE_EJECT">
|
||||
<label>_Eject tape</label>
|
||||
</object>
|
||||
</object>
|
||||
<object class="wxMenu">
|
||||
<label>Video</label>
|
||||
<object class="wxMenu">
|
||||
|
|
|
|||
419
src/pzx.c
Normal file
419
src/pzx.c
Normal file
|
|
@ -0,0 +1,419 @@
|
|||
/************************************************************************
|
||||
|
||||
PCem: IBM 5150 Cassette support
|
||||
|
||||
Copyright (C) 2019 John Elliott <seasip.webmaster@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
*************************************************************************/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "ibm.h"
|
||||
#include "pzx.h"
|
||||
|
||||
/* This module is intended to abstract all the details of a PZX file and
|
||||
* emit its contents as a bitstream in a form suitable for PCem. Similar
|
||||
* modules could be written to add support for other tape formats such as TZX,
|
||||
* TAP or CSW. */
|
||||
|
||||
#define CAS_LOG(x) pclog x
|
||||
/* #define CAS_LOG(x) */
|
||||
|
||||
static uint32_t peek2(uint8_t *data)
|
||||
{
|
||||
return (((uint32_t)data[1]) << 8) | data[0];
|
||||
}
|
||||
|
||||
static uint32_t peek4(uint8_t *data)
|
||||
{
|
||||
return (((uint32_t)data[3]) << 24) |
|
||||
(((uint32_t)data[2]) << 16) |
|
||||
(((uint32_t)data[1]) << 8) | data[0];
|
||||
}
|
||||
|
||||
/* Cue up the next pulse definition from the current PULS block. */
|
||||
static void pzx_parse_pulse(pzxfile_t *pzx)
|
||||
{
|
||||
pzx->puls_duration = peek2(pzx->curblock + pzx->puls_ptr);
|
||||
pzx->puls_ptr += 2;
|
||||
if (pzx->puls_duration > 0x8000)
|
||||
{
|
||||
pzx->puls_count = pzx->puls_duration & 0x7FFF;
|
||||
pzx->puls_duration = peek2(pzx->curblock + pzx->puls_ptr);
|
||||
pzx->puls_ptr += 2;
|
||||
}
|
||||
if (pzx->puls_duration >= 0x8000)
|
||||
{
|
||||
pzx->puls_duration &= 0x7FFF;
|
||||
pzx->puls_duration <<= 16;
|
||||
pzx->puls_duration |= peek2(pzx->curblock + pzx->puls_ptr);
|
||||
pzx->puls_ptr += 2;
|
||||
}
|
||||
if (!pzx->puls_count) pzx->puls_count = 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void pzx_init(pzxfile_t *pzx)
|
||||
{
|
||||
memset(pzx, 0, sizeof(pzxfile_t));
|
||||
pzx->state = PZX_CLOSED;
|
||||
}
|
||||
|
||||
/* Load the next block from a PZX-format file.
|
||||
*
|
||||
* Returns block if successful, NULL if end of file or error
|
||||
* Caller must free the block with free(). */
|
||||
uint8_t *pzx_load_block(FILE *fp)
|
||||
{
|
||||
uint8_t block_header[8];
|
||||
uint8_t *block_data;
|
||||
uint32_t block_len;
|
||||
|
||||
/* The first 8 bytes of a PZX block are fixed: the first 4 give
|
||||
* the ID, the second 4 the length (excluding the header itself) */
|
||||
if (fread(block_header, 1, 8, fp) < 8) return NULL; /* EoF */
|
||||
|
||||
block_len = peek4(block_header + 4);
|
||||
block_data = malloc(8 + block_len);
|
||||
if (!block_data) return NULL;
|
||||
memcpy(block_data, block_header, 8);
|
||||
if (!block_len) /* Block is only the header */
|
||||
{
|
||||
/* CAS_LOG(("Loaded PZX block: %-4.4s\n", block_data)); */
|
||||
return block_data;
|
||||
}
|
||||
if (fread(block_data + 8, 1, block_len, fp) < block_len)
|
||||
{
|
||||
free(block_data); /* Unexpected EoF */
|
||||
return NULL;
|
||||
}
|
||||
/* CAS_LOG(("Loaded PZX block: %-4.4s\n", block_data)); */
|
||||
return block_data;
|
||||
}
|
||||
|
||||
|
||||
/* Search the current file for PZX version headers and check they're all 1.x */
|
||||
static const char * pzx_check_version(FILE *fp)
|
||||
{
|
||||
uint8_t *block;
|
||||
static char message[80];
|
||||
|
||||
rewind(fp);
|
||||
while ( (block = pzx_load_block(fp)) )
|
||||
{
|
||||
if (!memcmp(block, "PZXT", 4))
|
||||
{
|
||||
CAS_LOG(("PZX version %d.%d\n", block[8], block[9]));
|
||||
if (block[8] != 1)
|
||||
{
|
||||
sprintf(message, "Unsupported PZX version %d.%d\n", block[8], block[9]);
|
||||
free(block);
|
||||
return message;
|
||||
}
|
||||
}
|
||||
free(block);
|
||||
}
|
||||
rewind(fp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
const char *pzx_open(pzxfile_t *pzx, FILE *fp)
|
||||
{
|
||||
const char *result;
|
||||
|
||||
rewind(fp);
|
||||
/* Check that this file is compatible */
|
||||
result = pzx_check_version(fp);
|
||||
if (result) return result;
|
||||
|
||||
pzx->level = 0;
|
||||
pzx->state = PZX_IDLE;
|
||||
pzx->input = fp;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void pzx_close(pzxfile_t *pzx)
|
||||
{
|
||||
if (pzx->input)
|
||||
{
|
||||
fclose(pzx->input);
|
||||
pzx->input = NULL;
|
||||
}
|
||||
if (pzx->curblock)
|
||||
{
|
||||
free(pzx->curblock);
|
||||
pzx->curblock = NULL;
|
||||
}
|
||||
pzx->state = PZX_CLOSED;
|
||||
}
|
||||
|
||||
/* Read the next block of type DATA, PAUS or PULS */
|
||||
int pzx_next_block(pzxfile_t *pzx)
|
||||
{
|
||||
long pos;
|
||||
|
||||
pos = ftell(pzx->input);
|
||||
while (pzx->state == PZX_IDLE)
|
||||
{
|
||||
uint8_t *blk;
|
||||
|
||||
/* In idle state there should be no current block. But
|
||||
* make sure of that */
|
||||
if (pzx->curblock)
|
||||
{
|
||||
free(pzx->curblock);
|
||||
pzx->curblock = NULL;
|
||||
}
|
||||
|
||||
/* Load the next block */
|
||||
blk = pzx_load_block(pzx->input);
|
||||
|
||||
/* If that didn't load we've reached the end of file; wrap to
|
||||
* beginning. */
|
||||
if (!blk)
|
||||
{
|
||||
rewind(pzx->input);
|
||||
blk = pzx_load_block(pzx->input);
|
||||
if (!blk) /* Couldn't even load first block */
|
||||
{
|
||||
pzx_close(pzx);
|
||||
return 0;
|
||||
}
|
||||
/* Have we read the whole file and come back to where
|
||||
* we were? */
|
||||
if (ftell(pzx->input) == pos)
|
||||
{
|
||||
free(blk);
|
||||
pzx_close(pzx);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
/* We have loaded the next block. What is it? */
|
||||
if (!memcmp(blk, "PULS", 4))
|
||||
{
|
||||
pzx->state = PZX_IN_PULS;
|
||||
pzx->curblock = blk;
|
||||
pzx->puls_len = 8 + peek4(blk + 4);
|
||||
pzx->puls_ptr = 8;
|
||||
pzx->puls_count = 0;
|
||||
pzx->puls_remain = 0;
|
||||
pzx->puls_duration = 0;
|
||||
pzx->level = 0;
|
||||
CAS_LOG(("Beginning PULS block\n"));
|
||||
}
|
||||
else if (!memcmp(blk, "PAUS", 4))
|
||||
{
|
||||
pzx->state = PZX_IN_PAUS;
|
||||
pzx->curblock = blk;
|
||||
pzx->paus_remain = peek4(blk + 8);
|
||||
pzx->level = (pzx->paus_remain >> 31);
|
||||
pzx->paus_remain &= 0x7FFFFFFF;
|
||||
CAS_LOG(("Beginning PAUS block, duration=%d\n",
|
||||
pzx->paus_remain));
|
||||
}
|
||||
else if (!memcmp(blk, "DATA", 4))
|
||||
{
|
||||
pzx->state = PZX_IN_DATA;
|
||||
pzx->curblock = blk;
|
||||
pzx->data_bits = peek4(blk + 8);
|
||||
pzx->level = (pzx->data_bits >> 31);
|
||||
pzx->data_bits &= 0x7FFFFFFF;
|
||||
pzx->data_tail = peek2(blk + 12);
|
||||
pzx->data_p0 = blk[14];
|
||||
pzx->data_p1 = blk[15];
|
||||
pzx->data_p = 0;
|
||||
pzx->data_w = 16;
|
||||
pzx->data_remain = 0;
|
||||
pzx->data_ptr = 16 + 2 * (pzx->data_p0 + pzx->data_p1);
|
||||
pzx->data_mask = 0x80;
|
||||
CAS_LOG(("Beginning DATA block, length=%d p0=%d p1=%d"
|
||||
" data_ptr=%d\n",
|
||||
pzx->data_bits,
|
||||
pzx->data_p0, pzx->data_p1,
|
||||
pzx->data_ptr));
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void pzx_endblock(pzxfile_t *pzx)
|
||||
{
|
||||
if (pzx->curblock) free(pzx->curblock);
|
||||
pzx->curblock = NULL;
|
||||
pzx->state = PZX_IDLE;
|
||||
}
|
||||
|
||||
/* PAUS is easy - just run the timer down */
|
||||
static int pzx_advance_paus(pzxfile_t *pzx, int time)
|
||||
{
|
||||
if (pzx->paus_remain > time)
|
||||
{
|
||||
pzx->paus_remain -= time;
|
||||
return 0;
|
||||
}
|
||||
time -= pzx->paus_remain;
|
||||
pzx_endblock(pzx);
|
||||
return time;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
static int pzx_advance_puls(pzxfile_t *pzx, int time)
|
||||
{
|
||||
/* At the start of a pulse sequence? */
|
||||
if (pzx->puls_count == 0)
|
||||
{
|
||||
pzx_parse_pulse(pzx);
|
||||
pzx->puls_remain = pzx->puls_duration;
|
||||
}
|
||||
/* Does sample trigger a pulse change? If not, that's easy. */
|
||||
if (time < pzx->puls_remain)
|
||||
{
|
||||
pzx->puls_remain -= time;
|
||||
return 0;
|
||||
}
|
||||
/* Sample does trigger a pulse change */
|
||||
time -= pzx->puls_remain;
|
||||
/* If there's another pulse in the current sequence, that's
|
||||
* straightforward; just flip the level and continue */
|
||||
--pzx->puls_count;
|
||||
pzx->level = !pzx->level;
|
||||
if (pzx->puls_count)
|
||||
{
|
||||
pzx->puls_remain = pzx->puls_duration;
|
||||
return time;
|
||||
}
|
||||
/* If we've reached the end of the pulse sequence, there may be
|
||||
* another one */
|
||||
if (pzx->puls_ptr < pzx->puls_len)
|
||||
{
|
||||
return time;
|
||||
}
|
||||
/* If there isn't another one, it's the end of the block */
|
||||
pzx_endblock(pzx);
|
||||
return time;
|
||||
}
|
||||
|
||||
|
||||
/* Decode a DATA block */
|
||||
static int pzx_advance_data(pzxfile_t *pzx, int time)
|
||||
{
|
||||
uint8_t bit;
|
||||
|
||||
/* Reached end of data? */
|
||||
if (pzx->data_bits == 0)
|
||||
{
|
||||
/* Time interval is covered by the tail bit */
|
||||
if (pzx->data_tail > time)
|
||||
{
|
||||
pzx->data_tail -= time;
|
||||
return 0;
|
||||
}
|
||||
/* Have run out of block */
|
||||
time -= pzx->data_tail;
|
||||
pzx_endblock(pzx);
|
||||
return time;
|
||||
}
|
||||
/* No more time remaining on the current bit? */
|
||||
if (pzx->data_p < 1 && !pzx->data_remain)
|
||||
{
|
||||
bit = pzx->curblock[pzx->data_ptr] & pzx->data_mask;
|
||||
pzx->data_mask >>= 1;
|
||||
if (!pzx->data_mask)
|
||||
{
|
||||
pzx->data_mask = 0x80;
|
||||
++pzx->data_ptr;
|
||||
}
|
||||
--pzx->data_bits;
|
||||
|
||||
if (bit)
|
||||
{
|
||||
pzx->data_p = pzx->data_p1;
|
||||
pzx->data_w = 16 + 2 * pzx->data_p0;
|
||||
pzx->data_remain = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
pzx->data_p = pzx->data_p0;
|
||||
pzx->data_w = 16;
|
||||
pzx->data_remain = 0;
|
||||
}
|
||||
}
|
||||
/* See if we've started processing the current waveform. If not,
|
||||
* load its first element (assuming that there is one) */
|
||||
if (!pzx->data_remain)
|
||||
{
|
||||
if (pzx->data_p)
|
||||
{
|
||||
pzx->data_remain = peek2(pzx->curblock + pzx->data_w);
|
||||
pzx->data_w += 2;
|
||||
pzx->data_p--;
|
||||
}
|
||||
}
|
||||
if (pzx->data_remain > time)
|
||||
{
|
||||
/* Time advance is contained within current wave */
|
||||
pzx->data_remain -= time;
|
||||
return 0;
|
||||
}
|
||||
else /* Move on to next element of wave / next bit / next block */
|
||||
{
|
||||
time -= pzx->data_remain;
|
||||
pzx->data_remain = 0;
|
||||
pzx->level = !pzx->level;
|
||||
}
|
||||
|
||||
return time;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
int pzx_advance(pzxfile_t *pzx, int time)
|
||||
{
|
||||
if (pzx->state == PZX_CLOSED) return 0; /* No tape loaded */
|
||||
|
||||
while (time)
|
||||
{
|
||||
switch (pzx->state)
|
||||
{
|
||||
case PZX_IDLE:
|
||||
if (!pzx_next_block(pzx)) return 0;
|
||||
break;
|
||||
case PZX_IN_PULS:
|
||||
time = pzx_advance_puls(pzx, time);
|
||||
break;
|
||||
case PZX_IN_PAUS:
|
||||
time = pzx_advance_paus(pzx, time);
|
||||
break;
|
||||
case PZX_IN_DATA:
|
||||
time = pzx_advance_data(pzx, time);
|
||||
break;
|
||||
case PZX_CLOSED: /*Should never get here*/
|
||||
return 0;
|
||||
|
||||
}
|
||||
}
|
||||
return pzx->level;
|
||||
}
|
||||
|
||||
|
||||
|
||||
71
src/pzx.h
Normal file
71
src/pzx.h
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
/************************************************************************
|
||||
|
||||
PCem: IBM 5150 cassette support
|
||||
|
||||
Copyright (C) 2019 John Elliott <seasip.webmaster@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
*************************************************************************/
|
||||
|
||||
typedef enum
|
||||
{
|
||||
PZX_CLOSED, /* File is not open */
|
||||
PZX_IDLE, /* File is open, no block loaded */
|
||||
PZX_IN_PULS, /* File is open, current block is a PULS block */
|
||||
PZX_IN_DATA, /* File is open, current block is a DATA block */
|
||||
PZX_IN_PAUS, /* File is open, current block is a PAUS block */
|
||||
} PZX_STATE;
|
||||
|
||||
|
||||
typedef struct pzxfile_t
|
||||
{
|
||||
FILE *input; /* Input PZX file */
|
||||
uint8_t *curblock; /* Currently-loaded block, if any */
|
||||
int level; /* Current signal level */
|
||||
PZX_STATE state; /* State machine current status */
|
||||
/* State variables for PULS */
|
||||
uint32_t puls_ptr; /* Pointer within PULS block */
|
||||
uint32_t puls_len; /* Length of PULS block */
|
||||
uint32_t puls_count; /* Count of pulses */
|
||||
uint32_t puls_duration; /* Duration of each pulse */
|
||||
uint32_t puls_remain; /* Time remaining in this pulse */
|
||||
/* State variables for PAUS */
|
||||
uint32_t paus_remain; /* Time remaining in this pause */
|
||||
/* State variables for DATA */
|
||||
uint32_t data_ptr; /* Pointer within DATA block */
|
||||
uint32_t data_bits; /* Count of bits */
|
||||
uint16_t data_tail; /* Length of pulse after last bit */
|
||||
uint8_t data_mask; /* Mask for current bit */
|
||||
uint8_t data_p0; /* Length of 0 encoding */
|
||||
uint8_t data_p1; /* Length of 1 encoding */
|
||||
int data_p; /* Current sequence being emitted */
|
||||
uint32_t data_w; /* Current waveform */
|
||||
uint32_t data_remain; /* Current data pulse time remaining */
|
||||
} pzxfile_t;
|
||||
|
||||
uint8_t *pzx_load_block(FILE *fp);
|
||||
|
||||
/* Initialise structure */
|
||||
void pzx_init(pzxfile_t *pzx);
|
||||
|
||||
/* Open file for input */
|
||||
const char *pzx_open(pzxfile_t *pzx, FILE *fp);
|
||||
|
||||
/* Close file */
|
||||
void pzx_close(pzxfile_t *pzx);
|
||||
|
||||
/* Advance by 'time' samples (3.5MHz sample rate) and return current state */
|
||||
int pzx_advance(pzxfile_t *pzx, int time);
|
||||
|
|
@ -10,6 +10,8 @@
|
|||
#define IDM_BPB_DISABLE 40015
|
||||
#define IDM_CONFIG 40020
|
||||
#define IDM_STATUS 40030
|
||||
#define IDM_CASSETTE_LOAD 40040
|
||||
#define IDM_CASSETTE_EJECT 40041
|
||||
#define IDM_VID_RESIZE 40050
|
||||
#define IDM_VID_REMEMBER 40051
|
||||
#define IDM_VID_ASPECT 40052
|
||||
|
|
|
|||
2271
src/wx-resources.cpp
2271
src/wx-resources.cpp
File diff suppressed because it is too large
Load diff
|
|
@ -18,6 +18,8 @@
|
|||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include "ibm.h"
|
||||
#include "device.h"
|
||||
#include "cassette.h"
|
||||
#include "cdrom-ioctl.h"
|
||||
#include "cdrom-image.h"
|
||||
#include "config.h"
|
||||
|
|
@ -899,6 +901,22 @@ int wx_handle_command(void* hwnd, int wParam, int checked)
|
|||
{
|
||||
zip_eject();
|
||||
}
|
||||
else if (ID_IS("IDM_CASSETTE_LOAD"))
|
||||
{
|
||||
if (!getfile(hwnd,
|
||||
"Tape image (*.pzxi;*.pzx)|*.pzxi;*.pzx|All files (*.*)|*.*",
|
||||
cassettefn))
|
||||
{
|
||||
cassette_eject();
|
||||
cassette_load(openfilestring);
|
||||
saveconfig(NULL);
|
||||
}
|
||||
}
|
||||
else if (ID_IS("IDM_CASSETTE_EJECT"))
|
||||
{
|
||||
cassette_eject();
|
||||
saveconfig(NULL);
|
||||
}
|
||||
else if (ID_IS("IDM_MACHINE_TOGGLE"))
|
||||
{
|
||||
if (emulation_state != EMULATION_STOPPED)
|
||||
|
|
|
|||
Loading…
Reference in a new issue