diff --git a/README.md b/README.md index e0a3c23ac..9696756bf 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# 86Box [![Build Status](http://polar.rol.im/job/86Box/badge/icon)](http://polar.rol.im/job/86Box) +# 86Box [![Build Status](http://dome.rol.im/job/86Box/badge/icon)](http://dome.rol.im/job/86Box) 86Box (formerly PCem Unofficial, PCem Experimental, or PCem-X) is an unofficial branch of the PCem emulator, which aims to emulate IBM compatible machines from 1981-2000 period. This branch adds several emulated motherboards. --- diff --git a/src/86box.h b/src/86box.h index 312dd5500..516356138 100644 --- a/src/86box.h +++ b/src/86box.h @@ -1,4 +1,42 @@ -/* Copyright holders: Tenshi - see COPYING for more details -*/ -#define emulator_version "1.00" +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Main emulator include file. + * + * Version: @(#)86box.h 1.0.2 2017/06/04 + * + * Author: Miran Grca, + * Copyright 2016-2017 Miran Grca. + */ +#ifndef BOX_H +# define BOX_H + + +#if defined(ENABLE_BUSLOGIC_LOG) || \ + defined(ENABLE_CDROM_LOG) || \ + defined(ENABLE_D86F_LOG) || \ + defined(ENABLE_FDC_LOG) || \ + defined(ENABLE_IDE_LOG) || \ + defined(ENABLE_NIC_LOG) +# define ENABLE_LOG_TOGGLES 1 +#endif + +#if defined(ENABLE_LOG_BREAKPOINT) || defined(ENABLE_VRAM_DUMP) +# define ENABLE_LOG_COMMANDS 1 +#endif + +#define EMU_VERSION "2.00" +#define EMU_VERSION_W L"2.00" + +#define EMU_NAME "86Box" +#define EMU_NAME_W L"86Box" + +#define CONFIG_FILE_W L"86box.cfg" + + +#endif /*BOX_H*/ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt deleted file mode 100644 index 275c04819..000000000 --- a/src/CMakeLists.txt +++ /dev/null @@ -1,55 +0,0 @@ -cmake_minimum_required(VERSION 2.8.8) -project(86box) - -set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_SOURCE_DIR}/CMakeModules) - -set(SRCS -386.c 386_dynarec.c 386_dynarec_ops.c 808x.c acer386sx.c acerm3a.c aha154x.c ali1429.c amstrad.c cdrom-ioctl.c cdrom-iso.c -cdrom-null.c codegen.c codegen_ops.c codegen_timing_486.c codegen_timing_686.c codegen_timing_pentium.c codegen_timing_winchip.c compaq.c config.c cpu.c dac.c -device.c disc.c disc_86f.c disc_fdi.c disc_imd.c disc_img.c disc_random.c disc_td0.c dma.c fdc.c fdc37c665.c fdc37c932fr.c fdd.c fdi2raw.c gameport.c headland.c i430hx.c i430lx.c i430fx.c -i430nx.c i430vx.c i440fx.c ide.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 lpt.c mcr.c mem.c memregs.c model.c mouse.c mouse_amstrad.c mouse_ps2.c -mouse_serial.c ne2000.c neat.c nethandler.c nmi.c nvr.c olivetti_m24.c opti.c pc.c pc87306.c pci.c pic.c piix.c pit.c ppi.c ps1.c rom.c rtc.c -scat.c scattergather.c scsi.c scsi_cdrom.c serial.c sis496.c sis85c471.c sio.c sound.c sound_ad1848.c sound_adlib.c sound_adlibgold.c sound_cms.c -sound_dbopl.cc sound_emu8k.c sound_gus.c sound_mpu401_uart.c sound_opl.c sound_pas16.c sound_ps1.c sound_pssj.c sound_resid.cc -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 timer.c um8669f.c vid_ati_eeprom.c vid_ati_mach64.c vid_ati18800.c -vid_ati28800.c vid_ati68860_ramdac.c vid_bt485_ramdac.c vid_cga.c vid_cl_gd.c vid_cl_gd_blit.c vid_cl_ramdac.c vid_colorplus.c vid_ega.c vid_et4000.c -vid_et4000w32.c vid_hercules.c vid_herculesplus.c vid_icd2061.c vid_ics2595.c vid_incolor.c vid_mda.c vid_nv_riva128.c -vid_olivetti_m24.c vid_oti067.c vid_paradise.c vid_pc1512.c vid_pc1640.c vid_pc200.c -vid_pcjr.c vid_ps1_svga.c vid_s3.c vid_s3_virge.c vid_sdac_ramdac.c vid_stg_ramdac.c vid_svga.c -vid_svga_render.c vid_tandy.c vid_tandysl.c vid_tgui9440.c vid_tkd8001_ramdac.c vid_tvga.c vid_unk_ramdac.c -vid_vga.c vid_voodoo.c video.c wd76c10.c win.c win-config.c win-d3d.cc win-d3d-fs.cc win-ddraw.cc -win-ddraw-fs.cc win-ddraw-screenshot.cc win-deviceconfig.c win-hdconf.c win-joystick.cc win-joystickconfig.c win-keyboard.cc win-midi.c win-mouse.cc -win-status.c win-video.c x86seg.c x87.c xtide.c pc.rc -dosbox/dbopl.cpp dosbox/nukedopl.cpp dosbox/vid_cga_comp.c -lzf/lzf_c.c lzf/lzf_d.c -resid-fp/convolve.cc resid-fp/convolve-sse.cc resid-fp/envelope.cc resid-fp/extfilt.cc resid-fp/filter.cc resid-fp/pot.cc resid-fp/sid.cc resid-fp/voice.cc resid-fp/wave6581__ST.cc resid-fp/wave6581_P_T.cc resid-fp/wave6581_PS_.cc resid-fp/wave6581_PST.cc resid-fp/wave8580__ST.cc resid-fp/wave8580_P_T.cc resid-fp/wave8580_PS_.cc resid-fp/wave8580_PST.cc resid-fp/wave.cc -slirp/bootp.c slirp/ip_icmp.c slirp/misc.c slirp/socket.c slirp/tcp_timer.c slirp/cksum.c slirp/ip_input.c slirp/queue.c slirp/tcp_input.c slirp/tftp.c slirp/debug.c slirp/ip_output.c slirp/sbuf.c slirp/tcp_output.c slirp/udp.c slirp/if.c slirp/mbuf.c slirp/slirp.c slirp/tcp_subr.c -) - -if(CMAKE_SIZEOF_VOID_P EQUAL 8) - set(_ARCH_64 1) -else() - set(_ARCH_32 1) -endif() - -include(FindOpenAL REQUIRED) -include(FindDirectInput REQUIRED) -include(FindDirectDraw REQUIRED) - -if(_ARCH_32) -set(SRCS ${SRCS} -codegen_x86.c -) -else() -set(SRCS ${SRCS} -codegen_x86-64.c -) -endif() - -add_definitions(-msse2 -mstackrealign -mwindows) - -add_executable(86box ${SRCS}) - -target_link_libraries(86box winmm openal.dll openal ddraw dinput8 dxguid d3d9 d3dx9 wsock32 iphlpapi stdc++) \ No newline at end of file diff --git a/src/CMakeModules/FindD3D9.cmake b/src/CMakeModules/FindD3D9.cmake deleted file mode 100644 index 6e7ed3237..000000000 --- a/src/CMakeModules/FindD3D9.cmake +++ /dev/null @@ -1,53 +0,0 @@ -# Locate directdraw -# This module defines -# D3D9_LIBRARIES -# D3D9_FOUND, if false, do not try to link to directinput -# D3D9_INCLUDE_DIR, where to find the headers -# -# $D3D9_DIR is an environment variable that would -# point to the this path in the plateform devkit (Samples\Multimedia\DirectShow) -# -# Created by Cedric Pinson. -# - -SET( D3D9_FOUND FALSE ) - -IF( WIN32 ) - FIND_PATH( D3D9_ROOT_DIR Include/D3D9.h - PATHS - $ENV{PATH} - $ENV{PROGRAMFILES} - ) - - FIND_PATH( D3D9_INCLUDE_DIR d3d9.h - PATHS - ${D3D9_ROOT_DIR}/Include - ) - - FIND_LIBRARY( D3D9_LIBRARY d3d9.lib d3dx9 - PATHS - ${D3D9_ROOT_DIR}/lib/x86 - ) - - FIND_LIBRARY( D3D9_GUID_LIBRARY dxguid.lib - PATHS - ${D3D9_ROOT_DIR}/lib/x86 - ) - - FIND_LIBRARY( D3D9_ERR_LIBRARY dxerr.lib - PATHS - ${D3D9_ROOT_DIR}/lib/x86 - ) - - SET( D3D9_LIBRARIES - ${D3D9_LIBRARY} - ${D3D9_GUID_LIBRARY} - ${D3D9_ERR_LIBRARY} - ) - - IF ( D3D9_INCLUDE_DIR AND D3D9_LIBRARIES ) - SET( D3D9_FOUND TRUE ) - ENDIF ( D3D9_INCLUDE_DIR AND D3D9_LIBRARIES ) -ENDIF( WIN32 ) - -MARK_AS_ADVANCED( D3D9_FOUND ) \ No newline at end of file diff --git a/src/CMakeModules/FindDirectDraw.cmake b/src/CMakeModules/FindDirectDraw.cmake deleted file mode 100644 index c5f995313..000000000 --- a/src/CMakeModules/FindDirectDraw.cmake +++ /dev/null @@ -1,53 +0,0 @@ -# Locate directdraw -# This module defines -# DDRAW_LIBRARIES -# DDRAW_FOUND, if false, do not try to link to directinput -# DDRAW_INCLUDE_DIR, where to find the headers -# -# $DDRAW_DIR is an environment variable that would -# point to the this path in the plateform devkit (Samples\Multimedia\DirectShow) -# -# Created by Cedric Pinson. -# - -SET( DDRAW_FOUND FALSE ) - -IF( WIN32 ) - FIND_PATH( DDRAW_ROOT_DIR Include/D3D10.h - PATHS - $ENV{PATH} - $ENV{PROGRAMFILES} - ) - - FIND_PATH( DDRAW_INCLUDE_DIR ddraw.h - PATHS - ${DDRAW_ROOT_DIR}/Include - ) - - FIND_LIBRARY( DDRAW_LIBRARY ddraw.lib - PATHS - ${DDRAW_ROOT_DIR}/lib/x86 - ) - - FIND_LIBRARY( DDRAW_GUID_LIBRARY dxguid.lib - PATHS - ${DDRAW_ROOT_DIR}/lib/x86 - ) - - FIND_LIBRARY( DDRAW_ERR_LIBRARY dxerr.lib - PATHS - ${DDRAW_ROOT_DIR}/lib/x86 - ) - - SET( DDRAW_LIBRARIES - ${DDRAW_LIBRARY} - ${DDRAW_GUID_LIBRARY} - ${DDRAW_ERR_LIBRARY} - ) - - IF ( DDRAW_INCLUDE_DIR AND DDRAW_LIBRARIES ) - SET( DDRAW_FOUND TRUE ) - ENDIF ( DDRAW_INCLUDE_DIR AND DDRAW_LIBRARIES ) -ENDIF( WIN32 ) - -MARK_AS_ADVANCED( DDRAW_FOUND ) \ No newline at end of file diff --git a/src/CMakeModules/FindDirectInput.cmake b/src/CMakeModules/FindDirectInput.cmake deleted file mode 100644 index b7b457527..000000000 --- a/src/CMakeModules/FindDirectInput.cmake +++ /dev/null @@ -1,53 +0,0 @@ -# Locate directinput -# This module defines -# DIRECTINPUT_LIBRARIES -# DIRECTINPUT_FOUND, if false, do not try to link to directinput -# DIRECTINPUT_INCLUDE_DIR, where to find the headers -# -# $DIRECTINPUT_DIR is an environment variable that would -# point to the this path in the plateform devkit (Samples\Multimedia\DirectShow) -# -# Created by Cedric Pinson. -# - -SET( DIRECTINPUT_FOUND FALSE ) - -IF( WIN32 ) - FIND_PATH( DIRECTINPUT_ROOT_DIR Include/D3D10.h - PATHS - $ENV{PATH} - $ENV{PROGRAMFILES} - ) - - FIND_PATH( DIRECTINPUT_INCLUDE_DIR dinput.h - PATHS - ${DIRECTINPUT_ROOT_DIR}/Include - ) - - FIND_LIBRARY( DIRECTINPUT_LIBRARY dinput7.lib dinput8.lib - PATHS - ${DIRECTINPUT_ROOT_DIR}/lib/x86 - ) - - FIND_LIBRARY( DIRECTINPUT_GUID_LIBRARY dxguid.lib - PATHS - ${DIRECTINPUT_ROOT_DIR}/lib/x86 - ) - - FIND_LIBRARY( DIRECTINPUT_ERR_LIBRARY dxerr.lib - PATHS - ${DIRECTINPUT_ROOT_DIR}/lib/x86 - ) - - SET( DIRECTINPUT_LIBRARIES - ${DIRECTINPUT_LIBRARY} - ${DIRECTINPUT_GUID_LIBRARY} - ${DIRECTINPUT_ERR_LIBRARY} - ) - - IF ( DIRECTINPUT_INCLUDE_DIR AND DIRECTINPUT_LIBRARIES ) - SET( DIRECTINPUT_FOUND TRUE ) - ENDIF ( DIRECTINPUT_INCLUDE_DIR AND DIRECTINPUT_LIBRARIES ) -ENDIF( WIN32 ) - -MARK_AS_ADVANCED( DIRECTINPUT_FOUND ) \ No newline at end of file diff --git a/src/386.c b/src/CPU/386.c similarity index 87% rename from src/386.c rename to src/CPU/386.c index 2029c1afd..074fa9696 100644 --- a/src/386.c +++ b/src/CPU/386.c @@ -1,14 +1,19 @@ +#include +#ifndef INFINITY +# define INFINITY (__builtin_inff()) +#endif #include #include #include -#include "ibm.h" +#include "../ibm.h" +#include "cpu.h" #include "x86.h" #include "x87.h" -#include "mem.h" -#include "cpu.h" -#include "disc.h" -#include "fdc.h" -#include "timer.h" +#include "../mem.h" +#include "../disc.h" +#include "../fdc.h" +#include "../pic.h" +#include "../timer.h" #include "386_common.h" @@ -23,6 +28,13 @@ uint32_t oldpc2; int trap; +uint16_t flags,eflags; +uint32_t oldds,oldss,olddslimit,oldsslimit,olddslimitw,oldsslimitw; + +x86seg gdt,ldt,idt,tr; +x86seg _cs,_ds,_es,_ss,_fs,_gs; +x86seg _oldds; + extern int cpl_override; @@ -35,6 +47,8 @@ uint16_t ea_rseg; int is486; int cgate32; +uint32_t cr2, cr3, cr4; +uint32_t dr[8]; uint8_t romext[32768]; @@ -56,7 +70,7 @@ uint32_t *eal_r, *eal_w; uint16_t *mod1add[2][8]; uint32_t *mod1seg[8]; -static inline void fetch_ea_32_long(uint32_t rmdat) +static __inline void fetch_ea_32_long(uint32_t rmdat) { eal_r = eal_w = NULL; easeg = cpu_state.ea_seg->base; @@ -74,7 +88,7 @@ static inline void fetch_ea_32_long(uint32_t rmdat) case 1: cpu_state.pc++; cpu_state.eaaddr = ((uint32_t)(int8_t)getbyte()) + cpu_state.regs[sib & 7].l; -// pc++; + /* pc++; */ break; case 2: cpu_state.eaaddr = (fastreadl(cs + cpu_state.pc + 1)) + cpu_state.regs[sib & 7].l; @@ -129,7 +143,7 @@ static inline void fetch_ea_32_long(uint32_t rmdat) } } -static inline void fetch_ea_16_long(uint32_t rmdat) +static __inline void fetch_ea_16_long(uint32_t rmdat) { eal_r = eal_w = NULL; easeg = cpu_state.ea_seg->base; @@ -215,22 +229,23 @@ void exec386(int cycs) int tempi; int cycdiff; int oldcyc; + int cycle_period = cycs / 2000; /*Use a 5us timing granularity*/ cycles+=cycs; -// output=3; + /* output=3; */ while (cycles>0) { cycdiff=0; oldcyc=cycles; timer_start_period(cycles << TIMER_SHIFT); -// pclog("%i %02X\n", ins, ram[8]); - while (cycdiff<100) + /* pclog("%i %02X\n", ins, ram[8]); */ + while (cycdiff < cycle_period) { /* testr[0]=EAX; testr[1]=EBX; testr[2]=ECX; testr[3]=EDX; testr[4]=ESI; testr[5]=EDI; testr[6]=EBP; testr[7]=ESP;*/ /* testr[8]=flags;*/ -// oldcs2=oldcs; -// oldpc2=oldpc; + /* oldcs2=oldcs; */ + /* oldpc2=oldpc; */ oldcs=CS; cpu_state.oldpc = cpu_state.pc; oldcpl=CPL; @@ -262,8 +277,8 @@ dontprint=0; if (cpu_state.abrt) { flags_rebuild(); -// pclog("Abort\n"); -// if (CS == 0x228) pclog("Abort at %04X:%04X - %i %i %i\n",CS,pc,notpresent,nullseg,cpu_state.abrt); + /* pclog("Abort\n"); */ + /* if (CS == 0x228) pclog("Abort at %04X:%04X - %i %i %i\n",CS,pc,notpresent,nullseg,cpu_state.abrt); */ /* if (testr[0]!=EAX) pclog("EAX corrupted %08X\n",pc); if (testr[1]!=EBX) pclog("EBX corrupted %08X\n",pc); if (testr[2]!=ECX) pclog("ECX corrupted %08X\n",pc); @@ -297,8 +312,8 @@ dontprint=0; if (trap) { flags_rebuild(); -// oldpc=pc; -// oldcs=CS; + /* oldpc=pc; */ + /* oldcs=CS; */ if (msw&1) { pmodeint(1,0); @@ -320,19 +335,24 @@ dontprint=0; { cpu_state.oldpc = cpu_state.pc; oldcs = CS; -// pclog("NMI\n"); + /* pclog("NMI\n"); */ x86_int(2); nmi_enable = 0; + if (nmi_auto_clear) + { + nmi_auto_clear = 0; + nmi = 0; + } } else if ((flags&I_FLAG) && pic_intpending) { temp=picinterrupt(); if (temp!=0xFF) { -// if (temp == 0x54) pclog("Take int 54\n"); -// if (output) output=3; -// if (temp == 0xd) pclog("Hardware int %02X %i %04X(%08X):%08X\n",temp,ins, CS,cs,pc); -// if (temp==0x54) output=3; + /* if (temp == 0x54) pclog("Take int 54\n"); */ + /* if (output) output=3; */ + /* if (temp == 0xd) pclog("Hardware int %02X %i %04X(%08X):%08X\n",temp,ins, CS,cs,pc); */ + /* if (temp==0x54) output=3; */ flags_rebuild(); if (msw&1) { @@ -350,9 +370,9 @@ dontprint=0; oxpc=cpu_state.pc; cpu_state.pc=readmemw(0,addr); loadcs(readmemw(0,addr+2)); -// if (temp==0x76) pclog("INT to %04X:%04X\n",CS,pc); + /* if (temp==0x76) pclog("INT to %04X:%04X\n",CS,pc); */ } -// pclog("Now at %04X(%08X):%08X\n", CS, cs, pc); + /* pclog("Now at %04X(%08X):%08X\n", CS, cs, pc); */ } } diff --git a/src/386.h b/src/CPU/386.h similarity index 100% rename from src/386.h rename to src/CPU/386.h diff --git a/src/386_common.h b/src/CPU/386_common.h similarity index 72% rename from src/386_common.h rename to src/CPU/386_common.h index d1350f55d..562c2445d 100644 --- a/src/386_common.h +++ b/src/CPU/386_common.h @@ -1,6 +1,21 @@ -/* Copyright holders: Sarah Walker, Tenshi - see COPYING for more details -*/ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Common 386 CPU code. + * + * Version: @(#)386_common.h 1.0.0 2017/05/30 + * + * Author: Sarah Walker, + * Miran Grca, + * Copyright 2008-2017 Sarah Walker. + * Copyright 2016-2017 Miran Grca. + */ + extern uint16_t ea_rseg; #undef readmemb @@ -8,39 +23,15 @@ extern uint16_t ea_rseg; #define readmemb(s,a) ((readlookup2[(uint32_t)((s)+(a))>>12]==-1 || (s)==0xFFFFFFFF)?readmemb386l(s,a): *(uint8_t *)(readlookup2[(uint32_t)((s)+(a))>>12] + (uint32_t)((s) + (a))) ) -#define readmemq(s,a) ((readlookup2[(uint32_t)((s)+(a))>>12]==-1 || (s)==0xFFFFFFFF || (((s)+(a))&0xFFF)>0xFF8)?readmemql(s,a):*(uint64_t *)(readlookup2[(uint32_t)((s)+(a))>>12]+(uint32_t)((s)+(a)))) +#define readmemq(s,a) ((readlookup2[(uint32_t)((s)+(a))>>12]==-1 || (s)==0xFFFFFFFF || (((s)+(a)) & 7))?readmemql(s,a):*(uint64_t *)(readlookup2[(uint32_t)((s)+(a))>>12]+(uint32_t)((s)+(a)))) #define writememb(s,a,v) if (writelookup2[(uint32_t)((s)+(a))>>12]==-1 || (s)==0xFFFFFFFF) writememb386l(s,a,v); else *(uint8_t *)(writelookup2[(uint32_t)((s) + (a)) >> 12] + (uint32_t)((s) + (a))) = v -#define writememw(s,a,v) if (writelookup2[(uint32_t)((s)+(a))>>12]==-1 || (s)==0xFFFFFFFF || (((s)+(a))&0xFFF)>0xFFE) writememwl(s,a,v); else *(uint16_t *)(writelookup2[(uint32_t)((s) + (a)) >> 12] + (uint32_t)((s) + (a))) = v -#define writememl(s,a,v) if (writelookup2[(uint32_t)((s)+(a))>>12]==-1 || (s)==0xFFFFFFFF || (((s)+(a))&0xFFF)>0xFFC) writememll(s,a,v); else *(uint32_t *)(writelookup2[(uint32_t)((s) + (a)) >> 12] + (uint32_t)((s) + (a))) = v -#define writememq(s,a,v) if (writelookup2[(uint32_t)((s)+(a))>>12]==-1 || (s)==0xFFFFFFFF || (((s)+(a))&0xFFF)>0xFF8) writememql(s,a,v); else *(uint64_t *)(writelookup2[(uint32_t)((s) + (a)) >> 12] + (uint32_t)((s) + (a))) = v +#define writememw(s,a,v) if (writelookup2[(uint32_t)((s)+(a))>>12]==-1 || (s)==0xFFFFFFFF || (((s)+(a)) & 1)) writememwl(s,a,v); else *(uint16_t *)(writelookup2[(uint32_t)((s) + (a)) >> 12] + (uint32_t)((s) + (a))) = v +#define writememl(s,a,v) if (writelookup2[(uint32_t)((s)+(a))>>12]==-1 || (s)==0xFFFFFFFF || (((s)+(a)) & 3)) writememll(s,a,v); else *(uint32_t *)(writelookup2[(uint32_t)((s) + (a)) >> 12] + (uint32_t)((s) + (a))) = v +#define writememq(s,a,v) if (writelookup2[(uint32_t)((s)+(a))>>12]==-1 || (s)==0xFFFFFFFF || (((s)+(a)) & 7)) writememql(s,a,v); else *(uint64_t *)(writelookup2[(uint32_t)((s) + (a)) >> 12] + (uint32_t)((s) + (a))) = v -#if 0 -#define check_io_perm(port) if (!IOPLp || (eflags&VM_FLAG)) \ - { \ - int tempi = checkio(port); \ - if (cpu_state.abrt) return 1; \ - if (tempi) \ - { \ - x86gpf("check_io_perm(): no permission",0); \ - return 1; \ - } \ - } - -#define checkio_perm(port) if (!IOPLp || (eflags&VM_FLAG)) \ - { \ - tempi = checkio(port); \ - if (cpu_state.abrt) break; \ - if (tempi) \ - { \ - x86gpf("checkio_perm(): no permission",0); \ - break; \ - } \ - } -#endif - #define check_io_perm(port) if (msw&1 && ((CPL > IOPL) || (eflags&VM_FLAG))) \ { \ int tempi = checkio(port); \ @@ -64,7 +55,7 @@ extern uint16_t ea_rseg; } #define CHECK_READ(chseg, low, high) \ - if ((low < (chseg)->limit_low) || (high > (chseg)->limit_high)) \ + if ((low < (chseg)->limit_low) || (high > (chseg)->limit_high) || ((msw & 1) && !(eflags & VM_FLAG) && (((chseg)->access & 10) == 8))) \ { \ x86gpf("Limit check", 0); \ return 1; \ @@ -79,7 +70,7 @@ extern uint16_t ea_rseg; } #define CHECK_WRITE(chseg, low, high) \ - if ((low < (chseg)->limit_low) || (high > (chseg)->limit_high) || !((chseg)->access & 2)) \ + if ((low < (chseg)->limit_low) || (high > (chseg)->limit_high) || !((chseg)->access & 2) || ((msw & 1) && !(eflags & VM_FLAG) && ((chseg)->access & 8))) \ { \ x86gpf("Limit check", 0); \ return 1; \ @@ -118,7 +109,7 @@ extern uint16_t ea_rseg; -static inline uint8_t fastreadb(uint32_t a) +static __inline uint8_t fastreadb(uint32_t a) { uint8_t *t; @@ -126,33 +117,33 @@ static inline uint8_t fastreadb(uint32_t a) return *((uint8_t *)&pccache2[a]); t = getpccache(a); if (cpu_state.abrt) - return; + return 0xFF; pccache = a >> 12; pccache2 = t; return *((uint8_t *)&pccache2[a]); } -static inline uint16_t fastreadw(uint32_t a) +static __inline uint16_t fastreadw(uint32_t a) { uint8_t *t; uint16_t val; if ((a&0xFFF)>0xFFE) { - val = readmemb(0, a); - val |= (readmemb(0, a + 1) << 8); + val = fastreadb(a); + val |= (fastreadb(a + 1) << 8); return val; } if ((a>>12)==pccache) return *((uint16_t *)&pccache2[a]); t = getpccache(a); if (cpu_state.abrt) - return; + return 0xff; pccache = a >> 12; pccache2 = t; return *((uint16_t *)&pccache2[a]); } -static inline uint32_t fastreadl(uint32_t a) +static __inline uint32_t fastreadl(uint32_t a) { uint8_t *t; uint32_t val; @@ -165,36 +156,34 @@ static inline uint32_t fastreadl(uint32_t a) return 0; pccache2 = t; pccache=a>>12; - //return *((uint32_t *)&pccache2[a]); + /* return *((uint32_t *)&pccache2[a]); */ } return *((uint32_t *)&pccache2[a]); } - val =readmemb(0,a); - val |=(readmemb(0,a+1)<<8); - val |=(readmemb(0,a+2)<<16); - val |=(readmemb(0,a+3)<<24); + val = fastreadw(a); + val |= (fastreadw(a + 2) << 16); return val; } -static inline uint8_t getbyte() +static __inline uint8_t getbyte() { cpu_state.pc++; return fastreadb(cs + (cpu_state.pc - 1)); } -static inline uint16_t getword() +static __inline uint16_t getword() { cpu_state.pc+=2; return fastreadw(cs+(cpu_state.pc-2)); } -static inline uint32_t getlong() +static __inline uint32_t getlong() { cpu_state.pc+=4; return fastreadl(cs+(cpu_state.pc-4)); } -static inline uint64_t getquad() +static __inline uint64_t getquad() { cpu_state.pc+=8; return fastreadl(cs+(cpu_state.pc-8)) | ((uint64_t)fastreadl(cs+(cpu_state.pc-4)) << 32); @@ -202,7 +191,7 @@ static inline uint64_t getquad() -static inline uint8_t geteab() +static __inline uint8_t geteab() { if (cpu_mod == 3) return (cpu_rm & 4) ? cpu_state.regs[cpu_rm & 3].b.h : cpu_state.regs[cpu_rm&3].b.l; @@ -211,48 +200,48 @@ static inline uint8_t geteab() return readmemb(easeg, cpu_state.eaaddr); } -static inline uint16_t geteaw() +static __inline uint16_t geteaw() { if (cpu_mod == 3) return cpu_state.regs[cpu_rm].w; -// cycles-=3; + /* cycles-=3; */ if (eal_r) return *(uint16_t *)eal_r; return readmemw(easeg, cpu_state.eaaddr); } -static inline uint32_t geteal() +static __inline uint32_t geteal() { if (cpu_mod == 3) return cpu_state.regs[cpu_rm].l; -// cycles-=3; + /* cycles-=3; */ if (eal_r) return *eal_r; return readmeml(easeg, cpu_state.eaaddr); } -static inline uint64_t geteaq() +static __inline uint64_t geteaq() { return readmemq(easeg, cpu_state.eaaddr); } -static inline uint8_t geteab_mem() +static __inline uint8_t geteab_mem() { if (eal_r) return *(uint8_t *)eal_r; return readmemb(easeg,cpu_state.eaaddr); } -static inline uint16_t geteaw_mem() +static __inline uint16_t geteaw_mem() { if (eal_r) return *(uint16_t *)eal_r; return readmemw(easeg,cpu_state.eaaddr); } -static inline uint32_t geteal_mem() +static __inline uint32_t geteal_mem() { if (eal_r) return *eal_r; return readmeml(easeg,cpu_state.eaaddr); } -static inline void seteaq(uint64_t v) +static __inline void seteaq(uint64_t v) { writememql(easeg, cpu_state.eaaddr, v); } diff --git a/src/386_dynarec.c b/src/CPU/386_dynarec.c similarity index 86% rename from src/386_dynarec.c rename to src/CPU/386_dynarec.c index 4fd3555f9..c59110cd6 100644 --- a/src/386_dynarec.c +++ b/src/CPU/386_dynarec.c @@ -1,21 +1,28 @@ +#include +#ifndef INFINITY +# define INFINITY (__builtin_inff()) +#endif #include #include #include -#include "ibm.h" +#include "../ibm.h" +#include "cpu.h" #include "x86.h" #include "x86_ops.h" #include "x87.h" -#include "mem.h" +#include "../mem.h" #include "codegen.h" -#include "cpu.h" -#include "disc.h" -#include "fdc.h" -#include "timer.h" +#include "../disc.h" +#include "../fdc.h" +#include "../pic.h" +#include "../timer.h" #include "386_common.h" #define CPU_BLOCK_END() cpu_block_end = 1 +uint32_t cpu_cur_status = 0; + int cpu_reps, cpu_reps_latched; int cpu_notreps, cpu_notreps_latched; @@ -62,7 +69,7 @@ uint32_t *eal_r, *eal_w; uint16_t *mod1add[2][8]; uint32_t *mod1seg[8]; -static inline void fetch_ea_32_long(uint32_t rmdat) +static __inline void fetch_ea_32_long(uint32_t rmdat) { eal_r = eal_w = NULL; easeg = cpu_state.ea_seg->base; @@ -80,7 +87,6 @@ static inline void fetch_ea_32_long(uint32_t rmdat) case 1: cpu_state.pc++; cpu_state.eaaddr = ((uint32_t)(int8_t)getbyte()) + cpu_state.regs[sib & 7].l; -// cpu_state.pc++; break; case 2: cpu_state.eaaddr = (fastreadl(cs + cpu_state.pc + 1)) + cpu_state.regs[sib & 7].l; @@ -136,7 +142,7 @@ static inline void fetch_ea_32_long(uint32_t rmdat) cpu_state.last_ea = cpu_state.eaaddr; } -static inline void fetch_ea_16_long(uint32_t rmdat) +static __inline void fetch_ea_16_long(uint32_t rmdat) { eal_r = eal_w = NULL; easeg = cpu_state.ea_seg->base; @@ -187,7 +193,6 @@ static inline void fetch_ea_16_long(uint32_t rmdat) void x86_int(int num) { uint32_t addr; -// pclog("x86_int %02x %04x:%04x\n", num, CS,pc); flags_rebuild(); cpu_state.pc=cpu_state.oldpc; if (msw&1) @@ -225,8 +230,6 @@ void x86_int(int num) void x86_int_sw(int num) { uint32_t addr; -// pclog("x86_int_sw %02x %04x:%04x\n", num, CS,pc); -// pclog("x86_int\n"); flags_rebuild(); cycles -= timing_int; if (msw&1) @@ -264,14 +267,6 @@ void x86_int_sw(int num) void x86illegal() { - uint16_t addr; -// pclog("x86 illegal %04X %08X %04X:%08X %02X\n",msw,cr0,CS,pc,opcode); - -// if (output) -// { -// dumpregs(); -// exit(-1); -// } x86_int(6); } @@ -359,14 +354,28 @@ static void prefetch_flush() #define PREFETCH_FLUSH() prefetch_flush() +int checkio(int port) +{ + uint16_t t; + uint8_t d; + cpl_override = 1; + t = readmemw(tr.base, 0x66); + cpl_override = 0; + if (cpu_state.abrt) return 0; + if ((t+(port>>3))>tr.limit) return 1; + cpl_override = 1; + d = readmemb386l(0, tr.base + t + (port >> 3)); + cpl_override = 0; + return d&(1<<(port&7)); +} + int rep386(int fv) { uint8_t temp; - uint32_t c;//=CX; + uint32_t c; uint8_t temp2; uint16_t tempw,tempw2,of; - uint32_t ipc = cpu_state.oldpc;//pc-1; - uint32_t oldds; + uint32_t ipc = cpu_state.oldpc; uint32_t rep32 = cpu_state.op32; uint32_t templ,templ2; int tempz; @@ -384,16 +393,9 @@ int rep386(int fv) flags_rebuild(); of = flags; -// if (inrecomp) pclog("REP32 %04X %04X ",use32,rep32); startrep: temp=opcode2=readmemb(cs,cpu_state.pc); cpu_state.pc++; -// if (firstrepcycle && temp==0xA5) pclog("REP MOVSW %06X:%04X %06X:%04X\n",ds,SI,es,DI); -// if (inrecomp) pclog("REP %02X %04X\n",temp,ipc); c=(rep32&0x200)?ECX:CX; -/* if (rep32 && (msw&1)) - { - if (temp!=0x67 && temp!=0x66 && (rep32|temp)!=0x1AB && (rep32|temp)!=0x3AB) pclog("32-bit REP %03X %08X %04X:%06X\n",temp|rep32,c,CS,pc); - }*/ switch (temp|rep32) { case 0xC3: case 0x1C3: case 0x2C3: case 0x3C3: @@ -436,7 +438,6 @@ int rep386(int fv) PREFETCH_PREFIX(); goto startrep; case 0x6C: case 0x16C: /*REP INSB*/ -// cpu_notreps++; if (c>0) { checkio_perm(DX); @@ -453,7 +454,6 @@ int rep386(int fv) else firstrepcycle=1; break; case 0x26C: case 0x36C: /*REP INSB*/ -// cpu_notreps++; if (c>0) { checkio_perm(DX); @@ -470,10 +470,8 @@ int rep386(int fv) else firstrepcycle=1; break; case 0x6D: /*REP INSW*/ -// cpu_notreps++; if (c>0) { -// pclog("REP INSW %04x %04x:%04x %04x\n", DX, ES, DI, CX); tempw=inw(DX); writememw(es,DI,tempw); if (cpu_state.abrt) break; @@ -487,7 +485,6 @@ int rep386(int fv) else firstrepcycle=1; break; case 0x16D: /*REP INSL*/ -// cpu_notreps++; if (c>0) { templ=inl(DX); @@ -503,7 +500,6 @@ int rep386(int fv) else firstrepcycle=1; break; case 0x26D: /*REP INSW*/ -// cpu_notreps++; if (c>0) { tempw=inw(DX); @@ -519,7 +515,6 @@ int rep386(int fv) else firstrepcycle=1; break; case 0x36D: /*REP INSL*/ -// cpu_notreps++; if (c>0) { templ=inl(DX); @@ -535,7 +530,6 @@ int rep386(int fv) else firstrepcycle=1; break; case 0x6E: case 0x16E: /*REP OUTSB*/ -// cpu_notreps++; if (c>0) { temp2 = readmemb(cpu_state.ea_seg->base, SI); @@ -552,7 +546,6 @@ int rep386(int fv) else firstrepcycle=1; break; case 0x26E: case 0x36E: /*REP OUTSB*/ -// cpu_notreps++; if (c>0) { temp2 = readmemb(cpu_state.ea_seg->base, ESI); @@ -569,12 +562,10 @@ int rep386(int fv) else firstrepcycle=1; break; case 0x6F: /*REP OUTSW*/ -// cpu_notreps++; if (c>0) { tempw = readmemw(cpu_state.ea_seg->base, SI); if (cpu_state.abrt) break; -// pclog("OUTSW %04X -> %04X\n",SI,tempw); outw(DX,tempw); if (flags&D_FLAG) SI-=2; else SI+=2; @@ -586,7 +577,6 @@ int rep386(int fv) else firstrepcycle=1; break; case 0x16F: /*REP OUTSL*/ -// cpu_notreps++; if (c > 0) { templ = readmeml(cpu_state.ea_seg->base, SI); @@ -602,7 +592,6 @@ int rep386(int fv) else firstrepcycle = 1; break; case 0x26F: /*REP OUTSW*/ -// cpu_notreps++; if (c>0) { tempw = readmemw(cpu_state.ea_seg->base, ESI); @@ -618,7 +607,6 @@ int rep386(int fv) else firstrepcycle=1; break; case 0x36F: /*REP OUTSL*/ -// cpu_notreps++; if (c > 0) { templ = readmeml(cpu_state.ea_seg->base, ESI); @@ -635,7 +623,6 @@ int rep386(int fv) break; case 0x90: case 0x190: /*REP NOP*/ case 0x290: case 0x390: -// cpu_notreps++; break; case 0xA4: case 0x1A4: /*REP MOVSB*/ while (c > 0) @@ -643,7 +630,6 @@ int rep386(int fv) CHECK_WRITE_REP(&_es, DI, DI); temp2 = readmemb(cpu_state.ea_seg->base, SI); if (cpu_state.abrt) break; writememb(es,DI,temp2); if (cpu_state.abrt) break; -// if (output==3) pclog("MOVSB %08X:%04X -> %08X:%04X %02X\n",ds,SI,es,DI,temp2); if (flags&D_FLAG) { DI--; SI--; } else { DI++; SI++; } c--; @@ -700,7 +686,6 @@ int rep386(int fv) { CHECK_WRITE_REP(&_es, DI, DI+3); templ = readmeml(cpu_state.ea_seg->base, SI); if (cpu_state.abrt) break; -// pclog("MOVSD %08X from %08X to %08X (%04X:%08X)\n", templ, ds+SI, es+DI, CS, pc); writememl(es,DI,templ); if (cpu_state.abrt) break; if (flags&D_FLAG) { DI-=4; SI-=4; } else { DI+=4; SI+=4; } @@ -721,7 +706,6 @@ int rep386(int fv) CHECK_WRITE_REP(&_es, EDI, EDI+1); tempw = readmemw(cpu_state.ea_seg->base, ESI); if (cpu_state.abrt) break; writememw(es,EDI,tempw); if (cpu_state.abrt) break; -// if (output) pclog("Written %04X from %08X to %08X %i %08X %04X %08X %04X\n",tempw,ds+ESI,es+EDI,c,ds,ES,es,ES); if (flags&D_FLAG) { EDI-=2; ESI-=2; } else { EDI+=2; ESI+=2; } c--; @@ -740,9 +724,7 @@ int rep386(int fv) { CHECK_WRITE_REP(&_es, EDI, EDI+3); templ = readmeml(cpu_state.ea_seg->base, ESI); if (cpu_state.abrt) break; -// if ((EDI&0xFFFF0000)==0xA0000) cycles-=12; writememl(es,EDI,templ); if (cpu_state.abrt) break; -// if (output) pclog("Load %08X from %08X to %08X %04X %08X %04X %08X\n",templ,ESI,EDI,DS,ds,ES,es); if (flags&D_FLAG) { EDI-=4; ESI-=4; } else { EDI+=4; ESI+=4; } c--; @@ -757,7 +739,6 @@ int rep386(int fv) else firstrepcycle=1; break; case 0xA6: case 0x1A6: /*REP CMPSB*/ -// cpu_notreps++; tempz = (fv) ? 1 : 0; if ((c>0) && (fv==tempz)) { @@ -776,7 +757,6 @@ int rep386(int fv) else firstrepcycle=1; break; case 0x2A6: case 0x3A6: /*REP CMPSB*/ -// cpu_notreps++; tempz = (fv) ? 1 : 0; if ((c>0) && (fv==tempz)) { @@ -795,14 +775,11 @@ int rep386(int fv) else firstrepcycle=1; break; case 0xA7: /*REP CMPSW*/ -// cpu_notreps++; tempz = (fv) ? 1 : 0; if ((c>0) && (fv==tempz)) { -// pclog("CMPSW (%04x:%04x)%05X (%04x:%04x)%05X ", DS,SI, ds+SI, ES,DI, es+DI); tempw = readmemw(cpu_state.ea_seg->base, SI); tempw2=readmemw(es,DI); -// pclog("%04X %04X %c%c %c%c\n", tempw, tempw2, tempw & 0xff, tempw >> 8, tempw2 & 0xff, tempw2 >> 8); if (cpu_state.abrt) { flags=of; break; } if (flags&D_FLAG) { DI-=2; SI-=2; } @@ -817,7 +794,6 @@ int rep386(int fv) else firstrepcycle=1; break; case 0x1A7: /*REP CMPSL*/ -// cpu_notreps++; tempz = (fv) ? 1 : 0; if ((c>0) && (fv==tempz)) { @@ -836,7 +812,6 @@ int rep386(int fv) else firstrepcycle=1; break; case 0x2A7: /*REP CMPSW*/ -// cpu_notreps++; tempz = (fv) ? 1 : 0; if ((c>0) && (fv==tempz)) { @@ -855,7 +830,6 @@ int rep386(int fv) else firstrepcycle=1; break; case 0x3A7: /*REP CMPSL*/ -// cpu_notreps++; tempz = (fv) ? 1 : 0; if ((c>0) && (fv==tempz)) { @@ -989,8 +963,6 @@ int rep386(int fv) else firstrepcycle=1; break; case 0xAC: case 0x1AC: /*REP LODSB*/ -// cpu_notreps++; -// if (ds==0xFFFFFFFF) pclog("Null selector REP LODSB %04X(%06X):%06X\n",CS,cs,pc); if (c>0) { AL = readmemb(cpu_state.ea_seg->base, SI); @@ -1005,8 +977,6 @@ int rep386(int fv) else firstrepcycle=1; break; case 0x2AC: case 0x3AC: /*REP LODSB*/ -// cpu_notreps++; -// if (ds==0xFFFFFFFF) pclog("Null selector REP LODSB %04X(%06X):%06X\n",CS,cs,pc); if (c>0) { AL = readmemb(cpu_state.ea_seg->base, ESI); @@ -1021,8 +991,6 @@ int rep386(int fv) else firstrepcycle=1; break; case 0xAD: /*REP LODSW*/ -// cpu_notreps++; -// if (ds==0xFFFFFFFF) pclog("Null selector REP LODSW %04X(%06X):%06X\n",CS,cs,pc); if (c>0) { AX = readmemw(cpu_state.ea_seg->base, SI); @@ -1037,8 +1005,6 @@ int rep386(int fv) else firstrepcycle=1; break; case 0x1AD: /*REP LODSL*/ -// cpu_notreps++; -// if (ds==0xFFFFFFFF) pclog("Null selector REP LODSL %04X(%06X):%06X\n",CS,cs,pc); if (c>0) { EAX = readmeml(cpu_state.ea_seg->base, SI); @@ -1053,8 +1019,6 @@ int rep386(int fv) else firstrepcycle=1; break; case 0x2AD: /*REP LODSW*/ -// cpu_notreps++; -// if (ds==0xFFFFFFFF) pclog("Null selector REP LODSW %04X(%06X):%06X\n",CS,cs,pc); if (c>0) { AX = readmemw(cpu_state.ea_seg->base, ESI); @@ -1069,8 +1033,6 @@ int rep386(int fv) else firstrepcycle=1; break; case 0x3AD: /*REP LODSL*/ -// cpu_notreps++; -// if (ds==0xFFFFFFFF) pclog("Null selector REP LODSL %04X(%06X):%06X\n",CS,cs,pc); if (c>0) { EAX = readmeml(cpu_state.ea_seg->base, ESI); @@ -1086,8 +1048,6 @@ int rep386(int fv) break; case 0xAE: case 0x1AE: /*REP SCASB*/ cpu_notreps++; -// if (es==0xFFFFFFFF) pclog("Null selector REP SCASB %04X(%06X):%06X\n",CS,cs,pc); -// tempz=(fv)?1:0; tempz = (fv) ? 1 : 0; while ((c > 0) && (fv == tempz)) { @@ -1110,14 +1070,11 @@ int rep386(int fv) break; case 0x2AE: case 0x3AE: /*REP SCASB*/ cpu_notreps++; -// if (es==0xFFFFFFFF) pclog("Null selector REP SCASB %04X(%06X):%06X\n",CS,cs,pc); -// tempz=(fv)?1:0; tempz = (fv) ? 1 : 0; while ((c > 0) && (fv == tempz)) { temp2=readmemb(es,EDI); if (cpu_state.abrt) { flags=of; break; } -// if (output) pclog("Compare %02X,%02X\n",temp2,AL); setsub8(AL,temp2); tempz = (ZF_SET()) ? 1 : 0; if (flags&D_FLAG) EDI--; @@ -1135,7 +1092,6 @@ int rep386(int fv) break; case 0xAF: /*REP SCASW*/ cpu_notreps++; -// if (es==0xFFFFFFFF) pclog("Null selector REP SCASW %04X(%06X):%06X\n",CS,cs,pc); tempz = (fv) ? 1 : 0; while ((c > 0) && (fv == tempz)) { @@ -1158,7 +1114,6 @@ int rep386(int fv) break; case 0x1AF: /*REP SCASL*/ cpu_notreps++; -// if (es==0xFFFFFFFF) pclog("Null selector REP SCASL %04X(%06X):%06X\n",CS,cs,pc); tempz = (fv) ? 1 : 0; while ((c > 0) && (fv == tempz)) { @@ -1181,7 +1136,6 @@ int rep386(int fv) break; case 0x2AF: /*REP SCASW*/ cpu_notreps++; -// if (es==0xFFFFFFFF) pclog("Null selector REP SCASW %04X(%06X):%06X\n",CS,cs,pc); tempz = (fv) ? 1 : 0; while ((c > 0) && (fv == tempz)) { @@ -1204,7 +1158,6 @@ int rep386(int fv) break; case 0x3AF: /*REP SCASL*/ cpu_notreps++; -// if (es==0xFFFFFFFF) pclog("Null selector REP SCASL %04X(%06X):%06X\n",CS,cs,pc); tempz = (fv) ? 1 : 0; while ((c > 0) && (fv == tempz)) { @@ -1229,7 +1182,6 @@ int rep386(int fv) default: cpu_state.pc = ipc+1; - //pclog("Bad REP %02X %i\n", temp, rep32 >> 8); break; } if (rep32&0x200) ECX=c; @@ -1237,27 +1189,6 @@ int rep386(int fv) CPU_BLOCK_END(); PREFETCH_RUN(total_cycles, 1, -1, reads, reads_l, writes, writes_l, 0); return cpu_state.abrt; -//pclog("rep cpu_block_end=%d %p\n", cpu_block_end, (void *)&cpu_block_end); -// if (output) pclog("%03X %03X\n",rep32,use32); -} - -int checkio(int port) -{ - uint16_t t; - uint8_t d; - cpl_override = 1; - t = readmemw(tr.base, 0x66); - cpl_override = 0; -// pclog("CheckIO 1 %08X %04x %02x\n",tr.base, eflags, _cs.access); - if (cpu_state.abrt) return 0; -// pclog("CheckIO %04X %01X %01X %02X %04X %04X %08X ",CS,CPL,IOPL,port,t,t+(port>>3),tr.base+t+(port>>3)); - if ((t+(port>>3))>tr.limit) return 1; - cpl_override = 1; - d = readmemb386l(0, tr.base + t + (port >> 3)); -// d=readmemb(tr.base,t+(port>>3)); - cpl_override = 0; -// pclog("%02X %02X\n",d,d&(1<<(port&7))); - return d&(1<<(port&7)); } int xout=0; @@ -1276,15 +1207,20 @@ int xout=0; int divl(uint32_t val) { + uint64_t num, quo; + uint32_t rem, quo32; + if (val==0) { divexcp(); return 1; } - uint64_t num=(((uint64_t)EDX)<<32)|EAX; - uint64_t quo=num/val; - uint32_t rem=num%val; - uint32_t quo32=(uint32_t)(quo&0xFFFFFFFF); + + num=(((uint64_t)EDX)<<32)|EAX; + quo=num/val; + rem=num%val; + quo32=(uint32_t)(quo&0xFFFFFFFF); + if (quo!=(uint64_t)quo32) { divexcp(); @@ -1296,15 +1232,20 @@ int divl(uint32_t val) } int idivl(int32_t val) { + int64_t num, quo; + int32_t rem, quo32; + if (val==0) { divexcp(); return 1; } - int64_t num=(((uint64_t)EDX)<<32)|EAX; - int64_t quo=num/val; - int32_t rem=num%val; - int32_t quo32=(int32_t)(quo&0xFFFFFFFF); + + num=(((uint64_t)EDX)<<32)|EAX; + quo=num/val; + rem=num%val; + quo32=(int32_t)(quo&0xFFFFFFFF); + if (quo!=(int64_t)quo32) { divexcp(); @@ -1338,7 +1279,19 @@ int dontprint=0; #define CACHE_ON() (!(cr0 & (1 << 30)) /*&& (cr0 & 1)*/ && !(flags & T_FLAG)) -//#define CACHE_ON() 0 + +static int cpu_cycle_period(void) +{ + switch(cpu_pci_speed) + { + case 333333333: + return is_pentium ? 1000 : 1333; + break; + default: + return 1000; + break; + } +} static int cycles_main = 0; void exec386_dynarec(int cycs) @@ -1348,18 +1301,51 @@ void exec386_dynarec(int cycs) int tempi; int cycdiff; int oldcyc; + uint32_t start_pc = 0; -//output = 3; cycles_main += cycs; while (cycles_main > 0) { int cycles_start; - - cycles += 1000; + +#if 0 + switch(cpu_pci_speed) + { + case 16000000: + cycles += 640; + break; + case 20000000: + cycles += 800; + break; + case 25000000: + default: + cycles += 1000; + break; + case 27500000: + cycles += 1100; + break; + case 30000000: + cycles += 1200; + break; + case 333333333: + cycles += 1333; + break; + case 37500000: + cycles += 1500; + break; + case 40000000: + cycles += 1600; + break; + case 41666667: + cycles += 1666; + break; + } +#endif + cycles += cpu_cycle_period(); + cycles_start = cycles; timer_start_period(cycles << TIMER_SHIFT); -// output=3; while (cycles>0) { oldcs = CS; @@ -1370,11 +1356,9 @@ void exec386_dynarec(int cycs) cycdiff=0; oldcyc=cycles; -// if (output && CACHE_ON()) pclog("Block %04x:%04x %04x:%08x\n", CS, pc, SS,ESP); if (!CACHE_ON()) /*Interpret block*/ { cpu_block_end = 0; -// if (output) pclog("Interpret block at %04x:%04x %04x %04x %04x %04x %04x %04x %04x\n", CS, pc, AX, BX, CX, DX, SI, DI, SP); while (!cpu_block_end) { oldcs=CS; @@ -1385,19 +1369,13 @@ void exec386_dynarec(int cycs) cpu_state.ea_seg = &_ds; cpu_state.ssegs = 0; - opcodestart: fetchdat = fastreadl(cs + cpu_state.pc); -// if (!fetchdat) -// fatal("Dead with cache off\n"); if (!cpu_state.abrt) { trap = flags & T_FLAG; opcode = fetchdat & 0xFF; fetchdat >>= 8; -// if (output == 3) -// pclog("int %04X(%06X):%04X : %08X %08X %08X %08X %04X %04X %04X(%08X) %04X %04X %04X(%08X) %08X %08X %08X SP=%04X:%08X %02X %04X %i %08X %08X %i %i %02X %02X %02X %02X %02X %f %02X%02X %02X%02X\n",CS,cs,pc,EAX,EBX,ECX,EDX,CS,DS,ES,es,FS,GS,SS,ss,EDI,ESI,EBP,SS,ESP,opcode,flags,ins,0, ldt.base, CPL, stack32, pic.pend, pic.mask, pic.mask2, pic2.pend, pic2.mask, pit.c[0], ram[0x8f13f], ram[0x8f13e], ram[0x8f141], ram[0x8f140]); - cpu_state.pc++; x86_opcodes[(opcode | cpu_state.op32) & 0x3ff](fetchdat); } @@ -1443,28 +1421,29 @@ void exec386_dynarec(int cycs) and physical address. The physical address check will also catch any page faults at this stage*/ valid_block = (block->pc == cs + cpu_state.pc) && (block->_cs == cs) && - (block->use32 == use32) && (block->phys == phys_addr) && (block->stack32 == stack32); + (block->phys == phys_addr) && (block->status == cpu_cur_status); if (!valid_block) { uint64_t mask = (uint64_t)1 << ((phys_addr >> PAGE_MASK_SHIFT) & PAGE_MASK_MASK); - if (page->code_present_mask & mask) + if (page->code_present_mask[(phys_addr >> PAGE_MASK_INDEX_SHIFT) & PAGE_MASK_INDEX_MASK] & mask) { /*Walk page tree to see if we find the correct block*/ codeblock_t *new_block = codeblock_tree_find(phys_addr, cs); if (new_block) { valid_block = (new_block->pc == cs + cpu_state.pc) && (new_block->_cs == cs) && - (new_block->use32 == use32) && (new_block->phys == phys_addr) && (new_block->stack32 == stack32); + (new_block->phys == phys_addr) && (new_block->status == cpu_cur_status); if (valid_block) block = new_block; } } } - if (valid_block && (block->page_mask & page->dirty_mask)) + + if (valid_block && (block->page_mask & *block->dirty_mask)) { - codegen_check_flush(page, page->dirty_mask, phys_addr); - page->dirty_mask = 0; + codegen_check_flush(page, page->dirty_mask[(phys_addr >> 10) & 3], phys_addr); + page->dirty_mask[(phys_addr >> 10) & 3] = 0; if (!block->pc) valid_block = 0; } @@ -1477,15 +1456,15 @@ void exec386_dynarec(int cycs) allow the first page to be interpreted and for the page fault to occur when the page boundary is actually crossed.*/ - uint32_t phys_addr_2 = get_phys_noabrt(block->endpc) & ~0xfff; + uint32_t phys_addr_2 = get_phys_noabrt(block->endpc); page_t *page_2 = &pages[phys_addr_2 >> 12]; if ((block->phys_2 ^ phys_addr_2) & ~0xfff) valid_block = 0; - else if (block->page_mask2 & page_2->dirty_mask) + else if (block->page_mask2 & *block->dirty_mask2) { - codegen_check_flush(page_2, page_2->dirty_mask, phys_addr_2); - page_2->dirty_mask = 0; + codegen_check_flush(page_2, page_2->dirty_mask[(phys_addr_2 >> 10) & 3], phys_addr_2); + page_2->dirty_mask[(phys_addr_2 >> 10) & 3] = 0; if (!block->pc) valid_block = 0; } @@ -1504,13 +1483,11 @@ void exec386_dynarec(int cycs) void (*code)() = (void *)&block->data[BLOCK_START]; codeblock_hash[hash] = block; -// if (output) pclog("Run block at %04x:%04x %04x %04x %04x %04x %04x %04x ESP=%08x %04x %08x %08x %016llx %08x\n", CS, pc, AX, BX, CX, DX, SI, DI, ESP, BP, get_phys(cs+pc), block->phys, block->page_mask, block->endpc); inrecomp=1; code(); inrecomp=0; if (!use32) cpu_state.pc &= 0xffff; -// cpu_recomp_ins += block->ins; cpu_recomp_blocks++; /* ins += codeblock_ins[index]; insc += codeblock_ins[index];*/ @@ -1518,10 +1495,8 @@ inrecomp=0; } else if (valid_block && !cpu_state.abrt) { - uint32_t start_page = cpu_state.pc >> 12; - uint32_t start_pc = cpu_state.pc; + start_pc = cpu_state.pc; -// pclog("Hash %08x %i\n", codeblock_hash_pc[HASH(cs + pc)], codeblock_page_dirty[(cs + pc) >> 12]); cpu_block_end = 0; x86_was_reset = 0; @@ -1530,7 +1505,6 @@ inrecomp=0; codegen_block_start_recompile(block); codegen_in_recompile = 1; -// if (output) pclog("Recompile block at %04x:%04x %04x %04x %04x %04x %04x %04x ESP=%04x %04x %02x%02x:%02x%02x %02x%02x:%02x%02x %02x%02x:%02x%02x\n", CS, pc, AX, BX, CX, DX, SI, DI, ESP, BP, ram[0x116330+0x6df4+0xa+3], ram[0x116330+0x6df4+0xa+2], ram[0x116330+0x6df4+0xa+1], ram[0x116330+0x6df4+0xa+0], ram[0x11d136+3],ram[0x11d136+2],ram[0x11d136+1],ram[0x11d136+0], ram[(0x119abe)+0x3],ram[(0x119abe)+0x2],ram[(0x119abe)+0x1],ram[(0x119abe)+0x0]); while (!cpu_block_end) { oldcs=CS; @@ -1541,21 +1515,13 @@ inrecomp=0; cpu_state.ea_seg = &_ds; cpu_state.ssegs = 0; - opcodestart_compile: fetchdat = fastreadl(cs + cpu_state.pc); -// if (fetchdat == 0xffffffff) -// fatal("Dead ffffffff\n"); -// if (!fetchdat) -// fatal("Dead\n"); if (!cpu_state.abrt) { trap = flags & T_FLAG; opcode = fetchdat & 0xFF; fetchdat >>= 8; -// if (output == 3) -// pclog("%04X(%06X):%04X : %08X %08X %08X %08X %04X %04X %04X(%08X) %04X %04X %04X(%08X) %08X %08X %08X SP=%04X:%08X %02X %04X %i %08X %08X %i %i %02X %02X %02X %02X %02X %08x %08x\n",CS,cs,pc,EAX,EBX,ECX,EDX,CS,DS,ES,es,FS,GS,SS,ss,EDI,ESI,EBP,SS,ESP,opcode,flags,ins,0, ldt.base, CPL, stack32, pic.pend, pic.mask, pic.mask2, pic2.pend, pic2.mask, cs+pc, pccache); - cpu_state.pc++; codegen_generate_call(opcode, x86_opcodes[(opcode | cpu_state.op32) & 0x3ff], fetchdat, cpu_state.pc, cpu_state.pc-1); @@ -1572,7 +1538,7 @@ inrecomp=0; will prevent any block from spanning more than 2 pages. In practice this limit will never be hit, as host block size is only 2kB*/ - if ((cpu_state.pc - start_pc) > 4000) + if ((cpu_state.pc - start_pc) > 1000) CPU_BLOCK_END(); if (trap) @@ -1596,23 +1562,17 @@ inrecomp=0; codegen_reset(); codegen_in_recompile = 0; -// output &= ~2; } else if (!cpu_state.abrt) { /*Mark block but do not recompile*/ - uint32_t start_page = cpu_state.pc >> 12; - uint32_t start_pc = cpu_state.pc; + start_pc = cpu_state.pc; -// pclog("Hash %08x %i\n", codeblock_hash_pc[HASH(cs + pc)], codeblock_page_dirty[(cs + pc) >> 12]); cpu_block_end = 0; x86_was_reset = 0; -// cpu_new_blocks++; - codegen_block_init(phys_addr); -// if (output) pclog("Recompile block at %04x:%04x %04x %04x %04x %04x %04x %04x ESP=%04x %04x %02x%02x:%02x%02x %02x%02x:%02x%02x %02x%02x:%02x%02x\n", CS, pc, AX, BX, CX, DX, SI, DI, ESP, BP, ram[0x116330+0x6df4+0xa+3], ram[0x116330+0x6df4+0xa+2], ram[0x116330+0x6df4+0xa+1], ram[0x116330+0x6df4+0xa+0], ram[0x11d136+3],ram[0x11d136+2],ram[0x11d136+1],ram[0x11d136+0], ram[(0x119abe)+0x3],ram[(0x119abe)+0x2],ram[(0x119abe)+0x1],ram[(0x119abe)+0x0]); while (!cpu_block_end) { oldcs=CS; @@ -1632,9 +1592,6 @@ inrecomp=0; opcode = fetchdat & 0xFF; fetchdat >>= 8; -// if (output == 3) -// pclog("%04X(%06X):%04X : %08X %08X %08X %08X %04X %04X %04X(%08X) %04X %04X %04X(%08X) %08X %08X %08X SP=%04X:%08X %02X %04X %i %08X %08X %i %i %02X %02X %02X %02X %02X %08x %08x\n",CS,cs,pc,EAX,EBX,ECX,EDX,CS,DS,ES,es,FS,GS,SS,ss,EDI,ESI,EBP,SS,ESP,opcode,flags,ins,0, ldt.base, CPL, stack32, pic.pend, pic.mask, pic.mask2, pic2.pend, pic2.mask, cs+pc, pccache); - cpu_state.pc++; x86_opcodes[(opcode | cpu_state.op32) & 0x3ff](fetchdat); @@ -1649,7 +1606,7 @@ inrecomp=0; will prevent any block from spanning more than 2 pages. In practice this limit will never be hit, as host block size is only 2kB*/ - if ((cpu_state.pc - start_pc) > 4000) + if ((cpu_state.pc - start_pc) > 1000) CPU_BLOCK_END(); if (trap) @@ -1671,18 +1628,12 @@ inrecomp=0; if (x86_was_reset) codegen_reset(); - -// output &= ~2; } -// if (output && (SP & 1)) -// fatal("odd SP\n"); } cycdiff=oldcyc-cycles; tsc += cycdiff; -// timer_end_period(cycles); - if (cpu_state.abrt) { flags_rebuild(); @@ -1710,8 +1661,6 @@ inrecomp=0; { flags_rebuild(); -// oldpc=pc; -// oldcs=CS; if (msw&1) { pmodeint(1,0); @@ -1734,7 +1683,6 @@ inrecomp=0; temp=picinterrupt(); if (temp!=0xFF) { -// pclog("IRQ %02X %04X:%04X %04X:%04X\n", temp, SS, SP, CS, pc); CPU_BLOCK_END(); flags_rebuild(); if (msw&1) diff --git a/src/386_dynarec_ops.c b/src/CPU/386_dynarec_ops.c similarity index 88% rename from src/386_dynarec_ops.c rename to src/CPU/386_dynarec_ops.c index bf2fe7ad4..e0e018872 100644 --- a/src/386_dynarec_ops.c +++ b/src/CPU/386_dynarec_ops.c @@ -1,11 +1,16 @@ -#include "ibm.h" +#include +#ifndef INFINITY +# define INFINITY (__builtin_inff()) +#endif +#include "../ibm.h" #include "cpu.h" #include "x86.h" #include "x86_ops.h" #include "x87.h" #include "x86_flags.h" -#include "mem.h" +#include "../mem.h" #include "codegen.h" +#include "../pic.h" #define CPU_BLOCK_END() cpu_block_end = 1 @@ -15,7 +20,7 @@ extern uint16_t *mod1add[2][8]; extern uint32_t *mod1seg[8]; -static inline void fetch_ea_32_long(uint32_t rmdat) +static __inline void fetch_ea_32_long(uint32_t rmdat) { eal_r = eal_w = NULL; easeg = cpu_state.ea_seg->base; @@ -31,7 +36,7 @@ static inline void fetch_ea_32_long(uint32_t rmdat) cpu_state.last_ea = cpu_state.eaaddr; } -static inline void fetch_ea_16_long(uint32_t rmdat) +static __inline void fetch_ea_16_long(uint32_t rmdat) { eal_r = eal_w = NULL; easeg = cpu_state.ea_seg->base; diff --git a/src/386_ops.h b/src/CPU/386_ops.h similarity index 99% rename from src/386_ops.h rename to src/CPU/386_ops.h index 15ce9349a..0217c384d 100644 --- a/src/386_ops.h +++ b/src/CPU/386_ops.h @@ -1,6 +1,23 @@ -/* Copyright holders: Sarah Walker, Tenshi, leilei - see COPYING for more details -*/ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * 286/386+ instruction handlers list. + * + * Version: @(#)386_ops.h 1.0.0 2017/05/30 + * + * Author: Sarah Walker, + * leilei, + * Miran Grca, + * Copyright 2008-2017 Sarah Walker. + * Copyright 2016-2017 leilei. + * Copyright 2016-2017 Miran Grca. + */ + #include "x86_ops.h" @@ -15,7 +32,7 @@ } \ } while (0) -static inline void PUSH_W(uint16_t val) +static __inline void PUSH_W(uint16_t val) { if (stack32) { @@ -31,7 +48,7 @@ static inline void PUSH_W(uint16_t val) } } -static inline void PUSH_L(uint32_t val) +static __inline void PUSH_L(uint32_t val) { if (stack32) { @@ -47,7 +64,7 @@ static inline void PUSH_L(uint32_t val) } } -static inline uint16_t POP_W() +static __inline uint16_t POP_W() { uint16_t ret; if (stack32) @@ -65,7 +82,7 @@ static inline uint16_t POP_W() return ret; } -static inline uint32_t POP_L() +static __inline uint32_t POP_L() { uint32_t ret; if (stack32) @@ -83,7 +100,7 @@ static inline uint32_t POP_L() return ret; } -static inline uint16_t POP_W_seg(uint32_t seg) +static __inline uint16_t POP_W_seg(uint32_t seg) { uint16_t ret; if (stack32) @@ -101,7 +118,7 @@ static inline uint16_t POP_W_seg(uint32_t seg) return ret; } -static inline uint32_t POP_L_seg(uint32_t seg) +static __inline uint32_t POP_L_seg(uint32_t seg) { uint32_t ret; if (stack32) @@ -119,6 +136,17 @@ static inline uint32_t POP_L_seg(uint32_t seg) return ret; } +static int fopcode; + +static int ILLEGAL(uint32_t fetchdat) +{ + cpu_state.pc = cpu_state.oldpc; + + pclog("Illegal instruction %08X (%02X)\n", fetchdat, fopcode); + x86illegal(); + return 0; +} + #include "x86seg.h" #include "x86_ops_arith.h" #include "x86_ops_atomic.h" @@ -133,6 +161,8 @@ static inline uint32_t POP_L_seg(uint32_t seg) #include "x86_ops_io.h" #include "x86_ops_jump.h" #include "x86_ops_misc.h" +#include "x87_ops.h" +#include "x86_ops_i686.h" #include "x86_ops_mmx.h" #include "x86_ops_mmx_arith.h" #include "x86_ops_mmx_cmp.h" @@ -156,25 +186,12 @@ static inline uint32_t POP_L_seg(uint32_t seg) #include "x86_ops_string.h" #include "x86_ops_xchg.h" -static int fopcode; - -static int ILLEGAL(uint32_t fetchdat) -{ - cpu_state.pc = cpu_state.oldpc; - -// fatal("Illegal instruction %08X\n", fetchdat); - pclog("Illegal instruction %08X (%02X)\n", fetchdat, fopcode); - x86illegal(); - return 0; -} - static int op0F_w_a16(uint32_t fetchdat) { int opcode = fetchdat & 0xff; fopcode = opcode; cpu_state.pc++; - // pclog("A16W: 0F %02X\n", opcode); PREFETCH_PREFIX(); return x86_opcodes_0f[opcode](fetchdat >> 8); @@ -185,7 +202,6 @@ static int op0F_l_a16(uint32_t fetchdat) fopcode = opcode; cpu_state.pc++; - // pclog("A16L: 0F %02X\n", opcode); PREFETCH_PREFIX(); return x86_opcodes_0f[opcode | 0x100](fetchdat >> 8); @@ -196,7 +212,6 @@ static int op0F_w_a32(uint32_t fetchdat) fopcode = opcode; cpu_state.pc++; - // pclog("A32W: 0F %02X\n", opcode); PREFETCH_PREFIX(); return x86_opcodes_0f[opcode | 0x200](fetchdat >> 8); @@ -207,15 +222,11 @@ static int op0F_l_a32(uint32_t fetchdat) fopcode = opcode; cpu_state.pc++; - // pclog("A32L: 0F %02X\n", opcode); PREFETCH_PREFIX(); return x86_opcodes_0f[opcode | 0x300](fetchdat >> 8); } -#include "x87_ops.h" -#include "x86_ops_i686.h" - OpFn OP_TABLE(286_0f)[1024] = { /*16-bit data, 16-bit addr*/ @@ -1241,7 +1252,7 @@ OpFn OP_TABLE(286)[1024] = /*c0*/ opC0_a16, opC1_w_a16, opRET_w_imm, opRET_w, opLES_w_a16, opLDS_w_a16, opMOV_b_imm_a16,opMOV_w_imm_a16,opENTER_w, opLEAVE_w, opRETF_a16_imm, opRETF_a16, opINT3, opINT, opINTO, opIRET_286, /*d0*/ opD0_a16, opD1_w_a16, opD2_a16, opD3_w_a16, opAAM, opAAD, opSETALC, opXLAT_a16, opESCAPE_d8_a16,opESCAPE_d9_a16,opESCAPE_da_a16,opESCAPE_db_a16,opESCAPE_dc_a16,opESCAPE_dd_a16,opESCAPE_de_a16,opESCAPE_df_a16, /*e0*/ opLOOPNE_w, opLOOPE_w, opLOOP_w, opJCXZ, opIN_AL_imm, opIN_AX_imm, opOUT_AL_imm, opOUT_AX_imm, opCALL_r16, opJMP_r16, opJMP_far_a16, opJMP_r8, opIN_AL_DX, opIN_AX_DX, opOUT_AL_DX, opOUT_AX_DX, -/*f0*/ opLOCK, ILLEGAL, opREPNE, opREPE, opHLT, opCMC, opF6_a16, opF7_w_a16, opCLC, opSTC, opCLI, opSTI, opCLD, opSTD, opINCDEC_b_a16, opFF_w_a16, +/*f0*/ opLOCK, opLOCK, opREPNE, opREPE, opHLT, opCMC, opF6_a16, opF7_w_a16, opCLC, opSTC, opCLI, opSTI, opCLD, opSTD, opINCDEC_b_a16, opFF_w_a16, /*32-bit data, 16-bit addr*/ /* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ @@ -1263,7 +1274,7 @@ OpFn OP_TABLE(286)[1024] = /*c0*/ opC0_a16, opC1_w_a16, opRET_w_imm, opRET_w, opLES_w_a16, opLDS_w_a16, opMOV_b_imm_a16,opMOV_w_imm_a16,opENTER_w, opLEAVE_w, opRETF_a16_imm, opRETF_a16, opINT3, opINT, opINTO, opIRET_286, /*d0*/ opD0_a16, opD1_w_a16, opD2_a16, opD3_w_a16, opAAM, opAAD, opSETALC, opXLAT_a16, opESCAPE_d8_a16,opESCAPE_d9_a16,opESCAPE_da_a16,opESCAPE_db_a16,opESCAPE_dc_a16,opESCAPE_dd_a16,opESCAPE_de_a16,opESCAPE_df_a16, /*e0*/ opLOOPNE_w, opLOOPE_w, opLOOP_w, opJCXZ, opIN_AL_imm, opIN_AX_imm, opOUT_AL_imm, opOUT_AX_imm, opCALL_r16, opJMP_r16, opJMP_far_a16, opJMP_r8, opIN_AL_DX, opIN_AX_DX, opOUT_AL_DX, opOUT_AX_DX, -/*f0*/ opLOCK, ILLEGAL, opREPNE, opREPE, opHLT, opCMC, opF6_a16, opF7_w_a16, opCLC, opSTC, opCLI, opSTI, opCLD, opSTD, opINCDEC_b_a16, opFF_w_a16, +/*f0*/ opLOCK, opLOCK, opREPNE, opREPE, opHLT, opCMC, opF6_a16, opF7_w_a16, opCLC, opSTC, opCLI, opSTI, opCLD, opSTD, opINCDEC_b_a16, opFF_w_a16, /*16-bit data, 32-bit addr*/ /* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ @@ -1285,7 +1296,7 @@ OpFn OP_TABLE(286)[1024] = /*c0*/ opC0_a16, opC1_w_a16, opRET_w_imm, opRET_w, opLES_w_a16, opLDS_w_a16, opMOV_b_imm_a16,opMOV_w_imm_a16,opENTER_w, opLEAVE_w, opRETF_a16_imm, opRETF_a16, opINT3, opINT, opINTO, opIRET_286, /*d0*/ opD0_a16, opD1_w_a16, opD2_a16, opD3_w_a16, opAAM, opAAD, opSETALC, opXLAT_a16, opESCAPE_d8_a16,opESCAPE_d9_a16,opESCAPE_da_a16,opESCAPE_db_a16,opESCAPE_dc_a16,opESCAPE_dd_a16,opESCAPE_de_a16,opESCAPE_df_a16, /*e0*/ opLOOPNE_w, opLOOPE_w, opLOOP_w, opJCXZ, opIN_AL_imm, opIN_AX_imm, opOUT_AL_imm, opOUT_AX_imm, opCALL_r16, opJMP_r16, opJMP_far_a16, opJMP_r8, opIN_AL_DX, opIN_AX_DX, opOUT_AL_DX, opOUT_AX_DX, -/*f0*/ opLOCK, ILLEGAL, opREPNE, opREPE, opHLT, opCMC, opF6_a16, opF7_w_a16, opCLC, opSTC, opCLI, opSTI, opCLD, opSTD, opINCDEC_b_a16, opFF_w_a16, +/*f0*/ opLOCK, opLOCK, opREPNE, opREPE, opHLT, opCMC, opF6_a16, opF7_w_a16, opCLC, opSTC, opCLI, opSTI, opCLD, opSTD, opINCDEC_b_a16, opFF_w_a16, /*32-bit data, 32-bit addr*/ /* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ @@ -1307,7 +1318,7 @@ OpFn OP_TABLE(286)[1024] = /*c0*/ opC0_a16, opC1_w_a16, opRET_w_imm, opRET_w, opLES_w_a16, opLDS_w_a16, opMOV_b_imm_a16,opMOV_w_imm_a16,opENTER_w, opLEAVE_w, opRETF_a16_imm, opRETF_a16, opINT3, opINT, opINTO, opIRET_286, /*d0*/ opD0_a16, opD1_w_a16, opD2_a16, opD3_w_a16, opAAM, opAAD, opSETALC, opXLAT_a16, opESCAPE_d8_a16,opESCAPE_d9_a16,opESCAPE_da_a16,opESCAPE_db_a16,opESCAPE_dc_a16,opESCAPE_dd_a16,opESCAPE_de_a16,opESCAPE_df_a16, /*e0*/ opLOOPNE_w, opLOOPE_w, opLOOP_w, opJCXZ, opIN_AL_imm, opIN_AX_imm, opOUT_AL_imm, opOUT_AX_imm, opCALL_r16, opJMP_r16, opJMP_far_a16, opJMP_r8, opIN_AL_DX, opIN_AX_DX, opOUT_AL_DX, opOUT_AX_DX, -/*f0*/ opLOCK, ILLEGAL, opREPNE, opREPE, opHLT, opCMC, opF6_a16, opF7_w_a16, opCLC, opSTC, opCLI, opSTI, opCLD, opSTD, opINCDEC_b_a16, opFF_w_a16, +/*f0*/ opLOCK, opLOCK, opREPNE, opREPE, opHLT, opCMC, opF6_a16, opF7_w_a16, opCLC, opSTC, opCLI, opSTI, opCLD, opSTD, opINCDEC_b_a16, opFF_w_a16, }; OpFn OP_TABLE(386)[1024] = @@ -1332,7 +1343,7 @@ OpFn OP_TABLE(386)[1024] = /*c0*/ opC0_a16, opC1_w_a16, opRET_w_imm, opRET_w, opLES_w_a16, opLDS_w_a16, opMOV_b_imm_a16,opMOV_w_imm_a16,opENTER_w, opLEAVE_w, opRETF_a16_imm, opRETF_a16, opINT3, opINT, opINTO, opIRET, /*d0*/ opD0_a16, opD1_w_a16, opD2_a16, opD3_w_a16, opAAM, opAAD, opSETALC, opXLAT_a16, opESCAPE_d8_a16,opESCAPE_d9_a16,opESCAPE_da_a16,opESCAPE_db_a16,opESCAPE_dc_a16,opESCAPE_dd_a16,opESCAPE_de_a16,opESCAPE_df_a16, /*e0*/ opLOOPNE_w, opLOOPE_w, opLOOP_w, opJCXZ, opIN_AL_imm, opIN_AX_imm, opOUT_AL_imm, opOUT_AX_imm, opCALL_r16, opJMP_r16, opJMP_far_a16, opJMP_r8, opIN_AL_DX, opIN_AX_DX, opOUT_AL_DX, opOUT_AX_DX, -/*f0*/ opLOCK, ILLEGAL, opREPNE, opREPE, opHLT, opCMC, opF6_a16, opF7_w_a16, opCLC, opSTC, opCLI, opSTI, opCLD, opSTD, opINCDEC_b_a16, opFF_w_a16, +/*f0*/ opLOCK, opINT1, opREPNE, opREPE, opHLT, opCMC, opF6_a16, opF7_w_a16, opCLC, opSTC, opCLI, opSTI, opCLD, opSTD, opINCDEC_b_a16, opFF_w_a16, /*32-bit data, 16-bit addr*/ /* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ @@ -1354,7 +1365,7 @@ OpFn OP_TABLE(386)[1024] = /*c0*/ opC0_a16, opC1_l_a16, opRET_l_imm, opRET_l, opLES_l_a16, opLDS_l_a16, opMOV_b_imm_a16,opMOV_l_imm_a16,opENTER_l, opLEAVE_l, opRETF_a32_imm, opRETF_a32, opINT3, opINT, opINTO, opIRETD, /*d0*/ opD0_a16, opD1_l_a16, opD2_a16, opD3_l_a16, opAAM, opAAD, opSETALC, opXLAT_a16, opESCAPE_d8_a16,opESCAPE_d9_a16,opESCAPE_da_a16,opESCAPE_db_a16,opESCAPE_dc_a16,opESCAPE_dd_a16,opESCAPE_de_a16,opESCAPE_df_a16, /*e0*/ opLOOPNE_w, opLOOPE_w, opLOOP_w, opJCXZ, opIN_AL_imm, opIN_EAX_imm, opOUT_AL_imm, opOUT_EAX_imm, opCALL_r32, opJMP_r32, opJMP_far_a32, opJMP_r8, opIN_AL_DX, opIN_EAX_DX, opOUT_AL_DX, opOUT_EAX_DX, -/*f0*/ opLOCK, ILLEGAL, opREPNE, opREPE, opHLT, opCMC, opF6_a16, opF7_l_a16, opCLC, opSTC, opCLI, opSTI, opCLD, opSTD, opINCDEC_b_a16, opFF_l_a16, +/*f0*/ opLOCK, opINT1, opREPNE, opREPE, opHLT, opCMC, opF6_a16, opF7_l_a16, opCLC, opSTC, opCLI, opSTI, opCLD, opSTD, opINCDEC_b_a16, opFF_l_a16, /*16-bit data, 32-bit addr*/ /* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ @@ -1376,7 +1387,7 @@ OpFn OP_TABLE(386)[1024] = /*c0*/ opC0_a32, opC1_w_a32, opRET_w_imm, opRET_w, opLES_w_a32, opLDS_w_a32, opMOV_b_imm_a32,opMOV_w_imm_a32,opENTER_w, opLEAVE_w, opRETF_a16_imm, opRETF_a16, opINT3, opINT, opINTO, opIRET, /*d0*/ opD0_a32, opD1_w_a32, opD2_a32, opD3_w_a32, opAAM, opAAD, opSETALC, opXLAT_a32, opESCAPE_d8_a32,opESCAPE_d9_a32,opESCAPE_da_a32,opESCAPE_db_a32,opESCAPE_dc_a32,opESCAPE_dd_a32,opESCAPE_de_a32,opESCAPE_df_a32, /*e0*/ opLOOPNE_l, opLOOPE_l, opLOOP_l, opJECXZ, opIN_AL_imm, opIN_AX_imm, opOUT_AL_imm, opOUT_AX_imm, opCALL_r16, opJMP_r16, opJMP_far_a16, opJMP_r8, opIN_AL_DX, opIN_AX_DX, opOUT_AL_DX, opOUT_AX_DX, -/*f0*/ opLOCK, ILLEGAL, opREPNE, opREPE, opHLT, opCMC, opF6_a32, opF7_w_a32, opCLC, opSTC, opCLI, opSTI, opCLD, opSTD, opINCDEC_b_a32, opFF_w_a32, +/*f0*/ opLOCK, opINT1, opREPNE, opREPE, opHLT, opCMC, opF6_a32, opF7_w_a32, opCLC, opSTC, opCLI, opSTI, opCLD, opSTD, opINCDEC_b_a32, opFF_w_a32, /*32-bit data, 32-bit addr*/ /* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ @@ -1398,5 +1409,5 @@ OpFn OP_TABLE(386)[1024] = /*c0*/ opC0_a32, opC1_l_a32, opRET_l_imm, opRET_l, opLES_l_a32, opLDS_l_a32, opMOV_b_imm_a32,opMOV_l_imm_a32,opENTER_l, opLEAVE_l, opRETF_a32_imm, opRETF_a32, opINT3, opINT, opINTO, opIRETD, /*d0*/ opD0_a32, opD1_l_a32, opD2_a32, opD3_l_a32, opAAM, opAAD, opSETALC, opXLAT_a32, opESCAPE_d8_a32,opESCAPE_d9_a32,opESCAPE_da_a32,opESCAPE_db_a32,opESCAPE_dc_a32,opESCAPE_dd_a32,opESCAPE_de_a32,opESCAPE_df_a32, /*e0*/ opLOOPNE_l, opLOOPE_l, opLOOP_l, opJECXZ, opIN_AL_imm, opIN_EAX_imm, opOUT_AL_imm, opOUT_EAX_imm, opCALL_r32, opJMP_r32, opJMP_far_a32, opJMP_r8, opIN_AL_DX, opIN_EAX_DX, opOUT_AL_DX, opOUT_EAX_DX, -/*f0*/ opLOCK, ILLEGAL, opREPNE, opREPE, opHLT, opCMC, opF6_a32, opF7_l_a32, opCLC, opSTC, opCLI, opSTI, opCLD, opSTD, opINCDEC_b_a32, opFF_l_a32, +/*f0*/ opLOCK, opINT1, opREPNE, opREPE, opHLT, opCMC, opF6_a32, opF7_l_a32, opCLC, opSTC, opCLI, opSTI, opCLD, opSTD, opINCDEC_b_a32, opFF_l_a32, }; diff --git a/src/808x.c b/src/CPU/808x.c similarity index 86% rename from src/808x.c rename to src/CPU/808x.c index 36a4e1467..faa951409 100644 --- a/src/808x.c +++ b/src/CPU/808x.c @@ -1,8 +1,21 @@ -/* Copyright holders: Sarah Walker, Tenshi - see COPYING for more details -*/ -//1B64 - Vid_SetMode (Vid_Vesa.c) -//6689c - CONS_Printf +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * 808x CPU emulation. + * + * Version: @(#)808x.c 1.0.0 2017/05/30 + * + * Author: Sarah Walker, + * Miran Grca, + * Copyright 2008-2017 Sarah Walker. + * Copyright 2016-2017 Miran Grca. + */ + /*SHR AX,1 4 clocks - fetch opcode @@ -13,18 +26,20 @@ 2 clocks - fetch opcode 1 2 clocks - execute 2 clocks - fetch opcode 2 etc*/ #include -#include "ibm.h" - +#include +#include "../ibm.h" #include "cpu.h" -#include "keyboard.h" -#include "mem.h" -#include "nmi.h" -#include "pic.h" -#include "timer.h" #include "x86.h" +#include "../keyboard.h" +#include "../mem.h" +#include "../nmi.h" +#include "../pic.h" +#include "../scsi.h" +#include "../timer.h" int xt_cpu_multi; int nmi = 0; +int nmi_auto_clear = 0; int nextcyc=0; int cycdiff; @@ -47,12 +62,14 @@ void writememll(uint32_t seg, uint32_t addr, uint32_t val); uint8_t readmemb(uint32_t a) { if (a!=(cs+cpu_state.pc)) memcycs+=4; + if (readlookup2 == NULL) return readmembl(a); if (readlookup2[(a)>>12]==-1) return readmembl(a); else return *(uint8_t *)(readlookup2[(a) >> 12] + (a)); } uint8_t readmembf(uint32_t a) { + if (readlookup2 == NULL) return readmembl(a); if (readlookup2[(a)>>12]==-1) return readmembl(a); else return *(uint8_t *)(readlookup2[(a) >> 12] + (a)); } @@ -60,6 +77,7 @@ uint8_t readmembf(uint32_t a) uint16_t readmemw(uint32_t s, uint16_t a) { if (a!=(cs+cpu_state.pc)) memcycs+=(8>>is8086); + if (readlookup2 == NULL) return readmemwl(s,a); if ((readlookup2[((s)+(a))>>12]==-1 || (s)==0xFFFFFFFF)) return readmemwl(s,a); else return *(uint16_t *)(readlookup2[(s + a) >> 12] + s + a); } @@ -77,6 +95,7 @@ void writemembl(uint32_t addr, uint8_t val); void writememb(uint32_t a, uint8_t v) { memcycs+=4; + if (writelookup2 == NULL) writemembl(a,v); if (writelookup2[(a)>>12]==-1) writemembl(a,v); else *(uint8_t *)(writelookup2[a >> 12] + a) = v; } @@ -84,18 +103,20 @@ void writememwl(uint32_t seg, uint32_t addr, uint16_t val); void writememw(uint32_t s, uint32_t a, uint16_t v) { memcycs+=(8>>is8086); + if (writelookup2 == NULL) writememwl(s,a,v); if (writelookup2[((s)+(a))>>12]==-1 || (s)==0xFFFFFFFF) writememwl(s,a,v); else *(uint16_t *)(writelookup2[(s + a) >> 12] + s + a) = v; } void writememll(uint32_t seg, uint32_t addr, uint32_t val); void writememl(uint32_t s, uint32_t a, uint32_t v) { + if (writelookup2 == NULL) writememll(s,a,v); if (writelookup2[((s)+(a))>>12]==-1 || (s)==0xFFFFFFFF) writememll(s,a,v); else *(uint32_t *)(writelookup2[(s + a) >> 12] + s + a) = v; } -void dumpregs(); +void dumpregs(int); uint16_t oldcs; int oldcpl; @@ -109,14 +130,13 @@ int output=0; int shadowbios=0; int ins=0; -//#define readmemb(a) (((a)<0xA0000)?ram[a]:readmembl(a)) int fetchcycles=0,memcycs,fetchclocks; uint8_t prefetchqueue[6]; uint16_t prefetchpc; int prefetchw=0; -inline uint8_t FETCH() +static __inline uint8_t FETCH() { uint8_t temp; /* temp=prefetchqueue[0]; @@ -134,20 +154,16 @@ inline uint8_t FETCH() } }*/ -// uint8_t temp=readmemb(cs+pc); -// if (output) printf("FETCH %04X %i\n",pc,fetchcycles); - if (prefetchw==0) //(fetchcycles<4) + if (prefetchw==0) { cycles-=(4-(fetchcycles&3)); fetchclocks+=(4-(fetchcycles&3)); fetchcycles=4; temp=readmembf(cs+cpu_state.pc); prefetchpc = cpu_state.pc = cpu_state.pc + 1; -// if (output) printf(" FETCH %04X:%04X %02X %04X %04X %i\n",CS,pc-1,temp,pc,prefetchpc,prefetchw); if (is8086 && (cpu_state.pc&1)) { prefetchqueue[0]=readmembf(cs+cpu_state.pc); -// if (output) printf(" PREFETCHED from %04X:%04X %02X 8086\n",CS,prefetchpc,prefetchqueue[prefetchw]); prefetchpc++; prefetchw++; } @@ -161,19 +177,15 @@ inline uint8_t FETCH() prefetchqueue[3]=prefetchqueue[4]; prefetchqueue[4]=prefetchqueue[5]; prefetchw--; -// if (output) printf("PREFETCH %04X:%04X %02X %04X %04X %i\n",CS,pc,temp,pc,prefetchpc,prefetchw); fetchcycles-=4; -// fetchclocks+=4; cpu_state.pc++; } -// if (output) printf("%i\n",fetchcycles); return temp; } -inline void FETCHADD(int c) +static __inline void FETCHADD(int c) { int d; -// if (output) printf("FETCHADD %i\n",c); if (c<0) return; if (prefetchw>((is8086)?4:3)) return; d=c+(fetchcycles&3); @@ -183,26 +195,22 @@ inline void FETCHADD(int c) if (is8086 && !(prefetchpc&1)) { prefetchqueue[prefetchw]=readmembf(cs+prefetchpc); -// printf("PREFETCHED from %04X:%04X %02X 8086\n",CS,prefetchpc,prefetchqueue[prefetchw]); prefetchpc++; prefetchw++; } if (prefetchw<6) { prefetchqueue[prefetchw]=readmembf(cs+prefetchpc); -// printf("PREFETCHED from %04X:%04X %02X\n",CS,prefetchpc,prefetchqueue[prefetchw]); prefetchpc++; prefetchw++; } } fetchcycles+=c; if (fetchcycles>16) fetchcycles=16; -// if (fetchcycles>24) fetchcycles=24; } void FETCHCOMPLETE() { -// pclog("Fetchcomplete %i %i %i\n",fetchcycles&3,fetchcycles,prefetchw); if (!(fetchcycles&3)) return; if (prefetchw>((is8086)?4:3)) return; if (!prefetchw) nextcyc=(4-(fetchcycles&3)); @@ -211,47 +219,24 @@ void FETCHCOMPLETE() if (is8086 && !(prefetchpc&1)) { prefetchqueue[prefetchw]=readmembf(cs+prefetchpc); -// printf("PREFETCHEDc from %04X:%04X %02X 8086\n",CS,prefetchpc,prefetchqueue[prefetchw]); prefetchpc++; prefetchw++; } if (prefetchw<6) { prefetchqueue[prefetchw]=readmembf(cs+prefetchpc); -// printf("PREFETCHEDc from %04X:%04X %02X\n",CS,prefetchpc,prefetchqueue[prefetchw]); prefetchpc++; prefetchw++; } fetchcycles+=(4-(fetchcycles&3)); } -inline void FETCHCLEAR() +static __inline void FETCHCLEAR() { -/* int c; - fetchcycles=0; - prefetchpc=pc; - if (is8086 && (prefetchpc&1)) cycles-=4; - for (c=0;c<((is8086)?6:4);c++) - { - prefetchqueue[c]=readmembf(cs+prefetchpc); - if (!is8086 || !(prefetchpc&1)) cycles-=4; - prefetchpc++; - } - prefetchw=(is8086)?6:4;*/ -// fetchcycles=0; prefetchpc=cpu_state.pc; prefetchw=0; memcycs=cycdiff-cycles; fetchclocks=0; -// memcycs=cycles; -/* prefetchqueue[0]=readmembf(cs+prefetchpc); - prefetchpc++; - prefetchw=1; - if (is8086 && prefetchpc&1) - { - prefetchqueue[1]=readmembf(cs+prefetchpc); - prefetchpc++; - }*/ } static uint16_t getword() @@ -391,30 +376,28 @@ static void fetcheal() cpu_state.last_ea = cpu_state.eaaddr; } -static inline uint8_t geteab() +static __inline uint8_t geteab() { if (cpu_mod == 3) return (cpu_rm & 4) ? cpu_state.regs[cpu_rm & 3].b.h : cpu_state.regs[cpu_rm & 3].b.l; return readmemb(easeg+cpu_state.eaaddr); } -static inline uint16_t geteaw() +static __inline uint16_t geteaw() { if (cpu_mod == 3) return cpu_state.regs[cpu_rm].w; -// if (output==3) printf("GETEAW %04X:%08X\n",easeg,eaaddr); return readmemw(easeg,cpu_state.eaaddr); } -static inline uint16_t geteaw2() +static __inline uint16_t geteaw2() { if (cpu_mod == 3) return cpu_state.regs[cpu_rm].w; -// printf("Getting addr from %04X:%04X %05X\n",easeg,eaaddr+2,easeg+eaaddr+2); return readmemw(easeg,(cpu_state.eaaddr+2)&0xFFFF); } -static inline void seteab(uint8_t val) +static __inline void seteab(uint8_t val) { if (cpu_mod == 3) { @@ -429,19 +412,20 @@ static inline void seteab(uint8_t val) } } -static inline void seteaw(uint16_t val) +static __inline void seteaw(uint16_t val) { if (cpu_mod == 3) cpu_state.regs[cpu_rm].w = val; else { writememw(easeg,cpu_state.eaaddr,val); -// writememb(easeg+eaaddr+1,val>>8); } } +#undef getr8 #define getr8(r) ((r & 4) ? cpu_state.regs[r & 3].b.h : cpu_state.regs[r & 3].b.l) +#undef setr8 #define setr8(r,v) if (r & 4) cpu_state.regs[r & 3].b.h = v; \ else cpu_state.regs[r & 3].b.l = v; @@ -465,10 +449,14 @@ void makeznptable() if (c&64) d++; if (c&128) d++; if (d&1) + { znptable8[c]=0; + } else + { znptable8[c]=P_FLAG; - if (c == 0xb1) pclog("znp8 b1 = %i %02X\n", d, znptable8[c]); + } + if (c == 0xb1) pclog("znp8 b1 = %i %02X\n", d, znptable8[c]); if (!c) znptable8[c]|=Z_FLAG; if (c&0x80) znptable8[c]|=N_FLAG; } @@ -491,9 +479,7 @@ void makeznptable() if (c == 0x65b1) pclog("znp16 65b1 = %i %02X\n", d, znptable16[c]); if (!c) znptable16[c]|=Z_FLAG; if (c&0x8000) znptable16[c]|=N_FLAG; - } - -// makemod1table(); + } } int timetolive=0; @@ -502,46 +488,28 @@ extern uint32_t oldpc2; int indump = 0; -void dumpregs() +void dumpregs(int force) { int c,d=0,e=0; #ifndef RELEASE_BUILD FILE *f; - if (indump) return; +#endif + + /* Only dump when needed, and only once.. */ + if (indump || (!force && !dump_on_exit)) return; + +#ifndef RELEASE_BUILD indump = 1; -// return; output=0; -// return; -// savenvr(); -// return; -chdir(pcempath); + _wchdir(pcempath); nopageerrors=1; -/* f=fopen("rram3.dmp","wb"); - for (c=0;c<0x8000000;c++) putc(readmemb(c+0x10000000),f); - fclose(f);*/ f=fopen("ram.dmp","wb"); fwrite(ram,mem_size*1024,1,f); fclose(f); -/* pclog("Dumping rram5.dmp\n"); - f=fopen("rram5.dmp","wb"); - for (c=0;c<0x1000000;c++) putc(readmemb(c+0x10150000),f); - fclose(f);*/ pclog("Dumping rram.dmp\n"); f=fopen("rram.dmp","wb"); for (c=0;c<0x1000000;c++) putc(readmemb(c),f); fclose(f); -/* f=fopen("rram2.dmp","wb"); - for (c=0;c<0x100000;c++) putc(readmemb(c+0xbff00000),f); - fclose(f); - f = fopen("stack.dmp","wb"); - for (c = 0; c < 0x6000; c++) putc(readmemb(c+0xFFDFA000), f); - fclose(f); - f = fopen("tempx.dmp","wb"); - for (c = 0; c < 0x10000; c++) putc(readmemb(c+0xFC816000), f); - fclose(f); - f = fopen("tempx2.dmp","wb"); - for (c = 0; c < 0x10000; c++) putc(readmemb(c+0xFDEF5000), f); - fclose(f);*/ pclog("Dumping rram4.dmp\n"); f=fopen("rram4.dmp","wb"); for (c=0;c<0x0050000;c++) @@ -551,36 +519,6 @@ chdir(pcempath); } fclose(f); pclog("Dumping done\n"); -/* f=fopen("rram6.dmp","wb"); - for (c=0;c<0x1000000;c++) putc(readmemb(c+0xBF000000),f); - fclose(f);*/ -/* f=fopen("ram6.bin","wb"); - fwrite(ram+0x10100,0xA000,1,f); - fclose(f); - f=fopen("boot.bin","wb"); - fwrite(ram+0x7C00,0x200,1,f); - fclose(f); - f=fopen("ram7.bin","wb"); - fwrite(ram+0x11100,0x2000,1,f); - fclose(f); - f=fopen("ram8.bin","wb"); - fwrite(ram+0x3D210,0x200,1,f); - fclose(f); */ -/* f=fopen("bios.dmp","wb"); - fwrite(rom,0x20000,1,f); - fclose(f);*/ -/* f=fopen("kernel.dmp","wb"); - for (c=0;c<0x200000;c++) putc(readmemb(c+0xC0000000),f); - fclose(f);*/ -/* f=fopen("rram.dmp","wb"); - for (c=0;c<0x1500000;c++) putc(readmemb(c),f); - fclose(f); - if (!times) - { - f=fopen("thing.dmp","wb"); - fwrite(ram+0x11E50,0x1000,1,f); - fclose(f); - }*/ #endif if (is386) printf("EAX=%08X EBX=%08X ECX=%08X EDX=%08X\nEDI=%08X ESI=%08X EBP=%08X ESP=%08X\n",EAX,EBX,ECX,EDX,EDI,ESI,EBP,ESP); @@ -630,9 +568,8 @@ void resetx86() resets++; ins = 0; use32=0; + cpu_cur_status = 0; stack32=0; -// i86_Reset(); -// cs=0xFFFF0; cpu_state.pc=0; msw=0; if (is486) @@ -645,14 +582,7 @@ void resetx86() eflags=0; cgate32=0; loadcs(0xFFFF); - if (AT) - { - rammask = mem_a20_state ? 0xffffffff : 0xffefffff; - } - else - { - rammask = 0xfffff; - } + rammask = AT ? 0xFFFFFFFF : 0xfffff; idt.base = 0; flags=2; makeznptable(); @@ -662,6 +592,7 @@ void resetx86() FETCHCLEAR(); x87_reset(); cpu_set_edx(); + EAX = 0; ESP=0; mmu_perm=4; memset(inscounts, 0, sizeof(inscounts)); @@ -669,16 +600,14 @@ void resetx86() codegen_reset(); x86_was_reset = 1; port_92_clear_reset(); + scsi_card_reset(); } void softresetx86() { -// dumpregs(); -// exit(-1); use32=0; stack32=0; -// i86_Reset(); -// cs=0xFFFF0; + cpu_cur_status = 0; cpu_state.pc=0; msw=0; cr0=0; @@ -686,12 +615,12 @@ void softresetx86() eflags=0; cgate32=0; loadcs(0xFFFF); - //rammask=0xFFFFFFFF; flags=2; idt.base = 0; x86seg_reset(); x86_was_reset = 1; port_92_clear_reset(); + scsi_card_reset(); } static void setznp8(uint8_t val) @@ -792,7 +721,6 @@ static void setsub16(uint16_t a, uint16_t b) flags|=znptable16[c&0xFFFF]; if (c&0x10000) flags|=C_FLAG; if ((a^b)&(a^c)&0x8000) flags|=V_FLAG; -// if (output) printf("%04X %04X %i\n",a^b,a^c,flags&V_FLAG); if (((a&0xF)-(b&0xF))&0x10) flags|=A_FLAG; } static void setsub16nc(uint16_t a, uint16_t b) @@ -832,18 +760,16 @@ int firstrepcycle=1; void rep(int fv) { - uint8_t temp; + uint8_t temp = 0; int c=CX; uint8_t temp2; uint16_t tempw,tempw2; - uint16_t ipc=cpu_state.oldpc;//pc-1; + uint16_t ipc=cpu_state.oldpc; int changeds=0; - uint32_t oldds; + uint32_t oldds = 0; startrep: temp=FETCH(); -// if (firstrepcycle && temp==0xA5) printf("REP MOVSW %06X:%04X %06X:%04X\n",ds,SI,es,DI); -// if (output) printf("REP %02X %04X\n",temp,ipc); switch (temp) { case 0x08: @@ -890,7 +816,6 @@ void rep(int fv) { temp2=readmemb(ds+SI); writememb(es+DI,temp2); -// if (output) printf("Moved %02X from %04X:%04X to %04X:%04X\n",temp2,ds>>4,SI,es>>4,DI); if (flags&D_FLAG) { DI--; SI--; } else { DI++; SI++; } c--; @@ -899,9 +824,6 @@ void rep(int fv) FETCHADD(17-memcycs); } if (IRQTEST && c>0) cpu_state.pc=ipc; -// if (c>0) { firstrepcycle=0; pc=ipc; if (cpu_state.ssegs) cpu_state.ssegs++; FETCHCLEAR(); } -// else firstrepcycle=1; -// } break; case 0xA5: /*REP MOVSW*/ while (c>0 && !IRQTEST) @@ -917,9 +839,6 @@ void rep(int fv) FETCHADD(17 - memcycs); } if (IRQTEST && c>0) cpu_state.pc=ipc; -// if (c>0) { firstrepcycle=0; pc=ipc; if (cpu_state.ssegs) cpu_state.ssegs++; FETCHCLEAR(); } -// else firstrepcycle=1; -// } break; case 0xA6: /*REP CMPSB*/ if (fv) flags|=Z_FLAG; @@ -929,7 +848,6 @@ void rep(int fv) memcycs=0; temp=readmemb(ds+SI); temp2=readmemb(es+DI); -// printf("CMPSB %c %c %i %05X %05X %04X:%04X\n",temp,temp2,c,ds+SI,es+DI,cs>>4,pc); if (flags&D_FLAG) { DI--; SI--; } else { DI++; SI++; } c--; @@ -939,8 +857,6 @@ void rep(int fv) FETCHADD(30 - memcycs); } if (IRQTEST && c>0 && (fv==((flags&Z_FLAG)?1:0))) cpu_state.pc=ipc; -// if ((c>0) && (fv==((flags&Z_FLAG)?1:0))) { pc=ipc; firstrepcycle=0; if (cpu_state.ssegs) cpu_state.ssegs++; FETCHCLEAR(); } -// else firstrepcycle=1; break; case 0xA7: /*REP CMPSW*/ if (fv) flags|=Z_FLAG; @@ -959,9 +875,6 @@ void rep(int fv) FETCHADD(30 - memcycs); } if (IRQTEST && c>0 && (fv==((flags&Z_FLAG)?1:0))) cpu_state.pc=ipc; -// if ((c>0) && (fv==((flags&Z_FLAG)?1:0))) { pc=ipc; firstrepcycle=0; if (cpu_state.ssegs) cpu_state.ssegs++; FETCHCLEAR(); } -// else firstrepcycle=1; -// if (firstrepcycle) printf("REP CMPSW %06X:%04X %06X:%04X %04X %04X\n",ds,SI,es,DI,tempw,tempw2); break; case 0xAA: /*REP STOSB*/ while (c>0 && !IRQTEST) @@ -976,8 +889,6 @@ void rep(int fv) FETCHADD(10 - memcycs); } if (IRQTEST && c>0) cpu_state.pc=ipc; -// if (c>0) { firstrepcycle=0; pc=ipc; if (ssegs) ssegs++; FETCHCLEAR(); } -// else firstrepcycle=1; break; case 0xAB: /*REP STOSW*/ while (c>0 && !IRQTEST) @@ -992,8 +903,6 @@ void rep(int fv) FETCHADD(10 - memcycs); } if (IRQTEST && c>0) cpu_state.pc=ipc; -// if (c>0) { firstrepcycle=0; pc=ipc; if (ssegs) ssegs++; FETCHCLEAR(); } -// else firstrepcycle=1; break; case 0xAC: /*REP LODSB*/ if (c>0) @@ -1025,18 +934,14 @@ void rep(int fv) if ((c>0) && (fv==((flags&Z_FLAG)?1:0))) { temp2=readmemb(es+DI); -// if (output) printf("SCASB %02X %c %02X %05X ",temp2,temp2,AL,es+DI); setsub8(AL,temp2); -// if (output && flags&Z_FLAG) printf("Match %02X %02X\n",AL,temp2); if (flags&D_FLAG) DI--; else DI++; c--; cycles -= 15; } -//if (output) printf("%i %i %i %i\n",c,(c>0),(fv==((flags&Z_FLAG)?1:0)),((c>0) && (fv==((flags&Z_FLAG)?1:0)))); if ((c>0) && (fv==((flags&Z_FLAG)?1:0))) { cpu_state.pc=ipc; firstrepcycle=0; if (cpu_state.ssegs) cpu_state.ssegs++; FETCHCLEAR(); } else firstrepcycle=1; -// cycles-=120; break; case 0xAF: /*REP SCASW*/ if (fv) flags|=Z_FLAG; @@ -1057,15 +962,11 @@ void rep(int fv) cpu_state.pc = ipc+1; cycles-=20; FETCHCLEAR(); -// printf("Bad REP %02X\n",temp); -// dumpregs(); -// exit(-1); } CX=c; if (changeds) ds=oldds; if (IRQTEST) takeint = 1; -// if (pc==ipc) FETCHCLEAR(); } @@ -1075,10 +976,9 @@ int firstrepcycle; int skipnextprint=0; int instime=0; -//#if 0 void execx86(int cycs) { - uint8_t temp,temp2; + uint8_t temp = 0,temp2; uint16_t addr,tempw,tempw2,tempw3,tempw4; int8_t offset; int tempws; @@ -1087,24 +987,14 @@ void execx86(int cycs) int tempi; int trap; -// printf("Run x86! %i %i\n",cycles,cycs); cycles+=cycs; -// i86_Execute(cycs); -// return; while (cycles>0) { -// old83=old82; -// old82=old8; -// old8=oldpc|(oldcs<<16); -// if (pc==0x96B && cs==0x9E040) { printf("Hit it\n"); output=1; timetolive=150; } -// if (pc<0x8000) printf("%04X : %04X %04X %04X %04X %04X %04X %04X %04X %04X %04X %04X %04X %02X %04X %i\n",pc,AX,BX,CX,DX,cs>>4,ds>>4,es>>4,ss>>4,DI,SI,BP,SP,opcode,flags,disctime); cycdiff=cycles; timer_start_period(cycles*xt_cpu_multi); current_diff = 0; cycles-=nextcyc; -// if (instime) pclog("Cycles %i %i\n",cycles,cycdiff); nextcyc=0; -// if (output) printf("CLOCK %i %i\n",cycdiff,cycles); fetchclocks=0; oldcs=CS; cpu_state.oldpc=cpu_state.pc; @@ -1113,33 +1003,17 @@ void execx86(int cycs) tempc=flags&C_FLAG; trap=flags&T_FLAG; cpu_state.pc--; -// output=1; -// if (output) printf("%04X:%04X : %04X %04X %04X %04X %04X %04X %04X %04X %04X %04X %04X %04X %02X %04X\n",cs>>4,pc,AX,BX,CX,DX,cs>>4,ds>>4,es>>4,ss>>4,DI,SI,BP,SP,opcode,flags&~0x200,rmdat); -//#if 0 if (output) { -// if ((opcode!=0xF2 && opcode!=0xF3) || firstrepcycle) -// { if (!skipnextprint) printf("%04X:%04X : %04X %04X %04X %04X %04X %04X %04X %04X %04X %04X %04X %04X %02X %04X %i %p %02X\n",cs,cpu_state.pc,AX,BX,CX,DX,CS,DS,ES,SS,DI,SI,BP,SP,opcode,flags, ins, ram, ram[0x1a925]); skipnextprint=0; -// ins++; -// } } -//#endif cpu_state.pc++; inhlt=0; -// if (ins==500000) { dumpregs(); exit(0); }*/ switch (opcode) { case 0x00: /*ADD 8,reg*/ fetchea(); -/* if (!rmdat) pc--; - if (!rmdat) - { - fatal("Crashed\n"); -// clear_keybuf(); -// readkey(); - }*/ temp=geteab(); setadd8(temp,getr8(cpu_reg)); temp+=getr8(cpu_reg); @@ -1322,7 +1196,6 @@ void execx86(int cycs) cpu_state.last_ea = SP; noint=1; cycles-=12; -// output=1; break; case 0x18: /*SBB 8,reg*/ @@ -1338,7 +1211,6 @@ void execx86(int cycs) fetchea(); tempw=geteaw(); tempw2=cpu_state.regs[cpu_reg].w; -// printf("%04X:%04X SBB %04X-%04X,%i\n",cs>>4,pc,tempw,tempw2,tempc); setsbc16(tempw,tempw2); tempw-=(tempw2+tempc); seteaw(tempw); @@ -1355,7 +1227,6 @@ void execx86(int cycs) fetchea(); tempw=geteaw(); tempw2=cpu_state.regs[cpu_reg].w; -// printf("%04X:%04X SBB %04X-%04X,%i\n",cs>>4,pc,tempw,tempw2,tempc); setsbc16(tempw2,tempw); tempw2-=(tempw+tempc); cpu_state.regs[cpu_reg].w=tempw2; @@ -1447,7 +1318,6 @@ void execx86(int cycs) cpu_state.ssegs=2; cycles-=4; goto opcodestart; -// break; case 0x27: /*DAA*/ if ((flags&A_FLAG) || ((AL&0xF)>9)) @@ -1457,15 +1327,11 @@ void execx86(int cycs) flags|=A_FLAG; if (tempi&0x100) flags|=C_FLAG; } -// else -// flags&=~A_FLAG; if ((flags&C_FLAG) || (AL>0x9F)) { AL+=0x60; flags|=C_FLAG; } -// else -// flags&=~C_FLAG; setznp8(AL); cycles-=4; break; @@ -1481,7 +1347,6 @@ void execx86(int cycs) case 0x29: /*SUB 16,reg*/ fetchea(); tempw=geteaw(); -// printf("%04X:%04X %04X-%04X\n",cs>>4,pc,tempw,cpu_state.regs[cpu_reg].w); setsub16(tempw,cpu_state.regs[cpu_reg].w); tempw-=cpu_state.regs[cpu_reg].w; seteaw(tempw); @@ -1497,7 +1362,6 @@ void execx86(int cycs) case 0x2B: /*SUB cpu_reg,16*/ fetchea(); tempw=geteaw(); -// printf("%04X:%04X %04X-%04X\n",cs>>4,pc,cpu_state.regs[cpu_reg].w,tempw); setsub16(cpu_state.regs[cpu_reg].w,tempw); cpu_state.regs[cpu_reg].w-=tempw; cycles-=((cpu_mod==3)?3:13); @@ -1509,8 +1373,6 @@ void execx86(int cycs) cycles-=4; break; case 0x2D: /*SUB AX,#16*/ -// printf("INS %i\n",ins); -// output=1; tempw=getword(); setsub16(AX,tempw); AX-=tempw; @@ -1531,15 +1393,11 @@ void execx86(int cycs) flags|=A_FLAG; if (tempi&0x100) flags|=C_FLAG; } -// else -// flags&=~A_FLAG; if ((flags&C_FLAG)||(AL>0x9F)) { AL-=0x60; flags|=C_FLAG; } -// else -// flags&=~C_FLAG; setznp8(AL); cycles-=4; break; @@ -1599,7 +1457,6 @@ void execx86(int cycs) cpu_state.ssegs=2; cycles-=4; goto opcodestart; -// break; case 0x37: /*AAA*/ if ((flags&A_FLAG)||((AL&0xF)>9)) @@ -1617,28 +1474,24 @@ void execx86(int cycs) case 0x38: /*CMP 8,reg*/ fetchea(); temp=geteab(); -// if (output) printf("CMP %02X-%02X\n",temp,getr8(cpu_reg)); setsub8(temp,getr8(cpu_reg)); cycles-=((cpu_mod==3)?3:13); break; case 0x39: /*CMP 16,reg*/ fetchea(); tempw=geteaw(); -// if (output) printf("CMP %04X-%04X\n",tempw,cpu_state.regs[cpu_reg].w); setsub16(tempw,cpu_state.regs[cpu_reg].w); cycles-=((cpu_mod==3)?3:13); break; case 0x3A: /*CMP cpu_reg,8*/ fetchea(); temp=geteab(); -// if (output) printf("CMP %02X-%02X\n",getr8(cpu_reg),temp); setsub8(getr8(cpu_reg),temp); cycles-=((cpu_mod==3)?3:13); break; case 0x3B: /*CMP cpu_reg,16*/ fetchea(); tempw=geteaw(); -// printf("CMP %04X-%04X\n",cpu_state.regs[cpu_reg].w,tempw); setsub16(cpu_state.regs[cpu_reg].w,tempw); cycles-=((cpu_mod==3)?3:13); break; @@ -1660,7 +1513,6 @@ void execx86(int cycs) cpu_state.ssegs=2; cycles-=4; goto opcodestart; -// break; case 0x3F: /*AAS*/ if ((flags&A_FLAG)||((AL&0xF)>9)) @@ -1830,13 +1682,11 @@ void execx86(int cycs) cycles-=((cpu_mod==3)?4:23); break; case 0x10: /*ADC b,#8*/ -// temp2+=(flags&C_FLAG); setadc8(temp,temp2); seteab(temp+temp2+tempc); cycles-=((cpu_mod==3)?4:23); break; case 0x18: /*SBB b,#8*/ -// temp2+=(flags&C_FLAG); setsbc8(temp,temp2); seteab(temp-(temp2+tempc)); cycles-=((cpu_mod==3)?4:23); @@ -1864,11 +1714,6 @@ void execx86(int cycs) setsub8(temp,temp2); cycles-=((cpu_mod==3)?4:14); break; - -// default: -// printf("Bad 80 opcode %02X\n",rmdat&0x38); -// dumpregs(); -// exit(-1); } break; @@ -1892,7 +1737,6 @@ void execx86(int cycs) cycles-=((cpu_mod==3)?4:23); break; case 0x10: /*ADC w,#16*/ -// tempw2+=(flags&C_FLAG); setadc16(tempw,tempw2); tempw+=tempw2+tempc; seteaw(tempw); @@ -1906,7 +1750,6 @@ void execx86(int cycs) cycles-=((cpu_mod==3)?4:23); break; case 0x18: /*SBB w,#16*/ -// tempw2+=(flags&C_FLAG); setsbc16(tempw,tempw2); seteaw(tempw-(tempw2+tempc)); cycles-=((cpu_mod==3)?4:23); @@ -1925,15 +1768,9 @@ void execx86(int cycs) cycles-=((cpu_mod==3)?4:23); break; case 0x38: /*CMP w,#16*/ -// printf("CMP %04X %04X\n",tempw,tempw2); setsub16(tempw,tempw2); cycles-=((cpu_mod==3)?4:14); break; - -// default: -// printf("Bad 81 opcode %02X\n",rmdat&0x38); -// dumpregs(); -// exit(-1); } break; @@ -1958,14 +1795,12 @@ void execx86(int cycs) cycles-=((cpu_mod==3)?4:23); break; case 0x10: /*ADC w,#8*/ -// tempw2+=(flags&C_FLAG); setadc16(tempw,tempw2); tempw+=tempw2+tempc; seteaw(tempw); cycles-=((cpu_mod==3)?4:23); break; case 0x18: /*SBB w,#8*/ -// tempw2+=(flags&C_FLAG); setsbc16(tempw,tempw2); tempw-=(tempw2+tempc); seteaw(tempw); @@ -1995,11 +1830,6 @@ void execx86(int cycs) setsub16(tempw,tempw2); cycles-=((cpu_mod==3)?4:14); break; - -// default: -// printf("Bad 83 opcode %02X\n",rmdat&0x38); -// dumpregs(); -// exit(-1); } break; @@ -2086,9 +1916,7 @@ void execx86(int cycs) break; case 0x8E: /*MOV sreg,w*/ -// if (output) printf("MOV %04X ",pc); fetchea(); -// if (output) printf("%04X %02X\n",pc,rmdat); switch (rmdat&0x38) { case 0x00: /*ES*/ @@ -2108,8 +1936,6 @@ void execx86(int cycs) tempw=geteaw(); loadseg(tempw,&_ss); if (cpu_state.ssegs) oldss=ss; -// printf("LOAD SS %04X %04X\n",tempw,SS); -// printf("SS loaded with %04X %04X:%04X %04X %04X %04X\n",ss>>4,cs>>4,pc,CX,DX,es>>4); break; } cycles-=((cpu_mod==3)?2:12); @@ -2154,7 +1980,6 @@ void execx86(int cycs) tempw4=cpu_state.pc; if (cpu_state.ssegs) ss=oldss; cpu_state.pc=tempw; -// printf("0x9a"); loadcs(tempw2); writememw(ss,(SP-2)&0xFFFF,tempw3); writememw(ss,(SP-4)&0xFFFF,tempw4); @@ -2196,9 +2021,8 @@ void execx86(int cycs) break; case 0xA1: /*MOV AX,(w)*/ addr=getword(); -// printf("Reading AX from %05X %04X:%04X\n",ds+addr,ds>>4,addr); AX=readmemw(ds,addr); - cycles-=!4; + cycles-=14; break; case 0xA2: /*MOV (w),AL*/ addr=getword(); @@ -2207,7 +2031,6 @@ void execx86(int cycs) break; case 0xA3: /*MOV (w),AX*/ addr=getword(); -// if (!addr) printf("Write !addr %04X:%04X\n",cs>>4,pc); writememw(ds,addr,AX); cycles-=14; break; @@ -2237,7 +2060,6 @@ void execx86(int cycs) case 0xA7: /*CMPSW*/ tempw =readmemw(ds,SI); tempw2=readmemw(es,DI); -// printf("CMPSW %04X %04X\n",tempw,tempw2); setsub16(tempw,tempw2); if (flags&D_FLAG) { DI-=2; SI-=2; } else { DI+=2; SI+=2; } @@ -2269,13 +2091,11 @@ void execx86(int cycs) break; case 0xAC: /*LODSB*/ AL=readmemb(ds+SI); -// printf("LODSB %04X:%04X %02X %04X:%04X\n",cs>>4,pc,AL,ds>>4,SI); if (flags&D_FLAG) SI--; else SI++; cycles-=16; break; case 0xAD: /*LODSW*/ -// if (times) printf("LODSW %04X:%04X\n",cs>>4,pc); AX=readmemw(ds,SI); if (flags&D_FLAG) SI-=2; else SI+=2; @@ -2339,8 +2159,6 @@ void execx86(int cycs) tempw=getword(); if (cpu_state.ssegs) ss=oldss; cpu_state.pc=readmemw(ss,SP); -// printf("C2\n"); -// printf("RET to %04X\n",pc); SP+=2+tempw; cycles-=24; FETCHCLEAR(); @@ -2349,16 +2167,14 @@ void execx86(int cycs) case 0xC3: /*RET*/ if (cpu_state.ssegs) ss=oldss; cpu_state.pc=readmemw(ss,SP); -// printf("C3\n"); -// if (output) printf("RET to %04X %05X\n",pc,ss+SP); SP+=2; cycles-=20; FETCHCLEAR(); break; case 0xC4: /*LES*/ fetchea(); - cpu_state.regs[cpu_reg].w=readmemw(easeg,cpu_state.eaaddr); //geteaw(); - tempw=readmemw(easeg,(cpu_state.eaaddr+2)&0xFFFF); //geteaw2(); + cpu_state.regs[cpu_reg].w=readmemw(easeg,cpu_state.eaaddr); + tempw=readmemw(easeg,(cpu_state.eaaddr+2)&0xFFFF); loadseg(tempw,&_es); cycles-=24; break; @@ -2388,7 +2204,6 @@ void execx86(int cycs) tempw=getword(); if (cpu_state.ssegs) ss=oldss; cpu_state.pc=readmemw(ss,SP); -// printf("CA\n"); loadcs(readmemw(ss,SP+2)); SP+=4; SP+=tempw; @@ -2399,7 +2214,6 @@ void execx86(int cycs) case 0xCB: /*RETF*/ if (cpu_state.ssegs) ss=oldss; cpu_state.pc=readmemw(ss,SP); -// printf("CB\n"); loadcs(readmemw(ss,SP+2)); SP+=4; cycles-=34; @@ -2414,11 +2228,9 @@ void execx86(int cycs) addr=3<<2; flags&=~I_FLAG; flags&=~T_FLAG; -// printf("CC %04X:%04X ",CS,pc); cpu_state.pc=readmemw(0,addr); loadcs(readmemw(0,addr+2)); FETCHCLEAR(); -// printf("%04X:%04X\n",CS,pc); cycles-=72; break; case 0xCD: /*INT*/ @@ -2445,7 +2257,6 @@ void execx86(int cycs) tempw=CS; tempw2=cpu_state.pc; cpu_state.pc=readmemw(ss,SP); -// printf("CF\n"); loadcs(readmemw(ss,((SP+2)&0xFFFF))); flags=readmemw(ss,((SP+4)&0xFFFF))&0xFFF; SP+=6; @@ -2464,7 +2275,6 @@ void execx86(int cycs) temp<<=1; if (flags&C_FLAG) temp|=1; seteab(temp); -// setznp8(temp); if ((flags&C_FLAG)^(temp>>7)) flags|=V_FLAG; else flags&=~V_FLAG; cycles-=((cpu_mod==3)?2:23); @@ -2475,7 +2285,6 @@ void execx86(int cycs) temp>>=1; if (flags&C_FLAG) temp|=0x80; seteab(temp); -// setznp8(temp); if ((temp^(temp>>1))&0x40) flags|=V_FLAG; else flags&=~V_FLAG; cycles-=((cpu_mod==3)?2:23); @@ -2487,7 +2296,6 @@ void execx86(int cycs) temp<<=1; if (temp2) temp|=1; seteab(temp); -// setznp8(temp); if ((flags&C_FLAG)^(temp>>7)) flags|=V_FLAG; else flags&=~V_FLAG; cycles-=((cpu_mod==3)?2:23); @@ -2499,7 +2307,6 @@ void execx86(int cycs) temp>>=1; if (temp2) temp|=0x80; seteab(temp); -// setznp8(temp); if ((temp^(temp>>1))&0x40) flags|=V_FLAG; else flags&=~V_FLAG; cycles-=((cpu_mod==3)?2:23); @@ -2537,11 +2344,6 @@ void execx86(int cycs) flags|=A_FLAG; flags&=~V_FLAG; break; - -// default: -// printf("Bad D0 opcode %02X\n",rmdat&0x38); -// dumpregs(); -// exit(-1); } break; @@ -2556,7 +2358,6 @@ void execx86(int cycs) tempw<<=1; if (flags&C_FLAG) tempw|=1; seteaw(tempw); -// setznp16(tempw); if ((flags&C_FLAG)^(tempw>>15)) flags|=V_FLAG; else flags&=~V_FLAG; cycles-=((cpu_mod==3)?2:23); @@ -2567,7 +2368,6 @@ void execx86(int cycs) tempw>>=1; if (flags&C_FLAG) tempw|=0x8000; seteaw(tempw); -// setznp16(tempw); if ((tempw^(tempw>>1))&0x4000) flags|=V_FLAG; else flags&=~V_FLAG; cycles-=((cpu_mod==3)?2:23); @@ -2590,7 +2390,6 @@ void execx86(int cycs) tempw>>=1; if (temp2) tempw|=0x8000; seteaw(tempw); -// setznp16(tempw); if ((tempw^(tempw>>1))&0x4000) flags|=V_FLAG; else flags&=~V_FLAG; cycles-=((cpu_mod==3)?2:23); @@ -2629,11 +2428,6 @@ void execx86(int cycs) flags|=A_FLAG; flags&=~V_FLAG; break; - -// default: -// printf("Bad D1 opcode %02X\n",rmdat&0x38); -// dumpregs(); -// exit(-1); } break; @@ -2641,9 +2435,7 @@ void execx86(int cycs) fetchea(); temp=geteab(); c=CL; -// cycles-=c; if (!c) break; -// if (c>7) printf("Shiftb %i %02X\n",rmdat&0x38,c); switch (rmdat&0x38) { case 0x00: /*ROL b,CL*/ @@ -2657,7 +2449,6 @@ void execx86(int cycs) if (temp2) flags|=C_FLAG; else flags&=~C_FLAG; seteab(temp); -// setznp8(temp); if ((flags&C_FLAG)^(temp>>7)) flags|=V_FLAG; else flags&=~V_FLAG; cycles-=((cpu_mod==3)?8:28); @@ -2679,7 +2470,6 @@ void execx86(int cycs) cycles-=((cpu_mod==3)?8:28); break; case 0x10: /*RCL b,CL*/ -// printf("RCL %i %02X %02X\n",c,CL,temp); while (c>0) { templ=flags&C_FLAG; @@ -2691,7 +2481,6 @@ void execx86(int cycs) c--; cycles-=4; } -// printf("Now %02X\n",temp); seteab(temp); if ((flags&C_FLAG)^(temp>>7)) flags|=V_FLAG; else flags&=~V_FLAG; @@ -2709,8 +2498,6 @@ void execx86(int cycs) c--; cycles-=4; } -// if (temp2) flags|=C_FLAG; -// else flags&=~C_FLAG; seteab(temp); if ((temp^(temp>>1))&0x40) flags|=V_FLAG; else flags&=~V_FLAG; @@ -2751,11 +2538,6 @@ void execx86(int cycs) cycles-=((cpu_mod==3)?8:28); flags|=A_FLAG; break; - -// default: -// printf("Bad D2 opcode %02X\n",rmdat&0x38); -// dumpregs(); -// exit(-1); } break; @@ -2763,9 +2545,7 @@ void execx86(int cycs) fetchea(); tempw=geteaw(); c=CL; -// cycles-=c; if (!c) break; -// if (c>15) printf("Shiftw %i %02X\n",rmdat&0x38,c); switch (rmdat&0x38) { case 0x00: /*ROL w,CL*/ @@ -2879,11 +2659,6 @@ void execx86(int cycs) cycles-=((cpu_mod==3)?8:28); flags|=A_FLAG; break; - -// default: -// printf("Bad D3 opcode %02X\n",rmdat&0x38); -// dumpregs(); -// exit(-1); } break; @@ -2930,12 +2705,10 @@ void execx86(int cycs) cycles-=6; break; case 0xE2: /*LOOP*/ -// printf("LOOP start\n"); offset=(int8_t)FETCH(); CX--; if (CX) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } cycles-=5; -// printf("LOOP end!\n"); break; case 0xE3: /*JCXZ*/ offset=(int8_t)FETCH(); @@ -2969,7 +2742,6 @@ void execx86(int cycs) case 0xE8: /*CALL rel 16*/ tempw=getword(); if (cpu_state.ssegs) ss=oldss; -// writememb(ss+((SP-1)&0xFFFF),pc>>8); writememw(ss,((SP-2)&0xFFFF),cpu_state.pc); SP-=2; cpu_state.last_ea = SP; @@ -2978,10 +2750,8 @@ void execx86(int cycs) FETCHCLEAR(); break; case 0xE9: /*JMP rel 16*/ -// pclog("PC was %04X\n",cpu_state.pc); tempw = getword(); cpu_state.pc += tempw; -// pclog("PC now %04X\n",cpu_state.pc); cycles-=15; FETCHCLEAR(); break; @@ -2989,10 +2759,7 @@ void execx86(int cycs) addr=getword(); tempw=getword(); cpu_state.pc=addr; -// printf("EA\n"); loadcs(tempw); -// cs=loadcs(CS); -// cs=CS<<4; cycles-=15; FETCHCLEAR(); break; @@ -3034,13 +2801,6 @@ void execx86(int cycs) break; case 0xF4: /*HLT*/ -// printf("IN HLT!!!! %04X:%04X %08X %08X %08X\n",oldcs,oldpc,old8,old82,old83); -/* if (!(flags & I_FLAG)) - { - pclog("HLT\n"); - dumpregs(); - exit(-1); - }*/ inhlt=1; cpu_state.pc--; FETCHCLEAR(); @@ -3057,6 +2817,7 @@ void execx86(int cycs) switch (rmdat&0x38) { case 0x00: /*TEST b,#8*/ + case 0x08: temp2=FETCH(); temp&=temp2; setznp8(temp); @@ -3098,25 +2859,9 @@ void execx86(int cycs) if (temp) { tempw2=tempw%temp; -/* if (!tempw) - { - writememw((ss+SP)-2,flags|0xF000); - writememw((ss+SP)-4,cs>>4); - writememw((ss+SP)-6,pc); - SP-=6; - flags&=~I_FLAG; - pc=readmemw(0); - cs=readmemw(2)<<4; - printf("Div by zero %04X:%04X\n",cs>>4,pc); -// dumpregs(); -// exit(-1); - } - else - {*/ AH=tempw2; tempw/=temp; AL=tempw&0xFF; -// } } else { @@ -3128,14 +2873,8 @@ void execx86(int cycs) flags&=~I_FLAG; flags&=~T_FLAG; cpu_state.pc=readmemw(0,0); -// printf("F6 30\n"); loadcs(readmemw(0,2)); FETCHCLEAR(); -// cs=loadcs(CS); -// cs=CS<<4; -// printf("Div by zero %04X:%04X %02X %02X\n",cs>>4,pc,0xf6,0x30); -// dumpregs(); -// exit(-1); } cycles-=80; break; @@ -3144,23 +2883,9 @@ void execx86(int cycs) if (temp) { tempw2=tempws%(int)((int8_t)temp); -/* if (!tempw) - { - writememw((ss+SP)-2,flags|0xF000); - writememw((ss+SP)-4,cs>>4); - writememw((ss+SP)-6,pc); - SP-=6; - flags&=~I_FLAG; - pc=readmemw(0); - cs=readmemw(2)<<4; - printf("Div by zero %04X:%04X\n",cs>>4,pc); - } - else - {*/ AH=tempw2&0xFF; tempws/=(int)((int8_t)temp); AL=tempws&0xFF; -// } } else { @@ -3172,20 +2897,11 @@ void execx86(int cycs) flags&=~I_FLAG; flags&=~T_FLAG; cpu_state.pc=readmemw(0,0); -// printf("F6 38\n"); loadcs(readmemw(0,2)); FETCHCLEAR(); -// cs=loadcs(CS); -// cs=CS<<4; -// printf("Div by zero %04X:%04X %02X %02X\n",cs>>4,pc,0xf6,0x38); } cycles-=101; break; - -// default: -// printf("Bad F6 opcode %02X\n",rmdat&0x38); -// dumpregs(); -// exit(-1); } break; @@ -3195,6 +2911,7 @@ void execx86(int cycs) switch (rmdat&0x38) { case 0x00: /*TEST w*/ + case 0x08: tempw2=getword(); setznp16(tempw&tempw2); flags&=~(C_FLAG|V_FLAG|A_FLAG); @@ -3213,7 +2930,6 @@ void execx86(int cycs) case 0x20: /*MUL AX,w*/ setznp16(AX); templ=AX*tempw; -// if (output) printf("%04X*%04X=%08X\n",AX,tempw,templ); AX=templ&0xFFFF; DX=templ>>16; if (AX|DX) flags&=~Z_FLAG; @@ -3224,24 +2940,18 @@ void execx86(int cycs) break; case 0x28: /*IMUL AX,w*/ setznp16(AX); -// printf("IMUL %i %i ",(int)((int16_t)AX),(int)((int16_t)tempw)); tempws=(int)((int16_t)AX)*(int)((int16_t)tempw); if ((tempws>>15) && ((tempws>>15)!=-1)) flags|=(C_FLAG|V_FLAG); else flags&=~(C_FLAG|V_FLAG); -// printf("%i ",tempws); AX=tempws&0xFFFF; tempws=(uint16_t)(tempws>>16); DX=tempws&0xFFFF; -// printf("%04X %04X\n",AX,DX); -// dumpregs(); -// exit(-1); if (AX|DX) flags&=~Z_FLAG; else flags|=Z_FLAG; cycles-=128; break; case 0x30: /*DIV AX,w*/ templ=(DX<<16)|AX; -// printf("DIV %08X/%04X\n",templ,tempw); if (tempw) { tempw2=templ%tempw; @@ -3259,7 +2969,6 @@ void execx86(int cycs) flags&=~I_FLAG; flags&=~T_FLAG; cpu_state.pc=readmemw(0,0); -// printf("F7 30\n"); loadcs(readmemw(0,2)); FETCHCLEAR(); } @@ -3267,11 +2976,9 @@ void execx86(int cycs) break; case 0x38: /*IDIV AX,w*/ tempws=(int)((DX<<16)|AX); -// printf("IDIV %i %i ",tempws,tempw); if (tempw) { tempw2=tempws%(int)((int16_t)tempw); -// printf("%04X ",tempw2); DX=tempw2; tempws/=(int)((int16_t)tempw); AX=tempws&0xFFFF; @@ -3286,17 +2993,11 @@ void execx86(int cycs) flags&=~I_FLAG; flags&=~T_FLAG; cpu_state.pc=readmemw(0,0); -// printf("F7 38\n"); loadcs(readmemw(0,2)); FETCHCLEAR(); } cycles-=165; break; - -// default: -// printf("Bad F7 opcode %02X\n",rmdat&0x38); -// dumpregs(); -// exit(-1); } break; @@ -3305,18 +3006,15 @@ void execx86(int cycs) cycles-=2; break; case 0xF9: /*STC*/ -// printf("STC %04X\n",pc); flags|=C_FLAG; cycles-=2; break; case 0xFA: /*CLI*/ flags&=~I_FLAG; -// printf("CLI at %04X:%04X\n",cs>>4,pc); cycles-=3; break; case 0xFB: /*STI*/ flags|=I_FLAG; -// printf("STI at %04X:%04X\n",cs>>4,pc); cycles-=2; break; case 0xFC: /*CLD*/ @@ -3344,7 +3042,6 @@ void execx86(int cycs) temp2=temp+1; if ((temp2&0x80) && !(temp&0x80)) flags|=V_FLAG; } -// setznp8(temp2); seteab(temp2); cycles-=((cpu_mod==3)?3:23); break; @@ -3356,17 +3053,13 @@ void execx86(int cycs) case 0x00: /*INC w*/ tempw=geteaw(); setadd16nc(tempw,1); -// setznp16(tempw+1); seteaw(tempw+1); cycles-=((cpu_mod==3)?3:23); break; case 0x08: /*DEC w*/ tempw=geteaw(); -// setsub16(tempw,1); setsub16nc(tempw,1); -// setznp16(tempw-1); seteaw(tempw-1); -// if (output) printf("DEC - %04X\n",tempw); cycles-=((cpu_mod==3)?3:23); break; case 0x10: /*CALL*/ @@ -3376,18 +3069,16 @@ void execx86(int cycs) SP-=2; cpu_state.last_ea = SP; cpu_state.pc=tempw; -// printf("FF 10\n"); cycles-=((cpu_mod==3)?20:29); FETCHCLEAR(); break; case 0x18: /*CALL far*/ tempw=readmemw(easeg,cpu_state.eaaddr); - tempw2=readmemw(easeg,(cpu_state.eaaddr+2)&0xFFFF); //geteaw2(); + tempw2=readmemw(easeg,(cpu_state.eaaddr+2)&0xFFFF); tempw3=CS; tempw4=cpu_state.pc; if (cpu_state.ssegs) ss=oldss; cpu_state.pc=tempw; -// printf("FF 18\n"); loadcs(tempw2); writememw(ss,(SP-2)&0xFFFF,tempw3); writememw(ss,((SP-4)&0xFFFF),tempw4); @@ -3398,34 +3089,24 @@ void execx86(int cycs) break; case 0x20: /*JMP*/ cpu_state.pc=geteaw(); -// printf("FF 20\n"); cycles-=((cpu_mod==3)?11:18); FETCHCLEAR(); break; case 0x28: /*JMP far*/ - cpu_state.pc=readmemw(easeg,cpu_state.eaaddr); //geteaw(); -// printf("FF 28\n"); - loadcs(readmemw(easeg,(cpu_state.eaaddr+2)&0xFFFF)); //geteaw2(); -// cs=loadcs(CS); -// cs=CS<<4; + cpu_state.pc=readmemw(easeg,cpu_state.eaaddr); + loadcs(readmemw(easeg,(cpu_state.eaaddr+2)&0xFFFF)); cycles-=24; FETCHCLEAR(); break; case 0x30: /*PUSH w*/ case 0x38: /*PUSH w alias, reported by reenigne*/ tempw=geteaw(); -// if (output) printf("PUSH %04X %i %02X %04X %04X %02X %02X\n",tempw,rm,rmdat,easeg,eaaddr,ram[0x22340+0x5638],ram[0x22340+0x5639]); if (cpu_state.ssegs) ss=oldss; writememw(ss,((SP-2)&0xFFFF),tempw); SP-=2; cpu_state.last_ea = SP; cycles-=((cpu_mod==3)?15:24); break; - -// default: -// printf("Bad FF opcode %02X\n",rmdat&0x38); -// dumpregs(); -// exit(-1); } break; @@ -3433,25 +3114,9 @@ void execx86(int cycs) FETCH(); cycles-=8; break; - -/* printf("Bad opcode %02X at %04X:%04X from %04X:%04X %08X\n",opcode,cs>>4,pc,old8>>16,old8&0xFFFF,old82); - dumpregs(); - exit(-1);*/ } cpu_state.pc&=0xFFFF; -/* if ((CS & 0xf000) == 0xa000) - { - dumpregs(); - exit(-1); - }*/ -// output = 3; -/* if (CS == 0xf000) - { - dumpregs(); - exit(-1); - } - output = 3;*/ if (cpu_state.ssegs) { ds=oldds; @@ -3459,8 +3124,6 @@ void execx86(int cycs) cpu_state.ssegs=0; } -// output = 3; - // if (instime) printf("%i %i %i %i\n",cycdiff,cycles,memcycs,fetchclocks); FETCHADD(((cycdiff-cycles)-memcycs)-fetchclocks); if ((cycdiff-cycles)> 12].head; uint64_t a = _cs | ((uint64_t)phys << 32); @@ -87,7 +88,7 @@ static inline codeblock_t *codeblock_tree_find(uint32_t phys, uint32_t _cs) return block; } -static inline void codeblock_tree_add(codeblock_t *new_block) +static __inline void codeblock_tree_add(codeblock_t *new_block) { codeblock_t *block = pages[new_block->phys >> 12].head; uint64_t a = new_block->_cs | ((uint64_t)new_block->phys << 32); @@ -121,7 +122,7 @@ static inline void codeblock_tree_add(codeblock_t *new_block) } } -static inline void codeblock_tree_delete(codeblock_t *block) +static __inline void codeblock_tree_delete(codeblock_t *block) { codeblock_t *parent = block->parent; @@ -236,8 +237,10 @@ static inline void codeblock_tree_delete(codeblock_t *block) } } +#define PAGE_MASK_INDEX_MASK 3 +#define PAGE_MASK_INDEX_SHIFT 10 #define PAGE_MASK_MASK 63 -#define PAGE_MASK_SHIFT 6 +#define PAGE_MASK_SHIFT 4 extern codeblock_t *codeblock; @@ -297,7 +300,7 @@ extern int block_pos; #define CPU_BLOCK_END() cpu_block_end = 1 -static inline void addbyte(uint8_t val) +static __inline void addbyte(uint8_t val) { codeblock[block_current].data[block_pos++] = val; if (block_pos >= BLOCK_MAX) @@ -306,9 +309,10 @@ static inline void addbyte(uint8_t val) } } -static inline void addword(uint16_t val) +static __inline void addword(uint16_t val) { - *(uint16_t *)&codeblock[block_current].data[block_pos] = val; + uint16_t *p = (uint16_t *)&codeblock[block_current].data[block_pos]; + *p = val; block_pos += 2; if (block_pos >= BLOCK_MAX) { @@ -316,9 +320,10 @@ static inline void addword(uint16_t val) } } -static inline void addlong(uint32_t val) +static __inline void addlong(uint32_t val) { - *(uint32_t *)&codeblock[block_current].data[block_pos] = val; + uint32_t *p = (uint32_t *)&codeblock[block_current].data[block_pos]; + *p = val; block_pos += 4; if (block_pos >= BLOCK_MAX) { @@ -326,9 +331,10 @@ static inline void addlong(uint32_t val) } } -static inline void addquad(uint64_t val) +static __inline void addquad(uint64_t val) { - *(uint64_t *)&codeblock[block_current].data[block_pos] = val; + uint64_t *p = (uint64_t *)&codeblock[block_current].data[block_pos]; + *p = val; block_pos += 8; if (block_pos >= BLOCK_MAX) { diff --git a/src/codegen_ops.c b/src/CPU/codegen_ops.c similarity index 99% rename from src/codegen_ops.c rename to src/CPU/codegen_ops.c index a1f846a52..2bd6550e2 100644 --- a/src/codegen_ops.c +++ b/src/CPU/codegen_ops.c @@ -1,4 +1,5 @@ -#include "ibm.h" +#include "../ibm.h" +#include "../mem.h" #include "x86.h" #include "x86_ops.h" #include "x86_flags.h" diff --git a/src/codegen_ops.h b/src/CPU/codegen_ops.h similarity index 100% rename from src/codegen_ops.h rename to src/CPU/codegen_ops.h diff --git a/src/codegen_ops_arith.h b/src/CPU/codegen_ops_arith.h similarity index 75% rename from src/codegen_ops_arith.h rename to src/CPU/codegen_ops_arith.h index b732f9f9f..ed2ce1ece 100644 --- a/src/codegen_ops_arith.h +++ b/src/CPU/codegen_ops_arith.h @@ -2,15 +2,15 @@ static uint32_t ropINC_rw(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uin { int host_reg; - CALL_FUNC(flags_rebuild_c); + CALL_FUNC((uintptr_t)flags_rebuild_c); host_reg = LOAD_REG_W(opcode & 7); - STORE_HOST_REG_ADDR_WL((uint32_t)&cpu_state.flags_op1, host_reg); + STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_op1, host_reg); ADD_HOST_REG_IMM_W(host_reg, 1); - STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op2, 1); - STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_INC16); - STORE_HOST_REG_ADDR_WL((uint32_t)&cpu_state.flags_res, host_reg); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, 1); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_INC16); + STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_res, host_reg); STORE_REG_W_RELEASE(host_reg); codegen_flags_changed = 1; @@ -21,15 +21,15 @@ static uint32_t ropINC_rl(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uin { int host_reg; - CALL_FUNC(flags_rebuild_c); + CALL_FUNC((uintptr_t)flags_rebuild_c); host_reg = LOAD_REG_L(opcode & 7); - STORE_HOST_REG_ADDR((uint32_t)&cpu_state.flags_op1, host_reg); + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_op1, host_reg); ADD_HOST_REG_IMM(host_reg, 1); - STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op2, 1); - STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_INC32); - STORE_HOST_REG_ADDR((uint32_t)&cpu_state.flags_res, host_reg); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, 1); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_INC32); + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_res, host_reg); STORE_REG_L_RELEASE(host_reg); codegen_flags_changed = 1; @@ -40,15 +40,15 @@ static uint32_t ropDEC_rw(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uin { int host_reg; - CALL_FUNC(flags_rebuild_c); + CALL_FUNC((uintptr_t)flags_rebuild_c); host_reg = LOAD_REG_W(opcode & 7); - STORE_HOST_REG_ADDR_WL((uint32_t)&cpu_state.flags_op1, host_reg); + STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_op1, host_reg); SUB_HOST_REG_IMM_W(host_reg, 1); - STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op2, 1); - STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_DEC16); - STORE_HOST_REG_ADDR_WL((uint32_t)&cpu_state.flags_res, host_reg); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, 1); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_DEC16); + STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_res, host_reg); STORE_REG_W_RELEASE(host_reg); codegen_flags_changed = 1; @@ -59,15 +59,15 @@ static uint32_t ropDEC_rl(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uin { int host_reg; - CALL_FUNC(flags_rebuild_c); + CALL_FUNC((uintptr_t)flags_rebuild_c); host_reg = LOAD_REG_L(opcode & 7); - STORE_HOST_REG_ADDR((uint32_t)&cpu_state.flags_op1, host_reg); + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_op1, host_reg); SUB_HOST_REG_IMM(host_reg, 1); - STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op2, 1); - STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_DEC32); - STORE_HOST_REG_ADDR((uint32_t)&cpu_state.flags_res, host_reg); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, 1); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_DEC32); + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_res, host_reg); STORE_REG_L_RELEASE(host_reg); codegen_flags_changed = 1; @@ -93,12 +93,12 @@ static uint32_t ropDEC_rl(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uin MEM_CHECK_WRITE(target_seg); \ dst_reg = MEM_LOAD_ADDR_EA_B_NO_ABRT(target_seg); \ } \ - STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_ ## op ## 8); \ + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ ## op ## 8); \ src_reg = LOAD_REG_B((fetchdat >> 3) & 7); \ - STORE_HOST_REG_ADDR_BL((uint32_t)&cpu_state.flags_op1, dst_reg); \ - STORE_HOST_REG_ADDR_BL((uint32_t)&cpu_state.flags_op2, src_reg); \ + STORE_HOST_REG_ADDR_BL((uintptr_t)&cpu_state.flags_op1, dst_reg); \ + STORE_HOST_REG_ADDR_BL((uintptr_t)&cpu_state.flags_op2, src_reg); \ op ## _HOST_REG_B(dst_reg, src_reg); \ - STORE_HOST_REG_ADDR_BL((uint32_t)&cpu_state.flags_res, dst_reg); \ + STORE_HOST_REG_ADDR_BL((uintptr_t)&cpu_state.flags_res, dst_reg); \ if (writeback) \ { \ if ((fetchdat & 0xc0) == 0xc0) \ @@ -133,12 +133,12 @@ static uint32_t ropDEC_rl(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uin MEM_CHECK_WRITE_W(target_seg); \ dst_reg = MEM_LOAD_ADDR_EA_W_NO_ABRT(target_seg); \ } \ - STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_ ## op ## 16); \ + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ ## op ## 16); \ src_reg = LOAD_REG_W((fetchdat >> 3) & 7); \ - STORE_HOST_REG_ADDR_WL((uint32_t)&cpu_state.flags_op1, dst_reg); \ - STORE_HOST_REG_ADDR_WL((uint32_t)&cpu_state.flags_op2, src_reg); \ + STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_op1, dst_reg); \ + STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_op2, src_reg); \ op ## _HOST_REG_W(dst_reg, src_reg); \ - STORE_HOST_REG_ADDR_WL((uint32_t)&cpu_state.flags_res, dst_reg); \ + STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_res, dst_reg); \ if (writeback) \ { \ if ((fetchdat & 0xc0) == 0xc0) \ @@ -173,12 +173,12 @@ static uint32_t ropDEC_rl(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uin MEM_CHECK_WRITE_L(target_seg); \ dst_reg = MEM_LOAD_ADDR_EA_L_NO_ABRT(target_seg); \ } \ - STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_ ## op ## 32); \ + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ ## op ## 32); \ src_reg = LOAD_REG_L((fetchdat >> 3) & 7); \ - STORE_HOST_REG_ADDR((uint32_t)&cpu_state.flags_op1, dst_reg); \ - STORE_HOST_REG_ADDR((uint32_t)&cpu_state.flags_op2, src_reg); \ + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_op1, dst_reg); \ + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_op2, src_reg); \ op ## _HOST_REG_L(dst_reg, src_reg); \ - STORE_HOST_REG_ADDR((uint32_t)&cpu_state.flags_res, dst_reg); \ + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_res, dst_reg); \ if (writeback) \ { \ if ((fetchdat & 0xc0) == 0xc0) \ @@ -215,11 +215,11 @@ static uint32_t ropDEC_rl(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uin } \ \ dst_reg = LOAD_REG_B((fetchdat >> 3) & 7); \ - STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_ ## op ## 8); \ - STORE_HOST_REG_ADDR_BL((uint32_t)&cpu_state.flags_op1, dst_reg); \ - STORE_HOST_REG_ADDR_BL((uint32_t)&cpu_state.flags_op2, src_reg); \ + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ ## op ## 8); \ + STORE_HOST_REG_ADDR_BL((uintptr_t)&cpu_state.flags_op1, dst_reg); \ + STORE_HOST_REG_ADDR_BL((uintptr_t)&cpu_state.flags_op2, src_reg); \ op ## _HOST_REG_B(dst_reg, src_reg); \ - STORE_HOST_REG_ADDR_BL((uint32_t)&cpu_state.flags_res, dst_reg); \ + STORE_HOST_REG_ADDR_BL((uintptr_t)&cpu_state.flags_res, dst_reg); \ if (writeback) STORE_REG_B_RELEASE(dst_reg); \ else RELEASE_REG(dst_reg); \ RELEASE_REG(src_reg); \ @@ -244,11 +244,11 @@ static uint32_t ropDEC_rl(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uin } \ \ dst_reg = LOAD_REG_W((fetchdat >> 3) & 7); \ - STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_ ## op ## 16); \ - STORE_HOST_REG_ADDR_WL((uint32_t)&cpu_state.flags_op1, dst_reg); \ - STORE_HOST_REG_ADDR_WL((uint32_t)&cpu_state.flags_op2, src_reg); \ + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ ## op ## 16); \ + STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_op1, dst_reg); \ + STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_op2, src_reg); \ op ## _HOST_REG_W(dst_reg, src_reg); \ - STORE_HOST_REG_ADDR_WL((uint32_t)&cpu_state.flags_res, dst_reg); \ + STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_res, dst_reg); \ if (writeback) STORE_REG_W_RELEASE(dst_reg); \ else RELEASE_REG(dst_reg); \ RELEASE_REG(src_reg); \ @@ -273,11 +273,11 @@ static uint32_t ropDEC_rl(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uin } \ \ dst_reg = LOAD_REG_L((fetchdat >> 3) & 7); \ - STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_ ## op ## 32); \ - STORE_HOST_REG_ADDR((uint32_t)&cpu_state.flags_op1, dst_reg); \ - STORE_HOST_REG_ADDR((uint32_t)&cpu_state.flags_op2, src_reg); \ + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ ## op ## 32); \ + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_op1, dst_reg); \ + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_op2, src_reg); \ op ## _HOST_REG_L(dst_reg, src_reg); \ - STORE_HOST_REG_ADDR((uint32_t)&cpu_state.flags_res, dst_reg); \ + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_res, dst_reg); \ if (writeback) STORE_REG_L_RELEASE(dst_reg); \ else RELEASE_REG(dst_reg); \ RELEASE_REG(src_reg); \ @@ -308,11 +308,11 @@ static uint32_t ropCMP_b_rm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, u } dst_reg = LOAD_REG_B((fetchdat >> 3) & 7); - STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_SUB8); - STORE_HOST_REG_ADDR_BL((uint32_t)&cpu_state.flags_op1, dst_reg); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_SUB8); + STORE_HOST_REG_ADDR_BL((uintptr_t)&cpu_state.flags_op1, dst_reg); dst_reg = CMP_HOST_REG_B(dst_reg, src_reg); - STORE_HOST_REG_ADDR_BL((uint32_t)&cpu_state.flags_op2, src_reg); - STORE_HOST_REG_ADDR_BL((uint32_t)&cpu_state.flags_res, dst_reg); + STORE_HOST_REG_ADDR_BL((uintptr_t)&cpu_state.flags_op2, src_reg); + STORE_HOST_REG_ADDR_BL((uintptr_t)&cpu_state.flags_res, dst_reg); RELEASE_REG(dst_reg); RELEASE_REG(src_reg); @@ -336,11 +336,11 @@ static uint32_t ropCMP_w_rm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, u } dst_reg = LOAD_REG_W((fetchdat >> 3) & 7); - STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_SUB16); - STORE_HOST_REG_ADDR_WL((uint32_t)&cpu_state.flags_op1, dst_reg); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_SUB16); + STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_op1, dst_reg); dst_reg = CMP_HOST_REG_W(dst_reg, src_reg); - STORE_HOST_REG_ADDR_WL((uint32_t)&cpu_state.flags_op2, src_reg); - STORE_HOST_REG_ADDR_WL((uint32_t)&cpu_state.flags_res, dst_reg); + STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_op2, src_reg); + STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_res, dst_reg); RELEASE_REG(dst_reg); RELEASE_REG(src_reg); @@ -364,11 +364,11 @@ static uint32_t ropCMP_l_rm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, u } dst_reg = LOAD_REG_L((fetchdat >> 3) & 7); - STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_SUB32); - STORE_HOST_REG_ADDR((uint32_t)&cpu_state.flags_op1, dst_reg); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_SUB32); + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_op1, dst_reg); dst_reg = CMP_HOST_REG_L(dst_reg, src_reg); - STORE_HOST_REG_ADDR((uint32_t)&cpu_state.flags_op2, src_reg); - STORE_HOST_REG_ADDR((uint32_t)&cpu_state.flags_res, dst_reg); + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_op2, src_reg); + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_res, dst_reg); RELEASE_REG(dst_reg); RELEASE_REG(src_reg); @@ -392,12 +392,12 @@ static uint32_t ropCMP_b_rmw(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, dst_reg = 0; } - STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_SUB8); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_SUB8); src_reg = LOAD_REG_B((fetchdat >> 3) & 7); - STORE_HOST_REG_ADDR_BL((uint32_t)&cpu_state.flags_op1, dst_reg); + STORE_HOST_REG_ADDR_BL((uintptr_t)&cpu_state.flags_op1, dst_reg); dst_reg = CMP_HOST_REG_B(dst_reg, src_reg); - STORE_HOST_REG_ADDR_BL((uint32_t)&cpu_state.flags_op2, src_reg); - STORE_HOST_REG_ADDR_BL((uint32_t)&cpu_state.flags_res, dst_reg); + STORE_HOST_REG_ADDR_BL((uintptr_t)&cpu_state.flags_op2, src_reg); + STORE_HOST_REG_ADDR_BL((uintptr_t)&cpu_state.flags_res, dst_reg); RELEASE_REG(dst_reg); RELEASE_REG(src_reg); @@ -420,12 +420,12 @@ static uint32_t ropCMP_w_rmw(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, dst_reg = 0; } \ - STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_SUB16); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_SUB16); src_reg = LOAD_REG_W((fetchdat >> 3) & 7); - STORE_HOST_REG_ADDR_WL((uint32_t)&cpu_state.flags_op1, dst_reg); + STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_op1, dst_reg); dst_reg = CMP_HOST_REG_W(dst_reg, src_reg); - STORE_HOST_REG_ADDR_WL((uint32_t)&cpu_state.flags_op2, src_reg); - STORE_HOST_REG_ADDR_WL((uint32_t)&cpu_state.flags_res, dst_reg); + STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_op2, src_reg); + STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_res, dst_reg); RELEASE_REG(dst_reg); RELEASE_REG(src_reg); @@ -448,12 +448,12 @@ static uint32_t ropCMP_l_rmw(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, dst_reg = 0; } - STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_SUB32); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_SUB32); src_reg = LOAD_REG_L((fetchdat >> 3) & 7); - STORE_HOST_REG_ADDR((uint32_t)&cpu_state.flags_op1, dst_reg); + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_op1, dst_reg); dst_reg = CMP_HOST_REG_L(dst_reg, src_reg); - STORE_HOST_REG_ADDR((uint32_t)&cpu_state.flags_op2, src_reg); - STORE_HOST_REG_ADDR((uint32_t)&cpu_state.flags_res, dst_reg); + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_op2, src_reg); + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_res, dst_reg); RELEASE_REG(dst_reg); RELEASE_REG(src_reg); @@ -466,11 +466,11 @@ static uint32_t ropADD_AL_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, { int host_reg = LOAD_REG_B(REG_AL); - STORE_HOST_REG_ADDR_BL((uint32_t)&cpu_state.flags_op1, host_reg); + STORE_HOST_REG_ADDR_BL((uintptr_t)&cpu_state.flags_op1, host_reg); ADD_HOST_REG_IMM_B(host_reg, fetchdat & 0xff); - STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op2, fetchdat & 0xff); - STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_ADD8); - STORE_HOST_REG_ADDR_BL((uint32_t)&cpu_state.flags_res, host_reg); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, fetchdat & 0xff); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ADD8); + STORE_HOST_REG_ADDR_BL((uintptr_t)&cpu_state.flags_res, host_reg); STORE_REG_B_RELEASE(host_reg); codegen_flags_changed = 1; @@ -480,11 +480,11 @@ static uint32_t ropADD_AX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, { int host_reg = LOAD_REG_W(REG_AX); - STORE_HOST_REG_ADDR_WL((uint32_t)&cpu_state.flags_op1, host_reg); + STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_op1, host_reg); ADD_HOST_REG_IMM_W(host_reg, fetchdat & 0xffff); - STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op2, fetchdat & 0xffff); - STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_ADD16); - STORE_HOST_REG_ADDR_WL((uint32_t)&cpu_state.flags_res, host_reg); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, fetchdat & 0xffff); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ADD16); + STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_res, host_reg); STORE_REG_W_RELEASE(host_reg); codegen_flags_changed = 1; @@ -494,12 +494,12 @@ static uint32_t ropADD_EAX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32 { int host_reg = LOAD_REG_L(REG_EAX); - STORE_HOST_REG_ADDR((uint32_t)&cpu_state.flags_op1, host_reg); + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_op1, host_reg); fetchdat = fastreadl(cs + op_pc); ADD_HOST_REG_IMM(host_reg, fetchdat); - STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op2, fetchdat); - STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_ADD32); - STORE_HOST_REG_ADDR((uint32_t)&cpu_state.flags_res, host_reg); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, fetchdat); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ADD32); + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_res, host_reg); STORE_REG_L_RELEASE(host_reg); codegen_flags_changed = 1; @@ -510,11 +510,11 @@ static uint32_t ropCMP_AL_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, { int host_reg = LOAD_REG_B(REG_AL); - STORE_HOST_REG_ADDR_BL((uint32_t)&cpu_state.flags_op1, host_reg); + STORE_HOST_REG_ADDR_BL((uintptr_t)&cpu_state.flags_op1, host_reg); host_reg = CMP_HOST_REG_IMM_B(host_reg, fetchdat & 0xff); - STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op2, fetchdat & 0xff); - STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_SUB8); - STORE_HOST_REG_ADDR_BL((uint32_t)&cpu_state.flags_res, host_reg); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, fetchdat & 0xff); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_SUB8); + STORE_HOST_REG_ADDR_BL((uintptr_t)&cpu_state.flags_res, host_reg); RELEASE_REG(host_reg); codegen_flags_changed = 1; @@ -524,11 +524,11 @@ static uint32_t ropCMP_AX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, { int host_reg = LOAD_REG_W(REG_AX); - STORE_HOST_REG_ADDR_WL((uint32_t)&cpu_state.flags_op1, host_reg); + STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_op1, host_reg); host_reg = CMP_HOST_REG_IMM_W(host_reg, fetchdat & 0xffff); - STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op2, fetchdat & 0xffff); - STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_SUB16); - STORE_HOST_REG_ADDR_WL((uint32_t)&cpu_state.flags_res, host_reg); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, fetchdat & 0xffff); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_SUB16); + STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_res, host_reg); RELEASE_REG(host_reg); codegen_flags_changed = 1; @@ -538,12 +538,12 @@ static uint32_t ropCMP_EAX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32 { int host_reg = LOAD_REG_L(REG_EAX); - STORE_HOST_REG_ADDR((uint32_t)&cpu_state.flags_op1, host_reg); + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_op1, host_reg); fetchdat = fastreadl(cs + op_pc); host_reg = CMP_HOST_REG_IMM_L(host_reg, fetchdat); - STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op2, fetchdat); - STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_SUB32); - STORE_HOST_REG_ADDR((uint32_t)&cpu_state.flags_res, host_reg); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, fetchdat); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_SUB32); + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_res, host_reg); RELEASE_REG(host_reg); codegen_flags_changed = 1; @@ -554,11 +554,11 @@ static uint32_t ropSUB_AL_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, { int host_reg = LOAD_REG_B(REG_AL); - STORE_HOST_REG_ADDR_BL((uint32_t)&cpu_state.flags_op1, host_reg); + STORE_HOST_REG_ADDR_BL((uintptr_t)&cpu_state.flags_op1, host_reg); SUB_HOST_REG_IMM_B(host_reg, fetchdat & 0xff); - STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op2, fetchdat & 0xff); - STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_SUB8); - STORE_HOST_REG_ADDR_BL((uint32_t)&cpu_state.flags_res, host_reg); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, fetchdat & 0xff); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_SUB8); + STORE_HOST_REG_ADDR_BL((uintptr_t)&cpu_state.flags_res, host_reg); STORE_REG_B_RELEASE(host_reg); codegen_flags_changed = 1; @@ -568,11 +568,11 @@ static uint32_t ropSUB_AX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, { int host_reg = LOAD_REG_W(REG_AX); - STORE_HOST_REG_ADDR_WL((uint32_t)&cpu_state.flags_op1, host_reg); + STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_op1, host_reg); SUB_HOST_REG_IMM_W(host_reg, fetchdat & 0xffff); - STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op2, fetchdat & 0xffff); - STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_SUB16); - STORE_HOST_REG_ADDR_WL((uint32_t)&cpu_state.flags_res, host_reg); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, fetchdat & 0xffff); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_SUB16); + STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_res, host_reg); STORE_REG_W_RELEASE(host_reg); codegen_flags_changed = 1; @@ -582,12 +582,12 @@ static uint32_t ropSUB_EAX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32 { int host_reg = LOAD_REG_L(REG_EAX); - STORE_HOST_REG_ADDR((uint32_t)&cpu_state.flags_op1, host_reg); + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_op1, host_reg); fetchdat = fastreadl(cs + op_pc); SUB_HOST_REG_IMM(host_reg, fetchdat); - STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op2, fetchdat); - STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_SUB32); - STORE_HOST_REG_ADDR((uint32_t)&cpu_state.flags_res, host_reg); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, fetchdat); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_SUB32); + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_res, host_reg); STORE_REG_L_RELEASE(host_reg); codegen_flags_changed = 1; @@ -598,7 +598,7 @@ static uint32_t rop80(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_ { int host_reg; uint32_t imm; - x86seg *target_seg; + x86seg *target_seg = NULL; if ((fetchdat & 0x30) == 0x10) return 0; @@ -629,38 +629,38 @@ static uint32_t rop80(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_ switch (fetchdat & 0x38) { case 0x00: /*ADD*/ - STORE_HOST_REG_ADDR_BL((uint32_t)&cpu_state.flags_op1, host_reg); + STORE_HOST_REG_ADDR_BL((uintptr_t)&cpu_state.flags_op1, host_reg); ADD_HOST_REG_IMM_B(host_reg, imm); - STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op2, imm); - STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_ADD8); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, imm); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ADD8); break; case 0x08: /*OR*/ OR_HOST_REG_IMM(host_reg, imm); - STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_ZN8); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN8); break; case 0x20: /*AND*/ AND_HOST_REG_IMM(host_reg, imm | 0xffffff00); - STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_ZN8); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN8); break; case 0x28: /*SUB*/ - STORE_HOST_REG_ADDR_BL((uint32_t)&cpu_state.flags_op1, host_reg); + STORE_HOST_REG_ADDR_BL((uintptr_t)&cpu_state.flags_op1, host_reg); SUB_HOST_REG_IMM_B(host_reg, imm); - STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op2, imm); - STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_SUB8); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, imm); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_SUB8); break; case 0x30: /*XOR*/ XOR_HOST_REG_IMM(host_reg, imm); - STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_ZN8); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN8); break; case 0x38: /*CMP*/ - STORE_HOST_REG_ADDR_BL((uint32_t)&cpu_state.flags_op1, host_reg); + STORE_HOST_REG_ADDR_BL((uintptr_t)&cpu_state.flags_op1, host_reg); host_reg = CMP_HOST_REG_IMM_B(host_reg, imm); - STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op2, imm); - STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_SUB8); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, imm); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_SUB8); break; } - STORE_HOST_REG_ADDR_BL((uint32_t)&cpu_state.flags_res, host_reg); + STORE_HOST_REG_ADDR_BL((uintptr_t)&cpu_state.flags_res, host_reg); if ((fetchdat & 0x38) != 0x38) { if ((fetchdat & 0xc0) != 0xc0) @@ -684,7 +684,7 @@ static uint32_t rop81_w(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint3 { int host_reg; uint32_t imm; - x86seg *target_seg; + x86seg *target_seg = NULL; if ((fetchdat & 0x30) == 0x10) return 0; @@ -715,38 +715,38 @@ static uint32_t rop81_w(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint3 switch (fetchdat & 0x38) { case 0x00: /*ADD*/ - STORE_HOST_REG_ADDR_WL((uint32_t)&cpu_state.flags_op1, host_reg); + STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_op1, host_reg); ADD_HOST_REG_IMM_W(host_reg, imm); - STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op2, imm); - STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_ADD16); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, imm); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ADD16); break; case 0x08: /*OR*/ OR_HOST_REG_IMM(host_reg, imm); - STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_ZN16); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN16); break; case 0x20: /*AND*/ AND_HOST_REG_IMM(host_reg, imm | 0xffff0000); - STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_ZN16); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN16); break; case 0x28: /*SUB*/ - STORE_HOST_REG_ADDR_WL((uint32_t)&cpu_state.flags_op1, host_reg); + STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_op1, host_reg); SUB_HOST_REG_IMM_W(host_reg, imm); - STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op2, imm); - STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_SUB16); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, imm); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_SUB16); break; case 0x30: /*XOR*/ XOR_HOST_REG_IMM(host_reg, imm); - STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_ZN16); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN16); break; case 0x38: /*CMP*/ - STORE_HOST_REG_ADDR_WL((uint32_t)&cpu_state.flags_op1, host_reg); + STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_op1, host_reg); host_reg = CMP_HOST_REG_IMM_W(host_reg, imm); - STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op2, imm); - STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_SUB16); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, imm); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_SUB16); break; } - STORE_HOST_REG_ADDR_WL((uint32_t)&cpu_state.flags_res, host_reg); + STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_res, host_reg); if ((fetchdat & 0x38) != 0x38) { if ((fetchdat & 0xc0) != 0xc0) @@ -769,7 +769,7 @@ static uint32_t rop81_l(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint3 { int host_reg; uint32_t imm; - x86seg *target_seg; + x86seg *target_seg = NULL; if ((fetchdat & 0x30) == 0x10) return 0; @@ -799,38 +799,38 @@ static uint32_t rop81_l(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint3 switch (fetchdat & 0x38) { case 0x00: /*ADD*/ - STORE_HOST_REG_ADDR((uint32_t)&cpu_state.flags_op1, host_reg); + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_op1, host_reg); ADD_HOST_REG_IMM(host_reg, imm); - STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op2, imm); - STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_ADD32); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, imm); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ADD32); break; case 0x08: /*OR*/ OR_HOST_REG_IMM(host_reg, imm); - STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_ZN32); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN32); break; case 0x20: /*AND*/ AND_HOST_REG_IMM(host_reg, imm); - STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_ZN32); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN32); break; case 0x28: /*SUB*/ - STORE_HOST_REG_ADDR((uint32_t)&cpu_state.flags_op1, host_reg); + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_op1, host_reg); SUB_HOST_REG_IMM(host_reg, imm); - STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op2, imm); - STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_SUB32); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, imm); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_SUB32); break; case 0x30: /*XOR*/ XOR_HOST_REG_IMM(host_reg, imm); - STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_ZN32); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN32); break; case 0x38: /*CMP*/ - STORE_HOST_REG_ADDR((uint32_t)&cpu_state.flags_op1, host_reg); + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_op1, host_reg); host_reg = CMP_HOST_REG_IMM_L(host_reg, imm); - STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op2, imm); - STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_SUB32); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, imm); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_SUB32); break; } - STORE_HOST_REG_ADDR((uint32_t)&cpu_state.flags_res, host_reg); + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_res, host_reg); if ((fetchdat & 0x38) != 0x38) { if ((fetchdat & 0xc0) != 0xc0) @@ -854,7 +854,7 @@ static uint32_t rop83_w(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint3 { int host_reg; uint32_t imm; - x86seg *target_seg; + x86seg *target_seg = NULL; if ((fetchdat & 0x30) == 0x10) return 0; @@ -888,38 +888,38 @@ static uint32_t rop83_w(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint3 switch (fetchdat & 0x38) { case 0x00: /*ADD*/ - STORE_HOST_REG_ADDR_WL((uint32_t)&cpu_state.flags_op1, host_reg); + STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_op1, host_reg); ADD_HOST_REG_IMM_W(host_reg, imm); - STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op2, imm); - STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_ADD16); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, imm); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ADD16); break; case 0x08: /*OR*/ OR_HOST_REG_IMM(host_reg, imm); - STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_ZN16); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN16); break; case 0x20: /*AND*/ AND_HOST_REG_IMM(host_reg, imm | 0xffff0000); - STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_ZN16); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN16); break; case 0x28: /*SUB*/ - STORE_HOST_REG_ADDR_WL((uint32_t)&cpu_state.flags_op1, host_reg); + STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_op1, host_reg); SUB_HOST_REG_IMM_W(host_reg, imm); - STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op2, imm); - STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_SUB16); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, imm); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_SUB16); break; case 0x30: /*XOR*/ XOR_HOST_REG_IMM(host_reg, imm); - STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_ZN16); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN16); break; case 0x38: /*CMP*/ - STORE_HOST_REG_ADDR_WL((uint32_t)&cpu_state.flags_op1, host_reg); + STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_op1, host_reg); host_reg = CMP_HOST_REG_IMM_W(host_reg, imm); - STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op2, imm); - STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_SUB16); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, imm); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_SUB16); break; } - STORE_HOST_REG_ADDR_WL((uint32_t)&cpu_state.flags_res, host_reg); + STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_res, host_reg); if ((fetchdat & 0x38) != 0x38) { if ((fetchdat & 0xc0) != 0xc0) @@ -942,7 +942,7 @@ static uint32_t rop83_l(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint3 { int host_reg; uint32_t imm; - x86seg *target_seg; + x86seg *target_seg = NULL; if ((fetchdat & 0x30) == 0x10) return 0; @@ -976,38 +976,38 @@ static uint32_t rop83_l(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint3 switch (fetchdat & 0x38) { case 0x00: /*ADD*/ - STORE_HOST_REG_ADDR((uint32_t)&cpu_state.flags_op1, host_reg); + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_op1, host_reg); ADD_HOST_REG_IMM(host_reg, imm); - STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op2, imm); - STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_ADD32); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, imm); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ADD32); break; case 0x08: /*OR*/ OR_HOST_REG_IMM(host_reg, imm); - STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_ZN32); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN32); break; case 0x20: /*AND*/ AND_HOST_REG_IMM(host_reg, imm); - STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_ZN32); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN32); break; case 0x28: /*SUB*/ - STORE_HOST_REG_ADDR((uint32_t)&cpu_state.flags_op1, host_reg); + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_op1, host_reg); SUB_HOST_REG_IMM(host_reg, imm); - STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op2, imm); - STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_SUB32); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, imm); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_SUB32); break; case 0x30: /*XOR*/ XOR_HOST_REG_IMM(host_reg, imm); - STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_ZN32); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN32); break; case 0x38: /*CMP*/ - STORE_HOST_REG_ADDR((uint32_t)&cpu_state.flags_op1, host_reg); + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_op1, host_reg); host_reg = CMP_HOST_REG_IMM_L(host_reg, imm); - STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op2, imm); - STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_SUB32); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, imm); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_SUB32); break; } - STORE_HOST_REG_ADDR((uint32_t)&cpu_state.flags_res, host_reg); + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_res, host_reg); if ((fetchdat & 0x38) != 0x38) { if ((fetchdat & 0xc0) != 0xc0) diff --git a/src/codegen_ops_fpu.h b/src/CPU/codegen_ops_fpu.h similarity index 98% rename from src/codegen_ops_fpu.h rename to src/CPU/codegen_ops_fpu.h index 4fafa33ce..7cc9499e5 100644 --- a/src/codegen_ops_fpu.h +++ b/src/CPU/codegen_ops_fpu.h @@ -491,7 +491,7 @@ static uint32_t ropFSTSW_AX(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, u int host_reg; FP_ENTER(); - host_reg = LOAD_VAR_W(&cpu_state.npxs); + host_reg = LOAD_VAR_W((uintptr_t)&cpu_state.npxs); STORE_REG_TARGET_W_RELEASE(host_reg, REG_AX); return op_pc; @@ -622,9 +622,11 @@ static uint32_t ropFCHS(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint3 static uint32_t ropFLD ## name(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ { \ static double fp_imm = v; \ + static uint64_t *fpp; \ \ FP_ENTER(); \ - FP_LOAD_IMM_Q(*(uint64_t *)&fp_imm); \ + fpp = (uint64_t *)&fp_imm; \ + FP_LOAD_IMM_Q(*fpp); \ \ return op_pc; \ } diff --git a/src/codegen_ops_jump.h b/src/CPU/codegen_ops_jump.h similarity index 93% rename from src/codegen_ops_jump.h rename to src/CPU/codegen_ops_jump.h index 8dba96c7c..0ad293744 100644 --- a/src/codegen_ops_jump.h +++ b/src/CPU/codegen_ops_jump.h @@ -75,16 +75,16 @@ static uint32_t ropLOOP(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint3 return op_pc+1; } -static int BRANCH_COND_B(int pc_offset, uint32_t op_pc, uint32_t offset, int not) +static void BRANCH_COND_B(int pc_offset, uint32_t op_pc, uint32_t offset, int not) { - CALL_FUNC(CF_SET); + CALL_FUNC((uintptr_t)CF_SET); if (not) TEST_ZERO_JUMP_L(0, op_pc+pc_offset+offset, timing_bt); else TEST_NONZERO_JUMP_L(0, op_pc+pc_offset+offset, timing_bt); } -static int BRANCH_COND_E(int pc_offset, uint32_t op_pc, uint32_t offset, int not) +static void BRANCH_COND_E(int pc_offset, uint32_t op_pc, uint32_t offset, int not) { int host_reg; @@ -122,7 +122,7 @@ static int BRANCH_COND_E(int pc_offset, uint32_t op_pc, uint32_t offset, int not break; case FLAGS_UNKNOWN: - CALL_FUNC(ZF_SET); + CALL_FUNC((uintptr_t)ZF_SET); if (not) TEST_ZERO_JUMP_L(0, op_pc+pc_offset+offset, timing_bt); else @@ -131,25 +131,25 @@ static int BRANCH_COND_E(int pc_offset, uint32_t op_pc, uint32_t offset, int not } } -static int BRANCH_COND_O(int pc_offset, uint32_t op_pc, uint32_t offset, int not) +static void BRANCH_COND_O(int pc_offset, uint32_t op_pc, uint32_t offset, int not) { - CALL_FUNC(VF_SET); + CALL_FUNC((uintptr_t)VF_SET); if (not) TEST_ZERO_JUMP_L(0, op_pc+pc_offset+offset, timing_bt); else TEST_NONZERO_JUMP_L(0, op_pc+pc_offset+offset, timing_bt); } -static int BRANCH_COND_P(int pc_offset, uint32_t op_pc, uint32_t offset, int not) +static void BRANCH_COND_P(int pc_offset, uint32_t op_pc, uint32_t offset, int not) { - CALL_FUNC(PF_SET); + CALL_FUNC((uintptr_t)PF_SET); if (not) TEST_ZERO_JUMP_L(0, op_pc+pc_offset+offset, timing_bt); else TEST_NONZERO_JUMP_L(0, op_pc+pc_offset+offset, timing_bt); } -static int BRANCH_COND_S(int pc_offset, uint32_t op_pc, uint32_t offset, int not) +static void BRANCH_COND_S(int pc_offset, uint32_t op_pc, uint32_t offset, int not) { int host_reg; @@ -204,7 +204,7 @@ static int BRANCH_COND_S(int pc_offset, uint32_t op_pc, uint32_t offset, int not break; case FLAGS_UNKNOWN: - CALL_FUNC(NF_SET); + CALL_FUNC((uintptr_t)NF_SET); if (not) TEST_ZERO_JUMP_L(0, op_pc+pc_offset+offset, timing_bt); else diff --git a/src/codegen_ops_logic.h b/src/CPU/codegen_ops_logic.h similarity index 100% rename from src/codegen_ops_logic.h rename to src/CPU/codegen_ops_logic.h diff --git a/src/codegen_ops_misc.h b/src/CPU/codegen_ops_misc.h similarity index 78% rename from src/codegen_ops_misc.h rename to src/CPU/codegen_ops_misc.h index 9d9ee7507..e5d4f59dd 100644 --- a/src/codegen_ops_misc.h +++ b/src/CPU/codegen_ops_misc.h @@ -27,13 +27,13 @@ static uint32_t ropSTI(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32 static uint32_t ropFE(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) { - x86seg *target_seg; + x86seg *target_seg = NULL; int host_reg; if ((fetchdat & 0x30) != 0x00) return 0; - CALL_FUNC(flags_rebuild_c); + CALL_FUNC((uintptr_t)flags_rebuild_c); if ((fetchdat & 0xc0) == 0xc0) host_reg = LOAD_REG_B(fetchdat & 7); @@ -50,18 +50,18 @@ static uint32_t ropFE(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_ switch (fetchdat & 0x38) { case 0x00: /*INC*/ - STORE_HOST_REG_ADDR_BL((uint32_t)&cpu_state.flags_op1, host_reg); + STORE_HOST_REG_ADDR_BL((uintptr_t)&cpu_state.flags_op1, host_reg); ADD_HOST_REG_IMM_B(host_reg, 1); - STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op2, 1); - STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_INC8); - STORE_HOST_REG_ADDR_BL((uint32_t)&cpu_state.flags_res, host_reg); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, 1); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_INC8); + STORE_HOST_REG_ADDR_BL((uintptr_t)&cpu_state.flags_res, host_reg); break; case 0x08: /*DEC*/ - STORE_HOST_REG_ADDR_BL((uint32_t)&cpu_state.flags_op1, host_reg); + STORE_HOST_REG_ADDR_BL((uintptr_t)&cpu_state.flags_op1, host_reg); SUB_HOST_REG_IMM_B(host_reg, 1); - STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op2, 1); - STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_DEC8); - STORE_HOST_REG_ADDR_BL((uint32_t)&cpu_state.flags_res, host_reg); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, 1); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_DEC8); + STORE_HOST_REG_ADDR_BL((uintptr_t)&cpu_state.flags_res, host_reg); break; } @@ -79,14 +79,14 @@ static uint32_t ropFE(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_ static uint32_t codegen_temp; static uint32_t ropFF_16(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) { - x86seg *target_seg; + x86seg *target_seg = NULL; int host_reg; if ((fetchdat & 0x30) != 0x00 && (fetchdat & 0x08)) return 0; if ((fetchdat & 0x30) == 0x00) - CALL_FUNC(flags_rebuild_c); + CALL_FUNC((uintptr_t)flags_rebuild_c); if ((fetchdat & 0xc0) == 0xc0) host_reg = LOAD_REG_W(fetchdat & 7); @@ -111,11 +111,11 @@ static uint32_t ropFF_16(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint switch (fetchdat & 0x38) { case 0x00: /*INC*/ - STORE_HOST_REG_ADDR_WL((uint32_t)&cpu_state.flags_op1, host_reg); + STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_op1, host_reg); ADD_HOST_REG_IMM_W(host_reg, 1); - STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op2, 1); - STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_INC16); - STORE_HOST_REG_ADDR_WL((uint32_t)&cpu_state.flags_res, host_reg); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, 1); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_INC16); + STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_res, host_reg); if ((fetchdat & 0xc0) == 0xc0) STORE_REG_W_RELEASE(host_reg); else @@ -126,11 +126,11 @@ static uint32_t ropFF_16(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint codegen_flags_changed = 1; return op_pc + 1; case 0x08: /*DEC*/ - STORE_HOST_REG_ADDR_WL((uint32_t)&cpu_state.flags_op1, host_reg); + STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_op1, host_reg); SUB_HOST_REG_IMM_W(host_reg, 1); - STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op2, 1); - STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_DEC16); - STORE_HOST_REG_ADDR_WL((uint32_t)&cpu_state.flags_res, host_reg); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, 1); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_DEC16); + STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_res, host_reg); if ((fetchdat & 0xc0) == 0xc0) STORE_REG_W_RELEASE(host_reg); else @@ -168,17 +168,18 @@ static uint32_t ropFF_16(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint SP_MODIFY(-2); return op_pc + 1; } + return 0; } static uint32_t ropFF_32(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) { - x86seg *target_seg; + x86seg *target_seg = NULL; int host_reg; if ((fetchdat & 0x30) != 0x00 && (fetchdat & 0x08)) return 0; if ((fetchdat & 0x30) == 0x00) - CALL_FUNC(flags_rebuild_c); + CALL_FUNC((uintptr_t)flags_rebuild_c); if ((fetchdat & 0xc0) == 0xc0) host_reg = LOAD_REG_L(fetchdat & 7); @@ -203,11 +204,11 @@ static uint32_t ropFF_32(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint switch (fetchdat & 0x38) { case 0x00: /*INC*/ - STORE_HOST_REG_ADDR((uint32_t)&cpu_state.flags_op1, host_reg); + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_op1, host_reg); ADD_HOST_REG_IMM(host_reg, 1); - STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op2, 1); - STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_INC32); - STORE_HOST_REG_ADDR((uint32_t)&cpu_state.flags_res, host_reg); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, 1); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_INC32); + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_res, host_reg); if ((fetchdat & 0xc0) == 0xc0) STORE_REG_L_RELEASE(host_reg); else @@ -218,11 +219,11 @@ static uint32_t ropFF_32(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint codegen_flags_changed = 1; return op_pc + 1; case 0x08: /*DEC*/ - STORE_HOST_REG_ADDR((uint32_t)&cpu_state.flags_op1, host_reg); + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_op1, host_reg); SUB_HOST_REG_IMM(host_reg, 1); - STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op2, 1); - STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_DEC32); - STORE_HOST_REG_ADDR((uint32_t)&cpu_state.flags_res, host_reg); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, 1); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_DEC32); + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_res, host_reg); if ((fetchdat & 0xc0) == 0xc0) STORE_REG_L_RELEASE(host_reg); else @@ -260,4 +261,5 @@ static uint32_t ropFF_32(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint SP_MODIFY(-4); return op_pc + 1; } + return 0; } diff --git a/src/codegen_ops_mmx.h b/src/CPU/codegen_ops_mmx.h similarity index 100% rename from src/codegen_ops_mmx.h rename to src/CPU/codegen_ops_mmx.h diff --git a/src/codegen_ops_mov.h b/src/CPU/codegen_ops_mov.h similarity index 98% rename from src/codegen_ops_mov.h rename to src/CPU/codegen_ops_mov.h index bfee56a29..cb4498343 100644 --- a/src/codegen_ops_mov.h +++ b/src/CPU/codegen_ops_mov.h @@ -512,22 +512,22 @@ static uint32_t ropMOV_w_seg(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, switch (fetchdat & 0x38) { case 0x00: /*ES*/ - host_reg = LOAD_VAR_WL(&ES); + host_reg = LOAD_VAR_WL((uintptr_t)&ES); break; case 0x08: /*CS*/ - host_reg = LOAD_VAR_WL(&CS); + host_reg = LOAD_VAR_WL((uintptr_t)&CS); break; case 0x18: /*DS*/ - host_reg = LOAD_VAR_WL(&DS); + host_reg = LOAD_VAR_WL((uintptr_t)&DS); break; case 0x10: /*SS*/ - host_reg = LOAD_VAR_WL(&SS); + host_reg = LOAD_VAR_WL((uintptr_t)&SS); break; case 0x20: /*FS*/ - host_reg = LOAD_VAR_WL(&FS); + host_reg = LOAD_VAR_WL((uintptr_t)&FS); break; case 0x28: /*GS*/ - host_reg = LOAD_VAR_WL(&GS); + host_reg = LOAD_VAR_WL((uintptr_t)&GS); break; default: return 0; diff --git a/src/codegen_ops_shift.h b/src/CPU/codegen_ops_shift.h similarity index 87% rename from src/codegen_ops_shift.h rename to src/CPU/codegen_ops_shift.h index 937a82ee8..b67c34544 100644 --- a/src/codegen_ops_shift.h +++ b/src/CPU/codegen_ops_shift.h @@ -13,29 +13,29 @@ reg = MEM_LOAD_ADDR_EA_ ## size ## _NO_ABRT(target_seg); \ if (immediate) count = fastreadb(cs + op_pc + 1) & 0x1f; \ } \ - STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op2, count); \ + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, count); \ \ - res_store((uint32_t)&cpu_state.flags_op1, reg); \ + res_store((uintptr_t)&cpu_state.flags_op1, reg); \ \ switch (fetchdat & 0x38) \ { \ case 0x20: case 0x30: /*SHL*/ \ SHL_ ## size ## _IMM(reg, count); \ - STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_SHL ## size2); \ + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_SHL ## size2); \ break; \ \ case 0x28: /*SHR*/ \ SHR_ ## size ## _IMM(reg, count); \ - STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_SHR ## size2); \ + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_SHR ## size2); \ break; \ \ case 0x38: /*SAR*/ \ SAR_ ## size ## _IMM(reg, count); \ - STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_SAR ## size2); \ + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_SAR ## size2); \ break; \ } \ \ - res_store((uint32_t)&cpu_state.flags_res, reg); \ + res_store((uintptr_t)&cpu_state.flags_res, reg); \ if ((fetchdat & 0xc0) == 0xc0) \ STORE_REG_ ## size ## _RELEASE(reg); \ else \ @@ -46,7 +46,7 @@ static uint32_t ropC0(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) { - x86seg *target_seg; + x86seg *target_seg = NULL; int count; int reg; @@ -59,7 +59,7 @@ static uint32_t ropC0(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_ } static uint32_t ropC1_w(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) { - x86seg *target_seg; + x86seg *target_seg = NULL; int count; int reg; @@ -72,7 +72,7 @@ static uint32_t ropC1_w(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint3 } static uint32_t ropC1_l(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) { - x86seg *target_seg; + x86seg *target_seg = NULL; int count; int reg; @@ -86,7 +86,7 @@ static uint32_t ropC1_l(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint3 static uint32_t ropD0(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) { - x86seg *target_seg; + x86seg *target_seg = NULL; int count = 1; int reg; @@ -99,7 +99,7 @@ static uint32_t ropD0(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_ } static uint32_t ropD1_w(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) { - x86seg *target_seg; + x86seg *target_seg = NULL; int count = 1; int reg; @@ -112,7 +112,7 @@ static uint32_t ropD1_w(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint3 } static uint32_t ropD1_l(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) { - x86seg *target_seg; + x86seg *target_seg = NULL; int count = 1; int reg; diff --git a/src/codegen_ops_stack.h b/src/CPU/codegen_ops_stack.h similarity index 95% rename from src/codegen_ops_stack.h rename to src/CPU/codegen_ops_stack.h index 082d8a4e3..96b900273 100644 --- a/src/codegen_ops_stack.h +++ b/src/CPU/codegen_ops_stack.h @@ -85,8 +85,6 @@ static uint32_t ropPUSH_imm_b32(uint8_t opcode, uint32_t fetchdat, uint32_t op_3 static uint32_t ropPOP_16(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) { - int host_reg; - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); LOAD_STACK_TO_EA(0); MEM_LOAD_ADDR_EA_W(&_ss); @@ -97,8 +95,6 @@ static uint32_t ropPOP_16(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uin } static uint32_t ropPOP_32(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) { - int host_reg; - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); LOAD_STACK_TO_EA(0); MEM_LOAD_ADDR_EA_L(&_ss); @@ -110,8 +106,6 @@ static uint32_t ropPOP_32(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uin static uint32_t ropRET_16(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) { - int host_reg; - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); LOAD_STACK_TO_EA(0); MEM_LOAD_ADDR_EA_W(&_ss); @@ -122,8 +116,6 @@ static uint32_t ropRET_16(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uin } static uint32_t ropRET_32(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) { - int host_reg; - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); LOAD_STACK_TO_EA(0); MEM_LOAD_ADDR_EA_L(&_ss); @@ -136,7 +128,6 @@ static uint32_t ropRET_32(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uin static uint32_t ropRET_imm_16(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) { uint16_t offset = fetchdat & 0xffff; - int host_reg; STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); LOAD_STACK_TO_EA(0); @@ -149,7 +140,6 @@ static uint32_t ropRET_imm_16(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, static uint32_t ropRET_imm_32(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) { uint16_t offset = fetchdat & 0xffff; - int host_reg; STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); LOAD_STACK_TO_EA(0); @@ -254,8 +244,6 @@ ROP_PUSH_SEG(SS) #define ROP_POP_SEG(seg, rseg) \ static uint32_t ropPOP_ ## seg ## _16(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ { \ - int host_reg; \ - \ STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); \ LOAD_STACK_TO_EA(0); \ MEM_LOAD_ADDR_EA_W(&_ss); \ @@ -266,8 +254,6 @@ static uint32_t ropPOP_ ## seg ## _16(uint8_t opcode, uint32_t fetchdat, uint32_ } \ static uint32_t ropPOP_ ## seg ## _32(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ { \ - int host_reg; \ - \ STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); \ LOAD_STACK_TO_EA(0); \ MEM_LOAD_ADDR_EA_W(&_ss); \ diff --git a/src/codegen_ops_x86-64.h b/src/CPU/codegen_ops_x86-64.h similarity index 82% rename from src/codegen_ops_x86-64.h rename to src/CPU/codegen_ops_x86-64.h index 452241e81..f6ec2f055 100644 --- a/src/codegen_ops_x86-64.h +++ b/src/CPU/codegen_ops_x86-64.h @@ -1,6 +1,7 @@ /*Register allocation : R8-R15 - emulated registers */ +#include #define HOST_REG_XMM_START 0 #define HOST_REG_XMM_END 7 @@ -20,7 +21,7 @@ static inline int find_host_xmm_reg() fatal("Out of host XMM regs!\n"); return c; } -static void call(codeblock_t *block, uintptr_t func) +static inline void call(codeblock_t *block, uintptr_t func) { uintptr_t diff = func - (uintptr_t)&block->data[block_pos + 5]; @@ -42,7 +43,7 @@ static void call(codeblock_t *block, uintptr_t func) } } -static void call_long(uintptr_t func) +static inline void call_long(uintptr_t func) { codegen_reg_loaded[0] = codegen_reg_loaded[1] = codegen_reg_loaded[2] = codegen_reg_loaded[3] = 0; codegen_reg_loaded[4] = codegen_reg_loaded[5] = codegen_reg_loaded[6] = codegen_reg_loaded[7] = 0; @@ -54,7 +55,7 @@ static void call_long(uintptr_t func) addbyte(0xd0); } -static void load_param_1_32(codeblock_t *block, uint32_t param) +static inline void load_param_1_32(codeblock_t *block, uint32_t param) { #if WIN64 addbyte(0xb9); /*MOVL $fetchdat,%ecx*/ @@ -63,7 +64,7 @@ static void load_param_1_32(codeblock_t *block, uint32_t param) #endif addlong(param); } -static void load_param_1_reg_32(int reg) +static inline void load_param_1_reg_32(int reg) { #if WIN64 if (reg & 8) @@ -77,7 +78,8 @@ static void load_param_1_reg_32(int reg) addbyte(0xc0 | REG_EDI | (reg << 3)); #endif } -static void load_param_1_64(codeblock_t *block, uint64_t param) +#if 0 +static inline void load_param_1_64(codeblock_t *block, uint64_t param) { addbyte(0x48); #if WIN64 @@ -87,8 +89,9 @@ static void load_param_1_64(codeblock_t *block, uint64_t param) #endif addquad(param); } +#endif -static void load_param_2_32(codeblock_t *block, uint32_t param) +static inline void load_param_2_32(codeblock_t *block, uint32_t param) { #if WIN64 addbyte(0xba); /*MOVL $fetchdat,%edx*/ @@ -97,7 +100,7 @@ static void load_param_2_32(codeblock_t *block, uint32_t param) #endif addlong(param); } -static void load_param_2_reg_32(int reg) +static inline void load_param_2_reg_32(int reg) { #if WIN64 if (reg & 8) @@ -111,7 +114,7 @@ static void load_param_2_reg_32(int reg) addbyte(0xc0 | REG_ESI | (reg << 3)); #endif } -static void load_param_2_64(codeblock_t *block, uint64_t param) +static inline void load_param_2_64(codeblock_t *block, uint64_t param) { addbyte(0x48); #if WIN64 @@ -122,7 +125,7 @@ static void load_param_2_64(codeblock_t *block, uint64_t param) addquad(param); } -static void load_param_3_reg_32(int reg) +static inline void load_param_3_reg_32(int reg) { if (reg & 8) { @@ -149,7 +152,7 @@ static void load_param_3_reg_32(int reg) #endif } } -static void load_param_3_reg_64(int reg) +static inline void load_param_3_reg_64(int reg) { if (reg & 8) { @@ -177,7 +180,7 @@ static void load_param_3_reg_64(int reg) } } -static void CALL_FUNC(uintptr_t func) +static inline void CALL_FUNC(uintptr_t func) { codegen_reg_loaded[0] = codegen_reg_loaded[1] = codegen_reg_loaded[2] = codegen_reg_loaded[3] = 0; codegen_reg_loaded[4] = codegen_reg_loaded[5] = codegen_reg_loaded[6] = codegen_reg_loaded[7] = 0; @@ -189,14 +192,13 @@ static void CALL_FUNC(uintptr_t func) addbyte(0xd0); } -static void RELEASE_REG(int host_reg) +static inline void RELEASE_REG(int host_reg) { } -static int LOAD_REG_B(int reg) +static inline int LOAD_REG_B(int reg) { int host_reg = reg & 3; -// host_reg_mapping[host_reg] = reg; if (!codegen_reg_loaded[reg & 3]) { @@ -213,10 +215,9 @@ static int LOAD_REG_B(int reg) return host_reg | 8; } -static int LOAD_REG_W(int reg) +static inline int LOAD_REG_W(int reg) { int host_reg = reg; -// host_reg_mapping[host_reg] = reg; if (!codegen_reg_loaded[reg & 7]) { @@ -230,10 +231,9 @@ static int LOAD_REG_W(int reg) return host_reg | 8; } -static int LOAD_REG_L(int reg) +static inline int LOAD_REG_L(int reg) { int host_reg = reg; -// host_reg_mapping[host_reg] = reg; if (!codegen_reg_loaded[reg & 7]) { @@ -248,7 +248,7 @@ static int LOAD_REG_L(int reg) return host_reg | 8; } -static int LOAD_REG_IMM(uint32_t imm) +static inline int LOAD_REG_IMM(uint32_t imm) { int host_reg = REG_EBX; @@ -258,7 +258,7 @@ static int LOAD_REG_IMM(uint32_t imm) return host_reg; } -static void STORE_REG_TARGET_B_RELEASE(int host_reg, int guest_reg) +static inline void STORE_REG_TARGET_B_RELEASE(int host_reg, int guest_reg) { int dest_reg = LOAD_REG_L(guest_reg & 3) & 7; @@ -359,7 +359,7 @@ static void STORE_REG_TARGET_B_RELEASE(int host_reg, int guest_reg) } } } -static void STORE_REG_TARGET_W_RELEASE(int host_reg, int guest_reg) +static inline void STORE_REG_TARGET_W_RELEASE(int host_reg, int guest_reg) { int dest_reg = LOAD_REG_L(guest_reg & 7) & 7; @@ -387,7 +387,7 @@ static void STORE_REG_TARGET_W_RELEASE(int host_reg, int guest_reg) addbyte(cpu_state_offset(regs[guest_reg & 7].w)); } } -static void STORE_REG_TARGET_L_RELEASE(int host_reg, int guest_reg) +static inline void STORE_REG_TARGET_L_RELEASE(int host_reg, int guest_reg) { if (host_reg & 8) { @@ -410,7 +410,7 @@ static void STORE_REG_TARGET_L_RELEASE(int host_reg, int guest_reg) } } -static void STORE_REG_B_RELEASE(int host_reg) +static inline void STORE_REG_B_RELEASE(int host_reg) { if (host_reg & 0x10) { @@ -428,7 +428,7 @@ static void STORE_REG_B_RELEASE(int host_reg) addbyte(cpu_state_offset(regs[host_reg & 7].b)); } } -static void STORE_REG_W_RELEASE(int host_reg) +static inline void STORE_REG_W_RELEASE(int host_reg) { addbyte(0x66); /*MOVW [reg],host_reg*/ addbyte(0x44); @@ -436,7 +436,7 @@ static void STORE_REG_W_RELEASE(int host_reg) addbyte(0x45 | ((host_reg & 7) << 3)); addbyte(cpu_state_offset(regs[host_reg & 7].w)); } -static void STORE_REG_L_RELEASE(int host_reg) +static inline void STORE_REG_L_RELEASE(int host_reg) { addbyte(0x44); /*MOVL [reg],host_reg*/ addbyte(0x89); @@ -444,7 +444,7 @@ static void STORE_REG_L_RELEASE(int host_reg) addbyte(cpu_state_offset(regs[host_reg & 7].l)); } -static void STORE_IMM_REG_B(int reg, uint8_t val) +static inline void STORE_IMM_REG_B(int reg, uint8_t val) { if (reg & 4) { @@ -476,7 +476,7 @@ static void STORE_IMM_REG_B(int reg, uint8_t val) addbyte(cpu_state_offset(regs[reg & 7].b)); } } -static void STORE_IMM_REG_W(int reg, uint16_t val) +static inline void STORE_IMM_REG_W(int reg, uint16_t val) { addbyte(0x66); /*MOVW reg, imm*/ addbyte(0x41); @@ -488,7 +488,7 @@ static void STORE_IMM_REG_W(int reg, uint16_t val) addbyte(0x45 | (reg << 3)); addbyte(cpu_state_offset(regs[reg & 7].w)); } -static void STORE_IMM_REG_L(int reg, uint32_t val) +static inline void STORE_IMM_REG_L(int reg, uint32_t val) { addbyte(0x41); /*MOVL reg, imm*/ addbyte(0xb8 | reg); @@ -499,7 +499,7 @@ static void STORE_IMM_REG_L(int reg, uint32_t val) addbyte(cpu_state_offset(regs[reg & 7].l)); } -static void STORE_IMM_ADDR_L(uintptr_t addr, uint32_t val) +static inline void STORE_IMM_ADDR_L(uintptr_t addr, uint32_t val) { if (addr >= (uintptr_t)&cpu_state && addr < ((uintptr_t)&cpu_state)+0x100) { @@ -533,7 +533,6 @@ static void STORE_IMM_ADDR_L(uintptr_t addr, uint32_t val) static x86seg *FETCH_EA_16(x86seg *op_ea_seg, uint32_t fetchdat, int op_ssegs, uint32_t *op_pc) { int mod = (fetchdat >> 6) & 3; - int reg = (fetchdat >> 3) & 7; int rm = fetchdat & 7; if (!mod && rm == 6) @@ -655,7 +654,6 @@ static x86seg *FETCH_EA_16(x86seg *op_ea_seg, uint32_t fetchdat, int op_ssegs, u static x86seg *FETCH_EA_32(x86seg *op_ea_seg, uint32_t fetchdat, int op_ssegs, uint32_t *op_pc, int stack_offset) { int mod = (fetchdat >> 6) & 3; - int reg = (fetchdat >> 3) & 7; int rm = fetchdat & 7; uint32_t new_eaaddr; @@ -847,7 +845,7 @@ static x86seg *FETCH_EA_32(x86seg *op_ea_seg, uint32_t fetchdat, int op_ssegs, u return op_ea_seg; } -static x86seg *FETCH_EA(x86seg *op_ea_seg, uint32_t fetchdat, int op_ssegs, uint32_t *op_pc, uint32_t op_32) +static inline x86seg *FETCH_EA(x86seg *op_ea_seg, uint32_t fetchdat, int op_ssegs, uint32_t *op_pc, uint32_t op_32) { if (op_32 & 0x200) return FETCH_EA_32(op_ea_seg, fetchdat, op_ssegs, op_pc, 0); @@ -856,7 +854,7 @@ static x86seg *FETCH_EA(x86seg *op_ea_seg, uint32_t fetchdat, int op_ssegs, uint -static void CHECK_SEG_READ(x86seg *seg) +static inline void CHECK_SEG_READ(x86seg *seg) { /*Segments always valid in real/V86 mode*/ if (!(cr0 & 1) || (eflags & VM_FLAG)) @@ -866,13 +864,15 @@ static void CHECK_SEG_READ(x86seg *seg) return; if (seg->checked) return; + if ((seg == &_ds) && codegen_flat_ds) + return; if (IS_32_ADDR(&seg->base)) { addbyte(0x83); /*CMP seg->base, -1*/ addbyte(0x3c); addbyte(0x25); - addlong((uint32_t)&seg->base); + addlong((uint32_t)(uintptr_t)&seg->base); addbyte(-1); } else @@ -890,7 +890,7 @@ static void CHECK_SEG_READ(x86seg *seg) seg->checked = 1; } -static void CHECK_SEG_WRITE(x86seg *seg) +static inline void CHECK_SEG_WRITE(x86seg *seg) { /*Segments always valid in real/V86 mode*/ if (!(cr0 & 1) || (eflags & VM_FLAG)) @@ -900,13 +900,15 @@ static void CHECK_SEG_WRITE(x86seg *seg) return; if (seg->checked) return; + if ((seg == &_ds) && codegen_flat_ds) + return; if (IS_32_ADDR(&seg->base)) { addbyte(0x83); /*CMP seg->base, -1*/ addbyte(0x3c); addbyte(0x25); - addlong((uint32_t)&seg->base); + addlong((uint32_t)(uintptr_t)&seg->base); addbyte(-1); } else @@ -924,12 +926,15 @@ static void CHECK_SEG_WRITE(x86seg *seg) seg->checked = 1; } -static void CHECK_SEG_LIMITS(x86seg *seg, int end_offset) +static inline void CHECK_SEG_LIMITS(x86seg *seg, int end_offset) { + if ((seg == &_ds && codegen_flat_ds) || (seg == &_ss && codegen_flat_ss)) + return; + if (IS_32_ADDR(&seg->base)) { addbyte(0xb8 | REG_ESI); /*MOV ESI, &addr*/ - addlong((uint32_t)seg); + addlong((uint32_t)(uintptr_t)seg); } else { @@ -960,14 +965,19 @@ static void CHECK_SEG_LIMITS(x86seg *seg, int end_offset) } } -static void MEM_LOAD_ADDR_EA_B(x86seg *seg) +static inline void MEM_LOAD_ADDR_EA_B(x86seg *seg) { - if (IS_32_ADDR(&seg->base)) + if ((seg == &_ds && codegen_flat_ds) || (seg == &_ss && codegen_flat_ss)) + { + addbyte(0x31); /*XOR ECX, ECX*/ + addbyte(0xc9); + } + else if (IS_32_ADDR(&seg->base)) { addbyte(0x8b); /*MOVL ECX, seg->base*/ addbyte(0x0c); addbyte(0x25); - addlong((uint32_t)&seg->base); + addlong((uint32_t)(uintptr_t)&seg->base); } else { @@ -993,7 +1003,7 @@ static void MEM_LOAD_ADDR_EA_B(x86seg *seg) addbyte(0x8b); addbyte(0x34); addbyte(0xf5); - addlong((uint32_t)readlookup2); + addlong((uint32_t)(uintptr_t)readlookup2); } else { @@ -1018,24 +1028,29 @@ static void MEM_LOAD_ADDR_EA_B(x86seg *seg) /*slowpath:*/ load_param_1_reg_32(REG_ECX); load_param_2_reg_32(REG_EAX); - call_long(readmemb386l); + call_long((uintptr_t)readmemb386l); addbyte(0x80); /*CMP abrt, 0*/ addbyte(0x7d); - addbyte(cpu_state_offset(abrt)); + addbyte((uint8_t)cpu_state_offset(abrt)); addbyte(0); addbyte(0x0f); /*JNE end*/ addbyte(0x85); addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); /*done:*/ } -static void MEM_LOAD_ADDR_EA_W(x86seg *seg) +static inline void MEM_LOAD_ADDR_EA_W(x86seg *seg) { - if (IS_32_ADDR(&seg->base)) + if ((seg == &_ds && codegen_flat_ds) || (seg == &_ss && codegen_flat_ss)) + { + addbyte(0x31); /*XOR ECX, ECX*/ + addbyte(0xc9); + } + else if (IS_32_ADDR(&seg->base)) { addbyte(0x8b); /*MOVL ECX, seg->base*/ addbyte(0x0c); addbyte(0x25); - addlong((uint32_t)&seg->base); + addlong((uint32_t)(uintptr_t)&seg->base); } else { @@ -1049,16 +1064,14 @@ static void MEM_LOAD_ADDR_EA_W(x86seg *seg) addbyte(0x8d); addbyte(0x34); addbyte(0x08); - addbyte(0x67); /*LEA EDI, 1[ESI]*/ - addbyte(0x8d); - addbyte(0x7e); - addbyte(0x01); + addbyte(0x89); /*MOV EDI, ESI*/ + addbyte(0xf7); addbyte(0xc1); /*SHR ESI, 12*/ addbyte(0xe8 | REG_ESI); addbyte(12); - addbyte(0xf7); /*TEST EDI, 0xfff*/ + addbyte(0xf7); /*TEST EDI, 1*/ addbyte(0xc7); - addlong(0xfff); + addlong(1); if (IS_32_ADDR(readlookup2)) { addbyte(0x67); /*MOV RSI, readlookup2[ESI*8]*/ @@ -1066,7 +1079,7 @@ static void MEM_LOAD_ADDR_EA_W(x86seg *seg) addbyte(0x8b); addbyte(0x34); addbyte(0xf5); - addlong((uint32_t)readlookup2); + addlong((uint32_t)(uintptr_t)readlookup2); } else { @@ -1078,124 +1091,52 @@ static void MEM_LOAD_ADDR_EA_W(x86seg *seg) addbyte(0x34); addbyte(0xf2); } - addbyte(0x74); /*JE slowpath*/ - addbyte(3+2+5+2); - addbyte(0x83); /*CMP ESI, -1*/ - addbyte(0xf8 | REG_ESI); - addbyte(-1); - addbyte(0x74); /*JE slowpath*/ - addbyte(5+2); - addbyte(0x66); /*MOV AX,-1[RDI+RSI]*/ - addbyte(0x8b); - addbyte(0x44); - addbyte(REG_EDI | (REG_ESI << 3)); - addbyte(-1); - addbyte(0xeb); /*JMP done*/ - addbyte(2+2+12+4+6); - /*slowpath:*/ - load_param_1_reg_32(REG_ECX); - load_param_2_reg_32(REG_EAX); - call_long(readmemwl); - addbyte(0x80); /*CMP abrt, 0*/ - addbyte(0x7d); - addbyte(cpu_state_offset(abrt)); - addbyte(0); - addbyte(0x0f); /*JNE end*/ - addbyte(0x85); - addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); - /*done:*/ -} -static void MEM_LOAD_ADDR_EA_W_OFFSET(x86seg *seg, int offset) -{ - addbyte(0x83); /*ADD EAX, offset*/ - addbyte(0xc0); - addbyte(offset); - MEM_LOAD_ADDR_EA_W(seg); -} -static void MEM_LOAD_ADDR_EA_L(x86seg *seg) -{ - if (IS_32_ADDR(&seg->base)) - { - addbyte(0x8b); /*MOVL ECX, seg->base*/ - addbyte(0x0c); - addbyte(0x25); - addlong((uint32_t)&seg->base); - } - else - { - addbyte(0x48); /*MOV RSI, &seg->base*/ - addbyte(0xb8 | REG_ESI); - addquad((uint64_t)&seg->base); - addbyte(0x8b); /*MOV ECX, [RSI]*/ - addbyte(0x0e); - } - addbyte(0x67); /*LEA ESI, (EAX,ECX)*/ - addbyte(0x8d); - addbyte(0x34); - addbyte(0x08); - addbyte(0x67); /*LEA EDI, 3[ESI]*/ - addbyte(0x8d); - addbyte(0x7e); - addbyte(0x03); - addbyte(0xc1); /*SHR ESI, 12*/ - addbyte(0xe8 | REG_ESI); - addbyte(12); - addbyte(0xf7); /*TEST EDI, 0xffc*/ - addbyte(0xc7); - addlong(0xffc); - if (IS_32_ADDR(readlookup2)) - { - addbyte(0x67); /*MOV RSI, readlookup2[ESI*8]*/ - addbyte(0x48); - addbyte(0x8b); - addbyte(0x34); - addbyte(0xf5); - addlong((uint32_t)readlookup2); - } - else - { - addbyte(0x48); /*MOV RDX, readlookup2*/ - addbyte(0xb8 | REG_EDX); - addquad((uint64_t)readlookup2); - addbyte(0x48); /*MOV RSI, [RDX+RSI*8]*/ - addbyte(0x8b); - addbyte(0x34); - addbyte(0xf2); - } - addbyte(0x74); /*JE slowpath*/ + addbyte(0x75); /*JNE slowpath*/ addbyte(3+2+4+2); addbyte(0x83); /*CMP ESI, -1*/ addbyte(0xf8 | REG_ESI); addbyte(-1); addbyte(0x74); /*JE slowpath*/ addbyte(4+2); - addbyte(0x8b); /*MOV EAX,-3[RDI+RSI]*/ - addbyte(0x44); + addbyte(0x66); /*MOV AX,[RDI+RSI]*/ + addbyte(0x8b); + addbyte(0x04); addbyte(REG_EDI | (REG_ESI << 3)); - addbyte(-3); addbyte(0xeb); /*JMP done*/ addbyte(2+2+12+4+6); /*slowpath:*/ load_param_1_reg_32(REG_ECX); load_param_2_reg_32(REG_EAX); - call_long(readmemll); + call_long((uintptr_t)readmemwl); addbyte(0x80); /*CMP abrt, 0*/ addbyte(0x7d); - addbyte(cpu_state_offset(abrt)); + addbyte((uint8_t)cpu_state_offset(abrt)); addbyte(0); addbyte(0x0f); /*JNE end*/ addbyte(0x85); addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); /*done:*/ } -static void MEM_LOAD_ADDR_EA_Q(x86seg *seg) +static inline void MEM_LOAD_ADDR_EA_W_OFFSET(x86seg *seg, int offset) { - if (IS_32_ADDR(&seg->base)) + addbyte(0x83); /*ADD EAX, offset*/ + addbyte(0xc0); + addbyte(offset); + MEM_LOAD_ADDR_EA_W(seg); +} +static inline void MEM_LOAD_ADDR_EA_L(x86seg *seg) +{ + if ((seg == &_ds && codegen_flat_ds) || (seg == &_ss && codegen_flat_ss)) + { + addbyte(0x31); /*XOR ECX, ECX*/ + addbyte(0xc9); + } + else if (IS_32_ADDR(&seg->base)) { addbyte(0x8b); /*MOVL ECX, seg->base*/ addbyte(0x0c); addbyte(0x25); - addlong((uint32_t)&seg->base); + addlong((uint32_t)(uintptr_t)&seg->base); } else { @@ -1209,16 +1150,14 @@ static void MEM_LOAD_ADDR_EA_Q(x86seg *seg) addbyte(0x8d); addbyte(0x34); addbyte(0x08); - addbyte(0x67); /*LEA EDI, 7[ESI]*/ - addbyte(0x8d); - addbyte(0x7e); - addbyte(0x07); + addbyte(0x89); /*MOV EDI, ESI*/ + addbyte(0xf7); addbyte(0xc1); /*SHR ESI, 12*/ addbyte(0xe8 | REG_ESI); addbyte(12); - addbyte(0xf7); /*TEST EDI, 0xff8*/ + addbyte(0xf7); /*TEST EDI, 3*/ addbyte(0xc7); - addlong(0xff8); + addlong(3); if (IS_32_ADDR(readlookup2)) { addbyte(0x67); /*MOV RSI, readlookup2[ESI*8]*/ @@ -1226,7 +1165,7 @@ static void MEM_LOAD_ADDR_EA_Q(x86seg *seg) addbyte(0x8b); addbyte(0x34); addbyte(0xf5); - addlong((uint32_t)readlookup2); + addlong((uint32_t)(uintptr_t)readlookup2); } else { @@ -1238,27 +1177,104 @@ static void MEM_LOAD_ADDR_EA_Q(x86seg *seg) addbyte(0x34); addbyte(0xf2); } - addbyte(0x74); /*JE slowpath*/ - addbyte(3+2+5+2); + addbyte(0x75); /*JNE slowpath*/ + addbyte(3+2+3+2); addbyte(0x83); /*CMP ESI, -1*/ addbyte(0xf8 | REG_ESI); addbyte(-1); addbyte(0x74); /*JE slowpath*/ - addbyte(5+2); - addbyte(0x48); /*MOV RAX,-7[RDI+RSI]*/ - addbyte(0x8b); - addbyte(0x44); + addbyte(3+2); + addbyte(0x8b); /*MOV EAX,[RDI+RSI]*/ + addbyte(0x04); addbyte(REG_EDI | (REG_ESI << 3)); - addbyte(-7); addbyte(0xeb); /*JMP done*/ addbyte(2+2+12+4+6); /*slowpath:*/ load_param_1_reg_32(REG_ECX); load_param_2_reg_32(REG_EAX); - call_long(readmemql); + call_long((uintptr_t)readmemll); addbyte(0x80); /*CMP abrt, 0*/ addbyte(0x7d); - addbyte(cpu_state_offset(abrt)); + addbyte((uint8_t)cpu_state_offset(abrt)); + addbyte(0); + addbyte(0x0f); /*JNE end*/ + addbyte(0x85); + addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); + /*done:*/ +} +static inline void MEM_LOAD_ADDR_EA_Q(x86seg *seg) +{ + if ((seg == &_ds && codegen_flat_ds) || (seg == &_ss && codegen_flat_ss)) + { + addbyte(0x31); /*XOR ECX, ECX*/ + addbyte(0xc9); + } + else if (IS_32_ADDR(&seg->base)) + { + addbyte(0x8b); /*MOVL ECX, seg->base*/ + addbyte(0x0c); + addbyte(0x25); + addlong((uint32_t)(uintptr_t)&seg->base); + } + else + { + addbyte(0x48); /*MOV RSI, &seg->base*/ + addbyte(0xb8 | REG_ESI); + addquad((uint64_t)&seg->base); + addbyte(0x8b); /*MOV ECX, [RSI]*/ + addbyte(0x0e); + } + addbyte(0x67); /*LEA ESI, (EAX,ECX)*/ + addbyte(0x8d); + addbyte(0x34); + addbyte(0x08); + addbyte(0x89); /*MOV EDI, ESI*/ + addbyte(0xf7); + addbyte(0xc1); /*SHR ESI, 12*/ + addbyte(0xe8 | REG_ESI); + addbyte(12); + addbyte(0xf7); /*TEST EDI, 7*/ + addbyte(0xc7); + addlong(7); + if (IS_32_ADDR(readlookup2)) + { + addbyte(0x67); /*MOV RSI, readlookup2[ESI*8]*/ + addbyte(0x48); + addbyte(0x8b); + addbyte(0x34); + addbyte(0xf5); + addlong((uint32_t)(uintptr_t)readlookup2); + } + else + { + addbyte(0x48); /*MOV RDX, readlookup2*/ + addbyte(0xb8 | REG_EDX); + addquad((uint64_t)readlookup2); + addbyte(0x48); /*MOV RSI, [RDX+RSI*8]*/ + addbyte(0x8b); + addbyte(0x34); + addbyte(0xf2); + } + addbyte(0x75); /*JNE slowpath*/ + addbyte(3+2+4+2); + addbyte(0x83); /*CMP ESI, -1*/ + addbyte(0xf8 | REG_ESI); + addbyte(-1); + addbyte(0x74); /*JE slowpath*/ + addbyte(4+2); + addbyte(0x48); /*MOV RAX,[RDI+RSI]*/ + addbyte(0x8b); + addbyte(0x04); + addbyte(REG_EDI | (REG_ESI << 3)); + addbyte(0xeb); /*JMP done*/ + addbyte(2+2+12+4+6); + /*slowpath:*/ + load_param_1_reg_32(REG_ECX); + load_param_2_reg_32(REG_EAX); + call_long((uintptr_t)readmemql); + addbyte(0x80); /*CMP abrt, 0*/ + addbyte(0x7d); + addbyte((uint8_t)cpu_state_offset(abrt)); addbyte(0); addbyte(0x0f); /*JNE end*/ addbyte(0x85); @@ -1266,26 +1282,26 @@ static void MEM_LOAD_ADDR_EA_Q(x86seg *seg) /*done:*/ } -static void MEM_LOAD_ADDR_IMM_B(x86seg *seg, uint32_t addr) +static inline void MEM_LOAD_ADDR_IMM_B(x86seg *seg, uint32_t addr) { addbyte(0xb8); /*MOV EAX, addr*/ addlong(addr); MEM_LOAD_ADDR_EA_B(seg); } -static void MEM_LOAD_ADDR_IMM_W(x86seg *seg, uint32_t addr) +static inline void MEM_LOAD_ADDR_IMM_W(x86seg *seg, uint32_t addr) { addbyte(0xb8); /*MOV EAX, addr*/ addlong(addr); MEM_LOAD_ADDR_EA_W(seg); } -static void MEM_LOAD_ADDR_IMM_L(x86seg *seg, uint32_t addr) +static inline void MEM_LOAD_ADDR_IMM_L(x86seg *seg, uint32_t addr) { addbyte(0xb8); /*MOV EAX, addr*/ addlong(addr); MEM_LOAD_ADDR_EA_L(seg); } -static void MEM_STORE_ADDR_EA_B(x86seg *seg, int host_reg) +static inline void MEM_STORE_ADDR_EA_B(x86seg *seg, int host_reg) { if (host_reg & 0x10) { @@ -1309,12 +1325,17 @@ static void MEM_STORE_ADDR_EA_B(x86seg *seg, int host_reg) addbyte(8); host_reg = 8; } - if (IS_32_ADDR(&seg->base)) + if ((seg == &_ds && codegen_flat_ds) || (seg == &_ss && codegen_flat_ss)) + { + addbyte(0x31); /*XOR ECX, ECX*/ + addbyte(0xc9); + } + else if (IS_32_ADDR(&seg->base)) { addbyte(0x8b); /*MOVL ECX, seg->base*/ addbyte(0x0c); addbyte(0x25); - addlong((uint32_t)&seg->base); + addlong((uint32_t)(uintptr_t)&seg->base); } else { @@ -1340,7 +1361,7 @@ static void MEM_STORE_ADDR_EA_B(x86seg *seg, int host_reg) addbyte(0x8b); addbyte(0x34); addbyte(0xf5); - addlong((uint32_t)writelookup2); + addlong((uint32_t)(uintptr_t)writelookup2); } else { @@ -1376,24 +1397,29 @@ static void MEM_STORE_ADDR_EA_B(x86seg *seg, int host_reg) load_param_1_reg_32(REG_ECX); load_param_2_reg_32(REG_EAX); load_param_3_reg_32(host_reg); - call_long(writememb386l); + call_long((uintptr_t)writememb386l); addbyte(0x80); /*CMP abrt, 0*/ addbyte(0x7d); - addbyte(cpu_state_offset(abrt)); + addbyte((uint8_t)cpu_state_offset(abrt)); addbyte(0); addbyte(0x0f); /*JNE end*/ addbyte(0x85); addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); /*done:*/ } -static void MEM_STORE_ADDR_EA_W(x86seg *seg, int host_reg) +static inline void MEM_STORE_ADDR_EA_W(x86seg *seg, int host_reg) { - if (IS_32_ADDR(&seg->base)) + if ((seg == &_ds && codegen_flat_ds) || (seg == &_ss && codegen_flat_ss)) + { + addbyte(0x31); /*XOR ECX, ECX*/ + addbyte(0xc9); + } + else if (IS_32_ADDR(&seg->base)) { addbyte(0x8b); /*MOVL ECX, seg->base*/ addbyte(0x0c); addbyte(0x25); - addlong((uint32_t)&seg->base); + addlong((uint32_t)(uintptr_t)&seg->base); } else { @@ -1407,16 +1433,14 @@ static void MEM_STORE_ADDR_EA_W(x86seg *seg, int host_reg) addbyte(0x8d); addbyte(0x34); addbyte(0x08); - addbyte(0x67); /*LEA EDI, 1[ESI]*/ - addbyte(0x8d); - addbyte(0x7e); - addbyte(0x01); + addbyte(0x89); /*MOV EDI, ESI*/ + addbyte(0xf7); addbyte(0xc1); /*SHR ESI, 12*/ addbyte(0xe8 | REG_ESI); addbyte(12); - addbyte(0xf7); /*TEST EDI, 0xfff*/ + addbyte(0xf7); /*TEST EDI, 1*/ addbyte(0xc7); - addlong(0xfff); + addlong(1); if (IS_32_ADDR(writelookup2)) { addbyte(0x67); /*MOV RSI, writelookup2[ESI*8]*/ @@ -1424,7 +1448,7 @@ static void MEM_STORE_ADDR_EA_W(x86seg *seg, int host_reg) addbyte(0x8b); addbyte(0x34); addbyte(0xf5); - addlong((uint32_t)writelookup2); + addlong((uint32_t)(uintptr_t)writelookup2); } else { @@ -1436,97 +1460,7 @@ static void MEM_STORE_ADDR_EA_W(x86seg *seg, int host_reg) addbyte(0x34); addbyte(0xf2); } - addbyte(0x74); /*JE slowpath*/ - addbyte(3+2+((host_reg & 8) ? 6:5)+2); - addbyte(0x83); /*CMP ESI, -1*/ - addbyte(0xf8 | REG_ESI); - addbyte(-1); - addbyte(0x74); /*JE slowpath*/ - addbyte(((host_reg & 8) ? 6:5)+2); - if (host_reg & 8) - { - addbyte(0x66); /*MOV -1[RDI+RSI],host_reg*/ - addbyte(0x44); - addbyte(0x89); - addbyte(0x44 | ((host_reg & 7) << 3)); - addbyte(REG_EDI | (REG_ESI << 3)); - addbyte(-1); - } - else - { - addbyte(0x66); /*MOV -1[RDI+RSI],host_reg*/ - addbyte(0x89); - addbyte(0x44 | (host_reg << 3)); - addbyte(REG_EDI | (REG_ESI << 3)); - addbyte(-1); - } - addbyte(0xeb); /*JMP done*/ - addbyte(2+2+3+12+4+6); - /*slowpath:*/ - load_param_1_reg_32(REG_ECX); - load_param_2_reg_32(REG_EAX); - load_param_3_reg_32(host_reg); - call_long(writememwl); - addbyte(0x80); /*CMP abrt, 0*/ - addbyte(0x7d); - addbyte(cpu_state_offset(abrt)); - addbyte(0); - addbyte(0x0f); /*JNE end*/ - addbyte(0x85); - addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); - /*done:*/ -} -static void MEM_STORE_ADDR_EA_L(x86seg *seg, int host_reg) -{ - if (IS_32_ADDR(&seg->base)) - { - addbyte(0x8b); /*MOVL ECX, seg->base*/ - addbyte(0x0c); - addbyte(0x25); - addlong((uint32_t)&seg->base); - } - else - { - addbyte(0x48); /*MOV RSI, &seg->base*/ - addbyte(0xb8 | REG_ESI); - addquad((uint64_t)&seg->base); - addbyte(0x8b); /*MOV ECX, [RSI]*/ - addbyte(0x0e); - } - addbyte(0x67); /*LEA ESI, (EAX,ECX)*/ - addbyte(0x8d); - addbyte(0x34); - addbyte(0x08); - addbyte(0x67); /*LEA EDI, 3[ESI]*/ - addbyte(0x8d); - addbyte(0x7e); - addbyte(0x03); - addbyte(0xc1); /*SHR ESI, 12*/ - addbyte(0xe8 | REG_ESI); - addbyte(12); - addbyte(0xf7); /*TEST EDI, 0xffc*/ - addbyte(0xc7); - addlong(0xffc); - if (IS_32_ADDR(writelookup2)) - { - addbyte(0x67); /*MOV RSI, writelookup2[ESI*8]*/ - addbyte(0x48); - addbyte(0x8b); - addbyte(0x34); - addbyte(0xf5); - addlong((uint32_t)writelookup2); - } - else - { - addbyte(0x48); /*MOV RDX, writelookup2*/ - addbyte(0xb8 | REG_EDX); - addquad((uint64_t)writelookup2); - addbyte(0x48); /*MOV RSI, [RDX+RSI*8]*/ - addbyte(0x8b); - addbyte(0x34); - addbyte(0xf2); - } - addbyte(0x74); /*JE slowpath*/ + addbyte(0x75); /*JNE slowpath*/ addbyte(3+2+((host_reg & 8) ? 5:4)+2); addbyte(0x83); /*CMP ESI, -1*/ addbyte(0xf8 | REG_ESI); @@ -1535,18 +1469,18 @@ static void MEM_STORE_ADDR_EA_L(x86seg *seg, int host_reg) addbyte(((host_reg & 8) ? 5:4)+2); if (host_reg & 8) { - addbyte(0x44); /*MOV -3[RDI+RSI],host_reg*/ + addbyte(0x66); /*MOV [RDI+RSI],host_reg*/ + addbyte(0x44); addbyte(0x89); - addbyte(0x44 | ((host_reg & 7) << 3)); + addbyte(0x04 | ((host_reg & 7) << 3)); addbyte(REG_EDI | (REG_ESI << 3)); - addbyte(-3); } else { - addbyte(0x89); /*MOV -3[RDI+RSI],host_reg*/ - addbyte(0x44 | (host_reg << 3)); + addbyte(0x66); /*MOV [RDI+RSI],host_reg*/ + addbyte(0x89); + addbyte(0x04 | (host_reg << 3)); addbyte(REG_EDI | (REG_ESI << 3)); - addbyte(-3); } addbyte(0xeb); /*JMP done*/ addbyte(2+2+3+12+4+6); @@ -1554,24 +1488,29 @@ static void MEM_STORE_ADDR_EA_L(x86seg *seg, int host_reg) load_param_1_reg_32(REG_ECX); load_param_2_reg_32(REG_EAX); load_param_3_reg_32(host_reg); - call_long(writememll); + call_long((uintptr_t)writememwl); addbyte(0x80); /*CMP abrt, 0*/ addbyte(0x7d); - addbyte(cpu_state_offset(abrt)); + addbyte((uint8_t)cpu_state_offset(abrt)); addbyte(0); addbyte(0x0f); /*JNE end*/ addbyte(0x85); addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); /*done:*/ } -static void MEM_STORE_ADDR_EA_Q(x86seg *seg, int host_reg, int host_reg2) +static inline void MEM_STORE_ADDR_EA_L(x86seg *seg, int host_reg) { - if (IS_32_ADDR(&seg->base)) + if ((seg == &_ds && codegen_flat_ds) || (seg == &_ss && codegen_flat_ss)) + { + addbyte(0x31); /*XOR ECX, ECX*/ + addbyte(0xc9); + } + else if (IS_32_ADDR(&seg->base)) { addbyte(0x8b); /*MOVL ECX, seg->base*/ addbyte(0x0c); addbyte(0x25); - addlong((uint32_t)&seg->base); + addlong((uint32_t)(uintptr_t)&seg->base); } else { @@ -1585,16 +1524,14 @@ static void MEM_STORE_ADDR_EA_Q(x86seg *seg, int host_reg, int host_reg2) addbyte(0x8d); addbyte(0x34); addbyte(0x08); - addbyte(0x67); /*LEA EDI, 7[ESI]*/ - addbyte(0x8d); - addbyte(0x7e); - addbyte(0x07); + addbyte(0x89); /*MOV EDI, ESI*/ + addbyte(0xf7); addbyte(0xc1); /*SHR ESI, 12*/ addbyte(0xe8 | REG_ESI); addbyte(12); - addbyte(0xf7); /*TEST EDI, 0xff8*/ + addbyte(0xf7); /*TEST EDI, 3*/ addbyte(0xc7); - addlong(0xff8); + addlong(3); if (IS_32_ADDR(writelookup2)) { addbyte(0x67); /*MOV RSI, writelookup2[ESI*8]*/ @@ -1602,7 +1539,7 @@ static void MEM_STORE_ADDR_EA_Q(x86seg *seg, int host_reg, int host_reg2) addbyte(0x8b); addbyte(0x34); addbyte(0xf5); - addlong((uint32_t)writelookup2); + addlong((uint32_t)(uintptr_t)writelookup2); } else { @@ -1614,28 +1551,115 @@ static void MEM_STORE_ADDR_EA_Q(x86seg *seg, int host_reg, int host_reg2) addbyte(0x34); addbyte(0xf2); } - addbyte(0x74); /*JE slowpath*/ - addbyte(3+2+5+2); + addbyte(0x75); /*JNE slowpath*/ + addbyte(3+2+((host_reg & 8) ? 4:3)+2); addbyte(0x83); /*CMP ESI, -1*/ addbyte(0xf8 | REG_ESI); addbyte(-1); addbyte(0x74); /*JE slowpath*/ - addbyte(5+2); + addbyte(((host_reg & 8) ? 4:3)+2); if (host_reg & 8) { - addbyte(0x4c); /*MOV -7[RDI+RSI],host_reg*/ + addbyte(0x44); /*MOV -3[RDI+RSI],host_reg*/ addbyte(0x89); - addbyte(0x44 | ((host_reg & 7) << 3)); + addbyte(0x04 | ((host_reg & 7) << 3)); addbyte(REG_EDI | (REG_ESI << 3)); - addbyte(-7); } else { - addbyte(0x48); /*MOV -3[RDI+RSI],host_reg*/ - addbyte(0x89); - addbyte(0x44 | (host_reg << 3)); + addbyte(0x89); /*MOV -3[RDI+RSI],host_reg*/ + addbyte(0x04 | (host_reg << 3)); + addbyte(REG_EDI | (REG_ESI << 3)); + } + addbyte(0xeb); /*JMP done*/ + addbyte(2+2+3+12+4+6); + /*slowpath:*/ + load_param_1_reg_32(REG_ECX); + load_param_2_reg_32(REG_EAX); + load_param_3_reg_32(host_reg); + call_long((uintptr_t)writememll); + addbyte(0x80); /*CMP abrt, 0*/ + addbyte(0x7d); + addbyte((uint8_t)cpu_state_offset(abrt)); + addbyte(0); + addbyte(0x0f); /*JNE end*/ + addbyte(0x85); + addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); + /*done:*/ +} +static inline void MEM_STORE_ADDR_EA_Q(x86seg *seg, int host_reg, int host_reg2) +{ + if ((seg == &_ds && codegen_flat_ds) || (seg == &_ss && codegen_flat_ss)) + { + addbyte(0x31); /*XOR ECX, ECX*/ + addbyte(0xc9); + } + else if (IS_32_ADDR(&seg->base)) + { + addbyte(0x8b); /*MOVL ECX, seg->base*/ + addbyte(0x0c); + addbyte(0x25); + addlong((uint32_t)(uintptr_t)&seg->base); + } + else + { + addbyte(0x48); /*MOV RSI, &seg->base*/ + addbyte(0xb8 | REG_ESI); + addquad((uint64_t)&seg->base); + addbyte(0x8b); /*MOV ECX, [RSI]*/ + addbyte(0x0e); + } + addbyte(0x67); /*LEA ESI, (EAX,ECX)*/ + addbyte(0x8d); + addbyte(0x34); + addbyte(0x08); + addbyte(0x89); /*MOV EDI, ESI*/ + addbyte(0xf7); + addbyte(0xc1); /*SHR ESI, 12*/ + addbyte(0xe8 | REG_ESI); + addbyte(12); + addbyte(0xf7); /*TEST EDI, 7*/ + addbyte(0xc7); + addlong(7); + if (IS_32_ADDR(writelookup2)) + { + addbyte(0x67); /*MOV RSI, writelookup2[ESI*8]*/ + addbyte(0x48); + addbyte(0x8b); + addbyte(0x34); + addbyte(0xf5); + addlong((uint32_t)(uintptr_t)writelookup2); + } + else + { + addbyte(0x48); /*MOV RDX, writelookup2*/ + addbyte(0xb8 | REG_EDX); + addquad((uint64_t)writelookup2); + addbyte(0x48); /*MOV RSI, [RDX+RSI*8]*/ + addbyte(0x8b); + addbyte(0x34); + addbyte(0xf2); + } + addbyte(0x75); /*JNE slowpath*/ + addbyte(3+2+4+2); + addbyte(0x83); /*CMP ESI, -1*/ + addbyte(0xf8 | REG_ESI); + addbyte(-1); + addbyte(0x74); /*JE slowpath*/ + addbyte(4+2); + if (host_reg & 8) + { + addbyte(0x4c); /*MOV [RDI+RSI],host_reg*/ + addbyte(0x89); + addbyte(0x04 | ((host_reg & 7) << 3)); + addbyte(REG_EDI | (REG_ESI << 3)); + } + else + { + addbyte(0x48); /*MOV [RDI+RSI],host_reg*/ + addbyte(0x89); + addbyte(0x04 | (host_reg << 3)); addbyte(REG_EDI | (REG_ESI << 3)); - addbyte(-7); } addbyte(0xeb); /*JMP done*/ addbyte(2+2+3+12+4+6); @@ -1643,10 +1667,10 @@ static void MEM_STORE_ADDR_EA_Q(x86seg *seg, int host_reg, int host_reg2) load_param_1_reg_32(REG_ECX); load_param_2_reg_32(REG_EAX); load_param_3_reg_64(host_reg); - call_long(writememql); + call_long((uintptr_t)writememql); addbyte(0x80); /*CMP abrt, 0*/ addbyte(0x7d); - addbyte(cpu_state_offset(abrt)); + addbyte((uint8_t)cpu_state_offset(abrt)); addbyte(0); addbyte(0x0f); /*JNE end*/ addbyte(0x85); @@ -1654,26 +1678,26 @@ static void MEM_STORE_ADDR_EA_Q(x86seg *seg, int host_reg, int host_reg2) /*done:*/ } -static void MEM_STORE_ADDR_IMM_B(x86seg *seg, uint32_t addr, int host_reg) +static inline void MEM_STORE_ADDR_IMM_B(x86seg *seg, uint32_t addr, int host_reg) { addbyte(0xb8); /*MOV EAX, addr*/ addlong(addr); MEM_STORE_ADDR_EA_B(seg, host_reg); } -static void MEM_STORE_ADDR_IMM_W(x86seg *seg, uint32_t addr, int host_reg) +static inline void MEM_STORE_ADDR_IMM_W(x86seg *seg, uint32_t addr, int host_reg) { addbyte(0xb8); /*MOV EAX, addr*/ addlong(addr); MEM_STORE_ADDR_EA_W(seg, host_reg); } -static void MEM_STORE_ADDR_IMM_L(x86seg *seg, uint32_t addr, int host_reg) +static inline void MEM_STORE_ADDR_IMM_L(x86seg *seg, uint32_t addr, int host_reg) { addbyte(0xb8); /*MOV EAX, addr*/ addlong(addr); MEM_STORE_ADDR_EA_L(seg, host_reg); } -static void STORE_HOST_REG_ADDR_BL(uintptr_t addr, int host_reg) +static inline void STORE_HOST_REG_ADDR_BL(uintptr_t addr, int host_reg) { int temp_reg = REG_ECX; @@ -1703,7 +1727,7 @@ static void STORE_HOST_REG_ADDR_BL(uintptr_t addr, int host_reg) { addbyte(0x89); /*MOV addr, temp_reg*/ addbyte(0x45 | (temp_reg << 3)); - addbyte((uint32_t)addr - (uint32_t)&cpu_state - 128); + addbyte((uint32_t)addr - (uint32_t)(uintptr_t)&cpu_state - 128); } else if (IS_32_ADDR(addr)) { @@ -1721,7 +1745,7 @@ static void STORE_HOST_REG_ADDR_BL(uintptr_t addr, int host_reg) addbyte(0x06 | (temp_reg << 3)); } } -static void STORE_HOST_REG_ADDR_WL(uintptr_t addr, int host_reg) +static inline void STORE_HOST_REG_ADDR_WL(uintptr_t addr, int host_reg) { int temp_reg = REG_ECX; @@ -1737,7 +1761,7 @@ static void STORE_HOST_REG_ADDR_WL(uintptr_t addr, int host_reg) { addbyte(0x89); /*MOV addr, temp_reg*/ addbyte(0x45 | (temp_reg << 3)); - addbyte((uint32_t)addr - (uint32_t)&cpu_state - 128); + addbyte((uint32_t)addr - (uint32_t)(uintptr_t)&cpu_state - 128); } else if (IS_32_ADDR(addr)) { @@ -1755,7 +1779,7 @@ static void STORE_HOST_REG_ADDR_WL(uintptr_t addr, int host_reg) addbyte(0x06 | (temp_reg << 3)); } } -static void STORE_HOST_REG_ADDR_W(uintptr_t addr, int host_reg) +static inline void STORE_HOST_REG_ADDR_W(uintptr_t addr, int host_reg) { if (addr >= (uintptr_t)&cpu_state && addr < ((uintptr_t)&cpu_state)+0x100) { @@ -1764,7 +1788,7 @@ static void STORE_HOST_REG_ADDR_W(uintptr_t addr, int host_reg) addbyte(0x44); addbyte(0x89); addbyte(0x45 | ((host_reg & 7) << 3)); - addbyte((uint32_t)addr - (uint32_t)&cpu_state - 128); + addbyte((uint32_t)addr - (uint32_t)(uintptr_t)&cpu_state - 128); } else if (IS_32_ADDR(addr)) { @@ -1789,7 +1813,7 @@ static void STORE_HOST_REG_ADDR_W(uintptr_t addr, int host_reg) addbyte(0x06 | ((host_reg & 7) << 3)); } } -static void STORE_HOST_REG_ADDR(uintptr_t addr, int host_reg) +static inline void STORE_HOST_REG_ADDR(uintptr_t addr, int host_reg) { if (addr >= (uintptr_t)&cpu_state && addr < ((uintptr_t)&cpu_state)+0x100) { @@ -1797,7 +1821,7 @@ static void STORE_HOST_REG_ADDR(uintptr_t addr, int host_reg) addbyte(0x44); addbyte(0x89); /*MOVL [addr],host_reg*/ addbyte(0x45 | ((host_reg & 7) << 3)); - addbyte((uint32_t)addr - (uint32_t)&cpu_state - 128); + addbyte((uint32_t)addr - (uint32_t)(uintptr_t)&cpu_state - 128); } else if (IS_32_ADDR(addr)) { @@ -1821,7 +1845,7 @@ static void STORE_HOST_REG_ADDR(uintptr_t addr, int host_reg) } } -static void AND_HOST_REG_B(int dst_reg, int src_reg) +static inline void AND_HOST_REG_B(int dst_reg, int src_reg) { if (dst_reg & src_reg & 8) { @@ -1944,7 +1968,7 @@ static void AND_HOST_REG_B(int dst_reg, int src_reg) } } } -static void AND_HOST_REG_W(int dst_reg, int src_reg) +static inline void AND_HOST_REG_W(int dst_reg, int src_reg) { if (dst_reg & src_reg & 8) { @@ -1974,7 +1998,7 @@ static void AND_HOST_REG_W(int dst_reg, int src_reg) addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); } } -static void AND_HOST_REG_L(int dst_reg, int src_reg) +static inline void AND_HOST_REG_L(int dst_reg, int src_reg) { if (dst_reg & src_reg & 8) { @@ -2000,7 +2024,7 @@ static void AND_HOST_REG_L(int dst_reg, int src_reg) addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); } } -static void AND_HOST_REG_IMM(int host_reg, uint32_t imm) +static inline void AND_HOST_REG_IMM(int host_reg, uint32_t imm) { if (host_reg & 0x10) { @@ -2021,7 +2045,7 @@ static void AND_HOST_REG_IMM(int host_reg, uint32_t imm) } } -static int TEST_HOST_REG_B(int dst_reg, int src_reg) +static inline int TEST_HOST_REG_B(int dst_reg, int src_reg) { if (dst_reg & 8) { @@ -2036,7 +2060,7 @@ static int TEST_HOST_REG_B(int dst_reg, int src_reg) return dst_reg & ~0x10; } -static int TEST_HOST_REG_W(int dst_reg, int src_reg) +static inline int TEST_HOST_REG_W(int dst_reg, int src_reg) { if (dst_reg & 8) { @@ -2051,7 +2075,7 @@ static int TEST_HOST_REG_W(int dst_reg, int src_reg) return dst_reg; } -static int TEST_HOST_REG_L(int dst_reg, int src_reg) +static inline int TEST_HOST_REG_L(int dst_reg, int src_reg) { if (dst_reg & 8) { @@ -2066,7 +2090,7 @@ static int TEST_HOST_REG_L(int dst_reg, int src_reg) return dst_reg; } -static int TEST_HOST_REG_IMM(int host_reg, uint32_t imm) +static inline int TEST_HOST_REG_IMM(int host_reg, uint32_t imm) { if (host_reg & 8) { @@ -2092,7 +2116,7 @@ static int TEST_HOST_REG_IMM(int host_reg, uint32_t imm) return host_reg; } -static void OR_HOST_REG_B(int dst_reg, int src_reg) +static inline void OR_HOST_REG_B(int dst_reg, int src_reg) { if (dst_reg & src_reg & 8) { @@ -2214,7 +2238,7 @@ static void OR_HOST_REG_B(int dst_reg, int src_reg) } } } -static void OR_HOST_REG_W(int dst_reg, int src_reg) +static inline void OR_HOST_REG_W(int dst_reg, int src_reg) { if (dst_reg & src_reg & 8) { @@ -2244,7 +2268,7 @@ static void OR_HOST_REG_W(int dst_reg, int src_reg) addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); } } -static void OR_HOST_REG_L(int dst_reg, int src_reg) +static inline void OR_HOST_REG_L(int dst_reg, int src_reg) { if (dst_reg & src_reg & 8) { @@ -2270,7 +2294,7 @@ static void OR_HOST_REG_L(int dst_reg, int src_reg) addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); } } -static void OR_HOST_REG_IMM(int host_reg, uint32_t imm) +static inline void OR_HOST_REG_IMM(int host_reg, uint32_t imm) { if (host_reg & 0x10) { @@ -2293,10 +2317,9 @@ static void OR_HOST_REG_IMM(int host_reg, uint32_t imm) addbyte(0xc8 | (host_reg & 7)); addlong(imm); } -// fatal("OR to bad register\n"); } -static void XOR_HOST_REG_B(int dst_reg, int src_reg) +static inline void XOR_HOST_REG_B(int dst_reg, int src_reg) { if (dst_reg & src_reg & 8) { @@ -2418,7 +2441,7 @@ static void XOR_HOST_REG_B(int dst_reg, int src_reg) } } } -static void XOR_HOST_REG_W(int dst_reg, int src_reg) +static inline void XOR_HOST_REG_W(int dst_reg, int src_reg) { if (dst_reg & src_reg & 8) { @@ -2448,7 +2471,7 @@ static void XOR_HOST_REG_W(int dst_reg, int src_reg) addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); } } -static void XOR_HOST_REG_L(int dst_reg, int src_reg) +static inline void XOR_HOST_REG_L(int dst_reg, int src_reg) { if (dst_reg & src_reg & 8) { @@ -2474,7 +2497,7 @@ static void XOR_HOST_REG_L(int dst_reg, int src_reg) addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); } } -static void XOR_HOST_REG_IMM(int host_reg, uint32_t imm) +static inline void XOR_HOST_REG_IMM(int host_reg, uint32_t imm) { if (host_reg & 0x10) { @@ -2497,10 +2520,9 @@ static void XOR_HOST_REG_IMM(int host_reg, uint32_t imm) addbyte(0xf0 | (host_reg & 7)); addlong(imm); } -// fatal("XOR to bad register\n"); } -static void ADD_HOST_REG_B(int dst_reg, int src_reg) +static inline void ADD_HOST_REG_B(int dst_reg, int src_reg) { if (dst_reg & src_reg & 8) { @@ -2594,7 +2616,7 @@ static void ADD_HOST_REG_B(int dst_reg, int src_reg) else fatal("!(dst_reg & src_reg & 8)\n"); } -static void ADD_HOST_REG_W(int dst_reg, int src_reg) +static inline void ADD_HOST_REG_W(int dst_reg, int src_reg) { if (dst_reg & src_reg & 8) { @@ -2620,7 +2642,7 @@ static void ADD_HOST_REG_W(int dst_reg, int src_reg) else fatal("!(dst_reg & src_reg & 8)\n"); } -static void ADD_HOST_REG_L(int dst_reg, int src_reg) +static inline void ADD_HOST_REG_L(int dst_reg, int src_reg) { if (dst_reg & src_reg & 8) { @@ -2644,7 +2666,7 @@ static void ADD_HOST_REG_L(int dst_reg, int src_reg) fatal("!(dst_reg & src_reg & 8)\n"); } -static void SUB_HOST_REG_B(int dst_reg, int src_reg) +static inline void SUB_HOST_REG_B(int dst_reg, int src_reg) { if (dst_reg & src_reg & 8) { @@ -2765,10 +2787,8 @@ static void SUB_HOST_REG_B(int dst_reg, int src_reg) addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); } } - -// fatal("!(dst_reg & src_reg & 8) subb %i %i\n", dst_reg, src_reg); } -static void SUB_HOST_REG_W(int dst_reg, int src_reg) +static inline void SUB_HOST_REG_W(int dst_reg, int src_reg) { if (dst_reg & src_reg & 8) { @@ -2798,7 +2818,7 @@ static void SUB_HOST_REG_W(int dst_reg, int src_reg) addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); } } -static void SUB_HOST_REG_L(int dst_reg, int src_reg) +static inline void SUB_HOST_REG_L(int dst_reg, int src_reg) { if (dst_reg & src_reg & 8) { @@ -2825,7 +2845,7 @@ static void SUB_HOST_REG_L(int dst_reg, int src_reg) } } -static int CMP_HOST_REG_B(int dst_reg, int src_reg) +static inline int CMP_HOST_REG_B(int dst_reg, int src_reg) { if (dst_reg & 8) { @@ -2840,7 +2860,7 @@ static int CMP_HOST_REG_B(int dst_reg, int src_reg) return dst_reg & ~0x10; } -static int CMP_HOST_REG_W(int dst_reg, int src_reg) +static inline int CMP_HOST_REG_W(int dst_reg, int src_reg) { if (dst_reg & 8) { @@ -2855,7 +2875,7 @@ static int CMP_HOST_REG_W(int dst_reg, int src_reg) return dst_reg; } -static int CMP_HOST_REG_L(int dst_reg, int src_reg) +static inline int CMP_HOST_REG_L(int dst_reg, int src_reg) { if (dst_reg & 8) { @@ -2871,7 +2891,7 @@ static int CMP_HOST_REG_L(int dst_reg, int src_reg) return dst_reg; } -static void ADD_HOST_REG_IMM_B(int host_reg, uint8_t imm) +static inline void ADD_HOST_REG_IMM_B(int host_reg, uint8_t imm) { if (host_reg & 0x10) { @@ -2891,7 +2911,7 @@ static void ADD_HOST_REG_IMM_B(int host_reg, uint8_t imm) addbyte(imm); } } -static void ADD_HOST_REG_IMM_W(int host_reg, uint16_t imm) +static inline void ADD_HOST_REG_IMM_W(int host_reg, uint16_t imm) { addbyte(0x66); /*ADDW host_reg, imm*/ if (host_reg & 8) @@ -2900,7 +2920,7 @@ static void ADD_HOST_REG_IMM_W(int host_reg, uint16_t imm) addbyte(0xC0 | (host_reg & 7)); addword(imm); } -static void ADD_HOST_REG_IMM(int host_reg, uint32_t imm) +static inline void ADD_HOST_REG_IMM(int host_reg, uint32_t imm) { if (host_reg & 8) addbyte(0x41); @@ -2909,7 +2929,7 @@ static void ADD_HOST_REG_IMM(int host_reg, uint32_t imm) addlong(imm); } -static void SUB_HOST_REG_IMM_B(int host_reg, uint8_t imm) +static inline void SUB_HOST_REG_IMM_B(int host_reg, uint8_t imm) { if (host_reg & 0x10) { @@ -2929,7 +2949,7 @@ static void SUB_HOST_REG_IMM_B(int host_reg, uint8_t imm) addbyte(imm); } } -static void SUB_HOST_REG_IMM_W(int host_reg, uint16_t imm) +static inline void SUB_HOST_REG_IMM_W(int host_reg, uint16_t imm) { addbyte(0x66); /*SUBW host_reg, imm*/ if (host_reg & 8) @@ -2938,7 +2958,7 @@ static void SUB_HOST_REG_IMM_W(int host_reg, uint16_t imm) addbyte(0xE8 | (host_reg & 7)); addword(imm); } -static void SUB_HOST_REG_IMM(int host_reg, uint32_t imm) +static inline void SUB_HOST_REG_IMM(int host_reg, uint32_t imm) { if (host_reg & 8) addbyte(0x41); @@ -2947,7 +2967,7 @@ static void SUB_HOST_REG_IMM(int host_reg, uint32_t imm) addlong(imm); } -static int CMP_HOST_REG_IMM_B(int host_reg, uint8_t imm) +static inline int CMP_HOST_REG_IMM_B(int host_reg, uint8_t imm) { if (host_reg & 8) { @@ -2960,9 +2980,9 @@ static int CMP_HOST_REG_IMM_B(int host_reg, uint8_t imm) SUB_HOST_REG_IMM_B(host_reg, imm); - return host_reg;// & ~0x10; + return host_reg; } -static int CMP_HOST_REG_IMM_W(int host_reg, uint16_t imm) +static inline int CMP_HOST_REG_IMM_W(int host_reg, uint16_t imm) { if (host_reg & 8) { @@ -2977,7 +2997,7 @@ static int CMP_HOST_REG_IMM_W(int host_reg, uint16_t imm) return host_reg; } -static int CMP_HOST_REG_IMM_L(int host_reg, uint32_t imm) +static inline int CMP_HOST_REG_IMM_L(int host_reg, uint32_t imm) { if (host_reg & 8) { @@ -2993,13 +3013,13 @@ static int CMP_HOST_REG_IMM_L(int host_reg, uint32_t imm) return host_reg; } -static void LOAD_STACK_TO_EA(int off) +static inline void LOAD_STACK_TO_EA(int off) { if (stack32) { addbyte(0x8b); /*MOVL EAX,[ESP]*/ addbyte(0x45 | (REG_EAX << 3)); - addbyte(cpu_state_offset(regs[REG_ESP].l)); + addbyte((uint8_t)cpu_state_offset(regs[REG_ESP].l)); if (off) { addbyte(0x83); /*ADD EAX, off*/ @@ -3012,7 +3032,7 @@ static void LOAD_STACK_TO_EA(int off) addbyte(0x0f); /*MOVZX EAX,W[ESP]*/ addbyte(0xb7); addbyte(0x45 | (REG_EAX << 3)); - addbyte(cpu_state_offset(regs[REG_ESP].w)); + addbyte((uint8_t)cpu_state_offset(regs[REG_ESP].w)); if (off) { addbyte(0x66); /*ADD AX, off*/ @@ -3021,13 +3041,13 @@ static void LOAD_STACK_TO_EA(int off) } } } -static void LOAD_EBP_TO_EA(int off) +static inline void LOAD_EBP_TO_EA(int off) { if (stack32) { addbyte(0x8b); /*MOVL EAX,[EBP]*/ addbyte(0x45 | (REG_EAX << 3)); - addbyte(cpu_state_offset(regs[REG_EBP].l)); + addbyte((uint8_t)cpu_state_offset(regs[REG_EBP].l)); if (off) { addbyte(0x83); /*ADD EAX, off*/ @@ -3040,7 +3060,7 @@ static void LOAD_EBP_TO_EA(int off) addbyte(0x0f); /*MOVZX EAX,W[EBP]*/ addbyte(0xb7); addbyte(0x45 | (REG_EAX << 3)); - addbyte(cpu_state_offset(regs[REG_BP].l)); + addbyte((uint8_t)cpu_state_offset(regs[REG_BP].l)); if (off) { addbyte(0x66); /*ADD AX, off*/ @@ -3050,7 +3070,7 @@ static void LOAD_EBP_TO_EA(int off) } } -static void SP_MODIFY(int off) +static inline void SP_MODIFY(int off) { if (stack32) { @@ -3058,14 +3078,14 @@ static void SP_MODIFY(int off) { addbyte(0x83); /*ADD [ESP], off*/ addbyte(0x45); - addbyte(cpu_state_offset(regs[REG_ESP].l)); + addbyte((uint8_t)cpu_state_offset(regs[REG_ESP].l)); addbyte(off); } else { addbyte(0x81); /*ADD [ESP], off*/ addbyte(0x45); - addbyte(cpu_state_offset(regs[REG_ESP].l)); + addbyte((uint8_t)cpu_state_offset(regs[REG_ESP].l)); addlong(off); } } @@ -3076,7 +3096,7 @@ static void SP_MODIFY(int off) addbyte(0x66); /*ADD [SP], off*/ addbyte(0x83); addbyte(0x45); - addbyte(cpu_state_offset(regs[REG_ESP].w)); + addbyte((uint8_t)cpu_state_offset(regs[REG_ESP].w)); addbyte(off); } else @@ -3084,13 +3104,13 @@ static void SP_MODIFY(int off) addbyte(0x66); /*ADD [SP], off*/ addbyte(0x81); addbyte(0x45); - addbyte(cpu_state_offset(regs[REG_ESP].w)); + addbyte((uint8_t)cpu_state_offset(regs[REG_ESP].w)); addword(off); } } } -static void TEST_ZERO_JUMP_W(int host_reg, uint32_t new_pc, int taken_cycles) +static inline void TEST_ZERO_JUMP_W(int host_reg, uint32_t new_pc, int taken_cycles) { addbyte(0x66); /*CMPW host_reg, 0*/ if (host_reg & 8) @@ -3102,19 +3122,19 @@ static void TEST_ZERO_JUMP_W(int host_reg, uint32_t new_pc, int taken_cycles) addbyte(7+5+(taken_cycles ? 4 : 0)); addbyte(0xC7); /*MOVL [pc], new_pc*/ addbyte(0x45); - addbyte(cpu_state_offset(pc)); + addbyte((uint8_t)cpu_state_offset(pc)); addlong(new_pc); if (taken_cycles) { addbyte(0x83); /*SUB $codegen_block_cycles, cyclcs*/ addbyte(0x6d); - addbyte(cpu_state_offset(_cycles)); + addbyte((uint8_t)cpu_state_offset(_cycles)); addbyte(taken_cycles); } addbyte(0xe9); /*JMP end*/ addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); } -static void TEST_ZERO_JUMP_L(int host_reg, uint32_t new_pc, int taken_cycles) +static inline void TEST_ZERO_JUMP_L(int host_reg, uint32_t new_pc, int taken_cycles) { if (host_reg & 8) addbyte(0x41); @@ -3125,20 +3145,20 @@ static void TEST_ZERO_JUMP_L(int host_reg, uint32_t new_pc, int taken_cycles) addbyte(7+5+(taken_cycles ? 4 : 0)); addbyte(0xC7); /*MOVL [pc], new_pc*/ addbyte(0x45); - addbyte(cpu_state_offset(pc)); + addbyte((uint8_t)cpu_state_offset(pc)); addlong(new_pc); if (taken_cycles) { addbyte(0x83); /*SUB $codegen_block_cycles, cyclcs*/ addbyte(0x6d); - addbyte(cpu_state_offset(_cycles)); + addbyte((uint8_t)cpu_state_offset(_cycles)); addbyte(taken_cycles); } addbyte(0xe9); /*JMP end*/ addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); } -static void TEST_NONZERO_JUMP_W(int host_reg, uint32_t new_pc, int taken_cycles) +static inline void TEST_NONZERO_JUMP_W(int host_reg, uint32_t new_pc, int taken_cycles) { addbyte(0x66); /*CMPW host_reg, 0*/ if (host_reg & 8) @@ -3150,19 +3170,19 @@ static void TEST_NONZERO_JUMP_W(int host_reg, uint32_t new_pc, int taken_cycles) addbyte(7+5+(taken_cycles ? 4 : 0)); addbyte(0xC7); /*MOVL [pc], new_pc*/ addbyte(0x45); - addbyte(cpu_state_offset(pc)); + addbyte((uint8_t)cpu_state_offset(pc)); addlong(new_pc); if (taken_cycles) { addbyte(0x83); /*SUB $codegen_block_cycles, cyclcs*/ addbyte(0x6d); - addbyte(cpu_state_offset(_cycles)); + addbyte((uint8_t)cpu_state_offset(_cycles)); addbyte(taken_cycles); } addbyte(0xe9); /*JMP end*/ addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); } -static void TEST_NONZERO_JUMP_L(int host_reg, uint32_t new_pc, int taken_cycles) +static inline void TEST_NONZERO_JUMP_L(int host_reg, uint32_t new_pc, int taken_cycles) { if (host_reg & 8) addbyte(0x41); @@ -3173,41 +3193,41 @@ static void TEST_NONZERO_JUMP_L(int host_reg, uint32_t new_pc, int taken_cycles) addbyte(7+5+(taken_cycles ? 4 : 0)); addbyte(0xC7); /*MOVL [pc], new_pc*/ addbyte(0x45); - addbyte(cpu_state_offset(pc)); + addbyte((uint8_t)cpu_state_offset(pc)); addlong(new_pc); if (taken_cycles) { addbyte(0x83); /*SUB $codegen_block_cycles, cyclcs*/ addbyte(0x6d); - addbyte(cpu_state_offset(_cycles)); + addbyte((uint8_t)cpu_state_offset(_cycles)); addbyte(taken_cycles); } addbyte(0xe9); /*JMP end*/ addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); } -static int BRANCH_COND_BE(int pc_offset, uint32_t op_pc, uint32_t offset, int not) +static inline void BRANCH_COND_BE(int pc_offset, uint32_t op_pc, uint32_t offset, int not) { + uint8_t *jump1; + if (codegen_flags_changed && cpu_state.flags_op != FLAGS_UNKNOWN) { addbyte(0x83); /*CMP flags_res, 0*/ addbyte(0x7d); - addbyte(cpu_state_offset(flags_res)); + addbyte((uint8_t)cpu_state_offset(flags_res)); addbyte(0); addbyte(0x74); /*JZ +*/ } else { - CALL_FUNC(ZF_SET); + CALL_FUNC((uintptr_t)ZF_SET); addbyte(0x85); /*TEST EAX,EAX*/ addbyte(0xc0); addbyte(0x75); /*JNZ +*/ } - if (not) - addbyte(12+2+2+7+5+(timing_bt ? 8 : 0)); - else - addbyte(12+2+2); - CALL_FUNC(CF_SET); + jump1 = &codeblock[block_current].data[block_pos]; + addbyte(0); + CALL_FUNC((uintptr_t)CF_SET); addbyte(0x85); /*TEST EAX,EAX*/ addbyte(0xc0); if (not) @@ -3215,30 +3235,35 @@ static int BRANCH_COND_BE(int pc_offset, uint32_t op_pc, uint32_t offset, int no else addbyte(0x74); /*JZ +*/ addbyte(7+5+(timing_bt ? 4 : 0)); + + if (!not) + *jump1 = (uintptr_t)&codeblock[block_current].data[block_pos] - (uintptr_t)jump1 - 1; addbyte(0xC7); /*MOVL [pc], new_pc*/ addbyte(0x45); - addbyte(cpu_state_offset(pc)); + addbyte((uint8_t)cpu_state_offset(pc)); addlong(op_pc+pc_offset+offset); if (timing_bt) { addbyte(0x83); /*SUB $codegen_block_cycles, cyclcs*/ addbyte(0x6d); - addbyte(cpu_state_offset(_cycles)); + addbyte((uint8_t)cpu_state_offset(_cycles)); addbyte(timing_bt); } addbyte(0xe9); /*JMP end*/ addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); + if (not) + *jump1 = (uintptr_t)&codeblock[block_current].data[block_pos] - (uintptr_t)jump1 - 1; } -static int BRANCH_COND_L(int pc_offset, uint32_t op_pc, uint32_t offset, int not) +static inline void BRANCH_COND_L(int pc_offset, uint32_t op_pc, uint32_t offset, int not) { - CALL_FUNC(NF_SET); + CALL_FUNC((uintptr_t)NF_SET); addbyte(0x85); /*TEST EAX,EAX*/ addbyte(0xc0); addbyte(0x0f); /*SETNE BL*/ addbyte(0x95); addbyte(0xc3); - CALL_FUNC(VF_SET); + CALL_FUNC((uintptr_t)VF_SET); addbyte(0x85); /*TEST EAX,EAX*/ addbyte(0xc0); addbyte(0x0f); /*SETNE AL*/ @@ -3253,48 +3278,46 @@ static int BRANCH_COND_L(int pc_offset, uint32_t op_pc, uint32_t offset, int not addbyte(7+5+(timing_bt ? 4 : 0)); addbyte(0xC7); /*MOVL [pc], new_pc*/ addbyte(0x45); - addbyte(cpu_state_offset(pc)); + addbyte((uint8_t)cpu_state_offset(pc)); addlong(op_pc+pc_offset+offset); if (timing_bt) { addbyte(0x83); /*SUB $codegen_block_cycles, cyclcs*/ addbyte(0x6d); - addbyte(cpu_state_offset(_cycles)); + addbyte((uint8_t)cpu_state_offset(_cycles)); addbyte(timing_bt); } addbyte(0xe9); /*JMP end*/ addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); } -static int BRANCH_COND_LE(int pc_offset, uint32_t op_pc, uint32_t offset, int not) +static inline void BRANCH_COND_LE(int pc_offset, uint32_t op_pc, uint32_t offset, int not) { + uint8_t *jump1; if (codegen_flags_changed && cpu_state.flags_op != FLAGS_UNKNOWN) { addbyte(0x83); /*CMP flags_res, 0*/ addbyte(0x7d); - addbyte(cpu_state_offset(flags_res)); + addbyte((uint8_t)cpu_state_offset(flags_res)); addbyte(0); addbyte(0x74); /*JZ +*/ } else { - CALL_FUNC(ZF_SET); + CALL_FUNC((uintptr_t)ZF_SET); addbyte(0x85); /*TEST EAX,EAX*/ addbyte(0xc0); addbyte(0x75); /*JNZ +*/ } - if (not) - addbyte(12+2+3+12+2+3+2+2+7+5+(timing_bt ? 8 : 0)); - else - addbyte(12+2+3+12+2+3+2+2); - - CALL_FUNC(NF_SET); + jump1 = &codeblock[block_current].data[block_pos]; + addbyte(0); + CALL_FUNC((uintptr_t)NF_SET); addbyte(0x85); /*TEST EAX,EAX*/ addbyte(0xc0); addbyte(0x0f); /*SETNE BL*/ addbyte(0x95); addbyte(0xc3); - CALL_FUNC(VF_SET); + CALL_FUNC((uintptr_t)VF_SET); addbyte(0x85); /*TEST EAX,EAX*/ addbyte(0xc0); addbyte(0x0f); /*SETNE AL*/ @@ -3307,22 +3330,26 @@ static int BRANCH_COND_LE(int pc_offset, uint32_t op_pc, uint32_t offset, int no else addbyte(0x74); /*JZ +*/ addbyte(7+5+(timing_bt ? 4 : 0)); + if (!not) + *jump1 = (uintptr_t)&codeblock[block_current].data[block_pos] - (uintptr_t)jump1 - 1; addbyte(0xC7); /*MOVL [pc], new_pc*/ addbyte(0x45); - addbyte(cpu_state_offset(pc)); + addbyte((uint8_t)cpu_state_offset(pc)); addlong(op_pc+pc_offset+offset); if (timing_bt) { addbyte(0x83); /*SUB $codegen_block_cycles, cyclcs*/ addbyte(0x6d); - addbyte(cpu_state_offset(_cycles)); + addbyte((uint8_t)cpu_state_offset(_cycles)); addbyte(timing_bt); } addbyte(0xe9); /*JMP end*/ addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); + if (not) + *jump1 = (uintptr_t)&codeblock[block_current].data[block_pos] - (uintptr_t)jump1 - 1; } -static int LOAD_VAR_W(uintptr_t addr) +static inline int LOAD_VAR_W(uintptr_t addr) { int host_reg = REG_EBX; @@ -3353,11 +3380,11 @@ static int LOAD_VAR_W(uintptr_t addr) return host_reg; } -static int LOAD_VAR_WL(uintptr_t addr) +static inline int LOAD_VAR_WL(uintptr_t addr) { return LOAD_VAR_W(addr); } -static int LOAD_VAR_L(uintptr_t addr) +static inline int LOAD_VAR_L(uintptr_t addr) { int host_reg = REG_EBX; @@ -3386,7 +3413,7 @@ static int LOAD_VAR_L(uintptr_t addr) return host_reg; } -static int COPY_REG(int src_reg) +static inline int COPY_REG(int src_reg) { if (src_reg & 8) addbyte(0x44); @@ -3396,7 +3423,7 @@ static int COPY_REG(int src_reg) return REG_ECX | (src_reg & 0x10); } -static int LOAD_HOST_REG(int host_reg) +static inline int LOAD_HOST_REG(int host_reg) { if (host_reg & 8) addbyte(0x44); @@ -3406,7 +3433,7 @@ static int LOAD_HOST_REG(int host_reg) return REG_EBX | (host_reg & 0x10); } -static int ZERO_EXTEND_W_B(int reg) +static inline int ZERO_EXTEND_W_B(int reg) { if (reg & 0x10) { @@ -3428,7 +3455,7 @@ static int ZERO_EXTEND_W_B(int reg) return REG_EAX; } -static int ZERO_EXTEND_L_B(int reg) +static inline int ZERO_EXTEND_L_B(int reg) { if (reg & 0x10) { @@ -3450,7 +3477,7 @@ static int ZERO_EXTEND_L_B(int reg) return REG_EAX; } -static int ZERO_EXTEND_L_W(int reg) +static inline int ZERO_EXTEND_L_W(int reg) { if (reg & 8) addbyte(0x41); @@ -3461,7 +3488,7 @@ static int ZERO_EXTEND_L_W(int reg) return REG_EAX; } -static int SIGN_EXTEND_W_B(int reg) +static inline int SIGN_EXTEND_W_B(int reg) { if (reg & 0x10) { @@ -3483,7 +3510,7 @@ static int SIGN_EXTEND_W_B(int reg) return REG_EAX; } -static int SIGN_EXTEND_L_B(int reg) +static inline int SIGN_EXTEND_L_B(int reg) { if (reg & 0x10) { @@ -3505,7 +3532,7 @@ static int SIGN_EXTEND_L_B(int reg) return REG_EAX; } -static int SIGN_EXTEND_L_W(int reg) +static inline int SIGN_EXTEND_L_W(int reg) { if (reg & 8) addbyte(0x41); @@ -3516,7 +3543,7 @@ static int SIGN_EXTEND_L_W(int reg) return REG_EAX; } -static void SHL_B_IMM(int reg, int count) +static inline void SHL_B_IMM(int reg, int count) { if (reg & 0x10) { @@ -3539,7 +3566,7 @@ static void SHL_B_IMM(int reg, int count) addbyte(count); } } -static void SHL_W_IMM(int reg, int count) +static inline void SHL_W_IMM(int reg, int count) { addbyte(0x66); /*SHL reg, count*/ if (reg & 8) @@ -3548,7 +3575,7 @@ static void SHL_W_IMM(int reg, int count) addbyte(0xc0 | (reg & 7) | 0x20); addbyte(count); } -static void SHL_L_IMM(int reg, int count) +static inline void SHL_L_IMM(int reg, int count) { if (reg & 8) addbyte(0x41); @@ -3556,7 +3583,7 @@ static void SHL_L_IMM(int reg, int count) addbyte(0xc0 | (reg & 7) | 0x20); addbyte(count); } -static void SHR_B_IMM(int reg, int count) +static inline void SHR_B_IMM(int reg, int count) { if (reg & 0x10) { @@ -3579,7 +3606,7 @@ static void SHR_B_IMM(int reg, int count) addbyte(count); } } -static void SHR_W_IMM(int reg, int count) +static inline void SHR_W_IMM(int reg, int count) { addbyte(0x66); /*SHR reg, count*/ if (reg & 8) @@ -3588,7 +3615,7 @@ static void SHR_W_IMM(int reg, int count) addbyte(0xc0 | (reg & 7) | 0x28); addbyte(count); } -static void SHR_L_IMM(int reg, int count) +static inline void SHR_L_IMM(int reg, int count) { if (reg & 8) addbyte(0x41); @@ -3596,7 +3623,7 @@ static void SHR_L_IMM(int reg, int count) addbyte(0xc0 | (reg & 7) | 0x28); addbyte(count); } -static void SAR_B_IMM(int reg, int count) +static inline void SAR_B_IMM(int reg, int count) { if (reg & 0x10) { @@ -3619,7 +3646,7 @@ static void SAR_B_IMM(int reg, int count) addbyte(count); } } -static void SAR_W_IMM(int reg, int count) +static inline void SAR_W_IMM(int reg, int count) { addbyte(0x66); /*SAR reg, count*/ if (reg & 8) @@ -3628,7 +3655,7 @@ static void SAR_W_IMM(int reg, int count) addbyte(0xc0 | (reg & 7) | 0x38); addbyte(count); } -static void SAR_L_IMM(int reg, int count) +static inline void SAR_L_IMM(int reg, int count) { if (reg & 8) addbyte(0x41); @@ -3637,7 +3664,7 @@ static void SAR_L_IMM(int reg, int count) addbyte(count); } -static void NEG_HOST_REG_B(int reg) +static inline void NEG_HOST_REG_B(int reg) { if (reg & 0x10) { @@ -3660,7 +3687,7 @@ static void NEG_HOST_REG_B(int reg) addbyte(0xd8 | (reg & 7)); } } -static void NEG_HOST_REG_W(int reg) +static inline void NEG_HOST_REG_W(int reg) { addbyte(0x66); if (reg & 8) @@ -3668,7 +3695,7 @@ static void NEG_HOST_REG_W(int reg) addbyte(0xf7); addbyte(0xd8 | (reg & 7)); } -static void NEG_HOST_REG_L(int reg) +static inline void NEG_HOST_REG_L(int reg) { if (reg & 8) addbyte(0x41); @@ -3677,7 +3704,7 @@ static void NEG_HOST_REG_L(int reg) } -static void FP_ENTER() +static inline void FP_ENTER() { if (codegen_fpu_entered) return; @@ -3693,7 +3720,7 @@ static void FP_ENTER() { addbyte(0x48); /*MOV RAX, &cr0*/ addbyte(0xb8 | REG_EAX); - addquad(&cr0); + addquad((uint64_t)&cr0); addbyte(0xf6); /*TEST [RAX], 0xc*/ addbyte(0 | (REG_EAX << 3)); addbyte(0x0c); @@ -3702,21 +3729,21 @@ static void FP_ENTER() addbyte(7+5+12+5); addbyte(0xC7); /*MOVL [oldpc],op_old_pc*/ addbyte(0x45); - addbyte(cpu_state_offset(oldpc)); + addbyte((uint8_t)cpu_state_offset(oldpc)); addlong(op_old_pc); load_param_1_32(&codeblock[block_current], 7); - CALL_FUNC(x86_int); + CALL_FUNC((uintptr_t)x86_int); addbyte(0xe9); /*JMP end*/ addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); codegen_fpu_entered = 1; } -static void FP_FXCH(int reg) +static inline void FP_FXCH(int reg) { addbyte(0x8b); /*MOV EAX, [TOP]*/ addbyte(0x45); - addbyte(cpu_state_offset(TOP)); + addbyte((uint8_t)cpu_state_offset(TOP)); addbyte(0x89); /*MOV EBX, EAX*/ addbyte(0xc3); addbyte(0x83); /*ADD EAX, reg*/ @@ -3727,7 +3754,7 @@ static void FP_FXCH(int reg) addbyte(0x8b); addbyte(0x54); addbyte(0xdd); - addbyte(cpu_state_offset(ST)); + addbyte((uint8_t)cpu_state_offset(ST)); addbyte(0x83); /*AND EAX, 7*/ addbyte(0xe0); addbyte(0x07); @@ -3735,65 +3762,65 @@ static void FP_FXCH(int reg) addbyte(0x8b); addbyte(0x4c); addbyte(0xc5); - addbyte(cpu_state_offset(ST)); + addbyte((uint8_t)cpu_state_offset(ST)); addbyte(0x48); /*MOV ST[RAX*8], RDX*/ addbyte(0x89); addbyte(0x54); addbyte(0xc5); - addbyte(cpu_state_offset(ST)); + addbyte((uint8_t)cpu_state_offset(ST)); addbyte(0x48); /*MOV ST[RBX*8], RCX*/ addbyte(0x89); addbyte(0x4c); addbyte(0xdd); - addbyte(cpu_state_offset(ST)); + addbyte((uint8_t)cpu_state_offset(ST)); addbyte(0x8a); /*MOV CL, tag[EAX]*/ addbyte(0x4c); addbyte(0x05); - addbyte(cpu_state_offset(tag)); + addbyte((uint8_t)cpu_state_offset(tag)); addbyte(0x8a); /*MOV DL, tag[EBX]*/ addbyte(0x54); addbyte(0x1d); - addbyte(cpu_state_offset(tag)); + addbyte((uint8_t)cpu_state_offset(tag)); addbyte(0x88); /*MOV tag[EBX], CL*/ addbyte(0x4c); addbyte(0x1d); - addbyte(cpu_state_offset(tag)); + addbyte((uint8_t)cpu_state_offset(tag)); addbyte(0x88); /*MOV tag[EAX], DL*/ addbyte(0x54); addbyte(0x05); - addbyte(cpu_state_offset(tag)); + addbyte((uint8_t)cpu_state_offset(tag)); addbyte(0x48); /*MOV RDX, MM[RBX*8]*/ addbyte(0x8b); addbyte(0x54); addbyte(0xdd); - addbyte(cpu_state_offset(MM)); + addbyte((uint8_t)cpu_state_offset(MM)); addbyte(0x48); /*MOV RCX, MM[RAX*8]*/ addbyte(0x8b); addbyte(0x4c); addbyte(0xc5); - addbyte(cpu_state_offset(MM)); + addbyte((uint8_t)cpu_state_offset(MM)); addbyte(0x48); /*MOV MM[RAX*8], RDX*/ addbyte(0x89); addbyte(0x54); addbyte(0xc5); - addbyte(cpu_state_offset(MM)); + addbyte((uint8_t)cpu_state_offset(MM)); addbyte(0x48); /*MOV MM[RBX*8], RCX*/ addbyte(0x89); addbyte(0x4c); addbyte(0xdd); - addbyte(cpu_state_offset(MM)); + addbyte((uint8_t)cpu_state_offset(MM)); reg = reg; } -static void FP_FLD(int reg) +static inline void FP_FLD(int reg) { addbyte(0x8b); /*MOV EAX, [TOP]*/ addbyte(0x45); - addbyte(cpu_state_offset(TOP)); + addbyte((uint8_t)cpu_state_offset(TOP)); addbyte(0x89); /*MOV EBX, EAX*/ addbyte(0xc3); if (reg) @@ -3819,7 +3846,7 @@ static void FP_FLD(int reg) addbyte(0x8b); addbyte(0x4c); addbyte(0xc5); - addbyte(cpu_state_offset(ST)); + addbyte((uint8_t)cpu_state_offset(ST)); addbyte(0x83); /*AND EBX, 7*/ addbyte(0xe3); addbyte(0x07); @@ -3827,45 +3854,45 @@ static void FP_FLD(int reg) addbyte(0x8b); addbyte(0x54); addbyte(0xc5); - addbyte(cpu_state_offset(MM)); + addbyte((uint8_t)cpu_state_offset(MM)); addbyte(0x8a); /*MOV AL, [tag+EAX]*/ addbyte(0x44); addbyte(0x05); - addbyte(cpu_state_offset(tag)); + addbyte((uint8_t)cpu_state_offset(tag)); addbyte(0x48); /*MOV ST[EBX*8], RCX*/ addbyte(0x89); addbyte(0x4c); addbyte(0xdd); - addbyte(cpu_state_offset(ST)); + addbyte((uint8_t)cpu_state_offset(ST)); addbyte(0x48); /*MOV ST_i64[EBX*8], RDX*/ addbyte(0x89); addbyte(0x54); addbyte(0xdd); - addbyte(cpu_state_offset(MM)); + addbyte((uint8_t)cpu_state_offset(MM)); addbyte(0x88); /*MOV [tag+EBX], AL*/ addbyte(0x44); addbyte(0x1d); - addbyte(cpu_state_offset(tag)); + addbyte((uint8_t)cpu_state_offset(tag)); addbyte(0x89); /*MOV [TOP], EBX*/ addbyte(0x5d); - addbyte(cpu_state_offset(TOP)); + addbyte((uint8_t)cpu_state_offset(TOP)); } -static void FP_FST(int reg) +static inline void FP_FST(int reg) { addbyte(0x8b); /*MOV EAX, [TOP]*/ addbyte(0x45); - addbyte(cpu_state_offset(TOP)); + addbyte((uint8_t)cpu_state_offset(TOP)); addbyte(0x48); /*MOV RCX, ST[EAX*8]*/ addbyte(0x8b); addbyte(0x4c); addbyte(0xc5); - addbyte(cpu_state_offset(ST)); + addbyte((uint8_t)cpu_state_offset(ST)); addbyte(0x8a); /*MOV BL, [tag+EAX]*/ addbyte(0x5c); addbyte(0x05); - addbyte(cpu_state_offset(tag)); + addbyte((uint8_t)cpu_state_offset(tag)); if (reg) { @@ -3881,22 +3908,22 @@ static void FP_FST(int reg) addbyte(0x89); addbyte(0x4c); addbyte(0xc5); - addbyte(cpu_state_offset(ST)); + addbyte((uint8_t)cpu_state_offset(ST)); addbyte(0x88); /*MOV [tag+EAX], BL*/ addbyte(0x5c); addbyte(0x05); - addbyte(cpu_state_offset(tag)); + addbyte((uint8_t)cpu_state_offset(tag)); } -static void FP_POP() +static inline void FP_POP() { addbyte(0x8b); /*MOV EAX, [TOP]*/ addbyte(0x45); - addbyte(cpu_state_offset(TOP)); + addbyte((uint8_t)cpu_state_offset(TOP)); addbyte(0xc6); /*MOVB tag[EAX], 3*/ addbyte(0x44); addbyte(0x05); - addbyte(cpu_state_offset(tag)); + addbyte((uint8_t)cpu_state_offset(tag)); addbyte(3); addbyte(0x83); /*ADD AL, 1*/ addbyte(0xc0); @@ -3906,17 +3933,17 @@ static void FP_POP() addbyte(7); addbyte(0x89); /*MOV [TOP], EAX*/ addbyte(0x45); - addbyte(cpu_state_offset(TOP)); + addbyte((uint8_t)cpu_state_offset(TOP)); } -static void FP_POP2() +static inline void FP_POP2() { addbyte(0x8b); /*MOV EAX, [TOP]*/ addbyte(0x45); - addbyte(cpu_state_offset(TOP)); + addbyte((uint8_t)cpu_state_offset(TOP)); addbyte(0xc6); /*MOVB tag[EAX], 3*/ addbyte(0x44); addbyte(0x05); - addbyte(cpu_state_offset(tag)); + addbyte((uint8_t)cpu_state_offset(tag)); addbyte(3); addbyte(0x83); /*ADD AL, 2*/ addbyte(0xc0); @@ -3926,14 +3953,14 @@ static void FP_POP2() addbyte(7); addbyte(0x89); /*MOV [TOP], EAX*/ addbyte(0x45); - addbyte(cpu_state_offset(TOP)); + addbyte((uint8_t)cpu_state_offset(TOP)); } -static void FP_LOAD_S() +static inline void FP_LOAD_S() { addbyte(0x8b); /*MOV EBX, TOP*/ addbyte(0x5d); - addbyte(cpu_state_offset(TOP)); + addbyte((uint8_t)cpu_state_offset(TOP)); addbyte(0x66); /*MOVD XMM0, EAX*/ addbyte(0x0f); addbyte(0x6e); @@ -3952,24 +3979,24 @@ static void FP_LOAD_S() addbyte(0xc0); addbyte(0x89); /*MOV TOP, EBX*/ addbyte(0x5d); - addbyte(cpu_state_offset(TOP)); + addbyte((uint8_t)cpu_state_offset(TOP)); addbyte(0x66); /*MOVQ [ST+EBX*8], XMM0*/ addbyte(0x0f); addbyte(0xd6); addbyte(0x44); addbyte(0xdd); - addbyte(cpu_state_offset(ST)); + addbyte((uint8_t)cpu_state_offset(ST)); addbyte(0x0f); /*SETE [tag+EBX]*/ addbyte(0x94); addbyte(0x44); addbyte(0x1d); - addbyte(cpu_state_offset(tag)); + addbyte((uint8_t)cpu_state_offset(tag)); } -static void FP_LOAD_D() +static inline void FP_LOAD_D() { addbyte(0x8b); /*MOV EBX, TOP*/ addbyte(0x5d); - addbyte(cpu_state_offset(TOP)); + addbyte((uint8_t)cpu_state_offset(TOP)); addbyte(0x83); /*SUB EBX, 1*/ addbyte(0xeb); addbyte(0x01); @@ -3981,24 +4008,24 @@ static void FP_LOAD_D() addbyte(0xc0); addbyte(0x89); /*MOV TOP, EBX*/ addbyte(0x5d); - addbyte(cpu_state_offset(TOP)); + addbyte((uint8_t)cpu_state_offset(TOP)); addbyte(0x48); /*MOVQ [ST+EBX*8], RAX*/ addbyte(0x89); addbyte(0x44); addbyte(0xdd); - addbyte(cpu_state_offset(ST)); + addbyte((uint8_t)cpu_state_offset(ST)); addbyte(0x0f); /*SETE [tag+EBX]*/ addbyte(0x94); addbyte(0x44); addbyte(0x1d); - addbyte(cpu_state_offset(tag)); + addbyte((uint8_t)cpu_state_offset(tag)); } -static void FP_LOAD_IW() +static inline void FP_LOAD_IW() { addbyte(0x8b); /*MOV EBX, TOP*/ addbyte(0x5d); - addbyte(cpu_state_offset(TOP)); + addbyte((uint8_t)cpu_state_offset(TOP)); addbyte(0x0f); /*MOVSX EAX, AX*/ addbyte(0xbf); addbyte(0xc0); @@ -4016,24 +4043,24 @@ static void FP_LOAD_IW() addbyte(0xc0); addbyte(0x89); /*MOV TOP, EBX*/ addbyte(0x5d); - addbyte(cpu_state_offset(TOP)); + addbyte((uint8_t)cpu_state_offset(TOP)); addbyte(0x66); /*MOVQ [ST+EBX*8], XMM0*/ addbyte(0x0f); addbyte(0xd6); addbyte(0x44); addbyte(0xdd); - addbyte(cpu_state_offset(ST)); + addbyte((uint8_t)cpu_state_offset(ST)); addbyte(0x0f); /*SETE [tag+EBX]*/ addbyte(0x94); addbyte(0x44); addbyte(0x1d); - addbyte(cpu_state_offset(tag)); + addbyte((uint8_t)cpu_state_offset(tag)); } -static void FP_LOAD_IL() +static inline void FP_LOAD_IL() { addbyte(0x8b); /*MOV EBX, TOP*/ addbyte(0x5d); - addbyte(cpu_state_offset(TOP)); + addbyte((uint8_t)cpu_state_offset(TOP)); addbyte(0x83); /*SUB EBX, 1*/ addbyte(0xeb); addbyte(0x01); @@ -4048,24 +4075,24 @@ static void FP_LOAD_IL() addbyte(0xc0); addbyte(0x89); /*MOV TOP, EBX*/ addbyte(0x5d); - addbyte(cpu_state_offset(TOP)); + addbyte((uint8_t)cpu_state_offset(TOP)); addbyte(0x66); /*MOVQ [ST+EBX*8], XMM0*/ addbyte(0x0f); addbyte(0xd6); addbyte(0x44); addbyte(0xdd); - addbyte(cpu_state_offset(ST)); + addbyte((uint8_t)cpu_state_offset(ST)); addbyte(0x0f); /*SETE [tag+EBX]*/ addbyte(0x94); addbyte(0x44); addbyte(0x1d); - addbyte(cpu_state_offset(tag)); + addbyte((uint8_t)cpu_state_offset(tag)); } -static void FP_LOAD_IQ() +static inline void FP_LOAD_IQ() { addbyte(0x8b); /*MOV EBX, TOP*/ addbyte(0x5d); - addbyte(cpu_state_offset(TOP)); + addbyte((uint8_t)cpu_state_offset(TOP)); addbyte(0x83); /*SUB EBX, 1*/ addbyte(0xeb); addbyte(0x01); @@ -4084,10 +4111,10 @@ static void FP_LOAD_IQ() addbyte(0x89); addbyte(0x44); addbyte(0xdd); - addbyte(cpu_state_offset(MM)); + addbyte((uint8_t)cpu_state_offset(MM)); addbyte(0x89); /*MOV TOP, EBX*/ addbyte(0x5d); - addbyte(cpu_state_offset(TOP)); + addbyte((uint8_t)cpu_state_offset(TOP)); addbyte(0x0f); /*SETE AL*/ addbyte(0x94); addbyte(0xc0); @@ -4096,20 +4123,20 @@ static void FP_LOAD_IQ() addbyte(0xd6); addbyte(0x44); addbyte(0xdd); - addbyte(cpu_state_offset(ST)); + addbyte((uint8_t)cpu_state_offset(ST)); addbyte(0x0c); /*OR AL, TAG_UINT64*/ addbyte(TAG_UINT64); addbyte(0x88); /*MOV [tag+EBX], AL*/ addbyte(0x44); addbyte(0x1d); - addbyte(cpu_state_offset(tag)); + addbyte((uint8_t)cpu_state_offset(tag)); } -static void FP_LOAD_IMM_Q(uint64_t v) +static inline void FP_LOAD_IMM_Q(uint64_t v) { addbyte(0x8b); /*MOV EBX, TOP*/ addbyte(0x5d); - addbyte(cpu_state_offset(TOP)); + addbyte((uint8_t)cpu_state_offset(TOP)); addbyte(0x83); /*SUB EBX, 1*/ addbyte(0xeb); addbyte(0x01); @@ -4119,28 +4146,28 @@ static void FP_LOAD_IMM_Q(uint64_t v) addbyte(0xc7); /*MOV ST[EBP+EBX*8], v*/ addbyte(0x44); addbyte(0xdd); - addbyte(cpu_state_offset(ST)); + addbyte((uint8_t)cpu_state_offset(ST)); addlong(v & 0xffffffff); addbyte(0xc7); /*MOV ST[EBP+EBX*8]+4, v*/ addbyte(0x44); addbyte(0xdd); - addbyte(cpu_state_offset(ST) + 4); + addbyte((uint8_t)cpu_state_offset(ST) + 4); addlong(v >> 32); addbyte(0x89); /*MOV TOP, EBX*/ addbyte(0x5d); - addbyte(cpu_state_offset(TOP)); + addbyte((uint8_t)cpu_state_offset(TOP)); addbyte(0xc6); /*MOV [tag+EBX], (v ? 0 : 1)*/ addbyte(0x44); addbyte(0x1d); - addbyte(cpu_state_offset(tag)); + addbyte((uint8_t)cpu_state_offset(tag)); addbyte(v ? 0 : 1); } -static void FP_FCHS() +static inline void FP_FCHS() { addbyte(0x8b); /*MOV EAX, TOP*/ addbyte(0x45); - addbyte(cpu_state_offset(TOP)); + addbyte((uint8_t)cpu_state_offset(TOP)); addbyte(0xf2); /*SUBSD XMM0, XMM0*/ addbyte(0x0f); addbyte(0x5c); @@ -4150,25 +4177,25 @@ static void FP_FCHS() addbyte(0x5c); addbyte(0x44); addbyte(0xc5); - addbyte(cpu_state_offset(ST)); + addbyte((uint8_t)cpu_state_offset(ST)); addbyte(0x80); /*AND tag[EAX], ~TAG_UINT64*/ addbyte(0x64); addbyte(0x05); - addbyte(cpu_state_offset(tag[0])); + addbyte((uint8_t)cpu_state_offset(tag[0])); addbyte(~TAG_UINT64); addbyte(0xf2); /*MOVSD ST[EAX*8], XMM0*/ addbyte(0x0f); addbyte(0x11); addbyte(0x44); addbyte(0xc5); - addbyte(cpu_state_offset(ST)); + addbyte((uint8_t)cpu_state_offset(ST)); } -static int FP_LOAD_REG(int reg) +static inline int FP_LOAD_REG(int reg) { addbyte(0x8b); /*MOV EBX, TOP*/ addbyte(0x5d); - addbyte(cpu_state_offset(TOP)); + addbyte((uint8_t)cpu_state_offset(TOP)); if (reg) { addbyte(0x83); /*ADD EBX, reg*/ @@ -4183,7 +4210,7 @@ static int FP_LOAD_REG(int reg) addbyte(0x7e); addbyte(0x44); addbyte(0xdd); - addbyte(cpu_state_offset(ST)); + addbyte((uint8_t)cpu_state_offset(ST)); addbyte(0xf2); /*CVTSD2SS XMM0, XMM0*/ addbyte(0x0f); addbyte(0x5a); @@ -4195,11 +4222,11 @@ static int FP_LOAD_REG(int reg) return REG_EBX; } -static void FP_LOAD_REG_D(int reg, int *host_reg1, int *host_reg2) +static inline void FP_LOAD_REG_D(int reg, int *host_reg1, int *host_reg2) { addbyte(0x8b); /*MOV EBX, TOP*/ addbyte(0x5d); - addbyte(cpu_state_offset(TOP)); + addbyte((uint8_t)cpu_state_offset(TOP)); if (reg) { addbyte(0x83); /*ADD EBX, reg*/ @@ -4213,11 +4240,11 @@ static void FP_LOAD_REG_D(int reg, int *host_reg1, int *host_reg2) addbyte(0x8b); addbyte(0x5c); addbyte(0xdd); - addbyte(cpu_state_offset(ST)); + addbyte((uint8_t)cpu_state_offset(ST)); *host_reg1 = REG_EBX; } -static int64_t x87_fround(double b) +static inline int64_t x87_fround(double b) { int64_t a, c; @@ -4239,15 +4266,17 @@ static int64_t x87_fround(double b) case 3: /*Chop*/ return (int64_t)b; } + + return 0; } -static int FP_LOAD_REG_INT_W(int reg) +static inline int FP_LOAD_REG_INT_W(int reg) { addbyte(0x89); /*MOV EBX, EAX*/ addbyte(0xc3); addbyte(0x8b); /*MOV EAX, [TOP]*/ addbyte(0x45); - addbyte(cpu_state_offset(TOP)); + addbyte((uint8_t)cpu_state_offset(TOP)); if (reg) { addbyte(0x83); /*ADD EAX, reg*/ @@ -4262,22 +4291,22 @@ static int FP_LOAD_REG_INT_W(int reg) addbyte(0x7e); addbyte(0x44); addbyte(0xc5); - addbyte(cpu_state_offset(ST)); + addbyte((uint8_t)cpu_state_offset(ST)); - CALL_FUNC(x87_fround); + CALL_FUNC((uintptr_t)x87_fround); addbyte(0x93); /*XCHG EBX, EAX*/ return REG_EBX; } -static int FP_LOAD_REG_INT(int reg) +static inline int FP_LOAD_REG_INT(int reg) { addbyte(0x89); /*MOV EBX, EAX*/ addbyte(0xc3); addbyte(0x8b); /*MOV EAX, [TOP]*/ addbyte(0x45); - addbyte(cpu_state_offset(TOP)); + addbyte((uint8_t)cpu_state_offset(TOP)); if (reg) { addbyte(0x83); /*ADD EAX, reg*/ @@ -4292,22 +4321,22 @@ static int FP_LOAD_REG_INT(int reg) addbyte(0x7e); addbyte(0x44); addbyte(0xc5); - addbyte(cpu_state_offset(ST)); + addbyte((uint8_t)cpu_state_offset(ST)); - CALL_FUNC(x87_fround); + CALL_FUNC((uintptr_t)x87_fround); addbyte(0x93); /*XCHG EBX, EAX*/ return REG_EBX; } -static void FP_LOAD_REG_INT_Q(int reg, int *host_reg1, int *host_reg2) +static inline void FP_LOAD_REG_INT_Q(int reg, int *host_reg1, int *host_reg2) { addbyte(0x89); /*MOV EBX, EAX*/ addbyte(0xc3); addbyte(0x8b); /*MOV EAX, [TOP]*/ addbyte(0x45); - addbyte(cpu_state_offset(TOP)); + addbyte((uint8_t)cpu_state_offset(TOP)); if (reg) { addbyte(0x83); /*ADD EAX, reg*/ @@ -4327,7 +4356,7 @@ static void FP_LOAD_REG_INT_Q(int reg, int *host_reg1, int *host_reg2) addbyte(0x8b); addbyte(0x44); addbyte(0xc5); - addbyte(cpu_state_offset(MM)); + addbyte((uint8_t)cpu_state_offset(MM)); addbyte(0x48); /*XCHG RBX, RAX*/ addbyte(0x93); @@ -4340,7 +4369,7 @@ static void FP_LOAD_REG_INT_Q(int reg, int *host_reg1, int *host_reg2) addbyte(0xf6); /*TEST TAG[EAX], TAG_UINT64*/ addbyte(0x44); addbyte(0x05); - addbyte(cpu_state_offset(tag)); + addbyte((uint8_t)cpu_state_offset(tag)); addbyte(TAG_UINT64); addbyte(0x74); /*JZ +*/ @@ -4350,7 +4379,7 @@ static void FP_LOAD_REG_INT_Q(int reg, int *host_reg1, int *host_reg2) addbyte(0x8b); addbyte(0x44); addbyte(0xc5); - addbyte(cpu_state_offset(MM)); + addbyte((uint8_t)cpu_state_offset(MM)); addbyte(0xeb); /*JMP done*/ addbyte(6+12); @@ -4360,9 +4389,9 @@ static void FP_LOAD_REG_INT_Q(int reg, int *host_reg1, int *host_reg2) addbyte(0x7e); addbyte(0x44); addbyte(0xc5); - addbyte(cpu_state_offset(ST)); + addbyte((uint8_t)cpu_state_offset(ST)); - CALL_FUNC(x87_fround); + CALL_FUNC((uintptr_t)x87_fround); addbyte(0x48); /*XCHG RBX, RAX*/ addbyte(0x93); @@ -4377,11 +4406,11 @@ static void FP_LOAD_REG_INT_Q(int reg, int *host_reg1, int *host_reg2) #define FPU_SUB 2 #define FPU_SUBR 3 -static void FP_OP_REG(int op, int dst, int src) +static inline void FP_OP_REG(int op, int dst, int src) { addbyte(0x8b); /*MOV EAX, [TOP]*/ addbyte(0x45); - addbyte(cpu_state_offset(TOP)); + addbyte((uint8_t)cpu_state_offset(TOP)); addbyte(0x89); /*MOV EBX, EAX*/ addbyte(0xc3); if (dst) @@ -4405,7 +4434,7 @@ static void FP_OP_REG(int op, int dst, int src) addbyte(0x80); /*AND tag[EAX], ~TAG_UINT64*/ addbyte(0x64); addbyte(0x05); - addbyte(cpu_state_offset(tag)); + addbyte((uint8_t)cpu_state_offset(tag)); addbyte(~TAG_UINT64); if (op == FPU_DIVR || op == FPU_SUBR) { @@ -4414,7 +4443,7 @@ static void FP_OP_REG(int op, int dst, int src) addbyte(0x7e); addbyte(0x44); addbyte(0xdd); - addbyte(cpu_state_offset(ST)); + addbyte((uint8_t)cpu_state_offset(ST)); } else { @@ -4423,7 +4452,7 @@ static void FP_OP_REG(int op, int dst, int src) addbyte(0x7e); addbyte(0x44); addbyte(0xc5); - addbyte(cpu_state_offset(ST)); + addbyte((uint8_t)cpu_state_offset(ST)); } switch (op) { @@ -4433,7 +4462,7 @@ static void FP_OP_REG(int op, int dst, int src) addbyte(0x58); addbyte(0x44); addbyte(0xdd); - addbyte(cpu_state_offset(ST)); + addbyte((uint8_t)cpu_state_offset(ST)); break; case FPU_DIV: addbyte(0xf2); /*DIVSD XMM0, ST[RBX*8]*/ @@ -4441,7 +4470,7 @@ static void FP_OP_REG(int op, int dst, int src) addbyte(0x5e); addbyte(0x44); addbyte(0xdd); - addbyte(cpu_state_offset(ST)); + addbyte((uint8_t)cpu_state_offset(ST)); break; case FPU_DIVR: addbyte(0xf2); /*DIVSD XMM0, ST[RAX*8]*/ @@ -4449,7 +4478,7 @@ static void FP_OP_REG(int op, int dst, int src) addbyte(0x5e); addbyte(0x44); addbyte(0xc5); - addbyte(cpu_state_offset(ST)); + addbyte((uint8_t)cpu_state_offset(ST)); break; case FPU_MUL: addbyte(0xf2); /*MULSD XMM0, ST[RBX*8]*/ @@ -4457,7 +4486,7 @@ static void FP_OP_REG(int op, int dst, int src) addbyte(0x59); addbyte(0x44); addbyte(0xdd); - addbyte(cpu_state_offset(ST)); + addbyte((uint8_t)cpu_state_offset(ST)); break; case FPU_SUB: addbyte(0xf2); /*SUBSD XMM0, ST[RBX*8]*/ @@ -4465,7 +4494,7 @@ static void FP_OP_REG(int op, int dst, int src) addbyte(0x5c); addbyte(0x44); addbyte(0xdd); - addbyte(cpu_state_offset(ST)); + addbyte((uint8_t)cpu_state_offset(ST)); break; case FPU_SUBR: addbyte(0xf2); /*SUBSD XMM0, ST[RAX*8]*/ @@ -4473,7 +4502,7 @@ static void FP_OP_REG(int op, int dst, int src) addbyte(0x5c); addbyte(0x44); addbyte(0xc5); - addbyte(cpu_state_offset(ST)); + addbyte((uint8_t)cpu_state_offset(ST)); break; } addbyte(0x66); /*MOVQ [RSI+RAX*8], XMM0*/ @@ -4481,24 +4510,24 @@ static void FP_OP_REG(int op, int dst, int src) addbyte(0xd6); addbyte(0x44); addbyte(0xc5); - addbyte(cpu_state_offset(ST)); + addbyte((uint8_t)cpu_state_offset(ST)); } -static void FP_OP_MEM(int op) +static inline void FP_OP_MEM(int op) { addbyte(0x8b); /*MOV EAX, [TOP]*/ addbyte(0x45); - addbyte(cpu_state_offset(TOP)); + addbyte((uint8_t)cpu_state_offset(TOP)); addbyte(0xf3); /*MOVQ XMM0, ST[RAX*8]*/ addbyte(0x0f); addbyte(0x7e); addbyte(0x44); addbyte(0xc5); - addbyte(cpu_state_offset(ST)); + addbyte((uint8_t)cpu_state_offset(ST)); addbyte(0x80); /*AND tag[EAX], ~TAG_UINT64*/ addbyte(0x64); addbyte(0x05); - addbyte(cpu_state_offset(tag)); + addbyte((uint8_t)cpu_state_offset(tag)); addbyte(~TAG_UINT64); switch (op) @@ -4547,7 +4576,7 @@ static void FP_OP_MEM(int op) addbyte(0xd6); addbyte(0x4c); addbyte(0xc5); - addbyte(cpu_state_offset(ST)); + addbyte((uint8_t)cpu_state_offset(ST)); } else { @@ -4556,11 +4585,11 @@ static void FP_OP_MEM(int op) addbyte(0xd6); addbyte(0x44); addbyte(0xc5); - addbyte(cpu_state_offset(ST)); + addbyte((uint8_t)cpu_state_offset(ST)); } } -static void FP_OP_S(int op) +static inline void FP_OP_S(int op) { addbyte(0x66); /*MOVD XMM1, EAX*/ addbyte(0x0f); @@ -4572,7 +4601,7 @@ static void FP_OP_S(int op) addbyte(0xc9); FP_OP_MEM(op); } -static void FP_OP_D(int op) +static inline void FP_OP_D(int op) { addbyte(0x66); /*MOVQ XMM1, RAX*/ addbyte(0x48); @@ -4614,7 +4643,7 @@ static void FP_OP_D(int op) addbyte(0x08); } } -static void FP_OP_IW(int op) +static inline void FP_OP_IW(int op) { addbyte(0x0f); /*MOVSX EAX, AX*/ addbyte(0xbf); @@ -4625,7 +4654,7 @@ static void FP_OP_IW(int op) addbyte(0xc8); FP_OP_MEM(op); } -static void FP_OP_IL(int op) +static inline void FP_OP_IL(int op) { addbyte(0xf2); /*CVTSI2SD XMM1, EAX*/ addbyte(0x0f); @@ -4639,11 +4668,11 @@ static void FP_OP_IL(int op) #define C2 (1<<10) #define C3 (1<<14) -static void FP_COMPARE_REG(int dst, int src) +static inline void FP_COMPARE_REG(int dst, int src) { addbyte(0x8b); /*MOV EAX, [TOP]*/ addbyte(0x45); - addbyte(cpu_state_offset(TOP)); + addbyte((uint8_t)cpu_state_offset(TOP)); addbyte(0x89); /*MOV EBX, EAX*/ addbyte(0xc3); if (src || dst) @@ -4658,9 +4687,7 @@ static void FP_COMPARE_REG(int dst, int src) addbyte(0x8a); /*MOV CL, [npxs+1]*/ addbyte(0x4d); - addbyte(cpu_state_offset(npxs) + 1); -// addbyte(0xdb); /*FCLEX*/ -// addbyte(0xe2); + addbyte((uint8_t)cpu_state_offset(npxs) + 1); addbyte(0x80); /*AND CL, ~(C0|C2|C3)*/ addbyte(0xe1); addbyte((~(C0|C2|C3)) >> 8); @@ -4672,13 +4699,13 @@ static void FP_COMPARE_REG(int dst, int src) addbyte(0x7e); addbyte(0x44); addbyte(0xdd); - addbyte(cpu_state_offset(ST)); + addbyte((uint8_t)cpu_state_offset(ST)); addbyte(0x66); /*COMISD XMM0, ST[RAX*8]*/ addbyte(0x0f); addbyte(0x2f); addbyte(0x44); addbyte(0xc5); - addbyte(cpu_state_offset(ST)); + addbyte((uint8_t)cpu_state_offset(ST)); } else { @@ -4687,13 +4714,13 @@ static void FP_COMPARE_REG(int dst, int src) addbyte(0x7e); addbyte(0x44); addbyte(0xc5); - addbyte(cpu_state_offset(ST)); + addbyte((uint8_t)cpu_state_offset(ST)); addbyte(0x66); /*COMISD XMM0, ST[RBX*8]*/ addbyte(0x0f); addbyte(0x2f); addbyte(0x44); addbyte(0xdd); - addbyte(cpu_state_offset(ST)); + addbyte((uint8_t)cpu_state_offset(ST)); } addbyte(0x9f); /*LAHF*/ @@ -4704,26 +4731,24 @@ static void FP_COMPARE_REG(int dst, int src) addbyte(0xe1); addbyte(0x88); /*MOV [npxs+1], CL*/ addbyte(0x4d); - addbyte(cpu_state_offset(npxs) + 1); + addbyte((uint8_t)cpu_state_offset(npxs) + 1); } -static void FP_COMPARE_MEM() +static inline void FP_COMPARE_MEM() { addbyte(0x8b); /*MOV EAX, [TOP]*/ addbyte(0x45); - addbyte(cpu_state_offset(TOP)); + addbyte((uint8_t)cpu_state_offset(TOP)); addbyte(0x8a); /*MOV CL, [npxs+1]*/ addbyte(0x4d); - addbyte(cpu_state_offset(npxs) + 1); -// addbyte(0xdb); /*FCLEX*/ -// addbyte(0xe2); + addbyte((uint8_t)cpu_state_offset(npxs) + 1); addbyte(0xf3); /*MOVQ XMM0, ST[RAX*8]*/ addbyte(0x0f); addbyte(0x7e); addbyte(0x44); addbyte(0xc5); - addbyte(cpu_state_offset(ST)); + addbyte((uint8_t)cpu_state_offset(ST)); addbyte(0x80); /*AND CL, ~(C0|C2|C3)*/ addbyte(0xe1); addbyte((~(C0|C2|C3)) >> 8); @@ -4739,9 +4764,9 @@ static void FP_COMPARE_MEM() addbyte(0xe1); addbyte(0x88); /*MOV [npxs+1], CL*/ addbyte(0x4d); - addbyte(cpu_state_offset(npxs) + 1); + addbyte((uint8_t)cpu_state_offset(npxs) + 1); } -static void FP_COMPARE_S() +static inline void FP_COMPARE_S() { addbyte(0x66); /*MOVD XMM1, EAX*/ addbyte(0x0f); @@ -4753,7 +4778,7 @@ static void FP_COMPARE_S() addbyte(0xc9); FP_COMPARE_MEM(); } -static void FP_COMPARE_D() +static inline void FP_COMPARE_D() { addbyte(0x66); /*MOVQ XMM1, RAX*/ addbyte(0x48); @@ -4762,7 +4787,7 @@ static void FP_COMPARE_D() addbyte(0xc8); FP_COMPARE_MEM(); } -static void FP_COMPARE_IW() +static inline void FP_COMPARE_IW() { addbyte(0x0f); /*MOVSX EAX, AX*/ addbyte(0xbf); @@ -4773,7 +4798,7 @@ static void FP_COMPARE_IW() addbyte(0xc8); FP_COMPARE_MEM(); } -static void FP_COMPARE_IL() +static inline void FP_COMPARE_IL() { addbyte(0xf2); /*CVTSI2SD XMM1, EAX*/ addbyte(0x0f); @@ -4782,11 +4807,11 @@ static void FP_COMPARE_IL() FP_COMPARE_MEM(); } -static void UPDATE_NPXC(int reg) +static inline void UPDATE_NPXC(int reg) { } -static void SET_BITS(uintptr_t addr, uint32_t val) +static inline void SET_BITS(uintptr_t addr, uint32_t val) { if (IS_32_ADDR(addr)) { @@ -4827,7 +4852,7 @@ static void SET_BITS(uintptr_t addr, uint32_t val) } } -static void CLEAR_BITS(uintptr_t addr, uint32_t val) +static inline void CLEAR_BITS(uintptr_t addr, uint32_t val) { if (IS_32_ADDR(addr)) { @@ -4871,7 +4896,7 @@ static void CLEAR_BITS(uintptr_t addr, uint32_t val) #define LOAD_Q_REG_1 REG_EAX #define LOAD_Q_REG_2 REG_EDX -static void MMX_ENTER() +static inline void MMX_ENTER() { if (codegen_mmx_entered) return; @@ -4888,7 +4913,7 @@ static void MMX_ENTER() { addbyte(0x48); /*MOV RAX, &cr0*/ addbyte(0xb8 | REG_EAX); - addquad(&cr0); + addquad((uint64_t)&cr0); addbyte(0xf6); /*TEST [RAX], 0xc*/ addbyte(0 | (REG_EAX << 3)); addbyte(0x0c); @@ -4897,10 +4922,10 @@ static void MMX_ENTER() addbyte(7+5+12+5); addbyte(0xC7); /*MOVL [oldpc],op_old_pc*/ addbyte(0x45); - addbyte(cpu_state_offset(oldpc)); + addbyte((uint8_t)cpu_state_offset(oldpc)); addlong(op_old_pc); load_param_1_32(&codeblock[block_current], 7); - CALL_FUNC(x86_int); + CALL_FUNC((uintptr_t)x86_int); addbyte(0xe9); /*JMP end*/ addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); @@ -4909,35 +4934,35 @@ static void MMX_ENTER() addbyte(0xc0); addbyte(0xc6); /*MOV ISMMX, 1*/ addbyte(0x45); - addbyte(cpu_state_offset(ismmx)); + addbyte((uint8_t)cpu_state_offset(ismmx)); addbyte(1); addbyte(0x89); /*MOV TOP, EAX*/ addbyte(0x45); - addbyte(cpu_state_offset(TOP)); + addbyte((uint8_t)cpu_state_offset(TOP)); addbyte(0x89); /*MOV tag, EAX*/ addbyte(0x45); - addbyte(cpu_state_offset(tag[0])); + addbyte((uint8_t)cpu_state_offset(tag[0])); addbyte(0x89); /*MOV tag+4, EAX*/ addbyte(0x45); - addbyte(cpu_state_offset(tag[4])); + addbyte((uint8_t)cpu_state_offset(tag[4])); codegen_mmx_entered = 1; } extern int mmx_ebx_ecx_loaded; -static int LOAD_MMX_D(int guest_reg) +static inline int LOAD_MMX_D(int guest_reg) { int host_reg = REG_EBX; addbyte(0x8b); /*MOV EBX, reg*/ addbyte(0x44 | (host_reg << 3)); addbyte(0x25); - addbyte(cpu_state_offset(MM[guest_reg].l[0])); + addbyte((uint8_t)cpu_state_offset(MM[guest_reg].l[0])); return host_reg; } -static void LOAD_MMX_Q(int guest_reg, int *host_reg1, int *host_reg2) +static inline void LOAD_MMX_Q(int guest_reg, int *host_reg1, int *host_reg2) { int host_reg = REG_EBX; @@ -4948,11 +4973,11 @@ static void LOAD_MMX_Q(int guest_reg, int *host_reg1, int *host_reg2) addbyte(0x8b); /*MOV RBX, reg*/ addbyte(0x44 | ((host_reg & 7) << 3)); addbyte(0x25); - addbyte(cpu_state_offset(MM[guest_reg].q)); + addbyte((uint8_t)cpu_state_offset(MM[guest_reg].q)); *host_reg1 = host_reg; } -static int LOAD_MMX_Q_MMX(int guest_reg) +static inline int LOAD_MMX_Q_MMX(int guest_reg) { int dst_reg = find_host_xmm_reg(); host_reg_xmm_mapping[dst_reg] = 100; @@ -4962,12 +4987,12 @@ static int LOAD_MMX_Q_MMX(int guest_reg) addbyte(0x7e); addbyte(0x44 | ((dst_reg & 7) << 3)); addbyte(0x25); - addbyte(cpu_state_offset(MM[guest_reg].q)); + addbyte((uint8_t)cpu_state_offset(MM[guest_reg].q)); return dst_reg; } -static int LOAD_INT_TO_MMX(int src_reg1, int src_reg2) +static inline int LOAD_INT_TO_MMX(int src_reg1, int src_reg2) { int dst_reg = find_host_xmm_reg(); host_reg_xmm_mapping[dst_reg] = 100; @@ -4984,21 +5009,21 @@ static int LOAD_INT_TO_MMX(int src_reg1, int src_reg2) return dst_reg; } -static void STORE_MMX_LQ(int guest_reg, int host_reg1) +static inline void STORE_MMX_LQ(int guest_reg, int host_reg1) { addbyte(0xC7); /*MOVL [reg],0*/ addbyte(0x44); addbyte(0x25); - addbyte(cpu_state_offset(MM[guest_reg].l[1])); + addbyte((uint8_t)cpu_state_offset(MM[guest_reg].l[1])); addlong(0); if (host_reg1 & 8) addbyte(0x44); addbyte(0x89); /*MOVL [reg],host_reg*/ addbyte(0x44 | ((host_reg1 & 7) << 3)); addbyte(0x25); - addbyte(cpu_state_offset(MM[guest_reg].l[0])); + addbyte((uint8_t)cpu_state_offset(MM[guest_reg].l[0])); } -static void STORE_MMX_Q(int guest_reg, int host_reg1, int host_reg2) +static inline void STORE_MMX_Q(int guest_reg, int host_reg1, int host_reg2) { if (host_reg1 & 8) addbyte(0x4c); @@ -5007,20 +5032,20 @@ static void STORE_MMX_Q(int guest_reg, int host_reg1, int host_reg2) addbyte(0x89); /*MOV [reg],host_reg*/ addbyte(0x44 | ((host_reg1 & 7) << 3)); addbyte(0x25); - addbyte(cpu_state_offset(MM[guest_reg].l[0])); + addbyte((uint8_t)cpu_state_offset(MM[guest_reg].l[0])); } -static void STORE_MMX_Q_MMX(int guest_reg, int host_reg) +static inline void STORE_MMX_Q_MMX(int guest_reg, int host_reg) { addbyte(0x66); /*MOVQ [guest_reg],host_reg*/ addbyte(0x0f); addbyte(0xd6); addbyte(0x44 | (host_reg << 3)); addbyte(0x25); - addbyte(cpu_state_offset(MM[guest_reg].q)); + addbyte((uint8_t)cpu_state_offset(MM[guest_reg].q)); } #define MMX_x86_OP(name, opcode) \ -static void MMX_ ## name(int dst_reg, int src_reg) \ +static inline void MMX_ ## name(int dst_reg, int src_reg) \ { \ addbyte(0x66); /*op dst_reg, src_reg*/ \ addbyte(0x0f); \ @@ -5073,7 +5098,7 @@ MMX_x86_OP(PMULLW, 0xd5); MMX_x86_OP(PMULHW, 0xe5); MMX_x86_OP(PMADDWD, 0xf5); -static void MMX_PACKSSWB(int dst_reg, int src_reg) +static inline void MMX_PACKSSWB(int dst_reg, int src_reg) { addbyte(0x66); /*PACKSSWB dst_reg, src_reg*/ addbyte(0x0f); @@ -5085,7 +5110,7 @@ static void MMX_PACKSSWB(int dst_reg, int src_reg) addbyte(0xc0 | (dst_reg << 3) | dst_reg); addbyte(0x08); } -static void MMX_PACKUSWB(int dst_reg, int src_reg) +static inline void MMX_PACKUSWB(int dst_reg, int src_reg) { addbyte(0x66); /*PACKUSWB dst_reg, src_reg*/ addbyte(0x0f); @@ -5097,7 +5122,7 @@ static void MMX_PACKUSWB(int dst_reg, int src_reg) addbyte(0xc0 | (dst_reg << 3) | dst_reg); addbyte(0x08); } -static void MMX_PACKSSDW(int dst_reg, int src_reg) +static inline void MMX_PACKSSDW(int dst_reg, int src_reg) { addbyte(0x66); /*PACKSSDW dst_reg, src_reg*/ addbyte(0x0f); @@ -5109,7 +5134,7 @@ static void MMX_PACKSSDW(int dst_reg, int src_reg) addbyte(0xc0 | (dst_reg << 3) | dst_reg); addbyte(0x08); } -static void MMX_PUNPCKHBW(int dst_reg, int src_reg) +static inline void MMX_PUNPCKHBW(int dst_reg, int src_reg) { addbyte(0x66); /*PUNPCKLBW dst_reg, src_reg*/ addbyte(0x0f); @@ -5121,7 +5146,7 @@ static void MMX_PUNPCKHBW(int dst_reg, int src_reg) addbyte(0xc0 | (dst_reg << 3) | dst_reg); addbyte(0x0e); } -static void MMX_PUNPCKHWD(int dst_reg, int src_reg) +static inline void MMX_PUNPCKHWD(int dst_reg, int src_reg) { addbyte(0x66); /*PUNPCKLWD dst_reg, src_reg*/ addbyte(0x0f); @@ -5133,7 +5158,7 @@ static void MMX_PUNPCKHWD(int dst_reg, int src_reg) addbyte(0xc0 | (dst_reg << 3) | dst_reg); addbyte(0x0e); } -static void MMX_PUNPCKHDQ(int dst_reg, int src_reg) +static inline void MMX_PUNPCKHDQ(int dst_reg, int src_reg) { addbyte(0x66); /*PUNPCKLDQ dst_reg, src_reg*/ addbyte(0x0f); @@ -5146,7 +5171,7 @@ static void MMX_PUNPCKHDQ(int dst_reg, int src_reg) addbyte(0x0e); } -static void MMX_PSRLW_imm(int dst_reg, int amount) +static inline void MMX_PSRLW_imm(int dst_reg, int amount) { addbyte(0x66); /*PSRLW dst_reg, amount*/ addbyte(0x0f); @@ -5154,7 +5179,7 @@ static void MMX_PSRLW_imm(int dst_reg, int amount) addbyte(0xc0 | dst_reg | 0x10); addbyte(amount); } -static void MMX_PSRAW_imm(int dst_reg, int amount) +static inline void MMX_PSRAW_imm(int dst_reg, int amount) { addbyte(0x66); /*PSRAW dst_reg, amount*/ addbyte(0x0f); @@ -5162,7 +5187,7 @@ static void MMX_PSRAW_imm(int dst_reg, int amount) addbyte(0xc0 | dst_reg | 0x20); addbyte(amount); } -static void MMX_PSLLW_imm(int dst_reg, int amount) +static inline void MMX_PSLLW_imm(int dst_reg, int amount) { addbyte(0x66); /*PSLLW dst_reg, amount*/ addbyte(0x0f); @@ -5171,7 +5196,7 @@ static void MMX_PSLLW_imm(int dst_reg, int amount) addbyte(amount); } -static void MMX_PSRLD_imm(int dst_reg, int amount) +static inline void MMX_PSRLD_imm(int dst_reg, int amount) { addbyte(0x66); /*PSRLD dst_reg, amount*/ addbyte(0x0f); @@ -5179,7 +5204,7 @@ static void MMX_PSRLD_imm(int dst_reg, int amount) addbyte(0xc0 | dst_reg | 0x10); addbyte(amount); } -static void MMX_PSRAD_imm(int dst_reg, int amount) +static inline void MMX_PSRAD_imm(int dst_reg, int amount) { addbyte(0x66); /*PSRAD dst_reg, amount*/ addbyte(0x0f); @@ -5187,7 +5212,7 @@ static void MMX_PSRAD_imm(int dst_reg, int amount) addbyte(0xc0 | dst_reg | 0x20); addbyte(amount); } -static void MMX_PSLLD_imm(int dst_reg, int amount) +static inline void MMX_PSLLD_imm(int dst_reg, int amount) { addbyte(0x66); /*PSLLD dst_reg, amount*/ addbyte(0x0f); @@ -5196,7 +5221,7 @@ static void MMX_PSLLD_imm(int dst_reg, int amount) addbyte(amount); } -static void MMX_PSRLQ_imm(int dst_reg, int amount) +static inline void MMX_PSRLQ_imm(int dst_reg, int amount) { addbyte(0x66); /*PSRLQ dst_reg, amount*/ addbyte(0x0f); @@ -5204,7 +5229,7 @@ static void MMX_PSRLQ_imm(int dst_reg, int amount) addbyte(0xc0 | dst_reg | 0x10); addbyte(amount); } -static void MMX_PSRAQ_imm(int dst_reg, int amount) +static inline void MMX_PSRAQ_imm(int dst_reg, int amount) { addbyte(0x66); /*PSRAQ dst_reg, amount*/ addbyte(0x0f); @@ -5212,7 +5237,7 @@ static void MMX_PSRAQ_imm(int dst_reg, int amount) addbyte(0xc0 | dst_reg | 0x20); addbyte(amount); } -static void MMX_PSLLQ_imm(int dst_reg, int amount) +static inline void MMX_PSLLQ_imm(int dst_reg, int amount) { addbyte(0x66); /*PSLLQ dst_reg, amount*/ addbyte(0x0f); @@ -5222,14 +5247,14 @@ static void MMX_PSLLQ_imm(int dst_reg, int amount) } -static void SAVE_EA() +static inline void SAVE_EA() { addbyte(0x89); /*MOV [ESP+0x24], EAX*/ addbyte(0x44); addbyte(0x24); addbyte(0x24); } -static void LOAD_EA() +static inline void LOAD_EA() { addbyte(0x8b); /*MOV EAX, [ESP+0x24]*/ addbyte(0x44); @@ -5239,18 +5264,23 @@ static void LOAD_EA() #define MEM_CHECK_WRITE_B MEM_CHECK_WRITE -static void MEM_CHECK_WRITE(x86seg *seg) +static inline void MEM_CHECK_WRITE(x86seg *seg) { - uint8_t *jump1, *jump2; + uint8_t *jump1, *jump2, *jump3 = NULL; CHECK_SEG_WRITE(seg); - if (IS_32_ADDR(&seg->base)) + if ((seg == &_ds && codegen_flat_ds) || (seg == &_ss && codegen_flat_ss)) + { + addbyte(0x31); /*XOR ESI, ESI*/ + addbyte(0xf6); + } + else if (IS_32_ADDR(&seg->base)) { addbyte(0x8b); /*MOV ESI, seg->base*/ addbyte(0x34); addbyte(0x25); - addlong((uint32_t)&seg->base); + addlong((uint32_t)(uintptr_t)&seg->base); } else { @@ -5264,37 +5294,66 @@ static void MEM_CHECK_WRITE(x86seg *seg) /*seg = ESI, addr = EAX*/ + if (IS_32_ADDR(&cr0)) + { + addbyte(0x83); /*CMP cr0, 0*/ + addbyte(0x3c); + addbyte(0x25); + addlong((uint32_t)(uintptr_t)&cr0); + addbyte(0); + } + else + { + addbyte(0x48); /*MOV RDI, &cr0*/ + addbyte(0xbf); + addquad((uint64_t)&cr0); + addbyte(0x83); /*CMPL [RDI], 0*/ + addbyte(0x3f); + addbyte(0); + } addbyte(0x67); /*LEA EDI, [EAX+ESI]*/ addbyte(0x8d); addbyte(0x3c); addbyte(0x30); - addbyte(0x83); /*CMP cr0, 0*/ - addbyte(0x3c); - addbyte(0x25); - addlong((uint32_t)&cr0); - addbyte(0); addbyte(0x79); /*JNS +*/ jump1 = &codeblock[block_current].data[block_pos]; addbyte(0); -// addbyte(0xc3); /*RET*/ addbyte(0xc1); /*SHR EDI, 12*/ addbyte(0xef); addbyte(12); - addbyte(0x83); /*CMP ESI, -1*/ - addbyte(0xfe); - addbyte(-1); - addbyte(0x74); /*JE slowpath*/ - addbyte(10); - addbyte(0x83); /*CMP writelookup2[RDI*8],-1*/ - addbyte(0x3c); - addbyte(0xfd); - addlong((uint32_t)writelookup2); - addbyte(-1); + if (!(seg == &_ds && codegen_flat_ds) && !(seg == &_ss && codegen_flat_ss)) + { + addbyte(0x83); /*CMP ESI, -1*/ + addbyte(0xfe); + addbyte(-1); + addbyte(0x74); /*JE slowpath*/ + jump3 = &codeblock[block_current].data[block_pos]; + addbyte(0); + } + if (IS_32_ADDR(writelookup2)) + { + addbyte(0x83); /*CMP writelookup2[RDI*8],-1*/ + addbyte(0x3c); + addbyte(0xfd); + addlong((uint32_t)(uintptr_t)writelookup2); + addbyte(-1); + } + else + { + addbyte(0x48); /*MOV RCX, writelookup2*/ + addbyte(0xb9); + addquad((uint64_t)writelookup2); + addbyte(0x83); /*CMP [RCX+RDI*8], -1*/ + addbyte(0x3c); + addbyte(0xf9); + addbyte(-1); + } addbyte(0x75); /*JNE +*/ jump2 = &codeblock[block_current].data[block_pos]; addbyte(0); -// addbyte(0xc3); /*RET*/ - + + if (!(seg == &_ds && codegen_flat_ds) && !(seg == &_ss && codegen_flat_ss)) + *jump3 = (uintptr_t)&codeblock[block_current].data[block_pos] - (uintptr_t)jump3 - 1; /*slowpath:*/ addbyte(0x67); /*LEA EDI, [EAX+ESI]*/ addbyte(0x8d); @@ -5305,46 +5364,38 @@ static void MEM_CHECK_WRITE(x86seg *seg) load_param_1_reg_32(REG_EDI); load_param_2_32(&codeblock[block_current], 1); - -// addbyte(0x6a); /*PUSH 1*/ -// addbyte(1); -// addbyte(0x57); /*PUSH EDI*/ - call(&codeblock[block_current], mmutranslatereal); -// addbyte(0x48); /*ADD ESP, 8*/ -// addbyte(0x83); -// addbyte(0xc4); -// addbyte(8); + call(&codeblock[block_current], (uintptr_t)mmutranslatereal); addbyte(0x80); /*CMP abrt, 0*/ addbyte(0x7d); - addbyte(cpu_state_offset(abrt)); + addbyte((uint8_t)cpu_state_offset(abrt)); addbyte(0); addbyte(0x0f); /*JNE mem_abrt_rout*/ addbyte(0x85); - addlong((uintptr_t)&codeblock[block_current].data[BLOCK_EXIT_OFFSET] - ((uint32_t)(&codeblock[block_current].data[block_pos]) + 4)); -// addbyte(0xc3); /*RET*/ + addlong((uintptr_t)&codeblock[block_current].data[BLOCK_EXIT_OFFSET] - ((uintptr_t)(&codeblock[block_current].data[block_pos]) + 4)); *jump1 = (uintptr_t)&codeblock[block_current].data[block_pos] - (uintptr_t)jump1 - 1; *jump2 = (uintptr_t)&codeblock[block_current].data[block_pos] - (uintptr_t)jump2 - 1; - - -// addbyte(0xe8); /*CALL mem_store_addr_ea_b*/ -// addlong(mem_check_write - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); LOAD_EA(); } -static void MEM_CHECK_WRITE_W(x86seg *seg) +static inline void MEM_CHECK_WRITE_W(x86seg *seg) { - uint8_t *jump1, *jump2, *jump3, *jump4; + uint8_t *jump1, *jump2, *jump3, *jump4 = NULL; int jump_pos; CHECK_SEG_WRITE(seg); - if (IS_32_ADDR(&seg->base)) + if ((seg == &_ds && codegen_flat_ds) || (seg == &_ss && codegen_flat_ss)) + { + addbyte(0x31); /*XOR ESI, ESI*/ + addbyte(0xf6); + } + else if (IS_32_ADDR(&seg->base)) { addbyte(0x8b); /*MOV ESI, seg->base*/ addbyte(0x34); addbyte(0x25); - addlong((uint32_t)&seg->base); + addlong((uint32_t)(uintptr_t)&seg->base); } else { @@ -5358,27 +5409,45 @@ static void MEM_CHECK_WRITE_W(x86seg *seg) /*seg = ESI, addr = EAX*/ + if (IS_32_ADDR(&cr0)) + { + addbyte(0x83); /*CMP cr0, 0*/ + addbyte(0x3c); + addbyte(0x25); + addlong((uint32_t)(uintptr_t)&cr0); + addbyte(0); + } + else + { + addbyte(0x48); /*MOV RDI, &cr0*/ + addbyte(0xbf); + addquad((uint64_t)&cr0); + addbyte(0x83); /*CMPL [RDI], 0*/ + addbyte(0x3f); + addbyte(0); + } addbyte(0x67); /*LEA EDI, [EAX+ESI]*/ addbyte(0x8d); addbyte(0x3c); addbyte(0x30); - addbyte(0x83); /*CMP cr0, 0*/ - addbyte(0x3c); - addbyte(0x25); - addlong((uint32_t)&cr0); - addbyte(0); addbyte(0x79); /*JNS +*/ jump1 = &codeblock[block_current].data[block_pos]; addbyte(0); - addbyte(0x83); /*CMP ESI, -1*/ - addbyte(0xfe); - addbyte(-1); + if (!(seg == &_ds && codegen_flat_ds) && !(seg == &_ss && codegen_flat_ss)) + { + addbyte(0x83); /*CMP ESI, -1*/ + addbyte(0xfe); + addbyte(-1); + } addbyte(0x8d); /*LEA ESI, 1[EDI]*/ addbyte(0x77); addbyte(0x01); - addbyte(0x74); /*JE slowpath*/ - jump4 = &codeblock[block_current].data[block_pos]; - addbyte(0); + if (!(seg == &_ds && codegen_flat_ds) && !(seg == &_ss && codegen_flat_ss)) + { + addbyte(0x74); /*JE slowpath*/ + jump4 = &codeblock[block_current].data[block_pos]; + addbyte(0); + } addbyte(0x89); /*MOV EBX, EDI*/ addbyte(0xfb); addbyte(0xc1); /*SHR EDI, 12*/ @@ -5387,40 +5456,64 @@ static void MEM_CHECK_WRITE_W(x86seg *seg) addbyte(0xc1); /*SHR ESI, 12*/ addbyte(0xee); addbyte(12); - addbyte(0x83); /*CMP writelookup2[RDI*8],-1*/ - addbyte(0x3c); - addbyte(0xfd); - addlong((uint32_t)writelookup2); - addbyte(-1); + if (IS_32_ADDR(writelookup2)) + { + addbyte(0x83); /*CMP writelookup2[RDI*8],-1*/ + addbyte(0x3c); + addbyte(0xfd); + addlong((uint32_t)(uintptr_t)writelookup2); + addbyte(-1); + } + else + { + addbyte(0x48); /*MOV RAX, writelookup2*/ + addbyte(0xb8); + addquad((uint64_t)writelookup2); + addbyte(0x83); /*CMP [RAX+RDI*8], -1*/ + addbyte(0x3c); + addbyte(0xf8); + addbyte(-1); + } addbyte(0x74); /*JE +*/ jump2 = &codeblock[block_current].data[block_pos]; addbyte(0); - addbyte(0x83); /*CMP writelookup2[RSI*8],-1*/ - addbyte(0x3c); - addbyte(0xf5); - addlong((uint32_t)writelookup2); - addbyte(-1); + if (IS_32_ADDR(writelookup2)) + { + addbyte(0x83); /*CMP writelookup2[RSI*8],-1*/ + addbyte(0x3c); + addbyte(0xf5); + addlong((uint32_t)(uintptr_t)writelookup2); + addbyte(-1); + } + else + { + addbyte(0x83); /*CMP [RAX+RSI*8], -1*/ + addbyte(0x3c); + addbyte(0xf0); + addbyte(-1); + } addbyte(0x75); /*JNE +*/ jump3 = &codeblock[block_current].data[block_pos]; addbyte(0); /*slowpath:*/ *jump2 = (uintptr_t)&codeblock[block_current].data[block_pos] - (uintptr_t)jump2 - 1; - *jump4 = (uintptr_t)&codeblock[block_current].data[block_pos] - (uintptr_t)jump4 - 1; + if (!(seg == &_ds && codegen_flat_ds) && !(seg == &_ss && codegen_flat_ss)) + *jump4 = (uintptr_t)&codeblock[block_current].data[block_pos] - (uintptr_t)jump4 - 1; jump_pos = block_pos; load_param_1_reg_32(REG_EBX); load_param_2_32(&codeblock[block_current], 1); - call(&codeblock[block_current], mmutranslatereal); + call(&codeblock[block_current], (uintptr_t)mmutranslatereal); addbyte(0x83); /*ADD EBX, 1*/ addbyte(0xc3); addbyte(1); addbyte(0x80); /*CMP abrt, 0*/ addbyte(0x7d); - addbyte(cpu_state_offset(abrt)); + addbyte((uint8_t)cpu_state_offset(abrt)); addbyte(0); addbyte(0x0f); /*JNE mem_abrt_rout*/ addbyte(0x85); - addlong((uintptr_t)&codeblock[block_current].data[BLOCK_EXIT_OFFSET] - ((uint32_t)(&codeblock[block_current].data[block_pos]) + 4)); + addlong((uintptr_t)&codeblock[block_current].data[BLOCK_EXIT_OFFSET] - ((uintptr_t)(&codeblock[block_current].data[block_pos]) + 4)); /*If bits 0-11 of the address are now 0 then this crosses a page, so loop back*/ addbyte(0xf7); /*TEST $fff, EBX*/ addbyte(0xc3); @@ -5434,19 +5527,24 @@ static void MEM_CHECK_WRITE_W(x86seg *seg) LOAD_EA(); } -static void MEM_CHECK_WRITE_L(x86seg *seg) +static inline void MEM_CHECK_WRITE_L(x86seg *seg) { - uint8_t *jump1, *jump2, *jump3, *jump4; + uint8_t *jump1, *jump2, *jump3, *jump4 = NULL; int jump_pos; CHECK_SEG_WRITE(seg); - if (IS_32_ADDR(&seg->base)) + if ((seg == &_ds && codegen_flat_ds) || (seg == &_ss && codegen_flat_ss)) + { + addbyte(0x31); /*XOR ESI, ESI*/ + addbyte(0xf6); + } + else if (IS_32_ADDR(&seg->base)) { addbyte(0x8b); /*MOV ESI, seg->base*/ addbyte(0x34); addbyte(0x25); - addlong((uint32_t)&seg->base); + addlong((uint32_t)(uintptr_t)&seg->base); } else { @@ -5460,27 +5558,45 @@ static void MEM_CHECK_WRITE_L(x86seg *seg) /*seg = ESI, addr = EAX*/ + if (IS_32_ADDR(&cr0)) + { + addbyte(0x83); /*CMP cr0, 0*/ + addbyte(0x3c); + addbyte(0x25); + addlong((uint32_t)(uintptr_t)&cr0); + addbyte(0); + } + else + { + addbyte(0x48); /*MOV RDI, &cr0*/ + addbyte(0xbf); + addquad((uint64_t)&cr0); + addbyte(0x83); /*CMPL [RDI], 0*/ + addbyte(0x3f); + addbyte(0); + } addbyte(0x67); /*LEA EDI, [EAX+ESI]*/ addbyte(0x8d); addbyte(0x3c); addbyte(0x30); - addbyte(0x83); /*CMP cr0, 0*/ - addbyte(0x3c); - addbyte(0x25); - addlong((uint32_t)&cr0); - addbyte(0); addbyte(0x79); /*JNS +*/ jump1 = &codeblock[block_current].data[block_pos]; addbyte(0); - addbyte(0x83); /*CMP ESI, -1*/ - addbyte(0xfe); - addbyte(-1); + if (!(seg == &_ds && codegen_flat_ds) && !(seg == &_ss && codegen_flat_ss)) + { + addbyte(0x83); /*CMP ESI, -1*/ + addbyte(0xfe); + addbyte(-1); + } addbyte(0x8d); /*LEA ESI, 3[EDI]*/ addbyte(0x77); addbyte(0x03); - addbyte(0x74); /*JE slowpath*/ - jump4 = &codeblock[block_current].data[block_pos]; - addbyte(0); + if (!(seg == &_ds && codegen_flat_ds) && !(seg == &_ss && codegen_flat_ss)) + { + addbyte(0x74); /*JE slowpath*/ + jump4 = &codeblock[block_current].data[block_pos]; + addbyte(0); + } addbyte(0x89); /*MOV EBX, EDI*/ addbyte(0xfb); addbyte(0xc1); /*SHR EDI, 12*/ @@ -5489,40 +5605,64 @@ static void MEM_CHECK_WRITE_L(x86seg *seg) addbyte(0xc1); /*SHR ESI, 12*/ addbyte(0xee); addbyte(12); - addbyte(0x83); /*CMP writelookup2[RDI*8],-1*/ - addbyte(0x3c); - addbyte(0xfd); - addlong((uint32_t)writelookup2); - addbyte(-1); + if (IS_32_ADDR(writelookup2)) + { + addbyte(0x83); /*CMP writelookup2[RDI*8],-1*/ + addbyte(0x3c); + addbyte(0xfd); + addlong((uint32_t)(uintptr_t)writelookup2); + addbyte(-1); + } + else + { + addbyte(0x48); /*MOV RAX, writelookup2*/ + addbyte(0xb8); + addquad((uint64_t)writelookup2); + addbyte(0x83); /*CMP [RAX+RDI*8], -1*/ + addbyte(0x3c); + addbyte(0xf8); + addbyte(-1); + } addbyte(0x74); /*JE slowpath*/ jump2 = &codeblock[block_current].data[block_pos]; addbyte(0); - addbyte(0x83); /*CMP writelookup2[RSI*8],-1*/ - addbyte(0x3c); - addbyte(0xf5); - addlong((uint32_t)writelookup2); - addbyte(-1); + if (IS_32_ADDR(writelookup2)) + { + addbyte(0x83); /*CMP writelookup2[RSI*8],-1*/ + addbyte(0x3c); + addbyte(0xf5); + addlong((uint32_t)(uintptr_t)writelookup2); + addbyte(-1); + } + else + { + addbyte(0x83); /*CMP [RAX+RSI*8], -1*/ + addbyte(0x3c); + addbyte(0xf0); + addbyte(-1); + } addbyte(0x75); /*JNE +*/ jump3 = &codeblock[block_current].data[block_pos]; addbyte(0); /*slowpath:*/ *jump2 = (uintptr_t)&codeblock[block_current].data[block_pos] - (uintptr_t)jump2 - 1; - *jump4 = (uintptr_t)&codeblock[block_current].data[block_pos] - (uintptr_t)jump4 - 1; + if (!(seg == &_ds && codegen_flat_ds) && !(seg == &_ss && codegen_flat_ss)) + *jump4 = (uintptr_t)&codeblock[block_current].data[block_pos] - (uintptr_t)jump4 - 1; jump_pos = block_pos; load_param_1_reg_32(REG_EBX); load_param_2_32(&codeblock[block_current], 1); - call(&codeblock[block_current], mmutranslatereal); + call(&codeblock[block_current], (uintptr_t)mmutranslatereal); addbyte(0x83); /*ADD EBX, 3*/ addbyte(0xc3); addbyte(3); addbyte(0x80); /*CMP abrt, 0*/ addbyte(0x7d); - addbyte(cpu_state_offset(abrt)); + addbyte((uint8_t)cpu_state_offset(abrt)); addbyte(0); addbyte(0x0f); /*JNE mem_abrt_rout*/ addbyte(0x85); - addlong((uintptr_t)&codeblock[block_current].data[BLOCK_EXIT_OFFSET] - ((uint32_t)(&codeblock[block_current].data[block_pos]) + 4)); + addlong((uintptr_t)&codeblock[block_current].data[BLOCK_EXIT_OFFSET] - ((uintptr_t)(&codeblock[block_current].data[block_pos]) + 4)); /*If bits 0-11 of the address are now 0 then this crosses a page, so loop back*/ addbyte(0xf7); /*TEST $ffc, EBX*/ addbyte(0xc3); @@ -5536,14 +5676,19 @@ static void MEM_CHECK_WRITE_L(x86seg *seg) LOAD_EA(); } -static int MEM_LOAD_ADDR_EA_B_NO_ABRT(x86seg *seg) +static inline int MEM_LOAD_ADDR_EA_B_NO_ABRT(x86seg *seg) { - if (IS_32_ADDR(&seg->base)) + if ((seg == &_ds && codegen_flat_ds) || (seg == &_ss && codegen_flat_ss)) + { + addbyte(0x31); /*XOR ECX, ECX*/ + addbyte(0xc9); + } + else if (IS_32_ADDR(&seg->base)) { addbyte(0x8b); /*MOVL ECX, seg->base*/ addbyte(0x0c); addbyte(0x25); - addlong((uint32_t)&seg->base); + addlong((uint32_t)(uintptr_t)&seg->base); } else { @@ -5569,7 +5714,7 @@ static int MEM_LOAD_ADDR_EA_B_NO_ABRT(x86seg *seg) addbyte(0x8b); addbyte(0x34); addbyte(0xf5); - addlong((uint32_t)readlookup2); + addlong((uint32_t)(uintptr_t)readlookup2); } else { @@ -5594,7 +5739,7 @@ static int MEM_LOAD_ADDR_EA_B_NO_ABRT(x86seg *seg) /*slowpath:*/ load_param_1_reg_32(REG_ECX); load_param_2_reg_32(REG_EAX); - call_long(readmemb386l); + call_long((uintptr_t)readmemb386l); addbyte(0x89); /*MOV ECX, EAX*/ addbyte(0xc1); /*done:*/ @@ -5603,14 +5748,19 @@ static int MEM_LOAD_ADDR_EA_B_NO_ABRT(x86seg *seg) return REG_ECX; } -static int MEM_LOAD_ADDR_EA_W_NO_ABRT(x86seg *seg) +static inline int MEM_LOAD_ADDR_EA_W_NO_ABRT(x86seg *seg) { - if (IS_32_ADDR(&seg->base)) + if ((seg == &_ds && codegen_flat_ds) || (seg == &_ss && codegen_flat_ss)) + { + addbyte(0x31); /*XOR ECX, ECX*/ + addbyte(0xc9); + } + else if (IS_32_ADDR(&seg->base)) { addbyte(0x8b); /*MOVL ECX, seg->base*/ addbyte(0x0c); addbyte(0x25); - addlong((uint32_t)&seg->base); + addlong((uint32_t)(uintptr_t)&seg->base); } else { @@ -5624,16 +5774,14 @@ static int MEM_LOAD_ADDR_EA_W_NO_ABRT(x86seg *seg) addbyte(0x8d); addbyte(0x34); addbyte(0x08); - addbyte(0x67); /*LEA EDI, 1[ESI]*/ - addbyte(0x8d); - addbyte(0x7e); - addbyte(0x01); + addbyte(0x89); /*MOV EDI, ESI*/ + addbyte(0xf7); addbyte(0xc1); /*SHR ESI, 12*/ addbyte(0xe8 | REG_ESI); addbyte(12); - addbyte(0xf7); /*TEST EDI, 0xfff*/ + addbyte(0xf7); /*TEST EDI, 1*/ addbyte(0xc7); - addlong(0xfff); + addlong(1); if (IS_32_ADDR(readlookup2)) { addbyte(0x67); /*MOV RSI, readlookup2[ESI*8]*/ @@ -5641,7 +5789,7 @@ static int MEM_LOAD_ADDR_EA_W_NO_ABRT(x86seg *seg) addbyte(0x8b); addbyte(0x34); addbyte(0xf5); - addlong((uint32_t)readlookup2); + addlong((uint32_t)(uintptr_t)readlookup2); } else { @@ -5653,99 +5801,100 @@ static int MEM_LOAD_ADDR_EA_W_NO_ABRT(x86seg *seg) addbyte(0x34); addbyte(0xf2); } - addbyte(0x74); /*JE slowpath*/ - addbyte(3+2+5+2); - addbyte(0x83); /*CMP ESI, -1*/ - addbyte(0xf8 | REG_ESI); - addbyte(-1); - addbyte(0x74); /*JE slowpath*/ - addbyte(5+2); - addbyte(0x66); /*MOV AX,-1[RDI+RSI]*/ - addbyte(0x8b); - addbyte(0x44); - addbyte(REG_EDI | (REG_ESI << 3)); - addbyte(-1); - addbyte(0xeb); /*JMP done*/ - addbyte(2+2+12); - /*slowpath:*/ - load_param_1_reg_32(REG_ECX); - load_param_2_reg_32(REG_EAX); - call_long(readmemwl); - addbyte(0x89); /*MOV ECX, EAX*/ - addbyte(0xc1); - /*done:*/ - - host_reg_mapping[REG_ECX] = 8; - - return REG_ECX; -} -static int MEM_LOAD_ADDR_EA_L_NO_ABRT(x86seg *seg) -{ - if (IS_32_ADDR(&seg->base)) - { - addbyte(0x8b); /*MOVL ECX, seg->base*/ - addbyte(0x0c); - addbyte(0x25); - addlong((uint32_t)&seg->base); - } - else - { - addbyte(0x48); /*MOV RSI, &seg->base*/ - addbyte(0xb8 | REG_ESI); - addquad((uint64_t)&seg->base); - addbyte(0x8b); /*MOV ECX, [RSI]*/ - addbyte(0x0e); - } - addbyte(0x67); /*LEA ESI, (EAX,ECX)*/ - addbyte(0x8d); - addbyte(0x34); - addbyte(0x08); - addbyte(0x67); /*LEA EDI, 3[ESI]*/ - addbyte(0x8d); - addbyte(0x7e); - addbyte(0x03); - addbyte(0xc1); /*SHR ESI, 12*/ - addbyte(0xe8 | REG_ESI); - addbyte(12); - addbyte(0xf7); /*TEST EDI, 0xffc*/ - addbyte(0xc7); - addlong(0xffc); - if (IS_32_ADDR(readlookup2)) - { - addbyte(0x67); /*MOV RSI, readlookup2[ESI*8]*/ - addbyte(0x48); - addbyte(0x8b); - addbyte(0x34); - addbyte(0xf5); - addlong((uint32_t)readlookup2); - } - else - { - addbyte(0x48); /*MOV RDX, readlookup2*/ - addbyte(0xb8 | REG_EDX); - addquad((uint64_t)readlookup2); - addbyte(0x48); /*MOV RSI, [RDX+RSI*8]*/ - addbyte(0x8b); - addbyte(0x34); - addbyte(0xf2); - } - addbyte(0x74); /*JE slowpath*/ + addbyte(0x75); /*JNE slowpath*/ addbyte(3+2+4+2); addbyte(0x83); /*CMP ESI, -1*/ addbyte(0xf8 | REG_ESI); addbyte(-1); addbyte(0x74); /*JE slowpath*/ addbyte(4+2); - addbyte(0x8b); /*MOV EAX,-3[RDI+RSI]*/ - addbyte(0x44); + addbyte(0x66); /*MOV AX,[RDI+RSI]*/ + addbyte(0x8b); + addbyte(0x04); addbyte(REG_EDI | (REG_ESI << 3)); - addbyte(-3); addbyte(0xeb); /*JMP done*/ addbyte(2+2+12); /*slowpath:*/ load_param_1_reg_32(REG_ECX); load_param_2_reg_32(REG_EAX); - call_long(readmemll); + call_long((uintptr_t)readmemwl); + addbyte(0x89); /*MOV ECX, EAX*/ + addbyte(0xc1); + /*done:*/ + + host_reg_mapping[REG_ECX] = 8; + + return REG_ECX; +} +static inline int MEM_LOAD_ADDR_EA_L_NO_ABRT(x86seg *seg) +{ + if ((seg == &_ds && codegen_flat_ds) || (seg == &_ss && codegen_flat_ss)) + { + addbyte(0x31); /*XOR ECX, ECX*/ + addbyte(0xc9); + } + else if (IS_32_ADDR(&seg->base)) + { + addbyte(0x8b); /*MOVL ECX, seg->base*/ + addbyte(0x0c); + addbyte(0x25); + addlong((uint32_t)(uintptr_t)&seg->base); + } + else + { + addbyte(0x48); /*MOV RSI, &seg->base*/ + addbyte(0xb8 | REG_ESI); + addquad((uint64_t)&seg->base); + addbyte(0x8b); /*MOV ECX, [RSI]*/ + addbyte(0x0e); + } + addbyte(0x67); /*LEA ESI, (EAX,ECX)*/ + addbyte(0x8d); + addbyte(0x34); + addbyte(0x08); + addbyte(0x89); /*MOV EDI, ESI*/ + addbyte(0xf7); + addbyte(0xc1); /*SHR ESI, 12*/ + addbyte(0xe8 | REG_ESI); + addbyte(12); + addbyte(0xf7); /*TEST EDI, 3*/ + addbyte(0xc7); + addlong(3); + if (IS_32_ADDR(readlookup2)) + { + addbyte(0x67); /*MOV RSI, readlookup2[ESI*8]*/ + addbyte(0x48); + addbyte(0x8b); + addbyte(0x34); + addbyte(0xf5); + addlong((uint32_t)(uintptr_t)readlookup2); + } + else + { + addbyte(0x48); /*MOV RDX, readlookup2*/ + addbyte(0xb8 | REG_EDX); + addquad((uint64_t)readlookup2); + addbyte(0x48); /*MOV RSI, [RDX+RSI*8]*/ + addbyte(0x8b); + addbyte(0x34); + addbyte(0xf2); + } + addbyte(0x75); /*JNE slowpath*/ + addbyte(3+2+3+2); + addbyte(0x83); /*CMP ESI, -1*/ + addbyte(0xf8 | REG_ESI); + addbyte(-1); + addbyte(0x74); /*JE slowpath*/ + addbyte(3+2); + addbyte(0x8b); /*MOV EAX,[RDI+RSI]*/ + addbyte(0x04); + addbyte(REG_EDI | (REG_ESI << 3)); + addbyte(0xeb); /*JMP done*/ + addbyte(2+2+12); + /*slowpath:*/ + load_param_1_reg_32(REG_ECX); + load_param_2_reg_32(REG_EAX); + call_long((uintptr_t)readmemll); addbyte(0x89); /*MOV ECX, EAX*/ addbyte(0xc1); /*done:*/ @@ -5755,7 +5904,7 @@ static int MEM_LOAD_ADDR_EA_L_NO_ABRT(x86seg *seg) return REG_ECX; } -static void MEM_STORE_ADDR_EA_B_NO_ABRT(x86seg *seg, int host_reg) +static inline void MEM_STORE_ADDR_EA_B_NO_ABRT(x86seg *seg, int host_reg) { if (host_reg & 0x10) { @@ -5779,12 +5928,17 @@ static void MEM_STORE_ADDR_EA_B_NO_ABRT(x86seg *seg, int host_reg) addbyte(8); host_reg = 8; } - if (IS_32_ADDR(&seg->base)) + if ((seg == &_ds && codegen_flat_ds) || (seg == &_ss && codegen_flat_ss)) + { + addbyte(0x31); /*XOR EBX, EBX*/ + addbyte(0xdb); + } + else if (IS_32_ADDR(&seg->base)) { addbyte(0x8b); /*MOVL EBX, seg->base*/ addbyte(0x1c); addbyte(0x25); - addlong((uint32_t)&seg->base); + addlong((uint32_t)(uintptr_t)&seg->base); } else { @@ -5810,7 +5964,7 @@ static void MEM_STORE_ADDR_EA_B_NO_ABRT(x86seg *seg, int host_reg) addbyte(0x8b); addbyte(0x34); addbyte(0xf5); - addlong((uint32_t)writelookup2); + addlong((uint32_t)(uintptr_t)writelookup2); } else { @@ -5846,17 +6000,22 @@ static void MEM_STORE_ADDR_EA_B_NO_ABRT(x86seg *seg, int host_reg) load_param_3_reg_32(host_reg); load_param_1_reg_32(REG_EBX); load_param_2_reg_32(REG_EAX); - call_long(writememb386l); + call_long((uintptr_t)writememb386l); /*done:*/ } -static void MEM_STORE_ADDR_EA_W_NO_ABRT(x86seg *seg, int host_reg) +static inline void MEM_STORE_ADDR_EA_W_NO_ABRT(x86seg *seg, int host_reg) { - if (IS_32_ADDR(&seg->base)) + if ((seg == &_ds && codegen_flat_ds) || (seg == &_ss && codegen_flat_ss)) + { + addbyte(0x31); /*XOR EBX, EBX*/ + addbyte(0xdb); + } + else if (IS_32_ADDR(&seg->base)) { addbyte(0x8b); /*MOVL EBX, seg->base*/ addbyte(0x1c); addbyte(0x25); - addlong((uint32_t)&seg->base); + addlong((uint32_t)(uintptr_t)&seg->base); } else { @@ -5870,16 +6029,14 @@ static void MEM_STORE_ADDR_EA_W_NO_ABRT(x86seg *seg, int host_reg) addbyte(0x8d); addbyte(0x34); addbyte(0x18); - addbyte(0x67); /*LEA EDI, 1[ESI]*/ - addbyte(0x8d); - addbyte(0x7e); - addbyte(0x01); + addbyte(0x89); /*MOV EDI, ESI*/ + addbyte(0xf7); addbyte(0xc1); /*SHR ESI, 12*/ addbyte(0xe8 | REG_ESI); addbyte(12); - addbyte(0xf7); /*TEST EDI, 0xfff*/ + addbyte(0xf7); /*TEST EDI, 1*/ addbyte(0xc7); - addlong(0xfff); + addlong(1); if (IS_32_ADDR(writelookup2)) { addbyte(0x67); /*MOV RSI, writelookup2[ESI*8]*/ @@ -5887,7 +6044,7 @@ static void MEM_STORE_ADDR_EA_W_NO_ABRT(x86seg *seg, int host_reg) addbyte(0x8b); addbyte(0x34); addbyte(0xf5); - addlong((uint32_t)writelookup2); + addlong((uint32_t)(uintptr_t)writelookup2); } else { @@ -5899,90 +6056,7 @@ static void MEM_STORE_ADDR_EA_W_NO_ABRT(x86seg *seg, int host_reg) addbyte(0x34); addbyte(0xf2); } - addbyte(0x74); /*JE slowpath*/ - addbyte(3+2+((host_reg & 8) ? 6:5)+2); - addbyte(0x83); /*CMP ESI, -1*/ - addbyte(0xf8 | REG_ESI); - addbyte(-1); - addbyte(0x74); /*JE slowpath*/ - addbyte(((host_reg & 8) ? 6:5)+2); - if (host_reg & 8) - { - addbyte(0x66); /*MOV -1[RDI+RSI],host_reg*/ - addbyte(0x44); - addbyte(0x89); - addbyte(0x44 | ((host_reg & 7) << 3)); - addbyte(REG_EDI | (REG_ESI << 3)); - addbyte(-1); - } - else - { - addbyte(0x66); /*MOV -1[RDI+RSI],host_reg*/ - addbyte(0x89); - addbyte(0x44 | (host_reg << 3)); - addbyte(REG_EDI | (REG_ESI << 3)); - addbyte(-1); - } - addbyte(0xeb); /*JMP done*/ - addbyte(2+2+3+12); - /*slowpath:*/ - load_param_3_reg_32(host_reg); - load_param_1_reg_32(REG_EBX); - load_param_2_reg_32(REG_EAX); - call_long(writememwl); - /*done:*/ -} -static void MEM_STORE_ADDR_EA_L_NO_ABRT(x86seg *seg, int host_reg) -{ - if (IS_32_ADDR(&seg->base)) - { - addbyte(0x8b); /*MOVL EBX, seg->base*/ - addbyte(0x1c); - addbyte(0x25); - addlong((uint32_t)&seg->base); - } - else - { - addbyte(0x48); /*MOV RSI, &seg->base*/ - addbyte(0xb8 | REG_ESI); - addquad((uint64_t)&seg->base); - addbyte(0x8b); /*MOV EBX, [RSI]*/ - addbyte(0x1e); - } - addbyte(0x67); /*LEA ESI, (EAX,EBX)*/ - addbyte(0x8d); - addbyte(0x34); - addbyte(0x18); - addbyte(0x67); /*LEA EDI, 3[ESI]*/ - addbyte(0x8d); - addbyte(0x7e); - addbyte(0x03); - addbyte(0xc1); /*SHR ESI, 12*/ - addbyte(0xe8 | REG_ESI); - addbyte(12); - addbyte(0xf7); /*TEST EDI, 0xffc*/ - addbyte(0xc7); - addlong(0xffc); - if (IS_32_ADDR(writelookup2)) - { - addbyte(0x67); /*MOV RSI, writelookup2[ESI*8]*/ - addbyte(0x48); - addbyte(0x8b); - addbyte(0x34); - addbyte(0xf5); - addlong((uint32_t)writelookup2); - } - else - { - addbyte(0x48); /*MOV RDX, writelookup2*/ - addbyte(0xb8 | REG_EDX); - addquad((uint64_t)writelookup2); - addbyte(0x48); /*MOV RSI, [RDX+RSI*8]*/ - addbyte(0x8b); - addbyte(0x34); - addbyte(0xf2); - } - addbyte(0x74); /*JE slowpath*/ + addbyte(0x75); /*JNE slowpath*/ addbyte(3+2+((host_reg & 8) ? 5:4)+2); addbyte(0x83); /*CMP ESI, -1*/ addbyte(0xf8 | REG_ESI); @@ -5991,18 +6065,18 @@ static void MEM_STORE_ADDR_EA_L_NO_ABRT(x86seg *seg, int host_reg) addbyte(((host_reg & 8) ? 5:4)+2); if (host_reg & 8) { - addbyte(0x44); /*MOV -3[RDI+RSI],host_reg*/ + addbyte(0x66); /*MOV [RDI+RSI],host_reg*/ + addbyte(0x44); addbyte(0x89); - addbyte(0x44 | ((host_reg & 7) << 3)); + addbyte(0x04 | ((host_reg & 7) << 3)); addbyte(REG_EDI | (REG_ESI << 3)); - addbyte(-3); } else { - addbyte(0x89); /*MOV -3[RDI+RSI],host_reg*/ - addbyte(0x44 | (host_reg << 3)); + addbyte(0x66); /*MOV [RDI+RSI],host_reg*/ + addbyte(0x89); + addbyte(0x04 | (host_reg << 3)); addbyte(REG_EDI | (REG_ESI << 3)); - addbyte(-3); } addbyte(0xeb); /*JMP done*/ addbyte(2+2+3+12); @@ -6010,18 +6084,100 @@ static void MEM_STORE_ADDR_EA_L_NO_ABRT(x86seg *seg, int host_reg) load_param_3_reg_32(host_reg); load_param_1_reg_32(REG_EBX); load_param_2_reg_32(REG_EAX); - call_long(writememll); + call_long((uintptr_t)writememwl); + /*done:*/ +} +static inline void MEM_STORE_ADDR_EA_L_NO_ABRT(x86seg *seg, int host_reg) +{ + if ((seg == &_ds && codegen_flat_ds) || (seg == &_ss && codegen_flat_ss)) + { + addbyte(0x31); /*XOR EBX, EBX*/ + addbyte(0xdb); + } + else if (IS_32_ADDR(&seg->base)) + { + addbyte(0x8b); /*MOVL EBX, seg->base*/ + addbyte(0x1c); + addbyte(0x25); + addlong((uint32_t)(uintptr_t)&seg->base); + } + else + { + addbyte(0x48); /*MOV RSI, &seg->base*/ + addbyte(0xb8 | REG_ESI); + addquad((uint64_t)&seg->base); + addbyte(0x8b); /*MOV EBX, [RSI]*/ + addbyte(0x1e); + } + addbyte(0x67); /*LEA ESI, (EAX,EBX)*/ + addbyte(0x8d); + addbyte(0x34); + addbyte(0x18); + addbyte(0x89); /*MOV EDI, ESI*/ + addbyte(0xf7); + addbyte(0xc1); /*SHR ESI, 12*/ + addbyte(0xe8 | REG_ESI); + addbyte(12); + addbyte(0xf7); /*TEST EDI, 3*/ + addbyte(0xc7); + addlong(3); + if (IS_32_ADDR(writelookup2)) + { + addbyte(0x67); /*MOV RSI, writelookup2[ESI*8]*/ + addbyte(0x48); + addbyte(0x8b); + addbyte(0x34); + addbyte(0xf5); + addlong((uint32_t)(uintptr_t)writelookup2); + } + else + { + addbyte(0x48); /*MOV RDX, writelookup2*/ + addbyte(0xb8 | REG_EDX); + addquad((uint64_t)writelookup2); + addbyte(0x48); /*MOV RSI, [RDX+RSI*8]*/ + addbyte(0x8b); + addbyte(0x34); + addbyte(0xf2); + } + addbyte(0x75); /*JNE slowpath*/ + addbyte(3+2+((host_reg & 8) ? 4:3)+2); + addbyte(0x83); /*CMP ESI, -1*/ + addbyte(0xf8 | REG_ESI); + addbyte(-1); + addbyte(0x74); /*JE slowpath*/ + addbyte(((host_reg & 8) ? 4:3)+2); + if (host_reg & 8) + { + addbyte(0x44); /*MOV [RDI+RSI],host_reg*/ + addbyte(0x89); + addbyte(0x04 | ((host_reg & 7) << 3)); + addbyte(REG_EDI | (REG_ESI << 3)); + } + else + { + addbyte(0x89); /*MOV [RDI+RSI],host_reg*/ + addbyte(0x04 | (host_reg << 3)); + addbyte(REG_EDI | (REG_ESI << 3)); + } + addbyte(0xeb); /*JMP done*/ + addbyte(2+2+3+12); + /*slowpath:*/ + load_param_3_reg_32(host_reg); + load_param_1_reg_32(REG_EBX); + load_param_2_reg_32(REG_EAX); + call_long((uintptr_t)writememll); /*done:*/ } -static void LOAD_SEG(int host_reg, void *seg) +static inline void LOAD_SEG(int host_reg, void *seg) { load_param_2_64(&codeblock[block_current], (uint64_t)seg); load_param_1_reg_32(host_reg); - CALL_FUNC(loadseg); + CALL_FUNC((uintptr_t)loadseg); addbyte(0x80); /*CMP abrt, 0*/ addbyte(0x7d); - addbyte(cpu_state_offset(abrt)); + addbyte((uint8_t)cpu_state_offset(abrt)); addbyte(0); addbyte(0x0f); /*JNE end*/ addbyte(0x85); diff --git a/src/codegen_ops_x86.h b/src/CPU/codegen_ops_x86.h similarity index 73% rename from src/codegen_ops_x86.h rename to src/CPU/codegen_ops_x86.h index ac6111669..3af481791 100644 --- a/src/codegen_ops_x86.h +++ b/src/CPU/codegen_ops_x86.h @@ -35,14 +35,15 @@ static inline int find_host_xmm_reg() return c; } -static void STORE_IMM_ADDR_B(uintptr_t addr, uint8_t val) +#if 0 +static inline void STORE_IMM_ADDR_B(uintptr_t addr, uint8_t val) { addbyte(0xC6); /*MOVB [addr],val*/ addbyte(0x05); addlong(addr); addbyte(val); } -static void STORE_IMM_ADDR_W(uintptr_t addr, uint16_t val) +static inline void STORE_IMM_ADDR_W(uintptr_t addr, uint16_t val) { addbyte(0x66); /*MOVW [addr],val*/ addbyte(0xC7); @@ -50,7 +51,8 @@ static void STORE_IMM_ADDR_W(uintptr_t addr, uint16_t val) addlong(addr); addword(val); } -static void STORE_IMM_ADDR_L(uintptr_t addr, uint32_t val) +#endif +static inline void STORE_IMM_ADDR_L(uintptr_t addr, uint32_t val) { if (addr >= (uintptr_t)&cpu_state && addr < ((uintptr_t)&cpu_state)+0x100) { @@ -68,33 +70,33 @@ static void STORE_IMM_ADDR_L(uintptr_t addr, uint32_t val) } } -static void STORE_IMM_REG_B(int reg, uint8_t val) +static inline void STORE_IMM_REG_B(int reg, uint8_t val) { addbyte(0xC6); /*MOVB [addr],val*/ addbyte(0x45); if (reg & 4) - addbyte(cpu_state_offset(regs[reg & 3].b.h)); + addbyte((uint8_t)cpu_state_offset(regs[reg & 3].b.h)); else - addbyte(cpu_state_offset(regs[reg & 3].b.l)); + addbyte((uint8_t)cpu_state_offset(regs[reg & 3].b.l)); addbyte(val); } -static void STORE_IMM_REG_W(int reg, uint16_t val) +static inline void STORE_IMM_REG_W(int reg, uint16_t val) { addbyte(0x66); /*MOVW [addr],val*/ addbyte(0xC7); addbyte(0x45); - addbyte(cpu_state_offset(regs[reg & 7].w)); + addbyte((uint8_t)cpu_state_offset(regs[reg & 7].w)); addword(val); } -static void STORE_IMM_REG_L(int reg, uint32_t val) +static inline void STORE_IMM_REG_L(int reg, uint32_t val) { addbyte(0xC7); /*MOVL [addr],val*/ addbyte(0x45); - addbyte(cpu_state_offset(regs[reg & 7].l)); + addbyte((uint8_t)cpu_state_offset(regs[reg & 7].l)); addlong(val); } -static int LOAD_REG_B(int reg) +static inline int LOAD_REG_B(int reg) { int host_reg = find_host_reg(); host_reg_mapping[host_reg] = reg; @@ -103,13 +105,13 @@ static int LOAD_REG_B(int reg) addbyte(0xb6); addbyte(0x45 | (host_reg << 3)); if (reg & 4) - addbyte(cpu_state_offset(regs[reg & 3].b.h)); + addbyte((uint8_t)cpu_state_offset(regs[reg & 3].b.h)); else - addbyte(cpu_state_offset(regs[reg & 3].b.l)); + addbyte((uint8_t)cpu_state_offset(regs[reg & 3].b.l)); return host_reg; } -static int LOAD_REG_W(int reg) +static inline int LOAD_REG_W(int reg) { int host_reg = find_host_reg(); host_reg_mapping[host_reg] = reg; @@ -117,23 +119,23 @@ static int LOAD_REG_W(int reg) addbyte(0x0f); /*MOVZX W[reg],host_reg*/ addbyte(0xb7); addbyte(0x45 | (host_reg << 3)); - addbyte(cpu_state_offset(regs[reg & 7].w)); + addbyte((uint8_t)cpu_state_offset(regs[reg & 7].w)); return host_reg; } -static int LOAD_REG_L(int reg) +static inline int LOAD_REG_L(int reg) { int host_reg = find_host_reg(); host_reg_mapping[host_reg] = reg; addbyte(0x8b); /*MOVL host_reg,[reg]*/ addbyte(0x45 | (host_reg << 3)); - addbyte(cpu_state_offset(regs[reg & 7].l)); + addbyte((uint8_t)cpu_state_offset(regs[reg & 7].l)); return host_reg; } -static int LOAD_VAR_W(uintptr_t addr) +static inline int LOAD_VAR_W(uintptr_t addr) { int host_reg = find_host_reg(); host_reg_mapping[host_reg] = 0; @@ -145,7 +147,7 @@ static int LOAD_VAR_W(uintptr_t addr) return host_reg; } -static int LOAD_VAR_WL(uintptr_t addr) +static inline int LOAD_VAR_WL(uintptr_t addr) { int host_reg = find_host_reg(); host_reg_mapping[host_reg] = 0; @@ -157,7 +159,7 @@ static int LOAD_VAR_WL(uintptr_t addr) return host_reg; } -static int LOAD_VAR_L(uintptr_t addr) +static inline int LOAD_VAR_L(uintptr_t addr) { int host_reg = find_host_reg(); host_reg_mapping[host_reg] = 0; @@ -169,7 +171,7 @@ static int LOAD_VAR_L(uintptr_t addr) return host_reg; } -static int LOAD_REG_IMM(uint32_t imm) +static inline int LOAD_REG_IMM(uint32_t imm) { int host_reg = find_host_reg(); host_reg_mapping[host_reg] = 0; @@ -181,7 +183,7 @@ static int LOAD_REG_IMM(uint32_t imm) return host_reg; } -static int LOAD_HOST_REG(int host_reg) +static inline int LOAD_HOST_REG(int host_reg) { int new_host_reg = find_host_reg(); host_reg_mapping[new_host_reg] = 0; @@ -192,64 +194,64 @@ static int LOAD_HOST_REG(int host_reg) return new_host_reg; } -static void STORE_REG_B_RELEASE(int host_reg) +static inline void STORE_REG_B_RELEASE(int host_reg) { addbyte(0x88); /*MOVB [reg],host_reg*/ addbyte(0x45 | (host_reg << 3)); if (host_reg_mapping[host_reg] & 4) - addbyte(cpu_state_offset(regs[host_reg_mapping[host_reg] & 3].b.h)); + addbyte((uint8_t)cpu_state_offset(regs[host_reg_mapping[host_reg] & 3].b.h)); else - addbyte(cpu_state_offset(regs[host_reg_mapping[host_reg] & 3].b.l)); + addbyte((uint8_t)cpu_state_offset(regs[host_reg_mapping[host_reg] & 3].b.l)); host_reg_mapping[host_reg] = -1; } -static void STORE_REG_W_RELEASE(int host_reg) +static inline void STORE_REG_W_RELEASE(int host_reg) { addbyte(0x66); /*MOVW [reg],host_reg*/ addbyte(0x89); addbyte(0x45 | (host_reg << 3)); - addbyte(cpu_state_offset(regs[host_reg_mapping[host_reg]].w)); + addbyte((uint8_t)cpu_state_offset(regs[host_reg_mapping[host_reg]].w)); host_reg_mapping[host_reg] = -1; } -static void STORE_REG_L_RELEASE(int host_reg) +static inline void STORE_REG_L_RELEASE(int host_reg) { addbyte(0x89); /*MOVL [reg],host_reg*/ addbyte(0x45 | (host_reg << 3)); - addbyte(cpu_state_offset(regs[host_reg_mapping[host_reg]].l)); + addbyte((uint8_t)cpu_state_offset(regs[host_reg_mapping[host_reg]].l)); host_reg_mapping[host_reg] = -1; } -static void STORE_REG_TARGET_B_RELEASE(int host_reg, int guest_reg) +static inline void STORE_REG_TARGET_B_RELEASE(int host_reg, int guest_reg) { addbyte(0x88); /*MOVB [guest_reg],host_reg*/ addbyte(0x45 | (host_reg << 3)); if (guest_reg & 4) - addbyte(cpu_state_offset(regs[guest_reg & 3].b.h)); + addbyte((uint8_t)cpu_state_offset(regs[guest_reg & 3].b.h)); else - addbyte(cpu_state_offset(regs[guest_reg & 3].b.l)); + addbyte((uint8_t)cpu_state_offset(regs[guest_reg & 3].b.l)); host_reg_mapping[host_reg] = -1; } -static void STORE_REG_TARGET_W_RELEASE(int host_reg, int guest_reg) +static inline void STORE_REG_TARGET_W_RELEASE(int host_reg, int guest_reg) { addbyte(0x66); /*MOVW [guest_reg],host_reg*/ addbyte(0x89); addbyte(0x45 | (host_reg << 3)); - addbyte(cpu_state_offset(regs[guest_reg & 7].w)); + addbyte((uint8_t)cpu_state_offset(regs[guest_reg & 7].w)); host_reg_mapping[host_reg] = -1; } -static void STORE_REG_TARGET_L_RELEASE(int host_reg, int guest_reg) +static inline void STORE_REG_TARGET_L_RELEASE(int host_reg, int guest_reg) { addbyte(0x89); /*MOVL [guest_reg],host_reg*/ addbyte(0x45 | (host_reg << 3)); - addbyte(cpu_state_offset(regs[guest_reg & 7].l)); + addbyte((uint8_t)cpu_state_offset(regs[guest_reg & 7].l)); host_reg_mapping[host_reg] = -1; } -static void RELEASE_REG(int host_reg) +static inline void RELEASE_REG(int host_reg) { host_reg_mapping[host_reg] = -1; } -static void STORE_HOST_REG_ADDR_W(uintptr_t addr, int host_reg) +static inline void STORE_HOST_REG_ADDR_W(uintptr_t addr, int host_reg) { if (addr >= (uintptr_t)&cpu_state && addr < ((uintptr_t)&cpu_state)+0x100) { @@ -266,7 +268,7 @@ static void STORE_HOST_REG_ADDR_W(uintptr_t addr, int host_reg) addlong(addr); } } -static void STORE_HOST_REG_ADDR(uintptr_t addr, int host_reg) +static inline void STORE_HOST_REG_ADDR(uintptr_t addr, int host_reg) { if (addr >= (uintptr_t)&cpu_state && addr < ((uintptr_t)&cpu_state)+0x100) { @@ -284,29 +286,29 @@ static void STORE_HOST_REG_ADDR(uintptr_t addr, int host_reg) #define STORE_HOST_REG_ADDR_BL STORE_HOST_REG_ADDR #define STORE_HOST_REG_ADDR_WL STORE_HOST_REG_ADDR -static void ADD_HOST_REG_B(int dst_reg, int src_reg) +static inline void ADD_HOST_REG_B(int dst_reg, int src_reg) { addbyte(0x00); /*ADDB dst_reg, src_reg*/ addbyte(0xc0 | dst_reg | (src_reg << 3)); } -static void ADD_HOST_REG_W(int dst_reg, int src_reg) +static inline void ADD_HOST_REG_W(int dst_reg, int src_reg) { addbyte(0x66); /*ADDW dst_reg, src_reg*/ addbyte(0x01); addbyte(0xc0 | dst_reg | (src_reg << 3)); } -static void ADD_HOST_REG_L(int dst_reg, int src_reg) +static inline void ADD_HOST_REG_L(int dst_reg, int src_reg) { addbyte(0x01); /*ADDL dst_reg, src_reg*/ addbyte(0xc0 | dst_reg | (src_reg << 3)); } -static void ADD_HOST_REG_IMM_B(int host_reg, uint8_t imm) +static inline void ADD_HOST_REG_IMM_B(int host_reg, uint8_t imm) { addbyte(0x80); /*ADDB host_reg, imm*/ addbyte(0xC0 | host_reg); addbyte(imm); } -static void ADD_HOST_REG_IMM_W(int host_reg, uint16_t imm) +static inline void ADD_HOST_REG_IMM_W(int host_reg, uint16_t imm) { if (imm < 0x80 || imm >= 0xff80) { @@ -323,7 +325,7 @@ static void ADD_HOST_REG_IMM_W(int host_reg, uint16_t imm) addword(imm); } } -static void ADD_HOST_REG_IMM(int host_reg, uint32_t imm) +static inline void ADD_HOST_REG_IMM(int host_reg, uint32_t imm) { if (imm < 0x80 || imm >= 0xffffff80) { @@ -341,12 +343,12 @@ static void ADD_HOST_REG_IMM(int host_reg, uint32_t imm) #define AND_HOST_REG_B AND_HOST_REG_L #define AND_HOST_REG_W AND_HOST_REG_L -static void AND_HOST_REG_L(int dst_reg, int src_reg) +static inline void AND_HOST_REG_L(int dst_reg, int src_reg) { addbyte(0x21); /*ANDL dst_reg, src_reg*/ addbyte(0xc0 | dst_reg | (src_reg << 3)); } -static void AND_HOST_REG_IMM(int host_reg, uint32_t imm) +static inline void AND_HOST_REG_IMM(int host_reg, uint32_t imm) { if (imm < 0x80 || imm >= 0xffffff80) { @@ -361,25 +363,25 @@ static void AND_HOST_REG_IMM(int host_reg, uint32_t imm) addlong(imm); } } -static int TEST_HOST_REG_B(int dst_reg, int src_reg) +static inline int TEST_HOST_REG_B(int dst_reg, int src_reg) { AND_HOST_REG_B(dst_reg, src_reg); return dst_reg; } -static int TEST_HOST_REG_W(int dst_reg, int src_reg) +static inline int TEST_HOST_REG_W(int dst_reg, int src_reg) { AND_HOST_REG_W(dst_reg, src_reg); return dst_reg; } -static int TEST_HOST_REG_L(int dst_reg, int src_reg) +static inline int TEST_HOST_REG_L(int dst_reg, int src_reg) { AND_HOST_REG_L(dst_reg, src_reg); return dst_reg; } -static int TEST_HOST_REG_IMM(int host_reg, uint32_t imm) +static inline int TEST_HOST_REG_IMM(int host_reg, uint32_t imm) { AND_HOST_REG_IMM(host_reg, imm); @@ -388,12 +390,12 @@ static int TEST_HOST_REG_IMM(int host_reg, uint32_t imm) #define OR_HOST_REG_B OR_HOST_REG_L #define OR_HOST_REG_W OR_HOST_REG_L -static void OR_HOST_REG_L(int dst_reg, int src_reg) +static inline void OR_HOST_REG_L(int dst_reg, int src_reg) { addbyte(0x09); /*ORL dst_reg, src_reg*/ addbyte(0xc0 | dst_reg | (src_reg << 3)); } -static void OR_HOST_REG_IMM(int host_reg, uint32_t imm) +static inline void OR_HOST_REG_IMM(int host_reg, uint32_t imm) { if (imm < 0x80 || imm >= 0xffffff80) { @@ -409,46 +411,46 @@ static void OR_HOST_REG_IMM(int host_reg, uint32_t imm) } } -static void NEG_HOST_REG_B(int reg) +static inline void NEG_HOST_REG_B(int reg) { addbyte(0xf6); addbyte(0xd8 | reg); } -static void NEG_HOST_REG_W(int reg) +static inline void NEG_HOST_REG_W(int reg) { addbyte(0x66); addbyte(0xf7); addbyte(0xd8 | reg); } -static void NEG_HOST_REG_L(int reg) +static inline void NEG_HOST_REG_L(int reg) { addbyte(0xf7); addbyte(0xd8 | reg); } -static void SUB_HOST_REG_B(int dst_reg, int src_reg) +static inline void SUB_HOST_REG_B(int dst_reg, int src_reg) { addbyte(0x28); /*SUBB dst_reg, src_reg*/ addbyte(0xc0 | dst_reg | (src_reg << 3)); } -static void SUB_HOST_REG_W(int dst_reg, int src_reg) +static inline void SUB_HOST_REG_W(int dst_reg, int src_reg) { addbyte(0x66); /*SUBW dst_reg, src_reg*/ addbyte(0x29); addbyte(0xc0 | dst_reg | (src_reg << 3)); } -static void SUB_HOST_REG_L(int dst_reg, int src_reg) +static inline void SUB_HOST_REG_L(int dst_reg, int src_reg) { addbyte(0x29); /*SUBL dst_reg, src_reg*/ addbyte(0xc0 | dst_reg | (src_reg << 3)); } -static void SUB_HOST_REG_IMM_B(int host_reg, uint8_t imm) +static inline void SUB_HOST_REG_IMM_B(int host_reg, uint8_t imm) { addbyte(0x80); /*SUBB host_reg, imm*/ addbyte(0xE8 | host_reg); addbyte(imm); } -static void SUB_HOST_REG_IMM_W(int host_reg, uint16_t imm) +static inline void SUB_HOST_REG_IMM_W(int host_reg, uint16_t imm) { if (imm < 0x80 || imm >= 0xff80) { @@ -465,7 +467,7 @@ static void SUB_HOST_REG_IMM_W(int host_reg, uint16_t imm) addword(imm); } } -static void SUB_HOST_REG_IMM(int host_reg, uint32_t imm) +static inline void SUB_HOST_REG_IMM(int host_reg, uint32_t imm) { if (imm < 0x80 || imm >= 0xffffff80) { @@ -481,37 +483,37 @@ static void SUB_HOST_REG_IMM(int host_reg, uint32_t imm) } } -static int CMP_HOST_REG_B(int dst_reg, int src_reg) +static inline int CMP_HOST_REG_B(int dst_reg, int src_reg) { SUB_HOST_REG_B(dst_reg, src_reg); return dst_reg; } -static int CMP_HOST_REG_W(int dst_reg, int src_reg) +static inline int CMP_HOST_REG_W(int dst_reg, int src_reg) { SUB_HOST_REG_W(dst_reg, src_reg); return dst_reg; } -static int CMP_HOST_REG_L(int dst_reg, int src_reg) +static inline int CMP_HOST_REG_L(int dst_reg, int src_reg) { SUB_HOST_REG_L(dst_reg, src_reg); return dst_reg; } -static int CMP_HOST_REG_IMM_B(int host_reg, uint8_t imm) +static inline int CMP_HOST_REG_IMM_B(int host_reg, uint8_t imm) { SUB_HOST_REG_IMM_B(host_reg, imm); return host_reg; } -static int CMP_HOST_REG_IMM_W(int host_reg, uint16_t imm) +static inline int CMP_HOST_REG_IMM_W(int host_reg, uint16_t imm) { SUB_HOST_REG_IMM_W(host_reg, imm); return host_reg; } -static int CMP_HOST_REG_IMM_L(int host_reg, uint32_t imm) +static inline int CMP_HOST_REG_IMM_L(int host_reg, uint32_t imm) { SUB_HOST_REG_IMM(host_reg, imm); @@ -520,12 +522,12 @@ static int CMP_HOST_REG_IMM_L(int host_reg, uint32_t imm) #define XOR_HOST_REG_B XOR_HOST_REG_L #define XOR_HOST_REG_W XOR_HOST_REG_L -static void XOR_HOST_REG_L(int dst_reg, int src_reg) +static inline void XOR_HOST_REG_L(int dst_reg, int src_reg) { addbyte(0x31); /*XORL dst_reg, src_reg*/ addbyte(0xc0 | dst_reg | (src_reg << 3)); } -static void XOR_HOST_REG_IMM(int host_reg, uint32_t imm) +static inline void XOR_HOST_REG_IMM(int host_reg, uint32_t imm) { if (imm < 0x80 || imm >= 0xffffff80) { @@ -541,64 +543,64 @@ static void XOR_HOST_REG_IMM(int host_reg, uint32_t imm) } } -static void CALL_FUNC(void *dest) +static inline void CALL_FUNC(uintptr_t dest) { addbyte(0xE8); /*CALL*/ - addlong(((uint8_t *)dest - (uint8_t *)(&codeblock[block_current].data[block_pos + 4]))); + addlong(((uintptr_t)dest - (uintptr_t)(&codeblock[block_current].data[block_pos + 4]))); } -static void SHL_B_IMM(int reg, int count) +static inline void SHL_B_IMM(int reg, int count) { addbyte(0xc0); /*SHL reg, count*/ addbyte(0xc0 | reg | 0x20); addbyte(count); } -static void SHL_W_IMM(int reg, int count) +static inline void SHL_W_IMM(int reg, int count) { addbyte(0x66); /*SHL reg, count*/ addbyte(0xc1); addbyte(0xc0 | reg | 0x20); addbyte(count); } -static void SHL_L_IMM(int reg, int count) +static inline void SHL_L_IMM(int reg, int count) { addbyte(0xc1); /*SHL reg, count*/ addbyte(0xc0 | reg | 0x20); addbyte(count); } -static void SHR_B_IMM(int reg, int count) +static inline void SHR_B_IMM(int reg, int count) { addbyte(0xc0); /*SHR reg, count*/ addbyte(0xc0 | reg | 0x28); addbyte(count); } -static void SHR_W_IMM(int reg, int count) +static inline void SHR_W_IMM(int reg, int count) { addbyte(0x66); /*SHR reg, count*/ addbyte(0xc1); addbyte(0xc0 | reg | 0x28); addbyte(count); } -static void SHR_L_IMM(int reg, int count) +static inline void SHR_L_IMM(int reg, int count) { addbyte(0xc1); /*SHR reg, count*/ addbyte(0xc0 | reg | 0x28); addbyte(count); } -static void SAR_B_IMM(int reg, int count) +static inline void SAR_B_IMM(int reg, int count) { addbyte(0xc0); /*SAR reg, count*/ addbyte(0xc0 | reg | 0x38); addbyte(count); } -static void SAR_W_IMM(int reg, int count) +static inline void SAR_W_IMM(int reg, int count) { addbyte(0x66); /*SAR reg, count*/ addbyte(0xc1); addbyte(0xc0 | reg | 0x38); addbyte(count); } -static void SAR_L_IMM(int reg, int count) +static inline void SAR_L_IMM(int reg, int count) { addbyte(0xc1); /*SAR reg, count*/ addbyte(0xc0 | reg | 0x38); @@ -606,7 +608,7 @@ static void SAR_L_IMM(int reg, int count) } -static void CHECK_SEG_READ(x86seg *seg) +static inline void CHECK_SEG_READ(x86seg *seg) { /*Segments always valid in real/V86 mode*/ if (!(cr0 & 1) || (eflags & VM_FLAG)) @@ -616,6 +618,8 @@ static void CHECK_SEG_READ(x86seg *seg) return; if (seg->checked) return; + if (seg == &_ds && codegen_flat_ds) + return; addbyte(0x83); /*CMP seg->base, -1*/ addbyte(0x05|0x38); @@ -627,7 +631,7 @@ static void CHECK_SEG_READ(x86seg *seg) seg->checked = 1; } -static void CHECK_SEG_WRITE(x86seg *seg) +static inline void CHECK_SEG_WRITE(x86seg *seg) { /*Segments always valid in real/V86 mode*/ if (!(cr0 & 1) || (eflags & VM_FLAG)) @@ -637,6 +641,8 @@ static void CHECK_SEG_WRITE(x86seg *seg) return; if (seg->checked) return; + if (seg == &_ds && codegen_flat_ds) + return; addbyte(0x83); /*CMP seg->base, -1*/ addbyte(0x05|0x38); @@ -648,8 +654,11 @@ static void CHECK_SEG_WRITE(x86seg *seg) seg->checked = 1; } -static void CHECK_SEG_LIMITS(x86seg *seg, int end_offset) +static inline void CHECK_SEG_LIMITS(x86seg *seg, int end_offset) { + if ((seg == &_ds && codegen_flat_ds) || (seg == &_ss && codegen_flat_ss)) + return; + addbyte(0x3b); /*CMP EAX, seg->limit_low*/ addbyte(0x05); addlong((uint32_t)&seg->limit_low); @@ -673,21 +682,37 @@ static void CHECK_SEG_LIMITS(x86seg *seg, int end_offset) } } -static void MEM_LOAD_ADDR_EA_B(x86seg *seg) +static inline void MEM_LOAD_ADDR_EA_B(x86seg *seg) { - addbyte(0x8b); /*MOVL EDX, seg->base*/ - addbyte(0x05 | (REG_EDX << 3)); - addlong((uint32_t)&seg->base); + if ((seg == &_ds && codegen_flat_ds) || (seg == &_ss && codegen_flat_ss)) + { + addbyte(0x31); /*XOR EDX, EDX*/ + addbyte(0xd2); + } + else + { + addbyte(0x8b); /*MOVL EDX, seg->base*/ + addbyte(0x05 | (REG_EDX << 3)); + addlong((uint32_t)&seg->base); + } addbyte(0xe8); /*CALL mem_load_addr_ea_b*/ addlong(mem_load_addr_ea_b - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); host_reg_mapping[0] = 8; } -static int MEM_LOAD_ADDR_EA_B_NO_ABRT(x86seg *seg) +static inline int MEM_LOAD_ADDR_EA_B_NO_ABRT(x86seg *seg) { - addbyte(0x8b); /*MOVL EDX, seg->base*/ - addbyte(0x05 | (REG_EDX << 3)); - addlong((uint32_t)&seg->base); + if ((seg == &_ds && codegen_flat_ds) || (seg == &_ss && codegen_flat_ss)) + { + addbyte(0x31); /*XOR EDX, EDX*/ + addbyte(0xd2); + } + else + { + addbyte(0x8b); /*MOVL EDX, seg->base*/ + addbyte(0x05 | (REG_EDX << 3)); + addlong((uint32_t)&seg->base); + } addbyte(0xe8); /*CALL mem_load_addr_ea_b_no_abrt*/ addlong(mem_load_addr_ea_b_no_abrt - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); @@ -695,21 +720,37 @@ static int MEM_LOAD_ADDR_EA_B_NO_ABRT(x86seg *seg) return REG_ECX; } -static void MEM_LOAD_ADDR_EA_W(x86seg *seg) +static inline void MEM_LOAD_ADDR_EA_W(x86seg *seg) { - addbyte(0x8b); /*MOVL EDX, seg->base*/ - addbyte(0x05 | (REG_EDX << 3)); - addlong((uint32_t)&seg->base); + if ((seg == &_ds && codegen_flat_ds) || (seg == &_ss && codegen_flat_ss)) + { + addbyte(0x31); /*XOR EDX, EDX*/ + addbyte(0xd2); + } + else + { + addbyte(0x8b); /*MOVL EDX, seg->base*/ + addbyte(0x05 | (REG_EDX << 3)); + addlong((uint32_t)&seg->base); + } addbyte(0xe8); /*CALL mem_load_addr_ea_w*/ addlong(mem_load_addr_ea_w - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); host_reg_mapping[0] = 8; } -static void MEM_LOAD_ADDR_EA_W_OFFSET(x86seg *seg, int offset) +static inline void MEM_LOAD_ADDR_EA_W_OFFSET(x86seg *seg, int offset) { - addbyte(0x8b); /*MOVL EDX, seg->base*/ - addbyte(0x05 | (REG_EDX << 3)); - addlong((uint32_t)&seg->base); + if ((seg == &_ds && codegen_flat_ds) || (seg == &_ss && codegen_flat_ss)) + { + addbyte(0x31); /*XOR EDX, EDX*/ + addbyte(0xd2); + } + else + { + addbyte(0x8b); /*MOVL EDX, seg->base*/ + addbyte(0x05 | (REG_EDX << 3)); + addlong((uint32_t)&seg->base); + } addbyte(0x83); /*ADD EAX, offset*/ addbyte(0xc0); addbyte(offset); @@ -718,11 +759,19 @@ static void MEM_LOAD_ADDR_EA_W_OFFSET(x86seg *seg, int offset) host_reg_mapping[0] = 8; } -static int MEM_LOAD_ADDR_EA_W_NO_ABRT(x86seg *seg) +static inline int MEM_LOAD_ADDR_EA_W_NO_ABRT(x86seg *seg) { - addbyte(0x8b); /*MOVL EDX, seg->base*/ - addbyte(0x05 | (REG_EDX << 3)); - addlong((uint32_t)&seg->base); + if ((seg == &_ds && codegen_flat_ds) || (seg == &_ss && codegen_flat_ss)) + { + addbyte(0x31); /*XOR EDX, EDX*/ + addbyte(0xd2); + } + else + { + addbyte(0x8b); /*MOVL EDX, seg->base*/ + addbyte(0x05 | (REG_EDX << 3)); + addlong((uint32_t)&seg->base); + } addbyte(0xe8); /*CALL mem_load_addr_ea_w_no_abrt*/ addlong(mem_load_addr_ea_w_no_abrt - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); @@ -730,22 +779,38 @@ static int MEM_LOAD_ADDR_EA_W_NO_ABRT(x86seg *seg) return REG_ECX; } -static void MEM_LOAD_ADDR_EA_L(x86seg *seg) +static inline void MEM_LOAD_ADDR_EA_L(x86seg *seg) { - addbyte(0x8b); /*MOVL EDX, seg->base*/ - addbyte(0x05 | (REG_EDX << 3)); - addlong((uint32_t)&seg->base); + if ((seg == &_ds && codegen_flat_ds) || (seg == &_ss && codegen_flat_ss)) + { + addbyte(0x31); /*XOR EDX, EDX*/ + addbyte(0xd2); + } + else + { + addbyte(0x8b); /*MOVL EDX, seg->base*/ + addbyte(0x05 | (REG_EDX << 3)); + addlong((uint32_t)&seg->base); + } addbyte(0xe8); /*CALL mem_load_addr_ea_l*/ addlong(mem_load_addr_ea_l - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); host_reg_mapping[0] = 8; } -static int MEM_LOAD_ADDR_EA_L_NO_ABRT(x86seg *seg) +static inline int MEM_LOAD_ADDR_EA_L_NO_ABRT(x86seg *seg) { - addbyte(0x8b); /*MOVL EDX, seg->base*/ - addbyte(0x05 | (REG_EDX << 3)); - addlong((uint32_t)&seg->base); + if ((seg == &_ds && codegen_flat_ds) || (seg == &_ss && codegen_flat_ss)) + { + addbyte(0x31); /*XOR EDX, EDX*/ + addbyte(0xd2); + } + else + { + addbyte(0x8b); /*MOVL EDX, seg->base*/ + addbyte(0x05 | (REG_EDX << 3)); + addlong((uint32_t)&seg->base); + } addbyte(0xe8); /*CALL mem_load_addr_ea_l_no_abrt*/ addlong(mem_load_addr_ea_l_no_abrt - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); @@ -754,41 +819,57 @@ static int MEM_LOAD_ADDR_EA_L_NO_ABRT(x86seg *seg) return REG_ECX; } -static void MEM_LOAD_ADDR_EA_Q(x86seg *seg) +static inline void MEM_LOAD_ADDR_EA_Q(x86seg *seg) { - addbyte(0x8b); /*MOVL EDX, seg->base*/ - addbyte(0x05 | (REG_EDX << 3)); - addlong((uint32_t)&seg->base); + if ((seg == &_ds && codegen_flat_ds) || (seg == &_ss && codegen_flat_ss)) + { + addbyte(0x31); /*XOR EDX, EDX*/ + addbyte(0xd2); + } + else + { + addbyte(0x8b); /*MOVL EDX, seg->base*/ + addbyte(0x05 | (REG_EDX << 3)); + addlong((uint32_t)&seg->base); + } addbyte(0xe8); /*CALL mem_load_addr_ea_q*/ addlong(mem_load_addr_ea_q - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); host_reg_mapping[0] = 8; } -static void MEM_LOAD_ADDR_IMM_B(x86seg *seg, uint32_t addr) +static inline void MEM_LOAD_ADDR_IMM_B(x86seg *seg, uint32_t addr) { addbyte(0xb8); /*MOV EAX, addr*/ addlong(addr); MEM_LOAD_ADDR_EA_B(seg); } -static void MEM_LOAD_ADDR_IMM_W(x86seg *seg, uint32_t addr) +static inline void MEM_LOAD_ADDR_IMM_W(x86seg *seg, uint32_t addr) { addbyte(0xb8); /*MOV EAX, addr*/ addlong(addr); MEM_LOAD_ADDR_EA_W(seg); } -static void MEM_LOAD_ADDR_IMM_L(x86seg *seg, uint32_t addr) +static inline void MEM_LOAD_ADDR_IMM_L(x86seg *seg, uint32_t addr) { addbyte(0xb8); /*MOV EAX, addr*/ addlong(addr); MEM_LOAD_ADDR_EA_L(seg); } -static void MEM_STORE_ADDR_EA_B(x86seg *seg, int host_reg) +static inline void MEM_STORE_ADDR_EA_B(x86seg *seg, int host_reg) { - addbyte(0x8b); /*MOVL ESI, seg->base*/ - addbyte(0x05 | (REG_ESI << 3)); - addlong((uint32_t)&seg->base); + if ((seg == &_ds && codegen_flat_ds) || (seg == &_ss && codegen_flat_ss)) + { + addbyte(0x31); /*XOR ESI, ESI*/ + addbyte(0xf6); + } + else + { + addbyte(0x8b); /*MOVL ESI, seg->base*/ + addbyte(0x05 | (REG_ESI << 3)); + addlong((uint32_t)&seg->base); + } if (host_reg != REG_ECX) { addbyte(0x89); /*MOV ECX, host_reg*/ @@ -797,11 +878,19 @@ static void MEM_STORE_ADDR_EA_B(x86seg *seg, int host_reg) addbyte(0xe8); /*CALL mem_store_addr_ea_b*/ addlong(mem_store_addr_ea_b - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); } -static void MEM_STORE_ADDR_EA_B_NO_ABRT(x86seg *seg, int host_reg) +static inline void MEM_STORE_ADDR_EA_B_NO_ABRT(x86seg *seg, int host_reg) { - addbyte(0x8b); /*MOVL ESI, seg->base*/ - addbyte(0x05 | (REG_ESI << 3)); - addlong((uint32_t)&seg->base); + if ((seg == &_ds && codegen_flat_ds) || (seg == &_ss && codegen_flat_ss)) + { + addbyte(0x31); /*XOR ESI, ESI*/ + addbyte(0xf6); + } + else + { + addbyte(0x8b); /*MOVL ESI, seg->base*/ + addbyte(0x05 | (REG_ESI << 3)); + addlong((uint32_t)&seg->base); + } if (host_reg != REG_ECX) { addbyte(0x89); /*MOV ECX, host_reg*/ @@ -810,11 +899,19 @@ static void MEM_STORE_ADDR_EA_B_NO_ABRT(x86seg *seg, int host_reg) addbyte(0xe8); /*CALL mem_store_addr_ea_b_no_abrt*/ addlong(mem_store_addr_ea_b_no_abrt - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); } -static void MEM_STORE_ADDR_EA_W(x86seg *seg, int host_reg) +static inline void MEM_STORE_ADDR_EA_W(x86seg *seg, int host_reg) { - addbyte(0x8b); /*MOVL ESI, seg->base*/ - addbyte(0x05 | (REG_ESI << 3)); - addlong((uint32_t)&seg->base); + if ((seg == &_ds && codegen_flat_ds) || (seg == &_ss && codegen_flat_ss)) + { + addbyte(0x31); /*XOR ESI, ESI*/ + addbyte(0xf6); + } + else + { + addbyte(0x8b); /*MOVL ESI, seg->base*/ + addbyte(0x05 | (REG_ESI << 3)); + addlong((uint32_t)&seg->base); + } if (host_reg != REG_ECX) { addbyte(0x89); /*MOV ECX, host_reg*/ @@ -823,11 +920,19 @@ static void MEM_STORE_ADDR_EA_W(x86seg *seg, int host_reg) addbyte(0xe8); /*CALL mem_store_addr_ea_w*/ addlong(mem_store_addr_ea_w - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); } -static void MEM_STORE_ADDR_EA_W_NO_ABRT(x86seg *seg, int host_reg) +static inline void MEM_STORE_ADDR_EA_W_NO_ABRT(x86seg *seg, int host_reg) { - addbyte(0x8b); /*MOVL ESI, seg->base*/ - addbyte(0x05 | (REG_ESI << 3)); - addlong((uint32_t)&seg->base); + if ((seg == &_ds && codegen_flat_ds) || (seg == &_ss && codegen_flat_ss)) + { + addbyte(0x31); /*XOR ESI, ESI*/ + addbyte(0xf6); + } + else + { + addbyte(0x8b); /*MOVL ESI, seg->base*/ + addbyte(0x05 | (REG_ESI << 3)); + addlong((uint32_t)&seg->base); + } if (host_reg != REG_ECX) { addbyte(0x89); /*MOV ECX, host_reg*/ @@ -836,11 +941,19 @@ static void MEM_STORE_ADDR_EA_W_NO_ABRT(x86seg *seg, int host_reg) addbyte(0xe8); /*CALL mem_store_addr_ea_w_no_abrt*/ addlong(mem_store_addr_ea_w_no_abrt - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); } -static void MEM_STORE_ADDR_EA_L(x86seg *seg, int host_reg) +static inline void MEM_STORE_ADDR_EA_L(x86seg *seg, int host_reg) { - addbyte(0x8b); /*MOVL ESI, seg->base*/ - addbyte(0x05 | (REG_ESI << 3)); - addlong((uint32_t)&seg->base); + if ((seg == &_ds && codegen_flat_ds) || (seg == &_ss && codegen_flat_ss)) + { + addbyte(0x31); /*XOR ESI, ESI*/ + addbyte(0xf6); + } + else + { + addbyte(0x8b); /*MOVL ESI, seg->base*/ + addbyte(0x05 | (REG_ESI << 3)); + addlong((uint32_t)&seg->base); + } if (host_reg != REG_ECX) { addbyte(0x89); /*MOV ECX, host_reg*/ @@ -849,11 +962,19 @@ static void MEM_STORE_ADDR_EA_L(x86seg *seg, int host_reg) addbyte(0xe8); /*CALL mem_store_addr_ea_l*/ addlong(mem_store_addr_ea_l - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); } -static void MEM_STORE_ADDR_EA_L_NO_ABRT(x86seg *seg, int host_reg) +static inline void MEM_STORE_ADDR_EA_L_NO_ABRT(x86seg *seg, int host_reg) { - addbyte(0x8b); /*MOVL ESI, seg->base*/ - addbyte(0x05 | (REG_ESI << 3)); - addlong((uint32_t)&seg->base); + if ((seg == &_ds && codegen_flat_ds) || (seg == &_ss && codegen_flat_ss)) + { + addbyte(0x31); /*XOR ESI, ESI*/ + addbyte(0xf6); + } + else + { + addbyte(0x8b); /*MOVL ESI, seg->base*/ + addbyte(0x05 | (REG_ESI << 3)); + addlong((uint32_t)&seg->base); + } if (host_reg != REG_ECX) { addbyte(0x89); /*MOV ECX, host_reg*/ @@ -862,7 +983,7 @@ static void MEM_STORE_ADDR_EA_L_NO_ABRT(x86seg *seg, int host_reg) addbyte(0xe8); /*CALL mem_store_addr_ea_l_no_abrt*/ addlong(mem_store_addr_ea_l_no_abrt - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); } -static void MEM_STORE_ADDR_EA_Q(x86seg *seg, int host_reg, int host_reg2) +static inline void MEM_STORE_ADDR_EA_Q(x86seg *seg, int host_reg, int host_reg2) { if (host_reg != REG_EBX) { @@ -874,26 +995,34 @@ static void MEM_STORE_ADDR_EA_Q(x86seg *seg, int host_reg, int host_reg2) addbyte(0x89); /*MOV ECX, host_reg2*/ addbyte(0xc0 | REG_ECX | (host_reg2 << 3)); } - addbyte(0x8b); /*MOVL ESI, seg->base*/ - addbyte(0x05 | (REG_ESI << 3)); - addlong((uint32_t)&seg->base); + if ((seg == &_ds && codegen_flat_ds) || (seg == &_ss && codegen_flat_ss)) + { + addbyte(0x31); /*XOR ESI, ESI*/ + addbyte(0xf6); + } + else + { + addbyte(0x8b); /*MOVL ESI, seg->base*/ + addbyte(0x05 | (REG_ESI << 3)); + addlong((uint32_t)&seg->base); + } addbyte(0xe8); /*CALL mem_store_addr_ea_q*/ addlong(mem_store_addr_ea_q - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); } -static void MEM_STORE_ADDR_IMM_B(x86seg *seg, uint32_t addr, int host_reg) +static inline void MEM_STORE_ADDR_IMM_B(x86seg *seg, uint32_t addr, int host_reg) { addbyte(0xb8); /*MOV EAX, addr*/ addlong(addr); MEM_STORE_ADDR_EA_B(seg, host_reg); } -static void MEM_STORE_ADDR_IMM_L(x86seg *seg, uint32_t addr, int host_reg) +static inline void MEM_STORE_ADDR_IMM_L(x86seg *seg, uint32_t addr, int host_reg) { addbyte(0xb8); /*MOV EAX, addr*/ addlong(addr); MEM_STORE_ADDR_EA_L(seg, host_reg); } -static void MEM_STORE_ADDR_IMM_W(x86seg *seg, uint32_t addr, int host_reg) +static inline void MEM_STORE_ADDR_IMM_W(x86seg *seg, uint32_t addr, int host_reg) { addbyte(0xb8); /*MOV EAX, addr*/ addlong(addr); @@ -901,10 +1030,9 @@ static void MEM_STORE_ADDR_IMM_W(x86seg *seg, uint32_t addr, int host_reg) } -static x86seg *FETCH_EA_16(x86seg *op_ea_seg, uint32_t fetchdat, int op_ssegs, uint32_t *op_pc) +static inline x86seg *FETCH_EA_16(x86seg *op_ea_seg, uint32_t fetchdat, int op_ssegs, uint32_t *op_pc) { int mod = (fetchdat >> 6) & 3; - int reg = (fetchdat >> 3) & 7; int rm = fetchdat & 7; if (!mod && rm == 6) { @@ -942,7 +1070,7 @@ static x86seg *FETCH_EA_16(x86seg *op_ea_seg, uint32_t fetchdat, int op_ssegs, u break; case 2: addbyte(0xb8); /*MOVL EAX, imm16*/ - addlong((fetchdat >> 8) & 0xffff);// pc++; + addlong((fetchdat >> 8) & 0xffff); addbyte(0x03); /*ADDL EAX, *mod1add[0][rm]*/ addbyte(0x05); addlong((uint32_t)mod1add[0][rm]); @@ -964,11 +1092,10 @@ static x86seg *FETCH_EA_16(x86seg *op_ea_seg, uint32_t fetchdat, int op_ssegs, u return op_ea_seg; } -static x86seg *FETCH_EA_32(x86seg *op_ea_seg, uint32_t fetchdat, int op_ssegs, uint32_t *op_pc, int stack_offset) +static inline x86seg *FETCH_EA_32(x86seg *op_ea_seg, uint32_t fetchdat, int op_ssegs, uint32_t *op_pc, int stack_offset) { uint32_t new_eaaddr; int mod = (fetchdat >> 6) & 3; - int reg = (fetchdat >> 3) & 7; int rm = fetchdat & 7; if (rm == 4) @@ -983,20 +1110,20 @@ static x86seg *FETCH_EA_32(x86seg *op_ea_seg, uint32_t fetchdat, int op_ssegs, u { new_eaaddr = fastreadl(cs + (*op_pc) + 1); addbyte(0xb8); /*MOVL EAX, imm32*/ - addlong(new_eaaddr);// pc++; + addlong(new_eaaddr); (*op_pc) += 4; } else { addbyte(0x8b); /*MOVL EAX, regs[sib&7].l*/ addbyte(0x45); - addbyte(cpu_state_offset(regs[sib & 7].l)); + addbyte((uint8_t)cpu_state_offset(regs[sib & 7].l)); } break; case 1: addbyte(0x8b); /*MOVL EAX, regs[sib&7].l*/ addbyte(0x45); - addbyte(cpu_state_offset(regs[sib & 7].l)); + addbyte((uint8_t)cpu_state_offset(regs[sib & 7].l)); addbyte(0x83); /*ADDL EAX, imm8*/ addbyte(0xc0 | REG_EAX); addbyte((int8_t)(rmdat >> 16)); @@ -1008,7 +1135,7 @@ static x86seg *FETCH_EA_32(x86seg *op_ea_seg, uint32_t fetchdat, int op_ssegs, u addlong(new_eaaddr); addbyte(0x03); /*ADDL EAX, regs[sib&7].l*/ addbyte(0x45); - addbyte(cpu_state_offset(regs[sib & 7].l)); + addbyte((uint8_t)cpu_state_offset(regs[sib & 7].l)); (*op_pc) += 4; break; } @@ -1035,20 +1162,20 @@ static x86seg *FETCH_EA_32(x86seg *op_ea_seg, uint32_t fetchdat, int op_ssegs, u case 0: addbyte(0x03); /*ADDL EAX, regs[sib&7].l*/ addbyte(0x45); - addbyte(cpu_state_offset(regs[(sib >> 3) & 7].l)); + addbyte((uint8_t)cpu_state_offset(regs[(sib >> 3) & 7].l)); break; case 1: - addbyte(0x8B); addbyte(0x45 | (REG_EDI << 3)); addbyte(cpu_state_offset(regs[(sib >> 3) & 7].l)); /*MOVL EDI, reg*/ + addbyte(0x8B); addbyte(0x45 | (REG_EDI << 3)); addbyte((uint8_t)cpu_state_offset(regs[(sib >> 3) & 7].l)); /*MOVL EDI, reg*/ addbyte(0x01); addbyte(0xc0 | REG_EAX | (REG_EDI << 3)); /*ADDL EAX, EDI*/ addbyte(0x01); addbyte(0xc0 | REG_EAX | (REG_EDI << 3)); /*ADDL EAX, EDI*/ break; case 2: - addbyte(0x8B); addbyte(0x45 | (REG_EDI << 3)); addbyte(cpu_state_offset(regs[(sib >> 3) & 7].l)); /*MOVL EDI, reg*/ + addbyte(0x8B); addbyte(0x45 | (REG_EDI << 3)); addbyte((uint8_t)cpu_state_offset(regs[(sib >> 3) & 7].l)); /*MOVL EDI, reg*/ addbyte(0xC1); addbyte(0xE0 | REG_EDI); addbyte(2); /*SHL EDI, 2*/ addbyte(0x01); addbyte(0xc0 | REG_EAX | (REG_EDI << 3)); /*ADDL EAX, EDI*/ break; case 3: - addbyte(0x8B); addbyte(0x45 | (REG_EDI << 3)); addbyte(cpu_state_offset(regs[(sib >> 3) & 7].l)); /*MOVL EDI reg*/ + addbyte(0x8B); addbyte(0x45 | (REG_EDI << 3)); addbyte((uint8_t)cpu_state_offset(regs[(sib >> 3) & 7].l)); /*MOVL EDI reg*/ addbyte(0xC1); addbyte(0xE0 | REG_EDI); addbyte(3); /*SHL EDI, 3*/ addbyte(0x01); addbyte(0xc0 | REG_EAX | (REG_EDI << 3)); /*ADDL EAX, EDI*/ break; @@ -1067,7 +1194,7 @@ static x86seg *FETCH_EA_32(x86seg *op_ea_seg, uint32_t fetchdat, int op_ssegs, u } addbyte(0x8b); /*MOVL EAX, regs[rm].l*/ addbyte(0x45); - addbyte(cpu_state_offset(regs[rm].l)); + addbyte((uint8_t)cpu_state_offset(regs[rm].l)); cpu_state.eaaddr = cpu_state.regs[rm].l; if (mod) { @@ -1092,7 +1219,7 @@ static x86seg *FETCH_EA_32(x86seg *op_ea_seg, uint32_t fetchdat, int op_ssegs, u return op_ea_seg; } -static x86seg *FETCH_EA(x86seg *op_ea_seg, uint32_t fetchdat, int op_ssegs, uint32_t *op_pc, uint32_t op_32) +static inline x86seg *FETCH_EA(x86seg *op_ea_seg, uint32_t fetchdat, int op_ssegs, uint32_t *op_pc, uint32_t op_32) { if (op_32 & 0x200) return FETCH_EA_32(op_ea_seg, fetchdat, op_ssegs, op_pc, 0); @@ -1100,13 +1227,13 @@ static x86seg *FETCH_EA(x86seg *op_ea_seg, uint32_t fetchdat, int op_ssegs, uint } -static void LOAD_STACK_TO_EA(int off) +static inline void LOAD_STACK_TO_EA(int off) { if (stack32) { addbyte(0x8b); /*MOVL EAX,[ESP]*/ addbyte(0x45 | (REG_EAX << 3)); - addbyte(cpu_state_offset(regs[REG_ESP].l)); + addbyte((uint8_t)cpu_state_offset(regs[REG_ESP].l)); if (off) { addbyte(0x83); /*ADD EAX, off*/ @@ -1119,7 +1246,7 @@ static void LOAD_STACK_TO_EA(int off) addbyte(0x0f); /*MOVZX EAX,W[ESP]*/ addbyte(0xb7); addbyte(0x45 | (REG_EAX << 3)); - addbyte(cpu_state_offset(regs[REG_ESP].w)); + addbyte((uint8_t)cpu_state_offset(regs[REG_ESP].w)); if (off) { addbyte(0x66); /*ADD AX, off*/ @@ -1129,13 +1256,13 @@ static void LOAD_STACK_TO_EA(int off) } } -static void LOAD_EBP_TO_EA(int off) +static inline void LOAD_EBP_TO_EA(int off) { if (stack32) { addbyte(0x8b); /*MOVL EAX,[EBP]*/ addbyte(0x45 | (REG_EAX << 3)); - addbyte(cpu_state_offset(regs[REG_EBP].l)); + addbyte((uint8_t)cpu_state_offset(regs[REG_EBP].l)); if (off) { addbyte(0x83); /*ADD EAX, off*/ @@ -1148,7 +1275,7 @@ static void LOAD_EBP_TO_EA(int off) addbyte(0x0f); /*MOVZX EAX,W[EBP]*/ addbyte(0xb7); addbyte(0x45 | (REG_EAX << 3)); - addbyte(cpu_state_offset(regs[REG_EBP].w)); + addbyte((uint8_t)cpu_state_offset(regs[REG_EBP].w)); if (off) { addbyte(0x66); /*ADD AX, off*/ @@ -1158,7 +1285,7 @@ static void LOAD_EBP_TO_EA(int off) } } -static void SP_MODIFY(int off) +static inline void SP_MODIFY(int off) { if (stack32) { @@ -1166,14 +1293,14 @@ static void SP_MODIFY(int off) { addbyte(0x83); /*ADD [ESP], off*/ addbyte(0x45); - addbyte(cpu_state_offset(regs[REG_ESP].l)); + addbyte((uint8_t)cpu_state_offset(regs[REG_ESP].l)); addbyte(off); } else { addbyte(0x81); /*ADD [ESP], off*/ addbyte(0x45); - addbyte(cpu_state_offset(regs[REG_ESP].l)); + addbyte((uint8_t)cpu_state_offset(regs[REG_ESP].l)); addlong(off); } } @@ -1184,7 +1311,7 @@ static void SP_MODIFY(int off) addbyte(0x66); /*ADD [SP], off*/ addbyte(0x83); addbyte(0x45); - addbyte(cpu_state_offset(regs[REG_ESP].w)); + addbyte((uint8_t)cpu_state_offset(regs[REG_ESP].w)); addbyte(off); } else @@ -1192,14 +1319,14 @@ static void SP_MODIFY(int off) addbyte(0x66); /*ADD [SP], off*/ addbyte(0x81); addbyte(0x45); - addbyte(cpu_state_offset(regs[REG_ESP].w)); + addbyte((uint8_t)cpu_state_offset(regs[REG_ESP].w)); addword(off); } } } -static void TEST_ZERO_JUMP_W(int host_reg, uint32_t new_pc, int taken_cycles) +static inline void TEST_ZERO_JUMP_W(int host_reg, uint32_t new_pc, int taken_cycles) { addbyte(0x66); /*CMPW host_reg, 0*/ addbyte(0x83); @@ -1209,19 +1336,19 @@ static void TEST_ZERO_JUMP_W(int host_reg, uint32_t new_pc, int taken_cycles) addbyte(7+5+(taken_cycles ? 4 : 0)); addbyte(0xC7); /*MOVL [pc], new_pc*/ addbyte(0x45); - addbyte(cpu_state_offset(pc)); + addbyte((uint8_t)cpu_state_offset(pc)); addlong(new_pc); if (taken_cycles) { addbyte(0x83); /*SUB $codegen_block_cycles, cyclcs*/ addbyte(0x6d); - addbyte(cpu_state_offset(_cycles)); + addbyte((uint8_t)cpu_state_offset(_cycles)); addbyte(taken_cycles); } addbyte(0xe9); /*JMP end*/ addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); } -static void TEST_ZERO_JUMP_L(int host_reg, uint32_t new_pc, int taken_cycles) +static inline void TEST_ZERO_JUMP_L(int host_reg, uint32_t new_pc, int taken_cycles) { addbyte(0x83); /*CMPW host_reg, 0*/ addbyte(0xc0 | 0x38 | host_reg); @@ -1230,20 +1357,20 @@ static void TEST_ZERO_JUMP_L(int host_reg, uint32_t new_pc, int taken_cycles) addbyte(7+5+(taken_cycles ? 4 : 0)); addbyte(0xC7); /*MOVL [pc], new_pc*/ addbyte(0x45); - addbyte(cpu_state_offset(pc)); + addbyte((uint8_t)cpu_state_offset(pc)); addlong(new_pc); if (taken_cycles) { addbyte(0x83); /*SUB $codegen_block_cycles, cyclcs*/ addbyte(0x6d); - addbyte(cpu_state_offset(_cycles)); + addbyte((uint8_t)cpu_state_offset(_cycles)); addbyte(taken_cycles); } addbyte(0xe9); /*JMP end*/ addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); } -static void TEST_NONZERO_JUMP_W(int host_reg, uint32_t new_pc, int taken_cycles) +static inline void TEST_NONZERO_JUMP_W(int host_reg, uint32_t new_pc, int taken_cycles) { addbyte(0x66); /*CMPW host_reg, 0*/ addbyte(0x83); @@ -1253,19 +1380,19 @@ static void TEST_NONZERO_JUMP_W(int host_reg, uint32_t new_pc, int taken_cycles) addbyte(7+5+(taken_cycles ? 4 : 0)); addbyte(0xC7); /*MOVL [pc], new_pc*/ addbyte(0x45); - addbyte(cpu_state_offset(pc)); + addbyte((uint8_t)cpu_state_offset(pc)); addlong(new_pc); if (taken_cycles) { addbyte(0x83); /*SUB $codegen_block_cycles, cyclcs*/ addbyte(0x6d); - addbyte(cpu_state_offset(_cycles)); + addbyte((uint8_t)cpu_state_offset(_cycles)); addbyte(taken_cycles); } addbyte(0xe9); /*JMP end*/ addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); } -static void TEST_NONZERO_JUMP_L(int host_reg, uint32_t new_pc, int taken_cycles) +static inline void TEST_NONZERO_JUMP_L(int host_reg, uint32_t new_pc, int taken_cycles) { addbyte(0x83); /*CMPW host_reg, 0*/ addbyte(0xc0 | 0x38 | host_reg); @@ -1274,30 +1401,30 @@ static void TEST_NONZERO_JUMP_L(int host_reg, uint32_t new_pc, int taken_cycles) addbyte(7+5+(taken_cycles ? 4 : 0)); addbyte(0xC7); /*MOVL [pc], new_pc*/ addbyte(0x45); - addbyte(cpu_state_offset(pc)); + addbyte((uint8_t)cpu_state_offset(pc)); addlong(new_pc); if (taken_cycles) { addbyte(0x83); /*SUB $codegen_block_cycles, cyclcs*/ addbyte(0x6d); - addbyte(cpu_state_offset(_cycles)); + addbyte((uint8_t)cpu_state_offset(_cycles)); addbyte(taken_cycles); } addbyte(0xe9); /*JMP end*/ addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); } -static int BRANCH_COND_BE(int pc_offset, uint32_t op_pc, uint32_t offset, int not) +static inline void BRANCH_COND_BE(int pc_offset, uint32_t op_pc, uint32_t offset, int not) { switch (codegen_flags_changed ? cpu_state.flags_op : FLAGS_UNKNOWN) { case FLAGS_SUB8: addbyte(0x8a); /*MOV AL, flags_op1*/ addbyte(0x45); - addbyte(cpu_state_offset(flags_op1)); + addbyte((uint8_t)cpu_state_offset(flags_op1)); addbyte(0x3a); /*CMP AL, flags_op2*/ addbyte(0x45); - addbyte(cpu_state_offset(flags_op2)); + addbyte((uint8_t)cpu_state_offset(flags_op2)); if (not) addbyte(0x76); /*JBE*/ else @@ -1307,11 +1434,11 @@ static int BRANCH_COND_BE(int pc_offset, uint32_t op_pc, uint32_t offset, int no addbyte(0x66); /*MOV AX, flags_op1*/ addbyte(0x8b); addbyte(0x45); - addbyte(cpu_state_offset(flags_op1)); + addbyte((uint8_t)cpu_state_offset(flags_op1)); addbyte(0x66); /*CMP AX, flags_op2*/ addbyte(0x3b); addbyte(0x45); - addbyte(cpu_state_offset(flags_op2)); + addbyte((uint8_t)cpu_state_offset(flags_op2)); if (not) addbyte(0x76); /*JBE*/ else @@ -1320,10 +1447,10 @@ static int BRANCH_COND_BE(int pc_offset, uint32_t op_pc, uint32_t offset, int no case FLAGS_SUB32: addbyte(0x8b); /*MOV EAX, flags_op1*/ addbyte(0x45); - addbyte(cpu_state_offset(flags_op1)); + addbyte((uint8_t)cpu_state_offset(flags_op1)); addbyte(0x3b); /*CMP EAX, flags_op2*/ addbyte(0x45); - addbyte(cpu_state_offset(flags_op2)); + addbyte((uint8_t)cpu_state_offset(flags_op2)); if (not) addbyte(0x76); /*JBE*/ else @@ -1335,13 +1462,13 @@ static int BRANCH_COND_BE(int pc_offset, uint32_t op_pc, uint32_t offset, int no { addbyte(0x83); /*CMP flags_res, 0*/ addbyte(0x7d); - addbyte(cpu_state_offset(flags_res)); + addbyte((uint8_t)cpu_state_offset(flags_res)); addbyte(0); addbyte(0x74); /*JZ +*/ } else { - CALL_FUNC(ZF_SET); + CALL_FUNC((uintptr_t)ZF_SET); addbyte(0x85); /*TEST EAX,EAX*/ addbyte(0xc0); addbyte(0x75); /*JNZ +*/ @@ -1350,7 +1477,7 @@ static int BRANCH_COND_BE(int pc_offset, uint32_t op_pc, uint32_t offset, int no addbyte(5+2+2+7+5+(timing_bt ? 4 : 0)); else addbyte(5+2+2); - CALL_FUNC(CF_SET); + CALL_FUNC((uintptr_t)CF_SET); addbyte(0x85); /*TEST EAX,EAX*/ addbyte(0xc0); if (not) @@ -1362,30 +1489,30 @@ static int BRANCH_COND_BE(int pc_offset, uint32_t op_pc, uint32_t offset, int no addbyte(7+5+(timing_bt ? 4 : 0)); addbyte(0xC7); /*MOVL [pc], new_pc*/ addbyte(0x45); - addbyte(cpu_state_offset(pc)); + addbyte((uint8_t)cpu_state_offset(pc)); addlong(op_pc+pc_offset+offset); if (timing_bt) { addbyte(0x83); /*SUB $codegen_block_cycles, cyclcs*/ addbyte(0x6d); - addbyte(cpu_state_offset(_cycles)); + addbyte((uint8_t)cpu_state_offset(_cycles)); addbyte(timing_bt); } addbyte(0xe9); /*JMP end*/ addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); } -static int BRANCH_COND_L(int pc_offset, uint32_t op_pc, uint32_t offset, int not) +static inline void BRANCH_COND_L(int pc_offset, uint32_t op_pc, uint32_t offset, int not) { switch (codegen_flags_changed ? cpu_state.flags_op : FLAGS_UNKNOWN) { case FLAGS_SUB8: addbyte(0x8a); /*MOV AL, flags_op1*/ addbyte(0x45); - addbyte(cpu_state_offset(flags_op1)); + addbyte((uint8_t)cpu_state_offset(flags_op1)); addbyte(0x3a); /*CMP AL, flags_op2*/ addbyte(0x45); - addbyte(cpu_state_offset(flags_op2)); + addbyte((uint8_t)cpu_state_offset(flags_op2)); if (not) addbyte(0x7c); /*JL*/ else @@ -1395,11 +1522,11 @@ static int BRANCH_COND_L(int pc_offset, uint32_t op_pc, uint32_t offset, int not addbyte(0x66); /*MOV AX, flags_op1*/ addbyte(0x8b); addbyte(0x45); - addbyte(cpu_state_offset(flags_op1)); + addbyte((uint8_t)cpu_state_offset(flags_op1)); addbyte(0x66); /*CMP AX, flags_op2*/ addbyte(0x3b); addbyte(0x45); - addbyte(cpu_state_offset(flags_op2)); + addbyte((uint8_t)cpu_state_offset(flags_op2)); if (not) addbyte(0x7c); /*JL*/ else @@ -1408,10 +1535,10 @@ static int BRANCH_COND_L(int pc_offset, uint32_t op_pc, uint32_t offset, int not case FLAGS_SUB32: addbyte(0x8b); /*MOV EAX, flags_op1*/ addbyte(0x45); - addbyte(cpu_state_offset(flags_op1)); + addbyte((uint8_t)cpu_state_offset(flags_op1)); addbyte(0x3b); /*CMP EAX, flags_op2*/ addbyte(0x45); - addbyte(cpu_state_offset(flags_op2)); + addbyte((uint8_t)cpu_state_offset(flags_op2)); if (not) addbyte(0x7c); /*JL*/ else @@ -1419,13 +1546,13 @@ static int BRANCH_COND_L(int pc_offset, uint32_t op_pc, uint32_t offset, int not break; default: - CALL_FUNC(NF_SET); + CALL_FUNC((uintptr_t)NF_SET); addbyte(0x85); /*TEST EAX,EAX*/ addbyte(0xc0); addbyte(0x0f); /*SETNE BL*/ addbyte(0x95); addbyte(0xc3); - CALL_FUNC(VF_SET); + CALL_FUNC((uintptr_t)VF_SET); addbyte(0x85); /*TEST EAX,EAX*/ addbyte(0xc0); addbyte(0x0f); /*SETNE AL*/ @@ -1442,30 +1569,30 @@ static int BRANCH_COND_L(int pc_offset, uint32_t op_pc, uint32_t offset, int not addbyte(7+5+(timing_bt ? 4 : 0)); addbyte(0xC7); /*MOVL [pc], new_pc*/ addbyte(0x45); - addbyte(cpu_state_offset(pc)); + addbyte((uint8_t)cpu_state_offset(pc)); addlong(op_pc+pc_offset+offset); if (timing_bt) { addbyte(0x83); /*SUB $codegen_block_cycles, cyclcs*/ addbyte(0x6d); - addbyte(cpu_state_offset(_cycles)); + addbyte((uint8_t)cpu_state_offset(_cycles)); addbyte(timing_bt); } addbyte(0xe9); /*JMP end*/ addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); } -static int BRANCH_COND_LE(int pc_offset, uint32_t op_pc, uint32_t offset, int not) +static inline void BRANCH_COND_LE(int pc_offset, uint32_t op_pc, uint32_t offset, int not) { switch (codegen_flags_changed ? cpu_state.flags_op : FLAGS_UNKNOWN) { case FLAGS_SUB8: addbyte(0x8a); /*MOV AL, flags_op1*/ addbyte(0x45); - addbyte(cpu_state_offset(flags_op1)); + addbyte((uint8_t)cpu_state_offset(flags_op1)); addbyte(0x3a); /*CMP AL, flags_op2*/ addbyte(0x45); - addbyte(cpu_state_offset(flags_op2)); + addbyte((uint8_t)cpu_state_offset(flags_op2)); if (not) addbyte(0x7e); /*JLE*/ else @@ -1475,11 +1602,11 @@ static int BRANCH_COND_LE(int pc_offset, uint32_t op_pc, uint32_t offset, int no addbyte(0x66); /*MOV AX, flags_op1*/ addbyte(0x8b); addbyte(0x45); - addbyte(cpu_state_offset(flags_op1)); + addbyte((uint8_t)cpu_state_offset(flags_op1)); addbyte(0x66); /*CMP AX, flags_op2*/ addbyte(0x3b); addbyte(0x45); - addbyte(cpu_state_offset(flags_op2)); + addbyte((uint8_t)cpu_state_offset(flags_op2)); if (not) addbyte(0x7e); /*JLE*/ else @@ -1488,10 +1615,10 @@ static int BRANCH_COND_LE(int pc_offset, uint32_t op_pc, uint32_t offset, int no case FLAGS_SUB32: addbyte(0x8b); /*MOV EAX, flags_op1*/ addbyte(0x45); - addbyte(cpu_state_offset(flags_op1)); + addbyte((uint8_t)cpu_state_offset(flags_op1)); addbyte(0x3b); /*CMP EAX, flags_op2*/ addbyte(0x45); - addbyte(cpu_state_offset(flags_op2)); + addbyte((uint8_t)cpu_state_offset(flags_op2)); if (not) addbyte(0x7e); /*JLE*/ else @@ -1503,13 +1630,13 @@ static int BRANCH_COND_LE(int pc_offset, uint32_t op_pc, uint32_t offset, int no { addbyte(0x83); /*CMP flags_res, 0*/ addbyte(0x7d); - addbyte(cpu_state_offset(flags_res)); + addbyte((uint8_t)cpu_state_offset(flags_res)); addbyte(0); addbyte(0x74); /*JZ +*/ } else { - CALL_FUNC(ZF_SET); + CALL_FUNC((uintptr_t)ZF_SET); addbyte(0x85); /*TEST EAX,EAX*/ addbyte(0xc0); addbyte(0x75); /*JNZ +*/ @@ -1519,13 +1646,13 @@ static int BRANCH_COND_LE(int pc_offset, uint32_t op_pc, uint32_t offset, int no else addbyte(5+2+3+5+2+3+2+2); - CALL_FUNC(NF_SET); + CALL_FUNC((uintptr_t)NF_SET); addbyte(0x85); /*TEST EAX,EAX*/ addbyte(0xc0); addbyte(0x0f); /*SETNE BL*/ addbyte(0x95); addbyte(0xc3); - CALL_FUNC(VF_SET); + CALL_FUNC((uintptr_t)VF_SET); addbyte(0x85); /*TEST EAX,EAX*/ addbyte(0xc0); addbyte(0x0f); /*SETNE AL*/ @@ -1542,13 +1669,13 @@ static int BRANCH_COND_LE(int pc_offset, uint32_t op_pc, uint32_t offset, int no addbyte(7+5+(timing_bt ? 4 : 0)); addbyte(0xC7); /*MOVL [pc], new_pc*/ addbyte(0x45); - addbyte(cpu_state_offset(pc)); + addbyte((uint8_t)cpu_state_offset(pc)); addlong(op_pc+pc_offset+offset); if (timing_bt) { addbyte(0x83); /*SUB $codegen_block_cycles, cyclcs*/ addbyte(0x6d); - addbyte(cpu_state_offset(_cycles)); + addbyte((uint8_t)cpu_state_offset(_cycles)); addbyte(timing_bt); } addbyte(0xe9); /*JMP end*/ @@ -1556,7 +1683,7 @@ static int BRANCH_COND_LE(int pc_offset, uint32_t op_pc, uint32_t offset, int no } -static void FP_ENTER() +static inline void FP_ENTER() { if (codegen_fpu_entered) return; @@ -1569,7 +1696,7 @@ static void FP_ENTER() addbyte(7+7+5+5); addbyte(0xC7); /*MOVL [oldpc],op_old_pc*/ addbyte(0x45); - addbyte(cpu_state_offset(oldpc)); + addbyte((uint8_t)cpu_state_offset(oldpc)); addlong(op_old_pc); addbyte(0xc7); /*MOV [ESP], 7*/ addbyte(0x04); @@ -1583,7 +1710,7 @@ static void FP_ENTER() codegen_fpu_entered = 1; } -static void FP_FLD(int reg) +static inline void FP_FLD(int reg) { if (codeblock[block_current].flags & CODEBLOCK_STATIC_TOP) { @@ -1591,38 +1718,38 @@ static void FP_FLD(int reg) addbyte(0x0f); addbyte(0x7e); addbyte(0x45); - addbyte(cpu_state_offset(ST[(cpu_state.TOP + reg) & 7])); + addbyte((uint8_t)cpu_state_offset(ST[(cpu_state.TOP + reg) & 7])); addbyte(0xc6); /*MOVB TOP[EBP], (TOP-1) & 7*/ addbyte(0x45); - addbyte(cpu_state_offset(TOP)); + addbyte((uint8_t)cpu_state_offset(TOP)); addbyte((cpu_state.TOP - 1) & 7); addbyte(0xf3); /*MOVQ XMM1, MM[reg][EBP]*/ addbyte(0x0f); addbyte(0x7e); addbyte(0x4d); - addbyte(cpu_state_offset(MM[(cpu_state.TOP + reg) & 7].q)); + addbyte((uint8_t)cpu_state_offset(MM[(cpu_state.TOP + reg) & 7].q)); addbyte(0x66); /*MOVQ ST[-1][EBP], XMM0*/ addbyte(0x0f); addbyte(0xd6); addbyte(0x45); - addbyte(cpu_state_offset(ST[(cpu_state.TOP - 1) & 7])); + addbyte((uint8_t)cpu_state_offset(ST[(cpu_state.TOP - 1) & 7])); addbyte(0x8a); /*MOV AL, tag[reg][EBP]*/ addbyte(0x45); - addbyte(cpu_state_offset(tag[(cpu_state.TOP + reg) & 7])); + addbyte((uint8_t)cpu_state_offset(tag[(cpu_state.TOP + reg) & 7])); addbyte(0x66); /*MOVQ MM[-1][EBP], XMM1*/ addbyte(0x0f); addbyte(0xd6); addbyte(0x4d); - addbyte(cpu_state_offset(MM[(cpu_state.TOP - 1) & 7].q)); + addbyte((uint8_t)cpu_state_offset(MM[(cpu_state.TOP - 1) & 7].q)); addbyte(0x88); /*MOV tag[-1][EBP], AL*/ addbyte(0x45); - addbyte(cpu_state_offset(tag[(cpu_state.TOP - 1) & 7])); + addbyte((uint8_t)cpu_state_offset(tag[(cpu_state.TOP - 1) & 7])); } else { addbyte(0x8b); /*MOV EAX, [TOP]*/ addbyte(0x45); - addbyte(cpu_state_offset(TOP)); + addbyte((uint8_t)cpu_state_offset(TOP)); addbyte(0x89); /*MOV EBX, EAX*/ addbyte(0xc3); if (reg) @@ -1647,46 +1774,46 @@ static void FP_FLD(int reg) addbyte(0xdd); /*FLD [ST+EAX*8]*/ addbyte(0x44); addbyte(0xc5); - addbyte(cpu_state_offset(ST)); + addbyte((uint8_t)cpu_state_offset(ST)); addbyte(0x83); /*AND EBX, 7*/ addbyte(0xe3); addbyte(0x07); addbyte(0x8b); /*MOV EDX, [ST_i64+EAX]*/ addbyte(0x54); addbyte(0xc5); - addbyte(cpu_state_offset(MM)); + addbyte((uint8_t)cpu_state_offset(MM)); addbyte(0x8b); /*MOV ECX, [ST_i64+4+EAX]*/ addbyte(0x4c); addbyte(0xc5); - addbyte(cpu_state_offset(MM)+4); + addbyte((uint8_t)cpu_state_offset(MM)+4); addbyte(0x8a); /*MOV AL, [tag+EAX]*/ addbyte(0x44); addbyte(0x05); - addbyte(cpu_state_offset(tag[0])); + addbyte((uint8_t)cpu_state_offset(tag[0])); addbyte(0xdd); /*FSTP [ST+EBX*8]*/ addbyte(0x5c); addbyte(0xdd); - addbyte(cpu_state_offset(ST)); + addbyte((uint8_t)cpu_state_offset(ST)); addbyte(0x88); /*MOV [tag+EBX], AL*/ addbyte(0x44); addbyte(0x1d); - addbyte(cpu_state_offset(tag[0])); + addbyte((uint8_t)cpu_state_offset(tag[0])); addbyte(0x89); /*MOV [ST_i64+EBX], EDX*/ addbyte(0x54); addbyte(0xdd); - addbyte(cpu_state_offset(MM)); + addbyte((uint8_t)cpu_state_offset(MM)); addbyte(0x89); /*MOV [ST_i64+EBX+4], ECX*/ addbyte(0x4c); addbyte(0xdd); - addbyte(cpu_state_offset(MM)+4); + addbyte((uint8_t)cpu_state_offset(MM)+4); addbyte(0x89); /*MOV [TOP], EBX*/ addbyte(0x5d); - addbyte(cpu_state_offset(TOP)); + addbyte((uint8_t)cpu_state_offset(TOP)); } } -static void FP_FST(int reg) +static inline void FP_FST(int reg) { if (codeblock[block_current].flags & CODEBLOCK_STATIC_TOP) { @@ -1694,32 +1821,32 @@ static void FP_FST(int reg) addbyte(0x0f); addbyte(0x7e); addbyte(0x45); - addbyte(cpu_state_offset(ST[cpu_state.TOP])); + addbyte((uint8_t)cpu_state_offset(ST[cpu_state.TOP])); addbyte(0x8a); /*MOV AL, tag[0][EBP]*/ addbyte(0x45); - addbyte(cpu_state_offset(tag[cpu_state.TOP])); + addbyte((uint8_t)cpu_state_offset(tag[cpu_state.TOP])); addbyte(0x66); /*MOVQ ST[reg][EBP], XMM0*/ addbyte(0x0f); addbyte(0xd6); addbyte(0x45); - addbyte(cpu_state_offset(ST[(cpu_state.TOP + reg) & 7])); + addbyte((uint8_t)cpu_state_offset(ST[(cpu_state.TOP + reg) & 7])); addbyte(0x88); /*MOV tag[reg][EBP], AL*/ addbyte(0x45); - addbyte(cpu_state_offset(tag[(cpu_state.TOP + reg) & 7])); + addbyte((uint8_t)cpu_state_offset(tag[(cpu_state.TOP + reg) & 7])); } else { addbyte(0x8b); /*MOV EAX, [TOP]*/ addbyte(0x45); - addbyte(cpu_state_offset(TOP)); + addbyte((uint8_t)cpu_state_offset(TOP)); addbyte(0xdd); /*FLD [ST+EAX*8]*/ addbyte(0x44); addbyte(0xc5); - addbyte(cpu_state_offset(ST)); + addbyte((uint8_t)cpu_state_offset(ST)); addbyte(0x8a); /*MOV BL, [tag+EAX]*/ addbyte(0x5c); addbyte(0x05); - addbyte(cpu_state_offset(tag[0])); + addbyte((uint8_t)cpu_state_offset(tag[0])); if (reg) { @@ -1734,15 +1861,15 @@ static void FP_FST(int reg) addbyte(0xdd); /*FSTP [ST+EAX*8]*/ addbyte(0x5c); addbyte(0xc5); - addbyte(cpu_state_offset(ST)); + addbyte((uint8_t)cpu_state_offset(ST)); addbyte(0x88); /*MOV [tag+EAX], BL*/ addbyte(0x5c); addbyte(0x05); - addbyte(cpu_state_offset(tag[0])); + addbyte((uint8_t)cpu_state_offset(tag[0])); } } -static void FP_FXCH(int reg) +static inline void FP_FXCH(int reg) { if (codeblock[block_current].flags & CODEBLOCK_STATIC_TOP) { @@ -1750,60 +1877,60 @@ static void FP_FXCH(int reg) addbyte(0x0f); addbyte(0x7e); addbyte(0x45); - addbyte(cpu_state_offset(ST[cpu_state.TOP])); + addbyte((uint8_t)cpu_state_offset(ST[cpu_state.TOP])); addbyte(0xf3); /*MOVQ XMM1, ST[reg][EBP]*/ addbyte(0x0f); addbyte(0x7e); addbyte(0x4d); - addbyte(cpu_state_offset(ST[(cpu_state.TOP + reg) & 7])); + addbyte((uint8_t)cpu_state_offset(ST[(cpu_state.TOP + reg) & 7])); addbyte(0x66); /*MOVQ ST[reg][EBP], XMM0*/ addbyte(0x0f); addbyte(0xd6); addbyte(0x45); - addbyte(cpu_state_offset(ST[(cpu_state.TOP + reg) & 7])); + addbyte((uint8_t)cpu_state_offset(ST[(cpu_state.TOP + reg) & 7])); addbyte(0xf3); /*MOVQ XMM2, MM[0][EBP]*/ addbyte(0x0f); addbyte(0x7e); addbyte(0x55); - addbyte(cpu_state_offset(MM[cpu_state.TOP].q)); + addbyte((uint8_t)cpu_state_offset(MM[cpu_state.TOP].q)); addbyte(0x66); /*MOVQ ST[0][EBP], XMM1*/ addbyte(0x0f); addbyte(0xd6); addbyte(0x4d); - addbyte(cpu_state_offset(ST[cpu_state.TOP])); + addbyte((uint8_t)cpu_state_offset(ST[cpu_state.TOP])); addbyte(0xf3); /*MOVQ XMM3, MM[reg][EBP]*/ addbyte(0x0f); addbyte(0x7e); addbyte(0x5d); - addbyte(cpu_state_offset(MM[(cpu_state.TOP + reg) & 7].q)); + addbyte((uint8_t)cpu_state_offset(MM[(cpu_state.TOP + reg) & 7].q)); addbyte(0x66); /*MOVQ MM[reg][EBP], XMM2*/ addbyte(0x0f); addbyte(0xd6); addbyte(0x55); - addbyte(cpu_state_offset(MM[(cpu_state.TOP + reg) & 7].q)); + addbyte((uint8_t)cpu_state_offset(MM[(cpu_state.TOP + reg) & 7].q)); addbyte(0x8a); /*MOV AL, tag[0][EBP]*/ addbyte(0x45); - addbyte(cpu_state_offset(tag[cpu_state.TOP])); + addbyte((uint8_t)cpu_state_offset(tag[cpu_state.TOP])); addbyte(0x66); /*MOVQ MM[0][EBP], XMM3*/ addbyte(0x0f); addbyte(0xd6); addbyte(0x5d); - addbyte(cpu_state_offset(MM[cpu_state.TOP].q)); + addbyte((uint8_t)cpu_state_offset(MM[cpu_state.TOP].q)); addbyte(0x8a); /*MOV AH, tag[reg][EBP]*/ addbyte(0x65); - addbyte(cpu_state_offset(tag[(cpu_state.TOP + reg) & 7])); + addbyte((uint8_t)cpu_state_offset(tag[(cpu_state.TOP + reg) & 7])); addbyte(0x88); /*MOV tag[reg][EBP], AL*/ addbyte(0x45); - addbyte(cpu_state_offset(tag[(cpu_state.TOP + reg) & 7])); + addbyte((uint8_t)cpu_state_offset(tag[(cpu_state.TOP + reg) & 7])); addbyte(0x88); /*MOV tag[0][EBP], AH*/ addbyte(0x65); - addbyte(cpu_state_offset(tag[cpu_state.TOP])); + addbyte((uint8_t)cpu_state_offset(tag[cpu_state.TOP])); } else { addbyte(0x8b); /*MOV EAX, [TOP]*/ addbyte(0x45); - addbyte(cpu_state_offset(TOP)); + addbyte((uint8_t)cpu_state_offset(TOP)); addbyte(0x89); /*MOV EBX, EAX*/ addbyte(0xc3); addbyte(0x83); /*ADD EAX, reg*/ @@ -1813,38 +1940,38 @@ static void FP_FXCH(int reg) addbyte(0xdd); /*FLD [ST+EBX*8]*/ addbyte(0x44); addbyte(0xdd); - addbyte(cpu_state_offset(ST)); + addbyte((uint8_t)cpu_state_offset(ST)); addbyte(0x83); /*AND EAX, 7*/ addbyte(0xe0); addbyte(0x07); addbyte(0xdd); /*FLD [ST+EAX*8]*/ addbyte(0x44); addbyte(0xc5); - addbyte(cpu_state_offset(ST)); + addbyte((uint8_t)cpu_state_offset(ST)); addbyte(0xdd); /*FSTP [ST+EBX*8]*/ addbyte(0x5c); addbyte(0xdd); - addbyte(cpu_state_offset(ST)); + addbyte((uint8_t)cpu_state_offset(ST)); addbyte(0xdd); /*FSTP [ST+EAX*8]*/ addbyte(0x5c); addbyte(0xc5); - addbyte(cpu_state_offset(ST)); + addbyte((uint8_t)cpu_state_offset(ST)); addbyte(0x8a); /*MOV CL, tag[EAX]*/ addbyte(0x4c); addbyte(0x05); - addbyte(cpu_state_offset(tag[0])); + addbyte((uint8_t)cpu_state_offset(tag[0])); addbyte(0x8a); /*MOV DL, tag[EBX]*/ addbyte(0x54); addbyte(0x1d); - addbyte(cpu_state_offset(tag[0])); + addbyte((uint8_t)cpu_state_offset(tag[0])); addbyte(0x88); /*MOV tag[EBX], CL*/ addbyte(0x4c); addbyte(0x1d); - addbyte(cpu_state_offset(tag[0])); + addbyte((uint8_t)cpu_state_offset(tag[0])); addbyte(0x88); /*MOV tag[EAX], DL*/ addbyte(0x54); addbyte(0x05); - addbyte(cpu_state_offset(tag[0])); + addbyte((uint8_t)cpu_state_offset(tag[0])); addbyte(0xbe); /*MOVL ESI, ST_int64*/ addlong((uintptr_t)cpu_state.MM); addbyte(0x8b); /*MOV ECX, ST_int64[EAX*8]*/ @@ -1879,7 +2006,7 @@ static void FP_FXCH(int reg) } -static void FP_LOAD_S() +static inline void FP_LOAD_S() { if (codeblock[block_current].flags & CODEBLOCK_STATIC_TOP) { @@ -1893,22 +2020,22 @@ static void FP_LOAD_S() addbyte(0x24); addbyte(0xc6); /*MOVB TOP[EBP], (TOP-1) & 7*/ addbyte(0x45); - addbyte(cpu_state_offset(TOP)); + addbyte((uint8_t)cpu_state_offset(TOP)); addbyte((cpu_state.TOP - 1) & 7); addbyte(0x0f); /*SETE tag[reg][EBP]*/ addbyte(0x94); addbyte(0x45); - addbyte(cpu_state_offset(tag[(cpu_state.TOP - 1) & 7])); + addbyte((uint8_t)cpu_state_offset(tag[(cpu_state.TOP - 1) & 7])); addbyte(0xdd); /*FSTP ST[reg][EBP]*/ addbyte(0x5d); - addbyte(cpu_state_offset(ST[(cpu_state.TOP - 1) & 7])); + addbyte((uint8_t)cpu_state_offset(ST[(cpu_state.TOP - 1) & 7])); block_current = block_current; } else { addbyte(0x8b); /*MOV EBX, TOP*/ addbyte(0x5d); - addbyte(cpu_state_offset(TOP)); + addbyte((uint8_t)cpu_state_offset(TOP)); addbyte(0x89); /*MOV [ESP], EAX*/ addbyte(0x04); addbyte(0x24); @@ -1925,44 +2052,44 @@ static void FP_LOAD_S() addbyte(0xc0); addbyte(0x89); /*MOV TOP, EBX*/ addbyte(0x5d); - addbyte(cpu_state_offset(TOP)); + addbyte((uint8_t)cpu_state_offset(TOP)); addbyte(0xdd); /*FSTP [ST+EBX*8]*/ addbyte(0x5c); addbyte(0xdd); - addbyte(cpu_state_offset(ST)); + addbyte((uint8_t)cpu_state_offset(ST)); addbyte(0x0f); /*SETE [tag+EBX]*/ addbyte(0x94); addbyte(0x44); addbyte(0x1d); - addbyte(cpu_state_offset(tag[0])); + addbyte((uint8_t)cpu_state_offset(tag[0])); } } -static void FP_LOAD_D() +static inline void FP_LOAD_D() { if (codeblock[block_current].flags & CODEBLOCK_STATIC_TOP) { addbyte(0x89); /*MOV ST[reg][EBP], EAX*/ addbyte(0x45); - addbyte(cpu_state_offset(ST[(cpu_state.TOP - 1) & 7])); + addbyte((uint8_t)cpu_state_offset(ST[(cpu_state.TOP - 1) & 7])); addbyte(0x09); /*OR EAX, EDX*/ addbyte(0xd0); addbyte(0x89); /*MOV ST[reg][EBP]+4, EDX*/ addbyte(0x55); - addbyte(cpu_state_offset(ST[(cpu_state.TOP - 1) & 7]) + 4); + addbyte((uint8_t)cpu_state_offset(ST[(cpu_state.TOP - 1) & 7]) + 4); addbyte(0xc6); /*MOVB TOP[EBP], (TOP-1) & 7*/ addbyte(0x45); - addbyte(cpu_state_offset(TOP)); + addbyte((uint8_t)cpu_state_offset(TOP)); addbyte((cpu_state.TOP - 1) & 7); addbyte(0x0f); /*SETE tag[reg][EBP]*/ addbyte(0x94); addbyte(0x45); - addbyte(cpu_state_offset(tag[(cpu_state.TOP - 1) & 7])); + addbyte((uint8_t)cpu_state_offset(tag[(cpu_state.TOP - 1) & 7])); } else { addbyte(0x8b); /*MOV EBX, TOP*/ addbyte(0x5d); - addbyte(cpu_state_offset(TOP)); + addbyte((uint8_t)cpu_state_offset(TOP)); addbyte(0x89); /*MOV [ESP], EAX*/ addbyte(0x04); addbyte(0x24); @@ -1986,19 +2113,19 @@ static void FP_LOAD_D() addbyte(0); addbyte(0x89); /*MOV TOP, EBX*/ addbyte(0x5d); - addbyte(cpu_state_offset(TOP)); + addbyte((uint8_t)cpu_state_offset(TOP)); addbyte(0xdd); /*FSTP [ST+EBX*8]*/ addbyte(0x5c); addbyte(0xdd); - addbyte(cpu_state_offset(ST)); + addbyte((uint8_t)cpu_state_offset(ST)); addbyte(0x0f); /*SETE [tag+EBX]*/ addbyte(0x94); addbyte(0x44); addbyte(0x1d); - addbyte(cpu_state_offset(tag[0])); + addbyte((uint8_t)cpu_state_offset(tag[0])); } } -static void FP_LOAD_IW() +static inline void FP_LOAD_IW() { if (codeblock[block_current].flags & CODEBLOCK_STATIC_TOP) { @@ -2014,21 +2141,21 @@ static void FP_LOAD_IW() addbyte(0x24); addbyte(0xc6); /*MOVB TOP[EBP], (TOP-1) & 7*/ addbyte(0x45); - addbyte(cpu_state_offset(TOP)); + addbyte((uint8_t)cpu_state_offset(TOP)); addbyte((cpu_state.TOP - 1) & 7); addbyte(0x0f); /*SETE tag[reg][EBP]*/ addbyte(0x94); addbyte(0x45); - addbyte(cpu_state_offset(tag[(cpu_state.TOP - 1) & 7])); + addbyte((uint8_t)cpu_state_offset(tag[(cpu_state.TOP - 1) & 7])); addbyte(0xdd); /*FSTP ST[reg][EBP]*/ addbyte(0x5d); - addbyte(cpu_state_offset(ST[(cpu_state.TOP - 1) & 7])); + addbyte((uint8_t)cpu_state_offset(ST[(cpu_state.TOP - 1) & 7])); } else { addbyte(0x8b); /*MOV EBX, TOP*/ addbyte(0x5d); - addbyte(cpu_state_offset(TOP)); + addbyte((uint8_t)cpu_state_offset(TOP)); addbyte(0x89); /*MOV [ESP], EAX*/ addbyte(0x04); addbyte(0x24); @@ -2046,19 +2173,19 @@ static void FP_LOAD_IW() addbyte(0); addbyte(0x89); /*MOV TOP, EBX*/ addbyte(0x5d); - addbyte(cpu_state_offset(TOP)); + addbyte((uint8_t)cpu_state_offset(TOP)); addbyte(0xdd); /*FSTP [ST+EBX*8]*/ addbyte(0x5c); addbyte(0xdd); - addbyte(cpu_state_offset(ST)); + addbyte((uint8_t)cpu_state_offset(ST)); addbyte(0x0f); /*SETE [tag+EBX]*/ addbyte(0x94); addbyte(0x44); addbyte(0x1d); - addbyte(cpu_state_offset(tag[0])); + addbyte((uint8_t)cpu_state_offset(tag[0])); } } -static void FP_LOAD_IL() +static inline void FP_LOAD_IL() { if (codeblock[block_current].flags & CODEBLOCK_STATIC_TOP) { @@ -2072,21 +2199,21 @@ static void FP_LOAD_IL() addbyte(0x24); addbyte(0xc6); /*MOVB TOP[EBP], (TOP-1) & 7*/ addbyte(0x45); - addbyte(cpu_state_offset(TOP)); + addbyte((uint8_t)cpu_state_offset(TOP)); addbyte((cpu_state.TOP - 1) & 7); addbyte(0x0f); /*SETE tag[reg][EBP]*/ addbyte(0x94); addbyte(0x45); - addbyte(cpu_state_offset(tag[(cpu_state.TOP - 1) & 7])); + addbyte((uint8_t)cpu_state_offset(tag[(cpu_state.TOP - 1) & 7])); addbyte(0xdd); /*FSTP ST[reg][EBP]*/ addbyte(0x5d); - addbyte(cpu_state_offset(ST[(cpu_state.TOP - 1) & 7])); + addbyte((uint8_t)cpu_state_offset(ST[(cpu_state.TOP - 1) & 7])); } else { addbyte(0x8b); /*MOV EBX, TOP*/ addbyte(0x5d); - addbyte(cpu_state_offset(TOP)); + addbyte((uint8_t)cpu_state_offset(TOP)); addbyte(0x89); /*MOV [ESP], EAX*/ addbyte(0x04); addbyte(0x24); @@ -2104,54 +2231,54 @@ static void FP_LOAD_IL() addbyte(0); addbyte(0x89); /*MOV TOP, EBX*/ addbyte(0x5d); - addbyte(cpu_state_offset(TOP)); + addbyte((uint8_t)cpu_state_offset(TOP)); addbyte(0xdd); /*FSTP [ST+EBX*8]*/ addbyte(0x5c); addbyte(0xdd); - addbyte(cpu_state_offset(ST)); + addbyte((uint8_t)cpu_state_offset(ST)); addbyte(0x0f); /*SETE [tag+EBX]*/ addbyte(0x94); addbyte(0x44); addbyte(0x1d); - addbyte(cpu_state_offset(tag[0])); + addbyte((uint8_t)cpu_state_offset(tag[0])); } } -static void FP_LOAD_IQ() +static inline void FP_LOAD_IQ() { if (codeblock[block_current].flags & CODEBLOCK_STATIC_TOP) { addbyte(0x89); /*MOV MM[reg][EBP], EAX*/ addbyte(0x45); - addbyte(cpu_state_offset(MM[(cpu_state.TOP - 1) & 7].q)); + addbyte((uint8_t)cpu_state_offset(MM[(cpu_state.TOP - 1) & 7].q)); addbyte(0x09); /*OR EAX, EDX*/ addbyte(0xd0); addbyte(0x89); /*MOV MM[reg][EBP]+4, EDX*/ addbyte(0x55); - addbyte(cpu_state_offset(MM[(cpu_state.TOP - 1) & 7].q) + 4); + addbyte((uint8_t)cpu_state_offset(MM[(cpu_state.TOP - 1) & 7].q) + 4); addbyte(0x0f); /*SETE AL*/ addbyte(0x94); addbyte(0xc0); addbyte(0xdf); /*FILDq MM[reg][EBP]*/ addbyte(0x6d); - addbyte(cpu_state_offset(MM[(cpu_state.TOP - 1) & 7].q)); + addbyte((uint8_t)cpu_state_offset(MM[(cpu_state.TOP - 1) & 7].q)); addbyte(0x0c); /*OR AL, TAG_UINT64*/ addbyte(TAG_UINT64); addbyte(0xc6); /*MOVB TOP[EBP], (TOP-1) & 7*/ addbyte(0x45); - addbyte(cpu_state_offset(TOP)); + addbyte((uint8_t)cpu_state_offset(TOP)); addbyte((cpu_state.TOP - 1) & 7); addbyte(0x88); /*MOV tag[reg][EBP], AL*/ addbyte(0x45); - addbyte(cpu_state_offset(tag[(cpu_state.TOP - 1) & 7])); + addbyte((uint8_t)cpu_state_offset(tag[(cpu_state.TOP - 1) & 7])); addbyte(0xdd); /*FSTP ST[reg][EBP]*/ addbyte(0x5d); - addbyte(cpu_state_offset(ST[(cpu_state.TOP - 1) & 7])); + addbyte((uint8_t)cpu_state_offset(ST[(cpu_state.TOP - 1) & 7])); } else { addbyte(0x8b); /*MOV EBX, TOP*/ addbyte(0x5d); - addbyte(cpu_state_offset(TOP)); + addbyte((uint8_t)cpu_state_offset(TOP)); addbyte(0x83); /*SUB EBX, 1*/ addbyte(0xeb); addbyte(1); @@ -2161,65 +2288,65 @@ static void FP_LOAD_IQ() addbyte(0x89); /*MOV [ST_i64+EBX*8], EAX*/ addbyte(0x44); addbyte(0xdd); - addbyte(cpu_state_offset(MM)); + addbyte((uint8_t)cpu_state_offset(MM)); addbyte(0x09); /*OR EAX, EDX*/ addbyte(0xd0); addbyte(0x89); /*MOV [ST_i64+4+EBX*8], EDX*/ addbyte(0x54); addbyte(0xdd); - addbyte(cpu_state_offset(MM)+4); + addbyte((uint8_t)cpu_state_offset(MM)+4); addbyte(0x83); /*CMP EAX, 0*/ addbyte(0xf8); addbyte(0); addbyte(0xdf); /*FILDl [ST_i64+EBX*8]*/ addbyte(0x6c); addbyte(0xdd); - addbyte(cpu_state_offset(MM)); + addbyte((uint8_t)cpu_state_offset(MM)); addbyte(0x0f); /*SETE AL*/ addbyte(0x94); addbyte(0xc0); addbyte(0xdd); /*FSTP [ST+EBX*8]*/ addbyte(0x5c); addbyte(0xdd); - addbyte(cpu_state_offset(ST)); + addbyte((uint8_t)cpu_state_offset(ST)); addbyte(0x0c); /*OR AL, TAG_UINT64*/ addbyte(TAG_UINT64); addbyte(0x89); /*MOV TOP, EBX*/ addbyte(0x5d); - addbyte(cpu_state_offset(TOP)); + addbyte((uint8_t)cpu_state_offset(TOP)); addbyte(0x88); /*MOV [tag+EBX], AL*/ addbyte(0x44); addbyte(0x1d); - addbyte(cpu_state_offset(tag[0])); + addbyte((uint8_t)cpu_state_offset(tag[0])); } } -static void FP_LOAD_IMM_Q(uint64_t v) +static inline void FP_LOAD_IMM_Q(uint64_t v) { if (codeblock[block_current].flags & CODEBLOCK_STATIC_TOP) { addbyte(0xc7); /*MOV ST[reg][EBP], v*/ addbyte(0x45); - addbyte(cpu_state_offset(ST[(cpu_state.TOP - 1) & 7])); + addbyte((uint8_t)cpu_state_offset(ST[(cpu_state.TOP - 1) & 7])); addlong(v & 0xffffffff); addbyte(0xc7); /*MOV ST[reg][EBP]+4, v*/ addbyte(0x45); - addbyte(cpu_state_offset(ST[(cpu_state.TOP - 1) & 7]) + 4); + addbyte((uint8_t)cpu_state_offset(ST[(cpu_state.TOP - 1) & 7]) + 4); addlong(v >> 32); addbyte(0xc6); /*MOVB TOP[EBP], (TOP-1) & 7*/ addbyte(0x45); - addbyte(cpu_state_offset(TOP)); + addbyte((uint8_t)cpu_state_offset(TOP)); addbyte((cpu_state.TOP - 1) & 7); addbyte(0xc6); /*MOVB tag[reg][EBP], 1:0*/ addbyte(0x45); - addbyte(cpu_state_offset(tag[(cpu_state.TOP - 1) & 7])); + addbyte((uint8_t)cpu_state_offset(tag[(cpu_state.TOP - 1) & 7])); addbyte(v ? 0 : 1); } else { addbyte(0x8b); /*MOV EBX, TOP*/ addbyte(0x5d); - addbyte(cpu_state_offset(TOP)); + addbyte((uint8_t)cpu_state_offset(TOP)); addbyte(0x83); /*SUB EBX, 1*/ addbyte(0xeb); addbyte(1); @@ -2229,37 +2356,37 @@ static void FP_LOAD_IMM_Q(uint64_t v) addbyte(0xc7); /*MOV ST[EBP+EBX*8], v*/ addbyte(0x44); addbyte(0xdd); - addbyte(cpu_state_offset(ST)); + addbyte((uint8_t)cpu_state_offset(ST)); addlong(v & 0xffffffff); addbyte(0xc7); /*MOV ST[EBP+EBX*8]+4, v*/ addbyte(0x44); addbyte(0xdd); - addbyte(cpu_state_offset(ST) + 4); + addbyte((uint8_t)cpu_state_offset(ST) + 4); addlong(v >> 32); addbyte(0xc6); /*MOVB tag[reg][EBP], 1:0*/ addbyte(0x44); addbyte(0x1d); - addbyte(cpu_state_offset(tag[0])); + addbyte((uint8_t)cpu_state_offset(tag[0])); addbyte(v ? 0 : 1); addbyte(0x89); /*MOV TOP, EBX*/ addbyte(0x5d); - addbyte(cpu_state_offset(TOP)); + addbyte((uint8_t)cpu_state_offset(TOP)); } } -static int FP_LOAD_REG(int reg) +static inline int FP_LOAD_REG(int reg) { if (codeblock[block_current].flags & CODEBLOCK_STATIC_TOP) { addbyte(0xdd); /*FLD ST[reg][EBP]*/ addbyte(0x45); - addbyte(cpu_state_offset(ST[(cpu_state.TOP + reg) & 7])); + addbyte((uint8_t)cpu_state_offset(ST[(cpu_state.TOP + reg) & 7])); } else { addbyte(0x8b); /*MOV EBX, TOP*/ addbyte(0x5d); - addbyte(cpu_state_offset(TOP)); + addbyte((uint8_t)cpu_state_offset(TOP)); if (reg) { addbyte(0x83); /*ADD EBX, reg*/ @@ -2272,7 +2399,7 @@ static int FP_LOAD_REG(int reg) addbyte(0xdd); /*FLD ST[EBX*8]*/ addbyte(0x44); addbyte(0xdd); - addbyte(cpu_state_offset(ST)); + addbyte((uint8_t)cpu_state_offset(ST)); } addbyte(0xd9); /*FSTP [ESP]*/ addbyte(0x1c); @@ -2284,19 +2411,19 @@ static int FP_LOAD_REG(int reg) return REG_EBX; } -static void FP_LOAD_REG_D(int reg, int *host_reg1, int *host_reg2) +static inline void FP_LOAD_REG_D(int reg, int *host_reg1, int *host_reg2) { if (codeblock[block_current].flags & CODEBLOCK_STATIC_TOP) { addbyte(0xdd); /*FLD ST[reg][EBP]*/ addbyte(0x45); - addbyte(cpu_state_offset(ST[(cpu_state.TOP + reg) & 7])); + addbyte((uint8_t)cpu_state_offset(ST[(cpu_state.TOP + reg) & 7])); } else { addbyte(0x8b); /*MOV EBX, TOP*/ addbyte(0x5d); - addbyte(cpu_state_offset(TOP)); + addbyte((uint8_t)cpu_state_offset(TOP)); if (reg) { addbyte(0x83); /*ADD EBX, reg*/ @@ -2309,7 +2436,7 @@ static void FP_LOAD_REG_D(int reg, int *host_reg1, int *host_reg2) addbyte(0xdd); /*FLD ST[EBX*8]*/ addbyte(0x44); addbyte(0xdd); - addbyte(cpu_state_offset(ST)); + addbyte((uint8_t)cpu_state_offset(ST)); } addbyte(0xdd); /*FSTP [ESP]*/ addbyte(0x1c); @@ -2326,11 +2453,11 @@ static void FP_LOAD_REG_D(int reg, int *host_reg1, int *host_reg2) *host_reg2 = REG_ECX; } -static int FP_LOAD_REG_INT_W(int reg) +static inline int FP_LOAD_REG_INT_W(int reg) { addbyte(0x8b); /*MOV EBX, TOP*/ addbyte(0x5d); - addbyte(cpu_state_offset(TOP)); + addbyte((uint8_t)cpu_state_offset(TOP)); if (reg) { addbyte(0x83); /*ADD EBX, reg*/ @@ -2343,28 +2470,28 @@ static int FP_LOAD_REG_INT_W(int reg) addbyte(0xdd); /*FLD ST[EBX*8]*/ addbyte(0x44); addbyte(0xdd); - addbyte(cpu_state_offset(ST)); + addbyte((uint8_t)cpu_state_offset(ST)); addbyte(0xd9); /*FLDCW cpu_state.new_npxc*/ addbyte(0x6d); - addbyte(cpu_state_offset(new_npxc)); + addbyte((uint8_t)cpu_state_offset(new_npxc)); addbyte(0xdb); /*FISTP [ESP]*/ addbyte(0x1c); addbyte(0x24); addbyte(0xd9); /*FLDCW cpu_state.old_npxc*/ addbyte(0x6d); - addbyte(cpu_state_offset(old_npxc)); + addbyte((uint8_t)cpu_state_offset(old_npxc)); addbyte(0x8b); /*MOV EBX, [ESP]*/ addbyte(0x1c); addbyte(0x24); return REG_EBX; } -static int FP_LOAD_REG_INT(int reg) +static inline int FP_LOAD_REG_INT(int reg) { addbyte(0x8b); /*MOV EBX, TOP*/ addbyte(0x5d); - addbyte(cpu_state_offset(TOP)); + addbyte((uint8_t)cpu_state_offset(TOP)); if (reg) { addbyte(0x83); /*ADD EBX, reg*/ @@ -2377,28 +2504,28 @@ static int FP_LOAD_REG_INT(int reg) addbyte(0xdd); /*FLD ST[EBX*8]*/ addbyte(0x44); addbyte(0xdd); - addbyte(cpu_state_offset(ST)); + addbyte((uint8_t)cpu_state_offset(ST)); addbyte(0xd9); /*FLDCW cpu_state.new_npxc*/ addbyte(0x6d); - addbyte(cpu_state_offset(new_npxc)); + addbyte((uint8_t)cpu_state_offset(new_npxc)); addbyte(0xdb); /*FISTP [ESP]*/ addbyte(0x1c); addbyte(0x24); addbyte(0xd9); /*FLDCW cpu_state.old_npxc*/ addbyte(0x6d); - addbyte(cpu_state_offset(old_npxc)); + addbyte((uint8_t)cpu_state_offset(old_npxc)); addbyte(0x8b); /*MOV EBX, [ESP]*/ addbyte(0x1c); addbyte(0x24); return REG_EBX; } -static void FP_LOAD_REG_INT_Q(int reg, int *host_reg1, int *host_reg2) +static inline void FP_LOAD_REG_INT_Q(int reg, int *host_reg1, int *host_reg2) { addbyte(0x8b); /*MOV EBX, TOP*/ addbyte(0x5d); - addbyte(cpu_state_offset(TOP)); + addbyte((uint8_t)cpu_state_offset(TOP)); if (reg) { addbyte(0x83); /*ADD EBX, reg*/ @@ -2416,11 +2543,11 @@ static void FP_LOAD_REG_INT_Q(int reg, int *host_reg1, int *host_reg2) addbyte(0x8b); /*MOV ECX, [ST_i64+EBX*8]*/ addbyte(0x4c); addbyte(0xdd); - addbyte(cpu_state_offset(MM)+4); + addbyte((uint8_t)cpu_state_offset(MM)+4); addbyte(0x8b); /*MOV EBX, [ST_i64+EBX*8]*/ addbyte(0x5c); addbyte(0xdd); - addbyte(cpu_state_offset(MM)); + addbyte((uint8_t)cpu_state_offset(MM)); return; } @@ -2428,7 +2555,7 @@ static void FP_LOAD_REG_INT_Q(int reg, int *host_reg1, int *host_reg2) addbyte(0xf6); /*TEST TAG[EBX], TAG_UINT64*/ addbyte(0x44); addbyte(0x1d); - addbyte(cpu_state_offset(tag[0])); + addbyte((uint8_t)cpu_state_offset(tag[0])); addbyte(TAG_UINT64); addbyte(0x74); /*JZ +*/ addbyte(4+4+2); @@ -2436,11 +2563,11 @@ static void FP_LOAD_REG_INT_Q(int reg, int *host_reg1, int *host_reg2) addbyte(0x8b); /*MOV ECX, [ST_i64+EBX*8]*/ addbyte(0x4c); addbyte(0xdd); - addbyte(cpu_state_offset(MM)+4); + addbyte((uint8_t)cpu_state_offset(MM)+4); addbyte(0x8b); /*MOV EBX, [ST_i64+EBX*8]*/ addbyte(0x5c); addbyte(0xdd); - addbyte(cpu_state_offset(MM)); + addbyte((uint8_t)cpu_state_offset(MM)); addbyte(0xeb); /*JMP done*/ addbyte(4+3+3+3+3+4); @@ -2448,17 +2575,17 @@ static void FP_LOAD_REG_INT_Q(int reg, int *host_reg1, int *host_reg2) addbyte(0xdd); /*FLD ST[EBX*8]*/ addbyte(0x44); addbyte(0xdd); - addbyte(cpu_state_offset(ST)); + addbyte((uint8_t)cpu_state_offset(ST)); addbyte(0xd9); /*FLDCW cpu_state.new_npxc*/ addbyte(0x6d); - addbyte(cpu_state_offset(new_npxc)); + addbyte((uint8_t)cpu_state_offset(new_npxc)); addbyte(0xdf); /*FISTPQ [ESP]*/ addbyte(0x3c); addbyte(0x24); addbyte(0xd9); /*FLDCW cpu_state.old_npxc*/ addbyte(0x6d); - addbyte(cpu_state_offset(old_npxc)); + addbyte((uint8_t)cpu_state_offset(old_npxc)); addbyte(0x8b); /*MOV EBX, [ESP]*/ addbyte(0x1c); addbyte(0x24); @@ -2471,28 +2598,28 @@ static void FP_LOAD_REG_INT_Q(int reg, int *host_reg1, int *host_reg2) *host_reg2 = REG_ECX; } -static void FP_POP() +static inline void FP_POP() { if (codeblock[block_current].flags & CODEBLOCK_STATIC_TOP) { addbyte(0xc6); /*MOVB tag[0][EBP], 3*/ addbyte(0x45); - addbyte(cpu_state_offset(tag[cpu_state.TOP])); + addbyte((uint8_t)cpu_state_offset(tag[cpu_state.TOP])); addbyte(3); addbyte(0xc6); /*MOVB TOP[EBP], (TOP-1) & 7*/ addbyte(0x45); - addbyte(cpu_state_offset(TOP)); + addbyte((uint8_t)cpu_state_offset(TOP)); addbyte((cpu_state.TOP + 1) & 7); } else { addbyte(0x8b); /*MOV EAX, TOP*/ addbyte(0x45); - addbyte(cpu_state_offset(TOP)); + addbyte((uint8_t)cpu_state_offset(TOP)); addbyte(0xc6); /*MOVB tag[EAX], 3*/ addbyte(0x44); addbyte(0x05); - addbyte(cpu_state_offset(tag[0])); + addbyte((uint8_t)cpu_state_offset(tag[0])); addbyte(3); addbyte(0x04); /*ADD AL, 1*/ addbyte(1); @@ -2500,35 +2627,35 @@ static void FP_POP() addbyte(7); addbyte(0x88); /*MOV TOP, AL*/ addbyte(0x45); - addbyte(cpu_state_offset(TOP)); + addbyte((uint8_t)cpu_state_offset(TOP)); } } -static void FP_POP2() +static inline void FP_POP2() { if (codeblock[block_current].flags & CODEBLOCK_STATIC_TOP) { addbyte(0xc6); /*MOVB tag[0][EBP], 3*/ addbyte(0x45); - addbyte(cpu_state_offset(tag[cpu_state.TOP])); + addbyte((uint8_t)cpu_state_offset(tag[cpu_state.TOP])); addbyte(3); addbyte(0xc6); /*MOVB tag[1][EBP], 3*/ addbyte(0x45); - addbyte(cpu_state_offset(tag[(cpu_state.TOP+1)&7])); + addbyte((uint8_t)cpu_state_offset(tag[(cpu_state.TOP+1)&7])); addbyte(3); addbyte(0xc6); /*MOVB TOP[EBP], (TOP+2) & 7*/ addbyte(0x45); - addbyte(cpu_state_offset(TOP)); + addbyte((uint8_t)cpu_state_offset(TOP)); addbyte((cpu_state.TOP + 2) & 7); } else { addbyte(0x8b); /*MOV EAX, TOP*/ addbyte(0x45); - addbyte(cpu_state_offset(TOP)); + addbyte((uint8_t)cpu_state_offset(TOP)); addbyte(0xc6); /*MOVB tag[EAX], 3*/ addbyte(0x44); addbyte(0x05); - addbyte(cpu_state_offset(tag[0])); + addbyte((uint8_t)cpu_state_offset(tag[0])); addbyte(3); addbyte(0x04); /*ADD AL, 2*/ addbyte(2); @@ -2536,7 +2663,7 @@ static void FP_POP2() addbyte(7); addbyte(0x88); /*MOV TOP, AL*/ addbyte(0x45); - addbyte(cpu_state_offset(TOP)); + addbyte((uint8_t)cpu_state_offset(TOP)); } } @@ -2547,7 +2674,7 @@ static void FP_POP2() #define FPU_SUB 0x20 #define FPU_SUBR 0x28 -static void FP_OP_S(int op) +static inline void FP_OP_S(int op) { if (codeblock[block_current].flags & CODEBLOCK_STATIC_TOP) { @@ -2556,34 +2683,34 @@ static void FP_OP_S(int op) addbyte(0x24); addbyte(0xdd); /*FLD ST[dst][EBP]*/ addbyte(0x45); - addbyte(cpu_state_offset(ST[cpu_state.TOP])); + addbyte((uint8_t)cpu_state_offset(ST[cpu_state.TOP])); addbyte(0x80); /*AND tag[dst][EBP], ~TAG_UINT64*/ addbyte(0x65); - addbyte(cpu_state_offset(tag[cpu_state.TOP])); + addbyte((uint8_t)cpu_state_offset(tag[cpu_state.TOP])); addbyte(~TAG_UINT64); addbyte(0xd8); /*FADD [ESP]*/ addbyte(0x04 | op); addbyte(0x24); addbyte(0xdd); /*FSTP ST[dst][EBP]*/ addbyte(0x5d); - addbyte(cpu_state_offset(ST[cpu_state.TOP])); + addbyte((uint8_t)cpu_state_offset(ST[cpu_state.TOP])); } else { addbyte(0x8b); /*MOV EBX, TOP*/ addbyte(0x5d); - addbyte(cpu_state_offset(TOP)); + addbyte((uint8_t)cpu_state_offset(TOP)); addbyte(0x89); /*MOV [ESP], EAX*/ addbyte(0x04); addbyte(0x24); addbyte(0xdd); /*FLD ST[EBX*8]*/ addbyte(0x44); addbyte(0xdd); - addbyte(cpu_state_offset(ST)); + addbyte((uint8_t)cpu_state_offset(ST)); addbyte(0x80); /*AND tag[EBX], ~TAG_UINT64*/ addbyte(0x64); addbyte(0x1d); - addbyte(cpu_state_offset(tag[0])); + addbyte((uint8_t)cpu_state_offset(tag[0])); addbyte(~TAG_UINT64); addbyte(0xd8); /*FADD [ESP]*/ addbyte(0x04 | op); @@ -2591,10 +2718,10 @@ static void FP_OP_S(int op) addbyte(0xdd); /*FSTP [ST+EBX*8]*/ addbyte(0x5c); addbyte(0xdd); - addbyte(cpu_state_offset(ST)); + addbyte((uint8_t)cpu_state_offset(ST)); } } -static void FP_OP_D(int op) +static inline void FP_OP_D(int op) { if (codeblock[block_current].flags & CODEBLOCK_STATIC_TOP) { @@ -2609,33 +2736,33 @@ static void FP_OP_D(int op) { addbyte(0xd9); /*FLDCW cpu_state.new_npxc*/ addbyte(0x6d); - addbyte(cpu_state_offset(new_npxc)); + addbyte((uint8_t)cpu_state_offset(new_npxc)); } addbyte(0xdd); /*FLD ST[dst][EBP]*/ addbyte(0x45); - addbyte(cpu_state_offset(ST[cpu_state.TOP])); + addbyte((uint8_t)cpu_state_offset(ST[cpu_state.TOP])); addbyte(0x80); /*AND tag[dst][EBP], ~TAG_UINT64*/ addbyte(0x65); - addbyte(cpu_state_offset(tag[cpu_state.TOP])); + addbyte((uint8_t)cpu_state_offset(tag[cpu_state.TOP])); addbyte(~TAG_UINT64); addbyte(0xdc); /*FADD [ESP]*/ addbyte(0x04 | op); addbyte(0x24); addbyte(0xdd); /*FSTP ST[dst][EBP]*/ addbyte(0x5d); - addbyte(cpu_state_offset(ST[cpu_state.TOP])); + addbyte((uint8_t)cpu_state_offset(ST[cpu_state.TOP])); if (((cpu_state.npxc >> 10) & 3) && op == FPU_ADD) { addbyte(0xd9); /*FLDCW cpu_state.old_npxc*/ addbyte(0x6d); - addbyte(cpu_state_offset(old_npxc)); + addbyte((uint8_t)cpu_state_offset(old_npxc)); } } else { addbyte(0x8b); /*MOV EBX, TOP*/ addbyte(0x5d); - addbyte(cpu_state_offset(TOP)); + addbyte((uint8_t)cpu_state_offset(TOP)); addbyte(0x89); /*MOV [ESP], EAX*/ addbyte(0x04); addbyte(0x24); @@ -2643,7 +2770,7 @@ static void FP_OP_D(int op) { addbyte(0xd9); /*FLDCW cpu_state.new_npxc*/ addbyte(0x6d); - addbyte(cpu_state_offset(new_npxc)); + addbyte((uint8_t)cpu_state_offset(new_npxc)); } addbyte(0x89); /*MOV [ESP+4], EDX*/ addbyte(0x54); @@ -2652,11 +2779,11 @@ static void FP_OP_D(int op) addbyte(0xdd); /*FLD ST[EBX*8]*/ addbyte(0x44); addbyte(0xdd); - addbyte(cpu_state_offset(ST)); + addbyte((uint8_t)cpu_state_offset(ST)); addbyte(0x80); /*AND tag[EBX], ~TAG_UINT64*/ addbyte(0x64); addbyte(0x1d); - addbyte(cpu_state_offset(tag[0])); + addbyte((uint8_t)cpu_state_offset(tag[0])); addbyte(~TAG_UINT64); addbyte(0xdc); /*FADD [ESP]*/ addbyte(0x04 | op); @@ -2664,16 +2791,16 @@ static void FP_OP_D(int op) addbyte(0xdd); /*FSTP [ST+EBX*8]*/ addbyte(0x5c); addbyte(0xdd); - addbyte(cpu_state_offset(ST)); + addbyte((uint8_t)cpu_state_offset(ST)); if (((cpu_state.npxc >> 10) & 3) && op == FPU_ADD) { addbyte(0xd9); /*FLDCW cpu_state.old_npxc*/ addbyte(0x6d); - addbyte(cpu_state_offset(old_npxc)); + addbyte((uint8_t)cpu_state_offset(old_npxc)); } } } -static void FP_OP_IW(int op) +static inline void FP_OP_IW(int op) { if (codeblock[block_current].flags & CODEBLOCK_STATIC_TOP) { @@ -2683,34 +2810,34 @@ static void FP_OP_IW(int op) addbyte(0x24); addbyte(0xdd); /*FLD ST[0][EBP]*/ addbyte(0x45); - addbyte(cpu_state_offset(ST[cpu_state.TOP])); + addbyte((uint8_t)cpu_state_offset(ST[cpu_state.TOP])); addbyte(0x80); /*AND tag[0][EBP], ~TAG_UINT64*/ addbyte(0x65); - addbyte(cpu_state_offset(tag[cpu_state.TOP])); + addbyte((uint8_t)cpu_state_offset(tag[cpu_state.TOP])); addbyte(~TAG_UINT64); addbyte(0xde); /*FADD [ESP]*/ addbyte(0x04 | op); addbyte(0x24); addbyte(0xdd); /*FSTP ST[0][EBP]*/ addbyte(0x5d); - addbyte(cpu_state_offset(ST[cpu_state.TOP])); + addbyte((uint8_t)cpu_state_offset(ST[cpu_state.TOP])); } else { addbyte(0x8b); /*MOV EBX, TOP*/ addbyte(0x5d); - addbyte(cpu_state_offset(TOP)); + addbyte((uint8_t)cpu_state_offset(TOP)); addbyte(0x89); /*MOV [ESP], EAX*/ addbyte(0x04); addbyte(0x24); addbyte(0xdd); /*FLD ST[EBX*8]*/ addbyte(0x44); addbyte(0xdd); - addbyte(cpu_state_offset(ST)); + addbyte((uint8_t)cpu_state_offset(ST)); addbyte(0x80); /*AND tag[EBX], ~TAG_UINT64*/ addbyte(0x64); addbyte(0x1d); - addbyte(cpu_state_offset(tag[0])); + addbyte((uint8_t)cpu_state_offset(tag[0])); addbyte(~TAG_UINT64); addbyte(0xde); /*FADD [ESP]*/ addbyte(0x04 | op); @@ -2718,10 +2845,10 @@ static void FP_OP_IW(int op) addbyte(0xdd); /*FSTP [ST+EBX*8]*/ addbyte(0x5c); addbyte(0xdd); - addbyte(cpu_state_offset(ST)); + addbyte((uint8_t)cpu_state_offset(ST)); } } -static void FP_OP_IL(int op) +static inline void FP_OP_IL(int op) { if (codeblock[block_current].flags & CODEBLOCK_STATIC_TOP) { @@ -2730,34 +2857,34 @@ static void FP_OP_IL(int op) addbyte(0x24); addbyte(0xdd); /*FLD ST[0][EBP]*/ addbyte(0x45); - addbyte(cpu_state_offset(ST[cpu_state.TOP])); + addbyte((uint8_t)cpu_state_offset(ST[cpu_state.TOP])); addbyte(0x80); /*AND tag[0][EBP], ~TAG_UINT64*/ addbyte(0x65); - addbyte(cpu_state_offset(tag[cpu_state.TOP])); + addbyte((uint8_t)cpu_state_offset(tag[cpu_state.TOP])); addbyte(~TAG_UINT64); addbyte(0xda); /*FADD [ESP]*/ addbyte(0x04 | op); addbyte(0x24); addbyte(0xdd); /*FSTP ST[0][EBP]*/ addbyte(0x5d); - addbyte(cpu_state_offset(ST[cpu_state.TOP])); + addbyte((uint8_t)cpu_state_offset(ST[cpu_state.TOP])); } else { addbyte(0x8b); /*MOV EBX, TOP*/ addbyte(0x5d); - addbyte(cpu_state_offset(TOP)); + addbyte((uint8_t)cpu_state_offset(TOP)); addbyte(0x89); /*MOV [ESP], EAX*/ addbyte(0x04); addbyte(0x24); addbyte(0xdd); /*FLD ST[EBX*8]*/ addbyte(0x44); addbyte(0xdd); - addbyte(cpu_state_offset(ST)); + addbyte((uint8_t)cpu_state_offset(ST)); addbyte(0x80); /*AND tag[EBX], ~TAG_UINT64*/ addbyte(0x64); addbyte(0x1d); - addbyte(cpu_state_offset(tag[0])); + addbyte((uint8_t)cpu_state_offset(tag[0])); addbyte(~TAG_UINT64); addbyte(0xda); /*FADD [ESP]*/ addbyte(0x04 | op); @@ -2765,10 +2892,11 @@ static void FP_OP_IL(int op) addbyte(0xdd); /*FSTP [ST+EBX*8]*/ addbyte(0x5c); addbyte(0xdd); - addbyte(cpu_state_offset(ST)); + addbyte((uint8_t)cpu_state_offset(ST)); } } -static void FP_OP_IQ(int op) +#if 0 +static inline void FP_OP_IQ(int op) { if (codeblock[block_current].flags & CODEBLOCK_STATIC_TOP) { @@ -2781,23 +2909,23 @@ static void FP_OP_IQ(int op) addbyte(0x04); addbyte(0xdd); /*FLD ST[0][EBP]*/ addbyte(0x45); - addbyte(cpu_state_offset(ST[cpu_state.TOP])); + addbyte((uint8_t)cpu_state_offset(ST[cpu_state.TOP])); addbyte(0x80); /*AND tag[0][EBP], ~TAG_UINT64*/ addbyte(0x65); - addbyte(cpu_state_offset(tag[cpu_state.TOP])); + addbyte((uint8_t)cpu_state_offset(tag[cpu_state.TOP])); addbyte(~TAG_UINT64); addbyte(0xdc); /*FADD [ESP]*/ addbyte(0x04 | op); addbyte(0x24); addbyte(0xdd); /*FSTP ST[0][EBP]*/ addbyte(0x5d); - addbyte(cpu_state_offset(ST[cpu_state.TOP])); + addbyte((uint8_t)cpu_state_offset(ST[cpu_state.TOP])); } else { addbyte(0x8b); /*MOV EBX, TOP*/ addbyte(0x5d); - addbyte(cpu_state_offset(TOP)); + addbyte((uint8_t)cpu_state_offset(TOP)); addbyte(0x89); /*MOV [ESP], EAX*/ addbyte(0x04); addbyte(0x24); @@ -2808,11 +2936,11 @@ static void FP_OP_IQ(int op) addbyte(0xdd); /*FLD ST[EBX*8]*/ addbyte(0x44); addbyte(0xdd); - addbyte(cpu_state_offset(ST)); + addbyte((uint8_t)cpu_state_offset(ST)); addbyte(0x80); /*AND tag[EBX], ~TAG_UINT64*/ addbyte(0x64); addbyte(0x1d); - addbyte(cpu_state_offset(tag[0])); + addbyte((uint8_t)cpu_state_offset(tag[0])); addbyte(~TAG_UINT64); addbyte(0xdc); /*FADD [ESP]*/ addbyte(0x04 | op); @@ -2820,16 +2948,16 @@ static void FP_OP_IQ(int op) addbyte(0xdd); /*FSTP [ST+EBX*8]*/ addbyte(0x5c); addbyte(0xdd); - addbyte(cpu_state_offset(ST)); + addbyte((uint8_t)cpu_state_offset(ST)); } } - +#endif #define C0 (1<<8) #define C1 (1<<9) #define C2 (1<<10) #define C3 (1<<14) -static void FP_COMPARE_S() +static inline void FP_COMPARE_S() { if (codeblock[block_current].flags & CODEBLOCK_STATIC_TOP) { @@ -2838,10 +2966,10 @@ static void FP_COMPARE_S() addbyte(0x24); addbyte(0xdd); /*FLD ST[0][EBP]*/ addbyte(0x45); - addbyte(cpu_state_offset(ST[cpu_state.TOP])); + addbyte((uint8_t)cpu_state_offset(ST[cpu_state.TOP])); addbyte(0x8a); /*MOV BL, [npxs+1]*/ addbyte(0x5d); - addbyte(cpu_state_offset(npxs) + 1); + addbyte((uint8_t)cpu_state_offset(npxs) + 1); addbyte(0xdb); /*FCLEX*/ addbyte(0xe2); addbyte(0x80); /*AND BL, ~(C0|C2|C3)*/ @@ -2859,23 +2987,23 @@ static void FP_COMPARE_S() addbyte(0xe3); addbyte(0x88); /*MOV [npxs+1], BL*/ addbyte(0x5d); - addbyte(cpu_state_offset(npxs) + 1); + addbyte((uint8_t)cpu_state_offset(npxs) + 1); } else { addbyte(0x8b); /*MOV EBX, TOP*/ addbyte(0x5d); - addbyte(cpu_state_offset(TOP)); + addbyte((uint8_t)cpu_state_offset(TOP)); addbyte(0x89); /*MOV [ESP], EAX*/ addbyte(0x04); addbyte(0x24); addbyte(0xdd); /*FLD ST[EBX*8]*/ addbyte(0x44); addbyte(0xdd); - addbyte(cpu_state_offset(ST)); + addbyte((uint8_t)cpu_state_offset(ST)); addbyte(0x8a); /*MOV BL, [npxs+1]*/ addbyte(0x5d); - addbyte(cpu_state_offset(npxs) + 1); + addbyte((uint8_t)cpu_state_offset(npxs) + 1); addbyte(0xdb); /*FCLEX*/ addbyte(0xe2); addbyte(0x80); /*AND BL, ~(C0|C2|C3)*/ @@ -2893,10 +3021,10 @@ static void FP_COMPARE_S() addbyte(0xe3); addbyte(0x88); /*MOV [npxs+1], BL*/ addbyte(0x5d); - addbyte(cpu_state_offset(npxs) + 1); + addbyte((uint8_t)cpu_state_offset(npxs) + 1); } } -static void FP_COMPARE_D() +static inline void FP_COMPARE_D() { if (codeblock[block_current].flags & CODEBLOCK_STATIC_TOP) { @@ -2909,10 +3037,10 @@ static void FP_COMPARE_D() addbyte(0x04); addbyte(0xdd); /*FLD ST[0][EBP]*/ addbyte(0x45); - addbyte(cpu_state_offset(ST[cpu_state.TOP])); + addbyte((uint8_t)cpu_state_offset(ST[cpu_state.TOP])); addbyte(0x8a); /*MOV BL, [npxs+1]*/ addbyte(0x5d); - addbyte(cpu_state_offset(npxs) + 1); + addbyte((uint8_t)cpu_state_offset(npxs) + 1); addbyte(0xdb); /*FCLEX*/ addbyte(0xe2); addbyte(0x80); /*AND BL, ~(C0|C2|C3)*/ @@ -2930,13 +3058,13 @@ static void FP_COMPARE_D() addbyte(0xe3); addbyte(0x88); /*MOV [npxs+1], BL*/ addbyte(0x5d); - addbyte(cpu_state_offset(npxs) + 1); + addbyte((uint8_t)cpu_state_offset(npxs) + 1); } else { addbyte(0x8b); /*MOV EBX, TOP*/ addbyte(0x5d); - addbyte(cpu_state_offset(TOP)); + addbyte((uint8_t)cpu_state_offset(TOP)); addbyte(0x89); /*MOV [ESP], EAX*/ addbyte(0x04); addbyte(0x24); @@ -2947,10 +3075,10 @@ static void FP_COMPARE_D() addbyte(0xdd); /*FLD ST[EBX*8]*/ addbyte(0x44); addbyte(0xdd); - addbyte(cpu_state_offset(ST)); + addbyte((uint8_t)cpu_state_offset(ST)); addbyte(0x8a); /*MOV BL, [npxs+1]*/ addbyte(0x5d); - addbyte(cpu_state_offset(npxs) + 1); + addbyte((uint8_t)cpu_state_offset(npxs) + 1); addbyte(0xdb); /*FCLEX*/ addbyte(0xe2); addbyte(0x80); /*AND BL, ~(C0|C2|C3)*/ @@ -2968,10 +3096,10 @@ static void FP_COMPARE_D() addbyte(0xe3); addbyte(0x88); /*MOV [npxs+1], BL*/ addbyte(0x5d); - addbyte(cpu_state_offset(npxs) + 1); + addbyte((uint8_t)cpu_state_offset(npxs) + 1); } } -static void FP_COMPARE_IW() +static inline void FP_COMPARE_IW() { if (codeblock[block_current].flags & CODEBLOCK_STATIC_TOP) { @@ -2981,10 +3109,10 @@ static void FP_COMPARE_IW() addbyte(0x24); addbyte(0xdd); /*FLD ST[0][EBP]*/ addbyte(0x45); - addbyte(cpu_state_offset(ST[cpu_state.TOP])); + addbyte((uint8_t)cpu_state_offset(ST[cpu_state.TOP])); addbyte(0x8a); /*MOV BL, [npxs+1]*/ addbyte(0x5d); - addbyte(cpu_state_offset(npxs) + 1); + addbyte((uint8_t)cpu_state_offset(npxs) + 1); addbyte(0xdb); /*FCLEX*/ addbyte(0xe2); addbyte(0x80); /*AND BL, ~(C0|C2|C3)*/ @@ -3002,23 +3130,23 @@ static void FP_COMPARE_IW() addbyte(0xe3); addbyte(0x88); /*MOV [npxs+1], BL*/ addbyte(0x5d); - addbyte(cpu_state_offset(npxs) + 1); + addbyte((uint8_t)cpu_state_offset(npxs) + 1); } else { addbyte(0x8b); /*MOV EBX, TOP*/ addbyte(0x5d); - addbyte(cpu_state_offset(TOP)); + addbyte((uint8_t)cpu_state_offset(TOP)); addbyte(0x89); /*MOV [ESP], EAX*/ addbyte(0x04); addbyte(0x24); addbyte(0xdd); /*FLD ST[EBX*8]*/ addbyte(0x44); addbyte(0xdd); - addbyte(cpu_state_offset(ST)); + addbyte((uint8_t)cpu_state_offset(ST)); addbyte(0x8a); /*MOV BL, [npxs+1]*/ addbyte(0x5d); - addbyte(cpu_state_offset(npxs) + 1); + addbyte((uint8_t)cpu_state_offset(npxs) + 1); addbyte(0xdb); /*FCLEX*/ addbyte(0xe2); addbyte(0x80); /*AND BL, ~(C0|C2|C3)*/ @@ -3036,10 +3164,10 @@ static void FP_COMPARE_IW() addbyte(0xe3); addbyte(0x88); /*MOV [npxs+1], BL*/ addbyte(0x5d); - addbyte(cpu_state_offset(npxs) + 1); + addbyte((uint8_t)cpu_state_offset(npxs) + 1); } } -static void FP_COMPARE_IL() +static inline void FP_COMPARE_IL() { if (codeblock[block_current].flags & CODEBLOCK_STATIC_TOP) { @@ -3048,10 +3176,10 @@ static void FP_COMPARE_IL() addbyte(0x24); addbyte(0xdd); /*FLD ST[0][EBP]*/ addbyte(0x45); - addbyte(cpu_state_offset(ST[cpu_state.TOP])); + addbyte((uint8_t)cpu_state_offset(ST[cpu_state.TOP])); addbyte(0x8a); /*MOV BL, [npxs+1]*/ addbyte(0x5d); - addbyte(cpu_state_offset(npxs) + 1); + addbyte((uint8_t)cpu_state_offset(npxs) + 1); addbyte(0xdb); /*FCLEX*/ addbyte(0xe2); addbyte(0x80); /*AND BL, ~(C0|C2|C3)*/ @@ -3069,23 +3197,23 @@ static void FP_COMPARE_IL() addbyte(0xe3); addbyte(0x88); /*MOV [npxs+1], BL*/ addbyte(0x5d); - addbyte(cpu_state_offset(npxs) + 1); + addbyte((uint8_t)cpu_state_offset(npxs) + 1); } else { addbyte(0x8b); /*MOV EBX, TOP*/ addbyte(0x5d); - addbyte(cpu_state_offset(TOP)); + addbyte((uint8_t)cpu_state_offset(TOP)); addbyte(0x89); /*MOV [ESP], EAX*/ addbyte(0x04); addbyte(0x24); addbyte(0xdd); /*FLD ST[EBX*8]*/ addbyte(0x44); addbyte(0xdd); - addbyte(cpu_state_offset(ST)); + addbyte((uint8_t)cpu_state_offset(ST)); addbyte(0x8a); /*MOV BL, [npxs+1]*/ addbyte(0x5d); - addbyte(cpu_state_offset(npxs) + 1); + addbyte((uint8_t)cpu_state_offset(npxs) + 1); addbyte(0xdb); /*FCLEX*/ addbyte(0xe2); addbyte(0x80); /*AND BL, ~(C0|C2|C3)*/ @@ -3103,33 +3231,33 @@ static void FP_COMPARE_IL() addbyte(0xe3); addbyte(0x88); /*MOV [npxs+1], BL*/ addbyte(0x5d); - addbyte(cpu_state_offset(npxs) + 1); + addbyte((uint8_t)cpu_state_offset(npxs) + 1); } } -static void FP_OP_REG(int op, int dst, int src) +static inline void FP_OP_REG(int op, int dst, int src) { if (codeblock[block_current].flags & CODEBLOCK_STATIC_TOP) { addbyte(0xdd); /*FLD ST[dst][EBP]*/ addbyte(0x45); - addbyte(cpu_state_offset(ST[(cpu_state.TOP + dst) & 7])); + addbyte((uint8_t)cpu_state_offset(ST[(cpu_state.TOP + dst) & 7])); addbyte(0xdc); /*FADD ST[src][EBP]*/ addbyte(0x45 | op); - addbyte(cpu_state_offset(ST[(cpu_state.TOP + src) & 7])); + addbyte((uint8_t)cpu_state_offset(ST[(cpu_state.TOP + src) & 7])); addbyte(0x80); /*AND tag[dst][EBP], ~TAG_UINT64*/ addbyte(0x65); - addbyte(cpu_state_offset(tag[(cpu_state.TOP + dst) & 7])); + addbyte((uint8_t)cpu_state_offset(tag[(cpu_state.TOP + dst) & 7])); addbyte(~TAG_UINT64); addbyte(0xdd); /*FSTP ST[dst][EBP]*/ addbyte(0x5d); - addbyte(cpu_state_offset(ST[(cpu_state.TOP + dst) & 7])); + addbyte((uint8_t)cpu_state_offset(ST[(cpu_state.TOP + dst) & 7])); } else { addbyte(0x8b); /*MOV EAX, TOP*/ addbyte(0x45); - addbyte(cpu_state_offset(TOP)); + addbyte((uint8_t)cpu_state_offset(TOP)); addbyte(0x89); /*MOV EBX, EAX*/ addbyte(0xc3); if (src || dst) @@ -3147,62 +3275,62 @@ static void FP_OP_REG(int op, int dst, int src) addbyte(0xdd); /*FLD ST[EBX*8]*/ addbyte(0x44); addbyte(0xdd); - addbyte(cpu_state_offset(ST)); + addbyte((uint8_t)cpu_state_offset(ST)); addbyte(0x80); /*AND tag[EBX], ~TAG_UINT64*/ addbyte(0x64); addbyte(0x1d); - addbyte(cpu_state_offset(tag[0])); + addbyte((uint8_t)cpu_state_offset(tag[0])); addbyte(~TAG_UINT64); addbyte(0xdc); /*FADD ST[EAX*8]*/ addbyte(0x44 | op); addbyte(0xc5); - addbyte(cpu_state_offset(ST)); + addbyte((uint8_t)cpu_state_offset(ST)); addbyte(0xdd); /*FSTP ST[EBX*8]*/ addbyte(0x5c); addbyte(0xdd); - addbyte(cpu_state_offset(ST)); + addbyte((uint8_t)cpu_state_offset(ST)); } else { addbyte(0xdd); /*FLD [ESI+EAX*8]*/ addbyte(0x44); addbyte(0xc5); - addbyte(cpu_state_offset(ST)); + addbyte((uint8_t)cpu_state_offset(ST)); addbyte(0x80); /*AND tag[EAX], ~TAG_UINT64*/ addbyte(0x64); addbyte(0x05); - addbyte(cpu_state_offset(tag[0])); + addbyte((uint8_t)cpu_state_offset(tag[0])); addbyte(~TAG_UINT64); addbyte(0xdc); /*FADD ST[EBX*8]*/ addbyte(0x44 | op); addbyte(0xdd); - addbyte(cpu_state_offset(ST)); + addbyte((uint8_t)cpu_state_offset(ST)); addbyte(0xdd); /*FSTP ST[EAX*8]*/ addbyte(0x5c); addbyte(0xc5); - addbyte(cpu_state_offset(ST)); + addbyte((uint8_t)cpu_state_offset(ST)); } } } -static void FP_COMPARE_REG(int dst, int src) +static inline void FP_COMPARE_REG(int dst, int src) { if (codeblock[block_current].flags & CODEBLOCK_STATIC_TOP) { addbyte(0x8a); /*MOV CL, [npxs+1]*/ addbyte(0x4d); - addbyte(cpu_state_offset(npxs) + 1); + addbyte((uint8_t)cpu_state_offset(npxs) + 1); addbyte(0xdb); /*FCLEX*/ addbyte(0xe2); addbyte(0xdd); /*FLD ST[dst][EBP]*/ addbyte(0x45); - addbyte(cpu_state_offset(ST[(cpu_state.TOP + dst) & 7])); + addbyte((uint8_t)cpu_state_offset(ST[(cpu_state.TOP + dst) & 7])); addbyte(0x80); /*AND CL, ~(C0|C2|C3)*/ addbyte(0xe1); addbyte((~(C0|C2|C3)) >> 8); addbyte(0xdc); /*FCOMP ST[src][EBP]*/ addbyte(0x5d); - addbyte(cpu_state_offset(ST[(cpu_state.TOP + src) & 7])); + addbyte((uint8_t)cpu_state_offset(ST[(cpu_state.TOP + src) & 7])); addbyte(0xdf); /*FSTSW AX*/ addbyte(0xe0); addbyte(0x80); /*AND AH, (C0|C2|C3)*/ @@ -3212,13 +3340,13 @@ static void FP_COMPARE_REG(int dst, int src) addbyte(0xe1); addbyte(0x88); /*MOV [npxs+1], CL*/ addbyte(0x4d); - addbyte(cpu_state_offset(npxs) + 1); + addbyte((uint8_t)cpu_state_offset(npxs) + 1); } else { addbyte(0x8b); /*MOV EAX, TOP*/ addbyte(0x45); - addbyte(cpu_state_offset(TOP)); + addbyte((uint8_t)cpu_state_offset(TOP)); addbyte(0x89); /*MOV EBX, EAX*/ addbyte(0xc3); if (src || dst) @@ -3233,7 +3361,7 @@ static void FP_COMPARE_REG(int dst, int src) addbyte(0x8a); /*MOV CL, [npxs+1]*/ addbyte(0x4d); - addbyte(cpu_state_offset(npxs) + 1); + addbyte((uint8_t)cpu_state_offset(npxs) + 1); addbyte(0xdb); /*FCLEX*/ addbyte(0xe2); addbyte(0x80); /*AND CL, ~(C0|C2|C3)*/ @@ -3245,22 +3373,22 @@ static void FP_COMPARE_REG(int dst, int src) addbyte(0xdd); /*FLD ST[EBX*8]*/ addbyte(0x44); addbyte(0xdd); - addbyte(cpu_state_offset(ST)); + addbyte((uint8_t)cpu_state_offset(ST)); addbyte(0xdc); /*FCOMP ST[EAX*8]*/ addbyte(0x44 | 0x18); addbyte(0xc5); - addbyte(cpu_state_offset(ST)); + addbyte((uint8_t)cpu_state_offset(ST)); } else { addbyte(0xdd); /*FLD [ESI+EAX*8]*/ addbyte(0x44); addbyte(0xc5); - addbyte(cpu_state_offset(ST)); + addbyte((uint8_t)cpu_state_offset(ST)); addbyte(0xdc); /*FCOMP ST[EBX*8]*/ addbyte(0x44 | 0x18); addbyte(0xdd); - addbyte(cpu_state_offset(ST)); + addbyte((uint8_t)cpu_state_offset(ST)); } addbyte(0xdf); /*FSTSW AX*/ @@ -3272,57 +3400,57 @@ static void FP_COMPARE_REG(int dst, int src) addbyte(0xe1); addbyte(0x88); /*MOV [npxs+1], CL*/ addbyte(0x4d); - addbyte(cpu_state_offset(npxs) + 1); + addbyte((uint8_t)cpu_state_offset(npxs) + 1); } } -static void FP_FCHS() +static inline void FP_FCHS() { if (codeblock[block_current].flags & CODEBLOCK_STATIC_TOP) { addbyte(0xdd); /*FLD ST[0][EBP]*/ addbyte(0x45); - addbyte(cpu_state_offset(ST[cpu_state.TOP])); + addbyte((uint8_t)cpu_state_offset(ST[cpu_state.TOP])); addbyte(0xd9); /*FCHS*/ addbyte(0xe0); addbyte(0x80); /*AND tag[dst][EBP], ~TAG_UINT64*/ addbyte(0x65); - addbyte(cpu_state_offset(tag[cpu_state.TOP])); + addbyte((uint8_t)cpu_state_offset(tag[cpu_state.TOP])); addbyte(~TAG_UINT64); addbyte(0xdd); /*FSTP ST[dst][EBP]*/ addbyte(0x5d); - addbyte(cpu_state_offset(ST[cpu_state.TOP])); + addbyte((uint8_t)cpu_state_offset(ST[cpu_state.TOP])); } else { addbyte(0x8b); /*MOV EAX, TOP*/ addbyte(0x45); - addbyte(cpu_state_offset(TOP)); + addbyte((uint8_t)cpu_state_offset(TOP)); addbyte(0xdd); /*FLD [ESI+EAX*8]*/ addbyte(0x44); addbyte(0xc5); - addbyte(cpu_state_offset(ST)); + addbyte((uint8_t)cpu_state_offset(ST)); addbyte(0x80); /*AND tag[EAX], ~TAG_UINT64*/ addbyte(0x64); addbyte(0x05); - addbyte(cpu_state_offset(tag[0])); + addbyte((uint8_t)cpu_state_offset(tag[0])); addbyte(~TAG_UINT64); addbyte(0xd9); /*FCHS*/ addbyte(0xe0); addbyte(0xdd); /*FSTP ST[EAX*8]*/ addbyte(0x5c); addbyte(0xc5); - addbyte(cpu_state_offset(ST)); + addbyte((uint8_t)cpu_state_offset(ST)); } } -static void UPDATE_NPXC(int reg) +static inline void UPDATE_NPXC(int reg) { addbyte(0x66); /*AND cpu_state.new_npxc, ~0xc00*/ addbyte(0x81); addbyte(0x65); - addbyte(cpu_state_offset(new_npxc)); + addbyte((uint8_t)cpu_state_offset(new_npxc)); addword(~0xc00); if (reg) { @@ -3340,24 +3468,24 @@ static void UPDATE_NPXC(int reg) addbyte(0x66); /*OR cpu_state.new_npxc, reg*/ addbyte(0x09); addbyte(0x45 | (reg << 3)); - addbyte(cpu_state_offset(new_npxc)); + addbyte((uint8_t)cpu_state_offset(new_npxc)); } -static int ZERO_EXTEND_W_B(int reg) +static inline int ZERO_EXTEND_W_B(int reg) { addbyte(0x0f); /*MOVZX regl, regb*/ addbyte(0xb6); addbyte(0xc0 | reg | (reg << 3)); return reg; } -static int ZERO_EXTEND_L_B(int reg) +static inline int ZERO_EXTEND_L_B(int reg) { addbyte(0x0f); /*MOVZX regl, regb*/ addbyte(0xb6); addbyte(0xc0 | reg | (reg << 3)); return reg; } -static int ZERO_EXTEND_L_W(int reg) +static inline int ZERO_EXTEND_L_W(int reg) { addbyte(0x0f); /*MOVZX regl, regw*/ addbyte(0xb7); @@ -3365,21 +3493,21 @@ static int ZERO_EXTEND_L_W(int reg) return reg; } -static int SIGN_EXTEND_W_B(int reg) +static inline int SIGN_EXTEND_W_B(int reg) { addbyte(0x0f); /*MOVSX regl, regb*/ addbyte(0xbe); addbyte(0xc0 | reg | (reg << 3)); return reg; } -static int SIGN_EXTEND_L_B(int reg) +static inline int SIGN_EXTEND_L_B(int reg) { addbyte(0x0f); /*MOVSX regl, regb*/ addbyte(0xbe); addbyte(0xc0 | reg | (reg << 3)); return reg; } -static int SIGN_EXTEND_L_W(int reg) +static inline int SIGN_EXTEND_L_W(int reg) { addbyte(0x0f); /*MOVSX regl, regw*/ addbyte(0xbf); @@ -3387,12 +3515,12 @@ static int SIGN_EXTEND_L_W(int reg) return reg; } -static int COPY_REG(int src_reg) +static inline int COPY_REG(int src_reg) { return src_reg; } -static void SET_BITS(uintptr_t addr, uint32_t val) +static inline void SET_BITS(uintptr_t addr, uint32_t val) { if (val & ~0xff) { @@ -3409,7 +3537,7 @@ static void SET_BITS(uintptr_t addr, uint32_t val) addbyte(val); } } -static void CLEAR_BITS(uintptr_t addr, uint32_t val) +static inline void CLEAR_BITS(uintptr_t addr, uint32_t val) { if (val & ~0xff) { @@ -3430,7 +3558,7 @@ static void CLEAR_BITS(uintptr_t addr, uint32_t val) #define LOAD_Q_REG_1 REG_EAX #define LOAD_Q_REG_2 REG_EDX -static void MMX_ENTER() +static inline void MMX_ENTER() { if (codegen_mmx_entered) return; @@ -3443,7 +3571,7 @@ static void MMX_ENTER() addbyte(7+7+5+5); addbyte(0xC7); /*MOVL [oldpc],op_old_pc*/ addbyte(0x45); - addbyte(cpu_state_offset(oldpc)); + addbyte((uint8_t)cpu_state_offset(oldpc)); addlong(op_old_pc); addbyte(0xc7); /*MOV [ESP], 7*/ addbyte(0x04); @@ -3458,35 +3586,35 @@ static void MMX_ENTER() addbyte(0xc0); addbyte(0xc6); /*MOV ISMMX, 1*/ addbyte(0x45); - addbyte(cpu_state_offset(ismmx)); + addbyte((uint8_t)cpu_state_offset(ismmx)); addbyte(1); - addbyte(0x8b); /*MOV TOP, EAX*/ + addbyte(0x89); /*MOV TOP, EAX*/ addbyte(0x45); - addbyte(cpu_state_offset(TOP)); - addbyte(0x8b); /*MOV tag, EAX*/ + addbyte((uint8_t)cpu_state_offset(TOP)); + addbyte(0x89); /*MOV tag, EAX*/ addbyte(0x45); - addbyte(cpu_state_offset(tag[0])); - addbyte(0x8b); /*MOV tag+4, EAX*/ + addbyte((uint8_t)cpu_state_offset(tag[0])); + addbyte(0x89); /*MOV tag+4, EAX*/ addbyte(0x45); - addbyte(cpu_state_offset(tag[4])); + addbyte((uint8_t)cpu_state_offset(tag[4])); codegen_mmx_entered = 1; } extern int mmx_ebx_ecx_loaded; -static int LOAD_MMX_D(int guest_reg) +static inline int LOAD_MMX_D(int guest_reg) { int host_reg = find_host_reg(); host_reg_mapping[host_reg] = 100; addbyte(0x8b); /*MOV EBX, reg*/ addbyte(0x45 | (host_reg << 3)); - addbyte(cpu_state_offset(MM[guest_reg].l[0])); + addbyte((uint8_t)cpu_state_offset(MM[guest_reg].l[0])); return host_reg; } -static int LOAD_MMX_Q(int guest_reg, int *host_reg1, int *host_reg2) +static inline void LOAD_MMX_Q(int guest_reg, int *host_reg1, int *host_reg2) { if (!mmx_ebx_ecx_loaded) { @@ -3502,12 +3630,12 @@ static int LOAD_MMX_Q(int guest_reg, int *host_reg1, int *host_reg2) addbyte(0x8b); /*MOV EBX, reg*/ addbyte(0x45 | ((*host_reg1) << 3)); - addbyte(cpu_state_offset(MM[guest_reg].l[0])); + addbyte((uint8_t)cpu_state_offset(MM[guest_reg].l[0])); addbyte(0x8b); /*MOV ECX, reg+4*/ addbyte(0x45 | ((*host_reg2) << 3)); - addbyte(cpu_state_offset(MM[guest_reg].l[1])); + addbyte((uint8_t)cpu_state_offset(MM[guest_reg].l[1])); } -static int LOAD_MMX_Q_MMX(int guest_reg) +static inline int LOAD_MMX_Q_MMX(int guest_reg) { int dst_reg = find_host_xmm_reg(); host_reg_xmm_mapping[dst_reg] = guest_reg; @@ -3516,12 +3644,12 @@ static int LOAD_MMX_Q_MMX(int guest_reg) addbyte(0x0f); addbyte(0x7e); addbyte(0x45 | (dst_reg << 3)); - addbyte(cpu_state_offset(MM[guest_reg].q)); + addbyte((uint8_t)cpu_state_offset(MM[guest_reg].q)); return dst_reg; } -static int LOAD_INT_TO_MMX(int src_reg1, int src_reg2) +static inline int LOAD_INT_TO_MMX(int src_reg1, int src_reg2) { int dst_reg = find_host_xmm_reg(); host_reg_xmm_mapping[dst_reg] = 100; @@ -3542,36 +3670,36 @@ static int LOAD_INT_TO_MMX(int src_reg1, int src_reg2) return dst_reg; } -static void STORE_MMX_LQ(int guest_reg, int host_reg1) +static inline void STORE_MMX_LQ(int guest_reg, int host_reg1) { addbyte(0xC7); /*MOVL [reg],0*/ addbyte(0x45); - addbyte(cpu_state_offset(MM[guest_reg].l[1])); + addbyte((uint8_t)cpu_state_offset(MM[guest_reg].l[1])); addlong(0); addbyte(0x89); /*MOVL [reg],host_reg*/ addbyte(0x45 | (host_reg1 << 3)); - addbyte(cpu_state_offset(MM[guest_reg].l[0])); + addbyte((uint8_t)cpu_state_offset(MM[guest_reg].l[0])); } -static void STORE_MMX_Q(int guest_reg, int host_reg1, int host_reg2) +static inline void STORE_MMX_Q(int guest_reg, int host_reg1, int host_reg2) { addbyte(0x89); /*MOVL [reg],host_reg*/ addbyte(0x45 | (host_reg1 << 3)); - addbyte(cpu_state_offset(MM[guest_reg].l[0])); + addbyte((uint8_t)cpu_state_offset(MM[guest_reg].l[0])); addbyte(0x89); /*MOVL [reg],host_reg*/ addbyte(0x45 | (host_reg2 << 3)); - addbyte(cpu_state_offset(MM[guest_reg].l[1])); + addbyte((uint8_t)cpu_state_offset(MM[guest_reg].l[1])); } -static void STORE_MMX_Q_MMX(int guest_reg, int host_reg) +static inline void STORE_MMX_Q_MMX(int guest_reg, int host_reg) { addbyte(0x66); /*MOVQ [guest_reg],host_reg*/ addbyte(0x0f); addbyte(0xd6); addbyte(0x45 | (host_reg << 3)); - addbyte(cpu_state_offset(MM[guest_reg].q)); + addbyte((uint8_t)cpu_state_offset(MM[guest_reg].q)); } #define MMX_x86_OP(name, opcode) \ -static void MMX_ ## name(int dst_reg, int src_reg) \ +static inline void MMX_ ## name(int dst_reg, int src_reg) \ { \ addbyte(0x66); /*op dst_reg, src_reg*/ \ addbyte(0x0f); \ @@ -3624,7 +3752,7 @@ MMX_x86_OP(PMULLW, 0xd5); MMX_x86_OP(PMULHW, 0xe5); MMX_x86_OP(PMADDWD, 0xf5); -static void MMX_PACKSSWB(int dst_reg, int src_reg) +static inline void MMX_PACKSSWB(int dst_reg, int src_reg) { addbyte(0x66); /*PACKSSWB dst_reg, src_reg*/ addbyte(0x0f); @@ -3636,7 +3764,7 @@ static void MMX_PACKSSWB(int dst_reg, int src_reg) addbyte(0xc0 | (dst_reg << 3) | dst_reg); addbyte(0x08); } -static void MMX_PACKUSWB(int dst_reg, int src_reg) +static inline void MMX_PACKUSWB(int dst_reg, int src_reg) { addbyte(0x66); /*PACKUSWB dst_reg, src_reg*/ addbyte(0x0f); @@ -3648,7 +3776,7 @@ static void MMX_PACKUSWB(int dst_reg, int src_reg) addbyte(0xc0 | (dst_reg << 3) | dst_reg); addbyte(0x08); } -static void MMX_PACKSSDW(int dst_reg, int src_reg) +static inline void MMX_PACKSSDW(int dst_reg, int src_reg) { addbyte(0x66); /*PACKSSDW dst_reg, src_reg*/ addbyte(0x0f); @@ -3660,7 +3788,7 @@ static void MMX_PACKSSDW(int dst_reg, int src_reg) addbyte(0xc0 | (dst_reg << 3) | dst_reg); addbyte(0x08); } -static void MMX_PUNPCKHBW(int dst_reg, int src_reg) +static inline void MMX_PUNPCKHBW(int dst_reg, int src_reg) { addbyte(0x66); /*PUNPCKLBW dst_reg, src_reg*/ addbyte(0x0f); @@ -3672,7 +3800,7 @@ static void MMX_PUNPCKHBW(int dst_reg, int src_reg) addbyte(0xc0 | (dst_reg << 3) | dst_reg); addbyte(0x0e); } -static void MMX_PUNPCKHWD(int dst_reg, int src_reg) +static inline void MMX_PUNPCKHWD(int dst_reg, int src_reg) { addbyte(0x66); /*PUNPCKLWD dst_reg, src_reg*/ addbyte(0x0f); @@ -3684,7 +3812,7 @@ static void MMX_PUNPCKHWD(int dst_reg, int src_reg) addbyte(0xc0 | (dst_reg << 3) | dst_reg); addbyte(0x0e); } -static void MMX_PUNPCKHDQ(int dst_reg, int src_reg) +static inline void MMX_PUNPCKHDQ(int dst_reg, int src_reg) { addbyte(0x66); /*PUNPCKLDQ dst_reg, src_reg*/ addbyte(0x0f); @@ -3697,7 +3825,7 @@ static void MMX_PUNPCKHDQ(int dst_reg, int src_reg) addbyte(0x0e); } -static void MMX_PSRLW_imm(int dst_reg, int amount) +static inline void MMX_PSRLW_imm(int dst_reg, int amount) { addbyte(0x66); /*PSRLW dst_reg, amount*/ addbyte(0x0f); @@ -3705,7 +3833,7 @@ static void MMX_PSRLW_imm(int dst_reg, int amount) addbyte(0xc0 | dst_reg | 0x10); addbyte(amount); } -static void MMX_PSRAW_imm(int dst_reg, int amount) +static inline void MMX_PSRAW_imm(int dst_reg, int amount) { addbyte(0x66); /*PSRAW dst_reg, amount*/ addbyte(0x0f); @@ -3713,7 +3841,7 @@ static void MMX_PSRAW_imm(int dst_reg, int amount) addbyte(0xc0 | dst_reg | 0x20); addbyte(amount); } -static void MMX_PSLLW_imm(int dst_reg, int amount) +static inline void MMX_PSLLW_imm(int dst_reg, int amount) { addbyte(0x66); /*PSLLW dst_reg, amount*/ addbyte(0x0f); @@ -3722,7 +3850,7 @@ static void MMX_PSLLW_imm(int dst_reg, int amount) addbyte(amount); } -static void MMX_PSRLD_imm(int dst_reg, int amount) +static inline void MMX_PSRLD_imm(int dst_reg, int amount) { addbyte(0x66); /*PSRLD dst_reg, amount*/ addbyte(0x0f); @@ -3730,7 +3858,7 @@ static void MMX_PSRLD_imm(int dst_reg, int amount) addbyte(0xc0 | dst_reg | 0x10); addbyte(amount); } -static void MMX_PSRAD_imm(int dst_reg, int amount) +static inline void MMX_PSRAD_imm(int dst_reg, int amount) { addbyte(0x66); /*PSRAD dst_reg, amount*/ addbyte(0x0f); @@ -3738,7 +3866,7 @@ static void MMX_PSRAD_imm(int dst_reg, int amount) addbyte(0xc0 | dst_reg | 0x20); addbyte(amount); } -static void MMX_PSLLD_imm(int dst_reg, int amount) +static inline void MMX_PSLLD_imm(int dst_reg, int amount) { addbyte(0x66); /*PSLLD dst_reg, amount*/ addbyte(0x0f); @@ -3747,7 +3875,7 @@ static void MMX_PSLLD_imm(int dst_reg, int amount) addbyte(amount); } -static void MMX_PSRLQ_imm(int dst_reg, int amount) +static inline void MMX_PSRLQ_imm(int dst_reg, int amount) { addbyte(0x66); /*PSRLQ dst_reg, amount*/ addbyte(0x0f); @@ -3755,7 +3883,7 @@ static void MMX_PSRLQ_imm(int dst_reg, int amount) addbyte(0xc0 | dst_reg | 0x10); addbyte(amount); } -static void MMX_PSRAQ_imm(int dst_reg, int amount) +static inline void MMX_PSRAQ_imm(int dst_reg, int amount) { addbyte(0x66); /*PSRAQ dst_reg, amount*/ addbyte(0x0f); @@ -3763,7 +3891,7 @@ static void MMX_PSRAQ_imm(int dst_reg, int amount) addbyte(0xc0 | dst_reg | 0x20); addbyte(amount); } -static void MMX_PSLLQ_imm(int dst_reg, int amount) +static inline void MMX_PSLLQ_imm(int dst_reg, int amount) { addbyte(0x66); /*PSLLQ dst_reg, amount*/ addbyte(0x0f); @@ -3773,14 +3901,14 @@ static void MMX_PSLLQ_imm(int dst_reg, int amount) } -static void SAVE_EA() +static inline void SAVE_EA() { addbyte(0x89); /*MOV [ESP+12], EAX*/ addbyte(0x44); addbyte(0x24); addbyte(12); } -static void LOAD_EA() +static inline void LOAD_EA() { addbyte(0x8b); /*MOV EAX, [ESP+12]*/ addbyte(0x44); @@ -3789,38 +3917,62 @@ static void LOAD_EA() } #define MEM_CHECK_WRITE_B MEM_CHECK_WRITE -static void MEM_CHECK_WRITE(x86seg *seg) +static inline void MEM_CHECK_WRITE(x86seg *seg) { CHECK_SEG_WRITE(seg); - addbyte(0x8b); /*MOVL ESI, seg->base*/ - addbyte(0x05 | (REG_ESI << 3)); - addlong((uint32_t)&seg->base); + if ((seg == &_ds && codegen_flat_ds) || (seg == &_ss && codegen_flat_ss)) + { + addbyte(0x31); /*XOR ESI, ESI*/ + addbyte(0xf6); + } + else + { + addbyte(0x8b); /*MOVL ESI, seg->base*/ + addbyte(0x05 | (REG_ESI << 3)); + addlong((uint32_t)&seg->base); + } addbyte(0xe8); /*CALL mem_check_write*/ addlong(mem_check_write - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); LOAD_EA(); } -static void MEM_CHECK_WRITE_W(x86seg *seg) +static inline void MEM_CHECK_WRITE_W(x86seg *seg) { CHECK_SEG_WRITE(seg); - addbyte(0x8b); /*MOVL ESI, seg->base*/ - addbyte(0x05 | (REG_ESI << 3)); - addlong((uint32_t)&seg->base); + if ((seg == &_ds && codegen_flat_ds) || (seg == &_ss && codegen_flat_ss)) + { + addbyte(0x31); /*XOR ESI, ESI*/ + addbyte(0xf6); + } + else + { + addbyte(0x8b); /*MOVL ESI, seg->base*/ + addbyte(0x05 | (REG_ESI << 3)); + addlong((uint32_t)&seg->base); + } addbyte(0xe8); /*CALL mem_check_write_w*/ addlong(mem_check_write_w - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); LOAD_EA(); } -static void MEM_CHECK_WRITE_L(x86seg *seg) +static inline void MEM_CHECK_WRITE_L(x86seg *seg) { CHECK_SEG_WRITE(seg); - addbyte(0x8b); /*MOVL ESI, seg->base*/ - addbyte(0x05 | (REG_ESI << 3)); - addlong((uint32_t)&seg->base); + if ((seg == &_ds && codegen_flat_ds) || (seg == &_ss && codegen_flat_ss)) + { + addbyte(0x31); /*XOR ESI, ESI*/ + addbyte(0xf6); + } + else + { + addbyte(0x8b); /*MOVL ESI, seg->base*/ + addbyte(0x05 | (REG_ESI << 3)); + addlong((uint32_t)&seg->base); + } addbyte(0xe8); /*CALL mem_check_write_l*/ addlong(mem_check_write_l - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); LOAD_EA(); } -static void LOAD_SEG(int host_reg, void *seg) +static inline void LOAD_SEG(int host_reg, void *seg) { addbyte(0xc7); /*MOV [ESP+4], seg*/ addbyte(0x44); @@ -3830,10 +3982,10 @@ static void LOAD_SEG(int host_reg, void *seg) addbyte(0x89); /*MOV [ESP], host_reg*/ addbyte(0x04 | (host_reg << 3)); addbyte(0x24); - CALL_FUNC(loadseg); + CALL_FUNC((uintptr_t)loadseg); addbyte(0x80); /*CMP abrt, 0*/ addbyte(0x7d); - addbyte(cpu_state_offset(abrt)); + addbyte((uint8_t)cpu_state_offset(abrt)); addbyte(0); addbyte(0x0f); /*JNE end*/ addbyte(0x85); diff --git a/src/codegen_ops_xchg.h b/src/CPU/codegen_ops_xchg.h similarity index 99% rename from src/codegen_ops_xchg.h rename to src/CPU/codegen_ops_xchg.h index 0e937d187..597d26e1b 100644 --- a/src/codegen_ops_xchg.h +++ b/src/CPU/codegen_ops_xchg.h @@ -44,9 +44,9 @@ OP_XCHG_EAX_(EBP) static uint32_t ropXCHG_b(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) { -#ifdef __amd64__ +/* #ifdef __amd64__ return 0; -#else +#else */ int src_reg, dst_reg, temp_reg; if ((fetchdat & 0xc0) != 0xc0) @@ -59,7 +59,7 @@ static uint32_t ropXCHG_b(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uin STORE_REG_TARGET_B_RELEASE(temp_reg, fetchdat & 7); return op_pc + 1; -#endif +/* #endif */ } static uint32_t ropXCHG_w(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) { diff --git a/src/codegen_timing_486.c b/src/CPU/codegen_timing_486.c similarity index 99% rename from src/codegen_timing_486.c rename to src/CPU/codegen_timing_486.c index 0cd8c25b7..ddcbc260c 100644 --- a/src/codegen_timing_486.c +++ b/src/CPU/codegen_timing_486.c @@ -1,9 +1,9 @@ -#include "ibm.h" +#include "../ibm.h" +#include "../mem.h" #include "cpu.h" #include "x86.h" #include "x86_ops.h" #include "x87.h" -#include "mem.h" #include "codegen.h" #define CYCLES(c) (int *)c @@ -251,7 +251,7 @@ static int *opcode_timings_8x[8] = static int timing_count; static uint8_t last_prefix; -static inline int COUNT(int *c, int op_32) +static __inline int COUNT(int *c, int op_32) { if ((uintptr_t)c <= 10000) return (int)c; diff --git a/src/codegen_timing_686.c b/src/CPU/codegen_timing_686.c similarity index 98% rename from src/codegen_timing_686.c rename to src/CPU/codegen_timing_686.c index 5b2b5eda5..550c7e231 100644 --- a/src/codegen_timing_686.c +++ b/src/CPU/codegen_timing_686.c @@ -8,12 +8,12 @@ - Out of order execution (beyond most simplistic approximation) */ -#include "ibm.h" +#include "../ibm.h" #include "cpu.h" #include "x86.h" #include "x86_ops.h" #include "x87.h" -#include "mem.h" +#include "../mem.h" #include "codegen.h" /*Instruction has different execution time for 16 and 32 bit data. Does not pair */ @@ -855,7 +855,7 @@ void codegen_timing_686_prefix(uint8_t prefix, uint32_t fetchdat) void codegen_timing_686_opcode(uint8_t opcode, uint32_t fetchdat, int op_32) { - int *timings; + uint32_t *timings; int mod3 = ((fetchdat & 0xc0) == 0xc0); int bit8 = !(opcode & 1); @@ -863,48 +863,39 @@ void codegen_timing_686_opcode(uint8_t opcode, uint32_t fetchdat, int op_32) { case 0x0f: timings = mod3 ? opcode_timings_0f_mod3 : opcode_timings_0f; -// pclog("timings 0f\n"); break; case 0xd8: timings = mod3 ? opcode_timings_d8_mod3 : opcode_timings_d8; opcode = (opcode >> 3) & 7; -// pclog("timings d8\n"); break; case 0xd9: timings = mod3 ? opcode_timings_d9_mod3 : opcode_timings_d9; opcode = mod3 ? opcode & 0x3f : (opcode >> 3) & 7; -// pclog("timings d9\n"); break; case 0xda: timings = mod3 ? opcode_timings_da_mod3 : opcode_timings_da; opcode = (opcode >> 3) & 7; -// pclog("timings da\n"); break; case 0xdb: timings = mod3 ? opcode_timings_db_mod3 : opcode_timings_db; opcode = mod3 ? opcode & 0x3f : (opcode >> 3) & 7; -// pclog("timings db\n"); break; case 0xdc: timings = mod3 ? opcode_timings_dc_mod3 : opcode_timings_dc; opcode = (opcode >> 3) & 7; -// pclog("timings dc\n"); break; case 0xdd: timings = mod3 ? opcode_timings_dd_mod3 : opcode_timings_dd; opcode = (opcode >> 3) & 7; -// pclog("timings dd\n"); break; case 0xde: timings = mod3 ? opcode_timings_de_mod3 : opcode_timings_de; opcode = (opcode >> 3) & 7; -// pclog("timings de\n"); break; case 0xdf: timings = mod3 ? opcode_timings_df_mod3 : opcode_timings_df; opcode = (opcode >> 3) & 7; -// pclog("timings df\n"); break; default: @@ -914,7 +905,6 @@ void codegen_timing_686_opcode(uint8_t opcode, uint32_t fetchdat, int op_32) timings = mod3 ? opcode_timings_mod3 : opcode_timings_8x; if (!mod3) opcode = (fetchdat >> 3) & 7; -// pclog("timings 80 %p %p %p\n", (void *)timings, (void *)opcode_timings_mod3, (void *)opcode_timings_8x); break; case 0xc0: case 0xc1: @@ -935,22 +925,18 @@ void codegen_timing_686_opcode(uint8_t opcode, uint32_t fetchdat, int op_32) case 0xf6: timings = mod3 ? opcode_timings_f6_mod3 : opcode_timings_f6; opcode = (fetchdat >> 3) & 7; -// pclog("timings f6\n"); break; case 0xf7: timings = mod3 ? opcode_timings_f7_mod3 : opcode_timings_f7; opcode = (fetchdat >> 3) & 7; -// pclog("timings f7\n"); break; case 0xff: timings = mod3 ? opcode_timings_ff_mod3 : opcode_timings_ff; opcode = (fetchdat >> 3) & 7; -// pclog("timings ff\n"); break; default: timings = mod3 ? opcode_timings_mod3 : opcode_timings; -// pclog("timings normal\n"); break; } } @@ -970,7 +956,6 @@ void codegen_timing_686_opcode(uint8_t opcode, uint32_t fetchdat, int op_32) codegen_block_cycles += COUNT(prev_timings[prev_opcode], prev_op_32) + decode_delay; decode_delay = (-COUNT(prev_timings[prev_opcode], prev_op_32)) + 1; prev_full = 0; -// pclog("Not pairable %i\n", COUNT(prev_timings[prev_opcode], prev_op_32) + decode_delay); } else if (((timings[opcode] & PAIR_MASK) == PAIR_X || (timings[opcode] & PAIR_MASK) == PAIR_X_BRANCH) && (prev_timings[opcode] & PAIR_MASK) == PAIR_X) @@ -980,7 +965,6 @@ void codegen_timing_686_opcode(uint8_t opcode, uint32_t fetchdat, int op_32) codegen_block_cycles += COUNT(prev_timings[prev_opcode], prev_op_32) + decode_delay; decode_delay = (-COUNT(prev_timings[prev_opcode], prev_op_32)) + 1; prev_full = 0; -// pclog("Not pairable %i\n", COUNT(prev_timings[prev_opcode], prev_op_32) + decode_delay); } else if (prev_regmask & regmask) { @@ -989,7 +973,6 @@ void codegen_timing_686_opcode(uint8_t opcode, uint32_t fetchdat, int op_32) codegen_block_cycles += COUNT(prev_timings[prev_opcode], prev_op_32) + decode_delay; decode_delay = (-COUNT(prev_timings[prev_opcode], prev_op_32)) + 1; prev_full = 0; -// pclog("Not pairable %i\n", COUNT(prev_timings[prev_opcode], prev_op_32) + decode_delay); } else { @@ -1003,7 +986,6 @@ void codegen_timing_686_opcode(uint8_t opcode, uint32_t fetchdat, int op_32) decode_delay = (-t_pair) + 1; prev_full = 0; -// pclog("Pairable %i %i %i %02x %02x\n", t_pair, t1, t2, opcode, prev_opcode); return; } } @@ -1016,12 +998,10 @@ void codegen_timing_686_opcode(uint8_t opcode, uint32_t fetchdat, int op_32) /*Instruction not pairable*/ codegen_block_cycles += COUNT(timings[opcode], op_32) + decode_delay; decode_delay = (-COUNT(timings[opcode], op_32)) + 1; -// pclog("Not pairable %i\n", COUNT(timings[opcode], op_32) + decode_delay); } else { /*Instruction might pair with next*/ -// pclog("Might pair - %02x %02x %08x %08x %08x %p %p %p\n", last_prefix, opcode, timings[opcode], timings[opcode] & PAIR_MASK, PAIR_X_BRANCH, timings, opcode_timings_0f, opcode_timings_0f_mod3); prev_full = 1; prev_opcode = opcode; prev_timings = timings; diff --git a/src/codegen_timing_pentium.c b/src/CPU/codegen_timing_pentium.c similarity index 68% rename from src/codegen_timing_pentium.c rename to src/CPU/codegen_timing_pentium.c index 31d4cafe7..ecea3125d 100644 --- a/src/codegen_timing_pentium.c +++ b/src/CPU/codegen_timing_pentium.c @@ -2,21 +2,23 @@ - U/V integer pairing - FPU/FXCH pairing - Prefix decode delay (including shadowing) + - FPU latencies Elements not taken into account : - Branch prediction (beyond most simplistic approximation) - PMMX decode queue - - FPU latencies - MMX latencies */ -#include "ibm.h" +#include "../ibm.h" #include "cpu.h" #include "x86.h" #include "x86_ops.h" #include "x87.h" -#include "mem.h" +#include "../mem.h" #include "codegen.h" + + /*Instruction has different execution time for 16 and 32 bit data. Does not pair */ #define CYCLES_HAS_MULTI (1 << 28) @@ -37,69 +39,126 @@ static int pair_timings[4][4] = /*Instruction follows either register timing, read-modify, or read-modify-write. May be pairable*/ -#define CYCLES_REG (0 << 0) -#define CYCLES_RM (1 << 0) -#define CYCLES_RMW (2 << 0) -#define CYCLES_BRANCH (3 << 0) +#define CYCLES_REG (0ull << 0) +#define CYCLES_RM (1ull << 0) +#define CYCLES_RMW (2ull << 0) +#define CYCLES_BRANCH (3ull << 0) -#define CYCLES_MASK ((1 << 7) - 1) +/*Instruction has immediate data. Can only be used with PAIR_U/PAIR_V/PAIR_UV*/ +#define CYCLES_HASIMM (3ull << 2) +#define CYCLES_IMM8 (1ull << 2) +#define CYCLES_IMM1632 (2ull << 2) + +#define CYCLES_MASK ((1ull << 7) - 1) /*Instruction is MMX shift or pack/unpack instruction*/ -#define MMX_SHIFTPACK (1 << 7) +#define MMX_SHIFTPACK (1ull << 7) /*Instruction is MMX multiply instruction*/ -#define MMX_MULTIPLY (1 << 8) +#define MMX_MULTIPLY (1ull << 8) /*Instruction does not pair*/ -#define PAIR_NP (0 << 29) +#define PAIR_NP (0ull << 29) /*Instruction pairs in U pipe only*/ -#define PAIR_U (1 << 29) +#define PAIR_U (1ull << 29) /*Instruction pairs in V pipe only*/ -#define PAIR_V (2 << 29) +#define PAIR_V (2ull << 29) /*Instruction pairs in both U and V pipes*/ -#define PAIR_UV (3 << 29) +#define PAIR_UV (3ull << 29) /*Instruction pairs in U pipe only and only with FXCH*/ -#define PAIR_FX (5 << 29) +#define PAIR_FX (5ull << 29) /*Instruction is FXCH and only pairs in V pipe with FX pairable instruction*/ -#define PAIR_FXCH (6 << 29) +#define PAIR_FXCH (6ull << 29) -#define PAIR_MASK (7 << 29) +#define PAIR_FPU (4ull << 29) + +#define PAIR_MASK (7ull << 29) /*Instruction has input dependency on register in REG field*/ -#define SRCDEP_REG (1 << 9) +#define SRCDEP_REG (1ull << 9) /*Instruction has input dependency on register in R/M field*/ -#define SRCDEP_RM (1 << 10) +#define SRCDEP_RM (1ull << 10) /*Instruction modifies register in REG field*/ -#define DSTDEP_REG (1 << 11) +#define DSTDEP_REG (1ull << 11) /*Instruction modifies register in R/M field*/ -#define DSTDEP_RM (1 << 12) +#define DSTDEP_RM (1ull << 12) /*Instruction has input dependency on given register*/ -#define SRCDEP_EAX (1 << 13) -#define SRCDEP_ECX (1 << 14) -#define SRCDEP_EDX (1 << 15) -#define SRCDEP_EBX (1 << 16) -#define SRCDEP_ESP (1 << 17) -#define SRCDEP_EBP (1 << 18) -#define SRCDEP_ESI (1 << 19) -#define SRCDEP_EDI (1 << 20) +#define SRCDEP_EAX (1ull << 13) +#define SRCDEP_ECX (1ull << 14) +#define SRCDEP_EDX (1ull << 15) +#define SRCDEP_EBX (1ull << 16) +#define SRCDEP_ESP (1ull << 17) +#define SRCDEP_EBP (1ull << 18) +#define SRCDEP_ESI (1ull << 19) +#define SRCDEP_EDI (1ull << 20) /*Instruction modifies given register*/ -#define DSTDEP_EAX (1 << 21) -#define DSTDEP_ECX (1 << 22) -#define DSTDEP_EDX (1 << 23) -#define DSTDEP_EBX (1 << 24) -#define DSTDEP_ESP (1 << 25) -#define DSTDEP_EBP (1 << 26) -#define DSTDEP_ESI (1 << 27) -#define DSTDEP_EDI (1 << 28) +#define DSTDEP_EAX (1ull << 21) +#define DSTDEP_ECX (1ull << 22) +#define DSTDEP_EDX (1ull << 23) +#define DSTDEP_EBX (1ull << 24) +#define DSTDEP_ESP (1ull << 25) +#define DSTDEP_EBP (1ull << 26) +#define DSTDEP_ESI (1ull << 27) +#define DSTDEP_EDI (1ull << 28) + +/*Instruction pops the FPU stack*/ +#define FPU_POP (1ull << 32) +/*Instruction pops the FPU stack twice*/ +#define FPU_POP2 (1ull << 33) +/*Instruction pushes onto the FPU stack*/ +#define FPU_PUSH (1ull << 34) + +/*Instruction writes to ST(0)*/ +#define FPU_WRITE_ST0 (1ull << 35) +/*Instruction reads from ST(0)*/ +#define FPU_READ_ST0 (1ull << 36) +/*Instruction reads from and writes to ST(0)*/ +#define FPU_RW_ST0 (3ull << 35) + +/*Instruction reads from ST(1)*/ +#define FPU_READ_ST1 (1ull << 37) +/*Instruction writes to ST(1)*/ +#define FPU_WRITE_ST1 (1ull << 38) +/*Instruction reads from and writes to ST(1)*/ +#define FPU_RW_ST1 (3ull << 37) + +/*Instruction reads from ST(reg)*/ +#define FPU_READ_STREG (1ull << 39) +/*Instruction writes to ST(reg)*/ +#define FPU_WRITE_STREG (1ull << 40) +/*Instruction reads from and writes to ST(reg)*/ +#define FPU_RW_STREG (3ull << 39) + +/*comp_time = cycles until instruction complete + i_overlap = cycles that overlap with integer + f_overlap = cycles that overlap with subsequent FPU*/ +#define FPU_CYCLES(comp_time, i_overlap, f_overlap) ((uint64_t)comp_time) | ((uint64_t)i_overlap << 41) | ((uint64_t)f_overlap << 49) | PAIR_FPU + +#define FPU_COMP_TIME(timing) (timing & 0xff) +#define FPU_I_OVERLAP(timing) ((timing >> 41) & 0xff) +#define FPU_F_OVERLAP(timing) ((timing >> 49) & 0xff) + +#define FPU_I_LATENCY(timing) (FPU_COMP_TIME(timing) - FPU_I_OVERLAP(timing)) + +#define FPU_F_LATENCY(timing) (FPU_I_OVERLAP(timing) - FPU_F_OVERLAP(timing)) + +#define FPU_RESULT_LATENCY(timing) ((timing >> 41) & 0xff) + +#define FPU_FXCH (1ull << 56) #define INVALID 0 static int u_pipe_full; static uint32_t u_pipe_opcode; -static uint32_t *u_pipe_timings; +static uint64_t *u_pipe_timings; static uint32_t u_pipe_op_32; static uint32_t u_pipe_regmask; +static uint32_t u_pipe_fetchdat; +static int u_pipe_decode_delay_offset; + +static int fpu_latency; +static int fpu_st_latency[8]; #define REGMASK_SHIFTPACK (1 << 8) #define REGMASK_MULTIPLY (1 << 8) @@ -155,7 +214,7 @@ static uint32_t get_dstdep_mask(uint32_t data, uint32_t fetchdat, int bit8) return mask; } -static uint32_t opcode_timings[256] = +static uint64_t opcode_timings[256] = { /* ADD ADD ADD ADD*/ /*00*/ PAIR_UV | CYCLES_RMW | SRCDEP_REG, PAIR_UV | CYCLES_RMW | SRCDEP_REG, PAIR_UV | CYCLES_RM | SRCDEP_REG | DSTDEP_REG, PAIR_UV | CYCLES_RM | SRCDEP_REG | DSTDEP_REG, @@ -291,43 +350,43 @@ static uint32_t opcode_timings[256] = PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_UV | CYCLES_RMW, INVALID }; -static uint32_t opcode_timings_mod3[256] = +static uint64_t opcode_timings_mod3[256] = { /* ADD ADD ADD ADD*/ /*00*/ PAIR_UV | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, PAIR_UV | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, PAIR_UV | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, PAIR_UV | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, /* ADD ADD PUSH ES POP ES*/ - PAIR_UV | CYCLES_REG | SRCDEP_EAX | SRCDEP_RM | DSTDEP_EAX, PAIR_UV | CYCLES_REG | SRCDEP_EAX | SRCDEP_RM | DSTDEP_EAX, PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(3), + PAIR_UV | CYCLES_REG | SRCDEP_EAX | DSTDEP_EAX, PAIR_UV | CYCLES_REG | SRCDEP_EAX | DSTDEP_EAX, PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(3), /* OR OR OR OR*/ PAIR_UV | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, PAIR_UV | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, PAIR_UV | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, PAIR_UV | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, /* OR OR PUSH CS */ - PAIR_UV | CYCLES_REG | SRCDEP_EAX | SRCDEP_RM | DSTDEP_EAX, PAIR_UV | CYCLES_REG | SRCDEP_EAX | SRCDEP_RM | DSTDEP_EAX, PAIR_NP | CYCLES(1), INVALID, + PAIR_UV | CYCLES_REG | SRCDEP_EAX | DSTDEP_EAX, PAIR_UV | CYCLES_REG | SRCDEP_EAX | DSTDEP_EAX, PAIR_NP | CYCLES(1), INVALID, /* ADC ADC ADC ADC*/ /*10*/ PAIR_U | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, PAIR_U | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, PAIR_U | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, PAIR_U | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, /* ADC ADC PUSH SS POP SS*/ - PAIR_U | CYCLES_REG | SRCDEP_EAX | SRCDEP_RM | DSTDEP_EAX, PAIR_U | CYCLES_REG | SRCDEP_EAX | SRCDEP_RM | DSTDEP_EAX, PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(3), + PAIR_U | CYCLES_REG | SRCDEP_EAX | DSTDEP_EAX, PAIR_U | CYCLES_REG | SRCDEP_EAX | DSTDEP_EAX, PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(3), /* SBB SBB SBB SBB*/ PAIR_U | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, PAIR_U | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, PAIR_U | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, PAIR_U | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, /* SBB SBB PUSH DS POP DS*/ - PAIR_U | CYCLES_REG | SRCDEP_EAX | SRCDEP_RM | DSTDEP_EAX, PAIR_U | CYCLES_REG | SRCDEP_EAX | SRCDEP_RM | DSTDEP_EAX, PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(3), + PAIR_U | CYCLES_REG | SRCDEP_EAX | DSTDEP_EAX, PAIR_U | CYCLES_REG | SRCDEP_EAX | DSTDEP_EAX, PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(3), /* AND AND AND AND*/ /*20*/ PAIR_UV | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, PAIR_UV | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, PAIR_UV | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, PAIR_UV | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, /* AND AND DAA*/ - PAIR_UV | CYCLES_REG | SRCDEP_EAX | SRCDEP_RM | DSTDEP_EAX, PAIR_UV | CYCLES_REG | SRCDEP_EAX | SRCDEP_RM | DSTDEP_EAX, INVALID, PAIR_NP | CYCLES(3), + PAIR_UV | CYCLES_REG | SRCDEP_EAX | DSTDEP_EAX, PAIR_UV | CYCLES_REG | SRCDEP_EAX | DSTDEP_EAX, INVALID, PAIR_NP | CYCLES(3), /* SUB SUB SUB SUB*/ PAIR_UV | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, PAIR_UV | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, PAIR_UV | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, PAIR_UV | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, /* SUB SUB DAS*/ - PAIR_UV | CYCLES_REG | SRCDEP_EAX | SRCDEP_RM | DSTDEP_EAX, PAIR_UV | CYCLES_REG | SRCDEP_EAX | SRCDEP_RM | DSTDEP_EAX, INVALID, PAIR_NP | CYCLES(3), + PAIR_UV | CYCLES_REG | SRCDEP_EAX | DSTDEP_EAX, PAIR_UV | CYCLES_REG | SRCDEP_EAX | DSTDEP_EAX, INVALID, PAIR_NP | CYCLES(3), /* XOR XOR XOR XOR*/ /*30*/ PAIR_UV | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, PAIR_UV | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, PAIR_UV | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, PAIR_UV | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, /* XOR XOR AAA*/ - PAIR_UV | CYCLES_REG | SRCDEP_EAX | SRCDEP_RM | DSTDEP_EAX, PAIR_UV | CYCLES_REG | SRCDEP_EAX | SRCDEP_RM | DSTDEP_EAX, INVALID, PAIR_NP | CYCLES(3), + PAIR_UV | CYCLES_REG | SRCDEP_EAX | DSTDEP_EAX, PAIR_UV | CYCLES_REG | SRCDEP_EAX | DSTDEP_EAX, INVALID, PAIR_NP | CYCLES(3), /* CMP CMP CMP CMP*/ PAIR_UV | CYCLES_REG | SRCDEP_REG | SRCDEP_RM, PAIR_UV | CYCLES_REG | SRCDEP_REG | SRCDEP_RM, PAIR_UV | CYCLES_REG | SRCDEP_REG | SRCDEP_RM, PAIR_UV | CYCLES_REG | SRCDEP_RM | SRCDEP_REG, /* CMP CMP AAS*/ - PAIR_UV | CYCLES_REG | SRCDEP_EAX | SRCDEP_RM, PAIR_UV | CYCLES_REG | SRCDEP_EAX, INVALID, PAIR_NP | CYCLES(3), + PAIR_UV | CYCLES_REG | SRCDEP_EAX, PAIR_UV | CYCLES_REG | SRCDEP_EAX, INVALID, PAIR_NP | CYCLES(3), /* INC EAX INC ECX INC EDX INC EBX*/ /*40*/ PAIR_UV | CYCLES_REG | SRCDEP_EAX | DSTDEP_EAX, PAIR_UV | CYCLES_REG | SRCDEP_ECX | DSTDEP_ECX, PAIR_UV | CYCLES_REG | SRCDEP_EDX | DSTDEP_EDX, PAIR_UV | CYCLES_REG | SRCDEP_EBX | DSTDEP_EBX, @@ -428,7 +487,7 @@ static uint32_t opcode_timings_mod3[256] = PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_UV | CYCLES_REG, INVALID }; -static uint32_t opcode_timings_0f[256] = +static uint64_t opcode_timings_0f[256] = { /*00*/ PAIR_NP | CYCLES(20), PAIR_NP | CYCLES(11), PAIR_NP | CYCLES(11), PAIR_NP | CYCLES(10), INVALID, PAIR_NP | CYCLES(195), PAIR_NP | CYCLES(7), INVALID, @@ -510,7 +569,7 @@ static uint32_t opcode_timings_0f[256] = PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, INVALID, PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, INVALID, }; -static uint32_t opcode_timings_0f_mod3[256] = +static uint64_t opcode_timings_0f_mod3[256] = { /*00*/ PAIR_NP | CYCLES(20), PAIR_NP | CYCLES(11), PAIR_NP | CYCLES(11), PAIR_NP | CYCLES(10), INVALID, PAIR_NP | CYCLES(195), PAIR_NP | CYCLES(7), INVALID, @@ -593,53 +652,53 @@ static uint32_t opcode_timings_0f_mod3[256] = PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, INVALID, }; -static uint32_t opcode_timings_shift[8] = +static uint64_t opcode_timings_shift[8] = { PAIR_U | CYCLES_RMW, PAIR_U | CYCLES_RMW, PAIR_U | CYCLES_RMW, PAIR_U | CYCLES_RMW, PAIR_U | CYCLES_RMW, PAIR_U | CYCLES_RMW, PAIR_U | CYCLES_RMW, PAIR_U | CYCLES_RMW, }; -static uint32_t opcode_timings_shift_mod3[8] = +static uint64_t opcode_timings_shift_mod3[8] = { PAIR_U | CYCLES_REG | DSTDEP_RM, PAIR_U | CYCLES_REG | DSTDEP_RM, PAIR_U | CYCLES_REG | DSTDEP_RM, PAIR_U | CYCLES_REG | DSTDEP_RM, PAIR_U | CYCLES_REG | DSTDEP_RM, PAIR_U | CYCLES_REG | DSTDEP_RM, PAIR_U | CYCLES_REG | DSTDEP_RM, PAIR_U | CYCLES_REG | DSTDEP_RM, }; -static uint32_t opcode_timings_f6[8] = +static uint64_t opcode_timings_f6[8] = { /* TST NOT NEG*/ PAIR_UV | CYCLES_RM, INVALID, PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), /* MUL IMUL DIV IDIV*/ PAIR_NP | CYCLES(11), PAIR_NP | CYCLES(11), PAIR_NP | CYCLES(17), PAIR_NP | CYCLES(22) }; -static uint32_t opcode_timings_f6_mod3[8] = +static uint64_t opcode_timings_f6_mod3[8] = { /* TST NOT NEG*/ PAIR_UV | CYCLES_REG | SRCDEP_RM, INVALID, PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), /* MUL IMUL DIV IDIV*/ PAIR_NP | CYCLES(11), PAIR_NP | CYCLES(11), PAIR_NP | CYCLES(17), PAIR_NP | CYCLES(22) }; -static uint32_t opcode_timings_f7[8] = +static uint64_t opcode_timings_f7[8] = { /* TST NOT NEG*/ PAIR_UV | CYCLES_RM, INVALID, PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), /* MUL IMUL DIV IDIV*/ PAIR_NP | CYCLES_MULTI(11,10), PAIR_NP | CYCLES_MULTI(11,10), PAIR_NP | CYCLES_MULTI(25,41), PAIR_NP | CYCLES_MULTI(30,46) }; -static uint32_t opcode_timings_f7_mod3[8] = +static uint64_t opcode_timings_f7_mod3[8] = { /* TST NOT NEG*/ PAIR_UV | CYCLES_REG | SRCDEP_RM, INVALID, PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), /* MUL IMUL DIV IDIV*/ PAIR_NP | CYCLES_MULTI(11,10), PAIR_NP | CYCLES_MULTI(11,10), PAIR_NP | CYCLES_MULTI(25,41), PAIR_NP | CYCLES_MULTI(30,46) }; -static uint32_t opcode_timings_ff[8] = +static uint64_t opcode_timings_ff[8] = { /* INC DEC CALL CALL far*/ PAIR_UV | CYCLES_RMW, PAIR_UV | CYCLES_RMW, PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(0), /* JMP JMP far PUSH*/ PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(0), PAIR_NP | CYCLES(2), INVALID }; -static uint32_t opcode_timings_ff_mod3[8] = +static uint64_t opcode_timings_ff_mod3[8] = { /* INC DEC CALL CALL far*/ PAIR_UV | CYCLES_REG | SRCDEP_RM | DSTDEP_RM, PAIR_UV | CYCLES_REG | SRCDEP_RM | DSTDEP_RM, PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(0), @@ -647,82 +706,83 @@ static uint32_t opcode_timings_ff_mod3[8] = PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(0), PAIR_NP | CYCLES(2), INVALID }; -static uint32_t opcode_timings_d8[8] = +static uint64_t opcode_timings_d8[8] = { -/* FADDs FMULs FCOMs FCOMPs*/ - PAIR_FX | CYCLES(1), PAIR_FX | CYCLES(1), PAIR_FX | CYCLES(1), PAIR_FX | CYCLES(1), -/* FSUBs FSUBRs FDIVs FDIVRs*/ - PAIR_FX | CYCLES(1), PAIR_FX | CYCLES(1), PAIR_FX | CYCLES(39), PAIR_FX | CYCLES(39) +/* FADDs FMULs FCOMs FCOMPs*/ + PAIR_FX | FPU_RW_ST0 | FPU_CYCLES(3,2,2), PAIR_FX | FPU_RW_ST0 | FPU_CYCLES(3,2,2), PAIR_FX | FPU_READ_ST0 | FPU_CYCLES(1,0,0), PAIR_FX | FPU_POP | FPU_READ_ST0 | FPU_CYCLES(1,0,0), +/* FSUBs FSUBRs FDIVs FDIVRs*/ + PAIR_FX | FPU_RW_ST0 | FPU_CYCLES(3,2,2), PAIR_FX | FPU_RW_ST0 | FPU_CYCLES(3,2,2), PAIR_FX | FPU_RW_ST0 | FPU_CYCLES(39,38,2), PAIR_FX | FPU_RW_ST0 | FPU_CYCLES(39,38,2) }; -static uint32_t opcode_timings_d8_mod3[8] = +static uint64_t opcode_timings_d8_mod3[8] = { -/* FADD FMUL FCOM FCOMP*/ - PAIR_FX | CYCLES(1), PAIR_FX | CYCLES(1), PAIR_FX | CYCLES(1), PAIR_FX | CYCLES(1), -/* FSUB FSUBR FDIV FDIVR*/ - PAIR_FX | CYCLES(1), PAIR_FX | CYCLES(1), PAIR_FX | CYCLES(39), PAIR_FX | CYCLES(39) +/* FADD FMUL FCOM FCOMP*/ + PAIR_FX | FPU_RW_ST0 | FPU_READ_STREG | FPU_CYCLES(3,2,2), PAIR_FX | FPU_RW_ST0 | FPU_READ_STREG | FPU_CYCLES(3,2,2), PAIR_FX | FPU_READ_ST0 | FPU_READ_STREG | FPU_CYCLES(1,0,0), PAIR_FX | FPU_POP | FPU_READ_ST0 | FPU_READ_STREG | FPU_CYCLES(1,0,0), +/* FSUB FSUBR FDIV FDIVR*/ + PAIR_FX | FPU_RW_ST0 | FPU_READ_STREG | FPU_CYCLES(3,2,2), PAIR_FX | FPU_RW_ST0 | FPU_READ_STREG | FPU_CYCLES(3,2,2), PAIR_FX | FPU_RW_ST0 | FPU_READ_STREG | FPU_CYCLES(39,38,2), PAIR_FX | FPU_RW_ST0 | FPU_READ_STREG | FPU_CYCLES(39,38,2) }; -static uint32_t opcode_timings_d9[8] = +static uint64_t opcode_timings_d9[8] = { -/* FLDs FSTs FSTPs*/ - PAIR_FX | CYCLES(1), INVALID, PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), -/* FLDENV FLDCW FSTENV FSTCW*/ - PAIR_NP | CYCLES(32), PAIR_NP | CYCLES(7), PAIR_NP | CYCLES(48), PAIR_NP | CYCLES(2) +/* FLDs FSTs FSTPs*/ + PAIR_FX | FPU_PUSH | FPU_CYCLES(1,0,0), INVALID, PAIR_NP | FPU_READ_ST0 | FPU_CYCLES(2,0,0), PAIR_NP | FPU_READ_ST0 | FPU_POP | FPU_CYCLES(2,0,0), +/* FLDENV FLDCW FSTENV FSTCW*/ + PAIR_NP | FPU_CYCLES(32,0,0), PAIR_NP | FPU_CYCLES(8,0,0), PAIR_NP | FPU_CYCLES(48,0,0), PAIR_NP | FPU_CYCLES(2,0,0) }; -static uint32_t opcode_timings_d9_mod3[64] = +static uint64_t opcode_timings_d9_mod3[64] = { /*FLD*/ - PAIR_FX | CYCLES(1), PAIR_FX | CYCLES(1), PAIR_FX | CYCLES(1), PAIR_FX | CYCLES(1), - PAIR_FX | CYCLES(1), PAIR_FX | CYCLES(1), PAIR_FX | CYCLES(1), PAIR_FX | CYCLES(1), + PAIR_FX | FPU_PUSH | FPU_READ_STREG | FPU_CYCLES(1,0,0), PAIR_FX | FPU_PUSH | FPU_READ_STREG | FPU_CYCLES(1,0,0), PAIR_FX | FPU_PUSH | FPU_READ_STREG | FPU_CYCLES(1,0,0), PAIR_FX | FPU_PUSH | FPU_READ_STREG | FPU_CYCLES(1,0,0), + PAIR_FX | FPU_PUSH | FPU_READ_STREG | FPU_CYCLES(1,0,0), PAIR_FX | FPU_PUSH | FPU_READ_STREG | FPU_CYCLES(1,0,0), PAIR_FX | FPU_PUSH | FPU_READ_STREG | FPU_CYCLES(1,0,0), PAIR_FX | FPU_PUSH | FPU_READ_STREG | FPU_CYCLES(1,0,0), /*FXCH*/ - PAIR_V | CYCLES(0), PAIR_V | CYCLES(0), PAIR_V | CYCLES(0), PAIR_V | CYCLES(0), - PAIR_V | CYCLES(0), PAIR_V | CYCLES(0), PAIR_V | CYCLES(0), PAIR_V | CYCLES(0), + PAIR_FXCH | FPU_FXCH | CYCLES(0), PAIR_FXCH | FPU_FXCH | CYCLES(0), PAIR_FXCH | FPU_FXCH | CYCLES(0), PAIR_FXCH | FPU_FXCH | CYCLES(0), + PAIR_FXCH | FPU_FXCH | CYCLES(0), PAIR_FXCH | FPU_FXCH | CYCLES(0), PAIR_FXCH | FPU_FXCH | CYCLES(0), PAIR_FXCH | FPU_FXCH | CYCLES(0), /*FNOP*/ - PAIR_NP | CYCLES(3), INVALID, INVALID, INVALID, - INVALID, INVALID, INVALID, INVALID, + PAIR_NP | FPU_CYCLES(3,0,0), INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, /*FSTP*/ - PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), - PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), -/* opFCHS opFABS*/ - PAIR_FX | CYCLES(1), PAIR_FX | CYCLES(3), INVALID, INVALID, -/* opFTST opFXAM*/ - PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(21), INVALID, INVALID, -/* opFLD1 opFLDL2T opFLDL2E opFLDPI*/ - PAIR_NP | CYCLES(2), CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), -/* opFLDEG2 opFLDLN2 opFLDZ*/ - PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(2), INVALID, -/* opF2XM1 opFYL2X opFPTAN opFPATAN*/ - PAIR_NP | CYCLES(13), PAIR_NP | CYCLES(22), PAIR_NP | CYCLES(100), PAIR_NP | CYCLES(100), -/* opFDECSTP opFINCSTP,*/ - INVALID, INVALID, PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), -/* opFPREM opFSQRT opFSINCOS*/ - PAIR_NP | CYCLES(70), INVALID, PAIR_NP | CYCLES(70), PAIR_NP | CYCLES(50), -/* opFRNDINT opFSCALE opFSIN opFCOS*/ - PAIR_NP | CYCLES(9), PAIR_NP | CYCLES(20), PAIR_NP | CYCLES(50), PAIR_NP | CYCLES(50) + PAIR_NP | FPU_READ_ST0 | FPU_WRITE_STREG | FPU_POP | FPU_CYCLES(1,0,0), PAIR_NP | FPU_READ_ST0 | FPU_WRITE_STREG | FPU_POP | FPU_CYCLES(1,0,0), PAIR_NP | FPU_READ_ST0 | FPU_WRITE_STREG | FPU_POP | FPU_CYCLES(1,0,0), PAIR_NP | FPU_READ_ST0 | FPU_WRITE_STREG | FPU_POP | FPU_CYCLES(1,0,0), + PAIR_NP | FPU_READ_ST0 | FPU_WRITE_STREG | FPU_POP | FPU_CYCLES(1,0,0), PAIR_NP | FPU_READ_ST0 | FPU_WRITE_STREG | FPU_POP | FPU_CYCLES(1,0,0), PAIR_NP | FPU_READ_ST0 | FPU_WRITE_STREG | FPU_POP | FPU_CYCLES(1,0,0), PAIR_NP | FPU_READ_ST0 | FPU_WRITE_STREG | FPU_POP | FPU_CYCLES(1,0,0), +/* opFCHS opFABS*/ + PAIR_FX | FPU_CYCLES(1,0,0), PAIR_FX | FPU_CYCLES(1,0,0), INVALID, INVALID, +/* opFTST opFXAM*/ + PAIR_NP | FPU_CYCLES(1,0,0), PAIR_NP | FPU_CYCLES(21,4,0), INVALID, INVALID, +/* opFLD1 opFLDL2T opFLDL2E opFLDPI*/ + PAIR_NP | FPU_PUSH | FPU_CYCLES(2,0,0), PAIR_NP | FPU_PUSH | FPU_CYCLES(5,2,2), PAIR_NP | FPU_PUSH | FPU_CYCLES(5,2,2), PAIR_NP | FPU_PUSH | FPU_CYCLES(5,2,2), +/* opFLDEG2 opFLDLN2 opFLDZ*/ + PAIR_NP | FPU_PUSH | FPU_CYCLES(5,2,2), PAIR_NP | FPU_PUSH | FPU_CYCLES(5,2,2), PAIR_NP | FPU_PUSH | FPU_CYCLES(2,0,0), INVALID, +/* opF2XM1 opFYL2X opFPTAN opFPATAN*/ + PAIR_NP | FPU_CYCLES(53,2,2), PAIR_NP | FPU_CYCLES(103,2,2), PAIR_NP | FPU_CYCLES(120,36,0), PAIR_NP | FPU_CYCLES(112,2,2), +/* opFDECSTP opFINCSTP,*/ + INVALID, INVALID, PAIR_NP | FPU_CYCLES(2,0,0), PAIR_NP | FPU_CYCLES(2,0,0), +/* opFPREM opFSQRT opFSINCOS*/ + PAIR_NP | FPU_CYCLES(64,2,2), INVALID, PAIR_NP | FPU_CYCLES(70,69,2), PAIR_NP | FPU_CYCLES(89,2,2), +/* opFRNDINT opFSCALE opFSIN opFCOS*/ + PAIR_NP | FPU_CYCLES(9,0,0), PAIR_NP | FPU_CYCLES(20,5,0), PAIR_NP | FPU_CYCLES(65,2,2), PAIR_NP | FPU_CYCLES(65,2,2) }; -static uint32_t opcode_timings_da[8] = +static uint64_t opcode_timings_da[8] = { -/* FIADDl FIMULl FICOMl FICOMPl*/ - PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), -/* FISUBl FISUBRl FIDIVl FIDIVRl*/ - PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(42), PAIR_NP | CYCLES(42) +/* FIADDl FIMULl FICOMl FICOMPl*/ + PAIR_NP | FPU_RW_ST0 | FPU_CYCLES(6,2,2), PAIR_NP | FPU_RW_ST0 | FPU_CYCLES(6,2,2), PAIR_NP | FPU_READ_ST0 | FPU_CYCLES(4,0,0), PAIR_NP | FPU_READ_ST0 | FPU_POP | FPU_CYCLES(4,0,0), +/* FISUBl FISUBRl FIDIVl FIDIVRl*/ + PAIR_NP | FPU_RW_ST0 | FPU_CYCLES(6,2,2), PAIR_NP | FPU_RW_ST0 | FPU_CYCLES(6,2,2), PAIR_NP | FPU_RW_ST0 | FPU_CYCLES(42,38,2), PAIR_NP | FPU_RW_ST0 | FPU_CYCLES(42,38,2) }; -static uint32_t opcode_timings_da_mod3[8] = +static uint64_t opcode_timings_da_mod3[8] = { - INVALID, INVALID, INVALID, INVALID, - INVALID, PAIR_NP | CYCLES(5), INVALID, INVALID + INVALID, INVALID, INVALID, INVALID, +/* FCOMPP*/ + INVALID, PAIR_NP | FPU_POP2 | FPU_CYCLES(1,0,0), INVALID, INVALID }; -static uint32_t opcode_timings_db[8] = +static uint64_t opcode_timings_db[8] = { -/* FLDil FSTil FSTPil*/ - PAIR_NP | CYCLES(1), INVALID, PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), -/* FLDe FSTPe*/ - INVALID, PAIR_NP | CYCLES(3), INVALID, PAIR_NP | CYCLES(3) +/* FLDil FSTil FSTPil*/ + PAIR_NP | FPU_PUSH | FPU_CYCLES(3,2,2), INVALID, PAIR_NP | FPU_READ_ST0 | FPU_CYCLES(6,0,0), PAIR_NP | FPU_READ_ST0 | FPU_POP | FPU_CYCLES(6,0,0), +/* FLDe FSTPe*/ + INVALID, PAIR_NP | FPU_PUSH | FPU_CYCLES(3,0,0), INVALID, PAIR_NP | FPU_READ_ST0 | FPU_POP | FPU_CYCLES(3,0,0) }; -static uint32_t opcode_timings_db_mod3[64] = +static uint64_t opcode_timings_db_mod3[64] = { INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, @@ -736,10 +796,10 @@ static uint32_t opcode_timings_db_mod3[64] = INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, -/* opFNOP opFCLEX opFINIT*/ - INVALID, PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(7), PAIR_NP | CYCLES(17), -/* opFNOP opFNOP*/ - PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), INVALID, INVALID, +/* opFNOP opFCLEX opFINIT*/ + INVALID, PAIR_NP | FPU_CYCLES(1,0,0), PAIR_NP | FPU_CYCLES(7,0,0), PAIR_NP | FPU_CYCLES(17,0,0), +/* opFNOP opFNOP*/ + PAIR_NP | FPU_CYCLES(1,0,0), PAIR_NP | FPU_CYCLES(1,0,0), INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, @@ -751,76 +811,84 @@ static uint32_t opcode_timings_db_mod3[64] = INVALID, INVALID, INVALID, INVALID, }; -static uint32_t opcode_timings_dc[8] = +static uint64_t opcode_timings_dc[8] = { -/* FADDd FMULd FCOMd FCOMPd*/ - PAIR_FX | CYCLES(1), PAIR_FX | CYCLES(1), PAIR_FX | CYCLES(1), PAIR_FX | CYCLES(1), -/* FSUBd FSUBRd FDIVd FDIVRd*/ - PAIR_FX | CYCLES(1), PAIR_FX | CYCLES(1), PAIR_FX | CYCLES(39), PAIR_FX | CYCLES(39) +/* FADDd FMULd FCOMd FCOMPd*/ + PAIR_FX | FPU_RW_ST0 | FPU_CYCLES(3,2,2), PAIR_FX | FPU_RW_ST0 | FPU_CYCLES(3,2,2), PAIR_FX | FPU_READ_ST0 | FPU_CYCLES(1,0,0), PAIR_FX | FPU_READ_ST0 | FPU_POP | FPU_CYCLES(1,0,0), +/* FSUBd FSUBRd FDIVd FDIVRd*/ + PAIR_FX | FPU_RW_ST0 | FPU_CYCLES(3,2,2), PAIR_FX | FPU_RW_ST0 | FPU_CYCLES(3,2,2), PAIR_FX | FPU_RW_ST0 | FPU_CYCLES(39,38,2), PAIR_FX | FPU_RW_ST0 | FPU_CYCLES(39,38,2) }; -static uint32_t opcode_timings_dc_mod3[8] = +static uint64_t opcode_timings_dc_mod3[8] = { -/* opFADDr opFMULr*/ - PAIR_FX | CYCLES(1), PAIR_FX | CYCLES(1), INVALID, INVALID, -/* opFSUBRr opFSUBr opFDIVRr opFDIVr*/ - PAIR_FX | CYCLES(1), PAIR_FX | CYCLES(1), PAIR_FX | CYCLES(39), PAIR_FX | CYCLES(39) +/* opFADDr opFMULr*/ + PAIR_FX | FPU_READ_ST0 | FPU_RW_STREG | FPU_CYCLES(3,2,2), PAIR_FX | FPU_READ_ST0 | FPU_RW_STREG | FPU_CYCLES(3,2,2), INVALID, INVALID, +/* opFSUBRr opFSUBr opFDIVRr opFDIVr*/ + PAIR_FX | FPU_READ_ST0 | FPU_RW_STREG | FPU_CYCLES(3,2,2), PAIR_FX | FPU_READ_ST0 | FPU_RW_STREG | FPU_CYCLES(3,2,2), PAIR_FX | FPU_READ_ST0 | FPU_RW_STREG | FPU_CYCLES(39,38,2), PAIR_FX | FPU_READ_ST0 | FPU_RW_STREG | FPU_CYCLES(39,38,2) }; -static uint32_t opcode_timings_dd[8] = +static uint64_t opcode_timings_dd[8] = { -/* FLDd FSTd FSTPd*/ - PAIR_FX | CYCLES(1), INVALID, PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), -/* FRSTOR FSAVE FSTSW*/ - PAIR_NP | CYCLES(70), INVALID, PAIR_NP | CYCLES(127), PAIR_NP | CYCLES(2) +/* FLDd FSTd FSTPd*/ + PAIR_FX | FPU_PUSH | FPU_CYCLES(1,0,0), INVALID, PAIR_NP | FPU_READ_ST0 | FPU_CYCLES(2,0,0), PAIR_NP | FPU_READ_ST0 | FPU_POP | FPU_CYCLES(2,0,0), +/* FRSTOR FSAVE FSTSW*/ + PAIR_NP | FPU_CYCLES(70,0,0), INVALID, PAIR_NP | FPU_CYCLES(127,0,0), PAIR_NP | FPU_CYCLES(6,0,0) }; -static uint32_t opcode_timings_dd_mod3[8] = +static uint64_t opcode_timings_dd_mod3[8] = { -/* FFFREE FST FSTP*/ - PAIR_NP | CYCLES(3), INVALID, PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), -/* FUCOM FUCOMP*/ - PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), INVALID, INVALID +/* FFFREE FST FSTP*/ + PAIR_NP | FPU_CYCLES(2,0,0), INVALID, PAIR_NP | FPU_READ_ST0 | FPU_WRITE_STREG | FPU_CYCLES(1,0,0), PAIR_NP | FPU_READ_ST0 | FPU_WRITE_STREG | FPU_POP | FPU_CYCLES(1,0,0), +/* FUCOM FUCOMP*/ + PAIR_NP | FPU_READ_ST0 | FPU_READ_STREG | FPU_CYCLES(1,0,0), PAIR_NP | FPU_READ_ST0 | FPU_READ_STREG | FPU_POP | FPU_CYCLES(1,0,0), INVALID, INVALID }; -static uint32_t opcode_timings_de[8] = +static uint64_t opcode_timings_de[8] = { -/* FIADDw FIMULw FICOMw FICOMPw*/ - PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), -/* FISUBw FISUBRw FIDIVw FIDIVRw*/ - PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(42), PAIR_NP | CYCLES(42) +/* FIADDw FIMULw FICOMw FICOMPw*/ + PAIR_NP | FPU_RW_ST0 | FPU_CYCLES(6,2,2), PAIR_NP | FPU_RW_ST0 | FPU_CYCLES(6,2,2), PAIR_NP | FPU_READ_ST0 | FPU_CYCLES(4,0,0), PAIR_NP | FPU_READ_ST0 | FPU_POP | FPU_CYCLES(4,0,0), +/* FISUBw FISUBRw FIDIVw FIDIVRw*/ + PAIR_NP | FPU_RW_ST0 | FPU_CYCLES(6,2,2), PAIR_NP | FPU_RW_ST0 | FPU_CYCLES(6,2,2), PAIR_NP | FPU_RW_ST0 | FPU_CYCLES(42,38,2), PAIR_NP | FPU_RW_ST0 | FPU_CYCLES(42,38,2) }; -static uint32_t opcode_timings_de_mod3[8] = +static uint64_t opcode_timings_de_mod3[8] = { -/* FADD FMUL FCOMPP*/ - PAIR_FX | CYCLES(1), PAIR_FX | CYCLES(1), INVALID, PAIR_FX | CYCLES(1), -/* FSUB FSUBR FDIV FDIVR*/ - PAIR_FX | CYCLES(1), PAIR_FX | CYCLES(1), PAIR_FX | CYCLES(39), PAIR_FX | CYCLES(39) +/* FADDP FMULP FCOMPP*/ + PAIR_FX | FPU_READ_ST0 | FPU_RW_STREG | FPU_POP | FPU_CYCLES(3,2,2), PAIR_FX | FPU_READ_ST0 | FPU_RW_STREG | FPU_POP | FPU_CYCLES(3,2,2), INVALID, PAIR_FX | FPU_READ_ST0 | FPU_READ_ST1 | FPU_POP2 | FPU_CYCLES(1,0,0), +/* FSUBP FSUBRP FDIVP FDIVRP*/ + PAIR_FX | FPU_READ_ST0 | FPU_RW_STREG | FPU_POP | FPU_CYCLES(3,2,2), PAIR_FX | FPU_READ_ST0 | FPU_RW_STREG | FPU_POP | FPU_CYCLES(3,2,2), PAIR_FX | FPU_READ_ST0 | FPU_RW_STREG | FPU_POP | FPU_CYCLES(39,38,2), PAIR_FX | FPU_READ_ST0 | FPU_RW_STREG | FPU_POP | FPU_CYCLES(39,38,2) }; -static uint32_t opcode_timings_df[8] = +static uint64_t opcode_timings_df[8] = { -/* FILDiw FISTiw FISTPiw*/ - PAIR_NP | CYCLES(1), INVALID, PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), -/* FILDiq FBSTP FISTPiq*/ - INVALID, PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(148), PAIR_NP | CYCLES(6) +/* FILDiw FISTiw FISTPiw*/ + PAIR_NP | FPU_PUSH | FPU_CYCLES(3,2,2), INVALID, PAIR_NP | FPU_READ_ST0 | FPU_CYCLES(6,0,0), PAIR_NP | FPU_READ_ST0 | FPU_POP | FPU_CYCLES(6,0,0), +/* FILDiq FBSTP FISTPiq*/ + INVALID, PAIR_NP | FPU_PUSH | FPU_CYCLES(3,2,2), PAIR_NP | FPU_READ_ST0 | FPU_POP | FPU_CYCLES(148,0,0), PAIR_NP | FPU_READ_ST0 | FPU_POP | FPU_CYCLES(6,0,0) }; -static uint32_t opcode_timings_df_mod3[8] = +static uint64_t opcode_timings_df_mod3[8] = { - INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, /* FSTSW AX*/ - PAIR_NP | CYCLES(2), INVALID, INVALID, INVALID + PAIR_NP | FPU_CYCLES(6,0,0), INVALID, INVALID, INVALID }; -static uint32_t opcode_timings_8x[8] = +static uint64_t opcode_timings_81[8] = { - PAIR_UV | CYCLES_RMW | SRCDEP_REG, PAIR_UV | CYCLES_RMW | SRCDEP_REG, PAIR_UV | CYCLES_RMW | SRCDEP_REG, PAIR_UV | CYCLES_RMW | SRCDEP_REG, - PAIR_UV | CYCLES_RMW | SRCDEP_REG, PAIR_UV | CYCLES_RMW | SRCDEP_REG, PAIR_UV | CYCLES_RMW | SRCDEP_REG, PAIR_UV | CYCLES_RM | SRCDEP_REG + PAIR_UV | CYCLES_RMW | SRCDEP_REG | CYCLES_IMM1632, PAIR_UV | CYCLES_RMW | SRCDEP_REG | CYCLES_IMM1632, PAIR_UV | CYCLES_RMW | SRCDEP_REG | CYCLES_IMM1632, PAIR_UV | CYCLES_RMW | SRCDEP_REG | CYCLES_IMM1632, + PAIR_UV | CYCLES_RMW | SRCDEP_REG | CYCLES_IMM1632, PAIR_UV | CYCLES_RMW | SRCDEP_REG | CYCLES_IMM1632, PAIR_UV | CYCLES_RMW | SRCDEP_REG | CYCLES_IMM1632, PAIR_UV | CYCLES_RM | SRCDEP_REG | CYCLES_IMM1632 +}; +static uint64_t opcode_timings_8x[8] = +{ + PAIR_UV | CYCLES_RMW | SRCDEP_REG | CYCLES_IMM8, PAIR_UV | CYCLES_RMW | SRCDEP_REG | CYCLES_IMM8, PAIR_UV | CYCLES_RMW | SRCDEP_REG | CYCLES_IMM8, PAIR_UV | CYCLES_RMW | SRCDEP_REG | CYCLES_IMM8, + PAIR_UV | CYCLES_RMW | SRCDEP_REG | CYCLES_IMM8, PAIR_UV | CYCLES_RMW | SRCDEP_REG | CYCLES_IMM8, PAIR_UV | CYCLES_RMW | SRCDEP_REG | CYCLES_IMM8, PAIR_UV | CYCLES_RM | SRCDEP_REG | CYCLES_IMM8 }; -static int decode_delay; +static int decode_delay, decode_delay_offset; static uint8_t last_prefix; +static int prefixes; -static inline int COUNT(uint32_t c, int op_32) +static inline int COUNT(uint64_t c, int op_32) { + if ((c & PAIR_FPU) && !(c & FPU_FXCH)) + return FPU_I_LATENCY(c); if (c & CYCLES_HAS_MULTI) { if (op_32 & 0x100) @@ -831,6 +899,10 @@ static inline int COUNT(uint32_t c, int op_32) return c & 0xffff; if ((c & PAIR_MASK) == PAIR_FX) return c & 0xffff; + if ((c & PAIR_MASK) == PAIR_FXCH) + return c & 0xffff; + if ((c & PAIR_UV) && !(c & PAIR_FPU)) + c &= 3; switch (c & CYCLES_MASK) { case CYCLES_REG: @@ -843,24 +915,136 @@ static inline int COUNT(uint32_t c, int op_32) return cpu_hasMMX ? 1 : 2; } - fatal("Illegal COUNT %08x\n", c); + fatal("Illegal COUNT %016llx\n", c); return c; } +static int codegen_fpu_latencies(uint64_t timings, int reg) +{ + int latency = fpu_latency; + + if ((timings & FPU_RW_ST0) && fpu_st_latency[0] && fpu_st_latency[0] > latency) + latency = fpu_st_latency[0]; + if ((timings & FPU_RW_ST1) && fpu_st_latency[1] && fpu_st_latency[1] > latency) + latency = fpu_st_latency[1]; + if ((timings & FPU_RW_STREG) && fpu_st_latency[reg] && fpu_st_latency[reg] > latency) + latency = fpu_st_latency[reg]; + + return latency; +} + +#define SUB_AND_CLAMP(latency, count) \ + latency -= count; \ + if (latency < 0) \ + latency = 0 + +static void codegen_fpu_latency_clock(int count) +{ + SUB_AND_CLAMP(fpu_latency, count); + SUB_AND_CLAMP(fpu_st_latency[0], count); + SUB_AND_CLAMP(fpu_st_latency[1], count); + SUB_AND_CLAMP(fpu_st_latency[2], count); + SUB_AND_CLAMP(fpu_st_latency[3], count); + SUB_AND_CLAMP(fpu_st_latency[4], count); + SUB_AND_CLAMP(fpu_st_latency[5], count); + SUB_AND_CLAMP(fpu_st_latency[6], count); + SUB_AND_CLAMP(fpu_st_latency[7], count); +} + +static inline int codegen_timing_has_displacement(uint32_t fetchdat, int op_32) +{ + if (op_32 & 0x200) + { + if ((fetchdat & 7) == 4 && (fetchdat & 0xc0) != 0xc0) + { + /*Has SIB*/ + if ((fetchdat & 0xc0) == 0x40 || (fetchdat & 0xc0) == 0x80 || (fetchdat & 0x700) == 0x500) + return 1; + } + else + { + if ((fetchdat & 0xc0) == 0x40 || (fetchdat & 0xc0) == 0x80 || (fetchdat & 0xc7) == 0x05) + return 1; + } + } + else + { + if ((fetchdat & 0xc0) == 0x40 || (fetchdat & 0xc0) == 0x80 || (fetchdat & 0xc7) == 0x06) + return 1; + } + return 0; +} + +/*The instruction is only of interest here if it's longer than 7 bytes, as that's the + limit on Pentium MMX parallel decoding*/ +static inline int codegen_timing_instr_length(uint64_t timing, uint32_t fetchdat, int op_32) +{ + int len = prefixes; + if ((timing & CYCLES_MASK) == CYCLES_RM || (timing & CYCLES_MASK) == CYCLES_RMW) + { + len += 2; /*Opcode + ModR/M*/ + if ((timing & CYCLES_HASIMM) == CYCLES_IMM8) + len++; + if ((timing & CYCLES_HASIMM) == CYCLES_IMM1632) + len += (op_32 & 0x100) ? 4 : 2; + + if (op_32 & 0x200) + { + if ((fetchdat & 7) == 4 && (fetchdat & 0xc0) != 0xc0) + { + /* Has SIB*/ + len++; + if ((fetchdat & 0xc0) == 0x40) + len++; + else if ((fetchdat & 0xc0) == 0x80) + len += 4; + else if ((fetchdat & 0x700) == 0x500) + len += 4; + } + else + { + if ((fetchdat & 0xc0) == 0x40) + len++; + else if ((fetchdat & 0xc0) == 0x80) + len += 4; + else if ((fetchdat & 0xc7) == 0x05) + len += 4; + } + } + else + { + if ((fetchdat & 0xc0) == 0x40) + len++; + else if ((fetchdat & 0xc0) == 0x80) + len += 2; + else if ((fetchdat & 0xc7) == 0x06) + len += 2; + } + } + + return len; +} + void codegen_timing_pentium_block_start() { - u_pipe_full = decode_delay = 0; + u_pipe_full = decode_delay = decode_delay_offset = 0; } void codegen_timing_pentium_start() { -// decode_delay = 0; last_prefix = 0; + prefixes = 0; } void codegen_timing_pentium_prefix(uint8_t prefix, uint32_t fetchdat) { + prefixes++; + if ((prefix & 0xf8) == 0xd8) + { + last_prefix = prefix; + return; + } if (cpu_hasMMX && prefix == 0x0f) { /*On Pentium MMX 0fh prefix is 'free'*/ @@ -870,7 +1054,7 @@ void codegen_timing_pentium_prefix(uint8_t prefix, uint32_t fetchdat) if (cpu_hasMMX && (prefix == 0x66 || prefix == 0x67)) { /*On Pentium MMX 66h and 67h prefixes take 2 clocks*/ - decode_delay += 2; + decode_delay_offset += 2; last_prefix = prefix; return; } @@ -882,13 +1066,86 @@ void codegen_timing_pentium_prefix(uint8_t prefix, uint32_t fetchdat) } /*On Pentium all prefixes take 1 cycle to decode. Decode may be shadowed by execution of previous instructions*/ - decode_delay++; + decode_delay_offset++; last_prefix = prefix; } +static void codegen_instruction(uint64_t *timings, uint8_t opcode, uint32_t fetchdat, int decode_delay_offset, int op_32) +{ + int instr_cycles, latency = 0; + + if ((timings[opcode] & PAIR_FPU) && !(timings[opcode] & FPU_FXCH)) + instr_cycles = latency = codegen_fpu_latencies(timings[opcode], fetchdat & 7); + else + { + instr_cycles = 0; + } + + if ((decode_delay + decode_delay_offset) > 0) + codegen_fpu_latency_clock(decode_delay + decode_delay_offset + instr_cycles); + else + codegen_fpu_latency_clock(instr_cycles); + instr_cycles += COUNT(timings[opcode], op_32); + if ((decode_delay + decode_delay_offset) > 0) + codegen_block_cycles += instr_cycles + decode_delay + decode_delay_offset; + else + codegen_block_cycles += instr_cycles; + decode_delay = (-instr_cycles) + 1; + + if (timings[opcode] & FPU_POP) + { + int c; + + for (c = 0; c < 7; c++) + fpu_st_latency[c] = fpu_st_latency[c+1]; + fpu_st_latency[7] = 0; + } + if (timings[opcode] & FPU_POP2) + { + int c; + + for (c = 0; c < 6; c++) + fpu_st_latency[c] = fpu_st_latency[c+2]; + fpu_st_latency[6] = fpu_st_latency[7] = 0; + } + if ((timings[opcode] & PAIR_FPU) && !(timings[opcode] & FPU_FXCH)) + { + fpu_latency = FPU_F_LATENCY(timings[opcode]); + } + + if (timings[opcode] & FPU_PUSH) + { + int c; + + for (c = 0; c < 7; c++) + fpu_st_latency[c+1] = fpu_st_latency[c]; + fpu_st_latency[0] = 0; + } + if (timings[opcode] & FPU_WRITE_ST0) + { + fpu_st_latency[0] = FPU_RESULT_LATENCY(timings[opcode]); + } + if (timings[opcode] & FPU_WRITE_ST1) + { + fpu_st_latency[1] = FPU_RESULT_LATENCY(timings[opcode]); + } + if (timings[opcode] & FPU_WRITE_STREG) + { + int reg = fetchdat & 7; + if (timings[opcode] & FPU_POP) + reg--; + if (reg >= 0 && + !(reg == 0 && (timings[opcode] & FPU_WRITE_ST0)) && + !(reg == 1 && (timings[opcode] & FPU_WRITE_ST1))) + { + fpu_st_latency[reg] = FPU_RESULT_LATENCY(timings[opcode]); + } + } +} + void codegen_timing_pentium_opcode(uint8_t opcode, uint32_t fetchdat, int op_32) { - int *timings; + uint64_t *timings; int mod3 = ((fetchdat & 0xc0) == 0xc0); int bit8 = !(opcode & 1); @@ -896,92 +1153,79 @@ void codegen_timing_pentium_opcode(uint8_t opcode, uint32_t fetchdat, int op_32) { case 0x0f: timings = mod3 ? opcode_timings_0f_mod3 : opcode_timings_0f; -// pclog("timings 0f\n"); break; case 0xd8: timings = mod3 ? opcode_timings_d8_mod3 : opcode_timings_d8; opcode = (opcode >> 3) & 7; -// pclog("timings d8\n"); break; case 0xd9: timings = mod3 ? opcode_timings_d9_mod3 : opcode_timings_d9; opcode = mod3 ? opcode & 0x3f : (opcode >> 3) & 7; -// pclog("timings d9\n"); break; case 0xda: timings = mod3 ? opcode_timings_da_mod3 : opcode_timings_da; opcode = (opcode >> 3) & 7; -// pclog("timings da\n"); break; case 0xdb: timings = mod3 ? opcode_timings_db_mod3 : opcode_timings_db; opcode = mod3 ? opcode & 0x3f : (opcode >> 3) & 7; -// pclog("timings db\n"); break; case 0xdc: timings = mod3 ? opcode_timings_dc_mod3 : opcode_timings_dc; opcode = (opcode >> 3) & 7; -// pclog("timings dc\n"); break; case 0xdd: timings = mod3 ? opcode_timings_dd_mod3 : opcode_timings_dd; opcode = (opcode >> 3) & 7; -// pclog("timings dd\n"); break; case 0xde: timings = mod3 ? opcode_timings_de_mod3 : opcode_timings_de; opcode = (opcode >> 3) & 7; -// pclog("timings de\n"); break; case 0xdf: timings = mod3 ? opcode_timings_df_mod3 : opcode_timings_df; opcode = (opcode >> 3) & 7; -// pclog("timings df\n"); break; default: switch (opcode) { - case 0x80: case 0x81: case 0x82: case 0x83: + case 0x80: case 0x82: case 0x83: timings = mod3 ? opcode_timings_mod3 : opcode_timings_8x; if (!mod3) opcode = (fetchdat >> 3) & 7; -// pclog("timings 80 %p %p %p\n", (void *)timings, (void *)opcode_timings_mod3, (void *)opcode_timings_8x); + break; + case 0x81: + timings = mod3 ? opcode_timings_mod3 : opcode_timings_81; + if (!mod3) + opcode = (fetchdat >> 3) & 7; break; case 0xc0: case 0xc1: case 0xd0: case 0xd1: case 0xd2: case 0xd3: timings = mod3 ? opcode_timings_shift_mod3 : opcode_timings_shift; opcode = (fetchdat >> 3) & 7; -// pclog("timings c0\n"); break; case 0xf6: timings = mod3 ? opcode_timings_f6_mod3 : opcode_timings_f6; opcode = (fetchdat >> 3) & 7; -// pclog("timings f6\n"); break; case 0xf7: timings = mod3 ? opcode_timings_f7_mod3 : opcode_timings_f7; opcode = (fetchdat >> 3) & 7; -// pclog("timings f7\n"); break; case 0xff: timings = mod3 ? opcode_timings_ff_mod3 : opcode_timings_ff; opcode = (fetchdat >> 3) & 7; -// pclog("timings ff\n"); break; default: timings = mod3 ? opcode_timings_mod3 : opcode_timings; -// pclog("timings normal\n"); break; } } - if (decode_delay < 0) - decode_delay = 0; - if (u_pipe_full) { uint8_t regmask = get_srcdep_mask(timings[opcode], fetchdat, bit8); @@ -993,52 +1237,92 @@ void codegen_timing_pentium_opcode(uint8_t opcode, uint32_t fetchdat, int op_32) if ((timings[opcode] & PAIR_MASK) == PAIR_FXCH && (u_pipe_timings[u_pipe_opcode] & PAIR_MASK) != PAIR_FX) goto nopair; - - if ((timings[opcode] & PAIR_V) && !(u_pipe_regmask & regmask) && !decode_delay) - { - int t1 = u_pipe_timings[u_pipe_opcode] & CYCLES_MASK; - int t2 = timings[opcode] & CYCLES_MASK; - int t_pair; - - if (t1 < 0 || t2 < 0 || t1 > CYCLES_BRANCH || t2 > CYCLES_BRANCH) - fatal("Pair out of range\n"); - - t_pair = pair_timings[t1][t2]; - if (t_pair < 1) - fatal("Illegal pair timings : t1=%i t2=%i u_opcode=%02x v_opcode=%02x\n", t1, t2, u_pipe_opcode, opcode); -// pclog("Paired timings : t_pair=%i t1=%i t2=%i u_opcode=%02x v_opcode=%02x %08x:%08x\n", t_pair, t1, t2, u_pipe_opcode, opcode, cs, pc); - codegen_block_cycles += t_pair; - decode_delay = (-t_pair) + 1; - - /*Instruction can pair with previous*/ + if ((u_pipe_timings[u_pipe_opcode] & PAIR_MASK) == PAIR_FX && + (timings[opcode] & PAIR_MASK) == PAIR_FXCH) + { + int temp; + + codegen_instruction(u_pipe_timings, u_pipe_opcode, u_pipe_fetchdat, u_pipe_decode_delay_offset, u_pipe_op_32); + + temp = fpu_st_latency[fetchdat & 7]; + fpu_st_latency[fetchdat & 7] = fpu_st_latency[0]; + fpu_st_latency[0] = temp; + u_pipe_full = 0; + decode_delay_offset = 0; return; } + + if ((timings[opcode] & PAIR_V) && !(u_pipe_regmask & regmask) && (decode_delay+decode_delay_offset+u_pipe_decode_delay_offset) <= 0) + { + int has_displacement; + + if (timings[opcode] & CYCLES_HASIMM) + has_displacement = codegen_timing_has_displacement(fetchdat, op_32); + else + has_displacement = 0; + + if (!has_displacement && (!cpu_hasMMX || codegen_timing_instr_length(timings[opcode], fetchdat, op_32) <= 7)) + { + int t1 = u_pipe_timings[u_pipe_opcode] & CYCLES_MASK; + int t2 = timings[opcode] & CYCLES_MASK; + int t_pair; + uint64_t temp_timing; + + if (!(u_pipe_timings[u_pipe_opcode] & PAIR_FPU)) + t1 &= 3; + if (!(timings[opcode] & PAIR_FPU)) + t2 &= 3; + + if (t1 < 0 || t2 < 0 || t1 > CYCLES_BRANCH || t2 > CYCLES_BRANCH) + fatal("Pair out of range\n"); + + t_pair = pair_timings[t1][t2]; + if (t_pair < 1) + fatal("Illegal pair timings : t1=%i t2=%i u_opcode=%02x v_opcode=%02x\n", t1, t2, u_pipe_opcode, opcode); + + /*Instruction can pair with previous*/ + temp_timing = t_pair; + codegen_instruction(&temp_timing, 0, 0, 0, 0); + u_pipe_full = 0; + decode_delay_offset = 0; + return; + } + } nopair: /*Instruction can not pair with previous*/ /*Run previous now*/ - codegen_block_cycles += COUNT(u_pipe_timings[u_pipe_opcode], u_pipe_op_32) + decode_delay; - decode_delay = (-COUNT(u_pipe_timings[u_pipe_opcode], u_pipe_op_32)) + 1; + codegen_instruction(u_pipe_timings, u_pipe_opcode, u_pipe_fetchdat, u_pipe_decode_delay_offset, u_pipe_op_32); u_pipe_full = 0; -// pclog("Evicited U-pipe timings : t1=%i u_opcode=%02x decode_delay=%i %08x:%08x\n", COUNT(u_pipe_timings[u_pipe_opcode], u_pipe_op_32), u_pipe_opcode, decode_delay, cs, pc); } - if ((timings[opcode] & PAIR_U) && !decode_delay) + if ((timings[opcode] & PAIR_U) && (decode_delay + decode_delay_offset) <= 0) { - /*Instruction might pair with next*/ - u_pipe_full = 1; - u_pipe_opcode = opcode; - u_pipe_timings = timings; - u_pipe_op_32 = op_32; - u_pipe_regmask = get_dstdep_mask(timings[opcode], fetchdat, bit8); - return; + int has_displacement; + + if (timings[opcode] & CYCLES_HASIMM) + has_displacement = codegen_timing_has_displacement(fetchdat, op_32); + else + has_displacement = 0; + + if ((!has_displacement || cpu_hasMMX) && (!cpu_hasMMX || codegen_timing_instr_length(timings[opcode], fetchdat, op_32) <= 7)) + { + /*Instruction might pair with next*/ + u_pipe_full = 1; + u_pipe_opcode = opcode; + u_pipe_timings = timings; + u_pipe_op_32 = op_32; + u_pipe_regmask = get_dstdep_mask(timings[opcode], fetchdat, bit8); + u_pipe_fetchdat = fetchdat; + u_pipe_decode_delay_offset = decode_delay_offset; + decode_delay_offset = 0; + return; + } } /*Instruction can not pair and must run now*/ - - codegen_block_cycles += COUNT(timings[opcode], op_32) + decode_delay; - decode_delay = (-COUNT(timings[opcode], op_32)) + 1; -// pclog("Non-pairable timings : %08x t1=%i opcode=%02x mod3=%i decode_delay=%i %08x:%08x %08x %p %p\n", timings[opcode], COUNT(timings[opcode], op_32), opcode, mod3, decode_delay, cs, pc, opcode_timings[0x04], (void *)timings, (void *)opcode_timings); + codegen_instruction(timings, opcode, fetchdat, decode_delay_offset, op_32); + decode_delay_offset = 0; } void codegen_timing_pentium_block_end() @@ -1046,7 +1330,7 @@ void codegen_timing_pentium_block_end() if (u_pipe_full) { /*Run previous now*/ - codegen_block_cycles += COUNT(u_pipe_timings[u_pipe_opcode], u_pipe_op_32) + decode_delay; + codegen_block_cycles += COUNT(u_pipe_timings[u_pipe_opcode], u_pipe_op_32) + decode_delay + decode_delay_offset; u_pipe_full = 0; } } diff --git a/src/codegen_timing_winchip.c b/src/CPU/codegen_timing_winchip.c similarity index 99% rename from src/codegen_timing_winchip.c rename to src/CPU/codegen_timing_winchip.c index 342fbb0b6..a76a08e7a 100644 --- a/src/codegen_timing_winchip.c +++ b/src/CPU/codegen_timing_winchip.c @@ -1,9 +1,9 @@ -#include "ibm.h" +#include "../ibm.h" +#include "../mem.h" #include "cpu.h" #include "x86.h" #include "x86_ops.h" #include "x87.h" -#include "mem.h" #include "codegen.h" #define CYCLES(c) (int *)c @@ -251,7 +251,7 @@ static int *opcode_timings_8x[8] = static int timing_count; static uint8_t last_prefix; -static inline int COUNT(int *c, int op_32) +static __inline int COUNT(int *c, int op_32) { if ((uintptr_t)c <= 10000) return (int)c; diff --git a/src/codegen_x86-64.c b/src/CPU/codegen_x86-64.c similarity index 90% rename from src/codegen_x86-64.c rename to src/CPU/codegen_x86-64.c index 7673a08e4..3ce22d95e 100644 --- a/src/codegen_x86-64.c +++ b/src/CPU/codegen_x86-64.c @@ -1,16 +1,14 @@ #ifdef __amd64__ #include -#include "ibm.h" +#include "../ibm.h" +#include "../mem.h" #include "cpu.h" #include "x86.h" #include "x86_flags.h" #include "x86_ops.h" #include "x87.h" -#include "mem.h" - #include "386_common.h" - #include "codegen.h" #include "codegen_ops.h" #include "codegen_ops_x86-64.h" @@ -24,6 +22,7 @@ #endif +int codegen_flat_ds, codegen_flat_ss; int codegen_flags_changed = 0; int codegen_fpu_entered = 0; int codegen_fpu_loaded_iq[8]; @@ -88,7 +87,6 @@ void codegen_init() exit(-1); } #endif -// pclog("Codegen is %p\n", (void *)pages[0xfab12 >> 12].block); } void codegen_reset() @@ -100,25 +98,11 @@ void codegen_reset() void dump_block() { - codeblock_t *block = pages[0x119000 >> 12].block; - - pclog("dump_block:\n"); - while (block) - { - uint32_t start_pc = (block->pc & 0xffc) | (block->phys & ~0xfff); - uint32_t end_pc = (block->endpc & 0xffc) | (block->phys & ~0xfff); - pclog(" %p : %08x-%08x %08x-%08x %p %p\n", (void *)block, start_pc, end_pc, block->pc, block->endpc, (void *)block->prev, (void *)block->next); - if (!block->pc) - fatal("Dead PC=0\n"); - - block = block->next; - } - pclog("dump_block done\n"); } static void add_to_block_list(codeblock_t *block) { - codeblock_t *block_prev = pages[block->phys >> 12].block; + codeblock_t *block_prev = pages[block->phys >> 12].block[(block->phys >> 10) & 3]; if (!block->page_mask) fatal("add_to_block_list - mask = 0\n"); @@ -127,12 +111,12 @@ static void add_to_block_list(codeblock_t *block) { block->next = block_prev; block_prev->prev = block; - pages[block->phys >> 12].block = block; + pages[block->phys >> 12].block[(block->phys >> 10) & 3] = block; } else { block->next = NULL; - pages[block->phys >> 12].block = block; + pages[block->phys >> 12].block[(block->phys >> 10) & 3] = block; } if (block->next) @@ -143,18 +127,18 @@ static void add_to_block_list(codeblock_t *block) if (block->page_mask2) { - block_prev = pages[block->phys_2 >> 12].block_2; + block_prev = pages[block->phys_2 >> 12].block_2[(block->phys_2 >> 10) & 3]; if (block_prev) { block->next_2 = block_prev; block_prev->prev_2 = block; - pages[block->phys_2 >> 12].block_2 = block; + pages[block->phys_2 >> 12].block_2[(block->phys_2 >> 10) & 3] = block; } else { block->next_2 = NULL; - pages[block->phys_2 >> 12].block_2 = block; + pages[block->phys_2 >> 12].block_2[(block->phys_2 >> 10) & 3] = block; } } } @@ -172,7 +156,7 @@ static void remove_from_block_list(codeblock_t *block, uint32_t pc) } else { - pages[block->phys >> 12].block = block->next; + pages[block->phys >> 12].block[(block->phys >> 10) & 3] = block->next; if (block->next) block->next->prev = NULL; else @@ -193,8 +177,7 @@ static void remove_from_block_list(codeblock_t *block, uint32_t pc) } else { -// pclog(" pages.block_2=%p 3 %p %p\n", (void *)block->next_2, (void *)block, (void *)pages[block->phys_2 >> 12].block_2); - pages[block->phys_2 >> 12].block_2 = block->next_2; + pages[block->phys_2 >> 12].block_2[(block->phys_2 >> 10) & 3] = block->next_2; if (block->next_2) block->next_2->prev_2 = NULL; else @@ -219,7 +202,7 @@ static void delete_block(codeblock_t *block) void codegen_check_flush(page_t *page, uint64_t mask, uint32_t phys_addr) { - struct codeblock_t *block = page->block; + struct codeblock_t *block = page->block[(phys_addr >> 10) & 3]; while (block) { @@ -233,7 +216,7 @@ void codegen_check_flush(page_t *page, uint64_t mask, uint32_t phys_addr) block = block->next; } - block = page->block_2; + block = page->block_2[(phys_addr >> 10) & 3]; while (block) { @@ -254,17 +237,14 @@ void codegen_block_init(uint32_t phys_addr) int has_evicted = 0; page_t *page = &pages[phys_addr >> 12]; - if (!page->block) + if (!page->block[(phys_addr >> 10) & 3]) mem_flush_write_page(phys_addr, cs+cpu_state.pc); block_current = (block_current + 1) & BLOCK_MASK; block = &codeblock[block_current]; -// if (block->pc == 0xb00b4ff5) -// pclog("Init target block\n"); if (block->pc != 0) { -// pclog("Reuse block : was %08x now %08x\n", block->pc, cs+pc); delete_block(block); cpu_recomp_reuse++; } @@ -276,13 +256,15 @@ void codegen_block_init(uint32_t phys_addr) block->_cs = cs; block->pnt = block_current; block->phys = phys_addr; - block->use32 = use32; - block->stack32 = stack32; + block->dirty_mask = &page->dirty_mask[(phys_addr >> PAGE_MASK_INDEX_SHIFT) & PAGE_MASK_INDEX_MASK]; + block->dirty_mask2 = NULL; block->next = block->prev = NULL; block->next_2 = block->prev_2 = NULL; block->page_mask = 0; block->flags = 0; + block->status = cpu_cur_status; + block->was_recompiled = 0; recomp_page = block->phys & ~0xfff; @@ -295,7 +277,7 @@ void codegen_block_start_recompile(codeblock_t *block) int has_evicted = 0; page_t *page = &pages[block->phys >> 12]; - if (!page->block) + if (!page->block[(block->phys >> 10) & 3]) mem_flush_write_page(block->phys, cs+cpu_state.pc); block_num = HASH(block->phys); @@ -361,8 +343,6 @@ void codegen_block_start_recompile(codeblock_t *block) addbyte(0xBD); addquad(((uintptr_t)&cpu_state) + 128); -// pclog("New block %i for %08X %03x\n", block_current, cs+pc, block_num); - last_op32 = -1; last_ea_seg = NULL; last_ssegs = -1; @@ -388,6 +368,9 @@ void codegen_block_start_recompile(codeblock_t *block) codegen_reg_loaded[4] = codegen_reg_loaded[5] = codegen_reg_loaded[6] = codegen_reg_loaded[7] = 0; block->was_recompiled = 1; + + codegen_flat_ds = cpu_cur_status & CPU_STATUS_FLATDS; + codegen_flat_ss = cpu_cur_status & CPU_STATUS_FLATSS; } void codegen_block_remove() @@ -403,59 +386,60 @@ void codegen_block_remove() void codegen_block_generate_end_mask() { codeblock_t *block = &codeblock[block_current]; - uint32_t start_pc = (block->pc & 0xffc) | (block->phys & ~0xfff); - uint32_t end_pc = ((codegen_endpc + 3) & 0xffc) | (block->phys & ~0xfff); + uint32_t start_pc; + uint32_t end_pc; block->endpc = codegen_endpc; block->page_mask = 0; - start_pc = block->pc & 0xffc; - start_pc &= ~PAGE_MASK_MASK; - end_pc = ((block->endpc & 0xffc) + PAGE_MASK_MASK) & ~PAGE_MASK_MASK; - if (end_pc > 0xfff || end_pc < start_pc) - end_pc = 0xfff; + start_pc = (block->pc & 0x3ff) & ~15; + if ((block->pc ^ block->endpc) & ~0x3ff) + end_pc = 0x3ff & ~15; + else + end_pc = (block->endpc & 0x3ff) & ~15; + if (end_pc < start_pc) + end_pc = 0x3ff; start_pc >>= PAGE_MASK_SHIFT; end_pc >>= PAGE_MASK_SHIFT; -// pclog("block_end: %08x %08x\n", start_pc, end_pc); for (; start_pc <= end_pc; start_pc++) { block->page_mask |= ((uint64_t)1 << start_pc); -// pclog(" %08x %llx\n", start_pc, block->page_mask); } - pages[block->phys >> 12].code_present_mask |= block->page_mask; + pages[block->phys >> 12].code_present_mask[(block->phys >> 10) & 3] |= block->page_mask; block->phys_2 = -1; block->page_mask2 = 0; block->next_2 = block->prev_2 = NULL; - if ((block->pc ^ block->endpc) & ~0xfff) + if ((block->pc ^ block->endpc) & ~0x3ff) { block->phys_2 = get_phys_noabrt(block->endpc); if (block->phys_2 != -1) { -// pclog("start block - %08x %08x %p %p %p %08x\n", block->pc, block->endpc, (void *)block, (void *)block->next_2, (void *)pages[block->phys_2 >> 12].block_2, block->phys_2); + page_t *page_2 = &pages[block->phys_2 >> 12]; start_pc = 0; - end_pc = (block->endpc & 0xfff) >> PAGE_MASK_SHIFT; + end_pc = (block->endpc & 0x3ff) >> PAGE_MASK_SHIFT; for (; start_pc <= end_pc; start_pc++) block->page_mask2 |= ((uint64_t)1 << start_pc); - - if (!pages[block->phys_2 >> 12].block_2) + page_2->code_present_mask[(block->phys_2 >> 10) & 3] |= block->page_mask2; + + if (!pages[block->phys_2 >> 12].block_2[(block->phys_2 >> 10) & 3]) mem_flush_write_page(block->phys_2, block->endpc); -// pclog("New block - %08x %08x %p %p phys %08x %08x %016llx\n", block->pc, block->endpc, (void *)block, (void *)block->next_2, block->phys, block->phys_2, block->page_mask2); + if (!block->page_mask2) fatal("!page_mask2\n"); if (block->next_2) { -// pclog(" next_2->pc=%08x\n", block->next_2->pc); if (!block->next_2->pc) fatal("block->next_2->pc=0 %p\n", (void *)block->next_2); } + + block->dirty_mask2 = &page_2->dirty_mask[(block->phys_2 >> PAGE_MASK_INDEX_SHIFT) & PAGE_MASK_INDEX_MASK]; } } -// pclog("block_end: %08x %08x %016llx\n", block->pc, block->endpc, block->page_mask); recomp_page = -1; } @@ -485,16 +469,6 @@ void codegen_block_end_recompile(codeblock_t *block) addbyte(cpu_state_offset(cpu_recomp_ins)); addlong(codegen_block_ins); } -#if 0 - if (codegen_block_full_ins) - { - addbyte(0x81); /*ADD $codegen_block_ins,ins*/ - addbyte(0x04); - addbyte(0x25); - addlong((uint32_t)&cpu_recomp_full_ins); - addlong(codegen_block_full_ins); - } -#endif addbyte(0x48); /*ADDL $40,%rsp*/ addbyte(0x83); addbyte(0xC4); @@ -521,7 +495,6 @@ void codegen_block_end_recompile(codeblock_t *block) block->next_2 = block->prev_2 = NULL; codegen_block_generate_end_mask(); add_to_block_list(block); -// pclog("End block %i\n", block_num); } void codegen_flush() @@ -728,7 +701,7 @@ static x86seg *codegen_generate_ea_16_long(x86seg *op_ea_seg, uint32_t fetchdat, } return op_ea_seg; } -//#if 0 + static x86seg *codegen_generate_ea_32_long(x86seg *op_ea_seg, uint32_t fetchdat, int op_ssegs, uint32_t *op_pc, int stack_offset) { uint32_t new_eaaddr; @@ -930,7 +903,7 @@ static x86seg *codegen_generate_ea_32_long(x86seg *op_ea_seg, uint32_t fetchdat, } return op_ea_seg; } -//#endif + void codegen_generate_call(uint8_t opcode, OpFn op, uint32_t fetchdat, uint32_t new_pc, uint32_t old_pc) { codeblock_t *block = &codeblock[block_current]; @@ -1115,17 +1088,6 @@ generate_call: addlong(codegen_block_ins); codegen_block_ins = 0; } -#if 0 - if (codegen_block_full_ins) - { - addbyte(0x81); /*ADD $codegen_block_ins,ins*/ - addbyte(0x04); - addbyte(0x25); - addlong((uint32_t)&cpu_recomp_full_ins); - addlong(codegen_block_full_ins); - codegen_block_full_ins = 0; - } -#endif } if (recomp_op_table && recomp_op_table[(opcode | op_32) & 0x1ff]) { @@ -1145,8 +1107,6 @@ generate_call: } op = op_table[((opcode >> opcode_shift) | op_32) & opcode_mask]; -// if (output) -// pclog("Generate call at %08X %02X %08X %02X %08X %08X %08X %08X %08X %02X %02X %02X %02X\n", &codeblock[block_current][block_pos], opcode, new_pc, ram[old_pc], EAX, EBX, ECX, EDX, ESI, ram[0x7bd2+6],ram[0x7bd2+7],ram[0x7bd2+8],ram[0x7bd2+9]); if (op_ssegs != last_ssegs) { last_ssegs = op_ssegs; @@ -1155,7 +1115,7 @@ generate_call: addbyte(cpu_state_offset(ssegs)); addbyte(op_ssegs); } -//#if 0 + if ((!test_modrm || (op_table == x86_dynarec_opcodes && opcode_modrm[opcode]) || (op_table == x86_dynarec_opcodes_0f && opcode_0f_modrm[opcode]))/* && !(op_32 & 0x200)*/) @@ -1181,10 +1141,9 @@ generate_call: op_ea_seg = codegen_generate_ea_32_long(op_ea_seg, fetchdat, op_ssegs, &op_pc, stack_offset); op_pc -= pc_off; } -//#endif + if (op_ea_seg != last_ea_seg) { -// last_ea_seg = op_ea_seg; addbyte(0xC7); /*MOVL $&_ds,(ea_seg)*/ addbyte(0x45); addbyte(cpu_state_offset(ea_seg)); @@ -1221,8 +1180,6 @@ generate_call: addbyte(0x0F); addbyte(0x85); /*JNZ 0*/ addlong((uint32_t)&block->data[BLOCK_EXIT_OFFSET] - (uint32_t)(&block->data[block_pos + 4])); -// call(block, codegen_debug); - codegen_endpc = (cs + cpu_state.pc) + 8; } diff --git a/src/codegen_x86-64.h b/src/CPU/codegen_x86-64.h similarity index 94% rename from src/codegen_x86-64.h rename to src/CPU/codegen_x86-64.h index e8cd97015..648a30342 100644 --- a/src/codegen_x86-64.h +++ b/src/CPU/codegen_x86-64.h @@ -10,7 +10,7 @@ #define BLOCK_EXIT_OFFSET 0x7e0 #define BLOCK_GPF_OFFSET (BLOCK_EXIT_OFFSET - 20) -#define BLOCK_MAX 1650 +#define BLOCK_MAX 1620 enum { diff --git a/src/codegen_x86.c b/src/CPU/codegen_x86.c similarity index 83% rename from src/codegen_x86.c rename to src/CPU/codegen_x86.c index 65eddfabd..f747fd262 100644 --- a/src/codegen_x86.c +++ b/src/CPU/codegen_x86.c @@ -1,13 +1,13 @@ #if defined i386 || defined __i386 || defined __i386__ || defined _X86_ || defined WIN32 || defined _WIN32 || defined _WIN32 #include -#include "ibm.h" +#include "../ibm.h" #include "cpu.h" #include "x86.h" #include "x86_flags.h" #include "x86_ops.h" #include "x87.h" -#include "mem.h" +#include "../mem.h" #include "386_common.h" @@ -23,6 +23,7 @@ #include #endif +int codegen_flat_ds, codegen_flat_ss; int mmx_ebx_ecx_loaded; int codegen_flags_changed = 0; int codegen_fpu_entered = 0; @@ -80,7 +81,7 @@ uint32_t mem_check_write_l; static uint32_t gen_MEM_LOAD_ADDR_EA_B() { - uint32_t addr = &codeblock[block_current].data[block_pos]; + uint32_t addr = (uint32_t)&codeblock[block_current].data[block_pos]; addbyte(0x89); /*MOV ESI, EDX*/ addbyte(0xd6); @@ -115,7 +116,7 @@ static uint32_t gen_MEM_LOAD_ADDR_EA_B() addbyte(8); addbyte(0x80); /*CMP abrt, 0*/ addbyte(0x7d); - addbyte(cpu_state_offset(abrt)); + addbyte((uint8_t)cpu_state_offset(abrt)); addbyte(0); addbyte(0x0f); /*MOVZX EAX, AL*/ addbyte(0xb6); @@ -130,37 +131,35 @@ static uint32_t gen_MEM_LOAD_ADDR_EA_B() static uint32_t gen_MEM_LOAD_ADDR_EA_W() { - uint32_t addr = &codeblock[block_current].data[block_pos]; + uint32_t addr = (uint32_t)&codeblock[block_current].data[block_pos]; addbyte(0x89); /*MOV ESI, EDX*/ addbyte(0xd6); addbyte(0x01); /*ADDL EDX, EAX*/ addbyte(0xc2); - addbyte(0x8d); /*LEA EDI, 1[EDX]*/ - addbyte(0x7a); - addbyte(0x01); + addbyte(0x89); /*MOV EDI, EDX*/ + addbyte(0xd7); addbyte(0xc1); /*SHR EDX, 12*/ addbyte(0xea); addbyte(12); - addbyte(0xf7); /*TEST EDI, 0xfff*/ + addbyte(0xf7); /*TEST EDI, 1*/ addbyte(0xc7); - addlong(0xfff); + addlong(1); addbyte(0x8b); /*MOV EDX, readlookup2[EDX*4]*/ addbyte(0x14); addbyte(0x95); addlong((uint32_t)readlookup2); - addbyte(0x74); /*JE slowpath*/ - addbyte(3+2+5+1); + addbyte(0x75); /*JNE slowpath*/ + addbyte(3+2+4+1); addbyte(0x83); /*CMP EDX, -1*/ addbyte(0xfa); addbyte(-1); addbyte(0x74); /*JE slowpath*/ - addbyte(5+1); - addbyte(0x0f); /*MOVZX EAX, -1[EDX+EDI]W*/ + addbyte(4+1); + addbyte(0x0f); /*MOVZX EAX, [EDX+EDI]W*/ addbyte(0xb7); - addbyte(0x44); + addbyte(0x04); addbyte(0x3a); - addbyte(-1); addbyte(0xc3); /*RET*/ addbyte(0x50); /*slowpath: PUSH EAX*/ @@ -172,7 +171,7 @@ static uint32_t gen_MEM_LOAD_ADDR_EA_W() addbyte(8); addbyte(0x80); /*CMP abrt, 0*/ addbyte(0x7d); - addbyte(cpu_state_offset(abrt)); + addbyte((uint8_t)cpu_state_offset(abrt)); addbyte(0); addbyte(0x0f); /*MOVZX EAX, AX*/ addbyte(0xb7); @@ -187,36 +186,34 @@ static uint32_t gen_MEM_LOAD_ADDR_EA_W() static uint32_t gen_MEM_LOAD_ADDR_EA_L() { - uint32_t addr = &codeblock[block_current].data[block_pos]; + uint32_t addr = (uint32_t)&codeblock[block_current].data[block_pos]; addbyte(0x89); /*MOV ESI, EDX*/ addbyte(0xd6); addbyte(0x01); /*ADDL EDX, EAX*/ addbyte(0xc2); - addbyte(0x8d); /*LEA EDI, 3[EDX]*/ - addbyte(0x7a); - addbyte(0x03); + addbyte(0x89); /*MOV EDI, EDX*/ + addbyte(0xd7); addbyte(0xc1); /*SHR EDX, 12*/ addbyte(0xea); addbyte(12); - addbyte(0xf7); /*TEST EDI, 0xffc*/ + addbyte(0xf7); /*TEST EDI, 3*/ addbyte(0xc7); - addlong(0xffc); + addlong(3); addbyte(0x8b); /*MOV EDX, readlookup2[EDX*4]*/ addbyte(0x14); addbyte(0x95); addlong((uint32_t)readlookup2); - addbyte(0x74); /*JE slowpath*/ - addbyte(3+2+4+1); + addbyte(0x75); /*JNE slowpath*/ + addbyte(3+2+3+1); addbyte(0x83); /*CMP EDX, -1*/ addbyte(0xfa); addbyte(-1); addbyte(0x74); /*JE slowpath*/ - addbyte(4+1); - addbyte(0x8b); /*MOV EAX, -3[EDX+EDI]*/ - addbyte(0x44); + addbyte(3+1); + addbyte(0x8b); /*MOV EAX, [EDX+EDI]*/ + addbyte(0x04); addbyte(0x3a); - addbyte(-3); addbyte(0xc3); /*RET*/ addbyte(0x50); /*slowpath: PUSH EAX*/ @@ -228,7 +225,7 @@ static uint32_t gen_MEM_LOAD_ADDR_EA_L() addbyte(8); addbyte(0x80); /*CMP abrt, 0*/ addbyte(0x7d); - addbyte(cpu_state_offset(abrt)); + addbyte((uint8_t)cpu_state_offset(abrt)); addbyte(0); addbyte(0x0f); /*JNE mem_abrt_rout*/ addbyte(0x85); @@ -240,40 +237,38 @@ static uint32_t gen_MEM_LOAD_ADDR_EA_L() static uint32_t gen_MEM_LOAD_ADDR_EA_Q() { - uint32_t addr = &codeblock[block_current].data[block_pos]; + uint32_t addr = (uint32_t)&codeblock[block_current].data[block_pos]; addbyte(0x89); /*MOV ESI, EDX*/ addbyte(0xd6); addbyte(0x01); /*ADDL EDX, EAX*/ addbyte(0xc2); - addbyte(0x8d); /*LEA EDI, 7[EDX]*/ - addbyte(0x7a); - addbyte(0x07); + addbyte(0x89); /*MOV EDI, EDX*/ + addbyte(0xd7); addbyte(0xc1); /*SHR EDX, 12*/ addbyte(0xea); addbyte(12); - addbyte(0xf7); /*TEST EDI, 0xff8*/ + addbyte(0xf7); /*TEST EDI, 7*/ addbyte(0xc7); - addlong(0xff8); + addlong(7); addbyte(0x8b); /*MOV EDX, readlookup2[EDX*4]*/ addbyte(0x14); addbyte(0x95); addlong((uint32_t)readlookup2); - addbyte(0x74); /*JE slowpath*/ - addbyte(3+2+4+4+1); + addbyte(0x75); /*JNE slowpath*/ + addbyte(3+2+3+4+1); addbyte(0x83); /*CMP EDX, -1*/ addbyte(0xfa); addbyte(-1); addbyte(0x74); /*JE slowpath*/ - addbyte(4+4+1); + addbyte(3+4+1); addbyte(0x8b); /*MOV EAX, [EDX+EDI]*/ - addbyte(0x44); + addbyte(0x04); addbyte(0x3a); - addbyte(-7); addbyte(0x8b); /*MOV EDX, [EDX+EDI+4]*/ addbyte(0x54); addbyte(0x3a); - addbyte(-7+4); + addbyte(4); addbyte(0xc3); /*RET*/ addbyte(0x50); /*slowpath: PUSH EAX*/ @@ -285,7 +280,7 @@ static uint32_t gen_MEM_LOAD_ADDR_EA_Q() addbyte(8); addbyte(0x80); /*CMP abrt, 0*/ addbyte(0x7d); - addbyte(cpu_state_offset(abrt)); + addbyte((uint8_t)cpu_state_offset(abrt)); addbyte(0); addbyte(0x0f); /*JNE mem_abrt_rout*/ addbyte(0x85); @@ -297,7 +292,7 @@ static uint32_t gen_MEM_LOAD_ADDR_EA_Q() static uint32_t gen_MEM_STORE_ADDR_EA_B() { - uint32_t addr = &codeblock[block_current].data[block_pos]; + uint32_t addr = (uint32_t)&codeblock[block_current].data[block_pos]; /*dat = ECX, seg = ESI, addr = EAX*/ addbyte(0x89); /*MOV EBX, ESI*/ @@ -333,7 +328,7 @@ static uint32_t gen_MEM_STORE_ADDR_EA_B() addbyte(12); addbyte(0x80); /*CMP abrt, 0*/ addbyte(0x7d); - addbyte(cpu_state_offset(abrt)); + addbyte((uint8_t)cpu_state_offset(abrt)); addbyte(0); addbyte(0x0f); /*JNE mem_abrt_rout*/ addbyte(0x85); @@ -345,38 +340,36 @@ static uint32_t gen_MEM_STORE_ADDR_EA_B() static uint32_t gen_MEM_STORE_ADDR_EA_W() { - uint32_t addr = &codeblock[block_current].data[block_pos]; + uint32_t addr = (uint32_t)&codeblock[block_current].data[block_pos]; /*dat = ECX, seg = ESI, addr = EAX*/ addbyte(0x89); /*MOV EBX, ESI*/ addbyte(0xf3); addbyte(0x01); /*ADDL ESI, EAX*/ addbyte(0xc0 | (REG_EAX << 3) | REG_ESI); - addbyte(0x8d); /*LEA EDI, 1[ESI]*/ - addbyte(0x7e); - addbyte(0x01); + addbyte(0x89); /*MOV EDI, ESI*/ + addbyte(0xf7); addbyte(0xc1); /*SHR ESI, 12*/ addbyte(0xe8 | REG_ESI); addbyte(12); - addbyte(0xf7); /*TEST EDI, 0xfff*/ + addbyte(0xf7); /*TEST EDI, 1*/ addbyte(0xc7); - addlong(0xfff); + addlong(1); addbyte(0x8b); /*MOV ESI, readlookup2[ESI*4]*/ addbyte(0x04 | (REG_ESI << 3)); addbyte(0x85 | (REG_ESI << 3)); addlong((uint32_t)writelookup2); - addbyte(0x74); /*JE slowpath*/ - addbyte(3+2+5+1); + addbyte(0x75); /*JNE slowpath*/ + addbyte(3+2+4+1); addbyte(0x83); /*CMP ESI, -1*/ addbyte(0xf8 | REG_ESI); addbyte(-1); addbyte(0x74); /*JE slowpath*/ - addbyte(5+1); - addbyte(0x66); /*MOV -1[EDI+ESI],CX*/ + addbyte(4+1); + addbyte(0x66); /*MOV [EDI+ESI],CX*/ addbyte(0x89); - addbyte(0x44 | (REG_CX << 3)); + addbyte(0x04 | (REG_CX << 3)); addbyte(REG_EDI | (REG_ESI << 3)); - addbyte(-1); addbyte(0xc3); /*RET*/ addbyte(0x51); /*slowpath: PUSH ECX*/ @@ -389,7 +382,7 @@ static uint32_t gen_MEM_STORE_ADDR_EA_W() addbyte(12); addbyte(0x80); /*CMP abrt, 0*/ addbyte(0x7d); - addbyte(cpu_state_offset(abrt)); + addbyte((uint8_t)cpu_state_offset(abrt)); addbyte(0); addbyte(0x0f); /*JNE mem_abrt_rout*/ addbyte(0x85); @@ -401,37 +394,35 @@ static uint32_t gen_MEM_STORE_ADDR_EA_W() static uint32_t gen_MEM_STORE_ADDR_EA_L() { - uint32_t addr = &codeblock[block_current].data[block_pos]; + uint32_t addr = (uint32_t)&codeblock[block_current].data[block_pos]; /*dat = ECX, seg = ESI, addr = EAX*/ addbyte(0x89); /*MOV EBX, ESI*/ addbyte(0xf3); addbyte(0x01); /*ADDL ESI, EAX*/ addbyte(0xc0 | (REG_EAX << 3) | REG_ESI); - addbyte(0x8d); /*LEA EDI, 3[ESI]*/ - addbyte(0x7e); - addbyte(0x03); + addbyte(0x89); /*MOV EDI, ESI*/ + addbyte(0xf7); addbyte(0xc1); /*SHR ESI, 12*/ addbyte(0xe8 | REG_ESI); addbyte(12); - addbyte(0xf7); /*TEST EDI, 0xffc*/ + addbyte(0xf7); /*TEST EDI, 3*/ addbyte(0xc7); - addlong(0xffc); + addlong(3); addbyte(0x8b); /*MOV ESI, readlookup2[ESI*4]*/ addbyte(0x04 | (REG_ESI << 3)); addbyte(0x85 | (REG_ESI << 3)); addlong((uint32_t)writelookup2); - addbyte(0x74); /*JE slowpath*/ - addbyte(3+2+4+1); + addbyte(0x75); /*JNE slowpath*/ + addbyte(3+2+3+1); addbyte(0x83); /*CMP ESI, -1*/ addbyte(0xf8 | REG_ESI); addbyte(-1); addbyte(0x74); /*JE slowpath*/ - addbyte(4+1); - addbyte(0x89); /*MOV -3[EDI+ESI],ECX*/ - addbyte(0x44 | (REG_ECX << 3)); + addbyte(3+1); + addbyte(0x89); /*MOV [EDI+ESI],ECX*/ + addbyte(0x04 | (REG_ECX << 3)); addbyte(REG_EDI | (REG_ESI << 3)); - addbyte(-3); addbyte(0xc3); /*RET*/ addbyte(0x51); /*slowpath: PUSH ECX*/ @@ -444,7 +435,7 @@ static uint32_t gen_MEM_STORE_ADDR_EA_L() addbyte(12); addbyte(0x80); /*CMP abrt, 0*/ addbyte(0x7d); - addbyte(cpu_state_offset(abrt)); + addbyte((uint8_t)cpu_state_offset(abrt)); addbyte(0); addbyte(0x0f); /*JNE mem_abrt_rout*/ addbyte(0x85); @@ -456,41 +447,39 @@ static uint32_t gen_MEM_STORE_ADDR_EA_L() static uint32_t gen_MEM_STORE_ADDR_EA_Q() { - uint32_t addr = &codeblock[block_current].data[block_pos]; + uint32_t addr = (uint32_t)&codeblock[block_current].data[block_pos]; /*dat = EBX/ECX, seg = ESI, addr = EAX*/ addbyte(0x89); /*MOV EDX, ESI*/ addbyte(0xf2); addbyte(0x01); /*ADDL ESI, EAX*/ addbyte(0xc0 | (REG_EAX << 3) | REG_ESI); - addbyte(0x8d); /*LEA EDI, 7[ESI]*/ - addbyte(0x7e); - addbyte(0x07); + addbyte(0x89); /*MOV EDI, ESI*/ + addbyte(0xf7); addbyte(0xc1); /*SHR ESI, 12*/ addbyte(0xe8 | REG_ESI); addbyte(12); - addbyte(0xf7); /*TEST EDI, 0xff8*/ + addbyte(0xf7); /*TEST EDI, 7*/ addbyte(0xc7); - addlong(0xff8); + addlong(7); addbyte(0x8b); /*MOV ESI, readlookup2[ESI*4]*/ addbyte(0x04 | (REG_ESI << 3)); addbyte(0x85 | (REG_ESI << 3)); addlong((uint32_t)writelookup2); - addbyte(0x74); /*JE slowpath*/ - addbyte(3+2+4+4+1); + addbyte(0x75); /*JNE slowpath*/ + addbyte(3+2+3+4+1); addbyte(0x83); /*CMP ESI, -1*/ addbyte(0xf8 | REG_ESI); addbyte(-1); addbyte(0x74); /*JE slowpath*/ - addbyte(4+4+1); - addbyte(0x89); /*MOV -7[EDI+ESI],EBX*/ - addbyte(0x44 | (REG_EBX << 3)); + addbyte(3+4+1); + addbyte(0x89); /*MOV [EDI+ESI],EBX*/ + addbyte(0x04 | (REG_EBX << 3)); addbyte(REG_EDI | (REG_ESI << 3)); - addbyte(-7); - addbyte(0x89); /*MOV -7[EDI+ESI],EBX*/ + addbyte(0x89); /*MOV 4[EDI+ESI],EBX*/ addbyte(0x44 | (REG_ECX << 3)); addbyte(REG_EDI | (REG_ESI << 3)); - addbyte(-7+4); + addbyte(4); addbyte(0xc3); /*RET*/ addbyte(0x51); /*slowpath: PUSH ECX*/ @@ -504,7 +493,7 @@ static uint32_t gen_MEM_STORE_ADDR_EA_Q() addbyte(16); addbyte(0x80); /*CMP abrt, 0*/ addbyte(0x7d); - addbyte(cpu_state_offset(abrt)); + addbyte((uint8_t)cpu_state_offset(abrt)); addbyte(0); addbyte(0x0f); /*JNE mem_abrt_rout*/ addbyte(0x85); @@ -514,10 +503,12 @@ static uint32_t gen_MEM_STORE_ADDR_EA_Q() return addr; } +#ifndef RELEASE_BUILD static char gen_MEM_LOAD_ADDR_EA_B_NO_ABRT_err[] = "gen_MEM_LOAD_ADDR_EA_B_NO_ABRT aborted\n"; +#endif static uint32_t gen_MEM_LOAD_ADDR_EA_B_NO_ABRT() { - uint32_t addr = &codeblock[block_current].data[block_pos]; + uint32_t addr = (uint32_t)&codeblock[block_current].data[block_pos]; addbyte(0x89); /*MOV ESI, EDX*/ addbyte(0xd6); @@ -553,7 +544,7 @@ static uint32_t gen_MEM_LOAD_ADDR_EA_B_NO_ABRT() #ifndef RELEASE_BUILD addbyte(0x80); /*CMP abrt, 0*/ addbyte(0x7d); - addbyte(cpu_state_offset(abrt)); + addbyte((uint8_t)cpu_state_offset(abrt)); addbyte(0); #endif addbyte(0x0f); /*MOVZX ECX, AL*/ @@ -568,7 +559,7 @@ static uint32_t gen_MEM_LOAD_ADDR_EA_B_NO_ABRT() addbyte(0xc7); /*MOV [ESP], gen_MEM_LOAD_ADDR_EA_B_NO_ABRT_err*/ addbyte(0x04); addbyte(0x24); - addlong(gen_MEM_LOAD_ADDR_EA_B_NO_ABRT_err); + addlong((uint32_t)gen_MEM_LOAD_ADDR_EA_B_NO_ABRT_err); addbyte(0xe8); /*CALL fatal*/ addlong((uint32_t)fatal - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); /*Should not return!*/ @@ -576,40 +567,40 @@ static uint32_t gen_MEM_LOAD_ADDR_EA_B_NO_ABRT() return addr; } +#ifndef RELEASE_BUILD static char gen_MEM_LOAD_ADDR_EA_W_NO_ABRT_err[] = "gen_MEM_LOAD_ADDR_EA_W_NO_ABRT aborted\n"; +#endif static uint32_t gen_MEM_LOAD_ADDR_EA_W_NO_ABRT() { - uint32_t addr = &codeblock[block_current].data[block_pos]; + uint32_t addr = (uint32_t)&codeblock[block_current].data[block_pos]; addbyte(0x89); /*MOV ESI, EDX*/ addbyte(0xd6); addbyte(0x01); /*ADDL EDX, EAX*/ addbyte(0xc2); - addbyte(0x8d); /*LEA EDI, 1[EDX]*/ - addbyte(0x7a); - addbyte(0x01); + addbyte(0x89); /*MOV EDI, EDX*/ + addbyte(0xd7); addbyte(0xc1); /*SHR EDX, 12*/ addbyte(0xea); addbyte(12); - addbyte(0xf7); /*TEST EDI, 0xfff*/ + addbyte(0xf7); /*TEST EDI, 1*/ addbyte(0xc7); - addlong(0xfff); + addlong(1); addbyte(0x8b); /*MOV EDX, readlookup2[EDX*4]*/ addbyte(0x14); addbyte(0x95); addlong((uint32_t)readlookup2); - addbyte(0x74); /*JE slowpath*/ - addbyte(3+2+5+1); + addbyte(0x75); /*JNE slowpath*/ + addbyte(3+2+4+1); addbyte(0x83); /*CMP EDX, -1*/ addbyte(0xfa); addbyte(-1); addbyte(0x74); /*JE slowpath*/ - addbyte(5+1); - addbyte(0x0f); /*MOVZX EEX, -1[EDX+EDI]W*/ + addbyte(4+1); + addbyte(0x0f); /*MOVZX ECX, [EDX+EDI]W*/ addbyte(0xb7); - addbyte(0x4c); + addbyte(0x0c); addbyte(0x3a); - addbyte(-1); addbyte(0xc3); /*RET*/ addbyte(0x50); /*slowpath: PUSH EAX*/ @@ -622,7 +613,7 @@ static uint32_t gen_MEM_LOAD_ADDR_EA_W_NO_ABRT() #ifndef RELEASE_BUILD addbyte(0x80); /*CMP abrt, 0*/ addbyte(0x7d); - addbyte(cpu_state_offset(abrt)); + addbyte((uint8_t)cpu_state_offset(abrt)); addbyte(0); #endif addbyte(0x0f); /*MOVZX ECX, AX*/ @@ -637,7 +628,7 @@ static uint32_t gen_MEM_LOAD_ADDR_EA_W_NO_ABRT() addbyte(0xc7); /*MOV [ESP], gen_MEM_LOAD_ADDR_EA_W_NO_ABRT_err*/ addbyte(0x04); addbyte(0x24); - addlong(gen_MEM_LOAD_ADDR_EA_W_NO_ABRT_err); + addlong((uint32_t)gen_MEM_LOAD_ADDR_EA_W_NO_ABRT_err); addbyte(0xe8); /*CALL fatal*/ addlong((uint32_t)fatal - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); /*Should not return!*/ @@ -645,39 +636,39 @@ static uint32_t gen_MEM_LOAD_ADDR_EA_W_NO_ABRT() return addr; } +#ifndef RELEASE_BUILD static char gen_MEM_LOAD_ADDR_EA_L_NO_ABRT_err[] = "gen_MEM_LOAD_ADDR_EA_L_NO_ABRT aborted\n"; +#endif static uint32_t gen_MEM_LOAD_ADDR_EA_L_NO_ABRT() { - uint32_t addr = &codeblock[block_current].data[block_pos]; + uint32_t addr = (uint32_t)&codeblock[block_current].data[block_pos]; addbyte(0x89); /*MOV ESI, EDX*/ addbyte(0xd6); addbyte(0x01); /*ADDL EDX, EAX*/ addbyte(0xc2); - addbyte(0x8d); /*LEA EDI, 3[EDX]*/ - addbyte(0x7a); - addbyte(0x03); + addbyte(0x89); /*MOV EDI, EDX*/ + addbyte(0xd7); addbyte(0xc1); /*SHR EDX, 12*/ addbyte(0xea); addbyte(12); - addbyte(0xf7); /*TEST EDI, 0xffc*/ + addbyte(0xf7); /*TEST EDI, 3*/ addbyte(0xc7); - addlong(0xffc); + addlong(3); addbyte(0x8b); /*MOV EDX, readlookup2[EDX*4]*/ addbyte(0x14); addbyte(0x95); addlong((uint32_t)readlookup2); - addbyte(0x74); /*JE slowpath*/ - addbyte(3+2+4+1); + addbyte(0x75); /*JE slowpath*/ + addbyte(3+2+3+1); addbyte(0x83); /*CMP EDX, -1*/ addbyte(0xfa); addbyte(-1); addbyte(0x74); /*JE slowpath*/ - addbyte(4+1); - addbyte(0x8b); /*MOV ECX, -3[EDX+EDI]*/ - addbyte(0x4c); + addbyte(3+1); + addbyte(0x8b); /*MOV ECX, [EDX+EDI]*/ + addbyte(0x0c); addbyte(0x3a); - addbyte(-3); addbyte(0xc3); /*RET*/ addbyte(0x50); /*slowpath: PUSH EAX*/ @@ -692,7 +683,7 @@ static uint32_t gen_MEM_LOAD_ADDR_EA_L_NO_ABRT() #ifndef RELEASE_BUILD addbyte(0x80); /*CMP abrt, 0*/ addbyte(0x7d); - addbyte(cpu_state_offset(abrt)); + addbyte((uint8_t)cpu_state_offset(abrt)); addbyte(0); addbyte(0x75); /*JNE mem_abrt_rout*/ addbyte(1); @@ -705,7 +696,7 @@ static uint32_t gen_MEM_LOAD_ADDR_EA_L_NO_ABRT() addbyte(0xc7); /*MOV [ESP], gen_MEM_LOAD_ADDR_EA_L_NO_ABRT_err*/ addbyte(0x04); addbyte(0x24); - addlong(gen_MEM_LOAD_ADDR_EA_L_NO_ABRT_err); + addlong((uint32_t)gen_MEM_LOAD_ADDR_EA_L_NO_ABRT_err); addbyte(0xe8); /*CALL fatal*/ addlong((uint32_t)fatal - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); /*Should not return!*/ @@ -713,10 +704,12 @@ static uint32_t gen_MEM_LOAD_ADDR_EA_L_NO_ABRT() return addr; } +#ifndef RELEASE_BUILD static char gen_MEM_STORE_ADDR_EA_B_NO_ABRT_err[] = "gen_MEM_STORE_ADDR_EA_B_NO_ABRT aborted\n"; +#endif static uint32_t gen_MEM_STORE_ADDR_EA_B_NO_ABRT() { - uint32_t addr = &codeblock[block_current].data[block_pos]; + uint32_t addr = (uint32_t)&codeblock[block_current].data[block_pos]; /*dat = ECX, seg = ESI, addr = EAX*/ addbyte(0x89); /*MOV EBX, ESI*/ @@ -753,7 +746,7 @@ static uint32_t gen_MEM_STORE_ADDR_EA_B_NO_ABRT() #ifndef RELEASE_BUILD addbyte(0x80); /*CMP abrt, 0*/ addbyte(0x7d); - addbyte(cpu_state_offset(abrt)); + addbyte((uint8_t)cpu_state_offset(abrt)); addbyte(0); addbyte(0x75); /*JNE mem_abrt_rout*/ addbyte(1); @@ -763,7 +756,7 @@ static uint32_t gen_MEM_STORE_ADDR_EA_B_NO_ABRT() addbyte(0xc7); /*MOV [ESP], gen_MEM_STORE_ADDR_EA_B_NO_ABRT_err*/ addbyte(0x04); addbyte(0x24); - addlong(gen_MEM_STORE_ADDR_EA_B_NO_ABRT_err); + addlong((uint32_t)gen_MEM_STORE_ADDR_EA_B_NO_ABRT_err); addbyte(0xe8); /*CALL fatal*/ addlong((uint32_t)fatal - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); /*Should not return!*/ @@ -771,41 +764,41 @@ static uint32_t gen_MEM_STORE_ADDR_EA_B_NO_ABRT() return addr; } +#ifndef RELEASE_BUILD static char gen_MEM_STORE_ADDR_EA_W_NO_ABRT_err[] = "gen_MEM_STORE_ADDR_EA_W_NO_ABRT aborted\n"; +#endif static uint32_t gen_MEM_STORE_ADDR_EA_W_NO_ABRT() { - uint32_t addr = &codeblock[block_current].data[block_pos]; + uint32_t addr = (uint32_t)&codeblock[block_current].data[block_pos]; /*dat = ECX, seg = ESI, addr = EAX*/ addbyte(0x89); /*MOV EBX, ESI*/ addbyte(0xf3); addbyte(0x01); /*ADDL ESI, EAX*/ addbyte(0xc0 | (REG_EAX << 3) | REG_ESI); - addbyte(0x8d); /*LEA EDI, 1[ESI]*/ - addbyte(0x7e); - addbyte(0x01); + addbyte(0x89); /*MOV EDI, ESI*/ + addbyte(0xf7); addbyte(0xc1); /*SHR ESI, 12*/ addbyte(0xe8 | REG_ESI); addbyte(12); - addbyte(0xf7); /*TEST EDI, 0xfff*/ + addbyte(0xf7); /*TEST EDI, 1*/ addbyte(0xc7); - addlong(0xfff); + addlong(1); addbyte(0x8b); /*MOV ESI, readlookup2[ESI*4]*/ addbyte(0x04 | (REG_ESI << 3)); addbyte(0x85 | (REG_ESI << 3)); addlong((uint32_t)writelookup2); - addbyte(0x74); /*JE slowpath*/ - addbyte(3+2+5+1); + addbyte(0x75); /*JNE slowpath*/ + addbyte(3+2+4+1); addbyte(0x83); /*CMP ESI, -1*/ addbyte(0xf8 | REG_ESI); addbyte(-1); addbyte(0x74); /*JE slowpath*/ - addbyte(5+1); - addbyte(0x66); /*MOV -1[EDI+ESI],CX*/ + addbyte(4+1); + addbyte(0x66); /*MOV [EDI+ESI],CX*/ addbyte(0x89); - addbyte(0x44 | (REG_CX << 3)); + addbyte(0x04 | (REG_CX << 3)); addbyte(REG_EDI | (REG_ESI << 3)); - addbyte(-1); addbyte(0xc3); /*RET*/ addbyte(0x51); /*slowpath: PUSH ECX*/ @@ -819,7 +812,7 @@ static uint32_t gen_MEM_STORE_ADDR_EA_W_NO_ABRT() #ifndef RELEASE_BUILD addbyte(0x80); /*CMP abrt, 0*/ addbyte(0x7d); - addbyte(cpu_state_offset(abrt)); + addbyte((uint8_t)cpu_state_offset(abrt)); addbyte(0); addbyte(0x75); /*JNE mem_abrt_rout*/ addbyte(1); @@ -829,7 +822,7 @@ static uint32_t gen_MEM_STORE_ADDR_EA_W_NO_ABRT() addbyte(0xc7); /*MOV [ESP], gen_MEM_STORE_ADDR_EA_W_NO_ABRT_err*/ addbyte(0x04); addbyte(0x24); - addlong(gen_MEM_STORE_ADDR_EA_W_NO_ABRT_err); + addlong((uint32_t)gen_MEM_STORE_ADDR_EA_W_NO_ABRT_err); addbyte(0xe8); /*CALL fatal*/ addlong((uint32_t)fatal - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); /*Should not return!*/ @@ -837,40 +830,40 @@ static uint32_t gen_MEM_STORE_ADDR_EA_W_NO_ABRT() return addr; } +#ifndef RELEASE_BUILD static char gen_MEM_STORE_ADDR_EA_L_NO_ABRT_err[] = "gen_MEM_STORE_ADDR_EA_L_NO_ABRT aborted\n"; +#endif static uint32_t gen_MEM_STORE_ADDR_EA_L_NO_ABRT() { - uint32_t addr = &codeblock[block_current].data[block_pos]; + uint32_t addr = (uint32_t)&codeblock[block_current].data[block_pos]; /*dat = ECX, seg = ESI, addr = EAX*/ addbyte(0x89); /*MOV EBX, ESI*/ addbyte(0xf3); addbyte(0x01); /*ADDL ESI, EAX*/ addbyte(0xc0 | (REG_EAX << 3) | REG_ESI); - addbyte(0x8d); /*LEA EDI, 3[ESI]*/ - addbyte(0x7e); - addbyte(0x03); + addbyte(0x89); /*MOV EDI, ESI*/ + addbyte(0xf7); addbyte(0xc1); /*SHR ESI, 12*/ addbyte(0xe8 | REG_ESI); addbyte(12); - addbyte(0xf7); /*TEST EDI, 0xffc*/ + addbyte(0xf7); /*TEST EDI, 3*/ addbyte(0xc7); - addlong(0xffc); + addlong(3); addbyte(0x8b); /*MOV ESI, readlookup2[ESI*4]*/ addbyte(0x04 | (REG_ESI << 3)); addbyte(0x85 | (REG_ESI << 3)); addlong((uint32_t)writelookup2); - addbyte(0x74); /*JE slowpath*/ - addbyte(3+2+4+1); + addbyte(0x75); /*JNE slowpath*/ + addbyte(3+2+3+1); addbyte(0x83); /*CMP ESI, -1*/ addbyte(0xf8 | REG_ESI); addbyte(-1); addbyte(0x74); /*JE slowpath*/ - addbyte(4+1); - addbyte(0x89); /*MOV -3[EDI+ESI],ECX*/ - addbyte(0x44 | (REG_ECX << 3)); + addbyte(3+1); + addbyte(0x89); /*MOV [EDI+ESI],ECX*/ + addbyte(0x04 | (REG_ECX << 3)); addbyte(REG_EDI | (REG_ESI << 3)); - addbyte(-3); addbyte(0xc3); /*RET*/ addbyte(0x51); /*slowpath: PUSH ECX*/ @@ -884,17 +877,17 @@ static uint32_t gen_MEM_STORE_ADDR_EA_L_NO_ABRT() #ifndef RELEASE_BUILD addbyte(0x80); /*CMP abrt, 0*/ addbyte(0x7d); - addbyte(cpu_state_offset(abrt)); + addbyte((uint8_t)cpu_state_offset(abrt)); addbyte(0); addbyte(0x75); /*JNE mem_abrt_rout*/ addbyte(1); #endif addbyte(0xc3); /*RET*/ #ifndef RELEASE_BUILD - addbyte(0xc7); /*MOV [ESP], gen_MEM_STORE_ADDR_EA_W_NO_ABRT_err*/ + addbyte(0xc7); /*MOV [ESP], gen_MEM_STORE_ADDR_EA_L_NO_ABRT_err*/ addbyte(0x04); addbyte(0x24); - addlong(gen_MEM_STORE_ADDR_EA_W_NO_ABRT_err); + addlong((uint32_t)gen_MEM_STORE_ADDR_EA_L_NO_ABRT_err); addbyte(0xe8); /*CALL fatal*/ addlong((uint32_t)fatal - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); /*Should not return!*/ @@ -904,7 +897,7 @@ static uint32_t gen_MEM_STORE_ADDR_EA_L_NO_ABRT() static uint32_t gen_MEM_CHECK_WRITE() { - uint32_t addr = &codeblock[block_current].data[block_pos]; + uint32_t addr = (uint32_t)&codeblock[block_current].data[block_pos]; /*seg = ESI, addr = EAX*/ @@ -949,7 +942,7 @@ static uint32_t gen_MEM_CHECK_WRITE() addbyte(8); addbyte(0x80); /*CMP abrt, 0*/ addbyte(0x7d); - addbyte(cpu_state_offset(abrt)); + addbyte((uint8_t)cpu_state_offset(abrt)); addbyte(0); addbyte(0x0f); /*JNE mem_abrt_rout*/ addbyte(0x85); @@ -966,7 +959,7 @@ static uint32_t gen_MEM_CHECK_WRITE() static uint32_t gen_MEM_CHECK_WRITE_W() { - uint32_t addr = &codeblock[block_current].data[block_pos]; + uint32_t addr = (uint32_t)&codeblock[block_current].data[block_pos]; /*seg = ESI, addr = EAX*/ @@ -1030,7 +1023,7 @@ static uint32_t gen_MEM_CHECK_WRITE_W() addbyte(1); addbyte(0x80); /*CMP abrt, 0*/ addbyte(0x7d); - addbyte(cpu_state_offset(abrt)); + addbyte((uint8_t)cpu_state_offset(abrt)); addbyte(0); addbyte(0x0f); /*JNE mem_abrt_rout*/ addbyte(0x85); @@ -1048,7 +1041,7 @@ static uint32_t gen_MEM_CHECK_WRITE_W() static uint32_t gen_MEM_CHECK_WRITE_L() { - uint32_t addr = &codeblock[block_current].data[block_pos]; + uint32_t addr = (uint32_t)&codeblock[block_current].data[block_pos]; /*seg = ESI, addr = EAX*/ @@ -1112,7 +1105,7 @@ static uint32_t gen_MEM_CHECK_WRITE_L() addbyte(3); addbyte(0x80); /*CMP abrt, 0*/ addbyte(0x7d); - addbyte(cpu_state_offset(abrt)); + addbyte((uint8_t)cpu_state_offset(abrt)); addbyte(0); addbyte(0x0f); /*JNE mem_abrt_rout*/ addbyte(0x85); @@ -1130,7 +1123,6 @@ static uint32_t gen_MEM_CHECK_WRITE_L() void codegen_init() { - int c; #ifdef __linux__ void *start; size_t len; @@ -1157,11 +1149,10 @@ void codegen_init() exit(-1); } #endif -// pclog("Codegen is %p\n", (void *)pages[0xfab12 >> 12].block); block_current = BLOCK_SIZE; block_pos = 0; - mem_abrt_rout = &codeblock[block_current].data[block_pos]; + mem_abrt_rout = (uint32_t)&codeblock[block_current].data[block_pos]; addbyte(0x83); /*ADDL $16+4,%esp*/ addbyte(0xC4); addbyte(0x10+4); @@ -1171,39 +1162,39 @@ void codegen_init() addbyte(0x5b); /*POP EDX*/ addbyte(0xC3); /*RET*/ block_pos = (block_pos + 15) & ~15; - mem_load_addr_ea_l = gen_MEM_LOAD_ADDR_EA_L(); + mem_load_addr_ea_l = (uint32_t)gen_MEM_LOAD_ADDR_EA_L(); block_pos = (block_pos + 15) & ~15; - mem_load_addr_ea_w = gen_MEM_LOAD_ADDR_EA_W(); + mem_load_addr_ea_w = (uint32_t)gen_MEM_LOAD_ADDR_EA_W(); block_pos = (block_pos + 15) & ~15; - mem_load_addr_ea_b = gen_MEM_LOAD_ADDR_EA_B(); + mem_load_addr_ea_b = (uint32_t)gen_MEM_LOAD_ADDR_EA_B(); block_pos = (block_pos + 15) & ~15; - mem_load_addr_ea_q = gen_MEM_LOAD_ADDR_EA_Q(); + mem_load_addr_ea_q = (uint32_t)gen_MEM_LOAD_ADDR_EA_Q(); block_pos = (block_pos + 15) & ~15; - mem_store_addr_ea_l = gen_MEM_STORE_ADDR_EA_L(); + mem_store_addr_ea_l = (uint32_t)gen_MEM_STORE_ADDR_EA_L(); block_pos = (block_pos + 15) & ~15; - mem_store_addr_ea_w = gen_MEM_STORE_ADDR_EA_W(); + mem_store_addr_ea_w = (uint32_t)gen_MEM_STORE_ADDR_EA_W(); block_pos = (block_pos + 15) & ~15; - mem_store_addr_ea_b = gen_MEM_STORE_ADDR_EA_B(); + mem_store_addr_ea_b = (uint32_t)gen_MEM_STORE_ADDR_EA_B(); block_pos = (block_pos + 15) & ~15; - mem_store_addr_ea_q = gen_MEM_STORE_ADDR_EA_Q(); + mem_store_addr_ea_q = (uint32_t)gen_MEM_STORE_ADDR_EA_Q(); block_pos = (block_pos + 15) & ~15; - mem_load_addr_ea_b_no_abrt = gen_MEM_LOAD_ADDR_EA_B_NO_ABRT(); + mem_load_addr_ea_b_no_abrt = (uint32_t)gen_MEM_LOAD_ADDR_EA_B_NO_ABRT(); block_pos = (block_pos + 15) & ~15; - mem_store_addr_ea_b_no_abrt = gen_MEM_STORE_ADDR_EA_B_NO_ABRT(); + mem_store_addr_ea_b_no_abrt = (uint32_t)gen_MEM_STORE_ADDR_EA_B_NO_ABRT(); block_pos = (block_pos + 15) & ~15; - mem_load_addr_ea_w_no_abrt = gen_MEM_LOAD_ADDR_EA_W_NO_ABRT(); + mem_load_addr_ea_w_no_abrt = (uint32_t)gen_MEM_LOAD_ADDR_EA_W_NO_ABRT(); block_pos = (block_pos + 15) & ~15; - mem_store_addr_ea_w_no_abrt = gen_MEM_STORE_ADDR_EA_W_NO_ABRT(); + mem_store_addr_ea_w_no_abrt = (uint32_t)gen_MEM_STORE_ADDR_EA_W_NO_ABRT(); block_pos = (block_pos + 15) & ~15; - mem_load_addr_ea_l_no_abrt = gen_MEM_LOAD_ADDR_EA_L_NO_ABRT(); + mem_load_addr_ea_l_no_abrt = (uint32_t)gen_MEM_LOAD_ADDR_EA_L_NO_ABRT(); block_pos = (block_pos + 15) & ~15; - mem_store_addr_ea_l_no_abrt = gen_MEM_STORE_ADDR_EA_L_NO_ABRT(); + mem_store_addr_ea_l_no_abrt = (uint32_t)gen_MEM_STORE_ADDR_EA_L_NO_ABRT(); block_pos = (block_pos + 15) & ~15; - mem_check_write = gen_MEM_CHECK_WRITE(); + mem_check_write = (uint32_t)gen_MEM_CHECK_WRITE(); block_pos = (block_pos + 15) & ~15; - mem_check_write_w = gen_MEM_CHECK_WRITE_W(); + mem_check_write_w = (uint32_t)gen_MEM_CHECK_WRITE_W(); block_pos = (block_pos + 15) & ~15; - mem_check_write_l = gen_MEM_CHECK_WRITE_L(); + mem_check_write_l = (uint32_t)gen_MEM_CHECK_WRITE_L(); asm( "fstcw %0\n" @@ -1220,7 +1211,7 @@ void codegen_reset() void dump_block() { - codeblock_t *block = pages[0x119000 >> 12].block; +/* codeblock_t *block = pages[0x119000 >> 12].block; pclog("dump_block:\n"); while (block) @@ -1233,12 +1224,12 @@ void dump_block() block = block->next; } - pclog("dump_block done\n"); + pclog("dump_block done\n");*/ } static void add_to_block_list(codeblock_t *block) { - codeblock_t *block_prev = pages[block->phys >> 12].block; + codeblock_t *block_prev = pages[block->phys >> 12].block[(block->phys >> 10) & 3]; if (!block->page_mask) fatal("add_to_block_list - mask = 0\n"); @@ -1247,12 +1238,12 @@ static void add_to_block_list(codeblock_t *block) { block->next = block_prev; block_prev->prev = block; - pages[block->phys >> 12].block = block; + pages[block->phys >> 12].block[(block->phys >> 10) & 3] = block; } else { block->next = NULL; - pages[block->phys >> 12].block = block; + pages[block->phys >> 12].block[(block->phys >> 10) & 3] = block; } if (block->next) @@ -1263,18 +1254,18 @@ static void add_to_block_list(codeblock_t *block) if (block->page_mask2) { - block_prev = pages[block->phys_2 >> 12].block_2; + block_prev = pages[block->phys_2 >> 12].block_2[(block->phys_2 >> 10) & 3]; if (block_prev) { block->next_2 = block_prev; block_prev->prev_2 = block; - pages[block->phys_2 >> 12].block_2 = block; + pages[block->phys_2 >> 12].block_2[(block->phys_2 >> 10) & 3] = block; } else { block->next_2 = NULL; - pages[block->phys_2 >> 12].block_2 = block; + pages[block->phys_2 >> 12].block_2[(block->phys_2 >> 10) & 3] = block; } } } @@ -1292,7 +1283,7 @@ static void remove_from_block_list(codeblock_t *block, uint32_t pc) } else { - pages[block->phys >> 12].block = block->next; + pages[block->phys >> 12].block[(block->phys >> 10) & 3] = block->next; if (block->next) block->next->prev = NULL; else @@ -1313,8 +1304,7 @@ static void remove_from_block_list(codeblock_t *block, uint32_t pc) } else { -// pclog(" pages.block_2=%p 3 %p %p\n", (void *)block->next_2, (void *)block, (void *)pages[block->phys_2 >> 12].block_2); - pages[block->phys_2 >> 12].block_2 = block->next_2; + pages[block->phys_2 >> 12].block_2[(block->phys_2 >> 10) & 3] = block->next_2; if (block->next_2) block->next_2->prev_2 = NULL; else @@ -1339,7 +1329,7 @@ static void delete_block(codeblock_t *block) void codegen_check_flush(page_t *page, uint64_t mask, uint32_t phys_addr) { - struct codeblock_t *block = page->block; + struct codeblock_t *block = page->block[(phys_addr >> 10) & 3]; while (block) { @@ -1353,7 +1343,7 @@ void codegen_check_flush(page_t *page, uint64_t mask, uint32_t phys_addr) block = block->next; } - block = page->block_2; + block = page->block_2[(phys_addr >> 10) & 3]; while (block) { @@ -1371,20 +1361,16 @@ void codegen_check_flush(page_t *page, uint64_t mask, uint32_t phys_addr) void codegen_block_init(uint32_t phys_addr) { codeblock_t *block; - int has_evicted = 0; page_t *page = &pages[phys_addr >> 12]; - if (!page->block) + if (!page->block[(phys_addr >> 10) & 3]) mem_flush_write_page(phys_addr, cs+cpu_state.pc); block_current = (block_current + 1) & BLOCK_MASK; block = &codeblock[block_current]; -// if (block->pc == 0xb00b4ff5) -// pclog("Init target block\n"); if (block->pc != 0) { -// pclog("Reuse block : was %08x now %08x\n", block->pc, cs+pc); delete_block(block); cpu_recomp_reuse++; } @@ -1396,12 +1382,13 @@ void codegen_block_init(uint32_t phys_addr) block->_cs = cs; block->pnt = block_current; block->phys = phys_addr; - block->use32 = use32; - block->stack32 = stack32; + block->dirty_mask = &page->dirty_mask[(phys_addr >> PAGE_MASK_INDEX_SHIFT) & PAGE_MASK_INDEX_MASK]; + block->dirty_mask2 = NULL; block->next = block->prev = NULL; block->next_2 = block->prev_2 = NULL; block->page_mask = 0; block->flags = CODEBLOCK_STATIC_TOP; + block->status = cpu_cur_status; block->was_recompiled = 0; @@ -1412,10 +1399,9 @@ void codegen_block_init(uint32_t phys_addr) void codegen_block_start_recompile(codeblock_t *block) { - int has_evicted = 0; page_t *page = &pages[block->phys >> 12]; - if (!page->block) + if (!page->block[(block->phys >> 10) & 3]) mem_flush_write_page(block->phys, cs+cpu_state.pc); block_num = HASH(block->phys); @@ -1457,8 +1443,6 @@ void codegen_block_start_recompile(codeblock_t *block) addbyte(0xBD); /*MOVL EBP, &cpu_state*/ addlong(((uintptr_t)&cpu_state) + 128); -// pclog("New block %i for %08X %03x\n", block_current, cs+pc, block_num); - last_op32 = -1; last_ea_seg = NULL; last_ssegs = -1; @@ -1482,6 +1466,9 @@ void codegen_block_start_recompile(codeblock_t *block) block->TOP = cpu_state.TOP; block->was_recompiled = 1; + + codegen_flat_ds = cpu_cur_status & CPU_STATUS_FLATDS; + codegen_flat_ss = cpu_cur_status & CPU_STATUS_FLATSS; } void codegen_block_remove() @@ -1497,59 +1484,60 @@ void codegen_block_remove() void codegen_block_generate_end_mask() { codeblock_t *block = &codeblock[block_current]; - uint32_t start_pc = (block->pc & 0xffc) | (block->phys & ~0xfff); - uint32_t end_pc = ((codegen_endpc + 3) & 0xffc) | (block->phys & ~0xfff); + uint32_t start_pc; + uint32_t end_pc; block->endpc = codegen_endpc; block->page_mask = 0; - start_pc = block->pc & 0xffc; - start_pc &= ~PAGE_MASK_MASK; - end_pc = ((block->endpc & 0xffc) + PAGE_MASK_MASK) & ~PAGE_MASK_MASK; - if (end_pc > 0xfff || end_pc < start_pc) - end_pc = 0xfff; + start_pc = (block->pc & 0x3ff) & ~15; + if ((block->pc ^ block->endpc) & ~0x3ff) + end_pc = 0x3ff & ~15; + else + end_pc = (block->endpc & 0x3ff) & ~15; + if (end_pc < start_pc) + end_pc = 0x3ff; start_pc >>= PAGE_MASK_SHIFT; end_pc >>= PAGE_MASK_SHIFT; -// pclog("block_end: %08x %08x\n", start_pc, end_pc); for (; start_pc <= end_pc; start_pc++) { block->page_mask |= ((uint64_t)1 << start_pc); -// pclog(" %08x %llx\n", start_pc, block->page_mask); } - pages[block->phys >> 12].code_present_mask |= block->page_mask; + pages[block->phys >> 12].code_present_mask[(block->phys >> 10) & 3] |= block->page_mask; block->phys_2 = -1; block->page_mask2 = 0; block->next_2 = block->prev_2 = NULL; - if ((block->pc ^ block->endpc) & ~0xfff) + if ((block->pc ^ block->endpc) & ~0x3ff) { block->phys_2 = get_phys_noabrt(block->endpc); if (block->phys_2 != -1) { -// pclog("start block - %08x %08x %p %p %p %08x\n", block->pc, block->endpc, (void *)block, (void *)block->next_2, (void *)pages[block->phys_2 >> 12].block_2, block->phys_2); + page_t *page_2 = &pages[block->phys_2 >> 12]; start_pc = 0; - end_pc = (block->endpc & 0xfff) >> PAGE_MASK_SHIFT; + end_pc = (block->endpc & 0x3ff) >> PAGE_MASK_SHIFT; for (; start_pc <= end_pc; start_pc++) block->page_mask2 |= ((uint64_t)1 << start_pc); + page_2->code_present_mask[(block->phys_2 >> 10) & 3] |= block->page_mask2; - if (!pages[block->phys_2 >> 12].block_2) + if (!pages[block->phys_2 >> 12].block_2[(block->phys_2 >> 10) & 3]) mem_flush_write_page(block->phys_2, block->endpc); -// pclog("New block - %08x %08x %p %p phys %08x %08x %016llx\n", block->pc, block->endpc, (void *)block, (void *)block->next_2, block->phys, block->phys_2, block->page_mask2); + if (!block->page_mask2) fatal("!page_mask2\n"); if (block->next_2) { -// pclog(" next_2->pc=%08x\n", block->next_2->pc); if (!block->next_2->pc) fatal("block->next_2->pc=0 %p\n", (void *)block->next_2); } + + block->dirty_mask2 = &page_2->dirty_mask[(block->phys_2 >> PAGE_MASK_INDEX_SHIFT) & PAGE_MASK_INDEX_MASK]; } } -// pclog("block_end: %08x %08x %016llx\n", block->pc, block->endpc, block->page_mask); recomp_page = -1; } @@ -1569,14 +1557,14 @@ void codegen_block_end_recompile(codeblock_t *block) { addbyte(0x81); /*SUB $codegen_block_cycles, cyclcs*/ addbyte(0x6d); - addbyte(cpu_state_offset(_cycles)); + addbyte((uint8_t)cpu_state_offset(_cycles)); addlong(codegen_block_cycles); } if (codegen_block_ins) { addbyte(0x81); /*ADD $codegen_block_ins,ins*/ addbyte(0x45); - addbyte(cpu_state_offset(cpu_recomp_ins)); + addbyte((uint8_t)cpu_state_offset(cpu_recomp_ins)); addlong(codegen_block_ins); } #if 0 @@ -1605,7 +1593,6 @@ void codegen_block_end_recompile(codeblock_t *block) block->next_2 = block->prev_2 = NULL; codegen_block_generate_end_mask(); add_to_block_list(block); -// pclog("End block %i\n", block_num); if (!(block->flags & CODEBLOCK_HAS_FPU)) block->flags &= ~CODEBLOCK_STATIC_TOP; @@ -1616,29 +1603,6 @@ void codegen_flush() return; } -static int opcode_conditional_jump[256] = -{ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /*00*/ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*10*/ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*20*/ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*30*/ - - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*40*/ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*50*/ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*60*/ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*70*/ - - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*80*/ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*90*/ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*a0*/ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*b0*/ - - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*c0*/ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*d0*/ - 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*e0*/ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*f0*/ -}; - static int opcode_modrm[256] = { 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, /*00*/ @@ -1675,7 +1639,7 @@ int opcode_0f_modrm[256] = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*80*/ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*90*/ - 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, /*a0*/ + 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, /*a0*/ 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, /*b0*/ 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, /*c0*/ @@ -1698,7 +1662,7 @@ static x86seg *codegen_generate_ea_16_long(x86seg *op_ea_seg, uint32_t fetchdat, { addbyte(0xC7); /*MOVL $0,(ssegs)*/ addbyte(0x45); - addbyte(cpu_state_offset(eaaddr)); + addbyte((uint8_t)cpu_state_offset(eaaddr)); addlong((fetchdat >> 8) & 0xffff); (*op_pc) += 2; } @@ -1715,7 +1679,7 @@ static x86seg *codegen_generate_ea_16_long(x86seg *op_ea_seg, uint32_t fetchdat, break; case 1: addbyte(0xb8); /*MOVL ,%eax*/ - addlong((uint32_t)(int8_t)(rmdat >> 8));// pc++; + addlong((uint32_t)(int8_t)(rmdat >> 8)); addbyte(0x03); /*ADDL *mod1add[0][cpu_rm], %eax*/ addbyte(0x05); addlong((uint32_t)mod1add[0][cpu_rm]); @@ -1726,7 +1690,7 @@ static x86seg *codegen_generate_ea_16_long(x86seg *op_ea_seg, uint32_t fetchdat, break; case 2: addbyte(0xb8); /*MOVL ,%eax*/ - addlong((fetchdat >> 8) & 0xffff);// pc++; + addlong((fetchdat >> 8) & 0xffff); addbyte(0x03); /*ADDL *mod1add[0][cpu_rm], %eax*/ addbyte(0x05); addlong((uint32_t)mod1add[0][cpu_rm]); @@ -1763,14 +1727,14 @@ static x86seg *codegen_generate_ea_32_long(x86seg *op_ea_seg, uint32_t fetchdat, { new_eaaddr = fastreadl(cs + (*op_pc) + 1); addbyte(0xb8); /*MOVL ,%eax*/ - addlong(new_eaaddr);// pc++; + addlong(new_eaaddr); (*op_pc) += 4; } else { addbyte(0x8b); /*MOVL regs[sib&7].l, %eax*/ addbyte(0x45); - addbyte(cpu_state_offset(regs[sib & 7].l)); + addbyte((uint8_t)cpu_state_offset(regs[sib & 7].l)); } break; case 1: @@ -1779,7 +1743,7 @@ static x86seg *codegen_generate_ea_32_long(x86seg *op_ea_seg, uint32_t fetchdat, addlong(new_eaaddr); addbyte(0x03); /*ADDL regs[sib&7].l, %eax*/ addbyte(0x45); - addbyte(cpu_state_offset(regs[sib & 7].l)); + addbyte((uint8_t)cpu_state_offset(regs[sib & 7].l)); (*op_pc)++; break; case 2: @@ -1788,7 +1752,7 @@ static x86seg *codegen_generate_ea_32_long(x86seg *op_ea_seg, uint32_t fetchdat, addlong(new_eaaddr); addbyte(0x03); /*ADDL regs[sib&7].l, %eax*/ addbyte(0x45); - addbyte(cpu_state_offset(regs[sib & 7].l)); + addbyte((uint8_t)cpu_state_offset(regs[sib & 7].l)); (*op_pc) += 4; break; } @@ -1806,20 +1770,20 @@ static x86seg *codegen_generate_ea_32_long(x86seg *op_ea_seg, uint32_t fetchdat, case 0: addbyte(0x03); /*ADDL regs[sib&7].l, %eax*/ addbyte(0x45); - addbyte(cpu_state_offset(regs[(sib >> 3) & 7].l)); + addbyte((uint8_t)cpu_state_offset(regs[(sib >> 3) & 7].l)); break; case 1: - addbyte(0x8B); addbyte(0x5D); addbyte(cpu_state_offset(regs[(sib >> 3) & 7].l)); /*MOVL armregs[RD],%ebx*/ + addbyte(0x8B); addbyte(0x5D); addbyte((uint8_t)cpu_state_offset(regs[(sib >> 3) & 7].l)); /*MOVL armregs[RD],%ebx*/ addbyte(0x01); addbyte(0xD8); /*ADDL %ebx,%eax*/ addbyte(0x01); addbyte(0xD8); /*ADDL %ebx,%eax*/ break; case 2: - addbyte(0x8B); addbyte(0x5D); addbyte(cpu_state_offset(regs[(sib >> 3) & 7].l)); /*MOVL armregs[RD],%ebx*/ + addbyte(0x8B); addbyte(0x5D); addbyte((uint8_t)cpu_state_offset(regs[(sib >> 3) & 7].l)); /*MOVL armregs[RD],%ebx*/ addbyte(0xC1); addbyte(0xE3); addbyte(2); /*SHL $2,%ebx*/ addbyte(0x01); addbyte(0xD8); /*ADDL %ebx,%eax*/ break; case 3: - addbyte(0x8B); addbyte(0x5D); addbyte(cpu_state_offset(regs[(sib >> 3) & 7].l)); /*MOVL armregs[RD],%ebx*/ + addbyte(0x8B); addbyte(0x5D); addbyte((uint8_t)cpu_state_offset(regs[(sib >> 3) & 7].l)); /*MOVL armregs[RD],%ebx*/ addbyte(0xC1); addbyte(0xE3); addbyte(3); /*SHL $2,%ebx*/ addbyte(0x01); addbyte(0xD8); /*ADDL %ebx,%eax*/ break; @@ -1835,16 +1799,14 @@ static x86seg *codegen_generate_ea_32_long(x86seg *op_ea_seg, uint32_t fetchdat, new_eaaddr = fastreadl(cs + (*op_pc) + 1); addbyte(0xC7); /*MOVL $new_eaaddr,(eaaddr)*/ addbyte(0x45); - addbyte(cpu_state_offset(eaaddr)); + addbyte((uint8_t)cpu_state_offset(eaaddr)); addlong(new_eaaddr); (*op_pc) += 4; return op_ea_seg; } addbyte(0x8b); /*MOVL regs[sib&7].l, %eax*/ addbyte(0x45); - addbyte(cpu_state_offset(regs[cpu_rm].l)); -// addbyte(0xa1); /*MOVL regs[cpu_rm].l, %eax*/ -// addlong((uint32_t)&cpu_state.regs[cpu_rm].l); + addbyte((uint8_t)cpu_state_offset(regs[cpu_rm].l)); cpu_state.eaaddr = cpu_state.regs[cpu_rm].l; if (cpu_mod) { @@ -2032,19 +1994,19 @@ void codegen_generate_call(uint8_t opcode, OpFn op, uint32_t fetchdat, uint32_t generate_call: codegen_timing_opcode(opcode, fetchdat, op_32); - + if ((op_table == x86_dynarec_opcodes && - ((opcode & 0xf0) == 0x70 || (opcode & 0xfc) == 0xe0 || opcode == 0xc2 || + ((opcode & 0xf0) == 0x70 || (opcode & 0xfc) == 0xe0 || opcode == 0xc2 || (opcode & 0xfe) == 0xca || (opcode & 0xfc) == 0xcc || (opcode & 0xfc) == 0xe8 || - (opcode == 0xff && ((fetchdat & 0x38) >= 0x10 && (fetchdat & 0x38) < 0x30))) || - (op_table == x86_dynarec_opcodes_0f && ((opcode & 0xf0) == 0x80)))) + (opcode == 0xff && ((fetchdat & 0x38) >= 0x10 && (fetchdat & 0x38) < 0x30)))) || + (op_table == x86_dynarec_opcodes_0f && ((opcode & 0xf0) == 0x80))) { /*Opcode is likely to cause block to exit, update cycle count*/ if (codegen_block_cycles) { addbyte(0x81); /*SUB $codegen_block_cycles, cyclcs*/ addbyte(0x6d); - addbyte(cpu_state_offset(_cycles)); + addbyte((uint8_t)cpu_state_offset(_cycles)); addlong(codegen_block_cycles); codegen_block_cycles = 0; } @@ -2052,7 +2014,7 @@ generate_call: { addbyte(0x81); /*ADD $codegen_block_ins,ins*/ addbyte(0x45); - addbyte(cpu_state_offset(cpu_recomp_ins)); + addbyte((uint8_t)cpu_state_offset(cpu_recomp_ins)); addlong(codegen_block_ins); codegen_block_ins = 0; } @@ -2086,15 +2048,13 @@ generate_call: } op = op_table[((opcode >> opcode_shift) | op_32) & opcode_mask]; -// if (output) -// pclog("Generate call at %08X %02X %08X %02X %08X %08X %08X %08X %08X %02X %02X %02X %02X\n", &codeblock[block_current][block_pos], opcode, new_pc, ram[old_pc], EAX, EBX, ECX, EDX, ESI, ram[0x7bd2+6],ram[0x7bd2+7],ram[0x7bd2+8],ram[0x7bd2+9]); if (op_ssegs != last_ssegs) { last_ssegs = op_ssegs; addbyte(0xC6); /*MOVB [ssegs],op_ssegs*/ addbyte(0x45); - addbyte(cpu_state_offset(ssegs)); + addbyte((uint8_t)cpu_state_offset(ssegs)); addbyte(op_pc + pc_off); } @@ -2113,7 +2073,7 @@ generate_call: addbyte(0xC7); /*MOVL $rm | mod | reg,(rm_mod_reg_data)*/ addbyte(0x45); - addbyte(cpu_state_offset(rm_data.rm_mod_reg_data)); + addbyte((uint8_t)cpu_state_offset(rm_data.rm_mod_reg_data)); addlong(cpu_rm | (cpu_mod << 8) | (cpu_reg << 16)); op_pc += pc_off; @@ -2129,18 +2089,18 @@ generate_call: last_ea_seg = op_ea_seg; addbyte(0xC7); /*MOVL $&_ds,(ea_seg)*/ addbyte(0x45); - addbyte(cpu_state_offset(ea_seg)); + addbyte((uint8_t)cpu_state_offset(ea_seg)); addlong((uint32_t)op_ea_seg); } addbyte(0xC7); /*MOVL pc,new_pc*/ addbyte(0x45); - addbyte(cpu_state_offset(pc)); + addbyte((uint8_t)cpu_state_offset(pc)); addlong(op_pc + pc_off); addbyte(0xC7); /*MOVL $old_pc,(oldpc)*/ addbyte(0x45); - addbyte(cpu_state_offset(oldpc)); + addbyte((uint8_t)cpu_state_offset(oldpc)); addlong(old_pc); if (op_32 != last_op32) @@ -2148,7 +2108,7 @@ generate_call: last_op32 = op_32; addbyte(0xC7); /*MOVL $use32,(op32)*/ addbyte(0x45); - addbyte(cpu_state_offset(op32)); + addbyte((uint8_t)cpu_state_offset(op32)); addlong(op_32); } @@ -2169,9 +2129,6 @@ generate_call: addbyte(0x0F); addbyte(0x85); /*JNZ 0*/ addlong((uint32_t)&block->data[BLOCK_EXIT_OFFSET] - (uint32_t)(&block->data[block_pos + 4])); -// addbyte(0xE8); /*CALL*/ -// addlong(((uint8_t *)codegen_debug - (uint8_t *)(&block->data[block_pos + 4]))); - codegen_endpc = (cs + cpu_state.pc) + 8; } diff --git a/src/codegen_x86.h b/src/CPU/codegen_x86.h similarity index 100% rename from src/codegen_x86.h rename to src/CPU/codegen_x86.h diff --git a/src/cpu.c b/src/CPU/cpu.c similarity index 94% rename from src/cpu.c rename to src/CPU/cpu.c index 6db4457ab..0f12a59f1 100644 --- a/src/cpu.c +++ b/src/CPU/cpu.c @@ -1,13 +1,30 @@ -/* Copyright holders: Sarah Walker, Tenshi, leilei - see COPYING for more details -*/ -#include "ibm.h" +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * CPU type handler. + * + * Version: @(#)cpu.c 1.0.1 2017/06/03 + * + * Authors: Sarah Walker, + * leilei, + * Miran Grca, + * Copyright 2008-2017 Sarah Walker. + * Copyright 2016-2017 leilei. + * Copyright 2016-2017 Miran Grca. + */ +#include "../ibm.h" #include "cpu.h" -#include "model.h" -#include "io.h" +#include "../device.h" +#include "../model.h" +#include "../io.h" #include "x86_ops.h" -#include "mem.h" -#include "pci.h" +#include "../mem.h" +#include "../pci.h" #include "codegen.h" int isa_cycles; @@ -74,6 +91,9 @@ int cpu_hasrdtsc; int cpu_hasMMX, cpu_hasMSR; int cpu_hasCR4; int cpu_use_dynarec; +int cpu_cyrix_alignment; + +int hasfpu; uint64_t cpu_CR4_mask; @@ -81,6 +101,7 @@ int cpu_cycles_read, cpu_cycles_read_l, cpu_cycles_write, cpu_cycles_write_l; int cpu_prefetch_cycles, cpu_prefetch_width; int cpu_waitstates; int cpu_cache_int_enabled, cpu_cache_ext_enabled; +int cpu_pci_speed; int is286, is386; int israpidcad, is_pentium; @@ -132,6 +153,7 @@ int timing_iret_rm, timing_iret_v86, timing_iret_pm, timing_iret_pm_outer; int timing_call_rm, timing_call_pm, timing_call_pm_gate, timing_call_pm_gate_inner; int timing_retf_rm, timing_retf_pm, timing_retf_pm_outer; int timing_jmp_rm, timing_jmp_pm, timing_jmp_pm_gate; +int timing_misaligned; static struct { @@ -166,11 +188,13 @@ CPU cpus_8088[] = { /*8088 standard*/ {"8088/4.77", CPU_8088, 0, 4772728, 1, 0, 0, 0, 0, 0, 0,0,0,0}, - {"8088/7.16", CPU_8088, 1, 14318184/2, 1, 0, 0, 0, 0, 0, 0,0,0,0}, {"8088/8", CPU_8088, 1, 8000000, 1, 0, 0, 0, 0, 0, 0,0,0,0}, +#if 0 + {"8088/7.16", CPU_8088, 1, 14318184/2, 1, 0, 0, 0, 0, 0, 0,0,0,0}, {"8088/10", CPU_8088, 2, 10000000, 1, 0, 0, 0, 0, 0, 0,0,0,0}, {"8088/12", CPU_8088, 3, 12000000, 1, 0, 0, 0, 0, 0, 0,0,0,0}, {"8088/16", CPU_8088, 4, 16000000, 1, 0, 0, 0, 0, 0, 0,0,0,0}, +#endif {"", -1, 0, 0, 0, 0, 0,0,0,0} }; @@ -181,6 +205,15 @@ CPU cpus_pcjr[] = {"", -1, 0, 0, 0, 0, 0,0,0,0} }; +CPU cpus_europc[] = +{ + /*8088 EuroPC*/ + {"8088/4.77", CPU_8088, 0, 4772728, 1, 0, 0, 0, 0, 0, 0,0,0,0}, + {"8088/7.16", CPU_8088, 1, 14318184/2, 1, 0, 0, 0, 0, 0, 0,0,0,0}, + {"8088/9.54", CPU_8088, 1, 4772728*2, 1, 0, 0, 0, 0, 0, 0,0,0,0}, + {"", -1, 0, 0, 0, 0} +}; + CPU cpus_8086[] = { /*8086 standard*/ @@ -228,28 +261,31 @@ CPU cpus_ps1_m2011[] = {"", -1, 0, 0, 0, 0} }; -CPU cpus_i386[] = +CPU cpus_ps2_m30_286[] = { - /*i386*/ + /*286*/ + {"286/10", CPU_286, 2, 10000000, 1, 0, 0, 0, 0, 0, 2,2,2,2}, + {"286/12", CPU_286, 3, 12000000, 1, 0, 0, 0, 0, 0, 3,3,3,3}, + {"286/16", CPU_286, 4, 16000000, 1, 0, 0, 0, 0, 0, 3,3,3,3}, + {"286/20", CPU_286, 5, 20000000, 1, 0, 0, 0, 0, 0, 4,4,4,4}, + {"286/25", CPU_286, 6, 25000000, 1, 0, 0, 0, 0, 0, 4,4,4,4}, + {"", -1, 0, 0, 0, 0} +}; + +CPU cpus_i386SX[] = +{ + /*i386SX*/ {"i386SX/16", CPU_386SX, 0, 16000000, 1, 0, 0x2308, 0, 0, 0, 3,3,3,3}, {"i386SX/20", CPU_386SX, 1, 20000000, 1, 0, 0x2308, 0, 0, 0, 4,4,3,3}, {"i386SX/25", CPU_386SX, 2, 25000000, 1, 0, 0x2308, 0, 0, 0, 4,4,3,3}, {"i386SX/33", CPU_386SX, 3, 33333333, 1, 0, 0x2308, 0, 0, 0, 6,6,3,3}, {"i386SX/40", CPU_386SX, 4, 40000000, 1, 0, 0x2308, 0, 0, 0, 7,7,3,3}, - {"i386DX/16", CPU_386DX, 0, 16000000, 1, 0, 0x0308, 0, 0, 0, 3,3,3,3}, - {"i386DX/20", CPU_386DX, 1, 20000000, 1, 0, 0x0308, 0, 0, 0, 4,4,3,3}, - {"i386DX/25", CPU_386DX, 2, 25000000, 1, 0, 0x0308, 0, 0, 0, 4,4,3,3}, - {"i386DX/33", CPU_386DX, 3, 33333333, 1, 0, 0x0308, 0, 0, 0, 6,6,3,3}, - {"i386DX/40", CPU_386DX, 4, 40000000, 1, 0, 0x0308, 0, 0, 0, 7,7,3,3}, - {"RapidCAD/25", CPU_RAPIDCAD, 2, 25000000, 1, 0, 0x430, 0, 0, 0, 4,4,3,3}, - {"RapidCAD/33", CPU_RAPIDCAD, 3, 33333333, 1, 0, 0x430, 0, 0, 0, 6,6,3,3}, - {"RapidCAD/40", CPU_RAPIDCAD, 4, 40000000, 1, 0, 0x430, 0, 0, 0, 7,7,3,3}, {"", -1, 0, 0, 0} }; CPU cpus_i386DX[] = { - /*i386*/ + /*i386DX*/ {"i386DX/16", CPU_386DX, 0, 16000000, 1, 0, 0x0308, 0, 0, 0, 3,3,3,3}, {"i386DX/20", CPU_386DX, 1, 20000000, 1, 0, 0x0308, 0, 0, 0, 4,4,3,3}, {"i386DX/25", CPU_386DX, 2, 25000000, 1, 0, 0x0308, 0, 0, 0, 4,4,3,3}, @@ -263,12 +299,12 @@ CPU cpus_i386DX[] = CPU cpus_acer[] = { - /*i386*/ + /*i386SX*/ {"i386SX/25", CPU_386SX, 2, 25000000, 1, 0, 0x2308, 0, 0, 0, 4,4,4,4}, {"", -1, 0, 0, 0} }; -CPU cpus_Am386[] = +CPU cpus_Am386SX[] = { /*Am386*/ {"Am386SX/16", CPU_386SX, 0, 16000000, 1, 0, 0x2308, 0, 0, 0, 3,3,3,3}, @@ -276,9 +312,6 @@ CPU cpus_Am386[] = {"Am386SX/25", CPU_386SX, 2, 25000000, 1, 0, 0x2308, 0, 0, 0, 4,4,3,3}, {"Am386SX/33", CPU_386SX, 3, 33333333, 1, 0, 0x2308, 0, 0, 0, 6,6,3,3}, {"Am386SX/40", CPU_386SX, 4, 40000000, 1, 0, 0x2308, 0, 0, 0, 7,7,3,3}, - {"Am386DX/25", CPU_386DX, 2, 25000000, 1, 0, 0x0308, 0, 0, 0, 4,4,3,3}, - {"Am386DX/33", CPU_386DX, 3, 33333333, 1, 0, 0x0308, 0, 0, 0, 6,6,3,3}, - {"Am386DX/40", CPU_386DX, 4, 40000000, 1, 0, 0x0308, 0, 0, 0, 7,7,3,3}, {"", -1, 0, 0, 0} }; @@ -292,22 +325,15 @@ CPU cpus_Am386DX[] = {"", -1, 0, 0, 0} }; -CPU cpus_486SDLC[] = +CPU cpus_486SLC[] = { - /*Cx486SLC/DLC*/ + /*Cx486SLC*/ {"Cx486SLC/20", CPU_486SLC, 1, 20000000, 1, 0, 0x400, 0, 0x0000, 0, 4,4,3,3}, {"Cx486SLC/25", CPU_486SLC, 2, 25000000, 1, 0, 0x400, 0, 0x0000, 0, 4,4,3,3}, {"Cx486SLC/33", CPU_486SLC, 3, 33333333, 1, 0, 0x400, 0, 0x0000, 0, 6,6,3,3}, {"Cx486SRx2/32", CPU_486SLC, 3, 32000000, 2, 0, 0x406, 0, 0x0006, 0, 6,6,6,6}, {"Cx486SRx2/40", CPU_486SLC, 4, 40000000, 2, 0, 0x406, 0, 0x0006, 0, 8,8,6,6}, {"Cx486SRx2/50", CPU_486SLC, 5, 50000000, 2, 0, 0x406, 0, 0x0006, 0, 8,8,6,6}, - {"Cx486DLC/25", CPU_486DLC, 2, 25000000, 1, 0, 0x401, 0, 0x0001, 0, 4,4,3,3}, - {"Cx486DLC/33", CPU_486DLC, 3, 33333333, 1, 0, 0x401, 0, 0x0001, 0, 6,6,3,3}, - {"Cx486DLC/40", CPU_486DLC, 4, 40000000, 1, 0, 0x401, 0, 0x0001, 0, 7,7,3,3}, - {"Cx486DRx2/32", CPU_486DLC, 3, 32000000, 2, 0, 0x407, 0, 0x0007, 0, 6,6,6,6}, - {"Cx486DRx2/40", CPU_486DLC, 4, 40000000, 2, 0, 0x407, 0, 0x0007, 0, 8,8,6,6}, - {"Cx486DRx2/50", CPU_486DLC, 5, 50000000, 2, 0, 0x407, 0, 0x0007, 0, 8,8,6,6}, - {"Cx486DRx2/66", CPU_486DLC, 6, 66666666, 2, 0, 0x407, 0, 0x0007, 0, 12,12,6,6}, {"", -1, 0, 0, 0} }; @@ -332,6 +358,7 @@ CPU cpus_i486[] = {"i486SX/25", CPU_i486SX, 2, 25000000, 1, 25000000, 0x42a, 0, 0, CPU_SUPPORTS_DYNAREC, 4,4,3,3}, {"i486SX/33", CPU_i486SX, 3, 33333333, 1, 33333333, 0x42a, 0, 0, CPU_SUPPORTS_DYNAREC, 6,6,3,3}, {"i486SX2/50", CPU_i486SX, 5, 50000000, 2, 25000000, 0x45b, 0, 0, CPU_SUPPORTS_DYNAREC, 8,8,6,6}, + {"i486SX2/66 (Q0569)", CPU_i486SX, 6, 66666666, 2, 33333333, 0x45b, 0, 0, CPU_SUPPORTS_DYNAREC, 8,8,6,6}, {"i486DX/25", CPU_i486DX, 2, 25000000, 1, 25000000, 0x404, 0, 0, CPU_SUPPORTS_DYNAREC, 4,4,3,3}, {"i486DX/33", CPU_i486DX, 3, 33333333, 1, 33333333, 0x404, 0, 0, CPU_SUPPORTS_DYNAREC, 6,6,3,3}, {"i486DX/50", CPU_i486DX, 5, 50000000, 1, 25000000, 0x404, 0, 0, CPU_SUPPORTS_DYNAREC, 8,8,4,4}, @@ -409,7 +436,7 @@ CPU cpus_Cx486[] = {"6x86MX-PR300", CPU_Cx6x86MX, 18, 233333333, 3, 33333333, 0x600, 0x600, 0x0454, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 21,21,7,7}, {"6x86MX-PR333", CPU_Cx6x86MX, 18, 250000000, 3, 41666667, 0x600, 0x600, 0x0453, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 20,20,9,9}, {"6x86MX-PR366", CPU_Cx6x86MX, 18, 250000000, 3, 33333333, 0x600, 0x600, 0x0452, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 24,24,12,12}, - {"6x86MX-PR400", CPU_Cx6x86MX, 18, 285000000, 3, 31666667, 0x600, 0x600, 0x0453, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18,9,9}, + {"6x86MX-PR400", CPU_Cx6x86MX, 18, 285000000, 3, 41666667, 0x600, 0x600, 0x0453, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18,9,9}, {"", -1, 0, 0, 0} }; @@ -581,6 +608,8 @@ void cpu_set_edx() EDX = models[model].cpu[cpu_manufacturer].cpus[cpu].edx_reset; } +int enable_external_fpu = 0; + void cpu_set() { CPU *cpu_s; @@ -603,8 +632,8 @@ void cpu_set() is486 = (cpu_s->cpu_type >= CPU_i486SX) || (cpu_s->cpu_type == CPU_486SLC || cpu_s->cpu_type == CPU_486DLC || cpu_s->cpu_type == CPU_RAPIDCAD); is_pentium= (cpu_s->cpu_type >= CPU_WINCHIP); hasfpu = (cpu_s->cpu_type >= CPU_i486DX) || (cpu_s->cpu_type == CPU_RAPIDCAD); - cpu_iscyrix = (cpu_s->cpu_type == CPU_486SLC || cpu_s->cpu_type == CPU_486DLC || cpu_s->cpu_type == CPU_Cx486S || cpu_s->cpu_type == CPU_Cx486DX || cpu_s->cpu_type == CPU_Cx5x86 || cpu_s->cpu_type == CPU_Cx6x86 || cpu_s->cpu_type == CPU_Cx6x86MX || cpu_s->cpu_type == CPU_Cx6x86L || cpu_s->cpu_type == CPU_CxGX1); - cpu_16bitbus = cpu_16bitbus = (cpu_s->cpu_type == CPU_286 || cpu_s->cpu_type == CPU_386SX || cpu_s->cpu_type == CPU_486SLC); + cpu_iscyrix = (cpu_s->cpu_type == CPU_486SLC || cpu_s->cpu_type == CPU_486DLC || cpu_s->cpu_type == CPU_Cx486S || cpu_s->cpu_type == CPU_Cx486DX || cpu_s->cpu_type == CPU_Cx5x86 || cpu_s->cpu_type == CPU_Cx6x86 || cpu_s->cpu_type == CPU_Cx6x86MX || cpu_s->cpu_type == CPU_Cx6x86L || cpu_s->cpu_type == CPU_CxGX1); + cpu_16bitbus = (cpu_s->cpu_type == CPU_286 || cpu_s->cpu_type == CPU_386SX || cpu_s->cpu_type == CPU_486SLC); if (cpu_s->multi) cpu_busspeed = cpu_s->rspeed / cpu_s->multi; cpu_multi = cpu_s->multi; @@ -614,6 +643,14 @@ void cpu_set() cpu_hasCR4 = 0; ccr0 = ccr1 = ccr2 = ccr3 = ccr4 = ccr5 = ccr6 = 0; + if ((cpu_s->cpu_type == CPU_286) || (cpu_s->cpu_type == CPU_386SX) || (cpu_s->cpu_type == CPU_386DX) || (cpu_s->cpu_type == CPU_i486SX)) + { + if (enable_external_fpu) + { + hasfpu = 1; + } + } + cpu_update_waitstates(); isa_cycles = (int)(((int64_t)cpu_s->rspeed << ISA_CYCLES_SHIFT) / 8000000ll); @@ -720,7 +757,10 @@ void cpu_set() } memset(&msr, 0, sizeof(msr)); - + + timing_misaligned = 0; + cpu_cyrix_alignment = 0; + switch (cpu_s->cpu_type) { case CPU_8088: @@ -729,6 +769,37 @@ void cpu_set() case CPU_286: x86_setopcodes(ops_286, ops_286_0f, dynarec_ops_286, dynarec_ops_286_0f); + if (enable_external_fpu) + { + x86_dynarec_opcodes_d9_a16 = dynarec_ops_fpu_287_d9_a16; + x86_dynarec_opcodes_d9_a32 = dynarec_ops_fpu_287_d9_a32; + x86_dynarec_opcodes_da_a16 = dynarec_ops_fpu_287_da_a16; + x86_dynarec_opcodes_da_a32 = dynarec_ops_fpu_287_da_a32; + x86_dynarec_opcodes_db_a16 = dynarec_ops_fpu_287_db_a16; + x86_dynarec_opcodes_db_a32 = dynarec_ops_fpu_287_db_a32; + x86_dynarec_opcodes_dc_a16 = dynarec_ops_fpu_287_dc_a16; + x86_dynarec_opcodes_dc_a32 = dynarec_ops_fpu_287_dc_a32; + x86_dynarec_opcodes_dd_a16 = dynarec_ops_fpu_287_dd_a16; + x86_dynarec_opcodes_dd_a32 = dynarec_ops_fpu_287_dd_a32; + x86_dynarec_opcodes_de_a16 = dynarec_ops_fpu_287_de_a16; + x86_dynarec_opcodes_de_a32 = dynarec_ops_fpu_287_de_a32; + x86_dynarec_opcodes_df_a16 = dynarec_ops_fpu_287_df_a16; + x86_dynarec_opcodes_df_a32 = dynarec_ops_fpu_287_df_a32; + x86_opcodes_d9_a16 = ops_fpu_287_d9_a16; + x86_opcodes_d9_a32 = ops_fpu_287_d9_a32; + x86_opcodes_da_a16 = ops_fpu_287_da_a16; + x86_opcodes_da_a32 = ops_fpu_287_da_a32; + x86_opcodes_db_a16 = ops_fpu_287_db_a16; + x86_opcodes_db_a32 = ops_fpu_287_db_a32; + x86_opcodes_dc_a16 = ops_fpu_287_dc_a16; + x86_opcodes_dc_a32 = ops_fpu_287_dc_a32; + x86_opcodes_dd_a16 = ops_fpu_287_dd_a16; + x86_opcodes_dd_a32 = ops_fpu_287_dd_a32; + x86_opcodes_de_a16 = ops_fpu_287_de_a16; + x86_opcodes_de_a32 = ops_fpu_287_de_a32; + x86_opcodes_df_a16 = ops_fpu_287_df_a16; + x86_opcodes_df_a32 = ops_fpu_287_df_a32; + } timing_rr = 2; /*register dest - register src*/ timing_rm = 7; /*register dest - memory src*/ timing_mr = 7; /*memory dest - register src*/ @@ -883,6 +954,7 @@ void cpu_set() timing_jmp_rm = 9; timing_jmp_pm = 26; timing_jmp_pm_gate = 37; + timing_misaligned = 3; break; case CPU_486DLC: @@ -916,6 +988,7 @@ void cpu_set() timing_jmp_rm = 9; timing_jmp_pm = 26; timing_jmp_pm_gate = 37; + timing_misaligned = 3; break; case CPU_i486SX: @@ -949,6 +1022,7 @@ void cpu_set() timing_jmp_rm = 17; timing_jmp_pm = 19; timing_jmp_pm_gate = 32; + timing_misaligned = 3; break; case CPU_Am486SX: @@ -983,6 +1057,7 @@ void cpu_set() timing_jmp_rm = 17; timing_jmp_pm = 19; timing_jmp_pm_gate = 32; + timing_misaligned = 3; break; case CPU_Cx486S: @@ -1016,6 +1091,7 @@ void cpu_set() timing_jmp_rm = 9; timing_jmp_pm = 26; timing_jmp_pm_gate = 37; + timing_misaligned = 3; break; case CPU_Cx5x86: @@ -1048,6 +1124,8 @@ void cpu_set() timing_jmp_rm = 5; timing_jmp_pm = 7; timing_jmp_pm_gate = 17; + timing_misaligned = 2; + cpu_cyrix_alignment = 1; break; case CPU_WINCHIP: @@ -1086,6 +1164,8 @@ void cpu_set() timing_jmp_pm = 7; timing_jmp_pm_gate = 17; codegen_timing_set(&codegen_timing_winchip); + timing_misaligned = 2; + cpu_cyrix_alignment = 1; break; case CPU_PENTIUM: @@ -1118,6 +1198,7 @@ void cpu_set() timing_jmp_rm = 3; timing_jmp_pm = 3; timing_jmp_pm_gate = 18; + timing_misaligned = 3; cpu_hasrdtsc = 1; msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21); cpu_hasMMX = 0; @@ -1157,6 +1238,7 @@ void cpu_set() timing_jmp_rm = 3; timing_jmp_pm = 3; timing_jmp_pm_gate = 18; + timing_misaligned = 3; cpu_hasrdtsc = 1; msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21); cpu_hasMMX = 1; @@ -1195,6 +1277,8 @@ void cpu_set() timing_jmp_rm = 1; timing_jmp_pm = 4; timing_jmp_pm_gate = 14; + timing_misaligned = 2; + cpu_cyrix_alignment = 1; cpu_hasrdtsc = 1; msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21); cpu_hasMMX = 0; @@ -1233,6 +1317,8 @@ void cpu_set() timing_jmp_rm = 1; timing_jmp_pm = 4; timing_jmp_pm_gate = 14; + timing_misaligned = 2; + cpu_cyrix_alignment = 1; cpu_hasrdtsc = 1; msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21); cpu_hasMMX = 0; @@ -1254,6 +1340,8 @@ void cpu_set() timing_mml = 2; timing_bt = 5-1; /*branch taken*/ timing_bnt = 1; /*branch not taken*/ + timing_misaligned = 2; + cpu_cyrix_alignment = 1; cpu_hasrdtsc = 1; msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21); cpu_hasMMX = 0; @@ -1305,6 +1393,8 @@ void cpu_set() timing_jmp_rm = 1; timing_jmp_pm = 4; timing_jmp_pm_gate = 14; + timing_misaligned = 2; + cpu_cyrix_alignment = 1; cpu_hasrdtsc = 1; msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21); cpu_hasMMX = 1; @@ -1327,6 +1417,7 @@ void cpu_set() timing_mml = 3; timing_bt = 0; /*branch taken*/ timing_bnt = 1; /*branch not taken*/ + timing_misaligned = 3; cpu_hasrdtsc = 1; msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21); cpu_hasMMX = 1; @@ -1346,6 +1437,7 @@ void cpu_set() timing_mml = 3; timing_bt = 0; /*branch taken*/ timing_bnt = 1; /*branch not taken*/ + timing_misaligned = 3; cpu_hasrdtsc = 1; msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21); cpu_hasMMX = 1; @@ -1378,6 +1470,7 @@ void cpu_set() timing_mml = 1; timing_bt = 0; /*branch taken*/ timing_bnt = 1; /*branch not taken*/ + timing_misaligned = 3; cpu_hasrdtsc = 1; msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21); cpu_hasMMX = 0; @@ -1411,6 +1504,7 @@ void cpu_set() timing_mml = 1; timing_bt = 0; /*branch taken*/ timing_bnt = 1; /*branch not taken*/ + timing_misaligned = 3; cpu_hasrdtsc = 1; msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21); cpu_hasMMX = 1; @@ -1444,6 +1538,7 @@ void cpu_set() timing_mml = 1; timing_bt = 0; /*branch taken*/ timing_bnt = 1; /*branch not taken*/ + timing_misaligned = 3; cpu_hasrdtsc = 1; msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21); cpu_hasMMX = 1; @@ -1823,8 +1918,6 @@ void cpu_CPUID() EAX = CPUID; EBX = ECX = 0; EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B | CPUID_MMX | CPUID_SEP | CPUID_CMOV; - // EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B | CPUID_MMX | CPUID_CMOV; - // EDX = 0x0183FBFF; } else if (EAX == 2) { @@ -1849,8 +1942,6 @@ void cpu_CPUID() EAX = CPUID; EBX = ECX = 0; EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B | CPUID_MMX | CPUID_SEP | CPUID_FXSR | CPUID_CMOV; - // EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B | CPUID_MMX | CPUID_FXSR | CPUID_CMOV; - // EDX = 0x0183FBFF; } else if (EAX == 2) { @@ -1939,9 +2030,9 @@ void cpu_RDMSR() switch (ECX) { case 0x10: - EAX = tsc & 0xffffffff; - EDX = tsc >> 32; - break; + EAX = tsc & 0xffffffff; + EDX = tsc >> 32; + break; } break; case CPU_Cx6x86: @@ -1958,10 +2049,8 @@ void cpu_RDMSR() break; case CPU_PENTIUMPRO: - // case CPU_PENTIUM2: case CPU_PENTIUM2D: EAX = EDX = 0; - // pclog("RDMSR, ECX=%08X\n", ECX); switch (ECX) { case 0x10: @@ -1985,11 +2074,11 @@ void cpu_RDMSR() EAX = ecx79_msr & 0xffffffff; EDX = ecx79_msr >> 32; break; - case 0x88 ... 0x8B: + case 0x88: case 0x89: case 0x8A: case 0x8B: EAX = ecx8x_msr[ECX - 0x88] & 0xffffffff; EDX = ecx8x_msr[ECX - 0x88] >> 32; break; - case 0xC1 ... 0xC8: + case 0xC1: case 0xC2: case 0xC3: case 0xC4: case 0xC5: case 0xC6: case 0xC7: case 0xC8: EAX = msr_ia32_pmc[ECX - 0xC1] & 0xffffffff; EDX = msr_ia32_pmc[ECX - 0xC1] >> 32; break; @@ -2001,7 +2090,7 @@ void cpu_RDMSR() EAX = ecx116_msr & 0xffffffff; EDX = ecx116_msr >> 32; break; - case 0x118 ... 0x11B: + case 0x118: case 0x119: case 0x11A: case 0x11B: EAX = ecx11x_msr[ECX - 0x118] & 0xffffffff; EDX = ecx11x_msr[ECX - 0x118] >> 32; break; @@ -2034,7 +2123,8 @@ void cpu_RDMSR() EAX = ecx1e0_msr & 0xffffffff; EDX = ecx1e0_msr >> 32; break; - case 0x200 ... 0x20F: + case 0x200: case 0x201: case 0x202: case 0x203: case 0x204: case 0x205: case 0x206: case 0x207: + case 0x208: case 0x209: case 0x20A: case 0x20B: case 0x20C: case 0x20D: case 0x20E: case 0x20F: if (ECX & 1) { EAX = mtrr_physmask_msr[(ECX - 0x200) >> 1] & 0xffffffff; @@ -2058,8 +2148,7 @@ void cpu_RDMSR() EAX = mtrr_fix16k_a000_msr & 0xffffffff; EDX = mtrr_fix16k_a000_msr >> 32; break; - case 0x268 ... 0x26F: - // ((ECX - 0x268) * 0x8000) + case 0x268: case 0x269: case 0x26A: case 0x26B: case 0x26C: case 0x26D: case 0x26E: case 0x26F: EAX = mtrr_fix4k_msr[ECX - 0x268] & 0xffffffff; EDX = mtrr_fix4k_msr[ECX - 0x268] >> 32; break; @@ -2150,8 +2239,8 @@ void cpu_WRMSR() switch (ECX) { case 0x10: - tsc = EAX | ((uint64_t)EDX << 32); - break; + tsc = EAX | ((uint64_t)EDX << 32); + break; } break; case CPU_Cx6x86: @@ -2167,9 +2256,7 @@ void cpu_WRMSR() break; case CPU_PENTIUMPRO: - // case CPU_PENTIUM2: case CPU_PENTIUM2D: - // pclog("WRMSR, ECX=%08X\n", ECX); switch (ECX) { case 0x10: @@ -2185,10 +2272,10 @@ void cpu_WRMSR() case 0x79: ecx79_msr = EAX | ((uint64_t)EDX << 32); break; - case 0x88 ... 0x8B: + case 0x88: case 0x89: case 0x8A: case 0x8B: ecx8x_msr[ECX - 0x88] = EAX | ((uint64_t)EDX << 32); break; - case 0xC1 ... 0xC8: + case 0xC1: case 0xC2: case 0xC3: case 0xC4: case 0xC5: case 0xC6: case 0xC7: case 0xC8: msr_ia32_pmc[ECX - 0xC1] = EAX | ((uint64_t)EDX << 32); break; case 0xFE: @@ -2197,7 +2284,7 @@ void cpu_WRMSR() case 0x116: ecx116_msr = EAX | ((uint64_t)EDX << 32); break; - case 0x118 ... 0x011B: + case 0x118: case 0x119: case 0x11A: case 0x11B: ecx11x_msr[ECX - 0x118] = EAX | ((uint64_t)EDX << 32); break; case 0x11E: @@ -2205,17 +2292,14 @@ void cpu_WRMSR() break; case 0x174: if (models[model].cpu[cpu_manufacturer].cpus[cpu].cpu_type == CPU_PENTIUMPRO) goto i686_invalid_wrmsr; - // pclog("WRMSR SYSENTER_CS: old=%04X, new=%04X\n", cs_msr, (uint16_t) (EAX & 0xFFFF)); cs_msr = EAX & 0xFFFF; break; case 0x175: if (models[model].cpu[cpu_manufacturer].cpus[cpu].cpu_type == CPU_PENTIUMPRO) goto i686_invalid_wrmsr; - // pclog("WRMSR SYSENTER_ESP: old=%08X, new=%08X\n", esp_msr, EAX); esp_msr = EAX; break; case 0x176: if (models[model].cpu[cpu_manufacturer].cpus[cpu].cpu_type == CPU_PENTIUMPRO) goto i686_invalid_wrmsr; - // pclog("WRMSR SYSENTER_EIP: old=%08X, new=%08X\n", eip_msr, EAX); eip_msr = EAX; break; case 0x186: @@ -2227,7 +2311,8 @@ void cpu_WRMSR() case 0x1E0: ecx1e0_msr = EAX | ((uint64_t)EDX << 32); break; - case 0x200 ... 0x20F: + case 0x200: case 0x201: case 0x202: case 0x203: case 0x204: case 0x205: case 0x206: case 0x207: + case 0x208: case 0x209: case 0x20A: case 0x20B: case 0x20C: case 0x20D: case 0x20E: case 0x20F: if (ECX & 1) mtrr_physmask_msr[(ECX - 0x200) >> 1] = EAX | ((uint64_t)EDX << 32); else @@ -2242,8 +2327,7 @@ void cpu_WRMSR() case 0x259: mtrr_fix16k_a000_msr = EAX | ((uint64_t)EDX << 32); break; - case 0x268 ... 0x26F: - // ((ECX - 0x268) * 0x8000) + case 0x268: case 0x269: case 0x26A: case 0x26B: case 0x26C: case 0x26D: case 0x26E: case 0x26F: mtrr_fix4k_msr[ECX - 0x268] = EAX | ((uint64_t)EDX << 32); break; case 0x277: diff --git a/src/cpu.h b/src/CPU/cpu.h similarity index 79% rename from src/cpu.h rename to src/CPU/cpu.h index b75ee35b5..b792b36b8 100644 --- a/src/cpu.h +++ b/src/CPU/cpu.h @@ -1,6 +1,23 @@ -/* Copyright holders: Sarah Walker, Tenshi, leilei - see COPYING for more details -*/ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * CPU type handler. + * + * Version: @(#)cpu.h 1.0.0 2017/05/30 + * + * Author: Sarah Walker, + * leilei, + * Miran Grca, + * Copyright 2008-2017 Sarah Walker. + * Copyright 2016-2017 leilei. + * Copyright 2016-2017 Miran Grca. + */ + #ifndef _CPU_H_ #define _CPU_H_ @@ -65,6 +82,8 @@ extern int timing_call_rm, timing_call_pm, timing_call_pm_gate, timing_call_pm_g extern int timing_retf_rm, timing_retf_pm, timing_retf_pm_outer; extern int timing_jmp_rm, timing_jmp_pm, timing_jmp_pm_gate; +extern int timing_misaligned; + typedef struct { @@ -85,11 +104,11 @@ typedef struct extern CPU cpus_8088[]; extern CPU cpus_8086[]; extern CPU cpus_286[]; -extern CPU cpus_i386[]; +extern CPU cpus_i386SX[]; extern CPU cpus_i386DX[]; -extern CPU cpus_Am386[]; +extern CPU cpus_Am386SX[]; extern CPU cpus_Am386DX[]; -extern CPU cpus_486SDLC[]; +extern CPU cpus_486SLC[]; extern CPU cpus_486DLC[]; extern CPU cpus_i486[]; extern CPU cpus_Am486[]; @@ -107,15 +126,19 @@ extern CPU cpus_Pentium2[]; extern CPU cpus_Pentium2D[]; extern CPU cpus_pcjr[]; +extern CPU cpus_europc[]; extern CPU cpus_pc1512[]; extern CPU cpus_ibmat[]; extern CPU cpus_ps1_m2011[]; +extern CPU cpus_ps2_m30_286[]; extern CPU cpus_acer[]; extern int cpu_iscyrix; extern int cpu_16bitbus; extern int cpu_busspeed; extern int cpu_multi; +/*Cyrix 5x86/6x86 only has data misalignment penalties when crossing 8-byte boundaries*/ +extern int cpu_cyrix_alignment; extern int cpu_hasrdtsc; extern int cpu_hasMSR; @@ -132,12 +155,12 @@ extern uint64_t cpu_CR4_mask; #define CPU_SUPPORTS_DYNAREC 1 #define CPU_REQUIRES_DYNAREC 2 -// #define CPU_REQUIRES_DYNAREC 0 extern int cpu_cycles_read, cpu_cycles_read_l, cpu_cycles_write, cpu_cycles_write_l; extern int cpu_prefetch_cycles, cpu_prefetch_width; extern int cpu_waitstates; extern int cpu_cache_int_enabled, cpu_cache_ext_enabled; +extern int cpu_pci_speed; extern uint64_t tsc; @@ -160,5 +183,6 @@ extern int isa_cycles; #define ISA_CYCLES(x) ((x * isa_cycles) >> ISA_CYCLES_SHIFT) void cpu_update_waitstates(); +void cpu_set(); #endif diff --git a/src/x86.h b/src/CPU/x86.h similarity index 97% rename from src/x86.h rename to src/CPU/x86.h index 565d52591..deb210cb6 100644 --- a/src/x86.h +++ b/src/CPU/x86.h @@ -102,3 +102,6 @@ void x86gpf(char *s, uint16_t error); extern uint16_t zero; extern int x86_was_reset; + +extern int codegen_flat_ds; +extern int codegen_flat_ss; diff --git a/src/x86_flags.h b/src/CPU/x86_flags.h similarity index 90% rename from src/x86_flags.h rename to src/CPU/x86_flags.h index f1a394e61..dab54dbf6 100644 --- a/src/x86_flags.h +++ b/src/CPU/x86_flags.h @@ -35,10 +35,10 @@ enum FLAGS_DEC8, FLAGS_DEC16, - FLAGS_DEC32, + FLAGS_DEC32 }; -static inline int ZF_SET() +static __inline int ZF_SET() { switch (cpu_state.flags_op) { @@ -70,10 +70,13 @@ static inline int ZF_SET() case FLAGS_UNKNOWN: return flags & Z_FLAG; + + default: + return 0; } } -static inline int NF_SET() +static __inline int NF_SET() { switch (cpu_state.flags_op) { @@ -109,10 +112,13 @@ static inline int NF_SET() case FLAGS_UNKNOWN: return flags & N_FLAG; + + default: + return 0; } } -static inline int PF_SET() +static __inline int PF_SET() { switch (cpu_state.flags_op) { @@ -144,10 +150,13 @@ static inline int PF_SET() case FLAGS_UNKNOWN: return flags & P_FLAG; + + default: + return 0; } } -static inline int VF_SET() +static __inline int VF_SET() { switch (cpu_state.flags_op) { @@ -195,10 +204,13 @@ static inline int VF_SET() case FLAGS_UNKNOWN: return flags & V_FLAG; + + default: + return 0; } } -static inline int AF_SET() +static __inline int AF_SET() { switch (cpu_state.flags_op) { @@ -234,10 +246,13 @@ static inline int AF_SET() case FLAGS_UNKNOWN: return flags & A_FLAG; + + default: + return 0; } } -static inline int CF_SET() +static __inline int CF_SET() { switch (cpu_state.flags_op) { @@ -285,17 +300,13 @@ static inline int CF_SET() case FLAGS_INC32: case FLAGS_UNKNOWN: return flags & C_FLAG; + + default: + return 0; } } -//#define ZF_SET() (flags & Z_FLAG) -//#define NF_SET() (flags & N_FLAG) -//#define PF_SET() (flags & P_FLAG) -//#define VF_SET() (flags & V_FLAG) -//#define CF_SET() (flags & C_FLAG) -//#define AF_SET() (flags & A_FLAG) - -static inline void flags_rebuild() +static __inline void flags_rebuild() { if (cpu_state.flags_op != FLAGS_UNKNOWN) { @@ -311,12 +322,12 @@ static inline void flags_rebuild() } } -static inline void flags_extract() +static __inline void flags_extract() { cpu_state.flags_op = FLAGS_UNKNOWN; } -static inline void flags_rebuild_c() +static __inline void flags_rebuild_c() { if (cpu_state.flags_op != FLAGS_UNKNOWN) { @@ -327,17 +338,17 @@ static inline void flags_rebuild_c() } } -static inline void setznp8(uint8_t val) +static __inline void setznp8(uint8_t val) { cpu_state.flags_op = FLAGS_ZN8; cpu_state.flags_res = val; } -static inline void setznp16(uint16_t val) +static __inline void setznp16(uint16_t val) { cpu_state.flags_op = FLAGS_ZN16; cpu_state.flags_res = val; } -static inline void setznp32(uint32_t val) +static __inline void setznp32(uint32_t val) { cpu_state.flags_op = FLAGS_ZN32; cpu_state.flags_res = val; @@ -349,28 +360,28 @@ static inline void setznp32(uint32_t val) cpu_state.flags_op1 = orig; \ cpu_state.flags_op2 = shift; -static inline void setadd8(uint8_t a, uint8_t b) +static __inline void setadd8(uint8_t a, uint8_t b) { cpu_state.flags_op1 = a; cpu_state.flags_op2 = b; cpu_state.flags_res = (a + b) & 0xff; cpu_state.flags_op = FLAGS_ADD8; } -static inline void setadd16(uint16_t a, uint16_t b) +static __inline void setadd16(uint16_t a, uint16_t b) { cpu_state.flags_op1 = a; cpu_state.flags_op2 = b; cpu_state.flags_res = (a + b) & 0xffff; cpu_state.flags_op = FLAGS_ADD16; } -static inline void setadd32(uint32_t a, uint32_t b) +static __inline void setadd32(uint32_t a, uint32_t b) { cpu_state.flags_op1 = a; cpu_state.flags_op2 = b; cpu_state.flags_res = a + b; cpu_state.flags_op = FLAGS_ADD32; } -static inline void setadd8nc(uint8_t a, uint8_t b) +static __inline void setadd8nc(uint8_t a, uint8_t b) { flags_rebuild_c(); cpu_state.flags_op1 = a; @@ -378,7 +389,7 @@ static inline void setadd8nc(uint8_t a, uint8_t b) cpu_state.flags_res = (a + b) & 0xff; cpu_state.flags_op = FLAGS_INC8; } -static inline void setadd16nc(uint16_t a, uint16_t b) +static __inline void setadd16nc(uint16_t a, uint16_t b) { flags_rebuild_c(); cpu_state.flags_op1 = a; @@ -386,7 +397,7 @@ static inline void setadd16nc(uint16_t a, uint16_t b) cpu_state.flags_res = (a + b) & 0xffff; cpu_state.flags_op = FLAGS_INC16; } -static inline void setadd32nc(uint32_t a, uint32_t b) +static __inline void setadd32nc(uint32_t a, uint32_t b) { flags_rebuild_c(); cpu_state.flags_op1 = a; @@ -395,21 +406,21 @@ static inline void setadd32nc(uint32_t a, uint32_t b) cpu_state.flags_op = FLAGS_INC32; } -static inline void setsub8(uint8_t a, uint8_t b) +static __inline void setsub8(uint8_t a, uint8_t b) { cpu_state.flags_op1 = a; cpu_state.flags_op2 = b; cpu_state.flags_res = (a - b) & 0xff; cpu_state.flags_op = FLAGS_SUB8; } -static inline void setsub16(uint16_t a, uint16_t b) +static __inline void setsub16(uint16_t a, uint16_t b) { cpu_state.flags_op1 = a; cpu_state.flags_op2 = b; cpu_state.flags_res = (a - b) & 0xffff; cpu_state.flags_op = FLAGS_SUB16; } -static inline void setsub32(uint32_t a, uint32_t b) +static __inline void setsub32(uint32_t a, uint32_t b) { cpu_state.flags_op1 = a; cpu_state.flags_op2 = b; @@ -417,7 +428,7 @@ static inline void setsub32(uint32_t a, uint32_t b) cpu_state.flags_op = FLAGS_SUB32; } -static inline void setsub8nc(uint8_t a, uint8_t b) +static __inline void setsub8nc(uint8_t a, uint8_t b) { flags_rebuild_c(); cpu_state.flags_op1 = a; @@ -425,7 +436,7 @@ static inline void setsub8nc(uint8_t a, uint8_t b) cpu_state.flags_res = (a - b) & 0xff; cpu_state.flags_op = FLAGS_DEC8; } -static inline void setsub16nc(uint16_t a, uint16_t b) +static __inline void setsub16nc(uint16_t a, uint16_t b) { flags_rebuild_c(); cpu_state.flags_op1 = a; @@ -433,7 +444,7 @@ static inline void setsub16nc(uint16_t a, uint16_t b) cpu_state.flags_res = (a - b) & 0xffff; cpu_state.flags_op = FLAGS_DEC16; } -static inline void setsub32nc(uint32_t a, uint32_t b) +static __inline void setsub32nc(uint32_t a, uint32_t b) { flags_rebuild_c(); cpu_state.flags_op1 = a; @@ -442,7 +453,7 @@ static inline void setsub32nc(uint32_t a, uint32_t b) cpu_state.flags_op = FLAGS_DEC32; } -static inline void setadc8(uint8_t a, uint8_t b) +static __inline void setadc8(uint8_t a, uint8_t b) { uint16_t c=(uint16_t)a+(uint16_t)b+tempc; cpu_state.flags_op = FLAGS_UNKNOWN; @@ -452,7 +463,7 @@ static inline void setadc8(uint8_t a, uint8_t b) if (!((a^b)&0x80)&&((a^c)&0x80)) flags|=V_FLAG; if (((a&0xF)+(b&0xF))&0x10) flags|=A_FLAG; } -static inline void setadc16(uint16_t a, uint16_t b) +static __inline void setadc16(uint16_t a, uint16_t b) { uint32_t c=(uint32_t)a+(uint32_t)b+tempc; cpu_state.flags_op = FLAGS_UNKNOWN; @@ -463,7 +474,7 @@ static inline void setadc16(uint16_t a, uint16_t b) if (((a&0xF)+(b&0xF))&0x10) flags|=A_FLAG; } -static inline void setsbc8(uint8_t a, uint8_t b) +static __inline void setsbc8(uint8_t a, uint8_t b) { uint16_t c=(uint16_t)a-(((uint16_t)b)+tempc); cpu_state.flags_op = FLAGS_UNKNOWN; @@ -473,7 +484,7 @@ static inline void setsbc8(uint8_t a, uint8_t b) if ((a^b)&(a^c)&0x80) flags|=V_FLAG; if (((a&0xF)-(b&0xF))&0x10) flags|=A_FLAG; } -static inline void setsbc16(uint16_t a, uint16_t b) +static __inline void setsbc16(uint16_t a, uint16_t b) { uint32_t c=(uint32_t)a-(((uint32_t)b)+tempc); cpu_state.flags_op = FLAGS_UNKNOWN; @@ -485,7 +496,7 @@ static inline void setsbc16(uint16_t a, uint16_t b) if (((a&0xF)-(b&0xF))&0x10) flags|=A_FLAG; } -static inline void setadc32(uint32_t a, uint32_t b) +static __inline void setadc32(uint32_t a, uint32_t b) { uint32_t c=(uint32_t)a+(uint32_t)b+tempc; cpu_state.flags_op = FLAGS_UNKNOWN; @@ -496,7 +507,7 @@ static inline void setadc32(uint32_t a, uint32_t b) if (!((a^b)&0x80000000)&&((a^c)&0x80000000)) flags|=V_FLAG; if (((a&0xF)+(b&0xF)+tempc)&0x10) flags|=A_FLAG; } -static inline void setsbc32(uint32_t a, uint32_t b) +static __inline void setsbc32(uint32_t a, uint32_t b) { uint32_t c=(uint32_t)a-(((uint32_t)b)+tempc); cpu_state.flags_op = FLAGS_UNKNOWN; diff --git a/src/x86_ops.h b/src/CPU/x86_ops.h similarity index 78% rename from src/x86_ops.h rename to src/CPU/x86_ops.h index efaf7b717..389420921 100644 --- a/src/x86_ops.h +++ b/src/CPU/x86_ops.h @@ -46,6 +46,21 @@ extern OpFn dynarec_ops_k6_0f[1024]; extern OpFn dynarec_ops_pentiumpro_0f[1024]; extern OpFn dynarec_ops_pentium2d_0f[1024]; +extern OpFn dynarec_ops_fpu_287_d9_a16[256]; +extern OpFn dynarec_ops_fpu_287_d9_a32[256]; +extern OpFn dynarec_ops_fpu_287_da_a16[256]; +extern OpFn dynarec_ops_fpu_287_da_a32[256]; +extern OpFn dynarec_ops_fpu_287_db_a16[256]; +extern OpFn dynarec_ops_fpu_287_db_a32[256]; +extern OpFn dynarec_ops_fpu_287_dc_a16[32]; +extern OpFn dynarec_ops_fpu_287_dc_a32[32]; +extern OpFn dynarec_ops_fpu_287_dd_a16[256]; +extern OpFn dynarec_ops_fpu_287_dd_a32[256]; +extern OpFn dynarec_ops_fpu_287_de_a16[256]; +extern OpFn dynarec_ops_fpu_287_de_a32[256]; +extern OpFn dynarec_ops_fpu_287_df_a16[256]; +extern OpFn dynarec_ops_fpu_287_df_a32[256]; + extern OpFn dynarec_ops_fpu_d8_a16[32]; extern OpFn dynarec_ops_fpu_d8_a32[32]; extern OpFn dynarec_ops_fpu_d9_a16[256]; @@ -111,6 +126,21 @@ extern OpFn ops_k6_0f[1024]; extern OpFn ops_pentiumpro_0f[1024]; extern OpFn ops_pentium2d_0f[1024]; +extern OpFn ops_fpu_287_d9_a16[256]; +extern OpFn ops_fpu_287_d9_a32[256]; +extern OpFn ops_fpu_287_da_a16[256]; +extern OpFn ops_fpu_287_da_a32[256]; +extern OpFn ops_fpu_287_db_a16[256]; +extern OpFn ops_fpu_287_db_a32[256]; +extern OpFn ops_fpu_287_dc_a16[32]; +extern OpFn ops_fpu_287_dc_a32[32]; +extern OpFn ops_fpu_287_dd_a16[256]; +extern OpFn ops_fpu_287_dd_a32[256]; +extern OpFn ops_fpu_287_de_a16[256]; +extern OpFn ops_fpu_287_de_a32[256]; +extern OpFn ops_fpu_287_df_a16[256]; +extern OpFn ops_fpu_287_df_a32[256]; + extern OpFn ops_fpu_d8_a16[32]; extern OpFn ops_fpu_d8_a32[32]; extern OpFn ops_fpu_d9_a16[256]; diff --git a/src/x86_ops_arith.h b/src/CPU/x86_ops_arith.h similarity index 94% rename from src/x86_ops_arith.h rename to src/CPU/x86_ops_arith.h index 3a9f96953..3c6b67fa6 100644 --- a/src/x86_ops_arith.h +++ b/src/CPU/x86_ops_arith.h @@ -1,12 +1,14 @@ #define OP_ARITH(name, operation, setflags, flagops, gettempc) \ static int op ## name ## _b_rmw_a16(uint32_t fetchdat) \ { \ + uint8_t dst; \ + uint8_t src; \ if (gettempc) tempc = CF_SET() ? 1 : 0; \ fetch_ea_16(fetchdat); \ if (cpu_mod == 3) \ { \ - uint8_t dst = getr8(cpu_rm); \ - uint8_t src = getr8(cpu_reg); \ + dst = getr8(cpu_rm); \ + src = getr8(cpu_reg); \ setflags ## 8 flagops; \ setr8(cpu_rm, operation); \ CLOCK_CYCLES(timing_rr); \ @@ -14,8 +16,8 @@ } \ else \ { \ - uint8_t dst = geteab(); if (cpu_state.abrt) return 1; \ - uint8_t src = getr8(cpu_reg); \ + dst = geteab(); if (cpu_state.abrt) return 1; \ + src = getr8(cpu_reg); \ seteab(operation); if (cpu_state.abrt) return 1; \ setflags ## 8 flagops; \ CLOCK_CYCLES(timing_mr); \ @@ -25,12 +27,14 @@ } \ static int op ## name ## _b_rmw_a32(uint32_t fetchdat) \ { \ + uint8_t dst; \ + uint8_t src; \ if (gettempc) tempc = CF_SET() ? 1 : 0; \ fetch_ea_32(fetchdat); \ if (cpu_mod == 3) \ { \ - uint8_t dst = getr8(cpu_rm); \ - uint8_t src = getr8(cpu_reg); \ + dst = getr8(cpu_rm); \ + src = getr8(cpu_reg); \ setflags ## 8 flagops; \ setr8(cpu_rm, operation); \ CLOCK_CYCLES(timing_rr); \ @@ -38,8 +42,8 @@ } \ else \ { \ - uint8_t dst = geteab(); if (cpu_state.abrt) return 1; \ - uint8_t src = getr8(cpu_reg); \ + dst = geteab(); if (cpu_state.abrt) return 1; \ + src = getr8(cpu_reg); \ seteab(operation); if (cpu_state.abrt) return 1; \ setflags ## 8 flagops; \ CLOCK_CYCLES(timing_mr); \ @@ -50,12 +54,14 @@ \ static int op ## name ## _w_rmw_a16(uint32_t fetchdat) \ { \ + uint16_t dst; \ + uint16_t src; \ if (gettempc) tempc = CF_SET() ? 1 : 0; \ fetch_ea_16(fetchdat); \ if (cpu_mod == 3) \ { \ - uint16_t dst = cpu_state.regs[cpu_rm].w; \ - uint16_t src = cpu_state.regs[cpu_reg].w; \ + dst = cpu_state.regs[cpu_rm].w; \ + src = cpu_state.regs[cpu_reg].w; \ setflags ## 16 flagops; \ cpu_state.regs[cpu_rm].w = operation; \ CLOCK_CYCLES(timing_rr); \ @@ -63,8 +69,8 @@ } \ else \ { \ - uint16_t dst = geteaw(); if (cpu_state.abrt) return 1; \ - uint16_t src = cpu_state.regs[cpu_reg].w; \ + dst = geteaw(); if (cpu_state.abrt) return 1; \ + src = cpu_state.regs[cpu_reg].w; \ seteaw(operation); if (cpu_state.abrt) return 1; \ setflags ## 16 flagops; \ CLOCK_CYCLES(timing_mr); \ @@ -74,12 +80,14 @@ } \ static int op ## name ## _w_rmw_a32(uint32_t fetchdat) \ { \ + uint16_t dst; \ + uint16_t src; \ if (gettempc) tempc = CF_SET() ? 1 : 0; \ fetch_ea_32(fetchdat); \ if (cpu_mod == 3) \ { \ - uint16_t dst = cpu_state.regs[cpu_rm].w; \ - uint16_t src = cpu_state.regs[cpu_reg].w; \ + dst = cpu_state.regs[cpu_rm].w; \ + src = cpu_state.regs[cpu_reg].w; \ setflags ## 16 flagops; \ cpu_state.regs[cpu_rm].w = operation; \ CLOCK_CYCLES(timing_rr); \ @@ -87,8 +95,8 @@ } \ else \ { \ - uint16_t dst = geteaw(); if (cpu_state.abrt) return 1; \ - uint16_t src = cpu_state.regs[cpu_reg].w; \ + dst = geteaw(); if (cpu_state.abrt) return 1; \ + src = cpu_state.regs[cpu_reg].w; \ seteaw(operation); if (cpu_state.abrt) return 1; \ setflags ## 16 flagops; \ CLOCK_CYCLES(timing_mr); \ @@ -99,12 +107,14 @@ \ static int op ## name ## _l_rmw_a16(uint32_t fetchdat) \ { \ + uint32_t dst; \ + uint32_t src; \ if (gettempc) tempc = CF_SET() ? 1 : 0; \ fetch_ea_16(fetchdat); \ if (cpu_mod == 3) \ { \ - uint32_t dst = cpu_state.regs[cpu_rm].l; \ - uint32_t src = cpu_state.regs[cpu_reg].l; \ + dst = cpu_state.regs[cpu_rm].l; \ + src = cpu_state.regs[cpu_reg].l; \ setflags ## 32 flagops; \ cpu_state.regs[cpu_rm].l = operation; \ CLOCK_CYCLES(timing_rr); \ @@ -112,8 +122,8 @@ } \ else \ { \ - uint32_t dst = geteal(); if (cpu_state.abrt) return 1; \ - uint32_t src = cpu_state.regs[cpu_reg].l; \ + dst = geteal(); if (cpu_state.abrt) return 1; \ + src = cpu_state.regs[cpu_reg].l; \ seteal(operation); if (cpu_state.abrt) return 1; \ setflags ## 32 flagops; \ CLOCK_CYCLES(timing_mr); \ @@ -123,12 +133,14 @@ } \ static int op ## name ## _l_rmw_a32(uint32_t fetchdat) \ { \ + uint32_t dst; \ + uint32_t src; \ if (gettempc) tempc = CF_SET() ? 1 : 0; \ fetch_ea_32(fetchdat); \ if (cpu_mod == 3) \ { \ - uint32_t dst = cpu_state.regs[cpu_rm].l; \ - uint32_t src = cpu_state.regs[cpu_reg].l; \ + dst = cpu_state.regs[cpu_rm].l; \ + src = cpu_state.regs[cpu_reg].l; \ setflags ## 32 flagops; \ cpu_state.regs[cpu_rm].l = operation; \ CLOCK_CYCLES(timing_rr); \ @@ -136,8 +148,8 @@ } \ else \ { \ - uint32_t dst = geteal(); if (cpu_state.abrt) return 1; \ - uint32_t src = cpu_state.regs[cpu_reg].l; \ + dst = geteal(); if (cpu_state.abrt) return 1; \ + src = cpu_state.regs[cpu_reg].l; \ seteal(operation); if (cpu_state.abrt) return 1; \ setflags ## 32 flagops; \ CLOCK_CYCLES(timing_mr); \ diff --git a/src/x86_ops_atomic.h b/src/CPU/x86_ops_atomic.h similarity index 100% rename from src/x86_ops_atomic.h rename to src/CPU/x86_ops_atomic.h diff --git a/src/x86_ops_bcd.h b/src/CPU/x86_ops_bcd.h similarity index 100% rename from src/x86_ops_bcd.h rename to src/CPU/x86_ops_bcd.h diff --git a/src/x86_ops_bit.h b/src/CPU/x86_ops_bit.h similarity index 100% rename from src/x86_ops_bit.h rename to src/CPU/x86_ops_bit.h diff --git a/src/x86_ops_bitscan.h b/src/CPU/x86_ops_bitscan.h similarity index 94% rename from src/x86_ops_bitscan.h rename to src/CPU/x86_ops_bitscan.h index 834211128..9252b4b87 100644 --- a/src/x86_ops_bitscan.h +++ b/src/CPU/x86_ops_bitscan.h @@ -1,5 +1,6 @@ #define BS_common(start, end, dir, dest, time) \ flags_rebuild(); \ + instr_cycles = 0; \ if (temp) \ { \ int c; \ @@ -21,7 +22,7 @@ static int opBSF_w_a16(uint32_t fetchdat) { uint16_t temp; - int instr_cycles; + int instr_cycles = 0; fetch_ea_16(fetchdat); temp = geteaw(); if (cpu_state.abrt) return 1; @@ -36,7 +37,7 @@ static int opBSF_w_a16(uint32_t fetchdat) static int opBSF_w_a32(uint32_t fetchdat) { uint16_t temp; - int instr_cycles; + int instr_cycles = 0; fetch_ea_32(fetchdat); temp = geteaw(); if (cpu_state.abrt) return 1; @@ -51,7 +52,7 @@ static int opBSF_w_a32(uint32_t fetchdat) static int opBSF_l_a16(uint32_t fetchdat) { uint32_t temp; - int instr_cycles; + int instr_cycles = 0; fetch_ea_16(fetchdat); temp = geteal(); if (cpu_state.abrt) return 1; @@ -66,7 +67,7 @@ static int opBSF_l_a16(uint32_t fetchdat) static int opBSF_l_a32(uint32_t fetchdat) { uint32_t temp; - int instr_cycles; + int instr_cycles = 0; fetch_ea_32(fetchdat); temp = geteal(); if (cpu_state.abrt) return 1; @@ -82,7 +83,7 @@ static int opBSF_l_a32(uint32_t fetchdat) static int opBSR_w_a16(uint32_t fetchdat) { uint16_t temp; - int instr_cycles; + int instr_cycles = 0; fetch_ea_16(fetchdat); temp = geteaw(); if (cpu_state.abrt) return 1; @@ -97,7 +98,7 @@ static int opBSR_w_a16(uint32_t fetchdat) static int opBSR_w_a32(uint32_t fetchdat) { uint16_t temp; - int instr_cycles; + int instr_cycles = 0; fetch_ea_32(fetchdat); temp = geteaw(); if (cpu_state.abrt) return 1; @@ -112,7 +113,7 @@ static int opBSR_w_a32(uint32_t fetchdat) static int opBSR_l_a16(uint32_t fetchdat) { uint32_t temp; - int instr_cycles; + int instr_cycles = 0; fetch_ea_16(fetchdat); temp = geteal(); if (cpu_state.abrt) return 1; @@ -127,7 +128,7 @@ static int opBSR_l_a16(uint32_t fetchdat) static int opBSR_l_a32(uint32_t fetchdat) { uint32_t temp; - int instr_cycles; + int instr_cycles = 0; fetch_ea_32(fetchdat); temp = geteal(); if (cpu_state.abrt) return 1; diff --git a/src/x86_ops_call.h b/src/CPU/x86_ops_call.h similarity index 98% rename from src/x86_ops_call.h rename to src/CPU/x86_ops_call.h index 40d90a09e..d1f61021c 100644 --- a/src/x86_ops_call.h +++ b/src/CPU/x86_ops_call.h @@ -61,7 +61,7 @@ static int opCALL_far_w(uint32_t fetchdat) { uint32_t old_cs, old_pc; uint16_t new_cs, new_pc; - int cycles_old = cycles; + int cycles_old = cycles; UNUSED(cycles_old); new_pc = getwordf(); new_cs = getword(); if (cpu_state.abrt) return 1; @@ -77,7 +77,7 @@ static int opCALL_far_l(uint32_t fetchdat) { uint32_t old_cs, old_pc; uint32_t new_cs, new_pc; - int cycles_old = cycles; + int cycles_old = cycles; UNUSED(cycles_old); new_pc = getlong(); new_cs = getword(); if (cpu_state.abrt) return 1; @@ -95,7 +95,7 @@ static int opFF_w_a16(uint32_t fetchdat) { uint16_t old_cs, new_cs; uint32_t old_pc, new_pc; - int cycles_old = cycles; + int cycles_old = cycles; UNUSED(cycles_old); uint16_t temp; @@ -172,7 +172,7 @@ static int opFF_w_a32(uint32_t fetchdat) { uint16_t old_cs, new_cs; uint32_t old_pc, new_pc; - int cycles_old = cycles; + int cycles_old = cycles; UNUSED(cycles_old); uint16_t temp; @@ -250,7 +250,7 @@ static int opFF_l_a16(uint32_t fetchdat) { uint16_t old_cs, new_cs; uint32_t old_pc, new_pc; - int cycles_old = cycles; + int cycles_old = cycles; UNUSED(cycles_old); uint32_t temp; @@ -327,7 +327,7 @@ static int opFF_l_a32(uint32_t fetchdat) { uint16_t old_cs, new_cs; uint32_t old_pc, new_pc; - int cycles_old = cycles; + int cycles_old = cycles; UNUSED(cycles_old); uint32_t temp; diff --git a/src/x86_ops_flag.h b/src/CPU/x86_ops_flag.h similarity index 100% rename from src/x86_ops_flag.h rename to src/CPU/x86_ops_flag.h diff --git a/src/x86_ops_fpu.h b/src/CPU/x86_ops_fpu.h similarity index 100% rename from src/x86_ops_fpu.h rename to src/CPU/x86_ops_fpu.h diff --git a/src/x86_ops_i686.h b/src/CPU/x86_ops_i686.h similarity index 91% rename from src/x86_ops_i686.h rename to src/CPU/x86_ops_i686.h index 9afb0e5f0..a61d27025 100644 --- a/src/x86_ops_i686.h +++ b/src/CPU/x86_ops_i686.h @@ -1,6 +1,19 @@ -/* Copyright holders: Sarah Walker, Tenshi - see COPYING for more details -*/ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * x86 i686 (Pentium Pro/Pentium II) CPU Instructions. + * + * Version: @(#)x86_ops_i686.h 1.0.0 2017/05/30 + * + * Author: Miran Grca, + * Copyright 2016-2017 Miran Grca. + */ + static int internal_illegal(char *s) { cpu_state.pc = cpu_state.oldpc; @@ -33,16 +46,20 @@ static int opSYSENTER(uint32_t fetchdat) uint16_t sysenter_cs_seg_data[4]; uint16_t sysenter_ss_seg_data[4]; +#ifdef SYSENTER_LOG pclog("SYSENTER called\n"); +#endif if (!(cr0 & 1)) return internal_illegal("SYSENTER: CPU not in protected mode"); if (!(cs_msr & 0xFFFC)) return internal_illegal("SYSENTER: CS MSR is zero"); +#ifdef SYSENTER_LOG pclog("SYSENTER started:\n"); pclog("CS (%04X): base=%08X, limit=%08X, access=%02X, seg=%04X, limit_low=%08X, limit_high=%08X, checked=%i\n", CS, _cs.base, _cs.limit, _cs.access, _cs.seg, _cs.limit_low, _cs.limit_high, _cs.checked); pclog("SS (%04X): base=%08X, limit=%08X, access=%02X, seg=%04X, limit_low=%08X, limit_high=%08X, checked=%i\n", SS, _ss.base, _ss.limit, _ss.access, _ss.seg, _ss.limit_low, _ss.limit_high, _ss.checked); pclog("Model specific registers: cs_msr=%04X, esp_msr=%08X, eip_msr=%08X\n", cs_msr, esp_msr, eip_msr); pclog("Other information: eip=%08X esp=%08X eflags=%04X flags=%04X use32=%04X stack32=%i\n", cpu_state.pc, ESP, eflags, flags, use32, stack32); +#endif if (cpu_state.abrt) return 1; @@ -72,11 +89,13 @@ static int opSYSENTER(uint32_t fetchdat) CPU_BLOCK_END(); +#ifdef SYSENTER_LOG pclog("SYSENTER completed:\n"); pclog("CS (%04X): base=%08X, limit=%08X, access=%02X, seg=%04X, limit_low=%08X, limit_high=%08X, checked=%i\n", CS, _cs.base, _cs.limit, _cs.access, _cs.seg, _cs.limit_low, _cs.limit_high, _cs.checked); pclog("SS (%04X): base=%08X, limit=%08X, access=%02X, seg=%04X, limit_low=%08X, limit_high=%08X, checked=%i\n", SS, _ss.base, _ss.limit, _ss.access, _ss.seg, _ss.limit_low, _ss.limit_high, _ss.checked); pclog("Model specific registers: cs_msr=%04X, esp_msr=%08X, eip_msr=%08X\n", cs_msr, esp_msr, eip_msr); pclog("Other information: eip=%08X esp=%08X eflags=%04X flags=%04X use32=%04X stack32=%i\n", cpu_state.pc, ESP, eflags, flags, use32, stack32); +#endif return 0; } @@ -86,17 +105,21 @@ static int opSYSEXIT(uint32_t fetchdat) uint16_t sysexit_cs_seg_data[4]; uint16_t sysexit_ss_seg_data[4]; +#ifdef SYSEXIT_LOG pclog("SYSEXIT called\n"); +#endif if (!(cs_msr & 0xFFFC)) return internal_illegal("SYSEXIT: CS MSR is zero"); if (!(cr0 & 1)) return internal_illegal("SYSEXIT: CPU not in protected mode"); if (CS & 3) return internal_illegal("SYSEXIT: CPL not 0"); +#ifdef SYSEXIT_LOG pclog("SYSEXIT start:\n"); pclog("CS (%04X): base=%08X, limit=%08X, access=%02X, seg=%04X, limit_low=%08X, limit_high=%08X, checked=%i\n", CS, _cs.base, _cs.limit, _cs.access, _cs.seg, _cs.limit_low, _cs.limit_high, _cs.checked); pclog("SS (%04X): base=%08X, limit=%08X, access=%02X, seg=%04X, limit_low=%08X, limit_high=%08X, checked=%i\n", SS, _ss.base, _ss.limit, _ss.access, _ss.seg, _ss.limit_low, _ss.limit_high, _ss.checked); pclog("Model specific registers: cs_msr=%04X, esp_msr=%08X, eip_msr=%08X\n", cs_msr, esp_msr, eip_msr); pclog("Other information: eip=%08X esp=%08X eflags=%04X flags=%04X use32=%04X stack32=%i ECX=%08X EDX=%08X\n", cpu_state.pc, ESP, eflags, flags, use32, stack32, ECX, EDX); +#endif if (cpu_state.abrt) return 1; @@ -124,11 +147,13 @@ static int opSYSEXIT(uint32_t fetchdat) CPU_BLOCK_END(); +#ifdef SYSEXIT_LOG pclog("SYSEXIT completed:\n"); pclog("CS (%04X): base=%08X, limit=%08X, access=%02X, seg=%04X, limit_low=%08X, limit_high=%08X, checked=%i\n", CS, _cs.base, _cs.limit, _cs.access, _cs.seg, _cs.limit_low, _cs.limit_high, _cs.checked); pclog("SS (%04X): base=%08X, limit=%08X, access=%02X, seg=%04X, limit_low=%08X, limit_high=%08X, checked=%i\n", SS, _ss.base, _ss.limit, _ss.access, _ss.seg, _ss.limit_low, _ss.limit_high, _ss.checked); pclog("Model specific registers: cs_msr=%04X, esp_msr=%08X, eip_msr=%08X\n", cs_msr, esp_msr, eip_msr); pclog("Other information: eip=%08X esp=%08X eflags=%04X flags=%04X use32=%04X stack32=%i ECX=%08X EDX=%08X\n", cpu_state.pc, ESP, eflags, flags, use32, stack32, ECX, EDX); +#endif return 0; } @@ -138,10 +163,10 @@ static int opFXSAVESTOR_a16(uint32_t fetchdat) uint8_t fxinst = 0; uint16_t twd = x87_gettag(); uint16_t old_eaaddr = 0; - int old_ismmx = cpu_state.ismmx; uint8_t ftwb = 0; uint16_t rec_ftw = 0; uint16_t fpus = 0; + uint64_t *p; if (CPUID < 0x650) return ILLEGAL(fetchdat); @@ -160,9 +185,6 @@ static int opFXSAVESTOR_a16(uint32_t fetchdat) if ((fxinst > 1) || (cpu_mod == 3)) { - // if (fxinst > 1) pclog("FX instruction is: %02X\n", fxinst); - // if (cpu_mod == 3) pclog("MOD is 3\n"); - x86illegal(); return cpu_state.abrt; } @@ -174,8 +196,6 @@ static int opFXSAVESTOR_a16(uint32_t fetchdat) if (fxinst == 1) { /* FXRSTOR */ - // pclog("FXRSTOR issued\n"); - cpu_state.npxc = readmemw(easeg, cpu_state.eaaddr); fpus = readmemw(easeg, cpu_state.eaaddr + 2); cpu_state.npxc = (cpu_state.npxc & ~FPU_CW_Reserved_Bits) | 0x0040; @@ -239,10 +259,11 @@ static int opFXSAVESTOR_a16(uint32_t fetchdat) cpu_state.ismmx = 0; /*Horrible hack, but as PCem doesn't keep the FPU stack in 80-bit precision at all times something like this is needed*/ - if (cpu_state.MM[0].w[4] == 0xffff && cpu_state.MM[1].w[4] == 0xffff && cpu_state.MM[2].w[4] == 0xffff && cpu_state.MM[3].w[4] == 0xffff && - cpu_state.MM[4].w[4] == 0xffff && cpu_state.MM[5].w[4] == 0xffff && cpu_state.MM[6].w[4] == 0xffff && cpu_state.MM[7].w[4] == 0xffff && - !cpu_state.TOP && !(*(uint64_t *)cpu_state.tag)) - cpu_state.ismmx = old_ismmx; + p = (uint64_t *)cpu_state.tag; + if (cpu_state.MM_w4[0] == 0xffff && cpu_state.MM_w4[1] == 0xffff && cpu_state.MM_w4[2] == 0xffff && cpu_state.MM_w4[3] == 0xffff && + cpu_state.MM_w4[4] == 0xffff && cpu_state.MM_w4[5] == 0xffff && cpu_state.MM_w4[6] == 0xffff && cpu_state.MM_w4[7] == 0xffff && + !cpu_state.TOP && !(*p)) + cpu_state.ismmx = 1; x87_settag(rec_ftw); @@ -253,8 +274,6 @@ static int opFXSAVESTOR_a16(uint32_t fetchdat) else { /* FXSAVE */ - // pclog("FXSAVE issued\n"); - if ((twd & 0x0003) == 0x0003) ftwb |= 0x01; if ((twd & 0x000C) == 0x000C) ftwb |= 0x02; if ((twd & 0x0030) == 0x0030) ftwb |= 0x04; @@ -301,6 +320,14 @@ static int opFXSAVESTOR_a16(uint32_t fetchdat) cpu_state.eaaddr = old_eaaddr; + cpu_state.npxc = 0x37F; + cpu_state.new_npxc = (cpu_state.old_npxc & ~0xc00); + cpu_state.npxs = 0; + p = (uint64_t *)cpu_state.tag; + *p = 0x0303030303030303ll; + cpu_state.TOP = 0; + cpu_state.ismmx = 0; + CLOCK_CYCLES((cr0 & 1) ? 56 : 67); if(cpu_state.abrt) pclog("FXSAVE: abrt != 0\n"); @@ -314,10 +341,10 @@ static int opFXSAVESTOR_a32(uint32_t fetchdat) uint8_t fxinst = 0; uint16_t twd = x87_gettag(); uint32_t old_eaaddr = 0; - int old_ismmx = cpu_state.ismmx; uint8_t ftwb = 0; uint16_t rec_ftw = 0; uint16_t fpus = 0; + uint64_t *p; if (CPUID < 0x650) return ILLEGAL(fetchdat); @@ -336,9 +363,6 @@ static int opFXSAVESTOR_a32(uint32_t fetchdat) if ((fxinst > 1) || (cpu_mod == 3)) { - // if (fxinst > 1) pclog("FX instruction is: %02X\n", fxinst); - // if (cpu_mod == 3) pclog("MOD is 3\n"); - x86illegal(); return cpu_state.abrt; } @@ -350,8 +374,6 @@ static int opFXSAVESTOR_a32(uint32_t fetchdat) if (fxinst == 1) { /* FXRSTOR */ - // pclog("FXRSTOR issued\n"); - cpu_state.npxc = readmemw(easeg, cpu_state.eaaddr); fpus = readmemw(easeg, cpu_state.eaaddr + 2); cpu_state.npxc = (cpu_state.npxc & ~FPU_CW_Reserved_Bits) | 0x0040; @@ -415,10 +437,11 @@ static int opFXSAVESTOR_a32(uint32_t fetchdat) cpu_state.ismmx = 0; /*Horrible hack, but as PCem doesn't keep the FPU stack in 80-bit precision at all times something like this is needed*/ - if (cpu_state.MM[0].w[4] == 0xffff && cpu_state.MM[1].w[4] == 0xffff && cpu_state.MM[2].w[4] == 0xffff && cpu_state.MM[3].w[4] == 0xffff && - cpu_state.MM[4].w[4] == 0xffff && cpu_state.MM[5].w[4] == 0xffff && cpu_state.MM[6].w[4] == 0xffff && cpu_state.MM[7].w[4] == 0xffff && - !cpu_state.TOP && !(*(uint64_t *)cpu_state.tag)) - cpu_state.ismmx = old_ismmx; + p = (uint64_t *)cpu_state.tag; + if (cpu_state.MM_w4[0] == 0xffff && cpu_state.MM_w4[1] == 0xffff && cpu_state.MM_w4[2] == 0xffff && cpu_state.MM_w4[3] == 0xffff && + cpu_state.MM_w4[4] == 0xffff && cpu_state.MM_w4[5] == 0xffff && cpu_state.MM_w4[6] == 0xffff && cpu_state.MM_w4[7] == 0xffff && + !cpu_state.TOP && !(*p)) + cpu_state.ismmx = 1; x87_settag(rec_ftw); @@ -429,8 +452,6 @@ static int opFXSAVESTOR_a32(uint32_t fetchdat) else { /* FXSAVE */ - // pclog("FXSAVE issued\n"); - if ((twd & 0x0003) == 0x0003) ftwb |= 0x01; if ((twd & 0x000C) == 0x000C) ftwb |= 0x02; if ((twd & 0x0030) == 0x0030) ftwb |= 0x04; @@ -477,6 +498,14 @@ static int opFXSAVESTOR_a32(uint32_t fetchdat) cpu_state.eaaddr = old_eaaddr; + cpu_state.npxc = 0x37F; + cpu_state.new_npxc = (cpu_state.old_npxc & ~0xc00); + cpu_state.npxs = 0; + p = (uint64_t *)cpu_state.tag; + *p = 0x0303030303030303ll; + cpu_state.TOP = 0; + cpu_state.ismmx = 0; + CLOCK_CYCLES((cr0 & 1) ? 56 : 67); if(cpu_state.abrt) pclog("FXSAVE: abrt != 0\n"); diff --git a/src/x86_ops_inc_dec.h b/src/CPU/x86_ops_inc_dec.h similarity index 100% rename from src/x86_ops_inc_dec.h rename to src/CPU/x86_ops_inc_dec.h diff --git a/src/x86_ops_int.h b/src/CPU/x86_ops_int.h similarity index 80% rename from src/x86_ops_int.h rename to src/CPU/x86_ops_int.h index 139389160..e488ae83a 100644 --- a/src/x86_ops_int.h +++ b/src/CPU/x86_ops_int.h @@ -1,6 +1,6 @@ static int opINT3(uint32_t fetchdat) { - int cycles_old = cycles; + int cycles_old = cycles; UNUSED(cycles_old); if ((cr0 & 1) && (eflags & VM_FLAG) && (IOPL != 3)) { x86gpf(NULL,0); @@ -12,9 +12,23 @@ static int opINT3(uint32_t fetchdat) return 1; } +static int opINT1(uint32_t fetchdat) +{ + int cycles_old = cycles; UNUSED(cycles_old); + if ((cr0 & 1) && (eflags & VM_FLAG) && (IOPL != 3)) + { + x86gpf(NULL,0); + return 1; + } + x86_int_sw(1); + CLOCK_CYCLES((is486) ? 44 : 59); + PREFETCH_RUN(cycles_old-cycles, 1, -1, 0,0,0,0, 0); + return 1; +} + static int opINT(uint32_t fetchdat) { - int cycles_old = cycles; + int cycles_old = cycles; UNUSED(cycles_old); uint8_t temp; /*if (msw&1) pclog("INT %i %i %i\n",cr0&1,eflags&VM_FLAG,IOPL);*/ @@ -64,7 +78,7 @@ static int opINT(uint32_t fetchdat) static int opINTO(uint32_t fetchdat) { - int cycles_old = cycles; + int cycles_old = cycles; UNUSED(cycles_old); if ((cr0 & 1) && (eflags & VM_FLAG) && (IOPL != 3)) { diff --git a/src/x86_ops_io.h b/src/CPU/x86_ops_io.h similarity index 98% rename from src/x86_ops_io.h rename to src/CPU/x86_ops_io.h index 8f190cea0..7d42299cc 100644 --- a/src/x86_ops_io.h +++ b/src/CPU/x86_ops_io.h @@ -103,7 +103,6 @@ static int opOUT_AL_DX(uint32_t fetchdat) } static int opOUT_AX_DX(uint32_t fetchdat) { - //pclog("OUT_AX_DX %04X %04X\n", DX, AX); check_io_perm(DX); check_io_perm(DX + 1); outw(DX, AX); diff --git a/src/x86_ops_jump.h b/src/CPU/x86_ops_jump.h similarity index 96% rename from src/x86_ops_jump.h rename to src/CPU/x86_ops_jump.h index 93987633e..63ca65ea0 100644 --- a/src/x86_ops_jump.h +++ b/src/CPU/x86_ops_jump.h @@ -246,9 +246,11 @@ static int opJMP_r32(uint32_t fetchdat) static int opJMP_far_a16(uint32_t fetchdat) { - uint16_t addr = getwordf(); - uint16_t seg = getword(); if (cpu_state.abrt) return 1; - uint32_t oxpc = cpu_state.pc; + uint16_t addr, seg; + uint32_t oxpc; + addr = getwordf(); + seg = getword(); if (cpu_state.abrt) return 1; + oxpc = cpu_state.pc; cpu_state.pc = addr; loadcsjmp(seg, oxpc); CPU_BLOCK_END(); @@ -258,9 +260,11 @@ static int opJMP_far_a16(uint32_t fetchdat) } static int opJMP_far_a32(uint32_t fetchdat) { - uint32_t addr = getlong(); - uint16_t seg = getword(); if (cpu_state.abrt) return 1; - uint32_t oxpc = cpu_state.pc; + uint16_t seg; + uint32_t addr, oxpc; + addr = getlong(); + seg = getword(); if (cpu_state.abrt) return 1; + oxpc = cpu_state.pc; cpu_state.pc = addr; loadcsjmp(seg, oxpc); CPU_BLOCK_END(); @@ -321,8 +325,8 @@ static int opRET_l(uint32_t fetchdat) static int opRET_w_imm(uint32_t fetchdat) { - uint16_t offset = getwordf(); uint16_t ret; + uint16_t offset = getwordf(); ret = POP_W(); if (cpu_state.abrt) return 1; if (stack32) ESP += offset; @@ -337,8 +341,8 @@ static int opRET_w_imm(uint32_t fetchdat) } static int opRET_l_imm(uint32_t fetchdat) { - uint16_t offset = getwordf(); uint32_t ret; + uint16_t offset = getwordf(); ret = POP_L(); if (cpu_state.abrt) return 1; if (stack32) ESP += offset; diff --git a/src/x86_ops_misc.h b/src/CPU/x86_ops_misc.h similarity index 91% rename from src/x86_ops_misc.h rename to src/CPU/x86_ops_misc.h index ddf727f32..7734217eb 100644 --- a/src/x86_ops_misc.h +++ b/src/CPU/x86_ops_misc.h @@ -1,3 +1,21 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Miscellaneous x86 CPU Instructions. + * + * Version: @(#)x86_ops_misc.h 1.0.0 2017/05/30 + * + * Author: Sarah Walker, + * Miran Grca, + * Copyright 2008-2017 Sarah Walker. + * Copyright 2016-2017 Miran Grca. + */ + static int opCBW(uint32_t fetchdat) { AH = (AL & 0x80) ? 0xff : 0; @@ -56,6 +74,7 @@ static int opF6_a16(uint32_t fetchdat) switch (rmdat & 0x38) { case 0x00: /*TEST b,#8*/ + case 0x08: src = readmemb(cs, cpu_state.pc); cpu_state.pc++; if (cpu_state.abrt) return 1; setznp8(src & dst); if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); @@ -127,7 +146,6 @@ static int opF6_a16(uint32_t fetchdat) } else { -// pclog("IDIVb exception - %X / %08X = %X\n", tempws, dst, tempws2); x86_int(0); return 1; } @@ -153,6 +171,7 @@ static int opF6_a32(uint32_t fetchdat) switch (rmdat & 0x38) { case 0x00: /*TEST b,#8*/ + case 0x08: src = readmemb(cs, cpu_state.pc); cpu_state.pc++; if (cpu_state.abrt) return 1; setznp8(src & dst); if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); @@ -224,7 +243,6 @@ static int opF6_a32(uint32_t fetchdat) } else { -// pclog("IDIVb exception - %X / %08X = %X\n", tempws, dst, tempws2); x86_int(0); return 1; } @@ -253,6 +271,7 @@ static int opF7_w_a16(uint32_t fetchdat) switch (rmdat & 0x38) { case 0x00: /*TEST w*/ + case 0x08: src = getword(); if (cpu_state.abrt) return 1; setznp16(src & dst); if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); @@ -301,7 +320,6 @@ static int opF7_w_a16(uint32_t fetchdat) } else { -// fatal("DIVw BY 0 %04X:%04X %i\n",cs>>4,pc,ins); x86_int(0); return 1; } @@ -320,7 +338,6 @@ static int opF7_w_a16(uint32_t fetchdat) } else { -// pclog("IDIVw exception - %X / %08X = %X\n",tempws, dst, tempws2); x86_int(0); return 1; } @@ -346,6 +363,7 @@ static int opF7_w_a32(uint32_t fetchdat) switch (rmdat & 0x38) { case 0x00: /*TEST w*/ + case 0x08: src = getword(); if (cpu_state.abrt) return 1; setznp16(src & dst); if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); @@ -394,7 +412,6 @@ static int opF7_w_a32(uint32_t fetchdat) } else { -// fatal("DIVw BY 0 %04X:%04X %i\n",cs>>4,pc,ins); x86_int(0); return 1; } @@ -413,7 +430,6 @@ static int opF7_w_a32(uint32_t fetchdat) } else { -// pclog("IDIVw exception - %X / %08X = %X\n", tempws, dst, tempws2); x86_int(0); return 1; } @@ -439,6 +455,7 @@ static int opF7_l_a16(uint32_t fetchdat) switch (rmdat & 0x38) { case 0x00: /*TEST l*/ + case 0x08: src = getlong(); if (cpu_state.abrt) return 1; setznp32(src & dst); if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); @@ -508,6 +525,7 @@ static int opF7_l_a32(uint32_t fetchdat) switch (rmdat & 0x38) { case 0x00: /*TEST l*/ + case 0x08: src = getlong(); if (cpu_state.abrt) return 1; setznp32(src & dst); if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); @@ -721,13 +739,19 @@ static int opWBINVD(uint32_t fetchdat) return 0; } - - static int opLOADALL(uint32_t fetchdat) { + if (CPL && (cr0&1)) + { + x86gpf(NULL,0); + return 1; + } + msw = (msw & 1) | readmemw(0, 0x806); flags = (readmemw(0, 0x818) & 0xffd5) | 2; flags_extract(); + tr.seg = readmemw(0, 0x816); cpu_state.pc = readmemw(0, 0x81A); + ldt.seg = readmemw(0, 0x81C); DS = readmemw(0, 0x81E); SS = readmemw(0, 0x820); CS = readmemw(0, 0x822); @@ -741,14 +765,41 @@ static int opLOADALL(uint32_t fetchdat) CX = readmemw(0, 0x832); AX = readmemw(0, 0x834); es = readmemw(0, 0x836) | (readmemb(0, 0x838) << 16); + _es.access = readmemb(0, 0x839); + _es.limit = readmemw(0, 0x83A); cs = readmemw(0, 0x83C) | (readmemb(0, 0x83E) << 16); + _cs.access = readmemb(0, 0x83F); + _cs.limit = readmemw(0, 0x840); ss = readmemw(0, 0x842) | (readmemb(0, 0x844) << 16); + _ss.access = readmemb(0, 0x845); + _ss.limit = readmemw(0, 0x846); + if (_ss.base == 0 && _ss.limit_low == 0 && _ss.limit_high == 0xffffffff) + cpu_cur_status |= CPU_STATUS_FLATSS; + else + cpu_cur_status &= ~CPU_STATUS_FLATSS; ds = readmemw(0, 0x848) | (readmemb(0, 0x84A) << 16); + _ds.access = readmemb(0, 0x84B); + _ds.limit = readmemw(0, 0x84C); + if (_ds.base == 0 && _ds.limit_low == 0 && _ds.limit_high == 0xffffffff) + cpu_cur_status |= CPU_STATUS_FLATDS; + else + cpu_cur_status &= ~CPU_STATUS_FLATDS; + gdt.base = readmemw(0, 0x84E) | (readmemb(0, 0x850) << 16); + gdt.limit = readmemw(0, 0x852); + ldt.base = readmemw(0, 0x854) | (readmemb(0, 0x856) << 16); + ldt.access = readmemb(0, 0x857); + ldt.limit = readmemw(0, 0x858); + idt.base = readmemw(0, 0x85A) | (readmemb(0, 0x85C) << 16); + idt.limit = readmemw(0, 0x85E); + tr.base = readmemw(0, 0x860) | (readmemb(0, 0x862) << 16); + tr.access = readmemb(0, 0x863); + tr.limit = readmemw(0, 0x864); CLOCK_CYCLES(195); + PREFETCH_RUN(195, 1, -1, 51,0,0,0, 0); return 0; } -static int set_segment_limit(x86seg *s, uint8_t segdat3) +static void set_segment_limit(x86seg *s, uint8_t segdat3) { if ((s->access & 0x18) != 0x10 || !(s->access & (1 << 2))) /*expand-down*/ { @@ -762,7 +813,7 @@ static int set_segment_limit(x86seg *s, uint8_t segdat3) } } -static int loadall_load_segment(uint32_t addr, x86seg *s) +static void loadall_load_segment(uint32_t addr, x86seg *s) { uint32_t attrib = readmeml(0, addr); uint32_t segdat3 = (attrib >> 16) & 0xff; @@ -772,8 +823,29 @@ static int loadall_load_segment(uint32_t addr, x86seg *s) if (s == &_cs) use32 = (segdat3 & 0x40) ? 0x300 : 0; if (s == &_ss) stack32 = (segdat3 & 0x40) ? 1 : 0; + cpu_cur_status &= ~(CPU_STATUS_USE32 | CPU_STATUS_STACK32); + if (use32) + cpu_cur_status |= CPU_STATUS_USE32; + if (stack32) + cpu_cur_status |= CPU_STATUS_STACK32; set_segment_limit(s, segdat3); + + if (s == &_ds) + { + if (s->base == 0 && s->limit_low == 0 && s->limit_high == 0xffffffff) + + cpu_cur_status |= CPU_STATUS_FLATDS; + else + cpu_cur_status &= ~CPU_STATUS_FLATDS; + } + if (s == &_ss) + { + if (s->base == 0 && s->limit_low == 0 && s->limit_high == 0xffffffff) + cpu_cur_status |= CPU_STATUS_FLATSS; + else + cpu_cur_status &= ~CPU_STATUS_FLATSS; + } } static int opLOADALL386(uint32_t fetchdat) diff --git a/src/x86_ops_mmx.h b/src/CPU/x86_ops_mmx.h similarity index 100% rename from src/x86_ops_mmx.h rename to src/CPU/x86_ops_mmx.h diff --git a/src/x86_ops_mmx_arith.h b/src/CPU/x86_ops_mmx_arith.h similarity index 100% rename from src/x86_ops_mmx_arith.h rename to src/CPU/x86_ops_mmx_arith.h diff --git a/src/x86_ops_mmx_cmp.h b/src/CPU/x86_ops_mmx_cmp.h similarity index 100% rename from src/x86_ops_mmx_cmp.h rename to src/CPU/x86_ops_mmx_cmp.h diff --git a/src/x86_ops_mmx_logic.h b/src/CPU/x86_ops_mmx_logic.h similarity index 100% rename from src/x86_ops_mmx_logic.h rename to src/CPU/x86_ops_mmx_logic.h diff --git a/src/x86_ops_mmx_mov.h b/src/CPU/x86_ops_mmx_mov.h similarity index 100% rename from src/x86_ops_mmx_mov.h rename to src/CPU/x86_ops_mmx_mov.h diff --git a/src/x86_ops_mmx_pack.h b/src/CPU/x86_ops_mmx_pack.h similarity index 100% rename from src/x86_ops_mmx_pack.h rename to src/CPU/x86_ops_mmx_pack.h diff --git a/src/x86_ops_mmx_shift.h b/src/CPU/x86_ops_mmx_shift.h similarity index 100% rename from src/x86_ops_mmx_shift.h rename to src/CPU/x86_ops_mmx_shift.h diff --git a/src/x86_ops_mov.h b/src/CPU/x86_ops_mov.h similarity index 96% rename from src/x86_ops_mov.h rename to src/CPU/x86_ops_mov.h index a9ba431c2..bf82c3d66 100644 --- a/src/x86_ops_mov.h +++ b/src/CPU/x86_ops_mov.h @@ -181,6 +181,7 @@ static int opMOV_b_imm_a16(uint32_t fetchdat) { uint8_t temp; fetch_ea_16(fetchdat); + ILLEGAL_ON((rmdat & 0x38) != 0); temp = readmemb(cs,cpu_state.pc); cpu_state.pc++; if (cpu_state.abrt) return 1; CHECK_WRITE(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr); seteab(temp); @@ -192,6 +193,7 @@ static int opMOV_b_imm_a32(uint32_t fetchdat) { uint8_t temp; fetch_ea_32(fetchdat); + ILLEGAL_ON((rmdat & 0x38) != 0); temp = getbyte(); if (cpu_state.abrt) return 1; seteab(temp); CLOCK_CYCLES(timing_rr); @@ -203,6 +205,7 @@ static int opMOV_w_imm_a16(uint32_t fetchdat) { uint16_t temp; fetch_ea_16(fetchdat); + ILLEGAL_ON((rmdat & 0x38) != 0); temp = getword(); if (cpu_state.abrt) return 1; seteaw(temp); CLOCK_CYCLES(timing_rr); @@ -213,6 +216,7 @@ static int opMOV_w_imm_a32(uint32_t fetchdat) { uint16_t temp; fetch_ea_32(fetchdat); + ILLEGAL_ON((rmdat & 0x38) != 0); temp = getword(); if (cpu_state.abrt) return 1; seteaw(temp); CLOCK_CYCLES(timing_rr); @@ -223,6 +227,7 @@ static int opMOV_l_imm_a16(uint32_t fetchdat) { uint32_t temp; fetch_ea_16(fetchdat); + ILLEGAL_ON((rmdat & 0x38) != 0); temp = getlong(); if (cpu_state.abrt) return 1; seteal(temp); CLOCK_CYCLES(timing_rr); @@ -233,6 +238,7 @@ static int opMOV_l_imm_a32(uint32_t fetchdat) { uint32_t temp; fetch_ea_32(fetchdat); + ILLEGAL_ON((rmdat & 0x38) != 0); temp = getlong(); if (cpu_state.abrt) return 1; seteal(temp); CLOCK_CYCLES(timing_rr); @@ -243,8 +249,9 @@ static int opMOV_l_imm_a32(uint32_t fetchdat) static int opMOV_AL_a16(uint32_t fetchdat) { + uint8_t temp; uint16_t addr = getwordf(); - uint8_t temp = readmemb(cpu_state.ea_seg->base, addr); if (cpu_state.abrt) return 1; + temp = readmemb(cpu_state.ea_seg->base, addr); if (cpu_state.abrt) return 1; AL = temp; CLOCK_CYCLES((is486) ? 1 : 4); PREFETCH_RUN(4, 3, -1, 1,0,0,0, 0); @@ -252,8 +259,9 @@ static int opMOV_AL_a16(uint32_t fetchdat) } static int opMOV_AL_a32(uint32_t fetchdat) { + uint8_t temp; uint32_t addr = getlong(); - uint8_t temp = readmemb(cpu_state.ea_seg->base, addr); if (cpu_state.abrt) return 1; + temp = readmemb(cpu_state.ea_seg->base, addr); if (cpu_state.abrt) return 1; AL = temp; CLOCK_CYCLES((is486) ? 1 : 4); PREFETCH_RUN(4, 5, -1, 1,0,0,0, 1); @@ -261,8 +269,9 @@ static int opMOV_AL_a32(uint32_t fetchdat) } static int opMOV_AX_a16(uint32_t fetchdat) { + uint16_t temp; uint16_t addr = getwordf(); - uint16_t temp = readmemw(cpu_state.ea_seg->base, addr); if (cpu_state.abrt) return 1; + temp = readmemw(cpu_state.ea_seg->base, addr); if (cpu_state.abrt) return 1; AX = temp; CLOCK_CYCLES((is486) ? 1 : 4); PREFETCH_RUN(4, 3, -1, 1,0,0,0, 0); @@ -270,8 +279,9 @@ static int opMOV_AX_a16(uint32_t fetchdat) } static int opMOV_AX_a32(uint32_t fetchdat) { + uint16_t temp; uint32_t addr = getlong(); - uint16_t temp = readmemw(cpu_state.ea_seg->base, addr); if (cpu_state.abrt) return 1; + temp = readmemw(cpu_state.ea_seg->base, addr); if (cpu_state.abrt) return 1; AX = temp; CLOCK_CYCLES((is486) ? 1 : 4); PREFETCH_RUN(4, 5, -1, 1,0,0,0, 1); @@ -279,8 +289,9 @@ static int opMOV_AX_a32(uint32_t fetchdat) } static int opMOV_EAX_a16(uint32_t fetchdat) { + uint32_t temp; uint16_t addr = getwordf(); - uint32_t temp = readmeml(cpu_state.ea_seg->base, addr); if (cpu_state.abrt) return 1; + temp = readmeml(cpu_state.ea_seg->base, addr); if (cpu_state.abrt) return 1; EAX = temp; CLOCK_CYCLES((is486) ? 1 : 4); PREFETCH_RUN(4, 3, -1, 0,1,0,0, 0); @@ -288,8 +299,9 @@ static int opMOV_EAX_a16(uint32_t fetchdat) } static int opMOV_EAX_a32(uint32_t fetchdat) { + uint32_t temp; uint32_t addr = getlong(); - uint32_t temp = readmeml(cpu_state.ea_seg->base, addr); if (cpu_state.abrt) return 1; + temp = readmeml(cpu_state.ea_seg->base, addr); if (cpu_state.abrt) return 1; EAX = temp; CLOCK_CYCLES((is486) ? 1 : 4); PREFETCH_RUN(4, 5, -1, 0,1,0,0, 1); @@ -349,7 +361,7 @@ static int opMOV_a32_EAX(uint32_t fetchdat) static int opLEA_w_a16(uint32_t fetchdat) { fetch_ea_16(fetchdat); - // ILLEGAL_ON(cpu_mod == 3); + /* ILLEGAL_ON(cpu_mod == 3); */ cpu_state.regs[cpu_reg].w = (cpu_mod == 3) ? (cpu_state.last_ea & 0xffff) : cpu_state.eaaddr; CLOCK_CYCLES(timing_rr); PREFETCH_RUN(timing_rr, 2, rmdat, 0,0,0,0, 0); @@ -358,7 +370,7 @@ static int opLEA_w_a16(uint32_t fetchdat) static int opLEA_w_a32(uint32_t fetchdat) { fetch_ea_32(fetchdat); - // ILLEGAL_ON(cpu_mod == 3); + /* ILLEGAL_ON(cpu_mod == 3); */ cpu_state.regs[cpu_reg].w = (cpu_mod == 3) ? (cpu_state.last_ea & 0xffff) : cpu_state.eaaddr; CLOCK_CYCLES(timing_rr); PREFETCH_RUN(timing_rr, 2, rmdat, 0,0,0,0, 1); @@ -368,7 +380,7 @@ static int opLEA_w_a32(uint32_t fetchdat) static int opLEA_l_a16(uint32_t fetchdat) { fetch_ea_16(fetchdat); - // ILLEGAL_ON(cpu_mod == 3); + /* ILLEGAL_ON(cpu_mod == 3); */ cpu_state.regs[cpu_reg].l = ((cpu_mod == 3) ? cpu_state.last_ea : cpu_state.eaaddr) & 0xffff; CLOCK_CYCLES(timing_rr); PREFETCH_RUN(timing_rr, 2, rmdat, 0,0,0,0, 0); @@ -377,7 +389,7 @@ static int opLEA_l_a16(uint32_t fetchdat) static int opLEA_l_a32(uint32_t fetchdat) { fetch_ea_32(fetchdat); - // ILLEGAL_ON(cpu_mod == 3); + /* ILLEGAL_ON(cpu_mod == 3); */ cpu_state.regs[cpu_reg].l = (cpu_mod == 3) ? cpu_state.last_ea : cpu_state.eaaddr; CLOCK_CYCLES(timing_rr); PREFETCH_RUN(timing_rr, 2, rmdat, 0,0,0,0, 1); diff --git a/src/x86_ops_mov_ctrl.h b/src/CPU/x86_ops_mov_ctrl.h similarity index 100% rename from src/x86_ops_mov_ctrl.h rename to src/CPU/x86_ops_mov_ctrl.h diff --git a/src/x86_ops_mov_seg.h b/src/CPU/x86_ops_mov_seg.h similarity index 100% rename from src/x86_ops_mov_seg.h rename to src/CPU/x86_ops_mov_seg.h diff --git a/src/x86_ops_movx.h b/src/CPU/x86_ops_movx.h similarity index 100% rename from src/x86_ops_movx.h rename to src/CPU/x86_ops_movx.h diff --git a/src/x86_ops_msr.h b/src/CPU/x86_ops_msr.h similarity index 100% rename from src/x86_ops_msr.h rename to src/CPU/x86_ops_msr.h diff --git a/src/x86_ops_mul.h b/src/CPU/x86_ops_mul.h similarity index 100% rename from src/x86_ops_mul.h rename to src/CPU/x86_ops_mul.h diff --git a/src/x86_ops_pmode.h b/src/CPU/x86_ops_pmode.h similarity index 95% rename from src/x86_ops_pmode.h rename to src/CPU/x86_ops_pmode.h index 1f30fbfa7..85f028dbd 100644 --- a/src/x86_ops_pmode.h +++ b/src/CPU/x86_ops_pmode.h @@ -4,7 +4,7 @@ static int opARPL_a16(uint32_t fetchdat) NOTRM fetch_ea_16(fetchdat); - pclog("ARPL_a16\n"); + /* pclog("ARPL_a16\n"); */ temp_seg = geteaw(); if (cpu_state.abrt) return 1; flags_rebuild(); @@ -27,7 +27,7 @@ static int opARPL_a32(uint32_t fetchdat) NOTRM fetch_ea_32(fetchdat); - pclog("ARPL_a32\n"); + /* pclog("ARPL_a32\n"); */ temp_seg = geteaw(); if (cpu_state.abrt) return 1; flags_rebuild(); @@ -49,7 +49,7 @@ static int opARPL_a32(uint32_t fetchdat) static int opLAR_ ## name(uint32_t fetchdat) \ { \ int valid; \ - uint16_t sel, desc; \ + uint16_t sel, desc = 0; \ \ NOTRM \ fetch_ea(fetchdat); \ @@ -99,7 +99,7 @@ opLAR(l_a32, fetch_ea_32, 1, 1) static int opLSL_ ## name(uint32_t fetchdat) \ { \ int valid; \ - uint16_t sel, desc; \ + uint16_t sel, desc = 0; \ \ NOTRM \ fetch_ea(fetchdat); \ @@ -159,7 +159,7 @@ static int op0F00_common(uint32_t fetchdat, int ea32) uint16_t desc, sel; uint8_t access; -// pclog("op0F00 %02X %04X:%04X\n", rmdat & 0x38, CS, pc); + /* pclog("op0F00 %02X %04X:%04X\n", rmdat & 0x38, CS, pc); */ switch (rmdat & 0x38) { case 0x00: /*SLDT*/ @@ -293,12 +293,12 @@ static int op0F01_common(uint32_t fetchdat, int is32, int is286, int ea32) { uint32_t base; uint16_t limit, tempw; -// pclog("op0F01 %02X %04X:%04X\n", rmdat & 0x38, CS, pc); + /* pclog("op0F01 %02X %04X:%04X\n", rmdat & 0x38, CS, pc); */ switch (rmdat & 0x38) { case 0x00: /*SGDT*/ seteaw(gdt.limit); - base = gdt.base; //is32 ? gdt.base : (gdt.base & 0xffffff); + base = gdt.base; /* is32 ? gdt.base : (gdt.base & 0xffffff); */ if (is286) base |= 0xff000000; writememl(easeg, cpu_state.eaaddr + 2, base); @@ -321,10 +321,10 @@ static int op0F01_common(uint32_t fetchdat, int is32, int is286, int ea32) x86gpf(NULL,0); break; } -// pclog("LGDT %08X:%08X\n", easeg, eaaddr); + /* pclog("LGDT %08X:%08X\n", easeg, eaaddr); */ limit = geteaw(); base = readmeml(0, easeg + cpu_state.eaaddr + 2); if (cpu_state.abrt) return 1; -// pclog(" %08X %04X\n", base, limit); + /* pclog(" %08X %04X\n", base, limit); */ gdt.limit = limit; gdt.base = base; if (!is32) gdt.base &= 0xffffff; @@ -338,10 +338,10 @@ static int op0F01_common(uint32_t fetchdat, int is32, int is286, int ea32) x86gpf(NULL,0); break; } -// pclog("LIDT %08X:%08X\n", easeg, eaaddr); + /* pclog("LIDT %08X:%08X\n", easeg, eaaddr); */ limit = geteaw(); base = readmeml(0, easeg + cpu_state.eaaddr + 2); if (cpu_state.abrt) return 1; -// pclog(" %08X %04X\n", base, limit); + /* pclog(" %08X %04X\n", base, limit); */ idt.limit = limit; idt.base = base; if (!is32) idt.base &= 0xffffff; @@ -350,8 +350,9 @@ static int op0F01_common(uint32_t fetchdat, int is32, int is286, int ea32) break; case 0x20: /*SMSW*/ - if (is486) seteaw(msw); - else seteaw(msw | 0xFF00); + if (is486) seteaw(msw); + else if (is386) seteaw(msw | 0xFF00); + else seteaw(msw | 0xFFF0); CLOCK_CYCLES(2); PREFETCH_RUN(2, 2, rmdat, 0,0,(cpu_mod == 3) ? 0:1,0, ea32); break; @@ -364,6 +365,7 @@ static int op0F01_common(uint32_t fetchdat, int is32, int is286, int ea32) } tempw = geteaw(); if (cpu_state.abrt) return 1; if (msw & 1) tempw |= 1; + if (!is386) tempw &= 0xF; msw = tempw; PREFETCH_RUN(2, 2, rmdat, 0,0,(cpu_mod == 3) ? 0:1,0, ea32); break; diff --git a/src/x86_ops_prefix.h b/src/CPU/x86_ops_prefix.h similarity index 100% rename from src/x86_ops_prefix.h rename to src/CPU/x86_ops_prefix.h diff --git a/src/x86_ops_rep.h b/src/CPU/x86_ops_rep.h similarity index 100% rename from src/x86_ops_rep.h rename to src/CPU/x86_ops_rep.h diff --git a/src/x86_ops_ret.h b/src/CPU/x86_ops_ret.h similarity index 95% rename from src/x86_ops_ret.h rename to src/CPU/x86_ops_ret.h index 4f41a2049..0bc88e466 100644 --- a/src/x86_ops_ret.h +++ b/src/CPU/x86_ops_ret.h @@ -44,7 +44,7 @@ static int opRETF_a16(uint32_t fetchdat) { - int cycles_old = cycles; + int cycles_old = cycles; UNUSED(cycles_old); CPU_BLOCK_END(); RETF_a16(0); @@ -55,7 +55,7 @@ static int opRETF_a16(uint32_t fetchdat) } static int opRETF_a32(uint32_t fetchdat) { - int cycles_old = cycles; + int cycles_old = cycles; UNUSED(cycles_old); CPU_BLOCK_END(); RETF_a32(0); @@ -67,8 +67,8 @@ static int opRETF_a32(uint32_t fetchdat) static int opRETF_a16_imm(uint32_t fetchdat) { - int cycles_old = cycles; uint16_t offset = getwordf(); + int cycles_old = cycles; UNUSED(cycles_old); CPU_BLOCK_END(); RETF_a16(offset); @@ -79,8 +79,8 @@ static int opRETF_a16_imm(uint32_t fetchdat) } static int opRETF_a32_imm(uint32_t fetchdat) { - int cycles_old = cycles; uint16_t offset = getwordf(); + int cycles_old = cycles; UNUSED(cycles_old); CPU_BLOCK_END(); RETF_a32(offset); @@ -92,7 +92,7 @@ static int opRETF_a32_imm(uint32_t fetchdat) static int opIRET_286(uint32_t fetchdat) { - int cycles_old = cycles; + int cycles_old = cycles; UNUSED(cycles_old); if ((cr0 & 1) && (eflags & VM_FLAG) && (IOPL != 3)) { @@ -137,7 +137,7 @@ static int opIRET_286(uint32_t fetchdat) static int opIRET(uint32_t fetchdat) { - int cycles_old = cycles; + int cycles_old = cycles; UNUSED(cycles_old); if ((cr0 & 1) && (eflags & VM_FLAG) && (IOPL != 3)) { @@ -182,7 +182,7 @@ static int opIRET(uint32_t fetchdat) static int opIRETD(uint32_t fetchdat) { - int cycles_old = cycles; + int cycles_old = cycles; UNUSED(cycles_old); if ((cr0 & 1) && (eflags & VM_FLAG) && (IOPL != 3)) { diff --git a/src/x86_ops_set.h b/src/CPU/x86_ops_set.h similarity index 100% rename from src/x86_ops_set.h rename to src/CPU/x86_ops_set.h diff --git a/src/x86_ops_shift.h b/src/CPU/x86_ops_shift.h similarity index 97% rename from src/x86_ops_shift.h rename to src/CPU/x86_ops_shift.h index 495a1bf47..0c5a31f06 100644 --- a/src/x86_ops_shift.h +++ b/src/CPU/x86_ops_shift.h @@ -497,9 +497,11 @@ static int opD3_l_a32(uint32_t fetchdat) #define SHLD_w() \ if (count) \ { \ + int tempc; \ + uint32_t templ; \ uint16_t tempw = geteaw(); if (cpu_state.abrt) return 1; \ - int tempc = ((tempw << (count - 1)) & (1 << 15)) ? 1 : 0; \ - uint32_t templ = (tempw << 16) | cpu_state.regs[cpu_reg].w; \ + tempc = ((tempw << (count - 1)) & (1 << 15)) ? 1 : 0; \ + templ = (tempw << 16) | cpu_state.regs[cpu_reg].w; \ if (count <= 16) tempw = templ >> (16 - count); \ else tempw = (templ << count) >> 16; \ seteaw(tempw); if (cpu_state.abrt) return 1; \ @@ -511,8 +513,9 @@ static int opD3_l_a32(uint32_t fetchdat) #define SHLD_l() \ if (count) \ { \ + int tempc; \ uint32_t templ = geteal(); if (cpu_state.abrt) return 1; \ - int tempc = ((templ << (count - 1)) & (1 << 31)) ? 1 : 0; \ + tempc = ((templ << (count - 1)) & (1 << 31)) ? 1 : 0; \ templ = (templ << count) | (cpu_state.regs[cpu_reg].l >> (32 - count)); \ seteal(templ); if (cpu_state.abrt) return 1; \ setznp32(templ); \ @@ -523,10 +526,12 @@ static int opD3_l_a32(uint32_t fetchdat) #define SHRD_w() \ if (count) \ - { \ + { \ + int tempc; \ + uint32_t templ; \ uint16_t tempw = geteaw(); if (cpu_state.abrt) return 1; \ - int tempc = (tempw >> (count - 1)) & 1; \ - uint32_t templ = tempw | (cpu_state.regs[cpu_reg].w << 16); \ + tempc = (tempw >> (count - 1)) & 1; \ + templ = tempw | (cpu_state.regs[cpu_reg].w << 16); \ tempw = templ >> count; \ seteaw(tempw); if (cpu_state.abrt) return 1; \ setznp16(tempw); \ @@ -537,8 +542,9 @@ static int opD3_l_a32(uint32_t fetchdat) #define SHRD_l() \ if (count) \ { \ + int tempc; \ uint32_t templ = geteal(); if (cpu_state.abrt) return 1; \ - int tempc = (templ >> (count - 1)) & 1; \ + tempc = (templ >> (count - 1)) & 1; \ templ = (templ >> count) | (cpu_state.regs[cpu_reg].l << (32 - count)); \ seteal(templ); if (cpu_state.abrt) return 1; \ setznp32(templ); \ @@ -553,7 +559,7 @@ static int opD3_l_a32(uint32_t fetchdat) \ fetch_ea_16(fetchdat); \ count = getbyte() & 31; \ - operation(); \ + operation() \ \ CLOCK_CYCLES(3); \ PREFETCH_RUN(3, 3, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, 0); \ @@ -565,7 +571,7 @@ static int opD3_l_a32(uint32_t fetchdat) \ fetch_ea_16(fetchdat); \ count = CL & 31; \ - operation(); \ + operation() \ \ CLOCK_CYCLES(3); \ PREFETCH_RUN(3, 3, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, 0); \ @@ -577,7 +583,7 @@ static int opD3_l_a32(uint32_t fetchdat) \ fetch_ea_32(fetchdat); \ count = getbyte() & 31; \ - operation(); \ + operation() \ \ CLOCK_CYCLES(3); \ PREFETCH_RUN(3, 3, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, 1); \ @@ -589,7 +595,7 @@ static int opD3_l_a32(uint32_t fetchdat) \ fetch_ea_32(fetchdat); \ count = CL & 31; \ - operation(); \ + operation() \ \ CLOCK_CYCLES(3); \ PREFETCH_RUN(3, 3, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, 1); \ diff --git a/src/x86_ops_stack.h b/src/CPU/x86_ops_stack.h similarity index 96% rename from src/x86_ops_stack.h rename to src/CPU/x86_ops_stack.h index 86daf52aa..621f602b3 100644 --- a/src/x86_ops_stack.h +++ b/src/CPU/x86_ops_stack.h @@ -310,10 +310,16 @@ static int opPOPL_a32(uint32_t fetchdat) static int opENTER_w(uint32_t fetchdat) { - uint16_t offset = getwordf(); - int count = (fetchdat >> 16) & 0xff; cpu_state.pc++; - uint32_t tempEBP = EBP, tempESP = ESP, frame_ptr; + uint16_t offset; + int count; + uint32_t tempEBP, tempESP, frame_ptr; int reads = 0, writes = 1, instr_cycles = 0; + uint16_t tempw; + + offset = getwordf(); + count = (fetchdat >> 16) & 0xff; cpu_state.pc++; + tempEBP = EBP; + tempESP = ESP; PUSH_W(BP); if (cpu_state.abrt) return 1; frame_ptr = ESP; @@ -322,8 +328,6 @@ static int opENTER_w(uint32_t fetchdat) { while (--count) { - uint16_t tempw; - BP -= 2; tempw = readmemw(ss, BP); if (cpu_state.abrt) { ESP = tempESP; EBP = tempEBP; return 1; } @@ -348,10 +352,15 @@ static int opENTER_w(uint32_t fetchdat) } static int opENTER_l(uint32_t fetchdat) { - uint16_t offset = getwordf(); - int count = (fetchdat >> 16) & 0xff; cpu_state.pc++; - uint32_t tempEBP = EBP, tempESP = ESP, frame_ptr; + uint16_t offset; + int count; + uint32_t tempEBP, tempESP, frame_ptr; int reads = 0, writes = 1, instr_cycles = 0; + uint32_t templ; + + offset = getwordf(); + count = (fetchdat >> 16) & 0xff; cpu_state.pc++; + tempEBP = EBP; tempESP = ESP; PUSH_L(EBP); if (cpu_state.abrt) return 1; frame_ptr = ESP; @@ -360,8 +369,6 @@ static int opENTER_l(uint32_t fetchdat) { while (--count) { - uint32_t templ; - EBP -= 4; templ = readmeml(ss, EBP); if (cpu_state.abrt) { ESP = tempESP; EBP = tempEBP; return 1; } @@ -455,17 +462,17 @@ static int opLEAVE_l(uint32_t fetchdat) } -PUSH_SEG_OPS(CS); -PUSH_SEG_OPS(DS); -PUSH_SEG_OPS(ES); -PUSH_SEG_OPS(FS); -PUSH_SEG_OPS(GS); -PUSH_SEG_OPS(SS); +PUSH_SEG_OPS(CS) +PUSH_SEG_OPS(DS) +PUSH_SEG_OPS(ES) +PUSH_SEG_OPS(FS) +PUSH_SEG_OPS(GS) +PUSH_SEG_OPS(SS) -POP_SEG_OPS(DS, &_ds); -POP_SEG_OPS(ES, &_es); -POP_SEG_OPS(FS, &_fs); -POP_SEG_OPS(GS, &_gs); +POP_SEG_OPS(DS, &_ds) +POP_SEG_OPS(ES, &_es) +POP_SEG_OPS(FS, &_fs) +POP_SEG_OPS(GS, &_gs) static int opPOP_SS_w(uint32_t fetchdat) diff --git a/src/x86_ops_string.h b/src/CPU/x86_ops_string.h similarity index 100% rename from src/x86_ops_string.h rename to src/CPU/x86_ops_string.h diff --git a/src/x86_ops_xchg.h b/src/CPU/x86_ops_xchg.h similarity index 100% rename from src/x86_ops_xchg.h rename to src/CPU/x86_ops_xchg.h diff --git a/src/x86seg.c b/src/CPU/x86seg.c similarity index 76% rename from src/x86seg.c rename to src/CPU/x86seg.c index a6db3f8ac..399b6826f 100644 --- a/src/x86seg.c +++ b/src/CPU/x86seg.c @@ -1,14 +1,30 @@ -/* Copyright holders: Sarah Walker, SA1988 - see COPYING for more details -*/ -//#if 0 +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * x86 CPU segment emulation. + * + * Version: @(#)x86seg.c 1.0.0 2017/05/30 + * + * Author: Sarah Walker, + * Miran Grca, + * Copyright 2008-2017 Sarah Walker. + * Copyright 2016-2017 Miran Grca. + */ + #include #include #include -#include "ibm.h" -#include "mem.h" +#include "../ibm.h" +#include "../mem.h" +#include "../nvr.h" #include "x86.h" #include "386.h" +#include "386_common.h" #include "cpu.h" /*Controls whether the accessed bit in a descriptor is set when CS is loaded.*/ @@ -46,7 +62,7 @@ void x86abort(const char *format, ...) va_end(ap); fflush(stdout); savenvr(); - dumpregs(); + dumpregs(1); fflush(stdout); exit(-1); } @@ -73,19 +89,9 @@ void x86seg_reset() void x86_doabrt(int x86_abrt) { -// ingpf = 1; CS = oldcs; cpu_state.pc = cpu_state.oldpc; _cs.access = (oldcpl << 5) | 0x80; -// pclog("x86_doabrt - %02X %08X %04X:%08X %i\n", x86_abrt, abrt_error, CS, pc, ins); - -/* if (CS == 0x3433 && cpu_state.pc == 0x000006B0) - { - // pclog("Quit it\n"); - dumpregs(); - exit(-1); - }*/ -// pclog("GPF! - error %04X %04X(%08X):%08X %02X %02X %i %04X %i %i\n",error,CS,cs,cpu_state.pc,opcode,opcode2,ins,flags&I_FLAG,IOPL, dtimes); if (msw & 1) pmodeint(x86_abrt, 0); @@ -143,35 +149,52 @@ void x86_doabrt(int x86_abrt) SP-=4; } } -// ingpf = 0; -// cpu_state.abrt = gpf = 1; } void x86gpf(char *s, uint16_t error) { - // pclog("GPF %04X : %s\n", error, s); cpu_state.abrt = ABRT_GPF; abrt_error = error; } void x86ss(char *s, uint16_t error) { - // pclog("SS %04X\n", error); cpu_state.abrt = ABRT_SS; abrt_error = error; } void x86ts(char *s, uint16_t error) { - // pclog("TS %04X\n", error); cpu_state.abrt = ABRT_TS; abrt_error = error; } void x86np(char *s, uint16_t error) { - // pclog("NP %04X : %s\n", error, s); cpu_state.abrt = ABRT_NP; abrt_error = error; } +static void set_stack32(int s) +{ + stack32 = s; + if (stack32) + cpu_cur_status |= CPU_STATUS_STACK32; + else + cpu_cur_status &= ~CPU_STATUS_STACK32; +} + +static void set_use32(int u) +{ + if (u) + { + use32 = 0x300; + cpu_cur_status |= CPU_STATUS_USE32; + } + else + { + use32 = 0; + cpu_cur_status &= ~CPU_STATUS_USE32; + } +} + void do_seg_load(x86seg *s, uint16_t *segdat) { s->limit = segdat[0] | ((segdat[3] & 0xF) << 16); @@ -192,7 +215,21 @@ void do_seg_load(x86seg *s, uint16_t *segdat) s->limit_high = (segdat[3] & 0x40) ? 0xffffffff : 0xffff; s->limit_low = s->limit + 1; } -// if (output) pclog("SEG : base=%08x limit=%08x low=%08x high=%08x\n", s->base, s->limit, s->limit_low, s->limit_high); + + if (s == &_ds) + { + if (s->base == 0 && s->limit_low == 0 && s->limit_high == 0xffffffff) + cpu_cur_status |= CPU_STATUS_FLATDS; + else + cpu_cur_status &= ~CPU_STATUS_FLATDS; + } + if (s == &_ss) + { + if (s->base == 0 && s->limit_low == 0 && s->limit_high == 0xffffffff) + cpu_cur_status |= CPU_STATUS_FLATSS; + else + cpu_cur_status &= ~CPU_STATUS_FLATSS; + } } static void do_seg_v86_init(x86seg *s) @@ -212,7 +249,6 @@ static void check_seg_valid(x86seg *s) { if ((s->seg & ~7) >= ldt.limit) { -// pclog("Bigger than LDT limit %04X %04X %02X %02X %02X\n", s->seg, ldt.limit, opcode, opcode2, rmdat); valid = 0; } } @@ -220,7 +256,6 @@ static void check_seg_valid(x86seg *s) { if ((s->seg & ~7) >= gdt.limit) { -// pclog("Bigger than GDT limit %04X %04X\n", s->seg, gdt.limit); valid = 0; } } @@ -232,7 +267,6 @@ static void check_seg_valid(x86seg *s) case 0x1A: case 0x1B: /*Readable non-conforming code*/ if ((s->seg & 3) > dpl || (CPL) > dpl) { -// pclog("Data seg fail - %04X:%08X %04X %i\n", CS, cpu_state.pc, s->seg, dpl); valid = 0; break; } @@ -258,36 +292,25 @@ void loadseg(uint16_t seg, x86seg *s) if (msw&1 && !(eflags&VM_FLAG)) { -// intcount++; if (!(seg&~3)) { if (s==&_ss) { - // pclog("SS selector = NULL!\n"); x86ss(NULL,0); return; -// dumpregs(); -// exit(-1); } -// if (s->base!=-1) pclog("NEW! "); s->seg=0; - // s->access = 0; s->access = 0x80; s->base=-1; -// pclog("NULL selector %s%s%s%s %04X(%06X):%06X\n",(s==&_ds)?"DS":"",(s==&_es)?"ES":"",(s==&_fs)?"FS":"",(s==&_gs)?"GS":"",CS,cs,cpu_state.pc); + if (s == &_ds) + cpu_cur_status &= ~CPU_STATUS_FLATDS; return; } -// if (s==&_ss) pclog("Load SS %04X\n",seg); -// pclog("Protected mode seg load!\n"); addr=seg&~7; if (seg&4) { if (addr>=ldt.limit) { - // pclog("Bigger than LDT limit %04X %04X %02X %02X %02X\n",seg,ldt.limit, opcode, opcode2, rmdat); -// dumppic(); -// dumpregs(); -// exit(-1); x86gpf("loadseg(): Bigger than LDT limit",seg&~3); return; } @@ -297,9 +320,6 @@ void loadseg(uint16_t seg, x86seg *s) { if (addr>=gdt.limit) { - // pclog("Bigger than GDT limit %04X %04X 1\n",seg,gdt.limit); -// dumpregs(); -// exit(-1); x86gpf("loadseg(): Bigger than GDT limit",seg&~3); return; } @@ -315,15 +335,12 @@ void loadseg(uint16_t seg, x86seg *s) { if (!(seg&~3)) { - // pclog("Load SS null selector\n"); x86gpf(NULL,seg&~3); return; } if ((seg&3)!=CPL || dpl!=CPL) { - // pclog("Invalid SS permiss\n"); x86gpf(NULL,seg&~3); -// x86abort("Invalid SS permiss for %04X!\n",seg&0xFFFC); return; } switch ((segdat[2]>>8)&0x1F) @@ -331,19 +348,15 @@ void loadseg(uint16_t seg, x86seg *s) case 0x12: case 0x13: case 0x16: case 0x17: /*r/w*/ break; default: - // pclog("Invalid SS type\n"); x86gpf(NULL,seg&~3); -// x86abort("Invalid SS segment type for %04X!\n",seg&0xFFFC); return; } if (!(segdat[2]&0x8000)) { - // pclog("Load SS not present!\n"); x86ss(NULL,seg&~3); return; } - stack32 = (segdat[3] & 0x40) ? 1 : 0; -// pclog("Load SS %04x %04x %04x %04x\n", segdat[0], segdat[1], segdat[2], segdat[3]); + set_stack32((segdat[3] & 0x40) ? 1 : 0); } else if (s!=&_cs) { @@ -354,19 +367,15 @@ void loadseg(uint16_t seg, x86seg *s) case 0x10: case 0x11: case 0x12: case 0x13: /*Data segments*/ case 0x14: case 0x15: case 0x16: case 0x17: case 0x1A: case 0x1B: /*Readable non-conforming code*/ -// pclog("Load seg %04X %i %i %04X:%08X\n",seg,dpl,CS&3,CS,cpu_state.pc); if ((seg&3)>dpl || (CPL)>dpl) { - // pclog("Data seg fail - %04X:%08X %04X %i %04X\n",CS,cpu_state.pc,seg,dpl,segdat[2]); x86gpf(NULL,seg&~3); -// x86abort("Data segment load - level too low!\n",seg&0xFFFC); return; } break; case 0x1E: case 0x1F: /*Readable conforming code*/ break; default: - // pclog("Invalid segment type for %04X! %04X\n",seg&0xFFFC,segdat[2]); x86gpf(NULL,seg&~3); return; } @@ -393,6 +402,10 @@ void loadseg(uint16_t seg, x86seg *s) } #endif s->checked = 0; + if (s == &_ds) + codegen_flat_ds = 0; + if (s == &_ss) + codegen_flat_ss = 0; } else { @@ -402,6 +415,26 @@ void loadseg(uint16_t seg, x86seg *s) if (s == &_ss) stack32 = 0; s->checked = 1; + if (s == &_ds) + codegen_flat_ds = 0; + if (s == &_ss) + codegen_flat_ss = 0; + } + + if (s == &_ds) + { + if (s->base == 0 && s->limit_low == 0 && s->limit_high == 0xffffffff) + cpu_cur_status |= CPU_STATUS_FLATDS; + else + + cpu_cur_status &= ~CPU_STATUS_FLATDS; + } + if (s == &_ss) + { + if (s->base == 0 && s->limit_low == 0 && s->limit_high == 0xffffffff) + cpu_cur_status |= CPU_STATUS_FLATSS; + else + cpu_cur_status &= ~CPU_STATUS_FLATSS; } } @@ -416,24 +449,16 @@ void loadcs(uint16_t seg) if (output) pclog("Load CS %04X\n",seg); if (msw&1 && !(eflags&VM_FLAG)) { -// intcount++; -// flushmmucache(); -// pclog("Load CS %04X\n",seg); if (!(seg&~3)) { - // pclog("Trying to load CS with NULL selector! lcs\n"); -// dumpregs(); -// exit(-1); x86gpf(NULL,0); return; } -// pclog("Protected mode CS load! %04X\n",seg); addr=seg&~7; if (seg&4) { if (addr>=ldt.limit) { - // pclog("Bigger than LDT limit %04X %04X CS\n",seg,ldt.limit); x86gpf(NULL,seg&~3); return; } @@ -443,7 +468,6 @@ void loadcs(uint16_t seg) { if (addr>=gdt.limit) { - // pclog("Bigger than GDT limit %04X %04X CS\n",seg,gdt.limit); x86gpf(NULL,seg&~3); return; } @@ -454,9 +478,6 @@ void loadcs(uint16_t seg) segdat[1]=readmemw(0,addr+2); segdat[2]=readmemw(0,addr+4); segdat[3]=readmemw(0,addr+6); cpl_override=0; if (cpu_state.abrt) return; - // if (optype==JMP) pclog("Code seg - %04X - %04X %04X %04X %04X\n",seg,segdat[0],segdat[1],segdat[2],segdat[3]); -// if (!(segdat[2]&0x8000)) x86abort("Code segment not present!\n"); -// if (output) pclog("Segdat2 %04X\n",segdat[2]); if (segdat[2]&0x1000) /*Normal code segment*/ { if (!(segdat[2]&0x400)) /*Not conforming*/ @@ -464,7 +485,6 @@ void loadcs(uint16_t seg) if ((seg&3)>CPL) { x86gpf(NULL,seg&~3); - // pclog("loadcs RPL > CPL %04X %04X %i %02X\n",segdat[2],seg,CPL,opcode); return; } if (CPL != DPL) @@ -483,8 +503,7 @@ void loadcs(uint16_t seg) x86np("Load CS not present", seg & 0xfffc); return; } - if (segdat[3]&0x40) use32=0x300; - else use32=0; + set_use32(segdat[3] & 0x40); CS=(seg&~3)|CPL; do_seg_load(&_cs, segdat); use32=(segdat[3]&0x40)?0x300:0; @@ -495,8 +514,6 @@ void loadcs(uint16_t seg) writememw(0, addr+4, segdat[2] | 0x100); /*Set accessed bit*/ cpl_override = 0; #endif -// if (output) pclog("Load CS %08X\n",_cs.base); -// CS=(CS&0xFFFC)|((_cs.access>>5)&3); } else /*System segment*/ { @@ -508,14 +525,10 @@ void loadcs(uint16_t seg) switch (segdat[2]&0xF00) { default: - // pclog("Bad CS %02X %02X %i special descriptor %03X %04X\n",opcode,rmdat,optype,segdat[2]&0xF00,seg); x86gpf(NULL,seg&~3); return; } } -// pclog("CS = %04X base=%06X limit=%04X access=%02X %04X\n",CS,cs,_cs.limit,_cs.access,addr); -// dumpregs(); -// exit(-1); } else { @@ -534,26 +547,20 @@ void loadcsjmp(uint16_t seg, uint32_t oxpc) { uint16_t segdat[4]; uint32_t addr; - int count; uint16_t type,seg2; uint32_t newpc; -// pclog("Load CS JMP %04X\n",seg); if (msw&1 && !(eflags&VM_FLAG)) { if (!(seg&~3)) { - // pclog("Trying to load CS with NULL selector! lcsjmp\n"); x86gpf(NULL,0); return; -// dumpregs(); -// exit(-1); } addr=seg&~7; if (seg&4) { if (addr>=ldt.limit) { - // pclog("Bigger than LDT limit %04X %04X CS\n",seg,ldt.limit); x86gpf(NULL,seg&~3); return; } @@ -563,7 +570,6 @@ void loadcsjmp(uint16_t seg, uint32_t oxpc) { if (addr>=gdt.limit) { - // pclog("Bigger than GDT limit %04X %04X CS\n",seg,gdt.limit); x86gpf(NULL,seg&~3); return; } @@ -577,7 +583,6 @@ void loadcsjmp(uint16_t seg, uint32_t oxpc) if (output) pclog("%04X %04X %04X %04X\n",segdat[0],segdat[1],segdat[2],segdat[3]); if (segdat[2]&0x1000) /*Normal code segment*/ { -// pclog("Normal CS\n"); if (!(segdat[2]&0x400)) /*Not conforming*/ { if ((seg&3)>CPL) @@ -601,8 +606,7 @@ void loadcsjmp(uint16_t seg, uint32_t oxpc) x86np("Load CS JMP not present\n", seg & 0xfffc); return; } - if (segdat[3]&0x40) use32=0x300; - else use32=0; + set_use32(segdat[3]&0x40); #ifdef CS_ACCESSED cpl_override = 1; @@ -615,15 +619,12 @@ void loadcsjmp(uint16_t seg, uint32_t oxpc) do_seg_load(&_cs, segdat); if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); - use32=(segdat[3]&0x40)?0x300:0; cycles -= timing_jmp_pm; } else /*System segment*/ { -// pclog("System CS\n"); if (!(segdat[2]&0x8000)) { - // x86np("Load CS JMP system selector not present\n", seg & 0xfffc); return; } type=segdat[2]&0xF00; @@ -633,12 +634,10 @@ void loadcsjmp(uint16_t seg, uint32_t oxpc) { case 0x400: /*Call gate*/ case 0xC00: -// pclog("Call gate\n"); cgate32=(type&0x800); cgate16=!cgate32; oldcs=CS; cpu_state.oldpc=cpu_state.pc; - count=segdat[2]&31; #if 0 if ((DPL < CPL) || (DPL < (seg&3))) { @@ -665,18 +664,14 @@ void loadcsjmp(uint16_t seg, uint32_t oxpc) if (!(seg2&~3)) { - // pclog("Trying to load CS with NULL selector! lcsjmpcg\n"); x86gpf(NULL,0); return; -// dumpregs(); -// exit(-1); } addr=seg2&~7; if (seg2&4) { if (addr>=ldt.limit) { - // pclog("Bigger than LDT limit %04X %04X CSJ\n",seg2,gdt.limit); x86gpf(NULL,seg2&~3); return; } @@ -686,7 +681,6 @@ void loadcsjmp(uint16_t seg, uint32_t oxpc) { if (addr>=gdt.limit) { - // pclog("Bigger than GDT limit %04X %04X CSJ\n",seg2,gdt.limit); x86gpf(NULL,seg2&~3); return; } @@ -715,7 +709,6 @@ void loadcsjmp(uint16_t seg, uint32_t oxpc) case 0x1800: case 0x1900: case 0x1A00: case 0x1B00: /*Non-conforming code*/ if (DPL > CPL) { - // pclog("Call gate DPL > CPL"); x86gpf(NULL,seg2&~3); return; } @@ -723,8 +716,8 @@ void loadcsjmp(uint16_t seg, uint32_t oxpc) CS=seg2; do_seg_load(&_cs, segdat); if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); - use32=(segdat[3]&0x40)?0x300:0; - cpu_state.pc=newpc; + set_use32(segdat[3]&0x40); + cpu_state.pc=newpc; #ifdef CS_ACCESSED cpl_override = 1; @@ -734,7 +727,6 @@ void loadcsjmp(uint16_t seg, uint32_t oxpc) break; default: - // pclog("JMP Call gate bad segment type\n"); x86gpf(NULL,seg2&~3); return; } @@ -742,29 +734,20 @@ void loadcsjmp(uint16_t seg, uint32_t oxpc) break; + case 0x100: /*286 Task gate*/ case 0x900: /*386 Task gate*/ -// pclog("Task gate\n"); cpu_state.pc=oxpc; cpl_override=1; taskswitch286(seg,segdat,segdat[2]&0x800); flags &= ~NT_FLAG; cpl_override=0; -// case 0xB00: /*386 Busy task gate*/ -// if (optype==JMP) pclog("Task switch!\n"); -// taskswitch386(seg,segdat); return; default: - // pclog("Bad JMP CS %02X %02X %i special descriptor %03X %04X\n",opcode,rmdat,optype,segdat[2]&0xF00,seg); x86gpf(NULL,0); return; -// dumpregs(); -// exit(-1); } } -// pclog("CS = %04X base=%06X limit=%04X access=%02X %04X\n",CS,cs,_cs.limit,_cs.access,addr); -// dumpregs(); -// exit(-1); } else { @@ -782,7 +765,6 @@ void loadcsjmp(uint16_t seg, uint32_t oxpc) void PUSHW(uint16_t v) { -// if (output==3) pclog("PUSHW %04X to %08X\n",v,ESP-4); if (stack32) { writememw(ss,ESP-2,v); @@ -791,7 +773,6 @@ void PUSHW(uint16_t v) } else { -// pclog("Write %04X to %08X\n", v, ss+((SP-2)&0xFFFF)); writememw(ss,((SP-2)&0xFFFF),v); if (cpu_state.abrt) return; SP-=2; @@ -799,7 +780,6 @@ void PUSHW(uint16_t v) } void PUSHL(uint32_t v) { -// if (output==3) pclog("PUSHL %08X to %08X\n",v,ESP-4); if (stack32) { writememl(ss,ESP-4,v); @@ -855,8 +835,7 @@ void loadcscall(uint16_t seg) uint32_t addr,oldssbase=ss, oaddr; uint32_t newpc; int count; - uint16_t oldcs=CPL; - uint32_t oldss,oldsp,newsp,oldpc, oldsp2; + uint32_t oldss,oldsp,newsp, oldsp2; int type; uint16_t tempw; @@ -864,22 +843,17 @@ void loadcscall(uint16_t seg) if (msw&1 && !(eflags&VM_FLAG)) { - //flushmmucache(); if (csout) pclog("Protected mode CS load! %04X\n",seg); if (!(seg&~3)) { - // pclog("Trying to load CS with NULL selector! lcscall\n"); x86gpf(NULL,0); return; -// dumpregs(); -// exit(-1); } addr=seg&~7; if (seg&4) { if (addr>=ldt.limit) { - // pclog("Bigger than LDT limit %04X %04X CSC\n",seg,gdt.limit); x86gpf(NULL,seg&~3); return; } @@ -889,7 +863,6 @@ void loadcscall(uint16_t seg) { if (addr>=gdt.limit) { - // pclog("Bigger than GDT limit %04X %04X CSC\n",seg,gdt.limit); x86gpf(NULL,seg&~3); return; } @@ -911,31 +884,26 @@ void loadcscall(uint16_t seg) { if ((seg&3)>CPL) { - /* if (csout) */ // pclog("Not conforming, RPL > CPL\n"); x86gpf("loadcscall(): segment > CPL",seg&~3); return; } if (CPL != DPL) { - /* if (csout) */ // pclog("Not conforming, CPL != DPL (%i %i)\n",CPL,DPL); x86gpf(NULL,seg&~3); return; } } if (CPL < DPL) { - /* if (csout) */ // pclog("CPL < DPL\n"); x86gpf(NULL,seg&~3); return; } if (!(segdat[2]&0x8000)) { - /* if (csout) */ // pclog("Not present\n"); x86np("Load CS call not present", seg & 0xfffc); return; } - if (segdat[3]&0x40) use32=0x300; - else use32=0; + set_use32(segdat[3]&0x40); #ifdef CS_ACCESSED cpl_override = 1; @@ -954,7 +922,6 @@ void loadcscall(uint16_t seg) CS=seg; do_seg_load(&_cs, segdat); if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); - use32=(segdat[3]&0x40)?0x300:0; if (csout) pclog("Complete\n"); cycles -= timing_call_pm; } @@ -970,15 +937,7 @@ void loadcscall(uint16_t seg) cgate32=(type&0x800); cgate16=!cgate32; oldcs=CS; - oldpc=cpu_state.pc; count=segdat[2]&31; -#if 0 - if ((DPL < CPL) || (DPL < (seg&3))) - { - x86gpf("",seg&~3); - return; - } -#endif if ((DPL < CPL)) { x86gpf("loadcscall(): ex DPL < CPL",seg&~3); @@ -1001,18 +960,14 @@ void loadcscall(uint16_t seg) if (!(seg2&~3)) { - // pclog("Trying to load CS with NULL selector! lcscallcg\n"); x86gpf(NULL,0); return; -// dumpregs(); -// exit(-1); } addr=seg2&~7; if (seg2&4) { if (addr>=ldt.limit) { - // pclog("Bigger than LDT limit %04X %04X CSC\n",seg2,gdt.limit); x86gpf(NULL,seg2&~3); return; } @@ -1022,7 +977,6 @@ void loadcscall(uint16_t seg) { if (addr>=gdt.limit) { - // pclog("Bigger than GDT limit %04X %04X CSC\n",seg2,gdt.limit); x86gpf(NULL,seg2&~3); return; } @@ -1076,7 +1030,6 @@ void loadcscall(uint16_t seg) if (output) pclog("New stack %04X:%08X\n",newss,newsp); if (!(newss&~3)) { - // pclog("Call gate loading null SS\n"); x86ts(NULL,newss&~3); return; } @@ -1110,27 +1063,22 @@ void loadcscall(uint16_t seg) if (output) pclog("Read stack seg done!\n"); if (((newss & 3) != DPL) || (DPL2 != DPL)) { - // pclog("Call gate loading SS with wrong permissions %04X %04X %i %i %04X %04X\n", newss, seg2, DPL, DPL2, segdat[2], segdat2[2]); -// dumpregs(); -// exit(-1); x86ts(NULL,newss&~3); return; } if ((segdat2[2]&0x1A00)!=0x1200) { - // pclog("Call gate loading SS wrong type\n"); x86ts(NULL,newss&~3); return; } if (!(segdat2[2]&0x8000)) { - // pclog("Call gate loading SS not present\n"); x86np("Call gate loading SS not present\n", newss & 0xfffc); return; } if (!stack32) oldsp &= 0xFFFF; SS=newss; - stack32 = (segdat2[3] & 0x40) ? 1 : 0; + set_stack32((segdat2[3] & 0x40) ? 1 : 0); if (stack32) ESP=newsp; else SP=newsp; @@ -1147,7 +1095,7 @@ void loadcscall(uint16_t seg) CS=seg2; do_seg_load(&_cs, segdat); if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); - use32=(segdat[3]&0x40)?0x300:0; + set_use32(segdat[3]&0x40); cpu_state.pc=newpc; if (output) pclog("Set access 2\n"); @@ -1165,12 +1113,10 @@ void loadcscall(uint16_t seg) PUSHL(oldsp2); if (cpu_state.abrt) { - // pclog("ABRT PUSHL\n"); SS = oldss; ESP = oldsp2; return; } -// if (output) pclog("Stack now %04X:%08X\n",SS,ESP); if (count) { while (count) @@ -1179,16 +1125,12 @@ void loadcscall(uint16_t seg) PUSHL(readmeml(oldssbase,oldsp+(count*4))); if (cpu_state.abrt) { - // pclog("ABRT COPYL\n"); SS = oldss; ESP = oldsp2; return; } } } -// x86abort("Call gate with count %i\n",count); -// PUSHL(oldcs); -// PUSHL(oldpc); if (cpu_state.abrt) return; } else { @@ -1198,14 +1140,11 @@ void loadcscall(uint16_t seg) PUSHW(oldsp2); if (cpu_state.abrt) { - // pclog("ABRT PUSHW\n"); SS = oldss; ESP = oldsp2; return; } if (output) pclog("Write SP to %04X:%04X\n",SS,SP); -// if (output) pclog("Stack %04X %i %04X:%04X\n",SP,count,oldssbase,oldsp); -// if (output) pclog("PUSH %04X %04X %i %i now %04X:%08X\n",oldss,oldsp,count,stack32,SS,ESP); if (count) { while (count) @@ -1216,43 +1155,27 @@ void loadcscall(uint16_t seg) PUSHW(tempw); if (cpu_state.abrt) { - // pclog("ABRT COPYW\n"); SS = oldss; ESP = oldsp2; return; } } } -// if (output) pclog("Stack %04X\n",SP); -// if (count) x86abort("Call gate with count\n"); -// PUSHW(oldcs); -// PUSHW(oldpc); if (cpu_state.abrt) return; } cycles -= timing_call_pm_gate_inner; break; } else if (DPL > CPL) { - // pclog("Call gate DPL > CPL"); x86gpf(NULL,seg2&~3); return; } case 0x1C00: case 0x1D00: case 0x1E00: case 0x1F00: /*Conforming*/ -/* if (type==0xC00) - { - PUSHL(oldcs); - PUSHL(oldpc); if (cpu_state.abrt) return; - } - else - { - PUSHW(oldcs); - PUSHW(oldpc); if (cpu_state.abrt) return; - }*/ CS=seg2; do_seg_load(&_cs, segdat); if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); - use32=(segdat[3]&0x40)?0x300:0; - cpu_state.pc=newpc; + set_use32(segdat[3]&0x40); + cpu_state.pc=newpc; #ifdef CS_ACCESSED cpl_override = 1; @@ -1263,30 +1186,16 @@ void loadcscall(uint16_t seg) break; default: - // pclog("Call gate bad segment type\n"); x86gpf(NULL,seg2&~3); return; } break; -// case 0x900: /*386 Task gate*/ -// case 0xB00: /*386 Busy task gate*/ -// if (optype==JMP) pclog("Task switch!\n"); -// taskswitch386(seg,segdat); -// return; - - default: - // pclog("Bad CALL special descriptor %03X\n",segdat[2]&0xF00); x86gpf(NULL,seg&~3); return; -// dumpregs(); -// exit(-1); } } -// pclog("CS = %04X base=%06X limit=%04X access=%02X %04X\n",CS,cs,_cs.limit,_cs.access,addr); -// dumpregs(); -// exit(-1); } else { @@ -1324,20 +1233,12 @@ void pmoderetf(int is32, uint16_t off) if (output) pclog("Return to %04X:%08X\n",seg,newpc); if ((seg&3)=ldt.limit) { - // pclog("Bigger than LDT limit %04X %04X RETF\n",seg,ldt.limit); x86gpf(NULL,seg&~3); return; } @@ -1356,10 +1256,7 @@ void pmoderetf(int is32, uint16_t off) { if (addr>=gdt.limit) { - // pclog("Bigger than GDT limit %04X %04X RETF\n",seg,gdt.limit); x86gpf(NULL,seg&~3); -// dumpregs(); -// exit(-1); return; } addr+=gdt.base; @@ -1384,7 +1281,6 @@ void pmoderetf(int is32, uint16_t off) case 0x1800: case 0x1900: case 0x1A00: case 0x1B00: /*Non-conforming*/ if (CPL != DPL) { - // pclog("RETF non-conforming CPL != DPL\n"); ESP=oldsp; x86gpf(NULL,seg&~3); return; @@ -1393,20 +1289,17 @@ void pmoderetf(int is32, uint16_t off) case 0x1C00: case 0x1D00: case 0x1E00: case 0x1F00: /*Conforming*/ if (CPL < DPL) { - // pclog("RETF non-conforming CPL < DPL\n"); ESP=oldsp; x86gpf(NULL,seg&~3); return; } break; default: - // pclog("RETF CS not code segment\n"); x86gpf(NULL,seg&~3); return; } if (!(segdat[2]&0x8000)) { - // pclog("RETF CS not present %i %04X %04X %04X\n",ins, segdat[0], segdat[1], segdat[2]); ESP=oldsp; x86np("RETF CS not present\n", seg & 0xfffc); return; @@ -1425,9 +1318,8 @@ void pmoderetf(int is32, uint16_t off) do_seg_load(&_cs, segdat); _cs.access = (_cs.access & ~(3 << 5)) | ((CS & 3) << 5); if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); - use32=(segdat[3]&0x40)?0x300:0; - -// pclog("CPL=RPL return to %04X:%08X\n",CS,cpu_state.pc); + set_use32(segdat[3] & 0x40); + cycles -= timing_retf_pm; } else @@ -1437,7 +1329,6 @@ void pmoderetf(int is32, uint16_t off) case 0x1800: case 0x1900: case 0x1A00: case 0x1B00: /*Non-conforming*/ if ((seg&3) != DPL) { - // pclog("RETF non-conforming RPL != DPL\n"); ESP=oldsp; x86gpf(NULL,seg&~3); return; @@ -1447,7 +1338,6 @@ void pmoderetf(int is32, uint16_t off) case 0x1C00: case 0x1D00: case 0x1E00: case 0x1F00: /*Conforming*/ if ((seg&3) < DPL) { - // pclog("RETF non-conforming RPL < DPL\n"); ESP=oldsp; x86gpf(NULL,seg&~3); return; @@ -1455,15 +1345,12 @@ void pmoderetf(int is32, uint16_t off) if (output) pclog("RETF conforming, %i %i\n",seg&3, DPL); break; default: - // pclog("RETF CS not code segment\n"); ESP=oldsp; x86gpf(NULL,seg&~3); return; } if (!(segdat[2]&0x8000)) { - // pclog("RETF CS not present! %i %04X %04X %04X\n",ins, segdat[0], segdat[1], segdat[2]); - ESP=oldsp; x86np("RETF CS not present\n", seg & 0xfffc); return; @@ -1472,7 +1359,6 @@ void pmoderetf(int is32, uint16_t off) { newsp=POPL(); newss=POPL(); if (cpu_state.abrt) return; -// pclog("is32 new stack %04X:%04X\n",newss,newsp); } else { @@ -1480,12 +1366,10 @@ void pmoderetf(int is32, uint16_t off) newsp=POPW(); if (output) pclog("SS read from %04X:%04X\n",SS,SP); newss=POPW(); if (cpu_state.abrt) return; -// pclog("!is32 new stack %04X:%04X\n",newss,newsp); } if (output) pclog("Read new stack : %04X:%04X (%08X)\n", newss, newsp, ldt.base); if (!(newss&~3)) { - // pclog("RETF loading null SS\n"); ESP=oldsp; x86gpf(NULL,newss&~3); return; @@ -1495,7 +1379,6 @@ void pmoderetf(int is32, uint16_t off) { if (addr>=ldt.limit) { - // pclog("Bigger than LDT limit %04X %04X RETF SS\n",newss,gdt.limit); ESP=oldsp; x86gpf(NULL,newss&~3); return; @@ -1506,7 +1389,6 @@ void pmoderetf(int is32, uint16_t off) { if (addr>=gdt.limit) { - // pclog("Bigger than GDT limit %04X %04X RETF SS\n",newss,gdt.limit); ESP=oldsp; x86gpf(NULL,newss&~3); return; @@ -1519,42 +1401,32 @@ void pmoderetf(int is32, uint16_t off) segdat2[2]=readmemw(0,addr+4); segdat2[3]=readmemw(0,addr+6); cpl_override=0; if (cpu_state.abrt) { ESP=oldsp; return; } if (output) pclog("Segment data %04X %04X %04X %04X\n", segdat2[0], segdat2[1], segdat2[2], segdat2[3]); -// if (((newss & 3) != DPL) || (DPL2 != DPL)) if ((newss & 3) != (seg & 3)) { - // pclog("RETF loading SS with wrong permissions %i %i %04X %04X\n", newss & 3, seg & 3, newss, seg); ESP=oldsp; -// output = 3; -// dumpregs(); -// exit(-1); x86gpf(NULL,newss&~3); return; } if ((segdat2[2]&0x1A00)!=0x1200) { - // pclog("RETF loading SS wrong type\n"); ESP=oldsp; -// dumpregs(); -// exit(-1); x86gpf(NULL,newss&~3); return; } if (!(segdat2[2]&0x8000)) { - // pclog("RETF loading SS not present\n"); ESP=oldsp; x86np("RETF loading SS not present\n", newss & 0xfffc); return; } if (DPL2 != (seg & 3)) { - // pclog("RETF loading SS with wrong permissions2 %i %i %04X %04X\n", DPL2, seg & 3, newss, seg); ESP=oldsp; x86gpf(NULL,newss&~3); return; } SS=newss; - stack32 = (segdat2[3] & 0x40) ? 1 : 0; + set_stack32((segdat2[3] & 0x40) ? 1 : 0); if (stack32) ESP=newsp; else SP=newsp; do_seg_load(&_ss, segdat2); @@ -1576,7 +1448,7 @@ void pmoderetf(int is32, uint16_t off) CS=seg; do_seg_load(&_cs, segdat); if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); - use32=(segdat[3]&0x40)?0x300:0; + set_use32(segdat[3] & 0x40); if (stack32) ESP+=off; else SP+=off; @@ -1585,7 +1457,6 @@ void pmoderetf(int is32, uint16_t off) check_seg_valid(&_es); check_seg_valid(&_fs); check_seg_valid(&_gs); -// pclog("CPL=idt.limit) @@ -1624,19 +1489,15 @@ void pmodeint(int num, int soft) if (num==8) { /*Triple fault - reset!*/ - // pclog("Triple fault!\n"); -// output=1; softresetx86(); cpu_set_edx(); } else if (num==0xD) { - // pclog("Double fault!\n"); pmodeint(8,0); } else { - // pclog("INT out of range\n"); x86gpf(NULL,(num*8)+2+((soft)?0:1)); } if (output) pclog("addr >= IDT.limit\n"); @@ -1653,39 +1514,32 @@ void pmodeint(int num, int soft) if (output) pclog("Addr %08X seg %04X %04X %04X %04X\n",addr,segdat[0],segdat[1],segdat[2],segdat[3]); if (!(segdat[2]&0x1F00)) { - // pclog("No seg\n"); x86gpf(NULL,(num*8)+2); return; } if (DPL=0x800)?32:16; -// if (output) pclog("Int gate %04X %i oldpc %04X pc %04X\n",type,intgatesize,oldpc,cpu_state.pc); if (!(segdat[2]&0x8000)) { - // pclog("Int gate not present\n"); x86np("Int gate not present\n", (num << 3) | 2); return; } seg=segdat[1]; new_cpl = seg & 3; -// pclog("Interrupt gate : %04X:%04X%04X\n",seg,segdat[3],segdat[0]); addr=seg&~7; if (seg&4) { if (addr>=ldt.limit) { - // pclog("Bigger than LDT limit %04X %04X INT\n",seg,gdt.limit); x86gpf(NULL,seg&~3); return; } @@ -1695,18 +1549,11 @@ void pmodeint(int num, int soft) { if (addr>=gdt.limit) { - // pclog("Bigger than GDT limit %04X %04X INT %i\n",seg,gdt.limit,ins); x86gpf(NULL,seg&~3); return; } addr+=gdt.base; } -/* if ((seg&3) < CPL) - { - // pclog("INT to higher level\n"); - x86gpf(NULL,seg&~3); - return; - }*/ cpl_override=1; segdat2[0]=readmemw(0,addr); segdat2[1]=readmemw(0,addr+2); @@ -1716,26 +1563,21 @@ void pmodeint(int num, int soft) if (DPL2 > CPL) { - // pclog("INT to higher level 2\n"); x86gpf(NULL,seg&~3); return; } - //pclog("Type %04X\n",segdat2[2]); switch (segdat2[2]&0x1F00) { case 0x1800: case 0x1900: case 0x1A00: case 0x1B00: /*Non-conforming*/ if (DPL2=ldt.limit) { - // pclog("Bigger than LDT limit %04X %04X PMODEINT SS\n",newss,gdt.limit); x86ss(NULL,newss&~3); return; } @@ -1777,7 +1617,6 @@ void pmodeint(int num, int soft) { if (addr>=gdt.limit) { - // pclog("Bigger than GDT limit %04X %04X CSC\n",newss,gdt.limit); x86ss(NULL,newss&~3); return; } @@ -1790,24 +1629,21 @@ void pmodeint(int num, int soft) segdat3[3]=readmemw(0,addr+6); cpl_override=0; if (cpu_state.abrt) return; if (((newss & 3) != DPL2) || (DPL3 != DPL2)) { - // pclog("Int gate loading SS with wrong permissions\n"); x86ss(NULL,newss&~3); return; } if ((segdat3[2]&0x1A00)!=0x1200) { - // pclog("Int gate loading SS wrong type\n"); x86ss(NULL,newss&~3); return; } if (!(segdat3[2]&0x8000)) { - // pclog("Int gate loading SS not present\n"); x86np("Int gate loading SS not present\n", newss & 0xfffc); return; } SS=newss; - stack32 = (segdat3[3] & 0x40) ? 1 : 0; + set_stack32((segdat3[3] & 0x40) ? 1 : 0); if (stack32) ESP=newsp; else SP=newsp; do_seg_load(&_ss, segdat3); @@ -1822,7 +1658,6 @@ void pmodeint(int num, int soft) cpl_override=1; if (type>=0x800) { -// if (output) pclog("Push 32 %i\n",eflags&VM_FLAG); if (eflags & VM_FLAG) { PUSHL(GS); @@ -1837,82 +1672,63 @@ void pmodeint(int num, int soft) PUSHL(oldss); PUSHL(oldsp); PUSHL(flags|(eflags<<16)); -// if (soft) pclog("Pushl CS %08X\n", CS); PUSHL(CS); -// if (soft) pclog("Pushl PC %08X\n", cpu_state.pc); PUSHL(cpu_state.pc); if (cpu_state.abrt) return; -// if (output) pclog("32Stack %04X:%08X\n",SS,ESP); } else { -// if (output) pclog("Push 16\n"); PUSHW(oldss); PUSHW(oldsp); PUSHW(flags); -// if (soft) pclog("Pushw CS %04X\n", CS); PUSHW(CS); -// if (soft) pclog("Pushw pc %04X\n", cpu_state.pc); PUSHW(cpu_state.pc); if (cpu_state.abrt) return; -// if (output) pclog("16Stack %04X:%08X\n",SS,ESP); } cpl_override=0; _cs.access=0 | 0x80; cycles -= timing_int_pm_outer - timing_int_pm; -// pclog("Non-confirming int gate, CS = %04X\n"); break; } else if (DPL2!=CPL) { - // pclog("Non-conforming int gate DPL != CPL\n"); x86gpf(NULL,seg&~3); return; } case 0x1C00: case 0x1D00: case 0x1E00: case 0x1F00: /*Conforming*/ if (!(segdat2[2]&0x8000)) { - // pclog("Int gate CS not present\n"); x86np("Int gate CS not present\n", segdat[1] & 0xfffc); return; } if ((eflags & VM_FLAG) && DPL20x800) { PUSHL(flags|(eflags<<16)); -// if (soft) pclog("Pushlc CS %08X\n", CS); PUSHL(CS); -// if (soft) pclog("Pushlc PC %08X\n", cpu_state.pc); PUSHL(cpu_state.pc); if (cpu_state.abrt) return; } else { PUSHW(flags); -// if (soft) pclog("Pushwc CS %04X\n", CS); PUSHW(CS); -// if (soft) pclog("Pushwc PC %04X\n", cpu_state.pc); PUSHW(cpu_state.pc); if (cpu_state.abrt) return; } new_cpl = CS & 3; break; default: - // pclog("Int gate CS not code segment - %04X %04X %04X %04X\n",segdat2[0],segdat2[1],segdat2[2],segdat2[3]); x86gpf(NULL,seg&~3); return; } do_seg_load(&_cs, segdat2); CS = (seg & ~3) | new_cpl; _cs.access = (_cs.access & ~(3 << 5)) | (new_cpl << 5); -// pclog("New CS = %04X\n",CS); if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); if (type>0x800) cpu_state.pc=segdat[0]|(segdat[3]<<16); else cpu_state.pc=segdat[0]; - use32=(segdat2[3]&0x40)?0x300:0; -// pclog("Int gate done!\n"); + set_use32(segdat2[3]&0x40); #ifdef CS_ACCESSED cpl_override = 1; @@ -1924,22 +1740,18 @@ void pmodeint(int num, int soft) if (!(type&0x100)) { flags&=~I_FLAG; -// pclog("INT %02X disabling interrupts %i\n",num,soft); } flags&=~(T_FLAG|NT_FLAG); -// if (output) pclog("Final Stack %04X:%08X\n",SS,ESP); cycles -= timing_int_pm; break; case 0x500: /*Task gate*/ -// pclog("Task gate\n"); seg=segdat[1]; addr=seg&~7; if (seg&4) { if (addr>=ldt.limit) { - // pclog("Bigger than LDT limit %04X %04X INT\n",seg,gdt.limit); x86gpf(NULL,seg&~3); return; } @@ -1949,7 +1761,6 @@ void pmodeint(int num, int soft) { if (addr>=gdt.limit) { - // pclog("Bigger than GDT limit %04X %04X INT %i\n",seg,gdt.limit,ins); x86gpf(NULL,seg&~3); return; } @@ -1963,7 +1774,6 @@ void pmodeint(int num, int soft) cpl_override=0; if (cpu_state.abrt) return; if (!(segdat2[2]&0x8000)) { - // pclog("Int task gate not present\n"); x86np("Int task gate not present\n", segdat[1] & 0xfffc); return; } @@ -1974,7 +1784,6 @@ void pmodeint(int num, int soft) break; default: - // pclog("Bad int gate type %04X %04X %04X %04X %04X\n",segdat[2]&0x1F00,segdat[0],segdat[1],segdat[2],segdat[3]); x86gpf(NULL,seg&~3); return; } @@ -1993,10 +1802,8 @@ void pmodeiret(int is32) uint32_t oldsp=ESP; if (is386 && (eflags&VM_FLAG)) { -// if (output) pclog("V86 IRET\n"); if (IOPL!=3) { - // pclog("V86 IRET! IOPL!=3\n"); x86gpf(NULL,0); return; } @@ -2025,31 +1832,21 @@ void pmodeiret(int is32) return; } -// pclog("IRET %i\n",is32); - //flushmmucache(); -// if (output) pclog("Pmode IRET %04X:%04X ",CS,cpu_state.pc); - if (flags&NT_FLAG) { -// pclog("NT IRET\n"); seg=readmemw(tr.base,0); addr=seg&~7; if (seg&4) { - if (addr>=ldt.limit) - { - // pclog("TS Bigger than LDT limit %04X %04X IRET\n",seg,gdt.limit); - x86gpf(NULL,seg&~3); - return; - } - addr+=ldt.base; + pclog("TS LDT %04X %04X IRET\n",seg,gdt.limit); + x86ts(NULL,seg&~3); + return; } else { if (addr>=gdt.limit) { - // pclog("TS Bigger than GDT limit %04X %04X IRET\n",seg,gdt.limit); - x86gpf(NULL,seg&~3); + x86ts(NULL,seg&~3); return; } addr+=gdt.base; @@ -2067,38 +1864,30 @@ void pmodeiret(int is32) flagmask=0xFFFF; if (CPL) flagmask&=~0x3000; if (IOPL>16)&VM_FLAG)) { -// pclog("IRETD to V86\n"); - newsp=POPL(); newss=POPL(); segs[0]=POPL(); segs[1]=POPL(); segs[2]=POPL(); segs[3]=POPL(); if (cpu_state.abrt) { ESP = oldsp; return; } -// pclog("Pop stack %04X:%04X\n",newss,newsp); eflags=tempflags>>16; loadseg(segs[0],&_es); do_seg_v86_init(&_es); loadseg(segs[1],&_ds); do_seg_v86_init(&_ds); + cpu_cur_status &= ~CPU_STATUS_FLATDS; loadseg(segs[2],&_fs); do_seg_v86_init(&_fs); loadseg(segs[3],&_gs); do_seg_v86_init(&_gs); -// pclog("V86 IRET %04X:%08X\n",SS,ESP); -// output=3; - cpu_state.pc=newpc; _cs.base=seg<<4; _cs.limit=0xFFFF; @@ -2111,15 +1900,11 @@ void pmodeiret(int is32) ESP=newsp; loadseg(newss,&_ss); do_seg_v86_init(&_ss); + cpu_cur_status &= ~CPU_STATUS_FLATSS; use32=0; + cpu_cur_status &= ~CPU_STATUS_USE32; flags=(tempflags&0xFFD5)|2; cycles -= timing_iret_v86; -// pclog("V86 IRET to %04X:%04X %04X:%04X %04X %04X %04X %04X %i\n",CS,cpu_state.pc,SS,SP,DS,ES,FS,GS,cpu_state.abrt); - // if (CS==0xFFFF && pc==0xFFFFFFFF) timetolive=12; -/* { - dumpregs(); - exit(-1); - }*/ return; } } @@ -2129,25 +1914,18 @@ void pmodeiret(int is32) seg=POPW(); tempflags=POPW(); if (cpu_state.abrt) { ESP = oldsp; return; } } -// if (!is386) tempflags&=0xFFF; -// pclog("Returned to %04X:%08X %04X %04X %i\n",seg,newpc,flags,tempflags, ins); if (!(seg&~3)) { - // pclog("IRET CS=0\n"); ESP = oldsp; -// dumpregs(); -// exit(-1); x86gpf(NULL,0); return; } -// if (output) pclog("IRET %04X:%08X\n",seg,newpc); addr=seg&~7; if (seg&4) { if (addr>=ldt.limit) { - // pclog("Bigger than LDT limit %04X %04X IRET\n",seg,gdt.limit); ESP = oldsp; x86gpf(NULL,seg&~3); return; @@ -2158,7 +1936,6 @@ void pmodeiret(int is32) { if (addr>=gdt.limit) { - // pclog("Bigger than GDT limit %04X %04X IRET\n",seg,gdt.limit); ESP = oldsp; x86gpf(NULL,seg&~3); return; @@ -2167,7 +1944,6 @@ void pmodeiret(int is32) } if ((seg&3) < CPL) { - // pclog("IRET to lower level\n"); ESP = oldsp; x86gpf(NULL,seg&~3); return; @@ -2177,17 +1953,13 @@ void pmodeiret(int is32) segdat[1]=readmemw(0,addr+2); segdat[2]=readmemw(0,addr+4); segdat[3]=readmemw(0,addr+6); cpl_override=0; if (cpu_state.abrt) { ESP = oldsp; return; } -// pclog("Seg type %04X %04X\n",segdat[2]&0x1F00,segdat[2]); switch (segdat[2]&0x1F00) { case 0x1800: case 0x1900: case 0x1A00: case 0x1B00: /*Non-conforming code*/ if ((seg&3) != DPL) { - // pclog("IRET NC DPL %04X %04X %04X %04X %04X\n", seg, segdat[0], segdat[1], segdat[2], segdat[3]); ESP = oldsp; -// dumpregs(); -// exit(-1); x86gpf(NULL,seg&~3); return; } @@ -2195,36 +1967,29 @@ void pmodeiret(int is32) case 0x1C00: case 0x1D00: case 0x1E00: case 0x1F00: /*Conforming code*/ if ((seg&3) < DPL) { - // pclog("IRET C DPL\n"); ESP = oldsp; x86gpf(NULL,seg&~3); return; } break; default: - // pclog("IRET CS != code seg\n"); ESP = oldsp; x86gpf(NULL,seg&~3); -// dumpregs(); -// exit(-1); return; } if (!(segdat[2]&0x8000)) { - // pclog("IRET CS not present %i %04X %04X %04X\n",ins, segdat[0], segdat[1], segdat[2]); ESP = oldsp; x86np("IRET CS not present\n", seg & 0xfffc); return; } -// pclog("Seg %04X CPL %04X\n",seg,CPL); if ((seg&3) == CPL) { -// pclog("Same level\n"); CS=seg; do_seg_load(&_cs, segdat); _cs.access = (_cs.access & ~(3 << 5)) | ((CS & 3) << 5); if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); - use32=(segdat[3]&0x40)?0x300:0; + set_use32(segdat[3]&0x40); #ifdef CS_ACCESSED cpl_override = 1; @@ -2252,7 +2017,6 @@ void pmodeiret(int is32) if (!(newss&~3)) { - // pclog("IRET loading null SS\n"); ESP = oldsp; x86gpf(NULL,newss&~3); return; @@ -2262,7 +2026,6 @@ void pmodeiret(int is32) { if (addr>=ldt.limit) { - // pclog("Bigger than LDT limit %04X %04X PMODEIRET SS\n",newss,gdt.limit); ESP = oldsp; x86gpf(NULL,newss&~3); return; @@ -2273,7 +2036,6 @@ void pmodeiret(int is32) { if (addr>=gdt.limit) { - // pclog("Bigger than GDT limit %04X %04X PMODEIRET\n",newss,gdt.limit); ESP = oldsp; x86gpf(NULL,newss&~3); return; @@ -2285,40 +2047,32 @@ void pmodeiret(int is32) segdat2[1]=readmemw(0,addr+2); segdat2[2]=readmemw(0,addr+4); segdat2[3]=readmemw(0,addr+6); cpl_override=0; if (cpu_state.abrt) { ESP = oldsp; return; } -// pclog("IRET SS sd2 %04X\n",segdat2[2]); -// if (((newss & 3) != DPL) || (DPL2 != DPL)) if ((newss & 3) != (seg & 3)) { - // pclog("IRET loading SS with wrong permissions %04X %04X\n", newss, seg); ESP = oldsp; -// dumpregs(); -// exit(-1); x86gpf(NULL,newss&~3); return; } if ((segdat2[2]&0x1A00)!=0x1200) { - // pclog("IRET loading SS wrong type\n"); ESP = oldsp; x86gpf(NULL,newss&~3); return; } if (DPL2 != (seg & 3)) { - // pclog("IRET loading SS with wrong permissions2 %i %i %04X %04X\n", DPL2, seg & 3, newss, seg); ESP = oldsp; x86gpf(NULL,newss&~3); return; } if (!(segdat2[2]&0x8000)) { - // pclog("IRET loading SS not present\n"); ESP = oldsp; x86np("IRET loading SS not present\n", newss & 0xfffc); return; } SS=newss; - stack32 = (segdat2[3] & 0x40) ? 1 : 0; + set_stack32((segdat2[3] & 0x40) ? 1 : 0); if (stack32) ESP=newsp; else SP=newsp; do_seg_load(&_ss, segdat2); @@ -2340,7 +2094,7 @@ void pmodeiret(int is32) do_seg_load(&_cs, segdat); _cs.access = (_cs.access & ~(3 << 5)) | ((CS & 3) << 5); if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); - use32=(segdat[3]&0x40)?0x300:0; + set_use32(segdat[3] & 0x40); check_seg_valid(&_ds); check_seg_valid(&_es); @@ -2351,7 +2105,6 @@ void pmodeiret(int is32) cpu_state.pc=newpc; flags=(flags&~flagmask)|(tempflags&flagmask&0xFFD5)|2; if (is32) eflags=tempflags>>16; -// pclog("done\n"); } void taskswitch286(uint16_t seg, uint16_t *segdat, int is32) @@ -2371,17 +2124,14 @@ void taskswitch286(uint16_t seg, uint16_t *segdat, int is32) uint16_t segdat2[4]; -//output=3; - base=segdat[1]|((segdat[2]&0xFF)<<16)|((segdat[3]>>8)<<24); - limit=segdat[0]|((segdat[3]&0xF)<<16); -// pclog("286 Task switch! %04X:%04X\n",CS,cpu_state.pc); -/// pclog("TSS %04X base %08X limit %04X old TSS %04X %08X %i\n",seg,base,limit,tr.seg,tr.base,ins); -// / pclog("%04X %04X %04X %04X\n",segdat[0],segdat[1],segdat[2],segdat[3]); + base=segdat[1]|((segdat[2]&0xFF)<<16); + limit=segdat[0]; - if (is386) + if (is32) { -// if (output) pclog("32-bit TSS\n"); - + base |= (segdat[3]>>8)<<24; + limit |= (segdat[3]&0xF)<<16; + new_cr3=readmeml(base,0x1C); new_pc=readmeml(base,0x20); new_flags=readmeml(base,0x24); @@ -2396,7 +2146,6 @@ void taskswitch286(uint16_t seg, uint16_t *segdat, int is32) new_edi=readmeml(base,0x44); new_es=readmemw(base,0x48); -// if (output) pclog("Read CS from %08X\n",base+0x4C); new_cs=readmemw(base,0x4C); new_ss=readmemw(base,0x50); new_ds=readmemw(base,0x54); @@ -2417,7 +2166,6 @@ void taskswitch286(uint16_t seg, uint16_t *segdat, int is32) if (optype==IRET) flags&=~NT_FLAG; -// if (output) pclog("Write PC %08X %08X\n",tr.base,cpu_state.pc); cpu_386_flags_rebuild(); writememl(tr.base,0x1C,cr3); writememl(tr.base,0x20,cpu_state.pc); @@ -2433,7 +2181,6 @@ void taskswitch286(uint16_t seg, uint16_t *segdat, int is32) writememl(tr.base,0x44,EDI); writememl(tr.base,0x48,ES); -// if (output) pclog("Write CS %04X to %08X\n",CS,tr.base+0x4C); writememl(tr.base,0x4C,CS); writememl(tr.base,0x50,SS); writememl(tr.base,0x54,DS); @@ -2460,41 +2207,31 @@ void taskswitch286(uint16_t seg, uint16_t *segdat, int is32) cr3=new_cr3; -// pclog("TS New CR3 %08X\n",cr3); flushmmucache(); - - - + cpu_state.pc=new_pc; -// if (output) pclog("New pc %08X\n",new_pc); flags=new_flags; eflags=new_flags>>16; cpu_386_flags_extract(); -// if (output) pclog("Load LDT %04X\n",new_ldt); ldt.seg=new_ldt; templ=(ldt.seg&~7)+gdt.base; -// if (output) pclog("Load from %08X %08X\n",templ,gdt.base); ldt.limit=readmemw(0,templ); - if (readmemb(templ+6)&0x80) + if (readmemb(0,templ+6)&0x80) { ldt.limit<<=12; ldt.limit|=0xFFF; } - ldt.base=(readmemw(0,templ+2))|(readmemb(templ+4)<<16)|(readmemb(templ+7)<<24); -// if (output) pclog("Limit %04X Base %08X\n",ldt.limit,ldt.base); - + ldt.base=(readmemw(0,templ+2))|(readmemb(0,templ+4)<<16)|(readmemb(0,templ+7)<<24); if (eflags&VM_FLAG) { - // pclog("Task switch V86!\n"); x86gpf(NULL,0); return; } if (!(new_cs&~3)) { - // pclog("TS loading null CS\n"); x86gpf(NULL,0); return; } @@ -2503,7 +2240,6 @@ void taskswitch286(uint16_t seg, uint16_t *segdat, int is32) { if (addr>=ldt.limit) { - // pclog("Bigger than LDT limit %04X %04X %04X TS\n",new_cs,ldt.limit,addr); x86gpf(NULL,0); return; } @@ -2513,7 +2249,6 @@ void taskswitch286(uint16_t seg, uint16_t *segdat, int is32) { if (addr>=gdt.limit) { - // pclog("Bigger than GDT limit %04X %04X TS\n",new_cs,gdt.limit); x86gpf(NULL,0); return; } @@ -2525,7 +2260,6 @@ void taskswitch286(uint16_t seg, uint16_t *segdat, int is32) segdat2[3]=readmemw(0,addr+6); if (!(segdat2[2]&0x8000)) { - // pclog("TS loading CS not present\n"); x86np("TS loading CS not present\n", new_cs & 0xfffc); return; } @@ -2534,7 +2268,6 @@ void taskswitch286(uint16_t seg, uint16_t *segdat, int is32) case 0x1800: case 0x1900: case 0x1A00: case 0x1B00: /*Non-conforming*/ if ((new_cs&3) != DPL2) { - // pclog("TS load CS non-conforming RPL != DPL"); x86gpf(NULL,new_cs&~3); return; } @@ -2542,22 +2275,19 @@ void taskswitch286(uint16_t seg, uint16_t *segdat, int is32) case 0x1C00: case 0x1D00: case 0x1E00: case 0x1F00: /*Conforming*/ if ((new_cs&3) < DPL2) { - // pclog("TS load CS non-conforming RPL < DPL"); x86gpf(NULL,new_cs&~3); return; } break; default: - // pclog("TS load CS not code segment\n"); x86gpf(NULL,new_cs&~3); return; } -// if (output) pclog("new_cs %04X\n",new_cs); CS=new_cs; do_seg_load(&_cs, segdat2); if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); - use32=(segdat2[3]&0x40)?0x300:0; + set_use32(segdat2[3] & 0x40); EAX=new_eax; ECX=new_ecx; @@ -2583,11 +2313,165 @@ void taskswitch286(uint16_t seg, uint16_t *segdat, int is32) } else { - // pclog("16-bit TSS\n"); - resetx86(); - //exit(-1); - } + new_pc=readmemw(base,0x0E); + new_flags=readmemw(base,0x10); + + new_eax=readmemw(base,0x12); + new_ecx=readmemw(base,0x14); + new_edx=readmemw(base,0x16); + new_ebx=readmemw(base,0x18); + new_esp=readmemw(base,0x1A); + new_ebp=readmemw(base,0x1C); + new_esi=readmemw(base,0x1E); + new_edi=readmemw(base,0x20); + new_es=readmemw(base,0x22); + new_cs=readmemw(base,0x24); + new_ss=readmemw(base,0x26); + new_ds=readmemw(base,0x28); + new_ldt=readmemw(base,0x2A); + + if (cpu_state.abrt) return; + if (optype==JMP || optype==OPTYPE_INT) + { + if (tr.seg&4) tempw=readmemw(ldt.base,(tr.seg&~7)+4); + else tempw=readmemw(gdt.base,(tr.seg&~7)+4); + if (cpu_state.abrt) return; + tempw&=~0x200; + if (tr.seg&4) writememw(ldt.base,(tr.seg&~7)+4,tempw); + else writememw(gdt.base,(tr.seg&~7)+4,tempw); + } + + if (optype==IRET) flags&=~NT_FLAG; + + cpu_386_flags_rebuild(); + writememw(tr.base,0x0E,cpu_state.pc); + writememw(tr.base,0x10,flags); + + writememw(tr.base,0x12,AX); + writememw(tr.base,0x14,CX); + writememw(tr.base,0x16,DX); + writememw(tr.base,0x18,BX); + writememw(tr.base,0x1A,SP); + writememw(tr.base,0x1C,BP); + writememw(tr.base,0x1E,SI); + writememw(tr.base,0x20,DI); + + writememw(tr.base,0x22,ES); + writememw(tr.base,0x24,CS); + writememw(tr.base,0x26,SS); + writememw(tr.base,0x28,DS); + writememw(tr.base,0x2A,ldt.seg); + + if (optype==OPTYPE_INT) + { + writememw(base,0,tr.seg); + new_flags|=NT_FLAG; + } + if (cpu_state.abrt) return; + if (optype==JMP || optype==OPTYPE_INT) + { + if (tr.seg&4) tempw=readmemw(ldt.base,(seg&~7)+4); + else tempw=readmemw(gdt.base,(seg&~7)+4); + if (cpu_state.abrt) return; + tempw|=0x200; + if (tr.seg&4) writememw(ldt.base,(seg&~7)+4,tempw); + else writememw(gdt.base,(seg&~7)+4,tempw); + } + + cpu_state.pc=new_pc; + flags=new_flags; + cpu_386_flags_extract(); + + ldt.seg=new_ldt; + templ=(ldt.seg&~7)+gdt.base; + ldt.limit=readmemw(0,templ); + ldt.base=(readmemw(0,templ+2))|(readmemb(0,templ+4)<<16); + + if (!(new_cs&~3)) + { + pclog("TS loading null CS\n"); + x86gpf(NULL,0); + return; + } + addr=new_cs&~7; + if (new_cs&4) + { + if (addr>=ldt.limit) + { + pclog("Bigger than LDT limit %04X %04X %04X TS\n",new_cs,ldt.limit,addr); + x86gpf(NULL,0); + return; + } + addr+=ldt.base; + } + else + { + if (addr>=gdt.limit) + { + pclog("Bigger than GDT limit %04X %04X TS\n",new_cs,gdt.limit); + x86gpf(NULL,0); + return; + } + addr+=gdt.base; + } + segdat2[0]=readmemw(0,addr); + segdat2[1]=readmemw(0,addr+2); + segdat2[2]=readmemw(0,addr+4); + segdat2[3]=readmemw(0,addr+6); + if (!(segdat2[2]&0x8000)) + { + pclog("TS loading CS not present\n"); + x86np("TS loading CS not present\n", new_cs & 0xfffc); + return; + } + switch (segdat2[2]&0x1F00) + { + case 0x1800: case 0x1900: case 0x1A00: case 0x1B00: /*Non-conforming*/ + if ((new_cs&3) != DPL2) + { + pclog("TS load CS non-conforming RPL != DPL"); + x86gpf(NULL,new_cs&~3); + return; + } + break; + case 0x1C00: case 0x1D00: case 0x1E00: case 0x1F00: /*Conforming*/ + if ((new_cs&3) < DPL2) + { + pclog("TS load CS non-conforming RPL < DPL"); + x86gpf(NULL,new_cs&~3); + return; + } + break; + default: + pclog("TS load CS not code segment\n"); + x86gpf(NULL,new_cs&~3); + return; + } + + CS=new_cs; + do_seg_load(&_cs, segdat2); + if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + set_use32(0); + + AX=new_eax; + CX=new_ecx; + DX=new_edx; + BX=new_ebx; + SP=new_esp; + BP=new_ebp; + SI=new_esi; + DI=new_edi; + + if (output) pclog("Load ES %04X\n",new_es); + loadseg(new_es,&_es); + if (output) pclog("Load SS %04X\n",new_ss); + loadseg(new_ss,&_ss); + if (output) pclog("Load DS %04X\n",new_ds); + loadseg(new_ds,&_ds); + + if (output) pclog("Resuming at %04X:%08X\n",CS,cpu_state.pc); + } tr.seg=seg; tr.base=base; diff --git a/src/CPU/x86seg.h b/src/CPU/x86seg.h new file mode 100644 index 000000000..f4badadf4 --- /dev/null +++ b/src/CPU/x86seg.h @@ -0,0 +1,17 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * x86 CPU segment emulation. + * + * Version: @(#)x86seg.h 1.0.0 2017/05/30 + * + * Author: Miran Grca, + * Copyright 2016-2017 Miran Grca. + */ + +void do_seg_load(x86seg *s, uint16_t *segdat); diff --git a/src/x87.c b/src/CPU/x87.c similarity index 93% rename from src/x87.c rename to src/CPU/x87.c index 547e56091..a241130fb 100644 --- a/src/x87.c +++ b/src/CPU/x87.c @@ -1,24 +1,14 @@ -//Quake timedemo demo1 - 8.1FPS - -//11A00 - D_SCAlloc -//11C1C - D_CacheSurface - -//36174 - SCR_CalcRefdef - -//SCR_CalcRefdef -//Calls R_SetVrect and R_ViewChanged - #define fplog 0 - #include -#include "ibm.h" -#include "pic.h" +#include "../ibm.h" +#include "../pic.h" #include "x86.h" #include "x86_flags.h" #include "x86_ops.h" #include "x87.h" #include "386_common.h" + uint16_t x87_gettag() { uint16_t ret = 0; diff --git a/src/x87.h b/src/CPU/x87.h similarity index 78% rename from src/x87.h rename to src/CPU/x87.h index 6a0c532b1..5e3db1960 100644 --- a/src/x87.h +++ b/src/CPU/x87.h @@ -1,9 +1,6 @@ uint32_t x87_pc_off,x87_op_off; uint16_t x87_pc_seg,x87_op_seg; -static inline void x87_set_mmx(); -static inline void x87_emms(); - uint16_t x87_gettag(); void x87_settag(uint16_t new_tag); diff --git a/src/CPU/x87_ops.h b/src/CPU/x87_ops.h new file mode 100644 index 000000000..5af874826 --- /dev/null +++ b/src/CPU/x87_ops.h @@ -0,0 +1,1702 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * x87 FPU instructions core. + * + * Version: @(#)x87_ops.h 1.0.0 2017/05/30 + * + * Author: Sarah Walker, + * leilei, + * Miran Grca, + * Copyright 2008-2017 Sarah Walker. + * Copyright 2016-2017 leilei. + * Copyright 2016-2017 Miran Grca. + */ + +#include +#include + +#define fplog 0 + +static int rounding_modes[4] = {FE_TONEAREST, FE_DOWNWARD, FE_UPWARD, FE_TOWARDZERO}; + +#define ST(x) cpu_state.ST[((cpu_state.TOP+(x))&7)] + +#define C0 (1<<8) +#define C1 (1<<9) +#define C2 (1<<10) +#define C3 (1<<14) + +#define STATUS_ZERODIVIDE 4 + +#define x87_div(dst, src1, src2) do \ + { \ + if (((double)src2) == 0.0) \ + { \ + cpu_state.npxs |= STATUS_ZERODIVIDE; \ + if (cpu_state.npxc & STATUS_ZERODIVIDE) \ + dst = src1 / (double)src2; \ + else \ + { \ + pclog("FPU : divide by zero\n"); \ + picint(1 << 13); \ + } \ + return 1; \ + } \ + else \ + dst = src1 / (double)src2; \ + } while (0) + +static __inline void x87_set_mmx() +{ + uint64_t *p; + cpu_state.TOP = 0; + p = (uint64_t *)cpu_state.tag; + *p = 0; + cpu_state.ismmx = 1; +} + +static __inline void x87_emms() +{ + uint64_t *p; + p = (uint64_t *)cpu_state.tag; + *p = 0x0303030303030303ll; + cpu_state.ismmx = 0; +} + +static __inline void x87_checkexceptions() +{ +} + +static __inline void x87_push(double i) +{ + cpu_state.TOP=(cpu_state.TOP-1)&7; + cpu_state.ST[cpu_state.TOP] = i; + cpu_state.tag[cpu_state.TOP&7] = (i == 0.0) ? 1 : 0; +} + +static __inline double x87_pop() +{ + double t = cpu_state.ST[cpu_state.TOP]; + cpu_state.tag[cpu_state.TOP&7] = 3; + cpu_state.TOP=(cpu_state.TOP+1)&7; + return t; +} + +static __inline int64_t x87_fround(double b) +{ + int64_t a, c; + + switch ((cpu_state.npxc>>10)&3) + { + case 0: /*Nearest*/ + a = (int64_t)floor(b); + c = (int64_t)floor(b + 1.0); + if ((b - a) < (c - b)) + return a; + else if ((b - a) > (c - b)) + return c; + else + return (a & 1) ? c : a; + case 1: /*Down*/ + return (int64_t)floor(b); + case 2: /*Up*/ + return (int64_t)ceil(b); + case 3: /*Chop*/ + return (int64_t)b; + default: + return (int64_t)0; + } +} +#define BIAS80 16383 +#define BIAS64 1023 + +static __inline double x87_ld80() +{ + int64_t exp64; + int64_t blah; + int64_t exp64final; + int64_t mant64; + int64_t sign; + struct { + int16_t begin; + union + { + double d; + uint64_t ll; + } eind; + } test; + test.eind.ll = readmeml(easeg,cpu_state.eaaddr); + test.eind.ll |= (uint64_t)readmeml(easeg,cpu_state.eaaddr+4)<<32; + test.begin = readmemw(easeg,cpu_state.eaaddr+8); + + exp64 = (((test.begin&0x7fff) - BIAS80)); + blah = ((exp64 >0)?exp64:-exp64)&0x3ff; + exp64final = ((exp64 >0)?blah:-blah) +BIAS64; + + mant64 = (test.eind.ll >> 11) & (0xfffffffffffffll); + sign = (test.begin&0x8000)?1:0; + + if ((test.begin & 0x7fff) == 0x7fff) + exp64final = 0x7ff; + if ((test.begin & 0x7fff) == 0) + exp64final = 0; + if (test.eind.ll & 0x400) + mant64++; + + test.eind.ll = (sign <<63)|(exp64final << 52)| mant64; + + return test.eind.d; +} + +static __inline void x87_st80(double d) +{ + int64_t sign80; + int64_t exp80; + int64_t exp80final; + int64_t mant80; + int64_t mant80final; + + struct { + int16_t begin; + union + { + double d; + uint64_t ll; + } eind; + } test; + + test.eind.d=d; + + sign80 = (test.eind.ll&(0x8000000000000000ll))?1:0; + exp80 = test.eind.ll&(0x7ff0000000000000ll); + exp80final = (exp80>>52); + mant80 = test.eind.ll&(0x000fffffffffffffll); + mant80final = (mant80 << 11); + + if (exp80final == 0x7ff) /*Infinity / Nan*/ + { + exp80final = 0x7fff; + mant80final |= (0x8000000000000000ll); + } + else if (d != 0){ /* Zero is a special case */ + /* Elvira wants the 8 and tcalc doesn't */ + mant80final |= (0x8000000000000000ll); + /* Ca-cyber doesn't like this when result is zero. */ + exp80final += (BIAS80 - BIAS64); + } + test.begin = (((int16_t)sign80)<<15)| (int16_t)exp80final; + test.eind.ll = mant80final; + + writememl(easeg,cpu_state.eaaddr,test.eind.ll); + writememl(easeg,cpu_state.eaaddr+4,test.eind.ll>>32); + writememw(easeg,cpu_state.eaaddr+8,test.begin); +} + +static __inline void x87_st_fsave(int reg) +{ + reg = (cpu_state.TOP + reg) & 7; + + if (cpu_state.tag[reg] & TAG_UINT64) + { + writememl(easeg, cpu_state.eaaddr, cpu_state.MM[reg].q & 0xffffffff); + writememl(easeg, cpu_state.eaaddr + 4, cpu_state.MM[reg].q >> 32); + writememw(easeg, cpu_state.eaaddr + 8, 0x5555); + } + else + x87_st80(cpu_state.ST[reg]); +} + +static __inline void x87_ld_frstor(int reg) +{ + reg = (cpu_state.TOP + reg) & 7; + + cpu_state.MM[reg].q = readmemq(easeg, cpu_state.eaaddr); + cpu_state.MM_w4[reg] = readmemw(easeg, cpu_state.eaaddr + 8); + + if (cpu_state.MM_w4[reg] == 0x5555 && cpu_state.tag[reg] == 2) + { + cpu_state.tag[reg] = TAG_UINT64; + cpu_state.ST[reg] = (double)cpu_state.MM[reg].q; + } + else + cpu_state.ST[reg] = x87_ld80(); +} + +static __inline void x87_ldmmx(MMX_REG *r, uint16_t *w4) +{ + r->l[0] = readmeml(easeg, cpu_state.eaaddr); + r->l[1] = readmeml(easeg, cpu_state.eaaddr + 4); + *w4 = readmemw(easeg, cpu_state.eaaddr + 8); +} + +static __inline void x87_stmmx(MMX_REG r) +{ + writememl(easeg, cpu_state.eaaddr, r.l[0]); + writememl(easeg, cpu_state.eaaddr + 4, r.l[1]); + writememw(easeg, cpu_state.eaaddr + 8, 0xffff); +} + +static __inline uint16_t x87_compare(double a, double b) +{ +#if defined i386 || defined __i386 || defined __i386__ || defined _X86_ || defined WIN32 || defined _WIN32 || defined _WIN32 + uint32_t out; + + if (!is386) + { + if (((a == INFINITY) || (a == -INFINITY)) && ((b == INFINITY) || (b == -INFINITY))) + { + /* pclog("Comparing infinity\n"); */ + + __asm volatile ("" : : : "memory"); + + __asm( + "fldl %2\n" + "fldl %1\n" + "fclex\n" + "fcompp\n" + "fnstsw %0\n" + : "=m" (out) + : "m" (a), "m" (a) + ); + + return out & (C0|C2|C3); + } + } + + /* Memory barrier, to force GCC to write to the input parameters + * before the compare rather than after */ + __asm volatile ("" : : : "memory"); + + __asm( + "fldl %2\n" + "fldl %1\n" + "fclex\n" + "fcompp\n" + "fnstsw %0\n" + : "=m" (out) + : "m" (a), "m" (b) + ); + + return out & (C0|C2|C3); +#else + /* Generic C version is known to give incorrect results in some + * situations, eg comparison of infinity (Unreal) */ + uint32_t out = 0; + + if (is386) + { + if (((a == INFINITY) || (a == -INFINITY)) && ((b == INFINITY) || (b == -INFINITY))) + { + out |= C3; + return out; + } + + if (a == b) + out |= C3; + else if (a < b) + out |= C0; + } + else + { + if (a == b) + out |= C3; + else if (a < b) + out |= C0; + } + + return out; +#endif +} + +static __inline uint16_t x87_ucompare(double a, double b) +{ +#if defined i386 || defined __i386 || defined __i386__ || defined _X86_ || defined WIN32 || defined _WIN32 || defined _WIN32 + uint32_t out; + + /* Memory barrier, to force GCC to write to the input parameters + * before the compare rather than after */ + __asm volatile ("" : : : "memory"); + + __asm( + "fldl %2\n" + "fldl %1\n" + "fclex\n" + "fucompp\n" + "fnstsw %0\n" + : "=m" (out) + : "m" (a), "m" (b) + ); + + return out & (C0|C2|C3); +#else + /* Generic C version is known to give incorrect results in some + * situations, eg comparison of infinity (Unreal) */ + uint32_t out = 0; + + if (a == b) + out |= C3; + else if (a < b) + out |= C0; + + return out; +#endif +} + +typedef union +{ + float s; + uint32_t i; +} x87_ts; + +typedef union +{ + double d; + uint64_t i; +} x87_td; + +#define FP_ENTER() do \ + { \ + if (cr0 & 0xc) \ + { \ + x86_int(7); \ + return 1; \ + } \ + fpucount++; \ + } while (0) + +#include "x87_ops_arith.h" +#include "x87_ops_misc.h" +#include "x87_ops_loadstore.h" + +static int op_nofpu_a16(uint32_t fetchdat) +{ + if (cr0 & 0xc) + { + x86_int(7); + return 1; + } + else + { + fetch_ea_16(fetchdat); + return 0; + } +} +static int op_nofpu_a32(uint32_t fetchdat) +{ + if (cr0 & 0xc) + { + x86_int(7); + return 1; + } + else + { + fetch_ea_32(fetchdat); + return 0; + } +} + +static int FPU_ILLEGAL_a16(uint32_t fetchdat) +{ + fetch_ea_16(fetchdat); + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 2, rmdat, 0,0,0,0, 0); + return 0; +} + +static int FPU_ILLEGAL_a32(uint32_t fetchdat) +{ + fetch_ea_32(fetchdat); + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 2, rmdat, 0,0,0,0, 0); + return 0; +} + +#define ILLEGAL_a16 FPU_ILLEGAL_a16 +#define ILLEGAL_a32 FPU_ILLEGAL_a32 + +OpFn OP_TABLE(fpu_d8_a16)[32] = +{ + opFADDs_a16, opFMULs_a16, opFCOMs_a16, opFCOMPs_a16, opFSUBs_a16, opFSUBRs_a16, opFDIVs_a16, opFDIVRs_a16, + opFADDs_a16, opFMULs_a16, opFCOMs_a16, opFCOMPs_a16, opFSUBs_a16, opFSUBRs_a16, opFDIVs_a16, opFDIVRs_a16, + opFADDs_a16, opFMULs_a16, opFCOMs_a16, opFCOMPs_a16, opFSUBs_a16, opFSUBRs_a16, opFDIVs_a16, opFDIVRs_a16, + opFADD, opFMUL, opFCOM, opFCOMP, opFSUB, opFSUBR, opFDIV, opFDIVR +}; +OpFn OP_TABLE(fpu_d8_a32)[32] = +{ + opFADDs_a32, opFMULs_a32, opFCOMs_a32, opFCOMPs_a32, opFSUBs_a32, opFSUBRs_a32, opFDIVs_a32, opFDIVRs_a32, + opFADDs_a32, opFMULs_a32, opFCOMs_a32, opFCOMPs_a32, opFSUBs_a32, opFSUBRs_a32, opFDIVs_a32, opFDIVRs_a32, + opFADDs_a32, opFMULs_a32, opFCOMs_a32, opFCOMPs_a32, opFSUBs_a32, opFSUBRs_a32, opFDIVs_a32, opFDIVRs_a32, + opFADD, opFMUL, opFCOM, opFCOMP, opFSUB, opFSUBR, opFDIV, opFDIVR +}; + +OpFn OP_TABLE(fpu_287_d9_a16)[256] = +{ + opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, + opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, + opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, + opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, + opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, + opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, + + opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, + opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, + opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, + opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, + opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, + opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, + + opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, + opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, + opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, + opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, + opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, + opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, + + opFLD, opFLD, opFLD, opFLD, opFLD, opFLD, opFLD, opFLD, + opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, + opFNOP, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, /*Invalid*/ + opFCHS, opFABS, ILLEGAL_a16, ILLEGAL_a16, opFTST, opFXAM, ILLEGAL_a16, ILLEGAL_a16, + opFLD1, opFLDL2T, opFLDL2E, opFLDPI, opFLDEG2, opFLDLN2, opFLDZ, ILLEGAL_a16, + opF2XM1, opFYL2X, opFPTAN, opFPATAN, ILLEGAL_a16, opFPREM1, opFDECSTP, opFINCSTP, + opFPREM, opFYL2XP1, opFSQRT, opFSINCOS, opFRNDINT, opFSCALE, opFSIN, opFCOS +}; + +OpFn OP_TABLE(fpu_287_d9_a32)[256] = +{ + opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, + opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, + opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, + opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, + opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, + opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, + + opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, + opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, + opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, + opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, + opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, + opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, + + opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, + opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, + opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, + opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, + opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, + opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, + + opFLD, opFLD, opFLD, opFLD, opFLD, opFLD, opFLD, opFLD, + opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, + opFNOP, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, /*Invalid*/ + opFCHS, opFABS, ILLEGAL_a32, ILLEGAL_a32, opFTST, opFXAM, ILLEGAL_a32, ILLEGAL_a32, + opFLD1, opFLDL2T, opFLDL2E, opFLDPI, opFLDEG2, opFLDLN2, opFLDZ, ILLEGAL_a32, + opF2XM1, opFYL2X, opFPTAN, opFPATAN, ILLEGAL_a32, opFPREM1, opFDECSTP, opFINCSTP, + opFPREM, opFYL2XP1, opFSQRT, opFSINCOS, opFRNDINT, opFSCALE, opFSIN, opFCOS +}; + +OpFn OP_TABLE(fpu_d9_a16)[256] = +{ + opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, + opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, + opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, + opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, + opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, + opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, + + opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, + opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, + opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, + opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, + opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, + opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, + + opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, + opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, + opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, + opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, + opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, + opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, + + opFLD, opFLD, opFLD, opFLD, opFLD, opFLD, opFLD, opFLD, + opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, + opFNOP, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, /*Invalid*/ + opFCHS, opFABS, ILLEGAL_a16, ILLEGAL_a16, opFTST, opFXAM, ILLEGAL_a16, ILLEGAL_a16, + opFLD1, opFLDL2T, opFLDL2E, opFLDPI, opFLDEG2, opFLDLN2, opFLDZ, ILLEGAL_a16, + opF2XM1, opFYL2X, opFPTAN, opFPATAN, ILLEGAL_a16, opFPREM1, opFDECSTP, opFINCSTP, + opFPREM, opFYL2XP1, opFSQRT, opFSINCOS, opFRNDINT, opFSCALE, opFSIN, opFCOS +}; + +OpFn OP_TABLE(fpu_d9_a32)[256] = +{ + opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, + opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, + opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, + opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, + opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, + opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, + + opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, + opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, + opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, + opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, + opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, + opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, + + opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, + opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, + opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, + opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, + opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, + opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, + + opFLD, opFLD, opFLD, opFLD, opFLD, opFLD, opFLD, opFLD, + opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, + opFNOP, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, /*Invalid*/ + opFCHS, opFABS, ILLEGAL_a32, ILLEGAL_a32, opFTST, opFXAM, ILLEGAL_a32, ILLEGAL_a32, + opFLD1, opFLDL2T, opFLDL2E, opFLDPI, opFLDEG2, opFLDLN2, opFLDZ, ILLEGAL_a32, + opF2XM1, opFYL2X, opFPTAN, opFPATAN, ILLEGAL_a32, opFPREM1, opFDECSTP, opFINCSTP, + opFPREM, opFYL2XP1, opFSQRT, opFSINCOS, opFRNDINT, opFSCALE, opFSIN, opFCOS +}; + +OpFn OP_TABLE(fpu_287_da_a16)[256] = +{ + opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, + opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, + opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, + opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, + opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, + opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, + opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, + opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, + + opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, + opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, + opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, + opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, + opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, + opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, + opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, + opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, + + opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, + opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, + opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, + opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, + opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, + opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, + opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, + opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, + + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, +}; +OpFn OP_TABLE(fpu_287_da_a32)[256] = +{ + opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, + opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, + opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, + opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, + opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, + opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, + opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, + opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, + + opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, + opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, + opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, + opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, + opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, + opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, + opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, + opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, + + opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, + opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, + opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, + opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, + opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, + opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, + opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, + opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, + + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, +}; + +OpFn OP_TABLE(fpu_da_a16)[256] = +{ + opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, + opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, + opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, + opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, + opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, + opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, + opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, + opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, + + opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, + opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, + opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, + opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, + opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, + opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, + opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, + opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, + + opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, + opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, + opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, + opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, + opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, + opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, + opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, + opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, + + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, opFUCOMPP, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, +}; +OpFn OP_TABLE(fpu_da_a32)[256] = +{ + opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, + opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, + opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, + opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, + opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, + opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, + opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, + opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, + + opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, + opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, + opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, + opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, + opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, + opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, + opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, + opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, + + opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, + opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, + opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, + opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, + opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, + opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, + opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, + opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, + + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, opFUCOMPP, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, +}; + +OpFn OP_TABLE(fpu_686_da_a16)[256] = +{ + opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, + opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, + opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, + opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, + opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, + opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, + opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, + opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, + + opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, + opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, + opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, + opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, + opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, + opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, + opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, + opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, + + opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, + opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, + opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, + opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, + opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, + opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, + opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, + opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, + + opFCMOVB, opFCMOVB, opFCMOVB, opFCMOVB, opFCMOVB, opFCMOVB, opFCMOVB, opFCMOVB, + opFCMOVE, opFCMOVE, opFCMOVE, opFCMOVE, opFCMOVE, opFCMOVE, opFCMOVE, opFCMOVE, + opFCMOVBE, opFCMOVBE, opFCMOVBE, opFCMOVBE, opFCMOVBE, opFCMOVBE, opFCMOVBE, opFCMOVBE, + opFCMOVU, opFCMOVU, opFCMOVU, opFCMOVU, opFCMOVU, opFCMOVU, opFCMOVU, opFCMOVU, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, opFUCOMPP, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, +}; +OpFn OP_TABLE(fpu_686_da_a32)[256] = +{ + opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, + opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, + opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, + opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, + opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, + opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, + opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, + opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, + + opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, + opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, + opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, + opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, + opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, + opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, + opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, + opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, + + opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, + opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, + opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, + opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, + opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, + opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, + opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, + opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, + + opFCMOVB, opFCMOVB, opFCMOVB, opFCMOVB, opFCMOVB, opFCMOVB, opFCMOVB, opFCMOVB, + opFCMOVE, opFCMOVE, opFCMOVE, opFCMOVE, opFCMOVE, opFCMOVE, opFCMOVE, opFCMOVE, + opFCMOVBE, opFCMOVBE, opFCMOVBE, opFCMOVBE, opFCMOVBE, opFCMOVBE, opFCMOVBE, opFCMOVBE, + opFCMOVU, opFCMOVU, opFCMOVU, opFCMOVU, opFCMOVU, opFCMOVU, opFCMOVU, opFCMOVU, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, opFUCOMPP, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, +}; + +OpFn OP_TABLE(fpu_287_db_a16)[256] = +{ + opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, + opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, + + opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, + opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, + + opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, + opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, + + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFNOP, opFNOP, opFCLEX, opFINIT, opFNOP, opFNOP, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, +}; +OpFn OP_TABLE(fpu_287_db_a32)[256] = +{ + opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, + opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, + + opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, + opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, + + opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, + opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, + + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFNOP, opFNOP, opFCLEX, opFINIT, opFNOP, opFNOP, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, +}; + +OpFn OP_TABLE(fpu_db_a16)[256] = +{ + opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, + opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, + + opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, + opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, + + opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, + opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, + + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFNOP, opFNOP, opFCLEX, opFINIT, opFNOP, opFNOP, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, +}; +OpFn OP_TABLE(fpu_db_a32)[256] = +{ + opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, + opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, + + opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, + opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, + + opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, + opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, + + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFNOP, opFNOP, opFCLEX, opFINIT, opFNOP, opFNOP, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, +}; + +OpFn OP_TABLE(fpu_686_db_a16)[256] = +{ + opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, + opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, + + opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, + opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, + + opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, + opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, + + opFCMOVNB, opFCMOVNB, opFCMOVNB, opFCMOVNB, opFCMOVNB, opFCMOVNB, opFCMOVNB, opFCMOVNB, + opFCMOVNE, opFCMOVNE, opFCMOVNE, opFCMOVNE, opFCMOVNE, opFCMOVNE, opFCMOVNE, opFCMOVNE, + opFCMOVNBE, opFCMOVNBE, opFCMOVNBE, opFCMOVNBE, opFCMOVNBE, opFCMOVNBE, opFCMOVNBE, opFCMOVNBE, + opFCMOVNU, opFCMOVNU, opFCMOVNU, opFCMOVNU, opFCMOVNU, opFCMOVNU, opFCMOVNU, opFCMOVNU, + opFNOP, opFNOP, opFCLEX, opFINIT, opFNOP, opFNOP, ILLEGAL_a16, ILLEGAL_a16, + opFUCOMI, opFUCOMI, opFUCOMI, opFUCOMI, opFUCOMI, opFUCOMI, opFUCOMI, opFUCOMI, + opFCOMI, opFCOMI, opFCOMI, opFCOMI, opFCOMI, opFCOMI, opFCOMI, opFCOMI, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, +}; +OpFn OP_TABLE(fpu_686_db_a32)[256] = +{ + opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, + opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, + + opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, + opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, + + opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, + opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, + + opFCMOVNB, opFCMOVNB, opFCMOVNB, opFCMOVNB, opFCMOVNB, opFCMOVNB, opFCMOVNB, opFCMOVNB, + opFCMOVNE, opFCMOVNE, opFCMOVNE, opFCMOVNE, opFCMOVNE, opFCMOVNE, opFCMOVNE, opFCMOVNE, + opFCMOVNBE, opFCMOVNBE, opFCMOVNBE, opFCMOVNBE, opFCMOVNBE, opFCMOVNBE, opFCMOVNBE, opFCMOVNBE, + opFCMOVNU, opFCMOVNU, opFCMOVNU, opFCMOVNU, opFCMOVNU, opFCMOVNU, opFCMOVNU, opFCMOVNU, + opFNOP, opFNOP, opFCLEX, opFINIT, opFNOP, opFNOP, ILLEGAL_a32, ILLEGAL_a32, + opFUCOMI, opFUCOMI, opFUCOMI, opFUCOMI, opFUCOMI, opFUCOMI, opFUCOMI, opFUCOMI, + opFCOMI, opFCOMI, opFCOMI, opFCOMI, opFCOMI, opFCOMI, opFCOMI, opFCOMI, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, +}; + +OpFn OP_TABLE(fpu_287_dc_a16)[32] = +{ + opFADDd_a16, opFMULd_a16, opFCOMd_a16, opFCOMPd_a16, opFSUBd_a16, opFSUBRd_a16, opFDIVd_a16, opFDIVRd_a16, + opFADDd_a16, opFMULd_a16, opFCOMd_a16, opFCOMPd_a16, opFSUBd_a16, opFSUBRd_a16, opFDIVd_a16, opFDIVRd_a16, + opFADDd_a16, opFMULd_a16, opFCOMd_a16, opFCOMPd_a16, opFSUBd_a16, opFSUBRd_a16, opFDIVd_a16, opFDIVRd_a16, + opFADDr, opFMULr, ILLEGAL_a16, ILLEGAL_a16, opFSUBRr, opFSUBr, opFDIVRr, opFDIVr +}; +OpFn OP_TABLE(fpu_287_dc_a32)[32] = +{ + opFADDd_a32, opFMULd_a32, opFCOMd_a32, opFCOMPd_a32, opFSUBd_a32, opFSUBRd_a32, opFDIVd_a32, opFDIVRd_a32, + opFADDd_a32, opFMULd_a32, opFCOMd_a32, opFCOMPd_a32, opFSUBd_a32, opFSUBRd_a32, opFDIVd_a32, opFDIVRd_a32, + opFADDd_a32, opFMULd_a32, opFCOMd_a32, opFCOMPd_a32, opFSUBd_a32, opFSUBRd_a32, opFDIVd_a32, opFDIVRd_a32, + opFADDr, opFMULr, ILLEGAL_a32, ILLEGAL_a32, opFSUBRr, opFSUBr, opFDIVRr, opFDIVr +}; + +OpFn OP_TABLE(fpu_dc_a16)[32] = +{ + opFADDd_a16, opFMULd_a16, opFCOMd_a16, opFCOMPd_a16, opFSUBd_a16, opFSUBRd_a16, opFDIVd_a16, opFDIVRd_a16, + opFADDd_a16, opFMULd_a16, opFCOMd_a16, opFCOMPd_a16, opFSUBd_a16, opFSUBRd_a16, opFDIVd_a16, opFDIVRd_a16, + opFADDd_a16, opFMULd_a16, opFCOMd_a16, opFCOMPd_a16, opFSUBd_a16, opFSUBRd_a16, opFDIVd_a16, opFDIVRd_a16, + opFADDr, opFMULr, opFCOM, opFCOMP, opFSUBRr, opFSUBr, opFDIVRr, opFDIVr +}; +OpFn OP_TABLE(fpu_dc_a32)[32] = +{ + opFADDd_a32, opFMULd_a32, opFCOMd_a32, opFCOMPd_a32, opFSUBd_a32, opFSUBRd_a32, opFDIVd_a32, opFDIVRd_a32, + opFADDd_a32, opFMULd_a32, opFCOMd_a32, opFCOMPd_a32, opFSUBd_a32, opFSUBRd_a32, opFDIVd_a32, opFDIVRd_a32, + opFADDd_a32, opFMULd_a32, opFCOMd_a32, opFCOMPd_a32, opFSUBd_a32, opFSUBRd_a32, opFDIVd_a32, opFDIVRd_a32, + opFADDr, opFMULr, opFCOM, opFCOMP, opFSUBRr, opFSUBr, opFDIVRr, opFDIVr +}; + +OpFn OP_TABLE(fpu_287_dd_a16)[256] = +{ + opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, + opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, + opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, + opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, + + opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, + opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, + opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, + opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, + + opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, + opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, + opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, + opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, + + opFFREE, opFFREE, opFFREE, opFFREE, opFFREE, opFFREE, opFFREE, opFFREE, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFST, opFST, opFST, opFST, opFST, opFST, opFST, opFST, + opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, +}; +OpFn OP_TABLE(fpu_287_dd_a32)[256] = +{ + opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, + opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, + opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, + opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, + + opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, + opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, + opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, + opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, + + opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, + opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, + opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, + opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, + + opFFREE, opFFREE, opFFREE, opFFREE, opFFREE, opFFREE, opFFREE, opFFREE, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFST, opFST, opFST, opFST, opFST, opFST, opFST, opFST, + opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, +}; + +OpFn OP_TABLE(fpu_dd_a16)[256] = +{ + opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, + opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, + opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, + opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, + + opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, + opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, + opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, + opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, + + opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, + opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, + opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, + opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, + + opFFREE, opFFREE, opFFREE, opFFREE, opFFREE, opFFREE, opFFREE, opFFREE, + opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, + opFST, opFST, opFST, opFST, opFST, opFST, opFST, opFST, + opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, + opFUCOM, opFUCOM, opFUCOM, opFUCOM, opFUCOM, opFUCOM, opFUCOM, opFUCOM, + opFUCOMP, opFUCOMP, opFUCOMP, opFUCOMP, opFUCOMP, opFUCOMP, opFUCOMP, opFUCOMP, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, +}; +OpFn OP_TABLE(fpu_dd_a32)[256] = +{ + opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, + opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, + opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, + opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, + + opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, + opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, + opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, + opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, + + opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, + opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, + opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, + opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, + + opFFREE, opFFREE, opFFREE, opFFREE, opFFREE, opFFREE, opFFREE, opFFREE, + opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, + opFST, opFST, opFST, opFST, opFST, opFST, opFST, opFST, + opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, + opFUCOM, opFUCOM, opFUCOM, opFUCOM, opFUCOM, opFUCOM, opFUCOM, opFUCOM, + opFUCOMP, opFUCOMP, opFUCOMP, opFUCOMP, opFUCOMP, opFUCOMP, opFUCOMP, opFUCOMP, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, +}; + +OpFn OP_TABLE(fpu_287_de_a16)[256] = +{ + opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, + opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, + opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, + opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, + opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, + opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, + opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, + opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, + + opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, + opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, + opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, + opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, + opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, + opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, + opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, + opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, + + opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, + opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, + opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, + opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, + opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, + opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, + opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, + opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, + + opFADDP, opFADDP, opFADDP, opFADDP, opFADDP, opFADDP, opFADDP, opFADDP, + opFMULP, opFMULP, opFMULP, opFMULP, opFMULP, opFMULP, opFMULP, opFMULP, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, opFCOMPP, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, + opFSUBP, opFSUBP, opFSUBP, opFSUBP, opFSUBP, opFSUBP, opFSUBP, opFSUBP, + opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, + opFDIVP, opFDIVP, opFDIVP, opFDIVP, opFDIVP, opFDIVP, opFDIVP, opFDIVP, +}; + +OpFn OP_TABLE(fpu_287_de_a32)[256] = +{ + opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, + opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, + opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, + opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, + opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, + opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, + opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, + opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, + + opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, + opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, + opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, + opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, + opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, + opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, + opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, + opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, + + opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, + opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, + opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, + opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, + opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, + opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, + opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, + opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, + + opFADDP, opFADDP, opFADDP, opFADDP, opFADDP, opFADDP, opFADDP, opFADDP, + opFMULP, opFMULP, opFMULP, opFMULP, opFMULP, opFMULP, opFMULP, opFMULP, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, opFCOMPP, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, + opFSUBP, opFSUBP, opFSUBP, opFSUBP, opFSUBP, opFSUBP, opFSUBP, opFSUBP, + opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, + opFDIVP, opFDIVP, opFDIVP, opFDIVP, opFDIVP, opFDIVP, opFDIVP, opFDIVP, +}; + +OpFn OP_TABLE(fpu_de_a16)[256] = +{ + opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, + opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, + opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, + opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, + opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, + opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, + opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, + opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, + + opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, + opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, + opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, + opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, + opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, + opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, + opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, + opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, + + opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, + opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, + opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, + opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, + opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, + opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, + opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, + opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, + + opFADDP, opFADDP, opFADDP, opFADDP, opFADDP, opFADDP, opFADDP, opFADDP, + opFMULP, opFMULP, opFMULP, opFMULP, opFMULP, opFMULP, opFMULP, opFMULP, + opFCOMP, opFCOMP, opFCOMP, opFCOMP, opFCOMP, opFCOMP, opFCOMP, opFCOMP, + ILLEGAL_a16, opFCOMPP, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, + opFSUBP, opFSUBP, opFSUBP, opFSUBP, opFSUBP, opFSUBP, opFSUBP, opFSUBP, + opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, + opFDIVP, opFDIVP, opFDIVP, opFDIVP, opFDIVP, opFDIVP, opFDIVP, opFDIVP, +}; + +OpFn OP_TABLE(fpu_de_a32)[256] = +{ + opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, + opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, + opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, + opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, + opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, + opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, + opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, + opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, + + opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, + opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, + opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, + opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, + opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, + opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, + opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, + opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, + + opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, + opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, + opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, + opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, + opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, + opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, + opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, + opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, + + opFADDP, opFADDP, opFADDP, opFADDP, opFADDP, opFADDP, opFADDP, opFADDP, + opFMULP, opFMULP, opFMULP, opFMULP, opFMULP, opFMULP, opFMULP, opFMULP, + opFCOMP, opFCOMP, opFCOMP, opFCOMP, opFCOMP, opFCOMP, opFCOMP, opFCOMP, + ILLEGAL_a32, opFCOMPP, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, + opFSUBP, opFSUBP, opFSUBP, opFSUBP, opFSUBP, opFSUBP, opFSUBP, opFSUBP, + opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, + opFDIVP, opFDIVP, opFDIVP, opFDIVP, opFDIVP, opFDIVP, opFDIVP, opFDIVP, +}; + +OpFn OP_TABLE(fpu_287_df_a16)[256] = +{ + opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, + opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, + FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, + FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, + + opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, + opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, + FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, + FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, + + opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, + opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, + FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, + FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, + + opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTSW_AX, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, +}; +OpFn OP_TABLE(fpu_287_df_a32)[256] = +{ + opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, + opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, + FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, + FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, + + opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, + opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, + FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, + FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, + + opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, + opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, + FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, + FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, + + opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSTSW_AX, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, +}; + +OpFn OP_TABLE(fpu_df_a16)[256] = +{ + opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, + opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, + FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, + FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, + + opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, + opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, + FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, + FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, + + opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, + opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, + FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, + FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, + + opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, + opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, + opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, + opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, + opFSTSW_AX, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, +}; +OpFn OP_TABLE(fpu_df_a32)[256] = +{ + opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, + opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, + FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, + FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, + + opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, + opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, + FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, + FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, + + opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, + opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, + FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, + FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, + + opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, + opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, + opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, + opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, + opFSTSW_AX, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, +}; + +OpFn OP_TABLE(fpu_686_df_a16)[256] = +{ + opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, + opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, + FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, + FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, + + opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, + opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, + FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, + FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, + + opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, + opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, + FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, + FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, + + opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, + opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, + opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, + opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, + opFSTSW_AX, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFUCOMIP, opFUCOMIP, opFUCOMIP, opFUCOMIP, opFUCOMIP, opFUCOMIP, opFUCOMIP, opFUCOMIP, + opFCOMIP, opFCOMIP, opFCOMIP, opFCOMIP, opFCOMIP, opFCOMIP, opFCOMIP, opFCOMIP, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, +}; +OpFn OP_TABLE(fpu_686_df_a32)[256] = +{ + opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, + opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, + FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, + FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, + + opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, + opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, + FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, + FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, + + opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, + opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, + FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, + FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, + + opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, + opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, + opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, + opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, + opFSTSW_AX, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFUCOMIP, opFUCOMIP, opFUCOMIP, opFUCOMIP, opFUCOMIP, opFUCOMIP, opFUCOMIP, opFUCOMIP, + opFCOMIP, opFCOMIP, opFCOMIP, opFCOMIP, opFCOMIP, opFCOMIP, opFCOMIP, opFCOMIP, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, +}; + +OpFn OP_TABLE(nofpu_a16)[256] = +{ + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, +}; +OpFn OP_TABLE(nofpu_a32)[256] = +{ + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, +}; diff --git a/src/x87_ops_arith.h b/src/CPU/x87_ops_arith.h similarity index 99% rename from src/x87_ops_arith.h rename to src/CPU/x87_ops_arith.h index 48a141e2f..f53ad9213 100644 --- a/src/x87_ops_arith.h +++ b/src/CPU/x87_ops_arith.h @@ -165,11 +165,14 @@ static int opFCOMP(uint32_t fetchdat) static int opFCOMPP(uint32_t fetchdat) { + uint64_t *p, *q; FP_ENTER(); cpu_state.pc++; if (fplog) pclog("FCOMPP\n"); cpu_state.npxs &= ~(C0|C2|C3); - if (*(uint64_t *)&ST(0) == ((uint64_t)1 << 63) && *(uint64_t *)&ST(1) == 0) + p = (uint64_t *)&ST(0); + q = (uint64_t *)&ST(1); + if ((*p == ((uint64_t)1 << 63) && *q == 0) && is386) cpu_state.npxs |= C0; /*Nasty hack to fix 80387 detection*/ else cpu_state.npxs |= x87_compare(ST(0), ST(1)); diff --git a/src/x87_ops_loadstore.h b/src/CPU/x87_ops_loadstore.h similarity index 96% rename from src/x87_ops_loadstore.h rename to src/CPU/x87_ops_loadstore.h index ed083b921..39a14c4fb 100644 --- a/src/x87_ops_loadstore.h +++ b/src/CPU/x87_ops_loadstore.h @@ -1,3 +1,21 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * x87 FPU instructions core. + * + * Version: @(#)x87_ops_loadstore.h 1.0.0 2017/05/30 + * + * Author: Sarah Walker, + * Miran Grca, + * Copyright 2008-2017 Sarah Walker. + * Copyright 2016-2017 Miran Grca. + */ + static int opFILDiw_a16(uint32_t fetchdat) { int16_t temp; diff --git a/src/x87_ops_misc.h b/src/CPU/x87_ops_misc.h similarity index 98% rename from src/x87_ops_misc.h rename to src/CPU/x87_ops_misc.h index ea31c74e0..fd1cc3de6 100644 --- a/src/x87_ops_misc.h +++ b/src/CPU/x87_ops_misc.h @@ -29,13 +29,16 @@ static int opFCLEX(uint32_t fetchdat) static int opFINIT(uint32_t fetchdat) { + uint64_t *p; FP_ENTER(); cpu_state.pc++; cpu_state.npxc = 0x37F; cpu_state.new_npxc = (cpu_state.old_npxc & ~0xc00); cpu_state.npxs = 0; - *(uint64_t *)cpu_state.tag = 0x0303030303030303ll; + p = (uint64_t *)cpu_state.tag; + *p = 0x0303030303030303ll; cpu_state.TOP = 0; + cpu_state.ismmx = 0; CLOCK_CYCLES(17); return 0; } @@ -90,6 +93,7 @@ static int opFSTP(uint32_t fetchdat) static int FSTOR() { + uint64_t *p; FP_ENTER(); switch ((cr0 & 1) | (cpu_state.op32 & 0x100)) { @@ -124,9 +128,10 @@ static int FSTOR() cpu_state.ismmx = 0; /*Horrible hack, but as PCem doesn't keep the FPU stack in 80-bit precision at all times something like this is needed*/ + p = (uint64_t *)cpu_state.tag; if (cpu_state.MM_w4[0] == 0xffff && cpu_state.MM_w4[1] == 0xffff && cpu_state.MM_w4[2] == 0xffff && cpu_state.MM_w4[3] == 0xffff && cpu_state.MM_w4[4] == 0xffff && cpu_state.MM_w4[5] == 0xffff && cpu_state.MM_w4[6] == 0xffff && cpu_state.MM_w4[7] == 0xffff && - !cpu_state.TOP && !(*(uint64_t *)cpu_state.tag)) + !cpu_state.TOP && !(*p)) cpu_state.ismmx = 1; CLOCK_CYCLES((cr0 & 1) ? 34 : 44); @@ -150,6 +155,8 @@ static int opFSTOR_a32(uint32_t fetchdat) static int FSAVE() { + uint64_t *p; + FP_ENTER(); if (fplog) pclog("FSAVE %08X:%08X %i\n", easeg, cpu_state.eaaddr, cpu_state.ismmx); cpu_state.npxs = (cpu_state.npxs & ~(7 << 11)) | (cpu_state.TOP << 11); @@ -282,6 +289,15 @@ static int FSAVE() } break; } + + cpu_state.npxc = 0x37F; + cpu_state.new_npxc = (cpu_state.old_npxc & ~0xc00); + cpu_state.npxs = 0; + p = (uint64_t *)cpu_state.tag; + *p = 0x0303030303030303ll; + cpu_state.TOP = 0; + cpu_state.ismmx = 0; + CLOCK_CYCLES((cr0 & 1) ? 56 : 67); return cpu_state.abrt; } diff --git a/src/H b/src/H new file mode 100644 index 000000000..5033690bc --- /dev/null +++ b/src/H @@ -0,0 +1,23 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Handling of the emulated machines. + * + * Version: @(#)xxx.h 1.0.1 2017/06/21 + * + * Authors: Sarah Walker, + * Miran Grca, + * Fred N. van Kempen, + * Copyright 2008-2017 Sarah Walker. + * Copyright 2016-2017 Miran Grca. + */ +#ifndef EMU_xxx_H +# define EMU_xxx_H + + +#endif /*EMU_xxx_H*/ diff --git a/src/M b/src/M new file mode 100644 index 000000000..105e8a6c7 --- /dev/null +++ b/src/M @@ -0,0 +1,18 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Handling of the emulated machines. + * + * Version: @(#)xxx.c 1.0.1 2017/06/21 + * + * Authors: Sarah Walker, + * Miran Grca, + * Fred N. van Kempen, + * Copyright 2008-2017 Sarah Walker. + * Copyright 2016-2017 Miran Grca. + */ diff --git a/src/Makefile.am b/src/Makefile.am deleted file mode 100644 index 10ca53e8d..000000000 --- a/src/Makefile.am +++ /dev/null @@ -1,51 +0,0 @@ -# Makefile.am for PCem - -bin_PROGRAMS = pcem -noinst_SCRIPTS = ../pcem -CLEANFILES = $(noinst_SCRIPTS) - -../pcem: pcem - cp pcem .. - -amrefresh: - - -pcem_CFLAGS = $(allegro_CFLAGS) - -pcem_LDADD = $(allegro_LIBS) -lopenal -lalut - -pcem_SOURCES = 386.c 386_dynarec.c 386_dynarec_ops.c 808x.c acer386sx.c ali1429.c allegro-gui.c \ -allegro-gui-configure.c allegro-gui-deviceconfig.c allegro-gui-hdconf.c allegro-joystick.c allegro-keyboard.c allegro-main.c \ -allegro-midi.c allegro-mouse.c allegro-video.c amstrad.c cdrom-ioctl-linux.c cdrom-iso.c cdrom-null.c \ -codegen.c codegen_ops.c codegen_timing_486.c codegen_timing_686.c codegen_timing_pentium.c codegen_timing_winchip.c compaq.c config.c cpu.c \ -dac.c device.c disc.c disc_fdi.c disc_img.c disc_sector.c dma.c fdc.c fdc37c665.c fdd.c fdi2raw.c gameport.c \ -headland.c i430lx.c i430fx.c i430vx.c ide.c intel.c intel_flash.c io.c jim.c \ -keyboard.c keyboard_amstrad.c keyboard_at.c keyboard_olim24.c keyboard_pcjr.c keyboard_xt.c \ -linux-time.c lpt.c mcr.c mem.c model.c mouse.c mouse_ps2.c mouse_serial.c neat.c nmi.c nvr.c \ -olivetti_m24.c opti.c pc.c pci.c pic.c piix.c pit.c ppi.c ps1.c rom.c scat.c serial.c sis496.c sound.c \ -sound_ad1848.c sound_adlib.c sound_adlibgold.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 thread-pthread.c \ -timer.c um8669f.c um8881f.c vid_ati_eeprom.c vid_ati_mach64.c vid_ati18800.c vid_ati28800.c \ -vid_ati68860_ramdac.c vid_cga.c vid_cl_gd.c vid_cl_gd_blit.c vid_cl_ramdac.c vid_ega.c vid_et4000.c vid_et4000w32.c vid_hercules.c vid_herculesplus.c\ -vid_icd2061.c vid_ics2595.c vid_incolor.c vid_mda.c vid_nv_riva128.c vid_olivetti_m24.c vid_oti067.c vid_paradise.c vid_pc200.c \ -vid_pc1512.c vid_pc1640.c vid_pcjr.c vid_ps1_svga.c vid_s3.c vid_s3_virge.c vid_sdac_ramdac.c \ -vid_stg_ramdac.c vid_svga.c vid_svga_render.c vid_tandy.c vid_tandysl.c vid_tgui9440.c \ -vid_tkd8001_ramdac.c vid_tvga.c vid_unk_ramdac.c vid_vga.c vid_voodoo.c video.c wd76c10.c \ -x86seg.c x87.c xtide.c sound_dbopl.cc sound_resid.cc dosbox/dbopl.cpp \ -resid-fp/convolve.cc resid-fp/convolve-sse.cc resid-fp/envelope.cc \ -resid-fp/extfilt.cc resid-fp/filter.cc resid-fp/pot.cc resid-fp/sid.cc \ -resid-fp/voice.cc resid-fp/wave6581_PS_.cc resid-fp/wave6581_PST.cc \ -resid-fp/wave6581_P_T.cc resid-fp/wave6581__ST.cc resid-fp/wave8580_PS_.cc \ -resid-fp/wave8580_PST.cc resid-fp/wave8580_P_T.cc resid-fp/wave8580__ST.cc \ -resid-fp/wave.cc - -if CPU_I386 -pcem_SOURCES += codegen_x86.c -pcem_CFLAGS += -msse2 -endif - -if CPU_X86_64 -pcem_SOURCES += codegen_x86-64.c -endif - diff --git a/src/Makefile.in b/src/Makefile.in deleted file mode 100644 index 1d3455bca..000000000 --- a/src/Makefile.in +++ /dev/null @@ -1,2956 +0,0 @@ -# Makefile.in generated by automake 1.11.1 from Makefile.am. -# @configure_input@ - -# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, -# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, -# Inc. -# This Makefile.in is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY, to the extent permitted by law; without -# even the implied warranty of MERCHANTABILITY or FITNESS FOR A -# PARTICULAR PURPOSE. - -@SET_MAKE@ - -# Makefile.am for PCem - - -VPATH = @srcdir@ -pkgdatadir = $(datadir)/@PACKAGE@ -pkgincludedir = $(includedir)/@PACKAGE@ -pkglibdir = $(libdir)/@PACKAGE@ -pkglibexecdir = $(libexecdir)/@PACKAGE@ -am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd -install_sh_DATA = $(install_sh) -c -m 644 -install_sh_PROGRAM = $(install_sh) -c -install_sh_SCRIPT = $(install_sh) -c -INSTALL_HEADER = $(INSTALL_DATA) -transform = $(program_transform_name) -NORMAL_INSTALL = : -PRE_INSTALL = : -POST_INSTALL = : -NORMAL_UNINSTALL = : -PRE_UNINSTALL = : -POST_UNINSTALL = : -build_triplet = @build@ -host_triplet = @host@ -bin_PROGRAMS = pcem$(EXEEXT) -@CPU_I386_TRUE@am__append_1 = codegen_x86.c -@CPU_X86_64_TRUE@am__append_2 = codegen_x86-64.c -subdir = src -DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in -ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 -am__aclocal_m4_deps = $(top_srcdir)/configure.ac -am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ - $(ACLOCAL_M4) -mkinstalldirs = $(install_sh) -d -CONFIG_CLEAN_FILES = -CONFIG_CLEAN_VPATH_FILES = -am__installdirs = "$(DESTDIR)$(bindir)" -PROGRAMS = $(bin_PROGRAMS) -am__pcem_SOURCES_DIST = 386.c 386_dynarec.c 386_dynarec_ops.c 808x.c \ - acer386sx.c ali1429.c allegro-gui.c allegro-gui-configure.c \ - allegro-gui-hdconf.c allegro-joystick.c allegro-keyboard.c \ - allegro-main.c allegro-midi.c allegro-mouse.c allegro-video.c \ - amstrad.c cdrom-ioctl-linux.c cdrom-null.c codegen.c \ - codegen_ops.c codegen_timing_486.c codegen_timing_pentium.c \ - compaq.c config.c cpu.c dac.c device.c disc.c disc_fdi.c \ - disc_img.c dma.c fdc.c fdc37c665.c fdi2raw.c gameport.c \ - headland.c i430lx.c i430fx.c i430vx.c ide.c intel.c \ - intel_flash.c io.c jim.c keyboard.c keyboard_amstrad.c \ - keyboard_at.c keyboard_olim24.c keyboard_pcjr.c keyboard_xt.c \ - linux-time.c lpt.c mcr.c mem.c model.c mouse.c mouse_ps2.c \ - mouse_serial.c neat.c nmi.c nvr.c olivetti_m24.c opti.c pc.c \ - pci.c pic.c piix.c pit.c ppi.c ps1.c rom.c serial.c sis496.c \ - sound.c sound_ad1848.c sound_adlib.c sound_adlibgold.c \ - sound_cms.c sound_emu8k.c sound_gus.c sound_mpu401_uart.c \ - sound_opl.c sound_pas16.c sound_sb.c sound_sb_dsp.c \ - sound_sn76489.c sound_speaker.c sound_ssi2001.c sound_wss.c \ - soundopenal.c thread-pthread.c timer.c um8669f.c um8881f.c \ - vid_ati_eeprom.c vid_ati_mach64.c vid_ati18800.c \ - vid_ati28800.c vid_ati68860_ramdac.c vid_cga.c vid_cl5429.c \ - vid_ega.c vid_et4000.c vid_et4000w32.c vid_hercules.c \ - vid_icd2061.c vid_ics2595.c vid_mda.c vid_olivetti_m24.c \ - vid_oti067.c vid_paradise.c vid_pc200.c vid_pc1512.c \ - vid_pc1640.c vid_pcjr.c vid_s3.c vid_s3_virge.c \ - vid_sdac_ramdac.c vid_stg_ramdac.c vid_svga.c \ - vid_svga_render.c vid_tandy.c vid_tgui9440.c \ - vid_tkd8001_ramdac.c vid_tvga.c vid_unk_ramdac.c vid_vga.c \ - vid_voodoo.c video.c wd76c10.c x86seg.c x87.c xtide.c \ - sound_dbopl.cc sound_resid.cc dosbox/dbopl.cpp \ - resid-fp/convolve.cc resid-fp/convolve-sse.cc \ - resid-fp/envelope.cc resid-fp/extfilt.cc resid-fp/filter.cc \ - resid-fp/pot.cc resid-fp/sid.cc resid-fp/voice.cc \ - resid-fp/wave6581_PS_.cc resid-fp/wave6581_PST.cc \ - resid-fp/wave6581_P_T.cc resid-fp/wave6581__ST.cc \ - resid-fp/wave8580_PS_.cc resid-fp/wave8580_PST.cc \ - resid-fp/wave8580_P_T.cc resid-fp/wave8580__ST.cc \ - resid-fp/wave.cc codegen_x86.c codegen_x86-64.c -@CPU_I386_TRUE@am__objects_1 = pcem-codegen_x86.$(OBJEXT) -@CPU_X86_64_TRUE@am__objects_2 = pcem-codegen_x86-64.$(OBJEXT) -am_pcem_OBJECTS = pcem-386.$(OBJEXT) pcem-386_dynarec.$(OBJEXT) \ - pcem-386_dynarec_ops.$(OBJEXT) pcem-808x.$(OBJEXT) \ - pcem-acer386sx.$(OBJEXT) pcem-ali1429.$(OBJEXT) \ - pcem-allegro-gui.$(OBJEXT) \ - pcem-allegro-gui-configure.$(OBJEXT) \ - pcem-allegro-gui-hdconf.$(OBJEXT) \ - pcem-allegro-joystick.$(OBJEXT) \ - pcem-allegro-keyboard.$(OBJEXT) pcem-allegro-main.$(OBJEXT) \ - pcem-allegro-midi.$(OBJEXT) pcem-allegro-mouse.$(OBJEXT) \ - pcem-allegro-video.$(OBJEXT) pcem-amstrad.$(OBJEXT) \ - pcem-cdrom-ioctl-linux.$(OBJEXT) pcem-cdrom-null.$(OBJEXT) \ - pcem-codegen.$(OBJEXT) pcem-codegen_ops.$(OBJEXT) \ - pcem-codegen_timing_486.$(OBJEXT) \ - pcem-codegen_timing_pentium.$(OBJEXT) pcem-compaq.$(OBJEXT) \ - pcem-config.$(OBJEXT) pcem-cpu.$(OBJEXT) pcem-dac.$(OBJEXT) \ - pcem-device.$(OBJEXT) pcem-disc.$(OBJEXT) \ - pcem-disc_fdi.$(OBJEXT) pcem-disc_img.$(OBJEXT) \ - pcem-dma.$(OBJEXT) pcem-fdc.$(OBJEXT) pcem-fdc37c665.$(OBJEXT) \ - pcem-fdi2raw.$(OBJEXT) pcem-gameport.$(OBJEXT) \ - pcem-headland.$(OBJEXT) pcem-i430lx.$(OBJEXT) \ - pcem-i430fx.$(OBJEXT) pcem-i430vx.$(OBJEXT) pcem-ide.$(OBJEXT) \ - pcem-intel.$(OBJEXT) pcem-intel_flash.$(OBJEXT) \ - pcem-io.$(OBJEXT) pcem-jim.$(OBJEXT) pcem-keyboard.$(OBJEXT) \ - pcem-keyboard_amstrad.$(OBJEXT) pcem-keyboard_at.$(OBJEXT) \ - pcem-keyboard_olim24.$(OBJEXT) pcem-keyboard_pcjr.$(OBJEXT) \ - pcem-keyboard_xt.$(OBJEXT) pcem-linux-time.$(OBJEXT) \ - pcem-lpt.$(OBJEXT) pcem-mcr.$(OBJEXT) pcem-mem.$(OBJEXT) \ - pcem-model.$(OBJEXT) pcem-mouse.$(OBJEXT) \ - pcem-mouse_ps2.$(OBJEXT) pcem-mouse_serial.$(OBJEXT) \ - pcem-neat.$(OBJEXT) pcem-nmi.$(OBJEXT) pcem-nvr.$(OBJEXT) \ - pcem-olivetti_m24.$(OBJEXT) pcem-opti.$(OBJEXT) \ - pcem-pc.$(OBJEXT) pcem-pci.$(OBJEXT) pcem-pic.$(OBJEXT) \ - pcem-piix.$(OBJEXT) pcem-pit.$(OBJEXT) pcem-ppi.$(OBJEXT) \ - pcem-ps1.$(OBJEXT) pcem-rom.$(OBJEXT) pcem-serial.$(OBJEXT) \ - pcem-sis496.$(OBJEXT) pcem-sound.$(OBJEXT) \ - pcem-sound_ad1848.$(OBJEXT) pcem-sound_adlib.$(OBJEXT) \ - pcem-sound_adlibgold.$(OBJEXT) pcem-sound_cms.$(OBJEXT) \ - pcem-sound_emu8k.$(OBJEXT) pcem-sound_gus.$(OBJEXT) \ - pcem-sound_mpu401_uart.$(OBJEXT) pcem-sound_opl.$(OBJEXT) \ - pcem-sound_pas16.$(OBJEXT) pcem-sound_sb.$(OBJEXT) \ - pcem-sound_sb_dsp.$(OBJEXT) pcem-sound_sn76489.$(OBJEXT) \ - pcem-sound_speaker.$(OBJEXT) pcem-sound_ssi2001.$(OBJEXT) \ - pcem-sound_wss.$(OBJEXT) pcem-soundopenal.$(OBJEXT) \ - pcem-thread-pthread.$(OBJEXT) pcem-timer.$(OBJEXT) \ - pcem-um8669f.$(OBJEXT) pcem-um8881f.$(OBJEXT) \ - pcem-vid_ati_eeprom.$(OBJEXT) pcem-vid_ati_mach64.$(OBJEXT) \ - pcem-vid_ati18800.$(OBJEXT) pcem-vid_ati28800.$(OBJEXT) \ - pcem-vid_ati68860_ramdac.$(OBJEXT) pcem-vid_cga.$(OBJEXT) \ - pcem-vid_cl5429.$(OBJEXT) pcem-vid_ega.$(OBJEXT) \ - pcem-vid_et4000.$(OBJEXT) pcem-vid_et4000w32.$(OBJEXT) \ - pcem-vid_hercules.$(OBJEXT) pcem-vid_icd2061.$(OBJEXT) \ - pcem-vid_ics2595.$(OBJEXT) pcem-vid_mda.$(OBJEXT) \ - pcem-vid_olivetti_m24.$(OBJEXT) pcem-vid_oti067.$(OBJEXT) \ - pcem-vid_paradise.$(OBJEXT) pcem-vid_pc200.$(OBJEXT) \ - pcem-vid_pc1512.$(OBJEXT) pcem-vid_pc1640.$(OBJEXT) \ - pcem-vid_pcjr.$(OBJEXT) pcem-vid_s3.$(OBJEXT) \ - pcem-vid_s3_virge.$(OBJEXT) pcem-vid_sdac_ramdac.$(OBJEXT) \ - pcem-vid_stg_ramdac.$(OBJEXT) pcem-vid_svga.$(OBJEXT) \ - pcem-vid_svga_render.$(OBJEXT) pcem-vid_tandy.$(OBJEXT) \ - pcem-vid_tgui9440.$(OBJEXT) pcem-vid_tkd8001_ramdac.$(OBJEXT) \ - pcem-vid_tvga.$(OBJEXT) pcem-vid_unk_ramdac.$(OBJEXT) \ - pcem-vid_vga.$(OBJEXT) pcem-vid_voodoo.$(OBJEXT) \ - pcem-video.$(OBJEXT) pcem-wd76c10.$(OBJEXT) \ - pcem-x86seg.$(OBJEXT) pcem-x87.$(OBJEXT) pcem-xtide.$(OBJEXT) \ - sound_dbopl.$(OBJEXT) sound_resid.$(OBJEXT) dbopl.$(OBJEXT) \ - convolve.$(OBJEXT) convolve-sse.$(OBJEXT) envelope.$(OBJEXT) \ - extfilt.$(OBJEXT) filter.$(OBJEXT) pot.$(OBJEXT) sid.$(OBJEXT) \ - voice.$(OBJEXT) wave6581_PS_.$(OBJEXT) wave6581_PST.$(OBJEXT) \ - wave6581_P_T.$(OBJEXT) wave6581__ST.$(OBJEXT) \ - wave8580_PS_.$(OBJEXT) wave8580_PST.$(OBJEXT) \ - wave8580_P_T.$(OBJEXT) wave8580__ST.$(OBJEXT) wave.$(OBJEXT) \ - $(am__objects_1) $(am__objects_2) -pcem_OBJECTS = $(am_pcem_OBJECTS) -am__DEPENDENCIES_1 = -pcem_DEPENDENCIES = $(am__DEPENDENCIES_1) -SCRIPTS = $(noinst_SCRIPTS) -DEFAULT_INCLUDES = -I.@am__isrc@ -depcomp = $(SHELL) $(top_srcdir)/depcomp -am__depfiles_maybe = depfiles -am__mv = mv -f -COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ - $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -CCLD = $(CC) -LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ -CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ - $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -CXXLD = $(CXX) -CXXLINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) \ - -o $@ -SOURCES = $(pcem_SOURCES) -DIST_SOURCES = $(am__pcem_SOURCES_DIST) -ETAGS = etags -CTAGS = ctags -DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) -ACLOCAL = @ACLOCAL@ -ALLEGRO_CONFIG = @ALLEGRO_CONFIG@ -AMTAR = @AMTAR@ -AUTOCONF = @AUTOCONF@ -AUTOHEADER = @AUTOHEADER@ -AUTOMAKE = @AUTOMAKE@ -AWK = @AWK@ -CC = @CC@ -CCDEPMODE = @CCDEPMODE@ -CFLAGS = @CFLAGS@ -CPPFLAGS = @CPPFLAGS@ -CXX = @CXX@ -CXXDEPMODE = @CXXDEPMODE@ -CXXFLAGS = @CXXFLAGS@ -CYGPATH_W = @CYGPATH_W@ -DEFS = @DEFS@ -DEPDIR = @DEPDIR@ -ECHO_C = @ECHO_C@ -ECHO_N = @ECHO_N@ -ECHO_T = @ECHO_T@ -EXEEXT = @EXEEXT@ -INSTALL = @INSTALL@ -INSTALL_DATA = @INSTALL_DATA@ -INSTALL_PROGRAM = @INSTALL_PROGRAM@ -INSTALL_SCRIPT = @INSTALL_SCRIPT@ -INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ -LDFLAGS = @LDFLAGS@ -LIBOBJS = @LIBOBJS@ -LIBS = @LIBS@ -LTLIBOBJS = @LTLIBOBJS@ -MAKEINFO = @MAKEINFO@ -MKDIR_P = @MKDIR_P@ -OBJEXT = @OBJEXT@ -PACKAGE = @PACKAGE@ -PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ -PACKAGE_NAME = @PACKAGE_NAME@ -PACKAGE_STRING = @PACKAGE_STRING@ -PACKAGE_TARNAME = @PACKAGE_TARNAME@ -PACKAGE_URL = @PACKAGE_URL@ -PACKAGE_VERSION = @PACKAGE_VERSION@ -PATH_SEPARATOR = @PATH_SEPARATOR@ -SET_MAKE = @SET_MAKE@ -SHELL = @SHELL@ -STRIP = @STRIP@ -VERSION = @VERSION@ -abs_builddir = @abs_builddir@ -abs_srcdir = @abs_srcdir@ -abs_top_builddir = @abs_top_builddir@ -abs_top_srcdir = @abs_top_srcdir@ -ac_ct_CC = @ac_ct_CC@ -ac_ct_CXX = @ac_ct_CXX@ -allegro_CFLAGS = @allegro_CFLAGS@ -allegro_LIBS = @allegro_LIBS@ -am__include = @am__include@ -am__leading_dot = @am__leading_dot@ -am__quote = @am__quote@ -am__tar = @am__tar@ -am__untar = @am__untar@ -bindir = @bindir@ -build = @build@ -build_alias = @build_alias@ -build_cpu = @build_cpu@ -build_os = @build_os@ -build_vendor = @build_vendor@ -builddir = @builddir@ -datadir = @datadir@ -datarootdir = @datarootdir@ -docdir = @docdir@ -dvidir = @dvidir@ -exec_prefix = @exec_prefix@ -host = @host@ -host_alias = @host_alias@ -host_cpu = @host_cpu@ -host_os = @host_os@ -host_vendor = @host_vendor@ -htmldir = @htmldir@ -includedir = @includedir@ -infodir = @infodir@ -install_sh = @install_sh@ -libdir = @libdir@ -libexecdir = @libexecdir@ -localedir = @localedir@ -localstatedir = @localstatedir@ -mandir = @mandir@ -mkdir_p = @mkdir_p@ -oldincludedir = @oldincludedir@ -pdfdir = @pdfdir@ -prefix = @prefix@ -program_transform_name = @program_transform_name@ -psdir = @psdir@ -sbindir = @sbindir@ -sharedstatedir = @sharedstatedir@ -srcdir = @srcdir@ -sysconfdir = @sysconfdir@ -target_alias = @target_alias@ -top_build_prefix = @top_build_prefix@ -top_builddir = @top_builddir@ -top_srcdir = @top_srcdir@ -noinst_SCRIPTS = ../pcem -CLEANFILES = $(noinst_SCRIPTS) -pcem_CFLAGS = $(allegro_CFLAGS) -pcem_LDADD = $(allegro_LIBS) -lopenal -lalut -pcem_SOURCES = 386.c 386_dynarec.c 386_dynarec_ops.c 808x.c \ - acer386sx.c ali1429.c allegro-gui.c allegro-gui-configure.c \ - allegro-gui-hdconf.c allegro-joystick.c allegro-keyboard.c \ - allegro-main.c allegro-midi.c allegro-mouse.c allegro-video.c \ - amstrad.c cdrom-ioctl-linux.c cdrom-null.c codegen.c \ - codegen_ops.c codegen_timing_486.c codegen_timing_pentium.c \ - compaq.c config.c cpu.c dac.c device.c disc.c disc_fdi.c \ - disc_img.c dma.c fdc.c fdc37c665.c fdi2raw.c gameport.c \ - headland.c i430lx.c i430fx.c i430vx.c ide.c intel.c \ - intel_flash.c io.c jim.c keyboard.c keyboard_amstrad.c \ - keyboard_at.c keyboard_olim24.c keyboard_pcjr.c keyboard_xt.c \ - linux-time.c lpt.c mcr.c mem.c model.c mouse.c mouse_ps2.c \ - mouse_serial.c neat.c nmi.c nvr.c olivetti_m24.c opti.c pc.c \ - pci.c pic.c piix.c pit.c ppi.c ps1.c rom.c serial.c sis496.c \ - sound.c sound_ad1848.c sound_adlib.c sound_adlibgold.c \ - sound_cms.c sound_emu8k.c sound_gus.c sound_mpu401_uart.c \ - sound_opl.c sound_pas16.c sound_sb.c sound_sb_dsp.c \ - sound_sn76489.c sound_speaker.c sound_ssi2001.c sound_wss.c \ - soundopenal.c thread-pthread.c timer.c um8669f.c um8881f.c \ - vid_ati_eeprom.c vid_ati_mach64.c vid_ati18800.c \ - vid_ati28800.c vid_ati68860_ramdac.c vid_cga.c vid_cl5429.c \ - vid_ega.c vid_et4000.c vid_et4000w32.c vid_hercules.c \ - vid_icd2061.c vid_ics2595.c vid_mda.c vid_olivetti_m24.c \ - vid_oti067.c vid_paradise.c vid_pc200.c vid_pc1512.c \ - vid_pc1640.c vid_pcjr.c vid_s3.c vid_s3_virge.c \ - vid_sdac_ramdac.c vid_stg_ramdac.c vid_svga.c \ - vid_svga_render.c vid_tandy.c vid_tgui9440.c \ - vid_tkd8001_ramdac.c vid_tvga.c vid_unk_ramdac.c vid_vga.c \ - vid_voodoo.c video.c wd76c10.c x86seg.c x87.c xtide.c \ - sound_dbopl.cc sound_resid.cc dosbox/dbopl.cpp \ - resid-fp/convolve.cc resid-fp/convolve-sse.cc \ - resid-fp/envelope.cc resid-fp/extfilt.cc resid-fp/filter.cc \ - resid-fp/pot.cc resid-fp/sid.cc resid-fp/voice.cc \ - resid-fp/wave6581_PS_.cc resid-fp/wave6581_PST.cc \ - resid-fp/wave6581_P_T.cc resid-fp/wave6581__ST.cc \ - resid-fp/wave8580_PS_.cc resid-fp/wave8580_PST.cc \ - resid-fp/wave8580_P_T.cc resid-fp/wave8580__ST.cc \ - resid-fp/wave.cc $(am__append_1) $(am__append_2) -all: all-am - -.SUFFIXES: -.SUFFIXES: .c .cc .cpp .o .obj -$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) - @for dep in $?; do \ - case '$(am__configure_deps)' in \ - *$$dep*) \ - ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ - && { if test -f $@; then exit 0; else break; fi; }; \ - exit 1;; \ - esac; \ - done; \ - echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/Makefile'; \ - $(am__cd) $(top_srcdir) && \ - $(AUTOMAKE) --gnu src/Makefile -.PRECIOUS: Makefile -Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status - @case '$?' in \ - *config.status*) \ - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ - *) \ - echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ - cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ - esac; - -$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh - -$(top_srcdir)/configure: $(am__configure_deps) - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh -$(ACLOCAL_M4): $(am__aclocal_m4_deps) - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh -$(am__aclocal_m4_deps): -install-binPROGRAMS: $(bin_PROGRAMS) - @$(NORMAL_INSTALL) - test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)" - @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ - for p in $$list; do echo "$$p $$p"; done | \ - sed 's/$(EXEEXT)$$//' | \ - while read p p1; do if test -f $$p; \ - then echo "$$p"; echo "$$p"; else :; fi; \ - done | \ - sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \ - -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ - sed 'N;N;N;s,\n, ,g' | \ - $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ - { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ - if ($$2 == $$4) files[d] = files[d] " " $$1; \ - else { print "f", $$3 "/" $$4, $$1; } } \ - END { for (d in files) print "f", d, files[d] }' | \ - while read type dir files; do \ - if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ - test -z "$$files" || { \ - echo " $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ - $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ - } \ - ; done - -uninstall-binPROGRAMS: - @$(NORMAL_UNINSTALL) - @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ - files=`for p in $$list; do echo "$$p"; done | \ - sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ - -e 's/$$/$(EXEEXT)/' `; \ - test -n "$$list" || exit 0; \ - echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ - cd "$(DESTDIR)$(bindir)" && rm -f $$files - -clean-binPROGRAMS: - -test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS) -pcem$(EXEEXT): $(pcem_OBJECTS) $(pcem_DEPENDENCIES) - @rm -f pcem$(EXEEXT) - $(CXXLINK) $(pcem_OBJECTS) $(pcem_LDADD) $(LIBS) - -mostlyclean-compile: - -rm -f *.$(OBJEXT) - -distclean-compile: - -rm -f *.tab.c - -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/convolve-sse.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/convolve.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbopl.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/envelope.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/extfilt.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/filter.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-386.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-386_dynarec.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-386_dynarec_ops.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-808x.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-acer386sx.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-ali1429.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-allegro-gui-configure.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-allegro-gui-hdconf.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-allegro-gui.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-allegro-joystick.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-allegro-keyboard.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-allegro-main.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-allegro-midi.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-allegro-mouse.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-allegro-video.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-amstrad.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-cdrom-ioctl-linux.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-cdrom-null.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-codegen.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-codegen_ops.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-codegen_timing_486.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-codegen_timing_pentium.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-codegen_x86-64.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-codegen_x86.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-compaq.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-config.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-cpu.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-dac.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-device.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-disc.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-disc_fdi.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-disc_img.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-dma.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-fdc.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-fdc37c665.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-fdi2raw.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-gameport.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-headland.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-i430fx.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-i430lx.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-i430vx.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-ide.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-intel.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-intel_flash.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-io.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-jim.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-keyboard.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-keyboard_amstrad.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-keyboard_at.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-keyboard_olim24.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-keyboard_pcjr.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-keyboard_xt.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-linux-time.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-lpt.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-mcr.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-mem.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-model.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-mouse.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-mouse_ps2.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-mouse_serial.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-neat.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-nmi.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-nvr.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-olivetti_m24.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-opti.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-pc.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-pci.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-pic.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-piix.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-pit.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-ppi.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-ps1.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-rom.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-serial.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-sis496.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-sound.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-sound_ad1848.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-sound_adlib.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-sound_adlibgold.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-sound_cms.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-sound_emu8k.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-sound_gus.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-sound_mpu401_uart.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-sound_opl.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-sound_pas16.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-sound_sb.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-sound_sb_dsp.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-sound_sn76489.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-sound_speaker.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-sound_ssi2001.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-sound_wss.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-soundopenal.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-thread-pthread.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-timer.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-um8669f.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-um8881f.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_ati18800.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_ati28800.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_ati68860_ramdac.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_ati_eeprom.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_ati_mach64.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_cga.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_cl5429.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_ega.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_et4000.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_et4000w32.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_hercules.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_icd2061.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_ics2595.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_mda.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_olivetti_m24.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_oti067.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_paradise.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_pc1512.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_pc1640.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_pc200.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_pcjr.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_s3.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_s3_virge.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_sdac_ramdac.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_stg_ramdac.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_svga.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_svga_render.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_tandy.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_tgui9440.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_tkd8001_ramdac.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_tvga.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_unk_ramdac.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_vga.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_voodoo.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-video.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-wd76c10.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-x86seg.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-x87.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-xtide.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pot.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sid.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sound_dbopl.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sound_resid.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/voice.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/wave.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/wave6581_PST.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/wave6581_PS_.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/wave6581_P_T.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/wave6581__ST.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/wave8580_PST.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/wave8580_PS_.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/wave8580_P_T.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/wave8580__ST.Po@am__quote@ - -.c.o: -@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(COMPILE) -c $< - -.c.obj: -@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` - -pcem-386.o: 386.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-386.o -MD -MP -MF $(DEPDIR)/pcem-386.Tpo -c -o pcem-386.o `test -f '386.c' || echo '$(srcdir)/'`386.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-386.Tpo $(DEPDIR)/pcem-386.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='386.c' object='pcem-386.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-386.o `test -f '386.c' || echo '$(srcdir)/'`386.c - -pcem-386.obj: 386.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-386.obj -MD -MP -MF $(DEPDIR)/pcem-386.Tpo -c -o pcem-386.obj `if test -f '386.c'; then $(CYGPATH_W) '386.c'; else $(CYGPATH_W) '$(srcdir)/386.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-386.Tpo $(DEPDIR)/pcem-386.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='386.c' object='pcem-386.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-386.obj `if test -f '386.c'; then $(CYGPATH_W) '386.c'; else $(CYGPATH_W) '$(srcdir)/386.c'; fi` - -pcem-386_dynarec.o: 386_dynarec.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-386_dynarec.o -MD -MP -MF $(DEPDIR)/pcem-386_dynarec.Tpo -c -o pcem-386_dynarec.o `test -f '386_dynarec.c' || echo '$(srcdir)/'`386_dynarec.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-386_dynarec.Tpo $(DEPDIR)/pcem-386_dynarec.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='386_dynarec.c' object='pcem-386_dynarec.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-386_dynarec.o `test -f '386_dynarec.c' || echo '$(srcdir)/'`386_dynarec.c - -pcem-386_dynarec.obj: 386_dynarec.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-386_dynarec.obj -MD -MP -MF $(DEPDIR)/pcem-386_dynarec.Tpo -c -o pcem-386_dynarec.obj `if test -f '386_dynarec.c'; then $(CYGPATH_W) '386_dynarec.c'; else $(CYGPATH_W) '$(srcdir)/386_dynarec.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-386_dynarec.Tpo $(DEPDIR)/pcem-386_dynarec.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='386_dynarec.c' object='pcem-386_dynarec.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-386_dynarec.obj `if test -f '386_dynarec.c'; then $(CYGPATH_W) '386_dynarec.c'; else $(CYGPATH_W) '$(srcdir)/386_dynarec.c'; fi` - -pcem-386_dynarec_ops.o: 386_dynarec_ops.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-386_dynarec_ops.o -MD -MP -MF $(DEPDIR)/pcem-386_dynarec_ops.Tpo -c -o pcem-386_dynarec_ops.o `test -f '386_dynarec_ops.c' || echo '$(srcdir)/'`386_dynarec_ops.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-386_dynarec_ops.Tpo $(DEPDIR)/pcem-386_dynarec_ops.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='386_dynarec_ops.c' object='pcem-386_dynarec_ops.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-386_dynarec_ops.o `test -f '386_dynarec_ops.c' || echo '$(srcdir)/'`386_dynarec_ops.c - -pcem-386_dynarec_ops.obj: 386_dynarec_ops.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-386_dynarec_ops.obj -MD -MP -MF $(DEPDIR)/pcem-386_dynarec_ops.Tpo -c -o pcem-386_dynarec_ops.obj `if test -f '386_dynarec_ops.c'; then $(CYGPATH_W) '386_dynarec_ops.c'; else $(CYGPATH_W) '$(srcdir)/386_dynarec_ops.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-386_dynarec_ops.Tpo $(DEPDIR)/pcem-386_dynarec_ops.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='386_dynarec_ops.c' object='pcem-386_dynarec_ops.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-386_dynarec_ops.obj `if test -f '386_dynarec_ops.c'; then $(CYGPATH_W) '386_dynarec_ops.c'; else $(CYGPATH_W) '$(srcdir)/386_dynarec_ops.c'; fi` - -pcem-808x.o: 808x.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-808x.o -MD -MP -MF $(DEPDIR)/pcem-808x.Tpo -c -o pcem-808x.o `test -f '808x.c' || echo '$(srcdir)/'`808x.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-808x.Tpo $(DEPDIR)/pcem-808x.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='808x.c' object='pcem-808x.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-808x.o `test -f '808x.c' || echo '$(srcdir)/'`808x.c - -pcem-808x.obj: 808x.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-808x.obj -MD -MP -MF $(DEPDIR)/pcem-808x.Tpo -c -o pcem-808x.obj `if test -f '808x.c'; then $(CYGPATH_W) '808x.c'; else $(CYGPATH_W) '$(srcdir)/808x.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-808x.Tpo $(DEPDIR)/pcem-808x.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='808x.c' object='pcem-808x.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-808x.obj `if test -f '808x.c'; then $(CYGPATH_W) '808x.c'; else $(CYGPATH_W) '$(srcdir)/808x.c'; fi` - -pcem-acer386sx.o: acer386sx.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-acer386sx.o -MD -MP -MF $(DEPDIR)/pcem-acer386sx.Tpo -c -o pcem-acer386sx.o `test -f 'acer386sx.c' || echo '$(srcdir)/'`acer386sx.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-acer386sx.Tpo $(DEPDIR)/pcem-acer386sx.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='acer386sx.c' object='pcem-acer386sx.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-acer386sx.o `test -f 'acer386sx.c' || echo '$(srcdir)/'`acer386sx.c - -pcem-acer386sx.obj: acer386sx.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-acer386sx.obj -MD -MP -MF $(DEPDIR)/pcem-acer386sx.Tpo -c -o pcem-acer386sx.obj `if test -f 'acer386sx.c'; then $(CYGPATH_W) 'acer386sx.c'; else $(CYGPATH_W) '$(srcdir)/acer386sx.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-acer386sx.Tpo $(DEPDIR)/pcem-acer386sx.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='acer386sx.c' object='pcem-acer386sx.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-acer386sx.obj `if test -f 'acer386sx.c'; then $(CYGPATH_W) 'acer386sx.c'; else $(CYGPATH_W) '$(srcdir)/acer386sx.c'; fi` - -pcem-ali1429.o: ali1429.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-ali1429.o -MD -MP -MF $(DEPDIR)/pcem-ali1429.Tpo -c -o pcem-ali1429.o `test -f 'ali1429.c' || echo '$(srcdir)/'`ali1429.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-ali1429.Tpo $(DEPDIR)/pcem-ali1429.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='ali1429.c' object='pcem-ali1429.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-ali1429.o `test -f 'ali1429.c' || echo '$(srcdir)/'`ali1429.c - -pcem-ali1429.obj: ali1429.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-ali1429.obj -MD -MP -MF $(DEPDIR)/pcem-ali1429.Tpo -c -o pcem-ali1429.obj `if test -f 'ali1429.c'; then $(CYGPATH_W) 'ali1429.c'; else $(CYGPATH_W) '$(srcdir)/ali1429.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-ali1429.Tpo $(DEPDIR)/pcem-ali1429.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='ali1429.c' object='pcem-ali1429.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-ali1429.obj `if test -f 'ali1429.c'; then $(CYGPATH_W) 'ali1429.c'; else $(CYGPATH_W) '$(srcdir)/ali1429.c'; fi` - -pcem-allegro-gui.o: allegro-gui.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-allegro-gui.o -MD -MP -MF $(DEPDIR)/pcem-allegro-gui.Tpo -c -o pcem-allegro-gui.o `test -f 'allegro-gui.c' || echo '$(srcdir)/'`allegro-gui.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-allegro-gui.Tpo $(DEPDIR)/pcem-allegro-gui.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='allegro-gui.c' object='pcem-allegro-gui.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-allegro-gui.o `test -f 'allegro-gui.c' || echo '$(srcdir)/'`allegro-gui.c - -pcem-allegro-gui.obj: allegro-gui.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-allegro-gui.obj -MD -MP -MF $(DEPDIR)/pcem-allegro-gui.Tpo -c -o pcem-allegro-gui.obj `if test -f 'allegro-gui.c'; then $(CYGPATH_W) 'allegro-gui.c'; else $(CYGPATH_W) '$(srcdir)/allegro-gui.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-allegro-gui.Tpo $(DEPDIR)/pcem-allegro-gui.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='allegro-gui.c' object='pcem-allegro-gui.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-allegro-gui.obj `if test -f 'allegro-gui.c'; then $(CYGPATH_W) 'allegro-gui.c'; else $(CYGPATH_W) '$(srcdir)/allegro-gui.c'; fi` - -pcem-allegro-gui-configure.o: allegro-gui-configure.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-allegro-gui-configure.o -MD -MP -MF $(DEPDIR)/pcem-allegro-gui-configure.Tpo -c -o pcem-allegro-gui-configure.o `test -f 'allegro-gui-configure.c' || echo '$(srcdir)/'`allegro-gui-configure.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-allegro-gui-configure.Tpo $(DEPDIR)/pcem-allegro-gui-configure.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='allegro-gui-configure.c' object='pcem-allegro-gui-configure.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-allegro-gui-configure.o `test -f 'allegro-gui-configure.c' || echo '$(srcdir)/'`allegro-gui-configure.c - -pcem-allegro-gui-configure.obj: allegro-gui-configure.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-allegro-gui-configure.obj -MD -MP -MF $(DEPDIR)/pcem-allegro-gui-configure.Tpo -c -o pcem-allegro-gui-configure.obj `if test -f 'allegro-gui-configure.c'; then $(CYGPATH_W) 'allegro-gui-configure.c'; else $(CYGPATH_W) '$(srcdir)/allegro-gui-configure.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-allegro-gui-configure.Tpo $(DEPDIR)/pcem-allegro-gui-configure.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='allegro-gui-configure.c' object='pcem-allegro-gui-configure.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-allegro-gui-configure.obj `if test -f 'allegro-gui-configure.c'; then $(CYGPATH_W) 'allegro-gui-configure.c'; else $(CYGPATH_W) '$(srcdir)/allegro-gui-configure.c'; fi` - -pcem-allegro-gui-hdconf.o: allegro-gui-hdconf.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-allegro-gui-hdconf.o -MD -MP -MF $(DEPDIR)/pcem-allegro-gui-hdconf.Tpo -c -o pcem-allegro-gui-hdconf.o `test -f 'allegro-gui-hdconf.c' || echo '$(srcdir)/'`allegro-gui-hdconf.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-allegro-gui-hdconf.Tpo $(DEPDIR)/pcem-allegro-gui-hdconf.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='allegro-gui-hdconf.c' object='pcem-allegro-gui-hdconf.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-allegro-gui-hdconf.o `test -f 'allegro-gui-hdconf.c' || echo '$(srcdir)/'`allegro-gui-hdconf.c - -pcem-allegro-gui-hdconf.obj: allegro-gui-hdconf.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-allegro-gui-hdconf.obj -MD -MP -MF $(DEPDIR)/pcem-allegro-gui-hdconf.Tpo -c -o pcem-allegro-gui-hdconf.obj `if test -f 'allegro-gui-hdconf.c'; then $(CYGPATH_W) 'allegro-gui-hdconf.c'; else $(CYGPATH_W) '$(srcdir)/allegro-gui-hdconf.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-allegro-gui-hdconf.Tpo $(DEPDIR)/pcem-allegro-gui-hdconf.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='allegro-gui-hdconf.c' object='pcem-allegro-gui-hdconf.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-allegro-gui-hdconf.obj `if test -f 'allegro-gui-hdconf.c'; then $(CYGPATH_W) 'allegro-gui-hdconf.c'; else $(CYGPATH_W) '$(srcdir)/allegro-gui-hdconf.c'; fi` - -pcem-allegro-joystick.o: allegro-joystick.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-allegro-joystick.o -MD -MP -MF $(DEPDIR)/pcem-allegro-joystick.Tpo -c -o pcem-allegro-joystick.o `test -f 'allegro-joystick.c' || echo '$(srcdir)/'`allegro-joystick.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-allegro-joystick.Tpo $(DEPDIR)/pcem-allegro-joystick.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='allegro-joystick.c' object='pcem-allegro-joystick.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-allegro-joystick.o `test -f 'allegro-joystick.c' || echo '$(srcdir)/'`allegro-joystick.c - -pcem-allegro-joystick.obj: allegro-joystick.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-allegro-joystick.obj -MD -MP -MF $(DEPDIR)/pcem-allegro-joystick.Tpo -c -o pcem-allegro-joystick.obj `if test -f 'allegro-joystick.c'; then $(CYGPATH_W) 'allegro-joystick.c'; else $(CYGPATH_W) '$(srcdir)/allegro-joystick.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-allegro-joystick.Tpo $(DEPDIR)/pcem-allegro-joystick.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='allegro-joystick.c' object='pcem-allegro-joystick.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-allegro-joystick.obj `if test -f 'allegro-joystick.c'; then $(CYGPATH_W) 'allegro-joystick.c'; else $(CYGPATH_W) '$(srcdir)/allegro-joystick.c'; fi` - -pcem-allegro-keyboard.o: allegro-keyboard.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-allegro-keyboard.o -MD -MP -MF $(DEPDIR)/pcem-allegro-keyboard.Tpo -c -o pcem-allegro-keyboard.o `test -f 'allegro-keyboard.c' || echo '$(srcdir)/'`allegro-keyboard.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-allegro-keyboard.Tpo $(DEPDIR)/pcem-allegro-keyboard.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='allegro-keyboard.c' object='pcem-allegro-keyboard.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-allegro-keyboard.o `test -f 'allegro-keyboard.c' || echo '$(srcdir)/'`allegro-keyboard.c - -pcem-allegro-keyboard.obj: allegro-keyboard.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-allegro-keyboard.obj -MD -MP -MF $(DEPDIR)/pcem-allegro-keyboard.Tpo -c -o pcem-allegro-keyboard.obj `if test -f 'allegro-keyboard.c'; then $(CYGPATH_W) 'allegro-keyboard.c'; else $(CYGPATH_W) '$(srcdir)/allegro-keyboard.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-allegro-keyboard.Tpo $(DEPDIR)/pcem-allegro-keyboard.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='allegro-keyboard.c' object='pcem-allegro-keyboard.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-allegro-keyboard.obj `if test -f 'allegro-keyboard.c'; then $(CYGPATH_W) 'allegro-keyboard.c'; else $(CYGPATH_W) '$(srcdir)/allegro-keyboard.c'; fi` - -pcem-allegro-main.o: allegro-main.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-allegro-main.o -MD -MP -MF $(DEPDIR)/pcem-allegro-main.Tpo -c -o pcem-allegro-main.o `test -f 'allegro-main.c' || echo '$(srcdir)/'`allegro-main.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-allegro-main.Tpo $(DEPDIR)/pcem-allegro-main.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='allegro-main.c' object='pcem-allegro-main.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-allegro-main.o `test -f 'allegro-main.c' || echo '$(srcdir)/'`allegro-main.c - -pcem-allegro-main.obj: allegro-main.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-allegro-main.obj -MD -MP -MF $(DEPDIR)/pcem-allegro-main.Tpo -c -o pcem-allegro-main.obj `if test -f 'allegro-main.c'; then $(CYGPATH_W) 'allegro-main.c'; else $(CYGPATH_W) '$(srcdir)/allegro-main.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-allegro-main.Tpo $(DEPDIR)/pcem-allegro-main.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='allegro-main.c' object='pcem-allegro-main.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-allegro-main.obj `if test -f 'allegro-main.c'; then $(CYGPATH_W) 'allegro-main.c'; else $(CYGPATH_W) '$(srcdir)/allegro-main.c'; fi` - -pcem-allegro-midi.o: allegro-midi.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-allegro-midi.o -MD -MP -MF $(DEPDIR)/pcem-allegro-midi.Tpo -c -o pcem-allegro-midi.o `test -f 'allegro-midi.c' || echo '$(srcdir)/'`allegro-midi.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-allegro-midi.Tpo $(DEPDIR)/pcem-allegro-midi.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='allegro-midi.c' object='pcem-allegro-midi.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-allegro-midi.o `test -f 'allegro-midi.c' || echo '$(srcdir)/'`allegro-midi.c - -pcem-allegro-midi.obj: allegro-midi.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-allegro-midi.obj -MD -MP -MF $(DEPDIR)/pcem-allegro-midi.Tpo -c -o pcem-allegro-midi.obj `if test -f 'allegro-midi.c'; then $(CYGPATH_W) 'allegro-midi.c'; else $(CYGPATH_W) '$(srcdir)/allegro-midi.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-allegro-midi.Tpo $(DEPDIR)/pcem-allegro-midi.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='allegro-midi.c' object='pcem-allegro-midi.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-allegro-midi.obj `if test -f 'allegro-midi.c'; then $(CYGPATH_W) 'allegro-midi.c'; else $(CYGPATH_W) '$(srcdir)/allegro-midi.c'; fi` - -pcem-allegro-mouse.o: allegro-mouse.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-allegro-mouse.o -MD -MP -MF $(DEPDIR)/pcem-allegro-mouse.Tpo -c -o pcem-allegro-mouse.o `test -f 'allegro-mouse.c' || echo '$(srcdir)/'`allegro-mouse.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-allegro-mouse.Tpo $(DEPDIR)/pcem-allegro-mouse.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='allegro-mouse.c' object='pcem-allegro-mouse.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-allegro-mouse.o `test -f 'allegro-mouse.c' || echo '$(srcdir)/'`allegro-mouse.c - -pcem-allegro-mouse.obj: allegro-mouse.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-allegro-mouse.obj -MD -MP -MF $(DEPDIR)/pcem-allegro-mouse.Tpo -c -o pcem-allegro-mouse.obj `if test -f 'allegro-mouse.c'; then $(CYGPATH_W) 'allegro-mouse.c'; else $(CYGPATH_W) '$(srcdir)/allegro-mouse.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-allegro-mouse.Tpo $(DEPDIR)/pcem-allegro-mouse.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='allegro-mouse.c' object='pcem-allegro-mouse.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-allegro-mouse.obj `if test -f 'allegro-mouse.c'; then $(CYGPATH_W) 'allegro-mouse.c'; else $(CYGPATH_W) '$(srcdir)/allegro-mouse.c'; fi` - -pcem-allegro-video.o: allegro-video.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-allegro-video.o -MD -MP -MF $(DEPDIR)/pcem-allegro-video.Tpo -c -o pcem-allegro-video.o `test -f 'allegro-video.c' || echo '$(srcdir)/'`allegro-video.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-allegro-video.Tpo $(DEPDIR)/pcem-allegro-video.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='allegro-video.c' object='pcem-allegro-video.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-allegro-video.o `test -f 'allegro-video.c' || echo '$(srcdir)/'`allegro-video.c - -pcem-allegro-video.obj: allegro-video.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-allegro-video.obj -MD -MP -MF $(DEPDIR)/pcem-allegro-video.Tpo -c -o pcem-allegro-video.obj `if test -f 'allegro-video.c'; then $(CYGPATH_W) 'allegro-video.c'; else $(CYGPATH_W) '$(srcdir)/allegro-video.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-allegro-video.Tpo $(DEPDIR)/pcem-allegro-video.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='allegro-video.c' object='pcem-allegro-video.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-allegro-video.obj `if test -f 'allegro-video.c'; then $(CYGPATH_W) 'allegro-video.c'; else $(CYGPATH_W) '$(srcdir)/allegro-video.c'; fi` - -pcem-amstrad.o: amstrad.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-amstrad.o -MD -MP -MF $(DEPDIR)/pcem-amstrad.Tpo -c -o pcem-amstrad.o `test -f 'amstrad.c' || echo '$(srcdir)/'`amstrad.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-amstrad.Tpo $(DEPDIR)/pcem-amstrad.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='amstrad.c' object='pcem-amstrad.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-amstrad.o `test -f 'amstrad.c' || echo '$(srcdir)/'`amstrad.c - -pcem-amstrad.obj: amstrad.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-amstrad.obj -MD -MP -MF $(DEPDIR)/pcem-amstrad.Tpo -c -o pcem-amstrad.obj `if test -f 'amstrad.c'; then $(CYGPATH_W) 'amstrad.c'; else $(CYGPATH_W) '$(srcdir)/amstrad.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-amstrad.Tpo $(DEPDIR)/pcem-amstrad.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='amstrad.c' object='pcem-amstrad.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-amstrad.obj `if test -f 'amstrad.c'; then $(CYGPATH_W) 'amstrad.c'; else $(CYGPATH_W) '$(srcdir)/amstrad.c'; fi` - -pcem-cdrom-ioctl-linux.o: cdrom-ioctl-linux.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-cdrom-ioctl-linux.o -MD -MP -MF $(DEPDIR)/pcem-cdrom-ioctl-linux.Tpo -c -o pcem-cdrom-ioctl-linux.o `test -f 'cdrom-ioctl-linux.c' || echo '$(srcdir)/'`cdrom-ioctl-linux.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-cdrom-ioctl-linux.Tpo $(DEPDIR)/pcem-cdrom-ioctl-linux.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='cdrom-ioctl-linux.c' object='pcem-cdrom-ioctl-linux.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-cdrom-ioctl-linux.o `test -f 'cdrom-ioctl-linux.c' || echo '$(srcdir)/'`cdrom-ioctl-linux.c - -pcem-cdrom-ioctl-linux.obj: cdrom-ioctl-linux.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-cdrom-ioctl-linux.obj -MD -MP -MF $(DEPDIR)/pcem-cdrom-ioctl-linux.Tpo -c -o pcem-cdrom-ioctl-linux.obj `if test -f 'cdrom-ioctl-linux.c'; then $(CYGPATH_W) 'cdrom-ioctl-linux.c'; else $(CYGPATH_W) '$(srcdir)/cdrom-ioctl-linux.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-cdrom-ioctl-linux.Tpo $(DEPDIR)/pcem-cdrom-ioctl-linux.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='cdrom-ioctl-linux.c' object='pcem-cdrom-ioctl-linux.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-cdrom-ioctl-linux.obj `if test -f 'cdrom-ioctl-linux.c'; then $(CYGPATH_W) 'cdrom-ioctl-linux.c'; else $(CYGPATH_W) '$(srcdir)/cdrom-ioctl-linux.c'; fi` - -pcem-cdrom-null.o: cdrom-null.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-cdrom-null.o -MD -MP -MF $(DEPDIR)/pcem-cdrom-null.Tpo -c -o pcem-cdrom-null.o `test -f 'cdrom-null.c' || echo '$(srcdir)/'`cdrom-null.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-cdrom-null.Tpo $(DEPDIR)/pcem-cdrom-null.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='cdrom-null.c' object='pcem-cdrom-null.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-cdrom-null.o `test -f 'cdrom-null.c' || echo '$(srcdir)/'`cdrom-null.c - -pcem-cdrom-null.obj: cdrom-null.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-cdrom-null.obj -MD -MP -MF $(DEPDIR)/pcem-cdrom-null.Tpo -c -o pcem-cdrom-null.obj `if test -f 'cdrom-null.c'; then $(CYGPATH_W) 'cdrom-null.c'; else $(CYGPATH_W) '$(srcdir)/cdrom-null.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-cdrom-null.Tpo $(DEPDIR)/pcem-cdrom-null.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='cdrom-null.c' object='pcem-cdrom-null.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-cdrom-null.obj `if test -f 'cdrom-null.c'; then $(CYGPATH_W) 'cdrom-null.c'; else $(CYGPATH_W) '$(srcdir)/cdrom-null.c'; fi` - -pcem-codegen.o: codegen.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-codegen.o -MD -MP -MF $(DEPDIR)/pcem-codegen.Tpo -c -o pcem-codegen.o `test -f 'codegen.c' || echo '$(srcdir)/'`codegen.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-codegen.Tpo $(DEPDIR)/pcem-codegen.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='codegen.c' object='pcem-codegen.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-codegen.o `test -f 'codegen.c' || echo '$(srcdir)/'`codegen.c - -pcem-codegen.obj: codegen.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-codegen.obj -MD -MP -MF $(DEPDIR)/pcem-codegen.Tpo -c -o pcem-codegen.obj `if test -f 'codegen.c'; then $(CYGPATH_W) 'codegen.c'; else $(CYGPATH_W) '$(srcdir)/codegen.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-codegen.Tpo $(DEPDIR)/pcem-codegen.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='codegen.c' object='pcem-codegen.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-codegen.obj `if test -f 'codegen.c'; then $(CYGPATH_W) 'codegen.c'; else $(CYGPATH_W) '$(srcdir)/codegen.c'; fi` - -pcem-codegen_ops.o: codegen_ops.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-codegen_ops.o -MD -MP -MF $(DEPDIR)/pcem-codegen_ops.Tpo -c -o pcem-codegen_ops.o `test -f 'codegen_ops.c' || echo '$(srcdir)/'`codegen_ops.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-codegen_ops.Tpo $(DEPDIR)/pcem-codegen_ops.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='codegen_ops.c' object='pcem-codegen_ops.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-codegen_ops.o `test -f 'codegen_ops.c' || echo '$(srcdir)/'`codegen_ops.c - -pcem-codegen_ops.obj: codegen_ops.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-codegen_ops.obj -MD -MP -MF $(DEPDIR)/pcem-codegen_ops.Tpo -c -o pcem-codegen_ops.obj `if test -f 'codegen_ops.c'; then $(CYGPATH_W) 'codegen_ops.c'; else $(CYGPATH_W) '$(srcdir)/codegen_ops.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-codegen_ops.Tpo $(DEPDIR)/pcem-codegen_ops.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='codegen_ops.c' object='pcem-codegen_ops.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-codegen_ops.obj `if test -f 'codegen_ops.c'; then $(CYGPATH_W) 'codegen_ops.c'; else $(CYGPATH_W) '$(srcdir)/codegen_ops.c'; fi` - -pcem-codegen_timing_486.o: codegen_timing_486.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-codegen_timing_486.o -MD -MP -MF $(DEPDIR)/pcem-codegen_timing_486.Tpo -c -o pcem-codegen_timing_486.o `test -f 'codegen_timing_486.c' || echo '$(srcdir)/'`codegen_timing_486.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-codegen_timing_486.Tpo $(DEPDIR)/pcem-codegen_timing_486.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='codegen_timing_486.c' object='pcem-codegen_timing_486.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-codegen_timing_486.o `test -f 'codegen_timing_486.c' || echo '$(srcdir)/'`codegen_timing_486.c - -pcem-codegen_timing_486.obj: codegen_timing_486.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-codegen_timing_486.obj -MD -MP -MF $(DEPDIR)/pcem-codegen_timing_486.Tpo -c -o pcem-codegen_timing_486.obj `if test -f 'codegen_timing_486.c'; then $(CYGPATH_W) 'codegen_timing_486.c'; else $(CYGPATH_W) '$(srcdir)/codegen_timing_486.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-codegen_timing_486.Tpo $(DEPDIR)/pcem-codegen_timing_486.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='codegen_timing_486.c' object='pcem-codegen_timing_486.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-codegen_timing_486.obj `if test -f 'codegen_timing_486.c'; then $(CYGPATH_W) 'codegen_timing_486.c'; else $(CYGPATH_W) '$(srcdir)/codegen_timing_486.c'; fi` - -pcem-codegen_timing_pentium.o: codegen_timing_pentium.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-codegen_timing_pentium.o -MD -MP -MF $(DEPDIR)/pcem-codegen_timing_pentium.Tpo -c -o pcem-codegen_timing_pentium.o `test -f 'codegen_timing_pentium.c' || echo '$(srcdir)/'`codegen_timing_pentium.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-codegen_timing_pentium.Tpo $(DEPDIR)/pcem-codegen_timing_pentium.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='codegen_timing_pentium.c' object='pcem-codegen_timing_pentium.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-codegen_timing_pentium.o `test -f 'codegen_timing_pentium.c' || echo '$(srcdir)/'`codegen_timing_pentium.c - -pcem-codegen_timing_pentium.obj: codegen_timing_pentium.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-codegen_timing_pentium.obj -MD -MP -MF $(DEPDIR)/pcem-codegen_timing_pentium.Tpo -c -o pcem-codegen_timing_pentium.obj `if test -f 'codegen_timing_pentium.c'; then $(CYGPATH_W) 'codegen_timing_pentium.c'; else $(CYGPATH_W) '$(srcdir)/codegen_timing_pentium.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-codegen_timing_pentium.Tpo $(DEPDIR)/pcem-codegen_timing_pentium.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='codegen_timing_pentium.c' object='pcem-codegen_timing_pentium.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-codegen_timing_pentium.obj `if test -f 'codegen_timing_pentium.c'; then $(CYGPATH_W) 'codegen_timing_pentium.c'; else $(CYGPATH_W) '$(srcdir)/codegen_timing_pentium.c'; fi` - -pcem-compaq.o: compaq.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-compaq.o -MD -MP -MF $(DEPDIR)/pcem-compaq.Tpo -c -o pcem-compaq.o `test -f 'compaq.c' || echo '$(srcdir)/'`compaq.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-compaq.Tpo $(DEPDIR)/pcem-compaq.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='compaq.c' object='pcem-compaq.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-compaq.o `test -f 'compaq.c' || echo '$(srcdir)/'`compaq.c - -pcem-compaq.obj: compaq.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-compaq.obj -MD -MP -MF $(DEPDIR)/pcem-compaq.Tpo -c -o pcem-compaq.obj `if test -f 'compaq.c'; then $(CYGPATH_W) 'compaq.c'; else $(CYGPATH_W) '$(srcdir)/compaq.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-compaq.Tpo $(DEPDIR)/pcem-compaq.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='compaq.c' object='pcem-compaq.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-compaq.obj `if test -f 'compaq.c'; then $(CYGPATH_W) 'compaq.c'; else $(CYGPATH_W) '$(srcdir)/compaq.c'; fi` - -pcem-config.o: config.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-config.o -MD -MP -MF $(DEPDIR)/pcem-config.Tpo -c -o pcem-config.o `test -f 'config.c' || echo '$(srcdir)/'`config.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-config.Tpo $(DEPDIR)/pcem-config.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='config.c' object='pcem-config.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-config.o `test -f 'config.c' || echo '$(srcdir)/'`config.c - -pcem-config.obj: config.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-config.obj -MD -MP -MF $(DEPDIR)/pcem-config.Tpo -c -o pcem-config.obj `if test -f 'config.c'; then $(CYGPATH_W) 'config.c'; else $(CYGPATH_W) '$(srcdir)/config.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-config.Tpo $(DEPDIR)/pcem-config.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='config.c' object='pcem-config.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-config.obj `if test -f 'config.c'; then $(CYGPATH_W) 'config.c'; else $(CYGPATH_W) '$(srcdir)/config.c'; fi` - -pcem-cpu.o: cpu.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-cpu.o -MD -MP -MF $(DEPDIR)/pcem-cpu.Tpo -c -o pcem-cpu.o `test -f 'cpu.c' || echo '$(srcdir)/'`cpu.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-cpu.Tpo $(DEPDIR)/pcem-cpu.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='cpu.c' object='pcem-cpu.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-cpu.o `test -f 'cpu.c' || echo '$(srcdir)/'`cpu.c - -pcem-cpu.obj: cpu.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-cpu.obj -MD -MP -MF $(DEPDIR)/pcem-cpu.Tpo -c -o pcem-cpu.obj `if test -f 'cpu.c'; then $(CYGPATH_W) 'cpu.c'; else $(CYGPATH_W) '$(srcdir)/cpu.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-cpu.Tpo $(DEPDIR)/pcem-cpu.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='cpu.c' object='pcem-cpu.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-cpu.obj `if test -f 'cpu.c'; then $(CYGPATH_W) 'cpu.c'; else $(CYGPATH_W) '$(srcdir)/cpu.c'; fi` - -pcem-dac.o: dac.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-dac.o -MD -MP -MF $(DEPDIR)/pcem-dac.Tpo -c -o pcem-dac.o `test -f 'dac.c' || echo '$(srcdir)/'`dac.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-dac.Tpo $(DEPDIR)/pcem-dac.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='dac.c' object='pcem-dac.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-dac.o `test -f 'dac.c' || echo '$(srcdir)/'`dac.c - -pcem-dac.obj: dac.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-dac.obj -MD -MP -MF $(DEPDIR)/pcem-dac.Tpo -c -o pcem-dac.obj `if test -f 'dac.c'; then $(CYGPATH_W) 'dac.c'; else $(CYGPATH_W) '$(srcdir)/dac.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-dac.Tpo $(DEPDIR)/pcem-dac.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='dac.c' object='pcem-dac.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-dac.obj `if test -f 'dac.c'; then $(CYGPATH_W) 'dac.c'; else $(CYGPATH_W) '$(srcdir)/dac.c'; fi` - -pcem-device.o: device.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-device.o -MD -MP -MF $(DEPDIR)/pcem-device.Tpo -c -o pcem-device.o `test -f 'device.c' || echo '$(srcdir)/'`device.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-device.Tpo $(DEPDIR)/pcem-device.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='device.c' object='pcem-device.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-device.o `test -f 'device.c' || echo '$(srcdir)/'`device.c - -pcem-device.obj: device.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-device.obj -MD -MP -MF $(DEPDIR)/pcem-device.Tpo -c -o pcem-device.obj `if test -f 'device.c'; then $(CYGPATH_W) 'device.c'; else $(CYGPATH_W) '$(srcdir)/device.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-device.Tpo $(DEPDIR)/pcem-device.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='device.c' object='pcem-device.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-device.obj `if test -f 'device.c'; then $(CYGPATH_W) 'device.c'; else $(CYGPATH_W) '$(srcdir)/device.c'; fi` - -pcem-disc.o: disc.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-disc.o -MD -MP -MF $(DEPDIR)/pcem-disc.Tpo -c -o pcem-disc.o `test -f 'disc.c' || echo '$(srcdir)/'`disc.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-disc.Tpo $(DEPDIR)/pcem-disc.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='disc.c' object='pcem-disc.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-disc.o `test -f 'disc.c' || echo '$(srcdir)/'`disc.c - -pcem-disc.obj: disc.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-disc.obj -MD -MP -MF $(DEPDIR)/pcem-disc.Tpo -c -o pcem-disc.obj `if test -f 'disc.c'; then $(CYGPATH_W) 'disc.c'; else $(CYGPATH_W) '$(srcdir)/disc.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-disc.Tpo $(DEPDIR)/pcem-disc.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='disc.c' object='pcem-disc.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-disc.obj `if test -f 'disc.c'; then $(CYGPATH_W) 'disc.c'; else $(CYGPATH_W) '$(srcdir)/disc.c'; fi` - -pcem-disc_fdi.o: disc_fdi.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-disc_fdi.o -MD -MP -MF $(DEPDIR)/pcem-disc_fdi.Tpo -c -o pcem-disc_fdi.o `test -f 'disc_fdi.c' || echo '$(srcdir)/'`disc_fdi.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-disc_fdi.Tpo $(DEPDIR)/pcem-disc_fdi.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='disc_fdi.c' object='pcem-disc_fdi.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-disc_fdi.o `test -f 'disc_fdi.c' || echo '$(srcdir)/'`disc_fdi.c - -pcem-disc_fdi.obj: disc_fdi.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-disc_fdi.obj -MD -MP -MF $(DEPDIR)/pcem-disc_fdi.Tpo -c -o pcem-disc_fdi.obj `if test -f 'disc_fdi.c'; then $(CYGPATH_W) 'disc_fdi.c'; else $(CYGPATH_W) '$(srcdir)/disc_fdi.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-disc_fdi.Tpo $(DEPDIR)/pcem-disc_fdi.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='disc_fdi.c' object='pcem-disc_fdi.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-disc_fdi.obj `if test -f 'disc_fdi.c'; then $(CYGPATH_W) 'disc_fdi.c'; else $(CYGPATH_W) '$(srcdir)/disc_fdi.c'; fi` - -pcem-disc_img.o: disc_img.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-disc_img.o -MD -MP -MF $(DEPDIR)/pcem-disc_img.Tpo -c -o pcem-disc_img.o `test -f 'disc_img.c' || echo '$(srcdir)/'`disc_img.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-disc_img.Tpo $(DEPDIR)/pcem-disc_img.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='disc_img.c' object='pcem-disc_img.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-disc_img.o `test -f 'disc_img.c' || echo '$(srcdir)/'`disc_img.c - -pcem-disc_img.obj: disc_img.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-disc_img.obj -MD -MP -MF $(DEPDIR)/pcem-disc_img.Tpo -c -o pcem-disc_img.obj `if test -f 'disc_img.c'; then $(CYGPATH_W) 'disc_img.c'; else $(CYGPATH_W) '$(srcdir)/disc_img.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-disc_img.Tpo $(DEPDIR)/pcem-disc_img.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='disc_img.c' object='pcem-disc_img.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-disc_img.obj `if test -f 'disc_img.c'; then $(CYGPATH_W) 'disc_img.c'; else $(CYGPATH_W) '$(srcdir)/disc_img.c'; fi` - -pcem-dma.o: dma.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-dma.o -MD -MP -MF $(DEPDIR)/pcem-dma.Tpo -c -o pcem-dma.o `test -f 'dma.c' || echo '$(srcdir)/'`dma.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-dma.Tpo $(DEPDIR)/pcem-dma.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='dma.c' object='pcem-dma.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-dma.o `test -f 'dma.c' || echo '$(srcdir)/'`dma.c - -pcem-dma.obj: dma.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-dma.obj -MD -MP -MF $(DEPDIR)/pcem-dma.Tpo -c -o pcem-dma.obj `if test -f 'dma.c'; then $(CYGPATH_W) 'dma.c'; else $(CYGPATH_W) '$(srcdir)/dma.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-dma.Tpo $(DEPDIR)/pcem-dma.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='dma.c' object='pcem-dma.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-dma.obj `if test -f 'dma.c'; then $(CYGPATH_W) 'dma.c'; else $(CYGPATH_W) '$(srcdir)/dma.c'; fi` - -pcem-fdc.o: fdc.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-fdc.o -MD -MP -MF $(DEPDIR)/pcem-fdc.Tpo -c -o pcem-fdc.o `test -f 'fdc.c' || echo '$(srcdir)/'`fdc.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-fdc.Tpo $(DEPDIR)/pcem-fdc.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='fdc.c' object='pcem-fdc.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-fdc.o `test -f 'fdc.c' || echo '$(srcdir)/'`fdc.c - -pcem-fdc.obj: fdc.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-fdc.obj -MD -MP -MF $(DEPDIR)/pcem-fdc.Tpo -c -o pcem-fdc.obj `if test -f 'fdc.c'; then $(CYGPATH_W) 'fdc.c'; else $(CYGPATH_W) '$(srcdir)/fdc.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-fdc.Tpo $(DEPDIR)/pcem-fdc.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='fdc.c' object='pcem-fdc.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-fdc.obj `if test -f 'fdc.c'; then $(CYGPATH_W) 'fdc.c'; else $(CYGPATH_W) '$(srcdir)/fdc.c'; fi` - -pcem-fdc37c665.o: fdc37c665.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-fdc37c665.o -MD -MP -MF $(DEPDIR)/pcem-fdc37c665.Tpo -c -o pcem-fdc37c665.o `test -f 'fdc37c665.c' || echo '$(srcdir)/'`fdc37c665.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-fdc37c665.Tpo $(DEPDIR)/pcem-fdc37c665.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='fdc37c665.c' object='pcem-fdc37c665.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-fdc37c665.o `test -f 'fdc37c665.c' || echo '$(srcdir)/'`fdc37c665.c - -pcem-fdc37c665.obj: fdc37c665.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-fdc37c665.obj -MD -MP -MF $(DEPDIR)/pcem-fdc37c665.Tpo -c -o pcem-fdc37c665.obj `if test -f 'fdc37c665.c'; then $(CYGPATH_W) 'fdc37c665.c'; else $(CYGPATH_W) '$(srcdir)/fdc37c665.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-fdc37c665.Tpo $(DEPDIR)/pcem-fdc37c665.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='fdc37c665.c' object='pcem-fdc37c665.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-fdc37c665.obj `if test -f 'fdc37c665.c'; then $(CYGPATH_W) 'fdc37c665.c'; else $(CYGPATH_W) '$(srcdir)/fdc37c665.c'; fi` - -pcem-fdi2raw.o: fdi2raw.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-fdi2raw.o -MD -MP -MF $(DEPDIR)/pcem-fdi2raw.Tpo -c -o pcem-fdi2raw.o `test -f 'fdi2raw.c' || echo '$(srcdir)/'`fdi2raw.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-fdi2raw.Tpo $(DEPDIR)/pcem-fdi2raw.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='fdi2raw.c' object='pcem-fdi2raw.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-fdi2raw.o `test -f 'fdi2raw.c' || echo '$(srcdir)/'`fdi2raw.c - -pcem-fdi2raw.obj: fdi2raw.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-fdi2raw.obj -MD -MP -MF $(DEPDIR)/pcem-fdi2raw.Tpo -c -o pcem-fdi2raw.obj `if test -f 'fdi2raw.c'; then $(CYGPATH_W) 'fdi2raw.c'; else $(CYGPATH_W) '$(srcdir)/fdi2raw.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-fdi2raw.Tpo $(DEPDIR)/pcem-fdi2raw.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='fdi2raw.c' object='pcem-fdi2raw.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-fdi2raw.obj `if test -f 'fdi2raw.c'; then $(CYGPATH_W) 'fdi2raw.c'; else $(CYGPATH_W) '$(srcdir)/fdi2raw.c'; fi` - -pcem-gameport.o: gameport.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-gameport.o -MD -MP -MF $(DEPDIR)/pcem-gameport.Tpo -c -o pcem-gameport.o `test -f 'gameport.c' || echo '$(srcdir)/'`gameport.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-gameport.Tpo $(DEPDIR)/pcem-gameport.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='gameport.c' object='pcem-gameport.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-gameport.o `test -f 'gameport.c' || echo '$(srcdir)/'`gameport.c - -pcem-gameport.obj: gameport.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-gameport.obj -MD -MP -MF $(DEPDIR)/pcem-gameport.Tpo -c -o pcem-gameport.obj `if test -f 'gameport.c'; then $(CYGPATH_W) 'gameport.c'; else $(CYGPATH_W) '$(srcdir)/gameport.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-gameport.Tpo $(DEPDIR)/pcem-gameport.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='gameport.c' object='pcem-gameport.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-gameport.obj `if test -f 'gameport.c'; then $(CYGPATH_W) 'gameport.c'; else $(CYGPATH_W) '$(srcdir)/gameport.c'; fi` - -pcem-headland.o: headland.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-headland.o -MD -MP -MF $(DEPDIR)/pcem-headland.Tpo -c -o pcem-headland.o `test -f 'headland.c' || echo '$(srcdir)/'`headland.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-headland.Tpo $(DEPDIR)/pcem-headland.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='headland.c' object='pcem-headland.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-headland.o `test -f 'headland.c' || echo '$(srcdir)/'`headland.c - -pcem-headland.obj: headland.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-headland.obj -MD -MP -MF $(DEPDIR)/pcem-headland.Tpo -c -o pcem-headland.obj `if test -f 'headland.c'; then $(CYGPATH_W) 'headland.c'; else $(CYGPATH_W) '$(srcdir)/headland.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-headland.Tpo $(DEPDIR)/pcem-headland.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='headland.c' object='pcem-headland.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-headland.obj `if test -f 'headland.c'; then $(CYGPATH_W) 'headland.c'; else $(CYGPATH_W) '$(srcdir)/headland.c'; fi` - -pcem-i430lx.o: i430lx.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-i430lx.o -MD -MP -MF $(DEPDIR)/pcem-i430lx.Tpo -c -o pcem-i430lx.o `test -f 'i430lx.c' || echo '$(srcdir)/'`i430lx.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-i430lx.Tpo $(DEPDIR)/pcem-i430lx.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='i430lx.c' object='pcem-i430lx.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-i430lx.o `test -f 'i430lx.c' || echo '$(srcdir)/'`i430lx.c - -pcem-i430lx.obj: i430lx.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-i430lx.obj -MD -MP -MF $(DEPDIR)/pcem-i430lx.Tpo -c -o pcem-i430lx.obj `if test -f 'i430lx.c'; then $(CYGPATH_W) 'i430lx.c'; else $(CYGPATH_W) '$(srcdir)/i430lx.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-i430lx.Tpo $(DEPDIR)/pcem-i430lx.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='i430lx.c' object='pcem-i430lx.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-i430lx.obj `if test -f 'i430lx.c'; then $(CYGPATH_W) 'i430lx.c'; else $(CYGPATH_W) '$(srcdir)/i430lx.c'; fi` - -pcem-i430fx.o: i430fx.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-i430fx.o -MD -MP -MF $(DEPDIR)/pcem-i430fx.Tpo -c -o pcem-i430fx.o `test -f 'i430fx.c' || echo '$(srcdir)/'`i430fx.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-i430fx.Tpo $(DEPDIR)/pcem-i430fx.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='i430fx.c' object='pcem-i430fx.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-i430fx.o `test -f 'i430fx.c' || echo '$(srcdir)/'`i430fx.c - -pcem-i430fx.obj: i430fx.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-i430fx.obj -MD -MP -MF $(DEPDIR)/pcem-i430fx.Tpo -c -o pcem-i430fx.obj `if test -f 'i430fx.c'; then $(CYGPATH_W) 'i430fx.c'; else $(CYGPATH_W) '$(srcdir)/i430fx.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-i430fx.Tpo $(DEPDIR)/pcem-i430fx.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='i430fx.c' object='pcem-i430fx.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-i430fx.obj `if test -f 'i430fx.c'; then $(CYGPATH_W) 'i430fx.c'; else $(CYGPATH_W) '$(srcdir)/i430fx.c'; fi` - -pcem-i430vx.o: i430vx.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-i430vx.o -MD -MP -MF $(DEPDIR)/pcem-i430vx.Tpo -c -o pcem-i430vx.o `test -f 'i430vx.c' || echo '$(srcdir)/'`i430vx.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-i430vx.Tpo $(DEPDIR)/pcem-i430vx.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='i430vx.c' object='pcem-i430vx.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-i430vx.o `test -f 'i430vx.c' || echo '$(srcdir)/'`i430vx.c - -pcem-i430vx.obj: i430vx.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-i430vx.obj -MD -MP -MF $(DEPDIR)/pcem-i430vx.Tpo -c -o pcem-i430vx.obj `if test -f 'i430vx.c'; then $(CYGPATH_W) 'i430vx.c'; else $(CYGPATH_W) '$(srcdir)/i430vx.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-i430vx.Tpo $(DEPDIR)/pcem-i430vx.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='i430vx.c' object='pcem-i430vx.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-i430vx.obj `if test -f 'i430vx.c'; then $(CYGPATH_W) 'i430vx.c'; else $(CYGPATH_W) '$(srcdir)/i430vx.c'; fi` - -pcem-ide.o: ide.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-ide.o -MD -MP -MF $(DEPDIR)/pcem-ide.Tpo -c -o pcem-ide.o `test -f 'ide.c' || echo '$(srcdir)/'`ide.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-ide.Tpo $(DEPDIR)/pcem-ide.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='ide.c' object='pcem-ide.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-ide.o `test -f 'ide.c' || echo '$(srcdir)/'`ide.c - -pcem-ide.obj: ide.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-ide.obj -MD -MP -MF $(DEPDIR)/pcem-ide.Tpo -c -o pcem-ide.obj `if test -f 'ide.c'; then $(CYGPATH_W) 'ide.c'; else $(CYGPATH_W) '$(srcdir)/ide.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-ide.Tpo $(DEPDIR)/pcem-ide.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='ide.c' object='pcem-ide.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-ide.obj `if test -f 'ide.c'; then $(CYGPATH_W) 'ide.c'; else $(CYGPATH_W) '$(srcdir)/ide.c'; fi` - -pcem-intel.o: intel.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-intel.o -MD -MP -MF $(DEPDIR)/pcem-intel.Tpo -c -o pcem-intel.o `test -f 'intel.c' || echo '$(srcdir)/'`intel.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-intel.Tpo $(DEPDIR)/pcem-intel.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='intel.c' object='pcem-intel.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-intel.o `test -f 'intel.c' || echo '$(srcdir)/'`intel.c - -pcem-intel.obj: intel.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-intel.obj -MD -MP -MF $(DEPDIR)/pcem-intel.Tpo -c -o pcem-intel.obj `if test -f 'intel.c'; then $(CYGPATH_W) 'intel.c'; else $(CYGPATH_W) '$(srcdir)/intel.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-intel.Tpo $(DEPDIR)/pcem-intel.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='intel.c' object='pcem-intel.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-intel.obj `if test -f 'intel.c'; then $(CYGPATH_W) 'intel.c'; else $(CYGPATH_W) '$(srcdir)/intel.c'; fi` - -pcem-intel_flash.o: intel_flash.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-intel_flash.o -MD -MP -MF $(DEPDIR)/pcem-intel_flash.Tpo -c -o pcem-intel_flash.o `test -f 'intel_flash.c' || echo '$(srcdir)/'`intel_flash.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-intel_flash.Tpo $(DEPDIR)/pcem-intel_flash.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='intel_flash.c' object='pcem-intel_flash.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-intel_flash.o `test -f 'intel_flash.c' || echo '$(srcdir)/'`intel_flash.c - -pcem-intel_flash.obj: intel_flash.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-intel_flash.obj -MD -MP -MF $(DEPDIR)/pcem-intel_flash.Tpo -c -o pcem-intel_flash.obj `if test -f 'intel_flash.c'; then $(CYGPATH_W) 'intel_flash.c'; else $(CYGPATH_W) '$(srcdir)/intel_flash.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-intel_flash.Tpo $(DEPDIR)/pcem-intel_flash.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='intel_flash.c' object='pcem-intel_flash.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-intel_flash.obj `if test -f 'intel_flash.c'; then $(CYGPATH_W) 'intel_flash.c'; else $(CYGPATH_W) '$(srcdir)/intel_flash.c'; fi` - -pcem-io.o: io.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-io.o -MD -MP -MF $(DEPDIR)/pcem-io.Tpo -c -o pcem-io.o `test -f 'io.c' || echo '$(srcdir)/'`io.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-io.Tpo $(DEPDIR)/pcem-io.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='io.c' object='pcem-io.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-io.o `test -f 'io.c' || echo '$(srcdir)/'`io.c - -pcem-io.obj: io.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-io.obj -MD -MP -MF $(DEPDIR)/pcem-io.Tpo -c -o pcem-io.obj `if test -f 'io.c'; then $(CYGPATH_W) 'io.c'; else $(CYGPATH_W) '$(srcdir)/io.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-io.Tpo $(DEPDIR)/pcem-io.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='io.c' object='pcem-io.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-io.obj `if test -f 'io.c'; then $(CYGPATH_W) 'io.c'; else $(CYGPATH_W) '$(srcdir)/io.c'; fi` - -pcem-jim.o: jim.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-jim.o -MD -MP -MF $(DEPDIR)/pcem-jim.Tpo -c -o pcem-jim.o `test -f 'jim.c' || echo '$(srcdir)/'`jim.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-jim.Tpo $(DEPDIR)/pcem-jim.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='jim.c' object='pcem-jim.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-jim.o `test -f 'jim.c' || echo '$(srcdir)/'`jim.c - -pcem-jim.obj: jim.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-jim.obj -MD -MP -MF $(DEPDIR)/pcem-jim.Tpo -c -o pcem-jim.obj `if test -f 'jim.c'; then $(CYGPATH_W) 'jim.c'; else $(CYGPATH_W) '$(srcdir)/jim.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-jim.Tpo $(DEPDIR)/pcem-jim.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='jim.c' object='pcem-jim.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-jim.obj `if test -f 'jim.c'; then $(CYGPATH_W) 'jim.c'; else $(CYGPATH_W) '$(srcdir)/jim.c'; fi` - -pcem-keyboard.o: keyboard.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-keyboard.o -MD -MP -MF $(DEPDIR)/pcem-keyboard.Tpo -c -o pcem-keyboard.o `test -f 'keyboard.c' || echo '$(srcdir)/'`keyboard.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-keyboard.Tpo $(DEPDIR)/pcem-keyboard.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='keyboard.c' object='pcem-keyboard.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-keyboard.o `test -f 'keyboard.c' || echo '$(srcdir)/'`keyboard.c - -pcem-keyboard.obj: keyboard.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-keyboard.obj -MD -MP -MF $(DEPDIR)/pcem-keyboard.Tpo -c -o pcem-keyboard.obj `if test -f 'keyboard.c'; then $(CYGPATH_W) 'keyboard.c'; else $(CYGPATH_W) '$(srcdir)/keyboard.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-keyboard.Tpo $(DEPDIR)/pcem-keyboard.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='keyboard.c' object='pcem-keyboard.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-keyboard.obj `if test -f 'keyboard.c'; then $(CYGPATH_W) 'keyboard.c'; else $(CYGPATH_W) '$(srcdir)/keyboard.c'; fi` - -pcem-keyboard_amstrad.o: keyboard_amstrad.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-keyboard_amstrad.o -MD -MP -MF $(DEPDIR)/pcem-keyboard_amstrad.Tpo -c -o pcem-keyboard_amstrad.o `test -f 'keyboard_amstrad.c' || echo '$(srcdir)/'`keyboard_amstrad.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-keyboard_amstrad.Tpo $(DEPDIR)/pcem-keyboard_amstrad.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='keyboard_amstrad.c' object='pcem-keyboard_amstrad.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-keyboard_amstrad.o `test -f 'keyboard_amstrad.c' || echo '$(srcdir)/'`keyboard_amstrad.c - -pcem-keyboard_amstrad.obj: keyboard_amstrad.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-keyboard_amstrad.obj -MD -MP -MF $(DEPDIR)/pcem-keyboard_amstrad.Tpo -c -o pcem-keyboard_amstrad.obj `if test -f 'keyboard_amstrad.c'; then $(CYGPATH_W) 'keyboard_amstrad.c'; else $(CYGPATH_W) '$(srcdir)/keyboard_amstrad.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-keyboard_amstrad.Tpo $(DEPDIR)/pcem-keyboard_amstrad.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='keyboard_amstrad.c' object='pcem-keyboard_amstrad.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-keyboard_amstrad.obj `if test -f 'keyboard_amstrad.c'; then $(CYGPATH_W) 'keyboard_amstrad.c'; else $(CYGPATH_W) '$(srcdir)/keyboard_amstrad.c'; fi` - -pcem-keyboard_at.o: keyboard_at.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-keyboard_at.o -MD -MP -MF $(DEPDIR)/pcem-keyboard_at.Tpo -c -o pcem-keyboard_at.o `test -f 'keyboard_at.c' || echo '$(srcdir)/'`keyboard_at.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-keyboard_at.Tpo $(DEPDIR)/pcem-keyboard_at.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='keyboard_at.c' object='pcem-keyboard_at.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-keyboard_at.o `test -f 'keyboard_at.c' || echo '$(srcdir)/'`keyboard_at.c - -pcem-keyboard_at.obj: keyboard_at.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-keyboard_at.obj -MD -MP -MF $(DEPDIR)/pcem-keyboard_at.Tpo -c -o pcem-keyboard_at.obj `if test -f 'keyboard_at.c'; then $(CYGPATH_W) 'keyboard_at.c'; else $(CYGPATH_W) '$(srcdir)/keyboard_at.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-keyboard_at.Tpo $(DEPDIR)/pcem-keyboard_at.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='keyboard_at.c' object='pcem-keyboard_at.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-keyboard_at.obj `if test -f 'keyboard_at.c'; then $(CYGPATH_W) 'keyboard_at.c'; else $(CYGPATH_W) '$(srcdir)/keyboard_at.c'; fi` - -pcem-keyboard_olim24.o: keyboard_olim24.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-keyboard_olim24.o -MD -MP -MF $(DEPDIR)/pcem-keyboard_olim24.Tpo -c -o pcem-keyboard_olim24.o `test -f 'keyboard_olim24.c' || echo '$(srcdir)/'`keyboard_olim24.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-keyboard_olim24.Tpo $(DEPDIR)/pcem-keyboard_olim24.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='keyboard_olim24.c' object='pcem-keyboard_olim24.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-keyboard_olim24.o `test -f 'keyboard_olim24.c' || echo '$(srcdir)/'`keyboard_olim24.c - -pcem-keyboard_olim24.obj: keyboard_olim24.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-keyboard_olim24.obj -MD -MP -MF $(DEPDIR)/pcem-keyboard_olim24.Tpo -c -o pcem-keyboard_olim24.obj `if test -f 'keyboard_olim24.c'; then $(CYGPATH_W) 'keyboard_olim24.c'; else $(CYGPATH_W) '$(srcdir)/keyboard_olim24.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-keyboard_olim24.Tpo $(DEPDIR)/pcem-keyboard_olim24.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='keyboard_olim24.c' object='pcem-keyboard_olim24.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-keyboard_olim24.obj `if test -f 'keyboard_olim24.c'; then $(CYGPATH_W) 'keyboard_olim24.c'; else $(CYGPATH_W) '$(srcdir)/keyboard_olim24.c'; fi` - -pcem-keyboard_pcjr.o: keyboard_pcjr.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-keyboard_pcjr.o -MD -MP -MF $(DEPDIR)/pcem-keyboard_pcjr.Tpo -c -o pcem-keyboard_pcjr.o `test -f 'keyboard_pcjr.c' || echo '$(srcdir)/'`keyboard_pcjr.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-keyboard_pcjr.Tpo $(DEPDIR)/pcem-keyboard_pcjr.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='keyboard_pcjr.c' object='pcem-keyboard_pcjr.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-keyboard_pcjr.o `test -f 'keyboard_pcjr.c' || echo '$(srcdir)/'`keyboard_pcjr.c - -pcem-keyboard_pcjr.obj: keyboard_pcjr.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-keyboard_pcjr.obj -MD -MP -MF $(DEPDIR)/pcem-keyboard_pcjr.Tpo -c -o pcem-keyboard_pcjr.obj `if test -f 'keyboard_pcjr.c'; then $(CYGPATH_W) 'keyboard_pcjr.c'; else $(CYGPATH_W) '$(srcdir)/keyboard_pcjr.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-keyboard_pcjr.Tpo $(DEPDIR)/pcem-keyboard_pcjr.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='keyboard_pcjr.c' object='pcem-keyboard_pcjr.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-keyboard_pcjr.obj `if test -f 'keyboard_pcjr.c'; then $(CYGPATH_W) 'keyboard_pcjr.c'; else $(CYGPATH_W) '$(srcdir)/keyboard_pcjr.c'; fi` - -pcem-keyboard_xt.o: keyboard_xt.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-keyboard_xt.o -MD -MP -MF $(DEPDIR)/pcem-keyboard_xt.Tpo -c -o pcem-keyboard_xt.o `test -f 'keyboard_xt.c' || echo '$(srcdir)/'`keyboard_xt.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-keyboard_xt.Tpo $(DEPDIR)/pcem-keyboard_xt.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='keyboard_xt.c' object='pcem-keyboard_xt.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-keyboard_xt.o `test -f 'keyboard_xt.c' || echo '$(srcdir)/'`keyboard_xt.c - -pcem-keyboard_xt.obj: keyboard_xt.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-keyboard_xt.obj -MD -MP -MF $(DEPDIR)/pcem-keyboard_xt.Tpo -c -o pcem-keyboard_xt.obj `if test -f 'keyboard_xt.c'; then $(CYGPATH_W) 'keyboard_xt.c'; else $(CYGPATH_W) '$(srcdir)/keyboard_xt.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-keyboard_xt.Tpo $(DEPDIR)/pcem-keyboard_xt.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='keyboard_xt.c' object='pcem-keyboard_xt.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-keyboard_xt.obj `if test -f 'keyboard_xt.c'; then $(CYGPATH_W) 'keyboard_xt.c'; else $(CYGPATH_W) '$(srcdir)/keyboard_xt.c'; fi` - -pcem-linux-time.o: linux-time.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-linux-time.o -MD -MP -MF $(DEPDIR)/pcem-linux-time.Tpo -c -o pcem-linux-time.o `test -f 'linux-time.c' || echo '$(srcdir)/'`linux-time.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-linux-time.Tpo $(DEPDIR)/pcem-linux-time.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='linux-time.c' object='pcem-linux-time.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-linux-time.o `test -f 'linux-time.c' || echo '$(srcdir)/'`linux-time.c - -pcem-linux-time.obj: linux-time.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-linux-time.obj -MD -MP -MF $(DEPDIR)/pcem-linux-time.Tpo -c -o pcem-linux-time.obj `if test -f 'linux-time.c'; then $(CYGPATH_W) 'linux-time.c'; else $(CYGPATH_W) '$(srcdir)/linux-time.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-linux-time.Tpo $(DEPDIR)/pcem-linux-time.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='linux-time.c' object='pcem-linux-time.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-linux-time.obj `if test -f 'linux-time.c'; then $(CYGPATH_W) 'linux-time.c'; else $(CYGPATH_W) '$(srcdir)/linux-time.c'; fi` - -pcem-lpt.o: lpt.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-lpt.o -MD -MP -MF $(DEPDIR)/pcem-lpt.Tpo -c -o pcem-lpt.o `test -f 'lpt.c' || echo '$(srcdir)/'`lpt.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-lpt.Tpo $(DEPDIR)/pcem-lpt.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='lpt.c' object='pcem-lpt.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-lpt.o `test -f 'lpt.c' || echo '$(srcdir)/'`lpt.c - -pcem-lpt.obj: lpt.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-lpt.obj -MD -MP -MF $(DEPDIR)/pcem-lpt.Tpo -c -o pcem-lpt.obj `if test -f 'lpt.c'; then $(CYGPATH_W) 'lpt.c'; else $(CYGPATH_W) '$(srcdir)/lpt.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-lpt.Tpo $(DEPDIR)/pcem-lpt.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='lpt.c' object='pcem-lpt.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-lpt.obj `if test -f 'lpt.c'; then $(CYGPATH_W) 'lpt.c'; else $(CYGPATH_W) '$(srcdir)/lpt.c'; fi` - -pcem-mcr.o: mcr.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-mcr.o -MD -MP -MF $(DEPDIR)/pcem-mcr.Tpo -c -o pcem-mcr.o `test -f 'mcr.c' || echo '$(srcdir)/'`mcr.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-mcr.Tpo $(DEPDIR)/pcem-mcr.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='mcr.c' object='pcem-mcr.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-mcr.o `test -f 'mcr.c' || echo '$(srcdir)/'`mcr.c - -pcem-mcr.obj: mcr.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-mcr.obj -MD -MP -MF $(DEPDIR)/pcem-mcr.Tpo -c -o pcem-mcr.obj `if test -f 'mcr.c'; then $(CYGPATH_W) 'mcr.c'; else $(CYGPATH_W) '$(srcdir)/mcr.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-mcr.Tpo $(DEPDIR)/pcem-mcr.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='mcr.c' object='pcem-mcr.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-mcr.obj `if test -f 'mcr.c'; then $(CYGPATH_W) 'mcr.c'; else $(CYGPATH_W) '$(srcdir)/mcr.c'; fi` - -pcem-mem.o: mem.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-mem.o -MD -MP -MF $(DEPDIR)/pcem-mem.Tpo -c -o pcem-mem.o `test -f 'mem.c' || echo '$(srcdir)/'`mem.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-mem.Tpo $(DEPDIR)/pcem-mem.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='mem.c' object='pcem-mem.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-mem.o `test -f 'mem.c' || echo '$(srcdir)/'`mem.c - -pcem-mem.obj: mem.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-mem.obj -MD -MP -MF $(DEPDIR)/pcem-mem.Tpo -c -o pcem-mem.obj `if test -f 'mem.c'; then $(CYGPATH_W) 'mem.c'; else $(CYGPATH_W) '$(srcdir)/mem.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-mem.Tpo $(DEPDIR)/pcem-mem.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='mem.c' object='pcem-mem.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-mem.obj `if test -f 'mem.c'; then $(CYGPATH_W) 'mem.c'; else $(CYGPATH_W) '$(srcdir)/mem.c'; fi` - -pcem-model.o: model.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-model.o -MD -MP -MF $(DEPDIR)/pcem-model.Tpo -c -o pcem-model.o `test -f 'model.c' || echo '$(srcdir)/'`model.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-model.Tpo $(DEPDIR)/pcem-model.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='model.c' object='pcem-model.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-model.o `test -f 'model.c' || echo '$(srcdir)/'`model.c - -pcem-model.obj: model.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-model.obj -MD -MP -MF $(DEPDIR)/pcem-model.Tpo -c -o pcem-model.obj `if test -f 'model.c'; then $(CYGPATH_W) 'model.c'; else $(CYGPATH_W) '$(srcdir)/model.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-model.Tpo $(DEPDIR)/pcem-model.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='model.c' object='pcem-model.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-model.obj `if test -f 'model.c'; then $(CYGPATH_W) 'model.c'; else $(CYGPATH_W) '$(srcdir)/model.c'; fi` - -pcem-mouse.o: mouse.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-mouse.o -MD -MP -MF $(DEPDIR)/pcem-mouse.Tpo -c -o pcem-mouse.o `test -f 'mouse.c' || echo '$(srcdir)/'`mouse.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-mouse.Tpo $(DEPDIR)/pcem-mouse.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='mouse.c' object='pcem-mouse.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-mouse.o `test -f 'mouse.c' || echo '$(srcdir)/'`mouse.c - -pcem-mouse.obj: mouse.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-mouse.obj -MD -MP -MF $(DEPDIR)/pcem-mouse.Tpo -c -o pcem-mouse.obj `if test -f 'mouse.c'; then $(CYGPATH_W) 'mouse.c'; else $(CYGPATH_W) '$(srcdir)/mouse.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-mouse.Tpo $(DEPDIR)/pcem-mouse.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='mouse.c' object='pcem-mouse.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-mouse.obj `if test -f 'mouse.c'; then $(CYGPATH_W) 'mouse.c'; else $(CYGPATH_W) '$(srcdir)/mouse.c'; fi` - -pcem-mouse_ps2.o: mouse_ps2.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-mouse_ps2.o -MD -MP -MF $(DEPDIR)/pcem-mouse_ps2.Tpo -c -o pcem-mouse_ps2.o `test -f 'mouse_ps2.c' || echo '$(srcdir)/'`mouse_ps2.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-mouse_ps2.Tpo $(DEPDIR)/pcem-mouse_ps2.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='mouse_ps2.c' object='pcem-mouse_ps2.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-mouse_ps2.o `test -f 'mouse_ps2.c' || echo '$(srcdir)/'`mouse_ps2.c - -pcem-mouse_ps2.obj: mouse_ps2.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-mouse_ps2.obj -MD -MP -MF $(DEPDIR)/pcem-mouse_ps2.Tpo -c -o pcem-mouse_ps2.obj `if test -f 'mouse_ps2.c'; then $(CYGPATH_W) 'mouse_ps2.c'; else $(CYGPATH_W) '$(srcdir)/mouse_ps2.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-mouse_ps2.Tpo $(DEPDIR)/pcem-mouse_ps2.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='mouse_ps2.c' object='pcem-mouse_ps2.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-mouse_ps2.obj `if test -f 'mouse_ps2.c'; then $(CYGPATH_W) 'mouse_ps2.c'; else $(CYGPATH_W) '$(srcdir)/mouse_ps2.c'; fi` - -pcem-mouse_serial.o: mouse_serial.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-mouse_serial.o -MD -MP -MF $(DEPDIR)/pcem-mouse_serial.Tpo -c -o pcem-mouse_serial.o `test -f 'mouse_serial.c' || echo '$(srcdir)/'`mouse_serial.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-mouse_serial.Tpo $(DEPDIR)/pcem-mouse_serial.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='mouse_serial.c' object='pcem-mouse_serial.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-mouse_serial.o `test -f 'mouse_serial.c' || echo '$(srcdir)/'`mouse_serial.c - -pcem-mouse_serial.obj: mouse_serial.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-mouse_serial.obj -MD -MP -MF $(DEPDIR)/pcem-mouse_serial.Tpo -c -o pcem-mouse_serial.obj `if test -f 'mouse_serial.c'; then $(CYGPATH_W) 'mouse_serial.c'; else $(CYGPATH_W) '$(srcdir)/mouse_serial.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-mouse_serial.Tpo $(DEPDIR)/pcem-mouse_serial.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='mouse_serial.c' object='pcem-mouse_serial.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-mouse_serial.obj `if test -f 'mouse_serial.c'; then $(CYGPATH_W) 'mouse_serial.c'; else $(CYGPATH_W) '$(srcdir)/mouse_serial.c'; fi` - -pcem-neat.o: neat.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-neat.o -MD -MP -MF $(DEPDIR)/pcem-neat.Tpo -c -o pcem-neat.o `test -f 'neat.c' || echo '$(srcdir)/'`neat.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-neat.Tpo $(DEPDIR)/pcem-neat.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='neat.c' object='pcem-neat.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-neat.o `test -f 'neat.c' || echo '$(srcdir)/'`neat.c - -pcem-neat.obj: neat.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-neat.obj -MD -MP -MF $(DEPDIR)/pcem-neat.Tpo -c -o pcem-neat.obj `if test -f 'neat.c'; then $(CYGPATH_W) 'neat.c'; else $(CYGPATH_W) '$(srcdir)/neat.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-neat.Tpo $(DEPDIR)/pcem-neat.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='neat.c' object='pcem-neat.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-neat.obj `if test -f 'neat.c'; then $(CYGPATH_W) 'neat.c'; else $(CYGPATH_W) '$(srcdir)/neat.c'; fi` - -pcem-nmi.o: nmi.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-nmi.o -MD -MP -MF $(DEPDIR)/pcem-nmi.Tpo -c -o pcem-nmi.o `test -f 'nmi.c' || echo '$(srcdir)/'`nmi.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-nmi.Tpo $(DEPDIR)/pcem-nmi.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='nmi.c' object='pcem-nmi.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-nmi.o `test -f 'nmi.c' || echo '$(srcdir)/'`nmi.c - -pcem-nmi.obj: nmi.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-nmi.obj -MD -MP -MF $(DEPDIR)/pcem-nmi.Tpo -c -o pcem-nmi.obj `if test -f 'nmi.c'; then $(CYGPATH_W) 'nmi.c'; else $(CYGPATH_W) '$(srcdir)/nmi.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-nmi.Tpo $(DEPDIR)/pcem-nmi.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='nmi.c' object='pcem-nmi.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-nmi.obj `if test -f 'nmi.c'; then $(CYGPATH_W) 'nmi.c'; else $(CYGPATH_W) '$(srcdir)/nmi.c'; fi` - -pcem-nvr.o: nvr.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-nvr.o -MD -MP -MF $(DEPDIR)/pcem-nvr.Tpo -c -o pcem-nvr.o `test -f 'nvr.c' || echo '$(srcdir)/'`nvr.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-nvr.Tpo $(DEPDIR)/pcem-nvr.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='nvr.c' object='pcem-nvr.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-nvr.o `test -f 'nvr.c' || echo '$(srcdir)/'`nvr.c - -pcem-nvr.obj: nvr.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-nvr.obj -MD -MP -MF $(DEPDIR)/pcem-nvr.Tpo -c -o pcem-nvr.obj `if test -f 'nvr.c'; then $(CYGPATH_W) 'nvr.c'; else $(CYGPATH_W) '$(srcdir)/nvr.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-nvr.Tpo $(DEPDIR)/pcem-nvr.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='nvr.c' object='pcem-nvr.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-nvr.obj `if test -f 'nvr.c'; then $(CYGPATH_W) 'nvr.c'; else $(CYGPATH_W) '$(srcdir)/nvr.c'; fi` - -pcem-olivetti_m24.o: olivetti_m24.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-olivetti_m24.o -MD -MP -MF $(DEPDIR)/pcem-olivetti_m24.Tpo -c -o pcem-olivetti_m24.o `test -f 'olivetti_m24.c' || echo '$(srcdir)/'`olivetti_m24.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-olivetti_m24.Tpo $(DEPDIR)/pcem-olivetti_m24.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='olivetti_m24.c' object='pcem-olivetti_m24.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-olivetti_m24.o `test -f 'olivetti_m24.c' || echo '$(srcdir)/'`olivetti_m24.c - -pcem-olivetti_m24.obj: olivetti_m24.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-olivetti_m24.obj -MD -MP -MF $(DEPDIR)/pcem-olivetti_m24.Tpo -c -o pcem-olivetti_m24.obj `if test -f 'olivetti_m24.c'; then $(CYGPATH_W) 'olivetti_m24.c'; else $(CYGPATH_W) '$(srcdir)/olivetti_m24.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-olivetti_m24.Tpo $(DEPDIR)/pcem-olivetti_m24.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='olivetti_m24.c' object='pcem-olivetti_m24.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-olivetti_m24.obj `if test -f 'olivetti_m24.c'; then $(CYGPATH_W) 'olivetti_m24.c'; else $(CYGPATH_W) '$(srcdir)/olivetti_m24.c'; fi` - -pcem-opti.o: opti.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-opti.o -MD -MP -MF $(DEPDIR)/pcem-opti.Tpo -c -o pcem-opti.o `test -f 'opti.c' || echo '$(srcdir)/'`opti.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-opti.Tpo $(DEPDIR)/pcem-opti.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='opti.c' object='pcem-opti.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-opti.o `test -f 'opti.c' || echo '$(srcdir)/'`opti.c - -pcem-opti.obj: opti.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-opti.obj -MD -MP -MF $(DEPDIR)/pcem-opti.Tpo -c -o pcem-opti.obj `if test -f 'opti.c'; then $(CYGPATH_W) 'opti.c'; else $(CYGPATH_W) '$(srcdir)/opti.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-opti.Tpo $(DEPDIR)/pcem-opti.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='opti.c' object='pcem-opti.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-opti.obj `if test -f 'opti.c'; then $(CYGPATH_W) 'opti.c'; else $(CYGPATH_W) '$(srcdir)/opti.c'; fi` - -pcem-pc.o: pc.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-pc.o -MD -MP -MF $(DEPDIR)/pcem-pc.Tpo -c -o pcem-pc.o `test -f 'pc.c' || echo '$(srcdir)/'`pc.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-pc.Tpo $(DEPDIR)/pcem-pc.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='pc.c' object='pcem-pc.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-pc.o `test -f 'pc.c' || echo '$(srcdir)/'`pc.c - -pcem-pc.obj: pc.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-pc.obj -MD -MP -MF $(DEPDIR)/pcem-pc.Tpo -c -o pcem-pc.obj `if test -f 'pc.c'; then $(CYGPATH_W) 'pc.c'; else $(CYGPATH_W) '$(srcdir)/pc.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-pc.Tpo $(DEPDIR)/pcem-pc.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='pc.c' object='pcem-pc.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-pc.obj `if test -f 'pc.c'; then $(CYGPATH_W) 'pc.c'; else $(CYGPATH_W) '$(srcdir)/pc.c'; fi` - -pcem-pci.o: pci.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-pci.o -MD -MP -MF $(DEPDIR)/pcem-pci.Tpo -c -o pcem-pci.o `test -f 'pci.c' || echo '$(srcdir)/'`pci.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-pci.Tpo $(DEPDIR)/pcem-pci.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='pci.c' object='pcem-pci.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-pci.o `test -f 'pci.c' || echo '$(srcdir)/'`pci.c - -pcem-pci.obj: pci.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-pci.obj -MD -MP -MF $(DEPDIR)/pcem-pci.Tpo -c -o pcem-pci.obj `if test -f 'pci.c'; then $(CYGPATH_W) 'pci.c'; else $(CYGPATH_W) '$(srcdir)/pci.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-pci.Tpo $(DEPDIR)/pcem-pci.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='pci.c' object='pcem-pci.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-pci.obj `if test -f 'pci.c'; then $(CYGPATH_W) 'pci.c'; else $(CYGPATH_W) '$(srcdir)/pci.c'; fi` - -pcem-pic.o: pic.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-pic.o -MD -MP -MF $(DEPDIR)/pcem-pic.Tpo -c -o pcem-pic.o `test -f 'pic.c' || echo '$(srcdir)/'`pic.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-pic.Tpo $(DEPDIR)/pcem-pic.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='pic.c' object='pcem-pic.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-pic.o `test -f 'pic.c' || echo '$(srcdir)/'`pic.c - -pcem-pic.obj: pic.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-pic.obj -MD -MP -MF $(DEPDIR)/pcem-pic.Tpo -c -o pcem-pic.obj `if test -f 'pic.c'; then $(CYGPATH_W) 'pic.c'; else $(CYGPATH_W) '$(srcdir)/pic.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-pic.Tpo $(DEPDIR)/pcem-pic.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='pic.c' object='pcem-pic.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-pic.obj `if test -f 'pic.c'; then $(CYGPATH_W) 'pic.c'; else $(CYGPATH_W) '$(srcdir)/pic.c'; fi` - -pcem-piix.o: piix.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-piix.o -MD -MP -MF $(DEPDIR)/pcem-piix.Tpo -c -o pcem-piix.o `test -f 'piix.c' || echo '$(srcdir)/'`piix.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-piix.Tpo $(DEPDIR)/pcem-piix.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='piix.c' object='pcem-piix.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-piix.o `test -f 'piix.c' || echo '$(srcdir)/'`piix.c - -pcem-piix.obj: piix.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-piix.obj -MD -MP -MF $(DEPDIR)/pcem-piix.Tpo -c -o pcem-piix.obj `if test -f 'piix.c'; then $(CYGPATH_W) 'piix.c'; else $(CYGPATH_W) '$(srcdir)/piix.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-piix.Tpo $(DEPDIR)/pcem-piix.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='piix.c' object='pcem-piix.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-piix.obj `if test -f 'piix.c'; then $(CYGPATH_W) 'piix.c'; else $(CYGPATH_W) '$(srcdir)/piix.c'; fi` - -pcem-pit.o: pit.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-pit.o -MD -MP -MF $(DEPDIR)/pcem-pit.Tpo -c -o pcem-pit.o `test -f 'pit.c' || echo '$(srcdir)/'`pit.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-pit.Tpo $(DEPDIR)/pcem-pit.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='pit.c' object='pcem-pit.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-pit.o `test -f 'pit.c' || echo '$(srcdir)/'`pit.c - -pcem-pit.obj: pit.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-pit.obj -MD -MP -MF $(DEPDIR)/pcem-pit.Tpo -c -o pcem-pit.obj `if test -f 'pit.c'; then $(CYGPATH_W) 'pit.c'; else $(CYGPATH_W) '$(srcdir)/pit.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-pit.Tpo $(DEPDIR)/pcem-pit.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='pit.c' object='pcem-pit.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-pit.obj `if test -f 'pit.c'; then $(CYGPATH_W) 'pit.c'; else $(CYGPATH_W) '$(srcdir)/pit.c'; fi` - -pcem-ppi.o: ppi.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-ppi.o -MD -MP -MF $(DEPDIR)/pcem-ppi.Tpo -c -o pcem-ppi.o `test -f 'ppi.c' || echo '$(srcdir)/'`ppi.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-ppi.Tpo $(DEPDIR)/pcem-ppi.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='ppi.c' object='pcem-ppi.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-ppi.o `test -f 'ppi.c' || echo '$(srcdir)/'`ppi.c - -pcem-ppi.obj: ppi.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-ppi.obj -MD -MP -MF $(DEPDIR)/pcem-ppi.Tpo -c -o pcem-ppi.obj `if test -f 'ppi.c'; then $(CYGPATH_W) 'ppi.c'; else $(CYGPATH_W) '$(srcdir)/ppi.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-ppi.Tpo $(DEPDIR)/pcem-ppi.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='ppi.c' object='pcem-ppi.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-ppi.obj `if test -f 'ppi.c'; then $(CYGPATH_W) 'ppi.c'; else $(CYGPATH_W) '$(srcdir)/ppi.c'; fi` - -pcem-ps1.o: ps1.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-ps1.o -MD -MP -MF $(DEPDIR)/pcem-ps1.Tpo -c -o pcem-ps1.o `test -f 'ps1.c' || echo '$(srcdir)/'`ps1.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-ps1.Tpo $(DEPDIR)/pcem-ps1.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='ps1.c' object='pcem-ps1.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-ps1.o `test -f 'ps1.c' || echo '$(srcdir)/'`ps1.c - -pcem-ps1.obj: ps1.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-ps1.obj -MD -MP -MF $(DEPDIR)/pcem-ps1.Tpo -c -o pcem-ps1.obj `if test -f 'ps1.c'; then $(CYGPATH_W) 'ps1.c'; else $(CYGPATH_W) '$(srcdir)/ps1.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-ps1.Tpo $(DEPDIR)/pcem-ps1.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='ps1.c' object='pcem-ps1.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-ps1.obj `if test -f 'ps1.c'; then $(CYGPATH_W) 'ps1.c'; else $(CYGPATH_W) '$(srcdir)/ps1.c'; fi` - -pcem-rom.o: rom.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-rom.o -MD -MP -MF $(DEPDIR)/pcem-rom.Tpo -c -o pcem-rom.o `test -f 'rom.c' || echo '$(srcdir)/'`rom.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-rom.Tpo $(DEPDIR)/pcem-rom.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='rom.c' object='pcem-rom.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-rom.o `test -f 'rom.c' || echo '$(srcdir)/'`rom.c - -pcem-rom.obj: rom.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-rom.obj -MD -MP -MF $(DEPDIR)/pcem-rom.Tpo -c -o pcem-rom.obj `if test -f 'rom.c'; then $(CYGPATH_W) 'rom.c'; else $(CYGPATH_W) '$(srcdir)/rom.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-rom.Tpo $(DEPDIR)/pcem-rom.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='rom.c' object='pcem-rom.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-rom.obj `if test -f 'rom.c'; then $(CYGPATH_W) 'rom.c'; else $(CYGPATH_W) '$(srcdir)/rom.c'; fi` - -pcem-serial.o: serial.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-serial.o -MD -MP -MF $(DEPDIR)/pcem-serial.Tpo -c -o pcem-serial.o `test -f 'serial.c' || echo '$(srcdir)/'`serial.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-serial.Tpo $(DEPDIR)/pcem-serial.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='serial.c' object='pcem-serial.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-serial.o `test -f 'serial.c' || echo '$(srcdir)/'`serial.c - -pcem-serial.obj: serial.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-serial.obj -MD -MP -MF $(DEPDIR)/pcem-serial.Tpo -c -o pcem-serial.obj `if test -f 'serial.c'; then $(CYGPATH_W) 'serial.c'; else $(CYGPATH_W) '$(srcdir)/serial.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-serial.Tpo $(DEPDIR)/pcem-serial.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='serial.c' object='pcem-serial.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-serial.obj `if test -f 'serial.c'; then $(CYGPATH_W) 'serial.c'; else $(CYGPATH_W) '$(srcdir)/serial.c'; fi` - -pcem-sis496.o: sis496.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-sis496.o -MD -MP -MF $(DEPDIR)/pcem-sis496.Tpo -c -o pcem-sis496.o `test -f 'sis496.c' || echo '$(srcdir)/'`sis496.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-sis496.Tpo $(DEPDIR)/pcem-sis496.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sis496.c' object='pcem-sis496.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-sis496.o `test -f 'sis496.c' || echo '$(srcdir)/'`sis496.c - -pcem-sis496.obj: sis496.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-sis496.obj -MD -MP -MF $(DEPDIR)/pcem-sis496.Tpo -c -o pcem-sis496.obj `if test -f 'sis496.c'; then $(CYGPATH_W) 'sis496.c'; else $(CYGPATH_W) '$(srcdir)/sis496.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-sis496.Tpo $(DEPDIR)/pcem-sis496.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sis496.c' object='pcem-sis496.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-sis496.obj `if test -f 'sis496.c'; then $(CYGPATH_W) 'sis496.c'; else $(CYGPATH_W) '$(srcdir)/sis496.c'; fi` - -pcem-sound.o: sound.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-sound.o -MD -MP -MF $(DEPDIR)/pcem-sound.Tpo -c -o pcem-sound.o `test -f 'sound.c' || echo '$(srcdir)/'`sound.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-sound.Tpo $(DEPDIR)/pcem-sound.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sound.c' object='pcem-sound.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-sound.o `test -f 'sound.c' || echo '$(srcdir)/'`sound.c - -pcem-sound.obj: sound.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-sound.obj -MD -MP -MF $(DEPDIR)/pcem-sound.Tpo -c -o pcem-sound.obj `if test -f 'sound.c'; then $(CYGPATH_W) 'sound.c'; else $(CYGPATH_W) '$(srcdir)/sound.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-sound.Tpo $(DEPDIR)/pcem-sound.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sound.c' object='pcem-sound.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-sound.obj `if test -f 'sound.c'; then $(CYGPATH_W) 'sound.c'; else $(CYGPATH_W) '$(srcdir)/sound.c'; fi` - -pcem-sound_ad1848.o: sound_ad1848.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-sound_ad1848.o -MD -MP -MF $(DEPDIR)/pcem-sound_ad1848.Tpo -c -o pcem-sound_ad1848.o `test -f 'sound_ad1848.c' || echo '$(srcdir)/'`sound_ad1848.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-sound_ad1848.Tpo $(DEPDIR)/pcem-sound_ad1848.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sound_ad1848.c' object='pcem-sound_ad1848.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-sound_ad1848.o `test -f 'sound_ad1848.c' || echo '$(srcdir)/'`sound_ad1848.c - -pcem-sound_ad1848.obj: sound_ad1848.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-sound_ad1848.obj -MD -MP -MF $(DEPDIR)/pcem-sound_ad1848.Tpo -c -o pcem-sound_ad1848.obj `if test -f 'sound_ad1848.c'; then $(CYGPATH_W) 'sound_ad1848.c'; else $(CYGPATH_W) '$(srcdir)/sound_ad1848.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-sound_ad1848.Tpo $(DEPDIR)/pcem-sound_ad1848.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sound_ad1848.c' object='pcem-sound_ad1848.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-sound_ad1848.obj `if test -f 'sound_ad1848.c'; then $(CYGPATH_W) 'sound_ad1848.c'; else $(CYGPATH_W) '$(srcdir)/sound_ad1848.c'; fi` - -pcem-sound_adlib.o: sound_adlib.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-sound_adlib.o -MD -MP -MF $(DEPDIR)/pcem-sound_adlib.Tpo -c -o pcem-sound_adlib.o `test -f 'sound_adlib.c' || echo '$(srcdir)/'`sound_adlib.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-sound_adlib.Tpo $(DEPDIR)/pcem-sound_adlib.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sound_adlib.c' object='pcem-sound_adlib.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-sound_adlib.o `test -f 'sound_adlib.c' || echo '$(srcdir)/'`sound_adlib.c - -pcem-sound_adlib.obj: sound_adlib.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-sound_adlib.obj -MD -MP -MF $(DEPDIR)/pcem-sound_adlib.Tpo -c -o pcem-sound_adlib.obj `if test -f 'sound_adlib.c'; then $(CYGPATH_W) 'sound_adlib.c'; else $(CYGPATH_W) '$(srcdir)/sound_adlib.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-sound_adlib.Tpo $(DEPDIR)/pcem-sound_adlib.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sound_adlib.c' object='pcem-sound_adlib.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-sound_adlib.obj `if test -f 'sound_adlib.c'; then $(CYGPATH_W) 'sound_adlib.c'; else $(CYGPATH_W) '$(srcdir)/sound_adlib.c'; fi` - -pcem-sound_adlibgold.o: sound_adlibgold.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-sound_adlibgold.o -MD -MP -MF $(DEPDIR)/pcem-sound_adlibgold.Tpo -c -o pcem-sound_adlibgold.o `test -f 'sound_adlibgold.c' || echo '$(srcdir)/'`sound_adlibgold.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-sound_adlibgold.Tpo $(DEPDIR)/pcem-sound_adlibgold.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sound_adlibgold.c' object='pcem-sound_adlibgold.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-sound_adlibgold.o `test -f 'sound_adlibgold.c' || echo '$(srcdir)/'`sound_adlibgold.c - -pcem-sound_adlibgold.obj: sound_adlibgold.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-sound_adlibgold.obj -MD -MP -MF $(DEPDIR)/pcem-sound_adlibgold.Tpo -c -o pcem-sound_adlibgold.obj `if test -f 'sound_adlibgold.c'; then $(CYGPATH_W) 'sound_adlibgold.c'; else $(CYGPATH_W) '$(srcdir)/sound_adlibgold.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-sound_adlibgold.Tpo $(DEPDIR)/pcem-sound_adlibgold.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sound_adlibgold.c' object='pcem-sound_adlibgold.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-sound_adlibgold.obj `if test -f 'sound_adlibgold.c'; then $(CYGPATH_W) 'sound_adlibgold.c'; else $(CYGPATH_W) '$(srcdir)/sound_adlibgold.c'; fi` - -pcem-sound_cms.o: sound_cms.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-sound_cms.o -MD -MP -MF $(DEPDIR)/pcem-sound_cms.Tpo -c -o pcem-sound_cms.o `test -f 'sound_cms.c' || echo '$(srcdir)/'`sound_cms.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-sound_cms.Tpo $(DEPDIR)/pcem-sound_cms.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sound_cms.c' object='pcem-sound_cms.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-sound_cms.o `test -f 'sound_cms.c' || echo '$(srcdir)/'`sound_cms.c - -pcem-sound_cms.obj: sound_cms.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-sound_cms.obj -MD -MP -MF $(DEPDIR)/pcem-sound_cms.Tpo -c -o pcem-sound_cms.obj `if test -f 'sound_cms.c'; then $(CYGPATH_W) 'sound_cms.c'; else $(CYGPATH_W) '$(srcdir)/sound_cms.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-sound_cms.Tpo $(DEPDIR)/pcem-sound_cms.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sound_cms.c' object='pcem-sound_cms.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-sound_cms.obj `if test -f 'sound_cms.c'; then $(CYGPATH_W) 'sound_cms.c'; else $(CYGPATH_W) '$(srcdir)/sound_cms.c'; fi` - -pcem-sound_emu8k.o: sound_emu8k.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-sound_emu8k.o -MD -MP -MF $(DEPDIR)/pcem-sound_emu8k.Tpo -c -o pcem-sound_emu8k.o `test -f 'sound_emu8k.c' || echo '$(srcdir)/'`sound_emu8k.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-sound_emu8k.Tpo $(DEPDIR)/pcem-sound_emu8k.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sound_emu8k.c' object='pcem-sound_emu8k.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-sound_emu8k.o `test -f 'sound_emu8k.c' || echo '$(srcdir)/'`sound_emu8k.c - -pcem-sound_emu8k.obj: sound_emu8k.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-sound_emu8k.obj -MD -MP -MF $(DEPDIR)/pcem-sound_emu8k.Tpo -c -o pcem-sound_emu8k.obj `if test -f 'sound_emu8k.c'; then $(CYGPATH_W) 'sound_emu8k.c'; else $(CYGPATH_W) '$(srcdir)/sound_emu8k.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-sound_emu8k.Tpo $(DEPDIR)/pcem-sound_emu8k.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sound_emu8k.c' object='pcem-sound_emu8k.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-sound_emu8k.obj `if test -f 'sound_emu8k.c'; then $(CYGPATH_W) 'sound_emu8k.c'; else $(CYGPATH_W) '$(srcdir)/sound_emu8k.c'; fi` - -pcem-sound_gus.o: sound_gus.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-sound_gus.o -MD -MP -MF $(DEPDIR)/pcem-sound_gus.Tpo -c -o pcem-sound_gus.o `test -f 'sound_gus.c' || echo '$(srcdir)/'`sound_gus.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-sound_gus.Tpo $(DEPDIR)/pcem-sound_gus.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sound_gus.c' object='pcem-sound_gus.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-sound_gus.o `test -f 'sound_gus.c' || echo '$(srcdir)/'`sound_gus.c - -pcem-sound_gus.obj: sound_gus.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-sound_gus.obj -MD -MP -MF $(DEPDIR)/pcem-sound_gus.Tpo -c -o pcem-sound_gus.obj `if test -f 'sound_gus.c'; then $(CYGPATH_W) 'sound_gus.c'; else $(CYGPATH_W) '$(srcdir)/sound_gus.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-sound_gus.Tpo $(DEPDIR)/pcem-sound_gus.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sound_gus.c' object='pcem-sound_gus.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-sound_gus.obj `if test -f 'sound_gus.c'; then $(CYGPATH_W) 'sound_gus.c'; else $(CYGPATH_W) '$(srcdir)/sound_gus.c'; fi` - -pcem-sound_mpu401_uart.o: sound_mpu401_uart.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-sound_mpu401_uart.o -MD -MP -MF $(DEPDIR)/pcem-sound_mpu401_uart.Tpo -c -o pcem-sound_mpu401_uart.o `test -f 'sound_mpu401_uart.c' || echo '$(srcdir)/'`sound_mpu401_uart.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-sound_mpu401_uart.Tpo $(DEPDIR)/pcem-sound_mpu401_uart.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sound_mpu401_uart.c' object='pcem-sound_mpu401_uart.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-sound_mpu401_uart.o `test -f 'sound_mpu401_uart.c' || echo '$(srcdir)/'`sound_mpu401_uart.c - -pcem-sound_mpu401_uart.obj: sound_mpu401_uart.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-sound_mpu401_uart.obj -MD -MP -MF $(DEPDIR)/pcem-sound_mpu401_uart.Tpo -c -o pcem-sound_mpu401_uart.obj `if test -f 'sound_mpu401_uart.c'; then $(CYGPATH_W) 'sound_mpu401_uart.c'; else $(CYGPATH_W) '$(srcdir)/sound_mpu401_uart.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-sound_mpu401_uart.Tpo $(DEPDIR)/pcem-sound_mpu401_uart.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sound_mpu401_uart.c' object='pcem-sound_mpu401_uart.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-sound_mpu401_uart.obj `if test -f 'sound_mpu401_uart.c'; then $(CYGPATH_W) 'sound_mpu401_uart.c'; else $(CYGPATH_W) '$(srcdir)/sound_mpu401_uart.c'; fi` - -pcem-sound_opl.o: sound_opl.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-sound_opl.o -MD -MP -MF $(DEPDIR)/pcem-sound_opl.Tpo -c -o pcem-sound_opl.o `test -f 'sound_opl.c' || echo '$(srcdir)/'`sound_opl.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-sound_opl.Tpo $(DEPDIR)/pcem-sound_opl.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sound_opl.c' object='pcem-sound_opl.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-sound_opl.o `test -f 'sound_opl.c' || echo '$(srcdir)/'`sound_opl.c - -pcem-sound_opl.obj: sound_opl.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-sound_opl.obj -MD -MP -MF $(DEPDIR)/pcem-sound_opl.Tpo -c -o pcem-sound_opl.obj `if test -f 'sound_opl.c'; then $(CYGPATH_W) 'sound_opl.c'; else $(CYGPATH_W) '$(srcdir)/sound_opl.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-sound_opl.Tpo $(DEPDIR)/pcem-sound_opl.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sound_opl.c' object='pcem-sound_opl.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-sound_opl.obj `if test -f 'sound_opl.c'; then $(CYGPATH_W) 'sound_opl.c'; else $(CYGPATH_W) '$(srcdir)/sound_opl.c'; fi` - -pcem-sound_pas16.o: sound_pas16.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-sound_pas16.o -MD -MP -MF $(DEPDIR)/pcem-sound_pas16.Tpo -c -o pcem-sound_pas16.o `test -f 'sound_pas16.c' || echo '$(srcdir)/'`sound_pas16.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-sound_pas16.Tpo $(DEPDIR)/pcem-sound_pas16.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sound_pas16.c' object='pcem-sound_pas16.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-sound_pas16.o `test -f 'sound_pas16.c' || echo '$(srcdir)/'`sound_pas16.c - -pcem-sound_pas16.obj: sound_pas16.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-sound_pas16.obj -MD -MP -MF $(DEPDIR)/pcem-sound_pas16.Tpo -c -o pcem-sound_pas16.obj `if test -f 'sound_pas16.c'; then $(CYGPATH_W) 'sound_pas16.c'; else $(CYGPATH_W) '$(srcdir)/sound_pas16.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-sound_pas16.Tpo $(DEPDIR)/pcem-sound_pas16.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sound_pas16.c' object='pcem-sound_pas16.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-sound_pas16.obj `if test -f 'sound_pas16.c'; then $(CYGPATH_W) 'sound_pas16.c'; else $(CYGPATH_W) '$(srcdir)/sound_pas16.c'; fi` - -pcem-sound_sb.o: sound_sb.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-sound_sb.o -MD -MP -MF $(DEPDIR)/pcem-sound_sb.Tpo -c -o pcem-sound_sb.o `test -f 'sound_sb.c' || echo '$(srcdir)/'`sound_sb.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-sound_sb.Tpo $(DEPDIR)/pcem-sound_sb.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sound_sb.c' object='pcem-sound_sb.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-sound_sb.o `test -f 'sound_sb.c' || echo '$(srcdir)/'`sound_sb.c - -pcem-sound_sb.obj: sound_sb.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-sound_sb.obj -MD -MP -MF $(DEPDIR)/pcem-sound_sb.Tpo -c -o pcem-sound_sb.obj `if test -f 'sound_sb.c'; then $(CYGPATH_W) 'sound_sb.c'; else $(CYGPATH_W) '$(srcdir)/sound_sb.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-sound_sb.Tpo $(DEPDIR)/pcem-sound_sb.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sound_sb.c' object='pcem-sound_sb.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-sound_sb.obj `if test -f 'sound_sb.c'; then $(CYGPATH_W) 'sound_sb.c'; else $(CYGPATH_W) '$(srcdir)/sound_sb.c'; fi` - -pcem-sound_sb_dsp.o: sound_sb_dsp.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-sound_sb_dsp.o -MD -MP -MF $(DEPDIR)/pcem-sound_sb_dsp.Tpo -c -o pcem-sound_sb_dsp.o `test -f 'sound_sb_dsp.c' || echo '$(srcdir)/'`sound_sb_dsp.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-sound_sb_dsp.Tpo $(DEPDIR)/pcem-sound_sb_dsp.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sound_sb_dsp.c' object='pcem-sound_sb_dsp.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-sound_sb_dsp.o `test -f 'sound_sb_dsp.c' || echo '$(srcdir)/'`sound_sb_dsp.c - -pcem-sound_sb_dsp.obj: sound_sb_dsp.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-sound_sb_dsp.obj -MD -MP -MF $(DEPDIR)/pcem-sound_sb_dsp.Tpo -c -o pcem-sound_sb_dsp.obj `if test -f 'sound_sb_dsp.c'; then $(CYGPATH_W) 'sound_sb_dsp.c'; else $(CYGPATH_W) '$(srcdir)/sound_sb_dsp.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-sound_sb_dsp.Tpo $(DEPDIR)/pcem-sound_sb_dsp.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sound_sb_dsp.c' object='pcem-sound_sb_dsp.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-sound_sb_dsp.obj `if test -f 'sound_sb_dsp.c'; then $(CYGPATH_W) 'sound_sb_dsp.c'; else $(CYGPATH_W) '$(srcdir)/sound_sb_dsp.c'; fi` - -pcem-sound_sn76489.o: sound_sn76489.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-sound_sn76489.o -MD -MP -MF $(DEPDIR)/pcem-sound_sn76489.Tpo -c -o pcem-sound_sn76489.o `test -f 'sound_sn76489.c' || echo '$(srcdir)/'`sound_sn76489.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-sound_sn76489.Tpo $(DEPDIR)/pcem-sound_sn76489.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sound_sn76489.c' object='pcem-sound_sn76489.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-sound_sn76489.o `test -f 'sound_sn76489.c' || echo '$(srcdir)/'`sound_sn76489.c - -pcem-sound_sn76489.obj: sound_sn76489.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-sound_sn76489.obj -MD -MP -MF $(DEPDIR)/pcem-sound_sn76489.Tpo -c -o pcem-sound_sn76489.obj `if test -f 'sound_sn76489.c'; then $(CYGPATH_W) 'sound_sn76489.c'; else $(CYGPATH_W) '$(srcdir)/sound_sn76489.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-sound_sn76489.Tpo $(DEPDIR)/pcem-sound_sn76489.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sound_sn76489.c' object='pcem-sound_sn76489.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-sound_sn76489.obj `if test -f 'sound_sn76489.c'; then $(CYGPATH_W) 'sound_sn76489.c'; else $(CYGPATH_W) '$(srcdir)/sound_sn76489.c'; fi` - -pcem-sound_speaker.o: sound_speaker.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-sound_speaker.o -MD -MP -MF $(DEPDIR)/pcem-sound_speaker.Tpo -c -o pcem-sound_speaker.o `test -f 'sound_speaker.c' || echo '$(srcdir)/'`sound_speaker.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-sound_speaker.Tpo $(DEPDIR)/pcem-sound_speaker.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sound_speaker.c' object='pcem-sound_speaker.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-sound_speaker.o `test -f 'sound_speaker.c' || echo '$(srcdir)/'`sound_speaker.c - -pcem-sound_speaker.obj: sound_speaker.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-sound_speaker.obj -MD -MP -MF $(DEPDIR)/pcem-sound_speaker.Tpo -c -o pcem-sound_speaker.obj `if test -f 'sound_speaker.c'; then $(CYGPATH_W) 'sound_speaker.c'; else $(CYGPATH_W) '$(srcdir)/sound_speaker.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-sound_speaker.Tpo $(DEPDIR)/pcem-sound_speaker.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sound_speaker.c' object='pcem-sound_speaker.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-sound_speaker.obj `if test -f 'sound_speaker.c'; then $(CYGPATH_W) 'sound_speaker.c'; else $(CYGPATH_W) '$(srcdir)/sound_speaker.c'; fi` - -pcem-sound_ssi2001.o: sound_ssi2001.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-sound_ssi2001.o -MD -MP -MF $(DEPDIR)/pcem-sound_ssi2001.Tpo -c -o pcem-sound_ssi2001.o `test -f 'sound_ssi2001.c' || echo '$(srcdir)/'`sound_ssi2001.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-sound_ssi2001.Tpo $(DEPDIR)/pcem-sound_ssi2001.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sound_ssi2001.c' object='pcem-sound_ssi2001.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-sound_ssi2001.o `test -f 'sound_ssi2001.c' || echo '$(srcdir)/'`sound_ssi2001.c - -pcem-sound_ssi2001.obj: sound_ssi2001.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-sound_ssi2001.obj -MD -MP -MF $(DEPDIR)/pcem-sound_ssi2001.Tpo -c -o pcem-sound_ssi2001.obj `if test -f 'sound_ssi2001.c'; then $(CYGPATH_W) 'sound_ssi2001.c'; else $(CYGPATH_W) '$(srcdir)/sound_ssi2001.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-sound_ssi2001.Tpo $(DEPDIR)/pcem-sound_ssi2001.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sound_ssi2001.c' object='pcem-sound_ssi2001.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-sound_ssi2001.obj `if test -f 'sound_ssi2001.c'; then $(CYGPATH_W) 'sound_ssi2001.c'; else $(CYGPATH_W) '$(srcdir)/sound_ssi2001.c'; fi` - -pcem-sound_wss.o: sound_wss.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-sound_wss.o -MD -MP -MF $(DEPDIR)/pcem-sound_wss.Tpo -c -o pcem-sound_wss.o `test -f 'sound_wss.c' || echo '$(srcdir)/'`sound_wss.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-sound_wss.Tpo $(DEPDIR)/pcem-sound_wss.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sound_wss.c' object='pcem-sound_wss.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-sound_wss.o `test -f 'sound_wss.c' || echo '$(srcdir)/'`sound_wss.c - -pcem-sound_wss.obj: sound_wss.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-sound_wss.obj -MD -MP -MF $(DEPDIR)/pcem-sound_wss.Tpo -c -o pcem-sound_wss.obj `if test -f 'sound_wss.c'; then $(CYGPATH_W) 'sound_wss.c'; else $(CYGPATH_W) '$(srcdir)/sound_wss.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-sound_wss.Tpo $(DEPDIR)/pcem-sound_wss.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sound_wss.c' object='pcem-sound_wss.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-sound_wss.obj `if test -f 'sound_wss.c'; then $(CYGPATH_W) 'sound_wss.c'; else $(CYGPATH_W) '$(srcdir)/sound_wss.c'; fi` - -pcem-soundopenal.o: soundopenal.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-soundopenal.o -MD -MP -MF $(DEPDIR)/pcem-soundopenal.Tpo -c -o pcem-soundopenal.o `test -f 'soundopenal.c' || echo '$(srcdir)/'`soundopenal.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-soundopenal.Tpo $(DEPDIR)/pcem-soundopenal.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='soundopenal.c' object='pcem-soundopenal.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-soundopenal.o `test -f 'soundopenal.c' || echo '$(srcdir)/'`soundopenal.c - -pcem-soundopenal.obj: soundopenal.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-soundopenal.obj -MD -MP -MF $(DEPDIR)/pcem-soundopenal.Tpo -c -o pcem-soundopenal.obj `if test -f 'soundopenal.c'; then $(CYGPATH_W) 'soundopenal.c'; else $(CYGPATH_W) '$(srcdir)/soundopenal.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-soundopenal.Tpo $(DEPDIR)/pcem-soundopenal.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='soundopenal.c' object='pcem-soundopenal.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-soundopenal.obj `if test -f 'soundopenal.c'; then $(CYGPATH_W) 'soundopenal.c'; else $(CYGPATH_W) '$(srcdir)/soundopenal.c'; fi` - -pcem-thread-pthread.o: thread-pthread.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-thread-pthread.o -MD -MP -MF $(DEPDIR)/pcem-thread-pthread.Tpo -c -o pcem-thread-pthread.o `test -f 'thread-pthread.c' || echo '$(srcdir)/'`thread-pthread.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-thread-pthread.Tpo $(DEPDIR)/pcem-thread-pthread.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='thread-pthread.c' object='pcem-thread-pthread.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-thread-pthread.o `test -f 'thread-pthread.c' || echo '$(srcdir)/'`thread-pthread.c - -pcem-thread-pthread.obj: thread-pthread.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-thread-pthread.obj -MD -MP -MF $(DEPDIR)/pcem-thread-pthread.Tpo -c -o pcem-thread-pthread.obj `if test -f 'thread-pthread.c'; then $(CYGPATH_W) 'thread-pthread.c'; else $(CYGPATH_W) '$(srcdir)/thread-pthread.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-thread-pthread.Tpo $(DEPDIR)/pcem-thread-pthread.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='thread-pthread.c' object='pcem-thread-pthread.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-thread-pthread.obj `if test -f 'thread-pthread.c'; then $(CYGPATH_W) 'thread-pthread.c'; else $(CYGPATH_W) '$(srcdir)/thread-pthread.c'; fi` - -pcem-timer.o: timer.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-timer.o -MD -MP -MF $(DEPDIR)/pcem-timer.Tpo -c -o pcem-timer.o `test -f 'timer.c' || echo '$(srcdir)/'`timer.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-timer.Tpo $(DEPDIR)/pcem-timer.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='timer.c' object='pcem-timer.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-timer.o `test -f 'timer.c' || echo '$(srcdir)/'`timer.c - -pcem-timer.obj: timer.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-timer.obj -MD -MP -MF $(DEPDIR)/pcem-timer.Tpo -c -o pcem-timer.obj `if test -f 'timer.c'; then $(CYGPATH_W) 'timer.c'; else $(CYGPATH_W) '$(srcdir)/timer.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-timer.Tpo $(DEPDIR)/pcem-timer.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='timer.c' object='pcem-timer.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-timer.obj `if test -f 'timer.c'; then $(CYGPATH_W) 'timer.c'; else $(CYGPATH_W) '$(srcdir)/timer.c'; fi` - -pcem-um8669f.o: um8669f.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-um8669f.o -MD -MP -MF $(DEPDIR)/pcem-um8669f.Tpo -c -o pcem-um8669f.o `test -f 'um8669f.c' || echo '$(srcdir)/'`um8669f.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-um8669f.Tpo $(DEPDIR)/pcem-um8669f.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='um8669f.c' object='pcem-um8669f.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-um8669f.o `test -f 'um8669f.c' || echo '$(srcdir)/'`um8669f.c - -pcem-um8669f.obj: um8669f.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-um8669f.obj -MD -MP -MF $(DEPDIR)/pcem-um8669f.Tpo -c -o pcem-um8669f.obj `if test -f 'um8669f.c'; then $(CYGPATH_W) 'um8669f.c'; else $(CYGPATH_W) '$(srcdir)/um8669f.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-um8669f.Tpo $(DEPDIR)/pcem-um8669f.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='um8669f.c' object='pcem-um8669f.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-um8669f.obj `if test -f 'um8669f.c'; then $(CYGPATH_W) 'um8669f.c'; else $(CYGPATH_W) '$(srcdir)/um8669f.c'; fi` - -pcem-um8881f.o: um8881f.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-um8881f.o -MD -MP -MF $(DEPDIR)/pcem-um8881f.Tpo -c -o pcem-um8881f.o `test -f 'um8881f.c' || echo '$(srcdir)/'`um8881f.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-um8881f.Tpo $(DEPDIR)/pcem-um8881f.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='um8881f.c' object='pcem-um8881f.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-um8881f.o `test -f 'um8881f.c' || echo '$(srcdir)/'`um8881f.c - -pcem-um8881f.obj: um8881f.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-um8881f.obj -MD -MP -MF $(DEPDIR)/pcem-um8881f.Tpo -c -o pcem-um8881f.obj `if test -f 'um8881f.c'; then $(CYGPATH_W) 'um8881f.c'; else $(CYGPATH_W) '$(srcdir)/um8881f.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-um8881f.Tpo $(DEPDIR)/pcem-um8881f.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='um8881f.c' object='pcem-um8881f.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-um8881f.obj `if test -f 'um8881f.c'; then $(CYGPATH_W) 'um8881f.c'; else $(CYGPATH_W) '$(srcdir)/um8881f.c'; fi` - -pcem-vid_ati_eeprom.o: vid_ati_eeprom.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vid_ati_eeprom.o -MD -MP -MF $(DEPDIR)/pcem-vid_ati_eeprom.Tpo -c -o pcem-vid_ati_eeprom.o `test -f 'vid_ati_eeprom.c' || echo '$(srcdir)/'`vid_ati_eeprom.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-vid_ati_eeprom.Tpo $(DEPDIR)/pcem-vid_ati_eeprom.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='vid_ati_eeprom.c' object='pcem-vid_ati_eeprom.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_ati_eeprom.o `test -f 'vid_ati_eeprom.c' || echo '$(srcdir)/'`vid_ati_eeprom.c - -pcem-vid_ati_eeprom.obj: vid_ati_eeprom.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vid_ati_eeprom.obj -MD -MP -MF $(DEPDIR)/pcem-vid_ati_eeprom.Tpo -c -o pcem-vid_ati_eeprom.obj `if test -f 'vid_ati_eeprom.c'; then $(CYGPATH_W) 'vid_ati_eeprom.c'; else $(CYGPATH_W) '$(srcdir)/vid_ati_eeprom.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-vid_ati_eeprom.Tpo $(DEPDIR)/pcem-vid_ati_eeprom.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='vid_ati_eeprom.c' object='pcem-vid_ati_eeprom.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_ati_eeprom.obj `if test -f 'vid_ati_eeprom.c'; then $(CYGPATH_W) 'vid_ati_eeprom.c'; else $(CYGPATH_W) '$(srcdir)/vid_ati_eeprom.c'; fi` - -pcem-vid_ati_mach64.o: vid_ati_mach64.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vid_ati_mach64.o -MD -MP -MF $(DEPDIR)/pcem-vid_ati_mach64.Tpo -c -o pcem-vid_ati_mach64.o `test -f 'vid_ati_mach64.c' || echo '$(srcdir)/'`vid_ati_mach64.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-vid_ati_mach64.Tpo $(DEPDIR)/pcem-vid_ati_mach64.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='vid_ati_mach64.c' object='pcem-vid_ati_mach64.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_ati_mach64.o `test -f 'vid_ati_mach64.c' || echo '$(srcdir)/'`vid_ati_mach64.c - -pcem-vid_ati_mach64.obj: vid_ati_mach64.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vid_ati_mach64.obj -MD -MP -MF $(DEPDIR)/pcem-vid_ati_mach64.Tpo -c -o pcem-vid_ati_mach64.obj `if test -f 'vid_ati_mach64.c'; then $(CYGPATH_W) 'vid_ati_mach64.c'; else $(CYGPATH_W) '$(srcdir)/vid_ati_mach64.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-vid_ati_mach64.Tpo $(DEPDIR)/pcem-vid_ati_mach64.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='vid_ati_mach64.c' object='pcem-vid_ati_mach64.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_ati_mach64.obj `if test -f 'vid_ati_mach64.c'; then $(CYGPATH_W) 'vid_ati_mach64.c'; else $(CYGPATH_W) '$(srcdir)/vid_ati_mach64.c'; fi` - -pcem-vid_ati18800.o: vid_ati18800.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vid_ati18800.o -MD -MP -MF $(DEPDIR)/pcem-vid_ati18800.Tpo -c -o pcem-vid_ati18800.o `test -f 'vid_ati18800.c' || echo '$(srcdir)/'`vid_ati18800.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-vid_ati18800.Tpo $(DEPDIR)/pcem-vid_ati18800.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='vid_ati18800.c' object='pcem-vid_ati18800.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_ati18800.o `test -f 'vid_ati18800.c' || echo '$(srcdir)/'`vid_ati18800.c - -pcem-vid_ati18800.obj: vid_ati18800.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vid_ati18800.obj -MD -MP -MF $(DEPDIR)/pcem-vid_ati18800.Tpo -c -o pcem-vid_ati18800.obj `if test -f 'vid_ati18800.c'; then $(CYGPATH_W) 'vid_ati18800.c'; else $(CYGPATH_W) '$(srcdir)/vid_ati18800.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-vid_ati18800.Tpo $(DEPDIR)/pcem-vid_ati18800.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='vid_ati18800.c' object='pcem-vid_ati18800.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_ati18800.obj `if test -f 'vid_ati18800.c'; then $(CYGPATH_W) 'vid_ati18800.c'; else $(CYGPATH_W) '$(srcdir)/vid_ati18800.c'; fi` - -pcem-vid_ati28800.o: vid_ati28800.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vid_ati28800.o -MD -MP -MF $(DEPDIR)/pcem-vid_ati28800.Tpo -c -o pcem-vid_ati28800.o `test -f 'vid_ati28800.c' || echo '$(srcdir)/'`vid_ati28800.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-vid_ati28800.Tpo $(DEPDIR)/pcem-vid_ati28800.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='vid_ati28800.c' object='pcem-vid_ati28800.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_ati28800.o `test -f 'vid_ati28800.c' || echo '$(srcdir)/'`vid_ati28800.c - -pcem-vid_ati28800.obj: vid_ati28800.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vid_ati28800.obj -MD -MP -MF $(DEPDIR)/pcem-vid_ati28800.Tpo -c -o pcem-vid_ati28800.obj `if test -f 'vid_ati28800.c'; then $(CYGPATH_W) 'vid_ati28800.c'; else $(CYGPATH_W) '$(srcdir)/vid_ati28800.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-vid_ati28800.Tpo $(DEPDIR)/pcem-vid_ati28800.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='vid_ati28800.c' object='pcem-vid_ati28800.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_ati28800.obj `if test -f 'vid_ati28800.c'; then $(CYGPATH_W) 'vid_ati28800.c'; else $(CYGPATH_W) '$(srcdir)/vid_ati28800.c'; fi` - -pcem-vid_ati68860_ramdac.o: vid_ati68860_ramdac.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vid_ati68860_ramdac.o -MD -MP -MF $(DEPDIR)/pcem-vid_ati68860_ramdac.Tpo -c -o pcem-vid_ati68860_ramdac.o `test -f 'vid_ati68860_ramdac.c' || echo '$(srcdir)/'`vid_ati68860_ramdac.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-vid_ati68860_ramdac.Tpo $(DEPDIR)/pcem-vid_ati68860_ramdac.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='vid_ati68860_ramdac.c' object='pcem-vid_ati68860_ramdac.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_ati68860_ramdac.o `test -f 'vid_ati68860_ramdac.c' || echo '$(srcdir)/'`vid_ati68860_ramdac.c - -pcem-vid_ati68860_ramdac.obj: vid_ati68860_ramdac.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vid_ati68860_ramdac.obj -MD -MP -MF $(DEPDIR)/pcem-vid_ati68860_ramdac.Tpo -c -o pcem-vid_ati68860_ramdac.obj `if test -f 'vid_ati68860_ramdac.c'; then $(CYGPATH_W) 'vid_ati68860_ramdac.c'; else $(CYGPATH_W) '$(srcdir)/vid_ati68860_ramdac.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-vid_ati68860_ramdac.Tpo $(DEPDIR)/pcem-vid_ati68860_ramdac.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='vid_ati68860_ramdac.c' object='pcem-vid_ati68860_ramdac.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_ati68860_ramdac.obj `if test -f 'vid_ati68860_ramdac.c'; then $(CYGPATH_W) 'vid_ati68860_ramdac.c'; else $(CYGPATH_W) '$(srcdir)/vid_ati68860_ramdac.c'; fi` - -pcem-vid_cga.o: vid_cga.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vid_cga.o -MD -MP -MF $(DEPDIR)/pcem-vid_cga.Tpo -c -o pcem-vid_cga.o `test -f 'vid_cga.c' || echo '$(srcdir)/'`vid_cga.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-vid_cga.Tpo $(DEPDIR)/pcem-vid_cga.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='vid_cga.c' object='pcem-vid_cga.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_cga.o `test -f 'vid_cga.c' || echo '$(srcdir)/'`vid_cga.c - -pcem-vid_cga.obj: vid_cga.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vid_cga.obj -MD -MP -MF $(DEPDIR)/pcem-vid_cga.Tpo -c -o pcem-vid_cga.obj `if test -f 'vid_cga.c'; then $(CYGPATH_W) 'vid_cga.c'; else $(CYGPATH_W) '$(srcdir)/vid_cga.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-vid_cga.Tpo $(DEPDIR)/pcem-vid_cga.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='vid_cga.c' object='pcem-vid_cga.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_cga.obj `if test -f 'vid_cga.c'; then $(CYGPATH_W) 'vid_cga.c'; else $(CYGPATH_W) '$(srcdir)/vid_cga.c'; fi` - -pcem-vid_cl5429.o: vid_cl5429.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vid_cl5429.o -MD -MP -MF $(DEPDIR)/pcem-vid_cl5429.Tpo -c -o pcem-vid_cl5429.o `test -f 'vid_cl5429.c' || echo '$(srcdir)/'`vid_cl5429.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-vid_cl5429.Tpo $(DEPDIR)/pcem-vid_cl5429.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='vid_cl5429.c' object='pcem-vid_cl5429.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_cl5429.o `test -f 'vid_cl5429.c' || echo '$(srcdir)/'`vid_cl5429.c - -pcem-vid_cl5429.obj: vid_cl5429.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vid_cl5429.obj -MD -MP -MF $(DEPDIR)/pcem-vid_cl5429.Tpo -c -o pcem-vid_cl5429.obj `if test -f 'vid_cl5429.c'; then $(CYGPATH_W) 'vid_cl5429.c'; else $(CYGPATH_W) '$(srcdir)/vid_cl5429.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-vid_cl5429.Tpo $(DEPDIR)/pcem-vid_cl5429.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='vid_cl5429.c' object='pcem-vid_cl5429.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_cl5429.obj `if test -f 'vid_cl5429.c'; then $(CYGPATH_W) 'vid_cl5429.c'; else $(CYGPATH_W) '$(srcdir)/vid_cl5429.c'; fi` - -pcem-vid_ega.o: vid_ega.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vid_ega.o -MD -MP -MF $(DEPDIR)/pcem-vid_ega.Tpo -c -o pcem-vid_ega.o `test -f 'vid_ega.c' || echo '$(srcdir)/'`vid_ega.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-vid_ega.Tpo $(DEPDIR)/pcem-vid_ega.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='vid_ega.c' object='pcem-vid_ega.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_ega.o `test -f 'vid_ega.c' || echo '$(srcdir)/'`vid_ega.c - -pcem-vid_ega.obj: vid_ega.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vid_ega.obj -MD -MP -MF $(DEPDIR)/pcem-vid_ega.Tpo -c -o pcem-vid_ega.obj `if test -f 'vid_ega.c'; then $(CYGPATH_W) 'vid_ega.c'; else $(CYGPATH_W) '$(srcdir)/vid_ega.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-vid_ega.Tpo $(DEPDIR)/pcem-vid_ega.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='vid_ega.c' object='pcem-vid_ega.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_ega.obj `if test -f 'vid_ega.c'; then $(CYGPATH_W) 'vid_ega.c'; else $(CYGPATH_W) '$(srcdir)/vid_ega.c'; fi` - -pcem-vid_et4000.o: vid_et4000.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vid_et4000.o -MD -MP -MF $(DEPDIR)/pcem-vid_et4000.Tpo -c -o pcem-vid_et4000.o `test -f 'vid_et4000.c' || echo '$(srcdir)/'`vid_et4000.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-vid_et4000.Tpo $(DEPDIR)/pcem-vid_et4000.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='vid_et4000.c' object='pcem-vid_et4000.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_et4000.o `test -f 'vid_et4000.c' || echo '$(srcdir)/'`vid_et4000.c - -pcem-vid_et4000.obj: vid_et4000.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vid_et4000.obj -MD -MP -MF $(DEPDIR)/pcem-vid_et4000.Tpo -c -o pcem-vid_et4000.obj `if test -f 'vid_et4000.c'; then $(CYGPATH_W) 'vid_et4000.c'; else $(CYGPATH_W) '$(srcdir)/vid_et4000.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-vid_et4000.Tpo $(DEPDIR)/pcem-vid_et4000.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='vid_et4000.c' object='pcem-vid_et4000.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_et4000.obj `if test -f 'vid_et4000.c'; then $(CYGPATH_W) 'vid_et4000.c'; else $(CYGPATH_W) '$(srcdir)/vid_et4000.c'; fi` - -pcem-vid_et4000w32.o: vid_et4000w32.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vid_et4000w32.o -MD -MP -MF $(DEPDIR)/pcem-vid_et4000w32.Tpo -c -o pcem-vid_et4000w32.o `test -f 'vid_et4000w32.c' || echo '$(srcdir)/'`vid_et4000w32.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-vid_et4000w32.Tpo $(DEPDIR)/pcem-vid_et4000w32.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='vid_et4000w32.c' object='pcem-vid_et4000w32.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_et4000w32.o `test -f 'vid_et4000w32.c' || echo '$(srcdir)/'`vid_et4000w32.c - -pcem-vid_et4000w32.obj: vid_et4000w32.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vid_et4000w32.obj -MD -MP -MF $(DEPDIR)/pcem-vid_et4000w32.Tpo -c -o pcem-vid_et4000w32.obj `if test -f 'vid_et4000w32.c'; then $(CYGPATH_W) 'vid_et4000w32.c'; else $(CYGPATH_W) '$(srcdir)/vid_et4000w32.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-vid_et4000w32.Tpo $(DEPDIR)/pcem-vid_et4000w32.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='vid_et4000w32.c' object='pcem-vid_et4000w32.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_et4000w32.obj `if test -f 'vid_et4000w32.c'; then $(CYGPATH_W) 'vid_et4000w32.c'; else $(CYGPATH_W) '$(srcdir)/vid_et4000w32.c'; fi` - -pcem-vid_hercules.o: vid_hercules.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vid_hercules.o -MD -MP -MF $(DEPDIR)/pcem-vid_hercules.Tpo -c -o pcem-vid_hercules.o `test -f 'vid_hercules.c' || echo '$(srcdir)/'`vid_hercules.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-vid_hercules.Tpo $(DEPDIR)/pcem-vid_hercules.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='vid_hercules.c' object='pcem-vid_hercules.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_hercules.o `test -f 'vid_hercules.c' || echo '$(srcdir)/'`vid_hercules.c - -pcem-vid_hercules.obj: vid_hercules.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vid_hercules.obj -MD -MP -MF $(DEPDIR)/pcem-vid_hercules.Tpo -c -o pcem-vid_hercules.obj `if test -f 'vid_hercules.c'; then $(CYGPATH_W) 'vid_hercules.c'; else $(CYGPATH_W) '$(srcdir)/vid_hercules.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-vid_hercules.Tpo $(DEPDIR)/pcem-vid_hercules.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='vid_hercules.c' object='pcem-vid_hercules.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_hercules.obj `if test -f 'vid_hercules.c'; then $(CYGPATH_W) 'vid_hercules.c'; else $(CYGPATH_W) '$(srcdir)/vid_hercules.c'; fi` - -pcem-vid_icd2061.o: vid_icd2061.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vid_icd2061.o -MD -MP -MF $(DEPDIR)/pcem-vid_icd2061.Tpo -c -o pcem-vid_icd2061.o `test -f 'vid_icd2061.c' || echo '$(srcdir)/'`vid_icd2061.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-vid_icd2061.Tpo $(DEPDIR)/pcem-vid_icd2061.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='vid_icd2061.c' object='pcem-vid_icd2061.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_icd2061.o `test -f 'vid_icd2061.c' || echo '$(srcdir)/'`vid_icd2061.c - -pcem-vid_icd2061.obj: vid_icd2061.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vid_icd2061.obj -MD -MP -MF $(DEPDIR)/pcem-vid_icd2061.Tpo -c -o pcem-vid_icd2061.obj `if test -f 'vid_icd2061.c'; then $(CYGPATH_W) 'vid_icd2061.c'; else $(CYGPATH_W) '$(srcdir)/vid_icd2061.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-vid_icd2061.Tpo $(DEPDIR)/pcem-vid_icd2061.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='vid_icd2061.c' object='pcem-vid_icd2061.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_icd2061.obj `if test -f 'vid_icd2061.c'; then $(CYGPATH_W) 'vid_icd2061.c'; else $(CYGPATH_W) '$(srcdir)/vid_icd2061.c'; fi` - -pcem-vid_ics2595.o: vid_ics2595.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vid_ics2595.o -MD -MP -MF $(DEPDIR)/pcem-vid_ics2595.Tpo -c -o pcem-vid_ics2595.o `test -f 'vid_ics2595.c' || echo '$(srcdir)/'`vid_ics2595.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-vid_ics2595.Tpo $(DEPDIR)/pcem-vid_ics2595.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='vid_ics2595.c' object='pcem-vid_ics2595.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_ics2595.o `test -f 'vid_ics2595.c' || echo '$(srcdir)/'`vid_ics2595.c - -pcem-vid_ics2595.obj: vid_ics2595.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vid_ics2595.obj -MD -MP -MF $(DEPDIR)/pcem-vid_ics2595.Tpo -c -o pcem-vid_ics2595.obj `if test -f 'vid_ics2595.c'; then $(CYGPATH_W) 'vid_ics2595.c'; else $(CYGPATH_W) '$(srcdir)/vid_ics2595.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-vid_ics2595.Tpo $(DEPDIR)/pcem-vid_ics2595.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='vid_ics2595.c' object='pcem-vid_ics2595.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_ics2595.obj `if test -f 'vid_ics2595.c'; then $(CYGPATH_W) 'vid_ics2595.c'; else $(CYGPATH_W) '$(srcdir)/vid_ics2595.c'; fi` - -pcem-vid_mda.o: vid_mda.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vid_mda.o -MD -MP -MF $(DEPDIR)/pcem-vid_mda.Tpo -c -o pcem-vid_mda.o `test -f 'vid_mda.c' || echo '$(srcdir)/'`vid_mda.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-vid_mda.Tpo $(DEPDIR)/pcem-vid_mda.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='vid_mda.c' object='pcem-vid_mda.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_mda.o `test -f 'vid_mda.c' || echo '$(srcdir)/'`vid_mda.c - -pcem-vid_mda.obj: vid_mda.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vid_mda.obj -MD -MP -MF $(DEPDIR)/pcem-vid_mda.Tpo -c -o pcem-vid_mda.obj `if test -f 'vid_mda.c'; then $(CYGPATH_W) 'vid_mda.c'; else $(CYGPATH_W) '$(srcdir)/vid_mda.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-vid_mda.Tpo $(DEPDIR)/pcem-vid_mda.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='vid_mda.c' object='pcem-vid_mda.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_mda.obj `if test -f 'vid_mda.c'; then $(CYGPATH_W) 'vid_mda.c'; else $(CYGPATH_W) '$(srcdir)/vid_mda.c'; fi` - -pcem-vid_olivetti_m24.o: vid_olivetti_m24.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vid_olivetti_m24.o -MD -MP -MF $(DEPDIR)/pcem-vid_olivetti_m24.Tpo -c -o pcem-vid_olivetti_m24.o `test -f 'vid_olivetti_m24.c' || echo '$(srcdir)/'`vid_olivetti_m24.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-vid_olivetti_m24.Tpo $(DEPDIR)/pcem-vid_olivetti_m24.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='vid_olivetti_m24.c' object='pcem-vid_olivetti_m24.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_olivetti_m24.o `test -f 'vid_olivetti_m24.c' || echo '$(srcdir)/'`vid_olivetti_m24.c - -pcem-vid_olivetti_m24.obj: vid_olivetti_m24.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vid_olivetti_m24.obj -MD -MP -MF $(DEPDIR)/pcem-vid_olivetti_m24.Tpo -c -o pcem-vid_olivetti_m24.obj `if test -f 'vid_olivetti_m24.c'; then $(CYGPATH_W) 'vid_olivetti_m24.c'; else $(CYGPATH_W) '$(srcdir)/vid_olivetti_m24.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-vid_olivetti_m24.Tpo $(DEPDIR)/pcem-vid_olivetti_m24.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='vid_olivetti_m24.c' object='pcem-vid_olivetti_m24.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_olivetti_m24.obj `if test -f 'vid_olivetti_m24.c'; then $(CYGPATH_W) 'vid_olivetti_m24.c'; else $(CYGPATH_W) '$(srcdir)/vid_olivetti_m24.c'; fi` - -pcem-vid_oti067.o: vid_oti067.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vid_oti067.o -MD -MP -MF $(DEPDIR)/pcem-vid_oti067.Tpo -c -o pcem-vid_oti067.o `test -f 'vid_oti067.c' || echo '$(srcdir)/'`vid_oti067.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-vid_oti067.Tpo $(DEPDIR)/pcem-vid_oti067.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='vid_oti067.c' object='pcem-vid_oti067.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_oti067.o `test -f 'vid_oti067.c' || echo '$(srcdir)/'`vid_oti067.c - -pcem-vid_oti067.obj: vid_oti067.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vid_oti067.obj -MD -MP -MF $(DEPDIR)/pcem-vid_oti067.Tpo -c -o pcem-vid_oti067.obj `if test -f 'vid_oti067.c'; then $(CYGPATH_W) 'vid_oti067.c'; else $(CYGPATH_W) '$(srcdir)/vid_oti067.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-vid_oti067.Tpo $(DEPDIR)/pcem-vid_oti067.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='vid_oti067.c' object='pcem-vid_oti067.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_oti067.obj `if test -f 'vid_oti067.c'; then $(CYGPATH_W) 'vid_oti067.c'; else $(CYGPATH_W) '$(srcdir)/vid_oti067.c'; fi` - -pcem-vid_paradise.o: vid_paradise.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vid_paradise.o -MD -MP -MF $(DEPDIR)/pcem-vid_paradise.Tpo -c -o pcem-vid_paradise.o `test -f 'vid_paradise.c' || echo '$(srcdir)/'`vid_paradise.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-vid_paradise.Tpo $(DEPDIR)/pcem-vid_paradise.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='vid_paradise.c' object='pcem-vid_paradise.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_paradise.o `test -f 'vid_paradise.c' || echo '$(srcdir)/'`vid_paradise.c - -pcem-vid_paradise.obj: vid_paradise.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vid_paradise.obj -MD -MP -MF $(DEPDIR)/pcem-vid_paradise.Tpo -c -o pcem-vid_paradise.obj `if test -f 'vid_paradise.c'; then $(CYGPATH_W) 'vid_paradise.c'; else $(CYGPATH_W) '$(srcdir)/vid_paradise.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-vid_paradise.Tpo $(DEPDIR)/pcem-vid_paradise.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='vid_paradise.c' object='pcem-vid_paradise.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_paradise.obj `if test -f 'vid_paradise.c'; then $(CYGPATH_W) 'vid_paradise.c'; else $(CYGPATH_W) '$(srcdir)/vid_paradise.c'; fi` - -pcem-vid_pc200.o: vid_pc200.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vid_pc200.o -MD -MP -MF $(DEPDIR)/pcem-vid_pc200.Tpo -c -o pcem-vid_pc200.o `test -f 'vid_pc200.c' || echo '$(srcdir)/'`vid_pc200.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-vid_pc200.Tpo $(DEPDIR)/pcem-vid_pc200.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='vid_pc200.c' object='pcem-vid_pc200.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_pc200.o `test -f 'vid_pc200.c' || echo '$(srcdir)/'`vid_pc200.c - -pcem-vid_pc200.obj: vid_pc200.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vid_pc200.obj -MD -MP -MF $(DEPDIR)/pcem-vid_pc200.Tpo -c -o pcem-vid_pc200.obj `if test -f 'vid_pc200.c'; then $(CYGPATH_W) 'vid_pc200.c'; else $(CYGPATH_W) '$(srcdir)/vid_pc200.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-vid_pc200.Tpo $(DEPDIR)/pcem-vid_pc200.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='vid_pc200.c' object='pcem-vid_pc200.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_pc200.obj `if test -f 'vid_pc200.c'; then $(CYGPATH_W) 'vid_pc200.c'; else $(CYGPATH_W) '$(srcdir)/vid_pc200.c'; fi` - -pcem-vid_pc1512.o: vid_pc1512.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vid_pc1512.o -MD -MP -MF $(DEPDIR)/pcem-vid_pc1512.Tpo -c -o pcem-vid_pc1512.o `test -f 'vid_pc1512.c' || echo '$(srcdir)/'`vid_pc1512.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-vid_pc1512.Tpo $(DEPDIR)/pcem-vid_pc1512.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='vid_pc1512.c' object='pcem-vid_pc1512.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_pc1512.o `test -f 'vid_pc1512.c' || echo '$(srcdir)/'`vid_pc1512.c - -pcem-vid_pc1512.obj: vid_pc1512.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vid_pc1512.obj -MD -MP -MF $(DEPDIR)/pcem-vid_pc1512.Tpo -c -o pcem-vid_pc1512.obj `if test -f 'vid_pc1512.c'; then $(CYGPATH_W) 'vid_pc1512.c'; else $(CYGPATH_W) '$(srcdir)/vid_pc1512.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-vid_pc1512.Tpo $(DEPDIR)/pcem-vid_pc1512.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='vid_pc1512.c' object='pcem-vid_pc1512.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_pc1512.obj `if test -f 'vid_pc1512.c'; then $(CYGPATH_W) 'vid_pc1512.c'; else $(CYGPATH_W) '$(srcdir)/vid_pc1512.c'; fi` - -pcem-vid_pc1640.o: vid_pc1640.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vid_pc1640.o -MD -MP -MF $(DEPDIR)/pcem-vid_pc1640.Tpo -c -o pcem-vid_pc1640.o `test -f 'vid_pc1640.c' || echo '$(srcdir)/'`vid_pc1640.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-vid_pc1640.Tpo $(DEPDIR)/pcem-vid_pc1640.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='vid_pc1640.c' object='pcem-vid_pc1640.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_pc1640.o `test -f 'vid_pc1640.c' || echo '$(srcdir)/'`vid_pc1640.c - -pcem-vid_pc1640.obj: vid_pc1640.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vid_pc1640.obj -MD -MP -MF $(DEPDIR)/pcem-vid_pc1640.Tpo -c -o pcem-vid_pc1640.obj `if test -f 'vid_pc1640.c'; then $(CYGPATH_W) 'vid_pc1640.c'; else $(CYGPATH_W) '$(srcdir)/vid_pc1640.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-vid_pc1640.Tpo $(DEPDIR)/pcem-vid_pc1640.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='vid_pc1640.c' object='pcem-vid_pc1640.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_pc1640.obj `if test -f 'vid_pc1640.c'; then $(CYGPATH_W) 'vid_pc1640.c'; else $(CYGPATH_W) '$(srcdir)/vid_pc1640.c'; fi` - -pcem-vid_pcjr.o: vid_pcjr.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vid_pcjr.o -MD -MP -MF $(DEPDIR)/pcem-vid_pcjr.Tpo -c -o pcem-vid_pcjr.o `test -f 'vid_pcjr.c' || echo '$(srcdir)/'`vid_pcjr.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-vid_pcjr.Tpo $(DEPDIR)/pcem-vid_pcjr.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='vid_pcjr.c' object='pcem-vid_pcjr.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_pcjr.o `test -f 'vid_pcjr.c' || echo '$(srcdir)/'`vid_pcjr.c - -pcem-vid_pcjr.obj: vid_pcjr.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vid_pcjr.obj -MD -MP -MF $(DEPDIR)/pcem-vid_pcjr.Tpo -c -o pcem-vid_pcjr.obj `if test -f 'vid_pcjr.c'; then $(CYGPATH_W) 'vid_pcjr.c'; else $(CYGPATH_W) '$(srcdir)/vid_pcjr.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-vid_pcjr.Tpo $(DEPDIR)/pcem-vid_pcjr.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='vid_pcjr.c' object='pcem-vid_pcjr.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_pcjr.obj `if test -f 'vid_pcjr.c'; then $(CYGPATH_W) 'vid_pcjr.c'; else $(CYGPATH_W) '$(srcdir)/vid_pcjr.c'; fi` - -pcem-vid_s3.o: vid_s3.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vid_s3.o -MD -MP -MF $(DEPDIR)/pcem-vid_s3.Tpo -c -o pcem-vid_s3.o `test -f 'vid_s3.c' || echo '$(srcdir)/'`vid_s3.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-vid_s3.Tpo $(DEPDIR)/pcem-vid_s3.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='vid_s3.c' object='pcem-vid_s3.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_s3.o `test -f 'vid_s3.c' || echo '$(srcdir)/'`vid_s3.c - -pcem-vid_s3.obj: vid_s3.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vid_s3.obj -MD -MP -MF $(DEPDIR)/pcem-vid_s3.Tpo -c -o pcem-vid_s3.obj `if test -f 'vid_s3.c'; then $(CYGPATH_W) 'vid_s3.c'; else $(CYGPATH_W) '$(srcdir)/vid_s3.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-vid_s3.Tpo $(DEPDIR)/pcem-vid_s3.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='vid_s3.c' object='pcem-vid_s3.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_s3.obj `if test -f 'vid_s3.c'; then $(CYGPATH_W) 'vid_s3.c'; else $(CYGPATH_W) '$(srcdir)/vid_s3.c'; fi` - -pcem-vid_s3_virge.o: vid_s3_virge.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vid_s3_virge.o -MD -MP -MF $(DEPDIR)/pcem-vid_s3_virge.Tpo -c -o pcem-vid_s3_virge.o `test -f 'vid_s3_virge.c' || echo '$(srcdir)/'`vid_s3_virge.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-vid_s3_virge.Tpo $(DEPDIR)/pcem-vid_s3_virge.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='vid_s3_virge.c' object='pcem-vid_s3_virge.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_s3_virge.o `test -f 'vid_s3_virge.c' || echo '$(srcdir)/'`vid_s3_virge.c - -pcem-vid_s3_virge.obj: vid_s3_virge.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vid_s3_virge.obj -MD -MP -MF $(DEPDIR)/pcem-vid_s3_virge.Tpo -c -o pcem-vid_s3_virge.obj `if test -f 'vid_s3_virge.c'; then $(CYGPATH_W) 'vid_s3_virge.c'; else $(CYGPATH_W) '$(srcdir)/vid_s3_virge.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-vid_s3_virge.Tpo $(DEPDIR)/pcem-vid_s3_virge.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='vid_s3_virge.c' object='pcem-vid_s3_virge.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_s3_virge.obj `if test -f 'vid_s3_virge.c'; then $(CYGPATH_W) 'vid_s3_virge.c'; else $(CYGPATH_W) '$(srcdir)/vid_s3_virge.c'; fi` - -pcem-vid_sdac_ramdac.o: vid_sdac_ramdac.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vid_sdac_ramdac.o -MD -MP -MF $(DEPDIR)/pcem-vid_sdac_ramdac.Tpo -c -o pcem-vid_sdac_ramdac.o `test -f 'vid_sdac_ramdac.c' || echo '$(srcdir)/'`vid_sdac_ramdac.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-vid_sdac_ramdac.Tpo $(DEPDIR)/pcem-vid_sdac_ramdac.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='vid_sdac_ramdac.c' object='pcem-vid_sdac_ramdac.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_sdac_ramdac.o `test -f 'vid_sdac_ramdac.c' || echo '$(srcdir)/'`vid_sdac_ramdac.c - -pcem-vid_sdac_ramdac.obj: vid_sdac_ramdac.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vid_sdac_ramdac.obj -MD -MP -MF $(DEPDIR)/pcem-vid_sdac_ramdac.Tpo -c -o pcem-vid_sdac_ramdac.obj `if test -f 'vid_sdac_ramdac.c'; then $(CYGPATH_W) 'vid_sdac_ramdac.c'; else $(CYGPATH_W) '$(srcdir)/vid_sdac_ramdac.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-vid_sdac_ramdac.Tpo $(DEPDIR)/pcem-vid_sdac_ramdac.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='vid_sdac_ramdac.c' object='pcem-vid_sdac_ramdac.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_sdac_ramdac.obj `if test -f 'vid_sdac_ramdac.c'; then $(CYGPATH_W) 'vid_sdac_ramdac.c'; else $(CYGPATH_W) '$(srcdir)/vid_sdac_ramdac.c'; fi` - -pcem-vid_stg_ramdac.o: vid_stg_ramdac.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vid_stg_ramdac.o -MD -MP -MF $(DEPDIR)/pcem-vid_stg_ramdac.Tpo -c -o pcem-vid_stg_ramdac.o `test -f 'vid_stg_ramdac.c' || echo '$(srcdir)/'`vid_stg_ramdac.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-vid_stg_ramdac.Tpo $(DEPDIR)/pcem-vid_stg_ramdac.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='vid_stg_ramdac.c' object='pcem-vid_stg_ramdac.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_stg_ramdac.o `test -f 'vid_stg_ramdac.c' || echo '$(srcdir)/'`vid_stg_ramdac.c - -pcem-vid_stg_ramdac.obj: vid_stg_ramdac.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vid_stg_ramdac.obj -MD -MP -MF $(DEPDIR)/pcem-vid_stg_ramdac.Tpo -c -o pcem-vid_stg_ramdac.obj `if test -f 'vid_stg_ramdac.c'; then $(CYGPATH_W) 'vid_stg_ramdac.c'; else $(CYGPATH_W) '$(srcdir)/vid_stg_ramdac.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-vid_stg_ramdac.Tpo $(DEPDIR)/pcem-vid_stg_ramdac.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='vid_stg_ramdac.c' object='pcem-vid_stg_ramdac.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_stg_ramdac.obj `if test -f 'vid_stg_ramdac.c'; then $(CYGPATH_W) 'vid_stg_ramdac.c'; else $(CYGPATH_W) '$(srcdir)/vid_stg_ramdac.c'; fi` - -pcem-vid_svga.o: vid_svga.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vid_svga.o -MD -MP -MF $(DEPDIR)/pcem-vid_svga.Tpo -c -o pcem-vid_svga.o `test -f 'vid_svga.c' || echo '$(srcdir)/'`vid_svga.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-vid_svga.Tpo $(DEPDIR)/pcem-vid_svga.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='vid_svga.c' object='pcem-vid_svga.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_svga.o `test -f 'vid_svga.c' || echo '$(srcdir)/'`vid_svga.c - -pcem-vid_svga.obj: vid_svga.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vid_svga.obj -MD -MP -MF $(DEPDIR)/pcem-vid_svga.Tpo -c -o pcem-vid_svga.obj `if test -f 'vid_svga.c'; then $(CYGPATH_W) 'vid_svga.c'; else $(CYGPATH_W) '$(srcdir)/vid_svga.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-vid_svga.Tpo $(DEPDIR)/pcem-vid_svga.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='vid_svga.c' object='pcem-vid_svga.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_svga.obj `if test -f 'vid_svga.c'; then $(CYGPATH_W) 'vid_svga.c'; else $(CYGPATH_W) '$(srcdir)/vid_svga.c'; fi` - -pcem-vid_svga_render.o: vid_svga_render.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vid_svga_render.o -MD -MP -MF $(DEPDIR)/pcem-vid_svga_render.Tpo -c -o pcem-vid_svga_render.o `test -f 'vid_svga_render.c' || echo '$(srcdir)/'`vid_svga_render.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-vid_svga_render.Tpo $(DEPDIR)/pcem-vid_svga_render.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='vid_svga_render.c' object='pcem-vid_svga_render.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_svga_render.o `test -f 'vid_svga_render.c' || echo '$(srcdir)/'`vid_svga_render.c - -pcem-vid_svga_render.obj: vid_svga_render.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vid_svga_render.obj -MD -MP -MF $(DEPDIR)/pcem-vid_svga_render.Tpo -c -o pcem-vid_svga_render.obj `if test -f 'vid_svga_render.c'; then $(CYGPATH_W) 'vid_svga_render.c'; else $(CYGPATH_W) '$(srcdir)/vid_svga_render.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-vid_svga_render.Tpo $(DEPDIR)/pcem-vid_svga_render.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='vid_svga_render.c' object='pcem-vid_svga_render.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_svga_render.obj `if test -f 'vid_svga_render.c'; then $(CYGPATH_W) 'vid_svga_render.c'; else $(CYGPATH_W) '$(srcdir)/vid_svga_render.c'; fi` - -pcem-vid_tandy.o: vid_tandy.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vid_tandy.o -MD -MP -MF $(DEPDIR)/pcem-vid_tandy.Tpo -c -o pcem-vid_tandy.o `test -f 'vid_tandy.c' || echo '$(srcdir)/'`vid_tandy.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-vid_tandy.Tpo $(DEPDIR)/pcem-vid_tandy.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='vid_tandy.c' object='pcem-vid_tandy.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_tandy.o `test -f 'vid_tandy.c' || echo '$(srcdir)/'`vid_tandy.c - -pcem-vid_tandy.obj: vid_tandy.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vid_tandy.obj -MD -MP -MF $(DEPDIR)/pcem-vid_tandy.Tpo -c -o pcem-vid_tandy.obj `if test -f 'vid_tandy.c'; then $(CYGPATH_W) 'vid_tandy.c'; else $(CYGPATH_W) '$(srcdir)/vid_tandy.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-vid_tandy.Tpo $(DEPDIR)/pcem-vid_tandy.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='vid_tandy.c' object='pcem-vid_tandy.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_tandy.obj `if test -f 'vid_tandy.c'; then $(CYGPATH_W) 'vid_tandy.c'; else $(CYGPATH_W) '$(srcdir)/vid_tandy.c'; fi` - -pcem-vid_tgui9440.o: vid_tgui9440.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vid_tgui9440.o -MD -MP -MF $(DEPDIR)/pcem-vid_tgui9440.Tpo -c -o pcem-vid_tgui9440.o `test -f 'vid_tgui9440.c' || echo '$(srcdir)/'`vid_tgui9440.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-vid_tgui9440.Tpo $(DEPDIR)/pcem-vid_tgui9440.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='vid_tgui9440.c' object='pcem-vid_tgui9440.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_tgui9440.o `test -f 'vid_tgui9440.c' || echo '$(srcdir)/'`vid_tgui9440.c - -pcem-vid_tgui9440.obj: vid_tgui9440.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vid_tgui9440.obj -MD -MP -MF $(DEPDIR)/pcem-vid_tgui9440.Tpo -c -o pcem-vid_tgui9440.obj `if test -f 'vid_tgui9440.c'; then $(CYGPATH_W) 'vid_tgui9440.c'; else $(CYGPATH_W) '$(srcdir)/vid_tgui9440.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-vid_tgui9440.Tpo $(DEPDIR)/pcem-vid_tgui9440.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='vid_tgui9440.c' object='pcem-vid_tgui9440.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_tgui9440.obj `if test -f 'vid_tgui9440.c'; then $(CYGPATH_W) 'vid_tgui9440.c'; else $(CYGPATH_W) '$(srcdir)/vid_tgui9440.c'; fi` - -pcem-vid_tkd8001_ramdac.o: vid_tkd8001_ramdac.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vid_tkd8001_ramdac.o -MD -MP -MF $(DEPDIR)/pcem-vid_tkd8001_ramdac.Tpo -c -o pcem-vid_tkd8001_ramdac.o `test -f 'vid_tkd8001_ramdac.c' || echo '$(srcdir)/'`vid_tkd8001_ramdac.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-vid_tkd8001_ramdac.Tpo $(DEPDIR)/pcem-vid_tkd8001_ramdac.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='vid_tkd8001_ramdac.c' object='pcem-vid_tkd8001_ramdac.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_tkd8001_ramdac.o `test -f 'vid_tkd8001_ramdac.c' || echo '$(srcdir)/'`vid_tkd8001_ramdac.c - -pcem-vid_tkd8001_ramdac.obj: vid_tkd8001_ramdac.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vid_tkd8001_ramdac.obj -MD -MP -MF $(DEPDIR)/pcem-vid_tkd8001_ramdac.Tpo -c -o pcem-vid_tkd8001_ramdac.obj `if test -f 'vid_tkd8001_ramdac.c'; then $(CYGPATH_W) 'vid_tkd8001_ramdac.c'; else $(CYGPATH_W) '$(srcdir)/vid_tkd8001_ramdac.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-vid_tkd8001_ramdac.Tpo $(DEPDIR)/pcem-vid_tkd8001_ramdac.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='vid_tkd8001_ramdac.c' object='pcem-vid_tkd8001_ramdac.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_tkd8001_ramdac.obj `if test -f 'vid_tkd8001_ramdac.c'; then $(CYGPATH_W) 'vid_tkd8001_ramdac.c'; else $(CYGPATH_W) '$(srcdir)/vid_tkd8001_ramdac.c'; fi` - -pcem-vid_tvga.o: vid_tvga.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vid_tvga.o -MD -MP -MF $(DEPDIR)/pcem-vid_tvga.Tpo -c -o pcem-vid_tvga.o `test -f 'vid_tvga.c' || echo '$(srcdir)/'`vid_tvga.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-vid_tvga.Tpo $(DEPDIR)/pcem-vid_tvga.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='vid_tvga.c' object='pcem-vid_tvga.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_tvga.o `test -f 'vid_tvga.c' || echo '$(srcdir)/'`vid_tvga.c - -pcem-vid_tvga.obj: vid_tvga.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vid_tvga.obj -MD -MP -MF $(DEPDIR)/pcem-vid_tvga.Tpo -c -o pcem-vid_tvga.obj `if test -f 'vid_tvga.c'; then $(CYGPATH_W) 'vid_tvga.c'; else $(CYGPATH_W) '$(srcdir)/vid_tvga.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-vid_tvga.Tpo $(DEPDIR)/pcem-vid_tvga.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='vid_tvga.c' object='pcem-vid_tvga.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_tvga.obj `if test -f 'vid_tvga.c'; then $(CYGPATH_W) 'vid_tvga.c'; else $(CYGPATH_W) '$(srcdir)/vid_tvga.c'; fi` - -pcem-vid_unk_ramdac.o: vid_unk_ramdac.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vid_unk_ramdac.o -MD -MP -MF $(DEPDIR)/pcem-vid_unk_ramdac.Tpo -c -o pcem-vid_unk_ramdac.o `test -f 'vid_unk_ramdac.c' || echo '$(srcdir)/'`vid_unk_ramdac.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-vid_unk_ramdac.Tpo $(DEPDIR)/pcem-vid_unk_ramdac.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='vid_unk_ramdac.c' object='pcem-vid_unk_ramdac.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_unk_ramdac.o `test -f 'vid_unk_ramdac.c' || echo '$(srcdir)/'`vid_unk_ramdac.c - -pcem-vid_unk_ramdac.obj: vid_unk_ramdac.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vid_unk_ramdac.obj -MD -MP -MF $(DEPDIR)/pcem-vid_unk_ramdac.Tpo -c -o pcem-vid_unk_ramdac.obj `if test -f 'vid_unk_ramdac.c'; then $(CYGPATH_W) 'vid_unk_ramdac.c'; else $(CYGPATH_W) '$(srcdir)/vid_unk_ramdac.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-vid_unk_ramdac.Tpo $(DEPDIR)/pcem-vid_unk_ramdac.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='vid_unk_ramdac.c' object='pcem-vid_unk_ramdac.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_unk_ramdac.obj `if test -f 'vid_unk_ramdac.c'; then $(CYGPATH_W) 'vid_unk_ramdac.c'; else $(CYGPATH_W) '$(srcdir)/vid_unk_ramdac.c'; fi` - -pcem-vid_vga.o: vid_vga.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vid_vga.o -MD -MP -MF $(DEPDIR)/pcem-vid_vga.Tpo -c -o pcem-vid_vga.o `test -f 'vid_vga.c' || echo '$(srcdir)/'`vid_vga.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-vid_vga.Tpo $(DEPDIR)/pcem-vid_vga.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='vid_vga.c' object='pcem-vid_vga.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_vga.o `test -f 'vid_vga.c' || echo '$(srcdir)/'`vid_vga.c - -pcem-vid_vga.obj: vid_vga.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vid_vga.obj -MD -MP -MF $(DEPDIR)/pcem-vid_vga.Tpo -c -o pcem-vid_vga.obj `if test -f 'vid_vga.c'; then $(CYGPATH_W) 'vid_vga.c'; else $(CYGPATH_W) '$(srcdir)/vid_vga.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-vid_vga.Tpo $(DEPDIR)/pcem-vid_vga.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='vid_vga.c' object='pcem-vid_vga.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_vga.obj `if test -f 'vid_vga.c'; then $(CYGPATH_W) 'vid_vga.c'; else $(CYGPATH_W) '$(srcdir)/vid_vga.c'; fi` - -pcem-vid_voodoo.o: vid_voodoo.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vid_voodoo.o -MD -MP -MF $(DEPDIR)/pcem-vid_voodoo.Tpo -c -o pcem-vid_voodoo.o `test -f 'vid_voodoo.c' || echo '$(srcdir)/'`vid_voodoo.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-vid_voodoo.Tpo $(DEPDIR)/pcem-vid_voodoo.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='vid_voodoo.c' object='pcem-vid_voodoo.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_voodoo.o `test -f 'vid_voodoo.c' || echo '$(srcdir)/'`vid_voodoo.c - -pcem-vid_voodoo.obj: vid_voodoo.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vid_voodoo.obj -MD -MP -MF $(DEPDIR)/pcem-vid_voodoo.Tpo -c -o pcem-vid_voodoo.obj `if test -f 'vid_voodoo.c'; then $(CYGPATH_W) 'vid_voodoo.c'; else $(CYGPATH_W) '$(srcdir)/vid_voodoo.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-vid_voodoo.Tpo $(DEPDIR)/pcem-vid_voodoo.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='vid_voodoo.c' object='pcem-vid_voodoo.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_voodoo.obj `if test -f 'vid_voodoo.c'; then $(CYGPATH_W) 'vid_voodoo.c'; else $(CYGPATH_W) '$(srcdir)/vid_voodoo.c'; fi` - -pcem-video.o: video.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-video.o -MD -MP -MF $(DEPDIR)/pcem-video.Tpo -c -o pcem-video.o `test -f 'video.c' || echo '$(srcdir)/'`video.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-video.Tpo $(DEPDIR)/pcem-video.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='video.c' object='pcem-video.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-video.o `test -f 'video.c' || echo '$(srcdir)/'`video.c - -pcem-video.obj: video.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-video.obj -MD -MP -MF $(DEPDIR)/pcem-video.Tpo -c -o pcem-video.obj `if test -f 'video.c'; then $(CYGPATH_W) 'video.c'; else $(CYGPATH_W) '$(srcdir)/video.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-video.Tpo $(DEPDIR)/pcem-video.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='video.c' object='pcem-video.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-video.obj `if test -f 'video.c'; then $(CYGPATH_W) 'video.c'; else $(CYGPATH_W) '$(srcdir)/video.c'; fi` - -pcem-wd76c10.o: wd76c10.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-wd76c10.o -MD -MP -MF $(DEPDIR)/pcem-wd76c10.Tpo -c -o pcem-wd76c10.o `test -f 'wd76c10.c' || echo '$(srcdir)/'`wd76c10.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-wd76c10.Tpo $(DEPDIR)/pcem-wd76c10.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='wd76c10.c' object='pcem-wd76c10.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-wd76c10.o `test -f 'wd76c10.c' || echo '$(srcdir)/'`wd76c10.c - -pcem-wd76c10.obj: wd76c10.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-wd76c10.obj -MD -MP -MF $(DEPDIR)/pcem-wd76c10.Tpo -c -o pcem-wd76c10.obj `if test -f 'wd76c10.c'; then $(CYGPATH_W) 'wd76c10.c'; else $(CYGPATH_W) '$(srcdir)/wd76c10.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-wd76c10.Tpo $(DEPDIR)/pcem-wd76c10.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='wd76c10.c' object='pcem-wd76c10.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-wd76c10.obj `if test -f 'wd76c10.c'; then $(CYGPATH_W) 'wd76c10.c'; else $(CYGPATH_W) '$(srcdir)/wd76c10.c'; fi` - -pcem-x86seg.o: x86seg.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-x86seg.o -MD -MP -MF $(DEPDIR)/pcem-x86seg.Tpo -c -o pcem-x86seg.o `test -f 'x86seg.c' || echo '$(srcdir)/'`x86seg.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-x86seg.Tpo $(DEPDIR)/pcem-x86seg.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='x86seg.c' object='pcem-x86seg.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-x86seg.o `test -f 'x86seg.c' || echo '$(srcdir)/'`x86seg.c - -pcem-x86seg.obj: x86seg.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-x86seg.obj -MD -MP -MF $(DEPDIR)/pcem-x86seg.Tpo -c -o pcem-x86seg.obj `if test -f 'x86seg.c'; then $(CYGPATH_W) 'x86seg.c'; else $(CYGPATH_W) '$(srcdir)/x86seg.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-x86seg.Tpo $(DEPDIR)/pcem-x86seg.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='x86seg.c' object='pcem-x86seg.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-x86seg.obj `if test -f 'x86seg.c'; then $(CYGPATH_W) 'x86seg.c'; else $(CYGPATH_W) '$(srcdir)/x86seg.c'; fi` - -pcem-x87.o: x87.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-x87.o -MD -MP -MF $(DEPDIR)/pcem-x87.Tpo -c -o pcem-x87.o `test -f 'x87.c' || echo '$(srcdir)/'`x87.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-x87.Tpo $(DEPDIR)/pcem-x87.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='x87.c' object='pcem-x87.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-x87.o `test -f 'x87.c' || echo '$(srcdir)/'`x87.c - -pcem-x87.obj: x87.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-x87.obj -MD -MP -MF $(DEPDIR)/pcem-x87.Tpo -c -o pcem-x87.obj `if test -f 'x87.c'; then $(CYGPATH_W) 'x87.c'; else $(CYGPATH_W) '$(srcdir)/x87.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-x87.Tpo $(DEPDIR)/pcem-x87.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='x87.c' object='pcem-x87.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-x87.obj `if test -f 'x87.c'; then $(CYGPATH_W) 'x87.c'; else $(CYGPATH_W) '$(srcdir)/x87.c'; fi` - -pcem-xtide.o: xtide.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-xtide.o -MD -MP -MF $(DEPDIR)/pcem-xtide.Tpo -c -o pcem-xtide.o `test -f 'xtide.c' || echo '$(srcdir)/'`xtide.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-xtide.Tpo $(DEPDIR)/pcem-xtide.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='xtide.c' object='pcem-xtide.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-xtide.o `test -f 'xtide.c' || echo '$(srcdir)/'`xtide.c - -pcem-xtide.obj: xtide.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-xtide.obj -MD -MP -MF $(DEPDIR)/pcem-xtide.Tpo -c -o pcem-xtide.obj `if test -f 'xtide.c'; then $(CYGPATH_W) 'xtide.c'; else $(CYGPATH_W) '$(srcdir)/xtide.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-xtide.Tpo $(DEPDIR)/pcem-xtide.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='xtide.c' object='pcem-xtide.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-xtide.obj `if test -f 'xtide.c'; then $(CYGPATH_W) 'xtide.c'; else $(CYGPATH_W) '$(srcdir)/xtide.c'; fi` - -pcem-codegen_x86.o: codegen_x86.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-codegen_x86.o -MD -MP -MF $(DEPDIR)/pcem-codegen_x86.Tpo -c -o pcem-codegen_x86.o `test -f 'codegen_x86.c' || echo '$(srcdir)/'`codegen_x86.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-codegen_x86.Tpo $(DEPDIR)/pcem-codegen_x86.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='codegen_x86.c' object='pcem-codegen_x86.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-codegen_x86.o `test -f 'codegen_x86.c' || echo '$(srcdir)/'`codegen_x86.c - -pcem-codegen_x86.obj: codegen_x86.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-codegen_x86.obj -MD -MP -MF $(DEPDIR)/pcem-codegen_x86.Tpo -c -o pcem-codegen_x86.obj `if test -f 'codegen_x86.c'; then $(CYGPATH_W) 'codegen_x86.c'; else $(CYGPATH_W) '$(srcdir)/codegen_x86.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-codegen_x86.Tpo $(DEPDIR)/pcem-codegen_x86.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='codegen_x86.c' object='pcem-codegen_x86.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-codegen_x86.obj `if test -f 'codegen_x86.c'; then $(CYGPATH_W) 'codegen_x86.c'; else $(CYGPATH_W) '$(srcdir)/codegen_x86.c'; fi` - -pcem-codegen_x86-64.o: codegen_x86-64.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-codegen_x86-64.o -MD -MP -MF $(DEPDIR)/pcem-codegen_x86-64.Tpo -c -o pcem-codegen_x86-64.o `test -f 'codegen_x86-64.c' || echo '$(srcdir)/'`codegen_x86-64.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-codegen_x86-64.Tpo $(DEPDIR)/pcem-codegen_x86-64.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='codegen_x86-64.c' object='pcem-codegen_x86-64.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-codegen_x86-64.o `test -f 'codegen_x86-64.c' || echo '$(srcdir)/'`codegen_x86-64.c - -pcem-codegen_x86-64.obj: codegen_x86-64.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-codegen_x86-64.obj -MD -MP -MF $(DEPDIR)/pcem-codegen_x86-64.Tpo -c -o pcem-codegen_x86-64.obj `if test -f 'codegen_x86-64.c'; then $(CYGPATH_W) 'codegen_x86-64.c'; else $(CYGPATH_W) '$(srcdir)/codegen_x86-64.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pcem-codegen_x86-64.Tpo $(DEPDIR)/pcem-codegen_x86-64.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='codegen_x86-64.c' object='pcem-codegen_x86-64.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-codegen_x86-64.obj `if test -f 'codegen_x86-64.c'; then $(CYGPATH_W) 'codegen_x86-64.c'; else $(CYGPATH_W) '$(srcdir)/codegen_x86-64.c'; fi` - -.cc.o: -@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ $< - -.cc.obj: -@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` - -dbopl.o: dosbox/dbopl.cpp -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT dbopl.o -MD -MP -MF $(DEPDIR)/dbopl.Tpo -c -o dbopl.o `test -f 'dosbox/dbopl.cpp' || echo '$(srcdir)/'`dosbox/dbopl.cpp -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/dbopl.Tpo $(DEPDIR)/dbopl.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='dosbox/dbopl.cpp' object='dbopl.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o dbopl.o `test -f 'dosbox/dbopl.cpp' || echo '$(srcdir)/'`dosbox/dbopl.cpp - -dbopl.obj: dosbox/dbopl.cpp -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT dbopl.obj -MD -MP -MF $(DEPDIR)/dbopl.Tpo -c -o dbopl.obj `if test -f 'dosbox/dbopl.cpp'; then $(CYGPATH_W) 'dosbox/dbopl.cpp'; else $(CYGPATH_W) '$(srcdir)/dosbox/dbopl.cpp'; fi` -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/dbopl.Tpo $(DEPDIR)/dbopl.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='dosbox/dbopl.cpp' object='dbopl.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o dbopl.obj `if test -f 'dosbox/dbopl.cpp'; then $(CYGPATH_W) 'dosbox/dbopl.cpp'; else $(CYGPATH_W) '$(srcdir)/dosbox/dbopl.cpp'; fi` - -convolve.o: resid-fp/convolve.cc -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT convolve.o -MD -MP -MF $(DEPDIR)/convolve.Tpo -c -o convolve.o `test -f 'resid-fp/convolve.cc' || echo '$(srcdir)/'`resid-fp/convolve.cc -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/convolve.Tpo $(DEPDIR)/convolve.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='resid-fp/convolve.cc' object='convolve.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o convolve.o `test -f 'resid-fp/convolve.cc' || echo '$(srcdir)/'`resid-fp/convolve.cc - -convolve.obj: resid-fp/convolve.cc -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT convolve.obj -MD -MP -MF $(DEPDIR)/convolve.Tpo -c -o convolve.obj `if test -f 'resid-fp/convolve.cc'; then $(CYGPATH_W) 'resid-fp/convolve.cc'; else $(CYGPATH_W) '$(srcdir)/resid-fp/convolve.cc'; fi` -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/convolve.Tpo $(DEPDIR)/convolve.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='resid-fp/convolve.cc' object='convolve.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o convolve.obj `if test -f 'resid-fp/convolve.cc'; then $(CYGPATH_W) 'resid-fp/convolve.cc'; else $(CYGPATH_W) '$(srcdir)/resid-fp/convolve.cc'; fi` - -convolve-sse.o: resid-fp/convolve-sse.cc -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT convolve-sse.o -MD -MP -MF $(DEPDIR)/convolve-sse.Tpo -c -o convolve-sse.o `test -f 'resid-fp/convolve-sse.cc' || echo '$(srcdir)/'`resid-fp/convolve-sse.cc -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/convolve-sse.Tpo $(DEPDIR)/convolve-sse.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='resid-fp/convolve-sse.cc' object='convolve-sse.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o convolve-sse.o `test -f 'resid-fp/convolve-sse.cc' || echo '$(srcdir)/'`resid-fp/convolve-sse.cc - -convolve-sse.obj: resid-fp/convolve-sse.cc -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT convolve-sse.obj -MD -MP -MF $(DEPDIR)/convolve-sse.Tpo -c -o convolve-sse.obj `if test -f 'resid-fp/convolve-sse.cc'; then $(CYGPATH_W) 'resid-fp/convolve-sse.cc'; else $(CYGPATH_W) '$(srcdir)/resid-fp/convolve-sse.cc'; fi` -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/convolve-sse.Tpo $(DEPDIR)/convolve-sse.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='resid-fp/convolve-sse.cc' object='convolve-sse.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o convolve-sse.obj `if test -f 'resid-fp/convolve-sse.cc'; then $(CYGPATH_W) 'resid-fp/convolve-sse.cc'; else $(CYGPATH_W) '$(srcdir)/resid-fp/convolve-sse.cc'; fi` - -envelope.o: resid-fp/envelope.cc -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT envelope.o -MD -MP -MF $(DEPDIR)/envelope.Tpo -c -o envelope.o `test -f 'resid-fp/envelope.cc' || echo '$(srcdir)/'`resid-fp/envelope.cc -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/envelope.Tpo $(DEPDIR)/envelope.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='resid-fp/envelope.cc' object='envelope.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o envelope.o `test -f 'resid-fp/envelope.cc' || echo '$(srcdir)/'`resid-fp/envelope.cc - -envelope.obj: resid-fp/envelope.cc -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT envelope.obj -MD -MP -MF $(DEPDIR)/envelope.Tpo -c -o envelope.obj `if test -f 'resid-fp/envelope.cc'; then $(CYGPATH_W) 'resid-fp/envelope.cc'; else $(CYGPATH_W) '$(srcdir)/resid-fp/envelope.cc'; fi` -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/envelope.Tpo $(DEPDIR)/envelope.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='resid-fp/envelope.cc' object='envelope.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o envelope.obj `if test -f 'resid-fp/envelope.cc'; then $(CYGPATH_W) 'resid-fp/envelope.cc'; else $(CYGPATH_W) '$(srcdir)/resid-fp/envelope.cc'; fi` - -extfilt.o: resid-fp/extfilt.cc -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT extfilt.o -MD -MP -MF $(DEPDIR)/extfilt.Tpo -c -o extfilt.o `test -f 'resid-fp/extfilt.cc' || echo '$(srcdir)/'`resid-fp/extfilt.cc -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/extfilt.Tpo $(DEPDIR)/extfilt.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='resid-fp/extfilt.cc' object='extfilt.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o extfilt.o `test -f 'resid-fp/extfilt.cc' || echo '$(srcdir)/'`resid-fp/extfilt.cc - -extfilt.obj: resid-fp/extfilt.cc -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT extfilt.obj -MD -MP -MF $(DEPDIR)/extfilt.Tpo -c -o extfilt.obj `if test -f 'resid-fp/extfilt.cc'; then $(CYGPATH_W) 'resid-fp/extfilt.cc'; else $(CYGPATH_W) '$(srcdir)/resid-fp/extfilt.cc'; fi` -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/extfilt.Tpo $(DEPDIR)/extfilt.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='resid-fp/extfilt.cc' object='extfilt.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o extfilt.obj `if test -f 'resid-fp/extfilt.cc'; then $(CYGPATH_W) 'resid-fp/extfilt.cc'; else $(CYGPATH_W) '$(srcdir)/resid-fp/extfilt.cc'; fi` - -filter.o: resid-fp/filter.cc -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT filter.o -MD -MP -MF $(DEPDIR)/filter.Tpo -c -o filter.o `test -f 'resid-fp/filter.cc' || echo '$(srcdir)/'`resid-fp/filter.cc -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/filter.Tpo $(DEPDIR)/filter.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='resid-fp/filter.cc' object='filter.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o filter.o `test -f 'resid-fp/filter.cc' || echo '$(srcdir)/'`resid-fp/filter.cc - -filter.obj: resid-fp/filter.cc -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT filter.obj -MD -MP -MF $(DEPDIR)/filter.Tpo -c -o filter.obj `if test -f 'resid-fp/filter.cc'; then $(CYGPATH_W) 'resid-fp/filter.cc'; else $(CYGPATH_W) '$(srcdir)/resid-fp/filter.cc'; fi` -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/filter.Tpo $(DEPDIR)/filter.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='resid-fp/filter.cc' object='filter.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o filter.obj `if test -f 'resid-fp/filter.cc'; then $(CYGPATH_W) 'resid-fp/filter.cc'; else $(CYGPATH_W) '$(srcdir)/resid-fp/filter.cc'; fi` - -pot.o: resid-fp/pot.cc -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT pot.o -MD -MP -MF $(DEPDIR)/pot.Tpo -c -o pot.o `test -f 'resid-fp/pot.cc' || echo '$(srcdir)/'`resid-fp/pot.cc -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/pot.Tpo $(DEPDIR)/pot.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='resid-fp/pot.cc' object='pot.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o pot.o `test -f 'resid-fp/pot.cc' || echo '$(srcdir)/'`resid-fp/pot.cc - -pot.obj: resid-fp/pot.cc -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT pot.obj -MD -MP -MF $(DEPDIR)/pot.Tpo -c -o pot.obj `if test -f 'resid-fp/pot.cc'; then $(CYGPATH_W) 'resid-fp/pot.cc'; else $(CYGPATH_W) '$(srcdir)/resid-fp/pot.cc'; fi` -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/pot.Tpo $(DEPDIR)/pot.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='resid-fp/pot.cc' object='pot.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o pot.obj `if test -f 'resid-fp/pot.cc'; then $(CYGPATH_W) 'resid-fp/pot.cc'; else $(CYGPATH_W) '$(srcdir)/resid-fp/pot.cc'; fi` - -sid.o: resid-fp/sid.cc -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT sid.o -MD -MP -MF $(DEPDIR)/sid.Tpo -c -o sid.o `test -f 'resid-fp/sid.cc' || echo '$(srcdir)/'`resid-fp/sid.cc -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/sid.Tpo $(DEPDIR)/sid.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='resid-fp/sid.cc' object='sid.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o sid.o `test -f 'resid-fp/sid.cc' || echo '$(srcdir)/'`resid-fp/sid.cc - -sid.obj: resid-fp/sid.cc -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT sid.obj -MD -MP -MF $(DEPDIR)/sid.Tpo -c -o sid.obj `if test -f 'resid-fp/sid.cc'; then $(CYGPATH_W) 'resid-fp/sid.cc'; else $(CYGPATH_W) '$(srcdir)/resid-fp/sid.cc'; fi` -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/sid.Tpo $(DEPDIR)/sid.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='resid-fp/sid.cc' object='sid.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o sid.obj `if test -f 'resid-fp/sid.cc'; then $(CYGPATH_W) 'resid-fp/sid.cc'; else $(CYGPATH_W) '$(srcdir)/resid-fp/sid.cc'; fi` - -voice.o: resid-fp/voice.cc -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT voice.o -MD -MP -MF $(DEPDIR)/voice.Tpo -c -o voice.o `test -f 'resid-fp/voice.cc' || echo '$(srcdir)/'`resid-fp/voice.cc -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/voice.Tpo $(DEPDIR)/voice.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='resid-fp/voice.cc' object='voice.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o voice.o `test -f 'resid-fp/voice.cc' || echo '$(srcdir)/'`resid-fp/voice.cc - -voice.obj: resid-fp/voice.cc -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT voice.obj -MD -MP -MF $(DEPDIR)/voice.Tpo -c -o voice.obj `if test -f 'resid-fp/voice.cc'; then $(CYGPATH_W) 'resid-fp/voice.cc'; else $(CYGPATH_W) '$(srcdir)/resid-fp/voice.cc'; fi` -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/voice.Tpo $(DEPDIR)/voice.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='resid-fp/voice.cc' object='voice.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o voice.obj `if test -f 'resid-fp/voice.cc'; then $(CYGPATH_W) 'resid-fp/voice.cc'; else $(CYGPATH_W) '$(srcdir)/resid-fp/voice.cc'; fi` - -wave6581_PS_.o: resid-fp/wave6581_PS_.cc -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT wave6581_PS_.o -MD -MP -MF $(DEPDIR)/wave6581_PS_.Tpo -c -o wave6581_PS_.o `test -f 'resid-fp/wave6581_PS_.cc' || echo '$(srcdir)/'`resid-fp/wave6581_PS_.cc -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/wave6581_PS_.Tpo $(DEPDIR)/wave6581_PS_.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='resid-fp/wave6581_PS_.cc' object='wave6581_PS_.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o wave6581_PS_.o `test -f 'resid-fp/wave6581_PS_.cc' || echo '$(srcdir)/'`resid-fp/wave6581_PS_.cc - -wave6581_PS_.obj: resid-fp/wave6581_PS_.cc -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT wave6581_PS_.obj -MD -MP -MF $(DEPDIR)/wave6581_PS_.Tpo -c -o wave6581_PS_.obj `if test -f 'resid-fp/wave6581_PS_.cc'; then $(CYGPATH_W) 'resid-fp/wave6581_PS_.cc'; else $(CYGPATH_W) '$(srcdir)/resid-fp/wave6581_PS_.cc'; fi` -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/wave6581_PS_.Tpo $(DEPDIR)/wave6581_PS_.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='resid-fp/wave6581_PS_.cc' object='wave6581_PS_.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o wave6581_PS_.obj `if test -f 'resid-fp/wave6581_PS_.cc'; then $(CYGPATH_W) 'resid-fp/wave6581_PS_.cc'; else $(CYGPATH_W) '$(srcdir)/resid-fp/wave6581_PS_.cc'; fi` - -wave6581_PST.o: resid-fp/wave6581_PST.cc -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT wave6581_PST.o -MD -MP -MF $(DEPDIR)/wave6581_PST.Tpo -c -o wave6581_PST.o `test -f 'resid-fp/wave6581_PST.cc' || echo '$(srcdir)/'`resid-fp/wave6581_PST.cc -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/wave6581_PST.Tpo $(DEPDIR)/wave6581_PST.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='resid-fp/wave6581_PST.cc' object='wave6581_PST.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o wave6581_PST.o `test -f 'resid-fp/wave6581_PST.cc' || echo '$(srcdir)/'`resid-fp/wave6581_PST.cc - -wave6581_PST.obj: resid-fp/wave6581_PST.cc -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT wave6581_PST.obj -MD -MP -MF $(DEPDIR)/wave6581_PST.Tpo -c -o wave6581_PST.obj `if test -f 'resid-fp/wave6581_PST.cc'; then $(CYGPATH_W) 'resid-fp/wave6581_PST.cc'; else $(CYGPATH_W) '$(srcdir)/resid-fp/wave6581_PST.cc'; fi` -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/wave6581_PST.Tpo $(DEPDIR)/wave6581_PST.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='resid-fp/wave6581_PST.cc' object='wave6581_PST.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o wave6581_PST.obj `if test -f 'resid-fp/wave6581_PST.cc'; then $(CYGPATH_W) 'resid-fp/wave6581_PST.cc'; else $(CYGPATH_W) '$(srcdir)/resid-fp/wave6581_PST.cc'; fi` - -wave6581_P_T.o: resid-fp/wave6581_P_T.cc -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT wave6581_P_T.o -MD -MP -MF $(DEPDIR)/wave6581_P_T.Tpo -c -o wave6581_P_T.o `test -f 'resid-fp/wave6581_P_T.cc' || echo '$(srcdir)/'`resid-fp/wave6581_P_T.cc -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/wave6581_P_T.Tpo $(DEPDIR)/wave6581_P_T.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='resid-fp/wave6581_P_T.cc' object='wave6581_P_T.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o wave6581_P_T.o `test -f 'resid-fp/wave6581_P_T.cc' || echo '$(srcdir)/'`resid-fp/wave6581_P_T.cc - -wave6581_P_T.obj: resid-fp/wave6581_P_T.cc -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT wave6581_P_T.obj -MD -MP -MF $(DEPDIR)/wave6581_P_T.Tpo -c -o wave6581_P_T.obj `if test -f 'resid-fp/wave6581_P_T.cc'; then $(CYGPATH_W) 'resid-fp/wave6581_P_T.cc'; else $(CYGPATH_W) '$(srcdir)/resid-fp/wave6581_P_T.cc'; fi` -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/wave6581_P_T.Tpo $(DEPDIR)/wave6581_P_T.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='resid-fp/wave6581_P_T.cc' object='wave6581_P_T.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o wave6581_P_T.obj `if test -f 'resid-fp/wave6581_P_T.cc'; then $(CYGPATH_W) 'resid-fp/wave6581_P_T.cc'; else $(CYGPATH_W) '$(srcdir)/resid-fp/wave6581_P_T.cc'; fi` - -wave6581__ST.o: resid-fp/wave6581__ST.cc -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT wave6581__ST.o -MD -MP -MF $(DEPDIR)/wave6581__ST.Tpo -c -o wave6581__ST.o `test -f 'resid-fp/wave6581__ST.cc' || echo '$(srcdir)/'`resid-fp/wave6581__ST.cc -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/wave6581__ST.Tpo $(DEPDIR)/wave6581__ST.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='resid-fp/wave6581__ST.cc' object='wave6581__ST.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o wave6581__ST.o `test -f 'resid-fp/wave6581__ST.cc' || echo '$(srcdir)/'`resid-fp/wave6581__ST.cc - -wave6581__ST.obj: resid-fp/wave6581__ST.cc -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT wave6581__ST.obj -MD -MP -MF $(DEPDIR)/wave6581__ST.Tpo -c -o wave6581__ST.obj `if test -f 'resid-fp/wave6581__ST.cc'; then $(CYGPATH_W) 'resid-fp/wave6581__ST.cc'; else $(CYGPATH_W) '$(srcdir)/resid-fp/wave6581__ST.cc'; fi` -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/wave6581__ST.Tpo $(DEPDIR)/wave6581__ST.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='resid-fp/wave6581__ST.cc' object='wave6581__ST.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o wave6581__ST.obj `if test -f 'resid-fp/wave6581__ST.cc'; then $(CYGPATH_W) 'resid-fp/wave6581__ST.cc'; else $(CYGPATH_W) '$(srcdir)/resid-fp/wave6581__ST.cc'; fi` - -wave8580_PS_.o: resid-fp/wave8580_PS_.cc -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT wave8580_PS_.o -MD -MP -MF $(DEPDIR)/wave8580_PS_.Tpo -c -o wave8580_PS_.o `test -f 'resid-fp/wave8580_PS_.cc' || echo '$(srcdir)/'`resid-fp/wave8580_PS_.cc -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/wave8580_PS_.Tpo $(DEPDIR)/wave8580_PS_.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='resid-fp/wave8580_PS_.cc' object='wave8580_PS_.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o wave8580_PS_.o `test -f 'resid-fp/wave8580_PS_.cc' || echo '$(srcdir)/'`resid-fp/wave8580_PS_.cc - -wave8580_PS_.obj: resid-fp/wave8580_PS_.cc -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT wave8580_PS_.obj -MD -MP -MF $(DEPDIR)/wave8580_PS_.Tpo -c -o wave8580_PS_.obj `if test -f 'resid-fp/wave8580_PS_.cc'; then $(CYGPATH_W) 'resid-fp/wave8580_PS_.cc'; else $(CYGPATH_W) '$(srcdir)/resid-fp/wave8580_PS_.cc'; fi` -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/wave8580_PS_.Tpo $(DEPDIR)/wave8580_PS_.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='resid-fp/wave8580_PS_.cc' object='wave8580_PS_.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o wave8580_PS_.obj `if test -f 'resid-fp/wave8580_PS_.cc'; then $(CYGPATH_W) 'resid-fp/wave8580_PS_.cc'; else $(CYGPATH_W) '$(srcdir)/resid-fp/wave8580_PS_.cc'; fi` - -wave8580_PST.o: resid-fp/wave8580_PST.cc -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT wave8580_PST.o -MD -MP -MF $(DEPDIR)/wave8580_PST.Tpo -c -o wave8580_PST.o `test -f 'resid-fp/wave8580_PST.cc' || echo '$(srcdir)/'`resid-fp/wave8580_PST.cc -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/wave8580_PST.Tpo $(DEPDIR)/wave8580_PST.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='resid-fp/wave8580_PST.cc' object='wave8580_PST.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o wave8580_PST.o `test -f 'resid-fp/wave8580_PST.cc' || echo '$(srcdir)/'`resid-fp/wave8580_PST.cc - -wave8580_PST.obj: resid-fp/wave8580_PST.cc -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT wave8580_PST.obj -MD -MP -MF $(DEPDIR)/wave8580_PST.Tpo -c -o wave8580_PST.obj `if test -f 'resid-fp/wave8580_PST.cc'; then $(CYGPATH_W) 'resid-fp/wave8580_PST.cc'; else $(CYGPATH_W) '$(srcdir)/resid-fp/wave8580_PST.cc'; fi` -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/wave8580_PST.Tpo $(DEPDIR)/wave8580_PST.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='resid-fp/wave8580_PST.cc' object='wave8580_PST.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o wave8580_PST.obj `if test -f 'resid-fp/wave8580_PST.cc'; then $(CYGPATH_W) 'resid-fp/wave8580_PST.cc'; else $(CYGPATH_W) '$(srcdir)/resid-fp/wave8580_PST.cc'; fi` - -wave8580_P_T.o: resid-fp/wave8580_P_T.cc -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT wave8580_P_T.o -MD -MP -MF $(DEPDIR)/wave8580_P_T.Tpo -c -o wave8580_P_T.o `test -f 'resid-fp/wave8580_P_T.cc' || echo '$(srcdir)/'`resid-fp/wave8580_P_T.cc -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/wave8580_P_T.Tpo $(DEPDIR)/wave8580_P_T.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='resid-fp/wave8580_P_T.cc' object='wave8580_P_T.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o wave8580_P_T.o `test -f 'resid-fp/wave8580_P_T.cc' || echo '$(srcdir)/'`resid-fp/wave8580_P_T.cc - -wave8580_P_T.obj: resid-fp/wave8580_P_T.cc -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT wave8580_P_T.obj -MD -MP -MF $(DEPDIR)/wave8580_P_T.Tpo -c -o wave8580_P_T.obj `if test -f 'resid-fp/wave8580_P_T.cc'; then $(CYGPATH_W) 'resid-fp/wave8580_P_T.cc'; else $(CYGPATH_W) '$(srcdir)/resid-fp/wave8580_P_T.cc'; fi` -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/wave8580_P_T.Tpo $(DEPDIR)/wave8580_P_T.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='resid-fp/wave8580_P_T.cc' object='wave8580_P_T.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o wave8580_P_T.obj `if test -f 'resid-fp/wave8580_P_T.cc'; then $(CYGPATH_W) 'resid-fp/wave8580_P_T.cc'; else $(CYGPATH_W) '$(srcdir)/resid-fp/wave8580_P_T.cc'; fi` - -wave8580__ST.o: resid-fp/wave8580__ST.cc -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT wave8580__ST.o -MD -MP -MF $(DEPDIR)/wave8580__ST.Tpo -c -o wave8580__ST.o `test -f 'resid-fp/wave8580__ST.cc' || echo '$(srcdir)/'`resid-fp/wave8580__ST.cc -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/wave8580__ST.Tpo $(DEPDIR)/wave8580__ST.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='resid-fp/wave8580__ST.cc' object='wave8580__ST.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o wave8580__ST.o `test -f 'resid-fp/wave8580__ST.cc' || echo '$(srcdir)/'`resid-fp/wave8580__ST.cc - -wave8580__ST.obj: resid-fp/wave8580__ST.cc -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT wave8580__ST.obj -MD -MP -MF $(DEPDIR)/wave8580__ST.Tpo -c -o wave8580__ST.obj `if test -f 'resid-fp/wave8580__ST.cc'; then $(CYGPATH_W) 'resid-fp/wave8580__ST.cc'; else $(CYGPATH_W) '$(srcdir)/resid-fp/wave8580__ST.cc'; fi` -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/wave8580__ST.Tpo $(DEPDIR)/wave8580__ST.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='resid-fp/wave8580__ST.cc' object='wave8580__ST.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o wave8580__ST.obj `if test -f 'resid-fp/wave8580__ST.cc'; then $(CYGPATH_W) 'resid-fp/wave8580__ST.cc'; else $(CYGPATH_W) '$(srcdir)/resid-fp/wave8580__ST.cc'; fi` - -wave.o: resid-fp/wave.cc -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT wave.o -MD -MP -MF $(DEPDIR)/wave.Tpo -c -o wave.o `test -f 'resid-fp/wave.cc' || echo '$(srcdir)/'`resid-fp/wave.cc -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/wave.Tpo $(DEPDIR)/wave.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='resid-fp/wave.cc' object='wave.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o wave.o `test -f 'resid-fp/wave.cc' || echo '$(srcdir)/'`resid-fp/wave.cc - -wave.obj: resid-fp/wave.cc -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT wave.obj -MD -MP -MF $(DEPDIR)/wave.Tpo -c -o wave.obj `if test -f 'resid-fp/wave.cc'; then $(CYGPATH_W) 'resid-fp/wave.cc'; else $(CYGPATH_W) '$(srcdir)/resid-fp/wave.cc'; fi` -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/wave.Tpo $(DEPDIR)/wave.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='resid-fp/wave.cc' object='wave.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o wave.obj `if test -f 'resid-fp/wave.cc'; then $(CYGPATH_W) 'resid-fp/wave.cc'; else $(CYGPATH_W) '$(srcdir)/resid-fp/wave.cc'; fi` - -.cpp.o: -@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ $< - -.cpp.obj: -@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` - -ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) - list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ - unique=`for i in $$list; do \ - if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ - done | \ - $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ - END { if (nonempty) { for (i in files) print i; }; }'`; \ - mkid -fID $$unique -tags: TAGS - -TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ - $(TAGS_FILES) $(LISP) - set x; \ - here=`pwd`; \ - list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ - unique=`for i in $$list; do \ - if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ - done | \ - $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ - END { if (nonempty) { for (i in files) print i; }; }'`; \ - shift; \ - if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ - test -n "$$unique" || unique=$$empty_fix; \ - if test $$# -gt 0; then \ - $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ - "$$@" $$unique; \ - else \ - $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ - $$unique; \ - fi; \ - fi -ctags: CTAGS -CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ - $(TAGS_FILES) $(LISP) - list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ - unique=`for i in $$list; do \ - if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ - done | \ - $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ - END { if (nonempty) { for (i in files) print i; }; }'`; \ - test -z "$(CTAGS_ARGS)$$unique" \ - || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ - $$unique - -GTAGS: - here=`$(am__cd) $(top_builddir) && pwd` \ - && $(am__cd) $(top_srcdir) \ - && gtags -i $(GTAGS_ARGS) "$$here" - -distclean-tags: - -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags - -distdir: $(DISTFILES) - @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ - topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ - list='$(DISTFILES)'; \ - dist_files=`for file in $$list; do echo $$file; done | \ - sed -e "s|^$$srcdirstrip/||;t" \ - -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ - case $$dist_files in \ - */*) $(MKDIR_P) `echo "$$dist_files" | \ - sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ - sort -u` ;; \ - esac; \ - for file in $$dist_files; do \ - if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ - if test -d $$d/$$file; then \ - dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ - if test -d "$(distdir)/$$file"; then \ - find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ - fi; \ - if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ - cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ - find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ - fi; \ - cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ - else \ - test -f "$(distdir)/$$file" \ - || cp -p $$d/$$file "$(distdir)/$$file" \ - || exit 1; \ - fi; \ - done -check-am: all-am -check: check-am -all-am: Makefile $(PROGRAMS) $(SCRIPTS) -installdirs: - for dir in "$(DESTDIR)$(bindir)"; do \ - test -z "$$dir" || $(MKDIR_P) "$$dir"; \ - done -install: install-am -install-exec: install-exec-am -install-data: install-data-am -uninstall: uninstall-am - -install-am: all-am - @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am - -installcheck: installcheck-am -install-strip: - $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ - install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ - `test -z '$(STRIP)' || \ - echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install -mostlyclean-generic: - -clean-generic: - -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) - -distclean-generic: - -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) - -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) - -maintainer-clean-generic: - @echo "This command is intended for maintainers to use" - @echo "it deletes files that may require special tools to rebuild." -clean: clean-am - -clean-am: clean-binPROGRAMS clean-generic mostlyclean-am - -distclean: distclean-am - -rm -rf ./$(DEPDIR) - -rm -f Makefile -distclean-am: clean-am distclean-compile distclean-generic \ - distclean-tags - -dvi: dvi-am - -dvi-am: - -html: html-am - -html-am: - -info: info-am - -info-am: - -install-data-am: - -install-dvi: install-dvi-am - -install-dvi-am: - -install-exec-am: install-binPROGRAMS - -install-html: install-html-am - -install-html-am: - -install-info: install-info-am - -install-info-am: - -install-man: - -install-pdf: install-pdf-am - -install-pdf-am: - -install-ps: install-ps-am - -install-ps-am: - -installcheck-am: - -maintainer-clean: maintainer-clean-am - -rm -rf ./$(DEPDIR) - -rm -f Makefile -maintainer-clean-am: distclean-am maintainer-clean-generic - -mostlyclean: mostlyclean-am - -mostlyclean-am: mostlyclean-compile mostlyclean-generic - -pdf: pdf-am - -pdf-am: - -ps: ps-am - -ps-am: - -uninstall-am: uninstall-binPROGRAMS - -.MAKE: install-am install-strip - -.PHONY: CTAGS GTAGS all all-am check check-am clean clean-binPROGRAMS \ - clean-generic ctags distclean distclean-compile \ - distclean-generic distclean-tags distdir dvi dvi-am html \ - html-am info info-am install install-am install-binPROGRAMS \ - install-data install-data-am install-dvi install-dvi-am \ - install-exec install-exec-am install-html install-html-am \ - install-info install-info-am install-man install-pdf \ - install-pdf-am install-ps install-ps-am install-strip \ - installcheck installcheck-am installdirs maintainer-clean \ - maintainer-clean-generic mostlyclean mostlyclean-compile \ - mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \ - uninstall-am uninstall-binPROGRAMS - - -../pcem: pcem - cp pcem .. - -amrefresh: - -# Tell versions [3.59,3.63) of GNU make to not export all variables. -# Otherwise a system limit (for SysV at least) may be exceeded. -.NOEXPORT: diff --git a/src/Makefile.local b/src/Makefile.local new file mode 100644 index 000000000..9b9988201 --- /dev/null +++ b/src/Makefile.local @@ -0,0 +1,42 @@ +# +# 86Box A hypervisor and IBM PC system emulator that specializes in +# running old operating systems and software designed for IBM +# PC systems and compatibles from 1981 through fairly recent +# system designs based on the PCI bus. +# +# This file is part of the 86Box distribution. +# +# Prefix for localizing the general Makefile.mingw for local +# settings, so we can avoid changing the main one for all of +# our local setups. +# +# Version: @(#)Makefile.local 1.0.2 2017/05/23 +# +# Author: Fred N. van Kempen, +# + +######################################################################### +# Anything here will override defaults in Makefile.MinGW. # +######################################################################### + + +DEBUG = y +OPTIM = n +COPTIM = -O1 + +# Name of the executable. +PROG = yourexe + +# Various compile-time options. +STUFF = #-DROM_TRACE=0xC800 -DIO_TRACE=0x70 +EXTRAS = #-DYOURNAME + + + +######################################################################### +# Include the master Makefile.MinGW for the rest. # +######################################################################### +include Makefile.mingw + + +# End of Makefile.local. diff --git a/src/Makefile.mingw b/src/Makefile.mingw index fc210da6e..481bfc275 100644 --- a/src/Makefile.mingw +++ b/src/Makefile.mingw @@ -1,51 +1,551 @@ -VPATH = . dosbox lzf resid-fp slirp -CPP = g++.exe -CC = gcc.exe -WINDRES = windres.exe -CFLAGS = -O3 -march=native -mtune=native -fbranch-probabilities -fvpt -fpeel-loops -ftracer -fomit-frame-pointer -ffast-math -msse -msse2 -msse3 -mssse3 -mfpmath=sse -mstackrealign -DFLAGS = -O3 -march=i686 -fomit-frame-pointer -msse2 -mstackrealign -OBJ = 386.o 386_dynarec.o 386_dynarec_ops.o 808x.o acer386sx.o acerm3a.o ali1429.o amstrad.o buslogic.o cdrom-ioctl.o cdrom-iso.o \ - cdrom-null.o codegen.o codegen_ops.o codegen_timing_486.o codegen_timing_686.o codegen_timing_pentium.o codegen_timing_winchip.o codegen_x86.o compaq.o config.o cpu.o dac.o \ - device.o disc.o disc_86f.o disc_fdi.o disc_imd.o disc_img.o disc_random.o disc_td0.o dma.o fdc.o fdc37c665.o fdc37c932fr.o fdd.o fdi2raw.o gameport.o headland.o i430hx.o i430lx.o i430fx.o \ - i430nx.o i430vx.o i440fx.o ide.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 lpt.o mcr.o mem.o memregs.o model.o mouse.o mouse_ps2.o \ - mouse_serial.o ne2000.o neat.o nethandler.o nmi.o nvr.o olivetti_m24.o opti495.o pc.o pc87306.o pci.o pic.o piix.o pit.o ppi.o ps1.o rom.o rtc.o \ - scat.o scsi.o scsi_cdrom.o serial.o sis496.o sis85c471.o sio.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_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 sound_ym7128.o \ - soundopenal.o tandy_eeprom.o tandy_rom.o timer.o um8669f.o vid_ati_eeprom.o vid_ati_mach64.o vid_ati18800.o \ - vid_ati28800.o vid_ati68860_ramdac.o vid_bt485_ramdac.o vid_cga.o vid_cl_gd.o vid_cl_gd_blit.o vid_cl_ramdac.o vid_colorplus.o vid_ega.o vid_et4000.o \ - vid_et4000w32.o vid_hercules.o vid_herculesplus.o vid_icd2061.o vid_ics2595.o vid_incolor.o vid_mda.o vid_nv_riva128.o \ - vid_olivetti_m24.o vid_oti067.o vid_paradise.o vid_pc1512.o vid_pc1640.o vid_pc200.o \ - vid_pcjr.o vid_ps1_svga.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_tandysl.o vid_tgui9440.o vid_tkd8001_ramdac.o vid_tvga.o vid_unk_ramdac.o \ - vid_vga.o vid_wy700.o vid_voodoo.o video.o w83877f.o wd76c10.o win.o win-config.o win-d3d.o win-d3d-fs.o win-ddraw.o \ - win-ddraw-fs.o win-ddraw-screenshot.o win-deviceconfig.o win-hdconf.o win-joystick.o win-joystickconfig.o win-keyboard.o win-midi.o win-mouse.o \ - win-status.o win-video.o x86seg.o x87.o xtide.o pc.res -DBOBJ = dbopl.o nukedopl.o vid_cga_comp.o -LZFOBJ = lzf_c.o lzf_d.o -SIDOBJ = convolve.o convolve-sse.o envelope.o extfilt.o filter.o pot.o sid.o voice.o wave6581__ST.o wave6581_P_T.o wave6581_PS_.o wave6581_PST.o wave8580__ST.o wave8580_P_T.o wave8580_PS_.o wave8580_PST.o wave.o -SLIRPOBJ = bootp.o ip_icmp.o misc.o socket.o tcp_timer.o cksum.o ip_input.o queue.o tcp_input.o tftp.o debug.o ip_output.o sbuf.o tcp_output.o udp.o if.o mbuf.o slirp.o tcp_subr.o +# +# 86Box A hypervisor and IBM PC system emulator that specializes in +# running old operating systems and software designed for IBM +# PC systems and compatibles from 1981 through fairly recent +# system designs based on the PCI bus. +# +# This file is part of the 86Box distribution. +# +# Modified Makefile for Win32 (MinGW32) environment. +# +# Version: @(#)Makefile.mingw 1.0.31 2017/06/19 +# +# Authors: Miran Grca, +# Fred N. van Kempen, +# + +# Name of the executable. +ifndef PROG +PROG = 86Box +endif + +# Various compile-time options. +# -DROM_TRACE=0xcd800 traces ROM access from segment C800 +# -DIO_TACE=0x66 traces I/O on port 0x66 +ifndef STUFF +STUFF = +endif + +# Add feature selections here. +# -DANSI_CFG forces the config file to ANSI encoding. +# -DENABLE_VRAM_DUMP enables Video Ram dumping. +# -DENABLE_LOG_BREAKPOINT enables extra logging. +# -DENABLE_BUSLOGIC_LOG enables extra logging. +# -DENABLE_CDROM_LOG enables extra logging. +# -DENABLE_D86F_LOG enables extra logging. +# -DENABLE_FDC_LOG enables extra logging. +# -DENABLE_IDE_LOG enables extra logging. +# -DENABLE_SERIAL_LOG enables extra logging. +# -DENABLE_NIC_LOG enables extra logging. +ifndef EXTRAS +EXTRAS = +endif + +# Defaults for several build options (possibly defined in a chained file.) +ifndef DEBUG +DEBUG = n +endif +ifndef OPTIM +OPTIM = n +endif +ifndef RELEASE +RELEASE = n +endif +ifndef USB +USB = n +endif +ifndef X64 +X64 = n +endif -LIBS = -mwindows -lwinmm -lopenal.dll -lopenal -lddraw -ldinput8 -ldxguid -ld3d9 -ld3dx9 -lwsock32 -liphlpapi -lstdc++ -static-libstdc++ -static-libgcc -static +######################################################################### +# Nothing should need changing from here on.. # +######################################################################### +VPATH = . cpu \ + sound \ + sound/munt sound/munt/c_interface sound/munt/sha1 \ + sound/munt/srchelper \ + sound/resid-fp \ + video lzf network network/slirp win +PLAT = win/ +ifeq ($(X64), y) +CPP = g++.exe -m64 +CC = gcc.exe -m64 +else +CPP = g++.exe -m32 +CC = gcc.exe -m32 +endif +WINDRES = windres.exe -86Box.exe: $(OBJ) $(DBOBJ) $(LZFOBJ) $(SIDOBJ) $(SLIRPOBJ) - $(CC) $(OBJ) $(DBOBJ) $(LZFOBJ) $(SIDOBJ) $(SLIRPOBJ) -o "86Box.exe" $(LIBS) - strip "86Box.exe" +OPTS = -DWIN32 -I$(PLAT) $(EXTRAS) $(STUFF) -all : 86Box.exe +ifeq ($(X64), y) + ifeq ($(OPTIM), y) + DFLAGS = -march=native + else + DFLAGS = + endif +else + ifeq ($(OPTIM), y) + DFLAGS = -march=native + else + DFLAGS = -march=i686 + endif +endif +ifeq ($(DEBUG), y) + DFLAGS += -ggdb -DDEBUG + AOPTIM = + ifndef COPTIM + COPTIM = -Og + endif +else + ifeq ($(OPTIM), y) + AOPTIM = -mtune=native + ifndef COPTIM + COPTIM = -O6 + endif + else + ifndef COPTIM + COPTIM = -O3 + endif + endif +endif +AFLAGS = -msse -msse2 -mfpmath=sse +CFLAGS = $(OPTS) $(DFLAGS) $(COPTIM) $(AOPTIM) $(AFLAGS) \ + -fomit-frame-pointer -mstackrealign -Wall +RFLAGS = --input-format=rc -O coff +ifeq ($(RELEASE), y) +CFLAGS += -DRELEASE_BUILD +RFLAGS += -DRELEASE_BUILD +endif +ifeq ($(VRAMDUMP), y) +CFLAGS += -DENABLE_VRAM_DUMP +RFLAGS += -DENABLE_VRAM_DUMP +endif -clean : - rm *.o - rm *.exe - rm *.res +ifeq ($(X64), y) +PLATCG = codegen_x86-64.o +else +PLATCG = codegen_x86.o +endif -%.o : %.c - $(CC) $(CFLAGS) -c $< -%.o : %.cc - $(CPP) $(CFLAGS) -c $< +MAINOBJ = pc.o config.o device.o timer.o dma.o io.o nmi.o pic.o \ + mca.o mcr.o pit.o ppi.o pci.o sio.o intel.o rom.o mem.o \ + memregs.o intel_flash.o rtc.o nvr.o ps2_nvr.o +CPUOBJ = cpu.o 386.o 386_dynarec.o 386_dynarec_ops.o 808x.o \ + codegen.o \ + codegen_ops.o codegen_timing_486.o \ + codegen_timing_686.o codegen_timing_pentium.o \ + codegen_timing_winchip.o $(PLATCG) \ + x86seg.o x87.o +SYSOBJ = model.o \ + headland.o \ + i430hx.o i430lx.o i430fx.o i430nx.o i430vx.o i440fx.o \ + neat.o \ + ali1429.o \ + opti495.o \ + scat.o \ + sis496.o \ + wd76c10.o \ + acer386sx.o acerm3a.o amstrad.o \ + compaq.o laserxt.o jim.o \ + olivetti_m24.o ps1.o ps2.o ps2_mca.o \ + tandy_eeprom.o tandy_rom.o +DEVOBJ = bugger.o lpt.o serial.o \ + fdc37c665.o fdc37c669.o fdc37c932fr.o \ + pc87306.o sis85c471.o w83877f.o \ + keyboard.o \ + keyboard_xt.o keyboard_at.o keyboard_pcjr.o \ + keyboard_amstrad.o keyboard_olim24.o \ + gameport.o \ + joystick_standard.o joystick_ch_flightstick_pro.o \ + joystick_sw_pad.o joystick_tm_fcs.o \ + mouse.o mouse_serial.o mouse_ps2.o mouse_bus.o \ + fdd.o fdc.o fdi2raw.o \ + hdd.o hdd_image.o \ + mfm_at.o mfm_xebec.o hdd_esdi.o ide.o xtide.o piix.o \ + disc.o \ + disc_86f.o disc_fdi.o disc_imd.o disc_img.o \ + disc_random.o disc_td0.o \ + cdrom.o \ + cdrom_dosbox.o cdrom_image.o cdrom_ioctl.o cdrom_null.o +ifdef USB +USBOBJ = usb.o +endif +NETOBJ = network.o \ + net_pcap.o \ + net_slirp.o \ + bootp.o ip_icmp.o misc.o socket.o tcp_timer.o cksum.o \ + ip_input.o queue.o tcp_input.o debug.o ip_output.o \ + sbuf.o tcp_output.o udp.o if.o mbuf.o slirp.o tcp_subr.o \ + net_ne2000.o +SCSIOBJ = scsi.o scsi_disk.o scsi_buslogic.o scsi_aha154x.o +SNDOBJ = sound.o \ + openal.o \ + dbopl.o nukedopl.o \ + convolve.o convolve-sse.o envelope.o extfilt.o \ + filter.o pot.o sid.o voice.o wave6581__ST.o \ + wave6581_P_T.o wave6581_PS_.o wave6581_PST.o \ + wave8580__ST.o wave8580_P_T.o wave8580_PS_.o \ + wave8580_PST.o wave.o \ + midi.o \ + midi_mt32.o \ + Analog.o BReverbModel.o File.o FileStream.o LA32Ramp.o \ + LA32FloatWaveGenerator.o LA32WaveGenerator.o \ + MidiStreamParser.o Part.o Partial.o PartialManager.o \ + Poly.o ROMInfo.o Synth.o Tables.o TVA.o TVF.o TVP.o \ + sha1.o c_interface.o \ + midi_system.o \ + snd_speaker.o snd_ps1.o snd_pssj.o \ + snd_adlib.o snd_adlibgold.o snd_ad1848.o \ + snd_sb.o snd_sb_dsp.o snd_cms.o snd_dbopl.o \ + snd_emu8k.o snd_gus.o snd_opl.o \ + snd_mpu401.o snd_pas16.o snd_resid.o \ + snd_sn76489.o snd_ssi2001.o snd_wss.o \ + snd_ym7128.o +VIDOBJ = video.o \ + vid_cga.o vid_cga_comp.o vid_mda.o \ + vid_ega.o vid_ega_render.o \ + vid_vga.o vid_svga.o vid_svga_render.o \ + vid_hercules.o vid_herculesplus.o vid_incolor.o \ + vid_colorplus.o \ + vid_genius.o \ + vid_s3.o vid_s3_virge.o \ + vid_et4000.o vid_et4000w32.o vid_icd2061.o \ + vid_oti067.o \ + vid_paradise.o \ + vid_tvga.o vid_tgui9440.o vid_tkd8001_ramdac.o \ + vid_ati_eeprom.o vid_ati18800.o vid_ati28800.o \ + vid_ati68860_ramdac.o vid_ati_mach64.o \ + vid_ics2595.o \ + vid_sdac_ramdac.o \ + vid_stg_ramdac.o \ + vid_unk_ramdac.o \ + vid_wy700.o \ + vid_voodoo.o \ + vid_pcjr.o vid_ps1_svga.o \ + vid_olivetti_m24.o \ + vid_pc1512.o vid_pc1640.o vid_pc200.o \ + vid_tandy.o vid_tandysl.o +WINOBJ = win.o \ + win_ddraw.o win_ddraw_fs.o win_ddraw_screenshot.o \ + win_d3d.o win_d3d_fs.o \ + win_language.o win_status.o win_opendir.o win_dynld.o \ + win_video.o win_serial.o win_keyboard.o win_mouse.o \ + win_iodev.o win_joystick.o win_midi.o \ + win_settings.o win_deviceconfig.o win_joystickconfig.o \ + 86Box.res +OBJ = $(MAINOBJ) $(CPUOBJ) $(SYSOBJ) $(DEVOBJ) $(USBOBJ) \ + $(NETOBJ) $(SCSIOBJ) $(SNDOBJ) $(VIDOBJ) $(WINOBJ) -pc.res: pc.rc - $(WINDRES) -i pc.rc --input-format=rc -o pc.res -O coff +LZFOBJ = lzf_c.o lzf_d.o + +LIBS = -mwindows \ + -lopenal.dll \ + -lddraw -ldinput8 -ldxguid -ld3d9 -ld3dx9 \ + -lcomctl32 -lkernel32 -lwsock32 -lwinmm -liphlpapi -lpsapi \ + -static -lstdc++ -lgcc + + +# Build rules. +%.o: %.c + @echo $< + @$(CC) $(CFLAGS) -c $< + +%.o: %.cc + @echo $< + @$(CPP) $(CFLAGS) -c $< + +%.o: %.cpp + @echo $< + @$(CPP) $(CFLAGS) -c $< + +all: $(PROG).exe pcap_if.exe + + +$(PROG).exe: $(OBJ) $(LZFOBJ) + @echo Linking $(PROG).exe .. + @$(CC) -o $(PROG).exe $(OBJ) $(LZFOBJ) $(LIBS) +ifneq ($(DEBUG), y) + @strip $(PROG).exe +endif + +pcap_if.exe: pcap_if.o win_dynld.o pcap_if.res + @echo Linking pcap_if.exe .. + @$(CC) -o pcap_if.exe pcap_if.o win_dynld.o pcap_if.res +ifneq ($(DEBUG), y) + @strip pcap_if.exe +endif + + + +clean: + -rm *.o + -rm *.exe + -rm *.res + +86Box.res: 86Box.rc + @echo Processing $< + @$(WINDRES) $(RFLAGS) $(EXTRAS) -i win/86Box.rc -o 86Box.res + +pcap_if.res: pcap_if.rc + @echo Processing $< + @$(WINDRES) $(RFLAGS) -i win/pcap_if.rc -o pcap_if.res + + +# Module dependencies. +acer386sx.o: ibm.h cpu/cpu.h io.h device.h model.h + +acerm3a.o: ibm.h cpu/cpu.h io.h device.h model.h + +ali1429.o: ibm.h cpu/cpu.h io.h mem.h device.h model.h + +amstrad.o: ibm.h cpu/cpu.h io.h device.h model.h keyboard.h lpt.h mouse.h + +bugger.o: ibm.h io.h bugger.h + +cdrom.o: 86box.h cdrom.h ibm.h ide.h piix.h scsi.h timer.h \ + win/plat_iodev.h + +cdrom_ioctl.o: ibm.h cdrom.h cdrom_ioctl.h scsi.h + +cdrom_null.o: ibm.h cdrom.h cdrom_ioctl.h + +compaq.o: ibm.h cpu/cpu.h mem.h device.h model.h + +config.o: cdrom.h config.h device.h disc.h fdc.h fdd.h ibm.h \ + cpu/cpu.h gameport.h ide.h hdd.h model.h mouse.h \ + network/network.h nvr.h scsi.h win/plat_joystick.h \ + win/plat_midi.h sound/snd_dbopl.h sound/snd_mpu401.h \ + sound/snd_opl.h sound/sound.h video/video.h win/win.h \ + win/win_language.h + +device.o: ibm.h cpu/cpu.h config.h device.h model.h sound/sound.h + +disc.o: ibm.h config.h disc.h disc_fdi.h disc_img.h disc_86f.h \ + disc_td0.h disc_imd.h fdc.h fdd.h timer.h + +disc_86f.o: lzf/lzf.h config.h dma.h disc.h disc_86f.h disc_random.h \ + fdc.h fdd.h ibm.h + +disc_fdi.o: ibm.h disc.h disc_img.h disc_fdi.h fdc.h fdd.h fdi2raw.h \ + ibm.h disc.h disc_imd.h fdc.h fdd.h ibm.h config.h disc.h \ + disc_img.h fdc.h fdd.h + +disc_random.o: disc_random.h + +disc_td0.o: ibm.h disc.h disc_td0.h fdc.h fdd.h + +dma.o: ibm.h cpu/x86.h mem.h io.h dma.h + +fdc.o: ibm.h disc.h dma.h fdc.h fdd.h io.h pic.h timer.h + +fdc37c665.o: ibm.h disc.h fdc.h fdd.h ide.h io.h lpt.h serial.h \ + fdc37c665.h ibm.h disc.h fdc.h fdd.h io.h ide.h \ + lpt.h serial.h fdc37c669.h + +fdc37c932fr.o: ibm.h disc.h fdc.h fdd.h ide.h io.h lpt.h serial.h \ + fdc37c932fr.h + +fdd.o: ibm.h disc.h fdc.h fdd.h + +fdi2raw.o: fdi2raw.h ibm.h + +gameport.o: ibm.h cpu/cpu.h device.h io.h timer.h gameport.h \ + joystick_ch_flightstick_pro.h joystick_standard.h \ + joystick_sw_pad.h joystick_tm_fcs.h plat_joystick.h + +hdd.o: ibm.h cpu/cpu.h device.h hdd.h model.h hdd_esdi.h \ + mfm_at.h mfm_xebec.h xtide.h + +hdd_image.o: ibm.h ide.h hdd_image.h + +hdd_esdi.o: ibm.h device.h dma.h hdd_image.h io.h mca.h mem.h \ + pic.h rom.h timer.h hdd_esdi.h + +headland.o: ibm.h cpu/cpu.h io.h mem.h device.h model.h + +i430fx.o: ibm.h cpu/cpu.h mem.h pci.h device.h model.h + +i430hx.o: ibm.h cpu/cpu.h io.h mem.h pci.h device.h model.h + +i430lx.o: ibm.h cpu/cpu.h mem.h pci.h device.h model.h + +i430nx.o: ibm.h cpu/cpu.h mem.h pci.h device.h model.h + +i430vx.o: ibm.h cpu/cpu.h io.h mem.h pci.h device.h model.h + +i440fx.o: ibm.h cpu/cpu.h io.h mem.h pci.h device.h model.h + +i82335.o: ibm.h io.h mem.h + +ide.o: 86box.h cdrom.h hdd_image.h ibm.h io.h pic.h timer.h cdrom.h scsi.h ide.h + +intel.o: ibm.h cpu/cpu.h io.h mem.h pit.h timer.h intel.h + +intel_flash.o: ibm.h cpu/cpu.h device.h mem.h model.h rom.h + +io.o: ibm.h io.h + +jim.o: ibm.h cpu/cpu.h io.h device.h model.h + +joystick_ch_flightstick_pro.o: ibm.h device.h timer.h gameport.h \ + joystick_standard.h plat_joystick.h + +joystick_standard.o: ibm.h device.h timer.h gameport.h \ + joystick_standard.h plat_joystick.h + +joystick_sw_pad.o: ibm.h device.h timer.h gameport.h \ + joystick_sw_pad.h plat_joystick.h + +joystick_tm_fcs.o: ibm.h device.h timer.h gameport.h \ + joystick_standard.h plat_joystick.h + +keyboard.o: ibm.h plat_keyboard.h keyboard.h + +keyboard_amstrad.o: ibm.h io.h mem.h pic.h pit.h timer.h sound/sound.h \ + sound/snd_speaker.h keyboard.h keyboard_amstrad.h + +keyboard_at.o: ibm.h io.h mem.h pic.h pit.h timer.h disc.h fdc.h \ + sound/sound.h sound/snd_speaker.h keyboard.h keyboard_at.h + +keyboard_olim24.o: ibm.h io.h mem.h pic.h pit.h timer.h mouse.h \ + sound/sound.h sound/snd_speaker.h keyboard.h keyboard_olim24.h + +keyboard_pcjr.o: ibm.h io.h mem.h nmi.h pic.h pit.h timer.h \ + device.h sound/sound.h sound/snd_speaker.h \ + sound/snd_sn76489.h keyboard.h keyboard_pcjr.h + +keyboard_xt.o: ibm.h io.h mem.h pic.h pit.h timer.h device.h tandy_eeprom.h \ + sound/sound.h sound/snd_speaker.h keyboard.h keyboard_xt.h + +laserxt.o: ibm.h cpu/cpu.h io.h mem.h device.h model.h + +lpt.o: ibm.h io.h lpt.h + +mca.o: ibm.h io.h mem.h mca.h + +mcr.o: ibm.h + +mem.o: ibm.h cpu/cpu.h cpu/x86_ops.h cpu/x86.h config.h \ + io.h mem.h rom.h cpu/codegen.h video/video.h + +memregs.o: ibm.h io.h memregs.h + +mfm_at.o: ibm.h device.h hdd_image.h io.h pic.h timer.h mfm_at.h + +mfm_xebec.o: ibm.h device.h dma.h hdd_image.h io.h mem.h pic.h rom.h timer.h mfm_xebec.h + +model.o: ibm.h io.h mem.h rom.h device.h model.h cpu/cpu.h \ + mouse.h mouse_ps2.h cdrom.h disc.h dma.h fdc.h \ + fdc37c665.h fdc37c669.h fdc37c932fr.h \ + gameport.h i82335.h ide.h intel.h intel_flash.h \ + keyboard_amstrad.h keyboard_at.h keyboard_olim24.h \ + keyboard_pcjr.h keyboard_xt.h lpt.h mem.h memregs.h \ + nmi.h nvr.h pc87306.h pci.h pic.h piix.h pit.h ps2_mca.h \ + serial.h sis85c471.h sio.h sound/snd_ps1.h sound/snd_pssj.h \ + sound/snd_sn76489.h tandy_eeprom.h tandy_rom.h \ + video/vid_pcjr.h video/vid_tandy.h w83877f.h wd76c10.h \ + xtide.h bugger.h + +mouse.o: ibm.h cpu/cpu.h device.h model.h \ + mouse.h mouse_serial.h mouse_ps2.h mouse_bus.h keyboard_olim24.h + +mouse_bus.o: ibm.h io.h pic.h mouse.h mouse_bus.h plat_mouse.h + +mouse_ps2.o: ibm.h keyboard_at.h mouse.h mouse_ps2.h plat_mouse.h + +mouse_serial.o: ibm.h timer.h serial.h mouse.h mouse_serial.h + +neat.o: ibm.h cpu/cpu.h io.h device.h model.h + +nmi.o: ibm.h io.h nmi.h + +nvr.o: ibm.h cpu/cpu.h device.h io.h mem.h model.h nvr.h \ + pic.h rom.h timer.h rtc.h + +olivetti_m24.o: ibm.h cpu/cpu.h io.h device.h model.h + +opti495.o: ibm.h cpu/cpu.h io.h mem.h device.h model.h + +pc.o: 86box.h ibm.h mem.h cpu/cpu.h cpu/x86_ops.h cpu/codegen.h \ + dma.h nvr.h pic.h pit.h timer.h device.h model.h disc.h \ + disc_86f.h disc_fdi.h disc_imd.h disc_img.h disc_td0.h \ + disc_random.h config.h fdc.h fdd.h gameport.h plat_joystick.h \ + plat_midi.h hdd.h ide.h cdrom.h cdrom_ioctl.h cdrom_image.h \ + cdrom_null.h scsi.h keyboard.h plat_keyboard.h keyboard_at.h \ + mouse.h plat_mouse.h network/network.h serial.h \ + sound/sound.h sound/snd_cms.h sound/snd_dbopl.h \ + sound/snd_mpu401.h sound/snd_opl.h sound/snd_gus.h \ + sound/snd_sb.h sound/snd_speaker.h sound/snd_ssi2001.h \ + video/video.h video/vid_voodoo.h win/plat_ui.h + +pc87306.o: ibm.h disc.h fdc.h fdd.h ide.h io.h lpt.h serial.h pc87306.h + +pci.o: ibm.h io.h mem.h pic.h pci.h + +pic.o: ibm.h io.h pic.h pit.h + +piix.o: ibm.h dma.h ide.h io.h mem.h pci.h piix.h + +pit.o: ibm.h cpu/cpu.h dma.h io.h pic.h pit.h device.h timer.h \ + model.h sound/snd_speaker.h video/video.h + +ppi.o: ibm.h pit.h plat_keyboard.h plat_mouse.h + +ps1.o: ibm.h cpu/cpu.h io.h mem.h rom.h device.h model.h lpt.h serial.h + +ps2.o: ibm.h cpu/cpu.h io.h mem.h rom.h device.h model.h lpt.h serial.h + +ps2_mca.o: ibm.h cpu/cpu.h cpu/x86.h io.h mca.h mem.h rom.h device.h \ + lpt.h ps2_mca.h ps2_nvr.h serial.h + +ps2_nvr.o: ibm.h device.h io.h mem.h rom.h ps2_nvr.h + +rom.o: config.h ibm.h mem.h rom.h + +rtc.o: nvr.h rtc.h + +scat.o: ibm.h cpu/cpu.h io.h mem.h device.h model.h + +scsi.o: 86box.h ibm.h timer.h device.h cdrom.h scsi.h \ + scsi_aha154x.h scsi_buslogic.h + +scsi_aha154x.o: ibm.h io.h mca.h mem.h mca.h rom.h dma.h pic.h timer.h \ + device.h cdrom.h scsi.h scsi_disk.h scsi_aha154x.h \ + +scsi_buslogic.o: ibm.h io.h mem.h rom.h dma.h pic.h pci.h timer.h \ + device.h scsi.h scsi_disk.h cdrom.h scsi_buslogic.h + +scsi_disk.o: 86box.h cdrom.h hdd_image.h ibm.h ide.h piix.h scsi.h \ + scsi_disk.h timer.h win/plat_iodev.h + +serial.o: ibm.h io.h pic.h timer.h serial.h plat_serial.h + +sio.o: ibm.h cdrom.h disc.h dma.h fdc.h keyboard_at.h ide.h \ + io.h mem.h pci.h sio.h + +sis496.o: ibm.h cpu/cpu.h io.h mem.h pci.h device.h model.h + +sis50x.o: ibm.h device.h io.h mem.h pci.h sis50x.h + +sis85c471.o: ibm.h ide.h disc.h fdc.h fdd.h io.h lpt.h serial.h sis85c471.h + +tandy_eeprom.o: ibm.h device.h mem.h io.h rom.h tandy_eeprom.h + +tandy_rom.o: ibm.h device.h io.h mem.h rom.h tandy_rom.h + +timer.o: ibm.h timer.h + +usb.o: ibm.h io.h mem.h usb.h + +w83877f.o: ibm.h disc.h fdc.h fdd.h io.h lpt.h serial.h w83877f.h + +wd76c10.o: ibm.h disc.h fdc.h io.h mem.h serial.h wd76c10.h + +xtide.o: ibm.h io.h mem.h rom.h device.h ide.h xtide.h + + +# End of Makefile.mingw. diff --git a/src/Makefile.mingw64 b/src/Makefile.mingw64 index a42aa3cc4..2f0f9b408 100644 --- a/src/Makefile.mingw64 +++ b/src/Makefile.mingw64 @@ -1,52 +1,33 @@ -VPATH = . dosbox lzf resid-fp slirp -CPP = g++.exe -CC = gcc.exe -WINDRES = windres.exe -CFLAGS = -O3 -march=native -mtune=native -fbranch-probabilities -fvpt -fpeel-loops -ftracer -fomit-frame-pointer -ffast-math -msse -msse2 -msse3 -mssse3 -mfpmath=sse -mstackrealign -DFLAGS = -O3 -fomit-frame-pointer -msse2 -mstackrealign -OBJ = 386.o 386_dynarec.o 386_dynarec_ops.o 808x.o acer386sx.o acerm3a.o ali1429.o amstrad.o buslogic.o cdrom-ioctl.o cdrom-iso.o \ - cdrom-null.o codegen.o codegen_ops.o codegen_timing_486.o codegen_timing_686.o codegen_timing_pentium.o codegen_timing_winchip.o codegen_x86-64.o compaq.o config.o cpu.o dac.o \ - device.o disc.o disc_86f.o disc_fdi.o disc_imd.o disc_img.o disc_random.o disc_td0.o dma.o fdc.o fdc37c665.o fdc37c932fr.o fdd.o fdi2raw.o gameport.o headland.o i430hx.o i430lx.o i430fx.o \ - i430nx.o i430vx.o i440fx.o ide.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 lpt.o mcr.o mem.o memregs.o model.o mouse.o mouse_ps2.o \ - mouse_serial.o ne2000.o neat.o nethandler.o nmi.o nvr.o olivetti_m24.o opti495.o pc.o pc87306.o pci.o pic.o piix.o pit.o ppi.o ps1.o rom.o rtc.o \ - scat.o scsi.o scsi_cdrom.o serial.o sis496.o sis85c471.o sio.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_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 sound_ym7128.o \ - soundopenal.o tandy_eeprom.o tandy_rom.o timer.o um8669f.o vid_ati_eeprom.o vid_ati_mach64.o vid_ati18800.o \ - vid_ati28800.o vid_ati68860_ramdac.o vid_bt485_ramdac.o vid_cga.o vid_cl_gd.o vid_cl_gd_blit.o vid_cl_ramdac.o vid_colorplus.o vid_ega.o vid_et4000.o \ - vid_et4000w32.o vid_hercules.o vid_herculesplus.ovid_icd2061.o vid_ics2595.o vid_incolor.o vid_mda.o vid_nv_riva128.o \ - vid_olivetti_m24.o vid_oti067.o vid_paradise.o vid_pc1512.o vid_pc1640.o vid_pc200.o \ - vid_pcjr.o vid_ps1_svga.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_tandysl.o vid_tgui9440.o vid_tkd8001_ramdac.o vid_tvga.o vid_unk_ramdac.o \ - vid_vga.o vid_wy700.o vid_voodoo.o video.o w83877f.o wd76c10.o win.o win-config.o win-d3d.o win-d3d-fs.o win-ddraw.o \ - win-ddraw-fs.o win-ddraw-screenshot.o win-deviceconfig.o win-hdconf.o win-joystick.o win-joystickconfig.o win-keyboard.o win-midi.o win-mouse.o \ - win-status.o win-video.o x86seg.o x87.o xtide.o pc.res -DBOBJ = dbopl.o nukedopl.o vid_cga_comp.o -LZFOBJ = lzf_c.o lzf_d.o -SIDOBJ = convolve.o convolve-sse.o envelope.o extfilt.o filter.o pot.o sid.o voice.o wave6581__ST.o wave6581_P_T.o wave6581_PS_.o wave6581_PST.o wave8580__ST.o wave8580_P_T.o wave8580_PS_.o wave8580_PST.o wave.o -SLIRPOBJ = bootp.o ip_icmp.o misc.o socket.o tcp_timer.o cksum.o ip_input.o queue.o tcp_input.o tftp.o debug.o ip_output.o sbuf.o tcp_output.o udp.o if.o mbuf.o slirp.o tcp_subr.o +# +# 86Box A hypervisor and IBM PC system emulator that specializes in +# running old operating systems and software designed for IBM +# PC systems and compatibles from 1981 through fairly recent +# system designs based on the PCI bus. +# +# This file is part of the 86Box distribution. +# +# Modified Makefile for Win64 MinGW 64-bit environment. +# +# Version: @(#)Makefile.mingw64 1.0.2 2017/05/06 +# +# Authors: Kotori, +# Fred N. van Kempen, +# Sarah Walker, +# Richard G., +# + +# Include the default Makefile. +include Makefile.mingw + +# Name of the executable. +PROG = 86Box64 + +# Various compile-time options. +STUFF = +EXTRAS = +DEBUG = n +OPTIM = n +X64 = y -LIBS = -mwindows -lwinmm -lopenal -lddraw -ldinput8 -ldxguid -ld3d9 -ld3dx9 -lwsock32 -liphlpapi -lstdc++ -static-libstdc++ -static-libgcc -static -lopenal.dll -lgcov -lPacket -lwpcap - -86Box64.exe: $(OBJ) $(DBOBJ) $(LZFOBJ) $(SIDOBJ) $(SLIRPOBJ) - $(CC) $(OBJ) $(DBOBJ) $(LZFOBJ) $(SIDOBJ) $(SLIRPOBJ) -o "86Box64.exe" $(LIBS) - strip "86Box64.exe" - peflags --bigaddr=false 86Box64.exe - -all : 86Box64.exe - -clean : - rm *.o - rm *.exe - rm *.res - -%.o : %.c - $(CC) $(CFLAGS) -c $< - -%.o : %.cc - $(CPP) $(CFLAGS) -c $< - -pc.res: pc.rc - $(WINDRES) -i pc.rc --input-format=rc -o pc.res -O coff +# End of Makefile.mingw64. diff --git a/src/Makefile_AMD.mingw b/src/Makefile_AMD.mingw deleted file mode 100644 index 436b11d5f..000000000 --- a/src/Makefile_AMD.mingw +++ /dev/null @@ -1,2 +0,0 @@ -include Makefile.mingw -CFLAGS = -O3 -march=amdfam10 -mtune=amdfam10 -fbranch-probabilities -fvpt -funroll-loops -fpeel-loops -ftracer -fomit-frame-pointer -ffast-math -msse -msse2 -msse3 -mfpmath=sse -mstackrealign \ No newline at end of file diff --git a/src/Makefile_AMD.mingw64 b/src/Makefile_AMD.mingw64 deleted file mode 100644 index d891ed4a4..000000000 --- a/src/Makefile_AMD.mingw64 +++ /dev/null @@ -1,2 +0,0 @@ -include Makefile.mingw64 -CFLAGS = -O3 -march=amdfam10 -mtune=amdfam10 -fbranch-probabilities -fvpt -funroll-loops -fpeel-loops -ftracer -fomit-frame-pointer -ffast-math -msse -msse2 -msse3 -mfpmath=sse -mstackrealign \ No newline at end of file diff --git a/src/NETWORK/bswap.h b/src/NETWORK/bswap.h new file mode 100644 index 000000000..81275a6e6 --- /dev/null +++ b/src/NETWORK/bswap.h @@ -0,0 +1,198 @@ +/* Copyright holders: neozeed + see COPYING for more details +*/ +#ifndef BSWAP_H +#define BSWAP_H + +#include + +#ifdef HAVE_BYTESWAP_H +#include +#else +# define bswap_16(x) \ + ( \ + ((uint16_t)( \ + (((uint16_t)(x) & (uint16_t)0x00ffU) << 8) | \ + (((uint16_t)(x) & (uint16_t)0xff00U) >> 8) )) \ + ) + +# define bswap_32(x) \ + ( \ + ((uint32_t)( \ + (((uint32_t)(x) & (uint32_t)0x000000ffUL) << 24) | \ + (((uint32_t)(x) & (uint32_t)0x0000ff00UL) << 8) | \ + (((uint32_t)(x) & (uint32_t)0x00ff0000UL) >> 8) | \ + (((uint32_t)(x) & (uint32_t)0xff000000UL) >> 24) )) \ + ) + +# define bswap_64(x) \ + ( \ + ((uint64_t)( \ + (uint64_t)(((uint64_t)(x) & (uint64_t)0x00000000000000ffULL) << 56) | \ + (uint64_t)(((uint64_t)(x) & (uint64_t)0x000000000000ff00ULL) << 40) | \ + (uint64_t)(((uint64_t)(x) & (uint64_t)0x0000000000ff0000ULL) << 24) | \ + (uint64_t)(((uint64_t)(x) & (uint64_t)0x00000000ff000000ULL) << 8) | \ + (uint64_t)(((uint64_t)(x) & (uint64_t)0x000000ff00000000ULL) >> 8) | \ + (uint64_t)(((uint64_t)(x) & (uint64_t)0x0000ff0000000000ULL) >> 24) | \ + (uint64_t)(((uint64_t)(x) & (uint64_t)0x00ff000000000000ULL) >> 40) | \ + (uint64_t)(((uint64_t)(x) & (uint64_t)0xff00000000000000ULL) >> 56) )) \ + ) +#endif /*HAVE_BYTESWAP_H*/ + +static __inline uint16_t bswap16(uint16_t x) +{ + return bswap_16(x); +} + +static __inline uint32_t bswap32(uint32_t x) +{ + return bswap_32(x); +} + +static __inline uint64_t bswap64(uint64_t x) +{ + return bswap_64(x); +} + +static __inline void bswap16s(uint16_t *s) +{ + *s = bswap16(*s); +} + +static __inline void bswap32s(uint32_t *s) +{ + *s = bswap32(*s); +} + +static __inline void bswap64s(uint64_t *s) +{ + *s = bswap64(*s); +} + +#if defined(WORDS_BIGENDIAN) +# define be_bswap(v, size) (v) +# define le_bswap(v, size) bswap ## size(v) +# define be_bswaps(v, size) +# define le_bswaps(p, size) *p = bswap ## size(*p); +#else +# define le_bswap(v, size) (v) +# define be_bswap(v, size) bswap ## size(v) +# define le_bswaps(v, size) +# define be_bswaps(p, size) *p = bswap ## size(*p); +#endif + +#define CPU_CONVERT(endian, size, type)\ +static __inline type endian ## size ## _to_cpu(type v)\ +{\ + return endian ## _bswap(v, size);\ +}\ +\ +static __inline type cpu_to_ ## endian ## size(type v)\ +{\ + return endian ## _bswap(v, size);\ +}\ +\ +static __inline void endian ## size ## _to_cpus(type *p)\ +{\ + endian ## _bswaps(p, size)\ +}\ +\ +static __inline void cpu_to_ ## endian ## size ## s(type *p)\ +{\ + endian ## _bswaps(p, size)\ +}\ +\ +static __inline type endian ## size ## _to_cpup(const type *p)\ +{\ + return endian ## size ## _to_cpu(*p);\ +}\ +\ +static __inline void cpu_to_ ## endian ## size ## w(type *p, type v)\ +{\ + *p = cpu_to_ ## endian ## size(v);\ +} + +CPU_CONVERT(be, 16, uint16_t) +CPU_CONVERT(be, 32, uint32_t) +CPU_CONVERT(be, 64, uint64_t) + +CPU_CONVERT(le, 16, uint16_t) +CPU_CONVERT(le, 32, uint32_t) +CPU_CONVERT(le, 64, uint64_t) + +/* unaligned versions (optimized for frequent unaligned accesses)*/ + +#if defined(__i386__) || defined(__powerpc__) + +#define cpu_to_le16wu(p, v) cpu_to_le16w(p, v) +#define cpu_to_le32wu(p, v) cpu_to_le32w(p, v) +#define le16_to_cpupu(p) le16_to_cpup(p) +#define le32_to_cpupu(p) le32_to_cpup(p) + +#define cpu_to_be16wu(p, v) cpu_to_be16w(p, v) +#define cpu_to_be32wu(p, v) cpu_to_be32w(p, v) + +#else + +static __inline void cpu_to_le16wu(uint16_t *p, uint16_t v) +{ + uint8_t *p1 = (uint8_t *)p; + + p1[0] = v; + p1[1] = v >> 8; +} + +static __inline void cpu_to_le32wu(uint32_t *p, uint32_t v) +{ + uint8_t *p1 = (uint8_t *)p; + + p1[0] = v; + p1[1] = v >> 8; + p1[2] = v >> 16; + p1[3] = v >> 24; +} + +static __inline uint16_t le16_to_cpupu(const uint16_t *p) +{ + const uint8_t *p1 = (const uint8_t *)p; + return p1[0] | (p1[1] << 8); +} + +static __inline uint32_t le32_to_cpupu(const uint32_t *p) +{ + const uint8_t *p1 = (const uint8_t *)p; + return p1[0] | (p1[1] << 8) | (p1[2] << 16) | (p1[3] << 24); +} + +static __inline void cpu_to_be16wu(uint16_t *p, uint16_t v) +{ + uint8_t *p1 = (uint8_t *)p; + + p1[0] = v >> 8; + p1[1] = v; +} + +static __inline void cpu_to_be32wu(uint32_t *p, uint32_t v) +{ + uint8_t *p1 = (uint8_t *)p; + + p1[0] = v >> 24; + p1[1] = v >> 16; + p1[2] = v >> 8; + p1[3] = v; +} + +#endif + +#ifdef WORDS_BIGENDIAN +#define cpu_to_32wu cpu_to_be32wu +#else +#define cpu_to_32wu cpu_to_le32wu +#endif + +#undef le_bswap +#undef be_bswap +#undef le_bswaps +#undef be_bswaps + +#endif /* BSWAP_H */ diff --git a/src/NETWORK/net_ne2000.c b/src/NETWORK/net_ne2000.c new file mode 100644 index 000000000..d98fdf019 --- /dev/null +++ b/src/NETWORK/net_ne2000.c @@ -0,0 +1,2300 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Implementation of an NE2000/RTL8029AS network controller. + * + * NOTE: The file will also implement an NE1000 for 8-bit ISA systems. + * + * Version: @(#)net_ne2000.c 1.0.11 2017/06/14 + * + * Authors: Fred N. van Kempen, + * Peter Grehan, grehan@iprg.nokia.com> + * SA1988, Tenshi + * + * Based on @(#)ne2k.cc v1.56.2.1 2004/02/02 22:37:22 cbothamy + * Portions Copyright (C) 2002 MandrakeSoft S.A. + */ +#include +#include +#include +#include +#include +#include "../ibm.h" +#include "../io.h" +#include "../mem.h" +#include "../rom.h" +#include "../pci.h" +#include "../pic.h" +#include "../device.h" +#include "../config.h" +#include "../disc_random.h" +#include "network.h" +#include "net_ne2000.h" +#include "bswap.h" + + +/* ROM BIOS file paths. */ +#define ROM_PATH_NE1000 L"roms/network/ne1000/ne1000.rom" +#define ROM_PATH_NE2000 L"roms/network/ne2000/ne2000.rom" +#define ROM_PATH_RTL8029 L"roms/network/rtl8029as/rtl8029as.rom" + +/* PCI info. */ +#define PCI_VENDID 0x10ec /* Realtek, Inc */ +#define PCI_DEVID 0x8029 /* RTL8029AS */ +#define PCI_REGSIZE 256 /* size of PCI space */ + + +/* For PCI. */ +typedef union { + uint32_t addr; + uint8_t addr_regs[4]; +} bar_t; + + +/* Never completely fill the ne2k ring so that we never + hit the unclear completely full buffer condition. */ +#define NE2K_NEVER_FULL_RING (1) + +#define NE2K_MEMSIZ (32*1024) +#define NE2K_MEMSTART (16*1024) +#define NE2K_MEMEND (NE2K_MEMSTART+NE2K_MEMSIZ) + + +typedef struct { + /* Page 0 */ + + /* Command Register - 00h read/write */ + struct CR_t { + int stop; /* STP - Software Reset command */ + int start; /* START - start the NIC */ + int tx_packet; /* TXP - initiate packet transmission */ + uint8_t rdma_cmd; /* RD0,RD1,RD2 - Remote DMA command */ + uint8_t pgsel; /* PS0,PS1 - Page select */ + } CR; + + /* Interrupt Status Register - 07h read/write */ + struct ISR_t { + int pkt_rx; /* PRX - packet received with no errors */ + int pkt_tx; /* PTX - packet txed with no errors */ + int rx_err; /* RXE - packet rxed with 1 or more errors */ + int tx_err; /* TXE - packet txed " " " " " */ + int overwrite; /* OVW - rx buffer resources exhausted */ + int cnt_oflow; /* CNT - network tally counter MSB's set */ + int rdma_done; /* RDC - remote DMA complete */ + int reset; /* RST - reset status */ + } ISR; + + /* Interrupt Mask Register - 0fh write */ + struct IMR_t { + int rx_inte; /* PRXE - packet rx interrupt enable */ + int tx_inte; /* PTXE - packet tx interrput enable */ + int rxerr_inte; /* RXEE - rx error interrupt enable */ + int txerr_inte; /* TXEE - tx error interrupt enable */ + int overw_inte; /* OVWE - overwrite warn int enable */ + int cofl_inte; /* CNTE - counter o'flow int enable */ + int rdma_inte; /* RDCE - remote DMA complete int enable */ + int reserved; /* D7 - reserved */ + } IMR; + + /* Data Configuration Register - 0eh write */ + struct DCR_t { + int wdsize; /* WTS - 8/16-bit select */ + int endian; /* BOS - byte-order select */ + int longaddr; /* LAS - long-address select */ + int loop; /* LS - loopback select */ + int auto_rx; /* AR - auto-remove rx pkts with remote DMA */ + uint8_t fifo_size; /* FT0,FT1 - fifo threshold */ + } DCR; + + /* Transmit Configuration Register - 0dh write */ + struct TCR_t { + int crc_disable; /* CRC - inhibit tx CRC */ + uint8_t loop_cntl; /* LB0,LB1 - loopback control */ + int ext_stoptx; /* ATD - allow tx disable by external mcast */ + int coll_prio; /* OFST - backoff algorithm select */ + uint8_t reserved; /* D5,D6,D7 - reserved */ + } TCR; + + /* Transmit Status Register - 04h read */ + struct TSR_t { + int tx_ok; /* PTX - tx complete without error */ + int reserved; /* D1 - reserved */ + int collided; /* COL - tx collided >= 1 times */ + int aborted; /* ABT - aborted due to excessive collisions */ + int no_carrier; /* CRS - carrier-sense lost */ + int fifo_ur; /* FU - FIFO underrun */ + int cd_hbeat; /* CDH - no tx cd-heartbeat from transceiver */ + int ow_coll; /* OWC - out-of-window collision */ + } TSR; + + /* Receive Configuration Register - 0ch write */ + struct RCR_t { + int errors_ok; /* SEP - accept pkts with rx errors */ + int runts_ok; /* AR - accept < 64-byte runts */ + int broadcast; /* AB - accept eth broadcast address */ + int multicast; /* AM - check mcast hash array */ + int promisc; /* PRO - accept all packets */ + int monitor; /* MON - check pkts, but don't rx */ + uint8_t reserved; /* D6,D7 - reserved */ + } RCR; + + /* Receive Status Register - 0ch read */ + struct RSR_t { + int rx_ok; /* PRX - rx complete without error */ + int bad_crc; /* CRC - Bad CRC detected */ + int bad_falign; /* FAE - frame alignment error */ + int fifo_or; /* FO - FIFO overrun */ + int rx_missed; /* MPA - missed packet error */ + int rx_mbit; /* PHY - unicast or mcast/bcast address match */ + int rx_disabled; /* DIS - set when in monitor mode */ + int deferred; /* DFR - collision active */ + } RSR; + + uint16_t local_dma; /* 01,02h read ; current local DMA addr */ + uint8_t page_start; /* 01h write ; page start regr */ + uint8_t page_stop; /* 02h write ; page stop regr */ + uint8_t bound_ptr; /* 03h read/write ; boundary pointer */ + uint8_t tx_page_start; /* 04h write ; transmit page start reg */ + uint8_t num_coll; /* 05h read ; number-of-collisions reg */ + uint16_t tx_bytes; /* 05,06h write ; transmit byte-count reg */ + uint8_t fifo; /* 06h read ; FIFO */ + uint16_t remote_dma; /* 08,09h read ; current remote DMA addr */ + uint16_t remote_start; /* 08,09h write ; remote start address reg */ + uint16_t remote_bytes; /* 0a,0bh write ; remote byte-count reg */ + uint8_t tallycnt_0; /* 0dh read ; tally ctr 0 (frame align errs) */ + uint8_t tallycnt_1; /* 0eh read ; tally ctr 1 (CRC errors) */ + uint8_t tallycnt_2; /* 0fh read ; tally ctr 2 (missed pkt errs) */ + + /* Page 1 */ + + /* Command Register 00h (repeated) */ + + uint8_t physaddr[6]; /* 01-06h read/write ; MAC address */ + uint8_t curr_page; /* 07h read/write ; current page register */ + uint8_t mchash[8]; /* 08-0fh read/write ; multicast hash array */ + + /* Page 2 - diagnostic use only */ + + /* Command Register 00h (repeated) */ + + /* Page Start Register 01h read (repeated) + * Page Stop Register 02h read (repeated) + * Current Local DMA Address 01,02h write (repeated) + * Transmit Page start address 04h read (repeated) + * Receive Configuration Register 0ch read (repeated) + * Transmit Configuration Register 0dh read (repeated) + * Data Configuration Register 0eh read (repeated) + * Interrupt Mask Register 0fh read (repeated) + */ + uint8_t rempkt_ptr; /* 03h read/write ; rmt next-pkt ptr */ + uint8_t localpkt_ptr; /* 05h read/write ; lcl next-pkt ptr */ + uint16_t address_cnt; /* 06,07h read/write ; address cter */ + + /* Page 3 - should never be modified. */ + + /* Novell ASIC state */ + uint8_t macaddr[32]; /* ASIC ROM'd MAC address, even bytes */ + uint8_t mem[NE2K_MEMSIZ]; /* on-chip packet memory */ + + int board; + int is_pci; + char name[32]; + uint32_t base_address; + int base_irq; + uint32_t bios_addr, + bios_size, + bios_mask; + bar_t pci_bar[2]; + uint8_t pci_regs[PCI_REGSIZE]; + int tx_timer_index; + int tx_timer_active; + uint8_t maclocal[6]; /* configured MAC (local) address */ + uint8_t eeprom[128]; /* for RTL8029AS */ + rom_t bios_rom; + int card; /* PCI card slot */ +} nic_t; + + +static void nic_rx(void *, uint8_t *, int); +static void nic_tx(nic_t *, uint32_t); + + +static void +nelog(int lvl, const char *fmt, ...) +{ +#ifdef ENABLE_NIC_LOG + va_list ap; + + if (nic_do_log >= lvl) { + va_start(ap, fmt); + vprintf(fmt, ap); + va_end(ap); + fflush(stdout); + } +#endif +} + + +static void +nic_interrupt(nic_t *dev, int set) +{ + if (PCI && dev->is_pci) { + if (set) + pci_set_irq(dev->card, PCI_INTC); + else + pci_clear_irq(dev->card, PCI_INTC); + } else { + if (set) + picint(1<base_irq); + else + picintc(1<base_irq); + } +} + + +/* reset - restore state to power-up, cancelling all i/o */ +static void +nic_reset(void *priv) +{ + nic_t *dev = (nic_t *)priv; + int i; + + nelog(1, "%s: reset\n", dev->name); + + /* Initialize the MAC address area by doubling the physical address */ + dev->macaddr[0] = dev->physaddr[0]; + dev->macaddr[1] = dev->physaddr[0]; + dev->macaddr[2] = dev->physaddr[1]; + dev->macaddr[3] = dev->physaddr[1]; + dev->macaddr[4] = dev->physaddr[2]; + dev->macaddr[5] = dev->physaddr[2]; + dev->macaddr[6] = dev->physaddr[3]; + dev->macaddr[7] = dev->physaddr[3]; + dev->macaddr[8] = dev->physaddr[4]; + dev->macaddr[9] = dev->physaddr[4]; + dev->macaddr[10] = dev->physaddr[5]; + dev->macaddr[11] = dev->physaddr[5]; + + /* ne2k signature */ + for (i=12; i<32; i++) + dev->macaddr[i] = 0x57; + + /* Zero out registers and memory */ + memset(&dev->CR, 0x00, sizeof(dev->CR) ); + memset(&dev->ISR, 0x00, sizeof(dev->ISR)); + memset(&dev->IMR, 0x00, sizeof(dev->IMR)); + memset(&dev->DCR, 0x00, sizeof(dev->DCR)); + memset(&dev->TCR, 0x00, sizeof(dev->TCR)); + memset(&dev->TSR, 0x00, sizeof(dev->TSR)); + memset(&dev->RSR, 0x00, sizeof(dev->RSR)); + dev->tx_timer_active = 0; + dev->local_dma = 0; + dev->page_start = 0; + dev->page_stop = 0; + dev->bound_ptr = 0; + dev->tx_page_start = 0; + dev->num_coll = 0; + dev->tx_bytes = 0; + dev->fifo = 0; + dev->remote_dma = 0; + dev->remote_start = 0; + dev->remote_bytes = 0; + dev->tallycnt_0 = 0; + dev->tallycnt_1 = 0; + dev->tallycnt_2 = 0; + + dev->curr_page = 0; + + dev->rempkt_ptr = 0; + dev->localpkt_ptr = 0; + dev->address_cnt = 0; + + memset(&dev->mem, 0x00, sizeof(dev->mem)); + + /* Set power-up conditions */ + dev->CR.stop = 1; + dev->CR.rdma_cmd = 4; + dev->ISR.reset = 1; + dev->DCR.longaddr = 1; + + nic_interrupt(dev, 0); +} + + +static void +nic_soft_reset(void *priv) +{ + nic_t *dev = (nic_t *)priv; + + memset(&(dev->ISR), 0x00, sizeof(dev->ISR)); + dev->ISR.reset = 1; +} + + +/* + * Access the 32K private RAM. + * + * The NE2000 memory is accessed through the data port of the + * ASIC (offset 0) after setting up a remote-DMA transfer. + * Both byte and word accesses are allowed. + * The first 16 bytes contains the MAC address at even locations, + * and there is 16K of buffer memory starting at 16K. + */ +static uint32_t +chipmem_read(nic_t *dev, uint32_t addr, unsigned int len) +{ + uint32_t retval = 0; + + if ((len == 2) && (addr & 0x1)) { + nelog(3, "%s: unaligned chipmem word read\n", dev->name); + } + + /* ROM'd MAC address */ + if ((addr >=0) && (addr <= 31)) { + retval = dev->macaddr[addr % 32]; + if ((len == 2) || (len == 4)) { + retval |= (dev->macaddr[(addr + 1) % 32] << 8); + } + if (len == 4) { + retval |= (dev->macaddr[(addr + 2) % 32] << 16); + retval |= (dev->macaddr[(addr + 3) % 32] << 24); + } + return(retval); + } + + if ((addr >= NE2K_MEMSTART) && (addr < NE2K_MEMEND)) { + retval = dev->mem[addr - NE2K_MEMSTART]; + if ((len == 2) || (len == 4)) { + retval |= (dev->mem[addr - NE2K_MEMSTART + 1] << 8); + } + if (len == 4) { + retval |= (dev->mem[addr - NE2K_MEMSTART + 2] << 16); + retval |= (dev->mem[addr - NE2K_MEMSTART + 3] << 24); + } + return(retval); + } + + nelog(3, "%s: out-of-bounds chipmem read, %04X\n", dev->name, addr); + + if (dev->is_pci) { + return(0xff); + } else { + switch(len) { + case 1: + return(0xff); + case 2: + return(0xffff); + } + } + + return(0xffff); +} + + +static void +chipmem_write(nic_t *dev, uint32_t addr, uint32_t val, unsigned len) +{ + if ((len == 2) && (addr & 0x1)) { + nelog(3, "%s: unaligned chipmem word write\n", dev->name); + } + + if ((addr >= NE2K_MEMSTART) && (addr < NE2K_MEMEND)) { + dev->mem[addr-NE2K_MEMSTART] = val & 0xff; + if ((len == 2) || (len == 4)) { + dev->mem[addr-NE2K_MEMSTART+1] = val >> 8; + } + if (len == 4) { + dev->mem[addr-NE2K_MEMSTART+2] = val >> 16; + dev->mem[addr-NE2K_MEMSTART+3] = val >> 24; + } + } else { + nelog(3, "%s: out-of-bounds chipmem write, %04X\n", dev->name, addr); + } +} + + +/* + * Access the ASIC I/O space. + * + * This is the high 16 bytes of i/o space (the lower 16 bytes + * is for the DS8390). Only two locations are used: offset 0, + * which is used for data transfer, and offset 0x0f, which is + * used to reset the device. + * + * The data transfer port is used to as 'external' DMA to the + * DS8390. The chip has to have the DMA registers set up, and + * after that, insw/outsw instructions can be used to move + * the appropriate number of bytes to/from the device. + */ +static uint32_t +asic_read(nic_t *dev, uint32_t off, unsigned int len) +{ + uint32_t retval = 0; + + switch(off) { + case 0x00: /* Data register */ + /* A read remote-DMA command must have been issued, + and the source-address and length registers must + have been initialised. */ + if (len > dev->remote_bytes) { + nelog(3, "%s: DMA read underrun iolen=%d remote_bytes=%d\n", + dev->name, len, dev->remote_bytes); + } + + nelog(3, "%s: DMA read: addr=%4x remote_bytes=%d\n", + dev->name, dev->remote_dma,dev->remote_bytes); + retval = chipmem_read(dev, dev->remote_dma, len); + + /* The 8390 bumps the address and decreases the byte count + by the selected word size after every access, not by + the amount of data requested by the host (io_len). */ + if (len == 4) { + dev->remote_dma += len; + } else { + dev->remote_dma += (dev->DCR.wdsize + 1); + } + + if (dev->remote_dma == dev->page_stop << 8) { + dev->remote_dma = dev->page_start << 8; + } + + /* keep s.remote_bytes from underflowing */ + if (dev->remote_bytes > dev->DCR.wdsize) { + if (len == 4) { + dev->remote_bytes -= len; + } else { + dev->remote_bytes -= (dev->DCR.wdsize + 1); + } + } else { + dev->remote_bytes = 0; + } + + /* If all bytes have been written, signal remote-DMA complete */ + if (dev->remote_bytes == 0) { + dev->ISR.rdma_done = 1; + if (dev->IMR.rdma_inte) + nic_interrupt(dev, 1); + } + break; + + case 0x0f: /* Reset register */ + nic_soft_reset(dev); + break; + + default: + nelog(3, "%s: ASIC read invalid address %04x\n", + dev->name, (unsigned)off); + break; + } + + return(retval); +} + + +static void +asic_write(nic_t *dev, uint32_t off, uint32_t val, unsigned len) +{ + nelog(3, "%s: ASIC write addr=0x%02x, value=0x%04x\n", + dev->name, (unsigned)off, (unsigned) val); + switch(off) { + case 0x00: /* Data register - see asic_read for a description */ + if ((len > 1) && (dev->DCR.wdsize == 0)) { + nelog(3, "%s: DMA write length %d on byte mode operation\n", + dev->name, len); + break; + } + if (dev->remote_bytes == 0) { + nelog(3, "%s: DMA write, byte count 0\n", dev->name); + } + + chipmem_write(dev, dev->remote_dma, val, len); + if (len == 4) { + dev->remote_dma += len; + } else { + dev->remote_dma += (dev->DCR.wdsize + 1); + } + + if (dev->remote_dma == dev->page_stop << 8) { + dev->remote_dma = dev->page_start << 8; + } + + if (len == 4) { + dev->remote_bytes -= len; + } else { + dev->remote_bytes -= (dev->DCR.wdsize + 1); + } + + if (dev->remote_bytes > NE2K_MEMSIZ) { + dev->remote_bytes = 0; + } + + /* If all bytes have been written, signal remote-DMA complete */ + if (dev->remote_bytes == 0) { + dev->ISR.rdma_done = 1; + if (dev->IMR.rdma_inte) + nic_interrupt(dev, 1); + } + break; + + case 0x0f: /* Reset register */ + /* end of reset pulse */ + break; + + default: /* this is invalid, but happens under win95 device detection */ + nelog(3, "%s: ASIC write invalid address %04x, ignoring\n", + dev->name, (unsigned)off); + break; + } +} + + +/* Handle reads/writes to the 'zeroth' page of the DS8390 register file. */ +static uint32_t +page0_read(nic_t *dev, uint32_t off, unsigned int len) +{ + uint8_t retval = 0; + + if (len > 1) { + /* encountered with win98 hardware probe */ + nelog(3, "%s: bad length! Page0 read from register 0x%02x, len=%u\n", + dev->name, off, len); + return(retval); + } + + switch(off) { + case 0x01: /* CLDA0 */ + retval = (dev->local_dma & 0xff); + break; + + case 0x02: /* CLDA1 */ + retval = (dev->local_dma >> 8); + break; + + case 0x03: /* BNRY */ + retval = dev->bound_ptr; + break; + + case 0x04: /* TSR */ + retval = ((dev->TSR.ow_coll << 7) | + (dev->TSR.cd_hbeat << 6) | + (dev->TSR.fifo_ur << 5) | + (dev->TSR.no_carrier << 4) | + (dev->TSR.aborted << 3) | + (dev->TSR.collided << 2) | + (dev->TSR.tx_ok)); + break; + + case 0x05: /* NCR */ + retval = dev->num_coll; + break; + + case 0x06: /* FIFO */ + /* reading FIFO is only valid in loopback mode */ + nelog(3, "%s: reading FIFO not supported yet\n", dev->name); + retval = dev->fifo; + break; + + case 0x07: /* ISR */ + retval = ((dev->ISR.reset << 7) | + (dev->ISR.rdma_done << 6) | + (dev->ISR.cnt_oflow << 5) | + (dev->ISR.overwrite << 4) | + (dev->ISR.tx_err << 3) | + (dev->ISR.rx_err << 2) | + (dev->ISR.pkt_tx << 1) | + (dev->ISR.pkt_rx)); + break; + + case 0x08: /* CRDA0 */ + retval = (dev->remote_dma & 0xff); + break; + + case 0x09: /* CRDA1 */ + retval = (dev->remote_dma >> 8); + break; + + case 0x0a: /* reserved / RTL8029ID0 */ + if (dev->is_pci) { + retval = 0x50; + } else { + nelog(3, "%s: reserved Page0 read - 0x0a\n", dev->name); + retval = 0xff; + } + break; + + case 0x0b: /* reserved / RTL8029ID1 */ + if (dev->is_pci) { + retval = 0x43; + } else { + nelog(3, "%s: reserved Page0 read - 0x0b\n", dev->name); + retval = 0xff; + } + break; + + case 0x0c: /* RSR */ + retval = ((dev->RSR.deferred << 7) | + (dev->RSR.rx_disabled << 6) | + (dev->RSR.rx_mbit << 5) | + (dev->RSR.rx_missed << 4) | + (dev->RSR.fifo_or << 3) | + (dev->RSR.bad_falign << 2) | + (dev->RSR.bad_crc << 1) | + (dev->RSR.rx_ok)); + break; + + case 0x0d: /* CNTR0 */ + retval = dev->tallycnt_0; + break; + + case 0x0e: /* CNTR1 */ + retval = dev->tallycnt_1; + break; + + case 0x0f: /* CNTR2 */ + retval = dev->tallycnt_2; + break; + + default: + nelog(3, "%s: Page0 register 0x%02x out of range\n", + dev->name, off); + break; + } + + nelog(3, "%s: Page0 read from register 0x%02x, value=0x%02x\n", + dev->name, off, retval); + + return(retval); +} + + +static void +page0_write(nic_t *dev, uint32_t off, uint32_t val, unsigned len) +{ + uint8_t val2; + + /* It appears to be a common practice to use outw on page0 regs... */ + + /* break up outw into two outb's */ + if (len == 2) { + page0_write(dev, off, (val & 0xff), 1); + if (off < 0x0f) + page0_write(dev, off+1, ((val>>8)&0xff), 1); + return; + } + + nelog(3, "%s: Page0 write to register 0x%02x, value=0x%02x\n", + dev->name, off, val); + + switch(off) { + case 0x01: /* PSTART */ + dev->page_start = val; + break; + + case 0x02: /* PSTOP */ + dev->page_stop = val; + break; + + case 0x03: /* BNRY */ + dev->bound_ptr = val; + break; + + case 0x04: /* TPSR */ + dev->tx_page_start = val; + break; + + case 0x05: /* TBCR0 */ + /* Clear out low byte and re-insert */ + dev->tx_bytes &= 0xff00; + dev->tx_bytes |= (val & 0xff); + break; + + case 0x06: /* TBCR1 */ + /* Clear out high byte and re-insert */ + dev->tx_bytes &= 0x00ff; + dev->tx_bytes |= ((val & 0xff) << 8); + break; + + case 0x07: /* ISR */ + val &= 0x7f; /* clear RST bit - status-only bit */ + /* All other values are cleared iff the ISR bit is 1 */ + dev->ISR.pkt_rx &= ~((int)((val & 0x01) == 0x01)); + dev->ISR.pkt_tx &= ~((int)((val & 0x02) == 0x02)); + dev->ISR.rx_err &= ~((int)((val & 0x04) == 0x04)); + dev->ISR.tx_err &= ~((int)((val & 0x08) == 0x08)); + dev->ISR.overwrite &= ~((int)((val & 0x10) == 0x10)); + dev->ISR.cnt_oflow &= ~((int)((val & 0x20) == 0x20)); + dev->ISR.rdma_done &= ~((int)((val & 0x40) == 0x40)); + val = ((dev->ISR.rdma_done << 6) | + (dev->ISR.cnt_oflow << 5) | + (dev->ISR.overwrite << 4) | + (dev->ISR.tx_err << 3) | + (dev->ISR.rx_err << 2) | + (dev->ISR.pkt_tx << 1) | + (dev->ISR.pkt_rx)); + val &= ((dev->IMR.rdma_inte << 6) | + (dev->IMR.cofl_inte << 5) | + (dev->IMR.overw_inte << 4) | + (dev->IMR.txerr_inte << 3) | + (dev->IMR.rxerr_inte << 2) | + (dev->IMR.tx_inte << 1) | + (dev->IMR.rx_inte)); + if (val == 0x00) + nic_interrupt(dev, 0); + break; + + case 0x08: /* RSAR0 */ + /* Clear out low byte and re-insert */ + dev->remote_start &= 0xff00; + dev->remote_start |= (val & 0xff); + dev->remote_dma = dev->remote_start; + break; + + case 0x09: /* RSAR1 */ + /* Clear out high byte and re-insert */ + dev->remote_start &= 0x00ff; + dev->remote_start |= ((val & 0xff) << 8); + dev->remote_dma = dev->remote_start; + break; + + case 0x0a: /* RBCR0 */ + /* Clear out low byte and re-insert */ + dev->remote_bytes &= 0xff00; + dev->remote_bytes |= (val & 0xff); + break; + + case 0x0b: /* RBCR1 */ + /* Clear out high byte and re-insert */ + dev->remote_bytes &= 0x00ff; + dev->remote_bytes |= ((val & 0xff) << 8); + break; + + case 0x0c: /* RCR */ + /* Check if the reserved bits are set */ + if (val & 0xc0) { + nelog(3, "%s: RCR write, reserved bits set\n", + dev->name); + } + + /* Set all other bit-fields */ + dev->RCR.errors_ok = ((val & 0x01) == 0x01); + dev->RCR.runts_ok = ((val & 0x02) == 0x02); + dev->RCR.broadcast = ((val & 0x04) == 0x04); + dev->RCR.multicast = ((val & 0x08) == 0x08); + dev->RCR.promisc = ((val & 0x10) == 0x10); + dev->RCR.monitor = ((val & 0x20) == 0x20); + + /* Monitor bit is a little suspicious... */ + if (val & 0x20) nelog(3, "%s: RCR write, monitor bit set!\n", + dev->name); + break; + + case 0x0d: /* TCR */ + /* Check reserved bits */ + if (val & 0xe0) nelog(3, "%s: TCR write, reserved bits set\n", + dev->name); + + /* Test loop mode (not supported) */ + if (val & 0x06) { + dev->TCR.loop_cntl = (val & 0x6) >> 1; + nelog(3, "%s: TCR write, loop mode %d not supported\n", + dev->name, dev->TCR.loop_cntl); + } else { + dev->TCR.loop_cntl = 0; + } + + /* Inhibit-CRC not supported. */ + if (val & 0x01) nelog(3, + "%s: TCR write, inhibit-CRC not supported\n",dev->name); + + /* Auto-transmit disable very suspicious */ + if (val & 0x08) nelog(3, + "%s: TCR write, auto transmit disable not supported\n", + dev->name); + + /* Allow collision-offset to be set, although not used */ + dev->TCR.coll_prio = ((val & 0x08) == 0x08); + break; + + case 0x0e: /* DCR */ + /* the loopback mode is not suppported yet */ + if (! (val & 0x08)) nelog(3, + "%s: DCR write, loopback mode selected\n", dev->name); + + /* It is questionable to set longaddr and auto_rx, since + * they are not supported on the NE2000. Print a warning + * and continue. */ + if (val & 0x04) + nelog(3, "%s: DCR write - LAS set ???\n", dev->name); + if (val & 0x10) + nelog(3, "%s: DCR write - AR set ???\n", dev->name); + + /* Set other values. */ + dev->DCR.wdsize = ((val & 0x01) == 0x01); + dev->DCR.endian = ((val & 0x02) == 0x02); + dev->DCR.longaddr = ((val & 0x04) == 0x04); /* illegal ? */ + dev->DCR.loop = ((val & 0x08) == 0x08); + dev->DCR.auto_rx = ((val & 0x10) == 0x10); /* also illegal ? */ + dev->DCR.fifo_size = (val & 0x50) >> 5; + break; + + case 0x0f: /* IMR */ + /* Check for reserved bit */ + if (val & 0x80) + nelog(3, "%s: IMR write, reserved bit set\n",dev->name); + + /* Set other values */ + dev->IMR.rx_inte = ((val & 0x01) == 0x01); + dev->IMR.tx_inte = ((val & 0x02) == 0x02); + dev->IMR.rxerr_inte = ((val & 0x04) == 0x04); + dev->IMR.txerr_inte = ((val & 0x08) == 0x08); + dev->IMR.overw_inte = ((val & 0x10) == 0x10); + dev->IMR.cofl_inte = ((val & 0x20) == 0x20); + dev->IMR.rdma_inte = ((val & 0x40) == 0x40); + val2 = ((dev->ISR.rdma_done << 6) | + (dev->ISR.cnt_oflow << 5) | + (dev->ISR.overwrite << 4) | + (dev->ISR.tx_err << 3) | + (dev->ISR.rx_err << 2) | + (dev->ISR.pkt_tx << 1) | + (dev->ISR.pkt_rx)); + if (((val & val2) & 0x7f) == 0) + nic_interrupt(dev, 0); + else + nic_interrupt(dev, 1); + break; + + default: + nelog(3, "%s: Page0 write, bad register 0x%02x\n", + dev->name, off); + break; + } +} + + +/* Handle reads/writes to the first page of the DS8390 register file. */ +static uint32_t +page1_read(nic_t *dev, uint32_t off, unsigned int len) +{ + nelog(3, "%s: Page1 read from register 0x%02x, len=%u\n", + dev->name, off, len); + + switch(off) { + case 0x01: /* PAR0-5 */ + case 0x02: + case 0x03: + case 0x04: + case 0x05: + case 0x06: + return(dev->physaddr[off - 1]); + + case 0x07: /* CURR */ + nelog(3, "%s: returning current page: 0x%02x\n", + dev->name, (dev->curr_page)); + return(dev->curr_page); + + case 0x08: /* MAR0-7 */ + case 0x09: + case 0x0a: + case 0x0b: + case 0x0c: + case 0x0d: + case 0x0e: + case 0x0f: + return(dev->mchash[off - 8]); + + default: + nelog(3, "%s: Page1 read register 0x%02x out of range\n", + dev->name, off); + return(0); + } +} + + +static void +page1_write(nic_t *dev, uint32_t off, uint32_t val, unsigned len) +{ + nelog(3, "%s: Page1 write to register 0x%02x, len=%u, value=0x%04x\n", + dev->name, off, len, val); + + switch(off) { + case 0x01: /* PAR0-5 */ + case 0x02: + case 0x03: + case 0x04: + case 0x05: + case 0x06: + dev->physaddr[off - 1] = val; + if (off == 6) nelog(3, + "%s: physical address set to %02x:%02x:%02x:%02x:%02x:%02x\n", + dev->name, + dev->physaddr[0], dev->physaddr[1], + dev->physaddr[2], dev->physaddr[3], + dev->physaddr[4], dev->physaddr[5]); + break; + + case 0x07: /* CURR */ + dev->curr_page = val; + break; + + case 0x08: /* MAR0-7 */ + case 0x09: + case 0x0a: + case 0x0b: + case 0x0c: + case 0x0d: + case 0x0e: + case 0x0f: + dev->mchash[off - 8] = val; + break; + + default: + nelog(3, "%s: Page1 write register 0x%02x out of range\n", + dev->name, off); + break; + } +} + + +/* Handle reads/writes to the second page of the DS8390 register file. */ +static uint32_t +page2_read(nic_t *dev, uint32_t off, unsigned int len) +{ + nelog(3, "%s: Page2 read from register 0x%02x, len=%u\n", + dev->name, off, len); + + switch(off) { + case 0x01: /* PSTART */ + return(dev->page_start); + + case 0x02: /* PSTOP */ + return(dev->page_stop); + + case 0x03: /* Remote Next-packet pointer */ + return(dev->rempkt_ptr); + + case 0x04: /* TPSR */ + return(dev->tx_page_start); + + case 0x05: /* Local Next-packet pointer */ + return(dev->localpkt_ptr); + + case 0x06: /* Address counter (upper) */ + return(dev->address_cnt >> 8); + + case 0x07: /* Address counter (lower) */ + return(dev->address_cnt & 0xff); + + case 0x08: /* Reserved */ + case 0x09: + case 0x0a: + case 0x0b: + nelog(3, "%s: reserved Page2 read - register 0x%02x\n", + dev->name, off); + return(0xff); + + case 0x0c: /* RCR */ + return ((dev->RCR.monitor << 5) | + (dev->RCR.promisc << 4) | + (dev->RCR.multicast << 3) | + (dev->RCR.broadcast << 2) | + (dev->RCR.runts_ok << 1) | + (dev->RCR.errors_ok)); + + case 0x0d: /* TCR */ + return ((dev->TCR.coll_prio << 4) | + (dev->TCR.ext_stoptx << 3) | + ((dev->TCR.loop_cntl & 0x3) << 1) | + (dev->TCR.crc_disable)); + + case 0x0e: /* DCR */ + return (((dev->DCR.fifo_size & 0x3) << 5) | + (dev->DCR.auto_rx << 4) | + (dev->DCR.loop << 3) | + (dev->DCR.longaddr << 2) | + (dev->DCR.endian << 1) | + (dev->DCR.wdsize)); + + case 0x0f: /* IMR */ + return ((dev->IMR.rdma_inte << 6) | + (dev->IMR.cofl_inte << 5) | + (dev->IMR.overw_inte << 4) | + (dev->IMR.txerr_inte << 3) | + (dev->IMR.rxerr_inte << 2) | + (dev->IMR.tx_inte << 1) | + (dev->IMR.rx_inte)); + + default: + nelog(3, "%s: Page2 register 0x%02x out of range\n", + dev->name, off); + break; + } + + return(0); +} + + +static void +page2_write(nic_t *dev, uint32_t off, uint32_t val, unsigned len) +{ +/* Maybe all writes here should be BX_PANIC()'d, since they + affect internal operation, but let them through for now + and print a warning. */ + nelog(3, "%s: Page2 write to register 0x%02x, len=%u, value=0x%04x\n", + dev->name, off, len, val); + switch(off) { + case 0x01: /* CLDA0 */ + /* Clear out low byte and re-insert */ + dev->local_dma &= 0xff00; + dev->local_dma |= (val & 0xff); + break; + + case 0x02: /* CLDA1 */ + /* Clear out high byte and re-insert */ + dev->local_dma &= 0x00ff; + dev->local_dma |= ((val & 0xff) << 8); + break; + + case 0x03: /* Remote Next-pkt pointer */ + dev->rempkt_ptr = val; + break; + + case 0x04: + nelog(3, "page 2 write to reserved register 0x04\n"); + break; + + case 0x05: /* Local Next-packet pointer */ + dev->localpkt_ptr = val; + break; + + case 0x06: /* Address counter (upper) */ + /* Clear out high byte and re-insert */ + dev->address_cnt &= 0x00ff; + dev->address_cnt |= ((val & 0xff) << 8); + break; + + case 0x07: /* Address counter (lower) */ + /* Clear out low byte and re-insert */ + dev->address_cnt &= 0xff00; + dev->address_cnt |= (val & 0xff); + break; + + case 0x08: + case 0x09: + case 0x0a: + case 0x0b: + case 0x0c: + case 0x0d: + case 0x0e: + case 0x0f: + nelog(3, "%s: Page2 write to reserved register 0x%02x\n", + dev->name, off); + break; + + default: + nelog(3, "%s: Page2 write, illegal register 0x%02x\n", + dev->name, off); + break; + } +} + + +/* Writes to this page are illegal. */ +static uint32_t +page3_read(nic_t *dev, uint32_t off, unsigned int len) +{ + if (dev->is_pci) switch(off) { + case 0x3: /* CONFIG0 */ + return(0x00); + + case 0x5: /* CONFIG2 */ + return(0x40); + + case 0x6: /* CONFIG3 */ + return(0x40); + + default: + break; + } + + nelog(3, "%s: Page3 read register 0x%02x attempted\n", dev->name, off); + return(0x00); +} + + +static void +page3_write(nic_t *dev, uint32_t off, uint32_t val, unsigned len) +{ + nelog(3, "%s: Page3 write register 0x%02x attempted\n", dev->name, off); +} + + +/* Routines for handling reads/writes to the Command Register. */ +static uint32_t +read_cr(nic_t *dev) +{ + uint32_t retval; + + retval = (((dev->CR.pgsel & 0x03) << 6) | + ((dev->CR.rdma_cmd & 0x07) << 3) | + (dev->CR.tx_packet << 2) | + (dev->CR.start << 1) | + (dev->CR.stop)); + nelog(3, "%s: read CR returns 0x%02x\n", dev->name, retval); + + return(retval); +} + + +static void +write_cr(nic_t *dev, uint32_t val) +{ + nelog(3, "%s: wrote 0x%02x to CR\n", dev->name, val); + + /* Validate remote-DMA */ + if ((val & 0x38) == 0x00) { + nelog(3, "%s: CR write - invalid rDMA value 0\n", dev->name); + val |= 0x20; /* dma_cmd == 4 is a safe default */ + } + + /* Check for s/w reset */ + if (val & 0x01) { + dev->ISR.reset = 1; + dev->CR.stop = 1; + } else { + dev->CR.stop = 0; + } + + dev->CR.rdma_cmd = (val & 0x38) >> 3; + + /* If start command issued, the RST bit in the ISR */ + /* must be cleared */ + if ((val & 0x02) && !dev->CR.start) + dev->ISR.reset = 0; + + dev->CR.start = ((val & 0x02) == 0x02); + dev->CR.pgsel = (val & 0xc0) >> 6; + + /* Check for send-packet command */ + if (dev->CR.rdma_cmd == 3) { + /* Set up DMA read from receive ring */ + dev->remote_start = dev->remote_dma = dev->bound_ptr * 256; + dev->remote_bytes = (uint16_t) chipmem_read(dev, dev->bound_ptr * 256 + 2, 2); + nelog(3, "%s: sending buffer #x%x length %d\n", + dev->name, dev->remote_start, dev->remote_bytes); + } + + /* Check for start-tx */ + if ((val & 0x04) && dev->TCR.loop_cntl) { + if (dev->TCR.loop_cntl != 1) { + nelog(3, "%s: loop mode %d not supported\n", + dev->name, dev->TCR.loop_cntl); + } else { + nic_rx(dev, + &dev->mem[dev->tx_page_start*256 - NE2K_MEMSTART], + dev->tx_bytes); + } + } else if (val & 0x04) { + if (dev->CR.stop || (!dev->CR.start && !dev->is_pci)) { + if (dev->tx_bytes == 0) /* njh@bandsman.co.uk */ { + return; /* Solaris9 probe */ + } + nelog(3, "%s: CR write - tx start, dev in reset\n", dev->name); + } + + if (dev->tx_bytes == 0) + nelog(3, "%s: CR write - tx start, tx bytes == 0\n", dev->name); + + /* Send the packet to the system driver */ + dev->CR.tx_packet = 1; + network_tx(&dev->mem[dev->tx_page_start*256 - NE2K_MEMSTART], + dev->tx_bytes); + + /* some more debug */ + if (dev->tx_timer_active) + nelog(3, "%s: CR write, tx timer still active\n", dev->name); + + nic_tx(dev, val); + } + + /* Linux probes for an interrupt by setting up a remote-DMA read + * of 0 bytes with remote-DMA completion interrupts enabled. + * Detect this here */ + if (dev->CR.rdma_cmd == 0x01 && dev->CR.start && dev->remote_bytes == 0) { + dev->ISR.rdma_done = 1; + if (dev->IMR.rdma_inte) { + nic_interrupt(dev, 1); + if (! dev->is_pci) + nic_interrupt(dev, 0); + } + } +} + + +static uint32_t +nic_read(nic_t *dev, uint32_t addr, unsigned len) +{ + uint32_t retval = 0; + int off = addr - dev->base_address; + + nelog(3, "%s: read addr %x, len %d\n", dev->name, addr, len); + + if (off >= 0x10) { + retval = asic_read(dev, off - 0x10, len); + } else if (off == 0x00) { + retval = read_cr(dev); + } else switch(dev->CR.pgsel) { + case 0x00: + retval = page0_read(dev, off, len); + break; + + case 0x01: + retval = page1_read(dev, off, len); + break; + + case 0x02: + retval = page2_read(dev, off, len); + break; + + case 0x03: + retval = page3_read(dev, off, len); + break; + + default: + nelog(3, "%s: unknown value of pgsel in read - %d\n", + dev->name, dev->CR.pgsel); + break; + } + + return(retval); +} + + +static uint8_t +nic_readb(uint16_t addr, void *priv) +{ + return(nic_read((nic_t *)priv, addr, 1)); +} + + +static uint16_t +nic_readw(uint16_t addr, void *priv) +{ + nic_t *dev = (nic_t *)priv; + + if (dev->DCR.wdsize & 1) + return(nic_read(dev, addr, 2)); + else + return(nic_read(dev, addr, 1)); +} + + +static uint32_t +nic_readl(uint16_t addr, void *priv) +{ + return(nic_read((nic_t *)priv, addr, 4)); +} + + +static void +nic_write(nic_t *dev, uint32_t addr, uint32_t val, unsigned len) +{ + int off = addr - dev->base_address; + + nelog(3, "%s: write addr %x, value %x len %d\n", dev->name, addr, val, len); + + /* The high 16 bytes of i/o space are for the ne2000 asic - + the low 16 bytes are for the DS8390, with the current + page being selected by the PS0,PS1 registers in the + command register */ + if (off >= 0x10) { + asic_write(dev, off - 0x10, val, len); + } else if (off == 0x00) { + write_cr(dev, val); + } else switch(dev->CR.pgsel) { + case 0x00: + page0_write(dev, off, val, len); + break; + + case 0x01: + page1_write(dev, off, val, len); + break; + + case 0x02: + page2_write(dev, off, val, len); + break; + + case 0x03: + page3_write(dev, off, val, len); + break; + + default: + nelog(3, "%s: unknown value of pgsel in write - %d\n", + dev->name, dev->CR.pgsel); + break; + } +} + + +static void +nic_writeb(uint16_t addr, uint8_t val, void *priv) +{ + nic_write((nic_t *)priv, addr, val, 1); +} + + +static void +nic_writew(uint16_t addr, uint16_t val, void *priv) +{ + nic_t *dev = (nic_t *)priv; + + if (dev->DCR.wdsize & 1) + nic_write(dev, addr, val, 2); + else + nic_write(dev, addr, val, 1); +} + + +static void +nic_writel(uint16_t addr, uint32_t val, void *priv) +{ + nic_write((nic_t *)priv, addr, val, 4); +} + + +static void +nic_ioset(nic_t *dev, uint16_t addr) +{ + if (dev->is_pci) { + io_sethandler(addr, 16, + nic_readb, nic_readw, nic_readl, + nic_writeb, nic_writew, nic_writel, dev); + io_sethandler(addr+16, 16, + nic_readb, nic_readw, nic_readl, + nic_writeb, nic_writew, nic_writel, dev); + io_sethandler(addr+0x1f, 1, + nic_readb, nic_readw, nic_readl, + nic_writeb, nic_writew, nic_writel, dev); + } else { + io_sethandler(addr, 16, + nic_readb, NULL, NULL, + nic_writeb, NULL, NULL, dev); + io_sethandler(addr+16, 16, + nic_readb, nic_readw, NULL, + nic_writeb, nic_writew, NULL, dev); + io_sethandler(addr+0x1f, 1, + nic_readb, NULL, NULL, + nic_writeb, NULL, NULL, dev); + } +} + + +static void +nic_ioremove(nic_t *dev, int16_t addr) +{ + if (dev->is_pci) { + io_removehandler(addr, 16, + nic_readb, nic_readw, nic_readl, + nic_writeb, nic_writew, nic_writel, dev); + io_removehandler(addr+16, 16, + nic_readb, nic_readw, nic_readl, + nic_writeb, nic_writew, nic_writel, dev); + io_removehandler(addr+0x1f, 1, + nic_readb, nic_readw, nic_readl, + nic_writeb, nic_writew, nic_writel, dev); + } else { + io_removehandler(addr, 16, + nic_readb, NULL, NULL, + nic_writeb, NULL, NULL, dev); + io_removehandler(addr+16, 16, + nic_readb, nic_readw, NULL, + nic_writeb, nic_writew, NULL, dev); + io_removehandler(addr+0x1f, 1, + nic_readb, NULL, NULL, + nic_writeb, NULL, NULL, dev); + } +} + + +static void +nic_update_bios(nic_t *dev) +{ + int reg_bios_enable; + + reg_bios_enable = 1; + + /* PCI BIOS stuff, just enable_disable. */ + if ((dev->bios_addr > 0) && reg_bios_enable) { + mem_mapping_enable(&dev->bios_rom.mapping); + mem_mapping_set_addr(&dev->bios_rom.mapping, + dev->bios_addr, dev->bios_size); + nelog(1, "%s: BIOS now at: %06X\n", dev->name, dev->bios_addr); + } else { + nelog(1, "%s: BIOS disabled\n", dev->name); + mem_mapping_disable(&dev->bios_rom.mapping); + dev->bios_addr = 0; + if (dev->is_pci) + dev->pci_bar[1].addr = 0; + } +} + + +static uint8_t +nic_pci_read(int func, int addr, void *priv) +{ + nic_t *dev = (nic_t *)priv; + uint8_t ret = 0x00; + + switch(addr) { + case 0x00: /* PCI_VID_LO */ + case 0x01: /* PCI_VID_HI */ + ret = dev->pci_regs[addr]; + break; + + case 0x02: /* PCI_DID_LO */ + case 0x03: /* PCI_DID_HI */ + ret = dev->pci_regs[addr]; + break; + + case 0x04: /* PCI_COMMAND_LO */ + case 0x05: /* PCI_COMMAND_HI */ + ret = dev->pci_regs[addr]; + break; + + case 0x06: /* PCI_STATUS_LO */ + case 0x07: /* PCI_STATUS_HI */ + ret = dev->pci_regs[addr]; + break; + + case 0x08: /* PCI_REVID */ + ret = 0x00; /* Rev. 00 */ + break; + case 0x09: /* PCI_PIFR */ + ret = 0x00; /* Rev. 00 */ + break; + + case 0x0A: /* PCI_SCR */ + ret = dev->pci_regs[addr]; + break; + + case 0x0B: /* PCI_BCR */ + ret = dev->pci_regs[addr]; + break; + +#if 0 + case 0x0C: /* (reserved) */ + ret = dev->pci_regs[addr]; + break; + + case 0x0D: /* PCI_LTR */ + case 0x0E: /* PCI_HTR */ + ret = dev->pci_regs[addr]; + break; + + case 0x0F: /* (reserved) */ + ret = dev->pci_regs[addr]; + break; +#endif + + case 0x10: /* PCI_BAR 7:5 */ + ret = (dev->pci_bar[0].addr_regs[1] & 0xe0) | 0x01; + break; + case 0x11: /* PCI_BAR 15:8 */ + ret = dev->pci_bar[0].addr_regs[1]; + break; + case 0x12: /* PCI_BAR 23:16 */ + ret = dev->pci_bar[0].addr_regs[2]; + break; + case 0x13: /* PCI_BAR 31:24 */ + ret = dev->pci_bar[0].addr_regs[3]; + break; + + case 0x2C: /* PCI_SVID_LO */ + case 0x2D: /* PCI_SVID_HI */ + ret = dev->pci_regs[addr]; + break; + + case 0x2E: /* PCI_SID_LO */ + case 0x2F: /* PCI_SID_HI */ + ret = dev->pci_regs[addr]; + break; + + case 0x30: /* PCI_ROMBAR */ + ret = dev->pci_bar[1].addr_regs[0] & 0x01; + break; + case 0x31: /* PCI_ROMBAR 15:11 */ + ret = (dev->pci_bar[1].addr_regs[1] & dev->bios_mask) | 0x18; + break; + case 0x32: /* PCI_ROMBAR 23:16 */ + ret = dev->pci_bar[1].addr_regs[2]; + break; + case 0x33: /* PCI_ROMBAR 31:24 */ + ret = dev->pci_bar[1].addr_regs[3]; + break; + + case 0x3C: /* PCI_ILR */ + ret = dev->pci_regs[addr]; + break; + + case 0x3D: /* PCI_IPR */ + ret = dev->pci_regs[addr]; + break; + } + + nelog(2, "%s: PCI_Read(%d, %04x) = %02x\n", dev->name, func, addr, ret); + + return(ret); +} + + +static void +nic_pci_write(int func, int addr, uint8_t val, void *priv) +{ + nic_t *dev = (nic_t *)priv; + uint8_t valxor; + + nelog(2, "%s: PCI_Write(%d, %04x, %02x)\n", dev->name, func, addr, val); + + switch(addr) { + case 0x04: /* PCI_COMMAND_LO */ + valxor = (val & 0x23) ^ dev->pci_regs[addr]; + if (valxor & PCI_COMMAND_IO) + { + nic_ioremove(dev, dev->base_address); + if ((dev->base_address != 0) && (val & PCI_COMMAND_IO)) + { + nic_ioset(dev, dev->base_address); + } + } +#if 0 + if (val & PCI_COMMAND_MEMORY) { + ... + } +#endif + dev->pci_regs[addr] = val & 0x23; + break; + +#if 0 + case 0x0C: /* (reserved) */ + dev->pci_regs[addr] = val; + break; + + case 0x0D: /* PCI_LTR */ + dev->pci_regs[addr] = val; + break; + + case 0x0E: /* PCI_HTR */ + dev->pci_regs[addr] = val; + break; + + case 0x0F: /* (reserved) */ + dev->pci_regs[addr] = val; + break; +#endif + + case 0x10: /* PCI_BAR */ + val &= 0xfc; /* 0xe0 acc to RTL DS */ + val |= 0x01; /* re-enable IOIN bit */ + /*FALLTHROUGH*/ + + case 0x11: /* PCI_BAR */ + case 0x12: /* PCI_BAR */ + case 0x13: /* PCI_BAR */ + /* Remove old I/O. */ + nic_ioremove(dev, dev->base_address); + + /* Set new I/O as per PCI request. */ + dev->pci_bar[0].addr_regs[addr & 3] = val; + + /* Then let's calculate the new I/O base. */ + dev->base_address = dev->pci_bar[0].addr & 0xffe0; + + /* Log the new base. */ + nelog(1, "%s: PCI: new I/O base is %04X\n", + dev->name, dev->base_address); + /* We're done, so get out of the here. */ + if (dev->pci_regs[4] & PCI_COMMAND_IO) + { + if (dev->base_address != 0) + { + nic_ioset(dev, dev->base_address); + } + } + break; + + case 0x30: /* PCI_ROMBAR */ + case 0x31: /* PCI_ROMBAR */ + case 0x32: /* PCI_ROMBAR */ + case 0x33: /* PCI_ROMBAR */ + dev->pci_bar[1].addr_regs[addr & 3] = val; + dev->pci_bar[1].addr_regs[1] &= dev->bios_mask; + dev->pci_bar[1].addr &= 0xffffe000; + dev->bios_addr = dev->pci_bar[1].addr; + dev->pci_bar[1].addr |= 0x1801; + nic_update_bios(dev); + return; + + case 0x3C: /* PCI_ILR */ + nelog(1, "%s: IRQ now: %i\n", dev->name, val); + dev->base_irq = val; + dev->pci_regs[addr] = dev->base_irq; + return; + } +} + + +/* + * Return the 6-bit index into the multicast + * table. Stolen unashamedly from FreeBSD's if_ed.c + */ +static int +mcast_index(const void *dst) +{ +#define POLYNOMIAL 0x04c11db6 + unsigned long crc = 0xffffffffL; + int carry, i, j; + unsigned char b; + unsigned char *ep = (unsigned char *) dst; + + for (i = 6; --i >= 0;) + { + b = *ep++; + for (j = 8; --j >= 0;) + { + carry = ((crc & 0x80000000L) ? 1 : 0) ^ (b & 0x01); + crc <<= 1; + b >>= 1; + if (carry) + { + crc = ((crc ^ POLYNOMIAL) | carry); + } + } + } + return (crc >> 26); +#undef POLYNOMIAL +} + + +static void +nic_tx(nic_t *dev, uint32_t val) +{ + dev->CR.tx_packet = 0; + dev->TSR.tx_ok = 1; + dev->ISR.pkt_tx = 1; + + /* Generate an interrupt if not masked */ + if (dev->IMR.tx_inte) + nic_interrupt(dev, 1); + dev->tx_timer_active = 0; +} + + +/* + * Called by the platform-specific code when an Ethernet frame + * has been received. The destination address is tested to see + * if it should be accepted, and if the RX ring has enough room, + * it is copied into it and the receive process is updated. + */ +static void +nic_rx(void *priv, uint8_t *buf, int io_len) +{ + static uint8_t bcast_addr[6] = {0xff,0xff,0xff,0xff,0xff,0xff}; + nic_t *dev = (nic_t *)priv; + uint8_t pkthdr[4]; + uint8_t *startptr; + int pages, avail; + int idx, nextpage; + int endbytes; + + if (io_len != 60) + nelog(2, "%s: rx_frame with length %d\n", dev->name, io_len); + + if ((dev->CR.stop != 0) || (dev->page_start == 0)) return; + + /* + * Add the pkt header + CRC to the length, and work + * out how many 256-byte pages the frame would occupy. + */ + pages = (io_len + sizeof(pkthdr) + sizeof(uint32_t) + 255)/256; + if (dev->curr_page < dev->bound_ptr) { + avail = dev->bound_ptr - dev->curr_page; + } else { + avail = (dev->page_stop - dev->page_start) - + (dev->curr_page - dev->bound_ptr); + } + + /* + * Avoid getting into a buffer overflow condition by + * not attempting to do partial receives. The emulation + * to handle this condition seems particularly painful. + */ + if ((avail < pages) +#if NE2K_NEVER_FULL_RING + || (avail == pages) +#endif + ) { + nelog(1, "%s: no space\n", dev->name); + return; + } + + if ((io_len < 40/*60*/) && !dev->RCR.runts_ok) { + nelog(1, "%s: rejected small packet, length %d\n", dev->name, io_len); + return; + } + + /* Some computers don't care... */ + if (io_len < 60) + io_len = 60; + + nelog(2, "%s: RX %x:%x:%x:%x:%x:%x > %x:%x:%x:%x:%x:%x len %d\n", + dev->name, + buf[6], buf[7], buf[8], buf[9], buf[10], buf[11], + buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], + io_len); + + /* Do address filtering if not in promiscuous mode. */ + if (! dev->RCR.promisc) { + /* If this is a broadcast frame.. */ + if (! memcmp(buf, bcast_addr, 6)) { + /* Broadcast not enabled, we're done. */ + if (! dev->RCR.broadcast) { + nelog(2, "%s: RX BC disabled\n", dev->name); + return; + } + } + + /* If this is a multicast frame.. */ + else if (buf[0] & 0x01) { + /* Multicast not enabled, we're done. */ + if (! dev->RCR.multicast) { +#if 1 + nelog(2, "%s: RX MC disabled\n", dev->name); +#endif + return; + } + + /* Are we listening to this multicast address? */ + idx = mcast_index(buf); + if (! (dev->mchash[idx>>3] & (1<<(idx&0x7)))) { + nelog(2, "%s: RX MC not listed\n", dev->name); + return; + } + } + + /* Unicast, must be for us.. */ + else if (memcmp(buf, dev->physaddr, 6)) return; + } else { + nelog(2, "%s: RX promiscuous receive\n", dev->name); + } + + nextpage = dev->curr_page + pages; + if (nextpage >= dev->page_stop) + nextpage -= (dev->page_stop - dev->page_start); + + /* Set up packet header. */ + pkthdr[0] = 0x01; /* RXOK - packet is OK */ + if (buf[0] & 0x01) + pkthdr[0] |= 0x20; /* MULTICAST packet */ + pkthdr[1] = nextpage; /* ptr to next packet */ + pkthdr[2] = (io_len + sizeof(pkthdr))&0xff; /* length-low */ + pkthdr[3] = (io_len + sizeof(pkthdr))>>8; /* length-hi */ + nelog(2, "%s: RX pkthdr [%02x %02x %02x %02x]\n", + dev->name, pkthdr[0], pkthdr[1], pkthdr[2], pkthdr[3]); + + /* Copy into buffer, update curpage, and signal interrupt if config'd */ + startptr = &dev->mem[(dev->curr_page * 256) - NE2K_MEMSTART]; + memcpy(startptr, pkthdr, sizeof(pkthdr)); + if ((nextpage > dev->curr_page) || + ((dev->curr_page + pages) == dev->page_stop)) { + memcpy(startptr+sizeof(pkthdr), buf, io_len); + } else { + endbytes = (dev->page_stop - dev->curr_page) * 256; + memcpy(startptr+sizeof(pkthdr), buf, endbytes-sizeof(pkthdr)); + startptr = &dev->mem[(dev->page_start * 256) - NE2K_MEMSTART]; + memcpy(startptr, buf+endbytes-sizeof(pkthdr), io_len-endbytes+8); + } + dev->curr_page = nextpage; + + dev->RSR.rx_ok = 1; + dev->RSR.rx_mbit = (buf[0] & 0x01) ? 1 : 0; + dev->ISR.pkt_rx = 1; + + if (dev->IMR.rx_inte) + nic_interrupt(dev, 1); +} + + +static void +nic_rom_init(nic_t *dev, wchar_t *s) +{ + uint32_t temp; + FILE *f; + + if (s == NULL) + { + return; + } + + if (dev->bios_addr > 0) { + if ((f = romfopen(s, L"rb")) != NULL) { + fseek(f, 0L, SEEK_END); + temp = ftell(f); + fclose(f); + dev->bios_size = 0x10000; + if (temp <= 0x8000) + dev->bios_size = 0x8000; + if (temp <= 0x4000) + dev->bios_size = 0x4000; + if (temp <= 0x2000) + dev->bios_size = 0x2000; + dev->bios_mask = (dev->bios_size >> 8) & 0xff; + dev->bios_mask = (0x100 - dev->bios_mask) & 0xff; + } else { + dev->bios_addr = 0x00000; + dev->bios_size = 0; + return; + } + + /* Create a memory mapping for the space. */ + rom_init(&dev->bios_rom, s, dev->bios_addr, + dev->bios_size, dev->bios_size-1, 0, MEM_MAPPING_EXTERNAL); + } + + nelog(1, "%s: BIOS configured at %06lX (size %ld)\n", + dev->name, dev->bios_addr, dev->bios_size); +} + + +static void * +nic_init(int board) +{ + uint32_t mac; + wchar_t *rom; + nic_t *dev; + int i; + + /* Get the desired debug level. */ + i = device_get_config_int("debug"); + if (i > 0) nic_do_log = i; + + dev = malloc(sizeof(nic_t)); + memset(dev, 0x00, sizeof(nic_t)); + dev->board = board; + rom = NULL; + switch(dev->board) { + case NE2K_NE1000: + strcpy(dev->name, "NE1000"); + dev->maclocal[0] = 0x00; /* 00:00:D8 (NE1000 ISA OID) */ + dev->maclocal[1] = 0x00; + dev->maclocal[2] = 0xD8; + rom = ROM_PATH_NE1000; + break; + + case NE2K_NE2000: + strcpy(dev->name, "NE2000"); + dev->maclocal[0] = 0x00; /* 00:A0:0C (NE2000 compatible OID) */ + dev->maclocal[1] = 0xA0; + dev->maclocal[2] = 0x0C; + rom = ROM_PATH_NE2000; + break; + + case NE2K_RTL8029AS: + dev->is_pci = (PCI) ? 1 : 0; + strcpy(dev->name, "RTL8029AS"); + dev->maclocal[0] = 0x00; /* 00:20:18 (RTL 8029AS PCI OID) */ + dev->maclocal[1] = 0x20; + dev->maclocal[2] = 0x18; + rom = ROM_PATH_RTL8029; + break; + } + + if (dev->is_pci) { + dev->base_address = 0x340; + dev->base_irq = 10; + } else { + dev->base_address = device_get_config_hex16("base"); + dev->bios_addr = device_get_config_hex20("bios_addr"); + dev->base_irq = device_get_config_int("irq"); + } + + /* See if we have a local MAC address configured. */ + mac = device_get_config_mac("mac", -1); + + /* Make this device known to the I/O system. */ + nic_ioset(dev, dev->base_address); + + /* Set up our BIOS ROM space, if any. */ + nic_rom_init(dev, rom); + + if (dev->is_pci) { + /* + * Configure the PCI space registers. + * + * We do this here, so the I/O routines are generic. + */ + dev->pci_regs[0x00] = (PCI_VENDID&0xff); + dev->pci_regs[0x01] = (PCI_VENDID>>8); + dev->pci_regs[0x02] = (PCI_DEVID&0xff); + dev->pci_regs[0x03] = (PCI_DEVID>>8); + + dev->pci_regs[0x04] = 0x01; /* IOEN */ + dev->pci_regs[0x05] = 0x00; + dev->pci_regs[0x07] = 0x02; /* DST0, medium devsel */ + + dev->pci_regs[0x0B] = 0x02; /* BCR: Network Controller */ + dev->pci_regs[0x0A] = 0x00; /* SCR: Ethernet */ + + dev->pci_regs[0x2C] = (PCI_VENDID&0xff); + dev->pci_regs[0x2D] = (PCI_VENDID>>8); + dev->pci_regs[0x2E] = (PCI_DEVID&0xff); + dev->pci_regs[0x2F] = (PCI_DEVID>>8); + + dev->pci_regs[0x3D] = PCI_INTC; /* PCI_IPR */ + + /* Enable our address space in PCI. */ + dev->pci_bar[0].addr_regs[0] = 0x01; + + /* Enable our BIOS space in PCI, if needed. */ + if (dev->bios_addr > 0) { + dev->pci_bar[1].addr = 0x000F8000; + dev->pci_bar[1].addr_regs[1] = dev->bios_mask; + dev->pci_bar[1].addr |= 0x1801; + } else { + dev->pci_bar[1].addr = 0; + } + + /* Initialize the RTL8029 EEPROM. */ + memset(dev->eeprom, 0x00, sizeof(dev->eeprom)); + dev->eeprom[0x76] = + dev->eeprom[0x7A] = + dev->eeprom[0x7E] = (PCI_DEVID&0xff); + dev->eeprom[0x77] = + dev->eeprom[0x7B] = + dev->eeprom[0x7F] = (PCI_DEVID>>8); + dev->eeprom[0x78] = + dev->eeprom[0x7C] = (PCI_VENDID&0xff); + dev->eeprom[0x79] = + dev->eeprom[0x7D] = (PCI_VENDID>>8); + + /* Insert this device onto the PCI bus, keep its slot number. */ + dev->card = pci_add(nic_pci_read, nic_pci_write, dev); + } + + /* Set up our BIA. */ + if (mac & 0xff000000) { + /* Generate new local MAC. */ + dev->maclocal[3] = disc_random_generate(); + dev->maclocal[4] = disc_random_generate(); + dev->maclocal[5] = disc_random_generate(); + mac = (((int) dev->maclocal[3]) << 16); + mac |= (((int) dev->maclocal[4]) << 8); + mac |= ((int) dev->maclocal[5]); + device_set_config_mac("mac", mac); + } else { + dev->maclocal[3] = (mac>>16) & 0xff; + dev->maclocal[4] = (mac>>8) & 0xff; + dev->maclocal[5] = (mac & 0xff); + } + memcpy(dev->physaddr, dev->maclocal, sizeof(dev->maclocal)); + + nelog(0, "%s: I/O=%04x, IRQ=%d, MAC=%02x:%02x:%02x:%02x:%02x:%02x\n", + dev->name, dev->base_address, dev->base_irq, + dev->physaddr[0], dev->physaddr[1], dev->physaddr[2], + dev->physaddr[3], dev->physaddr[4], dev->physaddr[5]); + + /* Reset the board. */ + nic_reset(dev); + + if (network_attach(dev, dev->physaddr, nic_rx) < 0) { +#if 0 + msgbox_error_wstr(ghwnd, L"Unable to init platform network"); +#endif + nelog(0, "%s: unable to init platform network type %d\n", + dev->name, network_type); +#if 0 + /* + * To avoid crashes, we ignore the fact that even though + * there is no active platform support, we just continue + * initializing. If we return an error here, the device + * handling code will throw a fatal error... --FvK + */ + free(dev); + return(NULL); +#endif + } + + nelog(1, "%s: %s attached IO=0x%X IRQ=%d\n", dev->name, + dev->is_pci?"PCI":"ISA", dev->base_address, dev->base_irq); + + return(dev); +} + + +static void +nic_close(void *priv) +{ + nic_t *dev = (nic_t *)priv; + + /* Make sure the platform layer is shut down. */ + network_close(); + + nic_ioremove(dev, dev->base_address); + + free(dev); + + nelog(1, "%s: closed\n", dev->name); +} + + +static void * +ne1000_init(void) +{ + return(nic_init(NE2K_NE1000)); +} + + +static void * +ne2000_init(void) +{ + return(nic_init(NE2K_NE2000)); +} + + +static void * +rtl8029as_init(void) +{ + return(nic_init(NE2K_RTL8029AS)); +} + + +static device_config_t ne1000_config[] = +{ + { + "base", "Address", CONFIG_HEX16, "", 0x300, + { + { + "0x280", 0x280 + }, + { + "0x300", 0x300 + }, + { + "0x320", 0x320 + }, + { + "0x340", 0x340 + }, + { + "0x360", 0x360 + }, + { + "0x380", 0x380 + }, + { + "" + } + }, + }, + { + "irq", "IRQ", CONFIG_SELECTION, "", 3, + { + { + "IRQ 3", 3 + }, + { + "IRQ 5", 5 + }, + { + "IRQ 7", 7 + }, + { + "" + } + }, + }, + { + "mac", "MAC Address", CONFIG_MAC, "", -1 + }, + { + "bios_addr", "BIOS address", CONFIG_HEX20, "", 0, + { + { + "Disabled", 0x00000 + }, + { + "D000", 0xD0000 + }, + { + "D800", 0xD8000 + }, + { + "C800", 0xC8000 + }, + { + "" + } + }, + }, + { + "", "", -1 + } +}; + +static device_config_t ne2000_config[] = +{ + { + "base", "Address", CONFIG_HEX16, "", 0x300, + { + { + "0x280", 0x280 + }, + { + "0x300", 0x300 + }, + { + "0x320", 0x320 + }, + { + "0x340", 0x340 + }, + { + "0x360", 0x360 + }, + { + "0x380", 0x380 + }, + { + "" + } + }, + }, + { + "irq", "IRQ", CONFIG_SELECTION, "", 10, + { + { + "IRQ 3", 3 + }, + { + "IRQ 5", 5 + }, + { + "IRQ 7", 7 + }, + { + "IRQ 10", 10 + }, + { + "IRQ 11", 11 + }, + { + "" + } + }, + }, + { + "mac", "MAC Address", CONFIG_MAC, "", -1 + }, + { + "bios_addr", "BIOS address", CONFIG_HEX20, "", 0, + { + { + "Disabled", 0x00000 + }, + { + "D000", 0xD0000 + }, + { + "D800", 0xD8000 + }, + { + "C800", 0xC8000 + }, + { + "" + } + }, + }, + { + "", "", -1 + } +}; + +static device_config_t rtl8029as_config[] = +{ +#if 1 + /* + * WTF. + * Even though it is PCI, the user should still have control + * over whether or not it's Option ROM BIOS will be enabled + * or not. + */ + { + "bios_addr", "BIOS address", CONFIG_HEX20, "", 0, + { + { + "Disabled", 0x00000 + }, + { + "D000", 0xD0000 + }, + { + "D800", 0xD8000 + }, + { + "C800", 0xC8000 + }, + { + "" + } + }, + }, +#endif + { + "mac", "MAC Address", CONFIG_MAC, "", -1 + }, + { + "", "", -1 + } +}; + + + +device_t ne1000_device = { + "Novell NE1000", + 0, + ne1000_init, + nic_close, + NULL, + NULL, + NULL, + NULL, + ne1000_config +}; + +device_t ne2000_device = { + "Novell NE2000", + 0, + ne2000_init, + nic_close, + NULL, + NULL, + NULL, + NULL, + ne2000_config +}; + +device_t rtl8029as_device = { + "Realtek RTL8029AS", + 0, + rtl8029as_init, + nic_close, + NULL, + NULL, + NULL, + NULL, + rtl8029as_config +}; diff --git a/src/NETWORK/net_ne2000.h b/src/NETWORK/net_ne2000.h new file mode 100644 index 000000000..44dcc3311 --- /dev/null +++ b/src/NETWORK/net_ne2000.h @@ -0,0 +1,29 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Definitions for the NE2000 ethernet controller. + * + * Version: @(#)net_ne2000.h 1.0.3 2017/05/17 + * + * Author: Fred N. van Kempen, + */ +#ifndef NET_NE2000_H +# define NET_NE2000_H + + +#define NE2K_NE1000 1 /* 8bit ISA NE1000 */ +#define NE2K_NE2000 2 /* 16bit ISA NE2000 */ +#define NE2K_RTL8029AS 3 /* 32bi PCI Realtek 8029AS */ + + +extern device_t ne1000_device; +extern device_t ne2000_device; +extern device_t rtl8029as_device; + + +#endif /*NET_NE2000_H*/ diff --git a/src/NETWORK/net_pcap.c b/src/NETWORK/net_pcap.c new file mode 100644 index 000000000..324b368b3 --- /dev/null +++ b/src/NETWORK/net_pcap.c @@ -0,0 +1,278 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Handle WinPcap library processing. + * + * Version: @(#)net_pcap.c 1.0.5 2017/06/04 + * + * Author: Fred N. van Kempen, + */ +#include +#include +#include +#include +#include +#include "../ibm.h" +#include "../config.h" +#include "../device.h" +#include "network.h" +#include "../WIN/plat_dynld.h" +#include "../WIN/plat_thread.h" + + +static void *pcap_handle; /* handle to WinPcap DLL */ +static pcap_t *pcap; /* handle to WinPcap library */ +static thread_t *poll_tid; +static NETRXCB poll_rx; /* network RX function to call */ +static void *poll_arg; /* network RX function arg */ + + +/* Pointers to the real functions. */ +static const char *(*f_pcap_lib_version)(void); +static int (*f_pcap_findalldevs)(pcap_if_t **,char *); +static void (*f_pcap_freealldevs)(pcap_if_t *); +static pcap_t *(*f_pcap_open_live)(const char *,int,int,int,char *); +static int (*f_pcap_compile)(pcap_t *,struct bpf_program *, + const char *,int,bpf_u_int32); +static int (*f_pcap_setfilter)(pcap_t *,struct bpf_program *); +static const u_char *(*f_pcap_next)(pcap_t *,struct pcap_pkthdr *); +static int (*f_pcap_sendpacket)(pcap_t *,const u_char *,int); +static void (*f_pcap_close)(pcap_t *); +static dllimp_t pcap_imports[] = { + { "pcap_lib_version", &f_pcap_lib_version }, + { "pcap_findalldevs", &f_pcap_findalldevs }, + { "pcap_freealldevs", &f_pcap_freealldevs }, + { "pcap_open_live", &f_pcap_open_live }, + { "pcap_compile", &f_pcap_compile }, + { "pcap_setfilter", &f_pcap_setfilter }, + { "pcap_next", &f_pcap_next }, + { "pcap_sendpacket", &f_pcap_sendpacket }, + { "pcap_close", &f_pcap_close }, + { NULL, NULL }, +}; + + +/* Handle the receiving of frames from the channel. */ +static void +poll_thread(void *arg) +{ + uint8_t *mac = (uint8_t *)arg; + const uint8_t *data = NULL; + struct pcap_pkthdr h; + uint32_t mac_cmp32[2]; + uint16_t mac_cmp16[2]; + event_t *evt; + + pclog("PCAP: polling thread started, arg %08lx\n", arg); + + /* Create a waitable event. */ + evt = thread_create_event(); + + /* As long as the channel is open.. */ + while (pcap != NULL) { + /* Wait for the next packet to arrive. */ + data = f_pcap_next(pcap, &h); + if (data != NULL) { + /* Received MAC. */ + mac_cmp32[0] = *(uint32_t *)(data+6); + mac_cmp16[0] = *(uint16_t *)(data+10); + + /* Local MAC. */ + mac_cmp32[1] = *(uint32_t *)mac; + mac_cmp16[1] = *(uint16_t *)(mac+4); + if ((mac_cmp32[0] != mac_cmp32[1]) || + (mac_cmp16[0] != mac_cmp16[1])) { + if (poll_rx != NULL) + poll_rx(poll_arg, (uint8_t *)data, h.caplen); + } else { + /* Mark as invalid packet. */ + data = NULL; + } + } + + /* If we did not get anything, wait a while. */ + if (data == NULL) + thread_wait_event(evt, 10); + } + + thread_destroy_event(evt); + poll_tid = NULL; + + pclog("PCAP: polling stopped.\n"); +} + + +/* Initialize the (Win)Pcap module for use. */ +int +network_pcap_init(netdev_t *list) +{ + char errbuf[PCAP_ERRBUF_SIZE]; + pcap_if_t *devlist, *dev; + int i = 0; + + /* Local variables. */ + pcap = NULL; + + /* Try loading the DLL. */ + pcap_handle = dynld_module("wpcap.dll", pcap_imports); + if (pcap_handle == NULL) return(-1); + + /* Retrieve the device list from the local machine */ + if (f_pcap_findalldevs(&devlist, errbuf) == -1) { + pclog("PCAP: error in pcap_findalldevs: %s\n", errbuf); + return(-1); + } + + for (dev=devlist; dev!=NULL; dev=dev->next) { + strcpy(list->device, dev->name); + if (dev->description) + strcpy(list->description, dev->description); + else + memset(list->description, '\0', sizeof(list->description)); + list++; i++; + } + + /* Release the memory. */ + f_pcap_freealldevs(devlist); + + return(i); +} + + +/* Initialize the (Win)Pcap module for use. */ +void +network_pcap_reset(void) +{ + /* Try loading the DLL. */ + pcap_handle = dynld_module("wpcap.dll", pcap_imports); + return; +} + + +/* Initialize WinPcap for us. */ +int +network_pcap_setup(uint8_t *mac, NETRXCB func, void *arg) +{ + char temp[PCAP_ERRBUF_SIZE]; + char filter_exp[255]; + struct bpf_program fp; + char *dev; + + /* Did we already load the DLL? */ + if (pcap_handle == NULL) return(-1); + +#if 1 + /* Get the value of our capture interface. */ + dev = network_pcap; + if (dev == NULL) { + pclog(" PCap device is a null pointer!\n"); + return(-1); + } + if ((dev[0] == '\0') || !strcmp(dev, "none")) { + pclog(" No network device configured!\n"); + return(-1); + } + pclog(" Network interface: '%s'\n", dev); +#endif + + strcpy(temp, f_pcap_lib_version()); + dev = strchr(temp, '('); + if (dev != NULL) *(dev-1) = '\0'; + pclog("PCAP: initializing, %s\n", temp); + +#if 0 + /* Get the value of our capture interface. */ + dev = network_pcap; + if ((dev[0] == '\0') || !strcmp(dev, "none")) { + pclog(" No network device configured!\n"); + return(-1); + } + pclog(" Network interface: '%s'\n", dev); +#else + dev = network_pcap; +#endif + + pcap = f_pcap_open_live(dev, /* interface name */ + 1518, /* maximum packet size */ + 1, /* promiscuous mode? */ + 10, /* timeout in msec */ + temp); /* error buffer */ + if (pcap == NULL) { + pclog(" Unable to open device: %s!\n", temp); + return(-1); + } + + /* Create a MAC address based packet filter. */ + pclog(" Installing packet filter for MAC=%02x:%02x:%02x:%02x:%02x:%02x\n", + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + sprintf(filter_exp, + "( ((ether dst ff:ff:ff:ff:ff:ff) or (ether dst %02x:%02x:%02x:%02x:%02x:%02x)) and not (ether src %02x:%02x:%02x:%02x:%02x:%02x) )", + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5], + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + if (f_pcap_compile(pcap, &fp, filter_exp, 0, 0xffffffff) != -1) { + if (f_pcap_setfilter(pcap, &fp) == -1) + pclog(" Error installing filter (%s) !\n", filter_exp); + } else { + pclog(" Could not compile filter (%s) !\n", filter_exp); + } + + /* Save the callback info. */ + poll_rx = func; + poll_arg = arg; + + pclog(" Starting thread..\n"); + poll_tid = thread_create(poll_thread, mac); + + return(0); +} + + +/* Close up shop. */ +void +network_pcap_close(void) +{ + pcap_t *pc; + + if (pcap != NULL) { + pclog("Closing WinPcap\n"); + + /* Tell the polling thread to shut down. */ + pc = pcap; pcap = NULL; +#if 1 + /* Terminate the polling thread. */ + if (poll_tid != NULL) { + thread_kill(poll_tid); + poll_tid = NULL; + } +#else + /* Wait for the polling thread to shut down. */ + while (poll_tid != NULL) + ; +#endif + + /* OK, now shut down WinPcap itself. */ + f_pcap_close(pc); + + /* Unload the DLL if possible. */ + if (pcap_handle != NULL) { + dynld_close(pcap_handle); + pcap_handle = NULL; + } + } + poll_rx = NULL; + poll_arg = NULL; +} + + +/* Send a packet to the Pcap interface. */ +void +network_pcap_in(uint8_t *bufp, int len) +{ + if (pcap != NULL) + f_pcap_sendpacket(pcap, bufp, len); +} diff --git a/src/NETWORK/net_slirp.c b/src/NETWORK/net_slirp.c new file mode 100644 index 000000000..514845fdb --- /dev/null +++ b/src/NETWORK/net_slirp.c @@ -0,0 +1,194 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Handle SLiRP library processing. + * + * Version: @(#)net_slirp.c 1.0.4 2017/06/14 + * + * Author: Fred N. van Kempen, + */ +#include +#include +#include +#include +#include "slirp/slirp.h" +#include "slirp/queue.h" +#include "../ibm.h" +#include "../config.h" +#include "../device.h" +#include "network.h" +#include "../WIN/plat_thread.h" + + +static queueADT slirpq; /* SLiRP library handle */ +static thread_t *poll_tid; +static NETRXCB poll_rx; /* network RX function to call */ +static void *poll_arg; /* network RX function arg */ + + +/* Instead of calling this and crashing some times + or experencing jitter, this is called by the + 60Hz clock which seems to do the job. */ +static void +slirp_tic(void) +{ + int ret2, nfds; + struct timeval tv; + fd_set rfds, wfds, xfds; + int tmo; + + /* Let SLiRP create a list of all open sockets. */ + nfds = -1; + FD_ZERO(&rfds); + FD_ZERO(&wfds); + FD_ZERO(&xfds); + tmo = slirp_select_fill(&nfds, &rfds, &wfds, &xfds); /* this can crash */ + if (tmo < 0) + tmo = 500; + + tv.tv_sec = 0; + tv.tv_usec = tmo; + + /* Now wait for something to happen, or at most 'tmo' usec. */ + ret2 = select(nfds+1, &rfds, &wfds, &xfds, &tv); + + /* If something happened, let SLiRP handle it. */ + if (ret2 >= 0) + slirp_select_poll(&rfds, &wfds, &xfds); +} + + +/* Handle the receiving of frames. */ +static void +poll_thread(void *arg) +{ + struct queuepacket *qp; + event_t *evt; + + pclog("SLiRP: polling thread started, arg %08lx\n", arg); + + /* Create a waitable event. */ + evt = thread_create_event(); + + while (slirpq != NULL) { + /* See if there is any work. */ + slirp_tic(); + + /* Wait for the next packet to arrive. */ + if (QueuePeek(slirpq) == 0) { + /* If we did not get anything, wait a while. */ + thread_wait_event(evt, 10); + continue; + } + + /* Grab a packet from the queue. */ + qp = QueueDelete(slirpq); +#if 0 + pclog("SLiRP: inQ:%d got a %dbyte packet @%08lx\n", + QueuePeek(slirpq), qp->len, qp); +#endif + + if (poll_rx != NULL) + poll_rx(poll_arg, (uint8_t *)&qp->data, qp->len); + + /* Done with this one. */ + free(qp); + } + + thread_destroy_event(evt); + poll_tid = NULL; + + pclog("SLiRP: polling stopped.\n"); +} + + +/* Initialize SLiRP for us. */ +int +network_slirp_setup(uint8_t *mac, NETRXCB func, void *arg) +{ + pclog("SLiRP: initializing..\n"); + + if (slirp_init() != 0) { + pclog("SLiRP could not be initialized!\n"); + return(-1); + } + + slirpq = QueueCreate(); + pclog(" Packet queue is at %08lx\n", &slirpq); + + /* Save the callback info. */ + poll_rx = func; + poll_arg = arg; + + pclog("SLiRP: starting thread..\n"); + poll_tid = thread_create(poll_thread, mac); + + return(0); +} + + +void +network_slirp_close(void) +{ + queueADT sl; + + if (slirpq != NULL) { + pclog("Closing SLiRP\n"); + + /* Tell the polling thread to shut down. */ + sl = slirpq; slirpq = NULL; +#if 1 + /* Terminate the polling thread. */ + if (poll_tid != NULL) { + thread_kill(poll_tid); + poll_tid = NULL; + } +#else + /* Wait for the polling thread to shut down. */ + while (poll_tid != NULL) + ; +#endif + + /* OK, now shut down SLiRP itself. */ + QueueDestroy(sl); + slirp_exit(0); + } + + poll_rx = NULL; + poll_arg = NULL; +} + + +/* Send a packet to the SLiRP interface. */ +void +network_slirp_in(uint8_t *pkt, int pkt_len) +{ + if (slirpq != NULL) + slirp_input((const uint8_t *)pkt, pkt_len); +} + + +void +slirp_output(const uint8_t *pkt, int pkt_len) +{ + struct queuepacket *qp; + + if (slirpq != NULL) { + qp = (struct queuepacket *)malloc(sizeof(struct queuepacket)); + qp->len = pkt_len; + memcpy(qp->data, pkt, pkt_len); + QueueEnter(slirpq, qp); + } +} + + +int +slirp_can_output(void) +{ + return((slirpq != NULL)?1:0); +} diff --git a/src/NETWORK/network.c b/src/NETWORK/network.c new file mode 100644 index 000000000..87d2613ac --- /dev/null +++ b/src/NETWORK/network.c @@ -0,0 +1,269 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Implementation of the network module. + * + * NOTE The definition of the netcard_t is currently not optimal; + * it should be malloc'ed and then linked to the NETCARD def. + * Will be done later. + * + * Version: @(#)network.c 1.0.10 2017/06/14 + * + * Author: Fred N. van Kempen, + */ +#include +#include +#include +#include +#include "../ibm.h" +#include "../device.h" +#include "network.h" +#include "net_ne2000.h" +#include "../WIN/plat_ui.h" + + +static netcard_t net_cards[] = { + { "None", "none", NULL, + NULL, NULL }, + { "Novell NE1000", "ne1k", &ne1000_device, + NULL, NULL }, + { "Novell NE2000", "ne2k", &ne2000_device, + NULL, NULL }, + { "Realtek RTL8029AS", "ne2kpci", &rtl8029as_device, + NULL, NULL }, + { "", "", NULL, + NULL, NULL } +}; + + +/* Global variables. */ +int network_card; +int network_type; +int network_ndev; +int nic_do_log; +netdev_t network_devs[32]; +char network_pcap[512]; + + +/* + * Initialize the configured network cards. + * + * This function gets called only once, from the System + * Platform initialization code (currently in pc.c) to + * set our local stuff to a known state. + */ +void +network_init(void) +{ + int i; + +#if ENABLE_NIC_LOG + nic_do_log = ENABLE_NIC_LOG; +#else + nic_do_log = 0; +#endif + +#if 0 + network_type = NET_TYPE_NONE; + network_card = 0; +#endif + + /* Create a first device entry that's always there, as needed by UI. */ + strcpy(network_devs[0].device, "none"); + strcpy(network_devs[0].description, "None"); + network_ndev = 1; + + /* Initialize the Pcap system module, if present. */ + i = network_pcap_init(&network_devs[network_ndev]); + if (i > 0) + network_ndev += i; + + if (network_type != NET_TYPE_PCAP) + network_pcap_close(); +} + + +/* + * Attach a network card to the system. + * + * This function is called by a hardware driver ("card") after it has + * finished initializing itself, to link itself to the platform support + * modules. + */ +int +network_attach(void *dev, uint8_t *mac, NETRXCB rx) +{ + int ret = -1; + + if (network_card == 0) return(ret); + + /* Save the card's callback info. */ + net_cards[network_card].private = dev; + net_cards[network_card].rx = rx; + + /* Start the platform module. */ + switch(network_type) { + case NET_TYPE_PCAP: + ret = network_pcap_setup(mac, rx, dev); + if (ret < 0) { + plat_msgbox_error(IDS_2219); + network_type = NET_TYPE_NONE; + } + break; + + case NET_TYPE_SLIRP: + ret = network_slirp_setup(mac, rx, dev); + break; + } + + return(ret); +} + + +/* Stop any network activity. */ +void +network_close(void) +{ + switch(network_type) { + case NET_TYPE_PCAP: + network_pcap_close(); + break; + + case NET_TYPE_SLIRP: + network_slirp_close(); + break; + } + +} + + +/* + * Reset the network card(s). + * + * This function is called each time the system is reset, + * either a hard reset (including power-up) or a soft reset + * including C-A-D reset.) It is responsible for connecting + * everything together. + */ +void +network_reset(void) +{ + pclog("NETWORK: reset (type=%d, card=%d)\n", network_type, network_card); + + /* Just in case.. */ + network_close(); + + /* If no active card, we're done. */ + if ((network_type==NET_TYPE_NONE) || (network_card==0)) return; + + if (network_type==NET_TYPE_PCAP) network_pcap_reset(); + + pclog("NETWORK: set up for %s, card='%s'\n", + (network_type==NET_TYPE_SLIRP)?"SLiRP":"WinPcap", + net_cards[network_card].name); + + /* Add the (new?) card to the I/O system. */ + if (net_cards[network_card].device) { + pclog("NETWORK: adding device '%s'\n", + net_cards[network_card].name); + device_add(net_cards[network_card].device); + } +} + + +/* Transmit a packet to one of the network providers. */ +void +network_tx(uint8_t *bufp, int len) +{ + switch(network_type) { + case NET_TYPE_PCAP: + network_pcap_in(bufp, len); + break; + + case NET_TYPE_SLIRP: + network_slirp_in(bufp, len); + break; + } +} + + +/* UI */ +int +network_card_available(int card) +{ + if (net_cards[card].device) + return(device_available(net_cards[card].device)); + + return(1); +} + + +/* UI */ +char * +network_card_getname(int card) +{ + return(net_cards[card].name); +} + + +/* UI */ +device_t * +network_card_getdevice(int card) +{ + return(net_cards[card].device); +} + + +/* UI */ +int +network_card_has_config(int card) +{ + if (! net_cards[card].device) return(0); + + return(net_cards[card].device->config ? 1 : 0); +} + + +/* UI */ +char * +network_card_get_internal_name(int card) +{ + return(net_cards[card].internal_name); +} + + +/* UI */ +int +network_card_get_from_internal_name(char *s) +{ + int c = 0; + + while (strlen(net_cards[c].internal_name)) { + if (! strcmp(net_cards[c].internal_name, s)) + return(c); + c++; + } + + return(-1); +} + + +int +network_dev_to_id(char *dev) +{ + int i = 0; + + for (i=0; i + */ +#ifndef EMU_NETWORK_H +# define EMU_NETWORK_H +# include + + +/* Network provider types. */ +#define NET_TYPE_NONE 0 /* networking disabled */ +#define NET_TYPE_PCAP 1 /* use the (Win)Pcap API */ +#define NET_TYPE_SLIRP 2 /* use the SLiRP port forwarder */ + +/* Supported network cards. */ +#define NE1000 1 +#define NE2000 2 +#define RTL8029AS 3 + + +typedef void (*NETRXCB)(void *, uint8_t *, int); + + +typedef struct { + char name[64]; + char internal_name[32]; + device_t *device; + void *private; + int (*poll)(void *); + NETRXCB rx; +} netcard_t; + +typedef struct { + char device[128]; + char description[128]; +} netdev_t; + + +/* Global variables. */ +extern int nic_do_log; +extern int network_card; +extern int network_type; +extern int network_ndev; +extern netdev_t network_devs[32]; +extern char network_pcap[512]; + + +/* Function prototypes. */ +extern void network_init(void); +extern int network_attach(void *, uint8_t *, NETRXCB); +extern void network_close(void); +extern void network_reset(void); +extern void network_tx(uint8_t *, int); + +extern int network_pcap_init(netdev_t *); +extern void network_pcap_reset(void); +extern int network_pcap_setup(uint8_t *, NETRXCB, void *); +extern void network_pcap_close(void); +extern void network_pcap_in(uint8_t *, int); + +extern int network_slirp_setup(uint8_t *, NETRXCB, void *); +extern void network_slirp_close(void); +extern void network_slirp_in(uint8_t *, int); + +extern int network_dev_to_id(char *); +extern int network_card_available(int); +extern char *network_card_getname(int); +extern int network_card_has_config(int); +extern char *network_card_get_internal_name(int); +extern int network_card_get_from_internal_name(char *); +extern device_t *network_card_getdevice(int); + + +#endif /*EMU_NETWORK_H*/ diff --git a/src/NETWORK/pcap_if.c b/src/NETWORK/pcap_if.c new file mode 100644 index 000000000..31ec33f7d --- /dev/null +++ b/src/NETWORK/pcap_if.c @@ -0,0 +1,267 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Simple program to show usage of WinPcap. + * + * Based on the "libpcap" examples. + * + * Version: @(#)pcap_if.c 1.0.3 2017/06/04 + * + * Author: Fred N. van Kempen, + */ +#include +#include +#include +#include +#include +#include "plat_dynld.h" + + +static void *pcap_handle; /* handle to WinPcap DLL */ + + +/* Pointers to the real functions. */ +static int (*f_pcap_findalldevs)(pcap_if_t **,char *); +static void (*f_pcap_freealldevs)(pcap_if_t *); +static pcap_t *(*f_pcap_open_live)(const char *,int,int,int,char *); +static int (*f_pcap_next_ex)(pcap_t*,struct pcap_pkthdr**,const unsigned char**); +static void (*f_pcap_close)(pcap_t *); +static dllimp_t pcap_imports[] = { + { "pcap_findalldevs", &f_pcap_findalldevs }, + { "pcap_freealldevs", &f_pcap_freealldevs }, + { "pcap_open_live", &f_pcap_open_live }, + { "pcap_next_ex", &f_pcap_next_ex }, + { "pcap_close", &f_pcap_close }, + { NULL, NULL }, +}; + + +typedef struct { + char device[128]; + char description[128]; +} dev_t; + + +/* Retrieve an easy-to-use list of devices. */ +static int +get_devlist(dev_t *list) +{ + char errbuf[PCAP_ERRBUF_SIZE]; + pcap_if_t *devlist, *dev; + int i = 0; + + /* Retrieve the device list from the local machine */ + if (f_pcap_findalldevs(&devlist, errbuf) == -1) { + fprintf(stderr,"Error in pcap_findalldevs_ex: %s\n", errbuf); + return(-1); + } + + for (dev=devlist; dev!=NULL; dev=dev->next) { + strcpy(list->device, dev->name); + if (dev->description) + strcpy(list->description, dev->description); + else + memset(list->description, '\0', sizeof(list->description)); + list++; + i++; + } + + /* Release the memory. */ + f_pcap_freealldevs(devlist); + + return(i); +} + + +/* Simple HEXDUMP routine for raw data. */ +static void +hex_dump(unsigned char *bufp, int len) +{ + char asci[20]; + unsigned char c; + long addr; + + addr = 0; + while (len-- > 0) { + c = bufp[addr]; + if ((addr % 16) == 0) + printf("%04lx %02x", addr, c); + else + printf(" %02x", c); + asci[(addr & 15)] = (uint8_t)isprint(c) ? c : '.'; + if ((++addr % 16) == 0) { + asci[16] = '\0'; + printf(" | %s |\n", asci); + } + } + + if (addr % 16) { + while (addr % 16) { + printf(" "); + asci[(addr & 15)] = ' '; + addr++; + } + asci[16] = '\0'; + printf(" | %s |\n", asci); + } +} + + +/* Print a standard Ethernet MAC address. */ +static void +eth_praddr(unsigned char *ptr) +{ + printf("%02x:%02x:%02x:%02x:%02x:%02x", + ptr[0], ptr[1], ptr[2], ptr[3], ptr[4], ptr[5]); +} + + +/* Print a standard Ethernet header. */ +static int +eth_prhdr(unsigned char *ptr) +{ + unsigned short type; + + printf("Ethernet "); + eth_praddr(ptr+6); + printf(" > "); + eth_praddr(ptr); + type = (ptr[12] << 8) | ptr[13]; + printf(" type %04x\n", type); + + return(14); +} + + +/* Capture packets from the network, and print them. */ +static int +start_cap(char *dev) +{ + char temp[PCAP_ERRBUF_SIZE]; + struct pcap_pkthdr *hdr; + const unsigned char *pkt; + struct tm *ltime; + time_t now; + pcap_t *pcap; + int rc; + + /* Open the device for reading from it. */ + pcap = f_pcap_open_live(dev, + 1518, /* MTU */ + 1, /* promisc mode */ + 10, /* timeout */ + temp); + if (pcap == NULL) { + fprintf(stderr, "Pcap: open_live(%s): %s\n", dev, temp); + return(2); + } + + printf("Listening on '%s'..\n", dev); + for (;;) { + rc = f_pcap_next_ex(pcap, &hdr, &pkt); + if (rc < 0) break; + + /* Did we time out? */ + if (rc == 0) continue; + + /* Convert the timestamp to readable format. */ + now = hdr->ts.tv_sec; + ltime = localtime(&now); + strftime(temp, sizeof(temp), "%H:%M:%S", ltime); + + /* Process and print the packet. */ + printf("\n<< %s,%.6ld len=%u\n", + temp, hdr->ts.tv_usec, hdr->len); + rc = eth_prhdr((unsigned char *)pkt); + hex_dump((unsigned char *)pkt+rc, hdr->len-rc); + } + + /* All done, close up. */ + f_pcap_close(pcap); + + return(0); +} + + +/* Show a list of available network interfaces. */ +static void +show_devs(dev_t *list, int num) +{ + int i; + + if (num > 0) { + printf("Available network interfaces:\n\n"); + + for (i=0; idevice); + if (list->description[0] != '\0') + printf(" (%s)\n", list->description); + else + printf(" (No description available)\n"); + list++; + printf("\n"); + } + } else { + printf("No interfaces found!\nMake sure WinPcap is installed.\n"); + } +} + + +void +pclog(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); +} + + +int +main(int argc, char **argv) +{ + dev_t interfaces[32]; + int numdev, i; + + /* Try loading the DLL. */ + pcap_handle = dynld_module("wpcap.dll", pcap_imports); + if (pcap_handle == NULL) { + fprintf(stderr, "Unable to load WinPcap DLL !\n"); + return(1); + } + + /* Get the list. */ + numdev = get_devlist(interfaces); + + if (argc == 1) { + /* No arguments, just show the list. */ + show_devs(interfaces, numdev); + + dynld_close(pcap_handle); + + return(numdev); + } + + /* Assume argument to be the interface number to listen on. */ + i = atoi(argv[1]); + if (i < 0 || i > numdev) { + fprintf(stderr, "Invalid interface number %d !\n", i); + + dynld_close(pcap_handle); + + return(1); + } + + /* Looks good, go and listen.. */ + i = start_cap(interfaces[i-1].device); + + dynld_close(pcap_handle); + + return(i); +} diff --git a/src/slirp/COPYRIGHT.txt b/src/NETWORK/slirp/COPYRIGHT.txt similarity index 100% rename from src/slirp/COPYRIGHT.txt rename to src/NETWORK/slirp/COPYRIGHT.txt diff --git a/src/slirp/VERSION.txt b/src/NETWORK/slirp/VERSION.txt similarity index 100% rename from src/slirp/VERSION.txt rename to src/NETWORK/slirp/VERSION.txt diff --git a/src/slirp/bootp.c b/src/NETWORK/slirp/bootp.c similarity index 100% rename from src/slirp/bootp.c rename to src/NETWORK/slirp/bootp.c diff --git a/src/slirp/bootp.h b/src/NETWORK/slirp/bootp.h similarity index 100% rename from src/slirp/bootp.h rename to src/NETWORK/slirp/bootp.h diff --git a/src/slirp/cksum.c b/src/NETWORK/slirp/cksum.c similarity index 100% rename from src/slirp/cksum.c rename to src/NETWORK/slirp/cksum.c diff --git a/src/slirp/config-host.h b/src/NETWORK/slirp/config-host.h similarity index 100% rename from src/slirp/config-host.h rename to src/NETWORK/slirp/config-host.h diff --git a/src/slirp/config.h b/src/NETWORK/slirp/config.h similarity index 100% rename from src/slirp/config.h rename to src/NETWORK/slirp/config.h diff --git a/src/slirp/ctl.h b/src/NETWORK/slirp/ctl.h similarity index 100% rename from src/slirp/ctl.h rename to src/NETWORK/slirp/ctl.h diff --git a/src/slirp/debug.c b/src/NETWORK/slirp/debug.c similarity index 100% rename from src/slirp/debug.c rename to src/NETWORK/slirp/debug.c diff --git a/src/slirp/debug.h b/src/NETWORK/slirp/debug.h similarity index 97% rename from src/slirp/debug.h rename to src/NETWORK/slirp/debug.h index 9a8c5e8c8..a1eafa130 100644 --- a/src/slirp/debug.h +++ b/src/NETWORK/slirp/debug.h @@ -37,7 +37,6 @@ extern int slirp_debug; #endif void debug_init _P((char *, int)); -//void ttystats _P((struct ttys *)); void allttystats _P((void)); void ipstats _P((void)); void vjstats _P((void)); diff --git a/src/slirp/icmp_var.h b/src/NETWORK/slirp/icmp_var.h similarity index 100% rename from src/slirp/icmp_var.h rename to src/NETWORK/slirp/icmp_var.h diff --git a/src/slirp/if.c b/src/NETWORK/slirp/if.c similarity index 100% rename from src/slirp/if.c rename to src/NETWORK/slirp/if.c diff --git a/src/slirp/if.h b/src/NETWORK/slirp/if.h similarity index 100% rename from src/slirp/if.h rename to src/NETWORK/slirp/if.h diff --git a/src/slirp/ip.h b/src/NETWORK/slirp/ip.h similarity index 100% rename from src/slirp/ip.h rename to src/NETWORK/slirp/ip.h diff --git a/src/slirp/ip_icmp.c b/src/NETWORK/slirp/ip_icmp.c similarity index 100% rename from src/slirp/ip_icmp.c rename to src/NETWORK/slirp/ip_icmp.c diff --git a/src/slirp/ip_icmp.h b/src/NETWORK/slirp/ip_icmp.h similarity index 100% rename from src/slirp/ip_icmp.h rename to src/NETWORK/slirp/ip_icmp.h diff --git a/src/slirp/ip_input.c b/src/NETWORK/slirp/ip_input.c similarity index 99% rename from src/slirp/ip_input.c rename to src/NETWORK/slirp/ip_input.c index fb8f3fcf1..62fd5d202 100644 --- a/src/slirp/ip_input.c +++ b/src/NETWORK/slirp/ip_input.c @@ -37,7 +37,6 @@ * Please read the file COPYRIGHT for the * terms and conditions of the copyright. */ - #include "slirp.h" #include "ip_icmp.h" diff --git a/src/slirp/ip_output.c b/src/NETWORK/slirp/ip_output.c similarity index 100% rename from src/slirp/ip_output.c rename to src/NETWORK/slirp/ip_output.c diff --git a/src/slirp/libslirp.h b/src/NETWORK/slirp/libslirp.h similarity index 100% rename from src/slirp/libslirp.h rename to src/NETWORK/slirp/libslirp.h diff --git a/src/slirp/main.h b/src/NETWORK/slirp/main.h similarity index 100% rename from src/slirp/main.h rename to src/NETWORK/slirp/main.h diff --git a/src/slirp/mbuf.c b/src/NETWORK/slirp/mbuf.c similarity index 100% rename from src/slirp/mbuf.c rename to src/NETWORK/slirp/mbuf.c diff --git a/src/slirp/mbuf.h b/src/NETWORK/slirp/mbuf.h similarity index 100% rename from src/slirp/mbuf.h rename to src/NETWORK/slirp/mbuf.h diff --git a/src/slirp/misc.c b/src/NETWORK/slirp/misc.c similarity index 98% rename from src/slirp/misc.c rename to src/NETWORK/slirp/misc.c index 88c0c13e0..90bc2483e 100644 --- a/src/slirp/misc.c +++ b/src/NETWORK/slirp/misc.c @@ -82,6 +82,10 @@ inet_aton(cp, ia) } #endif + +extern void pclog(char *fmt, ...); + + /* * Get our IP address and put it in our_addr */ @@ -91,14 +95,14 @@ getouraddr() char buff[512]; struct hostent *he = NULL; #define ANCIENT - #ifdef ANCIENT - if (gethostname(&buff,500) == 0) - he = gethostbyname(&buff); +#ifdef ANCIENT + if (gethostname(buff,500) == 0) + he = gethostbyname(buff); if (he) our_addr = *(struct in_addr *)he->h_addr; if (our_addr.s_addr == 0) our_addr.s_addr = loopback_addr.s_addr; - #else +#else if (gethostname(buff,256) == 0) { struct addrinfo hints = { 0 }; @@ -113,8 +117,9 @@ getouraddr() } if (our_addr.s_addr == 0) our_addr.s_addr = loopback_addr.s_addr; - #endif - #undef ANCIENT +#endif +#undef ANCIENT + pclog(" Our IP address: %s (%s)\n", inet_ntoa(our_addr), buff); } //#if SIZEOF_CHAR_P == 8 diff --git a/src/slirp/misc.h b/src/NETWORK/slirp/misc.h similarity index 100% rename from src/slirp/misc.h rename to src/NETWORK/slirp/misc.h diff --git a/src/slirp/queue.c b/src/NETWORK/slirp/queue.c similarity index 100% rename from src/slirp/queue.c rename to src/NETWORK/slirp/queue.c diff --git a/src/slirp/queue.h b/src/NETWORK/slirp/queue.h similarity index 98% rename from src/slirp/queue.h rename to src/NETWORK/slirp/queue.h index 534dcb84b..786950ab7 100644 --- a/src/slirp/queue.h +++ b/src/NETWORK/slirp/queue.h @@ -96,4 +96,6 @@ queueElementT QueueDelete(queueADT queue); int QueueIsEmpty(queueADT queue); int QueueIsFull(queueADT queue); +int QueuePeek(queueADT queue); + #endif /* not defined _QUEUE_H */ diff --git a/src/slirp/sbuf.c b/src/NETWORK/slirp/sbuf.c similarity index 100% rename from src/slirp/sbuf.c rename to src/NETWORK/slirp/sbuf.c diff --git a/src/slirp/sbuf.h b/src/NETWORK/slirp/sbuf.h similarity index 100% rename from src/slirp/sbuf.h rename to src/NETWORK/slirp/sbuf.h diff --git a/src/slirp/slirp.c b/src/NETWORK/slirp/slirp.c similarity index 91% rename from src/slirp/slirp.c rename to src/NETWORK/slirp/slirp.c index 8725b8922..3068dc72c 100644 --- a/src/slirp/slirp.c +++ b/src/NETWORK/slirp/slirp.c @@ -1,22 +1,20 @@ #include "slirp.h" -/* host address */ -struct in_addr our_addr; -/* host dns address */ -struct in_addr dns_addr; -/* host loopback address */ -struct in_addr loopback_addr; -/* address for slirp virtual addresses */ -struct in_addr special_addr; -/* virtual address alias for host */ -struct in_addr alias_addr; +/* Our actual addresses. */ +char slirp_hostname[33]; +struct in_addr our_addr; /* host IP address */ +struct in_addr dns_addr; /* host DNS server */ +struct in_addr loopback_addr; /* host loopback address */ +/* Our SLiRP virtual addresses. */ +struct in_addr special_addr; /* virtual IP address */ +struct in_addr alias_addr; /* virtual address alias for host */ const uint8_t special_ethaddr[6] = { - 0x52, 0x54, 0x00, 0x12, 0x35, 0x00 + 0x52, 0x54, 0x00, 0x12, 0x35, 0x00 /* virtual MAC address. */ }; -uint8_t client_ethaddr[6]; +uint8_t client_ethaddr[6]; /* guest's MAC address */ int do_slowtimo; int link_up; @@ -27,10 +25,14 @@ struct ex_list *exec_list; /* XXX: suppress those select globals */ fd_set *global_readfds, *global_writefds, *global_xfds; -char slirp_hostname[33]; + +extern void pclog(const char *, ...); +extern int config_get_int(char *, char *, int); + +#define printf pclog + #ifdef _WIN32 - static int get_dns_addr(struct in_addr *pdns_addr) { FIXED_INFO *FixedInfo=NULL; @@ -62,16 +64,11 @@ static int get_dns_addr(struct in_addr *pdns_addr) pIPAddr = &(FixedInfo->DnsServerList); inet_aton(pIPAddr->IpAddress.String, &tmp_addr); *pdns_addr = tmp_addr; -#if 0 - printf( "DNS Servers:\n" ); - printf( "DNS Addr:%s\n", pIPAddr->IpAddress.String ); - - pIPAddr = FixedInfo -> DnsServerList.Next; + printf( " DNS Servers:\n" ); while ( pIPAddr ) { - printf( "DNS Addr:%s\n", pIPAddr ->IpAddress.String ); + printf( " Address: %s\n", pIPAddr ->IpAddress.String ); pIPAddr = pIPAddr ->Next; } -#endif if (FixedInfo) { GlobalFree(FixedInfo); FixedInfo = NULL; @@ -117,9 +114,9 @@ static int get_dns_addr(struct in_addr *pdns_addr) return -1; return 0; } - #endif + #ifdef _WIN32 void slirp_cleanup(void) { @@ -127,13 +124,17 @@ void slirp_cleanup(void) } #endif -int slirp_init(void) + +int +slirp_init(void) { - struct in_addr myaddr; - int rc; - char* category = "SLiRP Port Forwarding"; - char key[32]; - int i = 0, udp, from, to; + char* category = "SLiRP Port Forwarding"; + char key[32]; + struct in_addr myaddr; + int i = 0, udp, from, to; + int rc; + + pclog("%s initializing..\n", category); #ifdef SLIRP_DEBUG // debug_init("/tmp/slirp.log", DEBUG_DEFAULT); @@ -165,29 +166,28 @@ debug_init("slirplog.txt",DEBUG_DEFAULT); return -1; inet_aton(CTL_SPECIAL, &special_addr); - alias_addr.s_addr = special_addr.s_addr | htonl(CTL_ALIAS); - getouraddr(); + alias_addr.s_addr = special_addr.s_addr | htonl(CTL_ALIAS); + getouraddr(); + inet_aton(CTL_LOCAL, &myaddr); - inet_aton("10.0.2.15",&myaddr); + while (1) { + sprintf(key, "%d_udp", i); + udp = config_get_int(category, key, 0); + sprintf(key, "%d_from", i); + from = config_get_int(category, key, 0); + if (from < 1) + break; + sprintf(key, "%d_to", i); + to = config_get_int(category, key, from); - while (1) { - sprintf(key, "%d_udp", i); - udp = config_get_int(category, key, 0); - sprintf(key, "%d_from", i); - from = config_get_int(category, key, 0); - if (from < 1) - break; - sprintf(key, "%d_to", i); - to = config_get_int(category, key, from); + rc = slirp_redir(udp, from, myaddr, to); + if (rc == 0) + pclog("slirp redir %d -> %d successful\n", from, to); + else + pclog("slirp redir %d -> %d failed (%d)\n", from, to, rc); - rc = slirp_redir(udp, from, myaddr, to); - if (rc == 0) - pclog("slirp redir %d -> %d successful\n", from, to); - else - pclog("slirp redir %d -> %d failed (%d)\n", from, to, rc); - - i++; - } + i++; + } return 0; } @@ -464,7 +464,7 @@ void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds) //winsock2.h:549:32: note: expected 'const char *' but argument is of type 'int *' //WINSOCK_API_LINKAGE int PASCAL send(SOCKET,const char*,int,int); JASON //ret = send(so->s, "a", 1, 0); WHY THE HELL WAS THIS HERE?! - ret = send(so->s, &ret, 0, 0); //This is what it should be. + ret = send(so->s, (char *)&ret, 0, 0); //This is what it should be. if (ret < 0) { /* XXXXX Must fix, zero bytes is a NOP */ if (errno == EAGAIN || errno == EWOULDBLOCK || @@ -510,7 +510,7 @@ void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds) /* tcp_input will take care of it */ } else { - ret = send(so->s, &ret, 0,0); + ret = send(so->s, (char *)&ret, 0,0); if (ret < 0) { /* XXX */ if (errno == EAGAIN || errno == EWOULDBLOCK || diff --git a/src/slirp/slirp.h b/src/NETWORK/slirp/slirp.h similarity index 95% rename from src/slirp/slirp.h rename to src/NETWORK/slirp/slirp.h index 92cfe2fc9..3f4efd0bd 100644 --- a/src/slirp/slirp.h +++ b/src/NETWORK/slirp/slirp.h @@ -12,7 +12,7 @@ #include "slirp_config.h" #ifdef _WIN32 -#ifdef __GNUC__ //MINGW? +#ifdef __GNUC__ /* MINGW? */ # include typedef uint8_t u_int8_t; typedef uint16_t u_int16_t; @@ -39,7 +39,7 @@ typedef unsigned long ioctlsockopt_t; #endif -# include //needs to be on top otherwise, it'll pull in winsock1 +# include /* needs to be on top otherwise, it'll pull in winsock1 */ # include # include @@ -243,8 +243,6 @@ int inet_aton _P((const char *cp, struct in_addr *ia)); #define PACK_END 0 #define PACKED__ #elif _MSC_VER -//#define PRAGMA_PACK_SUPPORTED 1 -//#define PACK_END 4 #define PACKED__ #else #error "Packed attribute or pragma shall be supported" @@ -323,15 +321,20 @@ void lprint _P((const char *, ...)); extern int do_echo; #ifdef _MSC_VER -#define inline +#define __inline #endif #if SIZEOF_CHAR_P == 4 # define insque_32 insque # define remque_32 remque #else - extern inline void insque_32 _P((void *, void *)); - extern inline void remque_32 _P((void *)); +# ifdef NEED_QUE32_INLINE +extern __inline void insque_32 _P((void *, void *)); +extern __inline void remque_32 _P((void *)); +# else +extern void insque_32 _P((void *, void *)); +extern void remque_32 _P((void *)); +# endif #endif #ifndef _WIN32 diff --git a/src/slirp/slirp_config.h b/src/NETWORK/slirp/slirp_config.h similarity index 100% rename from src/slirp/slirp_config.h rename to src/NETWORK/slirp/slirp_config.h diff --git a/src/slirp/socket.c b/src/NETWORK/slirp/socket.c similarity index 100% rename from src/slirp/socket.c rename to src/NETWORK/slirp/socket.c diff --git a/src/slirp/socket.h b/src/NETWORK/slirp/socket.h similarity index 100% rename from src/slirp/socket.h rename to src/NETWORK/slirp/socket.h diff --git a/src/slirp/tcp.h b/src/NETWORK/slirp/tcp.h similarity index 100% rename from src/slirp/tcp.h rename to src/NETWORK/slirp/tcp.h diff --git a/src/slirp/tcp_input.c b/src/NETWORK/slirp/tcp_input.c similarity index 99% rename from src/slirp/tcp_input.c rename to src/NETWORK/slirp/tcp_input.c index 77006a2d7..97187788d 100644 --- a/src/slirp/tcp_input.c +++ b/src/NETWORK/slirp/tcp_input.c @@ -37,7 +37,6 @@ * Please read the file COPYRIGHT for the * terms and conditions of the copyright. */ - #include #include "slirp.h" #include "ip_icmp.h" diff --git a/src/slirp/tcp_output.c b/src/NETWORK/slirp/tcp_output.c similarity index 100% rename from src/slirp/tcp_output.c rename to src/NETWORK/slirp/tcp_output.c diff --git a/src/slirp/tcp_subr.c b/src/NETWORK/slirp/tcp_subr.c similarity index 100% rename from src/slirp/tcp_subr.c rename to src/NETWORK/slirp/tcp_subr.c diff --git a/src/slirp/tcp_timer.c b/src/NETWORK/slirp/tcp_timer.c similarity index 100% rename from src/slirp/tcp_timer.c rename to src/NETWORK/slirp/tcp_timer.c diff --git a/src/slirp/tcp_timer.h b/src/NETWORK/slirp/tcp_timer.h similarity index 100% rename from src/slirp/tcp_timer.h rename to src/NETWORK/slirp/tcp_timer.h diff --git a/src/slirp/tcp_var.h b/src/NETWORK/slirp/tcp_var.h similarity index 100% rename from src/slirp/tcp_var.h rename to src/NETWORK/slirp/tcp_var.h diff --git a/src/slirp/tcpip.h b/src/NETWORK/slirp/tcpip.h similarity index 100% rename from src/slirp/tcpip.h rename to src/NETWORK/slirp/tcpip.h diff --git a/src/slirp/tftp.c b/src/NETWORK/slirp/tftp.c similarity index 100% rename from src/slirp/tftp.c rename to src/NETWORK/slirp/tftp.c diff --git a/src/slirp/tftp.h b/src/NETWORK/slirp/tftp.h similarity index 100% rename from src/slirp/tftp.h rename to src/NETWORK/slirp/tftp.h diff --git a/src/slirp/udp.c b/src/NETWORK/slirp/udp.c similarity index 99% rename from src/slirp/udp.c rename to src/NETWORK/slirp/udp.c index 318ac6400..fbeb3c340 100644 --- a/src/slirp/udp.c +++ b/src/NETWORK/slirp/udp.c @@ -150,6 +150,7 @@ udp_input(m, iphlen) goto bad; } +#ifdef NEED_TFTP /* * handle TFTP */ @@ -157,6 +158,7 @@ udp_input(m, iphlen) tftp_input(m); goto bad; } +#endif /* * Locate pcb for datagram. diff --git a/src/slirp/udp.h b/src/NETWORK/slirp/udp.h similarity index 100% rename from src/slirp/udp.h rename to src/NETWORK/slirp/udp.h diff --git a/src/dosbox/dbopl.cpp b/src/SOUND/dbopl.cpp similarity index 99% rename from src/dosbox/dbopl.cpp rename to src/SOUND/dbopl.cpp index b5d4bfe65..e8002b7cf 100644 --- a/src/dosbox/dbopl.cpp +++ b/src/SOUND/dbopl.cpp @@ -869,6 +869,9 @@ Channel* Channel::BlockTemplate( Chip* chip, Bit32u samples, Bit32s* output ) { return (this + 2); } break; + case sm2Percussion: + case sm3Percussion: + break; } //Init the operators with the the current vibrato and tremolo values Op( 0 )->Prepare( chip ); @@ -940,6 +943,9 @@ Channel* Channel::BlockTemplate( Chip* chip, Bit32u samples, Bit32s* output ) { output[ i * 2 + 0 ] += sample & maskLeft; output[ i * 2 + 1 ] += sample & maskRight; break; + case sm2Percussion: + case sm3Percussion: + break; } } switch( mode ) { diff --git a/src/dosbox/dbopl.h b/src/SOUND/dbopl.h similarity index 100% rename from src/dosbox/dbopl.h rename to src/SOUND/dbopl.h diff --git a/src/filters.h b/src/SOUND/filters.h similarity index 71% rename from src/filters.h rename to src/SOUND/filters.h index acc022ba0..528bf0b05 100644 --- a/src/filters.h +++ b/src/SOUND/filters.h @@ -3,8 +3,7 @@ */ #define NCoef 2 -//fc=350Hz -static inline float low_iir(int i, float NewSample) { +static __inline float low_iir(int i, float NewSample) { float ACoef[NCoef+1] = { 0.00049713569693400649, 0.00099427139386801299, @@ -17,17 +16,17 @@ static inline float low_iir(int i, float NewSample) { 0.93726236021404663000 }; - static float y[2][NCoef+1]; //output samples - static float x[2][NCoef+1]; //input samples + static float y[2][NCoef+1]; /* output samples */ + static float x[2][NCoef+1]; /* input samples */ int n; - //shift the old samples + /* shift the old samples */ for(n=NCoef; n>0; n--) { x[i][n] = x[i][n-1]; y[i][n] = y[i][n-1]; } - //Calculate the new output + /* Calculate the new output */ x[i][0] = NewSample; y[i][0] = ACoef[0] * x[i][0]; for(n=1; n<=NCoef; n++) @@ -36,8 +35,7 @@ static inline float low_iir(int i, float NewSample) { return y[i][0]; } -//fc=350Hz -static inline float low_cut_iir(int i, float NewSample) { +static __inline float low_cut_iir(int i, float NewSample) { float ACoef[NCoef+1] = { 0.96839970114733542000, -1.93679940229467080000, @@ -50,17 +48,17 @@ static inline float low_cut_iir(int i, float NewSample) { 0.93726236021916731000 }; - static float y[2][NCoef+1]; //output samples - static float x[2][NCoef+1]; //input samples + static float y[2][NCoef+1]; /* output samples */ + static float x[2][NCoef+1]; /* input samples */ int n; - //shift the old samples + /* shift the old samples */ for(n=NCoef; n>0; n--) { x[i][n] = x[i][n-1]; y[i][n] = y[i][n-1]; } - //Calculate the new output + /* Calculate the new output */ x[i][0] = NewSample; y[i][0] = ACoef[0] * x[i][0]; for(n=1; n<=NCoef; n++) @@ -69,8 +67,7 @@ static inline float low_cut_iir(int i, float NewSample) { return y[i][0]; } -//fc=3.5kHz -static inline float high_iir(int i, float NewSample) { +static __inline float high_iir(int i, float NewSample) { float ACoef[NCoef+1] = { 0.72248704753064896000, -1.44497409506129790000, @@ -82,17 +79,17 @@ static inline float high_iir(int i, float NewSample) { -1.36640781670578510000, 0.52352474706139873000 }; - static float y[2][NCoef+1]; //output samples - static float x[2][NCoef+1]; //input samples + static float y[2][NCoef+1]; /* output samples */ + static float x[2][NCoef+1]; /* input samples */ int n; - //shift the old samples + /* shift the old samples */ for(n=NCoef; n>0; n--) { x[i][n] = x[i][n-1]; y[i][n] = y[i][n-1]; } - //Calculate the new output + /* Calculate the new output */ x[i][0] = NewSample; y[i][0] = ACoef[0] * x[i][0]; for(n=1; n<=NCoef; n++) @@ -101,8 +98,7 @@ static inline float high_iir(int i, float NewSample) { return y[i][0]; } -//fc=3.5kHz -static inline float high_cut_iir(int i, float NewSample) { +static __inline float high_cut_iir(int i, float NewSample) { float ACoef[NCoef+1] = { 0.03927726802250377400, 0.07855453604500754700, @@ -114,17 +110,17 @@ static inline float high_cut_iir(int i, float NewSample) { -1.36640781666419950000, 0.52352474703279628000 }; - static float y[2][NCoef+1]; //output samples - static float x[2][NCoef+1]; //input samples + static float y[2][NCoef+1]; /* output samples */ + static float x[2][NCoef+1]; /* input samples */ int n; - //shift the old samples + /* shift the old samples */ for(n=NCoef; n>0; n--) { x[i][n] = x[i][n-1]; y[i][n] = y[i][n-1]; } - //Calculate the new output + /* Calculate the new output */ x[i][0] = NewSample; y[i][0] = ACoef[0] * x[i][0]; for(n=1; n<=NCoef; n++) @@ -135,11 +131,10 @@ static inline float high_cut_iir(int i, float NewSample) { #undef NCoef -#define NCoef 1 +#define NCoef 2 -//fc=3.2kHz -static inline float sb_iir(int i, float NewSample) { -/* float ACoef[NCoef+1] = { +static __inline float sb_iir(int i, float NewSample) { + float ACoef[NCoef+1] = { 0.03356837051492005100, 0.06713674102984010200, 0.03356837051492005100 @@ -149,9 +144,9 @@ static inline float sb_iir(int i, float NewSample) { 1.00000000000000000000, -1.41898265221812010000, 0.55326988968868285000 - };*/ + }; - float ACoef[NCoef+1] = { +/* float ACoef[NCoef+1] = { 0.17529642630084405000, 0.17529642630084405000 }; @@ -159,18 +154,19 @@ static inline float sb_iir(int i, float NewSample) { float BCoef[NCoef+1] = { 1.00000000000000000000, -0.64940759319751051000 - }; - static float y[2][NCoef+1]; //output samples - static float x[2][NCoef+1]; //input samples + };*/ + + static float y[2][NCoef+1]; /* output samples */ + static float x[2][NCoef+1]; /* input samples */ int n; - //shift the old samples + /* shift the old samples */ for(n=NCoef; n>0; n--) { x[i][n] = x[i][n-1]; y[i][n] = y[i][n-1]; } - //Calculate the new output + /* Calculate the new output */ x[i][0] = NewSample; y[i][0] = ACoef[0] * x[i][0]; for(n=1; n<=NCoef; n++) @@ -184,8 +180,7 @@ static inline float sb_iir(int i, float NewSample) { #undef NCoef #define NCoef 2 -//fc=150Hz -static inline float adgold_highpass_iir(int i, float NewSample) { +static __inline float adgold_highpass_iir(int i, float NewSample) { float ACoef[NCoef+1] = { 0.98657437157334349000, -1.97314874314668700000, @@ -198,17 +193,17 @@ static inline float adgold_highpass_iir(int i, float NewSample) { 0.97261396931534050000 }; - static float y[2][NCoef+1]; //output samples - static float x[2][NCoef+1]; //input samples + static float y[2][NCoef+1]; /* output samples */ + static float x[2][NCoef+1]; /* input samples */ int n; - //shift the old samples + /* shift the old samples */ for(n=NCoef; n>0; n--) { x[i][n] = x[i][n-1]; y[i][n] = y[i][n-1]; } - //Calculate the new output + /* Calculate the new output */ x[i][0] = NewSample; y[i][0] = ACoef[0] * x[i][0]; for(n=1; n<=NCoef; n++) @@ -217,8 +212,7 @@ static inline float adgold_highpass_iir(int i, float NewSample) { return y[i][0]; } -//fc=150Hz -static inline float adgold_lowpass_iir(int i, float NewSample) { +static __inline float adgold_lowpass_iir(int i, float NewSample) { float ACoef[NCoef+1] = { 0.00009159473951071446, 0.00018318947902142891, @@ -231,17 +225,17 @@ static inline float adgold_lowpass_iir(int i, float NewSample) { 0.97261396931306277000 }; - static float y[2][NCoef+1]; //output samples - static float x[2][NCoef+1]; //input samples + static float y[2][NCoef+1]; /* output samples */ + static float x[2][NCoef+1]; /* input samples */ int n; - //shift the old samples + /* shift the old samples */ for(n=NCoef; n>0; n--) { x[i][n] = x[i][n-1]; y[i][n] = y[i][n-1]; } - //Calculate the new output + /* Calculate the new output */ x[i][0] = NewSample; y[i][0] = ACoef[0] * x[i][0]; for(n=1; n<=NCoef; n++) @@ -250,8 +244,7 @@ static inline float adgold_lowpass_iir(int i, float NewSample) { return y[i][0]; } -//fc=56Hz -static inline float adgold_pseudo_stereo_iir(float NewSample) { +static __inline float adgold_pseudo_stereo_iir(float NewSample) { float ACoef[NCoef+1] = { 0.00001409030866231767, 0.00002818061732463533, @@ -264,17 +257,17 @@ static inline float adgold_pseudo_stereo_iir(float NewSample) { 0.98738361004063568000 }; - static float y[NCoef+1]; //output samples - static float x[NCoef+1]; //input samples + static float y[NCoef+1]; /* output samples */ + static float x[NCoef+1]; /* input samples */ int n; - //shift the old samples + /* shift the old samples */ for(n=NCoef; n>0; n--) { x[n] = x[n-1]; y[n] = y[n-1]; } - //Calculate the new output + /* Calculate the new output */ x[0] = NewSample; y[0] = ACoef[0] * x[0]; for(n=1; n<=NCoef; n++) diff --git a/src/SOUND/midi.c b/src/SOUND/midi.c new file mode 100644 index 000000000..d8b1a8d8f --- /dev/null +++ b/src/SOUND/midi.c @@ -0,0 +1,247 @@ +#include +#include +#include +#include +#include "../device.h" +#include "midi.h" +#include "../ibm.h" + +#include "../WIN/plat_midi.h" +#include "../WIN/plat_ticks.h" +#include "midi_system.h" +#include "midi_mt32.h" + +int midi_device_current = 0; +static int midi_device_last = 0; + +typedef struct +{ + const char *name; + const char *internal_name; + device_t *device; +} MIDI_DEVICE; + +static MIDI_DEVICE devices[] = +{ + {"None", "none", NULL}, + {SYSTEM_MIDI_NAME, SYSTEM_MIDI_INTERNAL_NAME, &system_midi_device}, + {"Roland MT-32 Emulation", "mt32", &mt32_device}, + {"", "", NULL} +}; + +static midi_device_t* m_device = NULL; + +int midi_device_available(int card) +{ + if (devices[card].device) + return device_available(devices[card].device); + + return 1; +} + +char *midi_device_getname(int card) +{ + return (char *) devices[card].name; +} + +device_t *midi_device_getdevice(int card) +{ + return devices[card].device; +} + +int midi_device_has_config(int card) +{ + if (!devices[card].device) + return 0; + return devices[card].device->config ? 1 : 0; +} + +char *midi_device_get_internal_name(int card) +{ + return (char *) devices[card].internal_name; +} + +int midi_device_get_from_internal_name(char *s) +{ + int c = 0; + + while (strlen(devices[c].internal_name)) + { + if (!strcmp(devices[c].internal_name, s)) + return c; + c++; + } + + return 0; +} + +void midi_device_init() +{ + if (devices[midi_device_current].device) + device_add(devices[midi_device_current].device); + midi_device_last = midi_device_current; +} + +static uint8_t midi_rt_buf[1024]; +static uint8_t midi_cmd_buf[1024]; +static int midi_cmd_pos = 0; +static int midi_cmd_len = 0; +static uint8_t midi_status = 0; +static unsigned int midi_sysex_start = 0; +static unsigned int midi_sysex_delay = 0; + +uint8_t MIDI_evt_len[256] = { + 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // 0x00 + 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // 0x10 + 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // 0x20 + 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // 0x30 + 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // 0x40 + 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // 0x50 + 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // 0x60 + 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // 0x70 + + 3,3,3,3, 3,3,3,3, 3,3,3,3, 3,3,3,3, // 0x80 + 3,3,3,3, 3,3,3,3, 3,3,3,3, 3,3,3,3, // 0x90 + 3,3,3,3, 3,3,3,3, 3,3,3,3, 3,3,3,3, // 0xa0 + 3,3,3,3, 3,3,3,3, 3,3,3,3, 3,3,3,3, // 0xb0 + + 2,2,2,2, 2,2,2,2, 2,2,2,2, 2,2,2,2, // 0xc0 + 2,2,2,2, 2,2,2,2, 2,2,2,2, 2,2,2,2, // 0xd0 + + 3,3,3,3, 3,3,3,3, 3,3,3,3, 3,3,3,3, // 0xe0 + + 0,2,3,2, 0,0,1,0, 1,0,1,1, 1,0,1,0 // 0xf0 +}; + +static unsigned int midi_pos; +static uint8_t midi_sysex_data[1024+2]; + +void midi_init(midi_device_t* device) +{ + memset(midi_rt_buf, 0, sizeof(midi_rt_buf)); + memset(midi_cmd_buf, 0, sizeof(midi_cmd_buf)); + + midi_cmd_pos = midi_cmd_len = 0; + midi_status = 0; + + midi_sysex_start = midi_sysex_delay = 0; + + m_device = device; + +} + +void midi_close() +{ + m_device = NULL; +} + +void midi_poll() +{ + if (m_device && m_device->poll) m_device->poll(); +} + +void play_msg(uint8_t *msg) +{ + if (m_device->play_msg) m_device->play_msg(msg); +} + + +void play_sysex(uint8_t *sysex, unsigned int len) +{ + if (m_device->play_sysex) m_device->play_sysex(sysex, len); +} + +#define SYSEX_SIZE 1024 +#define RAWBUF 1024 + +void midi_write(uint8_t val) +{ + if (!m_device) return; + + if (m_device->write && m_device->write(val)) return; + + uint32_t passed_ticks; + + if (midi_sysex_start) + { + passed_ticks = get_ticks() - midi_sysex_start; + if (passed_ticks < midi_sysex_delay) + { + delay_ms(midi_sysex_delay - passed_ticks); + } + } + + /* Test for a realtime MIDI message */ + if (val >= 0xf8) + { + midi_rt_buf[0] = val; + play_msg(midi_rt_buf); + return; + } + + /* Test for a active sysex transfer */ + + if (midi_status == 0xf0) + { + if (!(val & 0x80)) + { + if (midi_pos < (SYSEX_SIZE-1)) midi_sysex_data[midi_pos++] = val; + return; + } + else + { + midi_sysex_data[midi_pos++] = 0xf7; + + if ((midi_sysex_start) && (midi_pos >= 4) && (midi_pos <= 9) && (midi_sysex_data[1] == 0x411) && (midi_sysex_data[3] == 0x16)) + { + /* pclog("MIDI: Skipping invalid MT-32 SysEx MIDI message\n"); */ + } + else + { + play_sysex(midi_sysex_data, midi_pos); + if (midi_sysex_start) + { + if (midi_sysex_data[5] == 0x7f) + { + midi_sysex_delay = 290; /* All parameters reset */ + } + else if ((midi_sysex_data[5] == 0x10) && (midi_sysex_data[6] == 0x00) && (midi_sysex_data[7] == 0x04)) + { + midi_sysex_delay = 145; /* Viking Child */ + } + else if ((midi_sysex_data[5] == 0x10) && (midi_sysex_data[6] == 0x00) && (midi_sysex_data[7] == 0x01)) + { + midi_sysex_delay = 30; /* Dark Sun 1 */ + } + else + midi_sysex_delay = (unsigned int) (((float) (midi_pos) * 1.25f) * 1000.0f / 3125.0f) + 2; + + midi_sysex_start = get_ticks(); + } + } + } + } + + + if (val & 0x80) + { + midi_status = val; + midi_cmd_pos = 0; + midi_cmd_len = MIDI_evt_len[val]; + if (midi_status == 0xf0) + { + midi_sysex_data[0] = 0xf0; + midi_pos = 1; + } + } + + if (midi_cmd_len) + { + midi_cmd_buf[midi_cmd_pos++] = val; + if (midi_cmd_pos >= midi_cmd_len) + { + play_msg(midi_cmd_buf); + midi_cmd_pos = 1; + } + } +} diff --git a/src/SOUND/midi.h b/src/SOUND/midi.h new file mode 100644 index 000000000..371c79eb4 --- /dev/null +++ b/src/SOUND/midi.h @@ -0,0 +1,35 @@ +extern int midi_device_current; + +int midi_device_available(int card); +char *midi_device_getname(int card); +struct device_t *midi_device_getdevice(int card); +int midi_device_has_config(int card); +char *midi_device_get_internal_name(int card); +int midi_device_get_from_internal_name(char *s); +void midi_device_init(); + +typedef struct midi_device_t +{ + void (*play_sysex)(uint8_t *sysex, unsigned int len); + void (*play_msg)(uint8_t *msg); + void (*poll)(); + int (*write)(uint8_t val); +} midi_device_t; + +void midi_init(midi_device_t* device); +void midi_close(); +void midi_write(uint8_t val); +void midi_poll(); + +#if 0 +#ifdef _WIN32 +#define SYSTEM_MIDI_NAME "Windows MIDI" +#define SYSTEM_MIDI_INTERNAL_NAME "windows_midi" +#else +#define SYSTEM_MIDI_NAME "System MIDI" +#define SYSTEM_MIDI_INTERNAL_NAME "system_midi" +#endif +#else +#define SYSTEM_MIDI_NAME "System MIDI" +#define SYSTEM_MIDI_INTERNAL_NAME "system_midi" +#endif \ No newline at end of file diff --git a/src/SOUND/midi_mt32.c b/src/SOUND/midi_mt32.c new file mode 100644 index 000000000..6233f9ae4 --- /dev/null +++ b/src/SOUND/midi_mt32.c @@ -0,0 +1,323 @@ +#include +#include +#include +#include "munt/c_interface/c_interface.h" +#include "../WIN/plat_thread.h" +#include "../ibm.h" +#include "../device.h" +#include "../mem.h" +#include "../rom.h" +#include "midi_mt32.h" +#include "midi.h" +#include "sound.h" + +extern void givealbuffer_midi(void *buf, uint32_t size); +extern void pclog(const char *format, ...); +extern void al_set_midi(int freq, int buf_size); + +static const mt32emu_report_handler_i_v0 handler_v0 = { + /** Returns the actual interface version ID */ + NULL, //mt32emu_report_handler_version (*getVersionID)(mt32emu_report_handler_i i); + + /** Callback for debug messages, in vprintf() format */ + NULL, //void (*printDebug)(void *instance_data, const char *fmt, va_list list); + /** Callbacks for reporting errors */ + NULL, //void (*onErrorControlROM)(void *instance_data); + NULL, //void (*onErrorPCMROM)(void *instance_data); + /** Callback for reporting about displaying a new custom message on LCD */ + NULL, //void (*showLCDMessage)(void *instance_data, const char *message); + /** Callback for reporting actual processing of a MIDI message */ + NULL, //void (*onMIDIMessagePlayed)(void *instance_data); + /** + * Callback for reporting an overflow of the input MIDI queue. + * Returns MT32EMU_BOOL_TRUE if a recovery action was taken + * and yet another attempt to enqueue the MIDI event is desired. + */ + NULL, //mt32emu_boolean (*onMIDIQueueOverflow)(void *instance_data); + /** + * Callback invoked when a System Realtime MIDI message is detected in functions + * mt32emu_parse_stream and mt32emu_play_short_message and the likes. + */ + NULL, //void (*onMIDISystemRealtime)(void *instance_data, mt32emu_bit8u system_realtime); + /** Callbacks for reporting system events */ + NULL, //void (*onDeviceReset)(void *instance_data); + NULL, //void (*onDeviceReconfig)(void *instance_data); + /** Callbacks for reporting changes of reverb settings */ + NULL, //void (*onNewReverbMode)(void *instance_data, mt32emu_bit8u mode); + NULL, //void (*onNewReverbTime)(void *instance_data, mt32emu_bit8u time); + NULL, //void (*onNewReverbLevel)(void *instance_data, mt32emu_bit8u level); + /** Callbacks for reporting various information */ + NULL, //void (*onPolyStateChanged)(void *instance_data, mt32emu_bit8u part_num); + NULL, //void (*onProgramChanged)(void *instance_data, mt32emu_bit8u part_num, const char *sound_group_name, const char *patch_name); +}; + +static const mt32emu_report_handler_i handler = { &handler_v0 }; + +static mt32emu_context context = NULL; +static int roms_present = -1; + +mt32emu_return_code mt32_check(const char* func, mt32emu_return_code ret, mt32emu_return_code expected) +{ + if (ret != expected) + { + pclog("%s() failed, expected %d but returned %d\n", func, expected, ret); + return 0; + } + return 1; +} + +int mt32_available() +{ + if (roms_present < 0) + roms_present = (rom_present(L"roms/mt32/mt32_control.rom") && rom_present(L"roms/mt32/mt32_pcm.rom")); + return roms_present; +} + +static thread_t *thread_h = NULL; +static event_t *event = NULL; + +#define RENDER_RATE 30 + +static uint32_t samplerate = 44100; +static int buf_size = 0; +static float* buffer = NULL; +static int16_t* buffer_int16 = NULL; +static int midi_pos = 0; + +void mt32_stream(float* stream, int len) +{ + if (context) mt32emu_render_float(context, stream, len); +} + +void mt32_stream_int16(int16_t* stream, int len) +{ + if (context) mt32emu_render_bit16s(context, stream, len); +} + +void mt32_poll() +{ + midi_pos++; + if (midi_pos == 48000/RENDER_RATE) + { + midi_pos = 0; + thread_set_event(event); + } +} + +extern int soundon; + +static void mt32_thread(void *param) +{ + while (1) + { + thread_wait_event(event, -1); + if (sound_is_float) + { + memset(buffer, 0, buf_size * sizeof(float)); + mt32_stream(buffer, (samplerate/RENDER_RATE)); + if (soundon) + givealbuffer_midi(buffer, buf_size); + } + else + { + memset(buffer_int16, 0, buf_size * sizeof(int16_t)); + mt32_stream_int16(buffer_int16, (samplerate/RENDER_RATE)); + if (soundon) + givealbuffer_midi(buffer_int16, buf_size); + } + } +} + +void mt32_msg(uint8_t* val) +{ + if (context) mt32_check("mt32emu_play_msg", mt32emu_play_msg(context, *(uint32_t*)val), MT32EMU_RC_OK); +} + +void mt32_sysex(uint8_t* data, unsigned int len) +{ + if (context) mt32_check("mt32emu_play_sysex", mt32emu_play_sysex(context, data, len), MT32EMU_RC_OK); +} + +void* mt32_init() +{ + wchar_t s[512]; + char fn[512]; + context = mt32emu_create_context(handler, NULL); + if (!rom_getfile(L"roms/mt32/mt32_control.rom", s, 512)) return 0; + wcstombs(fn, s, (wcslen(s) << 1) + 2); + if (!mt32_check("mt32emu_add_rom_file", mt32emu_add_rom_file(context, fn), MT32EMU_RC_ADDED_CONTROL_ROM)) return 0; + if (!rom_getfile(L"roms/mt32/mt32_pcm.rom", s, 512)) return 0; + wcstombs(fn, s, (wcslen(s) << 1) + 2); + if (!mt32_check("mt32emu_add_rom_file", mt32emu_add_rom_file(context, fn), MT32EMU_RC_ADDED_PCM_ROM)) return 0; + + if (!mt32_check("mt32emu_open_synth", mt32emu_open_synth(context), MT32EMU_RC_OK)) return 0; + + event = thread_create_event(); + thread_h = thread_create(mt32_thread, 0); + samplerate = mt32emu_get_actual_stereo_output_samplerate(context); + buf_size = samplerate/RENDER_RATE*2; + if (sound_is_float) + { + buffer = malloc(buf_size * sizeof(float)); + buffer_int16 = NULL; + } + else + { + buffer = NULL; + buffer_int16 = malloc(buf_size * sizeof(int16_t)); + } + + mt32emu_set_output_gain(context, device_get_config_int("output_gain")/100.0f); + mt32emu_set_reverb_enabled(context, device_get_config_int("reverb")); + mt32emu_set_reverb_output_gain(context, device_get_config_int("reverb_output_gain")/100.0f); + mt32emu_set_reversed_stereo_enabled(context, device_get_config_int("reversed_stereo")); + + pclog("mt32 output gain: %f\n", mt32emu_get_output_gain(context)); + pclog("mt32 reverb output gain: %f\n", mt32emu_get_reverb_output_gain(context)); + pclog("mt32 reverb: %d\n", mt32emu_is_reverb_enabled(context)); + pclog("mt32 reversed stereo: %d\n", mt32emu_is_reversed_stereo_enabled(context)); + + al_set_midi(samplerate, buf_size); + + pclog("mt32 (Munt %s) initialized, samplerate %d, buf_size %d\n", mt32emu_get_library_version_string(), samplerate, buf_size); + + midi_device_t* dev = malloc(sizeof(midi_device_t)); + memset(dev, 0, sizeof(midi_device_t)); + + dev->play_msg = mt32_msg; + dev->play_sysex = mt32_sysex; + dev->poll = mt32_poll; + + midi_init(dev); + + return dev; +} + +void mt32_close(void* p) +{ + if (!p) return; + + if (thread_h) + thread_kill(thread_h); + if (event) + thread_destroy_event(event); + event = NULL; + thread_h = NULL; + + if (context) + { + mt32emu_close_synth(context); + mt32emu_free_context(context); + } + context = NULL; + + if (buffer) + free(buffer); + buffer = NULL; + + if (buffer_int16) + free(buffer_int16); + buffer_int16 = NULL; + + midi_close(); + + free((midi_device_t*)p); + + pclog("mt32 closed\n"); +} + +static device_config_t mt32_config[] = +{ + { + .name = "output_gain", + .description = "Output Gain", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "100%", + .value = 100 + }, + { + .description = "75%", + .value = 75 + }, + { + .description = "50%", + .value = 50 + }, + { + .description = "25%", + .value = 25 + }, + { + .description = "0%", + .value = 0 + }, + { + .description = "" + } + }, + .default_int = 100 + }, + { + .name = "reverb", + .description = "Reverb", + .type = CONFIG_BINARY, + .default_int = 1 + }, + { + .name = "reverb_output_gain", + .description = "Reverb Output Gain", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "100%", + .value = 100 + }, + { + .description = "75%", + .value = 75 + }, + { + .description = "50%", + .value = 50 + }, + { + .description = "25%", + .value = 25 + }, + { + .description = "0%", + .value = 0 + }, + { + .description = "" + } + }, + .default_int = 100 + }, + { + .name = "reversed_stereo", + .description = "Reversed stereo", + .type = CONFIG_BINARY, + .default_int = 0 + }, + { + .type = -1 + } +}; + +device_t mt32_device = +{ + "Roland MT-32 Emulation", + 0, + mt32_init, + mt32_close, + mt32_available, + NULL, + NULL, + NULL, + mt32_config +}; diff --git a/src/SOUND/midi_mt32.h b/src/SOUND/midi_mt32.h new file mode 100644 index 000000000..9a80989a6 --- /dev/null +++ b/src/SOUND/midi_mt32.h @@ -0,0 +1 @@ +extern device_t mt32_device; diff --git a/src/SOUND/midi_system.c b/src/SOUND/midi_system.c new file mode 100644 index 000000000..d69fc3a4b --- /dev/null +++ b/src/SOUND/midi_system.c @@ -0,0 +1,62 @@ +#include +#include +#include +#include +#include "../device.h" +#include "../WIN/plat_midi.h" +#include "midi_system.h" +#include "midi.h" + +void* system_midi_init() +{ + midi_device_t* dev = malloc(sizeof(midi_device_t)); + memset(dev, 0, sizeof(midi_device_t)); + + dev->play_msg = plat_midi_play_msg; + dev->play_sysex = plat_midi_play_sysex; + dev->write = plat_midi_write; + + plat_midi_init(); + + midi_init(dev); + + return dev; +} + +void system_midi_close(void* p) +{ + plat_midi_close(); + + midi_close(); +} + +int system_midi_available() +{ + return plat_midi_get_num_devs(); +} + +static device_config_t system_midi_config[] = +{ + { + .name = "midi", + .description = "MIDI out device", + .type = CONFIG_MIDI, + .default_int = 0 + }, + { + .type = -1 + } +}; + +device_t system_midi_device = +{ + SYSTEM_MIDI_NAME, + 0, + system_midi_init, + system_midi_close, + system_midi_available, + NULL, + NULL, + NULL, + system_midi_config +}; diff --git a/src/SOUND/midi_system.h b/src/SOUND/midi_system.h new file mode 100644 index 000000000..7afbb4c45 --- /dev/null +++ b/src/SOUND/midi_system.h @@ -0,0 +1 @@ +extern device_t system_midi_device; diff --git a/src/SOUND/munt/Analog.cpp b/src/SOUND/munt/Analog.cpp new file mode 100644 index 000000000..2901198f2 --- /dev/null +++ b/src/SOUND/munt/Analog.cpp @@ -0,0 +1,424 @@ +/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher + * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#include + +#include "internals.h" + +#include "Analog.h" +#include "Synth.h" + +namespace MT32Emu { + +/* FIR approximation of the overall impulse response of the cascade composed of the sample & hold circuit and the low pass filter + * of the MT-32 first generation. + * The coefficients below are found by windowing the inverse DFT of the 1024 pin frequency response converted to the minimum phase. + * The frequency response of the LPF is computed directly, the effect of the S&H is approximated by multiplying the LPF frequency + * response by the corresponding sinc. Although, the LPF has DC gain of 3.2, we ignore this in the emulation and use normalised model. + * The peak gain of the normalised cascade appears about 1.7 near 11.8 kHz. Relative error doesn't exceed 1% for the frequencies + * below 12.5 kHz. In the higher frequency range, the relative error is below 8%. Peak error value is at 16 kHz. + */ +static const FloatSample COARSE_LPF_FLOAT_TAPS_MT32[] = { + 1.272473681f, -0.220267785f, -0.158039905f, 0.179603785f, -0.111484097f, 0.054137498f, -0.023518029f, 0.010997169f, -0.006935698f +}; + +// Similar approximation for new MT-32 and CM-32L/LAPC-I LPF. As the voltage controlled amplifier was introduced, LPF has unity DC gain. +// The peak gain value shifted towards higher frequencies and a bit higher about 1.83 near 13 kHz. +static const FloatSample COARSE_LPF_FLOAT_TAPS_CM32L[] = { + 1.340615635f, -0.403331694f, 0.036005517f, 0.066156844f, -0.069672532f, 0.049563806f, -0.031113416f, 0.019169774f, -0.012421368f +}; + +static const unsigned int COARSE_LPF_INT_FRACTION_BITS = 14; + +// Integer versions of the FIRs above multiplied by (1 << 14) and rounded. +static const IntSampleEx COARSE_LPF_INT_TAPS_MT32[] = { + 20848, -3609, -2589, 2943, -1827, 887, -385, 180, -114 +}; + +static const IntSampleEx COARSE_LPF_INT_TAPS_CM32L[] = { + 21965, -6608, 590, 1084, -1142, 812, -510, 314, -204 +}; + +/* Combined FIR that both approximates the impulse response of the analogue circuits of sample & hold and the low pass filter + * in the audible frequency range (below 20 kHz) and attenuates unwanted mirror spectra above 28 kHz as well. It is a polyphase + * filter intended for resampling the signal to 48 kHz yet for applying high frequency boost. + * As with the filter above, the analogue LPF frequency response is obtained for 1536 pin grid for range up to 96 kHz and multiplied + * by the corresponding sinc. The result is further squared, windowed and passed to generalised Parks-McClellan routine as a desired response. + * Finally, the minimum phase factor is found that's essentially the coefficients below. + * Relative error in the audible frequency range doesn't exceed 0.0006%, attenuation in the stopband is better than 100 dB. + * This level of performance makes it nearly bit-accurate for standard 16-bit sample resolution. + */ + +// FIR version for MT-32 first generation. +static const FloatSample ACCURATE_LPF_TAPS_MT32[] = { + 0.003429281f, 0.025929869f, 0.096587777f, 0.228884848f, 0.372413431f, 0.412386503f, 0.263980018f, + -0.014504962f, -0.237394528f, -0.257043496f, -0.103436603f, 0.063996095f, 0.124562333f, 0.083703206f, + 0.013921662f, -0.033475018f, -0.046239712f, -0.029310921f, 0.00126585f, 0.021060961f, 0.017925605f, + 0.003559874f, -0.005105248f, -0.005647917f, -0.004157918f, -0.002065664f, 0.00158747f, 0.003762585f, + 0.001867137f, -0.001090028f, -0.001433979f, -0.00022367f, 4.34308E-05f, -0.000247827f, 0.000157087f, + 0.000605823f, 0.000197317f, -0.000370511f, -0.000261202f, 9.96069E-05f, 9.85073E-05f, -5.28754E-05f, + -1.00912E-05f, 7.69943E-05f, 2.03162E-05f, -5.67967E-05f, -3.30637E-05f, 1.61958E-05f, 1.73041E-05f +}; + +// FIR version for new MT-32 and CM-32L/LAPC-I. +static const FloatSample ACCURATE_LPF_TAPS_CM32L[] = { + 0.003917452f, 0.030693861f, 0.116424199f, 0.275101674f, 0.43217361f, 0.431247894f, 0.183255659f, + -0.174955671f, -0.354240244f, -0.212401714f, 0.072259178f, 0.204655344f, 0.108336211f, -0.039099027f, + -0.075138174f, -0.026261906f, 0.00582663f, 0.003052193f, 0.00613657f, 0.017017951f, 0.008732535f, + -0.011027427f, -0.012933664f, 0.001158097f, 0.006765958f, 0.00046778f, -0.002191106f, 0.001561017f, + 0.001842871f, -0.001996876f, -0.002315836f, 0.000980965f, 0.001817454f, -0.000243272f, -0.000972848f, + 0.000149941f, 0.000498886f, -0.000204436f, -0.000347415f, 0.000142386f, 0.000249137f, -4.32946E-05f, + -0.000131231f, 3.88575E-07f, 4.48813E-05f, -1.31906E-06f, -1.03499E-05f, 7.71971E-06f, 2.86721E-06f +}; + +// According to the CM-64 PCB schematic, there is a difference in the values of the LPF entrance resistors for the reverb and non-reverb channels. +// This effectively results in non-unity LPF DC gain for the reverb channel of 0.68 while the LPF has unity DC gain for the LA32 output channels. +// In emulation, the reverb output gain is multiplied by this factor to compensate for the LPF gain difference. +static const float CM32L_REVERB_TO_LA32_ANALOG_OUTPUT_GAIN_FACTOR = 0.68f; + +static const unsigned int OUTPUT_GAIN_FRACTION_BITS = 8; +static const float OUTPUT_GAIN_MULTIPLIER = float(1 << OUTPUT_GAIN_FRACTION_BITS); + +static const unsigned int COARSE_LPF_DELAY_LINE_LENGTH = 8; // Must be a power of 2 +static const unsigned int ACCURATE_LPF_DELAY_LINE_LENGTH = 16; // Must be a power of 2 +static const unsigned int ACCURATE_LPF_NUMBER_OF_PHASES = 3; // Upsampling factor +static const unsigned int ACCURATE_LPF_PHASE_INCREMENT_REGULAR = 2; // Downsampling factor +static const unsigned int ACCURATE_LPF_PHASE_INCREMENT_OVERSAMPLED = 1; // No downsampling +static const Bit32u ACCURATE_LPF_DELTAS_REGULAR[][ACCURATE_LPF_NUMBER_OF_PHASES] = { { 0, 0, 0 }, { 1, 1, 0 }, { 1, 2, 1 } }; +static const Bit32u ACCURATE_LPF_DELTAS_OVERSAMPLED[][ACCURATE_LPF_NUMBER_OF_PHASES] = { { 0, 0, 0 }, { 1, 0, 0 }, { 1, 0, 1 } }; + +template +class AbstractLowPassFilter { +public: + static AbstractLowPassFilter &createLowPassFilter(const AnalogOutputMode mode, const bool oldMT32AnalogLPF); + + virtual ~AbstractLowPassFilter() {} + virtual SampleEx process(const SampleEx sample) = 0; + + virtual bool hasNextSample() const { + return false; + } + + virtual unsigned int getOutputSampleRate() const { + return SAMPLE_RATE; + } + + virtual unsigned int estimateInSampleCount(const unsigned int outSamples) const { + return outSamples; + } + + virtual void addPositionIncrement(const unsigned int) {} +}; + +template +class NullLowPassFilter : public AbstractLowPassFilter { +public: + SampleEx process(const SampleEx sample) { + return sample; + } +}; + +template +class CoarseLowPassFilter : public AbstractLowPassFilter { +private: + const SampleEx * const lpfTaps; + SampleEx ringBuffer[COARSE_LPF_DELAY_LINE_LENGTH]; + unsigned int ringBufferPosition; + +public: + static inline const SampleEx *getLPFTaps(const bool oldMT32AnalogLPF); + static inline SampleEx normaliseSample(const SampleEx sample); + + explicit CoarseLowPassFilter(const bool oldMT32AnalogLPF) : + lpfTaps(getLPFTaps(oldMT32AnalogLPF)), + ringBufferPosition(0) + { + Synth::muteSampleBuffer(ringBuffer, COARSE_LPF_DELAY_LINE_LENGTH); + } + + SampleEx process(const SampleEx inSample) { + static const unsigned int DELAY_LINE_MASK = COARSE_LPF_DELAY_LINE_LENGTH - 1; + + SampleEx sample = lpfTaps[COARSE_LPF_DELAY_LINE_LENGTH] * ringBuffer[ringBufferPosition]; + ringBuffer[ringBufferPosition] = Synth::clipSampleEx(inSample); + + for (unsigned int i = 0; i < COARSE_LPF_DELAY_LINE_LENGTH; i++) { + sample += lpfTaps[i] * ringBuffer[(i + ringBufferPosition) & DELAY_LINE_MASK]; + } + + ringBufferPosition = (ringBufferPosition - 1) & DELAY_LINE_MASK; + + return normaliseSample(sample); + } +}; + +class AccurateLowPassFilter : public AbstractLowPassFilter, public AbstractLowPassFilter { +private: + const FloatSample * const LPF_TAPS; + const Bit32u (* const deltas)[ACCURATE_LPF_NUMBER_OF_PHASES]; + const unsigned int phaseIncrement; + const unsigned int outputSampleRate; + + FloatSample ringBuffer[ACCURATE_LPF_DELAY_LINE_LENGTH]; + unsigned int ringBufferPosition; + unsigned int phase; + +public: + AccurateLowPassFilter(const bool oldMT32AnalogLPF, const bool oversample); + FloatSample process(const FloatSample sample); + IntSampleEx process(const IntSampleEx sample); + bool hasNextSample() const; + unsigned int getOutputSampleRate() const; + unsigned int estimateInSampleCount(const unsigned int outSamples) const; + void addPositionIncrement(const unsigned int positionIncrement); +}; + +static inline IntSampleEx normaliseSample(const IntSampleEx sample) { + return sample >> OUTPUT_GAIN_FRACTION_BITS; +} + +static inline FloatSample normaliseSample(const FloatSample sample) { + return sample; +} + +static inline float getActualReverbOutputGain(const float reverbGain, const bool mt32ReverbCompatibilityMode) { + return mt32ReverbCompatibilityMode ? reverbGain : reverbGain * CM32L_REVERB_TO_LA32_ANALOG_OUTPUT_GAIN_FACTOR; +} + +static inline IntSampleEx getIntOutputGain(const float outputGain) { + return IntSampleEx(((OUTPUT_GAIN_MULTIPLIER < outputGain) ? OUTPUT_GAIN_MULTIPLIER : outputGain) * OUTPUT_GAIN_MULTIPLIER); +} + +template +class AnalogImpl : public Analog { +public: + AbstractLowPassFilter &leftChannelLPF; + AbstractLowPassFilter &rightChannelLPF; + SampleEx synthGain; + SampleEx reverbGain; + + AnalogImpl(const AnalogOutputMode mode, const bool oldMT32AnalogLPF) : + leftChannelLPF(AbstractLowPassFilter::createLowPassFilter(mode, oldMT32AnalogLPF)), + rightChannelLPF(AbstractLowPassFilter::createLowPassFilter(mode, oldMT32AnalogLPF)), + synthGain(0), + reverbGain(0) + {} + + ~AnalogImpl() { + delete &leftChannelLPF; + delete &rightChannelLPF; + } + + unsigned int getOutputSampleRate() const { + return leftChannelLPF.getOutputSampleRate(); + } + + Bit32u getDACStreamsLength(const Bit32u outputLength) const { + return leftChannelLPF.estimateInSampleCount(outputLength); + } + + void setSynthOutputGain(const float synthGain); + void setReverbOutputGain(const float reverbGain, const bool mt32ReverbCompatibilityMode); + + bool process(IntSample *outStream, const IntSample *nonReverbLeft, const IntSample *nonReverbRight, const IntSample *reverbDryLeft, const IntSample *reverbDryRight, const IntSample *reverbWetLeft, const IntSample *reverbWetRight, Bit32u outLength); + bool process(FloatSample *outStream, const FloatSample *nonReverbLeft, const FloatSample *nonReverbRight, const FloatSample *reverbDryLeft, const FloatSample *reverbDryRight, const FloatSample *reverbWetLeft, const FloatSample *reverbWetRight, Bit32u outLength); + + template + void produceOutput(Sample *outStream, const Sample *nonReverbLeft, const Sample *nonReverbRight, const Sample *reverbDryLeft, const Sample *reverbDryRight, const Sample *reverbWetLeft, const Sample *reverbWetRight, Bit32u outLength) { + if (outStream == NULL) { + leftChannelLPF.addPositionIncrement(outLength); + rightChannelLPF.addPositionIncrement(outLength); + return; + } + + while (0 < (outLength--)) { + SampleEx outSampleL; + SampleEx outSampleR; + + if (leftChannelLPF.hasNextSample()) { + outSampleL = leftChannelLPF.process(0); + outSampleR = rightChannelLPF.process(0); + } else { + SampleEx inSampleL = (SampleEx(*(nonReverbLeft++)) + SampleEx(*(reverbDryLeft++))) * synthGain + SampleEx(*(reverbWetLeft++)) * reverbGain; + SampleEx inSampleR = (SampleEx(*(nonReverbRight++)) + SampleEx(*(reverbDryRight++))) * synthGain + SampleEx(*(reverbWetRight++)) * reverbGain; + + outSampleL = leftChannelLPF.process(normaliseSample(inSampleL)); + outSampleR = rightChannelLPF.process(normaliseSample(inSampleR)); + } + + *(outStream++) = Synth::clipSampleEx(outSampleL); + *(outStream++) = Synth::clipSampleEx(outSampleR); + } + } +}; + +Analog *Analog::createAnalog(const AnalogOutputMode mode, const bool oldMT32AnalogLPF, const RendererType rendererType) { + switch (rendererType) + { + case RendererType_BIT16S: + return new AnalogImpl(mode, oldMT32AnalogLPF); + case RendererType_FLOAT: + return new AnalogImpl(mode, oldMT32AnalogLPF); + } + return NULL; +} + +template<> +bool AnalogImpl::process(IntSample *outStream, const IntSample *nonReverbLeft, const IntSample *nonReverbRight, const IntSample *reverbDryLeft, const IntSample *reverbDryRight, const IntSample *reverbWetLeft, const IntSample *reverbWetRight, Bit32u outLength) { + produceOutput(outStream, nonReverbLeft, nonReverbRight, reverbDryLeft, reverbDryRight, reverbWetLeft, reverbWetRight, outLength); + return true; +} + +template<> +bool AnalogImpl::process(IntSample *, const IntSample *, const IntSample *, const IntSample *, const IntSample *, const IntSample *, const IntSample *, Bit32u) { + return false; +} + +template<> +bool AnalogImpl::process(FloatSample *, const FloatSample *, const FloatSample *, const FloatSample *, const FloatSample *, const FloatSample *, const FloatSample *, Bit32u) { + return false; +} + +template<> +bool AnalogImpl::process(FloatSample *outStream, const FloatSample *nonReverbLeft, const FloatSample *nonReverbRight, const FloatSample *reverbDryLeft, const FloatSample *reverbDryRight, const FloatSample *reverbWetLeft, const FloatSample *reverbWetRight, Bit32u outLength) { + produceOutput(outStream, nonReverbLeft, nonReverbRight, reverbDryLeft, reverbDryRight, reverbWetLeft, reverbWetRight, outLength); + return true; +} + +template<> +void AnalogImpl::setSynthOutputGain(const float useSynthGain) { + synthGain = getIntOutputGain(useSynthGain); +} + +template<> +void AnalogImpl::setReverbOutputGain(const float useReverbGain, const bool mt32ReverbCompatibilityMode) { + reverbGain = getIntOutputGain(getActualReverbOutputGain(useReverbGain, mt32ReverbCompatibilityMode)); +} + +template<> +void AnalogImpl::setSynthOutputGain(const float useSynthGain) { + synthGain = useSynthGain; +} + +template<> +void AnalogImpl::setReverbOutputGain(const float useReverbGain, const bool mt32ReverbCompatibilityMode) { + reverbGain = getActualReverbOutputGain(useReverbGain, mt32ReverbCompatibilityMode); +} + +template<> +AbstractLowPassFilter &AbstractLowPassFilter::createLowPassFilter(AnalogOutputMode mode, bool oldMT32AnalogLPF) { + switch (mode) { + case AnalogOutputMode_COARSE: + return *new CoarseLowPassFilter(oldMT32AnalogLPF); + case AnalogOutputMode_ACCURATE: + return *new AccurateLowPassFilter(oldMT32AnalogLPF, false); + case AnalogOutputMode_OVERSAMPLED: + return *new AccurateLowPassFilter(oldMT32AnalogLPF, true); + default: + return *new NullLowPassFilter; + } +} + +template<> +AbstractLowPassFilter &AbstractLowPassFilter::createLowPassFilter(AnalogOutputMode mode, bool oldMT32AnalogLPF) { + switch (mode) { + case AnalogOutputMode_COARSE: + return *new CoarseLowPassFilter(oldMT32AnalogLPF); + case AnalogOutputMode_ACCURATE: + return *new AccurateLowPassFilter(oldMT32AnalogLPF, false); + case AnalogOutputMode_OVERSAMPLED: + return *new AccurateLowPassFilter(oldMT32AnalogLPF, true); + default: + return *new NullLowPassFilter; + } +} + +template<> +const IntSampleEx *CoarseLowPassFilter::getLPFTaps(const bool oldMT32AnalogLPF) { + return oldMT32AnalogLPF ? COARSE_LPF_INT_TAPS_MT32 : COARSE_LPF_INT_TAPS_CM32L; +} + +template<> +const FloatSample *CoarseLowPassFilter::getLPFTaps(const bool oldMT32AnalogLPF) { + return oldMT32AnalogLPF ? COARSE_LPF_FLOAT_TAPS_MT32 : COARSE_LPF_FLOAT_TAPS_CM32L; +} + +template<> +IntSampleEx CoarseLowPassFilter::normaliseSample(const IntSampleEx sample) { + return sample >> COARSE_LPF_INT_FRACTION_BITS; +} + +template<> +FloatSample CoarseLowPassFilter::normaliseSample(const FloatSample sample) { + return sample; +} + +AccurateLowPassFilter::AccurateLowPassFilter(const bool oldMT32AnalogLPF, const bool oversample) : + LPF_TAPS(oldMT32AnalogLPF ? ACCURATE_LPF_TAPS_MT32 : ACCURATE_LPF_TAPS_CM32L), + deltas(oversample ? ACCURATE_LPF_DELTAS_OVERSAMPLED : ACCURATE_LPF_DELTAS_REGULAR), + phaseIncrement(oversample ? ACCURATE_LPF_PHASE_INCREMENT_OVERSAMPLED : ACCURATE_LPF_PHASE_INCREMENT_REGULAR), + outputSampleRate(SAMPLE_RATE * ACCURATE_LPF_NUMBER_OF_PHASES / phaseIncrement), + ringBufferPosition(0), + phase(0) +{ + Synth::muteSampleBuffer(ringBuffer, ACCURATE_LPF_DELAY_LINE_LENGTH); +} + +FloatSample AccurateLowPassFilter::process(const FloatSample inSample) { + static const unsigned int DELAY_LINE_MASK = ACCURATE_LPF_DELAY_LINE_LENGTH - 1; + + FloatSample sample = (phase == 0) ? LPF_TAPS[ACCURATE_LPF_DELAY_LINE_LENGTH * ACCURATE_LPF_NUMBER_OF_PHASES] * ringBuffer[ringBufferPosition] : 0.0f; + if (!hasNextSample()) { + ringBuffer[ringBufferPosition] = inSample; + } + + for (unsigned int tapIx = phase, delaySampleIx = 0; delaySampleIx < ACCURATE_LPF_DELAY_LINE_LENGTH; delaySampleIx++, tapIx += ACCURATE_LPF_NUMBER_OF_PHASES) { + sample += LPF_TAPS[tapIx] * ringBuffer[(delaySampleIx + ringBufferPosition) & DELAY_LINE_MASK]; + } + + phase += phaseIncrement; + if (ACCURATE_LPF_NUMBER_OF_PHASES <= phase) { + phase -= ACCURATE_LPF_NUMBER_OF_PHASES; + ringBufferPosition = (ringBufferPosition - 1) & DELAY_LINE_MASK; + } + + return ACCURATE_LPF_NUMBER_OF_PHASES * sample; +} + +IntSampleEx AccurateLowPassFilter::process(const IntSampleEx sample) { + return IntSampleEx(process(FloatSample(sample))); +} + +bool AccurateLowPassFilter::hasNextSample() const { + return phaseIncrement <= phase; +} + +unsigned int AccurateLowPassFilter::getOutputSampleRate() const { + return outputSampleRate; +} + +unsigned int AccurateLowPassFilter::estimateInSampleCount(const unsigned int outSamples) const { + Bit32u cycleCount = outSamples / ACCURATE_LPF_NUMBER_OF_PHASES; + Bit32u remainder = outSamples - cycleCount * ACCURATE_LPF_NUMBER_OF_PHASES; + return cycleCount * phaseIncrement + deltas[remainder][phase]; +} + +void AccurateLowPassFilter::addPositionIncrement(const unsigned int positionIncrement) { + phase = (phase + positionIncrement * phaseIncrement) % ACCURATE_LPF_NUMBER_OF_PHASES; +} + +} // namespace MT32Emu diff --git a/src/SOUND/munt/Analog.h b/src/SOUND/munt/Analog.h new file mode 100644 index 000000000..edaab4fe2 --- /dev/null +++ b/src/SOUND/munt/Analog.h @@ -0,0 +1,53 @@ +/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher + * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#ifndef MT32EMU_ANALOG_H +#define MT32EMU_ANALOG_H + +#include "globals.h" +#include "internals.h" +#include "Enumerations.h" +#include "Types.h" + +namespace MT32Emu { + +/* Analog class is dedicated to perform fair emulation of analogue circuitry of hardware units that is responsible + * for processing output signal after the DAC. It appears that the analogue circuit labeled "LPF" on the schematic + * also applies audible changes to the signal spectra. There is a significant boost of higher frequencies observed + * aside from quite poor attenuation of the mirror spectra above 16 kHz which is due to a relatively low filter order. + * + * As the final mixing of multiplexed output signal is performed after the DAC, this function is migrated here from Synth. + * Saying precisely, mixing is performed within the LPF as the entrance resistors are actually components of a LPF + * designed using the multiple feedback topology. Nevertheless, the schematic separates them. + */ +class Analog { +public: + static Analog *createAnalog(const AnalogOutputMode mode, const bool oldMT32AnalogLPF, const RendererType rendererType); + + virtual ~Analog() {}; + virtual unsigned int getOutputSampleRate() const = 0; + virtual Bit32u getDACStreamsLength(const Bit32u outputLength) const = 0; + virtual void setSynthOutputGain(const float synthGain) = 0; + virtual void setReverbOutputGain(const float reverbGain, const bool mt32ReverbCompatibilityMode) = 0; + + virtual bool process(IntSample *outStream, const IntSample *nonReverbLeft, const IntSample *nonReverbRight, const IntSample *reverbDryLeft, const IntSample *reverbDryRight, const IntSample *reverbWetLeft, const IntSample *reverbWetRight, Bit32u outLength) = 0; + virtual bool process(FloatSample *outStream, const FloatSample *nonReverbLeft, const FloatSample *nonReverbRight, const FloatSample *reverbDryLeft, const FloatSample *reverbDryRight, const FloatSample *reverbWetLeft, const FloatSample *reverbWetRight, Bit32u outLength) = 0; +}; + +} // namespace MT32Emu + +#endif // #ifndef MT32EMU_ANALOG_H diff --git a/src/SOUND/munt/BReverbModel.cpp b/src/SOUND/munt/BReverbModel.cpp new file mode 100644 index 000000000..af559a92a --- /dev/null +++ b/src/SOUND/munt/BReverbModel.cpp @@ -0,0 +1,662 @@ +/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher + * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#include + +#include "internals.h" + +#include "BReverbModel.h" +#include "Synth.h" + +// Analysing of state of reverb RAM address lines gives exact sizes of the buffers of filters used. This also indicates that +// the reverb model implemented in the real devices consists of three series allpass filters preceded by a non-feedback comb (or a delay with a LPF) +// and followed by three parallel comb filters + +namespace MT32Emu { + +// Because LA-32 chip makes it's output available to process by the Boss chip with a significant delay, +// the Boss chip puts to the buffer the LA32 dry output when it is ready and performs processing of the _previously_ latched data. +// Of course, the right way would be to use a dedicated variable for this, but our reverb model is way higher level, +// so we can simply increase the input buffer size. +static const Bit32u PROCESS_DELAY = 1; + +static const Bit32u MODE_3_ADDITIONAL_DELAY = 1; +static const Bit32u MODE_3_FEEDBACK_DELAY = 1; + +// Avoid denormals degrading performance, using biased input +static const FloatSample BIAS = 1e-20f; + +struct BReverbSettings { + const Bit32u numberOfAllpasses; + const Bit32u * const allpassSizes; + const Bit32u numberOfCombs; + const Bit32u * const combSizes; + const Bit32u * const outLPositions; + const Bit32u * const outRPositions; + const Bit8u * const filterFactors; + const Bit8u * const feedbackFactors; + const Bit8u * const dryAmps; + const Bit8u * const wetLevels; + const Bit8u lpfAmp; +}; + +// Default reverb settings for "new" reverb model implemented in CM-32L / LAPC-I. +// Found by tracing reverb RAM data lines (thanks go to Lord_Nightmare & balrog). +static const BReverbSettings &getCM32L_LAPCSettings(const ReverbMode mode) { + static const Bit32u MODE_0_NUMBER_OF_ALLPASSES = 3; + static const Bit32u MODE_0_ALLPASSES[] = {994, 729, 78}; + static const Bit32u MODE_0_NUMBER_OF_COMBS = 4; // Well, actually there are 3 comb filters, but the entrance LPF + delay can be processed via a hacked comb. + static const Bit32u MODE_0_COMBS[] = {705 + PROCESS_DELAY, 2349, 2839, 3632}; + static const Bit32u MODE_0_OUTL[] = {2349, 141, 1960}; + static const Bit32u MODE_0_OUTR[] = {1174, 1570, 145}; + static const Bit8u MODE_0_COMB_FACTOR[] = {0xA0, 0x60, 0x60, 0x60}; + static const Bit8u MODE_0_COMB_FEEDBACK[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x28, 0x48, 0x60, 0x78, 0x80, 0x88, 0x90, 0x98, + 0x28, 0x48, 0x60, 0x78, 0x80, 0x88, 0x90, 0x98, + 0x28, 0x48, 0x60, 0x78, 0x80, 0x88, 0x90, 0x98}; + static const Bit8u MODE_0_DRY_AMP[] = {0xA0, 0xA0, 0xA0, 0xA0, 0xB0, 0xB0, 0xB0, 0xD0}; + static const Bit8u MODE_0_WET_AMP[] = {0x10, 0x30, 0x50, 0x70, 0x90, 0xC0, 0xF0, 0xF0}; + static const Bit8u MODE_0_LPF_AMP = 0x60; + + static const Bit32u MODE_1_NUMBER_OF_ALLPASSES = 3; + static const Bit32u MODE_1_ALLPASSES[] = {1324, 809, 176}; + static const Bit32u MODE_1_NUMBER_OF_COMBS = 4; // Same as for mode 0 above + static const Bit32u MODE_1_COMBS[] = {961 + PROCESS_DELAY, 2619, 3545, 4519}; + static const Bit32u MODE_1_OUTL[] = {2618, 1760, 4518}; + static const Bit32u MODE_1_OUTR[] = {1300, 3532, 2274}; + static const Bit8u MODE_1_COMB_FACTOR[] = {0x80, 0x60, 0x60, 0x60}; + static const Bit8u MODE_1_COMB_FEEDBACK[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x28, 0x48, 0x60, 0x70, 0x78, 0x80, 0x90, 0x98, + 0x28, 0x48, 0x60, 0x78, 0x80, 0x88, 0x90, 0x98, + 0x28, 0x48, 0x60, 0x78, 0x80, 0x88, 0x90, 0x98}; + static const Bit8u MODE_1_DRY_AMP[] = {0xA0, 0xA0, 0xB0, 0xB0, 0xB0, 0xB0, 0xB0, 0xE0}; + static const Bit8u MODE_1_WET_AMP[] = {0x10, 0x30, 0x50, 0x70, 0x90, 0xC0, 0xF0, 0xF0}; + static const Bit8u MODE_1_LPF_AMP = 0x60; + + static const Bit32u MODE_2_NUMBER_OF_ALLPASSES = 3; + static const Bit32u MODE_2_ALLPASSES[] = {969, 644, 157}; + static const Bit32u MODE_2_NUMBER_OF_COMBS = 4; // Same as for mode 0 above + static const Bit32u MODE_2_COMBS[] = {116 + PROCESS_DELAY, 2259, 2839, 3539}; + static const Bit32u MODE_2_OUTL[] = {2259, 718, 1769}; + static const Bit32u MODE_2_OUTR[] = {1136, 2128, 1}; + static const Bit8u MODE_2_COMB_FACTOR[] = {0, 0x20, 0x20, 0x20}; + static const Bit8u MODE_2_COMB_FEEDBACK[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x30, 0x58, 0x78, 0x88, 0xA0, 0xB8, 0xC0, 0xD0, + 0x30, 0x58, 0x78, 0x88, 0xA0, 0xB8, 0xC0, 0xD0, + 0x30, 0x58, 0x78, 0x88, 0xA0, 0xB8, 0xC0, 0xD0}; + static const Bit8u MODE_2_DRY_AMP[] = {0xA0, 0xA0, 0xB0, 0xB0, 0xB0, 0xB0, 0xC0, 0xE0}; + static const Bit8u MODE_2_WET_AMP[] = {0x10, 0x30, 0x50, 0x70, 0x90, 0xC0, 0xF0, 0xF0}; + static const Bit8u MODE_2_LPF_AMP = 0x80; + + static const Bit32u MODE_3_NUMBER_OF_ALLPASSES = 0; + static const Bit32u MODE_3_NUMBER_OF_COMBS = 1; + static const Bit32u MODE_3_DELAY[] = {16000 + MODE_3_FEEDBACK_DELAY + PROCESS_DELAY + MODE_3_ADDITIONAL_DELAY}; + static const Bit32u MODE_3_OUTL[] = {400, 624, 960, 1488, 2256, 3472, 5280, 8000}; + static const Bit32u MODE_3_OUTR[] = {800, 1248, 1920, 2976, 4512, 6944, 10560, 16000}; + static const Bit8u MODE_3_COMB_FACTOR[] = {0x68}; + static const Bit8u MODE_3_COMB_FEEDBACK[] = {0x68, 0x60}; + static const Bit8u MODE_3_DRY_AMP[] = {0x20, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, + 0x20, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50}; + static const Bit8u MODE_3_WET_AMP[] = {0x18, 0x18, 0x28, 0x40, 0x60, 0x80, 0xA8, 0xF8}; + + static const BReverbSettings REVERB_MODE_0_SETTINGS = {MODE_0_NUMBER_OF_ALLPASSES, MODE_0_ALLPASSES, MODE_0_NUMBER_OF_COMBS, MODE_0_COMBS, MODE_0_OUTL, MODE_0_OUTR, MODE_0_COMB_FACTOR, MODE_0_COMB_FEEDBACK, MODE_0_DRY_AMP, MODE_0_WET_AMP, MODE_0_LPF_AMP}; + static const BReverbSettings REVERB_MODE_1_SETTINGS = {MODE_1_NUMBER_OF_ALLPASSES, MODE_1_ALLPASSES, MODE_1_NUMBER_OF_COMBS, MODE_1_COMBS, MODE_1_OUTL, MODE_1_OUTR, MODE_1_COMB_FACTOR, MODE_1_COMB_FEEDBACK, MODE_1_DRY_AMP, MODE_1_WET_AMP, MODE_1_LPF_AMP}; + static const BReverbSettings REVERB_MODE_2_SETTINGS = {MODE_2_NUMBER_OF_ALLPASSES, MODE_2_ALLPASSES, MODE_2_NUMBER_OF_COMBS, MODE_2_COMBS, MODE_2_OUTL, MODE_2_OUTR, MODE_2_COMB_FACTOR, MODE_2_COMB_FEEDBACK, MODE_2_DRY_AMP, MODE_2_WET_AMP, MODE_2_LPF_AMP}; + static const BReverbSettings REVERB_MODE_3_SETTINGS = {MODE_3_NUMBER_OF_ALLPASSES, NULL, MODE_3_NUMBER_OF_COMBS, MODE_3_DELAY, MODE_3_OUTL, MODE_3_OUTR, MODE_3_COMB_FACTOR, MODE_3_COMB_FEEDBACK, MODE_3_DRY_AMP, MODE_3_WET_AMP, 0}; + + static const BReverbSettings * const REVERB_SETTINGS[] = {&REVERB_MODE_0_SETTINGS, &REVERB_MODE_1_SETTINGS, &REVERB_MODE_2_SETTINGS, &REVERB_MODE_3_SETTINGS}; + + return *REVERB_SETTINGS[mode]; +} + +// Default reverb settings for "old" reverb model implemented in MT-32. +// Found by tracing reverb RAM data lines (thanks go to Lord_Nightmare & balrog). +static const BReverbSettings &getMT32Settings(const ReverbMode mode) { + static const Bit32u MODE_0_NUMBER_OF_ALLPASSES = 3; + static const Bit32u MODE_0_ALLPASSES[] = {994, 729, 78}; + static const Bit32u MODE_0_NUMBER_OF_COMBS = 4; // Same as above in the new model implementation + static const Bit32u MODE_0_COMBS[] = {575 + PROCESS_DELAY, 2040, 2752, 3629}; + static const Bit32u MODE_0_OUTL[] = {2040, 687, 1814}; + static const Bit32u MODE_0_OUTR[] = {1019, 2072, 1}; + static const Bit8u MODE_0_COMB_FACTOR[] = {0xB0, 0x60, 0x60, 0x60}; + static const Bit8u MODE_0_COMB_FEEDBACK[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x28, 0x48, 0x60, 0x70, 0x78, 0x80, 0x90, 0x98, + 0x28, 0x48, 0x60, 0x78, 0x80, 0x88, 0x90, 0x98, + 0x28, 0x48, 0x60, 0x78, 0x80, 0x88, 0x90, 0x98}; + static const Bit8u MODE_0_DRY_AMP[] = {0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80}; + static const Bit8u MODE_0_WET_AMP[] = {0x10, 0x20, 0x30, 0x40, 0x50, 0x70, 0xA0, 0xE0}; + static const Bit8u MODE_0_LPF_AMP = 0x80; + + static const Bit32u MODE_1_NUMBER_OF_ALLPASSES = 3; + static const Bit32u MODE_1_ALLPASSES[] = {1324, 809, 176}; + static const Bit32u MODE_1_NUMBER_OF_COMBS = 4; // Same as above in the new model implementation + static const Bit32u MODE_1_COMBS[] = {961 + PROCESS_DELAY, 2619, 3545, 4519}; + static const Bit32u MODE_1_OUTL[] = {2618, 1760, 4518}; + static const Bit32u MODE_1_OUTR[] = {1300, 3532, 2274}; + static const Bit8u MODE_1_COMB_FACTOR[] = {0x90, 0x60, 0x60, 0x60}; + static const Bit8u MODE_1_COMB_FEEDBACK[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x28, 0x48, 0x60, 0x70, 0x78, 0x80, 0x90, 0x98, + 0x28, 0x48, 0x60, 0x78, 0x80, 0x88, 0x90, 0x98, + 0x28, 0x48, 0x60, 0x78, 0x80, 0x88, 0x90, 0x98}; + static const Bit8u MODE_1_DRY_AMP[] = {0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80}; + static const Bit8u MODE_1_WET_AMP[] = {0x10, 0x20, 0x30, 0x40, 0x50, 0x70, 0xA0, 0xE0}; + static const Bit8u MODE_1_LPF_AMP = 0x80; + + static const Bit32u MODE_2_NUMBER_OF_ALLPASSES = 3; + static const Bit32u MODE_2_ALLPASSES[] = {969, 644, 157}; + static const Bit32u MODE_2_NUMBER_OF_COMBS = 4; // Same as above in the new model implementation + static const Bit32u MODE_2_COMBS[] = {116 + PROCESS_DELAY, 2259, 2839, 3539}; + static const Bit32u MODE_2_OUTL[] = {2259, 718, 1769}; + static const Bit32u MODE_2_OUTR[] = {1136, 2128, 1}; + static const Bit8u MODE_2_COMB_FACTOR[] = {0, 0x60, 0x60, 0x60}; + static const Bit8u MODE_2_COMB_FEEDBACK[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x28, 0x48, 0x60, 0x70, 0x78, 0x80, 0x90, 0x98, + 0x28, 0x48, 0x60, 0x78, 0x80, 0x88, 0x90, 0x98, + 0x28, 0x48, 0x60, 0x78, 0x80, 0x88, 0x90, 0x98}; + static const Bit8u MODE_2_DRY_AMP[] = {0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80}; + static const Bit8u MODE_2_WET_AMP[] = {0x10, 0x20, 0x30, 0x40, 0x50, 0x70, 0xA0, 0xE0}; + static const Bit8u MODE_2_LPF_AMP = 0x80; + + static const Bit32u MODE_3_NUMBER_OF_ALLPASSES = 0; + static const Bit32u MODE_3_NUMBER_OF_COMBS = 1; + static const Bit32u MODE_3_DELAY[] = {16000 + MODE_3_FEEDBACK_DELAY + PROCESS_DELAY + MODE_3_ADDITIONAL_DELAY}; + static const Bit32u MODE_3_OUTL[] = {400, 624, 960, 1488, 2256, 3472, 5280, 8000}; + static const Bit32u MODE_3_OUTR[] = {800, 1248, 1920, 2976, 4512, 6944, 10560, 16000}; + static const Bit8u MODE_3_COMB_FACTOR[] = {0x68}; + static const Bit8u MODE_3_COMB_FEEDBACK[] = {0x68, 0x60}; + static const Bit8u MODE_3_DRY_AMP[] = {0x10, 0x10, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x10, 0x20, 0x20, 0x10, 0x20, 0x10, 0x20, 0x10}; + static const Bit8u MODE_3_WET_AMP[] = {0x08, 0x18, 0x28, 0x40, 0x60, 0x80, 0xA8, 0xF8}; + + static const BReverbSettings REVERB_MODE_0_SETTINGS = {MODE_0_NUMBER_OF_ALLPASSES, MODE_0_ALLPASSES, MODE_0_NUMBER_OF_COMBS, MODE_0_COMBS, MODE_0_OUTL, MODE_0_OUTR, MODE_0_COMB_FACTOR, MODE_0_COMB_FEEDBACK, MODE_0_DRY_AMP, MODE_0_WET_AMP, MODE_0_LPF_AMP}; + static const BReverbSettings REVERB_MODE_1_SETTINGS = {MODE_1_NUMBER_OF_ALLPASSES, MODE_1_ALLPASSES, MODE_1_NUMBER_OF_COMBS, MODE_1_COMBS, MODE_1_OUTL, MODE_1_OUTR, MODE_1_COMB_FACTOR, MODE_1_COMB_FEEDBACK, MODE_1_DRY_AMP, MODE_1_WET_AMP, MODE_1_LPF_AMP}; + static const BReverbSettings REVERB_MODE_2_SETTINGS = {MODE_2_NUMBER_OF_ALLPASSES, MODE_2_ALLPASSES, MODE_2_NUMBER_OF_COMBS, MODE_2_COMBS, MODE_2_OUTL, MODE_2_OUTR, MODE_2_COMB_FACTOR, MODE_2_COMB_FEEDBACK, MODE_2_DRY_AMP, MODE_2_WET_AMP, MODE_2_LPF_AMP}; + static const BReverbSettings REVERB_MODE_3_SETTINGS = {MODE_3_NUMBER_OF_ALLPASSES, NULL, MODE_3_NUMBER_OF_COMBS, MODE_3_DELAY, MODE_3_OUTL, MODE_3_OUTR, MODE_3_COMB_FACTOR, MODE_3_COMB_FEEDBACK, MODE_3_DRY_AMP, MODE_3_WET_AMP, 0}; + + static const BReverbSettings * const REVERB_SETTINGS[] = {&REVERB_MODE_0_SETTINGS, &REVERB_MODE_1_SETTINGS, &REVERB_MODE_2_SETTINGS, &REVERB_MODE_3_SETTINGS}; + + return *REVERB_SETTINGS[mode]; +} + +static inline IntSample weirdMul(IntSample sample, Bit8u addMask, Bit8u carryMask) { +#if MT32EMU_BOSS_REVERB_PRECISE_MODE + // This algorithm tries to emulate exactly Boss multiplication operation (at least this is what we see on reverb RAM data lines). + Bit8u mask = 0x80; + IntSampleEx res = 0; + for (int i = 0; i < 8; i++) { + IntSampleEx carry = (sample < 0) && (mask & carryMask) > 0 ? sample & 1 : 0; + sample >>= 1; + res += (mask & addMask) > 0 ? sample + carry : 0; + mask >>= 1; + } + return IntSample(res); +#else + (void)carryMask; + return IntSample((IntSampleEx(sample) * addMask) >> 8); +#endif +} + +static inline FloatSample weirdMul(FloatSample sample, Bit8u addMask, Bit8u carryMask) { + (void)carryMask; + return sample * addMask / 256.0f; +} + +static inline IntSample halveSample(IntSample sample) { + return sample >> 1; +} + +static inline FloatSample halveSample(FloatSample sample) { + return 0.5f * sample; +} + +static inline IntSample quarterSample(IntSample sample) { +#if MT32EMU_BOSS_REVERB_PRECISE_MODE + return (sample >> 1) / 2; +#else + return sample >> 2; +#endif +} + +static inline FloatSample quarterSample(FloatSample sample) { + return 0.25f * sample; +} + +static inline IntSample addDCBias(IntSample sample) { + return sample; +} + +static inline FloatSample addDCBias(FloatSample sample) { + return sample + BIAS; +} + +static inline IntSample addAllpassNoise(IntSample sample) { +#if MT32EMU_BOSS_REVERB_PRECISE_MODE + // This introduces reverb noise which actually makes output from the real Boss chip nondeterministic + return sample - 1; +#else + return sample; +#endif +} + +static inline FloatSample addAllpassNoise(FloatSample sample) { + return sample; +} + +/* NOTE: + * Thanks to Mok for discovering, the adder in BOSS reverb chip is found to perform addition with saturation to avoid integer overflow. + * Analysing of the algorithm suggests that the overflow is most probable when the combs output is added below. + * So, despite this isn't actually accurate, we only add the check here for performance reasons. + */ +static inline IntSample mixCombs(IntSample out1, IntSample out2, IntSample out3) { +#if MT32EMU_BOSS_REVERB_PRECISE_MODE + return Synth::clipSampleEx(Synth::clipSampleEx(Synth::clipSampleEx(Synth::clipSampleEx(IntSampleEx(out1) + (IntSampleEx(out1) >> 1)) + IntSampleEx(out2)) + (IntSampleEx(out2) >> 1)) + IntSampleEx(out3)); +#else + return Synth::clipSampleEx(IntSampleEx(out1) + (IntSampleEx(out1) >> 1) + IntSampleEx(out2) + (IntSampleEx(out2) >> 1) + IntSampleEx(out3)); +#endif +} + +static inline FloatSample mixCombs(FloatSample out1, FloatSample out2, FloatSample out3) { + return 1.5f * (out1 + out2) + out3; +} + +template +class RingBuffer { + static inline Sample sampleValueThreshold(); + +protected: + Sample *buffer; + const Bit32u size; + Bit32u index; + +public: + RingBuffer(const Bit32u newsize) : size(newsize), index(0) { + buffer = new Sample[size]; + } + + virtual ~RingBuffer() { + delete[] buffer; + buffer = NULL; + } + + Sample next() { + if (++index >= size) { + index = 0; + } + return buffer[index]; + } + + bool isEmpty() const { + if (buffer == NULL) return true; + + Sample *buf = buffer; + for (Bit32u i = 0; i < size; i++) { + if (*buf < -sampleValueThreshold() || *buf > sampleValueThreshold()) return false; + buf++; + } + return true; + } + + void mute() { + Synth::muteSampleBuffer(buffer, size); + } +}; + +template<> +IntSample RingBuffer::sampleValueThreshold() { + return 8; +} + +template<> +FloatSample RingBuffer::sampleValueThreshold() { + return 0.001f; +} + +template +class AllpassFilter : public RingBuffer { +public: + AllpassFilter(const Bit32u useSize) : RingBuffer(useSize) {} + + // This model corresponds to the allpass filter implementation of the real CM-32L device + // found from sample analysis + Sample process(const Sample in) { + const Sample bufferOut = this->next(); + + // store input - feedback / 2 + this->buffer[this->index] = in - halveSample(bufferOut); + + // return buffer output + feedforward / 2 + return bufferOut + halveSample(this->buffer[this->index]); + } +}; + +template +class CombFilter : public RingBuffer { +protected: + const Bit8u filterFactor; + Bit8u feedbackFactor; + +public: + CombFilter(const Bit32u useSize, const Bit8u useFilterFactor) : RingBuffer(useSize), filterFactor(useFilterFactor) {} + + // This model corresponds to the comb filter implementation of the real CM-32L device + void process(const Sample in) { + + // the previously stored value + const Sample last = this->buffer[this->index]; + + // prepare input + feedback + const Sample filterIn = in + weirdMul(this->next(), feedbackFactor, 0xF0); + + // store input + feedback processed by a low-pass filter + this->buffer[this->index] = weirdMul(last, filterFactor, 0xC0) - filterIn; + } + + Sample getOutputAt(const Bit32u outIndex) const { + return this->buffer[(this->size + this->index - outIndex) % this->size]; + } + + void setFeedbackFactor(const Bit8u useFeedbackFactor) { + feedbackFactor = useFeedbackFactor; + } +}; + +template +class DelayWithLowPassFilter : public CombFilter { + Bit8u amp; + +public: + DelayWithLowPassFilter(const Bit32u useSize, const Bit8u useFilterFactor, const Bit8u useAmp) + : CombFilter(useSize, useFilterFactor), amp(useAmp) {} + + void process(const Sample in) { + // the previously stored value + const Sample last = this->buffer[this->index]; + + // move to the next index + this->next(); + + // low-pass filter process + Sample lpfOut = weirdMul(last, this->filterFactor, 0xFF) + in; + + // store lpfOut multiplied by LPF amp factor + this->buffer[this->index] = weirdMul(lpfOut, amp, 0xFF); + } +}; + +template +class TapDelayCombFilter : public CombFilter { + Bit32u outL; + Bit32u outR; + +public: + TapDelayCombFilter(const Bit32u useSize, const Bit8u useFilterFactor) : CombFilter(useSize, useFilterFactor) {} + + void process(const Sample in) { + // the previously stored value + const Sample last = this->buffer[this->index]; + + // move to the next index + this->next(); + + // prepare input + feedback + // Actually, the size of the filter varies with the TIME parameter, the feedback sample is taken from the position just below the right output + const Sample filterIn = in + weirdMul(this->getOutputAt(outR + MODE_3_FEEDBACK_DELAY), this->feedbackFactor, 0xF0); + + // store input + feedback processed by a low-pass filter + this->buffer[this->index] = weirdMul(last, this->filterFactor, 0xF0) - filterIn; + } + + Sample getLeftOutput() const { + return this->getOutputAt(outL + PROCESS_DELAY + MODE_3_ADDITIONAL_DELAY); + } + + Sample getRightOutput() const { + return this->getOutputAt(outR + PROCESS_DELAY + MODE_3_ADDITIONAL_DELAY); + } + + void setOutputPositions(const Bit32u useOutL, const Bit32u useOutR) { + outL = useOutL; + outR = useOutR; + } +}; + +template +class BReverbModelImpl : public BReverbModel { +public: + AllpassFilter **allpasses; + CombFilter **combs; + + const BReverbSettings ¤tSettings; + const bool tapDelayMode; + Bit8u dryAmp; + Bit8u wetLevel; + + BReverbModelImpl(const ReverbMode mode, const bool mt32CompatibleModel) : + allpasses(NULL), combs(NULL), + currentSettings(mt32CompatibleModel ? getMT32Settings(mode) : getCM32L_LAPCSettings(mode)), + tapDelayMode(mode == REVERB_MODE_TAP_DELAY) + {} + + ~BReverbModelImpl() { + close(); + } + + bool isOpen() const { + return combs != NULL; + } + + void open() { + if (isOpen()) return; + if (currentSettings.numberOfAllpasses > 0) { + allpasses = new AllpassFilter*[currentSettings.numberOfAllpasses]; + for (Bit32u i = 0; i < currentSettings.numberOfAllpasses; i++) { + allpasses[i] = new AllpassFilter(currentSettings.allpassSizes[i]); + } + } + combs = new CombFilter*[currentSettings.numberOfCombs]; + if (tapDelayMode) { + *combs = new TapDelayCombFilter(*currentSettings.combSizes, *currentSettings.filterFactors); + } else { + combs[0] = new DelayWithLowPassFilter(currentSettings.combSizes[0], currentSettings.filterFactors[0], currentSettings.lpfAmp); + for (Bit32u i = 1; i < currentSettings.numberOfCombs; i++) { + combs[i] = new CombFilter(currentSettings.combSizes[i], currentSettings.filterFactors[i]); + } + } + mute(); + } + + void close() { + if (allpasses != NULL) { + for (Bit32u i = 0; i < currentSettings.numberOfAllpasses; i++) { + if (allpasses[i] != NULL) { + delete allpasses[i]; + allpasses[i] = NULL; + } + } + delete[] allpasses; + allpasses = NULL; + } + if (combs != NULL) { + for (Bit32u i = 0; i < currentSettings.numberOfCombs; i++) { + if (combs[i] != NULL) { + delete combs[i]; + combs[i] = NULL; + } + } + delete[] combs; + combs = NULL; + } + } + + void mute() { + if (allpasses != NULL) { + for (Bit32u i = 0; i < currentSettings.numberOfAllpasses; i++) { + allpasses[i]->mute(); + } + } + if (combs != NULL) { + for (Bit32u i = 0; i < currentSettings.numberOfCombs; i++) { + combs[i]->mute(); + } + } + } + + void setParameters(Bit8u time, Bit8u level) { + if (!isOpen()) return; + level &= 7; + time &= 7; + if (tapDelayMode) { + TapDelayCombFilter *comb = static_cast *> (*combs); + comb->setOutputPositions(currentSettings.outLPositions[time], currentSettings.outRPositions[time & 7]); + comb->setFeedbackFactor(currentSettings.feedbackFactors[((level < 3) || (time < 6)) ? 0 : 1]); + } else { + for (Bit32u i = 1; i < currentSettings.numberOfCombs; i++) { + combs[i]->setFeedbackFactor(currentSettings.feedbackFactors[(i << 3) + time]); + } + } + if (time == 0 && level == 0) { + dryAmp = wetLevel = 0; + } else { + if (tapDelayMode && ((time == 0) || (time == 1 && level == 1))) { + // Looks like MT-32 implementation has some minor quirks in this mode: + // for odd level values, the output level changes sometimes depending on the time value which doesn't seem right. + dryAmp = currentSettings.dryAmps[level + 8]; + } else { + dryAmp = currentSettings.dryAmps[level]; + } + wetLevel = currentSettings.wetLevels[level]; + } + } + + bool isActive() const { + if (!isOpen()) return false; + for (Bit32u i = 0; i < currentSettings.numberOfAllpasses; i++) { + if (!allpasses[i]->isEmpty()) return true; + } + for (Bit32u i = 0; i < currentSettings.numberOfCombs; i++) { + if (!combs[i]->isEmpty()) return true; + } + return false; + } + + bool isMT32Compatible(const ReverbMode mode) const { + return ¤tSettings == &getMT32Settings(mode); + } + + template + void produceOutput(const Sample *inLeft, const Sample *inRight, Sample *outLeft, Sample *outRight, Bit32u numSamples) { + if (!isOpen()) { + Synth::muteSampleBuffer(outLeft, numSamples); + Synth::muteSampleBuffer(outRight, numSamples); + return; + } + + while ((numSamples--) > 0) { + Sample dry; + + if (tapDelayMode) { + dry = halveSample(*(inLeft++)) + halveSample(*(inRight++)); + } else { + dry = quarterSample(*(inLeft++)) + quarterSample(*(inRight++)); + } + + // Looks like dryAmp doesn't change in MT-32 but it does in CM-32L / LAPC-I + dry = weirdMul(addDCBias(dry), dryAmp, 0xFF); + + if (tapDelayMode) { + TapDelayCombFilter *comb = static_cast *>(*combs); + comb->process(dry); + if (outLeft != NULL) { + *(outLeft++) = weirdMul(comb->getLeftOutput(), wetLevel, 0xFF); + } + if (outRight != NULL) { + *(outRight++) = weirdMul(comb->getRightOutput(), wetLevel, 0xFF); + } + } else { + DelayWithLowPassFilter * const entranceDelay = static_cast *>(combs[0]); + // If the output position is equal to the comb size, get it now in order not to loose it + Sample link = entranceDelay->getOutputAt(currentSettings.combSizes[0] - 1); + + // Entrance LPF. Note, comb.process() differs a bit here. + entranceDelay->process(dry); + + link = allpasses[0]->process(addAllpassNoise(link)); + link = allpasses[1]->process(link); + link = allpasses[2]->process(link); + + // If the output position is equal to the comb size, get it now in order not to loose it + Sample outL1 = combs[1]->getOutputAt(currentSettings.outLPositions[0] - 1); + + combs[1]->process(link); + combs[2]->process(link); + combs[3]->process(link); + + if (outLeft != NULL) { + Sample outL2 = combs[2]->getOutputAt(currentSettings.outLPositions[1]); + Sample outL3 = combs[3]->getOutputAt(currentSettings.outLPositions[2]); + Sample outSample = mixCombs(outL1, outL2, outL3); + *(outLeft++) = weirdMul(outSample, wetLevel, 0xFF); + } + if (outRight != NULL) { + Sample outR1 = combs[1]->getOutputAt(currentSettings.outRPositions[0]); + Sample outR2 = combs[2]->getOutputAt(currentSettings.outRPositions[1]); + Sample outR3 = combs[3]->getOutputAt(currentSettings.outRPositions[2]); + Sample outSample = mixCombs(outR1, outR2, outR3); + *(outRight++) = weirdMul(outSample, wetLevel, 0xFF); + } + } // if (tapDelayMode) + } // while ((numSamples--) > 0) + } // produceOutput + + bool process(const IntSample *inLeft, const IntSample *inRight, IntSample *outLeft, IntSample *outRight, Bit32u numSamples); + bool process(const FloatSample *inLeft, const FloatSample *inRight, FloatSample *outLeft, FloatSample *outRight, Bit32u numSamples); +}; + +BReverbModel *BReverbModel::createBReverbModel(const ReverbMode mode, const bool mt32CompatibleModel, const RendererType rendererType) { + switch (rendererType) + { + case RendererType_BIT16S: + return new BReverbModelImpl(mode, mt32CompatibleModel); + case RendererType_FLOAT: + return new BReverbModelImpl(mode, mt32CompatibleModel); + } + return NULL; +} + +template <> +bool BReverbModelImpl::process(const IntSample *inLeft, const IntSample *inRight, IntSample *outLeft, IntSample *outRight, Bit32u numSamples) { + produceOutput(inLeft, inRight, outLeft, outRight, numSamples); + return true; +} + +template <> +bool BReverbModelImpl::process(const FloatSample *, const FloatSample *, FloatSample *, FloatSample *, Bit32u) { + return false; +} + +template <> +bool BReverbModelImpl::process(const IntSample *, const IntSample *, IntSample *, IntSample *, Bit32u) { + return false; +} + +template <> +bool BReverbModelImpl::process(const FloatSample *inLeft, const FloatSample *inRight, FloatSample *outLeft, FloatSample *outRight, Bit32u numSamples) { + produceOutput(inLeft, inRight, outLeft, outRight, numSamples); + return true; +} + +} // namespace MT32Emu diff --git a/src/SOUND/munt/BReverbModel.h b/src/SOUND/munt/BReverbModel.h new file mode 100644 index 000000000..2d0c5b5ff --- /dev/null +++ b/src/SOUND/munt/BReverbModel.h @@ -0,0 +1,48 @@ +/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher + * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#ifndef MT32EMU_B_REVERB_MODEL_H +#define MT32EMU_B_REVERB_MODEL_H + +#include "globals.h" +#include "internals.h" +#include "Enumerations.h" +#include "Types.h" + +namespace MT32Emu { + +class BReverbModel { +public: + static BReverbModel *createBReverbModel(const ReverbMode mode, const bool mt32CompatibleModel, const RendererType rendererType); + + virtual ~BReverbModel() {}; + virtual bool isOpen() const = 0; + // After construction or a close(), open() must be called at least once before any other call (with the exception of close()). + virtual void open() = 0; + // May be called multiple times without an open() in between. + virtual void close() = 0; + virtual void mute() = 0; + virtual void setParameters(Bit8u time, Bit8u level) = 0; + virtual bool isActive() const = 0; + virtual bool isMT32Compatible(const ReverbMode mode) const = 0; + virtual bool process(const IntSample *inLeft, const IntSample *inRight, IntSample *outLeft, IntSample *outRight, Bit32u numSamples) = 0; + virtual bool process(const FloatSample *inLeft, const FloatSample *inRight, FloatSample *outLeft, FloatSample *outRight, Bit32u numSamples) = 0; +}; + +} // namespace MT32Emu + +#endif // #ifndef MT32EMU_B_REVERB_MODEL_H diff --git a/src/SOUND/munt/Enumerations.h b/src/SOUND/munt/Enumerations.h new file mode 100644 index 000000000..8dad8e88e --- /dev/null +++ b/src/SOUND/munt/Enumerations.h @@ -0,0 +1,188 @@ +/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher + * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +/* Using two guards since this file may be included twice with different MT32EMU_C_ENUMERATIONS define. */ + +#if (!defined MT32EMU_CPP_ENUMERATIONS_H && !defined MT32EMU_C_ENUMERATIONS) || (!defined MT32EMU_C_ENUMERATIONS_H && defined MT32EMU_C_ENUMERATIONS) + +#ifdef MT32EMU_C_ENUMERATIONS + +#define MT32EMU_C_ENUMERATIONS_H + +#define MT32EMU_DAC_INPUT_MODE_NAME mt32emu_dac_input_mode +#define MT32EMU_DAC_INPUT_MODE(ident) MT32EMU_DAC_##ident + +#define MT32EMU_MIDI_DELAY_MODE_NAME mt32emu_midi_delay_mode +#define MT32EMU_MIDI_DELAY_MODE(ident) MT32EMU_MDM_##ident + +#define MT32EMU_ANALOG_OUTPUT_MODE_NAME mt32emu_analog_output_mode +#define MT32EMU_ANALOG_OUTPUT_MODE(ident) MT32EMU_AOM_##ident + +#define MT32EMU_PARTIAL_STATE_NAME mt32emu_partial_state +#define MT32EMU_PARTIAL_STATE(ident) MT32EMU_PS_##ident + +#define MT32EMU_SAMPLERATE_CONVERSION_QUALITY_NAME mt32emu_samplerate_conversion_quality +#define MT32EMU_SAMPLERATE_CONVERSION_QUALITY(ident) MT32EMU_SRCQ_##ident + +#define MT32EMU_RENDERER_TYPE_NAME mt32emu_renderer_type +#define MT32EMU_RENDERER_TYPE(ident) MT32EMU_RT_##ident + +#else /* #ifdef MT32EMU_C_ENUMERATIONS */ + +#define MT32EMU_CPP_ENUMERATIONS_H + +#define MT32EMU_DAC_INPUT_MODE_NAME DACInputMode +#define MT32EMU_DAC_INPUT_MODE(ident) DACInputMode_##ident + +#define MT32EMU_MIDI_DELAY_MODE_NAME MIDIDelayMode +#define MT32EMU_MIDI_DELAY_MODE(ident) MIDIDelayMode_##ident + +#define MT32EMU_ANALOG_OUTPUT_MODE_NAME AnalogOutputMode +#define MT32EMU_ANALOG_OUTPUT_MODE(ident) AnalogOutputMode_##ident + +#define MT32EMU_PARTIAL_STATE_NAME PartialState +#define MT32EMU_PARTIAL_STATE(ident) PartialState_##ident + +#define MT32EMU_SAMPLERATE_CONVERSION_QUALITY_NAME SamplerateConversionQuality +#define MT32EMU_SAMPLERATE_CONVERSION_QUALITY(ident) SamplerateConversionQuality_##ident + +#define MT32EMU_RENDERER_TYPE_NAME RendererType +#define MT32EMU_RENDERER_TYPE(ident) RendererType_##ident + +namespace MT32Emu { + +#endif /* #ifdef MT32EMU_C_ENUMERATIONS */ + +/** + * Methods for emulating the connection between the LA32 and the DAC, which involves + * some hacks in the real devices for doubling the volume. + * See also http://en.wikipedia.org/wiki/Roland_MT-32#Digital_overflow + */ +enum MT32EMU_DAC_INPUT_MODE_NAME { + /** + * Produces samples at double the volume, without tricks. + * Nicer overdrive characteristics than the DAC hacks (it simply clips samples within range) + * Higher quality than the real devices + */ + MT32EMU_DAC_INPUT_MODE(NICE), + + /** + * Produces samples that exactly match the bits output from the emulated LA32. + * Nicer overdrive characteristics than the DAC hacks (it simply clips samples within range) + * Much less likely to overdrive than any other mode. + * Half the volume of any of the other modes. + * Output gain is ignored for both LA32 and reverb output. + * Perfect for developers while debugging :) + */ + MT32EMU_DAC_INPUT_MODE(PURE), + + /** + * Re-orders the LA32 output bits as in early generation MT-32s (according to Wikipedia). + * Bit order at DAC (where each number represents the original LA32 output bit number, and XX means the bit is always low): + * 15 13 12 11 10 09 08 07 06 05 04 03 02 01 00 XX + */ + MT32EMU_DAC_INPUT_MODE(GENERATION1), + + /** + * Re-orders the LA32 output bits as in later generations (personally confirmed on my CM-32L - KG). + * Bit order at DAC (where each number represents the original LA32 output bit number): + * 15 13 12 11 10 09 08 07 06 05 04 03 02 01 00 14 + */ + MT32EMU_DAC_INPUT_MODE(GENERATION2) +}; + +/** Methods for emulating the effective delay of incoming MIDI messages introduced by a MIDI interface. */ +enum MT32EMU_MIDI_DELAY_MODE_NAME { + /** Process incoming MIDI events immediately. */ + MT32EMU_MIDI_DELAY_MODE(IMMEDIATE), + + /** + * Delay incoming short MIDI messages as if they where transferred via a MIDI cable to a real hardware unit and immediate sysex processing. + * This ensures more accurate timing of simultaneous NoteOn messages. + */ + MT32EMU_MIDI_DELAY_MODE(DELAY_SHORT_MESSAGES_ONLY), + + /** Delay all incoming MIDI events as if they where transferred via a MIDI cable to a real hardware unit.*/ + MT32EMU_MIDI_DELAY_MODE(DELAY_ALL) +}; + +/** Methods for emulating the effects of analogue circuits of real hardware units on the output signal. */ +enum MT32EMU_ANALOG_OUTPUT_MODE_NAME { + /** Only digital path is emulated. The output samples correspond to the digital signal at the DAC entrance. */ + MT32EMU_ANALOG_OUTPUT_MODE(DIGITAL_ONLY), + /** Coarse emulation of LPF circuit. High frequencies are boosted, sample rate remains unchanged. */ + MT32EMU_ANALOG_OUTPUT_MODE(COARSE), + /** + * Finer emulation of LPF circuit. Output signal is upsampled to 48 kHz to allow emulation of audible mirror spectra above 16 kHz, + * which is passed through the LPF circuit without significant attenuation. + */ + MT32EMU_ANALOG_OUTPUT_MODE(ACCURATE), + /** + * Same as AnalogOutputMode_ACCURATE mode but the output signal is 2x oversampled, i.e. the output sample rate is 96 kHz. + * This makes subsequent resampling easier. Besides, due to nonlinear passband of the LPF emulated, it takes fewer number of MACs + * compared to a regular LPF FIR implementations. + */ + MT32EMU_ANALOG_OUTPUT_MODE(OVERSAMPLED) +}; + +enum MT32EMU_PARTIAL_STATE_NAME { + MT32EMU_PARTIAL_STATE(INACTIVE), + MT32EMU_PARTIAL_STATE(ATTACK), + MT32EMU_PARTIAL_STATE(SUSTAIN), + MT32EMU_PARTIAL_STATE(RELEASE) +}; + +enum MT32EMU_SAMPLERATE_CONVERSION_QUALITY_NAME { + /** Use this only when the speed is more important than the audio quality. */ + MT32EMU_SAMPLERATE_CONVERSION_QUALITY(FASTEST), + MT32EMU_SAMPLERATE_CONVERSION_QUALITY(FAST), + MT32EMU_SAMPLERATE_CONVERSION_QUALITY(GOOD), + MT32EMU_SAMPLERATE_CONVERSION_QUALITY(BEST) +}; + +enum MT32EMU_RENDERER_TYPE_NAME { + /** Use 16-bit signed samples in the renderer and the accurate wave generator model based on logarithmic fixed-point computations and LUTs. Maximum emulation accuracy and speed. */ + MT32EMU_RENDERER_TYPE(BIT16S), + /** Use float samples in the renderer and simplified wave generator model. Maximum output quality and minimum noise. */ + MT32EMU_RENDERER_TYPE(FLOAT) +}; + +#ifndef MT32EMU_C_ENUMERATIONS + +} // namespace MT32Emu + +#endif + +#undef MT32EMU_DAC_INPUT_MODE_NAME +#undef MT32EMU_DAC_INPUT_MODE + +#undef MT32EMU_MIDI_DELAY_MODE_NAME +#undef MT32EMU_MIDI_DELAY_MODE + +#undef MT32EMU_ANALOG_OUTPUT_MODE_NAME +#undef MT32EMU_ANALOG_OUTPUT_MODE + +#undef MT32EMU_PARTIAL_STATE_NAME +#undef MT32EMU_PARTIAL_STATE + +#undef MT32EMU_SAMPLERATE_CONVERSION_QUALITY_NAME +#undef MT32EMU_SAMPLERATE_CONVERSION_QUALITY + +#undef MT32EMU_RENDERER_TYPE_NAME +#undef MT32EMU_RENDERER_TYPE + +#endif /* #if (!defined MT32EMU_CPP_ENUMERATIONS_H && !defined MT32EMU_C_ENUMERATIONS) || (!defined MT32EMU_C_ENUMERATIONS_H && defined MT32EMU_C_ENUMERATIONS) */ diff --git a/src/SOUND/munt/File.cpp b/src/SOUND/munt/File.cpp new file mode 100644 index 000000000..a5967b4f3 --- /dev/null +++ b/src/SOUND/munt/File.cpp @@ -0,0 +1,77 @@ +/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher + * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#include + +#include "internals.h" + +#include "File.h" +#include "sha1/sha1.h" + +namespace MT32Emu { + +AbstractFile::AbstractFile() : sha1DigestCalculated(false) { + sha1Digest[0] = 0; + + reserved = NULL; +} + +AbstractFile::AbstractFile(const SHA1Digest &useSHA1Digest) : sha1DigestCalculated(true) { + memcpy(sha1Digest, useSHA1Digest, sizeof(SHA1Digest) - 1); + sha1Digest[sizeof(SHA1Digest) - 1] = 0; // Ensure terminator char. + + reserved = NULL; +} + +const File::SHA1Digest &AbstractFile::getSHA1() { + if (sha1DigestCalculated) { + return sha1Digest; + } + sha1DigestCalculated = true; + + size_t size = getSize(); + if (size == 0) { + return sha1Digest; + } + + const Bit8u *data = getData(); + if (data == NULL) { + return sha1Digest; + } + + unsigned char fileDigest[20]; + + sha1::calc(data, int(size), fileDigest); + sha1::toHexString(fileDigest, sha1Digest); + return sha1Digest; +} + +ArrayFile::ArrayFile(const Bit8u *useData, size_t useSize) : data(useData), size(useSize) +{} + +ArrayFile::ArrayFile(const Bit8u *useData, size_t useSize, const SHA1Digest &useSHA1Digest) : AbstractFile(useSHA1Digest), data(useData), size(useSize) +{} + +size_t ArrayFile::getSize() { + return size; +} + +const Bit8u *ArrayFile::getData() { + return data; +} + +} // namespace MT32Emu diff --git a/src/SOUND/munt/File.h b/src/SOUND/munt/File.h new file mode 100644 index 000000000..91a0a7fe6 --- /dev/null +++ b/src/SOUND/munt/File.h @@ -0,0 +1,73 @@ +/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher + * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#ifndef MT32EMU_FILE_H +#define MT32EMU_FILE_H + +#include + +#include "globals.h" +#include "Types.h" + +namespace MT32Emu { + +class MT32EMU_EXPORT File { +public: + // Includes terminator char. + typedef char SHA1Digest[41]; + + virtual ~File() {} + virtual size_t getSize() = 0; + virtual const Bit8u *getData() = 0; + virtual const SHA1Digest &getSHA1() = 0; + + virtual void close() = 0; +}; + +class MT32EMU_EXPORT AbstractFile : public File { +public: + const SHA1Digest &getSHA1(); + +protected: + AbstractFile(); + AbstractFile(const SHA1Digest &sha1Digest); + +private: + bool sha1DigestCalculated; + SHA1Digest sha1Digest; + + // Binary compatibility helper. + void *reserved; +}; + +class MT32EMU_EXPORT ArrayFile : public AbstractFile { +public: + ArrayFile(const Bit8u *data, size_t size); + ArrayFile(const Bit8u *data, size_t size, const SHA1Digest &sha1Digest); + + size_t getSize(); + const Bit8u *getData(); + void close() {} + +private: + const Bit8u *data; + size_t size; +}; + +} // namespace MT32Emu + +#endif // #ifndef MT32EMU_FILE_H diff --git a/src/SOUND/munt/FileStream.cpp b/src/SOUND/munt/FileStream.cpp new file mode 100644 index 000000000..48ecc84b1 --- /dev/null +++ b/src/SOUND/munt/FileStream.cpp @@ -0,0 +1,83 @@ +/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher + * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#include "internals.h" + +#include "FileStream.h" + +namespace MT32Emu { + +using std::ios_base; + +FileStream::FileStream() : ifsp(*new std::ifstream), data(NULL), size(0) +{} + +FileStream::~FileStream() { + // destructor closes ifsp + delete &ifsp; + delete[] data; +} + +size_t FileStream::getSize() { + if (size != 0) { + return size; + } + if (!ifsp.is_open()) { + return 0; + } + ifsp.seekg(0, ios_base::end); + size = size_t(ifsp.tellg()); + return size; +} + +const Bit8u *FileStream::getData() { + if (data != NULL) { + return data; + } + if (!ifsp.is_open()) { + return NULL; + } + if (getSize() == 0) { + return NULL; + } + Bit8u *fileData = new Bit8u[size]; + if (fileData == NULL) { + return NULL; + } + ifsp.seekg(0); + ifsp.read(reinterpret_cast(fileData), std::streamsize(size)); + if (size_t(ifsp.tellg()) != size) { + delete[] fileData; + return NULL; + } + data = fileData; + close(); + return data; +} + +bool FileStream::open(const char *filename) { + ifsp.clear(); + ifsp.open(filename, ios_base::in | ios_base::binary); + return !ifsp.fail(); +} + +void FileStream::close() { + ifsp.close(); + ifsp.clear(); +} + +} // namespace MT32Emu diff --git a/src/SOUND/munt/FileStream.h b/src/SOUND/munt/FileStream.h new file mode 100644 index 000000000..ea5de6952 --- /dev/null +++ b/src/SOUND/munt/FileStream.h @@ -0,0 +1,46 @@ +/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher + * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#ifndef MT32EMU_FILE_STREAM_H +#define MT32EMU_FILE_STREAM_H + +#include + +#include "globals.h" +#include "Types.h" +#include "File.h" + +namespace MT32Emu { + +class FileStream : public AbstractFile { +public: + MT32EMU_EXPORT FileStream(); + MT32EMU_EXPORT ~FileStream(); + MT32EMU_EXPORT size_t getSize(); + MT32EMU_EXPORT const Bit8u *getData(); + MT32EMU_EXPORT bool open(const char *filename); + MT32EMU_EXPORT void close(); + +private: + std::ifstream &ifsp; + const Bit8u *data; + size_t size; +}; + +} // namespace MT32Emu + +#endif // #ifndef MT32EMU_FILE_STREAM_H diff --git a/src/SOUND/munt/LA32FloatWaveGenerator.cpp b/src/SOUND/munt/LA32FloatWaveGenerator.cpp new file mode 100644 index 000000000..5cc04fdeb --- /dev/null +++ b/src/SOUND/munt/LA32FloatWaveGenerator.cpp @@ -0,0 +1,360 @@ +/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher + * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#include + +#include "internals.h" + +#include "LA32FloatWaveGenerator.h" +#include "mmath.h" +#include "Tables.h" + +namespace MT32Emu { + +static const float MIDDLE_CUTOFF_VALUE = 128.0f; +static const float RESONANCE_DECAY_THRESHOLD_CUTOFF_VALUE = 144.0f; +static const float MAX_CUTOFF_VALUE = 240.0f; + +float LA32FloatWaveGenerator::getPCMSample(unsigned int position) { + if (position >= pcmWaveLength) { + if (!pcmWaveLooped) { + return 0; + } + position = position % pcmWaveLength; + } + Bit16s pcmSample = pcmWaveAddress[position]; + float sampleValue = EXP2F(((pcmSample & 32767) - 32787.0f) / 2048.0f); + return ((pcmSample & 32768) == 0) ? sampleValue : -sampleValue; +} + +void LA32FloatWaveGenerator::initSynth(const bool useSawtoothWaveform, const Bit8u usePulseWidth, const Bit8u useResonance) { + sawtoothWaveform = useSawtoothWaveform; + pulseWidth = usePulseWidth; + resonance = useResonance; + + wavePos = 0.0f; + lastFreq = 0.0f; + + pcmWaveAddress = NULL; + active = true; +} + +void LA32FloatWaveGenerator::initPCM(const Bit16s * const usePCMWaveAddress, const Bit32u usePCMWaveLength, const bool usePCMWaveLooped, const bool usePCMWaveInterpolated) { + pcmWaveAddress = usePCMWaveAddress; + pcmWaveLength = usePCMWaveLength; + pcmWaveLooped = usePCMWaveLooped; + pcmWaveInterpolated = usePCMWaveInterpolated; + + pcmPosition = 0.0f; + active = true; +} + +// ampVal - Logarithmic amp of the wave generator +// pitch - Logarithmic frequency of the resulting wave +// cutoffRampVal - Composed of the base cutoff in range [78..178] left-shifted by 18 bits and the TVF modifier +float LA32FloatWaveGenerator::generateNextSample(const Bit32u ampVal, const Bit16u pitch, const Bit32u cutoffRampVal) { + if (!active) { + return 0.0f; + } + + float sample = 0.0f; + + // SEMI-CONFIRMED: From sample analysis: + // (1) Tested with a single partial playing PCM wave 77 with pitchCoarse 36 and no keyfollow, velocity follow, etc. + // This gives results within +/- 2 at the output (before any DAC bitshifting) + // when sustaining at levels 156 - 255 with no modifiers. + // (2) Tested with a special square wave partial (internal capture ID tva5) at TVA envelope levels 155-255. + // This gives deltas between -1 and 0 compared to the real output. Note that this special partial only produces + // positive amps, so negative still needs to be explored, as well as lower levels. + // + // Also still partially unconfirmed is the behaviour when ramping between levels, as well as the timing. + + float amp = EXP2F(ampVal / -1024.0f / 4096.0f); + float freq = EXP2F(pitch / 4096.0f - 16.0f) * SAMPLE_RATE; + + if (isPCMWave()) { + // Render PCM waveform + int len = pcmWaveLength; + int intPCMPosition = int(pcmPosition); + if (intPCMPosition >= len && !pcmWaveLooped) { + // We're now past the end of a non-looping PCM waveform so it's time to die. + deactivate(); + return 0.0f; + } + float positionDelta = freq * 2048.0f / SAMPLE_RATE; + + // Linear interpolation + float firstSample = getPCMSample(intPCMPosition); + // We observe that for partial structures with ring modulation the interpolation is not applied to the slave PCM partial. + // It's assumed that the multiplication circuitry intended to perform the interpolation on the slave PCM partial + // is borrowed by the ring modulation circuit (or the LA32 chip has a similar lack of resources assigned to each partial pair). + if (pcmWaveInterpolated) { + sample = firstSample + (getPCMSample(intPCMPosition + 1) - firstSample) * (pcmPosition - intPCMPosition); + } else { + sample = firstSample; + } + + float newPCMPosition = pcmPosition + positionDelta; + if (pcmWaveLooped) { + newPCMPosition = fmod(newPCMPosition, float(pcmWaveLength)); + } + pcmPosition = newPCMPosition; + } else { + // Render synthesised waveform + wavePos *= lastFreq / freq; + lastFreq = freq; + + float resAmp = EXP2F(1.0f - (32 - resonance) / 4.0f); + { + //static const float resAmpFactor = EXP2F(-7); + //resAmp = EXP2I(resonance << 10) * resAmpFactor; + } + + // The cutoffModifier may not be supposed to be directly added to the cutoff - + // it may for example need to be multiplied in some way. + // The 240 cutoffVal limit was determined via sample analysis (internal Munt capture IDs: glop3, glop4). + // More research is needed to be sure that this is correct, however. + float cutoffVal = cutoffRampVal / 262144.0f; + if (cutoffVal > MAX_CUTOFF_VALUE) { + cutoffVal = MAX_CUTOFF_VALUE; + } + + // Wave length in samples + float waveLen = SAMPLE_RATE / freq; + + // Init cosineLen + float cosineLen = 0.5f * waveLen; + if (cutoffVal > MIDDLE_CUTOFF_VALUE) { + cosineLen *= EXP2F((cutoffVal - MIDDLE_CUTOFF_VALUE) / -16.0f); // found from sample analysis + } + + // Start playing in center of first cosine segment + // relWavePos is shifted by a half of cosineLen + float relWavePos = wavePos + 0.5f * cosineLen; + if (relWavePos > waveLen) { + relWavePos -= waveLen; + } + + // Ratio of positive segment to wave length + float pulseLen = 0.5f; + if (pulseWidth > 128) { + pulseLen = EXP2F((64 - pulseWidth) / 64.0f); + //static const float pulseLenFactor = EXP2F(-192 / 64); + //pulseLen = EXP2I((256 - pulseWidthVal) << 6) * pulseLenFactor; + } + pulseLen *= waveLen; + + float hLen = pulseLen - cosineLen; + + // Ignore pulsewidths too high for given freq + if (hLen < 0.0f) { + hLen = 0.0f; + } + + // Ignore pulsewidths too high for given freq and cutoff + float lLen = waveLen - hLen - 2 * cosineLen; + if (lLen < 0.0f) { + lLen = 0.0f; + } + + // Correct resAmp for cutoff in range 50..66 + if ((cutoffVal >= MIDDLE_CUTOFF_VALUE) && (cutoffVal < RESONANCE_DECAY_THRESHOLD_CUTOFF_VALUE)) { + resAmp *= sin(FLOAT_PI * (cutoffVal - MIDDLE_CUTOFF_VALUE) / 32.0f); + } + + // Produce filtered square wave with 2 cosine waves on slopes + + // 1st cosine segment + if (relWavePos < cosineLen) { + sample = -cos(FLOAT_PI * relWavePos / cosineLen); + } else + + // high linear segment + if (relWavePos < (cosineLen + hLen)) { + sample = 1.f; + } else + + // 2nd cosine segment + if (relWavePos < (2 * cosineLen + hLen)) { + sample = cos(FLOAT_PI * (relWavePos - (cosineLen + hLen)) / cosineLen); + } else { + + // low linear segment + sample = -1.f; + } + + if (cutoffVal < MIDDLE_CUTOFF_VALUE) { + + // Attenuate samples below cutoff 50 + // Found by sample analysis + sample *= EXP2F(-0.125f * (MIDDLE_CUTOFF_VALUE - cutoffVal)); + } else { + + // Add resonance sine. Effective for cutoff > 50 only + float resSample = 1.0f; + + // Resonance decay speed factor + float resAmpDecayFactor = Tables::getInstance().resAmpDecayFactor[resonance >> 2]; + + // Now relWavePos counts from the middle of first cosine + relWavePos = wavePos; + + // negative segments + if (!(relWavePos < (cosineLen + hLen))) { + resSample = -resSample; + relWavePos -= cosineLen + hLen; + + // From the digital captures, the decaying speed of the resonance sine is found a bit different for the positive and the negative segments + resAmpDecayFactor += 0.25f; + } + + // Resonance sine WG + resSample *= sin(FLOAT_PI * relWavePos / cosineLen); + + // Resonance sine amp + float resAmpFadeLog2 = -0.125f * resAmpDecayFactor * (relWavePos / cosineLen); // seems to be exact + float resAmpFade = EXP2F(resAmpFadeLog2); + + // Now relWavePos set negative to the left from center of any cosine + relWavePos = wavePos; + + // negative segment + if (!(wavePos < (waveLen - 0.5f * cosineLen))) { + relWavePos -= waveLen; + } else + + // positive segment + if (!(wavePos < (hLen + 0.5f * cosineLen))) { + relWavePos -= cosineLen + hLen; + } + + // To ensure the output wave has no breaks, two different windows are appied to the beginning and the ending of the resonance sine segment + if (relWavePos < 0.5f * cosineLen) { + float syncSine = sin(FLOAT_PI * relWavePos / cosineLen); + if (relWavePos < 0.0f) { + // The window is synchronous square sine here + resAmpFade *= syncSine * syncSine; + } else { + // The window is synchronous sine here + resAmpFade *= syncSine; + } + } + + sample += resSample * resAmp * resAmpFade; + } + + // sawtooth waves + if (sawtoothWaveform) { + sample *= cos(FLOAT_2PI * wavePos / waveLen); + } + + wavePos++; + + // wavePos isn't supposed to be > waveLen + if (wavePos > waveLen) { + wavePos -= waveLen; + } + } + + // Multiply sample with current TVA value + sample *= amp; + return sample; +} + +void LA32FloatWaveGenerator::deactivate() { + active = false; +} + +bool LA32FloatWaveGenerator::isActive() const { + return active; +} + +bool LA32FloatWaveGenerator::isPCMWave() const { + return pcmWaveAddress != NULL; +} + +void LA32FloatPartialPair::init(const bool useRingModulated, const bool useMixed) { + ringModulated = useRingModulated; + mixed = useMixed; + masterOutputSample = 0.0f; + slaveOutputSample = 0.0f; +} + +void LA32FloatPartialPair::initSynth(const PairType useMaster, const bool sawtoothWaveform, const Bit8u pulseWidth, const Bit8u resonance) { + if (useMaster == MASTER) { + master.initSynth(sawtoothWaveform, pulseWidth, resonance); + } else { + slave.initSynth(sawtoothWaveform, pulseWidth, resonance); + } +} + +void LA32FloatPartialPair::initPCM(const PairType useMaster, const Bit16s *pcmWaveAddress, const Bit32u pcmWaveLength, const bool pcmWaveLooped) { + if (useMaster == MASTER) { + master.initPCM(pcmWaveAddress, pcmWaveLength, pcmWaveLooped, true); + } else { + slave.initPCM(pcmWaveAddress, pcmWaveLength, pcmWaveLooped, !ringModulated); + } +} + +void LA32FloatPartialPair::generateNextSample(const PairType useMaster, const Bit32u amp, const Bit16u pitch, const Bit32u cutoff) { + if (useMaster == MASTER) { + masterOutputSample = master.generateNextSample(amp, pitch, cutoff); + } else { + slaveOutputSample = slave.generateNextSample(amp, pitch, cutoff); + } +} + +static inline float produceDistortedSample(float sample) { + if (sample < -1.0f) { + return sample + 2.0f; + } else if (1.0f < sample) { + return sample - 2.0f; + } + return sample; +} + +float LA32FloatPartialPair::nextOutSample() { + if (!ringModulated) { + return masterOutputSample + slaveOutputSample; + } + /* + * SEMI-CONFIRMED: Ring modulation model derived from sample analysis of specially constructed patches which exploit distortion. + * LA32 ring modulator found to produce distorted output in case if the absolute value of maximal amplitude of one of the input partials exceeds 8191. + * This is easy to reproduce using synth partials with resonance values close to the maximum. It looks like an integer overflow happens in this case. + * As the distortion is strictly bound to the amplitude of the complete mixed square + resonance wave in the linear space, + * it is reasonable to assume the ring modulation is performed also in the linear space by sample multiplication. + * Most probably the overflow is caused by limited precision of the multiplication circuit as the very similar distortion occurs with panning. + */ + float ringModulatedSample = produceDistortedSample(masterOutputSample) * produceDistortedSample(slaveOutputSample); + return mixed ? masterOutputSample + ringModulatedSample : ringModulatedSample; +} + +void LA32FloatPartialPair::deactivate(const PairType useMaster) { + if (useMaster == MASTER) { + master.deactivate(); + masterOutputSample = 0.0f; + } else { + slave.deactivate(); + slaveOutputSample = 0.0f; + } +} + +bool LA32FloatPartialPair::isActive(const PairType useMaster) const { + return useMaster == MASTER ? master.isActive() : slave.isActive(); +} + +} // namespace MT32Emu diff --git a/src/SOUND/munt/LA32FloatWaveGenerator.h b/src/SOUND/munt/LA32FloatWaveGenerator.h new file mode 100644 index 000000000..7e92d0a67 --- /dev/null +++ b/src/SOUND/munt/LA32FloatWaveGenerator.h @@ -0,0 +1,132 @@ +/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher + * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#ifndef MT32EMU_LA32_FLOAT_WAVE_GENERATOR_H +#define MT32EMU_LA32_FLOAT_WAVE_GENERATOR_H + +#include "globals.h" +#include "internals.h" +#include "Types.h" +#include "LA32WaveGenerator.h" + +namespace MT32Emu { + +/** + * LA32WaveGenerator is aimed to represent the exact model of LA32 wave generator. + * The output square wave is created by adding high / low linear segments in-between + * the rising and falling cosine segments. Basically, it's very similar to the phase distortion synthesis. + * Behaviour of a true resonance filter is emulated by adding decaying sine wave. + * The beginning and the ending of the resonant sine is multiplied by a cosine window. + * To synthesise sawtooth waves, the resulting square wave is multiplied by synchronous cosine wave. + */ +class LA32FloatWaveGenerator { + //*************************************************************************** + // The local copy of partial parameters below + //*************************************************************************** + + bool active; + + // True means the resulting square wave is to be multiplied by the synchronous cosine + bool sawtoothWaveform; + + // Values in range [1..31] + // Value 1 correspong to the minimum resonance + Bit8u resonance; + + // Processed value in range [0..255] + // Values in range [0..128] have no effect and the resulting wave remains symmetrical + // Value 255 corresponds to the maximum possible asymmetric of the resulting wave + Bit8u pulseWidth; + + // Logarithmic PCM sample start address + const Bit16s *pcmWaveAddress; + + // Logarithmic PCM sample length + Bit32u pcmWaveLength; + + // true for looped logarithmic PCM samples + bool pcmWaveLooped; + + // false for slave PCM partials in the structures with the ring modulation + bool pcmWaveInterpolated; + + //*************************************************************************** + // Internal variables below + //*************************************************************************** + + float wavePos; + float lastFreq; + float pcmPosition; + + float getPCMSample(unsigned int position); + +public: + // Initialise the WG engine for generation of synth partial samples and set up the invariant parameters + void initSynth(const bool sawtoothWaveform, const Bit8u pulseWidth, const Bit8u resonance); + + // Initialise the WG engine for generation of PCM partial samples and set up the invariant parameters + void initPCM(const Bit16s * const pcmWaveAddress, const Bit32u pcmWaveLength, const bool pcmWaveLooped, const bool pcmWaveInterpolated); + + // Update parameters with respect to TVP, TVA and TVF, and generate next sample + float generateNextSample(const Bit32u amp, const Bit16u pitch, const Bit32u cutoff); + + // Deactivate the WG engine + void deactivate(); + + // Return active state of the WG engine + bool isActive() const; + + // Return true if the WG engine generates PCM wave samples + bool isPCMWave() const; +}; // class LA32FloatWaveGenerator + +class LA32FloatPartialPair : public LA32PartialPair { + LA32FloatWaveGenerator master; + LA32FloatWaveGenerator slave; + bool ringModulated; + bool mixed; + float masterOutputSample; + float slaveOutputSample; + +public: + // ringModulated should be set to false for the structures with mixing or stereo output + // ringModulated should be set to true for the structures with ring modulation + // mixed is used for the structures with ring modulation and indicates whether the master partial output is mixed to the ring modulator output + void init(const bool ringModulated, const bool mixed); + + // Initialise the WG engine for generation of synth partial samples and set up the invariant parameters + void initSynth(const PairType master, const bool sawtoothWaveform, const Bit8u pulseWidth, const Bit8u resonance); + + // Initialise the WG engine for generation of PCM partial samples and set up the invariant parameters + void initPCM(const PairType master, const Bit16s * const pcmWaveAddress, const Bit32u pcmWaveLength, const bool pcmWaveLooped); + + // Update parameters with respect to TVP, TVA and TVF, and generate next sample + void generateNextSample(const PairType master, const Bit32u amp, const Bit16u pitch, const Bit32u cutoff); + + // Perform mixing / ring modulation and return the result + float nextOutSample(); + + // Deactivate the WG engine + void deactivate(const PairType master); + + // Return active state of the WG engine + bool isActive(const PairType master) const; +}; // class LA32FloatPartialPair + +} // namespace MT32Emu + +#endif // #ifndef MT32EMU_LA32_FLOAT_WAVE_GENERATOR_H diff --git a/src/SOUND/munt/LA32Ramp.cpp b/src/SOUND/munt/LA32Ramp.cpp new file mode 100644 index 000000000..fda38d440 --- /dev/null +++ b/src/SOUND/munt/LA32Ramp.cpp @@ -0,0 +1,155 @@ +/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher + * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +/* +Some notes on this class: + +This emulates the LA-32's implementation of "ramps". A ramp in this context is a smooth transition from one value to another, handled entirely within the LA-32. +The LA-32 provides this feature for amplitude and filter cutoff values. + +The 8095 starts ramps on the LA-32 by setting two values in memory-mapped registers: + +(1) The target value (between 0 and 255) for the ramp to end on. This is represented by the "target" argument to startRamp(). +(2) The speed at which that value should be approached. This is represented by the "increment" argument to startRamp(). + +Once the ramp target value has been hit, the LA-32 raises an interrupt. + +Note that the starting point of the ramp is whatever internal value the LA-32 had when the registers were set. This is usually the end point of a previously completed ramp. + +Our handling of the "target" and "increment" values is based on sample analysis and a little guesswork. +Here's what we're pretty confident about: + - The most significant bit of "increment" indicates the direction that the LA32's current internal value ("current" in our emulation) should change in. + Set means downward, clear means upward. + - The lower 7 bits of "increment" indicate how quickly "current" should be changed. + - If "increment" is 0, no change to "current" is made and no interrupt is raised. [SEMI-CONFIRMED by sample analysis] + - Otherwise, if the MSb is set: + - If "current" already corresponds to a value <= "target", "current" is set immediately to the equivalent of "target" and an interrupt is raised. + - Otherwise, "current" is gradually reduced (at a rate determined by the lower 7 bits of "increment"), and once it reaches the equivalent of "target" an interrupt is raised. + - Otherwise (the MSb is unset): + - If "current" already corresponds to a value >= "target", "current" is set immediately to the equivalent of "target" and an interrupt is raised. + - Otherwise, "current" is gradually increased (at a rate determined by the lower 7 bits of "increment"), and once it reaches the equivalent of "target" an interrupt is raised. + +We haven't fully explored: + - Values when ramping between levels (though this is probably correct). + - Transition timing (may not be 100% accurate, especially for very fast ramps). +*/ + +#include "internals.h" + +#include "LA32Ramp.h" +#include "Tables.h" + +namespace MT32Emu { + +// SEMI-CONFIRMED from sample analysis. +const int TARGET_MULT = 0x40000; +const unsigned int MAX_CURRENT = 0xFF * TARGET_MULT; + +// We simulate the delay in handling "target was reached" interrupts by waiting +// this many samples before setting interruptRaised. +// FIXME: This should vary with the sample rate, but doesn't. +// SEMI-CONFIRMED: Since this involves asynchronous activity between the LA32 +// and the 8095, a good value is hard to pin down. +// This one matches observed behaviour on a few digital captures I had handy, +// and should be double-checked. We may also need a more sophisticated delay +// scheme eventually. +const int INTERRUPT_TIME = 7; + +LA32Ramp::LA32Ramp() : + current(0), + largeTarget(0), + largeIncrement(0), + interruptCountdown(0), + interruptRaised(false) { +} + +void LA32Ramp::startRamp(Bit8u target, Bit8u increment) { + // CONFIRMED: From sample analysis, this appears to be very accurate. + if (increment == 0) { + largeIncrement = 0; + } else { + // Three bits in the fractional part, no need to interpolate + // (unsigned int)(EXP2F(((increment & 0x7F) + 24) / 8.0f) + 0.125f) + Bit32u expArg = increment & 0x7F; + largeIncrement = 8191 - Tables::getInstance().exp9[~(expArg << 6) & 511]; + largeIncrement <<= expArg >> 3; + largeIncrement += 64; + largeIncrement >>= 9; + } + descending = (increment & 0x80) != 0; + if (descending) { + // CONFIRMED: From sample analysis, descending increments are slightly faster + largeIncrement++; + } + + largeTarget = target * TARGET_MULT; + interruptCountdown = 0; + interruptRaised = false; +} + +Bit32u LA32Ramp::nextValue() { + if (interruptCountdown > 0) { + if (--interruptCountdown == 0) { + interruptRaised = true; + } + } else if (largeIncrement != 0) { + // CONFIRMED from sample analysis: When increment is 0, the LA32 does *not* change the current value at all (and of course doesn't fire an interrupt). + if (descending) { + // Lowering current value + if (largeIncrement > current) { + current = largeTarget; + interruptCountdown = INTERRUPT_TIME; + } else { + current -= largeIncrement; + if (current <= largeTarget) { + current = largeTarget; + interruptCountdown = INTERRUPT_TIME; + } + } + } else { + // Raising current value + if (MAX_CURRENT - current < largeIncrement) { + current = largeTarget; + interruptCountdown = INTERRUPT_TIME; + } else { + current += largeIncrement; + if (current >= largeTarget) { + current = largeTarget; + interruptCountdown = INTERRUPT_TIME; + } + } + } + } + return current; +} + +bool LA32Ramp::checkInterrupt() { + bool wasRaised = interruptRaised; + interruptRaised = false; + return wasRaised; +} + +void LA32Ramp::reset() { + current = 0; + largeTarget = 0; + largeIncrement = 0; + descending = false; + interruptCountdown = 0; + interruptRaised = false; +} + +} // namespace MT32Emu diff --git a/src/SOUND/munt/LA32Ramp.h b/src/SOUND/munt/LA32Ramp.h new file mode 100644 index 000000000..25e70c22a --- /dev/null +++ b/src/SOUND/munt/LA32Ramp.h @@ -0,0 +1,46 @@ +/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher + * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#ifndef MT32EMU_LA32RAMP_H +#define MT32EMU_LA32RAMP_H + +#include "globals.h" +#include "Types.h" + +namespace MT32Emu { + +class LA32Ramp { +private: + Bit32u current; + unsigned int largeTarget; + unsigned int largeIncrement; + bool descending; + + int interruptCountdown; + bool interruptRaised; + +public: + LA32Ramp(); + void startRamp(Bit8u target, Bit8u increment); + Bit32u nextValue(); + bool checkInterrupt(); + void reset(); +}; + +} // namespace MT32Emu + +#endif // #ifndef MT32EMU_LA32RAMP_H diff --git a/src/SOUND/munt/LA32WaveGenerator.cpp b/src/SOUND/munt/LA32WaveGenerator.cpp new file mode 100644 index 000000000..9bdf40610 --- /dev/null +++ b/src/SOUND/munt/LA32WaveGenerator.cpp @@ -0,0 +1,422 @@ +/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher + * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#include + +#include "internals.h" + +#include "LA32WaveGenerator.h" +#include "Tables.h" + +namespace MT32Emu { + +static const Bit32u SINE_SEGMENT_RELATIVE_LENGTH = 1 << 18; +static const Bit32u MIDDLE_CUTOFF_VALUE = 128 << 18; +static const Bit32u RESONANCE_DECAY_THRESHOLD_CUTOFF_VALUE = 144 << 18; +static const Bit32u MAX_CUTOFF_VALUE = 240 << 18; +static const LogSample SILENCE = {65535, LogSample::POSITIVE}; + +Bit16u LA32Utilites::interpolateExp(const Bit16u fract) { + Bit16u expTabIndex = fract >> 3; + Bit16u extraBits = ~fract & 7; + Bit16u expTabEntry2 = 8191 - Tables::getInstance().exp9[expTabIndex]; + Bit16u expTabEntry1 = expTabIndex == 0 ? 8191 : (8191 - Tables::getInstance().exp9[expTabIndex - 1]); + return expTabEntry2 + (((expTabEntry1 - expTabEntry2) * extraBits) >> 3); +} + +Bit16s LA32Utilites::unlog(const LogSample &logSample) { + //Bit16s sample = (Bit16s)EXP2F(13.0f - logSample.logValue / 1024.0f); + Bit32u intLogValue = logSample.logValue >> 12; + Bit16u fracLogValue = logSample.logValue & 4095; + Bit16s sample = interpolateExp(fracLogValue) >> intLogValue; + return logSample.sign == LogSample::POSITIVE ? sample : -sample; +} + +void LA32Utilites::addLogSamples(LogSample &logSample1, const LogSample &logSample2) { + Bit32u logSampleValue = logSample1.logValue + logSample2.logValue; + logSample1.logValue = logSampleValue < 65536 ? Bit16u(logSampleValue) : 65535; + logSample1.sign = logSample1.sign == logSample2.sign ? LogSample::POSITIVE : LogSample::NEGATIVE; +} + +Bit32u LA32WaveGenerator::getSampleStep() { + // sampleStep = EXP2F(pitch / 4096.0f + 4.0f) + Bit32u sampleStep = LA32Utilites::interpolateExp(~pitch & 4095); + sampleStep <<= pitch >> 12; + sampleStep >>= 8; + sampleStep &= ~1; + return sampleStep; +} + +Bit32u LA32WaveGenerator::getResonanceWaveLengthFactor(Bit32u effectiveCutoffValue) { + // resonanceWaveLengthFactor = (Bit32u)EXP2F(12.0f + effectiveCutoffValue / 4096.0f); + Bit32u resonanceWaveLengthFactor = LA32Utilites::interpolateExp(~effectiveCutoffValue & 4095); + resonanceWaveLengthFactor <<= effectiveCutoffValue >> 12; + return resonanceWaveLengthFactor; +} + +Bit32u LA32WaveGenerator::getHighLinearLength(Bit32u effectiveCutoffValue) { + // Ratio of positive segment to wave length + Bit32u effectivePulseWidthValue = 0; + if (pulseWidth > 128) { + effectivePulseWidthValue = (pulseWidth - 128) << 6; + } + + Bit32u highLinearLength = 0; + // highLinearLength = EXP2F(19.0f - effectivePulseWidthValue / 4096.0f + effectiveCutoffValue / 4096.0f) - 2 * SINE_SEGMENT_RELATIVE_LENGTH; + if (effectivePulseWidthValue < effectiveCutoffValue) { + Bit32u expArg = effectiveCutoffValue - effectivePulseWidthValue; + highLinearLength = LA32Utilites::interpolateExp(~expArg & 4095); + highLinearLength <<= 7 + (expArg >> 12); + highLinearLength -= 2 * SINE_SEGMENT_RELATIVE_LENGTH; + } + return highLinearLength; +} + +void LA32WaveGenerator::computePositions(Bit32u highLinearLength, Bit32u lowLinearLength, Bit32u resonanceWaveLengthFactor) { + // Assuming 12-bit multiplication used here + squareWavePosition = resonanceSinePosition = (wavePosition >> 8) * (resonanceWaveLengthFactor >> 4); + if (squareWavePosition < SINE_SEGMENT_RELATIVE_LENGTH) { + phase = POSITIVE_RISING_SINE_SEGMENT; + return; + } + squareWavePosition -= SINE_SEGMENT_RELATIVE_LENGTH; + if (squareWavePosition < highLinearLength) { + phase = POSITIVE_LINEAR_SEGMENT; + return; + } + squareWavePosition -= highLinearLength; + if (squareWavePosition < SINE_SEGMENT_RELATIVE_LENGTH) { + phase = POSITIVE_FALLING_SINE_SEGMENT; + return; + } + squareWavePosition -= SINE_SEGMENT_RELATIVE_LENGTH; + resonanceSinePosition = squareWavePosition; + if (squareWavePosition < SINE_SEGMENT_RELATIVE_LENGTH) { + phase = NEGATIVE_FALLING_SINE_SEGMENT; + return; + } + squareWavePosition -= SINE_SEGMENT_RELATIVE_LENGTH; + if (squareWavePosition < lowLinearLength) { + phase = NEGATIVE_LINEAR_SEGMENT; + return; + } + squareWavePosition -= lowLinearLength; + phase = NEGATIVE_RISING_SINE_SEGMENT; +} + +void LA32WaveGenerator::advancePosition() { + wavePosition += getSampleStep(); + wavePosition %= 4 * SINE_SEGMENT_RELATIVE_LENGTH; + + Bit32u effectiveCutoffValue = (cutoffVal > MIDDLE_CUTOFF_VALUE) ? (cutoffVal - MIDDLE_CUTOFF_VALUE) >> 10 : 0; + Bit32u resonanceWaveLengthFactor = getResonanceWaveLengthFactor(effectiveCutoffValue); + Bit32u highLinearLength = getHighLinearLength(effectiveCutoffValue); + Bit32u lowLinearLength = (resonanceWaveLengthFactor << 8) - 4 * SINE_SEGMENT_RELATIVE_LENGTH - highLinearLength; + computePositions(highLinearLength, lowLinearLength, resonanceWaveLengthFactor); + + resonancePhase = ResonancePhase(((resonanceSinePosition >> 18) + (phase > POSITIVE_FALLING_SINE_SEGMENT ? 2 : 0)) & 3); +} + +void LA32WaveGenerator::generateNextSquareWaveLogSample() { + Bit32u logSampleValue; + switch (phase) { + case POSITIVE_RISING_SINE_SEGMENT: + case NEGATIVE_FALLING_SINE_SEGMENT: + logSampleValue = Tables::getInstance().logsin9[(squareWavePosition >> 9) & 511]; + break; + case POSITIVE_FALLING_SINE_SEGMENT: + case NEGATIVE_RISING_SINE_SEGMENT: + logSampleValue = Tables::getInstance().logsin9[~(squareWavePosition >> 9) & 511]; + break; + case POSITIVE_LINEAR_SEGMENT: + case NEGATIVE_LINEAR_SEGMENT: + default: + logSampleValue = 0; + break; + } + logSampleValue <<= 2; + logSampleValue += amp >> 10; + if (cutoffVal < MIDDLE_CUTOFF_VALUE) { + logSampleValue += (MIDDLE_CUTOFF_VALUE - cutoffVal) >> 9; + } + + squareLogSample.logValue = logSampleValue < 65536 ? Bit16u(logSampleValue) : 65535; + squareLogSample.sign = phase < NEGATIVE_FALLING_SINE_SEGMENT ? LogSample::POSITIVE : LogSample::NEGATIVE; +} + +void LA32WaveGenerator::generateNextResonanceWaveLogSample() { + Bit32u logSampleValue; + if (resonancePhase == POSITIVE_FALLING_RESONANCE_SINE_SEGMENT || resonancePhase == NEGATIVE_RISING_RESONANCE_SINE_SEGMENT) { + logSampleValue = Tables::getInstance().logsin9[~(resonanceSinePosition >> 9) & 511]; + } else { + logSampleValue = Tables::getInstance().logsin9[(resonanceSinePosition >> 9) & 511]; + } + logSampleValue <<= 2; + logSampleValue += amp >> 10; + + // From the digital captures, the decaying speed of the resonance sine is found a bit different for the positive and the negative segments + Bit32u decayFactor = phase < NEGATIVE_FALLING_SINE_SEGMENT ? resAmpDecayFactor : resAmpDecayFactor + 1; + // Unsure about resonanceSinePosition here. It's possible that dedicated counter & decrement are used. Although, cutoff is finely ramped, so maybe not. + logSampleValue += resonanceAmpSubtraction + (((resonanceSinePosition >> 4) * decayFactor) >> 8); + + // To ensure the output wave has no breaks, two different windows are appied to the beginning and the ending of the resonance sine segment + if (phase == POSITIVE_RISING_SINE_SEGMENT || phase == NEGATIVE_FALLING_SINE_SEGMENT) { + // The window is synchronous sine here + logSampleValue += Tables::getInstance().logsin9[(squareWavePosition >> 9) & 511] << 2; + } else if (phase == POSITIVE_FALLING_SINE_SEGMENT || phase == NEGATIVE_RISING_SINE_SEGMENT) { + // The window is synchronous square sine here + logSampleValue += Tables::getInstance().logsin9[~(squareWavePosition >> 9) & 511] << 3; + } + + if (cutoffVal < MIDDLE_CUTOFF_VALUE) { + // For the cutoff values below the cutoff middle point, it seems the amp of the resonance wave is expotentially decayed + logSampleValue += 31743 + ((MIDDLE_CUTOFF_VALUE - cutoffVal) >> 9); + } else if (cutoffVal < RESONANCE_DECAY_THRESHOLD_CUTOFF_VALUE) { + // For the cutoff values below this point, the amp of the resonance wave is sinusoidally decayed + Bit32u sineIx = (cutoffVal - MIDDLE_CUTOFF_VALUE) >> 13; + logSampleValue += Tables::getInstance().logsin9[sineIx] << 2; + } + + // After all the amp decrements are added, it should be safe now to adjust the amp of the resonance wave to what we see on captures + logSampleValue -= 1 << 12; + + resonanceLogSample.logValue = logSampleValue < 65536 ? Bit16u(logSampleValue) : 65535; + resonanceLogSample.sign = resonancePhase < NEGATIVE_FALLING_RESONANCE_SINE_SEGMENT ? LogSample::POSITIVE : LogSample::NEGATIVE; +} + +void LA32WaveGenerator::generateNextSawtoothCosineLogSample(LogSample &logSample) const { + Bit32u sawtoothCosinePosition = wavePosition + (1 << 18); + if ((sawtoothCosinePosition & (1 << 18)) > 0) { + logSample.logValue = Tables::getInstance().logsin9[~(sawtoothCosinePosition >> 9) & 511]; + } else { + logSample.logValue = Tables::getInstance().logsin9[(sawtoothCosinePosition >> 9) & 511]; + } + logSample.logValue <<= 2; + logSample.sign = ((sawtoothCosinePosition & (1 << 19)) == 0) ? LogSample::POSITIVE : LogSample::NEGATIVE; +} + +void LA32WaveGenerator::pcmSampleToLogSample(LogSample &logSample, const Bit16s pcmSample) const { + Bit32u logSampleValue = (32787 - (pcmSample & 32767)) << 1; + logSampleValue += amp >> 10; + logSample.logValue = logSampleValue < 65536 ? Bit16u(logSampleValue) : 65535; + logSample.sign = pcmSample < 0 ? LogSample::NEGATIVE : LogSample::POSITIVE; +} + +void LA32WaveGenerator::generateNextPCMWaveLogSamples() { + // This should emulate the ladder we see in the PCM captures for pitches 01, 02, 07, etc. + // The most probable cause is the factor in the interpolation formula is one bit less + // accurate than the sample position counter + pcmInterpolationFactor = (wavePosition & 255) >> 1; + Bit32u pcmWaveTableIx = wavePosition >> 8; + pcmSampleToLogSample(firstPCMLogSample, pcmWaveAddress[pcmWaveTableIx]); + if (pcmWaveInterpolated) { + pcmWaveTableIx++; + if (pcmWaveTableIx < pcmWaveLength) { + pcmSampleToLogSample(secondPCMLogSample, pcmWaveAddress[pcmWaveTableIx]); + } else { + if (pcmWaveLooped) { + pcmWaveTableIx -= pcmWaveLength; + pcmSampleToLogSample(secondPCMLogSample, pcmWaveAddress[pcmWaveTableIx]); + } else { + secondPCMLogSample = SILENCE; + } + } + } else { + secondPCMLogSample = SILENCE; + } + // pcmSampleStep = (Bit32u)EXP2F(pitch / 4096.0f + 3.0f); + Bit32u pcmSampleStep = LA32Utilites::interpolateExp(~pitch & 4095); + pcmSampleStep <<= pitch >> 12; + // Seeing the actual lengths of the PCM wave for pitches 00..12, + // the pcmPosition counter can be assumed to have 8-bit fractions + pcmSampleStep >>= 9; + wavePosition += pcmSampleStep; + if (wavePosition >= (pcmWaveLength << 8)) { + if (pcmWaveLooped) { + wavePosition -= pcmWaveLength << 8; + } else { + deactivate(); + } + } +} + +void LA32WaveGenerator::initSynth(const bool useSawtoothWaveform, const Bit8u usePulseWidth, const Bit8u useResonance) { + sawtoothWaveform = useSawtoothWaveform; + pulseWidth = usePulseWidth; + resonance = useResonance; + + wavePosition = 0; + + squareWavePosition = 0; + phase = POSITIVE_RISING_SINE_SEGMENT; + + resonanceSinePosition = 0; + resonancePhase = POSITIVE_RISING_RESONANCE_SINE_SEGMENT; + resonanceAmpSubtraction = (32 - resonance) << 10; + resAmpDecayFactor = Tables::getInstance().resAmpDecayFactor[resonance >> 2] << 2; + + pcmWaveAddress = NULL; + active = true; +} + +void LA32WaveGenerator::initPCM(const Bit16s * const usePCMWaveAddress, const Bit32u usePCMWaveLength, const bool usePCMWaveLooped, const bool usePCMWaveInterpolated) { + pcmWaveAddress = usePCMWaveAddress; + pcmWaveLength = usePCMWaveLength; + pcmWaveLooped = usePCMWaveLooped; + pcmWaveInterpolated = usePCMWaveInterpolated; + + wavePosition = 0; + active = true; +} + +void LA32WaveGenerator::generateNextSample(const Bit32u useAmp, const Bit16u usePitch, const Bit32u useCutoffVal) { + if (!active) { + return; + } + + amp = useAmp; + pitch = usePitch; + + if (isPCMWave()) { + generateNextPCMWaveLogSamples(); + return; + } + + // The 240 cutoffVal limit was determined via sample analysis (internal Munt capture IDs: glop3, glop4). + // More research is needed to be sure that this is correct, however. + cutoffVal = (useCutoffVal > MAX_CUTOFF_VALUE) ? MAX_CUTOFF_VALUE : useCutoffVal; + + generateNextSquareWaveLogSample(); + generateNextResonanceWaveLogSample(); + if (sawtoothWaveform) { + LogSample cosineLogSample; + generateNextSawtoothCosineLogSample(cosineLogSample); + LA32Utilites::addLogSamples(squareLogSample, cosineLogSample); + LA32Utilites::addLogSamples(resonanceLogSample, cosineLogSample); + } + advancePosition(); +} + +LogSample LA32WaveGenerator::getOutputLogSample(const bool first) const { + if (!isActive()) { + return SILENCE; + } + if (isPCMWave()) { + return first ? firstPCMLogSample : secondPCMLogSample; + } + return first ? squareLogSample : resonanceLogSample; +} + +void LA32WaveGenerator::deactivate() { + active = false; +} + +bool LA32WaveGenerator::isActive() const { + return active; +} + +bool LA32WaveGenerator::isPCMWave() const { + return pcmWaveAddress != NULL; +} + +Bit32u LA32WaveGenerator::getPCMInterpolationFactor() const { + return pcmInterpolationFactor; +} + +void LA32IntPartialPair::init(const bool useRingModulated, const bool useMixed) { + ringModulated = useRingModulated; + mixed = useMixed; +} + +void LA32IntPartialPair::initSynth(const PairType useMaster, const bool sawtoothWaveform, const Bit8u pulseWidth, const Bit8u resonance) { + if (useMaster == MASTER) { + master.initSynth(sawtoothWaveform, pulseWidth, resonance); + } else { + slave.initSynth(sawtoothWaveform, pulseWidth, resonance); + } +} + +void LA32IntPartialPair::initPCM(const PairType useMaster, const Bit16s *pcmWaveAddress, const Bit32u pcmWaveLength, const bool pcmWaveLooped) { + if (useMaster == MASTER) { + master.initPCM(pcmWaveAddress, pcmWaveLength, pcmWaveLooped, true); + } else { + slave.initPCM(pcmWaveAddress, pcmWaveLength, pcmWaveLooped, !ringModulated); + } +} + +void LA32IntPartialPair::generateNextSample(const PairType useMaster, const Bit32u amp, const Bit16u pitch, const Bit32u cutoff) { + if (useMaster == MASTER) { + master.generateNextSample(amp, pitch, cutoff); + } else { + slave.generateNextSample(amp, pitch, cutoff); + } +} + +Bit16s LA32IntPartialPair::unlogAndMixWGOutput(const LA32WaveGenerator &wg) { + if (!wg.isActive()) { + return 0; + } + Bit16s firstSample = LA32Utilites::unlog(wg.getOutputLogSample(true)); + Bit16s secondSample = LA32Utilites::unlog(wg.getOutputLogSample(false)); + if (wg.isPCMWave()) { + return Bit16s(firstSample + (((Bit32s(secondSample) - Bit32s(firstSample)) * wg.getPCMInterpolationFactor()) >> 7)); + } + return firstSample + secondSample; +} + +Bit16s LA32IntPartialPair::nextOutSample() { + if (!ringModulated) { + return unlogAndMixWGOutput(master) + unlogAndMixWGOutput(slave); + } + + /* + * SEMI-CONFIRMED: Ring modulation model derived from sample analysis of specially constructed patches which exploit distortion. + * LA32 ring modulator found to produce distorted output in case if the absolute value of maximal amplitude of one of the input partials exceeds 8191. + * This is easy to reproduce using synth partials with resonance values close to the maximum. It looks like an integer overflow happens in this case. + * As the distortion is strictly bound to the amplitude of the complete mixed square + resonance wave in the linear space, + * it is reasonable to assume the ring modulation is performed also in the linear space by sample multiplication. + * Most probably the overflow is caused by limited precision of the multiplication circuit as the very similar distortion occurs with panning. + */ + Bit16s nonOverdrivenMasterSample = unlogAndMixWGOutput(master); // Store master partial sample for further mixing + Bit16s masterSample = nonOverdrivenMasterSample << 2; + masterSample >>= 2; + + /* SEMI-CONFIRMED from sample analysis: + * We observe that for partial structures with ring modulation the interpolation is not applied to the slave PCM partial. + * It's assumed that the multiplication circuitry intended to perform the interpolation on the slave PCM partial + * is borrowed by the ring modulation circuit (or the LA32 chip has a similar lack of resources assigned to each partial pair). + */ + Bit16s slaveSample = slave.isPCMWave() ? LA32Utilites::unlog(slave.getOutputLogSample(true)) : unlogAndMixWGOutput(slave); + slaveSample <<= 2; + slaveSample >>= 2; + Bit16s ringModulatedSample = Bit16s((Bit32s(masterSample) * Bit32s(slaveSample)) >> 13); + return mixed ? nonOverdrivenMasterSample + ringModulatedSample : ringModulatedSample; +} + +void LA32IntPartialPair::deactivate(const PairType useMaster) { + if (useMaster == MASTER) { + master.deactivate(); + } else { + slave.deactivate(); + } +} + +bool LA32IntPartialPair::isActive(const PairType useMaster) const { + return useMaster == MASTER ? master.isActive() : slave.isActive(); +} + +} // namespace MT32Emu diff --git a/src/SOUND/munt/LA32WaveGenerator.h b/src/SOUND/munt/LA32WaveGenerator.h new file mode 100644 index 000000000..c206daa63 --- /dev/null +++ b/src/SOUND/munt/LA32WaveGenerator.h @@ -0,0 +1,266 @@ +/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher + * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#ifndef MT32EMU_LA32_WAVE_GENERATOR_H +#define MT32EMU_LA32_WAVE_GENERATOR_H + +#include "globals.h" +#include "internals.h" +#include "Types.h" + +namespace MT32Emu { + +/** + * LA32 performs wave generation in the log-space that allows replacing multiplications by cheap additions + * It's assumed that only low-bit multiplications occur in a few places which are unavoidable like these: + * - interpolation of exponent table (obvious, a delta value has 4 bits) + * - computation of resonance amp decay envelope (the table contains values with 1-2 "1" bits except the very first value 31 but this case can be found using inversion) + * - interpolation of PCM samples (obvious, the wave position counter is in the linear space, there is no log() table in the chip) + * and it seems to be implemented in the same way as in the Boss chip, i.e. right shifted additions which involved noticeable precision loss + * Subtraction is supposed to be replaced by simple inversion + * As the logarithmic sine is always negative, all the logarithmic values are treated as decrements + */ +struct LogSample { + // 16-bit fixed point value, includes 12-bit fractional part + // 4-bit integer part allows to present any 16-bit sample in the log-space + // Obviously, the log value doesn't contain the sign of the resulting sample + Bit16u logValue; + enum { + POSITIVE, + NEGATIVE + } sign; +}; + +class LA32Utilites { +public: + static Bit16u interpolateExp(const Bit16u fract); + static Bit16s unlog(const LogSample &logSample); + static void addLogSamples(LogSample &logSample1, const LogSample &logSample2); +}; + +/** + * LA32WaveGenerator is aimed to represent the exact model of LA32 wave generator. + * The output square wave is created by adding high / low linear segments in-between + * the rising and falling cosine segments. Basically, it's very similar to the phase distortion synthesis. + * Behaviour of a true resonance filter is emulated by adding decaying sine wave. + * The beginning and the ending of the resonant sine is multiplied by a cosine window. + * To synthesise sawtooth waves, the resulting square wave is multiplied by synchronous cosine wave. + */ +class LA32WaveGenerator { + //*************************************************************************** + // The local copy of partial parameters below + //*************************************************************************** + + bool active; + + // True means the resulting square wave is to be multiplied by the synchronous cosine + bool sawtoothWaveform; + + // Logarithmic amp of the wave generator + Bit32u amp; + + // Logarithmic frequency of the resulting wave + Bit16u pitch; + + // Values in range [1..31] + // Value 1 correspong to the minimum resonance + Bit8u resonance; + + // Processed value in range [0..255] + // Values in range [0..128] have no effect and the resulting wave remains symmetrical + // Value 255 corresponds to the maximum possible asymmetric of the resulting wave + Bit8u pulseWidth; + + // Composed of the base cutoff in range [78..178] left-shifted by 18 bits and the TVF modifier + Bit32u cutoffVal; + + // Logarithmic PCM sample start address + const Bit16s *pcmWaveAddress; + + // Logarithmic PCM sample length + Bit32u pcmWaveLength; + + // true for looped logarithmic PCM samples + bool pcmWaveLooped; + + // false for slave PCM partials in the structures with the ring modulation + bool pcmWaveInterpolated; + + //*************************************************************************** + // Internal variables below + //*************************************************************************** + + // Relative position within either the synth wave or the PCM sampled wave + // 0 - start of the positive rising sine segment of the square wave or start of the PCM sample + // 1048576 (2^20) - end of the negative rising sine segment of the square wave + // For PCM waves, the address of the currently playing sample equals (wavePosition / 256) + Bit32u wavePosition; + + // Relative position within a square wave phase: + // 0 - start of the phase + // 262144 (2^18) - end of a sine phase in the square wave + Bit32u squareWavePosition; + + // Relative position within the positive or negative wave segment: + // 0 - start of the corresponding positive or negative segment of the square wave + // 262144 (2^18) - corresponds to end of the first sine phase in the square wave + // The same increment sampleStep is used to indicate the current position + // since the length of the resonance wave is always equal to four square wave sine segments. + Bit32u resonanceSinePosition; + + // The amp of the resonance sine wave grows with the resonance value + // As the resonance value cannot change while the partial is active, it is initialised once + Bit32u resonanceAmpSubtraction; + + // The decay speed of resonance sine wave, depends on the resonance value + Bit32u resAmpDecayFactor; + + // Fractional part of the pcmPosition + Bit32u pcmInterpolationFactor; + + // Current phase of the square wave + enum { + POSITIVE_RISING_SINE_SEGMENT, + POSITIVE_LINEAR_SEGMENT, + POSITIVE_FALLING_SINE_SEGMENT, + NEGATIVE_FALLING_SINE_SEGMENT, + NEGATIVE_LINEAR_SEGMENT, + NEGATIVE_RISING_SINE_SEGMENT + } phase; + + // Current phase of the resonance wave + enum ResonancePhase { + POSITIVE_RISING_RESONANCE_SINE_SEGMENT, + POSITIVE_FALLING_RESONANCE_SINE_SEGMENT, + NEGATIVE_FALLING_RESONANCE_SINE_SEGMENT, + NEGATIVE_RISING_RESONANCE_SINE_SEGMENT + } resonancePhase; + + // Resulting log-space samples of the square and resonance waves + LogSample squareLogSample; + LogSample resonanceLogSample; + + // Processed neighbour log-space samples of the PCM wave + LogSample firstPCMLogSample; + LogSample secondPCMLogSample; + + //*************************************************************************** + // Internal methods below + //*************************************************************************** + + Bit32u getSampleStep(); + Bit32u getResonanceWaveLengthFactor(Bit32u effectiveCutoffValue); + Bit32u getHighLinearLength(Bit32u effectiveCutoffValue); + + void computePositions(Bit32u highLinearLength, Bit32u lowLinearLength, Bit32u resonanceWaveLengthFactor); + void advancePosition(); + + void generateNextSquareWaveLogSample(); + void generateNextResonanceWaveLogSample(); + void generateNextSawtoothCosineLogSample(LogSample &logSample) const; + + void pcmSampleToLogSample(LogSample &logSample, const Bit16s pcmSample) const; + void generateNextPCMWaveLogSamples(); + +public: + // Initialise the WG engine for generation of synth partial samples and set up the invariant parameters + void initSynth(const bool sawtoothWaveform, const Bit8u pulseWidth, const Bit8u resonance); + + // Initialise the WG engine for generation of PCM partial samples and set up the invariant parameters + void initPCM(const Bit16s * const pcmWaveAddress, const Bit32u pcmWaveLength, const bool pcmWaveLooped, const bool pcmWaveInterpolated); + + // Update parameters with respect to TVP, TVA and TVF, and generate next sample + void generateNextSample(const Bit32u amp, const Bit16u pitch, const Bit32u cutoff); + + // WG output in the log-space consists of two components which are to be added (or ring modulated) in the linear-space afterwards + LogSample getOutputLogSample(const bool first) const; + + // Deactivate the WG engine + void deactivate(); + + // Return active state of the WG engine + bool isActive() const; + + // Return true if the WG engine generates PCM wave samples + bool isPCMWave() const; + + // Return current PCM interpolation factor + Bit32u getPCMInterpolationFactor() const; +}; // class LA32WaveGenerator + +// LA32PartialPair contains a structure of two partials being mixed / ring modulated +class LA32PartialPair { +public: + enum PairType { + MASTER, + SLAVE + }; + + virtual ~LA32PartialPair() {} + + // ringModulated should be set to false for the structures with mixing or stereo output + // ringModulated should be set to true for the structures with ring modulation + // mixed is used for the structures with ring modulation and indicates whether the master partial output is mixed to the ring modulator output + virtual void init(const bool ringModulated, const bool mixed) = 0; + + // Initialise the WG engine for generation of synth partial samples and set up the invariant parameters + virtual void initSynth(const PairType master, const bool sawtoothWaveform, const Bit8u pulseWidth, const Bit8u resonance) = 0; + + // Initialise the WG engine for generation of PCM partial samples and set up the invariant parameters + virtual void initPCM(const PairType master, const Bit16s * const pcmWaveAddress, const Bit32u pcmWaveLength, const bool pcmWaveLooped) = 0; + + // Deactivate the WG engine + virtual void deactivate(const PairType master) = 0; +}; // class LA32PartialPair + +class LA32IntPartialPair : public LA32PartialPair { + LA32WaveGenerator master; + LA32WaveGenerator slave; + bool ringModulated; + bool mixed; + + static Bit16s unlogAndMixWGOutput(const LA32WaveGenerator &wg); + +public: + // ringModulated should be set to false for the structures with mixing or stereo output + // ringModulated should be set to true for the structures with ring modulation + // mixed is used for the structures with ring modulation and indicates whether the master partial output is mixed to the ring modulator output + void init(const bool ringModulated, const bool mixed); + + // Initialise the WG engine for generation of synth partial samples and set up the invariant parameters + void initSynth(const PairType master, const bool sawtoothWaveform, const Bit8u pulseWidth, const Bit8u resonance); + + // Initialise the WG engine for generation of PCM partial samples and set up the invariant parameters + void initPCM(const PairType master, const Bit16s * const pcmWaveAddress, const Bit32u pcmWaveLength, const bool pcmWaveLooped); + + // Update parameters with respect to TVP, TVA and TVF, and generate next sample + void generateNextSample(const PairType master, const Bit32u amp, const Bit16u pitch, const Bit32u cutoff); + + // Perform mixing / ring modulation of WG output and return the result + // Although, LA32 applies panning itself, we assume it is applied in the mixer, not within a pair + Bit16s nextOutSample(); + + // Deactivate the WG engine + void deactivate(const PairType master); + + // Return active state of the WG engine + bool isActive(const PairType master) const; +}; // class LA32IntPartialPair + +} // namespace MT32Emu + +#endif // #ifndef MT32EMU_LA32_WAVE_GENERATOR_H diff --git a/src/SOUND/munt/MemoryRegion.h b/src/SOUND/munt/MemoryRegion.h new file mode 100644 index 000000000..807f14782 --- /dev/null +++ b/src/SOUND/munt/MemoryRegion.h @@ -0,0 +1,132 @@ +/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher + * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#ifndef MT32EMU_MEMORY_REGION_H +#define MT32EMU_MEMORY_REGION_H + +#include + +#include "globals.h" +#include "Types.h" +#include "Structures.h" + +namespace MT32Emu { + +enum MemoryRegionType { + MR_PatchTemp, MR_RhythmTemp, MR_TimbreTemp, MR_Patches, MR_Timbres, MR_System, MR_Display, MR_Reset +}; + +class Synth; + +class MemoryRegion { +private: + Synth *synth; + Bit8u *realMemory; + Bit8u *maxTable; +public: + MemoryRegionType type; + Bit32u startAddr, entrySize, entries; + + MemoryRegion(Synth *useSynth, Bit8u *useRealMemory, Bit8u *useMaxTable, MemoryRegionType useType, Bit32u useStartAddr, Bit32u useEntrySize, Bit32u useEntries) { + synth = useSynth; + realMemory = useRealMemory; + maxTable = useMaxTable; + type = useType; + startAddr = useStartAddr; + entrySize = useEntrySize; + entries = useEntries; + } + int lastTouched(Bit32u addr, Bit32u len) const { + return (offset(addr) + len - 1) / entrySize; + } + int firstTouchedOffset(Bit32u addr) const { + return offset(addr) % entrySize; + } + int firstTouched(Bit32u addr) const { + return offset(addr) / entrySize; + } + Bit32u regionEnd() const { + return startAddr + entrySize * entries; + } + bool contains(Bit32u addr) const { + return addr >= startAddr && addr < regionEnd(); + } + int offset(Bit32u addr) const { + return addr - startAddr; + } + Bit32u getClampedLen(Bit32u addr, Bit32u len) const { + if (addr + len > regionEnd()) + return regionEnd() - addr; + return len; + } + Bit32u next(Bit32u addr, Bit32u len) const { + if (addr + len > regionEnd()) { + return regionEnd() - addr; + } + return 0; + } + Bit8u getMaxValue(int off) const { + if (maxTable == NULL) + return 0xFF; + return maxTable[off % entrySize]; + } + Bit8u *getRealMemory() const { + return realMemory; + } + bool isReadable() const { + return getRealMemory() != NULL; + } + void read(unsigned int entry, unsigned int off, Bit8u *dst, unsigned int len) const; + void write(unsigned int entry, unsigned int off, const Bit8u *src, unsigned int len, bool init = false) const; +}; // class MemoryRegion + +class PatchTempMemoryRegion : public MemoryRegion { +public: + PatchTempMemoryRegion(Synth *useSynth, Bit8u *useRealMemory, Bit8u *useMaxTable) : MemoryRegion(useSynth, useRealMemory, useMaxTable, MR_PatchTemp, MT32EMU_MEMADDR(0x030000), sizeof(MemParams::PatchTemp), 9) {} +}; +class RhythmTempMemoryRegion : public MemoryRegion { +public: + RhythmTempMemoryRegion(Synth *useSynth, Bit8u *useRealMemory, Bit8u *useMaxTable) : MemoryRegion(useSynth, useRealMemory, useMaxTable, MR_RhythmTemp, MT32EMU_MEMADDR(0x030110), sizeof(MemParams::RhythmTemp), 85) {} +}; +class TimbreTempMemoryRegion : public MemoryRegion { +public: + TimbreTempMemoryRegion(Synth *useSynth, Bit8u *useRealMemory, Bit8u *useMaxTable) : MemoryRegion(useSynth, useRealMemory, useMaxTable, MR_TimbreTemp, MT32EMU_MEMADDR(0x040000), sizeof(TimbreParam), 8) {} +}; +class PatchesMemoryRegion : public MemoryRegion { +public: + PatchesMemoryRegion(Synth *useSynth, Bit8u *useRealMemory, Bit8u *useMaxTable) : MemoryRegion(useSynth, useRealMemory, useMaxTable, MR_Patches, MT32EMU_MEMADDR(0x050000), sizeof(PatchParam), 128) {} +}; +class TimbresMemoryRegion : public MemoryRegion { +public: + TimbresMemoryRegion(Synth *useSynth, Bit8u *useRealMemory, Bit8u *useMaxTable) : MemoryRegion(useSynth, useRealMemory, useMaxTable, MR_Timbres, MT32EMU_MEMADDR(0x080000), sizeof(MemParams::PaddedTimbre), 64 + 64 + 64 + 64) {} +}; +class SystemMemoryRegion : public MemoryRegion { +public: + SystemMemoryRegion(Synth *useSynth, Bit8u *useRealMemory, Bit8u *useMaxTable) : MemoryRegion(useSynth, useRealMemory, useMaxTable, MR_System, MT32EMU_MEMADDR(0x100000), sizeof(MemParams::System), 1) {} +}; +class DisplayMemoryRegion : public MemoryRegion { +public: + DisplayMemoryRegion(Synth *useSynth) : MemoryRegion(useSynth, NULL, NULL, MR_Display, MT32EMU_MEMADDR(0x200000), SYSEX_BUFFER_SIZE - 1, 1) {} +}; +class ResetMemoryRegion : public MemoryRegion { +public: + ResetMemoryRegion(Synth *useSynth) : MemoryRegion(useSynth, NULL, NULL, MR_Reset, MT32EMU_MEMADDR(0x7F0000), 0x3FFF, 1) {} +}; + +} // namespace MT32Emu + +#endif // #ifndef MT32EMU_MEMORY_REGION_H diff --git a/src/SOUND/munt/MidiEventQueue.h b/src/SOUND/munt/MidiEventQueue.h new file mode 100644 index 000000000..c5174d6cc --- /dev/null +++ b/src/SOUND/munt/MidiEventQueue.h @@ -0,0 +1,71 @@ +/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher + * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#ifndef MT32EMU_MIDI_EVENT_QUEUE_H +#define MT32EMU_MIDI_EVENT_QUEUE_H + +#include "globals.h" +#include "Types.h" + +namespace MT32Emu { + +/** + * Used to safely store timestamped MIDI events in a local queue. + */ +struct MidiEvent { + Bit32u shortMessageData; + const Bit8u *sysexData; + Bit32u sysexLength; + Bit32u timestamp; + + ~MidiEvent(); + void setShortMessage(Bit32u shortMessageData, Bit32u timestamp); + void setSysex(const Bit8u *sysexData, Bit32u sysexLength, Bit32u timestamp); +}; + +/** + * Simple queue implementation using a ring buffer to store incoming MIDI event before the synth actually processes it. + * It is intended to: + * - get rid of prerenderer while retaining graceful partial abortion + * - add fair emulation of the MIDI interface delays + * - extend the synth interface with the default implementation of a typical rendering loop. + * THREAD SAFETY: + * It is safe to use either in a single thread environment or when there are only two threads - one performs only reading + * and one performs only writing. More complicated usage requires external synchronisation. + */ +class MidiEventQueue { +private: + MidiEvent * const ringBuffer; + const Bit32u ringBufferMask; + volatile Bit32u startPosition; + volatile Bit32u endPosition; + +public: + MidiEventQueue(Bit32u ringBufferSize = DEFAULT_MIDI_EVENT_QUEUE_SIZE); // Must be a power of 2 + ~MidiEventQueue(); + void reset(); + bool pushShortMessage(Bit32u shortMessageData, Bit32u timestamp); + bool pushSysex(const Bit8u *sysexData, Bit32u sysexLength, Bit32u timestamp); + const MidiEvent *peekMidiEvent(); + void dropMidiEvent(); + bool isFull() const; + bool inline isEmpty() const; +}; + +} // namespace MT32Emu + +#endif // #ifndef MT32EMU_MIDI_EVENT_QUEUE_H diff --git a/src/SOUND/munt/MidiStreamParser.cpp b/src/SOUND/munt/MidiStreamParser.cpp new file mode 100644 index 000000000..3a70bec18 --- /dev/null +++ b/src/SOUND/munt/MidiStreamParser.cpp @@ -0,0 +1,289 @@ +/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher + * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#include +#include + +#include "internals.h" + +#include "MidiStreamParser.h" +#include "Synth.h" + +using namespace MT32Emu; + +DefaultMidiStreamParser::DefaultMidiStreamParser(Synth &useSynth, Bit32u initialStreamBufferCapacity) : + MidiStreamParser(initialStreamBufferCapacity), synth(useSynth), timestampSet(false) {} + +void DefaultMidiStreamParser::setTimestamp(const Bit32u useTimestamp) { + timestampSet = true; + timestamp = useTimestamp; +} + +void DefaultMidiStreamParser::resetTimestamp() { + timestampSet = false; +} + +void DefaultMidiStreamParser::handleShortMessage(const Bit32u message) { + do { + if (timestampSet) { + if (synth.playMsg(message, timestamp)) return; + } + else { + if (synth.playMsg(message)) return; + } + } while (synth.reportHandler->onMIDIQueueOverflow()); +} + +void DefaultMidiStreamParser::handleSysex(const Bit8u *stream, const Bit32u length) { + do { + if (timestampSet) { + if (synth.playSysex(stream, length, timestamp)) return; + } + else { + if (synth.playSysex(stream, length)) return; + } + } while (synth.reportHandler->onMIDIQueueOverflow()); +} + +void DefaultMidiStreamParser::handleSystemRealtimeMessage(const Bit8u realtime) { + synth.reportHandler->onMIDISystemRealtime(realtime); +} + +void DefaultMidiStreamParser::printDebug(const char *debugMessage) { + synth.printDebug("%s", debugMessage); +} + +MidiStreamParser::MidiStreamParser(Bit32u initialStreamBufferCapacity) : + MidiStreamParserImpl(*this, *this, initialStreamBufferCapacity) {} + +MidiStreamParserImpl::MidiStreamParserImpl(MidiReceiver &useReceiver, MidiReporter &useReporter, Bit32u initialStreamBufferCapacity) : + midiReceiver(useReceiver), midiReporter(useReporter) +{ + if (initialStreamBufferCapacity < SYSEX_BUFFER_SIZE) initialStreamBufferCapacity = SYSEX_BUFFER_SIZE; + if (MAX_STREAM_BUFFER_SIZE < initialStreamBufferCapacity) initialStreamBufferCapacity = MAX_STREAM_BUFFER_SIZE; + streamBufferCapacity = initialStreamBufferCapacity; + streamBuffer = new Bit8u[streamBufferCapacity]; + streamBufferSize = 0; + runningStatus = 0; + + reserved = NULL; +} + +MidiStreamParserImpl::~MidiStreamParserImpl() { + delete[] streamBuffer; +} + +void MidiStreamParserImpl::parseStream(const Bit8u *stream, Bit32u length) { + while (length > 0) { + Bit32u parsedMessageLength = 0; + if (0xF8 <= *stream) { + // Process System Realtime immediately and go on + midiReceiver.handleSystemRealtimeMessage(*stream); + parsedMessageLength = 1; + // No effect on the running status + } else if (streamBufferSize > 0) { + // Check if there is something in streamBuffer waiting for being processed + if (*streamBuffer == 0xF0) { + parsedMessageLength = parseSysexFragment(stream, length); + } else { + parsedMessageLength = parseShortMessageDataBytes(stream, length); + } + } else { + if (*stream == 0xF0) { + runningStatus = 0; // SysEx clears the running status + parsedMessageLength = parseSysex(stream, length); + } else { + parsedMessageLength = parseShortMessageStatus(stream); + } + } + + // Parsed successfully + stream += parsedMessageLength; + length -= parsedMessageLength; + } +} + +void MidiStreamParserImpl::processShortMessage(const Bit32u message) { + // Adds running status to the MIDI message if it doesn't contain one + Bit8u status = Bit8u(message); + if (0xF8 <= status) { + midiReceiver.handleSystemRealtimeMessage(status); + } else if (processStatusByte(status)) { + midiReceiver.handleShortMessage((message << 8) | status); + } else if (0x80 <= status) { // If no running status available yet, skip this message + midiReceiver.handleShortMessage(message); + } +} + +// We deal with SysEx messages below 512 bytes long in most cases. Nevertheless, it seems reasonable to support a possibility +// to load bulk dumps using a single message. However, this is known to fail with a real device due to limited input buffer size. +bool MidiStreamParserImpl::checkStreamBufferCapacity(const bool preserveContent) { + if (streamBufferSize < streamBufferCapacity) return true; + if (streamBufferCapacity < MAX_STREAM_BUFFER_SIZE) { + Bit8u *oldStreamBuffer = streamBuffer; + streamBufferCapacity = MAX_STREAM_BUFFER_SIZE; + streamBuffer = new Bit8u[streamBufferCapacity]; + if (preserveContent) memcpy(streamBuffer, oldStreamBuffer, streamBufferSize); + delete[] oldStreamBuffer; + return true; + } + return false; +} + +// Checks input byte whether it is a status byte. If not, replaces it with running status when available. +// Returns true if the input byte was changed to running status. +bool MidiStreamParserImpl::processStatusByte(Bit8u &status) { + if (status < 0x80) { + // First byte isn't status, try running status + if (runningStatus < 0x80) { + // No running status available yet + midiReporter.printDebug("processStatusByte: No valid running status yet, MIDI message ignored"); + return false; + } + status = runningStatus; + return true; + } else if (status < 0xF0) { + // Store current status as running for a Voice message + runningStatus = status; + } else if (status < 0xF8) { + // System Common clears running status + runningStatus = 0; + } // System Realtime doesn't affect running status + return false; +} + +// Returns # of bytes parsed +Bit32u MidiStreamParserImpl::parseShortMessageStatus(const Bit8u stream[]) { + Bit8u status = *stream; + Bit32u parsedLength = processStatusByte(status) ? 0 : 1; + if (0x80 <= status) { // If no running status available yet, skip one byte + *streamBuffer = status; + ++streamBufferSize; + } + return parsedLength; +} + +// Returns # of bytes parsed +Bit32u MidiStreamParserImpl::parseShortMessageDataBytes(const Bit8u stream[], Bit32u length) { + const Bit32u shortMessageLength = Synth::getShortMessageLength(*streamBuffer); + Bit32u parsedLength = 0; + + // Append incoming bytes to streamBuffer + while ((streamBufferSize < shortMessageLength) && (length-- > 0)) { + Bit8u dataByte = *(stream++); + if (dataByte < 0x80) { + // Add data byte to streamBuffer + streamBuffer[streamBufferSize++] = dataByte; + } else if (dataByte < 0xF8) { + // Discard invalid bytes and start over + char s[128]; + sprintf(s, "parseShortMessageDataBytes: Invalid short message: status %02x, expected length %i, actual %i -> ignored", *streamBuffer, shortMessageLength, streamBufferSize); + midiReporter.printDebug(s); + streamBufferSize = 0; // Clear streamBuffer + return parsedLength; + } else { + // Bypass System Realtime message + midiReceiver.handleSystemRealtimeMessage(dataByte); + } + ++parsedLength; + } + if (streamBufferSize < shortMessageLength) return parsedLength; // Still lacks data bytes + + // Assemble short message + Bit32u shortMessage = streamBuffer[0]; + for (Bit32u i = 1; i < shortMessageLength; ++i) { + shortMessage |= streamBuffer[i] << (i << 3); + } + midiReceiver.handleShortMessage(shortMessage); + streamBufferSize = 0; // Clear streamBuffer + return parsedLength; +} + +// Returns # of bytes parsed +Bit32u MidiStreamParserImpl::parseSysex(const Bit8u stream[], const Bit32u length) { + // Find SysEx length + Bit32u sysexLength = 1; + while (sysexLength < length) { + Bit8u nextByte = stream[sysexLength++]; + if (0x80 <= nextByte) { + if (nextByte == 0xF7) { + // End of SysEx + midiReceiver.handleSysex(stream, sysexLength); + return sysexLength; + } + if (0xF8 <= nextByte) { + // The System Realtime message must be processed right after return + // but the SysEx is actually fragmented and to be reconstructed in streamBuffer + --sysexLength; + break; + } + // Illegal status byte in SysEx message, aborting + midiReporter.printDebug("parseSysex: SysEx message lacks end-of-sysex (0xf7), ignored"); + // Continue parsing from that point + return sysexLength - 1; + } + } + + // Store incomplete SysEx message for further processing + streamBufferSize = sysexLength; + if (checkStreamBufferCapacity(false)) { + memcpy(streamBuffer, stream, sysexLength); + } else { + // Not enough buffer capacity, don't care about the real buffer content, just mark the first byte + *streamBuffer = *stream; + streamBufferSize = streamBufferCapacity; + } + return sysexLength; +} + +// Returns # of bytes parsed +Bit32u MidiStreamParserImpl::parseSysexFragment(const Bit8u stream[], const Bit32u length) { + Bit32u parsedLength = 0; + while (parsedLength < length) { + Bit8u nextByte = stream[parsedLength++]; + if (nextByte < 0x80) { + // Add SysEx data byte to streamBuffer + if (checkStreamBufferCapacity(true)) streamBuffer[streamBufferSize++] = nextByte; + continue; + } + if (0xF8 <= nextByte) { + // Bypass System Realtime message + midiReceiver.handleSystemRealtimeMessage(nextByte); + continue; + } + if (nextByte != 0xF7) { + // Illegal status byte in SysEx message, aborting + midiReporter.printDebug("parseSysexFragment: SysEx message lacks end-of-sysex (0xf7), ignored"); + // Clear streamBuffer and continue parsing from that point + streamBufferSize = 0; + --parsedLength; + break; + } + // End of SysEx + if (checkStreamBufferCapacity(true)) { + streamBuffer[streamBufferSize++] = nextByte; + midiReceiver.handleSysex(streamBuffer, streamBufferSize); + streamBufferSize = 0; // Clear streamBuffer + break; + } + // Encountered streamBuffer overrun + midiReporter.printDebug("parseSysexFragment: streamBuffer overrun while receiving SysEx message, ignored. Max allowed size of fragmented SysEx is 32768 bytes."); + streamBufferSize = 0; // Clear streamBuffer + break; + } + return parsedLength; +} diff --git a/src/SOUND/munt/MidiStreamParser.h b/src/SOUND/munt/MidiStreamParser.h new file mode 100644 index 000000000..881ec032f --- /dev/null +++ b/src/SOUND/munt/MidiStreamParser.h @@ -0,0 +1,124 @@ +/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher + * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#ifndef MT32EMU_MIDI_STREAM_PARSER_H +#define MT32EMU_MIDI_STREAM_PARSER_H + +#include "globals.h" +#include "Types.h" + +namespace MT32Emu { + +class Synth; + +// Interface for a user-supplied class to receive parsed well-formed MIDI messages. +class MT32EMU_EXPORT MidiReceiver { +public: + // Invoked when a complete short MIDI message is parsed in the input MIDI stream. + virtual void handleShortMessage(const Bit32u message) = 0; + + // Invoked when a complete well-formed System Exclusive MIDI message is parsed in the input MIDI stream. + virtual void handleSysex(const Bit8u stream[], const Bit32u length) = 0; + + // Invoked when a System Realtime MIDI message is parsed in the input MIDI stream. + virtual void handleSystemRealtimeMessage(const Bit8u realtime) = 0; + +protected: + ~MidiReceiver() {} +}; + +// Interface for a user-supplied class to receive notifications of input MIDI stream parse errors. +class MT32EMU_EXPORT MidiReporter { +public: + // Invoked when an error occurs during processing the input MIDI stream. + virtual void printDebug(const char *debugMessage) = 0; + +protected: + ~MidiReporter() {} +}; + +// Provides a context for parsing a stream of MIDI events coming from a single source. +// There can be multiple MIDI sources feeding MIDI events to a single Synth object. +// NOTE: Calls from multiple threads which feed a single Synth object with data must be explicitly synchronised, +// although, no synchronisation is required with the rendering thread. +class MT32EMU_EXPORT MidiStreamParserImpl { +public: + // The first two arguments provide for implementations of essential interfaces needed. + // The third argument specifies streamBuffer initial capacity. The buffer capacity should be large enough to fit the longest SysEx expected. + // If a longer SysEx occurs, streamBuffer is reallocated to the maximum size of MAX_STREAM_BUFFER_SIZE (32768 bytes). + // Default capacity is SYSEX_BUFFER_SIZE (1000 bytes) which is enough to fit SysEx messages in common use. + MidiStreamParserImpl(MidiReceiver &, MidiReporter &, Bit32u initialStreamBufferCapacity = SYSEX_BUFFER_SIZE); + virtual ~MidiStreamParserImpl(); + + // Parses a block of raw MIDI bytes. All the parsed MIDI messages are sent in sequence to the user-supplied methods for further processing. + // SysEx messages are allowed to be fragmented across several calls to this method. Running status is also handled for short messages. + // NOTE: the total length of a SysEx message being fragmented shall not exceed MAX_STREAM_BUFFER_SIZE (32768 bytes). + void parseStream(const Bit8u *stream, Bit32u length); + + // Convenience method which accepts a Bit32u-encoded short MIDI message and sends it to the user-supplied method for further processing. + // The short MIDI message may contain no status byte, the running status is used in this case. + void processShortMessage(const Bit32u message); + +private: + Bit8u runningStatus; + Bit8u *streamBuffer; + Bit32u streamBufferCapacity; + Bit32u streamBufferSize; + MidiReceiver &midiReceiver; + MidiReporter &midiReporter; + + // Binary compatibility helper. + void *reserved; + + bool checkStreamBufferCapacity(const bool preserveContent); + bool processStatusByte(Bit8u &status); + Bit32u parseShortMessageStatus(const Bit8u stream[]); + Bit32u parseShortMessageDataBytes(const Bit8u stream[], Bit32u length); + Bit32u parseSysex(const Bit8u stream[], const Bit32u length); + Bit32u parseSysexFragment(const Bit8u stream[], const Bit32u length); +}; // class MidiStreamParserImpl + +// An abstract class that provides a context for parsing a stream of MIDI events coming from a single source. +class MT32EMU_EXPORT MidiStreamParser : public MidiStreamParserImpl, protected MidiReceiver, protected MidiReporter { +public: + // The argument specifies streamBuffer initial capacity. The buffer capacity should be large enough to fit the longest SysEx expected. + // If a longer SysEx occurs, streamBuffer is reallocated to the maximum size of MAX_STREAM_BUFFER_SIZE (32768 bytes). + // Default capacity is SYSEX_BUFFER_SIZE (1000 bytes) which is enough to fit SysEx messages in common use. + explicit MidiStreamParser(Bit32u initialStreamBufferCapacity = SYSEX_BUFFER_SIZE); +}; + +class MT32EMU_EXPORT DefaultMidiStreamParser : public MidiStreamParser { +public: + explicit DefaultMidiStreamParser(Synth &synth, Bit32u initialStreamBufferCapacity = SYSEX_BUFFER_SIZE); + void setTimestamp(const Bit32u useTimestamp); + void resetTimestamp(); + +protected: + void handleShortMessage(const Bit32u message); + void handleSysex(const Bit8u *stream, const Bit32u length); + void handleSystemRealtimeMessage(const Bit8u realtime); + void printDebug(const char *debugMessage); + +private: + Synth &synth; + bool timestampSet; + Bit32u timestamp; +}; + +} // namespace MT32Emu + +#endif // MT32EMU_MIDI_STREAM_PARSER_H diff --git a/src/SOUND/munt/Part.cpp b/src/SOUND/munt/Part.cpp new file mode 100644 index 000000000..85cc23970 --- /dev/null +++ b/src/SOUND/munt/Part.cpp @@ -0,0 +1,695 @@ +/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher + * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#include +#include + +#include "internals.h" + +#include "Part.h" +#include "Partial.h" +#include "PartialManager.h" +#include "Poly.h" +#include "Synth.h" + +namespace MT32Emu { + +static const Bit8u PartialStruct[13] = { + 0, 0, 2, 2, 1, 3, + 3, 0, 3, 0, 2, 1, 3 +}; + +static const Bit8u PartialMixStruct[13] = { + 0, 1, 0, 1, 1, 0, + 1, 3, 3, 2, 2, 2, 2 +}; + +RhythmPart::RhythmPart(Synth *useSynth, unsigned int usePartNum): Part(useSynth, usePartNum) { + strcpy(name, "Rhythm"); + rhythmTemp = &synth->mt32ram.rhythmTemp[0]; + refresh(); +} + +Part::Part(Synth *useSynth, unsigned int usePartNum) { + synth = useSynth; + partNum = usePartNum; + patchCache[0].dirty = true; + holdpedal = false; + patchTemp = &synth->mt32ram.patchTemp[partNum]; + if (usePartNum == 8) { + // Nasty hack for rhythm + timbreTemp = NULL; + } else { + sprintf(name, "Part %d", partNum + 1); + timbreTemp = &synth->mt32ram.timbreTemp[partNum]; + } + currentInstr[0] = 0; + currentInstr[10] = 0; + modulation = 0; + expression = 100; + pitchBend = 0; + activePartialCount = 0; + memset(patchCache, 0, sizeof(patchCache)); +} + +Part::~Part() { + while (!activePolys.isEmpty()) { + delete activePolys.takeFirst(); + } +} + +void Part::setDataEntryMSB(unsigned char midiDataEntryMSB) { + if (nrpn) { + // The last RPN-related control change was for an NRPN, + // which the real synths don't support. + return; + } + if (rpn != 0) { + // The RPN has been set to something other than 0, + // which is the only RPN that these synths support + return; + } + patchTemp->patch.benderRange = midiDataEntryMSB > 24 ? 24 : midiDataEntryMSB; + updatePitchBenderRange(); +} + +void Part::setNRPN() { + nrpn = true; +} + +void Part::setRPNLSB(unsigned char midiRPNLSB) { + nrpn = false; + rpn = (rpn & 0xFF00) | midiRPNLSB; +} + +void Part::setRPNMSB(unsigned char midiRPNMSB) { + nrpn = false; + rpn = (rpn & 0x00FF) | (midiRPNMSB << 8); +} + +void Part::setHoldPedal(bool pressed) { + if (holdpedal && !pressed) { + holdpedal = false; + stopPedalHold(); + } else { + holdpedal = pressed; + } +} + +Bit32s Part::getPitchBend() const { + return pitchBend; +} + +void Part::setBend(unsigned int midiBend) { + // CONFIRMED: + pitchBend = ((signed(midiBend) - 8192) * pitchBenderRange) >> 14; // PORTABILITY NOTE: Assumes arithmetic shift +} + +Bit8u Part::getModulation() const { + return modulation; +} + +void Part::setModulation(unsigned int midiModulation) { + modulation = Bit8u(midiModulation); +} + +void Part::resetAllControllers() { + modulation = 0; + expression = 100; + pitchBend = 0; + setHoldPedal(false); +} + +void Part::reset() { + resetAllControllers(); + allSoundOff(); + rpn = 0xFFFF; +} + +void RhythmPart::refresh() { + // (Re-)cache all the mapped timbres ahead of time + for (unsigned int drumNum = 0; drumNum < synth->controlROMMap->rhythmSettingsCount; drumNum++) { + int drumTimbreNum = rhythmTemp[drumNum].timbre; + if (drumTimbreNum >= 127) { // 94 on MT-32 + continue; + } + PatchCache *cache = drumCache[drumNum]; + backupCacheToPartials(cache); + for (int t = 0; t < 4; t++) { + // Common parameters, stored redundantly + cache[t].dirty = true; + cache[t].reverb = rhythmTemp[drumNum].reverbSwitch > 0; + } + } + updatePitchBenderRange(); +} + +void Part::refresh() { + backupCacheToPartials(patchCache); + for (int t = 0; t < 4; t++) { + // Common parameters, stored redundantly + patchCache[t].dirty = true; + patchCache[t].reverb = patchTemp->patch.reverbSwitch > 0; + } + memcpy(currentInstr, timbreTemp->common.name, 10); + synth->newTimbreSet(partNum, patchTemp->patch.timbreGroup, patchTemp->patch.timbreNum, currentInstr); + updatePitchBenderRange(); +} + +const char *Part::getCurrentInstr() const { + return ¤tInstr[0]; +} + +void RhythmPart::refreshTimbre(unsigned int absTimbreNum) { + for (int m = 0; m < 85; m++) { + if (rhythmTemp[m].timbre == absTimbreNum - 128) { + drumCache[m][0].dirty = true; + } + } +} + +void Part::refreshTimbre(unsigned int absTimbreNum) { + if (getAbsTimbreNum() == absTimbreNum) { + memcpy(currentInstr, timbreTemp->common.name, 10); + patchCache[0].dirty = true; + } +} + +void Part::setPatch(const PatchParam *patch) { + patchTemp->patch = *patch; +} + +void RhythmPart::setTimbre(TimbreParam * /*timbre*/) { + synth->printDebug("%s: Attempted to call setTimbre() - doesn't make sense for rhythm", name); +} + +void Part::setTimbre(TimbreParam *timbre) { + *timbreTemp = *timbre; +} + +unsigned int RhythmPart::getAbsTimbreNum() const { + synth->printDebug("%s: Attempted to call getAbsTimbreNum() - doesn't make sense for rhythm", name); + return 0; +} + +unsigned int Part::getAbsTimbreNum() const { + return (patchTemp->patch.timbreGroup * 64) + patchTemp->patch.timbreNum; +} + +#if MT32EMU_MONITOR_MIDI > 0 +void RhythmPart::setProgram(unsigned int patchNum) { + synth->printDebug("%s: Attempt to set program (%d) on rhythm is invalid", name, patchNum); +} +#else +void RhythmPart::setProgram(unsigned int) { } +#endif + +void Part::setProgram(unsigned int patchNum) { + setPatch(&synth->mt32ram.patches[patchNum]); + holdpedal = false; + allSoundOff(); + setTimbre(&synth->mt32ram.timbres[getAbsTimbreNum()].timbre); + refresh(); +} + +void Part::updatePitchBenderRange() { + pitchBenderRange = patchTemp->patch.benderRange * 683; +} + +void Part::backupCacheToPartials(PatchCache cache[4]) { + // check if any partials are still playing with the old patch cache + // if so then duplicate the cached data from the part to the partial so that + // we can change the part's cache without affecting the partial. + // We delay this until now to avoid a copy operation with every note played + for (Poly *poly = activePolys.getFirst(); poly != NULL; poly = poly->getNext()) { + poly->backupCacheToPartials(cache); + } +} + +void Part::cacheTimbre(PatchCache cache[4], const TimbreParam *timbre) { + backupCacheToPartials(cache); + int partialCount = 0; + for (int t = 0; t < 4; t++) { + if (((timbre->common.partialMute >> t) & 0x1) == 1) { + cache[t].playPartial = true; + partialCount++; + } else { + cache[t].playPartial = false; + continue; + } + + // Calculate and cache common parameters + cache[t].srcPartial = timbre->partial[t]; + + cache[t].pcm = timbre->partial[t].wg.pcmWave; + + switch (t) { + case 0: + cache[t].PCMPartial = (PartialStruct[int(timbre->common.partialStructure12)] & 0x2) ? true : false; + cache[t].structureMix = PartialMixStruct[int(timbre->common.partialStructure12)]; + cache[t].structurePosition = 0; + cache[t].structurePair = 1; + break; + case 1: + cache[t].PCMPartial = (PartialStruct[int(timbre->common.partialStructure12)] & 0x1) ? true : false; + cache[t].structureMix = PartialMixStruct[int(timbre->common.partialStructure12)]; + cache[t].structurePosition = 1; + cache[t].structurePair = 0; + break; + case 2: + cache[t].PCMPartial = (PartialStruct[int(timbre->common.partialStructure34)] & 0x2) ? true : false; + cache[t].structureMix = PartialMixStruct[int(timbre->common.partialStructure34)]; + cache[t].structurePosition = 0; + cache[t].structurePair = 3; + break; + case 3: + cache[t].PCMPartial = (PartialStruct[int(timbre->common.partialStructure34)] & 0x1) ? true : false; + cache[t].structureMix = PartialMixStruct[int(timbre->common.partialStructure34)]; + cache[t].structurePosition = 1; + cache[t].structurePair = 2; + break; + default: + break; + } + + cache[t].partialParam = &timbre->partial[t]; + + cache[t].waveform = timbre->partial[t].wg.waveform; + } + for (int t = 0; t < 4; t++) { + // Common parameters, stored redundantly + cache[t].dirty = false; + cache[t].partialCount = partialCount; + cache[t].sustain = (timbre->common.noSustain == 0); + } + //synth->printDebug("Res 1: %d 2: %d 3: %d 4: %d", cache[0].waveform, cache[1].waveform, cache[2].waveform, cache[3].waveform); + +#if MT32EMU_MONITOR_INSTRUMENTS > 0 + synth->printDebug("%s (%s): Recached timbre", name, currentInstr); + for (int i = 0; i < 4; i++) { + synth->printDebug(" %d: play=%s, pcm=%s (%d), wave=%d", i, cache[i].playPartial ? "YES" : "NO", cache[i].PCMPartial ? "YES" : "NO", timbre->partial[i].wg.pcmWave, timbre->partial[i].wg.waveform); + } +#endif +} + +const char *Part::getName() const { + return name; +} + +void Part::setVolume(unsigned int midiVolume) { + // CONFIRMED: This calculation matches the table used in the control ROM + patchTemp->outputLevel = Bit8u(midiVolume * 100 / 127); + //synth->printDebug("%s (%s): Set volume to %d", name, currentInstr, midiVolume); +} + +Bit8u Part::getVolume() const { + return patchTemp->outputLevel; +} + +Bit8u Part::getExpression() const { + return expression; +} + +void Part::setExpression(unsigned int midiExpression) { + // CONFIRMED: This calculation matches the table used in the control ROM + expression = Bit8u(midiExpression * 100 / 127); +} + +void RhythmPart::setPan(unsigned int midiPan) { + // CONFIRMED: This does change patchTemp, but has no actual effect on playback. +#if MT32EMU_MONITOR_MIDI > 0 + synth->printDebug("%s: Pointlessly setting pan (%d) on rhythm part", name, midiPan); +#endif + Part::setPan(midiPan); +} + +void Part::setPan(unsigned int midiPan) { + // NOTE: Panning is inverted compared to GM. + + // CM-32L: Divide by 8.5 + patchTemp->panpot = Bit8u((midiPan << 3) / 68); + // FIXME: MT-32: Divide by 9 + //patchTemp->panpot = Bit8u(midiPan / 9); + + //synth->printDebug("%s (%s): Set pan to %d", name, currentInstr, panpot); +} + +/** + * Applies key shift to a MIDI key and converts it into an internal key value in the range 12-108. + */ +unsigned int Part::midiKeyToKey(unsigned int midiKey) { + int key = midiKey + patchTemp->patch.keyShift; + if (key < 36) { + // After keyShift is applied, key < 36, so move up by octaves + while (key < 36) { + key += 12; + } + } else if (key > 132) { + // After keyShift is applied, key > 132, so move down by octaves + while (key > 132) { + key -= 12; + } + } + key -= 24; + return key; +} + +void RhythmPart::noteOn(unsigned int midiKey, unsigned int velocity) { + if (midiKey < 24 || midiKey > 108) { /*> 87 on MT-32)*/ + synth->printDebug("%s: Attempted to play invalid key %d (velocity %d)", name, midiKey, velocity); + return; + } + unsigned int key = midiKey; + unsigned int drumNum = key - 24; + int drumTimbreNum = rhythmTemp[drumNum].timbre; + const int drumTimbreCount = 64 + synth->controlROMMap->timbreRCount; // 94 on MT-32, 128 on LAPC-I/CM32-L + if (drumTimbreNum == 127 || drumTimbreNum >= drumTimbreCount) { // timbre #127 is OFF, no sense to play it + synth->printDebug("%s: Attempted to play unmapped key %d (velocity %d)", name, midiKey, velocity); + return; + } + // CONFIRMED: Two special cases described by Mok + if (drumTimbreNum == 64 + 6) { + noteOff(0); + key = 1; + } else if (drumTimbreNum == 64 + 7) { + // This noteOff(0) is not performed on MT-32, only LAPC-I + noteOff(0); + key = 0; + } + int absTimbreNum = drumTimbreNum + 128; + TimbreParam *timbre = &synth->mt32ram.timbres[absTimbreNum].timbre; + memcpy(currentInstr, timbre->common.name, 10); + if (drumCache[drumNum][0].dirty) { + cacheTimbre(drumCache[drumNum], timbre); + } +#if MT32EMU_MONITOR_INSTRUMENTS > 0 + synth->printDebug("%s (%s): Start poly (drum %d, timbre %d): midiKey %u, key %u, velo %u, mod %u, exp %u, bend %u", name, currentInstr, drumNum, absTimbreNum, midiKey, key, velocity, modulation, expression, pitchBend); +#if MT32EMU_MONITOR_INSTRUMENTS > 1 + // According to info from Mok, keyShift does not appear to affect anything on rhythm part on LAPC-I, but may do on MT-32 - needs investigation + synth->printDebug(" Patch: (timbreGroup %u), (timbreNum %u), (keyShift %u), fineTune %u, benderRange %u, assignMode %u, (reverbSwitch %u)", patchTemp->patch.timbreGroup, patchTemp->patch.timbreNum, patchTemp->patch.keyShift, patchTemp->patch.fineTune, patchTemp->patch.benderRange, patchTemp->patch.assignMode, patchTemp->patch.reverbSwitch); + synth->printDebug(" PatchTemp: outputLevel %u, (panpot %u)", patchTemp->outputLevel, patchTemp->panpot); + synth->printDebug(" RhythmTemp: timbre %u, outputLevel %u, panpot %u, reverbSwitch %u", rhythmTemp[drumNum].timbre, rhythmTemp[drumNum].outputLevel, rhythmTemp[drumNum].panpot, rhythmTemp[drumNum].reverbSwitch); +#endif +#endif + playPoly(drumCache[drumNum], &rhythmTemp[drumNum], midiKey, key, velocity); +} + +void Part::noteOn(unsigned int midiKey, unsigned int velocity) { + unsigned int key = midiKeyToKey(midiKey); + if (patchCache[0].dirty) { + cacheTimbre(patchCache, timbreTemp); + } +#if MT32EMU_MONITOR_INSTRUMENTS > 0 + synth->printDebug("%s (%s): Start poly: midiKey %u, key %u, velo %u, mod %u, exp %u, bend %u", name, currentInstr, midiKey, key, velocity, modulation, expression, pitchBend); +#if MT32EMU_MONITOR_INSTRUMENTS > 1 + synth->printDebug(" Patch: timbreGroup %u, timbreNum %u, keyShift %u, fineTune %u, benderRange %u, assignMode %u, reverbSwitch %u", patchTemp->patch.timbreGroup, patchTemp->patch.timbreNum, patchTemp->patch.keyShift, patchTemp->patch.fineTune, patchTemp->patch.benderRange, patchTemp->patch.assignMode, patchTemp->patch.reverbSwitch); + synth->printDebug(" PatchTemp: outputLevel %u, panpot %u", patchTemp->outputLevel, patchTemp->panpot); +#endif +#endif + playPoly(patchCache, NULL, midiKey, key, velocity); +} + +bool Part::abortFirstPoly(unsigned int key) { + for (Poly *poly = activePolys.getFirst(); poly != NULL; poly = poly->getNext()) { + if (poly->getKey() == key) { + return poly->startAbort(); + } + } + return false; +} + +bool Part::abortFirstPoly(PolyState polyState) { + for (Poly *poly = activePolys.getFirst(); poly != NULL; poly = poly->getNext()) { + if (poly->getState() == polyState) { + return poly->startAbort(); + } + } + return false; +} + +bool Part::abortFirstPolyPreferHeld() { + if (abortFirstPoly(POLY_Held)) { + return true; + } + return abortFirstPoly(); +} + +bool Part::abortFirstPoly() { + if (activePolys.isEmpty()) { + return false; + } + return activePolys.getFirst()->startAbort(); +} + +void Part::playPoly(const PatchCache cache[4], const MemParams::RhythmTemp *rhythmTemp, unsigned int midiKey, unsigned int key, unsigned int velocity) { + // CONFIRMED: Even in single-assign mode, we don't abort playing polys if the timbre to play is completely muted. + unsigned int needPartials = cache[0].partialCount; + if (needPartials == 0) { + synth->printDebug("%s (%s): Completely muted instrument", name, currentInstr); + return; + } + + if ((patchTemp->patch.assignMode & 2) == 0) { + // Single-assign mode + abortFirstPoly(key); + if (synth->isAbortingPoly()) return; + } + + if (!synth->partialManager->freePartials(needPartials, partNum)) { +#if MT32EMU_MONITOR_PARTIALS > 0 + synth->printDebug("%s (%s): Insufficient free partials to play key %d (velocity %d); needed=%d, free=%d, assignMode=%d", name, currentInstr, midiKey, velocity, needPartials, synth->partialManager->getFreePartialCount(), patchTemp->patch.assignMode); + synth->printPartialUsage(); +#endif + return; + } + if (synth->isAbortingPoly()) return; + + Poly *poly = synth->partialManager->assignPolyToPart(this); + if (poly == NULL) { + synth->printDebug("%s (%s): No free poly to play key %d (velocity %d)", name, currentInstr, midiKey, velocity); + return; + } + if (patchTemp->patch.assignMode & 1) { + // Priority to data first received + activePolys.prepend(poly); + } else { + activePolys.append(poly); + } + + Partial *partials[4]; + for (int x = 0; x < 4; x++) { + if (cache[x].playPartial) { + partials[x] = synth->partialManager->allocPartial(partNum); + activePartialCount++; + } else { + partials[x] = NULL; + } + } + poly->reset(key, velocity, cache[0].sustain, partials); + + for (int x = 0; x < 4; x++) { + if (partials[x] != NULL) { +#if MT32EMU_MONITOR_PARTIALS > 2 + synth->printDebug("%s (%s): Allocated partial %d", name, currentInstr, partials[x]->debugGetPartialNum()); +#endif + partials[x]->startPartial(this, poly, &cache[x], rhythmTemp, partials[cache[x].structurePair]); + } + } +#if MT32EMU_MONITOR_PARTIALS > 1 + synth->printPartialUsage(); +#endif + synth->reportHandler->onPolyStateChanged(Bit8u(partNum)); +} + +void Part::allNotesOff() { + // The MIDI specification states - and Mok confirms - that all notes off (0x7B) + // should treat the hold pedal as usual. + for (Poly *poly = activePolys.getFirst(); poly != NULL; poly = poly->getNext()) { + // FIXME: This has special handling of key 0 in NoteOff that Mok has not yet confirmed applies to AllNotesOff. + // if (poly->canSustain() || poly->getKey() == 0) { + // FIXME: The real devices are found to be ignoring non-sustaining polys while processing AllNotesOff. Need to be confirmed. + if (poly->canSustain()) { + poly->noteOff(holdpedal); + } + } +} + +void Part::allSoundOff() { + // MIDI "All sound off" (0x78) should release notes immediately regardless of the hold pedal. + // This controller is not actually implemented by the synths, though (according to the docs and Mok) - + // we're only using this method internally. + for (Poly *poly = activePolys.getFirst(); poly != NULL; poly = poly->getNext()) { + poly->startDecay(); + } +} + +void Part::stopPedalHold() { + for (Poly *poly = activePolys.getFirst(); poly != NULL; poly = poly->getNext()) { + poly->stopPedalHold(); + } +} + +void RhythmPart::noteOff(unsigned int midiKey) { + stopNote(midiKey); +} + +void Part::noteOff(unsigned int midiKey) { + stopNote(midiKeyToKey(midiKey)); +} + +void Part::stopNote(unsigned int key) { +#if MT32EMU_MONITOR_INSTRUMENTS > 0 + synth->printDebug("%s (%s): stopping key %d", name, currentInstr, key); +#endif + + for (Poly *poly = activePolys.getFirst(); poly != NULL; poly = poly->getNext()) { + // Generally, non-sustaining instruments ignore note off. They die away eventually anyway. + // Key 0 (only used by special cases on rhythm part) reacts to note off even if non-sustaining or pedal held. + if (poly->getKey() == key && (poly->canSustain() || key == 0)) { + if (poly->noteOff(holdpedal && key != 0)) { + break; + } + } + } +} + +const MemParams::PatchTemp *Part::getPatchTemp() const { + return patchTemp; +} + +unsigned int Part::getActivePartialCount() const { + return activePartialCount; +} + +const Poly *Part::getFirstActivePoly() const { + return activePolys.getFirst(); +} + +unsigned int Part::getActiveNonReleasingPartialCount() const { + unsigned int activeNonReleasingPartialCount = 0; + for (Poly *poly = activePolys.getFirst(); poly != NULL; poly = poly->getNext()) { + if (poly->getState() != POLY_Releasing) { + activeNonReleasingPartialCount += poly->getActivePartialCount(); + } + } + return activeNonReleasingPartialCount; +} + +Synth *Part::getSynth() const { + return synth; +} + +void Part::partialDeactivated(Poly *poly) { + activePartialCount--; + if (!poly->isActive()) { + activePolys.remove(poly); + synth->partialManager->polyFreed(poly); + synth->reportHandler->onPolyStateChanged(Bit8u(partNum)); + } +} + +PolyList::PolyList() : firstPoly(NULL), lastPoly(NULL) {} + +bool PolyList::isEmpty() const { +#ifdef MT32EMU_POLY_LIST_DEBUG + if ((firstPoly == NULL || lastPoly == NULL) && firstPoly != lastPoly) { + printf("PolyList: desynchronised firstPoly & lastPoly pointers\n"); + } +#endif + return firstPoly == NULL && lastPoly == NULL; +} + +Poly *PolyList::getFirst() const { + return firstPoly; +} + +Poly *PolyList::getLast() const { + return lastPoly; +} + +void PolyList::prepend(Poly *poly) { +#ifdef MT32EMU_POLY_LIST_DEBUG + if (poly->getNext() != NULL) { + printf("PolyList: Non-NULL next field in a Poly being prepended is ignored\n"); + } +#endif + poly->setNext(firstPoly); + firstPoly = poly; + if (lastPoly == NULL) { + lastPoly = poly; + } +} + +void PolyList::append(Poly *poly) { +#ifdef MT32EMU_POLY_LIST_DEBUG + if (poly->getNext() != NULL) { + printf("PolyList: Non-NULL next field in a Poly being appended is ignored\n"); + } +#endif + poly->setNext(NULL); + if (lastPoly != NULL) { +#ifdef MT32EMU_POLY_LIST_DEBUG + if (lastPoly->getNext() != NULL) { + printf("PolyList: Non-NULL next field in the lastPoly\n"); + } +#endif + lastPoly->setNext(poly); + } + lastPoly = poly; + if (firstPoly == NULL) { + firstPoly = poly; + } +} + +Poly *PolyList::takeFirst() { + Poly *oldFirst = firstPoly; + firstPoly = oldFirst->getNext(); + if (firstPoly == NULL) { +#ifdef MT32EMU_POLY_LIST_DEBUG + if (lastPoly != oldFirst) { + printf("PolyList: firstPoly != lastPoly in a list with a single Poly\n"); + } +#endif + lastPoly = NULL; + } + oldFirst->setNext(NULL); + return oldFirst; +} + +void PolyList::remove(Poly * const polyToRemove) { + if (polyToRemove == firstPoly) { + takeFirst(); + return; + } + for (Poly *poly = firstPoly; poly != NULL; poly = poly->getNext()) { + if (poly->getNext() == polyToRemove) { + if (polyToRemove == lastPoly) { +#ifdef MT32EMU_POLY_LIST_DEBUG + if (lastPoly->getNext() != NULL) { + printf("PolyList: Non-NULL next field in the lastPoly\n"); + } +#endif + lastPoly = poly; + } + poly->setNext(polyToRemove->getNext()); + polyToRemove->setNext(NULL); + break; + } + } +} + +} // namespace MT32Emu diff --git a/src/SOUND/munt/Part.h b/src/SOUND/munt/Part.h new file mode 100644 index 000000000..a4de1060b --- /dev/null +++ b/src/SOUND/munt/Part.h @@ -0,0 +1,153 @@ +/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher + * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#ifndef MT32EMU_PART_H +#define MT32EMU_PART_H + +#include "globals.h" +#include "internals.h" +#include "Types.h" +#include "Structures.h" + +namespace MT32Emu { + +class Poly; +class Synth; + +class PolyList { +private: + Poly *firstPoly; + Poly *lastPoly; + +public: + PolyList(); + bool isEmpty() const; + Poly *getFirst() const; + Poly *getLast() const; + void prepend(Poly *poly); + void append(Poly *poly); + Poly *takeFirst(); + void remove(Poly * const poly); +}; + +class Part { +private: + // Direct pointer to sysex-addressable memory dedicated to this part (valid for parts 1-8, NULL for rhythm) + TimbreParam *timbreTemp; + + // 0=Part 1, .. 7=Part 8, 8=Rhythm + unsigned int partNum; + + bool holdpedal; + + unsigned int activePartialCount; + PatchCache patchCache[4]; + PolyList activePolys; + + void setPatch(const PatchParam *patch); + unsigned int midiKeyToKey(unsigned int midiKey); + + bool abortFirstPoly(unsigned int key); + +protected: + Synth *synth; + // Direct pointer into sysex-addressable memory + MemParams::PatchTemp *patchTemp; + char name[8]; // "Part 1".."Part 8", "Rhythm" + char currentInstr[11]; + Bit8u modulation; + Bit8u expression; + Bit32s pitchBend; + bool nrpn; + Bit16u rpn; + Bit16u pitchBenderRange; // (patchTemp->patch.benderRange * 683) at the time of the last MIDI program change or MIDI data entry. + + void backupCacheToPartials(PatchCache cache[4]); + void cacheTimbre(PatchCache cache[4], const TimbreParam *timbre); + void playPoly(const PatchCache cache[4], const MemParams::RhythmTemp *rhythmTemp, unsigned int midiKey, unsigned int key, unsigned int velocity); + void stopNote(unsigned int key); + const char *getName() const; + +public: + Part(Synth *synth, unsigned int usePartNum); + virtual ~Part(); + void reset(); + void setDataEntryMSB(unsigned char midiDataEntryMSB); + void setNRPN(); + void setRPNLSB(unsigned char midiRPNLSB); + void setRPNMSB(unsigned char midiRPNMSB); + void resetAllControllers(); + virtual void noteOn(unsigned int midiKey, unsigned int velocity); + virtual void noteOff(unsigned int midiKey); + void allNotesOff(); + void allSoundOff(); + Bit8u getVolume() const; // Internal volume, 0-100, exposed for use by ExternalInterface + void setVolume(unsigned int midiVolume); + Bit8u getModulation() const; + void setModulation(unsigned int midiModulation); + Bit8u getExpression() const; + void setExpression(unsigned int midiExpression); + virtual void setPan(unsigned int midiPan); + Bit32s getPitchBend() const; + void setBend(unsigned int midiBend); + virtual void setProgram(unsigned int midiProgram); + void setHoldPedal(bool pedalval); + void stopPedalHold(); + void updatePitchBenderRange(); + virtual void refresh(); + virtual void refreshTimbre(unsigned int absTimbreNum); + virtual void setTimbre(TimbreParam *timbre); + virtual unsigned int getAbsTimbreNum() const; + const char *getCurrentInstr() const; + const Poly *getFirstActivePoly() const; + unsigned int getActivePartialCount() const; + unsigned int getActiveNonReleasingPartialCount() const; + Synth *getSynth() const; + + const MemParams::PatchTemp *getPatchTemp() const; + + // This should only be called by Poly + void partialDeactivated(Poly *poly); + + // These are rather specialised, and should probably only be used by PartialManager + bool abortFirstPoly(PolyState polyState); + // Abort the first poly in PolyState_HELD, or if none exists, the first active poly in any state. + bool abortFirstPolyPreferHeld(); + bool abortFirstPoly(); +}; // class Part + +class RhythmPart: public Part { + // Pointer to the area of the MT-32's memory dedicated to rhythm + const MemParams::RhythmTemp *rhythmTemp; + + // This caches the timbres/settings in use by the rhythm part + PatchCache drumCache[85][4]; +public: + RhythmPart(Synth *synth, unsigned int usePartNum); + void refresh(); + void refreshTimbre(unsigned int timbreNum); + void setTimbre(TimbreParam *timbre); + void noteOn(unsigned int key, unsigned int velocity); + void noteOff(unsigned int midiKey); + unsigned int getAbsTimbreNum() const; + void setPan(unsigned int midiPan); + void setProgram(unsigned int patchNum); +}; + +} // namespace MT32Emu + +#endif // #ifndef MT32EMU_PART_H diff --git a/src/SOUND/munt/Partial.cpp b/src/SOUND/munt/Partial.cpp new file mode 100644 index 000000000..72a3af0ab --- /dev/null +++ b/src/SOUND/munt/Partial.cpp @@ -0,0 +1,403 @@ +/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher + * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#include + +#include "internals.h" + +#include "Partial.h" +#include "Part.h" +#include "Poly.h" +#include "Synth.h" +#include "Tables.h" +#include "TVA.h" +#include "TVF.h" +#include "TVP.h" + +namespace MT32Emu { + +static const Bit8u PAN_NUMERATOR_MASTER[] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7}; +static const Bit8u PAN_NUMERATOR_SLAVE[] = {0, 1, 2, 3, 4, 5, 6, 7, 7, 7, 7, 7, 7, 7, 7}; + +// We assume the pan is applied using the same 13-bit multiplier circuit that is also used for ring modulation +// because of the observed sample overflow, so the panSetting values are likely mapped in a similar way via a LUT. +// FIXME: Sample analysis suggests that the use of panSetting is linear, but there are some quirks that still need to be resolved. +static Bit32s getPANFactor(Bit32s panSetting) { + static const Bit32s PAN_FACTORS_COUNT = 15; + static Bit32s PAN_FACTORS[PAN_FACTORS_COUNT]; + static bool firstRun = true; + + if (firstRun) { + firstRun = false; + for (Bit32u i = 1; i < PAN_FACTORS_COUNT; i++) { + PAN_FACTORS[i] = Bit32s(0.5 + i * 8192.0 / double(PAN_FACTORS_COUNT - 1)); + } + } + return PAN_FACTORS[panSetting]; +} + +Partial::Partial(Synth *useSynth, int useDebugPartialNum) : + synth(useSynth), debugPartialNum(useDebugPartialNum), sampleNum(0), + floatMode(useSynth->getSelectedRendererType() == RendererType_FLOAT) { + // Initialisation of tva, tvp and tvf uses 'this' pointer + // and thus should not be in the initializer list to avoid a compiler warning + tva = new TVA(this, &Ramp); + tvp = new TVP(this); + tvf = new TVF(this, &cutoffModifierRamp); + ownerPart = -1; + poly = NULL; + pair = NULL; + switch (synth->getSelectedRendererType()) { + case RendererType_BIT16S: + la32Pair = new LA32IntPartialPair; + break; + case RendererType_FLOAT: + la32Pair = new LA32FloatPartialPair; + break; + default: + la32Pair = NULL; + } +} + +Partial::~Partial() { + delete la32Pair; + delete tva; + delete tvp; + delete tvf; +} + +// Only used for debugging purposes +int Partial::debugGetPartialNum() const { + return debugPartialNum; +} + +// Only used for debugging purposes +Bit32u Partial::debugGetSampleNum() const { + return sampleNum; +} + +int Partial::getOwnerPart() const { + return ownerPart; +} + +bool Partial::isActive() const { + return ownerPart > -1; +} + +const Poly *Partial::getPoly() const { + return poly; +} + +void Partial::activate(int part) { + // This just marks the partial as being assigned to a part + ownerPart = part; +} + +void Partial::deactivate() { + if (!isActive()) { + return; + } + ownerPart = -1; + if (poly != NULL) { + poly->partialDeactivated(this); + } +#if MT32EMU_MONITOR_PARTIALS > 2 + synth->printDebug("[+%lu] [Partial %d] Deactivated", sampleNum, debugPartialNum); + synth->printPartialUsage(sampleNum); +#endif + if (isRingModulatingSlave()) { + pair->la32Pair->deactivate(LA32PartialPair::SLAVE); + } else { + la32Pair->deactivate(LA32PartialPair::MASTER); + if (hasRingModulatingSlave()) { + pair->deactivate(); + pair = NULL; + } + } + if (pair != NULL) { + pair->pair = NULL; + } +} + +void Partial::startPartial(const Part *part, Poly *usePoly, const PatchCache *usePatchCache, const MemParams::RhythmTemp *rhythmTemp, Partial *pairPartial) { + if (usePoly == NULL || usePatchCache == NULL) { + synth->printDebug("[Partial %d] *** Error: Starting partial for owner %d, usePoly=%s, usePatchCache=%s", debugPartialNum, ownerPart, usePoly == NULL ? "*** NULL ***" : "OK", usePatchCache == NULL ? "*** NULL ***" : "OK"); + return; + } + patchCache = usePatchCache; + poly = usePoly; + mixType = patchCache->structureMix; + structurePosition = patchCache->structurePosition; + + Bit8u panSetting = rhythmTemp != NULL ? rhythmTemp->panpot : part->getPatchTemp()->panpot; + if (mixType == 3) { + if (structurePosition == 0) { + panSetting = PAN_NUMERATOR_MASTER[panSetting] << 1; + } else { + panSetting = PAN_NUMERATOR_SLAVE[panSetting] << 1; + } + // Do a normal mix independent of any pair partial. + mixType = 0; + pairPartial = NULL; + } else { + // Mok wanted an option for smoother panning, and we love Mok. +#ifndef INACCURATE_SMOOTH_PAN + // CONFIRMED by Mok: exactly bytes like this (right shifted?) are sent to the LA32. + panSetting &= 0x0E; +#endif + } + + leftPanValue = synth->reversedStereoEnabled ? 14 - panSetting : panSetting; + rightPanValue = 14 - leftPanValue; + + if (!floatMode) { + leftPanValue = getPANFactor(leftPanValue); + rightPanValue = getPANFactor(rightPanValue); + } + + // SEMI-CONFIRMED: From sample analysis: + // Found that timbres with 3 or 4 partials (i.e. one using two partial pairs) are mixed in two different ways. + // Either partial pairs are added or subtracted, it depends on how the partial pairs are allocated. + // It seems that partials are grouped into quarters and if the partial pairs are allocated in different quarters the subtraction happens. + // Though, this matters little for the majority of timbres, it becomes crucial for timbres which contain several partials that sound very close. + // In this case that timbre can sound totally different depending of the way it is mixed up. + // Most easily this effect can be displayed with the help of a special timbre consisting of several identical square wave partials (3 or 4). + // Say, it is 3-partial timbre. Just play any two notes simultaneously and the polys very probably are mixed differently. + // Moreover, the partial allocator retains the last partial assignment it did and all the subsequent notes will sound the same as the last released one. + // The situation is better with 4-partial timbres since then a whole quarter is assigned for each poly. However, if a 3-partial timbre broke the normal + // whole-quarter assignment or after some partials got aborted, even 4-partial timbres can be found sounding differently. + // This behaviour is also confirmed with two more special timbres: one with identical sawtooth partials, and one with PCM wave 02. + // For my personal taste, this behaviour rather enriches the sounding and should be emulated. + // Also, the current partial allocator model probably needs to be refined. + if (debugPartialNum & 8) { + leftPanValue = -leftPanValue; + rightPanValue = -rightPanValue; + } + + if (patchCache->PCMPartial) { + pcmNum = patchCache->pcm; + if (synth->controlROMMap->pcmCount > 128) { + // CM-32L, etc. support two "banks" of PCMs, selectable by waveform type parameter. + if (patchCache->waveform > 1) { + pcmNum += 128; + } + } + pcmWave = &synth->pcmWaves[pcmNum]; + } else { + pcmWave = NULL; + } + + // CONFIRMED: pulseWidthVal calculation is based on information from Mok + pulseWidthVal = (poly->getVelocity() - 64) * (patchCache->srcPartial.wg.pulseWidthVeloSensitivity - 7) + Tables::getInstance().pulseWidth100To255[patchCache->srcPartial.wg.pulseWidth]; + if (pulseWidthVal < 0) { + pulseWidthVal = 0; + } else if (pulseWidthVal > 255) { + pulseWidthVal = 255; + } + + pair = pairPartial; + alreadyOutputed = false; + tva->reset(part, patchCache->partialParam, rhythmTemp); + tvp->reset(part, patchCache->partialParam); + tvf->reset(patchCache->partialParam, tvp->getBasePitch()); + + LA32PartialPair::PairType pairType; + LA32PartialPair *useLA32Pair; + if (isRingModulatingSlave()) { + pairType = LA32PartialPair::SLAVE; + useLA32Pair = pair->la32Pair; + } else { + pairType = LA32PartialPair::MASTER; + la32Pair->init(hasRingModulatingSlave(), mixType == 1); + useLA32Pair = la32Pair; + } + if (isPCM()) { + useLA32Pair->initPCM(pairType, &synth->pcmROMData[pcmWave->addr], pcmWave->len, pcmWave->loop); + } else { + useLA32Pair->initSynth(pairType, (patchCache->waveform & 1) != 0, pulseWidthVal, patchCache->srcPartial.tvf.resonance + 1); + } + if (!hasRingModulatingSlave()) { + la32Pair->deactivate(LA32PartialPair::SLAVE); + } +} + +Bit32u Partial::getAmpValue() { + // SEMI-CONFIRMED: From sample analysis: + // (1) Tested with a single partial playing PCM wave 77 with pitchCoarse 36 and no keyfollow, velocity follow, etc. + // This gives results within +/- 2 at the output (before any DAC bitshifting) + // when sustaining at levels 156 - 255 with no modifiers. + // (2) Tested with a special square wave partial (internal capture ID tva5) at TVA envelope levels 155-255. + // This gives deltas between -1 and 0 compared to the real output. Note that this special partial only produces + // positive amps, so negative still needs to be explored, as well as lower levels. + // + // Also still partially unconfirmed is the behaviour when ramping between levels, as well as the timing. + // TODO: The tests above were performed using the float model, to be refined + Bit32u ampRampVal = 67117056 - ampRamp.nextValue(); + if (ampRamp.checkInterrupt()) { + tva->handleInterrupt(); + } + return ampRampVal; +} + +Bit32u Partial::getCutoffValue() { + if (isPCM()) { + return 0; + } + Bit32u cutoffModifierRampVal = cutoffModifierRamp.nextValue(); + if (cutoffModifierRamp.checkInterrupt()) { + tvf->handleInterrupt(); + } + return (tvf->getBaseCutoff() << 18) + cutoffModifierRampVal; +} + +bool Partial::hasRingModulatingSlave() const { + return pair != NULL && structurePosition == 0 && (mixType == 1 || mixType == 2); +} + +bool Partial::isRingModulatingSlave() const { + return pair != NULL && structurePosition == 1 && (mixType == 1 || mixType == 2); +} + +bool Partial::isPCM() const { + return pcmWave != NULL; +} + +const ControlROMPCMStruct *Partial::getControlROMPCMStruct() const { + if (pcmWave != NULL) { + return pcmWave->controlROMPCMStruct; + } + return NULL; +} + +Synth *Partial::getSynth() const { + return synth; +} + +TVA *Partial::getTVA() const { + return tva; +} + +void Partial::backupCache(const PatchCache &cache) { + if (patchCache == &cache) { + cachebackup = cache; + patchCache = &cachebackup; + } +} + +bool Partial::canProduceOutput() { + if (!isActive() || alreadyOutputed || isRingModulatingSlave()) { + return false; + } + if (poly == NULL) { + synth->printDebug("[Partial %d] *** ERROR: poly is NULL at Partial::produceOutput()!", debugPartialNum); + return false; + } + return true; +} + +template +bool Partial::generateNextSample(LA32PairImpl *la32PairImpl) { + if (!tva->isPlaying() || !la32PairImpl->isActive(LA32PartialPair::MASTER)) { + deactivate(); + return false; + } + la32PairImpl->generateNextSample(LA32PartialPair::MASTER, getAmpValue(), tvp->nextPitch(), getCutoffValue()); + if (hasRingModulatingSlave()) { + la32PairImpl->generateNextSample(LA32PartialPair::SLAVE, pair->getAmpValue(), pair->tvp->nextPitch(), pair->getCutoffValue()); + if (!pair->tva->isPlaying() || !la32PairImpl->isActive(LA32PartialPair::SLAVE)) { + pair->deactivate(); + if (mixType == 2) { + deactivate(); + return false; + } + } + } + return true; +} + +void Partial::produceAndMixSample(IntSample *&leftBuf, IntSample *&rightBuf, LA32IntPartialPair *la32IntPair) { + IntSampleEx sample = la32IntPair->nextOutSample(); + + // FIXME: LA32 may produce distorted sound in case if the absolute value of maximal amplitude of the input exceeds 8191 + // when the panning value is non-zero. Most probably the distortion occurs in the same way it does with ring modulation, + // and it seems to be caused by limited precision of the common multiplication circuit. + // From analysis of this overflow, it is obvious that the right channel output is actually found + // by subtraction of the left channel output from the input. + // Though, it is unknown whether this overflow is exploited somewhere. + + IntSampleEx leftOut = ((sample * leftPanValue) >> 13) + IntSampleEx(*leftBuf); + IntSampleEx rightOut = ((sample * rightPanValue) >> 13) + IntSampleEx(*rightBuf); + *(leftBuf++) = Synth::clipSampleEx(leftOut); + *(rightBuf++) = Synth::clipSampleEx(rightOut); +} + +void Partial::produceAndMixSample(FloatSample *&leftBuf, FloatSample *&rightBuf, LA32FloatPartialPair *la32FloatPair) { + FloatSample sample = la32FloatPair->nextOutSample(); + FloatSample leftOut = (sample * leftPanValue) / 14.0f; + FloatSample rightOut = (sample * rightPanValue) / 14.0f; + *(leftBuf++) += leftOut; + *(rightBuf++) += rightOut; +} + +template +bool Partial::doProduceOutput(Sample *leftBuf, Sample *rightBuf, Bit32u length, LA32PairImpl *la32PairImpl) { + if (!canProduceOutput()) return false; + alreadyOutputed = true; + + for (sampleNum = 0; sampleNum < length; sampleNum++) { + if (!generateNextSample(la32PairImpl)) break; + produceAndMixSample(leftBuf, rightBuf, la32PairImpl); + } + sampleNum = 0; + return true; +} + +bool Partial::produceOutput(IntSample *leftBuf, IntSample *rightBuf, Bit32u length) { + if (floatMode) { + synth->printDebug("Partial: Invalid call to produceOutput()!\n", synth->getSelectedRendererType()); + return false; + } + return doProduceOutput(leftBuf, rightBuf, length, static_cast(la32Pair)); +} + +bool Partial::produceOutput(FloatSample *leftBuf, FloatSample *rightBuf, Bit32u length) { + if (!floatMode) { + synth->printDebug("Partial: Invalid call to produceOutput()!\n", synth->getSelectedRendererType()); + return false; + } + return doProduceOutput(leftBuf, rightBuf, length, static_cast(la32Pair)); +} + +bool Partial::shouldReverb() { + if (!isActive()) { + return false; + } + return patchCache->reverb; +} + +void Partial::startAbort() { + // This is called when the partial manager needs to terminate partials for re-use by a new Poly. + tva->startAbort(); +} + +void Partial::startDecayAll() { + tva->startDecay(); + tvp->startDecay(); + tvf->startDecay(); +} + +} // namespace MT32Emu diff --git a/src/SOUND/munt/Partial.h b/src/SOUND/munt/Partial.h new file mode 100644 index 000000000..bdb65952e --- /dev/null +++ b/src/SOUND/munt/Partial.h @@ -0,0 +1,129 @@ +/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher + * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#ifndef MT32EMU_PARTIAL_H +#define MT32EMU_PARTIAL_H + +#include "globals.h" +#include "internals.h" +#include "Types.h" +#include "Structures.h" +#include "LA32Ramp.h" +#include "LA32WaveGenerator.h" +#include "LA32FloatWaveGenerator.h" + +namespace MT32Emu { + +class Part; +class Poly; +class Synth; +class TVA; +class TVF; +class TVP; +struct ControlROMPCMStruct; + +// A partial represents one of up to four waveform generators currently playing within a poly. +class Partial { +private: + Synth *synth; + const int debugPartialNum; // Only used for debugging + // Number of the sample currently being rendered by produceOutput(), or 0 if no run is in progress + // This is only kept available for debugging purposes. + Bit32u sampleNum; + + // Actually, this is a 4-bit register but we abuse this to emulate inverted mixing. + // Also we double the value to enable INACCURATE_SMOOTH_PAN, with respect to MoK. + Bit32s leftPanValue, rightPanValue; + + int ownerPart; // -1 if unassigned + int mixType; + int structurePosition; // 0 or 1 of a structure pair + + // Only used for PCM partials + int pcmNum; + // FIXME: Give this a better name (e.g. pcmWaveInfo) + PCMWaveEntry *pcmWave; + + // Final pulse width value, with velfollow applied, matching what is sent to the LA32. + // Range: 0-255 + int pulseWidthVal; + + Poly *poly; + Partial *pair; + + TVA *tva; + TVP *tvp; + TVF *tvf; + + LA32Ramp ampRamp; + LA32Ramp cutoffModifierRamp; + + // TODO: This should be owned by PartialPair + LA32PartialPair *la32Pair; + const bool floatMode; + + const PatchCache *patchCache; + PatchCache cachebackup; + + Bit32u getAmpValue(); + Bit32u getCutoffValue(); + + template + bool doProduceOutput(Sample *leftBuf, Sample *rightBuf, Bit32u length, LA32PairImpl *la32PairImpl); + bool canProduceOutput(); + template + bool generateNextSample(LA32PairImpl *la32PairImpl); + void produceAndMixSample(IntSample *&leftBuf, IntSample *&rightBuf, LA32IntPartialPair *la32IntPair); + void produceAndMixSample(FloatSample *&leftBuf, FloatSample *&rightBuf, LA32FloatPartialPair *la32FloatPair); + +public: + bool alreadyOutputed; + + Partial(Synth *synth, int debugPartialNum); + ~Partial(); + + int debugGetPartialNum() const; + Bit32u debugGetSampleNum() const; + + int getOwnerPart() const; + const Poly *getPoly() const; + bool isActive() const; + void activate(int part); + void deactivate(void); + void startPartial(const Part *part, Poly *usePoly, const PatchCache *useCache, const MemParams::RhythmTemp *rhythmTemp, Partial *pairPartial); + void startAbort(); + void startDecayAll(); + bool shouldReverb(); + bool hasRingModulatingSlave() const; + bool isRingModulatingSlave() const; + bool isPCM() const; + const ControlROMPCMStruct *getControlROMPCMStruct() const; + Synth *getSynth() const; + TVA *getTVA() const; + + void backupCache(const PatchCache &cache); + + // Returns true only if data written to buffer + // These functions produce processed stereo samples + // made from combining this single partial with its pair, if it has one. + bool produceOutput(IntSample *leftBuf, IntSample *rightBuf, Bit32u length); + bool produceOutput(FloatSample *leftBuf, FloatSample *rightBuf, Bit32u length); +}; // class Partial + +} // namespace MT32Emu + +#endif // #ifndef MT32EMU_PARTIAL_H diff --git a/src/SOUND/munt/PartialManager.cpp b/src/SOUND/munt/PartialManager.cpp new file mode 100644 index 000000000..6c622a9aa --- /dev/null +++ b/src/SOUND/munt/PartialManager.cpp @@ -0,0 +1,298 @@ +/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher + * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#include +#include + +#include "internals.h" + +#include "PartialManager.h" +#include "Part.h" +#include "Partial.h" +#include "Poly.h" +#include "Synth.h" + +namespace MT32Emu { + +PartialManager::PartialManager(Synth *useSynth, Part **useParts) { + synth = useSynth; + parts = useParts; + partialTable = new Partial *[synth->getPartialCount()]; + freePolys = new Poly *[synth->getPartialCount()]; + firstFreePolyIndex = 0; + for (unsigned int i = 0; i < synth->getPartialCount(); i++) { + partialTable[i] = new Partial(synth, i); + freePolys[i] = new Poly(); + } +} + +PartialManager::~PartialManager(void) { + for (unsigned int i = 0; i < synth->getPartialCount(); i++) { + delete partialTable[i]; + if (freePolys[i] != NULL) delete freePolys[i]; + } + delete[] partialTable; + delete[] freePolys; +} + +void PartialManager::clearAlreadyOutputed() { + for (unsigned int i = 0; i < synth->getPartialCount(); i++) { + partialTable[i]->alreadyOutputed = false; + } +} + +bool PartialManager::shouldReverb(int i) { + return partialTable[i]->shouldReverb(); +} + +bool PartialManager::produceOutput(int i, IntSample *leftBuf, IntSample *rightBuf, Bit32u bufferLength) { + return partialTable[i]->produceOutput(leftBuf, rightBuf, bufferLength); +} + +bool PartialManager::produceOutput(int i, FloatSample *leftBuf, FloatSample *rightBuf, Bit32u bufferLength) { + return partialTable[i]->produceOutput(leftBuf, rightBuf, bufferLength); +} + +void PartialManager::deactivateAll() { + for (unsigned int i = 0; i < synth->getPartialCount(); i++) { + partialTable[i]->deactivate(); + } +} + +unsigned int PartialManager::setReserve(Bit8u *rset) { + unsigned int pr = 0; + for (int x = 0; x <= 8; x++) { + numReservedPartialsForPart[x] = rset[x]; + pr += rset[x]; + } + return pr; +} + +Partial *PartialManager::allocPartial(int partNum) { + Partial *outPartial = NULL; + + // Get the first inactive partial + for (unsigned int partialNum = 0; partialNum < synth->getPartialCount(); partialNum++) { + if (!partialTable[partialNum]->isActive()) { + outPartial = partialTable[partialNum]; + break; + } + } + if (outPartial != NULL) { + outPartial->activate(partNum); + } + return outPartial; +} + +unsigned int PartialManager::getFreePartialCount(void) { + int count = 0; + for (unsigned int i = 0; i < synth->getPartialCount(); i++) { + if (!partialTable[i]->isActive()) { + count++; + } + } + return count; +} + +// This function is solely used to gather data for debug output at the moment. +void PartialManager::getPerPartPartialUsage(unsigned int perPartPartialUsage[9]) { + memset(perPartPartialUsage, 0, 9 * sizeof(unsigned int)); + for (unsigned int i = 0; i < synth->getPartialCount(); i++) { + if (partialTable[i]->isActive()) { + perPartPartialUsage[partialTable[i]->getOwnerPart()]++; + } + } +} + +// Finds the lowest-priority part that is exceeding its reserved partial allocation and has a poly +// in POLY_Releasing, then kills its first releasing poly. +// Parts with higher priority than minPart are not checked. +// Assumes that getFreePartials() has been called to make numReservedPartialsForPart up-to-date. +bool PartialManager::abortFirstReleasingPolyWhereReserveExceeded(int minPart) { + if (minPart == 8) { + // Rhythm is highest priority + minPart = -1; + } + for (int partNum = 7; partNum >= minPart; partNum--) { + int usePartNum = partNum == -1 ? 8 : partNum; + if (parts[usePartNum]->getActivePartialCount() > numReservedPartialsForPart[usePartNum]) { + // This part has exceeded its reserved partial count. + // If it has any releasing polys, kill its first one and we're done. + if (parts[usePartNum]->abortFirstPoly(POLY_Releasing)) { + return true; + } + } + } + return false; +} + +// Finds the lowest-priority part that is exceeding its reserved partial allocation and has a poly, then kills +// its first poly in POLY_Held - or failing that, its first poly in any state. +// Parts with higher priority than minPart are not checked. +// Assumes that getFreePartials() has been called to make numReservedPartialsForPart up-to-date. +bool PartialManager::abortFirstPolyPreferHeldWhereReserveExceeded(int minPart) { + if (minPart == 8) { + // Rhythm is highest priority + minPart = -1; + } + for (int partNum = 7; partNum >= minPart; partNum--) { + int usePartNum = partNum == -1 ? 8 : partNum; + if (parts[usePartNum]->getActivePartialCount() > numReservedPartialsForPart[usePartNum]) { + // This part has exceeded its reserved partial count. + // If it has any polys, kill its first (preferably held) one and we're done. + if (parts[usePartNum]->abortFirstPolyPreferHeld()) { + return true; + } + } + } + return false; +} + +bool PartialManager::freePartials(unsigned int needed, int partNum) { + // CONFIRMED: Barring bugs, this matches the real LAPC-I according to information from Mok. + + // BUG: There's a bug in the LAPC-I implementation: + // When allocating for rhythm part, or when allocating for a part that is using fewer partials than it has reserved, + // held and playing polys on the rhythm part can potentially be aborted before releasing polys on the rhythm part. + // This bug isn't present on MT-32. + // I consider this to be a bug because I think that playing polys should always have priority over held polys, + // and held polys should always have priority over releasing polys. + + // NOTE: This code generally aborts polys in parts (according to certain conditions) in the following order: + // 7, 6, 5, 4, 3, 2, 1, 0, 8 (rhythm) + // (from lowest priority, meaning most likely to have polys aborted, to highest priority, meaning least likely) + + if (needed == 0) { + return true; + } + + // Note that calling getFreePartialCount() also ensures that numReservedPartialsPerPart is up-to-date + if (getFreePartialCount() >= needed) { + return true; + } + + // Note: These #ifdefs are temporary until we have proper "quirk" configuration. + // Also, the MT-32 version isn't properly confirmed yet. +#ifdef MT32EMU_QUIRK_FREE_PARTIALS_MT32 + // On MT-32, we bail out before even killing releasing partials if the allocating part has exceeded its reserve and is configured for priority-to-earlier-polys. + if (parts[partNum]->getActiveNonReleasingPartialCount() + needed > numReservedPartialsForPart[partNum] && (synth->getPart(partNum)->getPatchTemp()->patch.assignMode & 1)) { + return false; + } +#endif + + for (;;) { +#ifdef MT32EMU_QUIRK_FREE_PARTIALS_MT32 + // Abort releasing polys in parts that have exceeded their partial reservation (working backwards from part 7, with rhythm last) + if (!abortFirstReleasingPolyWhereReserveExceeded(-1)) { + break; + } +#else + // Abort releasing polys in non-rhythm parts that have exceeded their partial reservation (working backwards from part 7) + if (!abortFirstReleasingPolyWhereReserveExceeded(0)) { + break; + } +#endif + if (synth->isAbortingPoly() || getFreePartialCount() >= needed) { + return true; + } + } + + if (parts[partNum]->getActiveNonReleasingPartialCount() + needed > numReservedPartialsForPart[partNum]) { + // With the new partials we're freeing for, we would end up using more partials than we have reserved. + if (synth->getPart(partNum)->getPatchTemp()->patch.assignMode & 1) { + // Priority is given to earlier polys, so just give up + return false; + } + // Only abort held polys in the target part and parts that have a lower priority + // (higher part number = lower priority, except for rhythm, which has the highest priority). + for (;;) { + if (!abortFirstPolyPreferHeldWhereReserveExceeded(partNum)) { + break; + } + if (synth->isAbortingPoly() || getFreePartialCount() >= needed) { + return true; + } + } + if (needed > numReservedPartialsForPart[partNum]) { + return false; + } + } else { + // At this point, we're certain that we've reserved enough partials to play our poly. + // Check all parts from lowest to highest priority to see whether they've exceeded their + // reserve, and abort their polys until until we have enough free partials or they're within + // their reserve allocation. + for (;;) { + if (!abortFirstPolyPreferHeldWhereReserveExceeded(-1)) { + break; + } + if (synth->isAbortingPoly() || getFreePartialCount() >= needed) { + return true; + } + } + } + + // Abort polys in the target part until there are enough free partials for the new one + for (;;) { + if (!parts[partNum]->abortFirstPolyPreferHeld()) { + break; + } + if (synth->isAbortingPoly() || getFreePartialCount() >= needed) { + return true; + } + } + + // Aww, not enough partials for you. + return false; +} + +const Partial *PartialManager::getPartial(unsigned int partialNum) const { + if (partialNum > synth->getPartialCount() - 1) { + return NULL; + } + return partialTable[partialNum]; +} + +Poly *PartialManager::assignPolyToPart(Part *part) { + if (firstFreePolyIndex < synth->getPartialCount()) { + Poly *poly = freePolys[firstFreePolyIndex]; + freePolys[firstFreePolyIndex] = NULL; + firstFreePolyIndex++; + poly->setPart(part); + return poly; + } + return NULL; +} + +void PartialManager::polyFreed(Poly *poly) { + if (0 == firstFreePolyIndex) { + synth->printDebug("Cannot return freed poly, currently active polys:\n"); + for (Bit32u partNum = 0; partNum < 9; partNum++) { + const Poly *activePoly = synth->getPart(partNum)->getFirstActivePoly(); + Bit32u polyCount = 0; + while (activePoly != NULL) { + activePoly = activePoly->getNext(); + polyCount++; + } + synth->printDebug("Part: %i, active poly count: %i\n", partNum, polyCount); + } + } + poly->setPart(NULL); + firstFreePolyIndex--; + freePolys[firstFreePolyIndex] = poly; +} + +} // namespace MT32Emu diff --git a/src/SOUND/munt/PartialManager.h b/src/SOUND/munt/PartialManager.h new file mode 100644 index 000000000..46d8eeb98 --- /dev/null +++ b/src/SOUND/munt/PartialManager.h @@ -0,0 +1,64 @@ +/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher + * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#ifndef MT32EMU_PARTIALMANAGER_H +#define MT32EMU_PARTIALMANAGER_H + +#include "globals.h" +#include "internals.h" +#include "Types.h" + +namespace MT32Emu { + +class Part; +class Partial; +class Poly; +class Synth; + +class PartialManager { +private: + Synth *synth; + Part **parts; + Poly **freePolys; + Partial **partialTable; + Bit8u numReservedPartialsForPart[9]; + Bit32u firstFreePolyIndex; + + bool abortFirstReleasingPolyWhereReserveExceeded(int minPart); + bool abortFirstPolyPreferHeldWhereReserveExceeded(int minPart); + +public: + PartialManager(Synth *synth, Part **parts); + ~PartialManager(); + Partial *allocPartial(int partNum); + unsigned int getFreePartialCount(void); + void getPerPartPartialUsage(unsigned int perPartPartialUsage[9]); + bool freePartials(unsigned int needed, int partNum); + unsigned int setReserve(Bit8u *rset); + void deactivateAll(); + bool produceOutput(int i, IntSample *leftBuf, IntSample *rightBuf, Bit32u bufferLength); + bool produceOutput(int i, FloatSample *leftBuf, FloatSample *rightBuf, Bit32u bufferLength); + bool shouldReverb(int i); + void clearAlreadyOutputed(); + const Partial *getPartial(unsigned int partialNum) const; + Poly *assignPolyToPart(Part *part); + void polyFreed(Poly *poly); +}; // class PartialManager + +} // namespace MT32Emu + +#endif // #ifndef MT32EMU_PARTIALMANAGER_H diff --git a/src/SOUND/munt/Poly.cpp b/src/SOUND/munt/Poly.cpp new file mode 100644 index 000000000..44b8d2446 --- /dev/null +++ b/src/SOUND/munt/Poly.cpp @@ -0,0 +1,190 @@ +/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher + * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#include + +#include "internals.h" + +#include "Poly.h" +#include "Part.h" +#include "Partial.h" +#include "Synth.h" + +namespace MT32Emu { + +Poly::Poly() { + part = NULL; + key = 255; + velocity = 255; + sustain = false; + activePartialCount = 0; + for (int i = 0; i < 4; i++) { + partials[i] = NULL; + } + state = POLY_Inactive; + next = NULL; +} + +void Poly::setPart(Part *usePart) { + part = usePart; +} + +void Poly::reset(unsigned int newKey, unsigned int newVelocity, bool newSustain, Partial **newPartials) { + if (isActive()) { + // This should never happen + part->getSynth()->printDebug("Resetting active poly. Active partial count: %i\n", activePartialCount); + for (int i = 0; i < 4; i++) { + if (partials[i] != NULL && partials[i]->isActive()) { + partials[i]->deactivate(); + activePartialCount--; + } + } + state = POLY_Inactive; + } + + key = newKey; + velocity = newVelocity; + sustain = newSustain; + + activePartialCount = 0; + for (int i = 0; i < 4; i++) { + partials[i] = newPartials[i]; + if (newPartials[i] != NULL) { + activePartialCount++; + state = POLY_Playing; + } + } +} + +bool Poly::noteOff(bool pedalHeld) { + // Generally, non-sustaining instruments ignore note off. They die away eventually anyway. + // Key 0 (only used by special cases on rhythm part) reacts to note off even if non-sustaining or pedal held. + if (state == POLY_Inactive || state == POLY_Releasing) { + return false; + } + if (pedalHeld) { + if (state == POLY_Held) { + return false; + } + state = POLY_Held; + } else { + startDecay(); + } + return true; +} + +bool Poly::stopPedalHold() { + if (state != POLY_Held) { + return false; + } + return startDecay(); +} + +bool Poly::startDecay() { + if (state == POLY_Inactive || state == POLY_Releasing) { + return false; + } + state = POLY_Releasing; + + for (int t = 0; t < 4; t++) { + Partial *partial = partials[t]; + if (partial != NULL) { + partial->startDecayAll(); + } + } + return true; +} + +bool Poly::startAbort() { + if (state == POLY_Inactive || part->getSynth()->isAbortingPoly()) { + return false; + } + for (int t = 0; t < 4; t++) { + Partial *partial = partials[t]; + if (partial != NULL) { + partial->startAbort(); + part->getSynth()->abortingPoly = this; + } + } + return true; +} + +void Poly::backupCacheToPartials(PatchCache cache[4]) { + for (int partialNum = 0; partialNum < 4; partialNum++) { + Partial *partial = partials[partialNum]; + if (partial != NULL) { + partial->backupCache(cache[partialNum]); + } + } +} + +/** + * Returns the internal key identifier. + * For non-rhythm, this is within the range 12 to 108. + * For rhythm on MT-32, this is 0 or 1 (special cases) or within the range 24 to 87. + * For rhythm on devices with extended PCM sounds (e.g. CM-32L), this is 0, 1 or 24 to 108 + */ +unsigned int Poly::getKey() const { + return key; +} + +unsigned int Poly::getVelocity() const { + return velocity; +} + +bool Poly::canSustain() const { + return sustain; +} + +PolyState Poly::getState() const { + return state; +} + +unsigned int Poly::getActivePartialCount() const { + return activePartialCount; +} + +bool Poly::isActive() const { + return state != POLY_Inactive; +} + +// This is called by Partial to inform the poly that the Partial has deactivated +void Poly::partialDeactivated(Partial *partial) { + for (int i = 0; i < 4; i++) { + if (partials[i] == partial) { + partials[i] = NULL; + activePartialCount--; + } + } + if (activePartialCount == 0) { + state = POLY_Inactive; + if (part->getSynth()->abortingPoly == this) { + part->getSynth()->abortingPoly = NULL; + } + } + part->partialDeactivated(this); +} + +Poly *Poly::getNext() const { + return next; +} + +void Poly::setNext(Poly *poly) { + next = poly; +} + +} // namespace MT32Emu diff --git a/src/SOUND/munt/Poly.h b/src/SOUND/munt/Poly.h new file mode 100644 index 000000000..b2d4eceaf --- /dev/null +++ b/src/SOUND/munt/Poly.h @@ -0,0 +1,70 @@ +/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher + * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#ifndef MT32EMU_POLY_H +#define MT32EMU_POLY_H + +#include "globals.h" +#include "internals.h" + +namespace MT32Emu { + +class Part; +class Partial; +struct PatchCache; + +class Poly { +private: + Part *part; + unsigned int key; + unsigned int velocity; + unsigned int activePartialCount; + bool sustain; + + PolyState state; + + Partial *partials[4]; + + Poly *next; + +public: + Poly(); + void setPart(Part *usePart); + void reset(unsigned int key, unsigned int velocity, bool sustain, Partial **partials); + bool noteOff(bool pedalHeld); + bool stopPedalHold(); + bool startDecay(); + bool startAbort(); + + void backupCacheToPartials(PatchCache cache[4]); + + unsigned int getKey() const; + unsigned int getVelocity() const; + bool canSustain() const; + PolyState getState() const; + unsigned int getActivePartialCount() const; + bool isActive() const; + + void partialDeactivated(Partial *partial); + + Poly *getNext() const; + void setNext(Poly *poly); +}; // class Poly + +} // namespace MT32Emu + +#endif // #ifndef MT32EMU_POLY_H diff --git a/src/SOUND/munt/ROMInfo.cpp b/src/SOUND/munt/ROMInfo.cpp new file mode 100644 index 000000000..3eef26adf --- /dev/null +++ b/src/SOUND/munt/ROMInfo.cpp @@ -0,0 +1,117 @@ +/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher + * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#include + +#include "internals.h" + +#include "ROMInfo.h" + +namespace MT32Emu { + +static const ROMInfo *getKnownROMInfoFromList(Bit32u index) { + // Known ROMs + static const ROMInfo CTRL_MT32_V1_04 = {65536, "5a5cb5a77d7d55ee69657c2f870416daed52dea7", ROMInfo::Control, "ctrl_mt32_1_04", "MT-32 Control v1.04", ROMInfo::Full, NULL}; + static const ROMInfo CTRL_MT32_V1_05 = {65536, "e17a3a6d265bf1fa150312061134293d2b58288c", ROMInfo::Control, "ctrl_mt32_1_05", "MT-32 Control v1.05", ROMInfo::Full, NULL}; + static const ROMInfo CTRL_MT32_V1_06 = {65536, "a553481f4e2794c10cfe597fef154eef0d8257de", ROMInfo::Control, "ctrl_mt32_1_06", "MT-32 Control v1.06", ROMInfo::Full, NULL}; + static const ROMInfo CTRL_MT32_V1_07 = {65536, "b083518fffb7f66b03c23b7eb4f868e62dc5a987", ROMInfo::Control, "ctrl_mt32_1_07", "MT-32 Control v1.07", ROMInfo::Full, NULL}; + static const ROMInfo CTRL_MT32_BLUER = {65536, "7b8c2a5ddb42fd0732e2f22b3340dcf5360edf92", ROMInfo::Control, "ctrl_mt32_bluer", "MT-32 Control BlueRidge", ROMInfo::Full, NULL}; + + static const ROMInfo CTRL_CM32L_V1_00 = {65536, "73683d585cd6948cc19547942ca0e14a0319456d", ROMInfo::Control, "ctrl_cm32l_1_00", "CM-32L/LAPC-I Control v1.00", ROMInfo::Full, NULL}; + static const ROMInfo CTRL_CM32L_V1_02 = {65536, "a439fbb390da38cada95a7cbb1d6ca199cd66ef8", ROMInfo::Control, "ctrl_cm32l_1_02", "CM-32L/LAPC-I Control v1.02", ROMInfo::Full, NULL}; + + static const ROMInfo PCM_MT32 = {524288, "f6b1eebc4b2d200ec6d3d21d51325d5b48c60252", ROMInfo::PCM, "pcm_mt32", "MT-32 PCM ROM", ROMInfo::Full, NULL}; + static const ROMInfo PCM_CM32L = {1048576, "289cc298ad532b702461bfc738009d9ebe8025ea", ROMInfo::PCM, "pcm_cm32l", "CM-32L/CM-64/LAPC-I PCM ROM", ROMInfo::Full, NULL}; + + static const ROMInfo * const ROM_INFOS[] = { + &CTRL_MT32_V1_04, + &CTRL_MT32_V1_05, + &CTRL_MT32_V1_06, + &CTRL_MT32_V1_07, + &CTRL_MT32_BLUER, + &CTRL_CM32L_V1_00, + &CTRL_CM32L_V1_02, + &PCM_MT32, + &PCM_CM32L, + NULL}; + + return ROM_INFOS[index]; +} + +const ROMInfo* ROMInfo::getROMInfo(File *file) { + size_t fileSize = file->getSize(); + for (Bit32u i = 0; getKnownROMInfoFromList(i) != NULL; i++) { + const ROMInfo *romInfo = getKnownROMInfoFromList(i); + if (fileSize == romInfo->fileSize && !strcmp(file->getSHA1(), romInfo->sha1Digest)) { + return romInfo; + } + } + return NULL; +} + +void ROMInfo::freeROMInfo(const ROMInfo *romInfo) { + (void) romInfo; +} + +static Bit32u getROMCount() { + Bit32u count; + for(count = 0; getKnownROMInfoFromList(count) != NULL; count++) { + } + return count; +} + +const ROMInfo** ROMInfo::getROMInfoList(Bit32u types, Bit32u pairTypes) { + const ROMInfo **romInfoList = new const ROMInfo*[getROMCount() + 1]; + const ROMInfo **currentROMInList = romInfoList; + for (Bit32u i = 0; getKnownROMInfoFromList(i) != NULL; i++) { + const ROMInfo *romInfo = getKnownROMInfoFromList(i); + if ((types & (1 << romInfo->type)) && (pairTypes & (1 << romInfo->pairType))) { + *currentROMInList++ = romInfo; + } + } + *currentROMInList = NULL; + return romInfoList; +} + +void ROMInfo::freeROMInfoList(const ROMInfo **romInfoList) { + delete[] romInfoList; +} + +ROMImage::ROMImage(File *useFile) : file(useFile), romInfo(ROMInfo::getROMInfo(file)) +{} + +ROMImage::~ROMImage() { + ROMInfo::freeROMInfo(romInfo); +} + +const ROMImage* ROMImage::makeROMImage(File *file) { + return new ROMImage(file); +} + +void ROMImage::freeROMImage(const ROMImage *romImage) { + delete romImage; +} + +File* ROMImage::getFile() const { + return file; +} + +const ROMInfo* ROMImage::getROMInfo() const { + return romInfo; +} + +} // namespace MT32Emu diff --git a/src/SOUND/munt/ROMInfo.h b/src/SOUND/munt/ROMInfo.h new file mode 100644 index 000000000..cd4a1c5ac --- /dev/null +++ b/src/SOUND/munt/ROMInfo.h @@ -0,0 +1,80 @@ +/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher + * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#ifndef MT32EMU_ROMINFO_H +#define MT32EMU_ROMINFO_H + +#include + +#include "globals.h" +#include "File.h" + +namespace MT32Emu { + +// Defines vital info about ROM file to be used by synth and applications + +struct ROMInfo { +public: + size_t fileSize; + const File::SHA1Digest &sha1Digest; + enum Type {PCM, Control, Reverb} type; + const char *shortName; + const char *description; + enum PairType {Full, FirstHalf, SecondHalf, Mux0, Mux1} pairType; + ROMInfo *pairROMInfo; + + // Returns a ROMInfo struct by inspecting the size and the SHA1 hash + MT32EMU_EXPORT static const ROMInfo* getROMInfo(File *file); + + // Currently no-op + MT32EMU_EXPORT static void freeROMInfo(const ROMInfo *romInfo); + + // Allows retrieving a NULL-terminated list of ROMInfos for a range of types and pairTypes + // (specified by bitmasks) + // Useful for GUI/console app to output information on what ROMs it supports + MT32EMU_EXPORT static const ROMInfo** getROMInfoList(Bit32u types, Bit32u pairTypes); + + // Frees the list of ROMInfos given + MT32EMU_EXPORT static void freeROMInfoList(const ROMInfo **romInfos); +}; + +// Synth::open() is to require a full control ROMImage and a full PCM ROMImage to work + +class ROMImage { +private: + File * const file; + const ROMInfo * const romInfo; + + ROMImage(File *file); + ~ROMImage(); + +public: + // Creates a ROMImage object given a ROMInfo and a File. Keeps a reference + // to the File and ROMInfo given, which must be freed separately by the user + // after the ROMImage is freed + MT32EMU_EXPORT static const ROMImage* makeROMImage(File *file); + + // Must only be done after all Synths using the ROMImage are deleted + MT32EMU_EXPORT static void freeROMImage(const ROMImage *romImage); + + MT32EMU_EXPORT File *getFile() const; + MT32EMU_EXPORT const ROMInfo *getROMInfo() const; +}; + +} // namespace MT32Emu + +#endif // #ifndef MT32EMU_ROMINFO_H diff --git a/src/SOUND/munt/SampleRateConverter.cpp b/src/SOUND/munt/SampleRateConverter.cpp new file mode 100644 index 000000000..2d7866ba6 --- /dev/null +++ b/src/SOUND/munt/SampleRateConverter.cpp @@ -0,0 +1,110 @@ +/* Copyright (C) 2015-2017 Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#include "SampleRateConverter.h" + +#if MT32EMU_WITH_LIBSOXR_RESAMPLER +#include "srchelper/SoxrAdapter.h" +#elif MT32EMU_WITH_LIBSAMPLERATE_RESAMPLER +#include "srchelper/SamplerateAdapter.h" +#else +#include "srchelper/InternalResampler.h" +#endif + +#include "Synth.h" + +using namespace MT32Emu; + +static inline void *createDelegate(Synth &synth, double targetSampleRate, SamplerateConversionQuality quality) { +#if MT32EMU_WITH_LIBSOXR_RESAMPLER + return new SoxrAdapter(synth, targetSampleRate, quality); +#elif MT32EMU_WITH_LIBSAMPLERATE_RESAMPLER + return new SamplerateAdapter(synth, targetSampleRate, quality); +#else + return new InternalResampler(synth, targetSampleRate, quality); +#endif +} + +AnalogOutputMode SampleRateConverter::getBestAnalogOutputMode(double targetSampleRate) { + if (Synth::getStereoOutputSampleRate(AnalogOutputMode_ACCURATE) < targetSampleRate) { + return AnalogOutputMode_OVERSAMPLED; + } else if (Synth::getStereoOutputSampleRate(AnalogOutputMode_COARSE) < targetSampleRate) { + return AnalogOutputMode_ACCURATE; + } + return AnalogOutputMode_COARSE; +} + +SampleRateConverter::SampleRateConverter(Synth &useSynth, double targetSampleRate, SamplerateConversionQuality useQuality) : + synthInternalToTargetSampleRateRatio(SAMPLE_RATE / targetSampleRate), + useSynthDelegate(useSynth.getStereoOutputSampleRate() == targetSampleRate), + srcDelegate(useSynthDelegate ? &useSynth : createDelegate(useSynth, targetSampleRate, useQuality)) +{} + +SampleRateConverter::~SampleRateConverter() { + if (!useSynthDelegate) { +#if MT32EMU_WITH_LIBSOXR_RESAMPLER + delete static_cast(srcDelegate); +#elif MT32EMU_WITH_LIBSAMPLERATE_RESAMPLER + delete static_cast(srcDelegate); +#else + delete static_cast(srcDelegate); +#endif + } +} + +void SampleRateConverter::getOutputSamples(float *buffer, unsigned int length) { + if (useSynthDelegate) { + static_cast(srcDelegate)->render(buffer, length); + return; + } + +#if MT32EMU_WITH_LIBSOXR_RESAMPLER + static_cast(srcDelegate)->getOutputSamples(buffer, length); +#elif MT32EMU_WITH_LIBSAMPLERATE_RESAMPLER + static_cast(srcDelegate)->getOutputSamples(buffer, length); +#else + static_cast(srcDelegate)->getOutputSamples(buffer, length); +#endif +} + +void SampleRateConverter::getOutputSamples(Bit16s *outBuffer, unsigned int length) { + static const unsigned int CHANNEL_COUNT = 2; + + if (useSynthDelegate) { + static_cast(srcDelegate)->render(outBuffer, length); + return; + } + + float floatBuffer[CHANNEL_COUNT * MAX_SAMPLES_PER_RUN]; + while (length > 0) { + const unsigned int size = MAX_SAMPLES_PER_RUN < length ? MAX_SAMPLES_PER_RUN : length; + getOutputSamples(floatBuffer, size); + float *outs = floatBuffer; + float *ends = floatBuffer + CHANNEL_COUNT * size; + while (outs < ends) { + *(outBuffer++) = Synth::convertSample(*(outs++)); + } + length -= size; + } +} + +double SampleRateConverter::convertOutputToSynthTimestamp(double outputTimestamp) const { + return outputTimestamp * synthInternalToTargetSampleRateRatio; +} + +double SampleRateConverter::convertSynthToOutputTimestamp(double synthTimestamp) const { + return synthTimestamp / synthInternalToTargetSampleRateRatio; +} diff --git a/src/SOUND/munt/SampleRateConverter.h b/src/SOUND/munt/SampleRateConverter.h new file mode 100644 index 000000000..437f9b29f --- /dev/null +++ b/src/SOUND/munt/SampleRateConverter.h @@ -0,0 +1,71 @@ +/* Copyright (C) 2015-2017 Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#ifndef MT32EMU_SAMPLE_RATE_CONVERTER_H +#define MT32EMU_SAMPLE_RATE_CONVERTER_H + +#include "globals.h" +#include "Types.h" +#include "Enumerations.h" + +namespace MT32Emu { + +class Synth; + +/* SampleRateConverter class allows to convert the synthesiser output to any desired sample rate. + * It processes the completely mixed stereo output signal as it passes the analogue circuit emulation, + * so emulating the synthesiser output signal passing further through an ADC. + * Several conversion quality options are provided which allow to trade-off the conversion speed vs. the passband width. + * All the options except FASTEST guarantee full suppression of the aliasing noise in terms of the 16-bit integer samples. + */ +class MT32EMU_EXPORT SampleRateConverter { +public: + // Returns the value of AnalogOutputMode for which the output signal may retain its full frequency spectrum + // at the sample rate specified by the targetSampleRate argument. + static AnalogOutputMode getBestAnalogOutputMode(double targetSampleRate); + + // Creates a SampleRateConverter instance that converts output signal from the synth to the given sample rate + // with the specified conversion quality. + SampleRateConverter(Synth &synth, double targetSampleRate, SamplerateConversionQuality quality); + ~SampleRateConverter(); + + // Fills the provided output buffer with the results of the sample rate conversion. + // The input samples are automatically retrieved from the synth as necessary. + void getOutputSamples(MT32Emu::Bit16s *buffer, unsigned int length); + + // Fills the provided output buffer with the results of the sample rate conversion. + // The input samples are automatically retrieved from the synth as necessary. + void getOutputSamples(float *buffer, unsigned int length); + + // Returns the number of samples produced at the internal synth sample rate (32000 Hz) + // that correspond to the number of samples at the target sample rate. + // Intended to facilitate audio time synchronisation. + double convertOutputToSynthTimestamp(double outputTimestamp) const; + + // Returns the number of samples produced at the target sample rate + // that correspond to the number of samples at the internal synth sample rate (32000 Hz). + // Intended to facilitate audio time synchronisation. + double convertSynthToOutputTimestamp(double synthTimestamp) const; + +private: + const double synthInternalToTargetSampleRateRatio; + const bool useSynthDelegate; + void * const srcDelegate; +}; // class SampleRateConverter + +} // namespace MT32Emu + +#endif // MT32EMU_SAMPLE_RATE_CONVERTER_H diff --git a/src/SOUND/munt/Structures.h b/src/SOUND/munt/Structures.h new file mode 100644 index 000000000..d3abf4ee7 --- /dev/null +++ b/src/SOUND/munt/Structures.h @@ -0,0 +1,259 @@ +/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher + * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#ifndef MT32EMU_STRUCTURES_H +#define MT32EMU_STRUCTURES_H + +#include "globals.h" +#include "Types.h" + +namespace MT32Emu { + +// MT32EMU_MEMADDR() converts from sysex-padded, MT32EMU_SYSEXMEMADDR converts to it +// Roland provides documentation using the sysex-padded addresses, so we tend to use that in code and output +#define MT32EMU_MEMADDR(x) ((((x) & 0x7f0000) >> 2) | (((x) & 0x7f00) >> 1) | ((x) & 0x7f)) +#define MT32EMU_SYSEXMEMADDR(x) ((((x) & 0x1FC000) << 2) | (((x) & 0x3F80) << 1) | ((x) & 0x7f)) + +#ifdef _MSC_VER +#define MT32EMU_ALIGN_PACKED __declspec(align(1)) +#else +#define MT32EMU_ALIGN_PACKED __attribute__((packed)) +#endif + +// The following structures represent the MT-32's memory +// Since sysex allows this memory to be written to in blocks of bytes, +// we keep this packed so that we can copy data into the various +// banks directly +#if defined(_MSC_VER) || defined(__MINGW32__) +#pragma pack(push, 1) +#else +#pragma pack(1) +#endif + +struct TimbreParam { + struct CommonParam { + char name[10]; + Bit8u partialStructure12; // 1 & 2 0-12 (1-13) + Bit8u partialStructure34; // 3 & 4 0-12 (1-13) + Bit8u partialMute; // 0-15 (0000-1111) + Bit8u noSustain; // ENV MODE 0-1 (Normal, No sustain) + } MT32EMU_ALIGN_PACKED common; + + struct PartialParam { + struct WGParam { + Bit8u pitchCoarse; // 0-96 (C1,C#1-C9) + Bit8u pitchFine; // 0-100 (-50 to +50 (cents - confirmed by Mok)) + Bit8u pitchKeyfollow; // 0-16 (-1, -1/2, -1/4, 0, 1/8, 1/4, 3/8, 1/2, 5/8, 3/4, 7/8, 1, 5/4, 3/2, 2, s1, s2) + Bit8u pitchBenderEnabled; // 0-1 (OFF, ON) + Bit8u waveform; // MT-32: 0-1 (SQU/SAW); LAPC-I: WG WAVEFORM/PCM BANK 0 - 3 (SQU/1, SAW/1, SQU/2, SAW/2) + Bit8u pcmWave; // 0-127 (1-128) + Bit8u pulseWidth; // 0-100 + Bit8u pulseWidthVeloSensitivity; // 0-14 (-7 - +7) + } MT32EMU_ALIGN_PACKED wg; + + struct PitchEnvParam { + Bit8u depth; // 0-10 + Bit8u veloSensitivity; // 0-100 + Bit8u timeKeyfollow; // 0-4 + Bit8u time[4]; // 0-100 + Bit8u level[5]; // 0-100 (-50 - +50) // [3]: SUSTAIN LEVEL, [4]: END LEVEL + } MT32EMU_ALIGN_PACKED pitchEnv; + + struct PitchLFOParam { + Bit8u rate; // 0-100 + Bit8u depth; // 0-100 + Bit8u modSensitivity; // 0-100 + } MT32EMU_ALIGN_PACKED pitchLFO; + + struct TVFParam { + Bit8u cutoff; // 0-100 + Bit8u resonance; // 0-30 + Bit8u keyfollow; // -1, -1/2, -1/4, 0, 1/8, 1/4, 3/8, 1/2, 5/8, 3/4, 7/8, 1, 5/4, 3/2, 2 + Bit8u biasPoint; // 0-127 (<1A-<7C >1A-7C) + Bit8u biasLevel; // 0-14 (-7 - +7) + Bit8u envDepth; // 0-100 + Bit8u envVeloSensitivity; // 0-100 + Bit8u envDepthKeyfollow; // DEPTH KEY FOLL0W 0-4 + Bit8u envTimeKeyfollow; // TIME KEY FOLLOW 0-4 + Bit8u envTime[5]; // 0-100 + Bit8u envLevel[4]; // 0-100 // [3]: SUSTAIN LEVEL + } MT32EMU_ALIGN_PACKED tvf; + + struct TVAParam { + Bit8u level; // 0-100 + Bit8u veloSensitivity; // 0-100 + Bit8u biasPoint1; // 0-127 (<1A-<7C >1A-7C) + Bit8u biasLevel1; // 0-12 (-12 - 0) + Bit8u biasPoint2; // 0-127 (<1A-<7C >1A-7C) + Bit8u biasLevel2; // 0-12 (-12 - 0) + Bit8u envTimeKeyfollow; // TIME KEY FOLLOW 0-4 + Bit8u envTimeVeloSensitivity; // VELOS KEY FOLL0W 0-4 + Bit8u envTime[5]; // 0-100 + Bit8u envLevel[4]; // 0-100 // [3]: SUSTAIN LEVEL + } MT32EMU_ALIGN_PACKED tva; + } MT32EMU_ALIGN_PACKED partial[4]; // struct PartialParam +} MT32EMU_ALIGN_PACKED; // struct TimbreParam + +struct PatchParam { + Bit8u timbreGroup; // TIMBRE GROUP 0-3 (group A, group B, Memory, Rhythm) + Bit8u timbreNum; // TIMBRE NUMBER 0-63 + Bit8u keyShift; // KEY SHIFT 0-48 (-24 - +24 semitones) + Bit8u fineTune; // FINE TUNE 0-100 (-50 - +50 cents) + Bit8u benderRange; // BENDER RANGE 0-24 + Bit8u assignMode; // ASSIGN MODE 0-3 (POLY1, POLY2, POLY3, POLY4) + Bit8u reverbSwitch; // REVERB SWITCH 0-1 (OFF,ON) + Bit8u dummy; // (DUMMY) +} MT32EMU_ALIGN_PACKED; + +const unsigned int SYSTEM_MASTER_TUNE_OFF = 0; +const unsigned int SYSTEM_REVERB_MODE_OFF = 1; +const unsigned int SYSTEM_REVERB_TIME_OFF = 2; +const unsigned int SYSTEM_REVERB_LEVEL_OFF = 3; +const unsigned int SYSTEM_RESERVE_SETTINGS_START_OFF = 4; +const unsigned int SYSTEM_RESERVE_SETTINGS_END_OFF = 12; +const unsigned int SYSTEM_CHAN_ASSIGN_START_OFF = 13; +const unsigned int SYSTEM_CHAN_ASSIGN_END_OFF = 21; +const unsigned int SYSTEM_MASTER_VOL_OFF = 22; + +struct MemParams { + // NOTE: The MT-32 documentation only specifies PatchTemp areas for parts 1-8. + // The LAPC-I documentation specified an additional area for rhythm at the end, + // where all parameters but fine tune, assign mode and output level are ignored + struct PatchTemp { + PatchParam patch; + Bit8u outputLevel; // OUTPUT LEVEL 0-100 + Bit8u panpot; // PANPOT 0-14 (R-L) + Bit8u dummyv[6]; + } MT32EMU_ALIGN_PACKED patchTemp[9]; + + struct RhythmTemp { + Bit8u timbre; // TIMBRE 0-94 (M1-M64,R1-30,OFF); LAPC-I: 0-127 (M01-M64,R01-R63) + Bit8u outputLevel; // OUTPUT LEVEL 0-100 + Bit8u panpot; // PANPOT 0-14 (R-L) + Bit8u reverbSwitch; // REVERB SWITCH 0-1 (OFF,ON) + } MT32EMU_ALIGN_PACKED rhythmTemp[85]; + + TimbreParam timbreTemp[8]; + + PatchParam patches[128]; + + // NOTE: There are only 30 timbres in the "rhythm" bank for MT-32; the additional 34 are for LAPC-I and above + struct PaddedTimbre { + TimbreParam timbre; + Bit8u padding[10]; + } MT32EMU_ALIGN_PACKED timbres[64 + 64 + 64 + 64]; // Group A, Group B, Memory, Rhythm + + struct System { + Bit8u masterTune; // MASTER TUNE 0-127 432.1-457.6Hz + Bit8u reverbMode; // REVERB MODE 0-3 (room, hall, plate, tap delay) + Bit8u reverbTime; // REVERB TIME 0-7 (1-8) + Bit8u reverbLevel; // REVERB LEVEL 0-7 (1-8) + Bit8u reserveSettings[9]; // PARTIAL RESERVE (PART 1) 0-32 + Bit8u chanAssign[9]; // MIDI CHANNEL (PART1) 0-16 (1-16,OFF) + Bit8u masterVol; // MASTER VOLUME 0-100 + } MT32EMU_ALIGN_PACKED system; +}; // struct MemParams + +struct SoundGroup { + Bit8u timbreNumberTableAddrLow; + Bit8u timbreNumberTableAddrHigh; + Bit8u displayPosition; + Bit8u name[9]; + Bit8u timbreCount; + Bit8u pad; +} MT32EMU_ALIGN_PACKED; + +#if defined(_MSC_VER) || defined(__MINGW32__) +#pragma pack(pop) +#else +#pragma pack() +#endif + +struct ControlROMFeatureSet { + unsigned int quirkPitchEnvelopeOverflow : 1; + + // Features below don't actually depend on control ROM version, which is used to identify hardware model + unsigned int defaultReverbMT32Compatible : 1; + unsigned int oldMT32AnalogLPF : 1; +}; + +struct ControlROMMap { + const char *shortName; + const ControlROMFeatureSet &featureSet; + Bit16u pcmTable; // 4 * pcmCount bytes + Bit16u pcmCount; + Bit16u timbreAMap; // 128 bytes + Bit16u timbreAOffset; + bool timbreACompressed; + Bit16u timbreBMap; // 128 bytes + Bit16u timbreBOffset; + bool timbreBCompressed; + Bit16u timbreRMap; // 2 * timbreRCount bytes + Bit16u timbreRCount; + Bit16u rhythmSettings; // 4 * rhythmSettingsCount bytes + Bit16u rhythmSettingsCount; + Bit16u reserveSettings; // 9 bytes + Bit16u panSettings; // 8 bytes + Bit16u programSettings; // 8 bytes + Bit16u rhythmMaxTable; // 4 bytes + Bit16u patchMaxTable; // 16 bytes + Bit16u systemMaxTable; // 23 bytes + Bit16u timbreMaxTable; // 72 bytes + Bit16u soundGroupsTable; // 14 bytes each entry + Bit16u soundGroupsCount; +}; + +struct ControlROMPCMStruct { + Bit8u pos; + Bit8u len; + Bit8u pitchLSB; + Bit8u pitchMSB; +}; + +struct PCMWaveEntry { + Bit32u addr; + Bit32u len; + bool loop; + ControlROMPCMStruct *controlROMPCMStruct; +}; + +// This is basically a per-partial, pre-processed combination of timbre and patch/rhythm settings +struct PatchCache { + bool playPartial; + bool PCMPartial; + int pcm; + Bit8u waveform; + + Bit32u structureMix; + int structurePosition; + int structurePair; + + // The following fields are actually common to all partials in the timbre + bool dirty; + Bit32u partialCount; + bool sustain; + bool reverb; + + TimbreParam::PartialParam srcPartial; + + // The following directly points into live sysex-addressable memory + const TimbreParam::PartialParam *partialParam; +}; + +} // namespace MT32Emu + +#endif // #ifndef MT32EMU_STRUCTURES_H diff --git a/src/SOUND/munt/Synth.cpp b/src/SOUND/munt/Synth.cpp new file mode 100644 index 000000000..e8464fc90 --- /dev/null +++ b/src/SOUND/munt/Synth.cpp @@ -0,0 +1,2286 @@ +/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher + * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#include + +#include "internals.h" + +#include "Synth.h" +#include "Analog.h" +#include "BReverbModel.h" +#include "File.h" +#include "MemoryRegion.h" +#include "MidiEventQueue.h" +#include "Part.h" +#include "Partial.h" +#include "PartialManager.h" +#include "Poly.h" +#include "ROMInfo.h" +#include "TVA.h" + +namespace MT32Emu { + +// MIDI interface data transfer rate in samples. Used to simulate the transfer delay. +static const double MIDI_DATA_TRANSFER_RATE = double(SAMPLE_RATE) / 31250.0 * 8.0; + +// FIXME: there should be more specific feature sets for various MT-32 control ROM versions +static const ControlROMFeatureSet OLD_MT32_COMPATIBLE = { true, true, true }; +static const ControlROMFeatureSet CM32L_COMPATIBLE = { false, false, false }; + +static const ControlROMMap ControlROMMaps[7] = { + // ID Features PCMmap PCMc tmbrA tmbrAO, tmbrAC tmbrB tmbrBO tmbrBC tmbrR trC rhythm rhyC rsrv panpot prog rhyMax patMax sysMax timMax sndGrp sGC + { "ctrl_mt32_1_04", OLD_MT32_COMPATIBLE, 0x3000, 128, 0x8000, 0x0000, false, 0xC000, 0x4000, false, 0x3200, 30, 0x73A6, 85, 0x57C7, 0x57E2, 0x57D0, 0x5252, 0x525E, 0x526E, 0x520A, 0x7064, 19 }, + { "ctrl_mt32_1_05", OLD_MT32_COMPATIBLE, 0x3000, 128, 0x8000, 0x0000, false, 0xC000, 0x4000, false, 0x3200, 30, 0x7414, 85, 0x57C7, 0x57E2, 0x57D0, 0x5252, 0x525E, 0x526E, 0x520A, 0x70CA, 19 }, + { "ctrl_mt32_1_06", OLD_MT32_COMPATIBLE, 0x3000, 128, 0x8000, 0x0000, false, 0xC000, 0x4000, false, 0x3200, 30, 0x7414, 85, 0x57D9, 0x57F4, 0x57E2, 0x5264, 0x5270, 0x5280, 0x521C, 0x70CA, 19 }, + { "ctrl_mt32_1_07", OLD_MT32_COMPATIBLE, 0x3000, 128, 0x8000, 0x0000, false, 0xC000, 0x4000, false, 0x3200, 30, 0x73fe, 85, 0x57B1, 0x57CC, 0x57BA, 0x523C, 0x5248, 0x5258, 0x51F4, 0x70B0, 19 }, // MT-32 revision 1 + {"ctrl_mt32_bluer", OLD_MT32_COMPATIBLE, 0x3000, 128, 0x8000, 0x0000, false, 0xC000, 0x4000, false, 0x3200, 30, 0x741C, 85, 0x57E5, 0x5800, 0x57EE, 0x5270, 0x527C, 0x528C, 0x5228, 0x70CE, 19 }, // MT-32 Blue Ridge mod + {"ctrl_cm32l_1_00", CM32L_COMPATIBLE, 0x8100, 256, 0x8000, 0x8000, true, 0x8080, 0x8000, true, 0x8500, 64, 0x8580, 85, 0x4F65, 0x4F80, 0x4F6E, 0x48A1, 0x48A5, 0x48BE, 0x48D5, 0x5A6C, 19 }, + {"ctrl_cm32l_1_02", CM32L_COMPATIBLE, 0x8100, 256, 0x8000, 0x8000, true, 0x8080, 0x8000, true, 0x8500, 64, 0x8580, 85, 0x4F93, 0x4FAE, 0x4F9C, 0x48CB, 0x48CF, 0x48E8, 0x48FF, 0x5A96, 19 } // CM-32L + // (Note that all but CM-32L ROM actually have 86 entries for rhythmTemp) +}; + +static const PartialState PARTIAL_PHASE_TO_STATE[8] = { + PartialState_ATTACK, PartialState_ATTACK, PartialState_ATTACK, PartialState_ATTACK, + PartialState_SUSTAIN, PartialState_SUSTAIN, PartialState_RELEASE, PartialState_INACTIVE +}; + +static inline PartialState getPartialState(PartialManager *partialManager, unsigned int partialNum) { + const Partial *partial = partialManager->getPartial(partialNum); + return partial->isActive() ? PARTIAL_PHASE_TO_STATE[partial->getTVA()->getPhase()] : PartialState_INACTIVE; +} + +template +static inline void convertSampleFormat(const I *inBuffer, O *outBuffer, const Bit32u len) { + if (inBuffer == NULL || outBuffer == NULL) return; + + const I *inBufferEnd = inBuffer + len; + while (inBuffer < inBufferEnd) { + *(outBuffer++) = Synth::convertSample(*(inBuffer++)); + } +} + +class Renderer { +protected: + Synth &synth; + + void printDebug(const char *msg) const { + synth.printDebug(msg); + } + + bool isActivated() const { + return synth.activated; + } + + bool isAbortingPoly() const { + return synth.isAbortingPoly(); + } + + Analog &getAnalog() const { + return *synth.analog; + } + + MidiEventQueue &getMidiQueue() { + return *synth.midiQueue; + } + + PartialManager &getPartialManager() { + return *synth.partialManager; + } + + BReverbModel &getReverbModel() { + return *synth.reverbModel; + } + + Bit32u getRenderedSampleCount() { + return synth.renderedSampleCount; + } + + void incRenderedSampleCount(const Bit32u count) { + synth.renderedSampleCount += count; + } + +public: + Renderer(Synth &useSynth) : synth(useSynth) {} + + virtual ~Renderer() {} + + virtual void render(IntSample *stereoStream, Bit32u len) = 0; + virtual void render(FloatSample *stereoStream, Bit32u len) = 0; + virtual void renderStreams(const DACOutputStreams &streams, Bit32u len) = 0; + virtual void renderStreams(const DACOutputStreams &streams, Bit32u len) = 0; +}; + +template +class RendererImpl : public Renderer { + // These buffers are used for building the output streams as they are found at the DAC entrance. + // The output is mixed down to stereo interleaved further in the analog circuitry emulation. + Sample tmpNonReverbLeft[MAX_SAMPLES_PER_RUN], tmpNonReverbRight[MAX_SAMPLES_PER_RUN]; + Sample tmpReverbDryLeft[MAX_SAMPLES_PER_RUN], tmpReverbDryRight[MAX_SAMPLES_PER_RUN]; + Sample tmpReverbWetLeft[MAX_SAMPLES_PER_RUN], tmpReverbWetRight[MAX_SAMPLES_PER_RUN]; + + const DACOutputStreams tmpBuffers; + DACOutputStreams createTmpBuffers() { + DACOutputStreams buffers = { + tmpNonReverbLeft, tmpNonReverbRight, + tmpReverbDryLeft, tmpReverbDryRight, + tmpReverbWetLeft, tmpReverbWetRight + }; + return buffers; + } + +public: + RendererImpl(Synth &useSynth) : + Renderer(useSynth), + tmpBuffers(createTmpBuffers()) + {} + + void render(IntSample *stereoStream, Bit32u len); + void render(FloatSample *stereoStream, Bit32u len); + void renderStreams(const DACOutputStreams &streams, Bit32u len); + void renderStreams(const DACOutputStreams &streams, Bit32u len); + + template + void doRenderAndConvert(O *stereoStream, Bit32u len); + void doRender(Sample *stereoStream, Bit32u len); + + template + void doRenderAndConvertStreams(const DACOutputStreams &streams, Bit32u len); + void doRenderStreams(const DACOutputStreams &streams, Bit32u len); + void produceLA32Output(Sample *buffer, Bit32u len); + void convertSamplesToOutput(Sample *buffer, Bit32u len); + void produceStreams(const DACOutputStreams &streams, Bit32u len); +}; + +class Extensions { +public: + RendererType selectedRendererType; +}; + +Bit32u Synth::getLibraryVersionInt() { + return (MT32EMU_VERSION_MAJOR << 16) | (MT32EMU_VERSION_MINOR << 8) | (MT32EMU_VERSION_PATCH); +} + +const char *Synth::getLibraryVersionString() { + return MT32EMU_VERSION; +} + +Bit8u Synth::calcSysexChecksum(const Bit8u *data, const Bit32u len, const Bit8u initChecksum) { + unsigned int checksum = -initChecksum; + for (unsigned int i = 0; i < len; i++) { + checksum -= data[i]; + } + return Bit8u(checksum & 0x7f); +} + +Bit32u Synth::getStereoOutputSampleRate(AnalogOutputMode analogOutputMode) { + static const unsigned int SAMPLE_RATES[] = {SAMPLE_RATE, SAMPLE_RATE, SAMPLE_RATE * 3 / 2, SAMPLE_RATE * 3}; + + return SAMPLE_RATES[analogOutputMode]; +} + +Synth::Synth(ReportHandler *useReportHandler) : + mt32ram(*new MemParams), + mt32default(*new MemParams), + extensions(*new Extensions) +{ + opened = false; + reverbOverridden = false; + partialCount = DEFAULT_MAX_PARTIALS; + controlROMMap = NULL; + controlROMFeatures = NULL; + + if (useReportHandler == NULL) { + reportHandler = new ReportHandler; + isDefaultReportHandler = true; + } else { + reportHandler = useReportHandler; + isDefaultReportHandler = false; + } + + for (int i = 0; i < 4; i++) { + reverbModels[i] = NULL; + } + reverbModel = NULL; + analog = NULL; + renderer = NULL; + setDACInputMode(DACInputMode_NICE); + setMIDIDelayMode(MIDIDelayMode_DELAY_SHORT_MESSAGES_ONLY); + setOutputGain(1.0f); + setReverbOutputGain(1.0f); + setReversedStereoEnabled(false); + selectRendererType(RendererType_BIT16S); + + patchTempMemoryRegion = NULL; + rhythmTempMemoryRegion = NULL; + timbreTempMemoryRegion = NULL; + patchesMemoryRegion = NULL; + timbresMemoryRegion = NULL; + systemMemoryRegion = NULL; + displayMemoryRegion = NULL; + resetMemoryRegion = NULL; + paddedTimbreMaxTable = NULL; + + partialManager = NULL; + pcmWaves = NULL; + pcmROMData = NULL; + soundGroupNames = NULL; + midiQueue = NULL; + lastReceivedMIDIEventTimestamp = 0; + memset(parts, 0, sizeof(parts)); + renderedSampleCount = 0; +} + +Synth::~Synth() { + close(); // Make sure we're closed and everything is freed + if (isDefaultReportHandler) { + delete reportHandler; + } + delete &mt32ram; + delete &mt32default; + delete &extensions; +} + +void ReportHandler::showLCDMessage(const char *data) { + printf("WRITE-LCD: %s\n", data); +} + +void ReportHandler::printDebug(const char *fmt, va_list list) { + vprintf(fmt, list); + printf("\n"); +} + +void Synth::newTimbreSet(Bit8u partNum, Bit8u timbreGroup, Bit8u timbreNumber, const char patchName[]) { + const char *soundGroupName; + switch (timbreGroup) { + case 1: + timbreNumber += 64; + // Fall-through + case 0: + soundGroupName = soundGroupNames[soundGroupIx[timbreNumber]]; + break; + case 2: + soundGroupName = soundGroupNames[controlROMMap->soundGroupsCount - 2]; + break; + case 3: + soundGroupName = soundGroupNames[controlROMMap->soundGroupsCount - 1]; + break; + default: + soundGroupName = NULL; + break; + } + reportHandler->onProgramChanged(partNum, soundGroupName, patchName); +} + +void Synth::printDebug(const char *fmt, ...) { + va_list ap; + va_start(ap, fmt); +#if MT32EMU_DEBUG_SAMPLESTAMPS > 0 + reportHandler->printDebug("[%u]", (va_list)&renderedSampleCount); +#endif + reportHandler->printDebug(fmt, ap); + va_end(ap); +} + +void Synth::setReverbEnabled(bool newReverbEnabled) { + if (!opened) return; + if (isReverbEnabled() == newReverbEnabled) return; + if (newReverbEnabled) { + bool oldReverbOverridden = reverbOverridden; + reverbOverridden = false; + refreshSystemReverbParameters(); + reverbOverridden = oldReverbOverridden; + } else { +#if MT32EMU_REDUCE_REVERB_MEMORY + reverbModel->close(); +#endif + reverbModel = NULL; + } +} + +bool Synth::isReverbEnabled() const { + return reverbModel != NULL; +} + +void Synth::setReverbOverridden(bool newReverbOverridden) { + reverbOverridden = newReverbOverridden; +} + +bool Synth::isReverbOverridden() const { + return reverbOverridden; +} + +void Synth::setReverbCompatibilityMode(bool mt32CompatibleMode) { + if (!opened || (isMT32ReverbCompatibilityMode() == mt32CompatibleMode)) return; + bool oldReverbEnabled = isReverbEnabled(); + setReverbEnabled(false); + for (int i = 0; i < 4; i++) { + delete reverbModels[i]; + } + initReverbModels(mt32CompatibleMode); + setReverbEnabled(oldReverbEnabled); + setReverbOutputGain(reverbOutputGain); +} + +bool Synth::isMT32ReverbCompatibilityMode() const { + return opened && (reverbModels[REVERB_MODE_ROOM]->isMT32Compatible(REVERB_MODE_ROOM)); +} + +bool Synth::isDefaultReverbMT32Compatible() const { + return opened && controlROMFeatures->defaultReverbMT32Compatible; +} + +void Synth::setDACInputMode(DACInputMode mode) { + dacInputMode = mode; +} + +DACInputMode Synth::getDACInputMode() const { + return dacInputMode; +} + +void Synth::setMIDIDelayMode(MIDIDelayMode mode) { + midiDelayMode = mode; +} + +MIDIDelayMode Synth::getMIDIDelayMode() const { + return midiDelayMode; +} + +void Synth::setOutputGain(float newOutputGain) { + if (newOutputGain < 0.0f) newOutputGain = -newOutputGain; + outputGain = newOutputGain; + if (analog != NULL) analog->setSynthOutputGain(newOutputGain); +} + +float Synth::getOutputGain() const { + return outputGain; +} + +void Synth::setReverbOutputGain(float newReverbOutputGain) { + if (newReverbOutputGain < 0.0f) newReverbOutputGain = -newReverbOutputGain; + reverbOutputGain = newReverbOutputGain; + if (analog != NULL) analog->setReverbOutputGain(newReverbOutputGain, isMT32ReverbCompatibilityMode()); +} + +float Synth::getReverbOutputGain() const { + return reverbOutputGain; +} + +void Synth::setReversedStereoEnabled(bool enabled) { + reversedStereoEnabled = enabled; +} + +bool Synth::isReversedStereoEnabled() const { + return reversedStereoEnabled; +} + +bool Synth::loadControlROM(const ROMImage &controlROMImage) { + File *file = controlROMImage.getFile(); + const ROMInfo *controlROMInfo = controlROMImage.getROMInfo(); + if ((controlROMInfo == NULL) + || (controlROMInfo->type != ROMInfo::Control) + || (controlROMInfo->pairType != ROMInfo::Full)) { +#if MT32EMU_MONITOR_INIT + printDebug("Invalid Control ROM Info provided"); +#endif + return false; + } + +#if MT32EMU_MONITOR_INIT + printDebug("Found Control ROM: %s, %s", controlROMInfo->shortName, controlROMInfo->description); +#endif + const Bit8u *fileData = file->getData(); + memcpy(controlROMData, fileData, CONTROL_ROM_SIZE); + + // Control ROM successfully loaded, now check whether it's a known type + controlROMMap = NULL; + controlROMFeatures = NULL; + for (unsigned int i = 0; i < sizeof(ControlROMMaps) / sizeof(ControlROMMaps[0]); i++) { + if (strcmp(controlROMInfo->shortName, ControlROMMaps[i].shortName) == 0) { + controlROMMap = &ControlROMMaps[i]; + controlROMFeatures = &controlROMMap->featureSet; + return true; + } + } +#if MT32EMU_MONITOR_INIT + printDebug("Control ROM failed to load"); +#endif + return false; +} + +bool Synth::loadPCMROM(const ROMImage &pcmROMImage) { + File *file = pcmROMImage.getFile(); + const ROMInfo *pcmROMInfo = pcmROMImage.getROMInfo(); + if ((pcmROMInfo == NULL) + || (pcmROMInfo->type != ROMInfo::PCM) + || (pcmROMInfo->pairType != ROMInfo::Full)) { + return false; + } +#if MT32EMU_MONITOR_INIT + printDebug("Found PCM ROM: %s, %s", pcmROMInfo->shortName, pcmROMInfo->description); +#endif + size_t fileSize = file->getSize(); + if (fileSize != (2 * pcmROMSize)) { +#if MT32EMU_MONITOR_INIT + printDebug("PCM ROM file has wrong size (expected %d, got %d)", 2 * pcmROMSize, fileSize); +#endif + return false; + } + const Bit8u *fileData = file->getData(); + for (size_t i = 0; i < pcmROMSize; i++) { + Bit8u s = *(fileData++); + Bit8u c = *(fileData++); + + int order[16] = {0, 9, 1, 2, 3, 4, 5, 6, 7, 10, 11, 12, 13, 14, 15, 8}; + + Bit16s log = 0; + for (int u = 0; u < 15; u++) { + int bit; + if (order[u] < 8) { + bit = (s >> (7 - order[u])) & 0x1; + } else { + bit = (c >> (7 - (order[u] - 8))) & 0x1; + } + log = log | Bit16s(bit << (15 - u)); + } + pcmROMData[i] = log; + } + return true; +} + +bool Synth::initPCMList(Bit16u mapAddress, Bit16u count) { + ControlROMPCMStruct *tps = reinterpret_cast(&controlROMData[mapAddress]); + for (int i = 0; i < count; i++) { + Bit32u rAddr = tps[i].pos * 0x800; + Bit32u rLenExp = (tps[i].len & 0x70) >> 4; + Bit32u rLen = 0x800 << rLenExp; + if (rAddr + rLen > pcmROMSize) { + printDebug("Control ROM error: Wave map entry %d points to invalid PCM address 0x%04X, length 0x%04X", i, rAddr, rLen); + return false; + } + pcmWaves[i].addr = rAddr; + pcmWaves[i].len = rLen; + pcmWaves[i].loop = (tps[i].len & 0x80) != 0; + pcmWaves[i].controlROMPCMStruct = &tps[i]; + //int pitch = (tps[i].pitchMSB << 8) | tps[i].pitchLSB; + //bool unaffectedByMasterTune = (tps[i].len & 0x01) == 0; + //printDebug("PCM %d: pos=%d, len=%d, pitch=%d, loop=%s, unaffectedByMasterTune=%s", i, rAddr, rLen, pitch, pcmWaves[i].loop ? "YES" : "NO", unaffectedByMasterTune ? "YES" : "NO"); + } + return false; +} + +bool Synth::initCompressedTimbre(Bit16u timbreNum, const Bit8u *src, Bit32u srcLen) { + // "Compressed" here means that muted partials aren't present in ROM (except in the case of partial 0 being muted). + // Instead the data from the previous unmuted partial is used. + if (srcLen < sizeof(TimbreParam::CommonParam)) { + return false; + } + TimbreParam *timbre = &mt32ram.timbres[timbreNum].timbre; + timbresMemoryRegion->write(timbreNum, 0, src, sizeof(TimbreParam::CommonParam), true); + unsigned int srcPos = sizeof(TimbreParam::CommonParam); + unsigned int memPos = sizeof(TimbreParam::CommonParam); + for (int t = 0; t < 4; t++) { + if (t != 0 && ((timbre->common.partialMute >> t) & 0x1) == 0x00) { + // This partial is muted - we'll copy the previously copied partial, then + srcPos -= sizeof(TimbreParam::PartialParam); + } else if (srcPos + sizeof(TimbreParam::PartialParam) >= srcLen) { + return false; + } + timbresMemoryRegion->write(timbreNum, memPos, src + srcPos, sizeof(TimbreParam::PartialParam)); + srcPos += sizeof(TimbreParam::PartialParam); + memPos += sizeof(TimbreParam::PartialParam); + } + return true; +} + +bool Synth::initTimbres(Bit16u mapAddress, Bit16u offset, Bit16u count, Bit16u startTimbre, bool compressed) { + const Bit8u *timbreMap = &controlROMData[mapAddress]; + for (Bit16u i = 0; i < count * 2; i += 2) { + Bit16u address = (timbreMap[i + 1] << 8) | timbreMap[i]; + if (!compressed && (address + offset + sizeof(TimbreParam) > CONTROL_ROM_SIZE)) { + printDebug("Control ROM error: Timbre map entry 0x%04x for timbre %d points to invalid timbre address 0x%04x", i, startTimbre, address); + return false; + } + address += offset; + if (compressed) { + if (!initCompressedTimbre(startTimbre, &controlROMData[address], CONTROL_ROM_SIZE - address)) { + printDebug("Control ROM error: Timbre map entry 0x%04x for timbre %d points to invalid timbre at 0x%04x", i, startTimbre, address); + return false; + } + } else { + timbresMemoryRegion->write(startTimbre, 0, &controlROMData[address], sizeof(TimbreParam), true); + } + startTimbre++; + } + return true; +} + +void Synth::initReverbModels(bool mt32CompatibleMode) { + reverbModels[REVERB_MODE_ROOM] = BReverbModel::createBReverbModel(REVERB_MODE_ROOM, mt32CompatibleMode, getSelectedRendererType()); + reverbModels[REVERB_MODE_HALL] = BReverbModel::createBReverbModel(REVERB_MODE_HALL, mt32CompatibleMode, getSelectedRendererType()); + reverbModels[REVERB_MODE_PLATE] = BReverbModel::createBReverbModel(REVERB_MODE_PLATE, mt32CompatibleMode, getSelectedRendererType()); + reverbModels[REVERB_MODE_TAP_DELAY] = BReverbModel::createBReverbModel(REVERB_MODE_TAP_DELAY, mt32CompatibleMode, getSelectedRendererType()); +#if !MT32EMU_REDUCE_REVERB_MEMORY + for (int i = REVERB_MODE_ROOM; i <= REVERB_MODE_TAP_DELAY; i++) { + reverbModels[i]->open(); + } +#endif +} + +void Synth::initSoundGroups(char newSoundGroupNames[][9]) { + memcpy(soundGroupIx, &controlROMData[controlROMMap->soundGroupsTable - sizeof(soundGroupIx)], sizeof(soundGroupIx)); + const SoundGroup *table = reinterpret_cast(&controlROMData[controlROMMap->soundGroupsTable]); + for (unsigned int i = 0; i < controlROMMap->soundGroupsCount; i++) { + memcpy(&newSoundGroupNames[i][0], table[i].name, sizeof(table[i].name)); + } +} + +bool Synth::open(const ROMImage &controlROMImage, const ROMImage &pcmROMImage, AnalogOutputMode analogOutputMode) { + return open(controlROMImage, pcmROMImage, DEFAULT_MAX_PARTIALS, analogOutputMode); +} + +bool Synth::open(const ROMImage &controlROMImage, const ROMImage &pcmROMImage, Bit32u usePartialCount, AnalogOutputMode analogOutputMode) { + if (opened) { + return false; + } + partialCount = usePartialCount; + abortingPoly = NULL; + + // This is to help detect bugs + memset(&mt32ram, '?', sizeof(mt32ram)); + +#if MT32EMU_MONITOR_INIT + printDebug("Loading Control ROM"); +#endif + if (!loadControlROM(controlROMImage)) { + printDebug("Init Error - Missing or invalid Control ROM image"); + reportHandler->onErrorControlROM(); + dispose(); + return false; + } + + initMemoryRegions(); + + // 512KB PCM ROM for MT-32, etc. + // 1MB PCM ROM for CM-32L, LAPC-I, CM-64, CM-500 + // Note that the size below is given in samples (16-bit), not bytes + pcmROMSize = controlROMMap->pcmCount == 256 ? 512 * 1024 : 256 * 1024; + pcmROMData = new Bit16s[pcmROMSize]; + +#if MT32EMU_MONITOR_INIT + printDebug("Loading PCM ROM"); +#endif + if (!loadPCMROM(pcmROMImage)) { + printDebug("Init Error - Missing PCM ROM image"); + reportHandler->onErrorPCMROM(); + dispose(); + return false; + } + +#if MT32EMU_MONITOR_INIT + printDebug("Initialising Reverb Models"); +#endif + bool mt32CompatibleReverb = controlROMFeatures->defaultReverbMT32Compatible; +#if MT32EMU_MONITOR_INIT + printDebug("Using %s Compatible Reverb Models", mt32CompatibleReverb ? "MT-32" : "CM-32L"); +#endif + initReverbModels(mt32CompatibleReverb); + +#if MT32EMU_MONITOR_INIT + printDebug("Initialising Timbre Bank A"); +#endif + if (!initTimbres(controlROMMap->timbreAMap, controlROMMap->timbreAOffset, 0x40, 0, controlROMMap->timbreACompressed)) { + dispose(); + return false; + } + +#if MT32EMU_MONITOR_INIT + printDebug("Initialising Timbre Bank B"); +#endif + if (!initTimbres(controlROMMap->timbreBMap, controlROMMap->timbreBOffset, 0x40, 64, controlROMMap->timbreBCompressed)) { + dispose(); + return false; + } + +#if MT32EMU_MONITOR_INIT + printDebug("Initialising Timbre Bank R"); +#endif + if (!initTimbres(controlROMMap->timbreRMap, 0, controlROMMap->timbreRCount, 192, true)) { + dispose(); + return false; + } + +#if MT32EMU_MONITOR_INIT + printDebug("Initialising Timbre Bank M"); +#endif + // CM-64 seems to initialise all bytes in this bank to 0. + memset(&mt32ram.timbres[128], 0, sizeof(mt32ram.timbres[128]) * 64); + + partialManager = new PartialManager(this, parts); + + pcmWaves = new PCMWaveEntry[controlROMMap->pcmCount]; + +#if MT32EMU_MONITOR_INIT + printDebug("Initialising PCM List"); +#endif + initPCMList(controlROMMap->pcmTable, controlROMMap->pcmCount); + +#if MT32EMU_MONITOR_INIT + printDebug("Initialising Rhythm Temp"); +#endif + memcpy(mt32ram.rhythmTemp, &controlROMData[controlROMMap->rhythmSettings], controlROMMap->rhythmSettingsCount * 4); + +#if MT32EMU_MONITOR_INIT + printDebug("Initialising Patches"); +#endif + for (Bit8u i = 0; i < 128; i++) { + PatchParam *patch = &mt32ram.patches[i]; + patch->timbreGroup = i / 64; + patch->timbreNum = i % 64; + patch->keyShift = 24; + patch->fineTune = 50; + patch->benderRange = 12; + patch->assignMode = 0; + patch->reverbSwitch = 1; + patch->dummy = 0; + } + +#if MT32EMU_MONITOR_INIT + printDebug("Initialising System"); +#endif + // The MT-32 manual claims that "Standard pitch" is 442Hz. + mt32ram.system.masterTune = 0x4A; // Confirmed on CM-64 + mt32ram.system.reverbMode = 0; // Confirmed + mt32ram.system.reverbTime = 5; // Confirmed + mt32ram.system.reverbLevel = 3; // Confirmed + memcpy(mt32ram.system.reserveSettings, &controlROMData[controlROMMap->reserveSettings], 9); // Confirmed + for (Bit8u i = 0; i < 9; i++) { + // This is the default: {1, 2, 3, 4, 5, 6, 7, 8, 9} + // An alternative configuration can be selected by holding "Master Volume" + // and pressing "PART button 1" on the real MT-32's frontpanel. + // The channel assignment is then {0, 1, 2, 3, 4, 5, 6, 7, 9} + mt32ram.system.chanAssign[i] = i + 1; + } + mt32ram.system.masterVol = 100; // Confirmed + + bool oldReverbOverridden = reverbOverridden; + reverbOverridden = false; + refreshSystem(); + reverbOverridden = oldReverbOverridden; + + char(*writableSoundGroupNames)[9] = new char[controlROMMap->soundGroupsCount][9]; + soundGroupNames = writableSoundGroupNames; + initSoundGroups(writableSoundGroupNames); + + for (int i = 0; i < 9; i++) { + MemParams::PatchTemp *patchTemp = &mt32ram.patchTemp[i]; + + // Note that except for the rhythm part, these patch fields will be set in setProgram() below anyway. + patchTemp->patch.timbreGroup = 0; + patchTemp->patch.timbreNum = 0; + patchTemp->patch.keyShift = 24; + patchTemp->patch.fineTune = 50; + patchTemp->patch.benderRange = 12; + patchTemp->patch.assignMode = 0; + patchTemp->patch.reverbSwitch = 1; + patchTemp->patch.dummy = 0; + + patchTemp->outputLevel = 80; + patchTemp->panpot = controlROMData[controlROMMap->panSettings + i]; + memset(patchTemp->dummyv, 0, sizeof(patchTemp->dummyv)); + patchTemp->dummyv[1] = 127; + + if (i < 8) { + parts[i] = new Part(this, i); + parts[i]->setProgram(controlROMData[controlROMMap->programSettings + i]); + } else { + parts[i] = new RhythmPart(this, i); + } + } + + // For resetting mt32 mid-execution + mt32default = mt32ram; + + midiQueue = new MidiEventQueue(); + + analog = Analog::createAnalog(analogOutputMode, controlROMFeatures->oldMT32AnalogLPF, getSelectedRendererType()); +#if MT32EMU_MONITOR_INIT + static const char *ANALOG_OUTPUT_MODES[] = { "Digital only", "Coarse", "Accurate", "Oversampled2x" }; + printDebug("Using Analog output mode %s", ANALOG_OUTPUT_MODES[analogOutputMode]); +#endif + setOutputGain(outputGain); + setReverbOutputGain(reverbOutputGain); + + switch (getSelectedRendererType()) { + case RendererType_BIT16S: + renderer = new RendererImpl(*this); +#if MT32EMU_MONITOR_INIT + printDebug("Using integer 16-bit samples in renderer and wave generator"); +#endif + break; + case RendererType_FLOAT: + renderer = new RendererImpl(*this); +#if MT32EMU_MONITOR_INIT + printDebug("Using float 32-bit samples in renderer and wave generator"); +#endif + break; + default: + printDebug("Synth: Unknown renderer type %i\n", getSelectedRendererType()); + dispose(); + return false; + } + + opened = true; + activated = false; + +#if MT32EMU_MONITOR_INIT + printDebug("*** Initialisation complete ***"); +#endif + return true; +} + +void Synth::dispose() { + opened = false; + + delete midiQueue; + midiQueue = NULL; + + delete renderer; + renderer = NULL; + + delete analog; + analog = NULL; + + delete partialManager; + partialManager = NULL; + + for (int i = 0; i < 9; i++) { + delete parts[i]; + parts[i] = NULL; + } + + delete[] soundGroupNames; + soundGroupNames = NULL; + + delete[] pcmWaves; + pcmWaves = NULL; + + delete[] pcmROMData; + pcmROMData = NULL; + + deleteMemoryRegions(); + + for (int i = 0; i < 4; i++) { + delete reverbModels[i]; + reverbModels[i] = NULL; + } + reverbModel = NULL; + controlROMFeatures = NULL; + controlROMMap = NULL; +} + +void Synth::close() { + if (opened) { + dispose(); + } +} + +bool Synth::isOpen() const { + return opened; +} + +void Synth::flushMIDIQueue() { + if (midiQueue != NULL) { + for (;;) { + const MidiEvent *midiEvent = midiQueue->peekMidiEvent(); + if (midiEvent == NULL) break; + if (midiEvent->sysexData == NULL) { + playMsgNow(midiEvent->shortMessageData); + } else { + playSysexNow(midiEvent->sysexData, midiEvent->sysexLength); + } + midiQueue->dropMidiEvent(); + } + lastReceivedMIDIEventTimestamp = renderedSampleCount; + } +} + +Bit32u Synth::setMIDIEventQueueSize(Bit32u useSize) { + static const Bit32u MAX_QUEUE_SIZE = (1 << 24); // This results in about 256 Mb - much greater than any reasonable value + + if (midiQueue == NULL) return 0; + flushMIDIQueue(); + + // Find a power of 2 that is >= useSize + Bit32u binarySize = 1; + if (useSize < MAX_QUEUE_SIZE) { + // Using simple linear search as this isn't time critical + while (binarySize < useSize) binarySize <<= 1; + } else { + binarySize = MAX_QUEUE_SIZE; + } + delete midiQueue; + midiQueue = new MidiEventQueue(binarySize); + return binarySize; +} + +Bit32u Synth::getShortMessageLength(Bit32u msg) { + if ((msg & 0xF0) == 0xF0) { + switch (msg & 0xFF) { + case 0xF1: + case 0xF3: + return 2; + case 0xF2: + return 3; + default: + return 1; + } + } + // NOTE: This calculation isn't quite correct + // as it doesn't consider the running status byte + return ((msg & 0xE0) == 0xC0) ? 2 : 3; +} + +Bit32u Synth::addMIDIInterfaceDelay(Bit32u len, Bit32u timestamp) { + Bit32u transferTime = Bit32u(double(len) * MIDI_DATA_TRANSFER_RATE); + // Dealing with wrapping + if (Bit32s(timestamp - lastReceivedMIDIEventTimestamp) < 0) { + timestamp = lastReceivedMIDIEventTimestamp; + } + timestamp += transferTime; + lastReceivedMIDIEventTimestamp = timestamp; + return timestamp; +} + +bool Synth::playMsg(Bit32u msg) { + return playMsg(msg, renderedSampleCount); +} + +bool Synth::playMsg(Bit32u msg, Bit32u timestamp) { + if ((msg & 0xF8) == 0xF8) { + reportHandler->onMIDISystemRealtime(Bit8u(msg)); + return true; + } + if (midiQueue == NULL) return false; + if (midiDelayMode != MIDIDelayMode_IMMEDIATE) { + timestamp = addMIDIInterfaceDelay(getShortMessageLength(msg), timestamp); + } + if (!activated) activated = true; + do { + if (midiQueue->pushShortMessage(msg, timestamp)) return true; + } while (reportHandler->onMIDIQueueOverflow()); + return false; +} + +bool Synth::playSysex(const Bit8u *sysex, Bit32u len) { + return playSysex(sysex, len, renderedSampleCount); +} + +bool Synth::playSysex(const Bit8u *sysex, Bit32u len, Bit32u timestamp) { + if (midiQueue == NULL) return false; + if (midiDelayMode == MIDIDelayMode_DELAY_ALL) { + timestamp = addMIDIInterfaceDelay(len, timestamp); + } + if (!activated) activated = true; + do { + if (midiQueue->pushSysex(sysex, len, timestamp)) return true; + } while (reportHandler->onMIDIQueueOverflow()); + return false; +} + +void Synth::playMsgNow(Bit32u msg) { + if (!opened) return; + + // NOTE: Active sense IS implemented in real hardware. However, realtime processing is clearly out of the library scope. + // It is assumed that realtime consumers of the library respond to these MIDI events as appropriate. + + Bit8u code = Bit8u((msg & 0x0000F0) >> 4); + Bit8u chan = Bit8u(msg & 0x00000F); + Bit8u note = Bit8u((msg & 0x007F00) >> 8); + Bit8u velocity = Bit8u((msg & 0x7F0000) >> 16); + + //printDebug("Playing chan %d, code 0x%01x note: 0x%02x", chan, code, note); + + Bit8u part = chantable[chan]; + if (part > 8) { +#if MT32EMU_MONITOR_MIDI > 0 + printDebug("Play msg on unreg chan %d (%d): code=0x%01x, vel=%d", chan, part, code, velocity); +#endif + return; + } + playMsgOnPart(part, code, note, velocity); +} + +void Synth::playMsgOnPart(Bit8u part, Bit8u code, Bit8u note, Bit8u velocity) { + if (!opened) return; + + Bit32u bend; + + if (!activated) activated = true; + //printDebug("Synth::playMsgOnPart(%02x, %02x, %02x, %02x)", part, code, note, velocity); + switch (code) { + case 0x8: + //printDebug("Note OFF - Part %d", part); + // The MT-32 ignores velocity for note off + parts[part]->noteOff(note); + break; + case 0x9: + //printDebug("Note ON - Part %d, Note %d Vel %d", part, note, velocity); + if (velocity == 0) { + // MIDI defines note-on with velocity 0 as being the same as note-off with velocity 40 + parts[part]->noteOff(note); + } else { + parts[part]->noteOn(note, velocity); + } + break; + case 0xB: // Control change + switch (note) { + case 0x01: // Modulation + //printDebug("Modulation: %d", velocity); + parts[part]->setModulation(velocity); + break; + case 0x06: + parts[part]->setDataEntryMSB(velocity); + break; + case 0x07: // Set volume + //printDebug("Volume set: %d", velocity); + parts[part]->setVolume(velocity); + break; + case 0x0A: // Pan + //printDebug("Pan set: %d", velocity); + parts[part]->setPan(velocity); + break; + case 0x0B: + //printDebug("Expression set: %d", velocity); + parts[part]->setExpression(velocity); + break; + case 0x40: // Hold (sustain) pedal + //printDebug("Hold pedal set: %d", velocity); + parts[part]->setHoldPedal(velocity >= 64); + break; + + case 0x62: + case 0x63: + parts[part]->setNRPN(); + break; + case 0x64: + parts[part]->setRPNLSB(velocity); + break; + case 0x65: + parts[part]->setRPNMSB(velocity); + break; + + case 0x79: // Reset all controllers + //printDebug("Reset all controllers"); + parts[part]->resetAllControllers(); + break; + + case 0x7B: // All notes off + //printDebug("All notes off"); + parts[part]->allNotesOff(); + break; + + case 0x7C: + case 0x7D: + case 0x7E: + case 0x7F: + // CONFIRMED:Mok: A real LAPC-I responds to these controllers as follows: + parts[part]->setHoldPedal(false); + parts[part]->allNotesOff(); + break; + + default: +#if MT32EMU_MONITOR_MIDI > 0 + printDebug("Unknown MIDI Control code: 0x%02x - vel 0x%02x", note, velocity); +#endif + return; + } + + break; + case 0xC: // Program change + //printDebug("Program change %01x", note); + parts[part]->setProgram(note); + break; + case 0xE: // Pitch bender + bend = (velocity << 7) | (note); + //printDebug("Pitch bender %02x", bend); + parts[part]->setBend(bend); + break; + default: +#if MT32EMU_MONITOR_MIDI > 0 + printDebug("Unknown Midi code: 0x%01x - %02x - %02x", code, note, velocity); +#endif + return; + } + reportHandler->onMIDIMessagePlayed(); +} + +void Synth::playSysexNow(const Bit8u *sysex, Bit32u len) { + if (len < 2) { + printDebug("playSysex: Message is too short for sysex (%d bytes)", len); + } + if (sysex[0] != 0xF0) { + printDebug("playSysex: Message lacks start-of-sysex (0xF0)"); + return; + } + // Due to some programs (e.g. Java) sending buffers with junk at the end, we have to go through and find the end marker rather than relying on len. + Bit32u endPos; + for (endPos = 1; endPos < len; endPos++) { + if (sysex[endPos] == 0xF7) { + break; + } + } + if (endPos == len) { + printDebug("playSysex: Message lacks end-of-sysex (0xf7)"); + return; + } + playSysexWithoutFraming(sysex + 1, endPos - 1); +} + +void Synth::playSysexWithoutFraming(const Bit8u *sysex, Bit32u len) { + if (len < 4) { + printDebug("playSysexWithoutFraming: Message is too short (%d bytes)!", len); + return; + } + if (sysex[0] != SYSEX_MANUFACTURER_ROLAND) { + printDebug("playSysexWithoutFraming: Header not intended for this device manufacturer: %02x %02x %02x %02x", int(sysex[0]), int(sysex[1]), int(sysex[2]), int(sysex[3])); + return; + } + if (sysex[2] == SYSEX_MDL_D50) { + printDebug("playSysexWithoutFraming: Header is intended for model D-50 (not yet supported): %02x %02x %02x %02x", int(sysex[0]), int(sysex[1]), int(sysex[2]), int(sysex[3])); + return; + } else if (sysex[2] != SYSEX_MDL_MT32) { + printDebug("playSysexWithoutFraming: Header not intended for model MT-32: %02x %02x %02x %02x", int(sysex[0]), int(sysex[1]), int(sysex[2]), int(sysex[3])); + return; + } + playSysexWithoutHeader(sysex[1], sysex[3], sysex + 4, len - 4); +} + +void Synth::playSysexWithoutHeader(Bit8u device, Bit8u command, const Bit8u *sysex, Bit32u len) { + if (device > 0x10) { + // We have device ID 0x10 (default, but changeable, on real MT-32), < 0x10 is for channels + printDebug("playSysexWithoutHeader: Message is not intended for this device ID (provided: %02x, expected: 0x10 or channel)", int(device)); + return; + } + // This is checked early in the real devices (before any sysex length checks or further processing) + // FIXME: Response to SYSEX_CMD_DAT reset with partials active (and in general) is untested. + if ((command == SYSEX_CMD_DT1 || command == SYSEX_CMD_DAT) && sysex[0] == 0x7F) { + reset(); + return; + } + + if (command == SYSEX_CMD_EOD) { +#if MT32EMU_MONITOR_SYSEX > 0 + printDebug("playSysexWithoutHeader: Ignored unsupported command %02x", command); +#endif + return; + } + if (len < 4) { + printDebug("playSysexWithoutHeader: Message is too short (%d bytes)!", len); + return; + } + Bit8u checksum = calcSysexChecksum(sysex, len - 1); + if (checksum != sysex[len - 1]) { + printDebug("playSysexWithoutHeader: Message checksum is incorrect (provided: %02x, expected: %02x)!", sysex[len - 1], checksum); + return; + } + len -= 1; // Exclude checksum + switch (command) { + case SYSEX_CMD_WSD: +#if MT32EMU_MONITOR_SYSEX > 0 + printDebug("playSysexWithoutHeader: Ignored unsupported command %02x", command); +#endif + break; + case SYSEX_CMD_DAT: + /* Outcommented until we (ever) actually implement handshake communication + if (hasActivePartials()) { + printDebug("playSysexWithoutHeader: Got SYSEX_CMD_DAT but partials are active - ignoring"); + // FIXME: We should send SYSEX_CMD_RJC in this case + break; + } + */ + // Deliberate fall-through + case SYSEX_CMD_DT1: + writeSysex(device, sysex, len); + break; + case SYSEX_CMD_RQD: + if (hasActivePartials()) { + printDebug("playSysexWithoutHeader: Got SYSEX_CMD_RQD but partials are active - ignoring"); + // FIXME: We should send SYSEX_CMD_RJC in this case + break; + } + // Deliberate fall-through + case SYSEX_CMD_RQ1: + readSysex(device, sysex, len); + break; + default: + printDebug("playSysexWithoutHeader: Unsupported command %02x", command); + return; + } +} + +void Synth::readSysex(Bit8u /*device*/, const Bit8u * /*sysex*/, Bit32u /*len*/) const { + // NYI +} + +void Synth::writeSysex(Bit8u device, const Bit8u *sysex, Bit32u len) { + if (!opened) return; + reportHandler->onMIDIMessagePlayed(); + Bit32u addr = (sysex[0] << 16) | (sysex[1] << 8) | (sysex[2]); + addr = MT32EMU_MEMADDR(addr); + sysex += 3; + len -= 3; + //printDebug("Sysex addr: 0x%06x", MT32EMU_SYSEXMEMADDR(addr)); + // NOTE: Please keep both lower and upper bounds in each check, for ease of reading + + // Process channel-specific sysex by converting it to device-global + if (device < 0x10) { +#if MT32EMU_MONITOR_SYSEX > 0 + printDebug("WRITE-CHANNEL: Channel %d temp area 0x%06x", device, MT32EMU_SYSEXMEMADDR(addr)); +#endif + if (/*addr >= MT32EMU_MEMADDR(0x000000) && */addr < MT32EMU_MEMADDR(0x010000)) { + int offset; + if (chantable[device] > 8) { +#if MT32EMU_MONITOR_SYSEX > 0 + printDebug(" (Channel not mapped to a part... 0 offset)"); +#endif + offset = 0; + } else if (chantable[device] == 8) { +#if MT32EMU_MONITOR_SYSEX > 0 + printDebug(" (Channel mapped to rhythm... 0 offset)"); +#endif + offset = 0; + } else { + offset = chantable[device] * sizeof(MemParams::PatchTemp); +#if MT32EMU_MONITOR_SYSEX > 0 + printDebug(" (Setting extra offset to %d)", offset); +#endif + } + addr += MT32EMU_MEMADDR(0x030000) + offset; + } else if (/*addr >= MT32EMU_MEMADDR(0x010000) && */ addr < MT32EMU_MEMADDR(0x020000)) { + addr += MT32EMU_MEMADDR(0x030110) - MT32EMU_MEMADDR(0x010000); + } else if (/*addr >= MT32EMU_MEMADDR(0x020000) && */ addr < MT32EMU_MEMADDR(0x030000)) { + int offset; + if (chantable[device] > 8) { +#if MT32EMU_MONITOR_SYSEX > 0 + printDebug(" (Channel not mapped to a part... 0 offset)"); +#endif + offset = 0; + } else if (chantable[device] == 8) { +#if MT32EMU_MONITOR_SYSEX > 0 + printDebug(" (Channel mapped to rhythm... 0 offset)"); +#endif + offset = 0; + } else { + offset = chantable[device] * sizeof(TimbreParam); +#if MT32EMU_MONITOR_SYSEX > 0 + printDebug(" (Setting extra offset to %d)", offset); +#endif + } + addr += MT32EMU_MEMADDR(0x040000) - MT32EMU_MEMADDR(0x020000) + offset; + } else { +#if MT32EMU_MONITOR_SYSEX > 0 + printDebug(" Invalid channel"); +#endif + return; + } + } + + // Process device-global sysex (possibly converted from channel-specific sysex above) + for (;;) { + // Find the appropriate memory region + const MemoryRegion *region = findMemoryRegion(addr); + + if (region == NULL) { + printDebug("Sysex write to unrecognised address %06x, len %d", MT32EMU_SYSEXMEMADDR(addr), len); + break; + } + writeMemoryRegion(region, addr, region->getClampedLen(addr, len), sysex); + + Bit32u next = region->next(addr, len); + if (next == 0) { + break; + } + addr += next; + sysex += next; + len -= next; + } +} + +void Synth::readMemory(Bit32u addr, Bit32u len, Bit8u *data) { + if (!opened) return; + const MemoryRegion *region = findMemoryRegion(addr); + if (region != NULL) { + readMemoryRegion(region, addr, len, data); + } +} + +void Synth::initMemoryRegions() { + // Timbre max tables are slightly more complicated than the others, which are used directly from the ROM. + // The ROM (sensibly) just has maximums for TimbreParam.commonParam followed by just one TimbreParam.partialParam, + // so we produce a table with all partialParams filled out, as well as padding for PaddedTimbre, for quick lookup. + paddedTimbreMaxTable = new Bit8u[sizeof(MemParams::PaddedTimbre)]; + memcpy(&paddedTimbreMaxTable[0], &controlROMData[controlROMMap->timbreMaxTable], sizeof(TimbreParam::CommonParam) + sizeof(TimbreParam::PartialParam)); // commonParam and one partialParam + int pos = sizeof(TimbreParam::CommonParam) + sizeof(TimbreParam::PartialParam); + for (int i = 0; i < 3; i++) { + memcpy(&paddedTimbreMaxTable[pos], &controlROMData[controlROMMap->timbreMaxTable + sizeof(TimbreParam::CommonParam)], sizeof(TimbreParam::PartialParam)); + pos += sizeof(TimbreParam::PartialParam); + } + memset(&paddedTimbreMaxTable[pos], 0, 10); // Padding + patchTempMemoryRegion = new PatchTempMemoryRegion(this, reinterpret_cast(&mt32ram.patchTemp[0]), &controlROMData[controlROMMap->patchMaxTable]); + rhythmTempMemoryRegion = new RhythmTempMemoryRegion(this, reinterpret_cast(&mt32ram.rhythmTemp[0]), &controlROMData[controlROMMap->rhythmMaxTable]); + timbreTempMemoryRegion = new TimbreTempMemoryRegion(this, reinterpret_cast(&mt32ram.timbreTemp[0]), paddedTimbreMaxTable); + patchesMemoryRegion = new PatchesMemoryRegion(this, reinterpret_cast(&mt32ram.patches[0]), &controlROMData[controlROMMap->patchMaxTable]); + timbresMemoryRegion = new TimbresMemoryRegion(this, reinterpret_cast(&mt32ram.timbres[0]), paddedTimbreMaxTable); + systemMemoryRegion = new SystemMemoryRegion(this, reinterpret_cast(&mt32ram.system), &controlROMData[controlROMMap->systemMaxTable]); + displayMemoryRegion = new DisplayMemoryRegion(this); + resetMemoryRegion = new ResetMemoryRegion(this); +} + +void Synth::deleteMemoryRegions() { + delete patchTempMemoryRegion; + patchTempMemoryRegion = NULL; + delete rhythmTempMemoryRegion; + rhythmTempMemoryRegion = NULL; + delete timbreTempMemoryRegion; + timbreTempMemoryRegion = NULL; + delete patchesMemoryRegion; + patchesMemoryRegion = NULL; + delete timbresMemoryRegion; + timbresMemoryRegion = NULL; + delete systemMemoryRegion; + systemMemoryRegion = NULL; + delete displayMemoryRegion; + displayMemoryRegion = NULL; + delete resetMemoryRegion; + resetMemoryRegion = NULL; + + delete[] paddedTimbreMaxTable; + paddedTimbreMaxTable = NULL; +} + +MemoryRegion *Synth::findMemoryRegion(Bit32u addr) { + MemoryRegion *regions[] = { + patchTempMemoryRegion, + rhythmTempMemoryRegion, + timbreTempMemoryRegion, + patchesMemoryRegion, + timbresMemoryRegion, + systemMemoryRegion, + displayMemoryRegion, + resetMemoryRegion, + NULL + }; + for (int pos = 0; regions[pos] != NULL; pos++) { + if (regions[pos]->contains(addr)) { + return regions[pos]; + } + } + return NULL; +} + +void Synth::readMemoryRegion(const MemoryRegion *region, Bit32u addr, Bit32u len, Bit8u *data) { + unsigned int first = region->firstTouched(addr); + //unsigned int last = region->lastTouched(addr, len); + unsigned int off = region->firstTouchedOffset(addr); + len = region->getClampedLen(addr, len); + + unsigned int m; + + if (region->isReadable()) { + region->read(first, off, data, len); + } else { + // FIXME: We might want to do these properly in future + for (m = 0; m < len; m += 2) { + data[m] = 0xff; + if (m + 1 < len) { + data[m+1] = Bit8u(region->type); + } + } + } +} + +void Synth::writeMemoryRegion(const MemoryRegion *region, Bit32u addr, Bit32u len, const Bit8u *data) { + unsigned int first = region->firstTouched(addr); + unsigned int last = region->lastTouched(addr, len); + unsigned int off = region->firstTouchedOffset(addr); + switch (region->type) { + case MR_PatchTemp: + region->write(first, off, data, len); + //printDebug("Patch temp: Patch %d, offset %x, len %d", off/16, off % 16, len); + + for (unsigned int i = first; i <= last; i++) { + int absTimbreNum = mt32ram.patchTemp[i].patch.timbreGroup * 64 + mt32ram.patchTemp[i].patch.timbreNum; + char timbreName[11]; + memcpy(timbreName, mt32ram.timbres[absTimbreNum].timbre.common.name, 10); + timbreName[10] = 0; +#if MT32EMU_MONITOR_SYSEX > 0 + printDebug("WRITE-PARTPATCH (%d-%d@%d..%d): %d; timbre=%d (%s), outlevel=%d", first, last, off, off + len, i, absTimbreNum, timbreName, mt32ram.patchTemp[i].outputLevel); +#endif + if (parts[i] != NULL) { + if (i != 8) { + // Note: Confirmed on CM-64 that we definitely *should* update the timbre here, + // but only in the case that the sysex actually writes to those values + if (i == first && off > 2) { +#if MT32EMU_MONITOR_SYSEX > 0 + printDebug(" (Not updating timbre, since those values weren't touched)"); +#endif + } else { + parts[i]->setTimbre(&mt32ram.timbres[parts[i]->getAbsTimbreNum()].timbre); + } + } + parts[i]->refresh(); + } + } + break; + case MR_RhythmTemp: + region->write(first, off, data, len); + for (unsigned int i = first; i <= last; i++) { + int timbreNum = mt32ram.rhythmTemp[i].timbre; + char timbreName[11]; + if (timbreNum < 94) { + memcpy(timbreName, mt32ram.timbres[128 + timbreNum].timbre.common.name, 10); + timbreName[10] = 0; + } else { + strcpy(timbreName, "[None]"); + } +#if MT32EMU_MONITOR_SYSEX > 0 + printDebug("WRITE-RHYTHM (%d-%d@%d..%d): %d; level=%02x, panpot=%02x, reverb=%02x, timbre=%d (%s)", first, last, off, off + len, i, mt32ram.rhythmTemp[i].outputLevel, mt32ram.rhythmTemp[i].panpot, mt32ram.rhythmTemp[i].reverbSwitch, mt32ram.rhythmTemp[i].timbre, timbreName); +#endif + } + if (parts[8] != NULL) { + parts[8]->refresh(); + } + break; + case MR_TimbreTemp: + region->write(first, off, data, len); + for (unsigned int i = first; i <= last; i++) { + char instrumentName[11]; + memcpy(instrumentName, mt32ram.timbreTemp[i].common.name, 10); + instrumentName[10] = 0; +#if MT32EMU_MONITOR_SYSEX > 0 + printDebug("WRITE-PARTTIMBRE (%d-%d@%d..%d): timbre=%d (%s)", first, last, off, off + len, i, instrumentName); +#endif + if (parts[i] != NULL) { + parts[i]->refresh(); + } + } + break; + case MR_Patches: + region->write(first, off, data, len); +#if MT32EMU_MONITOR_SYSEX > 0 + for (unsigned int i = first; i <= last; i++) { + PatchParam *patch = &mt32ram.patches[i]; + int patchAbsTimbreNum = patch->timbreGroup * 64 + patch->timbreNum; + char instrumentName[11]; + memcpy(instrumentName, mt32ram.timbres[patchAbsTimbreNum].timbre.common.name, 10); + instrumentName[10] = 0; + Bit8u *n = (Bit8u *)patch; + printDebug("WRITE-PATCH (%d-%d@%d..%d): %d; timbre=%d (%s) %02X%02X%02X%02X%02X%02X%02X%02X", first, last, off, off + len, i, patchAbsTimbreNum, instrumentName, n[0], n[1], n[2], n[3], n[4], n[5], n[6], n[7]); + } +#endif + break; + case MR_Timbres: + // Timbres + first += 128; + last += 128; + region->write(first, off, data, len); + for (unsigned int i = first; i <= last; i++) { +#if MT32EMU_MONITOR_TIMBRES >= 1 + TimbreParam *timbre = &mt32ram.timbres[i].timbre; + char instrumentName[11]; + memcpy(instrumentName, timbre->common.name, 10); + instrumentName[10] = 0; + printDebug("WRITE-TIMBRE (%d-%d@%d..%d): %d; name=\"%s\"", first, last, off, off + len, i, instrumentName); +#if MT32EMU_MONITOR_TIMBRES >= 2 +#define DT(x) printDebug(" " #x ": %d", timbre->x) + DT(common.partialStructure12); + DT(common.partialStructure34); + DT(common.partialMute); + DT(common.noSustain); + +#define DTP(x) \ + DT(partial[x].wg.pitchCoarse); \ + DT(partial[x].wg.pitchFine); \ + DT(partial[x].wg.pitchKeyfollow); \ + DT(partial[x].wg.pitchBenderEnabled); \ + DT(partial[x].wg.waveform); \ + DT(partial[x].wg.pcmWave); \ + DT(partial[x].wg.pulseWidth); \ + DT(partial[x].wg.pulseWidthVeloSensitivity); \ + DT(partial[x].pitchEnv.depth); \ + DT(partial[x].pitchEnv.veloSensitivity); \ + DT(partial[x].pitchEnv.timeKeyfollow); \ + DT(partial[x].pitchEnv.time[0]); \ + DT(partial[x].pitchEnv.time[1]); \ + DT(partial[x].pitchEnv.time[2]); \ + DT(partial[x].pitchEnv.time[3]); \ + DT(partial[x].pitchEnv.level[0]); \ + DT(partial[x].pitchEnv.level[1]); \ + DT(partial[x].pitchEnv.level[2]); \ + DT(partial[x].pitchEnv.level[3]); \ + DT(partial[x].pitchEnv.level[4]); \ + DT(partial[x].pitchLFO.rate); \ + DT(partial[x].pitchLFO.depth); \ + DT(partial[x].pitchLFO.modSensitivity); \ + DT(partial[x].tvf.cutoff); \ + DT(partial[x].tvf.resonance); \ + DT(partial[x].tvf.keyfollow); \ + DT(partial[x].tvf.biasPoint); \ + DT(partial[x].tvf.biasLevel); \ + DT(partial[x].tvf.envDepth); \ + DT(partial[x].tvf.envVeloSensitivity); \ + DT(partial[x].tvf.envDepthKeyfollow); \ + DT(partial[x].tvf.envTimeKeyfollow); \ + DT(partial[x].tvf.envTime[0]); \ + DT(partial[x].tvf.envTime[1]); \ + DT(partial[x].tvf.envTime[2]); \ + DT(partial[x].tvf.envTime[3]); \ + DT(partial[x].tvf.envTime[4]); \ + DT(partial[x].tvf.envLevel[0]); \ + DT(partial[x].tvf.envLevel[1]); \ + DT(partial[x].tvf.envLevel[2]); \ + DT(partial[x].tvf.envLevel[3]); \ + DT(partial[x].tva.level); \ + DT(partial[x].tva.veloSensitivity); \ + DT(partial[x].tva.biasPoint1); \ + DT(partial[x].tva.biasLevel1); \ + DT(partial[x].tva.biasPoint2); \ + DT(partial[x].tva.biasLevel2); \ + DT(partial[x].tva.envTimeKeyfollow); \ + DT(partial[x].tva.envTimeVeloSensitivity); \ + DT(partial[x].tva.envTime[0]); \ + DT(partial[x].tva.envTime[1]); \ + DT(partial[x].tva.envTime[2]); \ + DT(partial[x].tva.envTime[3]); \ + DT(partial[x].tva.envTime[4]); \ + DT(partial[x].tva.envLevel[0]); \ + DT(partial[x].tva.envLevel[1]); \ + DT(partial[x].tva.envLevel[2]); \ + DT(partial[x].tva.envLevel[3]); + + DTP(0); + DTP(1); + DTP(2); + DTP(3); +#undef DTP +#undef DT +#endif +#endif + // FIXME:KG: Not sure if the stuff below should be done (for rhythm and/or parts)... + // Does the real MT-32 automatically do this? + for (unsigned int part = 0; part < 9; part++) { + if (parts[part] != NULL) { + parts[part]->refreshTimbre(i); + } + } + } + break; + case MR_System: + region->write(0, off, data, len); + + reportHandler->onDeviceReconfig(); + // FIXME: We haven't properly confirmed any of this behaviour + // In particular, we tend to reset things such as reverb even if the write contained + // the same parameters as were already set, which may be wrong. + // On the other hand, the real thing could be resetting things even when they aren't touched + // by the write at all. +#if MT32EMU_MONITOR_SYSEX > 0 + printDebug("WRITE-SYSTEM:"); +#endif + if (off <= SYSTEM_MASTER_TUNE_OFF && off + len > SYSTEM_MASTER_TUNE_OFF) { + refreshSystemMasterTune(); + } + if (off <= SYSTEM_REVERB_LEVEL_OFF && off + len > SYSTEM_REVERB_MODE_OFF) { + refreshSystemReverbParameters(); + } + if (off <= SYSTEM_RESERVE_SETTINGS_END_OFF && off + len > SYSTEM_RESERVE_SETTINGS_START_OFF) { + refreshSystemReserveSettings(); + } + if (off <= SYSTEM_CHAN_ASSIGN_END_OFF && off + len > SYSTEM_CHAN_ASSIGN_START_OFF) { + int firstPart = off - SYSTEM_CHAN_ASSIGN_START_OFF; + if(firstPart < 0) + firstPart = 0; + int lastPart = off + len - SYSTEM_CHAN_ASSIGN_START_OFF; + if(lastPart > 8) + lastPart = 8; + refreshSystemChanAssign(Bit8u(firstPart), Bit8u(lastPart)); + } + if (off <= SYSTEM_MASTER_VOL_OFF && off + len > SYSTEM_MASTER_VOL_OFF) { + refreshSystemMasterVol(); + } + break; + case MR_Display: + char buf[SYSEX_BUFFER_SIZE]; + memcpy(&buf, &data[0], len); + buf[len] = 0; +#if MT32EMU_MONITOR_SYSEX > 0 + printDebug("WRITE-LCD: %s", buf); +#endif + reportHandler->showLCDMessage(buf); + break; + case MR_Reset: + reset(); + break; + } +} + +void Synth::refreshSystemMasterTune() { +#if MT32EMU_MONITOR_SYSEX > 0 + //FIXME:KG: This is just an educated guess. + // The LAPC-I documentation claims a range of 427.5Hz-452.6Hz (similar to what we have here) + // The MT-32 documentation claims a range of 432.1Hz-457.6Hz + float masterTune = 440.0f * EXP2F((mt32ram.system.masterTune - 64.0f) / (128.0f * 12.0f)); + printDebug(" Master Tune: %f", masterTune); +#endif +} + +void Synth::refreshSystemReverbParameters() { +#if MT32EMU_MONITOR_SYSEX > 0 + printDebug(" Reverb: mode=%d, time=%d, level=%d", mt32ram.system.reverbMode, mt32ram.system.reverbTime, mt32ram.system.reverbLevel); +#endif + if (reverbOverridden) { +#if MT32EMU_MONITOR_SYSEX > 0 + printDebug(" (Reverb overridden - ignoring)"); +#endif + return; + } + reportHandler->onNewReverbMode(mt32ram.system.reverbMode); + reportHandler->onNewReverbTime(mt32ram.system.reverbTime); + reportHandler->onNewReverbLevel(mt32ram.system.reverbLevel); + + BReverbModel *oldReverbModel = reverbModel; + if (mt32ram.system.reverbTime == 0 && mt32ram.system.reverbLevel == 0) { + // Setting both time and level to 0 effectively disables wet reverb output on real devices. + // Take a shortcut in this case to reduce CPU load. + reverbModel = NULL; + } else { + reverbModel = reverbModels[mt32ram.system.reverbMode]; + } + if (reverbModel != oldReverbModel) { +#if MT32EMU_REDUCE_REVERB_MEMORY + if (oldReverbModel != NULL) { + oldReverbModel->close(); + } + if (isReverbEnabled()) { + reverbModel->open(); + } +#else + if (isReverbEnabled()) { + reverbModel->mute(); + } +#endif + } + if (isReverbEnabled()) { + reverbModel->setParameters(mt32ram.system.reverbTime, mt32ram.system.reverbLevel); + } +} + +void Synth::refreshSystemReserveSettings() { + Bit8u *rset = mt32ram.system.reserveSettings; +#if MT32EMU_MONITOR_SYSEX > 0 + printDebug(" Partial reserve: 1=%02d 2=%02d 3=%02d 4=%02d 5=%02d 6=%02d 7=%02d 8=%02d Rhythm=%02d", rset[0], rset[1], rset[2], rset[3], rset[4], rset[5], rset[6], rset[7], rset[8]); +#endif + partialManager->setReserve(rset); +} + +void Synth::refreshSystemChanAssign(Bit8u firstPart, Bit8u lastPart) { + memset(chantable, 0xFF, sizeof(chantable)); + + // CONFIRMED: In the case of assigning a channel to multiple parts, the lower part wins. + for (Bit32u i = 0; i <= 8; i++) { + if (parts[i] != NULL && i >= firstPart && i <= lastPart) { + // CONFIRMED: Decay is started for all polys, and all controllers are reset, for every part whose assignment was touched by the sysex write. + parts[i]->allSoundOff(); + parts[i]->resetAllControllers(); + } + Bit8u chan = mt32ram.system.chanAssign[i]; + if (chan < 16 && chantable[chan] > 8) { + chantable[chan] = Bit8u(i); + } + } + +#if MT32EMU_MONITOR_SYSEX > 0 + Bit8u *rset = mt32ram.system.chanAssign; + printDebug(" Part assign: 1=%02d 2=%02d 3=%02d 4=%02d 5=%02d 6=%02d 7=%02d 8=%02d Rhythm=%02d", rset[0], rset[1], rset[2], rset[3], rset[4], rset[5], rset[6], rset[7], rset[8]); +#endif +} + +void Synth::refreshSystemMasterVol() { +#if MT32EMU_MONITOR_SYSEX > 0 + printDebug(" Master volume: %d", mt32ram.system.masterVol); +#endif +} + +void Synth::refreshSystem() { + refreshSystemMasterTune(); + refreshSystemReverbParameters(); + refreshSystemReserveSettings(); + refreshSystemChanAssign(0, 8); + refreshSystemMasterVol(); +} + +void Synth::reset() { + if (!opened) return; +#if MT32EMU_MONITOR_SYSEX > 0 + printDebug("RESET"); +#endif + reportHandler->onDeviceReset(); + partialManager->deactivateAll(); + mt32ram = mt32default; + for (int i = 0; i < 9; i++) { + parts[i]->reset(); + if (i != 8) { + parts[i]->setProgram(controlROMData[controlROMMap->programSettings + i]); + } else { + parts[8]->refresh(); + } + } + refreshSystem(); + isActive(); +} + +MidiEvent::~MidiEvent() { + if (sysexData != NULL) { + delete[] sysexData; + } +} + +void MidiEvent::setShortMessage(Bit32u useShortMessageData, Bit32u useTimestamp) { + if (sysexData != NULL) { + delete[] sysexData; + } + shortMessageData = useShortMessageData; + timestamp = useTimestamp; + sysexData = NULL; + sysexLength = 0; +} + +void MidiEvent::setSysex(const Bit8u *useSysexData, Bit32u useSysexLength, Bit32u useTimestamp) { + if (sysexData != NULL) { + delete[] sysexData; + } + shortMessageData = 0; + timestamp = useTimestamp; + sysexLength = useSysexLength; + Bit8u *dstSysexData = new Bit8u[sysexLength]; + sysexData = dstSysexData; + memcpy(dstSysexData, useSysexData, sysexLength); +} + +MidiEventQueue::MidiEventQueue(Bit32u useRingBufferSize) : ringBuffer(new MidiEvent[useRingBufferSize]), ringBufferMask(useRingBufferSize - 1) { + memset(ringBuffer, 0, useRingBufferSize * sizeof(MidiEvent)); + reset(); +} + +MidiEventQueue::~MidiEventQueue() { + delete[] ringBuffer; +} + +void MidiEventQueue::reset() { + startPosition = 0; + endPosition = 0; +} + +bool MidiEventQueue::pushShortMessage(Bit32u shortMessageData, Bit32u timestamp) { + Bit32u newEndPosition = (endPosition + 1) & ringBufferMask; + // Is ring buffer full? + if (startPosition == newEndPosition) return false; + ringBuffer[endPosition].setShortMessage(shortMessageData, timestamp); + endPosition = newEndPosition; + return true; +} + +bool MidiEventQueue::pushSysex(const Bit8u *sysexData, Bit32u sysexLength, Bit32u timestamp) { + Bit32u newEndPosition = (endPosition + 1) & ringBufferMask; + // Is ring buffer full? + if (startPosition == newEndPosition) return false; + ringBuffer[endPosition].setSysex(sysexData, sysexLength, timestamp); + endPosition = newEndPosition; + return true; +} + +const MidiEvent *MidiEventQueue::peekMidiEvent() { + return isEmpty() ? NULL : &ringBuffer[startPosition]; +} + +void MidiEventQueue::dropMidiEvent() { + // Is ring buffer empty? + if (startPosition != endPosition) { + startPosition = (startPosition + 1) & ringBufferMask; + } +} + +bool MidiEventQueue::isFull() const { + return startPosition == ((endPosition + 1) & ringBufferMask); +} + +bool MidiEventQueue::isEmpty() const { + return startPosition == endPosition; +} + +void Synth::selectRendererType(RendererType newRendererType) { + extensions.selectedRendererType = newRendererType; +} + +RendererType Synth::getSelectedRendererType() const { + return extensions.selectedRendererType; +} + +Bit32u Synth::getStereoOutputSampleRate() const { + return (analog == NULL) ? SAMPLE_RATE : analog->getOutputSampleRate(); +} + +template +void RendererImpl::doRender(Sample *stereoStream, Bit32u len) { + if (!isActivated()) { + incRenderedSampleCount(getAnalog().getDACStreamsLength(len)); + if (!getAnalog().process(NULL, NULL, NULL, NULL, NULL, NULL, stereoStream, len)) { + printDebug("RendererImpl: Invalid call to Analog::process()!\n"); + } + Synth::muteSampleBuffer(stereoStream, len << 1); + return; + } + + while (len > 0) { + // As in AnalogOutputMode_ACCURATE mode output is upsampled, MAX_SAMPLES_PER_RUN is more than enough for the temp buffers. + Bit32u thisPassLen = len > MAX_SAMPLES_PER_RUN ? MAX_SAMPLES_PER_RUN : len; + doRenderStreams(tmpBuffers, getAnalog().getDACStreamsLength(thisPassLen)); + if (!getAnalog().process(stereoStream, tmpNonReverbLeft, tmpNonReverbRight, tmpReverbDryLeft, tmpReverbDryRight, tmpReverbWetLeft, tmpReverbWetRight, thisPassLen)) { + printDebug("RendererImpl: Invalid call to Analog::process()!\n"); + Synth::muteSampleBuffer(stereoStream, len << 1); + return; + } + stereoStream += thisPassLen << 1; + len -= thisPassLen; + } +} + +template +template +void RendererImpl::doRenderAndConvert(O *stereoStream, Bit32u len) { + Sample renderingBuffer[MAX_SAMPLES_PER_RUN << 1]; + while (len > 0) { + Bit32u thisPassLen = len > MAX_SAMPLES_PER_RUN ? MAX_SAMPLES_PER_RUN : len; + doRender(renderingBuffer, thisPassLen); + convertSampleFormat(renderingBuffer, stereoStream, thisPassLen << 1); + stereoStream += thisPassLen << 1; + len -= thisPassLen; + } +} + +template<> +void RendererImpl::render(IntSample *stereoStream, Bit32u len) { + doRender(stereoStream, len); +} + +template<> +void RendererImpl::render(FloatSample *stereoStream, Bit32u len) { + doRenderAndConvert(stereoStream, len); +} + +template<> +void RendererImpl::render(IntSample *stereoStream, Bit32u len) { + doRenderAndConvert(stereoStream, len); +} + +template<> +void RendererImpl::render(FloatSample *stereoStream, Bit32u len) { + doRender(stereoStream, len); +} + +template +static inline void renderStereo(bool opened, Renderer *renderer, S *stream, Bit32u len) { + if (opened) { + renderer->render(stream, len); + } else { + Synth::muteSampleBuffer(stream, len << 1); + } +} + +void Synth::render(Bit16s *stream, Bit32u len) { + renderStereo(opened, renderer, stream, len); +} + +void Synth::render(float *stream, Bit32u len) { + renderStereo(opened, renderer, stream, len); +} + +template +static inline void advanceStream(Sample *&stream, Bit32u len) { + if (stream != NULL) { + stream += len; + } +} + +template +static inline void advanceStreams(DACOutputStreams &streams, Bit32u len) { + advanceStream(streams.nonReverbLeft, len); + advanceStream(streams.nonReverbRight, len); + advanceStream(streams.reverbDryLeft, len); + advanceStream(streams.reverbDryRight, len); + advanceStream(streams.reverbWetLeft, len); + advanceStream(streams.reverbWetRight, len); +} + +template +static inline void muteStreams(const DACOutputStreams &streams, Bit32u len) { + Synth::muteSampleBuffer(streams.nonReverbLeft, len); + Synth::muteSampleBuffer(streams.nonReverbRight, len); + Synth::muteSampleBuffer(streams.reverbDryLeft, len); + Synth::muteSampleBuffer(streams.reverbDryRight, len); + Synth::muteSampleBuffer(streams.reverbWetLeft, len); + Synth::muteSampleBuffer(streams.reverbWetRight, len); +} + +template +static inline void convertStreamsFormat(const DACOutputStreams &inStreams, const DACOutputStreams &outStreams, Bit32u len) { + convertSampleFormat(inStreams.nonReverbLeft, outStreams.nonReverbLeft, len); + convertSampleFormat(inStreams.nonReverbRight, outStreams.nonReverbRight, len); + convertSampleFormat(inStreams.reverbDryLeft, outStreams.reverbDryLeft, len); + convertSampleFormat(inStreams.reverbDryRight, outStreams.reverbDryRight, len); + convertSampleFormat(inStreams.reverbWetLeft, outStreams.reverbWetLeft, len); + convertSampleFormat(inStreams.reverbWetRight, outStreams.reverbWetRight, len); +} + +template +void RendererImpl::doRenderStreams(const DACOutputStreams &streams, Bit32u len) +{ + DACOutputStreams tmpStreams = streams; + while (len > 0) { + // We need to ensure zero-duration notes will play so add minimum 1-sample delay. + Bit32u thisLen = 1; + if (!isAbortingPoly()) { + const MidiEvent *nextEvent = getMidiQueue().peekMidiEvent(); + Bit32s samplesToNextEvent = (nextEvent != NULL) ? Bit32s(nextEvent->timestamp - getRenderedSampleCount()) : MAX_SAMPLES_PER_RUN; + if (samplesToNextEvent > 0) { + thisLen = len > MAX_SAMPLES_PER_RUN ? MAX_SAMPLES_PER_RUN : len; + if (thisLen > Bit32u(samplesToNextEvent)) { + thisLen = samplesToNextEvent; + } + } else { + if (nextEvent->sysexData == NULL) { + synth.playMsgNow(nextEvent->shortMessageData); + // If a poly is aborting we don't drop the event from the queue. + // Instead, we'll return to it again when the abortion is done. + if (!isAbortingPoly()) { + getMidiQueue().dropMidiEvent(); + } + } else { + synth.playSysexNow(nextEvent->sysexData, nextEvent->sysexLength); + getMidiQueue().dropMidiEvent(); + } + } + } + produceStreams(tmpStreams, thisLen); + advanceStreams(tmpStreams, thisLen); + len -= thisLen; + } +} + +template +template +void RendererImpl::doRenderAndConvertStreams(const DACOutputStreams &streams, Bit32u len) { + Sample cnvNonReverbLeft[MAX_SAMPLES_PER_RUN], cnvNonReverbRight[MAX_SAMPLES_PER_RUN]; + Sample cnvReverbDryLeft[MAX_SAMPLES_PER_RUN], cnvReverbDryRight[MAX_SAMPLES_PER_RUN]; + Sample cnvReverbWetLeft[MAX_SAMPLES_PER_RUN], cnvReverbWetRight[MAX_SAMPLES_PER_RUN]; + + const DACOutputStreams cnvStreams = { + cnvNonReverbLeft, cnvNonReverbRight, + cnvReverbDryLeft, cnvReverbDryRight, + cnvReverbWetLeft, cnvReverbWetRight + }; + + DACOutputStreams tmpStreams = streams; + + while (len > 0) { + Bit32u thisPassLen = len > MAX_SAMPLES_PER_RUN ? MAX_SAMPLES_PER_RUN : len; + doRenderStreams(cnvStreams, thisPassLen); + convertStreamsFormat(cnvStreams, tmpStreams, thisPassLen); + advanceStreams(tmpStreams, thisPassLen); + len -= thisPassLen; + } +} + +template<> +void RendererImpl::renderStreams(const DACOutputStreams &streams, Bit32u len) { + doRenderStreams(streams, len); +} + +template<> +void RendererImpl::renderStreams(const DACOutputStreams &streams, Bit32u len) { + doRenderAndConvertStreams(streams, len); +} + +template<> +void RendererImpl::renderStreams(const DACOutputStreams &streams, Bit32u len) { + doRenderAndConvertStreams(streams, len); +} + +template<> +void RendererImpl::renderStreams(const DACOutputStreams &streams, Bit32u len) { + doRenderStreams(streams, len); +} + +template +static inline void renderStreams(bool opened, Renderer *renderer, const DACOutputStreams &streams, Bit32u len) { + if (opened) { + renderer->renderStreams(streams, len); + } else { + muteStreams(streams, len); + } +} + +void Synth::renderStreams(const DACOutputStreams &streams, Bit32u len) { + MT32Emu::renderStreams(opened, renderer, streams, len); +} + +void Synth::renderStreams(const DACOutputStreams &streams, Bit32u len) { + MT32Emu::renderStreams(opened, renderer, streams, len); +} + +void Synth::renderStreams( + Bit16s *nonReverbLeft, Bit16s *nonReverbRight, + Bit16s *reverbDryLeft, Bit16s *reverbDryRight, + Bit16s *reverbWetLeft, Bit16s *reverbWetRight, + Bit32u len) +{ + DACOutputStreams streams = { + nonReverbLeft, nonReverbRight, + reverbDryLeft, reverbDryRight, + reverbWetLeft, reverbWetRight + }; + renderStreams(streams, len); +} + +void Synth::renderStreams( + float *nonReverbLeft, float *nonReverbRight, + float *reverbDryLeft, float *reverbDryRight, + float *reverbWetLeft, float *reverbWetRight, + Bit32u len) +{ + DACOutputStreams streams = { + nonReverbLeft, nonReverbRight, + reverbDryLeft, reverbDryRight, + reverbWetLeft, reverbWetRight + }; + renderStreams(streams, len); +} + +// In GENERATION2 units, the output from LA32 goes to the Boss chip already bit-shifted. +// In NICE mode, it's also better to increase volume before the reverb processing to preserve accuracy. +template <> +void RendererImpl::produceLA32Output(IntSample *buffer, Bit32u len) { + switch (synth.getDACInputMode()) { + case DACInputMode_GENERATION2: + while (len--) { + *buffer = (*buffer & 0x8000) | ((*buffer << 1) & 0x7FFE) | ((*buffer >> 14) & 0x0001); + ++buffer; + } + break; + case DACInputMode_NICE: + while (len--) { + *buffer = Synth::clipSampleEx(IntSampleEx(*buffer) << 1); + ++buffer; + } + break; + default: + break; + } +} + +template <> +void RendererImpl::convertSamplesToOutput(IntSample *buffer, Bit32u len) { + if (synth.getDACInputMode() == DACInputMode_GENERATION1) { + while (len--) { + *buffer = IntSample((*buffer & 0x8000) | ((*buffer << 1) & 0x7FFE)); + ++buffer; + } + } +} + +static inline float produceDistortedSample(float sample) { + if (sample < -2.0f) { + return sample + 4.0f; + } else if (2.0f < sample) { + return sample - 4.0f; + } + return sample; +} + +template <> +void RendererImpl::produceLA32Output(FloatSample *buffer, Bit32u len) { + if (synth.getDACInputMode() == DACInputMode_GENERATION2) { + while (len--) { + *buffer = produceDistortedSample(*buffer); + buffer++; + } + } +} + +template <> +void RendererImpl::convertSamplesToOutput(FloatSample *buffer, Bit32u len) { + if (synth.getDACInputMode() == DACInputMode_GENERATION1) { + while (len--) { + *buffer = produceDistortedSample(*buffer); + buffer++; + } + } +} + +template +void RendererImpl::produceStreams(const DACOutputStreams &streams, Bit32u len) { + if (isActivated()) { + // Even if LA32 output isn't desired, we proceed anyway with temp buffers + Sample *nonReverbLeft = streams.nonReverbLeft == NULL ? tmpNonReverbLeft : streams.nonReverbLeft; + Sample *nonReverbRight = streams.nonReverbRight == NULL ? tmpNonReverbRight : streams.nonReverbRight; + Sample *reverbDryLeft = streams.reverbDryLeft == NULL ? tmpReverbDryLeft : streams.reverbDryLeft; + Sample *reverbDryRight = streams.reverbDryRight == NULL ? tmpReverbDryRight : streams.reverbDryRight; + + Synth::muteSampleBuffer(nonReverbLeft, len); + Synth::muteSampleBuffer(nonReverbRight, len); + Synth::muteSampleBuffer(reverbDryLeft, len); + Synth::muteSampleBuffer(reverbDryRight, len); + + for (unsigned int i = 0; i < synth.getPartialCount(); i++) { + if (getPartialManager().shouldReverb(i)) { + getPartialManager().produceOutput(i, reverbDryLeft, reverbDryRight, len); + } else { + getPartialManager().produceOutput(i, nonReverbLeft, nonReverbRight, len); + } + } + + produceLA32Output(reverbDryLeft, len); + produceLA32Output(reverbDryRight, len); + + if (synth.isReverbEnabled()) { + if (!getReverbModel().process(reverbDryLeft, reverbDryRight, streams.reverbWetLeft, streams.reverbWetRight, len)) { + printDebug("RendererImpl: Invalid call to BReverbModel::process()!\n"); + } + if (streams.reverbWetLeft != NULL) convertSamplesToOutput(streams.reverbWetLeft, len); + if (streams.reverbWetRight != NULL) convertSamplesToOutput(streams.reverbWetRight, len); + } else { + Synth::muteSampleBuffer(streams.reverbWetLeft, len); + Synth::muteSampleBuffer(streams.reverbWetRight, len); + } + + // Don't bother with conversion if the output is going to be unused + if (streams.nonReverbLeft != NULL) { + produceLA32Output(nonReverbLeft, len); + convertSamplesToOutput(nonReverbLeft, len); + } + if (streams.nonReverbRight != NULL) { + produceLA32Output(nonReverbRight, len); + convertSamplesToOutput(nonReverbRight, len); + } + if (streams.reverbDryLeft != NULL) convertSamplesToOutput(reverbDryLeft, len); + if (streams.reverbDryRight != NULL) convertSamplesToOutput(reverbDryRight, len); + } else { + muteStreams(streams, len); + } + + getPartialManager().clearAlreadyOutputed(); + incRenderedSampleCount(len); +} + +void Synth::printPartialUsage(Bit32u sampleOffset) { + unsigned int partialUsage[9]; + partialManager->getPerPartPartialUsage(partialUsage); + if (sampleOffset > 0) { + printDebug("[+%u] Partial Usage: 1:%02d 2:%02d 3:%02d 4:%02d 5:%02d 6:%02d 7:%02d 8:%02d R: %02d TOTAL: %02d", sampleOffset, partialUsage[0], partialUsage[1], partialUsage[2], partialUsage[3], partialUsage[4], partialUsage[5], partialUsage[6], partialUsage[7], partialUsage[8], getPartialCount() - partialManager->getFreePartialCount()); + } else { + printDebug("Partial Usage: 1:%02d 2:%02d 3:%02d 4:%02d 5:%02d 6:%02d 7:%02d 8:%02d R: %02d TOTAL: %02d", partialUsage[0], partialUsage[1], partialUsage[2], partialUsage[3], partialUsage[4], partialUsage[5], partialUsage[6], partialUsage[7], partialUsage[8], getPartialCount() - partialManager->getFreePartialCount()); + } +} + +bool Synth::hasActivePartials() const { + if (!opened) { + return false; + } + for (unsigned int partialNum = 0; partialNum < getPartialCount(); partialNum++) { + if (partialManager->getPartial(partialNum)->isActive()) { + return true; + } + } + return false; +} + +bool Synth::isActive() { + if (!opened) { + return false; + } + if (!midiQueue->isEmpty() || hasActivePartials()) { + return true; + } + if (isReverbEnabled() && reverbModel->isActive()) { + return true; + } + activated = false; + return false; +} + +Bit32u Synth::getPartialCount() const { + return partialCount; +} + +void Synth::getPartStates(bool *partStates) const { + if (!opened) { + memset(partStates, 0, 9 * sizeof(bool)); + return; + } + for (int partNumber = 0; partNumber < 9; partNumber++) { + const Part *part = parts[partNumber]; + partStates[partNumber] = part->getActiveNonReleasingPartialCount() > 0; + } +} + +Bit32u Synth::getPartStates() const { + if (!opened) return 0; + bool partStates[9]; + getPartStates(partStates); + Bit32u bitSet = 0; + for (int partNumber = 8; partNumber >= 0; partNumber--) { + bitSet = (bitSet << 1) | (partStates[partNumber] ? 1 : 0); + } + return bitSet; +} + +void Synth::getPartialStates(PartialState *partialStates) const { + if (!opened) { + memset(partialStates, 0, partialCount * sizeof(PartialState)); + return; + } + for (unsigned int partialNum = 0; partialNum < partialCount; partialNum++) { + partialStates[partialNum] = getPartialState(partialManager, partialNum); + } +} + +void Synth::getPartialStates(Bit8u *partialStates) const { + if (!opened) { + memset(partialStates, 0, ((partialCount + 3) >> 2)); + return; + } + for (unsigned int quartNum = 0; (4 * quartNum) < partialCount; quartNum++) { + Bit8u packedStates = 0; + for (unsigned int i = 0; i < 4; i++) { + unsigned int partialNum = (4 * quartNum) + i; + if (partialCount <= partialNum) break; + PartialState partialState = getPartialState(partialManager, partialNum); + packedStates |= (partialState & 3) << (2 * i); + } + partialStates[quartNum] = packedStates; + } +} + +Bit32u Synth::getPlayingNotes(Bit8u partNumber, Bit8u *keys, Bit8u *velocities) const { + Bit32u playingNotes = 0; + if (opened && (partNumber < 9)) { + const Part *part = parts[partNumber]; + const Poly *poly = part->getFirstActivePoly(); + while (poly != NULL) { + keys[playingNotes] = Bit8u(poly->getKey()); + velocities[playingNotes] = Bit8u(poly->getVelocity()); + playingNotes++; + poly = poly->getNext(); + } + } + return playingNotes; +} + +const char *Synth::getPatchName(Bit8u partNumber) const { + return (!opened || partNumber > 8) ? NULL : parts[partNumber]->getCurrentInstr(); +} + +const Part *Synth::getPart(Bit8u partNum) const { + if (partNum > 8) { + return NULL; + } + return parts[partNum]; +} + +void MemoryRegion::read(unsigned int entry, unsigned int off, Bit8u *dst, unsigned int len) const { + off += entry * entrySize; + // This method should never be called with out-of-bounds parameters, + // or on an unsupported region - seeing any of this debug output indicates a bug in the emulator + if (off > entrySize * entries - 1) { +#if MT32EMU_MONITOR_SYSEX > 0 + synth->printDebug("read[%d]: parameters start out of bounds: entry=%d, off=%d, len=%d", type, entry, off, len); +#endif + return; + } + if (off + len > entrySize * entries) { +#if MT32EMU_MONITOR_SYSEX > 0 + synth->printDebug("read[%d]: parameters end out of bounds: entry=%d, off=%d, len=%d", type, entry, off, len); +#endif + len = entrySize * entries - off; + } + Bit8u *src = getRealMemory(); + if (src == NULL) { +#if MT32EMU_MONITOR_SYSEX > 0 + synth->printDebug("read[%d]: unreadable region: entry=%d, off=%d, len=%d", type, entry, off, len); +#endif + return; + } + memcpy(dst, src + off, len); +} + +void MemoryRegion::write(unsigned int entry, unsigned int off, const Bit8u *src, unsigned int len, bool init) const { + unsigned int memOff = entry * entrySize + off; + // This method should never be called with out-of-bounds parameters, + // or on an unsupported region - seeing any of this debug output indicates a bug in the emulator + if (off > entrySize * entries - 1) { +#if MT32EMU_MONITOR_SYSEX > 0 + synth->printDebug("write[%d]: parameters start out of bounds: entry=%d, off=%d, len=%d", type, entry, off, len); +#endif + return; + } + if (off + len > entrySize * entries) { +#if MT32EMU_MONITOR_SYSEX > 0 + synth->printDebug("write[%d]: parameters end out of bounds: entry=%d, off=%d, len=%d", type, entry, off, len); +#endif + len = entrySize * entries - off; + } + Bit8u *dest = getRealMemory(); + if (dest == NULL) { +#if MT32EMU_MONITOR_SYSEX > 0 + synth->printDebug("write[%d]: unwritable region: entry=%d, off=%d, len=%d", type, entry, off, len); +#endif + return; + } + + for (unsigned int i = 0; i < len; i++) { + Bit8u desiredValue = src[i]; + Bit8u maxValue = getMaxValue(memOff); + // maxValue == 0 means write-protected unless called from initialisation code, in which case it really means the maximum value is 0. + if (maxValue != 0 || init) { + if (desiredValue > maxValue) { +#if MT32EMU_MONITOR_SYSEX > 0 + synth->printDebug("write[%d]: Wanted 0x%02x at %d, but max 0x%02x", type, desiredValue, memOff, maxValue); +#endif + desiredValue = maxValue; + } + dest[memOff] = desiredValue; + } else if (desiredValue != 0) { +#if MT32EMU_MONITOR_SYSEX > 0 + // Only output debug info if they wanted to write non-zero, since a lot of things cause this to spit out a lot of debug info otherwise. + synth->printDebug("write[%d]: Wanted 0x%02x at %d, but write-protected", type, desiredValue, memOff); +#endif + } + memOff++; + } +} + +} // namespace MT32Emu diff --git a/src/SOUND/munt/Synth.h b/src/SOUND/munt/Synth.h new file mode 100644 index 000000000..4ce023201 --- /dev/null +++ b/src/SOUND/munt/Synth.h @@ -0,0 +1,484 @@ +/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher + * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#ifndef MT32EMU_SYNTH_H +#define MT32EMU_SYNTH_H + +#include +#include +#include + +#include "globals.h" +#include "Types.h" +#include "Enumerations.h" + +namespace MT32Emu { + +class Analog; +class BReverbModel; +class Extensions; +class MemoryRegion; +class MidiEventQueue; +class Part; +class Poly; +class Partial; +class PartialManager; +class Renderer; +class ROMImage; + +class PatchTempMemoryRegion; +class RhythmTempMemoryRegion; +class TimbreTempMemoryRegion; +class PatchesMemoryRegion; +class TimbresMemoryRegion; +class SystemMemoryRegion; +class DisplayMemoryRegion; +class ResetMemoryRegion; + +struct ControlROMFeatureSet; +struct ControlROMMap; +struct PCMWaveEntry; +struct MemParams; + +const Bit8u SYSEX_MANUFACTURER_ROLAND = 0x41; + +const Bit8u SYSEX_MDL_MT32 = 0x16; +const Bit8u SYSEX_MDL_D50 = 0x14; + +const Bit8u SYSEX_CMD_RQ1 = 0x11; // Request data #1 +const Bit8u SYSEX_CMD_DT1 = 0x12; // Data set 1 +const Bit8u SYSEX_CMD_WSD = 0x40; // Want to send data +const Bit8u SYSEX_CMD_RQD = 0x41; // Request data +const Bit8u SYSEX_CMD_DAT = 0x42; // Data set +const Bit8u SYSEX_CMD_ACK = 0x43; // Acknowledge +const Bit8u SYSEX_CMD_EOD = 0x45; // End of data +const Bit8u SYSEX_CMD_ERR = 0x4E; // Communications error +const Bit8u SYSEX_CMD_RJC = 0x4F; // Rejection + +const Bit32u CONTROL_ROM_SIZE = 64 * 1024; + +// Set of multiplexed output streams appeared at the DAC entrance. +template +struct DACOutputStreams { + T *nonReverbLeft; + T *nonReverbRight; + T *reverbDryLeft; + T *reverbDryRight; + T *reverbWetLeft; + T *reverbWetRight; +}; + +// Class for the client to supply callbacks for reporting various errors and information +class MT32EMU_EXPORT ReportHandler { +public: + virtual ~ReportHandler() {} + + // Callback for debug messages, in vprintf() format + virtual void printDebug(const char *fmt, va_list list); + // Callbacks for reporting errors + virtual void onErrorControlROM() {} + virtual void onErrorPCMROM() {} + // Callback for reporting about displaying a new custom message on LCD + virtual void showLCDMessage(const char *message); + // Callback for reporting actual processing of a MIDI message + virtual void onMIDIMessagePlayed() {} + // Callback for reporting an overflow of the input MIDI queue. + // Returns true if a recovery action was taken and yet another attempt to enqueue the MIDI event is desired. + virtual bool onMIDIQueueOverflow() { return false; } + // Callback invoked when a System Realtime MIDI message is detected at the input. + virtual void onMIDISystemRealtime(Bit8u /* systemRealtime */) {} + // Callbacks for reporting system events + virtual void onDeviceReset() {} + virtual void onDeviceReconfig() {} + // Callbacks for reporting changes of reverb settings + virtual void onNewReverbMode(Bit8u /* mode */) {} + virtual void onNewReverbTime(Bit8u /* time */) {} + virtual void onNewReverbLevel(Bit8u /* level */) {} + // Callbacks for reporting various information + virtual void onPolyStateChanged(Bit8u /* partNum */) {} + virtual void onProgramChanged(Bit8u /* partNum */, const char * /* soundGroupName */, const char * /* patchName */) {} +}; + +class Synth { +friend class DefaultMidiStreamParser; +friend class Part; +friend class Partial; +friend class PartialManager; +friend class Poly; +friend class Renderer; +friend class RhythmPart; +friend class SamplerateAdapter; +friend class SoxrAdapter; +friend class TVA; +friend class TVP; + +private: + // **************************** Implementation fields ************************** + + PatchTempMemoryRegion *patchTempMemoryRegion; + RhythmTempMemoryRegion *rhythmTempMemoryRegion; + TimbreTempMemoryRegion *timbreTempMemoryRegion; + PatchesMemoryRegion *patchesMemoryRegion; + TimbresMemoryRegion *timbresMemoryRegion; + SystemMemoryRegion *systemMemoryRegion; + DisplayMemoryRegion *displayMemoryRegion; + ResetMemoryRegion *resetMemoryRegion; + + Bit8u *paddedTimbreMaxTable; + + PCMWaveEntry *pcmWaves; // Array + + const ControlROMFeatureSet *controlROMFeatures; + const ControlROMMap *controlROMMap; + Bit8u controlROMData[CONTROL_ROM_SIZE]; + Bit16s *pcmROMData; + size_t pcmROMSize; // This is in 16-bit samples, therefore half the number of bytes in the ROM + + Bit8u soundGroupIx[128]; // For each standard timbre + const char (*soundGroupNames)[9]; // Array + + Bit32u partialCount; + Bit8u chantable[16]; // NOTE: value above 8 means that the channel is not assigned + + MidiEventQueue *midiQueue; + volatile Bit32u lastReceivedMIDIEventTimestamp; + volatile Bit32u renderedSampleCount; + + MemParams &mt32ram, &mt32default; + + BReverbModel *reverbModels[4]; + BReverbModel *reverbModel; + bool reverbOverridden; + + MIDIDelayMode midiDelayMode; + DACInputMode dacInputMode; + + float outputGain; + float reverbOutputGain; + + bool reversedStereoEnabled; + + bool opened; + bool activated; + + bool isDefaultReportHandler; + ReportHandler *reportHandler; + + PartialManager *partialManager; + Part *parts[9]; + + // When a partial needs to be aborted to free it up for use by a new Poly, + // the controller will busy-loop waiting for the sound to finish. + // We emulate this by delaying new MIDI events processing until abortion finishes. + Poly *abortingPoly; + + Analog *analog; + Renderer *renderer; + + // Binary compatibility helper. + Extensions &extensions; + + // **************************** Implementation methods ************************** + + Bit32u addMIDIInterfaceDelay(Bit32u len, Bit32u timestamp); + bool isAbortingPoly() const { return abortingPoly != NULL; } + + void readSysex(Bit8u channel, const Bit8u *sysex, Bit32u len) const; + void initMemoryRegions(); + void deleteMemoryRegions(); + MemoryRegion *findMemoryRegion(Bit32u addr); + void writeMemoryRegion(const MemoryRegion *region, Bit32u addr, Bit32u len, const Bit8u *data); + void readMemoryRegion(const MemoryRegion *region, Bit32u addr, Bit32u len, Bit8u *data); + + bool loadControlROM(const ROMImage &controlROMImage); + bool loadPCMROM(const ROMImage &pcmROMImage); + + bool initPCMList(Bit16u mapAddress, Bit16u count); + bool initTimbres(Bit16u mapAddress, Bit16u offset, Bit16u timbreCount, Bit16u startTimbre, bool compressed); + bool initCompressedTimbre(Bit16u drumNum, const Bit8u *mem, Bit32u memLen); + void initReverbModels(bool mt32CompatibleMode); + void initSoundGroups(char newSoundGroupNames[][9]); + + void refreshSystemMasterTune(); + void refreshSystemReverbParameters(); + void refreshSystemReserveSettings(); + void refreshSystemChanAssign(Bit8u firstPart, Bit8u lastPart); + void refreshSystemMasterVol(); + void refreshSystem(); + void reset(); + void dispose(); + + void printPartialUsage(Bit32u sampleOffset = 0); + + void newTimbreSet(Bit8u partNum, Bit8u timbreGroup, Bit8u timbreNumber, const char patchName[]); + void printDebug(const char *fmt, ...); + + // partNum should be 0..7 for Part 1..8, or 8 for Rhythm + const Part *getPart(Bit8u partNum) const; + +public: + static inline Bit16s clipSampleEx(Bit32s sampleEx) { + // Clamp values above 32767 to 32767, and values below -32768 to -32768 + // FIXME: Do we really need this stuff? I think these branches are very well predicted. Instead, this introduces a chain. + // The version below is actually a bit faster on my system... + //return ((sampleEx + 0x8000) & ~0xFFFF) ? Bit16s((sampleEx >> 31) ^ 0x7FFF) : (Bit16s)sampleEx; + return ((-0x8000 <= sampleEx) && (sampleEx <= 0x7FFF)) ? Bit16s(sampleEx) : Bit16s((sampleEx >> 31) ^ 0x7FFF); + } + + static inline float clipSampleEx(float sampleEx) { + return sampleEx; + } + + template + static inline void muteSampleBuffer(S *buffer, Bit32u len) { + if (buffer == NULL) return; + memset(buffer, 0, len * sizeof(S)); + } + + static inline void muteSampleBuffer(float *buffer, Bit32u len) { + if (buffer == NULL) return; + // FIXME: Use memset() where compatibility is guaranteed (if this turns out to be a win) + while (len--) { + *(buffer++) = 0.0f; + } + } + + static inline Bit16s convertSample(float sample) { + return Synth::clipSampleEx(Bit32s(sample * 16384.0f)); // This multiplier takes into account the DAC bit shift + } + + static inline float convertSample(Bit16s sample) { + return float(sample) / 16384.0f; // This multiplier takes into account the DAC bit shift + } + + // Returns library version as an integer in format: 0x00MMmmpp, where: + // MM - major version number + // mm - minor version number + // pp - patch number + MT32EMU_EXPORT static Bit32u getLibraryVersionInt(); + // Returns library version as a C-string in format: "MAJOR.MINOR.PATCH" + MT32EMU_EXPORT static const char *getLibraryVersionString(); + + MT32EMU_EXPORT static Bit32u getShortMessageLength(Bit32u msg); + MT32EMU_EXPORT static Bit8u calcSysexChecksum(const Bit8u *data, const Bit32u len, const Bit8u initChecksum = 0); + + // Returns output sample rate used in emulation of stereo analog circuitry of hardware units. + // See comment for AnalogOutputMode. + MT32EMU_EXPORT static Bit32u getStereoOutputSampleRate(AnalogOutputMode analogOutputMode); + + // Optionally sets callbacks for reporting various errors, information and debug messages + MT32EMU_EXPORT explicit Synth(ReportHandler *useReportHandler = NULL); + MT32EMU_EXPORT ~Synth(); + + // Used to initialise the MT-32. Must be called before any other function. + // Returns true if initialization was sucessful, otherwise returns false. + // controlROMImage and pcmROMImage represent Control and PCM ROM images for use by synth. + // usePartialCount sets the maximum number of partials playing simultaneously for this session (optional). + // analogOutputMode sets the mode for emulation of analogue circuitry of the hardware units (optional). + MT32EMU_EXPORT bool open(const ROMImage &controlROMImage, const ROMImage &pcmROMImage, Bit32u usePartialCount = DEFAULT_MAX_PARTIALS, AnalogOutputMode analogOutputMode = AnalogOutputMode_COARSE); + + // Overloaded method which opens the synth with default partial count. + MT32EMU_EXPORT bool open(const ROMImage &controlROMImage, const ROMImage &pcmROMImage, AnalogOutputMode analogOutputMode); + + // Closes the MT-32 and deallocates any memory used by the synthesizer + MT32EMU_EXPORT void close(); + + // Returns true if the synth is in completely initialized state, otherwise returns false. + MT32EMU_EXPORT bool isOpen() const; + + // All the enqueued events are processed by the synth immediately. + MT32EMU_EXPORT void flushMIDIQueue(); + + // Sets size of the internal MIDI event queue. The queue size is set to the minimum power of 2 that is greater or equal to the size specified. + // The queue is flushed before reallocation. + // Returns the actual queue size being used. + MT32EMU_EXPORT Bit32u setMIDIEventQueueSize(Bit32u); + + // Enqueues a MIDI event for subsequent playback. + // The MIDI event will be processed not before the specified timestamp. + // The timestamp is measured as the global rendered sample count since the synth was created (at the native sample rate 32000 Hz). + // The minimum delay involves emulation of the delay introduced while the event is transferred via MIDI interface + // and emulation of the MCU busy-loop while it frees partials for use by a new Poly. + // Calls from multiple threads must be synchronised, although, no synchronisation is required with the rendering thread. + // The methods return false if the MIDI event queue is full and the message cannot be enqueued. + + // Enqueues a single short MIDI message to play at specified time. The message must contain a status byte. + MT32EMU_EXPORT bool playMsg(Bit32u msg, Bit32u timestamp); + // Enqueues a single well formed System Exclusive MIDI message to play at specified time. + MT32EMU_EXPORT bool playSysex(const Bit8u *sysex, Bit32u len, Bit32u timestamp); + + // Enqueues a single short MIDI message to be processed ASAP. The message must contain a status byte. + MT32EMU_EXPORT bool playMsg(Bit32u msg); + // Enqueues a single well formed System Exclusive MIDI message to be processed ASAP. + MT32EMU_EXPORT bool playSysex(const Bit8u *sysex, Bit32u len); + + // WARNING: + // The methods below don't ensure minimum 1-sample delay between sequential MIDI events, + // and a sequence of NoteOn and immediately succeeding NoteOff messages is always silent. + // A thread that invokes these methods must be explicitly synchronised with the thread performing sample rendering. + + // Sends a short MIDI message to the synth for immediate playback. The message must contain a status byte. + // See the WARNING above. + MT32EMU_EXPORT void playMsgNow(Bit32u msg); + // Sends unpacked short MIDI message to the synth for immediate playback. The message must contain a status byte. + // See the WARNING above. + MT32EMU_EXPORT void playMsgOnPart(Bit8u part, Bit8u code, Bit8u note, Bit8u velocity); + + // Sends a single well formed System Exclusive MIDI message for immediate processing. The length is in bytes. + // See the WARNING above. + MT32EMU_EXPORT void playSysexNow(const Bit8u *sysex, Bit32u len); + // Sends inner body of a System Exclusive MIDI message for direct processing. The length is in bytes. + // See the WARNING above. + MT32EMU_EXPORT void playSysexWithoutFraming(const Bit8u *sysex, Bit32u len); + // Sends inner body of a System Exclusive MIDI message for direct processing. The length is in bytes. + // See the WARNING above. + MT32EMU_EXPORT void playSysexWithoutHeader(Bit8u device, Bit8u command, const Bit8u *sysex, Bit32u len); + // Sends inner body of a System Exclusive MIDI message for direct processing. The length is in bytes. + // See the WARNING above. + MT32EMU_EXPORT void writeSysex(Bit8u channel, const Bit8u *sysex, Bit32u len); + + // Allows to disable wet reverb output altogether. + MT32EMU_EXPORT void setReverbEnabled(bool reverbEnabled); + // Returns whether wet reverb output is enabled. + MT32EMU_EXPORT bool isReverbEnabled() const; + // Sets override reverb mode. In this mode, emulation ignores sysexes (or the related part of them) which control the reverb parameters. + // This mode is in effect until it is turned off. When the synth is re-opened, the override mode is unchanged but the state + // of the reverb model is reset to default. + MT32EMU_EXPORT void setReverbOverridden(bool reverbOverridden); + // Returns whether reverb settings are overridden. + MT32EMU_EXPORT bool isReverbOverridden() const; + // Forces reverb model compatibility mode. By default, the compatibility mode corresponds to the used control ROM version. + // Invoking this method with the argument set to true forces emulation of old MT-32 reverb circuit. + // When the argument is false, emulation of the reverb circuit used in new generation of MT-32 compatible modules is enforced + // (these include CM-32L and LAPC-I). + MT32EMU_EXPORT void setReverbCompatibilityMode(bool mt32CompatibleMode); + // Returns whether reverb is in old MT-32 compatibility mode. + MT32EMU_EXPORT bool isMT32ReverbCompatibilityMode() const; + // Returns whether default reverb compatibility mode is the old MT-32 compatibility mode. + MT32EMU_EXPORT bool isDefaultReverbMT32Compatible() const; + // Sets new DAC input mode. See DACInputMode for details. + MT32EMU_EXPORT void setDACInputMode(DACInputMode mode); + // Returns current DAC input mode. See DACInputMode for details. + MT32EMU_EXPORT DACInputMode getDACInputMode() const; + // Sets new MIDI delay mode. See MIDIDelayMode for details. + MT32EMU_EXPORT void setMIDIDelayMode(MIDIDelayMode mode); + // Returns current MIDI delay mode. See MIDIDelayMode for details. + MT32EMU_EXPORT MIDIDelayMode getMIDIDelayMode() const; + + // Sets output gain factor for synth output channels. Applied to all output samples and unrelated with the synth's Master volume, + // it rather corresponds to the gain of the output analog circuitry of the hardware units. However, together with setReverbOutputGain() + // it offers to the user a capability to control the gain of reverb and non-reverb output channels independently. + // Ignored in DACInputMode_PURE + MT32EMU_EXPORT void setOutputGain(float gain); + // Returns current output gain factor for synth output channels. + MT32EMU_EXPORT float getOutputGain() const; + + // Sets output gain factor for the reverb wet output channels. It rather corresponds to the gain of the output + // analog circuitry of the hardware units. However, together with setOutputGain() it offers to the user a capability + // to control the gain of reverb and non-reverb output channels independently. + // + // Note: We're currently emulate CM-32L/CM-64 reverb quite accurately and the reverb output level closely + // corresponds to the level of digital capture. Although, according to the CM-64 PCB schematic, + // there is a difference in the reverb analogue circuit, and the resulting output gain is 0.68 + // of that for LA32 analogue output. This factor is applied to the reverb output gain. + // Ignored in DACInputMode_PURE + MT32EMU_EXPORT void setReverbOutputGain(float gain); + // Returns current output gain factor for reverb wet output channels. + MT32EMU_EXPORT float getReverbOutputGain() const; + + // Swaps left and right output channels. + MT32EMU_EXPORT void setReversedStereoEnabled(bool enabled); + // Returns whether left and right output channels are swapped. + MT32EMU_EXPORT bool isReversedStereoEnabled() const; + + // Selects new type of the wave generator and renderer to be used during subsequent calls to open(). + // By default, RendererType_BIT16S is selected. + // See RendererType for details. + MT32EMU_EXPORT void selectRendererType(RendererType); + // Returns previously selected type of the wave generator and renderer. + // See RendererType for details. + MT32EMU_EXPORT RendererType getSelectedRendererType() const; + + // Returns actual sample rate used in emulation of stereo analog circuitry of hardware units. + // See comment for render() below. + MT32EMU_EXPORT Bit32u getStereoOutputSampleRate() const; + + // Renders samples to the specified output stream as if they were sampled at the analog stereo output. + // When AnalogOutputMode is set to ACCURATE (OVERSAMPLED), the output signal is upsampled to 48 (96) kHz in order + // to retain emulation accuracy in whole audible frequency spectra. Otherwise, native digital signal sample rate is retained. + // getStereoOutputSampleRate() can be used to query actual sample rate of the output signal. + // The length is in frames, not bytes (in 16-bit stereo, one frame is 4 bytes). Uses NATIVE byte ordering. + MT32EMU_EXPORT void render(Bit16s *stream, Bit32u len); + // Same as above but outputs to a float stereo stream. + MT32EMU_EXPORT void render(float *stream, Bit32u len); + + // Renders samples to the specified output streams as if they appeared at the DAC entrance. + // No further processing performed in analog circuitry emulation is applied to the signal. + // NULL may be specified in place of any or all of the stream buffers to skip it. + // The length is in samples, not bytes. Uses NATIVE byte ordering. + MT32EMU_EXPORT void renderStreams(Bit16s *nonReverbLeft, Bit16s *nonReverbRight, Bit16s *reverbDryLeft, Bit16s *reverbDryRight, Bit16s *reverbWetLeft, Bit16s *reverbWetRight, Bit32u len); + MT32EMU_EXPORT void renderStreams(const DACOutputStreams &streams, Bit32u len); + // Same as above but outputs to float streams. + MT32EMU_EXPORT void renderStreams(float *nonReverbLeft, float *nonReverbRight, float *reverbDryLeft, float *reverbDryRight, float *reverbWetLeft, float *reverbWetRight, Bit32u len); + MT32EMU_EXPORT void renderStreams(const DACOutputStreams &streams, Bit32u len); + + // Returns true when there is at least one active partial, otherwise false. + MT32EMU_EXPORT bool hasActivePartials() const; + + // Returns true if the synth is active and subsequent calls to render() may result in non-trivial output (i.e. silence). + // The synth is considered active when either there are pending MIDI events in the queue, there is at least one active partial, + // or the reverb is (somewhat unreliably) detected as being active. + MT32EMU_EXPORT bool isActive(); + + // Returns the maximum number of partials playing simultaneously. + MT32EMU_EXPORT Bit32u getPartialCount() const; + + // Fills in current states of all the parts into the array provided. The array must have at least 9 entries to fit values for all the parts. + // If the value returned for a part is true, there is at least one active non-releasing partial playing on this part. + // This info is useful in emulating behaviour of LCD display of the hardware units. + MT32EMU_EXPORT void getPartStates(bool *partStates) const; + + // Returns current states of all the parts as a bit set. The least significant bit corresponds to the state of part 1, + // total of 9 bits hold the states of all the parts. If the returned bit for a part is set, there is at least one active + // non-releasing partial playing on this part. This info is useful in emulating behaviour of LCD display of the hardware units. + MT32EMU_EXPORT Bit32u getPartStates() const; + + // Fills in current states of all the partials into the array provided. The array must be large enough to accommodate states of all the partials. + MT32EMU_EXPORT void getPartialStates(PartialState *partialStates) const; + + // Fills in current states of all the partials into the array provided. Each byte in the array holds states of 4 partials + // starting from the least significant bits. The state of each partial is packed in a pair of bits. + // The array must be large enough to accommodate states of all the partials (see getPartialCount()). + MT32EMU_EXPORT void getPartialStates(Bit8u *partialStates) const; + + // Fills in information about currently playing notes on the specified part into the arrays provided. The arrays must be large enough + // to accommodate data for all the playing notes. The maximum number of simultaneously playing notes cannot exceed the number of partials. + // Argument partNumber should be 0..7 for Part 1..8, or 8 for Rhythm. + // Returns the number of currently playing notes on the specified part. + MT32EMU_EXPORT Bit32u getPlayingNotes(Bit8u partNumber, Bit8u *keys, Bit8u *velocities) const; + + // Returns name of the patch set on the specified part. + // Argument partNumber should be 0..7 for Part 1..8, or 8 for Rhythm. + MT32EMU_EXPORT const char *getPatchName(Bit8u partNumber) const; + + // Stores internal state of emulated synth into an array provided (as it would be acquired from hardware). + MT32EMU_EXPORT void readMemory(Bit32u addr, Bit32u len, Bit8u *data); +}; // class Synth + +} // namespace MT32Emu + +#endif // #ifndef MT32EMU_SYNTH_H diff --git a/src/SOUND/munt/TVA.cpp b/src/SOUND/munt/TVA.cpp new file mode 100644 index 000000000..d75abe50a --- /dev/null +++ b/src/SOUND/munt/TVA.cpp @@ -0,0 +1,370 @@ +/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher + * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +/* + * This class emulates the calculations performed by the 8095 microcontroller in order to configure the LA-32's amplitude ramp for a single partial at each stage of its TVA envelope. + * Unless we introduced bugs, it should be pretty much 100% accurate according to Mok's specifications. +*/ + +#include "internals.h" + +#include "TVA.h" +#include "Part.h" +#include "Partial.h" +#include "Poly.h" +#include "Synth.h" +#include "Tables.h" + +namespace MT32Emu { + +// CONFIRMED: Matches a table in ROM - haven't got around to coming up with a formula for it yet. +static Bit8u biasLevelToAmpSubtractionCoeff[13] = {255, 187, 137, 100, 74, 54, 40, 29, 21, 15, 10, 5, 0}; + +TVA::TVA(const Partial *usePartial, LA32Ramp *useAmpRamp) : + partial(usePartial), ampRamp(useAmpRamp), system(&usePartial->getSynth()->mt32ram.system), phase(TVA_PHASE_DEAD) { +} + +void TVA::startRamp(Bit8u newTarget, Bit8u newIncrement, int newPhase) { + target = newTarget; + phase = newPhase; + ampRamp->startRamp(newTarget, newIncrement); +#if MT32EMU_MONITOR_TVA >= 1 + partial->getSynth()->printDebug("[+%lu] [Partial %d] TVA,ramp,%d,%d,%d,%d", partial->debugGetSampleNum(), partial->debugGetPartialNum(), (newIncrement & 0x80) ? -1 : 1, (newIncrement & 0x7F), newPhase); +#endif +} + +void TVA::end(int newPhase) { + phase = newPhase; + playing = false; +#if MT32EMU_MONITOR_TVA >= 1 + partial->getSynth()->printDebug("[+%lu] [Partial %d] TVA,end,%d", partial->debugGetSampleNum(), partial->debugGetPartialNum(), newPhase); +#endif +} + +static int multBias(Bit8u biasLevel, int bias) { + return (bias * biasLevelToAmpSubtractionCoeff[biasLevel]) >> 5; +} + +static int calcBiasAmpSubtraction(Bit8u biasPoint, Bit8u biasLevel, int key) { + if ((biasPoint & 0x40) == 0) { + int bias = biasPoint + 33 - key; + if (bias > 0) { + return multBias(biasLevel, bias); + } + } else { + int bias = biasPoint - 31 - key; + if (bias < 0) { + bias = -bias; + return multBias(biasLevel, bias); + } + } + return 0; +} + +static int calcBiasAmpSubtractions(const TimbreParam::PartialParam *partialParam, int key) { + int biasAmpSubtraction1 = calcBiasAmpSubtraction(partialParam->tva.biasPoint1, partialParam->tva.biasLevel1, key); + if (biasAmpSubtraction1 > 255) { + return 255; + } + int biasAmpSubtraction2 = calcBiasAmpSubtraction(partialParam->tva.biasPoint2, partialParam->tva.biasLevel2, key); + if (biasAmpSubtraction2 > 255) { + return 255; + } + int biasAmpSubtraction = biasAmpSubtraction1 + biasAmpSubtraction2; + if (biasAmpSubtraction > 255) { + return 255; + } + return biasAmpSubtraction; +} + +static int calcVeloAmpSubtraction(Bit8u veloSensitivity, unsigned int velocity) { + // FIXME:KG: Better variable names + int velocityMult = veloSensitivity - 50; + int absVelocityMult = velocityMult < 0 ? -velocityMult : velocityMult; + velocityMult = signed(unsigned(velocityMult * (signed(velocity) - 64)) << 2); + return absVelocityMult - (velocityMult >> 8); // PORTABILITY NOTE: Assumes arithmetic shift +} + +static int calcBasicAmp(const Tables *tables, const Partial *partial, const MemParams::System *system, const TimbreParam::PartialParam *partialParam, const MemParams::PatchTemp *patchTemp, const MemParams::RhythmTemp *rhythmTemp, int biasAmpSubtraction, int veloAmpSubtraction, Bit8u expression) { + int amp = 155; + + if (!partial->isRingModulatingSlave()) { + amp -= tables->masterVolToAmpSubtraction[system->masterVol]; + if (amp < 0) { + return 0; + } + amp -= tables->levelToAmpSubtraction[patchTemp->outputLevel]; + if (amp < 0) { + return 0; + } + amp -= tables->levelToAmpSubtraction[expression]; + if (amp < 0) { + return 0; + } + if (rhythmTemp != NULL) { + amp -= tables->levelToAmpSubtraction[rhythmTemp->outputLevel]; + if (amp < 0) { + return 0; + } + } + } + amp -= biasAmpSubtraction; + if (amp < 0) { + return 0; + } + amp -= tables->levelToAmpSubtraction[partialParam->tva.level]; + if (amp < 0) { + return 0; + } + amp -= veloAmpSubtraction; + if (amp < 0) { + return 0; + } + if (amp > 155) { + amp = 155; + } + amp -= partialParam->tvf.resonance >> 1; + if (amp < 0) { + return 0; + } + return amp; +} + +static int calcKeyTimeSubtraction(Bit8u envTimeKeyfollow, int key) { + if (envTimeKeyfollow == 0) { + return 0; + } + return (key - 60) >> (5 - envTimeKeyfollow); // PORTABILITY NOTE: Assumes arithmetic shift +} + +void TVA::reset(const Part *newPart, const TimbreParam::PartialParam *newPartialParam, const MemParams::RhythmTemp *newRhythmTemp) { + part = newPart; + partialParam = newPartialParam; + patchTemp = newPart->getPatchTemp(); + rhythmTemp = newRhythmTemp; + + playing = true; + + const Tables *tables = &Tables::getInstance(); + + int key = partial->getPoly()->getKey(); + int velocity = partial->getPoly()->getVelocity(); + + keyTimeSubtraction = calcKeyTimeSubtraction(partialParam->tva.envTimeKeyfollow, key); + + biasAmpSubtraction = calcBiasAmpSubtractions(partialParam, key); + veloAmpSubtraction = calcVeloAmpSubtraction(partialParam->tva.veloSensitivity, velocity); + + int newTarget = calcBasicAmp(tables, partial, system, partialParam, patchTemp, newRhythmTemp, biasAmpSubtraction, veloAmpSubtraction, part->getExpression()); + int newPhase; + if (partialParam->tva.envTime[0] == 0) { + // Initially go to the TVA_PHASE_ATTACK target amp, and spend the next phase going from there to the TVA_PHASE_2 target amp + // Note that this means that velocity never affects time for this partial. + newTarget += partialParam->tva.envLevel[0]; + newPhase = TVA_PHASE_ATTACK; // The first target used in nextPhase() will be TVA_PHASE_2 + } else { + // Initially go to the base amp determined by TVA level, part volume, etc., and spend the next phase going from there to the full TVA_PHASE_ATTACK target amp. + newPhase = TVA_PHASE_BASIC; // The first target used in nextPhase() will be TVA_PHASE_ATTACK + } + + ampRamp->reset();//currentAmp = 0; + + // "Go downward as quickly as possible". + // Since the current value is 0, the LA32Ramp will notice that we're already at or below the target and trying to go downward, + // and therefore jump to the target immediately and raise an interrupt. + startRamp(Bit8u(newTarget), 0x80 | 127, newPhase); +} + +void TVA::startAbort() { + startRamp(64, 0x80 | 127, TVA_PHASE_RELEASE); +} + +void TVA::startDecay() { + if (phase >= TVA_PHASE_RELEASE) { + return; + } + Bit8u newIncrement; + if (partialParam->tva.envTime[4] == 0) { + newIncrement = 1; + } else { + newIncrement = -partialParam->tva.envTime[4]; + } + // The next time nextPhase() is called, it will think TVA_PHASE_RELEASE has finished and the partial will be aborted + startRamp(0, newIncrement, TVA_PHASE_RELEASE); +} + +void TVA::handleInterrupt() { + nextPhase(); +} + +void TVA::recalcSustain() { + // We get pinged periodically by the pitch code to recalculate our values when in sustain. + // This is done so that the TVA will respond to things like MIDI expression and volume changes while it's sustaining, which it otherwise wouldn't do. + + // The check for envLevel[3] == 0 strikes me as slightly dumb. FIXME: Explain why + if (phase != TVA_PHASE_SUSTAIN || partialParam->tva.envLevel[3] == 0) { + return; + } + // We're sustaining. Recalculate all the values + const Tables *tables = &Tables::getInstance(); + int newTarget = calcBasicAmp(tables, partial, system, partialParam, patchTemp, rhythmTemp, biasAmpSubtraction, veloAmpSubtraction, part->getExpression()); + newTarget += partialParam->tva.envLevel[3]; + // Since we're in TVA_PHASE_SUSTAIN at this point, we know that target has been reached and an interrupt fired, so we can rely on it being the current amp. + int targetDelta = newTarget - target; + + // Calculate an increment to get to the new amp value in a short, more or less consistent amount of time + Bit8u newIncrement; + if (targetDelta >= 0) { + newIncrement = tables->envLogarithmicTime[Bit8u(targetDelta)] - 2; + } else { + newIncrement = (tables->envLogarithmicTime[Bit8u(-targetDelta)] - 2) | 0x80; + } + // Configure so that once the transition's complete and nextPhase() is called, we'll just re-enter sustain phase (or decay phase, depending on parameters at the time). + startRamp(newTarget, newIncrement, TVA_PHASE_SUSTAIN - 1); +} + +bool TVA::isPlaying() const { + return playing; +} + +int TVA::getPhase() const { + return phase; +} + +void TVA::nextPhase() { + const Tables *tables = &Tables::getInstance(); + + if (phase >= TVA_PHASE_DEAD || !playing) { + partial->getSynth()->printDebug("TVA::nextPhase(): Shouldn't have got here with phase %d, playing=%s", phase, playing ? "true" : "false"); + return; + } + int newPhase = phase + 1; + + if (newPhase == TVA_PHASE_DEAD) { + end(newPhase); + return; + } + + bool allLevelsZeroFromNowOn = false; + if (partialParam->tva.envLevel[3] == 0) { + if (newPhase == TVA_PHASE_4) { + allLevelsZeroFromNowOn = true; + } else if (partialParam->tva.envLevel[2] == 0) { + if (newPhase == TVA_PHASE_3) { + allLevelsZeroFromNowOn = true; + } else if (partialParam->tva.envLevel[1] == 0) { + if (newPhase == TVA_PHASE_2) { + allLevelsZeroFromNowOn = true; + } else if (partialParam->tva.envLevel[0] == 0) { + if (newPhase == TVA_PHASE_ATTACK) { // this line added, missing in ROM - FIXME: Add description of repercussions + allLevelsZeroFromNowOn = true; + } + } + } + } + } + + int newTarget; + int newIncrement = 0; // Initialised to please compilers + int envPointIndex = phase; + + if (!allLevelsZeroFromNowOn) { + newTarget = calcBasicAmp(tables, partial, system, partialParam, patchTemp, rhythmTemp, biasAmpSubtraction, veloAmpSubtraction, part->getExpression()); + + if (newPhase == TVA_PHASE_SUSTAIN || newPhase == TVA_PHASE_RELEASE) { + if (partialParam->tva.envLevel[3] == 0) { + end(newPhase); + return; + } + if (!partial->getPoly()->canSustain()) { + newPhase = TVA_PHASE_RELEASE; + newTarget = 0; + newIncrement = -partialParam->tva.envTime[4]; + if (newIncrement == 0) { + // We can't let the increment be 0, or there would be no emulated interrupt. + // So we do an "upward" increment, which should set the amp to 0 extremely quickly + // and cause an "interrupt" to bring us back to nextPhase(). + newIncrement = 1; + } + } else { + newTarget += partialParam->tva.envLevel[3]; + newIncrement = 0; + } + } else { + newTarget += partialParam->tva.envLevel[envPointIndex]; + } + } else { + newTarget = 0; + } + + if ((newPhase != TVA_PHASE_SUSTAIN && newPhase != TVA_PHASE_RELEASE) || allLevelsZeroFromNowOn) { + int envTimeSetting = partialParam->tva.envTime[envPointIndex]; + + if (newPhase == TVA_PHASE_ATTACK) { + envTimeSetting -= (signed(partial->getPoly()->getVelocity()) - 64) >> (6 - partialParam->tva.envTimeVeloSensitivity); // PORTABILITY NOTE: Assumes arithmetic shift + + if (envTimeSetting <= 0 && partialParam->tva.envTime[envPointIndex] != 0) { + envTimeSetting = 1; + } + } else { + envTimeSetting -= keyTimeSubtraction; + } + if (envTimeSetting > 0) { + int targetDelta = newTarget - target; + if (targetDelta <= 0) { + if (targetDelta == 0) { + // target and newTarget are the same. + // We can't have an increment of 0 or we wouldn't get an emulated interrupt. + // So instead make the target one less than it really should be and set targetDelta accordingly. + targetDelta = -1; + newTarget--; + if (newTarget < 0) { + // Oops, newTarget is less than zero now, so let's do it the other way: + // Make newTarget one more than it really should've been and set targetDelta accordingly. + // FIXME (apparent bug in real firmware): + // This means targetDelta will be positive just below here where it's inverted, and we'll end up using envLogarithmicTime[-1], and we'll be setting newIncrement to be descending later on, etc.. + targetDelta = 1; + newTarget = -newTarget; + } + } + targetDelta = -targetDelta; + newIncrement = tables->envLogarithmicTime[Bit8u(targetDelta)] - envTimeSetting; + if (newIncrement <= 0) { + newIncrement = 1; + } + newIncrement = newIncrement | 0x80; + } else { + // FIXME: The last 22 or so entries in this table are 128 - surely that fucks things up, since that ends up being -128 signed? + newIncrement = tables->envLogarithmicTime[Bit8u(targetDelta)] - envTimeSetting; + if (newIncrement <= 0) { + newIncrement = 1; + } + } + } else { + newIncrement = newTarget >= target ? (0x80 | 127) : 127; + } + + // FIXME: What's the point of this? It's checked or set to non-zero everywhere above + if (newIncrement == 0) { + newIncrement = 1; + } + } + + startRamp(Bit8u(newTarget), Bit8u(newIncrement), newPhase); +} + +} // namespace MT32Emu diff --git a/src/SOUND/munt/TVA.h b/src/SOUND/munt/TVA.h new file mode 100644 index 000000000..cf9296d48 --- /dev/null +++ b/src/SOUND/munt/TVA.h @@ -0,0 +1,100 @@ +/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher + * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#ifndef MT32EMU_TVA_H +#define MT32EMU_TVA_H + +#include "globals.h" +#include "Types.h" +#include "Structures.h" + +namespace MT32Emu { + +class LA32Ramp; +class Part; +class Partial; + +// Note that when entering nextPhase(), newPhase is set to phase + 1, and the descriptions/names below refer to +// newPhase's value. +enum { + // In this phase, the base amp (as calculated in calcBasicAmp()) is targeted with an instant time. + // This phase is entered by reset() only if time[0] != 0. + TVA_PHASE_BASIC = 0, + + // In this phase, level[0] is targeted within time[0], and velocity potentially affects time + TVA_PHASE_ATTACK = 1, + + // In this phase, level[1] is targeted within time[1] + TVA_PHASE_2 = 2, + + // In this phase, level[2] is targeted within time[2] + TVA_PHASE_3 = 3, + + // In this phase, level[3] is targeted within time[3] + TVA_PHASE_4 = 4, + + // In this phase, immediately goes to PHASE_RELEASE unless the poly is set to sustain. + // Aborts the partial if level[3] is 0. + // Otherwise level[3] is continued, no phase change will occur until some external influence (like pedal release) + TVA_PHASE_SUSTAIN = 5, + + // In this phase, 0 is targeted within time[4] (the time calculation is quite different from the other phases) + TVA_PHASE_RELEASE = 6, + + // It's PHASE_DEAD, Jim. + TVA_PHASE_DEAD = 7 +}; + +class TVA { +private: + const Partial * const partial; + LA32Ramp *ampRamp; + const MemParams::System * const system; + + const Part *part; + const TimbreParam::PartialParam *partialParam; + const MemParams::PatchTemp *patchTemp; + const MemParams::RhythmTemp *rhythmTemp; + + bool playing; + + int biasAmpSubtraction; + int veloAmpSubtraction; + int keyTimeSubtraction; + + Bit8u target; + int phase; + + void startRamp(Bit8u newTarget, Bit8u newIncrement, int newPhase); + void end(int newPhase); + void nextPhase(); + +public: + TVA(const Partial *partial, LA32Ramp *ampRamp); + void reset(const Part *part, const TimbreParam::PartialParam *partialParam, const MemParams::RhythmTemp *rhythmTemp); + void handleInterrupt(); + void recalcSustain(); + void startDecay(); + void startAbort(); + + bool isPlaying() const; + int getPhase() const; +}; // class TVA + +} // namespace MT32Emu + +#endif // #ifndef MT32EMU_TVA_H diff --git a/src/SOUND/munt/TVF.cpp b/src/SOUND/munt/TVF.cpp new file mode 100644 index 000000000..cafeb4a8d --- /dev/null +++ b/src/SOUND/munt/TVF.cpp @@ -0,0 +1,233 @@ +/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher + * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#include "internals.h" + +#include "TVF.h" +#include "LA32Ramp.h" +#include "Partial.h" +#include "Poly.h" +#include "Tables.h" + +namespace MT32Emu { + +// Note that when entering nextPhase(), newPhase is set to phase + 1, and the descriptions/names below refer to +// newPhase's value. +enum { + // When this is the target phase, level[0] is targeted within time[0] + // Note that this phase is always set up in reset(), not nextPhase() + PHASE_ATTACK = 1, + + // When this is the target phase, level[1] is targeted within time[1] + PHASE_2 = 2, + + // When this is the target phase, level[2] is targeted within time[2] + PHASE_3 = 3, + + // When this is the target phase, level[3] is targeted within time[3] + PHASE_4 = 4, + + // When this is the target phase, immediately goes to PHASE_RELEASE unless the poly is set to sustain. + // Otherwise level[3] is continued with increment 0 - no phase change will occur until some external influence (like pedal release) + PHASE_SUSTAIN = 5, + + // 0 is targeted within time[4] (the time calculation is quite different from the other phases) + PHASE_RELEASE = 6, + + // 0 is targeted with increment 0 (thus theoretically staying that way forever) + PHASE_DONE = 7 +}; + +static int calcBaseCutoff(const TimbreParam::PartialParam *partialParam, Bit32u basePitch, unsigned int key) { + // This table matches the values used by a real LAPC-I. + static const Bit8s biasLevelToBiasMult[] = {85, 42, 21, 16, 10, 5, 2, 0, -2, -5, -10, -16, -21, -74, -85}; + // These values represent unique options with no consistent pattern, so we have to use something like a table in any case. + // The table entries, when divided by 21, match approximately what the manual claims: + // -1, -1/2, -1/4, 0, 1/8, 1/4, 3/8, 1/2, 5/8, 3/4, 7/8, 1, 5/4, 3/2, 2, s1, s2 + // Note that the entry for 1/8 is rounded to 2 (from 1/8 * 21 = 2.625), which seems strangely inaccurate compared to the others. + static const Bit8s keyfollowMult21[] = {-21, -10, -5, 0, 2, 5, 8, 10, 13, 16, 18, 21, 26, 32, 42, 21, 21}; + int baseCutoff = keyfollowMult21[partialParam->tvf.keyfollow] - keyfollowMult21[partialParam->wg.pitchKeyfollow]; + // baseCutoff range now: -63 to 63 + baseCutoff *= int(key) - 60; + // baseCutoff range now: -3024 to 3024 + int biasPoint = partialParam->tvf.biasPoint; + if ((biasPoint & 0x40) == 0) { + // biasPoint range here: 0 to 63 + int bias = biasPoint + 33 - key; // bias range here: -75 to 84 + if (bias > 0) { + bias = -bias; // bias range here: -1 to -84 + baseCutoff += bias * biasLevelToBiasMult[partialParam->tvf.biasLevel]; // Calculation range: -7140 to 7140 + // baseCutoff range now: -10164 to 10164 + } + } else { + // biasPoint range here: 64 to 127 + int bias = biasPoint - 31 - key; // bias range here: -75 to 84 + if (bias < 0) { + baseCutoff += bias * biasLevelToBiasMult[partialParam->tvf.biasLevel]; // Calculation range: -6375 to 6375 + // baseCutoff range now: -9399 to 9399 + } + } + // baseCutoff range now: -10164 to 10164 + baseCutoff += ((partialParam->tvf.cutoff << 4) - 800); + // baseCutoff range now: -10964 to 10964 + if (baseCutoff >= 0) { + // FIXME: Potentially bad if baseCutoff ends up below -2056? + int pitchDeltaThing = (basePitch >> 4) + baseCutoff - 3584; + if (pitchDeltaThing > 0) { + baseCutoff -= pitchDeltaThing; + } + } else if (baseCutoff < -2048) { + baseCutoff = -2048; + } + baseCutoff += 2056; + baseCutoff >>= 4; // PORTABILITY NOTE: Hmm... Depends whether it could've been below -2056, but maybe arithmetic shift assumed? + if (baseCutoff > 255) { + baseCutoff = 255; + } + return Bit8u(baseCutoff); +} + +TVF::TVF(const Partial *usePartial, LA32Ramp *useCutoffModifierRamp) : + partial(usePartial), cutoffModifierRamp(useCutoffModifierRamp) { +} + +void TVF::startRamp(Bit8u newTarget, Bit8u newIncrement, int newPhase) { + target = newTarget; + phase = newPhase; + cutoffModifierRamp->startRamp(newTarget, newIncrement); +#if MT32EMU_MONITOR_TVF >= 1 + partial->getSynth()->printDebug("[+%lu] [Partial %d] TVF,ramp,%d,%d,%d,%d", partial->debugGetSampleNum(), partial->debugGetPartialNum(), newTarget, (newIncrement & 0x80) ? -1 : 1, (newIncrement & 0x7F), newPhase); +#endif +} + +void TVF::reset(const TimbreParam::PartialParam *newPartialParam, unsigned int basePitch) { + partialParam = newPartialParam; + + unsigned int key = partial->getPoly()->getKey(); + unsigned int velocity = partial->getPoly()->getVelocity(); + + const Tables *tables = &Tables::getInstance(); + + baseCutoff = calcBaseCutoff(newPartialParam, basePitch, key); +#if MT32EMU_MONITOR_TVF >= 1 + partial->getSynth()->printDebug("[+%lu] [Partial %d] TVF,base,%d", partial->debugGetSampleNum(), partial->debugGetPartialNum(), baseCutoff); +#endif + + int newLevelMult = velocity * newPartialParam->tvf.envVeloSensitivity; + newLevelMult >>= 6; + newLevelMult += 109 - newPartialParam->tvf.envVeloSensitivity; + newLevelMult += (signed(key) - 60) >> (4 - newPartialParam->tvf.envDepthKeyfollow); + if (newLevelMult < 0) { + newLevelMult = 0; + } + newLevelMult *= newPartialParam->tvf.envDepth; + newLevelMult >>= 6; + if (newLevelMult > 255) { + newLevelMult = 255; + } + levelMult = newLevelMult; + + if (newPartialParam->tvf.envTimeKeyfollow != 0) { + keyTimeSubtraction = (signed(key) - 60) >> (5 - newPartialParam->tvf.envTimeKeyfollow); + } else { + keyTimeSubtraction = 0; + } + + int newTarget = (newLevelMult * newPartialParam->tvf.envLevel[0]) >> 8; + int envTimeSetting = newPartialParam->tvf.envTime[0] - keyTimeSubtraction; + int newIncrement; + if (envTimeSetting <= 0) { + newIncrement = (0x80 | 127); + } else { + newIncrement = tables->envLogarithmicTime[newTarget] - envTimeSetting; + if (newIncrement <= 0) { + newIncrement = 1; + } + } + cutoffModifierRamp->reset(); + startRamp(newTarget, newIncrement, PHASE_2 - 1); +} + +Bit8u TVF::getBaseCutoff() const { + return baseCutoff; +} + +void TVF::handleInterrupt() { + nextPhase(); +} + +void TVF::startDecay() { + if (phase >= PHASE_RELEASE) { + return; + } + if (partialParam->tvf.envTime[4] == 0) { + startRamp(0, 1, PHASE_DONE - 1); + } else { + startRamp(0, -partialParam->tvf.envTime[4], PHASE_DONE - 1); + } +} + +void TVF::nextPhase() { + const Tables *tables = &Tables::getInstance(); + int newPhase = phase + 1; + + switch (newPhase) { + case PHASE_DONE: + startRamp(0, 0, newPhase); + return; + case PHASE_SUSTAIN: + case PHASE_RELEASE: + // FIXME: Afaict newPhase should never be PHASE_RELEASE here. And if it were, this is an odd way to handle it. + if (!partial->getPoly()->canSustain()) { + phase = newPhase; // FIXME: Correct? + startDecay(); // FIXME: This should actually start decay even if phase is already 6. Does that matter? + return; + } + startRamp((levelMult * partialParam->tvf.envLevel[3]) >> 8, 0, newPhase); + return; + } + + int envPointIndex = phase; + int envTimeSetting = partialParam->tvf.envTime[envPointIndex] - keyTimeSubtraction; + + int newTarget = (levelMult * partialParam->tvf.envLevel[envPointIndex]) >> 8; + int newIncrement; + if (envTimeSetting > 0) { + int targetDelta = newTarget - target; + if (targetDelta == 0) { + if (newTarget == 0) { + targetDelta = 1; + newTarget = 1; + } else { + targetDelta = -1; + newTarget--; + } + } + newIncrement = tables->envLogarithmicTime[targetDelta < 0 ? -targetDelta : targetDelta] - envTimeSetting; + if (newIncrement <= 0) { + newIncrement = 1; + } + if (targetDelta < 0) { + newIncrement |= 0x80; + } + } else { + newIncrement = newTarget >= target ? (0x80 | 127) : 127; + } + startRamp(newTarget, newIncrement, newPhase); +} + +} // namespace MT32Emu diff --git a/src/SOUND/munt/TVF.h b/src/SOUND/munt/TVF.h new file mode 100644 index 000000000..e637aa5b4 --- /dev/null +++ b/src/SOUND/munt/TVF.h @@ -0,0 +1,61 @@ +/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher + * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#ifndef MT32EMU_TVF_H +#define MT32EMU_TVF_H + +#include "globals.h" +#include "Types.h" +#include "Structures.h" + +namespace MT32Emu { + +class LA32Ramp; +class Partial; + +class TVF { +private: + const Partial * const partial; + LA32Ramp *cutoffModifierRamp; + const TimbreParam::PartialParam *partialParam; + + Bit8u baseCutoff; + int keyTimeSubtraction; + unsigned int levelMult; + + Bit8u target; + unsigned int phase; + + void startRamp(Bit8u newTarget, Bit8u newIncrement, int newPhase); + void nextPhase(); + +public: + TVF(const Partial *partial, LA32Ramp *cutoffModifierRamp); + void reset(const TimbreParam::PartialParam *partialParam, Bit32u basePitch); + // Returns the base cutoff (without envelope modification). + // The base cutoff is calculated when reset() is called and remains static + // for the lifetime of the partial. + // Barring bugs, the number returned is confirmed accurate + // (based on specs from Mok). + Bit8u getBaseCutoff() const; + void handleInterrupt(); + void startDecay(); +}; // class TVF + +} // namespace MT32Emu + +#endif // #ifndef MT32EMU_TVF_H diff --git a/src/SOUND/munt/TVP.cpp b/src/SOUND/munt/TVP.cpp new file mode 100644 index 000000000..9adedf851 --- /dev/null +++ b/src/SOUND/munt/TVP.cpp @@ -0,0 +1,330 @@ +/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher + * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#include + +#include "internals.h" + +#include "TVP.h" +#include "Part.h" +#include "Partial.h" +#include "Poly.h" +#include "Synth.h" +#include "TVA.h" + +namespace MT32Emu { + +// FIXME: Add Explanation +static Bit16u lowerDurationToDivisor[] = {34078, 37162, 40526, 44194, 48194, 52556, 57312, 62499}; + +// These values represent unique options with no consistent pattern, so we have to use something like a table in any case. +// The table matches exactly what the manual claims (when divided by 8192): +// -1, -1/2, -1/4, 0, 1/8, 1/4, 3/8, 1/2, 5/8, 3/4, 7/8, 1, 5/4, 3/2, 2, s1, s2 +// ...except for the last two entries, which are supposed to be "1 cent above 1" and "2 cents above 1", respectively. They can only be roughly approximated with this integer math. +static Bit16s pitchKeyfollowMult[] = {-8192, -4096, -2048, 0, 1024, 2048, 3072, 4096, 5120, 6144, 7168, 8192, 10240, 12288, 16384, 8198, 8226}; + +// Note: Keys < 60 use keyToPitchTable[60 - key], keys >= 60 use keyToPitchTable[key - 60]. +// FIXME: This table could really be shorter, since we never use e.g. key 127. +static Bit16u keyToPitchTable[] = { + 0, 341, 683, 1024, 1365, 1707, 2048, 2389, + 2731, 3072, 3413, 3755, 4096, 4437, 4779, 5120, + 5461, 5803, 6144, 6485, 6827, 7168, 7509, 7851, + 8192, 8533, 8875, 9216, 9557, 9899, 10240, 10581, + 10923, 11264, 11605, 11947, 12288, 12629, 12971, 13312, + 13653, 13995, 14336, 14677, 15019, 15360, 15701, 16043, + 16384, 16725, 17067, 17408, 17749, 18091, 18432, 18773, + 19115, 19456, 19797, 20139, 20480, 20821, 21163, 21504, + 21845, 22187, 22528, 22869 +}; + +TVP::TVP(const Partial *usePartial) : + partial(usePartial), system(&usePartial->getSynth()->mt32ram.system) { + // We want to do processing 4000 times per second. FIXME: This is pretty arbitrary. + maxCounter = SAMPLE_RATE / 4000; + // The timer runs at 500kHz. We only need to bother updating it every maxCounter samples, before we do processing. + // This is how much to increment it by every maxCounter samples. + processTimerIncrement = 500000 * maxCounter / SAMPLE_RATE; +} + +static Bit16s keyToPitch(unsigned int key) { + // We're using a table to do: return round_to_nearest_or_even((key - 60) * (4096.0 / 12.0)) + // Banker's rounding is just slightly annoying to do in C++ + int k = int(key); + Bit16s pitch = keyToPitchTable[abs(k - 60)]; + return key < 60 ? -pitch : pitch; +} + +static inline Bit32s coarseToPitch(Bit8u coarse) { + return (coarse - 36) * 4096 / 12; // One semitone per coarse offset +} + +static inline Bit32s fineToPitch(Bit8u fine) { + return (fine - 50) * 4096 / 1200; // One cent per fine offset +} + +static Bit32u calcBasePitch(const Partial *partial, const TimbreParam::PartialParam *partialParam, const MemParams::PatchTemp *patchTemp, unsigned int key) { + Bit32s basePitch = keyToPitch(key); + basePitch = (basePitch * pitchKeyfollowMult[partialParam->wg.pitchKeyfollow]) >> 13; // PORTABILITY NOTE: Assumes arithmetic shift + basePitch += coarseToPitch(partialParam->wg.pitchCoarse); + basePitch += fineToPitch(partialParam->wg.pitchFine); + // NOTE:Mok: This is done on MT-32, but not LAPC-I: + //pitch += coarseToPitch(patchTemp->patch.keyShift + 12); + basePitch += fineToPitch(patchTemp->patch.fineTune); + + const ControlROMPCMStruct *controlROMPCMStruct = partial->getControlROMPCMStruct(); + if (controlROMPCMStruct != NULL) { + basePitch += (Bit32s(controlROMPCMStruct->pitchMSB) << 8) | Bit32s(controlROMPCMStruct->pitchLSB); + } else { + if ((partialParam->wg.waveform & 1) == 0) { + basePitch += 37133; // This puts Middle C at around 261.64Hz (assuming no other modifications, masterTune of 64, etc.) + } else { + // Sawtooth waves are effectively double the frequency of square waves. + // Thus we add 4096 less than for square waves here, which results in halving the frequency. + basePitch += 33037; + } + } + if (basePitch < 0) { + basePitch = 0; + } + if (basePitch > 59392) { + basePitch = 59392; + } + return Bit32u(basePitch); +} + +static Bit32u calcVeloMult(Bit8u veloSensitivity, unsigned int velocity) { + if (veloSensitivity == 0 || veloSensitivity > 3) { + // Note that on CM-32L/LAPC-I veloSensitivity is never > 3, since it's clipped to 3 by the max tables. + return 21845; // aka floor(4096 / 12 * 64), aka ~64 semitones + } + // When velocity is 127, the multiplier is 21845, aka ~64 semitones (regardless of veloSensitivity). + // The lower the velocity, the lower the multiplier. The veloSensitivity determines the amount decreased per velocity value. + // The minimum multiplier (with velocity 0, veloSensitivity 3) is 170 (~half a semitone). + Bit32u veloMult = 32768; + veloMult -= (127 - velocity) << (5 + veloSensitivity); + veloMult *= 21845; + veloMult >>= 15; + return veloMult; +} + +static Bit32s calcTargetPitchOffsetWithoutLFO(const TimbreParam::PartialParam *partialParam, int levelIndex, unsigned int velocity) { + int veloMult = calcVeloMult(partialParam->pitchEnv.veloSensitivity, velocity); + int targetPitchOffsetWithoutLFO = partialParam->pitchEnv.level[levelIndex] - 50; + targetPitchOffsetWithoutLFO = (targetPitchOffsetWithoutLFO * veloMult) >> (16 - partialParam->pitchEnv.depth); // PORTABILITY NOTE: Assumes arithmetic shift + return targetPitchOffsetWithoutLFO; +} + +void TVP::reset(const Part *usePart, const TimbreParam::PartialParam *usePartialParam) { + part = usePart; + partialParam = usePartialParam; + patchTemp = part->getPatchTemp(); + + unsigned int key = partial->getPoly()->getKey(); + unsigned int velocity = partial->getPoly()->getVelocity(); + + // FIXME: We're using a per-TVP timer instead of a system-wide one for convenience. + timeElapsed = 0; + + basePitch = calcBasePitch(partial, partialParam, patchTemp, key); + currentPitchOffset = calcTargetPitchOffsetWithoutLFO(partialParam, 0, velocity); + targetPitchOffsetWithoutLFO = currentPitchOffset; + phase = 0; + + if (partialParam->pitchEnv.timeKeyfollow) { + timeKeyfollowSubtraction = Bit32s(key - 60) >> (5 - partialParam->pitchEnv.timeKeyfollow); // PORTABILITY NOTE: Assumes arithmetic shift + } else { + timeKeyfollowSubtraction = 0; + } + lfoPitchOffset = 0; + counter = 0; + pitch = basePitch; + + // These don't really need to be initialised, but it aids debugging. + pitchOffsetChangePerBigTick = 0; + targetPitchOffsetReachedBigTick = 0; + shifts = 0; +} + +Bit32u TVP::getBasePitch() const { + return basePitch; +} + +void TVP::updatePitch() { + Bit32s newPitch = basePitch + currentPitchOffset; + if (!partial->isPCM() || (partial->getControlROMPCMStruct()->len & 0x01) == 0) { // FIXME: Use !partial->pcmWaveEntry->unaffectedByMasterTune instead + // FIXME: masterTune recalculation doesn't really happen here, and there are various bugs not yet emulated + // 171 is ~half a semitone. + newPitch += ((system->masterTune - 64) * 171) >> 6; // PORTABILITY NOTE: Assumes arithmetic shift. + } + if ((partialParam->wg.pitchBenderEnabled & 1) != 0) { + newPitch += part->getPitchBend(); + } + if (newPitch < 0) { + newPitch = 0; + } + + // Skipping this check seems about right emulation of MT-32 GEN0 quirk exploited in Colonel's Bequest timbre "Lightning" + if (partial->getSynth()->controlROMFeatures->quirkPitchEnvelopeOverflow == 0) { + if (newPitch > 59392) { + newPitch = 59392; + } + } + pitch = Bit16u(newPitch); + + // FIXME: We're doing this here because that's what the CM-32L does - we should probably move this somewhere more appropriate in future. + partial->getTVA()->recalcSustain(); +} + +void TVP::targetPitchOffsetReached() { + currentPitchOffset = targetPitchOffsetWithoutLFO + lfoPitchOffset; + + switch (phase) { + case 3: + case 4: + { + int newLFOPitchOffset = (part->getModulation() * partialParam->pitchLFO.modSensitivity) >> 7; + newLFOPitchOffset = (newLFOPitchOffset + partialParam->pitchLFO.depth) << 1; + if (pitchOffsetChangePerBigTick > 0) { + // Go in the opposite direction to last time + newLFOPitchOffset = -newLFOPitchOffset; + } + lfoPitchOffset = newLFOPitchOffset; + int targetPitchOffset = targetPitchOffsetWithoutLFO + lfoPitchOffset; + setupPitchChange(targetPitchOffset, 101 - partialParam->pitchLFO.rate); + updatePitch(); + break; + } + case 6: + updatePitch(); + break; + default: + nextPhase(); + } +} + +void TVP::nextPhase() { + phase++; + int envIndex = phase == 6 ? 4 : phase; + + targetPitchOffsetWithoutLFO = calcTargetPitchOffsetWithoutLFO(partialParam, envIndex, partial->getPoly()->getVelocity()); // pitch we'll reach at the end + + int changeDuration = partialParam->pitchEnv.time[envIndex - 1]; + changeDuration -= timeKeyfollowSubtraction; + if (changeDuration > 0) { + setupPitchChange(targetPitchOffsetWithoutLFO, changeDuration); // changeDuration between 0 and 112 now + updatePitch(); + } else { + targetPitchOffsetReached(); + } +} + +// Shifts val to the left until bit 31 is 1 and returns the number of shifts +static Bit8u normalise(Bit32u &val) { + Bit8u leftShifts; + for (leftShifts = 0; leftShifts < 31; leftShifts++) { + if ((val & 0x80000000) != 0) { + break; + } + val = val << 1; + } + return leftShifts; +} + +void TVP::setupPitchChange(int targetPitchOffset, Bit8u changeDuration) { + bool negativeDelta = targetPitchOffset < currentPitchOffset; + Bit32s pitchOffsetDelta = targetPitchOffset - currentPitchOffset; + if (pitchOffsetDelta > 32767 || pitchOffsetDelta < -32768) { + pitchOffsetDelta = 32767; + } + if (negativeDelta) { + pitchOffsetDelta = -pitchOffsetDelta; + } + // We want to maximise the number of bits of the Bit16s "pitchOffsetChangePerBigTick" we use in order to get the best possible precision later + Bit32u absPitchOffsetDelta = pitchOffsetDelta << 16; + Bit8u normalisationShifts = normalise(absPitchOffsetDelta); // FIXME: Double-check: normalisationShifts is usually between 0 and 15 here, unless the delta is 0, in which case it's 31 + absPitchOffsetDelta = absPitchOffsetDelta >> 1; // Make room for the sign bit + + changeDuration--; // changeDuration's now between 0 and 111 + unsigned int upperDuration = changeDuration >> 3; // upperDuration's now between 0 and 13 + shifts = normalisationShifts + upperDuration + 2; + Bit16u divisor = lowerDurationToDivisor[changeDuration & 7]; + Bit16s newPitchOffsetChangePerBigTick = ((absPitchOffsetDelta & 0xFFFF0000) / divisor) >> 1; // Result now fits within 15 bits. FIXME: Check nothing's getting sign-extended incorrectly + if (negativeDelta) { + newPitchOffsetChangePerBigTick = -newPitchOffsetChangePerBigTick; + } + pitchOffsetChangePerBigTick = newPitchOffsetChangePerBigTick; + + int currentBigTick = timeElapsed >> 8; + int durationInBigTicks = divisor >> (12 - upperDuration); + if (durationInBigTicks > 32767) { + durationInBigTicks = 32767; + } + // The result of the addition may exceed 16 bits, but wrapping is fine and intended here. + targetPitchOffsetReachedBigTick = currentBigTick + durationInBigTicks; +} + +void TVP::startDecay() { + phase = 5; + lfoPitchOffset = 0; + targetPitchOffsetReachedBigTick = timeElapsed >> 8; // FIXME: Afaict there's no good reason for this - check +} + +Bit16u TVP::nextPitch() { + // FIXME: Write explanation of counter and time increment + if (counter == 0) { + timeElapsed += processTimerIncrement; + timeElapsed = timeElapsed & 0x00FFFFFF; + process(); + } + counter = (counter + 1) % maxCounter; + return pitch; +} + +void TVP::process() { + if (phase == 0) { + targetPitchOffsetReached(); + return; + } + if (phase == 5) { + nextPhase(); + return; + } + if (phase > 7) { + updatePitch(); + return; + } + + Bit16s negativeBigTicksRemaining = (timeElapsed >> 8) - targetPitchOffsetReachedBigTick; + if (negativeBigTicksRemaining >= 0) { + // We've reached the time for a phase change + targetPitchOffsetReached(); + return; + } + // FIXME: Write explanation for this stuff + int rightShifts = shifts; + if (rightShifts > 13) { + rightShifts -= 13; + negativeBigTicksRemaining = negativeBigTicksRemaining >> rightShifts; // PORTABILITY NOTE: Assumes arithmetic shift + rightShifts = 13; + } + int newResult = (negativeBigTicksRemaining * pitchOffsetChangePerBigTick) >> rightShifts; // PORTABILITY NOTE: Assumes arithmetic shift + newResult += targetPitchOffsetWithoutLFO + lfoPitchOffset; + currentPitchOffset = newResult; + updatePitch(); +} + +} // namespace MT32Emu diff --git a/src/SOUND/munt/TVP.h b/src/SOUND/munt/TVP.h new file mode 100644 index 000000000..55f89c5f4 --- /dev/null +++ b/src/SOUND/munt/TVP.h @@ -0,0 +1,74 @@ +/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher + * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#ifndef MT32EMU_TVP_H +#define MT32EMU_TVP_H + +#include "globals.h" +#include "Types.h" +#include "Structures.h" + +namespace MT32Emu { + +class Part; +class Partial; + +class TVP { +private: + const Partial * const partial; + const MemParams::System * const system; // FIXME: Only necessary because masterTune calculation is done in the wrong place atm. + + const Part *part; + const TimbreParam::PartialParam *partialParam; + const MemParams::PatchTemp *patchTemp; + + int maxCounter; + int processTimerIncrement; + int counter; + Bit32u timeElapsed; + + int phase; + Bit32u basePitch; + Bit32s targetPitchOffsetWithoutLFO; + Bit32s currentPitchOffset; + + Bit16s lfoPitchOffset; + // In range -12 - 36 + Bit8s timeKeyfollowSubtraction; + + Bit16s pitchOffsetChangePerBigTick; + Bit16u targetPitchOffsetReachedBigTick; + unsigned int shifts; + + Bit16u pitch; + + void updatePitch(); + void setupPitchChange(int targetPitchOffset, Bit8u changeDuration); + void targetPitchOffsetReached(); + void nextPhase(); + void process(); +public: + TVP(const Partial *partial); + void reset(const Part *part, const TimbreParam::PartialParam *partialParam); + Bit32u getBasePitch() const; + Bit16u nextPitch(); + void startDecay(); +}; // class TVP + +} // namespace MT32Emu + +#endif // #ifndef MT32EMU_TVP_H diff --git a/src/SOUND/munt/Tables.cpp b/src/SOUND/munt/Tables.cpp new file mode 100644 index 000000000..f12caa6b6 --- /dev/null +++ b/src/SOUND/munt/Tables.cpp @@ -0,0 +1,97 @@ +/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher + * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#include "internals.h" + +#include "Tables.h" +#include "mmath.h" + +namespace MT32Emu { + +// UNUSED: const int MIDDLEC = 60; + +const Tables &Tables::getInstance() { + static const Tables instance; + return instance; +} + +Tables::Tables() { + for (int lf = 0; lf <= 100; lf++) { + // CONFIRMED:KG: This matches a ROM table found by Mok + float fVal = (2.0f - LOG10F(float(lf) + 1.0f)) * 128.0f; + int val = int(fVal + 1.0); + if (val > 255) { + val = 255; + } + levelToAmpSubtraction[lf] = Bit8u(val); + } + + envLogarithmicTime[0] = 64; + for (int lf = 1; lf <= 255; lf++) { + // CONFIRMED:KG: This matches a ROM table found by Mok + envLogarithmicTime[lf] = Bit8u(ceil(64.0f + LOG2F(float(lf)) * 8.0f)); + } + +#if 0 + // The table below is to be used in conjunction with emulation of VCA of newer generation units which is currently missing. + // These relatively small values are rather intended to fine-tune the overall amplification of the VCA. + // CONFIRMED: Based on a table found by Mok in the LAPC-I control ROM + // Note that this matches the MT-32 table, but with the values clamped to a maximum of 8. + memset(masterVolToAmpSubtraction, 8, 71); + memset(masterVolToAmpSubtraction + 71, 7, 3); + memset(masterVolToAmpSubtraction + 74, 6, 4); + memset(masterVolToAmpSubtraction + 78, 5, 3); + memset(masterVolToAmpSubtraction + 81, 4, 4); + memset(masterVolToAmpSubtraction + 85, 3, 3); + memset(masterVolToAmpSubtraction + 88, 2, 4); + memset(masterVolToAmpSubtraction + 92, 1, 4); + memset(masterVolToAmpSubtraction + 96, 0, 5); +#else + // CONFIRMED: Based on a table found by Mok in the MT-32 control ROM + masterVolToAmpSubtraction[0] = 255; + for (int masterVol = 1; masterVol <= 100; masterVol++) { + masterVolToAmpSubtraction[masterVol] = Bit8u(106.31 - 16.0f * LOG2F(float(masterVol))); + } +#endif + + for (int i = 0; i <= 100; i++) { + pulseWidth100To255[i] = Bit8u(i * 255 / 100.0f + 0.5f); + //synth->printDebug("%d: %d", i, pulseWidth100To255[i]); + } + + // The LA32 chip contains an exponent table inside. The table contains 12-bit integer values. + // The actual table size is 512 rows. The 9 higher bits of the fractional part of the argument are used as a lookup address. + // To improve the precision of computations, the lower bits are supposed to be used for interpolation as the LA32 chip also + // contains another 512-row table with inverted differences between the main table values. + for (int i = 0; i < 512; i++) { + exp9[i] = Bit16u(8191.5f - EXP2F(13.0f + ~i / 512.0f)); + } + + // There is a logarithmic sine table inside the LA32 chip. The table contains 13-bit integer values. + for (int i = 1; i < 512; i++) { + logsin9[i] = Bit16u(0.5f - LOG2F(sin((i + 0.5f) / 1024.0f * FLOAT_PI)) * 1024.0f); + } + + // The very first value is clamped to the maximum possible 13-bit integer + logsin9[0] = 8191; + + // found from sample analysis + static const Bit8u resAmpDecayFactorTable[] = {31, 16, 12, 8, 5, 3, 2, 1}; + resAmpDecayFactor = resAmpDecayFactorTable; +} + +} // namespace MT32Emu diff --git a/src/SOUND/munt/Tables.h b/src/SOUND/munt/Tables.h new file mode 100644 index 000000000..47465097e --- /dev/null +++ b/src/SOUND/munt/Tables.h @@ -0,0 +1,62 @@ +/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher + * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#ifndef MT32EMU_TABLES_H +#define MT32EMU_TABLES_H + +#include "globals.h" +#include "Types.h" + +namespace MT32Emu { + +class Tables { +private: + Tables(); + Tables(Tables &); + ~Tables() {} + +public: + static const Tables &getInstance(); + + // Constant LUTs + + // CONFIRMED: This is used to convert several parameters to amp-modifying values in the TVA envelope: + // - PatchTemp.outputLevel + // - RhythmTemp.outlevel + // - PartialParam.tva.level + // - expression + // It's used to determine how much to subtract from the amp envelope's target value + Bit8u levelToAmpSubtraction[101]; + + // CONFIRMED: ... + Bit8u envLogarithmicTime[256]; + + // CONFIRMED: ... + Bit8u masterVolToAmpSubtraction[101]; + + // CONFIRMED: + Bit8u pulseWidth100To255[101]; + + Bit16u exp9[512]; + Bit16u logsin9[512]; + + const Bit8u *resAmpDecayFactor; +}; // class Tables + +} // namespace MT32Emu + +#endif // #ifndef MT32EMU_TABLES_H diff --git a/src/SOUND/munt/Types.h b/src/SOUND/munt/Types.h new file mode 100644 index 000000000..f70e4795c --- /dev/null +++ b/src/SOUND/munt/Types.h @@ -0,0 +1,32 @@ +/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher + * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#ifndef MT32EMU_TYPES_H +#define MT32EMU_TYPES_H + +namespace MT32Emu { + +typedef unsigned int Bit32u; +typedef signed int Bit32s; +typedef unsigned short int Bit16u; +typedef signed short int Bit16s; +typedef unsigned char Bit8u; +typedef signed char Bit8s; + +} + +#endif diff --git a/src/SOUND/munt/c_interface/c_interface.cpp b/src/SOUND/munt/c_interface/c_interface.cpp new file mode 100644 index 000000000..9028c2612 --- /dev/null +++ b/src/SOUND/munt/c_interface/c_interface.cpp @@ -0,0 +1,635 @@ +/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher + * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#include "../globals.h" +#include "../Types.h" +#include "../File.h" +#include "../FileStream.h" +#include "../ROMInfo.h" +#include "../Synth.h" +#include "../MidiStreamParser.h" + +#include "c_types.h" +#include "c_interface.h" + +using namespace MT32Emu; + +namespace MT32Emu { + +static mt32emu_service_version getSynthVersionID(mt32emu_service_i) { + return MT32EMU_SERVICE_VERSION_CURRENT; +} + +static const mt32emu_service_i_v0 SERVICE_VTABLE = { + getSynthVersionID, + mt32emu_get_supported_report_handler_version, + mt32emu_get_supported_midi_receiver_version, + mt32emu_get_library_version_int, + mt32emu_get_library_version_string, + mt32emu_get_stereo_output_samplerate, + mt32emu_create_context, + mt32emu_free_context, + mt32emu_add_rom_data, + mt32emu_add_rom_file, + mt32emu_get_rom_info, + mt32emu_set_partial_count, + mt32emu_set_analog_output_mode, + mt32emu_open_synth, + mt32emu_close_synth, + mt32emu_is_open, + mt32emu_get_actual_stereo_output_samplerate, + mt32emu_flush_midi_queue, + mt32emu_set_midi_event_queue_size, + mt32emu_set_midi_receiver, + mt32emu_parse_stream, + mt32emu_parse_stream_at, + mt32emu_play_short_message, + mt32emu_play_short_message_at, + mt32emu_play_msg, + mt32emu_play_sysex, + mt32emu_play_msg_at, + mt32emu_play_sysex_at, + mt32emu_play_msg_now, + mt32emu_play_msg_on_part, + mt32emu_play_sysex_now, + mt32emu_write_sysex, + mt32emu_set_reverb_enabled, + mt32emu_is_reverb_enabled, + mt32emu_set_reverb_overridden, + mt32emu_is_reverb_overridden, + mt32emu_set_reverb_compatibility_mode, + mt32emu_is_mt32_reverb_compatibility_mode, + mt32emu_is_default_reverb_mt32_compatible, + mt32emu_set_dac_input_mode, + mt32emu_get_dac_input_mode, + mt32emu_set_midi_delay_mode, + mt32emu_get_midi_delay_mode, + mt32emu_set_output_gain, + mt32emu_get_output_gain, + mt32emu_set_reverb_output_gain, + mt32emu_get_reverb_output_gain, + mt32emu_set_reversed_stereo_enabled, + mt32emu_is_reversed_stereo_enabled, + mt32emu_render_bit16s, + mt32emu_render_float, + mt32emu_render_bit16s_streams, + mt32emu_render_float_streams, + mt32emu_has_active_partials, + mt32emu_is_active, + mt32emu_get_partial_count, + mt32emu_get_part_states, + mt32emu_get_partial_states, + mt32emu_get_playing_notes, + mt32emu_get_patch_name, + mt32emu_read_memory +}; + +} // namespace MT32Emu + +struct mt32emu_data { + ReportHandler *reportHandler; + Synth *synth; + const ROMImage *controlROMImage; + const ROMImage *pcmROMImage; + DefaultMidiStreamParser *midiParser; + Bit32u partialCount; + AnalogOutputMode analogOutputMode; +}; + +// Internal C++ utility stuff + +namespace MT32Emu { + +class DelegatingReportHandlerAdapter : public ReportHandler { +public: + DelegatingReportHandlerAdapter(mt32emu_report_handler_i useReportHandler, void *useInstanceData) : + delegate(useReportHandler), instanceData(useInstanceData) {} + +protected: + const mt32emu_report_handler_i delegate; + void * const instanceData; + +private: + void printDebug(const char *fmt, va_list list) { + if (delegate.v0->printDebug == NULL) { + ReportHandler::printDebug(fmt, list); + } else { + delegate.v0->printDebug(instanceData, fmt, list); + } + } + + void onErrorControlROM() { + if (delegate.v0->onErrorControlROM == NULL) { + ReportHandler::onErrorControlROM(); + } else { + delegate.v0->onErrorControlROM(instanceData); + } + } + + void onErrorPCMROM() { + if (delegate.v0->onErrorPCMROM == NULL) { + ReportHandler::onErrorPCMROM(); + } else { + delegate.v0->onErrorPCMROM(instanceData); + } + } + + void showLCDMessage(const char *message) { + if (delegate.v0->showLCDMessage == NULL) { + ReportHandler::showLCDMessage(message); + } else { + delegate.v0->showLCDMessage(instanceData, message); + } + } + + void onMIDIMessagePlayed() { + if (delegate.v0->onMIDIMessagePlayed == NULL) { + ReportHandler::onMIDIMessagePlayed(); + } else { + delegate.v0->onMIDIMessagePlayed(instanceData); + } + } + + bool onMIDIQueueOverflow() { + if (delegate.v0->onMIDIQueueOverflow == NULL) { + return ReportHandler::onMIDIQueueOverflow(); + } + return delegate.v0->onMIDIQueueOverflow(instanceData) != MT32EMU_BOOL_FALSE; + } + + void onMIDISystemRealtime(Bit8u systemRealtime) { + if (delegate.v0->onMIDISystemRealtime == NULL) { + ReportHandler::onMIDISystemRealtime(systemRealtime); + } else { + delegate.v0->onMIDISystemRealtime(instanceData, systemRealtime); + } + } + + void onDeviceReset() { + if (delegate.v0->onDeviceReset == NULL) { + ReportHandler::onDeviceReset(); + } else { + delegate.v0->onDeviceReset(instanceData); + } + } + + void onDeviceReconfig() { + if (delegate.v0->onDeviceReconfig == NULL) { + ReportHandler::onDeviceReconfig(); + } else { + delegate.v0->onDeviceReconfig(instanceData); + } + } + + void onNewReverbMode(Bit8u mode) { + if (delegate.v0->onNewReverbMode == NULL) { + ReportHandler::onNewReverbMode(mode); + } else { + delegate.v0->onNewReverbMode(instanceData, mode); + } + } + + void onNewReverbTime(Bit8u time) { + if (delegate.v0->onNewReverbTime == NULL) { + ReportHandler::onNewReverbTime(time); + } else { + delegate.v0->onNewReverbTime(instanceData, time); + } + } + + void onNewReverbLevel(Bit8u level) { + if (delegate.v0->onNewReverbLevel == NULL) { + ReportHandler::onNewReverbLevel(level); + } else { + delegate.v0->onNewReverbLevel(instanceData, level); + } + } + + void onPolyStateChanged(Bit8u partNum) { + if (delegate.v0->onPolyStateChanged == NULL) { + ReportHandler::onPolyStateChanged(partNum); + } else { + delegate.v0->onPolyStateChanged(instanceData, partNum); + } + } + + void onProgramChanged(Bit8u partNum, const char *soundGroupName, const char *patchName) { + if (delegate.v0->onProgramChanged == NULL) { + ReportHandler::onProgramChanged(partNum, soundGroupName, patchName); + } else { + delegate.v0->onProgramChanged(instanceData, partNum, soundGroupName, patchName); + } + } +}; + +class DelegatingMidiStreamParser : public DefaultMidiStreamParser { +public: + DelegatingMidiStreamParser(const mt32emu_data *useData, mt32emu_midi_receiver_i useMIDIReceiver, void *useInstanceData) : + DefaultMidiStreamParser(*useData->synth), delegate(useMIDIReceiver), instanceData(useInstanceData) {} + +protected: + mt32emu_midi_receiver_i delegate; + void *instanceData; + +private: + void handleShortMessage(const Bit32u message) { + if (delegate.v0->handleShortMessage == NULL) { + DefaultMidiStreamParser::handleShortMessage(message); + } else { + delegate.v0->handleShortMessage(instanceData, message); + } + } + + void handleSysex(const Bit8u *stream, const Bit32u length) { + if (delegate.v0->handleSysex == NULL) { + DefaultMidiStreamParser::handleSysex(stream, length); + } else { + delegate.v0->handleSysex(instanceData, stream, length); + } + } + + void handleSystemRealtimeMessage(const Bit8u realtime) { + if (delegate.v0->handleSystemRealtimeMessage == NULL) { + DefaultMidiStreamParser::handleSystemRealtimeMessage(realtime); + } else { + delegate.v0->handleSystemRealtimeMessage(instanceData, realtime); + } + } +}; + +static mt32emu_return_code addROMFile(mt32emu_data *data, File *file) { + const ROMImage *image = ROMImage::makeROMImage(file); + const ROMInfo *info = image->getROMInfo(); + if (info == NULL) { + ROMImage::freeROMImage(image); + return MT32EMU_RC_ROM_NOT_IDENTIFIED; + } + if (info->type == ROMInfo::Control) { + if (data->controlROMImage != NULL) { + delete data->controlROMImage->getFile(); + ROMImage::freeROMImage(data->controlROMImage); + } + data->controlROMImage = image; + return MT32EMU_RC_ADDED_CONTROL_ROM; + } else if (info->type == ROMInfo::PCM) { + if (data->pcmROMImage != NULL) { + delete data->pcmROMImage->getFile(); + ROMImage::freeROMImage(data->pcmROMImage); + } + data->pcmROMImage = image; + return MT32EMU_RC_ADDED_PCM_ROM; + } + ROMImage::freeROMImage(image); + return MT32EMU_RC_OK; // No support for reverb ROM yet. +} + +} // namespace MT32Emu + +// C-visible implementation + +extern "C" { + +mt32emu_service_i mt32emu_get_service_i() { + mt32emu_service_i i; + i.v0 = &SERVICE_VTABLE; + return i; +} + +mt32emu_report_handler_version mt32emu_get_supported_report_handler_version() { + return MT32EMU_REPORT_HANDLER_VERSION_CURRENT; +} + +mt32emu_midi_receiver_version mt32emu_get_supported_midi_receiver_version() { + return MT32EMU_MIDI_RECEIVER_VERSION_CURRENT; +} + +mt32emu_bit32u mt32emu_get_library_version_int() { + return Synth::getLibraryVersionInt(); +} + +const char *mt32emu_get_library_version_string() { + return Synth::getLibraryVersionString(); +} + +mt32emu_bit32u mt32emu_get_stereo_output_samplerate(const mt32emu_analog_output_mode analog_output_mode) { + return Synth::getStereoOutputSampleRate(static_cast(analog_output_mode)); +} + +mt32emu_context mt32emu_create_context(mt32emu_report_handler_i report_handler, void *instance_data) { + mt32emu_data *data = new mt32emu_data; + data->reportHandler = (report_handler.v0 != NULL) ? new DelegatingReportHandlerAdapter(report_handler, instance_data) : new ReportHandler; + data->synth = new Synth(data->reportHandler); + data->midiParser = new DefaultMidiStreamParser(*data->synth); + data->controlROMImage = NULL; + data->pcmROMImage = NULL; + data->partialCount = DEFAULT_MAX_PARTIALS; + data->analogOutputMode = AnalogOutputMode_COARSE; + + return data; +} + +void mt32emu_free_context(mt32emu_context data) { + if (data == NULL) return; + + if (data->controlROMImage != NULL) { + delete data->controlROMImage->getFile(); + ROMImage::freeROMImage(data->controlROMImage); + data->controlROMImage = NULL; + } + if (data->pcmROMImage != NULL) { + delete data->pcmROMImage->getFile(); + ROMImage::freeROMImage(data->pcmROMImage); + data->pcmROMImage = NULL; + } + delete data->midiParser; + data->midiParser = NULL; + delete data->synth; + data->synth = NULL; + delete data->reportHandler; + data->reportHandler = NULL; + delete data; +} + +mt32emu_return_code mt32emu_add_rom_data(mt32emu_context context, const mt32emu_bit8u *data, size_t data_size, const mt32emu_sha1_digest *sha1_digest) { + if (sha1_digest == NULL) return addROMFile(context, new ArrayFile(data, data_size)); + return addROMFile(context, new ArrayFile(data, data_size, *sha1_digest)); +} + +mt32emu_return_code mt32emu_add_rom_file(mt32emu_context context, const char *filename) { + mt32emu_return_code rc = MT32EMU_RC_OK; + FileStream *fs = new FileStream; + if (fs->open(filename)) { + if (fs->getData() != NULL) { + rc = addROMFile(context, fs); + if (rc > 0) return rc; + } else { + rc = MT32EMU_RC_FILE_NOT_LOADED; + } + } else { + rc = MT32EMU_RC_FILE_NOT_FOUND; + } + delete fs; + return rc; +} + +void mt32emu_get_rom_info(mt32emu_const_context context, mt32emu_rom_info *rom_info) { + const ROMInfo *romInfo = context->controlROMImage == NULL ? NULL : context->controlROMImage->getROMInfo(); + if (romInfo != NULL) { + rom_info->control_rom_id = romInfo->shortName; + rom_info->control_rom_description = romInfo->description; + rom_info->control_rom_sha1_digest = romInfo->sha1Digest; + } else { + rom_info->control_rom_id = NULL; + rom_info->control_rom_description = NULL; + rom_info->control_rom_sha1_digest = NULL; + } + romInfo = context->pcmROMImage == NULL ? NULL : context->pcmROMImage->getROMInfo(); + if (romInfo != NULL) { + rom_info->pcm_rom_id = romInfo->shortName; + rom_info->pcm_rom_description = romInfo->description; + rom_info->pcm_rom_sha1_digest = romInfo->sha1Digest; + } else { + rom_info->pcm_rom_id = NULL; + rom_info->pcm_rom_description = NULL; + rom_info->pcm_rom_sha1_digest = NULL; + } +} + +void mt32emu_set_partial_count(mt32emu_context context, const mt32emu_bit32u partial_count) { + context->partialCount = partial_count; +} + +void mt32emu_set_analog_output_mode(mt32emu_context context, const mt32emu_analog_output_mode analog_output_mode) { + context->analogOutputMode = static_cast(analog_output_mode); +} + +void mt32emu_select_renderer_type(mt32emu_context context, const mt32emu_renderer_type renderer_type) { + context->synth->selectRendererType(static_cast(renderer_type)); +} + +mt32emu_renderer_type mt32emu_get_selected_renderer_type(mt32emu_context context) { + return static_cast(context->synth->getSelectedRendererType()); +} + +mt32emu_return_code mt32emu_open_synth(mt32emu_const_context context) { + if ((context->controlROMImage == NULL) || (context->pcmROMImage == NULL)) { + return MT32EMU_RC_MISSING_ROMS; + } + if (!context->synth->open(*context->controlROMImage, *context->pcmROMImage, context->partialCount, context->analogOutputMode)) { + return MT32EMU_RC_FAILED; + } + return MT32EMU_RC_OK; +} + +void mt32emu_close_synth(mt32emu_const_context context) { + context->synth->close(); +} + +mt32emu_boolean mt32emu_is_open(mt32emu_const_context context) { + return context->synth->isOpen() ? MT32EMU_BOOL_TRUE : MT32EMU_BOOL_FALSE; +} + +mt32emu_bit32u mt32emu_get_actual_stereo_output_samplerate(mt32emu_const_context context) { + return context->synth->getStereoOutputSampleRate(); +} + +void mt32emu_flush_midi_queue(mt32emu_const_context context) { + context->synth->flushMIDIQueue(); +} + +mt32emu_bit32u mt32emu_set_midi_event_queue_size(mt32emu_const_context context, const mt32emu_bit32u queue_size) { + return context->synth->setMIDIEventQueueSize(queue_size); +} + +void mt32emu_set_midi_receiver(mt32emu_context context, mt32emu_midi_receiver_i midi_receiver, void *instance_data) { + delete context->midiParser; + context->midiParser = (midi_receiver.v0 != NULL) ? new DelegatingMidiStreamParser(context, midi_receiver, instance_data) : new DefaultMidiStreamParser(*context->synth); +} + +void mt32emu_parse_stream(mt32emu_const_context context, const mt32emu_bit8u *stream, mt32emu_bit32u length) { + context->midiParser->resetTimestamp(); + context->midiParser->parseStream(stream, length); +} + +void mt32emu_parse_stream_at(mt32emu_const_context context, const mt32emu_bit8u *stream, mt32emu_bit32u length, mt32emu_bit32u timestamp) { + context->midiParser->setTimestamp(timestamp); + context->midiParser->parseStream(stream, length); +} + +void mt32emu_play_short_message(mt32emu_const_context context, mt32emu_bit32u message) { + context->midiParser->resetTimestamp(); + context->midiParser->processShortMessage(message); +} + +void mt32emu_play_short_message_at(mt32emu_const_context context, mt32emu_bit32u message, mt32emu_bit32u timestamp) { + context->midiParser->setTimestamp(timestamp); + context->midiParser->processShortMessage(message); +} + +mt32emu_return_code mt32emu_play_msg(mt32emu_const_context context, mt32emu_bit32u msg) { + if (!context->synth->isOpen()) return MT32EMU_RC_NOT_OPENED; + return (context->synth->playMsg(msg)) ? MT32EMU_RC_OK : MT32EMU_RC_QUEUE_FULL; +} + +mt32emu_return_code mt32emu_play_sysex(mt32emu_const_context context, const mt32emu_bit8u *sysex, mt32emu_bit32u len) { + if (!context->synth->isOpen()) return MT32EMU_RC_NOT_OPENED; + return (context->synth->playSysex(sysex, len)) ? MT32EMU_RC_OK : MT32EMU_RC_QUEUE_FULL; +} + +mt32emu_return_code mt32emu_play_msg_at(mt32emu_const_context context, mt32emu_bit32u msg, mt32emu_bit32u timestamp) { + if (!context->synth->isOpen()) return MT32EMU_RC_NOT_OPENED; + return (context->synth->playMsg(msg, timestamp)) ? MT32EMU_RC_OK : MT32EMU_RC_QUEUE_FULL; +} + +mt32emu_return_code mt32emu_play_sysex_at(mt32emu_const_context context, const mt32emu_bit8u *sysex, mt32emu_bit32u len, mt32emu_bit32u timestamp) { + if (!context->synth->isOpen()) return MT32EMU_RC_NOT_OPENED; + return (context->synth->playSysex(sysex, len, timestamp)) ? MT32EMU_RC_OK : MT32EMU_RC_QUEUE_FULL; +} + +void mt32emu_play_msg_now(mt32emu_const_context context, mt32emu_bit32u msg) { + context->synth->playMsgNow(msg); +} + +void mt32emu_play_msg_on_part(mt32emu_const_context context, mt32emu_bit8u part, mt32emu_bit8u code, mt32emu_bit8u note, mt32emu_bit8u velocity) { + context->synth->playMsgOnPart(part, code, note, velocity); +} + +void mt32emu_play_sysex_now(mt32emu_const_context context, const mt32emu_bit8u *sysex, mt32emu_bit32u len) { + context->synth->playSysexNow(sysex, len); +} + +void mt32emu_write_sysex(mt32emu_const_context context, mt32emu_bit8u channel, const mt32emu_bit8u *sysex, mt32emu_bit32u len) { + context->synth->writeSysex(channel, sysex, len); +} + +void mt32emu_set_reverb_enabled(mt32emu_const_context context, const mt32emu_boolean reverb_enabled) { + context->synth->setReverbEnabled(reverb_enabled != MT32EMU_BOOL_FALSE); +} + +mt32emu_boolean mt32emu_is_reverb_enabled(mt32emu_const_context context) { + return context->synth->isReverbEnabled() ? MT32EMU_BOOL_TRUE : MT32EMU_BOOL_FALSE; +} + +void mt32emu_set_reverb_overridden(mt32emu_const_context context, const mt32emu_boolean reverb_overridden) { + context->synth->setReverbOverridden(reverb_overridden != MT32EMU_BOOL_FALSE); +} + +mt32emu_boolean mt32emu_is_reverb_overridden(mt32emu_const_context context) { + return context->synth->isReverbOverridden() ? MT32EMU_BOOL_TRUE : MT32EMU_BOOL_FALSE; +} + +void mt32emu_set_reverb_compatibility_mode(mt32emu_const_context context, const mt32emu_boolean mt32_compatible_mode) { + context->synth->setReverbCompatibilityMode(mt32_compatible_mode != MT32EMU_BOOL_FALSE); +} + +mt32emu_boolean mt32emu_is_mt32_reverb_compatibility_mode(mt32emu_const_context context) { + return context->synth->isMT32ReverbCompatibilityMode() ? MT32EMU_BOOL_TRUE : MT32EMU_BOOL_FALSE; +} + +mt32emu_boolean mt32emu_is_default_reverb_mt32_compatible(mt32emu_const_context context) { + return context->synth->isDefaultReverbMT32Compatible() ? MT32EMU_BOOL_TRUE : MT32EMU_BOOL_FALSE; +} + +void mt32emu_set_dac_input_mode(mt32emu_const_context context, const mt32emu_dac_input_mode mode) { + context->synth->setDACInputMode(static_cast(mode)); +} + +mt32emu_dac_input_mode mt32emu_get_dac_input_mode(mt32emu_const_context context) { + return static_cast(context->synth->getDACInputMode()); +} + +void mt32emu_set_midi_delay_mode(mt32emu_const_context context, const mt32emu_midi_delay_mode mode) { + context->synth->setMIDIDelayMode(static_cast(mode)); +} + +mt32emu_midi_delay_mode mt32emu_get_midi_delay_mode(mt32emu_const_context context) { + return static_cast(context->synth->getMIDIDelayMode()); +} + +void mt32emu_set_output_gain(mt32emu_const_context context, float gain) { + context->synth->setOutputGain(gain); +} + +float mt32emu_get_output_gain(mt32emu_const_context context) { + return context->synth->getOutputGain(); +} + +void mt32emu_set_reverb_output_gain(mt32emu_const_context context, float gain) { + context->synth->setReverbOutputGain(gain); +} + +float mt32emu_get_reverb_output_gain(mt32emu_const_context context) { + return context->synth->getReverbOutputGain(); +} + +void mt32emu_set_reversed_stereo_enabled(mt32emu_const_context context, const mt32emu_boolean enabled) { + context->synth->setReversedStereoEnabled(enabled != MT32EMU_BOOL_FALSE); +} + +mt32emu_boolean mt32emu_is_reversed_stereo_enabled(mt32emu_const_context context) { + return context->synth->isReversedStereoEnabled() ? MT32EMU_BOOL_TRUE : MT32EMU_BOOL_FALSE; +} + +void mt32emu_render_bit16s(mt32emu_const_context context, mt32emu_bit16s *stream, mt32emu_bit32u len) { + context->synth->render(stream, len); +} + +void mt32emu_render_float(mt32emu_const_context context, float *stream, mt32emu_bit32u len) { + context->synth->render(stream, len); +} + +void mt32emu_render_bit16s_streams(mt32emu_const_context context, const mt32emu_dac_output_bit16s_streams *streams, mt32emu_bit32u len) { + context->synth->renderStreams(*reinterpret_cast *>(streams), len); +} + +void mt32emu_render_float_streams(mt32emu_const_context context, const mt32emu_dac_output_float_streams *streams, mt32emu_bit32u len) { + context->synth->renderStreams(*reinterpret_cast *>(streams), len); +} + +mt32emu_boolean mt32emu_has_active_partials(mt32emu_const_context context) { + return context->synth->hasActivePartials() ? MT32EMU_BOOL_TRUE : MT32EMU_BOOL_FALSE; +} + +mt32emu_boolean mt32emu_is_active(mt32emu_const_context context) { + return context->synth->isActive() ? MT32EMU_BOOL_TRUE : MT32EMU_BOOL_FALSE; +} + +mt32emu_bit32u mt32emu_get_partial_count(mt32emu_const_context context) { + return context->synth->getPartialCount(); +} + +mt32emu_bit32u mt32emu_get_part_states(mt32emu_const_context context) { + return context->synth->getPartStates(); +} + +void mt32emu_get_partial_states(mt32emu_const_context context, mt32emu_bit8u *partial_states) { + context->synth->getPartialStates(partial_states); +} + +mt32emu_bit32u mt32emu_get_playing_notes(mt32emu_const_context context, mt32emu_bit8u part_number, mt32emu_bit8u *keys, mt32emu_bit8u *velocities) { + return context->synth->getPlayingNotes(part_number, keys, velocities); +} + +const char *mt32emu_get_patch_name(mt32emu_const_context context, mt32emu_bit8u part_number) { + return context->synth->getPatchName(part_number); +} + +void mt32emu_read_memory(mt32emu_const_context context, mt32emu_bit32u addr, mt32emu_bit32u len, mt32emu_bit8u *data) { + context->synth->readMemory(addr, len, data); +} + +} // extern "C" diff --git a/src/SOUND/munt/c_interface/c_interface.h b/src/SOUND/munt/c_interface/c_interface.h new file mode 100644 index 000000000..09c004b0d --- /dev/null +++ b/src/SOUND/munt/c_interface/c_interface.h @@ -0,0 +1,418 @@ +/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher + * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#ifndef MT32EMU_C_INTERFACE_H +#define MT32EMU_C_INTERFACE_H + +#include + +#include "../globals.h" +#include "c_types.h" + +#undef MT32EMU_EXPORT +#define MT32EMU_EXPORT MT32EMU_EXPORT_ATTRIBUTE + +#ifdef __cplusplus +extern "C" { +#endif + +/* == Context-independent functions == */ + +/* === Interface handling === */ + +/** Returns mt32emu_service_i interface. */ +MT32EMU_EXPORT mt32emu_service_i mt32emu_get_service_i(); + +#if MT32EMU_EXPORTS_TYPE == 2 +#undef MT32EMU_EXPORT +#define MT32EMU_EXPORT +#endif + +/** + * Returns the version ID of mt32emu_report_handler_i interface the library has been compiled with. + * This allows a client to fall-back gracefully instead of silently not receiving expected event reports. + */ +MT32EMU_EXPORT mt32emu_report_handler_version mt32emu_get_supported_report_handler_version(); + +/** + * Returns the version ID of mt32emu_midi_receiver_version_i interface the library has been compiled with. + * This allows a client to fall-back gracefully instead of silently not receiving expected MIDI messages. + */ +MT32EMU_EXPORT mt32emu_midi_receiver_version mt32emu_get_supported_midi_receiver_version(); + +/** + * Returns library version as an integer in format: 0x00MMmmpp, where: + * MM - major version number + * mm - minor version number + * pp - patch number + */ +MT32EMU_EXPORT mt32emu_bit32u mt32emu_get_library_version_int(); + +/** + * Returns library version as a C-string in format: "MAJOR.MINOR.PATCH". + */ +MT32EMU_EXPORT const char *mt32emu_get_library_version_string(); + +/** + * Returns output sample rate used in emulation of stereo analog circuitry of hardware units for particular analog_output_mode. + * See comment for mt32emu_analog_output_mode. + */ +MT32EMU_EXPORT mt32emu_bit32u mt32emu_get_stereo_output_samplerate(const mt32emu_analog_output_mode analog_output_mode); + +/** + * Returns the value of analog_output_mode for which the output signal may retain its full frequency spectrum + * at the sample rate specified by the target_samplerate argument. + * See comment for mt32emu_analog_output_mode. + */ +MT32EMU_EXPORT mt32emu_analog_output_mode mt32emu_get_best_analog_output_mode(const double target_samplerate); + +/* == Context-dependent functions == */ + +/** Initialises a new emulation context and installs custom report handler if non-NULL. */ +MT32EMU_EXPORT mt32emu_context mt32emu_create_context(mt32emu_report_handler_i report_handler, void *instance_data); + +/** Closes and destroys emulation context. */ +MT32EMU_EXPORT void mt32emu_free_context(mt32emu_context context); + +/** + * Adds new ROM identified by its SHA1 digest to the emulation context replacing previously added ROM of the same type if any. + * Argument sha1_digest can be NULL, in this case the digest will be computed using the actual ROM data. + * If sha1_digest is set to non-NULL, it is assumed being correct and will not be recomputed. + * This function doesn't immediately change the state of already opened synth. Newly added ROM will take effect upon next call of mt32emu_open_synth(). + * Returns positive value upon success. + */ +MT32EMU_EXPORT mt32emu_return_code mt32emu_add_rom_data(mt32emu_context context, const mt32emu_bit8u *data, size_t data_size, const mt32emu_sha1_digest *sha1_digest); + +/** + * Loads a ROM file, identify it by SHA1 digest, and adds it to the emulation context replacing previously added ROM of the same type if any. + * This function doesn't immediately change the state of already opened synth. Newly added ROM will take effect upon next call of mt32emu_open_synth(). + * Returns positive value upon success. + */ +MT32EMU_EXPORT mt32emu_return_code mt32emu_add_rom_file(mt32emu_context context, const char *filename); + +/** + * Fills in mt32emu_rom_info structure with identifiers and descriptions of control and PCM ROM files identified and added to the synth context. + * If one of the ROM files is not loaded and identified yet, NULL is returned in the corresponding fields of the mt32emu_rom_info structure. + */ +MT32EMU_EXPORT void mt32emu_get_rom_info(mt32emu_const_context context, mt32emu_rom_info *rom_info); + +/** + * Allows to override the default maximum number of partials playing simultaneously within the emulation session. + * This function doesn't immediately change the state of already opened synth. Newly set value will take effect upon next call of mt32emu_open_synth(). + */ +MT32EMU_EXPORT void mt32emu_set_partial_count(mt32emu_context context, const mt32emu_bit32u partial_count); + +/** + * Allows to override the default mode for emulation of analogue circuitry of the hardware units within the emulation session. + * This function doesn't immediately change the state of already opened synth. Newly set value will take effect upon next call of mt32emu_open_synth(). + */ +MT32EMU_EXPORT void mt32emu_set_analog_output_mode(mt32emu_context context, const mt32emu_analog_output_mode analog_output_mode); + +/** + * Allows to convert the synthesiser output to any desired sample rate. The samplerate conversion + * processes the completely mixed stereo output signal as it passes the analogue circuit emulation, + * so emulating the synthesiser output signal passing further through an ADC. When the samplerate + * argument is set to 0, the default output sample rate is used which depends on the current + * mode of analog circuitry emulation. See mt32emu_analog_output_mode. + * This function doesn't immediately change the state of already opened synth. + * Newly set value will take effect upon next call of mt32emu_open_synth(). + */ +MT32EMU_EXPORT void mt32emu_set_stereo_output_samplerate(mt32emu_context context, const double samplerate); + +/** + * Several samplerate conversion quality options are provided which allow to trade-off the conversion speed vs. + * the retained passband width. All the options except FASTEST guarantee full suppression of the aliasing noise + * in terms of the 16-bit integer samples. + * This function doesn't immediately change the state of already opened synth. + * Newly set value will take effect upon next call of mt32emu_open_synth(). + */ +MT32EMU_EXPORT void mt32emu_set_samplerate_conversion_quality(mt32emu_context context, const mt32emu_samplerate_conversion_quality quality); + +/** + * Selects new type of the wave generator and renderer to be used during subsequent calls to mt32emu_open_synth(). + * By default, MT32EMU_RT_BIT16S is selected. + * See mt32emu_renderer_type for details. + */ +MT32EMU_EXPORT void mt32emu_select_renderer_type(mt32emu_context context, const mt32emu_renderer_type renderer_type); + +/** + * Returns previously selected type of the wave generator and renderer. + * See mt32emu_renderer_type for details. + */ +MT32EMU_EXPORT mt32emu_renderer_type mt32emu_get_selected_renderer_type(mt32emu_context context); + +/** + * Prepares the emulation context to receive MIDI messages and produce output audio data using aforehand added set of ROMs, + * and optionally set the maximum partial count and the analog output mode. + * Returns MT32EMU_RC_OK upon success. + */ +MT32EMU_EXPORT mt32emu_return_code mt32emu_open_synth(mt32emu_const_context context); + +/** Closes the emulation context freeing allocated resources. Added ROMs remain unaffected and ready for reuse. */ +MT32EMU_EXPORT void mt32emu_close_synth(mt32emu_const_context context); + +/** Returns true if the synth is in completely initialized state, otherwise returns false. */ +MT32EMU_EXPORT mt32emu_boolean mt32emu_is_open(mt32emu_const_context context); + +/** + * Returns actual sample rate of the fully processed output stereo signal. + * If samplerate conversion is used (i.e. when mt32emu_set_stereo_output_samplerate() has been invoked with a non-zero value), + * the returned value is the desired output samplerate rounded down to the closest integer. + * Otherwise, the output samplerate is choosen depending on the emulation mode of stereo analog circuitry of hardware units. + * See comment for mt32emu_analog_output_mode for more info. + */ +MT32EMU_EXPORT mt32emu_bit32u mt32emu_get_actual_stereo_output_samplerate(mt32emu_const_context context); + +/** + * Returns the number of samples produced at the internal synth sample rate (32000 Hz) + * that correspond to the given number of samples at the output sample rate. + * Intended to facilitate audio time synchronisation. + */ +MT32EMU_EXPORT mt32emu_bit32u mt32emu_convert_output_to_synth_timestamp(mt32emu_const_context context, mt32emu_bit32u output_timestamp); + +/** + * Returns the number of samples produced at the output sample rate + * that correspond to the given number of samples at the internal synth sample rate (32000 Hz). + * Intended to facilitate audio time synchronisation. + */ +MT32EMU_EXPORT mt32emu_bit32u mt32emu_convert_synth_to_output_timestamp(mt32emu_const_context context, mt32emu_bit32u synth_timestamp); + +/** All the enqueued events are processed by the synth immediately. */ +MT32EMU_EXPORT void mt32emu_flush_midi_queue(mt32emu_const_context context); + +/** + * Sets size of the internal MIDI event queue. The queue size is set to the minimum power of 2 that is greater or equal to the size specified. + * The queue is flushed before reallocation. + * Returns the actual queue size being used. + */ +MT32EMU_EXPORT mt32emu_bit32u mt32emu_set_midi_event_queue_size(mt32emu_const_context context, const mt32emu_bit32u queue_size); + +/** + * Installs custom MIDI receiver object intended for receiving MIDI messages generated by MIDI stream parser. + * MIDI stream parser is involved when functions mt32emu_parse_stream() and mt32emu_play_short_message() or the likes are called. + * By default, parsed short MIDI messages and System Exclusive messages are sent to the synth input MIDI queue. + * This function allows to override default behaviour. If midi_receiver argument is set to NULL, the default behaviour is restored. + */ +MT32EMU_EXPORT void mt32emu_set_midi_receiver(mt32emu_context context, mt32emu_midi_receiver_i midi_receiver, void *instance_data); + +/* Enqueues a MIDI event for subsequent playback. + * The MIDI event will be processed not before the specified timestamp. + * The timestamp is measured as the global rendered sample count since the synth was created (at the native sample rate 32000 Hz). + * The minimum delay involves emulation of the delay introduced while the event is transferred via MIDI interface + * and emulation of the MCU busy-loop while it frees partials for use by a new Poly. + * Calls from multiple threads must be synchronised, although, no synchronisation is required with the rendering thread. + * onMIDIQueueOverflow callback is invoked when the MIDI event queue is full and the message cannot be enqueued. + */ + +/** + * Parses a block of raw MIDI bytes and enqueues parsed MIDI messages for further processing ASAP. + * SysEx messages are allowed to be fragmented across several calls to this method. Running status is also handled for short messages. + * When a System Realtime MIDI message is parsed, onMIDISystemRealtime callback is invoked. + * NOTE: the total length of a SysEx message being fragmented shall not exceed MT32EMU_MAX_STREAM_BUFFER_SIZE (32768 bytes). + */ +MT32EMU_EXPORT void mt32emu_parse_stream(mt32emu_const_context context, const mt32emu_bit8u *stream, mt32emu_bit32u length); + +/** + * Parses a block of raw MIDI bytes and enqueues parsed MIDI messages to play at specified time. + * SysEx messages are allowed to be fragmented across several calls to this method. Running status is also handled for short messages. + * When a System Realtime MIDI message is parsed, onMIDISystemRealtime callback is invoked. + * NOTE: the total length of a SysEx message being fragmented shall not exceed MT32EMU_MAX_STREAM_BUFFER_SIZE (32768 bytes). + */ +MT32EMU_EXPORT void mt32emu_parse_stream_at(mt32emu_const_context context, const mt32emu_bit8u *stream, mt32emu_bit32u length, mt32emu_bit32u timestamp); + +/** + * Enqueues a single mt32emu_bit32u-encoded short MIDI message with full processing ASAP. + * The short MIDI message may contain no status byte, the running status is used in this case. + * When the argument is a System Realtime MIDI message, onMIDISystemRealtime callback is invoked. + */ +MT32EMU_EXPORT void mt32emu_play_short_message(mt32emu_const_context context, mt32emu_bit32u message); + +/** + * Enqueues a single mt32emu_bit32u-encoded short MIDI message to play at specified time with full processing. + * The short MIDI message may contain no status byte, the running status is used in this case. + * When the argument is a System Realtime MIDI message, onMIDISystemRealtime callback is invoked. + */ +MT32EMU_EXPORT void mt32emu_play_short_message_at(mt32emu_const_context context, mt32emu_bit32u message, mt32emu_bit32u timestamp); + +/** Enqueues a single short MIDI message to be processed ASAP. The message must contain a status byte. */ +MT32EMU_EXPORT mt32emu_return_code mt32emu_play_msg(mt32emu_const_context context, mt32emu_bit32u msg); +/** Enqueues a single well formed System Exclusive MIDI message to be processed ASAP. */ +MT32EMU_EXPORT mt32emu_return_code mt32emu_play_sysex(mt32emu_const_context context, const mt32emu_bit8u *sysex, mt32emu_bit32u len); + +/** Enqueues a single short MIDI message to play at specified time. The message must contain a status byte. */ +MT32EMU_EXPORT mt32emu_return_code mt32emu_play_msg_at(mt32emu_const_context context, mt32emu_bit32u msg, mt32emu_bit32u timestamp); +/** Enqueues a single well formed System Exclusive MIDI message to play at specified time. */ +MT32EMU_EXPORT mt32emu_return_code mt32emu_play_sysex_at(mt32emu_const_context context, const mt32emu_bit8u *sysex, mt32emu_bit32u len, mt32emu_bit32u timestamp); + +/* WARNING: + * The methods below don't ensure minimum 1-sample delay between sequential MIDI events, + * and a sequence of NoteOn and immediately succeeding NoteOff messages is always silent. + * A thread that invokes these methods must be explicitly synchronised with the thread performing sample rendering. + */ + +/** + * Sends a short MIDI message to the synth for immediate playback. The message must contain a status byte. + * See the WARNING above. + */ +MT32EMU_EXPORT void mt32emu_play_msg_now(mt32emu_const_context context, mt32emu_bit32u msg); +/** + * Sends unpacked short MIDI message to the synth for immediate playback. The message must contain a status byte. + * See the WARNING above. + */ +MT32EMU_EXPORT void mt32emu_play_msg_on_part(mt32emu_const_context context, mt32emu_bit8u part, mt32emu_bit8u code, mt32emu_bit8u note, mt32emu_bit8u velocity); + +/** + * Sends a single well formed System Exclusive MIDI message for immediate processing. The length is in bytes. + * See the WARNING above. + */ +MT32EMU_EXPORT void mt32emu_play_sysex_now(mt32emu_const_context context, const mt32emu_bit8u *sysex, mt32emu_bit32u len); +/** + * Sends inner body of a System Exclusive MIDI message for direct processing. The length is in bytes. + * See the WARNING above. + */ +MT32EMU_EXPORT void mt32emu_write_sysex(mt32emu_const_context context, mt32emu_bit8u channel, const mt32emu_bit8u *sysex, mt32emu_bit32u len); + +/** Allows to disable wet reverb output altogether. */ +MT32EMU_EXPORT void mt32emu_set_reverb_enabled(mt32emu_const_context context, const mt32emu_boolean reverb_enabled); +/** Returns whether wet reverb output is enabled. */ +MT32EMU_EXPORT mt32emu_boolean mt32emu_is_reverb_enabled(mt32emu_const_context context); +/** + * Sets override reverb mode. In this mode, emulation ignores sysexes (or the related part of them) which control the reverb parameters. + * This mode is in effect until it is turned off. When the synth is re-opened, the override mode is unchanged but the state + * of the reverb model is reset to default. + */ +MT32EMU_EXPORT void mt32emu_set_reverb_overridden(mt32emu_const_context context, const mt32emu_boolean reverb_overridden); +/** Returns whether reverb settings are overridden. */ +MT32EMU_EXPORT mt32emu_boolean mt32emu_is_reverb_overridden(mt32emu_const_context context); +/** + * Forces reverb model compatibility mode. By default, the compatibility mode corresponds to the used control ROM version. + * Invoking this method with the argument set to true forces emulation of old MT-32 reverb circuit. + * When the argument is false, emulation of the reverb circuit used in new generation of MT-32 compatible modules is enforced + * (these include CM-32L and LAPC-I). + */ +MT32EMU_EXPORT void mt32emu_set_reverb_compatibility_mode(mt32emu_const_context context, const mt32emu_boolean mt32_compatible_mode); +/** Returns whether reverb is in old MT-32 compatibility mode. */ +MT32EMU_EXPORT mt32emu_boolean mt32emu_is_mt32_reverb_compatibility_mode(mt32emu_const_context context); +/** Returns whether default reverb compatibility mode is the old MT-32 compatibility mode. */ +MT32EMU_EXPORT mt32emu_boolean mt32emu_is_default_reverb_mt32_compatible(mt32emu_const_context context); + +/** Sets new DAC input mode. See mt32emu_dac_input_mode for details. */ +MT32EMU_EXPORT void mt32emu_set_dac_input_mode(mt32emu_const_context context, const mt32emu_dac_input_mode mode); +/** Returns current DAC input mode. See mt32emu_dac_input_mode for details. */ +MT32EMU_EXPORT mt32emu_dac_input_mode mt32emu_get_dac_input_mode(mt32emu_const_context context); + +/** Sets new MIDI delay mode. See mt32emu_midi_delay_mode for details. */ +MT32EMU_EXPORT void mt32emu_set_midi_delay_mode(mt32emu_const_context context, const mt32emu_midi_delay_mode mode); +/** Returns current MIDI delay mode. See mt32emu_midi_delay_mode for details. */ +MT32EMU_EXPORT mt32emu_midi_delay_mode mt32emu_get_midi_delay_mode(mt32emu_const_context context); + +/** + * Sets output gain factor for synth output channels. Applied to all output samples and unrelated with the synth's Master volume, + * it rather corresponds to the gain of the output analog circuitry of the hardware units. However, together with mt32emu_set_reverb_output_gain() + * it offers to the user a capability to control the gain of reverb and non-reverb output channels independently. + * Ignored in MT32EMU_DAC_PURE mode. + */ +MT32EMU_EXPORT void mt32emu_set_output_gain(mt32emu_const_context context, float gain); +/** Returns current output gain factor for synth output channels. */ +MT32EMU_EXPORT float mt32emu_get_output_gain(mt32emu_const_context context); + +/** + * Sets output gain factor for the reverb wet output channels. It rather corresponds to the gain of the output + * analog circuitry of the hardware units. However, together with mt32emu_set_output_gain() it offers to the user a capability + * to control the gain of reverb and non-reverb output channels independently. + * + * Note: We're currently emulate CM-32L/CM-64 reverb quite accurately and the reverb output level closely + * corresponds to the level of digital capture. Although, according to the CM-64 PCB schematic, + * there is a difference in the reverb analogue circuit, and the resulting output gain is 0.68 + * of that for LA32 analogue output. This factor is applied to the reverb output gain. + * Ignored in MT32EMU_DAC_PURE mode. + */ +MT32EMU_EXPORT void mt32emu_set_reverb_output_gain(mt32emu_const_context context, float gain); +/** Returns current output gain factor for reverb wet output channels. */ +MT32EMU_EXPORT float mt32emu_get_reverb_output_gain(mt32emu_const_context context); + +/** Swaps left and right output channels. */ +MT32EMU_EXPORT void mt32emu_set_reversed_stereo_enabled(mt32emu_const_context context, const mt32emu_boolean enabled); +/** Returns whether left and right output channels are swapped. */ +MT32EMU_EXPORT mt32emu_boolean mt32emu_is_reversed_stereo_enabled(mt32emu_const_context context); + +/** + * Renders samples to the specified output stream as if they were sampled at the analog stereo output at the desired sample rate. + * If the output sample rate is not specified explicitly, the default output sample rate is used which depends on the current + * mode of analog circuitry emulation. See mt32emu_analog_output_mode. + * The length is in frames, not bytes (in 16-bit stereo, one frame is 4 bytes). Uses NATIVE byte ordering. + */ +MT32EMU_EXPORT void mt32emu_render_bit16s(mt32emu_const_context context, mt32emu_bit16s *stream, mt32emu_bit32u len); +/** Same as above but outputs to a float stereo stream. */ +MT32EMU_EXPORT void mt32emu_render_float(mt32emu_const_context context, float *stream, mt32emu_bit32u len); + +/** + * Renders samples to the specified output streams as if they appeared at the DAC entrance. + * No further processing performed in analog circuitry emulation is applied to the signal. + * NULL may be specified in place of any or all of the stream buffers to skip it. + * The length is in samples, not bytes. Uses NATIVE byte ordering. + */ +MT32EMU_EXPORT void mt32emu_render_bit16s_streams(mt32emu_const_context context, const mt32emu_dac_output_bit16s_streams *streams, mt32emu_bit32u len); +/** Same as above but outputs to float streams. */ +MT32EMU_EXPORT void mt32emu_render_float_streams(mt32emu_const_context context, const mt32emu_dac_output_float_streams *streams, mt32emu_bit32u len); + +/** Returns true when there is at least one active partial, otherwise false. */ +MT32EMU_EXPORT mt32emu_boolean mt32emu_has_active_partials(mt32emu_const_context context); + +/** Returns true if mt32emu_has_active_partials() returns true, or reverb is (somewhat unreliably) detected as being active. */ +MT32EMU_EXPORT mt32emu_boolean mt32emu_is_active(mt32emu_const_context context); + +/** Returns the maximum number of partials playing simultaneously. */ +MT32EMU_EXPORT mt32emu_bit32u mt32emu_get_partial_count(mt32emu_const_context context); + +/** + * Returns current states of all the parts as a bit set. The least significant bit corresponds to the state of part 1, + * total of 9 bits hold the states of all the parts. If the returned bit for a part is set, there is at least one active + * non-releasing partial playing on this part. This info is useful in emulating behaviour of LCD display of the hardware units. + */ +MT32EMU_EXPORT mt32emu_bit32u mt32emu_get_part_states(mt32emu_const_context context); + +/** + * Fills in current states of all the partials into the array provided. Each byte in the array holds states of 4 partials + * starting from the least significant bits. The state of each partial is packed in a pair of bits. + * The array must be large enough to accommodate states of all the partials. + * @see getPartialCount() + */ +MT32EMU_EXPORT void mt32emu_get_partial_states(mt32emu_const_context context, mt32emu_bit8u *partial_states); + +/** + * Fills in information about currently playing notes on the specified part into the arrays provided. The arrays must be large enough + * to accommodate data for all the playing notes. The maximum number of simultaneously playing notes cannot exceed the number of partials. + * Argument partNumber should be 0..7 for Part 1..8, or 8 for Rhythm. + * Returns the number of currently playing notes on the specified part. + */ +MT32EMU_EXPORT mt32emu_bit32u mt32emu_get_playing_notes(mt32emu_const_context context, mt32emu_bit8u part_number, mt32emu_bit8u *keys, mt32emu_bit8u *velocities); + +/** + * Returns name of the patch set on the specified part. + * Argument partNumber should be 0..7 for Part 1..8, or 8 for Rhythm. + */ +MT32EMU_EXPORT const char *mt32emu_get_patch_name(mt32emu_const_context context, mt32emu_bit8u part_number); + +/** Stores internal state of emulated synth into an array provided (as it would be acquired from hardware). */ +MT32EMU_EXPORT void mt32emu_read_memory(mt32emu_const_context context, mt32emu_bit32u addr, mt32emu_bit32u len, mt32emu_bit8u *data); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif /* #ifndef MT32EMU_C_INTERFACE_H */ diff --git a/src/SOUND/munt/c_interface/c_types.h b/src/SOUND/munt/c_interface/c_types.h new file mode 100644 index 000000000..bf4dab8dc --- /dev/null +++ b/src/SOUND/munt/c_interface/c_types.h @@ -0,0 +1,322 @@ +/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher + * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#ifndef MT32EMU_C_TYPES_H +#define MT32EMU_C_TYPES_H + +#include +#include + +#include "../globals.h" + +#define MT32EMU_C_ENUMERATIONS +#include "../Enumerations.h" +#undef MT32EMU_C_ENUMERATIONS + +typedef unsigned int mt32emu_bit32u; +typedef signed int mt32emu_bit32s; +typedef unsigned short int mt32emu_bit16u; +typedef signed short int mt32emu_bit16s; +typedef unsigned char mt32emu_bit8u; +typedef signed char mt32emu_bit8s; + +typedef char mt32emu_sha1_digest[41]; + +typedef enum { + MT32EMU_BOOL_FALSE, MT32EMU_BOOL_TRUE +} mt32emu_boolean; + +typedef enum { + /* Operation completed normally. */ + MT32EMU_RC_OK = 0, + MT32EMU_RC_ADDED_CONTROL_ROM = 1, + MT32EMU_RC_ADDED_PCM_ROM = 2, + + /* Definite error occurred. */ + MT32EMU_RC_ROM_NOT_IDENTIFIED = -1, + MT32EMU_RC_FILE_NOT_FOUND = -2, + MT32EMU_RC_FILE_NOT_LOADED = -3, + MT32EMU_RC_MISSING_ROMS = -4, + MT32EMU_RC_NOT_OPENED = -5, + MT32EMU_RC_QUEUE_FULL = -6, + + /* Undefined error occurred. */ + MT32EMU_RC_FAILED = -100 +} mt32emu_return_code; + +/** Emulation context */ +typedef struct mt32emu_data *mt32emu_context; +typedef const struct mt32emu_data *mt32emu_const_context; + +/* Convenience aliases */ +#ifndef __cplusplus +typedef enum mt32emu_analog_output_mode mt32emu_analog_output_mode; +typedef enum mt32emu_dac_input_mode mt32emu_dac_input_mode; +typedef enum mt32emu_midi_delay_mode mt32emu_midi_delay_mode; +typedef enum mt32emu_partial_state mt32emu_partial_state; +typedef enum mt32emu_samplerate_conversion_quality mt32emu_samplerate_conversion_quality; +typedef enum mt32emu_renderer_type mt32emu_renderer_type; +#endif + +/** Contains identifiers and descriptions of ROM files being used. */ +typedef struct { + const char *control_rom_id; + const char *control_rom_description; + const char *control_rom_sha1_digest; + const char *pcm_rom_id; + const char *pcm_rom_description; + const char *pcm_rom_sha1_digest; +} mt32emu_rom_info; + +/** Set of multiplexed output bit16s streams appeared at the DAC entrance. */ +typedef struct { + mt32emu_bit16s *nonReverbLeft; + mt32emu_bit16s *nonReverbRight; + mt32emu_bit16s *reverbDryLeft; + mt32emu_bit16s *reverbDryRight; + mt32emu_bit16s *reverbWetLeft; + mt32emu_bit16s *reverbWetRight; +} mt32emu_dac_output_bit16s_streams; + +/** Set of multiplexed output float streams appeared at the DAC entrance. */ +typedef struct { + float *nonReverbLeft; + float *nonReverbRight; + float *reverbDryLeft; + float *reverbDryRight; + float *reverbWetLeft; + float *reverbWetRight; +} mt32emu_dac_output_float_streams; + +/* === Interface handling === */ + +/** Report handler interface versions */ +typedef enum { + MT32EMU_REPORT_HANDLER_VERSION_0 = 0, + MT32EMU_REPORT_HANDLER_VERSION_CURRENT = MT32EMU_REPORT_HANDLER_VERSION_0 +} mt32emu_report_handler_version; + +/** MIDI receiver interface versions */ +typedef enum { + MT32EMU_MIDI_RECEIVER_VERSION_0 = 0, + MT32EMU_MIDI_RECEIVER_VERSION_CURRENT = MT32EMU_MIDI_RECEIVER_VERSION_0 +} mt32emu_midi_receiver_version; + +/** Synth interface versions */ +typedef enum { + MT32EMU_SERVICE_VERSION_0 = 0, + MT32EMU_SERVICE_VERSION_1 = 1, + MT32EMU_SERVICE_VERSION_CURRENT = MT32EMU_SERVICE_VERSION_1 +} mt32emu_service_version; + +/* === Report Handler Interface === */ + +typedef union mt32emu_report_handler_i mt32emu_report_handler_i; + +/** Interface for handling reported events (initial version) */ +typedef struct { + /** Returns the actual interface version ID */ + mt32emu_report_handler_version (*getVersionID)(mt32emu_report_handler_i i); + + /** Callback for debug messages, in vprintf() format */ + void (*printDebug)(void *instance_data, const char *fmt, va_list list); + /** Callbacks for reporting errors */ + void (*onErrorControlROM)(void *instance_data); + void (*onErrorPCMROM)(void *instance_data); + /** Callback for reporting about displaying a new custom message on LCD */ + void (*showLCDMessage)(void *instance_data, const char *message); + /** Callback for reporting actual processing of a MIDI message */ + void (*onMIDIMessagePlayed)(void *instance_data); + /** + * Callback for reporting an overflow of the input MIDI queue. + * Returns MT32EMU_BOOL_TRUE if a recovery action was taken + * and yet another attempt to enqueue the MIDI event is desired. + */ + mt32emu_boolean (*onMIDIQueueOverflow)(void *instance_data); + /** + * Callback invoked when a System Realtime MIDI message is detected in functions + * mt32emu_parse_stream and mt32emu_play_short_message and the likes. + */ + void (*onMIDISystemRealtime)(void *instance_data, mt32emu_bit8u system_realtime); + /** Callbacks for reporting system events */ + void (*onDeviceReset)(void *instance_data); + void (*onDeviceReconfig)(void *instance_data); + /** Callbacks for reporting changes of reverb settings */ + void (*onNewReverbMode)(void *instance_data, mt32emu_bit8u mode); + void (*onNewReverbTime)(void *instance_data, mt32emu_bit8u time); + void (*onNewReverbLevel)(void *instance_data, mt32emu_bit8u level); + /** Callbacks for reporting various information */ + void (*onPolyStateChanged)(void *instance_data, mt32emu_bit8u part_num); + void (*onProgramChanged)(void *instance_data, mt32emu_bit8u part_num, const char *sound_group_name, const char *patch_name); +} mt32emu_report_handler_i_v0; + +/** + * Extensible interface for handling reported events. + * Union intended to view an interface of any subsequent version as any parent interface not requiring a cast. + * It is caller's responsibility to check the actual interface version in runtime using the getVersionID() method. + */ +union mt32emu_report_handler_i { + const mt32emu_report_handler_i_v0 *v0; +}; + +/* === MIDI Receiver Interface === */ + +typedef union mt32emu_midi_receiver_i mt32emu_midi_receiver_i; + +/** Interface for receiving MIDI messages generated by MIDI stream parser (initial version) */ +typedef struct { + /** Returns the actual interface version ID */ + mt32emu_midi_receiver_version (*getVersionID)(mt32emu_midi_receiver_i i); + + /** Invoked when a complete short MIDI message is parsed in the input MIDI stream. */ + void (*handleShortMessage)(void *instance_data, const mt32emu_bit32u message); + + /** Invoked when a complete well-formed System Exclusive MIDI message is parsed in the input MIDI stream. */ + void (*handleSysex)(void *instance_data, const mt32emu_bit8u stream[], const mt32emu_bit32u length); + + /** Invoked when a System Realtime MIDI message is parsed in the input MIDI stream. */ + void (*handleSystemRealtimeMessage)(void *instance_data, const mt32emu_bit8u realtime); +} mt32emu_midi_receiver_i_v0; + +/** + * Extensible interface for receiving MIDI messages. + * Union intended to view an interface of any subsequent version as any parent interface not requiring a cast. + * It is caller's responsibility to check the actual interface version in runtime using the getVersionID() method. + */ +union mt32emu_midi_receiver_i { + const mt32emu_midi_receiver_i_v0 *v0; +}; + +/* === Service Interface === */ + +typedef union mt32emu_service_i mt32emu_service_i; + +/** + * Basic interface that defines all the library services (initial version). + * The members closely resemble C functions declared in c_interface.h, and the intention is to provide for easier + * access when the library is dynamically loaded in run-time, e.g. as a plugin. This way the client only needs + * to bind to mt32emu_get_service_i() function instead of binding to each function it needs to use. + * See c_interface.h for parameter description. + */ +#define MT32EMU_SERVICE_I_V0 \ + /** Returns the actual interface version ID */ \ + mt32emu_service_version (*getVersionID)(mt32emu_service_i i); \ + mt32emu_report_handler_version (*getSupportedReportHandlerVersionID)(); \ + mt32emu_midi_receiver_version (*getSupportedMIDIReceiverVersionID)(); \ +\ + mt32emu_bit32u (*getLibraryVersionInt)(); \ + const char *(*getLibraryVersionString)(); \ +\ + mt32emu_bit32u (*getStereoOutputSamplerate)(const mt32emu_analog_output_mode analog_output_mode); \ +\ + mt32emu_context (*createContext)(mt32emu_report_handler_i report_handler, void *instance_data); \ + void (*freeContext)(mt32emu_context context); \ + mt32emu_return_code (*addROMData)(mt32emu_context context, const mt32emu_bit8u *data, size_t data_size, const mt32emu_sha1_digest *sha1_digest); \ + mt32emu_return_code (*addROMFile)(mt32emu_context context, const char *filename); \ + void (*getROMInfo)(mt32emu_const_context context, mt32emu_rom_info *rom_info); \ + void (*setPartialCount)(mt32emu_context context, const mt32emu_bit32u partial_count); \ + void (*setAnalogOutputMode)(mt32emu_context context, const mt32emu_analog_output_mode analog_output_mode); \ + mt32emu_return_code (*openSynth)(mt32emu_const_context context); \ + void (*closeSynth)(mt32emu_const_context context); \ + mt32emu_boolean (*isOpen)(mt32emu_const_context context); \ + mt32emu_bit32u (*getActualStereoOutputSamplerate)(mt32emu_const_context context); \ + void (*flushMIDIQueue)(mt32emu_const_context context); \ + mt32emu_bit32u (*setMIDIEventQueueSize)(mt32emu_const_context context, const mt32emu_bit32u queue_size); \ + void (*setMIDIReceiver)(mt32emu_context context, mt32emu_midi_receiver_i midi_receiver, void *instance_data); \ +\ + void (*parseStream)(mt32emu_const_context context, const mt32emu_bit8u *stream, mt32emu_bit32u length); \ + void (*parseStream_At)(mt32emu_const_context context, const mt32emu_bit8u *stream, mt32emu_bit32u length, mt32emu_bit32u timestamp); \ + void (*playShortMessage)(mt32emu_const_context context, mt32emu_bit32u message); \ + void (*playShortMessageAt)(mt32emu_const_context context, mt32emu_bit32u message, mt32emu_bit32u timestamp); \ + mt32emu_return_code (*playMsg)(mt32emu_const_context context, mt32emu_bit32u msg); \ + mt32emu_return_code (*playSysex)(mt32emu_const_context context, const mt32emu_bit8u *sysex, mt32emu_bit32u len); \ + mt32emu_return_code (*playMsgAt)(mt32emu_const_context context, mt32emu_bit32u msg, mt32emu_bit32u timestamp); \ + mt32emu_return_code (*playSysexAt)(mt32emu_const_context context, const mt32emu_bit8u *sysex, mt32emu_bit32u len, mt32emu_bit32u timestamp); \ +\ + void (*playMsgNow)(mt32emu_const_context context, mt32emu_bit32u msg); \ + void (*playMsgOnPart)(mt32emu_const_context context, mt32emu_bit8u part, mt32emu_bit8u code, mt32emu_bit8u note, mt32emu_bit8u velocity); \ + void (*playSysexNow)(mt32emu_const_context context, const mt32emu_bit8u *sysex, mt32emu_bit32u len); \ + void (*writeSysex)(mt32emu_const_context context, mt32emu_bit8u channel, const mt32emu_bit8u *sysex, mt32emu_bit32u len); \ +\ + void (*setReverbEnabled)(mt32emu_const_context context, const mt32emu_boolean reverb_enabled); \ + mt32emu_boolean (*isReverbEnabled)(mt32emu_const_context context); \ + void (*setReverbOverridden)(mt32emu_const_context context, const mt32emu_boolean reverb_overridden); \ + mt32emu_boolean (*isReverbOverridden)(mt32emu_const_context context); \ + void (*setReverbCompatibilityMode)(mt32emu_const_context context, const mt32emu_boolean mt32_compatible_mode); \ + mt32emu_boolean (*isMT32ReverbCompatibilityMode)(mt32emu_const_context context); \ + mt32emu_boolean (*isDefaultReverbMT32Compatible)(mt32emu_const_context context); \ +\ + void (*setDACInputMode)(mt32emu_const_context context, const mt32emu_dac_input_mode mode); \ + mt32emu_dac_input_mode (*getDACInputMode)(mt32emu_const_context context); \ +\ + void (*setMIDIDelayMode)(mt32emu_const_context context, const mt32emu_midi_delay_mode mode); \ + mt32emu_midi_delay_mode (*getMIDIDelayMode)(mt32emu_const_context context); \ +\ + void (*setOutputGain)(mt32emu_const_context context, float gain); \ + float (*getOutputGain)(mt32emu_const_context context); \ + void (*setReverbOutputGain)(mt32emu_const_context context, float gain); \ + float (*getReverbOutputGain)(mt32emu_const_context context); \ +\ + void (*setReversedStereoEnabled)(mt32emu_const_context context, const mt32emu_boolean enabled); \ + mt32emu_boolean (*isReversedStereoEnabled)(mt32emu_const_context context); \ +\ + void (*renderBit16s)(mt32emu_const_context context, mt32emu_bit16s *stream, mt32emu_bit32u len); \ + void (*renderFloat)(mt32emu_const_context context, float *stream, mt32emu_bit32u len); \ + void (*renderBit16sStreams)(mt32emu_const_context context, const mt32emu_dac_output_bit16s_streams *streams, mt32emu_bit32u len); \ + void (*renderFloatStreams)(mt32emu_const_context context, const mt32emu_dac_output_float_streams *streams, mt32emu_bit32u len); \ +\ + mt32emu_boolean (*hasActivePartials)(mt32emu_const_context context); \ + mt32emu_boolean (*isActive)(mt32emu_const_context context); \ + mt32emu_bit32u (*getPartialCount)(mt32emu_const_context context); \ + mt32emu_bit32u (*getPartStates)(mt32emu_const_context context); \ + void (*getPartialStates)(mt32emu_const_context context, mt32emu_bit8u *partial_states); \ + mt32emu_bit32u (*getPlayingNotes)(mt32emu_const_context context, mt32emu_bit8u part_number, mt32emu_bit8u *keys, mt32emu_bit8u *velocities); \ + const char *(*getPatchName)(mt32emu_const_context context, mt32emu_bit8u part_number); \ + void (*readMemory)(mt32emu_const_context context, mt32emu_bit32u addr, mt32emu_bit32u len, mt32emu_bit8u *data); + +#define MT32EMU_SERVICE_I_V1 \ + mt32emu_analog_output_mode (*getBestAnalogOutputMode)(const double target_samplerate); \ + void (*setStereoOutputSampleRate)(mt32emu_context context, const double samplerate); \ + void (*setSamplerateConversionQuality)(mt32emu_context context, const mt32emu_samplerate_conversion_quality quality); \ + void (*selectRendererType)(mt32emu_context context, mt32emu_renderer_type renderer_type); \ + mt32emu_renderer_type (*getSelectedRendererType)(mt32emu_context context); \ + mt32emu_bit32u (*convertOutputToSynthTimestamp)(mt32emu_const_context context, mt32emu_bit32u output_timestamp); \ + mt32emu_bit32u (*convertSynthToOutputTimestamp)(mt32emu_const_context context, mt32emu_bit32u synth_timestamp); + +typedef struct { + MT32EMU_SERVICE_I_V0 +} mt32emu_service_i_v0; + +typedef struct { + MT32EMU_SERVICE_I_V0 + MT32EMU_SERVICE_I_V1 +} mt32emu_service_i_v1; + +/** + * Extensible interface for all the library services. + * Union intended to view an interface of any subsequent version as any parent interface not requiring a cast. + * It is caller's responsibility to check the actual interface version in runtime using the getVersionID() method. + */ +union mt32emu_service_i { + const mt32emu_service_i_v0 *v0; + const mt32emu_service_i_v1 *v1; +}; + +#undef MT32EMU_SERVICE_I_V0 +#undef MT32EMU_SERVICE_I_V1 + +#endif /* #ifndef MT32EMU_C_TYPES_H */ diff --git a/src/SOUND/munt/c_interface/cpp_interface.h b/src/SOUND/munt/c_interface/cpp_interface.h new file mode 100644 index 000000000..f40ed7037 --- /dev/null +++ b/src/SOUND/munt/c_interface/cpp_interface.h @@ -0,0 +1,468 @@ +/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher + * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#ifndef MT32EMU_CPP_INTERFACE_H +#define MT32EMU_CPP_INTERFACE_H + +#include + +#include "../globals.h" +#include "c_types.h" + +#include "../Types.h" +#include "../Enumerations.h" + +#if MT32EMU_API_TYPE == 2 + +extern "C" { + +/** Returns mt32emu_service_i interface. */ +mt32emu_service_i mt32emu_get_service_i(); + +} + +#define mt32emu_get_supported_report_handler_version i.v0->getSupportedReportHandlerVersionID +#define mt32emu_get_supported_midi_receiver_version i.v0->getSupportedMIDIReceiverVersionID +#define mt32emu_get_library_version_int i.v0->getLibraryVersionInt +#define mt32emu_get_library_version_string i.v0->getLibraryVersionString +#define mt32emu_get_stereo_output_samplerate i.v0->getStereoOutputSamplerate +#define mt32emu_get_best_analog_output_mode iV1()->getBestAnalogOutputMode +#define mt32emu_create_context i.v0->createContext +#define mt32emu_free_context i.v0->freeContext +#define mt32emu_add_rom_data i.v0->addROMData +#define mt32emu_add_rom_file i.v0->addROMFile +#define mt32emu_get_rom_info i.v0->getROMInfo +#define mt32emu_set_partial_count i.v0->setPartialCount +#define mt32emu_set_analog_output_mode i.v0->setAnalogOutputMode +#define mt32emu_set_stereo_output_samplerate iV1()->setStereoOutputSampleRate +#define mt32emu_set_samplerate_conversion_quality iV1()->setSamplerateConversionQuality +#define mt32emu_select_renderer_type iV1()->selectRendererType +#define mt32emu_get_selected_renderer_type iV1()->getSelectedRendererType +#define mt32emu_open_synth i.v0->openSynth +#define mt32emu_close_synth i.v0->closeSynth +#define mt32emu_is_open i.v0->isOpen +#define mt32emu_get_actual_stereo_output_samplerate i.v0->getActualStereoOutputSamplerate +#define mt32emu_convert_output_to_synth_timestamp iV1()->convertOutputToSynthTimestamp +#define mt32emu_convert_synth_to_output_timestamp iV1()->convertSynthToOutputTimestamp +#define mt32emu_flush_midi_queue i.v0->flushMIDIQueue +#define mt32emu_set_midi_event_queue_size i.v0->setMIDIEventQueueSize +#define mt32emu_set_midi_receiver i.v0->setMIDIReceiver +#define mt32emu_parse_stream i.v0->parseStream +#define mt32emu_parse_stream_at i.v0->parseStream_At +#define mt32emu_play_short_message i.v0->playShortMessage +#define mt32emu_play_short_message_at i.v0->playShortMessageAt +#define mt32emu_play_msg i.v0->playMsg +#define mt32emu_play_sysex i.v0->playSysex +#define mt32emu_play_msg_at i.v0->playMsgAt +#define mt32emu_play_sysex_at i.v0->playSysexAt +#define mt32emu_play_msg_now i.v0->playMsgNow +#define mt32emu_play_msg_on_part i.v0->playMsgOnPart +#define mt32emu_play_sysex_now i.v0->playSysexNow +#define mt32emu_write_sysex i.v0->writeSysex +#define mt32emu_set_reverb_enabled i.v0->setReverbEnabled +#define mt32emu_is_reverb_enabled i.v0->isReverbEnabled +#define mt32emu_set_reverb_overridden i.v0->setReverbOverridden +#define mt32emu_is_reverb_overridden i.v0->isReverbOverridden +#define mt32emu_set_reverb_compatibility_mode i.v0->setReverbCompatibilityMode +#define mt32emu_is_mt32_reverb_compatibility_mode i.v0->isMT32ReverbCompatibilityMode +#define mt32emu_is_default_reverb_mt32_compatible i.v0->isDefaultReverbMT32Compatible +#define mt32emu_set_dac_input_mode i.v0->setDACInputMode +#define mt32emu_get_dac_input_mode i.v0->getDACInputMode +#define mt32emu_set_midi_delay_mode i.v0->setMIDIDelayMode +#define mt32emu_get_midi_delay_mode i.v0->getMIDIDelayMode +#define mt32emu_set_output_gain i.v0->setOutputGain +#define mt32emu_get_output_gain i.v0->getOutputGain +#define mt32emu_set_reverb_output_gain i.v0->setReverbOutputGain +#define mt32emu_get_reverb_output_gain i.v0->getReverbOutputGain +#define mt32emu_set_reversed_stereo_enabled i.v0->setReversedStereoEnabled +#define mt32emu_is_reversed_stereo_enabled i.v0->isReversedStereoEnabled +#define mt32emu_render_bit16s i.v0->renderBit16s +#define mt32emu_render_float i.v0->renderFloat +#define mt32emu_render_bit16s_streams i.v0->renderBit16sStreams +#define mt32emu_render_float_streams i.v0->renderFloatStreams +#define mt32emu_has_active_partials i.v0->hasActivePartials +#define mt32emu_is_active i.v0->isActive +#define mt32emu_get_partial_count i.v0->getPartialCount +#define mt32emu_get_part_states i.v0->getPartStates +#define mt32emu_get_partial_states i.v0->getPartialStates +#define mt32emu_get_playing_notes i.v0->getPlayingNotes +#define mt32emu_get_patch_name i.v0->getPatchName +#define mt32emu_read_memory i.v0->readMemory + +#else // #if MT32EMU_API_TYPE == 2 + +#include "c_interface.h" + +#endif // #if MT32EMU_API_TYPE == 2 + +namespace MT32Emu { + +namespace CppInterfaceImpl { + +static const mt32emu_report_handler_i NULL_REPORT_HANDLER = { NULL }; +static mt32emu_report_handler_i getReportHandlerThunk(); +static mt32emu_midi_receiver_i getMidiReceiverThunk(); + +} + +/* + * The classes below correspond to the interfaces defined in c_types.h and provided for convenience when using C++. + * The approach used makes no assumption of any internal class data memory layout, since the C++ standard does not + * provide any detail in this area and leaves it up to the implementation. Therefore, this way portability is guaranteed, + * despite the implementation may be a little inefficient. + * See c_types.h and c_interface.h for description of the corresponding interface methods. + */ + +// Defines the interface for handling reported events. +// Corresponds to the current version of mt32emu_report_handler_i interface. +class IReportHandler { +public: + virtual void printDebug(const char *fmt, va_list list) = 0; + virtual void onErrorControlROM() = 0; + virtual void onErrorPCMROM() = 0; + virtual void showLCDMessage(const char *message) = 0; + virtual void onMIDIMessagePlayed() = 0; + virtual bool onMIDIQueueOverflow() = 0; + virtual void onMIDISystemRealtime(Bit8u system_realtime) = 0; + virtual void onDeviceReset() = 0; + virtual void onDeviceReconfig() = 0; + virtual void onNewReverbMode(Bit8u mode) = 0; + virtual void onNewReverbTime(Bit8u time) = 0; + virtual void onNewReverbLevel(Bit8u level) = 0; + virtual void onPolyStateChanged(Bit8u part_num) = 0; + virtual void onProgramChanged(Bit8u part_num, const char *sound_group_name, const char *patch_name) = 0; + +protected: + ~IReportHandler() {} +}; + +// Defines the interface for receiving MIDI messages generated by MIDI stream parser. +// Corresponds to the current version of mt32emu_midi_receiver_i interface. +class IMidiReceiver { +public: + virtual void handleShortMessage(const Bit32u message) = 0; + virtual void handleSysex(const Bit8u stream[], const Bit32u length) = 0; + virtual void handleSystemRealtimeMessage(const Bit8u realtime) = 0; + +protected: + ~IMidiReceiver() {} +}; + +// Defines all the library services. +// Corresponds to the current version of mt32emu_service_i interface. +class Service { +public: +#if MT32EMU_API_TYPE == 2 + explicit Service(mt32emu_service_i interface, mt32emu_context context = NULL) : i(interface), c(context) {} +#else + explicit Service(mt32emu_context context = NULL) : c(context) {} +#endif + ~Service() { if (c != NULL) mt32emu_free_context(c); } + + // Context-independent methods + +#if MT32EMU_API_TYPE == 2 + mt32emu_service_version getVersionID() { return i.v0->getVersionID(i); } +#endif + mt32emu_report_handler_version getSupportedReportHandlerVersionID() { return mt32emu_get_supported_report_handler_version(); } + mt32emu_midi_receiver_version getSupportedMIDIReceiverVersionID() { return mt32emu_get_supported_midi_receiver_version(); } + + Bit32u getLibraryVersionInt() { return mt32emu_get_library_version_int(); } + const char *getLibraryVersionString() { return mt32emu_get_library_version_string(); } + + Bit32u getStereoOutputSamplerate(const AnalogOutputMode analog_output_mode) { return mt32emu_get_stereo_output_samplerate(static_cast(analog_output_mode)); } + AnalogOutputMode getBestAnalogOutputMode(const double target_samplerate) { return static_cast(mt32emu_get_best_analog_output_mode(target_samplerate)); } + + // Context-dependent methods + + mt32emu_context getContext() { return c; } + void createContext(mt32emu_report_handler_i report_handler = CppInterfaceImpl::NULL_REPORT_HANDLER, void *instance_data = NULL) { freeContext(); c = mt32emu_create_context(report_handler, instance_data); } + void createContext(IReportHandler &report_handler) { createContext(CppInterfaceImpl::getReportHandlerThunk(), &report_handler); } + void freeContext() { if (c != NULL) { mt32emu_free_context(c); c = NULL; } } + mt32emu_return_code addROMData(const Bit8u *data, size_t data_size, const mt32emu_sha1_digest *sha1_digest = NULL) { return mt32emu_add_rom_data(c, data, data_size, sha1_digest); } + mt32emu_return_code addROMFile(const char *filename) { return mt32emu_add_rom_file(c, filename); } + void getROMInfo(mt32emu_rom_info *rom_info) { mt32emu_get_rom_info(c, rom_info); } + void setPartialCount(const Bit32u partial_count) { mt32emu_set_partial_count(c, partial_count); } + void setAnalogOutputMode(const AnalogOutputMode analog_output_mode) { mt32emu_set_analog_output_mode(c, static_cast(analog_output_mode)); } + void setStereoOutputSampleRate(const double samplerate) { mt32emu_set_stereo_output_samplerate(c, samplerate); } + void setSamplerateConversionQuality(const SamplerateConversionQuality quality) { mt32emu_set_samplerate_conversion_quality(c, static_cast(quality)); } + void selectRendererType(const RendererType newRendererType) { mt32emu_select_renderer_type(c, static_cast(newRendererType)); } + RendererType getSelectedRendererType() { return static_cast(mt32emu_get_selected_renderer_type(c)); } + mt32emu_return_code openSynth() { return mt32emu_open_synth(c); } + void closeSynth() { mt32emu_close_synth(c); } + bool isOpen() { return mt32emu_is_open(c) != MT32EMU_BOOL_FALSE; } + Bit32u getActualStereoOutputSamplerate() { return mt32emu_get_actual_stereo_output_samplerate(c); } + Bit32u convertOutputToSynthTimestamp(Bit32u output_timestamp) { return mt32emu_convert_output_to_synth_timestamp(c, output_timestamp); } + Bit32u convertSynthToOutputTimestamp(Bit32u synth_timestamp) { return mt32emu_convert_synth_to_output_timestamp(c, synth_timestamp); } + void flushMIDIQueue() { mt32emu_flush_midi_queue(c); } + Bit32u setMIDIEventQueueSize(const Bit32u queue_size) { return mt32emu_set_midi_event_queue_size(c, queue_size); } + void setMIDIReceiver(mt32emu_midi_receiver_i midi_receiver, void *instance_data) { mt32emu_set_midi_receiver(c, midi_receiver, instance_data); } + void setMIDIReceiver(IMidiReceiver &midi_receiver) { setMIDIReceiver(CppInterfaceImpl::getMidiReceiverThunk(), &midi_receiver); } + + void parseStream(const Bit8u *stream, Bit32u length) { mt32emu_parse_stream(c, stream, length); } + void parseStream_At(const Bit8u *stream, Bit32u length, Bit32u timestamp) { mt32emu_parse_stream_at(c, stream, length, timestamp); } + void playShortMessage(Bit32u message) { mt32emu_play_short_message(c, message); } + void playShortMessageAt(Bit32u message, Bit32u timestamp) { mt32emu_play_short_message_at(c, message, timestamp); } + mt32emu_return_code playMsg(Bit32u msg) { return mt32emu_play_msg(c, msg); } + mt32emu_return_code playSysex(const Bit8u *sysex, Bit32u len) { return mt32emu_play_sysex(c, sysex, len); } + mt32emu_return_code playMsgAt(Bit32u msg, Bit32u timestamp) { return mt32emu_play_msg_at(c, msg, timestamp); } + mt32emu_return_code playSysexAt(const Bit8u *sysex, Bit32u len, Bit32u timestamp) { return mt32emu_play_sysex_at(c, sysex, len, timestamp); } + + void playMsgNow(Bit32u msg) { mt32emu_play_msg_now(c, msg); } + void playMsgOnPart(Bit8u part, Bit8u code, Bit8u note, Bit8u velocity) { mt32emu_play_msg_on_part(c, part, code, note, velocity); } + void playSysexNow(const Bit8u *sysex, Bit32u len) { mt32emu_play_sysex_now(c, sysex, len); } + void writeSysex(Bit8u channel, const Bit8u *sysex, Bit32u len) { mt32emu_write_sysex(c, channel, sysex, len); } + + void setReverbEnabled(const bool reverb_enabled) { mt32emu_set_reverb_enabled(c, reverb_enabled ? MT32EMU_BOOL_TRUE : MT32EMU_BOOL_FALSE); } + bool isReverbEnabled() { return mt32emu_is_reverb_enabled(c) != MT32EMU_BOOL_FALSE; } + void setReverbOverridden(const bool reverb_overridden) { mt32emu_set_reverb_overridden(c, reverb_overridden ? MT32EMU_BOOL_TRUE : MT32EMU_BOOL_FALSE); } + bool isReverbOverridden() { return mt32emu_is_reverb_overridden(c) != MT32EMU_BOOL_FALSE; } + void setReverbCompatibilityMode(const bool mt32_compatible_mode) { mt32emu_set_reverb_compatibility_mode(c, mt32_compatible_mode ? MT32EMU_BOOL_TRUE : MT32EMU_BOOL_FALSE); } + bool isMT32ReverbCompatibilityMode() { return mt32emu_is_mt32_reverb_compatibility_mode(c) != MT32EMU_BOOL_FALSE; } + bool isDefaultReverbMT32Compatible() { return mt32emu_is_default_reverb_mt32_compatible(c) != MT32EMU_BOOL_FALSE; } + + void setDACInputMode(const DACInputMode mode) { mt32emu_set_dac_input_mode(c, static_cast(mode)); } + DACInputMode getDACInputMode() { return static_cast(mt32emu_get_dac_input_mode(c)); } + + void setMIDIDelayMode(const MIDIDelayMode mode) { mt32emu_set_midi_delay_mode(c, static_cast(mode)); } + MIDIDelayMode getMIDIDelayMode() { return static_cast(mt32emu_get_midi_delay_mode(c)); } + + void setOutputGain(float gain) { mt32emu_set_output_gain(c, gain); } + float getOutputGain() { return mt32emu_get_output_gain(c); } + void setReverbOutputGain(float gain) { mt32emu_set_reverb_output_gain(c, gain); } + float getReverbOutputGain() { return mt32emu_get_reverb_output_gain(c); } + + void setReversedStereoEnabled(const bool enabled) { mt32emu_set_reversed_stereo_enabled(c, enabled ? MT32EMU_BOOL_TRUE : MT32EMU_BOOL_FALSE); } + bool isReversedStereoEnabled() { return mt32emu_is_reversed_stereo_enabled(c) != MT32EMU_BOOL_FALSE; } + + void renderBit16s(Bit16s *stream, Bit32u len) { mt32emu_render_bit16s(c, stream, len); } + void renderFloat(float *stream, Bit32u len) { mt32emu_render_float(c, stream, len); } + void renderBit16sStreams(const mt32emu_dac_output_bit16s_streams *streams, Bit32u len) { mt32emu_render_bit16s_streams(c, streams, len); } + void renderFloatStreams(const mt32emu_dac_output_float_streams *streams, Bit32u len) { mt32emu_render_float_streams(c, streams, len); } + + bool hasActivePartials() { return mt32emu_has_active_partials(c) != MT32EMU_BOOL_FALSE; } + bool isActive() { return mt32emu_is_active(c) != MT32EMU_BOOL_FALSE; } + Bit32u getPartialCount() { return mt32emu_get_partial_count(c); } + Bit32u getPartStates() { return mt32emu_get_part_states(c); } + void getPartialStates(Bit8u *partial_states) { mt32emu_get_partial_states(c, partial_states); } + Bit32u getPlayingNotes(Bit8u part_number, Bit8u *keys, Bit8u *velocities) { return mt32emu_get_playing_notes(c, part_number, keys, velocities); } + const char *getPatchName(Bit8u part_number) { return mt32emu_get_patch_name(c, part_number); } + void readMemory(Bit32u addr, Bit32u len, Bit8u *data) { mt32emu_read_memory(c, addr, len, data); } + +private: +#if MT32EMU_API_TYPE == 2 + const mt32emu_service_i i; +#endif + mt32emu_context c; + +#if MT32EMU_API_TYPE == 2 + const mt32emu_service_i_v1 *iV1() { return (getVersionID() < MT32EMU_SERVICE_VERSION_1) ? NULL : i.v1; } +#endif +}; + +namespace CppInterfaceImpl { + +static mt32emu_report_handler_version getReportHandlerVersionID(mt32emu_report_handler_i) { + return MT32EMU_REPORT_HANDLER_VERSION_CURRENT; +} + +static void printDebug(void *instance_data, const char *fmt, va_list list) { + static_cast(instance_data)->printDebug(fmt, list); +} + +static void onErrorControlROM(void *instance_data) { + static_cast(instance_data)->onErrorControlROM(); +} + +static void onErrorPCMROM(void *instance_data) { + static_cast(instance_data)->onErrorPCMROM(); +} + +static void showLCDMessage(void *instance_data, const char *message) { + static_cast(instance_data)->showLCDMessage(message); +} + +static void onMIDIMessagePlayed(void *instance_data) { + static_cast(instance_data)->onMIDIMessagePlayed(); +} + +static mt32emu_boolean onMIDIQueueOverflow(void *instance_data) { + return static_cast(instance_data)->onMIDIQueueOverflow() ? MT32EMU_BOOL_TRUE : MT32EMU_BOOL_FALSE; +} + +static void onMIDISystemRealtime(void *instance_data, mt32emu_bit8u system_realtime) { + static_cast(instance_data)->onMIDISystemRealtime(system_realtime); +} + +static void onDeviceReset(void *instance_data) { + static_cast(instance_data)->onDeviceReset(); +} + +static void onDeviceReconfig(void *instance_data) { + static_cast(instance_data)->onDeviceReconfig(); +} + +static void onNewReverbMode(void *instance_data, mt32emu_bit8u mode) { + static_cast(instance_data)->onNewReverbMode(mode); +} + +static void onNewReverbTime(void *instance_data, mt32emu_bit8u time) { + static_cast(instance_data)->onNewReverbTime(time); +} + +static void onNewReverbLevel(void *instance_data, mt32emu_bit8u level) { + static_cast(instance_data)->onNewReverbLevel(level); +} + +static void onPolyStateChanged(void *instance_data, mt32emu_bit8u part_num) { + static_cast(instance_data)->onPolyStateChanged(part_num); +} + +static void onProgramChanged(void *instance_data, mt32emu_bit8u part_num, const char *sound_group_name, const char *patch_name) { + static_cast(instance_data)->onProgramChanged(part_num, sound_group_name, patch_name); +} + +static mt32emu_report_handler_i getReportHandlerThunk() { + static const mt32emu_report_handler_i_v0 REPORT_HANDLER_V0_THUNK = { + getReportHandlerVersionID, + printDebug, + onErrorControlROM, + onErrorPCMROM, + showLCDMessage, + onMIDIMessagePlayed, + onMIDIQueueOverflow, + onMIDISystemRealtime, + onDeviceReset, + onDeviceReconfig, + onNewReverbMode, + onNewReverbTime, + onNewReverbLevel, + onPolyStateChanged, + onProgramChanged + }; + + static const mt32emu_report_handler_i REPORT_HANDLER_THUNK = { &REPORT_HANDLER_V0_THUNK }; + + return REPORT_HANDLER_THUNK; +} + +static mt32emu_midi_receiver_version getMidiReceiverVersionID(mt32emu_midi_receiver_i) { + return MT32EMU_MIDI_RECEIVER_VERSION_CURRENT; +} + +static void handleShortMessage(void *instance_data, const mt32emu_bit32u message) { + static_cast(instance_data)->handleShortMessage(message); +} + +static void handleSysex(void *instance_data, const mt32emu_bit8u stream[], const mt32emu_bit32u length) { + static_cast(instance_data)->handleSysex(stream, length); +} + +static void handleSystemRealtimeMessage(void *instance_data, const mt32emu_bit8u realtime) { + static_cast(instance_data)->handleSystemRealtimeMessage(realtime); +} + +static mt32emu_midi_receiver_i getMidiReceiverThunk() { + static const mt32emu_midi_receiver_i_v0 MIDI_RECEIVER_V0_THUNK = { + getMidiReceiverVersionID, + handleShortMessage, + handleSysex, + handleSystemRealtimeMessage + }; + + static const mt32emu_midi_receiver_i MIDI_RECEIVER_THUNK = { &MIDI_RECEIVER_V0_THUNK }; + + return MIDI_RECEIVER_THUNK; +} + +} // namespace CppInterfaceImpl + +} // namespace MT32Emu + +#if MT32EMU_API_TYPE == 2 + +#undef mt32emu_get_supported_report_handler_version +#undef mt32emu_get_supported_midi_receiver_version +#undef mt32emu_get_library_version_int +#undef mt32emu_get_library_version_string +#undef mt32emu_get_stereo_output_samplerate +#undef mt32emu_get_best_analog_output_mode +#undef mt32emu_create_context +#undef mt32emu_free_context +#undef mt32emu_add_rom_data +#undef mt32emu_add_rom_file +#undef mt32emu_get_rom_info +#undef mt32emu_set_partial_count +#undef mt32emu_set_analog_output_mode +#undef mt32emu_set_stereo_output_samplerate +#undef mt32emu_set_samplerate_conversion_quality +#undef mt32emu_select_renderer_type +#undef mt32emu_get_selected_renderer_type +#undef mt32emu_open_synth +#undef mt32emu_close_synth +#undef mt32emu_is_open +#undef mt32emu_get_actual_stereo_output_samplerate +#undef mt32emu_convert_output_to_synth_timestamp +#undef mt32emu_convert_synth_to_output_timestamp +#undef mt32emu_flush_midi_queue +#undef mt32emu_set_midi_event_queue_size +#undef mt32emu_set_midi_receiver +#undef mt32emu_parse_stream +#undef mt32emu_parse_stream_at +#undef mt32emu_play_short_message +#undef mt32emu_play_short_message_at +#undef mt32emu_play_msg +#undef mt32emu_play_sysex +#undef mt32emu_play_msg_at +#undef mt32emu_play_sysex_at +#undef mt32emu_play_msg_now +#undef mt32emu_play_msg_on_part +#undef mt32emu_play_sysex_now +#undef mt32emu_write_sysex +#undef mt32emu_set_reverb_enabled +#undef mt32emu_is_reverb_enabled +#undef mt32emu_set_reverb_overridden +#undef mt32emu_is_reverb_overridden +#undef mt32emu_set_reverb_compatibility_mode +#undef mt32emu_is_mt32_reverb_compatibility_mode +#undef mt32emu_is_default_reverb_mt32_compatible +#undef mt32emu_set_dac_input_mode +#undef mt32emu_get_dac_input_mode +#undef mt32emu_set_midi_delay_mode +#undef mt32emu_get_midi_delay_mode +#undef mt32emu_set_output_gain +#undef mt32emu_get_output_gain +#undef mt32emu_set_reverb_output_gain +#undef mt32emu_get_reverb_output_gain +#undef mt32emu_set_reversed_stereo_enabled +#undef mt32emu_is_reversed_stereo_enabled +#undef mt32emu_render_bit16s +#undef mt32emu_render_float +#undef mt32emu_render_bit16s_streams +#undef mt32emu_render_float_streams +#undef mt32emu_has_active_partials +#undef mt32emu_is_active +#undef mt32emu_get_partial_count +#undef mt32emu_get_part_states +#undef mt32emu_get_partial_states +#undef mt32emu_get_playing_notes +#undef mt32emu_get_patch_name +#undef mt32emu_read_memory + +#endif // #if MT32EMU_API_TYPE == 2 + +#endif /* #ifndef MT32EMU_CPP_INTERFACE_H */ diff --git a/src/SOUND/munt/config.h b/src/SOUND/munt/config.h new file mode 100644 index 000000000..7b6cd736f --- /dev/null +++ b/src/SOUND/munt/config.h @@ -0,0 +1,38 @@ +/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher + * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#ifndef MT32EMU_CONFIG_H +#define MT32EMU_CONFIG_H + +#define MT32EMU_VERSION "2.1.0" +#define MT32EMU_VERSION_MAJOR 2 +#define MT32EMU_VERSION_MINOR 1 +#define MT32EMU_VERSION_PATCH 0 + +/* Library Exports Configuration + * + * This reflects the API types actually provided by the library build. + * 0: The full-featured C++ API is only available in this build. The client application may ONLY use MT32EMU_API_TYPE 0. + * 1: The C-compatible API is only available. The library is built as a shared object, only C functions are exported, + * and thus the client application may NOT use MT32EMU_API_TYPE 0. + * 2: The C-compatible API is only available. The library is built as a shared object, only the factory function + * is exported, and thus the client application may ONLY use MT32EMU_API_TYPE 2. + * 3: All the available API types are provided by the library build. + */ +#define MT32EMU_EXPORTS_TYPE 3 + +#endif diff --git a/src/SOUND/munt/globals.h b/src/SOUND/munt/globals.h new file mode 100644 index 000000000..d9b4e02c1 --- /dev/null +++ b/src/SOUND/munt/globals.h @@ -0,0 +1,119 @@ +/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher + * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#ifndef MT32EMU_GLOBALS_H +#define MT32EMU_GLOBALS_H + +#include "config.h" + +/* Support for compiling shared library. */ +#ifdef MT32EMU_SHARED +#if defined _WIN32 || defined __CYGWIN__ +#ifdef _MSC_VER +#ifdef mt32emu_EXPORTS +#define MT32EMU_EXPORT_ATTRIBUTE _declspec(dllexport) +#else /* #ifdef mt32emu_EXPORTS */ +#define MT32EMU_EXPORT_ATTRIBUTE _declspec(dllimport) +#endif /* #ifdef mt32emu_EXPORTS */ +#else /* #ifdef _MSC_VER */ +#ifdef mt32emu_EXPORTS +#define MT32EMU_EXPORT_ATTRIBUTE __attribute__ ((dllexport)) +#else /* #ifdef mt32emu_EXPORTS */ +#define MT32EMU_EXPORT_ATTRIBUTE __attribute__ ((dllimport)) +#endif /* #ifdef mt32emu_EXPORTS */ +#endif /* #ifdef _MSC_VER */ +#else /* #if defined _WIN32 || defined __CYGWIN__ */ +#define MT32EMU_EXPORT_ATTRIBUTE __attribute__ ((visibility("default"))) +#endif /* #if defined _WIN32 || defined __CYGWIN__ */ +#else /* #ifdef MT32EMU_SHARED */ +#define MT32EMU_EXPORT_ATTRIBUTE +#endif /* #ifdef MT32EMU_SHARED */ + +#if MT32EMU_EXPORTS_TYPE == 1 || MT32EMU_EXPORTS_TYPE == 2 +#define MT32EMU_EXPORT +#else +#define MT32EMU_EXPORT MT32EMU_EXPORT_ATTRIBUTE +#endif + +/* Useful constants */ + +/* Sample rate to use in mixing. With the progress of development, we've found way too many thing dependent. + * In order to achieve further advance in emulation accuracy, sample rate made fixed throughout the emulator, + * except the emulation of analogue path. + * The output from the synth is supposed to be resampled externally in order to convert to the desired sample rate. + */ +#define MT32EMU_SAMPLE_RATE 32000 + +/* The default value for the maximum number of partials playing simultaneously. */ +#define MT32EMU_DEFAULT_MAX_PARTIALS 32 + +/* The higher this number, the more memory will be used, but the more samples can be processed in one run - + * various parts of sample generation can be processed more efficiently in a single run. + * A run's maximum length is that given to Synth::render(), so giving a value here higher than render() is ever + * called with will give no gain (but simply waste the memory). + * Note that this value does *not* in any way impose limitations on the length given to render(), and has no effect + * on the generated audio. + * This value must be >= 1. + */ +#define MT32EMU_MAX_SAMPLES_PER_RUN 4096 + +/* The default size of the internal MIDI event queue. + * It holds the incoming MIDI events before the rendering engine actually processes them. + * The main goal is to fairly emulate the real hardware behaviour which obviously + * uses an internal MIDI event queue to gather incoming data as well as the delays + * introduced by transferring data via the MIDI interface. + * This also facilitates building of an external rendering loop + * as the queue stores timestamped MIDI events. + */ +#define MT32EMU_DEFAULT_MIDI_EVENT_QUEUE_SIZE 1024 + +/* Maximum allowed size of MIDI parser input stream buffer. + * Should suffice for any reasonable bulk dump SysEx, as the h/w units have only 32K of RAM onboard. + */ +#define MT32EMU_MAX_STREAM_BUFFER_SIZE 32768 + +/* This should correspond to the MIDI buffer size used in real h/w devices. + * CM-32L control ROM seems using 1000 bytes, old MT-32 isn't confirmed by now. + */ +#define MT32EMU_SYSEX_BUFFER_SIZE 1000 + +#if defined(__cplusplus) && MT32EMU_API_TYPE != 1 + +namespace MT32Emu +{ +const unsigned int SAMPLE_RATE = MT32EMU_SAMPLE_RATE; +#undef MT32EMU_SAMPLE_RATE + +const unsigned int DEFAULT_MAX_PARTIALS = MT32EMU_DEFAULT_MAX_PARTIALS; +#undef MT32EMU_DEFAULT_MAX_PARTIALS + +const unsigned int MAX_SAMPLES_PER_RUN = MT32EMU_MAX_SAMPLES_PER_RUN; +#undef MT32EMU_MAX_SAMPLES_PER_RUN + +const unsigned int DEFAULT_MIDI_EVENT_QUEUE_SIZE = MT32EMU_DEFAULT_MIDI_EVENT_QUEUE_SIZE; +#undef MT32EMU_DEFAULT_MIDI_EVENT_QUEUE_SIZE + +const unsigned int MAX_STREAM_BUFFER_SIZE = MT32EMU_MAX_STREAM_BUFFER_SIZE; +#undef MT32EMU_MAX_STREAM_BUFFER_SIZE + +const unsigned int SYSEX_BUFFER_SIZE = MT32EMU_SYSEX_BUFFER_SIZE; +#undef MT32EMU_SYSEX_BUFFER_SIZE +} + +#endif /* #if defined(__cplusplus) && MT32EMU_API_TYPE != 1 */ + +#endif /* #ifndef MT32EMU_GLOBALS_H */ diff --git a/src/SOUND/munt/internals.h b/src/SOUND/munt/internals.h new file mode 100644 index 000000000..0bae8d9f7 --- /dev/null +++ b/src/SOUND/munt/internals.h @@ -0,0 +1,118 @@ +/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher + * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#ifndef MT32EMU_INTERNALS_H +#define MT32EMU_INTERNALS_H + +#include "Types.h" + +// Debugging + +// 0: Standard debug output is not stamped with the rendered sample count +// 1: Standard debug output is stamped with the rendered sample count +// NOTE: The "samplestamp" corresponds to the end of the last completed rendering run. +// This is important to bear in mind for debug output that occurs during a run. +#ifndef MT32EMU_DEBUG_SAMPLESTAMPS +#define MT32EMU_DEBUG_SAMPLESTAMPS 0 +#endif + +// 0: No debug output for initialisation progress +// 1: Debug output for initialisation progress +#ifndef MT32EMU_MONITOR_INIT +#define MT32EMU_MONITOR_INIT 0 +#endif + +// 0: No debug output for MIDI events +// 1: Debug output for weird MIDI events +#ifndef MT32EMU_MONITOR_MIDI +#define MT32EMU_MONITOR_MIDI 0 +#endif + +// 0: No debug output for note on/off +// 1: Basic debug output for note on/off +// 2: Comprehensive debug output for note on/off +#ifndef MT32EMU_MONITOR_INSTRUMENTS +#define MT32EMU_MONITOR_INSTRUMENTS 0 +#endif + +// 0: No debug output for partial allocations +// 1: Show partial stats when an allocation fails +// 2: Show partial stats with every new poly +// 3: Show individual partial allocations/deactivations +#ifndef MT32EMU_MONITOR_PARTIALS +#define MT32EMU_MONITOR_PARTIALS 0 +#endif + +// 0: No debug output for sysex +// 1: Basic debug output for sysex +#ifndef MT32EMU_MONITOR_SYSEX +#define MT32EMU_MONITOR_SYSEX 0 +#endif + +// 0: No debug output for sysex writes to the timbre areas +// 1: Debug output with the name and location of newly-written timbres +// 2: Complete dump of timbre parameters for newly-written timbres +#ifndef MT32EMU_MONITOR_TIMBRES +#define MT32EMU_MONITOR_TIMBRES 0 +#endif + +// 0: No TVA/TVF-related debug output. +// 1: Shows changes to TVA/TVF target, increment and phase. +#ifndef MT32EMU_MONITOR_TVA +#define MT32EMU_MONITOR_TVA 0 +#endif +#ifndef MT32EMU_MONITOR_TVF +#define MT32EMU_MONITOR_TVF 0 +#endif + +// Configuration + +// If non-zero, deletes reverb buffers that are not in use to save memory. +// If zero, keeps reverb buffers for all modes around all the time to avoid allocating/freeing in the critical path. +#ifndef MT32EMU_REDUCE_REVERB_MEMORY +#define MT32EMU_REDUCE_REVERB_MEMORY 1 +#endif + +// 0: Maximum speed at the cost of a bit lower emulation accuracy. +// 1: Maximum achievable emulation accuracy. +#ifndef MT32EMU_BOSS_REVERB_PRECISE_MODE +#define MT32EMU_BOSS_REVERB_PRECISE_MODE 0 +#endif + +namespace MT32Emu { + +typedef Bit16s IntSample; +typedef Bit32s IntSampleEx; +typedef float FloatSample; + +enum PolyState { + POLY_Playing, + POLY_Held, // This marks keys that have been released on the keyboard, but are being held by the pedal + POLY_Releasing, + POLY_Inactive +}; + +enum ReverbMode { + REVERB_MODE_ROOM, + REVERB_MODE_HALL, + REVERB_MODE_PLATE, + REVERB_MODE_TAP_DELAY +}; + +} // namespace MT32Emu + +#endif // #ifndef MT32EMU_INTERNALS_H diff --git a/src/SOUND/munt/mmath.h b/src/SOUND/munt/mmath.h new file mode 100644 index 000000000..9a9e642ba --- /dev/null +++ b/src/SOUND/munt/mmath.h @@ -0,0 +1,68 @@ +/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher + * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#ifndef MT32EMU_MMATH_H +#define MT32EMU_MMATH_H + +#include + +namespace MT32Emu { + +// Mathematical constants +const double DOUBLE_PI = 3.141592653589793; +const double DOUBLE_LN_10 = 2.302585092994046; +const float FLOAT_PI = 3.1415927f; +const float FLOAT_2PI = 6.2831853f; +const float FLOAT_LN_2 = 0.6931472f; +const float FLOAT_LN_10 = 2.3025851f; + +static inline float POWF(float x, float y) { + return pow(x, y); +} + +static inline float EXPF(float x) { + return exp(x); +} + +static inline float EXP2F(float x) { +#ifdef __APPLE__ + // on OSX exp2f() is 1.59 times faster than "exp() and the multiplication with FLOAT_LN_2" + return exp2f(x); +#else + return exp(FLOAT_LN_2 * x); +#endif +} + +static inline float EXP10F(float x) { + return exp(FLOAT_LN_10 * x); +} + +static inline float LOGF(float x) { + return log(x); +} + +static inline float LOG2F(float x) { + return log(x) / FLOAT_LN_2; +} + +static inline float LOG10F(float x) { + return log10(x); +} + +} // namespace MT32Emu + +#endif // #ifndef MT32EMU_MMATH_H diff --git a/src/SOUND/munt/mt32emu.h b/src/SOUND/munt/mt32emu.h new file mode 100644 index 000000000..6b93121be --- /dev/null +++ b/src/SOUND/munt/mt32emu.h @@ -0,0 +1,84 @@ +/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher + * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#ifndef MT32EMU_MT32EMU_H +#define MT32EMU_MT32EMU_H + +#include "config.h" + +/* API Configuration */ + +/* 0: Use full-featured C++ API. Well suitable when the library is to be linked statically. + * When the library is shared, ABI compatibility may be an issue. Therefore, it should + * only be used within a project comprising of several modules to share the library code. + * 1: Use C-compatible API. Make the library looks as a regular C library with well-defined ABI. + * This is also crucial when the library is to be linked with modules in a different + * language, either statically or dynamically. + * 2: Use plugin-like API via C-interface wrapped in a C++ class. This is mainly intended + * for a shared library being dynamically loaded in run-time. To get access to all the library + * services, a client application only needs to bind with a single factory function. + * 3: Use optimised C++ API compatible with the plugin API (type 2). The facade class also wraps + * the C functions but they are invoked directly. This enables the compiler to generate better + * code for the library when linked statically yet being consistent with the plugin-like API. + */ + +#ifdef MT32EMU_API_TYPE +#if MT32EMU_API_TYPE == 0 && (MT32EMU_EXPORTS_TYPE == 1 || MT32EMU_EXPORTS_TYPE == 2) +#error Incompatible setting MT32EMU_API_TYPE=0 +#elif MT32EMU_API_TYPE == 1 && (MT32EMU_EXPORTS_TYPE == 0 || MT32EMU_EXPORTS_TYPE == 2) +#error Incompatible setting MT32EMU_API_TYPE=1 +#elif MT32EMU_API_TYPE == 2 && (MT32EMU_EXPORTS_TYPE == 0) +#error Incompatible setting MT32EMU_API_TYPE=2 +#elif MT32EMU_API_TYPE == 3 && (MT32EMU_EXPORTS_TYPE == 0 || MT32EMU_EXPORTS_TYPE == 2) +#error Incompatible setting MT32EMU_API_TYPE=3 +#endif +#else /* #ifdef MT32EMU_API_TYPE */ +#if 0 < MT32EMU_EXPORTS_TYPE && MT32EMU_EXPORTS_TYPE < 3 +#define MT32EMU_API_TYPE MT32EMU_EXPORTS_TYPE +#else +#define MT32EMU_API_TYPE 0 +#endif +#endif /* #ifdef MT32EMU_API_TYPE */ + +/* MT32EMU_SHARED should be defined when building shared library, especially for Windows platforms. */ +/* +#define MT32EMU_SHARED +*/ + +#include "globals.h" + +#if !defined(__cplusplus) || MT32EMU_API_TYPE == 1 + +#include "c_interface/c_interface.h" + +#elif MT32EMU_API_TYPE == 2 || MT32EMU_API_TYPE == 3 + +#include "c_interface/cpp_interface.h" + +#else /* #if !defined(__cplusplus) || MT32EMU_API_TYPE == 1 */ + +#include "Types.h" +#include "File.h" +#include "FileStream.h" +#include "ROMInfo.h" +#include "Synth.h" +#include "MidiStreamParser.h" +#include "SampleRateConverter.h" + +#endif /* #if !defined(__cplusplus) || MT32EMU_API_TYPE == 1 */ + +#endif /* #ifndef MT32EMU_MT32EMU_H */ diff --git a/src/SOUND/munt/sha1/sha1.cpp b/src/SOUND/munt/sha1/sha1.cpp new file mode 100644 index 000000000..9b91cd9f2 --- /dev/null +++ b/src/SOUND/munt/sha1/sha1.cpp @@ -0,0 +1,185 @@ +/* + Copyright (c) 2011, Micael Hildenborg + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of Micael Hildenborg nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY Micael Hildenborg ''AS IS'' AND ANY + EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL Micael Hildenborg BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + Contributors: + Gustav + Several members in the gamedev.se forum. + Gregory Petrosyan + */ + +#include "sha1.h" + +namespace sha1 +{ + namespace // local + { + // Rotate an integer value to left. + inline unsigned int rol(const unsigned int value, + const unsigned int steps) + { + return ((value << steps) | (value >> (32 - steps))); + } + + // Sets the first 16 integers in the buffert to zero. + // Used for clearing the W buffert. + inline void clearWBuffert(unsigned int* buffert) + { + for (int pos = 16; --pos >= 0;) + { + buffert[pos] = 0; + } + } + + void innerHash(unsigned int* result, unsigned int* w) + { + unsigned int a = result[0]; + unsigned int b = result[1]; + unsigned int c = result[2]; + unsigned int d = result[3]; + unsigned int e = result[4]; + + int round = 0; + + #define sha1macro(func,val) \ + { \ + const unsigned int t = rol(a, 5) + (func) + e + val + w[round]; \ + e = d; \ + d = c; \ + c = rol(b, 30); \ + b = a; \ + a = t; \ + } + + while (round < 16) + { + sha1macro((b & c) | (~b & d), 0x5a827999) + ++round; + } + while (round < 20) + { + w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1); + sha1macro((b & c) | (~b & d), 0x5a827999) + ++round; + } + while (round < 40) + { + w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1); + sha1macro(b ^ c ^ d, 0x6ed9eba1) + ++round; + } + while (round < 60) + { + w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1); + sha1macro((b & c) | (b & d) | (c & d), 0x8f1bbcdc) + ++round; + } + while (round < 80) + { + w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1); + sha1macro(b ^ c ^ d, 0xca62c1d6) + ++round; + } + + #undef sha1macro + + result[0] += a; + result[1] += b; + result[2] += c; + result[3] += d; + result[4] += e; + } + } // namespace + + void calc(const void* src, const int bytelength, unsigned char* hash) + { + // Init the result array. + unsigned int result[5] = { 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0 }; + + // Cast the void src pointer to be the byte array we can work with. + const unsigned char* sarray = static_cast(src); + + // The reusable round buffer + unsigned int w[80]; + + // Loop through all complete 64byte blocks. + const int endOfFullBlocks = bytelength - 64; + int endCurrentBlock; + int currentBlock = 0; + + while (currentBlock <= endOfFullBlocks) + { + endCurrentBlock = currentBlock + 64; + + // Init the round buffer with the 64 byte block data. + for (int roundPos = 0; currentBlock < endCurrentBlock; currentBlock += 4) + { + // This line will swap endian on big endian and keep endian on little endian. + w[roundPos++] = static_cast(sarray[currentBlock + 3]) + | (static_cast(sarray[currentBlock + 2]) << 8) + | (static_cast(sarray[currentBlock + 1]) << 16) + | (static_cast(sarray[currentBlock]) << 24); + } + innerHash(result, w); + } + + // Handle the last and not full 64 byte block if existing. + endCurrentBlock = bytelength - currentBlock; + clearWBuffert(w); + int lastBlockBytes = 0; + for (;lastBlockBytes < endCurrentBlock; ++lastBlockBytes) + { + w[lastBlockBytes >> 2] |= static_cast(sarray[lastBlockBytes + currentBlock]) << ((3 - (lastBlockBytes & 3)) << 3); + } + w[lastBlockBytes >> 2] |= 0x80 << ((3 - (lastBlockBytes & 3)) << 3); + if (endCurrentBlock >= 56) + { + innerHash(result, w); + clearWBuffert(w); + } + w[15] = bytelength << 3; + innerHash(result, w); + + // Store hash in result pointer, and make sure we get in in the correct order on both endian models. + for (int hashByte = 20; --hashByte >= 0;) + { + hash[hashByte] = (result[hashByte >> 2] >> (((3 - hashByte) & 0x3) << 3)) & 0xff; + } + } + + void toHexString(const unsigned char* hash, char* hexstring) + { + const char hexDigits[] = { "0123456789abcdef" }; + + for (int hashByte = 20; --hashByte >= 0;) + { + hexstring[hashByte << 1] = hexDigits[(hash[hashByte] >> 4) & 0xf]; + hexstring[(hashByte << 1) + 1] = hexDigits[hash[hashByte] & 0xf]; + } + hexstring[40] = 0; + } +} // namespace sha1 diff --git a/src/SOUND/munt/sha1/sha1.h b/src/SOUND/munt/sha1/sha1.h new file mode 100644 index 000000000..96d8ce4da --- /dev/null +++ b/src/SOUND/munt/sha1/sha1.h @@ -0,0 +1,49 @@ +/* + Copyright (c) 2011, Micael Hildenborg + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of Micael Hildenborg nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY Micael Hildenborg ''AS IS'' AND ANY + EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL Micael Hildenborg BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef SHA1_DEFINED +#define SHA1_DEFINED + +namespace sha1 +{ + + /** + @param src points to any kind of data to be hashed. + @param bytelength the number of bytes to hash from the src pointer. + @param hash should point to a buffer of at least 20 bytes of size for storing the sha1 result in. + */ + void calc(const void* src, const int bytelength, unsigned char* hash); + + /** + @param hash is 20 bytes of sha1 hash. This is the same data that is the result from the calc function. + @param hexstring should point to a buffer of at least 41 bytes of size for storing the hexadecimal representation of the hash. A zero will be written at position 40, so the buffer will be a valid zero ended string. + */ + void toHexString(const unsigned char* hash, char* hexstring); + +} // namespace sha1 + +#endif // SHA1_DEFINED diff --git a/src/SOUND/munt/srchelper/InternalResampler.cpp b/src/SOUND/munt/srchelper/InternalResampler.cpp new file mode 100644 index 000000000..782d39bbe --- /dev/null +++ b/src/SOUND/munt/srchelper/InternalResampler.cpp @@ -0,0 +1,74 @@ +/* Copyright (C) 2015-2017 Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#include "InternalResampler.h" + +#include +#include + +#include "../Synth.h" + +using namespace SRCTools; + +namespace MT32Emu { + +class SynthWrapper : public FloatSampleProvider { + Synth &synth; + +public: + SynthWrapper(Synth &useSynth) : synth(useSynth) + {} + + void getOutputSamples(FloatSample *outBuffer, unsigned int size) { + synth.render(outBuffer, size); + } +}; + +static FloatSampleProvider &createModel(Synth &synth, SRCTools::FloatSampleProvider &synthSource, double targetSampleRate, SamplerateConversionQuality quality) { + static const double MAX_AUDIBLE_FREQUENCY = 20000.0; + + const double sourceSampleRate = synth.getStereoOutputSampleRate(); + if (quality != SamplerateConversionQuality_FASTEST) { + const bool oversampledMode = synth.getStereoOutputSampleRate() == Synth::getStereoOutputSampleRate(AnalogOutputMode_OVERSAMPLED); + // Oversampled input allows to bypass IIR interpolation stage and, in some cases, IIR decimation stage + if (oversampledMode && (0.5 * sourceSampleRate) <= targetSampleRate) { + // NOTE: In the oversampled mode, the transition band starts at 20kHz and ends at 28kHz + double passband = MAX_AUDIBLE_FREQUENCY; + double stopband = 0.5 * sourceSampleRate + MAX_AUDIBLE_FREQUENCY; + ResamplerStage &resamplerStage = *SincResampler::createSincResampler(sourceSampleRate, targetSampleRate, passband, stopband, ResamplerModel::DEFAULT_DB_SNR, ResamplerModel::DEFAULT_WINDOWED_SINC_MAX_UPSAMPLE_FACTOR); + return ResamplerModel::createResamplerModel(synthSource, resamplerStage); + } + } + return ResamplerModel::createResamplerModel(synthSource, sourceSampleRate, targetSampleRate, static_cast(quality)); +} + +} // namespace MT32Emu + +using namespace MT32Emu; + +InternalResampler::InternalResampler(Synth &synth, double targetSampleRate, SamplerateConversionQuality quality) : + synthSource(*new SynthWrapper(synth)), + model(createModel(synth, synthSource, targetSampleRate, quality)) +{} + +InternalResampler::~InternalResampler() { + ResamplerModel::freeResamplerModel(model, synthSource); + delete &synthSource; +} + +void InternalResampler::getOutputSamples(float *buffer, unsigned int length) { + model.getOutputSamples(buffer, length); +} diff --git a/src/SOUND/munt/srchelper/InternalResampler.h b/src/SOUND/munt/srchelper/InternalResampler.h new file mode 100644 index 000000000..87f8ff25d --- /dev/null +++ b/src/SOUND/munt/srchelper/InternalResampler.h @@ -0,0 +1,42 @@ +/* Copyright (C) 2015-2017 Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#ifndef MT32EMU_INTERNAL_RESAMPLER_H +#define MT32EMU_INTERNAL_RESAMPLER_H + +#include "../Enumerations.h" + +#include "FloatSampleProvider.h" + +namespace MT32Emu { + +class Synth; + +class InternalResampler { +public: + InternalResampler(Synth &synth, double targetSampleRate, SamplerateConversionQuality quality); + ~InternalResampler(); + + void getOutputSamples(float *buffer, unsigned int length); + +private: + SRCTools::FloatSampleProvider &synthSource; + SRCTools::FloatSampleProvider &model; +}; + +} // namespace MT32Emu + +#endif // MT32EMU_INTERNAL_RESAMPLER_H diff --git a/src/SOUND/munt/srchelper/SamplerateAdapter.cpp b/src/SOUND/munt/srchelper/SamplerateAdapter.cpp new file mode 100644 index 000000000..715d29872 --- /dev/null +++ b/src/SOUND/munt/srchelper/SamplerateAdapter.cpp @@ -0,0 +1,99 @@ +/* Copyright (C) 2015-2017 Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#include "SamplerateAdapter.h" + +#include "../Synth.h" + +using namespace MT32Emu; + +static const unsigned int CHANNEL_COUNT = 2; + +long SamplerateAdapter::getInputSamples(void *cb_data, float **data) { + SamplerateAdapter *instance = static_cast(cb_data); + unsigned int length = instance->inBufferSize < 1 ? 1 : (MAX_SAMPLES_PER_RUN < instance->inBufferSize ? MAX_SAMPLES_PER_RUN : instance->inBufferSize); + instance->synth.render(instance->inBuffer, length); + *data = instance->inBuffer; + instance->inBufferSize -= length; + return length; +} + +SamplerateAdapter::SamplerateAdapter(Synth &useSynth, double targetSampleRate, SamplerateConversionQuality quality) : + synth(useSynth), + inBuffer(new float[CHANNEL_COUNT * MAX_SAMPLES_PER_RUN]), + inBufferSize(MAX_SAMPLES_PER_RUN), + inputToOutputRatio(useSynth.getStereoOutputSampleRate() / targetSampleRate), + outputToInputRatio(targetSampleRate / useSynth.getStereoOutputSampleRate()) +{ + int error; + int conversionType; + switch (quality) { + case SamplerateConversionQuality_FASTEST: + conversionType = SRC_LINEAR; + break; + case SamplerateConversionQuality_FAST: + conversionType = SRC_SINC_FASTEST; + break; + case SamplerateConversionQuality_BEST: + conversionType = SRC_SINC_BEST_QUALITY; + break; + case SamplerateConversionQuality_GOOD: + default: + conversionType = SRC_SINC_MEDIUM_QUALITY; + break; + }; + resampler = src_callback_new(getInputSamples, conversionType, CHANNEL_COUNT, &error, this); + if (error != 0) { + synth.printDebug("SamplerateAdapter: Creation of Samplerate instance failed: %s\n", src_strerror(error)); + src_delete(resampler); + resampler = NULL; + } +} + +SamplerateAdapter::~SamplerateAdapter() { + delete[] inBuffer; + src_delete(resampler); +} + +void SamplerateAdapter::getOutputSamples(float *buffer, unsigned int length) { + if (resampler == NULL) { + Synth::muteSampleBuffer(buffer, CHANNEL_COUNT * length); + return; + } + while (length > 0) { + inBufferSize = static_cast(length * inputToOutputRatio + 0.5); + long gotFrames = src_callback_read(resampler, outputToInputRatio, long(length), buffer); + int error = src_error(resampler); + if (error != 0) { + synth.printDebug("SamplerateAdapter: Samplerate error during processing: %s > resetting\n", src_strerror(error)); + error = src_reset(resampler); + if (error != 0) { + synth.printDebug("SamplerateAdapter: Samplerate failed to reset: %s\n", src_strerror(error)); + src_delete(resampler); + resampler = NULL; + Synth::muteSampleBuffer(buffer, CHANNEL_COUNT * length); + synth.printDebug("SamplerateAdapter: Samplerate disabled\n"); + return; + } + continue; + } + if (gotFrames <= 0) { + synth.printDebug("SamplerateAdapter: got %li frames from Samplerate, weird\n", gotFrames); + } + buffer += CHANNEL_COUNT * gotFrames; + length -= gotFrames; + } +} diff --git a/src/SOUND/munt/srchelper/SamplerateAdapter.h b/src/SOUND/munt/srchelper/SamplerateAdapter.h new file mode 100644 index 000000000..0991fd771 --- /dev/null +++ b/src/SOUND/munt/srchelper/SamplerateAdapter.h @@ -0,0 +1,48 @@ +/* Copyright (C) 2015-2017 Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#ifndef MT32EMU_SAMPLERATE_ADAPTER_H +#define MT32EMU_SAMPLERATE_ADAPTER_H + +#include + +#include "../Enumerations.h" + +namespace MT32Emu { + +class Synth; + +class SamplerateAdapter { +public: + SamplerateAdapter(Synth &synth, double targetSampleRate, SamplerateConversionQuality quality); + ~SamplerateAdapter(); + + void getOutputSamples(float *outBuffer, unsigned int length); + +private: + Synth &synth; + float * const inBuffer; + unsigned int inBufferSize; + const double inputToOutputRatio; + const double outputToInputRatio; + SRC_STATE *resampler; + + static long getInputSamples(void *cb_data, float **data); +}; + +} // namespace MT32Emu + +#endif // MT32EMU_SAMPLERATE_ADAPTER_H diff --git a/src/SOUND/munt/srchelper/SoxrAdapter.cpp b/src/SOUND/munt/srchelper/SoxrAdapter.cpp new file mode 100644 index 000000000..5e8dca97d --- /dev/null +++ b/src/SOUND/munt/srchelper/SoxrAdapter.cpp @@ -0,0 +1,106 @@ +/* Copyright (C) 2015-2017 Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#include "SoxrAdapter.h" + +#include "../Synth.h" + +using namespace MT32Emu; + +static const unsigned int CHANNEL_COUNT = 2; + +size_t SoxrAdapter::getInputSamples(void *input_fn_state, soxr_in_t *data, size_t requested_len) { + unsigned int length = requested_len < 1 ? 1 : (MAX_SAMPLES_PER_RUN < requested_len ? MAX_SAMPLES_PER_RUN : static_cast(requested_len)); + SoxrAdapter *instance = static_cast(input_fn_state); + instance->synth.render(instance->inBuffer, length); + *data = instance->inBuffer; + return length; +} + +SoxrAdapter::SoxrAdapter(Synth &useSynth, double targetSampleRate, SamplerateConversionQuality quality) : + synth(useSynth), + inBuffer(new float[CHANNEL_COUNT * MAX_SAMPLES_PER_RUN]) +{ + soxr_io_spec_t ioSpec = soxr_io_spec(SOXR_FLOAT32_I, SOXR_FLOAT32_I); + unsigned long qualityRecipe; + switch (quality) { + case SamplerateConversionQuality_FASTEST: + qualityRecipe = SOXR_QQ; + break; + case SamplerateConversionQuality_FAST: + qualityRecipe = SOXR_LQ; + break; + case SamplerateConversionQuality_GOOD: + qualityRecipe = SOXR_MQ; + break; + case SamplerateConversionQuality_BEST: + default: + qualityRecipe = SOXR_16_BITQ; + break; + }; + soxr_quality_spec_t qSpec = soxr_quality_spec(qualityRecipe, 0); + soxr_runtime_spec_t rtSpec = soxr_runtime_spec(1); + soxr_error_t error; + resampler = soxr_create(synth.getStereoOutputSampleRate(), targetSampleRate, CHANNEL_COUNT, &error, &ioSpec, &qSpec, &rtSpec); + if (error != NULL) { + synth.printDebug("SoxrAdapter: Creation of SOXR instance failed: %s\n", soxr_strerror(error)); + soxr_delete(resampler); + resampler = NULL; + return; + } + error = soxr_set_input_fn(resampler, getInputSamples, this, MAX_SAMPLES_PER_RUN); + if (error != NULL) { + synth.printDebug("SoxrAdapter: Installing sample feed for SOXR failed: %s\n", soxr_strerror(error)); + soxr_delete(resampler); + resampler = NULL; + } +} + +SoxrAdapter::~SoxrAdapter() { + delete[] inBuffer; + if (resampler != NULL) { + soxr_delete(resampler); + } +} + +void SoxrAdapter::getOutputSamples(float *buffer, unsigned int length) { + if (resampler == NULL) { + Synth::muteSampleBuffer(buffer, CHANNEL_COUNT * length); + return; + } + while (length > 0) { + size_t gotFrames = soxr_output(resampler, buffer, size_t(length)); + soxr_error_t error = soxr_error(resampler); + if (error != NULL) { + synth.printDebug("SoxrAdapter: SOXR error during processing: %s > resetting\n", soxr_strerror(error)); + error = soxr_clear(resampler); + if (error != NULL) { + synth.printDebug("SoxrAdapter: SOXR failed to reset: %s\n", soxr_strerror(error)); + soxr_delete(resampler); + resampler = NULL; + Synth::muteSampleBuffer(buffer, CHANNEL_COUNT * length); + synth.printDebug("SoxrAdapter: SOXR disabled\n"); + return; + } + continue; + } + if (gotFrames == 0) { + synth.printDebug("SoxrAdapter: got 0 frames from SOXR, weird\n"); + } + buffer += CHANNEL_COUNT * gotFrames; + length -= static_cast(gotFrames); + } +} diff --git a/src/SOUND/munt/srchelper/SoxrAdapter.h b/src/SOUND/munt/srchelper/SoxrAdapter.h new file mode 100644 index 000000000..b97ca4da5 --- /dev/null +++ b/src/SOUND/munt/srchelper/SoxrAdapter.h @@ -0,0 +1,45 @@ +/* Copyright (C) 2015-2017 Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#ifndef MT32EMU_SOXR_ADAPTER_H +#define MT32EMU_SOXR_ADAPTER_H + +#include + +#include "../Enumerations.h" + +namespace MT32Emu { + +class Synth; + +class SoxrAdapter { +public: + SoxrAdapter(Synth &synth, double targetSampleRate, SamplerateConversionQuality quality); + ~SoxrAdapter(); + + void getOutputSamples(float *buffer, unsigned int length); + +private: + Synth &synth; + float * const inBuffer; + soxr_t resampler; + + static size_t getInputSamples(void *input_fn_state, soxr_in_t *data, size_t requested_len); +}; + +} // namespace MT32Emu + +#endif // MT32EMU_SOXR_ADAPTER_H diff --git a/src/SOUND/munt/srchelper/srctools/include/FIRResampler.h b/src/SOUND/munt/srchelper/srctools/include/FIRResampler.h new file mode 100644 index 000000000..7c09bf8de --- /dev/null +++ b/src/SOUND/munt/srchelper/srctools/include/FIRResampler.h @@ -0,0 +1,67 @@ +/* Copyright (C) 2015-2017 Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#ifndef SRCTOOLS_FIR_RESAMPLER_H +#define SRCTOOLS_FIR_RESAMPLER_H + +#include "ResamplerStage.h" + +namespace SRCTools { + +typedef FloatSample FIRCoefficient; + +static const unsigned int FIR_INTERPOLATOR_CHANNEL_COUNT = 2; + +class FIRResampler : public ResamplerStage { +public: + FIRResampler(const unsigned int upsampleFactor, const double downsampleFactor, const FIRCoefficient kernel[], const unsigned int kernelLength); + ~FIRResampler(); + + void process(const FloatSample *&inSamples, unsigned int &inLength, FloatSample *&outSamples, unsigned int &outLength); + unsigned int estimateInLength(const unsigned int outLength) const; + +private: + const struct Constants { + // Filter coefficients + const FIRCoefficient *taps; + // Indicates whether to interpolate filter taps + bool usePhaseInterpolation; + // Size of array of filter coefficients + unsigned int numberOfTaps; + // Upsampling factor + unsigned int numberOfPhases; + // Downsampling factor + double phaseIncrement; + // Index of last delay line element, generally greater than numberOfTaps to form a proper binary mask + unsigned int delayLineMask; + // Delay line + FloatSample(*ringBuffer)[FIR_INTERPOLATOR_CHANNEL_COUNT]; + + Constants(const unsigned int upsampleFactor, const double downsampleFactor, const FIRCoefficient kernel[], const unsigned int kernelLength); + } constants; + // Index of current sample in delay line + unsigned int ringBufferPosition; + // Current phase + double phase; + + bool needNextInSample() const; + void addInSamples(const FloatSample *&inSamples); + void getOutSamplesStereo(FloatSample *&outSamples); +}; // class FIRResampler + +} // namespace SRCTools + +#endif // SRCTOOLS_FIR_RESAMPLER_H diff --git a/src/SOUND/munt/srchelper/srctools/include/FloatSampleProvider.h b/src/SOUND/munt/srchelper/srctools/include/FloatSampleProvider.h new file mode 100644 index 000000000..e48afcced --- /dev/null +++ b/src/SOUND/munt/srchelper/srctools/include/FloatSampleProvider.h @@ -0,0 +1,34 @@ +/* Copyright (C) 2015-2017 Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#ifndef SRCTOOLS_FLOAT_SAMPLE_PROVIDER_H +#define SRCTOOLS_FLOAT_SAMPLE_PROVIDER_H + +namespace SRCTools { + +typedef float FloatSample; + +/** Interface defines an abstract source of samples. It can either define a single channel stream or a stream with interleaved channels. */ +class FloatSampleProvider { +public: + virtual ~FloatSampleProvider() {}; + + virtual void getOutputSamples(FloatSample *outBuffer, unsigned int size) = 0; +}; + +} // namespace SRCTools + +#endif // SRCTOOLS_FLOAT_SAMPLE_PROVIDER_H diff --git a/src/SOUND/munt/srchelper/srctools/include/IIR2xResampler.h b/src/SOUND/munt/srchelper/srctools/include/IIR2xResampler.h new file mode 100644 index 000000000..0bfe1c4c8 --- /dev/null +++ b/src/SOUND/munt/srchelper/srctools/include/IIR2xResampler.h @@ -0,0 +1,100 @@ +/* Copyright (C) 2015-2017 Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#ifndef SRCTOOLS_IIR_2X_RESAMPLER_H +#define SRCTOOLS_IIR_2X_RESAMPLER_H + +#include "ResamplerStage.h" + +namespace SRCTools { + +static const unsigned int IIR_RESAMPER_CHANNEL_COUNT = 2; +static const unsigned int IIR_SECTION_ORDER = 2; + +typedef FloatSample IIRCoefficient; +typedef FloatSample BufferedSample; + +typedef BufferedSample SectionBuffer[IIR_SECTION_ORDER]; + +// Non-trivial coefficients of a 2nd-order section of a parallel bank +// (zero-order numerator coefficient is always zero, zero-order denominator coefficient is always unity) +struct IIRSection { + IIRCoefficient num1; + IIRCoefficient num2; + IIRCoefficient den1; + IIRCoefficient den2; +}; + +class IIRResampler : public ResamplerStage { +public: + enum Quality { + // Used when providing custom IIR filter coefficients. + CUSTOM, + // Use fast elliptic filter with symmetric ripple: N=8, Ap=As=-99 dB, fp=0.125, fs = 0.25 (in terms of sample rate) + FAST, + // Use average elliptic filter with symmetric ripple: N=12, Ap=As=-106 dB, fp=0.193, fs = 0.25 (in terms of sample rate) + GOOD, + // Use sharp elliptic filter with symmetric ripple: N=18, Ap=As=-106 dB, fp=0.238, fs = 0.25 (in terms of sample rate) + BEST + }; + + // Returns the retained fraction of the passband for the given standard quality value + static double getPassbandFractionForQuality(Quality quality); + +protected: + explicit IIRResampler(const Quality quality); + explicit IIRResampler(const unsigned int useSectionsCount, const IIRCoefficient useFIR, const IIRSection useSections[]); + ~IIRResampler(); + + const struct Constants { + // Coefficient of the 0-order FIR part + IIRCoefficient fir; + // 2nd-order sections that comprise a parallel bank + const IIRSection *sections; + // Number of 2nd-order sections + unsigned int sectionsCount; + // Delay line per channel per section + SectionBuffer *buffer; + + Constants(const unsigned int useSectionsCount, const IIRCoefficient useFIR, const IIRSection useSections[], const Quality quality); + } constants; +}; // class IIRResampler + +class IIR2xInterpolator : public IIRResampler { +public: + explicit IIR2xInterpolator(const Quality quality); + explicit IIR2xInterpolator(const unsigned int useSectionsCount, const IIRCoefficient useFIR, const IIRSection useSections[]); + + void process(const FloatSample *&inSamples, unsigned int &inLength, FloatSample *&outSamples, unsigned int &outLength); + unsigned int estimateInLength(const unsigned int outLength) const; + +private: + FloatSample lastInputSamples[IIR_RESAMPER_CHANNEL_COUNT]; + unsigned int phase; +}; + +class IIR2xDecimator : public IIRResampler { +public: + explicit IIR2xDecimator(const Quality quality); + explicit IIR2xDecimator(const unsigned int useSectionsCount, const IIRCoefficient useFIR, const IIRSection useSections[]); + + void process(const FloatSample *&inSamples, unsigned int &inLength, FloatSample *&outSamples, unsigned int &outLength); + unsigned int estimateInLength(const unsigned int outLength) const; +}; + +} // namespace SRCTools + +#endif // SRCTOOLS_IIR_2X_RESAMPLER_H diff --git a/src/SOUND/munt/srchelper/srctools/include/LinearResampler.h b/src/SOUND/munt/srchelper/srctools/include/LinearResampler.h new file mode 100644 index 000000000..c81ff2a38 --- /dev/null +++ b/src/SOUND/munt/srchelper/srctools/include/LinearResampler.h @@ -0,0 +1,42 @@ +/* Copyright (C) 2015-2017 Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#ifndef SRCTOOLS_LINEAR_RESAMPLER_H +#define SRCTOOLS_LINEAR_RESAMPLER_H + +#include "ResamplerStage.h" + +namespace SRCTools { + +static const unsigned int LINEAR_RESAMPER_CHANNEL_COUNT = 2; + +class LinearResampler : public ResamplerStage { +public: + LinearResampler(double sourceSampleRate, double targetSampleRate); + ~LinearResampler() {} + + unsigned int estimateInLength(const unsigned int outLength) const; + void process(const FloatSample *&inSamples, unsigned int &inLength, FloatSample *&outSamples, unsigned int &outLength); + +private: + const double inputToOutputRatio; + double position; + FloatSample lastInputSamples[LINEAR_RESAMPER_CHANNEL_COUNT]; +}; + +} // namespace SRCTools + +#endif // SRCTOOLS_LINEAR_RESAMPLER_H diff --git a/src/SOUND/munt/srchelper/srctools/include/ResamplerModel.h b/src/SOUND/munt/srchelper/srctools/include/ResamplerModel.h new file mode 100644 index 000000000..f0ac23707 --- /dev/null +++ b/src/SOUND/munt/srchelper/srctools/include/ResamplerModel.h @@ -0,0 +1,63 @@ +/* Copyright (C) 2015-2017 Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#ifndef SRCTOOLS_RESAMPLER_MODEL_H +#define SRCTOOLS_RESAMPLER_MODEL_H + +#include "FloatSampleProvider.h" + +namespace SRCTools { + +class ResamplerStage; + +/** Model consists of one or more ResampleStage instances connected in a cascade. */ +namespace ResamplerModel { + +// Seems to be a good choice for 16-bit integer samples. +static const double DEFAULT_DB_SNR = 106; + +// When using linear interpolation, oversampling factor necessary to achieve the DEFAULT_DB_SNR is about 256. +// This figure is the upper estimation, and it can be found by analysing the frequency response of the linear interpolator. +// When less SNR is desired, this value should also decrease in accordance. +static const unsigned int DEFAULT_WINDOWED_SINC_MAX_DOWNSAMPLE_FACTOR = 256; + +// In the default resampler model, the input to the windowed sinc filter is always at least 2x oversampled during upsampling, +// so oversampling factor of 128 should be sufficient to achieve the DEFAULT_DB_SNR with linear interpolation. +static const unsigned int DEFAULT_WINDOWED_SINC_MAX_UPSAMPLE_FACTOR = DEFAULT_WINDOWED_SINC_MAX_DOWNSAMPLE_FACTOR / 2; + + +enum Quality { + // Use when the speed is more important than the audio quality. + FASTEST, + // Use FAST quality setting of the IIR stage (50% of passband retained). + FAST, + // Use GOOD quality setting of the IIR stage (77% of passband retained). + GOOD, + // Use BEST quality setting of the IIR stage (95% of passband retained). + BEST +}; + +FloatSampleProvider &createResamplerModel(FloatSampleProvider &source, double sourceSampleRate, double targetSampleRate, Quality quality); +FloatSampleProvider &createResamplerModel(FloatSampleProvider &source, ResamplerStage **stages, unsigned int stageCount); +FloatSampleProvider &createResamplerModel(FloatSampleProvider &source, ResamplerStage &stage); + +void freeResamplerModel(FloatSampleProvider &model, FloatSampleProvider &source); + +} // namespace ResamplerModel + +} // namespace SRCTools + +#endif // SRCTOOLS_RESAMPLER_MODEL_H diff --git a/src/SOUND/munt/srchelper/srctools/include/ResamplerStage.h b/src/SOUND/munt/srchelper/srctools/include/ResamplerStage.h new file mode 100644 index 000000000..6aea9624d --- /dev/null +++ b/src/SOUND/munt/srchelper/srctools/include/ResamplerStage.h @@ -0,0 +1,38 @@ +/* Copyright (C) 2015-2017 Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#ifndef SRCTOOLS_RESAMPLER_STAGE_H +#define SRCTOOLS_RESAMPLER_STAGE_H + +#include "FloatSampleProvider.h" + +namespace SRCTools { + +/** Interface defines an abstract source of samples. It can either define a single channel stream or a stream with interleaved channels. */ +class ResamplerStage { +public: + virtual ~ResamplerStage() {}; + + /** Returns a lower estimation of required number of input samples to produce the specified number of output samples. */ + virtual unsigned int estimateInLength(const unsigned int outLength) const = 0; + + /** Generates output samples. The arguments are adjusted in accordance with the number of samples processed. */ + virtual void process(const FloatSample *&inSamples, unsigned int &inLength, FloatSample *&outSamples, unsigned int &outLength) = 0; +}; + +} // namespace SRCTools + +#endif // SRCTOOLS_RESAMPLER_STAGE_H diff --git a/src/SOUND/munt/srchelper/srctools/include/SincResampler.h b/src/SOUND/munt/srchelper/srctools/include/SincResampler.h new file mode 100644 index 000000000..1551a1eda --- /dev/null +++ b/src/SOUND/munt/srchelper/srctools/include/SincResampler.h @@ -0,0 +1,46 @@ +/* Copyright (C) 2015-2017 Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#ifndef SRCTOOLS_SINC_RESAMPLER_H +#define SRCTOOLS_SINC_RESAMPLER_H + +#include "FIRResampler.h" + +namespace SRCTools { + +class ResamplerStage; + +namespace SincResampler { + + ResamplerStage *createSincResampler(const double inputFrequency, const double outputFrequency, const double passbandFrequency, const double stopbandFrequency, const double dbSNR, const unsigned int maxUpsampleFactor); + + namespace Utils { + void computeResampleFactors(unsigned int &upsampleFactor, double &downsampleFactor, const double inputFrequency, const double outputFrequency, const unsigned int maxUpsampleFactor); + unsigned int greatestCommonDivisor(unsigned int a, unsigned int b); + } + + namespace KaizerWindow { + double estimateBeta(double dbRipple); + unsigned int estimateOrder(double dbRipple, double fp, double fs); + double bessel(const double x); + void windowedSinc(FIRCoefficient kernel[], const unsigned int order, const double fc, const double beta, const double amp); + } + +} // namespace SincResampler + +} // namespace SRCTools + +#endif // SRCTOOLS_SINC_RESAMPLER_H diff --git a/src/SOUND/munt/srchelper/srctools/src/FIRResampler.cpp b/src/SOUND/munt/srchelper/srctools/src/FIRResampler.cpp new file mode 100644 index 000000000..2cded0c3d --- /dev/null +++ b/src/SOUND/munt/srchelper/srctools/src/FIRResampler.cpp @@ -0,0 +1,107 @@ +/* Copyright (C) 2015-2017 Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#include +#include + +#include "FIRResampler.h" + +using namespace SRCTools; + +FIRResampler::Constants::Constants(const unsigned int upsampleFactor, const double downsampleFactor, const FIRCoefficient kernel[], const unsigned int kernelLength) { + usePhaseInterpolation = downsampleFactor != floor(downsampleFactor); + FIRCoefficient *kernelCopy = new FIRCoefficient[kernelLength]; + memcpy(kernelCopy, kernel, kernelLength * sizeof(FIRCoefficient)); + taps = kernelCopy; + numberOfTaps = kernelLength; + numberOfPhases = upsampleFactor; + phaseIncrement = downsampleFactor; + unsigned int minDelayLineLength = static_cast(ceil(double(kernelLength) / upsampleFactor)); + unsigned int delayLineLength = 2; + while (delayLineLength < minDelayLineLength) delayLineLength <<= 1; + delayLineMask = delayLineLength - 1; + ringBuffer = new FloatSample[delayLineLength][FIR_INTERPOLATOR_CHANNEL_COUNT]; + FloatSample *s = *ringBuffer; + FloatSample *e = ringBuffer[delayLineLength]; + while (s < e) *(s++) = 0; +} + +FIRResampler::FIRResampler(const unsigned int upsampleFactor, const double downsampleFactor, const FIRCoefficient kernel[], const unsigned int kernelLength) : + constants(upsampleFactor, downsampleFactor, kernel, kernelLength), + ringBufferPosition(0), + phase(constants.numberOfPhases) +{} + +FIRResampler::~FIRResampler() { + delete[] constants.ringBuffer; + delete[] constants.taps; +} + +void FIRResampler::process(const FloatSample *&inSamples, unsigned int &inLength, FloatSample *&outSamples, unsigned int &outLength) { + while (outLength > 0) { + while (needNextInSample()) { + if (inLength == 0) return; + addInSamples(inSamples); + --inLength; + } + getOutSamplesStereo(outSamples); + --outLength; + } +} + +unsigned int FIRResampler::estimateInLength(const unsigned int outLength) const { + return static_cast((outLength * constants.phaseIncrement + phase) / constants.numberOfPhases); +} + +bool FIRResampler::needNextInSample() const { + return constants.numberOfPhases <= phase; +} + +void FIRResampler::addInSamples(const FloatSample *&inSamples) { + ringBufferPosition = (ringBufferPosition - 1) & constants.delayLineMask; + for (unsigned int i = 0; i < FIR_INTERPOLATOR_CHANNEL_COUNT; i++) { + constants.ringBuffer[ringBufferPosition][i] = *(inSamples++); + } + phase -= constants.numberOfPhases; +} + +// Optimised for processing stereo interleaved streams +void FIRResampler::getOutSamplesStereo(FloatSample *&outSamples) { + FloatSample leftSample = 0.0; + FloatSample rightSample = 0.0; + unsigned int delaySampleIx = ringBufferPosition; + if (constants.usePhaseInterpolation) { + double phaseFraction = phase - floor(phase); + unsigned int maxTapIx = phaseFraction == 0 ? constants.numberOfTaps : constants.numberOfTaps - 1; + for (unsigned int tapIx = static_cast(phase); tapIx < maxTapIx; tapIx += constants.numberOfPhases) { + FIRCoefficient tap = FIRCoefficient(constants.taps[tapIx] + (constants.taps[tapIx + 1] - constants.taps[tapIx]) * phaseFraction); + leftSample += tap * constants.ringBuffer[delaySampleIx][0]; + rightSample += tap * constants.ringBuffer[delaySampleIx][1]; + delaySampleIx = (delaySampleIx + 1) & constants.delayLineMask; + } + } else { + // Optimised for rational resampling ratios when phase is always integer + for (unsigned int tapIx = static_cast(phase); tapIx < constants.numberOfTaps; tapIx += constants.numberOfPhases) { + FIRCoefficient tap = constants.taps[tapIx]; + leftSample += tap * constants.ringBuffer[delaySampleIx][0]; + rightSample += tap * constants.ringBuffer[delaySampleIx][1]; + delaySampleIx = (delaySampleIx + 1) & constants.delayLineMask; + } + } + *(outSamples++) = leftSample; + *(outSamples++) = rightSample; + phase += constants.phaseIncrement; +} diff --git a/src/SOUND/munt/srchelper/srctools/src/IIR2xResampler.cpp b/src/SOUND/munt/srchelper/srctools/src/IIR2xResampler.cpp new file mode 100644 index 000000000..0016f23c9 --- /dev/null +++ b/src/SOUND/munt/srchelper/srctools/src/IIR2xResampler.cpp @@ -0,0 +1,229 @@ +/* Copyright (C) 2015-2017 Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#include + +#include "IIR2xResampler.h" + +namespace SRCTools { + + // Avoid denormals degrading performance, using biased input + static const BufferedSample BIAS = 1e-20f; + + // Sharp elliptic filter with symmetric ripple: N=18, Ap=As=-106 dB, fp=0.238, fs = 0.25 (in terms of sample rate) + static const IIRCoefficient FIR_BEST = 0.0014313792470984f; + static const IIRSection SECTIONS_BEST[] = { + { 2.85800356692148000f,-0.2607342682253230f,-0.602478421807085f, 0.109823442522145f }, + { -4.39519408383016000f, 1.4651975326003500f,-0.533817668127954f, 0.226045921792036f }, + { 0.86638550740991800f,-2.1053851417898500f,-0.429134968401065f, 0.403512574222174f }, + { 1.67161485530774000f, 0.7963595880494520f,-0.324989203363446f, 0.580756666711889f }, + { -1.19962759276471000f, 0.5873595178851540f,-0.241486447489019f, 0.724264899930934f }, + { 0.01631779946479250f,-0.6282334739461620f,-0.182766025706656f, 0.827774001858882f }, + { 0.28404415859352400f, 0.1038619997715160f,-0.145276649558926f, 0.898510501923554f }, + { -0.08105788424234910f, 0.0781551578108934f,-0.123965846623366f, 0.947105257601873f }, + { -0.00872608905948005f,-0.0222098231712466f,-0.115056854360748f, 0.983542001125711f } + }; + + // Average elliptic filter with symmetric ripple: N=12, Ap=As=-106 dB, fp=0.193, fs = 0.25 (in terms of sample rate) + static const IIRCoefficient FIR_GOOD = 0.000891054570268146f; + static const IIRSection SECTIONS_GOOD[] = { + { 2.2650157226725700f,-0.4034180565140230f,-0.750061486095301f, 0.157801404511953f }, + { -3.2788261989161700f, 1.3952152147542600f,-0.705854270206788f, 0.265564985645774f }, + { 0.4397975114813240f,-1.3957634748753100f,-0.639718853965265f, 0.435324134360315f }, + { 0.9827040216680520f, 0.1837182774040940f,-0.578569965618418f, 0.615205557837542f }, + { -0.3759752818621670f, 0.3266073609399490f,-0.540913588637109f, 0.778264420176574f }, + { -0.0253548089519618f,-0.0925779221603846f,-0.537704370375240f, 0.925800083252964f } + }; + + // Fast elliptic filter with symmetric ripple: N=8, Ap=As=-99 dB, fp=0.125, fs = 0.25 (in terms of sample rate) + static const IIRCoefficient FIR_FAST = 0.000882837778745889f; + static const IIRSection SECTIONS_FAST[] = { + { 1.215377077431620f,-0.35864455030878000f,-0.972220718789242f, 0.252934735930620f }, + { -1.525654419254140f, 0.86784918631245500f,-0.977713689358124f, 0.376580616703668f }, + { 0.136094441564220f,-0.50414116798010400f,-1.007004471865290f, 0.584048854845331f }, + { 0.180604082285806f,-0.00467624342403851f,-1.093486919012100f, 0.844904524843996f } + }; + + static inline BufferedSample calcNumerator(const IIRSection §ion, const BufferedSample buffer1, const BufferedSample buffer2) { + return section.num1 * buffer1 + section.num2 * buffer2; + } + + static inline BufferedSample calcDenominator(const IIRSection §ion, const BufferedSample input, const BufferedSample buffer1, const BufferedSample buffer2) { + return input - section.den1 * buffer1 - section.den2 * buffer2; + } + +} // namespace SRCTools + +using namespace SRCTools; + +double IIRResampler::getPassbandFractionForQuality(Quality quality) { + switch (quality) { + case FAST: + return 0.5; + case GOOD: + return 0.7708; + case BEST: + return 0.9524; + default: + return 0; + } +} + +IIRResampler::Constants::Constants(const unsigned int useSectionsCount, const IIRCoefficient useFIR, const IIRSection useSections[], const Quality quality) { + if (quality == CUSTOM) { + sectionsCount = useSectionsCount; + fir = useFIR; + sections = useSections; + } else { + unsigned int sectionsSize; + switch (quality) { + case FAST: + fir = FIR_FAST; + sections = SECTIONS_FAST; + sectionsSize = sizeof(SECTIONS_FAST); + break; + case GOOD: + fir = FIR_GOOD; + sections = SECTIONS_GOOD; + sectionsSize = sizeof(SECTIONS_GOOD); + break; + case BEST: + fir = FIR_BEST; + sections = SECTIONS_BEST; + sectionsSize = sizeof(SECTIONS_BEST); + break; + default: + sectionsSize = 0; + break; + } + sectionsCount = (sectionsSize / sizeof(IIRSection)); + } + const unsigned int delayLineSize = IIR_RESAMPER_CHANNEL_COUNT * sectionsCount; + buffer = new SectionBuffer[delayLineSize]; + BufferedSample *s = buffer[0]; + BufferedSample *e = buffer[delayLineSize]; + while (s < e) *(s++) = 0; +} + +IIRResampler::IIRResampler(const Quality quality) : + constants(0, 0.0f, NULL, quality) +{} + +IIRResampler::IIRResampler(const unsigned int useSectionsCount, const IIRCoefficient useFIR, const IIRSection useSections[]) : + constants(useSectionsCount, useFIR, useSections, IIRResampler::CUSTOM) +{} + +IIRResampler::~IIRResampler() { + delete[] constants.buffer; +} + +IIR2xInterpolator::IIR2xInterpolator(const Quality quality) : + IIRResampler(quality), + phase(1) +{ + for (unsigned int chIx = 0; chIx < IIR_RESAMPER_CHANNEL_COUNT; ++chIx) { + lastInputSamples[chIx] = 0; + } +} + +IIR2xInterpolator::IIR2xInterpolator(const unsigned int useSectionsCount, const IIRCoefficient useFIR, const IIRSection useSections[]) : + IIRResampler(useSectionsCount, useFIR, useSections), + phase(1) +{ + for (unsigned int chIx = 0; chIx < IIR_RESAMPER_CHANNEL_COUNT; ++chIx) { + lastInputSamples[chIx] = 0; + } +} + +void IIR2xInterpolator::process(const FloatSample *&inSamples, unsigned int &inLength, FloatSample *&outSamples, unsigned int &outLength) { + static const IIRCoefficient INTERPOLATOR_AMP = 2.0; + + while (outLength > 0 && inLength > 0) { + SectionBuffer *bufferp = constants.buffer; + for (unsigned int chIx = 0; chIx < IIR_RESAMPER_CHANNEL_COUNT; ++chIx) { + const FloatSample lastInputSample = lastInputSamples[chIx]; + const FloatSample inSample = inSamples[chIx]; + BufferedSample tmpOut = phase == 0 ? 0 : inSample * constants.fir; + for (unsigned int i = 0; i < constants.sectionsCount; ++i) { + const IIRSection §ion = constants.sections[i]; + SectionBuffer &buffer = *bufferp; + // For 2x interpolation, calculation of the numerator reduces to a single multiplication depending on the phase. + if (phase == 0) { + const BufferedSample numOutSample = section.num1 * lastInputSample; + const BufferedSample denOutSample = calcDenominator(section, BIAS + numOutSample, buffer[0], buffer[1]); + buffer[1] = denOutSample; + tmpOut += denOutSample; + } else { + const BufferedSample numOutSample = section.num2 * lastInputSample; + const BufferedSample denOutSample = calcDenominator(section, BIAS + numOutSample, buffer[1], buffer[0]); + buffer[0] = denOutSample; + tmpOut += denOutSample; + } + bufferp++; + } + *(outSamples++) = FloatSample(INTERPOLATOR_AMP * tmpOut); + if (phase > 0) { + lastInputSamples[chIx] = inSample; + } + } + outLength--; + if (phase > 0) { + inSamples += IIR_RESAMPER_CHANNEL_COUNT; + inLength--; + phase = 0; + } else { + phase = 1; + } + } +} + +unsigned int IIR2xInterpolator::estimateInLength(const unsigned int outLength) const { + return outLength >> 1; +} + +IIR2xDecimator::IIR2xDecimator(const Quality quality) : + IIRResampler(quality) +{} + +IIR2xDecimator::IIR2xDecimator(const unsigned int useSectionsCount, const IIRCoefficient useFIR, const IIRSection useSections[]) : + IIRResampler(useSectionsCount, useFIR, useSections) +{} + +void IIR2xDecimator::process(const FloatSample *&inSamples, unsigned int &inLength, FloatSample *&outSamples, unsigned int &outLength) { + while (outLength > 0 && inLength > 1) { + SectionBuffer *bufferp = constants.buffer; + for (unsigned int chIx = 0; chIx < IIR_RESAMPER_CHANNEL_COUNT; ++chIx) { + BufferedSample tmpOut = inSamples[chIx] * constants.fir; + for (unsigned int i = 0; i < constants.sectionsCount; ++i) { + const IIRSection §ion = constants.sections[i]; + SectionBuffer &buffer = *bufferp; + // For 2x decimation, calculation of the numerator is not performed for odd output samples which are to be omitted. + tmpOut += calcNumerator(section, buffer[0], buffer[1]); + buffer[1] = calcDenominator(section, BIAS + inSamples[chIx], buffer[0], buffer[1]); + buffer[0] = calcDenominator(section, BIAS + inSamples[chIx + IIR_RESAMPER_CHANNEL_COUNT], buffer[1], buffer[0]); + bufferp++; + } + *(outSamples++) = FloatSample(tmpOut); + } + outLength--; + inLength -= 2; + inSamples += 2 * IIR_RESAMPER_CHANNEL_COUNT; + } +} + +unsigned int IIR2xDecimator::estimateInLength(const unsigned int outLength) const { + return outLength << 1; +} diff --git a/src/SOUND/munt/srchelper/srctools/src/LinearResampler.cpp b/src/SOUND/munt/srchelper/srctools/src/LinearResampler.cpp new file mode 100644 index 000000000..98b9c77c7 --- /dev/null +++ b/src/SOUND/munt/srchelper/srctools/src/LinearResampler.cpp @@ -0,0 +1,47 @@ +/* Copyright (C) 2015-2017 Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#include "LinearResampler.h" + +using namespace SRCTools; + +LinearResampler::LinearResampler(double sourceSampleRate, double targetSampleRate) : + inputToOutputRatio(sourceSampleRate / targetSampleRate), + position(1.0) // Preload delay line which effectively makes resampler zero phase +{} + +void LinearResampler::process(const FloatSample *&inSamples, unsigned int &inLength, FloatSample *&outSamples, unsigned int &outLength) { + if (inLength == 0) return; + while (outLength > 0) { + while (1.0 <= position) { + position--; + inLength--; + for (unsigned int chIx = 0; chIx < LINEAR_RESAMPER_CHANNEL_COUNT; ++chIx) { + lastInputSamples[chIx] = *(inSamples++); + } + if (inLength == 0) return; + } + for (unsigned int chIx = 0; chIx < LINEAR_RESAMPER_CHANNEL_COUNT; chIx++) { + *(outSamples++) = FloatSample(lastInputSamples[chIx] + position * (inSamples[chIx] - lastInputSamples[chIx])); + } + outLength--; + position += inputToOutputRatio; + } +} + +unsigned int LinearResampler::estimateInLength(const unsigned int outLength) const { + return static_cast(outLength * inputToOutputRatio); +} diff --git a/src/SOUND/munt/srchelper/srctools/src/ResamplerModel.cpp b/src/SOUND/munt/srchelper/srctools/src/ResamplerModel.cpp new file mode 100644 index 000000000..4d2d93083 --- /dev/null +++ b/src/SOUND/munt/srchelper/srctools/src/ResamplerModel.cpp @@ -0,0 +1,153 @@ +/* Copyright (C) 2015-2017 Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#include +#include + +#include "ResamplerModel.h" + +#include "ResamplerStage.h" +#include "SincResampler.h" +#include "IIR2xResampler.h" +#include "LinearResampler.h" + +namespace SRCTools { + +namespace ResamplerModel { + +static const unsigned int CHANNEL_COUNT = 2; +static const unsigned int MAX_SAMPLES_PER_RUN = 4096; + +class CascadeStage : public FloatSampleProvider { +friend void freeResamplerModel(FloatSampleProvider &model, FloatSampleProvider &source); +public: + CascadeStage(FloatSampleProvider &source, ResamplerStage &resamplerStage); + + void getOutputSamples(FloatSample *outBuffer, unsigned int size); + +protected: + ResamplerStage &resamplerStage; + +private: + FloatSampleProvider &source; + FloatSample buffer[CHANNEL_COUNT * MAX_SAMPLES_PER_RUN]; + const FloatSample *bufferPtr; + unsigned int size; +}; + +class InternalResamplerCascadeStage : public CascadeStage { +public: + InternalResamplerCascadeStage(FloatSampleProvider &useSource, ResamplerStage &useResamplerStage) : + CascadeStage(useSource, useResamplerStage) + {} + + ~InternalResamplerCascadeStage() { + delete &resamplerStage; + } +}; + +} // namespace ResamplerModel + +} // namespace SRCTools + +using namespace SRCTools; + +FloatSampleProvider &ResamplerModel::createResamplerModel(FloatSampleProvider &source, double sourceSampleRate, double targetSampleRate, Quality quality) { + if (sourceSampleRate == targetSampleRate) { + return source; + } + if (quality == FASTEST) { + return *new InternalResamplerCascadeStage(source, *new LinearResampler(sourceSampleRate, targetSampleRate)); + } + const IIRResampler::Quality iirQuality = static_cast(quality); + const double iirPassbandFraction = IIRResampler::getPassbandFractionForQuality(iirQuality); + if (sourceSampleRate < targetSampleRate) { + ResamplerStage *iir2xInterpolator = new IIR2xInterpolator(iirQuality); + FloatSampleProvider &iir2xInterpolatorStage = *new InternalResamplerCascadeStage(source, *iir2xInterpolator); + + if (2.0 * sourceSampleRate == targetSampleRate) { + return iir2xInterpolatorStage; + } + + double passband = 0.5 * sourceSampleRate * iirPassbandFraction; + double stopband = 1.5 * sourceSampleRate; + ResamplerStage *sincResampler = SincResampler::createSincResampler(2.0 * sourceSampleRate, targetSampleRate, passband, stopband, DEFAULT_DB_SNR, DEFAULT_WINDOWED_SINC_MAX_UPSAMPLE_FACTOR); + return *new InternalResamplerCascadeStage(iir2xInterpolatorStage, *sincResampler); + } + + if (sourceSampleRate == 2.0 * targetSampleRate) { + ResamplerStage *iir2xDecimator = new IIR2xDecimator(iirQuality); + return *new InternalResamplerCascadeStage(source, *iir2xDecimator); + } + + double passband = 0.5 * targetSampleRate * iirPassbandFraction; + double stopband = 1.5 * targetSampleRate; + double sincOutSampleRate = 2.0 * targetSampleRate; + const unsigned int maxUpsampleFactor = static_cast(ceil(DEFAULT_WINDOWED_SINC_MAX_DOWNSAMPLE_FACTOR * sincOutSampleRate / sourceSampleRate)); + ResamplerStage *sincResampler = SincResampler::createSincResampler(sourceSampleRate, sincOutSampleRate, passband, stopband, DEFAULT_DB_SNR, maxUpsampleFactor); + FloatSampleProvider &sincResamplerStage = *new InternalResamplerCascadeStage(source, *sincResampler); + + ResamplerStage *iir2xDecimator = new IIR2xDecimator(iirQuality); + return *new InternalResamplerCascadeStage(sincResamplerStage, *iir2xDecimator); +} + +FloatSampleProvider &ResamplerModel::createResamplerModel(FloatSampleProvider &source, ResamplerStage **resamplerStages, unsigned int stageCount) { + FloatSampleProvider *prevStage = &source; + for (unsigned int i = 0; i < stageCount; i++) { + prevStage = new CascadeStage(*prevStage, *(resamplerStages[i])); + } + return *prevStage; +} + +FloatSampleProvider &ResamplerModel::createResamplerModel(FloatSampleProvider &source, ResamplerStage &stage) { + return *new CascadeStage(source, stage); +} + +void ResamplerModel::freeResamplerModel(FloatSampleProvider &model, FloatSampleProvider &source) { + FloatSampleProvider *currentStage = &model; + while (currentStage != &source) { + CascadeStage *cascadeStage = dynamic_cast(currentStage); + if (cascadeStage == NULL) return; + FloatSampleProvider &prevStage = cascadeStage->source; + delete currentStage; + currentStage = &prevStage; + } +} + +using namespace ResamplerModel; + +CascadeStage::CascadeStage(FloatSampleProvider &useSource, ResamplerStage &useResamplerStage) : + resamplerStage(useResamplerStage), + source(useSource), + bufferPtr(buffer), + size() +{} + +void CascadeStage::getOutputSamples(FloatSample *outBuffer, unsigned int length) { + while (length > 0) { + if (size == 0) { + size = resamplerStage.estimateInLength(length); + if (size < 1) { + size = 1; + } else if (MAX_SAMPLES_PER_RUN < size) { + size = MAX_SAMPLES_PER_RUN; + } + source.getOutputSamples(buffer, size); + bufferPtr = buffer; + } + resamplerStage.process(bufferPtr, size, outBuffer, length); + } +} diff --git a/src/SOUND/munt/srchelper/srctools/src/SincResampler.cpp b/src/SOUND/munt/srchelper/srctools/src/SincResampler.cpp new file mode 100644 index 000000000..38d0ebe45 --- /dev/null +++ b/src/SOUND/munt/srchelper/srctools/src/SincResampler.cpp @@ -0,0 +1,136 @@ +/* Copyright (C) 2015-2017 Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#include + +#ifdef SRCTOOLS_SINC_RESAMPLER_DEBUG_LOG +#include +#endif + +#include "SincResampler.h" + +#ifndef M_PI +static const double M_PI = 3.1415926535897932; +#endif + +using namespace SRCTools; + +using namespace SincResampler; + +using namespace Utils; + +void Utils::computeResampleFactors(unsigned int &upsampleFactor, double &downsampleFactor, const double inputFrequency, const double outputFrequency, const unsigned int maxUpsampleFactor) { + static const double RATIONAL_RATIO_ACCURACY_FACTOR = 1E15; + + upsampleFactor = static_cast(outputFrequency); + unsigned int downsampleFactorInt = static_cast(inputFrequency); + if ((upsampleFactor == outputFrequency) && (downsampleFactorInt == inputFrequency)) { + // Input and output frequencies are integers, try to reduce them + const unsigned int gcd = greatestCommonDivisor(upsampleFactor, downsampleFactorInt); + if (gcd > 1) { + upsampleFactor /= gcd; + downsampleFactor = downsampleFactorInt / gcd; + } else { + downsampleFactor = downsampleFactorInt; + } + if (upsampleFactor <= maxUpsampleFactor) return; + } else { + // Try to recover rational resample ratio by brute force + double inputToOutputRatio = inputFrequency / outputFrequency; + for (unsigned int i = 1; i <= maxUpsampleFactor; ++i) { + double testFactor = inputToOutputRatio * i; + if (floor(RATIONAL_RATIO_ACCURACY_FACTOR * testFactor + 0.5) == RATIONAL_RATIO_ACCURACY_FACTOR * floor(testFactor + 0.5)) { + // inputToOutputRatio found to be rational within the accuracy + upsampleFactor = i; + downsampleFactor = floor(testFactor + 0.5); + return; + } + } + } + // Use interpolation of FIR taps as the last resort + upsampleFactor = maxUpsampleFactor; + downsampleFactor = maxUpsampleFactor * inputFrequency / outputFrequency; +} + +unsigned int Utils::greatestCommonDivisor(unsigned int a, unsigned int b) { + while (0 < b) { + unsigned int r = a % b; + a = b; + b = r; + } + return a; +} + +double KaizerWindow::estimateBeta(double dbRipple) { + return 0.1102 * (dbRipple - 8.7); +} + +unsigned int KaizerWindow::estimateOrder(double dbRipple, double fp, double fs) { + const double transBW = (fs - fp); + return static_cast(ceil((dbRipple - 8) / (2.285 * 2 * M_PI * transBW))); +} + +double KaizerWindow::bessel(const double x) { + static const double EPS = 1.11E-16; + + double sum = 0.0; + double f = 1.0; + for (unsigned int i = 1;; ++i) { + f *= (0.5 * x / i); + double f2 = f * f; + if (f2 <= sum * EPS) break; + sum += f2; + } + return 1.0 + sum; +} + +void KaizerWindow::windowedSinc(FIRCoefficient kernel[], const unsigned int order, const double fc, const double beta, const double amp) { + const double fc_pi = M_PI * fc; + const double recipOrder = 1.0 / order; + const double mult = 2.0 * fc * amp / bessel(beta); + for (int i = order, j = 0; 0 <= i; i -= 2, ++j) { + double xw = i * recipOrder; + double win = bessel(beta * sqrt(fabs(1.0 - xw * xw))); + double xs = i * fc_pi; + double sinc = (i == 0) ? 1.0 : sin(xs) / xs; + FIRCoefficient imp = FIRCoefficient(mult * sinc * win); + kernel[j] = imp; + kernel[order - j] = imp; + } +} + +ResamplerStage *SincResampler::createSincResampler(const double inputFrequency, const double outputFrequency, const double passbandFrequency, const double stopbandFrequency, const double dbSNR, const unsigned int maxUpsampleFactor) { + unsigned int upsampleFactor; + double downsampleFactor; + computeResampleFactors(upsampleFactor, downsampleFactor, inputFrequency, outputFrequency, maxUpsampleFactor); + double baseSamplePeriod = 1.0 / (inputFrequency * upsampleFactor); + double fp = passbandFrequency * baseSamplePeriod; + double fs = stopbandFrequency * baseSamplePeriod; + double fc = 0.5 * (fp + fs); + double beta = KaizerWindow::estimateBeta(dbSNR); + unsigned int order = KaizerWindow::estimateOrder(dbSNR, fp, fs); + const unsigned int kernelLength = order + 1; + +#ifdef SRCTOOLS_SINC_RESAMPLER_DEBUG_LOG + std::clog << "FIR: " << upsampleFactor << "/" << downsampleFactor << ", N=" << kernelLength << ", NPh=" << kernelLength / double(upsampleFactor) << ", C=" << 0.5 / fc << ", fp=" << fp << ", fs=" << fs << ", M=" << maxUpsampleFactor << std::endl; +#endif + + FIRCoefficient *windowedSincKernel = new FIRCoefficient[kernelLength]; + KaizerWindow::windowedSinc(windowedSincKernel, order, fc, beta, upsampleFactor); + ResamplerStage *windowedSincStage = new FIRResampler(upsampleFactor, downsampleFactor, windowedSincKernel, kernelLength); + delete[] windowedSincKernel; + return windowedSincStage; +} diff --git a/src/dosbox/nukedopl.cpp b/src/SOUND/nukedopl.cpp similarity index 100% rename from src/dosbox/nukedopl.cpp rename to src/SOUND/nukedopl.cpp diff --git a/src/dosbox/nukedopl.h b/src/SOUND/nukedopl.h similarity index 100% rename from src/dosbox/nukedopl.h rename to src/SOUND/nukedopl.h diff --git a/src/SOUND/openal.c b/src/SOUND/openal.c new file mode 100644 index 000000000..c2d8d87fa --- /dev/null +++ b/src/SOUND/openal.c @@ -0,0 +1,245 @@ +#define USE_OPENAL +#include +#include +#include +#ifdef USE_OPENAL +# undef AL_API +# undef ALC_API +# define AL_LIBTYPE_STATIC +# define ALC_LIBTYPE_STATIC +# include +# include +# include +#endif +#include "../ibm.h" +#include "sound.h" + + +#define FREQ 48000 +#define BUFLEN SOUNDBUFLEN + + +#ifdef USE_OPENAL +ALuint buffers[4]; /* front and back buffers */ +ALuint buffers_cd[4]; /* front and back buffers */ +ALuint buffers_midi[4]; /* front and back buffers */ +static ALuint source[3]; /* audio source */ +#endif + +static int midi_freq = 44100; +static int midi_buf_size = 4410; +static int initialized = 0; + +void al_set_midi(int freq, int buf_size) +{ + midi_freq = freq; + midi_buf_size = buf_size; +} + +void closeal(void); +ALvoid alutInit(ALint *argc,ALbyte **argv) +{ + ALCcontext *Context; + ALCdevice *Device; + + /* Open device */ + Device = alcOpenDevice((ALCchar *)""); + if (Device != NULL) { + /* Create context(s) */ + Context = alcCreateContext(Device, NULL); + if (Context != NULL) { + /* Set active context */ + alcMakeContextCurrent(Context); + } + } +} + + +ALvoid alutExit(ALvoid) +{ + ALCcontext *Context; + ALCdevice *Device; + + /* Get active context */ + Context = alcGetCurrentContext(); + if (Context != NULL) { + /* Get device for active context */ + Device = alcGetContextsDevice(Context); + if (Device != NULL) { + /* Disable context */ + alcMakeContextCurrent(NULL); + + /* Close device */ + alcCloseDevice(Device); + } + + /* Release context(s) */ + alcDestroyContext(Context); + } +} + + +void closeal(void) +{ +#ifdef USE_OPENAL + alutExit(); +#endif +} + + +void initalmain(int argc, char *argv[]) +{ + if (!initialized) return; +#ifdef USE_OPENAL + alutInit(0,0); + atexit(closeal); +#endif + initialized = 0; +} + + +void inital(ALvoid) +{ + if (initialized) return; + +#ifdef USE_OPENAL + int c; + + float *buf = NULL, *cd_buf = NULL, *midi_buf = NULL; + int16_t *buf_int16 = NULL, *cd_buf_int16 = NULL, *midi_buf_int16 = NULL; + + if (sound_is_float) + { + buf = (float *) malloc((BUFLEN << 1) * sizeof(float)); + cd_buf = (float *) malloc((CD_BUFLEN << 1) * sizeof(float)); + midi_buf = (float *) malloc(midi_buf_size * sizeof(float)); + } + else + { + buf_int16 = (int16_t *) malloc((BUFLEN << 1) * sizeof(int16_t)); + cd_buf_int16 = (int16_t *) malloc((CD_BUFLEN << 1) * sizeof(int16_t)); + midi_buf_int16 = (int16_t *) malloc(midi_buf_size * sizeof(int16_t)); + } + + alGenBuffers(4, buffers); + alGenBuffers(4, buffers_cd); + alGenBuffers(4, buffers_midi); + + alGenSources(3, source); + + alSource3f(source[0], AL_POSITION, 0.0, 0.0, 0.0); + alSource3f(source[0], AL_VELOCITY, 0.0, 0.0, 0.0); + alSource3f(source[0], AL_DIRECTION, 0.0, 0.0, 0.0); + alSourcef (source[0], AL_ROLLOFF_FACTOR, 0.0 ); + alSourcei (source[0], AL_SOURCE_RELATIVE, AL_TRUE ); + alSource3f(source[1], AL_POSITION, 0.0, 0.0, 0.0); + alSource3f(source[1], AL_VELOCITY, 0.0, 0.0, 0.0); + alSource3f(source[1], AL_DIRECTION, 0.0, 0.0, 0.0); + alSourcef (source[1], AL_ROLLOFF_FACTOR, 0.0 ); + alSourcei (source[1], AL_SOURCE_RELATIVE, AL_TRUE ); + alSource3f(source[2], AL_POSITION, 0.0, 0.0, 0.0); + alSource3f(source[2], AL_VELOCITY, 0.0, 0.0, 0.0); + alSource3f(source[2], AL_DIRECTION, 0.0, 0.0, 0.0); + alSourcef (source[2], AL_ROLLOFF_FACTOR, 0.0 ); + alSourcei (source[2], AL_SOURCE_RELATIVE, AL_TRUE ); + + if (sound_is_float) + { + memset(buf,0,BUFLEN*2*sizeof(float)); + memset(cd_buf,0,BUFLEN*2*sizeof(float)); + memset(midi_buf,0,midi_buf_size*sizeof(float)); + } + else + { + memset(buf_int16,0,BUFLEN*2*sizeof(int16_t)); + memset(cd_buf_int16,0,BUFLEN*2*sizeof(int16_t)); + memset(midi_buf_int16,0,midi_buf_size*sizeof(int16_t)); + } + + for (c = 0; c < 4; c++) + { + if (sound_is_float) + { + alBufferData(buffers[c], AL_FORMAT_STEREO_FLOAT32, buf, BUFLEN*2*sizeof(float), FREQ); + alBufferData(buffers_cd[c], AL_FORMAT_STEREO_FLOAT32, cd_buf, CD_BUFLEN*2*sizeof(float), CD_FREQ); + alBufferData(buffers_midi[c], AL_FORMAT_STEREO_FLOAT32, midi_buf, midi_buf_size*sizeof(float), midi_freq); + } + else + { + alBufferData(buffers[c], AL_FORMAT_STEREO16, buf_int16, BUFLEN*2*sizeof(int16_t), FREQ); + alBufferData(buffers_cd[c], AL_FORMAT_STEREO16, cd_buf_int16, CD_BUFLEN*2*sizeof(int16_t), CD_FREQ); + alBufferData(buffers_midi[c], AL_FORMAT_STEREO16, midi_buf_int16, midi_buf_size*sizeof(int16_t), midi_freq); + } + } + + alSourceQueueBuffers(source[0], 4, buffers); + alSourceQueueBuffers(source[1], 4, buffers_cd); + alSourceQueueBuffers(source[2], 4, buffers_midi); + alSourcePlay(source[0]); + alSourcePlay(source[1]); + alSourcePlay(source[2]); + + if (sound_is_float) + { + free(midi_buf); + free(cd_buf); + free(buf); + } + else + { + free(midi_buf_int16); + free(cd_buf_int16); + free(buf_int16); + } + + initialized = 1; +#endif +} + +void givealbuffer_common(void *buf, uint8_t src, int size, int freq) +{ +#ifdef USE_OPENAL + int processed; + int state; + ALuint buffer; + + alGetSourcei(source[src], AL_SOURCE_STATE, &state); + + if (state==0x1014) + { + alSourcePlay(source[src]); + } + alGetSourcei(source[src], AL_BUFFERS_PROCESSED, &processed); + + if (processed>=1) + { + alSourceUnqueueBuffers(source[src], 1, &buffer); + + if (sound_is_float) + { + alBufferData(buffer, AL_FORMAT_STEREO_FLOAT32, buf, size * sizeof(float), freq); + } + else + { + alBufferData(buffer, AL_FORMAT_STEREO16, buf, size * sizeof(int16_t), freq); + } + + alSourceQueueBuffers(source[src], 1, &buffer); + } +#endif +} + +void givealbuffer(void *buf) +{ + givealbuffer_common(buf, 0, BUFLEN << 1, FREQ); +} + +void givealbuffer_cd(void *buf) +{ + givealbuffer_common(buf, 1, CD_BUFLEN << 1, CD_FREQ); +} + +void givealbuffer_midi(void *buf, uint32_t size) +{ + givealbuffer_common(buf, 2, size, midi_freq); +} diff --git a/src/resid-fp/AUTHORS b/src/SOUND/resid-fp/AUTHORS similarity index 100% rename from src/resid-fp/AUTHORS rename to src/SOUND/resid-fp/AUTHORS diff --git a/src/resid-fp/COPYING b/src/SOUND/resid-fp/COPYING similarity index 100% rename from src/resid-fp/COPYING rename to src/SOUND/resid-fp/COPYING diff --git a/src/resid-fp/ChangeLog b/src/SOUND/resid-fp/ChangeLog similarity index 100% rename from src/resid-fp/ChangeLog rename to src/SOUND/resid-fp/ChangeLog diff --git a/src/resid-fp/INSTALL b/src/SOUND/resid-fp/INSTALL similarity index 100% rename from src/resid-fp/INSTALL rename to src/SOUND/resid-fp/INSTALL diff --git a/src/resid-fp/Makefile.am b/src/SOUND/resid-fp/Makefile.am similarity index 100% rename from src/resid-fp/Makefile.am rename to src/SOUND/resid-fp/Makefile.am diff --git a/src/resid-fp/Makefile.in b/src/SOUND/resid-fp/Makefile.in similarity index 100% rename from src/resid-fp/Makefile.in rename to src/SOUND/resid-fp/Makefile.in diff --git a/src/resid-fp/NEWS b/src/SOUND/resid-fp/NEWS similarity index 100% rename from src/resid-fp/NEWS rename to src/SOUND/resid-fp/NEWS diff --git a/src/resid-fp/README b/src/SOUND/resid-fp/README similarity index 100% rename from src/resid-fp/README rename to src/SOUND/resid-fp/README diff --git a/src/resid-fp/README.VICE b/src/SOUND/resid-fp/README.VICE similarity index 100% rename from src/resid-fp/README.VICE rename to src/SOUND/resid-fp/README.VICE diff --git a/src/resid-fp/aclocal.m4 b/src/SOUND/resid-fp/aclocal.m4 similarity index 100% rename from src/resid-fp/aclocal.m4 rename to src/SOUND/resid-fp/aclocal.m4 diff --git a/src/resid-fp/configure b/src/SOUND/resid-fp/configure similarity index 100% rename from src/resid-fp/configure rename to src/SOUND/resid-fp/configure diff --git a/src/resid-fp/configure.in b/src/SOUND/resid-fp/configure.in similarity index 100% rename from src/resid-fp/configure.in rename to src/SOUND/resid-fp/configure.in diff --git a/src/resid-fp/convolve-sse.cc b/src/SOUND/resid-fp/convolve-sse.cc similarity index 100% rename from src/resid-fp/convolve-sse.cc rename to src/SOUND/resid-fp/convolve-sse.cc diff --git a/src/resid-fp/convolve.cc b/src/SOUND/resid-fp/convolve.cc similarity index 100% rename from src/resid-fp/convolve.cc rename to src/SOUND/resid-fp/convolve.cc diff --git a/src/resid-fp/envelope.cc b/src/SOUND/resid-fp/envelope.cc similarity index 100% rename from src/resid-fp/envelope.cc rename to src/SOUND/resid-fp/envelope.cc diff --git a/src/resid-fp/envelope.h b/src/SOUND/resid-fp/envelope.h similarity index 100% rename from src/resid-fp/envelope.h rename to src/SOUND/resid-fp/envelope.h diff --git a/src/resid-fp/extfilt.cc b/src/SOUND/resid-fp/extfilt.cc similarity index 100% rename from src/resid-fp/extfilt.cc rename to src/SOUND/resid-fp/extfilt.cc diff --git a/src/resid-fp/extfilt.h b/src/SOUND/resid-fp/extfilt.h similarity index 100% rename from src/resid-fp/extfilt.h rename to src/SOUND/resid-fp/extfilt.h diff --git a/src/resid-fp/filter.cc b/src/SOUND/resid-fp/filter.cc similarity index 100% rename from src/resid-fp/filter.cc rename to src/SOUND/resid-fp/filter.cc diff --git a/src/resid-fp/filter.h b/src/SOUND/resid-fp/filter.h similarity index 100% rename from src/resid-fp/filter.h rename to src/SOUND/resid-fp/filter.h diff --git a/src/resid-fp/pot.cc b/src/SOUND/resid-fp/pot.cc similarity index 100% rename from src/resid-fp/pot.cc rename to src/SOUND/resid-fp/pot.cc diff --git a/src/resid-fp/pot.h b/src/SOUND/resid-fp/pot.h similarity index 100% rename from src/resid-fp/pot.h rename to src/SOUND/resid-fp/pot.h diff --git a/src/resid-fp/samp2src.pl b/src/SOUND/resid-fp/samp2src.pl similarity index 100% rename from src/resid-fp/samp2src.pl rename to src/SOUND/resid-fp/samp2src.pl diff --git a/src/resid-fp/sid.cc b/src/SOUND/resid-fp/sid.cc similarity index 100% rename from src/resid-fp/sid.cc rename to src/SOUND/resid-fp/sid.cc diff --git a/src/resid-fp/sid.h b/src/SOUND/resid-fp/sid.h similarity index 100% rename from src/resid-fp/sid.h rename to src/SOUND/resid-fp/sid.h diff --git a/src/resid-fp/siddefs-fp.h b/src/SOUND/resid-fp/siddefs-fp.h similarity index 100% rename from src/resid-fp/siddefs-fp.h rename to src/SOUND/resid-fp/siddefs-fp.h diff --git a/src/resid-fp/siddefs-fp.h.in b/src/SOUND/resid-fp/siddefs-fp.h.in similarity index 100% rename from src/resid-fp/siddefs-fp.h.in rename to src/SOUND/resid-fp/siddefs-fp.h.in diff --git a/src/resid-fp/version.cc b/src/SOUND/resid-fp/version.cc similarity index 100% rename from src/resid-fp/version.cc rename to src/SOUND/resid-fp/version.cc diff --git a/src/resid-fp/voice.cc b/src/SOUND/resid-fp/voice.cc similarity index 100% rename from src/resid-fp/voice.cc rename to src/SOUND/resid-fp/voice.cc diff --git a/src/resid-fp/voice.h b/src/SOUND/resid-fp/voice.h similarity index 100% rename from src/resid-fp/voice.h rename to src/SOUND/resid-fp/voice.h diff --git a/src/resid-fp/wave.cc b/src/SOUND/resid-fp/wave.cc similarity index 100% rename from src/resid-fp/wave.cc rename to src/SOUND/resid-fp/wave.cc diff --git a/src/resid-fp/wave.h b/src/SOUND/resid-fp/wave.h similarity index 100% rename from src/resid-fp/wave.h rename to src/SOUND/resid-fp/wave.h diff --git a/src/resid-fp/wave6581_PST.cc b/src/SOUND/resid-fp/wave6581_PST.cc similarity index 100% rename from src/resid-fp/wave6581_PST.cc rename to src/SOUND/resid-fp/wave6581_PST.cc diff --git a/src/resid-fp/wave6581_PST.dat b/src/SOUND/resid-fp/wave6581_PST.dat similarity index 100% rename from src/resid-fp/wave6581_PST.dat rename to src/SOUND/resid-fp/wave6581_PST.dat diff --git a/src/resid-fp/wave6581_PS_.cc b/src/SOUND/resid-fp/wave6581_PS_.cc similarity index 100% rename from src/resid-fp/wave6581_PS_.cc rename to src/SOUND/resid-fp/wave6581_PS_.cc diff --git a/src/resid-fp/wave6581_PS_.dat b/src/SOUND/resid-fp/wave6581_PS_.dat similarity index 100% rename from src/resid-fp/wave6581_PS_.dat rename to src/SOUND/resid-fp/wave6581_PS_.dat diff --git a/src/resid-fp/wave6581_P_T.cc b/src/SOUND/resid-fp/wave6581_P_T.cc similarity index 100% rename from src/resid-fp/wave6581_P_T.cc rename to src/SOUND/resid-fp/wave6581_P_T.cc diff --git a/src/resid-fp/wave6581_P_T.dat b/src/SOUND/resid-fp/wave6581_P_T.dat similarity index 100% rename from src/resid-fp/wave6581_P_T.dat rename to src/SOUND/resid-fp/wave6581_P_T.dat diff --git a/src/resid-fp/wave6581__ST.cc b/src/SOUND/resid-fp/wave6581__ST.cc similarity index 100% rename from src/resid-fp/wave6581__ST.cc rename to src/SOUND/resid-fp/wave6581__ST.cc diff --git a/src/resid-fp/wave6581__ST.dat b/src/SOUND/resid-fp/wave6581__ST.dat similarity index 100% rename from src/resid-fp/wave6581__ST.dat rename to src/SOUND/resid-fp/wave6581__ST.dat diff --git a/src/resid-fp/wave8580_PST.cc b/src/SOUND/resid-fp/wave8580_PST.cc similarity index 100% rename from src/resid-fp/wave8580_PST.cc rename to src/SOUND/resid-fp/wave8580_PST.cc diff --git a/src/resid-fp/wave8580_PST.dat b/src/SOUND/resid-fp/wave8580_PST.dat similarity index 100% rename from src/resid-fp/wave8580_PST.dat rename to src/SOUND/resid-fp/wave8580_PST.dat diff --git a/src/resid-fp/wave8580_PS_.cc b/src/SOUND/resid-fp/wave8580_PS_.cc similarity index 100% rename from src/resid-fp/wave8580_PS_.cc rename to src/SOUND/resid-fp/wave8580_PS_.cc diff --git a/src/resid-fp/wave8580_PS_.dat b/src/SOUND/resid-fp/wave8580_PS_.dat similarity index 100% rename from src/resid-fp/wave8580_PS_.dat rename to src/SOUND/resid-fp/wave8580_PS_.dat diff --git a/src/resid-fp/wave8580_P_T.cc b/src/SOUND/resid-fp/wave8580_P_T.cc similarity index 100% rename from src/resid-fp/wave8580_P_T.cc rename to src/SOUND/resid-fp/wave8580_P_T.cc diff --git a/src/resid-fp/wave8580_P_T.dat b/src/SOUND/resid-fp/wave8580_P_T.dat similarity index 100% rename from src/resid-fp/wave8580_P_T.dat rename to src/SOUND/resid-fp/wave8580_P_T.dat diff --git a/src/resid-fp/wave8580__ST.cc b/src/SOUND/resid-fp/wave8580__ST.cc similarity index 100% rename from src/resid-fp/wave8580__ST.cc rename to src/SOUND/resid-fp/wave8580__ST.cc diff --git a/src/resid-fp/wave8580__ST.dat b/src/SOUND/resid-fp/wave8580__ST.dat similarity index 100% rename from src/resid-fp/wave8580__ST.dat rename to src/SOUND/resid-fp/wave8580__ST.dat diff --git a/src/sound_ad1848.c b/src/SOUND/snd_ad1848.c similarity index 92% rename from src/sound_ad1848.c rename to src/SOUND/snd_ad1848.c index 9dd339bce..10ff8b2b3 100644 --- a/src/sound_ad1848.c +++ b/src/SOUND/snd_ad1848.c @@ -2,12 +2,18 @@ AD1848 CODEC emulation (Windows Sound System compatible)*/ -#include "ibm.h" +#include +#include "../ibm.h" +#include "../dma.h" +#include "../pic.h" +#include "../timer.h" #include "sound.h" -#include "sound_ad1848.h" +#include "snd_ad1848.h" + static int ad1848_vols[64]; + void ad1848_setirq(ad1848_t *ad1848, int irq) { ad1848->irq = irq; @@ -22,7 +28,6 @@ uint8_t ad1848_read(uint16_t addr, void *p) { ad1848_t *ad1848 = (ad1848_t *)p; uint8_t temp = 0xff; -// pclog("ad1848_read - addr %04X %04X(%08X):%08X ", addr, CS, cs, pc); switch (addr & 3) { case 0: /*Index*/ @@ -35,7 +40,6 @@ uint8_t ad1848_read(uint16_t addr, void *p) temp = ad1848->status; break; } -// pclog("return %02X\n", temp); return temp; } @@ -43,7 +47,6 @@ void ad1848_write(uint16_t addr, uint8_t val, void *p) { ad1848_t *ad1848 = (ad1848_t *)p; double freq; -// pclog("ad1848_write - addr %04X val %02X %04X(%08X):%08X\n", addr, val, CS, cs, pc); switch (addr & 3) { case 0: /*Index*/ @@ -165,12 +168,10 @@ static void ad1848_poll(void *p) } ad1848->count--; -// pclog("ad1848_poll : enable %X %X %X %X %X %X\n", ad1848->pcm_buffer[0][ad1848->pos], ad1848->pcm_buffer[1][ad1848->pos], ad1848->out_l[0], ad1848->out_r[0], ad1848->out_l[1], ad1848->out_r[1]); } else { ad1848->out_l = ad1848->out_r = 0; -// pclog("ad1848_poll : not enable\n"); } } @@ -212,7 +213,6 @@ void ad1848_init(ad1848_t *ad1848) attenuation = pow(10, attenuation / 10); ad1848_vols[c] = (int)(attenuation * 65536); -// pclog("ad1848_vols %i = %f %i\n", c, attenuation, ad1848_vols[c]); } timer_add(ad1848_poll, &ad1848->timer_count, &ad1848->enable, ad1848); diff --git a/src/sound_ad1848.h b/src/SOUND/snd_ad1848.h similarity index 95% rename from src/sound_ad1848.h rename to src/SOUND/snd_ad1848.h index b97e1e499..3a0dd4e46 100644 --- a/src/sound_ad1848.h +++ b/src/SOUND/snd_ad1848.h @@ -1,5 +1,3 @@ -#include "timer.h" - typedef struct ad1848_t { int index; @@ -33,3 +31,5 @@ void ad1848_write(uint16_t addr, uint8_t val, void *p); void ad1848_update(ad1848_t *ad1848); void ad1848_speed_changed(ad1848_t *ad1848); + +void ad1848_init(ad1848_t *ad1848); diff --git a/src/SOUND/snd_adlib.c b/src/SOUND/snd_adlib.c new file mode 100644 index 000000000..e131d04c3 --- /dev/null +++ b/src/SOUND/snd_adlib.c @@ -0,0 +1,115 @@ +#include +#include "../ibm.h" +#include "../io.h" +#include "../mca.h" +#include "../device.h" +#include "sound.h" +#include "snd_adlib.h" +#include "snd_opl.h" + + +typedef struct adlib_t +{ + opl_t opl; + + uint8_t pos_regs[8]; +} adlib_t; + + +static void adlib_get_buffer(int32_t *buffer, int len, void *p) +{ + adlib_t *adlib = (adlib_t *)p; + int c; + + opl2_update2(&adlib->opl); + + for (c = 0; c < len * 2; c++) + buffer[c] += (int32_t)adlib->opl.buffer[c]; + + adlib->opl.pos = 0; +} + +uint8_t adlib_mca_read(int port, void *p) +{ + adlib_t *adlib = (adlib_t *)p; + + pclog("adlib_mca_read: port=%04x\n", port); + + return adlib->pos_regs[port & 7]; +} + +void adlib_mca_write(int port, uint8_t val, void *p) +{ + adlib_t *adlib = (adlib_t *)p; + + if (port < 0x102) + return; + + pclog("adlib_mca_write: port=%04x val=%02x\n", port, val); + + switch (port) + { + case 0x102: + if ((adlib->pos_regs[2] & 1) && !(val & 1)) + io_removehandler(0x0388, 0x0002, opl2_read, NULL, NULL, opl2_write, NULL, NULL, &adlib->opl); + if (!(adlib->pos_regs[2] & 1) && (val & 1)) + io_sethandler(0x0388, 0x0002, opl2_read, NULL, NULL, opl2_write, NULL, NULL, &adlib->opl); + break; + } + adlib->pos_regs[port & 7] = val; +} + +void *adlib_init() +{ + adlib_t *adlib = malloc(sizeof(adlib_t)); + memset(adlib, 0, sizeof(adlib_t)); + + pclog("adlib_init\n"); + opl2_init(&adlib->opl); + io_sethandler(0x0388, 0x0002, opl2_read, NULL, NULL, opl2_write, NULL, NULL, &adlib->opl); + sound_add_handler(adlib_get_buffer, adlib); + return adlib; +} + +void *adlib_mca_init() +{ + adlib_t *adlib = adlib_init(); + + io_removehandler(0x0388, 0x0002, opl2_read, NULL, NULL, opl2_write, NULL, NULL, &adlib->opl); + mca_add(adlib_mca_read, adlib_mca_write, adlib); + adlib->pos_regs[0] = 0xd7; + adlib->pos_regs[1] = 0x70; + + return adlib; +} + +void adlib_close(void *p) +{ + adlib_t *adlib = (adlib_t *)p; + + free(adlib); +} + +device_t adlib_device = +{ + "AdLib", + 0, + adlib_init, + adlib_close, + NULL, + NULL, + NULL, + NULL +}; + +device_t adlib_mca_device = +{ + "AdLib (MCA)", + DEVICE_MCA, + adlib_init, + adlib_close, + NULL, + NULL, + NULL, + NULL +}; diff --git a/src/SOUND/snd_adlib.h b/src/SOUND/snd_adlib.h new file mode 100644 index 000000000..1e2c363af --- /dev/null +++ b/src/SOUND/snd_adlib.h @@ -0,0 +1,2 @@ +extern device_t adlib_device; +extern device_t adlib_mca_device; diff --git a/src/sound_adlibgold.c b/src/SOUND/snd_adlibgold.c similarity index 95% rename from src/sound_adlibgold.c rename to src/SOUND/snd_adlibgold.c index a0f0956a9..e03a9cf9b 100644 --- a/src/sound_adlibgold.c +++ b/src/SOUND/snd_adlibgold.c @@ -1,18 +1,19 @@ #include #include -#include "ibm.h" -#include "device.h" - -#include "sound_opl.h" -#include "sound_ym7128.h" -#include "dma.h" -#include "io.h" -#include "pic.h" -#include "pit.h" +#include "../ibm.h" +#include "../io.h" +#include "../dma.h" +#include "../pic.h" +#include "../pit.h" +#include "../mem.h" +#include "../rom.h" +#include "../timer.h" +#include "../device.h" #include "sound.h" -#include "timer.h" - #include "filters.h" +#include "snd_opl.h" +#include "snd_ym7128.h" + typedef struct adgold_t { @@ -146,7 +147,6 @@ void adgold_update_irq_status(adgold_t *adgold) if ((adgold->adgold_status ^ 0xf) && !adgold->adgold_irq_status) { -// pclog("adgold irq %02X\n", adgold->adgold_status); picint(0x80); } @@ -161,14 +161,12 @@ void adgold_getsamp_dma(adgold_t *adgold, int channel) return; temp = dma_channel_read(1); -// pclog("adgold DMA1 return %02X %i L\n", temp, channel); if (temp == DMA_NODATA) return; adgold->adgold_mma_fifo[channel][adgold->adgold_mma_fifo_end[channel]] = temp; adgold->adgold_mma_fifo_end[channel] = (adgold->adgold_mma_fifo_end[channel] + 1) & 255; if (adgold->adgold_mma_regs[channel][0xc] & 0x60) { temp = dma_channel_read(1); -// pclog("adgold DMA1 return %02X %i H\n", temp, channel); adgold->adgold_mma_fifo[channel][adgold->adgold_mma_fifo_end[channel]] = temp; adgold->adgold_mma_fifo_end[channel] = (adgold->adgold_mma_fifo_end[channel] + 1) & 255; } @@ -182,7 +180,6 @@ void adgold_getsamp_dma(adgold_t *adgold, int channel) void adgold_write(uint16_t addr, uint8_t val, void *p) { adgold_t *adgold = (adgold_t *)p; -// if (addr > 0x389) pclog("adgold_write : addr %04X val %02X %04X:%04X\n", addr, val, CS, pc); switch (addr & 7) { case 0: case 1: @@ -326,12 +323,10 @@ void adgold_write(uint16_t addr, uint8_t val, void *p) if (!(adgold->adgold_mma_regs[0][0x9] & 1)) adgold->adgold_mma.voice_count[0] = adgold->adgold_mma.voice_latch[0]; -// pclog("adgold start! FIFO fill %i %i %i %02X\n", (adgold->adgold_mma_fifo_end[0] - adgold->adgold_mma_fifo_start[0]) & 255, adgold->adgold_mma_fifo_end[0], adgold->adgold_mma_fifo_start[0], adgold->adgold_mma_regs[0][0xc]); if (adgold->adgold_mma_regs[0][0xc] & 1) { if (adgold->adgold_mma_regs[0][0xc] & 0x80) { -// pclog("adgold start interleaved %i %i adgold->adgold_mma_enable[1] = 1; adgold->adgold_mma.voice_count[1] = adgold->adgold_mma.voice_latch[1]; @@ -364,7 +359,6 @@ void adgold_write(uint16_t addr, uint8_t val, void *p) } } } -// pclog("adgold end\n"); } adgold->adgold_mma_enable[0] = val & 0x01; break; @@ -413,7 +407,6 @@ void adgold_write(uint16_t addr, uint8_t val, void *p) if (!(adgold->adgold_mma_regs[1][0x9] & 1)) adgold->adgold_mma.voice_count[1] = adgold->adgold_mma.voice_latch[1]; -// pclog("adgold start! FIFO fill %i %i %i %02X\n", (adgold->adgold_mma_fifo_end[1] - adgold->adgold_mma_fifo_start[1]) & 255, adgold->adgold_mma_fifo_end[1], adgold->adgold_mma_fifo_start[1], adgold->adgold_mma_regs[1][0xc]); if (adgold->adgold_mma_regs[1][0xc] & 1) { while (((adgold->adgold_mma_fifo_end[1] - adgold->adgold_mma_fifo_start[1]) & 255) < 128) @@ -421,7 +414,6 @@ void adgold_write(uint16_t addr, uint8_t val, void *p) adgold_getsamp_dma(adgold, 1); } } -// pclog("adgold end\n"); } adgold->adgold_mma_enable[1] = val & 0x01; break; @@ -514,7 +506,6 @@ uint8_t adgold_read(uint16_t addr, void *p) temp = adgold->adgold_mma_regs[1][adgold->adgold_mma_addr]; break; } -// if (addr > 0x389) pclog("adgold_read : addr %04X %02X\n", addr, temp); return temp; } @@ -570,7 +561,6 @@ void adgold_mma_poll(adgold_t *adgold, int channel) } if (((adgold->adgold_mma_fifo_end[channel] - adgold->adgold_mma_fifo_start[channel]) & 255) < adgold->adgold_mma_intpos[channel] && !(adgold->adgold_mma_status & 0x01)) { -// pclog("adgold_mma_poll - IRQ! %i\n", channel); adgold->adgold_mma_status |= 1 << channel; adgold_update_irq_status(adgold); } @@ -594,7 +584,6 @@ void adgold_timer_poll(void *p) if (!adgold->adgold_mma.timer0_count) { adgold->adgold_mma.timer0_count = adgold->adgold_mma.timer0_latch; -// pclog("Timer 0 interrupt\n"); adgold->adgold_mma_status |= 0x10; adgold_update_irq_status(adgold); } @@ -611,7 +600,6 @@ void adgold_timer_poll(void *p) if (!adgold->adgold_mma.timer1_count) { adgold->adgold_mma.timer1_count = adgold->adgold_mma.timer1_latch; -// pclog("Timer 1 interrupt\n"); adgold->adgold_mma_status |= 0x20; adgold_update_irq_status(adgold); } @@ -622,7 +610,6 @@ void adgold_timer_poll(void *p) if (!adgold->adgold_mma.timer2_count) { adgold->adgold_mma.timer2_count = adgold->adgold_mma.timer2_latch; -// pclog("Timer 2 interrupt\n"); adgold->adgold_mma_status |= 0x40; adgold_update_irq_status(adgold); } @@ -786,7 +773,7 @@ void *adgold_init() for (; c >= 0; c--) attenuation[c] = 0; - f = romfopen("nvr/adgold.bin", "rb"); + f = nvrfopen(L"adgold.bin", L"rb"); if (f) { fread(adgold->adgold_eeprom, 0x18, 1, f); @@ -826,7 +813,7 @@ void adgold_close(void *p) FILE *f; adgold_t *adgold = (adgold_t *)p; - f = romfopen("nvr/adgold.bin", "wb"); + f = nvrfopen(L"adgold.bin", L"wb"); if (f) { fwrite(adgold->adgold_eeprom, 0x18, 1, f); @@ -839,13 +826,10 @@ void adgold_close(void *p) static device_config_t adgold_config[] = { { - .name = "surround", - .description = "Surround module", - .type = CONFIG_BINARY, - .default_int = 1 + "surround", "Surround module", CONFIG_BINARY, "", 1 }, { - .type = -1 + "", "", -1 } }; diff --git a/src/sound_adlibgold.h b/src/SOUND/snd_adlibgold.h similarity index 100% rename from src/sound_adlibgold.h rename to src/SOUND/snd_adlibgold.h diff --git a/src/sound_cms.c b/src/SOUND/snd_cms.c similarity index 90% rename from src/sound_cms.c rename to src/SOUND/snd_cms.c index f38f46f9c..1cbf723b2 100644 --- a/src/sound_cms.c +++ b/src/SOUND/snd_cms.c @@ -1,11 +1,14 @@ #include #include -#include "ibm.h" - -#include "device.h" -#include "io.h" +#include "../ibm.h" +#include "../io.h" +#include "../device.h" #include "sound.h" -#include "sound_cms.h" +#include "snd_cms.h" + + +#define MASTER_CLOCK 7159090 + typedef struct cms_t { @@ -37,9 +40,9 @@ void cms_update(cms_t *cms) { switch (cms->noisetype[c >> 1][c & 1]) { - case 0: cms->noisefreq[c >> 1][c & 1] = 31250; break; - case 1: cms->noisefreq[c >> 1][c & 1] = 15625; break; - case 2: cms->noisefreq[c >> 1][c & 1] = 7812; break; + case 0: cms->noisefreq[c >> 1][c & 1] = MASTER_CLOCK/256; break; + case 1: cms->noisefreq[c >> 1][c & 1] = MASTER_CLOCK/512; break; + case 2: cms->noisefreq[c >> 1][c & 1] = MASTER_CLOCK/1024; break; case 3: cms->noisefreq[c >> 1][c & 1] = cms->freq[c >> 1][(c & 1) * 3]; break; } } @@ -124,14 +127,14 @@ void cms_write(uint16_t addr, uint8_t val, void *p) case 0x0B: case 0x0C: case 0x0D: voice = cms->addrs[chip] & 7; cms->latch[chip][voice] = (cms->latch[chip][voice] & 0x700) | val; - cms->freq[chip][voice] = (15625 << (cms->latch[chip][voice] >> 8)) / (511 - (cms->latch[chip][voice] & 255)); + cms->freq[chip][voice] = (MASTER_CLOCK/512 << (cms->latch[chip][voice] >> 8)) / (511 - (cms->latch[chip][voice] & 255)); break; case 0x10: case 0x11: case 0x12: /*Octave*/ voice = (cms->addrs[chip] & 3) << 1; cms->latch[chip][voice] = (cms->latch[chip][voice] & 0xFF) | ((val & 7) << 8); cms->latch[chip][voice + 1] = (cms->latch[chip][voice + 1] & 0xFF) | ((val & 0x70) << 4); - cms->freq[chip][voice] = (15625 << (cms->latch[chip][voice] >> 8)) / (511 - (cms->latch[chip][voice] & 255)); - cms->freq[chip][voice + 1] = (15625 << (cms->latch[chip][voice + 1] >> 8)) / (511 - (cms->latch[chip][voice + 1] & 255)); + cms->freq[chip][voice] = (MASTER_CLOCK/512 << (cms->latch[chip][voice] >> 8)) / (511 - (cms->latch[chip][voice] & 255)); + cms->freq[chip][voice + 1] = (MASTER_CLOCK/512 << (cms->latch[chip][voice + 1] >> 8)) / (511 - (cms->latch[chip][voice + 1] & 255)); break; case 0x16: /*Noise*/ cms->noisetype[chip][0] = val & 3; diff --git a/src/sound_cms.h b/src/SOUND/snd_cms.h similarity index 100% rename from src/sound_cms.h rename to src/SOUND/snd_cms.h diff --git a/src/sound_dbopl.cc b/src/SOUND/snd_dbopl.cc similarity index 83% rename from src/sound_dbopl.cc rename to src/SOUND/snd_dbopl.cc index cd13180f3..94480ad4f 100644 --- a/src/sound_dbopl.cc +++ b/src/SOUND/snd_dbopl.cc @@ -1,9 +1,13 @@ -/* Copyright holders: The DOSBox Team, SA1988 +/* Copyright holders: Sarah Walker, SA1988 see COPYING for more details */ -#include "dosbox/dbopl.h" -#include "dosbox/nukedopl.h" -#include "sound_dbopl.h" +#include "dbopl.h" +#include "nukedopl.h" +#include "snd_dbopl.h" + + +int opl3_type = 0; + static struct { @@ -38,13 +42,13 @@ enum void opl_init(void (*timer_callback)(void *param, int timer, int64_t period), void *timer_param, int nr, int is_opl3) { - if (!is_opl3) + if (!is_opl3 || !opl3_type) { - DBOPL::InitTables(); - opl[nr].chip.Setup(48000, 0); + DBOPL::InitTables(); + opl[nr].chip.Setup(48000, is_opl3); opl[nr].timer_callback = timer_callback; opl[nr].timer_param = timer_param; - opl[nr].is_opl3 = 0; + opl[nr].is_opl3 = is_opl3; } else { @@ -82,18 +86,18 @@ void opl_timer_over(int nr, int timer) void opl_write(int nr, uint16_t addr, uint8_t val) { if (!(addr & 1)) - { - if (!opl[nr].is_opl3) - opl[nr].addr = (int)opl[nr].chip.WriteAddr(addr, val) & 0xff; - else - opl[nr].addr = (int)OPL3_WriteAddr(&opl[nr].opl3chip, addr, val) & 0x1ff; - } + { + if (!opl[nr].is_opl3 || !opl3_type) + opl[nr].addr = (int)opl[nr].chip.WriteAddr(addr, val) & (opl[nr].is_opl3 ? 0x1ff : 0xff); + else + opl[nr].addr = (int)OPL3_WriteAddr(&opl[nr].opl3chip, addr, val) & 0x1ff; + } else { - if (!opl[nr].is_opl3) - opl[nr].chip.WriteReg(opl[nr].addr, val); - else - OPL3_WriteReg(&opl[nr].opl3chip, opl[nr].addr, val); + if (!opl[nr].is_opl3 || !opl3_type) + opl[nr].chip.WriteReg(opl[nr].addr, val); + else + OPL3_WriteReg(&opl[nr].opl3chip, opl[nr].addr, val); switch (opl[nr].addr) { @@ -154,5 +158,18 @@ void opl2_update(int nr, int16_t *buffer, int samples) void opl3_update(int nr, int16_t *buffer, int samples) { + int c; + Bit32s buffer_32[samples*2]; + + if (opl3_type) + { OPL3_GenerateStream(&opl[nr].opl3chip, buffer, samples); + } + else + { + opl[nr].chip.GenerateBlock3(samples, buffer_32); + + for (c = 0; c < samples*2; c++) + buffer[c] = (int16_t)buffer_32[c]; + } } diff --git a/src/sound_dbopl.h b/src/SOUND/snd_dbopl.h similarity index 88% rename from src/sound_dbopl.h rename to src/SOUND/snd_dbopl.h index d16ce9549..6fd536f39 100644 --- a/src/sound_dbopl.h +++ b/src/SOUND/snd_dbopl.h @@ -1,4 +1,4 @@ -/* Copyright holders: The DOSBox Team, SA1988 +/* Copyright holders: Sarah Walker, SA1988 see COPYING for more details */ #ifdef __cplusplus @@ -10,6 +10,8 @@ extern "C" { void opl_timer_over(int nr, int timer); void opl2_update(int nr, int16_t *buffer, int samples); void opl3_update(int nr, int16_t *buffer, int samples); + + extern int opl3_type; #ifdef __cplusplus } #endif diff --git a/src/sound_emu8k.c b/src/SOUND/snd_emu8k.c similarity index 88% rename from src/sound_emu8k.c rename to src/SOUND/snd_emu8k.c index 6274b8839..67a50734f 100644 --- a/src/sound_emu8k.c +++ b/src/SOUND/snd_emu8k.c @@ -5,11 +5,15 @@ highest (10.72 Hz) = 2^12 steps = 4096*/ #include #include -#include "ibm.h" -#include "device.h" +#include "../ibm.h" +#include "../io.h" +#include "../mem.h" +#include "../rom.h" +#include "../timer.h" +#include "../device.h" #include "sound.h" -#include "sound_emu8k.h" -#include "timer.h" +#include "snd_emu8k.h" + enum { @@ -40,38 +44,48 @@ static int32_t filt_w0[256]; case 2: var = (var & 0x0000ffff) | ((val) << 16); break; \ } -static inline int16_t EMU8K_READ(emu8k_t *emu8k, uint32_t addr) +static __inline int16_t EMU8K_READ(emu8k_t *emu8k, uint16_t addr) { - addr &= 0xffffff; - if (addr < 0x80000) + addr &= EMU8K_MEM_ADDRESS_MASK; + /* TODO: I've read that the AWE64 Gold model had a 4MB Rom. It would be interesting + to find that rom and do some tests with it. */ + if (addr < EMU8K_ROM_MEM_1MB_END) return emu8k->rom[addr]; - if (addr < 0x200000 || addr >= emu8k->ram_end_addr) + if (addr < EMU8K_RAM_MEM_START || addr >= emu8k->ram_end_addr) return 0; if (!emu8k->ram) return 0; - return emu8k->ram[addr - 0x200000]; + return emu8k->ram[addr - EMU8K_RAM_MEM_START]; } -static inline int16_t EMU8K_READ_INTERP(emu8k_t *emu8k, uint32_t addr) +static __inline int16_t EMU8K_READ_INTERP(emu8k_t *emu8k, uint16_t addr) { int16_t dat1 = EMU8K_READ(emu8k, addr >> 8); int16_t dat2 = EMU8K_READ(emu8k, (addr >> 8) + 1); return ((dat1 * (0xff - (addr & 0xff))) + (dat2 * (addr & 0xff))) >> 8; } -static inline void EMU8K_WRITE(emu8k_t *emu8k, uint32_t addr, uint16_t val) +static __inline void EMU8K_WRITE(emu8k_t *emu8k, uint16_t addr, uint16_t val) { - addr &= 0xffffff; - if (emu8k->ram && addr >= 0x200000 && addr < emu8k->ram_end_addr) - emu8k->ram[addr - 0x200000] = val; -} -static int ff = 0; -static int voice_count = 0; + if ( !emu8k->ram || addr < EMU8K_RAM_MEM_START) + return; -uint16_t emu8k_inw(uint32_t addr, void *p) + /* It looks like if an application writes to a memory part outside of the available amount on the card, + it wraps, and opencubicplayer uses that to detect the amount of memory, as opposed to simply check + at the address that it has just tried to write. */ + addr &= EMU8K_MEM_ADDRESS_MASK; + while (addr >= emu8k->ram_end_addr) { + addr -= emu8k->ram_end_addr - EMU8K_RAM_MEM_START; + } + emu8k->ram[addr - EMU8K_RAM_MEM_START] = val; +} + +static int ff = 0; + +uint16_t emu8k_inw(uint16_t addr, void *p) { emu8k_t *emu8k = (emu8k_t *)p; - uint16_t ret; + uint16_t ret = 0xffff; /* pclog("emu8k_inw %04X reg=%i voice=%i\n", addr, emu8k->cur_reg, emu8k->cur_voice);*/ addr -= 0x220; @@ -81,8 +95,11 @@ uint16_t emu8k_inw(uint32_t addr, void *p) switch (emu8k->cur_reg) { case 0: - READ16(addr, emu8k->voice[emu8k->cur_voice].cpf); - return ret; + { + uint32_t var = (emu8k->voice[emu8k->cur_voice].cpf & 0xFFFF0000) | ((emu8k->voice[emu8k->cur_voice].addr >> 16) & 0xFFFF); + READ16(addr, var); + return ret; + } case 1: READ16(addr, emu8k->voice[emu8k->cur_voice].ptrx); @@ -104,7 +121,7 @@ uint16_t emu8k_inw(uint32_t addr, void *p) return ret; case 7: - READ16(addr, emu8k->voice[emu8k->cur_voice].cpf); + READ16(addr, emu8k->voice[emu8k->cur_voice].csl); return ret; } break; @@ -114,7 +131,8 @@ uint16_t emu8k_inw(uint32_t addr, void *p) { case 0: { - uint32_t val = (emu8k->voice[emu8k->cur_voice].ccca & 0xff000000) | (emu8k->voice[emu8k->cur_voice].addr >> 8); + emu8k->voice[emu8k->cur_voice].ccca = + (emu8k->voice[emu8k->cur_voice].ccca & 0xFF000000) | ((emu8k->voice[emu8k->cur_voice].addr >> 32) & EMU8K_MEM_ADDRESS_MASK); READ16(addr, emu8k->voice[emu8k->cur_voice].ccca); return ret; } @@ -170,7 +188,6 @@ uint16_t emu8k_inw(uint32_t addr, void *p) { case 0: { - uint32_t val = (emu8k->voice[emu8k->cur_voice].ccca & 0xff000000) | (emu8k->voice[emu8k->cur_voice].addr >> 8); READ16(addr, emu8k->voice[emu8k->cur_voice].ccca); return ret; } @@ -244,23 +261,24 @@ uint16_t emu8k_inw(uint32_t addr, void *p) return 0x1c | ((emu8k->id & 0x0002) ? 0xff02 : 0); } break; - case 0xc02: /*Status - I think!*/ - voice_count = (voice_count + 1) & 0x1f; -/* emu8k->c02_read ^= 0x1000; - pclog("Read status %04X\n", 0x803f | (voice_count << 8));*/ - return 0x803f | (voice_count << 8); + case 0xc02: + /* LS five bits = channel number, next 3 bits = register number + and MS 8 bits = VLSI test register. + Impulse tracker tests the non variability of the LS byte and the variability + of the MS byte to determine that it really is an AWE32. */ + return ((rand()&0xFF) << 8) | (emu8k->cur_reg << 5) | emu8k->cur_voice; } /* fatal("Bad EMU8K inw from %08X\n", addr);*/ return 0xffff; } -void emu8k_outw(uint32_t addr, uint16_t val, void *p) +void emu8k_outw(uint16_t addr, uint16_t val, void *p) { + float q; emu8k_t *emu8k = (emu8k_t *)p; emu8k_update(emu8k); /* pclog("emu8k_outw : addr=%08X reg=%i voice=%i val=%04X\n", addr, emu8k->cur_reg, emu8k->cur_voice, val);*/ -//emu8k_outw : addr=00000A22 reg=3 voice=21 val=0265 addr -= 0x220; switch (addr & 0xc02) { @@ -269,6 +287,8 @@ void emu8k_outw(uint32_t addr, uint16_t val, void *p) { case 0: WRITE16(addr, emu8k->voice[emu8k->cur_voice].cpf, val); + /* Ignoring any effect over writing to the "fractional address". The docs says that this value is constantly + updating, so it has no actual effect. */ return; case 1: @@ -285,7 +305,8 @@ void emu8k_outw(uint32_t addr, uint16_t val, void *p) case 6: WRITE16(addr, emu8k->voice[emu8k->cur_voice].psst, val); - emu8k->voice[emu8k->cur_voice].loop_start = (uint64_t)(emu8k->voice[emu8k->cur_voice].psst & 0xffffff) << 32; + /* TODO: Should we update only on MSB update, or this could be used as some sort of hack by applications? */ + emu8k->voice[emu8k->cur_voice].loop_start = (uint64_t)(emu8k->voice[emu8k->cur_voice].psst & EMU8K_MEM_ADDRESS_MASK) << 32; if (addr & 2) { emu8k->voice[emu8k->cur_voice].vol_l = val >> 8; @@ -295,9 +316,10 @@ void emu8k_outw(uint32_t addr, uint16_t val, void *p) return; case 7: - WRITE16(addr, emu8k->voice[emu8k->cur_voice].cpf, val); - emu8k->voice[emu8k->cur_voice].loop_end = (uint64_t)(emu8k->voice[emu8k->cur_voice].cpf & 0xffffff) << 32; -/* pclog("emu8k_outl : write CPF %08X\n", emu8k->voice[emu8k->cur_voice].cpf);*/ + WRITE16(addr, emu8k->voice[emu8k->cur_voice].csl, val); + /* TODO: Should we update only on MSB update, or this could be used as some sort of hack by applications? */ + emu8k->voice[emu8k->cur_voice].loop_end = (uint64_t)(emu8k->voice[emu8k->cur_voice].csl & EMU8K_MEM_ADDRESS_MASK) << 32; +/* pclog("emu8k_outl : write CSL %08X\n", emu8k->voice[emu8k->cur_voice].csl);*/ return; } break; @@ -307,7 +329,8 @@ void emu8k_outw(uint32_t addr, uint16_t val, void *p) { case 0: WRITE16(addr, emu8k->voice[emu8k->cur_voice].ccca, val); - emu8k->voice[emu8k->cur_voice].addr = (uint64_t)(emu8k->voice[emu8k->cur_voice].ccca & 0xffffff) << 32; + /* TODO: Should we update only on MSB update, or this could be used as some sort of hack by applications? */ + emu8k->voice[emu8k->cur_voice].addr = (uint64_t)(emu8k->voice[emu8k->cur_voice].ccca & EMU8K_MEM_ADDRESS_MASK) << 32; /* pclog("emu8k_outl : write CCCA %08X\n", emu8k->voice[emu8k->cur_voice].ccca);*/ return; @@ -384,10 +407,10 @@ void emu8k_outw(uint32_t addr, uint16_t val, void *p) { case 0: { - float q; - WRITE16(addr, emu8k->voice[emu8k->cur_voice].ccca, val); - emu8k->voice[emu8k->cur_voice].addr = (uint64_t)(emu8k->voice[emu8k->cur_voice].ccca & 0xffffff) << 32; + emu8k->voice[emu8k->cur_voice].addr = (uint64_t)(emu8k->voice[emu8k->cur_voice].ccca & EMU8K_MEM_ADDRESS_MASK) << 32; + /* TODO: Since "fractional address" is a separate register (cpf), should we add its contents to .addr or we assume that it + is reset to zero? */ q = (float)(emu8k->voice[emu8k->cur_voice].ccca >> 28) / 15.0f; q /= 10.0f; /*Horrible and wrong hack*/ @@ -487,14 +510,14 @@ void emu8k_outw(uint32_t addr, uint16_t val, void *p) } } -uint8_t emu8k_inb(uint32_t addr, void *p) +uint8_t emu8k_inb(uint16_t addr, void *p) { if (addr & 1) return emu8k_inw(addr & ~1, p) >> 1; return emu8k_inw(addr, p) & 0xff; } -void emu8k_outb(uint32_t addr, uint8_t val, void *p) +void emu8k_outb(uint16_t addr, uint8_t val, void *p) { if (addr & 1) emu8k_outw(addr & ~1, val << 8, p); @@ -504,13 +527,13 @@ void emu8k_outb(uint32_t addr, uint8_t val, void *p) void emu8k_update(emu8k_t *emu8k) { + int32_t *buf; + int pos; + int c; + int new_pos = (sound_pos_global * 44100) / 48000; if (emu8k->pos < new_pos) { - int32_t *buf; - int pos; - int c; - int32_t out_l = 0, out_r = 0; buf = &emu8k->buffer[emu8k->pos*2]; @@ -526,10 +549,7 @@ void emu8k_update(emu8k_t *emu8k) int32_t voice_l, voice_r; int32_t dat; int lfo1_vibrato, lfo2_vibrato; - int tremolo; - tremolo = ((lfotable[(emu8k->voice[c].lfo1_count >> 8) & 4095] * emu8k->voice[c].lfo1_trem) * 4) >> 12; - if (freqtable[emu8k->voice[c].pitch] >> 32) dat = EMU8K_READ(emu8k, emu8k->voice[c].addr >> 32); else @@ -676,14 +696,21 @@ void emu8k_init(emu8k_t *emu8k, int onboard_ram) int c; double out; - f = romfopen("roms/awe32.raw", "rb"); + f = romfopen(L"roms/awe32.raw", L"rb"); if (!f) fatal("ROMS/AWE32.RAW not found\n"); if (onboard_ram) { + /* Clip to 28MB, since that's the max that we can address. */ + if (onboard_ram > 0x7000) onboard_ram = 0x7000; emu8k->ram = malloc(onboard_ram * 1024); - emu8k->ram_end_addr = 0x200000 + ((onboard_ram * 1024) / 2); + emu8k->ram_end_addr = EMU8K_RAM_MEM_START + ((onboard_ram * 1024) / 2); + } + else + { + emu8k->ram = 0; + emu8k->ram_end_addr = EMU8K_RAM_MEM_START; } emu8k->rom = malloc(1024 * 1024); diff --git a/src/sound_emu8k.h b/src/SOUND/snd_emu8k.h similarity index 95% rename from src/sound_emu8k.h rename to src/SOUND/snd_emu8k.h index 79478ad56..6eea70a00 100644 --- a/src/sound_emu8k.h +++ b/src/SOUND/snd_emu8k.h @@ -1,3 +1,7 @@ +#define EMU8K_MEM_ADDRESS_MASK 0xFFFFFF +#define EMU8K_RAM_MEM_START 0x200000 +#define EMU8K_ROM_MEM_1MB_END 0x80000 + typedef struct emu8k_t { struct diff --git a/src/sound_gus.c b/src/SOUND/snd_gus.c similarity index 82% rename from src/sound_gus.c rename to src/SOUND/snd_gus.c index 7158c7203..bf625dfb2 100644 --- a/src/sound_gus.c +++ b/src/SOUND/snd_gus.c @@ -1,15 +1,15 @@ #include #include #include -#include "ibm.h" - -#include "device.h" -#include "dma.h" -#include "io.h" -#include "pic.h" +#include "../ibm.h" +#include "../io.h" +#include "../pic.h" +#include "../dma.h" +#include "../timer.h" +#include "../device.h" #include "sound.h" -#include "sound_gus.h" -#include "timer.h" +#include "snd_gus.h" + typedef struct gus_t { @@ -93,28 +93,23 @@ void pollgusirqs(gus_t *gus) { if (gus->waveirqs[c]) { -// gus->waveirqs[c]=0; gus->irqstatus2=0x60|c; if (gus->rampirqs[c]) gus->irqstatus2 |= 0x80; gus->irqstatus|=0x20; -// printf("Voice IRQ %i %02X %i\n",c,gus->irqstatus2,ins); if (gus->irq != -1) picint(1 << gus->irq); return; } if (gus->rampirqs[c]) { -// gus->rampirqs[c]=0; gus->irqstatus2=0xA0|c; gus->irqstatus|=0x40; -// printf("Ramp IRQ %i %02X %i\n",c,gus->irqstatus2,ins); if (gus->irq != -1) picint(1 << gus->irq); return; } } gus->irqstatus2=0xE0; -// gus->irqstatus&=~0x20; if (!gus->irqstatus && gus->irq != -1) picintc(1 << gus->irq); } @@ -164,7 +159,6 @@ void gus_midi_update_int_status(gus_t *gus) if ((gus->midi_status & MIDI_INT_MASTER) && (gus->irq_midi != -1)) { -// pclog("Take MIDI IRQ\n"); picint(1 << gus->irq_midi); } } @@ -174,7 +168,6 @@ void writegus(uint16_t addr, uint8_t val, void *p) gus_t *gus = (gus_t *)p; int c, d; int old; -// pclog("Write GUS %04X %02X %04X:%04X\n",addr,val,CS,pc); if (gus->latch_enable && addr != 0x24b) gus->latch_enable = 0; switch (addr) @@ -188,7 +181,6 @@ void writegus(uint16_t addr, uint8_t val, void *p) else if ((old & 3) == 3) { gus->midi_status |= MIDI_INT_TRANSMIT; -// pclog("MIDI_INT_TRANSMIT\n"); } gus_midi_update_int_status(gus); break; @@ -210,11 +202,9 @@ void writegus(uint16_t addr, uint8_t val, void *p) gus->global=val; break; case 0x344: /*Global low*/ -// if (gus->global!=0x43 && gus->global!=0x44) printf("Writing register %02X %02X %02X %i\n",gus->global,gus->voice,val, ins); switch (gus->global) { case 0: /*Voice control*/ -// if (val&1 && !(gus->ctrl[gus->voice]&1)) printf("Voice on %i\n",gus->voice); gus->ctrl[gus->voice]=val; break; case 1: /*Frequency control*/ @@ -223,41 +213,32 @@ void writegus(uint16_t addr, uint8_t val, void *p) case 2: /*Start addr high*/ gus->startx[gus->voice]=(gus->startx[gus->voice]&0xF807F)|(val<<7); gus->start[gus->voice]=(gus->start[gus->voice]&0x1F00FFFF)|(val<<16); -// printf("Write %i start %08X %08X\n",gus->voice,gus->start[gus->voice],gus->startx[gus->voice]); break; case 3: /*Start addr low*/ gus->start[gus->voice]=(gus->start[gus->voice]&0x1FFFFF00)|val; -// printf("Write %i start %08X %08X\n",gus->voice,gus->start[gus->voice],gus->startx[gus->voice]); break; case 4: /*End addr high*/ gus->endx[gus->voice]=(gus->endx[gus->voice]&0xF807F)|(val<<7); gus->end[gus->voice]=(gus->end[gus->voice]&0x1F00FFFF)|(val<<16); -// printf("Write %i end %08X %08X\n",gus->voice,gus->end[gus->voice],gus->endx[gus->voice]); break; case 5: /*End addr low*/ gus->end[gus->voice]=(gus->end[gus->voice]&0x1FFFFF00)|val; -// printf("Write %i end %08X %08X\n",gus->voice,gus->end[gus->voice],gus->endx[gus->voice]); break; case 0x6: /*Ramp frequency*/ gus->rfreq[gus->voice] = (int)( (double)((val & 63)*512)/(double)(1 << (3*(val >> 6)))); -// printf("RFREQ %02X %i %i %f\n",val,gus->voice,gus->rfreq[gus->voice],(double)(val & 63)/(double)(1 << (3*(val >> 6)))); break; case 0x9: /*Current volume*/ gus->curvol[gus->voice] = gus->rcur[gus->voice] = (gus->rcur[gus->voice] & ~(0xff << 6)) | (val << 6); -// printf("Vol %i is %04X\n",gus->voice,gus->curvol[gus->voice]); break; case 0xA: /*Current addr high*/ gus->cur[gus->voice]=(gus->cur[gus->voice]&0x1F00FFFF)|(val<<16); gus->curx[gus->voice]=(gus->curx[gus->voice]&0xF807F00)|((val<<7)<<8); -// gus->cur[gus->voice]=(gus->cur[gus->voice]&0x0F807F00)|((val<<7)<<8); -// printf("Write %i cur %08X\n",gus->voice,gus->cur[gus->voice],gus->curx[gus->voice]); break; case 0xB: /*Current addr low*/ gus->cur[gus->voice]=(gus->cur[gus->voice]&0x1FFFFF00)|val; -// printf("Write %i cur %08X\n",gus->voice,gus->cur[gus->voice],gus->curx[gus->voice]); break; case 0x42: /*DMA address low*/ @@ -268,21 +249,16 @@ gus->curx[gus->voice]=(gus->curx[gus->voice]&0xF807F00)|((val<<7)<<8); gus->addr=(gus->addr&0xFFF00)|val; break; case 0x45: /*Timer control*/ -// printf("Timer control %02X\n",val); gus->tctrl=val; break; } break; case 0x345: /*Global high*/ -// if (gus->global!=0x43 && gus->global!=0x44) printf("HWriting register %02X %02X %02X %04X:%04X %i %X\n",gus->global,gus->voice,val,CS,pc, ins, gus->rcur[1] >> 10); switch (gus->global) { case 0: /*Voice control*/ if (!(val&1) && gus->ctrl[gus->voice]&1) { -// printf("Voice on %i - start %05X end %05X freq %04X\n",gus->voice,gus->start[gus->voice],gus->end[gus->voice],gus->freq[gus->voice]); -// if (val&0x40) gus->cur[gus->voice]=gus->end[gus->voice]<<8; -// else gus->cur[gus->voice]=gus->start[gus->voice]<<8; } gus->ctrl[gus->voice] = val & 0x7f; @@ -298,52 +274,40 @@ gus->curx[gus->voice]=(gus->curx[gus->voice]&0xF807F00)|((val<<7)<<8); case 2: /*Start addr high*/ gus->startx[gus->voice]=(gus->startx[gus->voice]&0x07FFF)|(val<<15); gus->start[gus->voice]=(gus->start[gus->voice]&0x00FFFFFF)|((val&0x1F)<<24); -// printf("Write %i start %08X %08X %02X\n",gus->voice,gus->start[gus->voice],gus->startx[gus->voice],val); break; case 3: /*Start addr low*/ gus->startx[gus->voice]=(gus->startx[gus->voice]&0xFFF80)|(val&0x7F); gus->start[gus->voice]=(gus->start[gus->voice]&0x1FFF00FF)|(val<<8); -// printf("Write %i start %08X %08X\n",gus->voice,gus->start[gus->voice],gus->startx[gus->voice]); break; case 4: /*End addr high*/ gus->endx[gus->voice]=(gus->endx[gus->voice]&0x07FFF)|(val<<15); gus->end[gus->voice]=(gus->end[gus->voice]&0x00FFFFFF)|((val&0x1F)<<24); -// printf("Write %i end %08X %08X %02X\n",gus->voice,gus->end[gus->voice],gus->endx[gus->voice],val); break; case 5: /*End addr low*/ gus->endx[gus->voice]=(gus->endx[gus->voice]&0xFFF80)|(val&0x7F); gus->end[gus->voice]=(gus->end[gus->voice]&0x1FFF00FF)|(val<<8); -// printf("Write %i end %08X %08X\n",gus->voice,gus->end[gus->voice],gus->endx[gus->voice]); break; case 0x6: /*Ramp frequency*/ gus->rfreq[gus->voice] = (int)( (double)((val & 63) * (1 << 10))/(double)(1 << (3 * (val >> 6)))); -// pclog("Ramp freq %02X %i %i %f %i\n", val, gus->voice, gus->rfreq[gus->voice], (double)(val & 63)/(double)(1 << (3*(val >> 6))), ins); break; case 0x7: /*Ramp start*/ gus->rstart[gus->voice] = val << 14; -// pclog("Ramp start %04X\n", gus->rstart[gus->voice] >> 10); break; case 0x8: /*Ramp end*/ gus->rend[gus->voice] = val << 14; -// pclog("Ramp end %04X\n", gus->rend[gus->voice] >> 10); break; case 0x9: /*Current volume*/ gus->curvol[gus->voice] = gus->rcur[gus->voice] = (gus->rcur[gus->voice] & ~(0xff << 14)) | (val << 14); -// printf("Vol %i is %04X\n",gus->voice,gus->curvol[gus->voice]); break; case 0xA: /*Current addr high*/ gus->cur[gus->voice]=(gus->cur[gus->voice]&0x00FFFFFF)|((val&0x1F)<<24); gus->curx[gus->voice]=(gus->curx[gus->voice]&0x07FFF00)|((val<<15)<<8); -// printf("Write %i cur %08X %08X %02X\n",gus->voice,gus->cur[gus->voice],gus->curx[gus->voice],val); -// gus->cur[gus->voice]=(gus->cur[gus->voice]&0x007FFF00)|((val<<15)<<8); break; case 0xB: /*Current addr low*/ gus->cur[gus->voice]=(gus->cur[gus->voice]&0x1FFF00FF)|(val<<8); gus->curx[gus->voice]=(gus->curx[gus->voice]&0xFFF8000)|((val&0x7F)<<8); -// gus->cur[gus->voice]=(gus->cur[gus->voice]&0x0FFF8000)|((val&0x7F)<<8); -// printf("Write %i cur %08X %08X\n",gus->voice,gus->cur[gus->voice],gus->curx[gus->voice]); break; case 0xC: /*Pan*/ gus->pan_l[gus->voice] = 15 - (val & 0xf); @@ -355,7 +319,6 @@ gus->curx[gus->voice]=(gus->curx[gus->voice]&0xFFF8000)|((val&0x7F)<<8); gus->rampirqs[gus->voice] = ((val & 0xa0) == 0xa0) ? 1 : 0; if (gus->rampirqs[gus->voice] != old) pollgusirqs(gus); -// printf("Ramp control %02i %02X %02X %i\n",gus->voice,val,gus->rampirqs[gus->voice],ins); break; case 0xE: @@ -363,7 +326,6 @@ gus->curx[gus->voice]=(gus->curx[gus->voice]&0xFFF8000)|((val&0x7F)<<8); if (gus->voices>32) gus->voices=32; if (gus->voices<14) gus->voices=14; gus->global=val; -// printf("GUS voices %i\n",val&31); if (gus->voices < 14) gus->samp_latch = (int)(TIMER_USEC * (1000000.0 / 44100.0)); else @@ -373,7 +335,6 @@ gus->curx[gus->voice]=(gus->curx[gus->voice]&0xFFF8000)|((val&0x7F)<<8); case 0x41: /*DMA*/ if (val&1 && gus->dma != -1) { -// printf("DMA start! %05X %02X\n",gus->dmaaddr,val); if (val & 2) { c=0; @@ -391,7 +352,6 @@ gus->curx[gus->voice]=(gus->curx[gus->voice]&0xFFF8000)|((val&0x7F)<<8); if (dma_result & DMA_OVER) break; } -// printf("GUS->MEM Transferred %i bytes\n",c); gus->dmactrl=val&~0x40; if (val&0x20) gus->irqnext=1; } @@ -411,11 +371,9 @@ gus->curx[gus->voice]=(gus->curx[gus->voice]&0xFFF8000)|((val&0x7F)<<8); if (d & DMA_OVER) break; } -// printf("MEM->GUS Transferred %i bytes\n",c); gus->dmactrl=val&~0x40; if (val&0x20) gus->irqnext=1; } -// exit(-1); } break; @@ -442,24 +400,16 @@ gus->curx[gus->voice]=(gus->curx[gus->voice]&0xFFF8000)|((val&0x7F)<<8); gus->ad_status &= ~0x01; nmi = 0; } -// printf("Timer control %02X\n",val); -/* if ((val&4) && !(gus->tctrl&4)) - { - gus->t1=gus->t1l; - gus->t1on=1; - }*/ gus->tctrl=val; gus->sb_ctrl = val; break; case 0x46: /*Timer 1*/ gus->t1 = gus->t1l = val; gus->t1on = 1; -// printf("GUS timer 1 %i\n",val); break; case 0x47: /*Timer 2*/ gus->t2 = gus->t2l = val; gus->t2on = 1; -// printf("GUS timer 2 %i\n",val); break; case 0x4c: /*Reset*/ @@ -469,12 +419,10 @@ gus->curx[gus->voice]=(gus->curx[gus->voice]&0xFFF8000)|((val&0x7F)<<8); break; case 0x347: /*DRAM access*/ gus->ram[gus->addr]=val; -// pclog("GUS RAM write %05X %02X\n",gus->addr,val); gus->addr&=0xFFFFF; break; case 0x248: case 0x388: gus->adcommand = val; -// pclog("Setting ad command %02X %02X %p\n", val, gus->adcommand, &gus->adcommand); break; case 0x389: @@ -541,7 +489,6 @@ gus->curx[gus->voice]=(gus->curx[gus->voice]&0xFFF8000)|((val&0x7F)<<8); gus->sb_nmi = val & 0x80; } gus->latch_enable = 0; -// pclog("IRQ %i DMA %i\n", gus->irq, gus->dma); break; case 1: gus->gp1 = val; @@ -600,13 +547,11 @@ gus->curx[gus->voice]=(gus->curx[gus->voice]&0xFFF8000)|((val&0x7F)<<8); uint8_t readgus(uint16_t addr, void *p) { gus_t *gus = (gus_t *)p; - uint8_t val; -// /*if (addr!=0x246) */printf("Read GUS %04X %04X(%06X):%04X %02X\n",addr,CS,cs,pc,gus->global); + uint8_t val = 0xff; switch (addr) { case 0x340: /*MIDI status*/ val = gus->midi_status; -// pclog("Read MIDI status %02X\n", val); break; case 0x341: /*MIDI data*/ @@ -620,14 +565,12 @@ uint8_t readgus(uint16_t addr, void *p) val = gus->irqstatus & ~0x10; if (gus->ad_status & 0x19) val |= 0x10; -// pclog("Read IRQ status %02X\n", val); return val; case 0x24F: return 0; case 0x342: return gus->voice; case 0x343: return gus->global; case 0x344: /*Global low*/ -// /*if (gus->global!=0x43 && gus->global!=0x44) */printf("Reading register %02X %02X\n",gus->global,gus->voice); switch (gus->global) { case 0x82: /*Start addr high*/ @@ -644,7 +587,6 @@ uint8_t readgus(uint16_t addr, void *p) case 0x8F: /*IRQ status*/ val=gus->irqstatus2; -// pclog("Read IRQ status - %02X\n",val); gus->rampirqs[gus->irqstatus2&0x1F]=0; gus->waveirqs[gus->irqstatus2&0x1F]=0; pollgusirqs(gus); @@ -656,17 +598,12 @@ uint8_t readgus(uint16_t addr, void *p) case 0x0c: case 0x0d: case 0x0e: case 0x0f: val = 0xff; break; - -// default: -// fatal("Bad GUS global low read %02X\n",gus->global); } break; case 0x345: /*Global high*/ -// /*if (gus->global!=0x43 && gus->global!=0x44) */printf("HReading register %02X %02X\n",gus->global,gus->voice); switch (gus->global) { case 0x80: /*Voice control*/ -// pclog("Read voice control %02i %02X\n", gus->voice, gus->ctrl[gus->voice]|(gus->waveirqs[gus->voice]?0x80:0)); return gus->ctrl[gus->voice]|(gus->waveirqs[gus->voice]?0x80:0); case 0x82: /*Start addr high*/ @@ -675,7 +612,6 @@ uint8_t readgus(uint16_t addr, void *p) return gus->start[gus->voice]>>8; case 0x89: /*Current volume*/ -// pclog("Read current volume %i\n", gus->rcur[gus->voice] >> 14); return gus->rcur[gus->voice]>>14; case 0x8A: /*Current addr high*/ @@ -687,16 +623,13 @@ uint8_t readgus(uint16_t addr, void *p) return gus->pan_r[gus->voice]; case 0x8D: -// pclog("Read ramp control %02X %04X %08X %08X %08X\n",gus->rctrl[gus->voice]|(gus->rampirqs[gus->voice]?0x80:0),gus->rcur[gus->voice] >> 14,gus->rfreq[gus->voice],gus->rstart[gus->voice],gus->rend[gus->voice]); return gus->rctrl[gus->voice]|(gus->rampirqs[gus->voice]?0x80:0); case 0x8F: /*IRQ status*/ -// pclog("Read IRQ 1\n"); val=gus->irqstatus2; gus->rampirqs[gus->irqstatus2&0x1F]=0; gus->waveirqs[gus->irqstatus2&0x1F]=0; pollgusirqs(gus); -// pclog("Read IRQ status - %02X %i %i\n",val, gus->waveirqs[gus->irqstatus2&0x1F], gus->rampirqs[gus->irqstatus2&0x1F]); return val; case 0x41: /*DMA control*/ @@ -714,15 +647,11 @@ uint8_t readgus(uint16_t addr, void *p) case 0x0c: case 0x0d: case 0x0e: case 0x0f: val = 0xff; break; - -// default: -// fatal("Bad GUS global high read %02X\n",gus->global); } break; case 0x346: return 0xff; case 0x347: /*DRAM access*/ val=gus->ram[gus->addr]; -// pclog("GUS RAM read %05X %02X\n",gus->addr,val); gus->addr&=0xFFFFF; return val; case 0x349: return 0; @@ -753,19 +682,9 @@ uint8_t readgus(uint16_t addr, void *p) gus->sb_2xc &= 0x80; break; case 0x24e: -/* gus->ad_status |= 0x10; - if (gus->reg_ctrl & 0x80) - { - gus->reg_ctrl_r |= 0x80; - if (gus->sb_nmi) - nmi = 1; - else - picint(1 << gus->irq); - }*/ return gus->sb_2xe; case 0x248: case 0x388: -// pclog("Read ad_status %02X\n", gus->ad_status); if (gus->tctrl & GUS_TIMER_CTRL_AUTO) val = gus->sb_2xa; else @@ -785,12 +704,9 @@ uint8_t readgus(uint16_t addr, void *p) case 0x24A: val = gus->adcommand; -// pclog("Read ad command %02X %02X %p\n", gus->adcommand, val, &gus->adcommand); break; } -// printf("Bad GUS read %04X! %02X\n",addr,gus->global); -// exit(-1); return val; } @@ -799,13 +715,11 @@ void gus_poll_timer_1(void *p) gus_t *gus = (gus_t *)p; gus->timer_1 += (TIMER_USEC * 80); -// pclog("gus_poll_timer_1 %i %i %i %i %02X\n", gustime, gus->t1on, gus->t1, gus->t1l, gus->tctrl); if (gus->t1on) { gus->t1++; if (gus->t1 > 0xFF) { -// gus->t1on=0; gus->t1=gus->t1l; gus->ad_status |= 0x40; if (gus->tctrl&4) @@ -814,13 +728,11 @@ void gus_poll_timer_1(void *p) picint(1 << gus->irq); gus->ad_status |= 0x04; gus->irqstatus |= 0x04; -// pclog("GUS T1 IRQ!\n"); } } } if (gus->irqnext) { -// pclog("Take IRQ\n"); gus->irqnext=0; gus->irqstatus|=0x80; if (gus->irq != -1) @@ -834,13 +746,11 @@ void gus_poll_timer_2(void *p) gus_t *gus = (gus_t *)p; gus->timer_2 += (TIMER_USEC * 320); -// pclog("pollgus2 %i %i %i %i %02X\n", gustime, gus->t2on, gus->t2, gus->t2l, gus->tctrl); if (gus->t2on) { gus->t2++; if (gus->t2 > 0xFF) { -// gus->t2on=0; gus->t2=gus->t2l; gus->ad_status |= 0x20; if (gus->tctrl&8) @@ -849,13 +759,11 @@ void gus_poll_timer_2(void *p) picint(1 << gus->irq); gus->ad_status |= 0x02; gus->irqstatus |= 0x08; -// pclog("GUS T2 IRQ!\n"); } } } if (gus->irqnext) { -// pclog("Take IRQ\n"); gus->irqnext=0; gus->irqstatus|=0x80; if (gus->irq != -1) @@ -899,7 +807,6 @@ void gus_poll_wave(void *p) if ((gus->reset & 3) != 3) return; -//pclog("gus_poll_wave\n"); for (d=0;d<32;d++) { if (!(gus->ctrl[d] & 3)) @@ -929,10 +836,8 @@ void gus_poll_wave(void *p) v = (int16_t)(int8_t)((gus->ram[(gus->cur[d] >> 9) & 0xFFFFF] ^ 0x80) - 0x80); } -// pclog("Voice %i : %04X %05X %04X ", d, v, gus->cur[d] >> 9, gus->rcur[d] >> 10); if ((gus->rcur[d] >> 14) > 4095) v = (int16_t)(float)(v) * 24.0 * vol16bit[4095]; else v = (int16_t)(float)(v) * 24.0 * vol16bit[(gus->rcur[d]>>10) & 4095]; -// pclog("%f %04X\n", vol16bit[(gus->rcur[d]>>10) & 4095], v); gus->out_l += (v * gus->pan_l[d]) / 7; gus->out_r += (v * gus->pan_r[d]) / 7; @@ -959,7 +864,6 @@ void gus_poll_wave(void *p) { gus->waveirqs[d] = 1; update_irqs = 1; -// pclog("Causing wave IRQ %02X %i\n", gus->ctrl[d], d); } } } @@ -986,7 +890,6 @@ void gus_poll_wave(void *p) { gus->waveirqs[d] = 1; update_irqs = 1; -// pclog("Causing wave IRQ %02X %i\n", gus->ctrl[d], d); } } } @@ -1014,14 +917,12 @@ void gus_poll_wave(void *p) { gus->rampirqs[d] = 1; update_irqs = 1; -// pclog("Causing ramp IRQ %02X %i\n",gus->rctrl[d], d); } } } else { gus->rcur[d] += gus->rfreq[d]; -// if (d == 1) printf("RCUR+ %i %08X %08X %08X %08X\n",d,gus->rfreq[d],gus->rcur[d],gus->rstart[d],gus->rend[d]); if (gus->rcur[d] >= gus->rend[d]) { int diff = gus->rcur[d] - gus->rend[d]; @@ -1040,7 +941,6 @@ void gus_poll_wave(void *p) { gus->rampirqs[d] = 1; update_irqs = 1; -// pclog("Causing ramp IRQ %02X %i\n",gus->rctrl[d], d); } } } @@ -1087,7 +987,7 @@ void *gus_init() } for (c=4095;c>=0;c--) { - vol16bit[c]=out;//(float)c/4095.0;//out; + vol16bit[c]=out; out/=1.002709201; /* 0.0235 dB Steps */ } diff --git a/src/sound_gus.h b/src/SOUND/snd_gus.h similarity index 100% rename from src/sound_gus.h rename to src/SOUND/snd_gus.h diff --git a/src/SOUND/snd_mpu401.c b/src/SOUND/snd_mpu401.c new file mode 100644 index 000000000..e03211f59 --- /dev/null +++ b/src/SOUND/snd_mpu401.c @@ -0,0 +1,881 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Roland MPU-401 emulation. + * + * Version: @(#)sound_mpu401.c 1.0.1 2017/06/19 + * + * Author: Sarah Walker, + * DOSBox Team, + * Miran Grca, + * TheCollector1995, + * Copyright 2008-2017 Sarah Walker. + * Copyright 2008-2017 DOSBox Team. + * Copyright 2016-2017 Miran Grca. + * Copyright 2016-2017 TheCollector1995. + */ + +#include "../ibm.h" +#include "../device.h" +#include "../io.h" +#include "../pic.h" +#include "../timer.h" +#include "midi.h" +#include "sound.h" +#include "snd_mpu401.h" + +#include +#include + +enum +{ + STATUS_OUTPUT_NOT_READY = 0x40, + STATUS_INPUT_NOT_READY = 0x80 +}; + +static void MPU401_WriteCommand(mpu_t *mpu, uint8_t val); +static void MPU401_EOIHandlerDispatch(void *p); + +int mpu401_standalone_enable = 0; + +static int mpu401_event_callback = 0; +static int mpu401_eoi_callback = 0; +static int mpu401_reset_callback = 0; + +#ifdef ENABLE_MPU401_LOG +static int mpu401_do_log = 1; +static char logfmt[512]; +#endif + +static void +mpulog(const char *fmt, ...) +{ +#ifdef ENABLE_MPU401_LOG + va_list ap; + + if (mpu401_do_log) { + va_start(ap, fmt); + memset(logfmt, 0, 512); + strcpy(logfmt, "MPU-401: "); + strcpy(logfmt + strlen(logfmt), fmt); + vprintf(logfmt, ap); + va_end(ap); + } +#endif +} +#define pclog mpulog + + +static void QueueByte(mpu_t *mpu, uint8_t data) +{ + if (mpu->state.block_ack) + { + mpu->state.block_ack=0; + return; + } + + if (mpu->queue_used == 0 && mpu->intelligent) + { + mpu->state.irq_pending=1; + //PIC_ActivateIRQ(mpu->irq); + picint(1 << mpu->irq); + } + if (mpu->queue_used < MPU401_QUEUE) + { + int pos = mpu->queue_used+mpu->queue_pos; + + if (mpu->queue_pos >= MPU401_QUEUE) + mpu->queue_pos -= MPU401_QUEUE; + + if (pos>=MPU401_QUEUE) + pos-=MPU401_QUEUE; + + mpu->queue_used++; + mpu->queue[pos]=data; + } + else + pclog("MPU401:Data queue full\n"); +} + +static void ClrQueue(mpu_t *mpu) +{ + mpu->queue_used=0; + mpu->queue_pos=0; +} + +static void MPU401_Reset(mpu_t *mpu) +{ + uint8_t i; + + picintc(1 << mpu->irq); + mpu->mode=(mpu->intelligent ? M_INTELLIGENT : M_UART); + mpu->state.eoi_scheduled=0; + mpu->state.wsd=0; + mpu->state.wsm=0; + mpu->state.conductor=0; + mpu->state.cond_req=0; + mpu->state.cond_set=0; + mpu->state.playing=0; + mpu->state.run_irq=0; + mpu->state.irq_pending=0; + mpu->state.cmask=0xff; + mpu->state.amask=mpu->state.tmask=0; + mpu->state.midi_mask=0xffff; + mpu->state.data_onoff=0; + mpu->state.command_byte=0; + mpu->state.block_ack=0; + mpu->clock.tempo=mpu->clock.old_tempo=100; + mpu->clock.timebase=mpu->clock.old_timebase=120; + mpu->clock.tempo_rel=mpu->clock.old_tempo_rel=40; + mpu->clock.tempo_grad=0; + mpu->clock.clock_to_host=0; + mpu->clock.cth_rate=60; + mpu->clock.cth_counter=0; + ClrQueue(mpu); + mpu->state.req_mask=0; + mpu->condbuf.counter=0; + mpu->condbuf.type=T_OVERFLOW; + for (i=0;i<8;i++) {mpu->playbuf[i].type=T_OVERFLOW;mpu->playbuf[i].counter=0;} +} + +static void MPU401_ResetDone(void *p) +{ + mpu_t *mpu = (mpu_t *)p; + + pclog("MPU-401 reset callback\n"); + + mpu401_reset_callback = 0; + + mpu->state.reset=0; + if (mpu->state.cmd_pending) + { + MPU401_WriteCommand(mpu, mpu->state.cmd_pending-1); + mpu->state.cmd_pending=0; + } +} + +static void MPU401_WriteCommand(mpu_t *mpu, uint8_t val) +{ + uint8_t i; + + if (mpu->state.reset) + { + mpu->state.cmd_pending=val+1; + return; + } + + if (val<=0x2f) + { + switch (val&3) + { /* MIDI stop, start, continue */ + case 1: {midi_write(0xfc);break;} + case 2: {midi_write(0xfa);break;} + case 3: {midi_write(0xfb);break;} + } +// if (val&0x20) LOG(LOG_MISC,LOG_ERROR)("MPU-401:Unhandled Recording Command %x",(int)val); + switch (val&0xc) + { + case 0x4: /* Stop */ + mpu->state.playing=0; + mpu401_event_callback = 0; + for (i=0xb0;i<0xbf;i++) + { /* All notes off */ + midi_write(i); + midi_write(0x7b); + midi_write(0); + } + break; + case 0x8: /* Play */ +// LOG(LOG_MISC,LOG_NORMAL)("MPU-401:Intelligent mode playback started"); + mpu->state.playing=1; + mpu401_event_callback = (MPU401_TIMECONSTANT / (mpu->clock.tempo*mpu->clock.timebase)) * 1000 * TIMER_USEC; + ClrQueue(mpu); + break; + } + } + else if (val>=0xa0 && val<=0xa7) + { /* Request play counter */ + if (mpu->state.cmask&(1<<(val&7))) QueueByte(mpu, mpu->playbuf[val&7].counter); + } + else if (val>=0xd0 && val<=0xd7) + { /* Send data */ + mpu->state.old_chan=mpu->state.channel; + mpu->state.channel=val&7; + mpu->state.wsd=1; + mpu->state.wsm=0; + mpu->state.wsd_start=1; + } + else + switch (val) + { + case 0xdf: /* Send system message */ + mpu->state.wsd=0; + mpu->state.wsm=1; + mpu->state.wsd_start=1; + break; + case 0x8e: /* Conductor */ + mpu->state.cond_set=0; + break; + case 0x8f: + mpu->state.cond_set=1; + break; + case 0x94: /* Clock to host */ + mpu->clock.clock_to_host=0; + break; + case 0x95: + mpu->clock.clock_to_host=1; + break; + case 0xc2: /* Internal timebase */ + mpu->clock.timebase=48; + break; + case 0xc3: + mpu->clock.timebase=72; + break; + case 0xc4: + mpu->clock.timebase=96; + break; + case 0xc5: + mpu->clock.timebase=120; + break; + case 0xc6: + mpu->clock.timebase=144; + break; + case 0xc7: + mpu->clock.timebase=168; + break; + case 0xc8: + mpu->clock.timebase=192; + break; + /* Commands with data byte */ + case 0xe0: case 0xe1: case 0xe2: case 0xe4: case 0xe6: + case 0xe7: case 0xec: case 0xed: case 0xee: case 0xef: + mpu->state.command_byte=val; + break; + /* Commands 0xa# returning data */ + case 0xab: /* Request and clear recording counter */ + QueueByte(mpu, MSG_MPU_ACK); + QueueByte(mpu, 0); + return; + case 0xac: /* Request version */ + QueueByte(mpu, MSG_MPU_ACK); + QueueByte(mpu, MPU401_VERSION); + return; + case 0xad: /* Request revision */ + QueueByte(mpu, MSG_MPU_ACK); + QueueByte(mpu, MPU401_REVISION); + return; + case 0xaf: /* Request tempo */ + QueueByte(mpu, MSG_MPU_ACK); + QueueByte(mpu, mpu->clock.tempo); + return; + case 0xb1: /* Reset relative tempo */ + mpu->clock.tempo_rel=40; + break; + case 0xb9: /* Clear play map */ + case 0xb8: /* Clear play counters */ + for (i=0xb0;i<0xbf;i++) + { /* All notes off */ + midi_write(i); + midi_write(0x7b); + midi_write(0); + } + for (i=0;i<8;i++) + { + mpu->playbuf[i].counter=0; + mpu->playbuf[i].type=T_OVERFLOW; + } + mpu->condbuf.counter=0; + mpu->condbuf.type=T_OVERFLOW; + if (!(mpu->state.conductor=mpu->state.cond_set)) mpu->state.cond_req=0; + mpu->state.amask=mpu->state.tmask; + mpu->state.req_mask=0; + mpu->state.irq_pending=1; + break; + case 0xff: /* Reset MPU-401 */ + pclog("MPU-401:Reset %X\n",val); + mpu401_reset_callback = MPU401_RESETBUSY * 33 * TIMER_USEC; + mpu->state.reset=1; + MPU401_Reset(mpu); +#if 0 + if (mpu->mode==M_UART) return;//do not send ack in UART mode +#endif + break; + case 0x3f: /* UART mode */ + pclog("MPU-401:Set UART mode %X\n",val); + mpu->mode=M_UART; + break; + default:; + //LOG(LOG_MISC,LOG_NORMAL)("MPU-401:Unhandled command %X",val); + } + QueueByte(mpu, MSG_MPU_ACK); +} + +static void MPU401_WriteData(mpu_t *mpu, uint8_t val) +{ + if (mpu->mode==M_UART) {midi_write(val); return;} + + switch (mpu->state.command_byte) + { /* 0xe# command data */ + case 0x00: + break; + case 0xe0: /* Set tempo */ + mpu->state.command_byte=0; + mpu->clock.tempo=val; + return; + case 0xe1: /* Set relative tempo */ + mpu->state.command_byte=0; + if (val!=0x40) //default value + pclog("MPU-401:Relative tempo change not implemented\n"); + return; + case 0xe7: /* Set internal clock to host interval */ + mpu->state.command_byte=0; + mpu->clock.cth_rate=val>>2; + return; + case 0xec: /* Set active track mask */ + mpu->state.command_byte=0; + mpu->state.tmask=val; + return; + case 0xed: /* Set play counter mask */ + mpu->state.command_byte=0; + mpu->state.cmask=val; + return; + case 0xee: /* Set 1-8 MIDI channel mask */ + mpu->state.command_byte=0; + mpu->state.midi_mask&=0xff00; + mpu->state.midi_mask|=val; + return; + case 0xef: /* Set 9-16 MIDI channel mask */ + mpu->state.command_byte=0; + mpu->state.midi_mask&=0x00ff; + mpu->state.midi_mask|=((uint16_t)val)<<8; + return; + //case 0xe2: /* Set graduation for relative tempo */ + //case 0xe4: /* Set metronome */ + //case 0xe6: /* Set metronome measure length */ + default: + mpu->state.command_byte=0; + return; + } + static int length,cnt,posd; + if (mpu->state.wsd) + { /* Directly send MIDI message */ + if (mpu->state.wsd_start) + { + mpu->state.wsd_start=0; + cnt=0; + switch (val&0xf0) { + case 0xc0:case 0xd0: + mpu->playbuf[mpu->state.channel].value[0]=val; + length=2; + break; + case 0x80:case 0x90:case 0xa0:case 0xb0:case 0xe0: + mpu->playbuf[mpu->state.channel].value[0]=val; + length=3; + break; + case 0xf0: + //pclog("MPU-401:Illegal WSD byte\n"); + mpu->state.wsd=0; + mpu->state.channel=mpu->state.old_chan; + return; + default: /* MIDI with running status */ + cnt++; + midi_write(mpu->playbuf[mpu->state.channel].value[0]); + } + } + if (cntstate.wsd=0; + mpu->state.channel=mpu->state.old_chan; + } + return; + } + if (mpu->state.wsm) + { /* Directly send system message */ + if (val==MSG_EOX) {midi_write(MSG_EOX);mpu->state.wsm=0;return;} + if (mpu->state.wsd_start) { + mpu->state.wsd_start=0; + cnt=0; + switch (val) + { + case 0xf2:{ length=3; break;} + case 0xf3:{ length=2; break;} + case 0xf6:{ length=1; break;} + case 0xf0:{ length=0; break;} + default: + length=0; + } + } + if (!length || cntstate.wsm=0; + return; + } + if (mpu->state.cond_req) + { /* Command */ + switch (mpu->state.data_onoff) { + case -1: + return; + case 0: /* Timing byte */ + mpu->condbuf.vlength=0; + if (val<0xf0) mpu->state.data_onoff++; + else { + mpu->state.data_onoff=-1; + MPU401_EOIHandlerDispatch(mpu); + return; + } + if (val==0) mpu->state.send_now=1; + else mpu->state.send_now=0; + mpu->condbuf.counter=val; + break; + case 1: /* Command byte #1 */ + mpu->condbuf.type=T_COMMAND; + if (val==0xf8 || val==0xf9) mpu->condbuf.type=T_OVERFLOW; + mpu->condbuf.value[mpu->condbuf.vlength]=val; + mpu->condbuf.vlength++; + if ((val&0xf0)!=0xe0) MPU401_EOIHandlerDispatch(mpu); + else mpu->state.data_onoff++; + break; + case 2:/* Command byte #2 */ + mpu->condbuf.value[mpu->condbuf.vlength]=val; + mpu->condbuf.vlength++; + MPU401_EOIHandlerDispatch(mpu); + break; + } + return; + } + switch (mpu->state.data_onoff) + { /* Data */ + case -1: + return; + case 0: /* Timing byte */ + if (val<0xf0) mpu->state.data_onoff=1; + else { + mpu->state.data_onoff=-1; + MPU401_EOIHandlerDispatch(mpu); + return; + } + if (val==0) mpu->state.send_now=1; + else mpu->state.send_now=0; + mpu->playbuf[mpu->state.channel].counter=val; + break; + case 1: /* MIDI */ + mpu->playbuf[mpu->state.channel].vlength++; + posd=mpu->playbuf[mpu->state.channel].vlength; + if (posd==1) { + switch (val&0xf0) { + case 0xf0: /* System message or mark */ + if (val>0xf7) { + mpu->playbuf[mpu->state.channel].type=T_MARK; + mpu->playbuf[mpu->state.channel].sys_val=val; + length=1; + } else { + //LOG(LOG_MISC,LOG_ERROR)("MPU-401:Illegal message"); + mpu->playbuf[mpu->state.channel].type=T_MIDI_SYS; + mpu->playbuf[mpu->state.channel].sys_val=val; + length=1; + } + break; + case 0xc0: case 0xd0: /* MIDI Message */ + mpu->playbuf[mpu->state.channel].type=T_MIDI_NORM; + length=mpu->playbuf[mpu->state.channel].length=2; + break; + case 0x80: case 0x90: case 0xa0: case 0xb0: case 0xe0: + mpu->playbuf[mpu->state.channel].type=T_MIDI_NORM; + length=mpu->playbuf[mpu->state.channel].length=3; + break; + default: /* MIDI data with running status */ + posd++; + mpu->playbuf[mpu->state.channel].vlength++; + mpu->playbuf[mpu->state.channel].type=T_MIDI_NORM; + length=mpu->playbuf[mpu->state.channel].length; + break; + } + } + if (!(posd==1 && val>=0xf0)) mpu->playbuf[mpu->state.channel].value[posd-1]=val; + if (posd==length) MPU401_EOIHandlerDispatch(mpu); + } +} + +static void MPU401_IntelligentOut(mpu_t *mpu, uint8_t chan) +{ + uint8_t val; + uint8_t i; + switch (mpu->playbuf[chan].type) + { + case T_OVERFLOW: + break; + case T_MARK: + val=mpu->playbuf[chan].sys_val; + if (val==0xfc) + { + midi_write(val); + mpu->state.amask&=~(1<state.req_mask&=~(1<playbuf[chan].vlength;i++) + midi_write(mpu->playbuf[chan].value[i]); + break; + default: + break; + } +} + +static void UpdateTrack(mpu_t *mpu, uint8_t chan) +{ + MPU401_IntelligentOut(mpu, chan); + if (mpu->state.amask&(1<playbuf[chan].vlength=0; + mpu->playbuf[chan].type=T_OVERFLOW; + mpu->playbuf[chan].counter=0xf0; + mpu->state.req_mask|=(1<state.amask==0 && !mpu->state.conductor) mpu->state.req_mask|=(1<<12); + } +} + +static void UpdateConductor(mpu_t *mpu) +{ + if (mpu->condbuf.value[0]==0xfc) + { + mpu->condbuf.value[0]=0; + mpu->state.conductor=0; + mpu->state.req_mask&=~(1<<9); + if (mpu->state.amask==0) mpu->state.req_mask|=(1<<12); + return; + } + mpu->condbuf.vlength=0; + mpu->condbuf.counter=0xf0; + mpu->state.req_mask|=(1<<9); +} + +//Updates counters and requests new data on "End of Input" +static void MPU401_EOIHandler(void *p) +{ + mpu_t *mpu = (mpu_t *)p; + uint8_t i; + + pclog("MPU-401 end of input callback\n"); + + mpu401_eoi_callback = 0; + mpu->state.eoi_scheduled=0; + if (mpu->state.send_now) + { + mpu->state.send_now=0; + if (mpu->state.cond_req) UpdateConductor(mpu); + else UpdateTrack(mpu, mpu->state.channel); + } + mpu->state.irq_pending=0; + if (!mpu->state.playing || !mpu->state.req_mask) return; + i=0; + do { + if (mpu->state.req_mask&(1<state.req_mask&=~(1<state.send_now) + { + mpu->state.eoi_scheduled=1; + mpu401_eoi_callback = 60 * TIMER_USEC; /* Possible a bit longer */ + } + else if (!mpu->state.eoi_scheduled) + MPU401_EOIHandler(mpu); +} + +static void imf_write(uint16_t addr, uint8_t val, void *p) +{ + pclog("IMF:Wr %4X,%X\n", addr, val); +} + +uint8_t MPU401_ReadData(mpu_t *mpu) +{ + uint8_t ret; + + ret = MSG_MPU_ACK; + if (mpu->queue_used) + { + if (mpu->queue_pos>=MPU401_QUEUE) mpu->queue_pos-=MPU401_QUEUE; + ret=mpu->queue[mpu->queue_pos]; + mpu->queue_pos++;mpu->queue_used--; + } + if (!mpu->intelligent) return ret; + + if (mpu->queue_used == 0) picintc(1 << mpu->irq); + + if (ret>=0xf0 && ret<=0xf7) + { /* MIDI data request */ + mpu->state.channel=ret&7; + mpu->state.data_onoff=0; + mpu->state.cond_req=0; + } + if (ret==MSG_MPU_COMMAND_REQ) + { + mpu->state.data_onoff=0; + mpu->state.cond_req=1; + if (mpu->condbuf.type!=T_OVERFLOW) + { + mpu->state.block_ack=1; + MPU401_WriteCommand(mpu, mpu->condbuf.value[0]); + if (mpu->state.command_byte) MPU401_WriteData(mpu, mpu->condbuf.value[1]); + } + mpu->condbuf.type=T_OVERFLOW; + } + if (ret==MSG_MPU_END || ret==MSG_MPU_CLOCK || ret==MSG_MPU_ACK) { + mpu->state.data_onoff=-1; + MPU401_EOIHandlerDispatch(mpu); + } + + return ret; +} + +static void mpu401_write(uint16_t addr, uint8_t val, void *p) +{ + mpu_t *mpu = (mpu_t *)p; + + /* pclog("MPU401 Write Port %04X, val %x\n", addr, val); */ + + switch (addr & 1) + { + case 0: /*Data*/ + MPU401_WriteData(mpu, val); + pclog("Write Data (0x330) %X\n", val); + break; + + case 1: /*Command*/ + MPU401_WriteCommand(mpu, val); + pclog("Write Command (0x331) %x\n", val); + break; + } +} + +static uint8_t mpu401_read(uint16_t addr, void *p) +{ + mpu_t *mpu = (mpu_t *)p; + uint8_t ret; + + switch (addr & 1) + { + case 0: //Read Data + ret = MPU401_ReadData(mpu); + pclog("Read Data (0x330) %X\n", ret); + break; + + case 1: //Read Status + ret = 0x3f; /* Bits 6 and 7 clear */ + if (mpu->state.cmd_pending) ret|=STATUS_OUTPUT_NOT_READY; + if (!mpu->queue_used) ret|=STATUS_INPUT_NOT_READY; + pclog("Read Status (0x331) %x\n", ret); + break; + } + /* pclog("MPU401 Read Port %04X, ret %x\n", addr, ret); */ + return ret; +} + + +static void MPU401_Event(void *p) +{ + mpu_t *mpu = (mpu_t *)p; + uint8_t i; + int new_time; + + pclog("MPU-401 event callback\n"); + + if (mpu->mode==M_UART) + { + mpu401_event_callback = 0; + return; + } + if (mpu->state.irq_pending) goto next_event; + for (i=0;i<8;i++) { /* Decrease counters */ + if (mpu->state.amask&(1<playbuf[i].counter--; + if (mpu->playbuf[i].counter<=0) UpdateTrack(mpu, i); + } + } + if (mpu->state.conductor) { + mpu->condbuf.counter--; + if (mpu->condbuf.counter<=0) UpdateConductor(mpu); + } + if (mpu->clock.clock_to_host) { + mpu->clock.cth_counter++; + if (mpu->clock.cth_counter >= mpu->clock.cth_rate) { + mpu->clock.cth_counter=0; + mpu->state.req_mask|=(1<<13); + } + } + if (!mpu->state.irq_pending && mpu->state.req_mask) MPU401_EOIHandler(mpu); +next_event: + /* mpu401_event_callback = 0; */ + new_time = (mpu->clock.tempo * mpu->clock.timebase); + if (new_time == 0) + { + mpu401_event_callback = 0; + return; + } + else + { + mpu401_event_callback += (MPU401_TIMECONSTANT/new_time) * 1000 * TIMER_USEC; + pclog("Next event after %i us (time constant: %i)\n", (int) ((MPU401_TIMECONSTANT/new_time) * 1000 * TIMER_USEC), (int) MPU401_TIMECONSTANT); + } +} + +void mpu401_init(mpu_t *mpu, uint16_t addr, int irq, int mode) +{ +#if 0 + if (mode != M_INTELLIGENT) + { + mpu401_uart_init(mpu, addr); + return; + } +#endif + + mpu->status = STATUS_INPUT_NOT_READY; + mpu->irq = irq; + mpu->queue_used = 0; + mpu->queue_pos = 0; + mpu->mode = M_UART; + + mpu->intelligent = (mode == M_INTELLIGENT) ? 1 : 0; + pclog("Starting as %s (mode is %s)\n", mpu->intelligent ? "INTELLIGENT" : "UART", (mode == M_INTELLIGENT) ? "INTELLIGENT" : "UART"); + + mpu401_event_callback = 0; + mpu401_eoi_callback = 0; + mpu401_reset_callback = 0; + + io_sethandler(addr, 0x0002, mpu401_read, NULL, NULL, mpu401_write, NULL, NULL, mpu); + io_sethandler(0x2A20, 0x0010, NULL, NULL, NULL, imf_write, NULL, NULL, mpu); + timer_add(MPU401_Event, &mpu401_event_callback, &mpu401_event_callback, mpu); + timer_add(MPU401_EOIHandler, &mpu401_eoi_callback, &mpu401_eoi_callback, mpu); + timer_add(MPU401_ResetDone, &mpu401_reset_callback, &mpu401_reset_callback, mpu); + + MPU401_Reset(mpu); +} + +void mpu401_device_add(void) +{ + char *n; + + if (!mpu401_standalone_enable) + { + return; + } + + n = sound_card_get_internal_name(sound_card_current); + if (n != NULL) + { + if (!strcmp(n, "sb16") || !strcmp(n, "sbawe32")) + { + return; + } + } + + device_add(&mpu401_device); +} + +void *mpu401_standalone_init() +{ + mpu_t *mpu; + + mpu = malloc(sizeof(mpu_t)); + memset(mpu, 0, sizeof(mpu_t)); + + pclog("mpu_init\n"); + mpu401_init(mpu, device_get_config_hex16("base"), device_get_config_int("irq"), device_get_config_int("mode")); + + return mpu; +} + +void mpu401_standalone_close(void *p) +{ + mpu_t *mpu = (mpu_t *)p; + + free(mpu); +} + +static device_config_t mpu401_standalone_config[] = +{ + { + "base", "MPU-401 Address", CONFIG_HEX16, "", 0x330, + { + { + "0x300", 0x300 + }, + { + "0x330", 0x330 + }, + { + "" + } + } + }, + { + "irq", "MPU-401 IRQ", CONFIG_SELECTION, "", 9, + { + { + "IRQ 9", 9 + }, + { + "IRQ 3", 3 + }, + { + "IRQ 4", 4 + }, + { + "IRQ 5", 5 + }, + { + "IRQ 7", 7 + }, + { + "IRQ 10", 10 + }, + { + "" + } + } + }, + { + "mode", "Mode", CONFIG_SELECTION, "", 1, + { + { + "UART", M_UART + }, + { + "Intelligent", M_INTELLIGENT + }, + { + "" + } + } + }, + { + "", "", -1 + } +}; + +device_t mpu401_device = +{ + "MPU-401 (Standalone)", + 0, + mpu401_standalone_init, + mpu401_standalone_close, + NULL, + NULL, + NULL, + NULL, + mpu401_standalone_config +}; diff --git a/src/SOUND/snd_mpu401.h b/src/SOUND/snd_mpu401.h new file mode 100644 index 000000000..41c1e9240 --- /dev/null +++ b/src/SOUND/snd_mpu401.h @@ -0,0 +1,94 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Roland MPU-401 emulation. + * + * Version: @(#)sound_mpu401.h 1.0.0 2017/05/30 + * + * Author: Sarah Walker, + * DOSBox Team, + * Miran Grca, + * TheCollector1995, + * Copyright 2008-2017 Sarah Walker. + * Copyright 2008-2017 DOSBox Team. + * Copyright 2016-2017 Miran Grca. + * Copyright 2016-2017 TheCollector1995. + */ + +#define MPU401_VERSION 0x15 +#define MPU401_REVISION 0x01 +#define MPU401_QUEUE 32 +#define MPU401_TIMECONSTANT (60000000/1000.0f) +#define MPU401_RESETBUSY 27.0f + +typedef enum MpuMode { M_UART,M_INTELLIGENT } MpuMode; +typedef enum MpuDataType {T_OVERFLOW,T_MARK,T_MIDI_SYS,T_MIDI_NORM,T_COMMAND} MpuDataType; + +/* Messages sent to MPU-401 from host */ +#define MSG_EOX 0xf7 +#define MSG_OVERFLOW 0xf8 +#define MSG_MARK 0xfc + +/* Messages sent to host from MPU-401 */ +#define MSG_MPU_OVERFLOW 0xf8 +#define MSG_MPU_COMMAND_REQ 0xf9 +#define MSG_MPU_END 0xfc +#define MSG_MPU_CLOCK 0xfd +#define MSG_MPU_ACK 0xfe + +typedef struct mpu_t +{ + int uart_mode; + uint8_t rx_data; + int intelligent; + MpuMode mode; + int irq; + uint8_t status; + uint8_t queue[MPU401_QUEUE]; + int queue_pos,queue_used; + struct track + { + int counter; + uint8_t value[8],sys_val; + uint8_t vlength,length; + MpuDataType type; + } playbuf[8],condbuf; + struct { + int conductor,cond_req,cond_set, block_ack; + int playing,reset; + int wsd,wsm,wsd_start; + int run_irq,irq_pending; + int send_now; + int eoi_scheduled; + int data_onoff; + uint32_t command_byte,cmd_pending; + uint8_t tmask,cmask,amask; + uint16_t midi_mask; + uint16_t req_mask; + uint8_t channel,old_chan; + } state; + struct { + uint8_t timebase,old_timebase; + uint8_t tempo,old_tempo; + uint8_t tempo_rel,old_tempo_rel; + uint8_t tempo_grad; + uint8_t cth_rate,cth_counter; + int clock_to_host,cth_active; + } clock; +} mpu_t; + +uint8_t MPU401_ReadData(mpu_t *mpu); + +void mpu401_init(mpu_t *mpu, uint16_t addr, int irq, int mode); + +extern int mpu401_standalone_enable; + +void mpu401_device_add(void); +device_t mpu401_device; + +void mpu401_uart_init(mpu_t *mpu, uint16_t addr); diff --git a/src/sound_opl.c b/src/SOUND/snd_opl.c similarity index 92% rename from src/sound_opl.c rename to src/SOUND/snd_opl.c index 28647f6dc..c5ccc6070 100644 --- a/src/sound_opl.c +++ b/src/SOUND/snd_opl.c @@ -3,11 +3,13 @@ */ #include #include -#include "ibm.h" -#include "io.h" +#include "../ibm.h" +#include "../io.h" +#include "../timer.h" #include "sound.h" -#include "sound_opl.h" -#include "sound_dbopl.h" +#include "snd_opl.h" +#include "snd_dbopl.h" + /*Interfaces between PCem and the actual OPL emulator*/ @@ -86,8 +88,8 @@ void opl2_update2(opl_t *opl) opl2_update(1, &opl->buffer[opl->pos*2 + 1], sound_pos_global - opl->pos); for (; opl->pos < sound_pos_global; opl->pos++) { - opl->filtbuf[0] = opl->buffer[opl->pos*2] = (opl->buffer[opl->pos*2] / 4) + ((opl->filtbuf[0] * 11) / 16); - opl->filtbuf[1] = opl->buffer[opl->pos*2+1] = (opl->buffer[opl->pos*2+1] / 4) + ((opl->filtbuf[1] * 11) / 16); + opl->filtbuf[0] = opl->buffer[opl->pos*2] = (opl->buffer[opl->pos*2] / 2); + opl->filtbuf[1] = opl->buffer[opl->pos*2+1] = (opl->buffer[opl->pos*2+1] / 2); } } } @@ -99,8 +101,8 @@ void opl3_update2(opl_t *opl) opl3_update(0, &opl->buffer[opl->pos*2], sound_pos_global - opl->pos); for (; opl->pos < sound_pos_global; opl->pos++) { - opl->filtbuf[0] = opl->buffer[opl->pos*2] = (opl->buffer[opl->pos*2] / 4) + ((opl->filtbuf[0] * 11) / 16); - opl->filtbuf[1] = opl->buffer[opl->pos*2+1] = (opl->buffer[opl->pos*2+1] / 4) + ((opl->filtbuf[1] * 11) / 16); + opl->filtbuf[0] = opl->buffer[opl->pos*2] = (opl->buffer[opl->pos*2] / 2); + opl->filtbuf[1] = opl->buffer[opl->pos*2+1] = (opl->buffer[opl->pos*2+1] / 2); } } } diff --git a/src/sound_opl.h b/src/SOUND/snd_opl.h similarity index 100% rename from src/sound_opl.h rename to src/SOUND/snd_opl.h diff --git a/src/sound_pas16.c b/src/SOUND/snd_pas16.c similarity index 95% rename from src/sound_pas16.c rename to src/SOUND/snd_pas16.c index cc5a23538..e91b7a09a 100644 --- a/src/sound_pas16.c +++ b/src/SOUND/snd_pas16.c @@ -1,17 +1,17 @@ #include -#include "ibm.h" - -#include "device.h" -#include "dma.h" -#include "filters.h" -#include "io.h" -#include "pic.h" -#include "pit.h" +#include "../ibm.h" +#include "../io.h" +#include "../pic.h" +#include "../pit.h" +#include "../dma.h" +#include "../timer.h" +#include "../device.h" #include "sound.h" -#include "sound_opl.h" -#include "sound_pas16.h" -#include "sound_sb_dsp.h" -#include "timer.h" +#include "snd_opl.h" +#include "snd_pas16.h" +#include "snd_sb_dsp.h" +#include "filters.h" + /* Original PAS uses 2 x OPL2 @@ -149,7 +149,7 @@ static int pas16_sb_dmas[8] = {0, 1, 2, 3}; enum { PAS16_INT_SAMP = 0x04, - PAS16_INT_PCM = 0x08, + PAS16_INT_PCM = 0x08 }; enum @@ -260,6 +260,10 @@ static uint8_t pas16_in(uint16_t port, void *p) case 0xff8b: /*Master mode read*/ temp = 0x20 | 0x10 | 0x01; /*AT bus, XT/AT timing*/ break; + + default: + temp = 0xff; + break; } /* if (port != 0x388 && port != 0x389 && port != 0xb8b) */pclog("pas16_in : port %04X return %02X %04X:%04X\n", port, temp, CS,cpu_state.pc); /* if (CS == 0x1FF4 && pc == 0x0585) @@ -289,7 +293,6 @@ static void pas16_out(uint16_t port, uint8_t val, void *p) case 0xb89: pas16->irq_stat &= ~val; -// pas16_update_irqs(); break; case 0xb8a: @@ -299,7 +302,6 @@ static void pas16_out(uint16_t port, uint8_t val, void *p) case 0xb8b: pas16->irq_ena = val; -// pas16_update_irqs(); break; case 0xf88: @@ -490,9 +492,8 @@ static void pas16_pit_out(uint16_t port, uint8_t val, void *p) static uint8_t pas16_pit_in(uint16_t port, void *p) { pas16_t *pas16 = (pas16_t *)p; - uint8_t temp; + uint8_t temp = 0xff; int t = port & 3; -// printf("Read PIT %04X ",addr); switch (port & 3) { case 0: case 1: case 2: /*Timers*/ @@ -538,7 +539,6 @@ static uint8_t pas16_pit_in(uint16_t port, void *p) temp = pas16->pit.ctrl; break; } -// printf("%02X %i %i %04X:%04X\n",temp,pit.rm[addr&3],pit.wp,cs>>4,pc); return temp; } @@ -552,8 +552,6 @@ static void pas16_pcm_poll(void *p) pas16_t *pas16 = (pas16_t *)p; pas16_update(pas16); -// if (pas16->pcm_ctrl & PAS16_PCM_ENA) -// pclog("pas16_pcm_poll : poll %i %i ", pas16->pit.c[0], pas16->pit.l[0]); if (pas16->pit.m[0] & 2) { if (pas16->pit.l[0]) @@ -566,13 +564,10 @@ static void pas16_pcm_poll(void *p) pas16->pit.c[0] = -1; pas16->pit.enable[0] = 0; } -// if (pas16->pcm_ctrl & PAS16_PCM_ENA) -// pclog(" %i\n", pas16->pit.c[0]); pas16->irq_stat |= PAS16_INT_SAMP; if (pas16->irq_ena & PAS16_INT_SAMP) picint(1 << pas16->irq); -// pas16_update_irqs(); /*Update sample rate counter*/ if (pas16->pit.enable[1]) @@ -602,11 +597,6 @@ static void pas16_pcm_poll(void *p) pas16->stereo_lr = !pas16->stereo_lr; } -// pclog("pas16_pcm_poll : %04X %i\n", temp, pas16->stereo_lr); -// pclog("pas16_pcm_poll : %i %02X %i\n", pas16->pit.c[1], temp, pas16->pit.c[0]); -/* if (!pas16_pcm) - pas16_pcm=fopen("pas16->pcm", "wb"); - putc(temp, pas16_pcm);*/ } if (pas16->sys_conf_2 & PAS16_SC2_16BIT) pas16->pit.c[1] -= 2; @@ -614,8 +604,6 @@ static void pas16_pcm_poll(void *p) pas16->pit.c[1]--; if (pas16->pit.c[1] == 0) { -// if (pas16->pcm_ctrl & PAS16_PCM_ENA) -// pclog("pas16_pcm_poll : buffer over\n"); if (pas16->pit.m[1] & 2) { if (pas16->pit.l[1]) diff --git a/src/sound_pas16.h b/src/SOUND/snd_pas16.h similarity index 100% rename from src/sound_pas16.h rename to src/SOUND/snd_pas16.h diff --git a/src/sound_ps1.c b/src/SOUND/snd_ps1.c similarity index 88% rename from src/sound_ps1.c rename to src/SOUND/snd_ps1.c index 4f42cd4d8..85334101a 100644 --- a/src/sound_ps1.c +++ b/src/SOUND/snd_ps1.c @@ -1,10 +1,13 @@ #include -#include "ibm.h" -#include "device.h" -#include "io.h" +#include "../ibm.h" +#include "../io.h" +#include "../pic.h" +#include "../timer.h" +#include "../device.h" #include "sound.h" -#include "sound_ps1.h" -#include "sound_sn76489.h" +#include "snd_ps1.h" +#include "snd_sn76489.h" + typedef struct ps1_audio_t { @@ -36,8 +39,6 @@ static uint8_t ps1_audio_read(uint16_t port, void *p) { ps1_audio_t *ps1 = (ps1_audio_t *)p; uint8_t temp; - -// pclog("ps1_audio_read %04x %04x:%04x\n", port, CS, pc); switch (port & 7) { @@ -52,7 +53,6 @@ static uint8_t ps1_audio_read(uint16_t port, void *p) temp |= 0x08; /*FIFO full*/ if (ps1->fifo_read_idx == ps1->fifo_write_idx) temp |= 0x04; /*FIFO empty*/ -// pclog("Return status %02x\n", temp); return temp; case 3: /*FIFO timer*/ /*PS/1 technical reference says this should return the current value, @@ -67,13 +67,10 @@ static uint8_t ps1_audio_read(uint16_t port, void *p) static void ps1_audio_write(uint16_t port, uint8_t val, void *p) { ps1_audio_t *ps1 = (ps1_audio_t *)p; - -// pclog("ps1_audio_write %04x %02x\n", port, val); - + switch (port & 7) { case 0: /*DAC output*/ -// pclog("DAC write %08x %08x %i\n", ps1->fifo_write_idx, ps1->fifo_read_idx, ps1->fifo_write_idx - ps1->fifo_read_idx); if ((ps1->fifo_write_idx - ps1->fifo_read_idx) < 2048) { ps1->fifo[ps1->fifo_write_idx & 2047] = val; @@ -114,10 +111,8 @@ static void ps1_audio_callback(void *p) ps1->dac_val = ps1->fifo[ps1->fifo_read_idx & 2047]; ps1->fifo_read_idx++; } -// pclog("ps1_callback %08x %08x %08x\n", ps1->fifo_write_idx, ps1->fifo_read_idx, ps1->fifo_threshold); if ((ps1->fifo_write_idx - ps1->fifo_read_idx) == ps1->fifo_threshold) { -// pclog("FIFO almost empty\n"); ps1->status |= 0x02; /*FIFO almost empty*/ } ps1->status |= 0x10; /*ADC data ready*/ diff --git a/src/sound_ps1.h b/src/SOUND/snd_ps1.h similarity index 100% rename from src/sound_ps1.h rename to src/SOUND/snd_ps1.h diff --git a/src/sound_pssj.c b/src/SOUND/snd_pssj.c similarity index 92% rename from src/sound_pssj.c rename to src/SOUND/snd_pssj.c index 0e4963d5d..dc52aee46 100644 --- a/src/sound_pssj.c +++ b/src/SOUND/snd_pssj.c @@ -1,14 +1,14 @@ #include -#include "ibm.h" -#include "device.h" -#include "io.h" +#include "../ibm.h" +#include "../io.h" +#include "../dma.h" +#include "../pic.h" +#include "../timer.h" +#include "../device.h" #include "sound.h" -#include "sound_pssj.h" -#include "sound_sn76489.h" +#include "snd_pssj.h" +#include "snd_sn76489.h" -#include "dma.h" -#include "pic.h" -#include "timer.h" typedef struct pssj_t { @@ -41,7 +41,6 @@ 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: @@ -77,7 +76,6 @@ 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: @@ -99,7 +97,11 @@ static uint8_t pssj_read(uint16_t port, void *p) return pssj->freq & 0xff; case 3: return (pssj->freq >> 8) | (pssj->amplitude << 4); + default: + return 0xff; } + + return 0xff; } static void pssj_update(pssj_t *pssj) @@ -123,7 +125,6 @@ static void pssj_callback(void *p) if (data != DMA_NODATA) { pssj->dac_val = data & 0xff; -// pclog("DAC_val=%02x\n", data); } } else @@ -133,7 +134,6 @@ static void pssj_callback(void *p) if ((data & DMA_OVER) && data != DMA_NODATA) { -// pclog("Check IRQ %i %02x\n", pssj->irq, pssj->ctrl); if (pssj->ctrl & 0x08) { pssj->irq = 1; diff --git a/src/sound_pssj.h b/src/SOUND/snd_pssj.h similarity index 100% rename from src/sound_pssj.h rename to src/SOUND/snd_pssj.h diff --git a/src/sound_resid.cc b/src/SOUND/snd_resid.cc similarity index 98% rename from src/sound_resid.cc rename to src/SOUND/snd_resid.cc index 8185b6046..ef1d32854 100644 --- a/src/sound_resid.cc +++ b/src/SOUND/snd_resid.cc @@ -3,7 +3,8 @@ #include #include #include "resid-fp/sid.h" -#include "sound_resid.h" +#include "snd_resid.h" + typedef struct psid_t { @@ -12,9 +13,11 @@ typedef struct psid_t int16_t last_sample; } psid_t; + psid_t *psid; -void *sid_init() + +void *sid_init(void) { // psid_t *psid; int c; diff --git a/src/sound_resid.h b/src/SOUND/snd_resid.h similarity index 100% rename from src/sound_resid.h rename to src/SOUND/snd_resid.h diff --git a/src/sound_sb.c b/src/SOUND/snd_sb.c similarity index 61% rename from src/sound_sb.c rename to src/SOUND/snd_sb.c index 2c8f72335..317d066e2 100644 --- a/src/sound_sb.c +++ b/src/SOUND/snd_sb.c @@ -1,14 +1,40 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Sound Blaster emulation. + * + * Version: @(#)sound_sb.c 1.0.0 2017/05/30 + * + * Author: Sarah Walker, + * Miran Grca, + * TheCollector1995, + * Copyright 2008-2017 Sarah Walker. + * Copyright 2016-2017 Miran Grca. + * Copyright 2016-2017 TheCollector1995. + */ -#include "ibm.h" -#include "device.h" -#include "sound_emu8k.h" -#include "sound_mpu401_uart.h" -#include "sound_opl.h" -#include "sound_sb.h" -#include "sound_sb_dsp.h" - +#include +#include "../ibm.h" +#include "../io.h" +#include "../mca.h" +#include "../mem.h" +#include "../rom.h" +#include "../device.h" +#include "sound.h" +#include "snd_dbopl.h" +#include "snd_emu8k.h" +#include "snd_mpu401.h" +#include "snd_opl.h" +#include "snd_sb.h" +#include "snd_sb_dsp.h" #include "filters.h" + typedef struct sb_mixer_t { int master_l, master_r; @@ -28,17 +54,19 @@ typedef struct sb_t opl_t opl; sb_dsp_t dsp; sb_mixer_t mixer; - mpu401_uart_t mpu; + mpu_t mpu; emu8k_t emu8k; int pos; + + uint8_t pos_regs[8]; } sb_t; static int sb_att[]= { - 310,368,437,520,618,735,873,1038,1234,1467,1743,2072,2463,2927,3479, - 4134,4914,5840,6941,8250,9805,11653,13850,16461,19564,23252,27635,32845, - 39036,46395,55140,65535 + 50,65,82,103,130,164,207,260,328,413,520,655,825,1038,1307, + 1645,2072,2608,3283,4134,5205,6553,8250,10385,13075,16461,20724,26089, + 32845,41349,52055,65535 }; static void sb_get_buffer_opl2(int32_t *buffer, int len, void *p) @@ -54,8 +82,8 @@ static void sb_get_buffer_opl2(int32_t *buffer, int len, void *p) { int32_t out_l, out_r; - out_l = ((sb->opl.buffer[c] * mixer->fm_l) >> 16); - out_r = ((sb->opl.buffer[c + 1] * mixer->fm_r) >> 16); + out_l = ((((sb->opl.buffer[c] * mixer->fm_l) >> 16) * 51000) >> 16); + out_r = ((((sb->opl.buffer[c + 1] * mixer->fm_r) >> 16) * 51000) >> 16); if (sb->mixer.filter) { @@ -68,8 +96,8 @@ static void sb_get_buffer_opl2(int32_t *buffer, int len, void *p) out_r += ((int32_t)(sb->dsp.buffer[c + 1] * mixer->voice_r) / 3) >> 16; } - out_l = (out_l * mixer->master_l) >> 16; - out_r = (out_r * mixer->master_r) >> 16; + out_l = (out_l * mixer->master_l) >> 15; + out_r = (out_r * mixer->master_r) >> 15; if (mixer->bass_l != 8 || mixer->bass_r != 8 || mixer->treble_l != 8 || mixer->treble_r != 8) { @@ -103,11 +131,10 @@ static void sb_get_buffer_opl3(int32_t *buffer, int len, void *p) sb_dsp_update(&sb->dsp); for (c = 0; c < len * 2; c += 2) { - int c_emu8k = (((c/2) * 44100) / 48000)*2; int32_t out_l, out_r; - out_l = ((sb->opl.buffer[c] * mixer->fm_l) >> 16); - out_r = ((sb->opl.buffer[c + 1] * mixer->fm_r) >> 16); + out_l = ((((sb->opl.buffer[c] * mixer->fm_l) >> 16) * (opl3_type ? 47000 : 51000)) >> 16); + out_r = ((((sb->opl.buffer[c + 1] * mixer->fm_r) >> 16) * (opl3_type ? 47000 : 51000)) >> 16); if (sb->mixer.filter) { @@ -120,8 +147,8 @@ static void sb_get_buffer_opl3(int32_t *buffer, int len, void *p) out_r += ((int32_t)(sb->dsp.buffer[c + 1] * mixer->voice_r) / 3) >> 16; } - out_l = (out_l * mixer->master_l) >> 16; - out_r = (out_r * mixer->master_r) >> 16; + out_l = (out_l * mixer->master_l) >> 15; + out_r = (out_r * mixer->master_r) >> 15; if (mixer->bass_l != 8 || mixer->bass_r != 8 || mixer->treble_l != 8 || mixer->treble_r != 8) { @@ -160,8 +187,8 @@ static void sb_get_buffer_emu8k(int32_t *buffer, int len, void *p) int c_emu8k = (((c/2) * 44100) / 48000)*2; int32_t out_l, out_r; - out_l = (((int32_t)sb->opl.buffer[c] * (int32_t)mixer->fm_l) >> 16); - out_r = (((int32_t)sb->opl.buffer[c + 1] * (int32_t)mixer->fm_r) >> 16); + out_l = ((((sb->opl.buffer[c] * mixer->fm_l) >> 16) * (opl3_type ? 47000 : 51000)) >> 16); + out_r = ((((sb->opl.buffer[c + 1] * mixer->fm_r) >> 16) * (opl3_type ? 47000 : 51000)) >> 16); out_l += ((sb->emu8k.buffer[c_emu8k] * mixer->fm_l) >> 16); out_r += ((sb->emu8k.buffer[c_emu8k + 1] * mixer->fm_l) >> 16); @@ -177,8 +204,8 @@ static void sb_get_buffer_emu8k(int32_t *buffer, int len, void *p) out_r += ((int32_t)(sb->dsp.buffer[c + 1] * mixer->voice_r) / 3) >> 16; } - out_l = (out_l * mixer->master_l) >> 16; - out_r = (out_r * mixer->master_r) >> 16; + out_l = (out_l * mixer->master_l) >> 15; + out_r = (out_r * mixer->master_r) >> 15; if (mixer->bass_l != 8 || mixer->bass_r != 8 || mixer->treble_l != 8 || mixer->treble_r != 8) { @@ -226,8 +253,6 @@ void sb_pro_mixer_write(uint16_t addr, uint8_t val, void *p) mixer->treble_l = mixer->treble_r = 8; sound_set_cd_volume(((uint32_t)mixer->master_l * (uint32_t)mixer->cd_l) / 65535, ((uint32_t)mixer->master_r * (uint32_t)mixer->cd_r) / 65535); -// pclog("%02X %02X %02X\n", mixer->regs[0x04], mixer->regs[0x22], mixer->regs[0x26]); -// pclog("Mixer - %04X %04X %04X %04X %04X %04X\n", mixer->master_l, mixer->master_r, mixer->voice_l, mixer->voice_r, mixer->fm_l, mixer->fm_r); if (mixer->index == 0xe) sb_dsp_set_stereo(&sb->dsp, val & 2); } @@ -241,7 +266,14 @@ uint8_t sb_pro_mixer_read(uint16_t addr, void *p) if (!(addr & 1)) return mixer->index; - return mixer->regs[mixer->index]; + switch (mixer->index) + { + case 0x00: case 0x04: case 0x0a: case 0x0c: case 0x0e: + case 0x22: case 0x26: case 0x28: case 0x2e: + return mixer->regs[mixer->index]; + } + + return 0xff; } void sb_16_mixer_write(uint16_t addr, uint8_t val, void *p) @@ -301,8 +333,6 @@ void sb_16_mixer_write(uint16_t addr, uint8_t val, void *p) mixer->filter = 0; sound_set_cd_volume(((uint32_t)mixer->master_l * (uint32_t)mixer->cd_l) / 65535, ((uint32_t)mixer->master_r * (uint32_t)mixer->cd_r) / 65535); -// pclog("%02X %02X %02X %02X %02X %02X\n", mixer->regs[0x30], mixer->regs[0x31], mixer->regs[0x32], mixer->regs[0x33], mixer->regs[0x34], mixer->regs[0x35]); -// pclog("Mixer - %04X %04X %04X %04X %04X %04X\n", mixer->master_l, mixer->master_r, mixer->voice_l, mixer->voice_r, mixer->fm_l, mixer->fm_r); } } @@ -320,10 +350,10 @@ uint8_t sb_16_mixer_read(uint16_t addr, void *p) case 0x80: switch (sb->dsp.sb_irqnum) { - case 2: return 1; /*IRQ 7*/ - case 5: return 2; /*IRQ 7*/ + case 2: return 1; /*IRQ 2*/ + case 5: return 2; /*IRQ 5*/ case 7: return 4; /*IRQ 7*/ - case 10: return 8; /*IRQ 7*/ + case 10: return 8; /*IRQ 10*/ } break; case 0x81: @@ -357,7 +387,6 @@ uint8_t sb_16_mixer_read(uint16_t addr, void *p) temp |= 0x00; break; } - // return 0x22; /*DMA 1 and 5*/ return temp; case 0x82: return ((sb->dsp.sb_irq8) ? 1 : 0) | ((sb->dsp.sb_irq16) ? 2 : 0); @@ -370,15 +399,101 @@ void sb_mixer_init(sb_mixer_t *mixer) mixer->master_l = mixer->master_r = 65535; mixer->voice_l = mixer->voice_r = 65535; mixer->fm_l = mixer->fm_r = 65535; + mixer->cd_l = mixer->cd_r = 65535; mixer->bass_l = mixer->bass_r = 8; mixer->treble_l = mixer->treble_r = 8; mixer->filter = 1; + sound_set_cd_volume(((uint32_t)mixer->master_l * (uint32_t)mixer->cd_l) / 65535, + ((uint32_t)mixer->master_r * (uint32_t)mixer->cd_r) / 65535); +} + +static uint16_t sb_mcv_addr[8] = {0x200, 0x210, 0x220, 0x230, 0x240, 0x250, 0x260, 0x270}; + +uint8_t sb_mcv_read(int port, void *p) +{ + sb_t *sb = (sb_t *)p; + + pclog("sb_mcv_read: port=%04x\n", port); + + return sb->pos_regs[port & 7]; +} + +void sb_mcv_write(int port, uint8_t val, void *p) +{ + uint16_t addr; + sb_t *sb = (sb_t *)p; + + if (port < 0x102) + return; + + pclog("sb_mcv_write: port=%04x val=%02x\n", port, val); + + addr = sb_mcv_addr[sb->pos_regs[4] & 7]; + io_removehandler(addr+8, 0x0002, opl2_read, NULL, NULL, opl2_write, NULL, NULL, &sb->opl); + io_removehandler(0x0388, 0x0002, opl2_read, NULL, NULL, opl2_write, NULL, NULL, &sb->opl); + sb_dsp_setaddr(&sb->dsp, 0); + + sb->pos_regs[port & 7] = val; + + if (sb->pos_regs[2] & 1) + { + addr = sb_mcv_addr[sb->pos_regs[4] & 7]; + + io_sethandler(addr+8, 0x0002, opl2_read, NULL, NULL, opl2_write, NULL, NULL, &sb->opl); + io_sethandler(0x0388, 0x0002, opl2_read, NULL, NULL, opl2_write, NULL, NULL, &sb->opl); + sb_dsp_setaddr(&sb->dsp, addr); + } +} + +static int sb_pro_mcv_irqs[4] = {7, 5, 3, 3}; + +uint8_t sb_pro_mcv_read(int port, void *p) +{ + sb_t *sb = (sb_t *)p; + + pclog("sb_pro_mcv_read: port=%04x\n", port); + + return sb->pos_regs[port & 7]; +} + +void sb_pro_mcv_write(int port, uint8_t val, void *p) +{ + uint16_t addr; + sb_t *sb = (sb_t *)p; + + if (port < 0x102) + return; + + pclog("sb_pro_mcv_write: port=%04x val=%02x\n", port, val); + + addr = (sb->pos_regs[2] & 0x20) ? 0x220 : 0x240; + io_removehandler(addr+0, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl); + io_removehandler(addr+8, 0x0002, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl); + io_removehandler(0x0388, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl); + io_removehandler(addr+4, 0x0002, sb_pro_mixer_read, NULL, NULL, sb_pro_mixer_write, NULL, NULL, sb); + sb_dsp_setaddr(&sb->dsp, 0); + + sb->pos_regs[port & 7] = val; + + if (sb->pos_regs[2] & 1) + { + addr = (sb->pos_regs[2] & 0x20) ? 0x220 : 0x240; + + io_sethandler(addr+0, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl); + io_sethandler(addr+8, 0x0002, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl); + io_sethandler(0x0388, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl); + io_sethandler(addr+4, 0x0002, sb_pro_mixer_read, NULL, NULL, sb_pro_mixer_write, NULL, NULL, sb); + + sb_dsp_setaddr(&sb->dsp, addr); + } + sb_dsp_setirq(&sb->dsp, sb_pro_mcv_irqs[(sb->pos_regs[5] >> 4) & 3]); + sb_dsp_setdma8(&sb->dsp, sb->pos_regs[4] & 3); } void *sb_1_init() { sb_t *sb = malloc(sizeof(sb_t)); - uint16_t addr = device_get_config_int("addr"); + uint16_t addr = device_get_config_hex16("base"); memset(sb, 0, sizeof(sb_t)); opl2_init(&sb->opl); @@ -395,7 +510,7 @@ void *sb_1_init() void *sb_15_init() { sb_t *sb = malloc(sizeof(sb_t)); - uint16_t addr = device_get_config_int("addr"); + uint16_t addr = device_get_config_hex16("base"); memset(sb, 0, sizeof(sb_t)); opl2_init(&sb->opl); @@ -409,10 +524,28 @@ void *sb_15_init() sound_add_handler(sb_get_buffer_opl2, sb); return sb; } + +void *sb_mcv_init() +{ + sb_t *sb = malloc(sizeof(sb_t)); + memset(sb, 0, sizeof(sb_t)); + + opl2_init(&sb->opl); + sb_dsp_init(&sb->dsp, SB15); + sb_dsp_setaddr(&sb->dsp, 0); + sb_dsp_setirq(&sb->dsp, device_get_config_int("irq")); + sb_dsp_setdma8(&sb->dsp, device_get_config_int("dma")); + sb_mixer_init(&sb->mixer); + sound_add_handler(sb_get_buffer_opl2, sb); + mca_add(sb_mcv_read, sb_mcv_write, sb); + sb->pos_regs[0] = 0x84; + sb->pos_regs[1] = 0x50; + return sb; +} void *sb_2_init() { sb_t *sb = malloc(sizeof(sb_t)); - uint16_t addr = device_get_config_int("addr"); + uint16_t addr = device_get_config_hex16("base"); memset(sb, 0, sizeof(sb_t)); opl2_init(&sb->opl); @@ -430,7 +563,7 @@ void *sb_2_init() void *sb_pro_v1_init() { sb_t *sb = malloc(sizeof(sb_t)); - uint16_t addr = device_get_config_int("addr"); + uint16_t addr = device_get_config_hex16("base"); memset(sb, 0, sizeof(sb_t)); opl2_init(&sb->opl); @@ -449,6 +582,7 @@ void *sb_pro_v1_init() sb->mixer.regs[0x22] = 0xff; sb->mixer.regs[0x04] = 0xff; sb->mixer.regs[0x26] = 0xff; + sb->mixer.regs[0x28] = 0xff; sb->mixer.regs[0xe] = 0; return sb; @@ -457,7 +591,7 @@ void *sb_pro_v1_init() void *sb_pro_v2_init() { sb_t *sb = malloc(sizeof(sb_t)); - uint16_t addr = device_get_config_int("addr"); + uint16_t addr = device_get_config_hex16("base"); memset(sb, 0, sizeof(sb_t)); opl3_init(&sb->opl); @@ -468,22 +602,46 @@ void *sb_pro_v2_init() sb_mixer_init(&sb->mixer); io_sethandler(addr+0, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl); io_sethandler(addr+8, 0x0002, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl); - io_sethandler(0x0388, 0x0002, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl); + io_sethandler(0x0388, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl); io_sethandler(addr+4, 0x0002, sb_pro_mixer_read, NULL, NULL, sb_pro_mixer_write, NULL, NULL, sb); sound_add_handler(sb_get_buffer_opl3, sb); + sb->mixer.regs[0x22] = 0xff; + sb->mixer.regs[0x04] = 0xff; + sb->mixer.regs[0x26] = 0xff; + sb->mixer.regs[0x28] = 0xff; + sb->mixer.regs[0xe] = 0; + + return sb; +} + +void *sb_pro_mcv_init() +{ + sb_t *sb = malloc(sizeof(sb_t)); + memset(sb, 0, sizeof(sb_t)); + + opl3_init(&sb->opl); + sb_dsp_init(&sb->dsp, SBPRO2); + sb_mixer_init(&sb->mixer); + io_sethandler(0x0388, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl); + sound_add_handler(sb_get_buffer_opl3, sb); + sb->mixer.regs[0x22] = 0xff; sb->mixer.regs[0x04] = 0xff; sb->mixer.regs[0x26] = 0xff; sb->mixer.regs[0xe] = 0; + mca_add(sb_pro_mcv_read, sb_pro_mcv_write, sb); + sb->pos_regs[0] = 0x03; + sb->pos_regs[1] = 0x51; + return sb; } void *sb_16_init() { sb_t *sb = malloc(sizeof(sb_t)); - uint16_t addr = device_get_config_int("addr"); + uint16_t addr = device_get_config_hex16("base"); memset(sb, 0, sizeof(sb_t)); opl3_init(&sb->opl); @@ -493,12 +651,12 @@ void *sb_16_init() sb_dsp_setdma8(&sb->dsp, device_get_config_int("dma")); sb_dsp_setdma16(&sb->dsp, device_get_config_int("dma16")); sb_mixer_init(&sb->mixer); - io_sethandler(0x0220, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl); - io_sethandler(0x0228, 0x0002, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl); - io_sethandler(0x0388, 0x0002, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl); - io_sethandler(0x0224, 0x0002, sb_16_mixer_read, NULL, NULL, sb_16_mixer_write, NULL, NULL, sb); + io_sethandler(addr + 0, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl); + io_sethandler(addr + 8, 0x0002, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl); + io_sethandler(0x0388, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl); + io_sethandler(addr + 4, 0x0002, sb_16_mixer_read, NULL, NULL, sb_16_mixer_write, NULL, NULL, sb); sound_add_handler(sb_get_buffer_opl3, sb); - mpu401_uart_init(&sb->mpu, device_get_config_int("addr401")); + mpu401_init(&sb->mpu, device_get_config_hex16("base401"), device_get_config_int("irq401"), device_get_config_int("mode401")); sb->mixer.regs[0x30] = 31 << 3; sb->mixer.regs[0x31] = 31 << 3; @@ -506,6 +664,8 @@ void *sb_16_init() sb->mixer.regs[0x33] = 31 << 3; sb->mixer.regs[0x34] = 31 << 3; sb->mixer.regs[0x35] = 31 << 3; + sb->mixer.regs[0x36] = 31 << 3; + sb->mixer.regs[0x37] = 31 << 3; sb->mixer.regs[0x44] = 8 << 4; sb->mixer.regs[0x45] = 8 << 4; sb->mixer.regs[0x46] = 8 << 4; @@ -513,19 +673,20 @@ void *sb_16_init() sb->mixer.regs[0x22] = (sb->mixer.regs[0x30] & 0xf0) | (sb->mixer.regs[0x31] >> 4); sb->mixer.regs[0x04] = (sb->mixer.regs[0x32] & 0xf0) | (sb->mixer.regs[0x33] >> 4); sb->mixer.regs[0x26] = (sb->mixer.regs[0x34] & 0xf0) | (sb->mixer.regs[0x35] >> 4); + sb->mixer.regs[0x28] = (sb->mixer.regs[0x36] & 0xf0) | (sb->mixer.regs[0x37] >> 4); return sb; } int sb_awe32_available() { - return rom_present("roms/awe32.raw"); + return rom_present(L"roms/awe32.raw"); } void *sb_awe32_init() { sb_t *sb = malloc(sizeof(sb_t)); - uint16_t addr = device_get_config_int("addr"); + uint16_t addr = device_get_config_hex16("base"); int onboard_ram = device_get_config_int("onboard_ram"); memset(sb, 0, sizeof(sb_t)); @@ -536,12 +697,12 @@ void *sb_awe32_init() sb_dsp_setdma8(&sb->dsp, device_get_config_int("dma")); sb_dsp_setdma16(&sb->dsp, device_get_config_int("dma16")); sb_mixer_init(&sb->mixer); - io_sethandler(0x0220, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl); - io_sethandler(0x0228, 0x0002, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl); - io_sethandler(0x0388, 0x0002, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl); - io_sethandler(0x0224, 0x0002, sb_16_mixer_read, NULL, NULL, sb_16_mixer_write, NULL, NULL, sb); + io_sethandler(addr + 0, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl); + io_sethandler(addr + 8, 0x0002, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl); + io_sethandler(0x0388, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl); + io_sethandler(addr + 4, 0x0002, sb_16_mixer_read, NULL, NULL, sb_16_mixer_write, NULL, NULL, sb); sound_add_handler(sb_get_buffer_emu8k, sb); - mpu401_uart_init(&sb->mpu, device_get_config_int("addr401")); + mpu401_init(&sb->mpu, device_get_config_hex16("base401"), device_get_config_int("irq401"), device_get_config_int("mode401")); emu8k_init(&sb->emu8k, onboard_ram); sb->mixer.regs[0x30] = 31 << 3; @@ -550,6 +711,8 @@ void *sb_awe32_init() sb->mixer.regs[0x33] = 31 << 3; sb->mixer.regs[0x34] = 31 << 3; sb->mixer.regs[0x35] = 31 << 3; + sb->mixer.regs[0x36] = 31 << 3; + sb->mixer.regs[0x37] = 31 << 3; sb->mixer.regs[0x44] = 8 << 4; sb->mixer.regs[0x45] = 8 << 4; sb->mixer.regs[0x46] = 8 << 4; @@ -557,6 +720,7 @@ void *sb_awe32_init() sb->mixer.regs[0x22] = (sb->mixer.regs[0x30] & 0xf0) | (sb->mixer.regs[0x31] >> 4); sb->mixer.regs[0x04] = (sb->mixer.regs[0x32] & 0xf0) | (sb->mixer.regs[0x33] >> 4); sb->mixer.regs[0x26] = (sb->mixer.regs[0x34] & 0xf0) | (sb->mixer.regs[0x35] >> 4); + sb->mixer.regs[0x28] = (sb->mixer.regs[0x36] & 0xf0) | (sb->mixer.regs[0x37] >> 4); return sb; } @@ -594,446 +758,441 @@ void sb_add_status_info(char *s, int max_len, void *p) static device_config_t sb_config[] = { { - .name = "addr", - .description = "Address", - .type = CONFIG_BINARY, - .type = CONFIG_SELECTION, - .selection = + "base", "Address", CONFIG_HEX16, "", 0x220, { { - .description = "0x220", - .value = 0x220 + "0x220", 0x220 }, { - .description = "0x240", - .value = 0x240 + "0x240", 0x240 }, { - .description = "" + "" } - }, - .default_int = 0x220 + } }, { - .name = "irq", - .description = "IRQ", - .type = CONFIG_SELECTION, - .selection = + "irq", "IRQ", CONFIG_SELECTION, "", 7, { { - .description = "IRQ 2", - .value = 2 + "IRQ 2", 2 }, { - .description = "IRQ 3", - .value = 3 + "IRQ 3", 3 }, { - .description = "IRQ 5", - .value = 5 + "IRQ 5", 5 }, { - .description = "IRQ 7", - .value = 7 + "IRQ 7", 7 }, { - .description = "" + "" } - }, - .default_int = 7 + } }, { - .name = "dma", - .description = "DMA", - .type = CONFIG_SELECTION, - .selection = + "dma", "DMA", CONFIG_SELECTION, "", 1, { { - .description = "DMA 1", - .value = 1 + "DMA 1", 1 }, { - .description = "DMA 3", - .value = 3 + "DMA 3", 3 }, { - .description = "" + "" } - }, - .default_int = 1 + } }, { - .type = -1 + "", "", -1 + } +}; + +static device_config_t sb_mcv_config[] = +{ + { + "irq", "IRQ", CONFIG_SELECTION, "", 7, + { + { + "IRQ 3", 3 + }, + { + "IRQ 5", 5 + }, + { + "IRQ 7", 7 + }, + { + "" + } + } + }, + { + "dma", "DMA", CONFIG_SELECTION, "", 1, + { + { + "DMA 1", 1 + }, + { + "DMA 3", 3 + }, + { + "" + } + } + }, + { + "", "", -1 } }; static device_config_t sb_pro_config[] = { { - .name = "addr", - .description = "Address", - .type = CONFIG_BINARY, - .type = CONFIG_SELECTION, - .selection = + "base", "Address", CONFIG_HEX16, "", 0x220, { { - .description = "0x220", - .value = 0x220 + "0x220", 0x220 }, { - .description = "0x240", - .value = 0x240 + "0x240", 0x240 }, { - .description = "" + "" } - }, - .default_int = 0x220 + } }, { - .name = "irq", - .description = "IRQ", - .type = CONFIG_SELECTION, - .selection = + "irq", "IRQ", CONFIG_SELECTION, "", 7, { { - .description = "IRQ 2", - .value = 2 + "IRQ 2", 2 }, { - .description = "IRQ 5", - .value = 5 + "IRQ 5", 5 }, { - .description = "IRQ 7", - .value = 7 + "IRQ 7", 7 }, { - .description = "IRQ 10", - .value = 10 + "IRQ 10", 10 }, { - .description = "" + "" } - }, - .default_int = 7 + } }, { - .name = "dma", - .description = "DMA", - .type = CONFIG_SELECTION, - .selection = + "dma", "DMA", CONFIG_SELECTION, "", 1, { { - .description = "DMA 1", - .value = 1 + "DMA 1", 1 }, { - .description = "DMA 3", - .value = 3 + "DMA 3", 3 }, { - .description = "" + "" } - }, - .default_int = 1 + } }, { - .type = -1 + "", "", -1 } }; static device_config_t sb_16_config[] = { { - .name = "addr", - .description = "Address", - .type = CONFIG_BINARY, - .type = CONFIG_SELECTION, - .selection = + "base", "Address", CONFIG_HEX16, "", 0x220, { { - .description = "0x220", - .value = 0x220 + "0x220", 0x220 }, { - .description = "0x240", - .value = 0x240 + "0x240", 0x240 }, { - .description = "" + "0x260", 0x260 + }, + { + "0x280", 0x280 + }, + { + "" } - }, - .default_int = 0x220 + } }, { - .name = "addr401", - .description = "MPU-401 Address", - .type = CONFIG_BINARY, - .type = CONFIG_SELECTION, - .selection = + "base401", "MPU-401 Address", CONFIG_HEX16, "", 0x330, { { - .description = "0x300", - .value = 0x300 + "0x300", 0x300 }, { - .description = "0x330", - .value = 0x330 + "0x330", 0x330 }, { - .description = "" + "" } - }, - .default_int = 0x330 + } }, { - .name = "irq", - .description = "IRQ", - .type = CONFIG_SELECTION, - .selection = + "irq", "IRQ", CONFIG_SELECTION, "", 5, { { - .description = "IRQ 2", - .value = 2 + "IRQ 2", 2 }, { - .description = "IRQ 5", - .value = 5 + "IRQ 5", 5 }, { - .description = "IRQ 7", - .value = 7 + "IRQ 7", 7 }, { - .description = "IRQ 10", - .value = 10 + "IRQ 10", 10 }, { - .description = "" + "" } - }, - .default_int = 5 + } }, { - .name = "dma", - .description = "Low DMA channel", - .type = CONFIG_SELECTION, - .selection = + "irq401", "MPU-401 IRQ", CONFIG_SELECTION, "", 9, { { - .description = "DMA 0", - .value = 0 + "IRQ 9", 9 }, { - .description = "DMA 1", - .value = 1 + "IRQ 3", 3 }, { - .description = "DMA 3", - .value = 3 + "IRQ 4", 4 }, { - .description = "" + "IRQ 5", 5 + }, + { + "IRQ 7", 7 + }, + { + "IRQ 10", 10 + }, + { + "" } - }, - .default_int = 1 + } }, { - .name = "dma16", - .description = "High DMA channel", - .type = CONFIG_SELECTION, - .selection = + "dma", "Low DMA channel", CONFIG_SELECTION, "", 1, { { - .description = "DMA 5", - .value = 5 + "DMA 0", 0 }, { - .description = "DMA 6", - .value = 6 + "DMA 1", 1 }, { - .description = "DMA 7", - .value = 7 + "DMA 3", 3 }, { - .description = "" + "" } - }, - .default_int = 5 + } }, { - .name = "midi", - .description = "MIDI out device", - .type = CONFIG_MIDI, - .default_int = 0 + "dma16", "High DMA channel", CONFIG_SELECTION, "", 5, + { + { + "DMA 5", 5 + }, + { + "DMA 6", 6 + }, + { + "DMA 7", 7 + }, + { + "" + } + } }, { - .type = -1 + "mode401", "MPU-401 mode", CONFIG_SELECTION, "", 1, + { + { + "UART", M_UART + }, + { + "Intelligent", M_INTELLIGENT + }, + { + "" + } + } + }, + { + "", "", -1 } }; static device_config_t sb_awe32_config[] = { { - .name = "addr", - .description = "Address", - .type = CONFIG_BINARY, - .type = CONFIG_SELECTION, - .selection = + "base", "Address", CONFIG_HEX16, "", 0x220, { { - .description = "0x220", - .value = 0x220 + "0x220", 0x220 }, { - .description = "0x240", - .value = 0x240 + "0x240", 0x240 }, { - .description = "" + "0x260", 0x260 + }, + { + "0x280", 0x280 + }, + { + "" } - }, - .default_int = 0x220 + } }, { - .name = "addr401", - .description = "MPU-401 Address", - .type = CONFIG_BINARY, - .type = CONFIG_SELECTION, - .selection = + "base401", "MPU-401 Address", CONFIG_HEX16, "", 0x330, { { - .description = "0x300", - .value = 0x300 + "0x300", 0x300 }, { - .description = "0x330", - .value = 0x330 + "0x330", 0x330 }, { - .description = "" + "" } - }, - .default_int = 0x330 + } }, { - .name = "irq", - .description = "IRQ", - .type = CONFIG_SELECTION, - .selection = + "irq", "IRQ", CONFIG_SELECTION, "", 5, { { - .description = "IRQ 2", - .value = 2 + "IRQ 2", 2 }, { - .description = "IRQ 5", - .value = 5 + "IRQ 5", 5 }, { - .description = "IRQ 7", - .value = 7 + "IRQ 7", 7 }, { - .description = "IRQ 10", - .value = 10 + "IRQ 10", 10 }, { - .description = "" + "" } - }, - .default_int = 5 + } }, { - .name = "dma", - .description = "Low DMA channel", - .type = CONFIG_SELECTION, - .selection = + "irq401", "MPU-401 IRQ", CONFIG_SELECTION, "", 9, { { - .description = "DMA 0", - .value = 0 + "IRQ 9", 9 }, { - .description = "DMA 1", - .value = 1 + "IRQ 3", 3 }, { - .description = "DMA 3", - .value = 3 + "IRQ 4", 4 }, { - .description = "" + "IRQ 5", 5 + }, + { + "IRQ 7", 7 + }, + { + "IRQ 10", 10 + }, + { + "" } - }, - .default_int = 1 + } }, { - .name = "dma16", - .description = "High DMA channel", - .type = CONFIG_SELECTION, - .selection = + "dma", "Low DMA channel", CONFIG_SELECTION, "", 1, { { - .description = "DMA 5", - .value = 5 + "DMA 0", 0 }, { - .description = "DMA 6", - .value = 6 + "DMA 1", 1 }, { - .description = "DMA 7", - .value = 7 + "DMA 3", 3 }, { - .description = "" + "" } - }, - .default_int = 5 + } }, { - .name = "midi", - .description = "MIDI out device", - .type = CONFIG_MIDI, - .default_int = 0 - }, - { - .name = "onboard_ram", - .description = "Onboard RAM", - .type = CONFIG_SELECTION, - .selection = + "dma16", "High DMA channel", CONFIG_SELECTION, "", 5, { { - .description = "None", - .value = 0 + "DMA 5", 5 }, { - .description = "512 KB", - .value = 512 + "DMA 6", 6 }, { - .description = "2 MB", - .value = 2048 + "DMA 7", 7 }, { - .description = "8 MB", - .value = 8192 - }, - { - .description = "28 MB", - .value = 28*1024 - }, - { - .description = "" + "" } - }, - .default_int = 512 + } }, { - .type = -1 + "mode401", "MPU-401 mode", CONFIG_SELECTION, "", 1, + { + { + "UART", M_UART + }, + { + "Intelligent", M_INTELLIGENT + }, + { + "" + } + } + }, + { + "onboard_ram", "Onboard RAM", CONFIG_SELECTION, "", 512, + { + { + "None", 0 + }, + { + "512 KB", 512 + }, + { + "2 MB", 2048 + }, + { + "8 MB", 8192 + }, + { + "28 MB", 28*1024 + }, + { + "" + } + } + }, + { + "", "", -1 } }; @@ -1061,6 +1220,18 @@ device_t sb_15_device = sb_add_status_info, sb_config }; +device_t sb_mcv_device = +{ + "Sound Blaster MCV", + DEVICE_MCA, + sb_mcv_init, + sb_close, + NULL, + sb_speed_changed, + NULL, + sb_add_status_info, + sb_mcv_config +}; device_t sb_2_device = { "Sound Blaster v2.0", @@ -1097,6 +1268,18 @@ device_t sb_pro_v2_device = sb_add_status_info, sb_pro_config }; +device_t sb_pro_mcv_device = +{ + "Sound Blaster Pro MCV", + DEVICE_MCA, + sb_pro_mcv_init, + sb_close, + NULL, + sb_speed_changed, + NULL, + sb_add_status_info, + NULL +}; device_t sb_16_device = { "Sound Blaster 16", diff --git a/src/SOUND/snd_sb.h b/src/SOUND/snd_sb.h new file mode 100644 index 000000000..de5b5af93 --- /dev/null +++ b/src/SOUND/snd_sb.h @@ -0,0 +1,29 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Sound Blaster emulation. + * + * Version: @(#)sound_sb.h 1.0.0 2017/05/30 + * + * Author: Sarah Walker, + * Miran Grca, + * TheCollector1995, + * Copyright 2008-2017 Sarah Walker. + * Copyright 2016-2017 Miran Grca. + * Copyright 2016-2017 TheCollector1995. + */ + +extern device_t sb_1_device; +extern device_t sb_15_device; +extern device_t sb_mcv_device; +extern device_t sb_2_device; +extern device_t sb_pro_v1_device; +extern device_t sb_pro_v2_device; +extern device_t sb_pro_mcv_device; +extern device_t sb_16_device; +extern device_t sb_awe32_device; diff --git a/src/sound_sb_dsp.c b/src/SOUND/snd_sb_dsp.c similarity index 92% rename from src/sound_sb_dsp.c rename to src/SOUND/snd_sb_dsp.c index 40dd6e0e7..8ff2e4efc 100644 --- a/src/sound_sb_dsp.c +++ b/src/SOUND/snd_sb_dsp.c @@ -3,24 +3,25 @@ 486-33 - 20kHz 486-50 - 32kHz Pentium - 45kHz*/ - #include #include -#include "ibm.h" - - -#include "dma.h" -#include "io.h" -#include "pic.h" +#include "../ibm.h" +#include "../io.h" +#include "../pic.h" +#include "../dma.h" +#include "../timer.h" +#include "../device.h" +#include "midi.h" #include "sound.h" -#include "sound_sb_dsp.h" -#include "timer.h" +#include "snd_mpu401.h" +#include "snd_sb_dsp.h" + +mpu_t mpu; void pollsb(void *p); void sb_poll_i(void *p); - static int sbe2dat[4][9] = { { 0x01, -0x02, -0x04, 0x08, -0x10, 0x20, 0x40, -0x80, -106 }, { -0x01, 0x02, -0x04, 0x08, 0x10, -0x20, 0x40, -0x80, 165 }, @@ -100,7 +101,6 @@ uint16_t sb_dsp_versions[] = {0, 0, 0x105, 0x200, 0x201, 0x300, 0x302, 0x405, 0x void sb_irq(sb_dsp_t *dsp, int irq8) { -// pclog("IRQ %i %02X\n",irq8,pic.mask); if (irq8) dsp->sb_irq8 = 1; else dsp->sb_irq16 = 1; picint(1 << dsp->sb_irqnum); @@ -193,7 +193,6 @@ void sb_start_dma(sb_dsp_t *dsp, int dma8, int autoinit, uint8_t format, int len timer_update_outstanding(); dsp->sbleftright = 0; dsp->sbdacpos = 0; -// pclog("Start 8-bit DMA addr %06X len %04X\n",dma.ac[1]+(dma.page[1]<<16),len); } else { @@ -207,7 +206,6 @@ void sb_start_dma(sb_dsp_t *dsp, int dma8, int autoinit, uint8_t format, int len timer_process(); dsp->sbenable = dsp->sb_16_enable; timer_update_outstanding(); -// pclog("Start 16-bit DMA addr %06X len %04X\n",dma16.ac[1]+(dma16.page[1]<<16),len); } } @@ -225,7 +223,6 @@ void sb_start_dma_i(sb_dsp_t *dsp, int dma8, int autoinit, uint8_t format, int l timer_process(); dsp->sb_enable_i = dsp->sb_8_enable; timer_update_outstanding(); -// pclog("Start 8-bit input DMA addr %06X len %04X\n",dma.ac[1]+(dma.page[1]<<16),len); } else { @@ -239,7 +236,6 @@ void sb_start_dma_i(sb_dsp_t *dsp, int dma8, int autoinit, uint8_t format, int l timer_process(); dsp->sb_enable_i = dsp->sb_16_enable; timer_update_outstanding(); -// pclog("Start 16-bit input DMA addr %06X len %04X\n",dma.ac[1]+(dma.page[1]<<16),len); } } @@ -278,7 +274,6 @@ void sb_dsp_setdma16(sb_dsp_t *dsp, int dma) void sb_exec_command(sb_dsp_t *dsp) { int temp,c; -// pclog("sb_exec_command : SB command %02X\n", dsp->sb_command); switch (dsp->sb_command) { case 0x01: /*???*/ @@ -298,7 +293,6 @@ void sb_exec_command(sb_dsp_t *dsp) case 0x17: /*2-bit ADPCM output with reference*/ dsp->sbref = sb_8_read_dma(dsp); dsp->sbstep = 0; -// pclog("Ref byte 2 %02X\n",sbref); case 0x16: /*2-bit ADPCM output*/ sb_start_dma(dsp, 1, 0, ADPCM_2, dsp->sb_data[0] + (dsp->sb_data[1] << 8)); dsp->sbdat2 = sb_8_read_dma(dsp); @@ -329,14 +323,35 @@ void sb_exec_command(sb_dsp_t *dsp) dsp->sblatcho = dsp->sblatchi = TIMER_USEC * (256 - dsp->sb_data[0]); temp = 256 - dsp->sb_data[0]; temp = 1000000 / temp; -// pclog("Sample rate - %ihz (%i)\n",temp, dsp->sblatcho); dsp->sb_freq = temp; break; + + case 0x30: + case 0x31: + break; + + case 0x34: + dsp->uart_midi = 1; + dsp->uart_irq = 0; + break; + + case 0x35: + dsp->uart_midi = 1; + dsp->uart_irq = 1; + break; + + case 0x36: + case 0x37: + break; + + case 0x38: + dsp->onebyte_midi = 1; + break; + case 0x41: /*Set output sampling rate*/ case 0x42: /*Set input sampling rate*/ if (dsp->sb_type < SB16) break; dsp->sblatcho = (int)(TIMER_USEC * (1000000.0f / (float)(dsp->sb_data[1] + (dsp->sb_data[0] << 8)))); -// pclog("Sample rate - %ihz (%i)\n",dsp->sb_data[1]+(dsp->sb_data[0]<<8), dsp->sblatcho); dsp->sb_freq = dsp->sb_data[1] + (dsp->sb_data[0] << 8); dsp->sb_timeo = 256 + dsp->sb_freq; dsp->sblatchi = dsp->sblatcho; @@ -348,7 +363,6 @@ void sb_exec_command(sb_dsp_t *dsp) case 0x75: /*4-bit ADPCM output with reference*/ dsp->sbref = sb_8_read_dma(dsp); dsp->sbstep = 0; -// pclog("Ref byte 4 %02X\n",sbref); case 0x74: /*4-bit ADPCM output*/ sb_start_dma(dsp, 1, 0, ADPCM_4, dsp->sb_data[0] + (dsp->sb_data[1] << 8)); dsp->sbdat2 = sb_8_read_dma(dsp); @@ -357,7 +371,6 @@ void sb_exec_command(sb_dsp_t *dsp) case 0x77: /*2.6-bit ADPCM output with reference*/ dsp->sbref = sb_8_read_dma(dsp); dsp->sbstep = 0; -// pclog("Ref byte 26 %02X\n",sbref); case 0x76: /*2.6-bit ADPCM output*/ sb_start_dma(dsp, 1, 0, ADPCM_26, dsp->sb_data[0] + (dsp->sb_data[1] << 8)); dsp->sbdat2 = sb_8_read_dma(dsp); @@ -377,7 +390,6 @@ void sb_exec_command(sb_dsp_t *dsp) break; case 0x80: /*Pause DAC*/ dsp->sb_pausetime = dsp->sb_data[0] + (dsp->sb_data[1] << 8); -// pclog("SB pause %04X\n",sb_pausetime); timer_process(); dsp->sbenable = 1; timer_update_outstanding(); @@ -483,7 +495,6 @@ void sb_exec_command(sb_dsp_t *dsp) sb_add_data(dsp, dsp->sb_test); break; case 0xF2: /*Trigger 8-bit IRQ*/ -// pclog("Trigger IRQ\n"); sb_irq(dsp, 1); break; case 0xE7: /*???*/ @@ -499,13 +510,14 @@ void sb_exec_command(sb_dsp_t *dsp) case 0x0E: /*ASP set register*/ if (dsp->sb_type < SB16) break; dsp->sb_asp_regs[dsp->sb_data[0]] = dsp->sb_data[1]; -// pclog("ASP write reg %02X %02X\n", sb_data[0], sb_data[1]); break; case 0x0F: /*ASP get register*/ if (dsp->sb_type < SB16) break; -// sb_add_data(0); sb_add_data(dsp, dsp->sb_asp_regs[dsp->sb_data[0]]); -// pclog("ASP read reg %02X %02X\n", sb_data[0], sb_asp_regs[sb_data[0]]); + break; + case 0xF8: + if (dsp->sb_type >= SB16) break; + sb_add_data(dsp, 0); break; case 0xF9: if (dsp->sb_type < SB16) break; @@ -516,15 +528,12 @@ void sb_exec_command(sb_dsp_t *dsp) case 0x04: case 0x05: break; -// default: -// fatal("Exec bad SB command %02X\n",sb_command); } } void sb_write(uint16_t a, uint8_t v, void *priv) { sb_dsp_t *dsp = (sb_dsp_t *)priv; -// pclog("sb_write : Write soundblaster %04X %02X %04X:%04X %02X\n",a,v,CS,pc,dsp->sb_command); switch (a&0xF) { case 6: /*Reset*/ @@ -536,13 +545,18 @@ void sb_write(uint16_t a, uint8_t v, void *priv) dsp->sbreset = v; return; case 0xC: /*Command/data write*/ + if (dsp->uart_midi || dsp->onebyte_midi) + { + midi_write(v); + dsp->onebyte_midi = 0; + return; + } timer_process(); dsp->wb_time = TIMER_USEC * 1; dsp->wb_full = 1; timer_update_outstanding(); if (dsp->asp_data_len) { -// pclog("ASP data %i\n", dsp->asp_data_len); dsp->asp_data_len--; if (!dsp->asp_data_len) sb_add_data(dsp, 0); @@ -553,8 +567,6 @@ void sb_write(uint16_t a, uint8_t v, void *priv) dsp->sb_command = v; if (v == 0x01) sb_add_data(dsp, 0); -// if (sb_commands[v]==-1) -// fatal("Bad SB command %02X\n",v); dsp->sb_data_stat++; } else @@ -571,18 +583,19 @@ void sb_write(uint16_t a, uint8_t v, void *priv) uint8_t sb_read(uint16_t a, void *priv) { sb_dsp_t *dsp = (sb_dsp_t *)priv; -// if (a==0x224) output=1; -// pclog("sb_read : Read soundblaster %04X %04X:%04X\n",a,CS,pc); switch (a & 0xf) { case 0xA: /*Read data*/ + if (dsp->uart_midi) + { + return MPU401_ReadData(&mpu); + } dsp->sbreaddat = dsp->sb_read_data[dsp->sb_read_rp]; if (dsp->sb_read_rp != dsp->sb_read_wp) { dsp->sb_read_rp++; dsp->sb_read_rp &= 0xFF; } -// pclog("SB read %02X\n",sbreaddat); return dsp->sbreaddat; case 0xC: /*Write data ready*/ if (dsp->wb_full) @@ -627,7 +640,6 @@ void sb_dsp_init(sb_dsp_t *dsp, int type) void sb_dsp_setaddr(sb_dsp_t *dsp, uint16_t addr) { -// pclog("sb_dsp_setaddr : %04X\n", addr); io_removehandler(dsp->sb_addr + 6, 0x0002, sb_read, NULL, NULL, sb_write, NULL, NULL, dsp); io_removehandler(dsp->sb_addr + 0xa, 0x0006, sb_read, NULL, NULL, sb_write, NULL, NULL, dsp); dsp->sb_addr = addr; @@ -649,13 +661,11 @@ void pollsb(void *p) int tempi,ref; dsp->sbcount += dsp->sblatcho; -// pclog("PollSB %i %i %i %i\n",sb_8_enable,sb_8_pause,sb_pausetime,sb_8_output); if (dsp->sb_8_enable && !dsp->sb_8_pause && dsp->sb_pausetime < 0 && dsp->sb_8_output) { int data[2]; sb_dsp_update(dsp); -// pclog("Dopoll %i %02X %i\n", sb_8_length, sb_8_format, sblatcho); switch (dsp->sb_8_format) { case 0x00: /*Mono unsigned*/ @@ -805,9 +815,6 @@ void pollsb(void *p) else dsp->sbdatl = dsp->sbdatr = dsp->sbdat; break; - -// default: - //fatal("Unrecognised SB 8-bit format %02X\n",sb_8_format); } if (dsp->sb_8_length < 0) @@ -841,14 +848,10 @@ void pollsb(void *p) dsp->sbdatr = sb_16_read_dma(dsp); dsp->sb_16_length -= 2; break; - -// default: -// fatal("Unrecognised SB 16-bit format %02X\n",sb_16_format); } if (dsp->sb_16_length < 0) { -// pclog("16DMA over %i\n",dsp->sb_16_autoinit); if (dsp->sb_16_autoinit) dsp->sb_16_length = dsp->sb_16_autolen; else dsp->sb_16_enable = dsp->sbenable = 0; sb_irq(dsp, 0); @@ -861,7 +864,6 @@ void pollsb(void *p) { sb_irq(dsp, 1); dsp->sbenable = dsp->sb_8_enable; -// pclog("SB pause over\n"); } } } @@ -871,7 +873,6 @@ void sb_poll_i(void *p) sb_dsp_t *dsp = (sb_dsp_t *)p; dsp->sb_count_i += dsp->sblatchi; -// pclog("PollSBi %i %i %i %i\n",sb_8_enable,sb_8_pause,sb_pausetime,sb_8_output); if (dsp->sb_8_enable && !dsp->sb_8_pause && dsp->sb_pausetime < 0 && !dsp->sb_8_output) { switch (dsp->sb_8_format) @@ -894,14 +895,10 @@ void sb_poll_i(void *p) sb_8_write_dma(dsp, 0x00); dsp->sb_8_length -= 2; break; - -// default: -// fatal("Unrecognised SB 8-bit input format %02X\n",sb_8_format); } if (dsp->sb_8_length < 0) { -// pclog("Input DMA over %i\n",sb_8_autoinit); if (dsp->sb_8_autoinit) dsp->sb_8_length = dsp->sb_8_autolen; else dsp->sb_8_enable = dsp->sbenable = 0; sb_irq(dsp, 1); @@ -929,14 +926,10 @@ void sb_poll_i(void *p) sb_16_write_dma(dsp, 0); dsp->sb_16_length -= 2; break; - -// default: -// fatal("Unrecognised SB 16-bit input format %02X\n",sb_16_format); } if (dsp->sb_16_length < 0) { -// pclog("16iDMA over %i\n",sb_16_autoinit); if (dsp->sb_16_autoinit) dsp->sb_16_length = dsp->sb_16_autolen; else dsp->sb_16_enable = dsp->sbenable = 0; sb_irq(dsp, 0); @@ -956,7 +949,6 @@ void sb_dsp_update(sb_dsp_t *dsp) void sb_dsp_add_status_info(char *s, int max_len, sb_dsp_t *dsp) { char temps[128]; - int len; int freq; if (dsp->sb_timeo < 256) diff --git a/src/sound_sb_dsp.h b/src/SOUND/snd_sb_dsp.h similarity index 96% rename from src/sound_sb_dsp.h rename to src/SOUND/snd_sb_dsp.h index 9d4dee133..fb14284fa 100644 --- a/src/sound_sb_dsp.h +++ b/src/SOUND/snd_sb_dsp.h @@ -1,5 +1,9 @@ typedef struct sb_dsp_t -{ +{ + int uart_midi; + int uart_irq; + int onebyte_midi; + int sb_type; int sb_8_length, sb_8_format, sb_8_autoinit, sb_8_pause, sb_8_enable, sb_8_autolen, sb_8_output; diff --git a/src/sound_sn76489.c b/src/SOUND/snd_sn76489.c similarity index 98% rename from src/sound_sn76489.c rename to src/SOUND/snd_sn76489.c index 2dae07669..574769322 100644 --- a/src/sound_sn76489.c +++ b/src/SOUND/snd_sn76489.c @@ -1,12 +1,15 @@ #include -#include "ibm.h" -#include "device.h" -#include "io.h" +#include +#include "../ibm.h" +#include "../io.h" +#include "../device.h" #include "sound.h" -#include "sound_sn76489.h" +#include "snd_sn76489.h" + int sn76489_mute; + static float volslog[16]= { 0.00000f,0.59715f,0.75180f,0.94650f, @@ -15,8 +18,6 @@ static float volslog[16]= 7.51785f,9.46440f,11.9194f,15.0000f }; -//#define PSGCONST ((3579545.0 / 64.0) / 48000.0) - void sn76489_update(sn76489_t *sn76489) { for (; sn76489->pos < sound_pos_global; sn76489->pos++) diff --git a/src/sound_sn76489.h b/src/SOUND/snd_sn76489.h similarity index 100% rename from src/sound_sn76489.h rename to src/SOUND/snd_sn76489.h diff --git a/src/sound_speaker.c b/src/SOUND/snd_speaker.c similarity index 88% rename from src/sound_speaker.c rename to src/SOUND/snd_speaker.c index 8e678253e..3ac8298a9 100644 --- a/src/sound_speaker.c +++ b/src/SOUND/snd_speaker.c @@ -1,21 +1,24 @@ -#include "ibm.h" +#include "../ibm.h" #include "sound.h" -#include "sound_speaker.h" +#include "snd_speaker.h" + int speaker_mute = 0; - -static int16_t speaker_buffer[SOUNDBUFLEN]; - -static int speaker_pos = 0; - int speaker_gated = 0; int speaker_enable = 0, was_speaker_enable = 0; -void speaker_update() + +int gated,speakval,speakon; + + +static int16_t speaker_buffer[SOUNDBUFLEN]; +static int speaker_pos = 0; + + +void speaker_update(void) { int16_t val; -// printf("SPeaker - %i %i %i %02X\n",speakval,gated,speakon,pit.m[2]); for (; speaker_pos < sound_pos_global; speaker_pos++) { if (speaker_gated && was_speaker_enable) @@ -52,7 +55,8 @@ static void speaker_get_buffer(int32_t *buffer, int len, void *p) speaker_pos = 0; } -void speaker_init() + +void speaker_init(void) { sound_add_handler(speaker_get_buffer, NULL); speaker_mute = 0; diff --git a/src/sound_speaker.h b/src/SOUND/snd_speaker.h similarity index 100% rename from src/sound_speaker.h rename to src/SOUND/snd_speaker.h diff --git a/src/sound_ssi2001.c b/src/SOUND/snd_ssi2001.c similarity index 94% rename from src/sound_ssi2001.c rename to src/SOUND/snd_ssi2001.c index fd675c309..d42898b9d 100644 --- a/src/sound_ssi2001.c +++ b/src/SOUND/snd_ssi2001.c @@ -1,10 +1,11 @@ #include -#include "ibm.h" -#include "device.h" +#include "../ibm.h" +#include "../io.h" +#include "../device.h" #include "sound.h" +#include "snd_resid.h" +#include "snd_ssi2001.h" -#include "sound_resid.h" -#include "sound_ssi2001.h" typedef struct ssi2001_t { diff --git a/src/sound_ssi2001.h b/src/SOUND/snd_ssi2001.h similarity index 100% rename from src/sound_ssi2001.h rename to src/SOUND/snd_ssi2001.h diff --git a/src/sound_wss.c b/src/SOUND/snd_wss.c similarity index 83% rename from src/sound_wss.c rename to src/SOUND/snd_wss.c index b5fecd08f..a58bc0b64 100644 --- a/src/sound_wss.c +++ b/src/SOUND/snd_wss.c @@ -2,17 +2,18 @@ Windows Sound System emulation*/ -#include #include -#include "ibm.h" +#include +#include "../ibm.h" +#include "../io.h" +#include "../pic.h" +#include "../dma.h" +#include "../device.h" +#include "sound.h" +#include "snd_ad1848.h" +#include "snd_opl.h" +#include "snd_wss.h" -#include "device.h" -#include "dma.h" -#include "io.h" -#include "pic.h" -#include "sound_ad1848.h" -#include "sound_opl.h" -#include "sound_wss.h" /*530, 11, 3 - 530=23*/ /*530, 11, 1 - 530=22*/ @@ -27,7 +28,7 @@ static int wss_dma[4] = {0, 0, 1, 3}; static int wss_irq[8] = {5, 7, 9, 10, 11, 12, 14, 15}; /*W95 only uses 7-9, others may be wrong*/ -static uint16_t wss_addr[4] = {0x530, 0x604, 0xe80, 0xf40}; + typedef struct wss_t { @@ -41,16 +42,13 @@ uint8_t wss_read(uint16_t addr, void *p) { wss_t *wss = (wss_t *)p; uint8_t temp; -// pclog("wss_read - addr %04X %04X(%08X):%08X ", addr, CS, cs, pc); temp = 4 | (wss->config & 0x40); -// pclog("return %02X\n", temp); return temp; } void wss_write(uint16_t addr, uint8_t val, void *p) { wss_t *wss = (wss_t *)p; -// pclog("wss_write - addr %04X val %02X %04X(%08X):%08X\n", addr, val, CS, cs, pc); wss->config = val; ad1848_setdma(&wss->ad1848, wss_dma[val & 3]); @@ -78,8 +76,6 @@ static void wss_get_buffer(int32_t *buffer, int len, void *p) void *wss_init() { wss_t *wss = malloc(sizeof(wss_t)); - int c; - double attenuation; memset(wss, 0, sizeof(wss_t)); diff --git a/src/sound_wss.h b/src/SOUND/snd_wss.h similarity index 100% rename from src/sound_wss.h rename to src/SOUND/snd_wss.h diff --git a/src/sound_ym7128.c b/src/SOUND/snd_ym7128.c similarity index 84% rename from src/sound_ym7128.c rename to src/SOUND/snd_ym7128.c index 7c1aa06ff..4bea44f53 100644 --- a/src/sound_ym7128.c +++ b/src/SOUND/snd_ym7128.c @@ -1,9 +1,11 @@ -#include "ibm.h" -#include "sound_ym7128.h" +#include "../ibm.h" +#include "snd_ym7128.h" + static int attenuation[32]; static int tap_position[32]; + void ym7128_init(ym7128_t *ym7128) { int c; @@ -27,46 +29,37 @@ void ym7128_write(ym7128_t *ym7128, uint8_t val) int new_dat = val & 1; int new_sci = val & 2; int new_a0 = val & 4; -// pclog("ym7128_write %i %i %i\n", new_dat, new_sci, new_a0); if (!ym7128->sci && new_sci) ym7128->dat = (ym7128->dat << 1) | new_dat; if (ym7128->a0 != new_a0) { -// pclog("ym7128 write %i %02x\n", ym7128->a0, ym7128->dat); if (!ym7128->a0) ym7128->reg_sel = ym7128->dat & 0x1f; else { -// pclog("YM7128 write %02x %02x\n", ym7128->reg_sel, ym7128->dat); switch (ym7128->reg_sel) { case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07: ym7128->gl[ym7128->reg_sel & 7] = GET_ATTENUATION(ym7128->dat); -// pclog(" GL[%i] = %04x\n", ym7128->reg_sel & 7, GET_ATTENUATION(ym7128->dat)); break; case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f: ym7128->gr[ym7128->reg_sel & 7] = GET_ATTENUATION(ym7128->dat); -// pclog(" GR[%i] = %04x\n", ym7128->reg_sel & 7, GET_ATTENUATION(ym7128->dat)); break; case 0x10: ym7128->vm = GET_ATTENUATION(ym7128->dat); -// pclog(" VM = %04x\n", GET_ATTENUATION(ym7128->dat)); break; case 0x11: ym7128->vc = GET_ATTENUATION(ym7128->dat); -// pclog(" VC = %04x\n", GET_ATTENUATION(ym7128->dat)); break; case 0x12: ym7128->vl = GET_ATTENUATION(ym7128->dat); -// pclog(" VL = %04x\n", GET_ATTENUATION(ym7128->dat)); break; case 0x13: ym7128->vr = GET_ATTENUATION(ym7128->dat); -// pclog(" VR = %04x\n", GET_ATTENUATION(ym7128->dat)); break; case 0x14: @@ -83,7 +76,6 @@ void ym7128_write(ym7128_t *ym7128, uint8_t val) case 0x16: case 0x17: case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: ym7128->t[ym7128->reg_sel - 0x16] = tap_position[ym7128->dat & 0x1f]; -// pclog(" T[%i] = %i\n", ym7128->reg_sel - 0x16, tap_position[ym7128->dat & 0x1f]); break; } ym7128->regs[ym7128->reg_sel] = ym7128->dat; diff --git a/src/sound_ym7128.h b/src/SOUND/snd_ym7128.h similarity index 100% rename from src/sound_ym7128.h rename to src/SOUND/snd_ym7128.h diff --git a/src/SOUND/sound.c b/src/SOUND/sound.c new file mode 100644 index 000000000..addacdc8b --- /dev/null +++ b/src/SOUND/sound.c @@ -0,0 +1,448 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Sound emulation core. + * + * Version: @(#)sound.c 1.0.2 2017/06/14 + * + * Authors: Sarah Walker, + * Miran Grca, + * Copyright 2008-2017 Sarah Walker. + * Copyright 2016-2017 Miran Grca. + */ +#include +#include +#include +#include "../ibm.h" +#include "../device.h" +#include "../timer.h" +#include "../cdrom.h" +#include "../win/plat_thread.h" +#include "midi.h" +#include "sound.h" +#include "snd_opl.h" +#include "snd_adlib.h" +#include "snd_adlibgold.h" +#if 0 +#include "snd_pas16.h" +#endif +#include "snd_sb.h" +#include "snd_sb_dsp.h" +#include "snd_wss.h" +#include "filters.h" + + +int sound_card_current = 0; +static int sound_card_last = 0; + + +typedef struct +{ + char name[64]; + char internal_name[24]; + device_t *device; +} SOUND_CARD; + +static SOUND_CARD sound_cards[] = +{ + { "None", "none", NULL }, + { "Adlib", "adlib", &adlib_device }, + { "Adlib MCA", "adlib_mca", &adlib_mca_device }, + { "Sound Blaster 1.0", "sb", &sb_1_device }, + { "Sound Blaster 1.5", "sb1.5", &sb_15_device }, + { "Sound Blaster MCV", "sbmcv", &sb_mcv_device }, + { "Sound Blaster 2.0", "sb2.0", &sb_2_device }, + { "Sound Blaster Pro v1", "sbprov1", &sb_pro_v1_device }, + { "Sound Blaster Pro v2", "sbprov2", &sb_pro_v2_device }, + { "Sound Blaster Pro MCV", "sbpromcv", &sb_pro_mcv_device }, + { "Sound Blaster 16", "sb16", &sb_16_device }, + { "Sound Blaster AWE32", "sbawe32", &sb_awe32_device }, + { "Adlib Gold", "adlibgold", &adgold_device }, + { "Windows Sound System", "wss", &wss_device }, +#if 0 + { "Pro Audio Spectrum 16", "pas16", &pas16_device }, +#endif + { "", "", NULL } +}; + + +int sound_card_available(int card) +{ + if (sound_cards[card].device) + return device_available(sound_cards[card].device); + + return 1; +} + +char *sound_card_getname(int card) +{ + return sound_cards[card].name; +} + +device_t *sound_card_getdevice(int card) +{ + return sound_cards[card].device; +} + +int sound_card_has_config(int card) +{ + if (!sound_cards[card].device) + return 0; + return sound_cards[card].device->config ? 1 : 0; +} + +char *sound_card_get_internal_name(int card) +{ + return sound_cards[card].internal_name; +} + +int sound_card_get_from_internal_name(char *s) +{ + int c = 0; + + while (strlen(sound_cards[c].internal_name)) + { + if (!strcmp(sound_cards[c].internal_name, s)) + return c; + c++; + } + + return 0; +} + +void sound_card_init(void) +{ + if (sound_cards[sound_card_current].device) + device_add(sound_cards[sound_card_current].device); + sound_card_last = sound_card_current; +} + +static struct +{ + void (*get_buffer)(int32_t *buffer, int len, void *p); + void *priv; +} sound_handlers[8]; + +static int sound_handlers_num; + +static int sound_poll_time = 0, sound_poll_latch; +int sound_pos_global = 0; + +int soundon = 1; + +static int16_t cd_buffer[CDROM_NUM][CD_BUFLEN * 2]; +static float cd_out_buffer[CD_BUFLEN * 2]; +static int16_t cd_out_buffer_int16[CD_BUFLEN * 2]; +static thread_t *sound_cd_thread_h; +static event_t *sound_cd_event; +static unsigned int cd_vol_l, cd_vol_r; +static int cd_buf_update = CD_BUFLEN / SOUNDBUFLEN; + +int sound_is_float = 1; + +void sound_set_cd_volume(unsigned int vol_l, unsigned int vol_r) +{ + cd_vol_l = vol_l; + cd_vol_r = vol_r; +} + +static void sound_cd_thread(void *param) +{ + int i = 0; + + float cd_buffer_temp[2] = {0.0, 0.0}; + float cd_buffer_temp2[2] = {0.0, 0.0}; + + int c, has_audio; + + while (1) + { + thread_wait_event(sound_cd_event, -1); + if (!soundon) + { + return; + } + for (c = 0; c < CD_BUFLEN*2; c += 2) + { + if (sound_is_float) + { + cd_out_buffer[c] = 0.0; + cd_out_buffer[c+1] = 0.0; + } + else + { + cd_out_buffer_int16[c] = 0; + cd_out_buffer_int16[c+1] = 0; + } + } + for (i = 0; i < CDROM_NUM; i++) + { + has_audio = 0; + if (cdrom_drives[i].handler->audio_callback) + { + cdrom_drives[i].handler->audio_callback(i, cd_buffer[i], CD_BUFLEN*2); + has_audio = (cdrom_drives[i].bus_type && cdrom_drives[i].sound_on); + } + if (soundon && has_audio) + { + int32_t audio_vol_l = cdrom_mode_sense_get_volume(i, 0); + int32_t audio_vol_r = cdrom_mode_sense_get_volume(i, 1); + int channel_select[2]; + + channel_select[0] = cdrom_mode_sense_get_channel(i, 0); + channel_select[1] = cdrom_mode_sense_get_channel(i, 1); + + for (c = 0; c < CD_BUFLEN*2; c += 2) + { + /* First, transfer the CD audio data to the temporary buffer. */ + cd_buffer_temp[0] = (float) cd_buffer[i][c]; + cd_buffer_temp[1] = (float) cd_buffer[i][c+1]; + + /* Then, adjust input from drive according to ATAPI/SCSI volume. */ + cd_buffer_temp[0] *= (float) audio_vol_l; + cd_buffer_temp[0] /= 511.0; + cd_buffer_temp[1] *= (float) audio_vol_r; + cd_buffer_temp[1] /= 511.0; + + /*Apply ATAPI channel select*/ + cd_buffer_temp2[0] = cd_buffer_temp2[1] = 0.0; + if (channel_select[0] & 1) + { + cd_buffer_temp2[0] += cd_buffer_temp[0]; + } + if (channel_select[0] & 2) + { + cd_buffer_temp2[1] += cd_buffer_temp[0]; + } + if (channel_select[1] & 1) + { + cd_buffer_temp2[0] += cd_buffer_temp[1]; + } + if (channel_select[1] & 2) + { + cd_buffer_temp2[1] += cd_buffer_temp[1]; + } + + /*Apply sound card CD volume*/ + cd_buffer_temp2[0] *= (float) cd_vol_l; + cd_buffer_temp2[0] /= 65535.0; + + cd_buffer_temp2[1] *= (float) cd_vol_r; + cd_buffer_temp2[1] /= 65535.0; + + if (sound_is_float) + { + cd_out_buffer[c] += (cd_buffer_temp2[0] / 32768.0); + cd_out_buffer[c+1] += (cd_buffer_temp2[1] / 32768.0); + } + else + { + if (cd_buffer_temp2[0] > 32767) + cd_buffer_temp2[0] = 32767; + if (cd_buffer_temp2[0] < -32768) + cd_buffer_temp2[0] = -32768; + if (cd_buffer_temp2[1] > 32767) + cd_buffer_temp2[1] = 32767; + if (cd_buffer_temp2[1] < -32768) + cd_buffer_temp2[1] = -32768; + + cd_out_buffer_int16[c] += cd_buffer_temp2[0]; + cd_out_buffer_int16[c+1] += cd_buffer_temp2[1]; + } + } + } + } + if (sound_is_float) + { + givealbuffer_cd(cd_out_buffer); + } + else + { + givealbuffer_cd(cd_out_buffer_int16); + } + } +} + +static int32_t *outbuffer; +static float *outbuffer_ex; +static int16_t *outbuffer_ex_int16; + +static int cd_thread_enable = 0; + +void sound_realloc_buffers(void) +{ + if (outbuffer_ex != NULL) + { + free(outbuffer_ex); + } + + if (outbuffer_ex_int16 != NULL) + { + free(outbuffer_ex_int16); + } + + if (sound_is_float) + { + outbuffer_ex = malloc(SOUNDBUFLEN * 2 * sizeof(float)); + } + else + { + outbuffer_ex_int16 = malloc(SOUNDBUFLEN * 2 * sizeof(int16_t)); + } +} + +void sound_init(void) +{ + int i = 0; + int available_cdrom_drives = 0; + + initalmain(0,NULL); + inital(); + + outbuffer_ex = NULL; + outbuffer_ex_int16 = NULL; + + outbuffer = malloc(SOUNDBUFLEN * 2 * sizeof(int32_t)); + + sound_realloc_buffers(); + + for (i = 0; i < CDROM_NUM; i++) + { + if (cdrom_drives[i].bus_type != CDROM_BUS_DISABLED) + { + available_cdrom_drives++; + } + } + + if (available_cdrom_drives) + { + sound_cd_event = thread_create_event(); + sound_cd_thread_h = thread_create(sound_cd_thread, NULL); + } + + cd_thread_enable = available_cdrom_drives ? 1 : 0; +} + +void sound_add_handler(void (*get_buffer)(int32_t *buffer, int len, void *p), void *p) +{ + sound_handlers[sound_handlers_num].get_buffer = get_buffer; + sound_handlers[sound_handlers_num].priv = p; + sound_handlers_num++; +} + +void sound_poll(void *priv) +{ + sound_poll_time += sound_poll_latch; + + midi_poll(); + + sound_pos_global++; + if (sound_pos_global == SOUNDBUFLEN) + { + int c; + + memset(outbuffer, 0, SOUNDBUFLEN * 2 * sizeof(int32_t)); + + for (c = 0; c < sound_handlers_num; c++) + sound_handlers[c].get_buffer(outbuffer, SOUNDBUFLEN, sound_handlers[c].priv); + + + for (c = 0; c < SOUNDBUFLEN * 2; c++) + { + if (sound_is_float) + { + outbuffer_ex[c] = ((float) outbuffer[c]) / 32768.0; + } + else + { + if (outbuffer[c] > 32767) + outbuffer[c] = 32767; + if (outbuffer[c] < -32768) + outbuffer[c] = -32768; + + outbuffer_ex_int16[c] = outbuffer[c]; + } + } + + if (soundon) + { + if (sound_is_float) + { + givealbuffer(outbuffer_ex); + } + else + { + givealbuffer(outbuffer_ex_int16); + } + } + + if (cd_thread_enable) + { + cd_buf_update--; + if (!cd_buf_update) + { + cd_buf_update = (48000 / SOUNDBUFLEN) / (CD_FREQ / CD_BUFLEN); + thread_set_event(sound_cd_event); + } + } + + sound_pos_global = 0; + } +} + +void sound_speed_changed(void) +{ + sound_poll_latch = (int)((double)TIMER_USEC * (1000000.0 / 48000.0)); +} + +void sound_reset(void) +{ + int i = 0; + + timer_add(sound_poll, &sound_poll_time, TIMER_ALWAYS_ENABLED, NULL); + + sound_handlers_num = 0; + + sound_set_cd_volume(65535, 65535); + + for (i = 0; i < CDROM_NUM; i++) + { + if (cdrom_drives[i].handler->audio_stop) + { + cdrom_drives[i].handler->audio_stop(i); + } + } +} + +void sound_cd_thread_reset(void) +{ + int i = 0; + int available_cdrom_drives = 0; + + for (i = 0; i < CDROM_NUM; i++) + { + if (cdrom_drives[i].bus_type != CDROM_BUS_DISABLED) + { + available_cdrom_drives++; + } + } + + if (available_cdrom_drives && !cd_thread_enable) + { + sound_cd_event = thread_create_event(); + sound_cd_thread_h = thread_create(sound_cd_thread, NULL); + } + else if (!available_cdrom_drives && cd_thread_enable) + { + thread_destroy_event(sound_cd_event); + thread_kill(sound_cd_thread_h); + sound_cd_thread_h = NULL; + } + + cd_thread_enable = available_cdrom_drives ? 1 : 0; +} diff --git a/src/SOUND/sound.h b/src/SOUND/sound.h new file mode 100644 index 000000000..9afdaa902 --- /dev/null +++ b/src/SOUND/sound.h @@ -0,0 +1,50 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Sound emulation core. + * + * Version: @(#)sound.h 1.0.1 2017/06/14 + * + * Author: Sarah Walker, + * Miran Grca, + * Copyright 2008-2017 Sarah Walker. + * Copyright 2016-2017 Miran Grca. + */ + +void sound_add_handler(void (*get_buffer)(int32_t *buffer, int len, void *p), void *p); + +extern int sound_card_current; + +int sound_card_available(int card); +char *sound_card_getname(int card); +struct device_t *sound_card_getdevice(int card); +int sound_card_has_config(int card); +char *sound_card_get_internal_name(int card); +int sound_card_get_from_internal_name(char *s); +void sound_card_init(); +void sound_set_cd_volume(unsigned int vol_l, unsigned int vol_r); + +#define CD_FREQ 44100 +#define CD_BUFLEN (CD_FREQ / 10) + +extern int sound_pos_global; +void sound_speed_changed(); + +extern int sound_is_float; +void sound_realloc_buffers(void); + +void sound_init(); +void sound_reset(); + +void sound_cd_thread_reset(); + +void closeal(void); +void initalmain(int argc, char *argv[]); +void inital(); +void givealbuffer(void *buf); +void givealbuffer_cd(void *buf); diff --git a/src/vid_ati18800.c b/src/VIDEO/vid_ati18800.c similarity index 93% rename from src/vid_ati18800.c rename to src/VIDEO/vid_ati18800.c index 74cc6be64..ecbb4fe40 100644 --- a/src/vid_ati18800.c +++ b/src/VIDEO/vid_ati18800.c @@ -3,16 +3,17 @@ */ /*ATI 18800 emulation (VGA Edge-16)*/ #include -#include "ibm.h" -#include "device.h" -#include "io.h" -#include "mem.h" -#include "rom.h" +#include "../ibm.h" +#include "../io.h" +#include "../mem.h" +#include "../rom.h" +#include "../device.h" #include "video.h" #include "vid_ati18800.h" #include "vid_ati_eeprom.h" #include "vid_svga.h" + typedef struct ati18800_t { svga_t svga; @@ -30,8 +31,6 @@ void ati18800_out(uint16_t addr, uint8_t val, void *p) svga_t *svga = &ati18800->svga; uint8_t old; -// pclog("ati18800_out : %04X %02X %04X:%04X\n", addr, val, CS,cpu_state.pc); - if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) addr ^= 0x60; @@ -106,8 +105,6 @@ uint8_t ati18800_in(uint16_t addr, void *p) svga_t *svga = &ati18800->svga; uint8_t temp; -// if (addr != 0x3da) pclog("ati18800_in : %04X ", addr); - if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga->miscout&1)) addr ^= 0x60; switch (addr) @@ -123,7 +120,6 @@ uint8_t ati18800_in(uint16_t addr, void *p) if (ati_eeprom_read(&ati18800->eeprom)) temp |= 8; break; - default: temp = ati18800->regs[ati18800->index]; break; @@ -167,7 +163,7 @@ void *ati18800_init() ati18800_t *ati18800 = malloc(sizeof(ati18800_t)); memset(ati18800, 0, sizeof(ati18800_t)); - rom_init(&ati18800->bios_rom, "roms/vgaedge16.vbi", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + rom_init(&ati18800->bios_rom, L"roms/vga88.BIN", 0xc0000, 0x10000, 0xffff, 0, MEM_MAPPING_EXTERNAL); svga_init(&ati18800->svga, ati18800, 1 << 19, /*512kb*/ NULL, @@ -180,14 +176,14 @@ void *ati18800_init() ati18800->svga.miscout = 1; - ati_eeprom_load(&ati18800->eeprom, "ati18800.nvr", 0); + ati_eeprom_load(&ati18800->eeprom, L"ati18800.nvr", 0); return ati18800; } static int ati18800_available() { - return rom_present("roms/vgaedge16.vbi"); + return rom_present(L"roms/vga88.BIN"); } void ati18800_close(void *p) diff --git a/src/vid_ati18800.h b/src/VIDEO/vid_ati18800.h similarity index 100% rename from src/vid_ati18800.h rename to src/VIDEO/vid_ati18800.h diff --git a/src/vid_ati28800.c b/src/VIDEO/vid_ati28800.c similarity index 86% rename from src/vid_ati28800.c rename to src/VIDEO/vid_ati28800.c index 0db9a6b09..84d8ec8e4 100644 --- a/src/vid_ati28800.c +++ b/src/VIDEO/vid_ati28800.c @@ -3,17 +3,18 @@ */ /*ATI 28800 emulation (VGA Charger)*/ #include -#include "ibm.h" -#include "device.h" -#include "io.h" -#include "mem.h" -#include "rom.h" +#include "../ibm.h" +#include "../io.h" +#include "../mem.h" +#include "../rom.h" +#include "../device.h" +#include "../timer.h" #include "video.h" #include "vid_ati28800.h" #include "vid_ati_eeprom.h" #include "vid_svga.h" #include "vid_svga_render.h" -#include "timer.h" + typedef struct ati28800_t { @@ -34,8 +35,6 @@ void ati28800_out(uint16_t addr, uint8_t val, void *p) svga_t *svga = &ati28800->svga; uint8_t old; -// pclog("ati28800_out : %04X %02X %04X:%04X\n", addr, val, CS,cpu_state.pc); - if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga->miscout&1)) addr ^= 0x60; @@ -46,6 +45,7 @@ void ati28800_out(uint16_t addr, uint8_t val, void *p) break; case 0x1cf: ati28800->regs[ati28800->index & 0x3f] = val; + pclog("ATI 28800 ATI register write %02x %02x\n", ati28800->index, val); switch (ati28800->index & 0x3f) { case 0x2d: @@ -103,8 +103,6 @@ uint8_t ati28800_in(uint16_t addr, void *p) svga_t *svga = &ati28800->svga; uint8_t temp; -// if (addr != 0x3da) pclog("ati28800_in : %04X ", addr); - if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga->miscout&1)) addr ^= 0x60; switch (addr) @@ -157,7 +155,6 @@ void ati28800_svga_recalctimings(ati28800_t *ati28800) { double crtcconst; double _dispontime, _dispofftime, disptime; - int hdisp_old; svga_t *svga = &ati28800->svga; svga->vtotal = svga->crtc[6]; @@ -279,8 +276,6 @@ void ati28800_svga_recalctimings(ati28800_t *ati28800) } } -// pclog("svga_render %08X : %08X %08X %08X %08X %08X %i %i %02X %i %i\n", svga_render, svga_render_text_40, svga_render_text_80, svga_render_8bpp_lowres, svga_render_8bpp_highres, svga_render_blank, scrblank,gdcreg[6]&1,gdcreg[5]&0x60,bpp,seqregs[1]&8); - svga->linedbl = svga->crtc[9] & 0x80; svga->rowcount = svga->crtc[9] & 31; if (svga->recalctimings_ex) @@ -294,7 +289,6 @@ void ati28800_svga_recalctimings(ati28800_t *ati28800) disptime = svga->htotal; _dispontime = svga->hdisp_time; -// printf("Disptime %f dispontime %f hdisp %i\n",disptime,dispontime,crtc[1]*8); if (svga->seqregs[1] & 8) { disptime *= 2; _dispontime *= 2; } _dispofftime = disptime - _dispontime; _dispontime *= crtcconst; @@ -312,16 +306,44 @@ void ati28800_svga_recalctimings(ati28800_t *ati28800) void ati28800_recalctimings(svga_t *svga) { ati28800_t *ati28800 = (ati28800_t *)svga->p; + uint8_t clock_sel = (svga->miscout >> 2) & 3; + double freq; + #ifndef RELEASE_BUILD pclog("ati28800_recalctimings\n"); #endif - svga->interlace = (!svga->scrblank && (ati28800->regs[0x30] & 0x20)); + svga->interlace = (!svga->scrblank && (ati28800->regs[0x3e] & 2)); + + clock_sel |= (ati28800->regs[0x39] & 2) << 2; + clock_sel |= (ati28800->regs[0x3e] & 0x10) >> 1; + switch(clock_sel) + { + case 0x00: freq = 42954000; break; + case 0x01: freq = 48771000; break; + case 0x02: freq = 16657000; break; + case 0x03: freq = 36000000; break; + case 0x04: freq = 50350000; break; + case 0x05: freq = 56640000; break; + case 0x06: freq = 28322000; break; + case 0x07: freq = 44900000; break; + case 0x08: freq = 30240000; break; + case 0x09: freq = 32000000; break; + case 0x0a: freq = 37500000; break; + case 0x0b: freq = 39000000; break; + case 0x0c: freq = 40000000; break; + case 0x0d: freq = 56644000; break; + case 0x0e: freq = 75000000; break; + case 0x0f: freq = 65000000; break; + } + + svga->clock = cpuclock / freq; if (!svga->scrblank && (ati28800->regs[0x30] & 0x20)) /*Extended 256 colour modes*/ { #ifndef RELEASE_BUILD pclog("8bpp_highres\n"); #endif + svga->bpp = 8; svga->render = svga_render_8bpp_highres; svga->rowoffset <<= 1; svga->ma <<= 1; @@ -340,19 +362,19 @@ void *ati28800_init() if (gfxcard == GFX_VGAWONDERXL) { rom_init_interleaved(&ati28800->bios_rom, - "roms/XLEVEN.BIN", - "roms/XLODD.BIN", + L"roms/XLEVEN.BIN", + L"roms/XLODD.BIN", 0xc0000, 0x10000, 0xffff, 0, MEM_MAPPING_EXTERNAL); } else if (gfxcard == GFX_VGAWONDERXL24) { rom_init_interleaved(&ati28800->bios_rom, - "roms/112-14318-102.bin", - "roms/112-14319-102.bin", + L"roms/112-14318-102.bin", + L"roms/112-14319-102.bin", 0xc0000, 0x10000, 0xffff, 0, MEM_MAPPING_EXTERNAL); } else - rom_init(&ati28800->bios_rom, "roms/bios.bin", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + rom_init(&ati28800->bios_rom, L"roms/bios.bin", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); svga_init(&ati28800->svga, ati28800, memory, /*512kb*/ ati28800_recalctimings, @@ -365,24 +387,24 @@ void *ati28800_init() ati28800->svga.miscout = 1; - ati_eeprom_load(&ati28800->eeprom, "ati28800.nvr", 0); + ati_eeprom_load(&ati28800->eeprom, L"ati28800.nvr", 0); return ati28800; } static int ati28800_available() { - return rom_present("roms/bios.bin"); + return rom_present(L"roms/bios.bin"); } static int compaq_ati28800_available() { - return (rom_present("roms/XLEVEN.bin") && rom_present("roms/XLODD.bin")); + return (rom_present(L"roms/XLEVEN.bin") && rom_present(L"roms/XLODD.bin")); } static int ati28800_wonderxl24_available() { - return (rom_present("roms/112-14318-102.bin") && rom_present("roms/112-14319-102.bin")); + return (rom_present(L"roms/112-14318-102.bin") && rom_present(L"roms/112-14319-102.bin")); } void ati28800_close(void *p) @@ -418,58 +440,45 @@ void ati28800_add_status_info(char *s, int max_len, void *p) static device_config_t ati28800_config[] = { { - .name = "memory", - .description = "Memory size", - .type = CONFIG_SELECTION, - .selection = + "memory", "Memory size", CONFIG_SELECTION, "", 512, { { - .description = "256 kB", - .value = 256 + "256 kB", 256 }, { - .description = "512 kB", - .value = 512 + "512 kB", 512 }, { - .description = "" + "" } - }, - .default_int = 512 + } }, { - .type = -1 + "", "", -1 } }; static device_config_t ati28800_wonderxl_config[] = { { - .name = "memory", - .description = "Memory size", - .type = CONFIG_SELECTION, - .selection = + "memory", "Memory size", CONFIG_SELECTION, "", 512, { { - .description = "256 kB", - .value = 256 + "256 kB", 256 }, { - .description = "512 kB", - .value = 512 + "512 kB", 512 }, { - .description = "1 MB", - .value = 1024 + "1 MB", 1024 }, { - .description = "" + "" } - }, - .default_int = 512 + } }, { - .type = -1 + "", "", -1 } }; diff --git a/src/vid_ati28800.h b/src/VIDEO/vid_ati28800.h similarity index 100% rename from src/vid_ati28800.h rename to src/VIDEO/vid_ati28800.h diff --git a/src/vid_ati68860_ramdac.c b/src/VIDEO/vid_ati68860_ramdac.c similarity index 97% rename from src/vid_ati68860_ramdac.c rename to src/VIDEO/vid_ati68860_ramdac.c index 58cc899c0..f1d1d6b84 100644 --- a/src/vid_ati68860_ramdac.c +++ b/src/VIDEO/vid_ati68860_ramdac.c @@ -21,16 +21,16 @@ bit 0 Controls 6/8bit DAC. 0: 8bit DAC/LUT, 1: 6bit DAC/LUT 5-6 Always set ? 7 If set can remove "snow" in some cases (A860_Delay_L ?) ?? */ -#include "ibm.h" -#include "mem.h" +#include "../ibm.h" +#include "../mem.h" #include "video.h" #include "vid_svga.h" #include "vid_ati68860_ramdac.h" #include "vid_svga_render.h" + void ati68860_ramdac_out(uint16_t addr, uint8_t val, ati68860_ramdac_t *ramdac, svga_t *svga) { -// pclog("ati68860_out : addr %04X val %02X %04X:%04X\n", addr, val, CS,pc); switch (addr) { case 0: @@ -151,7 +151,6 @@ uint8_t ati68860_ramdac_in(uint16_t addr, ati68860_ramdac_t *ramdac, svga_t *svg ret = ramdac->regs[addr & 0xf]; break; } -// pclog("ati68860_in : addr %04X ret %02X %04X:%04X\n", addr, ret, CS,pc); return ret; } diff --git a/src/vid_ati68860_ramdac.h b/src/VIDEO/vid_ati68860_ramdac.h similarity index 100% rename from src/vid_ati68860_ramdac.h rename to src/VIDEO/vid_ati68860_ramdac.h diff --git a/src/vid_ati_eeprom.c b/src/VIDEO/vid_ati_eeprom.c similarity index 88% rename from src/vid_ati_eeprom.c rename to src/VIDEO/vid_ati_eeprom.c index 8111c30ab..198575a60 100644 --- a/src/vid_ati_eeprom.c +++ b/src/VIDEO/vid_ati_eeprom.c @@ -1,9 +1,12 @@ /* Copyright holders: Sarah Walker see COPYING for more details */ -#include "ibm.h" +#include "../ibm.h" +#include "../mem.h" +#include "../rom.h" #include "vid_ati_eeprom.h" + enum { EEPROM_IDLE, @@ -31,12 +34,12 @@ enum EEPROM_OP_EWEN = 3 }; -void ati_eeprom_load(ati_eeprom_t *eeprom, char *fn, int type) +void ati_eeprom_load(ati_eeprom_t *eeprom, wchar_t *fn, int type) { FILE *f; eeprom->type = type; - strcpy(eeprom->fn, fn); - f = romfopen(eeprom->fn, "rb"); + wcscpy(eeprom->fn, fn); + f = nvrfopen(eeprom->fn, L"rb"); if (!f) { memset(eeprom->data, 0, eeprom->type ? 512 : 128); @@ -48,7 +51,7 @@ void ati_eeprom_load(ati_eeprom_t *eeprom, char *fn, int type) void ati_eeprom_save(ati_eeprom_t *eeprom) { - FILE *f = romfopen(eeprom->fn, "wb"); + FILE *f = nvrfopen(eeprom->fn, L"wb"); if (!f) return; fwrite(eeprom->data, 1, eeprom->type ? 512 : 128, f); fclose(f); @@ -57,7 +60,6 @@ void ati_eeprom_save(ati_eeprom_t *eeprom) void ati_eeprom_write(ati_eeprom_t *eeprom, int ena, int clk, int dat) { int c; -// pclog("EEPROM write %i %i %i\n", ena, clk, dat); if (!ena) { eeprom->out = 1; @@ -73,7 +75,6 @@ void ati_eeprom_write(ati_eeprom_t *eeprom, int ena, int clk, int dat) } else if (ena) { -// pclog("EEPROM receive %i %i %i\n", ena, clk, dat); switch (eeprom->state) { case EEPROM_WAIT: @@ -86,7 +87,6 @@ void ati_eeprom_write(ati_eeprom_t *eeprom, int ena, int clk, int dat) eeprom->count--; if (!eeprom->count) { -// pclog("EEPROM opcode - %i\n", eeprom->opcode); switch (eeprom->opcode) { case EEPROM_OP_WRITE: @@ -118,11 +118,9 @@ void ati_eeprom_write(ati_eeprom_t *eeprom, int ena, int clk, int dat) eeprom->count--; if (!eeprom->count) { -// pclog("EEPROM dat - %02X\n", eeprom->dat); switch (eeprom->opcode) { case EEPROM_OP_WRITE: -// pclog("EEPROM_OP_WRITE addr %02X eeprom_dat %04X\n", (eeprom->dat >> 16) & (eeprom->type ? 255 : 63), eeprom->dat & 0xffff); if (!eeprom->wp) { eeprom->data[(eeprom->dat >> 16) & (eeprom->type ? 255 : 63)] = eeprom->dat & 0xffff; @@ -136,10 +134,8 @@ void ati_eeprom_write(ati_eeprom_t *eeprom, int ena, int clk, int dat) eeprom->count = 17; eeprom->state = EEPROM_OUTPUT; eeprom->dat = eeprom->data[eeprom->dat]; -// pclog("Trigger EEPROM_OUTPUT %04X\n", eeprom->dat); break; case EEPROM_OP_EW: -// pclog("EEPROM_OP_EW %i\n", eeprom->dat); switch (eeprom->dat) { case EEPROM_OP_EWDS: @@ -165,7 +161,6 @@ void ati_eeprom_write(ati_eeprom_t *eeprom, int ena, int clk, int dat) break; case EEPROM_OP_ERASE: -// pclog("EEPROM_OP_ERASE %i\n", eeprom->dat); if (!eeprom->wp) { eeprom->data[eeprom->dat] = 0xffff; @@ -176,7 +171,6 @@ void ati_eeprom_write(ati_eeprom_t *eeprom, int ena, int clk, int dat) break; case EEPROM_OP_WRALMAIN: -// pclog("EEPROM_OP_WRAL %04X\n", eeprom->dat); if (!eeprom->wp) { for (c = 0; c < 256; c++) @@ -202,11 +196,9 @@ void ati_eeprom_write(ati_eeprom_t *eeprom, int ena, int clk, int dat) case EEPROM_OUTPUT: eeprom->out = (eeprom->dat & 0x10000) ? 1 : 0; eeprom->dat <<= 1; -// pclog("EEPROM_OUTPUT - data %i\n", eeprom->out); eeprom->count--; if (!eeprom->count) { -// pclog("EEPROM_OUTPUT complete\n"); eeprom->state = EEPROM_IDLE; } break; diff --git a/src/vid_ati_eeprom.h b/src/VIDEO/vid_ati_eeprom.h similarity index 80% rename from src/vid_ati_eeprom.h rename to src/VIDEO/vid_ati_eeprom.h index 540f2c3f9..786ae0c8b 100644 --- a/src/vid_ati_eeprom.h +++ b/src/VIDEO/vid_ati_eeprom.h @@ -11,9 +11,9 @@ typedef struct ati_eeprom_t uint32_t dat; int type; - char fn[256]; + wchar_t fn[256]; } ati_eeprom_t; -void ati_eeprom_load(ati_eeprom_t *eeprom, char *fn, int type); +void ati_eeprom_load(ati_eeprom_t *eeprom, wchar_t *fn, int type); void ati_eeprom_write(ati_eeprom_t *eeprom, int ena, int clk, int dat); int ati_eeprom_read(ati_eeprom_t *eeprom); diff --git a/src/vid_ati_mach64.c b/src/VIDEO/vid_ati_mach64.c similarity index 68% rename from src/vid_ati_mach64.c rename to src/VIDEO/vid_ati_mach64.c index 27bf01adb..4d530c7b9 100644 --- a/src/vid_ati_mach64.c +++ b/src/VIDEO/vid_ati_mach64.c @@ -1,22 +1,38 @@ -/* Copyright holders: Sarah Walker - see COPYING for more details -*/ -/*ATI Mach64 emulation*/ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * ATi Mach64 graphics card emulation. + * + * Version: @(#)vid_ati_mach64.c 1.0.1 2017/06/04 + * + * Authors: Sarah Walker, + * Miran Grca, + * Copyright 2008-2017 Sarah Walker. + * Copyright 2016-2017 Miran Grca. + */ #include -#include "ibm.h" -#include "device.h" -#include "io.h" -#include "mem.h" -#include "pci.h" -#include "rom.h" -#include "thread.h" +#include "../ibm.h" +#include "../device.h" +#include "../io.h" +#include "../mem.h" +#include "../pci.h" +#include "../rom.h" +#include "../win/plat_thread.h" #include "video.h" #include "vid_svga.h" +#include "vid_svga_render.h" #include "vid_ati68860_ramdac.h" #include "vid_ati_eeprom.h" #include "vid_ics2595.h" -//#define MACH64_DEBUG +#ifdef CLAMP +#undef CLAMP +#endif #define FIFO_SIZE 65536 #define FIFO_MASK (FIFO_SIZE - 1) @@ -43,11 +59,18 @@ typedef struct uint32_t val; } fifo_entry_t; +enum +{ + MACH64_GX = 0, + MACH64_VT2 +}; + typedef struct mach64_t { mem_mapping_t linear_mapping; mem_mapping_t mmio_mapping; mem_mapping_t mmio_linear_mapping; + mem_mapping_t mmio_linear_mapping_2; ati68860_ramdac_t ramdac; ati_eeprom_t eeprom; @@ -59,7 +82,11 @@ typedef struct mach64_t uint8_t regs[256]; int index; + int type; + uint8_t pci_regs[256]; + uint8_t int_line; + int card; int bank_r[2]; int bank_w[2]; @@ -110,7 +137,9 @@ typedef struct mach64_t uint32_t gen_test_cntl; uint32_t gui_traj_cntl; - + + uint32_t host_cntl; + uint32_t mem_cntl; uint32_t ovr_clr; @@ -180,6 +209,35 @@ typedef struct mach64_t int blitter_busy; uint64_t blitter_time; uint64_t status_time; + + uint16_t pci_id; + uint32_t config_chip_id; + uint32_t block_decoded_io; + int use_block_decoded_io; + + int pll_addr; + uint8_t pll_regs[16]; + double pll_freq[4]; + + uint32_t config_stat0; + + uint32_t cur_clr0, cur_clr1; + + uint32_t overlay_dat[1024]; + uint32_t overlay_graphics_key_clr, overlay_graphics_key_msk; + uint32_t overlay_video_key_clr, overlay_video_key_msk; + uint32_t overlay_key_cntl; + uint32_t overlay_scale_inc; + uint32_t overlay_scale_cntl; + uint32_t overlay_y_x_start, overlay_y_x_end; + + uint32_t scaler_height_width; + int scaler_format; + int scaler_update; + + uint32_t buf_offset[2], buf_pitch[2]; + + int overlay_v_acc; } mach64_t; enum @@ -243,6 +301,11 @@ enum DST_24_ROT_EN = 0x80 }; +enum +{ + HOST_BYTE_ALIGN = (1 << 0) +}; + void mach64_write(uint32_t addr, uint8_t val, void *priv); uint8_t mach64_read(uint32_t addr, void *priv); void mach64_updatemapping(mach64_t *mach64); @@ -268,8 +331,6 @@ void mach64_out(uint16_t addr, uint8_t val, void *p) if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga->miscout & 1)) addr ^= 0x60; -// pclog("mach64 out %04X %02X\n", addr, val); - switch (addr) { case 0x1ce: @@ -277,21 +338,15 @@ void mach64_out(uint16_t addr, uint8_t val, void *p) break; case 0x1cf: mach64->regs[mach64->index & 0x3f] = val; - if ((mach64->index & 0x3f) == 0x2d) - { - if (val & 8) - { - svga->charseta = (svga->charseta & 0x3ffff) | ((((uint32_t) val) >> 4) << 18); - svga->charsetb = (svga->charsetb & 0x3ffff) | ((((uint32_t) val) >> 4) << 18); - } - break; - } if ((mach64->index & 0x3f) == 0x36) mach64_recalctimings(svga); break; case 0x3C6: case 0x3C7: case 0x3C8: case 0x3C9: - ati68860_ramdac_out((addr & 3) | ((mach64->dac_cntl & 3) << 2), val, &mach64->ramdac, svga); + if (mach64->type == MACH64_GX) + ati68860_ramdac_out((addr & 3) | ((mach64->dac_cntl & 3) << 2), val, &mach64->ramdac, svga); + else + svga_out(addr, val, svga); return; case 0x3cf: @@ -309,8 +364,6 @@ void mach64_out(uint16_t addr, uint8_t val, void *p) svga->crtcreg = val & 0x3f; return; case 0x3D5: - if (svga->crtcreg <= 0x18) - val &= mask_crtc[svga->crtcreg]; if ((svga->crtcreg < 7) && (svga->crtc[0x11] & 0x80)) return; if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80)) @@ -341,8 +394,6 @@ uint8_t mach64_in(uint16_t addr, void *p) if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga->miscout&1)) addr ^= 0x60; -// pclog("IN mach64 %04X\n", addr); - switch (addr) { case 0x1ce: @@ -351,7 +402,9 @@ uint8_t mach64_in(uint16_t addr, void *p) return mach64->regs[mach64->index & 0x3f]; case 0x3C6: case 0x3C7: case 0x3C8: case 0x3C9: - return ati68860_ramdac_in((addr & 3) | ((mach64->dac_cntl & 3) << 2), &mach64->ramdac, svga); + if (mach64->type == MACH64_GX) + return ati68860_ramdac_in((addr & 3) | ((mach64->dac_cntl & 3) << 2), &mach64->ramdac, svga); + return svga_in(addr, svga); case 0x3D4: return svga->crtcreg; @@ -372,60 +425,56 @@ void mach64_recalctimings(svga_t *svga) svga->vtotal = (mach64->crtc_v_total_disp & 2047) + 1; svga->dispend = ((mach64->crtc_v_total_disp >> 16) & 2047) + 1; svga->htotal = (mach64->crtc_h_total_disp & 255) + 1; - if (mach64->regs[0x2d] & 8) svga->htotal |= (mach64->regs[0x2d] & 1) ? 0x100 : 0; svga->hdisp_time = svga->hdisp = ((mach64->crtc_h_total_disp >> 16) & 255) + 1; svga->vsyncstart = (mach64->crtc_v_sync_strt_wid & 2047) + 1; svga->rowoffset = (mach64->crtc_off_pitch >> 22); svga->clock = cpuclock / mach64->ics2595.output_clock; svga->ma_latch = (mach64->crtc_off_pitch & 0x1fffff) * 2; - if (mach64->regs[0x2d] & 8) - { - svga->ma_latch |= (((uint32_t) (mach64->regs[0x30] & 0x40)) >> 6) << 16; - svga->ma_latch |= (((uint32_t) (mach64->regs[0x23] & 0x10)) >> 4) << 17; - svga->ma_latch |= (((uint32_t) (mach64->regs[0x2d] & 0xc)) >> 2) << 18; - } svga->linedbl = svga->rowcount = 0; svga->split = 0xffffff; svga->vblankstart = svga->dispend; -// svga_htotal <<= 1; -// svga_hdisp <<= 1; + svga->rowcount = mach64->crtc_gen_cntl & 1; svga->rowoffset <<= 1; - svga->render = mach64->ramdac.render; + if (mach64->type == MACH64_GX) + svga->render = mach64->ramdac.render; switch ((mach64->crtc_gen_cntl >> 8) & 7) { case 1: -// svga->render = svga_render_4bpp_highres; + if (mach64->type != MACH64_GX) + svga->render = svga_render_4bpp_highres; svga->hdisp *= 8; break; case 2: -// svga->render = svga_render_8bpp_highres; + if (mach64->type != MACH64_GX) + svga->render = svga_render_8bpp_highres; svga->hdisp *= 8; svga->rowoffset /= 2; break; case 3: -// svga->render = svga_render_15bpp_highres; + if (mach64->type != MACH64_GX) + svga->render = svga_render_15bpp_highres; svga->hdisp *= 8; - //svga_rowoffset *= 2; break; case 4: -// svga->render = svga_render_16bpp_highres; + if (mach64->type != MACH64_GX) + svga->render = svga_render_16bpp_highres; svga->hdisp *= 8; - //svga_rowoffset *= 2; break; case 5: -// svga->render = svga_render_24bpp_highres; + if (mach64->type != MACH64_GX) + svga->render = svga_render_24bpp_highres; svga->hdisp *= 8; svga->rowoffset = (svga->rowoffset * 3) / 2; break; case 6: -// svga->render = svga_render_32bpp_highres; + if (mach64->type != MACH64_GX) + svga->render = svga_render_32bpp_highres; svga->hdisp *= 8; svga->rowoffset *= 2; break; } svga->vrammask = mach64->vram_mask; -// pclog("mach64_recalctimings : frame %i,%i disp %i,%i vsync at %i rowoffset %i pixel clock %f MA %08X\n", svga->htotal, svga->vtotal, svga->hdisp, svga->dispend, svga->vsyncstart, svga->rowoffset, svga->clock, svga->ma); } else { @@ -439,16 +488,16 @@ void mach64_updatemapping(mach64_t *mach64) if (!(mach64->pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_MEM)) { - pclog("Update mapping - PCI disabled\n"); + /* pclog("Update mapping - PCI disabled\n"); */ mem_mapping_disable(&svga->mapping); mem_mapping_disable(&mach64->linear_mapping); mem_mapping_disable(&mach64->mmio_mapping); mem_mapping_disable(&mach64->mmio_linear_mapping); + mem_mapping_disable(&mach64->mmio_linear_mapping_2); return; } mem_mapping_disable(&mach64->mmio_mapping); -// pclog("Write mapping %02X\n", val); switch (svga->gdcreg[6] & 0xc) { case 0x0: /*128k at A0000*/ @@ -477,20 +526,29 @@ void mach64_updatemapping(mach64_t *mach64) svga->banked_mask = 0x7fff; break; } - // if (mach64->linear_base) - if ((mach64->config_cntl & 3) && mach64->linear_base) + if (mach64->linear_base) { - if ((mach64->config_cntl & 3) == 2) + if (mach64->type == MACH64_GX) { - /*8 MB aperture*/ - mem_mapping_set_addr(&mach64->linear_mapping, (mach64->linear_base & 0xff800000), (8 << 20) - 0x4000); - mem_mapping_set_addr(&mach64->mmio_linear_mapping, (mach64->linear_base & 0xff800000) + ((8 << 20) - 0x4000), 0x4000); + if ((mach64->config_cntl & 3) == 2) + { + /*8 MB aperture*/ + mem_mapping_set_addr(&mach64->linear_mapping, mach64->linear_base, (8 << 20) - 0x4000); + mem_mapping_set_addr(&mach64->mmio_linear_mapping, mach64->linear_base + ((8 << 20) - 0x4000), 0x4000); + } + else + { + /*4 MB aperture*/ + mem_mapping_set_addr(&mach64->linear_mapping, mach64->linear_base, (4 << 20) - 0x4000); + mem_mapping_set_addr(&mach64->mmio_linear_mapping, mach64->linear_base + ((4 << 20) - 0x4000), 0x4000); + } } else { - /*4 MB aperture*/ - mem_mapping_set_addr(&mach64->linear_mapping, (mach64->linear_base & 0xffc00000), (4 << 20) - 0x4000); - mem_mapping_set_addr(&mach64->mmio_linear_mapping, (mach64->linear_base & 0xffc00000) + ((4 << 20) - 0x4000), 0x4000); + /*2*8 MB aperture*/ + mem_mapping_set_addr(&mach64->linear_mapping, mach64->linear_base, (8 << 20) - 0x4000); + mem_mapping_set_addr(&mach64->mmio_linear_mapping, mach64->linear_base + ((8 << 20) - 0x4000), 0x4000); + mem_mapping_set_addr(&mach64->mmio_linear_mapping_2, mach64->linear_base + ((16 << 20) - 0x4000), 0x4000); } svga->linear_base = mach64->linear_base; } @@ -498,10 +556,19 @@ void mach64_updatemapping(mach64_t *mach64) { mem_mapping_disable(&mach64->linear_mapping); mem_mapping_disable(&mach64->mmio_linear_mapping); + mem_mapping_disable(&mach64->mmio_linear_mapping_2); } } -static inline void wake_fifo_thread(mach64_t *mach64) +static void mach64_update_irqs(mach64_t *mach64) +{ + if ((mach64->crtc_int_cntl & 0xaa0024) & ((mach64->crtc_int_cntl << 1) & 0xaa0024)) + pci_set_irq(mach64->card, PCI_INTA); + else + pci_clear_irq(mach64->card, PCI_INTA); +} + +static __inline void wake_fifo_thread(mach64_t *mach64) { thread_set_event(mach64->wake_fifo_thread); /*Wake up FIFO thread if moving from idle*/ } @@ -533,7 +600,6 @@ static void mach64_wait_fifo_idle(mach64_t *mach64) static void mach64_accel_write_fifo(mach64_t *mach64, uint32_t addr, uint8_t val) { -// pclog("mach64_accel_write_fifo: addr=%08x val=%02x\n", addr, val); switch (addr & 0x3ff) { case 0x100: case 0x101: case 0x102: case 0x103: @@ -556,8 +622,8 @@ static void mach64_accel_write_fifo(mach64_t *mach64, uint32_t addr, uint8_t val case 0x11e: case 0x11f: WRITE8(addr, mach64->dst_height_width, val); case 0x113: - if ((addr & 0x3ff) == 0x11b || (addr & 0x3ff) == 0x11f || - ((addr & 0x3ff) == 0x113) && !(val & 0x80)) + if (((addr & 0x3ff) == 0x11b || (addr & 0x3ff) == 0x11f || + (addr & 0x3ff) == 0x113) && !(val & 0x80)) { mach64_start_fill(mach64); #ifdef MACH64_DEBUG @@ -660,6 +726,10 @@ static void mach64_accel_write_fifo(mach64_t *mach64, uint32_t addr, uint8_t val case 0x23c: case 0x23d: case 0x23e: case 0x23f: mach64_blit(val, 8, mach64); break; + + case 0x240: case 0x241: case 0x242: case 0x243: + WRITE8(addr, mach64->host_cntl, val); + break; case 0x280: case 0x281: case 0x282: case 0x283: WRITE8(addr, mach64->pat_reg0, val); @@ -725,12 +795,15 @@ static void mach64_accel_write_fifo(mach64_t *mach64, uint32_t addr, uint8_t val break; case 0x333: WRITE8(addr - 3, mach64->pat_cntl, val & 7); + if (val & 0x10) + mach64->host_cntl |= HOST_BYTE_ALIGN; + else + mach64->host_cntl &= ~HOST_BYTE_ALIGN; break; } } static void mach64_accel_write_fifo_w(mach64_t *mach64, uint32_t addr, uint16_t val) { -// pclog("mach64_accel_write_fifo_w: addr=%08x val=%04x\n", addr, val); switch (addr & 0x3fe) { case 0x200: case 0x202: case 0x204: case 0x206: @@ -758,7 +831,6 @@ static void mach64_accel_write_fifo_w(mach64_t *mach64, uint32_t addr, uint16_t } static void mach64_accel_write_fifo_l(mach64_t *mach64, uint32_t addr, uint32_t val) { -// pclog("mach64_accel_write_fifo_l: addr=%08x %02x val=%08x\n", addr, addr >> 2, val); switch (addr & 0x3fc) { case 0x32c: @@ -805,7 +877,6 @@ static void fifo_thread(void *param) uint64_t start_time = timer_read(); uint64_t end_time; fifo_entry_t *fifo = &mach64->fifo[mach64->fifo_read_idx & FIFO_MASK]; - uint32_t val = fifo->val; switch (fifo->addr_type & FIFO_TYPE) { @@ -836,7 +907,6 @@ static void fifo_thread(void *param) static void mach64_queue(mach64_t *mach64, uint32_t addr, uint32_t val, uint32_t type) { fifo_entry_t *fifo = &mach64->fifo[mach64->fifo_write_idx & FIFO_MASK]; - int c; if (FIFO_FULL) { @@ -858,9 +928,7 @@ static void mach64_queue(mach64_t *mach64, uint32_t addr, uint32_t val, uint32_t void mach64_cursor_dump(mach64_t *mach64) { - svga_t *svga = &mach64->svga; -/* pclog("Mach64 cursor :\n"); - pclog("Ena = %i X = %i Y = %i Addr = %05X Xoff = %i Yoff = %i\n", svga->hwcursor.ena, svga->hwcursor.x, svga->hwcursor.y, svga->hwcursor.addr, svga->hwcursor.xoff, svga->hwcursor.yoff);*/ + return; } void mach64_start_fill(mach64_t *mach64) @@ -875,7 +943,6 @@ void mach64_start_fill(mach64_t *mach64) mach64->accel.dst_width = (mach64->dst_height_width >> 16) & 0x1fff; mach64->accel.dst_height = mach64->dst_height_width & 0x1fff; mach64->accel.x_count = mach64->accel.dst_width; - mach64->accel.y_count = mach64->accel.dst_height; mach64->accel.src_x = 0; mach64->accel.src_y = 0; @@ -925,11 +992,6 @@ void mach64_start_fill(mach64_t *mach64) mach64->accel.src_size = mach64_width[mach64->accel.src_pix_width]; mach64->accel.host_size = mach64_width[mach64->accel.host_pix_width]; -/* mach64->accel.src_x *= mach64_inc[mach64->accel.src_pix_width]; - mach64->accel.src_pitch *= mach64_inc[mach64->accel.src_pix_width]; - mach64->accel.dst_x *= mach64_inc[mach64->accel.dst_pix_width]; - mach64->accel.dst_pitch *= mach64_inc[mach64->accel.dst_pix_width];*/ - if (mach64->accel.src_size == WIDTH_1BIT) mach64->accel.src_offset <<= 3; else @@ -940,30 +1002,19 @@ void mach64_start_fill(mach64_t *mach64) else mach64->accel.dst_offset >>= mach64->accel.dst_size; -/* if (mach64->accel.source_fg == SRC_BLITSRC || mach64->accel.source_bg == SRC_BLITSRC) - {*/ - mach64->accel.xinc = (mach64->dst_cntl & DST_X_DIR) ? 1 : -1; - mach64->accel.yinc = (mach64->dst_cntl & DST_Y_DIR) ? 1 : -1; -/* } - else - { - mach64->accel.xinc = mach64_inc[mach64->accel.src_pix_width]; - mach64->accel.yinc = 1; - }*/ + mach64->accel.xinc = (mach64->dst_cntl & DST_X_DIR) ? 1 : -1; + mach64->accel.yinc = (mach64->dst_cntl & DST_Y_DIR) ? 1 : -1; mach64->accel.source_host = ((mach64->dp_src & 7) == SRC_HOST) || (((mach64->dp_src >> 8) & 7) == SRC_HOST); -// pclog("mach64_start_fill : pattern %08X %08X\n", mach64->pat_reg0, mach64->pat_reg1); for (y = 0; y < 8; y++) { for (x = 0; x < 8; x++) { uint32_t temp = (y & 4) ? mach64->pat_reg1 : mach64->pat_reg0; mach64->accel.pattern[y][x] = (temp >> (x + ((y & 3) * 8))) & 1; -// pclog("%i ", mach64->accel.pattern[y][x]); } -// pclog("\n"); } mach64->accel.sc_left = mach64->sc_left_right & 0x1fff; @@ -1069,16 +1120,10 @@ void mach64_start_line(mach64_t *mach64) mach64->accel.op = OP_LINE; } -#if 0 #define READ(addr, dat, width) if (width == 0) dat = svga->vram[((addr)) & mach64->vram_mask]; \ else if (width == 1) dat = *(uint16_t *)&svga->vram[((addr) << 1) & mach64->vram_mask]; \ else if (width == 2) dat = *(uint32_t *)&svga->vram[((addr) << 2) & mach64->vram_mask]; \ else dat = (svga->vram[((addr) >> 3) & mach64->vram_mask] >> ((addr) & 7)) & 1; -#endif -#define READ(addr, dat, width) if (width == 0) dat = svga->vram[((addr)) % (mach64->vram_mask + 1)]; \ - else if (width == 1) dat = *(uint16_t *)&svga->vram[((addr) << 1) % (mach64->vram_mask + 1)]; \ - else if (width == 2) dat = *(uint32_t *)&svga->vram[((addr) << 2) % (mach64->vram_mask + 1)]; \ - else dat = (svga->vram[((addr) >> 3) % (mach64->vram_mask + 1)] >> ((addr) & 7)) & 1; #define MIX switch (mix ? mach64->accel.mix_fg : mach64->accel.mix_bg) \ { \ @@ -1100,36 +1145,28 @@ void mach64_start_line(mach64_t *mach64) case 0xf: dest_dat = ~(src_dat | dest_dat); break; \ } -#if 0 - if (dest_dat & 1) \ - svga->vram[((addr) >> 3) % (mach64->vram_mask + 1)] |= 1 << ((addr) & 7); \ - else \ - svga->vram[((addr) >> 3) % (mach64->vram_mask + 1)] &= ~(1 << ((addr) & 7)); \ - svga->changedvram[(((addr) >> 3) % (mach64->vram_mask + 1)) >> 12] = changeframecount; -#endif - #define WRITE(addr, width) if (width == 0) \ { \ - svga->vram[(addr) % (mach64->vram_mask + 1)] = dest_dat; \ - svga->changedvram[((addr) % (mach64->vram_mask + 1)) >> 12] = changeframecount; \ + svga->vram[(addr) & mach64->vram_mask] = dest_dat; \ + svga->changedvram[((addr) & mach64->vram_mask) >> 12] = changeframecount; \ } \ else if (width == 1) \ { \ - *(uint16_t *)&svga->vram[((addr) << 1) % (mach64->vram_mask + 1)] = dest_dat; \ - svga->changedvram[(((addr) << 1) % (mach64->vram_mask + 1)) >> 12] = changeframecount; \ + *(uint16_t *)&svga->vram[((addr) << 1) & mach64->vram_mask] = dest_dat; \ + svga->changedvram[(((addr) << 1) & mach64->vram_mask) >> 12] = changeframecount; \ } \ else if (width == 2) \ { \ - *(uint32_t *)&svga->vram[((addr) << 2) % (mach64->vram_mask + 1)] = dest_dat; \ - svga->changedvram[(((addr) << 2) % (mach64->vram_mask + 1)) >> 12] = changeframecount; \ + *(uint32_t *)&svga->vram[((addr) << 2) & mach64->vram_mask] = dest_dat; \ + svga->changedvram[(((addr) << 2) & mach64->vram_mask) >> 12] = changeframecount; \ } \ else \ { \ if (dest_dat & 1) \ - svga->vram[((addr) >> 3) % (mach64->vram_mask + 1)] |= 1 << ((addr) & 7); \ + svga->vram[((addr) >> 3) & mach64->vram_mask] |= 1 << ((addr) & 7); \ else \ - svga->vram[((addr) >> 3) % (mach64->vram_mask + 1)] &= ~(1 << ((addr) & 7)); \ - svga->changedvram[(((addr) >> 3) % (mach64->vram_mask + 1)) >> 12] = changeframecount; \ + svga->vram[((addr) >> 3) & mach64->vram_mask] &= ~(1 << ((addr) & 7)); \ + svga->changedvram[(((addr) >> 3) & mach64->vram_mask) >> 12] = changeframecount; \ } void mach64_blit(uint32_t cpu_dat, int count, mach64_t *mach64) @@ -1150,8 +1187,8 @@ void mach64_blit(uint32_t cpu_dat, int count, mach64_t *mach64) while (count) { uint32_t src_dat, dest_dat; - uint32_t host_dat; - int mix; + uint32_t host_dat = 0; + int mix = 0; int dst_x = (mach64->accel.dst_x + mach64->accel.dst_x_start) & 0xfff; int dst_y = (mach64->accel.dst_y + mach64->accel.dst_y_start) & 0xfff; int src_x; @@ -1336,8 +1373,17 @@ void mach64_blit(uint32_t cpu_dat, int count, mach64_t *mach64) mach64->dst_y_x = (mach64->dst_y_x & 0xfff0000) | ((mach64->dst_y_x + (mach64->dst_height_width & 0x1fff)) & 0xfff); return; } - if (mach64->accel.source_host) - return; + if (mach64->host_cntl & HOST_BYTE_ALIGN) + { + if (mach64->accel.source_mix == MONO_SRC_HOST) + { + if (mach64->dp_pix_width & DP_BYTE_PIX_ORDER) + cpu_dat >>= (count & 7); + else + cpu_dat <<= (count & 7); + count &= ~7; + } + } } } break; @@ -1345,9 +1391,9 @@ void mach64_blit(uint32_t cpu_dat, int count, mach64_t *mach64) case OP_LINE: while (count) { - uint32_t src_dat, dest_dat; - uint32_t host_dat; - int mix; + uint32_t src_dat = 0, dest_dat; + uint32_t host_dat = 0; + int mix = 0; int draw_pixel = !(mach64->dst_cntl & DST_POLYGON_EN); if (mach64->accel.source_host) @@ -1423,8 +1469,6 @@ void mach64_blit(uint32_t cpu_dat, int count, mach64_t *mach64) READ(mach64->accel.dst_offset + (mach64->accel.dst_y * mach64->accel.dst_pitch) + mach64->accel.dst_x, dest_dat, mach64->accel.dst_size); -// pclog("Blit %i,%i %i,%i %X %X %i %02X %02X %i ", mach64->accel.src_x, mach64->accel.src_y, mach64->accel.dst_x, mach64->accel.dst_y, (mach64->accel.src_offset + (mach64->accel.src_y * mach64->accel.src_pitch) + mach64->accel.src_x) & 0x7fffff, (mach64->accel.dst_offset + (mach64->accel.dst_y * mach64->accel.dst_pitch) + mach64->accel.dst_x) & 0x7fffff, count, src_dat, dest_dat, mix); - switch (mach64->accel.clr_cmp_fn) { case 1: /*TRUE*/ @@ -1441,8 +1485,6 @@ void mach64_blit(uint32_t cpu_dat, int count, mach64_t *mach64) if (!cmp_clr) MIX -// pclog("%02X %i\n", dest_dat, mach64->accel.dst_height); - WRITE(mach64->accel.dst_offset + (mach64->accel.dst_y * mach64->accel.dst_pitch) + mach64->accel.dst_x, mach64->accel.dst_size); } @@ -1517,8 +1559,7 @@ void mach64_load_context(mach64_t *mach64) while (mach64->context_load_cntl & 0x30000) { - // addr = ((0x3fff - (mach64->context_load_cntl & 0x3fff)) * 256) & mach64->vram_mask; - addr = ((0x3fff - (mach64->context_load_cntl & 0x3fff)) * 256) % (mach64->vram_mask + 1); + addr = ((0x3fff - (mach64->context_load_cntl & 0x3fff)) * 256) & mach64->vram_mask; mach64->context_mask = *(uint32_t *)&svga->vram[addr]; #ifdef MACH64_DEBUG pclog("mach64_load_context %08X from %08X : mask %08X\n", mach64->context_load_cntl, addr, mach64->context_mask); @@ -1581,11 +1622,117 @@ void mach64_load_context(mach64_t *mach64) } } +#define PLL_REF_DIV 0x2 +#define VCLK_POST_DIV 0x6 +#define VCLK0_FB_DIV 0x7 + +static void pll_write(mach64_t *mach64, uint32_t addr, uint8_t val) +{ + int c; + + switch (addr & 3) + { + case 0: /*Clock sel*/ + break; + case 1: /*Addr*/ + mach64->pll_addr = (val >> 2) & 0xf; + break; + case 2: /*Data*/ + mach64->pll_regs[mach64->pll_addr] = val; + /* pclog("pll_write %02x,%02x\n", mach64->pll_addr, val); */ + + for (c = 0; c < 4; c++) + { + double m = (double)mach64->pll_regs[PLL_REF_DIV]; + double n = (double)mach64->pll_regs[VCLK0_FB_DIV+c]; + double r = 14318184.0; + double p = (double)(1 << ((mach64->pll_regs[VCLK_POST_DIV] >> (c*2)) & 3)); + + /* pclog("PLLfreq %i = %g %g m=%02x n=%02x p=%02x\n", c, (2.0 * r * n) / (m * p), p, mach64->pll_regs[PLL_REF_DIV], mach64->pll_regs[VCLK0_FB_DIV+c], mach64->pll_regs[VCLK_POST_DIV]); */ + mach64->pll_freq[c] = (2.0 * r * n) / (m * p); + /* pclog(" %g\n", mach64->pll_freq[c]); */ + } + break; + } +} + +#define OVERLAY_EN (1 << 30) +static void mach64_vblank_start(svga_t *svga) +{ + mach64_t *mach64 = (mach64_t *)svga->p; + int overlay_cmp_mix = (mach64->overlay_key_cntl >> 8) & 0xf; + + mach64->crtc_int_cntl |= 4; + mach64_update_irqs(mach64); + + svga->overlay.x = (mach64->overlay_y_x_start >> 16) & 0x7ff; + svga->overlay.y = mach64->overlay_y_x_start & 0x7ff; + + svga->overlay.xsize = ((mach64->overlay_y_x_end >> 16) & 0x7ff) - svga->overlay.x; + svga->overlay.ysize = (mach64->overlay_y_x_end & 0x7ff) - svga->overlay.y; + + svga->overlay.addr = mach64->buf_offset[0] & 0x3ffff8; + svga->overlay.pitch = mach64->buf_pitch[0] & 0xfff; + + svga->overlay.ena = (mach64->overlay_scale_cntl & OVERLAY_EN) && (overlay_cmp_mix != 1); + + mach64->overlay_v_acc = 0; + mach64->scaler_update = 1; +} + uint8_t mach64_ext_readb(uint32_t addr, void *p) { mach64_t *mach64 = (mach64_t *)p; uint8_t ret; - switch (addr & 0x3ff) + if (!(addr & 0x400)) + { +#ifdef MACH64_DEBUG + pclog("nmach64_ext_readb: addr=%04x %04x(%08x):%08x\n", addr, CS, cs, cpu_state.pc); +#endif + switch (addr & 0x3ff) + { + case 0x00: case 0x01: case 0x02: case 0x03: + READ8(addr, mach64->overlay_y_x_start); + break; + case 0x04: case 0x05: case 0x06: case 0x07: + READ8(addr, mach64->overlay_y_x_end); + break; + case 0x08: case 0x09: case 0x0a: case 0x0b: + READ8(addr, mach64->overlay_video_key_clr); + break; + case 0x0c: case 0x0d: case 0x0e: case 0x0f: + READ8(addr, mach64->overlay_video_key_msk); + break; + case 0x10: case 0x11: case 0x12: case 0x13: + READ8(addr, mach64->overlay_graphics_key_clr); + break; + case 0x14: case 0x15: case 0x16: case 0x17: + READ8(addr, mach64->overlay_graphics_key_msk); + break; + case 0x18: case 0x19: case 0x1a: case 0x1b: + READ8(addr, mach64->overlay_key_cntl); + break; + + case 0x20: case 0x21: case 0x22: case 0x23: + READ8(addr, mach64->overlay_scale_inc); + break; + case 0x24: case 0x25: case 0x26: case 0x27: + READ8(addr, mach64->overlay_scale_cntl); + break; + case 0x28: case 0x29: case 0x2a: case 0x2b: + READ8(addr, mach64->scaler_height_width); + break; + + case 0x4a: + ret = mach64->scaler_format; + break; + + default: + ret = 0xff; + break; + } + } + else switch (addr & 0x3ff) { case 0x00: case 0x01: case 0x02: case 0x03: READ8(addr, mach64->crtc_h_total_disp); @@ -1625,6 +1772,12 @@ uint8_t mach64_ext_readb(uint32_t addr, void *p) READ8(addr, mach64->ovr_wid_top_bottom); break; + case 0x60: case 0x61: case 0x62: case 0x63: + READ8(addr, mach64->cur_clr0); + break; + case 0x64: case 0x65: case 0x66: case 0x67: + READ8(addr, mach64->cur_clr1); + break; case 0x68: case 0x69: case 0x6a: case 0x6b: READ8(addr, mach64->cur_offset); break; @@ -1635,6 +1788,10 @@ uint8_t mach64_ext_readb(uint32_t addr, void *p) READ8(addr, mach64->cur_horz_vert_off); break; + case 0x79: + ret = 0x30; + break; + case 0x80: case 0x81: case 0x82: case 0x83: READ8(addr, mach64->scratch_reg0); break; @@ -1651,18 +1808,33 @@ uint8_t mach64_ext_readb(uint32_t addr, void *p) break; case 0xc0: case 0xc1: case 0xc2: case 0xc3: - ret = ati68860_ramdac_in((addr & 3) | ((mach64->dac_cntl & 3) << 2), &mach64->ramdac, &mach64->svga); + if (mach64->type == MACH64_GX) + ret = ati68860_ramdac_in((addr & 3) | ((mach64->dac_cntl & 3) << 2), &mach64->ramdac, &mach64->svga); + else + ret = ati68860_ramdac_in(addr & 3, &mach64->ramdac, &mach64->svga); break; case 0xc4: case 0xc5: case 0xc6: case 0xc7: + if (mach64->type == MACH64_VT2) + mach64->dac_cntl |= (4 << 24); READ8(addr, mach64->dac_cntl); break; case 0xd0: case 0xd1: case 0xd2: case 0xd3: READ8(addr, mach64->gen_test_cntl); break; - + + case 0xdc: case 0xdd: case 0xde: case 0xdf: + if (mach64->type == MACH64_GX) + mach64->config_cntl = (mach64->config_cntl & ~0x3ff0) | ((mach64->linear_base >> 22) << 4); + else + mach64->config_cntl = (mach64->config_cntl & ~0x3ff0) | ((mach64->linear_base >> 24) << 4); + READ8(addr, mach64->config_cntl); + break; case 0xe0: case 0xe1: case 0xe2: case 0xe3: - READ8(addr, 0x020000d7); /*88800GX-2*/ + READ8(addr, mach64->config_chip_id); + break; + case 0xe4: case 0xe5: case 0xe6: case 0xe7: + READ8(addr, mach64->config_stat0); break; case 0x100: case 0x101: case 0x102: case 0x103: @@ -1770,6 +1942,11 @@ uint8_t mach64_ext_readb(uint32_t addr, void *p) READ8(addr, mach64->src_cntl); break; + case 0x240: case 0x241: case 0x242: case 0x243: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->host_cntl); + break; + case 0x280: case 0x281: case 0x282: case 0x283: mach64_wait_fifo_idle(mach64); READ8(addr, mach64->pat_reg0); @@ -1879,9 +2056,15 @@ uint8_t mach64_ext_readb(uint32_t addr, void *p) } uint16_t mach64_ext_readw(uint32_t addr, void *p) { - mach64_t *mach64 = (mach64_t *)p; uint16_t ret; - switch (addr & 0x3ff) + if (!(addr & 0x400)) + { +#ifdef MACH64_DEBUG + pclog("nmach64_ext_readw: addr=%04x %04x(%08x):%08x\n", addr, CS, cs, cpu_state.pc); +#endif + ret = 0xffff; + } + else switch (addr & 0x3ff) { default: #ifdef MACH64_DEBUG @@ -1903,7 +2086,14 @@ uint32_t mach64_ext_readl(uint32_t addr, void *p) { mach64_t *mach64 = (mach64_t *)p; uint32_t ret; - switch (addr & 0x3ff) + if (!(addr & 0x400)) + { +#ifdef MACH64_DEBUG + pclog("nmach64_ext_readl: addr=%04x %04x(%08x):%08x\n", addr, CS, cs, cpu_state.pc); +#endif + ret = 0xffffffff; + } + else switch (addr & 0x3ff) { case 0x18: ret = mach64->crtc_int_cntl & ~1; @@ -1940,9 +2130,69 @@ void mach64_ext_writeb(uint32_t addr, uint8_t val, void *p) mach64_t *mach64 = (mach64_t *)p; svga_t *svga = &mach64->svga; #ifdef MACH64_DEBUG - pclog("mach64_ext_writeb : addr %08X val %02X\n", addr, val); + pclog("mach64_ext_writeb : addr %08X val %02X %04x(%08x):%08x\n", addr, val, CS,cs,cpu_state.pc); #endif - if (addr & 0x300) + if (!(addr & 0x400)) + { + switch (addr & 0x3ff) + { + case 0x00: case 0x01: case 0x02: case 0x03: + WRITE8(addr, mach64->overlay_y_x_start, val); + break; + case 0x04: case 0x05: case 0x06: case 0x07: + WRITE8(addr, mach64->overlay_y_x_end, val); + break; + case 0x08: case 0x09: case 0x0a: case 0x0b: + WRITE8(addr, mach64->overlay_video_key_clr, val); + break; + case 0x0c: case 0x0d: case 0x0e: case 0x0f: + WRITE8(addr, mach64->overlay_video_key_msk, val); + break; + case 0x10: case 0x11: case 0x12: case 0x13: + WRITE8(addr, mach64->overlay_graphics_key_clr, val); + break; + case 0x14: case 0x15: case 0x16: case 0x17: + WRITE8(addr, mach64->overlay_graphics_key_msk, val); + break; + case 0x18: case 0x19: case 0x1a: case 0x1b: + WRITE8(addr, mach64->overlay_key_cntl, val); + break; + + case 0x20: case 0x21: case 0x22: case 0x23: + WRITE8(addr, mach64->overlay_scale_inc, val); + break; + case 0x24: case 0x25: case 0x26: case 0x27: + WRITE8(addr, mach64->overlay_scale_cntl, val); + break; + case 0x28: case 0x29: case 0x2a: case 0x2b: + WRITE8(addr, mach64->scaler_height_width, val); + break; + + case 0x4a: + mach64->scaler_format = val & 0xf; + break; + + case 0x80: case 0x81: case 0x82: case 0x83: + WRITE8(addr, mach64->buf_offset[0], val); + break; + + case 0x8c: case 0x8d: case 0x8e: case 0x8f: + WRITE8(addr, mach64->buf_pitch[0], val); + break; + + case 0x98: case 0x99: case 0x9a: case 0x9b: + WRITE8(addr, mach64->buf_offset[1], val); + break; + + case 0xa4: case 0xa5: case 0xa6: case 0xa7: + WRITE8(addr, mach64->buf_pitch[1], val); + break; + } +#ifdef MACH64_DEBUG + pclog("nmach64_ext_writeb: addr=%04x val=%02x\n", addr, val); +#endif + } + else if (addr & 0x300) { mach64_queue(mach64, addr & 0x3ff, val, FIFO_WRITE_BYTE); } @@ -1968,7 +2218,10 @@ void mach64_ext_writeb(uint32_t addr, uint8_t val, void *p) break; case 0x18: - mach64->crtc_int_cntl = val; + mach64->crtc_int_cntl = (mach64->crtc_int_cntl & 0x75) | (val & ~0x75); + if (val & 4) + mach64->crtc_int_cntl &= ~4; + mach64_update_irqs(mach64); break; case 0x1c: case 0x1d: case 0x1e: case 0x1f: @@ -1990,6 +2243,16 @@ void mach64_ext_writeb(uint32_t addr, uint8_t val, void *p) WRITE8(addr, mach64->ovr_wid_top_bottom, val); break; + case 0x60: case 0x61: case 0x62: case 0x63: + WRITE8(addr, mach64->cur_clr0, val); + if (mach64->type == MACH64_VT2) + mach64->ramdac.pallook[0] = makecol32((mach64->cur_clr0 >> 24) & 0xff, (mach64->cur_clr0 >> 16) & 0xff, (mach64->cur_clr0 >> 8) & 0xff); + break; + case 0x64: case 0x65: case 0x66: case 0x67: + WRITE8(addr, mach64->cur_clr1, val); + if (mach64->type == MACH64_VT2) + mach64->ramdac.pallook[1] = makecol32((mach64->cur_clr1 >> 24) & 0xff, (mach64->cur_clr1 >> 16) & 0xff, (mach64->cur_clr1 >> 8) & 0xff); + break; case 0x68: case 0x69: case 0x6a: case 0x6b: WRITE8(addr, mach64->cur_offset, val); svga->hwcursor.addr = (mach64->cur_offset & 0xfffff) * 8; @@ -2017,7 +2280,13 @@ void mach64_ext_writeb(uint32_t addr, uint8_t val, void *p) case 0x90: case 0x91: case 0x92: case 0x93: WRITE8(addr, mach64->clock_cntl, val); - ics2595_write(&mach64->ics2595, val & 0x40, val & 0xf); + if (mach64->type == MACH64_GX) + ics2595_write(&mach64->ics2595, val & 0x40, val & 0xf); + else + { + pll_write(mach64, addr, val); + mach64->ics2595.output_clock = mach64->pll_freq[mach64->clock_cntl & 3]; + } svga_recalctimings(&mach64->svga); break; @@ -2051,7 +2320,10 @@ void mach64_ext_writeb(uint32_t addr, uint8_t val, void *p) break; case 0xc0: case 0xc1: case 0xc2: case 0xc3: - ati68860_ramdac_out((addr & 3) | ((mach64->dac_cntl & 3) << 2), val, &mach64->ramdac, &mach64->svga); + if (mach64->type == MACH64_GX) + ati68860_ramdac_out((addr & 3) | ((mach64->dac_cntl & 3) << 2), val, &mach64->ramdac, &mach64->svga); + else + ati68860_ramdac_out(addr & 3, val, &mach64->ramdac, &mach64->svga); break; case 0xc4: case 0xc5: case 0xc6: case 0xc7: WRITE8(addr, mach64->dac_cntl, val); @@ -2061,12 +2333,21 @@ void mach64_ext_writeb(uint32_t addr, uint8_t val, void *p) case 0xd0: case 0xd1: case 0xd2: case 0xd3: WRITE8(addr, mach64->gen_test_cntl, val); -// if (val == 2) output = 3; ati_eeprom_write(&mach64->eeprom, mach64->gen_test_cntl & 0x10, mach64->gen_test_cntl & 2, mach64->gen_test_cntl & 1); mach64->gen_test_cntl = (mach64->gen_test_cntl & ~8) | (ati_eeprom_read(&mach64->eeprom) ? 8 : 0); svga->hwcursor.ena = mach64->gen_test_cntl & 0x80; mach64_cursor_dump(mach64); break; + + case 0xdc: case 0xdd: case 0xde: case 0xdf: + WRITE8(addr, mach64->config_cntl, val); + mach64_updatemapping(mach64); + break; + + case 0xe4: case 0xe5: case 0xe6: case 0xe7: + if (mach64->type != MACH64_GX) + WRITE8(addr, mach64->config_stat0, val); + break; } } void mach64_ext_writew(uint32_t addr, uint16_t val, void *p) @@ -2075,7 +2356,15 @@ void mach64_ext_writew(uint32_t addr, uint16_t val, void *p) #ifdef MACH64_DEBUG pclog("mach64_ext_writew : addr %08X val %04X\n", addr, val); #endif - if (addr & 0x300) + if (!(addr & 0x400)) + { +#ifdef MACH64_DEBUG + pclog("nmach64_ext_writew: addr=%04x val=%04x %04x(%08x):%08x\n", addr, val, CS, cs, cpu_state.pc); +#endif + mach64_ext_writeb(addr, val, p); + mach64_ext_writeb(addr + 1, val >> 8, p); + } + else if (addr & 0x300) { mach64_queue(mach64, addr & 0x3fe, val, FIFO_WRITE_WORD); } @@ -2100,7 +2389,15 @@ void mach64_ext_writel(uint32_t addr, uint32_t val, void *p) if ((addr & 0x3c0) != 0x200) pclog("mach64_ext_writel : addr %08X val %08X\n", addr, val); #endif - if (addr & 0x300) + if (!(addr & 0x400)) + { +#ifdef MACH64_DEBUG + pclog("nmach64_ext_writel: addr=%04x val=%08x %04x(%08x):%08x\n", addr, val, CS, cs, cpu_state.pc); +#endif + mach64_ext_writew(addr, val, p); + mach64_ext_writew(addr + 2, val >> 16, p); + } + else if (addr & 0x300) { mach64_queue(mach64, addr & 0x3fc, val, FIFO_WRITE_DWORD); } @@ -2123,93 +2420,101 @@ uint8_t mach64_ext_inb(uint16_t port, void *p) { mach64_t *mach64 = (mach64_t *)p; uint8_t ret; -// if (CS == 0x2be7) output = 3; switch (port) { case 0x02ec: case 0x02ed: case 0x02ee: case 0x02ef: case 0x7eec: case 0x7eed: case 0x7eee: case 0x7eef: - ret = mach64_ext_readb(0x00 | (port & 3), p); + ret = mach64_ext_readb(0x400 | 0x00 | (port & 3), p); break; case 0x0aec: case 0x0aed: case 0x0aee: case 0x0aef: - ret = mach64_ext_readb(0x08 | (port & 3), p); + ret = mach64_ext_readb(0x400 | 0x08 | (port & 3), p); break; case 0x0eec: case 0x0eed: case 0x0eee: case 0x0eef: - ret = mach64_ext_readb(0x0c | (port & 3), p); + ret = mach64_ext_readb(0x400 | 0x0c | (port & 3), p); break; case 0x12ec: case 0x12ed: case 0x12ee: case 0x12ef: - ret = mach64_ext_readb(0x10 | (port & 3), p); + ret = mach64_ext_readb(0x400 | 0x10 | (port & 3), p); break; case 0x16ec: case 0x16ed: case 0x16ee: case 0x16ef: - ret = mach64_ext_readb(0x14 | (port & 3), p); + ret = mach64_ext_readb(0x400 | 0x14 | (port & 3), p); break; case 0x1aec: - ret = mach64_ext_readb(0x18, p); + ret = mach64_ext_readb(0x400 | 0x18, p); break; case 0x1eec: case 0x1eed: case 0x1eee: case 0x1eef: - ret = mach64_ext_readb(0x1c | (port & 3), p); + ret = mach64_ext_readb(0x400 | 0x1c | (port & 3), p); break; case 0x22ec: case 0x22ed: case 0x22ee: case 0x22ef: - ret = mach64_ext_readb(0x40 | (port & 3), p); + ret = mach64_ext_readb(0x400 | 0x40 | (port & 3), p); break; case 0x26ec: case 0x26ed: case 0x26ee: case 0x26ef: - ret = mach64_ext_readb(0x44 | (port & 3), p); + ret = mach64_ext_readb(0x400 | 0x44 | (port & 3), p); break; case 0x2aec: case 0x2aed: case 0x2aee: case 0x2aef: - ret = mach64_ext_readb(0x48 | (port & 3), p); + ret = mach64_ext_readb(0x400 | 0x48 | (port & 3), p); + break; + case 0x2eec: case 0x2eed: case 0x2eee: case 0x2eef: + ret = mach64_ext_readb(0x400 | 0x60 | (port & 3), p); break; + case 0x32ec: case 0x32ed: case 0x32ee: case 0x32ef: + ret = mach64_ext_readb(0x400 | 0x64 | (port & 3), p); + break; case 0x36ec: case 0x36ed: case 0x36ee: case 0x36ef: - ret = mach64_ext_readb(0x68 | (port & 3), p); + ret = mach64_ext_readb(0x400 | 0x68 | (port & 3), p); break; case 0x3aec: case 0x3aed: case 0x3aee: case 0x3aef: - ret = mach64_ext_readb(0x6c | (port & 3), p); + ret = mach64_ext_readb(0x400 | 0x6c | (port & 3), p); break; case 0x3eec: case 0x3eed: case 0x3eee: case 0x3eef: - ret = mach64_ext_readb(0x70 | (port & 3), p); + ret = mach64_ext_readb(0x400 | 0x70 | (port & 3), p); break; case 0x42ec: case 0x42ed: case 0x42ee: case 0x42ef: - ret = mach64_ext_readb(0x80 | (port & 3), p); + ret = mach64_ext_readb(0x400 | 0x80 | (port & 3), p); break; case 0x46ec: case 0x46ed: case 0x46ee: case 0x46ef: - ret = mach64_ext_readb(0x84 | (port & 3), p); + ret = mach64_ext_readb(0x400 | 0x84 | (port & 3), p); break; case 0x4aec: case 0x4aed: case 0x4aee: case 0x4aef: - ret = mach64_ext_readb(0x90 | (port & 3), p); + ret = mach64_ext_readb(0x400 | 0x90 | (port & 3), p); break; case 0x52ec: case 0x52ed: case 0x52ee: case 0x52ef: - ret = mach64_ext_readb(0xb0 | (port & 3), p); + ret = mach64_ext_readb(0x400 | 0xb0 | (port & 3), p); break; case 0x56ec: - ret = mach64_ext_readb(0xb4, p); + ret = mach64_ext_readb(0x400 | 0xb4, p); break; case 0x56ed: case 0x56ee: - ret = mach64_ext_readb(0xb5, p); + ret = mach64_ext_readb(0x400 | 0xb5, p); break; case 0x5aec: - ret = mach64_ext_readb(0xb8, p); + ret = mach64_ext_readb(0x400 | 0xb8, p); break; case 0x5aed: case 0x5aee: - ret = mach64_ext_readb(0xb9, p); + ret = mach64_ext_readb(0x400 | 0xb9, p); break; case 0x5eec: case 0x5eed: case 0x5eee: case 0x5eef: - ret = ati68860_ramdac_in((port & 3) | ((mach64->dac_cntl & 3) << 2), &mach64->ramdac, &mach64->svga); + if (mach64->type == MACH64_GX) + ret = ati68860_ramdac_in((port & 3) | ((mach64->dac_cntl & 3) << 2), &mach64->ramdac, &mach64->svga); + else + ret = ati68860_ramdac_in(port & 3, &mach64->ramdac, &mach64->svga); break; case 0x62ec: case 0x62ed: case 0x62ee: case 0x62ef: - ret = mach64_ext_readb(0xc4 | (port & 3), p); + ret = mach64_ext_readb(0x400 | 0xc4 | (port & 3), p); break; case 0x66ec: case 0x66ed: case 0x66ee: case 0x66ef: - ret = mach64_ext_readb(0xd0 | (port & 3), p); + ret = mach64_ext_readb(0x400 | 0xd0 | (port & 3), p); break; case 0x6aec: case 0x6aed: case 0x6aee: case 0x6aef: @@ -2218,27 +2523,11 @@ uint8_t mach64_ext_inb(uint16_t port, void *p) break; case 0x6eec: case 0x6eed: case 0x6eee: case 0x6eef: - ret = mach64_ext_readb(0xe0 | (port & 3), p); + ret = mach64_ext_readb(0x400 | 0xe0 | (port & 3), p); break; - case 0x72ec: - if (mach64->vram_size == 8) - { - if (PCI) - ret = 7 | (6 << 3); /*PCI, 256Kx16 DRAM*/ - else - ret = 6 | (6 << 3); /*VLB, 256Kx16 DRAM*/ - } - else - { - if (PCI) - ret = 7 | (3 << 3); /*PCI, 256Kx16 DRAM*/ - else - ret = 6 | (3 << 3); /*VLB, 256Kx16 DRAM*/ - } - break; - case 0x72ed: - ret = 5 << 1; /*ATI-68860*/ + case 0x72ec: case 0x72ed: case 0x72ee: case 0x72ef: + ret = mach64_ext_readb(0x400 | 0xe4 | (port & 3), p); break; default: @@ -2252,7 +2541,6 @@ uint8_t mach64_ext_inb(uint16_t port, void *p) } uint16_t mach64_ext_inw(uint16_t port, void *p) { - mach64_t *mach64 = (mach64_t *)p; uint16_t ret; switch (port) { @@ -2274,15 +2562,14 @@ uint16_t mach64_ext_inw(uint16_t port, void *p) } uint32_t mach64_ext_inl(uint16_t port, void *p) { - mach64_t *mach64 = (mach64_t *)p; uint32_t ret; switch (port) { case 0x56ec: - ret = mach64_ext_readl(0xb4, p); + ret = mach64_ext_readl(0x400 | 0xb4, p); break; case 0x5aec: - ret = mach64_ext_readl(0xb8, p); + ret = mach64_ext_readl(0x400 | 0xb8, p); break; default: @@ -2312,96 +2599,103 @@ void mach64_ext_outb(uint16_t port, uint8_t val, void *p) { case 0x02ec: case 0x02ed: case 0x02ee: case 0x02ef: case 0x7eec: case 0x7eed: case 0x7eee: case 0x7eef: - mach64_ext_writeb(0x00 | (port & 3), val, p); + mach64_ext_writeb(0x400 | 0x00 | (port & 3), val, p); break; case 0x0aec: case 0x0aed: case 0x0aee: case 0x0aef: - mach64_ext_writeb(0x08 | (port & 3), val, p); + mach64_ext_writeb(0x400 | 0x08 | (port & 3), val, p); break; case 0x0eec: case 0x0eed: case 0x0eee: case 0x0eef: - mach64_ext_writeb(0x0c | (port & 3), val, p); + mach64_ext_writeb(0x400 | 0x0c | (port & 3), val, p); break; case 0x16ec: case 0x16ed: case 0x16ee: case 0x16ef: - mach64_ext_writeb(0x14 | (port & 3), val, p); + mach64_ext_writeb(0x400 | 0x14 | (port & 3), val, p); break; case 0x1aec: - mach64_ext_writeb(0x18, val, p); + mach64_ext_writeb(0x400 | 0x18, val, p); break; case 0x1eec: case 0x1eed: case 0x1eee: case 0x1eef: - mach64_ext_writeb(0x1c | (port & 3), val, p); + mach64_ext_writeb(0x400 | 0x1c | (port & 3), val, p); break; case 0x22ec: case 0x22ed: case 0x22ee: case 0x22ef: - mach64_ext_writeb(0x40 | (port & 3), val, p); + mach64_ext_writeb(0x400 | 0x40 | (port & 3), val, p); break; case 0x26ec: case 0x26ed: case 0x26ee: case 0x26ef: - mach64_ext_writeb(0x44 | (port & 3), val, p); + mach64_ext_writeb(0x400 | 0x44 | (port & 3), val, p); break; case 0x2aec: case 0x2aed: case 0x2aee: case 0x2aef: - mach64_ext_writeb(0x48 | (port & 3), val, p); + mach64_ext_writeb(0x400 | 0x48 | (port & 3), val, p); + break; + case 0x2eec: case 0x2eed: case 0x2eee: case 0x2eef: + mach64_ext_writeb(0x400 | 0x60 | (port & 3), val, p); break; + case 0x32ec: case 0x32ed: case 0x32ee: case 0x32ef: + mach64_ext_writeb(0x400 | 0x64 | (port & 3), val, p); + break; case 0x36ec: case 0x36ed: case 0x36ee: case 0x36ef: - mach64_ext_writeb(0x68 | (port & 3), val, p); + mach64_ext_writeb(0x400 | 0x68 | (port & 3), val, p); break; case 0x3aec: case 0x3aed: case 0x3aee: case 0x3aef: - mach64_ext_writeb(0x6c | (port & 3), val, p); + mach64_ext_writeb(0x400 | 0x6c | (port & 3), val, p); break; case 0x3eec: case 0x3eed: case 0x3eee: case 0x3eef: - mach64_ext_writeb(0x70 | (port & 3), val, p); + mach64_ext_writeb(0x400 | 0x70 | (port & 3), val, p); break; case 0x42ec: case 0x42ed: case 0x42ee: case 0x42ef: - mach64_ext_writeb(0x80 | (port & 3), val, p); + mach64_ext_writeb(0x400 | 0x80 | (port & 3), val, p); break; case 0x46ec: case 0x46ed: case 0x46ee: case 0x46ef: - mach64_ext_writeb(0x84 | (port & 3), val, p); + mach64_ext_writeb(0x400 | 0x84 | (port & 3), val, p); break; case 0x4aec: case 0x4aed: case 0x4aee: case 0x4aef: - mach64_ext_writeb(0x90 | (port & 3), val, p); + mach64_ext_writeb(0x400 | 0x90 | (port & 3), val, p); break; case 0x52ec: case 0x52ed: case 0x52ee: case 0x52ef: - mach64_ext_writeb(0xb0 | (port & 3), val, p); + mach64_ext_writeb(0x400 | 0xb0 | (port & 3), val, p); break; case 0x56ec: - mach64_ext_writeb(0xb4, val, p); + mach64_ext_writeb(0x400 | 0xb4, val, p); break; case 0x56ed: case 0x56ee: - mach64_ext_writeb(0xb5, val, p); + mach64_ext_writeb(0x400 | 0xb5, val, p); break; case 0x5aec: - mach64_ext_writeb(0xb8, val, p); + mach64_ext_writeb(0x400 | 0xb8, val, p); break; case 0x5aed: case 0x5aee: - mach64_ext_writeb(0xb9, val, p); + mach64_ext_writeb(0x400 | 0xb9, val, p); break; case 0x5eec: case 0x5eed: case 0x5eee: case 0x5eef: - ati68860_ramdac_out((port & 3) | ((mach64->dac_cntl & 3) << 2), val, &mach64->ramdac, &mach64->svga); + if (mach64->type == MACH64_GX) + ati68860_ramdac_out((port & 3) | ((mach64->dac_cntl & 3) << 2), val, &mach64->ramdac, &mach64->svga); + else + ati68860_ramdac_out(port & 3, val, &mach64->ramdac, &mach64->svga); break; case 0x62ec: case 0x62ed: case 0x62ee: case 0x62ef: - mach64_ext_writeb(0xc4 | (port & 3), val, p); + mach64_ext_writeb(0x400 | 0xc4 | (port & 3), val, p); break; case 0x66ec: case 0x66ed: case 0x66ee: case 0x66ef: - mach64_ext_writeb(0xd0 | (port & 3), val, p); + mach64_ext_writeb(0x400 | 0xd0 | (port & 3), val, p); break; case 0x6aec: case 0x6aed: case 0x6aee: case 0x6aef: WRITE8(port, mach64->config_cntl, val); - mach64->linear_base = ((mach64->config_cntl & 0x3ff0) >> 4) << 22; mach64_updatemapping(mach64); break; } } void mach64_ext_outw(uint16_t port, uint16_t val, void *p) { - mach64_t *mach64 = (mach64_t *)p; #ifdef MACH64_DEBUG pclog("mach64_ext_outw : port %04X val %04X\n", port, val); #endif @@ -2421,8 +2715,7 @@ void mach64_ext_outw(uint16_t port, uint16_t val, void *p) } void mach64_ext_outl(uint16_t port, uint32_t val, void *p) { - mach64_t *mach64 = (mach64_t *)p; - pclog("mach64_ext_outl : port %04X val %08X\n", port, val); + /* pclog("mach64_ext_outl : port %04X val %08X\n", port, val); */ switch (port) { default: @@ -2438,13 +2731,73 @@ void mach64_ext_outl(uint16_t port, uint32_t val, void *p) } } +static uint8_t mach64_block_inb(uint16_t port, void *p) +{ + mach64_t *mach64 = (mach64_t *)p; + uint8_t ret; + + ret = mach64_ext_readb(0x400 | (port & 0x3ff), mach64); +#ifdef MACH64_DEBUG + pclog("mach64_block_inb : port %04X ret %02X %04x:%04x\n", port, ret, CS,cpu_state.pc); +#endif + return ret; +} +static uint16_t mach64_block_inw(uint16_t port, void *p) +{ + mach64_t *mach64 = (mach64_t *)p; + uint16_t ret; + + ret = mach64_ext_readw(0x400 | (port & 0x3ff), mach64); +#ifdef MACH64_DEBUG + pclog("mach64_block_inw : port %04X ret %04X\n", port, ret); +#endif + return ret; +} +static uint32_t mach64_block_inl(uint16_t port, void *p) +{ + mach64_t *mach64 = (mach64_t *)p; + uint32_t ret; + + ret = mach64_ext_readl(0x400 | (port & 0x3ff), mach64); +#ifdef MACH64_DEBUG + pclog("mach64_block_inl : port %04X ret %08X\n", port, ret); +#endif + return ret; +} + +static void mach64_block_outb(uint16_t port, uint8_t val, void *p) +{ + mach64_t *mach64 = (mach64_t *)p; + +#ifdef MACH64_DEBUG + pclog("mach64_block_outb : port %04X val %02X\n ", port, val); +#endif + mach64_ext_writeb(0x400 | (port & 0x3ff), val, mach64); +} +static void mach64_block_outw(uint16_t port, uint16_t val, void *p) +{ + mach64_t *mach64 = (mach64_t *)p; + +#ifdef MACH64_DEBUG + pclog("mach64_block_outw : port %04X val %04X\n ", port, val); +#endif + mach64_ext_writew(0x400 | (port & 0x3ff), val, mach64); +} +static void mach64_block_outl(uint16_t port, uint32_t val, void *p) +{ + mach64_t *mach64 = (mach64_t *)p; + +#ifdef MACH64_DEBUG + pclog("mach64_block_outl : port %04X val %08X\n ", port, val); +#endif + mach64_ext_writel(0x400 | (port & 0x3ff), val, mach64); +} + void mach64_write(uint32_t addr, uint8_t val, void *p) { mach64_t *mach64 = (mach64_t *)p; svga_t *svga = &mach64->svga; -// pclog("mach64_write : %05X %02X ", addr, val); addr = (addr & 0x7fff) + mach64->bank_w[(addr >> 15) & 1]; -// pclog("%08X\n", addr); svga_write_linear(addr, val, svga); } @@ -2453,10 +2806,8 @@ uint8_t mach64_read(uint32_t addr, void *p) mach64_t *mach64 = (mach64_t *)p; svga_t *svga = &mach64->svga; uint8_t ret; -// pclog("mach64_read : %05X ", addr); addr = (addr & 0x7fff) + mach64->bank_r[(addr >> 15) & 1]; ret = svga_read_linear(addr, svga); -// pclog("%08X %02X\n", addr, ret); return ret; } @@ -2467,8 +2818,8 @@ void mach64_hwcursor_draw(svga_t *svga, int displine) uint8_t dat; uint32_t col0 = mach64->ramdac.pallook[0]; uint32_t col1 = mach64->ramdac.pallook[1]; - int y_add = enable_overscan ? 16 : 0; - int x_add = enable_overscan ? 8 : 0; + int y_add = (enable_overscan && !suppress_overscan) ? 16 : 0; + int x_add = (enable_overscan && !suppress_overscan) ? 8 : 0; offset = svga->hwcursor_latch.xoff; for (x = 0; x < 64 - svga->hwcursor_latch.xoff; x += 4) @@ -2491,6 +2842,270 @@ void mach64_hwcursor_draw(svga_t *svga, int displine) svga->hwcursor_latch.addr += 16; } +#define CLAMP(x) do \ + { \ + if ((x) & ~0xff) \ + x = ((x) < 0) ? 0 : 0xff; \ + } \ + while (0) + +#define DECODE_ARGB1555() \ + do \ + { \ + for (x = 0; x < mach64->svga.overlay_latch.xsize; x++) \ + { \ + uint16_t dat = ((uint16_t *)src)[x]; \ + \ + int b = dat & 0x1f; \ + int g = (dat >> 5) & 0x1f; \ + int r = (dat >> 10) & 0x1f; \ + \ + b = (b << 3) | (b >> 2); \ + g = (g << 3) | (g >> 2); \ + r = (r << 3) | (r >> 2); \ + \ + mach64->overlay_dat[x] = (r << 16) | (g << 8) | b; \ + } \ + } while (0) + +#define DECODE_RGB565() \ + do \ + { \ + for (x = 0; x < mach64->svga.overlay_latch.xsize; x++) \ + { \ + uint16_t dat = ((uint16_t *)src)[x]; \ + \ + int b = dat & 0x1f; \ + int g = (dat >> 5) & 0x3f; \ + int r = (dat >> 11) & 0x1f; \ + \ + b = (b << 3) | (b >> 2); \ + g = (g << 2) | (g >> 4); \ + r = (r << 3) | (r >> 2); \ + \ + mach64->overlay_dat[x] = (r << 16) | (g << 8) | b; \ + } \ + } while (0) + +#define DECODE_ARGB8888() \ + do \ + { \ + for (x = 0; x < mach64->svga.overlay_latch.xsize; x++) \ + { \ + int b = src[0]; \ + int g = src[1]; \ + int r = src[2]; \ + src += 4; \ + \ + mach64->overlay_dat[x] = (r << 16) | (g << 8) | b; \ + } \ + } while (0) + +#define DECODE_VYUY422() \ + do \ + { \ + for (x = 0; x < mach64->svga.overlay_latch.xsize; x += 2) \ + { \ + uint8_t y1, y2; \ + int8_t u, v; \ + int dR, dG, dB; \ + int r, g, b; \ + \ + y1 = src[0]; \ + u = src[1] - 0x80; \ + y2 = src[2]; \ + v = src[3] - 0x80; \ + src += 4; \ + \ + dR = (359*v) >> 8; \ + dG = (88*u + 183*v) >> 8; \ + dB = (453*u) >> 8; \ + \ + r = y1 + dR; \ + CLAMP(r); \ + g = y1 - dG; \ + CLAMP(g); \ + b = y1 + dB; \ + CLAMP(b); \ + mach64->overlay_dat[x] = (r << 16) | (g << 8) | b; \ + \ + r = y2 + dR; \ + CLAMP(r); \ + g = y2 - dG; \ + CLAMP(g); \ + b = y2 + dB; \ + CLAMP(b); \ + mach64->overlay_dat[x+1] = (r << 16) | (g << 8) | b; \ + } \ + } while (0) + +#define DECODE_YVYU422() \ + do \ + { \ + for (x = 0; x < mach64->svga.overlay_latch.xsize; x += 2) \ + { \ + uint8_t y1, y2; \ + int8_t u, v; \ + int dR, dG, dB; \ + int r, g, b; \ + \ + u = src[0] - 0x80; \ + y1 = src[1]; \ + v = src[2] - 0x80; \ + y2 = src[3]; \ + src += 4; \ + \ + dR = (359*v) >> 8; \ + dG = (88*u + 183*v) >> 8; \ + dB = (453*u) >> 8; \ + \ + r = y1 + dR; \ + CLAMP(r); \ + g = y1 - dG; \ + CLAMP(g); \ + b = y1 + dB; \ + CLAMP(b); \ + mach64->overlay_dat[x] = (r << 16) | (g << 8) | b; \ + \ + r = y2 + dR; \ + CLAMP(r); \ + g = y2 - dG; \ + CLAMP(g); \ + b = y2 + dB; \ + CLAMP(b); \ + mach64->overlay_dat[x+1] = (r << 16) | (g << 8) | b; \ + } \ + } while (0) + +void mach64_overlay_draw(svga_t *svga, int displine) +{ + mach64_t *mach64 = (mach64_t *)svga->p; + int x; + int h_acc = 0; + int h_max = (mach64->scaler_height_width >> 16) & 0x3ff; + int h_inc = mach64->overlay_scale_inc >> 16; + int v_max = mach64->scaler_height_width & 0x3ff; + int v_inc = mach64->overlay_scale_inc & 0xffff; + uint32_t *p; + uint8_t *src = &svga->vram[svga->overlay.addr]; + int old_y = mach64->overlay_v_acc; + int y_diff; + int video_key_fn = mach64->overlay_key_cntl & 5; + int graphics_key_fn = (mach64->overlay_key_cntl >> 4) & 5; + int overlay_cmp_mix = (mach64->overlay_key_cntl >> 8) & 0xf; + + p = &((uint32_t *)buffer32->line[displine])[32 + mach64->svga.overlay_latch.x]; + + if (mach64->scaler_update) + { + switch (mach64->scaler_format) + { + case 0x3: + DECODE_ARGB1555(); + break; + case 0x4: + DECODE_RGB565(); + break; + case 0x6: + DECODE_ARGB8888(); + break; + case 0xb: + DECODE_VYUY422(); + break; + case 0xc: + DECODE_YVYU422(); + break; + + default: + /* pclog("Unknown Mach64 scaler format %x\n", mach64->scaler_format); */ + /*Fill buffer with something recognisably wrong*/ + for (x = 0; x < mach64->svga.overlay_latch.xsize; x++) + mach64->overlay_dat[x] = 0xff00ff; + break; + } + } + + if (overlay_cmp_mix == 2) + { + for (x = 0; x < mach64->svga.overlay_latch.xsize; x++) + { + int h = h_acc >> 12; + + p[x] = mach64->overlay_dat[h]; + + h_acc += h_inc; + if (h_acc > (h_max << 12)) + h_acc = (h_max << 12); + } + } + else + { + for (x = 0; x < mach64->svga.overlay_latch.xsize; x++) + { + int h = h_acc >> 12; + int gr_cmp = 0, vid_cmp = 0; + int use_video; + + switch (video_key_fn) + { + case 0: vid_cmp = 0; break; + case 1: vid_cmp = 1; break; + case 4: vid_cmp = ((mach64->overlay_dat[h] ^ mach64->overlay_video_key_clr) & mach64->overlay_video_key_msk); break; + case 5: vid_cmp = !((mach64->overlay_dat[h] ^ mach64->overlay_video_key_clr) & mach64->overlay_video_key_msk); break; + } + switch (graphics_key_fn) + { + case 0: gr_cmp = 0; break; + case 1: gr_cmp = 1; break; + case 4: gr_cmp = (((p[x]) ^ mach64->overlay_graphics_key_clr) & mach64->overlay_graphics_key_msk & 0xffffff); break; + case 5: gr_cmp = !(((p[x]) ^ mach64->overlay_graphics_key_clr) & mach64->overlay_graphics_key_msk & 0xffffff); break; + } + vid_cmp = vid_cmp ? -1 : 0; + gr_cmp = gr_cmp ? -1 : 0; + + switch (overlay_cmp_mix) + { + case 0x0: use_video = gr_cmp; break; + case 0x1: use_video = 0; break; + case 0x2: use_video = ~0; break; + case 0x3: use_video = ~gr_cmp; break; + case 0x4: use_video = ~vid_cmp; break; + case 0x5: use_video = gr_cmp ^ vid_cmp; break; + case 0x6: use_video = ~gr_cmp ^ vid_cmp; break; + case 0x7: use_video = vid_cmp; break; + case 0x8: use_video = ~gr_cmp | ~vid_cmp; break; + case 0x9: use_video = gr_cmp | ~vid_cmp; break; + case 0xa: use_video = ~gr_cmp | vid_cmp; break; + case 0xb: use_video = gr_cmp | vid_cmp; break; + case 0xc: use_video = gr_cmp & vid_cmp; break; + case 0xd: use_video = ~gr_cmp & vid_cmp; break; + case 0xe: use_video = gr_cmp & ~vid_cmp; break; + case 0xf: use_video = ~gr_cmp & ~vid_cmp; break; + } + + if (use_video) + p[x] = mach64->overlay_dat[h]; + + h_acc += h_inc; + if (h_acc > (h_max << 12)) + h_acc = (h_max << 12); + } + } + + mach64->overlay_v_acc += v_inc; + if (mach64->overlay_v_acc > (v_max << 12)) + mach64->overlay_v_acc = v_max << 12; + + y_diff = (mach64->overlay_v_acc >> 12) - (old_y >> 12); + + if (mach64->scaler_format == 6) + svga->overlay.addr += svga->overlay.pitch*4*y_diff; + else + svga->overlay.addr += svga->overlay.pitch*2*y_diff; + + mach64->scaler_update = y_diff; +} + static void mach64_io_remove(mach64_t *mach64) { int c; @@ -2506,6 +3121,9 @@ static void mach64_io_remove(mach64_t *mach64) } io_removehandler(0x01ce, 0x0002, mach64_in, NULL, NULL, mach64_out, NULL, NULL, mach64); + + if (mach64->block_decoded_io && mach64->block_decoded_io < 0x10000) + io_removehandler(mach64->block_decoded_io, 0x0400, mach64_block_inb, mach64_block_inw, mach64_block_inl, mach64_block_outb, mach64_block_outw, mach64_block_outl, mach64); } static void mach64_io_set(mach64_t *mach64) @@ -2516,38 +3134,45 @@ static void mach64_io_set(mach64_t *mach64) io_sethandler(0x03c0, 0x0020, mach64_in, NULL, NULL, mach64_out, NULL, NULL, mach64); - for (c = 0; c < 8; c++) + if (!mach64->use_block_decoded_io) { - io_sethandler((c * 0x1000) + 0x2ec, 0x0004, mach64_ext_inb, mach64_ext_inw, mach64_ext_inl, mach64_ext_outb, mach64_ext_outw, mach64_ext_outl, mach64); - io_sethandler((c * 0x1000) + 0x6ec, 0x0004, mach64_ext_inb, mach64_ext_inw, mach64_ext_inl, mach64_ext_outb, mach64_ext_outw, mach64_ext_outl, mach64); - io_sethandler((c * 0x1000) + 0xaec, 0x0004, mach64_ext_inb, mach64_ext_inw, mach64_ext_inl, mach64_ext_outb, mach64_ext_outw, mach64_ext_outl, mach64); - io_sethandler((c * 0x1000) + 0xeec, 0x0004, mach64_ext_inb, mach64_ext_inw, mach64_ext_inl, mach64_ext_outb, mach64_ext_outw, mach64_ext_outl, mach64); + for (c = 0; c < 8; c++) + { + io_sethandler((c * 0x1000) + 0x2ec, 0x0004, mach64_ext_inb, mach64_ext_inw, mach64_ext_inl, mach64_ext_outb, mach64_ext_outw, mach64_ext_outl, mach64); + io_sethandler((c * 0x1000) + 0x6ec, 0x0004, mach64_ext_inb, mach64_ext_inw, mach64_ext_inl, mach64_ext_outb, mach64_ext_outw, mach64_ext_outl, mach64); + io_sethandler((c * 0x1000) + 0xaec, 0x0004, mach64_ext_inb, mach64_ext_inw, mach64_ext_inl, mach64_ext_outb, mach64_ext_outw, mach64_ext_outl, mach64); + io_sethandler((c * 0x1000) + 0xeec, 0x0004, mach64_ext_inb, mach64_ext_inw, mach64_ext_inl, mach64_ext_outb, mach64_ext_outw, mach64_ext_outl, mach64); + } } io_sethandler(0x01ce, 0x0002, mach64_in, NULL, NULL, mach64_out, NULL, NULL, mach64); + + if (mach64->use_block_decoded_io && mach64->block_decoded_io && mach64->block_decoded_io < 0x10000) + io_sethandler(mach64->block_decoded_io, 0x0400, mach64_block_inb, mach64_block_inw, mach64_block_inl, mach64_block_outb, mach64_block_outw, mach64_block_outl, mach64); } uint8_t mach64_pci_read(int func, int addr, void *p) { mach64_t *mach64 = (mach64_t *)p; - svga_t *svga = &mach64->svga; - -// pclog("Mach64 PCI read %08X\n", addr); switch (addr) { case 0x00: return 0x02; /*ATi*/ case 0x01: return 0x10; - case 0x02: return 'X'; /*88800GX*/ - case 0x03: return 'G'; + case 0x02: return mach64->pci_id & 0xff; + case 0x03: return mach64->pci_id >> 8; case PCI_REG_COMMAND: return mach64->pci_regs[PCI_REG_COMMAND]; /*Respond to IO and memory accesses*/ case 0x07: return 1 << 1; /*Medium DEVSEL timing*/ - case 0x08: return 0; /*Revision ID*/ + case 0x08: /*Revision ID*/ + if (mach64->type == MACH64_GX) + return 0; + return 0x40; + case 0x09: return 0; /*Programming interface*/ case 0x0a: return 0x01; /*Supports VGA interface, XGA compatible*/ @@ -2558,10 +3183,20 @@ uint8_t mach64_pci_read(int func, int addr, void *p) case 0x12: return mach64->linear_base >> 16; case 0x13: return mach64->linear_base >> 24; + case 0x14: return 0x01; /*Block decoded IO address*/ + case 0x15: return mach64->block_decoded_io >> 8; + case 0x16: return mach64->block_decoded_io >> 16; + case 0x17: return mach64->block_decoded_io >> 24; + case 0x30: return mach64->pci_regs[0x30] & 0x01; /*BIOS ROM address*/ case 0x31: return 0x00; case 0x32: return mach64->pci_regs[0x32]; case 0x33: return mach64->pci_regs[0x33]; + + case 0x3c: return mach64->int_line; + case 0x3d: return PCI_INTA; + + case 0x40: return mach64->use_block_decoded_io; } return 0; } @@ -2570,8 +3205,6 @@ void mach64_pci_write(int func, int addr, uint8_t val, void *p) { mach64_t *mach64 = (mach64_t *)p; -// pclog("Mach64 PCI write %08X %02X\n", addr, val); - switch (addr) { case PCI_REG_COMMAND: @@ -2584,84 +3217,115 @@ void mach64_pci_write(int func, int addr, uint8_t val, void *p) break; case 0x12: - mach64->linear_base = (mach64->linear_base & 0xff000000) | ((val & 0xc0) << 16); + if (mach64->type == MACH64_VT2) + val = 0; + mach64->linear_base = (mach64->linear_base & 0xff000000) | ((val & 0x80) << 16); mach64_updatemapping(mach64); break; case 0x13: - mach64->linear_base = (mach64->linear_base & 0xc00000) | (val << 24); + mach64->linear_base = (mach64->linear_base & 0x800000) | (val << 24); mach64_updatemapping(mach64); break; + case 0x15: + if (mach64->type == MACH64_VT2) + { + if (mach64->pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_IO) + mach64_io_remove(mach64); + mach64->block_decoded_io = (mach64->block_decoded_io & 0xffff0000) | ((val & 0xfc) << 8); + if (mach64->pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_IO) + mach64_io_set(mach64); + } + break; + case 0x16: + if (mach64->type == MACH64_VT2) + { + if (mach64->pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_IO) + mach64_io_remove(mach64); + mach64->block_decoded_io = (mach64->block_decoded_io & 0xff00fc00) | (val << 16); + if (mach64->pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_IO) + mach64_io_set(mach64); + } + break; + case 0x17: + if (mach64->type == MACH64_VT2) + { + if (mach64->pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_IO) + mach64_io_remove(mach64); + mach64->block_decoded_io = (mach64->block_decoded_io & 0x00fffc00) | (val << 24); + if (mach64->pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_IO) + mach64_io_set(mach64); + } + break; + case 0x30: case 0x32: case 0x33: mach64->pci_regs[addr] = val; if (mach64->pci_regs[0x30] & 0x01) { uint32_t addr = (mach64->pci_regs[0x32] << 16) | (mach64->pci_regs[0x33] << 24); - pclog("Mach64 bios_rom enabled at %08x\n", addr); + /* pclog("Mach64 bios_rom enabled at %08x\n", addr); */ mem_mapping_set_addr(&mach64->bios_rom.mapping, addr, 0x8000); } else { - pclog("Mach64 bios_rom disabled\n"); + /* pclog("Mach64 bios_rom disabled\n"); */ mem_mapping_disable(&mach64->bios_rom.mapping); } return; + + case 0x3c: + mach64->int_line = val; + break; + + case 0x40: + if (mach64->type == MACH64_VT2) + { + if (mach64->pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_IO) + mach64_io_remove(mach64); + mach64->use_block_decoded_io = val & 0x04; + if (mach64->pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_IO) + mach64_io_set(mach64); + } + break; } } -void *mach64gx_init() +static void *mach64_common_init() { - int c; mach64_t *mach64 = malloc(sizeof(mach64_t)); - uint32_t vram_amount = 0; memset(mach64, 0, sizeof(mach64_t)); mach64->vram_size = device_get_config_int("memory"); - vram_amount = (mach64-> vram_size == 0) ? (1 << 19) : (mach64->vram_size << 20); - mach64->vram_mask = vram_amount - 1; + mach64->vram_mask = (mach64->vram_size << 20) - 1; - svga_init(&mach64->svga, mach64, vram_amount, + svga_init(&mach64->svga, mach64, mach64->vram_size << 20, mach64_recalctimings, mach64_in, mach64_out, mach64_hwcursor_draw, - NULL); + mach64_overlay_draw); - rom_init(&mach64->bios_rom, "roms/mach64gx/bios.bin", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); if (PCI) mem_mapping_disable(&mach64->bios_rom.mapping); - mem_mapping_add(&mach64->linear_mapping, 0, 0, svga_read_linear, svga_readw_linear, svga_readl_linear, svga_write_linear, svga_writew_linear, svga_writel_linear, NULL, 0, &mach64->svga); - mem_mapping_add(&mach64->mmio_linear_mapping, 0, 0, mach64_ext_readb, mach64_ext_readw, mach64_ext_readl, mach64_ext_writeb, mach64_ext_writew, mach64_ext_writel, NULL, 0, mach64); - mem_mapping_add(&mach64->mmio_mapping, 0xbc000, 0x04000, mach64_ext_readb, mach64_ext_readw, mach64_ext_readl, mach64_ext_writeb, mach64_ext_writew, mach64_ext_writel, NULL, 0, mach64); + mem_mapping_add(&mach64->linear_mapping, 0, 0, svga_read_linear, svga_readw_linear, svga_readl_linear, svga_write_linear, svga_writew_linear, svga_writel_linear, NULL, 0, &mach64->svga); + mem_mapping_add(&mach64->mmio_linear_mapping, 0, 0, mach64_ext_readb, mach64_ext_readw, mach64_ext_readl, mach64_ext_writeb, mach64_ext_writew, mach64_ext_writel, NULL, 0, mach64); + mem_mapping_add(&mach64->mmio_linear_mapping_2, 0, 0, mach64_ext_readb, mach64_ext_readw, mach64_ext_readl, mach64_ext_writeb, mach64_ext_writew, mach64_ext_writel, NULL, 0, mach64); + mem_mapping_add(&mach64->mmio_mapping, 0xbc000, 0x04000, mach64_ext_readb, mach64_ext_readw, mach64_ext_readl, mach64_ext_writeb, mach64_ext_writew, mach64_ext_writel, NULL, 0, mach64); mem_mapping_disable(&mach64->mmio_mapping); mach64_io_set(mach64); - pci_add(mach64_pci_read, mach64_pci_write, mach64); + mach64->card = pci_add(mach64_pci_read, mach64_pci_write, mach64); mach64->pci_regs[PCI_REG_COMMAND] = 3; mach64->pci_regs[0x30] = 0x00; mach64->pci_regs[0x32] = 0x0c; mach64->pci_regs[0x33] = 0x00; - ati_eeprom_load(&mach64->eeprom, "mach64.nvr", 1); - ati68860_ramdac_init(&mach64->ramdac); - - mach64->dac_cntl = 5 << 16; /*ATI 68860 RAMDAC*/ - + mach64->dst_cntl = 3; - switch(mach64->vram_size) - { - case 0: default: mach64->mem_cntl = 0; break; - case 1: mach64->mem_cntl = 1; break; - case 2: mach64->mem_cntl = 2; break; - case 4: mach64->mem_cntl = 3; break; - case 6: mach64->mem_cntl = 4; break; - case 8: mach64->mem_cntl = 5; break; - } - mach64->wake_fifo_thread = thread_create_event(); mach64->fifo_not_full_event = thread_create_event(); mach64->fifo_thread = thread_create(fifo_thread, mach64); @@ -2669,9 +3333,54 @@ void *mach64gx_init() return mach64; } +static void *mach64gx_init() +{ + mach64_t *mach64 = mach64_common_init(); + + mach64->type = MACH64_GX; + mach64->pci_id = (int)'X' | ((int)'G' << 8); + mach64->config_chip_id = 0x020000d7; + mach64->dac_cntl = 5 << 16; /*ATI 68860 RAMDAC*/ + mach64->config_stat0 = (5 << 9) | (3 << 3); /*ATI-68860, 256Kx16 DRAM*/ + if (PCI) + mach64->config_stat0 |= 0; /*PCI, 256Kx16 DRAM*/ + else + mach64->config_stat0 |= 1; /*VLB, 256Kx16 DRAM*/ + + ati_eeprom_load(&mach64->eeprom, L"mach64.nvr", 1); + + rom_init(&mach64->bios_rom, L"roms/mach64gx/bios.bin", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + + return mach64; +} +static void *mach64vt2_init() +{ + mach64_t *mach64 = mach64_common_init(); + svga_t *svga = &mach64->svga; + + mach64->type = MACH64_VT2; + mach64->pci_id = 0x5654; + mach64->config_chip_id = 0x40005654; + mach64->dac_cntl = 1 << 16; /*Internal 24-bit DAC*/ + mach64->config_stat0 = 4; + mach64->use_block_decoded_io = PCI ? 4 : 0; + + ati_eeprom_load(&mach64->eeprom, L"mach64vt.nvr", 1); + + rom_init(&mach64->bios_rom, L"roms/atimach64vt2pci.bin", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + + svga->vblank_start = mach64_vblank_start; + + return mach64; +} + int mach64gx_available() { - return rom_present("roms/mach64gx/bios.bin"); + return rom_present(L"roms/mach64gx/bios.bin"); +} +int mach64vt2_available() +{ + return rom_present(L"roms/atimach64vt2pci.bin"); } void mach64_close(void *p) @@ -2680,6 +3389,10 @@ void mach64_close(void *p) svga_close(&mach64->svga); + thread_kill(mach64->fifo_thread); + thread_destroy_event(mach64->wake_fifo_thread); + thread_destroy_event(mach64->fifo_not_full_event); + free(mach64); } @@ -2748,35 +3461,45 @@ void mach64_add_status_info(char *s, int max_len, void *p) static device_config_t mach64gx_config[] = { { - .name = "memory", - .description = "Memory size", - .type = CONFIG_SELECTION, - .selection = + "memory", "Memory size", CONFIG_SELECTION, "", 4, { { - .description = "512 kB", - .value = 0 + "1 MB", 1 }, { - .description = "1 MB", - .value = 1 + "2 MB", 2 }, { - .description = "2 MB", - .value = 2 + "4 MB", 4 }, { - .description = "4 MB", - .value = 4 - }, - { - .description = "" + "" } - }, - .default_int = 4 + } }, { - .type = -1 + "", "", -1 + } +}; + +static device_config_t mach64vt2_config[] = +{ + { + "memory", "Memory size", CONFIG_SELECTION, "", 4, + { + { + "2 MB", 2 + }, + { + "4 MB", 4 + }, + { + "" + } + } + }, + { + "", "", -1 } }; @@ -2792,3 +3515,15 @@ device_t mach64gx_device = mach64_add_status_info, mach64gx_config }; +device_t mach64vt2_device = +{ + "ATI Mach64VT2", + DEVICE_PCI, + mach64vt2_init, + mach64_close, + mach64vt2_available, + mach64_speed_changed, + mach64_force_redraw, + mach64_add_status_info, + mach64vt2_config +}; diff --git a/src/VIDEO/vid_ati_mach64.h b/src/VIDEO/vid_ati_mach64.h new file mode 100644 index 000000000..c159a6b57 --- /dev/null +++ b/src/VIDEO/vid_ati_mach64.h @@ -0,0 +1,20 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * ATi Mach64 graphics card emulation. + * + * Version: @(#)vid_ati_mach64.h 1.0.0 2017/05/30 + * + * Author: Sarah Walker, + * Miran Grca, + * Copyright 2008-2017 Sarah Walker. + * Copyright 2016-2017 Miran Grca. + */ + +extern device_t mach64gx_device; +extern device_t mach64vt2_device; diff --git a/src/vid_bt485_ramdac.c b/src/VIDEO/vid_bt485_ramdac.c similarity index 99% rename from src/vid_bt485_ramdac.c rename to src/VIDEO/vid_bt485_ramdac.c index 57848a128..e11f69132 100644 --- a/src/vid_bt485_ramdac.c +++ b/src/VIDEO/vid_bt485_ramdac.c @@ -3,12 +3,13 @@ */ /*Brooktree BT485 true colour RAMDAC emulation*/ /*Currently only a dummy stub for logging and passing output to the generic SVGA handler*/ -#include "ibm.h" -#include "mem.h" +#include "../ibm.h" +#include "../mem.h" #include "video.h" #include "vid_svga.h" #include "vid_bt485_ramdac.h" + int bt485_get_clock_divider(bt485_ramdac_t *ramdac) { return 1; /* Will be implemented later. */ diff --git a/src/vid_bt485_ramdac.h b/src/VIDEO/vid_bt485_ramdac.h similarity index 100% rename from src/vid_bt485_ramdac.h rename to src/VIDEO/vid_bt485_ramdac.h diff --git a/src/vid_cga.c b/src/VIDEO/vid_cga.c similarity index 88% rename from src/vid_cga.c rename to src/VIDEO/vid_cga.c index 6b69e7aca..2bb16be22 100644 --- a/src/vid_cga.c +++ b/src/VIDEO/vid_cga.c @@ -1,17 +1,36 @@ -/* Copyright holders: Sarah Walker, Tenshi - see COPYING for more details -*/ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Emulation of the old and new IBM CGA graphics cards. + * + * Version: @(#)vid_cga.c 1.0.0 2017/05/30 + * + * Author: Sarah Walker, + * Miran Grca, + * Copyright 2008-2017 Sarah Walker. + * Copyright 2016-2017 Miran Grca. + */ + /*CGA emulation*/ #include #include -#include "ibm.h" -#include "device.h" -#include "io.h" -#include "mem.h" -#include "timer.h" +#include "../ibm.h" +#include "../io.h" +#include "../mem.h" +#include "../timer.h" +#include "../device.h" #include "video.h" #include "vid_cga.h" -#include "dosbox/vid_cga_comp.h" +#include "vid_cga_comp.h" +#ifndef __unix +# include "../win/win_cgapal.h" /*YUCK*/ +#endif + #define CGA_RGB 0 #define CGA_COMPOSITE 1 @@ -31,7 +50,6 @@ void cga_out(uint16_t addr, uint8_t val, void *p) { cga_t *cga = (cga_t *)p; uint8_t old; -// pclog("CGA_OUT %04X %02X\n", addr, val); switch (addr) { case 0x3D4: @@ -55,6 +73,13 @@ void cga_out(uint16_t addr, uint8_t val, void *p) cga->cgamode = val; update_cga16_color(cga->cgamode); } +#ifndef __unix + if ((cga->cgamode ^ val) & 1) + { + cga_palette = (cga->rgb_type << 1); + cgapal_rebuild(); + } +#endif cga->cgamode = val; return; case 0x3D9: @@ -66,7 +91,6 @@ void cga_out(uint16_t addr, uint8_t val, void *p) uint8_t cga_in(uint16_t addr, void *p) { cga_t *cga = (cga_t *)p; -// pclog("CGA_IN %04X\n", addr); switch (addr) { case 0x3D4: @@ -82,7 +106,10 @@ uint8_t cga_in(uint16_t addr, void *p) void cga_write(uint32_t addr, uint8_t val, void *p) { cga_t *cga = (cga_t *)p; -// pclog("CGA_WRITE %04X %02X\n", addr, val); + /* Horrible hack, I know, but it's the only way to fix the 440FX BIOS filling the VRAM with garbage until Tom fixes the memory emulation. */ + if ((cs == 0xE0000) && (cpu_state.pc == 0xBF2F) && (romset == ROM_440FX)) return; + if ((cs == 0xE0000) && (cpu_state.pc == 0xBF77) && (romset == ROM_440FX)) return; + cga->vram[addr & 0x3fff] = val; if (cga->snow_enabled) { @@ -103,7 +130,6 @@ uint8_t cga_read(uint32_t addr, void *p) cga->charbuffer[(((int)(((cga->dispontime - cga->vidtime) * 2) / CGACONST)) & 0xfc) | 1] = cga->vram[addr & 0x3fff]; } egareads++; -// pclog("CGA_READ %04X\n", addr); return cga->vram[addr & 0x3fff]; } @@ -123,10 +149,8 @@ void cga_recalctimings(cga_t *cga) _dispontime = cga->crtc[1] << 1; } _dispofftime = disptime - _dispontime; -// printf("%i %f %f %f %i %i\n",cgamode&1,disptime,dispontime,dispofftime,crtc[0],crtc[1]); _dispontime *= CGACONST; _dispofftime *= CGACONST; -// printf("Timings - on %f off %f frame %f second %f\n",dispontime,dispofftime,(dispontime+dispofftime)*262.0,(dispontime+dispofftime)*262.0*59.92); cga->dispontime = (int)(_dispontime * (1 << TIMER_SHIFT)); cga->dispofftime = (int)(_dispofftime * (1 << TIMER_SHIFT)); } @@ -158,7 +182,6 @@ void cga_poll(void *p) { cga->firstline = cga->displine; video_wait_for_buffer(); -// printf("Firstline %i\n",firstline); } cga->lastline = cga->displine; for (c = 0; c < 8; c++) @@ -457,10 +480,16 @@ void *cga_standalone_init() cga_comp_init(cga->revision); timer_add(cga_poll, &cga->vidtime, TIMER_ALWAYS_ENABLED, cga); - mem_mapping_add(&cga->mapping, 0xb8000, 0x08000, cga_read, NULL, NULL, cga_write, NULL, NULL, NULL, 0, cga); + mem_mapping_add(&cga->mapping, 0xb8000, 0x08000, cga_read, NULL, NULL, cga_write, NULL, NULL, NULL, MEM_MAPPING_EXTERNAL, cga); io_sethandler(0x03d0, 0x0010, cga_in, NULL, NULL, cga_out, NULL, NULL, cga); overscan_x = overscan_y = 16; + +#ifndef __unix + cga->rgb_type = device_get_config_int("rgb_type"); + cga_palette = (cga->rgb_type << 1); + cgapal_rebuild(); +#endif return cga; } @@ -483,53 +512,63 @@ void cga_speed_changed(void *p) static device_config_t cga_config[] = { { - .name = "display_type", - .description = "Display type", - .type = CONFIG_SELECTION, - .selection = + "display_type", "Display type", CONFIG_SELECTION, "", CGA_RGB, { { - .description = "RGB", - .value = CGA_RGB + "RGB", CGA_RGB }, { - .description = "Composite", - .value = CGA_COMPOSITE + "Composite", CGA_COMPOSITE }, { - .description = "" + "" } - }, - .default_int = CGA_RGB + } }, { - .name = "composite_type", - .description = "Composite type", - .type = CONFIG_SELECTION, - .selection = + "composite_type", "Composite type", CONFIG_SELECTION, "", COMPOSITE_OLD, { { - .description = "Old", - .value = COMPOSITE_OLD + "Old", COMPOSITE_OLD }, { - .description = "New", - .value = COMPOSITE_NEW + "New", COMPOSITE_NEW }, { - .description = "" + "" } - }, - .default_int = COMPOSITE_OLD + } + }, +#ifndef __unix + { + "rgb_type", "RGB type", CONFIG_SELECTION, "", 0, + { + { + "Color", 0 + }, + { + "Green Monochrome", 1 + }, + { + "Amber Monochrome", 2 + }, + { + "Gray Monochrome", 3 + }, + { + "Color (no brown)", 4 + }, + { + "" + } + } + }, +#endif + { + "snow_enabled", "Snow emulation", CONFIG_BINARY, "", 1 }, { - .name = "snow_enabled", - .description = "Snow emulation", - .type = CONFIG_BINARY, - .default_int = 1 - }, - { - .type = -1 + "", "", -1 } }; diff --git a/src/vid_cga.h b/src/VIDEO/vid_cga.h similarity index 61% rename from src/vid_cga.h rename to src/VIDEO/vid_cga.h index e3b187777..bd8d5dbc5 100644 --- a/src/vid_cga.h +++ b/src/VIDEO/vid_cga.h @@ -1,6 +1,21 @@ -/* Copyright holders: Sarah Walker, Tenshi - see COPYING for more details -*/ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Emulation of the old and new IBM CGA graphics cards. + * + * Version: @(#)vid_cga.h 1.0.0 2017/05/30 + * + * Author: Sarah Walker, + * Miran Grca, + * Copyright 2008-2017 Sarah Walker. + * Copyright 2016-2017 Miran Grca. + */ + typedef struct cga_t { mem_mapping_t mapping; @@ -34,6 +49,9 @@ typedef struct cga_t int revision; int composite; int snow_enabled; +#ifndef __unix + int rgb_type; +#endif } cga_t; void cga_init(cga_t *cga); diff --git a/src/dosbox/vid_cga_comp.c b/src/VIDEO/vid_cga_comp.c similarity index 79% rename from src/dosbox/vid_cga_comp.c rename to src/VIDEO/vid_cga_comp.c index 7752f5ba6..513788bec 100644 --- a/src/dosbox/vid_cga_comp.c +++ b/src/VIDEO/vid_cga_comp.c @@ -1,5 +1,21 @@ -/* Code borrowed from DOSBox and adapted by OBattler. - Original author: reenigne. */ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * IBM CGA composite filter, borrowed from reenigne's DOSBox + * patch and ported to C. + * + * Version: @(#)vid_cga.c 1.0.0 2017/05/30 + * + * Author: reenigne, + * Miran Grca, + * Copyright 2015-2017 reenigne. + * Copyright 2015-2017 Miran Grca. + */ #include #include @@ -8,21 +24,23 @@ #include "../ibm.h" #include "../device.h" #include "../mem.h" -#include "../vid_cga.h" +#include "vid_cga.h" #include "vid_cga_comp.h" + int CGA_Composite_Table[1024]; + static double brightness = 0; static double contrast = 100; static double saturation = 100; static double sharpness = 0; static double hue_offset = 0; -// New algorithm by reenigne -// Works in all CGA modes/color settings and can simulate older and newer CGA revisions +/* New algorithm by reenigne + Works in all CGA modes/color settings and can simulate older and newer CGA revisions */ -static const double tau = 6.28318531; // == 2*pi +static const double tau = 6.28318531; /* == 2*pi */ static unsigned char chroma_multiplexer[256] = { 2, 2, 2, 2, 114,174, 4, 3, 2, 1,133,135, 2,113,150, 4, @@ -58,26 +76,28 @@ int video_sharpness; int tandy_mode_control = 0; static bool new_cga = 0; -static bool is_bw = 0; -static bool is_bpp1 = 0; - -static uint8_t comp_pal[256][3]; - -static Bit8u byte_clamp_other(int v) { return v < 0 ? 0 : (v > 255 ? 255 : v); } - -FILE *df; void update_cga16_color(uint8_t cgamode) { int x; - Bit32u x2; + double c, i, v; + double q, a, s, r; + double iq_adjust_i, iq_adjust_q; + double i0, i3, mode_saturation; + + static const double ri = 0.9563; + static const double rq = 0.6210; + static const double gi = -0.2721; + static const double gq = -0.6474; + static const double bi = -1.1069; + static const double bq = 1.7046; if (!new_cga) { min_v = chroma_multiplexer[0] + intensity[0]; max_v = chroma_multiplexer[255] + intensity[3]; } else { - double i0 = intensity[0]; - double i3 = intensity[3]; + i0 = intensity[0]; + i3 = intensity[3]; min_v = NEW_CGA(chroma_multiplexer[0], i0, i0, i0, i0); max_v = NEW_CGA(chroma_multiplexer[255], i3, i3, i3, i3); } @@ -88,9 +108,9 @@ void update_cga16_color(uint8_t cgamode) { else mode_hue = 4; - mode_contrast *= contrast * (new_cga ? 1.2 : 1)/100; // new CGA: 120% - mode_brightness += (new_cga ? brightness-10 : brightness)*5; // new CGA: -10 - double mode_saturation = (new_cga ? 4.35 : 2.9)*saturation/100; // new CGA: 150% + mode_contrast *= contrast * (new_cga ? 1.2 : 1)/100; /* new CGA: 120% */ + mode_brightness += (new_cga ? brightness-10 : brightness)*5; /* new CGA: -10 */ + mode_saturation = (new_cga ? 4.35 : 2.9)*saturation/100; /* new CGA: 150% */ for (x = 0; x < 1024; ++x) { int phase = x & 3; @@ -102,10 +122,8 @@ void update_cga16_color(uint8_t cgamode) { rc = (right & 8) | ((right & 7) != 0 ? 7 : 0); lc = (left & 8) | ((left & 7) != 0 ? 7 : 0); } - double c = - chroma_multiplexer[((lc & 7) << 5) | ((rc & 7) << 2) | phase]; - double i = intensity[(left >> 3) | ((right >> 2) & 2)]; - double v; + c = chroma_multiplexer[((lc & 7) << 5) | ((rc & 7) << 2) | phase]; + i = intensity[(left >> 3) | ((right >> 2) & 2)]; if (!new_cga) v = c + i; else { @@ -117,23 +135,16 @@ void update_cga16_color(uint8_t cgamode) { CGA_Composite_Table[x] = (int) (v*mode_contrast + mode_brightness); } - double i = CGA_Composite_Table[6*68] - CGA_Composite_Table[6*68 + 2]; - double q = CGA_Composite_Table[6*68 + 1] - CGA_Composite_Table[6*68 + 3]; + i = CGA_Composite_Table[6*68] - CGA_Composite_Table[6*68 + 2]; + q = CGA_Composite_Table[6*68 + 1] - CGA_Composite_Table[6*68 + 3]; - double a = tau*(33 + 90 + hue_offset + mode_hue)/360.0; - double c = cos(a); - double s = sin(a); - double r = 256*mode_saturation/sqrt(i*i+q*q); + a = tau*(33 + 90 + hue_offset + mode_hue)/360.0; + c = cos(a); + s = sin(a); + r = 256*mode_saturation/sqrt(i*i+q*q); - double iq_adjust_i = -(i*c + q*s)*r; - double iq_adjust_q = (q*c - i*s)*r; - - static const double ri = 0.9563; - static const double rq = 0.6210; - static const double gi = -0.2721; - static const double gq = -0.6474; - static const double bi = -1.1069; - static const double bq = 1.7046; + iq_adjust_i = -(i*c + q*s)*r; + iq_adjust_q = (q*c - i*s)*r; video_ri = (int) (ri*iq_adjust_i + rq*iq_adjust_q); video_rq = (int) (-ri*iq_adjust_q + rq*iq_adjust_i); @@ -163,6 +174,13 @@ Bit8u * Composite_Process(uint8_t cgamode, Bit8u border, Bit32u blocks/*, bool d int w = blocks*4; + int *o; + Bit8u *rgbi; + int *b; + int *i; + Bit32u* srgb; + int *ap, *bp; + #define COMPOSITE_CONVERT(I, Q) do { \ i[1] = (i[1]<<3) - ap[1]; \ a = ap[0]; \ @@ -182,10 +200,10 @@ Bit8u * Composite_Process(uint8_t cgamode, Bit8u border, Bit32u blocks/*, bool d #define OUT(v) do { *o = (v); ++o; } while (0) - // Simulate CGA composite output - int* o = temp; - Bit8u* rgbi = TempLine; - int* b = &CGA_Composite_Table[border*68]; + /* Simulate CGA composite output */ + o = temp; + rgbi = TempLine; + b = &CGA_Composite_Table[border*68]; for (x = 0; x < 4; ++x) OUT(b[(x+3)&3]); OUT(CGA_Composite_Table[(border<<6) | ((*rgbi)<<2) | 3]); @@ -198,9 +216,9 @@ Bit8u * Composite_Process(uint8_t cgamode, Bit8u border, Bit32u blocks/*, bool d OUT(b[x&3]); if ((cgamode & 4) != 0) { - // Decode - int* i = temp + 5; - Bit32u* srgb = (Bit32u *)TempLine; + /* Decode */ + i = temp + 5; + srgb = (Bit32u *)TempLine; for (x2 = 0; x2 < blocks*4; ++x2) { int c = (i[0]+i[0])<<3; int d = (i[-1]+i[1])<<3; @@ -211,21 +229,21 @@ Bit8u * Composite_Process(uint8_t cgamode, Bit8u border, Bit32u blocks/*, bool d } } else { - // Store chroma - int* i = temp + 4; - int* ap = atemp + 1; - int* bp = btemp + 1; + /* Store chroma */ + i = temp + 4; + ap = atemp + 1; + bp = btemp + 1; for (x = -1; x < w + 1; ++x) { ap[x] = i[-4]-((i[-2]-i[0]+i[2])<<1)+i[4]; bp[x] = (i[-3]-i[-1]+i[1]-i[3])<<1; ++i; } - // Decode + /* Decode */ i = temp + 5; i[-1] = (i[-1]<<3) - ap[-1]; i[0] = (i[0]<<3) - ap[0]; - Bit32u* srgb = (Bit32u *)TempLine; + srgb = (Bit32u *)TempLine; for (x2 = 0; x2 < blocks; ++x2) { int y,a,b,c,d,rr,gg,bb; COMPOSITE_CONVERT(a, b); diff --git a/src/VIDEO/vid_cga_comp.h b/src/VIDEO/vid_cga_comp.h new file mode 100644 index 000000000..fbea172e7 --- /dev/null +++ b/src/VIDEO/vid_cga_comp.h @@ -0,0 +1,27 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * IBM CGA composite filter, borrowed from reenigne's DOSBox + * patch and ported to C. + * + * Version: @(#)vid_cga.h 1.0.0 2017/05/30 + * + * Author: reenigne, + * Miran Grca, + * Copyright 2015-2017 reenigne. + * Copyright 2015-2017 Miran Grca. + */ + +#define Bit8u uint8_t +#define Bit32u uint32_t +#define Bitu unsigned int +#define bool uint8_t + +void update_cga16_color(uint8_t cgamode); +void cga_comp_init(int revision); +Bit8u * Composite_Process(uint8_t cgamode, Bit8u border, Bit32u blocks/*, bool doublewidth*/, Bit8u *TempLine); diff --git a/src/vid_cl5429.h b/src/VIDEO/vid_cl5429.h similarity index 100% rename from src/vid_cl5429.h rename to src/VIDEO/vid_cl5429.h diff --git a/src/vid_cl_gd.c b/src/VIDEO/vid_cl_gd.c similarity index 95% rename from src/vid_cl_gd.c rename to src/VIDEO/vid_cl_gd.c index b244f408a..89d9d3c77 100644 --- a/src/vid_cl_gd.c +++ b/src/VIDEO/vid_cl_gd.c @@ -1,10 +1,10 @@ #include #include -#include "ibm.h" -#include "device.h" -#include "io.h" -#include "mem.h" -#include "rom.h" +#include "../ibm.h" +#include "../io.h" +#include "../mem.h" +#include "../rom.h" +#include "../device.h" #include "video.h" #include "vid_svga.h" #include "vid_svga_render.h" @@ -12,6 +12,7 @@ #include "vid_cl_gd.h" #include "vid_cl_gd_blit.h" + void cirrus_update_bank_ptr(clgd_t *clgd, uint8_t bank_index); void clgd_recalctimings(svga_t *svga); @@ -410,8 +411,8 @@ void clgd_hwcursor_draw(svga_t *svga, int displine) int offset = svga->hwcursor_latch.x - svga->hwcursor_latch.xoff; int largecur = (svga->seqregs[0x12] & 4); int cursize = (largecur) ? 64 : 32; - int y_add = enable_overscan ? 16 : 0; - int x_add = enable_overscan ? 8 : 0; + int y_add = (enable_overscan && !suppress_overscan) ? 16 : 0; + int x_add = (enable_overscan && !suppress_overscan) ? 8 : 0; for (x = 0; x < cursize; x += 8) { @@ -648,6 +649,9 @@ uint8_t cirrus_mmio_blt_read(uint32_t address, void *p) case (CIRRUS_MMIO_BLTTRANSPARENTCOLORMASK + 1): value = svga->gdcreg[0x39]; break; + default: + value = 0xff; + break; } return value; @@ -803,7 +807,7 @@ uint8_t cirrus_read(uint32_t addr, void *p) return ret; } -void *clgd_common_init(char *romfn, uint8_t id) +void *clgd_common_init(wchar_t *romfn, uint8_t id) { clgd = malloc(sizeof(clgd_t)); svga_t *svga = &clgd->svga; @@ -877,92 +881,92 @@ void *clgd_common_init(char *romfn, uint8_t id) void *gd6235_init() { - return clgd_common_init("roms/vga6235.rom", CIRRUS_ID_CLGD6235); + return clgd_common_init(L"roms/vga6235.rom", CIRRUS_ID_CLGD6235); } void *gd5422_init() { - return clgd_common_init("roms/CL5422.ROM", CIRRUS_ID_CLGD5422); + return clgd_common_init(L"roms/CL5422.ROM", CIRRUS_ID_CLGD5422); } void *gd5429_init() { - return clgd_common_init("roms/5429.vbi", CIRRUS_ID_CLGD5429); + return clgd_common_init(L"roms/5429.vbi", CIRRUS_ID_CLGD5429); } void *gd5430_init() { - return clgd_common_init("roms/pci.BIN", CIRRUS_ID_CLGD5430); + return clgd_common_init(L"roms/pci.BIN", CIRRUS_ID_CLGD5430); } void *dia5430_init() { - return clgd_common_init("roms/diamondvlbus.BIN", CIRRUS_ID_CLGD5430); + return clgd_common_init(L"roms/diamondvlbus.BIN", CIRRUS_ID_CLGD5430); } void *gd5434_init() { - return clgd_common_init("roms/japan.BIN", CIRRUS_ID_CLGD5434); + return clgd_common_init(L"roms/japan.BIN", CIRRUS_ID_CLGD5434); } void *gd5436_init() { - return clgd_common_init("roms/5436.VBI", CIRRUS_ID_CLGD5436); + return clgd_common_init(L"roms/5436.VBI", CIRRUS_ID_CLGD5436); } void *gd5440_init() { - return clgd_common_init("roms/5440BIOS.BIN", CIRRUS_ID_CLGD5440); + return clgd_common_init(L"roms/5440BIOS.BIN", CIRRUS_ID_CLGD5440); } void *gd5446_init() { - return clgd_common_init("roms/5446BV.VBI", CIRRUS_ID_CLGD5446); + return clgd_common_init(L"roms/5446BV.VBI", CIRRUS_ID_CLGD5446); } static int gd5422_available() { - return rom_present("roms/CL5422.ROM"); + return rom_present(L"roms/CL5422.ROM"); } static int gd5429_available() { - return rom_present("roms/5429.vbi"); + return rom_present(L"roms/5429.vbi"); } static int gd5430_available() { - return rom_present("roms/pci.BIN"); + return rom_present(L"roms/pci.BIN"); } static int dia5430_available() { - return rom_present("roms/diamondvlbus.BIN"); + return rom_present(L"roms/diamondvlbus.BIN"); } static int gd5434_available() { - return rom_present("roms/japan.BIN"); + return rom_present(L"roms/japan.BIN"); } static int gd5436_available() { - return rom_present("roms/5436.VBI"); + return rom_present(L"roms/5436.VBI"); } static int gd5440_available() { - return rom_present("roms/5440BIOS.BIN"); + return rom_present(L"roms/5440BIOS.BIN"); } static int gd5446_available() { - return rom_present("roms/5446BV.VBI"); + return rom_present(L"roms/5446BV.VBI"); } static int gd6235_available() { - return rom_present("roms/vga6235.rom"); + return rom_present(L"roms/vga6235.rom"); } void clgd_close(void *p) @@ -1110,4 +1114,4 @@ device_t gd6235_device = clgd_speed_changed, clgd_force_redraw, clgd_add_status_info -}; \ No newline at end of file +}; diff --git a/src/vid_cl_gd.h b/src/VIDEO/vid_cl_gd.h similarity index 100% rename from src/vid_cl_gd.h rename to src/VIDEO/vid_cl_gd.h diff --git a/src/vid_cl_gd_blit.c b/src/VIDEO/vid_cl_gd_blit.c similarity index 97% rename from src/vid_cl_gd_blit.c rename to src/VIDEO/vid_cl_gd_blit.c index 0a5348629..18d6642f3 100644 --- a/src/vid_cl_gd_blit.c +++ b/src/VIDEO/vid_cl_gd_blit.c @@ -1,10 +1,10 @@ /*This is the CL-GD 5446 blitter, directly from QEMU*/ #include -#include "ibm.h" -#include "device.h" -#include "io.h" -#include "mem.h" -#include "rom.h" +#include "../ibm.h" +#include "../io.h" +#include "../mem.h" +#include "../rom.h" +#include "../device.h" #include "video.h" #include "vid_svga.h" #include "vid_svga_render.h" @@ -12,6 +12,7 @@ #include "vid_cl_gd.h" #include "vid_cl_gd_blit.h" + // Same for all the svga->vrammask which are -s>cirrus_addr_mask in the original. // Eventually this needs to be configurable @@ -24,6 +25,8 @@ #define glue(a,b) glue_hidden(a,b) #define glue_hidden(a,b) a ## b +static uint8_t rop_to_index[256]; + int cl_gd_ABS(int sval) { if (sval < 0) @@ -65,11 +68,11 @@ bool blit_is_unsafe(clgd_t *clgd, svga_t *svga) return false; } -void cirrus_bitblt_rop_nop(clgd_t *clgd, uint8_t *dst, const uint8_t *src, int dstpitch, int srcpitch, int bltwidth, int bltheight) +void cirrus_bitblt_rop_nop(clgd_t *clgd, svga_t *svga, uint8_t *dst, const uint8_t *src, int dstpitch, int srcpitch, int bltwidth, int bltheight) { } -void cirrus_bitblt_fill_nop(clgd_t *clgd, uint8_t *dst, int dstpitch, int bltwidth, int bltheight) +void cirrus_bitblt_fill_nop(clgd_t *clgd, svga_t *svga, uint8_t *dst, int dstpitch, int bltwidth, int bltheight) { } @@ -394,7 +397,7 @@ inline void cirrus_bitblt_bgcol(clgd_t *clgd, svga_t *svga) void cirrus_invalidate_region(clgd_t *clgd, svga_t *svga, int off_begin, int off_pitch, int bytesperline, int lines) { - int y; + int x, y; int off_cur; int off_cur_end; @@ -404,6 +407,10 @@ void cirrus_invalidate_region(clgd_t *clgd, svga_t *svga, int off_begin, int off off_cur_end = ((off_cur + bytesperline) & svga->vrammask); // Memory region set dirty off_begin += off_pitch; + for (x = (off_cur >> 12); x <= (off_cur_end >> 12); x++) + { + svga->changedvram[x]++; + } } } @@ -818,4 +825,4 @@ void init_rops() rop_to_index[CIRRUS_ROP_NOTSRC] = 13; rop_to_index[CIRRUS_ROP_NOTSRC_OR_DST] = 14; rop_to_index[CIRRUS_ROP_NOTSRC_AND_NOTDST] = 15; -} \ No newline at end of file +} diff --git a/src/vid_cl_gd_blit.h b/src/VIDEO/vid_cl_gd_blit.h similarity index 90% rename from src/vid_cl_gd_blit.h rename to src/VIDEO/vid_cl_gd_blit.h index c315ff3aa..ebf22eb56 100644 --- a/src/vid_cl_gd_blit.h +++ b/src/VIDEO/vid_cl_gd_blit.h @@ -1,5 +1,3 @@ -static uint8_t rop_to_index[256]; - #define le32_to_cpu(x) (x) #define le16_to_cpu(x) (x) diff --git a/src/vid_cl_gd_vga_rop.h b/src/VIDEO/vid_cl_gd_vga_rop.h similarity index 100% rename from src/vid_cl_gd_vga_rop.h rename to src/VIDEO/vid_cl_gd_vga_rop.h diff --git a/src/vid_cl_gd_vga_rop2.h b/src/VIDEO/vid_cl_gd_vga_rop2.h similarity index 100% rename from src/vid_cl_gd_vga_rop2.h rename to src/VIDEO/vid_cl_gd_vga_rop2.h diff --git a/src/vid_cl_ramdac.c b/src/VIDEO/vid_cl_ramdac.c similarity index 97% rename from src/vid_cl_ramdac.c rename to src/VIDEO/vid_cl_ramdac.c index 2520038ea..340d27c88 100644 --- a/src/vid_cl_ramdac.c +++ b/src/VIDEO/vid_cl_ramdac.c @@ -1,13 +1,14 @@ -#include "ibm.h" -#include "device.h" -#include "mem.h" -#include "rom.h" +#include "../ibm.h" +#include "../mem.h" +#include "../rom.h" +#include "../device.h" #include "video.h" #include "vid_svga.h" #include "vid_cl_ramdac.h" #include "vid_cl_gd.h" #include "vid_cl_gd_blit.h" + void cl_ramdac_out(uint16_t addr, uint8_t val, cl_ramdac_t *ramdac, void *clgd, svga_t *svga) { clgd_t *real_clgd = (clgd_t *) clgd; @@ -97,4 +98,4 @@ uint8_t cl_ramdac_in(uint16_t addr, cl_ramdac_t *ramdac, void *clgd, svga_t *svg break; } return svga_in(addr, svga); -} \ No newline at end of file +} diff --git a/src/vid_cl_ramdac.h b/src/VIDEO/vid_cl_ramdac.h similarity index 100% rename from src/vid_cl_ramdac.h rename to src/VIDEO/vid_cl_ramdac.h diff --git a/src/vid_colorplus.c b/src/VIDEO/vid_colorplus.c similarity index 91% rename from src/vid_colorplus.c rename to src/VIDEO/vid_colorplus.c index cb3ab38b3..ab07127f7 100644 --- a/src/vid_colorplus.c +++ b/src/VIDEO/vid_colorplus.c @@ -1,15 +1,16 @@ /*Plantronics ColorPlus emulation*/ #include #include -#include "ibm.h" -#include "device.h" -#include "io.h" -#include "mem.h" -#include "timer.h" +#include "../ibm.h" +#include "../io.h" +#include "../mem.h" +#include "../timer.h" +#include "../device.h" #include "video.h" #include "vid_cga.h" #include "vid_colorplus.h" -#include "dosbox/vid_cga_comp.h" +#include "vid_cga_comp.h" + /* Bits in the colorplus control register: */ #define COLORPLUS_PLANE_SWAP 0x40 /* Swap planes at 0000h and 4000h */ @@ -33,7 +34,6 @@ void colorplus_out(uint16_t addr, uint8_t val, void *p) { colorplus_t *colorplus = (colorplus_t *)p; -// pclog("COLORPLUS_OUT %04X %02X\n", addr, val); if (addr == 0x3DD) { colorplus->control = val & 0x70; @@ -55,7 +55,6 @@ void colorplus_write(uint32_t addr, uint8_t val, void *p) { colorplus_t *colorplus = (colorplus_t *)p; -// pclog("COLORPLUS_WRITE %04X %02X\n", addr, val); if ((colorplus->control & COLORPLUS_PLANE_SWAP) && (colorplus->control & COLORPLUS_EITHER_MODE) && (colorplus->cga.cgamode & CGA_GRAPHICS_MODE)) @@ -97,7 +96,6 @@ uint8_t colorplus_read(uint32_t addr, void *p) colorplus->cga.charbuffer[(((int)(((colorplus->cga.dispontime - colorplus->cga.vidtime) * 2) / CGACONST)) & 0xfc) | 1] = colorplus->cga.vram[addr & 0x7fff]; } egareads++; -// pclog("COLORPLUS_READ %04X\n", addr); return colorplus->cga.vram[addr & 0x7fff]; } @@ -145,7 +143,6 @@ void colorplus_poll(void *p) { colorplus->cga.firstline = colorplus->cga.displine; video_wait_for_buffer(); -// printf("Firstline %i\n",firstline); } colorplus->cga.lastline = colorplus->cga.displine; /* Left / right border */ @@ -225,7 +222,7 @@ void colorplus_poll(void *p) for (c = 0; c < x; c++) buffer32->line[colorplus->cga.displine][c] = buffer->line[colorplus->cga.displine][c] & 0xf; - Composite_Process(&colorplus->cga, 0, x >> 2, buffer32->line[colorplus->cga.displine]); + Composite_Process(colorplus->cga.cgamode, 0, x >> 2, buffer32->line[colorplus->cga.displine]); } colorplus->cga.sc = oldsc; @@ -380,9 +377,9 @@ void *colorplus_standalone_init() colorplus->cga.vram = malloc(0x8000); - cga_comp_init(&colorplus->cga); + cga_comp_init(1); timer_add(colorplus_poll, &colorplus->cga.vidtime, TIMER_ALWAYS_ENABLED, colorplus); - mem_mapping_add(&colorplus->cga.mapping, 0xb8000, 0x08000, colorplus_read, NULL, NULL, colorplus_write, NULL, NULL, NULL, 0, colorplus); + mem_mapping_add(&colorplus->cga.mapping, 0xb8000, 0x08000, colorplus_read, NULL, NULL, colorplus_write, NULL, NULL, NULL, MEM_MAPPING_EXTERNAL, colorplus); io_sethandler(0x03d0, 0x0010, colorplus_in, NULL, NULL, colorplus_out, NULL, NULL, colorplus); return colorplus; @@ -406,53 +403,38 @@ void colorplus_speed_changed(void *p) static device_config_t colorplus_config[] = { { - .name = "display_type", - .description = "Display type", - .type = CONFIG_SELECTION, - .selection = + "display_type", "Display type", CONFIG_SELECTION, "", CGA_RGB, { { - .description = "RGB", - .value = CGA_RGB + "RGB", CGA_RGB }, { - .description = "Composite", - .value = CGA_COMPOSITE + "Composite", CGA_COMPOSITE }, { - .description = "" + "" } - }, - .default_int = CGA_RGB + } }, { - .name = "composite_type", - .description = "Composite type", - .type = CONFIG_SELECTION, - .selection = + "composite_type", "Composite type", CONFIG_SELECTION, "", COMPOSITE_OLD, { { - .description = "Old", - .value = COMPOSITE_OLD + "Old", COMPOSITE_OLD }, { - .description = "New", - .value = COMPOSITE_NEW + "New", COMPOSITE_NEW }, { - .description = "" + "" } - }, - .default_int = COMPOSITE_OLD + } }, { - .name = "snow_enabled", - .description = "Snow emulation", - .type = CONFIG_BINARY, - .default_int = 1 + "snow_enabled", "Snow emulation", CONFIG_BINARY, "", 1 }, { - .type = -1 + "", "", -1 } }; diff --git a/src/vid_colorplus.h b/src/VIDEO/vid_colorplus.h similarity index 100% rename from src/vid_colorplus.h rename to src/VIDEO/vid_colorplus.h diff --git a/src/VIDEO/vid_ega.c b/src/VIDEO/vid_ega.c new file mode 100644 index 000000000..378db12e8 --- /dev/null +++ b/src/VIDEO/vid_ega.c @@ -0,0 +1,1285 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Emulation of the EGA, Chips & Technologies SuperEGA, and + * AX JEGA graphics cards. + * + * Version: @(#)vid_ega.c 1.0.2 2017/06/05 + * + * Author: Sarah Walker, + * Miran Grca, + * akm, + * Copyright 2008-2017 Sarah Walker. + * Copyright 2016-2017 Miran Grca. + * Copyright 2017-2017 akm. + */ + +#include +#include +#include "../ibm.h" +#include "../io.h" +#include "../mem.h" +#include "../rom.h" +#include "../timer.h" +#include "../device.h" +#include "video.h" +#include "vid_ega.h" +#include "vid_ega_render.h" + + +extern uint8_t edatlookup[4][4]; + +static uint8_t ega_rotate[8][256]; + +static uint32_t pallook16[256], pallook64[256]; + +/*3C2 controls default mode on EGA. On VGA, it determines monitor type (mono or colour)*/ +int egaswitchread,egaswitches=9; /*7=CGA mode (200 lines), 9=EGA mode (350 lines), 8=EGA mode (200 lines)*/ + +static int old_overscan_color = 0; + +int update_overscan = 0; + +uint8_t jfont_sbcs_19[SBCS19_LEN]; /* 256 * 19( * 8) */ +uint8_t jfont_dbcs_16[DBCS16_LEN]; /* 65536 * 16 * 2 (* 8) */ + +typedef struct { + char id[ID_LEN]; + char name[NAME_LEN]; + unsigned char width; + unsigned char height; + unsigned char type; +} fontx_h; + +typedef struct { + uint16_t start; + uint16_t end; +} fontxTbl; + +static __inline int ega_jega_enabled(ega_t *ega) +{ + if (!ega->is_jega) + { + return 0; + } + + return !(ega->RMOD1 & 0x40); +} + +void ega_jega_write_font(ega_t *ega) +{ + unsigned int chr = ega->RDFFB; + unsigned int chr_2 = ega->RDFSB; + + ega->RSTAT &= ~0x02; + + /* Check if the character code is in the Wide character set of Shift-JIS */ + if (((chr >= 0x40) && (chr <= 0x7e)) || ((chr >= 0x80) && (chr <= 0xfc))) + { + if (ega->font_index >= 32) + { + ega->font_index = 0; + } + chr <<= 8; + /* Fix vertical character position */ + chr |= chr_2; + if (ega->font_index < 16) + { + jfont_dbcs_16[(chr * 32) + (ega->font_index * 2)] = ega->RDFAP; /* 16x16 font */ + } + else + { + jfont_dbcs_16[(chr * 32) + ((ega->font_index - 16) * 2) + 1] = ega->RDFAP; /* 16x16 font */ + } + } + else + { + if (ega->font_index >= 19) + { + ega->font_index = 0; + } + jfont_sbcs_19[(chr * 19) + ega->font_index] = ega->RDFAP; /* 8x19 font */ + } + ega->font_index++; + ega->RSTAT |= 0x02; +} + +void ega_jega_read_font(ega_t *ega) +{ + unsigned int chr = ega->RDFFB; + unsigned int chr_2 = ega->RDFSB; + + ega->RSTAT &= ~0x02; + + /* Check if the character code is in the Wide character set of Shift-JIS */ + if (((chr >= 0x40) && (chr <= 0x7e)) || ((chr >= 0x80) && (chr <= 0xfc))) + { + if (ega->font_index >= 32) + { + ega->font_index = 0; + } + chr <<= 8; + /* Fix vertical character position */ + chr |= chr_2; + if (ega->font_index < 16) + { + ega->RDFAP = jfont_dbcs_16[(chr * 32) + (ega->font_index * 2)]; /* 16x16 font */ + } + else + { + ega->RDFAP = jfont_dbcs_16[(chr * 32) + ((ega->font_index - 16) * 2) + 1]; /* 16x16 font */ + } + } + else + { + if (ega->font_index >= 19) + { + ega->font_index = 0; + } + ega->RDFAP = jfont_sbcs_19[(chr * 19) + ega->font_index]; /* 8x19 font */ + } + ega->font_index++; + ega->RSTAT |= 0x02; +} + +void ega_out(uint16_t addr, uint8_t val, void *p) +{ + ega_t *ega = (ega_t *)p; + int c; + uint8_t o, old; + uint8_t crtcreg; + + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(ega->miscout & 1)) + addr ^= 0x60; + + switch (addr) + { + case 0x3c0: + case 0x3c1: + if (!ega->attrff) + ega->attraddr = val & 31; + else + { + ega->attrregs[ega->attraddr & 31] = val; + if (ega->attraddr < 16) + fullchange = changeframecount; + if (ega->attraddr == 0x10 || ega->attraddr == 0x14 || ega->attraddr < 0x10) + { + for (c = 0; c < 16; c++) + { + if (ega->attrregs[0x10] & 0x80) ega->egapal[c] = (ega->attrregs[c] & 0xf) | ((ega->attrregs[0x14] & 0xf) << 4); + else ega->egapal[c] = (ega->attrregs[c] & 0x3f) | ((ega->attrregs[0x14] & 0xc) << 4); + } + } + } + ega->attrff ^= 1; + break; + case 0x3c2: + egaswitchread = val & 0xc; + ega->vres = !(val & 0x80); + ega->pallook = ega->vres ? pallook16 : pallook64; + ega->vidclock = val & 4; /*printf("3C2 write %02X\n",val);*/ + ega->miscout=val; + break; + case 0x3c4: + ega->seqaddr = val; + break; + case 0x3c5: + o = ega->seqregs[ega->seqaddr & 0xf]; + ega->seqregs[ega->seqaddr & 0xf] = val; + if (o != val && (ega->seqaddr & 0xf) == 1) + ega_recalctimings(ega); + switch (ega->seqaddr & 0xf) + { + case 1: + if (ega->scrblank && !(val & 0x20)) + fullchange = 3; + ega->scrblank = (ega->scrblank & ~0x20) | (val & 0x20); + break; + case 2: + ega->writemask = val & 0xf; + break; + case 3: + ega->charsetb = (((val >> 2) & 3) * 0x10000) + 2; + ega->charseta = ((val & 3) * 0x10000) + 2; + break; + case 4: + ega->chain2_write = !(val & 4); + break; + } + break; + case 0x3ce: + ega->gdcaddr = val; + break; + case 0x3cf: + ega->gdcreg[ega->gdcaddr & 15] = val; + switch (ega->gdcaddr & 15) + { + case 2: + ega->colourcompare = val; + break; + case 4: + ega->readplane = val & 3; + break; + case 5: + ega->writemode = val & 3; + ega->readmode = val & 8; + ega->chain2_read = val & 0x10; + break; + case 6: + switch (val & 0xc) + { + case 0x0: /*128k at A0000*/ + mem_mapping_set_addr(&ega->mapping, 0xa0000, 0x20000); + break; + case 0x4: /*64k at A0000*/ + mem_mapping_set_addr(&ega->mapping, 0xa0000, 0x10000); + break; + case 0x8: /*32k at B0000*/ + mem_mapping_set_addr(&ega->mapping, 0xb0000, 0x08000); + break; + case 0xC: /*32k at B8000*/ + mem_mapping_set_addr(&ega->mapping, 0xb8000, 0x08000); + break; + } + break; + case 7: + ega->colournocare = val; + break; + } + break; + case 0x3d0: + case 0x3d4: + ega->crtcreg = val; + return; + case 0x3d1: + case 0x3d5: + if ((ega->crtcreg < 0xb9) || !ega->is_jega) + { + crtcreg = ega->crtcreg & 0x1f; + if (crtcreg <= 7 && ega->crtc[0x11] & 0x80) return; + old = ega->crtc[crtcreg]; + ega->crtc[crtcreg] = val; + if (old != val) + { + if (crtcreg < 0xe || crtcreg > 0x10) + { + fullchange = changeframecount; + ega_recalctimings(ega); + } + } + } + else + { + switch(ega->crtcreg) + { + case 0xb9: /* Mode register 1 */ + ega->RMOD1 = val; + break; + case 0xba: /* Mode register 2 */ + ega->RMOD2 = val; + break; + case 0xbb: /* ANK Group sel */ + ega->RDAGS = val; + break; + case 0xbc: /* Font access first byte */ + if (ega->RDFFB != val) + { + ega->RDFFB = val; + ega->font_index = 0; + } + break; + case 0xbd: /* Font access Second Byte */ + if (ega->RDFSB != val) + { + ega->RDFSB = val; + ega->font_index = 0; + } + break; + case 0xbe: /* Font Access Pattern */ + ega->RDFAP = val; + ega_jega_write_font(ega); + break; + case 0xdb: + ega->RPSSC = val; + break; + case 0xd9: + ega->RPSSU = val; + break; + case 0xda: + ega->RPSSL = val; + break; + case 0xdc: /* Superimposed mode (only AX-2 system, not implemented) */ + ega->RPPAJ = val; + break; + case 0xdd: + ega->RCMOD = val; + break; + case 0xde: /* Cursor Skew control */ + ega->RCSKW = val; + break; + case 0xdf: /* Font R/W register */ + ega->RSTAT = val; + break; + default: + pclog("JEGA: Write to illegal index %02X\n", ega->crtcreg); + break; + } + } + break; + } +} + +/* + * Get the input status register 0 + * + * Note by Tohka: Code from PCE. + */ +static uint8_t ega_get_input_status_0(ega_t *ega) +{ + unsigned bit; + uint8_t status0 = 0; + + bit = (egaswitchread >> 2) & 3; + + if (egaswitches & (0x08 >> bit)) { + status0 |= 0x10; + } + else { + status0 &= ~0x10; + } + + return status0; +} + +uint8_t ega_in(uint16_t addr, void *p) +{ + ega_t *ega = (ega_t *)p; + int crtcreg; + + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(ega->miscout & 1)) + addr ^= 0x60; + + switch (addr) + { + case 0x3c0: + return ega->attraddr; + case 0x3c1: + return ega->attrregs[ega->attraddr]; + case 0x3c2: + return ega_get_input_status_0(ega); + break; + case 0x3c4: + return ega->seqaddr; + case 0x3c5: + return ega->seqregs[ega->seqaddr & 0xf]; + case 0x3c8: + return 2; + case 0x3cc: + return ega->miscout; + case 0x3ce: + return ega->gdcaddr; + case 0x3cf: + return ega->gdcreg[ega->gdcaddr & 0xf]; + case 0x3d0: + case 0x3d4: + return ega->crtcreg; + case 0x3d1: + case 0x3d5: + if ((ega->crtcreg < 0xb9) || !ega->is_jega) + { + crtcreg = ega->crtcreg & 0x1f; + return ega->crtc[crtcreg]; + } + else + { + switch(ega->crtcreg) + { + case 0xb9: + return ega->RMOD1; + case 0xba: + return ega->RMOD2; + case 0xbb: + return ega->RDAGS; + case 0xbc: /* BCh RDFFB Font access First Byte */ + return ega->RDFFB; + case 0xbd: /* BDh RDFFB Font access Second Byte */ + return ega->RDFSB; + case 0xbe: /* BEh RDFAP Font Access Pattern */ + ega_jega_read_font(ega); + return ega->RDFAP; + case 0xdb: + return ega->RPSSC; + case 0xd9: + return ega->RPSSU; + case 0xda: + return ega->RPSSL; + case 0xdc: + return ega->RPPAJ; + case 0xdd: + return ega->RCMOD; + case 0xde: + return ega->RCSKW; + case 0xdf: + return ega->ROMSL; + case 0xbf: + return 0x03; /* The font is always readable and writable */ + default: + pclog("JEGA: Read from illegal index %02X\n", ega->crtcreg); + return 0x00; + } + } + case 0x3da: + ega->attrff = 0; + ega->stat ^= 0x30; /*Fools IBM EGA video BIOS self-test*/ + return ega->stat; + } + return 0xff; +} + +void ega_recalctimings(ega_t *ega) +{ + double _dispontime, _dispofftime, disptime; + double crtcconst; + + ega->vtotal = ega->crtc[6]; + ega->dispend = ega->crtc[0x12]; + ega->vsyncstart = ega->crtc[0x10]; + ega->split = ega->crtc[0x18]; + + if (ega->crtc[7] & 1) ega->vtotal |= 0x100; + if (ega->crtc[7] & 32) ega->vtotal |= 0x200; + ega->vtotal++; + + if (ega->crtc[7] & 2) ega->dispend |= 0x100; + if (ega->crtc[7] & 64) ega->dispend |= 0x200; + ega->dispend++; + + if (ega->crtc[7] & 4) ega->vsyncstart |= 0x100; + if (ega->crtc[7] & 128) ega->vsyncstart |= 0x200; + ega->vsyncstart++; + + if (ega->crtc[7] & 0x10) ega->split |= 0x100; + if (ega->crtc[9] & 0x40) ega->split |= 0x200; + ega->split+=2; + + ega->hdisp = ega->crtc[1]; + ega->hdisp++; + + ega->rowoffset = ega->crtc[0x13]; + ega->rowcount = ega->crtc[9] & 0x1f; + overscan_y = (ega->rowcount + 1) << 1; + + if (ega->vidclock) crtcconst = (ega->seqregs[1] & 1) ? MDACONST : (MDACONST * (9.0 / 8.0)); + else crtcconst = (ega->seqregs[1] & 1) ? CGACONST : (CGACONST * (9.0 / 8.0)); + + disptime = ega->crtc[0] + 2; + _dispontime = ega->crtc[1] + 1; + + if (ega->seqregs[1] & 8) + { + disptime*=2; + _dispontime*=2; + overscan_y <<= 1; + } + if (overscan_y < 16) + { + overscan_y = 16; + } + _dispofftime = disptime - _dispontime; + _dispontime *= crtcconst; + _dispofftime *= crtcconst; + + ega->dispontime = (int)(_dispontime * (1 << TIMER_SHIFT)); + ega->dispofftime = (int)(_dispofftime * (1 << TIMER_SHIFT)); +} + +void ega_poll(void *p) +{ + ega_t *ega = (ega_t *)p; + int x; + int drawcursor = 0; + int y_add = enable_overscan ? (overscan_y >> 1) : 0; + int x_add = enable_overscan ? 8 : 0; + int y_add_ex = enable_overscan ? overscan_y : 0; + int x_add_ex = enable_overscan ? 16 : 0; + uint32_t *q, i, j; + int wx = 640, wy = 350; + + if (!ega->linepos) + { + ega->vidtime += ega->dispofftime; + + ega->stat |= 1; + ega->linepos = 1; + + if (ega->dispon) + { + if (ega->firstline == 2000) + { + ega->firstline = ega->displine; + video_wait_for_buffer(); + } + + if (ega->scrblank) + { + ega_render_blank(ega); + } + else if (!(ega->gdcreg[6] & 1)) + { + if (ega_jega_enabled(ega)) + { + ega_render_text_jega(ega, drawcursor); + } + else + { + ega_render_text_standard(ega, drawcursor); + } + } + else + { + switch (ega->gdcreg[5] & 0x20) + { + case 0x00: + if (ega->seqregs[1] & 8) + { + ega_render_4bpp_lowres(ega); + } + else + { + ega_render_4bpp_highres(ega); + } + break; + case 0x20: + if (ega->seqregs[1] & 8) + { + ega_render_2bpp_lowres(ega); + } + else + { + ega_render_2bpp_highres(ega); + } + break; + } + } + if (ega->lastline < ega->displine) + ega->lastline = ega->displine; + } + + ega->displine++; + if ((ega->stat & 8) && ((ega->displine & 15) == (ega->crtc[0x11] & 15)) && ega->vslines) + ega->stat &= ~8; + ega->vslines++; + if (ega->displine > 500) + ega->displine = 0; + } + else + { + ega->vidtime += ega->dispontime; + if (ega->dispon) + ega->stat &= ~1; + ega->linepos = 0; + if (ega->sc == (ega->crtc[11] & 31)) + ega->con = 0; + if (ega->dispon) + { + if (ega->sc == (ega->crtc[9] & 31)) + { + ega->sc = 0; + + ega->maback += (ega->rowoffset << 3); + ega->maback &= ega->vrammask; + ega->ma = ega->maback; + } + else + { + ega->sc++; + ega->sc &= 31; + ega->ma = ega->maback; + } + } + ega->vc++; + ega->vc &= 1023; + if (ega->vc == ega->split) + { + ega->ma = ega->maback = 0; + if (ega->attrregs[0x10] & 0x20) + ega->scrollcache = 0; + } + if (ega->vc == ega->dispend) + { + ega->dispon=0; + if (ega->crtc[10] & 0x20) ega->cursoron = 0; + else ega->cursoron = ega->blink & 16; + if (!(ega->gdcreg[6] & 1) && !(ega->blink & 15)) + fullchange = 2; + ega->blink++; + + if (fullchange) + fullchange--; + } + if (ega->vc == ega->vsyncstart) + { + ega->dispon = 0; + ega->stat |= 8; + if (ega->seqregs[1] & 8) x = ega->hdisp * ((ega->seqregs[1] & 1) ? 8 : 9) * 2; + else x = ega->hdisp * ((ega->seqregs[1] & 1) ? 8 : 9); + if ((x != xsize || (ega->lastline - ega->firstline) != ysize) || update_overscan) + { + xsize = x; + ysize = ega->lastline - ega->firstline; + if (xsize < 64) xsize = 640; + if (ysize < 32) ysize = 200; + y_add = enable_overscan ? 14 : 0; + x_add = enable_overscan ? 8 : 0; + y_add_ex = enable_overscan ? 28 : 0; + x_add_ex = enable_overscan ? 16 : 0; + + if ((xsize > 2032) || ((ysize + y_add_ex) > 2048)) + { + x_add = x_add_ex = 0; + y_add = y_add_ex = 0; + suppress_overscan = 1; + } + else + { + suppress_overscan = 0; + } + + if (ega->vres) + updatewindowsize(xsize + x_add_ex, (ysize << 1) + y_add_ex); + else + updatewindowsize(xsize + x_add_ex, ysize + y_add_ex); + } + + if (enable_overscan) + { + if ((x >= 160) && ((ega->lastline - ega->firstline) >= 120)) + { + /* Draw (overscan_size - scroll size) lines of overscan on top. */ + for (i = 0; i < (y_add - (ega->crtc[8] & 0x1f)); i++) + { + q = &((uint32_t *)buffer32->line[i & 0x7ff])[32]; + + for (j = 0; j < (xsize + x_add_ex); j++) + { + q[j] = ega->pallook[ega->attrregs[0x11]]; + } + } + + /* Draw (overscan_size + scroll size) lines of overscan on the bottom. */ + for (i = 0; i < (y_add + (ega->crtc[8] & 0x1f)); i++) + { + q = &((uint32_t *)buffer32->line[(ysize + y_add + i - (ega->crtc[8] & 0x1f)) & 0x7ff])[32]; + + for (j = 0; j < (xsize + x_add_ex); j++) + { + q[j] = ega->pallook[ega->attrregs[0x11]]; + } + } + + for (i = (y_add - (ega->crtc[8] & 0x1f)); i < (ysize + y_add - (ega->crtc[8] & 0x1f)); i ++) + { + q = &((uint32_t *)buffer32->line[(i - (ega->crtc[8] & 0x1f)) & 0x7ff])[32]; + + for (j = 0; j < x_add; j++) + { + q[j] = ega->pallook[ega->attrregs[0x11]]; + q[xsize + x_add + j] = ega->pallook[ega->attrregs[0x11]]; + } + } + } + } + else + { + if (ega->crtc[8] & 0x1f) + { + /* Draw (scroll size) lines of overscan on the bottom. */ + for (i = 0; i < (ega->crtc[8] & 0x1f); i++) + { + q = &((uint32_t *)buffer32->line[(ysize + i - (ega->crtc[8] & 0x1f)) & 0x7ff])[32]; + + for (j = 0; j < xsize; j++) + { + q[j] = ega->pallook[ega->attrregs[0x11]]; + } + } + } + } + + video_blit_memtoscreen(32, 0, ega->firstline, ega->lastline + y_add_ex, xsize + x_add_ex, ega->lastline - ega->firstline + y_add_ex); + + frames++; + + ega->video_res_x = wx; + ega->video_res_y = wy + 1; + if (!(ega->gdcreg[6] & 1)) /*Text mode*/ + { + ega->video_res_x /= (ega->seqregs[1] & 1) ? 8 : 9; + ega->video_res_y /= (ega->crtc[9] & 31) + 1; + ega->video_bpp = 0; + } + else + { + if (ega->crtc[9] & 0x80) + ega->video_res_y /= 2; + if (!(ega->crtc[0x17] & 1)) + ega->video_res_y *= 2; + ega->video_res_y /= (ega->crtc[9] & 31) + 1; + if (ega->seqregs[1] & 8) + ega->video_res_x /= 2; + ega->video_bpp = (ega->gdcreg[5] & 0x20) ? 2 : 4; + } + + ega->firstline = 2000; + ega->lastline = 0; + + ega->maback = ega->ma = (ega->crtc[0xc] << 8)| ega->crtc[0xd]; + ega->ca = (ega->crtc[0xe] << 8) | ega->crtc[0xf]; + ega->ma <<= 2; + ega->maback <<= 2; + ega->ca <<= 2; + changeframecount = 2; + ega->vslines = 0; + } + if (ega->vc == ega->vtotal) + { + ega->vc = 0; + ega->sc = 0; + ega->dispon = 1; + ega->displine = 0; + ega->scrollcache = ega->attrregs[0x13] & 7; + } + if (ega->sc == (ega->crtc[10] & 31)) + ega->con = 1; + } +} + + +void ega_write(uint32_t addr, uint8_t val, void *p) +{ + ega_t *ega = (ega_t *)p; + uint8_t vala, valb, valc, vald; + int writemask2 = ega->writemask; + + egawrites++; + cycles -= video_timing_b; + cycles_lost += video_timing_b; + + if (addr >= 0xB0000) addr &= 0x7fff; + else addr &= 0xffff; + + if (ega->chain2_write) + { + writemask2 &= ~0xa; + if (addr & 1) + writemask2 <<= 1; + addr &= ~1; + } + + addr <<= 2; + + if (!(ega->gdcreg[6] & 1)) + fullchange = 2; + + switch (ega->writemode) + { + case 1: + if (writemask2 & 1) ega->vram[addr] = ega->la; + if (writemask2 & 2) ega->vram[addr | 0x1] = ega->lb; + if (writemask2 & 4) ega->vram[addr | 0x2] = ega->lc; + if (writemask2 & 8) ega->vram[addr | 0x3] = ega->ld; + break; + case 0: + if (ega->gdcreg[3] & 7) + val = ega_rotate[ega->gdcreg[3] & 7][val]; + + if (ega->gdcreg[8] == 0xff && !(ega->gdcreg[3] & 0x18) && !ega->gdcreg[1]) + { + if (writemask2 & 1) ega->vram[addr] = val; + if (writemask2 & 2) ega->vram[addr | 0x1] = val; + if (writemask2 & 4) ega->vram[addr | 0x2] = val; + if (writemask2 & 8) ega->vram[addr | 0x3] = val; + } + else + { + if (ega->gdcreg[1] & 1) vala = (ega->gdcreg[0] & 1) ? 0xff : 0; + else vala = val; + if (ega->gdcreg[1] & 2) valb = (ega->gdcreg[0] & 2) ? 0xff : 0; + else valb = val; + if (ega->gdcreg[1] & 4) valc = (ega->gdcreg[0] & 4) ? 0xff : 0; + else valc = val; + if (ega->gdcreg[1] & 8) vald = (ega->gdcreg[0] & 8) ? 0xff : 0; + else vald = val; + switch (ega->gdcreg[3] & 0x18) + { + case 0: /*Set*/ + if (writemask2 & 1) ega->vram[addr] = (vala & ega->gdcreg[8]) | (ega->la & ~ega->gdcreg[8]); + if (writemask2 & 2) ega->vram[addr | 0x1] = (valb & ega->gdcreg[8]) | (ega->lb & ~ega->gdcreg[8]); + if (writemask2 & 4) ega->vram[addr | 0x2] = (valc & ega->gdcreg[8]) | (ega->lc & ~ega->gdcreg[8]); + if (writemask2 & 8) ega->vram[addr | 0x3] = (vald & ega->gdcreg[8]) | (ega->ld & ~ega->gdcreg[8]); + break; + case 8: /*AND*/ + if (writemask2 & 1) ega->vram[addr] = (vala | ~ega->gdcreg[8]) & ega->la; + if (writemask2 & 2) ega->vram[addr | 0x1] = (valb | ~ega->gdcreg[8]) & ega->lb; + if (writemask2 & 4) ega->vram[addr | 0x2] = (valc | ~ega->gdcreg[8]) & ega->lc; + if (writemask2 & 8) ega->vram[addr | 0x3] = (vald | ~ega->gdcreg[8]) & ega->ld; + break; + case 0x10: /*OR*/ + if (writemask2 & 1) ega->vram[addr] = (vala & ega->gdcreg[8]) | ega->la; + if (writemask2 & 2) ega->vram[addr | 0x1] = (valb & ega->gdcreg[8]) | ega->lb; + if (writemask2 & 4) ega->vram[addr | 0x2] = (valc & ega->gdcreg[8]) | ega->lc; + if (writemask2 & 8) ega->vram[addr | 0x3] = (vald & ega->gdcreg[8]) | ega->ld; + break; + case 0x18: /*XOR*/ + if (writemask2 & 1) ega->vram[addr] = (vala & ega->gdcreg[8]) ^ ega->la; + if (writemask2 & 2) ega->vram[addr | 0x1] = (valb & ega->gdcreg[8]) ^ ega->lb; + if (writemask2 & 4) ega->vram[addr | 0x2] = (valc & ega->gdcreg[8]) ^ ega->lc; + if (writemask2 & 8) ega->vram[addr | 0x3] = (vald & ega->gdcreg[8]) ^ ega->ld; + break; + } + } + break; + case 2: + if (!(ega->gdcreg[3] & 0x18) && !ega->gdcreg[1]) + { + if (writemask2 & 1) ega->vram[addr] = (((val & 1) ? 0xff : 0) & ega->gdcreg[8]) | (ega->la & ~ega->gdcreg[8]); + if (writemask2 & 2) ega->vram[addr | 0x1] = (((val & 2) ? 0xff : 0) & ega->gdcreg[8]) | (ega->lb & ~ega->gdcreg[8]); + if (writemask2 & 4) ega->vram[addr | 0x2] = (((val & 4) ? 0xff : 0) & ega->gdcreg[8]) | (ega->lc & ~ega->gdcreg[8]); + if (writemask2 & 8) ega->vram[addr | 0x3] = (((val & 8) ? 0xff : 0) & ega->gdcreg[8]) | (ega->ld & ~ega->gdcreg[8]); + } + else + { + vala = ((val & 1) ? 0xff : 0); + valb = ((val & 2) ? 0xff : 0); + valc = ((val & 4) ? 0xff : 0); + vald = ((val & 8) ? 0xff : 0); + switch (ega->gdcreg[3] & 0x18) + { + case 0: /*Set*/ + if (writemask2 & 1) ega->vram[addr] = (vala & ega->gdcreg[8]) | (ega->la & ~ega->gdcreg[8]); + if (writemask2 & 2) ega->vram[addr | 0x1] = (valb & ega->gdcreg[8]) | (ega->lb & ~ega->gdcreg[8]); + if (writemask2 & 4) ega->vram[addr | 0x2] = (valc & ega->gdcreg[8]) | (ega->lc & ~ega->gdcreg[8]); + if (writemask2 & 8) ega->vram[addr | 0x3] = (vald & ega->gdcreg[8]) | (ega->ld & ~ega->gdcreg[8]); + break; + case 8: /*AND*/ + if (writemask2 & 1) ega->vram[addr] = (vala | ~ega->gdcreg[8]) & ega->la; + if (writemask2 & 2) ega->vram[addr | 0x1] = (valb | ~ega->gdcreg[8]) & ega->lb; + if (writemask2 & 4) ega->vram[addr | 0x2] = (valc | ~ega->gdcreg[8]) & ega->lc; + if (writemask2 & 8) ega->vram[addr | 0x3] = (vald | ~ega->gdcreg[8]) & ega->ld; + break; + case 0x10: /*OR*/ + if (writemask2 & 1) ega->vram[addr] = (vala & ega->gdcreg[8]) | ega->la; + if (writemask2 & 2) ega->vram[addr | 0x1] = (valb & ega->gdcreg[8]) | ega->lb; + if (writemask2 & 4) ega->vram[addr | 0x2] = (valc & ega->gdcreg[8]) | ega->lc; + if (writemask2 & 8) ega->vram[addr | 0x3] = (vald & ega->gdcreg[8]) | ega->ld; + break; + case 0x18: /*XOR*/ + if (writemask2 & 1) ega->vram[addr] = (vala & ega->gdcreg[8]) ^ ega->la; + if (writemask2 & 2) ega->vram[addr | 0x1] = (valb & ega->gdcreg[8]) ^ ega->lb; + if (writemask2 & 4) ega->vram[addr | 0x2] = (valc & ega->gdcreg[8]) ^ ega->lc; + if (writemask2 & 8) ega->vram[addr | 0x3] = (vald & ega->gdcreg[8]) ^ ega->ld; + break; + } + } + break; + } +} + +uint8_t ega_read(uint32_t addr, void *p) +{ + ega_t *ega = (ega_t *)p; + uint8_t temp, temp2, temp3, temp4; + int readplane = ega->readplane; + + egareads++; + cycles -= video_timing_b; + cycles_lost += video_timing_b; + if (addr >= 0xb0000) addr &= 0x7fff; + else addr &= 0xffff; + + if (ega->chain2_read) + { + readplane = (readplane & 2) | (addr & 1); + addr &= ~1; + } + + addr <<= 2; + + ega->la = ega->vram[addr]; + ega->lb = ega->vram[addr | 0x1]; + ega->lc = ega->vram[addr | 0x2]; + ega->ld = ega->vram[addr | 0x3]; + if (ega->readmode) + { + temp = (ega->colournocare & 1) ? 0xff : 0; + temp &= ega->la; + temp ^= (ega->colourcompare & 1) ? 0xff : 0; + temp2 = (ega->colournocare & 2) ? 0xff : 0; + temp2 &= ega->lb; + temp2 ^= (ega->colourcompare & 2) ? 0xff : 0; + temp3 = (ega->colournocare & 4) ? 0xff : 0; + temp3 &= ega->lc; + temp3 ^= (ega->colourcompare & 4) ? 0xff : 0; + temp4 = (ega->colournocare & 8) ? 0xff : 0; + temp4 &= ega->ld; + temp4 ^= (ega->colourcompare & 8) ? 0xff : 0; + return ~(temp | temp2 | temp3 | temp4); + } + return ega->vram[addr | readplane]; +} + +void ega_init(ega_t *ega) +{ + int c, d, e; + + ega->vram = malloc(0x40000); + ega->vrammask = 0x3ffff; + + for (c = 0; c < 256; c++) + { + e = c; + for (d = 0; d < 8; d++) + { + ega_rotate[d][c] = e; + e = (e >> 1) | ((e & 1) ? 0x80 : 0); + } + } + + for (c = 0; c < 4; c++) + { + for (d = 0; d < 4; d++) + { + edatlookup[c][d] = 0; + if (c & 1) edatlookup[c][d] |= 1; + if (d & 1) edatlookup[c][d] |= 2; + if (c & 2) edatlookup[c][d] |= 0x10; + if (d & 2) edatlookup[c][d] |= 0x20; + } + } + + for (c = 0; c < 256; c++) + { + pallook64[c] = makecol32(((c >> 2) & 1) * 0xaa, ((c >> 1) & 1) * 0xaa, (c & 1) * 0xaa); + pallook64[c] += makecol32(((c >> 5) & 1) * 0x55, ((c >> 4) & 1) * 0x55, ((c >> 3) & 1) * 0x55); + pallook16[c] = makecol32(((c >> 2) & 1) * 0xaa, ((c >> 1) & 1) * 0xaa, (c & 1) * 0xaa); + pallook16[c] += makecol32(((c >> 4) & 1) * 0x55, ((c >> 4) & 1) * 0x55, ((c >> 4) & 1) * 0x55); + if ((c & 0x17) == 6) + pallook16[c] = makecol32(0xaa, 0x55, 0); + } + ega->pallook = pallook16; + old_overscan_color = 0; +} + +void ega_common_defaults(ega_t *ega) +{ + ega->miscout |= 0x22; + ega->enablevram = 1; + ega->oddeven_page = 0; + + ega->seqregs[4] |= 2; + ega->extvram = 1; + + update_overscan = 0; + + ega->is_jega = 0; +} + +void *ega_standalone_init() +{ + ega_t *ega = malloc(sizeof(ega_t)); + memset(ega, 0, sizeof(ega_t)); + + overscan_x = 16; + overscan_y = 28; + + rom_init(&ega->bios_rom, L"roms/ibm_6277356_ega_card_u44_27128.bin", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + + if (ega->bios_rom.rom[0x3ffe] == 0xaa && ega->bios_rom.rom[0x3fff] == 0x55) + { + int c; + + for (c = 0; c < 0x2000; c++) + { + uint8_t temp = ega->bios_rom.rom[c]; + ega->bios_rom.rom[c] = ega->bios_rom.rom[0x3fff - c]; + ega->bios_rom.rom[0x3fff - c] = temp; + } + } + + ega->crtc[0] = 63; + ega->dispontime = 1000 * (1 << TIMER_SHIFT); + ega->dispofftime = 1000 * (1 << TIMER_SHIFT); + ega->dispontime <<= 1; + ega->dispofftime <<= 1; + + ega_init(ega); + + ega_common_defaults(ega); + + mem_mapping_add(&ega->mapping, 0xa0000, 0x20000, ega_read, NULL, NULL, ega_write, NULL, NULL, NULL, MEM_MAPPING_EXTERNAL, ega); + timer_add(ega_poll, &ega->vidtime, TIMER_ALWAYS_ENABLED, ega); + io_sethandler(0x03c0, 0x0020, ega_in, NULL, NULL, ega_out, NULL, NULL, ega); + return ega; +} + +void *cpqega_standalone_init() +{ + ega_t *ega = malloc(sizeof(ega_t)); + memset(ega, 0, sizeof(ega_t)); + + overscan_x = 16; + overscan_y = 28; + + rom_init(&ega->bios_rom, L"roms/108281-001.bin", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + + if (ega->bios_rom.rom[0x3ffe] == 0xaa && ega->bios_rom.rom[0x3fff] == 0x55) + { + int c; + + for (c = 0; c < 0x2000; c++) + { + uint8_t temp = ega->bios_rom.rom[c]; + ega->bios_rom.rom[c] = ega->bios_rom.rom[0x3fff - c]; + ega->bios_rom.rom[0x3fff - c] = temp; + } + } + + ega->crtc[0] = 63; + ega->dispontime = 1000 * (1 << TIMER_SHIFT); + ega->dispofftime = 1000 * (1 << TIMER_SHIFT); + + ega_init(ega); + + ega_common_defaults(ega); + + mem_mapping_add(&ega->mapping, 0xa0000, 0x20000, ega_read, NULL, NULL, ega_write, NULL, NULL, NULL, MEM_MAPPING_EXTERNAL, ega); + timer_add(ega_poll, &ega->vidtime, TIMER_ALWAYS_ENABLED, ega); + io_sethandler(0x03c0, 0x0020, ega_in, NULL, NULL, ega_out, NULL, NULL, ega); + return ega; +} + +void *sega_standalone_init() +{ + ega_t *ega = malloc(sizeof(ega_t)); + memset(ega, 0, sizeof(ega_t)); + + overscan_x = 16; + overscan_y = 28; + + rom_init(&ega->bios_rom, L"roms/lega.vbi", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + + if (ega->bios_rom.rom[0x3ffe] == 0xaa && ega->bios_rom.rom[0x3fff] == 0x55) + { + int c; + + for (c = 0; c < 0x2000; c++) + { + uint8_t temp = ega->bios_rom.rom[c]; + ega->bios_rom.rom[c] = ega->bios_rom.rom[0x3fff - c]; + ega->bios_rom.rom[0x3fff - c] = temp; + } + } + + ega->crtc[0] = 63; + ega->dispontime = 1000 * (1 << TIMER_SHIFT); + ega->dispofftime = 1000 * (1 << TIMER_SHIFT); + + ega_init(ega); + + ega_common_defaults(ega); + + mem_mapping_add(&ega->mapping, 0xa0000, 0x20000, ega_read, NULL, NULL, ega_write, NULL, NULL, NULL, MEM_MAPPING_EXTERNAL, ega); + timer_add(ega_poll, &ega->vidtime, TIMER_ALWAYS_ENABLED, ega); + io_sethandler(0x03c0, 0x0020, ega_in, NULL, NULL, ega_out, NULL, NULL, ega); + return ega; +} + +uint16_t chrtosht(FILE *fp) +{ + uint16_t i, j; + i = (uint8_t) getc(fp); + j = (uint8_t) getc(fp) << 8; + return (i | j); +} + +unsigned int getfontx2header(FILE *fp, fontx_h *header) +{ + fread(header->id, ID_LEN, 1, fp); + if (strncmp(header->id, "FONTX2", ID_LEN) != 0) + { + return 1; + } + fread(header->name, NAME_LEN, 1, fp); + header->width = (uint8_t)getc(fp); + header->height = (uint8_t)getc(fp); + header->type = (uint8_t)getc(fp); + return 0; +} + +void readfontxtbl(fontxTbl *table, unsigned int size, FILE *fp) +{ + while (size > 0) + { + table->start = chrtosht(fp); + table->end = chrtosht(fp); + ++table; + --size; + } +} + +static void LoadFontxFile(wchar_t *fname) +{ + fontx_h head; + fontxTbl *table; + unsigned int code; + uint8_t size; + unsigned int i; + + if (!fname) return; + if(*fname=='\0') return; + FILE * mfile=romfopen(fname,L"rb"); + if (!mfile) + { + pclog("MSG: Can't open FONTX2 file: %s\n",fname); + return; + } + if (getfontx2header(mfile, &head) != 0) + { + fclose(mfile); + pclog("MSG: FONTX2 header is incorrect\n"); + return; + } + /* switch whether the font is DBCS or not */ + if (head.type == DBCS) + { + if (head.width == 16 && head.height == 16) + { + size = getc(mfile); + table = (fontxTbl *)calloc(size, sizeof(fontxTbl)); + readfontxtbl(table, size, mfile); + for (i = 0; i < size; i++) + { + for (code = table[i].start; code <= table[i].end; code++) + { + fread(&jfont_dbcs_16[(code * 32)], sizeof(uint8_t), 32, mfile); + } + } + } + else + { + fclose(mfile); + pclog("MSG: FONTX2 DBCS font size is not correct\n"); + return; + } + } + else + { + if (head.width == 8 && head.height == 19) + { + fread(jfont_sbcs_19, sizeof(uint8_t), SBCS19_LEN, mfile); + } + else + { + fclose(mfile); + pclog("MSG: FONTX2 SBCS font size is not correct\n"); + return; + } + } + fclose(mfile); +} + +void *jega_standalone_init() +{ + ega_t *ega = (ega_t *) sega_standalone_init(); + + LoadFontxFile(L"roms/JPNHN19X.FNT"); + LoadFontxFile(L"roms/JPNZN16X.FNT"); + + ega->is_jega = 1; + + return ega; +} + +static int ega_standalone_available() +{ + return rom_present(L"roms/ibm_6277356_ega_card_u44_27128.bin"); +} + +static int cpqega_standalone_available() +{ + return rom_present(L"roms/108281-001.bin"); +} + +static int sega_standalone_available() +{ + return rom_present(L"roms/lega.vbi"); +} + +void ega_close(void *p) +{ + ega_t *ega = (ega_t *)p; + + free(ega->vram); + free(ega); +} + +void ega_speed_changed(void *p) +{ + ega_t *ega = (ega_t *)p; + + ega_recalctimings(ega); +} + +device_t ega_device = +{ + "EGA", + 0, + ega_standalone_init, + ega_close, + ega_standalone_available, + ega_speed_changed, + NULL, + NULL +}; + +device_t cpqega_device = +{ + "Compaq EGA", + 0, + cpqega_standalone_init, + ega_close, + cpqega_standalone_available, + ega_speed_changed, + NULL, + NULL +}; + +device_t sega_device = +{ + "SuperEGA", + 0, + sega_standalone_init, + ega_close, + sega_standalone_available, + ega_speed_changed, + NULL, + NULL +}; + +device_t jega_device = +{ + "AX JEGA", + 0, + jega_standalone_init, + ega_close, + sega_standalone_available, + ega_speed_changed, + NULL, + NULL +}; diff --git a/src/vid_ega.h b/src/VIDEO/vid_ega.h similarity index 62% rename from src/vid_ega.h rename to src/VIDEO/vid_ega.h index 0d3c12439..90ddf17a4 100644 --- a/src/vid_ega.h +++ b/src/VIDEO/vid_ega.h @@ -1,6 +1,26 @@ -/* Copyright holders: Sarah Walker, Tenshi - see COPYING for more details -*/ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Emulation of the EGA, Chips & Technologies SuperEGA, and + * AX JEGA graphics cards. + * + * Version: @(#)vid_ega.h 1.0.1 2017/06/05 + * + * Author: Sarah Walker, + * Miran Grca, + * akm, + * Copyright 2008-2017 Sarah Walker. + * Copyright 2016-2017 Miran Grca. + * Copyright 2017-2017 akm. + */ + +#include + typedef struct ega_t { mem_mapping_t mapping; @@ -68,8 +88,16 @@ typedef struct ega_t int vrammask; int video_res_x, video_res_y, video_bpp; + + uint8_t RMOD1, RMOD2, RDAGS, RDFFB, RDFSB, RDFAP, RPESL, RPULP, RPSSC, RPSSU, RPSSL; + uint8_t RPPAJ; + uint8_t RCMOD, RCCLH, RCCLL, RCCSL, RCCEL, RCSKW, ROMSL, RSTAT; + int is_jega, font_index; + int chr_left, chr_wide; } ega_t; +extern int update_overscan; + void *ega_standalone_init(); void ega_out(uint16_t addr, uint8_t val, void *p); uint8_t ega_in(uint16_t addr, void *p); @@ -77,7 +105,18 @@ void ega_poll(void *p); void ega_recalctimings(struct ega_t *ega); void ega_write(uint32_t addr, uint8_t val, void *p); uint8_t ega_read(uint32_t addr, void *p); +void ega_init(ega_t *ega); extern device_t ega_device; extern device_t cpqega_device; extern device_t sega_device; + +#define SBCS 0 +#define DBCS 1 +#define ID_LEN 6 +#define NAME_LEN 8 +#define SBCS19_LEN 256 * 19 +#define DBCS16_LEN 65536 * 32 + +extern uint8_t jfont_sbcs_19[SBCS19_LEN]; /* 256 * 19( * 8) */ +extern uint8_t jfont_dbcs_16[DBCS16_LEN]; /* 65536 * 16 * 2 (* 8) */ diff --git a/src/VIDEO/vid_ega_render.c b/src/VIDEO/vid_ega_render.c new file mode 100644 index 000000000..eea08992b --- /dev/null +++ b/src/VIDEO/vid_ega_render.c @@ -0,0 +1,534 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * EGA renderers. + * + * Version: @(#)vid_ega_render.c 1.0.1 2017/06/05 + * + * Author: Sarah Walker, + * Miran Grca, + * Copyright 2008-2017 Sarah Walker. + * Copyright 2016-2017 Miran Grca. + */ + +#include +#include "../ibm.h" +#include "../device.h" +#include "../mem.h" +#include "../rom.h" +#include "video.h" +#include "vid_ega.h" +#include "vid_ega_render.h" + + +int ega_display_line(ega_t *ega) +{ + int y_add = (enable_overscan) ? (overscan_y >> 1) : 0; + unsigned int dl = ega->displine; + if (ega->crtc[9] & 0x1f) + { + dl -= (ega->crtc[8] & 0x1f); + } + dl += y_add; + dl &= 0x7ff; + return dl; +} + +void ega_render_blank(ega_t *ega) +{ + int x_add = (enable_overscan) ? 8 : 0; + int dl = ega_display_line(ega); + int x, xx; + + for (x = 0; x < ega->hdisp; x++) + { + switch (ega->seqregs[1] & 9) + { + case 0: + for (xx = 0; xx < 9; xx++) ((uint32_t *)buffer32->line[dl])[(x * 9) + xx + 32 + x_add] = 0; + break; + case 1: + for (xx = 0; xx < 8; xx++) ((uint32_t *)buffer32->line[dl])[(x * 8) + xx + 32 + x_add] = 0; + break; + case 8: + for (xx = 0; xx < 18; xx++) ((uint32_t *)buffer32->line[dl])[(x * 18) + xx + 32 + x_add] = 0; + break; + case 9: + for (xx = 0; xx < 16; xx++) ((uint32_t *)buffer32->line[dl])[(x * 16) + xx + 32 + x_add] = 0; + break; + } + } +} + +void ega_render_text_standard(ega_t *ega, int drawcursor) +{ + int x_add = (enable_overscan) ? 8 : 0; + int dl = ega_display_line(ega); + uint8_t chr, dat, attr; + uint32_t charaddr; + int x, xx; + uint32_t fg, bg; + + if (fullchange) + { + for (x = 0; x < ega->hdisp; x++) + { + drawcursor = ((ega->ma == ega->ca) && ega->con && ega->cursoron); + chr = ega->vram[(ega->ma << 1) & ega->vrammask]; + attr = ega->vram[((ega->ma << 1) + 1) & ega->vrammask]; + + if (attr & 8) charaddr = ega->charsetb + (chr * 128); + else charaddr = ega->charseta + (chr * 128); + + if (drawcursor) + { + bg = ega->pallook[ega->egapal[attr & 15]]; + fg = ega->pallook[ega->egapal[attr >> 4]]; + } + else + { + fg = ega->pallook[ega->egapal[attr & 15]]; + bg = ega->pallook[ega->egapal[attr >> 4]]; + if (attr & 0x80 && ega->attrregs[0x10] & 8) + { + bg = ega->pallook[ega->egapal[(attr >> 4) & 7]]; + if (ega->blink & 16) + fg = bg; + } + } + + dat = ega->vram[charaddr + (ega->sc << 2)]; + if (ega->seqregs[1] & 8) + { + if (ega->seqregs[1] & 1) + { + for (xx = 0; xx < 8; xx++) + ((uint32_t *)buffer32->line[dl])[(((x << 4) + 32 + (xx << 1)) & 2047) + x_add] = + ((uint32_t *)buffer32->line[dl])[(((x << 4) + 33 + (xx << 1)) & 2047) + x_add] = (dat & (0x80 >> xx)) ? fg : bg; + } + else + { + for (xx = 0; xx < 8; xx++) + ((uint32_t *)buffer32->line[dl])[(((x * 18) + 32 + (xx << 1)) & 2047) + x_add] = + ((uint32_t *)buffer32->line[dl])[(((x * 18) + 33 + (xx << 1)) & 2047) + x_add] = (dat & (0x80 >> xx)) ? fg : bg; + if ((chr & ~0x1f) != 0xc0 || !(ega->attrregs[0x10] & 4)) + ((uint32_t *)buffer32->line[dl])[(((x * 18) + 32 + 16) & 2047) + x_add] = + ((uint32_t *)buffer32->line[dl])[(((x * 18) + 32 + 17) & 2047) + x_add] = bg; + else + ((uint32_t *)buffer32->line[dl])[(((x * 18) + 32 + 16) & 2047) + x_add] = + ((uint32_t *)buffer32->line[dl])[(((x * 18) + 32 + 17) & 2047) + x_add] = (dat & 1) ? fg : bg; + } + } + else + { + if (ega->seqregs[1] & 1) + { + for (xx = 0; xx < 8; xx++) + ((uint32_t *)buffer32->line[dl])[(((x << 3) + 32 + xx) & 2047) + x_add] = (dat & (0x80 >> xx)) ? fg : bg; + } + else + { + for (xx = 0; xx < 8; xx++) + ((uint32_t *)buffer32->line[dl])[(((x * 9) + 32 + xx) & 2047) + x_add] = (dat & (0x80 >> xx)) ? fg : bg; + if ((chr & ~0x1f) != 0xc0 || !(ega->attrregs[0x10] & 4)) + ((uint32_t *)buffer32->line[dl])[(((x * 9) + 32 + 8) & 2047) + x_add] = bg; + else + ((uint32_t *)buffer32->line[dl])[(((x * 9) + 32 + 8) & 2047) + x_add] = (dat & 1) ? fg : bg; + } + } + ega->ma += 4; + ega->ma &= ega->vrammask; + } + } +} + +static __inline int is_kanji1(uint8_t chr) +{ + return (chr >= 0x81 && chr <= 0x9f) || (chr >= 0xe0 && chr <= 0xfc); +} + +static __inline int is_kanji2(uint8_t chr) +{ + return (chr >= 0x40 && chr <= 0x7e) || (chr >= 0x80 && chr <= 0xfc); +} + +void ega_jega_render_blit_text(ega_t *ega, int x, int dl, int start, int width, uint16_t dat, int cw, uint32_t fg, uint32_t bg) +{ + int x_add = (enable_overscan) ? 8 : 0; + + int xx = 0; + int xxx = 0; + + if (ega->seqregs[1] & 8) + { + for (xx = start; xx < (start + width); xx++) + for (xxx = 0; xxx < cw; xxx++) + ((uint32_t *)buffer32->line[dl])[(((x * width) + 32 + (xxx << 1) + ((xx << 1) * cw)) & 2047) + x_add] = + ((uint32_t *)buffer32->line[dl])[(((x * width) + 33 + (xxx << 1) + ((xx << 1) * cw)) & 2047) + x_add] = (dat & (0x80 >> xx)) ? fg : bg; + } + else + { + for (xx = start; xx < (start + width); xx++) + ((uint32_t *)buffer32->line[dl])[(((x * width) + 32 + xxx + (xx * cw)) & 2047) + x_add] = (dat & (0x80 >> xx)) ? fg : bg; + } +} + +void ega_render_text_jega(ega_t *ega, int drawcursor) +{ + int dl = ega_display_line(ega); + uint8_t chr, attr; + uint16_t dat = 0, dat2; + int x; + uint32_t fg = 0, bg = 0; + + /* Temporary for DBCS. */ + unsigned int chr_left = 0; + unsigned int bsattr = 0; + int chr_wide = 0; + uint32_t bg_ex = 0; + uint32_t fg_ex = 0; + + int blocks = ega->hdisp; + int fline; + + unsigned int pad_y, exattr; + + if (fullchange) + { + for (x = 0; x < ega->hdisp; x++) + { + drawcursor = ((ega->ma == ega->ca) && ega->con && ega->cursoron); + chr = ega->vram[(ega->ma << 1) & ega->vrammask]; + attr = ega->vram[((ega->ma << 1) + 1) & ega->vrammask]; + + if (chr_wide == 0) + { + if (ega->RMOD2 & 0x80) + { + fg_ex = ega->pallook[ega->egapal[attr & 15]]; + + if (attr & 0x80 && ega->attrregs[0x10] & 8) + { + bg_ex = ega->pallook[ega->egapal[(attr >> 4) & 7]]; + } + else + { + bg_ex = ega->pallook[ega->egapal[attr >> 4]]; + } + } + else + { + if (attr & 0x40) + { + /* Reversed in JEGA mode */ + bg_ex = ega->pallook[ega->egapal[attr & 15]]; + fg_ex = ega->pallook[0]; + } + else + { + /* Reversed in JEGA mode */ + fg_ex = ega->pallook[ega->egapal[attr & 15]]; + bg_ex = ega->pallook[0]; + } + } + + if (drawcursor) + { + bg = fg_ex; + fg = bg_ex; + } + else + { + fg = fg_ex; + bg = bg_ex; + } + + if (attr & 0x80 && ega->attrregs[0x10] & 8) + { + if (ega->blink & 16) + fg = bg; + } + + /* Stay drawing if the char code is DBCS and not at last column. */ + if (is_kanji1(dat) && (blocks > 1)) + { + /* Set the present char/attr code to the next loop. */ + chr_left = chr; + chr_wide = 1; + } + else + { + /* The char code is ANK (8 dots width). */ + dat = jfont_sbcs_19[chr*19+(ega->sc)]; /* w8xh19 font */ + ega_jega_render_blit_text(ega, x, dl, 0, 8, dat, 1, fg, bg); + if (bsattr & 0x20) + { + /* Vertical line. */ + dat = 0x18; + ega_jega_render_blit_text(ega, x, fline, 0, 8, dat, 1, fg, bg); + } + if (ega->sc == 18 && bsattr & 0x10) + { + /* Underline. */ + dat = 0xff; + ega_jega_render_blit_text(ega, x, fline, 0, 8, dat, 1, fg, bg); + } + chr_wide = 0; + blocks--; + } + } + else + { + /* The char code may be in DBCS. */ + pad_y = ega->RPSSC; + exattr = 0; + + /* Note: The second column should be applied its basic attribute. */ + if (ega->RMOD2 & 0x40) + { + /* If JEGA Extended Attribute is enabled. */ + exattr = attr; + if ((exattr & 0x30) == 0x30) pad_y = ega->RPSSL; /* Set top padding of lower 2x character. */ + else if (exattr & 0x30) pad_y = ega->RPSSU; /* Set top padding of upper 2x character. */ + } + + if (ega->sc >= pad_y && ega->sc < 16 + pad_y) + { + /* Check the char code is in Wide charset of Shift-JIS. */ + if (is_kanji2(chr)) + { + fline = ega->sc - pad_y; + chr_left <<= 8; + /* Fix vertical position. */ + chr |= chr_left; + /* Horizontal wide font (Extended Attribute). */ + if (exattr & 0x20) + { + if (exattr & 0x10) fline = (fline >> 1) + 8; + else fline = fline >> 1; + } + /* Vertical wide font (Extended Attribute). */ + if (exattr & 0x40) + { + dat = jfont_dbcs_16[chr * 32 + fline * 2]; + if (!(exattr & 0x08)) + dat = jfont_dbcs_16[chr * 32 + fline * 2 + 1]; + /* Draw 8 dots. */ + ega_jega_render_blit_text(ega, x, dl, 0, 8, dat, 2, fg, bg); + } + else + { + /* Get the font pattern. */ + dat = jfont_dbcs_16[chr * 32 + fline * 2]; + dat <<= 8; + dat |= jfont_dbcs_16[chr * 32 + fline * 2 + 1]; + /* Bold (Extended Attribute). */ + if (exattr &= 0x80) + { + dat2 = dat; + dat2 >>= 1; + dat |= dat2; + /* Original JEGA colours the last row with the next column's attribute. */ + } + /* Draw 16 dots */ + ega_jega_render_blit_text(ega, x, dl, 0, 16, dat, 1, fg, bg); + } + } + else + { + /* Ignore wide char mode, put blank. */ + dat = 0; + ega_jega_render_blit_text(ega, x, dl, 0, 16, dat, 1, fg, bg); + } + } + else if (ega->sc == (17 + pad_y) && (bsattr & 0x10)) + { + /* Underline. */ + dat = 0xffff; + ega_jega_render_blit_text(ega, x, dl, 0, 16, dat, 1, fg, bg); + } + else + { + /* Draw blank */ + dat = 0; + ega_jega_render_blit_text(ega, x, dl, 0, 16, dat, 1, fg, bg); + } + + if (bsattr & 0x20) + { + /* Vertical line draw at last. */ + dat = 0x0180; + ega_jega_render_blit_text(ega, x, dl, 0, 16, dat, 1, fg, bg); + } + + chr_wide = 0; + blocks -= 2; /* Move by 2 columns. */ + } + + ega->ma += 4; + ega->ma &= ega->vrammask; + } + } +} + +void ega_render_2bpp_lowres(ega_t *ega) +{ + int x_add = (enable_overscan) ? 8 : 0; + int dl = ega_display_line(ega); + int x; + int offset; + uint8_t edat[4]; + + offset = ((8 - ega->scrollcache) << 1) + 16; + for (x = 0; x <= ega->hdisp; x++) + { + if (ega->sc & 1 && !(ega->crtc[0x17] & 1)) + { + edat[0] = ega->vram[(ega->ma << 1) + 0x8000]; + edat[1] = ega->vram[(ega->ma << 1) + 0x8001]; + } + else + { + edat[0] = ega->vram[(ega->ma << 1)]; + edat[1] = ega->vram[(ega->ma << 1) + 1]; + } + ega->ma += 4; + ega->ma &= ega->vrammask; + + ((uint32_t *)buffer32->line[dl])[(x << 4) + 14 + offset + x_add]= ((uint32_t *)buffer32->line[dl])[(x << 4) + 15 + offset + x_add] = ega->pallook[ega->egapal[edat[1] & 3]]; + ((uint32_t *)buffer32->line[dl])[(x << 4) + 12 + offset + x_add] = ((uint32_t *)buffer32->line[dl])[(x << 4) + 13 + offset + x_add] = ega->pallook[ega->egapal[(edat[1] >> 2) & 3]]; + ((uint32_t *)buffer32->line[dl])[(x << 4) + 10 + offset + x_add] = ((uint32_t *)buffer32->line[dl])[(x << 4) + 11 + offset + x_add] = ega->pallook[ega->egapal[(edat[1] >> 4) & 3]]; + ((uint32_t *)buffer32->line[dl])[(x << 4) + 8 + offset + x_add] = ((uint32_t *)buffer32->line[dl])[(x << 4) + 9 + offset + x_add] = ega->pallook[ega->egapal[(edat[1] >> 6) & 3]]; + ((uint32_t *)buffer32->line[dl])[(x << 4) + 6 + offset + x_add] = ((uint32_t *)buffer32->line[dl])[(x << 4) + 7 + offset + x_add] = ega->pallook[ega->egapal[(edat[0] >> 0) & 3]]; + ((uint32_t *)buffer32->line[dl])[(x << 4) + 4 + offset + x_add] = ((uint32_t *)buffer32->line[dl])[(x << 4) + 5 + offset + x_add] = ega->pallook[ega->egapal[(edat[0] >> 2) & 3]]; + ((uint32_t *)buffer32->line[dl])[(x << 4) + 2 + offset + x_add] = ((uint32_t *)buffer32->line[dl])[(x << 4) + 3 + offset + x_add] = ega->pallook[ega->egapal[(edat[0] >> 4) & 3]]; + ((uint32_t *)buffer32->line[dl])[(x << 4) + offset + x_add] = ((uint32_t *)buffer32->line[dl])[(x << 4) + 1 + offset + x_add] = ega->pallook[ega->egapal[(edat[0] >> 6) & 3]]; + } +} + +void ega_render_2bpp_highres(ega_t *ega) +{ + int x_add = (enable_overscan) ? 8 : 0; + int dl = ega_display_line(ega); + int x; + int offset; + uint8_t edat[4]; + + offset = ((8 - ega->scrollcache) << 1) + 16; + for (x = 0; x <= ega->hdisp; x++) + { + if (ega->sc & 1 && !(ega->crtc[0x17] & 1)) + { + edat[0] = ega->vram[(ega->ma << 1) + 0x8000]; + edat[1] = ega->vram[(ega->ma << 1) + 0x8001]; + } + else + { + edat[0] = ega->vram[(ega->ma << 1)]; + edat[1] = ega->vram[(ega->ma << 1) + 1]; + } + ega->ma += 4; + ega->ma &= ega->vrammask; + + ((uint32_t *)buffer32->line[dl])[(x << 4) + 7 + offset + x_add] = ega->pallook[ega->egapal[edat[1] & 3]]; + ((uint32_t *)buffer32->line[dl])[(x << 4) + 6 + offset + x_add] = ega->pallook[ega->egapal[(edat[1] >> 2) & 3]]; + ((uint32_t *)buffer32->line[dl])[(x << 4) + 5 + offset + x_add] = ega->pallook[ega->egapal[(edat[1] >> 4) & 3]]; + ((uint32_t *)buffer32->line[dl])[(x << 4) + 4 + offset + x_add] = ega->pallook[ega->egapal[(edat[1] >> 6) & 3]]; + ((uint32_t *)buffer32->line[dl])[(x << 4) + 3 + offset + x_add] = ega->pallook[ega->egapal[(edat[0] >> 0) & 3]]; + ((uint32_t *)buffer32->line[dl])[(x << 4) + 2 + offset + x_add] = ega->pallook[ega->egapal[(edat[0] >> 2) & 3]]; + ((uint32_t *)buffer32->line[dl])[(x << 4) + 1 + offset + x_add] = ega->pallook[ega->egapal[(edat[0] >> 4) & 3]]; + ((uint32_t *)buffer32->line[dl])[(x << 4) + offset + x_add] = ega->pallook[ega->egapal[(edat[0] >> 6) & 3]]; + } +} + +void ega_render_4bpp_lowres(ega_t *ega) +{ + int x_add = (enable_overscan) ? 8 : 0; + int dl = ega_display_line(ega); + uint8_t dat; + int x; + int offset; + uint8_t edat[4]; + + offset = ((8 - ega->scrollcache) << 1) + 16; + for (x = 0; x <= ega->hdisp; x++) + { + if (ega->sc & 1 && !(ega->crtc[0x17] & 1)) + { + edat[0] = ega->vram[ega->ma | 0x8000]; + edat[1] = ega->vram[ega->ma | 0x8001]; + edat[2] = ega->vram[ega->ma | 0x8002]; + edat[3] = ega->vram[ega->ma | 0x8003]; + } + else + { + edat[0] = ega->vram[ega->ma]; + edat[1] = ega->vram[ega->ma | 0x1]; + edat[2] = ega->vram[ega->ma | 0x2]; + edat[3] = ega->vram[ega->ma | 0x3]; + } + ega->ma += 4; + ega->ma &= ega->vrammask; + dat = edatlookup[edat[0] & 3][edat[1] & 3] | (edatlookup[edat[2] & 3][edat[3] & 3] << 2); + ((uint32_t *)buffer32->line[dl])[(x << 4) + 14 + offset + x_add] = ((uint32_t *)buffer32->line[dl])[(x << 4) + 15 + offset + x_add] = ega->pallook[ega->egapal[(dat & 0xf) & ega->attrregs[0x12]]]; + ((uint32_t *)buffer32->line[dl])[(x << 4) + 12 + offset + x_add] = ((uint32_t *)buffer32->line[dl])[(x << 4) + 13 + offset + x_add] = ega->pallook[ega->egapal[(dat >> 4) & ega->attrregs[0x12]]]; + dat = edatlookup[(edat[0] >> 2) & 3][(edat[1] >> 2) & 3] | (edatlookup[(edat[2] >> 2) & 3][(edat[3] >> 2) & 3] << 2); + ((uint32_t *)buffer32->line[dl])[(x << 4) + 10 + offset + x_add] = ((uint32_t *)buffer32->line[dl])[(x << 4) + 11 + offset + x_add] = ega->pallook[ega->egapal[(dat & 0xf) & ega->attrregs[0x12]]]; + ((uint32_t *)buffer32->line[dl])[(x << 4) + 8 + offset + x_add] = ((uint32_t *)buffer32->line[dl])[(x << 4) + 9 + offset + x_add] = ega->pallook[ega->egapal[(dat >> 4) & ega->attrregs[0x12]]]; + dat = edatlookup[(edat[0] >> 4) & 3][(edat[1] >> 4) & 3] | (edatlookup[(edat[2] >> 4) & 3][(edat[3] >> 4) & 3] << 2); + ((uint32_t *)buffer32->line[dl])[(x << 4) + 6 + offset + x_add] = ((uint32_t *)buffer32->line[dl])[(x << 4) + 7 + offset + x_add] = ega->pallook[ega->egapal[(dat & 0xf) & ega->attrregs[0x12]]]; + ((uint32_t *)buffer32->line[dl])[(x << 4) + 4 + offset + x_add] = ((uint32_t *)buffer32->line[dl])[(x << 4) + 5 + offset + x_add] = ega->pallook[ega->egapal[(dat >> 4) & ega->attrregs[0x12]]]; + dat = edatlookup[edat[0] >> 6][edat[1] >> 6] | (edatlookup[edat[2] >> 6][edat[3] >> 6] << 2); + ((uint32_t *)buffer32->line[dl])[(x << 4) + 2 + offset + x_add] = ((uint32_t *)buffer32->line[dl])[(x << 4) + 3 + offset + x_add] = ega->pallook[ega->egapal[(dat & 0xf) & ega->attrregs[0x12]]]; + ((uint32_t *)buffer32->line[dl])[(x << 4) + offset + x_add] = ((uint32_t *)buffer32->line[dl])[(x << 4) + 1 + offset + x_add] = ega->pallook[ega->egapal[(dat >> 4) & ega->attrregs[0x12]]]; + } +} + +void ega_render_4bpp_highres(ega_t *ega) +{ + int x_add = (enable_overscan) ? 8 : 0; + int dl = ega_display_line(ega); + uint8_t dat; + int x; + int offset; + uint8_t edat[4]; + + offset = (8 - ega->scrollcache) + 24; + for (x = 0; x <= ega->hdisp; x++) + { + if (ega->sc & 1 && !(ega->crtc[0x17] & 1)) + { + edat[0] = ega->vram[ega->ma | 0x8000]; + edat[1] = ega->vram[ega->ma | 0x8001]; + edat[2] = ega->vram[ega->ma | 0x8002]; + edat[3] = ega->vram[ega->ma | 0x8003]; + } + else + { + edat[0] = ega->vram[ega->ma]; + edat[1] = ega->vram[ega->ma | 0x1]; + edat[2] = ega->vram[ega->ma | 0x2]; + edat[3] = ega->vram[ega->ma | 0x3]; + } + ega->ma += 4; + ega->ma &= ega->vrammask; + + dat = edatlookup[edat[0] & 3][edat[1] & 3] | (edatlookup[edat[2] & 3][edat[3] & 3] << 2); + ((uint32_t *)buffer32->line[dl])[(x << 3) + 7 + offset + x_add] = ega->pallook[ega->egapal[(dat & 0xf) & ega->attrregs[0x12]]]; + ((uint32_t *)buffer32->line[dl])[(x << 3) + 6 + offset + x_add] = ega->pallook[ega->egapal[(dat >> 4) & ega->attrregs[0x12]]]; + dat = edatlookup[(edat[0] >> 2) & 3][(edat[1] >> 2) & 3] | (edatlookup[(edat[2] >> 2) & 3][(edat[3] >> 2) & 3] << 2); + ((uint32_t *)buffer32->line[dl])[(x << 3) + 5 + offset + x_add] = ega->pallook[ega->egapal[(dat & 0xf) & ega->attrregs[0x12]]]; + ((uint32_t *)buffer32->line[dl])[(x << 3) + 4 + offset + x_add] = ega->pallook[ega->egapal[(dat >> 4) & ega->attrregs[0x12]]]; + dat = edatlookup[(edat[0] >> 4) & 3][(edat[1] >> 4) & 3] | (edatlookup[(edat[2] >> 4) & 3][(edat[3] >> 4) & 3] << 2); + ((uint32_t *)buffer32->line[dl])[(x << 3) + 3 + offset + x_add] = ega->pallook[ega->egapal[(dat & 0xf) & ega->attrregs[0x12]]]; + ((uint32_t *)buffer32->line[dl])[(x << 3) + 2 + offset + x_add] = ega->pallook[ega->egapal[(dat >> 4) & ega->attrregs[0x12]]]; + dat = edatlookup[edat[0] >> 6][edat[1] >> 6] | (edatlookup[edat[2] >> 6][edat[3] >> 6] << 2); + ((uint32_t *)buffer32->line[dl])[(x << 3) + 1 + offset + x_add] = ega->pallook[ega->egapal[(dat & 0xf) & ega->attrregs[0x12]]]; + ((uint32_t *)buffer32->line[dl])[(x << 3) + offset + x_add] = ega->pallook[ega->egapal[(dat >> 4) & ega->attrregs[0x12]]]; + } +} diff --git a/src/VIDEO/vid_ega_render.h b/src/VIDEO/vid_ega_render.h new file mode 100644 index 000000000..b833128a9 --- /dev/null +++ b/src/VIDEO/vid_ega_render.h @@ -0,0 +1,37 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * EGA renderers. + * + * Version: @(#)vid_ega_render.h 1.0.1 2017/06/05 + * + * Author: Sarah Walker, + * Miran Grca, + * Copyright 2008-2017 Sarah Walker. + * Copyright 2016-2017 Miran Grca. + */ + +extern int firstline_draw, lastline_draw; +extern int displine; +extern int sc; + +extern uint32_t ma, ca; +extern int con, cursoron, cgablink; + +extern int scrollcache; + +extern uint8_t edatlookup[4][4]; + +void ega_render_blank(ega_t *ega); +void ega_render_text_standard(ega_t *ega, int drawcursor); +void ega_render_text_jega(ega_t *ega, int drawcursor); + +void ega_render_2bpp_lowres(ega_t *ega); +void ega_render_2bpp_highres(ega_t *ega); +void ega_render_4bpp_lowres(ega_t *ega); +void ega_render_4bpp_highres(ega_t *ega); diff --git a/src/vid_et4000.c b/src/VIDEO/vid_et4000.c similarity index 90% rename from src/vid_et4000.c rename to src/VIDEO/vid_et4000.c index aae35bdb5..9ee0255a6 100644 --- a/src/vid_et4000.c +++ b/src/VIDEO/vid_et4000.c @@ -3,17 +3,17 @@ */ /*ET4000 emulation*/ #include -#include "ibm.h" -#include "device.h" -#include "io.h" -#include "mem.h" -#include "rom.h" +#include "../ibm.h" +#include "../io.h" +#include "../mem.h" +#include "../rom.h" +#include "../device.h" #include "video.h" #include "vid_svga.h" #include "vid_unk_ramdac.h" - #include "vid_et4000.h" + typedef struct et4000_t { svga_t svga; @@ -46,8 +46,6 @@ void et4000_out(uint16_t addr, uint8_t val, void *p) if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga->miscout & 1)) addr ^= 0x60; -// pclog("ET4000 out %04X %02X\n", addr, val); - switch (addr) { case 0x3C6: case 0x3C7: case 0x3C8: case 0x3C9: @@ -58,13 +56,11 @@ void et4000_out(uint16_t addr, uint8_t val, void *p) svga->write_bank = (val & 0xf) * 0x10000; svga->read_bank = ((val >> 4) & 0xf) * 0x10000; et4000->banking = val; -// pclog("Banking write %08X %08X %02X\n", svga->write_bank, svga->read_bank, val); return; case 0x3D4: svga->crtcreg = val & 0x3f; return; case 0x3D5: - // pclog("ET4000 Write: CRTC %02X = %02X\n", svga->crtcreg, val); if ((svga->crtcreg < 7) && (svga->crtc[0x11] & 0x80)) return; if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80)) @@ -92,9 +88,7 @@ uint8_t et4000_in(uint16_t addr, void *p) if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga->miscout & 1)) addr ^= 0x60; - -// if (addr != 0x3da) pclog("IN ET4000 %04X\n", addr); - + switch (addr) { case 0x3C5: @@ -116,8 +110,6 @@ uint8_t et4000_in(uint16_t addr, void *p) void et4000_recalctimings(svga_t *svga) { - et4000_t *et4000 = (et4000_t *)svga->p; - svga->ma_latch |= (svga->crtc[0x33]&3)<<16; if (svga->crtc[0x35] & 1) svga->vblankstart += 0x400; if (svga->crtc[0x35] & 2) svga->vtotal += 0x400; @@ -128,8 +120,6 @@ void et4000_recalctimings(svga_t *svga) if (svga->crtc[0x3f] & 1) svga->htotal += 256; if (svga->attrregs[0x16] & 0x20) svga->hdisp <<= 1; -// pclog("Rowoffset %i\n",svga_rowoffset); - switch (((svga->miscout >> 2) & 3) | ((svga->crtc[0x34] << 1) & 4)) { case 0: case 1: break; @@ -154,7 +144,7 @@ void *et4000_init() et4000_t *et4000 = malloc(sizeof(et4000_t)); memset(et4000, 0, sizeof(et4000_t)); - rom_init(&et4000->bios_rom, "roms/et4000.BIN", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + rom_init(&et4000->bios_rom, L"roms/et4000.BIN", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); io_sethandler(0x03c0, 0x0020, et4000_in, NULL, NULL, et4000_out, NULL, NULL, et4000); @@ -169,7 +159,7 @@ void *et4000_init() static int et4000_available() { - return rom_present("roms/et4000.BIN"); + return rom_present(L"roms/et4000.BIN"); } void et4000_close(void *p) diff --git a/src/vid_et4000.h b/src/VIDEO/vid_et4000.h similarity index 100% rename from src/vid_et4000.h rename to src/VIDEO/vid_et4000.h diff --git a/src/vid_et4000w32.c b/src/VIDEO/vid_et4000w32.c similarity index 90% rename from src/vid_et4000w32.c rename to src/VIDEO/vid_et4000w32.c index d5e879443..d0a2b1e90 100644 --- a/src/vid_et4000w32.c +++ b/src/VIDEO/vid_et4000w32.c @@ -4,18 +4,19 @@ - Accelerator doesn't work in planar modes */ #include -#include "ibm.h" -#include "device.h" -#include "io.h" -#include "mem.h" -#include "pci.h" -#include "rom.h" -#include "thread.h" +#include "../ibm.h" +#include "../io.h" +#include "../mem.h" +#include "../pci.h" +#include "../rom.h" +#include "../device.h" +#include "../win/plat_thread.h" #include "video.h" #include "vid_svga.h" #include "vid_icd2061.h" #include "vid_stg_ramdac.h" + #define FIFO_SIZE 65536 #define FIFO_MASK (FIFO_SIZE - 1) #define FIFO_ENTRY_SIZE (1 << 31) @@ -120,17 +121,9 @@ void et4000w32p_out(uint16_t addr, uint8_t val, void *p) svga_t *svga = &et4000->svga; uint8_t old; -// pclog("et4000w32p_out: addr %04X val %02X %04X:%04X %02X %02X\n", addr, val, CS, pc, ram[0x487], ram[0x488]); - -/* if (ram[0x487] == 0x62) - fatal("mono\n");*/ -// if (!(addr==0x3D4 && (val&~1)==0xE) && !(addr==0x3D5 && (crtcreg&~1)==0xE)) pclog("ET4000W32p out %04X %02X %04X:%04X ",addr,val,CS,pc); - if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) addr ^= 0x60; -// if (!(addr==0x3D4 && (val&~1)==0xE) && !(addr==0x3D5 && (crtcreg&~1)==0xE)) pclog("%04X\n",addr); - switch (addr) { case 0x3c2: @@ -156,7 +149,6 @@ void et4000w32p_out(uint16_t addr, uint8_t val, void *p) { case 6: svga->gdcreg[svga->gdcaddr & 15] = val; - //et4k_b8000=((crtc[0x36]&0x38)==0x28) && ((gdcreg[6]&0xC)==4); et4000w32p_recalcmapping(et4000); return; } @@ -165,7 +157,6 @@ void et4000w32p_out(uint16_t addr, uint8_t val, void *p) svga->crtcreg = val & 63; return; case 0x3D5: -// pclog("Write CRTC R%02X %02X\n", crtcreg, val); if ((svga->crtcreg < 7) && (svga->crtc[0x11] & 0x80)) return; if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80)) @@ -191,8 +182,6 @@ void et4000w32p_out(uint16_t addr, uint8_t val, void *p) { et4000->linearbase = val << 22; } - // et4000->linearbase = val * 0x400000; -// pclog("Linear base now at %08X %02X\n", et4000w32p_linearbase, val); et4000w32p_recalcmapping(et4000); } if (svga->crtcreg == 0x32 || svga->crtcreg == 0x36) @@ -213,7 +202,6 @@ void et4000w32p_out(uint16_t addr, uint8_t val, void *p) svga->hwcursor.ena = et4000->regs[0xF7] & 0x80; svga->hwcursor.xoff = et4000->regs[0xE2] & 63; svga->hwcursor.yoff = et4000->regs[0xE6] & 63; -// pclog("HWCURSOR X %i Y %i\n",svga->hwcursor_x,svga->hwcursor_y); return; } @@ -224,19 +212,10 @@ uint8_t et4000w32p_in(uint16_t addr, void *p) { et4000w32p_t *et4000 = (et4000w32p_t *)p; svga_t *svga = &et4000->svga; - uint8_t temp; -// if (addr==0x3DA) pclog("In 3DA %04X(%06X):%04X\n",CS,cs,pc); - -// pclog("ET4000W32p in %04X %04X:%04X ",addr,CS,pc); -// if (addr != 0x3da && addr != 0x3ba) -// pclog("et4000w32p_in: addr %04X %04X:%04X %02X %02X\n", addr, CS, pc, ram[0x487], ram[0x488]); - if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) addr ^= 0x60; -// pclog("%04X\n",addr); - switch (addr) { case 0x3c5: @@ -254,17 +233,7 @@ uint8_t et4000w32p_in(uint16_t addr, void *p) case 0x3D4: return svga->crtcreg; case 0x3D5: -// pclog("Read CRTC R%02X %02X\n", crtcreg, crtc[crtcreg]); return svga->crtc[svga->crtcreg]; - - case 0x3DA: - svga->attrff = 0; - svga->cgastat ^= 0x30; - temp = svga->cgastat & 0x39; - if (svga->hdisp_on) temp |= 2; - if (!(svga->cgastat & 8)) temp |= 0x80; -// pclog("3DA in %02X\n",temp); - return temp; case 0x210A: case 0x211A: case 0x212A: case 0x213A: case 0x214A: case 0x215A: case 0x216A: case 0x217A: @@ -286,9 +255,7 @@ uint8_t et4000w32p_in(uint16_t addr, void *p) void et4000w32p_recalctimings(svga_t *svga) { et4000w32p_t *et4000 = (et4000w32p_t *)svga->p; -// pclog("Recalc %08X ",svga_ma); svga->ma_latch |= (svga->crtc[0x33] & 0x7) << 16; -// pclog("SVGA_MA %08X %i\n", svga_ma, (svga_miscout >> 2) & 3); if (svga->crtc[0x35] & 0x01) svga->vblankstart += 0x400; if (svga->crtc[0x35] & 0x02) svga->vtotal += 0x400; if (svga->crtc[0x35] & 0x04) svga->dispend += 0x400; @@ -321,14 +288,12 @@ void et4000w32p_recalcmapping(et4000w32p_t *et4000) if (!(et4000->pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_MEM)) { - // pclog("Update mapping - PCI disabled\n"); mem_mapping_disable(&svga->mapping); mem_mapping_disable(&et4000->linear_mapping); mem_mapping_disable(&et4000->mmu_mapping); return; } - // pclog("recalcmapping %p\n", svga); if (svga->crtc[0x36] & 0x10) /*Linear frame buffer*/ { mem_mapping_set_addr(&et4000->linear_mapping, et4000->linearbase, 0x200000); @@ -381,7 +346,6 @@ void et4000w32p_recalcmapping(et4000w32p_t *et4000) } mem_mapping_disable(&et4000->linear_mapping); -// pclog("ET4K map %02X\n", map); } et4000->linearbase_old = et4000->linearbase; @@ -472,6 +436,11 @@ static void et4000w32p_accel_write_mmu(et4000w32p_t *et4000, uint32_t addr, uint static void fifo_thread(void *param) { et4000w32p_t *et4000 = (et4000w32p_t *)param; + + uint64_t start_time = 0; + uint64_t end_time = 0; + + fifo_entry_t *fifo; while (1) { @@ -481,10 +450,8 @@ static void fifo_thread(void *param) et4000->blitter_busy = 1; while (!FIFO_EMPTY) { - uint64_t start_time = timer_read(); - uint64_t end_time; - fifo_entry_t *fifo = &et4000->fifo[et4000->fifo_read_idx & FIFO_MASK]; - uint32_t val = fifo->val; + start_time = timer_read(); + fifo = &et4000->fifo[et4000->fifo_read_idx & FIFO_MASK]; switch (fifo->addr_type & FIFO_TYPE) { @@ -509,7 +476,7 @@ static void fifo_thread(void *param) } } -static inline void wake_fifo_thread(et4000w32p_t *et4000) +static __inline void wake_fifo_thread(et4000w32p_t *et4000) { thread_set_event(et4000->wake_fifo_thread); /*Wake up FIFO thread if moving from idle*/ } @@ -526,7 +493,6 @@ static void et4000w32p_wait_fifo_idle(et4000w32p_t *et4000) static void et4000w32p_queue(et4000w32p_t *et4000, uint32_t addr, uint32_t val, uint32_t type) { fifo_entry_t *fifo = &et4000->fifo[et4000->fifo_write_idx & FIFO_MASK]; - int c; if (FIFO_FULL) { @@ -551,8 +517,6 @@ void et4000w32p_mmu_write(uint32_t addr, uint8_t val, void *p) et4000w32p_t *et4000 = (et4000w32p_t *)p; svga_t *svga = &et4000->svga; int bank; -// pclog("ET4K write %08X %02X %02X %04X(%08X):%08X\n",addr,val,et4000->acl.status,et4000->acl.internal.ctrl_routing,CS,cs,pc); -// et4000->acl.status |= ACL_RDST; switch (addr & 0x6000) { case 0x0000: /*MMU 0*/ @@ -603,7 +567,6 @@ uint8_t et4000w32p_mmu_read(uint32_t addr, void *p) svga_t *svga = &et4000->svga; int bank; uint8_t temp; -// pclog("ET4K read %08X %04X(%08X):%08X\n",addr,CS,cs,pc); switch (addr & 0x6000) { case 0x0000: /*MMU 0*/ @@ -650,13 +613,11 @@ uint8_t et4000w32p_mmu_read(uint32_t addr, void *p) case 0x7f36: temp = et4000->acl.status; -// et4000->acl.status &= ~ACL_RDST; temp &= ~0x03; if (!FIFO_EMPTY) temp |= 0x02; if (FIFO_FULL) temp |= 0x01; -// if (et4000->acl.internal.pos_x!=et4000->acl.internal.count_x || et4000->acl.internal.pos_y!=et4000->acl.internal.count_y) return et4000->acl.status | ACL_XYST; return temp; case 0x7f80: return et4000->acl.internal.pattern_addr; case 0x7f81: return et4000->acl.internal.pattern_addr >> 8; @@ -701,10 +662,6 @@ static int et4000w32_wrap_y[8]={1,2,4,8,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFF int bltout=0; void et4000w32_blit_start(et4000w32p_t *et4000) { -// if (et4000->acl.queued.xy_dir&0x80) -// pclog("Blit - %02X %08X (%i,%i) %08X (%i,%i) %08X (%i,%i) %i %i %i %02X %02X %02X\n",et4000->acl.queued.xy_dir,et4000->acl.internal.pattern_addr,(et4000->acl.internal.pattern_addr/3)%640,(et4000->acl.internal.pattern_addr/3)/640,et4000->acl.internal.source_addr,(et4000->acl.internal.source_addr/3)%640,(et4000->acl.internal.source_addr/3)/640,et4000->acl.internal.dest_addr,(et4000->acl.internal.dest_addr/3)%640,(et4000->acl.internal.dest_addr/3)/640,et4000->acl.internal.xy_dir,et4000->acl.internal.count_x,et4000->acl.internal.count_y,et4000->acl.internal.rop_fg,et4000->acl.internal.rop_bg, et4000->acl.internal.ctrl_routing); -// bltout=1; -// bltout=(et4000->acl.internal.count_x==1541); if (!(et4000->acl.queued.xy_dir & 0x20)) et4000->acl.internal.error = et4000->acl.internal.dmaj / 2; et4000->acl.pattern_addr= et4000->acl.internal.pattern_addr; @@ -824,8 +781,6 @@ void et4000w32_blit(int count, uint32_t mix, uint32_t sdat, int cpu_input, et400 int mixdat; if (!(et4000->acl.status & ACL_XYST)) return; -// if (count>400) pclog("New blit - %i,%i %06X (%i,%i) %06X %06X\n",et4000->acl.internal.count_x,et4000->acl.internal.count_y,et4000->acl.dest_addr,et4000->acl.dest_addr%640,et4000->acl.dest_addr/640,et4000->acl.source_addr,et4000->acl.pattern_addr); - //pclog("Blit exec - %i %i %i\n",count,et4000->acl.internal.pos_x,et4000->acl.internal.pos_y); if (et4000->acl.internal.xy_dir & 0x80) /*Line draw*/ { while (count--) @@ -874,7 +829,6 @@ void et4000w32_blit(int count, uint32_t mix, uint32_t sdat, int cpu_input, et400 et4000->acl.cpu_dat_pos++; } -// pclog("%i %i\n",et4000->acl.pix_pos,(et4000->acl.internal.pixel_depth>>4)&3); et4000->acl.pix_pos++; et4000->acl.internal.pos_x++; if (et4000->acl.pix_pos <= ((et4000->acl.internal.pixel_depth >> 4) & 3)) @@ -904,11 +858,9 @@ void et4000w32_blit(int count, uint32_t mix, uint32_t sdat, int cpu_input, et400 break; case 4: case 6: /*X+*/ et4000w32_incx(((et4000->acl.internal.pixel_depth >> 4) & 3) + 1, et4000); - //et4000->acl.internal.pos_x++; break; case 5: case 7: /*X-*/ et4000w32_decx(((et4000->acl.internal.pixel_depth >> 4) & 3) + 1, et4000); - //et4000->acl.internal.pos_x++; break; } et4000->acl.internal.error += et4000->acl.internal.dmin; @@ -939,7 +891,6 @@ void et4000w32_blit(int count, uint32_t mix, uint32_t sdat, int cpu_input, et400 et4000->acl.internal.pos_y > et4000->acl.internal.count_y) { et4000->acl.status &= ~(ACL_XYST | ACL_SSO); -// pclog("Blit line over\n"); return; } } @@ -1022,7 +973,6 @@ void et4000w32_blit(int count, uint32_t mix, uint32_t sdat, int cpu_input, et400 if (et4000->acl.internal.pos_y > et4000->acl.internal.count_y) { et4000->acl.status &= ~(ACL_XYST | ACL_SSO); -// pclog("Blit over\n"); return; } if (cpu_input) return; @@ -1042,21 +992,24 @@ void et4000w32p_hwcursor_draw(svga_t *svga, int displine) { int x, offset; uint8_t dat; + int y_add = (enable_overscan && !suppress_overscan) ? 16 : 0; + int x_add = (enable_overscan && !suppress_overscan) ? 8 : 0; offset = svga->hwcursor_latch.xoff; + for (x = 0; x < 64 - svga->hwcursor_latch.xoff; x += 4) { dat = svga->vram[svga->hwcursor_latch.addr + (offset >> 2)]; - if (!(dat & 2)) ((uint32_t *)buffer32->line[displine])[svga->hwcursor_latch.x + x + 32] = (dat & 1) ? 0xFFFFFF : 0; - else if ((dat & 3) == 3) ((uint32_t *)buffer32->line[displine])[svga->hwcursor_latch.x + x + 32] ^= 0xFFFFFF; + if (!(dat & 2)) ((uint32_t *)buffer32->line[displine + y_add])[svga->hwcursor_latch.x + x_add + x + 32] = (dat & 1) ? 0xFFFFFF : 0; + else if ((dat & 3) == 3) ((uint32_t *)buffer32->line[displine + y_add])[svga->hwcursor_latch.x + x_add + x + 32] ^= 0xFFFFFF; dat >>= 2; - if (!(dat & 2)) ((uint32_t *)buffer32->line[displine])[svga->hwcursor_latch.x + x + 33] = (dat & 1) ? 0xFFFFFF : 0; - else if ((dat & 3) == 3) ((uint32_t *)buffer32->line[displine])[svga->hwcursor_latch.x + x + 33] ^= 0xFFFFFF; + if (!(dat & 2)) ((uint32_t *)buffer32->line[displine + y_add])[svga->hwcursor_latch.x + x_add + x + 33 + x_add] = (dat & 1) ? 0xFFFFFF : 0; + else if ((dat & 3) == 3) ((uint32_t *)buffer32->line[displine + y_add])[svga->hwcursor_latch.x + x_add + x + 33 + x_add] ^= 0xFFFFFF; dat >>= 2; - if (!(dat & 2)) ((uint32_t *)buffer32->line[displine])[svga->hwcursor_latch.x + x + 34] = (dat & 1) ? 0xFFFFFF : 0; - else if ((dat & 3) == 3) ((uint32_t *)buffer32->line[displine])[svga->hwcursor_latch.x + x + 34] ^= 0xFFFFFF; + if (!(dat & 2)) ((uint32_t *)buffer32->line[displine + y_add])[svga->hwcursor_latch.x + x_add + x + 34] = (dat & 1) ? 0xFFFFFF : 0; + else if ((dat & 3) == 3) ((uint32_t *)buffer32->line[displine + y_add])[svga->hwcursor_latch.x + x_add + x + 34] ^= 0xFFFFFF; dat >>= 2; - if (!(dat & 2)) ((uint32_t *)buffer32->line[displine])[svga->hwcursor_latch.x + x + 35] = (dat & 1) ? 0xFFFFFF : 0; - else if ((dat & 3) == 3) ((uint32_t *)buffer32->line[displine])[svga->hwcursor_latch.x + x + 35] ^= 0xFFFFFF; + if (!(dat & 2)) ((uint32_t *)buffer32->line[displine + y_add])[svga->hwcursor_latch.x + x_add + x + 35] = (dat & 1) ? 0xFFFFFF : 0; + else if ((dat & 3) == 3) ((uint32_t *)buffer32->line[displine + y_add])[svga->hwcursor_latch.x + x_add + x + 35] ^= 0xFFFFFF; dat >>= 2; offset += 4; } @@ -1096,12 +1049,9 @@ static void et4000w32p_io_set(et4000w32p_t *et4000) uint8_t et4000w32p_pci_read(int func, int addr, void *p) { et4000w32p_t *et4000 = (et4000w32p_t *)p; - svga_t *svga = &et4000->svga; addr &= 0xff; - // pclog("ET4000 PCI read %08X\n", addr); - switch (addr) { case 0x00: return 0x0c; /*Tseng Labs*/ @@ -1139,12 +1089,9 @@ void et4000w32p_pci_write(int func, int addr, uint8_t val, void *p) { et4000w32p_t *et4000 = (et4000w32p_t *)p; svga_t *svga = &et4000->svga; - uint32_t temp = 0; addr &= 0xff; - // pclog("ET4000 PCI Write: value %02X to address %08X\n"); - switch (addr) { case PCI_REG_COMMAND: @@ -1172,7 +1119,6 @@ void et4000w32p_pci_write(int func, int addr, uint8_t val, void *p) et4000->pci_regs[0x33] &= 0xf0; if (et4000->pci_regs[0x30] & 0x01) { - // uint32_t addr = ((et4000->pci_regs[0x31] & 0x80) << 8) | ((et4000->pci_regs[0x32] & 0x0f) << 16) | (et4000->pci_regs[0x33] << 24); uint32_t addr = (et4000->pci_regs[0x33] << 24); if (!addr) { @@ -1206,7 +1152,7 @@ void *et4000w32p_init() et4000w32p_hwcursor_draw, NULL); - rom_init(&et4000->bios_rom, "roms/et4000w32.bin", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + rom_init(&et4000->bios_rom, L"roms/et4000w32.bin", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); if (PCI) mem_mapping_disable(&et4000->bios_rom.mapping); @@ -1241,7 +1187,7 @@ void *et4000w32p_init() int et4000w32p_available() { - return rom_present("roms/et4000w32.bin"); + return rom_present(L"roms/et4000w32.bin"); } void et4000w32p_close(void *p) @@ -1250,6 +1196,10 @@ void et4000w32p_close(void *p) svga_close(&et4000->svga); + thread_kill(et4000->fifo_thread); + thread_destroy_event(et4000->wake_fifo_thread); + thread_destroy_event(et4000->fifo_not_full_event); + free(et4000); } @@ -1286,27 +1236,21 @@ void et4000w32p_add_status_info(char *s, int max_len, void *p) static device_config_t et4000w32p_config[] = { { - .name = "memory", - .description = "Memory size", - .type = CONFIG_SELECTION, - .selection = + "memory", "Memory size", CONFIG_SELECTION, "", 2, { { - .description = "1 MB", - .value = 1 + "1 MB", 1 }, { - .description = "2 MB", - .value = 2 + "2 MB", 2 }, { - .description = "" + "" } - }, - .default_int = 2 + } }, { - .type = -1 + "", "", -1 } }; diff --git a/src/vid_et4000w32.h b/src/VIDEO/vid_et4000w32.h similarity index 100% rename from src/vid_et4000w32.h rename to src/VIDEO/vid_et4000w32.h diff --git a/src/vid_et4000w32i.c b/src/VIDEO/vid_et4000w32i.c similarity index 100% rename from src/vid_et4000w32i.c rename to src/VIDEO/vid_et4000w32i.c diff --git a/src/VIDEO/vid_genius.c b/src/VIDEO/vid_genius.c new file mode 100644 index 000000000..35db8905f --- /dev/null +++ b/src/VIDEO/vid_genius.c @@ -0,0 +1,630 @@ +/* MDSI Genius VHR emulation*/ +#include +#include "../ibm.h" +#include "../io.h" +#include "../mem.h" +#include "../rom.h" +#include "../timer.h" +#include "../device.h" +#include "video.h" +#include "vid_genius.h" + + +#define GENIUS_XSIZE 728 +#define GENIUS_YSIZE 1008 + + +void updatewindowsize(int x, int y); + +extern uint8_t fontdat8x12[256][16]; + +/* I'm at something of a disadvantage writing this emulation: I don't have an + * MDSI Genius card, nor do I have the BIOS extension (VHRBIOS.SYS) that came + * with it. What I do have are the GEM and Windows 1.04 drivers, plus a driver + * for a later MCA version of the card. The latter can be found at + * and is necessary if you + * want the Windows driver to work. + * + * This emulation appears to work correctly with: + * The MCA drivers GMC_ANSI.SYS and INS_ANSI.SYS + * The GEM driver SDGEN9.VGA + * The Windows 1.04 driver GENIUS.DRV + * + * As far as I can see, the card uses a fixed resolution of 728x1008 pixels. + * It has the following modes of operation: + * + * > MDA-compatible: 80x25 text, each character 9x15 pixels. + * > CGA-compatible: 640x200 mono graphics + * > Dual: MDA text in the top half, CGA graphics in the bottom + * > Native text: 80x66 text, each character 9x15 pixels. + * > Native graphics: 728x1008 mono graphics. + * + * Under the covers, this seems to translate to: + * > Text framebuffer. At B000:0000, 16k. Displayed if enable bit is set + * in the MDA control register. + * > Graphics framebuffer. In native modes goes from A000:0000 to A000:FFFF + * and B800:0000 to B800:FFFF. In CGA-compatible + * mode only the section at B800:0000 to B800:7FFF + * is visible. Displayed if enable bit is set in the + * CGA control register. + * + * Two card-specific registers control text and graphics display: + * + * 03B0: Control register. + * Bit 0: Map all graphics framebuffer into memory. + * Bit 2: Unknown. Set by GMC /M; cleared by mode set or GMC /T. + * Bit 4: Set for CGA-compatible graphics, clear for native graphics. + * Bit 5: Set for black on white, clear for white on black. + * + * 03B1: Character height register. + * Bits 0-1: Character cell height (0 => 15, 1 => 14, 2 => 13, 3 => 12) + * Bit 4: Set to double character cell height (scanlines are doubled) + * Bit 7: Unknown, seems to be set for all modes except 80x66 + * + * Not having the card also means I don't have its font. According to the + * card brochure the font is an 8x12 bitmap in a 9x15 character cell. I + * therefore generated it by taking the MDA font, increasing graphics to + * 16 pixels in height and reducing the height of characters so they fit + * in an 8x12 cell if necessary. + */ + + + +typedef struct genius_t +{ + mem_mapping_t mapping; + + uint8_t mda_crtc[32]; /* The 'CRTC' as the host PC sees it */ + int mda_crtcreg; /* Current CRTC register */ + uint8_t genius_control; /* Native control register + * I think bit 0 enables the full + * framebuffer. + */ + uint8_t genius_charh; /* Native character height register: + * 00h => chars are 15 pixels high + * 81h => chars are 14 pixels high + * 83h => chars are 12 pixels high + * 90h => chars are 30 pixels high [15 x 2] + * 93h => chars are 24 pixels high [12 x 2] + */ + uint8_t genius_mode; /* Current mode (see list at top of file) */ + uint8_t cga_ctrl; /* Emulated CGA control register */ + uint8_t mda_ctrl; /* Emulated MDA control register */ + uint8_t cga_colour; /* Emulated CGA colour register (ignored) */ + + uint8_t mda_stat; /* MDA status (IN 0x3BA) */ + uint8_t cga_stat; /* CGA status (IN 0x3DA) */ + + int font; /* Current font, 0 or 1 */ + int enabled; /* Display enabled, 0 or 1 */ + int detach; /* Detach cursor, 0 or 1 */ + + int dispontime, dispofftime; + int vidtime; + + int linepos, displine; + int vc; + int dispon, blink; + int vsynctime; + + uint8_t *vram; +} genius_t; + +/* Mapping of attributes to colours, in MDA emulation mode */ +static int mdacols[256][2][2]; + +void genius_recalctimings(genius_t *genius); +void genius_write(uint32_t addr, uint8_t val, void *p); +uint8_t genius_read(uint32_t addr, void *p); + + +void genius_out(uint16_t addr, uint8_t val, void *p) +{ + genius_t *genius = (genius_t *)p; + + switch (addr) + { + case 0x3b0: /* Command / control register */ + genius->genius_control = val; + if (val & 1) + { + mem_mapping_set_addr(&genius->mapping, 0xa0000, 0x28000); + } + else + { + mem_mapping_set_addr(&genius->mapping, 0xb0000, 0x10000); + } + + break; + + case 0x3b1: + genius->genius_charh = val; + break; + + /* Emulated CRTC, register select */ + case 0x3b2: case 0x3b4: case 0x3b6: + case 0x3d0: case 0x3d2: case 0x3d4: case 0x3d6: + genius->mda_crtcreg = val & 31; + break; + + /* Emulated CRTC, value */ + case 0x3b3: case 0x3b5: case 0x3b7: + case 0x3d1: case 0x3d3: case 0x3d5: case 0x3d7: + genius->mda_crtc[genius->mda_crtcreg] = val; + genius_recalctimings(genius); + return; + + /* Emulated MDA control register */ + case 0x3b8: + genius->mda_ctrl = val; + return; + /* Emulated CGA control register */ + case 0x3D8: + genius->cga_ctrl = val; + return; + /* Emulated CGA colour register */ + case 0x3D9: + genius->cga_colour = val; + return; + } +} + +uint8_t genius_in(uint16_t addr, void *p) +{ + genius_t *genius = (genius_t *)p; + + switch (addr) + { + case 0x3b0: case 0x3b2: case 0x3b4: case 0x3b6: + case 0x3d0: case 0x3d2: case 0x3d4: case 0x3d6: + return genius->mda_crtcreg; + case 0x3b1: case 0x3b3: case 0x3b5: case 0x3b7: + case 0x3d1: case 0x3d3: case 0x3d5: case 0x3d7: + return genius->mda_crtc[genius->mda_crtcreg]; + case 0x3b8: + return genius->mda_ctrl; + case 0x3d9: + return genius->cga_colour; + case 0x3ba: + return genius->mda_stat; + case 0x3d8: + return genius->cga_ctrl; + case 0x3da: + return genius->cga_stat; + } + return 0xff; +} + + + +void genius_write(uint32_t addr, uint8_t val, void *p) +{ + genius_t *genius = (genius_t *)p; + egawrites++; + + if (genius->genius_control & 1) + { + addr = addr % 0x28000; + } + else + /* If hi-res memory is disabled, only visible in the B000 segment */ + { + addr = (addr & 0xFFFF) + 0x10000; + } + genius->vram[addr] = val; +} + + + +uint8_t genius_read(uint32_t addr, void *p) +{ + genius_t *genius = (genius_t *)p; + egareads++; + + if (genius->genius_control & 1) + { + addr = addr % 0x28000; + } + else + /* If hi-res memory is disabled, only visible in the B000 segment */ + { + addr = (addr & 0xFFFF) + 0x10000; + } + return genius->vram[addr]; +} + + + +void genius_recalctimings(genius_t *genius) +{ + double disptime; + double _dispontime, _dispofftime; + + disptime = 0x31; + _dispontime = 0x28; + _dispofftime = disptime - _dispontime; + _dispontime *= MDACONST; + _dispofftime *= MDACONST; + genius->dispontime = (int)(_dispontime * (1 << TIMER_SHIFT)); + genius->dispofftime = (int)(_dispofftime * (1 << TIMER_SHIFT)); +} + + +/* Draw a single line of the screen in either text mode */ +void genius_textline(genius_t *genius, uint8_t background) +{ + int x; + int w = 80; /* 80 characters across */ + int cw = 9; /* Each character is 9 pixels wide */ + uint8_t chr, attr; + uint8_t bitmap[2]; + int blink, c, row; + int drawcursor, cursorline; + uint16_t addr; + uint8_t sc; + int charh; + uint16_t ma = (genius->mda_crtc[13] | (genius->mda_crtc[12] << 8)) & 0x3fff; + uint16_t ca = (genius->mda_crtc[15] | (genius->mda_crtc[14] << 8)) & 0x3fff; + unsigned char *framebuf = genius->vram + 0x10000; + uint8_t col; + + /* Character height is 12-15 */ + charh = 15 - (genius->genius_charh & 3); + if (genius->genius_charh & 0x10) + { + row = ((genius->displine >> 1) / charh); + sc = ((genius->displine >> 1) % charh); + } + else + { + row = (genius->displine / charh); + sc = (genius->displine % charh); + } + addr = ((ma & ~1) + row * w) * 2; + + ma += (row * w); + + if ((genius->mda_crtc[10] & 0x60) == 0x20) + { + cursorline = 0; + } + else + { + cursorline = ((genius->mda_crtc[10] & 0x1F) <= sc) && + ((genius->mda_crtc[11] & 0x1F) >= sc); + } + + for (x = 0; x < w; x++) + { + chr = framebuf[(addr + 2 * x) & 0x3FFF]; + attr = framebuf[(addr + 2 * x + 1) & 0x3FFF]; + drawcursor = ((ma == ca) && cursorline && genius->enabled && + (genius->mda_ctrl & 8)); + + switch (genius->mda_crtc[10] & 0x60) + { + case 0x00: drawcursor = drawcursor && (genius->blink & 16); break; + case 0x60: drawcursor = drawcursor && (genius->blink & 32); break; + } + blink = ((genius->blink & 16) && + (genius->mda_ctrl & 0x20) && + (attr & 0x80) && !drawcursor); + + if (genius->mda_ctrl & 0x20) attr &= 0x7F; + /* MDA underline */ + if (sc == charh && ((attr & 7) == 1)) + { + col = mdacols[attr][blink][1]; + + if (genius->genius_control & 0x20) + { + col ^= 15; + } + + for (c = 0; c < cw; c++) + { + if (col != background) + buffer->line[genius->displine][(x * cw) + c] = col; + } + } + else /* Draw 8 pixels of character */ + { + bitmap[0] = fontdat8x12[chr][sc]; + for (c = 0; c < 8; c++) + { + col = mdacols[attr][blink][(bitmap[0] & (1 << (c ^ 7))) ? 1 : 0]; + if (!(genius->enabled) || !(genius->mda_ctrl & 8)) + col = mdacols[0][0][0]; + + if (genius->genius_control & 0x20) + { + col ^= 15; + } + if (col != background) + { + buffer->line[genius->displine][(x * cw) + c] = col; + } + } + /* The ninth pixel column... */ + if ((chr & ~0x1f) == 0xc0) + { + /* Echo column 8 for the graphics chars */ + col = buffer->line[genius->displine][(x * cw) + 7]; + if (col != background) buffer->line[genius->displine][(x * cw) + 8] = col; + } + else /* Otherwise fill with background */ + { + col = mdacols[attr][blink][0]; + if (genius->genius_control & 0x20) + { + col ^= 15; + } + if (col != background) buffer->line[genius->displine][(x * cw) + 8] = col; + } + if (drawcursor) + { + for (c = 0; c < cw; c++) + buffer->line[genius->displine][(x * cw) + c] ^= mdacols[attr][0][1]; + } + ++ma; + } + } +} + + + + +/* Draw a line in the CGA 640x200 mode */ +void genius_cgaline(genius_t *genius) +{ + int x, c; + uint32_t dat; + uint8_t ink; + uint32_t addr; + + ink = (genius->genius_control & 0x20) ? 16 : 16+15; + /* We draw the CGA at row 600 */ + if (genius->displine < 600) + { + return; + } + addr = 0x18000 + 80 * ((genius->displine - 600) >> 2); + if ((genius->displine - 600) & 2) + { + addr += 0x2000; + } + + for (x = 0; x < 80; x++) + { + dat = genius->vram[addr]; + addr++; + + for (c = 0; c < 8; c++) + { + if (dat & 0x80) + { + buffer->line[genius->displine][x*8 + c] = ink; + } + dat = dat << 1; + } + } +} + + + + +/* Draw a line in the native high-resolution mode */ +void genius_hiresline(genius_t *genius) +{ + int x, c; + uint32_t dat; + uint8_t ink; + uint32_t addr; + + ink = (genius->genius_control & 0x20) ? 16 : 16+15; + /* The first 512 lines live at A0000 */ + if (genius->displine < 512) + { + addr = 128 * genius->displine; + } + else /* The second 496 live at B8000 */ + { + addr = 0x18000 + 128 * (genius->displine - 512); + } + + for (x = 0; x < 91; x++) + { + dat = genius->vram[addr]; + addr++; + + for (c = 0; c < 8; c++) + { + if (dat & 0x80) + { + buffer->line[genius->displine][x*8 + c] = ink; + } + dat = dat << 1; + } + } +} + + + + +void genius_poll(void *p) +{ + genius_t *genius = (genius_t *)p; + int x; + uint8_t background; + + if (!genius->linepos) + { + genius->vidtime += genius->dispofftime; + genius->cga_stat |= 1; + genius->mda_stat |= 1; + genius->linepos = 1; + if (genius->dispon) + { + if (genius->genius_control & 0x20) + { + background = 16 + 15; + } + else + { + background = 16; + } + if (genius->displine == 0) + { + video_wait_for_buffer(); + } + /* Start off with a blank line */ + for (x = 0; x < GENIUS_XSIZE; x++) + { + buffer->line[genius->displine][x] = background; + } + /* If graphics display enabled, draw graphics on top + * of the blanked line */ + if (genius->cga_ctrl & 8) + { + if (genius->genius_control & 8) + { + genius_cgaline(genius); + } + else + { + genius_hiresline(genius); + } + } + /* If MDA display is enabled, draw MDA text on top + * of the lot */ + if (genius->mda_ctrl & 8) + { + genius_textline(genius, background); + } + } + genius->displine++; + /* Hardcode a fixed refresh rate and VSYNC timing */ + if (genius->displine == 1008) /* Start of VSYNC */ + { + genius->cga_stat |= 8; + genius->dispon = 0; + } + if (genius->displine == 1040) /* End of VSYNC */ + { + genius->displine = 0; + genius->cga_stat &= ~8; + genius->dispon = 1; + } + } + else + { + if (genius->dispon) + { + genius->cga_stat &= ~1; + genius->mda_stat &= ~1; + } + genius->vidtime += genius->dispontime; + genius->linepos = 0; + + if (genius->displine == 1008) + { +/* Hardcode GENIUS_XSIZE * GENIUS_YSIZE window size */ + if (GENIUS_XSIZE != xsize || GENIUS_YSIZE != ysize) + { + xsize = GENIUS_XSIZE; + ysize = GENIUS_YSIZE; + if (xsize < 64) xsize = 656; + if (ysize < 32) ysize = 200; + updatewindowsize(xsize, ysize); + } + video_blit_memtoscreen_8(0, 0, xsize, ysize); + + frames++; + /* Fixed 728x1008 resolution */ + video_res_x = GENIUS_XSIZE; + video_res_y = GENIUS_YSIZE; + video_bpp = 1; + genius->blink++; + } + } +} + +void *genius_init() +{ + int c; + genius_t *genius = malloc(sizeof(genius_t)); + memset(genius, 0, sizeof(genius_t)); + + /* 160k video RAM */ + genius->vram = malloc(0x28000); + + timer_add(genius_poll, &genius->vidtime, TIMER_ALWAYS_ENABLED, genius); + + /* Occupy memory between 0xB0000 and 0xBFFFF (moves to 0xA0000 in + * high-resolution modes) */ + mem_mapping_add(&genius->mapping, 0xb0000, 0x10000, genius_read, NULL, NULL, genius_write, NULL, NULL, NULL, MEM_MAPPING_EXTERNAL, genius); + /* Respond to both MDA and CGA I/O ports */ + io_sethandler(0x03b0, 0x000C, genius_in, NULL, NULL, genius_out, NULL, NULL, genius); + io_sethandler(0x03d0, 0x0010, genius_in, NULL, NULL, genius_out, NULL, NULL, genius); + + /* MDA attributes */ + /* I don't know if the Genius's MDA emulation actually does + * emulate bright / non-bright. For the time being pretend it does. */ + for (c = 0; c < 256; c++) + { + mdacols[c][0][0] = mdacols[c][1][0] = mdacols[c][1][1] = 16; + if (c & 8) mdacols[c][0][1] = 15 + 16; + else mdacols[c][0][1] = 7 + 16; + } + mdacols[0x70][0][1] = 16; + mdacols[0x70][0][0] = mdacols[0x70][1][0] = mdacols[0x70][1][1] = 16 + 15; + mdacols[0xF0][0][1] = 16; + mdacols[0xF0][0][0] = mdacols[0xF0][1][0] = mdacols[0xF0][1][1] = 16 + 15; + mdacols[0x78][0][1] = 16 + 7; + mdacols[0x78][0][0] = mdacols[0x78][1][0] = mdacols[0x78][1][1] = 16 + 15; + mdacols[0xF8][0][1] = 16 + 7; + mdacols[0xF8][0][0] = mdacols[0xF8][1][0] = mdacols[0xF8][1][1] = 16 + 15; + mdacols[0x00][0][1] = mdacols[0x00][1][1] = 16; + mdacols[0x08][0][1] = mdacols[0x08][1][1] = 16; + mdacols[0x80][0][1] = mdacols[0x80][1][1] = 16; + mdacols[0x88][0][1] = mdacols[0x88][1][1] = 16; + +/* Start off in 80x25 text mode */ + genius->cga_stat = 0xF4; + genius->genius_mode = 2; + genius->enabled = 1; + genius->genius_charh = 0x90; /* Native character height register */ + return genius; +} + +void genius_close(void *p) +{ + genius_t *genius = (genius_t *)p; + + free(genius->vram); + free(genius); +} + +static int genius_available() +{ + return rom_present(L"roms/8x12.bin"); +} + +void genius_speed_changed(void *p) +{ + genius_t *genius = (genius_t *)p; + + genius_recalctimings(genius); +} + +device_t genius_device = +{ + "Genius VHR", + 0, + genius_init, + genius_close, + genius_available, + genius_speed_changed, + NULL, + NULL +}; diff --git a/src/VIDEO/vid_genius.h b/src/VIDEO/vid_genius.h new file mode 100644 index 000000000..77dce66f0 --- /dev/null +++ b/src/VIDEO/vid_genius.h @@ -0,0 +1 @@ +extern device_t genius_device; diff --git a/src/vid_hercules.c b/src/VIDEO/vid_hercules.c similarity index 92% rename from src/vid_hercules.c rename to src/VIDEO/vid_hercules.c index 9c24d8de5..bbb8b57b6 100644 --- a/src/vid_hercules.c +++ b/src/VIDEO/vid_hercules.c @@ -3,12 +3,17 @@ */ /*Hercules emulation*/ #include -#include "ibm.h" -#include "device.h" -#include "mem.h" -#include "timer.h" +#include "../ibm.h" +#include "../mem.h" +#include "../io.h" +#include "../timer.h" +#include "../device.h" #include "video.h" #include "vid_hercules.h" +#ifndef __unix +# include "../win/win_cgapal.h" /*YUCK*/ +#endif + typedef struct hercules_t { @@ -128,7 +133,6 @@ void hercules_poll(void *p) int oldvc; uint8_t chr, attr; uint16_t dat; - int cols[4]; int oldsc; int blink; if (!hercules->linepos) @@ -148,8 +152,6 @@ void hercules_poll(void *p) video_wait_for_buffer(); } hercules->lastline = hercules->displine; - cols[0] = 0; - cols[1] = 7; if ((hercules->ctrl & 2) && (hercules->ctrl2 & 1)) { ca = (hercules->sc & 3) * 0x2000; @@ -168,8 +170,8 @@ void hercules_poll(void *p) { for (x = 0; x < hercules->crtc[1]; x++) { - chr = hercules->vram[(hercules->ma << 1) & 0x3fff]; - attr = hercules->vram[((hercules->ma << 1) + 1) & 0x3fff]; + chr = hercules->vram[(hercules->ma << 1) & 0xfff]; + attr = hercules->vram[((hercules->ma << 1) + 1) & 0xfff]; drawcursor = ((hercules->ma == ca) && hercules->con && hercules->cursoron); blink = ((hercules->blink & 16) && (hercules->ctrl & 0x20) && (attr & 0x80) && !drawcursor); if (hercules->sc == 12 && ((attr & 7) == 1)) @@ -318,7 +320,7 @@ void *hercules_init() hercules->vram = malloc(0x10000); timer_add(hercules_poll, &hercules->vidtime, TIMER_ALWAYS_ENABLED, hercules); - mem_mapping_add(&hercules->mapping, 0xb0000, 0x08000, hercules_read, NULL, NULL, hercules_write, NULL, NULL, NULL, 0, hercules); + mem_mapping_add(&hercules->mapping, 0xb0000, 0x08000, hercules_read, NULL, NULL, hercules_write, NULL, NULL, NULL, MEM_MAPPING_EXTERNAL, hercules); io_sethandler(0x03b0, 0x0010, hercules_in, NULL, NULL, hercules_out, NULL, NULL, hercules); for (c = 0; c < 256; c++) @@ -342,6 +344,15 @@ void *hercules_init() overscan_x = overscan_y = 0; +#ifndef __unix + cga_palette = device_get_config_int("rgb_type") << 1; + if (cga_palette > 6) + { + cga_palette = 0; + } + cgapal_rebuild(); +#endif + return hercules; } @@ -360,6 +371,35 @@ void hercules_speed_changed(void *p) hercules_recalctimings(hercules); } +#ifndef __unix +static device_config_t hercules_config[] = +{ + { + "rgb_type", "Display type", CONFIG_SELECTION, "", 0, + { + { + "Default", 0 + }, + { + "Green", 1 + }, + { + "Amber", 2 + }, + { + "Gray", 3 + }, + { + "" + } + } + }, + { + "", "", -1 + } +}; +#endif + device_t hercules_device = { "Hercules", @@ -369,5 +409,10 @@ device_t hercules_device = NULL, hercules_speed_changed, NULL, +#ifdef __unix NULL +#else + NULL, + hercules_config +#endif }; diff --git a/src/vid_hercules.h b/src/VIDEO/vid_hercules.h similarity index 100% rename from src/vid_hercules.h rename to src/VIDEO/vid_hercules.h diff --git a/src/vid_herculesplus.c b/src/VIDEO/vid_herculesplus.c similarity index 95% rename from src/vid_herculesplus.c rename to src/VIDEO/vid_herculesplus.c index 6a35c8bcf..459107d03 100644 --- a/src/vid_herculesplus.c +++ b/src/VIDEO/vid_herculesplus.c @@ -4,10 +4,11 @@ /*Hercules InColor emulation*/ #include -#include "ibm.h" -#include "device.h" -#include "mem.h" -#include "timer.h" +#include "../ibm.h" +#include "../io.h" +#include "../mem.h" +#include "../timer.h" +#include "../device.h" #include "video.h" #include "vid_herculesplus.h" @@ -171,7 +172,6 @@ static void herculesplus_draw_char_rom(herculesplus_t *herculesplus, int x, uint unsigned val; unsigned ifg, ibg; const unsigned char *fnt; - uint32_t fg, bg; int cw = HERCULESPLUS_CW; blk = 0; @@ -248,9 +248,8 @@ static void herculesplus_draw_char_ram4(herculesplus_t *herculesplus, int x, uin int elg, blk; unsigned ull; unsigned val; - unsigned ifg, ibg, cfg, pmask, plane; + unsigned ifg, ibg, cfg; const unsigned char *fnt; - uint32_t fg; int cw = HERCULESPLUS_CW; int blink = herculesplus->ctrl & HERCULESPLUS_CTRL_BLINK; @@ -318,7 +317,6 @@ static void herculesplus_draw_char_ram4(herculesplus_t *herculesplus, int x, uin { /* Generate pixel colour */ cfg = 0; - pmask = 1; /* cfg = colour of foreground pixels */ if ((attr & 0x77) == 0) cfg = ibg; /* 'blank' attribute */ @@ -332,11 +330,10 @@ static void herculesplus_draw_char_ram48(herculesplus_t *herculesplus, int x, ui { unsigned i; int elg, blk, ul, ol, bld; - unsigned ull, oll, ulc, olc; + unsigned ull, oll, ulc = 0, olc = 0; unsigned val; - unsigned ifg, ibg, cfg, pmask, plane; + unsigned ibg, cfg; const unsigned char *fnt; - uint32_t fg; int cw = HERCULESPLUS_CW; int blink = herculesplus->ctrl & HERCULESPLUS_CTRL_BLINK; int font = (attr & 0x0F); @@ -452,8 +449,8 @@ static void herculesplus_text_line(herculesplus_t *herculesplus, uint16_t ca) for (x = 0; x < herculesplus->crtc[1]; x++) { - chr = herculesplus->vram[(herculesplus->ma << 1) & 0x3fff]; - attr = herculesplus->vram[((herculesplus->ma << 1) + 1) & 0x3fff]; + chr = herculesplus->vram[(herculesplus->ma << 1) & 0xfff]; + attr = herculesplus->vram[((herculesplus->ma << 1) + 1) & 0xfff]; drawcursor = ((herculesplus->ma == ca) && herculesplus->con && herculesplus->cursoron); @@ -488,10 +485,8 @@ static void herculesplus_text_line(herculesplus_t *herculesplus, uint16_t ca) static void herculesplus_graphics_line(herculesplus_t *herculesplus) { - uint8_t mask; uint16_t ca; - int x, c, plane, col; - uint8_t ink; + int x, c, plane = 0; uint16_t val; /* Graphics mode. */ @@ -524,7 +519,6 @@ void herculesplus_poll(void *p) if (!herculesplus->linepos) { -// pclog("InColor poll %i %i\n", herculesplus->vc, herculesplus->sc); herculesplus->vidtime += herculesplus->dispofftime; herculesplus->stat |= 1; herculesplus->linepos = 1; @@ -552,7 +546,6 @@ void herculesplus_poll(void *p) if (herculesplus->vc == herculesplus->crtc[7] && !herculesplus->sc) { herculesplus->stat |= 8; -// printf("VSYNC on %i %i\n",vc,sc); } herculesplus->displine++; if (herculesplus->displine >= 500) @@ -570,7 +563,6 @@ void herculesplus_poll(void *p) if (!herculesplus->vsynctime) { herculesplus->stat &= ~8; -// printf("VSYNC off %i %i\n",vc,sc); } } if (herculesplus->sc == (herculesplus->crtc[11] & 31) || ((herculesplus->crtc[8] & 3) == 3 && herculesplus->sc == ((herculesplus->crtc[11] & 31) >> 1))) @@ -602,7 +594,6 @@ void herculesplus_poll(void *p) herculesplus->dispon = 0; if (oldvc == herculesplus->crtc[4]) { -// printf("Display over at %i\n",displine); herculesplus->vc = 0; herculesplus->vadj = herculesplus->crtc[5]; if (!herculesplus->vadj) herculesplus->dispon=1; @@ -614,10 +605,9 @@ void herculesplus_poll(void *p) { herculesplus->dispon = 0; herculesplus->displine = 0; - herculesplus->vsynctime = 16;//(crtcm[3]>>4)+1; + herculesplus->vsynctime = 16; if (herculesplus->crtc[7]) { -// printf("Lastline %i Firstline %i %i\n",lastline,firstline,lastline-firstline); if ((herculesplus->ctrl & HERCULESPLUS_CTRL_GRAPH) && (herculesplus->ctrl2 & HERCULESPLUS_CTRL2_GRAPH)) { x = herculesplus->crtc[1] << 4; @@ -631,7 +621,6 @@ void herculesplus_poll(void *p) { xsize = x; ysize = herculesplus->lastline - herculesplus->firstline; -// printf("Resize to %i,%i - R1 %i\n",xsize,ysize,crtcm[1]); if (xsize < 64) xsize = 656; if (ysize < 32) ysize = 200; updatewindowsize(xsize, ysize); @@ -665,7 +654,6 @@ void herculesplus_poll(void *p) if ((herculesplus->sc == (herculesplus->crtc[10] & 31) || ((herculesplus->crtc[8] & 3) == 3 && herculesplus->sc == ((herculesplus->crtc[10] & 31) >> 1)))) { herculesplus->con = 1; -// printf("Cursor on - %02X %02X %02X\n",crtcm[8],crtcm[10],crtcm[11]); } } } @@ -679,7 +667,7 @@ void *herculesplus_init() herculesplus->vram = malloc(0x10000); /* 64k VRAM */ timer_add(herculesplus_poll, &herculesplus->vidtime, TIMER_ALWAYS_ENABLED, herculesplus); - mem_mapping_add(&herculesplus->mapping, 0xb0000, 0x10000, herculesplus_read, NULL, NULL, herculesplus_write, NULL, NULL, NULL, 0, herculesplus); + mem_mapping_add(&herculesplus->mapping, 0xb0000, 0x10000, herculesplus_read, NULL, NULL, herculesplus_write, NULL, NULL, NULL, MEM_MAPPING_EXTERNAL, herculesplus); io_sethandler(0x03b0, 0x0010, herculesplus_in, NULL, NULL, herculesplus_out, NULL, NULL, herculesplus); for (c = 0; c < 256; c++) diff --git a/src/vid_herculesplus.h b/src/VIDEO/vid_herculesplus.h similarity index 100% rename from src/vid_herculesplus.h rename to src/VIDEO/vid_herculesplus.h diff --git a/src/vid_icd2061.c b/src/VIDEO/vid_icd2061.c similarity index 78% rename from src/vid_icd2061.c rename to src/VIDEO/vid_icd2061.c index 8b57e5bb7..04c2db166 100644 --- a/src/vid_icd2061.c +++ b/src/VIDEO/vid_icd2061.c @@ -5,15 +5,15 @@ ICD2061 clock generator emulation Used by ET4000w32/p (Diamond Stealth 32)*/ -#include "ibm.h" +#include "../ibm.h" #include "vid_icd2061.h" + void icd2061_write(icd2061_t *icd2061, int val) { - int q, p, m, i, a; + int q, p, m, a; if ((val & 1) && !(icd2061->state & 1)) { - // pclog("ICD2061 write %02X %i %08X %i\n", val, icd2061->unlock, icd2061->data, icd2061->pos); if (!icd2061->status) { if (val & 2) @@ -35,24 +35,19 @@ void icd2061_write(icd2061_t *icd2061, int val) icd2061->pos++; if (icd2061->pos == 26) { - // pclog("ICD2061 data - %08X\n", icd2061->data); a = (icd2061->data >> 21) & 0x7; if (!(a & 4)) { q = (icd2061->data & 0x7f) - 2; m = 1 << ((icd2061->data >> 7) & 0x7); p = ((icd2061->data >> 10) & 0x7f) - 3; - i = (icd2061->data >> 17) & 0xf; - // pclog("p %i q %i m %i\n", p, q, m); if (icd2061->ctrl & (1 << a)) p <<= 1; icd2061->freq[a] = ((double)p / (double)q) * 2.0 * 14318184.0 / (double)m; - // pclog("ICD2061 freq %i = %f\n", a, icd2061->freq[a]); } else if (a == 6) { icd2061->ctrl = val; - // pclog("ICD2061 ctrl = %08X\n", val); } icd2061->unlock = icd2061->data = 0; icd2061->status = 0; @@ -64,6 +59,5 @@ void icd2061_write(icd2061_t *icd2061, int val) double icd2061_getfreq(icd2061_t *icd2061, int i) { - // pclog("Return freq %f\n", icd2061->freq[i]); return icd2061->freq[i]; } diff --git a/src/vid_icd2061.h b/src/VIDEO/vid_icd2061.h similarity index 100% rename from src/vid_icd2061.h rename to src/VIDEO/vid_icd2061.h diff --git a/src/vid_ics2595.c b/src/VIDEO/vid_ics2595.c similarity index 83% rename from src/vid_ics2595.c rename to src/VIDEO/vid_ics2595.c index 024cacd93..ffe6f504c 100644 --- a/src/vid_ics2595.c +++ b/src/VIDEO/vid_ics2595.c @@ -3,10 +3,10 @@ */ /*ICS2595 clock chip emulation Used by ATI Mach64*/ - -#include "ibm.h" +#include "../ibm.h" #include "vid_ics2595.h" + enum { ICS2595_IDLE = 0, @@ -14,16 +14,16 @@ enum ICS2595_READ }; + static int ics2595_div[4] = {8, 4, 2, 1}; + void ics2595_write(ics2595_t *ics2595, int strobe, int dat) { -// pclog("ics2595_write : %i %i\n", strobe, dat); if (strobe) { if ((dat & 8) && !ics2595->oldfs3) /*Data clock*/ { -// pclog(" - new dat %i\n", dat & 4); switch (ics2595->state) { case ICS2595_IDLE: @@ -38,13 +38,11 @@ void ics2595_write(ics2595_t *ics2595, int strobe, int dat) if (ics2595->pos == 20) { int d, n, l; -// pclog("ICS2595_WRITE : dat %08X\n", ics2595->dat); l = (ics2595->dat >> 2) & 0xf; n = ((ics2595->dat >> 7) & 255) + 257; d = ics2595_div[(ics2595->dat >> 16) & 3]; ics2595->clocks[l] = (14318181.8 * ((double)n / 46.0)) / (double)d; -// pclog("ICS2595 clock set - L %i N %i D %i freq = %f\n", l, n, d, (14318181.8 * ((double)n / 46.0)) / (double)d); ics2595->state = ICS2595_IDLE; } break; diff --git a/src/vid_ics2595.h b/src/VIDEO/vid_ics2595.h similarity index 100% rename from src/vid_ics2595.h rename to src/VIDEO/vid_ics2595.h diff --git a/src/vid_incolor.c b/src/VIDEO/vid_incolor.c similarity index 88% rename from src/vid_incolor.c rename to src/VIDEO/vid_incolor.c index df81b1636..636697c1a 100644 --- a/src/vid_incolor.c +++ b/src/VIDEO/vid_incolor.c @@ -2,12 +2,12 @@ see COPYING for more details */ /*Hercules InColor emulation*/ - #include -#include "ibm.h" -#include "device.h" -#include "mem.h" -#include "timer.h" +#include "../ibm.h" +#include "../io.h" +#include "../mem.h" +#include "../timer.h" +#include "../device.h" #include "video.h" #include "vid_incolor.h" @@ -72,71 +72,71 @@ static uint32_t incolor_rgb[64]; /* Mapping of inks to RGB */ static unsigned char init_rgb[64][3] = { - // rgbRGB - { 0x00, 0x00, 0x00 }, // 000000 - { 0x00, 0x00, 0xaa }, // 000001 - { 0x00, 0xaa, 0x00 }, // 000010 - { 0x00, 0xaa, 0xaa }, // 000011 - { 0xaa, 0x00, 0x00 }, // 000100 - { 0xaa, 0x00, 0xaa }, // 000101 - { 0xaa, 0xaa, 0x00 }, // 000110 - { 0xaa, 0xaa, 0xaa }, // 000111 - { 0x00, 0x00, 0x55 }, // 001000 - { 0x00, 0x00, 0xff }, // 001001 - { 0x00, 0xaa, 0x55 }, // 001010 - { 0x00, 0xaa, 0xff }, // 001011 - { 0xaa, 0x00, 0x55 }, // 001100 - { 0xaa, 0x00, 0xff }, // 001101 - { 0xaa, 0xaa, 0x55 }, // 001110 - { 0xaa, 0xaa, 0xff }, // 001111 - { 0x00, 0x55, 0x00 }, // 010000 - { 0x00, 0x55, 0xaa }, // 010001 - { 0x00, 0xff, 0x00 }, // 010010 - { 0x00, 0xff, 0xaa }, // 010011 - { 0xaa, 0x55, 0x00 }, // 010100 - { 0xaa, 0x55, 0xaa }, // 010101 - { 0xaa, 0xff, 0x00 }, // 010110 - { 0xaa, 0xff, 0xaa }, // 010111 - { 0x00, 0x55, 0x55 }, // 011000 - { 0x00, 0x55, 0xff }, // 011001 - { 0x00, 0xff, 0x55 }, // 011010 - { 0x00, 0xff, 0xff }, // 011011 - { 0xaa, 0x55, 0x55 }, // 011100 - { 0xaa, 0x55, 0xff }, // 011101 - { 0xaa, 0xff, 0x55 }, // 011110 - { 0xaa, 0xff, 0xff }, // 011111 - { 0x55, 0x00, 0x00 }, // 100000 - { 0x55, 0x00, 0xaa }, // 100001 - { 0x55, 0xaa, 0x00 }, // 100010 - { 0x55, 0xaa, 0xaa }, // 100011 - { 0xff, 0x00, 0x00 }, // 100100 - { 0xff, 0x00, 0xaa }, // 100101 - { 0xff, 0xaa, 0x00 }, // 100110 - { 0xff, 0xaa, 0xaa }, // 100111 - { 0x55, 0x00, 0x55 }, // 101000 - { 0x55, 0x00, 0xff }, // 101001 - { 0x55, 0xaa, 0x55 }, // 101010 - { 0x55, 0xaa, 0xff }, // 101011 - { 0xff, 0x00, 0x55 }, // 101100 - { 0xff, 0x00, 0xff }, // 101101 - { 0xff, 0xaa, 0x55 }, // 101110 - { 0xff, 0xaa, 0xff }, // 101111 - { 0x55, 0x55, 0x00 }, // 110000 - { 0x55, 0x55, 0xaa }, // 110001 - { 0x55, 0xff, 0x00 }, // 110010 - { 0x55, 0xff, 0xaa }, // 110011 - { 0xff, 0x55, 0x00 }, // 110100 - { 0xff, 0x55, 0xaa }, // 110101 - { 0xff, 0xff, 0x00 }, // 110110 - { 0xff, 0xff, 0xaa }, // 110111 - { 0x55, 0x55, 0x55 }, // 111000 - { 0x55, 0x55, 0xff }, // 111001 - { 0x55, 0xff, 0x55 }, // 111010 - { 0x55, 0xff, 0xff }, // 111011 - { 0xff, 0x55, 0x55 }, // 111100 - { 0xff, 0x55, 0xff }, // 111101 - { 0xff, 0xff, 0x55 }, // 111110 - { 0xff, 0xff, 0xff }, // 111111 + /* rgbRGB */ + { 0x00, 0x00, 0x00 }, /* 000000 */ + { 0x00, 0x00, 0xaa }, /* 000001 */ + { 0x00, 0xaa, 0x00 }, /* 000010 */ + { 0x00, 0xaa, 0xaa }, /* 000011 */ + { 0xaa, 0x00, 0x00 }, /* 000100 */ + { 0xaa, 0x00, 0xaa }, /* 000101 */ + { 0xaa, 0xaa, 0x00 }, /* 000110 */ + { 0xaa, 0xaa, 0xaa }, /* 000111 */ + { 0x00, 0x00, 0x55 }, /* 001000 */ + { 0x00, 0x00, 0xff }, /* 001001 */ + { 0x00, 0xaa, 0x55 }, /* 001010 */ + { 0x00, 0xaa, 0xff }, /* 001011 */ + { 0xaa, 0x00, 0x55 }, /* 001100 */ + { 0xaa, 0x00, 0xff }, /* 001101 */ + { 0xaa, 0xaa, 0x55 }, /* 001110 */ + { 0xaa, 0xaa, 0xff }, /* 001111 */ + { 0x00, 0x55, 0x00 }, /* 010000 */ + { 0x00, 0x55, 0xaa }, /* 010001 */ + { 0x00, 0xff, 0x00 }, /* 010010 */ + { 0x00, 0xff, 0xaa }, /* 010011 */ + { 0xaa, 0x55, 0x00 }, /* 010100 */ + { 0xaa, 0x55, 0xaa }, /* 010101 */ + { 0xaa, 0xff, 0x00 }, /* 010110 */ + { 0xaa, 0xff, 0xaa }, /* 010111 */ + { 0x00, 0x55, 0x55 }, /* 011000 */ + { 0x00, 0x55, 0xff }, /* 011001 */ + { 0x00, 0xff, 0x55 }, /* 011010 */ + { 0x00, 0xff, 0xff }, /* 011011 */ + { 0xaa, 0x55, 0x55 }, /* 011100 */ + { 0xaa, 0x55, 0xff }, /* 011101 */ + { 0xaa, 0xff, 0x55 }, /* 011110 */ + { 0xaa, 0xff, 0xff }, /* 011111 */ + { 0x55, 0x00, 0x00 }, /* 100000 */ + { 0x55, 0x00, 0xaa }, /* 100001 */ + { 0x55, 0xaa, 0x00 }, /* 100010 */ + { 0x55, 0xaa, 0xaa }, /* 100011 */ + { 0xff, 0x00, 0x00 }, /* 100100 */ + { 0xff, 0x00, 0xaa }, /* 100101 */ + { 0xff, 0xaa, 0x00 }, /* 100110 */ + { 0xff, 0xaa, 0xaa }, /* 100111 */ + { 0x55, 0x00, 0x55 }, /* 101000 */ + { 0x55, 0x00, 0xff }, /* 101001 */ + { 0x55, 0xaa, 0x55 }, /* 101010 */ + { 0x55, 0xaa, 0xff }, /* 101011 */ + { 0xff, 0x00, 0x55 }, /* 101100 */ + { 0xff, 0x00, 0xff }, /* 101101 */ + { 0xff, 0xaa, 0x55 }, /* 101110 */ + { 0xff, 0xaa, 0xff }, /* 101111 */ + { 0x55, 0x55, 0x00 }, /* 110000 */ + { 0x55, 0x55, 0xaa }, /* 110001 */ + { 0x55, 0xff, 0x00 }, /* 110010 */ + { 0x55, 0xff, 0xaa }, /* 110011 */ + { 0xff, 0x55, 0x00 }, /* 110100 */ + { 0xff, 0x55, 0xaa }, /* 110101 */ + { 0xff, 0xff, 0x00 }, /* 110110 */ + { 0xff, 0xff, 0xaa }, /* 110111 */ + { 0x55, 0x55, 0x55 }, /* 111000 */ + { 0x55, 0x55, 0xff }, /* 111001 */ + { 0x55, 0xff, 0x55 }, /* 111010 */ + { 0x55, 0xff, 0xff }, /* 111011 */ + { 0xff, 0x55, 0x55 }, /* 111100 */ + { 0xff, 0x55, 0xff }, /* 111101 */ + { 0xff, 0xff, 0x55 }, /* 111110 */ + { 0xff, 0xff, 0xff }, /* 111111 */ }; @@ -240,7 +240,7 @@ void incolor_write(uint32_t addr, uint8_t val, void *p) unsigned char wmode = incolor->crtc[INCOLOR_CRTC_RWCTRL] & INCOLOR_RWCTRL_WRMODE; unsigned char fg = incolor->crtc[INCOLOR_CRTC_RWCOL] & 0x0F; unsigned char bg = (incolor->crtc[INCOLOR_CRTC_RWCOL] >> 4)&0x0F; - unsigned char w; + unsigned char w = 0; unsigned char vmask; /* Mask of bit within byte */ unsigned char pmask; /* Mask of plane within colour value */ unsigned char latch; @@ -596,9 +596,9 @@ static void incolor_draw_char_ram48(incolor_t *incolor, int x, uint8_t chr, uint { unsigned i; int elg, blk, ul, ol, bld; - unsigned ull, oll, ulc, olc; + unsigned ull, oll, ulc = 0, olc = 0; unsigned val[4]; - unsigned ifg, ibg, cfg, pmask, plane; + unsigned ifg = 0, ibg, cfg, pmask, plane; const unsigned char *fnt; uint32_t fg; int cw = INCOLOR_CW; @@ -764,8 +764,8 @@ static void incolor_text_line(incolor_t *incolor, uint16_t ca) for (x = 0; x < incolor->crtc[1]; x++) { - chr = incolor->vram[(incolor->ma << 1) & 0x3fff]; - attr = incolor->vram[((incolor->ma << 1) + 1) & 0x3fff]; + chr = incolor->vram[(incolor->ma << 1) & 0xfff]; + attr = incolor->vram[((incolor->ma << 1) + 1) & 0xfff]; drawcursor = ((incolor->ma == ca) && incolor->con && incolor->cursoron); @@ -866,7 +866,6 @@ void incolor_poll(void *p) if (!incolor->linepos) { -// pclog("InColor poll %i %i\n", incolor->vc, incolor->sc); incolor->vidtime += incolor->dispofftime; incolor->stat |= 1; incolor->linepos = 1; @@ -894,7 +893,6 @@ void incolor_poll(void *p) if (incolor->vc == incolor->crtc[7] && !incolor->sc) { incolor->stat |= 8; -// printf("VSYNC on %i %i\n",vc,sc); } incolor->displine++; if (incolor->displine >= 500) @@ -912,7 +910,6 @@ void incolor_poll(void *p) if (!incolor->vsynctime) { incolor->stat &= ~8; -// printf("VSYNC off %i %i\n",vc,sc); } } if (incolor->sc == (incolor->crtc[11] & 31) || ((incolor->crtc[8] & 3) == 3 && incolor->sc == ((incolor->crtc[11] & 31) >> 1))) @@ -944,7 +941,6 @@ void incolor_poll(void *p) incolor->dispon = 0; if (oldvc == incolor->crtc[4]) { -// printf("Display over at %i\n",displine); incolor->vc = 0; incolor->vadj = incolor->crtc[5]; if (!incolor->vadj) incolor->dispon=1; @@ -956,10 +952,9 @@ void incolor_poll(void *p) { incolor->dispon = 0; incolor->displine = 0; - incolor->vsynctime = 16;//(crtcm[3]>>4)+1; + incolor->vsynctime = 16; if (incolor->crtc[7]) { -// printf("Lastline %i Firstline %i %i\n",lastline,firstline,lastline-firstline); if ((incolor->ctrl & INCOLOR_CTRL_GRAPH) && (incolor->ctrl2 & INCOLOR_CTRL2_GRAPH)) { x = incolor->crtc[1] << 4; @@ -973,7 +968,6 @@ void incolor_poll(void *p) { xsize = x; ysize = incolor->lastline - incolor->firstline; -// printf("Resize to %i,%i - R1 %i\n",xsize,ysize,crtcm[1]); if (xsize < 64) xsize = 656; if (ysize < 32) ysize = 200; updatewindowsize(xsize, ysize); @@ -1007,7 +1001,6 @@ void incolor_poll(void *p) if ((incolor->sc == (incolor->crtc[10] & 31) || ((incolor->crtc[8] & 3) == 3 && incolor->sc == ((incolor->crtc[10] & 31) >> 1)))) { incolor->con = 1; -// printf("Cursor on - %02X %02X %02X\n",crtcm[8],crtcm[10],crtcm[11]); } } } @@ -1021,7 +1014,7 @@ void *incolor_init() incolor->vram = malloc(0x40000); /* 4 planes of 64k */ timer_add(incolor_poll, &incolor->vidtime, TIMER_ALWAYS_ENABLED, incolor); - mem_mapping_add(&incolor->mapping, 0xb0000, 0x08000, incolor_read, NULL, NULL, incolor_write, NULL, NULL, NULL, 0, incolor); + mem_mapping_add(&incolor->mapping, 0xb0000, 0x08000, incolor_read, NULL, NULL, incolor_write, NULL, NULL, NULL, MEM_MAPPING_EXTERNAL, incolor); io_sethandler(0x03b0, 0x0010, incolor_in, NULL, NULL, incolor_out, NULL, NULL, incolor); for (c = 0; c < 64; c++) diff --git a/src/vid_incolor.h b/src/VIDEO/vid_incolor.h similarity index 100% rename from src/vid_incolor.h rename to src/VIDEO/vid_incolor.h diff --git a/src/vid_mda.c b/src/VIDEO/vid_mda.c similarity index 90% rename from src/vid_mda.c rename to src/VIDEO/vid_mda.c index 41461331a..d9e254b3a 100644 --- a/src/vid_mda.c +++ b/src/VIDEO/vid_mda.c @@ -3,13 +3,17 @@ */ /*MDA emulation*/ #include -#include "ibm.h" -#include "device.h" -#include "io.h" -#include "mem.h" -#include "timer.h" +#include "../ibm.h" +#include "../io.h" +#include "../mem.h" +#include "../timer.h" +#include "../device.h" #include "video.h" #include "vid_mda.h" +#ifndef __unix +# include "../win/win_cgapal.h" /*YUCK*/ +#endif + typedef struct mda_t { @@ -114,7 +118,6 @@ void mda_poll(void *p) int x, c; int oldvc; uint8_t chr, attr; - int cols[4]; int oldsc; int blink; if (!mda->linepos) @@ -132,12 +135,10 @@ void mda_poll(void *p) mda->firstline = mda->displine; } mda->lastline = mda->displine; - cols[0] = 0; - cols[1] = 7; for (x = 0; x < mda->crtc[1]; x++) { - chr = mda->vram[(mda->ma << 1) & 0x3fff]; - attr = mda->vram[((mda->ma << 1) + 1) & 0x3fff]; + chr = mda->vram[(mda->ma << 1) & 0xfff]; + attr = mda->vram[((mda->ma << 1) + 1) & 0xfff]; drawcursor = ((mda->ma == ca) && mda->con && mda->cursoron); blink = ((mda->blink & 16) && (mda->ctrl & 0x20) && (attr & 0x80) && !drawcursor); if (mda->sc == 12 && ((attr & 7) == 1)) @@ -164,7 +165,6 @@ void mda_poll(void *p) if (mda->vc == mda->crtc[7] && !mda->sc) { mda->stat |= 8; -// printf("VSYNC on %i %i\n",vc,sc); } mda->displine++; if (mda->displine >= 500) @@ -181,7 +181,6 @@ void mda_poll(void *p) if (!mda->vsynctime) { mda->stat&=~8; -// printf("VSYNC off %i %i\n",vc,sc); } } if (mda->sc == (mda->crtc[11] & 31) || ((mda->crtc[8] & 3) == 3 && mda->sc == ((mda->crtc[11] & 31) >> 1))) @@ -213,7 +212,6 @@ void mda_poll(void *p) mda->dispon=0; if (oldvc == mda->crtc[4]) { -// printf("Display over at %i\n",displine); mda->vc = 0; mda->vadj = mda->crtc[5]; if (!mda->vadj) mda->dispon = 1; @@ -228,14 +226,12 @@ void mda_poll(void *p) mda->vsynctime = 16; if (mda->crtc[7]) { -// printf("Lastline %i Firstline %i %i\n",lastline,firstline,lastline-firstline); x = mda->crtc[1] * 9; mda->lastline++; if (x != xsize || (mda->lastline - mda->firstline) != ysize) { xsize = x; ysize = mda->lastline - mda->firstline; -// printf("Resize to %i,%i - R1 %i\n",xsize,ysize,crtcm[1]); if (xsize < 64) xsize = 656; if (ysize < 32) ysize = 200; updatewindowsize(xsize, ysize); @@ -260,7 +256,6 @@ void mda_poll(void *p) if ((mda->sc == (mda->crtc[10] & 31) || ((mda->crtc[8] & 3) == 3 && mda->sc == ((mda->crtc[10] & 31) >> 1)))) { mda->con = 1; -// printf("Cursor on - %02X %02X %02X\n",crtcm[8],crtcm[10],crtcm[11]); } } } @@ -274,7 +269,7 @@ void *mda_init() mda->vram = malloc(0x1000); timer_add(mda_poll, &mda->vidtime, TIMER_ALWAYS_ENABLED, mda); - mem_mapping_add(&mda->mapping, 0xb0000, 0x08000, mda_read, NULL, NULL, mda_write, NULL, NULL, NULL, 0, mda); + mem_mapping_add(&mda->mapping, 0xb0000, 0x08000, mda_read, NULL, NULL, mda_write, NULL, NULL, NULL, MEM_MAPPING_EXTERNAL, mda); io_sethandler(0x03b0, 0x0010, mda_in, NULL, NULL, mda_out, NULL, NULL, mda); for (c = 0; c < 256; c++) @@ -298,6 +293,15 @@ void *mda_init() overscan_x = overscan_y = 0; +#ifndef __unix + cga_palette = device_get_config_int("rgb_type") << 1; + if (cga_palette > 6) + { + cga_palette = 0; + } + cgapal_rebuild(); +#endif + return mda; } @@ -316,6 +320,35 @@ void mda_speed_changed(void *p) mda_recalctimings(mda); } +#ifndef __unix +static device_config_t mda_config[] = +{ + { + "rgb_type", "Display type", CONFIG_SELECTION, "", 0, + { + { + "Default", 0 + }, + { + "Green", 1 + }, + { + "Amber", 2 + }, + { + "Gray", 3 + }, + { + "" + } + } + }, + { + "", "", -1 + } +}; +#endif + device_t mda_device = { "MDA", @@ -325,5 +358,10 @@ device_t mda_device = NULL, mda_speed_changed, NULL, +#ifdef __unix NULL +#else + NULL, + mda_config +#endif }; diff --git a/src/vid_mda.h b/src/VIDEO/vid_mda.h similarity index 100% rename from src/vid_mda.h rename to src/VIDEO/vid_mda.h diff --git a/src/VIDEO/vid_nv_riva128.c b/src/VIDEO/vid_nv_riva128.c new file mode 100644 index 000000000..c5b61a3e6 --- /dev/null +++ b/src/VIDEO/vid_nv_riva128.c @@ -0,0 +1,3427 @@ +/* Copyright holders: Melissa Goad, Tenshi + see COPYING for more details +*/ +/*nVidia RIVA 128 emulation*/ +#include +#include "../ibm.h" +#include "../io.h" +#include "../mem.h" +#include "../pci.h" +#include "../pic.h" +#include "../rom.h" +#include "../timer.h" +#include "../device.h" +#include "../win/plat_thread.h" +#include "video.h" +#include "vid_nv_riva128.h" +#include "vid_svga.h" +#include "vid_svga_render.h" + + +typedef struct riva128_t +{ + mem_mapping_t linear_mapping; + mem_mapping_t ramin_mapping; + mem_mapping_t mmio_mapping; + + rom_t bios_rom; + + svga_t svga; + + uint8_t card_id; + int is_nv3t; + + uint16_t vendor_id; + uint16_t device_id; + + uint32_t linear_base, linear_size; + + uint16_t rma_addr; + + uint8_t pci_regs[256]; + + int memory_size; + + uint8_t ext_regs_locked; + + uint8_t read_bank; + uint8_t write_bank; + + struct + { + uint32_t intr; + uint32_t intr_en; + uint32_t intr_line; + uint32_t enable; + } pmc; + + struct + { + uint32_t intr; + uint32_t intr_en; + } pbus; + + struct + { + uint32_t intr; + uint32_t intr_en; + + uint32_t ramht; + uint32_t ramht_addr; + uint32_t ramht_size; + + uint32_t ramfc; + uint32_t ramfc_addr; + + uint32_t ramro; + uint32_t ramro_addr; + uint32_t ramro_size; + + uint16_t chan_mode; + uint16_t chan_dma; + uint16_t chan_size; //0 = 1024, 1 = 512 + + struct + { + uint32_t dmaput; + uint32_t dmaget; + } channels[16]; + + struct + { + int chanid; + int push_enabled; + } caches[2]; + + struct + { + int subchan; + uint16_t method; + uint32_t param; + } cache0, cache1[64]; + } pfifo; + + struct + { + uint32_t addr; + uint32_t data; + uint8_t access_reg[4]; + uint8_t mode; + } rma; + + struct + { + uint32_t intr, intr_en; + + uint64_t time; + uint32_t alarm; + + uint16_t clock_mul, clock_div; + } ptimer; + + struct + { + int width; + int bpp; + uint32_t config_0; + } pfb; + + struct + { + uint32_t boot0; + } pextdev; + + struct + { + int pgraph_speedhack; + + uint32_t obj_handle[8]; + uint16_t obj_class[8]; + + uint32_t debug[5]; + + uint32_t intr; + uint32_t intr_en; + + uint32_t invalid; + uint32_t invalid_en; + + uint32_t ctx_switch[5]; + uint32_t ctx_control; + uint32_t ctx_user; + uint32_t ctx_cache[8][5]; + + uint32_t fifo_enable; + + uint32_t fifo_st2_addr; + uint32_t fifo_st2_data; + + uint32_t uclip_xmin, uclip_ymin, uclip_xmax, uclip_ymax; + uint32_t oclip_xmin, oclip_ymin, oclip_xmax, oclip_ymax; + + uint32_t src_canvas_min, src_canvas_max; + uint32_t dst_canvas_min, dst_canvas_max; + + uint8_t rop; + + uint32_t chroma; + + uint32_t beta; + + uint32_t notify; + + uint32_t surf_base[6]; + uint32_t surf_limit[6]; + + uint32_t cliprect_min[2]; + uint32_t cliprect_max[2]; + uint32_t cliprect_ctrl; + + uint32_t instance; + + uint32_t dma_intr, dma_intr_en; + + struct + { + uint32_t point_color; + int32_t point_x[0x20], point_y[0x20]; + } speedhack; + } pgraph; + + struct + { + uint32_t nvpll; + uint32_t nv_m,nv_n,nv_p; + + uint32_t mpll; + uint32_t m_m,m_n,m_p; + + uint32_t vpll; + uint32_t v_m,v_n,v_p; + + uint32_t pll_ctrl; + + uint32_t gen_ctrl; + } pramdac; + + uint32_t pramin[0x80000]; + + uint32_t channels[16][8][0x2000]; + + struct + { + int scl; + int sda; + uint8_t addr; //actually 7 bits + uint8_t data; + } i2c; + + int mtime, mfreq; + int nvtime, nvfreq; +} riva128_t; + +//Internally, the RIVA 128 operates in a weird 38-bit color depth, with 10 bits for RGB, and 8 bits for alpha, according to envytools. +typedef struct +{ + uint8_t a; + unsigned r : 10; + unsigned g : 10; + unsigned b : 10; +} riva128_color_t; + +const char* riva128_pmc_interrupts[32] = +{ + "","","","","PMEDIA","","","","PFIFO","","","","PGRAPH","","","","PRAMDAC.VIDEO","","","","PTIMER","","","","PCRTC","","","","PBUS","","","" +}; + +const char* riva128_pbus_interrupts[32] = +{ + "BUS_ERROR","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +}; + +const char* riva128_pfifo_interrupts[32] = +{ + "CACHE_ERROR","","","","RUNOUT","","","","RUNOUT_OVERFLOW","","","","DMA_PUSHER","","","","DMA_PTE","","","","","","","","","","","","","","","" +}; + +static uint32_t riva128_ramht_lookup(uint32_t handle, void *p); +//static void riva128_pgraph_volatile_reset(void *p); + +static uint8_t riva128_pci_read(int func, int addr, void *p); +static void riva128_pci_write(int func, int addr, uint8_t val, void *p); + +static uint8_t riva128_in(uint16_t addr, void *p); +static void riva128_out(uint16_t addr, uint8_t val, void *p); + +static void riva128_mmio_write_l(uint32_t addr, uint32_t val, void *p); + +/*static riva128_color_t riva128_pgraph_expand_color(uint32_t ctx, uint32_t color) +{ + riva128_color_t ret; + int format = ctx & 7; + int alpha_enable = (ctx >> 3) & 1; + + switch(format) + { + default: + pclog("RIVA 128 Unknown color format %i found!\n", format); + ret.a = 0x0; + break; + case 0: + ret.a = ((color >> 15) & 1) * 0xff; + ret.r = ((color >> 10) & 0x1f) << 5; + ret.g = ((color >> 5) & 0x1f) << 5; + ret.b = ((color >> 0) & 0x1f) << 5; + break; + case 1: + ret.a = ((color >> 24) & 0xff); + ret.r = ((color >> 16) & 0xff) << 2; + ret.g = ((color >> 8) & 0xff) << 2; + ret.b = ((color >> 0) & 0xff) << 2; + break; + case 2: + ret.a = ((color >> 30) & 3) * 0x55; + ret.r = ((color >> 20) & 0x3ff); + ret.g = ((color >> 10) & 0x3ff); + ret.b = ((color >> 0) & 0x3ff); + break; + case 3: + ret.a = ((color >> 8) & 0xff); + ret.r = ret.g = ret.b = ((color >> 0) & 0xff) << 2; + break; + case 4: + ret.a = ((color >> 16) & 0xffff) >> 8; + ret.r = ret.g = ret.b = ((color >> 0) & 0xffff) >> 6; + break; + } + + if(!alpha_enable) ret.a = 0xff; + + return ret; +} + +static uint32_t riva128_pgraph_blend_factor(uint32_t alpha, uint32_t beta) +{ + if(beta == 0xff) return alpha; + if(alpha == 0xff) return beta; + alpha >>= 4; + beta >>= 3; + return (alpha * beta) >> 1; +} + +static uint32_t riva128_pgraph_do_blend(uint32_t factor, uint32_t dst, uint32_t src, int is_r5g5b5) +{ + factor &= 0xf8; + if(factor == 0xf8) return src; + if(!factor) return dst; + src >>= 2; + dst >>= 2; + if(is_r5g5b5) + { + src &= 0xf8; + dst &= 0xf8; + } + return ((dst * (0x100 - factor)) + (src * factor)) >> 6; +}*/ + +static uint8_t riva128_pmc_read(uint32_t addr, void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + uint8_t ret = 0; + + //pclog("RIVA 128 PMC read %08X %04X:%08X\n", addr, CS, cpu_state.pc); + + if(riva128->card_id == 0x03) switch(addr) + { + case 0x000000: + ret = 0x10; + break; + case 0x000001: + ret = 0x01; + break; + case 0x000002: + ret = 0x03; + break; + case 0x000003: + ret = 0x00; + break; + } + else if(riva128->card_id == 0x04) switch(addr) + { + case 0x000000: + ret = 0x00; + break; + case 0x000001: + ret = 0x40; + break; + case 0x000002: + ret = 0x00; + break; + case 0x000003: + ret = 0x00; + break; + } + else if(riva128->card_id == 0x05) switch(addr) + { + case 0x000000: + ret = 0x00; + break; + case 0x000001: + ret = 0x40; + break; + case 0x000002: + ret = 0x10; + break; + case 0x000003: + ret = 0x00; + break; + } + switch(addr) + { + case 0x000100: + ret = riva128->pmc.intr & 0xff; + break; + case 0x000101: + ret = (riva128->pmc.intr >> 8) & 0xff; + break; + case 0x000102: + ret = (riva128->pmc.intr >> 16) & 0xff; + break; + case 0x000103: + ret = (riva128->pmc.intr >> 24) & 0xff; + break; + case 0x000140: + ret = riva128->pmc.intr & 0xff; + break; + case 0x000141: + ret = (riva128->pmc.intr_en >> 8) & 0xff; + break; + case 0x000142: + ret = (riva128->pmc.intr_en >> 16) & 0xff; + break; + case 0x000143: + ret = (riva128->pmc.intr_en >> 24) & 0xff; + break; + case 0x000160: + ret = riva128->pmc.intr_line & 0xff; + break; + case 0x000161: + ret = (riva128->pmc.intr_line >> 8) & 0xff; + break; + case 0x000162: + ret = (riva128->pmc.intr_line >> 16) & 0xff; + break; + case 0x000163: + ret = (riva128->pmc.intr_line >> 24) & 0xff; + break; + case 0x000200: + ret = riva128->pmc.enable & 0xff; + break; + case 0x000201: + ret = (riva128->pmc.enable >> 8) & 0xff; + break; + case 0x000202: + ret = (riva128->pmc.enable >> 16) & 0xff; + break; + case 0x000203: + ret = (riva128->pmc.enable >> 24) & 0xff; + break; + } + + return ret; +} + +static void riva128_pmc_write(uint32_t addr, uint32_t val, void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + //pclog("RIVA 128 PMC write %08X %08X %04X:%08X\n", addr, val, CS, cpu_state.pc); + + switch(addr) + { + case 0x000100: + riva128->pmc.intr &= ~val; + break; + case 0x000140: + riva128->pmc.intr_en = val & 3; + break; + case 0x000200: + riva128->pmc.enable = val; + break; + } +} + +static void riva128_pmc_interrupt(int num, void *p) +{ + //pclog("RIVA 128 PMC interrupt #%d fired!\n", num); + riva128_t *riva128 = (riva128_t *)p; + + riva128->pmc.intr |= (1 << num); + + if(riva128->pmc.intr_en & 1) picint(1 << riva128->pci_regs[0x3c]); +} + +static uint8_t riva128_pbus_read(uint32_t addr, void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + uint8_t ret = 0; + + //pclog("RIVA 128 PBUS read %08X %04X:%08X\n", addr, CS, cpu_state.pc); + + switch(addr) + { + case 0x001100: + ret = riva128->pbus.intr & 0xff; + break; + case 0x001101: + ret = (riva128->pbus.intr >> 8) & 0xff; + break; + case 0x001102: + ret = (riva128->pbus.intr >> 16) & 0xff; + break; + case 0x001103: + ret = (riva128->pbus.intr >> 24) & 0xff; + break; + case 0x001140: + ret = riva128->pbus.intr & 0xff; + break; + case 0x001141: + ret = (riva128->pbus.intr_en >> 8) & 0xff; + break; + case 0x001142: + ret = (riva128->pbus.intr_en >> 16) & 0xff; + break; + case 0x001143: + ret = (riva128->pbus.intr_en >> 24) & 0xff; + break; + } + + if((addr >= 0x001800) && (addr <= 0x0018ff)) ret = riva128_pci_read(0, addr - 0x1800, riva128); + + return ret; +} + +static void riva128_pbus_write(uint32_t addr, uint32_t val, void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + //pclog("RIVA 128 PBUS write %08X %08X %04X:%08X\n", addr, val, CS, cpu_state.pc); + + switch(addr) + { + case 0x001100: + riva128->pbus.intr &= ~val; + break; + case 0x001140: + riva128->pbus.intr_en = val; + break; + } + + if((addr >= 0x001800) && (addr <= 0x0018ff)) + { + riva128_pci_write(0, (addr & 0xfc) + 0, (val >> 0) & 0xff, riva128); + riva128_pci_write(0, (addr & 0xfc) + 1, (val >> 8) & 0xff, riva128); + riva128_pci_write(0, (addr & 0xfc) + 2, (val >> 16) & 0xff, riva128); + riva128_pci_write(0, (addr & 0xfc) + 3, (val >> 24) & 0xff, riva128); + } +} + +static uint8_t riva128_pfifo_read(uint32_t addr, void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + uint8_t ret = 0; + + // pclog("RIVA 128 PFIFO read %08X %04X:%08X\n", addr, CS, cpu_state.pc); + + switch(addr) + { + case 0x002100: + ret = riva128->pfifo.intr & 0xff; + break; + case 0x002101: + ret = (riva128->pfifo.intr >> 8) & 0xff; + break; + case 0x002102: + ret = (riva128->pfifo.intr >> 16) & 0xff; + break; + case 0x002103: + ret = (riva128->pfifo.intr >> 24) & 0xff; + break; + case 0x002140: + ret = riva128->pfifo.intr_en & 0xff; + break; + case 0x002141: + ret = (riva128->pfifo.intr_en >> 8) & 0xff; + break; + case 0x002142: + ret = (riva128->pfifo.intr_en >> 16) & 0xff; + break; + case 0x002143: + ret = (riva128->pfifo.intr_en >> 24) & 0xff; + break; + case 0x002210: + ret = riva128->pfifo.ramht & 0xff; + break; + case 0x002211: + ret = (riva128->pfifo.ramht >> 8) & 0xff; + break; + case 0x002212: + ret = (riva128->pfifo.ramht >> 16) & 0xff; + break; + case 0x002213: + ret = (riva128->pfifo.ramht >> 24) & 0xff; + break; + case 0x002214: + ret = riva128->pfifo.ramfc & 0xff; + break; + case 0x002215: + ret = (riva128->pfifo.ramfc >> 8) & 0xff; + break; + case 0x002216: + ret = (riva128->pfifo.ramfc >> 16) & 0xff; + break; + case 0x002217: + ret = (riva128->pfifo.ramfc >> 24) & 0xff; + break; + case 0x002218: + ret = riva128->pfifo.ramro & 0xff; + break; + case 0x002219: + ret = (riva128->pfifo.ramro >> 8) & 0xff; + break; + case 0x00221a: + ret = (riva128->pfifo.ramro >> 16) & 0xff; + break; + case 0x00221b: + ret = (riva128->pfifo.ramro >> 24) & 0xff; + break; + case 0x002504: + ret = riva128->pfifo.chan_mode & 0xff; + break; + case 0x002505: + ret = (riva128->pfifo.chan_mode >> 8) & 0xff; + break; + case 0x002506: + ret = (riva128->pfifo.chan_mode >> 16) & 0xff; + break; + case 0x002507: + ret = (riva128->pfifo.chan_mode >> 24) & 0xff; + break; + case 0x002508: + ret = riva128->pfifo.chan_dma & 0xff; + break; + case 0x002509: + ret = (riva128->pfifo.chan_dma >> 8) & 0xff; + break; + case 0x00250a: + ret = (riva128->pfifo.chan_dma >> 16) & 0xff; + break; + case 0x00250b: + ret = (riva128->pfifo.chan_dma >> 24) & 0xff; + break; + case 0x00250c: + ret = riva128->pfifo.chan_size & 0xff; + break; + case 0x00250d: + ret = (riva128->pfifo.chan_size >> 8) & 0xff; + break; + case 0x00250e: + ret = (riva128->pfifo.chan_size >> 16) & 0xff; + break; + case 0x00250f: + ret = (riva128->pfifo.chan_size >> 24) & 0xff; + break; + //HACK + case 0x002400: + ret = 0x10; + break; + case 0x002401: + ret = 0x00; + break; + case 0x003204: + ret = riva128->pfifo.caches[1].chanid; + break; + case 0x003214: + ret = 0x10; + break; + case 0x003215: + ret = 0x00; + break; + case 0x003220: + ret = 0x01; + break; + } + + return ret; +} + +static void riva128_pfifo_write(uint32_t addr, uint32_t val, void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + // pclog("RIVA 128 PFIFO write %08X %08X %04X:%08X\n", addr, val, CS, cpu_state.pc); + + switch(addr) + { + case 0x002100: + riva128->pfifo.intr &= ~val; + break; + case 0x002140: + riva128->pfifo.intr_en = val; + break; + case 0x002210: + riva128->pfifo.ramht = val; + riva128->pfifo.ramht_addr = (val & 0x1f0) << 8; + switch(val & 0x30000) + { + case 0x00000: + riva128->pfifo.ramht_size = 4 * 1024; + break; + case 0x10000: + riva128->pfifo.ramht_size = 8 * 1024; + break; + case 0x20000: + riva128->pfifo.ramht_size = 16 * 1024; + break; + case 0x30000: + riva128->pfifo.ramht_size = 32 * 1024; + break; + } + break; + case 0x002214: + riva128->pfifo.ramfc = val; + riva128->pfifo.ramfc_addr = (val & 0x1fe) << 4; + break; + case 0x002218: + riva128->pfifo.ramro = val; + riva128->pfifo.ramro_addr = (val & 0x1fe) << 4; + if(val & 0x10000) riva128->pfifo.ramro_size = 8192; + else riva128->pfifo.ramro_size = 512; + break; + case 0x002504: + riva128->pfifo.chan_mode = val; + break; + case 0x002508: + riva128->pfifo.chan_dma = val; + break; + case 0x00250c: + riva128->pfifo.chan_size = val; + break; + case 0x003200: + riva128->pfifo.caches[1].push_enabled = val; + break; + case 0x003204: + riva128->pfifo.caches[1].chanid = val; + break; + } +} + +static void riva128_pfifo_interrupt(int num, void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + + riva128->pfifo.intr |= (1 << num); + + riva128_pmc_interrupt(8, riva128); +} + +static uint8_t riva128_ptimer_read(uint32_t addr, void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + uint8_t ret = 0; + + //pclog("RIVA 128 PTIMER read %08X %04X:%08X\n", addr, CS, cpu_state.pc); + + switch(addr) + { + case 0x009100: + ret = riva128->ptimer.intr & 0xff; + break; + case 0x009101: + ret = (riva128->ptimer.intr >> 8) & 0xff; + break; + case 0x009102: + ret = (riva128->ptimer.intr >> 16) & 0xff; + break; + case 0x009103: + ret = (riva128->ptimer.intr >> 24) & 0xff; + break; + case 0x009140: + ret = riva128->ptimer.intr & 0xff; + break; + case 0x009141: + ret = (riva128->ptimer.intr_en >> 8) & 0xff; + break; + case 0x009142: + ret = (riva128->ptimer.intr_en >> 16) & 0xff; + break; + case 0x009143: + ret = (riva128->ptimer.intr_en >> 24) & 0xff; + break; + case 0x009200: + ret = riva128->ptimer.clock_div & 0xff; + break; + case 0x009201: + ret = (riva128->ptimer.clock_div >> 8) & 0xff; + break; + case 0x009202: + ret = (riva128->ptimer.clock_div >> 16) & 0xff; + break; + case 0x009203: + ret = (riva128->ptimer.clock_div >> 24) & 0xff; + break; + case 0x009210: + ret = riva128->ptimer.clock_mul & 0xff; + break; + case 0x009211: + ret = (riva128->ptimer.clock_mul >> 8) & 0xff; + break; + case 0x009212: + ret = (riva128->ptimer.clock_mul >> 16) & 0xff; + break; + case 0x009213: + ret = (riva128->ptimer.clock_mul >> 24) & 0xff; + break; + case 0x009400: + ret = riva128->ptimer.time & 0xff; + break; + case 0x009401: + ret = (riva128->ptimer.time >> 8) & 0xff; + break; + case 0x009402: + ret = (riva128->ptimer.time >> 16) & 0xff; + break; + case 0x009403: + ret = (riva128->ptimer.time >> 24) & 0xff; + break; + case 0x009410: + ret = (riva128->ptimer.time >> 32) & 0xff; + break; + case 0x009411: + ret = (riva128->ptimer.time >> 40) & 0xff; + break; + case 0x009412: + ret = (riva128->ptimer.time >> 48) & 0xff; + break; + case 0x009413: + ret = (riva128->ptimer.time >> 56) & 0xff; + break; + case 0x009420: + ret = riva128->ptimer.alarm & 0xff; + break; + case 0x009421: + ret = (riva128->ptimer.alarm >> 8) & 0xff; + break; + case 0x009422: + ret = (riva128->ptimer.alarm >> 16) & 0xff; + break; + case 0x009423: + ret = (riva128->ptimer.alarm >> 24) & 0xff; + break; + } + + + //riva128->ptimer.time += 0x10000; + + return ret; +} + +static void riva128_ptimer_write(uint32_t addr, uint32_t val, void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + pclog("RIVA 128 PTIMER write %08X %08X %04X:%08X\n", addr, val, CS, cpu_state.pc); + + switch(addr) + { + case 0x009100: + riva128->ptimer.intr &= ~val; + break; + case 0x009140: + riva128->ptimer.intr_en = val; + break; + case 0x009200: + if(!(val & 0xffff)) val = 1; + riva128->ptimer.clock_div = val & 0xffff; + break; + case 0x009210: + if((val & 0xffff) > riva128->ptimer.clock_div) val = riva128->ptimer.clock_div; + riva128->ptimer.clock_mul = val & 0xffff; + break; + case 0x009400: + riva128->ptimer.time &= 0x0fffffff00000000ULL; + riva128->ptimer.time |= val & 0xffffffe0; + break; + case 0x009410: + riva128->ptimer.time &= 0xffffffe0; + riva128->ptimer.time |= val & 0x0fffffff00000000ULL; + break; + case 0x009420: + riva128->ptimer.alarm = val & 0xffffffe0; + break; + } +} + +static void riva128_ptimer_interrupt(int num, void *p) +{ + //pclog("RIVA 128 PTIMER interrupt #%d fired!\n", num); + riva128_t *riva128 = (riva128_t *)p; + + riva128->ptimer.intr |= (1 << num); + + riva128_pmc_interrupt(20, riva128); +} + +static uint8_t riva128_pfb_read(uint32_t addr, void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + uint8_t ret = 0; + + //pclog("RIVA 128 PFB read %08X %04X:%08X\n", addr, CS, cpu_state.pc); + + switch(addr) + { + case 0x100000: + { + switch(riva128->card_id) + { + case 0x03: + { + switch(riva128->memory_size) + { + case 1: + case 8: + ret = 0; + case 2: + ret = 1; + case 4: + ret = 2; + } + ret |= 0x04; + break; + } + case 0x04: + case 0x05: + { + switch(riva128->memory_size) + { + case 4: + ret = 1; + break; + case 8: + ret = 2; + break; + case 16: + ret = 3; + break; + case 32: + ret = 0; + break; + } + ret |= 0x14; + break; + } + } + break; + } + case 0x100200: + ret = riva128->pfb.config_0 & 0xff; + break; + case 0x100201: + ret = (riva128->pfb.config_0 >> 8) & 0xff; + break; + case 0x100202: + ret = (riva128->pfb.config_0 >> 16) & 0xff; + break; + case 0x100203: + ret = (riva128->pfb.config_0 >> 24) & 0xff; + break; + } + + return ret; +} + +static void riva128_pfb_write(uint32_t addr, uint32_t val, void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + //pclog("RIVA 128 PFB write %08X %08X %04X:%08X\n", addr, val, CS, cpu_state.pc); + + switch(addr) + { + case 0x100200: + riva128->pfb.config_0 = val; + riva128->pfb.width = (val & 0x3f) << 5; + switch((val >> 8) & 3) + { + case 1: + riva128->pfb.bpp = 8; + break; + case 2: + riva128->pfb.bpp = 16; + break; + case 3: + riva128->pfb.bpp = 32; + break; + } + break; + } +} + +static uint8_t riva128_pextdev_read(uint32_t addr, void *p) +{ + //riva128_t *riva128 = (riva128_t *)p; + uint8_t ret = 0; + + //pclog("RIVA 128 PEXTDEV read %08X %04X:%08X\n", addr, CS, cpu_state.pc); + + switch(addr) + { + case 0x101000: + ret = 0x9e; + break; + case 0x101001: + ret = 0x01; + break; + } + + return ret; +} + +static void rivatnt_pgraph_ctx_switch(void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + + unsigned old_subc = (riva128->pgraph.ctx_user >> 13) & 7; + unsigned new_subc = (riva128->pgraph.fifo_st2_addr >> 12) & 7; + unsigned mthd = (riva128->pgraph.fifo_st2_addr >> 1) & 0x7ff; + unsigned do_ctx_switch = mthd == 0; + + if(!(riva128->pgraph.fifo_st2_addr & 1)) return; + riva128->pgraph.fifo_st2_addr &= ~1; + + if(old_subc != new_subc || do_ctx_switch) + { + uint32_t ctx_mask = 0x0303f0ff; + + unsigned reload = (riva128->pgraph.debug[1] >> 15) & 1; + + unsigned reset = (riva128->pgraph.debug[2] >> 28) & 1; + + if(do_ctx_switch) riva128->pgraph.ctx_cache[new_subc][3] = riva128->pgraph.fifo_st2_data & 0xffff; + + if(reload || do_ctx_switch) + { + uint32_t instance = riva128_ramht_lookup(riva128->pgraph.fifo_st2_data, riva128); + riva128->pgraph.ctx_cache[new_subc][0] = riva128->pramin[(instance >> 2)] & ctx_mask; + riva128->pgraph.ctx_cache[new_subc][1] = riva128->pramin[(instance >> 2) + 1] & 0xffff3f03; + riva128->pgraph.ctx_cache[new_subc][2] = riva128->pramin[(instance >> 2) + 2]; + riva128->pgraph.ctx_cache[new_subc][4] = riva128->pramin[(instance >> 2) + 3]; + } + + if(reset) + { + riva128->pgraph.debug[1] |= 1; + //riva128_pgraph_volatile_reset(riva128); + } + else riva128->pgraph.debug[1] &= ~1; + + if(riva128->pgraph.debug[1] & 0x100000) + { + int i; + for(i = 0; i < 5; i++) riva128->pgraph.ctx_switch[i] = riva128->pgraph.ctx_cache[new_subc][i]; + } + } +} + +static uint8_t riva128_pgraph_read(uint32_t addr, void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + uint8_t ret = 0; + + pclog("RIVA 128 PGRAPH read %08X %04X:%08X\n", addr, CS, cpu_state.pc); + + switch(addr) + { + case 0x400080: + ret = riva128->pgraph.debug[0] & 0xff; + break; + case 0x400081: + ret = (riva128->pgraph.debug[0] >> 8) & 0xff; + break; + case 0x400082: + ret = (riva128->pgraph.debug[0] >> 16) & 0xff; + break; + case 0x400083: + ret = (riva128->pgraph.debug[0] >> 24) & 0xff; + break; + case 0x400084: + ret = riva128->pgraph.debug[1] & 0xff; + break; + case 0x400085: + ret = (riva128->pgraph.debug[1] >> 8) & 0xff; + break; + case 0x400086: + ret = (riva128->pgraph.debug[1] >> 16) & 0xff; + break; + case 0x400087: + ret = (riva128->pgraph.debug[1] >> 24) & 0xff; + break; + case 0x400088: + ret = riva128->pgraph.debug[2] & 0xff; + break; + case 0x400089: + ret = (riva128->pgraph.debug[2] >> 8) & 0xff; + break; + case 0x40008a: + ret = (riva128->pgraph.debug[2] >> 16) & 0xff; + break; + case 0x40008b: + ret = (riva128->pgraph.debug[2] >> 24) & 0xff; + break; + case 0x40008c: + ret = riva128->pgraph.debug[3] & 0xff; + break; + case 0x40008d: + ret = (riva128->pgraph.debug[3] >> 8) & 0xff; + break; + case 0x40008e: + ret = (riva128->pgraph.debug[3] >> 16) & 0xff; + break; + case 0x40008f: + ret = (riva128->pgraph.debug[3] >> 24) & 0xff; + break; + + case 0x400100: + ret = riva128->pgraph.intr & 0xff; + break; + case 0x400101: + ret = (riva128->pgraph.intr >> 8) & 0xff; + break; + case 0x400102: + ret = (riva128->pgraph.intr >> 16) & 0xff; + break; + case 0x400103: + ret = (riva128->pgraph.intr >> 24) & 0xff; + break; + case 0x400104: + ret = riva128->pgraph.invalid & 0xff; + break; + case 0x400105: + ret = (riva128->pgraph.invalid >> 8) & 0xff; + break; + case 0x400106: + ret = (riva128->pgraph.invalid >> 16) & 0xff; + break; + case 0x400107: + ret = (riva128->pgraph.invalid >> 24) & 0xff; + break; + case 0x400140: + ret = riva128->pgraph.intr_en & 0xff; + break; + case 0x400141: + ret = (riva128->pgraph.intr_en >> 8) & 0xff; + break; + case 0x400142: + ret = (riva128->pgraph.intr_en >> 16) & 0xff; + break; + case 0x400143: + ret = (riva128->pgraph.intr_en >> 24) & 0xff; + break; + case 0x400144: + ret = riva128->pgraph.invalid_en & 0xff; + break; + case 0x400145: + ret = (riva128->pgraph.invalid_en >> 8) & 0xff; + break; + case 0x400146: + ret = (riva128->pgraph.invalid_en >> 16) & 0xff; + break; + case 0x400147: + ret = (riva128->pgraph.invalid_en >> 24) & 0xff; + break; + + case 0x400180: + ret = riva128->pgraph.ctx_switch[0] & 0xff; + break; + case 0x400181: + ret = (riva128->pgraph.ctx_switch[0] >> 8) & 0xff; + break; + case 0x400182: + ret = (riva128->pgraph.ctx_switch[0] >> 16) & 0xff; + break; + case 0x400183: + ret = (riva128->pgraph.ctx_switch[0] >> 24) & 0xff; + break; + + case 0x400190: + ret = riva128->pgraph.ctx_control & 0xff; + break; + case 0x400191: + ret = (riva128->pgraph.ctx_control >> 8) & 0xff; + break; + case 0x400192: + ret = (riva128->pgraph.ctx_control >> 16) & 0xff; + break; + case 0x400193: + ret = (riva128->pgraph.ctx_control >> 24) & 0xff; + break; + case 0x400194: + ret = riva128->pgraph.ctx_user & 0xff; + break; + case 0x400195: + ret = (riva128->pgraph.ctx_user >> 8) & 0xff; + break; + case 0x400196: + ret = (riva128->pgraph.ctx_user >> 16) & 0xff; + break; + case 0x400197: + ret = (riva128->pgraph.ctx_user >> 24) & 0xff; + break; + + case 0x4001a0: case 0x4001a1: case 0x4001a2: case 0x4001a3: case 0x4001a4: case 0x4001a5: case 0x4001a6: case 0x4001a7: + case 0x4001a8: case 0x4001a9: case 0x4001aa: case 0x4001ab: case 0x4001ac: case 0x4001ad: case 0x4001ae: case 0x4001af: + case 0x4001b0: case 0x4001b1: case 0x4001b2: case 0x4001b3: case 0x4001b4: case 0x4001b5: case 0x4001b6: case 0x4001b7: + case 0x4001b8: case 0x4001b9: case 0x4001ba: case 0x4001bb: case 0x4001bc: case 0x4001bd: case 0x4001be: case 0x4001bf: + ret = (riva128->pgraph.ctx_cache[(addr & 0x1c) >> 2][0] >> ((addr & 3) << 3)) & 0xff; + break; + + case 0x4006a4: + ret = riva128->pgraph.fifo_enable & 1; + break; + + case 0x401100: + ret = riva128->pgraph.dma_intr & 0xff; + break; + case 0x401101: + ret = (riva128->pgraph.dma_intr >> 8) & 0xff; + break; + case 0x401102: + ret = (riva128->pgraph.dma_intr >> 16) & 0xff; + break; + case 0x401103: + ret = (riva128->pgraph.dma_intr >> 24) & 0xff; + break; + case 0x401140: + ret = riva128->pgraph.dma_intr_en & 0xff; + break; + case 0x401141: + ret = (riva128->pgraph.dma_intr_en >> 8) & 0xff; + break; + case 0x401142: + ret = (riva128->pgraph.dma_intr_en >> 16) & 0xff; + break; + case 0x401143: + ret = (riva128->pgraph.dma_intr_en >> 24) & 0xff; + break; + } + + if(riva128->card_id == 0x03) switch(addr) + { + case 0x40053c: + ret = riva128->pgraph.uclip_xmin & 0xff; + break; + case 0x40053d: + ret = (riva128->pgraph.uclip_xmin >> 8) & 0xff; + break; + case 0x40053e: + ret = (riva128->pgraph.uclip_xmin >> 16) & 0xff; + break; + case 0x40053f: + ret = (riva128->pgraph.uclip_xmin >> 24) & 0xff; + break; + case 0x400540: + ret = riva128->pgraph.uclip_ymin & 0xff; + break; + case 0x400541: + ret = (riva128->pgraph.uclip_ymin >> 8) & 0xff; + break; + case 0x400542: + ret = (riva128->pgraph.uclip_ymin >> 16) & 0xff; + break; + case 0x400543: + ret = (riva128->pgraph.uclip_ymin >> 24) & 0xff; + break; + case 0x400544: + ret = riva128->pgraph.uclip_xmax & 0xff; + break; + case 0x400545: + ret = (riva128->pgraph.uclip_xmax >> 8) & 0xff; + break; + case 0x400546: + ret = (riva128->pgraph.uclip_xmax >> 16) & 0xff; + break; + case 0x400547: + ret = (riva128->pgraph.uclip_xmax >> 24) & 0xff; + break; + case 0x400548: + ret = riva128->pgraph.uclip_ymax & 0xff; + break; + case 0x400549: + ret = (riva128->pgraph.uclip_ymax >> 8) & 0xff; + break; + case 0x40054a: + ret = (riva128->pgraph.uclip_ymax >> 16) & 0xff; + break; + case 0x40054b: + ret = (riva128->pgraph.uclip_ymax >> 24) & 0xff; + break; + case 0x400560: + ret = riva128->pgraph.oclip_xmin & 0xff; + break; + case 0x400561: + ret = (riva128->pgraph.oclip_xmin >> 8) & 0xff; + break; + case 0x400562: + ret = (riva128->pgraph.oclip_xmin >> 16) & 0xff; + break; + case 0x400563: + ret = (riva128->pgraph.oclip_xmin >> 24) & 0xff; + break; + case 0x400564: + ret = riva128->pgraph.oclip_ymin & 0xff; + break; + case 0x400565: + ret = (riva128->pgraph.oclip_ymin >> 8) & 0xff; + break; + case 0x400566: + ret = (riva128->pgraph.oclip_ymin >> 16) & 0xff; + break; + case 0x400567: + ret = (riva128->pgraph.oclip_ymin >> 24) & 0xff; + break; + case 0x400568: + ret = riva128->pgraph.oclip_xmax & 0xff; + break; + case 0x400569: + ret = (riva128->pgraph.oclip_xmax >> 8) & 0xff; + break; + case 0x40056a: + ret = (riva128->pgraph.oclip_xmax >> 16) & 0xff; + break; + case 0x40056b: + ret = (riva128->pgraph.oclip_xmax >> 24) & 0xff; + break; + case 0x40056c: + ret = riva128->pgraph.oclip_ymax & 0xff; + break; + case 0x40056d: + ret = (riva128->pgraph.oclip_ymax >> 8) & 0xff; + break; + case 0x40056e: + ret = (riva128->pgraph.oclip_ymax >> 16) & 0xff; + break; + case 0x40056f: + ret = (riva128->pgraph.oclip_ymax >> 24) & 0xff; + break; + case 0x400624: + ret = riva128->pgraph.rop; + break; + case 0x40062c: + ret = riva128->pgraph.beta & 0xff; + break; + case 0x40062d: + ret = (riva128->pgraph.beta >> 8) & 0xff; + break; + case 0x40062e: + ret = (riva128->pgraph.beta >> 16) & 0xff; + break; + case 0x40062f: + ret = (riva128->pgraph.beta >> 24) & 0xff; + break; + case 0x400640: + ret = riva128->pgraph.beta & 0xff; + break; + case 0x400641: + ret = (riva128->pgraph.beta >> 8) & 0xff; + break; + case 0x400642: + ret = (riva128->pgraph.beta >> 16) & 0xff; + break; + case 0x400643: + ret = (riva128->pgraph.beta >> 24) & 0xff; + break; + case 0x400684: + ret = riva128->pgraph.notify & 0xff; + break; + case 0x400685: + ret = (riva128->pgraph.notify >> 8) & 0xff; + break; + case 0x400686: + ret = (riva128->pgraph.notify >> 16) & 0xff; + break; + case 0x400687: + ret = (riva128->pgraph.notify >> 24) & 0xff; + break; + case 0x400690: + ret = riva128->pgraph.cliprect_min[0] & 0xff; + break; + case 0x400691: + ret = (riva128->pgraph.cliprect_min[0] >> 8) & 0xff; + break; + case 0x400692: + ret = (riva128->pgraph.cliprect_min[0] >> 16) & 0xff; + break; + case 0x400693: + ret = (riva128->pgraph.cliprect_min[0] >> 24) & 0xff; + break; + case 0x400694: + ret = riva128->pgraph.cliprect_max[0] & 0xff; + break; + case 0x400695: + ret = (riva128->pgraph.cliprect_max[0] >> 8) & 0xff; + break; + case 0x400696: + ret = (riva128->pgraph.cliprect_max[0] >> 16) & 0xff; + break; + case 0x400697: + ret = (riva128->pgraph.cliprect_max[0] >> 24) & 0xff; + break; + case 0x400698: + ret = riva128->pgraph.cliprect_min[1] & 0xff; + break; + case 0x400699: + ret = (riva128->pgraph.cliprect_min[1] >> 8) & 0xff; + break; + case 0x40069a: + ret = (riva128->pgraph.cliprect_min[1] >> 16) & 0xff; + break; + case 0x40069b: + ret = (riva128->pgraph.cliprect_min[1] >> 24) & 0xff; + break; + case 0x40069c: + ret = riva128->pgraph.cliprect_max[1] & 0xff; + break; + case 0x40069d: + ret = (riva128->pgraph.cliprect_max[1] >> 8) & 0xff; + break; + case 0x40069e: + ret = (riva128->pgraph.cliprect_max[1] >> 16) & 0xff; + break; + case 0x40069f: + ret = (riva128->pgraph.cliprect_max[1] >> 24) & 0xff; + break; + case 0x4006a0: + ret = riva128->pgraph.cliprect_ctrl & 0xff; + break; + case 0x4006a1: + ret = (riva128->pgraph.cliprect_ctrl >> 8) & 0xff; + break; + case 0x4006a2: + ret = (riva128->pgraph.cliprect_ctrl >> 16) & 0xff; + break; + case 0x4006a3: + ret = (riva128->pgraph.cliprect_ctrl >> 24) & 0xff; + break; + } + + return ret; +} + +static void riva128_pgraph_write(uint32_t addr, uint32_t val, void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + pclog("RIVA 128 PGRAPH write %08X %08X %04X:%08X\n", addr, val, CS, cpu_state.pc); + + switch(addr) + { + case 0x400100: + riva128->pgraph.intr &= ~val; + break; + case 0x400104: + riva128->pgraph.invalid &= ~val; + break; + case 0x400140: + riva128->pgraph.intr_en = val; + if(riva128->card_id == 0x03) riva128->pgraph.intr_en &= 0x11111111; + else if(riva128->card_id < 0x10) riva128->pgraph.intr_en &= 0x00011311; + break; + case 0x400144: + if(riva128->card_id == 0x03) + { + riva128->pgraph.invalid_en = val; + riva128->pgraph.invalid_en &= 0x00011111; + } + break; + } + + if(riva128->card_id == 0x03) switch(addr) + { + case 0x400080: + riva128->pgraph.debug[0] = val & 0x13311110; + break; + case 0x400084: + riva128->pgraph.debug[1] = val & 0x10113301; + break; + case 0x400088: + riva128->pgraph.debug[2] = val & 0x1133f111; + break; + case 0x40008c: + riva128->pgraph.debug[3] = val & 0x1173ff31; + break; + case 0x400180: + riva128->pgraph.debug[1] &= ~1; //Clear recent volatile reset bit on object switch. + riva128->pgraph.ctx_switch[0] = val & 0x3ff3f71f; + break; + case 0x400190: + riva128->pgraph.ctx_control = val & 0x11010103; + break; + case 0x400194: + riva128->pgraph.ctx_user = val & 0x7f1fe000; + break; + case 0x4001a0: case 0x4001a4: case 0x4001a8: case 0x4001ac: case 0x4001b0: case 0x4001b4: case 0x4001b8: case 0x4001bc: + riva128->pgraph.ctx_cache[(addr & 0x1c) >> 2][0] = val & 0x3ff3f71f; + break; + case 0x40053c: + riva128->pgraph.uclip_xmin = val & 0x3ffff; + break; + case 0x400540: + riva128->pgraph.uclip_ymin = val & 0x3ffff; + break; + case 0x400544: + riva128->pgraph.uclip_xmax = val & 0x3ffff; + break; + case 0x400548: + riva128->pgraph.uclip_ymax = val & 0x3ffff; + break; + case 0x400550: + riva128->pgraph.src_canvas_min = val & (riva128->is_nv3t ? 0x7fff07ff : 0x3fff07ff); + break; + case 0x400554: + riva128->pgraph.src_canvas_max = val & (riva128->is_nv3t ? 0x7fff07ff : 0x3fff07ff); + break; + case 0x400558: + riva128->pgraph.dst_canvas_min = val & (riva128->is_nv3t ? 0x7fff07ff : 0x3fff07ff); + break; + case 0x40055c: + riva128->pgraph.dst_canvas_max = val & (riva128->is_nv3t ? 0x7fff07ff : 0x3fff07ff); + break; + case 0x400560: + riva128->pgraph.oclip_xmin = val & 0x3ffff; + break; + case 0x400564: + riva128->pgraph.oclip_ymin = val & 0x3ffff; + break; + case 0x400568: + riva128->pgraph.oclip_xmax = val & 0x3ffff; + break; + case 0x40056c: + riva128->pgraph.oclip_ymax = val & 0x3ffff; + break; + case 0x400624: + riva128->pgraph.rop = val & 0xff; + break; + case 0x40062c: + riva128->pgraph.chroma = val & 0x7fffffff; + break; + case 0x400640: + { + uint32_t tmp = val & 0x7f800000; + if(val & 0x80000000) tmp = 0; + riva128->pgraph.beta = tmp; + break; + } + case 0x400684: + riva128->pgraph.notify = val & 0x0011ffff; + break; + case 0x4006a0: + riva128->pgraph.cliprect_ctrl = val & 0x113; + break; + case 0x4006a4: + riva128->pgraph.fifo_enable = val & 1; + break; + case 0x401100: + riva128->pgraph.dma_intr &= ~val; + break; + case 0x401140: + riva128->pgraph.dma_intr_en = val & 0x00011111; + break; + } + else if(riva128->card_id < 0x10) switch(addr) + { + case 0x400080: + riva128->pgraph.debug[0] = val & 0x1337f000; + break; + case 0x400084: + riva128->pgraph.debug[1] = val & ((riva128->card_id == 0x04) ? 0x72113101 : 0xf2ffb701); + break; + case 0x400088: + riva128->pgraph.debug[2] = val & 0x11d7fff1; + break; + case 0x40008c: + riva128->pgraph.debug[3] = val & ((riva128->card_id == 0x04) ? 0x11ffff33 : 0xfbffff73); + break; + } + if(riva128->card_id >= 0x04) switch(addr) + { + case 0x400754: + riva128->pgraph.fifo_st2_addr = val; + break; + case 0x400758: + riva128->pgraph.fifo_st2_data = val; + rivatnt_pgraph_ctx_switch(riva128); + break; + } +} + +static void riva128_pgraph_interrupt(int num, void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + + riva128->pgraph.intr |= (1 << num); + + riva128_pmc_interrupt(12, riva128); +} + +static void riva128_pgraph_invalid_interrupt(int num, void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + + riva128->pgraph.invalid |= (1 << num); + + riva128_pgraph_interrupt(0, riva128); +} + +static uint8_t riva128_pramdac_read(uint32_t addr, void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + uint8_t ret = 0; + + //pclog("RIVA 128 PRAMDAC read %08X %04X:%08X\n", addr, CS, cpu_state.pc); + + switch(addr) + { + case 0x680500: + ret = riva128->pramdac.nvpll & 0xff; + break; + case 0x680501: + ret = (riva128->pramdac.nvpll >> 8) & 0xff; + break; + case 0x680502: + ret = (riva128->pramdac.nvpll >> 16) & 0xff; + break; + case 0x680503: + ret = (riva128->pramdac.nvpll >> 24) & 0xff; + break; + case 0x680504: + ret = riva128->pramdac.mpll & 0xff; + break; + case 0x680505: + ret = (riva128->pramdac.mpll >> 8) & 0xff; + break; + case 0x680506: + ret = (riva128->pramdac.mpll >> 16) & 0xff; + break; + case 0x680507: + ret = (riva128->pramdac.mpll >> 24) & 0xff; + break; + case 0x680508: + ret = riva128->pramdac.vpll & 0xff; + break; + case 0x680509: + ret = (riva128->pramdac.vpll >> 8) & 0xff; + break; + case 0x68050a: + ret = (riva128->pramdac.vpll >> 16) & 0xff; + break; + case 0x68050b: + ret = (riva128->pramdac.vpll >> 24) & 0xff; + break; + case 0x68050c: + ret = riva128->pramdac.pll_ctrl & 0xff; + break; + case 0x68050d: + ret = (riva128->pramdac.pll_ctrl >> 8) & 0xff; + break; + case 0x68050e: + ret = (riva128->pramdac.pll_ctrl >> 16) & 0xff; + break; + case 0x68050f: + ret = (riva128->pramdac.pll_ctrl >> 24) & 0xff; + break; + case 0x680600: + ret = riva128->pramdac.gen_ctrl & 0xff; + break; + case 0x680601: + ret = (riva128->pramdac.gen_ctrl >> 8) & 0xff; + break; + case 0x680602: + ret = (riva128->pramdac.gen_ctrl >> 16) & 0xff; + break; + case 0x680603: + ret = (riva128->pramdac.gen_ctrl >> 24) & 0xff; + break; + } + + return ret; +} + +static void riva128_pramdac_write(uint32_t addr, uint32_t val, void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + svga_t* svga = &riva128->svga; + //pclog("RIVA 128 PRAMDAC write %08X %08X %04X:%08X\n", addr, val, CS, cpu_state.pc); + + switch(addr) + { + case 0x680500: + riva128->pramdac.nvpll = val; + riva128->pramdac.nv_m = val & 0xff; + riva128->pramdac.nv_n = (val >> 8) & 0xff; + riva128->pramdac.nv_p = (val >> 16) & 7; + svga_recalctimings(svga); + break; + case 0x680504: + riva128->pramdac.mpll = val; + riva128->pramdac.m_m = val & 0xff; + riva128->pramdac.m_n = (val >> 8) & 0xff; + riva128->pramdac.m_p = (val >> 16) & 7; + svga_recalctimings(svga); + break; + case 0x680508: + riva128->pramdac.vpll = val; + riva128->pramdac.v_m = val & 0xff; + riva128->pramdac.v_n = (val >> 8) & 0xff; + riva128->pramdac.v_p = (val >> 16) & 7; + svga_recalctimings(svga); + break; + case 0x68050c: + riva128->pramdac.pll_ctrl = val; + break; + case 0x680600: + riva128->pramdac.gen_ctrl = val; + break; + } +} + +static uint32_t riva128_ramht_lookup(uint32_t handle, void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + uint32_t ramht_base = riva128->pfifo.ramht_addr; + + uint32_t tmp = handle; + uint32_t hash = 0; + + int bits; + + pclog("RIVA 128 RAMHT lookup with handle %08X %04X:%08X\n", handle, CS, cpu_state.pc); + + switch(riva128->pfifo.ramht_size) + { + case 4096: + bits = 12; + case 8192: + bits = 13; + case 16384: + bits = 14; + case 32768: + bits = 15; + } + + while(handle) + { + hash ^= (tmp & (riva128->pfifo.ramht_size - 1)); + tmp = handle >> 1; + } + + hash ^= riva128->pfifo.caches[1].chanid << (bits - 4); + + return riva128->pramin[ramht_base + (hash * 8)]; +} + +static void riva128_puller_exec_method(int chanid, int subchanid, int offset, uint32_t val, void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + pclog("RIVA 128 Puller executing method %04X on channel %01X[%01X] %04X:%08X\n", offset, chanid, subchanid, val, CS, cpu_state.pc); + + if(riva128->card_id == 0x03) + { + uint32_t tmp = riva128_ramht_lookup(val, riva128); + unsigned new_class = (tmp >> 16) & 0x1f; + unsigned old_subc = (riva128->pgraph.ctx_user >> 13) & 7; + unsigned new_subc = subchanid & 7; + riva128->pgraph.instance = (tmp & 0xffff) << 2; + if((old_subc != new_subc) || !offset) + { + uint32_t tmp_ctx = riva128->pramin[riva128->pgraph.instance]; + if(!offset) riva128->pgraph.ctx_cache[new_subc][0] = tmp_ctx & 0x3ff3f71f; + riva128->pgraph.ctx_user &= 0x1fe000; + riva128->pgraph.ctx_user |= tmp & 0x1f0000; + riva128->pgraph.ctx_user |= new_subc << 13; + if(riva128->pgraph.debug[1] & 0x100000) riva128->pgraph.ctx_switch[0] = riva128->pgraph.ctx_cache[new_subc][0]; + if(riva128->pgraph.debug[2] & 0x10000000) + { + //riva128_pgraph_volatile_reset(riva128); + riva128->pgraph.debug[1] |= 1; + } + else riva128->pgraph.debug[1] &= ~1; + if(riva128->pgraph.notify & 0x10000) + { + riva128_pgraph_invalid_interrupt(16, riva128); + riva128->pgraph.fifo_enable = 0; + } + } + + if(!riva128->pgraph.invalid && (((riva128->pgraph.debug[3] >> 20) & 3) == 3) && offset) + { + riva128_pgraph_invalid_interrupt(4, riva128); + riva128->pgraph.fifo_enable = 0; + } + + if((riva128->pgraph.debug[1] & 0x10000) && ((riva128->pgraph.instance >> 4) != riva128->pgraph.ctx_switch[3]) && (new_class == 0x0d || new_class == 0x0e || new_class == 0x14 || new_class == 0x17 || offset == 0x0104)) + { + riva128->pgraph.ctx_switch[3] = riva128->pgraph.instance >> 4; + riva128->pgraph.ctx_switch[1] = riva128->pramin[riva128->pgraph.instance + 4] & 0xffff; + riva128->pgraph.notify &= 0xf10000; + riva128->pgraph.notify |= (riva128->pramin[riva128->pgraph.instance + 4] >> 16) & 0xffff; + riva128->pgraph.ctx_switch[2] = riva128->pramin[riva128->pgraph.instance + 8] & 0x1ffff; + } + } +} + +static void riva128_pusher_run(int chanid, void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + svga_t *svga = &riva128->svga; + + while(riva128->pfifo.channels[chanid].dmaget != riva128->pfifo.channels[chanid].dmaput) + { + uint32_t dmaget = riva128->pfifo.channels[chanid].dmaget; + uint32_t cmd = ((uint32_t*)svga->vram)[dmaget >> 2]; + uint32_t* params = (uint32_t *)(((uint32_t*)svga->vram)[(dmaget + 4) >> 2]); + if(((cmd & 0xe0000003) == 0x20000000) && (riva128->card_id >= 0x04)) + { + //old nv4 jump command + riva128->pfifo.channels[chanid].dmaget = cmd & 0x1ffffffc; + } + if((cmd & 0xe0030003) == 0) + { + //nv3 increasing method command + uint32_t method = cmd & 0x1ffc; + int subchannel = (cmd >> 13) & 7; + int method_count = (cmd >> 18) & 0x7ff; + int i; + for(i = 0; ipfifo.channels[chanid].dmaget += 4; + } +} + +static void riva128_user_write(uint32_t addr, uint32_t val, void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + int chanid = (addr >> 16) & 0xf; + //int subchanid = (addr >> 13) & 0x7; + int offset = addr & 0x1fff; + + pclog("RIVA 128 USER write %08X %08X %04X:%08X\n", addr, val, CS, cpu_state.pc); + + addr -= 0x800000; + + if(riva128->pfifo.chan_mode & (1 << chanid)) + { + //DMA mode, at least this has docs. + switch(offset) + { + case 0x40: + riva128->pfifo.channels[chanid].dmaput = val; + if(riva128->pfifo.caches[1].push_enabled) riva128_pusher_run(chanid, riva128); + break; + case 0x44: + riva128->pfifo.channels[chanid].dmaget = val; + break; + } + } + else + { + //I don't know what to do here, as there are basically no docs on PIO PFIFO submission. + pclog("RIVA 128 PIO PFIFO submission attempted\n"); + } +} + +static uint8_t riva128_mmio_read(uint32_t addr, void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + uint8_t ret = 0; + + addr &= 0xffffff; + + //This logging condition is necessary to prevent A CATASTROPHIC LOG BLOWUP when polling PTIMER or PFIFO. DO NOT REMOVE. + if(!((addr >= 0x009000) && (addr <= 0x009fff)) && !((addr >= 0x002000) && (addr <= 0x003fff)) && !((addr >= 0x000000) + && (addr <= 0x000003)) && !((addr <= 0x680fff) && (addr >= 0x680000)) && !((addr >= 0x0c0000) && (addr <= 0x0cffff)) + && !((addr >= 0x110000) && (addr <= 0x11ffff)) && !(addr <= 0x000fff) && (addr >= 0x000000)) pclog("RIVA 128 MMIO read %08X %04X:%08X\n", addr, CS, cpu_state.pc); + + if((addr >= 0x000000) && (addr <= 0x000fff)) ret = riva128_pmc_read(addr, riva128); + if((addr >= 0x001000) && (addr <= 0x001fff)) ret = riva128_pbus_read(addr, riva128); + if((addr >= 0x002000) && (addr <= 0x002fff)) ret = riva128_pfifo_read(addr, riva128); + if((addr >= 0x009000) && (addr <= 0x009fff)) ret = riva128_ptimer_read(addr, riva128); + if((addr >= 0x100000) && (addr <= 0x100fff)) ret = riva128_pfb_read(addr, riva128); + if((addr >= 0x101000) && (addr <= 0x101fff)) ret = riva128_pextdev_read(addr, riva128); + if((addr >= 0x110000) && (addr <= 0x11ffff) && (riva128->card_id == 0x03)) ret = riva128->bios_rom.rom[addr & riva128->bios_rom.mask]; + if((addr >= 0x300000) && (addr <= 0x30ffff) && (riva128->card_id >= 0x04)) ret = riva128->bios_rom.rom[addr & riva128->bios_rom.mask]; + if((addr >= 0x400000) && (addr <= 0x400fff)) ret = riva128_pgraph_read(addr, riva128); + if((addr >= 0x680000) && (addr <= 0x680fff)) ret = riva128_pramdac_read(addr, riva128); + + switch(addr) + { + case 0x6013b4: case 0x6013b5: + case 0x6013d4: case 0x6013d5: + case 0x6013da: + case 0x0c03c2: case 0x0c03c3: case 0x0c03c4: case 0x0c03c5: + case 0x6813c6: case 0x6813c7: case 0x6813c8: case 0x6813c9: case 0x6813ca: case 0x6813cb: case 0x6813cc: + ret = riva128_in(addr & 0xfff, riva128); + break; + } + return ret; +} + +static uint16_t riva128_mmio_read_w(uint32_t addr, void *p) +{ + addr &= 0xffffff; + //pclog("RIVA 128 MMIO read %08X %04X:%08X\n", addr, CS, cpu_state.pc); + return (riva128_mmio_read(addr+0,p) << 0) | (riva128_mmio_read(addr+1,p) << 8); +} + +static uint32_t riva128_mmio_read_l(uint32_t addr, void *p) +{ + addr &= 0xffffff; + //pclog("RIVA 128 MMIO read %08X %04X:%08X\n", addr, CS, cpu_state.pc); + return (riva128_mmio_read(addr+0,p) << 0) | (riva128_mmio_read(addr+1,p) << 8) | (riva128_mmio_read(addr+2,p) << 16) | (riva128_mmio_read(addr+3,p) << 24); +} + +static void riva128_mmio_write(uint32_t addr, uint8_t val, void *p) +{ + addr &= 0xffffff; + //pclog("RIVA 128 MMIO write %08X %02X %04X:%08X\n", addr, val, CS, cpu_state.pc); + if(addr != 0x6013d4 && addr != 0x6013d5 && addr != 0x6013b4 && addr != 0x6013b5 && addr != 0x6013da && !((addr >= 0x6813c6) && (addr <= 0x6813cc))) + { + uint32_t tmp = riva128_mmio_read_l(addr,p); + tmp &= ~(0xff << ((addr & 3) << 3)); + tmp |= val << ((addr & 3) << 3); + riva128_mmio_write_l(addr, tmp, p); + } + else + { + riva128_out(addr & 0xfff, val & 0xff, p); + } +} + +static void riva128_mmio_write_w(uint32_t addr, uint16_t val, void *p) +{ + uint32_t tmp; + addr &= 0xffffff; + //pclog("RIVA 128 MMIO write %08X %04X %04X:%08X\n", addr, val, CS, cpu_state.pc); + tmp = riva128_mmio_read_l(addr,p); + tmp &= ~(0xffff << ((addr & 2) << 4)); + tmp |= val << ((addr & 2) << 4); + riva128_mmio_write_l(addr, tmp, p); +} + +static void riva128_mmio_write_l(uint32_t addr, uint32_t val, void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + + addr &= 0xffffff; + + //DO NOT REMOVE. This fixes a monstrous log blowup in win9x's drivers when accessing PFIFO. + if(!((addr >= 0x002000) && (addr <= 0x003fff)) && !((addr >= 0xc0000) && (addr <= 0xcffff)) && (addr != 0x000140)) pclog("RIVA 128 MMIO write %08X %08X %04X:%08X\n", addr, val, CS, cpu_state.pc); + + + if((addr >= 0x000000) && (addr <= 0x000fff)) riva128_pmc_write(addr, val, riva128); + if((addr >= 0x001000) && (addr <= 0x001fff)) riva128_pbus_write(addr, val, riva128); + if((addr >= 0x002000) && (addr <= 0x002fff)) riva128_pfifo_write(addr, val, riva128); + if((addr >= 0x009000) && (addr <= 0x009fff)) riva128_ptimer_write(addr, val, riva128); + if((addr >= 0x100000) && (addr <= 0x100fff)) riva128_pfb_write(addr, val, riva128); + if((addr >= 0x400000) && (addr <= 0x400fff)) riva128_pgraph_write(addr, val, riva128); + if((addr >= 0x680000) && (addr <= 0x680fff)) riva128_pramdac_write(addr, val, riva128); + if((addr >= 0x800000) && (addr <= 0xffffff)) riva128_user_write(addr, val, riva128); + + switch(addr) + { + case 0x6013b4: case 0x6013b5: + case 0x6013d4: case 0x6013d5: + case 0x6013da: + case 0x0c03c2: case 0x0c03c3: case 0x0c03c4: case 0x0c03c5: + case 0x6813c6: case 0x6813c7: case 0x6813c8: case 0x6813c9: case 0x6813ca: case 0x6813cb: case 0x6813cc: + riva128_out(addr & 0xfff, val & 0xff, p); + riva128_out((addr+1) & 0xfff, (val>>8) & 0xff, p); + riva128_out((addr+2) & 0xfff, (val>>16) & 0xff, p); + riva128_out((addr+3) & 0xfff, (val>>24) & 0xff, p); + break; + } +} + +static void riva128_ptimer_tick(void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + + double time = (double)riva128->ptimer.clock_mul / (double)riva128->ptimer.clock_div; + uint64_t tmp; + int alarm_check; + + time *= 10000; + + tmp = riva128->ptimer.time; + riva128->ptimer.time += (uint64_t)time << 5; + + alarm_check = ((uint32_t)tmp < riva128->ptimer.alarm) || ((uint32_t)riva128->ptimer.time >= riva128->ptimer.alarm); + + if(alarm_check) + { + //pclog("RIVA 128 PTIMER ALARM interrupt fired!\n"); + riva128_ptimer_interrupt(0, riva128); + } +} + +static void riva128_mclk_poll(void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + + if(riva128->card_id == 0x03) riva128_ptimer_tick(riva128); + + riva128->mtime += cpuclock / riva128->mfreq; +} + +static void riva128_nvclk_poll(void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + + if(riva128->card_id < 0x40 && riva128->card_id != 0x03) riva128_ptimer_tick(riva128); + + riva128->nvtime += cpuclock / riva128->nvfreq; +} + +static void riva128_vblank_poll(void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + svga_t *svga = &riva128->svga; + + if(svga->vc == svga->dispend) riva128_pmc_interrupt(24, riva128); +} + +static uint8_t riva128_rma_in(uint16_t addr, void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + uint8_t ret = 0; + + addr &= 0xff; + + //pclog("RIVA 128 RMA read %04X %04X:%08X\n", addr, CS, cpu_state.pc); + + switch(addr) + { + case 0x00: + ret = 0x65; + break; + case 0x01: + ret = 0xd0; + break; + case 0x02: + ret = 0x16; + break; + case 0x03: + ret = 0x2b; + break; + case 0x08: + case 0x09: + case 0x0a: + case 0x0b: + ret = riva128_mmio_read(riva128->rma.addr + (addr & 3), riva128); + break; + } + + return ret; +} + +static void riva128_rma_out(uint16_t addr, uint8_t val, void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + svga_t* svga = &riva128->svga; + + addr &= 0xff; + + //pclog("RIVA 128 RMA write %04X %02X %04X:%08X\n", addr, val, CS, cpu_state.pc); + + switch(addr) + { + case 0x04: + riva128->rma.addr &= ~0xff; + riva128->rma.addr |= val; + break; + case 0x05: + riva128->rma.addr &= ~0xff00; + riva128->rma.addr |= (val << 8); + break; + case 0x06: + riva128->rma.addr &= ~0xff0000; + riva128->rma.addr |= (val << 16); + break; + case 0x07: + riva128->rma.addr &= ~0xff000000; + riva128->rma.addr |= (val << 24); + break; + case 0x08: + case 0x0c: + case 0x10: + case 0x14: + riva128->rma.data &= ~0xff; + riva128->rma.data |= val; + break; + case 0x09: + case 0x0d: + case 0x11: + case 0x15: + riva128->rma.data &= ~0xff00; + riva128->rma.data |= (val << 8); + break; + case 0x0a: + case 0x0e: + case 0x12: + case 0x16: + riva128->rma.data &= ~0xff0000; + riva128->rma.data |= (val << 16); + break; + case 0x0b: + case 0x0f: + case 0x13: + case 0x17: + riva128->rma.data &= ~0xff000000; + riva128->rma.data |= (val << 24); + if(riva128->rma.addr < 0x1000000) riva128_mmio_write_l(riva128->rma.addr & 0xffffff, riva128->rma.data, riva128); + else svga_writel_linear((riva128->rma.addr - 0x1000000), riva128->rma.data, svga); + break; + } + + if(addr & 0x10) riva128->rma.addr+=4; +} + +static uint8_t riva128_in(uint16_t addr, void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + svga_t* svga = &riva128->svga; + uint8_t ret = 0; + + if((addr >= 0x3d0) && (addr <= 0x3d3)) + { + //pclog("RIVA 128 RMA BAR Register read %04X %04X:%08X\n", addr, CS, cpu_state.pc); + if(!(riva128->rma.mode & 1)) return ret; + ret = riva128_rma_in(riva128->rma_addr + ((riva128->rma.mode & 0xe) << 1) + (addr & 3), riva128); + return ret; + } + + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) + addr ^= 0x60; + + // if (addr != 0x3da) pclog("S3 in %04X %04X:%08X ", addr, CS, cpu_state.pc); + switch (addr) + { + case 0x3D4: + ret = svga->crtcreg; + break; + case 0x3D5: + switch(svga->crtcreg) + { + case 0x3e: + ret = (riva128->i2c.sda << 3) | (riva128->i2c.scl << 2); + break; + case 0x28: + ret = svga->crtc[0x28] & 3; + break; + default: + ret = svga->crtc[svga->crtcreg]; + break; + } + //if(svga->crtcreg > 0x18) + // pclog("RIVA 128 Extended CRTC read %02X %04X:%08X\n", svga->crtcreg, CS, cpu_state.pc); + break; + default: + ret = svga_in(addr, svga); + break; + } + // if (addr != 0x3da) pclog("%02X\n", ret); + return ret; +} + +static void riva128_out(uint16_t addr, uint8_t val, void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + svga_t *svga = &riva128->svga; + + uint8_t old; + + if((addr >= 0x3d0) && (addr <= 0x3d3)) + { + //pclog("RIVA 128 RMA BAR Register write %04X %02x %04X:%08X\n", addr, val, CS, cpu_state.pc); + riva128->rma.access_reg[addr & 3] = val; + if(!(riva128->rma.mode & 1)) return; + riva128_rma_out(riva128->rma_addr + ((riva128->rma.mode & 0xe) << 1) + (addr & 3), riva128->rma.access_reg[addr & 3], riva128); + return; + } + + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) + addr ^= 0x60; + + switch(addr) + { + case 0x3D4: + svga->crtcreg = val; + return; + case 0x3D5: + if ((svga->crtcreg < 7) && (svga->crtc[0x11] & 0x80)) + return; + if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80)) + val = (svga->crtc[7] & ~0x10) | (val & 0x10); + old = svga->crtc[svga->crtcreg]; + svga->crtc[svga->crtcreg] = val; + switch(svga->crtcreg) + { + case 0x1a: + svga_recalctimings(svga); + break; + case 0x1e: + riva128->read_bank = val; + if (svga->chain4) svga->read_bank = riva128->read_bank << 15; + else svga->read_bank = riva128->read_bank << 13; + break; + case 0x1d: + riva128->write_bank = val; + if (svga->chain4) svga->write_bank = riva128->write_bank << 15; + else svga->write_bank = riva128->write_bank << 13; + break; + case 0x26: + if (!svga->attrff) + svga->attraddr = val & 31; + break; + case 0x19: + case 0x25: + case 0x28: + case 0x2d: + svga_recalctimings(svga); + break; + case 0x38: + riva128->rma.mode = val & 0xf; + break; + case 0x3f: + riva128->i2c.scl = (val & 0x20) ? 1 : 0; + riva128->i2c.sda = (val & 0x10) ? 1 : 0; + break; + } + //if(svga->crtcreg > 0x18) + // pclog("RIVA 128 Extended CRTC write %02X %02x %04X:%08X\n", svga->crtcreg, val, CS, cpu_state.pc); + if (old != val) + { + if (svga->crtcreg < 0xE || svga->crtcreg > 0x10) + { + svga->fullchange = changeframecount; + svga_recalctimings(svga); + } + } + return; + } + + svga_out(addr, val, svga); +} + +static uint32_t riva128_ramin_readl(uint32_t addr, void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + uint32_t ret = riva128->pramin[(addr & 0x1ffffc) >> 2]; + return ret; +} + +static uint8_t riva128_ramin_readb(uint32_t addr, void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + uint32_t ret = riva128->pramin[(addr & 0x1ffffc) >> 2]; + ret >>= 24 - ((addr & 3) << 3); + return ret; +} + +static uint16_t riva128_ramin_readw(uint32_t addr, void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + uint32_t ret = riva128->pramin[(addr & 0x1ffffc) >> 2]; + ret >>= 16 - ((addr & 2) << 3); + return ret; +} + +static void riva128_ramin_writel(uint32_t addr, uint32_t val, void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + riva128->pramin[(addr & 0x1ffffc) >> 2] = val; +} + +static void riva128_ramin_writeb(uint32_t addr, uint8_t val, void *p) +{ + uint32_t tmp = riva128_ramin_readl(addr,p); + tmp &= ~(0xff << ((addr & 3) << 3)); + tmp |= val << ((addr & 3) << 3); + riva128_ramin_writel(addr, tmp, p); +} + +static void riva128_ramin_writew(uint32_t addr, uint16_t val, void *p) +{ + uint32_t tmp = riva128_ramin_readl(addr,p); + tmp &= ~(0xffff << ((addr & 2) << 4)); + tmp |= val << ((addr & 2) << 4); + riva128_ramin_writel(addr, tmp, p); +} + +static uint8_t riva128_pci_read(int func, int addr, void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + uint8_t ret = 0; + //pclog("RIVA 128 PCI read %02X %04X:%08X\n", addr, CS, cpu_state.pc); + switch (addr) + { + case 0x00: + ret = riva128->vendor_id & 0xff; + break; + case 0x01: + ret = riva128->vendor_id >> 8; + break; + + case 0x02: + ret = riva128->device_id & 0xff; + break; + case 0x03: + ret = riva128->device_id >> 8; + break; + + case 0x04: + ret = riva128->pci_regs[0x04] & 0x37; + break; + case 0x05: + ret = riva128->pci_regs[0x05] & 0x01; + break; + + case 0x06: + ret = 0x20; + break; + case 0x07: + ret = riva128->pci_regs[0x07] & 0x73; + break; + + case 0x08: + ret = 0x00; + break; /*Revision ID*/ + case 0x09: + ret = 0; + break; /*Programming interface*/ + + case 0x0a: + ret = 0x00; + break; /*Supports VGA interface*/ + case 0x0b: + ret = 0x03; /*output = 3; */break; + + case 0x0e: + ret = 0x00; + break; /*Header type*/ + + case 0x13: + case 0x17: + ret = riva128->pci_regs[addr]; + break; + + case 0x2c: + case 0x2d: + case 0x2e: + case 0x2f: + ret = riva128->pci_regs[addr]; + //if(CS == 0x0028) output = 3; + break; + + case 0x30: + return riva128->pci_regs[0x30] & 0x01; /*BIOS ROM address*/ + case 0x31: + return 0x00; + case 0x32: + return riva128->pci_regs[0x32]; + case 0x33: + return riva128->pci_regs[0x33]; + + case 0x34: + ret = 0x00; + break; + + case 0x3c: + ret = riva128->pci_regs[0x3c]; + break; + + case 0x3d: + ret = 0x01; + break; /*INTA*/ + + case 0x3e: + ret = 0x03; + break; + case 0x3f: + ret = 0x01; + break; + + } + // pclog("%02X\n", ret); + return ret; +} + +static void riva128_reenable_svga_mappings(svga_t *svga) +{ + switch (svga->gdcreg[6] & 0xc) /*Banked framebuffer*/ + { + case 0x0: /*128k at A0000*/ + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x20000); + svga->banked_mask = 0xffff; + break; + case 0x4: /*64k at A0000*/ + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x10000); + svga->banked_mask = 0xffff; + break; + case 0x8: /*32k at B0000*/ + mem_mapping_set_addr(&svga->mapping, 0xb0000, 0x08000); + svga->banked_mask = 0x7fff; + break; + case 0xC: /*32k at B8000*/ + mem_mapping_set_addr(&svga->mapping, 0xb8000, 0x08000); + svga->banked_mask = 0x7fff; + break; + } +} + +static void riva128_pci_write(int func, int addr, uint8_t val, void *p) +{ + //pclog("RIVA 128 PCI write %02X %02X %04X:%08X\n", addr, val, CS, cpu_state.pc); + riva128_t *riva128 = (riva128_t *)p; + svga_t* svga = &riva128->svga; + switch (addr) + { + case 0x00: + case 0x01: + case 0x02: + case 0x03: + case 0x08: + case 0x09: + case 0x0a: + case 0x0b: + case 0x3d: + case 0x3e: + case 0x3f: + return; + + case PCI_REG_COMMAND: + riva128->pci_regs[PCI_REG_COMMAND] = val & 0x27; + io_removehandler(0x03c0, 0x0020, riva128_in, NULL, NULL, riva128_out, NULL, NULL, riva128); + mem_mapping_disable(&svga->mapping); + mem_mapping_disable(&riva128->mmio_mapping); + mem_mapping_disable(&riva128->linear_mapping); + mem_mapping_disable(&riva128->ramin_mapping); + if (val & PCI_COMMAND_IO) + { + io_sethandler(0x03c0, 0x0020, riva128_in, NULL, NULL, riva128_out, NULL, NULL, riva128); + } + if (val & PCI_COMMAND_MEM) + { + uint32_t mmio_addr = riva128->pci_regs[0x13] << 24; + uint32_t linear_addr = riva128->pci_regs[0x17] << 24; + if (!mmio_addr && !linear_addr) + { + riva128_reenable_svga_mappings(svga); + } + if (mmio_addr) + { + mem_mapping_set_addr(&riva128->mmio_mapping, mmio_addr, 0x1000000); + } + if (linear_addr) + { + mem_mapping_set_addr(&riva128->linear_mapping, linear_addr, 0xc00000); + mem_mapping_set_addr(&riva128->ramin_mapping, linear_addr + 0xc00000, 0x200000); + svga->linear_base = linear_addr; + } + } + return; + + case 0x05: + riva128->pci_regs[0x05] = val & 0x01; + return; + + case 0x07: + riva128->pci_regs[0x07] = (riva128->pci_regs[0x07] & 0x8f) | (val & 0x70); + return; + + case 0x13: + { + uint32_t mmio_addr; + riva128->pci_regs[addr] = val; + mmio_addr = riva128->pci_regs[0x13] << 24; + mem_mapping_disable(&riva128->mmio_mapping); + if (mmio_addr) + { + mem_mapping_set_addr(&riva128->mmio_mapping, mmio_addr, 0x1000000); + } + return; + } + + case 0x17: + { + uint32_t linear_addr; + riva128->pci_regs[addr] = val; + linear_addr = riva128->pci_regs[0x17] << 24; + mem_mapping_disable(&riva128->linear_mapping); + mem_mapping_disable(&riva128->ramin_mapping); + if (linear_addr) + { + mem_mapping_set_addr(&riva128->linear_mapping, linear_addr, 0xc00000); + mem_mapping_set_addr(&riva128->ramin_mapping, linear_addr + 0xc00000, 0x200000); + svga->linear_base = linear_addr; + } + return; + } + + case 0x30: + case 0x32: + case 0x33: + riva128->pci_regs[addr] = val; + mem_mapping_disable(&riva128->bios_rom.mapping); + if (riva128->pci_regs[0x30] & 0x01) + { + uint32_t addr = (riva128->pci_regs[0x32] << 16) | (riva128->pci_regs[0x33] << 24); + // pclog("RIVA 128 bios_rom enabled at %08x\n", addr); + mem_mapping_set_addr(&riva128->bios_rom.mapping, addr, 0x8000); + } + return; + + /* case 0x3c: + riva128->pci_regs[0x3c] = val & 0x0f; + return; */ + + case 0x40: + case 0x41: + case 0x42: + case 0x43: + riva128->pci_regs[addr - 0x14] = val; //0x40-0x43 are ways to write to 0x2c-0x2f + return; + } +} + +static void rivatnt_pci_write(int func, int addr, uint8_t val, void *p) +{ + //pclog("RIVA 128 PCI write %02X %02X %04X:%08X\n", addr, val, CS, cpu_state.pc); + riva128_t *riva128 = (riva128_t *)p; + svga_t *svga = &riva128->svga; + switch (addr) + { + case 0x00: + case 0x01: + case 0x02: + case 0x03: + case 0x08: + case 0x09: + case 0x0a: + case 0x0b: + case 0x3d: + case 0x3e: + case 0x3f: + return; + + case PCI_REG_COMMAND: + riva128->pci_regs[PCI_REG_COMMAND] = val & 0x27; + io_removehandler(0x03c0, 0x0020, riva128_in, NULL, NULL, riva128_out, NULL, NULL, riva128); + mem_mapping_disable(&svga->mapping); + mem_mapping_disable(&riva128->mmio_mapping); + mem_mapping_disable(&riva128->linear_mapping); + if (val & PCI_COMMAND_IO) + { + io_sethandler(0x03c0, 0x0020, riva128_in, NULL, NULL, riva128_out, NULL, NULL, riva128); + } + if (val & PCI_COMMAND_MEM) + { + uint32_t mmio_addr = riva128->pci_regs[0x13] << 24; + uint32_t linear_addr = riva128->pci_regs[0x17] << 24; + if (!mmio_addr && !linear_addr) + { + riva128_reenable_svga_mappings(svga); + } + if (mmio_addr) + { + mem_mapping_set_addr(&riva128->mmio_mapping, mmio_addr, 0x1000000); + } + if (linear_addr) + { + mem_mapping_set_addr(&riva128->linear_mapping, linear_addr, 0x1000000); + svga->linear_base = linear_addr; + } + } + return; + + case 0x05: + riva128->pci_regs[0x05] = val & 0x01; + return; + + case 0x07: + riva128->pci_regs[0x07] = (riva128->pci_regs[0x07] & 0x8f) | (val & 0x70); + return; + + case 0x13: + { + uint32_t mmio_addr; + riva128->pci_regs[addr] = val; + mmio_addr = riva128->pci_regs[0x13] << 24; + mem_mapping_disable(&riva128->mmio_mapping); + if (mmio_addr) + { + mem_mapping_set_addr(&riva128->mmio_mapping, mmio_addr, 0x1000000); + } + return; + } + + case 0x17: + { + uint32_t linear_addr; + riva128->pci_regs[addr] = val; + linear_addr = riva128->pci_regs[0x17] << 24; + mem_mapping_disable(&riva128->linear_mapping); + if (linear_addr) + { + mem_mapping_set_addr(&riva128->linear_mapping, linear_addr, 0x1000000); + svga->linear_base = linear_addr; + } + return; + } + + case 0x30: + case 0x32: + case 0x33: + riva128->pci_regs[addr] = val; + mem_mapping_disable(&riva128->bios_rom.mapping); + if (riva128->pci_regs[0x30] & 0x01) + { + uint32_t addr = (riva128->pci_regs[0x32] << 16) | (riva128->pci_regs[0x33] << 24); + // pclog("RIVA TNT bios_rom enabled at %08x\n", addr); + mem_mapping_set_addr(&riva128->bios_rom.mapping, addr, 0x10000); + } + return; + + /* case 0x3c: + riva128->pci_regs[0x3c] = val & 0x0f; + return; */ + + case 0x40: + case 0x41: + case 0x42: + case 0x43: + riva128->pci_regs[addr - 0x14] = val; //0x40-0x43 are ways to write to 0x2c-0x2f + return; + } +} + +static void riva128_recalctimings(svga_t *svga) +{ + riva128_t *riva128 = (riva128_t *)svga->p; + + svga->ma_latch += (svga->crtc[0x19] & 0x1f) << 16; + svga->rowoffset += (svga->crtc[0x19] & 0xe0) << 3; + if (svga->crtc[0x25] & 0x01) svga->vtotal += 0x400; + if (svga->crtc[0x25] & 0x02) svga->dispend += 0x400; + if (svga->crtc[0x25] & 0x04) svga->vblankstart += 0x400; + if (svga->crtc[0x25] & 0x08) svga->vsyncstart += 0x400; + if (svga->crtc[0x25] & 0x10) svga->htotal += 0x100; + if (svga->crtc[0x2d] & 0x01) svga->hdisp += 0x100; + //The effects of the large screen bit seem to just be doubling the row offset. + //However, these large modes still don't work. Possibly core SVGA bug? It does report 640x2 res after all. + if (!(svga->crtc[0x1a] & 0x04)) svga->rowoffset <<= 1; + switch(svga->crtc[0x28] & 3) + { + case 1: + svga->bpp = 8; + svga->lowres = 0; + svga->render = svga_render_8bpp_highres; + break; + case 2: + svga->bpp = 16; + svga->lowres = 0; + svga->render = svga_render_16bpp_highres; + break; + case 3: + svga->bpp = 32; + svga->lowres = 0; + svga->render = svga_render_32bpp_highres; + break; + } + + /*if((svga->crtc[0x28] & 3) != 0) + { + if(svga->crtc[0x1a] & 2) svga_set_ramdac_type(svga, RAMDAC_6BIT); + else svga_set_ramdac_type(svga, RAMDAC_8BIT); + } + else svga_set_ramdac_type(svga, RAMDAC_6BIT);*/ + + double freq; + + if (((svga->miscout >> 2) & 2) == 2) + { + freq = 13500000.0; + + if(riva128->pramdac.v_m == 0) freq = 0; + else + { + freq = (freq * riva128->pramdac.v_n) / (1 << riva128->pramdac.v_p) / riva128->pramdac.v_m; + //pclog("RIVA 128 Pixel clock is %f Hz\n", freq); + } + + svga->clock = cpuclock / freq; + } + + freq = 1350.0; + + if(riva128->pramdac.nv_m == 0) freq = 0; + else + { + freq = (freq * riva128->pramdac.nv_n) / (1 << riva128->pramdac.nv_p) / riva128->pramdac.nv_m; + //pclog("RIVA 128 Core clock is %f Hz\n", freq); + } + + riva128->mfreq = freq; + + freq = 1350.0; + + if(riva128->pramdac.m_m == 0) freq = 0; + else + { + freq = (freq * riva128->pramdac.m_n) / (1 << riva128->pramdac.m_p) / riva128->pramdac.m_m; + //pclog("RIVA 128 Core clock is %f Hz\n", freq); + } + + riva128->nvfreq = freq; +} + +static void *riva128_init() +{ + riva128_t *riva128 = malloc(sizeof(riva128_t)); + memset(riva128, 0, sizeof(riva128_t)); + + riva128->card_id = 0x03; + riva128->is_nv3t = 0; + + riva128->vendor_id = 0x12d2; + riva128->device_id = 0x0018; + + riva128->memory_size = device_get_config_int("memory"); + + svga_init(&riva128->svga, riva128, riva128->memory_size << 20, + riva128_recalctimings, + riva128_in, riva128_out, + NULL, NULL); + + rom_init(&riva128->bios_rom, L"roms/Diamond_V330_rev-e.vbi", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + if (PCI) + mem_mapping_disable(&riva128->bios_rom.mapping); + + mem_mapping_add(&riva128->mmio_mapping, 0, 0, + riva128_mmio_read, + riva128_mmio_read_w, + riva128_mmio_read_l, + riva128_mmio_write, + riva128_mmio_write_w, + riva128_mmio_write_l, + NULL, + 0, + riva128); + + mem_mapping_add(&riva128->ramin_mapping, 0, 0, + riva128_ramin_readb, + riva128_ramin_readw, + riva128_ramin_readl, + riva128_ramin_writeb, + riva128_ramin_writew, + riva128_ramin_writel, + NULL, + 0, + riva128); + + mem_mapping_add(&riva128->linear_mapping, 0, 0, + svga_read_linear, + svga_readw_linear, + svga_readl_linear, + svga_write_linear, + svga_writew_linear, + svga_writel_linear, + NULL, + 0, + &riva128->svga); + + io_sethandler(0x03c0, 0x0020, riva128_in, NULL, NULL, riva128_out, NULL, NULL, riva128); + + // riva128->pci_regs[4] = 3; + riva128->pci_regs[4] = 7; + riva128->pci_regs[5] = 0; + riva128->pci_regs[6] = 0; + riva128->pci_regs[7] = 2; + + riva128->pci_regs[0x2c] = 0xd2; + riva128->pci_regs[0x2d] = 0x12; + riva128->pci_regs[0x2e] = 0x00; + riva128->pci_regs[0x2f] = 0x03; + + riva128->pci_regs[0x30] = 0x00; + riva128->pci_regs[0x32] = 0x0c; + riva128->pci_regs[0x33] = 0x00; + + riva128->pci_regs[0x3c] = device_get_config_int("irq"); + + riva128->pmc.intr = 0; + riva128->pbus.intr = 0; + riva128->pfifo.intr = 0; + riva128->pgraph.intr = 0; + riva128->ptimer.intr = 0; + + pci_add(riva128_pci_read, riva128_pci_write, riva128); + + riva128->ptimer.clock_mul = 1; + riva128->ptimer.clock_div = 1; + + //Some bullshit default values so that the emulator won't shit itself trying to boot. These'll be overwritten by the video BIOS anyway. + riva128->pramdac.m_m = 0x03; + riva128->pramdac.m_n = 0xc2; + riva128->pramdac.m_p = 0x0d; + + riva128->pramdac.nv_m = 0x03; + riva128->pramdac.nv_n = 0xc2; + riva128->pramdac.nv_p = 0x0d; + + timer_add(riva128_mclk_poll, &riva128->mtime, TIMER_ALWAYS_ENABLED, riva128); + timer_add(riva128_nvclk_poll, &riva128->nvtime, TIMER_ALWAYS_ENABLED, riva128); + timer_add(riva128_vblank_poll, &riva128->svga.vidtime, TIMER_ALWAYS_ENABLED, riva128); + + return riva128; +} + +static void riva128_close(void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + FILE *f = fopen("vram.dmp", "wb"); + fwrite(riva128->svga.vram, 4 << 20, 1, f); + fclose(f); + + svga_close(&riva128->svga); + + free(riva128); +} + +static int riva128_available() +{ + return rom_present(L"roms/Diamond_V330_rev-e.vbi"); +} + +static void riva128_speed_changed(void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + + svga_recalctimings(&riva128->svga); +} + +static void riva128_force_redraw(void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + + riva128->svga.fullchange = changeframecount; +} + +static void riva128_add_status_info(char *s, int max_len, void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + + svga_add_status_info(s, max_len, &riva128->svga); +} + +static device_config_t riva128_config[] = +{ + { + "memory", "Memory size", CONFIG_SELECTION, "", 4, + { + { + "1 MB", 1 + }, + { + "2 MB", 2 + }, + { + "4 MB", 4 + }, + { + "" + } + }, + }, + { + "irq", "IRQ", CONFIG_SELECTION, "", 3, + { + { + "IRQ 3", 3 + }, + { + "IRQ 4", 4 + }, + { + "IRQ 5", 5 + }, + { + "IRQ 7", 7 + }, + { + "IRQ 9", 9 + }, + { + "IRQ 10", 10 + }, + { + "IRQ 11", 11 + }, + { + "IRQ 12", 12 + }, + { + "IRQ 14", 14 + }, + { + "IRQ 15", 15 + }, + { + "" + } + }, + }, + { + -1 + } +}; + +/*static device_config_t riva128zx_config[] = +{ + { + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "1 MB", + .value = 1 + }, + { + .description = "2 MB", + .value = 2 + }, + { + .description = "4 MB", + .value = 4 + }, + { + .description = "8 MB", + .value = 8 + }, + { + .description = "" + } + }, + .default_int = 4 + }, + { + .name = "irq", + .description = "IRQ", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "IRQ 3", + .value = 3 + }, + { + .description = "IRQ 4", + .value = 4 + }, + { + .description = "IRQ 5", + .value = 5 + }, + { + .description = "IRQ 7", + .value = 7 + }, + { + .description = "IRQ 9", + .value = 9 + }, + { + .description = "IRQ 10", + .value = 10 + }, + { + .description = "IRQ 11", + .value = 11 + }, + { + .description = "IRQ 12", + .value = 12 + }, + { + .description = "IRQ 14", + .value = 14 + }, + { + .description = "IRQ 15", + .value = 15 + }, + { + .description = "" + } + }, + .default_int = 3 + }, + { + .type = -1 + } +};*/ + +device_t riva128_device = +{ + "nVidia RIVA 128", + 0, + riva128_init, + riva128_close, + riva128_available, + riva128_speed_changed, + riva128_force_redraw, + riva128_add_status_info, + riva128_config +}; + +static void *rivatnt_init() +{ + riva128_t *riva128 = malloc(sizeof(riva128_t)); + memset(riva128, 0, sizeof(riva128_t)); + + riva128->card_id = 0x04; + riva128->is_nv3t = 0; + + riva128->vendor_id = 0x10de; + riva128->device_id = 0x0020; + + riva128->memory_size = device_get_config_int("memory"); + + svga_init(&riva128->svga, riva128, riva128->memory_size << 20, + riva128_recalctimings, + riva128_in, riva128_out, + NULL, NULL); + + rom_init(&riva128->bios_rom, L"roms/NV4_diamond_revB.rom", 0xc0000, 0x10000, 0xffff, 0, MEM_MAPPING_EXTERNAL); + if (PCI) + mem_mapping_disable(&riva128->bios_rom.mapping); + + mem_mapping_add(&riva128->mmio_mapping, 0, 0, + riva128_mmio_read, + riva128_mmio_read_w, + riva128_mmio_read_l, + riva128_mmio_write, + riva128_mmio_write_w, + riva128_mmio_write_l, + NULL, + 0, + riva128); + mem_mapping_add(&riva128->linear_mapping, 0, 0, + svga_read_linear, + svga_readw_linear, + svga_readl_linear, + svga_write_linear, + svga_writew_linear, + svga_writel_linear, + NULL, + 0, + &riva128->svga); + + io_sethandler(0x03c0, 0x0020, riva128_in, NULL, NULL, riva128_out, NULL, NULL, riva128); + + // riva128->pci_regs[4] = 3; + riva128->pci_regs[4] = 7; + riva128->pci_regs[5] = 0; + riva128->pci_regs[6] = 0; + riva128->pci_regs[7] = 2; + + riva128->pci_regs[0x2c] = 0x02; + riva128->pci_regs[0x2d] = 0x11; + riva128->pci_regs[0x2e] = 0x16; + riva128->pci_regs[0x2f] = 0x10; + + riva128->pci_regs[0x30] = 0x00; + riva128->pci_regs[0x32] = 0x0c; + riva128->pci_regs[0x33] = 0x00; + + riva128->pci_regs[0x3c] = device_get_config_int("irq"); + + riva128->pmc.intr = 0; + riva128->pbus.intr = 0; + riva128->pfifo.intr = 0; + riva128->pgraph.intr = 0; + + pci_add(riva128_pci_read, rivatnt_pci_write, riva128); + + //Some bullshit default values so that the emulator won't shit itself trying to boot. These'll be overwritten by the video BIOS anyway. + riva128->pramdac.m_m = 0x03; + riva128->pramdac.m_n = 0xc2; + riva128->pramdac.m_p = 0x0d; + + riva128->pramdac.nv_m = 0x03; + riva128->pramdac.nv_n = 0xc2; + riva128->pramdac.nv_p = 0x0d; + + timer_add(riva128_mclk_poll, &riva128->mtime, TIMER_ALWAYS_ENABLED, riva128); + timer_add(riva128_nvclk_poll, &riva128->nvtime, TIMER_ALWAYS_ENABLED, riva128); + timer_add(riva128_vblank_poll, &riva128->svga.vidtime, TIMER_ALWAYS_ENABLED, riva128); + + return riva128; +} + +static void rivatnt_close(void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + FILE *f = fopen("vram.dmp", "wb"); + fwrite(riva128->svga.vram, 4 << 20, 1, f); + fclose(f); + + svga_close(&riva128->svga); + + free(riva128); +} + +static int rivatnt_available() +{ + return rom_present(L"roms/NV4_diamond_revB.rom"); +} + +static void rivatnt_speed_changed(void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + + svga_recalctimings(&riva128->svga); +} + +static void rivatnt_force_redraw(void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + + riva128->svga.fullchange = changeframecount; +} + +static void rivatnt_add_status_info(char *s, int max_len, void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + + svga_add_status_info(s, max_len, &riva128->svga); +} + +static device_config_t rivatnt_config[] = +{ + { + "memory", "Memory size", CONFIG_SELECTION, "", 16, + { + { + "4 MB", 4 + }, + { + "8 MB", 8 + }, + { + "16 MB", 16 + }, + { + "" + } + }, + }, + { + "irq", "IRQ", CONFIG_SELECTION, "", 3, + { + { + "IRQ 3", 3 + }, + { + "IRQ 4", 4 + }, + { + "IRQ 5", 5 + }, + { + "IRQ 7", 7 + }, + { + "IRQ 9", 9 + }, + { + "IRQ 10", 10 + }, + { + "IRQ 11", 11 + }, + { + "IRQ 12", 12 + }, + { + "IRQ 14", 14 + }, + { + "IRQ 15", 15 + }, + { + "" + } + }, + }, + { + -1 + } +}; + +device_t rivatnt_device = +{ + "nVidia RIVA TNT", + 0, + rivatnt_init, + rivatnt_close, + rivatnt_available, + rivatnt_speed_changed, + rivatnt_force_redraw, + rivatnt_add_status_info, + rivatnt_config +}; + +static void *rivatnt2_init() +{ + riva128_t *riva128 = malloc(sizeof(riva128_t)); + memset(riva128, 0, sizeof(riva128_t)); + + riva128->card_id = 0x05; + riva128->is_nv3t = 0; + + int model = device_get_config_int("model"); + + riva128->vendor_id = 0x10de; + riva128->device_id = ((model > 1) ? 0x0029 : 0x0028); + + riva128->memory_size = device_get_config_int("memory"); + + svga_init(&riva128->svga, riva128, riva128->memory_size << 20, + riva128_recalctimings, + riva128_in, riva128_out, + NULL, NULL); + + switch(model) + { + case 0: + rom_init(&riva128->bios_rom, L"roms/NV5diamond.bin", 0xc0000, 0x10000, 0xffff, 0, MEM_MAPPING_EXTERNAL); + break; + case 1: + rom_init(&riva128->bios_rom, L"roms/inno3d64bit.BIN", 0xc0000, 0x10000, 0xffff, 0, MEM_MAPPING_EXTERNAL); + break; + case 2: + rom_init(&riva128->bios_rom, L"roms/creative.BIN", 0xc0000, 0x10000, 0xffff, 0, MEM_MAPPING_EXTERNAL); + break; + } + if (PCI) + mem_mapping_disable(&riva128->bios_rom.mapping); + + mem_mapping_add(&riva128->mmio_mapping, 0, 0, + riva128_mmio_read, + riva128_mmio_read_w, + riva128_mmio_read_l, + riva128_mmio_write, + riva128_mmio_write_w, + riva128_mmio_write_l, + NULL, + 0, + riva128); + mem_mapping_add(&riva128->linear_mapping, 0, 0, + svga_read_linear, + svga_readw_linear, + svga_readl_linear, + svga_write_linear, + svga_writew_linear, + svga_writel_linear, + NULL, + 0, + &riva128->svga); + + io_sethandler(0x03c0, 0x0020, riva128_in, NULL, NULL, riva128_out, NULL, NULL, riva128); + + // riva128->pci_regs[4] = 3; + riva128->pci_regs[4] = 7; + riva128->pci_regs[5] = 0; + riva128->pci_regs[6] = 0; + riva128->pci_regs[7] = 2; + + riva128->pci_regs[0x2c] = 0x02; + riva128->pci_regs[0x2d] = 0x11; + riva128->pci_regs[0x2e] = 0x16; + riva128->pci_regs[0x2f] = 0x10; + + riva128->pci_regs[0x30] = 0x00; + riva128->pci_regs[0x32] = 0x0c; + riva128->pci_regs[0x33] = 0x00; + + riva128->pci_regs[0x3c] = device_get_config_int("irq"); + + riva128->pmc.intr = 0; + riva128->pbus.intr = 0; + riva128->pfifo.intr = 0; + riva128->pgraph.intr = 0; + + pci_add(riva128_pci_read, rivatnt_pci_write, riva128); + + //Some bullshit default values so that the emulator won't shit itself trying to boot. These'll be overwritten by the video BIOS anyway. + riva128->pramdac.m_m = 0x03; + riva128->pramdac.m_n = 0xc2; + riva128->pramdac.m_p = 0x0d; + + riva128->pramdac.nv_m = 0x03; + riva128->pramdac.nv_n = 0xc2; + riva128->pramdac.nv_p = 0x0d; + + timer_add(riva128_mclk_poll, &riva128->mtime, TIMER_ALWAYS_ENABLED, riva128); + timer_add(riva128_nvclk_poll, &riva128->nvtime, TIMER_ALWAYS_ENABLED, riva128); + timer_add(riva128_vblank_poll, &riva128->svga.vidtime, TIMER_ALWAYS_ENABLED, riva128); + + return riva128; +} + +static void rivatnt2_close(void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + FILE *f = fopen("vram.dmp", "wb"); + fwrite(riva128->svga.vram, 4 << 20, 1, f); + fclose(f); + + svga_close(&riva128->svga); + + free(riva128); +} + +static int rivatnt2_available() +{ + return rom_present(L"roms/NV5diamond.bin") || rom_present(L"roms/inno3d64bit.BIN") || rom_present(L"roms/creative.BIN"); +} + +static void rivatnt2_speed_changed(void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + + svga_recalctimings(&riva128->svga); +} + +static void rivatnt2_force_redraw(void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + + riva128->svga.fullchange = changeframecount; +} + +static void rivatnt2_add_status_info(char *s, int max_len, void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + + svga_add_status_info(s, max_len, &riva128->svga); +} + +static device_config_t rivatnt2_config[] = +{ + { + "model", "Card model", CONFIG_SELECTION, "", 0, + { + { + "Vanilla TNT2", 0, + }, + { + "TNT2 Pro", 1, + }, + { + "TNT2 Ultra", 2, + }, + }, + }, + { + "memory", "Memory size", CONFIG_SELECTION, "", 32, + { + { + "4 MB", 4 + }, + { + "8 MB", 8 + }, + { + "16 MB", 16 + }, + { + "32 MB", 32 + }, + { + "" + } + }, + }, + { + "irq", "IRQ", CONFIG_SELECTION, "", 3, + { + { + "IRQ 3", 3 + }, + { + "IRQ 4", 4 + }, + { + "IRQ 5", 5 + }, + { + "IRQ 7", 7 + }, + { + "IRQ 9", 9 + }, + { + "IRQ 10", 10 + }, + { + "IRQ 11", 11 + }, + { + "IRQ 12", 12 + }, + { + "IRQ 14", 14 + }, + { + "IRQ 15", 15 + }, + { + "" + } + }, + }, + { + "", "", -1 + } +}; + +device_t rivatnt2_device = +{ + "nVidia RIVA TNT2", + 0, + rivatnt2_init, + rivatnt2_close, + rivatnt2_available, + rivatnt2_speed_changed, + rivatnt2_force_redraw, + rivatnt2_add_status_info, + rivatnt2_config +}; + diff --git a/src/vid_nv_riva128.h b/src/VIDEO/vid_nv_riva128.h similarity index 100% rename from src/vid_nv_riva128.h rename to src/VIDEO/vid_nv_riva128.h diff --git a/src/vid_olivetti_m24.c b/src/VIDEO/vid_olivetti_m24.c similarity index 96% rename from src/vid_olivetti_m24.c rename to src/VIDEO/vid_olivetti_m24.c index cc80b7f12..f130c69fb 100644 --- a/src/vid_olivetti_m24.c +++ b/src/VIDEO/vid_olivetti_m24.c @@ -4,14 +4,15 @@ /*Olivetti M24 video emulation Essentially double-res CGA*/ #include -#include "ibm.h" -#include "device.h" -#include "io.h" -#include "mem.h" -#include "timer.h" +#include "../ibm.h" +#include "../io.h" +#include "../mem.h" +#include "../timer.h" +#include "../device.h" #include "video.h" #include "vid_olivetti_m24.h" + typedef struct m24_t { mem_mapping_t mapping; @@ -55,7 +56,6 @@ void m24_out(uint16_t addr, uint8_t val, void *p) { m24_t *m24 = (m24_t *)p; uint8_t old; -// pclog("m24_out %04X %02X\n", addr, val); switch (addr) { case 0x3d4: @@ -129,10 +129,8 @@ void m24_recalctimings(m24_t *m24) _dispontime = m24->crtc[1] << 1; } _dispofftime = disptime - _dispontime; -// printf("%i %f %f %f %i %i\n",cgamode&1,disptime,dispontime,dispofftime,crtc[0],crtc[1]); _dispontime *= CGACONST / 2; _dispofftime *= CGACONST / 2; -// printf("Timings - on %f off %f frame %f second %f\n",dispontime,dispofftime,(dispontime+dispofftime)*262.0,(dispontime+dispofftime)*262.0*59.92); m24->dispontime = (int)(_dispontime * (1 << TIMER_SHIFT)); m24->dispofftime = (int)(_dispofftime * (1 << TIMER_SHIFT)); } @@ -151,7 +149,6 @@ void m24_poll(void *p) int oldsc; if (!m24->linepos) { -// pclog("Line poll %i %i %i %i - %04X %i %i %i\n", m24_lineff, vc, sc, vadj, ma, firstline, lastline, displine); m24->vidtime += m24->dispofftime; m24->stat |= 1; m24->linepos = 1; @@ -160,11 +157,9 @@ void m24_poll(void *p) m24->sc = (m24->sc << 1) & 7; if (m24->dispon) { - pclog("dispon %i\n", m24->linepos); if (m24->displine < m24->firstline) { m24->firstline = m24->displine; -// printf("Firstline %i\n",firstline); } m24->lastline = m24->displine; for (c = 0; c < 8; c++) @@ -325,7 +320,6 @@ void m24_poll(void *p) } else { -// pclog("Line poll %i %i %i %i\n", m24_lineff, vc, sc, vadj); m24->vidtime += m24->dispontime; if (m24->dispon) m24->stat &= ~1; m24->linepos = 0; @@ -453,7 +447,6 @@ void m24_poll(void *p) void *m24_init() { - int c; m24_t *m24 = malloc(sizeof(m24_t)); memset(m24, 0, sizeof(m24_t)); diff --git a/src/vid_olivetti_m24.h b/src/VIDEO/vid_olivetti_m24.h similarity index 100% rename from src/vid_olivetti_m24.h rename to src/VIDEO/vid_olivetti_m24.h diff --git a/src/vid_oti067.c b/src/VIDEO/vid_oti067.c similarity index 75% rename from src/vid_oti067.c rename to src/VIDEO/vid_oti067.c index 6ded38b35..c04a43778 100644 --- a/src/vid_oti067.c +++ b/src/VIDEO/vid_oti067.c @@ -3,15 +3,16 @@ */ /*Oak OTI067 emulation*/ #include -#include "ibm.h" -#include "device.h" -#include "io.h" -#include "mem.h" -#include "rom.h" +#include "../ibm.h" +#include "../io.h" +#include "../mem.h" +#include "../rom.h" +#include "../device.h" #include "video.h" #include "vid_oti067.h" #include "vid_svga.h" + typedef struct oti067_t { svga_t svga; @@ -35,8 +36,6 @@ void oti067_out(uint16_t addr, uint8_t val, void *p) svga_t *svga = &oti067->svga; uint8_t old; -// pclog("oti067_out : %04X %02X %02X %i\n", addr, val, ram[0x489], ins); - if ((((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && addr < 0x3de) && !(svga->miscout & 1)) addr ^= 0x60; switch (addr) @@ -95,8 +94,6 @@ uint8_t oti067_in(uint16_t addr, void *p) svga_t *svga = &oti067->svga; uint8_t temp; -// if (addr != 0x3da && addr != 0x3ba) pclog("oti067_in : %04X ", addr); - if ((((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && addr < 0x3de) && !(svga->miscout & 1)) addr ^= 0x60; switch (addr) @@ -110,7 +107,6 @@ uint8_t oti067_in(uint16_t addr, void *p) case 0x3DE: temp = oti067->index | (oti067->chip_id << 5); - // temp = oti067->index | (2 << 5); break; case 0x3DF: if (oti067->index==0x10) temp = 0x18; @@ -121,7 +117,6 @@ uint8_t oti067_in(uint16_t addr, void *p) temp = svga_in(addr, svga); break; } -// if (addr != 0x3da && addr != 0x3ba) pclog("%02X %04X:%04X\n", temp, CS,pc); return temp; } @@ -153,7 +148,6 @@ void oti067_recalctimings(svga_t *svga) if (oti067->regs[0x14] & 0x08) svga->ma_latch |= 0x10000; if (oti067->regs[0x0d] & 0x0c) svga->rowoffset <<= 1; - // svga->interlace = oti067->regs[0x14] & 0x80; if (oti067->regs[0x14] & 0x80) { svga->vtotal *= 2; @@ -164,7 +158,7 @@ void oti067_recalctimings(svga_t *svga) } } -void *oti067_common_init(char *bios_fn, int vram_size, int chip_id) +void *oti067_common_init(wchar_t *bios_fn, int vram_size, int chip_id) { oti067_t *oti067 = malloc(sizeof(oti067_t)); memset(oti067, 0, sizeof(oti067_t)); @@ -192,33 +186,23 @@ void *oti067_common_init(char *bios_fn, int vram_size, int chip_id) void *oti067_init() { int vram_size = device_get_config_int("memory"); - return oti067_common_init("roms/oti067/bios.bin", vram_size, 2); + return oti067_common_init(L"roms/oti067/bios.bin", vram_size, 2); } void *oti077_init() { int vram_size = device_get_config_int("memory"); - return oti067_common_init("roms/oti077.vbi", vram_size, 5); -} - -void *oti067_acer386_init() -{ - oti067_t *oti067 = oti067_common_init("roms/acer386/oti067.bin", 512, 2); - - if (oti067) - oti067->bios_rom.rom[0x5d] = 0x74; - - return oti067; + return oti067_common_init(L"roms/oti077.vbi", vram_size, 5); } static int oti067_available() { - return rom_present("roms/oti067/bios.bin"); + return rom_present(L"roms/oti067/bios.bin"); } static int oti077_available() { - return rom_present("roms/oti077.vbi"); + return rom_present(L"roms/oti077.vbi"); } void oti067_close(void *p) @@ -254,58 +238,45 @@ void oti067_add_status_info(char *s, int max_len, void *p) static device_config_t oti067_config[] = { { - .name = "memory", - .description = "Memory size", - .type = CONFIG_SELECTION, - .selection = + "memory", "Memory size", CONFIG_SELECTION, "", 512, { { - .description = "256 kB", - .value = 256 + "256 kB", 256 }, { - .description = "512 kB", - .value = 512 + "512 kB", 512 }, { - .description = "" + "" } - }, - .default_int = 512 + } }, { - .type = -1 + "", "", -1 } }; static device_config_t oti077_config[] = { { - .name = "memory", - .description = "Memory size", - .type = CONFIG_SELECTION, - .selection = + "memory", "Memory size", CONFIG_SELECTION, "", 1024, { { - .description = "256 kB", - .value = 256 + "256 kB", 256 }, { - .description = "512 kB", - .value = 512 + "512 kB", 512 }, { - .description = "1 MB", - .value = 1024 + "1 MB", 1024 }, { - .description = "" + "" } - }, - .default_int = 1024 + } }, { - .type = -1 + "", "", -1 } }; @@ -321,17 +292,6 @@ device_t oti067_device = oti067_add_status_info, oti067_config }; -device_t oti067_acer386_device = -{ - "Oak OTI-067 (Acermate 386SX/25N)", - 0, - oti067_acer386_init, - oti067_close, - oti067_available, - oti067_speed_changed, - oti067_force_redraw, - oti067_add_status_info -}; device_t oti077_device = { "Oak OTI-077", diff --git a/src/vid_oti067.h b/src/VIDEO/vid_oti067.h similarity index 85% rename from src/vid_oti067.h rename to src/VIDEO/vid_oti067.h index 4ac802657..b9ac2dfcb 100644 --- a/src/vid_oti067.h +++ b/src/VIDEO/vid_oti067.h @@ -1,6 +1,7 @@ /* Copyright holders: Sarah Walker, Tenshi see COPYING for more details */ +extern device_t oti037_device; extern device_t oti067_device; extern device_t oti067_acer386_device; extern device_t oti077_device; diff --git a/src/vid_paradise.c b/src/VIDEO/vid_paradise.c similarity index 88% rename from src/vid_paradise.c rename to src/VIDEO/vid_paradise.c index 218f6683d..4527619fe 100644 --- a/src/vid_paradise.c +++ b/src/VIDEO/vid_paradise.c @@ -7,16 +7,18 @@ MegaPC uses W90C11A */ #include -#include "ibm.h" -#include "device.h" -#include "mem.h" -#include "rom.h" +#include "../ibm.h" +#include "../io.h" +#include "../mem.h" +#include "../rom.h" +#include "../device.h" #include "video.h" #include "vid_paradise.h" #include "vid_svga.h" #include "vid_svga_render.h" #include "vid_unk_ramdac.h" + typedef struct paradise_t { svga_t svga; @@ -45,8 +47,6 @@ void paradise_out(uint16_t addr, uint8_t val, void *p) if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) addr ^= 0x60; -// output = 3; -// pclog("Paradise out %04X %02X %04X:%04X\n", addr, val, CS, pc); switch (addr) { case 0x3c5: @@ -71,7 +71,6 @@ void paradise_out(uint16_t addr, uint8_t val, void *p) { if ((svga->gdcreg[6] & 0xc) != (val & 0xc)) { -// pclog("Write mapping %02X\n", val); switch (val&0xC) { case 0x0: /*128k at A0000*/ @@ -151,7 +150,6 @@ uint8_t paradise_in(uint16_t addr, void *p) if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) addr ^= 0x60; -// if (addr != 0x3da) pclog("Paradise in %04X\n", addr); switch (addr) { case 0x3c2: @@ -197,7 +195,6 @@ void paradise_remap(paradise_t *paradise) if (svga->seqregs[0x11] & 0x80) { -// pclog("Remap 1\n"); paradise->read_bank[0] = paradise->read_bank[2] = (svga->gdcreg[0x9] & 0x7f) << 12; paradise->read_bank[1] = paradise->read_bank[3] = ((svga->gdcreg[0x9] & 0x7f) << 12) + ((svga->gdcreg[6] & 0x08) ? 0 : 0x8000); paradise->write_bank[0] = paradise->write_bank[2] = (svga->gdcreg[0xa] & 0x7f) << 12; @@ -207,7 +204,6 @@ void paradise_remap(paradise_t *paradise) { if (svga->gdcreg[0x6] & 0xc) { -// pclog("Remap 2\n"); paradise->read_bank[0] = paradise->read_bank[2] = (svga->gdcreg[0xa] & 0x7f) << 12; paradise->write_bank[0] = paradise->write_bank[2] = (svga->gdcreg[0xa] & 0x7f) << 12; paradise->read_bank[1] = paradise->read_bank[3] = ((svga->gdcreg[0x9] & 0x7f) << 12) + ((svga->gdcreg[6] & 0x08) ? 0 : 0x8000); @@ -215,7 +211,6 @@ void paradise_remap(paradise_t *paradise) } else { -// pclog("Remap 3\n"); paradise->read_bank[0] = paradise->write_bank[0] = (svga->gdcreg[0xa] & 0x7f) << 12; paradise->read_bank[1] = paradise->write_bank[1] = ((svga->gdcreg[0xa] & 0x7f) << 12) + ((svga->gdcreg[6] & 0x08) ? 0 : 0x8000); paradise->read_bank[2] = paradise->write_bank[2] = (svga->gdcreg[0x9] & 0x7f) << 12; @@ -224,13 +219,11 @@ void paradise_remap(paradise_t *paradise) } else { - // pclog("Remap 4\n"); paradise->read_bank[0] = paradise->read_bank[2] = (svga->gdcreg[0x9] & 0x7f) << 12; paradise->read_bank[1] = paradise->read_bank[3] = ((svga->gdcreg[0x9] & 0x7f) << 12) + ((svga->gdcreg[6] & 0x08) ? 0 : 0x8000); paradise->write_bank[0] = paradise->write_bank[2] = (svga->gdcreg[0x9] & 0x7f) << 12; paradise->write_bank[1] = paradise->write_bank[3] = ((svga->gdcreg[0x9] & 0x7f) << 12) + ((svga->gdcreg[6] & 0x08) ? 0 : 0x8000); } -// pclog("Remap - %04X %04X\n", paradise->read_bank[0], paradise->write_bank[0]); } void paradise_recalctimings(svga_t *svga) @@ -243,9 +236,8 @@ void paradise_recalctimings(svga_t *svga) void paradise_write(uint32_t addr, uint8_t val, void *p) { paradise_t *paradise = (paradise_t *)p; -// pclog("paradise_write : %05X %02X ", addr, val); addr = (addr & 0x7fff) + paradise->write_bank[(addr >> 15) & 3]; -// pclog("%08X\n", addr); + /* Horrible hack, I know, but it's the only way to fix the 440FX BIOS filling the VRAM with garbage until Tom fixes the memory emulation. */ if ((cs == 0xE0000) && (cpu_state.pc == 0xBF2F) && (romset == ROM_440FX)) return; if ((cs == 0xE0000) && (cpu_state.pc == 0xBF77) && (romset == ROM_440FX)) return; @@ -255,9 +247,7 @@ void paradise_write(uint32_t addr, uint8_t val, void *p) uint8_t paradise_read(uint32_t addr, void *p) { paradise_t *paradise = (paradise_t *)p; -// pclog("paradise_read : %05X ", addr); addr = (addr & 0x7fff) + paradise->read_bank[(addr >> 15) & 3]; -// pclog("%08X\n", addr); return svga_read_linear(addr, ¶dise->svga); } @@ -334,7 +324,7 @@ static void *paradise_pvga1a_pc2086_init() paradise_t *paradise = paradise_pvga1a_init(); if (paradise) - rom_init(¶dise->bios_rom, "roms/pc2086/40186.ic171", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + rom_init(¶dise->bios_rom, L"roms/pc2086/40186.ic171", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); return paradise; } @@ -343,7 +333,7 @@ static void *paradise_pvga1a_pc3086_init() paradise_t *paradise = paradise_pvga1a_init(); if (paradise) - rom_init(¶dise->bios_rom, "roms/pc3086/c000.bin", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + rom_init(¶dise->bios_rom, L"roms/pc3086/c000.bin", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); return paradise; } @@ -354,8 +344,8 @@ static void *paradise_wd90c11_megapc_init() if (paradise) rom_init_interleaved(¶dise->bios_rom, - "roms/megapc/41651-bios lo.u18", - "roms/megapc/211253-bios hi.u19", + L"roms/megapc/41651-bios lo.u18", + L"roms/megapc/211253-bios hi.u19", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); return paradise; @@ -363,22 +353,7 @@ static void *paradise_wd90c11_megapc_init() static int paradise_wd90c11_standalone_available() { - return rom_present("roms/megapc/41651-bios lo.u18") && rom_present("roms/megapc/211253-bios hi.u19"); -} - -static void *cpqvga_init() -{ - paradise_t *paradise = paradise_pvga1a_init(); - - if (paradise) - rom_init(¶dise->bios_rom, "roms/1988-05-18.rom", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); - - return paradise; -} - -static int cpqvga_standalone_available() -{ - return rom_present("roms/1988-05-18.rom"); + return rom_present(L"roms/megapc/41651-bios lo.u18") && rom_present(L"roms/megapc/211253-bios hi.u19"); } void paradise_close(void *p) @@ -455,14 +430,3 @@ device_t paradise_wd90c11_device = paradise_force_redraw, paradise_add_status_info }; -device_t cpqvga_device = -{ - "Compaq/Paradise VGA", - 0, - cpqvga_init, - paradise_close, - cpqvga_standalone_available, - paradise_speed_changed, - paradise_force_redraw, - paradise_add_status_info -}; diff --git a/src/vid_paradise.h b/src/VIDEO/vid_paradise.h similarity index 89% rename from src/vid_paradise.h rename to src/VIDEO/vid_paradise.h index 63503670c..83dd1042b 100644 --- a/src/vid_paradise.h +++ b/src/VIDEO/vid_paradise.h @@ -5,4 +5,3 @@ extern device_t paradise_pvga1a_pc2086_device; extern device_t paradise_pvga1a_pc3086_device; extern device_t paradise_wd90c11_megapc_device; extern device_t paradise_wd90c11_device; -extern device_t cpqvga_device; diff --git a/src/vid_pc1512.c b/src/VIDEO/vid_pc1512.c similarity index 93% rename from src/vid_pc1512.c rename to src/VIDEO/vid_pc1512.c index 5f75ed157..832bde2ea 100644 --- a/src/vid_pc1512.c +++ b/src/VIDEO/vid_pc1512.c @@ -10,14 +10,15 @@ The Technical Reference Manual lists the video waitstate time as between 12 and 46 cycles. PCem currently always uses the lower number.*/ #include -#include "ibm.h" -#include "device.h" -#include "io.h" -#include "mem.h" -#include "timer.h" +#include "../ibm.h" +#include "../io.h" +#include "../mem.h" +#include "../timer.h" +#include "../device.h" #include "video.h" #include "vid_pc1512.h" + typedef struct pc1512_t { mem_mapping_t mapping; @@ -57,7 +58,6 @@ static void pc1512_out(uint16_t addr, uint8_t val, void *p) { pc1512_t *pc1512 = (pc1512_t *)p; uint8_t old; -// pclog("PC1512 out %04X %02X %04X:%04X\n",addr,val,CS,pc); switch (addr) { case 0x3d4: @@ -101,7 +101,6 @@ static void pc1512_out(uint16_t addr, uint8_t val, void *p) static uint8_t pc1512_in(uint16_t addr, void *p) { pc1512_t *pc1512 = (pc1512_t *)p; -// pclog("PC1512 in %04X %02X %04X:%04X\n",addr,CS,pc); switch (addr) { case 0x3d4: @@ -153,10 +152,8 @@ static void pc1512_recalctimings(pc1512_t *pc1512) disptime = 128; /*Fixed on PC1512*/ _dispontime = 80; _dispofftime = disptime - _dispontime; -// printf("%i %f %f %f %i %i\n",cgamode&1,disptime,dispontime,dispofftime,crtc[0],crtc[1]); _dispontime *= CGACONST; _dispofftime *= CGACONST; -// printf("Timings - on %f off %f frame %f second %f\n",dispontime,dispofftime,(dispontime+dispofftime)*262.0,(dispontime+dispofftime)*262.0*59.92); pc1512->dispontime = (int)(_dispontime * (1 << TIMER_SHIFT)); pc1512->dispofftime = (int)(_dispofftime * (1 << TIMER_SHIFT)); } @@ -167,7 +164,6 @@ static void pc1512_poll(void *p) uint16_t ca = (pc1512->crtc[15] | (pc1512->crtc[14] << 8)) & 0x3fff; int drawcursor; int x, c; - int oldvc; uint8_t chr, attr; uint16_t dat, dat2, dat3, dat4; int cols[4]; @@ -338,7 +334,6 @@ static void pc1512_poll(void *p) pc1512->displine++; if (pc1512->displine >= 360) pc1512->displine = 0; -// pclog("Line %i %i %i %i %i %i\n",displine,cgadispon,firstline,lastline,vc,sc); } else { @@ -376,11 +371,10 @@ static void pc1512_poll(void *p) { pc1512->maback = pc1512->ma; pc1512->sc = 0; - oldvc = pc1512->vc; pc1512->vc++; pc1512->vc &= 127; - if (pc1512->displine == 32)//oldvc == (cgamode & 2) ? 127 : 31) + if (pc1512->displine == 32) { pc1512->vc = 0; pc1512->vadj = 6; @@ -388,7 +382,7 @@ static void pc1512_poll(void *p) else pc1512->cursoron = pc1512->blink & 16; } - if (pc1512->displine >= 262)//vc == (cgamode & 2) ? 111 : 27) + if (pc1512->displine >= 262) { pc1512->dispon = 0; pc1512->displine = 0; @@ -409,11 +403,6 @@ static void pc1512_poll(void *p) } video_blit_memtoscreen_8(0, pc1512->firstline - 4, xsize, (pc1512->lastline - pc1512->firstline) + 8); -// blit(buffer,vbuf,0,firstline-4,0,0,xsize,(lastline-firstline)+8+1); -// if (vid_resize) stretch_blit(vbuf,screen,0,0,xsize,(lastline-firstline)+8+1,0,0,winsizex,winsizey); -// else stretch_blit(vbuf,screen,0,0,xsize,(lastline-firstline)+8+1,0,0,xsize,((lastline-firstline)<<1)+16+2); -// if (readflash) rectfill(screen,winsizex-40,8,winsizex-8,14,0xFFFFFFFF); -// readflash=0; video_res_x = xsize - 16; video_res_y = ysize; @@ -457,7 +446,6 @@ static void pc1512_poll(void *p) static void *pc1512_init() { - int c; pc1512_t *pc1512 = malloc(sizeof(pc1512_t)); memset(pc1512, 0, sizeof(pc1512_t)); diff --git a/src/vid_pc1512.h b/src/VIDEO/vid_pc1512.h similarity index 100% rename from src/vid_pc1512.h rename to src/VIDEO/vid_pc1512.h diff --git a/src/vid_pc1640.c b/src/VIDEO/vid_pc1640.c similarity index 95% rename from src/vid_pc1640.c rename to src/VIDEO/vid_pc1640.c index 610f322c0..3db12e57d 100644 --- a/src/vid_pc1640.c +++ b/src/VIDEO/vid_pc1640.c @@ -4,17 +4,18 @@ /*PC1640 video emulation. Mostly standard EGA, but with CGA & Hercules emulation*/ #include -#include "ibm.h" -#include "device.h" -#include "io.h" -#include "mem.h" -#include "rom.h" -#include "timer.h" +#include "../ibm.h" +#include "../io.h" +#include "../mem.h" +#include "../rom.h" +#include "../timer.h" +#include "../device.h" #include "video.h" #include "vid_cga.h" #include "vid_ega.h" #include "vid_pc1640.h" + typedef struct pc1640_t { mem_mapping_t cga_mapping; @@ -125,7 +126,7 @@ void *pc1640_init() ega_t *ega = &pc1640->ega; memset(pc1640, 0, sizeof(pc1640_t)); - rom_init(&pc1640->bios_rom, "roms/pc1640/40100", 0xc0000, 0x8000, 0x7fff, 0, 0); + rom_init(&pc1640->bios_rom, L"roms/pc1640/40100", 0xc0000, 0x8000, 0x7fff, 0, 0); ega_init(&pc1640->ega); pc1640->cga.vram = pc1640->ega.vram; diff --git a/src/vid_pc1640.h b/src/VIDEO/vid_pc1640.h similarity index 100% rename from src/vid_pc1640.h rename to src/VIDEO/vid_pc1640.h diff --git a/src/vid_pc200.c b/src/VIDEO/vid_pc200.c similarity index 97% rename from src/vid_pc200.c rename to src/VIDEO/vid_pc200.c index 99eeb3171..eef181c33 100644 --- a/src/vid_pc200.c +++ b/src/VIDEO/vid_pc200.c @@ -5,15 +5,16 @@ CGA with some NMI stuff. But we don't need that as it's only used for TV and LCD displays, and we're emulating a CRT*/ #include -#include "ibm.h" -#include "device.h" -#include "io.h" -#include "mem.h" -#include "timer.h" +#include "../ibm.h" +#include "../io.h" +#include "../mem.h" +#include "../timer.h" +#include "../device.h" #include "video.h" #include "vid_cga.h" #include "vid_pc200.h" + typedef struct pc200_t { mem_mapping_t mapping; diff --git a/src/vid_pc200.h b/src/VIDEO/vid_pc200.h similarity index 100% rename from src/vid_pc200.h rename to src/VIDEO/vid_pc200.h diff --git a/src/vid_pcjr.c b/src/VIDEO/vid_pcjr.c similarity index 87% rename from src/vid_pcjr.c rename to src/VIDEO/vid_pcjr.c index de5c1bc94..0557967d9 100644 --- a/src/vid_pcjr.c +++ b/src/VIDEO/vid_pcjr.c @@ -1,16 +1,20 @@ #include #include -#include "ibm.h" -#include "device.h" -#include "io.h" -#include "mem.h" -#include "timer.h" +#include "../ibm.h" +#include "../io.h" +#include "../mem.h" +#include "../pic.h" +#include "../timer.h" +#include "../device.h" #include "video.h" +#include "vid_cga_comp.h" #include "vid_pcjr.h" + #define PCJR_RGB 0 #define PCJR_COMPOSITE 1 + typedef struct pcjr_t { mem_mapping_t mapping; @@ -21,7 +25,7 @@ typedef struct pcjr_t int array_index; uint8_t array[32]; int array_ff; - int memctrl;//=-1; + int memctrl; uint8_t stat; int addr_mode; @@ -53,14 +57,12 @@ void pcjr_out(uint16_t addr, uint8_t val, void *p) { pcjr_t *pcjr = (pcjr_t *)p; uint8_t old; -// pclog("pcjr OUT %04X %02X\n",addr,val); switch (addr) { case 0x3d4: pcjr->crtcreg = val & 0x1f; return; case 0x3d5: -// pclog("CRTC write %02X %02x\n", pcjr->crtcreg, val); old = pcjr->crtc[pcjr->crtcreg]; pcjr->crtc[pcjr->crtcreg] = val & crtcmask[pcjr->crtcreg]; if (old != val) @@ -73,7 +75,6 @@ void pcjr_out(uint16_t addr, uint8_t val, void *p) } return; case 0x3da: -// pclog("Array write %02X %02X\n", pcjr->array_index, val); if (!pcjr->array_ff) pcjr->array_index = val & 0x1f; else @@ -97,7 +98,6 @@ void pcjr_out(uint16_t addr, uint8_t val, void *p) uint8_t pcjr_in(uint16_t addr, void *p) { pcjr_t *pcjr = (pcjr_t *)p; -// if (addr!=0x3DA) pclog("pcjr IN %04X\n",addr); switch (addr) { case 0x3d4: @@ -118,13 +118,11 @@ void pcjr_recalcaddress(pcjr_t *pcjr) { pcjr->vram = &ram[(pcjr->memctrl & 0x06) << 14]; pcjr->b8000 = &ram[(pcjr->memctrl & 0x30) << 11]; -// printf("VRAM at %05X B8000 at %05X\n",((pcjr->memctrl&0x6)<<14)+pcjr->base,((pcjr->memctrl&0x30)<<11)+pcjr->base); } else { pcjr->vram = &ram[(pcjr->memctrl & 0x07) << 14]; pcjr->b8000 = &ram[(pcjr->memctrl & 0x38) << 11]; -// printf("VRAM at %05X B8000 at %05X\n",((pcjr->memctrl&0x7)<<14)+pcjr->base,((pcjr->memctrl&0x38)<<11)+pcjr->base); } } @@ -135,7 +133,6 @@ void pcjr_write(uint32_t addr, uint8_t val, void *p) return; egawrites++; -// pclog("pcjr VRAM write %05X %02X %04X:%04X %04X:%04X\n",addr,val,CS,pc,DS,SI); pcjr->b8000[addr & 0x3fff] = val; } @@ -146,7 +143,6 @@ uint8_t pcjr_read(uint32_t addr, void *p) return 0xff; egareads++; -// pclog("pcjr VRAM read %05X %02X %04X:%04X\n",addr,pcjr->b8000[addr&0x7FFF],CS,pc); return pcjr->b8000[addr & 0x3fff]; } @@ -171,27 +167,8 @@ void pcjr_recalctimings(pcjr_t *pcjr) } -static int ntsc_col[8][8]= -{ - {0,0,0,0,0,0,0,0}, /*Black*/ - {0,0,1,1,1,1,0,0}, /*Blue*/ - {1,0,0,0,0,1,1,1}, /*Green*/ - {0,0,0,0,1,1,1,1}, /*Cyan*/ - {1,1,1,1,0,0,0,0}, /*Red*/ - {0,1,1,1,1,0,0,0}, /*Magenta*/ - {1,1,0,0,0,0,1,1}, /*Yellow*/ - {1,1,1,1,1,1,1,1} /*White*/ -}; - -/*static int cga4pal[8][4]= -{ - {0,2,4,6},{0,3,5,7},{0,3,4,7},{0,3,4,7}, - {0,10,12,14},{0,11,13,15},{0,11,12,15},{0,11,12,15} -};*/ - void pcjr_poll(void *p) { -// int *cgapal=cga4pal[((pcjr->col&0x10)>>2)|((cgamode&4)>>1)|((cgacol&0x20)>>5)]; pcjr_t *pcjr = (pcjr_t *)p; uint16_t ca = (pcjr->crtc[15] | (pcjr->crtc[14] << 8)) & 0x3fff; int drawcursor; @@ -200,16 +177,9 @@ void pcjr_poll(void *p) uint8_t chr, attr; uint16_t dat; int cols[4]; - int col; int oldsc; - int y_buf[8] = {0, 0, 0, 0, 0, 0, 0, 0}, y_val, y_tot; - int i_buf[8] = {0, 0, 0, 0, 0, 0, 0, 0}, i_val, i_tot; - int q_buf[8] = {0, 0, 0, 0, 0, 0, 0, 0}, q_val, q_tot; - int r, g, b; if (!pcjr->linepos) { -// cgapal[0]=pcjr->col&15; -// printf("Firstline %i Lastline %i pcjr->displine %i\n",firstline,lastline,pcjr->displine); pcjr->vidtime += pcjr->dispofftime; pcjr->stat &= ~1; pcjr->linepos = 1; @@ -333,7 +303,6 @@ void pcjr_poll(void *p) for (c = 0; c < 8; c++) buffer->line[pcjr->displine][(x << 3) + c + 8] = cols[(fontdat[chr][pcjr->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++) @@ -424,7 +393,6 @@ void pcjr_poll(void *p) } else { -// cols[0] = ((pcjr->mode & 0x12) == 0x12) ? 0 : (pcjr->col & 0xf) + 16; cols[0] = pcjr->array[0 + 16] + 16; if (pcjr->array[0] & 1) hline(buffer, 0, pcjr->displine, (pcjr->crtc[1] << 3) + 16, cols[0]); else hline(buffer, 0, pcjr->displine, (pcjr->crtc[1] << 4) + 16, cols[0]); @@ -443,7 +411,6 @@ void pcjr_poll(void *p) if (pcjr->vc == pcjr->crtc[7] && !pcjr->sc) { pcjr->stat |= 8; -// printf("VSYNC on %i %i\n",vc,sc); } pcjr->displine++; if (pcjr->displine >= 360) @@ -461,7 +428,6 @@ void pcjr_poll(void *p) if (!pcjr->vsynctime) { pcjr->stat &= ~8; -// printf("VSYNC off %i %i\n",vc,sc); } } if (pcjr->sc == (pcjr->crtc[11] & 31) || ((pcjr->crtc[8] & 3) == 3 && pcjr->sc == ((pcjr->crtc[11] & 31) >> 1))) @@ -480,25 +446,19 @@ void pcjr_poll(void *p) pcjr->dispon = 1; pcjr->ma = pcjr->maback = (pcjr->crtc[13] | (pcjr->crtc[12] << 8)) & 0x3fff; pcjr->sc = 0; -// printf("Display on!\n"); } } else if (pcjr->sc == pcjr->crtc[9] || ((pcjr->crtc[8] & 3) == 3 && pcjr->sc == (pcjr->crtc[9] >> 1))) { pcjr->maback = pcjr->ma; -// con=0; -// coff=0; pcjr->sc = 0; oldvc = pcjr->vc; pcjr->vc++; pcjr->vc &= 127; -// pclog("VC %i %i\n", pcjr->vc, pcjr->crtc[7]); -// printf("VC %i %i %i %i %i\n",vc,crtc[4],crtc[6],crtc[7],pcjr->dispon); if (pcjr->vc == pcjr->crtc[6]) pcjr->dispon = 0; if (oldvc == pcjr->crtc[4]) { -// printf("Display over at %i\n",pcjr->displine); pcjr->vc = 0; pcjr->vadj = pcjr->crtc[5]; if (!pcjr->vadj) @@ -507,19 +467,15 @@ void pcjr_poll(void *p) pcjr->ma = pcjr->maback = (pcjr->crtc[13] | (pcjr->crtc[12] << 8)) & 0x3fff; if ((pcjr->crtc[10] & 0x60) == 0x20) pcjr->cursoron = 0; else pcjr->cursoron = pcjr->blink & 16; -// printf("CRTC10 %02X %i\n",crtc[10],cursoron); } if (pcjr->vc == pcjr->crtc[7]) { pcjr->dispon = 0; pcjr->displine = 0; - pcjr->vsynctime = 16;//(crtc[3]>>4)+1; + pcjr->vsynctime = 16; picint(1 << 5); -// printf("pcjr->vsynctime %i %02X\n",pcjr->vsynctime,crtc[3]); -// pcjr->stat|=8; if (pcjr->crtc[7]) { -// printf("Lastline %i Firstline %i %i %i %i\n",lastline,firstline,lastline-firstline,crtc[1],xsize); if (pcjr->array[0] & 1) x = (pcjr->crtc[1] << 3) + 16; else x = (pcjr->crtc[1] << 4) + 16; pcjr->lastline++; @@ -527,13 +483,10 @@ void pcjr_poll(void *p) { xsize = x; ysize = pcjr->lastline - pcjr->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); if (pcjr->composite) video_blit_memtoscreen(0, pcjr->firstline-4, 0, (pcjr->lastline - pcjr->firstline) + 8, xsize, (pcjr->lastline - pcjr->firstline) + 8); @@ -606,27 +559,21 @@ device_t pcjr_video_device = static device_config_t pcjr_config[] = { { - .name = "display_type", - .description = "Display type", - .type = CONFIG_SELECTION, - .selection = + "display_type", "Display type", CONFIG_SELECTION, "", PCJR_RGB, { { - .description = "RGB", - .value = PCJR_RGB + "RGB", PCJR_RGB }, { - .description = "Composite", - .value = PCJR_COMPOSITE + "Composite", PCJR_COMPOSITE }, { - .description = "" + "" } - }, - .default_int = PCJR_RGB + } }, { - .type = -1 + "", "", -1 } }; diff --git a/src/vid_pcjr.h b/src/VIDEO/vid_pcjr.h similarity index 100% rename from src/vid_pcjr.h rename to src/VIDEO/vid_pcjr.h diff --git a/src/vid_ps1_svga.c b/src/VIDEO/vid_ps1_svga.c similarity index 89% rename from src/vid_ps1_svga.c rename to src/VIDEO/vid_ps1_svga.c index 700582938..9bb6acafc 100644 --- a/src/vid_ps1_svga.c +++ b/src/VIDEO/vid_ps1_svga.c @@ -1,6 +1,3 @@ -/* Copyright holders: Sarah Walker - see COPYING for more details -*/ /*Emulation of the SVGA chip in the IBM PS/1 Model 2121, or at least the 20 MHz version. @@ -11,15 +8,16 @@ it's just a VGA for now. */ #include -#include "ibm.h" -#include "device.h" -#include "io.h" -#include "mem.h" -#include "rom.h" +#include "../ibm.h" +#include "../io.h" +#include "../mem.h" +#include "../rom.h" +#include "../device.h" #include "video.h" #include "vid_svga.h" #include "vid_vga.h" + typedef struct ps1_m2121_svga_t { svga_t svga; @@ -37,8 +35,6 @@ void ps1_m2121_svga_out(uint16_t addr, uint8_t val, void *p) svga_t *svga = &ps1->svga; uint8_t old; -// pclog("svga_out : %04X %02X %04X:%04X %02X %i\n", addr, val, CS,cpu_state.pc, ram[0x489], ins); - if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) addr ^= 0x60; @@ -48,8 +44,6 @@ void ps1_m2121_svga_out(uint16_t addr, uint8_t val, void *p) svga->crtcreg = val & 0x1f; return; case 0x3D5: - if (svga->crtcreg <= 0x18) - val &= mask_crtc[svga->crtcreg]; if ((svga->crtcreg < 7) && (svga->crtc[0x11] & 0x80)) return; if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80)) @@ -91,8 +85,6 @@ uint8_t ps1_m2121_svga_in(uint16_t addr, void *p) svga_t *svga = &ps1->svga; uint8_t temp; -// if (addr != 0x3da) pclog("svga_in : %04X ", addr); - if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) addr ^= 0x60; @@ -123,7 +115,6 @@ uint8_t ps1_m2121_svga_in(uint16_t addr, void *p) temp = svga_in(addr, svga); break; } -// if (addr != 0x3da) pclog("%02X %04X:%04X\n", temp, CS,pc); return temp; } @@ -141,7 +132,6 @@ void *ps1_m2121_svga_init() io_sethandler(0x0100, 0x0002, ps1_m2121_svga_in, NULL, NULL, ps1_m2121_svga_out, NULL, NULL, ps1); io_sethandler(0x03c0, 0x0020, ps1_m2121_svga_in, NULL, NULL, ps1_m2121_svga_out, NULL, NULL, ps1); io_sethandler(0x2100, 0x0010, ps1_m2121_svga_in, NULL, NULL, ps1_m2121_svga_out, NULL, NULL, ps1); -// io_sethandler(0x210a, 0x0001, ps1_m2121_svga_in, NULL, NULL, ps1_m2121_svga_out, NULL, NULL, ps1); ps1->svga.bpp = 8; ps1->svga.miscout = 1; diff --git a/src/vid_ps1_svga.h b/src/VIDEO/vid_ps1_svga.h similarity index 100% rename from src/vid_ps1_svga.h rename to src/VIDEO/vid_ps1_svga.h diff --git a/src/vid_s3.c b/src/VIDEO/vid_s3.c similarity index 81% rename from src/vid_s3.c rename to src/VIDEO/vid_s3.c index caaf63cb8..5e569ce8e 100644 --- a/src/vid_s3.c +++ b/src/VIDEO/vid_s3.c @@ -1,26 +1,21 @@ -/* Copyright holders: Sarah Walker, SA1988 - see COPYING for more details -*/ /*S3 emulation*/ #include -#include "ibm.h" -#include "device.h" -#include "io.h" -#include "mem.h" -#include "pci.h" -#include "rom.h" -#include "thread.h" +#include "../ibm.h" +#include "../device.h" +#include "../io.h" +#include "../mem.h" +#include "../pci.h" +#include "../rom.h" +#include "../WIN/plat_thread.h" #include "video.h" #include "vid_s3.h" #include "vid_svga.h" #include "vid_svga_render.h" -#include "vid_bt485_ramdac.h" #include "vid_sdac_ramdac.h" enum { S3_VISION864, - S3_VISION964, S3_TRIO32, S3_TRIO64 }; @@ -71,7 +66,6 @@ typedef struct s3_t svga_t svga; sdac_ramdac_t ramdac; - bt485_ramdac_t bt485_ramdac; uint8_t bank; uint8_t ma_ext; @@ -82,13 +76,17 @@ typedef struct s3_t uint8_t id, id_ext, id_ext_pci; + uint8_t int_line; + int packed_mmio; uint32_t linear_base, linear_size; uint8_t pci_regs[256]; + int card; uint32_t vram_mask; + uint8_t status_9ae8; float (*getclock)(int clock, void *p); void *getclock_p; @@ -137,8 +135,16 @@ typedef struct s3_t int blitter_busy; uint64_t blitter_time; uint64_t status_time; + + uint8_t subsys_cntl, subsys_stat; } s3_t; +#define INT_VSY (1 << 0) +#define INT_GE_BSY (1 << 1) +#define INT_FIFO_OVR (1 << 2) +#define INT_FIFO_EMP (1 << 3) +#define INT_MASK 0xf + void s3_updatemapping(); void s3_accel_write(uint32_t addr, uint8_t val, void *p); @@ -160,6 +166,14 @@ static void s3_wait_fifo_idle(s3_t *s3) } } +static void s3_update_irqs(s3_t *s3) +{ + if (s3->subsys_cntl & s3->subsys_stat & INT_MASK) + pci_set_irq(s3->card, PCI_INTA); + else + pci_clear_irq(s3->card, PCI_INTA); +} + void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, s3_t *s3); #define WRITE8(addr, var, val) switch ((addr) & 3) \ @@ -407,59 +421,67 @@ static void s3_accel_out_fifo(s3_t *s3, uint16_t port, uint8_t val) static void s3_accel_out_fifo_w(s3_t *s3, uint16_t port, uint16_t val) { -// pclog("Accel out w %04X %04X\n", port, val); if (s3->accel.cmd & 0x100) { if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80) { if (s3->accel.cmd & 0x1000) - val = (val >> 8) | (val << 8); - s3_accel_start(16, 1, val | (val << 16), 0, s3); + val = (val >> 8) | (val << 8); + if ((s3->accel.cmd & 0x600) == 0x000) + s3_accel_start(8, 1, val | (val << 16), 0, s3); + else + s3_accel_start(16, 1, val | (val << 16), 0, s3); } else - s3_accel_start(2, 1, 0xffffffff, val | (val << 16), s3); + { + if ((s3->accel.cmd & 0x600) == 0x000) + s3_accel_start(1, 1, 0xffffffff, val | (val << 16), s3); + else + s3_accel_start(2, 1, 0xffffffff, val | (val << 16), s3); + } } } static void s3_accel_out_fifo_l(s3_t *s3, uint16_t port, uint32_t val) { -// pclog("Accel out l %04X %08X\n", port, val); if (s3->accel.cmd & 0x100) { if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80) { - if (s3->accel.cmd & 0x1000) - val = ((val & 0xff000000) >> 24) | ((val & 0x00ff0000) >> 8) | ((val & 0x0000ff00) << 8) | ((val & 0x000000ff) << 24); - if ((s3->accel.cmd & 0x600) == 0x400) + if (s3->accel.cmd & 0x400) + { + if (s3->accel.cmd & 0x1000) + val = ((val & 0xff000000) >> 24) | ((val & 0x00ff0000) >> 8) | ((val & 0x0000ff00) << 8) | ((val & 0x000000ff) << 24); s3_accel_start(32, 1, val, 0, s3); + } else if ((s3->accel.cmd & 0x600) == 0x200) { - s3_accel_start(16, 1, val >> 16, 0, s3); + if (s3->accel.cmd & 0x1000) + val = ((val & 0xff00ff00) >> 8) | ((val & 0x00ff00ff) << 8); s3_accel_start(16, 1, val, 0, s3); + s3_accel_start(16, 1, val >> 16, 0, s3); } - else if (!(s3->accel.cmd & 0x600)) + else { - s3_accel_start(8, 1, val >> 24, 0, s3); + if (s3->accel.cmd & 0x1000) + val = ((val & 0xff00ff00) >> 8) | ((val & 0x00ff00ff) << 8); + s3_accel_start(8, 1, val, 0, s3); s3_accel_start(8, 1, val >> 16, 0, s3); - s3_accel_start(8, 1, val >> 8, 0, s3); - s3_accel_start(8, 1, val, 0, s3); } } else { - if ((s3->accel.cmd & 0x600) == 0x400) + if (s3->accel.cmd & 0x400) s3_accel_start(4, 1, 0xffffffff, val, s3); else if ((s3->accel.cmd & 0x600) == 0x200) { - s3_accel_start(2, 1, 0xffffffff, val >> 16, s3); s3_accel_start(2, 1, 0xffffffff, val, s3); + s3_accel_start(2, 1, 0xffffffff, val >> 16, s3); } - else if (!(s3->accel.cmd & 0x600)) + else { - s3_accel_start(1, 1, 0xffffffff, val >> 24, s3); - s3_accel_start(1, 1, 0xffffffff, val >> 16, s3); - s3_accel_start(1, 1, 0xffffffff, val >> 8, s3); s3_accel_start(1, 1, 0xffffffff, val, s3); + s3_accel_start(1, 1, 0xffffffff, val >> 16, s3); } } } @@ -467,7 +489,6 @@ static void s3_accel_out_fifo_l(s3_t *s3, uint16_t port, uint32_t val) static void s3_accel_write_fifo(s3_t *s3, uint32_t addr, uint8_t val) { -// pclog("Write S3 accel %08X %02X\n", addr, val); if (s3->packed_mmio) { int addr_lo = addr & 1; @@ -573,7 +594,6 @@ static void s3_accel_write_fifo(s3_t *s3, uint32_t addr, uint8_t val) static void s3_accel_write_fifo_w(s3_t *s3, uint32_t addr, uint16_t val) { -// pclog("Write S3 accel w %08X %04X\n", addr, val); if (addr & 0x8000) { s3_accel_write_fifo(s3, addr, val); @@ -587,17 +607,24 @@ static void s3_accel_write_fifo_w(s3_t *s3, uint32_t addr, uint16_t val) { if (s3->accel.cmd & 0x1000) val = (val >> 8) | (val << 8); - s3_accel_start(16, 1, val | (val << 16), 0, s3); + if ((s3->accel.cmd & 0x600) == 0x000) + s3_accel_start(8, 1, val | (val << 16), 0, s3); + else + s3_accel_start(16, 1, val | (val << 16), 0, s3); } else - s3_accel_start(2, 1, 0xffffffff, val | (val << 16), s3); + { + if ((s3->accel.cmd & 0x600) == 0x000) + s3_accel_start(1, 1, 0xffffffff, val | (val << 16), s3); + else + s3_accel_start(2, 1, 0xffffffff, val | (val << 16), s3); + } } } } static void s3_accel_write_fifo_l(s3_t *s3, uint32_t addr, uint32_t val) { -// pclog("Write S3 accel l %08X %08X\n", addr, val); if (addr & 0x8000) { s3_accel_write_fifo(s3, addr, val); @@ -611,38 +638,40 @@ static void s3_accel_write_fifo_l(s3_t *s3, uint32_t addr, uint32_t val) { if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80) { - if (s3->accel.cmd & 0x1000) - val = ((val & 0xff000000) >> 24) | ((val & 0x00ff0000) >> 8) | ((val & 0x0000ff00) << 8) | ((val & 0x000000ff) << 24); - if ((s3->accel.cmd & 0x600) == 0x400) + if (s3->accel.cmd & 0x400) + { + if (s3->accel.cmd & 0x1000) + val = ((val & 0xff000000) >> 24) | ((val & 0x00ff0000) >> 8) | ((val & 0x0000ff00) << 8) | ((val & 0x000000ff) << 24); s3_accel_start(32, 1, val, 0, s3); + } else if ((s3->accel.cmd & 0x600) == 0x200) { + if (s3->accel.cmd & 0x1000) + val = ((val & 0xff00ff00) >> 8) | ((val & 0x00ff00ff) << 8); + s3_accel_start(16, 1, val, 0, s3); s3_accel_start(16, 1, val >> 16, 0, s3); - s3_accel_start(16, 1, val, 0, s3); } - else if (!(s3->accel.cmd & 0x600)) + else { - s3_accel_start(8, 1, val >> 24, 0, s3); + if (s3->accel.cmd & 0x1000) + val = ((val & 0xff00ff00) >> 8) | ((val & 0x00ff00ff) << 8); + s3_accel_start(8, 1, val, 0, s3); s3_accel_start(8, 1, val >> 16, 0, s3); - s3_accel_start(8, 1, val >> 8, 0, s3); - s3_accel_start(8, 1, val, 0, s3); } } else { - if ((s3->accel.cmd & 0x600) == 0x400) + if (s3->accel.cmd & 0x400) s3_accel_start(4, 1, 0xffffffff, val, s3); else if ((s3->accel.cmd & 0x600) == 0x200) { - s3_accel_start(2, 1, 0xffffffff, val, s3); + s3_accel_start(2, 1, 0xffffffff, val, s3); s3_accel_start(2, 1, 0xffffffff, val >> 16, s3); } - else if (!(s3->accel.cmd & 0x600)) + else { - s3_accel_start(1, 1, 0xffffffff, val, s3); - s3_accel_start(1, 1, 0xffffffff, val >> 8, s3); + s3_accel_start(1, 1, 0xffffffff, val, s3); s3_accel_start(1, 1, 0xffffffff, val >> 16, s3); - s3_accel_start(1, 1, 0xffffffff, val >> 24, s3); } } } @@ -664,7 +693,6 @@ static void fifo_thread(void *param) uint64_t start_time = timer_read(); uint64_t end_time; fifo_entry_t *fifo = &s3->fifo[s3->fifo_read_idx & FIFO_MASK]; - uint32_t val = fifo->val; switch (fifo->addr_type & FIFO_TYPE) { @@ -698,9 +726,19 @@ static void fifo_thread(void *param) s3->blitter_time += end_time - start_time; } s3->blitter_busy = 0; + s3->subsys_stat |= INT_FIFO_EMP; + s3_update_irqs(s3); } } +static void s3_vblank_start(svga_t *svga) +{ + s3_t *s3 = (s3_t *)svga->p; + + s3->subsys_stat |= INT_VSY; + s3_update_irqs(s3); +} + static void s3_queue(s3_t *s3, uint32_t addr, uint32_t val, uint32_t type) { fifo_entry_t *fifo = &s3->fifo[s3->fifo_write_idx & FIFO_MASK]; @@ -723,39 +761,6 @@ static void s3_queue(s3_t *s3, uint32_t addr, uint32_t val, uint32_t type) wake_fifo_thread(s3); } -void s3_update_linear_size(s3_t *s3) -{ - svga_t *svga = &s3->svga; - - switch (svga->crtc[0x58] & 3) - { - case 0: /*64k*/ - s3->linear_size = 0x10000; - break; - case 1: /*1mb*/ - s3->linear_size = 0x100000; - break; - case 2: /*2mb*/ - s3->linear_size = 0x200000; - break; - case 3: /*8mb*/ - switch(s3->chip) - { - case S3_TRIO32: - s3->linear_size = 0x200000; - svga->crtc[0x58] &= 0xfe; - break; - case S3_TRIO64: - s3->linear_size = 0x400000; - break; - default: - s3->linear_size = 0x800000; - break; - } - break; - } -} - void s3_out(uint16_t addr, uint8_t val, void *p) { s3_t *s3 = (s3_t *)p; @@ -764,8 +769,6 @@ void s3_out(uint16_t addr, uint8_t val, void *p) if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) addr ^= 0x60; - -// pclog("S3 out %04X %02X %04x:%08x\n", addr, val, CS, pc); switch (addr) { @@ -782,25 +785,28 @@ void s3_out(uint16_t addr, uint8_t val, void *p) } if (svga->seqaddr == 4) /*Chain-4 - update banking*/ { - if (val & 8) svga->write_bank = svga->read_bank = s3->bank << 16; - else svga->write_bank = svga->read_bank = s3->bank << 14; + if (val & 8 || (svga->crtc[0x31] & 8)) + svga->write_bank = svga->read_bank = s3->bank << 16; + else + svga->write_bank = svga->read_bank = s3->bank << 14; } break; case 0x3C6: case 0x3C7: case 0x3C8: case 0x3C9: -// pclog("Write RAMDAC %04X %02X %04X:%04X\n", addr, val, CS, pc); - if (s3->chip != S3_VISION964) + if (s3->chip == S3_VISION864) + { sdac_ramdac_out(addr, val, &s3->ramdac, svga); + return; + } else - bt485_ramdac_out(addr, val, &s3->bt485_ramdac, svga); - return; + { + break; + } case 0x3D4: svga->crtcreg = val & 0x7f; return; case 0x3D5: - if (svga->crtcreg <= 0x18) - val &= mask_crtc[svga->crtcreg]; if ((svga->crtcreg < 7) && (svga->crtc[0x11] & 0x80)) return; if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80)) @@ -812,6 +818,10 @@ void s3_out(uint16_t addr, uint8_t val, void *p) { case 0x31: s3->ma_ext = (s3->ma_ext & 0x1c) | ((val & 0x30) >> 4); + if (svga->chain4 || (svga->crtc[0x31] & 8)) + svga->write_bank = svga->read_bank = s3->bank << 16; + else + svga->write_bank = svga->read_bank = s3->bank << 14; break; case 0x32: svga->vrammask = (val & 0x40) ? 0x3ffff : s3->vram_mask; @@ -835,22 +845,25 @@ void s3_out(uint16_t addr, uint8_t val, void *p) case 0x35: s3->bank = (s3->bank & 0x70) | (val & 0xf); -// pclog("CRTC write R35 %02X\n", val); - if (svga->chain4) svga->write_bank = svga->read_bank = s3->bank << 16; - else svga->write_bank = svga->read_bank = s3->bank << 14; + if (svga->chain4 || (svga->crtc[0x31] & 8)) + svga->write_bank = svga->read_bank = s3->bank << 16; + else + svga->write_bank = svga->read_bank = s3->bank << 14; break; case 0x51: s3->bank = (s3->bank & 0x4f) | ((val & 0xc) << 2); -// pclog("CRTC write R51 %02X\n", val); - if (svga->chain4) svga->write_bank = svga->read_bank = s3->bank << 16; - else svga->write_bank = svga->read_bank = s3->bank << 14; + if (svga->chain4 || (svga->crtc[0x31] & 8)) + svga->write_bank = svga->read_bank = s3->bank << 16; + else + svga->write_bank = svga->read_bank = s3->bank << 14; s3->ma_ext = (s3->ma_ext & ~0xc) | ((val & 3) << 2); break; case 0x6a: s3->bank = val; -// pclog("CRTC write R6a %02X\n", val); - if (svga->chain4) svga->write_bank = svga->read_bank = s3->bank << 16; - else svga->write_bank = svga->read_bank = s3->bank << 14; + if (svga->chain4 || (svga->crtc[0x31] & 8)) + svga->write_bank = svga->read_bank = s3->bank << 16; + else + svga->write_bank = svga->read_bank = s3->bank << 14; break; case 0x3a: @@ -873,23 +886,7 @@ void s3_out(uint16_t addr, uint8_t val, void *p) break; case 0x53: - s3_updatemapping(s3); - break; - case 0x58: - s3_update_linear_size(s3); - // s3->linear_base &= ((s3->linear_size - 1) ^ 0xffffffff); - s3_updatemapping(s3); - break; - case 0x59: - s3->linear_base &= 0x00ffffff; - s3->linear_base |= (((uint32_t) val) << 24); - // s3->linear_base &= ((s3->linear_size - 1) ^ 0xffffffff); - s3_updatemapping(s3); - break; - case 0x5a: - s3->linear_base &= 0xff00ffff; - s3->linear_base |= (((uint32_t) val) << 16); - // s3->linear_base &= ((s3->linear_size - 1) ^ 0xffffffff); + case 0x58: case 0x59: case 0x5a: s3_updatemapping(s3); break; @@ -906,23 +903,6 @@ void s3_out(uint16_t addr, uint8_t val, void *p) } } break; - case 0x55: case 0x43: - if (s3->chip == S3_VISION964) - { - if (svga->crtc[0x55] & 3) - { - bt485_set_rs2(svga->crtc[0x55] & 1, &s3->bt485_ramdac); - bt485_set_rs3(svga->crtc[0x55] & 2, &s3->bt485_ramdac); - } - else - { - bt485_set_rs2(svga->crtc[0x43] & 2, &s3->bt485_ramdac); - bt485_set_rs3(0, &s3->bt485_ramdac); - } - pclog("RS2 is now %i, RS3 is now %i\n", s3->bt485_ramdac.rs2, s3->bt485_ramdac.rs3); - } - break; -// pclog("Write CRTC R%02X %02X\n", crtcreg, val); } if (old != val) { @@ -945,7 +925,6 @@ uint8_t s3_in(uint16_t addr, void *p) if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) addr ^= 0x60; -// if (addr != 0x3da) pclog("S3 in %04X %08x:%02x\n", addr, CS, pc); switch (addr) { case 0x3c1: @@ -959,29 +938,27 @@ uint8_t s3_in(uint16_t addr, void *p) break; case 0x3c6: case 0x3c7: case 0x3c8: case 0x3c9: -// pclog("Read RAMDAC %04X %04X:%04X\n", addr, CS, pc); - if (s3->chip != S3_VISION964) + if (s3->chip == S3_VISION864) + { return sdac_ramdac_in(addr, &s3->ramdac, svga); + } else - return bt485_ramdac_in(addr, &s3->bt485_ramdac, svga); + { + break; + } case 0x3d4: return svga->crtcreg; case 0x3d5: -// pclog("Read CRTC R%02X %02x %04X:%04X\n", svga->crtcreg, svga->crtc[svga->crtcreg], CS, pc); switch (svga->crtcreg) { case 0x2d: return 0x88; /*Extended chip ID*/ - case 0x2e: - // if ((s3->chip != S3_TRIO32) && (s3->chip != S3_TRIO64)) return 0xFF; - return s3->id_ext; /*New chip ID*/ + case 0x2e: return s3->id_ext; /*New chip ID*/ case 0x2f: return 0; /*Revision level*/ case 0x30: return s3->id; /*Chip ID*/ case 0x31: return (svga->crtc[0x31] & 0xcf) | ((s3->ma_ext & 3) << 4); case 0x35: return (svga->crtc[0x35] & 0xf0) | (s3->bank & 0xf); case 0x51: return (svga->crtc[0x51] & 0xf0) | ((s3->bank >> 2) & 0xc) | ((s3->ma_ext >> 2) & 3); - case 0x59: return ((s3->linear_base >> 24) & 0xff); - case 0x5a: return ((s3->linear_base >> 16) & 0xff); case 0x69: return s3->ma_ext; case 0x6a: return s3->bank; } @@ -995,10 +972,7 @@ void s3_recalctimings(svga_t *svga) s3_t *s3 = (s3_t *)svga->p; svga->hdisp = svga->hdisp_old; -// pclog("%i %i\n", svga->hdisp, svga->hdisp_time); -// pclog("recalctimings\n"); svga->ma_latch |= (s3->ma_ext << 16); -// pclog("SVGA_MA %08X\n", svga_ma); if (svga->crtc[0x5d] & 0x01) svga->htotal += 0x100; if (svga->crtc[0x5d] & 0x02) { @@ -1055,21 +1029,21 @@ void s3_recalctimings(svga_t *svga) void s3_updatemapping(s3_t *s3) { svga_t *svga = &s3->svga; - uint32_t lbase; -// video_write_a000_w = video_write_a000_l = NULL; - if (!(s3->pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_MEM)) { -// pclog("Update mapping - PCI disabled\n"); mem_mapping_disable(&svga->mapping); mem_mapping_disable(&s3->linear_mapping); mem_mapping_disable(&s3->mmio_mapping); return; } -// pclog("Update mapping - bank %02X ", svga->gdcreg[6] & 0xc); - switch (svga->gdcreg[6] & 0xc) /*Banked framebuffer*/ + if (svga->crtc[0x31] & 0x08) + { + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x10000); + svga->banked_mask = 0xffff; + } + else switch (svga->gdcreg[6] & 0xc) /*Banked framebuffer*/ { case 0x0: /*128k at A0000*/ mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x20000); @@ -1089,12 +1063,10 @@ void s3_updatemapping(s3_t *s3) break; } -// pclog("Linear framebuffer %02X ", svga->crtc[0x58] & 0x10); if (svga->crtc[0x58] & 0x10) /*Linear framebuffer*/ { mem_mapping_disable(&svga->mapping); -#if 0 s3->linear_base = (svga->crtc[0x5a] << 16) | (svga->crtc[0x59] << 24); switch (svga->crtc[0x58] & 3) { @@ -1108,47 +1080,11 @@ void s3_updatemapping(s3_t *s3) s3->linear_size = 0x200000; break; case 3: /*8mb*/ - switch(s3->chip) - { - case S3_TRIO32: - s3->linear_size = 0x200000; - svga->crtc[0x58] &= 0xfe; - break; - case S3_TRIO64: - s3->linear_size = 0x400000; - break; - default: - s3->linear_size = 0x800000; - break; - } + s3->linear_size = 0x800000; break; } s3->linear_base &= ~(s3->linear_size - 1); -#endif -// pclog("%08X %08X %02X %02X %02X\n", linear_base, linear_size, crtc[0x58], crtc[0x59], crtc[0x5a]); -// pclog("Linear framebuffer at %08X size %08X\n", s3->linear_base, s3->linear_size); - - if ((svga->crtc[0x68] & 0x80) && (s3->chip != S3_TRIO32)) - { - if (s3->linear_base & 0xe0000000) - { - /* If bits 31-29 are not all clear, disable linear base. */ - mem_mapping_disable(&s3->linear_mapping); - return; - } - else - { - lbase = s3->linear_base & 0x1fffffff; - } - } - else - { - lbase = s3->linear_base; - } - - svga->linear_base = lbase & ((s3->linear_size - 1) ^ 0xffffffff); - - if (lbase == 0xa0000) + if (s3->linear_base == 0xa0000) { mem_mapping_disable(&s3->linear_mapping); if (!(svga->crtc[0x53] & 0x10)) @@ -1156,15 +1092,13 @@ void s3_updatemapping(s3_t *s3) mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x10000); svga->banked_mask = 0xffff; } -// mem_mapping_set_addr(&s3->linear_mapping, 0xa0000, 0x10000); } else - mem_mapping_set_addr(&s3->linear_mapping, lbase, s3->linear_size); + mem_mapping_set_addr(&s3->linear_mapping, s3->linear_base, s3->linear_size); } else mem_mapping_disable(&s3->linear_mapping); - -// pclog("Memory mapped IO %02X\n", svga->crtc[0x53] & 0x10); + if (svga->crtc[0x53] & 0x10) /*Memory mapped IO*/ { mem_mapping_disable(&svga->mapping); @@ -1180,14 +1114,12 @@ static float s3_trio64_getclock(int clock, void *p) svga_t *svga = &s3->svga; float t; int m, n1, n2; -// pclog("Trio64_getclock %i %02X %02X\n", clock, svga->seqregs[0x13], svga->seqregs[0x12]); if (clock == 0) return 25175000.0; if (clock == 1) return 28322000.0; m = svga->seqregs[0x13] + 2; n1 = (svga->seqregs[0x12] & 0x1f) + 2; n2 = ((svga->seqregs[0x12] >> 5) & 0x07); t = (14318184.0 * ((float)m / (float)n1)) / (float)(1 << n2); -// pclog("TRIO64 clock %i %i %i %f %f %i\n", m, n1, n2, t, 14318184.0 * ((float)m / (float)n1), 1 << n2); return t; } @@ -1195,7 +1127,6 @@ static float s3_trio64_getclock(int clock, void *p) void s3_accel_out(uint16_t port, uint8_t val, void *p) { s3_t *s3 = (s3_t *)p; -// pclog("Accel out %04X %02X\n", port, val); if (port >= 0x8000) { @@ -1204,9 +1135,12 @@ void s3_accel_out(uint16_t port, uint8_t val, void *p) else switch (port) { case 0x42e8: + s3->subsys_stat &= ~val; + s3_update_irqs(s3); break; case 0x42e9: - s3->accel.subsys_cntl = val; + s3->subsys_cntl = val; + s3_update_irqs(s3); break; case 0x46e8: s3->accel.setup_md = val; @@ -1220,14 +1154,12 @@ void s3_accel_out(uint16_t port, uint8_t val, void *p) void s3_accel_out_w(uint16_t port, uint16_t val, void *p) { s3_t *s3 = (s3_t *)p; -// pclog("Accel out w %04X %04X\n", port, val); s3_queue(s3, port, val, FIFO_OUT_WORD); } void s3_accel_out_l(uint16_t port, uint32_t val, void *p) { s3_t *s3 = (s3_t *)p; -// pclog("Accel out l %04X %08X\n", port, val); s3_queue(s3, port, val, FIFO_OUT_DWORD); } @@ -1235,13 +1167,12 @@ uint8_t s3_accel_in(uint16_t port, void *p) { s3_t *s3 = (s3_t *)p; int temp; -// pclog("Accel in %04X\n", port); switch (port) { case 0x42e8: - return 0; + return s3->subsys_stat; case 0x42e9: - return 0; + return s3->subsys_cntl; case 0x82e8: s3_wait_fifo_idle(s3); @@ -1298,7 +1229,7 @@ uint8_t s3_accel_in(uint16_t port, void *p) if (!FIFO_EMPTY) temp |= 0x02; /*Hardware busy*/ else - temp |= 0x04; /*FIFO empty*/ + temp |= s3->status_9ae8; /*FIFO empty*/ if (FIFO_FULL) temp |= 0xf8; /*FIFO full*/ return temp; @@ -1423,19 +1354,16 @@ uint8_t s3_accel_in(uint16_t port, void *p) void s3_accel_write(uint32_t addr, uint8_t val, void *p) { s3_t *s3 = (s3_t *)p; -// pclog("s3_accel_write %08x %02x\n", addr, val); s3_queue(s3, addr & 0xffff, val, FIFO_WRITE_BYTE); } void s3_accel_write_w(uint32_t addr, uint16_t val, void *p) { s3_t *s3 = (s3_t *)p; -// pclog("s3_accel_write_w %08x %04x\n", addr, val); s3_queue(s3, addr & 0xffff, val, FIFO_WRITE_WORD); } void s3_accel_write_l(uint32_t addr, uint32_t val, void *p) { s3_t *s3 = (s3_t *)p; -// pclog("s3_accel_write_l %08x %08x\n", addr, val); s3_queue(s3, addr & 0xffff, val, FIFO_WRITE_DWORD); } @@ -1497,14 +1425,11 @@ void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat int clip_b = s3->accel.multifunc[3] & 0xfff; int clip_r = s3->accel.multifunc[4] & 0xfff; int vram_mask = (s3->accel.multifunc[0xa] & 0xc0) == 0xc0; - uint32_t mix_mask; + uint32_t mix_mask = 0; uint16_t *vram_w = (uint16_t *)svga->vram; uint32_t *vram_l = (uint32_t *)svga->vram; uint32_t compare = s3->accel.color_cmp; int compare_mode = (s3->accel.multifunc[0xe] >> 7) & 3; -//return; -// if (!cpu_input) pclog("Start S3 command %i %i, %i %i, %i (clip %i, %i to %i, %i %i)\n", s3->accel.cmd >> 13, s3->accel.cur_x, s3->accel.cur_y, s3->accel.maj_axis_pcnt & 0xfff, s3->accel.multifunc[0] & 0xfff, clip_l, clip_t, clip_r, clip_b, s3->accel.multifunc[0xe] & 0x20); -// else pclog(" S3 command %i, %i, %08x %08x\n", s3->accel.cmd >> 13, count, mix_dat, cpu_dat); if (!cpu_input) s3->accel.dat_count = 0; if (cpu_input && (s3->accel.multifunc[0xa] & 0xc0) != 0x80) @@ -1625,12 +1550,8 @@ void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat { READ((s3->accel.cy * s3->width) + s3->accel.cx, dest_dat); -// pclog("Line : %04i, %04i (%06X) - %02X (%02X %04X %05X) %02X (%02X %02X) ", s3->accel.cx, s3->accel.cy, s3->accel.dest + s3->accel.cx, src_dat, vram[s3->accel.src + s3->accel.cx], mix_dat & mix_mask, s3->accel.src + s3->accel.cx, dest_dat, s3->accel.frgd_color, s3->accel.bkgd_color); - MIX -// pclog("%02X\n", dest_dat); - WRITE((s3->accel.cy * s3->width) + s3->accel.cx); } } @@ -1640,8 +1561,6 @@ void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat if (s3->bpp == 0) cpu_dat >>= 8; else cpu_dat >>= 16; -// pclog("%i, %i - %i %i %i %i\n", s3->accel.cx, s3->accel.cy, s3->accel.err_term, s3->accel.maj_axis_pcnt, s3->accel.desty_axstp, s3->accel.destx_distp); - if (!s3->accel.sy) break; @@ -1694,16 +1613,21 @@ void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat if (s3->accel.cur_y & 0x1000) s3->accel.cy |= ~0xfff; s3->accel.dest = s3->accel.cy * s3->width; - -// pclog("Dest %08X (%i, %i) %04X %04X\n", s3->accel.dest, s3->accel.cx, s3->accel.cy, s3->accel.cur_x, s3->accel.cur_x & 0x1000); } + + s3->status_9ae8 = 4; /*To avoid the spam from OS/2's drivers*/ + + if ((s3->accel.cmd & 0x100) && !cpu_input) + { + s3->status_9ae8 = 2; /*To avoid the spam from OS/2's drivers*/ + return; /*Wait for data from CPU*/ + } + if ((s3->accel.cmd & 0x100) && !cpu_input) return; /*Wait for data from CPU*/ -// if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80 && !cpu_input) /*Mix data from CPU*/ -// return; frgd_mix = (s3->accel.frgd_mix >> 5) & 3; - bkgd_mix = (s3->accel.bkgd_mix >> 5) & 3; - + bkgd_mix = (s3->accel.bkgd_mix >> 5) & 3; + while (count-- && s3->accel.sy >= 0) { if (s3->accel.cx >= clip_l && s3->accel.cx <= clip_r && @@ -1722,14 +1646,9 @@ void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat compare_mode < 2) { READ(s3->accel.dest + s3->accel.cx, dest_dat); - - -// if (CS != 0xc000) pclog("Write %05X %02X %02X %04X (%02X %02X) ", s3->accel.dest + s3->accel.cx, src_dat, dest_dat, mix_dat, s3->accel.frgd_mix, s3->accel.bkgd_mix); MIX - -// if (CS != 0xc000) pclog("%02X\n", dest_dat); - + WRITE(s3->accel.dest + s3->accel.cx); } } @@ -1746,10 +1665,8 @@ void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat { if (s3->accel.cmd & 0x20) s3->accel.cx -= (s3->accel.maj_axis_pcnt & 0xfff) + 1; else s3->accel.cx += (s3->accel.maj_axis_pcnt & 0xfff) + 1; -// s3->accel.dest -= (s3->accel.maj_axis_pcnt & 0xfff) + 1; s3->accel.sx = s3->accel.maj_axis_pcnt & 0xfff; - -// s3->accel.dest += s3_width; + if (s3->accel.cmd & 0x80) s3->accel.cy++; else s3->accel.cy--; @@ -1785,12 +1702,8 @@ void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat s3->accel.src = s3->accel.cy * s3->width; s3->accel.dest = s3->accel.dy * s3->width; - -// pclog("Source %08X Dest %08X (%i, %i) - (%i, %i)\n", s3->accel.src, s3->accel.dest, s3->accel.cx, s3->accel.cy, s3->accel.dx, s3->accel.dy); } if ((s3->accel.cmd & 0x100) && !cpu_input) return; /*Wait for data from CPU*/ -// if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80 && !cpu_input) /*Mix data from CPU*/ -// return; if (s3->accel.sy < 0) return; @@ -1799,7 +1712,8 @@ void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat bkgd_mix = (s3->accel.bkgd_mix >> 5) & 3; if (!cpu_input && frgd_mix == 3 && !vram_mask && !compare_mode && - (s3->accel.cmd & 0xa0) == 0xa0 && (s3->accel.frgd_mix & 0xf) == 7) + (s3->accel.cmd & 0xa0) == 0xa0 && (s3->accel.frgd_mix & 0xf) == 7 && + (s3->accel.bkgd_mix & 0xf) == 7) { while (1) { @@ -1864,12 +1778,8 @@ void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat compare_mode < 2) { READ(s3->accel.dest + s3->accel.dx, dest_dat); - -// pclog("BitBlt : %04i, %04i (%06X) - %02X (%02X %04X %05X) %02X ", s3->accel.dx, s3->accel.dy, s3->accel.dest + s3->accel.dx, src_dat, vram[s3->accel.src + s3->accel.cx], mix_dat, s3->accel.src + s3->accel.cx, dest_dat); - - MIX -// pclog("%02X\n", dest_dat); + MIX WRITE(s3->accel.dest + s3->accel.dx); } @@ -1924,8 +1834,6 @@ void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat if (cpu_input/* && (s3->accel.multifunc[0xa] & 0xc0) == 0x80*/) return; if (s3->accel.sy < 0) { -// s3->accel.cur_x = s3->accel.cx; -// s3->accel.cur_y = s3->accel.cy; return; } } @@ -1950,9 +1858,6 @@ void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat if (s3->accel.cur_y & 0x1000) s3->accel.cy |= ~0xfff; /*Align source with destination*/ -// s3->accel.cx = (s3->accel.cx & ~7) | (s3->accel.dx & 7); -// s3->accel.cy = (s3->accel.cy & ~7) | (s3->accel.dy & 7); - s3->accel.pattern = (s3->accel.cy * s3->width) + s3->accel.cx; s3->accel.dest = s3->accel.dy * s3->width; @@ -1960,14 +1865,8 @@ void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat s3->accel.cy = s3->accel.dy & 7; s3->accel.src = s3->accel.pattern + (s3->accel.cy * s3->width); - -// pclog("Source %08X Dest %08X (%i, %i) - (%i, %i)\n", s3->accel.src, s3->accel.dest, s3->accel.cx, s3->accel.cy, s3->accel.dx, s3->accel.dy); -// dumpregs(); -// exit(-1); } if ((s3->accel.cmd & 0x100) && !cpu_input) return; /*Wait for data from CPU*/ -// if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80 && !cpu_input) /*Mix data from CPU*/ -// return; frgd_mix = (s3->accel.frgd_mix >> 5) & 3; bkgd_mix = (s3->accel.bkgd_mix >> 5) & 3; @@ -1995,13 +1894,9 @@ void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat compare_mode < 2) { READ(s3->accel.dest + s3->accel.dx, dest_dat); - -// pclog("Pattern fill : %04i, %04i (%06X) - %02X (%02X %04X %05X) %02X ", s3->accel.dx, s3->accel.dy, s3->accel.dest + s3->accel.dx, src_dat, vram[s3->accel.src + s3->accel.cx], mix_dat, s3->accel.src + s3->accel.cx, dest_dat); MIX -// pclog("%02X\n", dest_dat); - WRITE(s3->accel.dest + s3->accel.dx); } } @@ -2067,13 +1962,12 @@ void s3_hwcursor_draw(svga_t *svga, int displine) uint16_t dat[2]; int xx; int offset = svga->hwcursor_latch.x - svga->hwcursor_latch.xoff; - int y_add = enable_overscan ? 16 : 0; - int x_add = enable_overscan ? 8 : 0; - + int y_add = (enable_overscan && !suppress_overscan) ? 16 : 0; + int x_add = (enable_overscan && !suppress_overscan) ? 8 : 0; + if (svga->interlace && svga->hwcursor_oddeven) svga->hwcursor_latch.addr += 16; -// pclog("HWcursor %i %i\n", svga->hwcursor_latch.x, svga->hwcursor_latch.y); for (x = 0; x < 64; x += 16) { dat[0] = (svga->vram[svga->hwcursor_latch.addr] << 8) | svga->vram[svga->hwcursor_latch.addr + 1]; @@ -2086,7 +1980,6 @@ void s3_hwcursor_draw(svga_t *svga, int displine) ((uint32_t *)buffer32->line[displine + y_add])[offset + 32 + x_add] = (dat[1] & 0x8000) ? 0xffffff : 0; else if (dat[1] & 0x8000) ((uint32_t *)buffer32->line[displine + y_add])[offset + 32 + x_add] ^= 0xffffff; -// pclog("Plot %i, %i (%i %i) %04X %04X\n", offset, displine, x+xx, svga_hwcursor_on, dat[0], dat[1]); } offset++; @@ -2159,7 +2052,6 @@ uint8_t s3_pci_read(int func, int addr, void *p) { s3_t *s3 = (s3_t *)p; svga_t *svga = &s3->svga; -// pclog("S3 PCI read %08X\n", addr); switch (addr) { case 0x00: return 0x33; /*'S3'*/ @@ -2181,13 +2073,16 @@ uint8_t s3_pci_read(int func, int addr, void *p) case 0x10: return 0x00; /*Linear frame buffer address*/ case 0x11: return 0x00; - case 0x12: return ((s3->linear_base & ((s3->linear_size - 1) ^ 0xffffffff)) >> 16) & 0xff; - case 0x13: return ((s3->linear_base & ((s3->linear_size - 1) ^ 0xffffffff)) >> 24) & 0xff; + case 0x12: return svga->crtc[0x5a] & 0x80; + case 0x13: return svga->crtc[0x59]; case 0x30: return s3->pci_regs[0x30] & 0x01; /*BIOS ROM address*/ case 0x31: return 0x00; case 0x32: return s3->pci_regs[0x32]; case 0x33: return s3->pci_regs[0x33]; + + case 0x3c: return s3->int_line; + case 0x3d: return PCI_INTA; } return 0; } @@ -2196,11 +2091,10 @@ void s3_pci_write(int func, int addr, uint8_t val, void *p) { s3_t *s3 = (s3_t *)p; svga_t *svga = &s3->svga; -// pclog("s3_pci_write: addr=%02x val=%02x\n", addr, val); switch (addr) { case PCI_REG_COMMAND: - s3->pci_regs[PCI_REG_COMMAND] = val & 0x27; + s3->pci_regs[PCI_REG_COMMAND] = val & 0x23; if (val & PCI_COMMAND_IO) s3_io_set(s3); else @@ -2209,15 +2103,11 @@ void s3_pci_write(int func, int addr, uint8_t val, void *p) break; case 0x12: - s3->linear_base &= 0xff00ffff; - s3->linear_base |= (((uint32_t) val) << 16); - s3->linear_base &= ((s3->linear_size - 1) ^ 0xffffffff); + svga->crtc[0x5a] = val & 0x80; s3_updatemapping(s3); break; case 0x13: - s3->linear_base &= 0x00ffffff; - s3->linear_base |= (((uint32_t) val) << 24); - s3->linear_base &= ((s3->linear_size - 1) ^ 0xffffffff); + svga->crtc[0x59] = val; s3_updatemapping(s3); break; @@ -2226,15 +2116,17 @@ void s3_pci_write(int func, int addr, uint8_t val, void *p) if (s3->pci_regs[0x30] & 0x01) { uint32_t addr = (s3->pci_regs[0x32] << 16) | (s3->pci_regs[0x33] << 24); -// pclog("S3 bios_rom enabled at %08x\n", addr); mem_mapping_set_addr(&s3->bios_rom.mapping, addr, 0x8000); } else { -// pclog("S3 bios_rom disabled\n"); mem_mapping_disable(&s3->bios_rom.mapping); } return; + + case 0x3c: + s3->int_line = val; + return; } } @@ -2243,15 +2135,15 @@ static int vram_sizes[] = 7, /*512 kB*/ 6, /*1 MB*/ 4, /*2 MB*/ - 2, /*3 MB*/ + 0, 0, /*4 MB*/ 0, - 5, /*6 MB*/ + 0, 0, 3 /*8 MB*/ }; -static void *s3_init(char *bios_fn, int chip) +static void *s3_init(wchar_t *bios_fn, int chip) { s3_t *s3 = malloc(sizeof(s3_t)); svga_t *svga = &s3->svga; @@ -2285,34 +2177,34 @@ static void *s3_init(char *bios_fn, int chip) svga->crtc[0x36] = 2 | (3 << 2) | (1 << 4) | (vram_sizes[vram] << 5); else svga->crtc[0x36] = 1 | (3 << 2) | (1 << 4) | (vram_sizes[vram] << 5); - /* Set video BIOS to 32k (bit 2 = set). */ - svga->crtc[0x37] = 5 | (7 << 5); - if (s3->chip == S3_VISION964) svga->crtc[0x37] |= 0xe; + svga->crtc[0x37] = 1 | (7 << 5); + + svga->vblank_start = s3_vblank_start; s3_io_set(s3); - pci_add(s3_pci_read, s3_pci_write, s3); + s3->card = pci_add(s3_pci_read, s3_pci_write, s3); s3->pci_regs[0x04] = 7; s3->pci_regs[0x30] = 0x00; s3->pci_regs[0x32] = 0x0c; s3->pci_regs[0x33] = 0x00; - - s3->linear_size = 0x10000; s3->chip = chip; s3->wake_fifo_thread = thread_create_event(); s3->fifo_not_full_event = thread_create_event(); s3->fifo_thread = thread_create(fifo_thread, s3); + + s3->int_line = 0; return s3; } -void *s3_bahamas64_init() +void *s3_vision864_init(wchar_t *bios_fn) { - s3_t *s3 = s3_init("roms/bahamas64.BIN", S3_VISION864); + s3_t *s3 = s3_init(bios_fn, S3_VISION864); s3->id = 0xc1; /*Vision864P*/ s3->id_ext = s3->id_ext_pci = 0xc1; @@ -2324,34 +2216,31 @@ void *s3_bahamas64_init() return s3; } +void *s3_bahamas64_init() +{ + s3_t *s3 = s3_vision864_init(L"roms/bahamas64.BIN"); + return s3; +} + +void *s3_phoenix_vision864_init() +{ + s3_t *s3 = s3_vision864_init(L"roms/86c864p.bin"); + return s3; +} + int s3_bahamas64_available() { - return rom_present("roms/bahamas64.BIN"); + return rom_present(L"roms/bahamas64.BIN"); } -void *s3_9fx_init() +int s3_phoenix_vision864_available() { - s3_t *s3 = s3_init("roms/s3_764.bin", S3_TRIO64); - - s3->id = 0xe1; /*Trio64*/ - s3->id_ext = s3->id_ext_pci = 0x11; - s3->packed_mmio = 1; - - s3->getclock = s3_trio64_getclock; - s3->getclock_p = s3; - - return s3; -} - -int s3_9fx_available() -{ - return rom_present("roms/s3_764.bin"); + return rom_present(L"roms/86c864p.bin"); } void *s3_phoenix_trio32_init() { - s3_t *s3 = s3_init("roms/86C732P.bin", S3_TRIO32); - svga_t *svga = &s3->svga; + s3_t *s3 = s3_init(L"roms/86C732P.bin", S3_TRIO32); s3->id = 0xe1; /*Trio32*/ s3->id_ext = 0x10; @@ -2366,16 +2255,15 @@ void *s3_phoenix_trio32_init() int s3_phoenix_trio32_available() { - return rom_present("roms/86C732P.bin"); + return rom_present(L"roms/86C732P.bin"); } -void *s3_phoenix_trio64_init() +void *s3_trio64_init(wchar_t *bios_fn) { - s3_t *s3 = s3_init("roms/86c764x1.bin", S3_TRIO64); - svga_t *svga = &s3->svga; + s3_t *s3 = s3_init(bios_fn, S3_TRIO64); s3->id = 0xe1; /*Trio64*/ - s3->id_ext = s3->id_ext_pci = 0x11; + s3->id_ext = s3->id_ext_pci = 0x11; s3->packed_mmio = 1; s3->getclock = s3_trio64_getclock; @@ -2384,67 +2272,37 @@ void *s3_phoenix_trio64_init() return s3; } -int s3_phoenix_trio64_available() +void *s3_9fx_init() { - return rom_present("roms/86c764x1.bin"); + s3_t *s3 = s3_trio64_init(L"roms/s3_764.bin"); + return s3; } -void *s3_phoenix_vision864_init() +void *s3_phoenix_trio64_init() { - s3_t *s3 = s3_init("roms/86c864p.bin", S3_VISION864); - - s3->id = 0xc1; /*Vision864P*/ - s3->id_ext = s3->id_ext_pci = 0xc1; - s3->packed_mmio = 0; - - s3->getclock = sdac_getclock; - s3->getclock_p = &s3->ramdac; - - return s3; -} - -int s3_phoenix_vision864_available() -{ - return rom_present("roms/86c864p.BIN"); + s3_t *s3 = s3_trio64_init(L"roms/86C764X1.bin"); + return s3; } void *s3_diamond_stealth64_init() { - s3_t *s3 = s3_init("roms/STEALT64.BIN", S3_VISION864); - svga_t *svga = &s3->svga; + s3_t *s3 = s3_trio64_init(L"roms/STEALT64.BIN"); + return s3; +} - s3->id = 0xc1; /*Vision864P*/ - s3->id_ext = s3->id_ext_pci = 0xc1; - s3->packed_mmio = 0; - - s3->getclock = sdac_getclock; - s3->getclock_p = &s3->ramdac; +int s3_9fx_available() +{ + return rom_present(L"roms/s3_764.bin"); +} - return s3; +int s3_phoenix_trio64_available() +{ + return rom_present(L"roms/86c764x1.bin"); } int s3_diamond_stealth64_available() { - return rom_present("roms/STEALT64.BIN"); -} - -void *s3_miro_vision964_init() -{ - s3_t *s3 = s3_init("roms/mirocrystal.VBI", S3_VISION964); - - s3->id = 0xd1; /*Vision964P*/ - s3->id_ext = s3->id_ext_pci = 0xd1; - s3->packed_mmio = 1; - - s3->getclock = bt485_getclock; - s3->getclock_p = &s3->bt485_ramdac; - - return s3; -} - -int s3_miro_vision964_available() -{ - return rom_present("roms/mirocrystal.VBI"); + return rom_present(L"roms/STEALT64.BIN"); } void s3_close(void *p) @@ -2453,6 +2311,10 @@ void s3_close(void *p) svga_close(&s3->svga); + thread_kill(s3->fifo_thread); + thread_destroy_event(s3->wake_fifo_thread); + thread_destroy_event(s3->fifo_not_full_event); + free(s3); } @@ -2491,244 +2353,112 @@ void s3_add_status_info(char *s, int max_len, void *p) static device_config_t s3_bahamas64_config[] = { { - .name = "memory", - .description = "Memory size", - .type = CONFIG_SELECTION, - .selection = + "memory", "Memory size", CONFIG_SELECTION, "", 4, { { - .description = "1 MB", - .value = 1 + "1 MB", 1 }, { - .description = "2 MB", - .value = 2 + "2 MB", 2 }, { - .description = "4 MB", - .value = 4 + "4 MB", 4 }, /*Vision864 also supports 8 MB, however the Paradise BIOS is buggy (VESA modes don't work correctly)*/ { - .description = "" + "" } - }, - .default_int = 4 + } }, { - .type = -1 + "", "", -1 } }; static device_config_t s3_9fx_config[] = { { - .name = "memory", - .description = "Memory size", - .type = CONFIG_SELECTION, - .selection = + "memory", "Memory size", CONFIG_SELECTION, "", 2, { { - .description = "1 MB", - .value = 1 + "1 MB", 1 }, { - .description = "2 MB", - .value = 2 + "2 MB", 2 }, /*Trio64 also supports 4 MB, however the Number Nine BIOS does not*/ { - .description = "" + "" } - }, - .default_int = 2 + } }, { - .type = -1 + "is_pci", "Bus", CONFIG_SELECTION, "", 1, + { + { + "VLB", 0 + }, + { + "PCI", 1 + }, + { + "" + } + } + }, + { + "", "", -1 } }; static device_config_t s3_phoenix_trio32_config[] = { { - .name = "memory", - .description = "Memory size", - .type = CONFIG_SELECTION, - .selection = + "memory", "Memory size", CONFIG_SELECTION, "", 2, { { - .description = "512 KB", - .value = 0 + "512 KB", 0 }, { - .description = "1 MB", - .value = 1 + "1 MB", 1 }, { - .description = "2 MB", - .value = 2 + "2 MB", 2 }, { - .description = "" + "" } - }, - .default_int = 2 + } }, { - .type = -1 + "", "", -1 } }; static device_config_t s3_phoenix_trio64_config[] = { { - .name = "memory", - .description = "Memory size", - .type = CONFIG_SELECTION, - .selection = + "memory", "Memory size", CONFIG_SELECTION, "", 2, { { - .description = "512 KB", - .value = 0 + "512 KB", 0 }, { - .description = "1 MB", - .value = 1 + "1 MB", 1 }, { - .description = "2 MB", - .value = 2 + "2 MB", 2 }, { - .description = "4 MB", - .value = 4 + "4 MB", 4 }, { - .description = "" + "" } - }, - .default_int = 2 + } }, { - .type = -1 - } -}; - -static device_config_t s3_phoenix_vision864_config[] = -{ - { - .name = "memory", - .description = "Memory size", - .type = CONFIG_SELECTION, - .selection = - { - { - .description = "512 KB", - .value = 0 - }, - { - .description = "1 MB", - .value = 1 - }, - { - .description = "2 MB", - .value = 2 - }, - { - .description = "4 MB", - .value = 4 - }, - { - .description = "" - } - }, - .default_int = 2 - }, - { - .type = -1 - } -}; - -static device_config_t s3_diamond_stealth64_config[] = -{ - { - .name = "memory", - .description = "Memory size", - .type = CONFIG_SELECTION, - .selection = - { - { - .description = "512 KB", - .value = 0 - }, - { - .description = "1 MB", - .value = 1 - }, - { - .description = "2 MB", - .value = 2 - }, - { - .description = "3 MB", - .value = 3 - }, - { - .description = "4 MB", - .value = 4 - }, - { - .description = "" - } - }, - .default_int = 2 - }, - { - .type = -1 - } -}; - -static device_config_t s3_miro_vision964_config[] = -{ - { - .name = "memory", - .description = "Memory size", - .type = CONFIG_SELECTION, - .selection = - { - { - .description = "1 MB", - .value = 1 - }, - { - .description = "2 MB", - .value = 2 - }, - { - .description = "3 MB", - .value = 3 - }, - { - .description = "4 MB", - .value = 4 - }, - { - .description = "6 MB", - .value = 6 - }, - { - .description = "8 MB", - .value = 8 - }, - /*Vision864 also supports 8 MB, however the Paradise BIOS is buggy (VESA modes don't work correctly)*/ - { - .description = "" - } - }, - .default_int = 4 - }, - { - .type = -1 + "", "", -1 } }; @@ -2794,12 +2524,12 @@ device_t s3_phoenix_vision864_device = s3_speed_changed, s3_force_redraw, s3_add_status_info, - s3_phoenix_vision864_config + s3_bahamas64_config }; device_t s3_diamond_stealth64_device = { - "S3 Vision864 (Diamond Stealth64)", + "S3 Trio64 (Diamond Stealth64 DRAM)", 0, s3_diamond_stealth64_init, s3_close, @@ -2807,18 +2537,5 @@ device_t s3_diamond_stealth64_device = s3_speed_changed, s3_force_redraw, s3_add_status_info, - s3_diamond_stealth64_config -}; - -device_t s3_miro_vision964_device = -{ - "Micro Crystal S3 Vision964", - 0, - s3_miro_vision964_init, - s3_close, - s3_miro_vision964_available, - s3_speed_changed, - s3_force_redraw, - s3_add_status_info, - s3_miro_vision964_config + s3_phoenix_trio64_config }; diff --git a/src/VIDEO/vid_s3.h b/src/VIDEO/vid_s3.h new file mode 100644 index 000000000..8ace7397d --- /dev/null +++ b/src/VIDEO/vid_s3.h @@ -0,0 +1,26 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Emulation of the S3 Trio32, S3 Trio64, and S3 Vision864 + * graphics cards. + * + * Version: @(#)vid_s3.h 1.0.0 2017/05/30 + * + * Author: Sarah Walker, + * Miran Grca, + * Copyright 2008-2017 Sarah Walker. + * Copyright 2016-2017 Miran Grca. + */ + +device_t s3_bahamas64_device; +device_t s3_9fx_device; +device_t s3_phoenix_trio32_device; +device_t s3_phoenix_trio64_device; +device_t s3_phoenix_vision864_device; +device_t s3_diamond_stealth64_device; +/* device_t s3_miro_vision964_device; */ diff --git a/src/vid_s3_virge.c b/src/VIDEO/vid_s3_virge.c similarity index 93% rename from src/vid_s3_virge.c rename to src/VIDEO/vid_s3_virge.c index 5b0264633..4cb96ab8b 100644 --- a/src/vid_s3_virge.c +++ b/src/VIDEO/vid_s3_virge.c @@ -3,28 +3,29 @@ */ /*S3 ViRGE emulation*/ #include -#include "ibm.h" -#include "device.h" -#include "io.h" -#include "mem.h" -#include "pci.h" -#include "rom.h" -#include "thread.h" +#include "../ibm.h" +#include "../io.h" +#include "../mem.h" +#include "../pci.h" +#include "../rom.h" +#include "../device.h" +#include "../win/plat_thread.h" #include "video.h" #include "vid_s3_virge.h" #include "vid_svga.h" #include "vid_svga_render.h" + static uint64_t virge_time = 0; static uint64_t status_time = 0; static int reg_writes = 0, reg_reads = 0; static int dither[4][4] = { - 0, 4, 1, 5, - 6, 2, 7, 3, - 1, 5, 0, 4, - 7, 3, 6, 2, + {0, 4, 1, 5}, + {6, 2, 7, 3}, + {1, 5, 0, 4}, + {7, 3, 6, 2}, }; #define RB_SIZE 256 @@ -50,7 +51,7 @@ enum FIFO_INVALID = (0x00 << 24), FIFO_WRITE_BYTE = (0x01 << 24), FIFO_WRITE_WORD = (0x02 << 24), - FIFO_WRITE_DWORD = (0x03 << 24), + FIFO_WRITE_DWORD = (0x03 << 24) }; typedef struct @@ -120,6 +121,7 @@ typedef struct virge_t uint32_t linear_base, linear_size; uint8_t pci_regs[256]; + int card; int is_375; @@ -227,9 +229,11 @@ typedef struct virge_t event_t *fifo_not_full_event; int virge_busy; + + uint8_t subsys_stat, subsys_cntl; } virge_t; -static inline void wake_fifo_thread(virge_t *virge) +static __inline void wake_fifo_thread(virge_t *virge) { thread_set_event(virge->wake_fifo_thread); /*Wake up FIFO thread if moving from idle*/ } @@ -291,6 +295,26 @@ enum CMD_SET_COMMAND_NOP = (15 << 27) }; +#define INT_VSY (1 << 0) +#define INT_S3D_DONE (1 << 1) +#define INT_FIFO_OVF (1 << 2) +#define INT_FIFO_EMP (1 << 3) +#define INT_3DF_EMP (1 << 6) +#define INT_MASK 0xff + +static void s3_virge_update_irqs(virge_t *virge) +{ + if (!PCI) + { + return; + } + + if ((virge->svga.crtc[0x32] & 0x10) && (virge->subsys_stat & virge->subsys_cntl & INT_MASK)) + pci_set_irq(virge->card, PCI_INTA); + else + pci_clear_irq(virge->card, PCI_INTA); +} + static void s3_virge_out(uint16_t addr, uint8_t val, void *p) { virge_t *virge = (virge_t *)p; @@ -300,8 +324,6 @@ static void s3_virge_out(uint16_t addr, uint8_t val, void *p) if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) addr ^= 0x60; -// pclog("S3 out %04X %02X %04X:%08X %04X %04X %i\n", addr, val, CS, pc, ES, BX, ins); - switch (addr) { case 0x3c5: @@ -318,16 +340,10 @@ static void s3_virge_out(uint16_t addr, uint8_t val, void *p) } break; - //case 0x3C6: case 0x3C7: case 0x3C8: case 0x3C9: -// pclog("Write RAMDAC %04X %02X %04X:%04X\n", addr, val, CS, pc); - //sdac_ramdac_out(addr,val); - //return; - case 0x3d4: - svga->crtcreg = val;// & 0x7f; + svga->crtcreg = val; return; case 0x3d5: - //pclog("Write CRTC R%02X %02X %04x(%08x):%08x\n", svga->crtcreg, val, CS, cs, pc); if ((svga->crtcreg < 7) && (svga->crtc[0x11] & 0x80)) return; if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80)) @@ -346,6 +362,7 @@ static void s3_virge_out(uint16_t addr, uint8_t val, void *p) case 0x32: if ((svga->crtc[0x67] & 0xc) != 0xc) svga->vrammask = (val & 0x40) ? 0x3ffff : ((virge->memory_size << 20) - 1); + s3_virge_update_irqs(virge); break; case 0x50: @@ -366,7 +383,6 @@ static void s3_virge_out(uint16_t addr, uint8_t val, void *p) case 0x35: virge->bank = (virge->bank & 0x70) | (val & 0xf); -// pclog("CRTC write R35 %02X\n", val); if (svga->chain4) svga->write_bank = svga->read_bank = virge->bank << 16; else svga->write_bank = svga->read_bank = virge->bank << 14; break; @@ -378,7 +394,6 @@ static void s3_virge_out(uint16_t addr, uint8_t val, void *p) break; case 0x6a: virge->bank = val; -// pclog("CRTC write R6a %02X\n", val); if (svga->chain4) svga->write_bank = svga->read_bank = virge->bank << 16; else svga->write_bank = svga->read_bank = virge->bank << 14; break; @@ -420,15 +435,13 @@ static void s3_virge_out(uint16_t addr, uint8_t val, void *p) case 0x67: switch (val >> 4) { - case 3: svga->bpp = 15; break; - case 5: svga->bpp = 16; break; + case 2: case 3: svga->bpp = 15; break; + case 4: case 5: svga->bpp = 16; break; case 7: svga->bpp = 24; break; - case 13: svga->bpp = 32; break; + case 13: svga->bpp = (gfxcard == GFX_VIRGEVX) ? 24 : 32; break; default: svga->bpp = 8; break; } break; - //case 0x55: case 0x43: -// pclog("Write CRTC R%02X %02X\n", crtcreg, val); } if (old != val) { @@ -452,7 +465,6 @@ static uint8_t s3_virge_in(uint16_t addr, void *p) if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) addr ^= 0x60; -// if (addr != 0x3da) pclog("S3 in %04X %04X:%08X ", addr, CS, pc); switch (addr) { case 0x3c1: @@ -461,9 +473,6 @@ static uint8_t s3_virge_in(uint16_t addr, void *p) else ret = svga_in(addr, svga); break; - //case 0x3C6: case 0x3C7: case 0x3C8: case 0x3C9: -// pclog("Read RAMDAC %04X %04X:%04X\n", addr, CS, pc); - //return sdac_ramdac_in(addr); case 0x3c5: if (svga->seqaddr >= 8) @@ -478,7 +487,6 @@ static uint8_t s3_virge_in(uint16_t addr, void *p) ret = svga->crtcreg; break; case 0x3D5: - //pclog("Read CRTC R%02X %04X:%04X (%02x)\n", svga->crtcreg, CS, pc, svga->crtc[svga->crtcreg]); switch (svga->crtcreg) { case 0x2d: ret = virge->virge_id_high; break; /*Extended chip ID*/ @@ -500,7 +508,6 @@ static uint8_t s3_virge_in(uint16_t addr, void *p) ret = svga_in(addr, svga); break; } -// if (addr != 0x3da) pclog("%02X\n", ret); return ret; } @@ -520,7 +527,6 @@ static void s3_virge_recalctimings(svga_t *svga) if ((svga->crtc[0x67] & 0xc) != 0xc) /*VGA mode*/ { svga->ma_latch |= (virge->ma_ext << 16); -//pclog("VGA mode\n"); if (svga->crtc[0x51] & 0x30) svga->rowoffset += (svga->crtc[0x51] & 0x30) << 4; else if (svga->crtc[0x43] & 0x04) svga->rowoffset += 0x100; if (!svga->rowoffset) svga->rowoffset = 256; @@ -546,19 +552,20 @@ static void s3_virge_recalctimings(svga_t *svga) break; } } - -// pclog("svga->rowoffset = %i bpp=%i\n", svga->rowoffset, svga->bpp); - if (svga->bpp == 15 || svga->bpp == 16) - { - svga->htotal >>= 1; - svga->hdisp >>= 1; - } - if (svga->bpp == 24) - { - svga->rowoffset = (svga->rowoffset * 3) / 4; /*Hack*/ - } + + if (gfxcard != GFX_VIRGEVX) + { + if ((svga->bpp == 15) || (svga->bpp == 16)) + { + svga->htotal >>= 1; + svga->hdisp >>= 1; + } + if (svga->bpp == 24) + { + svga->rowoffset = (svga->rowoffset * 3) / 4; /*Hack*/ + } + } svga->vrammask = (svga->crtc[0x32] & 0x40) ? 0x3ffff : ((virge->memory_size << 20) - 1); -//pclog("VGA mode x_disp=%i dispend=%i vtotal=%i\n", svga->hdisp, svga->dispend, svga->vtotal); } else /*Streams mode*/ { @@ -582,7 +589,6 @@ static void s3_virge_recalctimings(svga_t *svga) svga->overlay.ena = (svga->overlay.x >= 0); svga->overlay.v_acc = virge->streams.dda_vert_accumulator; -//pclog("Streams mode x_disp=%i dispend=%i vtotal=%i x=%i y=%i ysize=%i\n", svga->hdisp, svga->dispend, svga->vtotal, svga->overlay.x, svga->overlay.y, svga->overlay.ysize); svga->rowoffset = virge->streams.pri_stride >> 3; switch ((virge->streams.pri_ctrl >> 24) & 0x7) @@ -611,7 +617,7 @@ static void s3_virge_recalctimings(svga_t *svga) if (((svga->miscout >> 2) & 3) == 3) { int n = svga->seqregs[0x12] & 0x1f; - int r = (svga->seqregs[0x12] >> 5) & (virge->is_375 ? 7 : 3); + int r = (svga->seqregs[0x12] >> 5) & ((virge->is_375 || (gfxcard == GFX_VIRGEVX)) ? 7 : 3); int m = svga->seqregs[0x13] & 0x7f; double freq = (((double)m + 2) / (((double)n + 2) * (double)(1 << r))) * 14318184.0; @@ -625,7 +631,6 @@ static void s3_virge_updatemapping(virge_t *virge) if (!(virge->pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_MEM)) { -// pclog("Update mapping - PCI disabled\n"); mem_mapping_disable(&svga->mapping); mem_mapping_disable(&virge->linear_mapping); mem_mapping_disable(&virge->mmio_mapping); @@ -676,7 +681,6 @@ static void s3_virge_updatemapping(virge_t *virge) } virge->linear_base &= ~(virge->linear_size - 1); svga->linear_base = virge->linear_base; -// pclog("%08X %08X %02X %02X %02X\n", linear_base, linear_size, crtc[0x58], crtc[0x59], crtc[0x5a]); pclog("Linear framebuffer at %08X size %08X\n", virge->linear_base, virge->linear_size); if (virge->linear_base == 0xa0000) { @@ -711,6 +715,14 @@ static void s3_virge_updatemapping(virge_t *virge) } +static void s3_virge_vblank_start(svga_t *svga) +{ + virge_t *virge = (virge_t *)svga->p; + + virge->subsys_stat |= INT_VSY; + s3_virge_update_irqs(virge); +} + static void s3_virge_wait_fifo_idle(virge_t *virge) { while (!FIFO_EMPTY) @@ -726,7 +738,6 @@ static uint8_t s3_virge_mmio_read(uint32_t addr, void *p) uint8_t ret; reg_reads++; -// pclog("New MMIO readb %08X\n", addr); switch (addr & 0xffff) { case 0x8505: @@ -757,7 +768,6 @@ static uint8_t s3_virge_mmio_read(uint32_t addr, void *p) static uint16_t s3_virge_mmio_read_w(uint32_t addr, void *p) { reg_reads++; -// pclog("New MMIO readw %08X\n", addr); switch (addr & 0xfffe) { default: @@ -770,7 +780,6 @@ static uint32_t s3_virge_mmio_read_l(uint32_t addr, void *p) virge_t *virge = (virge_t *)p; uint32_t ret = 0xffffffff; reg_reads++; -// pclog("New MMIO readl %08X %04X(%08X):%08X ", addr, CS, cs, pc); switch (addr & 0xfffc) { case 0x8180: @@ -845,9 +854,9 @@ static uint32_t s3_virge_mmio_read_l(uint32_t addr, void *p) ret = (0x10 << 8); else ret = (0x10 << 8) | (1 << 13); + ret |= virge->subsys_stat; if (!virge->virge_busy) wake_fifo_thread(virge); -// pclog("Read status %04x %i\n", ret, virge->s3d_busy); break; case 0xa4d4: s3_virge_wait_fifo_idle(virge); @@ -913,7 +922,6 @@ static uint32_t s3_virge_mmio_read_l(uint32_t addr, void *p) default: ret = s3_virge_mmio_read_w(addr, p) | (s3_virge_mmio_read_w(addr + 2, p) << 16); } -// /*if ((addr & 0xfffc) != 0x8504) */pclog("%02x\n", ret); return ret; } @@ -1270,7 +1278,6 @@ static void fifo_thread(void *param) static void s3_virge_queue(virge_t *virge, uint32_t addr, uint32_t val, uint32_t type) { fifo_entry_t *fifo = &virge->fifo[virge->fifo_write_idx & FIFO_MASK]; - int c; if (FIFO_FULL) { @@ -1295,9 +1302,7 @@ static void s3_virge_queue(virge_t *virge, uint32_t addr, uint32_t val, uint32_t static void s3_virge_mmio_write(uint32_t addr, uint8_t val, void *p) { virge_t *virge = (virge_t *)p; - svga_t *svga = &virge->svga; -// pclog("New MMIO writeb %08X %02X %04x(%08x):%08x\n", addr, val, CS, cs, pc); reg_writes++; if ((addr & 0xfffc) < 0x8000) { @@ -1327,7 +1332,6 @@ static void s3_virge_mmio_write_w(uint32_t addr, uint16_t val, void *p) { virge_t *virge = (virge_t *)p; reg_writes++; -// pclog("New MMIO writew %08X %04X %04x(%08x):%08x\n", addr, val, CS, cs, pc); if ((addr & 0xfffc) < 0x8000) { s3_virge_queue(virge, addr, val, FIFO_WRITE_WORD); @@ -1345,8 +1349,6 @@ static void s3_virge_mmio_write_l(uint32_t addr, uint32_t val, void *p) virge_t *virge = (virge_t *)p; svga_t *svga = &virge->svga; reg_writes++; -// if ((addr & 0xfffc) >= 0xb400 && (addr & 0xfffc) < 0xb800) -// pclog("New MMIO writel %08X %08X %04x(%08x):%08x\n", addr, val, CS, cs, pc); if ((addr & 0xfffc) < 0x8000) { @@ -1389,13 +1391,11 @@ static void s3_virge_mmio_write_l(uint32_t addr, uint32_t val, void *p) virge->streams.blend_ctrl = val; break; case 0x81c0: -// pclog("Write pri_fb0 %08x\n", val); virge->streams.pri_fb0 = val & 0x3fffff; svga_recalctimings(svga); svga->fullchange = changeframecount; break; case 0x81c4: -// pclog("Write pri_fb1 %08x\n", val); virge->streams.pri_fb1 = val & 0x3fffff; svga_recalctimings(svga); svga->fullchange = changeframecount; @@ -1406,7 +1406,6 @@ static void s3_virge_mmio_write_l(uint32_t addr, uint32_t val, void *p) svga->fullchange = changeframecount; break; case 0x81cc: -// pclog("Write buffer_ctrl %08x\n", val); virge->streams.buffer_ctrl = val; svga_recalctimings(svga); svga->fullchange = changeframecount; @@ -1475,6 +1474,12 @@ static void s3_virge_mmio_write_l(uint32_t addr, uint32_t val, void *p) svga_recalctimings(svga); svga->fullchange = changeframecount; break; + + case 0x8504: + virge->subsys_stat &= ~(val & 0xff); + virge->subsys_cntl = (val >> 8); + s3_virge_update_irqs(virge); + break; case 0xa000: case 0xa004: case 0xa008: case 0xa00c: case 0xa010: case 0xa014: case 0xa018: case 0xa01c: @@ -1659,11 +1664,6 @@ static void s3_virge_mmio_write_l(uint32_t addr, uint32_t val, void *p) virge->s3d_tri.cmd_set = val; if (!(val & CMD_SET_AE)) queue_triangle(virge); -/* { - thread_set_event(virge->wake_render_thread); - thread_wait_event(virge->wake_main_thread, -1); - } */ -// s3_virge_triangle(virge); break; case 0xb504: virge->s3d_tri.tbv = val & 0xfffff; @@ -1768,12 +1768,6 @@ static void s3_virge_mmio_write_l(uint32_t addr, uint32_t val, void *p) virge->s3d_tri.tlr = val >> 31; if (virge->s3d_tri.cmd_set & CMD_SET_AE) queue_triangle(virge); -/* { - thread_set_event(virge->wake_render_thread); - thread_wait_event(virge->wake_main_thread, -1); - }*/ - -// s3_virge_triangle(virge); break; } } @@ -1874,7 +1868,6 @@ static void s3_virge_mmio_write_l(uint32_t addr, uint32_t val, void *p) static void s3_virge_bitblt(virge_t *virge, int count, uint32_t cpu_dat) { - int cpu_input = (count != -1); uint8_t *vram = virge->svga.vram; uint32_t mono_pattern[64]; int count_mask; @@ -1884,6 +1877,11 @@ static void s3_virge_bitblt(virge_t *virge, int count, uint32_t cpu_dat) int x_mul; int cpu_dat_shift; uint32_t *pattern_data; + uint32_t src_addr; + uint32_t dest_addr; + uint32_t source = 0, dest, pattern; + uint32_t out = 0; + int update; switch (virge->s3d.cmd_set & CMD_SET_FORMAT_MASK) { @@ -1976,11 +1974,10 @@ static void s3_virge_bitblt(virge_t *virge, int count, uint32_t cpu_dat) return; while (count) { - uint32_t src_addr = virge->s3d.src_base + (virge->s3d.src_x * x_mul) + (virge->s3d.src_y * virge->s3d.src_str); - uint32_t dest_addr = virge->s3d.dest_base + (virge->s3d.dest_x * x_mul) + (virge->s3d.dest_y * virge->s3d.dest_str); - uint32_t source, dest, pattern; - uint32_t out = 0; - int update = 1; + src_addr = virge->s3d.src_base + (virge->s3d.src_x * x_mul) + (virge->s3d.src_y * virge->s3d.src_str); + dest_addr = virge->s3d.dest_base + (virge->s3d.dest_x * x_mul) + (virge->s3d.dest_y * virge->s3d.dest_str); + out = 0; + update = 1; switch (virge->s3d.cmd_set & (CMD_SET_MS | CMD_SET_IDS)) { @@ -2221,14 +2218,12 @@ skip_line: virge->s3d.dest_l = virge->s3d.plxstart; virge->s3d.h = virge->s3d.pycnt & 0x7ff; virge->s3d.rop = (virge->s3d.cmd_set >> 17) & 0xff; - //pclog("Start poly - l=%08x r=%08x h=%i rop=%02x\n", virge->s3d.dest_l, virge->s3d.dest_r, virge->s3d.h, virge->s3d.rop); while (virge->s3d.h) { int x = virge->s3d.dest_l >> 20; int xend = virge->s3d.dest_r >> 20; int y = virge->s3d.pystart & 0x7ff; int xdir = (x < xend) ? 1 : -1; - //pclog(" %03i: %i - %i %08x-%08x\n", y, x, xend, virge->s3d.dest_l, virge->s3d.dest_r); do { uint32_t dest_addr = virge->s3d.dest_base + (x * x_mul) + (y * virge->s3d.dest_str); @@ -2894,6 +2889,21 @@ static void tri(virge_t *virge, s3d_t *s3d_tri, s3d_state_t *state, int yc, int3 uint32_t dest_offset, z_offset; + uint32_t src_col; + int src_r = 0, src_g = 0, src_b = 0; + + int x; + int xe; + uint32_t z; + + uint32_t dest_addr, z_addr; + int dx; + int x_offset; + int xz_offset; + + int update; + uint16_t src_z = 0; + if (s3d_tri->cmd_set & CMD_SET_HC) { if (state->y < s3d_tri->clip_t) @@ -2930,21 +2940,20 @@ static void tri(virge_t *virge, s3d_t *s3d_tri, s3d_state_t *state, int yc, int3 for (; y_count > 0; y_count--) { - int x = (state->x1 + ((1 << 20) - 1)) >> 20; - int xe = (state->x2 + ((1 << 20) - 1)) >> 20; - uint32_t z = (state->base_z > 0) ? (state->base_z << 1) : 0; + x = (state->x1 + ((1 << 20) - 1)) >> 20; + xe = (state->x2 + ((1 << 20) - 1)) >> 20; + z = (state->base_z > 0) ? (state->base_z << 1) : 0; if (x_dir < 0) { x--; xe--; } - if (x != xe && (x_dir > 0 && x < xe) || (x_dir < 0 && x > xe)) + if (((x != xe) && ((x_dir > 0) && (x < xe))) || ((x_dir < 0) && (x > xe))) { - uint32_t dest_addr, z_addr; - int dx = (x_dir > 0) ? ((31 - ((state->x1-1) >> 15)) & 0x1f) : (((state->x1-1) >> 15) & 0x1f); - int x_offset = x_dir * (bpp + 1); - int xz_offset = x_dir << 1; + dx = (x_dir > 0) ? ((31 - ((state->x1-1) >> 15)) & 0x1f) : (((state->x1-1) >> 15) & 0x1f); + x_offset = x_dir * (bpp + 1); + xz_offset = x_dir << 1; if (x_dir > 0) dx += 1; state->r = state->base_r + ((s3d_tri->TdRdX * dx) >> 5); @@ -2957,8 +2966,6 @@ static void tri(virge_t *virge, s3d_t *s3d_tri, s3d_state_t *state, int yc, int3 state->d = state->base_d + ((s3d_tri->TdDdX * dx) >> 5); z += ((s3d_tri->TdZdX * dx) >> 5); -// pclog("Draw Y=%i X=%i to XE=%i %i %08x %08x %08x %08x %08x %08x %08x %08x %i %08x\n", state->y, x, xe, dx, state->x1, state->x2, dx1, virge->s3d.TdWdX, state->u, state->v, virge->s3d.TdUdX, virge->s3d.TdUdY, dx, (virge->s3d.TdUdX * dx) >> 4); - if (s3d_tri->cmd_set & CMD_SET_HC) { if (x_dir > 0) @@ -3020,8 +3027,7 @@ static void tri(virge_t *virge, s3d_t *s3d_tri, s3d_state_t *state, int yc, int3 for (; x != xe; x = (x + x_dir) & 0xfff) { - int update = 1; - uint16_t src_z; + update = 1; _x = x; _y = state->y; if (use_z) @@ -3038,9 +3044,6 @@ static void tri(virge_t *virge, s3d_t *s3d_tri, s3d_state_t *state, int yc, int3 if (s3d_tri->cmd_set & CMD_SET_ABC_ENABLE) { - uint32_t src_col; - int src_r, src_g, src_b; - switch (bpp) { case 0: /*8 bpp*/ @@ -3167,7 +3170,6 @@ static void s3_virge_triangle(virge_t *virge, s3d_t *s3d_tri) { case 0: dest_pixel = dest_pixel_gouraud_shaded_triangle; -// pclog("dest_pixel_gouraud_shaded_triangle\n"); break; case 1: case 5: @@ -3175,15 +3177,12 @@ static void s3_virge_triangle(virge_t *virge, s3d_t *s3d_tri) { case 0: dest_pixel = dest_pixel_lit_texture_reflection; -// pclog("dest_pixel_lit_texture_reflection\n"); break; case 1: dest_pixel = dest_pixel_lit_texture_modulate; -// pclog("dest_pixel_lit_texture_modulate\n"); break; case 2: dest_pixel = dest_pixel_lit_texture_decal; -// pclog("dest_pixel_lit_texture_decal\n"); break; default: pclog("bad triangle type %x\n", (s3d_tri->cmd_set >> 27) & 0xf); @@ -3193,7 +3192,6 @@ static void s3_virge_triangle(virge_t *virge, s3d_t *s3d_tri) case 2: case 6: dest_pixel = dest_pixel_unlit_texture_triangle; -// pclog("dest_pixel_unlit_texture_triangle\n"); break; default: pclog("bad triangle type %x\n", (s3d_tri->cmd_set >> 27) & 0xf); @@ -3204,47 +3202,39 @@ static void s3_virge_triangle(virge_t *virge, s3d_t *s3d_tri) { case 0: case 1: tex_sample = tex_sample_mipmap; -// pclog("use tex_sample_mipmap\n"); break; case 2: case 3: tex_sample = virge->bilinear_enabled ? tex_sample_mipmap_filter : tex_sample_mipmap; -// pclog("use tex_sample_mipmap_filter\n"); break; case 4: case 5: tex_sample = tex_sample_normal; -// pclog("use tex_sample_normal\n"); break; case 6: case 7: tex_sample = virge->bilinear_enabled ? tex_sample_normal_filter : tex_sample_normal; -// pclog("use tex_sample_normal_filter\n"); break; case (0 | 8): case (1 | 8): if (virge->is_375) tex_sample = tex_sample_persp_mipmap_375; else tex_sample = tex_sample_persp_mipmap; -// pclog("use tex_sample_persp_mipmap\n"); break; case (2 | 8): case (3 | 8): if (virge->is_375) tex_sample = virge->bilinear_enabled ? tex_sample_persp_mipmap_filter_375 : tex_sample_persp_mipmap_375; else tex_sample = virge->bilinear_enabled ? tex_sample_persp_mipmap_filter : tex_sample_persp_mipmap; -// pclog("use tex_sample_persp_mipmap_filter\n"); break; case (4 | 8): case (5 | 8): if (virge->is_375) tex_sample = tex_sample_persp_normal_375; else tex_sample = tex_sample_persp_normal; -// pclog("use tex_sample_persp_normal\n"); break; case (6 | 8): case (7 | 8): if (virge->is_375) tex_sample = virge->bilinear_enabled ? tex_sample_persp_normal_filter_375 : tex_sample_persp_normal_375; else tex_sample = virge->bilinear_enabled ? tex_sample_persp_normal_filter : tex_sample_persp_normal; -// pclog("use tex_sample_persp_normal_filter\n"); break; } @@ -3255,19 +3245,15 @@ static void s3_virge_triangle(virge_t *virge, s3d_t *s3d_tri) break; case 1: tex_read = (s3d_tri->cmd_set & CMD_SET_TWE) ? tex_ARGB4444 : tex_ARGB4444_nowrap; -// pclog("tex_ARGB4444\n"); break; case 2: tex_read = (s3d_tri->cmd_set & CMD_SET_TWE) ? tex_ARGB1555 : tex_ARGB1555_nowrap; -// pclog("tex_ARGB1555 %i\n", (s3d_tri->cmd_set >> 5) & 7); break; default: pclog("bad texture type %i\n", (s3d_tri->cmd_set >> 5) & 7); tex_read = (s3d_tri->cmd_set & CMD_SET_TWE) ? tex_ARGB1555 : tex_ARGB1555_nowrap; break; } - -// pclog("Triangle %i %i,%i to %i,%i %08x\n", y, x1 >> 20, y, s3d_tri->txend01 >> 20, y - (s3d_tri->ty01 + s3d_tri->ty12), state.cmd_set); state.y = s3d_tri->tys; state.x1 = s3d_tri->txs; @@ -3301,20 +3287,19 @@ static void render_thread(void *param) thread_set_event(virge->not_full_event); } virge->s3d_busy = 0; + virge->subsys_stat |= INT_S3D_DONE; + s3_virge_update_irqs(virge); } } static void queue_triangle(virge_t *virge) { - int c; -// pclog("queue_triangle: read=%i write=%i RB_ENTRIES=%i RB_FULL=%i\n", virge->s3d_read_idx, virge->s3d_write_idx, RB_ENTRIES, RB_FULL); if (RB_FULL) { thread_reset_event(virge->not_full_event); if (RB_FULL) thread_wait_event(virge->not_full_event, -1); /*Wait for room in ringbuffer*/ } -// pclog(" add at read=%i write=%i %i\n", virge->s3d_read_idx, virge->s3d_write_idx, virge->s3d_write_idx & RB_MASK); virge->s3d_buffer[virge->s3d_write_idx & RB_MASK] = virge->s3d_tri; virge->s3d_write_idx++; if (!virge->s3d_busy) @@ -3328,10 +3313,12 @@ static void s3_virge_hwcursor_draw(svga_t *svga, int displine) uint16_t dat[2]; int xx; int offset = svga->hwcursor_latch.x - svga->hwcursor_latch.xoff; - int y_add = enable_overscan ? 16 : 0; - int x_add = enable_overscan ? 8 : 0; + int y_add = (enable_overscan && !suppress_overscan) ? 16 : 0; + int x_add = (enable_overscan && !suppress_overscan) ? 8 : 0; -// pclog("HWcursor %i %i\n", svga->hwcursor_latch.x, svga->hwcursor_latch.y); + if (svga->interlace && svga->hwcursor_oddeven) + svga->hwcursor_latch.addr += 16; + for (x = 0; x < 64; x += 16) { dat[0] = (svga->vram[svga->hwcursor_latch.addr] << 8) | svga->vram[svga->hwcursor_latch.addr + 1]; @@ -3363,7 +3350,6 @@ static void s3_virge_hwcursor_draw(svga_t *svga, int displine) ((uint32_t *)buffer32->line[displine + y_add])[offset + 32 + x_add] = virge->hwcursor_col[dat[1] >> 15]; else if (dat[1] & 0x8000) ((uint32_t *)buffer32->line[displine + y_add])[offset + 32 + x_add] ^= 0xffffff; -// pclog("Plot %i, %i (%i %i) %04X %04X\n", offset, displine, x+xx, svga->hwcursor_on, dat[0], dat[1]); } offset++; @@ -3373,6 +3359,8 @@ static void s3_virge_hwcursor_draw(svga_t *svga, int displine) } svga->hwcursor_latch.addr += 4; } + if (svga->interlace && !svga->hwcursor_oddeven) + svga->hwcursor_latch.addr += 16; } #define DECODE_YCbCr() \ @@ -3448,18 +3436,18 @@ static void s3_virge_hwcursor_draw(svga_t *svga, int displine) b[x_write+1] = y2 + dB; \ CLAMP(b[x_write+1]); \ \ - r[x_write+2] = y2 + dR; \ + r[x_write+2] = y3 + dR; \ CLAMP(r[x_write+2]); \ - g[x_write+2] = y2 - dG; \ + g[x_write+2] = y3 - dG; \ CLAMP(g[x_write+2]); \ - b[x_write+2] = y2 + dB; \ + b[x_write+2] = y3 + dB; \ CLAMP(b[x_write+2]); \ \ - r[x_write+3] = y2 + dR; \ + r[x_write+3] = y4 + dR; \ CLAMP(r[x_write+3]); \ - g[x_write+3] = y2 - dG; \ + g[x_write+3] = y4 - dG; \ CLAMP(g[x_write+3]); \ - b[x_write+3] = y2 + dB; \ + b[x_write+3] = y4 + dB; \ CLAMP(b[x_write+3]); \ \ x_write = (x_write + 4) & 7; \ @@ -3608,9 +3596,6 @@ static void s3_virge_overlay_draw(svga_t *svga, int displine) int offset = (virge->streams.sec_x - virge->streams.pri_x) + 1; int h_acc = virge->streams.dda_horiz_accumulator; int r[8], g[8], b[8]; - int r_samp[8] = {0, 0, 0, 0, 0, 0, 0, 0}; - int g_samp[8] = {0, 0, 0, 0, 0, 0, 0, 0}; - int b_samp[8] = {0, 0, 0, 0, 0, 0, 0, 0}; int x_size, x_read = 4, x_write = 4; int x; uint32_t *p; @@ -3655,7 +3640,6 @@ static uint8_t s3_virge_pci_read(int func, int addr, void *p) virge_t *virge = (virge_t *)p; svga_t *svga = &virge->svga; uint8_t ret = 0; -// pclog("S3 PCI read %08X ", addr); switch (addr) { case 0x00: ret = 0x33; break; /*'S3'*/ @@ -3694,7 +3678,6 @@ static uint8_t s3_virge_pci_read(int func, int addr, void *p) case 0x3f: ret = 0xff; break; } -// pclog("%02X\n", ret); return ret; } @@ -3702,7 +3685,6 @@ static void s3_virge_pci_write(int func, int addr, uint8_t val, void *p) { virge_t *virge = (virge_t *)p; svga_t *svga = &virge->svga; -// pclog("S3 PCI write %08X %02X %04X:%08X\n", addr, val, CS, pc); switch (addr) { case 0x00: case 0x01: case 0x02: case 0x03: @@ -3738,13 +3720,11 @@ static void s3_virge_pci_write(int func, int addr, uint8_t val, void *p) if (virge->pci_regs[0x30] & 0x01) { uint32_t addr = (virge->pci_regs[0x32] << 16) | (virge->pci_regs[0x33] << 24); -// pclog("Virge bios_rom enabled at %08x\n", addr); mem_mapping_set_addr(&virge->bios_rom.mapping, addr, 0x8000); mem_mapping_enable(&virge->bios_rom.mapping); } else { -// pclog("Virge bios_rom disabled\n"); mem_mapping_disable(&virge->bios_rom.mapping); } return; @@ -3768,8 +3748,9 @@ static void *s3_virge_init() s3_virge_in, s3_virge_out, s3_virge_hwcursor_draw, s3_virge_overlay_draw); + virge->svga.vblank_start = s3_virge_vblank_start; - rom_init(&virge->bios_rom, "roms/s3virge.bin", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + rom_init(&virge->bios_rom, L"roms/s3virge.bin", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); if (PCI) mem_mapping_disable(&virge->bios_rom.mapping); @@ -3808,6 +3789,7 @@ static void *s3_virge_init() virge->pci_regs[6] = 0; virge->pci_regs[7] = 2; virge->pci_regs[0x32] = 0x0c; + virge->pci_regs[0x3c] = device_get_config_int("irq"); virge->pci_regs[0x3d] = 1; virge->pci_regs[0x3e] = 4; virge->pci_regs[0x3f] = 0xff; @@ -3828,13 +3810,13 @@ static void *s3_virge_init() break; } - virge->svga.crtc[0x37] = 1;// | (7 << 5); + virge->svga.crtc[0x37] = 1; virge->svga.crtc[0x53] = 1 << 3; virge->svga.crtc[0x59] = 0x70; virge->is_375 = 0; - pci_add(s3_virge_pci_read, s3_virge_pci_write, virge); + virge->card = pci_add(s3_virge_pci_read, s3_virge_pci_write, virge); virge->wake_render_thread = thread_create_event(); virge->wake_main_thread = thread_create_event(); @@ -3848,22 +3830,22 @@ static void *s3_virge_init() return virge; } -static void *s3_virge_375_init() +static void *s3_virge_988_init() { virge_t *virge = malloc(sizeof(virge_t)); memset(virge, 0, sizeof(virge_t)); - + virge->bilinear_enabled = device_get_config_int("bilinear"); virge->dithering_enabled = device_get_config_int("dithering"); virge->memory_size = device_get_config_int("memory"); - + svga_init(&virge->svga, virge, virge->memory_size << 20, s3_virge_recalctimings, s3_virge_in, s3_virge_out, s3_virge_hwcursor_draw, s3_virge_overlay_draw); - rom_init(&virge->bios_rom, "roms/86c375_1.bin", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + rom_init(&virge->bios_rom, L"roms/diamondstealth3000.VBI", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); if (PCI) mem_mapping_disable(&virge->bios_rom.mapping); @@ -3902,6 +3884,102 @@ static void *s3_virge_375_init() virge->pci_regs[6] = 0; virge->pci_regs[7] = 2; virge->pci_regs[0x32] = 0x0c; + virge->pci_regs[0x3c] = device_get_config_int("irq"); + virge->pci_regs[0x3d] = 1; + virge->pci_regs[0x3e] = 4; + virge->pci_regs[0x3f] = 0xff; + + virge->virge_id_high = 0x88; + virge->virge_id_low = 0x3d; + virge->virge_rev = 0; + virge->virge_id = 0xe1; + + switch (virge->memory_size) + { + case 2: + virge->svga.crtc[0x36] = 2 | (0 << 2) | (1 << 4) | (4 << 5); + break; + case 4: + default: + virge->svga.crtc[0x36] = 2 | (0 << 2) | (1 << 4) | (0 << 5); + break; + } + + virge->svga.crtc[0x37] = 1; + virge->svga.crtc[0x53] = 1 << 3; + virge->svga.crtc[0x59] = 0x70; + + virge->is_375 = 0; + + pci_add(s3_virge_pci_read, s3_virge_pci_write, virge); + + virge->wake_render_thread = thread_create_event(); + virge->wake_main_thread = thread_create_event(); + virge->not_full_event = thread_create_event(); + virge->render_thread = thread_create(render_thread, virge); + + virge->wake_fifo_thread = thread_create_event(); + virge->fifo_not_full_event = thread_create_event(); + virge->fifo_thread = thread_create(fifo_thread, virge); + + return virge; +} + +static void *s3_virge_375_init(wchar_t *romfn) +{ + virge_t *virge = malloc(sizeof(virge_t)); + memset(virge, 0, sizeof(virge_t)); + + virge->bilinear_enabled = device_get_config_int("bilinear"); + virge->dithering_enabled = device_get_config_int("dithering"); + virge->memory_size = device_get_config_int("memory"); + + svga_init(&virge->svga, virge, virge->memory_size << 20, + s3_virge_recalctimings, + s3_virge_in, s3_virge_out, + s3_virge_hwcursor_draw, + s3_virge_overlay_draw); + + rom_init(&virge->bios_rom, romfn, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + if (PCI) + mem_mapping_disable(&virge->bios_rom.mapping); + + mem_mapping_add(&virge->mmio_mapping, 0, 0, s3_virge_mmio_read, + s3_virge_mmio_read_w, + s3_virge_mmio_read_l, + s3_virge_mmio_write, + s3_virge_mmio_write_w, + s3_virge_mmio_write_l, + NULL, + 0, + virge); + mem_mapping_add(&virge->new_mmio_mapping, 0, 0, s3_virge_mmio_read, + s3_virge_mmio_read_w, + s3_virge_mmio_read_l, + s3_virge_mmio_write, + s3_virge_mmio_write_w, + s3_virge_mmio_write_l, + NULL, + 0, + virge); + mem_mapping_add(&virge->linear_mapping, 0, 0, svga_read_linear, + svga_readw_linear, + svga_readl_linear, + svga_write_linear, + svga_writew_linear, + svga_writel_linear, + NULL, + 0, + &virge->svga); + + io_sethandler(0x03c0, 0x0020, s3_virge_in, NULL, NULL, s3_virge_out, NULL, NULL, virge); + + virge->pci_regs[4] = 3; + virge->pci_regs[5] = 0; + virge->pci_regs[6] = 0; + virge->pci_regs[7] = 2; + virge->pci_regs[0x32] = 0x0c; + virge->pci_regs[0x3c] = device_get_config_int("irq"); virge->pci_regs[0x3d] = 1; virge->pci_regs[0x3e] = 4; virge->pci_regs[0x3f] = 0xff; @@ -3921,8 +3999,7 @@ static void *s3_virge_375_init() virge->svga.crtc[0x36] = 2 | (0 << 2) | (1 << 4) | (0 << 5); break; } -// virge->svga.crtc[0x36] = 2 | (0 << 2) | (1 << 4); - virge->svga.crtc[0x37] = 1;// | (7 << 5); + virge->svga.crtc[0x37] = 1; virge->svga.crtc[0x53] = 1 << 3; virge->svga.crtc[0x59] = 0x70; @@ -3944,6 +4021,16 @@ static void *s3_virge_375_init() return virge; } +static void *s3_virge_375_1_init() +{ + return s3_virge_375_init(L"roms/86c375_1.bin"); +} + +static void *s3_virge_375_4_init() +{ + return s3_virge_375_init(L"roms/86c375_4.bin"); +} + static void s3_virge_close(void *p) { virge_t *virge = (virge_t *)p; @@ -3958,6 +4045,10 @@ static void s3_virge_close(void *p) thread_destroy_event(virge->wake_main_thread); thread_destroy_event(virge->wake_render_thread); + thread_kill(virge->fifo_thread); + thread_destroy_event(virge->wake_fifo_thread); + thread_destroy_event(virge->fifo_not_full_event); + svga_close(&virge->svga); free(virge); @@ -3965,12 +4056,22 @@ static void s3_virge_close(void *p) static int s3_virge_available() { - return rom_present("roms/s3virge.bin"); + return rom_present(L"roms/s3virge.bin"); } -static int s3_virge_375_available() +static int s3_virge_988_available() { - return rom_present("roms/86c375_1.bin"); + return rom_present(L"roms/diamondstealth3000.VBI"); +} + +static int s3_virge_375_1_available() +{ + return rom_present(L"roms/86c375_1.bin"); +} + +static int s3_virge_375_4_available() +{ + return rom_present(L"roms/86c375_4.bin"); } static void s3_virge_speed_changed(void *p) @@ -4011,39 +4112,66 @@ static void s3_virge_add_status_info(char *s, int max_len, void *p) static device_config_t s3_virge_config[] = { { - .name = "memory", - .description = "Memory size", - .type = CONFIG_SELECTION, - .selection = + "memory", "Memory size", CONFIG_SELECTION, "", 4, { { - .description = "2 MB", - .value = 2 + "2 MB", 2 }, { - .description = "4 MB", - .value = 4 + "4 MB", 4 }, { - .description = "" + "" + } + } + }, + { + "irq", "IRQ", CONFIG_SELECTION, "", 3, + { + { + "IRQ 3", 3 + }, + { + "IRQ 4", 4 + }, + { + "IRQ 5", 5 + }, + { + "IRQ 7", 7 + }, + { + "IRQ 9", 9 + }, + { + "IRQ 10", 10 + }, + { + "IRQ 11", 11 + }, + { + "IRQ 12", 12 + }, + { + "IRQ 14", 14 + }, + { + "IRQ 15", 15 + }, + { + "" } }, - .default_int = 4 + .default_int = 3 }, { - .name = "bilinear", - .description = "Bilinear filtering", - .type = CONFIG_BINARY, - .default_int = 1 + "bilinear", "Bilinear filtering", CONFIG_BINARY, "", 1 }, { - .name = "dithering", - .description = "Dithering", - .type = CONFIG_BINARY, - .default_int = 1 + "dithering", "Dithering", CONFIG_BINARY, "", 1 }, { - .type = -1 + "", "", -1 } }; @@ -4060,13 +4188,39 @@ device_t s3_virge_device = s3_virge_config }; -device_t s3_virge_375_device = +device_t s3_virge_988_device = { - "S3 ViRGE/DX", + "Diamond Stealth 3D 3000 (S3 ViRGE/VX)", 0, - s3_virge_375_init, + s3_virge_988_init, s3_virge_close, - s3_virge_375_available, + s3_virge_988_available, + s3_virge_speed_changed, + s3_virge_force_redraw, + s3_virge_add_status_info, + s3_virge_config +}; + +device_t s3_virge_375_device = +{ + "S3 ViRGE/DX", + 0, + s3_virge_375_1_init, + s3_virge_close, + s3_virge_375_1_available, + s3_virge_speed_changed, + s3_virge_force_redraw, + s3_virge_add_status_info, + s3_virge_config +}; + +device_t s3_virge_375_4_device = +{ + "S3 ViRGE/DX (VBE 2.0)", + 0, + s3_virge_375_4_init, + s3_virge_close, + s3_virge_375_4_available, s3_virge_speed_changed, s3_virge_force_redraw, s3_virge_add_status_info, diff --git a/src/vid_s3_virge.h b/src/VIDEO/vid_s3_virge.h similarity index 64% rename from src/vid_s3_virge.h rename to src/VIDEO/vid_s3_virge.h index 3419b8657..74ee6454b 100644 --- a/src/vid_s3_virge.h +++ b/src/VIDEO/vid_s3_virge.h @@ -2,4 +2,6 @@ see COPYING for more details */ extern device_t s3_virge_device; +extern device_t s3_virge_988_device; extern device_t s3_virge_375_device; +extern device_t s3_virge_375_4_device; diff --git a/src/vid_sdac_ramdac.c b/src/VIDEO/vid_sdac_ramdac.c similarity index 81% rename from src/vid_sdac_ramdac.c rename to src/VIDEO/vid_sdac_ramdac.c index 412e4836e..3bff85104 100644 --- a/src/vid_sdac_ramdac.c +++ b/src/VIDEO/vid_sdac_ramdac.c @@ -3,12 +3,13 @@ */ /*87C716 'SDAC' true colour RAMDAC emulation*/ /*Misidentifies as AT&T 21C504*/ -#include "ibm.h" -#include "mem.h" +#include "../ibm.h" +#include "../mem.h" #include "video.h" #include "vid_svga.h" #include "vid_sdac_ramdac.h" + /* Returning divider * 2 */ int sdac_get_clock_divider(sdac_ramdac_t *ramdac) { @@ -25,7 +26,6 @@ int sdac_get_clock_divider(sdac_ramdac_t *ramdac) void sdac_ramdac_out(uint16_t addr, uint8_t val, sdac_ramdac_t *ramdac, svga_t *svga) { -// /*if (CS!=0xC000) */pclog("OUT RAMDAC %04X %02X %i %04X:%04X %i\n",addr,val,sdac_ramdac.magic_count,CS,pc, sdac_ramdac.rs2); switch (addr) { case 0x3C6: @@ -39,19 +39,18 @@ void sdac_ramdac_out(uint16_t addr, uint8_t val, sdac_ramdac_t *ramdac, svga_t * if (ramdac->magic_count == 4) { ramdac->command = val; -// pclog("RAMDAC command reg now %02X\n", val); switch (val >> 4) { case 0x2: case 0x3: case 0x8: case 0xa: svga->bpp = 15; break; case 0x4: case 0x9: case 0xe: svga->bpp = 24; break; case 0x5: case 0x6: case 0xc: svga->bpp = 16; break; - case 0x7: svga->bpp = 32; break; + case 0x7: case 0xd: svga->bpp = 32; break; case 0: case 1: default: svga->bpp = 8; break; } svga_recalctimings(svga); + pclog("RAMDAC: Mode: %i, BPP: %i\n", val >> 4, svga->bpp); } - //ramdac->magic_count = 0; break; case 0x3C7: @@ -71,7 +70,6 @@ void sdac_ramdac_out(uint16_t addr, uint8_t val, sdac_ramdac_t *ramdac, svga_t * if (!ramdac->reg_ff) ramdac->regs[ramdac->windex] = (ramdac->regs[ramdac->windex] & 0xff00) | val; else ramdac->regs[ramdac->windex] = (ramdac->regs[ramdac->windex] & 0x00ff) | (val << 8); ramdac->reg_ff = !ramdac->reg_ff; -// pclog("RAMDAC reg %02X now %04X\n", ramdac->windex, ramdac->regs[ramdac->windex]); if (!ramdac->reg_ff) ramdac->windex++; } break; @@ -82,7 +80,6 @@ void sdac_ramdac_out(uint16_t addr, uint8_t val, sdac_ramdac_t *ramdac, svga_t * uint8_t sdac_ramdac_in(uint16_t addr, sdac_ramdac_t *ramdac, svga_t *svga) { uint8_t temp; -// /*if (CS!=0xC000) */pclog("IN RAMDAC %04X %04X:%04X %i\n",addr,CS,pc, ramdac->rs2); switch (addr) { case 0x3C6: @@ -101,27 +98,15 @@ uint8_t sdac_ramdac_in(uint16_t addr, sdac_ramdac_t *ramdac, svga_t *svga) } return temp; case 0x3C7: -// if (ramdac->magic_count < 4) -// { ramdac->magic_count=0; -// break; -// } if (ramdac->rs2) return ramdac->rindex; break; case 0x3C8: -// if (ramdac->magic_count < 4) -// { ramdac->magic_count=0; -// break; -// } if (ramdac->rs2) return ramdac->windex; break; case 0x3C9: -// if (ramdac->magic_count < 4) -// { ramdac->magic_count=0; -// break; -// } if (ramdac->rs2) { if (!ramdac->reg_ff) temp = ramdac->regs[ramdac->rindex] & 0xff; @@ -144,7 +129,6 @@ float sdac_getclock(int clock, void *p) sdac_ramdac_t *ramdac = (sdac_ramdac_t *)p; float t; int m, n1, n2; -// pclog("SDAC_Getclock %i %04X\n", clock, ramdac->regs[clock]); if (clock == 0) return 25175000.0; if (clock == 1) return 28322000.0; clock ^= 1; /*Clocks 2 and 3 seem to be reversed*/ @@ -152,6 +136,5 @@ float sdac_getclock(int clock, void *p) n1 = ((ramdac->regs[clock] >> 8) & 0x1f) + 2; n2 = ((ramdac->regs[clock] >> 13) & 0x07); t = (14318184.0 * ((float)m / (float)n1)) / (float)(1 << n2); -// pclog("SDAC clock %i %i %i %f %04X %f %i\n", m, n1, n2, t, ramdac->regs[2], 14318184.0 * ((float)m / (float)n1), 1 << n2); return t; } diff --git a/src/vid_sdac_ramdac.h b/src/VIDEO/vid_sdac_ramdac.h similarity index 100% rename from src/vid_sdac_ramdac.h rename to src/VIDEO/vid_sdac_ramdac.h diff --git a/src/vid_stg_ramdac.c b/src/VIDEO/vid_stg_ramdac.c similarity index 86% rename from src/vid_stg_ramdac.c rename to src/VIDEO/vid_stg_ramdac.c index 7fbd69785..2881fff91 100644 --- a/src/vid_stg_ramdac.c +++ b/src/VIDEO/vid_stg_ramdac.c @@ -2,19 +2,19 @@ see COPYING for more details */ /*STG1702 true colour RAMDAC emulation*/ -#include "ibm.h" -#include "mem.h" +#include "../ibm.h" +#include "../mem.h" #include "video.h" #include "vid_svga.h" #include "vid_stg_ramdac.h" + static int stg_state_read[2][8] = {{1,2,3,4,0,0,0,0}, {1,2,3,4,5,6,7,7}}; static int stg_state_write[8] = {0,0,0,0,0,6,7,7}; -static int stg_state_indexed = 0; + void stg_ramdac_set_bpp(svga_t *svga, stg_ramdac_t *ramdac) { - int oldbpp = svga->bpp; if (ramdac->command & 0x8) { switch (ramdac->regs[3]) @@ -43,7 +43,6 @@ void stg_ramdac_set_bpp(svga_t *svga, stg_ramdac_t *ramdac) void stg_ramdac_out(uint16_t addr, uint8_t val, stg_ramdac_t *ramdac, svga_t *svga) { int didwrite, old; - //if (CS!=0xC000) pclog("OUT RAMDAC %04X %02X %i %04X:%04X\n",addr,val,stg_ramdac.magic_count,CS,pc); switch (addr) { case 0x3c6: @@ -65,7 +64,6 @@ void stg_ramdac_out(uint16_t addr, uint8_t val, stg_ramdac_t *ramdac, svga_t *sv stg_ramdac_set_bpp(svga, ramdac); } } - // pclog("Write RAMDAC command %02X\n",val); break; case 5: ramdac->index = (ramdac->index & 0xff00) | val; @@ -74,7 +72,6 @@ void stg_ramdac_out(uint16_t addr, uint8_t val, stg_ramdac_t *ramdac, svga_t *sv ramdac->index = (ramdac->index & 0xff) | (val << 8); break; case 7: - // pclog("Write RAMDAC reg %02X %02X\n", ramdac->index, val); if (ramdac->index < 0x100) { ramdac->regs[ramdac->index] = val; @@ -96,8 +93,7 @@ void stg_ramdac_out(uint16_t addr, uint8_t val, stg_ramdac_t *ramdac, svga_t *sv uint8_t stg_ramdac_in(uint16_t addr, stg_ramdac_t *ramdac, svga_t *svga) { - uint8_t temp; - //if (CS!=0xC000) pclog("IN RAMDAC %04X %04X:%04X\n",addr,CS,pc); + uint8_t temp = 0xff; switch (addr) { case 0x3c6: @@ -116,7 +112,6 @@ uint8_t stg_ramdac_in(uint16_t addr, stg_ramdac_t *ramdac, svga_t *svga) temp = ramdac->index >> 8; break; case 7: - // pclog("Read RAMDAC index %04X\n",ramdac->index); switch (ramdac->index) { case 0: @@ -151,7 +146,6 @@ float stg_getclock(int clock, void *p) float t; int m, n1, n2; float d; -// pclog("STG_Getclock %i %04X\n", clock, ramdac->regs[clock]); if (clock == 0) return 25175000.0; if (clock == 1) return 28322000.0; clock ^= 1; /*Clocks 2 and 3 seem to be reversed*/ @@ -173,8 +167,6 @@ float stg_getclock(int clock, void *p) d = 8.0; break; } - // t = (14318184.0 * ((float)m / (float)n1)) / (float)(1 << n2); t = (14318184.0 * ((float)m / d)) / (float)n1; -// pclog("STG clock %i %i %i %f %04X %f %i\n", m, n1, n2, t, ramdac->regs[2], 14318184.0 * ((float)m / (float)n1), 1 << n2); return t; } diff --git a/src/vid_stg_ramdac.h b/src/VIDEO/vid_stg_ramdac.h similarity index 100% rename from src/vid_stg_ramdac.h rename to src/VIDEO/vid_stg_ramdac.h diff --git a/src/vid_svga.c b/src/VIDEO/vid_svga.c similarity index 89% rename from src/vid_svga.c rename to src/VIDEO/vid_svga.c index d0090aa75..8684de91f 100644 --- a/src/vid_svga.c +++ b/src/VIDEO/vid_svga.c @@ -1,29 +1,46 @@ -/* Copyright holders: Sarah Walker, Tenshi - see COPYING for more details -*/ -/*Generic SVGA handling*/ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Generic SVGA handling. + * + * Version: @(#)vid_svga.c 1.0.0 2017/05/30 + * + * Author: Sarah Walker, + * Miran Grca, + * Copyright 2008-2017 Sarah Walker. + * Copyright 2016-2017 Miran Grca. + */ + /*This is intended to be used by another SVGA driver, and not as a card in it's own right*/ #include #include -#include "ibm.h" -#include "mem.h" +#include "../ibm.h" +#include "../io.h" +#include "../mem.h" +#ifdef ENABLE_VRAM_DUMP +#include "../rom.h" +#endif +#include "../timer.h" #include "video.h" #include "vid_svga.h" #include "vid_svga_render.h" -#include "io.h" -#include "timer.h" + #define svga_output 0 + void svga_doblit(int y1, int y2, int wx, int wy, svga_t *svga); extern uint8_t edatlookup[4][4]; uint8_t svga_rotate[8][256]; -static uint8_t mask_gdc[9] = {0x0F, 0x0F, 0x0F, 0x1F, 0x03, 0x7B, 0x0F, 0x0F, 0xFF}; -uint8_t mask_crtc[0x19] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 0x3F, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xCF, 0xFF, 0xFF, 0x7F, 0xFF, 0x7F, 0xEF, 0xFF}; -static uint8_t mask_seq[5] = {0x03, 0x3D, 0x0F, 0x3F, 0x0E}; +uint8_t mask_crtc[0x19] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 0x7F, 0xEF, 0xFF}; /*Primary SVGA device. As multiple video cards are not yet supported this is the only SVGA device.*/ @@ -31,8 +48,6 @@ static svga_t *svga_pri; static int old_overscan_color = 0; -static int sense_switches = 0xE; - svga_t *svga_pointer; svga_t *svga_get_pri() @@ -52,21 +67,23 @@ typedef union pci_bar uint8_t bytes[2]; } ichar; +#ifdef DEV_BRANCH ichar char12x24[65536][48]; uint8_t charedit_on = 0; ichar charcode; uint8_t charmode = 0; uint8_t charptr = 0; uint8_t charsettings = 0xEE; +#endif void svga_out(uint16_t addr, uint8_t val, void *p) { svga_t *svga = (svga_t *)p; int c; uint8_t o; -// printf("OUT SVGA %03X %02X %04X:%04X\n",addr,val,CS,pc); switch (addr) { +#ifdef DEV_BRANCH case 0x32CB: printf("Write 32CB: %04X\n", val); charedit_on = (val & 0x10) ? 1 : 0; @@ -81,7 +98,6 @@ void svga_out(uint16_t addr, uint8_t val, void *p) case 0x22CF: printf("Write 22CF: %04X\n", val); - // if (!charedit_on) return; switch(charmode) { case 1: case 2: @@ -100,8 +116,10 @@ void svga_out(uint16_t addr, uint8_t val, void *p) case 0x22CA: case 0x22CE: case 0x32CA: printf("OUT SVGA %03X %02X %04X:%04X\n",addr,val,CS,cpu_state.pc); return; +#endif case 0x3C0: + case 0x3C1: if (!svga->attrff) { svga->attraddr = val & 31; @@ -126,7 +144,6 @@ void svga_out(uint16_t addr, uint8_t val, void *p) if (svga->attrregs[0x10] & 0x80) svga->egapal[c] = (svga->attrregs[c] & 0xf) | ((svga->attrregs[0x14] & 3) << 4); else svga->egapal[c] = (svga->attrregs[c] & 0x3f); - // if (svga->attrregs[0x10] & 0x40) svga->egapal[c] |= ((svga->attrregs[0x14] & 0x0c) << 4); /* It seems these should always be enabled. */ svga->egapal[c] |= ((svga->attrregs[0x14] & 0x0c) << 4); } @@ -149,15 +166,13 @@ void svga_out(uint16_t addr, uint8_t val, void *p) svga->miscout = val; svga->enablevram = (val & 2) ? 1 : 0; svga->oddeven_page = (val & 0x20) ? 0 : 1; - svga->vidclock = val & 4;// printf("3C2 write %02X\n",val); + svga->vidclock = val & 4; if (val & 1) { -// pclog("Remove mono handler\n"); io_removehandler(0x03a0, 0x0020, svga->video_in, NULL, NULL, svga->video_out, NULL, NULL, svga->p); } else { -// pclog("Set mono handler\n"); io_sethandler(0x03a0, 0x0020, svga->video_in, NULL, NULL, svga->video_out, NULL, NULL, svga->p); } svga_recalctimings(svga); @@ -169,8 +184,8 @@ void svga_out(uint16_t addr, uint8_t val, void *p) if (svga->seqaddr > 0xf) return; o = svga->seqregs[svga->seqaddr & 0xf]; /* Sanitize value for the first 5 sequencer registers. */ - if ((svga->seqaddr & 0xf) <= 4) - val &= mask_seq[svga->seqaddr & 0xf]; + /* if ((svga->seqaddr & 0xf) <= 4) + val &= mask_seq[svga->seqaddr & 0xf]; */ svga->seqregs[svga->seqaddr & 0xf] = val; if (o != val && (svga->seqaddr & 0xf) == 1) svga_recalctimings(svga); @@ -235,7 +250,16 @@ void svga_out(uint16_t addr, uint8_t val, void *p) if (svga->ramdac_type == RAMDAC_8BIT) svga->pallook[svga->dac_write] = makecol32(svga->vgapal[svga->dac_write].r, svga->vgapal[svga->dac_write].g, svga->vgapal[svga->dac_write].b); else - svga->pallook[svga->dac_write] = makecol32(video_6to8[svga->vgapal[svga->dac_write].r], video_6to8[svga->vgapal[svga->dac_write].g], video_6to8[svga->vgapal[svga->dac_write].b]); + { + if ((romset == ROM_IBMPS1_2011) || (romset == ROM_IBMPS1_2121) || (romset == ROM_IBMPS2_M30_286)) + { + svga->pallook[svga->dac_write] = makecol32((svga->vgapal[svga->dac_write].r & 0x3f) * 4, (svga->vgapal[svga->dac_write].g & 0x3f) * 4, (svga->vgapal[svga->dac_write].b & 0x3f) * 4); + } + else + { + svga->pallook[svga->dac_write] = makecol32(video_6to8[svga->vgapal[svga->dac_write].r], video_6to8[svga->vgapal[svga->dac_write].g], video_6to8[svga->vgapal[svga->dac_write].b]); + } + } svga->dac_pos = 0; svga->dac_write = (svga->dac_write + 1) & 255; break; @@ -246,8 +270,8 @@ void svga_out(uint16_t addr, uint8_t val, void *p) break; case 0x3CF: /* Sanitize the first 9 GDC registers. */ - if ((svga->gdcaddr & 15) <= 8) - val &= mask_gdc[svga->gdcaddr & 15]; + /* if ((svga->gdcaddr & 15) <= 8) + val &= mask_gdc[svga->gdcaddr & 15]; */ o = svga->gdcreg[svga->gdcaddr & 15]; switch (svga->gdcaddr & 15) { @@ -259,11 +283,9 @@ void svga_out(uint16_t addr, uint8_t val, void *p) svga->chain2_read = val & 0x10; break; case 6: -// pclog("svga_out recalcmapping %p\n", svga); svga->oddeven_chain = (val & 2) ? 1 : 0; if ((svga->gdcreg[6] & 0xc) != (val & 0xc)) { -// pclog("Write mapping %02X\n", val); switch (val&0xC) { case 0x0: /*128k at A0000*/ @@ -295,26 +317,64 @@ void svga_out(uint16_t addr, uint8_t val, void *p) } } +/* + * Get the switch sense input + * + * This is reverse engineered from the IBM VGA BIOS. I have no + * idea how and why this works. + * + * Note by Tohka: This code is from PCE, modified to be 86Box-compatible. + */ +static int svga_get_input_status_0_ss(svga_t *svga) +{ + const unsigned char *p; + unsigned char dac[3]; + + static unsigned char vals[] = { + 0x12, 0x12, 0x12, 0x10, + 0x14, 0x14, 0x14, 0x10, + 0x2d, 0x14, 0x14, 0x00, + 0x14, 0x2d, 0x14, 0x00, + 0x14, 0x14, 0x2d, 0x00, + 0x2d, 0x2d, 0x2d, 0x00, + 0x00, 0x00, 0x00, 0xff + }; + + dac[0] = svga->vgapal[0].r >> 2; + dac[1] = svga->vgapal[0].g >> 2; + dac[2] = svga->vgapal[0].b >> 2; + + p = vals; + + while (p[3] != 0xff) { + if ((p[0] == dac[0]) && (p[1] == dac[1]) && (p[2] == dac[2])) { + return (p[3] != 0); + } + + p += 4; + } + + return (1); +} + uint8_t svga_in(uint16_t addr, void *p) { svga_t *svga = (svga_t *)p; uint8_t temp; -// if (addr!=0x3da) pclog("Read port %04X\n",addr); switch (addr) { +#ifdef DEV_BRANCH case 0x22CA: pclog("Read port %04X\n", addr); return 0xAA; case 0x22CB: pclog("Read port %04X\n", addr); - // return charmode; return 0xF0 | (charmode & 0x1F); case 0x22CE: pclog("Read port %04X\n", addr); return 0xCC; case 0x22CF: /* Read character bitmap */ pclog("Read port %04X\n", addr); - // if (!charedit_on) return 0xFF; switch(charmode) { case 1: case 2: @@ -334,21 +394,50 @@ uint8_t svga_in(uint16_t addr, void *p) case 0x32CB: pclog("Read port %04X\n", addr); return 0xEE; - // return 0xEE | (charedit_on ? 0x10 : 0); +#endif case 0x3C0: return svga->attraddr | svga->attr_palette_enable; case 0x3C1: return svga->attrregs[svga->attraddr]; case 0x3c2: -#if 0 - if ((svga->vgapal[0].r + svga->vgapal[0].g + svga->vgapal[0].b) >= 0x50) - temp = 0; - else - temp = 0x10; -#endif - temp = sense_switches & (1 << ((svga->miscout >> 2) & 3)); - return temp ? 0 : 0x10; + if ((romset == ROM_IBMPS1_2011) || (romset == ROM_IBMPS1_2121) || (romset == ROM_IBMPS2_M30_286)) + { + if ((svga->vgapal[0].r + svga->vgapal[0].g + svga->vgapal[0].b) >= 0x50) + { + temp = 0; + } + else + { + temp = 0x10; + } + } + else + { + if (gfxcard == GFX_RIVA128) + { + if ((svga->vgapal[0].r + svga->vgapal[0].g + svga->vgapal[0].b) >= 0x4e) + { + temp = 0; + } + else + { + temp = 0x10; + } + } + else + { + if (svga_get_input_status_0_ss(svga)) + { + temp = 0x10; + } + else + { + temp = 0; + } + } + } + return temp; case 0x3C4: return svga->seqaddr; case 0x3C5: @@ -391,7 +480,6 @@ uint8_t svga_in(uint16_t addr, void *p) svga->cgastat ^= 0x30; return svga->cgastat; } -// printf("Bad EGA read %04X %04X:%04X\n",addr,cs>>4,pc); return 0xFF; } @@ -417,7 +505,6 @@ void svga_recalctimings(svga_t *svga) { double crtcconst; double _dispontime, _dispofftime, disptime; - int hdisp_old; svga->vtotal = svga->crtc[6]; svga->dispend = svga->crtc[0x12]; @@ -469,6 +556,7 @@ void svga_recalctimings(svga_t *svga) { if (svga->seqregs[1] & 8) /*40 column*/ { +#if 0 if (svga->hdisp == 120) { svga->render = svga_render_text_40_12; @@ -476,12 +564,16 @@ void svga_recalctimings(svga_t *svga) } else { +#endif svga->render = svga_render_text_40; svga->hdisp *= (svga->seqregs[1] & 1) ? 16 : 18; +#if 0 } +#endif } else { +#if 0 if (svga->hdisp == 120) { svga->render = svga_render_text_80_12; @@ -489,9 +581,12 @@ void svga_recalctimings(svga_t *svga) } else { +#endif svga->render = svga_render_text_80; svga->hdisp *= (svga->seqregs[1] & 1) ? 8 : 9; +#if 0 } +#endif } svga->hdisp_old = svga->hdisp; } @@ -553,10 +648,18 @@ void svga_recalctimings(svga_t *svga) } } -// pclog("svga_render %08X : %08X %08X %08X %08X %08X %i %i %02X %i %i\n", svga_render, svga_render_text_40, svga_render_text_80, svga_render_8bpp_lowres, svga_render_8bpp_highres, svga_render_blank, scrblank,gdcreg[6]&1,gdcreg[5]&0x60,bpp,seqregs[1]&8); - svga->linedbl = svga->crtc[9] & 0x80; svga->rowcount = svga->crtc[9] & 31; + overscan_y = (svga->rowcount + 1) << 1; + if (svga->seqregs[1] & 8) /*Low res (320)*/ + { + overscan_y <<= 1; + } + if (overscan_y < 16) + { + overscan_y = 16; + } + /* pclog("SVGA row count: %i (scroll: %i)\n", svga->rowcount, svga->crtc[8] & 0x1f); */ if (svga->recalctimings_ex) svga->recalctimings_ex(svga); @@ -568,7 +671,6 @@ void svga_recalctimings(svga_t *svga) disptime = svga->htotal; _dispontime = svga->hdisp_time; -// printf("Disptime %f dispontime %f hdisp %i\n",disptime,dispontime,crtc[1]*8); if (svga->seqregs[1] & 8) { disptime *= 2; _dispontime *= 2; } _dispofftime = disptime - _dispontime; _dispontime *= crtcconst; @@ -624,7 +726,6 @@ void svga_poll(void *p) if (!svga->linepos) { -// if (!(vc & 15)) pclog("VC %i %i\n", vc, GetTickCount()); if (svga->displine == svga->hwcursor_latch.y && svga->hwcursor_latch.ena) { svga->hwcursor_on = 64 - svga->hwcursor_latch.yoff; @@ -649,7 +750,6 @@ void svga_poll(void *p) } svga->vidtime += svga->dispofftime; -// if (output) printf("Display off %f\n",vidtime); svga->cgastat |= 1; svga->linepos = 1; @@ -692,27 +792,21 @@ void svga_poll(void *p) svga->lastline = svga->displine; } -// pclog("%03i %06X %06X\n",displine,ma,vrammask); svga->displine++; if (svga->interlace) svga->displine++; if ((svga->cgastat & 8) && ((svga->displine & 15) == (svga->crtc[0x11] & 15)) && svga->vslines) { -// printf("Vsync off at line %i\n",displine); svga->cgastat &= ~8; } svga->vslines++; if (svga->displine > 1500) svga->displine = 0; -// pclog("Col is %08X %08X %08X %i %i %08X\n",((uint32_t *)buffer32->line[displine])[320],((uint32_t *)buffer32->line[displine])[321],((uint32_t *)buffer32->line[displine])[322], -// displine, vc, ma); } else { -// pclog("VC %i ma %05X\n", svga->vc, svga->ma); svga->vidtime += svga->dispontime; -// if (output) printf("Display on %f\n",vidtime); if (svga->dispon) svga->cgastat &= ~1; svga->hdisp_on = 0; @@ -751,14 +845,14 @@ void svga_poll(void *p) if (svga->vc == svga->split) { -// pclog("VC split\n"); svga->ma = svga->maback = 0; if (svga->attrregs[0x10] & 0x20) svga->scrollcache = 0; } if (svga->vc == svga->dispend) { -// pclog("VC dispend\n"); + if (svga->vblank_start) + svga->vblank_start(svga); svga->dispon=0; if (svga->crtc[10] & 0x20) svga->cursoron = 0; else svga->cursoron = svga->blink & 16; @@ -771,14 +865,12 @@ void svga_poll(void *p) if (svga->changedvram[x]) svga->changedvram[x]--; } -// memset(changedvram,0,2048); if (svga->fullchange) svga->fullchange--; } if (svga->vc == svga->vsyncstart) { int wx, wy; -// pclog("VC vsync %i %i\n", svga->firstline_draw, svga->lastline_draw); svga->dispon=0; svga->cgastat |= 8; x = svga->hdisp; @@ -792,8 +884,6 @@ void svga_poll(void *p) if (!svga->override) svga_doblit(svga->firstline_draw, svga->lastline_draw + 1, wx, wy, svga); - readflash = 0; - svga->firstline = 2000; svga->lastline = 0; @@ -815,7 +905,6 @@ void svga_poll(void *p) svga->video_res_x = wx; svga->video_res_y = wy + 1; -// pclog("%i %i %i\n", svga->video_res_x, svga->video_res_y, svga->lowres); if (!(svga->gdcreg[6] & 1)) /*Text mode*/ { svga->video_res_x /= (svga->seqregs[1] & 1) ? 8 : 9; @@ -839,16 +928,9 @@ void svga_poll(void *p) case 0x40: case 0x60: svga->video_bpp = svga->bpp; break; } } -// if (svga_interlace && oddeven) ma=maback=ma+(svga_rowoffset<<2); - -// pclog("Addr %08X vson %03X vsoff %01X %02X %02X %02X %i %i\n",ma,svga_vsyncstart,crtc[0x11]&0xF,crtc[0xD],crtc[0xC],crtc[0x33], svga_interlace, oddeven); } if (svga->vc == svga->vtotal) { -// pclog("VC vtotal\n"); - - -// printf("Frame over at line %i %i %i %i\n",displine,vc,svga_vsyncstart,svga_dispend); svga->vc = 0; svga->sc = 0; svga->dispon = 1; @@ -861,17 +943,17 @@ void svga_poll(void *p) svga->overlay_on = 0; svga->overlay_latch = svga->overlay; -// pclog("Latch HWcursor addr %08X\n", svga_hwcursor_latch.addr); - -// pclog("ADDR %08X\n",hwcursor_addr); } if (svga->sc == (svga->crtc[10] & 31)) svga->con = 1; } -// printf("2 %i\n",svga_vsyncstart); -//pclog("svga_poll %i %i %i %i %i %i %i\n", ins, svga->dispofftime, svga->dispontime, svga->vidtime, cyc_total, svga->linepos, svga->vc); } +#ifdef ENABLE_VRAM_DUMP +uint8_t *ext_vram; +int ext_memsize; +#endif + int svga_init(svga_t *svga, void *p, int memsize, void (*recalctimings_ex)(struct svga_t *svga), uint8_t (*video_in) (uint16_t addr, void *p), @@ -906,6 +988,10 @@ int svga_init(svga_t *svga, void *p, int memsize, svga->dispofftime = 1000 * (1 << TIMER_SHIFT); svga->bpp = 8; svga->vram = malloc(memsize); +#ifdef ENABLE_VRAM_DUMP + ext_vram = svga->vram; + ext_memsize = memsize; +#endif svga->vram_limit = memsize; svga->vrammask = memsize - 1; svga->changedvram = malloc(/*(memsize >> 12) << 1*/memsize >> 12); @@ -914,9 +1000,10 @@ int svga_init(svga_t *svga, void *p, int memsize, svga->video_out = video_out; svga->hwcursor_draw = hwcursor_draw; svga->overlay_draw = overlay_draw; -// _svga_recalctimings(svga); - mem_mapping_add(&svga->mapping, 0xa0000, 0x20000, svga_read, svga_readw, svga_readl, svga_write, svga_writew, svga_writel, NULL, 0, svga); + mem_mapping_add(&svga->mapping, 0xa0000, 0x20000, svga_read, svga_readw, svga_readl, svga_write, svga_writew, svga_writel, NULL, MEM_MAPPING_EXTERNAL, svga); + + memset(svga->vgapal, 0, sizeof(PALETTE)); timer_add(svga_poll, &svga->vidtime, TIMER_ALWAYS_ENABLED, svga); @@ -963,21 +1050,38 @@ void svga_write(uint32_t addr, uint8_t val, void *p) if (!(svga->gdcreg[6] & 1)) svga->fullchange=2; if (svga->chain4 || svga->fb_only) { + /* + 00000 -> writemask 1, addr 0 -> vram addr 00000 + 00001 -> writemask 2, addr 0 -> vram addr 00001 + 00002 -> writemask 4, addr 0 -> vram addr 00002 + 00003 -> writemask 8, addr 0 -> vram addr 00003 + 00004 -> writemask 1, addr 4 -> vram addr 00004 + 00005 -> writemask 2, addr 4 -> vram addr 00005 + 00006 -> writemask 4, addr 4 -> vram addr 00006 + 00007 -> writemask 8, addr 4 -> vram addr 00007 + */ writemask2=1<<(addr&3); addr&=~3; } else if (svga->chain2_write) { - if ((svga->gdcreg[6] & 0xC) == 0x4) +#if 0 + if (svga->oddeven_page) { - writemask2 &= (svga->oddeven_page ? ~0xe : ~0xb); + /* Odd/Even page is 1, mask out plane 2 or 3, according to bit 0 of the address. */ + writemask2 &= (addr & 1) ? 8 : 4; } else { - writemask2 &= ~0xa; + /* Odd/Even page is 2, mask out plane 0 or 1, according to bit 0 of the address. */ + writemask2 &= (addr & 1) ? 2 : 1; } +#endif + + writemask2 &= ~0xa; if (addr & 1) - writemask2 <<= 1; + writemask2 <<= 1; + addr &= ~1; addr <<= 2; } @@ -985,7 +1089,6 @@ void svga_write(uint32_t addr, uint8_t val, void *p) { addr<<=2; } - // addr %= svga->vram_limit; if (addr >= svga->vram_limit) return; @@ -1051,7 +1154,6 @@ void svga_write(uint32_t addr, uint8_t val, void *p) if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) ^ svga->ld; break; } -// pclog("- %02X %02X %02X %02X %08X\n",vram[addr],vram[addr|0x1],vram[addr|0x2],vram[addr|0x3],addr); } break; case 2: @@ -1138,12 +1240,14 @@ void svga_write(uint32_t addr, uint8_t val, void *p) break; } +#if 0 if (svga->render == svga_render_text_80_12) { FILE *f = fopen("hecon.dmp", "wb"); fwrite(svga->vram, 1, svga->vram_limit, f); fclose(f); } +#endif } uint8_t svga_read(uint32_t addr, void *p) @@ -1157,34 +1261,30 @@ uint8_t svga_read(uint32_t addr, void *p) cycles_lost += video_timing_b; egareads++; -// pclog("Readega %06X ",addr); addr &= svga->banked_mask; addr += svga->read_bank; - // latch_addr = (addr << 2) % svga->vram_limit; latch_addr = svga_mask_addr(addr << 2, svga); - // latch_addr = (addr << 2); - -// pclog("%05X %i %04X:%04X %02X %02X %i\n",addr,svga->chain4,CS,pc, vram[addr & 0x7fffff], vram[(addr << 2) & 0x7fffff], svga->readmode); -// pclog("%i\n", svga->readmode); if (svga->chain4 || svga->fb_only) { - // addr %= svga->vram_limit; if (addr >= svga->vram_limit) return 0xff; return svga->vram[svga_mask_addr(addr, svga)]; } else if (svga->chain2_read) { - readplane = (readplane & 2) | (addr & 1); + readplane = addr & 1; + if (svga->oddeven_page) + { + readplane |= 2; + } + addr &= ~1; addr <<= 2; } else addr<<=2; - - // addr %= svga->vram_limit; - + if (addr >= svga->vram_limit) return 0xff; @@ -1216,7 +1316,6 @@ uint8_t svga_read(uint32_t addr, void *p) temp4 ^= (svga->colourcompare & 8) ? 0xff : 0; return ~(temp | temp2 | temp3 | temp4); } -//pclog("Read %02X %04X %04X\n",vram[addr|svga->readplane],addr,svga->readplane); return svga->vram[addr | readplane]; } @@ -1242,16 +1341,23 @@ void svga_write_linear(uint32_t addr, uint8_t val, void *p) } else if (svga->chain2_write) { - if ((svga->gdcreg[6] & 0xC) == 0x4) +#if 0 + if (svga->oddeven_page) { - writemask2 &= (svga->oddeven_page ? ~0xe : ~0xb); + /* Odd/Even page is 1, mask out plane 2 or 3, according to bit 0 of the address. */ + writemask2 &= (addr & 1) ? 8 : 4; } else { - writemask2 &= ~0xa; + /* Odd/Even page is 2, mask out plane 0 or 1, according to bit 0 of the address. */ + writemask2 &= (addr & 1) ? 2 : 1; } +#endif + + writemask2 &= ~0xa; if (addr & 1) writemask2 <<= 1; + addr &= ~1; addr <<= 2; } @@ -1259,7 +1365,10 @@ void svga_write_linear(uint32_t addr, uint8_t val, void *p) { addr<<=2; } - // addr %= svga->vram_limit; + if ((gfxcard != GFX_RIVA128) && (gfxcard != GFX_RIVATNT) && (gfxcard != GFX_RIVATNT2)) + { + addr &= 0x7fffff; + } if (addr >= svga->vram_limit) return; if (svga_output) pclog("%08X\n", addr); @@ -1321,7 +1430,6 @@ void svga_write_linear(uint32_t addr, uint8_t val, void *p) if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) ^ svga->ld; break; } -// pclog("- %02X %02X %02X %02X %08X\n",vram[addr],vram[addr|0x1],vram[addr|0x2],vram[addr|0x3],addr); } break; case 2: @@ -1413,7 +1521,6 @@ uint8_t svga_read_linear(uint32_t addr, void *p) { svga_t *svga = (svga_t *)p; uint8_t temp, temp2, temp3, temp4; - uint32_t latch_addr; int readplane = svga->readplane; cycles -= video_timing_b; @@ -1422,36 +1529,43 @@ uint8_t svga_read_linear(uint32_t addr, void *p) egareads++; addr -= svga->linear_base; - - latch_addr = svga_mask_addr(addr << 2, svga); if (svga->chain4 || svga->fb_only) { - // addr %= svga->vram_limit; + if ((gfxcard != GFX_RIVA128) && (gfxcard != GFX_RIVATNT) && (gfxcard != GFX_RIVATNT2)) + { + addr &= 0x7fffff; + } if (addr >= svga->vram_limit) return 0xff; - return svga->vram[svga_mask_addr(addr, svga)]; + return svga->vram[addr]; } else if (svga->chain2_read) { - readplane = (readplane & 2) | (addr & 1); + readplane = addr & 1; + if (svga->oddeven_page) + { + readplane |= 2; + } + addr &= ~1; addr <<= 2; } else addr<<=2; - // addr %= svga->vram_limit; + if ((gfxcard != GFX_RIVA128) && (gfxcard != GFX_RIVATNT) && (gfxcard != GFX_RIVATNT2)) + { + addr &= 0x7fffff; + } if (addr >= svga->vram_limit) return 0xff; - addr = svga_mask_addr(addr, svga); - - svga->la = svga->vram[latch_addr]; - svga->lb = svga->vram[latch_addr | 0x1]; - svga->lc = svga->vram[latch_addr | 0x2]; - svga->ld = svga->vram[latch_addr | 0x3]; + svga->la = svga->vram[addr]; + svga->lb = svga->vram[addr | 0x1]; + svga->lc = svga->vram[addr | 0x2]; + svga->ld = svga->vram[addr | 0x3]; if (svga->readmode) { temp = (svga->colournocare & 1) ? 0xff : 0; @@ -1468,21 +1582,27 @@ uint8_t svga_read_linear(uint32_t addr, void *p) temp4 ^= (svga->colourcompare & 8) ? 0xff : 0; return ~(temp | temp2 | temp3 | temp4); } -//printf("Read %02X %04X %04X\n",vram[addr|svga->readplane],addr,svga->readplane); return svga->vram[addr | readplane]; } void svga_doblit(int y1, int y2, int wx, int wy, svga_t *svga) { - int y_add = (enable_overscan) ? 32 : 0; + int y_add = (enable_overscan) ? overscan_y : 0; int x_add = (enable_overscan) ? 16 : 0; - uint32_t *p, *q, i, j; + uint32_t *p, i, j; -// pclog("svga_doblit start\n"); svga->frames++; -// pclog("doblit %i %i\n", y1, y2); -// pclog("svga_doblit %i %i\n", wx, svga->hdisp); + if ((xsize > 2032) || (ysize > 2032)) + { + x_add = 0; + y_add = 0; + suppress_overscan = 1; + } + else + { + suppress_overscan = 0; + } if (y1 > y2) { @@ -1497,45 +1617,92 @@ void svga_doblit(int y1, int y2, int wx, int wy, svga_t *svga) if (xsize<64) xsize=640; if (ysize<32) ysize=200; + if ((xsize > 2032) || (ysize > 2032)) + { + x_add = 0; + y_add = 0; + suppress_overscan = 1; + } + else + { + suppress_overscan = 0; + } + updatewindowsize(xsize + x_add,ysize + y_add); } if (vid_resize) { xsize = wx; ysize = wy + 1; + + if ((xsize > 2032) || (ysize > 2032)) + { + x_add = 0; + y_add = 0; + suppress_overscan = 1; + } + else + { + suppress_overscan = 0; + } } - if (enable_overscan) + if (enable_overscan && !suppress_overscan) { if ((wx >= 160) && ((wy + 1) >= 120)) { - for (i = 0; i < 16; i++) + /* Draw (overscan_size - scroll size) lines of overscan on top. */ + for (i = 0; i < ((y_add >> 1) - (svga->crtc[8] & 0x1f)); i++) { - p = &((uint32_t *)buffer32->line[i])[32]; - q = &((uint32_t *)buffer32->line[ysize + y_add - 1 - i])[32]; + p = &((uint32_t *)buffer32->line[i & 0x7ff])[32]; for (j = 0; j < (xsize + x_add); j++) { - p[j] = svga->pallook[svga->attrregs[0x11]]; - q[j] = svga->pallook[svga->attrregs[0x11]]; + p[j] = svga_color_transform(svga->pallook[svga->attrregs[0x11]]); } } - for (i = 16; i < (ysize + 16); i ++) + /* Draw (overscan_size + scroll size) lines of overscan on the bottom. */ + for (i = 0; i < ((y_add >> 1) + (svga->crtc[8] & 0x1f)); i++) { - p = &((uint32_t *)buffer32->line[i])[32]; + p = &((uint32_t *)buffer32->line[(ysize + (y_add >> 1) + i - (svga->crtc[8] & 0x1f)) & 0x7ff])[32]; + + for (j = 0; j < (xsize + x_add); j++) + { + p[j] = svga_color_transform(svga->pallook[svga->attrregs[0x11]]); + } + } + + for (i = ((y_add >> 1) - (svga->crtc[8] & 0x1f)); i < (ysize + (y_add >> 1) - (svga->crtc[8] & 0x1f)); i ++) + { + p = &((uint32_t *)buffer32->line[i & 0x7ff])[32]; for (j = 0; j < 8; j++) { - p[j] = svga->pallook[svga->attrregs[0x11]]; - p[xsize + x_add - 1 - j] = svga->pallook[svga->attrregs[0x11]]; + p[j] = svga_color_transform(svga->pallook[svga->attrregs[0x11]]); + p[xsize + (x_add >> 1) + j] = svga_color_transform(svga->pallook[svga->attrregs[0x11]]); + } + } + } + } + else + { + if ((wx >= 160) && ((wy + 1) >= 120) && (svga->crtc[8] & 0x1f)) + { + /* Draw (scroll size) lines of overscan on the bottom. */ + for (i = 0; i < (svga->crtc[8] & 0x1f); i++) + { + p = &((uint32_t *)buffer32->line[(ysize + i - (svga->crtc[8] & 0x1f)) & 0x7ff])[32]; + + for (j = 0; j < xsize; j++) + { + p[j] = svga_color_transform(svga->pallook[svga->attrregs[0x11]]); } } } } video_blit_memtoscreen(32, 0, y1, y2 + y_add, xsize + x_add, ysize + y_add); -// pclog("svga_doblit end\n"); } void svga_writew(uint32_t addr, uint16_t val, void *p) @@ -1558,7 +1725,6 @@ void svga_writew(uint32_t addr, uint16_t val, void *p) if (svga_output) pclog("svga_writew: %05X ", addr); addr = (addr & svga->banked_mask) + svga->write_bank; - // addr %= svga->vram_limit; if ((!svga->extvram) && (addr >= 0x10000)) return; if (addr >= svga->vram_limit) return; @@ -1589,7 +1755,6 @@ void svga_writel(uint32_t addr, uint32_t val, void *p) if (svga_output) pclog("svga_writel: %05X ", addr); addr = (addr & svga->banked_mask) + svga->write_bank; - // addr %= svga->vram_limit; if ((!svga->extvram) && (addr >= 0x10000)) return; if (addr >= svga->vram_limit) return; @@ -1613,11 +1778,8 @@ uint16_t svga_readw(uint32_t addr, void *p) cycles -= video_timing_w; cycles_lost += video_timing_w; -// pclog("Readw %05X ", addr); addr = (addr & svga->banked_mask) + svga->read_bank; - // addr %= svga->vram_limit; if ((!svga->extvram) && (addr >= 0x10000)) return 0xffff; -// pclog("%08X %04X\n", addr, *(uint16_t *)&vram[addr]); if (addr >= svga->vram_limit) return 0xffff; return *(uint16_t *)&svga->vram[addr]; @@ -1630,18 +1792,18 @@ uint32_t svga_readl(uint32_t addr, void *p) if (!svga->enablevram) return 0xffffffff; if (!svga->fast) + { + if (addr == 0xBF0000) pclog ("%08X\n", svga_read(addr, p) | (svga_read(addr + 1, p) << 8) | (svga_read(addr + 2, p) << 16) | (svga_read(addr + 3, p) << 24)); return svga_read(addr, p) | (svga_read(addr + 1, p) << 8) | (svga_read(addr + 2, p) << 16) | (svga_read(addr + 3, p) << 24); + } egareads += 4; cycles -= video_timing_l; cycles_lost += video_timing_l; -// pclog("Readl %05X ", addr); addr = (addr & svga->banked_mask) + svga->read_bank; - // addr %= svga->vram_limit; if ((!svga->extvram) && (addr >= 0x10000)) return 0xffffffff; -// pclog("%08X %08X\n", addr, *(uint32_t *)&vram[addr]); if (addr >= svga->vram_limit) return 0xffffffff; return *(uint32_t *)&svga->vram[addr]; @@ -1666,9 +1828,11 @@ void svga_writew_linear(uint32_t addr, uint16_t val, void *p) cycles_lost += video_timing_w; if (svga_output) pclog("Write LFBw %08X %04X\n", addr, val); - // addr %= svga->vram_limit; addr -= svga->linear_base; - if ((!svga->extvram) && (addr >= 0x10000)) return; + if ((gfxcard != GFX_RIVA128) && (gfxcard != GFX_RIVATNT) && (gfxcard != GFX_RIVATNT2)) + { + addr &= 0x7fffff; + } if (addr >= svga->vram_limit) return; svga->changedvram[addr >> 12] = changeframecount; @@ -1696,9 +1860,11 @@ void svga_writel_linear(uint32_t addr, uint32_t val, void *p) cycles_lost += video_timing_l; if (svga_output) pclog("Write LFBl %08X %08X\n", addr, val); - // addr %= svga->vram_limit; addr -= svga->linear_base; - if ((!svga->extvram) && (addr >= 0x10000)) return; + if ((gfxcard != GFX_RIVA128) && (gfxcard != GFX_RIVATNT) && (gfxcard != GFX_RIVATNT2)) + { + addr &= 0x7fffff; + } if (addr >= svga->vram_limit) return; svga->changedvram[addr >> 12] = changeframecount; @@ -1719,9 +1885,11 @@ uint16_t svga_readw_linear(uint32_t addr, void *p) cycles -= video_timing_w; cycles_lost += video_timing_w; - // addr %= svga->vram_limit; addr -= svga->linear_base; - if ((!svga->extvram) && (addr >= 0x10000)) return 0xffff; + if ((gfxcard != GFX_RIVA128) && (gfxcard != GFX_RIVATNT) && (gfxcard != GFX_RIVATNT2)) + { + addr &= 0x7fffff; + } if (addr >= svga->vram_limit) return 0xffff; return *(uint16_t *)&svga->vram[addr]; @@ -1741,15 +1909,39 @@ uint32_t svga_readl_linear(uint32_t addr, void *p) cycles -= video_timing_l; cycles_lost += video_timing_l; - // addr %= svga->vram_limit; addr -= svga->linear_base; - if ((!svga->extvram) && (addr >= 0x10000)) return 0xffffffff; + if ((gfxcard != GFX_RIVA128) && (gfxcard != GFX_RIVATNT) && (gfxcard != GFX_RIVATNT2)) + { + addr &= 0x7fffff; + } if (addr >= svga->vram_limit) return 0xffffffff; return *(uint32_t *)&svga->vram[addr]; } +#ifdef ENABLE_VRAM_DUMP +void svga_dump_vram() +{ + FILE *f; + + if (ext_vram == NULL) + { + return; + } + + f = nvrfopen(L"svga_vram.dmp", L"wb"); + if (f == NULL) + { + return; + } + + fwrite(ext_vram, ext_memsize, 1, f); + + fclose(f); +} +#endif + void svga_add_status_info(char *s, int max_len, void *p) { svga_t *svga = (svga_t *)p; @@ -1778,4 +1970,4 @@ void svga_add_status_info(char *s, int max_len, void *p) sprintf(temps, "SVGA DAC in %i-bit mode\n", (svga->attrregs[0x10] & 0x80) ? 8 : 6); strncat(s, temps, max_len); -} \ No newline at end of file +} diff --git a/src/vid_svga.h b/src/VIDEO/vid_svga.h similarity index 83% rename from src/vid_svga.h rename to src/VIDEO/vid_svga.h index dce4278be..d4307dfde 100644 --- a/src/vid_svga.h +++ b/src/VIDEO/vid_svga.h @@ -1,6 +1,21 @@ -/* Copyright holders: Sarah Walker, Tenshi - see COPYING for more details -*/ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Generic SVGA handling. + * + * Version: @(#)vid_svga.h 1.0.0 2017/05/30 + * + * Author: Sarah Walker, + * Miran Grca, + * Copyright 2008-2017 Sarah Walker. + * Copyright 2016-2017 Miran Grca. + */ + typedef struct svga_t { mem_mapping_t mapping; @@ -91,8 +106,9 @@ typedef struct svga_t int ena; int x, y; int xoff, yoff; - int ysize; + int xsize, ysize; uint32_t addr; + uint32_t pitch; int v_acc, h_acc; } hwcursor, hwcursor_latch, overlay, overlay_latch; @@ -112,6 +128,8 @@ typedef struct svga_t void (*overlay_draw)(struct svga_t *svga, int displine); + void (*vblank_start)(struct svga_t *svga); + /*If set then another device is driving the monitor output and the SVGA card should not attempt to display anything */ int override; @@ -127,6 +145,7 @@ extern int svga_init(svga_t *svga, void *p, int memsize, void (*hwcursor_draw)(struct svga_t *svga, int displine), void (*overlay_draw)(struct svga_t *svga, int displine)); extern void svga_recalctimings(svga_t *svga); +extern void svga_close(svga_t *svga); uint8_t svga_read(uint32_t addr, void *p); @@ -157,3 +176,10 @@ void svga_set_override(svga_t *svga, int val); void svga_set_ramdac_type(svga_t *svga, int type); extern uint8_t mask_crtc[0x19]; + +void svga_close(svga_t *svga); + +uint32_t svga_mask_addr(uint32_t addr, svga_t *svga); +uint32_t svga_mask_changedaddr(uint32_t addr, svga_t *svga); + +void svga_doblit(int y1, int y2, int wx, int wy, svga_t *svga); diff --git a/src/vid_svga_render.c b/src/VIDEO/vid_svga_render.c similarity index 60% rename from src/vid_svga_render.c rename to src/VIDEO/vid_svga_render.c index 0565b0281..4c0c5c617 100644 --- a/src/vid_svga_render.c +++ b/src/VIDEO/vid_svga_render.c @@ -1,15 +1,129 @@ -/* Copyright holders: Sarah Walker - see COPYING for more details -*/ -#include "ibm.h" -#include "mem.h" +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * SVGA renderers. + * + * Version: @(#)vid_svga_render.c 1.0.0 2017/05/30 + * + * Author: Sarah Walker, + * Miran Grca, + * Copyright 2008-2017 Sarah Walker. + * Copyright 2016-2017 Miran Grca. + */ + +#include +#include "../ibm.h" +#include "../mem.h" #include "video.h" #include "vid_svga.h" #include "vid_svga_render.h" -#include + + +int invert_display = 0; + + +uint32_t svga_color_transform(uint32_t color) +{ + uint32_t temp = 0; + if (invert_display) + { + temp |= (0xff - (color & 0xff)); + temp |= (0xff00 - (color & 0xff00)); + temp |= (0xff0000 - (color & 0xff0000)); + } + else + { + temp = color; + } + return temp; +} + +int svga_display_line(svga_t *svga) +{ + int y_add = (enable_overscan) ? 16 : 0; + unsigned int dl = svga->displine; + if (svga->crtc[9] & 0x1f) + { + dl -= (svga->crtc[8] & 0x1f); + } + dl += y_add; + dl &= 0x7ff; + return dl; +} void svga_render_blank(svga_t *svga) { +#if 0 + int x, xx; + int y_add = (enable_overscan) ? 16 : 0; + int x_add = y_add >> 1; + int dl = svga_display_line(svga); + uint32_t *p; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + if (dl >= 2046) + { + return; + } + + for (x = 0; x < svga->hdisp; x++) + { + switch (svga->seqregs[1] & 9) + { + case 0: + for (xx = 0; xx < 9; xx++) + { + p = ((uint32_t *)buffer32->line[dl]); + if (&(p[(x * 9) + xx + 32 + x_add]) != NULL) + { + p[(x * 9) + xx + 32 + x_add] = svga_color_transform(0); + } + } + break; + + case 1: + for (xx = 0; xx < 8; xx++) + { + p = ((uint32_t *)buffer32->line[dl]); + if (&(p[(x * 8) + xx + 32 + x_add]) != NULL) + { + p[(x * 8) + xx + 32 + x_add] = svga_color_transform(0); + } + } + break; + + case 8: + for (xx = 0; xx < 18; xx++) + { + p = ((uint32_t *)buffer32->line[dl]); + if (&(p[(x * 18) + xx + 32 + x_add]) != NULL) + { + p[(x * 18) + xx + 32 + x_add] = svga_color_transform(0); + } + } + break; + + case 9: + for (xx = 0; xx < 16; xx++) + { + p = ((uint32_t *)buffer32->line[dl]); + if (&(p[(x * 16) + xx + 32 + x_add]) != NULL) + { + p[(x * 16) + xx + 32 + x_add] = svga_color_transform(0); + } + } + break; + } + } +#endif int x, xx; int y_add = (enable_overscan) ? 16 : 0; int x_add = y_add >> 1; @@ -23,16 +137,16 @@ void svga_render_blank(svga_t *svga) switch (svga->seqregs[1] & 9) { case 0: - for (xx = 0; xx < 9; xx++) ((uint32_t *)buffer32->line[svga->displine + y_add])[(x * 9) + xx + 32 + x_add] = 0; + for (xx = 0; xx < 9; xx++) ((uint32_t *)buffer32->line[svga->displine + y_add])[(x * 9) + xx + 32 + x_add] = svga_color_transform(0); break; case 1: - for (xx = 0; xx < 8; xx++) ((uint32_t *)buffer32->line[svga->displine + y_add])[(x * 8) + xx + 32 + x_add] = 0; + for (xx = 0; xx < 8; xx++) ((uint32_t *)buffer32->line[svga->displine + y_add])[(x * 8) + xx + 32 + x_add] = svga_color_transform(0); break; case 8: - for (xx = 0; xx < 18; xx++) ((uint32_t *)buffer32->line[svga->displine + y_add])[(x * 18) + xx + 32 + x_add] = 0; + for (xx = 0; xx < 18; xx++) ((uint32_t *)buffer32->line[svga->displine + y_add])[(x * 18) + xx + 32 + x_add] = svga_color_transform(0); break; case 9: - for (xx = 0; xx < 16; xx++) ((uint32_t *)buffer32->line[svga->displine + y_add])[(x * 16) + xx + 32 + x_add] = 0; + for (xx = 0; xx < 16; xx++) ((uint32_t *)buffer32->line[svga->displine + y_add])[(x * 16) + xx + 32 + x_add] = svga_color_transform(0); break; } } @@ -42,6 +156,7 @@ void svga_render_text_40(svga_t *svga) { int y_add = (enable_overscan) ? 16 : 0; int x_add = y_add >> 1; + int dl = svga_display_line(svga); if (svga->firstline_draw == 2000) svga->firstline_draw = svga->displine; @@ -49,7 +164,7 @@ void svga_render_text_40(svga_t *svga) if (svga->fullchange) { - uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[32 + x_add]; + uint32_t *p = &((uint32_t *)buffer32->line[dl])[32 + x_add]; int x, xx; int drawcursor; uint8_t chr, attr, dat; @@ -86,16 +201,16 @@ void svga_render_text_40(svga_t *svga) if (svga->seqregs[1] & 1) { for (xx = 0; xx < 16; xx += 2) - p[xx] = p[xx + 1] = (dat & (0x80 >> (xx >> 1))) ? fg : bg; + p[xx] = p[xx + 1] = (dat & (0x80 >> (xx >> 1))) ? svga_color_transform(fg) : svga_color_transform(bg); } else { for (xx = 0; xx < 16; xx += 2) - p[xx] = p[xx + 1] = (dat & (0x80 >> (xx >> 1))) ? fg : bg; + p[xx] = p[xx + 1] = (dat & (0x80 >> (xx >> 1))) ? svga_color_transform(fg) : svga_color_transform(bg); if ((chr & ~0x1F) != 0xC0 || !(svga->attrregs[0x10] & 4)) - p[16] = p[17] = bg; + p[16] = p[17] = svga_color_transform(bg); else - p[16] = p[17] = (dat & 1) ? fg : bg; + p[16] = p[17] = (dat & 1) ? svga_color_transform(fg) : svga_color_transform(bg); } svga->ma += 4; svga->ma = svga_mask_addr(svga->ma, svga); @@ -104,10 +219,12 @@ void svga_render_text_40(svga_t *svga) } } +#if 0 void svga_render_text_40_12(svga_t *svga) { int y_add = (enable_overscan) ? 16 : 0; int x_add = (enable_overscan) ? 12 : 0; + int dl = svga_display_line(svga); if (svga->firstline_draw == 2000) svga->firstline_draw = svga->displine; @@ -115,7 +232,7 @@ void svga_render_text_40_12(svga_t *svga) if (svga->fullchange) { - uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[32 + x_add]; + uint32_t *p = &((uint32_t *)buffer32->line[dl])[32 + x_add]; int x, xx; int drawcursor; uint8_t chr, attr; @@ -151,18 +268,20 @@ void svga_render_text_40_12(svga_t *svga) dat = *(uint16_t *) &(svga->vram[charaddr + (svga->sc << 2) - 1]); for (xx = 0; xx < 24; xx += 2) - p[xx] = p[xx + 1] = (dat & (0x800 >> (xx >> 1))) ? fg : bg; + p[xx] = p[xx + 1] = (dat & (0x800 >> (xx >> 1))) ? svga_color_transform(fg) : svga_color_transform(bg); svga->ma += 4; svga->ma = svga_mask_addr(svga->ma, svga); p += xinc; } } } +#endif void svga_render_text_80(svga_t *svga) { int y_add = (enable_overscan) ? 16 : 0; int x_add = y_add >> 1; + int dl = svga_display_line(svga); if (svga->firstline_draw == 2000) svga->firstline_draw = svga->displine; @@ -170,7 +289,7 @@ void svga_render_text_80(svga_t *svga) if (svga->fullchange) { - uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[32 + x_add]; + uint32_t *p = &((uint32_t *)buffer32->line[dl])[32 + x_add]; int x, xx; int drawcursor; uint8_t chr, attr, dat; @@ -207,16 +326,16 @@ void svga_render_text_80(svga_t *svga) if (svga->seqregs[1] & 1) { for (xx = 0; xx < 8; xx++) - p[xx] = (dat & (0x80 >> xx)) ? fg : bg; + p[xx] = (dat & (0x80 >> xx)) ? svga_color_transform(fg) : svga_color_transform(bg); } else { for (xx = 0; xx < 8; xx++) - p[xx] = (dat & (0x80 >> xx)) ? fg : bg; + p[xx] = (dat & (0x80 >> xx)) ? svga_color_transform(fg) : svga_color_transform(bg); if ((chr & ~0x1F) != 0xC0 || !(svga->attrregs[0x10] & 4)) - p[8] = bg; + p[8] = svga_color_transform(bg); else - p[8] = (dat & 1) ? fg : bg; + p[8] = (dat & 1) ? svga_color_transform(fg) : svga_color_transform(bg); } svga->ma += 4; svga->ma = svga_mask_addr(svga->ma, svga); @@ -225,10 +344,12 @@ void svga_render_text_80(svga_t *svga) } } +#if 0 void svga_render_text_80_12(svga_t *svga) { int y_add = (enable_overscan) ? 16 : 0; int x_add = (enable_overscan) ? 12 : 0; + int dl = svga_display_line(svga); if (svga->firstline_draw == 2000) svga->firstline_draw = svga->displine; @@ -236,7 +357,7 @@ void svga_render_text_80_12(svga_t *svga) if (svga->fullchange) { - uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[32 + x_add]; + uint32_t *p = &((uint32_t *)buffer32->line[dl])[32 + x_add]; int x, xx; int drawcursor; uint8_t chr, attr; @@ -273,19 +394,21 @@ void svga_render_text_80_12(svga_t *svga) dat = svga->vram[charaddr + (svga->sc << 2)] << 4; dat |= ((svga->vram[charaddr + (svga->sc << 2) + 1]) >> 4); for (xx = 0; xx < 12; xx++) - p[xx] = (dat & (0x800 >> xx)) ? fg : bg; + p[xx] = (dat & (0x800 >> xx)) ? svga_color_transform(fg) : svga_color_transform(bg); svga->ma += 4; svga->ma = svga_mask_addr(svga->ma, svga); p += xinc; } } } +#endif void svga_render_2bpp_lowres(svga_t *svga) { int changed_offset; int y_add = (enable_overscan) ? 16 : 0; int x_add = y_add >> 1; + int dl = svga_display_line(svga); if (svga->sc & 1 && !(svga->crtc[0x17] & 1)) changed_offset = (svga->ma << 1) >> 12; @@ -296,7 +419,7 @@ void svga_render_2bpp_lowres(svga_t *svga) { int x; int offset = ((8 - svga->scrollcache) << 1) + 16; - uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[offset + x_add]; + uint32_t *p = &((uint32_t *)buffer32->line[dl])[offset + x_add]; if (svga->firstline_draw == 2000) svga->firstline_draw = svga->displine; @@ -319,14 +442,14 @@ void svga_render_2bpp_lowres(svga_t *svga) svga->ma += 4; svga->ma = svga_mask_addr(svga->ma, svga); - p[0] = p[1] = svga->pallook[svga->egapal[(dat[0] >> 6) & 3] & svga->dac_mask]; - p[2] = p[3] = svga->pallook[svga->egapal[(dat[0] >> 4) & 3] & svga->dac_mask]; - p[4] = p[5] = svga->pallook[svga->egapal[(dat[0] >> 2) & 3] & svga->dac_mask]; - p[6] = p[7] = svga->pallook[svga->egapal[dat[0] & 3] & svga->dac_mask]; - p[8] = p[9] = svga->pallook[svga->egapal[(dat[1] >> 6) & 3] & svga->dac_mask]; - p[10] = p[11] = svga->pallook[svga->egapal[(dat[1] >> 4) & 3] & svga->dac_mask]; - p[12] = p[13] = svga->pallook[svga->egapal[(dat[1] >> 2) & 3] & svga->dac_mask]; - p[14] = p[15] = svga->pallook[svga->egapal[dat[1] & 3] & svga->dac_mask]; + p[0] = p[1] = svga_color_transform(svga->pallook[svga->egapal[(dat[0] >> 6) & 3] & svga->dac_mask]); + p[2] = p[3] = svga_color_transform(svga->pallook[svga->egapal[(dat[0] >> 4) & 3] & svga->dac_mask]); + p[4] = p[5] = svga_color_transform(svga->pallook[svga->egapal[(dat[0] >> 2) & 3] & svga->dac_mask]); + p[6] = p[7] = svga_color_transform(svga->pallook[svga->egapal[dat[0] & 3] & svga->dac_mask]); + p[8] = p[9] = svga_color_transform(svga->pallook[svga->egapal[(dat[1] >> 6) & 3] & svga->dac_mask]); + p[10] = p[11] = svga_color_transform(svga->pallook[svga->egapal[(dat[1] >> 4) & 3] & svga->dac_mask]); + p[12] = p[13] = svga_color_transform(svga->pallook[svga->egapal[(dat[1] >> 2) & 3] & svga->dac_mask]); + p[14] = p[15] = svga_color_transform(svga->pallook[svga->egapal[dat[1] & 3] & svga->dac_mask]); p += 16; } @@ -338,7 +461,8 @@ void svga_render_2bpp_highres(svga_t *svga) int changed_offset; int y_add = (enable_overscan) ? 16 : 0; int x_add = y_add >> 1; - + int dl = svga_display_line(svga); + if (svga->sc & 1 && !(svga->crtc[0x17] & 1)) changed_offset = ((svga->ma << 1) | 0x8000) >> 12; else @@ -348,7 +472,7 @@ void svga_render_2bpp_highres(svga_t *svga) { int x; int offset = (8 - svga->scrollcache) + 24; - uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[offset + x_add]; + uint32_t *p = &((uint32_t *)buffer32->line[dl])[offset + x_add]; if (svga->firstline_draw == 2000) svga->firstline_draw = svga->displine; @@ -371,14 +495,14 @@ void svga_render_2bpp_highres(svga_t *svga) svga->ma += 4; svga->ma = svga_mask_addr(svga->ma, svga); - p[0] = svga->pallook[svga->egapal[(dat[0] >> 6) & 3] & svga->dac_mask]; - p[1] = svga->pallook[svga->egapal[(dat[0] >> 4) & 3] & svga->dac_mask]; - p[2] = svga->pallook[svga->egapal[(dat[0] >> 2) & 3] & svga->dac_mask]; - p[3] = svga->pallook[svga->egapal[dat[0] & 3] & svga->dac_mask]; - p[4] = svga->pallook[svga->egapal[(dat[1] >> 6) & 3] & svga->dac_mask]; - p[5] = svga->pallook[svga->egapal[(dat[1] >> 4) & 3] & svga->dac_mask]; - p[6] = svga->pallook[svga->egapal[(dat[1] >> 2) & 3] & svga->dac_mask]; - p[7] = svga->pallook[svga->egapal[dat[1] & 3] & svga->dac_mask]; + p[0] = svga_color_transform(svga->pallook[svga->egapal[(dat[0] >> 6) & 3] & svga->dac_mask]); + p[1] = svga_color_transform(svga->pallook[svga->egapal[(dat[0] >> 4) & 3] & svga->dac_mask]); + p[2] = svga_color_transform(svga->pallook[svga->egapal[(dat[0] >> 2) & 3] & svga->dac_mask]); + p[3] = svga_color_transform(svga->pallook[svga->egapal[dat[0] & 3] & svga->dac_mask]); + p[4] = svga_color_transform(svga->pallook[svga->egapal[(dat[1] >> 6) & 3] & svga->dac_mask]); + p[5] = svga_color_transform(svga->pallook[svga->egapal[(dat[1] >> 4) & 3] & svga->dac_mask]); + p[6] = svga_color_transform(svga->pallook[svga->egapal[(dat[1] >> 2) & 3] & svga->dac_mask]); + p[7] = svga_color_transform(svga->pallook[svga->egapal[dat[1] & 3] & svga->dac_mask]); p += 8; } @@ -387,14 +511,20 @@ void svga_render_2bpp_highres(svga_t *svga) void svga_render_4bpp_lowres(svga_t *svga) { + int x; int y_add = (enable_overscan) ? 16 : 0; int x_add = y_add >> 1; + int dl = svga_display_line(svga); + int offset; + uint32_t *p; + uint32_t *r, *q; + uint8_t edat[4]; + uint8_t dat; if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) { - int x; - int offset = ((8 - svga->scrollcache) << 1) + 16; - uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[offset + x_add]; + offset = ((8 - svga->scrollcache) << 1) + 16; + p = &((uint32_t *)buffer32->line[dl])[offset + x_add]; if (svga->firstline_draw == 2000) svga->firstline_draw = svga->displine; @@ -402,25 +532,24 @@ void svga_render_4bpp_lowres(svga_t *svga) for (x = 0; x <= svga->hdisp; x += 16) { - uint8_t edat[4]; - uint8_t dat; - - *(uint32_t *)(&edat[0]) = *(uint32_t *)(&svga->vram[svga->ma]); + r = (uint32_t *)(&edat[0]); + q = (uint32_t *)(&svga->vram[svga->ma]); + *r = *q; svga->ma += 4; svga->ma = svga_mask_addr(svga->ma, svga); dat = edatlookup[edat[0] >> 6][edat[1] >> 6] | (edatlookup[edat[2] >> 6][edat[3] >> 6] << 2); - p[0] = p[1] = svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask] & svga->dac_mask]; - p[2] = p[3] = svga->pallook[svga->egapal[dat & svga->plane_mask] & svga->dac_mask]; + p[0] = p[1] = svga_color_transform(svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask] & svga->dac_mask]); + p[2] = p[3] = svga_color_transform(svga->pallook[svga->egapal[dat & svga->plane_mask] & svga->dac_mask]); dat = edatlookup[(edat[0] >> 4) & 3][(edat[1] >> 4) & 3] | (edatlookup[(edat[2] >> 4) & 3][(edat[3] >> 4) & 3] << 2); - p[4] = p[5] = svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask] & svga->dac_mask]; - p[6] = p[7] = svga->pallook[svga->egapal[dat & svga->plane_mask] & svga->dac_mask]; + p[4] = p[5] = svga_color_transform(svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask] & svga->dac_mask]); + p[6] = p[7] = svga_color_transform(svga->pallook[svga->egapal[dat & svga->plane_mask] & svga->dac_mask]); dat = edatlookup[(edat[0] >> 2) & 3][(edat[1] >> 2) & 3] | (edatlookup[(edat[2] >> 2) & 3][(edat[3] >> 2) & 3] << 2); - p[8] = p[9] = svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask] & svga->dac_mask]; - p[10] = p[11] = svga->pallook[svga->egapal[dat & svga->plane_mask] & svga->dac_mask]; + p[8] = p[9] = svga_color_transform(svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask] & svga->dac_mask]); + p[10] = p[11] = svga_color_transform(svga->pallook[svga->egapal[dat & svga->plane_mask] & svga->dac_mask]); dat = edatlookup[edat[0] & 3][edat[1] & 3] | (edatlookup[edat[2] & 3][edat[3] & 3] << 2); - p[12] = p[13] = svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask] & svga->dac_mask]; - p[14] = p[15] = svga->pallook[svga->egapal[dat & svga->plane_mask] & svga->dac_mask]; + p[12] = p[13] = svga_color_transform(svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask] & svga->dac_mask]); + p[14] = p[15] = svga_color_transform(svga->pallook[svga->egapal[dat & svga->plane_mask] & svga->dac_mask]); p += 16; } @@ -433,6 +562,13 @@ void svga_render_4bpp_highres(svga_t *svga) int changed_offset2; int y_add = (enable_overscan) ? 16 : 0; int x_add = y_add >> 1; + int dl = svga_display_line(svga); + int x; + int offset; + uint32_t *p; + uint8_t edat[4]; + uint8_t dat; + uint32_t *r, *q; if (svga->sc & 1 && !(svga->crtc[0x17] & 1)) changed_offset = svga_mask_addr(svga->ma | 0x8000, svga) >> 12; @@ -446,9 +582,8 @@ void svga_render_4bpp_highres(svga_t *svga) if (svga->changedvram[changed_offset] || svga->changedvram[changed_offset2] || svga->fullchange) { - int x; - int offset = (8 - svga->scrollcache) + 24; - uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[offset + x_add]; + offset = (8 - svga->scrollcache) + 24; + p = &((uint32_t *)buffer32->line[dl])[offset + x_add]; if (svga->firstline_draw == 2000) svga->firstline_draw = svga->displine; @@ -456,28 +591,27 @@ void svga_render_4bpp_highres(svga_t *svga) for (x = 0; x <= svga->hdisp; x += 8) { - uint8_t edat[4]; - uint8_t dat; - - if (svga->sc & 1 && !(svga->crtc[0x17] & 1)) - *(uint32_t *)(&edat[0]) = *(uint32_t *)(&svga->vram[svga_mask_addr(svga->ma | 0x8000, svga)]); + r = (uint32_t *)(&edat[0]); + if (svga->sc & 1 && !(svga->crtc[0x17] & 1)) + q = (uint32_t *)(&svga->vram[svga_mask_addr(svga->ma | 0x8000, svga)]); else - *(uint32_t *)(&edat[0]) = *(uint32_t *)(&svga->vram[svga->ma]); + q = (uint32_t *)(&svga->vram[svga->ma]); + *r = *q; svga->ma += 4; svga->ma = svga_mask_addr(svga->ma, svga); dat = edatlookup[edat[0] >> 6][edat[1] >> 6] | (edatlookup[edat[2] >> 6][edat[3] >> 6] << 2); - p[0] = svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask] & svga->dac_mask]; - p[1] = svga->pallook[svga->egapal[dat & svga->plane_mask] & svga->dac_mask]; + p[0] = svga_color_transform(svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask] & svga->dac_mask]); + p[1] = svga_color_transform(svga->pallook[svga->egapal[dat & svga->plane_mask] & svga->dac_mask]); dat = edatlookup[(edat[0] >> 4) & 3][(edat[1] >> 4) & 3] | (edatlookup[(edat[2] >> 4) & 3][(edat[3] >> 4) & 3] << 2); - p[2] = svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask] & svga->dac_mask]; - p[3] = svga->pallook[svga->egapal[dat & svga->plane_mask] & svga->dac_mask]; + p[2] = svga_color_transform(svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask] & svga->dac_mask]); + p[3] = svga_color_transform(svga->pallook[svga->egapal[dat & svga->plane_mask] & svga->dac_mask]); dat = edatlookup[(edat[0] >> 2) & 3][(edat[1] >> 2) & 3] | (edatlookup[(edat[2] >> 2) & 3][(edat[3] >> 2) & 3] << 2); - p[4] = svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask] & svga->dac_mask]; - p[5] = svga->pallook[svga->egapal[dat & svga->plane_mask] & svga->dac_mask]; + p[4] = svga_color_transform(svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask] & svga->dac_mask]); + p[5] = svga_color_transform(svga->pallook[svga->egapal[dat & svga->plane_mask] & svga->dac_mask]); dat = edatlookup[edat[0] & 3][edat[1] & 3] | (edatlookup[edat[2] & 3][edat[3] & 3] << 2); - p[6] = svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask] & svga->dac_mask]; - p[7] = svga->pallook[svga->egapal[dat & svga->plane_mask] & svga->dac_mask]; + p[6] = svga_color_transform(svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask] & svga->dac_mask]); + p[7] = svga_color_transform(svga->pallook[svga->egapal[dat & svga->plane_mask] & svga->dac_mask]); p += 8; } @@ -488,12 +622,13 @@ void svga_render_8bpp_lowres(svga_t *svga) { int y_add = (enable_overscan) ? 16 : 0; int x_add = y_add >> 1; + int dl = svga_display_line(svga); if (svga->changedvram[svga->ma >> 12] || svga->changedvram[svga_mask_changedaddr((svga->ma >> 12) + 1, svga)] || svga->fullchange) { int x; int offset = (8 - (svga->scrollcache & 6)) + 24; - uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[offset + x_add]; + uint32_t *p = &((uint32_t *)buffer32->line[dl])[offset + x_add]; if (svga->firstline_draw == 2000) svga->firstline_draw = svga->displine; @@ -503,30 +638,29 @@ void svga_render_8bpp_lowres(svga_t *svga) { uint32_t dat = *(uint32_t *)(&svga->vram[svga->ma]); - p[0] = p[1] = svga->pallook[dat & svga->dac_mask]; - p[2] = p[3] = svga->pallook[(dat >> 8) & svga->dac_mask]; - p[4] = p[5] = svga->pallook[(dat >> 16) & svga->dac_mask]; - p[6] = p[7] = svga->pallook[(dat >> 24) & svga->dac_mask]; + p[0] = p[1] = svga_color_transform(svga->pallook[dat & svga->dac_mask]); + p[2] = p[3] = svga_color_transform(svga->pallook[(dat >> 8) & svga->dac_mask]); + p[4] = p[5] = svga_color_transform(svga->pallook[(dat >> 16) & svga->dac_mask]); + p[6] = p[7] = svga_color_transform(svga->pallook[(dat >> 24) & svga->dac_mask]); svga->ma += 4; svga->ma = svga_mask_addr(svga->ma, svga); p += 8; } } - - // return NULL; } void svga_render_8bpp_highres(svga_t *svga) { int y_add = (enable_overscan) ? 16 : 0; int x_add = y_add >> 1; + int dl = svga_display_line(svga); if (svga->changedvram[svga->ma >> 12] || svga->changedvram[svga_mask_changedaddr((svga->ma >> 12) + 1, svga)] || svga->fullchange) { int x; int offset = (8 - ((svga->scrollcache & 6) >> 1)) + 24; - uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[offset + x_add]; + uint32_t *p = &((uint32_t *)buffer32->line[dl])[offset + x_add]; if (svga->firstline_draw == 2000) svga->firstline_draw = svga->displine; @@ -536,52 +670,65 @@ void svga_render_8bpp_highres(svga_t *svga) { uint32_t dat; dat = *(uint32_t *)(&svga->vram[svga->ma]); - p[0] = svga->pallook[dat & svga->dac_mask]; - p[1] = svga->pallook[(dat >> 8) & svga->dac_mask]; - p[2] = svga->pallook[(dat >> 16) & svga->dac_mask]; - p[3] = svga->pallook[(dat >> 24) & svga->dac_mask]; + p[0] = svga_color_transform(svga->pallook[dat & svga->dac_mask]); + p[1] = svga_color_transform(svga->pallook[(dat >> 8) & svga->dac_mask]); + p[2] = svga_color_transform(svga->pallook[(dat >> 16) & svga->dac_mask]); + p[3] = svga_color_transform(svga->pallook[(dat >> 24) & svga->dac_mask]); dat = *(uint32_t *)(&svga->vram[svga_mask_addr(svga->ma + 4, svga)]); - p[4] = svga->pallook[dat & svga->dac_mask]; - p[5] = svga->pallook[(dat >> 8) & svga->dac_mask]; - p[6] = svga->pallook[(dat >> 16) & svga->dac_mask]; - p[7] = svga->pallook[(dat >> 24) & svga->dac_mask]; + p[4] = svga_color_transform(svga->pallook[dat & svga->dac_mask]); + p[5] = svga_color_transform(svga->pallook[(dat >> 8) & svga->dac_mask]); + p[6] = svga_color_transform(svga->pallook[(dat >> 16) & svga->dac_mask]); + p[7] = svga_color_transform(svga->pallook[(dat >> 24) & svga->dac_mask]); svga->ma += 8; svga->ma = svga_mask_addr(svga->ma, svga); p += 8; } } - - // return NULL; } void svga_render_15bpp_lowres(svga_t *svga) { int y_add = (enable_overscan) ? 16 : 0; int x_add = y_add >> 1; + int dl = svga_display_line(svga); if (svga->changedvram[svga->ma >> 12] || svga->changedvram[svga_mask_changedaddr((svga->ma >> 12) + 1, svga)] || svga->fullchange) { int x; int offset = (8 - (svga->scrollcache & 6)) + 24; - uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[offset + x_add]; - + uint32_t *p = &((uint32_t *)buffer32->line[dl])[offset + x_add]; + if (svga->firstline_draw == 2000) svga->firstline_draw = svga->displine; svga->lastline_draw = svga->displine; - - for (x = 0; x <= svga->hdisp; x += 4) + + for (x = 0; x <= svga->hdisp; x += 16) { - uint32_t dat = *(uint32_t *)(&svga->vram[svga_mask_addr(svga->ma + (x << 1), svga)]); + uint32_t dat = *(uint32_t *)(&svga->vram[svga_mask_addr(svga->ma + x, svga)]); + p[x] = svga_color_transform(video_15to32[dat & 0xffff]); + p[x + 1] = svga_color_transform(video_15to32[dat & 0xffff]); + p[x + 2] = svga_color_transform(video_15to32[dat >> 16]); + p[x + 3] = svga_color_transform(video_15to32[dat >> 16]); + + dat = *(uint32_t *)(&svga->vram[svga_mask_addr(svga->ma + x + 4, svga)]); + p[x + 4] = svga_color_transform(video_15to32[dat & 0xffff]); + p[x + 5] = svga_color_transform(video_15to32[dat & 0xffff]); + p[x + 6] = svga_color_transform(video_15to32[dat >> 16]); + p[x + 7] = svga_color_transform(video_15to32[dat >> 16]); - p[x] = video_15to32[dat & 0xffff]; - p[x + 1] = video_15to32[dat >> 16]; + dat = *(uint32_t *)(&svga->vram[svga_mask_addr(svga->ma + x + 8, svga)]); + p[x + 8] = svga_color_transform(video_15to32[dat & 0xffff]); + p[x + 9] = svga_color_transform(video_15to32[dat & 0xffff]); + p[x + 10] = svga_color_transform(video_15to32[dat >> 16]); + p[x + 11] = svga_color_transform(video_15to32[dat >> 16]); - dat = *(uint32_t *)(&svga->vram[svga_mask_addr(svga->ma + (x << 1) + 4, svga)]); - - p[x] = video_15to32[dat & 0xffff]; - p[x + 1] = video_15to32[dat >> 16]; + dat = *(uint32_t *)(&svga->vram[svga_mask_addr(svga->ma + x + 12, svga)]); + p[x + 12] = svga_color_transform(video_15to32[dat & 0xffff]); + p[x + 13] = svga_color_transform(video_15to32[dat & 0xffff]); + p[x + 14] = svga_color_transform(video_15to32[dat >> 16]); + p[x + 15] = svga_color_transform(video_15to32[dat >> 16]); } svga->ma += x << 1; svga->ma = svga_mask_addr(svga->ma, svga); @@ -592,12 +739,13 @@ void svga_render_15bpp_highres(svga_t *svga) { int y_add = (enable_overscan) ? 16 : 0; int x_add = y_add >> 1; + int dl = svga_display_line(svga); if (svga->changedvram[svga->ma >> 12] || svga->changedvram[svga_mask_changedaddr((svga->ma >> 12) + 1, svga)] || svga->fullchange) { int x; int offset = (8 - ((svga->scrollcache & 6) >> 1)) + 24; - uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[offset + x_add]; + uint32_t *p = &((uint32_t *)buffer32->line[dl])[offset + x_add]; if (svga->firstline_draw == 2000) svga->firstline_draw = svga->displine; @@ -606,20 +754,20 @@ void svga_render_15bpp_highres(svga_t *svga) for (x = 0; x <= svga->hdisp; x += 8) { uint32_t dat = *(uint32_t *)(&svga->vram[svga_mask_addr(svga->ma + (x << 1), svga)]); - p[x] = video_15to32[dat & 0xffff]; - p[x + 1] = video_15to32[dat >> 16]; + p[x] = svga_color_transform(video_15to32[dat & 0xffff]); + p[x + 1] = svga_color_transform(video_15to32[dat >> 16]); dat = *(uint32_t *)(&svga->vram[svga_mask_addr(svga->ma + (x << 1) + 4, svga)]); - p[x + 2] = video_15to32[dat & 0xffff]; - p[x + 3] = video_15to32[dat >> 16]; + p[x + 2] = svga_color_transform(video_15to32[dat & 0xffff]); + p[x + 3] = svga_color_transform(video_15to32[dat >> 16]); dat = *(uint32_t *)(&svga->vram[svga_mask_addr(svga->ma + (x << 1) + 8, svga)]); - p[x + 4] = video_15to32[dat & 0xffff]; - p[x + 5] = video_15to32[dat >> 16]; + p[x + 4] = svga_color_transform(video_15to32[dat & 0xffff]); + p[x + 5] = svga_color_transform(video_15to32[dat >> 16]); dat = *(uint32_t *)(&svga->vram[svga_mask_addr(svga->ma + (x << 1) + 12, svga)]); - p[x + 6] = video_15to32[dat & 0xffff]; - p[x + 7] = video_15to32[dat >> 16]; + p[x + 6] = svga_color_transform(video_15to32[dat & 0xffff]); + p[x + 7] = svga_color_transform(video_15to32[dat >> 16]); } svga->ma += x << 1; svga->ma = svga_mask_addr(svga->ma, svga); @@ -630,28 +778,43 @@ void svga_render_16bpp_lowres(svga_t *svga) { int y_add = (enable_overscan) ? 16 : 0; int x_add = y_add >> 1; + int dl = svga_display_line(svga); if (svga->changedvram[svga->ma >> 12] || svga->changedvram[svga_mask_changedaddr((svga->ma >> 12) + 1, svga)] || svga->fullchange) { int x; int offset = (8 - (svga->scrollcache & 6)) + 24; - uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[offset + x_add]; - + uint32_t *p = &((uint32_t *)buffer32->line[dl])[offset + x_add]; + if (svga->firstline_draw == 2000) svga->firstline_draw = svga->displine; svga->lastline_draw = svga->displine; - - for (x = 0; x <= svga->hdisp; x += 4) + + for (x = 0; x <= svga->hdisp; x += 16) { - uint32_t dat = *(uint32_t *)(&svga->vram[svga_mask_addr(svga->ma + (x << 1), svga)]); + uint32_t dat = *(uint32_t *)(&svga->vram[svga_mask_addr(svga->ma + x, svga)]); + p[x] = svga_color_transform(video_16to32[dat & 0xffff]); + p[x + 1] = svga_color_transform(video_16to32[dat & 0xffff]); + p[x + 2] = svga_color_transform(video_16to32[dat >> 16]); + p[x + 3] = svga_color_transform(video_16to32[dat >> 16]); + + dat = *(uint32_t *)(&svga->vram[svga_mask_addr(svga->ma + x + 4, svga)]); + p[x + 4] = svga_color_transform(video_16to32[dat & 0xffff]); + p[x + 5] = svga_color_transform(video_16to32[dat & 0xffff]); + p[x + 6] = svga_color_transform(video_16to32[dat >> 16]); + p[x + 7] = svga_color_transform(video_16to32[dat >> 16]); - p[x] = video_16to32[dat & 0xffff]; - p[x + 1] = video_16to32[dat >> 16]; + dat = *(uint32_t *)(&svga->vram[svga_mask_addr(svga->ma + x + 8, svga)]); + p[x + 8] = svga_color_transform(video_16to32[dat & 0xffff]); + p[x + 9] = svga_color_transform(video_16to32[dat & 0xffff]); + p[x + 10] = svga_color_transform(video_16to32[dat >> 16]); + p[x + 11] = svga_color_transform(video_16to32[dat >> 16]); - dat = *(uint32_t *)(&svga->vram[svga_mask_addr(svga->ma + (x << 1) + 4, svga)]); - - p[x] = video_16to32[dat & 0xffff]; - p[x + 1] = video_16to32[dat >> 16]; + dat = *(uint32_t *)(&svga->vram[svga_mask_addr(svga->ma + x + 12, svga)]); + p[x + 12] = svga_color_transform(video_16to32[dat & 0xffff]); + p[x + 13] = svga_color_transform(video_16to32[dat & 0xffff]); + p[x + 14] = svga_color_transform(video_16to32[dat >> 16]); + p[x + 15] = svga_color_transform(video_16to32[dat >> 16]); } svga->ma += x << 1; svga->ma = svga_mask_addr(svga->ma, svga); @@ -662,12 +825,13 @@ void svga_render_16bpp_highres(svga_t *svga) { int y_add = (enable_overscan) ? 16 : 0; int x_add = y_add >> 1; + int dl = svga_display_line(svga); if (svga->changedvram[svga->ma >> 12] || svga->changedvram[svga_mask_changedaddr((svga->ma >> 12) + 1, svga)] || svga->fullchange) { int x; int offset = (8 - ((svga->scrollcache & 6) >> 1)) + 24; - uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[offset + x_add]; + uint32_t *p = &((uint32_t *)buffer32->line[dl])[offset + x_add]; if (svga->firstline_draw == 2000) svga->firstline_draw = svga->displine; @@ -676,20 +840,20 @@ void svga_render_16bpp_highres(svga_t *svga) for (x = 0; x <= svga->hdisp; x += 8) { uint32_t dat = *(uint32_t *)(&svga->vram[svga_mask_addr(svga->ma + (x << 1), svga)]); - p[x] = video_16to32[dat & 0xffff]; - p[x + 1] = video_16to32[dat >> 16]; + p[x] = svga_color_transform(video_16to32[dat & 0xffff]); + p[x + 1] = svga_color_transform(video_16to32[dat >> 16]); dat = *(uint32_t *)(&svga->vram[svga_mask_addr(svga->ma + (x << 1) + 4, svga)]); - p[x + 2] = video_16to32[dat & 0xffff]; - p[x + 3] = video_16to32[dat >> 16]; + p[x + 2] = svga_color_transform(video_16to32[dat & 0xffff]); + p[x + 3] = svga_color_transform(video_16to32[dat >> 16]); dat = *(uint32_t *)(&svga->vram[svga_mask_addr(svga->ma + (x << 1) + 8, svga)]); - p[x + 4] = video_16to32[dat & 0xffff]; - p[x + 5] = video_16to32[dat >> 16]; + p[x + 4] = svga_color_transform(video_16to32[dat & 0xffff]); + p[x + 5] = svga_color_transform(video_16to32[dat >> 16]); dat = *(uint32_t *)(&svga->vram[svga_mask_addr(svga->ma + (x << 1) + 12, svga)]); - p[x + 6] = video_16to32[dat & 0xffff]; - p[x + 7] = video_16to32[dat >> 16]; + p[x + 6] = svga_color_transform(video_16to32[dat & 0xffff]); + p[x + 7] = svga_color_transform(video_16to32[dat >> 16]); } svga->ma += x << 1; svga->ma = svga_mask_addr(svga->ma, svga); @@ -702,6 +866,7 @@ void svga_render_24bpp_lowres(svga_t *svga) uint32_t fg; int y_add = (enable_overscan) ? 16 : 0; int x_add = y_add >> 1; + int dl = svga_display_line(svga); if (svga->changedvram[svga->ma >> 12] || svga->changedvram[svga_mask_changedaddr((svga->ma >> 12) + 1, svga)] || svga->fullchange) { @@ -716,7 +881,7 @@ void svga_render_24bpp_lowres(svga_t *svga) fg = svga->vram[svga->ma] | (svga->vram[svga_mask_addr(svga->ma + 1, svga)] << 8) | (svga->vram[svga_mask_addr(svga->ma + 2, svga)] << 16); svga->ma += 3; svga->ma = svga_mask_addr(svga->ma, svga); - ((uint32_t *)buffer32->line[svga->displine + y_add])[(x << 1) + offset + x_add] = ((uint32_t *)buffer32->line[svga->displine + y_add])[(x << 1) + 1 + offset + x_add] = fg; + ((uint32_t *)buffer32->line[dl])[(x << 1) + offset + x_add] = ((uint32_t *)buffer32->line[dl])[(x << 1) + 1 + offset + x_add] = svga_color_transform(fg); } } } @@ -725,12 +890,13 @@ void svga_render_24bpp_highres(svga_t *svga) { int y_add = (enable_overscan) ? 16 : 0; int x_add = y_add >> 1; + int dl = svga_display_line(svga); if (svga->changedvram[svga->ma >> 12] || svga->changedvram[svga_mask_changedaddr((svga->ma >> 12) + 1, svga)] || svga->fullchange) { int x; int offset = (8 - ((svga->scrollcache & 6) >> 1)) + 24; - uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[offset + x_add]; + uint32_t *p = &((uint32_t *)buffer32->line[dl])[offset + x_add]; if (svga->firstline_draw == 2000) svga->firstline_draw = svga->displine; @@ -739,16 +905,16 @@ void svga_render_24bpp_highres(svga_t *svga) for (x = 0; x <= svga->hdisp; x += 4) { uint32_t dat = *(uint32_t *)(&svga->vram[svga->ma]); - p[x] = dat & 0xffffff; + p[x] = svga_color_transform(dat & 0xffffff); dat = *(uint32_t *)(&svga->vram[svga_mask_addr(svga->ma + 3, svga)]); - p[x + 1] = dat & 0xffffff; + p[x + 1] = svga_color_transform(dat & 0xffffff); dat = *(uint32_t *)(&svga->vram[svga_mask_addr(svga->ma + 6, svga)]); - p[x + 2] = dat & 0xffffff; + p[x + 2] = svga_color_transform(dat & 0xffffff); dat = *(uint32_t *)(&svga->vram[svga_mask_addr(svga->ma + 9, svga)]); - p[x + 3] = dat & 0xffffff; + p[x + 3] = svga_color_transform(dat & 0xffffff); svga->ma += 12; svga->ma = svga_mask_addr(svga->ma, svga); @@ -762,6 +928,7 @@ void svga_render_32bpp_lowres(svga_t *svga) uint32_t fg; int y_add = (enable_overscan) ? 16 : 0; int x_add = y_add >> 1; + int dl = svga_display_line(svga); if (svga->changedvram[svga->ma >> 12] || svga->changedvram[svga_mask_changedaddr((svga->ma >> 12) + 1, svga)] || svga->fullchange) { @@ -776,7 +943,7 @@ void svga_render_32bpp_lowres(svga_t *svga) fg = svga->vram[svga->ma] | (svga->vram[svga_mask_addr(svga->ma + 1, svga)] << 8) | (svga->vram[svga_mask_addr(svga->ma + 2, svga)] << 16); svga->ma += 4; svga->ma = svga_mask_addr(svga->ma, svga); - ((uint32_t *)buffer32->line[svga->displine + y_add])[(x << 1) + offset + x_add] = ((uint32_t *)buffer32->line[svga->displine + y_add])[(x << 1) + 1 + offset + x_add] = fg; + ((uint32_t *)buffer32->line[dl])[(x << 1) + offset + x_add] = ((uint32_t *)buffer32->line[dl])[(x << 1) + 1 + offset + x_add] = svga_color_transform(fg); } } } @@ -787,12 +954,13 @@ void svga_render_32bpp_highres(svga_t *svga) { int y_add = (enable_overscan) ? 16 : 0; int x_add = y_add >> 1; + int dl = svga_display_line(svga); if (svga->changedvram[svga->ma >> 12] || svga->changedvram[svga_mask_changedaddr((svga->ma >> 12) + 1, svga)] || svga->changedvram[svga_mask_changedaddr((svga->ma >> 12) + 2, svga)] || svga->fullchange) { int x; int offset = (8 - ((svga->scrollcache & 6) >> 1)) + 24; - uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[offset + x_add]; + uint32_t *p = &((uint32_t *)buffer32->line[dl])[offset + x_add]; if (svga->firstline_draw == 2000) svga->firstline_draw = svga->displine; @@ -801,7 +969,33 @@ void svga_render_32bpp_highres(svga_t *svga) for (x = 0; x <= svga->hdisp; x++) { uint32_t dat = *(uint32_t *)(&svga->vram[svga_mask_addr(svga->ma + (x << 2), svga)]); - p[x] = dat & 0xffffff; + p[x] = svga_color_transform(dat & 0xffffff); + } + svga->ma += 4; + svga->ma = svga_mask_addr(svga->ma, svga); + } +} + +void svga_render_ABGR8888_lowres(svga_t *svga) +{ + int y_add = (enable_overscan) ? 16 : 0; + int x_add = y_add >> 1; + int dl = svga_display_line(svga); + + if (svga->changedvram[svga->ma >> 12] || svga->changedvram[svga_mask_changedaddr((svga->ma >> 12) + 1, svga)] || svga->changedvram[svga_mask_changedaddr((svga->ma >> 12) + 2, svga)] || svga->fullchange) + { + int x; + int offset = (8 - ((svga->scrollcache & 6) >> 1)) + 24; + uint32_t *p = &((uint32_t *)buffer32->line[dl])[offset + x_add]; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + for (x = 0; x <= svga->hdisp; x++) + { + uint32_t dat = *(uint32_t *)(&svga->vram[svga_mask_addr(svga->ma + (x << 2), svga)]); + p[x << 1] = p[(x << 1) + 1] = svga_color_transform(((dat & 0xff0000) >> 16) | (dat & 0x00ff00) | ((dat & 0x0000ff) << 16)); } svga->ma += 4; svga->ma = svga_mask_addr(svga->ma, svga); @@ -812,12 +1006,13 @@ void svga_render_ABGR8888_highres(svga_t *svga) { int y_add = (enable_overscan) ? 16 : 0; int x_add = y_add >> 1; + int dl = svga_display_line(svga); if (svga->changedvram[svga->ma >> 12] || svga->changedvram[svga_mask_changedaddr((svga->ma >> 12) + 1, svga)] || svga->changedvram[svga_mask_changedaddr((svga->ma >> 12) + 2, svga)] || svga->fullchange) { int x; int offset = (8 - ((svga->scrollcache & 6) >> 1)) + 24; - uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[offset + x_add]; + uint32_t *p = &((uint32_t *)buffer32->line[dl])[offset + x_add]; if (svga->firstline_draw == 2000) svga->firstline_draw = svga->displine; @@ -826,7 +1021,33 @@ void svga_render_ABGR8888_highres(svga_t *svga) for (x = 0; x <= svga->hdisp; x++) { uint32_t dat = *(uint32_t *)(&svga->vram[svga_mask_addr(svga->ma + (x << 2), svga)]); - p[x] = ((dat & 0xff0000) >> 16) | (dat & 0x00ff00) | ((dat & 0x0000ff) << 16); + p[x] = svga_color_transform(((dat & 0xff0000) >> 16) | (dat & 0x00ff00) | ((dat & 0x0000ff) << 16)); + } + svga->ma += 4; + svga->ma = svga_mask_addr(svga->ma, svga); + } +} + +void svga_render_RGBA8888_lowres(svga_t *svga) +{ + int y_add = (enable_overscan) ? 16 : 0; + int x_add = y_add >> 1; + int dl = svga_display_line(svga); + + if (svga->changedvram[svga->ma >> 12] || svga->changedvram[svga_mask_changedaddr((svga->ma >> 12) + 1, svga)] || svga->changedvram[svga_mask_changedaddr((svga->ma >> 12) + 2, svga)] || svga->fullchange) + { + int x; + int offset = (8 - ((svga->scrollcache & 6) >> 1)) + 24; + uint32_t *p = &((uint32_t *)buffer32->line[dl])[offset + x_add]; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + for (x = 0; x <= svga->hdisp; x++) + { + uint32_t dat = *(uint32_t *)(&svga->vram[svga_mask_addr(svga->ma + (x << 2), svga)]); + p[x << 1] = p[(x << 1) + 1] = svga_color_transform(dat >> 8); } svga->ma += 4; svga->ma = svga_mask_addr(svga->ma, svga); @@ -837,12 +1058,13 @@ void svga_render_RGBA8888_highres(svga_t *svga) { int y_add = (enable_overscan) ? 16 : 0; int x_add = y_add >> 1; + int dl = svga_display_line(svga); if (svga->changedvram[svga->ma >> 12] || svga->changedvram[svga_mask_changedaddr((svga->ma >> 12) + 1, svga)] || svga->changedvram[svga_mask_changedaddr((svga->ma >> 12) + 2, svga)] || svga->fullchange) { int x; int offset = (8 - ((svga->scrollcache & 6) >> 1)) + 24; - uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[offset + x_add]; + uint32_t *p = &((uint32_t *)buffer32->line[dl])[offset + x_add]; if (svga->firstline_draw == 2000) svga->firstline_draw = svga->displine; @@ -851,7 +1073,7 @@ void svga_render_RGBA8888_highres(svga_t *svga) for (x = 0; x <= svga->hdisp; x++) { uint32_t dat = *(uint32_t *)(&svga->vram[svga_mask_addr(svga->ma + (x << 2), svga)]); - p[x] = dat >> 8; + p[x] = svga_color_transform(dat >> 8); } svga->ma += 4; svga->ma = svga_mask_addr(svga->ma, svga); diff --git a/src/vid_svga_render.h b/src/VIDEO/vid_svga_render.h similarity index 64% rename from src/vid_svga_render.h rename to src/VIDEO/vid_svga_render.h index f6611db57..cfad3585d 100644 --- a/src/vid_svga_render.h +++ b/src/VIDEO/vid_svga_render.h @@ -1,6 +1,21 @@ -/* Copyright holders: Sarah Walker - see COPYING for more details -*/ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * SVGA renderers. + * + * Version: @(#)vid_svga_render.h 1.0.0 2017/05/30 + * + * Author: Sarah Walker, + * Miran Grca, + * Copyright 2008-2017 Sarah Walker. + * Copyright 2016-2017 Miran Grca. + */ + extern int firstline_draw, lastline_draw; extern int displine; extern int sc; @@ -32,7 +47,9 @@ void svga_render_24bpp_lowres(svga_t *svga); void svga_render_24bpp_highres(svga_t *svga); void svga_render_32bpp_lowres(svga_t *svga); void svga_render_32bpp_highres(svga_t *svga); +void svga_render_ABGR8888_lowres(svga_t *svga); void svga_render_ABGR8888_highres(svga_t *svga); +void svga_render_RGBA8888_lowres(svga_t *svga); void svga_render_RGBA8888_highres(svga_t *svga); extern void (*svga_render)(svga_t *svga); diff --git a/src/vid_tandy.c b/src/VIDEO/vid_tandy.c similarity index 89% rename from src/vid_tandy.c rename to src/VIDEO/vid_tandy.c index 0cc52235d..d6151e44e 100644 --- a/src/vid_tandy.c +++ b/src/VIDEO/vid_tandy.c @@ -1,17 +1,19 @@ #include #include -#include "ibm.h" -#include "device.h" -#include "io.h" -#include "mem.h" -#include "timer.h" +#include "../ibm.h" +#include "../io.h" +#include "../mem.h" +#include "../timer.h" +#include "../device.h" #include "video.h" #include "vid_tandy.h" -#include "dosbox/vid_cga_comp.h" +#include "vid_cga_comp.h" + #define TANDY_RGB 0 #define TANDY_COMPOSITE 1 + typedef struct tandy_t { mem_mapping_t mapping; @@ -22,7 +24,7 @@ typedef struct tandy_t int array_index; uint8_t array[32]; - int memctrl;//=-1; + int memctrl; uint32_t base; uint8_t mode, col; uint8_t stat; @@ -56,7 +58,6 @@ void tandy_out(uint16_t addr, uint8_t val, void *p) { tandy_t *tandy = (tandy_t *)p; uint8_t old; -// pclog("Tandy OUT %04X %02X\n",addr,val); switch (addr) { case 0x3d4: @@ -103,7 +104,6 @@ void tandy_out(uint16_t addr, uint8_t val, void *p) uint8_t tandy_in(uint16_t addr, void *p) { tandy_t *tandy = (tandy_t *)p; -// if (addr!=0x3DA) pclog("Tandy IN %04X\n",addr); switch (addr) { case 0x3d4: @@ -123,28 +123,24 @@ 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); } } void tandy_ram_write(uint32_t addr, uint8_t val, void *p) { tandy_t *tandy = (tandy_t *)p; -// pclog("Tandy RAM write %05X %02X %04X:%04X\n",addr,val,CS,pc); ram[tandy->base + (addr & 0x1ffff)] = val; } uint8_t tandy_ram_read(uint32_t addr, void *p) { tandy_t *tandy = (tandy_t *)p; -// pclog("Tandy RAM read %05X %02X %04X:%04X\n",addr,ram[tandy->base + (addr & 0x1ffff)],CS,pc); return ram[tandy->base + (addr & 0x1ffff)]; } @@ -155,7 +151,6 @@ void tandy_write(uint32_t addr, uint8_t val, void *p) return; egawrites++; -// pclog("Tandy VRAM write %05X %02X %04X:%04X %04X:%04X\n",addr,val,CS,pc,DS,SI); tandy->b8000[addr & tandy->b8000_mask] = val; } @@ -166,7 +161,6 @@ uint8_t tandy_read(uint32_t addr, void *p) return 0xff; egareads++; -// pclog("Tandy VRAM read %05X %02X %04X:%04X\n",addr,tandy->b8000[addr&0x7FFF],CS,pc); return tandy->b8000[addr & tandy->b8000_mask]; } @@ -190,28 +184,8 @@ void tandy_recalctimings(tandy_t *tandy) tandy->dispofftime = (int)(_dispofftime * (1 << TIMER_SHIFT)); } - -static int ntsc_col[8][8]= -{ - {0,0,0,0,0,0,0,0}, /*Black*/ - {0,0,1,1,1,1,0,0}, /*Blue*/ - {1,0,0,0,0,1,1,1}, /*Green*/ - {0,0,0,0,1,1,1,1}, /*Cyan*/ - {1,1,1,1,0,0,0,0}, /*Red*/ - {0,1,1,1,1,0,0,0}, /*Magenta*/ - {1,1,0,0,0,0,1,1}, /*Yellow*/ - {1,1,1,1,1,1,1,1} /*White*/ -}; - -/*static int cga4pal[8][4]= -{ - {0,2,4,6},{0,3,5,7},{0,3,4,7},{0,3,4,7}, - {0,10,12,14},{0,11,13,15},{0,11,12,15},{0,11,12,15} -};*/ - void tandy_poll(void *p) { -// int *cgapal=cga4pal[((tandy->col&0x10)>>2)|((cgamode&4)>>1)|((cgacol&0x20)>>5)]; tandy_t *tandy = (tandy_t *)p; uint16_t ca = (tandy->crtc[15] | (tandy->crtc[14] << 8)) & 0x3fff; int drawcursor; @@ -222,14 +196,8 @@ void tandy_poll(void *p) int cols[4]; int col; int oldsc; - int y_buf[8] = {0, 0, 0, 0, 0, 0, 0, 0}, y_val, y_tot; - int i_buf[8] = {0, 0, 0, 0, 0, 0, 0, 0}, i_val, i_tot; - int q_buf[8] = {0, 0, 0, 0, 0, 0, 0, 0}, q_val, q_tot; - int r, g, b; if (!tandy->linepos) { -// 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; @@ -242,7 +210,6 @@ void tandy_poll(void *p) { tandy->firstline = tandy->displine; video_wait_for_buffer(); -// printf("Firstline %i\n",firstline); } tandy->lastline = tandy->displine; cols[0] = (tandy->array[2] & 0xf) + 16; @@ -267,8 +234,6 @@ void tandy_poll(void *p) else buffer->line[tandy->displine][c + (tandy->crtc[1] << 4) + 8] = (tandy->col & 15) + 16; } } -// printf("X %i %i\n",c+(crtc[1]<<4)+8,c+(crtc[1]<<3)+8); -// printf("Drawing %i %i %i\n",tandy->displine,vc,sc); if ((tandy->array[3] & 0x10) && (tandy->mode & 1)) /*320x200x16*/ { for (x = 0; x < tandy->crtc[1]; x++) @@ -356,7 +321,6 @@ void tandy_poll(void *p) 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++) @@ -485,7 +449,6 @@ void tandy_poll(void *p) 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) @@ -503,7 +466,6 @@ void tandy_poll(void *p) 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))) @@ -522,24 +484,19 @@ void tandy_poll(void *p) tandy->dispon = 1; 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 &= 127; -// printf("VC %i %i %i %i %i\n",vc,crtc[4],crtc[6],crtc[7],tandy->dispon); if (tandy->vc == tandy->crtc[6]) tandy->dispon = 0; if (oldvc == tandy->crtc[4]) { -// printf("Display over at %i\n",tandy->displine); tandy->vc = 0; tandy->vadj = tandy->crtc[5]; if (!tandy->vadj) @@ -548,18 +505,14 @@ void tandy_poll(void *p) 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; + tandy->vsynctime = 16; 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++; @@ -567,13 +520,10 @@ void tandy_poll(void *p) { 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); if (tandy->composite) video_blit_memtoscreen(0, tandy->firstline-4, 0, (tandy->lastline - tandy->firstline) + 8, xsize, (tandy->lastline - tandy->firstline) + 8); @@ -685,27 +635,21 @@ device_t tandy_device = static device_config_t tandy_config[] = { { - .name = "display_type", - .description = "Display type", - .type = CONFIG_SELECTION, - .selection = + "display_type", "Display type", CONFIG_SELECTION, "", TANDY_RGB, { { - .description = "RGB", - .value = TANDY_RGB + "RGB", TANDY_RGB }, { - .description = "Composite", - .value = TANDY_COMPOSITE + "Composite", TANDY_COMPOSITE }, { - .description = "" + "" } - }, - .default_int = TANDY_RGB + } }, { - .type = -1 + "", "", -1 } }; diff --git a/src/vid_tandy.h b/src/VIDEO/vid_tandy.h similarity index 100% rename from src/vid_tandy.h rename to src/VIDEO/vid_tandy.h diff --git a/src/vid_tandysl.c b/src/VIDEO/vid_tandysl.c similarity index 91% rename from src/vid_tandysl.c rename to src/VIDEO/vid_tandysl.c index 48d53d496..0c4225525 100644 --- a/src/vid_tandysl.c +++ b/src/VIDEO/vid_tandysl.c @@ -3,14 +3,15 @@ */ #include #include -#include "ibm.h" -#include "device.h" -#include "io.h" -#include "mem.h" -#include "timer.h" +#include "../ibm.h" +#include "../io.h" +#include "../mem.h" +#include "../timer.h" +#include "../device.h" #include "video.h" #include "vid_tandysl.h" + typedef struct tandysl_t { mem_mapping_t mapping; @@ -22,7 +23,7 @@ typedef struct tandysl_t int array_index; uint8_t array[32]; - int memctrl;//=-1; + int memctrl; uint32_t base; uint8_t mode, col; uint8_t stat; @@ -60,17 +61,14 @@ 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) @@ -101,7 +99,6 @@ static void tandysl_out(uint16_t addr, uint8_t val, void *p) break; case 0x3df: tandy->memctrl = val; -// pclog("tandy 3df write %02x\n", val); tandysl_recalcaddress(tandy); break; case 0x65: @@ -123,7 +120,6 @@ static void tandysl_out(uint16_t addr, uint8_t val, void *p) 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: @@ -133,7 +129,6 @@ static uint8_t tandysl_in(uint16_t addr, void *p) case 0x3da: return tandy->stat; } -// pclog("Bad Tandy IN %04x\n", addr); return 0xFF; } @@ -149,13 +144,11 @@ static void tandysl_recalcaddress(tandysl_t *tandy) { 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; } @@ -167,40 +160,32 @@ static void tandysl_recalcmapping(tandysl_t *tandy) 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)]; } @@ -211,7 +196,6 @@ static void tandysl_write(uint32_t addr, uint8_t val, void *p) 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 @@ -229,7 +213,6 @@ static uint8_t tandysl_read(uint32_t addr, void *p) 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) @@ -273,9 +256,6 @@ static void tandysl_poll(void *p) 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; @@ -288,7 +268,6 @@ static void tandysl_poll(void *p) { tandy->firstline = tandy->displine; video_wait_for_buffer(); -// printf("Firstline %i\n",firstline); } tandy->lastline = tandy->displine; cols[0] = (tandy->array[2] & 0xf) + 16; @@ -413,7 +392,6 @@ static void tandysl_poll(void *p) 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++) @@ -533,7 +511,6 @@ static void tandysl_poll(void *p) 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) @@ -551,7 +528,6 @@ static void tandysl_poll(void *p) 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))) @@ -573,28 +549,21 @@ static void tandysl_poll(void *p) 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) @@ -608,18 +577,14 @@ static void tandysl_poll(void *p) } 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; + tandy->vsynctime = 16; 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++; @@ -627,13 +592,10 @@ static void tandysl_poll(void *p) { 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); video_blit_memtoscreen_8(0, tandy->firstline-4, xsize, (tandy->lastline - tandy->firstline) + 8); @@ -690,7 +652,6 @@ static void tandysl_poll(void *p) static void *tandysl_init() { - int c; tandysl_t *tandy = malloc(sizeof(tandysl_t)); memset(tandy, 0, sizeof(tandysl_t)); diff --git a/src/vid_tandysl.h b/src/VIDEO/vid_tandysl.h similarity index 100% rename from src/vid_tandysl.h rename to src/VIDEO/vid_tandysl.h diff --git a/src/vid_tgui9440.c b/src/VIDEO/vid_tgui9440.c similarity index 89% rename from src/vid_tgui9440.c rename to src/VIDEO/vid_tgui9440.c index d6ce6ad8b..d0a11d317 100644 --- a/src/vid_tgui9440.c +++ b/src/VIDEO/vid_tgui9440.c @@ -3,18 +3,20 @@ */ /*Trident TGUI9440 emulation*/ #include -#include "ibm.h" -#include "device.h" -#include "io.h" -#include "mem.h" -#include "rom.h" -#include "thread.h" +#include "../ibm.h" +#include "../io.h" +#include "../mem.h" +#include "../pci.h" +#include "../rom.h" +#include "../device.h" +#include "../win/plat_thread.h" #include "video.h" #include "vid_svga.h" #include "vid_svga_render.h" #include "vid_tkd8001_ramdac.h" #include "vid_tgui9440.h" + #define FIFO_SIZE 65536 #define FIFO_MASK (FIFO_SIZE - 1) #define FIFO_ENTRY_SIZE (1 << 31) @@ -120,7 +122,6 @@ void tgui_out(uint16_t addr, uint8_t val, void *p) uint8_t old; -// pclog("tgui_out : %04X %02X %04X:%04X %i\n", addr, val, CS,pc, svga->bpp); if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga->miscout & 1)) addr ^= 0x60; switch (addr) @@ -211,7 +212,6 @@ void tgui_out(uint16_t addr, uint8_t val, void *p) val = (svga->crtc[7] & ~0x10) | (val & 0x10); old = svga->crtc[svga->crtcreg]; svga->crtc[svga->crtcreg] = val; -// if (svga->crtcreg != 0xE && svga->crtcreg != 0xF) pclog("CRTC R%02X = %02X\n", svga->crtcreg, val); if (old != val) { if (svga->crtcreg < 0xE || svga->crtcreg > 0x10) @@ -253,11 +253,9 @@ void tgui_out(uint16_t addr, uint8_t val, void *p) if (svga->gdcreg[0xf] & 4) { svga->write_bank = (val & 0x1f) * 65536; -// pclog("SVGAWBANK 3D8 %08X %04X:%04X\n",svgawbank,CS,pc); if (!(svga->gdcreg[0xf] & 1)) { svga->read_bank = (val & 0x1f) * 65536; -// pclog("SVGARBANK 3D8 %08X %04X:%04X\n",svgarbank,CS,pc); } } return; @@ -266,7 +264,6 @@ void tgui_out(uint16_t addr, uint8_t val, void *p) if ((svga->gdcreg[0xf] & 5) == 5) { svga->read_bank = (val & 0x1F) * 65536; -// pclog("SVGARBANK 3D9 %08X %04X:%04X\n",svgarbank,CS,pc); } return; @@ -287,8 +284,6 @@ uint8_t tgui_in(uint16_t addr, void *p) tgui_t *tgui = (tgui_t *)p; svga_t *svga = &tgui->svga; -// if (addr != 0x3da) pclog("tgui_in : %04X %04X:%04X\n", addr, CS,pc); - if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga->miscout & 1)) addr ^= 0x60; switch (addr) @@ -296,15 +291,9 @@ uint8_t tgui_in(uint16_t addr, void *p) case 0x3C5: if ((svga->seqaddr & 0xf) == 0xb) { -// printf("Read Trident ID %04X:%04X %04X\n",CS,pc,readmemw(ss,SP)); tgui->oldmode = 0; return 0xe3; /*TGUI9440AGi*/ } - if ((svga->seqaddr & 0xf) == 0xc) - { -// printf("Read Trident Power Up 1 %04X:%04X %04X\n",CS,pc,readmemw(ss,SP)); -// return 0x20; /*2 DRAM banks*/ - } if ((svga->seqaddr & 0xf) == 0xd) { if (tgui->oldmode) return tgui->oldctrl2; @@ -355,10 +344,8 @@ void tgui_recalctimings(svga_t *svga) svga->lowres = !(svga->crtc[0x2a] & 0x40); - // svga->interlace = svga->crtc[0x1e] & 4; if (svga->crtc[0x1e] & 4) { - // svga->rowoffset >>= 1; svga->vtotal *= 2; svga->dispend *= 2; svga->vblankstart *= 2; @@ -397,20 +384,16 @@ void tgui_recalctimings(svga_t *svga) void tgui_recalcmapping(tgui_t *tgui) { svga_t *svga = &tgui->svga; - -// pclog("tgui_recalcmapping : %02X %02X\n", svga->crtc[0x21], svga->gdcreg[6]); if (svga->crtc[0x21] & 0x20) { mem_mapping_disable(&svga->mapping); mem_mapping_set_addr(&tgui->linear_mapping, tgui->linear_base, tgui->linear_size); svga->linear_base = tgui->linear_base; -// pclog("Trident linear framebuffer at %08X - size %06X\n", tgui->linear_base, tgui->linear_size); mem_mapping_enable(&tgui->accel_mapping); } else { -// pclog("Write mapping %02X\n", val); mem_mapping_disable(&tgui->linear_mapping); mem_mapping_disable(&tgui->accel_mapping); switch (svga->gdcreg[6] & 0xC) @@ -454,7 +437,6 @@ void tgui_hwcursor_draw(svga_t *svga, int displine) ((uint32_t *)buffer32->line[displine + y_add])[offset + 32 + x_add] = (dat[1] & 0x80000000) ? 0xffffff : 0; else if (dat[1] & 0x80000000) ((uint32_t *)buffer32->line[displine + y_add])[offset + 32 + x_add] ^= 0xffffff; -// pclog("Plot %i, %i (%i %i) %04X %04X\n", offset, displine, x+xx, svga_hwcursor_on, dat[0], dat[1]); } offset++; @@ -467,9 +449,6 @@ void tgui_hwcursor_draw(svga_t *svga, int displine) uint8_t tgui_pci_read(int func, int addr, void *p) { tgui_t *tgui = (tgui_t *)p; - svga_t *svga = &tgui->svga; - -// pclog("Trident PCI read %08X\n", addr); switch (addr) { @@ -507,8 +486,6 @@ void tgui_pci_write(int func, int addr, uint8_t val, void *p) tgui_t *tgui = (tgui_t *)p; svga_t *svga = &tgui->svga; -// pclog("Trident PCI write %08X %02X\n", addr, val); - switch (addr) { case 0x12: @@ -534,7 +511,7 @@ void *tgui9440_init() tgui->vram_size = device_get_config_int("memory") << 20; tgui->vram_mask = tgui->vram_size - 1; - rom_init(&tgui->bios_rom, "roms/9440.vbi", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + rom_init(&tgui->bios_rom, L"roms/9440.vbi", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); svga_init(&tgui->svga, tgui, tgui->vram_size, tgui_recalctimings, @@ -560,7 +537,7 @@ void *tgui9440_init() static int tgui9440_available() { - return rom_present("roms/9440.vbi"); + return rom_present(L"roms/9440.vbi"); } void tgui_close(void *p) @@ -569,6 +546,10 @@ void tgui_close(void *p) svga_close(&tgui->svga); + thread_kill(tgui->fifo_thread); + thread_destroy_event(tgui->wake_fifo_thread); + thread_destroy_event(tgui->fifo_not_full_event); + free(tgui); } @@ -658,7 +639,6 @@ void tgui_accel_command(int count, uint32_t cpu_dat, tgui_t *tgui) } if (tgui->accel.flags & TGUI_SOLIDFILL) { -// pclog("SOLIDFILL\n"); for (y = 0; y < 8; y++) { for (x = 0; x < 8; x++) @@ -669,7 +649,6 @@ void tgui_accel_command(int count, uint32_t cpu_dat, tgui_t *tgui) } else if (tgui->accel.flags & TGUI_PATMONO) { -// pclog("PATMONO\n"); for (y = 0; y < 8; y++) { for (x = 0; x < 8; x++) @@ -682,7 +661,6 @@ void tgui_accel_command(int count, uint32_t cpu_dat, tgui_t *tgui) { if (tgui->accel.bpp == 0) { -// pclog("OTHER 8-bit\n"); for (y = 0; y < 8; y++) { for (x = 0; x < 8; x++) @@ -693,7 +671,6 @@ void tgui_accel_command(int count, uint32_t cpu_dat, tgui_t *tgui) } else { -// pclog("OTHER 16-bit\n"); for (y = 0; y < 8; y++) { for (x = 0; x < 8; x++) @@ -703,15 +680,9 @@ void tgui_accel_command(int count, uint32_t cpu_dat, tgui_t *tgui) } } } -/* for (y = 0; y < 8; y++) - { - if (count == -1) pclog("Pattern %i : %02X %02X %02X %02X %02X %02X %02X %02X\n", y, tgui->accel.tgui_pattern[y][0], tgui->accel.tgui_pattern[y][1], tgui->accel.tgui_pattern[y][2], tgui->accel.tgui_pattern[y][3], tgui->accel.tgui_pattern[y][4], tgui->accel.tgui_pattern[y][5], tgui->accel.tgui_pattern[y][6], tgui->accel.tgui_pattern[y][7]); - }*/ -// if (count == -1) pclog("Command %i %i %p\n", tgui->accel.command, TGUI_BITBLT, tgui); switch (tgui->accel.command) { case TGUI_BITBLT: -// if (count == -1) pclog("BITBLT src %i,%i dst %i,%i size %i,%i flags %04X\n", tgui->accel.src_x, tgui->accel.src_y, tgui->accel.dst_x, tgui->accel.dst_y, tgui->accel.size_x, tgui->accel.size_y, tgui->accel.flags); if (count == -1) { tgui->accel.src = tgui->accel.src_old = tgui->accel.src_x + (tgui->accel.src_y * tgui->accel.pitch); @@ -725,7 +696,6 @@ void tgui_accel_command(int count, uint32_t cpu_dat, tgui_t *tgui) case TGUI_SRCCPU: if (count == -1) { -// pclog("Blit start TGUI_SRCCPU\n"); if (svga->crtc[0x21] & 0x20) mem_mapping_set_handler(&tgui->linear_mapping, svga_read_linear, svga_readw_linear, svga_readl_linear, tgui_accel_write_fb_b, tgui_accel_write_fb_w, tgui_accel_write_fb_l); @@ -734,7 +704,6 @@ void tgui_accel_command(int count, uint32_t cpu_dat, tgui_t *tgui) } else count >>= 3; -// pclog("TGUI_SRCCPU\n"); while (count) { if (tgui->accel.bpp == 0) @@ -758,8 +727,6 @@ void tgui_accel_command(int count, uint32_t cpu_dat, tgui_t *tgui) WRITE(tgui->accel.dst, out); } -// pclog(" %i,%i %02X %02X %02X %02X\n", tgui->accel.x, tgui->accel.y, src_dat,dst_dat,pat_dat, out); - tgui->accel.src += xdir; tgui->accel.dst += xdir; tgui->accel.pat_x += xdir; @@ -780,7 +747,6 @@ void tgui_accel_command(int count, uint32_t cpu_dat, tgui_t *tgui) { if (svga->crtc[0x21] & 0x20) { -// pclog("Blit end\n"); mem_mapping_set_handler(&tgui->linear_mapping, svga_read_linear, svga_readw_linear, svga_readl_linear, svga_write_linear, svga_writew_linear, svga_writel_linear); } return; @@ -795,15 +761,12 @@ void tgui_accel_command(int count, uint32_t cpu_dat, tgui_t *tgui) case TGUI_SRCMONO | TGUI_SRCCPU: if (count == -1) { -// pclog("Blit start TGUI_SRCMONO | TGUI_SRCCPU\n"); if (svga->crtc[0x21] & 0x20) mem_mapping_set_handler(&tgui->linear_mapping, svga_read_linear, svga_readw_linear, svga_readl_linear, tgui_accel_write_fb_b, tgui_accel_write_fb_w, tgui_accel_write_fb_l); -// pclog(" %i\n", tgui->accel.command); if (tgui->accel.use_src) return; } -// pclog("TGUI_SRCMONO | TGUI_SRCCPU\n"); while (count) { src_dat = ((cpu_dat >> 31) ? tgui->accel.fg_col : tgui->accel.bg_col); @@ -819,7 +782,6 @@ void tgui_accel_command(int count, uint32_t cpu_dat, tgui_t *tgui) WRITE(tgui->accel.dst, out); } -// pclog(" %i,%i %02X %02X %02X %02X %i\n", tgui->accel.x, tgui->accel.y, src_dat,dst_dat,pat_dat, out, (!(tgui->accel.flags & TGUI_TRANSENA) || src_dat != trans_col)); cpu_dat <<= 1; tgui->accel.src += xdir; tgui->accel.dst += xdir; @@ -841,7 +803,6 @@ void tgui_accel_command(int count, uint32_t cpu_dat, tgui_t *tgui) { if (svga->crtc[0x21] & 0x20) { -// pclog("Blit end\n"); mem_mapping_set_handler(&tgui->linear_mapping, svga_read_linear, svga_readw_linear, svga_readl_linear, svga_write_linear, svga_writew_linear, svga_writel_linear); } return; @@ -866,7 +827,6 @@ void tgui_accel_command(int count, uint32_t cpu_dat, tgui_t *tgui) WRITE(tgui->accel.dst, out); } -// pclog(" %i,%i %02X %02X %02X %02X\n", tgui->accel.x, tgui->accel.y, src_dat,dst_dat,pat_dat, out); tgui->accel.src += xdir; tgui->accel.dst += xdir; @@ -914,7 +874,6 @@ static void tgui_accel_write_fifo(tgui_t *tgui, uint32_t addr, uint8_t val) case 0x27: /*ROP*/ tgui->accel.rop = val; tgui->accel.use_src = (val & 0x33) ^ ((val >> 2) & 0x33); -// pclog("Write ROP %02X %i\n", val, tgui->accel.use_src); break; case 0x28: /*Flags*/ @@ -1034,6 +993,9 @@ static void tgui_accel_write_fifo_fb_l(tgui_t *tgui, uint32_t addr, uint32_t val static void fifo_thread(void *param) { tgui_t *tgui = (tgui_t *)param; + uint64_t start_time; + uint64_t end_time; + fifo_entry_t *fifo; while (1) { @@ -1043,10 +1005,8 @@ static void fifo_thread(void *param) tgui->blitter_busy = 1; while (!FIFO_EMPTY) { - uint64_t start_time = timer_read(); - uint64_t end_time; - fifo_entry_t *fifo = &tgui->fifo[tgui->fifo_read_idx & FIFO_MASK]; - uint32_t val = fifo->val; + start_time = timer_read(); + fifo = &tgui->fifo[tgui->fifo_read_idx & FIFO_MASK]; switch (fifo->addr_type & FIFO_TYPE) { @@ -1077,7 +1037,7 @@ static void fifo_thread(void *param) } } -static inline void wake_fifo_thread(tgui_t *tgui) +static __inline void wake_fifo_thread(tgui_t *tgui) { thread_set_event(tgui->wake_fifo_thread); /*Wake up FIFO thread if moving from idle*/ } @@ -1094,7 +1054,6 @@ static void tgui_wait_fifo_idle(tgui_t *tgui) static void tgui_queue(tgui_t *tgui, uint32_t addr, uint32_t val, uint32_t type) { fifo_entry_t *fifo = &tgui->fifo[tgui->fifo_write_idx & FIFO_MASK]; - int c; if (FIFO_FULL) { @@ -1118,7 +1077,6 @@ static void tgui_queue(tgui_t *tgui, uint32_t addr, uint32_t val, uint32_t type) void tgui_accel_write(uint32_t addr, uint8_t val, void *p) { tgui_t *tgui = (tgui_t *)p; -// pclog("tgui_accel_write : %08X %02X %04X(%08X):%08X %02X\n", addr, val, CS,cs,pc, opcode); if ((addr & ~0xff) != 0xbff00) return; tgui_queue(tgui, addr, val, FIFO_WRITE_BYTE); @@ -1127,7 +1085,6 @@ void tgui_accel_write(uint32_t addr, uint8_t val, void *p) void tgui_accel_write_w(uint32_t addr, uint16_t val, void *p) { tgui_t *tgui = (tgui_t *)p; -// pclog("tgui_accel_write_w %08X %04X\n", addr, val); tgui_accel_write(addr, val, tgui); tgui_accel_write(addr + 1, val >> 8, tgui); } @@ -1135,7 +1092,6 @@ void tgui_accel_write_w(uint32_t addr, uint16_t val, void *p) void tgui_accel_write_l(uint32_t addr, uint32_t val, void *p) { tgui_t *tgui = (tgui_t *)p; -// pclog("tgui_accel_write_l %08X %08X\n", addr, val); tgui_accel_write(addr, val, tgui); tgui_accel_write(addr + 1, val >> 8, tgui); tgui_accel_write(addr + 2, val >> 16, tgui); @@ -1145,7 +1101,6 @@ void tgui_accel_write_l(uint32_t addr, uint32_t val, void *p) uint8_t tgui_accel_read(uint32_t addr, void *p) { tgui_t *tgui = (tgui_t *)p; -// pclog("tgui_accel_read : %08X\n", addr); if ((addr & ~0xff) != 0xbff00) return 0xff; if ((addr & 0xff) != 0x20) @@ -1245,14 +1200,12 @@ uint8_t tgui_accel_read(uint32_t addr, void *p) uint16_t tgui_accel_read_w(uint32_t addr, void *p) { tgui_t *tgui = (tgui_t *)p; -// pclog("tgui_accel_read_w %08X\n", addr); return tgui_accel_read(addr, tgui) | (tgui_accel_read(addr + 1, tgui) << 8); } uint32_t tgui_accel_read_l(uint32_t addr, void *p) { tgui_t *tgui = (tgui_t *)p; -// pclog("tgui_accel_read_l %08X\n", addr); return tgui_accel_read_w(addr, tgui) | (tgui_accel_read_w(addr + 2, tgui) << 16); } @@ -1260,7 +1213,6 @@ void tgui_accel_write_fb_b(uint32_t addr, uint8_t val, void *p) { svga_t *svga = (svga_t *)p; tgui_t *tgui = (tgui_t *)svga->p; -// pclog("tgui_accel_write_fb_b %08X %02X\n", addr, val); tgui_queue(tgui, addr, val, FIFO_WRITE_FB_BYTE); } @@ -1268,7 +1220,6 @@ void tgui_accel_write_fb_w(uint32_t addr, uint16_t val, void *p) { svga_t *svga = (svga_t *)p; tgui_t *tgui = (tgui_t *)svga->p; -// pclog("tgui_accel_write_fb_w %08X %04X\n", addr, val); tgui_queue(tgui, addr, val, FIFO_WRITE_FB_WORD); } @@ -1276,7 +1227,6 @@ void tgui_accel_write_fb_l(uint32_t addr, uint32_t val, void *p) { svga_t *svga = (svga_t *)p; tgui_t *tgui = (tgui_t *)svga->p; -// pclog("tgui_accel_write_fb_l %08X %08X\n", addr, val); tgui_queue(tgui, addr, val, FIFO_WRITE_FB_LONG); } @@ -1299,27 +1249,21 @@ void tgui_add_status_info(char *s, int max_len, void *p) static device_config_t tgui9440_config[] = { { - .name = "memory", - .description = "Memory size", - .type = CONFIG_SELECTION, - .selection = + "memory", "Memory size", CONFIG_SELECTION, "", 2, { { - .description = "1 MB", - .value = 1 + "1 MB", 1 }, { - .description = "2 MB", - .value = 2 + "2 MB", 2 }, { - .description = "" + "" } - }, - .default_int = 2 + } }, { - .type = -1 + "", "", -1 } }; diff --git a/src/vid_tgui9440.h b/src/VIDEO/vid_tgui9440.h similarity index 100% rename from src/vid_tgui9440.h rename to src/VIDEO/vid_tgui9440.h diff --git a/src/vid_tkd8001_ramdac.c b/src/VIDEO/vid_tkd8001_ramdac.c similarity index 85% rename from src/vid_tkd8001_ramdac.c rename to src/VIDEO/vid_tkd8001_ramdac.c index de75edaaa..553bc489f 100644 --- a/src/vid_tkd8001_ramdac.c +++ b/src/VIDEO/vid_tkd8001_ramdac.c @@ -2,18 +2,15 @@ see COPYING for more details */ /*Trident TKD8001 RAMDAC emulation*/ -#include "ibm.h" -#include "mem.h" +#include "../ibm.h" +#include "../mem.h" #include "video.h" #include "vid_svga.h" #include "vid_tkd8001_ramdac.h" -static int tkd8001_state=0; -static uint8_t tkd8001_ctrl; void tkd8001_ramdac_out(uint16_t addr, uint8_t val, tkd8001_ramdac_t *ramdac, svga_t *svga) { -// pclog("OUT RAMDAC %04X %02X %04X:%04X\n",addr,val,CS,pc); switch (addr) { case 0x3C6: @@ -38,7 +35,6 @@ void tkd8001_ramdac_out(uint16_t addr, uint8_t val, tkd8001_ramdac_t *ramdac, sv } return; } - // tkd8001_state = 0; break; case 0x3C7: case 0x3C8: case 0x3C9: ramdac->state = 0; @@ -49,13 +45,11 @@ void tkd8001_ramdac_out(uint16_t addr, uint8_t val, tkd8001_ramdac_t *ramdac, sv uint8_t tkd8001_ramdac_in(uint16_t addr, tkd8001_ramdac_t *ramdac, svga_t *svga) { -// pclog("IN RAMDAC %04X %04X:%04X\n",addr,CS,pc); switch (addr) { case 0x3C6: if (ramdac->state == 4) { - //tkd8001_state = 0; return ramdac->ctrl; } ramdac->state++; diff --git a/src/vid_tkd8001_ramdac.h b/src/VIDEO/vid_tkd8001_ramdac.h similarity index 100% rename from src/vid_tkd8001_ramdac.h rename to src/VIDEO/vid_tkd8001_ramdac.h diff --git a/src/vid_tvga.c b/src/VIDEO/vid_tvga.c similarity index 86% rename from src/vid_tvga.c rename to src/VIDEO/vid_tvga.c index f5fa8f4bb..7c6c7f255 100644 --- a/src/vid_tvga.c +++ b/src/VIDEO/vid_tvga.c @@ -3,17 +3,18 @@ */ /*Trident TVGA (8900D) emulation*/ #include -#include "ibm.h" -#include "device.h" -#include "io.h" -#include "mem.h" -#include "rom.h" +#include "../ibm.h" +#include "../io.h" +#include "../mem.h" +#include "../rom.h" +#include "../device.h" #include "video.h" #include "vid_svga.h" #include "vid_svga_render.h" #include "vid_tkd8001_ramdac.h" #include "vid_tvga.h" + typedef struct tvga_t { mem_mapping_t linear_mapping; @@ -53,7 +54,6 @@ void tvga_out(uint16_t addr, uint8_t val, void *p) uint8_t old; -// pclog("tvga_out : %04X %02X %04X:%04X %i\n", addr, val, CS,pc, svga->bpp); if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga->miscout & 1)) addr ^= 0x60; switch (addr) @@ -119,7 +119,6 @@ void tvga_out(uint16_t addr, uint8_t val, void *p) old = svga->crtc[svga->crtcreg]; val &= crtc_mask[svga->crtcreg]; svga->crtc[svga->crtcreg] = val; -// if (svga->crtcreg != 0xC && svga->crtcreg != 0xE && svga->crtcreg != 0xF) pclog("CRTC R%02X = %02X %04X:%04X\n", svga->crtcreg, val, CS, pc); if (old != val) { if (svga->crtcreg < 0xE || svga->crtcreg > 0x10) @@ -158,8 +157,6 @@ uint8_t tvga_in(uint16_t addr, void *p) tvga_t *tvga = (tvga_t *)p; svga_t *svga = &tvga->svga; -// if (addr != 0x3da) pclog("tvga_in : %04X %04X:%04X\n", addr, CS,pc); - if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga->miscout & 1)) addr ^= 0x60; switch (addr) @@ -167,15 +164,9 @@ uint8_t tvga_in(uint16_t addr, void *p) case 0x3C5: if ((svga->seqaddr & 0xf) == 0xb) { -// printf("Read Trident ID %04X:%04X %04X\n",CS,pc,readmemw(ss,SP)); tvga->oldmode = 0; return 0x33; /*TVGA8900D*/ } - if ((svga->seqaddr & 0xf) == 0xc) - { -// printf("Read Trident Power Up 1 %04X:%04X %04X\n",CS,pc,readmemw(ss,SP)); -// return 0x20; /*2 DRAM banks*/ - } if ((svga->seqaddr & 0xf) == 0xd) { if (tvga->oldmode) return tvga->oldctrl2; @@ -213,8 +204,6 @@ static void tvga_recalcbanking(tvga_t *tvga) svga->read_bank = (tvga->tvga_3d9 & 0x1f) * 65536; else svga->read_bank = svga->write_bank; - -// pclog("recalcbanking: write_bank=%08x read_bank=%08x GDC[E]=%02x GDC[F]=%02x SEQ[E]=%02x 3d8=%02x 3d9=%02x\n", svga->read_bank, svga->write_bank, svga->gdcreg[0xe], svga->gdcreg[0xf], svga->seqregs[0xe], tvga->tvga_3d8, tvga->tvga_3d9); } void tvga_recalctimings(svga_t *svga) @@ -245,7 +234,6 @@ void tvga_recalctimings(svga_t *svga) svga->hdisp_time *= 2; } - // svga->interlace = svga->crtc[0x1e] & 4; if (svga->crtc[0x1e] & 4) { svga->rowoffset >>= 1; @@ -298,7 +286,7 @@ void *tvga8900d_init() tvga->vram_size = device_get_config_int("memory") << 10; tvga->vram_mask = tvga->vram_size - 1; - rom_init(&tvga->bios_rom, "roms/TRIDENT.BIN", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + rom_init(&tvga->bios_rom, L"roms/TRIDENT.BIN", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); svga_init(&tvga->svga, tvga, tvga->vram_size, tvga_recalctimings, @@ -313,7 +301,7 @@ void *tvga8900d_init() static int tvga8900d_available() { - return rom_present("roms/TRIDENT.BIN"); + return rom_present(L"roms/TRIDENT.BIN"); } void tvga_close(void *p) @@ -349,32 +337,25 @@ void tvga_add_status_info(char *s, int max_len, void *p) static device_config_t tvga_config[] = { { - .name = "memory", - .description = "Memory size", - .type = CONFIG_SELECTION, - .selection = + "memory", "Memory size", CONFIG_SELECTION, "", 1024, { { - .description = "256 kB", - .value = 256 + "256 kB", 256 }, { - .description = "512 kB", - .value = 512 + "512 kB", 512 }, { - .description = "1 MB", - .value = 1024 + "1 MB", 1024 }, /*Chip supports 2mb, but drivers are buggy*/ { - .description = "" + "" } - }, - .default_int = 1024 + } }, { - .type = -1 + "", "", -1 } }; diff --git a/src/vid_tvga.h b/src/VIDEO/vid_tvga.h similarity index 100% rename from src/vid_tvga.h rename to src/VIDEO/vid_tvga.h diff --git a/src/vid_unk_ramdac.c b/src/VIDEO/vid_unk_ramdac.c similarity index 91% rename from src/vid_unk_ramdac.c rename to src/VIDEO/vid_unk_ramdac.c index cc57b3bb5..c2fb35bae 100644 --- a/src/vid_unk_ramdac.c +++ b/src/VIDEO/vid_unk_ramdac.c @@ -5,15 +5,15 @@ It is possibly a Sierra 1502x It's addressed by the TLIVESA1 driver for ET4000*/ /* Note by Tenshi: Not possibly, this *IS* a Sierra 1502x. */ -#include "ibm.h" -#include "mem.h" +#include "../ibm.h" +#include "../mem.h" #include "video.h" #include "vid_svga.h" #include "vid_unk_ramdac.h" + void unk_ramdac_out(uint16_t addr, uint8_t val, unk_ramdac_t *ramdac, svga_t *svga) { - // pclog("OUT RAMDAC %04X %02X\n",addr,val); int oldbpp = 0; switch (addr) { @@ -63,7 +63,6 @@ void unk_ramdac_out(uint16_t addr, uint8_t val, unk_ramdac_t *ramdac, svga_t *sv { svga_recalctimings(svga); } - // pclog("unk_ramdac: set to %02X (b5 = %i) [%02X], %i bpp\n", (val&1)|((val&0xC0)>>5), val & 0x20 ? 1 : 0, val, svga->bpp); return; } ramdac->state = 0; @@ -77,7 +76,6 @@ void unk_ramdac_out(uint16_t addr, uint8_t val, unk_ramdac_t *ramdac, svga_t *sv uint8_t unk_ramdac_in(uint16_t addr, unk_ramdac_t *ramdac, svga_t *svga) { - // pclog("IN RAMDAC %04X\n",addr); switch (addr) { case 0x3C6: diff --git a/src/vid_unk_ramdac.h b/src/VIDEO/vid_unk_ramdac.h similarity index 100% rename from src/vid_unk_ramdac.h rename to src/VIDEO/vid_unk_ramdac.h diff --git a/src/vid_vga.c b/src/VIDEO/vid_vga.c similarity index 88% rename from src/vid_vga.c rename to src/VIDEO/vid_vga.c index 3ad87e4bc..e1570b3c4 100644 --- a/src/vid_vga.c +++ b/src/VIDEO/vid_vga.c @@ -3,15 +3,16 @@ */ /*IBM VGA emulation*/ #include -#include "ibm.h" -#include "device.h" -#include "io.h" -#include "mem.h" -#include "rom.h" +#include "../ibm.h" +#include "../io.h" +#include "../mem.h" +#include "../rom.h" +#include "../device.h" #include "video.h" #include "vid_svga.h" #include "vid_vga.h" + typedef struct vga_t { svga_t svga; @@ -24,9 +25,7 @@ void vga_out(uint16_t addr, uint8_t val, void *p) vga_t *vga = (vga_t *)p; svga_t *svga = &vga->svga; uint8_t old; - -// pclog("vga_out : %04X %02X %04X:%04X %02X %i\n", addr, val, CS,pc, ram[0x489], ins); - + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) addr ^= 0x60; @@ -63,8 +62,6 @@ uint8_t vga_in(uint16_t addr, void *p) svga_t *svga = &vga->svga; uint8_t temp; -// if (addr != 0x3da) pclog("vga_in : %04X ", addr); - if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) addr ^= 0x60; @@ -80,7 +77,6 @@ uint8_t vga_in(uint16_t addr, void *p) temp = svga_in(addr, svga); break; } -// if (addr != 0x3da) pclog("%02X %04X:%04X\n", temp, CS,pc); return temp; } @@ -89,7 +85,7 @@ void *vga_init() vga_t *vga = malloc(sizeof(vga_t)); memset(vga, 0, sizeof(vga_t)); - rom_init(&vga->bios_rom, "roms/ibm_vga.bin", 0xc0000, 0x8000, 0x7fff, 0x2000, MEM_MAPPING_EXTERNAL); + rom_init(&vga->bios_rom, L"roms/ibm_vga.bin", 0xc0000, 0x8000, 0x7fff, 0x2000, MEM_MAPPING_EXTERNAL); svga_init(&vga->svga, vga, 1 << 18, /*256kb*/ NULL, @@ -105,12 +101,13 @@ void *vga_init() return vga; } +#ifdef DEV_BRANCH void *trigem_unk_init() { vga_t *vga = malloc(sizeof(vga_t)); memset(vga, 0, sizeof(vga_t)); - rom_init(&vga->bios_rom, "roms/ibm_vga.bin", 0xc0000, 0x8000, 0x7fff, 0x2000, MEM_MAPPING_EXTERNAL); + rom_init(&vga->bios_rom, L"roms/ibm_vga.bin", 0xc0000, 0x8000, 0x7fff, 0x2000, MEM_MAPPING_EXTERNAL); svga_init(&vga->svga, vga, 1 << 18, /*256kb*/ NULL, @@ -129,6 +126,7 @@ void *trigem_unk_init() return vga; } +#endif /*PS/1 uses a standard VGA controller, but with no option ROM*/ void *ps1vga_init() @@ -152,7 +150,7 @@ void *ps1vga_init() static int vga_available() { - return rom_present("roms/ibm_vga.bin"); + return rom_present(L"roms/ibm_vga.bin"); } void vga_close(void *p) @@ -196,6 +194,7 @@ device_t vga_device = vga_force_redraw, vga_add_status_info }; +#ifdef DEV_BRANCH device_t trigem_unk_device = { "VGA", @@ -207,6 +206,7 @@ device_t trigem_unk_device = vga_force_redraw, vga_add_status_info }; +#endif device_t ps1vga_device = { "PS/1 VGA", diff --git a/src/vid_vga.h b/src/VIDEO/vid_vga.h similarity index 100% rename from src/vid_vga.h rename to src/VIDEO/vid_vga.h diff --git a/src/vid_voodoo.c b/src/VIDEO/vid_voodoo.c similarity index 93% rename from src/vid_voodoo.c rename to src/VIDEO/vid_voodoo.c index d84de678d..042e88a42 100644 --- a/src/vid_voodoo.c +++ b/src/VIDEO/vid_voodoo.c @@ -1,16 +1,29 @@ #include #include -#include "ibm.h" -#include "device.h" -#include "mem.h" -#include "pci.h" -#include "thread.h" -#include "timer.h" +#include +#include "../ibm.h" +#include "../cpu/cpu.h" +#include "../mem.h" +#include "../rom.h" +#include "../pci.h" +#include "../timer.h" +#include "../device.h" +#include "../win/plat_thread.h" #include "video.h" #include "vid_svga.h" #include "vid_voodoo.h" #include "vid_voodoo_dither.h" +#ifdef MIN +#undef MIN +#endif +#ifdef ABS +#undef ABS +#endif +#ifdef CLAMP +#undef CLAMP +#endif + #define MIN(a, b) ((a) < (b) ? (a) : (b)) #define CLAMP(x) (((x) < 0) ? 0 : (((x) > 0xff) ? 0xff : (x))) @@ -49,7 +62,6 @@ static int tris = 0; static uint64_t status_time = 0; static uint64_t voodoo_time = 0; static int voodoo_render_time[2] = {0, 0}; -static int voodoo_render_time_old[2] = {0, 0}; typedef union int_float { @@ -160,13 +172,13 @@ typedef struct voodoo_params_t uint32_t texBaseAddr[2], texBaseAddr1[2], texBaseAddr2[2], texBaseAddr38[2]; - uint32_t tex_base[2][LOD_MAX+1]; + uint32_t tex_base[2][LOD_MAX+2]; int tex_width[2]; - int tex_w_mask[2][LOD_MAX+1]; - int tex_w_nmask[2][LOD_MAX+1]; - int tex_h_mask[2][LOD_MAX+1]; - int tex_shift[2][LOD_MAX+1]; - int tex_lod[2][LOD_MAX+1]; + int tex_w_mask[2][LOD_MAX+2]; + int tex_w_nmask[2][LOD_MAX+2]; + int tex_h_mask[2][LOD_MAX+2]; + int tex_shift[2][LOD_MAX+2]; + int tex_lod[2][LOD_MAX+2]; int tex_entry[2]; int detail_max[2], detail_bias[2], detail_scale[2]; @@ -181,6 +193,8 @@ typedef struct voodoo_params_t uint32_t front_offset; uint32_t swapbufferCMD; + + uint32_t stipple; } voodoo_params_t; typedef struct texture_t @@ -190,6 +204,7 @@ typedef struct texture_t volatile int refcount, refcount_r[2]; int is16; uint32_t palette_checksum; + uint32_t addr_start, addr_end; uint32_t *data; } texture_t; @@ -382,7 +397,7 @@ typedef struct voodoo_t uint8_t thefilterb[256][256]; // for blue /* the voodoo adds purple lines for some reason */ - uint16_t purpleline[1024]; + uint16_t purpleline[256][3]; texture_t texture_cache[2][TEX_CACHE_MAX]; uint8_t texture_present[2][4096]; @@ -493,7 +508,7 @@ enum SST_chromaKey = 0x134, SST_userIntrCMD = 0x13c, - + SST_stipple = 0x140, SST_color0 = 0x144, SST_color1 = 0x148, @@ -545,7 +560,7 @@ enum SST_cmdFifoHoles = 0x1f8, SST_fbiInit4 = 0x200, - + SST_vRetrace = 0x204, SST_backPorch = 0x208, SST_videoDimensions = 0x20c, SST_fbiInit0 = 0x210, @@ -730,6 +745,7 @@ enum LFB_FORMAT_RGB565 = 0, LFB_FORMAT_RGB555 = 1, LFB_FORMAT_ARGB1555 = 2, + LFB_FORMAT_XRGB8888 = 4, LFB_FORMAT_ARGB8888 = 5, LFB_FORMAT_DEPTH = 15, LFB_FORMAT_MASK = 15 @@ -963,8 +979,8 @@ enum enum { - BLTCMD_SRC_TILED = (1 << 10), - BLTCMD_DST_TILED = (1 << 12) + BLTCMD_SRC_TILED = (1 << 14), + BLTCMD_DST_TILED = (1 << 15) }; #define TEXTUREMODE_MASK 0x3ffff000 @@ -986,10 +1002,8 @@ static void voodoo_update_ncc(voodoo_t *voodoo, int tmu) for (col = 0; col < 256; col++) { int y = (col >> 4), i = (col >> 2) & 3, q = col & 3; - int _y = (col >> 4), _i = (col >> 2) & 3, _q = col & 3; int i_r, i_g, i_b; int q_r, q_g, q_b; - int r, g, b; y = (voodoo->nccTable[tmu][tbl].y[y >> 2] >> ((y & 3) * 8)) & 0xff; @@ -1085,7 +1099,9 @@ static void voodoo_recalc(voodoo_t *voodoo) voodoo->block_width = ((voodoo->fbiInit1 >> 4) & 15) * 2; if (voodoo->fbiInit6 & (1 << 30)) - voodoo->fbiInit1 += 1; + voodoo->block_width += 1; + if (voodoo->fbiInit1 & (1 << 24)) + voodoo->block_width += 32; voodoo->row_width = voodoo->block_width * 32 * 2; /* pclog("voodoo_recalc : front_offset %08X back_offset %08X aux_offset %08X draw_offset %08x\n", voodoo->params.front_offset, voodoo->back_offset, voodoo->params.aux_offset, voodoo->params.draw_offset); @@ -1098,8 +1114,6 @@ static void voodoo_recalc_tex(voodoo_t *voodoo, int tmu) int width = 256, height = 256; int shift = 8; int lod; - int lod_min = (voodoo->params.tLOD[tmu] >> 2) & 15; - int lod_max = (voodoo->params.tLOD[tmu] >> 8) & 15; uint32_t base = voodoo->params.texBaseAddr[tmu]; int tex_lod = 0; @@ -1119,7 +1133,7 @@ static void voodoo_recalc_tex(voodoo_t *voodoo, int tmu) tex_lod++; } - for (lod = 0; lod <= LOD_MAX; lod++) + for (lod = 0; lod <= LOD_MAX+1; lod++) { if (!width) width = 1; @@ -1466,8 +1480,10 @@ static void use_texture(voodoo_t *voodoo, voodoo_params_t *params, int tmu) else voodoo->texture_cache[tmu][c].palette_checksum = 0; - addr = voodoo->texture_cache[tmu][c].base + texture_offset[lod_min] * (voodoo->texture_cache[tmu][c].is16 ? 2 : 1); - addr_end = voodoo->texture_cache[tmu][c].base + texture_offset[lod_max+1] * (voodoo->texture_cache[tmu][c].is16 ? 2 : 1); + addr = voodoo->params.tex_base[tmu][lod_min]; + addr_end = voodoo->params.tex_base[tmu][lod_max+1]; + voodoo->texture_cache[tmu][c].addr_start = addr; + voodoo->texture_cache[tmu][c].addr_end = addr_end; for (; addr <= addr_end; addr += (1 << TEX_DIRTY_SHIFT)) voodoo->texture_present[tmu][(addr & voodoo->texture_mask) >> TEX_DIRTY_SHIFT] = 1; @@ -1486,10 +1502,8 @@ static void flush_texture_cache(voodoo_t *voodoo, uint32_t dirty_addr, int tmu) { if (voodoo->texture_cache[tmu][c].base != -1) { - int lod_min = (voodoo->texture_cache[tmu][c].tLOD >> 2) & 15; - int lod_max = (voodoo->texture_cache[tmu][c].tLOD >> 8) & 15; - int addr_start = voodoo->texture_cache[tmu][c].base + texture_offset[lod_min] * (voodoo->texture_cache[tmu][c].is16 ? 2 : 1); - int addr_end = voodoo->texture_cache[tmu][c].base + texture_offset[lod_max+1] * (voodoo->texture_cache[tmu][c].is16 ? 2 : 1); + int addr_start = voodoo->texture_cache[tmu][c].addr_start; + int addr_end = voodoo->texture_cache[tmu][c].addr_end; if (dirty_addr >= (addr_start & voodoo->texture_mask & ~0x3ff) && dirty_addr < (((addr_end & voodoo->texture_mask) + 0x3ff) & ~0x3ff)) { @@ -1636,7 +1650,7 @@ static inline int fastlog(uint64_t val) return (exp << 8) | logtable[frac]; } -static inline int fls(uint16_t val) +static inline int voodoo_fls(uint16_t val) { int num = 0; @@ -1767,7 +1781,6 @@ static inline void tex_read_4(voodoo_state_t *state, voodoo_texture_state_t *tex static inline void voodoo_get_texture(voodoo_t *voodoo, voodoo_params_t *params, voodoo_state_t *state, int tmu, int x) { - rgba_u tex_samples[4]; voodoo_texture_state_t texture_state; int d[4]; int s, t; @@ -1964,7 +1977,7 @@ static inline void voodoo_tmu_fetch(voodoo_t *voodoo, voodoo_params_t *params, v } \ else \ { \ - int fog_r, fog_g, fog_b, fog_a; \ + int fog_r, fog_g, fog_b, fog_a = 0; \ int fog_idx; \ \ if (!(params->fogMode & FOG_ADD)) \ @@ -2085,7 +2098,7 @@ static inline void voodoo_tmu_fetch(voodoo_t *voodoo, voodoo_params_t *params, v do \ { \ int _a; \ - int newdest_r, newdest_g, newdest_b; \ + int newdest_r = 0, newdest_g = 0, newdest_b = 0; \ \ switch (dest_afunc) \ { \ @@ -2240,12 +2253,12 @@ static inline void voodoo_tmu_fetch(voodoo_t *voodoo, voodoo_params_t *params, v #define dither2x2 (params->fbzMode & FBZ_DITHER_2x2) /*Perform texture fetch and blending for both TMUs*/ -static inline voodoo_tmu_fetch_and_blend(voodoo_t *voodoo, voodoo_params_t *params, voodoo_state_t *state, int x) +static inline void voodoo_tmu_fetch_and_blend(voodoo_t *voodoo, voodoo_params_t *params, voodoo_state_t *state, int x) { int r,g,b,a; int c_reverse, a_reverse; - int c_reverse1, a_reverse1; - int factor_r, factor_g, factor_b, factor_a; +// int c_reverse1, a_reverse1; + int factor_r = 0, factor_g = 0, factor_b = 0, factor_a = 0; voodoo_tmu_fetch(voodoo, params, state, 1, x); @@ -2259,8 +2272,8 @@ static inline voodoo_tmu_fetch_and_blend(voodoo_t *voodoo, voodoo_params_t *para c_reverse = !tc_reverse_blend; a_reverse = !tca_reverse_blend; } - c_reverse1 = c_reverse; - a_reverse1 = a_reverse; +/* c_reverse1 = c_reverse; + a_reverse1 = a_reverse;*/ if (tc_sub_clocal_1) { switch (tc_mselect_1) @@ -2582,6 +2595,8 @@ static void voodoo_half_triangle(voodoo_t *voodoo, voodoo_params_t *params, vood #ifndef NO_CODEGEN if (voodoo->use_recompiler) voodoo_draw = voodoo_get_block(voodoo, params, state, odd_even); + else + voodoo_draw = NULL; #endif if (voodoo_output) @@ -2651,7 +2666,7 @@ static void voodoo_half_triangle(voodoo_t *voodoo, voodoo_params_t *params, vood state->w += (params->dWdX * dx); if (voodoo_output) - pclog("%08llx %lli %lli\n", state->tmu0_t, state->tmu0_t >> (18+state->lod), (state->tmu0_t + (1 << 17+state->lod)) >> (18+state->lod)); + pclog("%08llx %lli %lli\n", state->tmu0_t, state->tmu0_t >> (18+state->lod), (state->tmu0_t + (1 << (17+state->lod))) >> (18+state->lod)); if (params->fbzMode & 1) { @@ -2710,8 +2725,8 @@ static void voodoo_half_triangle(voodoo_t *voodoo, voodoo_params_t *params, vood if (x2 > x && state->xdir < 0) goto next_line; - state->fb_mem = fb_mem = &voodoo->fb_mem[params->draw_offset + (real_y * voodoo->row_width)]; - state->aux_mem = aux_mem = &voodoo->fb_mem[params->aux_offset + (real_y * voodoo->row_width)]; + state->fb_mem = fb_mem = (uint16_t *)&voodoo->fb_mem[params->draw_offset + (real_y * voodoo->row_width)]; + state->aux_mem = aux_mem = (uint16_t *)&voodoo->fb_mem[(params->aux_offset + (real_y * voodoo->row_width)) & voodoo->fb_mask]; if (voodoo_output) pclog("%03i: x=%08x x2=%08x xstart=%08x xend=%08x dx=%08x start_x2=%08x\n", state->y, x, x2, state->xstart, state->xend, dx, start_x2); @@ -2743,11 +2758,10 @@ static void voodoo_half_triangle(voodoo_t *voodoo, voodoo_params_t *params, vood int update = 1; uint8_t cother_r, cother_g, cother_b, aother; uint8_t clocal_r, clocal_g, clocal_b, alocal; - int src_r, src_g, src_b, src_a; + int src_r = 0, src_g = 0, src_b = 0, src_a = 0; int msel_r, msel_g, msel_b, msel_a; uint8_t dest_r, dest_g, dest_b, dest_a; uint16_t dat; - uint16_t aux_dat; int sel; int32_t new_depth, w_depth; @@ -2757,7 +2771,7 @@ static void voodoo_half_triangle(voodoo_t *voodoo, voodoo_params_t *params, vood w_depth = 0xf001; else { - int exp = fls((uint16_t)((uint32_t)state->w >> 16)); + int exp = voodoo_fls((uint16_t)((uint32_t)state->w >> 16)); int mant = ((~(uint32_t)state->w >> (19 - exp))) & 0xfff; w_depth = (exp << 12) + mant + 1; if (w_depth > 0xffff) @@ -3097,7 +3111,7 @@ static void voodoo_half_triangle(voodoo_t *voodoo, voodoo_params_t *params, vood if (params->fbzMode & FBZ_RGB_WMASK) fb_mem[x] = src_b | (src_g << 5) | (src_r << 11); - if (params->fbzMode & FBZ_DEPTH_WMASK) + if ((params->fbzMode & (FBZ_DEPTH_WMASK | FBZ_DEPTH_ENABLE)) == (FBZ_DEPTH_WMASK | FBZ_DEPTH_ENABLE)) aux_mem[x] = new_depth; } } @@ -3169,7 +3183,6 @@ static void voodoo_triangle(voodoo_t *voodoo, voodoo_params_t *params, int odd_e { voodoo_state_t state; int vertexAy_adjusted; - int vertexBy_adjusted; int vertexCy_adjusted; int dx, dy; @@ -3245,7 +3258,6 @@ static void voodoo_triangle(voodoo_t *voodoo, voodoo_params_t *params, int odd_e state.vertexCx |= 0xffff0000; vertexAy_adjusted = (state.vertexAy+7) >> 4; - vertexBy_adjusted = (state.vertexBy+7) >> 4; vertexCy_adjusted = (state.vertexCy+7) >> 4; if (state.vertexBy - state.vertexAy) @@ -3408,7 +3420,19 @@ static inline void queue_triangle(voodoo_t *voodoo, voodoo_params_t *params) static void voodoo_fastfill(voodoo_t *voodoo, voodoo_params_t *params) { int y; + int low_y, high_y; + if (params->fbzMode & (1 << 17)) + { + high_y = voodoo->v_disp - params->clipLowY; + low_y = voodoo->v_disp - params->clipHighY; + } + else + { + low_y = params->clipLowY; + high_y = params->clipHighY; + } + if (params->fbzMode & FBZ_RGB_WMASK) { int r, g, b; @@ -3419,7 +3443,7 @@ static void voodoo_fastfill(voodoo_t *voodoo, voodoo_params_t *params) b = (params->color1 >> 3) & 0x1f; col = b | (g << 5) | (r << 11); - for (y = params->clipLowY; y < params->clipHighY; y++) + for (y = low_y; y < high_y; y++) { uint16_t *cbuf = (uint16_t *)&voodoo->fb_mem[(params->draw_offset + y*voodoo->row_width) & voodoo->fb_mask]; int x; @@ -3430,7 +3454,7 @@ static void voodoo_fastfill(voodoo_t *voodoo, voodoo_params_t *params) } if (params->fbzMode & FBZ_DEPTH_WMASK) { - for (y = params->clipLowY; y < params->clipHighY; y++) + for (y = low_y; y < high_y; y++) { uint16_t *abuf = (uint16_t *)&voodoo->fb_mem[(params->aux_offset + y*voodoo->row_width) & voodoo->fb_mask]; int x; @@ -3632,9 +3656,9 @@ static void triangle_setup(voodoo_t *voodoo) } if (voodoo->sSetupMode & SETUPMODE_W1) { - voodoo->params.tmu[1].startW = (int64_t)(voodoo->verts[va].sW0 * 4294967296.0f); - voodoo->params.tmu[1].dWdX = (int64_t)(((voodoo->verts[va].sW0 - voodoo->verts[vb].sW0) * dyBC - (voodoo->verts[vb].sW0 - voodoo->verts[vc].sW0) * dyAB) * 4294967296.0f); - voodoo->params.tmu[1].dWdY = (int64_t)(((voodoo->verts[vb].sW0 - voodoo->verts[vc].sW0) * dxAB - (voodoo->verts[va].sW0 - voodoo->verts[vb].sW0) * dxBC) * 4294967296.0f); + voodoo->params.tmu[1].startW = (int64_t)(voodoo->verts[va].sW1 * 4294967296.0f); + voodoo->params.tmu[1].dWdX = (int64_t)(((voodoo->verts[va].sW1 - voodoo->verts[vb].sW1) * dyBC - (voodoo->verts[vb].sW1 - voodoo->verts[vc].sW1) * dyAB) * 4294967296.0f); + voodoo->params.tmu[1].dWdY = (int64_t)(((voodoo->verts[vb].sW1 - voodoo->verts[vc].sW1) * dxAB - (voodoo->verts[va].sW1 - voodoo->verts[vb].sW1) * dxBC) * 4294967296.0f); } if (voodoo->sSetupMode & SETUPMODE_S1_T1) { @@ -3728,7 +3752,7 @@ static void blit_start(voodoo_t *voodoo) int size_x = ABS(voodoo->bltSizeX), size_y = ABS(voodoo->bltSizeY); int x_dir = (voodoo->bltSizeX > 0) ? 1 : -1; int y_dir = (voodoo->bltSizeY > 0) ? 1 : -1; - int src_x, dst_x; + int dst_x; int src_y = voodoo->bltSrcY & 0x7ff, dst_y = voodoo->bltDstY & 0x7ff; int src_stride = (voodoo->bltCommand & BLTCMD_SRC_TILED) ? ((voodoo->bltSrcXYStride & 0x3f) * 32*2) : (voodoo->bltSrcXYStride & 0xff8); int dst_stride = (voodoo->bltCommand & BLTCMD_DST_TILED) ? ((voodoo->bltDstXYStride & 0x3f) * 32*2) : (voodoo->bltDstXYStride & 0xff8); @@ -3754,6 +3778,7 @@ static void blit_start(voodoo_t *voodoo) { uint16_t src_dat = src[src_x]; uint16_t dst_dat = dst[dst_x]; + int rop = 0; if (voodoo->bltCommand & BLIT_CLIPPING_ENABLED) { @@ -3761,8 +3786,31 @@ static void blit_start(voodoo_t *voodoo) dst_y < voodoo->bltClipLowY || dst_y > voodoo->bltClipHighY) goto skip_pixel_blit; } - - MIX(src_dat, dst_dat, voodoo->bltRop[3]); + + if (voodoo->bltCommand & BLIT_SRC_CHROMA) + { + int r = (src_dat >> 11); + int g = (src_dat >> 5) & 0x3f; + int b = src_dat & 0x1f; + + if (r >= voodoo->bltSrcChromaMinR && r <= voodoo->bltSrcChromaMaxR && + g >= voodoo->bltSrcChromaMinG && g <= voodoo->bltSrcChromaMaxG && + b >= voodoo->bltSrcChromaMinB && b <= voodoo->bltSrcChromaMaxB) + rop |= BLIT_ROP_SRC_PASS; + } + if (voodoo->bltCommand & BLIT_DST_CHROMA) + { + int r = (dst_dat >> 11); + int g = (dst_dat >> 5) & 0x3f; + int b = dst_dat & 0x1f; + + if (r >= voodoo->bltDstChromaMinR && r <= voodoo->bltDstChromaMaxR && + g >= voodoo->bltDstChromaMinG && g <= voodoo->bltDstChromaMaxG && + b >= voodoo->bltDstChromaMinB && b <= voodoo->bltDstChromaMaxB) + rop |= BLIT_ROP_DST_PASS; + } + + MIX(src_dat, dst_dat, voodoo->bltRop[rop]); dst[dst_x] = dst_dat; skip_pixel_blit: @@ -3840,7 +3888,7 @@ skip_pixel_fill: size_x = voodoo->bltSizeX & 0x1ff; } - dst = (uint64_t *)&voodoo->fb_mem[dst_y*512*8 + dst_x*8]; + dst = (uint64_t *)&voodoo->fb_mem[(dst_y*512*8 + dst_x*8) & voodoo->fb_mask]; for (x = 0; x <= size_x; x++) dst[x] = dat64; @@ -3856,7 +3904,6 @@ skip_pixel_fill: static void blit_data(voodoo_t *voodoo, uint32_t data) { - uint32_t data_orig = data; int src_bits = 32; uint32_t base_addr = (voodoo->bltCommand & BLTCMD_DST_TILED) ? ((voodoo->bltDstBaseAddr & 0x3ff) << 12) : (voodoo->bltDstBaseAddr & 0x3ffff8); uint16_t *dst = (uint16_t *)&voodoo->fb_mem[base_addr + voodoo->blt.dst_y*voodoo->blt.dst_stride]; @@ -3866,8 +3913,8 @@ static void blit_data(voodoo_t *voodoo, uint32_t data) while (src_bits && voodoo->blt.cur_x <= voodoo->blt.size_x) { - int r, g, b; - uint16_t src_dat, dst_dat; + int r = 0, g = 0, b = 0; + uint16_t src_dat = 0, dst_dat; int x = (voodoo->blt.x_dir > 0) ? (voodoo->blt.dst_x + voodoo->blt.cur_x) : (voodoo->blt.dst_x - voodoo->blt.cur_x); int rop = 0; @@ -4414,12 +4461,28 @@ static void voodoo_reg_writel(uint32_t addr, uint32_t val, void *p) break; case SST_clipLeftRight: - voodoo->params.clipRight = val & 0x3ff; - voodoo->params.clipLeft = (val >> 16) & 0x3ff; + if (voodoo->type >= VOODOO_2) + { + voodoo->params.clipRight = val & 0xfff; + voodoo->params.clipLeft = (val >> 16) & 0xfff; + } + else + { + voodoo->params.clipRight = val & 0x3ff; + voodoo->params.clipLeft = (val >> 16) & 0x3ff; + } break; case SST_clipLowYHighY: - voodoo->params.clipHighY = val & 0x3ff; - voodoo->params.clipLowY = (val >> 16) & 0x3ff; + if (voodoo->type >= VOODOO_2) + { + voodoo->params.clipHighY = val & 0xfff; + voodoo->params.clipLowY = (val >> 16) & 0xfff; + } + else + { + voodoo->params.clipHighY = val & 0x3ff; + voodoo->params.clipLowY = (val >> 16) & 0x3ff; + } break; case SST_nopCMD: @@ -4451,7 +4514,9 @@ static void voodoo_reg_writel(uint32_t addr, uint32_t val, void *p) voodoo->params.chromaKey_b = val & 0xff; voodoo->params.chromaKey = val & 0xffffff; break; - + case SST_stipple: + voodoo->params.stipple = val; + break; case SST_color0: voodoo->params.color0 = val; break; @@ -4594,21 +4659,21 @@ static void voodoo_reg_writel(uint32_t addr, uint32_t val, void *p) break; case SST_bltSrcChromaRange: voodoo->bltSrcChromaRange = val; - voodoo->bltSrcChromaMinR = val & 0x1f; + voodoo->bltSrcChromaMinB = val & 0x1f; voodoo->bltSrcChromaMinG = (val >> 5) & 0x3f; - voodoo->bltSrcChromaMinB = (val >> 11) & 0x1f; - voodoo->bltSrcChromaMaxR = (val >> 16) & 0x1f; + voodoo->bltSrcChromaMinR = (val >> 11) & 0x1f; + voodoo->bltSrcChromaMaxB = (val >> 16) & 0x1f; voodoo->bltSrcChromaMaxG = (val >> 21) & 0x3f; - voodoo->bltSrcChromaMaxB = (val >> 27) & 0x1f; + voodoo->bltSrcChromaMaxR = (val >> 27) & 0x1f; break; case SST_bltDstChromaRange: voodoo->bltDstChromaRange = val; - voodoo->bltDstChromaMinR = val & 0x1f; + voodoo->bltDstChromaMinB = val & 0x1f; voodoo->bltDstChromaMinG = (val >> 5) & 0x3f; - voodoo->bltDstChromaMinB = (val >> 11) & 0x1f; - voodoo->bltDstChromaMaxR = (val >> 16) & 0x1f; + voodoo->bltDstChromaMinR = (val >> 11) & 0x1f; + voodoo->bltDstChromaMaxB = (val >> 16) & 0x1f; voodoo->bltDstChromaMaxG = (val >> 21) & 0x3f; - voodoo->bltDstChromaMaxB = (val >> 27) & 0x1f; + voodoo->bltDstChromaMaxR = (val >> 27) & 0x1f; break; case SST_bltClipX: voodoo->bltClipRight = val & 0xfff; @@ -5187,7 +5252,9 @@ static void voodoo_fb_writew(uint32_t addr, uint16_t val, void *p) rgba8_t colour_data; uint16_t depth_data; uint8_t alpha_data; - int write_mask; + int write_mask = 0; + + colour_data.r = colour_data.g = colour_data.b = colour_data.a = 0; depth_data = voodoo->params.zaColor & 0xffff; alpha_data = voodoo->params.zaColor >> 24; @@ -5257,7 +5324,7 @@ static void voodoo_fb_writew(uint32_t addr, uint16_t val, void *p) if (params->fogMode & FOG_ENABLE) { int32_t z = new_depth << 12; - int32_t w_depth = new_depth; + int64_t w_depth = (int64_t)(int32_t)new_depth; int32_t ia = alpha_data << 12; APPLY_FOG(write_data.r, write_data.g, write_data.b, z, ia, w_depth); @@ -5310,7 +5377,7 @@ static void voodoo_fb_writel(uint32_t addr, uint32_t val, void *p) rgba8_t colour_data[2]; uint16_t depth_data[2]; uint8_t alpha_data[2]; - int write_mask, count = 1; + int write_mask = 0, count = 1; depth_data[0] = depth_data[1] = voodoo->params.zaColor & 0xffff; alpha_data[0] = alpha_data[1] = voodoo->params.zaColor >> 24; @@ -5342,6 +5409,13 @@ static void voodoo_fb_writel(uint32_t addr, uint32_t val, void *p) count = 2; break; + case LFB_FORMAT_XRGB8888: + colour_data[0].b = val & 0xff; + colour_data[0].g = (val >> 8) & 0xff; + colour_data[0].r = (val >> 16) & 0xff; + write_mask = LFB_WRITE_COLOUR; + addr >>= 1; + break; case LFB_FORMAT_ARGB8888: colour_data[0].b = val & 0xff; colour_data[0].g = (val >> 8) & 0xff; @@ -5398,7 +5472,7 @@ static void voodoo_fb_writel(uint32_t addr, uint32_t val, void *p) if (params->fogMode & FOG_ENABLE) { int32_t z = new_depth << 12; - int32_t w_depth = new_depth; + int64_t w_depth = new_depth; int32_t ia = alpha_data[c] << 12; APPLY_FOG(write_data.r, write_data.g, write_data.b, z, ia, w_depth); @@ -5528,7 +5602,6 @@ static void voodoo_wake_timer(void *p) static inline void queue_command(voodoo_t *voodoo, uint32_t addr_type, uint32_t val) { fifo_entry_t *fifo = &voodoo->fifo[voodoo->fifo_write_idx & FIFO_MASK]; - int c; if (FIFO_FULL) { @@ -5573,6 +5646,18 @@ static uint16_t voodoo_readw(uint32_t addr, void *p) return 0xffff; } +static void voodoo_flush(voodoo_t *voodoo) +{ + voodoo->flush = 1; + while (!FIFO_EMPTY) + { + wake_fifo_thread_now(voodoo); + thread_wait_event(voodoo->fifo_not_full_event, 1); + } + wait_for_render_thread_idle(voodoo); + voodoo->flush = 0; +} + static uint32_t voodoo_readl(uint32_t addr, void *p) { voodoo_t *voodoo = (voodoo_t *)p; @@ -5611,24 +5696,55 @@ static uint32_t voodoo_readl(uint32_t addr, void *p) temp |= (voodoo->swap_count << 28); if (voodoo->cmd_written - voodoo->cmd_read) temp |= 0x380; /*Busy*/ + if (voodoo->cmdfifo_depth_rd != voodoo->cmdfifo_depth_wr) + temp |= 0x380; /*Busy*/ if (!voodoo->v_retrace) temp |= 0x40; if (!voodoo->voodoo_busy) wake_fifo_thread(voodoo); break; - - case SST_lfbMode: - voodoo->flush = 1; - while (!FIFO_EMPTY) - { - wake_fifo_thread_now(voodoo); - thread_wait_event(voodoo->fifo_not_full_event, 1); - } - wait_for_render_thread_idle(voodoo); - voodoo->flush = 0; + case SST_fbzColorPath: + voodoo_flush(voodoo); + temp = voodoo->params.fbzColorPath; + break; + case SST_fogMode: + voodoo_flush(voodoo); + temp = voodoo->params.fogMode; + break; + case SST_alphaMode: + voodoo_flush(voodoo); + temp = voodoo->params.alphaMode; + break; + case SST_fbzMode: + voodoo_flush(voodoo); + temp = voodoo->params.fbzMode; + break; + case SST_lfbMode: + voodoo_flush(voodoo); temp = voodoo->lfbMode; break; + case SST_clipLeftRight: + voodoo_flush(voodoo); + temp = voodoo->params.clipRight | (voodoo->params.clipLeft << 16); + break; + case SST_clipLowYHighY: + voodoo_flush(voodoo); + temp = voodoo->params.clipHighY | (voodoo->params.clipLowY << 16); + break; + + case SST_stipple: + voodoo_flush(voodoo); + temp = voodoo->params.stipple; + break; + case SST_color0: + voodoo_flush(voodoo); + temp = voodoo->params.color0; + break; + case SST_color1: + voodoo_flush(voodoo); + temp = voodoo->params.color1; + break; case SST_fbiPixelsIn: temp = voodoo->fbiPixelsIn & 0xffffff; @@ -5665,6 +5781,10 @@ static uint32_t voodoo_readl(uint32_t addr, void *p) temp = voodoo->fbiInit3; break; + case SST_vRetrace: + timer_clock(); + temp = voodoo->line & 0x1fff; + break; case SST_hvRetrace: timer_clock(); temp = voodoo->line & 0x1fff; @@ -5750,13 +5870,7 @@ static void voodoo_pixelclock_update(voodoo_t *voodoo) static void voodoo_writel(uint32_t addr, uint32_t val, void *p) { voodoo_t *voodoo = (voodoo_t *)p; - union - { - uint32_t i; - float f; - } tempif; - tempif.i = val; voodoo->wr_count++; addr &= 0xffffff; @@ -5863,6 +5977,8 @@ static void voodoo_writel(uint32_t addr, uint32_t val, void *p) happen here on a real Voodoo*/ voodoo->disp_buffer = 0; voodoo->draw_buffer = 1; + voodoo_recalc(voodoo); + voodoo->front_offset = voodoo->params.front_offset; } } break; @@ -5926,7 +6042,7 @@ static void voodoo_writel(uint32_t addr, uint32_t val, void *p) } } else - voodoo->dac_readdata = voodoo->dac_data[voodoo->dac_readdata]; + voodoo->dac_readdata = voodoo->dac_data[voodoo->dac_readdata & 7]; } else { @@ -6268,7 +6384,7 @@ static void fifo_thread(void *param) break; default: - fatal("Bad CMDFIFO packet %08x %08x\n", header, voodoo->cmdfifo_rp); + pclog("Bad CMDFIFO packet %08x %08x\n", header, voodoo->cmdfifo_rp); } end_time = timer_read(); @@ -6409,11 +6525,16 @@ static void voodoo_calc_clutData(voodoo_t *voodoo) static int FILTCAP, FILTCAPG, FILTCAPB = 0; /* color filter threshold values */ -static void voodoo_generate_filter(voodoo_t *voodoo) +static void voodoo_generate_filter_v1(voodoo_t *voodoo) { int g, h; float difference, diffg, diffb; float thiscol, thiscolg, thiscolb, lined; + float fcr, fcg, fcb; + + fcr = FILTCAP * 5; + fcg = FILTCAPG * 6; + fcb = FILTCAPB * 5; for (g=0;g FILTCAP) difference = FILTCAP; if (difference < -FILTCAP) @@ -6437,10 +6560,18 @@ static void voodoo_generate_filter(voodoo_t *voodoo) diffb = FILTCAPB; if (diffb < -FILTCAPB) diffb = -FILTCAPB; - - thiscol = g + (difference / 2); - thiscolg = g + (diffg / 2); /* need these divides so we can actually undither! */ - thiscolb = g + (diffb / 2); + + // hack - to make it not bleed onto black + //if (g == 0){ + //difference = diffg = diffb = 0; + //} + + if ((difference < fcr) || (-difference > -fcr)) + thiscol = g + (difference / 2); + if ((diffg < fcg) || (-diffg > -fcg)) + thiscolg = g + (diffg / 2); /* need these divides so we can actually undither! */ + if ((diffb < fcb) || (-diffb > -fcb)) + thiscolb = g + (diffb / 2); if (thiscol < 0) thiscol = 0; @@ -6462,10 +6593,115 @@ static void voodoo_generate_filter(voodoo_t *voodoo) voodoo->thefilterb[g][h] = thiscolb; } + lined = g + 4; + if (lined > 255) + lined = 255; + voodoo->purpleline[g][0] = lined; + voodoo->purpleline[g][2] = lined; + + lined = g + 0; + if (lined > 255) + lined = 255; + voodoo->purpleline[g][1] = lined; + } +} + +static void voodoo_generate_filter_v2(voodoo_t *voodoo) +{ + int g, h; + float difference; + float thiscol, thiscolg, thiscolb, lined; + float clr, clg, clb = 0; + float fcr, fcg, fcb = 0; + + // pre-clamping + + fcr = FILTCAP; + fcg = FILTCAPG; + fcb = FILTCAPB; + + if (fcr > 32) fcr = 32; + if (fcg > 32) fcg = 32; + if (fcb > 32) fcb = 32; + + for (g=0;g<256;g++) // pixel 1 - our target pixel we want to bleed into + { + for (h=0;h<256;h++) // pixel 2 - our main pixel + { + float avg; + float avgdiff; + + difference = (float)(g - h); + avg = (float)((g + g + g + g + h) / 5); + avgdiff = avg - (float)((g + h + h + h + h) / 5); + if (avgdiff < 0) avgdiff *= -1; + if (difference < 0) difference *= -1; + + thiscol = thiscolg = thiscolb = g; + + // try lighten + if (h > g) + { + clr = clg = clb = avgdiff; + + if (clr>fcr) clr=fcr; + if (clg>fcg) clg=fcg; + if (clb>fcb) clb=fcb; + + + thiscol = g + clr; + thiscolg = g + clg; + thiscolb = g + clb; + + if (thiscol>g+FILTCAP) + thiscol=g+FILTCAP; + if (thiscolg>g+FILTCAPG) + thiscolg=g+FILTCAPG; + if (thiscolb>g+FILTCAPB) + thiscolb=g+FILTCAPB; + + + if (thiscol>g+avgdiff) + thiscol=g+avgdiff; + if (thiscolg>g+avgdiff) + thiscolg=g+avgdiff; + if (thiscolb>g+avgdiff) + thiscolb=g+avgdiff; + + } + + if (difference > FILTCAP) + thiscol = g; + if (difference > FILTCAPG) + thiscolg = g; + if (difference > FILTCAPB) + thiscolb = g; + + // clamp + if (thiscol < 0) thiscol = 0; + if (thiscolg < 0) thiscolg = 0; + if (thiscolb < 0) thiscolb = 0; + + if (thiscol > 255) thiscol = 255; + if (thiscolg > 255) thiscolg = 255; + if (thiscolb > 255) thiscolb = 255; + + // add to the table + voodoo->thefilter[g][h] = (thiscol); + voodoo->thefilterg[g][h] = (thiscolg); + voodoo->thefilterb[g][h] = (thiscolb); + + // debug the ones that don't give us much of a difference + //if (difference < FILTCAP) + //pclog("Voodoofilter: %ix%i - %f difference, %f average difference, R=%f, G=%f, B=%f\n", g, h, difference, avgdiff, thiscol, thiscolg, thiscolb); + } + lined = g + 3; if (lined > 255) lined = 255; - voodoo->purpleline[g] = lined; + voodoo->purpleline[g][0] = lined; + voodoo->purpleline[g][1] = 0; + voodoo->purpleline[g][2] = lined; } } @@ -6490,51 +6726,32 @@ static void voodoo_threshold_check(voodoo_t *voodoo) pclog("Voodoo Filter Threshold Check: %06x - RED %i GREEN %i BLUE %i\n", voodoo->scrfilterThreshold, r, g, b); voodoo->scrfilterThresholdOld = voodoo->scrfilterThreshold; - voodoo_generate_filter(voodoo); + + if (voodoo->type == VOODOO_2) + voodoo_generate_filter_v2(voodoo); + else + voodoo_generate_filter_v1(voodoo); } } -static void voodoo_filterline(voodoo_t *voodoo, uint16_t *fil, int column, uint16_t *src, int line) +static void voodoo_filterline_v1(voodoo_t *voodoo, uint8_t *fil, int column, uint16_t *src, int line) { int x; + // Scratchpad for avoiding feedback streaks + uint8_t fil3[(voodoo->h_disp) * 3]; + /* 16 to 32-bit */ for (x=0; x> 5) & 63) << 2); /* Shift to 32-bit */ - fil[x*3+2] = (((src[x] >> 11) & 31) << 3); - } + fil[x*3] = ((src[x] & 31) << 3); + fil[x*3+1] = (((src[x] >> 5) & 63) << 2); + fil[x*3+2] = (((src[x] >> 11) & 31) << 3); - fil[x*3] = 0; - fil[x*3+1] = 0; /* Keep the compiler happy */ - fil[x*3+2] = 0; - - /* filtering time */ - - for (x=1; xthefilterb[fil[x*3]][fil[ (x-1) *3]]; - fil[(x-1)*3+1] = voodoo->thefilterg[fil[x*3+1]][fil[ (x-1) *3+1]]; - fil[(x-1)*3+2] = voodoo->thefilter[fil[x*3+2]][fil[ (x-1) *3+2]]; - } - for (x=0; xthefilterb[fil[x*3]][fil[ (x+1) *3]]; - fil[(x)*3+1] = voodoo->thefilterg[fil[x*3+1]][fil[ (x+1) *3+1]]; - fil[(x)*3+2] = voodoo->thefilter[fil[x*3+2]][fil[ (x+1) *3+2]]; - } - for (x=1; xthefilterb[fil[x*3]][fil[ (x-1) *3]]; - fil[(x-1)*3+1] = voodoo->thefilterg[fil[x*3+1]][fil[ (x-1) *3+1]]; - fil[(x-1)*3+2] = voodoo->thefilter[fil[x*3+2]][fil[ (x-1) *3+2]]; - } - for (x=1; xthefilterb[fil[x*3]][fil[ (x-1) *3]]; - fil[(x-1)*3+1] = voodoo->thefilterg[fil[x*3+1]][fil[ (x-1) *3+1]]; - fil[(x-1)*3+2] = voodoo->thefilter[fil[x*3+2]][fil[ (x-1) *3+2]]; + // Copy to our scratchpads + fil3[x*3+0] = fil[x*3+0]; + fil3[x*3+1] = fil[x*3+1]; + fil3[x*3+2] = fil[x*3+2]; } @@ -6544,17 +6761,115 @@ static void voodoo_filterline(voodoo_t *voodoo, uint16_t *fil, int column, uint1 { for (x=0; xpurpleline[fil[x*3]]; - fil[x*3+2] = voodoo->purpleline[fil[x*3+2]]; + fil[x*3] = voodoo->purpleline[fil[x*3]][0]; + fil[x*3+1] = voodoo->purpleline[fil[x*3+1]][1]; + fil[x*3+2] = voodoo->purpleline[fil[x*3+2]][2]; } } + + + /* filtering time */ + + for (x=1; xthefilterb[fil[x*3]][fil[ (x-1) *3]]; + fil3[(x)*3+1] = voodoo->thefilterg[fil[x*3+1]][fil[ (x-1) *3+1]]; + fil3[(x)*3+2] = voodoo->thefilter[fil[x*3+2]][fil[ (x-1) *3+2]]; + } + + for (x=1; xthefilterb[fil3[x*3]][fil3[ (x-1) *3]]; + fil[(x)*3+1] = voodoo->thefilterg[fil3[x*3+1]][fil3[ (x-1) *3+1]]; + fil[(x)*3+2] = voodoo->thefilter[fil3[x*3+2]][fil3[ (x-1) *3+2]]; + } + + for (x=1; xthefilterb[fil[x*3]][fil[ (x-1) *3]]; + fil3[(x)*3+1] = voodoo->thefilterg[fil[x*3+1]][fil[ (x-1) *3+1]]; + fil3[(x)*3+2] = voodoo->thefilter[fil[x*3+2]][fil[ (x-1) *3+2]]; + } + + for (x=0; xthefilterb[fil3[x*3]][fil3[ (x+1) *3]]; + fil[(x)*3+1] = voodoo->thefilterg[fil3[x*3+1]][fil3[ (x+1) *3+1]]; + fil[(x)*3+2] = voodoo->thefilter[fil3[x*3+2]][fil3[ (x+1) *3+2]]; + } } + +static void voodoo_filterline_v2(voodoo_t *voodoo, uint8_t *fil, int column, uint16_t *src, int line) +{ + int x; + + // Scratchpad for blending filter + uint8_t fil3[(voodoo->h_disp) * 3]; + + /* 16 to 32-bit */ + for (x=0; x> 5) & 63) << 2); + fil3[x*3+2] = fil[x*3+2] = (((src[x] >> 11) & 31) << 3); + } + + /* filtering time */ + + for (x=1; xthefilterb [((src[x+3] & 31) << 3)] [((src[x] & 31) << 3)]; + fil3[(x+3)*3+1] = voodoo->thefilterg [(((src[x+3] >> 5) & 63) << 2)] [(((src[x] >> 5) & 63) << 2)]; + fil3[(x+3)*3+2] = voodoo->thefilter [(((src[x+3] >> 11) & 31) << 3)] [(((src[x] >> 11) & 31) << 3)]; + + fil[(x+2)*3] = voodoo->thefilterb [fil3[(x+2)*3]][((src[x] & 31) << 3)]; + fil[(x+2)*3+1] = voodoo->thefilterg [fil3[(x+2)*3+1]][(((src[x] >> 5) & 63) << 2)]; + fil[(x+2)*3+2] = voodoo->thefilter [fil3[(x+2)*3+2]][(((src[x] >> 11) & 31) << 3)]; + + fil3[(x+1)*3] = voodoo->thefilterb [fil[(x+1)*3]][((src[x] & 31) << 3)]; + fil3[(x+1)*3+1] = voodoo->thefilterg [fil[(x+1)*3+1]][(((src[x] >> 5) & 63) << 2)]; + fil3[(x+1)*3+2] = voodoo->thefilter [fil[(x+1)*3+2]][(((src[x] >> 11) & 31) << 3)]; + + fil[(x-1)*3] = voodoo->thefilterb [fil3[(x-1)*3]][((src[x] & 31) << 3)]; + fil[(x-1)*3+1] = voodoo->thefilterg [fil3[(x-1)*3+1]][(((src[x] >> 5) & 63) << 2)]; + fil[(x-1)*3+2] = voodoo->thefilter [fil3[(x-1)*3+2]][(((src[x] >> 11) & 31) << 3)]; + } + + // unroll for edge cases + + fil3[(column-3)*3] = voodoo->thefilterb [((src[column-3] & 31) << 3)] [((src[column] & 31) << 3)]; + fil3[(column-3)*3+1] = voodoo->thefilterg [(((src[column-3] >> 5) & 63) << 2)] [(((src[column] >> 5) & 63) << 2)]; + fil3[(column-3)*3+2] = voodoo->thefilter [(((src[column-3] >> 11) & 31) << 3)] [(((src[column] >> 11) & 31) << 3)]; + + fil3[(column-2)*3] = voodoo->thefilterb [((src[column-2] & 31) << 3)] [((src[column] & 31) << 3)]; + fil3[(column-2)*3+1] = voodoo->thefilterg [(((src[column-2] >> 5) & 63) << 2)] [(((src[column] >> 5) & 63) << 2)]; + fil3[(column-2)*3+2] = voodoo->thefilter [(((src[column-2] >> 11) & 31) << 3)] [(((src[column] >> 11) & 31) << 3)]; + + fil3[(column-1)*3] = voodoo->thefilterb [((src[column-1] & 31) << 3)] [((src[column] & 31) << 3)]; + fil3[(column-1)*3+1] = voodoo->thefilterg [(((src[column-1] >> 5) & 63) << 2)] [(((src[column] >> 5) & 63) << 2)]; + fil3[(column-1)*3+2] = voodoo->thefilter [(((src[column-1] >> 11) & 31) << 3)] [(((src[column] >> 11) & 31) << 3)]; + + fil[(column-2)*3] = voodoo->thefilterb [fil3[(column-2)*3]][((src[column] & 31) << 3)]; + fil[(column-2)*3+1] = voodoo->thefilterg [fil3[(column-2)*3+1]][(((src[column] >> 5) & 63) << 2)]; + fil[(column-2)*3+2] = voodoo->thefilter [fil3[(column-2)*3+2]][(((src[column] >> 11) & 31) << 3)]; + + fil[(column-1)*3] = voodoo->thefilterb [fil3[(column-1)*3]][((src[column] & 31) << 3)]; + fil[(column-1)*3+1] = voodoo->thefilterg [fil3[(column-1)*3+1]][(((src[column] >> 5) & 63) << 2)]; + fil[(column-1)*3+2] = voodoo->thefilter [fil3[(column-1)*3+2]][(((src[column] >> 11) & 31) << 3)]; + + fil3[(column-1)*3] = voodoo->thefilterb [fil[(column-1)*3]][((src[column] & 31) << 3)]; + fil3[(column-1)*3+1] = voodoo->thefilterg [fil[(column-1)*3+1]][(((src[column] >> 5) & 63) << 2)]; + fil3[(column-1)*3+2] = voodoo->thefilter [fil[(column-1)*3+2]][(((src[column] >> 11) & 31) << 3)]; +} + + void voodoo_callback(void *p) { voodoo_t *voodoo = (voodoo_t *)p; - int y_add = enable_overscan ? 16 : 0; - int x_add = enable_overscan ? 8 : 0; + int y_add = (enable_overscan && !suppress_overscan) ? 16 : 0; + int x_add = (enable_overscan && !suppress_overscan) ? 8 : 0; if (voodoo->fbiInit0 & FBIINIT0_VGA_PASS) { @@ -6578,10 +6893,12 @@ void voodoo_callback(void *p) if (voodoo->scrfilter && voodoo->scrfilterEnabled) { - int j, offset; - uint16_t fil[(voodoo->h_disp + 1) * 3]; /* interleaved 24-bit RGB */ + uint8_t fil[(voodoo->h_disp) * 3]; /* interleaved 24-bit RGB */ - voodoo_filterline(voodoo, fil, voodoo->h_disp, src, voodoo->line); + if (voodoo->type == VOODOO_2) + voodoo_filterline_v2(voodoo, fil, voodoo->h_disp, src, voodoo->line); + else + voodoo_filterline_v1(voodoo, fil, voodoo->h_disp, src, voodoo->line); for (x = 0; x < voodoo->h_disp; x++) { @@ -6729,7 +7046,10 @@ void *voodoo_init() break; } - voodoo_generate_filter(voodoo); /*generate filter lookup tables*/ + if (voodoo->type == VOODOO_2) /*generate filter lookup tables*/ + voodoo_generate_filter_v2(voodoo); + else + voodoo_generate_filter_v1(voodoo); pci_add(voodoo_pci_read, voodoo_pci_write, voodoo); @@ -6834,17 +7154,19 @@ void *voodoo_init() void voodoo_close(void *p) { +#ifndef RELEASE_BUILD FILE *f; +#endif voodoo_t *voodoo = (voodoo_t *)p; int c; #ifndef RELEASE_BUILD - f = romfopen("texram.dmp", "wb"); + f = romfopen(L"texram.dmp", L"wb"); fwrite(voodoo->tex_mem[0], voodoo->texture_size*1024*1024, 1, f); fclose(f); if (voodoo->dual_tmus) { - f = romfopen("texram2.dmp", "wb"); + f = romfopen(L"texram2.dmp", L"wb"); fwrite(voodoo->tex_mem[1], voodoo->texture_size*1024*1024, 1, f); fclose(f); } @@ -6992,7 +7314,7 @@ static device_config_t voodoo_config[] = device_t voodoo_device = { "3DFX Voodoo Graphics", - 0, + DEVICE_PCI, voodoo_init, voodoo_close, NULL, diff --git a/src/vid_voodoo.h b/src/VIDEO/vid_voodoo.h similarity index 100% rename from src/vid_voodoo.h rename to src/VIDEO/vid_voodoo.h diff --git a/src/vid_voodoo_codegen_x86-64.h b/src/VIDEO/vid_voodoo_codegen_x86-64.h similarity index 98% rename from src/vid_voodoo_codegen_x86-64.h rename to src/VIDEO/vid_voodoo_codegen_x86-64.h index 8d3cc7271..160708b93 100644 --- a/src/vid_voodoo_codegen_x86-64.h +++ b/src/VIDEO/vid_voodoo_codegen_x86-64.h @@ -70,7 +70,6 @@ static __m128i xmm_ff_w;// = 0x00ff00ff00ff00ffull; static __m128i xmm_ff_b;// = 0x00000000ffffffffull; static uint32_t zero = 0; -static double const_1_48 = (double)(1ull << 4); static __m128i alookup[257], aminuslookup[256]; static __m128i minus_254;// = 0xff02ff02ff02ff02ull; @@ -161,7 +160,7 @@ static inline int codegen_texture_fetch(uint8_t *code_block, voodoo_t *voodoo, v addbyte(0x0f); /*MOVZX EAX, logtable[RAX]*/ addbyte(0xb6); addbyte(0x80); - addlong((uint32_t)logtable); + addlong((uint32_t)(uintptr_t)logtable); addbyte(0x09); /*OR EAX, EDX*/ addbyte(0xd0); addbyte(0x03); /*ADD EAX, state->lod*/ @@ -339,7 +338,7 @@ static inline int codegen_texture_fetch(uint8_t *code_block, voodoo_t *voodoo, v addbyte(0x48); addbyte(0x14); addbyte(0x25); - addlong(&zero); + addlong((uint32_t)(uintptr_t)&zero); addbyte(0x3b); /*CMP EDX, params->tex_h_mask[ESI]*/ addbyte(0x96); addlong(offsetof(voodoo_params_t, tex_h_mask[tmu])); @@ -353,7 +352,7 @@ static inline int codegen_texture_fetch(uint8_t *code_block, voodoo_t *voodoo, v addbyte(0x48); addbyte(0x1c); addbyte(0x25); - addlong(&zero); + addlong((uint32_t)(uintptr_t)&zero); addbyte(0x3b); /*CMP EBX, params->tex_h_mask[ESI]*/ addbyte(0x9e); addlong(offsetof(voodoo_params_t, tex_h_mask[tmu])); @@ -400,7 +399,7 @@ static inline int codegen_texture_fetch(uint8_t *code_block, voodoo_t *voodoo, v addbyte(0x48); addbyte(0x04); addbyte(0x25); - addlong(&zero); + addlong((uint32_t)(uintptr_t)&zero); addbyte(0x78); /*JS + - clamp on 0*/ addbyte(2+3+2+ 5+5+2); addbyte(0x3b); /*CMP EAX, EBP*/ @@ -434,7 +433,7 @@ static inline int codegen_texture_fetch(uint8_t *code_block, voodoo_t *voodoo, v addbyte(0x0c); addbyte(0x82); - if (state->clamp_s) + if (state->clamp_s[tmu]) { addbyte(0xeb); /*JMP +*/ addbyte(5+5+4+4); @@ -501,7 +500,7 @@ static inline int codegen_texture_fetch(uint8_t *code_block, voodoo_t *voodoo, v addbyte(0x49); /*MOV R8, bilinear_lookup*/ addbyte(0xb8); - addquad(bilinear_lookup); + addquad((uintptr_t)bilinear_lookup); addbyte(0x66); /*PUNPCKLBW XMM0, XMM2*/ addbyte(0x0f); @@ -607,7 +606,7 @@ static inline int codegen_texture_fetch(uint8_t *code_block, voodoo_t *voodoo, v addbyte(0xe8); addbyte(0xd3); /*SHR EBX, CL*/ addbyte(0xeb); - if (state->clamp_s) + if (state->clamp_s[tmu]) { addbyte(0x85); /*TEST EAX, EAX*/ addbyte(0xc0); @@ -615,7 +614,7 @@ static inline int codegen_texture_fetch(uint8_t *code_block, voodoo_t *voodoo, v addbyte(0x48); addbyte(0x04); addbyte(0x25); - addlong(&zero); + addlong((uint32_t)(uintptr_t)&zero); addbyte(0x3b); /*CMP EAX, params->tex_w_mask[ESI+ECX*4]*/ addbyte(0x84); addbyte(0x8e); @@ -634,7 +633,7 @@ static inline int codegen_texture_fetch(uint8_t *code_block, voodoo_t *voodoo, v addbyte(0x8e); addlong(offsetof(voodoo_params_t, tex_w_mask[tmu]) - 0x10); } - if (state->clamp_t) + if (state->clamp_t[tmu]) { addbyte(0x85); /*TEST EBX, EBX*/ addbyte(0xdb); @@ -642,7 +641,7 @@ static inline int codegen_texture_fetch(uint8_t *code_block, voodoo_t *voodoo, v addbyte(0x48); addbyte(0x1c); addbyte(0x25); - addlong(&zero); + addlong((uint32_t)(uintptr_t)&zero); addbyte(0x3b); /*CMP EBX, params->tex_h_mask[ESI+ECX*4]*/ addbyte(0x9c); addbyte(0x8e); @@ -1080,7 +1079,7 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0x0f); addbyte(0xef); addbyte(0x83); - addlong((uint32_t)&xmm_00_ff_w[0]); + addlong((uint32_t)(uintptr_t)&xmm_00_ff_w[0]); } else if (!tc_reverse_blend_1) { @@ -1089,14 +1088,14 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0xef); addbyte(0x04); addbyte(0x25); - addlong((uint32_t)&xmm_ff_w); + addlong((uint32_t)(uintptr_t)&xmm_ff_w); } addbyte(0x66); /*PADDW XMM0, xmm_01_w*/ addbyte(0x0f); addbyte(0xfd); addbyte(0x04); addbyte(0x25); - addlong((uint32_t)&xmm_01_w); + addlong((uint32_t)(uintptr_t)&xmm_01_w); addbyte(0xf3); /*MOVQ XMM1, XMM2*/ addbyte(0x0f); addbyte(0x7e); @@ -1217,7 +1216,7 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0x33); /*XOR EAX, i_00_ff_w[ECX*4]*/ addbyte(0x04); addbyte(0x8d); - addlong((uint32_t)i_00_ff_w); + addlong((uint32_t)(uintptr_t)i_00_ff_w); } else if (!tc_reverse_blend_1) { @@ -1404,7 +1403,7 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0x0f); addbyte(0xef); addbyte(0xa3); - addlong((uint32_t)&xmm_00_ff_w[0]); + addlong((uint32_t)(uintptr_t)&xmm_00_ff_w[0]); } else if (!tc_reverse_blend) { @@ -1413,14 +1412,14 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0xef); addbyte(0x24); addbyte(0x25); - addlong(&xmm_ff_w); + addlong((uint32_t)(uintptr_t)&xmm_ff_w); } addbyte(0x66); /*PADDW XMM4, 1*/ addbyte(0x0f); addbyte(0xfd); addbyte(0x24); addbyte(0x25); - addlong(&xmm_01_w); + addlong((uint32_t)(uintptr_t)&xmm_01_w); addbyte(0xf3); /*MOVQ XMM5, XMM1*/ addbyte(0x0f); addbyte(0x7e); @@ -1488,7 +1487,7 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0x0f); addbyte(0xef); addbyte(0x0d); - addlong(&xmm_ff_w); + addlong((uint32_t)(uintptr_t)&xmm_ff_w); } addbyte(0x66); /*PACKUSWB XMM0, XMM0*/ @@ -1585,7 +1584,7 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0x33); /*XOR EBX, i_00_ff_w[ECX*4]*/ addbyte(0x1c); addbyte(0x8d); - addlong((uint32_t)i_00_ff_w); + addlong((uint32_t)(uintptr_t)i_00_ff_w); } else if (!tca_reverse_blend) { @@ -2143,14 +2142,14 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0xef); addbyte(0x1c); addbyte(0x25); - addlong(&xmm_ff_w); + addlong((uint32_t)(uintptr_t)&xmm_ff_w); } addbyte(0x66); /*PADDW XMM3, 1*/ addbyte(0x0f); addbyte(0xfd); addbyte(0x1c); addbyte(0x25); - addlong(&xmm_01_w); + addlong((uint32_t)(uintptr_t)&xmm_01_w); addbyte(0x66); /*PMULLW XMM0, XMM3*/ addbyte(0x0f); addbyte(0xd5); @@ -2194,7 +2193,7 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0xef); addbyte(0x04); addbyte(0x25); - addlong(&xmm_ff_b); + addlong((uint32_t)(uintptr_t)&xmm_ff_b); } if (params->fogMode & FOG_ENABLE) @@ -2441,7 +2440,7 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo { addbyte(0x49); /*MOV R8, rgb565*/ addbyte(0xb8); - addquad(rgb565); + addquad((uintptr_t)rgb565); addbyte(0x8b); /*MOV EAX, state->x[EDI]*/ addbyte(0x87); addlong(offsetof(voodoo_state_t, x)); @@ -2489,7 +2488,7 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0xd5); addbyte(0x24); addbyte(0xd5); - addlong(alookup); + addlong((uint32_t)(uintptr_t)alookup); addbyte(0xf3); /*MOVQ XMM5, XMM4*/ addbyte(0x0f); addbyte(0x7e); @@ -2499,7 +2498,7 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0xfd); addbyte(0x24); addbyte(0x25); - addlong((uint32_t)alookup + 16); + addlong((uint32_t)(uintptr_t)alookup + 16); addbyte(0x66); /*PSRLW XMM5, 8*/ addbyte(0x0f); addbyte(0x71); @@ -2529,7 +2528,7 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0xfd); addbyte(0x24); addbyte(0x25); - addlong((uint32_t)alookup + 16); + addlong((uint32_t)(uintptr_t)alookup + 16); addbyte(0x66); /*PSRLW XMM5, 8*/ addbyte(0x0f); addbyte(0x71); @@ -2555,7 +2554,7 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0xd5); addbyte(0x24); addbyte(0xd5); - addlong(aminuslookup); + addlong((uint32_t)(uintptr_t)aminuslookup); addbyte(0xf3); /*MOVQ XMM5, XMM4*/ addbyte(0x0f); addbyte(0x7e); @@ -2565,7 +2564,7 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0xfd); addbyte(0x24); addbyte(0x25); - addlong((uint32_t)alookup + 16); + addlong((uint32_t)(uintptr_t)alookup + 16); addbyte(0x66); /*PSRLW XMM5, 8*/ addbyte(0x0f); addbyte(0x71); @@ -2587,7 +2586,7 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0x7e); addbyte(0x2c); addbyte(0x25); - addlong(&xmm_ff_w); + addlong((uint32_t)(uintptr_t)&xmm_ff_w); addbyte(0x66); /*PSUBW XMM5, XMM0*/ addbyte(0x0f); addbyte(0xf9); @@ -2605,7 +2604,7 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0xfd); addbyte(0x24); addbyte(0x25); - addlong((uint32_t)alookup + 16); + addlong((uint32_t)(uintptr_t)alookup + 16); addbyte(0x66); /*PSRLW XMM5, 8*/ addbyte(0x0f); addbyte(0x71); @@ -2633,7 +2632,7 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0xd5); addbyte(0x24); addbyte(0xd5); - addlong(&minus_254); + addlong((uint32_t)(uintptr_t)&minus_254); addbyte(0xf3); /*MOVQ XMM5, XMM4*/ addbyte(0x0f); addbyte(0x7e); @@ -2643,7 +2642,7 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0xfd); addbyte(0x24); addbyte(0x25); - addlong((uint32_t)alookup + 16); + addlong((uint32_t)(uintptr_t)alookup + 16); addbyte(0x66); /*PSRLW XMM5, 8*/ addbyte(0x0f); addbyte(0x71); @@ -2674,7 +2673,7 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0xd5); addbyte(0x04); addbyte(0xd5); - addlong(alookup); + addlong((uint32_t)(uintptr_t)alookup); addbyte(0xf3); /*MOVQ XMM5, XMM0*/ addbyte(0x0f); addbyte(0x7e); @@ -2684,7 +2683,7 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0xfd); addbyte(0x04); addbyte(0x25); - addlong((uint32_t)alookup + 16); + addlong((uint32_t)(uintptr_t)alookup + 16); addbyte(0x66); /*PSRLW XMM5, 8*/ addbyte(0x0f); addbyte(0x71); @@ -2714,7 +2713,7 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0xfd); addbyte(0x04); addbyte(0x25); - addlong((uint32_t)alookup + 16); + addlong((uint32_t)(uintptr_t)alookup + 16); addbyte(0x66); /*PSRLW XMM5, 8*/ addbyte(0x0f); addbyte(0x71); @@ -2740,7 +2739,7 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0xd5); addbyte(0x04); addbyte(0xd5); - addlong(aminuslookup); + addlong((uint32_t)(uintptr_t)aminuslookup); addbyte(0xf3); /*MOVQ XMM5, XMM0*/ addbyte(0x0f); addbyte(0x7e); @@ -2750,7 +2749,7 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0xfd); addbyte(0x04); addbyte(0x25); - addlong((uint32_t)alookup + 16); + addlong((uint32_t)(uintptr_t)alookup + 16); addbyte(0x66); /*PSRLW XMM5, 8*/ addbyte(0x0f); addbyte(0x71); @@ -2772,7 +2771,7 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0x7e); addbyte(0x2c); addbyte(0x25); - addlong(&xmm_ff_w); + addlong((uint32_t)(uintptr_t)&xmm_ff_w); addbyte(0x66); /*PSUBW XMM5, XMM6*/ addbyte(0x0f); addbyte(0xf9); @@ -2790,7 +2789,7 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0xfd); addbyte(0x04); addbyte(0x25); - addlong((uint32_t)alookup + 16); + addlong((uint32_t)(uintptr_t)alookup + 16); addbyte(0x66); /*PSRLW XMM5, 8*/ addbyte(0x0f); addbyte(0x71); @@ -2842,7 +2841,7 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo { addbyte(0x49); /*MOV R8, dither_rb*/ addbyte(0xb8); - addquad(dither2x2 ? dither_rb2x2 : dither_rb); + addquad(dither2x2 ? (uintptr_t)dither_rb2x2 : (uintptr_t)dither_rb); addbyte(0x4c); /*MOV ESI, real_y (R14)*/ addbyte(0x89); addbyte(0xf6); @@ -2980,7 +2979,7 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0x56); } - if (params->fbzMode & FBZ_DEPTH_WMASK) + if ((params->fbzMode & (FBZ_DEPTH_WMASK | FBZ_DEPTH_ENABLE)) == (FBZ_DEPTH_WMASK | FBZ_DEPTH_ENABLE)) { addbyte(0x66); /*MOV AX, new_depth*/ addbyte(0x8b); diff --git a/src/vid_voodoo_codegen_x86.h b/src/VIDEO/vid_voodoo_codegen_x86.h similarity index 98% rename from src/vid_voodoo_codegen_x86.h rename to src/VIDEO/vid_voodoo_codegen_x86.h index d10f3bbcc..0cd0fc7eb 100644 --- a/src/vid_voodoo_codegen_x86.h +++ b/src/VIDEO/vid_voodoo_codegen_x86.h @@ -85,7 +85,7 @@ static inline int codegen_texture_fetch(uint8_t *code_block, voodoo_t *voodoo, v addlong(tmu ? offsetof(voodoo_state_t, tmu1_w) : offsetof(voodoo_state_t, tmu0_w)); addbyte(0xdd); /*FLDq const_1_48*/ addbyte(0x05); - addlong(&const_1_48); + addlong((uint32_t)&const_1_48); addbyte(0xde); /*FDIV ST(1)*/ addbyte(0xf1); addbyte(0xdf); /*FILDq state->tmu0_s*/ @@ -129,7 +129,7 @@ static inline int codegen_texture_fetch(uint8_t *code_block, voodoo_t *voodoo, v addbyte(0x0f); /*MOVZX EBX, logtable[EBX]*/ addbyte(0xb6); addbyte(0x9b); - addlong(logtable); + addlong((uint32_t)logtable); addbyte(0x09); /*OR EAX, EBX*/ addbyte(0xd8); addbyte(0x03); /*ADD EAX, state->lod*/ @@ -227,8 +227,8 @@ static inline int codegen_texture_fetch(uint8_t *code_block, voodoo_t *voodoo, v addbyte(0x8b); /*MOV ECX, [ECX+EAX*4]*/ addbyte(0x0c); addbyte(0x81); - addbyte(0xbd); /*MOV EBP, 1*/ - addlong(1); + addbyte(0xbd); /*MOV EBP, 8*/ + addlong(8); addbyte(0x28); /*SUB DL, CL*/ addbyte(0xca); addbyte(0xd3); /*SHL EBP, CL*/ @@ -236,9 +236,6 @@ static inline int codegen_texture_fetch(uint8_t *code_block, voodoo_t *voodoo, v addbyte(0x8b); /*MOV EAX, state->tex_s[EDI]*/ addbyte(0x87); addlong(offsetof(voodoo_state_t, tex_s)); - addbyte(0xc1); /*SHL EBP, 3*/ - addbyte(0xe5); - addbyte(3); addbyte(0x8b); /*MOV EBX, state->tex_t[EDI]*/ addbyte(0x9f); addlong(offsetof(voodoo_state_t, tex_t)); @@ -325,7 +322,7 @@ static inline int codegen_texture_fetch(uint8_t *code_block, voodoo_t *voodoo, v addbyte(0x0f); /*CMOVS EDX, zero*/ addbyte(0x48); addbyte(0x15); - addlong(&zero); + addlong((uint32_t)&zero); addbyte(0x3b); /*CMP EDX, params->tex_h_mask[ESI]*/ addbyte(0x96); addlong(offsetof(voodoo_params_t, tex_h_mask[tmu])); @@ -338,7 +335,7 @@ static inline int codegen_texture_fetch(uint8_t *code_block, voodoo_t *voodoo, v addbyte(0x0f); /*CMOVS EBX, zero*/ addbyte(0x48); addbyte(0x1d); - addlong(&zero); + addlong((uint32_t)&zero); addbyte(0x3b); /*CMP EBX, params->tex_h_mask[ESI]*/ addbyte(0x9e); addlong(offsetof(voodoo_params_t, tex_h_mask[tmu])); @@ -382,7 +379,7 @@ static inline int codegen_texture_fetch(uint8_t *code_block, voodoo_t *voodoo, v addbyte(0x0f); /*CMOVS EAX, zero*/ addbyte(0x48); addbyte(0x05); - addlong(&zero); + addlong((uint32_t)&zero); addbyte(0x78); /*JS + - clamp on 0*/ addbyte(2+3+2+ 5+5+2); addbyte(0x3b); /*CMP EAX, EBP*/ @@ -416,7 +413,7 @@ static inline int codegen_texture_fetch(uint8_t *code_block, voodoo_t *voodoo, v addbyte(0x0c); addbyte(0x82); - if (state->clamp_s) + if (state->clamp_s[tmu]) { addbyte(0xeb); /*JMP +*/ addbyte(5+5+4+4); @@ -492,7 +489,7 @@ static inline int codegen_texture_fetch(uint8_t *code_block, voodoo_t *voodoo, v addbyte(0x81); /*ADD ESI, bilinear_lookup*/ addbyte(0xc6); - addlong(bilinear_lookup); + addlong((uint32_t)bilinear_lookup); addbyte(0x66); /*PMULLW XMM0, bilinear_lookup[ESI]*/ addbyte(0x0f); @@ -595,7 +592,7 @@ static inline int codegen_texture_fetch(uint8_t *code_block, voodoo_t *voodoo, v addbyte(0x0f); /*CMOVS EAX, zero*/ addbyte(0x48); addbyte(0x05); - addlong(&zero); + addlong((uint32_t)&zero); addbyte(0x3b); /*CMP EAX, params->tex_w_mask[ESI+ECX*4]*/ addbyte(0x84); addbyte(0x8e); @@ -621,7 +618,7 @@ static inline int codegen_texture_fetch(uint8_t *code_block, voodoo_t *voodoo, v addbyte(0x0f); /*CMOVS EBX, zero*/ addbyte(0x48); addbyte(0x1d); - addlong(&zero); + addlong((uint32_t)&zero); addbyte(0x3b); /*CMP EBX, params->tex_h_mask[ESI+ECX*4]*/ addbyte(0x9c); addbyte(0x8e); @@ -762,10 +759,14 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0x47); addbyte(0xc3); - if (depth_jump_pos) - *(uint8_t *)&code_block[depth_jump_pos] = (block_pos - depth_jump_pos) - 1; - if (depth_jump_pos) - *(uint8_t *)&code_block[depth_jump_pos2] = (block_pos - depth_jump_pos2) - 1; + if (depth_jump_pos) + { + *(uint8_t *)&code_block[depth_jump_pos] = (block_pos - depth_jump_pos) - 1; + } + if (depth_jump_pos2) + { + *(uint8_t *)&code_block[depth_jump_pos2] = (block_pos - depth_jump_pos2) - 1; + } if ((params->fogMode & (FOG_ENABLE|FOG_CONSTANT|FOG_Z|FOG_ALPHA)) == FOG_ENABLE) { @@ -1395,13 +1396,13 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0x0f); addbyte(0xef); addbyte(0x25); - addlong(&xmm_ff_w); + addlong((uint32_t)&xmm_ff_w); } addbyte(0x66); /*PADDW XMM4, 1*/ addbyte(0x0f); addbyte(0xfd); addbyte(0x25); - addlong(&xmm_01_w); + addlong((uint32_t)&xmm_01_w); addbyte(0xf3); /*MOVQ XMM5, XMM1*/ addbyte(0x0f); addbyte(0x7e); @@ -1469,7 +1470,7 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0x0f); addbyte(0xef); addbyte(0x0d); - addlong(&xmm_ff_w); + addlong((uint32_t)&xmm_ff_w); } addbyte(0x66); /*PACKUSWB XMM0, XMM0*/ @@ -2124,13 +2125,13 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0x0f); addbyte(0xef); addbyte(0x1d); - addlong(&xmm_ff_w); + addlong((uint32_t)&xmm_ff_w); } addbyte(0x66); /*PADDW XMM3, 1*/ addbyte(0x0f); addbyte(0xfd); addbyte(0x1d); - addlong(&xmm_01_w); + addlong((uint32_t)&xmm_01_w); addbyte(0x66); /*PMULLW XMM0, XMM3*/ addbyte(0x0f); addbyte(0xd5); @@ -2173,7 +2174,7 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0x0f); addbyte(0xef); addbyte(0x05); - addlong(&xmm_ff_b); + addlong((uint32_t)&xmm_ff_b); } //#if 0 // addbyte(0x66); /*MOVD state->out[EDI], XMM0*/ @@ -2462,7 +2463,7 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0x6e); addbyte(0x24); addbyte(0x85); - addlong(rgb565); + addlong((uint32_t)rgb565); addbyte(0x66); /*PUNPCKLBW XMM4, XMM2*/ addbyte(0x0f); addbyte(0x60); @@ -2486,7 +2487,7 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0xd5); addbyte(0x24); addbyte(0xd5); - addlong(alookup); + addlong((uint32_t)alookup); addbyte(0xf3); /*MOVQ XMM5, XMM4*/ addbyte(0x0f); addbyte(0x7e); @@ -2550,7 +2551,7 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0xd5); addbyte(0x24); addbyte(0xd5); - addlong(aminuslookup); + addlong((uint32_t)aminuslookup); addbyte(0xf3); /*MOVQ XMM5, XMM4*/ addbyte(0x0f); addbyte(0x7e); @@ -2580,7 +2581,7 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0x0f); addbyte(0x7e); addbyte(0x2d); - addlong(&xmm_ff_w); + addlong((uint32_t)&xmm_ff_w); addbyte(0x66); /*PSUBW XMM5, XMM0*/ addbyte(0x0f); addbyte(0xf9); @@ -2624,7 +2625,7 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0x0f); addbyte(0xd5); addbyte(0x25); - addlong(&minus_254); + addlong((uint32_t)&minus_254); addbyte(0xf3); /*MOVQ XMM5, XMM4*/ addbyte(0x0f); addbyte(0x7e); @@ -2664,7 +2665,7 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0xd5); addbyte(0x04); addbyte(0xd5); - addlong(alookup); + addlong((uint32_t)alookup); addbyte(0xf3); /*MOVQ XMM5, XMM0*/ addbyte(0x0f); addbyte(0x7e); @@ -2728,7 +2729,7 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0xd5); addbyte(0x04); addbyte(0xd5); - addlong(aminuslookup); + addlong((uint32_t)aminuslookup); addbyte(0xf3); /*MOVQ XMM5, XMM0*/ addbyte(0x0f); addbyte(0x7e); @@ -2758,7 +2759,7 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0x0f); addbyte(0x7e); addbyte(0x2d); - addlong(&xmm_ff_w); + addlong((uint32_t)&xmm_ff_w); addbyte(0x66); /*PSUBW XMM5, XMM6*/ addbyte(0x0f); addbyte(0xf9); @@ -2911,17 +2912,17 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0xb6); addbyte(0x9c); addbyte(0x33); - addlong(dither2x2 ? dither_g2x2 : dither_g); + addlong(dither2x2 ? (uint32_t)dither_g2x2 : (uint32_t)dither_g); addbyte(0x0f); /*MOVZX ECX, dither_rb[ECX+ESI]*/ addbyte(0xb6); addbyte(0x8c); addbyte(0x31); - addlong(dither2x2 ? dither_rb2x2 : dither_rb); + addlong(dither2x2 ? (uint32_t)dither_rb2x2 : (uint32_t)dither_rb); addbyte(0x0f); /*MOVZX EAX, dither_rb[EAX+ESI]*/ addbyte(0xb6); addbyte(0x84); addbyte(0x30); - addlong(dither2x2 ? dither_rb2x2 : dither_rb); + addlong(dither2x2 ? (uint32_t)dither_rb2x2 : (uint32_t)dither_rb); addbyte(0xc1); /*SHL EBX, 5*/ addbyte(0xe3); addbyte(5); @@ -2972,7 +2973,7 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0x56); } - if (params->fbzMode & FBZ_DEPTH_WMASK) + if ((params->fbzMode & (FBZ_DEPTH_WMASK | FBZ_DEPTH_ENABLE)) == (FBZ_DEPTH_WMASK | FBZ_DEPTH_ENABLE)) { addbyte(0x66); /*MOV AX, new_depth*/ addbyte(0x8b); @@ -3303,7 +3304,7 @@ static void voodoo_codegen_init(voodoo_t *voodoo) #ifdef __linux__ start = (void *)((long)voodoo->codegen_data & pagemask); - len = ((sizeof(voodoo_x86_data_t) * BLOCK_NUM) + pagesize) & pagemask; + len = ((sizeof(voodoo_x86_data_t) * BLOCK_NUM*2) + pagesize) & pagemask; if (mprotect(start, len, PROT_READ | PROT_WRITE | PROT_EXEC) != 0) { perror("mprotect"); diff --git a/src/vid_voodoo_dither.h b/src/VIDEO/vid_voodoo_dither.h similarity index 100% rename from src/vid_voodoo_dither.h rename to src/VIDEO/vid_voodoo_dither.h diff --git a/src/vid_wy700.c b/src/VIDEO/vid_wy700.c similarity index 98% rename from src/vid_wy700.c rename to src/VIDEO/vid_wy700.c index 41bb73ffb..0091ba534 100644 --- a/src/vid_wy700.c +++ b/src/VIDEO/vid_wy700.c @@ -1,17 +1,19 @@ /* Wyse-700 emulation*/ #include -#include "ibm.h" -#include "device.h" -#include "mem.h" -#include "timer.h" +#include "../ibm.h" +#include "../io.h" +#include "../mem.h" +#include "../timer.h" +#include "../device.h" #include "video.h" #include "vid_wy700.h" + #define WY700_XSIZE 1280 #define WY700_YSIZE 800 + void updatewindowsize(int x, int y); -void loadfont(char *s, int format); /* The Wyse 700 is an unusual video card. Though it has an MC6845 CRTC, this @@ -499,7 +501,7 @@ void wy700_textline(wy700_t *wy700) int x; int w = (wy700->wy700_mode == 0) ? 40 : 80; int cw = (wy700->wy700_mode == 0) ? 32 : 16; - uint8_t chr, attr, fg, bg; + uint8_t chr, attr; uint8_t bitmap[2]; uint8_t *fontbase = &fontdatw[0][0]; int blink, c; @@ -591,7 +593,7 @@ void wy700_cgaline(wy700_t *wy700) { int x, c; uint32_t dat; - uint8_t bitmap, ink; + uint8_t ink; uint16_t addr; uint16_t ma = (wy700->cga_crtc[13] | (wy700->cga_crtc[12] << 8)) & 0x3fff; @@ -651,7 +653,7 @@ void wy700_medresline(wy700_t *wy700) { int x, c; uint32_t dat; - uint8_t bitmap, ink; + uint8_t ink; uint32_t addr; addr = (wy700->displine >> 1) * 80 + 4 * wy700->wy700_base; @@ -709,7 +711,7 @@ void wy700_hiresline(wy700_t *wy700) { int x, c; uint32_t dat; - uint8_t bitmap, ink; + uint8_t ink; uint32_t addr; addr = (wy700->displine >> 1) * 160 + 4 * wy700->wy700_base; @@ -765,10 +767,6 @@ void wy700_hiresline(wy700_t *wy700) void wy700_poll(void *p) { wy700_t *wy700 = (wy700_t *)p; - int x, c; - int oldvc; - uint8_t chr, attr; - uint16_t dat; int mode; if (!wy700->linepos) @@ -886,7 +884,7 @@ void *wy700_init() /* Occupy memory between 0xB0000 and 0xBFFFF (moves to 0xA0000 in * high-resolution modes) */ - mem_mapping_add(&wy700->mapping, 0xb0000, 0x10000, wy700_read, NULL, NULL, wy700_write, NULL, NULL, NULL, 0, wy700); + mem_mapping_add(&wy700->mapping, 0xb0000, 0x10000, wy700_read, NULL, NULL, wy700_write, NULL, NULL, NULL, MEM_MAPPING_EXTERNAL, wy700); /* Respond to both MDA and CGA I/O ports */ io_sethandler(0x03b0, 0x000C, wy700_in, NULL, NULL, wy700_out, NULL, NULL, wy700); io_sethandler(0x03d0, 0x0010, wy700_in, NULL, NULL, wy700_out, NULL, NULL, wy700); diff --git a/src/vid_wy700.h b/src/VIDEO/vid_wy700.h similarity index 100% rename from src/vid_wy700.h rename to src/VIDEO/vid_wy700.h diff --git a/src/video.c b/src/VIDEO/video.c similarity index 72% rename from src/video.c rename to src/VIDEO/video.c index 9cd292101..fa541958c 100644 --- a/src/video.c +++ b/src/VIDEO/video.c @@ -4,34 +4,43 @@ #include #include #include -#include 1 -#include "ibm.h" -#include "config.h" -#include "device.h" -#include "mem.h" +#include +#include "../ibm.h" +#include "../cpu/cpu.h" +#include "../io.h" +#include "../mem.h" +#include "../rom.h" +#include "../config.h" +#include "../device.h" +#include "../timer.h" +#include "../win/plat_thread.h" #include "video.h" #include "vid_svga.h" -#include "io.h" -#include "cpu.h" -#include "rom.h" -#include "thread.h" -#include "timer.h" +#ifndef __unix +# include "../win/win_cgapal.h" /*YUCK*/ +#endif + #include "vid_ati18800.h" #include "vid_ati28800.h" #include "vid_ati_mach64.h" #include "vid_cga.h" -#include "vid_cl_ramdac.h" //vid_cl_gd.c needs this +#ifdef DEV_BRANCH +#include "vid_cl_ramdac.h" /* vid_cl_gd.c needs this */ #include "vid_cl_gd.h" +#endif #include "vid_ega.h" #include "vid_et4000.h" #include "vid_et4000w32.h" +#include "vid_genius.h" #include "vid_hercules.h" #include "vid_herculesplus.h" #include "vid_incolor.h" #include "vid_colorplus.h" #include "vid_mda.h" +#ifdef DEV_BRANCH #include "vid_nv_riva128.h" +#endif #include "vid_olivetti_m24.h" #include "vid_oti067.h" #include "vid_paradise.h" @@ -49,55 +58,56 @@ #include "vid_vga.h" #include "vid_wy700.h" + +int vid_cga_contrast = 0; +int cga_palette = 0; + typedef struct { char name[64]; + char internal_name[24]; device_t *device; int legacy_id; } VIDEO_CARD; static VIDEO_CARD video_cards[] = { - {"ATI Graphics Pro Turbo (Mach64 GX)", &mach64gx_device, GFX_MACH64GX}, - {"ATI VGA Charger (ATI-28800-5)", &ati28800_device, GFX_VGACHARGER}, - {"ATI VGA Wonder XL24 (ATI-28800-6)", &ati28800_wonderxl24_device, GFX_VGAWONDERXL24}, - {"ATI VGA Edge-16 (ATI-18800)", &ati18800_device, GFX_VGAEDGE16}, - {"CGA", &cga_device, GFX_CGA}, - {"Cirrus Logic CL-GD5429", &gd5429_device, GFX_CL_GD5429}, - {"Diamond Stealth 32 (Tseng ET4000/w32p)", &et4000w32p_device, GFX_ET4000W32}, - {"Diamond Stealth 64 DRAM (S3 Vision864)", &s3_diamond_stealth64_device,GFX_STEALTH64}, - {"Diamond Stealth 3D 2000 (S3 ViRGE)", &s3_virge_device, GFX_VIRGE}, - {"EGA", &ega_device, GFX_EGA}, - {"Chips & Technologies SuperEGA", &sega_device, GFX_SUPER_EGA}, - {"Compaq ATI VGA Wonder XL (ATI-28800-5)", &compaq_ati28800_device, GFX_VGAWONDERXL}, - {"Compaq EGA", &cpqega_device, GFX_COMPAQ_EGA}, - {"Compaq/Paradise VGA", &cpqvga_device, GFX_COMPAQ_VGA}, - {"Hercules", &hercules_device, GFX_HERCULES}, - {"Hercules Plus", &herculesplus_device, GFX_HERCULESPLUS}, - {"Hercules InColor", &incolor_device, GFX_INCOLOR}, - {"MDA", &mda_device, GFX_MDA}, - {"Miro Crystal S3 Vision964", &s3_miro_vision964_device, GFX_MIRO_VISION964}, - {"Number Nine 9FX (S3 Trio64)", &s3_9fx_device, GFX_N9_9FX}, - {"nVidia RIVA 128 (Experimental)", &riva128_device, GFX_RIVA128}, - {"nVidia RIVA TNT (Experimental)", &rivatnt_device, GFX_RIVATNT}, - {"nVidia TNT2 (Experimental)", &rivatnt2_device, GFX_RIVATNT2}, - - {"OAK OTI-067", &oti067_device, GFX_OTI067}, - {"OAK OTI-077", &oti077_device, GFX_OTI077}, - {"Paradise Bahamas 64 (S3 Vision864)", &s3_bahamas64_device, GFX_BAHAMAS64}, - {"Paradise WD90C11", ¶dise_wd90c11_device, GFX_WD90C11}, - {"Phoenix S3 Vision864", &s3_phoenix_vision864_device,GFX_PHOENIX_VISION864}, - {"Phoenix S3 Trio32", &s3_phoenix_trio32_device, GFX_PHOENIX_TRIO32}, - {"Phoenix S3 Trio64", &s3_phoenix_trio64_device, GFX_PHOENIX_TRIO64}, - {"Plantronics ColorPlus", &colorplus_device, GFX_COLORPLUS}, - {"S3 ViRGE/DX", &s3_virge_375_device, GFX_VIRGEDX}, - {"Trident TGUI9440", &tgui9440_device, GFX_TGUI9440}, - {"Trident TVGA8900D", &tvga8900d_device, GFX_TVGA}, - {"TriGem Unknown Adapter", &trigem_unk_device, GFX_TRIGEM_UNK}, - {"Tseng ET4000AX", &et4000_device, GFX_ET4000}, - {"VGA", &vga_device, GFX_VGA}, - {"Wyse 700", &wy700_device, GFX_WY700}, - {"", NULL, 0} + {"ATI Graphics Pro Turbo (Mach64 GX)", "mach64x", &mach64gx_device, GFX_MACH64GX}, + {"ATI Video Xpression (Mach64 VT2)", "mach64vt2", &mach64vt2_device, GFX_MACH64VT2}, + {"ATI VGA Charger (ATI-28800-5)", "ati28800", &ati28800_device, GFX_VGACHARGER}, + {"ATI VGA Wonder XL24 (ATI-28800-6)", "ati28800w", &ati28800_wonderxl24_device, GFX_VGAWONDERXL24}, + {"ATI VGA Edge-16 (ATI-18800)", "ati18800", &ati18800_device, GFX_VGAEDGE16}, + {"CGA", "cga", &cga_device, GFX_CGA}, + {"Diamond Stealth 32 (Tseng ET4000/w32p)", "stealth32", &et4000w32p_device, GFX_ET4000W32}, + {"Diamond Stealth 64 DRAM (S3 Trio64)", "stealth64d", &s3_diamond_stealth64_device,GFX_STEALTH64}, + {"Diamond Stealth 3D 2000 (S3 ViRGE)", "stealth3d_2000", &s3_virge_device, GFX_VIRGE}, + {"Diamond Stealth 3D 3000 (S3 ViRGE/VX)", "stealth3d_3000", &s3_virge_988_device, GFX_VIRGEVX}, + {"EGA", "ega", &ega_device, GFX_EGA}, + {"Chips & Technologies SuperEGA", "superega", &sega_device, GFX_SUPER_EGA}, + {"Compaq ATI VGA Wonder XL (ATI-28800-5)", "compaq_ati28800", &compaq_ati28800_device, GFX_VGAWONDERXL}, + {"Compaq EGA", "compaq_ega", &cpqega_device, GFX_COMPAQ_EGA}, + {"Hercules", "hercules", &hercules_device, GFX_HERCULES}, + {"Hercules Plus", "hercules_plus", &herculesplus_device, GFX_HERCULESPLUS}, + {"Hercules InColor", "incolor", &incolor_device, GFX_INCOLOR}, + {"MDA", "mda", &mda_device, GFX_MDA}, + {"MDSI Genius", "genius", &genius_device, GFX_GENIUS}, + {"Number Nine 9FX (S3 Trio64)", "n9_9fx", &s3_9fx_device, GFX_N9_9FX}, + {"OAK OTI-067", "oti067", &oti067_device, GFX_OTI067}, + {"OAK OTI-077", "oti077", &oti077_device, GFX_OTI077}, + {"Paradise Bahamas 64 (S3 Vision864)", "bahamas64", &s3_bahamas64_device, GFX_BAHAMAS64}, + {"Paradise WD90C11", "wd90c11", ¶dise_wd90c11_device, GFX_WD90C11}, + {"Phoenix S3 Vision864", "px_vision864", &s3_phoenix_vision864_device,GFX_PHOENIX_VISION864}, + {"Phoenix S3 Trio32", "px_trio32", &s3_phoenix_trio32_device, GFX_PHOENIX_TRIO32}, + {"Phoenix S3 Trio64", "px_trio64", &s3_phoenix_trio64_device, GFX_PHOENIX_TRIO64}, + {"Plantronics ColorPlus", "plantronics", &colorplus_device, GFX_COLORPLUS}, + {"S3 ViRGE/DX", "virge375", &s3_virge_375_device, GFX_VIRGEDX}, + {"S3 ViRGE/DX (VBE 2.0)", "virge375_vbe20", &s3_virge_375_4_device, GFX_VIRGEDX4}, + {"Trident TGUI9440", "tgui9440", &tgui9440_device, GFX_TGUI9440}, + {"Trident TVGA8900D", "tvga8900d", &tvga8900d_device, GFX_TVGA}, + {"Tseng ET4000AX", "et4000ax", &et4000_device, GFX_ET4000}, + {"VGA", "vga", &vga_device, GFX_VGA}, + {"Wyse 700", "wy700", &wy700_device, GFX_WY700}, + {"", "", NULL, 0} }; int video_card_available(int card) @@ -156,6 +166,25 @@ int video_new_to_old(int card) return video_cards[card].legacy_id; } +char *video_get_internal_name(int card) +{ + return video_cards[card].internal_name; +} + +int video_get_video_from_internal_name(char *s) +{ + int c = 0; + + while (video_cards[c].legacy_id != -1) + { + if (!strcmp(video_cards[c].internal_name, s)) + return video_cards[c].legacy_id; + c++; + } + + return 0; +} + int video_fullscreen = 0, video_fullscreen_scale, video_fullscreen_first; uint32_t *video_6to8, *video_15to32, *video_16to32; @@ -172,8 +201,8 @@ uint8_t edatlookup[4][4]; int enable_overscan; int overscan_x, overscan_y; + int force_43; -int enable_flash; /*Video timing settings - @@ -254,6 +283,11 @@ void video_init() { pclog("Video_init %i %i\n",romset,gfxcard); +#ifndef __unix + cga_palette = 0; + cgapal_rebuild(); +#endif + switch (romset) { case ROM_IBMPCJR: @@ -302,6 +336,10 @@ void video_init() return; case ROM_IBMPS1_2011: + case ROM_IBMPS2_M30_286: + case ROM_IBMPS2_M50: + case ROM_IBMPS2_M55SX: + case ROM_IBMPS2_M80: device_add(&ps1vga_device); return; @@ -318,14 +356,15 @@ BITMAP *buffer, *buffer32; uint8_t fontdat[256][8]; uint8_t fontdatm[256][16]; uint8_t fontdatw[512][32]; /* Wyse700 font */ +uint8_t fontdat8x12[256][16]; /* MDSI Genius font */ int xsize=1,ysize=1; PALETTE cgapal; -void loadfont(char *s, int format) +void loadfont(wchar_t *s, int format) { - FILE *f=romfopen(s,"rb"); + FILE *f=romfopen(s,L"rb"); int c,d; if (!f) { @@ -401,6 +440,16 @@ void loadfont(char *s, int format) } } break; + case 4: /* MDSI Genius */ + for (c=0;c<256;c++) + { + for (d=0;d<16;d++) + { + fontdat8x12[c][d]=getc(f); + } + } + break; + } fclose(f); } @@ -422,7 +471,7 @@ static void blit_thread(void *param); int calc_6to8(int c) { int ic, i8; - double dc, d8; + double d8; ic = c; if (ic == 64) { @@ -432,7 +481,6 @@ int calc_6to8(int c) { ic &= 0x3f; } - dc = (double) ic; d8 = (ic / 63.0) * 255.0; i8 = (int) d8; return i8 & 0xff; @@ -475,9 +523,9 @@ void initvideo() int c, d, e; /* Account for overscan. */ - buffer32 = create_bitmap(2064, 2056); + buffer32 = create_bitmap(2048, 2048); - buffer = create_bitmap(2064, 2056); + buffer = create_bitmap(2048, 2048); for (c = 0; c < 64; c++) { @@ -512,7 +560,6 @@ void initvideo() if (d & 1) edatlookup[c][d] |= 2; if (c & 2) edatlookup[c][d] |= 0x10; if (d & 2) edatlookup[c][d] |= 0x20; -// printf("Edat %i,%i now %02X\n",c,d,edatlookup[c][d]); } } @@ -643,21 +690,21 @@ void take_screenshot() #else time_t now; struct tm *info; -char screenshot_fn_partial[2048]; -char screenshot_fn[4096]; +wchar_t screenshot_fn_partial[2048]; +wchar_t screenshot_fn[4096]; void take_screenshot() { if ((vid_api < 0) || (vid_api > 1)) return; time(&now); info = localtime(&now); - memset(screenshot_fn, 0, 4096); - memset(screenshot_fn_partial, 0, 2048); + memset(screenshot_fn, 0, 8192); + memset(screenshot_fn_partial, 0, 4096); pclog("Video API is: %i\n", vid_api); if (vid_api == 1) { - strftime(screenshot_fn_partial, 2048, "screenshots\\%Y%m%d_%H%M%S.png", info); - append_filename(screenshot_fn, pcempath, screenshot_fn_partial, 4095); + wcsftime(screenshot_fn_partial, 2048, L"screenshots\\%Y%m%d_%H%M%S.png", info); + append_filename_w(screenshot_fn, pcempath, screenshot_fn_partial, 4095); if (video_fullscreen) { d3d_fs_take_screenshot(screenshot_fn); @@ -670,8 +717,8 @@ void take_screenshot() } else if (vid_api == 0) { - strftime(screenshot_fn_partial, 1024, "screenshots\\%Y%m%d_%H%M%S.bmp", info); - append_filename(screenshot_fn, pcempath, screenshot_fn_partial, 4095); + wcsftime(screenshot_fn_partial, 2048, L"screenshots\\%Y%m%d_%H%M%S.bmp", info); + append_filename_w(screenshot_fn, pcempath, screenshot_fn_partial, 4095); if (video_fullscreen) { ddraw_fs_take_screenshot(screenshot_fn); diff --git a/src/video.h b/src/VIDEO/video.h similarity index 77% rename from src/video.h rename to src/VIDEO/video.h index dc9f24eba..f9b7fef85 100644 --- a/src/video.h +++ b/src/VIDEO/video.h @@ -11,7 +11,7 @@ typedef struct { int w, h; uint8_t *dat; - uint8_t *line[0]; + uint8_t *line[]; } BITMAP; extern BITMAP *screen; @@ -39,6 +39,8 @@ int video_card_has_config(int card); int video_card_getid(char *s); int video_old_to_new(int card); int video_new_to_old(int card); +char *video_get_internal_name(int card); +int video_get_video_from_internal_name(char *s); extern int video_fullscreen, video_fullscreen_scale, video_fullscreen_first; @@ -79,10 +81,9 @@ extern void (*video_blit_memtoscreen_8_func)(int x, int y, int w, int h); /* Enable EGA/(S)VGA overscan border. */ extern int enable_overscan; extern int overscan_x, overscan_y; + /* Forcibly stretch emulated video output to 4:3 or not. */ extern int force_43; -/* Enable disk activity flash. */ -extern int enable_flash; extern int video_timing_b, video_timing_w, video_timing_l; extern int video_speed; @@ -101,10 +102,26 @@ extern "C" { #endif void take_screenshot(); -void d3d_take_screenshot(char *fn); -void d3d_fs_take_screenshot(char *fn); -void ddraw_take_screenshot(char *fn); -void ddraw_fs_take_screenshot(char *fn); +void d3d_take_screenshot(wchar_t *fn); +void d3d_fs_take_screenshot(wchar_t *fn); +void ddraw_take_screenshot(wchar_t *fn); +void ddraw_fs_take_screenshot(wchar_t *fn); #ifdef __cplusplus } #endif + +extern int cga_palette; +extern int vid_cga_contrast; + +void loadfont(wchar_t *s, int format); +void initvideo(); +void video_init(); +void closevideo(); +void video_updatetiming(); + +void hline(BITMAP *b, int x1, int y, int x2, uint32_t col); +void updatewindowsize(int x, int y); + +#ifdef ENABLE_VRAM_DUMP +void svga_dump_vram(); +#endif diff --git a/src/86Box.manifest b/src/WIN/86Box.manifest similarity index 87% rename from src/86Box.manifest rename to src/WIN/86Box.manifest index 7c75fcf37..be8c16756 100644 --- a/src/86Box.manifest +++ b/src/WIN/86Box.manifest @@ -1,12 +1,12 @@  -Your application description here. +Emulator for X86-based systems. + * Fred N. van Kempen, + * Copyright 2016-2017 Miran Grca. + */ +#include +#define IN_RESOURCE_H +#include "resource.h" +#include "../86box.h" +#undef IN_RESOURCE_H + +#define APSTUDIO_READONLY_SYMBOLS +#define APSTUDIO_HIDDEN_SYMBOLS +#include "windows.h" +#undef APSTUDIO_HIDDEN_SYMBOLS +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Menu +// + +MAINMENU MENU DISCARDABLE +BEGIN + POPUP "&Action" + BEGIN + MENUITEM "&Hard Reset", IDM_ACTION_HRESET + MENUITEM "&Ctrl+Alt+Del\tCtrl+F12", IDM_ACTION_RESET_CAD + MENUITEM SEPARATOR + MENUITEM "E&xit", IDM_ACTION_EXIT + END + POPUP "&View" + BEGIN + MENUITEM "&Resizeable window", IDM_VID_RESIZE + MENUITEM "R&emember size && position", IDM_VID_REMEMBER + MENUITEM SEPARATOR + POPUP "Re&nderer" + BEGIN + MENUITEM "&DirectDraw", IDM_VID_DDRAW + MENUITEM "Direct&3D 9", IDM_VID_D3D + END + MENUITEM SEPARATOR + POPUP "&Window scale factor" + BEGIN + MENUITEM "&0.5x", IDM_VID_SCALE_1X + MENUITEM "&1x", IDM_VID_SCALE_2X + MENUITEM "1.&5x", IDM_VID_SCALE_3X + MENUITEM "&2x", IDM_VID_SCALE_4X + END + MENUITEM SEPARATOR + MENUITEM "&Fullscreen\tCtrl+Alt+PageUP", IDM_VID_FULLSCREEN + POPUP "Fullscreen &stretch mode" + BEGIN + MENUITEM "&Full screen stretch", IDM_VID_FS_FULL + MENUITEM "&4:3", IDM_VID_FS_43 + MENUITEM "&Square pixels", IDM_VID_FS_SQ + MENUITEM "&Integer scale", IDM_VID_FS_INT + END + POPUP "E&GA/(S)VGA settings" + BEGIN + MENUITEM "&Inverted VGA monitor", IDM_VID_INVERT + MENUITEM "E&GA/(S)VGA overscan", IDM_VID_OVERSCAN + END + MENUITEM SEPARATOR + MENUITEM "F&orce 4:3 display ratio", IDM_VID_FORCE43 + MENUITEM "Change contrast for &monochrome display", IDM_VID_CGACON + END + POPUP "&Tools" + BEGIN + MENUITEM "&Settings...", IDM_CONFIG + MENUITEM SEPARATOR + MENUITEM "&Load configuration...", IDM_CONFIG_LOAD + MENUITEM "&Save configuration...", IDM_CONFIG_SAVE + MENUITEM SEPARATOR + MENUITEM "S&tatus", IDM_STATUS + MENUITEM "Take s&creenshot\tCtrl+F11", IDM_ACTION_SCREENSHOT + END +#if defined(ENABLE_LOG_TOGGLES) || defined(ENABLE_LOG_COMMANDS) + POPUP "&Logging" + BEGIN +# ifdef ENABLE_BUSLOGIC_LOG + MENUITEM "Enable BusLogic logs\tCtrl+F4", IDM_LOG_BUSLOGIC +# endif +# ifdef ENABLE_CDROM_LOG + MENUITEM "Enable CD-ROM logs\tCtrl+F5", IDM_LOG_CDROM +# endif +# ifdef ENABLE_D86F_LOG + MENUITEM "Enable floppy (86F) logs\tCtrl+F6", IDM_LOG_D86F +# endif +# ifdef ENABLE_FDC_LOG + MENUITEM "Enable floppy controller logs\tCtrl+F7", IDM_LOG_FDC +# endif +# ifdef ENABLE_IDE_LOG + MENUITEM "Enable IDE logs\tCtrl+F8", IDM_LOG_IDE +# endif +# ifdef ENABLE_SERIAL_LOG + MENUITEM "Enable Serial Port logs\tCtrl+F3", IDM_LOG_SERIAL +# endif +# ifdef ENABLE_NIC_LOG + MENUITEM "Enable Network logs\tCtrl+F9", IDM_LOG_NIC +# endif +# ifdef ENABLE_LOG_COMMANDS +# ifdef ENABLE_LOG_TOGGLES + MENUITEM SEPARATOR +# endif +# ifdef ENABLE_LOG_BREAKPOINT + MENUITEM "&Log breakpoint\tCtrl+F10", IDM_LOG_BREAKPOINT +# endif +# ifdef ENABLE_VRAM_DUMP + MENUITEM "Dump &video RAM\tCtrl+F1", IDM_DUMP_VRAM +# endif +# endif + END +#endif + POPUP "&Help" + BEGIN + MENUITEM "&About 86Box...", IDM_ABOUT + END +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Accelerator +// + +MAINACCEL ACCELERATORS MOVEABLE PURE +BEGIN +#ifdef ENABLE_VRAM_DUMP + VK_F1, IDM_DUMP_VRAM, CONTROL, VIRTKEY +#endif +#ifdef ENABLE_SERIAL_LOG + VK_F3, IDM_LOG_SERIAL, CONTROL, VIRTKEY +#endif +#ifdef ENABLE_BUSLOGIC_LOG + VK_F4, IDM_LOG_BUSLOGIC, CONTROL, VIRTKEY +#endif +#ifdef ENABLE_CDROM_LOG + VK_F5, IDM_LOG_CDROM, CONTROL, VIRTKEY +#endif +#ifdef ENABLE_D86F_LOG + VK_F6, IDM_LOG_D86F, CONTROL, VIRTKEY +#endif +#ifdef ENABLE_FDC_LOG + VK_F7, IDM_LOG_FDC, CONTROL, VIRTKEY +#endif +#ifdef ENABLE_IDE_LOG + VK_F8, IDM_LOG_IDE, CONTROL, VIRTKEY +#endif +#ifdef ENABLE_NIC_LOG + VK_F9, IDM_LOG_NIC, CONTROL, VIRTKEY +#endif +#ifdef ENABLE_LOG_BREAKPOINT + VK_F10, IDM_LOG_BREAKPOINT, CONTROL, VIRTKEY +#endif + VK_PRIOR,IDM_VID_FULLSCREEN, VIRTKEY, CONTROL , ALT + VK_F11, IDM_ACTION_SCREENSHOT, VIRTKEY, CONTROL + VK_F12, IDM_ACTION_RESET_CAD, VIRTKEY, CONTROL +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// +DLG_ABOUT DIALOG DISCARDABLE 0, 0, 209, 114 +STYLE DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "About 86Box" +FONT 9, "Segoe UI" +BEGIN + DEFPUSHBUTTON "OK",IDOK,129,94,71,12 + ICON 100,IDC_ABOUT_ICON,7,7,20,20 + LTEXT "86Box v2.00 - A fork of PCem\n\nAuthors: Sarah Walker, Miran Grca, Fred N. van Kempen (waltje), SA1988, MoochMcGee, reenigne, leilei, JohnElliott, greatpsycho, and others.\n\nReleased under the GNU General Public License version 2. See LICENSE for more information.", + IDC_ABOUT_ICON,54,7,146,73 + CONTROL "",IDC_ABOUT_ICON,"Static",SS_BLACKFRAME | SS_SUNKEN,0, + 86,208,1 +END + +DLG_STATUS DIALOG DISCARDABLE 0, 0, 186, 386 +STYLE DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Status" +FONT 9, "Segoe UI" +BEGIN + LTEXT "1",IDT_SDEVICE,16,16,180,1000 + LTEXT "1",IDT_STEXT,16,186,180,1000 +END + +DLG_CONFIG DIALOG DISCARDABLE 0, 0, 366, 241 +STYLE DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "86Box Settings" +FONT 9, "Segoe UI" +BEGIN + DEFPUSHBUTTON "OK",IDOK,246,220,50,14 + PUSHBUTTON "Cancel",IDCANCEL,307,220,50,14 + CONTROL "List2",IDC_SETTINGSCATLIST,"SysListView32",LVS_LIST | + LVS_SHOWSELALWAYS | LVS_SINGLESEL | WS_BORDER | WS_TABSTOP,7,7,90,197 + CONTROL "",-1,"Static",SS_BLACKFRAME | SS_SUNKEN,1,211,363,1 +/* Leave this commented out until we get into localization. */ +#if 0 + LTEXT "Language:",IDT_1700,7,222,41,10 + COMBOBOX IDC_COMBO_LANG,48,221,108,120,CBS_DROPDOWN | WS_VSCROLL | + WS_TABSTOP +#endif +END + +DLG_CFG_MACHINE DIALOG DISCARDABLE 97, 0, 267, 132 +STYLE DS_CONTROL | WS_CHILD +FONT 9, "Segoe UI" +BEGIN + COMBOBOX IDC_COMBO_MACHINE,71,7,138,120,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "Machine:",IDT_1701,7,8,60,10 + PUSHBUTTON "Configure",IDC_CONFIGURE_MACHINE,214,7,46,12 + COMBOBOX IDC_COMBO_CPU_TYPE,71,25,45,120,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "CPU type:",IDT_1702,7,26,59,10 + COMBOBOX IDC_COMBO_CPU,145,25,115,120,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "CPU:",IDT_1704,124,26,18,10 + COMBOBOX IDC_COMBO_WS,71,44,189,120,CBS_DROPDOWNLIST | WS_VSCROLL | + WS_TABSTOP + LTEXT "Wait states:",IDT_1703,7,45,60,10 + EDITTEXT IDC_MEMTEXT,70,63,45,12,ES_AUTOHSCROLL | ES_NUMBER + CONTROL "",IDC_MEMSPIN,"msctls_updown32",UDS_SETBUDDYINT | + UDS_ALIGNRIGHT | UDS_ARROWKEYS | UDS_NOTHOUSANDS,113,63, + 12,12 + LTEXT "MB",IDT_1705,123,64,10,10 + LTEXT "Memory:",IDT_1706,7,64,30,10 + LTEXT "NVR Path:",IDT_1700,7,83,60,10 + EDITTEXT IDC_EDIT_NVR_PATH,71,82,138,12 + PUSHBUTTON "&Specify...",IDC_BUTTON_NVR_PATH,214,82,46,12 + CONTROL "Dynamic Recompiler",IDC_CHECK_DYNAREC,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,7,100,94,10 + CONTROL "Enable FPU",IDC_CHECK_FPU,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,147,100,113,10 + CONTROL "Enable time sync",IDC_CHECK_SYNC,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,7,115,102,10 +END + +DLG_CFG_VIDEO DIALOG DISCARDABLE 97, 0, 267, 63 +STYLE DS_CONTROL | WS_CHILD +FONT 9, "Segoe UI" +BEGIN + LTEXT "Video:",IDT_1707,7,8,55,10 + COMBOBOX IDC_COMBO_VIDEO,71,7,140,120,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Configure",IDC_CONFIGURE_VID,214,7,46,12 + COMBOBOX IDC_COMBO_VIDEO_SPEED,71,25,189,120,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "Video speed:",IDT_1708,7,26,58,10 + CONTROL "Voodoo Graphics",IDC_CHECK_VOODOO,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,7,45,199,10 + PUSHBUTTON "Configure",IDC_BUTTON_VOODOO,214,44,46,12 +END + +DLG_CFG_INPUT DIALOG DISCARDABLE 97, 0, 267, 65 +STYLE DS_CONTROL | WS_CHILD +FONT 9, "Segoe UI" +BEGIN + LTEXT "Mouse :",IDT_1709,7,8,57,10 + COMBOBOX IDC_COMBO_MOUSE,71,7,189,120,CBS_DROPDOWN | WS_VSCROLL | + WS_TABSTOP + LTEXT "Joystick :",IDT_1710,7,26,58,10 + COMBOBOX IDC_COMBO_JOYSTICK,71,25,189,120,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Joystick 1...",IDC_JOY1,7,44,50,14 + PUSHBUTTON "Joystick 2...",IDC_JOY2,74,44,50,14 + PUSHBUTTON "Joystick 3...",IDC_JOY3,141,44,50,14 + PUSHBUTTON "Joystick 4...",IDC_JOY4,209,44,50,14 +END + +DLG_CFG_SOUND DIALOG DISCARDABLE 97, 0, 267, 116 +STYLE DS_CONTROL | WS_CHILD +FONT 9, "Segoe UI" +BEGIN + COMBOBOX IDC_COMBO_SOUND,71,7,140,120,CBS_DROPDOWNLIST | WS_VSCROLL | + WS_TABSTOP + LTEXT "Sound card:",IDT_1711,7,8,59,10 + PUSHBUTTON "Configure",IDC_CONFIGURE_SND,214,7,46,12 + + COMBOBOX IDC_COMBO_MIDI,71,25,140,120,CBS_DROPDOWNLIST | WS_VSCROLL | + WS_TABSTOP + LTEXT "MIDI Out Device:",IDT_1712,7,26,59,10 + PUSHBUTTON "Configure",IDC_CONFIGURE_MIDI,214,25,46,12 + + CONTROL "Standalone MPU-401",IDC_CHECK_MPU401,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,7,45,199,10 + PUSHBUTTON "Configure",IDC_CONFIGURE_MPU401,214,44,46,12 + + CONTROL "Innovation SSI-2001",IDC_CHECK_SSI,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,7,63,94,10 + CONTROL "CMS / Game Blaster",IDC_CHECK_CMS,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,147,63,94,10 + + CONTROL "Gravis Ultrasound",IDC_CHECK_GUS,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,7,81,94,10 + CONTROL "Use Nuked OPL",IDC_CHECK_NUKEDOPL,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,147,81,94,10 + + CONTROL "Use FLOAT32 sound",IDC_CHECK_FLOAT,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,7,99,94,10 +END + +DLG_CFG_NETWORK DIALOG DISCARDABLE 97, 0, 267, 63 +STYLE DS_CONTROL | WS_CHILD +FONT 9, "Segoe UI" +BEGIN + LTEXT "Network type:",IDT_1713,7,8,59,10 + COMBOBOX IDC_COMBO_NET_TYPE,71,7,189,120,CBS_DROPDOWNLIST | WS_VSCROLL | + WS_TABSTOP + + LTEXT "PCap device:",IDT_1714,7,26,59,10 + COMBOBOX IDC_COMBO_PCAP,71,25,189,120,CBS_DROPDOWNLIST | WS_VSCROLL | + WS_TABSTOP + + LTEXT "Network adapter:",IDT_1715,7,44,59,10 + COMBOBOX IDC_COMBO_NET,71,43,140,120,CBS_DROPDOWNLIST | WS_VSCROLL | + WS_TABSTOP + PUSHBUTTON "Configure",IDC_CONFIGURE_NET,214,43,46,12 +END + +DLG_CFG_PERIPHERALS DIALOG DISCARDABLE 97, 0, 267, 115 +STYLE DS_CONTROL | WS_CHILD +FONT 9, "Segoe UI" +BEGIN + LTEXT "SCSI Controller:",IDT_1716,7,8,59,10 + COMBOBOX IDC_COMBO_SCSI,71,7,140,120,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Configure",IDC_CONFIGURE_SCSI,214,7,46,12 + + LTEXT "HD Controller:",IDT_1717,7,26,61,10 + COMBOBOX IDC_COMBO_HDC,71,25,189,120,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + + LTEXT "Tertiary IDE:",IDT_1718,7,44,61,10 + COMBOBOX IDC_COMBO_IDE_TER,71,43,189,120,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + + LTEXT "Quaternary IDE:",IDT_1719,7,62,61,10 + COMBOBOX IDC_COMBO_IDE_QUA,71,61,189,120,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + + CONTROL "Serial port 1",IDC_CHECK_SERIAL1,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,7,80,94,10 + CONTROL "Serial port 2",IDC_CHECK_SERIAL2,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,147,80,94,10 + + CONTROL "Parallel port",IDC_CHECK_PARALLEL,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,7,98,94,10 + CONTROL "ISABugger device",IDC_CHECK_BUGGER,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,147,98,94,10 +END + +DLG_CFG_HARD_DISKS DIALOG DISCARDABLE 97, 0, 267, 154 +STYLE DS_CONTROL | WS_CHILD +FONT 9, "Segoe UI" +BEGIN + CONTROL "List1",IDC_LIST_HARD_DISKS,"SysListView32",LVS_REPORT | + LVS_SHOWSELALWAYS | LVS_SINGLESEL | WS_BORDER | + WS_TABSTOP,7,18,253,92 + LTEXT "Hard disks:",IDT_1720,7,7,34,8 + PUSHBUTTON "&New...",IDC_BUTTON_HDD_ADD_NEW,60,137,62,10 + PUSHBUTTON "&Existing...",IDC_BUTTON_HDD_ADD,129,137,62,10 + PUSHBUTTON "&Remove",IDC_BUTTON_HDD_REMOVE,198,137,62,10 + COMBOBOX IDC_COMBO_HD_BUS,33,117,90,12,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "Bus:",IDT_1721,7,118,24,8 + COMBOBOX IDC_COMBO_HD_CHANNEL,170,117,90,12,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "Channel:",IDT_1722,131,118,38,8 + COMBOBOX IDC_COMBO_HD_ID,170,117,22,12,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "ID:",IDT_1723,131,118,38,8 + COMBOBOX IDC_COMBO_HD_LUN,239,117,22,12,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "LUN:",IDT_1724,200,118,38,8 + COMBOBOX IDC_COMBO_HD_CHANNEL_IDE,170,117,90,12,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP +END + +DLG_CFG_HARD_DISKS_ADD DIALOG DISCARDABLE 0, 0, 219, 111 +STYLE DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Add Hard Disk" +FONT 9, "Segoe UI" +BEGIN + DEFPUSHBUTTON "OK",IDOK,55,89,50,14 + PUSHBUTTON "Cancel",IDCANCEL,112,89,50,14 + EDITTEXT IDC_EDIT_HD_FILE_NAME,7,16,153,12 + PUSHBUTTON "&Specify...",IDC_CFILE,167,16,44,12 + EDITTEXT IDC_EDIT_HD_SPT,183,34,28,12 + EDITTEXT IDC_EDIT_HD_HPC,112,34,28,12 + EDITTEXT IDC_EDIT_HD_CYL,42,34,28,12 + EDITTEXT IDC_EDIT_HD_SIZE,42,52,28,12 + COMBOBOX IDC_COMBO_HD_TYPE,113,52,98,12,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "Sectors:",IDT_1726,154,35,27,10 + LTEXT "Heads:",IDT_1727,81,35,29,8 + LTEXT "Cylinders:",IDT_1728,7,35,32,12 + LTEXT "Size (MB):",IDT_1729,7,54,33,8 + LTEXT "Type:",IDT_1730,86,54,24,8 + LTEXT "File name:",IDT_1731,7,7,204,9 + COMBOBOX IDC_COMBO_HD_BUS,33,71,58,12,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "Bus:",IDT_1721,7,72,24,8 + COMBOBOX IDC_COMBO_HD_CHANNEL,134,71,77,12,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "Channel:",IDT_1722,99,72,34,8 + COMBOBOX IDC_COMBO_HD_ID,133,71,26,12,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "ID:",IDT_1723,117,72,15,8 + COMBOBOX IDC_COMBO_HD_LUN,185,71,26,12,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "LUN:",IDT_1724,168,72,15,8 + COMBOBOX IDC_COMBO_HD_CHANNEL_IDE,134,71,77,12,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP +END + +DLG_CFG_REMOVABLE_DEVICES DIALOG DISCARDABLE 97, 0, 267, 202 +STYLE DS_CONTROL | WS_CHILD +FONT 9, "Segoe UI" +BEGIN + CONTROL "List1",IDC_LIST_FLOPPY_DRIVES,"SysListView32", + LVS_REPORT | LVS_SHOWSELALWAYS | LVS_SINGLESEL | WS_BORDER | + WS_TABSTOP,7,18,253,60 + LTEXT "Floppy drives:",IDT_1737,7,7,43,8 + COMBOBOX IDC_COMBO_FD_TYPE,33,85,90,12,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "Type:",IDT_1738,7,86,24,8 + CONTROL "Turbo timings (no accuracy)",IDC_CHECKTURBO,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,131,86,129,10 + CONTROL "List1",IDC_LIST_CDROM_DRIVES,"SysListView32",LVS_REPORT | + LVS_SHOWSELALWAYS | LVS_SINGLESEL | WS_BORDER | + WS_TABSTOP,7,116,253,60 + LTEXT "CD-ROM drives:",IDT_1739,7,106,50,8 + COMBOBOX IDC_COMBO_CD_BUS,33,183,90,12,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "Bus:",IDT_1740,7,184,24,8 + COMBOBOX IDC_COMBO_CD_ID,170,183,22,12,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "ID:",IDT_1741,131,184,38,8 + COMBOBOX IDC_COMBO_CD_LUN,239,183,22,12,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "LUN:",IDT_1742,200,184,38,8 + COMBOBOX IDC_COMBO_CD_CHANNEL_IDE,170,183,90,12,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "Channel:",IDT_1743,131,184,38,8 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// 24 +// + +1 24 MOVEABLE PURE "86Box.manifest" + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +#ifdef RELEASE_BUILD +/* Icon by Devcore - https://commons.wikimedia.org/wiki/File:Icon_PC_256x256.png */ +100 ICON DISCARDABLE "WIN/ICONS/86Box-RB.ico" +#else +/* Icon by Devcore - https://commons.wikimedia.org/wiki/File:Icon_PC2_256x256.png */ +100 ICON DISCARDABLE "WIN/ICONS/86Box.ico" +#endif +128 ICON DISCARDABLE "WIN/ICONS/floppy_525_1dd.ico" +129 ICON DISCARDABLE "WIN/ICONS/floppy_525_1dd_active.ico" +130 ICON DISCARDABLE "WIN/ICONS/floppy_525_2dd.ico" +131 ICON DISCARDABLE "WIN/ICONS/floppy_525_2dd_active.ico" +132 ICON DISCARDABLE "WIN/ICONS/floppy_525_2qd.ico" +133 ICON DISCARDABLE "WIN/ICONS/floppy_525_2qd_active.ico" +134 ICON DISCARDABLE "WIN/ICONS/floppy_525_2hd.ico" +135 ICON DISCARDABLE "WIN/ICONS/floppy_525_2hd_active.ico" +144 ICON DISCARDABLE "WIN/ICONS/floppy_35_1dd.ico" +145 ICON DISCARDABLE "WIN/ICONS/floppy_35_1dd_active.ico" +146 ICON DISCARDABLE "WIN/ICONS/floppy_35_2dd.ico" +147 ICON DISCARDABLE "WIN/ICONS/floppy_35_2dd_active.ico" +150 ICON DISCARDABLE "WIN/ICONS/floppy_35_2hd.ico" +151 ICON DISCARDABLE "WIN/ICONS/floppy_35_2hd_active.ico" +152 ICON DISCARDABLE "WIN/ICONS/floppy_35_2ed.ico" +153 ICON DISCARDABLE "WIN/ICONS/floppy_35_2ed_active.ico" +160 ICON DISCARDABLE "WIN/ICONS/cdrom_atapi.ico" +161 ICON DISCARDABLE "WIN/ICONS/cdrom_atapi_active.ico" +162 ICON DISCARDABLE "WIN/ICONS/cdrom_atapi_dma.ico" +163 ICON DISCARDABLE "WIN/ICONS/cdrom_atapi_dma_active.ico" +164 ICON DISCARDABLE "WIN/ICONS/cdrom_scsi.ico" +165 ICON DISCARDABLE "WIN/ICONS/cdrom_scsi_active.ico" +176 ICON DISCARDABLE "WIN/ICONS/hard_disk_removable_scsi.ico" +177 ICON DISCARDABLE "WIN/ICONS/hard_disk_removable_scsi_active.ico" +192 ICON DISCARDABLE "WIN/ICONS/hard_disk_mfm.ico" +193 ICON DISCARDABLE "WIN/ICONS/hard_disk_mfm_active.ico" +194 ICON DISCARDABLE "WIN/ICONS/hard_disk_xtide.ico" +195 ICON DISCARDABLE "WIN/ICONS/hard_disk_xtide_active.ico" +196 ICON DISCARDABLE "WIN/ICONS/hard_disk_rll.ico" +197 ICON DISCARDABLE "WIN/ICONS/hard_disk_rll_active.ico" +198 ICON DISCARDABLE "WIN/ICONS/hard_disk.ico" +199 ICON DISCARDABLE "WIN/ICONS/hard_disk_active.ico" +200 ICON DISCARDABLE "WIN/ICONS/hard_disk_ide.ico" +201 ICON DISCARDABLE "WIN/ICONS/hard_disk_ide_active.ico" +202 ICON DISCARDABLE "WIN/ICONS/hard_disk_scsi.ico" +203 ICON DISCARDABLE "WIN/ICONS/hard_disk_scsi_active.ico" +256 ICON DISCARDABLE "WIN/ICONS/machine.ico" +257 ICON DISCARDABLE "WIN/ICONS/video.ico" +258 ICON DISCARDABLE "WIN/ICONS/input_devices.ico" +259 ICON DISCARDABLE "WIN/ICONS/sound.ico" +260 ICON DISCARDABLE "WIN/ICONS/network.ico" +261 ICON DISCARDABLE "WIN/ICONS/other_peripherals.ico" +262 ICON DISCARDABLE "WIN/ICONS/hard_disk.ico" +263 ICON DISCARDABLE "WIN/ICONS/removable_devices.ico" +384 ICON DISCARDABLE "WIN/ICONS/floppy_525_1dd_empty.ico" +385 ICON DISCARDABLE "WIN/ICONS/floppy_525_1dd_empty_active.ico" +386 ICON DISCARDABLE "WIN/ICONS/floppy_525_2dd_empty.ico" +387 ICON DISCARDABLE "WIN/ICONS/floppy_525_2dd_empty_active.ico" +388 ICON DISCARDABLE "WIN/ICONS/floppy_525_2qd_empty.ico" +389 ICON DISCARDABLE "WIN/ICONS/floppy_525_2qd_empty_active.ico" +390 ICON DISCARDABLE "WIN/ICONS/floppy_525_2hd_empty.ico" +391 ICON DISCARDABLE "WIN/ICONS/floppy_525_2hd_empty_active.ico" +400 ICON DISCARDABLE "WIN/ICONS/floppy_35_1dd_empty.ico" +401 ICON DISCARDABLE "WIN/ICONS/floppy_35_1dd_empty_active.ico" +402 ICON DISCARDABLE "WIN/ICONS/floppy_35_2dd_empty.ico" +403 ICON DISCARDABLE "WIN/ICONS/floppy_35_2dd_empty_active.ico" +406 ICON DISCARDABLE "WIN/ICONS/floppy_35_2hd_empty.ico" +407 ICON DISCARDABLE "WIN/ICONS/floppy_35_2hd_empty_active.ico" +408 ICON DISCARDABLE "WIN/ICONS/floppy_35_2ed_empty.ico" +409 ICON DISCARDABLE "WIN/ICONS/floppy_35_2ed_empty_active.ico" +416 ICON DISCARDABLE "WIN/ICONS/cdrom_atapi_empty.ico" +417 ICON DISCARDABLE "WIN/ICONS/cdrom_atapi_empty_active.ico" +418 ICON DISCARDABLE "WIN/ICONS/cdrom_atapi_dma_empty.ico" +419 ICON DISCARDABLE "WIN/ICONS/cdrom_atapi_dma_empty_active.ico" +420 ICON DISCARDABLE "WIN/ICONS/cdrom_scsi_empty.ico" +421 ICON DISCARDABLE "WIN/ICONS/cdrom_scsi_empty_active.ico" +432 ICON DISCARDABLE "WIN/ICONS/hard_disk_removable_scsi_empty.ico" +433 ICON DISCARDABLE "WIN/ICONS/hard_disk_removable_scsi_empty_active.ico" +512 ICON DISCARDABLE "WIN/ICONS/floppy_disabled.ico" +514 ICON DISCARDABLE "WIN/ICONS/cdrom_disabled.ico" + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "#define APSTUDIO_HIDDEN_SYMBOLS\r\n" + "#include ""windows.h""\r\n" + "#undef APSTUDIO_HIDDEN_SYMBOLS\r\n" + "#include ""resources.h""\r\n" + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO DISCARDABLE +BEGIN + CONFIGUREDLG_MAIN, DIALOG + BEGIN + RIGHTMARGIN, 365 + END + + ABOUTDLG, DIALOG + BEGIN + RIGHTMARGIN, 208 + END + + CONFIGUREDLG_MACHINE, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 260 + TOPMARGIN, 7 + BOTTOMMARGIN, 105 + END + + CONFIGUREDLG_VIDEO, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 260 + TOPMARGIN, 7 + BOTTOMMARGIN, 56 + END + + CONFIGUREDLG_INPUT, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 260 + TOPMARGIN, 7 + BOTTOMMARGIN, 58 + END + + CONFIGUREDLG_SOUND, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 260 + TOPMARGIN, 7 + BOTTOMMARGIN, 109 + END + + CONFIGUREDLG_NETWORK, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 260 + TOPMARGIN, 7 + BOTTOMMARGIN, 56 + END + + CONFIGUREDLG_PERIPHERALS, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 260 + TOPMARGIN, 7 + BOTTOMMARGIN, 102 + END + + CONFIGUREDLG_HARD_DISKS, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 260 + TOPMARGIN, 7 + BOTTOMMARGIN, 137 + END + + CONFIGUREDLG_REMOVABLE_DEVICES, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 260 + TOPMARGIN, 7 + BOTTOMMARGIN, 195 + END +END +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// String Table +// + +STRINGTABLE DISCARDABLE +BEGIN + 2048 "86Box" + IDS_2049 "86Box Error" + IDS_2050 "86Box Fatal Error" + IDS_2051 "This will reset 86Box.\nAre you sure you want to save the settings?" + IDS_2052 "DirectDraw Screenshot Error" + IDS_2053 "Invalid number of sectors (valid values are between 1 and 63)" + IDS_2054 "Invalid number of heads (valid values are between 1 and 16)" + IDS_2055 "Invalid number of cylinders (valid values are between 1 and 266305)" + IDS_2056 "Please enter a valid file name" + IDS_2057 "Unable to open the file for write" + IDS_2058 "Attempting to create a HDI image larger than 4 GB" + IDS_2059 "Remember to partition and format the new drive" + IDS_2060 "Unable to open the file for read" + IDS_2061 "HDI or HDX image with a sector size that is not 512 are not supported" + IDS_2062 "86Box was unable to find any ROMs.\nAt least one ROM set is required to use 86Box." + IDS_2063 "Configured ROM set not available.\nDefaulting to an available ROM set." +END + +STRINGTABLE DISCARDABLE +BEGIN + IDS_2064 "Configured video BIOS not available.\nDefaulting to an available video BIOS." + IDS_2065 "Machine" + IDS_2066 "Video" + IDS_2067 "Input devices" + IDS_2068 "Sound" + IDS_2069 "Network" + IDS_2070 "Other peripherals" + IDS_2071 "Hard disks" + IDS_2072 "Removable devices" + IDS_2073 "%i"" floppy drive: %s" + IDS_2074 "Disabled CD-ROM drive" + IDS_2075 "%s CD-ROM drive: %s" + IDS_2076 "Host CD/DVD Drive (%c:)" + IDS_2077 "Click to capture mouse" + IDS_2078 "Press F12-F8 to release mouse" + IDS_2079 "Press F12-F8 or middle button to release mouse" +END + +STRINGTABLE DISCARDABLE +BEGIN + IDS_2080 "Drive" + IDS_2081 "Location" + IDS_2082 "Bus" + IDS_2083 "File" + IDS_2084 "C" + IDS_2085 "H" + IDS_2086 "S" + IDS_2087 "MB" + IDS_2088 "%i" + IDS_2089 "Enabled" + IDS_2090 "Mute" + IDS_2091 "Type" + IDS_2092 "Bus" + IDS_2093 "DMA" + IDS_2094 "KB" + IDS_2095 "MFM, RLL, or ESDI CD-ROM drives never existed" +END + +STRINGTABLE DISCARDABLE +BEGIN + IDS_2096 "Slave" + IDS_2097 "SCSI (ID %s, LUN %s)" + IDS_2098 "Adapter Type" + IDS_2099 "Base Address" + IDS_2100 "IRQ" + IDS_2101 "8-bit DMA" + IDS_2102 "16-bit DMA" + IDS_2103 "BIOS" + IDS_2104 "Network Type" + IDS_2105 "Surround Module" + IDS_2106 "MPU-401 Base Address" + IDS_2107 "No PCap devices found" + IDS_2108 "On-board RAM" + IDS_2109 "Memory Size" + IDS_2110 "Display Type" + IDS_2111 "RGB" +END + +STRINGTABLE DISCARDABLE +BEGIN + IDS_2112 "Composite" + IDS_2113 "Composite Type" + IDS_2114 "Old" + IDS_2115 "New" + IDS_2116 "RGB Type" + IDS_2117 "Color" + IDS_2118 "Monochrome (Green)" + IDS_2119 "Monochrome (Amber)" + IDS_2120 "Monochrome (Gray)" + IDS_2121 "Color (no brown)" + IDS_2122 "Monochrome (Default)" + IDS_2123 "Snow Emulation" + IDS_2124 "Bilinear Filtering" + IDS_2125 "Dithering" + IDS_2126 "Framebuffer Memory Size" + IDS_2127 "Texture Memory Size" +END + +STRINGTABLE DISCARDABLE +BEGIN + IDS_2128 "Screen Filter" + IDS_2129 "Render Threads" + IDS_2130 "Recompiler" + IDS_2131 "System Default" + IDS_2132 "%i Wait state(s)" + IDS_2133 "8-bit" + IDS_2134 "Slow 16-bit" + IDS_2135 "Fast 16-bit" + IDS_2136 "Slow VLB/PCI" + IDS_2137 "Mid VLB/PCI" + IDS_2138 "Fast VLB/PCI" + IDS_2139 "Microsoft 2-button mouse (serial)" + IDS_2140 "Mouse Systems mouse (serial)" + IDS_2141 "2-button mouse (PS/2)" + IDS_2142 "Microsoft Intellimouse (PS/2)" + IDS_2143 "Bus mouse" +END + +STRINGTABLE DISCARDABLE +BEGIN + IDS_2144 "Standard 2-button joystick(s)" + IDS_2145 "Standard 4-button joystick" + IDS_2146 "Standard 6-button joystick" + IDS_2147 "Standard 8-button joystick" + IDS_2148 "CH Flightstick Pro" + IDS_2149 "Microsoft SideWinder Pad" + IDS_2150 "Thrustmaster Flight Control System" + IDS_2151 "Disabled" + IDS_2152 "None" + IDS_2153 "AT Fixed Disk Adapter" + IDS_2154 "Internal IDE" + IDS_2155 "IRQ %i" + IDS_2156 "MFM (%01i:%01i)" + IDS_2157 "IDE (PIO+DMA) (%01i:%01i)" + IDS_2158 "SCSI (%02i:%02i)" + IDS_2159 "Invalid number of cylinders (valid values are between 1 and 1023)" + IDS_2160 "%" PRIu64 + IDS_2161 "Genius Bus mouse" + IDS_2162 "Amstrad mouse" + IDS_2163 "Attempting to create a spuriously large hard disk image" + IDS_2164 "Invalid number of sectors (valid values are between 1 and 99)" + IDS_2165 "MFM" + IDS_2166 "XT IDE" + IDS_2167 "RLL" + IDS_2168 "IDE (PIO-only)" + IDS_2169 "%01i:%01i" + IDS_2170 "Custom..." + IDS_2171 "%" PRIu64 " MB (CHS: %" PRIu64 ", %" PRIu64 ", %" PRIu64 ")" + IDS_2172 "Hard disk images (*.HDI;*.HDX;*.IMA;*.IMG)\0*.HDI;*.HDX;*.IMA;*.IMG\0All files (*.*)\0*.*\0" + IDS_2173"All floppy images (*.0??;*.12;*.144;*.360;*.720;*.86F;*.BIN;*.CQ;*.CQM;*.DSK;*.FDI;*.FDF;*.FLP;*.HDM;*.IMA;*.IMD;*.IMG;*.TD0;*.VFD;*.XDF)\0*.0??;*.12;*.144;*.360;*.720;*.86F;*.BIN;*.CQ;*.CQM;*.DSK;*.FDI;*.FDF;*.FLP;*.HDM;*.IMA;*.IMD;*.IMG;*.TD0;*.VFD;*.XDF\0Advanced sector-based images (*.IMD;*.TD0)\0*.IMD;*.TD0\0Basic sector-based images (*.0??;*.12;*.144;*.360;*.720;*.BIN;*.CQ;*.CQM;*.DSK;*.FDI;*.FDF;*.FLP;*.HDM;*.IMA;*.IMG;*.VFD;*.XDF)\0*.0??;*.12;*.144;*.360;*.720;*.BIN;*.CQ;*.CQM;*.DSK;*.FDI;*.FDF;*.FLP;*.HDM;*.IMA;*.IMG;*.VFD;*.XDF\0Flux images (*.FDI)\0*.FDI\0Surface-based images (*.86F)\0*.86F\0All files (*.*)\0*.*\0" + IDS_2174 "Configuration files (*.CFG)\0*.CFG\0All files (*.*)\0*.*\0" + IDS_2175 "CD-ROM image (*.ISO;*.CUE)\0*.ISO;*.CUE\0All files (*.*)\0*.*\0" + IDS_2176 "Use CTRL+ALT+PAGE DOWN to return to windowed mode" + IDS_2177 "Olivetti M24 mouse" + IDS_2178 "This image exists and will be overwritten.\nAre you sure you want to use it?" + IDS_2179 "Floppy %i (%s): %ws" + IDS_2180 "CD-ROM %i: %ws" + IDS_2181 "MFM hard disk" + IDS_2182 "IDE hard disk (PIO-only)" + IDS_2183 "IDE hard disk (PIO and DMA)" + IDS_2184 "SCSI hard disk" + IDS_2185 "(empty)" + IDS_2186 "(host drive %c:)" + IDS_2187 "Custom (large)..." + IDS_2188 "Type" + IDS_2189 "ATAPI (PIO-only)" + IDS_2190 "ATAPI (PIO and DMA)" + IDS_2191 "ATAPI (PIO-only) (%01i:%01i)" + IDS_2192 "ATAPI (PIO and DMA) (%01i:%01i)" + IDS_2193 "Use CTRL+ALT+PAGE DOWN to return to windowed mode" + IDS_2194 "Unable to create bitmap file: %s" + IDS_2195 "IDE (PIO-only) (%01i:%01i)" + IDS_2196 "Add New Hard Disk" + IDS_2197 "Add Existing Hard Disk" + IDS_2198 "SCSI removable disk %i: %s" + IDS_2199 "USB is not yet supported" + IDS_2200 "Invalid PCap device" + IDS_2201 "&Notify disk change" + IDS_2202 "SCSI (removable)" + IDS_2203 "SCSI (removable) (%02i:%02i)" + IDS_2204 "Pcap Library Not Available" + IDS_2205 "RLL (%01i:%01i)" + IDS_2206 "XT IDE (%01i:%01i)" + IDS_2207 "RLL hard disk" + IDS_2208 "XT IDE hard disk" + IDS_2209 "IDE (PIO and DMA)" + IDS_2210 "SCSI" + IDS_2211 "&New image..." + IDS_2212 "Existing image..." + IDS_2213 "Existing image (&Write-protected)..." + IDS_2214 "E&ject" + IDS_2215 "&Mute" + IDS_2216 "E&mpty" + IDS_2217 "&Reload previous image" + IDS_2218 "&Image..." + IDS_2219 "PCap failed to set up because it may not be initialized" + IDS_2220 "Image (&Write-protected)..." + IDS_2221 "Turbo" + IDS_2222 "On" + IDS_2223 "Off" + IDS_2224 "Logitech 3-button mouse (serial)" + IDS_2225 "Specify the NVR Path" + IDS_2226 "" + IDS_2227 "English (United States)" +END +#define IDS_LANG_ENUS IDS_2227 + + +#ifndef _MAC +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 2,0,0,0 + PRODUCTVERSION 2,0,0,0 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x1L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "Comments", "\0" + VALUE "CompanyName", "IRC #SoftHistory\0" + VALUE "FileDescription", "86Box - an emulator for X86-based systems\0" + VALUE "FileVersion", "2.00\0" + VALUE "InternalName", "86Box\0" + VALUE "LegalCopyright", "Copyright © SoftHistory, Sarah Walker, 2007-2017, Released under the GNU GPL v2\0" + VALUE "LegalTrademarks", "\0" + VALUE "OriginalFilename", "86Box.exe\0" + VALUE "PrivateBuild", "\0" + VALUE "ProductName", "86Box Emulator\0" + VALUE "ProductVersion", "2.00\0" + VALUE "SpecialBuild", "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + +#endif // !_MAC + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED diff --git a/src/WIN/ICONS/86Box-RB.ico b/src/WIN/ICONS/86Box-RB.ico new file mode 100644 index 000000000..2106da7e4 Binary files /dev/null and b/src/WIN/ICONS/86Box-RB.ico differ diff --git a/src/86Box.ico b/src/WIN/ICONS/86Box.ico similarity index 100% rename from src/86Box.ico rename to src/WIN/ICONS/86Box.ico diff --git a/src/WIN/ICONS/cdrom_atapi.ico b/src/WIN/ICONS/cdrom_atapi.ico new file mode 100644 index 000000000..cef9124ad Binary files /dev/null and b/src/WIN/ICONS/cdrom_atapi.ico differ diff --git a/src/WIN/ICONS/cdrom_atapi_active.ico b/src/WIN/ICONS/cdrom_atapi_active.ico new file mode 100644 index 000000000..e3e84541b Binary files /dev/null and b/src/WIN/ICONS/cdrom_atapi_active.ico differ diff --git a/src/WIN/ICONS/cdrom_atapi_dma.ico b/src/WIN/ICONS/cdrom_atapi_dma.ico new file mode 100644 index 000000000..972e1001f Binary files /dev/null and b/src/WIN/ICONS/cdrom_atapi_dma.ico differ diff --git a/src/WIN/ICONS/cdrom_atapi_dma_active.ico b/src/WIN/ICONS/cdrom_atapi_dma_active.ico new file mode 100644 index 000000000..17c857426 Binary files /dev/null and b/src/WIN/ICONS/cdrom_atapi_dma_active.ico differ diff --git a/src/WIN/ICONS/cdrom_atapi_dma_empty.ico b/src/WIN/ICONS/cdrom_atapi_dma_empty.ico new file mode 100644 index 000000000..d78f3fc82 Binary files /dev/null and b/src/WIN/ICONS/cdrom_atapi_dma_empty.ico differ diff --git a/src/WIN/ICONS/cdrom_atapi_dma_empty_active.ico b/src/WIN/ICONS/cdrom_atapi_dma_empty_active.ico new file mode 100644 index 000000000..3ddba4e8b Binary files /dev/null and b/src/WIN/ICONS/cdrom_atapi_dma_empty_active.ico differ diff --git a/src/WIN/ICONS/cdrom_atapi_empty.ico b/src/WIN/ICONS/cdrom_atapi_empty.ico new file mode 100644 index 000000000..67c2c8347 Binary files /dev/null and b/src/WIN/ICONS/cdrom_atapi_empty.ico differ diff --git a/src/WIN/ICONS/cdrom_atapi_empty_active.ico b/src/WIN/ICONS/cdrom_atapi_empty_active.ico new file mode 100644 index 000000000..a6d204499 Binary files /dev/null and b/src/WIN/ICONS/cdrom_atapi_empty_active.ico differ diff --git a/src/WIN/ICONS/cdrom_disabled.ico b/src/WIN/ICONS/cdrom_disabled.ico new file mode 100644 index 000000000..442daf320 Binary files /dev/null and b/src/WIN/ICONS/cdrom_disabled.ico differ diff --git a/src/WIN/ICONS/cdrom_scsi.ico b/src/WIN/ICONS/cdrom_scsi.ico new file mode 100644 index 000000000..50111bc5a Binary files /dev/null and b/src/WIN/ICONS/cdrom_scsi.ico differ diff --git a/src/WIN/ICONS/cdrom_scsi_active.ico b/src/WIN/ICONS/cdrom_scsi_active.ico new file mode 100644 index 000000000..d51e28c82 Binary files /dev/null and b/src/WIN/ICONS/cdrom_scsi_active.ico differ diff --git a/src/WIN/ICONS/cdrom_scsi_empty.ico b/src/WIN/ICONS/cdrom_scsi_empty.ico new file mode 100644 index 000000000..c10d00b48 Binary files /dev/null and b/src/WIN/ICONS/cdrom_scsi_empty.ico differ diff --git a/src/WIN/ICONS/cdrom_scsi_empty_active.ico b/src/WIN/ICONS/cdrom_scsi_empty_active.ico new file mode 100644 index 000000000..36ac042d0 Binary files /dev/null and b/src/WIN/ICONS/cdrom_scsi_empty_active.ico differ diff --git a/src/WIN/ICONS/floppy_35_1dd.ico b/src/WIN/ICONS/floppy_35_1dd.ico new file mode 100644 index 000000000..55842ba5d Binary files /dev/null and b/src/WIN/ICONS/floppy_35_1dd.ico differ diff --git a/src/WIN/ICONS/floppy_35_1dd_active.ico b/src/WIN/ICONS/floppy_35_1dd_active.ico new file mode 100644 index 000000000..b6728029a Binary files /dev/null and b/src/WIN/ICONS/floppy_35_1dd_active.ico differ diff --git a/src/WIN/ICONS/floppy_35_1dd_empty.ico b/src/WIN/ICONS/floppy_35_1dd_empty.ico new file mode 100644 index 000000000..4299c47ed Binary files /dev/null and b/src/WIN/ICONS/floppy_35_1dd_empty.ico differ diff --git a/src/WIN/ICONS/floppy_35_1dd_empty_active.ico b/src/WIN/ICONS/floppy_35_1dd_empty_active.ico new file mode 100644 index 000000000..c774f369a Binary files /dev/null and b/src/WIN/ICONS/floppy_35_1dd_empty_active.ico differ diff --git a/src/WIN/ICONS/floppy_35_2dd.ico b/src/WIN/ICONS/floppy_35_2dd.ico new file mode 100644 index 000000000..7957e2e2f Binary files /dev/null and b/src/WIN/ICONS/floppy_35_2dd.ico differ diff --git a/src/WIN/ICONS/floppy_35_2dd_active.ico b/src/WIN/ICONS/floppy_35_2dd_active.ico new file mode 100644 index 000000000..19522bc03 Binary files /dev/null and b/src/WIN/ICONS/floppy_35_2dd_active.ico differ diff --git a/src/WIN/ICONS/floppy_35_2dd_empty.ico b/src/WIN/ICONS/floppy_35_2dd_empty.ico new file mode 100644 index 000000000..732514db2 Binary files /dev/null and b/src/WIN/ICONS/floppy_35_2dd_empty.ico differ diff --git a/src/WIN/ICONS/floppy_35_2dd_empty_active.ico b/src/WIN/ICONS/floppy_35_2dd_empty_active.ico new file mode 100644 index 000000000..c3dd58afe Binary files /dev/null and b/src/WIN/ICONS/floppy_35_2dd_empty_active.ico differ diff --git a/src/WIN/ICONS/floppy_35_2ed.ico b/src/WIN/ICONS/floppy_35_2ed.ico new file mode 100644 index 000000000..449d68203 Binary files /dev/null and b/src/WIN/ICONS/floppy_35_2ed.ico differ diff --git a/src/WIN/ICONS/floppy_35_2ed_active.ico b/src/WIN/ICONS/floppy_35_2ed_active.ico new file mode 100644 index 000000000..e8ba0a579 Binary files /dev/null and b/src/WIN/ICONS/floppy_35_2ed_active.ico differ diff --git a/src/WIN/ICONS/floppy_35_2ed_empty.ico b/src/WIN/ICONS/floppy_35_2ed_empty.ico new file mode 100644 index 000000000..5801518ac Binary files /dev/null and b/src/WIN/ICONS/floppy_35_2ed_empty.ico differ diff --git a/src/WIN/ICONS/floppy_35_2ed_empty_active.ico b/src/WIN/ICONS/floppy_35_2ed_empty_active.ico new file mode 100644 index 000000000..1bf185022 Binary files /dev/null and b/src/WIN/ICONS/floppy_35_2ed_empty_active.ico differ diff --git a/src/WIN/ICONS/floppy_35_2hd.ico b/src/WIN/ICONS/floppy_35_2hd.ico new file mode 100644 index 000000000..36bbc5a2f Binary files /dev/null and b/src/WIN/ICONS/floppy_35_2hd.ico differ diff --git a/src/WIN/ICONS/floppy_35_2hd_active.ico b/src/WIN/ICONS/floppy_35_2hd_active.ico new file mode 100644 index 000000000..a5849237d Binary files /dev/null and b/src/WIN/ICONS/floppy_35_2hd_active.ico differ diff --git a/src/WIN/ICONS/floppy_35_2hd_empty.ico b/src/WIN/ICONS/floppy_35_2hd_empty.ico new file mode 100644 index 000000000..012b42c5a Binary files /dev/null and b/src/WIN/ICONS/floppy_35_2hd_empty.ico differ diff --git a/src/WIN/ICONS/floppy_35_2hd_empty_active.ico b/src/WIN/ICONS/floppy_35_2hd_empty_active.ico new file mode 100644 index 000000000..62527c891 Binary files /dev/null and b/src/WIN/ICONS/floppy_35_2hd_empty_active.ico differ diff --git a/src/WIN/ICONS/floppy_525_1dd.ico b/src/WIN/ICONS/floppy_525_1dd.ico new file mode 100644 index 000000000..64963661b Binary files /dev/null and b/src/WIN/ICONS/floppy_525_1dd.ico differ diff --git a/src/WIN/ICONS/floppy_525_1dd_active.ico b/src/WIN/ICONS/floppy_525_1dd_active.ico new file mode 100644 index 000000000..71ba656cb Binary files /dev/null and b/src/WIN/ICONS/floppy_525_1dd_active.ico differ diff --git a/src/WIN/ICONS/floppy_525_1dd_empty.ico b/src/WIN/ICONS/floppy_525_1dd_empty.ico new file mode 100644 index 000000000..51a42b835 Binary files /dev/null and b/src/WIN/ICONS/floppy_525_1dd_empty.ico differ diff --git a/src/WIN/ICONS/floppy_525_1dd_empty_active.ico b/src/WIN/ICONS/floppy_525_1dd_empty_active.ico new file mode 100644 index 000000000..99621601c Binary files /dev/null and b/src/WIN/ICONS/floppy_525_1dd_empty_active.ico differ diff --git a/src/WIN/ICONS/floppy_525_2dd.ico b/src/WIN/ICONS/floppy_525_2dd.ico new file mode 100644 index 000000000..b08b379c4 Binary files /dev/null and b/src/WIN/ICONS/floppy_525_2dd.ico differ diff --git a/src/WIN/ICONS/floppy_525_2dd_active.ico b/src/WIN/ICONS/floppy_525_2dd_active.ico new file mode 100644 index 000000000..382c5b62e Binary files /dev/null and b/src/WIN/ICONS/floppy_525_2dd_active.ico differ diff --git a/src/WIN/ICONS/floppy_525_2dd_empty.ico b/src/WIN/ICONS/floppy_525_2dd_empty.ico new file mode 100644 index 000000000..00feded42 Binary files /dev/null and b/src/WIN/ICONS/floppy_525_2dd_empty.ico differ diff --git a/src/WIN/ICONS/floppy_525_2dd_empty_active.ico b/src/WIN/ICONS/floppy_525_2dd_empty_active.ico new file mode 100644 index 000000000..c0e50f4c0 Binary files /dev/null and b/src/WIN/ICONS/floppy_525_2dd_empty_active.ico differ diff --git a/src/WIN/ICONS/floppy_525_2hd.ico b/src/WIN/ICONS/floppy_525_2hd.ico new file mode 100644 index 000000000..fffae20e1 Binary files /dev/null and b/src/WIN/ICONS/floppy_525_2hd.ico differ diff --git a/src/WIN/ICONS/floppy_525_2hd_active.ico b/src/WIN/ICONS/floppy_525_2hd_active.ico new file mode 100644 index 000000000..d865b19bd Binary files /dev/null and b/src/WIN/ICONS/floppy_525_2hd_active.ico differ diff --git a/src/WIN/ICONS/floppy_525_2hd_empty.ico b/src/WIN/ICONS/floppy_525_2hd_empty.ico new file mode 100644 index 000000000..2cdb251d3 Binary files /dev/null and b/src/WIN/ICONS/floppy_525_2hd_empty.ico differ diff --git a/src/WIN/ICONS/floppy_525_2hd_empty_active.ico b/src/WIN/ICONS/floppy_525_2hd_empty_active.ico new file mode 100644 index 000000000..30c65587e Binary files /dev/null and b/src/WIN/ICONS/floppy_525_2hd_empty_active.ico differ diff --git a/src/WIN/ICONS/floppy_525_2qd.ico b/src/WIN/ICONS/floppy_525_2qd.ico new file mode 100644 index 000000000..e3f370d93 Binary files /dev/null and b/src/WIN/ICONS/floppy_525_2qd.ico differ diff --git a/src/WIN/ICONS/floppy_525_2qd_active.ico b/src/WIN/ICONS/floppy_525_2qd_active.ico new file mode 100644 index 000000000..3abc238fc Binary files /dev/null and b/src/WIN/ICONS/floppy_525_2qd_active.ico differ diff --git a/src/WIN/ICONS/floppy_525_2qd_empty.ico b/src/WIN/ICONS/floppy_525_2qd_empty.ico new file mode 100644 index 000000000..880961b76 Binary files /dev/null and b/src/WIN/ICONS/floppy_525_2qd_empty.ico differ diff --git a/src/WIN/ICONS/floppy_525_2qd_empty_active.ico b/src/WIN/ICONS/floppy_525_2qd_empty_active.ico new file mode 100644 index 000000000..34a6a3777 Binary files /dev/null and b/src/WIN/ICONS/floppy_525_2qd_empty_active.ico differ diff --git a/src/WIN/ICONS/floppy_disabled.ico b/src/WIN/ICONS/floppy_disabled.ico new file mode 100644 index 000000000..8203863cb Binary files /dev/null and b/src/WIN/ICONS/floppy_disabled.ico differ diff --git a/src/WIN/ICONS/hard_disk.ico b/src/WIN/ICONS/hard_disk.ico new file mode 100644 index 000000000..9672a2454 Binary files /dev/null and b/src/WIN/ICONS/hard_disk.ico differ diff --git a/src/WIN/ICONS/hard_disk_active.ico b/src/WIN/ICONS/hard_disk_active.ico new file mode 100644 index 000000000..e888fb45c Binary files /dev/null and b/src/WIN/ICONS/hard_disk_active.ico differ diff --git a/src/WIN/ICONS/hard_disk_ide.ico b/src/WIN/ICONS/hard_disk_ide.ico new file mode 100644 index 000000000..91ded91a7 Binary files /dev/null and b/src/WIN/ICONS/hard_disk_ide.ico differ diff --git a/src/WIN/ICONS/hard_disk_ide_active.ico b/src/WIN/ICONS/hard_disk_ide_active.ico new file mode 100644 index 000000000..9f33e8c14 Binary files /dev/null and b/src/WIN/ICONS/hard_disk_ide_active.ico differ diff --git a/src/WIN/ICONS/hard_disk_mfm.ico b/src/WIN/ICONS/hard_disk_mfm.ico new file mode 100644 index 000000000..ee44a85a0 Binary files /dev/null and b/src/WIN/ICONS/hard_disk_mfm.ico differ diff --git a/src/WIN/ICONS/hard_disk_mfm_active.ico b/src/WIN/ICONS/hard_disk_mfm_active.ico new file mode 100644 index 000000000..caf8ef541 Binary files /dev/null and b/src/WIN/ICONS/hard_disk_mfm_active.ico differ diff --git a/src/WIN/ICONS/hard_disk_removable_scsi.ico b/src/WIN/ICONS/hard_disk_removable_scsi.ico new file mode 100644 index 000000000..59f80a96b Binary files /dev/null and b/src/WIN/ICONS/hard_disk_removable_scsi.ico differ diff --git a/src/WIN/ICONS/hard_disk_removable_scsi_active.ico b/src/WIN/ICONS/hard_disk_removable_scsi_active.ico new file mode 100644 index 000000000..de2979539 Binary files /dev/null and b/src/WIN/ICONS/hard_disk_removable_scsi_active.ico differ diff --git a/src/WIN/ICONS/hard_disk_removable_scsi_empty.ico b/src/WIN/ICONS/hard_disk_removable_scsi_empty.ico new file mode 100644 index 000000000..be5da8ee4 Binary files /dev/null and b/src/WIN/ICONS/hard_disk_removable_scsi_empty.ico differ diff --git a/src/WIN/ICONS/hard_disk_removable_scsi_empty_active.ico b/src/WIN/ICONS/hard_disk_removable_scsi_empty_active.ico new file mode 100644 index 000000000..8c08338ba Binary files /dev/null and b/src/WIN/ICONS/hard_disk_removable_scsi_empty_active.ico differ diff --git a/src/WIN/ICONS/hard_disk_rll.ico b/src/WIN/ICONS/hard_disk_rll.ico new file mode 100644 index 000000000..6d329868b Binary files /dev/null and b/src/WIN/ICONS/hard_disk_rll.ico differ diff --git a/src/WIN/ICONS/hard_disk_rll_active.ico b/src/WIN/ICONS/hard_disk_rll_active.ico new file mode 100644 index 000000000..5692d2452 Binary files /dev/null and b/src/WIN/ICONS/hard_disk_rll_active.ico differ diff --git a/src/WIN/ICONS/hard_disk_scsi.ico b/src/WIN/ICONS/hard_disk_scsi.ico new file mode 100644 index 000000000..7a31cc1f1 Binary files /dev/null and b/src/WIN/ICONS/hard_disk_scsi.ico differ diff --git a/src/WIN/ICONS/hard_disk_scsi_active.ico b/src/WIN/ICONS/hard_disk_scsi_active.ico new file mode 100644 index 000000000..e7579fd8e Binary files /dev/null and b/src/WIN/ICONS/hard_disk_scsi_active.ico differ diff --git a/src/WIN/ICONS/hard_disk_xtide.ico b/src/WIN/ICONS/hard_disk_xtide.ico new file mode 100644 index 000000000..3f64e2882 Binary files /dev/null and b/src/WIN/ICONS/hard_disk_xtide.ico differ diff --git a/src/WIN/ICONS/hard_disk_xtide_active.ico b/src/WIN/ICONS/hard_disk_xtide_active.ico new file mode 100644 index 000000000..806329fea Binary files /dev/null and b/src/WIN/ICONS/hard_disk_xtide_active.ico differ diff --git a/src/WIN/ICONS/input_devices.ico b/src/WIN/ICONS/input_devices.ico new file mode 100644 index 000000000..d18ad23d0 Binary files /dev/null and b/src/WIN/ICONS/input_devices.ico differ diff --git a/src/WIN/ICONS/machine.ico b/src/WIN/ICONS/machine.ico new file mode 100644 index 000000000..a247316c3 Binary files /dev/null and b/src/WIN/ICONS/machine.ico differ diff --git a/src/WIN/ICONS/network.ico b/src/WIN/ICONS/network.ico new file mode 100644 index 000000000..b078387d3 Binary files /dev/null and b/src/WIN/ICONS/network.ico differ diff --git a/src/WIN/ICONS/other_peripherals.ico b/src/WIN/ICONS/other_peripherals.ico new file mode 100644 index 000000000..111506318 Binary files /dev/null and b/src/WIN/ICONS/other_peripherals.ico differ diff --git a/src/WIN/ICONS/removable_devices.ico b/src/WIN/ICONS/removable_devices.ico new file mode 100644 index 000000000..45e15d3b4 Binary files /dev/null and b/src/WIN/ICONS/removable_devices.ico differ diff --git a/src/WIN/ICONS/sound.ico b/src/WIN/ICONS/sound.ico new file mode 100644 index 000000000..dfdc1b86c Binary files /dev/null and b/src/WIN/ICONS/sound.ico differ diff --git a/src/WIN/ICONS/video.ico b/src/WIN/ICONS/video.ico new file mode 100644 index 000000000..664132269 Binary files /dev/null and b/src/WIN/ICONS/video.ico differ diff --git a/src/WIN/pcap_if.rc b/src/WIN/pcap_if.rc new file mode 100644 index 000000000..dd4a8f120 --- /dev/null +++ b/src/WIN/pcap_if.rc @@ -0,0 +1,54 @@ +#ifdef _WIN32 +#include +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + + +/* + * Icons by Devcore + * - https://commons.wikimedia.org/wiki/File:Icon_PC_256x256.png + */ +#ifdef RELEASE_BUILD +100 ICON DISCARDABLE "WIN/ICONS/86Box-RB.ico" +#else +100 ICON DISCARDABLE "WIN/ICONS/86Box.ico" +#endif + + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,0,2,0 + PRODUCTVERSION 1,0,2,0 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x1L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "Comments", "\0" + VALUE "CompanyName", "IRC #SoftHistory\0" + VALUE "FileDescription", "PCap_IF - test tool for WinPcap\0" + VALUE "FileVersion", "1.0.2\0" + VALUE "InternalName", "pcap_if\0" + VALUE "LegalCopyright", "Copyright 2017 Fred N. van Kempen\0" + VALUE "LegalTrademarks", "\0" + VALUE "OriginalFilename", "pcap_if.exe\0" + VALUE "PrivateBuild", "\0" + VALUE "ProductName", "WinPcap Test Tool\0" + VALUE "ProductVersion", "1.0.2\0" + VALUE "SpecialBuild", "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END diff --git a/src/plat-dinput.h b/src/WIN/plat_dinput.h similarity index 100% rename from src/plat-dinput.h rename to src/WIN/plat_dinput.h diff --git a/src/WIN/plat_dir.h b/src/WIN/plat_dir.h new file mode 100644 index 000000000..6eb372aa0 --- /dev/null +++ b/src/WIN/plat_dir.h @@ -0,0 +1,76 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Definitions for the platform OpenDir module. + * + * Version: @(#)plat_dir.h 1.0.1 2017/05/17 + * + * Author: Fred N. van Kempen, + * Copyright 2017 Fred N. van Kempen. + */ +#ifndef PLAT_DIR_H +# define PLAT_DIR_H + + +#ifdef _MAX_FNAME +# define MAXNAMLEN _MAX_FNAME +#else +# define MAXNAMLEN 15 +#endif +# define MAXDIRLEN 127 + + +struct direct { + long d_ino; + unsigned short d_reclen; + unsigned short d_off; +#ifdef UNICODE + wchar_t d_name[MAXNAMLEN + 1]; +#else + char d_name[MAXNAMLEN + 1]; +#endif +}; +#define d_namlen d_reclen + + +typedef struct { + short flags; /* internal flags */ + short offset; /* offset of entry into dir */ + long handle; /* open handle to Win32 system */ + short sts; /* last known status code */ + char *dta; /* internal work data */ +#ifdef UNICODE + wchar_t dir[MAXDIRLEN+1]; /* open dir */ +#else + char dir[MAXDIRLEN+1]; /* open dir */ +#endif + struct direct dent; /* actual directory entry */ +} DIR; + + +/* Directory routine flags. */ +#define DIR_F_LOWER 0x0001 /* force to lowercase */ +#define DIR_F_SANE 0x0002 /* force this to sane path */ +#define DIR_F_ISROOT 0x0010 /* this is the root directory */ + + +/* Function prototypes. */ +#ifdef UNICODE +extern DIR *opendirw(const wchar_t *); +#else +extern DIR *opendir(const char *); +#endif +extern struct direct *readdir(DIR *); +extern long telldir(DIR *); +extern void seekdir(DIR *, long); +extern int closedir(DIR *); + +#define rewinddir(dirp) seekdir(dirp, 0L) + + +#endif /*PLAT_DIR_H*/ diff --git a/src/WIN/plat_dynld.h b/src/WIN/plat_dynld.h new file mode 100644 index 000000000..74af2e8f8 --- /dev/null +++ b/src/WIN/plat_dynld.h @@ -0,0 +1,30 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Define the Dynamic Module Loader interface. + * + * Version: @(#)plat_dynld.h 1.0.1 2017/05/21 + * + * Author: Fred N. van Kempen, + * Copyright 2017 Fred N. van Kempen + */ +#ifndef PLAT_DYNLD_H +# define PLAT_DYNLD_H + + +typedef struct { + const char *name; + void *func; +} dllimp_t; + + +extern void *dynld_module(const char *, dllimp_t *); +extern void dynld_close(void *); + + +#endif /*PLAT_DYNLD_H*/ diff --git a/src/WIN/plat_iodev.h b/src/WIN/plat_iodev.h new file mode 100644 index 000000000..650973483 --- /dev/null +++ b/src/WIN/plat_iodev.h @@ -0,0 +1,5 @@ +extern void cdrom_eject(uint8_t id); +extern void cdrom_reload(uint8_t id); +extern void removable_disk_unload(uint8_t id); +extern void removable_disk_eject(uint8_t id); +extern void removable_disk_reload(uint8_t id); diff --git a/src/plat-joystick.h b/src/WIN/plat_joystick.h similarity index 100% rename from src/plat-joystick.h rename to src/WIN/plat_joystick.h diff --git a/src/plat-keyboard.h b/src/WIN/plat_keyboard.h similarity index 100% rename from src/plat-keyboard.h rename to src/WIN/plat_keyboard.h diff --git a/src/WIN/plat_midi.h b/src/WIN/plat_midi.h new file mode 100644 index 000000000..b1b93b5e2 --- /dev/null +++ b/src/WIN/plat_midi.h @@ -0,0 +1,7 @@ +void plat_midi_init(); +void plat_midi_close(); +void plat_midi_play_msg(uint8_t* val); +void plat_midi_play_sysex(uint8_t* data, unsigned int len); +int plat_midi_write(uint8_t val); +int plat_midi_get_num_devs(); +void plat_midi_get_dev_name(int num, char *s); diff --git a/src/plat-mouse.h b/src/WIN/plat_mouse.h similarity index 100% rename from src/plat-mouse.h rename to src/WIN/plat_mouse.h diff --git a/src/WIN/plat_serial.h b/src/WIN/plat_serial.h new file mode 100644 index 000000000..56cf08126 --- /dev/null +++ b/src/WIN/plat_serial.h @@ -0,0 +1,52 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Definitions for the Bottom Half of the SERIAL card. + * + * Version: @(#)plat_serial.h 1.0.5 2017/06/04 + * + * Author: Fred N. van Kempen, + * Copyright 2017 Fred N. van Kempen. + */ +#ifndef PLAT_SERIAL_H +# define PLAT_SERIAL_H + + +typedef struct { + char name[80]; /* name of open port */ + void (*rd_done)(void *, int); + void *rd_arg; +#ifdef BHTTY_C + HANDLE handle; + OVERLAPPED rov, /* READ and WRITE events */ + wov; + int tmo; /* current timeout value */ + DCB dcb, /* terminal settings */ + odcb; + thread_t *tid; /* pointer to receiver thread */ + char buff[1024]; + int icnt, ihead, itail; +#endif +} BHTTY; + + +extern BHTTY *bhtty_open(char *__port, int __tmo); +extern void bhtty_close(BHTTY *); +extern int bhtty_flush(BHTTY *); +extern void bhtty_raw(BHTTY *, void *__arg); +extern int bhtty_speed(BHTTY *, long __speed); +extern int bhtty_params(BHTTY *, char __dbit, char __par, char __sbit); +extern int bhtty_sstate(BHTTY *, void *__arg); +extern int bhtty_gstate(BHTTY *, void *__arg); +extern int bhtty_crtscts(BHTTY *, char __yesno); +extern int bhtty_active(BHTTY *, int); +extern int bhtty_write(BHTTY *, unsigned char); +extern int bhtty_read(BHTTY *, unsigned char *, int); + + +#endif /*PLAT_SERIAL_H*/ diff --git a/src/WIN/plat_thread.h b/src/WIN/plat_thread.h new file mode 100644 index 000000000..dfb3a9c26 --- /dev/null +++ b/src/WIN/plat_thread.h @@ -0,0 +1,24 @@ +/* Copyright holders: Sarah Walker + see COPYING for more details +*/ +#ifndef PLAT_THREAD_H +# define PLAT_THREAD_H + + +typedef void thread_t; +typedef void event_t; + + +extern thread_t *thread_create(void (*thread_rout)(void *param), void *param); +extern void thread_kill(thread_t *handle); + +extern event_t *thread_create_event(void); +extern void thread_set_event(event_t *event); +extern void thread_reset_event(event_t *_event); +extern int thread_wait_event(event_t *event, int timeout); +extern void thread_destroy_event(event_t *_event); + +extern void thread_sleep(int t); + + +#endif /*PLAT_THREAD_H*/ diff --git a/src/WIN/plat_ticks.h b/src/WIN/plat_ticks.h new file mode 100644 index 000000000..d6e48f37a --- /dev/null +++ b/src/WIN/plat_ticks.h @@ -0,0 +1,2 @@ +uint32_t get_ticks(void); +void delay_ms(uint32_t count); diff --git a/src/WIN/plat_ui.h b/src/WIN/plat_ui.h new file mode 100644 index 000000000..7bc6d35d9 --- /dev/null +++ b/src/WIN/plat_ui.h @@ -0,0 +1,26 @@ +#ifndef __unix +extern void plat_msgbox_error(int i); +extern wchar_t *plat_get_string_from_id(int i); + +#ifndef IDS_2219 +#define IDS_2219 2219 +#endif + +#ifndef IDS_2077 +#define IDS_2077 2077 +#endif + +#ifndef IDS_2078 +#define IDS_2078 2078 +#endif + +#ifndef IDS_2079 +#define IDS_2079 2079 +#endif +#endif + +extern void plat_msgbox_fatal(char *string); +extern void get_executable_name(wchar_t *s, int size); +extern void set_window_title(wchar_t *s); +extern void startblit(void); +extern void endblit(void); diff --git a/src/WIN/resource.h b/src/WIN/resource.h new file mode 100644 index 000000000..864d0167e --- /dev/null +++ b/src/WIN/resource.h @@ -0,0 +1,460 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Windows resource defines. + * + * NOTE: FIXME: Strings 2176 and 2193 are same. + * + * Version: @(#)resource.h 1.0.4 2017/06/16 + * + * Authors: Sarah Walker, + * Miran Grca, + * Fred N. van Kempem, + * Copyright 2008-2017 Sarah Walker. + * Copyright 2016-2017 Miran Grca. + */ +#ifndef WIN_RESOURCE_H +# define WIN_RESOURCE_H + + +/* Dialog IDs. */ +#define DLG_ABOUT 101 /* top-level dialog */ +#define DLG_STATUS 102 /* top-level dialog */ +#define DLG_CONFIG 110 /* top-level dialog */ +#define DLG_CFG_MACHINE 111 /* sub-dialog of config */ +#define DLG_CFG_VIDEO 112 /* sub-dialog of config */ +#define DLG_CFG_INPUT 113 /* sub-dialog of config */ +#define DLG_CFG_SOUND 114 /* sub-dialog of config */ +#define DLG_CFG_NETWORK 115 /* sub-dialog of config */ +#define DLG_CFG_PERIPHERALS 116 /* sub-dialog of config */ +#define DLG_CFG_HARD_DISKS 117 /* sub-dialog of config */ +#define DLG_CFG_HARD_DISKS_ADD 118 /* sub-dialog of config */ +#define DLG_CFG_REMOVABLE_DEVICES 119 /* sub-dialog of config */ + +/* Static text label IDs. */ +#define IDT_1700 1700 /* Language: */ +#define IDT_1701 1701 /* Machine: */ +#define IDT_1702 1702 /* CPU type: */ +#define IDT_1703 1703 /* Wait states: */ +#define IDT_1704 1704 /* CPU: */ +#define IDT_1705 1705 /* MB == IDC_TEXT_MB */ +#define IDT_1706 1706 /* Memory: */ +#define IDT_1707 1707 /* Video: */ +#define IDT_1708 1708 /* Video speed: */ +#define IDT_1709 1709 /* Mouse: */ +#define IDT_1710 1710 /* Joystick: */ +#define IDT_1711 1711 /* Sound card: */ +#define IDT_1712 1712 /* MIDI Out Device: */ +#define IDT_1713 1713 /* Network type: */ +#define IDT_1714 1714 /* PCap device: */ +#define IDT_1715 1715 /* Network adapter: */ +#define IDT_1716 1716 /* SCSI Controller: */ +#define IDT_1717 1717 /* HD Controller: */ +#define IDT_1718 1718 /* Tertiary IDE: */ +#define IDT_1719 1719 /* Quaternary IDE: */ +#define IDT_1720 1720 /* Hard disks: */ +#define IDT_1721 1721 /* Bus: */ +#define IDT_1722 1722 /* Channel: */ +#define IDT_1723 1723 /* ID: */ +#define IDT_1724 1724 /* LUN: */ +#define IDT_1726 1726 /* Sectors: */ +#define IDT_1727 1727 /* Heads: */ +#define IDT_1728 1728 /* Cylinders: */ +#define IDT_1729 1729 /* Size (MB): */ +#define IDT_1730 1730 /* Type: */ +#define IDT_1731 1731 /* File name: */ +#define IDT_1737 1737 /* Floppy drives: */ +#define IDT_1738 1738 /* Type: */ +#define IDT_1739 1739 /* CD-ROM drives: */ +#define IDT_1740 1740 /* Bus: */ +#define IDT_1741 1741 /* ID: */ +#define IDT_1742 1742 /* LUN: */ +#define IDT_1743 1743 /* Channel: */ +#define IDT_STEXT 1744 /* text in status window */ +#define IDT_SDEVICE 1745 /* text in status window */ + + +/* + * To try to keep these organized, we now group the + * constants per dialog, as this allows easy adding + * and deleting items. + */ +#define IDC_SETTINGSCATLIST 1001 /* generic config */ +#define IDC_CFILE 1002 /* Select File dialog */ +#define IDC_CHECK_SYNC 1008 +/* Leave this as is until we finally get into localization in 86Box 3.00(?). */ +#if 0 +#define IDC_COMBO_LANG 1009 +#endif + +#define IDC_COMBO_MACHINE 1010 /* machine/cpu config */ +#define IDC_CONFIGURE_MACHINE 1011 +#define IDC_COMBO_CPU_TYPE 1012 +#define IDC_COMBO_CPU 1013 +#define IDC_CHECK_FPU 1014 +#define IDC_COMBO_WS 1015 +#define IDC_CHECK_DYNAREC 1016 +#define IDC_MEMTEXT 1017 +#define IDC_MEMSPIN 1018 +#define IDC_TEXT_MB IDT_1705 +#define IDC_EDIT_NVR_PATH 1019 +#define IDC_BUTTON_NVR_PATH 1020 + +#define IDC_VIDEO 1030 /* video config */ +#define IDC_COMBO_VIDEO 1031 +#define IDC_COMBO_VIDEO_SPEED 1032 +#define IDC_CHECK_VOODOO 1033 +#define IDC_BUTTON_VOODOO 1034 + +#define IDC_INPUT 1050 /* input config */ +#define IDC_COMBO_MOUSE 1051 +#define IDC_COMBO_JOYSTICK 1052 +#define IDC_COMBO_JOY 1053 + +#define IDC_SOUND 1070 /* sound config */ +#define IDC_COMBO_SOUND 1071 +#define IDC_CHECK_SSI 1072 +#define IDC_CHECK_CMS 1073 +#define IDC_CHECK_GUS 1074 +#define IDC_CHECK_NUKEDOPL 1075 +#define IDC_COMBO_MIDI 1076 +#define IDC_CHECK_MPU401 1077 +#define IDC_CONFIGURE_MPU401 1078 +#define IDC_CHECK_FLOAT 1079 + +#define IDC_COMBO_NET_TYPE 1090 /* network config */ +#define IDC_COMBO_PCAP 1091 +#define IDC_COMBO_NET 1092 + +#define IDC_OTHER_PERIPH 1110 /* other periph config */ +#define IDC_COMBO_SCSI 1111 +#define IDC_CONFIGURE_SCSI 1112 +#define IDC_COMBO_HDC 1113 +#define IDC_COMBO_IDE_TER 1114 +#define IDC_COMBO_IDE_QUA 1115 +#define IDC_CHECK_SERIAL1 1116 +#define IDC_CHECK_SERIAL2 1117 +#define IDC_CHECK_PARALLEL 1118 +#define IDC_CHECK_BUGGER 1119 + +#define IDC_HARD_DISKS 1130 /* hard disk config */ +#define IDC_LIST_HARD_DISKS 1131 +#define IDC_BUTTON_HDD_ADD_NEW 1132 +#define IDC_BUTTON_HDD_ADD 1133 +#define IDC_BUTTON_HDD_REMOVE 1134 +#define IDC_COMBO_HD_BUS 1135 +#define IDC_COMBO_HD_CHANNEL 1136 +#define IDC_COMBO_HD_ID 1137 +#define IDC_COMBO_HD_LUN 1138 +#define IDC_COMBO_HD_CHANNEL_IDE 1139 +#define IDC_EDIT_HD_FILE_NAME 1140 +#define IDC_EDIT_HD_SPT 1141 +#define IDC_EDIT_HD_HPC 1142 +#define IDC_EDIT_HD_CYL 1143 +#define IDC_EDIT_HD_SIZE 1144 +#define IDC_COMBO_HD_TYPE 1145 + +#define IDC_REMOV_DEVICES 1150 /* removable dev config */ +#define IDC_LIST_FLOPPY_DRIVES 1151 +#define IDC_COMBO_FD_TYPE 1152 +#define IDC_CHECKTURBO 1153 +#define IDC_BUTTON_FDD_ADD 1154 // status bar menu +#define IDC_BUTTON_FDD_EDIT 1155 // status bar menu +#define IDC_BUTTON_FDD_REMOVE 1156 // status bar menu +#define IDC_LIST_CDROM_DRIVES 1157 +#define IDC_COMBO_CD_BUS 1158 +#define IDC_COMBO_CD_ID 1159 +#define IDC_COMBO_CD_LUN 1160 +#define IDC_COMBO_CD_CHANNEL_IDE 1161 +#define IDC_BUTTON_CDROM_ADD 1162 // status bar menu +#define IDC_BUTTON_CDROM_EDIT 1163 // status bar menu +#define IDC_BUTTON_CDROM_REMOVE 1164 // status bar menu + + +/* For the DeviceConfig code, re-do later. */ +#define IDC_CONFIG_BASE 1200 +#define IDC_CONFIGURE_VID 1200 +#define IDC_CONFIGURE_SND 1201 +#define IDC_CONFIGURE_VOODOO 1202 +#define IDC_CONFIGURE_MOD 1203 +#define IDC_CONFIGURE_NET_TYPE 1204 +#define IDC_CONFIGURE_BUSLOGIC 1205 +#define IDC_CONFIGURE_PCAP 1206 +#define IDC_CONFIGURE_NET 1207 +#define IDC_CONFIGURE_MIDI 1208 +#define IDC_JOY1 1210 +#define IDC_JOY2 1211 +#define IDC_JOY3 1212 +#define IDC_JOY4 1213 +#define IDC_HDTYPE 1280 +#define IDC_RENDER 1281 +#define IDC_STATUS 1282 + + +/* String IDs. */ +#define IDS_STRINGS 2048 // "86Box" +#define IDS_2049 2049 // "86Box Error" +#define IDS_2050 2050 // "86Box Fatal Error" +#define IDS_2051 2051 // "This will reset 86Box.." +#define IDS_2052 2052 // "DirectDraw Screenshot Error" +#define IDS_2053 2053 // "Invalid number of sectors.." +#define IDS_2054 2054 // "Invalid number of heads.." +#define IDS_2055 2055 // "Invalid number of cylinders.." +#define IDS_2056 2056 // "Please enter a valid file name" +#define IDS_2057 2057 // "Unable to open the file for write" +#define IDS_2058 2058 // "Attempting to create a HDI.." +#define IDS_2059 2059 // "Remember to partition and.." +#define IDS_2060 2060 // "Unable to open the file.." +#define IDS_2061 2061 // "HDI or HDX image with a.." +#define IDS_2062 2062 // "86Box was unable to find any.." +#define IDS_2063 2063 // "Configured ROM set not avai.." +#define IDS_2064 2064 // "Configured video BIOS not.." +#define IDS_2065 2065 // "Machine" +#define IDS_2066 2066 // "Video" +#define IDS_2067 2067 // "Input devices" +#define IDS_2068 2068 // "Sound" +#define IDS_2069 2069 // "Network" +#define IDS_2070 2070 // "Other peripherals" +#define IDS_2071 2071 // "Hard disks" +#define IDS_2072 2072 // "Removable devices" +#define IDS_2073 2073 // "%i"" floppy drive: %s" +#define IDS_2074 2074 // "Disabled CD-ROM drive" +#define IDS_2075 2075 // "%s CD-ROM drive: %s" +#define IDS_2076 2076 // "Host CD/DVD Drive (%c:)" +#define IDS_2077 2077 // "Click to capture mouse" +#define IDS_2078 2078 // "Press F12-F8 to release mouse" +#define IDS_2079 2079 // "Press F12-F8 or middle button.." +#define IDS_2080 2080 // "Drive" +#define IDS_2081 2081 // "Location" +#define IDS_2082 2082 // "Bus" +#define IDS_2083 2083 // "File" +#define IDS_2084 2084 // "C" +#define IDS_2085 2085 // "H" +#define IDS_2086 2086 // "S" +#define IDS_2087 2087 // "MB" +#define IDS_2088 2088 // "%i" +#define IDS_2089 2089 // "Enabled" +#define IDS_2090 2090 // "Mute" +#define IDS_2091 2091 // "Type" +#define IDS_2092 2092 // "Bus" +#define IDS_2093 2093 // "DMA" +#define IDS_2094 2094 // "KB" +#define IDS_2095 2095 // "MFM, RLL, or ESDI CD-ROM.." +#define IDS_2096 2096 // "Slave" +#define IDS_2097 2097 // "SCSI (ID %s, LUN %s)" +#define IDS_2098 2098 // "Adapter Type" +#define IDS_2099 2099 // "Base Address" +#define IDS_2100 2100 // "IRQ" +#define IDS_2101 2101 // "8-bit DMA" +#define IDS_2102 2102 // "16-bit DMA" +#define IDS_2103 2103 // "BIOS" +#define IDS_2104 2104 // "Network Type" +#define IDS_2105 2105 // "Surround Module" +#define IDS_2106 2106 // "MPU-401 Base Address" +#define IDS_2107 2107 // "No PCap devices found" +#define IDS_2108 2108 // "On-board RAM" +#define IDS_2109 2109 // "Memory Size" +#define IDS_2110 2110 // "Display Type" +#define IDS_2111 2111 // "RGB" +#define IDS_2112 2112 // "Composite" +#define IDS_2113 2113 // "Composite Type" +#define IDS_2114 2114 // "Old" +#define IDS_2115 2115 // "New" +#define IDS_2116 2116 // "RGB Type" +#define IDS_2117 2117 // "Color" +#define IDS_2118 2118 // "Monochrome (Green)" +#define IDS_2119 2119 // "Monochrome (Amber)" +#define IDS_2120 2120 // "Monochrome (Gray)" +#define IDS_2121 2121 // "Color (no brown)" +#define IDS_2122 2122 // "Monochrome (Default)" +#define IDS_2123 2123 // "Snow Emulation" +#define IDS_2124 2124 // "Bilinear Filtering" +#define IDS_2125 2125 // "Dithering" +#define IDS_2126 2126 // "Framebuffer Memory Size" +#define IDS_2127 2127 // "Texture Memory Size" +#define IDS_2128 2128 // "Screen Filter" +#define IDS_2129 2129 // "Render Threads" +#define IDS_2130 2130 // "Recompiler" +#define IDS_2131 2131 // "System Default" +#define IDS_2132 2132 // "%i Wait state(s)" +#define IDS_2133 2133 // "8-bit" +#define IDS_2134 2134 // "Slow 16-bit" +#define IDS_2135 2135 // "Fast 16-bit" +#define IDS_2136 2136 // "Slow VLB/PCI" +#define IDS_2137 2137 // "Mid VLB/PCI" +#define IDS_2138 2138 // "Fast VLB/PCI" +#define IDS_2139 2139 // "Microsoft 2-button mouse (serial)" +#define IDS_2140 2140 // "Mouse Systems mouse (serial)" +#define IDS_2141 2141 // "2-button mouse (PS/2)" +#define IDS_2142 2142 // "Microsoft Intellimouse (PS/2)" +#define IDS_2143 2143 // "Bus mouse" +#define IDS_2144 2144 // "Standard 2-button joystick(s)" +#define IDS_2145 2145 // "Standard 4-button joystick" +#define IDS_2146 2146 // "Standard 6-button joystick" +#define IDS_2147 2147 // "Standard 8-button joystick" +#define IDS_2148 2148 // "CH Flightstick Pro" +#define IDS_2149 2149 // "Microsoft SideWinder Pad" +#define IDS_2150 2150 // "Thrustmaster Flight Control System" +#define IDS_2151 2151 // "Disabled" +#define IDS_2152 2152 // "None" +#define IDS_2153 2153 // "AT Fixed Disk Adapter" +#define IDS_2154 2154 // "Internal IDE" +#define IDS_2155 2155 // "IRQ %i" +#define IDS_2156 2156 // "MFM (%01i:%01i)" +#define IDS_2157 2157 // "IDE (PIO+DMA) (%01i:%01i)" +#define IDS_2158 2158 // "SCSI (%02i:%02i)" +#define IDS_2159 2159 // "Invalid number of cylinders.." +#define IDS_2160 2160 // "%" PRIu64 +#define IDS_2161 2161 // "Genius Bus mouse" +#define IDS_2162 2162 // "Amstrad mouse" +#define IDS_2163 2163 // "Attempting to create a spuriously.." +#define IDS_2164 2164 // "Invalid number of sectors.." +#define IDS_2165 2165 // "MFM" +#define IDS_2166 2166 // "XT IDE" +#define IDS_2167 2167 // "RLL" +#define IDS_2168 2168 // "IDE (PIO-only)" +#define IDS_2169 2169 // "%01i:%01i" +#define IDS_2170 2170 // "Custom..." +#define IDS_2171 2171 // "%" PRIu64 " MB (CHS: %" .. +#define IDS_2172 2172 // "Hard disk images .." +#define IDS_2173 2173 // "All floppy images .." +#define IDS_2174 2174 // "Configuration files .." +#define IDS_2175 2175 // "CD-ROM image .." +#define IDS_2176 2176 // "Use CTRL+ALT+PAGE DOWN .." +#define IDS_2177 2177 // "Olivetti M24 mouse" +#define IDS_2178 2178 // "This image exists and will.." +#define IDS_2179 2179 // "Floppy %i (%s): %ws" +#define IDS_2180 2180 // "CD-ROM %i: %ws" +#define IDS_2181 2181 // "MFM hard disk" +#define IDS_2182 2182 // "IDE hard disk (PIO-only)" +#define IDS_2183 2183 // "IDE hard disk (PIO and DMA)" +#define IDS_2184 2184 // "SCSI hard disk" +#define IDS_2185 2185 // "(empty)" +#define IDS_2186 2186 // "(host drive %c:)" +#define IDS_2187 2187 // "Custom (large)..." +#define IDS_2188 2188 // "Type" +#define IDS_2189 2189 // "ATAPI (PIO-only)" +#define IDS_2190 2190 // "ATAPI (PIO and DMA)" +#define IDS_2191 2191 // "ATAPI (PIO-only) (%01i:%01i)" +#define IDS_2192 2192 // "ATAPI (PIO and DMA) (%01i:%01i)" +#define IDS_2193 2193 // "Use CTRL+ALT+PAGE DOWN to .." +#define IDS_2194 2194 // "Unable to create bitmap file: %s" +#define IDS_2195 2195 // "IDE (PIO-only) (%01i:%01i)" +#define IDS_2196 2196 // "Add New Hard Disk" +#define IDS_2197 2197 // "Add Existing Hard Disk" +#define IDS_2198 2198 // "SCSI removable disk %i: %s" +#define IDS_2199 2199 // "USB is not yet supported" +#define IDS_2200 2200 // "Invalid PCap device" +#define IDS_2201 2201 // "&Notify disk change" +#define IDS_2202 2202 // "SCSI (removable)" +#define IDS_2203 2203 // "SCSI (removable) (%02i:%02i)" +#define IDS_2204 2204 // "Pcap Library Not Available" +#define IDS_2205 2205 // "RLL (%01i:%01i)" +#define IDS_2206 2206 // "XT IDE (%01i:%01i)" +#define IDS_2207 2207 // "RLL hard disk" +#define IDS_2208 2208 // "XT IDE hard disk" +#define IDS_2209 2209 // "IDE (PIO and DMA)" +#define IDS_2210 2210 // "SCSI" +#define IDS_2211 2211 // "&New image..." +#define IDS_2212 2212 // "Existing image..." +#define IDS_2213 2213 // "Existing image (&Write-.." +#define IDS_2214 2214 // "E&ject" +#define IDS_2215 2215 // "&Mute" +#define IDS_2216 2216 // "E&mpty" +#define IDS_2217 2217 // "&Reload previous image" +#define IDS_2218 2218 // "&Image..." +#define IDS_2219 2219 // "PCap failed to set up .." +#define IDS_2220 2220 // "Image (&Write-protected)..." +#define IDS_2221 2221 // "Turbo" +#define IDS_2222 2222 // "On" +#define IDS_2223 2223 // "Off" +#define IDS_2224 2224 // "Logitech 3-button mouse (serial)" +#define IDS_2225 2225 // "Specify the NVR Path" +#define IDS_2226 2226 // "" +#define IDS_2227 2227 // "English (United States)" + +#define IDS_LANG_ENUS IDS_2227 +#define STRINGS_NUM 180 + + +#define IDM_ABOUT 40001 +#define IDC_ABOUT_ICON 65535 +#define IDM_ACTION_SCREENSHOT 40011 +#define IDM_ACTION_HRESET 40012 +#define IDM_ACTION_RESET_CAD 40013 +#define IDM_ACTION_EXIT 40014 +#define IDM_CONFIG 40020 +#define IDM_CONFIG_LOAD 40021 +#define IDM_CONFIG_SAVE 40022 +#define IDM_STATUS 40030 +#define IDM_VID_RESIZE 40050 +#define IDM_VID_REMEMBER 40051 +#define IDM_VID_DDRAW 40060 +#define IDM_VID_D3D 40061 +#define IDM_VID_SCALE_1X 40064 +#define IDM_VID_SCALE_2X 40065 +#define IDM_VID_SCALE_3X 40066 +#define IDM_VID_SCALE_4X 40067 +#define IDM_VID_FULLSCREEN 40070 +#define IDM_VID_FS_FULL 40071 +#define IDM_VID_FS_43 40072 +#define IDM_VID_FS_SQ 40073 +#define IDM_VID_FS_INT 40074 +#define IDM_VID_FORCE43 40075 +#define IDM_VID_OVERSCAN 40076 +#define IDM_VID_INVERT 40079 +#define IDM_VID_CGACON 40080 + +#define IDM_LOG_BREAKPOINT 51201 +#define IDM_DUMP_VRAM 51202 // should be an Action + +#define IDM_LOG_SERIAL 51211 +#define IDM_LOG_D86F 51212 +#define IDM_LOG_FDC 51213 +#define IDM_LOG_IDE 51214 +#define IDM_LOG_CDROM 51215 +#define IDM_LOG_NIC 51216 +#define IDM_LOG_BUSLOGIC 51217 + +/* + * We need 7 bits for CDROM (2 bits ID and 5 bits for host drive), + * and 5 bits for Removable Disks (5 bits for ID), so we use an + * 8bit (256 entries) space for these devices. + */ +#define IDM_FLOPPY_IMAGE_NEW 0x1200 +#define IDM_FLOPPY_IMAGE_EXISTING 0x1300 +#define IDM_FLOPPY_IMAGE_EXISTING_WP 0x1400 +#define IDM_FLOPPY_DUMP_86F 0x1500 +#define IDM_FLOPPY_EJECT 0x1600 + +#define IDM_CDROM_MUTE 0x2200 +#define IDM_CDROM_EMPTY 0x2300 +#define IDM_CDROM_RELOAD 0x2400 +#define IDM_CDROM_IMAGE 0x2500 +#define IDM_CDROM_HOST_DRIVE 0x2600 + +#define IDM_RDISK_EJECT 0x3200 +#define IDM_RDISK_RELOAD 0x3300 +#define IDM_RDISK_SEND_CHANGE 0x3400 +#define IDM_RDISK_IMAGE 0x3500 +#define IDM_RDISK_IMAGE_WP 0x3600 + + +/* Next default values for new objects */ +#ifdef APSTUDIO_INVOKED +# ifndef APSTUDIO_READONLY_SYMBOLS +# define _APS_NO_MFC 1 +# define _APS_NEXT_RESOURCE_VALUE 1400 +# define _APS_NEXT_COMMAND_VALUE 55000 +# define _APS_NEXT_CONTROL_VALUE 1800 +# define _APS_NEXT_SYMED_VALUE 200 +# endif +#endif + + +#endif /*WIN_RESOURCE_H*/ diff --git a/src/WIN/win.c b/src/WIN/win.c new file mode 100644 index 000000000..15cffbeb6 --- /dev/null +++ b/src/WIN/win.c @@ -0,0 +1,2526 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * The Emulator's Windows core. + * + * Version: @(#)win.c 1.0.3 2017/06/12 + * + * Authors: Sarah Walker, + * Miran Grca, + * Fred N. van Kempen, + * Copyright 2008-2017 Sarah Walker. + * Copyright 2016-2017 Miran Grca. + */ +#include +#include +#include +#include +#include "../86box.h" +#include "../device.h" +#include "../disc.h" +#include "../fdd.h" +#include "../hdd.h" +#include "../ibm.h" +#include "../cpu/cpu.h" +#include "../mem.h" +#include "../rom.h" +#include "../nvr.h" +#include "../config.h" +#include "../model.h" +#include "../ide.h" +#include "../cdrom.h" +#include "../cdrom_null.h" +#include "../cdrom_ioctl.h" +#include "../cdrom_image.h" +#include "../scsi.h" +#include "../scsi_disk.h" +#include "../video/video.h" +#include "../video/vid_ega.h" +#include "../mouse.h" +#include "../sound/sound.h" +#include "../sound/snd_dbopl.h" +#include "plat_keyboard.h" +#include "plat_iodev.h" +#include "plat_mouse.h" +#include "plat_midi.h" +#include "plat_thread.h" +#include "plat_ticks.h" +#include "plat_ui.h" + +#include "win.h" +#include "win_cgapal.h" +#include "win_ddraw.h" +#include "win_d3d.h" +#include "win_language.h" + +#include +#include +#include +#include + + +#ifndef MAPVK_VK_TO_VSC +#define MAPVK_VK_TO_VSC 0 +#endif + +/* Declare Windows procedure */ +LRESULT CALLBACK WindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); +LRESULT CALLBACK subWindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); + +LRESULT CALLBACK StatusBarProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); + +#define TIMER_1SEC 1 + +extern int updatestatus; + + +typedef struct win_event_t +{ + HANDLE handle; +} win_event_t; + +LONG_PTR OriginalStatusBarProcedure; +HWND ghwnd; +HINSTANCE hinstance; +HMENU menu; +int pause = 0; +int scale = 0; +HWND hwndRender, hwndStatus; +uint64_t timer_freq; +int winsizex=640, winsizey=480; +int efwinsizey=480; +int gfx_present[GFX_MAX]; +HANDLE ghMutex; +HANDLE mainthreadh; +int infocus=1; +int drawits=0; +int romspresent[ROM_MAX]; +int quited=0; +RECT oldclip; +int mousecapture=0; +int recv_key[272]; +HMENU *sb_menu_handles; +uint64_t main_time; + + +static struct +{ + int (*init)(HWND h); + void (*close)(); + void (*resize)(int x, int y); +} vid_apis[2][2] = +{ { { ddraw_init, ddraw_close, NULL }, + { d3d_init, d3d_close, d3d_resize } }, + { { ddraw_fs_init, ddraw_fs_close, NULL }, + { d3d_fs_init, d3d_fs_close, NULL } } }; + +static int save_window_pos = 0; + +static RAWINPUTDEVICE device; + +static int win_doresize = 0; + +static int leave_fullscreen_flag = 0; + +static int unscaled_size_x = 0; +static int unscaled_size_y = 0; + +static uint64_t start_time; +static uint64_t end_time; + +HMENU smenu; + +static uint8_t host_cdrom_drive_available[26]; + +static uint8_t host_cdrom_drive_available_num = 0; + +static wchar_t **argv; +static int argc; +static wchar_t *argbuf; + +static HANDLE hinstAcc; + +static HICON hIcon[512]; + +static int *iStatusWidths; +static int *sb_icon_flags; +static int *sb_part_meanings; +static int *sb_part_icons; +static WCHAR **sbTips; + +static int sb_parts = 0; +static int sb_ready = 0; + + +void updatewindowsize(int x, int y) +{ + int owsx = winsizex; + int owsy = winsizey; + + int temp_overscan_x = overscan_x; + int temp_overscan_y = overscan_y; + + if (vid_resize) return; + + if (x < 160) x = 160; + if (y < 100) y = 100; + + if (x > 2048) x = 2048; + if (y > 2048) y = 2048; + + if (suppress_overscan) + { + temp_overscan_x = temp_overscan_y = 0; + } + + unscaled_size_x=x; efwinsizey=y; + + if (force_43) + { + /* Account for possible overscan. */ + if (temp_overscan_y == 16) + { + /* CGA */ + unscaled_size_y = ((int) (((double) (x - temp_overscan_x) / 4.0) * 3.0)) + temp_overscan_y; + } + else if (temp_overscan_y < 16) + { + /* MDA/Hercules */ + unscaled_size_y = ((int) (((double) (x) / 4.0) * 3.0)); + } + else + { + if (enable_overscan) + { + /* EGA/(S)VGA with overscan */ + unscaled_size_y = ((int) (((double) (x - temp_overscan_x) / 4.0) * 3.0)) + temp_overscan_y; + } + else + { + /* EGA/(S)VGA without overscan */ + unscaled_size_y = ((int) (((double) (x) / 4.0) * 3.0)); + } + } + } + else + { + unscaled_size_y = efwinsizey; + } + + switch(scale) + { + case 0: + winsizex = unscaled_size_x >> 1; + winsizey = unscaled_size_y >> 1; + break; + case 1: + winsizex = unscaled_size_x; + winsizey = unscaled_size_y; + break; + case 2: + winsizex = (unscaled_size_x * 3) >> 1; + winsizey = (unscaled_size_y * 3) >> 1; + break; + case 3: + winsizex = unscaled_size_x << 1; + winsizey = unscaled_size_y << 1; + break; + } + + if ((owsx != winsizex) || (owsy != winsizey)) + { + win_doresize = 1; + } + else + { + win_doresize = 0; + } +} + +void uws_natural(void) +{ + updatewindowsize(unscaled_size_x, efwinsizey); +} + +void releasemouse(void) +{ + if (mousecapture) + { + ClipCursor(&oldclip); + ShowCursor(TRUE); + mousecapture = 0; + } +} + +void startblit(void) +{ + WaitForSingleObject(ghMutex, INFINITE); +} + +void endblit(void) +{ + ReleaseMutex(ghMutex); +} + +void leave_fullscreen(void) +{ + leave_fullscreen_flag = 1; +} + +uint32_t get_ticks(void) +{ + return GetTickCount(); +} + +void delay_ms(uint32_t count) +{ + Sleep(count); +} + +void mainthread(LPVOID param) +{ + int frames = 0; + DWORD old_time, new_time; + + RECT r; + int sb_borders[3]; + + drawits=0; + old_time = GetTickCount(); + while (!quited) + { + if (updatestatus) + { + updatestatus = 0; + if (status_is_open) + { + SendMessage(status_hwnd, WM_USER, 0, 0); + } + } + new_time = GetTickCount(); + drawits += new_time - old_time; + old_time = new_time; + if (drawits > 0 && !pause) + { + start_time = timer_read(); + drawits-=10; if (drawits>50) drawits=0; + runpc(); + frames++; + if (frames >= 200 && nvr_dosave) + { + frames = 0; + nvr_dosave = 0; + savenvr(); + } + end_time = timer_read(); + main_time += end_time - start_time; + } + else + Sleep(1); + + if (!video_fullscreen && win_doresize && (winsizex > 0) && (winsizey > 0)) + { + video_wait_for_blit(); + SendMessage(hwndStatus, SB_GETBORDERS, 0, (LPARAM) sb_borders); + GetWindowRect(ghwnd, &r); + MoveWindow(hwndRender, 0, 0, winsizex, winsizey, TRUE); + GetWindowRect(hwndRender, &r); + MoveWindow(hwndStatus, 0, r.bottom + GetSystemMetrics(SM_CYEDGE), winsizex, 17, TRUE); + GetWindowRect(ghwnd, &r); + + MoveWindow(ghwnd, r.left, r.top, + winsizex + (GetSystemMetrics(vid_resize ? SM_CXSIZEFRAME : SM_CXFIXEDFRAME) * 2), + winsizey + (GetSystemMetrics(SM_CYEDGE) * 2) + (GetSystemMetrics(vid_resize ? SM_CYSIZEFRAME : SM_CYFIXEDFRAME) * 2) + GetSystemMetrics(SM_CYMENUSIZE) + GetSystemMetrics(SM_CYCAPTION) + 17 + sb_borders[1] + 1, + TRUE); + + if (mousecapture) + { + GetWindowRect(hwndRender, &r); + ClipCursor(&r); + } + + win_doresize = 0; + } + + if (leave_fullscreen_flag) + { + leave_fullscreen_flag = 0; + SendMessage(ghwnd, WM_LEAVEFULLSCREEN, 0, 0); + } + if (video_fullscreen && infocus) + { + SetCursorPos(9999, 9999); + } + } +} + +void *thread_create(void (*thread_rout)(void *param), void *param) +{ + return (void *)_beginthread(thread_rout, 0, param); +} + +void thread_kill(void *handle) +{ + TerminateThread(handle, 0); +} + +void thread_sleep(int t) +{ + Sleep(t); +} + +event_t *thread_create_event(void) +{ + win_event_t *event = malloc(sizeof(win_event_t)); + + event->handle = CreateEvent(NULL, FALSE, FALSE, NULL); + + return (event_t *)event; +} + +void thread_set_event(event_t *_event) +{ + win_event_t *event = (win_event_t *)_event; + + SetEvent(event->handle); +} + +void thread_reset_event(event_t *_event) +{ + win_event_t *event = (win_event_t *)_event; + + ResetEvent(event->handle); +} + +int thread_wait_event(event_t *_event, int timeout) +{ + win_event_t *event = (win_event_t *)_event; + + if (timeout == -1) + timeout = INFINITE; + + if (WaitForSingleObject(event->handle, timeout)) + return 1; + return 0; +} + +void thread_destroy_event(event_t *_event) +{ + win_event_t *event = (win_event_t *)_event; + + CloseHandle(event->handle); + + free(event); +} + +static void init_cdrom_host_drives(void) +{ + int i = 0; + WCHAR s[64]; + + host_cdrom_drive_available_num = 0; + + for (i='A'; i<='Z'; i++) + { + _swprintf(s, L"%c:\\", i); + + if (GetDriveType(s)==DRIVE_CDROM) + { + host_cdrom_drive_available[i - 'A'] = 1; + + host_cdrom_drive_available_num++; + } + else + { + host_cdrom_drive_available[i - 'A'] = 0; + } + } +} + + +HMENU create_popup_menu(int part) +{ + HMENU newHandle; + newHandle = CreatePopupMenu(); + AppendMenu(smenu, MF_POPUP, (UINT_PTR) newHandle, 0); + return newHandle; +} + + +void create_floppy_submenu(HMENU m, int id) +{ + AppendMenu(m, MF_STRING, IDM_FLOPPY_IMAGE_NEW | id, win_language_get_string_from_id(2211)); + AppendMenu(m, MF_SEPARATOR, 0, 0); + AppendMenu(m, MF_STRING, IDM_FLOPPY_IMAGE_EXISTING | id, win_language_get_string_from_id(2212)); + AppendMenu(m, MF_STRING, IDM_FLOPPY_IMAGE_EXISTING_WP | id, win_language_get_string_from_id(2213)); + AppendMenu(m, MF_SEPARATOR, 0, 0); + AppendMenu(m, MF_STRING, IDM_FLOPPY_EJECT | id, win_language_get_string_from_id(2214)); +} + +void create_cdrom_submenu(HMENU m, int id) +{ + int i = 0; + WCHAR s[64]; + + AppendMenu(m, MF_STRING, IDM_CDROM_MUTE | id, win_language_get_string_from_id(2215)); + AppendMenu(m, MF_SEPARATOR, 0, 0); + AppendMenu(m, MF_STRING, IDM_CDROM_EMPTY | id, win_language_get_string_from_id(2216)); + AppendMenu(m, MF_STRING, IDM_CDROM_RELOAD | id, win_language_get_string_from_id(2217)); + AppendMenu(m, MF_SEPARATOR, 0, 0); + AppendMenu(m, MF_STRING, IDM_CDROM_IMAGE | id, win_language_get_string_from_id(2218)); + + if (host_cdrom_drive_available_num == 0) + { + if ((cdrom_drives[id].host_drive >= 'A') && (cdrom_drives[id].host_drive <= 'Z')) + { + cdrom_drives[id].host_drive = 0; + } + + goto check_menu_items; + } + else + { + if ((cdrom_drives[id].host_drive >= 'A') && (cdrom_drives[id].host_drive <= 'Z')) + { + if (!host_cdrom_drive_available[cdrom_drives[id].host_drive - 'A']) + { + cdrom_drives[id].host_drive = 0; + } + } + } + + AppendMenu(m, MF_SEPARATOR, 0, 0); + + for (i = 0; i < 26; i++) + { + _swprintf(s, L"Host CD/DVD Drive (%c:)", i + 0x41); + if (host_cdrom_drive_available[i]) + { + AppendMenu(m, MF_STRING, IDM_CDROM_HOST_DRIVE | (i << 3) | id, s); + } + } + +check_menu_items: + if (!cdrom_drives[id].sound_on) + { + CheckMenuItem(m, IDM_CDROM_MUTE | id, MF_CHECKED); + } + + if (cdrom_drives[id].host_drive == 200) + { + CheckMenuItem(m, IDM_CDROM_IMAGE | id, MF_CHECKED); + } + else if ((cdrom_drives[id].host_drive >= 'A') && (cdrom_drives[id].host_drive <= 'Z')) + { + CheckMenuItem(m, IDM_CDROM_HOST_DRIVE | id | ((cdrom_drives[id].host_drive - 'A') << 3), MF_CHECKED); + } + else + { + cdrom_drives[id].host_drive = 0; + CheckMenuItem(m, IDM_CDROM_EMPTY | id, MF_CHECKED); + } +} + +void create_removable_disk_submenu(HMENU m, int id) +{ + AppendMenu(m, MF_STRING, IDM_RDISK_EJECT | id, win_language_get_string_from_id(2216)); + AppendMenu(m, MF_STRING, IDM_RDISK_RELOAD | id, win_language_get_string_from_id(2217)); + AppendMenu(m, MF_SEPARATOR, 0, 0); + AppendMenu(m, MF_STRING, IDM_RDISK_SEND_CHANGE | id, win_language_get_string_from_id(2201)); + AppendMenu(m, MF_SEPARATOR, 0, 0); + AppendMenu(m, MF_STRING, IDM_RDISK_IMAGE | id, win_language_get_string_from_id(2218)); + AppendMenu(m, MF_STRING, IDM_RDISK_IMAGE_WP | id, win_language_get_string_from_id(2220)); +} + +void get_executable_name(wchar_t *s, int size) +{ + GetModuleFileName(hinstance, s, size); +} + +void set_window_title(wchar_t *s) +{ + if (video_fullscreen) + return; + SetWindowText(ghwnd, s); +} + +uint64_t timer_read(void) +{ + LARGE_INTEGER qpc_time; + QueryPerformanceCounter(&qpc_time); + return qpc_time.QuadPart; +} + +static void process_command_line(void) +{ + WCHAR *cmdline; + int argc_max; + int i, q; + + cmdline = GetCommandLine(); + i = wcslen(cmdline) + 1; + argbuf = malloc(i * 2); + memcpy(argbuf, cmdline, i * 2); + + argc = 0; + argc_max = 64; + argv = malloc(sizeof(wchar_t *) * argc_max); + if (!argv) + { + free(argbuf); + return; + } + + i = 0; + + /* parse commandline into argc/argv format */ + while (argbuf[i]) + { + while (argbuf[i] == L' ') + i++; + + if (argbuf[i]) + { + if ((argbuf[i] == L'\'') || (argbuf[i] == L'"')) + { + q = argbuf[i++]; + if (!argbuf[i]) + break; + } + else + q = 0; + + argv[argc++] = &argbuf[i]; + + if (argc >= argc_max) + { + argc_max += 64; + argv = realloc(argv, sizeof(wchar_t *) * argc_max); + if (!argv) + { + free(argbuf); + return; + } + } + + while ((argbuf[i]) && ((q) ? (argbuf[i] != q) : (argbuf[i] != L' '))) + i++; + + if (argbuf[i]) + { + argbuf[i] = 0; + i++; + } + } + } + + argv[argc] = NULL; +} + +int find_in_array(int *array, int val, int len, int menu_base) +{ + int i = 0; + int temp = 0; + for (i = 0; i < len; i++) + { + CheckMenuItem(menu, menu_base + array[i], MF_UNCHECKED); + if (array[i] == val) + { + temp = 1; + } + } + return temp; +} + +HICON LoadIconEx(PCTSTR pszIconName) +{ + return (HICON) LoadImage(hinstance, pszIconName, IMAGE_ICON, 16, 16, LR_SHARED); +} + +HICON LoadIconBig(PCTSTR pszIconName) +{ + return (HICON) LoadImage(hinstance, pszIconName, IMAGE_ICON, 64, 64, 0); +} + +int fdd_type_to_icon(int type) +{ + switch(type) + { + default: + case 0: + return 512; + case 1: + return 128; + case 2: + return 130; + case 3: + return 132; + case 4: + case 5: + case 6: + return 134; + case 7: + return 144; + case 8: + return 146; + case 9: + case 10: + case 11: + case 12: + return 150; + case 13: + return 152; + } +} + +int count_hard_disks(int bus) +{ + int i = 0; + + int c = 0; + + for (i = 0; i < HDC_NUM; i++) + { + if (hdc[i].bus == bus) + { + c++; + } + } + + return c; +} + +int find_status_bar_part(int tag) +{ + int i = 0; + int found = -1; + + if (!sb_ready || (sb_parts == 0) || (sb_part_meanings == NULL)) + { + return -1; + } + + for (i = 0; i < sb_parts; i++) + { + if (sb_part_meanings[i] == tag) + { + found = i; + break; + } + } + + return found; +} + +/* This is for the disk activity indicator. */ +void update_status_bar_icon(int tag, int active) +{ + int found = -1; + int temp_flags = 0; + + if (((tag & 0xf0) >= SB_TEXT) || !sb_ready || (sb_parts == 0) || (sb_icon_flags == NULL) || (sb_part_icons == NULL)) + { + return; + } + + temp_flags |= active; + + found = find_status_bar_part(tag); + + if (found != -1) + { + if (temp_flags != (sb_icon_flags[found] & 1)) + { + sb_icon_flags[found] &= ~1; + sb_icon_flags[found] |= active; + + sb_part_icons[found] &= ~257; + sb_part_icons[found] |= sb_icon_flags[found]; + + SendMessage(hwndStatus, SB_SETICON, found, (LPARAM) hIcon[sb_part_icons[found]]); + } + } +} + +/* This is for the drive state indicator. */ +void update_status_bar_icon_state(int tag, int state) +{ + int found = -1; + + if (((tag & 0xf0) >= SB_HDD) || !sb_ready || (sb_parts == 0) || (sb_icon_flags == NULL) || (sb_part_icons == NULL)) + { + return; + } + + found = find_status_bar_part(tag); + + if (found != -1) + { + sb_icon_flags[found] &= ~256; + sb_icon_flags[found] |= state ? 256 : 0; + + sb_part_icons[found] &= ~257; + sb_part_icons[found] |= sb_icon_flags[found]; + + SendMessage(hwndStatus, SB_SETICON, found, (LPARAM) hIcon[sb_part_icons[found]]); + } +} + +void create_floppy_tip(int part) +{ + WCHAR wtext[512]; + WCHAR tempTip[512]; + + int drive = sb_part_meanings[part] & 0xf; + + mbstowcs(wtext, fdd_getname(fdd_get_type(drive)), strlen(fdd_getname(fdd_get_type(drive))) + 1); + if (wcslen(discfns[drive]) == 0) + { + _swprintf(tempTip, win_language_get_string_from_id(2179), drive + 1, wtext, win_language_get_string_from_id(2185)); + } + else + { + _swprintf(tempTip, win_language_get_string_from_id(2179), drive + 1, wtext, discfns[drive]); + } + + if (sbTips[part] != NULL) + { + free(sbTips[part]); + } + sbTips[part] = (WCHAR *) malloc((wcslen(tempTip) << 1) + 2); + wcscpy(sbTips[part], tempTip); +} + +void create_cdrom_tip(int part) +{ + WCHAR wtext[512]; + WCHAR tempTip[512]; + + int drive = sb_part_meanings[part] & 0xf; + + if (cdrom_drives[drive].host_drive == 200) + { + if (wcslen(cdrom_image[drive].image_path) == 0) + { + _swprintf(tempTip, win_language_get_string_from_id(2180), drive + 1, win_language_get_string_from_id(2185)); + } + else + { + _swprintf(tempTip, win_language_get_string_from_id(2180), drive + 1, cdrom_image[drive].image_path); + } + } + else if (cdrom_drives[drive].host_drive < 0x41) + { + _swprintf(tempTip, win_language_get_string_from_id(2180), drive + 1, win_language_get_string_from_id(2185)); + } + else + { + _swprintf(wtext, win_language_get_string_from_id(2186), cdrom_drives[drive].host_drive & ~0x20); + _swprintf(tempTip, win_language_get_string_from_id(2180), drive + 1, wtext); + } + + if (sbTips[part] != NULL) + { + free(sbTips[part]); + } + sbTips[part] = (WCHAR *) malloc((wcslen(tempTip) << 1) + 2); + wcscpy(sbTips[part], tempTip); +} + +void create_removable_hd_tip(int part) +{ + WCHAR tempTip[512]; + + int drive = sb_part_meanings[part] & 0x1f; + + if (wcslen(hdc[drive].fn) == 0) + { + _swprintf(tempTip, win_language_get_string_from_id(2198), drive, win_language_get_string_from_id(2185)); + } + else + { + _swprintf(tempTip, win_language_get_string_from_id(2198), drive, hdc[drive].fn); + } + + if (sbTips[part] != NULL) + { + free(sbTips[part]); + } + sbTips[part] = (WCHAR *) malloc((wcslen(tempTip) << 1) + 2); + wcscpy(sbTips[part], tempTip); +} + +void create_hd_tip(int part) +{ + WCHAR *szText; + int id = 2181; + + int bus = sb_part_meanings[part] & 0xf; + + switch(bus) + { + case HDD_BUS_MFM: + id = 2181; + break; + case HDD_BUS_RLL: + id = 2207; + break; + case HDD_BUS_XTIDE: + id = 2208; + break; + case HDD_BUS_IDE_PIO_ONLY: + id = 2182; + break; + case HDD_BUS_IDE_PIO_AND_DMA: + id = 2183; + break; + case HDD_BUS_SCSI: + id = 2184; + break; + } + + szText = (WCHAR *) win_language_get_string_from_id(id); + + if (sbTips[part] != NULL) + { + free(sbTips[part]); + } + sbTips[part] = (WCHAR *) malloc((wcslen(szText) << 1) + 2); + wcscpy(sbTips[part], szText); +} + +void update_tip(int meaning) +{ + int i = 0; + int part = -1; + + if (!sb_ready || (sb_parts == 0) || (sb_part_meanings == NULL)) + { + return; + } + + for (i = 0; i < sb_parts; i++) + { + if (sb_part_meanings[i] == meaning) + { + part = i; + } + } + + if (part != -1) + { + switch(meaning & 0xf0) + { + case SB_FLOPPY: + create_floppy_tip(part); + break; + case SB_CDROM: + create_cdrom_tip(part); + break; + case SB_RDISK: + create_removable_hd_tip(part); + break; + case SB_HDD: + create_hd_tip(part); + break; + default: + break; + } + + SendMessage(hwndStatus, SB_SETTIPTEXT, part, (LPARAM) sbTips[part]); + } +} + +void status_settextw(wchar_t *wstr) +{ + int i = 0; + int part = -1; + + if (!sb_ready || (sb_parts == 0) || (sb_part_meanings == NULL)) + { + return; + } + + for (i = 0; i < sb_parts; i++) + { + if (sb_part_meanings[i] == SB_TEXT) + { + part = i; + } + } + + if (part != -1) + { + SendMessage(hwndStatus, SB_SETTEXT, part | SBT_NOBORDERS, (LPARAM) wstr); + } +} + +static wchar_t cwstr[512]; + +void status_settext(char *str) +{ + memset(cwstr, 0, 1024); + mbstowcs(cwstr, str, strlen(str) + 1); + status_settextw(cwstr); +} + +void destroy_menu_handles(void) +{ + int i = 0; + + if (sb_parts == 0) + { + return; + } + + for (i = 0; i < sb_parts; i++) + { + DestroyMenu(sb_menu_handles[i]); + } + + free(sb_menu_handles); +} + +void destroy_tips(void) +{ + int i = 0; + + if (sb_parts == 0) + { + return; + } + + for (i = 0; i < sb_parts; i++) + { + free(sbTips[i]); + } + + free(sbTips); +} + +void update_status_bar_panes(HWND hwnds) +{ + int i, j, id; + int edge = 0; + + int c_mfm = 0; + int c_rll = 0; + int c_xtide = 0; + int c_ide_pio = 0; + int c_ide_dma = 0; + int c_scsi = 0; + + sb_ready = 0; + + c_mfm = count_hard_disks(HDD_BUS_MFM); + c_rll = count_hard_disks(HDD_BUS_RLL); + c_xtide = count_hard_disks(HDD_BUS_XTIDE); + c_ide_pio = count_hard_disks(HDD_BUS_IDE_PIO_ONLY); + c_ide_dma = count_hard_disks(HDD_BUS_IDE_PIO_AND_DMA); + c_scsi = count_hard_disks(HDD_BUS_SCSI); + + if (sb_parts > 0) + { + for (i = 0; i < sb_parts; i++) + { + SendMessage(hwnds, SB_SETICON, i, (LPARAM) NULL); + } + + sb_parts = 0; + + free(iStatusWidths); + free(sb_part_meanings); + free(sb_part_icons); + free(sb_icon_flags); + destroy_menu_handles(); + destroy_tips(); + } + + for (i = 0; i < FDD_NUM; i++) + { + if (fdd_get_type(i) != 0) + { + /* pclog("update_status_bar_panes(): Found floppy drive %c:, type %i\n", 65 + i, fdd_get_type(i)); */ + sb_parts++; + } + } + for (i = 0; i < CDROM_NUM; i++) + { + if (cdrom_drives[i].bus_type != 0) + { + sb_parts++; + } + } + for (i = 0; i < HDC_NUM; i++) + { + if (hdc[i].bus == HDD_BUS_SCSI_REMOVABLE) + { + sb_parts++; + } + } + if (c_mfm && !(models[model].flags & MODEL_HAS_IDE) && !!memcmp(hdd_controller_name, "none", 4) && !!memcmp(hdd_controller_name, "xtide", 5) && !!memcmp(hdd_controller_name, "esdi", 4)) + { + sb_parts++; + } + if (c_rll && !memcmp(hdd_controller_name, "esdi", 4)) + { + sb_parts++; + } + if (c_xtide && !memcmp(hdd_controller_name, "xtide", 5)) + { + sb_parts++; + } + if (c_ide_pio && (models[model].flags & MODEL_HAS_IDE)) + { + sb_parts++; + } + if (c_ide_dma && (models[model].flags & MODEL_HAS_IDE)) + { + sb_parts++; + } + if (c_scsi && (scsi_card_current != 0)) + { + sb_parts++; + } + sb_parts++; + + iStatusWidths = (int *) malloc(sb_parts * sizeof(int)); + sb_part_meanings = (int *) malloc(sb_parts * sizeof(int)); + sb_part_icons = (int *) malloc(sb_parts * sizeof(int)); + sb_icon_flags = (int *) malloc(sb_parts * sizeof(int)); + sb_menu_handles = (HMENU *) malloc(sb_parts * sizeof(HMENU)); + sbTips = (WCHAR **) malloc(sb_parts * sizeof(WCHAR *)); + + memset(iStatusWidths, 0, sb_parts * sizeof(int)); + memset(sb_part_meanings, 0, sb_parts * sizeof(int)); + memset(sb_part_icons, 0, sb_parts * sizeof(int)); + memset(sb_icon_flags, 0, sb_parts * sizeof(int)); + memset(sb_menu_handles, 0, sb_parts * sizeof(HMENU)); + memset(sbTips, 0, sb_parts * sizeof(WCHAR *)); + + sb_parts = 0; + + for (i = 0; i < FDD_NUM; i++) + { + if (fdd_get_type(i) != 0) + { + /* pclog("update_status_bar_panes(): Found floppy drive %c:, type %i\n", 65 + i, fdd_get_type(i)); */ + edge += SB_ICON_WIDTH; + iStatusWidths[sb_parts] = edge; + sb_part_meanings[sb_parts] = SB_FLOPPY | i; + sb_parts++; + } + } + for (i = 0; i < CDROM_NUM; i++) + { + if (cdrom_drives[i].bus_type != 0) + { + edge += SB_ICON_WIDTH; + iStatusWidths[sb_parts] = edge; + sb_part_meanings[sb_parts] = SB_CDROM | i; + sb_parts++; + } + } + for (i = 0; i < HDC_NUM; i++) + { + if (hdc[i].bus == HDD_BUS_SCSI_REMOVABLE) + { + edge += SB_ICON_WIDTH; + iStatusWidths[sb_parts] = edge; + sb_part_meanings[sb_parts] = SB_RDISK | i; + sb_parts++; + } + } + if (c_mfm && !(models[model].flags & MODEL_HAS_IDE) && !!memcmp(hdd_controller_name, "none", 4) && !!memcmp(hdd_controller_name, "xtide", 5) && !!memcmp(hdd_controller_name, "esdi", 4)) + { + edge += SB_ICON_WIDTH; + iStatusWidths[sb_parts] = edge; + sb_part_meanings[sb_parts] = SB_HDD | HDD_BUS_MFM; + sb_parts++; + } + if (c_rll && !memcmp(hdd_controller_name, "esdi", 4)) + { + edge += SB_ICON_WIDTH; + iStatusWidths[sb_parts] = edge; + sb_part_meanings[sb_parts] = SB_HDD | HDD_BUS_RLL; + sb_parts++; + } + if (c_xtide && !memcmp(hdd_controller_name, "xtide", 5)) + { + edge += SB_ICON_WIDTH; + iStatusWidths[sb_parts] = edge; + sb_part_meanings[sb_parts] = SB_HDD | HDD_BUS_XTIDE; + sb_parts++; + } + if (c_ide_pio && (models[model].flags & MODEL_HAS_IDE)) + { + edge += SB_ICON_WIDTH; + iStatusWidths[sb_parts] = edge; + sb_part_meanings[sb_parts] = SB_HDD | HDD_BUS_IDE_PIO_ONLY; + sb_parts++; + } + if (c_ide_dma && (models[model].flags & MODEL_HAS_IDE)) + { + edge += SB_ICON_WIDTH; + iStatusWidths[sb_parts] = edge; + sb_part_meanings[sb_parts] = SB_HDD | HDD_BUS_IDE_PIO_AND_DMA; + sb_parts++; + } + if (c_scsi) + { + edge += SB_ICON_WIDTH; + iStatusWidths[sb_parts] = edge; + sb_part_meanings[sb_parts] = SB_HDD | HDD_BUS_SCSI; + sb_parts++; + } + if (sb_parts) + { + iStatusWidths[sb_parts - 1] += (24 - SB_ICON_WIDTH); + } + iStatusWidths[sb_parts] = -1; + sb_part_meanings[sb_parts] = SB_TEXT; + sb_parts++; + + SendMessage(hwnds, SB_SETPARTS, (WPARAM) sb_parts, (LPARAM) iStatusWidths); + + for (i = 0; i < sb_parts; i++) + { + switch (sb_part_meanings[i] & 0xf0) + { + case SB_FLOPPY: + /* Floppy */ + sb_icon_flags[i] = (wcslen(discfns[sb_part_meanings[i] & 0xf]) == 0) ? 256 : 0; + sb_part_icons[i] = fdd_type_to_icon(fdd_get_type(sb_part_meanings[i] & 0xf)) | sb_icon_flags[i]; + sb_menu_handles[i] = create_popup_menu(i); + create_floppy_submenu(sb_menu_handles[i], sb_part_meanings[i] & 0xf); + EnableMenuItem(sb_menu_handles[i], IDM_FLOPPY_EJECT | (sb_part_meanings[i] & 0xf), MF_BYCOMMAND | ((sb_icon_flags[i] & 256) ? MF_GRAYED : MF_ENABLED)); + create_floppy_tip(i); + break; + case SB_CDROM: + /* CD-ROM */ + id = sb_part_meanings[i] & 0xf; + if (cdrom_drives[id].host_drive == 200) + { + sb_icon_flags[i] = (wcslen(cdrom_image[id].image_path) == 0) ? 256 : 0; + } + else if ((cdrom_drives[id].host_drive >= 'A') && (cdrom_drives[id].host_drive <= 'Z')) + { + sb_icon_flags[i] = 0; + } + else + { + sb_icon_flags[i] = 256; + } + if (cdrom_drives[id].bus_type == CDROM_BUS_SCSI) + { + j = 164; + } + else if (cdrom_drives[id].bus_type == CDROM_BUS_ATAPI_PIO_AND_DMA) + { + j = 162; + } + else + { + j = 160; + } + sb_part_icons[i] = j | sb_icon_flags[i]; + sb_menu_handles[i] = create_popup_menu(i); + create_cdrom_submenu(sb_menu_handles[i], sb_part_meanings[i] & 0xf); + EnableMenuItem(sb_menu_handles[i], IDM_CDROM_RELOAD | (sb_part_meanings[i] & 0xf), MF_BYCOMMAND | MF_GRAYED); + create_cdrom_tip(i); + break; + case SB_RDISK: + /* Removable hard disk */ + sb_icon_flags[i] = (wcslen(hdc[sb_part_meanings[i] & 0x1f].fn) == 0) ? 256 : 0; + sb_part_icons[i] = 176 + sb_icon_flags[i]; + sb_menu_handles[i] = create_popup_menu(i); + create_removable_disk_submenu(sb_menu_handles[i], sb_part_meanings[i] & 0x1f); + EnableMenuItem(sb_menu_handles[i], IDM_RDISK_EJECT | (sb_part_meanings[i] & 0x1f), MF_BYCOMMAND | ((sb_icon_flags[i] & 256) ? MF_GRAYED : MF_ENABLED)); + EnableMenuItem(sb_menu_handles[i], IDM_RDISK_RELOAD | (sb_part_meanings[i] & 0x1f), MF_BYCOMMAND | MF_GRAYED); + EnableMenuItem(sb_menu_handles[i], IDM_RDISK_SEND_CHANGE | (sb_part_meanings[i] & 0x1f), MF_BYCOMMAND | ((sb_icon_flags[i] & 256) ? MF_GRAYED : MF_ENABLED)); + create_removable_hd_tip(i); + break; + case SB_HDD: + /* Hard disk */ + sb_part_icons[i] = 192 + (((sb_part_meanings[i] & 0xf) - 1) << 1); + create_hd_tip(i); + break; + case SB_TEXT: + /* Status text */ + SendMessage(hwnds, SB_SETTEXT, i | SBT_NOBORDERS, (LPARAM) L""); + sb_part_icons[i] = -1; + break; + } + if (sb_part_icons[i] != -1) + { + SendMessage(hwnds, SB_SETTEXT, i | SBT_NOBORDERS, (LPARAM) ""); + SendMessage(hwnds, SB_SETICON, i, (LPARAM) hIcon[sb_part_icons[i]]); + SendMessage(hwnds, SB_SETTIPTEXT, i, (LPARAM) sbTips[i]); + /* pclog("Status bar part found: %02X (%i)\n", sb_part_meanings[i], sb_part_icons[i]); */ + } + else + { + SendMessage(hwnds, SB_SETICON, i, (LPARAM) NULL); + } + } + + sb_ready = 1; +} + +HWND EmulatorStatusBar(HWND hwndParent, int idStatus, HINSTANCE hinst) +{ + HWND hwndStatus; + int i; + RECT rectDialog; + int dw, dh; + + for (i = 128; i < 136; i++) + { + hIcon[i] = LoadIconEx((PCTSTR) i); + } + + for (i = 144; i < 148; i++) + { + hIcon[i] = LoadIconEx((PCTSTR) i); + } + + for (i = 150; i < 154; i++) + { + hIcon[i] = LoadIconEx((PCTSTR) i); + } + + for (i = 160; i < 166; i++) + { + hIcon[i] = LoadIconEx((PCTSTR) i); + } + + for (i = 176; i < 178; i++) + { + hIcon[i] = LoadIconEx((PCTSTR) i); + } + + for (i = 192; i < 204; i++) + { + hIcon[i] = LoadIconEx((PCTSTR) i); + } + + for (i = 384; i < 392; i++) + { + hIcon[i] = LoadIconEx((PCTSTR) i); + } + + for (i = 400; i < 404; i++) + { + hIcon[i] = LoadIconEx((PCTSTR) i); + } + + for (i = 406; i < 410; i++) + { + hIcon[i] = LoadIconEx((PCTSTR) i); + } + + for (i = 416; i < 422; i++) + { + hIcon[i] = LoadIconEx((PCTSTR) i); + } + + for (i = 432; i < 434; i++) + { + hIcon[i] = LoadIconEx((PCTSTR) i); + } + + GetWindowRect(hwndParent, &rectDialog); + dw = rectDialog.right - rectDialog.left; + dh = rectDialog.bottom - rectDialog.top; + + InitCommonControls(); + + hwndStatus = CreateWindowEx(0, STATUSCLASSNAME, (PCTSTR) NULL, SBARS_SIZEGRIP | WS_CHILD | WS_VISIBLE | SBT_TOOLTIPS, 0, dh - 17, dw, 17, hwndParent, + (HMENU) idStatus, hinst, NULL); + + GetWindowRect(hwndStatus, &rectDialog); + + SetWindowPos(hwndStatus, HWND_TOPMOST, rectDialog.left, rectDialog.top, rectDialog.right - rectDialog.left, rectDialog.bottom - rectDialog.top, SWP_SHOWWINDOW); + + SendMessage(hwndStatus, SB_SETMINHEIGHT, (WPARAM) 17, (LPARAM) 0); + + sb_parts = 0; + + update_status_bar_panes(hwndStatus); + + return hwndStatus; +} + +void win_menu_update(void) +{ +#if 0 + menu = LoadMenu(hThisInstance, TEXT("MainMenu")); + + smenu = LoadMenu(hThisInstance, TEXT("StatusBarMenu")); + initmenu(); + + SetMenu(ghwnd, menu); + + win_title_update = 1; +#endif +} + +int WINAPI WinMain (HINSTANCE hThisInstance, HINSTANCE hPrevInstance, LPSTR lpszArgument, int nFunsterStil) +{ + HWND hwnd; /* This is the handle for our window */ + MSG messages; /* Here messages to the application are saved */ + WNDCLASSEX wincl; /* Data structure for the windowclass */ + int c, d, bRet; + WCHAR emulator_title[200]; + LARGE_INTEGER qpc_freq; + HACCEL haccel; /* Handle to accelerator table */ + + memset(recv_key, 0, sizeof(recv_key)); + + process_command_line(); + + win_language_load_common_strings(); + + hinstance=hThisInstance; + /* The Window structure */ + wincl.hInstance = hThisInstance; + wincl.lpszClassName = szClassName; + wincl.lpfnWndProc = WindowProcedure; /* This function is called by windows */ + wincl.style = CS_DBLCLKS; /* Catch double-clicks */ + wincl.cbSize = sizeof (WNDCLASSEX); + + /* Use default icon and mouse-pointer */ + wincl.hIcon = LoadIcon(hinstance, (LPCTSTR) 100); + wincl.hIconSm = LoadIcon(hinstance, (LPCTSTR) 100); + wincl.hCursor = NULL; + wincl.lpszMenuName = NULL; /* No menu */ + wincl.cbClsExtra = 0; /* No extra bytes after the window class */ + wincl.cbWndExtra = 0; /* structure or the window instance */ + /* Use Windows's default color as the background of the window */ + wincl.hbrBackground = (HBRUSH) COLOR_BACKGROUND; + + /* Register the window class, and if it fails quit the program */ + if (!RegisterClassEx(&wincl)) + { + return 0; + } + + wincl.lpszClassName = szSubClassName; + wincl.lpfnWndProc = subWindowProcedure; /* This function is called by windows */ + + if (!RegisterClassEx(&wincl)) + { + return 0; + } + + menu = LoadMenu(hThisInstance, TEXT("MainMenu")); + + _swprintf(emulator_title, L"%s v%s", EMU_NAME_W, EMU_VERSION_W); + + /* The class is registered, let's create the program*/ + hwnd = CreateWindowEx ( + 0, /* Extended possibilites for variation */ + szClassName, /* Classname */ + emulator_title, /* Title Text */ + (WS_OVERLAPPEDWINDOW & ~WS_SIZEBOX)/* | DS_3DLOOK*/, /* default window */ + CW_USEDEFAULT, /* Windows decides the position */ + CW_USEDEFAULT, /* where the window ends up on the screen */ + 640+(GetSystemMetrics(SM_CXFIXEDFRAME)*2), /* The programs width */ + 480+(GetSystemMetrics(SM_CYFIXEDFRAME)*2)+GetSystemMetrics(SM_CYMENUSIZE)+GetSystemMetrics(SM_CYCAPTION)+1, /* and height in pixels */ + HWND_DESKTOP, /* The window is a child-window to desktop */ + menu, /* Menu */ + hThisInstance, /* Program Instance handler */ + NULL /* No Window Creation data */ + ); + + /* Make the window visible on the screen */ + ShowWindow (hwnd, nFunsterStil); + + /* Load the accelerator table */ + haccel = LoadAccelerators(hinstAcc, L"MainAccel"); + if (haccel == NULL) + { + fatal("haccel is null\n"); + } + + device.usUsagePage = 0x01; + device.usUsage = 0x06; + device.dwFlags = RIDEV_NOHOTKEYS; + device.hwndTarget = hwnd; + + if (RegisterRawInputDevices(&device, 1, sizeof(device))) + { + pclog("Raw input registered!\n"); + } + else + { + pclog("Raw input registration failed!\n"); + } + + get_registry_key_map(); + + ghwnd=hwnd; + + hwndRender = CreateWindow(L"STATIC", NULL, WS_VISIBLE | WS_CHILD | SS_BITMAP, 0, 0, 1, 1, ghwnd, NULL, hinstance, NULL); + + initpc(argc, argv); + + init_cdrom_host_drives(); + + hwndStatus = EmulatorStatusBar(hwnd, IDC_STATUS, hThisInstance); + + OriginalStatusBarProcedure = GetWindowLongPtr(hwndStatus, GWLP_WNDPROC); + SetWindowLongPtr(hwndStatus, GWL_WNDPROC, (LONG_PTR) &StatusBarProcedure); + + smenu = LoadMenu(hThisInstance, TEXT("StatusBarMenu")); + + initmodules(); + + if (vid_apis[0][vid_api].init(hwndRender) == 0) + { + if (vid_apis[0][vid_api ^ 1].init(hwndRender) == 0) + { + fatal("Both DirectDraw and Direct3D renderers failed to initialize\n"); + } + else + { + vid_api ^= 1; + } + } + + if (vid_resize) SetWindowLongPtr(hwnd, GWL_STYLE, (WS_OVERLAPPEDWINDOW&~WS_MINIMIZEBOX)|WS_VISIBLE); + else SetWindowLongPtr(hwnd, GWL_STYLE, (WS_OVERLAPPEDWINDOW&~WS_SIZEBOX&~WS_THICKFRAME&~WS_MAXIMIZEBOX&~WS_MINIMIZEBOX)|WS_VISIBLE); + +#ifdef ENABLE_LOG_TOGGLES +# ifdef ENABLE_BUSLOGIC_LOG + CheckMenuItem(menu, IDM_LOG_BUSLOGIC, buslogic_do_log ? MF_CHECKED : MF_UNCHECKED); +# endif +# ifdef ENABLE_CDROM_LOG + CheckMenuItem(menu, IDM_LOG_CDROM, cdrom_do_log ? MF_CHECKED : MF_UNCHECKED); +# endif +# ifdef ENABLE_D86F_LOG + CheckMenuItem(menu, IDM_LOG_D86F, d86f_do_log ? MF_CHECKED : MF_UNCHECKED); +# endif +# ifdef ENABLE_FDC_LOG + CheckMenuItem(menu, IDM_LOG_FDC, fdc_do_log ? MF_CHECKED : MF_UNCHECKED); +# endif +# ifdef ENABLE_IDE_LOG + CheckMenuItem(menu, IDM_LOG_IDE, ide_do_log ? MF_CHECKED : MF_UNCHECKED); +# endif +# ifdef ENABLE_SERIAL_LOG + CheckMenuItem(menu, IDM_LOG_SERIAL, serial_do_log ? MF_CHECKED : MF_UNCHECKED); +# endif +# ifdef ENABLE_NIC_LOG + /*FIXME: should be network_setlog(1:0) */ + CheckMenuItem(menu, IDM_LOG_NIC, nic_do_log ? MF_CHECKED : MF_UNCHECKED); +# endif +#endif + + CheckMenuItem(menu, IDM_VID_FORCE43, force_43 ? MF_CHECKED : MF_UNCHECKED); + CheckMenuItem(menu, IDM_VID_OVERSCAN, enable_overscan ? MF_CHECKED : MF_UNCHECKED); + CheckMenuItem(menu, IDM_VID_INVERT, invert_display ? MF_CHECKED : MF_UNCHECKED); + + if (vid_resize) CheckMenuItem(menu, IDM_VID_RESIZE, MF_CHECKED); + CheckMenuItem(menu, IDM_VID_DDRAW + vid_api, MF_CHECKED); + CheckMenuItem(menu, IDM_VID_FS_FULL + video_fullscreen_scale, MF_CHECKED); + CheckMenuItem(menu, IDM_VID_REMEMBER, window_remember ? MF_CHECKED : MF_UNCHECKED); + CheckMenuItem(menu, IDM_VID_SCALE_1X + scale, MF_CHECKED); + + CheckMenuItem(menu, IDM_VID_CGACON, vid_cga_contrast ? MF_CHECKED : MF_UNCHECKED); + + d=romset; + for (c=0;c= 0; c--) + { + if (gfx_present[c]) + { + gfxcard = c; + saveconfig(); + resetpchard(); + break; + } + } + } + + loadbios(); + resetpchard(); + + timeBeginPeriod(1); + + atexit(releasemouse); + + ghMutex = CreateMutex(NULL, FALSE, NULL); + mainthreadh=(HANDLE)_beginthread(mainthread,0,NULL); + SetThreadPriority(mainthreadh, THREAD_PRIORITY_HIGHEST); + + updatewindowsize(640, 480); + + QueryPerformanceFrequency(&qpc_freq); + timer_freq = qpc_freq.QuadPart; + + if (start_in_fullscreen) + { + startblit(); + mouse_close(); + vid_apis[0][vid_api].close(); + video_fullscreen = 1; + vid_apis[1][vid_api].init(hwndRender); + mouse_init(); + leave_fullscreen_flag = 0; + endblit(); + device_force_redraw(); + } + if (window_remember) + { + MoveWindow(hwnd, window_x, window_y, + window_w, + window_h, + TRUE); + } + else + { + MoveWindow(hwndRender, 0, 0, + winsizex, + winsizey, + TRUE); + MoveWindow(hwndStatus, 0, winsizey + 6, + winsizex, + 17, + TRUE); + } + + /* Run the message loop. It will run until GetMessage() returns 0 */ + while (!quited) + { + while (((bRet = GetMessage(&messages,NULL,0,0)) != 0) && !quited) + { + if (bRet == -1) + { + fatal("bRet is -1\n"); + } + + if (messages.message==WM_QUIT) quited=1; + if (!TranslateAccelerator(hwnd, haccel, &messages)) + { + TranslateMessage(&messages); + DispatchMessage(&messages); + } + + if (recv_key[0x58] && recv_key[0x42] && mousecapture) + { + ClipCursor(&oldclip); + ShowCursor(TRUE); + mousecapture=0; + } + + if ((recv_key[0x1D] || recv_key[0x9D]) && (recv_key[0x38] || recv_key[0xB8]) && (recv_key[0x51] || recv_key[0xD1]) && + video_fullscreen) + { + leave_fullscreen(); + } + } + + quited=1; + } + + startblit(); + Sleep(200); + TerminateThread(mainthreadh,0); + savenvr(); + saveconfig(); + closepc(); + + vid_apis[video_fullscreen][vid_api].close(); + + timeEndPeriod(1); + if (mousecapture) + { + ClipCursor(&oldclip); + ShowCursor(TRUE); + } + + UnregisterClass(szSubClassName, hinstance); + UnregisterClass(szClassName, hinstance); + + return messages.wParam; +} + +HHOOK hKeyboardHook; +int hook_enabled = 0; + +LRESULT CALLBACK LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam) +{ + BOOL bControlKeyDown; + KBDLLHOOKSTRUCT* p; + + if (nCode < 0 || nCode != HC_ACTION) + { + return CallNextHookEx( hKeyboardHook, nCode, wParam, lParam); + } + + p = (KBDLLHOOKSTRUCT*)lParam; + + if (p->vkCode == VK_TAB && p->flags & LLKHF_ALTDOWN) return 1; /* disable alt-tab */ + if (p->vkCode == VK_SPACE && p->flags & LLKHF_ALTDOWN) return 1; /* disable alt-tab */ + if((p->vkCode == VK_LWIN) || (p->vkCode == VK_RWIN)) return 1; /* disable windows keys */ + if (p->vkCode == VK_ESCAPE && p->flags & LLKHF_ALTDOWN) return 1; /* disable alt-escape */ + bControlKeyDown = GetAsyncKeyState (VK_CONTROL) >> ((sizeof(SHORT) * 8) - 1); /* checks ctrl key pressed */ + if (p->vkCode == VK_ESCAPE && bControlKeyDown) return 1; /* disable ctrl-escape */ + + return CallNextHookEx( hKeyboardHook, nCode, wParam, lParam ); +} + +void cdrom_close(uint8_t id) +{ + switch (cdrom_drives[id].host_drive) + { + case 0: + null_close(id); + break; + default: + ioctl_close(id); + break; + case 200: + image_close(id); + break; + } +} + +static BOOL CALLBACK about_dlgproc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + HWND h; + + switch (message) + { + case WM_INITDIALOG: + pause = 1; + h = GetDlgItem(hdlg, IDC_ABOUT_ICON); + SendMessage(h, STM_SETIMAGE, (WPARAM) IMAGE_ICON, (LPARAM) LoadIconBig((PCTSTR) 100)); + break; + + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case IDOK: + EndDialog(hdlg, 0); + pause = 0; + return TRUE; + default: + break; + } + break; + } + + return FALSE; +} + +void about_open(HWND hwnd) +{ + DialogBox(hinstance, (LPCTSTR)DLG_ABOUT, hwnd, about_dlgproc); +} + +static void win_pc_reset(int hard) +{ + pause=1; + Sleep(100); + savenvr(); + saveconfig(); + if (hard) + { + resetpchard(); + } + else + { + resetpc_cad(); + } + pause=0; +} + +void video_toggle_option(HMENU hmenu, int *val, int id) +{ + startblit(); + video_wait_for_blit(); + *val ^= 1; + CheckMenuItem(hmenu, id, *val ? MF_CHECKED : MF_UNCHECKED); + endblit(); + saveconfig(); + device_force_redraw(); +} + +LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + HMENU hmenu; + RECT rect; + int i = 0; + + switch (message) + { + case WM_CREATE: + SetTimer(hwnd, TIMER_1SEC, 1000, NULL); + hKeyboardHook = SetWindowsHookEx( WH_KEYBOARD_LL, LowLevelKeyboardProc, GetModuleHandle(NULL), 0 ); + hook_enabled = 1; + break; + + case WM_COMMAND: + hmenu=GetMenu(hwnd); + switch (LOWORD(wParam)) + { + case IDM_ACTION_SCREENSHOT: + take_screenshot(); + break; + + case IDM_ACTION_HRESET: + win_pc_reset(1); + break; + + case IDM_ACTION_RESET_CAD: + win_pc_reset(0); + break; + + case IDM_ACTION_EXIT: + PostQuitMessage (0); /* send a WM_QUIT to the message queue */ + break; + + case IDM_CONFIG: + win_settings_open(hwnd); + break; + + case IDM_ABOUT: + about_open(hwnd); + break; + + case IDM_STATUS: + status_open(hwnd); + break; + + case IDM_VID_RESIZE: + vid_resize = !vid_resize; + CheckMenuItem(hmenu, IDM_VID_RESIZE, (vid_resize)? MF_CHECKED : MF_UNCHECKED); + if (vid_resize) SetWindowLongPtr(hwnd, GWL_STYLE, (WS_OVERLAPPEDWINDOW & ~WS_MINIMIZEBOX) | WS_VISIBLE); + else SetWindowLongPtr(hwnd, GWL_STYLE, (WS_OVERLAPPEDWINDOW & ~WS_SIZEBOX & ~WS_THICKFRAME & ~WS_MAXIMIZEBOX & ~WS_MINIMIZEBOX) | WS_VISIBLE); + GetWindowRect(hwnd, &rect); + SetWindowPos(hwnd, 0, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER | SWP_FRAMECHANGED); + GetWindowRect(hwndStatus,&rect); + SetWindowPos(hwndStatus, 0, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER | SWP_FRAMECHANGED); + if (vid_resize) + { + CheckMenuItem(hmenu, IDM_VID_SCALE_1X + scale, MF_UNCHECKED); + CheckMenuItem(hmenu, IDM_VID_SCALE_2X, MF_CHECKED); + scale = 1; + } + EnableMenuItem(hmenu, IDM_VID_SCALE_1X, vid_resize ? MF_GRAYED : MF_ENABLED); + EnableMenuItem(hmenu, IDM_VID_SCALE_2X, vid_resize ? MF_GRAYED : MF_ENABLED); + EnableMenuItem(hmenu, IDM_VID_SCALE_3X, vid_resize ? MF_GRAYED : MF_ENABLED); + EnableMenuItem(hmenu, IDM_VID_SCALE_4X, vid_resize ? MF_GRAYED : MF_ENABLED); + win_doresize = 1; + saveconfig(); + break; + + case IDM_VID_REMEMBER: + window_remember = !window_remember; + CheckMenuItem(hmenu, IDM_VID_REMEMBER, window_remember ? MF_CHECKED : MF_UNCHECKED); + GetWindowRect(hwnd, &rect); + if (window_remember) + { + window_x = rect.left; + window_y = rect.top; + window_w = rect.right - rect.left; + window_h = rect.bottom - rect.top; + } + saveconfig(); + break; + + case IDM_VID_DDRAW: + case IDM_VID_D3D: + startblit(); + video_wait_for_blit(); + CheckMenuItem(hmenu, IDM_VID_DDRAW + vid_api, MF_UNCHECKED); + vid_apis[0][vid_api].close(); + vid_api = LOWORD(wParam) - IDM_VID_DDRAW; + CheckMenuItem(hmenu, IDM_VID_DDRAW + vid_api, MF_CHECKED); + vid_apis[0][vid_api].init(hwndRender); + endblit(); + saveconfig(); + device_force_redraw(); + break; + + case IDM_VID_FULLSCREEN: + if(video_fullscreen != 1) + { + if (video_fullscreen_first) + { + video_fullscreen_first = 0; + msgbox_info(ghwnd, IDS_2193); + } + + startblit(); + video_wait_for_blit(); + mouse_close(); + vid_apis[0][vid_api].close(); + video_fullscreen = 1; + vid_apis[1][vid_api].init(ghwnd); + mouse_init(); + leave_fullscreen_flag = 0; + endblit(); + saveconfig(); + device_force_redraw(); + } + break; + + case IDM_VID_FS_FULL: + case IDM_VID_FS_43: + case IDM_VID_FS_SQ: + case IDM_VID_FS_INT: + CheckMenuItem(hmenu, IDM_VID_FS_FULL + video_fullscreen_scale, MF_UNCHECKED); + video_fullscreen_scale = LOWORD(wParam) - IDM_VID_FS_FULL; + CheckMenuItem(hmenu, IDM_VID_FS_FULL + video_fullscreen_scale, MF_CHECKED); + saveconfig(); + device_force_redraw(); + break; + + case IDM_VID_SCALE_1X: + case IDM_VID_SCALE_2X: + case IDM_VID_SCALE_3X: + case IDM_VID_SCALE_4X: + CheckMenuItem(hmenu, IDM_VID_SCALE_1X + scale, MF_UNCHECKED); + scale = LOWORD(wParam) - IDM_VID_SCALE_1X; + CheckMenuItem(hmenu, IDM_VID_SCALE_1X + scale, MF_CHECKED); + saveconfig(); + device_force_redraw(); + break; + + case IDM_VID_FORCE43: + video_toggle_option(hmenu, &force_43, IDM_VID_FORCE43); + break; + + case IDM_VID_INVERT: + video_toggle_option(hmenu, &invert_display, IDM_VID_INVERT); + break; + + case IDM_VID_OVERSCAN: + update_overscan = 1; + video_toggle_option(hmenu, &enable_overscan, IDM_VID_OVERSCAN); + break; + + case IDM_VID_CGACON: + vid_cga_contrast = !vid_cga_contrast; + CheckMenuItem(menu, IDM_VID_CGACON, vid_cga_contrast ? MF_CHECKED : MF_UNCHECKED); + cgapal_rebuild(); + saveconfig(); + break; + +#ifdef ENABLE_LOG_TOGGLES +#ifdef ENABLE_BUSLOGIC_LOG + case IDM_LOG_BUSLOGIC: + buslogic_do_log ^= 1; + CheckMenuItem(hmenu, IDM_LOG_BUSLOGIC, buslogic_do_log ? MF_CHECKED : MF_UNCHECKED); + break; +#endif + +#ifdef ENABLE_CDROM_LOG + case IDM_LOG_CDROM: + cdrom_do_log ^= 1; + CheckMenuItem(hmenu, IDM_LOG_CDROM, cdrom_do_log ? MF_CHECKED : MF_UNCHECKED); + break; +#endif + +#ifdef ENABLE_D86F_LOG + case IDM_LOG_D86F: + d86f_do_log ^= 1; + CheckMenuItem(hmenu, IDM_LOG_D86F, d86f_do_log ? MF_CHECKED : MF_UNCHECKED); + break; +#endif + +#ifdef ENABLE_FDC_LOG + case IDM_LOG_FDC: + fdc_do_log ^= 1; + CheckMenuItem(hmenu, IDM_LOG_FDC, fdc_do_log ? MF_CHECKED : MF_UNCHECKED); + break; +#endif + +#ifdef ENABLE_IDE_LOG + case IDM_LOG_IDE: + ide_do_log ^= 1; + CheckMenuItem(hmenu, IDM_LOG_IDE, ide_do_log ? MF_CHECKED : MF_UNCHECKED); + break; +#endif + +#ifdef ENABLE_SERIAL_LOG + case IDM_LOG_SERIAL: + serial_do_log ^= 1; + CheckMenuItem(hmenu, IDM_LOG_SERIAL, serial_do_log ? MF_CHECKED : MF_UNCHECKED); + break; +#endif + +#ifdef ENABLE_NIC_LOG + case IDM_LOG_NIC: + /*FIXME: should be network_setlog() */ + nic_do_log ^= 1; + CheckMenuItem(hmenu, IDM_LOG_NIC, nic_do_log ? MF_CHECKED : MF_UNCHECKED); + break; +#endif +#endif + +#ifdef ENABLE_LOG_BREAKPOINT + case IDM_LOG_BREAKPOINT: + pclog("---- LOG BREAKPOINT ----\n"); + break; +#endif + +#ifdef ENABLE_VRAM_DUMP + case IDM_DUMP_VRAM: + svga_dump_vram(); + break; +#endif + + case IDM_CONFIG_LOAD: + pause = 1; + if (!file_dlg_st(hwnd, IDS_2174, "", 0)) + { + if (msgbox_reset_yn(ghwnd) == IDYES) + { + config_save(config_file_default); + for (i = 0; i < FDD_NUM; i++) + { + disc_close(i); + } + for (i = 0; i < CDROM_NUM; i++) + { + cdrom_drives[i].handler->exit(i); + if (cdrom_drives[i].host_drive == 200) + { + image_close(i); + } + else if ((cdrom_drives[i].host_drive >= 'A') && (cdrom_drives[i].host_drive <= 'Z')) + { + ioctl_close(i); + } + else + { + null_close(i); + } + } + resetpchard_close(); + loadconfig(wopenfilestring); + for (i = 0; i < CDROM_NUM; i++) + { + if (cdrom_drives[i].bus_type) + { + SCSIReset(cdrom_drives[i].scsi_device_id, cdrom_drives[i].scsi_device_lun); + } + + if (cdrom_drives[i].host_drive == 200) + { + image_open(i, cdrom_image[i].image_path); + } + else if ((cdrom_drives[i].host_drive >= 'A') && (cdrom_drives[i].host_drive <= 'Z')) + { + ioctl_open(i, cdrom_drives[i].host_drive); + } + else + { + cdrom_null_open(i, cdrom_drives[i].host_drive); + } + } + + disc_load(0, discfns[0]); + disc_load(1, discfns[1]); + disc_load(2, discfns[2]); + disc_load(3, discfns[3]); + + /* pclog_w(L"NVR path: %s\n", nvr_path); */ + mem_resize(); + loadbios(); + update_status_bar_panes(hwndStatus); + resetpchard_init(); + } + } + pause = 0; + break; + + case IDM_CONFIG_SAVE: + pause = 1; + if (!file_dlg_st(hwnd, IDS_2174, "", 1)) + { + config_save(wopenfilestring); + } + pause = 0; + break; + } + return 0; + + case WM_INPUT: + process_raw_input(lParam, infocus); + break; + + case WM_SETFOCUS: + infocus=1; + if (!hook_enabled) + { + hKeyboardHook = SetWindowsHookEx( WH_KEYBOARD_LL, LowLevelKeyboardProc, GetModuleHandle(NULL), 0 ); + hook_enabled = 1; + } + break; + + case WM_KILLFOCUS: + infocus=0; + if (mousecapture) + { + ClipCursor(&oldclip); + ShowCursor(TRUE); + mousecapture=0; + } + memset(recv_key, 0, sizeof(recv_key)); + if (video_fullscreen) + { + leave_fullscreen_flag = 1; + } + if (hook_enabled) + { + UnhookWindowsHookEx(hKeyboardHook); + hook_enabled = 0; + } + break; + + case WM_LBUTTONUP: + if (!mousecapture && !video_fullscreen) + { + GetClipCursor(&oldclip); + GetWindowRect(hwndRender, &rect); + + ClipCursor(&rect); + mousecapture = 1; + while (1) + { + if (ShowCursor(FALSE) < 0) + { + break; + } + } + } + break; + + case WM_MBUTTONUP: + if (!(mouse_get_type(mouse_type) & MOUSE_TYPE_3BUTTON)) + { + releasemouse(); + } + break; + + case WM_ENTERMENULOOP: + break; + + case WM_SIZE: + winsizex = (lParam & 0xFFFF); + winsizey = (lParam >> 16) - (17 + 6); + + if (winsizey < 0) + { + winsizey = 0; + } + + MoveWindow(hwndRender, 0, 0, winsizex, winsizey, TRUE); + + if (vid_apis[video_fullscreen][vid_api].resize) + { + startblit(); + video_wait_for_blit(); + vid_apis[video_fullscreen][vid_api].resize(winsizex, winsizey); + endblit(); + } + + MoveWindow(hwndStatus, 0, winsizey + 6, winsizex, 17, TRUE); + + if (mousecapture) + { + GetWindowRect(hwndRender, &rect); + + ClipCursor(&rect); + } + + if (window_remember) + { + GetWindowRect(hwnd, &rect); + window_x = rect.left; + window_y = rect.top; + window_w = rect.right - rect.left; + window_h = rect.bottom - rect.top; + save_window_pos = 1; + } + + saveconfig(); + break; + + case WM_MOVE: + if (window_remember) + { + GetWindowRect(hwnd, &rect); + window_x = rect.left; + window_y = rect.top; + window_w = rect.right - rect.left; + window_h = rect.bottom - rect.top; + save_window_pos = 1; + } + break; + + case WM_TIMER: + if (wParam == TIMER_1SEC) + { + onesec(); + } + break; + + case WM_RESETD3D: + startblit(); + if (video_fullscreen) + { + d3d_fs_reset(); + } + else + { + d3d_reset(); + } + endblit(); + break; + + case WM_LEAVEFULLSCREEN: + startblit(); + mouse_close(); + vid_apis[1][vid_api].close(); + video_fullscreen = 0; + saveconfig(); + vid_apis[0][vid_api].init(hwndRender); + mouse_init(); + endblit(); + device_force_redraw(); + break; + + case WM_KEYDOWN: + case WM_SYSKEYDOWN: + case WM_KEYUP: + case WM_SYSKEYUP: + return 0; + + case WM_DESTROY: + UnhookWindowsHookEx(hKeyboardHook); + KillTimer(hwnd, TIMER_1SEC); + PostQuitMessage (0); /* send a WM_QUIT to the message queue */ + break; + + case WM_SYSCOMMAND: + /* Disable ALT key *ALWAYS*, I don't think there's any use for reaching the menu that way. */ + if (wParam == SC_KEYMENU && HIWORD(lParam) <= 0) + { + return 0; /*disable ALT key for menu*/ + } + + default: + return DefWindowProc (hwnd, message, wParam, lParam); + } + return 0; +} + +LRESULT CALLBACK subWindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + switch (message) + { + default: + return DefWindowProc(hwnd, message, wParam, lParam); + } + return 0; +} + +VOID APIENTRY HandlePopupMenu(HWND hwnd, POINT pt, int id) +{ + if (id >= (sb_parts - 1)) + { + return; + } + pt.x = id * SB_ICON_WIDTH; /* Justify to the left. */ + pt.y = 0; /* Justify to the top. */ + ClientToScreen(hwnd, (LPPOINT) &pt); + TrackPopupMenu(sb_menu_handles[id], TPM_LEFTALIGN | TPM_BOTTOMALIGN | TPM_LEFTBUTTON, pt.x, pt.y, 0, hwndStatus, NULL); +} + +LRESULT CALLBACK StatusBarProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + RECT rc; + POINT pt; + + WCHAR temp_image_path[1024]; + int new_cdrom_drive; + int ret = 0; + int item_id = 0; + int item_params = 0; + int id = 0; + int part = 0; + int letter = 0; + + HMENU hmenu; + + switch (message) + { + case WM_COMMAND: + item_id = LOWORD(wParam) & 0xff00; /* Mask out the low 8 bits for item ID. */ + item_params = LOWORD(wParam) & 0x00ff; /* Mask out the high 8 bits for item parameter. */ + + switch (item_id) + { + case IDM_FLOPPY_IMAGE_EXISTING: + case IDM_FLOPPY_IMAGE_EXISTING_WP: + id = item_params & 0x0003; + part = find_status_bar_part(SB_FLOPPY | id); + if ((part == -1) || (sb_menu_handles == NULL)) + { + break; + } + + ret = file_dlg_w_st(hwnd, IDS_2173, discfns[id], 0); + if (!ret) + { + disc_close(id); + ui_writeprot[id] = (item_id == IDM_FLOPPY_IMAGE_EXISTING_WP) ? 1 : 0; + disc_load(id, wopenfilestring); + update_status_bar_icon_state(SB_FLOPPY | id, wcslen(discfns[id]) ? 0 : 1); + EnableMenuItem(sb_menu_handles[part], IDM_FLOPPY_EJECT | id, MF_BYCOMMAND | (wcslen(discfns[id]) ? MF_ENABLED : MF_GRAYED)); + update_tip(SB_FLOPPY | id); + saveconfig(); + } + break; + + case IDM_FLOPPY_EJECT: + id = item_params & 0x0003; + part = find_status_bar_part(SB_FLOPPY | id); + if ((part == -1) || (sb_menu_handles == NULL)) + { + break; + } + + disc_close(id); + update_status_bar_icon_state(SB_FLOPPY | id, 1); + EnableMenuItem(sb_menu_handles[part], IDM_FLOPPY_EJECT | id, MF_BYCOMMAND | MF_GRAYED); + update_tip(SB_FLOPPY | id); + saveconfig(); + break; + + case IDM_CDROM_MUTE: + id = item_params & 0x0007; + hmenu = GetSubMenu(smenu, id + 4); + Sleep(100); + cdrom_drives[id].sound_on ^= 1; + CheckMenuItem(hmenu, IDM_CDROM_MUTE | id, cdrom_drives[id].sound_on ? MF_UNCHECKED : MF_CHECKED); + saveconfig(); + sound_cd_thread_reset(); + break; + + case IDM_CDROM_EMPTY: + id = item_params & 0x0007; + cdrom_eject(id); + break; + + case IDM_CDROM_RELOAD: + id = item_params & 0x0007; + cdrom_reload(id); + break; + + case IDM_CDROM_IMAGE: + id = item_params & 0x0007; + part = find_status_bar_part(SB_CDROM | id); + if ((part == -1) || (sb_menu_handles == NULL)) + { + break; + } + + if (!file_dlg_w_st(hwnd, IDS_2175, cdrom_image[id].image_path, 0)) + { + cdrom_drives[id].prev_host_drive = cdrom_drives[id].host_drive; + wcscpy(temp_image_path, wopenfilestring); + if ((wcscmp(cdrom_image[id].image_path, temp_image_path) == 0) && (cdrom_drives[id].host_drive == 200)) + { + /* Switching from image to the same image. Do nothing. */ + break; + } + cdrom_drives[id].handler->exit(id); + cdrom_close(id); + image_open(id, temp_image_path); + /* Signal disc change to the emulated machine. */ + cdrom_insert(id); + CheckMenuItem(sb_menu_handles[part], IDM_CDROM_EMPTY | id, MF_UNCHECKED); + if ((cdrom_drives[id].host_drive >= 'A') && (cdrom_drives[id].host_drive <= 'Z')) + { + CheckMenuItem(sb_menu_handles[part], IDM_CDROM_HOST_DRIVE | id | ((cdrom_drives[id].host_drive - 'A') << 3), MF_UNCHECKED); + } + cdrom_drives[id].host_drive = (wcslen(cdrom_image[id].image_path) == 0) ? 0 : 200; + if (cdrom_drives[id].host_drive == 200) + { + CheckMenuItem(sb_menu_handles[part], IDM_CDROM_IMAGE | id, MF_CHECKED); + update_status_bar_icon_state(SB_CDROM | id, 0); + } + else + { + CheckMenuItem(sb_menu_handles[part], IDM_CDROM_IMAGE | id, MF_UNCHECKED); + CheckMenuItem(sb_menu_handles[part], IDM_CDROM_EMPTY | id, MF_UNCHECKED); + update_status_bar_icon_state(SB_CDROM | id, 1); + } + update_tip(SB_CDROM | id); + saveconfig(); + } + break; + + case IDM_CDROM_HOST_DRIVE: + id = item_params & 0x0007; + letter = ((item_params >> 3) & 0x001f) + 'A'; + part = find_status_bar_part(SB_CDROM | id); + if ((part == -1) || (sb_menu_handles == NULL)) + { + break; + } + + new_cdrom_drive = letter; + if (cdrom_drives[id].host_drive == new_cdrom_drive) + { + /* Switching to the same drive. Do nothing. */ + break; + } + cdrom_drives[id].prev_host_drive = cdrom_drives[id].host_drive; + cdrom_drives[id].handler->exit(id); + cdrom_close(id); + ioctl_open(id, new_cdrom_drive); + /* Signal disc change to the emulated machine. */ + cdrom_insert(id); + CheckMenuItem(sb_menu_handles[part], IDM_CDROM_EMPTY | id, MF_UNCHECKED); + if ((cdrom_drives[id].host_drive >= 'A') && (cdrom_drives[id].host_drive <= 'Z')) + { + CheckMenuItem(sb_menu_handles[part], IDM_CDROM_HOST_DRIVE | id | ((cdrom_drives[id].host_drive - 'A') << 3), MF_UNCHECKED); + } + CheckMenuItem(sb_menu_handles[part], IDM_CDROM_IMAGE | id, MF_UNCHECKED); + cdrom_drives[id].host_drive = new_cdrom_drive; + CheckMenuItem(sb_menu_handles[part], IDM_CDROM_HOST_DRIVE | id | ((cdrom_drives[id].host_drive - 'A') << 3), MF_CHECKED); + EnableMenuItem(sb_menu_handles[part], IDM_CDROM_RELOAD | id, MF_BYCOMMAND | MF_GRAYED); + update_status_bar_icon_state(SB_CDROM | id, 0); + update_tip(SB_CDROM | id); + saveconfig(); + break; + + case IDM_RDISK_EJECT: + id = item_params & 0x001f; + removable_disk_eject(id); + break; + + case IDM_RDISK_RELOAD: + id = item_params & 0x001f; + removable_disk_reload(id); + break; + + case IDM_RDISK_SEND_CHANGE: + id = item_params & 0x001f; + scsi_disk_insert(id); + break; + + case IDM_RDISK_IMAGE: + case IDM_RDISK_IMAGE_WP: + id = item_params & 0x001f; + ret = file_dlg_w_st(hwnd, IDS_2172, hdc[id].fn, id); + if (!ret) + { + removable_disk_unload(id); + memset(hdc[id].fn, 0, sizeof(hdc[id].fn)); + wcscpy(hdc[id].fn, wopenfilestring); + hdc[id].wp = (item_id == IDM_RDISK_IMAGE_WP) ? 1 : 0; + scsi_loadhd(hdc[id].scsi_id, hdc[id].scsi_lun, id); + scsi_disk_insert(id); + if (wcslen(hdc[id].fn) > 0) + { + update_status_bar_icon_state(SB_RDISK | id, 0); + EnableMenuItem(sb_menu_handles[part], IDM_RDISK_EJECT | id, MF_BYCOMMAND | MF_ENABLED); + EnableMenuItem(sb_menu_handles[part], IDM_RDISK_RELOAD | id, MF_BYCOMMAND | MF_GRAYED); + EnableMenuItem(sb_menu_handles[part], IDM_RDISK_SEND_CHANGE | id, MF_BYCOMMAND | MF_ENABLED); + } + else + { + update_status_bar_icon_state(SB_RDISK | id, 1); + EnableMenuItem(sb_menu_handles[part], IDM_RDISK_EJECT | id, MF_BYCOMMAND | MF_GRAYED); + EnableMenuItem(sb_menu_handles[part], IDM_RDISK_RELOAD | id, MF_BYCOMMAND | MF_GRAYED); + EnableMenuItem(sb_menu_handles[part], IDM_RDISK_SEND_CHANGE | id, MF_BYCOMMAND | MF_GRAYED); + } + update_tip(SB_RDISK | id); + saveconfig(); + } + break; + + default: + break; + } + return 0; + + case WM_LBUTTONDOWN: + case WM_RBUTTONDOWN: + GetClientRect(hwnd, (LPRECT)& rc); + pt.x = GET_X_LPARAM(lParam); + pt.y = GET_Y_LPARAM(lParam); + if (PtInRect((LPRECT) &rc, pt)) + { + HandlePopupMenu(hwnd, pt, (pt.x / SB_ICON_WIDTH)); + } + break; + + default: + return CallWindowProc((WNDPROC) OriginalStatusBarProcedure, hwnd, message, wParam, lParam); + } + return 0; +} diff --git a/src/WIN/win.h b/src/WIN/win.h new file mode 100644 index 000000000..d2006df00 --- /dev/null +++ b/src/WIN/win.h @@ -0,0 +1,115 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * The Emulator's Windows core. + * + * Version: @(#)win.h 1.0.0 2017/05/30 + * + * Author: Sarah Walker, + * Miran Grca, + * Copyright 2008-2017 Sarah Walker. + * Copyright 2016-2017 Miran Grca. + */ + +/* + * This should be named 'plat.h' and then include any + * Windows-specific header files needed, to keep them + * out of the main code. + */ +/* Copyright holders: Sarah Walker + see COPYING for more details +*/ +#ifndef BOX_WIN_H +# define BOX_WIN_H + +# ifndef NO_UNICODE +# define UNICODE +# endif +# define BITMAP WINDOWS_BITMAP +/* # ifdef _WIN32_WINNT + # undef _WIN32_WINNT + # define _WIN32_WINNT 0x0501 + # endif */ +# include +# include "resource.h" +# undef BITMAP + + +#define szClassName L"86BoxMainWnd" +#define szSubClassName L"86BoxSubWnd" +#define szStatusBarClassName L"86BoxStatusBar" + + +#define WM_RESETD3D WM_USER +#define WM_LEAVEFULLSCREEN WM_USER + 1 + +#define WM_SAVESETTINGS 0x8888 /* 86Box-specific message, used to tell the child dialog to save the currently specified settings. */ + +#define SB_ICON_WIDTH 24 + + +extern HINSTANCE hinstance; +extern HWND ghwnd; +extern HWND status_hwnd; +extern HWND hwndStatus; +extern int status_is_open; +extern int mousecapture; + +extern char openfilestring[260]; +extern WCHAR wopenfilestring[260]; + +extern int pause; + +extern HMENU smenu; +extern HMENU *sb_menu_handles; + + +#ifdef __cplusplus +extern "C" { +#endif + +extern void leave_fullscreen(void); + +extern void status_open(HWND hwnd); + +extern void deviceconfig_open(HWND hwnd, struct device_t *device); +extern void joystickconfig_open(HWND hwnd, int joy_nr, int type); + +extern int getfile(HWND hwnd, char *f, char *fn); +extern int getsfile(HWND hwnd, char *f, char *fn); + +extern void get_executable_name(wchar_t *s, int size); +extern void set_window_title(wchar_t *s); + +extern void startblit(void); +extern void endblit(void); + +extern void win_settings_open(HWND hwnd); +extern void win_menu_update(); + +extern void update_status_bar_panes(HWND hwnds); + +extern int fdd_type_to_icon(int type); + +extern void hard_disk_add_open(HWND hwnd, int is_existing); +extern int hard_disk_was_added(void); + +extern void get_registry_key_map(void); +extern void process_raw_input(LPARAM lParam, int infocus); + +extern int find_status_bar_part(int tag); + +extern void cdrom_close(uint8_t id); +extern void update_tip(int meaning); + +#ifdef __cplusplus +} +#endif + + +#endif /*BOX_WIN_H*/ diff --git a/src/WIN/win_cgapal.h b/src/WIN/win_cgapal.h new file mode 100644 index 000000000..0388cde27 --- /dev/null +++ b/src/WIN/win_cgapal.h @@ -0,0 +1,29 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * The Windows CGA palette handler header. + * + * Version: @(#)win_cgapal.h 1.0.0 2017/05/30 + * + * Author: Miran Grca, + * Copyright 2016-2017 Miran Grca. + */ + +extern PALETTE cgapal; +extern PALETTE cgapal_mono[6]; + +extern uint32_t pal_lookup[256]; + +#ifdef __cplusplus +extern "C" { +#endif +void cgapal_rebuild(); +void destroy_bitmap(BITMAP *b); +#ifdef __cplusplus +} +#endif diff --git a/src/WIN/win_crashdump.c b/src/WIN/win_crashdump.c new file mode 100644 index 000000000..957ce296e --- /dev/null +++ b/src/WIN/win_crashdump.c @@ -0,0 +1,225 @@ +/* Copyright holders: Riley + see COPYING for more details + + win_crashdump.c : Windows exception handler to make a crash dump just before a crash happens. +*/ +#define _WIN32_WINNT 0x0501 +#include +#include +#include +#include +#include +#include "../86box.h" +#include "win_crashdump.h" + + +#define ExceptionHandlerBufferSize (10240) + + +static PVOID hExceptionHandler; +static char *ExceptionHandlerBuffer; + + +LONG CALLBACK MakeCrashDump(PEXCEPTION_POINTERS ExceptionInfo) +{ + SYSTEMTIME SystemTime; + HANDLE hDumpFile; + DWORD Error; + char *BufPtr; + + /* + * Win32-specific functions will be used wherever possible, + * just in case the C stdlib-equivalents try to allocate + * memory. + * (The Win32-specific functions are generally just wrappers + * over NT system calls anyway.) + */ + if ((ExceptionInfo->ExceptionRecord->ExceptionCode >> 28) != 0xC) { + /* + * ExceptionCode is not a fatal exception (high 4b of + * ntstatus = 0xC) Not going to crash, let's not make + * a crash dump. + */ + return(EXCEPTION_CONTINUE_SEARCH); + } + + /* + * So, the program is about to crash. Oh no what do? + * Let's create a crash dump file as a debugging-aid. + * + * First, get the path to the executable. + */ + GetModuleFileName(NULL,ExceptionHandlerBuffer,ExceptionHandlerBufferSize); + if (GetLastError() != ERROR_SUCCESS) { + /* Could not get full path, create in current directory. */ + BufPtr = ExceptionHandlerBuffer; + } else { + /* + * Walk through the string backwards looking for the + * last backslash, so as to remove the "86Box.exe" + * filename from the string. + */ + BufPtr = &ExceptionHandlerBuffer[strlen(ExceptionHandlerBuffer)]; + for (; BufPtr > ExceptionHandlerBuffer; BufPtr--) { + if (BufPtr[0] == '\\') { + /* Found backslash, terminate the string after it. */ + BufPtr[1] = 0; + break; + } + } + + BufPtr = &ExceptionHandlerBuffer[strlen(ExceptionHandlerBuffer)]; + } + + /* + * What would a good filename be? + * + * It should contain the current date and time so as + * to be (hopefully!) unique. + */ + GetSystemTime(&SystemTime); + sprintf(CurrentBufferPointer, + "86box-%d%02d%02d-%02d-%02d-%02d-%03d.dmp", + SystemTime.wYear, + SystemTime.wMonth, + SystemTime.wDay, + SystemTime.wHour, + SystemTime.wMinute, + SystemTime.wSecond, + SystemTime.wMilliseconds); + + /* Now the filename is in the buffer, the file can be created. */ + hDumpFile = CreateFile( + ExceptionHandlerBuffer, // The filename of the file to open. + GENERIC_WRITE, // The permissions to request. + 0, // Make sure other processes can't + // touch the crash dump at all + // while it's open. + NULL, // Leave the security descriptor + // undefined, it doesn't matter. + OPEN_ALWAYS, // Opens the file if it exists, + // creates a new file if it doesn't. + FILE_ATTRIBUTE_NORMAL, // File attributes / etc don't matter. + NULL); // A template file is not being used. + + /* Check to make sure the file was actually created. */ + if (hDumpFile == INVALID_HANDLE_VALUE) { + /* CreateFile() failed, so just do nothing more. */ + return(EXCEPTION_CONTINUE_SEARCH); + } + + // Now the file is open, let's write the data we were passed out in a human-readable format. + + // Let's get the name of the module where the exception occured. + HMODULE hMods[1024]; + MODULEINFO modInfo; + HMODULE ipModule = 0; + DWORD cbNeeded; + + // Try to get a list of all loaded modules. + if (EnumProcessModules(GetCurrentProcess(), + hMods, sizeof(hMods), &cbNeeded)) { + // The list was obtained, walk through each of the modules. + for (DWORD i = 0; i < (cbNeeded / sizeof(HMODULE)); i++) { + // For each module, get the module information + // (base address, size, entry point) + GetModuleInformation(GetCurrentProcess(), + hMods[i], &modInfo, sizeof(MODULEINFO)); + // If the exception address is located in the range of + // where this module is loaded... + if ( (ExceptionInfo->ExceptionRecord->ExceptionAddress >= modInfo.lpBaseOfDll) && + (ExceptionInfo->ExceptionRecord->ExceptionAddress < (modInfo.lpBaseOfDll + modInfo.SizeOfImage))) { + // ...this is the module we're looking for! + ipModule = hMods[i]; + break; + } + } + } + + // Start to put the crash-dump string into the buffer. + sprintf(ExceptionHandlerBuffer, + "86Box version %s crashed on %d-%02d-%02d %02d:%02d:%02d.%03d\r\n\r\n" + "" + "Exception details:\r\n" + "Exception NTSTATUS code: 0x%08x\r\n" + "Occured at address: 0x%p", + emulator_version, + SystemTime.wYear, SystemTime.wMonth, SystemTime.wDay, + SystemTime.wHour, SystemTime.wMinute, SystemTime.wSecond, + SystemTime.wMilliseconds, + ExceptionInfo->ExceptionRecord->ExceptionCode, + ExceptionInfo->ExceptionRecord->ExceptionAddress); + + // If we found the module that the exception occured in, get the full path to the module the exception occured at and include it. + BufPtr = &ExceptionHandlerBuffer[strlen(ExceptionHandlerBuffer)]; + if (ipModule != 0) { + sprintf(BufPtr," ["); + GetModuleFileName(ipModule, &BufPtr[2], + ExceptionHandlerBufferSize - strlen(ExceptionHandlerBuffer)); + if (GetLastError() == ERROR_SUCCESS) { + BufPtr = &ExceptionHandlerBuffer[strlen(ExceptionHandlerBuffer)]; + sprintf(BufPtr,"]"); + BufPtr += 1; + } + } + + // Continue to create the crash-dump string. + sprintf(BufPtr, + "\r\n" + "Number of parameters: %d\r\n" + "Exception parameters: ", + ExceptionInfo->ExceptionRecord->NumberParameters); + + // Add the exception parameters to the crash-dump string. + for (int i = 0; i < ExceptionInfo->ExceptionRecord->NumberParameters; i++) { + BufPtr = &ExceptionHandlerBuffer[strlen(ExceptionHandlerBuffer)]; + sprintf(BufPtr,"0x%p ", + ExceptionInfo->ExceptionRecord->ExceptionInformation[i]); + } + BufPtr = &ExceptionHandlerBuffer[strlen(ExceptionHandlerBuffer) - 1]; + + PCONTEXT Registers = ExceptionInfo->ContextRecord; + +#if defined(__i386__) && !defined(__x86_64) + // This binary is being compiled for x86, include a register dump. + sprintf(BufPtr, + "\r\n" + "Register dump:\r\n" + "eax=0x%08x ebx=0x%08x ecx=0x%08x edx=0x%08x ebp=0x%08x esp=0x%08x esi=0x%08x edi=0x%08x eip=0x%08x\r\n" + "\r\n", + Registers->Eax, Registers->Ebx, Registers->Ecx, Registers->Edx, Registers->Ebp, Registers->Esp, Registers->Esi, Registers->Edi, Registers->Eip); +#else + // Register dump is supported by no other architectures right now. MinGW headers seem to lack the x64 CONTEXT structure definition. + sprintf(BufPtr,"\r\n"); +#endif + + // The crash-dump string has been created, write it to disk. + WriteFile(hDumpFile, ExceptionHandlerBuffer, + strlen(ExceptionHandlerBuffer), NULL, NULL); + + // Finally, close the file. + CloseHandle(hDumpFile); + + // And return, therefore causing the crash, + // but only after the crash dump has been created. + return(EXCEPTION_CONTINUE_SEARCH); +} + + +void InitCrashDump(void) +{ + /* + * An exception handler should not allocate memory, + * so allocate 10kb for it to use if it gets called, + * an amount which should be more than enough. + */ + ExceptionHandlerBuffer = malloc(ExceptionHandlerBufferSize); + + /* + * Register the exception handler. + * Zero first argument means this exception handler gets + * called last, therefore, crash dump is only made, when + * a crash is going to happen. + */ + hExceptionHandler = AddVectoredExceptionHandler(0, MakeCrashDump); +} diff --git a/src/WIN/win_crashdump.h b/src/WIN/win_crashdump.h new file mode 100644 index 000000000..8048cd7af --- /dev/null +++ b/src/WIN/win_crashdump.h @@ -0,0 +1,7 @@ +/* Copyright holders: Riley + see COPYING for more details + + win-crashdump.c : Windows crash dump exception handler header file. +*/ + +void InitCrashDump(); \ No newline at end of file diff --git a/src/win-d3d.cc b/src/WIN/win_d3d.cc similarity index 72% rename from src/win-d3d.cc rename to src/WIN/win_d3d.cc index d73deb98e..456b67254 100644 --- a/src/win-d3d.cc +++ b/src/WIN/win_d3d.cc @@ -1,23 +1,36 @@ -/* Copyright holders: Sarah Walker, Tenshi - see COPYING for more details -*/ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Direct3D 9 rendererer and screenshots taking. + * + * Version: @(#)win_d3d.cc 1.0.0 2017/05/30 + * + * Authors: Sarah Walker, + * Miran Grca, + * Copyright 2008-2017 Sarah Walker. + * Copyright 2016-2017 Miran Grca. + */ #include -#define BITMAP WINDOWS_BITMAP -#include -#undef BITMAP -#include -#include "resources.h" -#include "win-d3d.h" -#include "video.h" +#include "../video/video.h" +#include "win.h" +#include "win_d3d.h" +#include "win_cgapal.h" + extern "C" void fatal(const char *format, ...); extern "C" void pclog(const char *format, ...); -extern "C" void device_force_redraw(); -extern "C" void video_blit_complete(); +extern "C" void device_force_redraw(void); +extern "C" void video_blit_complete(void); -void d3d_init_objects(); -void d3d_close_objects(); + +void d3d_init_objects(void); +void d3d_close_objects(void); void d3d_blit_memtoscreen(int x, int y, int y1, int y2, int w, int h); void d3d_blit_memtoscreen_8(int x, int y, int w, int h); @@ -32,49 +45,32 @@ static HWND d3d_hwnd; struct CUSTOMVERTEX { FLOAT x, y, z, rhw; // from the D3DFVF_XYZRHW flag + DWORD color; FLOAT tu, tv; }; -static PALETTE cgapal= -{ - {0,0,0},{0,42,0},{42,0,0},{42,21,0}, - {0,0,0},{0,42,42},{42,0,42},{42,42,42}, - {0,0,0},{21,63,21},{63,21,21},{63,63,21}, - {0,0,0},{21,63,63},{63,21,63},{63,63,63}, - - {0,0,0},{0,0,42},{0,42,0},{0,42,42}, - {42,0,0},{42,0,42},{42,21,00},{42,42,42}, - {21,21,21},{21,21,63},{21,63,21},{21,63,63}, - {63,21,21},{63,21,63},{63,63,21},{63,63,63}, - - {0,0,0},{0,21,0},{0,0,42},{0,42,42}, - {42,0,21},{21,10,21},{42,0,42},{42,0,63}, - {21,21,21},{21,63,21},{42,21,42},{21,63,63}, - {63,0,0},{42,42,0},{63,21,42},{41,41,41}, - - {0,0,0},{0,42,42},{42,0,0},{42,42,42}, - {0,0,0},{0,42,42},{42,0,0},{42,42,42}, - {0,0,0},{0,63,63},{63,0,0},{63,63,63}, - {0,0,0},{0,63,63},{63,0,0},{63,63,63}, -}; - -static uint32_t pal_lookup[256]; - static CUSTOMVERTEX d3d_verts[] = { - { 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f}, - {2080.0f, 2080.0f, 1.0f, 1.0f, 1.0f, 1.0f}, - { 0.0f, 2080.0f, 1.0f, 1.0f, 0.0f, 1.0f}, + { 0.0f, 0.0f, 1.0f, 1.0f, 0xffffff, 0.0f, 0.0f}, + {2048.0f, 2048.0f, 1.0f, 1.0f, 0xffffff, 1.0f, 1.0f}, + { 0.0f, 2048.0f, 1.0f, 1.0f, 0xffffff, 0.0f, 1.0f}, - { 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f}, - {2080.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f}, - {2080.0f, 2080.0f, 1.0f, 1.0f, 1.0f, 1.0f}, + { 0.0f, 0.0f, 1.0f, 1.0f, 0xffffff, 0.0f, 0.0f}, + {2048.0f, 0.0f, 1.0f, 1.0f, 0xffffff, 1.0f, 0.0f}, + {2048.0f, 2048.0f, 1.0f, 1.0f, 0xffffff, 1.0f, 1.0f}, + + { 0.0f, 0.0f, 1.0f, 1.0f, 0xffffff, 0.0f, 0.0f}, + {2048.0f, 2048.0f, 1.0f, 1.0f, 0xffffff, 1.0f, 1.0f}, + { 0.0f, 2048.0f, 1.0f, 1.0f, 0xffffff, 0.0f, 1.0f}, + + { 0.0f, 0.0f, 1.0f, 1.0f, 0xffffff, 0.0f, 0.0f}, + {2048.0f, 0.0f, 1.0f, 1.0f, 0xffffff, 1.0f, 0.0f}, + {2048.0f, 2048.0f, 1.0f, 1.0f, 0xffffff, 1.0f, 1.0f} }; -void d3d_init(HWND h) +int d3d_init(HWND h) { int c; - HRESULT hr; for (c = 0; c < 256; c++) pal_lookup[c] = makecol(cgapal[c].r << 2, cgapal[c].g << 2, cgapal[c].b << 2); @@ -99,12 +95,14 @@ void d3d_init(HWND h) d3dpp.BackBufferWidth = 0; d3dpp.BackBufferHeight = 0; - hr = d3d->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, h, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &d3ddev); + d3d->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, h, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &d3ddev); d3d_init_objects(); video_blit_memtoscreen_func = d3d_blit_memtoscreen; video_blit_memtoscreen_8_func = d3d_blit_memtoscreen_8; + + return 1; } void d3d_close_objects() @@ -123,31 +121,29 @@ void d3d_close_objects() void d3d_init_objects() { - HRESULT hr; D3DLOCKED_RECT dr; int y; RECT r; - hr = d3ddev->CreateVertexBuffer(6*sizeof(CUSTOMVERTEX), + d3ddev->CreateVertexBuffer(12*sizeof(CUSTOMVERTEX), 0, - D3DFVF_XYZRHW | D3DFVF_TEX1, + D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX1, D3DPOOL_MANAGED, &v_buffer, NULL); - d3ddev->CreateTexture(2080, 2080, 1, 0, D3DFMT_X8R8G8B8, D3DPOOL_MANAGED, &d3dTexture, NULL); + d3ddev->CreateTexture(2048, 2048, 1, 0, D3DFMT_X8R8G8B8, D3DPOOL_MANAGED, &d3dTexture, NULL); r.top = r.left = 0; - r.bottom = 2079; - r.right = 2079; + r.bottom = r.right = 2047; if (FAILED(d3dTexture->LockRect(0, &dr, &r, 0))) fatal("LockRect failed\n"); - for (y = 0; y < 2056; y++) + for (y = 0; y < 2048; y++) { - uint32_t *p = (uint32_t *)(dr.pBits + (y * dr.Pitch)); - memset(p, 0, 2064 * 4); + uint32_t *p = (uint32_t *)((uintptr_t)dr.pBits + (y * dr.Pitch)); + memset(p, 0, 2048 * 4); } d3dTexture->UnlockRect(0); @@ -162,8 +158,6 @@ void d3d_init_objects() void d3d_resize(int x, int y) { - HRESULT hr; - d3dpp.BackBufferWidth = x; d3dpp.BackBufferHeight = y; @@ -173,7 +167,9 @@ void d3d_resize(int x, int y) void d3d_reset() { HRESULT hr; - + + if (!d3ddev) + return; memset(&d3dpp, 0, sizeof(d3dpp)); d3dpp.Flags = 0; @@ -235,14 +231,13 @@ void d3d_blit_memtoscreen(int x, int y, int y1, int y2, int w, int h) VOID* pVoid; D3DLOCKED_RECT dr; RECT r; - uint32_t *p, *src; int yy; if (y1 == y2) { video_blit_complete(); return; /*Nothing to do*/ - } + } r.top = y1; r.left = 0; @@ -255,7 +250,7 @@ void d3d_blit_memtoscreen(int x, int y, int y1, int y2, int w, int h) fatal("LockRect failed\n"); for (yy = y1; yy < y2; yy++) - memcpy(dr.pBits + ((yy - y1) * dr.Pitch), &(((uint32_t *)buffer32->line[yy + y])[x]), w * 4); + memcpy((void *)((uintptr_t)dr.pBits + ((yy - y1) * dr.Pitch)), &(((uint32_t *)buffer32->line[yy + y])[x]), w * 4); video_blit_complete(); d3dTexture->UnlockRect(0); @@ -263,16 +258,24 @@ void d3d_blit_memtoscreen(int x, int y, int y1, int y2, int w, int h) else video_blit_complete(); - d3d_verts[0].tu = d3d_verts[2].tu = d3d_verts[3].tu = 0;//0.5 / 2048.0; + d3d_verts[0].tu = d3d_verts[2].tu = d3d_verts[3].tu = 0;//0.5 / 2048.0; d3d_verts[0].tv = d3d_verts[3].tv = d3d_verts[4].tv = 0;//0.5 / 2048.0; - d3d_verts[1].tu = d3d_verts[4].tu = d3d_verts[5].tu = (float)w / 2080.0; - d3d_verts[1].tv = d3d_verts[2].tv = d3d_verts[5].tv = (float)h / 2080.0; + d3d_verts[1].tu = d3d_verts[4].tu = d3d_verts[5].tu = (float)w / 2048.0; + d3d_verts[1].tv = d3d_verts[2].tv = d3d_verts[5].tv = (float)h / 2048.0; + d3d_verts[0].color = d3d_verts[1].color = d3d_verts[2].color = + d3d_verts[3].color = d3d_verts[4].color = d3d_verts[5].color = + d3d_verts[6].color = d3d_verts[7].color = d3d_verts[8].color = + d3d_verts[9].color = d3d_verts[10].color = d3d_verts[11].color = 0xffffff; GetClientRect(d3d_hwnd, &r); d3d_verts[0].x = d3d_verts[2].x = d3d_verts[3].x = -0.5; d3d_verts[0].y = d3d_verts[3].y = d3d_verts[4].y = -0.5; d3d_verts[1].x = d3d_verts[4].x = d3d_verts[5].x = (r.right - r.left) - 0.5; d3d_verts[1].y = d3d_verts[2].y = d3d_verts[5].y = (r.bottom - r.top) - 0.5; + d3d_verts[6].x = d3d_verts[8].x = d3d_verts[9].x = (r.right - r.left) - 40.5; + d3d_verts[6].y = d3d_verts[9].y = d3d_verts[10].y = 8.5; + d3d_verts[7].x = d3d_verts[10].x = d3d_verts[11].x = (r.right - r.left) - 8.5; + d3d_verts[7].y = d3d_verts[8].y = d3d_verts[11].y = 14.5; if (hr == D3D_OK) hr = v_buffer->Lock(0, 0, (void**)&pVoid, 0); // lock the vertex buffer @@ -290,7 +293,7 @@ void d3d_blit_memtoscreen(int x, int y, int y1, int y2, int w, int h) hr = d3ddev->SetTexture(0, d3dTexture); if (hr == D3D_OK) - hr = d3ddev->SetFVF(D3DFVF_XYZRHW | D3DFVF_TEX1); + hr = d3ddev->SetFVF(D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX1); if (hr == D3D_OK) hr = d3ddev->SetStreamSource(0, v_buffer, 0, sizeof(CUSTOMVERTEX)); @@ -317,11 +320,10 @@ void d3d_blit_memtoscreen_8(int x, int y, int w, int h) VOID* pVoid; D3DLOCKED_RECT dr; RECT r; - uint32_t *p, *src; int yy, xx; HRESULT hr = D3D_OK; - if (h == 0) + if (h == 0) { video_blit_complete(); return; /*Nothing to do*/ @@ -330,7 +332,7 @@ void d3d_blit_memtoscreen_8(int x, int y, int w, int h) r.top = 0; r.left = 0; r.bottom = h; - r.right = 2079; + r.right = 2047; if (hr == D3D_OK) { @@ -339,7 +341,7 @@ void d3d_blit_memtoscreen_8(int x, int y, int w, int h) for (yy = 0; yy < h; yy++) { - uint32_t *p = (uint32_t *)(dr.pBits + (yy * dr.Pitch)); + uint32_t *p = (uint32_t *)((uintptr_t)dr.pBits + (yy * dr.Pitch)); if ((y + yy) >= 0 && (y + yy) < buffer->h) { for (xx = 0; xx < w; xx++) @@ -353,6 +355,32 @@ void d3d_blit_memtoscreen_8(int x, int y, int w, int h) else video_blit_complete(); + d3d_verts[0].tu = d3d_verts[2].tu = d3d_verts[3].tu = 0;//0.5 / 2048.0; + d3d_verts[0].tv = d3d_verts[3].tv = d3d_verts[4].tv = 0;//0.5 / 2048.0; + d3d_verts[1].tu = d3d_verts[4].tu = d3d_verts[5].tu = (float)w / 2048.0; + d3d_verts[1].tv = d3d_verts[2].tv = d3d_verts[5].tv = (float)h / 2048.0; + d3d_verts[0].color = d3d_verts[1].color = d3d_verts[2].color = + d3d_verts[3].color = d3d_verts[4].color = d3d_verts[5].color = + d3d_verts[6].color = d3d_verts[7].color = d3d_verts[8].color = + d3d_verts[9].color = d3d_verts[10].color = d3d_verts[11].color = 0xffffff; + + GetClientRect(d3d_hwnd, &r); + d3d_verts[0].x = d3d_verts[2].x = d3d_verts[3].x = -0.5; + d3d_verts[0].y = d3d_verts[3].y = d3d_verts[4].y = -0.5; + d3d_verts[1].x = d3d_verts[4].x = d3d_verts[5].x = (r.right - r.left) - 0.5; + d3d_verts[1].y = d3d_verts[2].y = d3d_verts[5].y = (r.bottom - r.top) - 0.5; + d3d_verts[6].x = d3d_verts[8].x = d3d_verts[9].x = (r.right - r.left) - 40.5; + d3d_verts[6].y = d3d_verts[9].y = d3d_verts[10].y = 8.5; + d3d_verts[7].x = d3d_verts[10].x = d3d_verts[11].x = (r.right - r.left) - 8.5; + d3d_verts[7].y = d3d_verts[8].y = d3d_verts[11].y = 14.5; + + if (hr == D3D_OK) + hr = v_buffer->Lock(0, 0, (void**)&pVoid, 0); // lock the vertex buffer + if (hr == D3D_OK) + memcpy(pVoid, d3d_verts, sizeof(d3d_verts)); // copy the vertices to the locked buffer + if (hr == D3D_OK) + hr = v_buffer->Unlock(); // unlock the vertex buffer + if (hr == D3D_OK) hr = d3ddev->BeginScene(); @@ -362,7 +390,7 @@ void d3d_blit_memtoscreen_8(int x, int y, int w, int h) hr = d3ddev->SetTexture(0, d3dTexture); if (hr == D3D_OK) - hr = d3ddev->SetFVF(D3DFVF_XYZRHW | D3DFVF_TEX1); + hr = d3ddev->SetFVF(D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX1); if (hr == D3D_OK) hr = d3ddev->SetStreamSource(0, v_buffer, 0, sizeof(CUSTOMVERTEX)); @@ -376,43 +404,22 @@ void d3d_blit_memtoscreen_8(int x, int y, int w, int h) if (hr == D3D_OK) hr = d3ddev->EndScene(); } - else - video_blit_complete(); - - d3d_verts[0].tu = d3d_verts[2].tu = d3d_verts[3].tu = 0;//0.5 / 2048.0; - d3d_verts[0].tv = d3d_verts[3].tv = d3d_verts[4].tv = 0;//0.5 / 2048.0; - d3d_verts[1].tu = d3d_verts[4].tu = d3d_verts[5].tu = (float)w / 2048.0; - d3d_verts[1].tv = d3d_verts[2].tv = d3d_verts[5].tv = (float)h / 2048.0; - - GetClientRect(d3d_hwnd, &r); - d3d_verts[0].x = d3d_verts[2].x = d3d_verts[3].x = -0.5; - d3d_verts[0].y = d3d_verts[3].y = d3d_verts[4].y = -0.5; - d3d_verts[1].x = d3d_verts[4].x = d3d_verts[5].x = (r.right - r.left) - 0.5; - d3d_verts[1].y = d3d_verts[2].y = d3d_verts[5].y = (r.bottom - r.top) - 0.5; if (hr == D3D_OK) - hr = v_buffer->Lock(0, 0, (void**)&pVoid, 0); // lock the vertex buffer - if (hr == D3D_OK) - memcpy(pVoid, d3d_verts, sizeof(d3d_verts)); // copy the vertices to the locked buffer - if (hr == D3D_OK) - hr = v_buffer->Unlock(); // unlock the vertex buffer - - if (hr == D3D_OK) hr = d3ddev->Present(NULL, NULL, d3d_hwnd, NULL); if (hr == D3DERR_DEVICELOST || hr == D3DERR_INVALIDCALL) PostMessage(d3d_hwnd, WM_RESETD3D, 0, 0); } -void d3d_take_screenshot(char *fn) +void d3d_take_screenshot(wchar_t *fn) { - HRESULT hr = D3D_OK; LPDIRECT3DSURFACE9 d3dSurface = NULL; if (!d3dTexture) return; - hr = d3ddev->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &d3dSurface); - hr = D3DXSaveSurfaceToFile(fn, D3DXIFF_PNG, d3dSurface, NULL, NULL); + d3ddev->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &d3dSurface); + D3DXSaveSurfaceToFile(fn, D3DXIFF_PNG, d3dSurface, NULL, NULL); d3dSurface->Release(); d3dSurface = NULL; diff --git a/src/WIN/win_d3d.h b/src/WIN/win_d3d.h new file mode 100644 index 000000000..11128d486 --- /dev/null +++ b/src/WIN/win_d3d.h @@ -0,0 +1,47 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Direct3D 9 rendererer and screenshots taking. + * + * Version: @(#)win_d3d.h 1.0.0 2017/05/30 + * + * Author: Sarah Walker, + * Miran Grca, + * Copyright 2008-2017 Sarah Walker. + * Copyright 2016-2017 Miran Grca. + */ + +#ifndef WIN_D3D_H +# define WIN_D3D_H +# define UNICODE +# define BITMAP WINDOWS_BITMAP +# include +# include +# undef BITMAP + + +#ifdef __cplusplus +extern "C" { +#endif + +extern int d3d_init(HWND h); +extern void d3d_close(void); +extern void d3d_reset(void); +extern void d3d_resize(int x, int y); + +extern int d3d_fs_init(HWND h); +extern void d3d_fs_close(void); +extern void d3d_fs_reset(void); +extern void d3d_fs_resize(int x, int y); + +#ifdef __cplusplus +} +#endif + + +#endif /*WIN_D3D_H*/ diff --git a/src/win-d3d-fs.cc b/src/WIN/win_d3d_fs.cc similarity index 64% rename from src/win-d3d-fs.cc rename to src/WIN/win_d3d_fs.cc index 86d8b895f..7a84bc77b 100644 --- a/src/win-d3d-fs.cc +++ b/src/WIN/win_d3d_fs.cc @@ -1,29 +1,41 @@ -/* Copyright holders: Sarah Walker, Tenshi - see COPYING for more details -*/ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Direct3D 9 full screen rendererer and screenshots taking. + * + * Version: @(#)win_d3d_fs.cc 1.0.1 2017/06/03 + * + * Authors: Sarah Walker, + * Miran Grca, + * Copyright 2008-2017 Sarah Walker. + * Copyright 2016-2017 Miran Grca. + */ #include #include -#define BITMAP WINDOWS_BITMAP -#include -#undef BITMAP -#include -#include "86box.h" -#include "resources.h" -#include "video.h" -#include "win-d3d-fs.h" +#include "../86box.h" +#include "../video/video.h" #include "win.h" +#include "win_d3d.h" +#include "win_cgapal.h" + extern "C" void fatal(const char *format, ...); extern "C" void pclog(const char *format, ...); -extern "C" void device_force_redraw(); +extern "C" void device_force_redraw(void); -static void d3d_fs_init_objects(); -static void d3d_fs_close_objects(); +static void d3d_fs_init_objects(void); +static void d3d_fs_close_objects(void); static void d3d_fs_blit_memtoscreen(int x, int y, int y1, int y2, int w, int h); static void d3d_fs_blit_memtoscreen_8(int x, int y, int w, int h); -extern "C" void video_blit_complete(); +extern "C" void video_blit_complete(void); + static LPDIRECT3D9 d3d = NULL; static LPDIRECT3DDEVICE9 d3ddev = NULL; @@ -39,10 +51,11 @@ static int d3d_fs_w, d3d_fs_h; struct CUSTOMVERTEX { FLOAT x, y, z, rhw; // from the D3DFVF_XYZRHW flag + DWORD color; FLOAT tu, tv; }; -static PALETTE cgapal= +PALETTE cgapal = { {0,0,0},{0,42,0},{42,0,0},{42,21,0}, {0,0,0},{0,42,42},{42,0,42},{42,42,42}, @@ -65,24 +78,97 @@ static PALETTE cgapal= {0,0,0},{0,63,63},{63,0,0},{63,63,63}, }; -static uint32_t pal_lookup[256]; +PALETTE cgapal_mono[6] = +{ + { // 0 - green, 4-color-optimized contrast + {0x00,0x00,0x00},{0x00,0x0d,0x03},{0x01,0x17,0x05},{0x01,0x1a,0x06},{0x02,0x28,0x09},{0x02,0x2c,0x0a},{0x03,0x39,0x0d},{0x03,0x3c,0x0e}, + {0x00,0x07,0x01},{0x01,0x13,0x04},{0x01,0x1f,0x07},{0x01,0x23,0x08},{0x02,0x31,0x0b},{0x02,0x35,0x0c},{0x05,0x3f,0x11},{0x0d,0x3f,0x17}, + }, + { // 1 - green, 16-color-optimized contrast + {0x00,0x00,0x00},{0x00,0x0d,0x03},{0x01,0x15,0x05},{0x01,0x17,0x05},{0x01,0x21,0x08},{0x01,0x24,0x08},{0x02,0x2e,0x0b},{0x02,0x31,0x0b}, + {0x01,0x22,0x08},{0x02,0x28,0x09},{0x02,0x30,0x0b},{0x02,0x32,0x0c},{0x03,0x39,0x0d},{0x03,0x3b,0x0e},{0x09,0x3f,0x14},{0x0d,0x3f,0x17}, + }, + { // 2 - amber, 4-color-optimized contrast + {0x00,0x00,0x00},{0x15,0x05,0x00},{0x20,0x0b,0x00},{0x24,0x0d,0x00},{0x33,0x18,0x00},{0x37,0x1b,0x00},{0x3f,0x26,0x01},{0x3f,0x2b,0x06}, + {0x0b,0x02,0x00},{0x1b,0x08,0x00},{0x29,0x11,0x00},{0x2e,0x14,0x00},{0x3b,0x1e,0x00},{0x3e,0x21,0x00},{0x3f,0x32,0x0a},{0x3f,0x38,0x0d}, + }, + { // 3 - amber, 16-color-optimized contrast + {0x00,0x00,0x00},{0x15,0x05,0x00},{0x1e,0x09,0x00},{0x21,0x0b,0x00},{0x2b,0x12,0x00},{0x2f,0x15,0x00},{0x38,0x1c,0x00},{0x3b,0x1e,0x00}, + {0x2c,0x13,0x00},{0x32,0x17,0x00},{0x3a,0x1e,0x00},{0x3c,0x1f,0x00},{0x3f,0x27,0x01},{0x3f,0x2a,0x04},{0x3f,0x36,0x0c},{0x3f,0x38,0x0d}, + }, + { // 4 - grey, 4-color-optimized contrast + {0x00,0x00,0x00},{0x0e,0x0f,0x10},{0x15,0x17,0x18},{0x18,0x1a,0x1b},{0x24,0x25,0x25},{0x27,0x28,0x28},{0x33,0x34,0x32},{0x37,0x38,0x35}, + {0x09,0x0a,0x0b},{0x11,0x12,0x13},{0x1c,0x1e,0x1e},{0x20,0x22,0x22},{0x2c,0x2d,0x2c},{0x2f,0x30,0x2f},{0x3c,0x3c,0x38},{0x3f,0x3f,0x3b}, + }, + { // 5 - grey, 16-color-optimized contrast + {0x00,0x00,0x00},{0x0e,0x0f,0x10},{0x13,0x14,0x15},{0x15,0x17,0x18},{0x1e,0x20,0x20},{0x20,0x22,0x22},{0x29,0x2a,0x2a},{0x2c,0x2d,0x2c}, + {0x1f,0x21,0x21},{0x23,0x25,0x25},{0x2b,0x2c,0x2b},{0x2d,0x2e,0x2d},{0x34,0x35,0x33},{0x37,0x37,0x34},{0x3e,0x3e,0x3a},{0x3f,0x3f,0x3b}, + } +}; + +uint32_t pal_lookup[256]; static CUSTOMVERTEX d3d_verts[] = { - { 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f}, - {2080.0f, 2080.0f, 1.0f, 1.0f, 1.0f, 1.0f}, - { 0.0f, 2080.0f, 1.0f, 1.0f, 0.0f, 1.0f}, + { 0.0f, 0.0f, 1.0f, 1.0f, 0xffffff, 0.0f, 0.0f}, + {2048.0f, 2048.0f, 1.0f, 1.0f, 0xffffff, 1.0f, 1.0f}, + { 0.0f, 2048.0f, 1.0f, 1.0f, 0xffffff, 0.0f, 1.0f}, - { 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f}, - {2080.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f}, - {2080.0f, 2080.0f, 1.0f, 1.0f, 1.0f, 1.0f}, + { 0.0f, 0.0f, 1.0f, 1.0f, 0xffffff, 0.0f, 0.0f}, + {2048.0f, 0.0f, 1.0f, 1.0f, 0xffffff, 1.0f, 0.0f}, + {2048.0f, 2048.0f, 1.0f, 1.0f, 0xffffff, 1.0f, 1.0f}, + + { 0.0f, 0.0f, 1.0f, 1.0f, 0xffffff, 0.0f, 0.0f}, + {2048.0f, 2048.0f, 1.0f, 1.0f, 0xffffff, 1.0f, 1.0f}, + { 0.0f, 2048.0f, 1.0f, 1.0f, 0xffffff, 0.0f, 1.0f}, + + { 0.0f, 0.0f, 1.0f, 1.0f, 0xffffff, 0.0f, 0.0f}, + {2048.0f, 0.0f, 1.0f, 1.0f, 0xffffff, 1.0f, 0.0f}, + {2048.0f, 2048.0f, 1.0f, 1.0f, 0xffffff, 1.0f, 1.0f} }; - -void d3d_fs_init(HWND h) + + +void cgapal_rebuild(void) { int c; - HRESULT hr; - char emulator_title[200]; + for (c = 0; c < 256; c++) + { + pal_lookup[c] = makecol(video_6to8[cgapal[c].r], video_6to8[cgapal[c].g], video_6to8[cgapal[c].b]); + } + if ((cga_palette > 1) && (cga_palette < 8)) + { + if (vid_cga_contrast != 0) + { + for (c = 0; c < 16; c++) + { + pal_lookup[c] = makecol(video_6to8[cgapal_mono[cga_palette - 2][c].r], video_6to8[cgapal_mono[cga_palette - 2][c].g], video_6to8[cgapal_mono[cga_palette - 2][c].b]); + pal_lookup[c + 16] = makecol(video_6to8[cgapal_mono[cga_palette - 2][c].r], video_6to8[cgapal_mono[cga_palette - 2][c].g], video_6to8[cgapal_mono[cga_palette - 2][c].b]); + pal_lookup[c + 32] = makecol(video_6to8[cgapal_mono[cga_palette - 2][c].r], video_6to8[cgapal_mono[cga_palette - 2][c].g], video_6to8[cgapal_mono[cga_palette - 2][c].b]); + pal_lookup[c + 48] = makecol(video_6to8[cgapal_mono[cga_palette - 2][c].r], video_6to8[cgapal_mono[cga_palette - 2][c].g], video_6to8[cgapal_mono[cga_palette - 2][c].b]); + } + } + else + { + for (c = 0; c < 16; c++) + { + pal_lookup[c] = makecol(video_6to8[cgapal_mono[cga_palette - 1][c].r], video_6to8[cgapal_mono[cga_palette - 1][c].g], video_6to8[cgapal_mono[cga_palette - 1][c].b]); + pal_lookup[c + 16] = makecol(video_6to8[cgapal_mono[cga_palette - 1][c].r], video_6to8[cgapal_mono[cga_palette - 1][c].g], video_6to8[cgapal_mono[cga_palette - 1][c].b]); + pal_lookup[c + 32] = makecol(video_6to8[cgapal_mono[cga_palette - 1][c].r], video_6to8[cgapal_mono[cga_palette - 1][c].g], video_6to8[cgapal_mono[cga_palette - 1][c].b]); + pal_lookup[c + 48] = makecol(video_6to8[cgapal_mono[cga_palette - 1][c].r], video_6to8[cgapal_mono[cga_palette - 1][c].g], video_6to8[cgapal_mono[cga_palette - 1][c].b]); + } + } + } + + if (cga_palette == 8) + { + pal_lookup[0x16] = makecol(video_6to8[42], video_6to8[42], video_6to8[0]); + } +} + +int d3d_fs_init(HWND h) +{ + int c; + WCHAR emulator_title[200]; d3d_fs_w = GetSystemMetrics(SM_CXSCREEN); d3d_fs_h = GetSystemMetrics(SM_CYSCREEN); @@ -92,7 +178,8 @@ void d3d_fs_init(HWND h) d3d_hwnd = h; - sprintf(emulator_title, "86Box v%s", emulator_version); + /*FIXME: should be done once, in win.c */ + _swprintf(emulator_title, L"%s v%s", EMU_NAME_W, EMU_VERSION_W); d3d_device_window = CreateWindowEx ( 0, szSubClassName, @@ -126,12 +213,14 @@ void d3d_fs_init(HWND h) d3dpp.BackBufferWidth = d3d_fs_w; d3dpp.BackBufferHeight = d3d_fs_h; - hr = d3d->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, h, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &d3ddev); + d3d->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, h, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &d3ddev); d3d_fs_init_objects(); video_blit_memtoscreen_func = d3d_fs_blit_memtoscreen; video_blit_memtoscreen_8_func = d3d_fs_blit_memtoscreen_8; + + return 1; } static void d3d_fs_close_objects() @@ -150,31 +239,29 @@ static void d3d_fs_close_objects() static void d3d_fs_init_objects() { - HRESULT hr; D3DLOCKED_RECT dr; int y; RECT r; - hr = d3ddev->CreateVertexBuffer(6*sizeof(CUSTOMVERTEX), + d3ddev->CreateVertexBuffer(12*sizeof(CUSTOMVERTEX), 0, - D3DFVF_XYZRHW | D3DFVF_TEX1, + D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX1, D3DPOOL_MANAGED, &v_buffer, NULL); - d3ddev->CreateTexture(2080, 2080, 1, 0, D3DFMT_X8R8G8B8, D3DPOOL_MANAGED, &d3dTexture, NULL); + d3ddev->CreateTexture(2048, 2048, 1, 0, D3DFMT_X8R8G8B8, D3DPOOL_MANAGED, &d3dTexture, NULL); r.top = r.left = 0; - r.bottom = 2079; - r.right = 2079; + r.bottom = r.right = 2047; if (FAILED(d3dTexture->LockRect(0, &dr, &r, 0))) fatal("LockRect failed\n"); - for (y = 0; y < 2080; y++) + for (y = 0; y < 2048; y++) { - uint32_t *p = (uint32_t *)(dr.pBits + (y * dr.Pitch)); - memset(p, 0, 2080 * 4); + uint32_t *p = (uint32_t *)((uintptr_t)dr.pBits + (y * dr.Pitch)); + memset(p, 0, 2048 * 4); } d3dTexture->UnlockRect(0); @@ -234,16 +321,7 @@ void d3d_fs_reset() void d3d_fs_close() { - if (d3dTexture) - { - d3dTexture->Release(); - d3dTexture = NULL; - } - if (v_buffer) - { - v_buffer->Release(); - v_buffer = NULL; - } + d3d_fs_close_objects(); if (d3ddev) { d3ddev->Release(); @@ -313,14 +391,13 @@ static void d3d_fs_blit_memtoscreen(int x, int y, int y1, int y2, int w, int h) VOID* pVoid; D3DLOCKED_RECT dr; RECT window_rect; - uint32_t *p, *src; int yy; double l, t, r, b; if (y1 == y2) { video_blit_complete(); - return; /*Nothing to do*/ + return; /*Nothing to do*/ } if (hr == D3D_OK && !(y1 == 0 && y2 == 0)) @@ -336,7 +413,7 @@ static void d3d_fs_blit_memtoscreen(int x, int y, int y1, int y2, int w, int h) fatal("LockRect failed\n"); for (yy = y1; yy < y2; yy++) - memcpy(dr.pBits + ((yy - y1) * dr.Pitch), &(((uint32_t *)buffer32->line[yy + y])[x]), w * 4); + memcpy((void *)((uintptr_t)dr.pBits + ((yy - y1) * dr.Pitch)), &(((uint32_t *)buffer32->line[yy + y])[x]), w * 4); video_blit_complete(); d3dTexture->UnlockRect(0); @@ -346,8 +423,12 @@ static void d3d_fs_blit_memtoscreen(int x, int y, int y1, int y2, int w, int h) d3d_verts[0].tu = d3d_verts[2].tu = d3d_verts[3].tu = 0; d3d_verts[0].tv = d3d_verts[3].tv = d3d_verts[4].tv = 0; - d3d_verts[1].tu = d3d_verts[4].tu = d3d_verts[5].tu = (float)w / 2080.0; - d3d_verts[1].tv = d3d_verts[2].tv = d3d_verts[5].tv = (float)h / 2080.0; + d3d_verts[1].tu = d3d_verts[4].tu = d3d_verts[5].tu = (float)w / 2048.0; + d3d_verts[1].tv = d3d_verts[2].tv = d3d_verts[5].tv = (float)h / 2048.0; + d3d_verts[0].color = d3d_verts[1].color = d3d_verts[2].color = + d3d_verts[3].color = d3d_verts[4].color = d3d_verts[5].color = + d3d_verts[6].color = d3d_verts[7].color = d3d_verts[8].color = + d3d_verts[9].color = d3d_verts[10].color = d3d_verts[11].color = 0xffffff; GetClientRect(d3d_device_window, &window_rect); d3d_fs_size(window_rect, &l, &t, &r, &b, w, h); @@ -364,6 +445,10 @@ static void d3d_fs_blit_memtoscreen(int x, int y, int y1, int y2, int w, int h) d3d_verts[4].y = t; d3d_verts[5].x = r; d3d_verts[5].y = b; + d3d_verts[6].x = d3d_verts[8].x = d3d_verts[9].x = r - 40.5; + d3d_verts[6].y = d3d_verts[9].y = d3d_verts[10].y = t + 8.5; + d3d_verts[7].x = d3d_verts[10].x = d3d_verts[11].x = r - 8.5; + d3d_verts[7].y = d3d_verts[8].y = d3d_verts[11].y = t + 14.5; if (hr == D3D_OK) hr = v_buffer->Lock(0, 0, (void**)&pVoid, 0); @@ -384,7 +469,7 @@ static void d3d_fs_blit_memtoscreen(int x, int y, int y1, int y2, int w, int h) hr = d3ddev->SetTexture(0, d3dTexture); if (hr == D3D_OK) - hr = d3ddev->SetFVF(D3DFVF_XYZRHW | D3DFVF_TEX1); + hr = d3ddev->SetFVF(D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX1); if (hr == D3D_OK) hr = d3ddev->SetStreamSource(0, v_buffer, 0, sizeof(CUSTOMVERTEX)); @@ -412,16 +497,15 @@ static void d3d_fs_blit_memtoscreen_8(int x, int y, int w, int h) VOID* pVoid; D3DLOCKED_RECT dr; RECT window_rect; - uint32_t *p, *src; int xx, yy; double l, t, r, b; - if (!h) + if (!h) { video_blit_complete(); - return; /*Nothing to do*/ + return; /*Nothing to do*/ } - + if (hr == D3D_OK) { RECT lock_rect; @@ -436,7 +520,7 @@ static void d3d_fs_blit_memtoscreen_8(int x, int y, int w, int h) for (yy = 0; yy < h; yy++) { - uint32_t *p = (uint32_t *)(dr.pBits + (yy * dr.Pitch)); + uint32_t *p = (uint32_t *)((uintptr_t)dr.pBits + (yy * dr.Pitch)); if ((y + yy) >= 0 && (y + yy) < buffer->h) { for (xx = 0; xx < w; xx++) @@ -450,11 +534,15 @@ static void d3d_fs_blit_memtoscreen_8(int x, int y, int w, int h) } else video_blit_complete(); - + d3d_verts[0].tu = d3d_verts[2].tu = d3d_verts[3].tu = 0; d3d_verts[0].tv = d3d_verts[3].tv = d3d_verts[4].tv = 0; - d3d_verts[1].tu = d3d_verts[4].tu = d3d_verts[5].tu = (float)w / 2080.0; - d3d_verts[1].tv = d3d_verts[2].tv = d3d_verts[5].tv = (float)h / 2080.0; + d3d_verts[1].tu = d3d_verts[4].tu = d3d_verts[5].tu = (float)w / 2048.0; + d3d_verts[1].tv = d3d_verts[2].tv = d3d_verts[5].tv = (float)h / 2048.0; + d3d_verts[0].color = d3d_verts[1].color = d3d_verts[2].color = + d3d_verts[3].color = d3d_verts[4].color = d3d_verts[5].color = + d3d_verts[6].color = d3d_verts[7].color = d3d_verts[8].color = + d3d_verts[9].color = d3d_verts[10].color = d3d_verts[11].color = 0xffffff; GetClientRect(d3d_device_window, &window_rect); d3d_fs_size(window_rect, &l, &t, &r, &b, w, h); @@ -471,6 +559,10 @@ static void d3d_fs_blit_memtoscreen_8(int x, int y, int w, int h) d3d_verts[4].y = t; d3d_verts[5].x = r; d3d_verts[5].y = b; + d3d_verts[6].x = d3d_verts[8].x = d3d_verts[9].x = r - 40.5; + d3d_verts[6].y = d3d_verts[9].y = d3d_verts[10].y = t + 8.5; + d3d_verts[7].x = d3d_verts[10].x = d3d_verts[11].x = r - 8.5; + d3d_verts[7].y = d3d_verts[8].y = d3d_verts[11].y = t + 14.5; if (hr == D3D_OK) hr = v_buffer->Lock(0, 0, (void**)&pVoid, 0); @@ -491,7 +583,7 @@ static void d3d_fs_blit_memtoscreen_8(int x, int y, int w, int h) hr = d3ddev->SetTexture(0, d3dTexture); if (hr == D3D_OK) - hr = d3ddev->SetFVF(D3DFVF_XYZRHW | D3DFVF_TEX1); + hr = d3ddev->SetFVF(D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX1); if (hr == D3D_OK) hr = d3ddev->SetStreamSource(0, v_buffer, 0, sizeof(CUSTOMVERTEX)); @@ -513,15 +605,15 @@ static void d3d_fs_blit_memtoscreen_8(int x, int y, int w, int h) PostMessage(ghwnd, WM_RESETD3D, 0, 0); } -void d3d_fs_take_screenshot(char *fn) + +void d3d_fs_take_screenshot(wchar_t *fn) { - HRESULT hr = D3D_OK; LPDIRECT3DSURFACE9 d3dSurface = NULL; if (!d3dTexture) return; - hr = d3ddev->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &d3dSurface); - hr = D3DXSaveSurfaceToFile(fn, D3DXIFF_PNG, d3dSurface, NULL, NULL); + d3ddev->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &d3dSurface); + D3DXSaveSurfaceToFile(fn, D3DXIFF_PNG, d3dSurface, NULL, NULL); d3dSurface->Release(); d3dSurface = NULL; diff --git a/src/win-ddraw.cc b/src/WIN/win_ddraw.cc similarity index 56% rename from src/win-ddraw.cc rename to src/WIN/win_ddraw.cc index 251029db7..e87265f87 100644 --- a/src/win-ddraw.cc +++ b/src/WIN/win_ddraw.cc @@ -3,124 +3,110 @@ */ #include #include -#define BITMAP WINDOWS_BITMAP -#include -#undef BITMAP -#include "win-ddraw.h" -#include "win-ddraw-screenshot.h" -#include "video.h" +#include "../video/video.h" +#include "win_ddraw.h" +#include "win_cgapal.h" + extern "C" void fatal(const char *format, ...); extern "C" void pclog(const char *format, ...); -extern "C" void device_force_redraw(); +extern "C" void device_force_redraw(void); -extern "C" void ddraw_init(HWND h); -extern "C" void ddraw_close(); +extern "C" int ddraw_init(HWND h); +extern "C" void ddraw_close(void); -extern "C" void video_blit_complete(); +extern "C" void video_blit_complete(void); static void ddraw_blit_memtoscreen(int x, int y, int y1, int y2, int w, int h); static void ddraw_blit_memtoscreen_8(int x, int y, int w, int h); static LPDIRECTDRAW lpdd = NULL; -static LPDIRECTDRAW4 lpdd4 = NULL; -static LPDIRECTDRAWSURFACE4 lpdds_pri = NULL; -static LPDIRECTDRAWSURFACE4 lpdds_back = NULL; -static LPDIRECTDRAWSURFACE4 lpdds_back2 = NULL; +static LPDIRECTDRAW7 lpdd7 = NULL; +static LPDIRECTDRAWSURFACE7 lpdds_pri = NULL; +static LPDIRECTDRAWSURFACE7 lpdds_back = NULL; +static LPDIRECTDRAWSURFACE7 lpdds_back2 = NULL; static LPDIRECTDRAWCLIPPER lpdd_clipper = NULL; static DDSURFACEDESC2 ddsd; static HWND ddraw_hwnd; -static PALETTE cgapal= +int ddraw_init(HWND h) { - {0,0,0},{0,42,0},{42,0,0},{42,21,0}, - {0,0,0},{0,42,42},{42,0,42},{42,42,42}, - {0,0,0},{21,63,21},{63,21,21},{63,63,21}, - {0,0,0},{21,63,63},{63,21,63},{63,63,63}, - - {0,0,0},{0,0,42},{0,42,0},{0,42,42}, - {42,0,0},{42,0,42},{42,21,00},{42,42,42}, - {21,21,21},{21,21,63},{21,63,21},{21,63,63}, - {63,21,21},{63,21,63},{63,63,21},{63,63,63}, - - {0,0,0},{0,21,0},{0,0,42},{0,42,42}, - {42,0,21},{21,10,21},{42,0,42},{42,0,63}, - {21,21,21},{21,63,21},{42,21,42},{21,63,63}, - {63,0,0},{42,42,0},{63,21,42},{41,41,41}, - - {0,0,0},{0,42,42},{42,0,0},{42,42,42}, - {0,0,0},{0,42,42},{42,0,0},{42,42,42}, - {0,0,0},{0,63,63},{63,0,0},{63,63,63}, - {0,0,0},{0,63,63},{63,0,0},{63,63,63}, -}; - -static uint32_t pal_lookup[256]; - -void ddraw_init(HWND h) -{ - int c; - - for (c = 0; c < 256; c++) - pal_lookup[c] = makecol(cgapal[c].r << 2, cgapal[c].g << 2, cgapal[c].b << 2); + cgapal_rebuild(); if (FAILED(DirectDrawCreate(NULL, &lpdd, NULL))) - fatal("DirectDrawCreate failed\n"); + return 0; - if (FAILED(lpdd->QueryInterface(IID_IDirectDraw4, (LPVOID *)&lpdd4))) - fatal("QueryInterface failed\n"); + if (FAILED(lpdd->QueryInterface(IID_IDirectDraw7, (LPVOID *)&lpdd7))) + return 0; lpdd->Release(); lpdd = NULL; atexit(ddraw_close); - if (FAILED(lpdd4->SetCooperativeLevel(h, DDSCL_NORMAL))) - fatal("SetCooperativeLevel failed\n"); + if (FAILED(lpdd7->SetCooperativeLevel(h, DDSCL_NORMAL))) + return 0; memset(&ddsd, 0, sizeof(ddsd)); ddsd.dwSize = sizeof(ddsd); ddsd.dwFlags = DDSD_CAPS; ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; - if (FAILED(lpdd4->CreateSurface(&ddsd, &lpdds_pri, NULL))) - fatal("CreateSurface failed\n"); + if (FAILED(lpdd7->CreateSurface(&ddsd, &lpdds_pri, NULL))) + return 0; - memset(&ddsd, 0, sizeof(ddsd)); - ddsd.dwSize = sizeof(ddsd); + // memset(&ddsd, 0, sizeof(ddsd)); + // ddsd.dwSize = sizeof(ddsd); ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT; - ddsd.dwWidth = 2080; - ddsd.dwHeight = 2080; + ddsd.dwWidth = 2048; + ddsd.dwHeight = 2048; ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY; - if (FAILED(lpdd4->CreateSurface(&ddsd, &lpdds_back, NULL))) - fatal("CreateSurface back failed\n"); + if (FAILED(lpdd7->CreateSurface(&ddsd, &lpdds_back, NULL))) + { + ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT; + ddsd.dwWidth = 2048; + ddsd.dwHeight = 2048; + ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY; + if (FAILED(lpdd7->CreateSurface(&ddsd, &lpdds_back, NULL))) + fatal("CreateSurface back failed\n"); + } memset(&ddsd, 0, sizeof(ddsd)); ddsd.dwSize = sizeof(ddsd); ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT; - ddsd.dwWidth = 2080; - ddsd.dwHeight = 2080; + ddsd.dwWidth = 2048; + ddsd.dwHeight = 2048; ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY; - if (FAILED(lpdd4->CreateSurface(&ddsd, &lpdds_back2, NULL))) - fatal("CreateSurface back failed\n"); + if (FAILED(lpdd7->CreateSurface(&ddsd, &lpdds_back2, NULL))) + { + ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT; + ddsd.dwWidth = 2048; + ddsd.dwHeight = 2048; + ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY; + if (FAILED(lpdd7->CreateSurface(&ddsd, &lpdds_back2, NULL))) + fatal("CreateSurface back failed\n"); + } - if (FAILED(lpdd4->CreateClipper(0, &lpdd_clipper, NULL))) - fatal("CreateClipper failed\n"); + if (FAILED(lpdd7->CreateClipper(0, &lpdd_clipper, NULL))) + return 0; if (FAILED(lpdd_clipper->SetHWnd(0, h))) - fatal("SetHWnd failed\n"); + return 0; if (FAILED(lpdds_pri->SetClipper(lpdd_clipper))) - fatal("SetClipper failed\n"); + return 0; pclog("DDRAW_INIT complete\n"); ddraw_hwnd = h; video_blit_memtoscreen_func = ddraw_blit_memtoscreen; video_blit_memtoscreen_8_func = ddraw_blit_memtoscreen_8; + + return 1; } -void ddraw_close() +void ddraw_close(void) { if (lpdds_back2) { @@ -142,10 +128,10 @@ void ddraw_close() lpdd_clipper->Release(); lpdd_clipper = NULL; } - if (lpdd4) + if (lpdd7) { - lpdd4->Release(); - lpdd4 = NULL; + lpdd7->Release(); + lpdd7 = NULL; } } @@ -153,12 +139,23 @@ static void ddraw_blit_memtoscreen(int x, int y, int y1, int y2, int w, int h) { RECT r_src; RECT r_dest; - int xx, yy; + int yy; POINT po; - uint32_t *p; HRESULT hr; // pclog("Blit memtoscreen %i,%i %i %i %i,%i\n", x, y, y1, y2, w, h); + if (lpdds_back == NULL) + { + video_blit_complete(); + return; /*Nothing to do*/ + } + + if (h <= 0) + { + video_blit_complete(); + return; + } + memset(&ddsd, 0, sizeof(ddsd)); ddsd.dwSize = sizeof(ddsd); @@ -177,7 +174,7 @@ static void ddraw_blit_memtoscreen(int x, int y, int y1, int y2, int w, int h) for (yy = y1; yy < y2; yy++) { if ((y + yy) >= 0 && (y + yy) < buffer->h) - memcpy(ddsd.lpSurface + (yy * ddsd.lPitch), &(((uint32_t *)buffer32->line[y + yy])[x]), w * 4); + memcpy((uint32_t *) &(((uint8_t *) ddsd.lpSurface)[yy * ddsd.lPitch]), &(((uint32_t *)buffer32->line[y + yy])[x]), w * 4); } video_blit_complete(); lpdds_back->Unlock(NULL); @@ -200,27 +197,6 @@ static void ddraw_blit_memtoscreen(int x, int y, int y1, int y2, int w, int h) lpdds_back2->Blt(&r_src, lpdds_back, &r_src, DDBLT_WAIT, NULL); } - if (readflash) - { - readflash = 0; - if (enable_flash) - { - hr = lpdds_back2->Lock(NULL, &ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL); - if (hr == DDERR_SURFACELOST) - { - lpdds_back2->Restore(); - lpdds_back2->Lock(NULL, &ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL); - device_force_redraw(); - } - if (!ddsd.lpSurface) return; - for (yy = 8; yy < 14; yy++) - { - p = (uint32_t *)(ddsd.lpSurface + (yy * ddsd.lPitch)); - for (xx = (w - 40); xx < (w - 8); xx++) - p[xx] = 0xffffffff; - } - } - } lpdds_back2->Unlock(NULL); // pclog("Blit from %i,%i %i,%i to %i,%i %i,%i\n", r_src.left, r_src.top, r_src.right, r_src.bottom, r_dest.left, r_dest.top, r_dest.right, r_dest.bottom); @@ -241,6 +217,12 @@ static void ddraw_blit_memtoscreen_8(int x, int y, int w, int h) uint32_t *p; HRESULT hr; + if (lpdds_back == NULL) + { + video_blit_complete(); + return; /*Nothing to do*/ + } + memset(&ddsd, 0, sizeof(ddsd)); ddsd.dwSize = sizeof(ddsd); @@ -261,14 +243,14 @@ static void ddraw_blit_memtoscreen_8(int x, int y, int w, int h) { if ((y + yy) >= 0 && (y + yy) < buffer->h) { - p = (uint32_t *)(ddsd.lpSurface + (yy * ddsd.lPitch)); + p = (uint32_t *) &(((uint8_t *) ddsd.lpSurface)[yy * ddsd.lPitch]); for (xx = 0; xx < w; xx++) { p[xx] = pal_lookup[buffer->line[y + yy][x + xx]]; } } } - p = (uint32_t *)(ddsd.lpSurface + (4 * ddsd.lPitch)); + p = &(((uint32_t *) ddsd.lpSurface)[4 * ddsd.lPitch]); lpdds_back->Unlock(NULL); video_blit_complete(); @@ -290,29 +272,6 @@ static void ddraw_blit_memtoscreen_8(int x, int y, int w, int h) lpdds_back2->Blt(&r_src, lpdds_back, &r_src, DDBLT_WAIT, NULL); } - if (readflash) - { - readflash = 0; - if (enable_flash) - { - hr = lpdds_back2->Lock(NULL, &ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL); - if (hr == DDERR_SURFACELOST) - { - lpdds_back2->Restore(); - lpdds_back2->Lock(NULL, &ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL); - device_force_redraw(); - } - if (!ddsd.lpSurface) return; - for (yy = 8; yy < 14; yy++) - { - p = (uint32_t *)(ddsd.lpSurface + (yy * ddsd.lPitch)); - for (xx = (w - 40); xx < (w - 8); xx++) - p[xx] = 0xffffffff; - } - lpdds_back2->Unlock(NULL); - } - } - hr = lpdds_pri->Blt(&r_dest, lpdds_back2, &r_src, DDBLT_WAIT, NULL); if (hr == DDERR_SURFACELOST) { @@ -321,7 +280,7 @@ static void ddraw_blit_memtoscreen_8(int x, int y, int w, int h) } } -void ddraw_take_screenshot(char *fn) +void ddraw_take_screenshot(wchar_t *fn) { ddraw_common_take_screenshot(fn, lpdds_back2); } diff --git a/src/WIN/win_ddraw.h b/src/WIN/win_ddraw.h new file mode 100644 index 000000000..5090aa0cc --- /dev/null +++ b/src/WIN/win_ddraw.h @@ -0,0 +1,30 @@ +/* Copyright holders: Sarah Walker, Tenshi + see COPYING for more details +*/ +#ifndef WIN_DDRAW_H +# define WIN_DDRAW_H +# define UNICODE +# define BITMAP WINDOWS_BITMAP +# include +# undef BITMAP + + +#ifdef __cplusplus +extern "C" { +#endif + +extern int ddraw_init(HWND h); +extern void ddraw_close(void); + +extern int ddraw_fs_init(HWND h); +extern void ddraw_fs_close(void); + +extern void ddraw_common_take_screenshot(wchar_t *fn, + IDirectDrawSurface7 *pDDSurface); + +#ifdef __cplusplus +} +#endif + + +#endif /*WIN_DDRAW_H*/ diff --git a/src/win-ddraw-fs.cc b/src/WIN/win_ddraw_fs.cc similarity index 72% rename from src/win-ddraw-fs.cc rename to src/WIN/win_ddraw_fs.cc index b1800d931..abb390093 100644 --- a/src/win-ddraw-fs.cc +++ b/src/WIN/win_ddraw_fs.cc @@ -2,120 +2,100 @@ see COPYING for more details */ #include -#define BITMAP WINDOWS_BITMAP -#include -#undef BITMAP -#include "win-ddraw-fs.h" -#include "win-ddraw-screenshot.h" -#include "video.h" +#include "../video/video.h" +#include "win_ddraw.h" +#include "win_cgapal.h" + + +static LPDIRECTDRAW lpdd = NULL; +static LPDIRECTDRAW7 lpdd7 = NULL; +static LPDIRECTDRAWSURFACE7 lpdds_pri = NULL; +static LPDIRECTDRAWSURFACE7 lpdds_back = NULL; +static LPDIRECTDRAWSURFACE7 lpdds_back2 = NULL; +static LPDIRECTDRAWCLIPPER lpdd_clipper = NULL; +static DDSURFACEDESC2 ddsd; +static HWND ddraw_hwnd; +static int ddraw_w, ddraw_h; + extern "C" void fatal(const char *format, ...); extern "C" void pclog(const char *format, ...); -extern "C" void device_force_redraw(); +extern "C" void device_force_redraw(void); -extern "C" void ddraw_fs_init(HWND h); -extern "C" void ddraw_fs_close(); +extern "C" int ddraw_fs_init(HWND h); +extern "C" void ddraw_fs_close(void); -extern "C" void video_blit_complete(); +extern "C" void video_blit_complete(void); -static void ddraw_fs_blit_memtoscreen(int x, int y, int y1, int y2, int w, int h); -static void ddraw_fs_blit_memtoscreen_8(int x, int y, int w, int h); +static void ddraw_fs_blit_memtoscreen(int, int, int, int, int, int); +static void ddraw_fs_blit_memtoscreen_8(int, int, int, int); -static LPDIRECTDRAW lpdd = NULL; -static LPDIRECTDRAW4 lpdd4 = NULL; -static LPDIRECTDRAWSURFACE4 lpdds_pri = NULL; -static LPDIRECTDRAWSURFACE4 lpdds_back = NULL; -static LPDIRECTDRAWSURFACE4 lpdds_back2 = NULL; -static LPDIRECTDRAWCLIPPER lpdd_clipper = NULL; -static DDSURFACEDESC2 ddsd; -static HWND ddraw_hwnd; -static int ddraw_w, ddraw_h; - -static PALETTE cgapal = +int ddraw_fs_init(HWND h) { - {0,0,0},{0,42,0},{42,0,0},{42,21,0}, - {0,0,0},{0,42,42},{42,0,42},{42,42,42}, - {0,0,0},{21,63,21},{63,21,21},{63,63,21}, - {0,0,0},{21,63,63},{63,21,63},{63,63,63}, - - {0,0,0},{0,0,42},{0,42,0},{0,42,42}, - {42,0,0},{42,0,42},{42,21,00},{42,42,42}, - {21,21,21},{21,21,63},{21,63,21},{21,63,63}, - {63,21,21},{63,21,63},{63,63,21},{63,63,63}, - - {0,0,0},{0,21,0},{0,0,42},{0,42,42}, - {42,0,21},{21,10,21},{42,0,42},{42,0,63}, - {21,21,21},{21,63,21},{42,21,42},{21,63,63}, - {63,0,0},{42,42,0},{63,21,42},{41,41,41}, - - {0,0,0},{0,42,42},{42,0,0},{42,42,42}, - {0,0,0},{0,42,42},{42,0,0},{42,42,42}, - {0,0,0},{0,63,63},{63,0,0},{63,63,63}, - {0,0,0},{0,63,63},{63,0,0},{63,63,63}, -}; - -static uint32_t pal_lookup[256]; - -void ddraw_fs_init(HWND h) -{ - int c; - ddraw_w = GetSystemMetrics(SM_CXSCREEN); ddraw_h = GetSystemMetrics(SM_CYSCREEN); - for (c = 0; c < 256; c++) - pal_lookup[c] = makecol(cgapal[c].r << 2, cgapal[c].g << 2, cgapal[c].b << 2); + cgapal_rebuild(); if (FAILED(DirectDrawCreate(NULL, &lpdd, NULL))) - fatal("DirectDrawCreate failed\n"); + return 0; - if (FAILED(lpdd->QueryInterface(IID_IDirectDraw4, (LPVOID *)&lpdd4))) - fatal("QueryInterface failed\n"); + if (FAILED(lpdd->QueryInterface(IID_IDirectDraw7, (LPVOID *)&lpdd7))) + return 0; lpdd->Release(); lpdd = NULL; atexit(ddraw_fs_close); - if (FAILED(lpdd4->SetCooperativeLevel(h, DDSCL_SETFOCUSWINDOW | + if (FAILED(lpdd7->SetCooperativeLevel(h, DDSCL_SETFOCUSWINDOW | DDSCL_CREATEDEVICEWINDOW | DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN | DDSCL_ALLOWREBOOT))) - fatal("SetCooperativeLevel failed\n"); + return 0; - if (FAILED(lpdd4->SetDisplayMode(ddraw_w, ddraw_h, 32, 0 ,0))) - fatal("SetDisplayMode failed\n"); + if (FAILED(lpdd7->SetDisplayMode(ddraw_w, ddraw_h, 32, 0 ,0))) + return 0; - memset(&ddsd, 0, sizeof(ddsd)); - ddsd.dwSize = sizeof(ddsd); + // memset(&ddsd, 0, sizeof(ddsd)); + // ddsd.dwSize = sizeof(ddsd); ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT; ddsd.dwBackBufferCount = 1; ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_COMPLEX | DDSCAPS_FLIP; - if (FAILED(lpdd4->CreateSurface(&ddsd, &lpdds_pri, NULL))) - fatal("CreateSurface failed\n"); + if (FAILED(lpdd7->CreateSurface(&ddsd, &lpdds_pri, NULL))) + return 0; ddsd.ddsCaps.dwCaps = DDSCAPS_BACKBUFFER; if (FAILED(lpdds_pri->GetAttachedSurface(&ddsd.ddsCaps, &lpdds_back2))) - fatal("CreateSurface back failed\n"); + return 0; memset(&ddsd, 0, sizeof(ddsd)); ddsd.dwSize = sizeof(ddsd); ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT; - ddsd.dwWidth = 2080; - ddsd.dwHeight = 2080; + ddsd.dwWidth = 2048; + ddsd.dwHeight = 2048; ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY; - if (FAILED(lpdd4->CreateSurface(&ddsd, &lpdds_back, NULL))) - fatal("CreateSurface back failed\n"); + if (FAILED(lpdd7->CreateSurface(&ddsd, &lpdds_back, NULL))) + { + ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT; + ddsd.dwWidth = 2048; + ddsd.dwHeight = 2048; + ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY; + if (FAILED(lpdd7->CreateSurface(&ddsd, &lpdds_back, NULL))) + return 0; + } pclog("DDRAW_INIT complete\n"); ddraw_hwnd = h; video_blit_memtoscreen_func = ddraw_fs_blit_memtoscreen; video_blit_memtoscreen_8_func = ddraw_fs_blit_memtoscreen_8; + + return 1; } -void ddraw_fs_close() +void ddraw_fs_close(void) { if (lpdds_back2) { @@ -137,10 +117,10 @@ void ddraw_fs_close() lpdd_clipper->Release(); lpdd_clipper = NULL; } - if (lpdd4) + if (lpdd7) { - lpdd4->Release(); - lpdd4 = NULL; + lpdd7->Release(); + lpdd7 = NULL; } } @@ -203,6 +183,12 @@ static void ddraw_fs_blit_memtoscreen(int x, int y, int y1, int y2, int w, int h HRESULT hr; DDBLTFX ddbltfx; + if (lpdds_back == NULL) + { + video_blit_complete(); + return; /*Nothing to do*/ + } + memset(&ddsd, 0, sizeof(ddsd)); ddsd.dwSize = sizeof(ddsd); @@ -248,17 +234,6 @@ static void ddraw_fs_blit_memtoscreen(int x, int y, int y1, int y2, int w, int h lpdds_back2->Blt(&r_dest, lpdds_back, &r_src, DDBLT_WAIT, NULL); } - if (readflash && enable_flash) - { - RECT r; - r.left = window_rect.right - 40; - r.right = window_rect.right - 8; - r.top = 8; - r.bottom = 14; - ddbltfx.dwFillColor = 0xffffff; - lpdds_back2->Blt(&r, NULL, NULL, DDBLT_WAIT | DDBLT_COLORFILL, &ddbltfx); - } - hr = lpdds_pri->Flip(NULL, DDFLIP_NOVSYNC); if (hr == DDERR_SURFACELOST) { @@ -276,6 +251,12 @@ static void ddraw_fs_blit_memtoscreen_8(int x, int y, int w, int h) HRESULT hr; DDBLTFX ddbltfx; + if (lpdds_back == NULL) + { + video_blit_complete(); + return; /*Nothing to do*/ + } + memset(&ddsd, 0, sizeof(ddsd)); ddsd.dwSize = sizeof(ddsd); @@ -296,7 +277,7 @@ static void ddraw_fs_blit_memtoscreen_8(int x, int y, int w, int h) { if ((y + yy) >= 0 && (y + yy) < buffer->h) { - uint32_t *p = (uint32_t *)(ddsd.lpSurface + (yy * ddsd.lPitch)); + uint32_t *p = (uint32_t *) &(((uint8_t *) ddsd.lpSurface)[yy * ddsd.lPitch]); for (xx = 0; xx < w; xx++) { p[xx] = pal_lookup[buffer->line[y + yy][x + xx]]; @@ -329,21 +310,10 @@ static void ddraw_fs_blit_memtoscreen_8(int x, int y, int w, int h) lpdds_back2->Blt(&r_dest, lpdds_back, &r_src, DDBLT_WAIT, NULL); } - if (readflash && enable_flash) - { - RECT r; - r.left = window_rect.right - 40; - r.right = window_rect.right - 8; - r.top = 8; - r.bottom = 14; - ddbltfx.dwFillColor = 0xffffff; - lpdds_back2->Blt(&r, NULL, NULL, DDBLT_WAIT | DDBLT_COLORFILL, &ddbltfx); - } - lpdds_pri->Flip(NULL, DDFLIP_NOVSYNC); } -void ddraw_fs_take_screenshot(char *fn) +void ddraw_fs_take_screenshot(wchar_t *fn) { ddraw_common_take_screenshot(fn, lpdds_back2); } diff --git a/src/win-ddraw-screenshot.cc b/src/WIN/win_ddraw_screenshot.cc similarity index 76% rename from src/win-ddraw-screenshot.cc rename to src/WIN/win_ddraw_screenshot.cc index 1942c30cb..b98a207d1 100644 --- a/src/win-ddraw-screenshot.cc +++ b/src/WIN/win_ddraw_screenshot.cc @@ -1,27 +1,39 @@ -/* Copyright holders: Tenshi - see COPYING for more details -*/ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * DirectDraw screenshot taking code. + * + * Version: @(#)win_ddraw_screenshot.cc 1.0.0 2017/05/30 + * + * Author: Miran Grca, + * Copyright 2016-2017 Miran Grca. + */ + #include #include +#define UNICODE #define BITMAP WINDOWS_BITMAP -#include +#include #undef BITMAP -#include "win-ddraw-screenshot.h" -#include "video.h" +#include "../video/video.h" +#include "win.h" +#include "win_ddraw.h" +#include "win_language.h" -extern "C" void fatal(const char *format, ...); -extern "C" void pclog(const char *format, ...); - -extern "C" void device_force_redraw(); - -extern "C" void ddraw_init(HWND h); -extern "C" void ddraw_close(); HBITMAP hbitmap; - int xs, ys, ys2; -void CopySurface(IDirectDrawSurface4 *pDDSurface) + +extern "C" void pclog(const char *format, ...); + + +void CopySurface(IDirectDrawSurface7 *pDDSurface) { HDC hdc, hmemdc; @@ -54,6 +66,7 @@ void CopySurface(IDirectDrawSurface4 *pDDSurface) return ; } + void DoubleLines(uint8_t *dst, uint8_t *src) { int i = 0; @@ -64,7 +77,9 @@ void DoubleLines(uint8_t *dst, uint8_t *src) } } -void SaveBitmap(char *szFilename,HBITMAP hBitmap) +static WCHAR szMessage[2048]; + +void SaveBitmap(wchar_t *szFilename,HBITMAP hBitmap) { HDC hdc=NULL; FILE* fp=NULL; @@ -73,8 +88,6 @@ void SaveBitmap(char *szFilename,HBITMAP hBitmap) BITMAPINFO bmpInfo; BITMAPFILEHEADER bmpFileHeader; - char szMessage[2048]; - do{ hdc=GetDC(NULL); @@ -103,10 +116,10 @@ void SaveBitmap(char *szFilename,HBITMAP hBitmap) GetDIBits(hdc,hBitmap,0,bmpInfo.bmiHeader.biHeight,pBuf, &bmpInfo, DIB_RGB_COLORS); - if((fp = fopen(szFilename,"wb"))==NULL) + if((fp = _wfopen(szFilename,L"wb"))==NULL) { - sprintf(szMessage, "Unable to Create Bitmap File %s", szFilename); - MessageBox( NULL, szMessage, "Error", MB_OK|MB_ICONERROR); + _swprintf(szMessage, win_language_get_string_from_id(2194), szFilename); + msgbox_error_wstr(ghwnd, szMessage); break; } @@ -122,7 +135,7 @@ void SaveBitmap(char *szFilename,HBITMAP hBitmap) bmpFileHeader.bfSize=sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+bmpInfo.bmiHeader.biSizeImage; - bmpFileHeader.bfType='MB'; + bmpFileHeader.bfType=0x4D42; bmpFileHeader.bfOffBits=sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER); @@ -151,7 +164,7 @@ void SaveBitmap(char *szFilename,HBITMAP hBitmap) if(fp) fclose(fp); } -void ddraw_common_take_screenshot(char *fn, IDirectDrawSurface4 *pDDSurface) +void ddraw_common_take_screenshot(wchar_t *fn, IDirectDrawSurface7 *pDDSurface) { xs = xsize; ys = ys2 = ysize; diff --git a/src/win-deviceconfig.c b/src/WIN/win_deviceconfig.c similarity index 62% rename from src/win-deviceconfig.c rename to src/WIN/win_deviceconfig.c index bff026317..3cce23331 100644 --- a/src/win-deviceconfig.c +++ b/src/WIN/win_deviceconfig.c @@ -1,37 +1,57 @@ -/* Copyright holders: Sarah Walker - see COPYING for more details -*/ -#define BITMAP WINDOWS_BITMAP -#include -#include -#undef BITMAP - -#include "ibm.h" -#include "config.h" -#include "device.h" -#include "resources.h" +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Windows device configuration dialog implementation. + * + * Version: @(#)win_deviceconfig.c 1.0.1 2017/06/19 + * + * Authors: Sarah Walker, + * Miran Grca, + * Copyright 2008-2017 Sarah Walker. + * Copyright 2016-2017 Miran Grca. + */ +#include "../ibm.h" +#include "../config.h" +#include "../device.h" +#include "plat_midi.h" +#define NO_UNICODE /*FIXME: not Unicode? */ #include "win.h" +#include "win_language.h" +#include + static device_t *config_device; + static BOOL CALLBACK deviceconfig_dlgproc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) { + HWND h; + + int val_int; + int ret; + int id; + device_config_t *config; + int c; + int num; + int changed; + char s[80]; + switch (message) { case WM_INITDIALOG: { - int id = IDC_CONFIG_BASE; - device_config_t *config = config_device->config; - int c; + id = IDC_CONFIG_BASE; + config = config_device->config; while (config->type != -1) { device_config_selection_t *selection = config->selection; - HWND h = GetDlgItem(hdlg, id); - int val_int; - char *val_string; - int num; - char s[80]; + h = GetDlgItem(hdlg, id); switch (config->type) { @@ -42,7 +62,7 @@ static BOOL CALLBACK deviceconfig_dlgproc(HWND hdlg, UINT message, WPARAM wParam id++; break; - + case CONFIG_SELECTION: val_int = config_get_int(config_device->name, config->name, config->default_int); @@ -60,12 +80,12 @@ static BOOL CALLBACK deviceconfig_dlgproc(HWND hdlg, UINT message, WPARAM wParam break; case CONFIG_MIDI: - val_int = config_get_int(NULL, config->name, config->default_int); + val_int = config_get_int(config_device->name, config->name, config->default_int); - num = midi_get_num_devs(); + num = plat_midi_get_num_devs(); for (c = 0; c < num; c++) { - midi_get_dev_name(c, s); + plat_midi_get_dev_name(c, s); SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)s); if (val_int == c) SendMessage(h, CB_SETCURSEL, c, 0); @@ -73,6 +93,38 @@ static BOOL CALLBACK deviceconfig_dlgproc(HWND hdlg, UINT message, WPARAM wParam id += 2; break; + + case CONFIG_HEX16: + val_int = config_get_hex16(config_device->name, config->name, config->default_int); + + c = 0; + while (selection->description[0]) + { + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)selection->description); + if (val_int == selection->value) + SendMessage(h, CB_SETCURSEL, c, 0); + selection++; + c++; + } + + id += 2; + break; + + case CONFIG_HEX20: + val_int = config_get_hex20(config_device->name, config->name, config->default_int); + + c = 0; + while (selection->description[0]) + { + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)selection->description); + if (val_int == selection->value) + SendMessage(h, CB_SETCURSEL, c, 0); + selection++; + c++; + } + + id += 2; + break; } config++; } @@ -84,17 +136,14 @@ static BOOL CALLBACK deviceconfig_dlgproc(HWND hdlg, UINT message, WPARAM wParam { case IDOK: { - int id = IDC_CONFIG_BASE; - device_config_t *config = config_device->config; - int c; - int changed = 0; + id = IDC_CONFIG_BASE; + config = config_device->config; + changed = 0; while (config->type != -1) { device_config_selection_t *selection = config->selection; - HWND h = GetDlgItem(hdlg, id); - int val_int; - char *val_string; + h = GetDlgItem(hdlg, id); switch (config->type) { @@ -106,7 +155,7 @@ static BOOL CALLBACK deviceconfig_dlgproc(HWND hdlg, UINT message, WPARAM wParam id++; break; - + case CONFIG_SELECTION: val_int = config_get_int(config_device->name, config->name, config->default_int); @@ -122,7 +171,7 @@ static BOOL CALLBACK deviceconfig_dlgproc(HWND hdlg, UINT message, WPARAM wParam break; case CONFIG_MIDI: - val_int = config_get_int(NULL, config->name, config->default_int); + val_int = config_get_int(config_device->name, config->name, config->default_int); c = SendMessage(h, CB_GETCURSEL, 0, 0); @@ -131,6 +180,34 @@ static BOOL CALLBACK deviceconfig_dlgproc(HWND hdlg, UINT message, WPARAM wParam id += 2; break; + + case CONFIG_HEX16: + val_int = config_get_hex16(config_device->name, config->name, config->default_int); + + c = SendMessage(h, CB_GETCURSEL, 0, 0); + + for (; c > 0; c--) + selection++; + + if (val_int != selection->value) + changed = 1; + + id += 2; + break; + + case CONFIG_HEX20: + val_int = config_get_hex20(config_device->name, config->name, config->default_int); + + c = SendMessage(h, CB_GETCURSEL, 0, 0); + + for (; c > 0; c--) + selection++; + + if (val_int != selection->value) + changed = 1; + + id += 2; + break; } config++; } @@ -140,11 +217,17 @@ static BOOL CALLBACK deviceconfig_dlgproc(HWND hdlg, UINT message, WPARAM wParam EndDialog(hdlg, 0); return TRUE; } - - if (MessageBox(NULL, "This will reset 86Box!\nOkay to continue?", "86Box", MB_OKCANCEL) != IDOK) - { - EndDialog(hdlg, 0); - return TRUE; + + ret = msgbox_reset(ghwnd); + switch(ret) + { + case IDNO: + EndDialog(hdlg, 0); + return TRUE; + case IDCANCEL: + return FALSE; + default: + break; } id = IDC_CONFIG_BASE; @@ -153,9 +236,7 @@ static BOOL CALLBACK deviceconfig_dlgproc(HWND hdlg, UINT message, WPARAM wParam while (config->type != -1) { device_config_selection_t *selection = config->selection; - HWND h = GetDlgItem(hdlg, id); - int val_int; - char *val_string; + h = GetDlgItem(hdlg, id); switch (config->type) { @@ -164,7 +245,7 @@ static BOOL CALLBACK deviceconfig_dlgproc(HWND hdlg, UINT message, WPARAM wParam id++; break; - + case CONFIG_SELECTION: c = SendMessage(h, CB_GETCURSEL, 0, 0); for (; c > 0; c--) @@ -176,10 +257,28 @@ static BOOL CALLBACK deviceconfig_dlgproc(HWND hdlg, UINT message, WPARAM wParam case CONFIG_MIDI: c = SendMessage(h, CB_GETCURSEL, 0, 0); - config_set_int(NULL, config->name, c); + config_set_int(config_device->name, config->name, c); id += 2; break; + + case CONFIG_HEX16: + c = SendMessage(h, CB_GETCURSEL, 0, 0); + for (; c > 0; c--) + selection++; + config_set_hex16(config_device->name, config->name, selection->value); + + id += 2; + break; + + case CONFIG_HEX20: + c = SendMessage(h, CB_GETCURSEL, 0, 0); + for (; c > 0; c--) + selection++; + config_set_hex20(config_device->name, config->name, selection->value); + + id += 2; + break; } config++; } @@ -247,16 +346,18 @@ void deviceconfig_open(HWND hwnd, device_t *device) data = (uint16_t *)(item + 1); *data++ = 0xFFFF; - *data++ = 0x0080; // button class + *data++ = 0x0080; /* button class */ data += MultiByteToWideChar(CP_ACP, 0, config->description, -1, data, 256); - *data++ = 0; // no creation data - + *data++ = 0; /* no creation data */ + y += 20; break; case CONFIG_SELECTION: case CONFIG_MIDI: + case CONFIG_HEX16: + case CONFIG_HEX20: /*Combo box*/ item = (DLGITEMTEMPLATE *)data; item->x = 70; @@ -270,10 +371,10 @@ void deviceconfig_open(HWND hwnd, device_t *device) data = (uint16_t *)(item + 1); *data++ = 0xFFFF; - *data++ = 0x0085; // combo box class + *data++ = 0x0085; /* combo box class */ data += MultiByteToWideChar(CP_ACP, 0, config->description, -1, data, 256); - *data++ = 0; // no creation data + *data++ = 0; /* no creation data */ if (((unsigned long)data) & 2) data++; @@ -291,10 +392,10 @@ void deviceconfig_open(HWND hwnd, device_t *device) data = (uint16_t *)(item + 1); *data++ = 0xFFFF; - *data++ = 0x0082; // static class + *data++ = 0x0082; /* static class */ data += MultiByteToWideChar(CP_ACP, 0, config->description, -1, data, 256); - *data++ = 0; // no creation data + *data++ = 0; /* no creation data */ if (((unsigned long)data) & 2) data++; @@ -311,23 +412,20 @@ void deviceconfig_open(HWND hwnd, device_t *device) dlg->cdit = (id - IDC_CONFIG_BASE) + 2; -// DEFPUSHBUTTON "OK",IDOK,64,232,50,14, WS_TABSTOP -// PUSHBUTTON "Cancel",IDCANCEL,128,232,50,14, WS_TABSTOP - item = (DLGITEMTEMPLATE *)data; item->x = 20; item->y = y; item->cx = 50; item->cy = 14; - item->id = IDOK; // OK button identifier + item->id = IDOK; /* OK button identifier */ item->style = WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON; data = (uint16_t *)(item + 1); *data++ = 0xFFFF; - *data++ = 0x0080; // button class + *data++ = 0x0080; /* button class */ data += MultiByteToWideChar(CP_ACP, 0, "OK", -1, data, 50); - *data++ = 0; // no creation data + *data++ = 0; /* no creation data */ if (((unsigned long)data) & 2) data++; @@ -337,15 +435,15 @@ void deviceconfig_open(HWND hwnd, device_t *device) item->y = y; item->cx = 50; item->cy = 14; - item->id = IDCANCEL; // OK button identifier + item->id = IDCANCEL; /* OK button identifier */ item->style = WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON; data = (uint16_t *)(item + 1); *data++ = 0xFFFF; - *data++ = 0x0080; // button class + *data++ = 0x0080; /* button class */ data += MultiByteToWideChar(CP_ACP, 0, "Cancel", -1, data, 50); - *data++ = 0; // no creation data + *data++ = 0; /* no creation data */ dlg->cy = y + 20; diff --git a/src/WIN/win_dynld.c b/src/WIN/win_dynld.c new file mode 100644 index 000000000..42b245fc5 --- /dev/null +++ b/src/WIN/win_dynld.c @@ -0,0 +1,64 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Try to load a support DLL. + * + * Version: @(#)win_dynld.c 1.0.2 2017/05/24 + * + * Author: Fred N. van Kempen, + * Copyright 2017 Fred N. van Kempen + */ +#include +#include +#include +#include +#include +#include +#include "plat_dynld.h" +#include "../ibm.h" + + +void * +dynld_module(const char *name, dllimp_t *table) +{ + HMODULE h; + dllimp_t *imp; + void *func; + /* char **foo; */ + + /* See if we can load the desired module. */ + if ((h = LoadLibrary(name)) == NULL) { + pclog("DynLd(\"%s\"): library not found!\n", name); + return(NULL); + } + + /* Now load the desired function pointers. */ + for (imp=table; imp->name!=NULL; imp++) { + func = GetProcAddress(h, imp->name); + if (func == NULL) { + pclog("DynLd(\"%s\"): function '%s' not found!\n", + name, imp->name); + CloseHandle(h); + return(NULL); + } + + /* To overcome typing issues.. */ + *(char **)imp->func = (char *)func; + } + + /* All good. */ + return((void *)h); +} + + +void +dynld_close(void *handle) +{ + if (handle != NULL) + FreeLibrary((HMODULE)handle); +} diff --git a/src/WIN/win_iodev.c b/src/WIN/win_iodev.c new file mode 100644 index 000000000..c2c2de9db --- /dev/null +++ b/src/WIN/win_iodev.c @@ -0,0 +1,197 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Windows IO device menu handler. + * + * Version: @(#)win_iodev.c 1.0.0 2017/05/30 + * + * Author: Miran Grca, + * Copyright 2016-2017 Miran Grca. + */ +#define UNICODE +#define _WIN32_WINNT 0x0501 +#define BITMAP WINDOWS_BITMAP +#include +#include +#undef BITMAP + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../ibm.h" +#include "../device.h" +#include "../cdrom.h" +#include "../cdrom_image.h" +#include "../cdrom_ioctl.h" +#include "../cdrom_null.h" +#include "../scsi_disk.h" +#include "plat_iodev.h" +#include "win.h" + + +void cdrom_eject(uint8_t id) +{ + int part; + + part = find_status_bar_part(SB_CDROM | id); + + if ((part == -1) || (sb_menu_handles == NULL)) + { + return; + } + + if (cdrom_drives[id].host_drive == 0) + { + /* Switch from empty to empty. Do nothing. */ + return; + } + cdrom_drives[id].handler->exit(id); + cdrom_close(id); + cdrom_null_open(id, 0); + if (cdrom_drives[id].bus_type) + { + /* Signal disc change to the emulated machine. */ + cdrom_insert(id); + } + CheckMenuItem(sb_menu_handles[part], IDM_CDROM_IMAGE | id, MF_UNCHECKED); + if ((cdrom_drives[id].host_drive >= 65) && (cdrom_drives[id].host_drive <= 90)) + { + CheckMenuItem(sb_menu_handles[part], IDM_CDROM_HOST_DRIVE | id | ((cdrom_drives[id].host_drive - 'A') << 3), MF_UNCHECKED); + } + cdrom_drives[id].prev_host_drive = cdrom_drives[id].host_drive; + cdrom_drives[id].host_drive=0; + CheckMenuItem(sb_menu_handles[part], IDM_CDROM_EMPTY | id, MF_CHECKED); + update_status_bar_icon_state(SB_CDROM | id, 1); + EnableMenuItem(sb_menu_handles[part], IDM_CDROM_RELOAD | id, MF_BYCOMMAND | MF_ENABLED); + update_tip(SB_CDROM | id); + saveconfig(); +} + +void cdrom_reload(uint8_t id) +{ + int part; + int new_cdrom_drive; + + part = find_status_bar_part(SB_CDROM | id); + + if ((part == -1) || (sb_menu_handles == NULL)) + { + return; + } + + if ((cdrom_drives[id].host_drive == cdrom_drives[id].prev_host_drive) || (cdrom_drives[id].prev_host_drive == 0) || (cdrom_drives[id].host_drive != 0)) + { + /* Switch from empty to empty. Do nothing. */ + return; + } + cdrom_close(id); + if (cdrom_drives[id].prev_host_drive == 200) + { + image_open(id, cdrom_image[id].image_path); + if (cdrom_drives[id].bus_type) + { + /* Signal disc change to the emulated machine. */ + cdrom_insert(id); + } + if (wcslen(cdrom_image[id].image_path) == 0) + { + CheckMenuItem(sb_menu_handles[part], IDM_CDROM_EMPTY | id, MF_CHECKED); + cdrom_drives[id].host_drive = 0; + CheckMenuItem(sb_menu_handles[part], IDM_CDROM_IMAGE | id, MF_UNCHECKED); + update_status_bar_icon_state(SB_CDROM | id, 1); + } + else + { + CheckMenuItem(sb_menu_handles[part], IDM_CDROM_EMPTY | id, MF_UNCHECKED); + cdrom_drives[id].host_drive = 200; + CheckMenuItem(sb_menu_handles[part], IDM_CDROM_IMAGE | id, MF_CHECKED); + update_status_bar_icon_state(SB_CDROM | id, 0); + } + } + else + { + new_cdrom_drive = cdrom_drives[id].prev_host_drive; + ioctl_open(id, new_cdrom_drive); + if (cdrom_drives[id].bus_type) + { + /* Signal disc change to the emulated machine. */ + cdrom_insert(id); + } + CheckMenuItem(sb_menu_handles[part], IDM_CDROM_EMPTY | id, MF_UNCHECKED); + cdrom_drives[id].host_drive = new_cdrom_drive; + CheckMenuItem(sb_menu_handles[part], IDM_CDROM_HOST_DRIVE | id | ((cdrom_drives[id].host_drive - 'A') << 3), MF_CHECKED); + update_status_bar_icon_state(SB_CDROM | id, 0); + } + EnableMenuItem(sb_menu_handles[part], IDM_CDROM_RELOAD | id, MF_BYCOMMAND | MF_GRAYED); + update_tip(SB_CDROM | id); + saveconfig(); +} + +void removable_disk_unload(uint8_t id) +{ + if (wcslen(hdc[id].fn) == 0) + { + /* Switch from empty to empty. Do nothing. */ + return; + } + scsi_unloadhd(hdc[id].scsi_id, hdc[id].scsi_lun, id); + scsi_disk_insert(id); +} + +void removable_disk_eject(uint8_t id) +{ + int part = 0; + + part = find_status_bar_part(SB_CDROM | id); + + if ((part == -1) || (sb_menu_handles == NULL)) + { + return; + } + + removable_disk_unload(id); + update_status_bar_icon_state(SB_RDISK | id, 1); + EnableMenuItem(sb_menu_handles[part], IDM_RDISK_EJECT | id, MF_BYCOMMAND | MF_GRAYED); + EnableMenuItem(sb_menu_handles[part], IDM_RDISK_RELOAD | id, MF_BYCOMMAND | MF_ENABLED); + EnableMenuItem(sb_menu_handles[part], IDM_RDISK_SEND_CHANGE | id, MF_BYCOMMAND | MF_GRAYED); + update_tip(SB_RDISK | id); + saveconfig(); +} + +void removable_disk_reload(uint8_t id) +{ + int part = 0; + + part = find_status_bar_part(SB_CDROM | id); + + if ((part == -1) || (sb_menu_handles == NULL)) + { + return; + } + + if (wcslen(hdc[id].fn) != 0) + { + /* Attempting to reload while an image is already loaded. Do nothing. */ + return; + } + scsi_reloadhd(id); + /* scsi_disk_insert(id); */ + update_status_bar_icon_state(SB_RDISK | id, wcslen(hdc[id].fn) ? 0 : 1); + EnableMenuItem(sb_menu_handles[part], IDM_RDISK_EJECT | id, MF_BYCOMMAND | (wcslen(hdc[id].fn) ? MF_ENABLED : MF_GRAYED)); + EnableMenuItem(sb_menu_handles[part], IDM_RDISK_RELOAD | id, MF_BYCOMMAND | MF_GRAYED); + EnableMenuItem(sb_menu_handles[part], IDM_RDISK_SEND_CHANGE | id, MF_BYCOMMAND | (wcslen(hdc[id].fn) ? MF_ENABLED : MF_GRAYED)); + update_tip(SB_RDISK | id); + saveconfig(); +} + diff --git a/src/win-joystick.cc b/src/WIN/win_joystick.cc similarity index 95% rename from src/win-joystick.cc rename to src/WIN/win_joystick.cc index 12c94e396..91c2138b0 100644 --- a/src/win-joystick.cc +++ b/src/WIN/win_joystick.cc @@ -1,15 +1,30 @@ -/* Copyright holders: Sarah Walker, Tenshi - see COPYING for more details -*/ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Joystick interface to host device. + * + * Version: @(#)win_joystick.cc 1.0.0 2017/05/30 + * + * Author: Sarah Walker, + * Miran Grca, + * Copyright 2008-2017 Sarah Walker. + * Copyright 2016-2017 Miran Grca. + */ + #define DIRECTINPUT_VERSION 0x0800 #include #include #include extern "C" { -#include "device.h" -#include "gameport.h" +#include "../device.h" +#include "../gameport.h" } -#include "plat-joystick.h" +#include "plat_joystick.h" #include "win.h" extern "C" int video_fullscreen; @@ -111,7 +126,6 @@ void joystick_init() DIPROPRANGE joy_axis_range; DIDEVICEINSTANCE device_instance; DIDEVCAPS devcaps; - int d; if (FAILED(lpdi->CreateDevice(joystick_guids[c], &lpdi_joystick_temp, NULL))) fatal("joystick_init : CreateDevice failed\n"); diff --git a/src/win-joystickconfig.c b/src/WIN/win_joystickconfig.c similarity index 89% rename from src/win-joystickconfig.c rename to src/WIN/win_joystickconfig.c index 8c75d303f..3cd5a0c68 100644 --- a/src/win-joystickconfig.c +++ b/src/WIN/win_joystickconfig.c @@ -6,19 +6,20 @@ #include #undef BITMAP -#include "ibm.h" -#include "config.h" -#include "device.h" -#include "gameport.h" -#include "plat-joystick.h" -#include "resources.h" +#include "../ibm.h" +#include "../config.h" +#include "../device.h" +#include "../gameport.h" +#include "plat_joystick.h" #include "win.h" + static int joystick_nr; static int joystick_config_type; #define AXIS_STRINGS_MAX 3 static char *axis_strings[AXIS_STRINGS_MAX] = {"X Axis", "Y Axis", "Z Axis"}; + static void rebuild_axis_button_selections(HWND hdlg) { int id = IDC_CONFIG_BASE + 2; @@ -151,14 +152,21 @@ static int get_pov(HWND hdlg, int id) static BOOL CALLBACK joystickconfig_dlgproc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) { + HWND h; + int c; + int id; + int joystick; + int nr_axes; + int nr_povs; + int mapping; + switch (message) { case WM_INITDIALOG: { - HWND h = GetDlgItem(hdlg, IDC_CONFIG_BASE); - int c, d; - int id = IDC_CONFIG_BASE + 2; - int joystick = joystick_state[joystick_nr].plat_joystick_nr; + h = GetDlgItem(hdlg, IDC_CONFIG_BASE); + id = IDC_CONFIG_BASE + 2; + joystick = joystick_state[joystick_nr].plat_joystick_nr; SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"None"); @@ -171,8 +179,8 @@ static BOOL CALLBACK joystickconfig_dlgproc(HWND hdlg, UINT message, WPARAM wPar if (joystick_state[joystick_nr].plat_joystick_nr) { - int nr_axes = plat_joystick_state[joystick-1].nr_axes; - int nr_povs = plat_joystick_state[joystick-1].nr_povs; + nr_axes = plat_joystick_state[joystick-1].nr_axes; + nr_povs = plat_joystick_state[joystick-1].nr_povs; for (c = 0; c < joystick_get_axis_count(joystick_config_type); c++) { int mapping = joystick_state[joystick_nr].axis_mapping[c]; @@ -194,8 +202,6 @@ static BOOL CALLBACK joystickconfig_dlgproc(HWND hdlg, UINT message, WPARAM wPar } for (c = 0; c < joystick_get_pov_count(joystick_config_type); c++) { - int mapping; - h = GetDlgItem(hdlg, id); mapping = joystick_state[joystick_nr].pov_mapping[c][0]; if (mapping & POV_X) @@ -229,10 +235,7 @@ static BOOL CALLBACK joystickconfig_dlgproc(HWND hdlg, UINT message, WPARAM wPar case IDOK: { - HWND h; - int joystick; - int c, d; - int id = IDC_CONFIG_BASE + 2; + id = IDC_CONFIG_BASE + 2; h = GetDlgItem(hdlg, IDC_CONFIG_BASE); joystick_state[joystick_nr].plat_joystick_nr = SendMessage(h, CB_GETCURSEL, 0, 0); @@ -272,7 +275,6 @@ static BOOL CALLBACK joystickconfig_dlgproc(HWND hdlg, UINT message, WPARAM wPar void joystickconfig_open(HWND hwnd, int joy_nr, int type) { -// device_config_t *config = device->config; uint16_t *data_block = malloc(16384); uint16_t *data; DLGTEMPLATE *dlg = (DLGTEMPLATE *)data_block; @@ -318,10 +320,10 @@ void joystickconfig_open(HWND hwnd, int joy_nr, int type) data = (uint16_t *)(item + 1); *data++ = 0xFFFF; - *data++ = 0x0085; // combo box class + *data++ = 0x0085; /* combo box class */ data += MultiByteToWideChar(CP_ACP, 0, "Device", -1, data, 256); - *data++ = 0; // no creation data + *data++ = 0; /* no creation data */ if (((unsigned long)data) & 2) data++; @@ -339,10 +341,10 @@ void joystickconfig_open(HWND hwnd, int joy_nr, int type) data = (uint16_t *)(item + 1); *data++ = 0xFFFF; - *data++ = 0x0082; // static class + *data++ = 0x0082; /* static class */ data += MultiByteToWideChar(CP_ACP, 0, "Device :", -1, data, 256); - *data++ = 0; // no creation data + *data++ = 0; /* no creation data */ if (((unsigned long)data) & 2) data++; @@ -365,10 +367,10 @@ void joystickconfig_open(HWND hwnd, int joy_nr, int type) data = (uint16_t *)(item + 1); *data++ = 0xFFFF; - *data++ = 0x0085; // combo box class + *data++ = 0x0085; /* combo box class */ data += MultiByteToWideChar(CP_ACP, 0, joystick_get_axis_name(type, c), -1, data, 256); - *data++ = 0; // no creation data + *data++ = 0; /* no creation data */ if (((unsigned long)data) & 2) data++; @@ -386,10 +388,10 @@ void joystickconfig_open(HWND hwnd, int joy_nr, int type) data = (uint16_t *)(item + 1); *data++ = 0xFFFF; - *data++ = 0x0082; // static class + *data++ = 0x0082; /* static class */ data += MultiByteToWideChar(CP_ACP, 0, joystick_get_axis_name(type, c), -1, data, 256); - *data++ = 0; // no creation data + *data++ = 0; /* no creation data */ if (((unsigned long)data) & 2) data++; @@ -412,10 +414,10 @@ void joystickconfig_open(HWND hwnd, int joy_nr, int type) data = (uint16_t *)(item + 1); *data++ = 0xFFFF; - *data++ = 0x0085; // combo box class + *data++ = 0x0085; /* combo box class */ data += MultiByteToWideChar(CP_ACP, 0, joystick_get_button_name(type, c), -1, data, 256); - *data++ = 0; // no creation data + *data++ = 0; /* no creation data */ if (((unsigned long)data) & 2) data++; @@ -433,10 +435,10 @@ void joystickconfig_open(HWND hwnd, int joy_nr, int type) data = (uint16_t *)(item + 1); *data++ = 0xFFFF; - *data++ = 0x0082; // static class + *data++ = 0x0082; /* static class */ data += MultiByteToWideChar(CP_ACP, 0, joystick_get_button_name(type, c), -1, data, 256); - *data++ = 0; // no creation data + *data++ = 0; /* no creation data */ if (((unsigned long)data) & 2) data++; @@ -461,14 +463,14 @@ void joystickconfig_open(HWND hwnd, int joy_nr, int type) data = (uint16_t *)(item + 1); *data++ = 0xFFFF; - *data++ = 0x0085; // combo box class + *data++ = 0x0085; /* combo box class */ if (c & 1) sprintf(s, "%s (Y axis)", joystick_get_pov_name(type, c/2)); else sprintf(s, "%s (X axis)", joystick_get_pov_name(type, c/2)); data += MultiByteToWideChar(CP_ACP, 0, s, -1, data, 256); - *data++ = 0; // no creation data + *data++ = 0; /* no creation data */ if (((unsigned long)data) & 2) data++; @@ -486,10 +488,10 @@ void joystickconfig_open(HWND hwnd, int joy_nr, int type) data = (uint16_t *)(item + 1); *data++ = 0xFFFF; - *data++ = 0x0082; // static class + *data++ = 0x0082; /* static class */ data += MultiByteToWideChar(CP_ACP, 0, s, -1, data, 256); - *data++ = 0; // no creation data + *data++ = 0; /* no creation data */ if (((unsigned long)data) & 2) data++; @@ -499,23 +501,20 @@ void joystickconfig_open(HWND hwnd, int joy_nr, int type) dlg->cdit = (id - IDC_CONFIG_BASE) + 2; -// DEFPUSHBUTTON "OK",IDOK,64,232,50,14, WS_TABSTOP -// PUSHBUTTON "Cancel",IDCANCEL,128,232,50,14, WS_TABSTOP - item = (DLGITEMTEMPLATE *)data; item->x = 20; item->y = y; item->cx = 50; item->cy = 14; - item->id = IDOK; // OK button identifier + item->id = IDOK; /* OK button identifier */ item->style = WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON; data = (uint16_t *)(item + 1); *data++ = 0xFFFF; - *data++ = 0x0080; // button class + *data++ = 0x0080; /* button class */ data += MultiByteToWideChar(CP_ACP, 0, "OK", -1, data, 50); - *data++ = 0; // no creation data + *data++ = 0; /* no creation data */ if (((unsigned long)data) & 2) data++; @@ -525,20 +524,18 @@ void joystickconfig_open(HWND hwnd, int joy_nr, int type) item->y = y; item->cx = 50; item->cy = 14; - item->id = IDCANCEL; // OK button identifier + item->id = IDCANCEL; /* OK button identifier */ item->style = WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON; data = (uint16_t *)(item + 1); *data++ = 0xFFFF; - *data++ = 0x0080; // button class + *data++ = 0x0080; /* button class */ data += MultiByteToWideChar(CP_ACP, 0, "Cancel", -1, data, 50); - *data++ = 0; // no creation data + *data++ = 0; /* no creation data */ dlg->cy = y + 20; - -// config_device = device; - + DialogBoxIndirect(hinstance, dlg, hwnd, joystickconfig_dlgproc); free(data_block); diff --git a/src/WIN/win_keyboard.c b/src/WIN/win_keyboard.c new file mode 100644 index 000000000..e7b847f7d --- /dev/null +++ b/src/WIN/win_keyboard.c @@ -0,0 +1,211 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Windows raw keyboard input handler. + * + * Version: @(#)win_d3d.cc 1.0.0 2017/05/30 + * + * Author: Miran Grca, + * Copyright 2016-2017 Miran Grca. + */ + +#define UNICODE +#define _WIN32_WINNT 0x0501 +#define BITMAP WINDOWS_BITMAP +#include +#include +#undef BITMAP + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../device.h" +#include "plat_keyboard.h" + +#include "win.h" + +#ifndef MAPVK_VK_TO_VSC +#define MAPVK_VK_TO_VSC 0 +#endif + +static uint16_t scancode_map[65536]; + +/* This is so we can disambiguate scan codes that would otherwise conflict and get + passed on incorrectly. */ +UINT16 convert_scan_code(UINT16 scan_code) +{ + switch (scan_code) + { + case 0xE001: + return 0xF001; + case 0xE002: + return 0xF002; + case 0xE0AA: + return 0xF003; + case 0xE005: + return 0xF005; + case 0xE006: + return 0xF006; + case 0xE007: + return 0xF007; + case 0xE071: + return 0xF008; + case 0xE072: + return 0xF009; + case 0xE07F: + return 0xF00A; + case 0xE0E1: + return 0xF00B; + case 0xE0EE: + return 0xF00C; + case 0xE0F1: + return 0xF00D; + case 0xE0FE: + return 0xF00E; + case 0xE0EF: + return 0xF00F; + + default: + return scan_code; + } +} + +void get_registry_key_map() +{ + WCHAR *keyName = L"SYSTEM\\CurrentControlSet\\Control\\Keyboard Layout"; + WCHAR *valueName = L"Scancode Map"; + unsigned char buf[32768]; + DWORD bufSize; + HKEY hKey; + int j; + UINT32 *bufEx2; + int scMapCount; + UINT16 *bufEx; + int scancode_unmapped; + int scancode_mapped; + + /* First, prepare the default scan code map list which is 1:1. + Remappings will be inserted directly into it. + 65536 bytes so scan codes fit in easily and it's easy to find what each maps too, + since each array element is a scan code and provides for E0, etc. ones too. */ + for (j = 0; j < 65536; j++) + scancode_map[j] = convert_scan_code(j); + + bufSize = 32768; + /* Get the scan code remappings from: + HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Keyboard Layout */ + if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, keyName, 0, 1, &hKey) == ERROR_SUCCESS) + { + if(RegQueryValueEx(hKey, valueName, NULL, NULL, buf, &bufSize) == ERROR_SUCCESS) + { + bufEx2 = (UINT32 *) buf; + scMapCount = bufEx2[2]; + if ((bufSize != 0) && (scMapCount != 0)) + { + bufEx = (UINT16 *) (buf + 12); + for (j = 0; j < scMapCount*2; j += 2) + { + /* Each scan code is 32-bit: 16 bits of remapped scan code, + and 16 bits of original scan code. */ + scancode_unmapped = bufEx[j + 1]; + scancode_mapped = bufEx[j]; + + scancode_mapped = convert_scan_code(scancode_mapped); + + /* Fixes scan code map logging. */ + scancode_map[scancode_unmapped] = scancode_mapped; + } + } + } + RegCloseKey(hKey); + } +} + +void process_raw_input(LPARAM lParam, int infocus) +{ + uint32_t ri_size = 0; + UINT size; + RAWINPUT *raw; + USHORT scancode; + + if (!infocus) + { + return; + } + + GetRawInputData((HRAWINPUT)lParam, RID_INPUT, NULL, &size, sizeof(RAWINPUTHEADER)); + + raw = malloc(size); + + if (raw == NULL) + { + return; + } + + /* Here we read the raw input data for the keyboard */ + ri_size = GetRawInputData((HRAWINPUT)(lParam), RID_INPUT, raw, &size, sizeof(RAWINPUTHEADER)); + + if(ri_size != size) + { + return; + } + + /* If the input is keyboard, we process it */ + if (raw->header.dwType == RIM_TYPEKEYBOARD) + { + RAWKEYBOARD rawKB = raw->data.keyboard; + scancode = rawKB.MakeCode; + + /* If it's not a scan code that starts with 0xE1 */ + if (!(rawKB.Flags & RI_KEY_E1)) + { + if (rawKB.Flags & RI_KEY_E0) + { + scancode |= (0xE0 << 8); + } + + /* Remap it according to the list from the Registry */ + scancode = scancode_map[scancode]; + + if ((scancode >> 8) == 0xF0) + { + scancode |= 0x100; /* Extended key code in disambiguated format */ + } + else if ((scancode >> 8) == 0xE0) + { + scancode |= 0x80; /* Normal extended key code */ + } + + /* If it's not 0 (therefore not 0xE1, 0xE2, etc), + then pass it on to the rawinputkey array */ + if (!(scancode & 0xf00)) + { + recv_key[scancode & 0x1ff] = !(rawKB.Flags & RI_KEY_BREAK); + } + } + else + { + if (rawKB.MakeCode == 0x1D) + { + scancode = 0xFF; + } + if (!(scancode & 0xf00)) + { + recv_key[scancode & 0x1ff] = !(rawKB.Flags & RI_KEY_BREAK); + } + } + } + + free(raw); +} \ No newline at end of file diff --git a/src/WIN/win_language.c b/src/WIN/win_language.c new file mode 100644 index 000000000..ed4e19159 --- /dev/null +++ b/src/WIN/win_language.c @@ -0,0 +1,267 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Windows localization core. + * + * Version: @(#)win_language.c 1.0.0 2017/05/30 + * + * Authors: Sarah Walker, + * Miran Grca, + * Copyright 2008-2017 Sarah Walker. + * Copyright 2016-2017 Miran Grca. + */ +#include +#define UNICODE +#define BITMAP WINDOWS_BITMAP +#include +#include +#include +#undef BITMAP + +#include + +#include "../ibm.h" +#include "../device.h" +#include "../ide.h" +#include "plat_ui.h" +#include "win.h" +#include "win_language.h" + + +LCID dwLanguage; + +uint32_t dwLangID, dwSubLangID; + +WCHAR lpResourceString[STRINGS_NUM][512]; + +char openfilestring[260]; +WCHAR wopenfilestring[260]; + +void win_language_set() +{ + SetThreadLocale(dwLanguage); +} + +void win_language_load_common_strings() +{ + int i = 0; + + for (i = 0; i < STRINGS_NUM; i++) + { + LoadString(hinstance, 2048 + i, lpResourceString[i], 512); + } +} + +LPTSTR win_language_get_settings_category(int i) +{ + return lpResourceString[17 + i]; +} + +void win_language_update() +{ + win_language_set(); + win_menu_update(); + win_language_load_common_strings(); +} + +void win_language_check() +{ + LCID dwLanguageNew = MAKELCID(dwLangID, dwSubLangID); + if (dwLanguageNew != dwLanguage) + { + dwLanguage = dwLanguageNew; + win_language_update(); + } +} + +LPTSTR win_language_get_string_from_id(int i) +{ + return lpResourceString[i - 2048]; +} + +wchar_t *plat_get_string_from_id(int i) +{ + return (wchar_t *) win_language_get_string_from_id(i); +} + +LPTSTR win_language_get_string_from_string(char *str) +{ + return lpResourceString[atoi(str) - 2048]; +} + +int msgbox_reset(HWND hwndParent) +{ + return MessageBox(hwndParent, lpResourceString[3], lpResourceString[0], MB_YESNOCANCEL | MB_ICONQUESTION); +} + +int msgbox_reset_yn(HWND hwndParent) +{ + return MessageBox(hwndParent, lpResourceString[3], lpResourceString[0], MB_YESNO | MB_ICONQUESTION); +} + +int msgbox_question(HWND hwndParent, int i) +{ + return MessageBox(hwndParent, win_language_get_string_from_id(i), lpResourceString[0], MB_YESNO | MB_ICONQUESTION); +} + +void msgbox_info(HWND hwndParent, int i) +{ + MessageBox(hwndParent, win_language_get_string_from_id(i), lpResourceString[0], MB_OK | MB_ICONINFORMATION); +} + +void msgbox_info_wstr(HWND hwndParent, WCHAR *wstr) +{ + MessageBox(hwndParent, wstr, lpResourceString[0], MB_OK | MB_ICONINFORMATION); +} + +void msgbox_error(HWND hwndParent, int i) +{ + MessageBox(hwndParent, win_language_get_string_from_id(i), lpResourceString[1], MB_OK | MB_ICONWARNING); +} + +void plat_msgbox_error(int i) +{ + msgbox_error(ghwnd, i); +} + +void msgbox_error_wstr(HWND hwndParent, WCHAR *wstr) +{ + MessageBox(hwndParent, wstr, lpResourceString[1], MB_OK | MB_ICONWARNING); +} + +void msgbox_critical(HWND hwndParent, int i) +{ + MessageBox(hwndParent, win_language_get_string_from_id(i), lpResourceString[2], MB_OK | MB_ICONERROR); +} + +void msgbox_fatal(HWND hwndParent, char *string) +{ + LPTSTR lptsTemp; + lptsTemp = (LPTSTR) malloc(512); + + mbstowcs(lptsTemp, string, strlen(string) + 1); + + MessageBox(hwndParent, lptsTemp, lpResourceString[2], MB_OK | MB_ICONERROR); + + free(lptsTemp); +} + +void plat_msgbox_fatal(char *string) +{ + msgbox_fatal(ghwnd, string); +} + +int file_dlg_w(HWND hwnd, WCHAR *f, WCHAR *fn, int save) +{ + OPENFILENAME ofn; /* common dialog box structure */ + BOOL r; + DWORD err; + + /* Initialize OPENFILENAME */ + ZeroMemory(&ofn, sizeof(ofn)); + ofn.lStructSize = sizeof(ofn); + ofn.hwndOwner = hwnd; + ofn.lpstrFile = wopenfilestring; + /* + Set lpstrFile[0] to '\0' so that GetOpenFileName does not + use the contents of szFile to initialize itself. + */ + memcpy(ofn.lpstrFile, fn, (wcslen(fn) << 1) + 2); + ofn.nMaxFile = 259; + ofn.lpstrFilter = f; + ofn.nFilterIndex = 1; + ofn.lpstrFileTitle = NULL; + ofn.nMaxFileTitle = 0; + ofn.lpstrInitialDir = NULL; + ofn.Flags = OFN_PATHMUSTEXIST; + if (!save) + { + ofn.Flags |= OFN_FILEMUSTEXIST; + } + + /* Display the Open dialog box. */ + + if (save) + { + pclog("GetSaveFileName - lpstrFile = %s\n", ofn.lpstrFile); + r = GetSaveFileName(&ofn); + } + else + { + pclog("GetOpenFileName - lpstrFile = %s\n", ofn.lpstrFile); + r = GetOpenFileName(&ofn); + } + if (r) + { + wcstombs(openfilestring, wopenfilestring, 520); + pclog("File dialog return true\n"); + return 0; + } + pclog("File dialog return false\n"); + err = CommDlgExtendedError(); + pclog("CommDlgExtendedError return %04X\n", err); + return 1; +} + +int file_dlg(HWND hwnd, WCHAR *f, char *fn, int save) +{ + WCHAR ufn[512]; + mbstowcs(ufn, fn, strlen(fn) + 1); + return file_dlg_w(hwnd, f, ufn, save); +} + +int file_dlg_w_st(HWND hwnd, int i, WCHAR *fn, int save) +{ + return file_dlg_w(hwnd, win_language_get_string_from_id(i), fn, save); +} + +int file_dlg_st(HWND hwnd, int i, char *fn, int save) +{ + return file_dlg(hwnd, win_language_get_string_from_id(i), fn, save); +} + +static int CALLBACK BrowseCallbackProc(HWND hwnd,UINT uMsg, LPARAM lParam, LPARAM lpData) +{ + if(uMsg == BFFM_INITIALIZED) + { + SendMessage(hwnd, BFFM_SETSELECTION, TRUE, lpData); + } + + return 0; +} + +WCHAR path[MAX_PATH]; + +wchar_t *BrowseFolder(wchar_t *saved_path, wchar_t *title) +{ + BROWSEINFO bi = { 0 }; + bi.lpszTitle = title; + bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_NEWDIALOGSTYLE; + bi.lpfn = BrowseCallbackProc; + bi.lParam = (LPARAM) saved_path; + + LPITEMIDLIST pidl = SHBrowseForFolder(&bi); + + if (pidl != 0) + { + /* Get the name of the folder and put it in path. */ + SHGetPathFromIDList(pidl, path); + + /* Free memory used. */ + IMalloc *imalloc = 0; + if (SUCCEEDED(SHGetMalloc(&imalloc))) + { + imalloc->lpVtbl->Free(imalloc, pidl); + imalloc->lpVtbl->Release(imalloc); + } + + return path; + } + + return L""; +} diff --git a/src/WIN/win_language.h b/src/WIN/win_language.h new file mode 100644 index 000000000..50b0105e3 --- /dev/null +++ b/src/WIN/win_language.h @@ -0,0 +1,53 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Windows localization core. + * + * Version: @(#)win_language.h 1.0.0 2017/05/30 + * + * Author: Sarah Walker, + * Miran Grca, + * Copyright 2008-2017 Sarah Walker. + * Copyright 2016-2017 Miran Grca. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +LCID dwLanguage; + +int msgbox_reset(HWND hwndParent); +int msgbox_reset_yn(HWND hwndParent); +int msgbox_question(HWND hwndParent, int i); +void msgbox_info(HWND hwndParent, int i); +void msgbox_info_wstr(HWND hwndParent, WCHAR *wstr); +void msgbox_error(HWND hwndParent, int i); +void msgbox_error_wstr(HWND hwndParent, WCHAR *wstr); +void msgbox_fatal(HWND hwndParent, char *string); +void msgbox_critical(HWND hwndParent, int i); + +int file_dlg_w(HWND hwnd, WCHAR *f, WCHAR *fn, int save); +int file_dlg(HWND hwnd, WCHAR *f, char *fn, int save); +int file_dlg_w_st(HWND hwnd, int i, WCHAR *fn, int save); +int file_dlg_st(HWND hwnd, int i, char *fn, int save); + +void win_language_load_common_strings(); +LPTSTR win_language_get_settings_category(int i); + +void win_language_update(); +void win_language_check(); + +LPTSTR win_language_get_string_from_id(int i); +LPTSTR win_language_get_string_from_string(char *str); + +wchar_t *BrowseFolder(wchar_t *saved_path, wchar_t *title); + +#ifdef __cplusplus +} +#endif diff --git a/src/WIN/win_midi.c b/src/WIN/win_midi.c new file mode 100644 index 000000000..4572c0b32 --- /dev/null +++ b/src/WIN/win_midi.c @@ -0,0 +1,125 @@ +#include +#include +#include "../ibm.h" +#include "../config.h" +#include "../SOUND/midi.h" +#include "plat_midi.h" + +int midi_id = 0; +static HMIDIOUT midi_out_device = NULL; + +HANDLE m_event; + +static uint8_t midi_rt_buf[1024]; +static uint8_t midi_cmd_buf[1024]; +static int midi_cmd_pos = 0; +static int midi_cmd_len = 0; +static uint8_t midi_status = 0; +static unsigned int midi_sysex_start = 0; +static unsigned int midi_sysex_delay = 0; + +void plat_midi_init() +{ + /* This is for compatibility with old configuration files. */ + midi_id = config_get_int("Sound", "midi_host_device", -1); + if (midi_id == -1) + { + midi_id = config_get_int(SYSTEM_MIDI_NAME, "midi", 0); + } + else + { + config_delete_var("Sound", "midi_host_device"); + config_set_int(SYSTEM_MIDI_NAME, "midi", midi_id); + } + + MMRESULT hr = MMSYSERR_NOERROR; + + memset(midi_rt_buf, 0, sizeof(midi_rt_buf)); + memset(midi_cmd_buf, 0, sizeof(midi_cmd_buf)); + + midi_cmd_pos = midi_cmd_len = 0; + midi_status = 0; + + midi_sysex_start = midi_sysex_delay = 0; + + m_event = CreateEvent(NULL, TRUE, TRUE, NULL); + + hr = midiOutOpen(&midi_out_device, midi_id, (DWORD) m_event, + 0, CALLBACK_EVENT); + if (hr != MMSYSERR_NOERROR) { + printf("midiOutOpen error - %08X\n",hr); + midi_id = 0; + hr = midiOutOpen(&midi_out_device, midi_id, (DWORD) m_event, + 0, CALLBACK_EVENT); + if (hr != MMSYSERR_NOERROR) { + printf("midiOutOpen error - %08X\n",hr); + return; + } + } + + midiOutReset(midi_out_device); +} + +void plat_midi_close() +{ + if (midi_out_device != NULL) + { + midiOutReset(midi_out_device); + midiOutClose(midi_out_device); + /* midi_out_device = NULL; */ + CloseHandle(m_event); + } +} + +int plat_midi_get_num_devs() +{ + return midiOutGetNumDevs(); +} +void plat_midi_get_dev_name(int num, char *s) +{ + MIDIOUTCAPS caps; + + midiOutGetDevCaps(num, &caps, sizeof(caps)); + strcpy(s, caps.szPname); +} + +void plat_midi_play_msg(uint8_t *msg) +{ + midiOutShortMsg(midi_out_device, *(uint32_t *) msg); +} + +MIDIHDR m_hdr; + +void plat_midi_play_sysex(uint8_t *sysex, unsigned int len) +{ + MMRESULT result; + + if (WaitForSingleObject(m_event, 2000) == WAIT_TIMEOUT) + { + pclog("Can't send MIDI message\n"); + return; + } + + midiOutUnprepareHeader(midi_out_device, &m_hdr, sizeof(m_hdr)); + + m_hdr.lpData = (char *) sysex; + m_hdr.dwBufferLength = len; + m_hdr.dwBytesRecorded = len; + m_hdr.dwUser = 0; + + result = midiOutPrepareHeader(midi_out_device, &m_hdr, sizeof(m_hdr)); + + if (result != MMSYSERR_NOERROR) return; + ResetEvent(m_event); + result = midiOutLongMsg(midi_out_device, &m_hdr, sizeof(m_hdr)); + if (result != MMSYSERR_NOERROR) + { + SetEvent(m_event); + return; + } +} + +int plat_midi_write(uint8_t val) +{ + return 0; +} diff --git a/src/win-mouse.cc b/src/WIN/win_mouse.cc similarity index 73% rename from src/win-mouse.cc rename to src/WIN/win_mouse.cc index 0eacdee78..0cb82df2f 100644 --- a/src/win-mouse.cc +++ b/src/WIN/win_mouse.cc @@ -1,28 +1,46 @@ -/* Copyright holders: Sarah Walker, Tenshi - see COPYING for more details -*/ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Mouse interface to host device. + * + * Version: @(#)win_mouse.cc 1.0.1 2017/06/21 + * + * Authors: Sarah Walker, + * Miran Grca, + * Copyright 2008-2017 Sarah Walker. + * Copyright 2016-2017 Miran Grca. + */ #define DIRECTINPUT_VERSION 0x0800 #include -#include "plat-mouse.h" +#include +#include "plat_mouse.h" #include "win.h" + extern "C" int video_fullscreen; extern "C" void fatal(const char *format, ...); extern "C" void pclog(const char *format, ...); -extern "C" void mouse_init(); -extern "C" void mouse_close(); -extern "C" void mouse_poll_host(); +extern "C" void mouse_init(void); +extern "C" void mouse_close(void); +extern "C" void mouse_poll_host(void); extern "C" void mouse_get_mickeys(int *x, int *y, int *z); + static LPDIRECTINPUT8 lpdi; static LPDIRECTINPUTDEVICE8 lpdi_mouse = NULL; static DIMOUSESTATE mousestate; static int mouse_x = 0, mouse_y = 0, mouse_z = 0; int mouse_buttons = 0; -void mouse_init() + +void mouse_init(void) { atexit(mouse_close); @@ -36,7 +54,8 @@ void mouse_init() fatal("mouse_init : SetDataFormat failed\n"); } -void mouse_close() + +void mouse_close(void) { if (lpdi_mouse) { @@ -45,7 +64,8 @@ void mouse_close() } } -void mouse_poll_host() + +void mouse_poll_host(void) { if (FAILED(lpdi_mouse->GetDeviceState(sizeof(DIMOUSESTATE), (LPVOID)&mousestate))) { @@ -66,6 +86,7 @@ void mouse_poll_host() mouse_x = mouse_y = mouse_buttons = 0; } + void mouse_get_mickeys(int *x, int *y, int *z) { *x = mouse_x; diff --git a/src/WIN/win_opendir.c b/src/WIN/win_opendir.c new file mode 100644 index 000000000..00347a365 --- /dev/null +++ b/src/WIN/win_opendir.c @@ -0,0 +1,213 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Implementation POSIX OpenDir(3) and friends for Win32 API. + * + * Based on old original code @(#)dir_win32.c 1.2.0 2007/04/19 + * + * Version: @(#)win_opendir.c 1.0.1 2017/05/17 + * + * Author: Fred N. van Kempen, + * Copyright 1998-2007 MicroWalt Corporation + * Copyright 2017 Fred N. van Kempen + */ +#define UNICODE +#include +#include +#include +#include +#include +#include +#include "../ibm.h" +#include "plat_dir.h" + + +#ifdef UNICODE +# define SUFFIX L"\\*" +# define FINDATA struct _wfinddata_t +# define FINDFIRST _wfindfirst +# define FINDNEXT _wfindnext +#else +# define SUFFIX "\\*" +# define FINDATA struct _finddata_t +# define FINDFIRST _findfirst +# define FINDNEXT _findnext +#endif + + +/* Open a directory. */ +DIR * +#ifdef UNICODE +opendirw(const wchar_t *name) +#else +opendir(const char *name) +#endif +{ + DIR *p; + + /* Create a new control structure. */ + p = (DIR *) malloc(sizeof(DIR)); + if (p == NULL) + return(NULL); + memset(p, 0x00, sizeof(DIR)); + p->flags = (DIR_F_LOWER | DIR_F_SANE); + p->offset = 0; + p->sts = 0; + + /* Create a work area. */ + p->dta = (char *)malloc(sizeof(FINDATA)); + if (p->dta == NULL) { + free(p); + return(NULL); + } + memset(p->dta, 0x00, sizeof(struct _finddata_t)); + + /* Add search filespec. */ +#ifdef UNICODE + wcscpy(p->dir, name); + wcscat(p->dir, SUFFIX); +#else + strcpy(p->dir, name); + strcat(p->dir, SUFFIX); +#endif + + /* Special case: flag if we are in the root directory. */ +#ifdef UNICODE + if (wcslen(p->dir) == 3) +#else + if (strlen(p->dir) == 3) +#endif + p->flags |= DIR_F_ISROOT; + + /* Start the searching by doing a FindFirst. */ + p->handle = FINDFIRST(p->dir, (FINDATA *)p->dta); + if (p->handle < 0L) { + free(p->dta); + free(p); + return(NULL); + } + + /* All OK. */ + return(p); +} + + +/* Close an open directory. */ +int +closedir(DIR *p) +{ + if (p == NULL) + return(0); + + _findclose(p->handle); + + if (p->dta != NULL) + free(p->dta); + free(p); + + return(0); +} + + +/* + * Read the next entry from a directory. + * Note that the DOS (FAT), Windows (FAT, FAT32) and Windows NTFS + * file systems do not have a root directory containing the UNIX- + * standard "." and ".." entries. Many applications do assume + * this anyway, so we simply fake these entries. + */ +struct direct * +readdir(DIR *p) +{ + FINDATA *ffp; + + if (p == NULL || p->sts == 1) + return(NULL); + + /* Format structure with current data. */ + ffp = (FINDATA *)p->dta; + p->dent.d_ino = 1L; + p->dent.d_off = p->offset++; + switch(p->offset) { + case 1: /* . */ +#ifdef UNICODE + wcsncpy(p->dent.d_name, L".", MAXNAMLEN+1); +#else + strncpy(p->dent.d_name, ".", MAXNAMLEN+1); +#endif + p->dent.d_reclen = 1; + break; + + case 2: /* .. */ +#ifdef UNICODE + wcsncpy(p->dent.d_name, L"..", MAXNAMLEN+1); +#else + strncpy(p->dent.d_name, "..", MAXNAMLEN+1); +#endif + p->dent.d_reclen = 2; + break; + + default: /* regular entry. */ +#ifdef UNICODE + wcsncpy(p->dent.d_name, ffp->name, MAXNAMLEN+1); +#else + strncpy(p->dent.d_name, ffp->name, MAXNAMLEN+1); +#endif + p->dent.d_reclen = (char) wcslen(p->dent.d_name); + } + + /* Read next entry. */ + p->sts = 0; + + /* Fake the "." and ".." entries here.. */ + if ((p->flags & DIR_F_ISROOT) && (p->offset <= 2)) + return(&(p->dent)); + + /* Get the next entry if we did not fake the above. */ + if (FINDNEXT(p->handle, ffp) < 0) + p->sts = 1; + + return(&(p->dent)); +} + + +/* Report current position within the directory. */ +long +telldir(DIR *p) +{ + return(p->offset); +} + + +void +seekdir(DIR *p, long newpos) +{ + short pos; + + /* First off, rewind to start of directory. */ + p->handle = FINDFIRST(p->dir, (FINDATA *)p->dta); + if (p->handle < 0L) { + p->sts = 1; + return; + } + p->offset = 0; + p->sts = 0; + + /* If we are rewinding, that's all... */ + if (newpos == 0L) return; + + /* Nope.. read entries until we hit the right spot. */ + pos = (short) newpos; + while (p->offset != pos) { + p->offset++; + if (FINDNEXT(p->handle, (FINDATA *)p->dta) < 0) { + p->sts = 1; + return; + } + } +} diff --git a/src/WIN/win_serial.c b/src/WIN/win_serial.c new file mode 100644 index 000000000..e44cf36d0 --- /dev/null +++ b/src/WIN/win_serial.c @@ -0,0 +1,571 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Implementation of host serial port services for Win32. + * + * This code is based on a universal serial port driver for + * Windows and UNIX systems, with support for FTDI and Prolific + * USB ports. Support for these has been removed. + * + * Version: @(#)win_serial.c 1.0.3 2017/06/04 + * + * Author: Fred N. van Kempen, + * Copyright 2017 Fred N. van Kempen. + */ +#include +#include +#include +#include "plat_thread.h" +#define BHTTY_C +#include "plat_serial.h" + + +extern void pclog(char *__fmt, ...); + + +/* Handle the receiving of data from the host port. */ +static void +bhtty_reader(void *arg) +{ + BHTTY *pp = (BHTTY *)arg; + unsigned char b; + DWORD n; + + pclog("%s: thread started\n", pp->name); + + /* As long as the channel is open.. */ + while (pp->tid != NULL) { + /* Post a READ on the device. */ + n = 0; + if (ReadFile(pp->handle, &b, (DWORD)1, &n, &pp->rov) == FALSE) { + n = GetLastError(); + if (n != ERROR_IO_PENDING) { + /* Not good, we got an error. */ + pclog("%s: I/O error %d in read!\n", pp->name, n); + break; + } + + /* The read is pending, wait for it.. */ + if (GetOverlappedResult(pp->handle, &pp->rov, &n, TRUE) == FALSE) { + n = GetLastError(); + pclog("%s: I/O error %d in read!\n", pp->name, n); + break; + } + } + +pclog("%s: got %d bytes of data\n", pp->name, n); + if (n == 1) { + /* We got data, update stuff. */ + if (pp->icnt < sizeof(pp->buff)) { +pclog("%s: queued byte %02x (%d)\n", pp->name, b, pp->icnt+1); + pp->buff[pp->ihead++] = b; + pp->ihead &= (sizeof(pp->buff)-1); + pp->icnt++; + + /* Do a callback to let them know. */ + if (pp->rd_done != NULL) + pp->rd_done(pp->rd_arg, n); + } else { + pclog("%s: RX buffer overrun!\n", pp->name); + } + } + } + + /* Error or done, clean up. */ + pp->tid = NULL; + pclog("%s: thread stopped.\n", pp->name); +} + + +/* Set the state of a port. */ +int +bhtty_sstate(BHTTY *pp, void *arg) +{ + /* Make sure we can do this. */ + if (arg == NULL) { + pclog("%s: invalid argument\n", pp->name); + return(-1); + } + + if (SetCommState(pp->handle, (DCB *)arg) == FALSE) { + /* Mark an error. */ + pclog("%s: set state: %d\n", pp->name, GetLastError()); + return(-1); + } + + return(0); +} + + +/* Fetch the state of a port. */ +int +bhtty_gstate(BHTTY *pp, void *arg) +{ + /* Make sure we can do this. */ + if (arg == NULL) { + pclog("%s: invalid argument\n", pp->name); + return(-1); + } + + if (GetCommState(pp->handle, (DCB *)arg) == FALSE) { + /* Mark an error. */ + pclog("%s: get state: %d\n", pp->name, GetLastError()); + return(-1); + } + + return(0); +} + + +/* Enable or disable RTS/CTS mode (hardware handshaking.) */ +int +bhtty_crtscts(BHTTY *pp, char yesno) +{ + /* Get the current mode. */ + if (bhtty_gstate(pp, &pp->dcb) < 0) return(-1); + + switch(yesno) { + case 0: /* disable CRTSCTS */ + pp->dcb.fOutxDsrFlow = 0; /* disable DSR/DCD mode */ + pp->dcb.fDsrSensitivity = 0; + + pp->dcb.fOutxCtsFlow = 0; /* disable RTS/CTS mode */ + + pp->dcb.fTXContinueOnXoff = 0; /* disable XON/XOFF mode */ + pp->dcb.fOutX = 0; + pp->dcb.fInX = 0; + break; + + case 1: /* enable CRTSCTS */ + pp->dcb.fOutxDsrFlow = 0; /* disable DSR/DCD mode */ + pp->dcb.fDsrSensitivity = 0; + + pp->dcb.fOutxCtsFlow = 1; /* enable RTS/CTS mode */ + + pp->dcb.fTXContinueOnXoff = 0; /* disable XON/XOFF mode */ + pp->dcb.fOutX = 0; + pp->dcb.fInX = 0; + break; + + default: + pclog("%s: invalid parameter '%d'!\n", pp->name, yesno); + return(-1); + } + + /* Set new mode. */ + if (bhtty_sstate(pp, &pp->dcb) < 0) return(-1); + + return(0); +} + + +/* Set the port parameters. */ +int +bhtty_params(BHTTY *pp, char dbit, char par, char sbit) +{ + /* Get the current mode. */ + if (bhtty_gstate(pp, &pp->dcb) < 0) return(-1); + + /* Set the desired word length. */ + switch((int)dbit) { + case -1: /* no change */ + break; + + case 5: /* FTDI doesnt like these */ + case 6: + case 9: + break; + + case 7: + case 8: + pp->dcb.ByteSize = dbit; + break; + + default: + pclog("%s: invalid parameter '%d'!\n", pp->name, dbit); + return(-1); + } + + /* Set the type of parity encoding. */ + switch((int)par) { + case -1: /* no change */ + case ' ': + break; + + case 0: + case 'N': + pp->dcb.fParity = FALSE; + pp->dcb.Parity = NOPARITY; + break; + + case 1: + case 'O': + pp->dcb.fParity = TRUE; + pp->dcb.Parity = ODDPARITY; + break; + + case 2: + case 'E': + pp->dcb.fParity = TRUE; + pp->dcb.Parity = EVENPARITY; + break; + + case 3: + case 'M': + case 4: + case 'S': + break; + + default: + pclog("%s: invalid parameter '%c'!\n", pp->name, par); + return(-1); + } + + /* Set the number of stop bits. */ + switch((int)sbit) { + case -1: /* no change */ + break; + + case 1: + pp->dcb.StopBits = ONESTOPBIT; + break; + + case 2: + pp->dcb.StopBits = TWOSTOPBITS; + break; + + default: + pclog("%s: invalid parameter '%d'!\n", pp->name, sbit); + return(-1); + } + + /* Set new mode. */ + if (bhtty_sstate(pp, &pp->dcb) < 0) return(-1); + + return(0); +} + + +/* Put a port in transparent ("raw") state. */ +void +bhtty_raw(BHTTY *pp, void *arg) +{ + DCB *dcb = (DCB *)arg; + + /* Make sure we can do this. */ + if (arg == NULL) { + pclog("%s: invalid parameter\n", pp->name); + return; + } + + /* Enable BINARY transparent mode. */ + dcb->fBinary = 1; + dcb->fErrorChar = 0; /* disable Error Replacement */ + dcb->fNull = 0; /* disable NUL stripping */ + + /* Disable the DTR and RTS lines. */ + dcb->fDtrControl = DTR_CONTROL_DISABLE; /* DTR line */ + dcb->fRtsControl = RTS_CONTROL_DISABLE; /* RTS line */ + + /* Disable DSR/DCD handshaking. */ + dcb->fOutxDsrFlow = 0; /* DSR handshaking */ + dcb->fDsrSensitivity = 0; /* DSR Sensitivity */ + + /* Disable RTS/CTS handshaking. */ + dcb->fOutxCtsFlow = 0; /* CTS handshaking */ + + /* Disable XON/XOFF handshaking. */ + dcb->fTXContinueOnXoff = 0; /* continue TX after Xoff */ + dcb->fOutX = 0; /* enable output X-ON/X-OFF */ + dcb->fInX = 0; /* enable input X-ON/X-OFF */ + dcb->XonChar = 0x11; /* ASCII XON */ + dcb->XoffChar = 0x13; /* ASCII XOFF */ + dcb->XonLim = 100; + dcb->XoffLim = 100; + + dcb->fParity = FALSE; + dcb->Parity = NOPARITY; + dcb->StopBits = ONESTOPBIT; + dcb->BaudRate = CBR_1200; +} + + +/* Set the port speed. */ +int +bhtty_speed(BHTTY *pp, long speed) +{ + /* Get the current mode and speed. */ + if (bhtty_gstate(pp, &pp->dcb) < 0) return(-1); + + /* + * Set speed. + * + * This is not entirely correct, we should use a table + * with DCB_xxx speed values here, but we removed that + * and just hardcode the speed value into DCB. --FvK + */ + pp->dcb.BaudRate = speed; + + /* Set new speed. */ + if (bhtty_sstate(pp, &pp->dcb) < 0) return(-1); + + return(0); +} + + +/* Clean up and flush. */ +int +bhtty_flush(BHTTY *pp) +{ + DWORD dwErrs; + COMSTAT cs; + + /* First, clear any errors. */ + (void)ClearCommError(pp->handle, &dwErrs, &cs); + + /* Now flush all buffers. */ + if (PurgeComm(pp->handle, + (PURGE_RXABORT | PURGE_TXABORT | \ + PURGE_RXCLEAR | PURGE_TXCLEAR)) == FALSE) { + pclog("%s: flush: %d\n", pp->name, GetLastError()); + return(-1); + } + + /* Re-clear any errors. */ + if (ClearCommError(pp->handle, &dwErrs, &cs) == FALSE) { + pclog("%s: clear errors: %d\n", pp->name, GetLastError()); + return(-1); + } + + return(0); +} + + +/* Close an open serial port. */ +void +bhtty_close(BHTTY *pp) +{ + /* If the polling thread is running, stop it. */ + (void)bhtty_active(pp, 0); + + /* Close the event handles. */ + if (pp->rov.hEvent != INVALID_HANDLE_VALUE) + CloseHandle(pp->rov.hEvent); + if (pp->wov.hEvent != INVALID_HANDLE_VALUE) + CloseHandle(pp->wov.hEvent); + + if (pp->handle != INVALID_HANDLE_VALUE) { + pclog("%s: closing host port\n", pp->name); + + /* Restore the previous port state, if any. */ + (void)bhtty_sstate(pp, &pp->odcb); + + /* Close the port. */ + CloseHandle(pp->handle); + pp->handle = INVALID_HANDLE_VALUE; + } + + /* Release the control block. */ + free(pp); +} + + +/* Open a host serial port for I/O. */ +BHTTY * +bhtty_open(char *port, int tmo) +{ + char temp[64]; + COMMTIMEOUTS to; + COMMCONFIG conf; + BHTTY *pp; + DWORD d; + + /* First things first... create a control block. */ + if ((pp = (BHTTY *)malloc(sizeof(BHTTY))) == NULL) { + pclog("%s: out of memory!\n", port); + return(NULL); + } + memset(pp, 0x00, sizeof(BHTTY)); + strncpy(pp->name, port, sizeof(pp->name)-1); + + /* Try a regular Win32 serial port. */ + sprintf(temp, "\\\\.\\%s", pp->name); + if ((pp->handle = CreateFile(temp, + (GENERIC_READ|GENERIC_WRITE), + 0, + NULL, + OPEN_EXISTING, + FILE_FLAG_OVERLAPPED, + 0)) == INVALID_HANDLE_VALUE) { + pclog("%s: open port: %d\n", pp->name, GetLastError()); + free(pp); + return(NULL); + } + + /* Create event handles. */ + pp->rov.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + pp->wov.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + + /* Set up buffer size of the port. */ + if (SetupComm(pp->handle, 32768L, 32768L) == FALSE) { + /* This fails on FTDI-based devices. */ + pclog("%s: set buffers: %d\n", pp->name, GetLastError()); +#if 0 + CloseHandle(pp->handle); + free(pp); + return(NULL); +#endif + } + + /* Grab default config for the driver and set it. */ + d = sizeof(COMMCONFIG); + memset(&conf, 0x00, d); + conf.dwSize = d; + if (GetDefaultCommConfig(temp, &conf, &d) == TRUE) { + /* Change config here... */ + + /* Set new configuration. */ + if (SetCommConfig(pp->handle, &conf, d) == FALSE) { + /* This fails on FTDI-based devices. */ + pclog("%s: set configuration: %d\n", pp->name, GetLastError()); +#if 0 + CloseHandle(pp->handle); + free(pp); + return(NULL); +#endif + } + } + pclog("%s: host port '%s' open\n", pp->name, temp); + + /* + * We now have an open port. To allow for clean exit + * of the application, we first retrieve the port's + * current settings, and save these for later. + */ + if (bhtty_gstate(pp, &pp->odcb) < 0) { + (void)bhtty_close(pp); + return(NULL); + } + memcpy(&pp->dcb, &pp->odcb, sizeof(DCB)); + + /* Force the port to BINARY mode. */ + bhtty_raw(pp, &pp->dcb); + + /* Set new state of this port. */ + if (bhtty_sstate(pp, &pp->dcb) < 0) { + (void)bhtty_close(pp); + return(NULL); + } + + /* Just to make sure.. disable RTS/CTS mode. */ + (void)bhtty_crtscts(pp, 0); + + /* Set new timeout values. */ + if (GetCommTimeouts(pp->handle, &to) == FALSE) { + pclog("%s: error %d while getting current TO\n", + pp->name, GetLastError()); + (void)bhtty_close(pp); + return(NULL); + } + if (tmo < 0) { + /* No timeout, immediate return. */ + to.ReadIntervalTimeout = MAXDWORD; + to.ReadTotalTimeoutMultiplier = 0; + to.ReadTotalTimeoutConstant = 0; + } else if (tmo == 0) { + /* No timeout, wait for data. */ + memset(&to, 0x00, sizeof(to)); + } else { + /* Timeout specified. */ + to.ReadIntervalTimeout = MAXDWORD; + to.ReadTotalTimeoutMultiplier = MAXDWORD; + to.ReadTotalTimeoutConstant = tmo; + } + if (SetCommTimeouts(pp->handle, &to) == FALSE) { + pclog("%s: error %d while setting TO\n", pp->name, GetLastError()); + (void)bhtty_close(pp); + return(NULL); + } + + /* Clear all errors and flush all buffers. */ + if (bhtty_flush(pp) < 0) { + (void)bhtty_close(pp); + return(NULL); + } + + return(pp); +} + + +/* Activate the I/O for this port. */ +int +bhtty_active(BHTTY *pp, int flg) +{ + if (flg) { + pclog("%s: starting thread..\n", pp->name); + pp->tid = thread_create(bhtty_reader, pp); + } else { + if (pp->tid != NULL) { + pclog("%s: stopping thread..\n", pp->name); + thread_kill(pp->tid); + pp->tid = NULL; + } + } + + return(0); +} + + +/* Try to write data to an open port. */ +int +bhtty_write(BHTTY *pp, unsigned char val) +{ + DWORD n = 0; + +pclog("%s: writing byte %02x\n", pp->name, val); + if (WriteFile(pp->handle, &val, 1, &n, &pp->wov) == FALSE) { + n = GetLastError(); + if (n != ERROR_IO_PENDING) { + /* Not good, we got an error. */ + pclog("%s: I/O error %d in write!\n", pp->name, n); + return(-1); + } + + /* The write is pending, wait for it.. */ + if (GetOverlappedResult(pp->handle, &pp->wov, &n, TRUE) == FALSE) { + n = GetLastError(); + pclog("%s: I/O error %d in write!\n", pp->name, n); + return(-1); + } + } + + return((int)n); +} + + +/* + * Try to read data from an open port. + * + * For now, we will use one byte per call. Eventually, + * we should go back to loading a buffer full of data, + * just to speed things up a bit. --FvK + */ +int +bhtty_read(BHTTY *pp, unsigned char *bufp, int max) +{ + if (pp->icnt == 0) return(0); + + while (max-- > 0) { + *bufp++ = pp->buff[pp->itail++]; +pclog("%s: dequeued byte %02x (%d)\n", pp->name, *(bufp-1), pp->icnt); + pp->itail &= (sizeof(pp->buff)-1); + if (--pp->icnt == 0) break; + } + + return(max); +} diff --git a/src/WIN/win_settings.c b/src/WIN/win_settings.c new file mode 100644 index 000000000..a6f504a92 --- /dev/null +++ b/src/WIN/win_settings.c @@ -0,0 +1,4369 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Windows 86Box Settings dialog handler. + * + * Version: @(#)win_settings.c 1.0.6 2017/06/21 + * + * Author: Miran Grca, + * Copyright 2016-2017 Miran Grca. + */ +#define UNICODE +#define BITMAP WINDOWS_BITMAP +#include +#include +#undef BITMAP + +#include +#include +#include "../ibm.h" +#include "../mem.h" +#include "../cpu/cpu.h" +#include "../nvr.h" +#include "../device.h" +#include "../model.h" +#include "../cdrom.h" +#include "../disc.h" +#include "../fdd.h" +#include "../hdd.h" +#include "../ide.h" +#include "../scsi.h" +#include "../scsi_buslogic.h" +#include "../network/network.h" +#include "../sound/midi.h" +#include "../sound/sound.h" +#include "../sound/snd_dbopl.h" +#include "../sound/snd_mpu401.h" +#include "../video/video.h" +#include "../video/vid_voodoo.h" +#include "../gameport.h" +#include "../mouse.h" +#include "plat_midi.h" +#include "win.h" +#include "win_language.h" + + +/* Machine category */ +static int temp_model, temp_cpu_m, temp_cpu, temp_wait_states, temp_mem_size, temp_dynarec, temp_fpu, temp_sync; +static wchar_t temp_nvr_path[520]; + +/* Video category */ +static int temp_gfxcard, temp_video_speed, temp_voodoo; + +/* Input devices category */ +static int temp_mouse, temp_joystick; + +/* Sound category */ +static int temp_sound_card, temp_midi_device, temp_mpu401, temp_SSI2001, temp_GAMEBLASTER, temp_GUS, temp_opl3_type; +static int temp_float; + +/* Network category */ +static int temp_net_type, temp_net_card; +static char temp_pcap_dev[520]; + +/* Peripherals category */ +static int temp_scsi_card, hdc_ignore, temp_ide_ter, temp_ide_ter_irq, temp_ide_qua, temp_ide_qua_irq; +static int temp_serial[2], temp_lpt, temp_bugger; + +static char temp_hdc_name[16]; + +/* Hard disks category */ +static hard_disk_t temp_hdc[HDC_NUM]; + +/* Removable devices category */ +static int temp_fdd_types[FDD_NUM]; +static int temp_fdd_turbo[FDD_NUM]; +static cdrom_drive_t temp_cdrom_drives[CDROM_NUM]; + +static HWND hwndParentDialog, hwndChildDialog; + +int hdd_controller_current; + +static int displayed_category = 0; + +extern int is486; +static int romstolist[ROM_MAX], listtomodel[ROM_MAX], romstomodel[ROM_MAX], modeltolist[ROM_MAX]; +static int settings_sound_to_list[20], settings_list_to_sound[20]; +static int settings_midi_to_list[20], settings_list_to_midi[20]; +static int settings_mouse_to_list[20], settings_list_to_mouse[20]; +static int settings_scsi_to_list[20], settings_list_to_scsi[20]; +static int settings_network_to_list[20], settings_list_to_network[20]; +static char *hdd_names[16]; + + +/* This does the initial read of global variables into the temporary ones. */ +static void win_settings_init(void) +{ + int i = 0; + + /* Machine category */ + temp_model = model; + temp_cpu_m = cpu_manufacturer; + temp_wait_states = cpu_waitstates; + temp_cpu = cpu; + temp_mem_size = mem_size; + memset(temp_nvr_path, 0, sizeof(temp_nvr_path)); + wcscpy(temp_nvr_path, nvr_path); + temp_dynarec = cpu_use_dynarec; + temp_fpu = enable_external_fpu; + temp_sync = enable_sync; + + /* Video category */ + temp_gfxcard = gfxcard; + temp_video_speed = video_speed; + temp_voodoo = voodoo_enabled; + + /* Input devices category */ + temp_mouse = mouse_type; + temp_joystick = joystick_type; + + /* Sound category */ + temp_sound_card = sound_card_current; + temp_midi_device = midi_device_current; + temp_mpu401 = mpu401_standalone_enable; + temp_SSI2001 = SSI2001; + temp_GAMEBLASTER = GAMEBLASTER; + temp_GUS = GUS; + temp_opl3_type = opl3_type; + temp_float = sound_is_float; + + /* Network category */ + temp_net_type = network_type; + memset(temp_pcap_dev, '\0', sizeof(temp_pcap_dev)); + strcpy(temp_pcap_dev, network_pcap); + temp_net_card = network_card; + + /* Peripherals category */ + temp_scsi_card = scsi_card_current; + strncpy(temp_hdc_name, hdd_controller_name, sizeof(temp_hdc_name) - 1); + temp_ide_ter = ide_enable[2]; + temp_ide_ter_irq = ide_irq[2]; + temp_ide_qua = ide_enable[3]; + temp_ide_qua_irq = ide_irq[3]; + temp_serial[0] = serial_enabled[0]; + temp_serial[1] = serial_enabled[1]; + temp_lpt = lpt_enabled; + temp_bugger = bugger_enabled; + + /* Hard disks category */ + memcpy(temp_hdc, hdc, HDC_NUM * sizeof(hard_disk_t)); + + /* Removable devices category */ + for (i = 0; i < FDD_NUM; i++) + { + temp_fdd_types[i] = fdd_get_type(i); + temp_fdd_turbo[i] = fdd_get_turbo(i); + } + memcpy(temp_cdrom_drives, cdrom_drives, CDROM_NUM * sizeof(cdrom_drive_t)); +} + + +/* This returns 1 if any variable has changed, 0 if not. */ +static int win_settings_changed(void) +{ + int i = 0; + int j = 0; + + /* Machine category */ + i = i || (model != temp_model); + i = i || (cpu_manufacturer != temp_cpu_m); + i = i || (cpu_waitstates != temp_wait_states); + i = i || (cpu != temp_cpu); + i = i || (mem_size != temp_mem_size); + i = i || wcscmp(temp_nvr_path, nvr_path); + i = i || (temp_dynarec != cpu_use_dynarec); + i = i || (temp_fpu != enable_external_fpu); + i = i || (temp_sync != enable_sync); + + /* Video category */ + i = i || (gfxcard != temp_gfxcard); + i = i || (video_speed != temp_video_speed); + i = i || (voodoo_enabled != temp_voodoo); + + /* Input devices category */ + i = i || (mouse_type != temp_mouse); + i = i || (joystick_type != temp_joystick); + + /* Sound category */ + i = i || (sound_card_current != temp_sound_card); + i = i || (midi_device_current != temp_midi_device); + i = i || (mpu401_standalone_enable != temp_mpu401); + i = i || (SSI2001 != temp_SSI2001); + i = i || (GAMEBLASTER != temp_GAMEBLASTER); + i = i || (GUS != temp_GUS); + i = i || (opl3_type != temp_opl3_type); + i = i || (sound_is_float != temp_float); + + /* Network category */ + i = i || (network_type != temp_net_type); + i = i || strcmp(temp_pcap_dev, network_pcap); + i = i || (network_card != temp_net_card); + + /* Peripherals category */ + i = i || (scsi_card_current != temp_scsi_card); + i = i || strncmp(temp_hdc_name, hdd_controller_name, sizeof(temp_hdc_name) - 1); + i = i || (temp_ide_ter != ide_enable[2]); + i = i || (temp_ide_ter_irq != ide_irq[2]); + i = i || (temp_ide_qua != ide_enable[3]); + i = i || (temp_ide_qua_irq != ide_irq[3]); + i = i || (temp_serial[0] != serial_enabled[0]); + i = i || (temp_serial[1] != serial_enabled[1]); + i = i || (temp_lpt != lpt_enabled); + i = i || (temp_bugger != bugger_enabled); + + /* Hard disks category */ + i = i || memcmp(hdc, temp_hdc, HDC_NUM * sizeof(hard_disk_t)); + + /* Removable devices category */ + for (j = 0; j < FDD_NUM; j++) + { + i = i || (temp_fdd_types[j] != fdd_get_type(j)); + i = i || (temp_fdd_turbo[j] != fdd_get_turbo(j)); + } + i = i || memcmp(cdrom_drives, temp_cdrom_drives, CDROM_NUM * sizeof(cdrom_drive_t)); + + return i; +} + + +static int settings_msgbox_reset(void) +{ + int i = 0; + int changed = 0; + + changed = win_settings_changed(); + + if (changed) + { + i = msgbox_reset(hwndParentDialog); + + if (i == IDNO) + { + return 1; + } + else if (i == IDCANCEL) + { + return 0; + } + else + { + return 2; + } + } + else +{ + return 1; + } +} + + +/* This saves the settings back to the global variables. */ +static void win_settings_save(void) +{ + int i = 0; + + resetpchard_close(); + + /* Machine category */ + model = temp_model; + romset = model_getromset(); + cpu_manufacturer = temp_cpu_m; + cpu_waitstates = temp_wait_states; + cpu = temp_cpu; + mem_size = temp_mem_size; + memset(nvr_path, 0, sizeof(nvr_path)); + wcscpy(nvr_path, temp_nvr_path); + cpu_use_dynarec = temp_dynarec; + enable_external_fpu = temp_fpu; + enable_sync = temp_sync; + + /* Video category */ + gfxcard = temp_gfxcard; + video_speed = temp_video_speed; + voodoo_enabled = temp_voodoo; + + /* Input devices category */ + mouse_type = temp_mouse; + joystick_type = temp_joystick; + + /* Sound category */ + sound_card_current = temp_sound_card; + midi_device_current = temp_midi_device; + mpu401_standalone_enable = temp_mpu401; + SSI2001 = temp_SSI2001; + GAMEBLASTER = temp_GAMEBLASTER; + GUS = temp_GUS; + opl3_type = temp_opl3_type; + sound_is_float = temp_float; + + /* Network category */ + network_type = temp_net_type; + memset(network_pcap, '\0', sizeof(network_pcap)); + strcpy(network_pcap, temp_pcap_dev); + network_card = temp_net_card; + + /* Peripherals category */ + scsi_card_current = temp_scsi_card; + strncpy(hdd_controller_name, temp_hdc_name, sizeof(temp_hdc_name) - 1); + ide_enable[2] = temp_ide_ter; + ide_irq[2] = temp_ide_ter_irq; + ide_enable[3] = temp_ide_qua; + ide_irq[3] = temp_ide_qua_irq; + serial_enabled[0] = temp_serial[0]; + serial_enabled[1] = temp_serial[1]; + lpt_enabled = temp_lpt; + bugger_enabled = temp_bugger; + + /* Hard disks category */ + memcpy(hdc, temp_hdc, HDC_NUM * sizeof(hard_disk_t)); + + /* Removable devices category */ + for (i = 0; i < FDD_NUM; i++) + { + fdd_set_type(i, temp_fdd_types[i]); + fdd_set_turbo(i, temp_fdd_turbo[i]); + } + memcpy(cdrom_drives, temp_cdrom_drives, CDROM_NUM * sizeof(cdrom_drive_t)); + + mem_resize(); + loadbios(); + + update_status_bar_panes(hwndStatus); + + sound_realloc_buffers(); + + resetpchard_init(); + + cpu_set(); + + cpu_update_waitstates(); + + saveconfig(); + + speedchanged(); + + if (joystick_type != 7) gameport_update_joystick_type(); +} + + +static void win_settings_machine_recalc_cpu(HWND hdlg) +{ + HWND h; + int temp_romset = 0; + int cpu_flags; + int cpu_type; + + temp_romset = model_getromset_ex(temp_model); + + h = GetDlgItem(hdlg, IDC_COMBO_WS); + cpu_type = models[romstomodel[temp_romset]].cpu[temp_cpu_m].cpus[temp_cpu].cpu_type; + if ((cpu_type >= CPU_286) && (cpu_type <= CPU_386DX)) + { + EnableWindow(h, TRUE); + } + else + { + EnableWindow(h, FALSE); + } + + h=GetDlgItem(hdlg, IDC_CHECK_DYNAREC); + cpu_flags = models[romstomodel[temp_romset]].cpu[temp_cpu_m].cpus[temp_cpu].cpu_flags; + if (!(cpu_flags & CPU_SUPPORTS_DYNAREC) && (cpu_flags & CPU_REQUIRES_DYNAREC)) + { + fatal("Attempting to select a CPU that requires the recompiler and does not support it at the same time\n"); + } + if (!(cpu_flags & CPU_SUPPORTS_DYNAREC) || (cpu_flags & CPU_REQUIRES_DYNAREC)) + { + if (!(cpu_flags & CPU_SUPPORTS_DYNAREC)) + { + temp_dynarec = 0; + } + if (cpu_flags & CPU_REQUIRES_DYNAREC) + { + temp_dynarec = 1; + } + SendMessage(h, BM_SETCHECK, temp_dynarec, 0); + EnableWindow(h, FALSE); + } + else + { + EnableWindow(h, TRUE); + } + + h = GetDlgItem(hdlg, IDC_CHECK_FPU); + cpu_type = models[romstomodel[temp_romset]].cpu[temp_cpu_m].cpus[temp_cpu].cpu_type; + if ((cpu_type < CPU_i486DX) && (cpu_type >= CPU_286)) + { + EnableWindow(h, TRUE); + } + else if (cpu_type < CPU_286) + { + temp_fpu = 0; + EnableWindow(h, FALSE); + } + else + { + temp_fpu = 1; + EnableWindow(h, FALSE); + } + SendMessage(h, BM_SETCHECK, temp_fpu, 0); +} + + +static void win_settings_machine_recalc_cpu_m(HWND hdlg) +{ + HWND h; + int c = 0; + int temp_romset = 0; + LPTSTR lptsTemp; + char *stransi; + + temp_romset = model_getromset_ex(temp_model); + lptsTemp = (LPTSTR) malloc(512); + + h = GetDlgItem(hdlg, IDC_COMBO_CPU); + SendMessage(h, CB_RESETCONTENT, 0, 0); + c = 0; + while (models[romstomodel[temp_romset]].cpu[temp_cpu_m].cpus[c].cpu_type != -1) + { + stransi = models[romstomodel[temp_romset]].cpu[temp_cpu_m].cpus[c].name; + mbstowcs(lptsTemp, stransi, strlen(stransi) + 1); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)lptsTemp); + c++; + } + EnableWindow(h, TRUE); + if (temp_cpu >= c) + { + temp_cpu = (c - 1); + } + SendMessage(h, CB_SETCURSEL, temp_cpu, 0); + + win_settings_machine_recalc_cpu(hdlg); + + free(lptsTemp); +} + + +static void win_settings_machine_recalc_model(HWND hdlg) +{ + HWND h; + int c = 0; + int temp_romset = 0; + LPTSTR lptsTemp; + char *stransi; + UDACCEL accel; + + temp_romset = model_getromset_ex(temp_model); + lptsTemp = (LPTSTR) malloc(512); + + h = GetDlgItem(hdlg, IDC_CONFIGURE_MACHINE); + if (model_getdevice(temp_model)) + { + EnableWindow(h, TRUE); + } + else + { + EnableWindow(h, FALSE); + } + + h = GetDlgItem(hdlg, IDC_COMBO_CPU_TYPE); + SendMessage(h, CB_RESETCONTENT, 0, 0); + c = 0; + while (models[romstomodel[temp_romset]].cpu[c].cpus != NULL && c < 4) + { + stransi = models[romstomodel[temp_romset]].cpu[c].name; + mbstowcs(lptsTemp, stransi, strlen(stransi) + 1); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)lptsTemp); + c++; + } + EnableWindow(h, TRUE); + if (temp_cpu_m >= c) + { + temp_cpu_m = (c - 1); + } + SendMessage(h, CB_SETCURSEL, temp_cpu_m, 0); + if (c == 1) + { + EnableWindow(h, FALSE); + } + else + { + EnableWindow(h, TRUE); + } + + win_settings_machine_recalc_cpu_m(hdlg); + + h = GetDlgItem(hdlg, IDC_MEMSPIN); + SendMessage(h, UDM_SETRANGE, 0, (models[romstomodel[temp_romset]].min_ram << 16) | models[romstomodel[temp_romset]].max_ram); + accel.nSec = 0; + accel.nInc = models[romstomodel[temp_romset]].ram_granularity; + SendMessage(h, UDM_SETACCEL, 1, (LPARAM)&accel); + if (!(models[romstomodel[temp_romset]].flags & MODEL_AT) || (models[romstomodel[temp_romset]].ram_granularity >= 128)) + { + SendMessage(h, UDM_SETPOS, 0, temp_mem_size); + h = GetDlgItem(hdlg, IDC_TEXT_MB); + SendMessage(h, WM_SETTEXT, 0, (LPARAM) win_language_get_string_from_id(IDS_2094)); + } + else + { + SendMessage(h, UDM_SETPOS, 0, temp_mem_size / 1024); + h = GetDlgItem(hdlg, IDC_TEXT_MB); + SendMessage(h, WM_SETTEXT, 0, (LPARAM) win_language_get_string_from_id(IDS_2087)); + } + + free(lptsTemp); +} + + +static BOOL CALLBACK win_settings_machine_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + HWND h; + int c = 0; + int d = 0; + LPTSTR lptsTemp; + char *stransi; + wchar_t *p; + + switch (message) + { + case WM_INITDIALOG: + lptsTemp = (LPTSTR) malloc(512); + + h = GetDlgItem(hdlg, IDC_COMBO_MACHINE); + for (c = 0; c < ROM_MAX; c++) + { + romstolist[c] = 0; + } + c = d = 0; + while (models[c].id != -1) + { + if (romspresent[models[c].id]) + { + stransi = models[c].name; + mbstowcs(lptsTemp, stransi, strlen(stransi) + 1); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) lptsTemp); + modeltolist[c] = d; + listtomodel[d] = c; + romstolist[models[c].id] = d; + romstomodel[models[c].id] = c; + d++; + } + c++; + } + SendMessage(h, CB_SETCURSEL, modeltolist[temp_model], 0); + + h = GetDlgItem(hdlg, IDC_COMBO_WS); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) win_language_get_string_from_id(IDS_2131)); + + for (c = 0; c < 8; c++) + { + wsprintf(lptsTemp, win_language_get_string_from_id(2132), c); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) lptsTemp); + } + + SendMessage(h, CB_SETCURSEL, temp_wait_states, 0); + + h=GetDlgItem(hdlg, IDC_CHECK_DYNAREC); + SendMessage(h, BM_SETCHECK, temp_dynarec, 0); + + h = GetDlgItem(hdlg, IDC_MEMSPIN); + SendMessage(h, UDM_SETBUDDY, (WPARAM)GetDlgItem(hdlg, IDC_MEMTEXT), 0); + + h=GetDlgItem(hdlg, IDC_CHECK_SYNC); + SendMessage(h, BM_SETCHECK, temp_sync, 0); + + win_settings_machine_recalc_model(hdlg); + + h = GetDlgItem(hdlg, IDC_EDIT_NVR_PATH); + SendMessage(h, WM_SETTEXT, 0, (LPARAM) temp_nvr_path); + + free(lptsTemp); + + return TRUE; + + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case IDC_COMBO_MACHINE: + if (HIWORD(wParam) == CBN_SELCHANGE) + { + h = GetDlgItem(hdlg, IDC_COMBO_MACHINE); + temp_model = listtomodel[SendMessage(h,CB_GETCURSEL,0,0)]; + + win_settings_machine_recalc_model(hdlg); + } + break; + case IDC_COMBO_CPU_TYPE: + if (HIWORD(wParam) == CBN_SELCHANGE) + { + h = GetDlgItem(hdlg, IDC_COMBO_CPU_TYPE); + temp_cpu_m = SendMessage(h, CB_GETCURSEL, 0, 0); + + temp_cpu = 0; + win_settings_machine_recalc_cpu_m(hdlg); + } + break; + case IDC_COMBO_CPU: + if (HIWORD(wParam) == CBN_SELCHANGE) + { + h = GetDlgItem(hdlg, IDC_COMBO_CPU); + temp_cpu = SendMessage(h, CB_GETCURSEL, 0, 0); + + win_settings_machine_recalc_cpu(hdlg); + } + break; + case IDC_CONFIGURE_MACHINE: + h = GetDlgItem(hdlg, IDC_COMBO_MACHINE); + temp_model = listtomodel[SendMessage(h, CB_GETCURSEL, 0, 0)]; + + deviceconfig_open(hdlg, (void *)model_getdevice(temp_model)); + break; + case IDC_BUTTON_NVR_PATH: + p = BrowseFolder(temp_nvr_path, win_language_get_string_from_id(IDS_2225)); + if (wcscmp(p, L"")) + { + memset(temp_nvr_path, 0, sizeof(temp_nvr_path)); + wcscpy(temp_nvr_path, p); + if (temp_nvr_path[wcslen(temp_nvr_path) - 1] == L'/') + { + temp_nvr_path[wcslen(temp_nvr_path) - 1] = L'\\'; + } + else if (temp_nvr_path[wcslen(temp_nvr_path) - 1] != L'\\') + { + temp_nvr_path[wcslen(temp_nvr_path)] = L'\\'; + } + h = GetDlgItem(hdlg, IDC_EDIT_NVR_PATH); + SendMessage(h, WM_SETTEXT, 0, (LPARAM) temp_nvr_path); + } + break; + } + + return FALSE; + + case WM_SAVESETTINGS: + lptsTemp = (LPTSTR) malloc(512); + stransi = (char *) malloc(512); + + h=GetDlgItem(hdlg, IDC_CHECK_DYNAREC); + temp_dynarec = SendMessage(h, BM_GETCHECK, 0, 0); + + h=GetDlgItem(hdlg, IDC_CHECK_SYNC); + temp_sync = SendMessage(h, BM_GETCHECK, 0, 0); + + h=GetDlgItem(hdlg, IDC_CHECK_FPU); + temp_fpu = SendMessage(h, BM_GETCHECK, 0, 0); + + h = GetDlgItem(hdlg, IDC_COMBO_WS); + temp_wait_states = SendMessage(h, CB_GETCURSEL, 0, 0); + + h = GetDlgItem(hdlg, IDC_MEMTEXT); + SendMessage(h, WM_GETTEXT, 255, (LPARAM) lptsTemp); + wcstombs(stransi, lptsTemp, (wcslen(lptsTemp) * 2) + 2); + sscanf(stransi, "%i", &temp_mem_size); + temp_mem_size &= ~(models[temp_model].ram_granularity - 1); + if (temp_mem_size < models[temp_model].min_ram) + { + temp_mem_size = models[temp_model].min_ram; + } + else if (temp_mem_size > models[temp_model].max_ram) + { + temp_mem_size = models[temp_model].max_ram; + } + if ((models[temp_model].flags & MODEL_AT) && (models[temp_model].ram_granularity < 128)) + { + temp_mem_size *= 1024; + } + + free(stransi); + free(lptsTemp); + + default: + return FALSE; + } + + return FALSE; +} + + +static void recalc_vid_list(HWND hdlg) +{ + HWND h = GetDlgItem(hdlg, IDC_COMBO_VIDEO); + int c = 0, d = 0; + int found_card = 0; + WCHAR szText[512]; + + SendMessage(h, CB_RESETCONTENT, 0, 0); + SendMessage(h, CB_SETCURSEL, 0, 0); + + while (1) + { + char *s = video_card_getname(c); + + if (!s[0]) + break; + + if (video_card_available(c) && gfx_present[video_new_to_old(c)] && + ((models[temp_model].flags & MODEL_PCI) || !(video_card_getdevice(c)->flags & DEVICE_PCI))) + { + mbstowcs(szText, s, strlen(s) + 1); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) szText); + if (video_new_to_old(c) == temp_gfxcard) + { + + SendMessage(h, CB_SETCURSEL, d, 0); + found_card = 1; + } + + d++; + } + + c++; + } + if (!found_card) + SendMessage(h, CB_SETCURSEL, 0, 0); + EnableWindow(h, models[temp_model].fixed_gfxcard ? FALSE : TRUE); + + h = GetDlgItem(hdlg, IDC_CHECK_VOODOO); + EnableWindow(h, (models[model].flags & MODEL_PCI) ? TRUE : FALSE); + + h = GetDlgItem(hdlg, IDC_BUTTON_VOODOO); + EnableWindow(h, ((models[model].flags & MODEL_PCI) && temp_voodoo) ? TRUE : FALSE); +} + + +static BOOL CALLBACK win_settings_video_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + HWND h; + LPTSTR lptsTemp; + char *stransi; + int gfx = 0; + + switch (message) + { + case WM_INITDIALOG: + lptsTemp = (LPTSTR) malloc(512); + stransi = (char *) malloc(512); + + recalc_vid_list(hdlg); + + h = GetDlgItem(hdlg, IDC_COMBO_VIDEO_SPEED); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) win_language_get_string_from_id(IDS_2133)); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) win_language_get_string_from_id(IDS_2134)); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) win_language_get_string_from_id(IDS_2135)); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) win_language_get_string_from_id(IDS_2136)); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) win_language_get_string_from_id(IDS_2137)); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) win_language_get_string_from_id(IDS_2138)); + SendMessage(h, CB_SETCURSEL, temp_video_speed, 0); + + h=GetDlgItem(hdlg, IDC_CHECK_VOODOO); + SendMessage(h, BM_SETCHECK, temp_voodoo, 0); + + h = GetDlgItem(hdlg, IDC_COMBO_VIDEO); + SendMessage(h, CB_GETLBTEXT, SendMessage(h, CB_GETCURSEL, 0, 0), (LPARAM) lptsTemp); + wcstombs(stransi, lptsTemp, (wcslen(lptsTemp) * 2) + 2); + gfx = video_card_getid(stransi); + + h = GetDlgItem(hdlg, IDC_CONFIGURE_VID); + if (video_card_has_config(gfx)) + { + EnableWindow(h, TRUE); + } + else + { + EnableWindow(h, FALSE); + } + + free(stransi); + free(lptsTemp); + + return TRUE; + + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case IDC_COMBO_VIDEO: + lptsTemp = (LPTSTR) malloc(512); + stransi = (char *) malloc(512); + + h = GetDlgItem(hdlg, IDC_COMBO_VIDEO); + SendMessage(h, CB_GETLBTEXT, SendMessage(h, CB_GETCURSEL, 0, 0), (LPARAM) lptsTemp); + wcstombs(stransi, lptsTemp, (wcslen(lptsTemp) * 2) + 2); + gfx = video_card_getid(stransi); + temp_gfxcard = video_new_to_old(gfx); + + h = GetDlgItem(hdlg, IDC_CONFIGURE_VID); + if (video_card_has_config(gfx)) + { + EnableWindow(h, TRUE); + } + else + { + EnableWindow(h, FALSE); + } + + free(stransi); + free(lptsTemp); + break; + + case IDC_CHECK_VOODOO: + h = GetDlgItem(hdlg, IDC_CHECK_VOODOO); + temp_voodoo = SendMessage(h, BM_GETCHECK, 0, 0); + + h = GetDlgItem(hdlg, IDC_BUTTON_VOODOO); + EnableWindow(h, temp_voodoo ? TRUE : FALSE); + break; + + case IDC_BUTTON_VOODOO: + deviceconfig_open(hdlg, (void *)&voodoo_device); + break; + + case IDC_CONFIGURE_VID: + lptsTemp = (LPTSTR) malloc(512); + stransi = (char *) malloc(512); + + h = GetDlgItem(hdlg, IDC_COMBO_VIDEO); + SendMessage(h, CB_GETLBTEXT, SendMessage(h, CB_GETCURSEL, 0, 0), (LPARAM) lptsTemp); + wcstombs(stransi, lptsTemp, (wcslen(lptsTemp) * 2) + 2); + deviceconfig_open(hdlg, (void *)video_card_getdevice(video_card_getid(stransi))); + + free(stransi); + free(lptsTemp); + break; + } + return FALSE; + + case WM_SAVESETTINGS: + lptsTemp = (LPTSTR) malloc(512); + stransi = (char *) malloc(512); + + h = GetDlgItem(hdlg, IDC_COMBO_VIDEO); + SendMessage(h, CB_GETLBTEXT, SendMessage(h, CB_GETCURSEL, 0, 0), (LPARAM) lptsTemp); + wcstombs(stransi, lptsTemp, (wcslen(lptsTemp) * 2) + 2); + temp_gfxcard = video_new_to_old(video_card_getid(stransi)); + + h = GetDlgItem(hdlg, IDC_COMBO_VIDEO_SPEED); + temp_video_speed = SendMessage(h, CB_GETCURSEL, 0, 0); + + h = GetDlgItem(hdlg, IDC_CHECK_VOODOO); + temp_voodoo = SendMessage(h, BM_GETCHECK, 0, 0); + + free(stransi); + free(lptsTemp); + + default: + return FALSE; + } + return FALSE; +} + + +static int mouse_valid(int type, int model) +{ + type &= MOUSE_TYPE_MASK; + + if ((type == MOUSE_TYPE_PS2) && + !(models[model].flags & MODEL_PS2)) return(0); + + if ((type == MOUSE_TYPE_AMSTRAD) && + !(models[model].flags & MODEL_AMSTRAD)) return(0); + + if ((type == MOUSE_TYPE_OLIM24) && + !(models[model].flags & MODEL_OLIM24)) return(0); + + return(1); +} + + +static BOOL CALLBACK win_settings_input_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + HWND h; + int c = 0; + int d = 0; + int type; + int str_id = 0; + + switch (message) + { + case WM_INITDIALOG: + h = GetDlgItem(hdlg, IDC_COMBO_MOUSE); + c = d = 0; + for (c = 0; c < mouse_get_ndev(); c++) + { + type = mouse_get_type(c); + + settings_mouse_to_list[c] = d; + + if (mouse_valid(type, temp_model)) + { + switch(c) + { + case MOUSE_TYPE_NONE: + str_id = IDS_2151; + break; + case MOUSE_TYPE_SERIAL: + default: + str_id = IDS_2139; + break; + case MOUSE_TYPE_PS2: + str_id = IDS_2141; + break; + case MOUSE_TYPE_PS2_MS: + str_id = IDS_2142; + break; + case MOUSE_TYPE_BUS: + str_id = IDS_2143; + break; + case MOUSE_TYPE_AMSTRAD: + str_id = IDS_2162; + break; + case MOUSE_TYPE_OLIM24: + str_id = IDS_2177; + break; + case MOUSE_TYPE_MSYSTEMS: + str_id = IDS_2140; + break; + case MOUSE_TYPE_LOGITECH: + str_id = IDS_2224; + break; + case MOUSE_TYPE_GENIUS: + str_id = IDS_2161; + break; + } + + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) win_language_get_string_from_id(str_id)); + + settings_list_to_mouse[d] = c; + d++; + } + } + + SendMessage(h, CB_SETCURSEL, settings_mouse_to_list[temp_mouse], 0); + + h = GetDlgItem(hdlg, IDC_COMBO_JOYSTICK); + c = 0; + while (joystick_get_name(c)) + { + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) win_language_get_string_from_id(2144 + c)); + c++; + } + EnableWindow(h, TRUE); + SendMessage(h, CB_SETCURSEL, temp_joystick, 0); + + h = GetDlgItem(hdlg, IDC_JOY1); + EnableWindow(h, (joystick_get_max_joysticks(temp_joystick) >= 1) ? TRUE : FALSE); + h = GetDlgItem(hdlg, IDC_JOY2); + EnableWindow(h, (joystick_get_max_joysticks(temp_joystick) >= 2) ? TRUE : FALSE); + h = GetDlgItem(hdlg, IDC_JOY3); + EnableWindow(h, (joystick_get_max_joysticks(temp_joystick) >= 3) ? TRUE : FALSE); + h = GetDlgItem(hdlg, IDC_JOY4); + EnableWindow(h, (joystick_get_max_joysticks(temp_joystick) >= 4) ? TRUE : FALSE); + + return TRUE; + + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case IDC_COMBO_JOYSTICK: + if (HIWORD(wParam) == CBN_SELCHANGE) + { + h = GetDlgItem(hdlg, IDC_COMBO_JOYSTICK); + temp_joystick = SendMessage(h, CB_GETCURSEL, 0, 0); + + h = GetDlgItem(hdlg, IDC_JOY1); + EnableWindow(h, (joystick_get_max_joysticks(temp_joystick) >= 1) ? TRUE : FALSE); + h = GetDlgItem(hdlg, IDC_JOY2); + EnableWindow(h, (joystick_get_max_joysticks(temp_joystick) >= 2) ? TRUE : FALSE); + h = GetDlgItem(hdlg, IDC_JOY3); + EnableWindow(h, (joystick_get_max_joysticks(temp_joystick) >= 3) ? TRUE : FALSE); + h = GetDlgItem(hdlg, IDC_JOY4); + EnableWindow(h, (joystick_get_max_joysticks(temp_joystick) >= 4) ? TRUE : FALSE); + } + break; + + case IDC_JOY1: + h = GetDlgItem(hdlg, IDC_COMBO_JOY); + temp_joystick = SendMessage(h, CB_GETCURSEL, 0, 0); + joystickconfig_open(hdlg, 0, temp_joystick); + break; + + case IDC_JOY2: + h = GetDlgItem(hdlg, IDC_COMBO_JOY); + temp_joystick = SendMessage(h, CB_GETCURSEL, 0, 0); + joystickconfig_open(hdlg, 1, temp_joystick); + break; + + case IDC_JOY3: + h = GetDlgItem(hdlg, IDC_COMBO_JOY); + temp_joystick = SendMessage(h, CB_GETCURSEL, 0, 0); + joystickconfig_open(hdlg, 2, temp_joystick); + break; + + case IDC_JOY4: + h = GetDlgItem(hdlg, IDC_COMBO_JOY); + temp_joystick = SendMessage(h, CB_GETCURSEL, 0, 0); + joystickconfig_open(hdlg, 3, temp_joystick); + break; + } + return FALSE; + + case WM_SAVESETTINGS: + h = GetDlgItem(hdlg, IDC_COMBO_MOUSE); + temp_mouse = settings_list_to_mouse[SendMessage(h, CB_GETCURSEL, 0, 0)]; + + h = GetDlgItem(hdlg, IDC_COMBO_JOYSTICK); + temp_joystick = SendMessage(h, CB_GETCURSEL, 0, 0); + + default: + return FALSE; + } + return FALSE; +} + + +static void recalc_hdd_list(HWND hdlg, int model, int use_selected_hdd) +{ + HWND h; + + char *s; + int valid = 0; + char old_name[16]; + int c, d; + + LPTSTR lptsTemp; + + lptsTemp = (LPTSTR) malloc(512); + + h = GetDlgItem(hdlg, IDC_COMBO_HDC); + + if (models[temp_model].flags & MODEL_HAS_IDE) + { + hdc_ignore = 1; + + SendMessage(h, CB_RESETCONTENT, 0, 0); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) win_language_get_string_from_id(IDS_2154)); + EnableWindow(h, FALSE); + SendMessage(h, CB_SETCURSEL, 0, 0); + } + else + { + hdc_ignore = 0; + + valid = 0; + + if (use_selected_hdd) + { + c = SendMessage(h, CB_GETCURSEL, 0, 0); + + if (c != -1 && hdd_names[c]) + { + strncpy(old_name, hdd_names[c], sizeof(old_name) - 1); + } + else + { + strcpy(old_name, "none"); + } + } + else + { + strncpy(old_name, temp_hdc_name, sizeof(old_name) - 1); + } + + SendMessage(h, CB_RESETCONTENT, 0, 0); + c = d = 0; + while (1) + { + s = hdd_controller_get_name(c); + if (s[0] == 0) + { + break; + } + if ((hdd_controller_get_flags(c) & DEVICE_AT) && !(models[model].flags & MODEL_AT)) + { + c++; + continue; + } + if ((hdd_controller_get_flags(c) & DEVICE_PS2) && !(models[model].flags & MODEL_PS2_HDD)) + { + c++; + continue; + } + if ((hdd_controller_get_flags(c) & DEVICE_MCA) && !(models[model].flags & MODEL_MCA)) + { + c++; + continue; + } + if (!hdd_controller_available(c)) + { + c++; + continue; + } + if (c < 2) + { + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) win_language_get_string_from_id(2152 + c)); + } + else + { + mbstowcs(lptsTemp, s, strlen(s) + 1); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) lptsTemp); + } + hdd_names[d] = hdd_controller_get_internal_name(c); + if (!strcmp(old_name, hdd_names[d])) + { + SendMessage(h, CB_SETCURSEL, d, 0); + valid = 1; + } + c++; + d++; + } + + if (!valid) + { + SendMessage(h, CB_SETCURSEL, 0, 0); + } + + EnableWindow(h, TRUE); + } + + free(lptsTemp); +} + + +int valid_ide_irqs[11] = { 2, 3, 4, 5, 7, 9, 10, 11, 12, 14, 15 }; + + +int find_irq_in_array(int irq, int def) +{ + int i = 0; + + for (i = 0; i < 11; i++) + { + if (valid_ide_irqs[i] == irq) + { + return i + 1; + } + } + + return 7 + def; +} + + +int mpu401_present(void) +{ + char *n; + + n = sound_card_get_internal_name(temp_sound_card); + if (n != NULL) + { + if (!strcmp(n, "sb16") || !strcmp(n, "sbawe32")) + { + return 1; + } + } + + return temp_mpu401 ? 1 : 0; +} + +int mpu401_standalone_allow(void) +{ + char *n, *md; + + n = sound_card_get_internal_name(temp_sound_card); + md = midi_device_get_internal_name(temp_midi_device); + if (n != NULL) + { + if (!strcmp(n, "sb16") || !strcmp(n, "sbawe32")) + { + return 0; + } + } + + if (md != NULL) + { + if (!strcmp(md, "none")) + { + return 0; + } + } + + return 1; +} + +static BOOL CALLBACK win_settings_sound_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + HWND h; + int c = 0; + int d = 0; + LPTSTR lptsTemp; + device_t *sound_dev, *midi_dev; + char *s; + + switch (message) + { + case WM_INITDIALOG: + lptsTemp = (LPTSTR) malloc(512); + + h = GetDlgItem(hdlg, IDC_COMBO_SOUND); + c = d = 0; + while (1) + { + s = sound_card_getname(c); + + if (!s[0]) + { + break; + } + + settings_sound_to_list[c] = d; + + if (sound_card_available(c)) + { + sound_dev = sound_card_getdevice(c); + + if (!sound_dev || (sound_dev->flags & DEVICE_MCA) == (models[temp_model].flags & MODEL_MCA)) + { + if (c == 0) + { + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) win_language_get_string_from_id(IDS_2152)); + } + else + { + mbstowcs(lptsTemp, s, strlen(s) + 1); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) lptsTemp); + } + settings_list_to_sound[d] = c; + d++; + } + } + + c++; + } + SendMessage(h, CB_SETCURSEL, settings_sound_to_list[temp_sound_card], 0); + + h = GetDlgItem(hdlg, IDC_CONFIGURE_SND); + if (sound_card_has_config(temp_sound_card)) + { + EnableWindow(h, TRUE); + } + else + { + EnableWindow(h, FALSE); + } + + h = GetDlgItem(hdlg, IDC_COMBO_MIDI); + c = d = 0; + while (1) + { + s = midi_device_getname(c); + + if (!s[0]) + { + break; + } + + settings_midi_to_list[c] = d; + + if (midi_device_available(c)) + { + midi_dev = midi_device_getdevice(c); + + if (!midi_dev || (midi_dev->flags & DEVICE_MCA) == (models[temp_model].flags & MODEL_MCA)) + { + if (c == 0) + { + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) win_language_get_string_from_id(IDS_2152)); + } + else + { + mbstowcs(lptsTemp, s, strlen(s) + 1); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) lptsTemp); + } + settings_list_to_midi[d] = c; + d++; + } + } + + c++; + } + SendMessage(h, CB_SETCURSEL, settings_sound_to_list[temp_midi_device], 0); + + h = GetDlgItem(hdlg, IDC_CONFIGURE_MIDI); + if (midi_device_has_config(temp_midi_device)) + { + EnableWindow(h, TRUE); + } + else + { + EnableWindow(h, FALSE); + } + + h = GetDlgItem(hdlg, IDC_CHECK_MPU401); + SendMessage(h, BM_SETCHECK, temp_mpu401, 0); + EnableWindow(h, mpu401_standalone_allow() ? TRUE : FALSE); + + h = GetDlgItem(hdlg, IDC_CONFIGURE_MPU401); + EnableWindow(h, (mpu401_standalone_allow() && temp_mpu401) ? TRUE : FALSE); + + h=GetDlgItem(hdlg, IDC_CHECK_CMS); + SendMessage(h, BM_SETCHECK, temp_GAMEBLASTER, 0); + + h=GetDlgItem(hdlg, IDC_CHECK_GUS); + SendMessage(h, BM_SETCHECK, temp_GUS, 0); + + h=GetDlgItem(hdlg, IDC_CHECK_SSI); + SendMessage(h, BM_SETCHECK, temp_SSI2001, 0); + + h=GetDlgItem(hdlg, IDC_CHECK_NUKEDOPL); + SendMessage(h, BM_SETCHECK, temp_opl3_type, 0); + + h=GetDlgItem(hdlg, IDC_CHECK_FLOAT); + SendMessage(h, BM_SETCHECK, temp_float, 0); + + free(lptsTemp); + + return TRUE; + + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case IDC_COMBO_SOUND: + h = GetDlgItem(hdlg, IDC_COMBO_SOUND); + temp_sound_card = settings_list_to_sound[SendMessage(h, CB_GETCURSEL, 0, 0)]; + + h = GetDlgItem(hdlg, IDC_CONFIGURE_SND); + if (sound_card_has_config(temp_sound_card)) + { + EnableWindow(h, TRUE); + } + else + { + EnableWindow(h, FALSE); + } + + h = GetDlgItem(hdlg, IDC_CHECK_MPU401); + SendMessage(h, BM_SETCHECK, temp_mpu401, 0); + EnableWindow(h, mpu401_standalone_allow() ? TRUE : FALSE); + + h = GetDlgItem(hdlg, IDC_CONFIGURE_MPU401); + EnableWindow(h, (mpu401_standalone_allow() && temp_mpu401) ? TRUE : FALSE); + break; + + case IDC_CONFIGURE_SND: + h = GetDlgItem(hdlg, IDC_COMBO_SOUND); + temp_sound_card = settings_list_to_sound[SendMessage(h, CB_GETCURSEL, 0, 0)]; + + deviceconfig_open(hdlg, (void *)sound_card_getdevice(temp_sound_card)); + break; + + case IDC_COMBO_MIDI: + h = GetDlgItem(hdlg, IDC_COMBO_MIDI); + temp_midi_device = settings_list_to_midi[SendMessage(h, CB_GETCURSEL, 0, 0)]; + + h = GetDlgItem(hdlg, IDC_CONFIGURE_MIDI); + if (midi_device_has_config(temp_midi_device)) + { + EnableWindow(h, TRUE); + } + else + { + EnableWindow(h, FALSE); + } + + h = GetDlgItem(hdlg, IDC_CHECK_MPU401); + SendMessage(h, BM_SETCHECK, temp_mpu401, 0); + EnableWindow(h, mpu401_standalone_allow() ? TRUE : FALSE); + + h = GetDlgItem(hdlg, IDC_CONFIGURE_MPU401); + EnableWindow(h, (mpu401_standalone_allow() && temp_mpu401) ? TRUE : FALSE); + break; + + case IDC_CONFIGURE_MIDI: + h = GetDlgItem(hdlg, IDC_COMBO_MIDI); + temp_midi_device = settings_list_to_midi[SendMessage(h, CB_GETCURSEL, 0, 0)]; + + deviceconfig_open(hdlg, (void *)midi_device_getdevice(temp_midi_device)); + break; + + case IDC_CHECK_MPU401: + h = GetDlgItem(hdlg, IDC_CHECK_MPU401); + temp_mpu401 = SendMessage(h, BM_GETCHECK, 0, 0); + + h = GetDlgItem(hdlg, IDC_CONFIGURE_MPU401); + EnableWindow(h, mpu401_present() ? TRUE : FALSE); + break; + + case IDC_CONFIGURE_MPU401: + deviceconfig_open(hdlg, (void *)&mpu401_device); + break; + } + return FALSE; + + case WM_SAVESETTINGS: + h = GetDlgItem(hdlg, IDC_COMBO_SOUND); + temp_sound_card = settings_list_to_sound[SendMessage(h, CB_GETCURSEL, 0, 0)]; + + h = GetDlgItem(hdlg, IDC_COMBO_MIDI); + temp_midi_device = settings_list_to_midi[SendMessage(h, CB_GETCURSEL, 0, 0)]; + + h = GetDlgItem(hdlg, IDC_CHECK_MPU401); + temp_mpu401 = SendMessage(h, BM_GETCHECK, 0, 0); + + h = GetDlgItem(hdlg, IDC_CHECK_CMS); + temp_GAMEBLASTER = SendMessage(h, BM_GETCHECK, 0, 0); + + h = GetDlgItem(hdlg, IDC_CHECK_GUS); + temp_GUS = SendMessage(h, BM_GETCHECK, 0, 0); + + h = GetDlgItem(hdlg, IDC_CHECK_SSI); + temp_SSI2001 = SendMessage(h, BM_GETCHECK, 0, 0); + + h = GetDlgItem(hdlg, IDC_CHECK_NUKEDOPL); + temp_opl3_type = SendMessage(h, BM_GETCHECK, 0, 0); + + h = GetDlgItem(hdlg, IDC_CHECK_FLOAT); + temp_float = SendMessage(h, BM_GETCHECK, 0, 0); + + default: + return FALSE; + } + return FALSE; +} + + +static BOOL CALLBACK win_settings_peripherals_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + HWND h; + int c = 0; + int d = 0; + LPTSTR lptsTemp; + device_t *scsi_dev; + + switch (message) + { + case WM_INITDIALOG: + lptsTemp = (LPTSTR) malloc(512); + + /*SCSI config*/ + h = GetDlgItem(hdlg, IDC_COMBO_SCSI); + c = d = 0; + while (1) + { + char *s = scsi_card_getname(c); + + if (!s[0]) + { + break; + } + + settings_scsi_to_list[c] = d; + + if (scsi_card_available(c)) + { + scsi_dev = scsi_card_getdevice(c); + + if (!scsi_dev || (scsi_dev->flags & DEVICE_MCA) == (models[temp_model].flags & MODEL_MCA)) + { + if (c == 0) + { + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) win_language_get_string_from_id(IDS_2152)); + } + else + { + mbstowcs(lptsTemp, s, strlen(s) + 1); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) lptsTemp); + } + settings_list_to_scsi[d] = c; + d++; + } + } + + c++; + } + SendMessage(h, CB_SETCURSEL, settings_scsi_to_list[temp_scsi_card], 0); + + h = GetDlgItem(hdlg, IDC_CONFIGURE_SCSI); + if (scsi_card_has_config(temp_scsi_card)) + { + EnableWindow(h, TRUE); + } + else + { + EnableWindow(h, FALSE); + } + + recalc_hdd_list(hdlg, temp_model, 0); + + h=GetDlgItem(hdlg, IDC_COMBO_IDE_TER); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) win_language_get_string_from_id(2151)); + + for (c = 0; c < 11; c++) + { + wsprintf(lptsTemp, win_language_get_string_from_id(IDS_2155), valid_ide_irqs[c]); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) lptsTemp); + } + + if (temp_ide_ter) + { + SendMessage(h, CB_SETCURSEL, find_irq_in_array(temp_ide_ter_irq, 0), 0); + } + else + { + SendMessage(h, CB_SETCURSEL, 0, 0); + } + + h=GetDlgItem(hdlg, IDC_COMBO_IDE_QUA); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) win_language_get_string_from_id(IDS_2151)); + + for (c = 0; c < 11; c++) + { + wsprintf(lptsTemp, win_language_get_string_from_id(IDS_2155), valid_ide_irqs[c]); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) lptsTemp); + } + + if (temp_ide_qua) + { + SendMessage(h, CB_SETCURSEL, find_irq_in_array(temp_ide_qua_irq, 1), 0); + } + else + { + SendMessage(h, CB_SETCURSEL, 0, 0); + } + + h=GetDlgItem(hdlg, IDC_CHECK_SERIAL1); + SendMessage(h, BM_SETCHECK, temp_serial[0], 0); + + h=GetDlgItem(hdlg, IDC_CHECK_SERIAL2); + SendMessage(h, BM_SETCHECK, temp_serial[1], 0); + + h=GetDlgItem(hdlg, IDC_CHECK_PARALLEL); + SendMessage(h, BM_SETCHECK, temp_lpt, 0); + + h=GetDlgItem(hdlg, IDC_CHECK_BUGGER); + SendMessage(h, BM_SETCHECK, temp_bugger, 0); + + free(lptsTemp); + + return TRUE; + + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case IDC_CONFIGURE_SCSI: + h = GetDlgItem(hdlg, IDC_COMBO_SCSI); + temp_scsi_card = settings_list_to_scsi[SendMessage(h, CB_GETCURSEL, 0, 0)]; + + deviceconfig_open(hdlg, (void *)scsi_card_getdevice(temp_scsi_card)); + break; + + case IDC_COMBO_SCSI: + h = GetDlgItem(hdlg, IDC_COMBO_SCSI); + temp_scsi_card = settings_list_to_scsi[SendMessage(h, CB_GETCURSEL, 0, 0)]; + + h = GetDlgItem(hdlg, IDC_CONFIGURE_SCSI); + if (scsi_card_has_config(temp_scsi_card)) + { + EnableWindow(h, TRUE); + } + else + { + EnableWindow(h, FALSE); + } + break; + } + return FALSE; + + case WM_SAVESETTINGS: + if (hdc_ignore == 0) + { + h = GetDlgItem(hdlg, IDC_COMBO_HDC); + c = SendMessage(h, CB_GETCURSEL, 0, 0); + if (hdd_names[c]) + { + strncpy(temp_hdc_name, hdd_names[c], sizeof(temp_hdc_name) - 1); + } + else + { + strcpy(temp_hdc_name, "none"); + } + } + else + { + strcpy(temp_hdc_name, "none"); + } + + h = GetDlgItem(hdlg, IDC_COMBO_SCSI); + temp_scsi_card = settings_list_to_scsi[SendMessage(h, CB_GETCURSEL, 0, 0)]; + + h = GetDlgItem(hdlg, IDC_COMBO_IDE_TER); + temp_ide_ter = SendMessage(h, CB_GETCURSEL, 0, 0); + if (temp_ide_ter > 1) + { + temp_ide_ter_irq = valid_ide_irqs[temp_ide_ter - 1]; + temp_ide_ter = 1; + } + + h = GetDlgItem(hdlg, IDC_COMBO_IDE_QUA); + temp_ide_qua = SendMessage(h, CB_GETCURSEL, 0, 0); + if (temp_ide_qua > 1) + { + temp_ide_qua_irq = valid_ide_irqs[temp_ide_qua - 1]; + temp_ide_qua = 1; + } + + h = GetDlgItem(hdlg, IDC_CHECK_SERIAL1); + temp_serial[0] = SendMessage(h, BM_GETCHECK, 0, 0); + + h = GetDlgItem(hdlg, IDC_CHECK_SERIAL2); + temp_serial[1] = SendMessage(h, BM_GETCHECK, 0, 0); + + h = GetDlgItem(hdlg, IDC_CHECK_PARALLEL); + temp_lpt = SendMessage(h, BM_GETCHECK, 0, 0); + + h = GetDlgItem(hdlg, IDC_CHECK_BUGGER); + temp_bugger = SendMessage(h, BM_GETCHECK, 0, 0); + + default: + return FALSE; + } + return FALSE; +} + + +int net_ignore_message = 0; + +static void network_recalc_combos(HWND hdlg) +{ + HWND h; + + net_ignore_message = 1; + + h = GetDlgItem(hdlg, IDC_COMBO_PCAP); + if (temp_net_type == NET_TYPE_PCAP) + { + EnableWindow(h, TRUE); + } + else + { + EnableWindow(h, FALSE); + } + + h = GetDlgItem(hdlg, IDC_COMBO_NET); + if (temp_net_type == NET_TYPE_SLIRP) + { + EnableWindow(h, TRUE); + } + else if ((temp_net_type == NET_TYPE_PCAP) && + (network_dev_to_id(temp_pcap_dev) > 0)) + { + EnableWindow(h, TRUE); + } + else + { + EnableWindow(h, FALSE); + } + + h = GetDlgItem(hdlg, IDC_CONFIGURE_NET); + if (network_card_has_config(temp_net_card) && + (temp_net_type == NET_TYPE_SLIRP)) + { + EnableWindow(h, TRUE); + } + else if (network_card_has_config(temp_net_card) && + (temp_net_type == NET_TYPE_PCAP) && + (network_dev_to_id(temp_pcap_dev) > 0)) + { + EnableWindow(h, TRUE); + } + else + { + EnableWindow(h, FALSE); + } + + net_ignore_message = 0; +} + +static BOOL CALLBACK win_settings_network_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + HWND h; + int c = 0; + int d = 0; + LPTSTR lptsTemp; + + switch (message) + { + case WM_INITDIALOG: + lptsTemp = (LPTSTR) malloc(512); + + h = GetDlgItem(hdlg, IDC_COMBO_NET_TYPE); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) L"None"); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) L"PCap"); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) L"SLiRP"); + SendMessage(h, CB_SETCURSEL, temp_net_type, 0); + + h = GetDlgItem(hdlg, IDC_COMBO_PCAP); + if (temp_net_type == NET_TYPE_PCAP) + { + EnableWindow(h, TRUE); + } + else + { + EnableWindow(h, FALSE); + } + + h = GetDlgItem(hdlg, IDC_COMBO_PCAP); + for (c = 0; c < network_ndev; c++) + { + mbstowcs(lptsTemp, network_devs[c].description, strlen(network_devs[c].description) + 1); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) lptsTemp); + } + SendMessage(h, CB_SETCURSEL, network_dev_to_id(temp_pcap_dev), 0); + + /*NIC config*/ + h = GetDlgItem(hdlg, IDC_COMBO_NET); + c = d = 0; + while (1) + { + char *s = network_card_getname(c); + + if (s[0] == '\0') + { + break; + } + + settings_network_to_list[c] = d; + + if (network_card_available(c)) + { + if (c == 0) + { + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) win_language_get_string_from_id(2152)); + } + else + { + mbstowcs(lptsTemp, s, strlen(s) + 1); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) lptsTemp); + } + settings_list_to_network[d] = c; + d++; + } + + c++; + } + SendMessage(h, CB_SETCURSEL, settings_network_to_list[temp_net_card], 0); + + network_recalc_combos(hdlg); + + free(lptsTemp); + + return TRUE; + + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case IDC_COMBO_NET_TYPE: + if (net_ignore_message) + { + return FALSE; + } + + h = GetDlgItem(hdlg, IDC_COMBO_NET_TYPE); + temp_net_type = SendMessage(h, CB_GETCURSEL, 0, 0); + + network_recalc_combos(hdlg); + break; + + case IDC_COMBO_PCAP: + if (net_ignore_message) + { + return FALSE; + } + + h = GetDlgItem(hdlg, IDC_COMBO_PCAP); + memset(temp_pcap_dev, '\0', sizeof(temp_pcap_dev)); + strcpy(temp_pcap_dev, network_devs[SendMessage(h, CB_GETCURSEL, 0, 0)].device); + + network_recalc_combos(hdlg); + break; + + case IDC_COMBO_NET: + if (net_ignore_message) + { + return FALSE; + } + + h = GetDlgItem(hdlg, IDC_COMBO_NET); + temp_net_card = settings_list_to_network[SendMessage(h, CB_GETCURSEL, 0, 0)]; + + network_recalc_combos(hdlg); + break; + + case IDC_CONFIGURE_NET: + if (net_ignore_message) + { + return FALSE; + } + + h = GetDlgItem(hdlg, IDC_COMBO_NET); + temp_net_card = settings_list_to_network[SendMessage(h, CB_GETCURSEL, 0, 0)]; + + deviceconfig_open(hdlg, (void *)network_card_getdevice(temp_net_card)); + break; + } + return FALSE; + + case WM_SAVESETTINGS: + h = GetDlgItem(hdlg, IDC_COMBO_NET_TYPE); + temp_net_type = SendMessage(h, CB_GETCURSEL, 0, 0); + + h = GetDlgItem(hdlg, IDC_COMBO_PCAP); + memset(temp_pcap_dev, '\0', sizeof(temp_pcap_dev)); + strcpy(temp_pcap_dev, network_devs[SendMessage(h, CB_GETCURSEL, 0, 0)].device); + + h = GetDlgItem(hdlg, IDC_COMBO_NET); + temp_net_card = settings_list_to_network[SendMessage(h, CB_GETCURSEL, 0, 0)]; + + default: + return FALSE; + } + + return FALSE; +} + +static BOOL win_settings_hard_disks_image_list_init(HWND hwndList) +{ + HICON hiconItem; + HIMAGELIST hSmall; + + int i = 0; + + hSmall = ImageList_Create(GetSystemMetrics(SM_CXSMICON), + GetSystemMetrics(SM_CYSMICON), + ILC_MASK | ILC_COLOR32, 1, 1); + + for (i = 0; i < 16; i += 2) + { + hiconItem = LoadIcon(hinstance, (LPCWSTR) (192 + i)); + ImageList_AddIcon(hSmall, hiconItem); + DestroyIcon(hiconItem); + } + + hiconItem = LoadIcon(hinstance, (LPCWSTR) 176); + ImageList_AddIcon(hSmall, hiconItem); + DestroyIcon(hiconItem); + + ListView_SetImageList(hwndList, hSmall, LVSIL_SMALL); + + return TRUE; +} + +int next_free_id = 0; + +static void normalize_hd_list() +{ + hard_disk_t ihdc[HDC_NUM]; + int i, j; + + j = 0; + memset(ihdc, 0, HDC_NUM * sizeof(hard_disk_t)); + + for (i = 0; i < HDC_NUM; i++) + { + if (temp_hdc[i].bus != HDD_BUS_DISABLED) + { + memcpy(&(ihdc[j]), &(temp_hdc[i]), sizeof(hard_disk_t)); + j++; + } + } + + memcpy(temp_hdc, ihdc, HDC_NUM * sizeof(hard_disk_t)); +} + +int hdc_id_to_listview_index[HDC_NUM]; +int hd_listview_items; + +hard_disk_t new_hdc; +int hdlv_current_sel; + +static int get_selected_hard_disk(HWND hdlg) +{ + int hard_disk = -1; + int i, j = 0; + HWND h; + + if (hd_listview_items == 0) + { + return 0; + } + + for (i = 0; i < hd_listview_items; i++) + { + h = GetDlgItem(hdlg, IDC_LIST_HARD_DISKS); + j = ListView_GetItemState(h, i, LVIS_SELECTED); + if (j) + { + hard_disk = i; + } + } + + return hard_disk; +} + +static void add_locations(HWND hdlg) +{ + LPTSTR lptsTemp; + HWND h; + int i = 0; + + lptsTemp = (LPTSTR) malloc(512); + + h = GetDlgItem(hdlg, IDC_COMBO_HD_BUS); + for (i = 0; i < 4; i++) + { + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) win_language_get_string_from_id(2165 + i)); + } + for (i = 0; i < 2; i++) + { + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) win_language_get_string_from_id(2209 + i)); + } + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) win_language_get_string_from_id(2202)); + + h = GetDlgItem(hdlg, IDC_COMBO_HD_CHANNEL); + for (i = 0; i < 8; i++) + { + wsprintf(lptsTemp, win_language_get_string_from_id(2169), i >> 1, i & 1); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) lptsTemp); + } + + h = GetDlgItem(hdlg, IDC_COMBO_HD_ID); + for (i = 0; i < 16; i++) + { + wsprintf(lptsTemp, win_language_get_string_from_id(2088), i); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) lptsTemp); + } + + h = GetDlgItem(hdlg, IDC_COMBO_HD_LUN); + for (i = 0; i < 8; i++) + { + wsprintf(lptsTemp, win_language_get_string_from_id(2088), i); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) lptsTemp); + } + + h = GetDlgItem(hdlg, IDC_COMBO_HD_CHANNEL_IDE); + for (i = 0; i < 8; i++) + { + wsprintf(lptsTemp, win_language_get_string_from_id(2169), i >> 1, i & 1); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) lptsTemp); + } + + free(lptsTemp); +} + +static void recalc_location_controls(HWND hdlg, int is_add_dlg) +{ + int i = 0; + HWND h; + + int bus = 0; + + for (i = IDT_1722; i <= IDT_1724; i++) + { + h = GetDlgItem(hdlg, i); + EnableWindow(h, FALSE); + ShowWindow(h, SW_HIDE); + } + + h = GetDlgItem(hdlg, IDC_COMBO_HD_CHANNEL); + EnableWindow(h, FALSE); + ShowWindow(h, SW_HIDE); + + h = GetDlgItem(hdlg, IDC_COMBO_HD_ID); + EnableWindow(h, FALSE); + ShowWindow(h, SW_HIDE); + + h = GetDlgItem(hdlg, IDC_COMBO_HD_LUN); + EnableWindow(h, FALSE); + ShowWindow(h, SW_HIDE); + + h = GetDlgItem(hdlg, IDC_COMBO_HD_CHANNEL_IDE); + EnableWindow(h, FALSE); + ShowWindow(h, SW_HIDE); + + if ((hd_listview_items > 0) || is_add_dlg) + { + h = GetDlgItem(hdlg, IDC_COMBO_HD_BUS); + bus = SendMessage(h, CB_GETCURSEL, 0, 0); + bus++; + + switch(bus) + { + case HDD_BUS_MFM: /* MFM */ + h = GetDlgItem(hdlg, IDT_1722); + ShowWindow(h, SW_SHOW); + EnableWindow(h, TRUE); + + h = GetDlgItem(hdlg, IDC_COMBO_HD_CHANNEL); + ShowWindow(h, SW_SHOW); + EnableWindow(h, TRUE); + SendMessage(h, CB_SETCURSEL, is_add_dlg ? new_hdc.mfm_channel : temp_hdc[hdlv_current_sel].mfm_channel, 0); + break; + case HDD_BUS_RLL: /* RLL */ + h = GetDlgItem(hdlg, IDT_1722); + ShowWindow(h, SW_SHOW); + EnableWindow(h, TRUE); + + h = GetDlgItem(hdlg, IDC_COMBO_HD_CHANNEL); + ShowWindow(h, SW_SHOW); + EnableWindow(h, TRUE); + SendMessage(h, CB_SETCURSEL, is_add_dlg ? new_hdc.rll_channel : temp_hdc[hdlv_current_sel].rll_channel, 0); + break; + case HDD_BUS_XTIDE: /* XT IDE */ + h = GetDlgItem(hdlg, IDT_1722); + ShowWindow(h, SW_SHOW); + EnableWindow(h, TRUE); + + h = GetDlgItem(hdlg, IDC_COMBO_HD_CHANNEL); + ShowWindow(h, SW_SHOW); + EnableWindow(h, TRUE); + SendMessage(h, CB_SETCURSEL, is_add_dlg ? new_hdc.xtide_channel : temp_hdc[hdlv_current_sel].xtide_channel, 0); + break; + case HDD_BUS_IDE_PIO_ONLY: /* IDE (PIO-only) */ + case HDD_BUS_IDE_PIO_AND_DMA: /* IDE (PIO and DMA) */ + h = GetDlgItem(hdlg, IDT_1722); + ShowWindow(h, SW_SHOW); + EnableWindow(h, TRUE); + + h = GetDlgItem(hdlg, IDC_COMBO_HD_CHANNEL_IDE); + ShowWindow(h, SW_SHOW); + EnableWindow(h, TRUE); + SendMessage(h, CB_SETCURSEL, is_add_dlg ? new_hdc.ide_channel : temp_hdc[hdlv_current_sel].ide_channel, 0); + break; + case HDD_BUS_SCSI: /* SCSI */ + case HDD_BUS_SCSI_REMOVABLE: /* SCSI (removable) */ + h = GetDlgItem(hdlg, IDT_1723); + ShowWindow(h, SW_SHOW); + EnableWindow(h, TRUE); + h = GetDlgItem(hdlg, IDT_1724); + ShowWindow(h, SW_SHOW); + EnableWindow(h, TRUE); + + h = GetDlgItem(hdlg, IDC_COMBO_HD_ID); + ShowWindow(h, SW_SHOW); + EnableWindow(h, TRUE); + SendMessage(h, CB_SETCURSEL, is_add_dlg ? new_hdc.scsi_id : temp_hdc[hdlv_current_sel].scsi_id, 0); + + h = GetDlgItem(hdlg, IDC_COMBO_HD_LUN); + ShowWindow(h, SW_SHOW); + EnableWindow(h, TRUE); + SendMessage(h, CB_SETCURSEL, is_add_dlg ? new_hdc.scsi_lun : temp_hdc[hdlv_current_sel].scsi_lun, 0); + break; + } + } + + if ((hd_listview_items == 0) && !is_add_dlg) + { + h = GetDlgItem(hdlg, IDT_1721); + EnableWindow(h, FALSE); + ShowWindow(h, SW_HIDE); + + h = GetDlgItem(hdlg, IDC_COMBO_HD_BUS); + EnableWindow(h, FALSE); ShowWindow(h, SW_HIDE); + } + else + { + h = GetDlgItem(hdlg, IDT_1721); + ShowWindow(h, SW_SHOW); + EnableWindow(h, TRUE); + + h = GetDlgItem(hdlg, IDC_COMBO_HD_BUS); + ShowWindow(h, SW_SHOW); + EnableWindow(h, TRUE); + } +} + +static void recalc_next_free_id(HWND hdlg) +{ + HWND h; + int i; + + int c_mfm = 0; + int c_rll = 0; + int c_xtide = 0; + int c_ide_pio = 0; + int c_ide_dma = 0; + int c_scsi = 0; + int enable_add = 0; + + next_free_id = -1; + + for (i = 0; i < HDC_NUM; i++) + { + if (temp_hdc[i].bus == HDD_BUS_MFM) + { + c_mfm++; + } + else if (temp_hdc[i].bus == HDD_BUS_RLL) + { + c_rll++; + } + else if (temp_hdc[i].bus == HDD_BUS_XTIDE) + { + c_xtide++; + } + else if (temp_hdc[i].bus == HDD_BUS_IDE_PIO_ONLY) + { + c_ide_pio++; + } + else if (temp_hdc[i].bus == HDD_BUS_IDE_PIO_AND_DMA) + { + c_ide_dma++; + } + else if (temp_hdc[i].bus == HDD_BUS_SCSI) + { + c_scsi++; + } + else if (temp_hdc[i].bus == HDD_BUS_SCSI_REMOVABLE) + { + c_scsi++; + } + } + + for (i = 0; i < HDC_NUM; i++) + { + if (temp_hdc[i].bus == HDD_BUS_DISABLED) + { + next_free_id = i; + break; + } + } + + /* pclog("Next free ID: %i\n", next_free_id); */ + + enable_add = enable_add || (next_free_id >= 0); + /* pclog("Enable add: %i\n", enable_add); */ + enable_add = enable_add && ((c_mfm < MFM_NUM) || (c_rll < RLL_NUM) || (c_xtide < XTIDE_NUM) || (c_ide_pio < IDE_NUM) || (c_ide_dma < IDE_NUM) || (c_scsi < SCSI_NUM)); + /* pclog("Enable add: %i\n", enable_add); */ + + h = GetDlgItem(hdlg, IDC_BUTTON_HDD_ADD_NEW); + + if (enable_add) + { + EnableWindow(h, TRUE); + } + else + { + EnableWindow(h, FALSE); + } + + h = GetDlgItem(hdlg, IDC_BUTTON_HDD_ADD); + + if (enable_add) + { + EnableWindow(h, TRUE); + } + else + { + EnableWindow(h, FALSE); + } + + h = GetDlgItem(hdlg, IDC_BUTTON_HDD_REMOVE); + + if ((c_mfm == 0) && (c_rll == 0) && (c_xtide == 0) && (c_ide_pio == 0) && (c_ide_dma == 0) && (c_scsi == 0)) + { + EnableWindow(h, FALSE); + } + else + { + EnableWindow(h, TRUE); + } +} + +static void win_settings_hard_disks_update_item(HWND hwndList, int i, int column) +{ + LVITEM lvI; + WCHAR szText[256]; + + lvI.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE; + lvI.stateMask = lvI.iSubItem = lvI.state = 0; + + lvI.iSubItem = column; + lvI.iItem = i; + + if (column == 0) + { + switch(temp_hdc[i].bus) + { + case HDD_BUS_MFM: + wsprintf(szText, win_language_get_string_from_id(2156), temp_hdc[i].mfm_channel >> 1, temp_hdc[i].mfm_channel & 1); + break; + case HDD_BUS_RLL: + wsprintf(szText, win_language_get_string_from_id(2205), temp_hdc[i].rll_channel >> 1, temp_hdc[i].rll_channel & 1); + break; + case HDD_BUS_XTIDE: + wsprintf(szText, win_language_get_string_from_id(2206), temp_hdc[i].xtide_channel >> 1, temp_hdc[i].xtide_channel & 1); + break; + case HDD_BUS_IDE_PIO_ONLY: + wsprintf(szText, win_language_get_string_from_id(2195), temp_hdc[i].ide_channel >> 1, temp_hdc[i].ide_channel & 1); + break; + case HDD_BUS_IDE_PIO_AND_DMA: + wsprintf(szText, win_language_get_string_from_id(2157), temp_hdc[i].ide_channel >> 1, temp_hdc[i].ide_channel & 1); + break; + case HDD_BUS_SCSI: + wsprintf(szText, win_language_get_string_from_id(2158), temp_hdc[i].scsi_id, temp_hdc[i].scsi_lun); + break; + case HDD_BUS_SCSI_REMOVABLE: + wsprintf(szText, win_language_get_string_from_id(2203), temp_hdc[i].scsi_id, temp_hdc[i].scsi_lun); + break; + } + lvI.pszText = szText; + lvI.iImage = temp_hdc[i].bus - 1; + } + else if (column == 1) + { + lvI.pszText = temp_hdc[i].fn; + lvI.iImage = 0; + } + else if (column == 2) + { + wsprintf(szText, win_language_get_string_from_id(2088), temp_hdc[i].tracks); + lvI.pszText = szText; + lvI.iImage = 0; + } + else if (column == 3) + { + wsprintf(szText, win_language_get_string_from_id(2088), temp_hdc[i].hpc); + lvI.pszText = szText; + lvI.iImage = 0; + } + else if (column == 4) + { + wsprintf(szText, win_language_get_string_from_id(2088), temp_hdc[i].spt); + lvI.pszText = szText; + lvI.iImage = 0; + } + else if (column == 5) + { + wsprintf(szText, win_language_get_string_from_id(2088), (temp_hdc[i].tracks * temp_hdc[i].hpc * temp_hdc[i].spt) >> 11); + lvI.pszText = szText; + lvI.iImage = 0; + } + + if (ListView_SetItem(hwndList, &lvI) == -1) + { + return; + } +} + +static BOOL win_settings_hard_disks_recalc_list(HWND hwndList) +{ + LVITEM lvI; + int i = 0; + int j = 0; + WCHAR szText[256]; + + hd_listview_items = 0; + hdlv_current_sel = -1; + + ListView_DeleteAllItems(hwndList); + + lvI.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE; + lvI.stateMask = lvI.iSubItem = lvI.state = 0; + + for (i = 0; i < HDC_NUM; i++) + { + if (temp_hdc[i].bus > 0) + { + hdc_id_to_listview_index[i] = j; + lvI.iSubItem = 0; + switch(temp_hdc[i].bus) + { + case HDD_BUS_MFM: + wsprintf(szText, win_language_get_string_from_id(2156), temp_hdc[i].mfm_channel >> 1, temp_hdc[i].mfm_channel & 1); + break; + case HDD_BUS_RLL: + wsprintf(szText, win_language_get_string_from_id(2205), temp_hdc[i].rll_channel >> 1, temp_hdc[i].rll_channel & 1); + break; + case HDD_BUS_XTIDE: + wsprintf(szText, win_language_get_string_from_id(2206), temp_hdc[i].xtide_channel >> 1, temp_hdc[i].xtide_channel & 1); + break; + case HDD_BUS_IDE_PIO_ONLY: + wsprintf(szText, win_language_get_string_from_id(2195), temp_hdc[i].ide_channel >> 1, temp_hdc[i].ide_channel & 1); + break; + case HDD_BUS_IDE_PIO_AND_DMA: + wsprintf(szText, win_language_get_string_from_id(2157), temp_hdc[i].ide_channel >> 1, temp_hdc[i].ide_channel & 1); + break; + case HDD_BUS_SCSI: + wsprintf(szText, win_language_get_string_from_id(2158), temp_hdc[i].scsi_id, temp_hdc[i].scsi_lun); + break; + case HDD_BUS_SCSI_REMOVABLE: + wsprintf(szText, win_language_get_string_from_id(2203), temp_hdc[i].scsi_id, temp_hdc[i].scsi_lun); + break; + } + lvI.pszText = szText; + lvI.iItem = j; + lvI.iImage = temp_hdc[i].bus - 1; + + if (ListView_InsertItem(hwndList, &lvI) == -1) + { + return FALSE; + } + + lvI.iSubItem = 1; + lvI.pszText = temp_hdc[i].fn; + lvI.iItem = j; + lvI.iImage = 0; + + if (ListView_SetItem(hwndList, &lvI) == -1) + { + return FALSE; + } + + lvI.iSubItem = 2; + wsprintf(szText, win_language_get_string_from_id(2088), temp_hdc[i].tracks); + lvI.pszText = szText; + lvI.iItem = j; + lvI.iImage = 0; + + if (ListView_SetItem(hwndList, &lvI) == -1) + { + return FALSE; + } + + lvI.iSubItem = 3; + wsprintf(szText, win_language_get_string_from_id(2088), temp_hdc[i].hpc); + lvI.pszText = szText; + lvI.iItem = j; + lvI.iImage = 0; + + if (ListView_SetItem(hwndList, &lvI) == -1) + { + return FALSE; + } + + lvI.iSubItem = 4; + wsprintf(szText, win_language_get_string_from_id(2088), temp_hdc[i].spt); + lvI.pszText = szText; + lvI.iItem = j; + lvI.iImage = 0; + + if (ListView_SetItem(hwndList, &lvI) == -1) + { + return FALSE; + } + + lvI.iSubItem = 5; + wsprintf(szText, win_language_get_string_from_id(2088), (temp_hdc[i].tracks * temp_hdc[i].hpc * temp_hdc[i].spt) >> 11); + lvI.pszText = szText; + lvI.iItem = j; + lvI.iImage = 0; + + if (ListView_SetItem(hwndList, &lvI) == -1) + { + return FALSE; + } + + j++; + } + else + { + hdc_id_to_listview_index[i] = -1; + } + } + + hd_listview_items = j; + + return TRUE; +} + +/* Icon, Bus, File, C, H, S, Size */ +#define C_COLUMNS_HARD_DISKS 6 + +static BOOL win_settings_hard_disks_init_columns(HWND hwndList) +{ + LVCOLUMN lvc; + int iCol; + + lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM; + + for (iCol = 0; iCol < C_COLUMNS_HARD_DISKS; iCol++) + { + lvc.iSubItem = iCol; + lvc.pszText = win_language_get_string_from_id(2082 + iCol); + + switch(iCol) + { + + case 0: /* Bus */ + lvc.cx = 135; + lvc.fmt = LVCFMT_LEFT; + break; + case 2: /* Cylinders */ + lvc.cx = 41; + lvc.fmt = LVCFMT_RIGHT; + break; + case 3: /* Heads */ + case 4: /* Sectors */ + lvc.cx = 25; + lvc.fmt = LVCFMT_RIGHT; + break; + case 1: /* File */ + lvc.cx = 150; + lvc.fmt = LVCFMT_LEFT; + break; + case 5: /* Size (MB) 8 */ + lvc.cx = 41; + lvc.fmt = LVCFMT_RIGHT; + break; + } + + if (ListView_InsertColumn(hwndList, iCol, &lvc) == -1) + { + return FALSE; + } + } + + return TRUE; +} + +static void get_edit_box_contents(HWND hdlg, int id, uint64_t *val) +{ + HWND h; + WCHAR szText[256]; + char stransi[256]; + + h = GetDlgItem(hdlg, id); + SendMessage(h, WM_GETTEXT, 255, (LPARAM) szText); + wcstombs(stransi, szText, (wcslen(szText) * 2) + 2); + sscanf(stransi, "%" PRIu64, val); +} + +static void get_combo_box_selection(HWND hdlg, int id, uint64_t *val) +{ + HWND h; + + h = GetDlgItem(hdlg, id); + *val = SendMessage(h, CB_GETCURSEL, 0, 0); +} + +static void set_edit_box_contents(HWND hdlg, int id, uint64_t val) +{ + HWND h; + WCHAR szText[256]; + + h = GetDlgItem(hdlg, id); + wsprintf(szText, win_language_get_string_from_id(2160), val); + SendMessage(h, WM_SETTEXT, (WPARAM) wcslen(szText), (LPARAM) szText); +} + +int hard_disk_added = 0; +int max_spt = 63; +int max_hpc = 255; +int max_tracks = 266305; + +int no_update = 0; + +int existing = 0; +uint64_t selection = 127; + +uint64_t spt, hpc, tracks, size; +wchar_t hd_file_name[512]; + +static hard_disk_t *hdc_ptr; + +static int hdconf_initialize_hdt_combo(HWND hdlg) +{ + HWND h; + int i = 0; + uint64_t temp_size = 0; + uint64_t size_mb = 0; + WCHAR szText[256]; + + selection = 127; + + h = GetDlgItem(hdlg, IDC_COMBO_HD_TYPE); + for (i = 0; i < 127; i++) + { + temp_size = hdt[i][0] * hdt[i][1] * hdt[i][2]; + size_mb = temp_size >> 11; + wsprintf(szText, win_language_get_string_from_id(2171), size_mb, hdt[i][0], hdt[i][1], hdt[i][2]); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) szText); + if ((tracks == hdt[i][0]) && (hpc == hdt[i][1]) && (spt == hdt[i][2])) + { + selection = i; + } + } + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) win_language_get_string_from_id(2170)); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) win_language_get_string_from_id(2187)); + SendMessage(h, CB_SETCURSEL, selection, 0); + return selection; +} + +static void recalc_selection(HWND hdlg) +{ + HWND h; + int i = 0; + + selection = 127; + h = GetDlgItem(hdlg, IDC_COMBO_HD_TYPE); + for (i = 0; i < 127; i++) + { + if ((tracks == hdt[i][0]) && (hpc == hdt[i][1]) && (spt == hdt[i][2])) + { + selection = i; + } + } + if ((selection == 127) && (hpc == 16) && (spt == 63)) + { + selection = 128; + } + SendMessage(h, CB_SETCURSEL, selection, 0); +} + +static int chs_enabled = 0; + +static BOOL CALLBACK win_settings_hard_disks_add_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + HWND h; + int64_t i = 0; + uint64_t temp; + FILE *f; + uint32_t sector_size = 512; + uint32_t zero = 0; + uint32_t base = 0x1000; + uint64_t signature = 0xD778A82044445459ll; + char buf[512]; + char *big_buf; + int b = 0; + uint64_t r = 0; + + switch (message) + { + case WM_INITDIALOG: + memset(hd_file_name, 0, sizeof(hd_file_name)); + + if (existing & 2) + { + next_free_id = (existing >> 3) & 0x1f; + hdc_ptr = &(hdc[next_free_id]); + } + else + { + hdc_ptr = &(temp_hdc[next_free_id]); + } + + SetWindowText(hdlg, win_language_get_string_from_id((existing & 1) ? 2197 : 2196)); + + no_update = 1; + spt = (existing & 1) ? 0 : 17; + set_edit_box_contents(hdlg, IDC_EDIT_HD_SPT, spt); + hpc = (existing & 1) ? 0 : 15; + set_edit_box_contents(hdlg, IDC_EDIT_HD_HPC, hpc); + tracks = (existing & 1) ? 0 : 1023; + set_edit_box_contents(hdlg, IDC_EDIT_HD_CYL, tracks); + size = (tracks * hpc * spt) << 9; + set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, size >> 20); + hdconf_initialize_hdt_combo(hdlg); + if (existing & 1) + { + h = GetDlgItem(hdlg, IDC_EDIT_HD_SPT); + EnableWindow(h, FALSE); + h = GetDlgItem(hdlg, IDC_EDIT_HD_HPC); + EnableWindow(h, FALSE); + h = GetDlgItem(hdlg, IDC_EDIT_HD_CYL); + EnableWindow(h, FALSE); + h = GetDlgItem(hdlg, IDC_EDIT_HD_SIZE); + EnableWindow(h, FALSE); + h = GetDlgItem(hdlg, IDC_COMBO_HD_TYPE); + EnableWindow(h, FALSE); + chs_enabled = 0; + } + else + { + chs_enabled = 1; + } + add_locations(hdlg); + h = GetDlgItem(hdlg, IDC_COMBO_HD_BUS); + if (existing & 2) + { + hdc_ptr->bus = HDD_BUS_SCSI_REMOVABLE; + max_spt = 99; + max_hpc = 255; + } + else + { + hdc_ptr->bus = HDD_BUS_IDE_PIO_ONLY; + max_spt = 63; + max_hpc = 16; + } + SendMessage(h, CB_SETCURSEL, hdc_ptr->bus, 0); + max_tracks = 266305; + recalc_location_controls(hdlg, 1); + if (existing & 2) + { + /* We're functioning as a load image dialog for a removable SCSI hard disk, + called from win.c, so let's hide the bus selection as we should not + allow it at this point. */ + EnableWindow(h, FALSE); + ShowWindow(h, SW_HIDE); + + h = GetDlgItem(hdlg, 1798); + ShowWindow(h, SW_HIDE); + + /* Disable and hide the SCSI ID and LUN combo boxes. */ + h = GetDlgItem(hdlg, IDC_COMBO_HD_ID); + EnableWindow(h, FALSE); + ShowWindow(h, SW_HIDE); + + h = GetDlgItem(hdlg, IDC_COMBO_HD_LUN); + EnableWindow(h, FALSE); + ShowWindow(h, SW_HIDE); + + /* Set the file name edit box contents to our existing parameters. */ + h = GetDlgItem(hdlg, IDC_EDIT_HD_FILE_NAME); + SendMessage(h, WM_SETTEXT, 0, (LPARAM) hdc[next_free_id].fn); + } + else + { + h = GetDlgItem(hdlg, IDC_COMBO_HD_CHANNEL); + SendMessage(h, CB_SETCURSEL, 0, 0); + h = GetDlgItem(hdlg, IDC_COMBO_HD_ID); + SendMessage(h, CB_SETCURSEL, 0, 0); + h = GetDlgItem(hdlg, IDC_COMBO_HD_LUN); + SendMessage(h, CB_SETCURSEL, 0, 0); + h = GetDlgItem(hdlg, IDC_COMBO_HD_CHANNEL_IDE); + SendMessage(h, CB_SETCURSEL, 0, 0); + } + h = GetDlgItem(hdlg, IDC_EDIT_HD_FILE_NAME); + EnableWindow(h, FALSE); + no_update = 0; + return TRUE; + + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case IDOK: + if (!(existing & 2)) + { + h = GetDlgItem(hdlg, IDC_COMBO_HD_BUS); + hdc_ptr->bus = SendMessage(h, CB_GETCURSEL, 0, 0) + 1; + } + + /* Make sure no file name is allowed with removable SCSI hard disks. */ + if ((wcslen(hd_file_name) == 0) && (hdc_ptr->bus != HDD_BUS_SCSI_REMOVABLE)) + { + hdc_ptr->bus = HDD_BUS_DISABLED; + msgbox_error(hwndParentDialog, IDS_2056); + return TRUE; + } + else if ((wcslen(hd_file_name) == 0) && (hdc_ptr->bus == HDD_BUS_SCSI_REMOVABLE)) + { + /* Mark hard disk added but return empty - it will signify the disk was ejected. */ + hdc_ptr->spt = hdc_ptr->hpc = hdc_ptr->tracks = 0; + memset(hdc_ptr->fn, 0, sizeof(hdc_ptr->fn)); + + goto hd_add_ok_common; + } + + get_edit_box_contents(hdlg, IDC_EDIT_HD_SPT, &(hdc_ptr->spt)); + get_edit_box_contents(hdlg, IDC_EDIT_HD_HPC, &(hdc_ptr->hpc)); + get_edit_box_contents(hdlg, IDC_EDIT_HD_CYL, &(hdc_ptr->tracks)); + spt = hdc_ptr->spt; + hpc = hdc_ptr->hpc; + tracks = hdc_ptr->tracks; + + if (existing & 2) + { + if (hdc_ptr->bus == HDD_BUS_SCSI_REMOVABLE) + { + memset(hdc_ptr->prev_fn, 0, sizeof(hdc_ptr->prev_fn)); + wcscpy(hdc_ptr->prev_fn, hdc_ptr->fn); + } + } + else + { + switch(hdc_ptr->bus) + { + case HDD_BUS_MFM: + h = GetDlgItem(hdlg, IDC_COMBO_HD_CHANNEL); + hdc_ptr->mfm_channel = SendMessage(h, CB_GETCURSEL, 0, 0); + break; + case HDD_BUS_RLL: + h = GetDlgItem(hdlg, IDC_COMBO_HD_CHANNEL); + hdc_ptr->rll_channel = SendMessage(h, CB_GETCURSEL, 0, 0); + break; + case HDD_BUS_XTIDE: + h = GetDlgItem(hdlg, IDC_COMBO_HD_CHANNEL); + hdc_ptr->xtide_channel = SendMessage(h, CB_GETCURSEL, 0, 0); + break; + case HDD_BUS_IDE_PIO_ONLY: + case HDD_BUS_IDE_PIO_AND_DMA: + h = GetDlgItem(hdlg, IDC_COMBO_HD_CHANNEL_IDE); + hdc_ptr->ide_channel = SendMessage(h, CB_GETCURSEL, 0, 0); + break; + case HDD_BUS_SCSI: + case HDD_BUS_SCSI_REMOVABLE: + h = GetDlgItem(hdlg, IDC_COMBO_HD_ID); + hdc_ptr->scsi_id = SendMessage(h, CB_GETCURSEL, 0, 0); + h = GetDlgItem(hdlg, IDC_COMBO_HD_LUN); + hdc_ptr->scsi_lun = SendMessage(h, CB_GETCURSEL, 0, 0); + break; + } + } + + memset(hdc_ptr->fn, 0, sizeof(hdc_ptr->fn)); + wcscpy(hdc_ptr->fn, hd_file_name); + + sector_size = 512; + + if (!(existing & 1) && (wcslen(hd_file_name) > 0)) + { + f = _wfopen(hd_file_name, L"wb"); + + if (image_is_hdi(hd_file_name)) + { + if (size >= 0x100000000ll) + { + fclose(f); + msgbox_error(hwndParentDialog, IDS_2058); + return TRUE; + } + + fwrite(&zero, 1, 4, f); /* 00000000: Zero/unknown */ + fwrite(&zero, 1, 4, f); /* 00000004: Zero/unknown */ + fwrite(&base, 1, 4, f); /* 00000008: Offset at which data starts */ + fwrite(&size, 1, 4, f); /* 0000000C: Full size of the data (32-bit) */ + fwrite(§or_size, 1, 4, f); /* 00000010: Sector size in bytes */ + fwrite(&spt, 1, 4, f); /* 00000014: Sectors per cylinder */ + fwrite(&hpc, 1, 4, f); /* 00000018: Heads per cylinder */ + fwrite(&tracks, 1, 4, f); /* 0000001C: Cylinders */ + + for (i = 0; i < 0x3f8; i++) + { + fwrite(&zero, 1, 4, f); + } + } + else if (image_is_hdx(hd_file_name, 0)) + { + if (size > 0xffffffffffffffffll) + { + fclose(f); + msgbox_error(hwndParentDialog, IDS_2163); + return TRUE; + } + + fwrite(&signature, 1, 8, f); /* 00000000: Signature */ + fwrite(&size, 1, 8, f); /* 00000008: Full size of the data (64-bit) */ + fwrite(§or_size, 1, 4, f); /* 00000010: Sector size in bytes */ + fwrite(&spt, 1, 4, f); /* 00000014: Sectors per cylinder */ + fwrite(&hpc, 1, 4, f); /* 00000018: Heads per cylinder */ + fwrite(&tracks, 1, 4, f); /* 0000001C: Cylinders */ + fwrite(&zero, 1, 4, f); /* 00000020: [Translation] Sectors per cylinder */ + fwrite(&zero, 1, 4, f); /* 00000004: [Translation] Heads per cylinder */ + } + + memset(buf, 0, 512); + size >>= 9; + r = (size >> 11) << 11; + size -= r; + r >>= 11; + + if (size) + { + for (i = 0; i < size; i++) + { + fwrite(buf, 1, 512, f); + } + } + + if (r) + { + big_buf = (char *) malloc(1048576); + memset(big_buf, 0, 1048576); + for (i = 0; i < r; i++) + { + fwrite(big_buf, 1, 1048576, f); + } + free(big_buf); + } + + fclose(f); + msgbox_info(hwndParentDialog, IDS_2059); + } + +hd_add_ok_common: + hard_disk_added = 1; + EndDialog(hdlg, 0); + return TRUE; + + case IDCANCEL: + hard_disk_added = 0; + if (!(existing & 2)) + { + hdc_ptr->bus = HDD_BUS_DISABLED; + } + EndDialog(hdlg, 0); + return TRUE; + + case IDC_CFILE: + if (!file_dlg_w(hdlg, win_language_get_string_from_id(2172), L"", !(existing & 1))) + { + if (!(existing & 1)) + { + f = _wfopen(wopenfilestring, L"rb"); + if (f != NULL) + { + fclose(f); + if (msgbox_question(ghwnd, IDS_2178) != IDYES) + { + return FALSE; + } + } + } + + f = _wfopen(wopenfilestring, (existing & 1) ? L"rb" : L"wb"); + if (f == NULL) + { +hdd_add_file_open_error: + msgbox_error(hwndParentDialog, (existing & 1) ? 2060 : 2057); + return TRUE; + } + if (existing & 1) + { + if (image_is_hdi(wopenfilestring) || image_is_hdx(wopenfilestring, 1)) + { + fseeko64(f, 0x10, SEEK_SET); + fread(§or_size, 1, 4, f); + if (sector_size != 512) + { + msgbox_error(hwndParentDialog, IDS_2061); + fclose(f); + return TRUE; + } + spt = hpc = tracks = 0; + fread(&spt, 1, 4, f); + fread(&hpc, 1, 4, f); + fread(&tracks, 1, 4, f); + } + else + { + fseeko64(f, 0, SEEK_END); + size = ftello64(f); + fclose(f); + if (((size % 17) == 0) && (size <= 133693440)) + { + spt = 17; + if (size <= 26738688) + { + hpc = 4; + } + else if (size <= 53477376) + { + hpc = 6; + } + else if (size <= 71303168) + { + hpc = 8; + } + else + { + hpc = 15; + } + } + else + { + spt = 63; + hpc = 16; + } + + tracks = ((size >> 9) / hpc) / spt; + } + + if ((spt > max_spt) || (hpc > max_hpc) || (tracks > max_tracks)) + { + goto hdd_add_file_open_error; + } + no_update = 1; + + set_edit_box_contents(hdlg, IDC_EDIT_HD_SPT, spt); + set_edit_box_contents(hdlg, IDC_EDIT_HD_HPC, hpc); + set_edit_box_contents(hdlg, IDC_EDIT_HD_CYL, tracks); + set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, size >> 20); + recalc_selection(hdlg); + + h = GetDlgItem(hdlg, IDC_EDIT_HD_SPT); + EnableWindow(h, TRUE); + h = GetDlgItem(hdlg, IDC_EDIT_HD_HPC); + EnableWindow(h, TRUE); + h = GetDlgItem(hdlg, IDC_EDIT_HD_CYL); + EnableWindow(h, TRUE); + h = GetDlgItem(hdlg, IDC_EDIT_HD_SIZE); + EnableWindow(h, TRUE); + h = GetDlgItem(hdlg, IDC_COMBO_HD_TYPE); + EnableWindow(h, TRUE); + + chs_enabled = 1; + + no_update = 0; + } + else + { + fclose(f); + } + } + + h = GetDlgItem(hdlg, IDC_EDIT_HD_FILE_NAME); + SendMessage(h, WM_SETTEXT, 0, (LPARAM) wopenfilestring); + memset(hd_file_name, 0, sizeof(hd_file_name)); + wcscpy(hd_file_name, wopenfilestring); + + return TRUE; + + case IDC_EDIT_HD_CYL: + if (no_update) + { + return FALSE; + } + + no_update = 1; + get_edit_box_contents(hdlg, IDC_EDIT_HD_CYL, &temp); + if (temp != tracks) + { + tracks = temp; + size = (tracks * hpc * spt) << 9; + set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, size >> 20); + recalc_selection(hdlg); + } + + if (tracks > max_tracks) + { + tracks = max_tracks; + size = (tracks * hpc * spt) << 9; + set_edit_box_contents(hdlg, IDC_EDIT_HD_CYL, tracks); + set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, (size >> 20)); + recalc_selection(hdlg); + } + + no_update = 0; + break; + + case IDC_EDIT_HD_HPC: + if (no_update) + { + return FALSE; + } + + no_update = 1; + get_edit_box_contents(hdlg, IDC_EDIT_HD_HPC, &temp); + if (temp != hpc) + { + hpc = temp; + size = (tracks * hpc * spt) << 9; + set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, size >> 20); + recalc_selection(hdlg); + } + + if (hpc > max_hpc) + { + hpc = max_hpc; + size = (tracks * hpc * spt) << 9; + set_edit_box_contents(hdlg, IDC_EDIT_HD_HPC, hpc); + set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, (size >> 20)); + recalc_selection(hdlg); + } + + no_update = 0; + break; + + case IDC_EDIT_HD_SPT: + if (no_update) + { + return FALSE; + } + + no_update = 1; + get_edit_box_contents(hdlg, IDC_EDIT_HD_SPT, &temp); + if (temp != spt) + { + spt = temp; + size = (tracks * hpc * spt) << 9; + set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, size >> 20); + recalc_selection(hdlg); + } + + if (spt > max_spt) + { + spt = max_spt; + size = (tracks * hpc * spt) << 9; + set_edit_box_contents(hdlg, IDC_EDIT_HD_SPT, spt); + set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, (size >> 20)); + recalc_selection(hdlg); + } + + no_update = 0; + break; + + case IDC_EDIT_HD_SIZE: + if (no_update) + { + return FALSE; + } + + no_update = 1; + get_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, &temp); + if (temp != (size >> 20)) + { + size = temp << 20; + tracks = ((size >> 9) / hpc) / spt; + set_edit_box_contents(hdlg, IDC_EDIT_HD_CYL, tracks); + recalc_selection(hdlg); + } + + if (tracks > max_tracks) + { + tracks = max_tracks; + size = (tracks * hpc * spt) << 9; + set_edit_box_contents(hdlg, IDC_EDIT_HD_CYL, tracks); + set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, (size >> 20)); + recalc_selection(hdlg); + } + + no_update = 0; + break; + + case IDC_COMBO_HD_TYPE: + if (no_update) + { + return FALSE; + } + + no_update = 1; + get_combo_box_selection(hdlg, IDC_COMBO_HD_TYPE, &temp); + if ((temp != selection) && (temp != 127) && (temp != 128)) + { + selection = temp; + tracks = hdt[selection][0]; + hpc = hdt[selection][1]; + spt = hdt[selection][2]; + size = (tracks * hpc * spt) << 9; + set_edit_box_contents(hdlg, IDC_EDIT_HD_CYL, tracks); + set_edit_box_contents(hdlg, IDC_EDIT_HD_HPC, hpc); + set_edit_box_contents(hdlg, IDC_EDIT_HD_SPT, spt); + set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, size >> 20); + } + else if ((temp != selection) && (temp == 127)) + { + selection = temp; + } + else if ((temp != selection) && (temp == 128)) + { + selection = temp; + hpc = 16; + spt = 63; + size = (tracks * hpc * spt) << 9; + set_edit_box_contents(hdlg, IDC_EDIT_HD_HPC, hpc); + set_edit_box_contents(hdlg, IDC_EDIT_HD_SPT, spt); + set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, size >> 20); + } + + if (spt > max_spt) + { + spt = max_spt; + size = (tracks * hpc * spt) << 9; + set_edit_box_contents(hdlg, IDC_EDIT_HD_SPT, spt); + set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, (size >> 20)); + recalc_selection(hdlg); + } + + if (hpc > max_hpc) + { + hpc = max_hpc; + size = (tracks * hpc * spt) << 9; + set_edit_box_contents(hdlg, IDC_EDIT_HD_HPC, hpc); + set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, (size >> 20)); + recalc_selection(hdlg); + } + + if (tracks > max_tracks) + { + tracks = max_tracks; + size = (tracks * hpc * spt) << 9; + set_edit_box_contents(hdlg, IDC_EDIT_HD_CYL, tracks); + set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, (size >> 20)); + recalc_selection(hdlg); + } + + no_update = 0; + break; + + case IDC_COMBO_HD_BUS: + if (no_update) + { + return FALSE; + } + + no_update = 1; + recalc_location_controls(hdlg, 1); + h = GetDlgItem(hdlg, IDC_COMBO_HD_BUS); + b = SendMessage(h,CB_GETCURSEL,0,0) + 1; + if (b == hdc_ptr->bus) + { + goto hd_add_bus_skip; + } + + hdc_ptr->bus = b; + + switch(hdc_ptr->bus) + { + case HDD_BUS_DISABLED: + default: + max_spt = max_hpc = max_tracks = 0; + break; + case HDD_BUS_MFM: + max_spt = 17; + max_hpc = 15; + max_tracks = 1023; + break; + case HDD_BUS_RLL: + case HDD_BUS_XTIDE: + max_spt = 63; + max_hpc = 16; + max_tracks = 1023; + break; + case HDD_BUS_IDE_PIO_ONLY: + case HDD_BUS_IDE_PIO_AND_DMA: + max_spt = 63; + max_hpc = 16; + max_tracks = 266305; + break; + case HDD_BUS_SCSI_REMOVABLE: + if (spt == 0) + { + spt = 63; + size = (tracks * hpc * spt) << 9; + set_edit_box_contents(hdlg, IDC_EDIT_HD_SPT, spt); + set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, (size >> 20)); + } + if (hpc == 0) + { + hpc = 16; + size = (tracks * hpc * spt) << 9; + set_edit_box_contents(hdlg, IDC_EDIT_HD_HPC, hpc); + set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, (size >> 20)); + } + if (tracks == 0) + { + tracks = 1023; + size = (tracks * hpc * spt) << 9; + set_edit_box_contents(hdlg, IDC_EDIT_HD_CYL, tracks); + set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, (size >> 20)); + } + case HDD_BUS_SCSI: + max_spt = 99; + max_hpc = 255; + max_tracks = 266305; + break; + } + + if ((hdc_ptr->bus == HDD_BUS_SCSI_REMOVABLE) && !chs_enabled) + { + h = GetDlgItem(hdlg, IDC_EDIT_HD_SPT); + EnableWindow(h, TRUE); + h = GetDlgItem(hdlg, IDC_EDIT_HD_HPC); + EnableWindow(h, TRUE); + h = GetDlgItem(hdlg, IDC_EDIT_HD_CYL); + EnableWindow(h, TRUE); + h = GetDlgItem(hdlg, IDC_EDIT_HD_SIZE); + EnableWindow(h, TRUE); + h = GetDlgItem(hdlg, IDC_COMBO_HD_TYPE); + EnableWindow(h, TRUE); + } + else if ((hdc_ptr->bus != HDD_BUS_SCSI_REMOVABLE) && !chs_enabled) + { + h = GetDlgItem(hdlg, IDC_EDIT_HD_SPT); + EnableWindow(h, FALSE); + h = GetDlgItem(hdlg, IDC_EDIT_HD_HPC); + EnableWindow(h, FALSE); + h = GetDlgItem(hdlg, IDC_EDIT_HD_CYL); + EnableWindow(h, FALSE); + h = GetDlgItem(hdlg, IDC_EDIT_HD_SIZE); + EnableWindow(h, FALSE); + h = GetDlgItem(hdlg, IDC_COMBO_HD_TYPE); + EnableWindow(h, FALSE); + } + + if (spt > max_spt) + { + spt = max_spt; + size = (tracks * hpc * spt) << 9; + set_edit_box_contents(hdlg, IDC_EDIT_HD_SPT, spt); + set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, (size >> 20)); + recalc_selection(hdlg); + } + + if (hpc > max_hpc) + { + hpc = max_hpc; + size = (tracks * hpc * spt) << 9; + set_edit_box_contents(hdlg, IDC_EDIT_HD_HPC, hpc); + set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, (size >> 20)); + recalc_selection(hdlg); + } + + if (tracks > max_tracks) + { + tracks = max_tracks; + size = (tracks * hpc * spt) << 9; + set_edit_box_contents(hdlg, IDC_EDIT_HD_CYL, tracks); + set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, (size >> 20)); + recalc_selection(hdlg); + } + +hd_add_bus_skip: + no_update = 0; + break; + } + + return FALSE; + } + + return FALSE; +} + +int hard_disk_was_added(void) +{ + return hard_disk_added; +} + +void hard_disk_add_open(HWND hwnd, int is_existing) +{ + existing = is_existing; + hard_disk_added = 0; + DialogBox(hinstance, (LPCWSTR)DLG_CFG_HARD_DISKS_ADD, hwnd, win_settings_hard_disks_add_proc); +} + +int ignore_change = 0; + +static BOOL CALLBACK win_settings_hard_disks_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + HWND h; + int old_sel = 0; + int b = 0; + + switch (message) + { + case WM_INITDIALOG: + ignore_change = 1; + + normalize_hd_list(); /* Normalize the hard disks so that non-disabled hard disks start from index 0, and so they are contiguous. + This will cause an emulator reset prompt on the first opening of this category with a messy hard disk list + (which can only happen by manually editing the configuration file). */ + h = GetDlgItem(hdlg, IDC_LIST_HARD_DISKS); + win_settings_hard_disks_init_columns(h); + win_settings_hard_disks_image_list_init(h); + win_settings_hard_disks_recalc_list(h); + recalc_next_free_id(hdlg); + add_locations(hdlg); + if (hd_listview_items > 0) + { + ListView_SetItemState(h, 0, LVIS_FOCUSED | LVIS_SELECTED, 0x000F); + hdlv_current_sel = 0; + h = GetDlgItem(hdlg, IDC_COMBO_HD_BUS); + SendMessage(h, CB_SETCURSEL, temp_hdc[0].bus - 1, 0); + } + else + { + hdlv_current_sel = -1; + } + recalc_location_controls(hdlg, 0); + + ignore_change = 0; + return TRUE; + + case WM_NOTIFY: + if ((hd_listview_items == 0) || ignore_change) + { + return FALSE; + } + + if ((((LPNMHDR)lParam)->code == LVN_ITEMCHANGED) && (((LPNMHDR)lParam)->idFrom == IDC_LIST_HARD_DISKS)) + { + old_sel = hdlv_current_sel; + hdlv_current_sel = get_selected_hard_disk(hdlg); + if (hdlv_current_sel == old_sel) + { + return FALSE; + } + else if (hdlv_current_sel == -1) + { + ignore_change = 1; + hdlv_current_sel = old_sel; + ListView_SetItemState(h, hdlv_current_sel, LVIS_FOCUSED | LVIS_SELECTED, 0x000F); + ignore_change = 0; + return FALSE; + } + ignore_change = 1; + h = GetDlgItem(hdlg, IDC_COMBO_HD_BUS); + SendMessage(h, CB_SETCURSEL, temp_hdc[hdlv_current_sel].bus - 1, 0); + recalc_location_controls(hdlg, 0); + ignore_change = 0; + } + break; + + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case IDC_COMBO_HD_BUS: + if (ignore_change) + { + return FALSE; + } + + ignore_change = 1; + h = GetDlgItem(hdlg, IDC_COMBO_HD_BUS); + b = SendMessage(h, CB_GETCURSEL, 0, 0) + 1; + if (b == temp_hdc[hdlv_current_sel].bus) + { + goto hd_bus_skip; + } + temp_hdc[hdlv_current_sel].bus = b; + recalc_location_controls(hdlg, 0); + h = GetDlgItem(hdlg, IDC_LIST_HARD_DISKS); + win_settings_hard_disks_update_item(h, hdlv_current_sel, 0); +hd_bus_skip: + ignore_change = 0; + return FALSE; + + case IDC_COMBO_HD_CHANNEL: + if (ignore_change) + { + return FALSE; + } + + ignore_change = 1; + h = GetDlgItem(hdlg, IDC_COMBO_HD_CHANNEL); + if (temp_hdc[hdlv_current_sel].bus == HDD_BUS_MFM) + { + temp_hdc[hdlv_current_sel].mfm_channel = SendMessage(h, CB_GETCURSEL, 0, 0); + } + else if (temp_hdc[hdlv_current_sel].bus == HDD_BUS_RLL) + { + temp_hdc[hdlv_current_sel].rll_channel = SendMessage(h, CB_GETCURSEL, 0, 0); + } + else if (temp_hdc[hdlv_current_sel].bus == HDD_BUS_XTIDE) + { + temp_hdc[hdlv_current_sel].xtide_channel = SendMessage(h, CB_GETCURSEL, 0, 0); + } + h = GetDlgItem(hdlg, IDC_LIST_HARD_DISKS); + win_settings_hard_disks_update_item(h, hdlv_current_sel, 0); + ignore_change = 0; + return FALSE; + + case IDC_COMBO_HD_CHANNEL_IDE: + if (ignore_change) + { + return FALSE; + } + + ignore_change = 1; + h = GetDlgItem(hdlg, IDC_COMBO_HD_CHANNEL_IDE); + temp_hdc[hdlv_current_sel].ide_channel = SendMessage(h, CB_GETCURSEL, 0, 0); + h = GetDlgItem(hdlg, IDC_LIST_HARD_DISKS); + win_settings_hard_disks_update_item(h, hdlv_current_sel, 0); + ignore_change = 0; + return FALSE; + + case IDC_COMBO_HD_ID: + if (ignore_change) + { + return FALSE; + } + + ignore_change = 1; + h = GetDlgItem(hdlg, IDC_COMBO_HD_ID); + temp_hdc[hdlv_current_sel].scsi_id = SendMessage(h, CB_GETCURSEL, 0, 0); + h = GetDlgItem(hdlg, IDC_LIST_HARD_DISKS); + win_settings_hard_disks_update_item(h, hdlv_current_sel, 0); + ignore_change = 0; + return FALSE; + + case IDC_COMBO_HD_LUN: + if (ignore_change) + { + return FALSE; + } + + ignore_change = 1; + h = GetDlgItem(hdlg, IDC_COMBO_HD_LUN); + temp_hdc[hdlv_current_sel].scsi_lun = SendMessage(h, CB_GETCURSEL, 0, 0); + h = GetDlgItem(hdlg, IDC_LIST_HARD_DISKS); + win_settings_hard_disks_update_item(h, hdlv_current_sel, 0); + ignore_change = 0; + return FALSE; + + case IDC_BUTTON_HDD_ADD: + hard_disk_add_open(hdlg, 1); + if (hard_disk_added) + { + ignore_change = 1; + h = GetDlgItem(hdlg, IDC_LIST_HARD_DISKS); + win_settings_hard_disks_recalc_list(h); + recalc_next_free_id(hdlg); + ignore_change = 0; + } + return FALSE; + + case IDC_BUTTON_HDD_ADD_NEW: + hard_disk_add_open(hdlg, 0); + if (hard_disk_added) + { + ignore_change = 1; + h = GetDlgItem(hdlg, IDC_LIST_HARD_DISKS); + win_settings_hard_disks_recalc_list(h); + recalc_next_free_id(hdlg); + ignore_change = 0; + } + return FALSE; + + case IDC_BUTTON_HDD_REMOVE: + memcpy(temp_hdc[hdlv_current_sel].fn, L"", 4); + temp_hdc[hdlv_current_sel].bus = HDD_BUS_DISABLED; /* Only set the bus to zero, the list normalize code below will take care of turning this entire entry to a complete zero. */ + normalize_hd_list(); /* Normalize the hard disks so that non-disabled hard disks start from index 0, and so they are contiguous. */ + ignore_change = 1; + h = GetDlgItem(hdlg, IDC_LIST_HARD_DISKS); + win_settings_hard_disks_recalc_list(h); + recalc_next_free_id(hdlg); + if (hd_listview_items > 0) + { + ListView_SetItemState(h, 0, LVIS_FOCUSED | LVIS_SELECTED, 0x000F); + hdlv_current_sel = 0; + h = GetDlgItem(hdlg, IDC_COMBO_HD_BUS); + SendMessage(h, CB_SETCURSEL, temp_hdc[0].bus - 1, 0); + } + else + { + hdlv_current_sel = -1; + } + recalc_location_controls(hdlg, 0); + ignore_change = 0; + return FALSE; + } + + default: + return FALSE; + } + + return FALSE; +} + +int fdlv_current_sel; +int cdlv_current_sel; + +static int combo_id_to_string_id(int combo_id) +{ + switch (combo_id) + { + case CDROM_BUS_DISABLED: /* Disabled */ + default: + return 2151; + break; + case CDROM_BUS_ATAPI_PIO_ONLY: /* Atapi (PIO-only) */ + return 2189; + break; + case CDROM_BUS_ATAPI_PIO_AND_DMA: /* Atapi (PIA and DMA) */ + return 2190; + break; + case CDROM_BUS_SCSI: /* SCSI */ + return 2210; + break; + } +} + +static int combo_id_to_format_string_id(int combo_id) +{ + switch (combo_id) + { + case CDROM_BUS_DISABLED: /* Disabled */ + default: + return 2151; + break; + case CDROM_BUS_ATAPI_PIO_ONLY: /* Atapi (PIO-only) */ + return 2191; + break; + case CDROM_BUS_ATAPI_PIO_AND_DMA: /* Atapi (PIA and DMA) */ + return 2192; + break; + case CDROM_BUS_SCSI: /* SCSI */ + return 2158; + break; + } +} + +static BOOL win_settings_floppy_drives_image_list_init(HWND hwndList) +{ + HICON hiconItem; + HIMAGELIST hSmall; + + int i = 0; + + hSmall = ImageList_Create(GetSystemMetrics(SM_CXSMICON), + GetSystemMetrics(SM_CYSMICON), + ILC_MASK | ILC_COLOR32, 1, 1); + + for (i = 0; i < 14; i++) + { + hiconItem = LoadIcon(hinstance, (LPCWSTR) fdd_type_to_icon(i)); + ImageList_AddIcon(hSmall, hiconItem); + DestroyIcon(hiconItem); + } + + ListView_SetImageList(hwndList, hSmall, LVSIL_SMALL); + + return TRUE; +} + +static BOOL win_settings_cdrom_drives_image_list_init(HWND hwndList) +{ + HICON hiconItem; + HIMAGELIST hSmall; + + hSmall = ImageList_Create(GetSystemMetrics(SM_CXSMICON), + GetSystemMetrics(SM_CYSMICON), + ILC_MASK | ILC_COLOR32, 1, 1); + + hiconItem = LoadIcon(hinstance, (LPCWSTR) 514); + ImageList_AddIcon(hSmall, hiconItem); + DestroyIcon(hiconItem); + + hiconItem = LoadIcon(hinstance, (LPCWSTR) 160); + ImageList_AddIcon(hSmall, hiconItem); + DestroyIcon(hiconItem); + + hiconItem = LoadIcon(hinstance, (LPCWSTR) 162); + ImageList_AddIcon(hSmall, hiconItem); + DestroyIcon(hiconItem); + + hiconItem = LoadIcon(hinstance, (LPCWSTR) 164); + ImageList_AddIcon(hSmall, hiconItem); + DestroyIcon(hiconItem); + + ListView_SetImageList(hwndList, hSmall, LVSIL_SMALL); + + return TRUE; +} + +static BOOL win_settings_floppy_drives_recalc_list(HWND hwndList) +{ + LVITEM lvI; + int i = 0; + char s[256]; + WCHAR szText[256]; + + lvI.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE; + lvI.stateMask = lvI.state = 0; + + for (i = 0; i < 4; i++) + { + lvI.iSubItem = 0; + if (temp_fdd_types[i] > 0) + { + strcpy(s, fdd_getname(temp_fdd_types[i])); + mbstowcs(szText, s, strlen(s) + 1); + lvI.pszText = szText; + } + else + { + lvI.pszText = win_language_get_string_from_id(2151); + } + lvI.iItem = i; + lvI.iImage = temp_fdd_types[i]; + + if (ListView_InsertItem(hwndList, &lvI) == -1) + return FALSE; + + lvI.iSubItem = 1; + lvI.pszText = win_language_get_string_from_id(temp_fdd_turbo[i] ? 2222 : 2223); + lvI.iItem = i; + lvI.iImage = 0; + + if (ListView_SetItem(hwndList, &lvI) == -1) + { + return FALSE; + } + } + + return TRUE; +} + +static BOOL win_settings_cdrom_drives_recalc_list(HWND hwndList) +{ + LVITEM lvI; + int i = 0; + WCHAR szText[256]; + int fsid = 0; + + lvI.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE; + lvI.stateMask = lvI.iSubItem = lvI.state = 0; + + for (i = 0; i < 4; i++) + { + fsid = combo_id_to_format_string_id(temp_cdrom_drives[i].bus_type); + + switch (temp_cdrom_drives[i].bus_type) + { + case CDROM_BUS_DISABLED: + default: + lvI.pszText = win_language_get_string_from_id(fsid); + lvI.iImage = 0; + break; + case CDROM_BUS_ATAPI_PIO_ONLY: + wsprintf(szText, win_language_get_string_from_id(fsid), temp_cdrom_drives[i].ide_channel >> 1, temp_cdrom_drives[i].ide_channel & 1); + lvI.pszText = szText; + lvI.iImage = 1; + break; + case CDROM_BUS_ATAPI_PIO_AND_DMA: + wsprintf(szText, win_language_get_string_from_id(fsid), temp_cdrom_drives[i].ide_channel >> 1, temp_cdrom_drives[i].ide_channel & 1); + lvI.pszText = szText; + lvI.iImage = 2; + break; + case CDROM_BUS_SCSI: + wsprintf(szText, win_language_get_string_from_id(fsid), temp_cdrom_drives[i].scsi_device_id, temp_cdrom_drives[i].scsi_device_lun); + lvI.pszText = szText; + lvI.iImage = 3; + break; + } + + lvI.iItem = i; + + if (ListView_InsertItem(hwndList, &lvI) == -1) + return FALSE; + } + + return TRUE; +} + +static BOOL win_settings_floppy_drives_init_columns(HWND hwndList) +{ + LVCOLUMN lvc; + + lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM; + + lvc.iSubItem = 0; + lvc.pszText = win_language_get_string_from_id(2188); + + lvc.cx = 292; + lvc.fmt = LVCFMT_LEFT; + + if (ListView_InsertColumn(hwndList, 0, &lvc) == -1) + { + return FALSE; + } + + lvc.iSubItem = 1; + lvc.pszText = win_language_get_string_from_id(2221); + + lvc.cx = 100; + lvc.fmt = LVCFMT_LEFT; + + if (ListView_InsertColumn(hwndList, 1, &lvc) == -1) + { + return FALSE; + } + + return TRUE; +} + +static BOOL win_settings_cdrom_drives_init_columns(HWND hwndList) +{ + LVCOLUMN lvc; + + lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM; + + lvc.iSubItem = 0; + lvc.pszText = win_language_get_string_from_id(2082); + + lvc.cx = 392; + lvc.fmt = LVCFMT_LEFT; + + if (ListView_InsertColumn(hwndList, 0, &lvc) == -1) + { + return FALSE; + } + + return TRUE; +} + +static int get_selected_floppy_drive(HWND hdlg) +{ + int floppy_drive = -1; + int i, j = 0; + HWND h; + + for (i = 0; i < 6; i++) + { + h = GetDlgItem(hdlg, IDC_LIST_FLOPPY_DRIVES); + j = ListView_GetItemState(h, i, LVIS_SELECTED); + if (j) + { + floppy_drive = i; + } + } + + return floppy_drive; +} + +static int get_selected_cdrom_drive(HWND hdlg) +{ + int cd_drive = -1; + int i, j = 0; + HWND h; + + for (i = 0; i < 6; i++) + { + h = GetDlgItem(hdlg, IDC_LIST_CDROM_DRIVES); + j = ListView_GetItemState(h, i, LVIS_SELECTED); + if (j) + { + cd_drive = i; + } + } + + return cd_drive; +} + +static void win_settings_floppy_drives_update_item(HWND hwndList, int i) +{ + LVITEM lvI; + char s[256]; + WCHAR szText[256]; + + lvI.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE; + lvI.stateMask = lvI.iSubItem = lvI.state = 0; + + lvI.iSubItem = 0; + lvI.iItem = i; + + if (temp_fdd_types[i] > 0) + { + strcpy(s, fdd_getname(temp_fdd_types[i])); + mbstowcs(szText, s, strlen(s) + 1); + lvI.pszText = szText; + } + else + { + lvI.pszText = win_language_get_string_from_id(2151); + } + lvI.iImage = temp_fdd_types[i]; + + if (ListView_SetItem(hwndList, &lvI) == -1) + { + return; + } + + lvI.iSubItem = 1; + lvI.pszText = win_language_get_string_from_id(temp_fdd_turbo[i] ? 2222 : 2223); + lvI.iItem = i; + lvI.iImage = 0; + + if (ListView_SetItem(hwndList, &lvI) == -1) + { + return; + } +} + +static void win_settings_cdrom_drives_update_item(HWND hwndList, int i) +{ + LVITEM lvI; + WCHAR szText[256]; + int fsid; + + lvI.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE; + lvI.stateMask = lvI.iSubItem = lvI.state = 0; + + lvI.iSubItem = 0; + lvI.iItem = i; + + fsid = combo_id_to_format_string_id(temp_cdrom_drives[i].bus_type); + + switch (temp_cdrom_drives[i].bus_type) + { + case CDROM_BUS_DISABLED: + default: + lvI.pszText = win_language_get_string_from_id(fsid); + lvI.iImage = 0; + break; + case CDROM_BUS_ATAPI_PIO_ONLY: + wsprintf(szText, win_language_get_string_from_id(fsid), temp_cdrom_drives[i].ide_channel >> 1, temp_cdrom_drives[i].ide_channel & 1); + lvI.pszText = szText; + lvI.iImage = 1; + break; + case CDROM_BUS_ATAPI_PIO_AND_DMA: + wsprintf(szText, win_language_get_string_from_id(fsid), temp_cdrom_drives[i].ide_channel >> 1, temp_cdrom_drives[i].ide_channel & 1); + lvI.pszText = szText; + lvI.iImage = 2; + break; + case CDROM_BUS_SCSI: + wsprintf(szText, win_language_get_string_from_id(fsid), temp_cdrom_drives[i].scsi_device_id, temp_cdrom_drives[i].scsi_device_lun); + lvI.pszText = szText; + lvI.iImage = 3; + break; + } + + if (ListView_SetItem(hwndList, &lvI) == -1) + { + return; + } +} + +static void cdrom_add_locations(HWND hdlg) +{ + LPTSTR lptsTemp; + HWND h; + int i = 0; + + lptsTemp = (LPTSTR) malloc(512); + + h = GetDlgItem(hdlg, IDC_COMBO_CD_BUS); + for (i = CDROM_BUS_DISABLED; i <= CDROM_BUS_SCSI; i++) + { + if ((i == CDROM_BUS_DISABLED) || (i >= CDROM_BUS_ATAPI_PIO_ONLY)) + { + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) win_language_get_string_from_id(combo_id_to_string_id(i))); + } + } + + h = GetDlgItem(hdlg, IDC_COMBO_CD_ID); + for (i = 0; i < 16; i++) + { + wsprintf(lptsTemp, win_language_get_string_from_id(2088), i); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) lptsTemp); + } + + h = GetDlgItem(hdlg, IDC_COMBO_CD_LUN); + for (i = 0; i < 8; i++) + { + wsprintf(lptsTemp, win_language_get_string_from_id(2088), i); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) lptsTemp); + } + + h = GetDlgItem(hdlg, IDC_COMBO_CD_CHANNEL_IDE); + for (i = 0; i < 8; i++) + { + wsprintf(lptsTemp, win_language_get_string_from_id(2169), i >> 1, i & 1); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) lptsTemp); + } + + free(lptsTemp); +} +static void cdrom_recalc_location_controls(HWND hdlg) +{ + int i = 0; + HWND h; + + int bus = temp_cdrom_drives[cdlv_current_sel].bus_type; + + for (i = IDT_1741; i < (IDT_1743 + 1); i++) + { + h = GetDlgItem(hdlg, i); + EnableWindow(h, FALSE); + ShowWindow(h, SW_HIDE); + } + + h = GetDlgItem(hdlg, IDC_COMBO_CD_ID); + EnableWindow(h, FALSE); + ShowWindow(h, SW_HIDE); + + h = GetDlgItem(hdlg, IDC_COMBO_CD_LUN); + EnableWindow(h, FALSE); + ShowWindow(h, SW_HIDE); + + h = GetDlgItem(hdlg, IDC_COMBO_CD_CHANNEL_IDE); + EnableWindow(h, FALSE); + ShowWindow(h, SW_HIDE); + + switch(bus) + { + case CDROM_BUS_ATAPI_PIO_ONLY: /* ATAPI (PIO-only) */ + case CDROM_BUS_ATAPI_PIO_AND_DMA: /* ATAPI (PIO and DMA) */ + h = GetDlgItem(hdlg, IDT_1743); + ShowWindow(h, SW_SHOW); + EnableWindow(h, TRUE); + + h = GetDlgItem(hdlg, IDC_COMBO_CD_CHANNEL_IDE); + ShowWindow(h, SW_SHOW); + EnableWindow(h, TRUE); + SendMessage(h, CB_SETCURSEL, temp_cdrom_drives[cdlv_current_sel].ide_channel, 0); + break; + case CDROM_BUS_SCSI: /* SCSI */ + h = GetDlgItem(hdlg, IDT_1741); + ShowWindow(h, SW_SHOW); + EnableWindow(h, TRUE); + h = GetDlgItem(hdlg, IDT_1742); + ShowWindow(h, SW_SHOW); + EnableWindow(h, TRUE); + + h = GetDlgItem(hdlg, IDC_COMBO_CD_ID); + ShowWindow(h, SW_SHOW); + EnableWindow(h, TRUE); + SendMessage(h, CB_SETCURSEL, temp_cdrom_drives[cdlv_current_sel].scsi_device_id, 0); + + h = GetDlgItem(hdlg, IDC_COMBO_CD_LUN); + ShowWindow(h, SW_SHOW); + EnableWindow(h, TRUE); + SendMessage(h, CB_SETCURSEL, temp_cdrom_drives[cdlv_current_sel].scsi_device_lun, 0); + break; + } +} + + +int rd_ignore_change = 0; + +static BOOL CALLBACK win_settings_removable_devices_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + HWND h; + int i = 0; + int old_sel = 0; + int b = 0; + int b2 = 0; + WCHAR szText[256]; + + switch (message) + { + case WM_INITDIALOG: + rd_ignore_change = 1; + + fdlv_current_sel = 0; + h = GetDlgItem(hdlg, IDC_LIST_FLOPPY_DRIVES); + win_settings_floppy_drives_init_columns(h); + win_settings_floppy_drives_image_list_init(h); + win_settings_floppy_drives_recalc_list(h); + ListView_SetItemState(h, 0, LVIS_FOCUSED | LVIS_SELECTED, 0x000F); + h = GetDlgItem(hdlg, IDC_COMBO_FD_TYPE); + for (i = 0; i < 14; i++) + { + if (i == 0) + { + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) win_language_get_string_from_id(2151)); + } + else + { + mbstowcs(szText, fdd_getname(i), strlen(fdd_getname(i)) + 1); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) szText); + } + } + SendMessage(h, CB_SETCURSEL, temp_fdd_types[fdlv_current_sel], 0); + + h = GetDlgItem(hdlg, IDC_CHECKTURBO); + SendMessage(h, BM_SETCHECK, temp_fdd_turbo[fdlv_current_sel], 0); + + cdlv_current_sel = 0; + h = GetDlgItem(hdlg, IDC_LIST_CDROM_DRIVES); + win_settings_cdrom_drives_init_columns(h); + win_settings_cdrom_drives_image_list_init(h); + win_settings_cdrom_drives_recalc_list(h); + ListView_SetItemState(h, 0, LVIS_FOCUSED | LVIS_SELECTED, 0x000F); + cdrom_add_locations(hdlg); + + h = GetDlgItem(hdlg, IDC_COMBO_CD_BUS); + + switch (temp_cdrom_drives[cdlv_current_sel].bus_type) + { + case CDROM_BUS_DISABLED: + default: + b = 0; + break; + case CDROM_BUS_ATAPI_PIO_ONLY: + b = 1; + break; + case CDROM_BUS_ATAPI_PIO_AND_DMA: + b = 2; + break; + case CDROM_BUS_SCSI: + b = 3; + break; + } + + SendMessage(h, CB_SETCURSEL, b, 0); + + cdrom_recalc_location_controls(hdlg); + + rd_ignore_change = 0; + return TRUE; + + case WM_NOTIFY: + if (rd_ignore_change) + { + return FALSE; + } + + if ((((LPNMHDR)lParam)->code == LVN_ITEMCHANGED) && (((LPNMHDR)lParam)->idFrom == IDC_LIST_FLOPPY_DRIVES)) + { + old_sel = fdlv_current_sel; + fdlv_current_sel = get_selected_floppy_drive(hdlg); + if (fdlv_current_sel == old_sel) + { + return FALSE; + } + else if (fdlv_current_sel == -1) + { + rd_ignore_change = 1; + fdlv_current_sel = old_sel; + ListView_SetItemState(h, fdlv_current_sel, LVIS_FOCUSED | LVIS_SELECTED, 0x000F); + rd_ignore_change = 0; + return FALSE; + } + rd_ignore_change = 1; + h = GetDlgItem(hdlg, IDC_COMBO_FD_TYPE); + SendMessage(h, CB_SETCURSEL, temp_fdd_types[fdlv_current_sel], 0); + h = GetDlgItem(hdlg, IDC_CHECKTURBO); + SendMessage(h, BM_SETCHECK, temp_fdd_turbo[fdlv_current_sel], 0); + rd_ignore_change = 0; + } + else if ((((LPNMHDR)lParam)->code == LVN_ITEMCHANGED) && (((LPNMHDR)lParam)->idFrom == IDC_LIST_CDROM_DRIVES)) + { + old_sel = cdlv_current_sel; + cdlv_current_sel = get_selected_cdrom_drive(hdlg); + if (cdlv_current_sel == old_sel) + { + return FALSE; + } + else if (cdlv_current_sel == -1) + { + rd_ignore_change = 1; + cdlv_current_sel = old_sel; + ListView_SetItemState(h, cdlv_current_sel, LVIS_FOCUSED | LVIS_SELECTED, 0x000F); + rd_ignore_change = 0; + return FALSE; + } + rd_ignore_change = 1; + + h = GetDlgItem(hdlg, IDC_COMBO_CD_BUS); + + switch (temp_cdrom_drives[cdlv_current_sel].bus_type) + { + case CDROM_BUS_DISABLED: + default: + b = 0; + break; + case CDROM_BUS_ATAPI_PIO_ONLY: + b = 1; + break; + case CDROM_BUS_ATAPI_PIO_AND_DMA: + b = 2; + break; + case CDROM_BUS_SCSI: + b = 3; + break; + } + + SendMessage(h, CB_SETCURSEL, b, 0); + + cdrom_recalc_location_controls(hdlg); + rd_ignore_change = 0; + } + break; + + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case IDC_COMBO_FD_TYPE: + if (rd_ignore_change) + { + return FALSE; + } + + rd_ignore_change = 1; + h = GetDlgItem(hdlg, IDC_COMBO_FD_TYPE); + temp_fdd_types[fdlv_current_sel] = SendMessage(h, CB_GETCURSEL, 0, 0); + h = GetDlgItem(hdlg, IDC_LIST_FLOPPY_DRIVES); + win_settings_floppy_drives_update_item(h, fdlv_current_sel); + rd_ignore_change = 0; + return FALSE; + + case IDC_CHECKTURBO: + if (rd_ignore_change) + { + return FALSE; + } + + rd_ignore_change = 1; + h = GetDlgItem(hdlg, IDC_CHECKTURBO); + temp_fdd_turbo[fdlv_current_sel] = SendMessage(h, BM_GETCHECK, 0, 0); + h = GetDlgItem(hdlg, IDC_LIST_FLOPPY_DRIVES); + win_settings_floppy_drives_update_item(h, fdlv_current_sel); + rd_ignore_change = 0; + return FALSE; + + case IDC_COMBO_CD_BUS: + if (rd_ignore_change) + { + return FALSE; + } + + rd_ignore_change = 1; + h = GetDlgItem(hdlg, IDC_COMBO_CD_BUS); + b = SendMessage(h, CB_GETCURSEL, 0, 0); + switch (b) + { + case 0: + b2 = CDROM_BUS_DISABLED; + break; + case 1: + b2 = CDROM_BUS_ATAPI_PIO_ONLY; + break; + case 2: + b2 = CDROM_BUS_ATAPI_PIO_AND_DMA; + break; + case 3: + b2 = CDROM_BUS_SCSI; + break; + } + if (b2 == temp_cdrom_drives[cdlv_current_sel].bus_type) + { + goto cdrom_bus_skip; + } + temp_cdrom_drives[cdlv_current_sel].bus_type = b2; + cdrom_recalc_location_controls(hdlg); + h = GetDlgItem(hdlg, IDC_LIST_CDROM_DRIVES); + win_settings_cdrom_drives_update_item(h, cdlv_current_sel); +cdrom_bus_skip: + rd_ignore_change = 0; + return FALSE; + + case IDC_COMBO_CD_ID: + if (rd_ignore_change) + { + return FALSE; + } + + rd_ignore_change = 1; + h = GetDlgItem(hdlg, IDC_COMBO_CD_ID); + temp_cdrom_drives[cdlv_current_sel].scsi_device_id = SendMessage(h, CB_GETCURSEL, 0, 0); + h = GetDlgItem(hdlg, IDC_LIST_CDROM_DRIVES); + win_settings_cdrom_drives_update_item(h, cdlv_current_sel); + rd_ignore_change = 0; + return FALSE; + + case IDC_COMBO_CD_LUN: + if (rd_ignore_change) + { + return FALSE; + } + + rd_ignore_change = 1; + h = GetDlgItem(hdlg, IDC_COMBO_CD_LUN); + temp_cdrom_drives[cdlv_current_sel].scsi_device_lun = SendMessage(h, CB_GETCURSEL, 0, 0); + h = GetDlgItem(hdlg, IDC_LIST_CDROM_DRIVES); + win_settings_cdrom_drives_update_item(h, cdlv_current_sel); + rd_ignore_change = 0; + return FALSE; + + case IDC_COMBO_CD_CHANNEL_IDE: + if (rd_ignore_change) + { + return FALSE; + } + + rd_ignore_change = 1; + h = GetDlgItem(hdlg, IDC_COMBO_CD_CHANNEL_IDE); + temp_cdrom_drives[cdlv_current_sel].ide_channel = SendMessage(h, CB_GETCURSEL, 0, 0); + h = GetDlgItem(hdlg, IDC_LIST_CDROM_DRIVES); + win_settings_cdrom_drives_update_item(h, cdlv_current_sel); + rd_ignore_change = 0; + return FALSE; + } + + default: + return FALSE; + } + + return FALSE; +} + +void win_settings_show_child(HWND hwndParent, DWORD child_id) +{ + if (child_id == displayed_category) + { + return; + } + else + { + displayed_category = child_id; + } + + SendMessage(hwndChildDialog, WM_SAVESETTINGS, 0, 0); + + DestroyWindow(hwndChildDialog); + + switch(child_id) + { + case 0: + hwndChildDialog = CreateDialog(hinstance, (LPCWSTR)DLG_CFG_MACHINE, hwndParent, win_settings_machine_proc); + break; + case 1: + hwndChildDialog = CreateDialog(hinstance, (LPCWSTR)DLG_CFG_VIDEO, hwndParent, win_settings_video_proc); + break; + case 2: + hwndChildDialog = CreateDialog(hinstance, (LPCWSTR)DLG_CFG_INPUT, hwndParent, win_settings_input_proc); + break; + case 3: + hwndChildDialog = CreateDialog(hinstance, (LPCWSTR)DLG_CFG_SOUND, hwndParent, win_settings_sound_proc); + break; + case 4: + hwndChildDialog = CreateDialog(hinstance, (LPCWSTR)DLG_CFG_NETWORK, hwndParent, win_settings_network_proc); + break; + case 5: + hwndChildDialog = CreateDialog(hinstance, (LPCWSTR)DLG_CFG_PERIPHERALS, hwndParent, win_settings_peripherals_proc); + break; + case 6: + hwndChildDialog = CreateDialog(hinstance, (LPCWSTR)DLG_CFG_HARD_DISKS, hwndParent, win_settings_hard_disks_proc); + break; + case 7: + hwndChildDialog = CreateDialog(hinstance, (LPCWSTR)DLG_CFG_REMOVABLE_DEVICES, hwndParent, win_settings_removable_devices_proc); + break; + default: + fatal("Invalid child dialog ID\n"); + return; + } + + ShowWindow(hwndChildDialog, SW_SHOWNORMAL); +} + +static BOOL win_settings_main_image_list_init(HWND hwndList) +{ + HICON hiconItem; + HIMAGELIST hSmall; + + int i = 0; + + hSmall = ImageList_Create(GetSystemMetrics(SM_CXSMICON), + GetSystemMetrics(SM_CYSMICON), + ILC_MASK | ILC_COLOR32, 1, 1); + + for (i = 0; i < 8; i++) + { + hiconItem = LoadIcon(hinstance, (LPCWSTR) (256 + i)); + ImageList_AddIcon(hSmall, hiconItem); + DestroyIcon(hiconItem); + } + + ListView_SetImageList(hwndList, hSmall, LVSIL_SMALL); + + return TRUE; +} + +static BOOL win_settings_main_insert_categories(HWND hwndList) +{ + LVITEM lvI; + int i = 0; + + lvI.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE; + lvI.stateMask = lvI.iSubItem = lvI.state = 0; + + for (i = 0; i < 8; i++) + { + lvI.pszText = win_language_get_settings_category(i); + lvI.iItem = i; + lvI.iImage = i; + + if (ListView_InsertItem(hwndList, &lvI) == -1) + return FALSE; + } + + return TRUE; +} + +static BOOL CALLBACK win_settings_main_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + HWND h; + int category; + int i = 0; + int j = 0; + + hwndParentDialog = hdlg; + + switch (message) + { + case WM_INITDIALOG: + pause = 1; + win_settings_init(); + displayed_category = -1; + h = GetDlgItem(hdlg, IDC_SETTINGSCATLIST); + win_settings_main_image_list_init(h); + win_settings_main_insert_categories(h); + ListView_SetItemState(h, 0, LVIS_FOCUSED | LVIS_SELECTED, 0x000F); +/* Leave this commented out until we do localization. */ +#if 0 + h = GetDlgItem(hdlg, IDC_COMBO_LANG); /* This is currently disabled, I am going to add localization options in the future. */ + EnableWindow(h, FALSE); + ShowWindow(h, SW_HIDE); + h = GetDlgItem(hdlg, IDS_LANG_ENUS); /*was:2047 !*/ + EnableWindow(h, FALSE); + ShowWindow(h, SW_HIDE); +#endif + return TRUE; + case WM_NOTIFY: + if ((((LPNMHDR)lParam)->code == LVN_ITEMCHANGED) && (((LPNMHDR)lParam)->idFrom == IDC_SETTINGSCATLIST)) + { + category = -1; + for (i = 0; i < 8; i++) + { + h = GetDlgItem(hdlg, IDC_SETTINGSCATLIST); + j = ListView_GetItemState(h, i, LVIS_SELECTED); + if (j) + { + category = i; + /* pclog("Category %i selected\n", i); */ + } + } + if (category != -1) + { + /* pclog("Showing child: %i\n", category); */ + win_settings_show_child(hdlg, category); + } + } + break; + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case IDOK: + /* pclog("Saving settings...\n"); */ + SendMessage(hwndChildDialog, WM_SAVESETTINGS, 0, 0); + i = settings_msgbox_reset(); + if (i > 0) + { + if (i == 2) + { + win_settings_save(); + } + + /* pclog("Destroying window...\n"); */ + DestroyWindow(hwndChildDialog); + EndDialog(hdlg, 0); + pause = 0; + return TRUE; + } + else + { + return FALSE; + } + case IDCANCEL: + DestroyWindow(hwndChildDialog); + EndDialog(hdlg, 0); + pause=0; + return TRUE; + } + break; + default: + return FALSE; + } + + return FALSE; +} + +void win_settings_open(HWND hwnd) +{ + DialogBox(hinstance, (LPCWSTR)DLG_CONFIG, hwnd, win_settings_main_proc); +} diff --git a/src/win-status.c b/src/WIN/win_status.c similarity index 75% rename from src/win-status.c rename to src/WIN/win_status.c index 345f9e2e5..0a0fc659c 100644 --- a/src/win-status.c +++ b/src/WIN/win_status.c @@ -6,23 +6,24 @@ #include #undef BITMAP -#include "ibm.h" -#include "device.h" -#include "video.h" -#include "resources.h" +#include "../ibm.h" +#include "../mem.h" +#include "../cpu/x86_ops.h" +#include "../cpu/codegen.h" +#include "../device.h" #include "win.h" -#include "x86_ops.h" -#include "mem.h" -#include "codegen.h" + HWND status_hwnd; int status_is_open = 0; + extern int sreadlnum, swritelnum, segareads, segawrites, scycles_lost; extern uint64_t main_time; static uint64_t status_time; + static BOOL CALLBACK status_dlgproc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) { char device_s[4096]; @@ -39,9 +40,6 @@ static BOOL CALLBACK status_dlgproc(HWND hdlg, UINT message, WPARAM wParam, LPAR "CPU speed : %f MIPS\n" "FPU speed : %f MFLOPS\n\n" -/* "Cache misses (read) : %i/sec\n" - "Cache misses (write) : %i/sec\n\n"*/ - "Video throughput (read) : %i bytes/sec\n" "Video throughput (write) : %i bytes/sec\n\n" "Effective clockspeed : %iHz\n\n" @@ -50,13 +48,8 @@ static BOOL CALLBACK status_dlgproc(HWND hdlg, UINT message, WPARAM wParam, LPAR "New blocks : %i\nOld blocks : %i\nRecompiled speed : %f MIPS\nAverage size : %f\n" "Flushes : %i\nEvicted : %i\nReused : %i\nRemoved : %i\nReal speed : %f MIPS" -// "\nFully recompiled ins %% : %f%%" ,mips, flops, -/*#ifndef DYNAREC - sreadlnum, - swritelnum, -#endif*/ segareads, segawrites, clockrate - scycles_lost, @@ -69,18 +62,13 @@ static BOOL CALLBACK status_dlgproc(HWND hdlg, UINT message, WPARAM wParam, LPAR cpu_recomp_reuse_latched, cpu_recomp_removed_latched, ((double)cpu_recomp_ins_latched / 1000000.0) / ((double)main_time / timer_freq) -// ((double)cpu_recomp_full_ins_latched / (double)cpu_recomp_ins_latched) * 100.0 -// cpu_reps_latched, cpu_notreps_latched ); main_time = 0; -/*#ifndef DYNAREC - device_add_status_info(device_s, 4096); -#endif*/ - SendDlgItemMessage(hdlg, IDC_STEXT_DEVICE, WM_SETTEXT, (WPARAM)NULL, (LPARAM)device_s); + SendDlgItemMessage(hdlg, IDT_SDEVICE, WM_SETTEXT, (WPARAM)NULL, (LPARAM)device_s); device_s[0] = 0; device_add_status_info(device_s, 4096); - SendDlgItemMessage(hdlg, IDC_STEXT1, WM_SETTEXT, (WPARAM)NULL, (LPARAM)device_s); + SendDlgItemMessage(hdlg, IDT_STEXT, WM_SETTEXT, (WPARAM)NULL, (LPARAM)device_s); } return TRUE; @@ -101,6 +89,6 @@ static BOOL CALLBACK status_dlgproc(HWND hdlg, UINT message, WPARAM wParam, LPAR void status_open(HWND hwnd) { - status_hwnd = CreateDialog(hinstance, TEXT("StatusDlg"), hwnd, status_dlgproc); + status_hwnd = CreateDialog(hinstance, (LPCSTR)DLG_STATUS, hwnd, status_dlgproc); ShowWindow(status_hwnd, SW_SHOW); } diff --git a/src/win-video.c b/src/WIN/win_video.c similarity index 95% rename from src/win-video.c rename to src/WIN/win_video.c index eed0059c6..3a50f7b9f 100644 --- a/src/win-video.c +++ b/src/WIN/win_video.c @@ -4,10 +4,13 @@ #include #include #include -#include "video.h" +#include "../video/video.h" +#include "win_cgapal.h" + BITMAP *screen; + void hline(BITMAP *b, int x1, int y, int x2, uint32_t col) { if (y < 0 || y >= buffer->h) diff --git a/src/acer386sx.c b/src/acer386sx.c index ea3bfe74d..47f0cbca8 100644 --- a/src/acer386sx.c +++ b/src/acer386sx.c @@ -2,15 +2,17 @@ see COPYING for more details */ #include "ibm.h" +#include "cpu/cpu.h" #include "io.h" -#include "cpu.h" +#include "device.h" +#include "model.h" -#include "acer386sx.h" static int acer_index = 0; static uint8_t acer_regs[256]; -void acer386sx_write(uint16_t addr, uint8_t val, void *priv) + +static void acer386sx_write(uint16_t addr, uint8_t val, void *priv) { if (addr & 1) acer_regs[acer_index] = val; @@ -18,7 +20,8 @@ void acer386sx_write(uint16_t addr, uint8_t val, void *priv) acer_index = val; } -uint8_t acer386sx_read(uint16_t addr, void *priv) + +static uint8_t acer386sx_read(uint16_t addr, void *priv) { if (addr & 1) { @@ -30,7 +33,8 @@ uint8_t acer386sx_read(uint16_t addr, void *priv) return acer_index; } -void acer386sx_init() + +void acer386sx_init(void) { io_sethandler(0x0022, 0x0002, acer386sx_read, NULL, NULL, acer386sx_write, NULL, NULL, NULL); } diff --git a/src/acer386sx.h b/src/acer386sx.h deleted file mode 100644 index e84de8235..000000000 --- a/src/acer386sx.h +++ /dev/null @@ -1,4 +0,0 @@ -/* Copyright holders: Sarah Walker - see COPYING for more details -*/ -void acer386sx_init(); diff --git a/src/acerm3a.c b/src/acerm3a.c index 769d3c0e0..a348d2b05 100644 --- a/src/acerm3a.c +++ b/src/acerm3a.c @@ -2,18 +2,23 @@ see COPYING for more details */ #include "ibm.h" +#include "cpu/cpu.h" #include "io.h" -#include "acerm3a.h" +#include "device.h" +#include "model.h" + static int acerm3a_index; -static void acerm3a_out(uint16_t port, uint8_t val, void *p) + +static void acerm3a_write(uint16_t port, uint8_t val, void *p) { if (port == 0xea) acerm3a_index = val; } -static uint8_t acerm3a_in(uint16_t port, void *p) + +static uint8_t acerm3a_read(uint16_t port, void *p) { if (port == 0xeb) { @@ -26,7 +31,8 @@ static uint8_t acerm3a_in(uint16_t port, void *p) return 0xff; } -void acerm3a_io_init() + +void acerm3a_io_init(void) { - io_sethandler(0x00ea, 0x0002, acerm3a_in, NULL, NULL, acerm3a_out, NULL, NULL, NULL); + io_sethandler(0x00ea, 0x0002, acerm3a_read, NULL, NULL, acerm3a_write, NULL, NULL, NULL); } diff --git a/src/acerm3a.h b/src/acerm3a.h deleted file mode 100644 index 300531940..000000000 --- a/src/acerm3a.h +++ /dev/null @@ -1,4 +0,0 @@ -/* Copyright holders: Sarah Walker - see COPYING for more details -*/ -void acerm3a_io_init(); diff --git a/src/ali1429.c b/src/ali1429.c index d01eaf863..7c24efcb2 100644 --- a/src/ali1429.c +++ b/src/ali1429.c @@ -3,16 +3,18 @@ */ #include #include "ibm.h" +#include "cpu/cpu.h" #include "io.h" #include "mem.h" -#include "cpu.h" +#include "device.h" +#include "model.h" -#include "ali1429.h" static int ali1429_index; static uint8_t ali1429_regs[256]; -static void ali1429_recalc() + +static void ali1429_recalc(void) { int c; @@ -46,14 +48,11 @@ static void ali1429_recalc() void ali1429_write(uint16_t port, uint8_t val, void *priv) { - int c; - if (!(port & 1)) ali1429_index = val; else { ali1429_regs[ali1429_index] = val; -// pclog("ALI1429 write %02X %02X %04X:%04X %i\n",ali1429_index,val,CS,pc,ins); switch (ali1429_index) { case 0x13: @@ -78,12 +77,13 @@ uint8_t ali1429_read(uint16_t port, void *priv) } -void ali1429_reset() +void ali1429_reset(void) { memset(ali1429_regs, 0xff, 256); } -void ali1429_init() + +void ali1429_init(void) { io_sethandler(0x0022, 0x0002, ali1429_read, NULL, NULL, ali1429_write, NULL, NULL, NULL); } diff --git a/src/ali1429.h b/src/ali1429.h deleted file mode 100644 index 83362e746..000000000 --- a/src/ali1429.h +++ /dev/null @@ -1,4 +0,0 @@ -/* Copyright holders: Sarah Walker - see COPYING for more details -*/ -void ali1429_init(); diff --git a/src/allegro-gui-configure.c b/src/allegro-gui-configure.c deleted file mode 100644 index dd7c50b2a..000000000 --- a/src/allegro-gui-configure.c +++ /dev/null @@ -1,639 +0,0 @@ -/* Copyright holders: Sarah Walker - see COPYING for more details -*/ -#include "ibm.h" -#include "device.h" -#include "allegro-main.h" -#include "allegro-gui.h" -#include "cpu.h" -#include "fdd.h" -#include "gameport.h" -#include "model.h" -#include "sound.h" -#include "video.h" -#include "vid_voodoo.h" - -static int romstolist[ROM_MAX], listtomodel[ROM_MAX], romstomodel[ROM_MAX], modeltolist[ROM_MAX]; -static int settings_sound_to_list[20], settings_list_to_sound[20]; - -typedef struct allegro_list_t -{ - char name[256]; - int num; -} allegro_list_t; - -static allegro_list_t model_list[ROM_MAX+1]; -static allegro_list_t video_list[GFX_MAX+1]; -static allegro_list_t sound_list[GFX_MAX+1]; -static allegro_list_t cpumanu_list[4]; -static allegro_list_t cpu_list[32]; -static allegro_list_t joystick_list[32]; - -static char mem_size_str[10], mem_size_units[3]; - -static allegro_list_t cache_list[] = -{ - {"A little", 0}, - {"A bit", 1}, - {"Some", 2}, - {"A lot", 3}, - {"Infinite", 4}, - {"", -1} -}; - -static allegro_list_t vidspeed_list[] = -{ - {"8-bit", 0}, - {"Slow 16-bit", 1}, - {"Fast 16-bit", 2}, - {"Slow VLB/PCI", 3}, - {"Mid VLB/PCI", 4}, - {"Fast VLB/PCI", 5}, - {"", -1} -}; - -static allegro_list_t fdd_list[] = -{ - {"None", 0}, - {"5.25\" 360k", 1}, - {"5.25\" 1.2M", 2}, - {"5.25\" 1.2M Dual RPM", 3}, - {"3.5\" 720k", 4}, - {"3.5\" 1.44M", 5}, - {"3.5\" 1.44M 3-Mode", 6}, - {"3.5\" 2.88M", 7}, - {"", -1} -}; - -static void reset_list(); - -static char *list_proc_model(int index, int *list_size) -{ - if (index < 0) - { - int c = 0; - - while (model_list[c].name[0]) - c++; - - *list_size = c; - return NULL; - } - - return model_list[index].name; -} - -static char *list_proc_video(int index, int *list_size) -{ - if (index < 0) - { - int c = 0; - - while (video_list[c].name[0]) - c++; - - *list_size = c; - return NULL; - } - - return video_list[index].name; -} - -static char *list_proc_cache(int index, int *list_size) -{ - if (index < 0) - { - int c = 0; - - while (cache_list[c].name[0]) - c++; - - *list_size = c; - return NULL; - } - - return cache_list[index].name; -} - -static char *list_proc_vidspeed(int index, int *list_size) -{ - if (index < 0) - { - int c = 0; - - while (vidspeed_list[c].name[0]) - c++; - - *list_size = c; - return NULL; - } - - return vidspeed_list[index].name; -} - -static char *list_proc_sound(int index, int *list_size) -{ - if (index < 0) - { - int c = 0; - - while (sound_list[c].name[0]) - c++; - - *list_size = c; - return NULL; - } - - return sound_list[index].name; -} - -static char *list_proc_cpumanu(int index, int *list_size) -{ - if (index < 0) - { - int c = 0; - - while (cpumanu_list[c].name[0]) - c++; - - *list_size = c; - return NULL; - } - - return cpumanu_list[index].name; -} - -static char *list_proc_cpu(int index, int *list_size) -{ - if (index < 0) - { - int c = 0; - - while (cpu_list[c].name[0]) - c++; - - *list_size = c; - return NULL; - } - - return cpu_list[index].name; -} - -static char *list_proc_fdd(int index, int *list_size) -{ - if (index < 0) - { - int c = 0; - - while (fdd_list[c].name[0]) - c++; - - *list_size = c; - return NULL; - } - - return fdd_list[index].name; -} - -static char *list_proc_joystick(int index, int *list_size) -{ - if (index < 0) - { - int c = 0; - - while (joystick_list[c].name[0]) - c++; - - *list_size = c; - return NULL; - } - - return joystick_list[index].name; -} - -static int voodoo_config_proc(int msg, DIALOG *d, int c) -{ - int ret = d_button_proc(msg, d, c); - - if (ret == D_CLOSE) - { - deviceconfig_open(&voodoo_device); - return D_O_K; - } - - return ret; -} - - -static int video_config_proc(int msg, DIALOG *d, int c); -static int sound_config_proc(int msg, DIALOG *d, int c); -static int list_proc(int msg, DIALOG *d, int c); - -static DIALOG configure_dialog[] = -{ - {d_shadow_box_proc, 0, 0, 568,352,0,0xffffff,0,0, 0,0,0,0,0}, // 0 - - {d_button_proc, 226, 328, 50, 16, 0, 0xffffff, 0, D_EXIT, 0, 0, "OK", 0, 0}, // 1 - {d_button_proc, 296, 328, 50, 16, 0, 0xffffff, 0, D_EXIT, 0, 0, "Cancel", 0, 0}, // 2 - - {list_proc, 70*2, 12, 152*2, 20, 0, 0xffffff, 0, 0, 0, 0, list_proc_model, 0, 0}, - - {list_proc, 70*2, 32, 152*2, 20, 0, 0xffffff, 0, 0, 0, 0, list_proc_video, 0, 0}, - - {list_proc, 70*2, 52, 152*2, 20, 0, 0xffffff, 0, 0, 0, 0, list_proc_cpumanu, 0, 0}, //5 - {list_proc, 70*2, 72, 152*2, 20, 0, 0xffffff, 0, 0, 0, 0, list_proc_cpu, 0, 0}, - {d_list_proc, 70*2, 112, 152*2, 20, 0, 0xffffff, 0, 0, 0, 0, list_proc_cache, 0, 0}, - {d_list_proc, 70*2, 132, 152*2, 20, 0, 0xffffff, 0, 0, 0, 0, list_proc_vidspeed, 0, 0}, - {list_proc, 70*2, 152, 152*2, 20, 0, 0xffffff, 0, 0, 0, 0, list_proc_sound, 0, 0}, //9 - - {d_edit_proc, 70*2, 236, 32, 14, 0, 0xffffff, 0, 0, 3, 0, mem_size_str, 0, 0}, - - {d_text_proc, 98*2, 236, 40, 10, 0, 0xffffff, 0, 0, 0, 0, mem_size_units, 0, 0}, - - {d_check_proc, 14*2, 252, 118*2, 10, 0, 0xffffff, 0, 0, 0, 0, "CMS / Game Blaster", 0, 0}, - {d_check_proc, 14*2, 268, 118*2, 10, 0, 0xffffff, 0, 0, 0, 0, "Gravis Ultrasound", 0, 0}, - {d_check_proc, 14*2, 284, 118*2, 10, 0, 0xffffff, 0, 0, 0, 0, "Innovation SSI-2001", 0, 0}, - {d_check_proc, 14*2, 300, 118*2, 10, 0, 0xffffff, 0, 0, 0, 0, "Composite CGA", 0, 0}, - {d_check_proc, 14*2, 316, 118*2, 10, 0, 0xffffff, 0, 0, 0, 0, "Voodoo Graphics", 0, 0}, - - {d_text_proc, 16*2, 16, 40, 10, 0, 0xffffff, 0, 0, 0, 0, "Machine :", 0, 0}, - {d_text_proc, 16*2, 36, 40, 10, 0, 0xffffff, 0, 0, 0, 0, "Video :", 0, 0}, - {d_text_proc, 16*2, 56, 40, 10, 0, 0xffffff, 0, 0, 0, 0, "CPU type :", 0, 0}, - {d_text_proc, 16*2, 76, 40, 10, 0, 0xffffff, 0, 0, 0, 0, "CPU :", 0, 0}, - {d_text_proc, 16*2, 116, 40, 10, 0, 0xffffff, 0, 0, 0, 0, "Cache :", 0, 0}, - {d_text_proc, 16*2, 136, 40, 10, 0, 0xffffff, 0, 0, 0, 0, "Video speed :", 0, 0}, - {d_text_proc, 16*2, 156, 40, 10, 0, 0xffffff, 0, 0, 0, 0, "Soundcard :", 0, 0}, - {d_text_proc, 16*2, 236, 40, 10, 0, 0xffffff, 0, 0, 0, 0, "Memory :", 0, 0}, - - {d_check_proc, 14*2, 92, 118*2, 10, 0, 0xffffff, 0, 0, 0, 0, "Dynamic Recompiler", 0, 0}, - - {d_text_proc, 16*2, 176, 40, 10, 0, 0xffffff, 0, 0, 0, 0, "Drive A: :", 0, 0}, - {d_text_proc, 16*2, 196, 40, 10, 0, 0xffffff, 0, 0, 0, 0, "Drive B: :", 0, 0}, - {d_list_proc, 70*2, 172, 152*2, 20, 0, 0xffffff, 0, 0, 0, 0, list_proc_fdd, 0, 0}, - {d_list_proc, 70*2, 192, 152*2, 20, 0, 0xffffff, 0, 0, 0, 0, list_proc_fdd, 0, 0}, - - {video_config_proc, 452, 32+4, 100, 14, 0, 0xffffff, 0, D_EXIT, 0, 0, "Configure...", 0, 0}, //30 - {sound_config_proc, 452, 152+4, 100, 14, 0, 0xffffff, 0, D_EXIT, 0, 0, "Configure...", 0, 0}, - {voodoo_config_proc, 452, 316, 100, 14, 0, 0xffffff, 0, D_EXIT, 0, 0, "Configure...", 0, 0}, - - {d_text_proc, 16*2, 216, 40, 10, 0, 0xffffff, 0, 0, 0, 0, "Joystick :", 0, 0}, - {d_list_proc, 70*2, 212, 152*2, 20, 0, 0xffffff, 0, 0, 0, 0, list_proc_joystick, 0, 0}, //34 - - {0,0,0,0,0,0,0,0,0,0,0,NULL,NULL,NULL} -}; - -static int list_proc(int msg, DIALOG *d, int c) -{ - int old = d->d1; - int ret = d_list_proc(msg, d, c); - - if (d->d1 != old) - { - int new_model = model_list[configure_dialog[3].d1].num; - int new_cpu_m = configure_dialog[5].d1; - int new_cpu = configure_dialog[6].d1; - int new_dynarec = configure_dialog[25].flags & D_SELECTED; - int new_gfxcard = video_old_to_new(video_list[configure_dialog[4].d1].num); - int new_mem_size; - int cpu_flags; - - reset_list(); - - if (models[new_model].fixed_gfxcard) - configure_dialog[4].flags |= D_DISABLED; - else - configure_dialog[4].flags &= ~D_DISABLED; - - cpu_flags = models[new_model].cpu[new_cpu_m].cpus[new_cpu].cpu_flags; - configure_dialog[25].flags = (((cpu_flags & CPU_SUPPORTS_DYNAREC) && new_dynarec) || (cpu_flags & CPU_REQUIRES_DYNAREC)) ? D_SELECTED : 0; - if (!(cpu_flags & CPU_SUPPORTS_DYNAREC) || (cpu_flags & CPU_REQUIRES_DYNAREC)) - configure_dialog[25].flags |= D_DISABLED; - - sscanf(mem_size_str, "%i", &new_mem_size); - new_mem_size &= ~(models[new_model].ram_granularity - 1); - if (new_mem_size < models[new_model].min_ram) - new_mem_size = models[new_model].min_ram; - else if (new_mem_size > models[new_model].max_ram) - new_mem_size = models[new_model].max_ram; - sprintf(mem_size_str, "%i", new_mem_size); - - if (models[new_model].is_at) - sprintf(mem_size_units, "MB"); - else - sprintf(mem_size_units, "kB"); - - if (!video_card_has_config(new_gfxcard)) - configure_dialog[30].flags |= D_DISABLED; - else - configure_dialog[30].flags &= ~D_DISABLED; - - if (!sound_card_has_config(configure_dialog[9].d1)) - configure_dialog[31].flags |= D_DISABLED; - else - configure_dialog[31].flags &= ~D_DISABLED; - - return D_REDRAW; - } - - return ret; -} - -static int video_config_proc(int msg, DIALOG *d, int c) -{ - int ret = d_button_proc(msg, d, c); - - if (ret == D_CLOSE) - { - int new_gfxcard = video_old_to_new(video_list[configure_dialog[4].d1].num); - - deviceconfig_open(video_card_getdevice(new_gfxcard)); - return D_O_K; - } - - return ret; -} -static int sound_config_proc(int msg, DIALOG *d, int c) -{ - int ret = d_button_proc(msg, d, c); - - if (ret == D_CLOSE) - { - int new_sndcard = sound_list[configure_dialog[9].d1].num; - - deviceconfig_open(sound_card_getdevice(new_sndcard)); - return D_O_K; - } - - return ret; -} - -static void reset_list() -{ - int model = model_list[configure_dialog[3].d1].num; - int cpumanu = configure_dialog[5].d1; - int cpu = configure_dialog[6].d1; - int c; - - memset(cpumanu_list, 0, sizeof(cpumanu_list)); - memset(cpu_list, 0, sizeof(cpu_list)); - - c = 0; - while (models[model].cpu[c].cpus != NULL && c < 3) - { - strcpy(cpumanu_list[c].name, models[model].cpu[c].name); - cpumanu_list[c].num = c; - c++; - } - - if (cpumanu >= c) - cpumanu = configure_dialog[6].d1 = c-1; - - c = 0; - while (models[model].cpu[cpumanu].cpus[c].cpu_type != -1) - { - strcpy(cpu_list[c].name, models[model].cpu[cpumanu].cpus[c].name); - cpu_list[c].num = c; - c++; - } - - if (cpu >= c) - cpu = configure_dialog[7].d1 = c-1; -} - -int settings_configure() -{ - int c, d; - int cpu_flags; - - memset(model_list, 0, sizeof(model_list)); - memset(video_list, 0, sizeof(video_list)); - memset(sound_list, 0, sizeof(sound_list)); - - for (c = 0; c < ROM_MAX; c++) - romstolist[c] = 0; - c = d = 0; - while (models[c].id != -1) - { - pclog("INITDIALOG : %i %i %i\n",c,models[c].id,romspresent[models[c].id]); - if (romspresent[models[c].id]) - { - strcpy(model_list[d].name, models[c].name); - model_list[d].num = c; - if (c == model) - configure_dialog[3].d1 = d; - d++; - } - c++; - } - - if (models[model].fixed_gfxcard) - configure_dialog[4].flags |= D_DISABLED; - else - configure_dialog[4].flags &= ~D_DISABLED; - - c = d = 0; - while (1) - { - char *s = video_card_getname(c); - - if (!s[0]) - break; -pclog("video_card_available : %i\n", c); - if (video_card_available(c)) - { - strcpy(video_list[d].name, video_card_getname(c)); - video_list[d].num = video_new_to_old(c); - if (video_new_to_old(c) == gfxcard) - configure_dialog[4].d1 = d; - d++; - } - - c++; - } - - if (!video_card_has_config(video_old_to_new(gfxcard))) - configure_dialog[30].flags |= D_DISABLED; - else - configure_dialog[30].flags &= ~D_DISABLED; - - c = d = 0; - while (1) - { - char *s = sound_card_getname(c); - - if (!s[0]) - break; - - if (sound_card_available(c)) - { - strcpy(sound_list[d].name, sound_card_getname(c)); - sound_list[d].num = c; - if (c == sound_card_current) - configure_dialog[9].d1 = d; - d++; - } - - c++; - } - - c = 0; - while (joystick_get_name(c)) - { - strcpy(joystick_list[c].name, joystick_get_name(c)); - if (c == joystick_type) - configure_dialog[34].d1 = c; - - c++; - } - - if (!sound_card_has_config(configure_dialog[9].d1)) - configure_dialog[31].flags |= D_DISABLED; - else - configure_dialog[31].flags &= ~D_DISABLED; - - configure_dialog[5].d1 = cpu_manufacturer; - configure_dialog[6].d1 = cpu; - configure_dialog[7].d1 = cache; - configure_dialog[8].d1 = video_speed; - reset_list(); -// strcpy(cpumanu_str, models[romstomodel[romset]].cpu[cpu_manufacturer].name); -// strcpy(cpu_str, models[romstomodel[romset]].cpu[cpu_manufacturer].cpus[cpu].name); -// strcpy(cache_str, cache_str_list[cache]); -// strcpy(vidspeed_str, vidspeed_str_list[video_speed]); - -// strcpy(soundcard_str, sound_card_getname(sound_card_current)); - - if (GAMEBLASTER) - configure_dialog[12].flags |= D_SELECTED; - else - configure_dialog[12].flags &= ~D_SELECTED; - - if (GUS) - configure_dialog[13].flags |= D_SELECTED; - else - configure_dialog[13].flags &= ~D_SELECTED; - - if (SSI2001) - configure_dialog[14].flags |= D_SELECTED; - else - configure_dialog[14].flags &= ~D_SELECTED; - - if (cga_comp) - configure_dialog[15].flags |= D_SELECTED; - else - configure_dialog[15].flags &= ~D_SELECTED; - - if (voodoo_enabled) - configure_dialog[16].flags |= D_SELECTED; - else - configure_dialog[16].flags &= ~D_SELECTED; - - if (models[model].is_at) - sprintf(mem_size_str, "%i", mem_size / 1024); - else - sprintf(mem_size_str, "%i", mem_size); - - if (models[model].is_at) - sprintf(mem_size_units, "MB"); - else - sprintf(mem_size_units, "kB"); - - cpu_flags = models[model].cpu[cpu_manufacturer].cpus[cpu].cpu_flags; - configure_dialog[25].flags = (((cpu_flags & CPU_SUPPORTS_DYNAREC) && cpu_use_dynarec) || (cpu_flags & CPU_REQUIRES_DYNAREC)) ? D_SELECTED : 0; - if (!(cpu_flags & CPU_SUPPORTS_DYNAREC) || (cpu_flags & CPU_REQUIRES_DYNAREC)) - configure_dialog[25].flags |= D_DISABLED; - - configure_dialog[28].d1 = fdd_get_type(0); - configure_dialog[29].d1 = fdd_get_type(1); - - while (1) - { - position_dialog(configure_dialog, SCREEN_W/2 - configure_dialog[0].w/2, SCREEN_H/2 - configure_dialog[0].h/2); - - c = popup_dialog(configure_dialog, 1); - - position_dialog(configure_dialog, -(SCREEN_W/2 - configure_dialog[0].w/2), -(SCREEN_H/2 - configure_dialog[0].h/2)); - - if (c == 1) - { - int new_model = model_list[configure_dialog[3].d1].num; - int new_gfxcard = video_list[configure_dialog[4].d1].num; - int new_sndcard = sound_list[configure_dialog[9].d1].num; - int new_cpu_m = configure_dialog[5].d1; - int new_cpu = configure_dialog[6].d1; - int new_mem_size; - int new_has_fpu = (models[new_model].cpu[new_cpu_m].cpus[new_cpu].cpu_type >= CPU_i486DX) ? 1 : 0; - int new_GAMEBLASTER = (configure_dialog[12].flags & D_SELECTED) ? 1 : 0; - int new_GUS = (configure_dialog[13].flags & D_SELECTED) ? 1 : 0; - int new_SSI2001 = (configure_dialog[14].flags & D_SELECTED) ? 1 : 0; - int new_voodoo = (configure_dialog[16].flags & D_SELECTED) ? 1 : 0; - int new_dynarec = (configure_dialog[25].flags & D_SELECTED) ? 1 : 0; - int new_fda = configure_dialog[28].d1; - int new_fdb = configure_dialog[29].d1; - - sscanf(mem_size_str, "%i", &new_mem_size); - new_mem_size &= ~(models[new_model].ram_granularity - 1); - if (new_mem_size < models[new_model].min_ram) - new_mem_size = models[new_model].min_ram; - else if (new_mem_size > models[new_model].max_ram) - new_mem_size = models[new_model].max_ram; - if (models[new_model].is_at) - new_mem_size *= 1024; - - if (new_model != model || new_gfxcard != gfxcard || new_mem_size != mem_size || - new_has_fpu != hasfpu || new_GAMEBLASTER != GAMEBLASTER || new_GUS != GUS || - new_SSI2001 != SSI2001 || new_sndcard != sound_card_current || new_voodoo != voodoo_enabled || - new_dynarec != cpu_use_dynarec || new_fda != fdd_get_type(0) || new_fdb != fdd_get_type(1)) - { - if (alert("This will reset 86Box!", "Okay to continue?", NULL, "OK", "Cancel", 0, 0) != 1) - continue; - - model = new_model; - romset = model_getromset(); - gfxcard = new_gfxcard; - mem_size = new_mem_size; - cpu_manufacturer = new_cpu_m; - cpu = new_cpu; - GAMEBLASTER = new_GAMEBLASTER; - GUS = new_GUS; - SSI2001 = new_SSI2001; - sound_card_current = new_sndcard; - voodoo_enabled = new_voodoo; - cpu_use_dynarec = new_dynarec; - - mem_resize(); - loadbios(); - resetpchard(); - - fdd_set_type(0, new_fda); - fdd_set_type(1, new_fdb); - } - - video_speed = configure_dialog[8].d1; - - cga_comp = (configure_dialog[15].flags & D_SELECTED) ? 1 : 0; - - cpu_manufacturer = new_cpu_m; - cpu = new_cpu; - cpu_set(); - - cache = configure_dialog[7].d1; - mem_updatecache(); - - joystick_type = configure_dialog[34].d1; - gameport_update_joystick_type(); - - saveconfig(); - - speedchanged(); - - return D_O_K; - } - - if (c == 2) - return D_O_K; - } - - return D_O_K; -} - diff --git a/src/allegro-gui-deviceconfig.c b/src/allegro-gui-deviceconfig.c deleted file mode 100644 index 9dcbb5011..000000000 --- a/src/allegro-gui-deviceconfig.c +++ /dev/null @@ -1,306 +0,0 @@ -/* Copyright holders: Sarah Walker - see COPYING for more details -*/ -#include "ibm.h" -#include "device.h" -#include "allegro-main.h" -#include "allegro-gui.h" -#include "config.h" - -static device_t *config_device; - -#define MAX_CONFIG_SIZE 64 -#define MAX_CONFIG_SELECTIONS 8 - -static device_config_selection_t *config_selections[MAX_CONFIG_SELECTIONS]; - -#define list_proc_device_func(i) \ - static char *list_proc_device_ ## i(int index, int *list_size) \ - { \ - device_config_selection_t *config = config_selections[i]; \ - \ - if (index < 0) \ - { \ - int c = 0; \ - \ - while (config[c].description[0]) \ - c++; \ - \ - *list_size = c; \ - return NULL; \ - } \ - \ - return config[index].description; \ - } - -list_proc_device_func(0) -list_proc_device_func(1) -list_proc_device_func(2) -list_proc_device_func(3) -list_proc_device_func(4) -list_proc_device_func(5) -list_proc_device_func(6) -list_proc_device_func(7) - -static DIALOG deviceconfig_dialog[MAX_CONFIG_SIZE] = -{ - {d_shadow_box_proc, 0, 0, 568,332,0,0xffffff,0,0, 0,0,0,0,0} // 0 -}; - -void deviceconfig_open(device_t *device) -{ - DIALOG *d; - device_config_t *config = device->config; - int y = 10; - int dialog_pos = 1; - int list_pos = 0; - int c; - int id_ok, id_cancel; - - memset((void *)((uintptr_t)deviceconfig_dialog) + sizeof(DIALOG), 0, sizeof(deviceconfig_dialog) - sizeof(DIALOG)); - deviceconfig_dialog[0].x = deviceconfig_dialog[0].y = 0; - - while (config->type != -1) - { - d = &deviceconfig_dialog[dialog_pos]; - - switch (config->type) - { - case CONFIG_BINARY: - d->x = 32; - d->y = y; - - d->w = 118*2; - d->h = 15; - - d->dp = config->description; - d->proc = d_check_proc; - - d->flags = config_get_int(device->name, config->name, config->default_int) ? D_SELECTED : 0; - d->bg = 0xffffff; - d->fg = 0; - - dialog_pos++; - - y += 20; - break; - - case CONFIG_SELECTION: - if (list_pos >= MAX_CONFIG_SELECTIONS) - break; - - d->x = 32; - d->y = y; - - d->w = 80; - d->h = 15; - - d->dp = config->description; - d->proc = d_text_proc; - - d->flags = 0; - d->bg = 0xffffff; - d->fg = 0; - - d++; - - d->x = 250; - d->y = y; - - d->w = 304; - d->h = 20; - - switch (list_pos) - { - case 0 : d->dp = list_proc_device_0; break; - case 1 : d->dp = list_proc_device_1; break; - case 2 : d->dp = list_proc_device_2; break; - case 3 : d->dp = list_proc_device_3; break; - case 4 : d->dp = list_proc_device_4; break; - case 5 : d->dp = list_proc_device_5; break; - case 6 : d->dp = list_proc_device_6; break; - case 7 : d->dp = list_proc_device_7; break; - } - d->proc = d_list_proc; - - d->flags = 0; - d->bg = 0xffffff; - d->fg = 0; - - config_selections[list_pos++] = config->selection; - - c = 0; - while (config->selection[c].description[0]) - { - if (config_get_int(device->name, config->name, config->default_int) == config->selection[c].value) - d->d1 = c; - c++; - } - - dialog_pos += 2; - - y += 20; - break; - - case CONFIG_MIDI: - break; - } - - config++; - - if (dialog_pos >= MAX_CONFIG_SIZE-3) - break; - } - - d = &deviceconfig_dialog[dialog_pos]; - - id_ok = dialog_pos; - id_cancel = dialog_pos + 1; - - d->x = 226; - d->y = y+8; - - d->w = 50; - d->h = 16; - - d->dp = "OK"; - d->proc = d_button_proc; - - d->flags = D_EXIT; - d->bg = 0xffffff; - d->fg = 0; - - d++; - - d->x = 296; - d->y = y+8; - - d->w = 50; - d->h = 16; - - d->dp = "Cancel"; - d->proc = d_button_proc; - - d->flags = D_EXIT; - d->bg = 0xffffff; - d->fg = 0; - - deviceconfig_dialog[0].h = y + 28; - - config_device = device; - - while (1) - { - position_dialog(deviceconfig_dialog, SCREEN_W/2 - deviceconfig_dialog[0].w/2, SCREEN_H/2 - deviceconfig_dialog[0].h/2); - - c = popup_dialog(deviceconfig_dialog, 1); - - position_dialog(deviceconfig_dialog, -(SCREEN_W/2 - deviceconfig_dialog[0].w/2), -(SCREEN_H/2 - deviceconfig_dialog[0].h/2)); - - if (c == id_ok) - { - int changed = 0; - - dialog_pos = 1; - config = device->config; - - while (config->type != -1) - { - int val; - - d = &deviceconfig_dialog[dialog_pos]; - - switch (config->type) - { - case CONFIG_BINARY: - val = (d->flags & D_SELECTED) ? 1 : 0; - - if (val != config_get_int(device->name, config->name, config->default_int)) - changed = 1; - - dialog_pos++; - break; - - case CONFIG_SELECTION: - if (list_pos >= MAX_CONFIG_SELECTIONS) - break; - - d++; - - val = config->selection[d->d1].value; - - if (val != config_get_int(device->name, config->name, config->default_int)) - changed = 1; - - dialog_pos += 2; - break; - - case CONFIG_MIDI: - break; - } - - config++; - - if (dialog_pos >= MAX_CONFIG_SIZE-3) - break; - } - - if (!changed) - return; - - if (alert("This will reset 86Box!", "Okay to continue?", NULL, "OK", "Cancel", 0, 0) != 1) - continue; - - dialog_pos = 1; - config = device->config; - - while (config->type != -1) - { - int val; - - d = &deviceconfig_dialog[dialog_pos]; - - switch (config->type) - { - case CONFIG_BINARY: - val = (d->flags & D_SELECTED) ? 1 : 0; - - config_set_int(config_device->name, config->name, val); - - dialog_pos++; - break; - - case CONFIG_SELECTION: - if (list_pos >= MAX_CONFIG_SELECTIONS) - break; - - d++; - - val = config->selection[d->d1].value; - - config_set_int(config_device->name, config->name, val); - - dialog_pos += 2; - break; - - case CONFIG_MIDI: - break; - } - - config++; - - if (dialog_pos >= MAX_CONFIG_SIZE-3) - break; - } - - saveconfig(); - - resetpchard(); - - return; - } - - if (c == id_cancel) - break; - } -} diff --git a/src/allegro-gui-hdconf.c b/src/allegro-gui-hdconf.c deleted file mode 100644 index a493c319f..000000000 --- a/src/allegro-gui-hdconf.c +++ /dev/null @@ -1,516 +0,0 @@ -/* Copyright holders: Sarah Walker - see COPYING for more details -*/ -#define _LARGEFILE_SOURCE -#define _LARGEFILE64_SOURCE -#define _GNU_SOURCE - -#include -#include "ibm.h" -#include "device.h" -#include "ide.h" -#include "allegro-main.h" -#include "allegro-gui.h" - -static char hd_path[4][260]; -static char hd_sectors[4][10]; -static char hd_heads[4][10]; -static char hd_cylinders[4][10]; -static char hd_size[4][20]; - -static char hd_path_new[260]; -static char hd_sectors_new[10]; -static char hd_heads_new[10]; -static char hd_cylinders_new[10]; -static char hd_size_new[20]; - -static int new_cdrom_channel; - -static hard_disk_t hdc_new[4]; - -static DIALOG hdparams_dialog[]= -{ - {d_shadow_box_proc, 0, 0, 194*2,86,0,0xffffff,0,0, 0,0,0,0,0}, // 0 - - {d_button_proc, 126, 66, 50, 14, 0, 0xffffff, 0, D_EXIT, 0, 0, "OK", 0, 0}, // 1 - {d_button_proc, 196, 66, 50, 16, 0, 0xffffff, 0, D_EXIT, 0, 0, "Cancel", 0, 0}, // 2 - - {d_text_proc, 7*2, 6, 170, 10, 0, 0xffffff, 0, 0, 0, 0, "Initial settings are based on file size", 0, 0}, - - {d_text_proc, 7*2, 22, 27, 10, 0, 0xffffff, 0, 0, 0, 0, "Sectors:", 0, 0}, - {d_text_proc, 63*2, 22, 29, 8, 0, 0xffffff, 0, 0, 0, 0, "Heads:", 0, 0}, - {d_text_proc, 120*2, 22, 28, 12, 0, 0xffffff, 0, 0, 0, 0, "Cylinders:", 0, 0}, - {d_edit_proc, 44*2, 22, 16*2, 12, 0, 0xffffff, 0, 0, 2, 0, hd_sectors_new, 0, 0}, - {d_edit_proc, 92*2, 22, 16*2, 12, 0, 0xffffff, 0, 0, 3, 0, hd_heads_new, 0, 0}, - {d_edit_proc, 168*2, 22, 24*2, 12, 0, 0xffffff, 0, 0, 5, 0, hd_cylinders_new, 0, 0}, - {d_text_proc, 7*2, 54, 136, 12, 0, 0xffffff, 0, 0, 0, 0, hd_size_new, 0, 0}, - - {0,0,0,0,0,0,0,0,0,0,0,NULL,NULL,NULL} -}; - -static int hdconf_open(int msg, DIALOG *d, int c) -{ - int drv = d->d2; - int ret = d_button_proc(msg, d, c); - - if (ret == D_EXIT) - { - char fn[260]; - int xsize = SCREEN_W - 32, ysize = SCREEN_H - 64; - - strcpy(fn, hd_path[drv]); - ret = file_select_ex("Please choose a disc image", fn, "IMG", 260, xsize, ysize); - if (ret) - { - uint64_t sz; - FILE *f = fopen64(fn, "rb"); - if (!f) - { - return D_REDRAW; - } - fseeko64(f, -1, SEEK_END); - sz = ftello64(f) + 1; - fclose(f); - sprintf(hd_sectors_new, "63"); - sprintf(hd_heads_new, "16"); - sprintf(hd_cylinders_new, "%i", (int)((sz / 512) / 16) / 63); - - while (1) - { - position_dialog(hdparams_dialog, SCREEN_W/2 - 186, SCREEN_H/2 - 86/2); - - ret = popup_dialog(hdparams_dialog, 1); - - position_dialog(hdparams_dialog, -(SCREEN_W/2 - 186), -(SCREEN_H/2 - 86/2)); - - if (ret == 1) - { - int spt, hpc, cyl; - sscanf(hd_sectors_new, "%i", &spt); - sscanf(hd_heads_new, "%i", &hpc); - sscanf(hd_cylinders_new, "%i", &cyl); - - if (spt > 63) - { - alert("Drive has too many sectors (maximum is 63)", NULL, NULL, "OK", NULL, 0, 0); - continue; - } - if (hpc > 128) - { - alert("Drive has too many heads (maximum is 128)", NULL, NULL, "OK", NULL, 0, 0); - continue; - } - if (cyl > 16383) - { - alert("Drive has too many cylinders (maximum is 16383)", NULL, NULL, "OK", NULL, 0, 0); - continue; - } - - hdc_new[drv].spt = spt; - hdc_new[drv].hpc = hpc; - hdc_new[drv].tracks = cyl; - - strcpy(hd_path[drv], fn); - sprintf(hd_sectors[drv], "%i", hdc_new[drv].spt); - sprintf(hd_heads[drv], "%i", hdc_new[drv].hpc); - sprintf(hd_cylinders[drv], "%i", hdc_new[drv].tracks); - sprintf(hd_size[drv], "Size : %imb", (((((uint64_t)hdc_new[drv].tracks*(uint64_t)hdc_new[drv].hpc)*(uint64_t)hdc_new[drv].spt)*512)/1024)/1024); - - return D_REDRAW; - } - - if (ret == 2) - break; - } - } - - return D_REDRAW; - } - - return ret; -} - -static int hdconf_new_file(int msg, DIALOG *d, int c) -{ - int ret = d_button_proc(msg, d, c); - - if (ret == D_EXIT) - { - char fn[260]; - int xsize = SCREEN_W - 32, ysize = SCREEN_H - 64; - - strcpy(fn, hd_path_new); - ret = file_select_ex("Please choose a disc image", fn, "IMG", 260, xsize, ysize); - if (ret) - strcpy(hd_path_new, fn); - - return D_REDRAW; - } - - return ret; -} - -static DIALOG hdnew_dialog[]= -{ - {d_shadow_box_proc, 0, 0, 194*2,86,0,0xffffff,0,0, 0,0,0,0,0}, // 0 - - {d_button_proc, 126, 66, 50, 14, 0, 0xffffff, 0, D_EXIT, 0, 0, "OK", 0, 0}, // 1 - {d_button_proc, 196, 66, 50, 16, 0, 0xffffff, 0, D_EXIT, 0, 0, "Cancel", 0, 0}, // 2 - - {d_edit_proc, 7*2, 6, 136*2, 10, 0, 0xffffff, 0, 0, 0, 0, hd_path_new, 0, 0}, - {hdconf_new_file, 143*2, 6, 16*2, 14, 0, 0xffffff, 0, D_EXIT, 0, 0, "...", 0, 0}, - - {d_text_proc, 7*2, 22, 27, 10, 0, 0xffffff, 0, 0, 0, 0, "Sectors:", 0, 0}, - {d_text_proc, 63*2, 22, 29, 8, 0, 0xffffff, 0, 0, 0, 0, "Heads:", 0, 0}, - {d_text_proc, 120*2, 22, 28, 12, 0, 0xffffff, 0, 0, 0, 0, "Cylinders:", 0, 0}, - {d_edit_proc, 44*2, 22, 16*2, 12, 0, 0xffffff, 0, 0, 2, 0, hd_sectors_new, 0, 0}, - {d_edit_proc, 92*2, 22, 16*2, 12, 0, 0xffffff, 0, 0, 3, 0, hd_heads_new, 0, 0}, - {d_edit_proc, 168*2, 22, 24*2, 12, 0, 0xffffff, 0, 0, 5, 0, hd_cylinders_new, 0, 0}, -// {d_text_proc, 7*2, 54, 136, 12, 0, -1, 0, 0, 0, 0, hd_size_new, 0, 0}, - - {0,0,0,0,0,0,0,0,0,0,0,NULL,NULL,NULL} -}; - -static int create_hd(char *fn, int cyl, int hpc, int spt) -{ - int c; - int e; - uint8_t buf[512]; - FILE *f = fopen64(hd_path_new, "wb"); - e = errno; - if (!f) - { - alert("Can't open file for write", NULL, NULL, "OK", NULL, 0, 0); - return -1; - } - memset(buf, 0, 512); - for (c = 0; c < (cyl * hpc * spt); c++) - { - fwrite(buf, 512, 1, f); - } - fclose(f); -} - -static int hdconf_new(int msg, DIALOG *d, int c) -{ - int drv = d->d2; - int ret = d_button_proc(msg, d, c); - - if (ret == D_EXIT) - { - sprintf(hd_sectors_new, "63"); - sprintf(hd_heads_new, "16"); - sprintf(hd_cylinders_new, "511"); - strcpy(hd_path_new, ""); - - while (1) - { - position_dialog(hdnew_dialog, SCREEN_W/2 - 186, SCREEN_H/2 - 86/2); - - ret = popup_dialog(hdnew_dialog, 1); - - position_dialog(hdnew_dialog, -(SCREEN_W/2 - 186), -(SCREEN_H/2 - 86/2)); - - if (ret == 1) - { - int spt, hpc, cyl; - int c, d; - FILE *f; - uint8_t *buf; - - sscanf(hd_sectors_new, "%i", &spt); - sscanf(hd_heads_new, "%i", &hpc); - sscanf(hd_cylinders_new, "%i", &cyl); - - if (spt > 63) - { - alert("Drive has too many sectors (maximum is 63)", NULL, NULL, "OK", NULL, 0, 0); - continue; - } - if (hpc > 128) - { - alert("Drive has too many heads (maximum is 128)", NULL, NULL, "OK", NULL, 0, 0); - continue; - } - if (cyl > 16383) - { - alert("Drive has too many cylinders (maximum is 16383)", NULL, NULL, "OK", NULL, 0, 0); - continue; - } - if (create_hd(hd_path_new, cyl, hpc, spt)) - return D_REDRAW; - - alert("Remember to partition and format the new drive", NULL, NULL, "OK", NULL, 0, 0); - - hdc_new[drv].spt = spt; - hdc_new[drv].hpc = hpc; - hdc_new[drv].tracks = cyl; - - strcpy(hd_path[drv], hd_path_new); - sprintf(hd_sectors[drv], "%i", hdc_new[drv].spt); - sprintf(hd_heads[drv], "%i", hdc_new[drv].hpc); - sprintf(hd_cylinders[drv], "%i", hdc_new[drv].tracks); - sprintf(hd_size[drv], "Size : %imb", (((((uint64_t)hdc_new[drv].tracks*(uint64_t)hdc_new[drv].hpc)*(uint64_t)hdc_new[drv].spt)*512)/1024)/1024); - - return D_REDRAW; - } - - if (ret == 2) - break; - } - - return D_REDRAW; - } - - return ret; -} - -static int hdconf_eject(int msg, DIALOG *d, int c) -{ - int drv = d->d2; - int ret = d_button_proc(msg, d, c); - - if (ret == D_EXIT) - { - hdc_new[drv].spt = 0; - hdc_new[drv].hpc = 0; - hdc_new[drv].tracks = 0; - strcpy(hd_path[drv], ""); - sprintf(hd_sectors[drv], "%i", hdc_new[drv].spt); - sprintf(hd_heads[drv], "%i", hdc_new[drv].hpc); - sprintf(hd_cylinders[drv], "%i", hdc_new[drv].tracks); - sprintf(hd_size[drv], "Size : %imb", (((((uint64_t)hdc_new[drv].tracks*(uint64_t)hdc_new[drv].hpc)*(uint64_t)hdc_new[drv].spt)*512)/1024)/1024); - - return D_REDRAW; - } - - return ret; -} - -static int hdconf_radio_hd(int msg, DIALOG *d, int c); -static int hdconf_radio_cd(int msg, DIALOG *d, int c); - -static DIALOG hdconf_dialog[]= -{ - {d_shadow_box_proc, 0, 0, 210*2,354,0,0xffffff,0,0, 0,0,0,0,0}, // 0 - - {d_button_proc, 150, 334, 50, 16, 0, 0xffffff, 0, D_EXIT, 0, 0, "OK", 0, 0}, // 1 - {d_button_proc, 220, 334, 50, 16, 0, 0xffffff, 0, D_EXIT, 0, 0, "Cancel", 0, 0}, // 2 - - {d_text_proc, 7*2, 6, 27, 10, 0, 0xffffff, 0, 0, 0, 0, "C:", 0, 0}, - {hdconf_radio_hd, 7*2, 22, 96, 12, 0, 0xffffff, 0, D_EXIT, 0, 0, "Hard drive", 0, 0}, // 4 - {hdconf_radio_cd, 100*2, 22, 64, 12, 0, 0xffffff, 0, D_EXIT, 0, 0, "CD-ROM", 0, 0}, // 5 - {d_edit_proc, 7*2, 38, 136*2, 12, 0, 0xffffff, 0, D_DISABLED, 0, 0, hd_path[0], 0, 0}, - {hdconf_open, 143*2, 38, 16*2, 14, 0, 0xffffff, 0, D_EXIT, 0, 0, "...", 0, 0}, - {hdconf_new, 159*2, 38, 24*2, 14, 0, 0xffffff, 0, D_EXIT, 0, 0, "New", 0, 0}, - {hdconf_eject, 183*2, 38, 24*2, 14, 0, 0xffffff, 0, D_EXIT, 0, 0, "Eject", 0, 0}, - - {d_text_proc, 7*2, 54, 27, 10, 0, 0xffffff, 0, 0, 0, 0, "Sectors:", 0, 0}, - {d_text_proc, 63*2, 54, 29, 8, 0, 0xffffff, 0, 0, 0, 0, "Heads:", 0, 0}, - {d_text_proc, 120*2, 54, 28, 12, 0, 0xffffff, 0, 0, 0, 0, "Cylinders:", 0, 0}, - {d_edit_proc, 44*2, 54, 16*2, 12, 0, 0xffffff, 0, D_DISABLED, 0, 0, hd_sectors[0], 0, 0}, - {d_edit_proc, 92*2, 54, 16*2, 12, 0, 0xffffff, 0, D_DISABLED, 0, 0, hd_heads[0], 0, 0}, - {d_edit_proc, 168*2, 54, 24*2, 12, 0, 0xffffff, 0, D_DISABLED, 0, 0, hd_cylinders[0], 0, 0}, - {d_text_proc, 7*2, 54, 136, 12, 0, 0xffffff, 0, 0, 0, 0, hd_size[0], 0, 0}, - - {d_text_proc, 7*2, 76, 27, 10, 0, 0xffffff, 0, 0, 0, 0, "D:", 0, 0}, - {hdconf_radio_hd, 7*2, 92, 96, 12, 0, 0xffffff, 0, D_EXIT, 1, 0, "Hard drive", 0, 0}, // 18 - {hdconf_radio_cd, 100*2, 92, 64, 12, 0, 0xffffff, 0, D_EXIT, 1, 0, "CD-ROM", 0, 0}, // 19 - {d_edit_proc, 7*2, 108, 136*2, 12, 0, 0xffffff, 0, D_DISABLED, 0, 0, hd_path[1], 0, 0}, - {hdconf_open, 143*2, 108, 16*2, 14, 0, 0xffffff, 0, D_EXIT, 0, 1, "...", 0, 0}, - {hdconf_new, 159*2, 108, 24*2, 14, 0, 0xffffff, 0, D_EXIT, 0, 1, "New", 0, 0}, - {hdconf_eject, 183*2, 108, 24*2, 14, 0, 0xffffff, 0, D_EXIT, 0, 1, "Eject", 0, 0}, - - {d_edit_proc, 44*2, 124, 16*2, 12, 0, 0xffffff, 0, D_DISABLED, 0, 0, hd_sectors[1], 0, 0}, - {d_edit_proc, 92*2, 124, 16*2, 12, 0, 0xffffff, 0, D_DISABLED, 0, 0, hd_heads[1], 0, 0}, - {d_edit_proc, 168*2, 124, 24*2, 12, 0, 0xffffff, 0, D_DISABLED, 0, 0, hd_cylinders[1], 0, 0}, - {d_text_proc, 7*2, 124, 27, 10, 0, 0xffffff, 0, 0, 0, 0, "Sectors:", 0, 0}, - {d_text_proc, 63*2, 124, 29, 8, 0, 0xffffff, 0, 0, 0, 0, "Heads:", 0, 0}, - {d_text_proc, 120*2, 124, 32, 12, 0, 0xffffff, 0, 0, 0, 0, "Cylinders:", 0, 0}, - {d_text_proc, 7*2, 140, 136, 12, 0, 0xffffff, 0, 0, 0, 0, hd_size[1], 0, 0}, - - {d_text_proc, 7*2, 162, 27, 10, 0, 0xffffff, 0, 0, 0, 0, "E:", 0, 0}, - {hdconf_radio_hd, 7*2, 178, 96, 12, 0, 0xffffff, 0, D_EXIT, 2, 0, "Hard drive", 0, 0}, // 32 - {hdconf_radio_cd, 100*2, 178, 64, 12, 0, 0xffffff, 0, D_EXIT, 2, 0, "CD-ROM", 0, 0}, // 33 - {d_edit_proc, 7*2, 194, 136*2, 12, 0, 0xffffff, 0, D_DISABLED, 0, 0, hd_path[2], 0, 0}, - {hdconf_open, 143*2, 194, 16*2, 14, 0, 0xffffff, 0, D_EXIT, 0, 2, "...", 0, 0}, - {hdconf_new, 159*2, 194, 24*2, 14, 0, 0xffffff, 0, D_EXIT, 0, 2, "New", 0, 0}, - {hdconf_eject, 183*2, 194, 24*2, 14, 0, 0xffffff, 0, D_EXIT, 0, 2, "Eject", 0, 0}, - - {d_edit_proc, 44*2, 210, 16*2, 12, 0, 0xffffff, 0, D_DISABLED, 0, 0, hd_sectors[2], 0, 0}, - {d_edit_proc, 92*2, 210, 16*2, 12, 0, 0xffffff, 0, D_DISABLED, 0, 0, hd_heads[2], 0, 0}, - {d_edit_proc, 168*2, 210, 24*2, 12, 0, 0xffffff, 0, D_DISABLED, 0, 0, hd_cylinders[2], 0, 0}, - {d_text_proc, 7*2, 210, 27, 10, 0, 0xffffff, 0, 0, 0, 0, "Sectors:", 0, 0}, - {d_text_proc, 63*2, 210, 29, 8, 0, 0xffffff, 0, 0, 0, 0, "Heads:", 0, 0}, - {d_text_proc, 120*2, 210, 32, 12, 0, 0xffffff, 0, 0, 0, 0, "Cylinders:", 0, 0}, - {d_text_proc, 7*2, 226, 136, 12, 0, 0xffffff, 0, 0, 0, 0, hd_size[2], 0, 0}, - - {d_text_proc, 7*2, 248, 27, 10, 0, 0xffffff, 0, 0, 0, 0, "F:", 0, 0}, - {hdconf_radio_hd, 7*2, 264, 96, 12, 0, 0xffffff, 0, D_EXIT, 3, 0, "Hard drive", 0, 0}, // 46 - {hdconf_radio_cd, 100*2, 264, 64, 12, 0, 0xffffff, 0, D_EXIT, 3, 0, "CD-ROM", 0, 0}, // 47 - {d_edit_proc, 7*2, 280, 136*2, 12, 0, 0xffffff, 0, D_DISABLED, 0, 0, hd_path[3], 0, 0}, - {hdconf_open, 143*2, 280, 16*2, 14, 0, 0xffffff, 0, D_EXIT, 0, 3, "...", 0, 0}, - {hdconf_new, 159*2, 280, 24*2, 14, 0, 0xffffff, 0, D_EXIT, 0, 3, "New", 0, 0}, - {hdconf_eject, 183*2, 280, 24*2, 14, 0, 0xffffff, 0, D_EXIT, 0, 3, "Eject", 0, 0}, - - {d_edit_proc, 44*2, 296, 16*2, 12, 0, 0xffffff, 0, D_DISABLED, 0, 0, hd_sectors[3], 0, 0}, - {d_edit_proc, 92*2, 296, 16*2, 12, 0, 0xffffff, 0, D_DISABLED, 0, 0, hd_heads[3], 0, 0}, - {d_edit_proc, 168*2, 296, 24*2, 12, 0, 0xffffff, 0, D_DISABLED, 0, 0, hd_cylinders[3], 0, 0}, - {d_text_proc, 7*2, 296, 27, 10, 0, 0xffffff, 0, 0, 0, 0, "Sectors:", 0, 0}, - {d_text_proc, 63*2, 296, 29, 8, 0, 0xffffff, 0, 0, 0, 0, "Heads:", 0, 0}, - {d_text_proc, 120*2, 296, 32, 12, 0, 0xffffff, 0, 0, 0, 0, "Cylinders:", 0, 0}, - {d_text_proc, 7*2, 312, 136, 12, 0, 0xffffff, 0, 0, 0, 0, hd_size[3], 0, 0}, - - {0,0,0,0,0,0,0,0,0,0,0,NULL,NULL,NULL} -}; - -static void update_hdd_cdrom() -{ - if (new_cdrom_channel == 0) - { - hdconf_dialog[4].flags &= ~D_SELECTED; - hdconf_dialog[5].flags |= D_SELECTED; - } - else - { - hdconf_dialog[4].flags |= D_SELECTED; - hdconf_dialog[5].flags &= ~D_SELECTED; - } - if (new_cdrom_channel == 1) - { - hdconf_dialog[18].flags &= ~D_SELECTED; - hdconf_dialog[19].flags |= D_SELECTED; - } - else - { - hdconf_dialog[18].flags |= D_SELECTED; - hdconf_dialog[19].flags &= ~D_SELECTED; - } - if (new_cdrom_channel == 2) - { - hdconf_dialog[32].flags &= ~D_SELECTED; - hdconf_dialog[33].flags |= D_SELECTED; - } - else - { - hdconf_dialog[32].flags |= D_SELECTED; - hdconf_dialog[33].flags &= ~D_SELECTED; - } - if (new_cdrom_channel == 3) - { - hdconf_dialog[46].flags &= ~D_SELECTED; - hdconf_dialog[47].flags |= D_SELECTED; - } - else - { - hdconf_dialog[46].flags |= D_SELECTED; - hdconf_dialog[47].flags &= ~D_SELECTED; - } -} - -static int hdconf_radio_hd(int msg, DIALOG *d, int c) -{ - int ret = d_radio_proc(msg, d, c); - - if (ret == D_CLOSE) - { - if (new_cdrom_channel == d->d1) - { - new_cdrom_channel = -1; - update_hdd_cdrom(); - } - - return D_REDRAW; - } - - return ret; -} -static int hdconf_radio_cd(int msg, DIALOG *d, int c) -{ - int ret = d_radio_proc(msg, d, c); - - if (ret == D_CLOSE) - { - if (new_cdrom_channel != d->d1) - { - new_cdrom_channel = d->d1; - update_hdd_cdrom(); - } - - return D_REDRAW; - } - - return ret; -} - -int disc_hdconf() -{ - int c; - int changed=0; - - hdc_new[0] = hdc[0]; - hdc_new[1] = hdc[1]; - hdc_new[2] = hdc[2]; - hdc_new[3] = hdc[3]; - strcpy(hd_path[0], ide_fn[0]); - strcpy(hd_path[1], ide_fn[1]); - strcpy(hd_path[2], ide_fn[2]); - strcpy(hd_path[3], ide_fn[3]); - sprintf(hd_sectors[0], "%i", hdc[0].spt); - sprintf(hd_sectors[1], "%i", hdc[1].spt); - sprintf(hd_sectors[2], "%i", hdc[2].spt); - sprintf(hd_sectors[3], "%i", hdc[3].spt); - sprintf(hd_heads[0], "%i", hdc[0].hpc); - sprintf(hd_heads[1], "%i", hdc[1].hpc); - sprintf(hd_heads[2], "%i", hdc[2].hpc); - sprintf(hd_heads[3], "%i", hdc[3].hpc); - sprintf(hd_cylinders[0], "%i", hdc[0].tracks); - sprintf(hd_cylinders[1], "%i", hdc[1].tracks); - sprintf(hd_cylinders[2], "%i", hdc[2].tracks); - sprintf(hd_cylinders[3], "%i", hdc[3].tracks); - sprintf(hd_size[0], "Size : %imb", (((((uint64_t)hdc[0].tracks*(uint64_t)hdc[0].hpc)*(uint64_t)hdc[0].spt)*512)/1024)/1024); - sprintf(hd_size[1], "Size : %imb", (((((uint64_t)hdc[1].tracks*(uint64_t)hdc[1].hpc)*(uint64_t)hdc[1].spt)*512)/1024)/1024); - sprintf(hd_size[2], "Size : %imb", (((((uint64_t)hdc[2].tracks*(uint64_t)hdc[2].hpc)*(uint64_t)hdc[2].spt)*512)/1024)/1024); - sprintf(hd_size[3], "Size : %imb", (((((uint64_t)hdc[3].tracks*(uint64_t)hdc[3].hpc)*(uint64_t)hdc[3].spt)*512)/1024)/1024); - - new_cdrom_channel = cdrom_channel; - - update_hdd_cdrom(); - - while (1) - { - position_dialog(hdconf_dialog, SCREEN_W/2 - hdconf_dialog[0].w/2, SCREEN_H/2 - hdconf_dialog[0].h/2); - - c = popup_dialog(hdconf_dialog, 1); - - position_dialog(hdconf_dialog, -(SCREEN_W/2 - hdconf_dialog[0].w/2), -(SCREEN_H/2 - hdconf_dialog[0].h/2)); - - if (c == 1) - { - if (alert("This will reset 86Box!", "Okay to continue?", NULL, "OK", "Cancel", 0, 0) == 1) - { - hdc[0] = hdc_new[0]; - hdc[1] = hdc_new[1]; - hdc[2] = hdc_new[2]; - hdc[3] = hdc_new[3]; - - strcpy(ide_fn[0], hd_path[0]); - strcpy(ide_fn[1], hd_path[1]); - strcpy(ide_fn[2], hd_path[2]); - strcpy(ide_fn[3], hd_path[3]); - - cdrom_channel = new_cdrom_channel; - - saveconfig(); - - resetpchard(); - - return D_O_K; - } - } - if (c == 2) - return D_O_K; - } - - return D_O_K; -} diff --git a/src/allegro-gui.c b/src/allegro-gui.c deleted file mode 100644 index 63b6ddef8..000000000 --- a/src/allegro-gui.c +++ /dev/null @@ -1,229 +0,0 @@ -/* Copyright holders: Sarah Walker - see COPYING for more details -*/ -#include "ibm.h" -#include "device.h" -#include "allegro-main.h" -#include "allegro-gui.h" -#include "disc.h" -#include "ide.h" - -static int file_return(void) -{ - return D_CLOSE; -} - -static int file_exit(void) -{ - quited = 1; - return D_CLOSE; -} - -static int file_reset(void) -{ - resetpchard(); - return D_CLOSE; -} - -static int file_cad(void) -{ - resetpc_cad(); - return D_CLOSE; -} - - -static MENU file_menu[]= -{ - {"&Return", file_return, NULL, 0, NULL}, - {"&Hard Reset", file_reset, NULL, 0, NULL}, - {"&Ctrl+Alt+Del", file_cad, NULL, 0, NULL}, - {"E&xit", file_exit, NULL, 0, NULL}, - {NULL,NULL,NULL,0,NULL} -}; - -static int disc_load_a() -{ - char fn[260]; - int ret; - int xsize = SCREEN_W - 32, ysize = SCREEN_H - 64; - strcpy(fn, discfns[0]); - ret = file_select_ex("Please choose a disc image", fn, "IMG;IMA;FDI", 260, xsize, ysize); - if (ret) - { - disc_close(0); - disc_load(0, fn); - saveconfig(); - } - return D_O_K; -} - -static int disc_load_b() -{ - char fn[260]; - int ret; - int xsize = SCREEN_W - 32, ysize = SCREEN_H - 64; - strcpy(fn, discfns[1]); - ret = file_select_ex("Please choose a disc image", fn, "IMG;IMA;FDI", 260, xsize, ysize); - if (ret) - { - disc_close(1); - disc_load(1, fn); - saveconfig(); - } - return D_O_K; -} - -static int disc_eject_a() -{ - disc_close(0); - saveconfig(); - - return D_O_K; -} - -static int disc_eject_b() -{ - disc_close(1); - saveconfig(); - - return D_O_K; -} - -static MENU disc_menu[]= -{ - {"Load drive &A:...", disc_load_a, NULL, 0, NULL}, - {"Load drive &B:...", disc_load_b, NULL, 0, NULL}, - {"&Eject drive &A:", disc_eject_a, NULL, 0, NULL}, - {"Eject drive &B:", disc_eject_b, NULL, 0, NULL}, - {"&Configure hard discs...", disc_hdconf, NULL, 0, NULL}, - {NULL,NULL,NULL,0,NULL} -}; - -static MENU cdrom_menu[]; - -static void cdrom_update() -{ - int c; - - for (c = 0; cdrom_menu[c].text; c++) - cdrom_menu[c].flags = 0; - - if (!cdrom_enabled) - cdrom_menu[0].flags = D_SELECTED; - else - cdrom_menu[1].flags = D_SELECTED; - - return D_O_K; -} - -static int cdrom_disabled() -{ - if (!cdrom_enabled) - return D_O_K; - - if (alert("This will reset 86Box!", "Okay to continue?", NULL, "OK", "Cancel", 0, 0) == 1) - { - atapi->exit(); - cdrom_enabled = 0; - saveconfig(); - resetpchard(); - cdrom_update(); - } - - return D_O_K; -} - -static int cdrom_empty() -{ - if (cdrom_enabled) - { - atapi->exit(); - cdrom_drive = -1; - cdrom_null_open(cdrom_drive); - return D_O_K; - } - - if (alert("This will reset 86Box!", "Okay to continue?", NULL, "OK", "Cancel", 0, 0) == 1) - { - cdrom_drive = -1; - cdrom_enabled = 1; - cdrom_null_open(cdrom_drive); - saveconfig(); - resetpchard(); - cdrom_update(); - } -} - -static int cdrom_dev() -{ - if (cdrom_enabled) - { - atapi->exit(); - cdrom_drive = 1; - ioctl_open(cdrom_drive); - return D_O_K; - } - - if (alert("This will reset 86Box!", "Okay to continue?", NULL, "OK", "Cancel", 0, 0) == 1) - { - cdrom_drive = 1; - cdrom_enabled = 1; - ioctl_open(cdrom_drive); - saveconfig(); - resetpchard(); - cdrom_update(); - } -} - -static MENU cdrom_menu[] = -{ - {"&Disabled", cdrom_disabled, NULL, 0, NULL}, - {"&Empty", cdrom_empty, NULL, 0, NULL}, - {"/dev/cdrom", cdrom_dev, NULL, 0, NULL}, - {NULL,NULL,NULL,0,NULL} -}; - -static MENU settings_menu[]= -{ - {"&Configure...", settings_configure, NULL, 0, NULL}, - {"CD-ROM", NULL, cdrom_menu, 0, NULL}, - {NULL,NULL,NULL,0,NULL} -}; - -static MENU main_menu[]= -{ - {"&File", NULL, file_menu, 0, NULL}, - {"&Disc", NULL, disc_menu, 0, NULL}, - {"&Settings", NULL, settings_menu, 0, NULL}, - {NULL,NULL,NULL,0,NULL} -}; - -static DIALOG main_windows_gui[]= -{ - {d_menu_proc, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, main_menu, NULL, NULL}, - {d_yield_proc, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, NULL, NULL, NULL}, - {0,0,0,0,0,0,0,0,0,0,0,NULL,NULL,NULL} -}; - -void gui_enter() -{ - DIALOG_PLAYER *dp; - int x = 1; - infocus = 0; - - dp = init_dialog(main_windows_gui, 0); - show_mouse(screen); - while (x && !(mouse_b & 2) && !key[KEY_ESC]) - { - x = update_dialog(dp); - } - show_mouse(NULL); - shutdown_dialog(dp); - - clear(screen); - clear_keybuf(); - - infocus = 1; - - device_force_redraw(); -} diff --git a/src/allegro-gui.h b/src/allegro-gui.h deleted file mode 100644 index 1ea830552..000000000 --- a/src/allegro-gui.h +++ /dev/null @@ -1,15 +0,0 @@ -/* Copyright holders: Sarah Walker - see COPYING for more details -*/ -void gui_enter(); - -extern int quited; - -extern int romspresent[ROM_MAX]; -extern int gfx_present[GFX_MAX]; - -int disc_hdconf(); - -int settings_configure(); - -void deviceconfig_open(device_t *device); diff --git a/src/allegro-joystick.c b/src/allegro-joystick.c deleted file mode 100644 index ed03267f9..000000000 --- a/src/allegro-joystick.c +++ /dev/null @@ -1,52 +0,0 @@ -/* Copyright holders: Sarah Walker - see COPYING for more details -*/ -#include "allegro-main.h" -#include "plat-joystick.h" -#include "device.h" -#include "gameport.h" - -plat_joystick_t plat_joystick_state[MAX_PLAT_JOYSTICKS]; -joystick_t joystick_state[MAX_JOYSTICKS]; - -int joysticks_present; - -void joystick_init() -{ - install_joystick(JOY_TYPE_AUTODETECT); - joysticks_present = num_joysticks; -} -void joystick_close() -{ -} -void joystick_poll() -{ - int c, d; - - poll_joystick(); - - for (c = 0; c < num_joysticks; c++) - { - plat_joystick_state[c].a[0] = joy[c].stick[0].axis[0].pos * 256; - plat_joystick_state[c].a[1] = joy[c].stick[0].axis[1].pos * 256; - for (d = 0; d < MAX_JOYSTICK_BUTTONS; d++) - plat_joystick_state[c].b[d] = joy[c].button[d].b; - } - for (c = 0; c < joystick_get_max_joysticks(joystick_type); c++) - { - if (c < num_joysticks) - { - for (d = 0; d < joystick_get_axis_count(joystick_type); d++) - joystick_state[c].axis[d] = plat_joystick_state[c].a[d]; - for (d = 0; d < joystick_get_button_count(joystick_type); d++) - joystick_state[c].button[d] = plat_joystick_state[c].b[d]; - } - else - { - for (d = 0; d < joystick_get_axis_count(joystick_type); d++) - joystick_state[c].axis[d] = 0; - for (d = 0; d < joystick_get_button_count(joystick_type); d++) - joystick_state[c].button[d] = 0; - } - } -} diff --git a/src/allegro-keyboard.c b/src/allegro-keyboard.c deleted file mode 100644 index a3e3c3a51..000000000 --- a/src/allegro-keyboard.c +++ /dev/null @@ -1,52 +0,0 @@ -/* Copyright holders: Sarah Walker - see COPYING for more details -*/ -#include "allegro-main.h" -#include "plat-keyboard.h" - -int recv_key[272]; -int rawinputkey[272]; - -static int key_convert[128] = -{ - -1, 0x1e, 0x30, 0x2e, 0x20, 0x12, 0x21, 0x22, /* , A, B, C, D, E, F, G*/ - 0x23, 0x17, 0x24, 0x25, 0x26, 0x32, 0x31, 0x18, /* H, I, J, K, L, M, N, O*/ - 0x19, 0x10, 0x13, 0x1f, 0x14, 0x16, 0x2f, 0x11, /* P, Q, R, S, T, U, V, W*/ - 0x2d, 0x15, 0x2c, 0x0b, 0x02, 0x03, 0x04, 0x05, /* X, Y, Z, 0, 1, 2, 3, 4*/ - 0x06, 0x07, 0x08, 0x09, 0x0a, 0x52, 0x4f, 0x50, /* 5, 6, 7, 8, 9, p0, p1, p2*/ - 0x51, 0x4b, 0x4c, 0x4d, 0x47, 0x48, 0x49, 0x3b, /* p3, p4, p5, p6, p7, p8, p9, F1*/ - 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, /* F2, F3, F4, F5, F6, F7, F8, F9*/ - 0x44, 0x57, 0x58, 0x01, 0x29, 0x0c, 0x0d, 0x0e, /*F10, F11, F12, ESC, `ª, -_, =+, backspace*/ - 0x0f, 0x1a, 0x1b, 0x1c, 0x27, 0x28, 0x2b, 0x56, /*TAB, [{, ]}, ENT, ;:, '@, \|, #~*/ - 0x33, 0x34, 0x35, 0x39, 0xd2, 0xd3, 0xc7, 0xcf, /* ,<, .>, /?, SPC, INS, DEL, HOME, END*/ - 0xc9, 0xd1, 0xcb, 0xcd, 0xc8, 0xd0, 0xb5, 0x37, /*PGU, PGD, LFT, RHT, UP, DN, /, * */ - 0x4a, 0x4e, 0x53, 0x9c, 0xff, -1, -1, -1, /* p-, p+, pDL, pEN, psc, pse, abnt, yen*/ - -1, -1, -1, -1, -1, -1, -1, -1, /*kana, convert, noconvert, at, circumflex, colon2, kanji, pad equals*/ - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 0x2a, 0x36, 0x1d, 0x9d, 0x38, /*, , lshift, rshift, lctrl, rctrl, alt*/ - 0xb8, 0xdb, 0xdc, 0xdd, 0x46, 0x45, 0x3a, -1 /*altgr, lwin, rwin, menu, scrlock, numlock, capslock*/ -}; - -void keyboard_init() -{ - install_keyboard(); -} - -void keyboard_close() -{ -} - -void keyboard_poll_host() -{ - int c; - - for (c = 0; c < 128; c++) - { - int key_idx = key_convert[c]; - if (key_idx == -1) - continue; - - if (key[c] != recv_key[key_idx]) - recv_key[key_idx] = key[c]; - } -} diff --git a/src/allegro-main.c b/src/allegro-main.c deleted file mode 100644 index 65bd43aea..000000000 --- a/src/allegro-main.c +++ /dev/null @@ -1,172 +0,0 @@ -/* Copyright holders: Sarah Walker - see COPYING for more details -*/ -#include "allegro-main.h" -#include "ibm.h" -#include "cpu.h" -#include "model.h" -#include "nvr.h" -#include "video.h" - -#undef printf - -int mousecapture = 0; -int quited = 0; -int winsizex = -1, winsizey = -1; - -int romspresent[ROM_MAX]; -int gfx_present[GFX_MAX]; - -void updatewindowsize(int x, int y) -{ - if (x < 128) - x = 128; - if (y < 128) - y = 128; - if (winsizex != x || winsizey != y) - { - winsizex = x; - winsizey = y; - allegro_video_update_size(x, y); - } -} - -void startblit() -{ -} - -void endblit() -{ -} - -static int ticks = 0; -static void timer_rout() -{ - ticks++; -} - -uint64_t timer_freq; -uint64_t timer_read() -{ - return 0; -} - -int main(int argc, char *argv[]) -{ - int frames = 0; - int c, d; - allegro_init(); - allegro_video_init(); - install_timer(); - install_int_ex(timer_rout, BPS_TO_TIMER(100)); - install_int_ex(onesec, BPS_TO_TIMER(1)); - midi_init(); - - initpc(argc, argv); - - d = romset; - for (c = 0; c < ROM_MAX; c++) - { - romset = c; - romspresent[c] = loadbios(); - pclog("romset %i - %i\n", c, romspresent[c]); - } - - for (c = 0; c < ROM_MAX; c++) - { - if (romspresent[c]) - break; - } - if (c == ROM_MAX) - { - printf("No ROMs present!\nYou must have at least one romset to use 86Box."); - return 0; - } - - romset=d; - c=loadbios(); - - if (!c) - { - if (romset != -1) - printf("Configured romset not available.\nDefaulting to available romset."); - for (c = 0; c < ROM_MAX; c++) - { - if (romspresent[c]) - { - romset = c; - model = model_getmodel(romset); - saveconfig(); - resetpchard(); - break; - } - } - } - - for (c = 0; c < GFX_MAX; c++) - gfx_present[c] = video_card_available(video_old_to_new(c)); - - if (!video_card_available(video_old_to_new(gfxcard))) - { - if (gfxcard) printf("Configured video BIOS not available.\nDefaulting to available romset."); - for (c = GFX_MAX-1; c >= 0; c--) - { - if (gfx_present[c]) - { - gfxcard = c; - saveconfig(); - resetpchard(); - break; - } - } - } - - resetpchard(); - - ticks = 0; - while (!quited) - { - if (ticks) - { - ticks--; - runpc(); - frames++; - if (frames >= 200 && nvr_dosave) - { - frames = 0; - nvr_dosave = 0; - savenvr(); - } - } - else - rest(1); - - if (ticks > 10) - ticks = 0; - - if ((mouse_b & 1) && !mousecapture) - mousecapture = 1; - - if (((key[KEY_LCONTROL] || key[KEY_RCONTROL]) && key[KEY_END]) || (mouse_b & 4)) - mousecapture = 0; - - if ((key[KEY_LCONTROL] || key[KEY_RCONTROL]) && key[KEY_ALT] && key[KEY_PGDN]) - { - int old_winsizex = winsizex, old_winsizey = winsizey; - if (winsizex < 512 || winsizey < 350) - updatewindowsize(512, 350); - gui_enter(); - if (old_winsizex < 512 || old_winsizey < 350) - updatewindowsize(old_winsizex, old_winsizey); - ticks = 0; - } - } - - closepc(); - - midi_close(); - - return 0; -} - -END_OF_MAIN(); diff --git a/src/allegro-main.h b/src/allegro-main.h deleted file mode 100644 index 4498defd3..000000000 --- a/src/allegro-main.h +++ /dev/null @@ -1,22 +0,0 @@ -/* Copyright holders: Sarah Walker - see COPYING for more details -*/ -#define getr8 allegro_getr8 -#define setr8 allegro_setr8 -#define get_filename allegro_get_filename -#define append_filename allegro_append_filename -#define put_backslash allegro_put_backslash -#define get_extension allegro_get_extension -#define GFX_VGA allegro_GFX_VGA -#define MAX_JOYSTICKS allegro_MAX_JOYSTICKS - -#include - -#undef MAX_JOYSTICKS -#undef GFX_VGA -#undef getr8 -#undef setr8 -#undef get_filename -#undef append_filename -#undef put_backslash -#undef get_extension diff --git a/src/allegro-midi.c b/src/allegro-midi.c deleted file mode 100644 index 9178f9e35..000000000 --- a/src/allegro-midi.c +++ /dev/null @@ -1,48 +0,0 @@ -/* Copyright holders: Sarah Walker - see COPYING for more details -*/ -#include "allegro-main.h" -#include "ibm.h" -#include "plat-midi.h" - -//#define USE_ALLEGRO_MIDI - -void midi_init() -{ -#ifdef USE_ALLEGRO_MIDI - install_sound(DIGI_NONE, MIDI_AUTODETECT, NULL); -#endif -} - -void midi_close() -{ -#ifdef USE_ALLEGRO_MIDI - remove_sound(); -#endif -} - -static int midi_cmd_pos, midi_len; -static uint8_t midi_command[3]; -static int midi_lengths[8] = {3, 3, 3, 3, 2, 2, 3, 0}; - -void midi_write(uint8_t val) -{ - if (val & 0x80) - { - midi_cmd_pos = 0; - midi_len = midi_lengths[(val >> 4) & 7]; - midi_command[0] = midi_command[1] = midi_command[2] = 0; - } - - if (midi_len && midi_cmd_pos < 3) - { - midi_command[midi_cmd_pos] = val; - - midi_cmd_pos++; - -#ifdef USE_ALLEGRO_MIDI - if (midi_cmd_pos == midi_len) - midi_out(midi_command, midi_len); -#endif - } -} diff --git a/src/allegro-mouse.c b/src/allegro-mouse.c deleted file mode 100644 index 60f287361..000000000 --- a/src/allegro-mouse.c +++ /dev/null @@ -1,34 +0,0 @@ -/* Copyright holders: Sarah Walker - see COPYING for more details -*/ -#include "allegro-main.h" -#include "plat-mouse.h" - -int mouse_buttons; - -void mouse_init() -{ - install_mouse(); -} - -void mouse_close() -{ -} - -void mouse_poll_host() -{ - //poll_mouse(); - mouse_buttons = mouse_b; -} - -void mouse_get_mickeys(int *x, int *y) -{ - if (mousecapture) - { - get_mouse_mickeys(x, y); -// position_mouse(64, 64); - } - else - *x = *y = 0; -} - diff --git a/src/allegro-video.c b/src/allegro-video.c deleted file mode 100644 index a4897ffc6..000000000 --- a/src/allegro-video.c +++ /dev/null @@ -1,130 +0,0 @@ -/* Copyright holders: Sarah Walker - see COPYING for more details -*/ -#include "allegro-main.h" -#include "ibm.h" -#include "video.h" - -#include "allegro-video.h" - -static PALETTE cgapal= -{ - {0,0,0},{0,42,0},{42,0,0},{42,21,0}, - {0,0,0},{0,42,42},{42,0,42},{42,42,42}, - {0,0,0},{21,63,21},{63,21,21},{63,63,21}, - {0,0,0},{21,63,63},{63,21,63},{63,63,63}, - - {0,0,0},{0,0,42},{0,42,0},{0,42,42}, - {42,0,0},{42,0,42},{42,21,00},{42,42,42}, - {21,21,21},{21,21,63},{21,63,21},{21,63,63}, - {63,21,21},{63,21,63},{63,63,21},{63,63,63}, - - {0,0,0},{0,21,0},{0,0,42},{0,42,42}, - {42,0,21},{21,10,21},{42,0,42},{42,0,63}, - {21,21,21},{21,63,21},{42,21,42},{21,63,63}, - {63,0,0},{42,42,0},{63,21,42},{41,41,41}, - - {0,0,0},{0,42,42},{42,0,0},{42,42,42}, - {0,0,0},{0,42,42},{42,0,0},{42,42,42}, - {0,0,0},{0,63,63},{63,0,0},{63,63,63}, - {0,0,0},{0,63,63},{63,0,0},{63,63,63}, -}; - -static uint32_t pal_lookup[256]; - -static void allegro_blit_memtoscreen(int x, int y, int y1, int y2, int w, int h); -static void allegro_blit_memtoscreen_8(int x, int y, int w, int h); -static BITMAP *buffer32_vscale; -void allegro_video_init() -{ - int c; - - set_color_depth(32); - set_gfx_mode(GFX_AUTODETECT_WINDOWED, 640, 480, 0, 0); - video_blit_memtoscreen = allegro_blit_memtoscreen; - video_blit_memtoscreen_8 = allegro_blit_memtoscreen_8; - - for (c = 0; c < 256; c++) - pal_lookup[c] = makecol(cgapal[c].r << 2, cgapal[c].g << 2, cgapal[c].b << 2); - - buffer32_vscale = create_bitmap(2048, 2048); -} - -void allegro_video_close() -{ - destroy_bitmap(buffer32_vscale); -} - -void allegro_video_update_size(int x, int y) -{ - if (set_gfx_mode(GFX_AUTODETECT_WINDOWED, x, y, 0, 0)) - fatal("Failed to set gfx mode %i,%i : %s\n", x, y, allegro_error); -} - -static void allegro_blit_memtoscreen(int x, int y, int y1, int y2, int w, int h) -{ - if (h < winsizey) - { - int yy; - - for (yy = y+y1; yy < y+y2; yy++) - { - if (yy >= 0) - { - memcpy(&((uint32_t *)buffer32_vscale->line[yy*2])[x], &((uint32_t *)buffer32->line[yy])[x], w*4); - memcpy(&((uint32_t *)buffer32_vscale->line[(yy*2)+1])[x], &((uint32_t *)buffer32->line[yy])[x], w*4); - } - } - - blit(buffer32_vscale, screen, x, (y+y1)*2, 0, y1, w, (y2-y1)*2); - } - else - blit(buffer32, screen, x, y+y1, 0, y1, w, y2-y1); -} - -static void allegro_blit_memtoscreen_8(int x, int y, int w, int h) -{ - int xx, yy; - int line_double = (winsizey > h) ? 1 : 0; - - if (y < 0) - { - h += y; - y = 0; - } - - for (yy = y; yy < y+h; yy++) - { - int dy = line_double ? yy*2 : yy; - if (dy < buffer->h) - { - if (line_double) - { - for (xx = x; xx < x+w; xx++) - { - ((uint32_t *)buffer32->line[dy])[xx] = - ((uint32_t *)buffer32->line[dy + 1])[xx] = pal_lookup[buffer->line[yy][xx]]; - } - } - else - { - for (xx = x; xx < x+w; xx++) - ((uint32_t *)buffer32->line[dy])[xx] = pal_lookup[buffer->line[yy][xx]]; - } - } - } - - if (readflash) - { - if (line_double) - rectfill(buffer32, x+SCREEN_W-40, y*2+8, SCREEN_W-8, y*2+14, makecol(255, 255, 255)); - else - rectfill(buffer32, x+SCREEN_W-40, y+8, SCREEN_W-8, y+14, makecol(255, 255, 255)); - readflash = 0; - } - - if (line_double) - blit(buffer32, screen, x, y*2, 0, 0, w, h*2); - else - blit(buffer32, screen, x, y, 0, 0, w, h); -} diff --git a/src/allegro-video.h b/src/allegro-video.h deleted file mode 100644 index bcd05b28d..000000000 --- a/src/allegro-video.h +++ /dev/null @@ -1,6 +0,0 @@ -/* Copyright holders: Sarah Walker - see COPYING for more details -*/ -void allegro_video_init(); -void allegro_video_close(); -void allegro_video_update_size(int x, int y); diff --git a/src/amstrad.c b/src/amstrad.c index 4c728ff0f..cb18923d7 100644 --- a/src/amstrad.c +++ b/src/amstrad.c @@ -1,20 +1,24 @@ +#include #include "ibm.h" +#include "cpu/cpu.h" #include "io.h" +#include "device.h" +#include "model.h" #include "keyboard.h" #include "lpt.h" #include "mouse.h" -#include "amstrad.h" static uint8_t amstrad_dead; -uint8_t amstrad_read(uint16_t port, void *priv) + +static uint8_t amstrad_read(uint16_t port, void *priv) { pclog("amstrad_read : %04X\n",port); switch (port) { case 0x379: - return 7 | readdacfifo(); + return 7; case 0x37a: if (romset == ROM_PC1512) return 0x20; if (romset == ROM_PC200) return 0x80; @@ -25,7 +29,8 @@ uint8_t amstrad_read(uint16_t port, void *priv) return 0xff; } -void amstrad_write(uint16_t port, uint8_t val, void *priv) + +static void amstrad_write(uint16_t port, uint8_t val, void *priv) { switch (port) { @@ -35,6 +40,7 @@ void amstrad_write(uint16_t port, uint8_t val, void *priv) } } + static uint8_t mousex, mousey; static void amstrad_mouse_write(uint16_t addr, uint8_t val, void *p) { @@ -58,7 +64,7 @@ typedef struct mouse_amstrad_t int oldb; } mouse_amstrad_t; -static void mouse_amstrad_poll(int x, int y, int z, int b, void *p) +static uint8_t mouse_amstrad_poll(int x, int y, int z, int b, void *p) { mouse_amstrad_t *mouse = (mouse_amstrad_t *)p; @@ -75,9 +81,12 @@ static void mouse_amstrad_poll(int x, int y, int z, int b, void *p) keyboard_send(0xfd); mouse->oldb = b; + + return(0); } -static void *mouse_amstrad_init() + +static void *mouse_amstrad_init(void) { mouse_amstrad_t *mouse = (mouse_amstrad_t *)malloc(sizeof(mouse_amstrad_t)); memset(mouse, 0, sizeof(mouse_amstrad_t)); @@ -85,6 +94,7 @@ static void *mouse_amstrad_init() return mouse; } + static void mouse_amstrad_close(void *p) { mouse_amstrad_t *mouse = (mouse_amstrad_t *)p; @@ -92,16 +102,19 @@ static void mouse_amstrad_close(void *p) free(mouse); } + mouse_t mouse_amstrad = { "Amstrad mouse", + "amstrad", + MOUSE_TYPE_AMSTRAD, mouse_amstrad_init, mouse_amstrad_close, - mouse_amstrad_poll, - MOUSE_TYPE_AMSTRAD + mouse_amstrad_poll }; -void amstrad_init() + +void amstrad_init(void) { lpt2_remove_ams(); diff --git a/src/amstrad.h b/src/amstrad.h deleted file mode 100644 index 1d4130f49..000000000 --- a/src/amstrad.h +++ /dev/null @@ -1,3 +0,0 @@ -void amstrad_init(); - -extern mouse_t mouse_amstrad; diff --git a/src/bswap.h b/src/bswap.h deleted file mode 100644 index f3cfe6a37..000000000 --- a/src/bswap.h +++ /dev/null @@ -1,205 +0,0 @@ -/* Copyright holders: Sarah Walker - see COPYING for more details -*/ -#ifndef BSWAP_H -#define BSWAP_H - -//#include "config-host.h" - -#include - -#ifdef HAVE_BYTESWAP_H -#include -#else - -#define bswap_16(x) \ -({ \ - uint16_t __x = (x); \ - ((uint16_t)( \ - (((uint16_t)(__x) & (uint16_t)0x00ffU) << 8) | \ - (((uint16_t)(__x) & (uint16_t)0xff00U) >> 8) )); \ -}) - -#define bswap_32(x) \ -({ \ - uint32_t __x = (x); \ - ((uint32_t)( \ - (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \ - (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \ - (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \ - (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) )); \ -}) - -#define bswap_64(x) \ -({ \ - uint64_t __x = (x); \ - ((uint64_t)( \ - (uint64_t)(((uint64_t)(__x) & (uint64_t)0x00000000000000ffULL) << 56) | \ - (uint64_t)(((uint64_t)(__x) & (uint64_t)0x000000000000ff00ULL) << 40) | \ - (uint64_t)(((uint64_t)(__x) & (uint64_t)0x0000000000ff0000ULL) << 24) | \ - (uint64_t)(((uint64_t)(__x) & (uint64_t)0x00000000ff000000ULL) << 8) | \ - (uint64_t)(((uint64_t)(__x) & (uint64_t)0x000000ff00000000ULL) >> 8) | \ - (uint64_t)(((uint64_t)(__x) & (uint64_t)0x0000ff0000000000ULL) >> 24) | \ - (uint64_t)(((uint64_t)(__x) & (uint64_t)0x00ff000000000000ULL) >> 40) | \ - (uint64_t)(((uint64_t)(__x) & (uint64_t)0xff00000000000000ULL) >> 56) )); \ -}) - -#endif /* !HAVE_BYTESWAP_H */ - -static inline uint16_t bswap16(uint16_t x) -{ - return bswap_16(x); -} - -static inline uint32_t bswap32(uint32_t x) -{ - return bswap_32(x); -} - -static inline uint64_t bswap64(uint64_t x) -{ - return bswap_64(x); -} - -static inline void bswap16s(uint16_t *s) -{ - *s = bswap16(*s); -} - -static inline void bswap32s(uint32_t *s) -{ - *s = bswap32(*s); -} - -static inline void bswap64s(uint64_t *s) -{ - *s = bswap64(*s); -} - -#if defined(WORDS_BIGENDIAN) -#define be_bswap(v, size) (v) -#define le_bswap(v, size) bswap ## size(v) -#define be_bswaps(v, size) -#define le_bswaps(p, size) *p = bswap ## size(*p); -#else -#define le_bswap(v, size) (v) -#define be_bswap(v, size) bswap ## size(v) -#define le_bswaps(v, size) -#define be_bswaps(p, size) *p = bswap ## size(*p); -#endif - -#define CPU_CONVERT(endian, size, type)\ -static inline type endian ## size ## _to_cpu(type v)\ -{\ - return endian ## _bswap(v, size);\ -}\ -\ -static inline type cpu_to_ ## endian ## size(type v)\ -{\ - return endian ## _bswap(v, size);\ -}\ -\ -static inline void endian ## size ## _to_cpus(type *p)\ -{\ - endian ## _bswaps(p, size)\ -}\ -\ -static inline void cpu_to_ ## endian ## size ## s(type *p)\ -{\ - endian ## _bswaps(p, size)\ -}\ -\ -static inline type endian ## size ## _to_cpup(const type *p)\ -{\ - return endian ## size ## _to_cpu(*p);\ -}\ -\ -static inline void cpu_to_ ## endian ## size ## w(type *p, type v)\ -{\ - *p = cpu_to_ ## endian ## size(v);\ -} - -CPU_CONVERT(be, 16, uint16_t) -CPU_CONVERT(be, 32, uint32_t) -CPU_CONVERT(be, 64, uint64_t) - -CPU_CONVERT(le, 16, uint16_t) -CPU_CONVERT(le, 32, uint32_t) -CPU_CONVERT(le, 64, uint64_t) - -/* unaligned versions (optimized for frequent unaligned accesses)*/ - -#if defined(__i386__) || defined(__powerpc__) - -#define cpu_to_le16wu(p, v) cpu_to_le16w(p, v) -#define cpu_to_le32wu(p, v) cpu_to_le32w(p, v) -#define le16_to_cpupu(p) le16_to_cpup(p) -#define le32_to_cpupu(p) le32_to_cpup(p) - -#define cpu_to_be16wu(p, v) cpu_to_be16w(p, v) -#define cpu_to_be32wu(p, v) cpu_to_be32w(p, v) - -#else - -static inline void cpu_to_le16wu(uint16_t *p, uint16_t v) -{ - uint8_t *p1 = (uint8_t *)p; - - p1[0] = v; - p1[1] = v >> 8; -} - -static inline void cpu_to_le32wu(uint32_t *p, uint32_t v) -{ - uint8_t *p1 = (uint8_t *)p; - - p1[0] = v; - p1[1] = v >> 8; - p1[2] = v >> 16; - p1[3] = v >> 24; -} - -static inline uint16_t le16_to_cpupu(const uint16_t *p) -{ - const uint8_t *p1 = (const uint8_t *)p; - return p1[0] | (p1[1] << 8); -} - -static inline uint32_t le32_to_cpupu(const uint32_t *p) -{ - const uint8_t *p1 = (const uint8_t *)p; - return p1[0] | (p1[1] << 8) | (p1[2] << 16) | (p1[3] << 24); -} - -static inline void cpu_to_be16wu(uint16_t *p, uint16_t v) -{ - uint8_t *p1 = (uint8_t *)p; - - p1[0] = v >> 8; - p1[1] = v; -} - -static inline void cpu_to_be32wu(uint32_t *p, uint32_t v) -{ - uint8_t *p1 = (uint8_t *)p; - - p1[0] = v >> 24; - p1[1] = v >> 16; - p1[2] = v >> 8; - p1[3] = v; -} - -#endif - -#ifdef WORDS_BIGENDIAN -#define cpu_to_32wu cpu_to_be32wu -#else -#define cpu_to_32wu cpu_to_le32wu -#endif - -#undef le_bswap -#undef be_bswap -#undef le_bswaps -#undef be_bswaps - -#endif /* BSWAP_H */ diff --git a/src/bugger.c b/src/bugger.c new file mode 100644 index 000000000..ce5ed03a9 --- /dev/null +++ b/src/bugger.c @@ -0,0 +1,323 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Implementation of the ISA Bus (de)Bugger expansion card + * sold as a DIY kit in the late 1980's in The Netherlands. + * This card was a assemble-yourself 8bit ISA addon card for + * PC and AT systems that had several tools to aid in low- + * level debugging (mostly for faulty BIOSes, bootloaders + * and system kernels...) + * + * The standard version had a total of 16 LEDs (8 RED, plus + * 8 GREEN), two 7-segment displays and one 8-position DIP + * switch block on board for use as debugging tools. + * + * The "Plus" version, added an extra 2 7-segment displays, + * as well as a very simple RS-232 serial interface that + * could be used as a mini-console terminal. + * + * Two I/O ports were used; one for control, at offset 0 in + * I/O space, and one for data, at offset 1 in I/O space. + * Both registers could be read from and written to. Although + * the author has a vague memory of a DIP switch to set the + * board's I/O address, comments in old software seems to + * indicate that it was actually fixed to 0x7A (and 0x7B.) + * + * A READ on the data register always returned the actual + * state of the DIP switch. Writing data to the LEDs was done + * in two steps.. first, the block number (RED or GREEN) was + * written to the CTRL register, and then the actual LED data + * was written to the DATA register. Likewise, data for the + * 7-segment displays was written. + * + * The serial port was a bit different, and its operation is + * not verified, but two extra bits in the control register + * were used to set up parameters, and also the actual data + * input and output. + * + * TODO: Still have to implement the RS232 Serial Port Parameters + * configuration register (CTRL_SPCFG bit set) but have to + * remember that stuff first... + * + * Version: @(#)bugger.c 1.0.4 2017/05/09 + * + * Author: Fred N. van Kempen, + * Copyright 1989-2017 Fred N. van Kempen. + */ +#include "ibm.h" +#include "io.h" +#include "bugger.h" + + +/* BugBugger registers. */ +#define BUG_CTRL 0 +# define CTRL_RLED 0x00 /* write to the RED LED block */ +# define CTRL_GLED 0x01 /* write to the GREEN LED block */ +# define CTRL_SEG1 0x02 /* write to the RIGHT 7SEG displays */ +# define CTRL_SEG2 0x04 /* write to the LEFT 7SEG displays */ +# define CTRL_SPORT 0x20 /* enable the serial port */ +# define CTRL_SPCFG 0x40 /* set up the serial port */ +# define CTRL_INIT 0x80 /* enable and reset the card */ +# define CTRL_RESET 0xff /* this resets the board */ +#define BUG_DATA 1 + + +static uint8_t bug_ctrl, /* control register */ + bug_data, /* data register */ + bug_ledr, bug_ledg, /* RED and GREEN LEDs */ + bug_seg1, bug_seg2, /* LEFT and RIGHT 7SEG displays */ + bug_spcfg; /* serial port configuration */ +# define FIFO_LEN 256 +static uint8_t bug_buff[FIFO_LEN], /* serial port data buffer */ + *bug_bptr; +# define UISTR_LEN 24 +static char bug_str[UISTR_LEN]; /* UI output string */ + + +extern void set_bugui(char *__str); + + +/* Update the system's UI with the actual Bugger status. */ +static void +bug_setui(void) +{ + /* Format all current info in a string. */ + sprintf(bug_str, "%02X:%02X %c%c%c%c%c%c%c%c-%c%c%c%c%c%c%c%c", + bug_seg2, bug_seg1, + (bug_ledg&0x80)?'G':'g', (bug_ledg&0x40)?'G':'g', + (bug_ledg&0x20)?'G':'g', (bug_ledg&0x10)?'G':'g', + (bug_ledg&0x08)?'G':'g', (bug_ledg&0x04)?'G':'g', + (bug_ledg&0x02)?'G':'g', (bug_ledg&0x01)?'G':'g', + (bug_ledr&0x80)?'R':'r', (bug_ledr&0x40)?'R':'r', + (bug_ledr&0x20)?'R':'r', (bug_ledr&0x10)?'R':'r', + (bug_ledr&0x08)?'R':'r', (bug_ledr&0x04)?'R':'r', + (bug_ledr&0x02)?'R':'r', (bug_ledr&0x01)?'R':'r'); + + /* Send formatted string to the UI. */ + status_settext(bug_str); +} + + +/* Flush the serial port. */ +static void +bug_spflsh(void) +{ + *bug_bptr = '\0'; + pclog("BUGGER- serial port [%s]\n", bug_buff); + bug_bptr = bug_buff; +} + + +/* Handle a write to the Serial Port Data register. */ +static void +bug_wsport(uint8_t val) +{ + uint8_t old = bug_ctrl; + + /* Clear the SPORT bit to indicate we are busy. */ + bug_ctrl &= ~CTRL_SPORT; + + /* Delay while processing byte.. */ + if (bug_bptr == &bug_buff[FIFO_LEN-1]) { + /* Buffer full, gotta flush. */ + bug_spflsh(); + } + + /* Write (store) the byte. */ + *bug_bptr++ = val; + + /* Restore the SPORT bit. */ + bug_ctrl |= (old & CTRL_SPORT); + + pclog("BUGGER- sport %02x\n", val); +} + + +/* Handle a write to the Serial Port Configuration register. */ +static void +bug_wspcfg(uint8_t val) +{ + bug_spcfg = val; + + pclog("BUGGER- spcfg %02x\n", bug_spcfg); +} + + +/* Handle a write to the control register. */ +static void +bug_wctrl(uint8_t val) +{ + if (val == CTRL_RESET) { + /* User wants us to reset. */ + bug_ctrl = CTRL_INIT; + bug_spcfg = 0x00; + bug_bptr = NULL; + } else { + /* If turning off the serial port, flush it. */ + if ((bug_ctrl & CTRL_SPORT) && !(val & CTRL_SPORT)) + bug_spflsh(); + + /* FIXME: did they do this using an XOR of operation bits? --FvK */ + + if (val & CTRL_SPCFG) { + /* User wants to configure the serial port. */ + bug_ctrl &= ~(CTRL_SPORT|CTRL_SEG2|CTRL_SEG1|CTRL_GLED); + bug_ctrl |= CTRL_SPCFG; + } else if (val & CTRL_SPORT) { + /* User wants to talk to the serial port. */ + bug_ctrl &= ~(CTRL_SPCFG|CTRL_SEG2|CTRL_SEG1|CTRL_GLED); + bug_ctrl |= CTRL_SPORT; + if (bug_bptr == NULL) + bug_bptr = bug_buff; + } else if (val & CTRL_SEG2) { + /* User selected SEG2 (LEFT, Plus only) for output. */ + bug_ctrl &= ~(CTRL_SPCFG|CTRL_SPORT|CTRL_SEG1|CTRL_GLED); + bug_ctrl |= CTRL_SEG2; + } else if (val & CTRL_SEG1) { + /* User selected SEG1 (RIGHT) for output. */ + bug_ctrl &= ~(CTRL_SPCFG|CTRL_SPORT|CTRL_SEG2|CTRL_GLED); + bug_ctrl |= CTRL_SEG1; + } else if (val & CTRL_GLED) { + /* User selected the GREEN LEDs for output. */ + bug_ctrl &= ~(CTRL_SPCFG|CTRL_SPORT|CTRL_SEG2|CTRL_SEG1); + bug_ctrl |= CTRL_GLED; + } else { + /* User selected the RED LEDs for output. */ + bug_ctrl &= + ~(CTRL_SPCFG|CTRL_SPORT|CTRL_SEG2|CTRL_SEG1|CTRL_GLED); + } + } + + /* Update the UI with active settings. */ + pclog("BUGGER- ctrl %02x\n", bug_ctrl); + bug_setui(); +} + + +/* Handle a write to the data register. */ +static void +bug_wdata(uint8_t val) +{ + bug_data = val; + + if (bug_ctrl & CTRL_SPCFG) + bug_wspcfg(val); + else if (bug_ctrl & CTRL_SPORT) + bug_wsport(val); + else { + if (bug_ctrl & CTRL_SEG2) + bug_seg2 = val; + else if (bug_ctrl & CTRL_SEG1) + bug_seg1 = val; + else if (bug_ctrl & CTRL_GLED) + bug_ledg = val; + else + bug_ledr = val; + + pclog("BUGGER- data %02x\n", bug_data); + } + + /* Update the UI with active settings. */ + bug_setui(); +} + + +/* Reset the ISA BusBugger controller. */ +static void +bug_reset(void) +{ + /* Clear the data register. */ + bug_data = 0x00; + + /* Clear the RED and GREEN LEDs. */ + bug_ledr = 0x00; bug_ledg = 0x00; + + /* Clear both 7SEG displays. */ + bug_seg1 = 0x00; bug_seg2 = 0x00; + + /* Reset the control register (updates UI.) */ + bug_wctrl(CTRL_RESET); +} + + +/* Handle a WRITE operation to one of our registers. */ +static void +bug_write(uint16_t port, uint8_t val, void *priv) +{ + switch (port-BUGGER_ADDR) { + case BUG_CTRL: /* control register */ + if (val == CTRL_RESET) { + /* Perform a full reset. */ + bug_reset(); + } else if (bug_ctrl & CTRL_INIT) { + /* Only allow writes if initialized. */ + bug_wctrl(val); + } + break; + + case BUG_DATA: /* data register */ + if (bug_ctrl & CTRL_INIT) { + bug_wdata(val); + } + break; + + } +} + + +/* Handle a READ operation from one of our registers. */ +static uint8_t +bug_read(uint16_t port, void *priv) +{ + uint8_t ret = 0xff; + + if (bug_ctrl & CTRL_INIT) switch (port-BUGGER_ADDR) { + case BUG_CTRL: /* control register */ + ret = bug_ctrl; + break; + + case BUG_DATA: /* data register */ + if (bug_ctrl & CTRL_SPCFG) { + ret = bug_spcfg; + } else if (bug_ctrl & CTRL_SPORT) { + ret = 0x00; /* input not supported */ + } else { + /* Just read the DIP switch. */ + ret = bug_data; + } + break; + + default: + break; + } + + return(ret); +} + + +/* Initialize the ISA BusBugger emulator. */ +void +bugger_init(void) +{ + pclog("ISA Bus (de)Bugger, I/O=%04x\n", BUGGER_ADDR); + + /* Initialize local registers. */ + bug_reset(); + + io_sethandler(BUGGER_ADDR, BUGGER_ADDRLEN, + bug_read, NULL, NULL, bug_write, NULL, NULL, NULL); +} + + +/* Remove the ISA BusBugger emulator from the system. */ +void +bugger_remove(void) +{ + io_removehandler(BUGGER_ADDR, BUGGER_ADDRLEN, + bug_read, NULL, NULL, bug_write, NULL, NULL, NULL); +} diff --git a/src/bugger.h b/src/bugger.h new file mode 100644 index 000000000..1d4dfb841 --- /dev/null +++ b/src/bugger.h @@ -0,0 +1,37 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Implementation of the ISA Bus (de)Bugger expansion card + * sold as a DIY kit in the late 1980's in The Netherlands. + * This card was a assemble-yourself 8bit ISA addon card for + * PC and AT systems that had several tools to aid in low- + * level debugging (mostly for faulty BIOSes, bootloaders + * and system kernels...) + * + * Definitions for the BUGGER card. + * + * Version: @(#)bugger.h 1.0.3 2017/04/07 + * + * Author: Fred N. van Kempen, + * Copyright 1989-2017 Fred N. van Kempen. + */ +#ifndef BUGGER_H +# define BUGGER_H + + +/* I/O port range used. */ +#define BUGGER_ADDR 0x007a +#define BUGGER_ADDRLEN 4 + + +/* Functions. */ +extern void bugger_init(void); +extern void bugger_remove(void); + + +#endif /*BUGGER_H*/ diff --git a/src/buslogic.c b/src/buslogic.c deleted file mode 100644 index 229b4baef..000000000 --- a/src/buslogic.c +++ /dev/null @@ -1,1682 +0,0 @@ -/* Copyright holders: SA1988 - see COPYING for more details -*/ -/*Buslogic SCSI emulation (including Adaptec 154x ISA software backward compatibility) and the Adaptec 154x itself*/ - -#include -#include -#include -#include - -#include "ibm.h" -#include "device.h" -#include "io.h" -#include "mem.h" -#include "rom.h" -#include "dma.h" -#include "pic.h" -#include "timer.h" - -#include "scsi.h" -#include "cdrom.h" - -#include "buslogic.h" - -typedef struct __attribute__((packed)) -{ - uint8_t hi; - uint8_t mid; - uint8_t lo; -} addr24; - -#define ADDR_TO_U32(x) (((x).hi << 16) | ((x).mid << 8) | (x).lo & 0xFF) -#define U32_TO_ADDR(a, x) do {(a).hi = (x) >> 16; (a).mid = (x) >> 8; (a).lo = (x) & 0xFF;} while(0) - -// I/O Port interface -// READ Port x+0: STATUS -// WRITE Port x+0: CONTROL -// -// READ Port x+1: DATA -// WRITE Port x+1: COMMAND -// -// READ Port x+2: INTERRUPT STATUS -// WRITE Port x+2: (undefined?) -// -// R/W Port x+3: (undefined) - -// READ STATUS flags -#define STAT_STST 0x80 // self-test in progress -#define STAT_DFAIL 0x40 // internal diagnostic failure -#define STAT_INIT 0x20 // mailbox initialization required -#define STAT_IDLE 0x10 // HBA is idle -#define STAT_CDFULL 0x08 // Command/Data output port is full -#define STAT_DFULL 0x04 // Data input port is full -#define STAT_INVCMD 0x01 // Invalid command - -// READ INTERRUPT STATUS flags -#define INTR_ANY 0x80 // any interrupt -#define INTR_SRCD 0x08 // SCSI reset detected -#define INTR_HACC 0x04 // HA command complete -#define INTR_MBOA 0x02 // MBO empty -#define INTR_MBIF 0x01 // MBI full - -// WRITE CONTROL commands -#define CTRL_HRST 0x80 // Hard reset -#define CTRL_SRST 0x40 // Soft reset -#define CTRL_IRST 0x20 // interrupt reset -#define CTRL_SCRST 0x10 // SCSI bus reset - -// READ/WRITE DATA commands -#define CMD_NOP 0x00 // No operation -#define CMD_MBINIT 0x01 // mailbox initialization -#define CMD_START_SCSI 0x02 // Start SCSI command -#define CMD_INQUIRY 0x04 // Adapter inquiry -#define CMD_EMBOI 0x05 // enable Mailbox Out Interrupt -#define CMD_SELTIMEOUT 0x06 // Set SEL timeout -#define CMD_BUSON_TIME 0x07 // set bus-On time -#define CMD_BUSOFF_TIME 0x08 // set bus-off time -#define CMD_DMASPEED 0x09 // set ISA DMA speed -#define CMD_RETDEVS 0x0A // return installed devices -#define CMD_RETCONF 0x0B // return configuration data -#define CMD_TARGET 0x0C // set HBA to target mode -#define CMD_RETSETUP 0x0D // return setup data -#define CMD_ECHO 0x1F // ECHO command data - -#pragma pack(1) -/** - * Auto SCSI structure which is located - * in host adapter RAM and contains several - * configuration parameters. - */ -typedef struct __attribute__((packed)) AutoSCSIRam -{ - uint8_t aInternalSignature[2]; - uint8_t cbInformation; - uint8_t aHostAdaptertype[6]; - uint8_t uReserved1; - uint8_t fFloppyEnabled : 1; - uint8_t fFloppySecondary : 1; - uint8_t fLevelSensitiveInterrupt : 1; - unsigned char uReserved2 : 2; - unsigned char uSystemRAMAreForBIOS : 3; - unsigned char uDMAChannel : 7; - uint8_t fDMAAutoConfiguration : 1; - unsigned char uIrqChannel : 7; - uint8_t fIrqAutoConfiguration : 1; - uint8_t uDMATransferRate; - uint8_t uSCSIId; - uint8_t fLowByteTerminated : 1; - uint8_t fParityCheckingEnabled : 1; - uint8_t fHighByteTerminated : 1; - uint8_t fNoisyCablingEnvironment : 1; - uint8_t fFastSynchronousNeogtiation : 1; - uint8_t fBusResetEnabled : 1; - uint8_t fReserved3 : 1; - uint8_t fActiveNegotiationEnabled : 1; - uint8_t uBusOnDelay; - uint8_t uBusOffDelay; - uint8_t fHostAdapterBIOSEnabled : 1; - uint8_t fBIOSRedirectionOfInt19 : 1; - uint8_t fExtendedTranslation : 1; - uint8_t fMapRemovableAsFixed : 1; - uint8_t fReserved4 : 1; - uint8_t fBIOSSupportsMoreThan2Drives : 1; - uint8_t fBIOSInterruptMode : 1; - uint8_t fFlopticalSupport : 1; - uint16_t u16DeviceEnabledMask; - uint16_t u16WidePermittedMask; - uint16_t u16FastPermittedMask; - uint16_t u16SynchronousPermittedMask; - uint16_t u16DisconnectPermittedMask; - uint16_t u16SendStartUnitCommandMask; - uint16_t u16IgnoreInBIOSScanMask; - unsigned char uPCIInterruptPin : 2; - unsigned char uHostAdapterIoPortAddress : 2; - uint8_t fStrictRoundRobinMode : 1; - uint8_t fVesaBusSpeedGreaterThan33MHz : 1; - uint8_t fVesaBurstWrite : 1; - uint8_t fVesaBurstRead : 1; - uint16_t u16UltraPermittedMask; - uint32_t uReserved5; - uint8_t uReserved6; - uint8_t uAutoSCSIMaximumLUN; - uint8_t fReserved7 : 1; - uint8_t fSCAMDominant : 1; - uint8_t fSCAMenabled : 1; - uint8_t fSCAMLevel2 : 1; - unsigned char uReserved8 : 4; - uint8_t fInt13Extension : 1; - uint8_t fReserved9 : 1; - uint8_t fCDROMBoot : 1; - unsigned char uReserved10 : 5; - unsigned char uBootTargetId : 4; - unsigned char uBootChannel : 4; - uint8_t fForceBusDeviceScanningOrder : 1; - unsigned char uReserved11 : 7; - uint16_t u16NonTaggedToAlternateLunPermittedMask; - uint16_t u16RenegotiateSyncAfterCheckConditionMask; - uint8_t aReserved12[10]; - uint8_t aManufacturingDiagnostic[2]; - uint16_t u16Checksum; -} AutoSCSIRam; -#pragma pack() - -/** - * The local Ram. - */ -typedef union HostAdapterLocalRam -{ - /** Byte view. */ - uint8_t u8View[256]; - /** Structured view. */ - struct __attribute__((packed)) - { - /** Offset 0 - 63 is for BIOS. */ - uint8_t u8Bios[64]; - /** Auto SCSI structure. */ - AutoSCSIRam autoSCSIData; - } structured; -} HostAdapterLocalRam; - -/** Structure for the INQUIRE_SETUP_INFORMATION reply. */ -typedef struct __attribute__((packed)) ReplyInquireSetupInformationSynchronousValue -{ - uint8_t uOffset : 4; - uint8_t uTransferPeriod : 3; - uint8_t fSynchronous : 1; -}ReplyInquireSetupInformationSynchronousValue; - -typedef struct __attribute__((packed)) ReplyInquireSetupInformation -{ - uint8_t fSynchronousInitiationEnabled : 1; - uint8_t fParityCheckingEnabled : 1; - uint8_t uReserved1 : 6; - uint8_t uBusTransferRate; - uint8_t uPreemptTimeOnBus; - uint8_t uTimeOffBus; - uint8_t cMailbox; - addr24 MailboxAddress; - ReplyInquireSetupInformationSynchronousValue SynchronousValuesId0To7[8]; - uint8_t uDisconnectPermittedId0To7; - uint8_t uSignature; - uint8_t uCharacterD; - uint8_t uHostBusType; - uint8_t uWideTransferPermittedId0To7; - uint8_t uWideTransfersActiveId0To7; - ReplyInquireSetupInformationSynchronousValue SynchronousValuesId8To15[8]; - uint8_t uDisconnectPermittedId8To15; - uint8_t uReserved2; - uint8_t uWideTransferPermittedId8To15; - uint8_t uWideTransfersActiveId8To15; -} ReplyInquireSetupInformation; - -/** Structure for the INQUIRE_EXTENDED_SETUP_INFORMATION. */ -#pragma pack(1) -typedef struct __attribute__((packed)) ReplyInquireExtendedSetupInformation -{ - uint8_t uBusType; - uint8_t uBiosAddress; - uint16_t u16ScatterGatherLimit; - uint8_t cMailbox; - uint32_t uMailboxAddressBase; - uint8_t uReserved1 : 2; - uint8_t fFastEISA : 1; - uint8_t uReserved2 : 3; - uint8_t fLevelSensitiveInterrupt : 1; - uint8_t uReserved3 : 1; - uint8_t aFirmwareRevision[3]; - uint8_t fHostWideSCSI : 1; - uint8_t fHostDifferentialSCSI : 1; - uint8_t fHostSupportsSCAM : 1; - uint8_t fHostUltraSCSI : 1; - uint8_t fHostSmartTermination : 1; - uint8_t uReserved4 : 3; -} ReplyInquireExtendedSetupInformation; -#pragma pack() - -typedef struct __attribute__((packed)) MailboxInit_t -{ - uint8_t Count; - addr24 Address; -} MailboxInit_t; - -#pragma pack(1) -typedef struct __attribute__((packed)) MailboxInitExtended_t -{ - uint8_t Count; - uint32_t Address; -} MailboxInitExtended_t; -#pragma pack() - -/////////////////////////////////////////////////////////////////////////////// -// -// Mailbox Definitions -// -// -/////////////////////////////////////////////////////////////////////////////// - -// -// Mailbox Out -// -// -// MBO Command Values -// - -#define MBO_FREE 0x00 -#define MBO_START 0x01 -#define MBO_ABORT 0x02 - -// -// Mailbox In -// -// -// MBI Status Values -// - -#define MBI_FREE 0x00 -#define MBI_SUCCESS 0x01 -#define MBI_ABORT 0x02 -#define MBI_NOT_FOUND 0x03 -#define MBI_ERROR 0x04 - -typedef struct __attribute__((packed)) Mailbox_t -{ - uint8_t CmdStatus; - addr24 CCBPointer; -} Mailbox_t; - -typedef struct __attribute__((packed)) Mailbox32_t -{ - uint32_t CCBPointer; - union - { - struct - { - uint8_t Reserved[3]; - uint8_t ActionCode; - } out; - struct - { - uint8_t HostStatus; - uint8_t TargetStatus; - uint8_t Reserved; - uint8_t CompletionCode; - } in; - } u; -} Mailbox32_t; - - -/////////////////////////////////////////////////////////////////////////////// -// -// CCB - Buslogic SCSI Command Control Block -// -// The CCB is a superset of the CDB (Command Descriptor Block) -// and specifies detailed information about a SCSI command. -// -/////////////////////////////////////////////////////////////////////////////// - -// -// Byte 0 Command Control Block Operation Code -// - -#define SCSI_INITIATOR_COMMAND 0x00 -#define TARGET_MODE_COMMAND 0x01 -#define SCATTER_GATHER_COMMAND 0x02 -#define SCSI_INITIATOR_COMMAND_RES 0x03 -#define SCATTER_GATHER_COMMAND_RES 0x04 -#define BUS_RESET 0x81 - -// -// Byte 1 Address and Direction Control -// - -#define CCB_TARGET_ID_SHIFT 0x06 // CCB Op Code = 00, 02 -#define CCB_INITIATOR_ID_SHIFT 0x06 // CCB Op Code = 01 -#define CCB_DATA_XFER_IN 0x01 -#define CCB_DATA_XFER_OUT 0x02 -#define CCB_LUN_MASK 0x07 // Logical Unit Number - -// -// Byte 2 SCSI_Command_Length - Length of SCSI CDB -// -// Byte 3 Request Sense Allocation Length -// - -#define FOURTEEN_BYTES 0x00 // Request Sense Buffer size -#define NO_AUTO_REQUEST_SENSE 0x01 // No Request Sense Buffer - -// -// Bytes 4, 5 and 6 Data Length // Data transfer byte count -// -// Bytes 7, 8 and 9 Data Pointer // SGD List or Data Buffer -// -// Bytes 10, 11 and 12 Link Pointer // Next CCB in Linked List -// -// Byte 13 Command Link ID // TBD (I don't know yet) -// -// Byte 14 Host Status // Host Adapter status -// - -#define CCB_COMPLETE 0x00 // CCB completed without error -#define CCB_LINKED_COMPLETE 0x0A // Linked command completed -#define CCB_LINKED_COMPLETE_INT 0x0B // Linked complete with interrupt -#define CCB_SELECTION_TIMEOUT 0x11 // Set SCSI selection timed out -#define CCB_DATA_OVER_UNDER_RUN 0x12 -#define CCB_UNEXPECTED_BUS_FREE 0x13 // Target dropped SCSI BSY -#define CCB_PHASE_SEQUENCE_FAIL 0x14 // Target bus phase sequence failure -#define CCB_BAD_MBO_COMMAND 0x15 // MBO command not 0, 1 or 2 -#define CCB_INVALID_OP_CODE 0x16 // CCB invalid operation code -#define CCB_BAD_LINKED_LUN 0x17 // Linked CCB LUN different from first -#define CCB_INVALID_DIRECTION 0x18 // Invalid target direction -#define CCB_DUPLICATE_CCB 0x19 // Duplicate CCB -#define CCB_INVALID_CCB 0x1A // Invalid CCB - bad parameter - -// -// Byte 15 Target Status -// -// See scsi.h files for these statuses. -// - -// -// Bytes 16 and 17 Reserved (must be 0) -// - -// -// Bytes 18 through 18+n-1, where n=size of CDB Command Descriptor Block -// - -typedef struct __attribute__((packed)) CCB32 -{ - uint8_t Opcode; - uint8_t Reserved1:3; - uint8_t ControlByte:2; - uint8_t TagQueued:1; - uint8_t QueueTag:2; - uint8_t CdbLength; - uint8_t RequestSenseLength; - uint32_t DataLength; - uint32_t DataPointer; - uint8_t Reserved2[2]; - uint8_t HostStatus; - uint8_t TargetStatus; - uint8_t Id; - uint8_t Lun:5; - uint8_t LegacyTagEnable:1; - uint8_t LegacyQueueTag:2; - uint8_t Cdb[12]; - uint8_t Reserved3[6]; - uint32_t SensePointer; -} CCB32; - -typedef struct __attribute__((packed)) CCB -{ - uint8_t Opcode; - uint8_t Lun:3; - uint8_t ControlByte:2; - uint8_t Id:3; - uint8_t CdbLength; - uint8_t RequestSenseLength; - addr24 DataLength; - addr24 DataPointer; - addr24 LinkPointer; - uint8_t LinkId; - uint8_t HostStatus; - uint8_t TargetStatus; - uint8_t Reserved[2]; - uint8_t Cdb[12]; -} CCB; - -typedef struct __attribute__((packed)) CCBC -{ - uint8_t Opcode; - uint8_t Pad1:3; - uint8_t ControlByte:2; - uint8_t Pad2:3; - uint8_t CdbLength; - uint8_t RequestSenseLength; - uint8_t Pad3[10]; - uint8_t HostStatus; - uint8_t TargetStatus; - uint8_t Pad4[2]; - uint8_t Cdb[12]; -} CCBC; - -typedef union __attribute__((packed)) CCBU -{ - CCB32 new; - CCB old; - CCBC common; -} CCBU; - -/////////////////////////////////////////////////////////////////////////////// -// -// Scatter/Gather Segment List Definitions -// -/////////////////////////////////////////////////////////////////////////////// - -// -// Adapter limits -// - -#define MAX_SG_DESCRIPTORS (scsi_model ? 32 : 17) - -typedef struct __attribute__((packed)) SGE32 -{ - uint32_t Segment; - uint32_t SegmentPointer; -} SGE32; - -typedef struct __attribute__((packed)) SGE -{ - addr24 Segment; - addr24 SegmentPointer; -} SGE; - -typedef struct __attribute__((packed)) BuslogicRequests_t -{ - CCBU CmdBlock; - uint8_t *RequestSenseBuffer; - uint32_t CCBPointer; - int Is24bit; - uint8_t TargetID; - uint8_t LUN; -} BuslogicRequests_t; - -typedef struct __attribute__((packed)) Buslogic_t -{ - rom_t bios; - int UseLocalRam; - int StrictRoundRobinMode; - int ExtendedLUNCCBFormat; - HostAdapterLocalRam LocalRam; - BuslogicRequests_t BuslogicRequests; - uint8_t Status; - uint8_t Interrupt; - uint8_t Geometry; - uint8_t Control; - uint8_t Command; - uint8_t CmdBuf[53]; - uint8_t CmdParam; - uint8_t CmdParamLeft; - uint8_t DataBuf[64]; - uint8_t DataReply; - uint8_t DataReplyLeft; - uint32_t MailboxCount; - uint32_t MailboxOutAddr; - uint32_t MailboxOutPosCur; - uint32_t MailboxInAddr; - uint32_t MailboxInPosCur; - int Irq; - int DmaChannel; - int IrqEnabled; - int Mbx24bit; -} Buslogic_t; - -int scsi_model = 1; -int scsi_base = 0x330; -int scsi_dma = 6; -int scsi_irq = 11; - -int buslogic_do_log = 0; - -static void BuslogicStartMailbox(Buslogic_t *Buslogic); - -void BuslogicLog(const char *format, ...) -{ - if (buslogic_do_log) - { - va_list ap; - va_start(ap, format); - vprintf(format, ap); - va_end(ap); - fflush(stdout); - } -} - -static void BuslogicClearInterrupt(Buslogic_t *Buslogic) -{ - BuslogicLog("Buslogic: Clearing Interrupt 0x%02X\n", Buslogic->Interrupt); - Buslogic->Interrupt = 0; - picintc(1 << Buslogic->Irq); -} - -static void BuslogicLocalRam(Buslogic_t *Buslogic) -{ - /* - * These values are mostly from what I think is right - * looking at the dmesg output from a Linux guest inside - * a VMware server VM. - * - * So they don't have to be right :) - */ - memset(Buslogic->LocalRam.u8View, 0, sizeof(HostAdapterLocalRam)); - Buslogic->LocalRam.structured.autoSCSIData.fLevelSensitiveInterrupt = 1; - Buslogic->LocalRam.structured.autoSCSIData.fParityCheckingEnabled = 1; - Buslogic->LocalRam.structured.autoSCSIData.fExtendedTranslation = 1; /* Same as in geometry register. */ - Buslogic->LocalRam.structured.autoSCSIData.u16DeviceEnabledMask = UINT16_MAX; /* All enabled. Maybe mask out non present devices? */ - Buslogic->LocalRam.structured.autoSCSIData.u16WidePermittedMask = UINT16_MAX; - Buslogic->LocalRam.structured.autoSCSIData.u16FastPermittedMask = UINT16_MAX; - Buslogic->LocalRam.structured.autoSCSIData.u16SynchronousPermittedMask = UINT16_MAX; - Buslogic->LocalRam.structured.autoSCSIData.u16DisconnectPermittedMask = UINT16_MAX; - Buslogic->LocalRam.structured.autoSCSIData.fStrictRoundRobinMode = Buslogic->StrictRoundRobinMode; - Buslogic->LocalRam.structured.autoSCSIData.u16UltraPermittedMask = UINT16_MAX; - /** @todo calculate checksum? */ -} - -static void BuslogicReset(Buslogic_t *Buslogic) -{ - Buslogic->Status = STAT_IDLE | STAT_INIT; - Buslogic->Geometry = 0x80; - Buslogic->Command = 0xFF; - Buslogic->CmdParam = 0; - Buslogic->CmdParamLeft = 0; - Buslogic->IrqEnabled = 1; - Buslogic->StrictRoundRobinMode = 0; - Buslogic->ExtendedLUNCCBFormat = 0; - Buslogic->MailboxOutPosCur = 0; - Buslogic->MailboxInPosCur = 0; - - BuslogicClearInterrupt(Buslogic); - - BuslogicLocalRam(Buslogic); -} - -static void BuslogicResetControl(Buslogic_t *Buslogic, uint8_t Reset) -{ - BuslogicReset(Buslogic); - if (Reset) - { - Buslogic->Status |= STAT_STST; - Buslogic->Status &= ~STAT_IDLE; - } -} - -static void BuslogicCommandComplete(Buslogic_t *Buslogic) -{ - Buslogic->Status |= STAT_IDLE; - Buslogic->DataReply = 0; - - if (Buslogic->Command != 0x02) - { - Buslogic->Status &= ~STAT_DFULL; - Buslogic->Interrupt = INTR_ANY | INTR_HACC; - picint(1 << Buslogic->Irq); - } - - Buslogic->Command = 0xFF; - Buslogic->CmdParam = 0; -} - -static void BuslogicMailboxIn(Buslogic_t *Buslogic, uint32_t CCBPointer, CCBU *CmdBlock, - uint8_t HostStatus, uint8_t TargetStatus, uint8_t MailboxCompletionCode) -{ - Mailbox32_t Mailbox32; - Mailbox_t MailboxIn; - - Mailbox32.CCBPointer = CCBPointer; - Mailbox32.u.in.HostStatus = HostStatus; - Mailbox32.u.in.TargetStatus = TargetStatus; - Mailbox32.u.in.CompletionCode = MailboxCompletionCode; - - uint32_t Incoming = Buslogic->MailboxInAddr + (Buslogic->MailboxInPosCur * (Buslogic->Mbx24bit ? sizeof(Mailbox_t) : sizeof(Mailbox32_t))); - - if (MailboxCompletionCode != MBI_NOT_FOUND) - { - CmdBlock->common.HostStatus = HostStatus; - CmdBlock->common.TargetStatus = TargetStatus; - - //Rewrite the CCB up to the CDB. - DMAPageWrite(CCBPointer, CmdBlock, offsetof(CCBC, Cdb)); - } - - BuslogicLog("Host Status 0x%02X, Target Status 0x%02X\n", HostStatus, TargetStatus); - - if (Buslogic->Mbx24bit) - { - MailboxIn.CmdStatus = Mailbox32.u.in.CompletionCode; - U32_TO_ADDR(MailboxIn.CCBPointer, Mailbox32.CCBPointer); - BuslogicLog("Mailbox 24-bit: Status=0x%02X, CCB at 0x%04X\n", MailboxIn.CmdStatus, ADDR_TO_U32(MailboxIn.CCBPointer)); - - DMAPageWrite(Incoming, &MailboxIn, sizeof(Mailbox_t)); - } - else - { - BuslogicLog("Mailbox 32-bit: Status=0x%02X, CCB at 0x%04X\n", Mailbox32.u.in.CompletionCode, Mailbox32.CCBPointer); - - DMAPageWrite(Incoming, &Mailbox32, sizeof(Mailbox32_t)); - } - - Buslogic->MailboxInPosCur++; - if (Buslogic->MailboxInPosCur > Buslogic->MailboxCount) - Buslogic->MailboxInPosCur = 0; - - Buslogic->Interrupt = INTR_MBIF | INTR_ANY; - picint(1 << Buslogic->Irq); -} - -static void BuslogicReadSGEntries(int Is24bit, uint32_t SGList, uint32_t Entries, SGE32 *SG) -{ - if (Is24bit) - { - uint32_t i; - SGE SGE24[MAX_SG_DESCRIPTORS]; - - DMAPageRead(SGList, &SGE24, Entries * sizeof(SGE)); - - for (i=0;iCmdBlock.old.DataPointer); - DataLength = ADDR_TO_U32(BuslogicRequests->CmdBlock.old.DataLength); - } - else - { - DataPointer = BuslogicRequests->CmdBlock.new.DataPointer; - DataLength = BuslogicRequests->CmdBlock.new.DataLength; - } - - if (BuslogicRequests->CmdBlock.common.Cdb[0] == GPCMD_TEST_UNIT_READY) - DataLength = 0; - - BuslogicLog("Data Buffer write: length %d, pointer 0x%04X\n", DataLength, DataPointer); - - if (DataLength && BuslogicRequests->CmdBlock.common.ControlByte != 0x03) - { - if (BuslogicRequests->CmdBlock.common.Opcode == SCATTER_GATHER_COMMAND || - BuslogicRequests->CmdBlock.common.Opcode == SCATTER_GATHER_COMMAND_RES) - { - uint32_t ScatterGatherRead; - uint32_t ScatterEntry; - SGE32 ScatterGatherBuffer[MAX_SG_DESCRIPTORS]; - uint32_t ScatterGatherLeft = DataLength / (Is24bit ? sizeof(SGE) : sizeof(SGE32)); - uint32_t ScatterGatherAddrCurrent = DataPointer; - uint32_t DataToTransfer = 0; - - do - { - ScatterGatherRead = (ScatterGatherLeft < ELEMENTS(ScatterGatherBuffer)) - ? ScatterGatherLeft : ELEMENTS(ScatterGatherBuffer); - - ScatterGatherLeft -= ScatterGatherRead; - - BuslogicReadSGEntries(Is24bit, ScatterGatherAddrCurrent, ScatterGatherRead, ScatterGatherBuffer); - - for (ScatterEntry = 0; ScatterEntry < ScatterGatherRead; ScatterEntry++) - { - uint32_t Address; - - Address = ScatterGatherBuffer[ScatterEntry].SegmentPointer; - DataToTransfer += ScatterGatherBuffer[ScatterEntry].Segment; - } - - ScatterGatherAddrCurrent += ScatterGatherRead * (Is24bit ? sizeof(SGE) : sizeof(SGE32)); - } while (ScatterGatherLeft > 0); - - BuslogicLog("Data to transfer (S/G) %d\n", DataToTransfer); - - SCSIDevices[scsi_cdrom_id].InitLength = DataToTransfer; - SCSIDevices[scsi_cdrom_id].CmdBuffer[SCSIDevices[scsi_cdrom_id].pos++] = SCSIDevices[scsi_cdrom_id].InitLength; - - //If the control byte is 0x00, it means that the transfer direction is set up by the SCSI command without - //checking its length, so do this procedure for both no read/write commands. - if (BuslogicRequests->CmdBlock.common.ControlByte == CCB_DATA_XFER_OUT || BuslogicRequests->CmdBlock.common.ControlByte == 0x00) - { - ScatterGatherLeft = DataLength / (Is24bit ? sizeof(SGE) : sizeof(SGE32)); - ScatterGatherAddrCurrent = DataPointer; - - do - { - ScatterGatherRead = (ScatterGatherLeft < ELEMENTS(ScatterGatherBuffer)) - ? ScatterGatherLeft : ELEMENTS(ScatterGatherBuffer); - - ScatterGatherLeft -= ScatterGatherRead; - - BuslogicReadSGEntries(Is24bit, ScatterGatherAddrCurrent, ScatterGatherRead, ScatterGatherBuffer); - - for (ScatterEntry = 0; ScatterEntry < ScatterGatherRead; ScatterEntry++) - { - uint32_t Address; - - Address = ScatterGatherBuffer[ScatterEntry].SegmentPointer; - DataToTransfer = ScatterGatherBuffer[ScatterEntry].Segment; - - DMAPageRead(Address, SCSIDevices[scsi_cdrom_id].CmdBuffer, DataToTransfer); - } - - ScatterGatherAddrCurrent += ScatterGatherRead * (Is24bit ? sizeof(SGE) : sizeof(SGE32)); - } while (ScatterGatherLeft > 0); - } - } - else if (BuslogicRequests->CmdBlock.common.Opcode == SCSI_INITIATOR_COMMAND || - BuslogicRequests->CmdBlock.common.Opcode == SCSI_INITIATOR_COMMAND_RES) - { - uint32_t Address = DataPointer; - SCSIDevices[scsi_cdrom_id].InitLength = DataLength; - SCSIDevices[scsi_cdrom_id].CmdBuffer[SCSIDevices[scsi_cdrom_id].pos++] = SCSIDevices[scsi_cdrom_id].InitLength; - - DMAPageRead(Address, SCSIDevices[scsi_cdrom_id].CmdBuffer, SCSIDevices[scsi_cdrom_id].InitLength); - } - } -} - -void BuslogicDataBufferFree(BuslogicRequests_t *BuslogicRequests) -{ - if (BuslogicRequests->Is24bit) - { - DataPointer = ADDR_TO_U32(BuslogicRequests->CmdBlock.old.DataPointer); - DataLength = ADDR_TO_U32(BuslogicRequests->CmdBlock.old.DataLength); - } - else - { - DataPointer = BuslogicRequests->CmdBlock.new.DataPointer; - DataLength = BuslogicRequests->CmdBlock.new.DataLength; - } - - if (BuslogicRequests->CmdBlock.common.Cdb[0] == GPCMD_TEST_UNIT_READY) - DataLength = 0; - - BuslogicLog("Data Buffer read: length %d, pointer 0x%04X\n", DataLength, DataPointer); - - //If the control byte is 0x00, it means that the transfer direction is set up by the SCSI command without - //checking its length, so do this procedure for both read/write commands. - if (DataLength > 0 && (BuslogicRequests->CmdBlock.common.ControlByte == CCB_DATA_XFER_IN || - BuslogicRequests->CmdBlock.common.ControlByte == 0x00) && BuslogicRequests->CmdBlock.common.ControlByte != 0x03) - { - if (BuslogicRequests->CmdBlock.common.Opcode == SCATTER_GATHER_COMMAND || - BuslogicRequests->CmdBlock.common.Opcode == SCATTER_GATHER_COMMAND_RES) - { - uint32_t ScatterGatherRead; - uint32_t ScatterEntry; - SGE32 ScatterGatherBuffer[MAX_SG_DESCRIPTORS]; - uint32_t ScatterGatherLeft = DataLength / (BuslogicRequests->Is24bit ? sizeof(SGE) : sizeof(SGE32)); - uint32_t ScatterGatherAddrCurrent = DataPointer; - - do - { - ScatterGatherRead = (ScatterGatherLeft < ELEMENTS(ScatterGatherBuffer)) - ? ScatterGatherLeft : ELEMENTS(ScatterGatherBuffer); - - ScatterGatherLeft -= ScatterGatherRead; - - BuslogicReadSGEntries(BuslogicRequests->Is24bit, ScatterGatherAddrCurrent, ScatterGatherRead, ScatterGatherBuffer); - - for (ScatterEntry = 0; ScatterEntry < ScatterGatherRead; ScatterEntry++) - { - uint32_t Address; - uint32_t DataToTransfer; - - Address = ScatterGatherBuffer[ScatterEntry].SegmentPointer; - DataToTransfer = ScatterGatherBuffer[ScatterEntry].Segment; - - DMAPageWrite(Address, SCSIDevices[scsi_cdrom_id].CmdBuffer, DataToTransfer); - } - - ScatterGatherAddrCurrent += ScatterGatherRead * (BuslogicRequests->Is24bit ? sizeof(SGE) : sizeof(SGE32)); - } while (ScatterGatherLeft > 0); - } - else if (BuslogicRequests->CmdBlock.common.Opcode == SCSI_INITIATOR_COMMAND || - BuslogicRequests->CmdBlock.common.Opcode == SCSI_INITIATOR_COMMAND_RES) - { - uint32_t Address = DataPointer; - DMAPageWrite(Address, SCSIDevices[scsi_cdrom_id].CmdBuffer, SCSIDevices[scsi_cdrom_id].InitLength); - } - } - - SCSIDevices[scsi_cdrom_id].InitLength = 0; -} - -uint8_t BuslogicRead(uint16_t Port, void *p) -{ - Buslogic_t *Buslogic = (Buslogic_t *)p; - uint8_t Temp; - - switch (Port & 3) - { - case 0: - Temp = Buslogic->Status; - if (Buslogic->Status & STAT_STST) - { - Buslogic->Status &= ~STAT_STST; - Buslogic->Status |= STAT_IDLE; - Temp = Buslogic->Status; - } - break; - - case 1: - if (Buslogic->UseLocalRam) - Temp = Buslogic->LocalRam.u8View[Buslogic->DataReply]; - else - Temp = Buslogic->DataBuf[Buslogic->DataReply]; - if (Buslogic->DataReplyLeft) - { - Buslogic->DataReply++; - Buslogic->DataReplyLeft--; - if (!Buslogic->DataReplyLeft) - { - BuslogicCommandComplete(Buslogic); - } - } - break; - - case 2: - Temp = Buslogic->Interrupt; - break; - - case 3: - Temp = Buslogic->Geometry; - break; - } - - BuslogicLog("Buslogic: Read Port 0x%02X, Returned Value %02X\n", Port, Temp); - return Temp; -} - -void BuslogicWrite(uint16_t Port, uint8_t Val, void *p) -{ - Buslogic_t *Buslogic = (Buslogic_t *)p; - BuslogicRequests_t *BuslogicRequests = &Buslogic->BuslogicRequests; - BuslogicLog("Buslogic: Write Port 0x%02X, Value %02X\n", Port, Val); - - switch (Port & 3) - { - case 0: - if ((Val & CTRL_HRST) || (Val & CTRL_SRST)) - { - uint8_t Reset = !!(Val & CTRL_HRST); - BuslogicResetControl(Buslogic, Reset); - break; - } - - if (Val & CTRL_IRST) - { - BuslogicClearInterrupt(Buslogic); - } - break; - - case 1: - if ((Val == 0x02) && (Buslogic->Command == 0xFF)) - { - SCSICallback[scsi_cdrom_id] = 1; - break; - } - - if (Buslogic->Command == 0xFF) - { - Buslogic->Command = Val; - Buslogic->CmdParam = 0; - - Buslogic->Status &= ~(STAT_INVCMD | STAT_IDLE); - BuslogicLog("Buslogic: Operation Code 0x%02X\n", Val); - switch (Buslogic->Command) - { - case 0x00: - case 0x04: - case 0x0A: - case 0x0B: - case 0x23: - case 0x84: - case 0x85: - Buslogic->CmdParamLeft = 0; - break; - - case 0x07: - case 0x08: - case 0x09: - case 0x0D: - case 0x1F: - case 0x21: - case 0x24: - case 0x25: - Buslogic->CmdParamLeft = 1; - break; - - case 0x8B: - case 0x8D: - case 0x8F: - case 0x96: - Buslogic->CmdParamLeft = scsi_model ? 1 : 0; - break; - - case 0x91: - Buslogic->CmdParamLeft = 2; - break; - - case 0x1C: - case 0x1D: - Buslogic->CmdParamLeft = 3; - break; - - case 0x06: - Buslogic->CmdParamLeft = 4; - break; - - case 0x01: - Buslogic->CmdParamLeft = sizeof(MailboxInit_t); - break; - - case 0x81: - Buslogic->CmdParamLeft = scsi_model ? sizeof(MailboxInitExtended_t) : 0; - break; - - case 0x28: - case 0x29: - case 0x86: //Valid only for PCI - case 0x95: //Valid only for PCI - Buslogic->CmdParamLeft = 0; - break; - } - } - else - { - Buslogic->CmdBuf[Buslogic->CmdParam] = Val; - Buslogic->CmdParam++; - Buslogic->CmdParamLeft--; - } - - if (!Buslogic->CmdParamLeft) - { - BuslogicLog("Running Operation Code 0x%02X\n", Buslogic->Command); - switch (Buslogic->Command) - { - case 0x00: - Buslogic->DataReplyLeft = 0; - break; - - case 0x01: - { - Buslogic->Mbx24bit = 1; - - MailboxInit_t *MailboxInit = (MailboxInit_t *)Buslogic->CmdBuf; - - Buslogic->MailboxCount = MailboxInit->Count; - Buslogic->MailboxOutAddr = ADDR_TO_U32(MailboxInit->Address); - Buslogic->MailboxInAddr = Buslogic->MailboxOutAddr + (Buslogic->MailboxCount * sizeof(Mailbox_t)); - - BuslogicLog("Buslogic Initialize Mailbox Command\n"); - BuslogicLog("Mailbox Out Address=0x%08X\n", Buslogic->MailboxOutAddr); - BuslogicLog("Mailbox In Address=0x%08X\n", Buslogic->MailboxInAddr); - BuslogicLog("Initialized Mailbox, %d entries at 0x%08X\n", MailboxInit->Count, ADDR_TO_U32(MailboxInit->Address)); - - Buslogic->Status &= ~STAT_INIT; - Buslogic->DataReplyLeft = 0; - } - break; - - case 0x04: - Buslogic->DataBuf[0] = 0x41; - Buslogic->DataBuf[1] = scsi_model ? 0x41 : 0x30; - Buslogic->DataBuf[2] = '5'; - Buslogic->DataBuf[3] = '0'; - Buslogic->DataReplyLeft = 4; - break; - - case 0x06: - Buslogic->DataReplyLeft = 0; - break; - - case 0x07: - Buslogic->DataReplyLeft = 0; - Buslogic->LocalRam.structured.autoSCSIData.uBusOnDelay = Buslogic->CmdBuf[0]; - BuslogicLog("Bus-on time: %d\n", Buslogic->CmdBuf[0]); - break; - - case 0x08: - Buslogic->DataReplyLeft = 0; - Buslogic->LocalRam.structured.autoSCSIData.uBusOffDelay = Buslogic->CmdBuf[0]; - BuslogicLog("Bus-off time: %d\n", Buslogic->CmdBuf[0]); - break; - - case 0x09: - Buslogic->DataReplyLeft = 0; - Buslogic->LocalRam.structured.autoSCSIData.uDMATransferRate = Buslogic->CmdBuf[0]; - BuslogicLog("DMA transfer rate: %02X\n", Buslogic->CmdBuf[0]); - break; - - case 0x0A: - if (scsi_cdrom_id < 8) - { - if (SCSIDevices[scsi_cdrom_id].LunType == SCSI_CDROM) - Buslogic->DataBuf[scsi_cdrom_id] = 1; - - Buslogic->DataBuf[7] = 0; - Buslogic->DataReplyLeft = 8; - } - break; - - case 0x0B: - Buslogic->DataBuf[0] = (1 << Buslogic->DmaChannel); - Buslogic->DataBuf[1] = (1 << (Buslogic->Irq - 9)); - Buslogic->DataBuf[2] = 7; - Buslogic->DataReplyLeft = 3; - break; - - case 0x0D: - { - Buslogic->DataReplyLeft = Buslogic->CmdBuf[0]; - - ReplyInquireSetupInformation *Reply = (ReplyInquireSetupInformation *)Buslogic->DataBuf; - - Reply->fSynchronousInitiationEnabled = 1; - Reply->fParityCheckingEnabled = 1; - Reply->cMailbox = Buslogic->MailboxCount; - U32_TO_ADDR(Reply->MailboxAddress, Buslogic->MailboxOutAddr); - - if (scsi_model) - { - Reply->uSignature = 'B'; - /* The 'D' signature prevents Buslogic's OS/2 drivers from getting too - * friendly with Adaptec hardware and upsetting the HBA state. - */ - Reply->uCharacterD = 'D'; /* BusLogic model. */ - Reply->uHostBusType = 'A'; /* ISA bus. */ - } - - BuslogicLog("Return Setup Information: %d\n", Buslogic->CmdBuf[0]); - } - break; - - - case 0x23: - if (scsi_cdrom_id >= 8) - { - if (SCSIDevices[scsi_cdrom_id].LunType == SCSI_CDROM) - Buslogic->DataBuf[scsi_cdrom_id] = 1; - - Buslogic->DataReplyLeft = 8; - } - break; - - case 0x1C: - { - uint32_t FIFOBuf; - addr24 Address; - - Buslogic->DataReplyLeft = 0; - Address.hi = Buslogic->CmdBuf[0]; - Address.mid = Buslogic->CmdBuf[1]; - Address.lo = Buslogic->CmdBuf[2]; - FIFOBuf = ADDR_TO_U32(Address); - DMAPageRead(FIFOBuf, &Buslogic->LocalRam.u8View[64], 64); - } - break; - - case 0x1D: - { - uint32_t FIFOBuf; - addr24 Address; - - Buslogic->DataReplyLeft = 0; - Address.hi = Buslogic->CmdBuf[0]; - Address.mid = Buslogic->CmdBuf[1]; - Address.lo = Buslogic->CmdBuf[2]; - FIFOBuf = ADDR_TO_U32(Address); - DMAPageWrite(FIFOBuf, &Buslogic->LocalRam.u8View[64], 64); - } - break; - - case 0x1F: - Buslogic->DataBuf[0] = Buslogic->CmdBuf[0]; - Buslogic->DataReplyLeft = 1; - break; - - case 0x21: - if (Buslogic->CmdParam == 1) - Buslogic->CmdParamLeft = Buslogic->CmdBuf[0]; - - Buslogic->DataReplyLeft = 0; - break; - - case 0x24: - { - uint8_t i; - uint16_t TargetsPresentMask = 0; - - for (i=0;iDataBuf[0] = TargetsPresentMask&0x0F; - Buslogic->DataBuf[1] = TargetsPresentMask>>8; - Buslogic->DataReplyLeft = 2; - } - break; - - case 0x25: - if (Buslogic->CmdBuf[0] == 0) - Buslogic->IrqEnabled = 0; - else - Buslogic->IrqEnabled = 1; - picintc(1 << Buslogic->Irq); - break; - - case 0x81: - { - if (scsi_model) - { - Buslogic->Mbx24bit = 0; - - MailboxInitExtended_t *MailboxInit = (MailboxInitExtended_t *)Buslogic->CmdBuf; - - Buslogic->MailboxCount = MailboxInit->Count; - Buslogic->MailboxOutAddr = MailboxInit->Address; - Buslogic->MailboxInAddr = MailboxInit->Address + (Buslogic->MailboxCount * sizeof(Mailbox32_t)); - - BuslogicLog("Buslogic Extended Initialize Mailbox Command\n"); - BuslogicLog("Mailbox Out Address=0x%08X\n", Buslogic->MailboxOutAddr); - BuslogicLog("Mailbox In Address=0x%08X\n", Buslogic->MailboxInAddr); - BuslogicLog("Initialized Extended Mailbox, %d entries at 0x%08X\n", MailboxInit->Count, MailboxInit->Address); - - Buslogic->Status &= ~STAT_INIT; - Buslogic->DataReplyLeft = 0; - } - else - { - Buslogic->DataReplyLeft = 0; - Buslogic->Status |= STAT_INVCMD; - } - } - break; - - case 0x84: - if (scsi_model) - { - Buslogic->DataBuf[0] = '7'; - Buslogic->DataReplyLeft = 1; - } - else - { - Buslogic->DataReplyLeft = 0; - Buslogic->Status |= STAT_INVCMD; - } - break; - - case 0x85: - if (scsi_model) - { - Buslogic->DataBuf[0] = 'B'; - Buslogic->DataReplyLeft = 1; - } - else - { - Buslogic->DataReplyLeft = 0; - Buslogic->Status |= STAT_INVCMD; - } - break; - - case 0x8B: - { - if (scsi_model) - { - int i; - - /* The reply length is set by the guest and is found in the first byte of the command buffer. */ - Buslogic->DataReplyLeft = Buslogic->CmdBuf[0]; - memset(Buslogic->DataBuf, 0, Buslogic->DataReplyLeft); - const char aModelName[] = "542B "; /* Trailing \0 is fine, that's the filler anyway. */ - int cCharsToTransfer = Buslogic->DataReplyLeft <= sizeof(aModelName) - ? Buslogic->DataReplyLeft - : sizeof(aModelName); - - for (i = 0; i < cCharsToTransfer; i++) - Buslogic->DataBuf[i] = aModelName[i]; - } - else - { - Buslogic->DataReplyLeft = 0; - Buslogic->Status |= STAT_INVCMD; - } - } - break; - - case 0x8D: - { - if (scsi_model) - { - Buslogic->DataReplyLeft = Buslogic->CmdBuf[0]; - ReplyInquireExtendedSetupInformation *Reply = (ReplyInquireExtendedSetupInformation *)Buslogic->DataBuf; - - Reply->uBusType = 'A'; /* ISA style */ - Reply->u16ScatterGatherLimit = 8192; - Reply->cMailbox = Buslogic->MailboxCount; - Reply->uMailboxAddressBase = Buslogic->MailboxOutAddr; - memcpy(Reply->aFirmwareRevision, "07B", sizeof(Reply->aFirmwareRevision)); - BuslogicLog("Return Extended Setup Information: %d\n", Buslogic->CmdBuf[0]); - } - else - { - Buslogic->DataReplyLeft = 0; - Buslogic->Status |= STAT_INVCMD; - } - } - break; - - case 0x8F: - if (scsi_model) - { - if (Buslogic->CmdBuf[0] == 0) - Buslogic->StrictRoundRobinMode = 0; - else if (Buslogic->CmdBuf[0] == 1) - Buslogic->StrictRoundRobinMode = 1; - - Buslogic->DataReplyLeft = 0; - } - else - { - Buslogic->DataReplyLeft = 0; - Buslogic->Status |= STAT_INVCMD; - } - break; - - case 0x91: - { - uint8_t Offset = Buslogic->CmdBuf[0]; - Buslogic->DataReplyLeft = Buslogic->CmdBuf[1]; - - Buslogic->UseLocalRam = 1; - Buslogic->DataReply = Offset; - } - break; - - case 0x96: - if (scsi_model) - { - if (Buslogic->CmdBuf[0] == 0) - Buslogic->ExtendedLUNCCBFormat = 0; - else if (Buslogic->CmdBuf[0] == 1) - Buslogic->ExtendedLUNCCBFormat = 1; - - Buslogic->DataReplyLeft = 0; - } - break; - - case 0x22: //undocumented - case 0x28: //only for the Adaptec 154xC series - case 0x29: //only for the Adaptec 154xC series - case 0x86: //PCI only, not ISA - case 0x95: //PCI only, not ISA - Buslogic->DataReplyLeft = 0; - Buslogic->Status |= STAT_INVCMD; - break; - } - } - - if (Buslogic->DataReplyLeft) - Buslogic->Status |= STAT_DFULL; - else if (!Buslogic->CmdParamLeft) - BuslogicCommandComplete(Buslogic); - break; - - case 2: - if (scsi_model) - Buslogic->Interrupt = Val; //For Buslogic - break; - - case 3: - if (scsi_model) - Buslogic->Geometry = Val; //For Buslogic - break; - } -} - -static uint8_t BuslogicConvertSenseLength(uint8_t RequestSenseLength) -{ - if (RequestSenseLength == 0) - RequestSenseLength = 14; - else if (RequestSenseLength == 1) - RequestSenseLength = 0; - - BuslogicLog("Request Sense length %i\n", RequestSenseLength); - - return RequestSenseLength; -} - -static void BuslogicSenseBufferAllocate(BuslogicRequests_t *BuslogicRequests) -{ - uint8_t SenseLength = BuslogicConvertSenseLength(BuslogicRequests->CmdBlock.common.RequestSenseLength); - - if (SenseLength) - BuslogicRequests->RequestSenseBuffer = (uint8_t *)malloc(SenseLength); -} - -static void BuslogicSenseBufferFree(BuslogicRequests_t *BuslogicRequests, int Copy) -{ - uint8_t SenseLength = BuslogicConvertSenseLength(BuslogicRequests->CmdBlock.common.RequestSenseLength); - - if (SenseLength && Copy) - { - uint32_t SenseBufferAddress; - - /*The sense address, in 32-bit mode, is located in the Sense Pointer of the CCB, but in - 24-bit mode, it is located at the end of the Command Descriptor Block. */ - - if (BuslogicRequests->Is24bit) - { - SenseBufferAddress = BuslogicRequests->CCBPointer; - SenseBufferAddress += BuslogicRequests->CmdBlock.common.CdbLength + offsetof(CCB, Cdb); - } - else - { - SenseBufferAddress = BuslogicRequests->CmdBlock.new.SensePointer; - } - - BuslogicLog("Request Sense address: %02X\n", SenseBufferAddress); - - DMAPageWrite(SenseBufferAddress, BuslogicRequests->RequestSenseBuffer, SenseLength); - } - //Free the sense buffer when needed. - free(BuslogicRequests->RequestSenseBuffer); -} - -static void BuslogicSCSIRequestSetup(Buslogic_t *Buslogic, uint32_t CCBPointer, Mailbox32_t *Mailbox32) -{ - BuslogicRequests_t *BuslogicRequests = &Buslogic->BuslogicRequests; - uint8_t Id, Lun; - - //Fetch data from the Command Control Block. - DMAPageRead(CCBPointer, &BuslogicRequests->CmdBlock, sizeof(CCB32)); - - BuslogicRequests->TargetID = Buslogic->Mbx24bit ? BuslogicRequests->CmdBlock.old.Id : BuslogicRequests->CmdBlock.new.Id; - BuslogicRequests->LUN = Buslogic->Mbx24bit ? BuslogicRequests->CmdBlock.old.Lun : BuslogicRequests->CmdBlock.new.Lun; - - Id = BuslogicRequests->TargetID; - Lun = BuslogicRequests->LUN; - - BuslogicLog("Scanning SCSI Target ID %i\n", Id); - - //Only SCSI CD-ROMs are supported at the moment, SCSI hard disk support will come soon. - if (Id == scsi_cdrom_id && Lun == 0) - { - BuslogicLog("SCSI Target ID %i detected and working\n", Id); - - BuslogicRequests->CCBPointer = CCBPointer; - BuslogicRequests->Is24bit = Buslogic->Mbx24bit; - - if (Mailbox32->u.out.ActionCode == MBO_START) - { - BuslogicSenseBufferAllocate(BuslogicRequests); - - BuslogicDataBufferAllocate(BuslogicRequests, BuslogicRequests->Is24bit); - - uint32_t i; - - pclog("SCSI Cdb[0]=0x%02X\n", BuslogicRequests->CmdBlock.common.Cdb[0]); - for (i = 1; i < BuslogicRequests->CmdBlock.common.CdbLength; i++) - pclog("SCSI Cdb[%i]=%i\n", i, BuslogicRequests->CmdBlock.common.Cdb[i]); - - pclog("Transfer Control %02X\n", BuslogicRequests->CmdBlock.common.ControlByte); - pclog("CDB Length %i\n", BuslogicRequests->CmdBlock.common.CdbLength); - pclog("CCB Opcode %x\n", BuslogicRequests->CmdBlock.common.Opcode); - - //This not ready/unit attention stuff below is only for the Buslogic! - //The Adaptec one is in scsi_cdrom.c. - - if (scsi_model) - { - if ((BuslogicRequests->CmdBlock.common.ControlByte != 0x03) && (BuslogicRequests->CmdBlock.common.Opcode == SCSI_INITIATOR_COMMAND)) - { - if (cdrom->medium_changed()) - { - pclog("Media changed\n"); - SCSICDROM_Insert(); - } - - if (!cdrom->ready() && SCSISense.UnitAttention) - { - /* If the drive is not ready, there is no reason to keep the - UNIT ATTENTION condition present, as we only use it to mark - disc changes. */ - SCSISense.UnitAttention = 0; - } - - /* If the UNIT ATTENTION condition is set and the command does not allow - execution under it, error out and report the condition. */ - if (SCSISense.UnitAttention == 1) - { - SCSISense.UnitAttention = 2; - if (!(SCSICommandTable[BuslogicRequests->CmdBlock.common.Cdb[0]] & ALLOW_UA)) - { - SCSISenseCodeError(SENSE_UNIT_ATTENTION, ASC_MEDIUM_MAY_HAVE_CHANGED, 0); - SCSIStatus = SCSI_STATUS_CHECK_CONDITION; - SCSICallback[Id]=50*SCSI_TIME; - BuslogicMailboxIn(Buslogic, BuslogicRequests->CCBPointer, &BuslogicRequests->CmdBlock, CCB_COMPLETE, SCSI_STATUS_CHECK_CONDITION, MBI_ERROR); - return; - } - } - else if (SCSISense.UnitAttention == 2) - { - if (BuslogicRequests->CmdBlock.common.Cdb[0]!=GPCMD_REQUEST_SENSE) - { - SCSISense.UnitAttention = 0; - } - } - - /* Unless the command is REQUEST SENSE, clear the sense. This will *NOT* - clear the UNIT ATTENTION condition if it's set. */ - if (BuslogicRequests->CmdBlock.common.Cdb[0]!=GPCMD_REQUEST_SENSE) - { - SCSIClearSense(BuslogicRequests->CmdBlock.common.Cdb[0], 0); - } - - /* Next it's time for NOT READY. */ - if ((SCSICommandTable[BuslogicRequests->CmdBlock.common.Cdb[0]] & CHECK_READY) && !cdrom->ready()) - { - pclog("Not ready\n"); - SCSISenseCodeError(SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT, 0); - SCSIStatus = SCSI_STATUS_CHECK_CONDITION; - SCSICallback[Id]=50*SCSI_TIME; - BuslogicMailboxIn(Buslogic, BuslogicRequests->CCBPointer, &BuslogicRequests->CmdBlock, CCB_COMPLETE, SCSI_STATUS_CHECK_CONDITION, MBI_ERROR); - return; - } - } - } - - //First, get the data buffer otherwise putting it after the - //exec function results into not getting read/write commands right and - //failing to detect the device. - - if (BuslogicRequests->CmdBlock.common.ControlByte == CCB_DATA_XFER_IN) - { - SCSIRead(Id, SCSIDevices[Id].CmdBuffer, SCSIDevices[Id].CmdBuffer, SCSIDevices[Id].InitLength); - } - else if (BuslogicRequests->CmdBlock.common.ControlByte == CCB_DATA_XFER_OUT) - { - SCSIWrite(Id, SCSIDevices[Id].CmdBuffer, SCSIDevices[Id].CmdBuffer, SCSIDevices[Id].InitLength); - } - - //Finally, execute the SCSI command immediately and get the transfer length. - - SCSIPhase = SCSI_PHASE_COMMAND; - SCSIExecCommand(Id, SCSIDevices[Id].CmdBuffer, BuslogicRequests->CmdBlock.common.Cdb); - SCSIGetLength(Id, &SCSIDevices[Id].InitLength); - - if (SCSIPhase == SCSI_PHASE_DATAIN) - { - SCSIReadData(Id, BuslogicRequests->CmdBlock.common.Cdb, SCSIDevices[Id].CmdBuffer, SCSIDevices[Id].InitLength); - } - else if (SCSIPhase == SCSI_PHASE_DATAOUT) - { - if (BuslogicRequests->CmdBlock.common.Cdb[0] == GPCMD_MODE_SELECT_6 || - BuslogicRequests->CmdBlock.common.Cdb[0] == GPCMD_MODE_SELECT_10) - { - //Mode Sense/Select stuff - if ((SCSIDevices[Id].pos >= prefix_len+4) && (page_flags[page_current] & PAGE_CHANGEABLE)) - { - mode_pages_in[page_current][SCSIDevices[Id].pos - prefix_len - 4] = SCSIDevices[Id].CmdBuffer[SCSIDevices[Id].pos - 2]; - mode_pages_in[page_current][SCSIDevices[Id].pos - prefix_len - 3] = SCSIDevices[Id].CmdBuffer[SCSIDevices[Id].pos - 1]; - } - } - } - - BuslogicDataBufferFree(BuslogicRequests); - - if (BuslogicRequests->RequestSenseBuffer) - BuslogicSenseBufferFree(BuslogicRequests, (SCSIStatus != SCSI_STATUS_OK)); - } - - pclog("Request complete\n"); - pclog("SCSI Status %02X, Sense %02X, Asc %02X, Ascq %02X\n", SCSIStatus, SCSISense.SenseKey, SCSISense.Asc, SCSISense.Ascq); - - - if (BuslogicRequests->CmdBlock.common.Opcode == SCSI_INITIATOR_COMMAND_RES || - BuslogicRequests->CmdBlock.common.Opcode == SCATTER_GATHER_COMMAND_RES) - { - if (BuslogicRequests->Is24bit) - { - U32_TO_ADDR(BuslogicRequests->CmdBlock.old.DataLength, SCSIDevices[Id].InitLength); - BuslogicLog("24-bit Residual data length for reading: %d\n", ADDR_TO_U32(BuslogicRequests->CmdBlock.old.DataLength)); - } - else - { - BuslogicRequests->CmdBlock.new.DataLength = SCSIDevices[Id].InitLength; - BuslogicLog("32-bit Residual data length for reading: %d\n", BuslogicRequests->CmdBlock.new.DataLength); - } - } - - if (SCSIStatus == SCSI_STATUS_OK) - { - BuslogicMailboxIn(Buslogic, BuslogicRequests->CCBPointer, &BuslogicRequests->CmdBlock, CCB_COMPLETE, SCSI_STATUS_OK, - MBI_SUCCESS); - } - else if (SCSIStatus == SCSI_STATUS_CHECK_CONDITION) - { - BuslogicMailboxIn(Buslogic, BuslogicRequests->CCBPointer, &BuslogicRequests->CmdBlock, CCB_COMPLETE, SCSI_STATUS_CHECK_CONDITION, - MBI_ERROR); - } - } - else - { - BuslogicMailboxIn(Buslogic, CCBPointer, &BuslogicRequests->CmdBlock, CCB_SELECTION_TIMEOUT, SCSI_STATUS_OK, MBI_ERROR); - - if (Mailbox32->u.out.ActionCode == MBO_START) - BuslogicStartMailbox(Buslogic); - } -} - -static void BuslogicSCSIRequestAbort(Buslogic_t *Buslogic, uint32_t CCBPointer) -{ - BuslogicRequests_t *BuslogicRequests = &Buslogic->BuslogicRequests; - CCBU CmdBlock; - - //Fetch data from the Command Control Block. - DMAPageRead(CCBPointer, &CmdBlock, sizeof(CCB32)); - - //Only SCSI CD-ROMs are supported at the moment, SCSI hard disk support will come soon. - BuslogicMailboxIn(Buslogic, CCBPointer, &CmdBlock, 0x26, SCSI_STATUS_OK, MBI_NOT_FOUND); -} - -static uint32_t BuslogicMailboxOut(Buslogic_t *Buslogic, Mailbox32_t *Mailbox32) -{ - Mailbox_t MailboxOut; - uint32_t Outgoing; - - if (Buslogic->Mbx24bit) - { - Outgoing = Buslogic->MailboxOutAddr + (Buslogic->MailboxOutPosCur * sizeof(Mailbox_t)); - - DMAPageRead(Outgoing, &MailboxOut, sizeof(Mailbox_t)); - - Mailbox32->CCBPointer = ADDR_TO_U32(MailboxOut.CCBPointer); - Mailbox32->u.out.ActionCode = MailboxOut.CmdStatus; - } - else - { - Outgoing = Buslogic->MailboxOutAddr + (Buslogic->MailboxOutPosCur * sizeof(Mailbox32_t)); - - DMAPageRead(Outgoing, Mailbox32, sizeof(Mailbox32_t)); - } - - return Outgoing; -} - -static void BuslogicStartMailbox(Buslogic_t *Buslogic) -{ - Mailbox32_t Mailbox32; - Mailbox_t MailboxOut; - uint32_t Outgoing; - - uint8_t MailboxOutCur = Buslogic->MailboxOutPosCur; - - do - { - Outgoing = BuslogicMailboxOut(Buslogic, &Mailbox32); - Buslogic->MailboxOutPosCur = (Buslogic->MailboxOutPosCur + 1) % Buslogic->MailboxCount; - } while (Mailbox32.u.out.ActionCode == MBO_FREE && MailboxOutCur != Buslogic->MailboxOutPosCur); - - uint8_t CmdStatus = MBO_FREE; - uint32_t CodeOffset = Buslogic->Mbx24bit ? offsetof(Mailbox_t, CmdStatus) : offsetof(Mailbox32_t, u.out.ActionCode); - - DMAPageWrite(Outgoing + CodeOffset, &CmdStatus, sizeof(CmdStatus)); - - if (Mailbox32.u.out.ActionCode == MBO_START || Mailbox32.u.out.ActionCode == MBO_FREE) - { - BuslogicLog("Start Mailbox Command\n"); - BuslogicSCSIRequestSetup(Buslogic, Mailbox32.CCBPointer, &Mailbox32); - } - else if (Mailbox32.u.out.ActionCode == MBO_ABORT) - { - BuslogicLog("Abort Mailbox Command\n"); - BuslogicSCSIRequestAbort(Buslogic, Mailbox32.CCBPointer); - } -} - -void BuslogicCommandCallback(void *p) -{ - Buslogic_t *Buslogic = (Buslogic_t *)p; - - SCSICallback[scsi_cdrom_id] = 0; - if (Buslogic->MailboxCount) - { - BuslogicStartMailbox(Buslogic); - } -} - -void *BuslogicInit() -{ - Buslogic_t *Buslogic = malloc(sizeof(Buslogic_t)); - memset(Buslogic, 0, sizeof(Buslogic_t)); - - Buslogic->Irq = scsi_irq; - Buslogic->DmaChannel = scsi_dma; - - io_sethandler(scsi_base, 0x0004, BuslogicRead, NULL, NULL, BuslogicWrite, NULL, NULL, Buslogic); - timer_add(BuslogicCommandCallback, &SCSICallback[scsi_cdrom_id], &SCSICallback[scsi_cdrom_id], Buslogic); - - BuslogicLog("Buslogic on port 0x%04X\n", scsi_base); - - BuslogicResetControl(Buslogic, CTRL_HRST); - - return Buslogic; -} - -void BuslogicClose(void *p) -{ - Buslogic_t *Buslogic = (Buslogic_t *)p; - free(Buslogic); -} - -device_t BuslogicDevice = -{ - "Adaptec/Buslogic", - 0, - BuslogicInit, - BuslogicClose, - NULL, - NULL, - NULL, - NULL -}; \ No newline at end of file diff --git a/src/buslogic.h b/src/buslogic.h deleted file mode 100644 index ffb5b4a05..000000000 --- a/src/buslogic.h +++ /dev/null @@ -1 +0,0 @@ -extern device_t BuslogicDevice; \ No newline at end of file diff --git a/src/cdrom-ioctl.c b/src/cdrom-ioctl.c deleted file mode 100644 index 37197b51f..000000000 --- a/src/cdrom-ioctl.c +++ /dev/null @@ -1,1089 +0,0 @@ -/* Copyright holders: Sarah Walker, Tenshi - see COPYING for more details -*/ -/*Win32 CD-ROM support via IOCTL*/ - -#include -#include -#include "ntddcdrm.h" -#include "ntddscsi.h" -#include "ibm.h" -#include "cdrom.h" -#include "cdrom-ioctl.h" - -int cdrom_drive; -int old_cdrom_drive; - -static CDROM ioctl_cdrom; - -static uint32_t last_block = 0; -uint32_t cdrom_capacity = 0; -static int ioctl_inited = 0; -static char ioctl_path[8]; -void ioctl_close(void); -static HANDLE hIOCTL; -static CDROM_TOC toc; -static int tocvalid = 0; - -// #define MSFtoLBA(m,s,f) (((((m*60)+s)*75)+f)-150) -/* The addresses sent from the guest are absolute, ie. a LBA of 0 corresponds to a MSF of 00:00:00. Otherwise, the counter displayed by the guest is wrong: - there is a seeming 2 seconds in which audio plays but counter does not move, while a data track before audio jumps to 2 seconds before the actual start - of the audio while audio still plays. With an absolute conversion, the counter is fine. */ -#define MSFtoLBA(m,s,f) ((((m*60)+s)*75)+f) - -enum -{ - CD_STOPPED = 0, - CD_PLAYING, - CD_PAUSED -}; - -static int ioctl_cd_state = CD_STOPPED; -static uint32_t ioctl_cd_pos = 0, ioctl_cd_end = 0; - -#define BUF_SIZE 32768 -static int16_t cd_buffer[BUF_SIZE]; -static int cd_buflen = 0; -void ioctl_audio_callback(int16_t *output, int len) -{ - RAW_READ_INFO in; - DWORD count; - -// return; -// pclog("Audio callback %08X %08X %i %i %i %04X %i\n", ioctl_cd_pos, ioctl_cd_end, ioctl_cd_state, cd_buflen, len, cd_buffer[4], GetTickCount()); - if (ioctl_cd_state != CD_PLAYING) - { - memset(output, 0, len * 2); - return; - } - while (cd_buflen < len) - { - if (ioctl_cd_pos < ioctl_cd_end) - { - in.DiskOffset.LowPart = (ioctl_cd_pos - 150) * 2048; - in.DiskOffset.HighPart = 0; - in.SectorCount = 1; - in.TrackMode = CDDA; - ioctl_open(0); -// pclog("Read to %i\n", cd_buflen); - if (!DeviceIoControl(hIOCTL, IOCTL_CDROM_RAW_READ, &in, sizeof(in), &cd_buffer[cd_buflen], 2352, &count, NULL)) - { -// pclog("DeviceIoControl returned false\n"); - memset(&cd_buffer[cd_buflen], 0, (BUF_SIZE - cd_buflen) * 2); - ioctl_cd_state = CD_STOPPED; - cd_buflen = len; - } - else - { -// pclog("DeviceIoControl returned true\n"); - ioctl_cd_pos++; - cd_buflen += (2352 / 2); - } - ioctl_close(); - } - else - { - memset(&cd_buffer[cd_buflen], 0, (BUF_SIZE - cd_buflen) * 2); - ioctl_cd_state = CD_STOPPED; - cd_buflen = len; - } - } - memcpy(output, cd_buffer, len * 2); -// for (c = 0; c < BUF_SIZE - len; c++) -// cd_buffer[c] = cd_buffer[c + cd_buflen]; - memcpy(&cd_buffer[0], &cd_buffer[len], (BUF_SIZE - len) * 2); - cd_buflen -= len; -// pclog("Done %i\n", GetTickCount()); -} - -void ioctl_audio_stop() -{ - ioctl_cd_state = CD_STOPPED; -} - -static int get_track_nr(uint32_t pos) -{ - int c; - int track = 0; - - if (!tocvalid) - return 0; - - for (c = toc.FirstTrack; c < toc.LastTrack; c++) - { - uint32_t track_address = toc.TrackData[c].Address[3] + - (toc.TrackData[c].Address[2] * 75) + - (toc.TrackData[c].Address[1] * 75 * 60); - - if (track_address <= pos) - track = c; - } - return track; -} - -static void ioctl_playaudio(uint32_t pos, uint32_t len, int ismsf) -{ - if (!cdrom_drive) return; - // pclog("Play audio - %08X %08X %i\n", pos, len, ismsf); - if (ismsf) - { - int m = (pos >> 16) & 0xff; - int s = (pos >> 8) & 0xff; - int f = pos & 0xff; - pos = MSFtoLBA(m, s, f); - m = (len >> 16) & 0xff; - s = (len >> 8) & 0xff; - f = len & 0xff; - len = MSFtoLBA(m, s, f); - // pclog("MSF - pos = %08X len = %08X\n", pos, len); - } - else - len += pos; - ioctl_cd_pos = pos;// + 150; - ioctl_cd_end = len;// + 150; - if (ioctl_cd_pos < 150) - { - /* Adjust because the host expects a minimum adjusted LBA of 0 which is equivalent to an absolute LBA of 150. */ - ioctl_cd_pos = 150; - } - ioctl_cd_state = CD_PLAYING; - // pclog("Audio start %08X %08X %i %i %i\n", ioctl_cd_pos, ioctl_cd_end, ioctl_cd_state, cd_buflen, len); -/* CDROM_PLAY_AUDIO_MSF msf; - long size; - BOOL b; - if (ismsf) - { - msf.StartingF=pos&0xFF; - msf.StartingS=(pos>>8)&0xFF; - msf.StartingM=(pos>>16)&0xFF; - msf.EndingF=len&0xFF; - msf.EndingS=(len>>8)&0xFF; - msf.EndingM=(len>>16)&0xFF; - } - else - { - msf.StartingF=(uint8_t)(addr%75); addr/=75; - msf.StartingS=(uint8_t)(addr%60); addr/=60; - msf.StartingM=(uint8_t)(addr); - addr=pos+len+150; - msf.EndingF=(uint8_t)(addr%75); addr/=75; - msf.EndingS=(uint8_t)(addr%60); addr/=60; - msf.EndingM=(uint8_t)(addr); - } - ioctl_open(0); - b = DeviceIoControl(hIOCTL,IOCTL_CDROM_PLAY_AUDIO_MSF,&msf,sizeof(msf),NULL,0,&size,NULL); - pclog("DeviceIoControl returns %i\n", (int) b); - ioctl_close();*/ -} - -static void ioctl_pause(void) -{ - if (!cdrom_drive) return; - if (ioctl_cd_state == CD_PLAYING) - ioctl_cd_state = CD_PAUSED; -// ioctl_open(0); -// DeviceIoControl(hIOCTL,IOCTL_CDROM_PAUSE_AUDIO,NULL,0,NULL,0,&size,NULL); -// ioctl_close(); -} - -static void ioctl_resume(void) -{ - if (!cdrom_drive) return; - if (ioctl_cd_state == CD_PAUSED) - ioctl_cd_state = CD_PLAYING; -// ioctl_open(0); -// DeviceIoControl(hIOCTL,IOCTL_CDROM_RESUME_AUDIO,NULL,0,NULL,0,&size,NULL); -// ioctl_close(); -} - -static void ioctl_stop(void) -{ - if (!cdrom_drive) return; - ioctl_cd_state = CD_STOPPED; -// ioctl_open(0); -// DeviceIoControl(hIOCTL,IOCTL_CDROM_STOP_AUDIO,NULL,0,NULL,0,&size,NULL); -// ioctl_close(); -} - -static void ioctl_seek(uint32_t pos) -{ - if (!cdrom_drive) return; - // ioctl_cd_state = CD_STOPPED; - // pclog("Seek %08X\n", pos); - ioctl_cd_pos = pos; - ioctl_cd_state = CD_STOPPED; -/* pos+=150; - CDROM_SEEK_AUDIO_MSF msf; - msf.F=(uint8_t)(pos%75); pos/=75; - msf.S=(uint8_t)(pos%60); pos/=60; - msf.M=(uint8_t)(pos); -// pclog("Seek to %02i:%02i:%02i\n",msf.M,msf.S,msf.F); - ioctl_open(0); - DeviceIoControl(hIOCTL,IOCTL_CDROM_SEEK_AUDIO_MSF,&msf,sizeof(msf),NULL,0,&size,NULL); - ioctl_close();*/ -} - -static int ioctl_ready(void) -{ - long size; - int temp; - CDROM_TOC ltoc; -// pclog("Ready? %i\n",cdrom_drive); - if (!cdrom_drive) return 0; - ioctl_open(0); - temp=DeviceIoControl(hIOCTL,IOCTL_CDROM_READ_TOC, NULL,0,<oc,sizeof(ltoc),&size,NULL); - ioctl_close(); - if (!temp) - return 0; - //pclog("ioctl_ready(): Drive opened successfully\n"); - //if ((cdrom_drive != old_cdrom_drive)) pclog("Drive has changed\n"); - if ((ltoc.TrackData[ltoc.LastTrack].Address[1] != toc.TrackData[toc.LastTrack].Address[1]) || - (ltoc.TrackData[ltoc.LastTrack].Address[2] != toc.TrackData[toc.LastTrack].Address[2]) || - (ltoc.TrackData[ltoc.LastTrack].Address[3] != toc.TrackData[toc.LastTrack].Address[3]) || - !tocvalid || (cdrom_drive != old_cdrom_drive)) - { - //pclog("ioctl_ready(): Disc or drive changed\n"); - ioctl_cd_state = CD_STOPPED; - /* pclog("Not ready %02X %02X %02X %02X %02X %02X %i\n",ltoc.TrackData[ltoc.LastTrack].Address[1],ltoc.TrackData[ltoc.LastTrack].Address[2],ltoc.TrackData[ltoc.LastTrack].Address[3], - toc.TrackData[ltoc.LastTrack].Address[1], toc.TrackData[ltoc.LastTrack].Address[2], toc.TrackData[ltoc.LastTrack].Address[3],tocvalid);*/ - // atapi_discchanged(); -/* ioctl_open(0); - temp=DeviceIoControl(hIOCTL,IOCTL_CDROM_READ_TOC, NULL,0,&toc,sizeof(toc),&size,NULL); - ioctl_close();*/ - if (cdrom_drive != old_cdrom_drive) - old_cdrom_drive = cdrom_drive; - return 1; - } -// pclog("IOCTL says ready\n"); -// pclog("ioctl_ready(): All is good\n"); - return 1; -} - -static int ioctl_get_last_block(unsigned char starttrack, int msf, int maxlen, int single) -{ - int len=4; - long size; - int c,d; - uint32_t temp; - CDROM_TOC lbtoc; - int lb=0; - if (!cdrom_drive) return 0; - ioctl_cd_state = CD_STOPPED; - // pclog("ioctl_readtoc(): IOCtl state now CD_STOPPED\n"); - ioctl_open(0); - DeviceIoControl(hIOCTL,IOCTL_CDROM_READ_TOC, NULL,0,&lbtoc,sizeof(lbtoc),&size,NULL); - ioctl_close(); - tocvalid=1; - for (c=d;c<=lbtoc.LastTrack;c++) - { - uint32_t address; - address = MSFtoLBA(toc.TrackData[c].Address[1],toc.TrackData[c].Address[2],toc.TrackData[c].Address[3]); - if (address > lb) - lb = address; - } - return lb; -} - -static int ioctl_medium_changed(void) -{ - long size; - int temp; - CDROM_TOC ltoc; - if (!cdrom_drive) return 0; /* This will be handled by the not ready handler instead. */ - ioctl_open(0); - temp=DeviceIoControl(hIOCTL,IOCTL_CDROM_READ_TOC, NULL,0,<oc,sizeof(ltoc),&size,NULL); - ioctl_close(); - if (!temp) - return 0; /* Drive empty, a not ready handler matter, not disc change. */ - if (!tocvalid || (cdrom_drive != old_cdrom_drive)) - { - ioctl_cd_state = CD_STOPPED; - toc = ltoc; - tocvalid = 1; - if (cdrom_drive != old_cdrom_drive) - old_cdrom_drive = cdrom_drive; - cdrom_capacity = ioctl_get_last_block(0, 0, 4096, 0); - if (cdrom_drive == old_cdrom_drive) - { - return 1; - } - else - { - return 0; - } - } - else - { - if ((ltoc.TrackData[ltoc.LastTrack].Address[1] != toc.TrackData[toc.LastTrack].Address[1]) || - (ltoc.TrackData[ltoc.LastTrack].Address[2] != toc.TrackData[toc.LastTrack].Address[2]) || - (ltoc.TrackData[ltoc.LastTrack].Address[3] != toc.TrackData[toc.LastTrack].Address[3])) - { - ioctl_cd_state = CD_STOPPED; - toc = ltoc; - cdrom_capacity = ioctl_get_last_block(0, 0, 4096, 0); - return 1; /* TOC mismatches. */ - } - } - return 0; /* None of the above, return 0. */ -} - -static uint8_t ioctl_getcurrentsubchannel(uint8_t *b, int msf) -{ - CDROM_SUB_Q_DATA_FORMAT insub; - SUB_Q_CHANNEL_DATA sub; - long size; - int pos=0; - if (!cdrom_drive) return 0; - - insub.Format = IOCTL_CDROM_CURRENT_POSITION; - ioctl_open(0); - DeviceIoControl(hIOCTL,IOCTL_CDROM_READ_Q_CHANNEL,&insub,sizeof(insub),&sub,sizeof(sub),&size,NULL); - ioctl_close(); - - if (ioctl_cd_state == CD_PLAYING || ioctl_cd_state == CD_PAUSED) - { - uint32_t cdpos = ioctl_cd_pos; - int track = get_track_nr(cdpos); - uint32_t track_address = toc.TrackData[track].Address[3] + - (toc.TrackData[track].Address[2] * 75) + - (toc.TrackData[track].Address[1] * 75 * 60); - - b[pos++] = sub.CurrentPosition.Control; - b[pos++] = track + 1; - b[pos++] = sub.CurrentPosition.IndexNumber; - - if (msf) - { - uint32_t dat = cdpos; - b[pos + 3] = (uint8_t)(dat % 75); dat /= 75; - b[pos + 2] = (uint8_t)(dat % 60); dat /= 60; - b[pos + 1] = (uint8_t)dat; - b[pos] = 0; - pos += 4; - dat = cdpos - track_address; - b[pos + 3] = (uint8_t)(dat % 75); dat /= 75; - b[pos + 2] = (uint8_t)(dat % 60); dat /= 60; - b[pos + 1] = (uint8_t)dat; - b[pos] = 0; - pos += 4; - } - else - { - b[pos++] = (cdpos >> 24) & 0xff; - b[pos++] = (cdpos >> 16) & 0xff; - b[pos++] = (cdpos >> 8) & 0xff; - b[pos++] = cdpos & 0xff; - cdpos -= track_address; - b[pos++] = (cdpos >> 24) & 0xff; - b[pos++] = (cdpos >> 16) & 0xff; - b[pos++] = (cdpos >> 8) & 0xff; - b[pos++] = cdpos & 0xff; - } - - if (ioctl_cd_state == CD_PLAYING) return 0x11; - return 0x12; - } - - b[pos++]=sub.CurrentPosition.Control; - b[pos++]=sub.CurrentPosition.TrackNumber; - b[pos++]=sub.CurrentPosition.IndexNumber; - - if (msf) - { - int c; - for (c = 0; c < 4; c++) - b[pos++] = sub.CurrentPosition.AbsoluteAddress[c]; - for (c = 0; c < 4; c++) - b[pos++] = sub.CurrentPosition.TrackRelativeAddress[c]; - } - else - { - uint32_t temp = MSFtoLBA(sub.CurrentPosition.AbsoluteAddress[1], sub.CurrentPosition.AbsoluteAddress[2], sub.CurrentPosition.AbsoluteAddress[3]); - b[pos++] = temp >> 24; - b[pos++] = temp >> 16; - b[pos++] = temp >> 8; - b[pos++] = temp; - temp = MSFtoLBA(sub.CurrentPosition.TrackRelativeAddress[1], sub.CurrentPosition.TrackRelativeAddress[2], sub.CurrentPosition.TrackRelativeAddress[3]); - b[pos++] = temp >> 24; - b[pos++] = temp >> 16; - b[pos++] = temp >> 8; - b[pos++] = temp; - } - - return 0x13; -} - -static void ioctl_eject(void) -{ - long size; - if (!cdrom_drive) return; - ioctl_cd_state = CD_STOPPED; - ioctl_open(0); - DeviceIoControl(hIOCTL,IOCTL_STORAGE_EJECT_MEDIA,NULL,0,NULL,0,&size,NULL); - ioctl_close(); -} - -static void ioctl_load(void) -{ - long size; - if (!cdrom_drive) return; - ioctl_cd_state = CD_STOPPED; - ioctl_open(0); - DeviceIoControl(hIOCTL,IOCTL_STORAGE_LOAD_MEDIA,NULL,0,NULL,0,&size,NULL); - ioctl_close(); - cdrom_capacity = ioctl_get_last_block(0, 0, 4096, 0); -} - -static int is_track_audio(uint32_t pos) -{ - int c; - int control = 0; - - if (!tocvalid) - return 0; - - // for (c = toc.FirstTrack; c <= toc.LastTrack; c++) - for (c = 0; c <= toc.LastTrack; c++) - { - uint32_t track_address = MSFtoLBA(toc.TrackData[c].Address[1],toc.TrackData[c].Address[2],toc.TrackData[c].Address[3]); - - // pclog("Track address: %i (%02X%02X%02X%02X), Position: %i\n", track_address, toc.TrackData[c].Address[0], toc.TrackData[c].Address[1], toc.TrackData[c].Address[2], toc.TrackData[c].Address[3], pos); - - if (track_address <= pos) - control = toc.TrackData[c].Control; - } - // pclog("Control: %i\n", control); - if ((control & 0xd) == 0) - { - return 1; - } - else if ((control & 0xd) == 1) - { - return 1; - } - else - { - return 0; - } -} - -static int ioctl_is_track_audio(uint32_t pos, int ismsf) -{ - if (ismsf) - { - int m = (pos >> 16) & 0xff; - int s = (pos >> 8) & 0xff; - int f = pos & 0xff; - pos = MSFtoLBA(m, s, f); - } - else - { - pos += 150; - } - return is_track_audio(pos); -} - -static int SCSICommand(const UCHAR *cdb, UCHAR *buf, uint32_t len) -{ - HANDLE fh; - DWORD ioctl_bytes; - DWORD out_size; - int ioctl_rv = 0; - UCHAR tbuf[65536]; - struct sptd_with_sense - { - SCSI_PASS_THROUGH_DIRECT s; - UCHAR sense[128]; - } sptd; - - memset(&sptd, 0, sizeof(sptd)); - sptd.s.Length = sizeof(sptd.s); - // sptd.s.CdbLength = sizeof(cdb); - sptd.s.CdbLength = 12; - sptd.s.DataIn = SCSI_IOCTL_DATA_IN; - sptd.s.TimeOutValue = 30; - sptd.s.DataBuffer = tbuf; - sptd.s.DataTransferLength = len; - sptd.s.SenseInfoLength = sizeof(sptd.sense); - sptd.s.SenseInfoOffset = offsetof(struct sptd_with_sense, sense); - - // memcpy(sptd.s.Cdb, cdb, sizeof(cdb)); - memcpy(sptd.s.Cdb, cdb, 12); - ioctl_rv = DeviceIoControl(hIOCTL, IOCTL_SCSI_PASS_THROUGH_DIRECT, &sptd, sizeof(sptd), &sptd, sizeof(sptd), &ioctl_bytes, NULL); - memcpy(buf, sptd.s.DataBuffer, len); - - return ioctl_rv; -} - -static void ioctl_read_capacity(uint8_t *b) -{ - const UCHAR cdb[] = { 0x25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - UCHAR buf[16]; - - ioctl_open(0); - - SCSICommand(cdb, buf, 16); - - memcpy(b, buf, 8); - - ioctl_close(); -} - -static void ioctl_read_subchannel(uint8_t *in_cdb, uint8_t *b) -{ - const UCHAR cdb[12]; - UCHAR buf[24]; - - ioctl_open(0); - - memcpy(cdb, in_cdb, 12); - SCSICommand(cdb, buf, 24); - - memcpy(b, buf, 24); - - ioctl_close(); -} - -static void ioctl_read_header(uint8_t *in_cdb, uint8_t *b) -{ - const UCHAR cdb[12]; - UCHAR buf[16]; - - ioctl_open(0); - - memcpy(cdb, in_cdb, 12); - SCSICommand(cdb, buf, 16); - - memcpy(b, buf, 8); - - ioctl_close(); -} - -static int ioctl_read_track_information(uint8_t *in_cdb, uint8_t *b) -{ - int maxlen = 0; - int len = 0; - - int ret = 0; - - const UCHAR cdb[12]; - UCHAR buf[65536]; - - maxlen = in_cdb[7]; - maxlen <<= 8; - maxlen |= in_cdb[8]; - - ioctl_open(0); - - memcpy(cdb, in_cdb, 12); - ret = SCSICommand(cdb, buf, 65535); - - if (!ret) - { - return 0; - } - - len = buf[0]; - len <<= 8; - len |= buf[1]; - len += 2; - - if (len > maxlen) - { - len = maxlen; - buf[0] = ((maxlen - 2) >> 8) * 0xff; - buf[1] = (maxlen - 2) & 0xff; - } - - memcpy(b, buf, len); - - ioctl_close(); - - return 1; -} - -static void ioctl_read_disc_information(uint8_t *b) -{ - const UCHAR cdb[] = { 0x51, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - UCHAR buf[68]; - - ioctl_open(0); - - SCSICommand(cdb, buf, 68); - - memcpy(b, buf, 34); - - ioctl_close(); -} - -static int SCSIReadCommon(const UCHAR *cdb_0, const UCHAR *cdb_1, const UCHAR *cdb_2, const UCHAR *cdb_4, uint8_t *b, UCHAR *buf) -{ - int ioctl_rv; - - ioctl_open(0); - - /* Fill the buffer with zeroes. */ - memset(b, 0, 2856); - - ioctl_rv = SCSICommand(cdb_0, buf, 2856); - memcpy(b, buf, 2648); - - /* Next, try to read RAW subchannel data. */ - ioctl_rv += SCSICommand(cdb_1, buf, 2856); - memcpy(b + 2648, buf + 2648, 96); - - /* Next, try to read Q subchannel data. */ - ioctl_rv += SCSICommand(cdb_2, buf, 2856); - memcpy(b + 2648 + 96, buf + 2648, 16); - - /* Next, try to read R - W subchannel data. */ - ioctl_rv += SCSICommand(cdb_4, buf, 2856); - memcpy(b + 2648 + 96 + 16, buf + 2648, 96); - - ioctl_close(); - - // pclog("rv: %i\n", ioctl_rv); - - return ioctl_rv; -} - -/* Direct SCSI read in MSF mode. */ -static int SCSIReadMSF(uint8_t *b, int sector) -{ - const UCHAR cdb_0[] = { 0xB9, 0, 0, ((sector >> 16) & 0xff), ((sector >> 8) & 0xff), (sector & 0xff), ((sector >> 16) & 0xff), ((sector >> 8) & 0xff), (sector & 0xff), 0xFC, 0, 0 }; - const UCHAR cdb_1[] = { 0xB9, 0, 0, ((sector >> 16) & 0xff), ((sector >> 8) & 0xff), (sector & 0xff), ((sector >> 16) & 0xff), ((sector >> 8) & 0xff), (sector & 0xff), 0xFC, 1, 0 }; - const UCHAR cdb_2[] = { 0xB9, 0, 0, ((sector >> 16) & 0xff), ((sector >> 8) & 0xff), (sector & 0xff), ((sector >> 16) & 0xff), ((sector >> 8) & 0xff), (sector & 0xff), 0xFC, 2, 0 }; - const UCHAR cdb_4[] = { 0xB9, 0, 0, ((sector >> 16) & 0xff), ((sector >> 8) & 0xff), (sector & 0xff), ((sector >> 16) & 0xff), ((sector >> 8) & 0xff), (sector & 0xff), 0xFC, 4, 0 }; - UCHAR buf[2856]; - - return SCSIReadCommon(cdb_0, cdb_1, cdb_2, cdb_4, b, buf); -} - -/* Direct SCSI read in LBA mode. */ -static void SCSIRead(uint8_t *b, int sector) -{ - const UCHAR cdb_0[] = { 0xBE, 0, (sector >> 24), ((sector >> 16) & 0xff), ((sector >> 8) & 0xff), (sector & 0xff), 0, 0, 1, 0xFC, 0, 0 }; - const UCHAR cdb_1[] = { 0xBE, 0, (sector >> 24), ((sector >> 16) & 0xff), ((sector >> 8) & 0xff), (sector & 0xff), 0, 0, 1, 0xFC, 1, 0 }; - const UCHAR cdb_2[] = { 0xBE, 0, (sector >> 24), ((sector >> 16) & 0xff), ((sector >> 8) & 0xff), (sector & 0xff), 0, 0, 1, 0xFC, 2, 0 }; - const UCHAR cdb_4[] = { 0xBE, 0, (sector >> 24), ((sector >> 16) & 0xff), ((sector >> 8) & 0xff), (sector & 0xff), 0, 0, 1, 0xFC, 4, 0 }; - UCHAR buf[2856]; - - SCSIReadCommon(cdb_0, cdb_1, cdb_2, cdb_4, b, buf); - return; -} - -static uint32_t msf_to_lba32(int lba) -{ - int m = (lba >> 16) & 0xff; - int s = (lba >> 8) & 0xff; - int f = lba & 0xff; - return (m * 60 * 75) + (s * 75) + f; -} - -static int ioctl_get_type(UCHAR *cdb, UCHAR *buf) -{ - int i = 0; - int ioctl_rv = 0; - - for (i = 2; i <= 5; i++) - { - cdb[1] = i << 2; - ioctl_rv = SCSICommand(cdb, buf, 2352); - if (ioctl_rv) - { - return i; - } - } - return 0; -} - -static int ioctl_sector_data_type(int sector, int ismsf) -{ - int ioctl_rv = 0; - const UCHAR cdb_lba[] = { 0xBE, 0, (sector >> 24), ((sector >> 16) & 0xff), ((sector >> 8) & 0xff), (sector & 0xff), 0, 0, 1, 0x10, 0, 0 }; - const UCHAR cdb_msf[] = { 0xB9, 0, 0, ((sector >> 16) & 0xff), ((sector >> 8) & 0xff), (sector & 0xff), ((sector >> 16) & 0xff), ((sector >> 8) & 0xff), (sector & 0xff), 0x10, 0, 0 }; - UCHAR buf[2352]; - - ioctl_open(0); - - if (ioctl_is_track_audio(sector, ismsf)) - { - return 1; - } - - if (ismsf) - { - ioctl_rv = ioctl_get_type(cdb_msf, buf); - } - else - { - ioctl_rv = ioctl_get_type(cdb_lba, buf); - } - - if (ioctl_rv) - { - ioctl_close(); - return ioctl_rv; - } - - if (ismsf) - { - sector = msf_to_lba32(sector); - if (sector < 150) - { - ioctl_close(); - return 0; - } - sector -= 150; - ioctl_rv = ioctl_get_type(cdb_lba, buf); - } - - ioctl_close(); - return ioctl_rv; -} - -static void ioctl_readsector_raw(uint8_t *b, int sector, int ismsf) -{ - if (!cdrom_drive) return; - if (ioctl_cd_state == CD_PLAYING) - return; - - if (ismsf) - { - if (!SCSIReadMSF(b, sector)) - { - sector = msf_to_lba32(sector); - if (sector < 150) - { - memset(b, 0, 2856); - return; - } - sector -= 150; - SCSIRead(b, sector); - } - } - else - { - SCSIRead(b, sector); - } -} - -static int ioctl_readtoc(unsigned char *b, unsigned char starttrack, int msf, int maxlen, int single) -{ - int len=4; - long size; - int c,d; - uint32_t temp; - if (!cdrom_drive) return 0; - ioctl_cd_state = CD_STOPPED; - ioctl_open(0); - DeviceIoControl(hIOCTL,IOCTL_CDROM_READ_TOC, NULL,0,&toc,sizeof(toc),&size,NULL); - ioctl_close(); - tocvalid=1; -// pclog("Read TOC done! %i\n",single); - b[2]=toc.FirstTrack; - b[3]=toc.LastTrack; - d=0; - for (c=0;c<=toc.LastTrack;c++) - { - if (toc.TrackData[c].TrackNumber>=starttrack) - { - d=c; - break; - } - } - b[2]=toc.TrackData[c].TrackNumber; - last_block = 0; - for (c=d;c<=toc.LastTrack;c++) - { - uint32_t address; - if ((len+8)>maxlen) break; -// pclog("Len %i max %i Track %02X - %02X %02X %i %i %i %i %08X\n",len,maxlen,toc.TrackData[c].TrackNumber,toc.TrackData[c].Adr,toc.TrackData[c].Control,toc.TrackData[c].Address[0],toc.TrackData[c].Address[1],toc.TrackData[c].Address[2],toc.TrackData[c].Address[3],MSFtoLBA(toc.TrackData[c].Address[1],toc.TrackData[c].Address[2],toc.TrackData[c].Address[3])); - b[len++]=0; /*Reserved*/ - b[len++]=(toc.TrackData[c].Adr<<4)|toc.TrackData[c].Control; - b[len++]=toc.TrackData[c].TrackNumber; - b[len++]=0; /*Reserved*/ - address = MSFtoLBA(toc.TrackData[c].Address[1],toc.TrackData[c].Address[2],toc.TrackData[c].Address[3]); - if (address > last_block) - last_block = address; - - if (msf) - { - b[len++]=toc.TrackData[c].Address[0]; - b[len++]=toc.TrackData[c].Address[1]; - b[len++]=toc.TrackData[c].Address[2]; - b[len++]=toc.TrackData[c].Address[3]; - } - else - { - temp=MSFtoLBA(toc.TrackData[c].Address[1],toc.TrackData[c].Address[2],toc.TrackData[c].Address[3]); - b[len++]=temp>>24; - b[len++]=temp>>16; - b[len++]=temp>>8; - b[len++]=temp; - } - if (single) break; - } - if (len > maxlen) - { - len = maxlen; - } - b[0] = (uint8_t)(((len-2) >> 8) & 0xff); - b[1] = (uint8_t)((len-2) & 0xff); -/* pclog("Table of Contents (%i bytes) : \n",size); - pclog("First track - %02X\n",toc.FirstTrack); - pclog("Last track - %02X\n",toc.LastTrack); - for (c=0;c<=toc.LastTrack;c++) - pclog("Track %02X - number %02X control %02X adr %02X address %02X %02X %02X %02X\n",c,toc.TrackData[c].TrackNumber,toc.TrackData[c].Control,toc.TrackData[c].Adr,toc.TrackData[c].Address[0],toc.TrackData[c].Address[1],toc.TrackData[c].Address[2],toc.TrackData[c].Address[3]); - for (c=0;c<=toc.LastTrack;c++) - pclog("Track %02X - number %02X control %02X adr %02X address %06X\n",c,toc.TrackData[c].TrackNumber,toc.TrackData[c].Control,toc.TrackData[c].Adr,MSFtoLBA(toc.TrackData[c].Address[1],toc.TrackData[c].Address[2],toc.TrackData[c].Address[3]));*/ - return len; -} - -static int ioctl_readtoc_session(unsigned char *b, int msf, int maxlen) -{ - int len=4; - int size; - uint32_t temp; - CDROM_READ_TOC_EX toc_ex; - CDROM_TOC_SESSION_DATA toc; - if (!cdrom_drive) return 0; - ioctl_cd_state = CD_STOPPED; - memset(&toc_ex,0,sizeof(toc_ex)); - memset(&toc,0,sizeof(toc)); - toc_ex.Format=CDROM_READ_TOC_EX_FORMAT_SESSION; - toc_ex.Msf=msf; - toc_ex.SessionTrack=0; - ioctl_open(0); - DeviceIoControl(hIOCTL,IOCTL_CDROM_READ_TOC_EX, &toc_ex,sizeof(toc_ex),&toc,sizeof(toc),(PDWORD)&size,NULL); - ioctl_close(); -// pclog("Read TOC session - %i %02X %02X %i %i %02X %02X %02X\n",size,toc.Length[0],toc.Length[1],toc.FirstCompleteSession,toc.LastCompleteSession,toc.TrackData[0].Adr,toc.TrackData[0].Control,toc.TrackData[0].TrackNumber); - b[2]=toc.FirstCompleteSession; - b[3]=toc.LastCompleteSession; - b[len++]=0; /*Reserved*/ - b[len++]=(toc.TrackData[0].Adr<<4)|toc.TrackData[0].Control; - b[len++]=toc.TrackData[0].TrackNumber; - b[len++]=0; /*Reserved*/ - if (msf) - { - b[len++]=toc.TrackData[0].Address[0]; - b[len++]=toc.TrackData[0].Address[1]; - b[len++]=toc.TrackData[0].Address[2]; - b[len++]=toc.TrackData[0].Address[3]; - } - else - { - temp=MSFtoLBA(toc.TrackData[0].Address[1],toc.TrackData[0].Address[2],toc.TrackData[0].Address[3]); - b[len++]=temp>>24; - b[len++]=temp>>16; - b[len++]=temp>>8; - b[len++]=temp; - } - - if (len > maxlen) - { - len = maxlen; - } - b[0] = ((len - 2) >> 8) & 0xff; - b[1] = (len - 2) & 0xff; - return len; -} - -static void ioctl_readtoc_raw(uint8_t *b, int msf, int maxlen) -{ - UCHAR cdb[12]; - UCHAR buf[65536]; - - int len = 0; - - ioctl_open(0); - - cdb[0] = 0x43; - cdb[1] = msf ? 2 : 0; - cdb[2] = 2; - cdb[3] = cdb[4] = cdb[5] = cdb[6] = 0; - cdb[7] = (maxlen >> 8) & 0xff; - cdb[8] = maxlen & 0xff; - cdb[9] = cdb[10] = cdb[11] = 0; - - SCSICommand(cdb, buf, 65535); - - len = buf[0]; - len <<= 8; - len |= buf[1]; - len += 2; - - memcpy(b, buf, len); - - ioctl_close(); -} - -#if 0 -static int ioctl_readtoc_raw(unsigned char *b, int maxlen) -{ - int len=4; - int size; - uint32_t temp; - int i; - int BytesRead = 0; - CDROM_READ_TOC_EX toc_ex; - CDROM_TOC_FULL_TOC_DATA toc; - if (!cdrom_drive) return 0; - ioctl_cd_state = CD_STOPPED; - memset(&toc_ex,0,sizeof(toc_ex)); - memset(&toc,0,sizeof(toc)); - toc_ex.Format=CDROM_READ_TOC_EX_FORMAT_FULL_TOC; - toc_ex.Msf=1; - toc_ex.SessionTrack=0; - ioctl_open(0); - DeviceIoControl(hIOCTL,IOCTL_CDROM_READ_TOC_EX, &toc_ex,sizeof(toc_ex),&toc,sizeof(toc),(PDWORD)&size,NULL); - ioctl_close(); -// pclog("Read TOC session - %i %02X %02X %i %i %02X %02X %02X\n",size,toc.Length[0],toc.Length[1],toc.FirstCompleteSession,toc.LastCompleteSession,toc.TrackData[0].Adr,toc.TrackData[0].Control,toc.TrackData[0].TrackNumber); - b[2]=toc.FirstCompleteSession; - b[3]=toc.LastCompleteSession; - - size -= sizeof(CDROM_TOC_FULL_TOC_DATA); - size /= sizeof(toc.Descriptors[0]); - - for (i = 0; i <= size; i++) - { - b[len++]=toc.Descriptors[i].SessionNumber; - b[len++]=(toc.Descriptors[i].Adr<<4)|toc.Descriptors[i].Control; - b[len++]=0; - b[len++]=toc.Descriptors[i].Reserved1; /*Reserved*/ - b[len++]=toc.Descriptors[i].MsfExtra[0]; - b[len++]=toc.Descriptors[i].MsfExtra[1]; - b[len++]=toc.Descriptors[i].MsfExtra[2]; - b[len++]=toc.Descriptors[i].Zero; - b[len++]=toc.Descriptors[i].Msf[0]; - b[len++]=toc.Descriptors[i].Msf[1]; - b[len++]=toc.Descriptors[i].Msf[2]; - } - - b[0] = (len >> 8) & 0xff; - b[1] = len & 0xff; - - return len; -} -#endif - -static uint32_t ioctl_size() -{ - uint8_t capacity_buffer[8]; - uint32_t capacity = 0; - ioctl_read_capacity(capacity_buffer); - capacity = ((uint32_t) capacity_buffer[0]) << 24; - capacity |= ((uint32_t) capacity_buffer[1]) << 16; - capacity |= ((uint32_t) capacity_buffer[2]) << 8; - capacity |= (uint32_t) capacity_buffer[3]; - return capacity + 1; - // return cdrom_capacity; -} - -static int ioctl_status() -{ - if (!(ioctl_ready) && (cdrom_drive <= 0)) - return CD_STATUS_EMPTY; - - switch(ioctl_cd_state) - { - case CD_PLAYING: - return CD_STATUS_PLAYING; - case CD_PAUSED: - return CD_STATUS_PAUSED; - case CD_STOPPED: - return CD_STATUS_STOPPED; - } -} - -void ioctl_reset() -{ - CDROM_TOC ltoc; - int temp; - long size; - - if (!cdrom_drive) - { - tocvalid = 0; - return; - } - - ioctl_open(0); - temp = DeviceIoControl(hIOCTL, IOCTL_CDROM_READ_TOC, NULL, 0, <oc, sizeof(ltoc), &size, NULL); - ioctl_close(); - - toc = ltoc; - tocvalid = 1; -} - -int ioctl_open(char d) -{ -// char s[8]; - if (!ioctl_inited) - { - sprintf(ioctl_path,"\\\\.\\%c:",d); - // pclog("Path is %s\n",ioctl_path); - tocvalid=0; - } -// pclog("Opening %s\n",ioctl_path); - // hIOCTL = CreateFile(/*"\\\\.\\g:"*/ioctl_path,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,0,NULL); - hIOCTL = CreateFile(ioctl_path, GENERIC_READ | GENERIC_WRITE, - FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL, NULL); - if (!hIOCTL) - { - //fatal("IOCTL"); - } - cdrom=&ioctl_cdrom; - if (!ioctl_inited) - { - ioctl_inited=1; - CloseHandle(hIOCTL); - hIOCTL = NULL; - } - return 0; -} - -void ioctl_close(void) -{ - if (hIOCTL) - { - CloseHandle(hIOCTL); - hIOCTL = NULL; - } -} - -static void ioctl_exit(void) -{ - ioctl_stop(); - ioctl_inited=0; - tocvalid=0; -} - -static CDROM ioctl_cdrom= -{ - ioctl_ready, - ioctl_medium_changed, - ioctl_readtoc, - ioctl_readtoc_session, - ioctl_readtoc_raw, - ioctl_getcurrentsubchannel, - ioctl_read_capacity, - ioctl_read_subchannel, - ioctl_read_header, - ioctl_read_disc_information, - ioctl_read_track_information, - ioctl_sector_data_type, - ioctl_readsector_raw, - ioctl_playaudio, - ioctl_seek, - ioctl_load, - ioctl_eject, - ioctl_pause, - ioctl_resume, - ioctl_size, - ioctl_status, - ioctl_is_track_audio, - ioctl_stop, - ioctl_exit -}; diff --git a/src/cdrom-ioctl.h b/src/cdrom-ioctl.h deleted file mode 100644 index 3c1f54981..000000000 --- a/src/cdrom-ioctl.h +++ /dev/null @@ -1,17 +0,0 @@ -/* Copyright holders: Sarah Walker, Tenshi - see COPYING for more details -*/ -#ifndef CDROM_IOCTL_H -#define CDROM_IOCTL_H - -/* this header file lists the functions provided by - various platform specific cdrom-ioctl files */ - -extern uint32_t cdrom_capacity; - -extern int ioctl_open(char d); -extern void ioctl_reset(); - -extern void ioctl_close(void); - -#endif /* ! CDROM_IOCTL_H */ diff --git a/src/cdrom-iso.c b/src/cdrom-iso.c deleted file mode 100644 index 7847f81af..000000000 --- a/src/cdrom-iso.c +++ /dev/null @@ -1,477 +0,0 @@ -/* Copyright holders: RichardG867, Tenshi - see COPYING for more details -*/ -/*ISO CD-ROM support*/ - -#include "ibm.h" -#include "cdrom.h" -#include "cdrom-iso.h" -#include - -static CDROM iso_cdrom; - -uint32_t last_block = 0; -static uint64_t image_size = 0; -static int iso_inited = 0; -char iso_path[1024]; -void iso_close(void); -static FILE* iso_image; -static int iso_changed = 0; - -static uint32_t lba = 0; - -static uint32_t iso_cd_pos = 0, iso_cd_end = 0; - -void iso_audio_callback(int16_t *output, int len) -{ - memset(output, 0, len * 2); - return; -} - -void iso_audio_stop() -{ - // pclog("iso_audio_stop stub\n"); -} - -static int get_track_nr(uint32_t pos) -{ - // pclog("get_track_nr stub\n"); - return 0; -} - -static void iso_playaudio(uint32_t pos, uint32_t len, int ismsf) -{ - // pclog("iso_playaudio stub\n"); - return; -} - -static void iso_pause(void) -{ - // pclog("iso_pause stub\n"); - return; -} - -static void iso_resume(void) -{ - // pclog("iso_resume stub\n"); - return; -} - -static void iso_stop(void) -{ - // pclog("iso_stop stub\n"); - return; -} - -static void iso_seek(uint32_t pos) -{ - // pclog("iso_seek stub\n"); - lba = pos; - return; -} - -static int iso_ready(void) -{ - if (strlen(iso_path) == 0) - { - return 0; - } - if (old_cdrom_drive != cdrom_drive) - { - // old_cdrom_drive = cdrom_drive; - return 1; - } - - if (iso_changed) - { - iso_changed = 0; - return 1; - } - - return 1; -} - -/* Always return 0, because there is no way to change the ISO without unmounting and remounting it. */ -static int iso_medium_changed(void) -{ - if (strlen(iso_path) == 0) - { - return 0; - } - - if (old_cdrom_drive != cdrom_drive) - { - old_cdrom_drive = cdrom_drive; - return 1; - } - - if (iso_changed) - { - iso_changed = 0; - return 1; - } - - return 0; -} - -static void lba_to_msf(uint8_t *buf, int lba) -{ - lba += 150; - buf[0] = (lba / 75) / 60; - buf[1] = (lba / 75) % 60; - buf[2] = lba % 75; -} - -static uint8_t iso_getcurrentsubchannel(uint8_t *b, int msf) -{ - long size; - int pos=0; - if (strlen(iso_path) == 0) - { - return 0; - } - - b[pos++]=0; - b[pos++]=0; - b[pos++]=0; - - int32_t temp = lba; - if (msf) - { - memset(&(b[pos]), 0, 8); - lba_to_msf(&(b[pos]), temp); - pos += 4; - lba_to_msf(&(b[pos]), temp); - pos += 4; - } - else - { - b[pos++] = temp >> 24; - b[pos++] = temp >> 16; - b[pos++] = temp >> 8; - b[pos++] = temp; - b[pos++] = temp >> 24; - b[pos++] = temp >> 16; - b[pos++] = temp >> 8; - b[pos++] = temp; - } - - return 0x13; -} - -static void iso_eject(void) -{ - // pclog("iso_eject stub\n"); -} - -static void iso_load(void) -{ - // pclog("iso_load stub\n"); -} - -static int iso_sector_data_type(int sector, int ismsf) -{ - return 2; /* Always Mode 1 */ -} - -static void iso_readsector_raw(uint8_t *b, int sector, int ismsf) -{ - uint32_t temp; - uint64_t file_pos = sector; - if (!cdrom_drive) return; - file_pos <<= 11; - memset(b, 0, 2856); - if (ismsf) - { - int m = (sector >> 16) & 0xff; - int s = (sector >> 8) & 0xff; - int f = sector & 0xff; - sector = (m * 60 * 75) + (s * 75) + f; - if (sector < 150) - { - memset(b, 0, 2856); - return; - } - sector -= 150; - } - iso_image = fopen(iso_path, "rb"); - fseeko64(iso_image, file_pos, SEEK_SET); - fread(b + 16, 2048, 1, iso_image); - fclose(iso_image); - - /* sync bytes */ - b[0] = 0; - memset(b + 1, 0xff, 10); - b[11] = 0; - b += 12; - lba_to_msf(b, sector); - b[3] = 1; /* mode 1 data */ - b += 4; - b += 2048; - memset(b, 0, 288); - b += 288; - memset(b, 0, 392); -} - -static int iso_readtoc(unsigned char *buf, unsigned char start_track, int msf, int maxlen, int single) -{ - uint8_t *q; - int len; - - if (start_track > 1 && start_track != 0xaa) - return -1; - q = buf + 2; - *q++ = 1; /* first session */ - *q++ = 1; /* last session */ - if (start_track <= 1) { - *q++ = 0; /* reserved */ - *q++ = 0x14; /* ADR, control */ - *q++ = 1; /* track number */ - *q++ = 0; /* reserved */ - if (msf) { - *q++ = 0; /* reserved */ - lba_to_msf(q, 0); - q += 3; - } else { - /* sector 0 */ - *q++ = 0; - *q++ = 0; - *q++ = 0; - *q++ = 0; - } - } - /* lead out track */ - *q++ = 0; /* reserved */ - *q++ = 0x16; /* ADR, control */ - *q++ = 0xaa; /* track number */ - *q++ = 0; /* reserved */ - last_block = image_size >> 11; - if (msf) { - *q++ = 0; /* reserved */ - lba_to_msf(q, last_block); - q += 3; - } else { - *q++ = last_block >> 24; - *q++ = last_block >> 16; - *q++ = last_block >> 8; - *q++ = last_block; - } - len = q - buf; - if (len > maxlen) - { - len = maxlen; - } - buf[0] = (uint8_t)(((len-2) >> 8) & 0xff); - buf[1] = (uint8_t)((len-2) & 0xff); - return len; -} - -static int iso_readtoc_session(unsigned char *buf, int msf, int maxlen) -{ - uint8_t *q; - - q = buf + 2; - *q++ = 1; /* first session */ - *q++ = 1; /* last session */ - - *q++ = 1; /* session number */ - *q++ = 0x14; /* data track */ - *q++ = 0; /* track number */ - *q++ = 0xa0; /* lead-in */ - *q++ = 0; /* min */ - *q++ = 0; /* sec */ - *q++ = 0; /* frame */ - *q++ = 0; - - if (maxlen < 12) - { - return maxlen; - } - return 12; -} - -static int iso_readtoc_raw(unsigned char *buf, int msf, int maxlen) -{ - uint8_t *q; - int len; - - q = buf + 2; - *q++ = 1; /* first session */ - *q++ = 1; /* last session */ - - *q++ = 1; /* session number */ - *q++ = 0x14; /* data track */ - *q++ = 0; /* track number */ - *q++ = 0xa0; /* lead-in */ - *q++ = 0; /* min */ - *q++ = 0; /* sec */ - *q++ = 0; /* frame */ - *q++ = 0; - *q++ = 1; /* first track */ - *q++ = 0x00; /* disk type */ - *q++ = 0x00; - - *q++ = 1; /* session number */ - *q++ = 0x14; /* data track */ - *q++ = 0; /* track number */ - *q++ = 0xa1; - *q++ = 0; /* min */ - *q++ = 0; /* sec */ - *q++ = 0; /* frame */ - *q++ = 0; - *q++ = 1; /* last track */ - *q++ = 0x00; - *q++ = 0x00; - - *q++ = 1; /* session number */ - *q++ = 0x14; /* data track */ - *q++ = 0; /* track number */ - *q++ = 0xa2; /* lead-out */ - *q++ = 0; /* min */ - *q++ = 0; /* sec */ - *q++ = 0; /* frame */ - last_block = image_size >> 11; - /* this is raw, must be msf */ - if (msf) - { - *q++ = 0; /* reserved */ - lba_to_msf(q, last_block); - q += 3; - } - else - { - *q++ = (last_block >> 24) & 0xff; - *q++ = (last_block >> 16) & 0xff; - *q++ = (last_block >> 8) & 0xff; - *q++ = last_block & 0xff; - } - - *q++ = 1; /* session number */ - *q++ = 0x14; /* ADR, control */ - *q++ = 0; /* track number */ - *q++ = 1; /* point */ - *q++ = 0; /* min */ - *q++ = 0; /* sec */ - *q++ = 0; /* frame */ - /* same here */ - if (msf) - { - *q++ = 0; /* reserved */ - lba_to_msf(q, 0); - q += 3; - } - else - { - *q++ = 0; - *q++ = 0; - *q++ = 0; - *q++ = 0; - } - - len = q - buf; - if (len > maxlen) - { - len = maxlen; - } - buf[0] = (uint8_t)(((len-2) >> 8) & 0xff); - buf[1] = (uint8_t)((len-2) & 0xff); - return len; -} - -static uint32_t iso_size() -{ - uint64_t iso_size; - - iso_image = fopen(iso_path, "rb"); - fseeko64(iso_image, 0, SEEK_END); - iso_size = ftello64(iso_image); - iso_size >>= 11; - fclose(iso_image); - - return (uint32_t) (iso_size); -} - -static int iso_status() -{ - if (!(iso_ready()) && (cdrom_drive != 200)) return CD_STATUS_EMPTY; - - return CD_STATUS_DATA_ONLY; -} - -void iso_reset() -{ -} - -int iso_open(char *fn) -{ - struct stat st; - - if (strcmp(fn, iso_path) != 0) - { - iso_changed = 1; - } - /* Make sure iso_changed stays when changing from ISO to another ISO. */ - if (!iso_inited && (cdrom_drive != 200)) iso_changed = 0; - if (!iso_inited || iso_changed) - { - sprintf(iso_path, "%s", fn); - // pclog("Path is %s\n", iso_path); - } - iso_image = fopen(iso_path, "rb"); - cdrom = &iso_cdrom; - if (!iso_inited || iso_changed) - { - if (!iso_inited) iso_inited = 1; - fclose(iso_image); - } - - stat(iso_path, &st); - image_size = st.st_size; - - return 0; -} - -void iso_close(void) -{ - if (iso_image) fclose(iso_image); - memset(iso_path, 0, 1024); -} - -static void iso_exit(void) -{ - // iso_stop(); - iso_inited = 0; -} - -static int iso_is_track_audio(uint32_t pos, int ismsf) -{ - return 0; -} - -static CDROM iso_cdrom = -{ - iso_ready, - iso_medium_changed, - iso_readtoc, - iso_readtoc_session, - iso_readtoc_raw, - iso_getcurrentsubchannel, - NULL, - NULL, - NULL, - NULL, - NULL, - iso_sector_data_type, - iso_readsector_raw, - iso_playaudio, - iso_seek, - iso_load, - iso_eject, - iso_pause, - iso_resume, - iso_size, - iso_status, - iso_is_track_audio, - iso_stop, - iso_exit -}; diff --git a/src/cdrom-iso.h b/src/cdrom-iso.h deleted file mode 100644 index 4dbcfca2e..000000000 --- a/src/cdrom-iso.h +++ /dev/null @@ -1,19 +0,0 @@ -/* Copyright holders: RichardG867, Tenshi - see COPYING for more details -*/ -#ifndef CDROM_ISO_H -#define CDROM_ISO_H - -/* this header file lists the functions provided by - various platform specific cdrom-ioctl files */ - -extern uint32_t last_block; - -extern char iso_path[1024]; - -extern int iso_open(char *fn); -extern void iso_reset(); - -extern void iso_close(void); - -#endif /* ! CDROM_ISO_H */ diff --git a/src/cdrom-null.c b/src/cdrom-null.c deleted file mode 100644 index 76ec0ab3c..000000000 --- a/src/cdrom-null.c +++ /dev/null @@ -1,153 +0,0 @@ -/* Copyright holders: Sarah Walker - see COPYING for more details -*/ -#include "ibm.h" -#include "cdrom.h" -#include "cdrom-ioctl.h" - -int cdrom_drive; - -static CDROM null_cdrom; - -void cdrom_null_audio_callback(int16_t *output, int len) -{ - memset(output, 0, len * 2); -} - -void cdrom_null_audio_stop() -{ -} - -static void null_playaudio(uint32_t pos, uint32_t len, int ismsf) -{ -} - -static void null_pause(void) -{ -} - -static void null_resume(void) -{ -} - -static void null_stop(void) -{ -} - -static void null_seek(uint32_t pos) -{ -} - -static int null_ready(void) -{ - return 0; -} - -/* Always return 0, the contents of a null CD-ROM drive never change. */ -static int null_medium_changed(void) -{ - return 0; -} - -static uint8_t null_getcurrentsubchannel(uint8_t *b, int msf) -{ - return 0x13; -} - -static void null_eject(void) -{ -} - -static void null_load(void) -{ -} - -static int null_sector_data_type(int sector, int ismsf) -{ - return 0; -} - -static void null_readsector_raw(uint8_t *b, int sector, int ismsf) -{ -} - -static int null_read_track_information(uint8_t *in_cdb, uint8_t *b) -{ - return 0; -} - -static int null_readtoc(unsigned char *b, unsigned char starttrack, int msf, int maxlen, int single) -{ - return 0; -} - -static int null_readtoc_session(unsigned char *b, int msf, int maxlen) -{ - return 0; -} - -static int null_readtoc_raw(unsigned char *b, int msf, int maxlen) -{ - return 0; -} - -static uint32_t null_size() -{ - return 0; -} - -static int null_status() -{ - return CD_STATUS_EMPTY; -} - -void cdrom_null_reset() -{ -} - -int cdrom_null_open(char d) -{ - cdrom = &null_cdrom; - return 0; -} - -void null_close(void) -{ -} - -static void null_exit(void) -{ -} - -static int null_is_track_audio(uint32_t pos, int ismsf) -{ - return 0; -} - -static CDROM null_cdrom = -{ - null_ready, - null_medium_changed, - null_readtoc, - null_readtoc_session, - null_readtoc_raw, - null_getcurrentsubchannel, - NULL, - NULL, - NULL, - NULL, - NULL, - null_sector_data_type, - null_readsector_raw, - null_playaudio, - null_seek, - null_load, - null_eject, - null_pause, - null_resume, - null_size, - null_status, - null_is_track_audio, - null_stop, - null_exit -}; diff --git a/src/cdrom-null.h b/src/cdrom-null.h deleted file mode 100644 index 6900f3d23..000000000 --- a/src/cdrom-null.h +++ /dev/null @@ -1,14 +0,0 @@ -/* Copyright holders: Sarah Walker - see COPYING for more details -*/ -#ifndef CDROM_IOCTL_H -#define CDROM_IOCTL_H - -/* this header file lists the functions provided by - various platform specific cdrom-ioctl files */ - -extern int cdrom_null_open(char d); -extern void cdrom_null_reset(); -extern void null_close(); - -#endif /* ! CDROM_IOCTL_H */ diff --git a/src/cdrom.c b/src/cdrom.c new file mode 100644 index 000000000..4f81e253c --- /dev/null +++ b/src/cdrom.c @@ -0,0 +1,3849 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Implementation of the CD-ROM drive with SCSI(-like) + * commands, for both ATAPI and SCSI usage. + * + * Version: @(#)cdrom.c 1.0.1 2017/06/03 + * + * Author: Miran Grca, + * Copyright 2016-2017 Miran Grca. + */ +#include +#include +#include +#include +#include + +#include "86box.h" +#include "cdrom.h" +#include "ibm.h" +#include "ide.h" +#include "piix.h" +#include "scsi.h" +#include "timer.h" +#include "win/plat_iodev.h" + +/* Bits of 'status' */ +#define ERR_STAT 0x01 +#define DRQ_STAT 0x08 /* Data request */ +#define DSC_STAT 0x10 +#define SERVICE_STAT 0x10 +#define READY_STAT 0x40 +#define BUSY_STAT 0x80 + +/* Bits of 'error' */ +#define ABRT_ERR 0x04 /* Command aborted */ +#define MCR_ERR 0x08 /* Media change request */ + +#define MODE_SELECT_PHASE_IDLE 0 +#define MODE_SELECT_PHASE_HEADER 1 +#define MODE_SELECT_PHASE_BLOCK_DESC 2 +#define MODE_SELECT_PHASE_PAGE_HEADER 3 +#define MODE_SELECT_PHASE_PAGE 4 + +cdrom_t cdrom[CDROM_NUM]; +cdrom_drive_t cdrom_drives[CDROM_NUM]; +uint8_t atapi_cdrom_drives[8] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; +uint8_t scsi_cdrom_drives[16][8] = { { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF } }; + +#ifdef __MSC__ +# pragma pack(push,1) +static struct +#else +static struct __attribute__((__packed__)) +#endif +{ + uint8_t opcode; + uint8_t polled; + uint8_t reserved2[2]; + uint8_t class; + uint8_t reserved3[2]; + uint16_t len; + uint8_t control; +} *gesn_cdb; +#ifdef __MSC__ +# pragma pack(pop) +#endif + +#ifdef __MSC__ +# pragma pack(push,1) +static struct +#else +static struct __attribute__((__packed__)) +#endif +{ + uint16_t len; + uint8_t notification_class; + uint8_t supported_events; +} *gesn_event_header; +#ifdef __MSC__ +# pragma pack(pop) +#endif + +/* Table of all SCSI commands and their flags, needed for the new disc change / not ready handler. */ +uint8_t cdrom_command_flags[0x100] = +{ + IMPLEMENTED | CHECK_READY | NONDATA, + IMPLEMENTED | ALLOW_UA | NONDATA | SCSI_ONLY, + 0, + IMPLEMENTED | ALLOW_UA, + 0, 0, 0, 0, + IMPLEMENTED | CHECK_READY, + 0, 0, + IMPLEMENTED | CHECK_READY | NONDATA, + 0, 0, 0, 0, 0, 0, + IMPLEMENTED | ALLOW_UA, + IMPLEMENTED | CHECK_READY | NONDATA | SCSI_ONLY, + 0, + IMPLEMENTED, + 0, 0, 0, 0, + IMPLEMENTED, + IMPLEMENTED | CHECK_READY, + 0, 0, + IMPLEMENTED | CHECK_READY, + 0, 0, 0, 0, 0, 0, + IMPLEMENTED | CHECK_READY, + 0, 0, + IMPLEMENTED | CHECK_READY, + 0, 0, + IMPLEMENTED | CHECK_READY | NONDATA, + 0, 0, 0, + IMPLEMENTED | CHECK_READY | NONDATA | SCSI_ONLY, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, + IMPLEMENTED | CHECK_READY, + IMPLEMENTED | CHECK_READY, /* Read TOC - can get through UNIT_ATTENTION, per VIDE-CDD.SYS + NOTE: The ATAPI reference says otherwise, but I think this is a question of + interpreting things right - the UNIT ATTENTION condition we have here + is a tradition from not ready to ready, by definition the drive + eventually becomes ready, make the condition go away. */ + IMPLEMENTED | CHECK_READY, + IMPLEMENTED | CHECK_READY, + IMPLEMENTED | ALLOW_UA, + IMPLEMENTED | CHECK_READY, + IMPLEMENTED | CHECK_READY, + 0, + IMPLEMENTED | ALLOW_UA, + IMPLEMENTED | CHECK_READY, + 0, 0, + IMPLEMENTED | CHECK_READY, + 0, 0, + IMPLEMENTED | CHECK_READY, + IMPLEMENTED | CHECK_READY, + 0, 0, + IMPLEMENTED, + 0, 0, 0, 0, + IMPLEMENTED, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + IMPLEMENTED | CHECK_READY, + 0, 0, + IMPLEMENTED | CHECK_READY, + 0, 0, 0, 0, + IMPLEMENTED | CHECK_READY, + 0, + IMPLEMENTED | CHECK_READY | NONDATA | SCSI_ONLY, + 0, 0, 0, 0, + IMPLEMENTED | CHECK_READY | ATAPI_ONLY, + 0, 0, 0, + IMPLEMENTED | CHECK_READY | ATAPI_ONLY, + IMPLEMENTED | CHECK_READY, + IMPLEMENTED | CHECK_READY, + IMPLEMENTED, + IMPLEMENTED | CHECK_READY, + IMPLEMENTED, + IMPLEMENTED | CHECK_READY, + IMPLEMENTED | CHECK_READY, + 0, 0, + IMPLEMENTED | CHECK_READY | SCSI_ONLY, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + IMPLEMENTED | CHECK_READY | SCSI_ONLY, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + IMPLEMENTED | SCSI_ONLY, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +uint64_t cdrom_mode_sense_page_flags[CDROM_NUM] = { (1LL << GPMODE_R_W_ERROR_PAGE) | (1LL << GPMODE_CDROM_PAGE) | (1LL << GPMODE_CDROM_AUDIO_PAGE) | (1LL << GPMODE_CAPABILITIES_PAGE) | (1LL << GPMODE_ALL_PAGES), + (1LL << GPMODE_R_W_ERROR_PAGE) | (1LL << GPMODE_CDROM_PAGE) | (1LL << GPMODE_CDROM_AUDIO_PAGE) | (1LL << GPMODE_CAPABILITIES_PAGE) | (1LL << GPMODE_ALL_PAGES), + (1LL << GPMODE_R_W_ERROR_PAGE) | (1LL << GPMODE_CDROM_PAGE) | (1LL << GPMODE_CDROM_AUDIO_PAGE) | (1LL << GPMODE_CAPABILITIES_PAGE) | (1LL << GPMODE_ALL_PAGES), + (1LL << GPMODE_R_W_ERROR_PAGE) | (1LL << GPMODE_CDROM_PAGE) | (1LL << GPMODE_CDROM_AUDIO_PAGE) | (1LL << GPMODE_CAPABILITIES_PAGE) | (1LL << GPMODE_ALL_PAGES) }; + +const uint8_t cdrom_mode_sense_pages_default[CDROM_NUM][0x40][0x40] = +{ + { { 0, 0 }, + { GPMODE_R_W_ERROR_PAGE, 6, 0, 5, 0, 0, 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { GPMODE_CDROM_PAGE, 6, 0, 1, 0, 60, 0, 75 }, + { 0x8E, 0xE, 4, 0, 0, 0, 0, 75, 1, 0xFF, 2, 0xFF, 0, 0, 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { GPMODE_CAPABILITIES_PAGE, 0x12, 0, 0, 1, 0, 0, 0, 0x02, 0xC2, 0, 2, 0, 0, 0x02, 0xC2, 0, 0, 0, 0 } }, + { { 0, 0 }, + { GPMODE_R_W_ERROR_PAGE, 6, 0, 5, 0, 0, 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { GPMODE_CDROM_PAGE, 6, 0, 1, 0, 60, 0, 75 }, + { 0x8E, 0xE, 4, 0, 0, 0, 0, 75, 1, 0xFF, 2, 0xFF, 0, 0, 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { GPMODE_CAPABILITIES_PAGE, 0x12, 0, 0, 1, 0, 0, 0, 0x02, 0xC2, 0, 2, 0, 0, 0x02, 0xC2, 0, 0, 0, 0 } }, + { { 0, 0 }, + { GPMODE_R_W_ERROR_PAGE, 6, 0, 5, 0, 0, 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { GPMODE_CDROM_PAGE, 6, 0, 1, 0, 60, 0, 75 }, + { 0x8E, 0xE, 4, 0, 0, 0, 0, 75, 1, 0xFF, 2, 0xFF, 0, 0, 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { GPMODE_CAPABILITIES_PAGE, 0x12, 0, 0, 1, 0, 0, 0, 0x02, 0xC2, 0, 2, 0, 0, 0x02, 0xC2, 0, 0, 0, 0 } }, + { { 0, 0 }, + { GPMODE_R_W_ERROR_PAGE, 6, 0, 5, 0, 0, 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { GPMODE_CDROM_PAGE, 6, 0, 1, 0, 60, 0, 75 }, + { 0x8E, 0xE, 4, 0, 0, 0, 0, 75, 1, 0xFF, 2, 0xFF, 0, 0, 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { GPMODE_CAPABILITIES_PAGE, 0x12, 0, 0, 1, 0, 0, 0, 0x02, 0xC2, 0, 2, 0, 0, 0x02, 0xC2, 0, 0, 0, 0 } } +}; + +uint8_t cdrom_mode_sense_pages_changeable[CDROM_NUM][0x40][0x40] = +{ + { { 0, 0 }, + { GPMODE_R_W_ERROR_PAGE, 6, 0, 5, 0, 0, 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { GPMODE_CDROM_PAGE, 6, 0, 1, 0, 60, 0, 75 }, + { 0x8E, 0xE, 4, 0, 0, 0, 0, 75, 1, 0xFF, 2, 0xFF, 0, 0, 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { GPMODE_CAPABILITIES_PAGE, 0x12, 0, 0, 1, 0, 0, 0, 0x02, 0xC2, 0, 2, 0, 0, 0x02, 0xC2, 0, 0, 0, 0 } }, + { { 0, 0 }, + { GPMODE_R_W_ERROR_PAGE, 6, 0, 5, 0, 0, 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { GPMODE_CDROM_PAGE, 6, 0, 1, 0, 60, 0, 75 }, + { 0x8E, 0xE, 4, 0, 0, 0, 0, 75, 1, 0xFF, 2, 0xFF, 0, 0, 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { GPMODE_CAPABILITIES_PAGE, 0x12, 0, 0, 1, 0, 0, 0, 0x02, 0xC2, 0, 2, 0, 0, 0x02, 0xC2, 0, 0, 0, 0 } }, + { { 0, 0 }, + { GPMODE_R_W_ERROR_PAGE, 6, 0, 5, 0, 0, 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { GPMODE_CDROM_PAGE, 6, 0, 1, 0, 60, 0, 75 }, + { 0x8E, 0xE, 4, 0, 0, 0, 0, 75, 1, 0xFF, 2, 0xFF, 0, 0, 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { GPMODE_CAPABILITIES_PAGE, 0x12, 0, 0, 1, 0, 0, 0, 0x02, 0xC2, 0, 2, 0, 0, 0x02, 0xC2, 0, 0, 0, 0 } }, + { { 0, 0 }, + { GPMODE_R_W_ERROR_PAGE, 6, 0, 5, 0, 0, 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { GPMODE_CDROM_PAGE, 6, 0, 1, 0, 60, 0, 75 }, + { 0x8E, 0xE, 4, 0, 0, 0, 0, 75, 1, 0xFF, 2, 0xFF, 0, 0, 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { GPMODE_CAPABILITIES_PAGE, 0x12, 0, 0, 1, 0, 0, 0, 0x02, 0xC2, 0, 2, 0, 0, 0x02, 0xC2, 0, 0, 0, 0 } } +}; + +uint8_t cdrom_mode_sense_pages_saved[CDROM_NUM][0x40][0x40] = +{ + { { 0, 0 }, + { GPMODE_R_W_ERROR_PAGE, 6, 0, 5, 0, 0, 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { GPMODE_CDROM_PAGE, 6, 0, 1, 0, 60, 0, 75 }, + { 0x8E, 0xE, 4, 0, 0, 0, 0, 75, 1, 0xFF, 2, 0xFF, 0, 0, 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { GPMODE_CAPABILITIES_PAGE, 0x12, 0, 0, 1, 0, 0, 0, 0x02, 0xC2, 0, 2, 0, 0, 0x02, 0xC2, 0, 0, 0, 0 } }, + { { 0, 0 }, + { GPMODE_R_W_ERROR_PAGE, 6, 0, 5, 0, 0, 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { GPMODE_CDROM_PAGE, 6, 0, 1, 0, 60, 0, 75 }, + { 0x8E, 0xE, 4, 0, 0, 0, 0, 75, 1, 0xFF, 2, 0xFF, 0, 0, 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { GPMODE_CAPABILITIES_PAGE, 0x12, 0, 0, 1, 0, 0, 0, 0x02, 0xC2, 0, 2, 0, 0, 0x02, 0xC2, 0, 0, 0, 0 } }, + { { 0, 0 }, + { GPMODE_R_W_ERROR_PAGE, 6, 0, 5, 0, 0, 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { GPMODE_CDROM_PAGE, 6, 0, 1, 0, 60, 0, 75 }, + { 0x8E, 0xE, 4, 0, 0, 0, 0, 75, 1, 0xFF, 2, 0xFF, 0, 0, 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { GPMODE_CAPABILITIES_PAGE, 0x12, 0, 0, 1, 0, 0, 0, 0x02, 0xC2, 0, 2, 0, 0, 0x02, 0xC2, 0, 0, 0, 0 } }, + { { 0, 0 }, + { GPMODE_R_W_ERROR_PAGE, 6, 0, 5, 0, 0, 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { GPMODE_CDROM_PAGE, 6, 0, 1, 0, 60, 0, 75 }, + { 0x8E, 0xE, 4, 0, 0, 0, 0, 75, 1, 0xFF, 2, 0xFF, 0, 0, 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { GPMODE_CAPABILITIES_PAGE, 0x12, 0, 0, 1, 0, 0, 0, 0x02, 0xC2, 0, 2, 0, 0, 0x02, 0xC2, 0, 0, 0, 0 } } +}; + +int cdrom_do_log = 0; + +void cdrom_log(const char *format, ...) +{ +#ifdef ENABLE_CDROM_LOG + if (cdrom_do_log) + { + va_list ap; + va_start(ap, format); + vprintf(format, ap); + va_end(ap); + fflush(stdout); + } +#endif +} + +int cdrom_mode_select_terminate(uint8_t id, int force); + +int find_cdrom_for_channel(uint8_t channel) +{ + uint8_t i = 0; + + for (i = 0; i < CDROM_NUM; i++) + { + if (((cdrom_drives[i].bus_type == CDROM_BUS_ATAPI_PIO_ONLY) || (cdrom_drives[i].bus_type == CDROM_BUS_ATAPI_PIO_AND_DMA)) && (cdrom_drives[i].ide_channel == channel)) + { + return i; + } + } + return 0xff; +} + +void cdrom_init(int id, int cdb_len_setting); + +void build_atapi_cdrom_map() +{ + uint8_t i = 0; + + memset(atapi_cdrom_drives, 0xff, 8); + + for (i = 0; i < 8; i++) + { + atapi_cdrom_drives[i] = find_cdrom_for_channel(i); + if (atapi_cdrom_drives[i] != 0xff) + { + cdrom_init(atapi_cdrom_drives[i], 12); + } + } +} + +int find_cdrom_for_scsi_id(uint8_t scsi_id, uint8_t scsi_lun) +{ + uint8_t i = 0; + + for (i = 0; i < CDROM_NUM; i++) + { + if ((cdrom_drives[i].bus_type == CDROM_BUS_SCSI) && (cdrom_drives[i].scsi_device_id == scsi_id) && (cdrom_drives[i].scsi_device_lun == scsi_lun)) + { + return i; + } + } + return 0xff; +} + +void build_scsi_cdrom_map() +{ + uint8_t i = 0; + uint8_t j = 0; + + for (i = 0; i < 16; i++) + { + memset(scsi_cdrom_drives[i], 0xff, 8); + } + + for (i = 0; i < 16; i++) + { + for (j = 0; j < 8; j++) + { + scsi_cdrom_drives[i][j] = find_cdrom_for_scsi_id(i, j); + if (scsi_cdrom_drives[i][j] != 0xff) + { + cdrom_init(scsi_cdrom_drives[i][j], 12); + } + } + } +} + +void cdrom_set_cdb_len(int id, int cdb_len) +{ + cdrom[id].cdb_len = cdb_len; +} + +void cdrom_reset_cdb_len(int id) +{ + cdrom[id].cdb_len = cdrom[id].cdb_len_setting ? 16 : 12; +} + +void cdrom_set_signature(int id) +{ + if (id >= CDROM_NUM) + { + return; + } + cdrom[id].phase = 1; + cdrom[id].request_length = 0xEB14; +} + +void cdrom_init(int id, int cdb_len_setting) +{ + if (id >= CDROM_NUM) + { + return; + } + memset(&(cdrom[id]), 0, sizeof(cdrom_t)); + cdrom[id].requested_blocks = 1; + if (cdb_len_setting <= 1) + { + cdrom[id].cdb_len_setting = cdb_len_setting; + } + cdrom_reset_cdb_len(id); + cdrom_mode_select_terminate(id, 1); + cdrom[id].cd_status = CD_STATUS_EMPTY; + cdrom[id].sense[0] = 0xf0; + cdrom[id].sense[7] = 10; + cdrom_drives[id].bus_mode = 0; + if (cdrom_drives[id].bus_type > CDROM_BUS_ATAPI_PIO_AND_DMA) + { + cdrom_drives[id].bus_mode |= 2; + } + if (cdrom_drives[id].bus_type < CDROM_BUS_SCSI) + { + cdrom_drives[id].bus_mode |= 1; + } + cdrom_log("CD-ROM %i: Bus type %i, bus mode %i\n", id, cdrom_drives[id].bus_type, cdrom_drives[id].bus_mode); + if (cdrom_drives[id].bus_type < CDROM_BUS_SCSI) + { + cdrom_set_signature(id); + cdrom_drives[id].max_blocks_at_once = 1; + } + else + { + cdrom_drives[id].max_blocks_at_once = 85; + } + cdrom[id].status = READY_STAT | DSC_STAT; + cdrom[id].pos = 0; + cdrom[id].packet_status = 0xff; + cdrom_sense_key = cdrom_asc = cdrom_ascq = cdrom[id].unit_attention = 0; + cdrom[id].cdb_len_setting = 0; + cdrom[id].cdb_len = 12; +} + +int cdrom_supports_pio(int id) +{ + return (cdrom_drives[id].bus_mode & 1); +} + +int cdrom_supports_dma(int id) +{ + return (cdrom_drives[id].bus_mode & 2); +} + +/* Returns: 0 for none, 1 for PIO, 2 for DMA. */ +int cdrom_current_mode(int id) +{ + if (!cdrom_supports_pio(id) && !cdrom_supports_dma(id)) + { + return 0; + } + if (cdrom_supports_pio(id) && !cdrom_supports_dma(id)) + { + return 1; + } + if (!cdrom_supports_pio(id) && cdrom_supports_dma(id)) + { + return 2; + } + if (cdrom_supports_pio(id) && cdrom_supports_dma(id)) + { + return (cdrom[id].features & 1) ? 2 : 1; + } + + return 0; +} + +/* Translates ATAPI status (ERR_STAT flag) to SCSI status. */ +int cdrom_CDROM_PHASE_to_scsi(uint8_t id) +{ + if (cdrom[id].status & ERR_STAT) + { + return SCSI_STATUS_CHECK_CONDITION; + } + else + { + return SCSI_STATUS_OK; + } +} + +/* Translates ATAPI phase (DRQ, I/O, C/D) to SCSI phase (MSG, C/D, I/O). */ +int cdrom_atapi_phase_to_scsi(uint8_t id) +{ + if (cdrom[id].status & 8) + { + switch (cdrom[id].phase & 3) + { + case 0: + return 0; + case 1: + return 2; + case 2: + return 1; + case 3: + return 7; + } + } + else + { + if ((cdrom[id].phase & 3) == 3) + { + return 3; + } + else + { + /* Translate reserved ATAPI phase to reserved SCSI phase. */ + return 4; + } + } + + return 0; +} + +int cdrom_lba_to_msf_accurate(int lba) +{ + int temp_pos; + int m, s, f; + + temp_pos = lba + 150; + f = temp_pos % 75; + temp_pos -= f; + temp_pos /= 75; + s = temp_pos % 60; + temp_pos -= s; + temp_pos /= 60; + m = temp_pos; + + return ((m << 16) | (s << 8) | f); +} + +uint32_t cdrom_mode_sense_get_channel(uint8_t id, int channel) +{ + return cdrom_mode_sense_pages_saved[id][GPMODE_CDROM_AUDIO_PAGE][channel ? 10 : 8]; +} + +uint32_t cdrom_mode_sense_get_volume(uint8_t id, int channel) +{ + return cdrom_mode_sense_pages_saved[id][GPMODE_CDROM_AUDIO_PAGE][channel ? 11 : 9]; +} + +void cdrom_mode_sense_load(uint8_t id) +{ + FILE *f; + switch(id) + { + case 0: + f = _wfopen(nvr_concat(L"cdrom_1_mode_sense.bin"), L"rb"); + break; + case 1: + f = _wfopen(nvr_concat(L"cdrom_2_mode_sense.bin"), L"rb"); + break; + case 2: + f = _wfopen(nvr_concat(L"cdrom_3_mode_sense.bin"), L"rb"); + break; + case 3: + f = _wfopen(nvr_concat(L"cdrom_4_mode_sense.bin"), L"rb"); + break; + default: + return; + } + if (!f) + { + return; + } + fread(cdrom_mode_sense_pages_saved[id][GPMODE_CDROM_AUDIO_PAGE], 1, 0x10, f); + fclose(f); +} + +void cdrom_mode_sense_save(uint8_t id) +{ + FILE *f; + switch(id) + { + case 0: + f = _wfopen(nvr_concat(L"cdrom_1_mode_sense.bin"), L"wb"); + break; + case 1: + f = _wfopen(nvr_concat(L"cdrom_2_mode_sense.bin"), L"wb"); + break; + case 2: + f = _wfopen(nvr_concat(L"cdrom_3_mode_sense.bin"), L"wb"); + break; + case 3: + f = _wfopen(nvr_concat(L"cdrom_4_mode_sense.bin"), L"wb"); + break; + default: + return; + } + if (!f) + { + return; + } + fwrite(cdrom_mode_sense_pages_saved[id][GPMODE_CDROM_AUDIO_PAGE], 1, 0x10, f); + fclose(f); +} + +int cdrom_mode_select_init(uint8_t id, uint8_t command, uint16_t pl_length, uint8_t do_save) +{ + switch(command) + { + case GPCMD_MODE_SELECT_6: + cdrom[id].current_page_len = 4; + break; + case GPCMD_MODE_SELECT_10: + cdrom[id].current_page_len = 8; + break; + default: + cdrom_log("CD-ROM %i: Attempting to initialize MODE SELECT with unrecognized command: %02X\n", id, command); + return -1; + } + if (pl_length == 0) + { + cdrom_log("CD-ROM %i: Attempting to initialize MODE SELECT with zero parameter list length: %02X\n", id, command); + return -2; + } + cdrom[id].current_page_pos = 0; + cdrom[id].mode_select_phase = MODE_SELECT_PHASE_HEADER; + cdrom[id].total_length = pl_length; + cdrom[id].written_length = 0; + cdrom[id].do_page_save = do_save; + return 1; +} + +int cdrom_mode_select_terminate(uint8_t id, int force) +{ + if (((cdrom[id].written_length >= cdrom[id].total_length) || force) && (cdrom[id].mode_select_phase != MODE_SELECT_PHASE_IDLE)) + { + cdrom_log("CD-ROM %i: MODE SELECT terminate: %i\n", id, force); + cdrom[id].current_page_pos = cdrom[id].current_page_len = cdrom[id].block_descriptor_len = 0; + cdrom[id].total_length = cdrom[id].written_length = 0; + cdrom[id].mode_select_phase = MODE_SELECT_PHASE_IDLE; + if (force) + { + cdrom_mode_sense_load(id); + } + return 1; + } + else + { + return 0; + } +} + +int cdrom_mode_select_header(uint8_t id, uint8_t val) +{ + if (cdrom[id].current_page_pos == 0) + { + cdrom[id].block_descriptor_len = 0; + } + else if (cdrom[id].current_page_pos == (cdrom[id].current_page_len - 2)) + { + if ((cdrom_drives[id].bus_type == CDROM_BUS_SCSI) && (cdrom[id].current_page_len == 8)) + { + cdrom[id].block_descriptor_len |= ((uint16_t) val) << 8; + cdrom_log("CD-ROM %i: Position: %02X, value: %02X, block descriptor length: %02X\n", id, cdrom[id].current_page_pos, val, cdrom[id].block_descriptor_len); + } + } + else if (cdrom[id].current_page_pos == (cdrom[id].current_page_len - 1)) + { + if (cdrom_drives[id].bus_type == CDROM_BUS_SCSI) + { + cdrom[id].block_descriptor_len |= (uint16_t) val; + cdrom_log("CD-ROM %i: Position: %02X, value: %02X, block descriptor length: %02X\n", id, cdrom[id].current_page_pos, val, cdrom[id].block_descriptor_len); + } + } + + cdrom[id].current_page_pos++; + + if (cdrom[id].current_page_pos >= cdrom[id].current_page_len) + { + cdrom[id].current_page_pos = 0; + if (cdrom[id].block_descriptor_len) + { + cdrom[id].mode_select_phase = MODE_SELECT_PHASE_BLOCK_DESC; + } + else + { + cdrom[id].mode_select_phase = MODE_SELECT_PHASE_PAGE_HEADER; + } + } + + return 1; +} + +int cdrom_mode_select_block_desc(uint8_t id) +{ + cdrom[id].current_page_pos++; + if (cdrom[id].current_page_pos >= 8) + { + cdrom[id].current_page_pos = 0; + cdrom[id].mode_select_phase = MODE_SELECT_PHASE_PAGE_HEADER; + } + return 1; +} + +static void cdrom_invalid_field_pl(uint8_t id); + +int cdrom_mode_select_page_header(uint8_t id, uint8_t val) +{ + if (cdrom[id].current_page_pos == 0) + { + cdrom[id].current_page_code = val & 0x3f; + if (!(cdrom_mode_sense_page_flags[id] & (1LL << cdrom[id].current_page_code))) + { + cdrom_log("CD-ROM %i: Trying to modify an unimplemented page: %02X\n", id, cdrom[id].current_page_code); + cdrom_mode_select_terminate(id, 1); + cdrom_invalid_field_pl(id); + } + cdrom[id].current_page_pos++; + } + else if (cdrom[id].current_page_pos == 1) + { + cdrom[id].current_page_pos = 0; + cdrom[id].current_page_len = val; + cdrom[id].mode_select_phase = MODE_SELECT_PHASE_PAGE; + } + return 1; +} + +int cdrom_mode_select_page(uint8_t id, uint8_t val) +{ + if (cdrom_mode_sense_pages_changeable[id][cdrom[id].current_page_code][cdrom[id].current_page_pos + 2] != 0xFF) + { + if (val != cdrom_mode_sense_pages_saved[id][cdrom[id].current_page_code][cdrom[id].current_page_pos + 2]) + { + /* Trying to change an unchangeable value. */ + cdrom_log("CD-ROM %i: Trying to change an unchangeable value: [%02X][%02X] = %02X (new: %02X)\n", id, cdrom[id].current_page_code, cdrom[id].current_page_pos + 2, cdrom_mode_sense_pages_saved[id][cdrom[id].current_page_code][cdrom[id].current_page_pos + 2], val); + cdrom_mode_select_terminate(id, 1); + cdrom_invalid_field_pl(id); + return 0; + } + } + else + { + if (cdrom[id].current_page_code == 0xE) + { + if ((cdrom[id].current_page_pos == 6) || (cdrom[id].current_page_pos == 8)) + { + if (val > 3) + { + /* Trying to set an unsupported audio channel. */ + cdrom_log("CD-ROM %i: Trying to set an unsupported value: [%02X][%02X] = %02X (new: %02X)\n", id, cdrom[id].current_page_code, cdrom[id].current_page_pos, cdrom_mode_sense_pages_saved[id][cdrom[id].current_page_code][cdrom[id].current_page_pos + 2], val); + return 0; + } + } + } + cdrom_mode_sense_pages_saved[id][cdrom[id].current_page_code][cdrom[id].current_page_pos + 2] = val; + } + cdrom[id].current_page_pos++; + if (cdrom[id].current_page_pos >= cdrom[id].current_page_len) + { + cdrom[id].current_page_pos = 0; + cdrom[id].mode_select_phase = MODE_SELECT_PHASE_PAGE_HEADER; + } + return 1; +} + +static void cdrom_command_complete(uint8_t id); + +int cdrom_mode_select_write(uint8_t id, uint8_t val) +{ + int ret = 0; + int ret2 = 0; + + if (id > CDROM_NUM) + { + cdrom_log("MODE SELECT: attempted write to wrong CD-ROM drive\n", val); + return -6; + } + + if (cdrom[id].total_length == 0) + { + cdrom_log("CD-ROM %i: MODE SELECT: attempted write when not initialized (%02X)\n", id, val); + return -3; + } + + cdrom[id].written_length++; + + switch (cdrom[id].mode_select_phase) + { + case MODE_SELECT_PHASE_IDLE: + cdrom_log("CD-ROM %i: MODE SELECT idle (%02X)\n", id, val); + ret = 1; + break; + case MODE_SELECT_PHASE_HEADER: + cdrom_log("CD-ROM %i: MODE SELECT header (%02X)\n", id, val); + ret = cdrom_mode_select_header(id, val); + break; + case MODE_SELECT_PHASE_BLOCK_DESC: + cdrom_log("CD-ROM %i: MODE SELECT block descriptor (%02X)\n", id, val); + ret = cdrom_mode_select_block_desc(id); + break; + case MODE_SELECT_PHASE_PAGE_HEADER: + cdrom_log("CD-ROM %i: MODE SELECT page header (%02X)\n", id, val); + ret = cdrom_mode_select_page_header(id, val); + break; + case MODE_SELECT_PHASE_PAGE: + cdrom_log("CD-ROM %i: MODE SELECT page (%02X)\n", id, val); + ret = cdrom_mode_select_page(id, val); + if (cdrom[id].mode_select_phase == MODE_SELECT_PHASE_PAGE_HEADER) + { + if (cdrom[id].do_page_save && (cdrom_mode_sense_pages_default[id][cdrom[id].current_page_code][0] & 0x80)) + { + cdrom_log("CD-ROM %i: Page %i finished, saving it...\n", id, cdrom[id].current_page_code); + cdrom_mode_sense_save(id); + } + } + break; + default: + cdrom_log("CD-ROM %i: MODE SELECT unknown phase (%02X)\n", id, val); + ret = -4; + break; + } + + /* On termination, override the return value, but only if it is 1. */ + ret2 = cdrom_mode_select_terminate(id, 0); + if (ret2) + { + cdrom_command_complete(id); + } + if (ret2 && (ret == 1)) + { + ret = -5; + } + + return ret; +} + +uint8_t cdrom_read_capacity_cdb[12] = {0x25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + +static int cdrom_pass_through(uint8_t id, uint32_t *len, uint8_t *cdb, uint8_t *buffer); + +int cdrom_read_capacity(uint8_t id, uint8_t *cdb, uint8_t *buffer, uint32_t *len) +{ + int ret = 0; + int size = 0; + + if (cdrom_drives[id].handler->pass_through) + { + ret = cdrom_pass_through(id, len, cdb, buffer); + if (!ret) + { + return 0; + } + if (*len == 65534) + { + *len = 8; + } + } + else + { + size = cdrom_drives[id].handler->size(id) - 1; /* IMPORTANT: What's returned is the last LBA block. */ + memset(buffer, 0, 8); + buffer[0] = (size >> 24) & 0xff; + buffer[1] = (size >> 16) & 0xff; + buffer[2] = (size >> 8) & 0xff; + buffer[3] = size & 0xff; + buffer[6] = 8; /* 2048 = 0x0800 */ + *len = 8; + } + return 1; +} + +/*SCSI Mode Sense 6/10*/ +uint8_t cdrom_mode_sense_read(uint8_t id, uint8_t page_control, uint8_t page, uint8_t pos) +{ + switch (page_control) + { + case 0: + case 3: + return cdrom_mode_sense_pages_saved[id][page][pos]; + break; + case 1: + return cdrom_mode_sense_pages_changeable[id][page][pos]; + break; + case 2: + return cdrom_mode_sense_pages_default[id][page][pos]; + break; + } + + return 0; +} + +uint32_t cdrom_mode_sense(uint8_t id, uint8_t *buf, uint32_t pos, uint8_t type, uint8_t block_descriptor_len) +{ + uint8_t page_control = (type >> 6) & 3; + + int i = 0; + int j = 0; + + uint8_t msplen; + + type &= 0x3f; + + if (block_descriptor_len) + { + buf[pos++] = 1; /* Density code. */ + buf[pos++] = 0; /* Number of blocks (0 = all). */ + buf[pos++] = 0; + buf[pos++] = 0; + buf[pos++] = 0; /* Reserved. */ + buf[pos++] = 0; /* Block length (0x800 = 2048 bytes). */ + buf[pos++] = 8; + buf[pos++] = 0; + } + + for (i = 0; i < 0x40; i++) + { + if ((type == GPMODE_ALL_PAGES) || (type == i)) + { + if (cdrom_mode_sense_page_flags[id] & (1LL << cdrom[id].current_page_code)) + { + buf[pos++] = cdrom_mode_sense_read(id, page_control, i, 0); + msplen = cdrom_mode_sense_read(id, page_control, i, 1); + buf[pos++] = msplen; + cdrom_log("CD-ROM %i: MODE SENSE: Page [%02X] length %i\n", id, i, msplen); + for (j = 0; j < msplen; j++) + { + buf[pos++] = cdrom_mode_sense_read(id, page_control, i, 2 + j); + } + } + } + } + + return pos; +} + +void cdrom_update_request_length(uint8_t id, int len, int block_len) +{ + /* For media access commands, make sure the requested DRQ length matches the block length. */ + switch (cdrom[id].current_cdb[0]) + { + case 0x08: + case 0x28: + case 0xa8: + case 0xb9: + case 0xbe: + if (cdrom[id].request_length < block_len) + { + cdrom[id].request_length = block_len; + } + /* Make sure we respect the limit of how many blocks we can transfer at once. */ + if (cdrom[id].requested_blocks > cdrom_drives[id].max_blocks_at_once) + { + cdrom[id].requested_blocks = cdrom_drives[id].max_blocks_at_once; + } + cdrom[id].block_total = (cdrom[id].requested_blocks * block_len); + if (len > cdrom[id].block_total) + { + len = cdrom[id].block_total; + } + break; + default: + cdrom[id].packet_len = len; + break; + } + /* If the DRQ length is odd, and the total remaining length is bigger, make sure it's even. */ + if ((cdrom[id].request_length & 1) && (cdrom[id].request_length < len)) + { + cdrom[id].request_length &= 0xfffe; + } + /* If the DRQ length is smaller or equal in size to the total remaining length, set it to that. */ + if (len <= cdrom[id].request_length) + { + cdrom[id].request_length = len; + } + return; +} + +static int cdrom_is_media_access(uint8_t id) +{ + switch (cdrom[id].current_cdb[0]) + { + case 0x08: + case 0x28: + case 0xa8: + case 0xb9: + case 0xbe: + return 1; + default: + return 0; + } +} + +static void cdrom_command_common(uint8_t id) +{ + cdrom[id].status = BUSY_STAT; + cdrom[id].phase = 1; + cdrom[id].pos = 0; + if (cdrom[id].packet_status == CDROM_PHASE_COMPLETE) + { + cdrom[id].callback = 20 * CDROM_TIME; + } + else if (cdrom[id].packet_status == CDROM_PHASE_DATA_IN) + { + if (cdrom[id].current_cdb[0] == 0x42) + { + cdrom_log("CD-ROM %i: READ SUBCHANNEL\n"); + cdrom[id].callback = 1000 * CDROM_TIME; + } + else + { + cdrom[id].callback = 60 * CDROM_TIME; + } + } + else + { + cdrom[id].callback = 60 * CDROM_TIME; + } +} + +static void cdrom_command_complete(uint8_t id) +{ + cdrom[id].packet_status = CDROM_PHASE_COMPLETE; + cdrom_command_common(id); +} + +static void cdrom_command_read(uint8_t id) +{ + cdrom[id].packet_status = CDROM_PHASE_DATA_IN; + cdrom_command_common(id); + cdrom[id].total_read = 0; +} + +static void cdrom_command_read_dma(uint8_t id) +{ + cdrom[id].packet_status = CDROM_PHASE_DATA_IN_DMA; + cdrom_command_common(id); + cdrom[id].total_read = 0; +} + +static void cdrom_command_write(uint8_t id) +{ + cdrom[id].packet_status = CDROM_PHASE_DATA_OUT; + cdrom_command_common(id); +} + +static void cdrom_command_write_dma(uint8_t id) +{ + cdrom[id].packet_status = CDROM_PHASE_DATA_OUT_DMA; + cdrom_command_common(id); +} + +static int cdrom_request_length_is_zero(uint8_t id) +{ + if ((cdrom[id].request_length == 0) && (cdrom_drives[id].bus_type < CDROM_BUS_SCSI)) + { + return 1; + } + return 0; +} + +static void cdrom_data_command_finish(uint8_t id, int len, int block_len, int alloc_len, int direction) +{ + cdrom_log("CD-ROM %i: Finishing command (%02X): %i, %i, %i, %i, %i\n", id, cdrom[id].current_cdb[0], len, block_len, alloc_len, direction, cdrom[id].request_length); + cdrom[id].pos=0; + if (alloc_len >= 0) + { + if (alloc_len < len) + { + len = alloc_len; + } + } + if (cdrom_request_length_is_zero(id) || (len == 0) || (cdrom_current_mode(id) == 0)) + { + if (cdrom_drives[id].bus_type == CDROM_BUS_SCSI) + { + SCSIDevices[cdrom_drives[id].scsi_device_id][cdrom_drives[id].scsi_device_lun].InitLength = 0; + } + else + { + cdrom[id].init_length = 0; + } + cdrom_command_complete(id); + } + else + { + if (cdrom_current_mode(id) == 2) + { + if (direction == 0) + { + if (cdrom_drives[id].bus_type == CDROM_BUS_SCSI) + { + SCSIDevices[cdrom_drives[id].scsi_device_id][cdrom_drives[id].scsi_device_lun].InitLength = alloc_len; + } + else + { + cdrom[id].init_length = alloc_len; + } + cdrom_command_read_dma(id); + } + else + { + cdrom_command_write_dma(id); + } + } + else + { + cdrom_update_request_length(id, len, block_len); + if (direction == 0) + { + cdrom_command_read(id); + } + else + { + cdrom_command_write(id); + } + } + } + + cdrom_log("CD-ROM %i: Status: %i, cylinder %i, packet length: %i, position: %i, phase: %i\n", id, cdrom[id].packet_status, cdrom[id].request_length, cdrom[id].packet_len, cdrom[id].pos, cdrom[id].phase); +} + +static void cdrom_sense_clear(int id, int command) +{ + cdrom[id].previous_command = command; + cdrom_sense_key = cdrom_asc = cdrom_ascq = 0; +} + +static void cdrom_cmd_error(uint8_t id) +{ + cdrom[id].error = ((cdrom_sense_key & 0xf) << 4) | ABRT_ERR; + if (cdrom[id].unit_attention) + { + cdrom[id].error |= MCR_ERR; + } + cdrom[id].status = READY_STAT | ERR_STAT; + cdrom[id].phase = 3; + cdrom[id].packet_status = 0x80; + cdrom[id].callback = 50 * CDROM_TIME; + cdrom_log("CD-ROM %i: ERROR: %02X/%02X/%02X\n", id, cdrom_sense_key, cdrom_asc, cdrom_ascq); +} + +static void cdrom_unit_attention(uint8_t id) +{ + cdrom[id].error = (SENSE_UNIT_ATTENTION << 4) | ABRT_ERR; + if (cdrom[id].unit_attention) + { + cdrom[id].error |= MCR_ERR; + } + cdrom[id].status = READY_STAT | ERR_STAT; + cdrom[id].phase = 3; + cdrom[id].packet_status = 0x80; + cdrom[id].callback = 50 * CDROM_TIME; + cdrom_log("CD-ROM %i: UNIT ATTENTION\n", id); +} + +static void cdrom_not_ready(uint8_t id) +{ + cdrom_sense_key = SENSE_NOT_READY; + cdrom_asc = ASC_MEDIUM_NOT_PRESENT; + cdrom_ascq = 0; + cdrom_cmd_error(id); +} + +static void cdrom_invalid_lun(uint8_t id) +{ + cdrom_sense_key = SENSE_ILLEGAL_REQUEST; + cdrom_asc = ASC_INV_LUN; + cdrom_ascq = 0; + cdrom_cmd_error(id); +} + +static void cdrom_illegal_opcode(uint8_t id) +{ + cdrom_sense_key = SENSE_ILLEGAL_REQUEST; + cdrom_asc = ASC_ILLEGAL_OPCODE; + cdrom_ascq = 0; + cdrom_cmd_error(id); +} + +static void cdrom_lba_out_of_range(uint8_t id) +{ + cdrom_sense_key = SENSE_ILLEGAL_REQUEST; + cdrom_asc = ASC_LBA_OUT_OF_RANGE; + cdrom_ascq = 0; + cdrom_cmd_error(id); +} + +static void cdrom_invalid_field(uint8_t id) +{ + cdrom_sense_key = SENSE_ILLEGAL_REQUEST; + cdrom_asc = ASC_INV_FIELD_IN_CMD_PACKET; + cdrom_ascq = 0; + cdrom_cmd_error(id); + cdrom[id].status = 0x53; +} + +static void cdrom_invalid_field_pl(uint8_t id) +{ + cdrom_sense_key = SENSE_ILLEGAL_REQUEST; + cdrom_asc = ASC_INV_FIELD_IN_PARAMETER_LIST; + cdrom_ascq = 0; + cdrom_cmd_error(id); + cdrom[id].status = 0x53; +} + +static void cdrom_illegal_mode(uint8_t id) +{ + cdrom_sense_key = SENSE_ILLEGAL_REQUEST; + cdrom_asc = ASC_ILLEGAL_MODE_FOR_THIS_TRACK; + cdrom_ascq = 0; + cdrom_cmd_error(id); +} + +static void cdrom_incompatible_format(uint8_t id) +{ + cdrom_sense_key = SENSE_ILLEGAL_REQUEST; + cdrom_asc = ASC_INCOMPATIBLE_FORMAT; + cdrom_ascq = 0; + cdrom_cmd_error(id); +} + +static void cdrom_data_phase_error(uint8_t id) +{ + cdrom_sense_key = SENSE_ILLEGAL_REQUEST; + cdrom_asc = ASC_DATA_PHASE_ERROR; + cdrom_ascq = 0; + cdrom_cmd_error(id); +} + +static int cdrom_pass_through(uint8_t id, uint32_t *len, uint8_t *cdb, uint8_t *buffer) +{ + int ret = 0; + uint8_t temp_cdb[16]; + + memset(temp_cdb, 0, 16); + + if (cdb[0] == 8) + { + temp_cdb[0] = 0x28; + temp_cdb[8] = cdb[4]; + temp_cdb[3] = cdb[1]; + temp_cdb[4] = cdb[2]; + temp_cdb[5] = cdb[3]; + } + else + { + memcpy(temp_cdb, cdb, 16); + } + + ret = cdrom_drives[id].handler->pass_through(id, temp_cdb, buffer, len); + cdrom_log("CD-ROM %i: Data from pass through: %02X %02X %02X %02X %02X %02X %02X %02X\n", id, buffer[0], buffer[1], buffer[2], buffer[3], buffer[4], buffer[5], buffer[6], buffer[7]); + cdrom_log("CD-ROM %i: Returned value: %i\n", id, ret); + + if (!ret) + { + /* Command failed with OS error code, return illegal opcode. */ + cdrom_log("CD-ROM %i: Command failed with OS error code, return illegal opcode.\n", id); + cdrom_illegal_opcode(id); + return 0; + } + else + { + if ((cdrom_sense_key != 0) || (cdrom_asc != 0) || (cdrom_ascq != 0)) + { + /* Command failed with sense, error with that sense. */ + cdrom_log("CD-ROM %i: Command failed with sense, error with that sense (%02X/%02X/%02X).\n", id, cdrom_sense_key, cdrom_asc, cdrom_ascq); + cdrom_cmd_error(id); + return 0; + } + else + { + /* Command was performed successfully. */ + cdrom_log("CD-ROM %i: Command was performed successfully.\n", id); + return 1; + } + } +} + +void cdrom_update_cdb(uint8_t *cdb, int lba_pos, int number_of_blocks) +{ + int temp = 0; + + switch(cdb[0]) + { + case GPCMD_READ_6: + cdb[1] = (lba_pos >> 16) & 0xff; + cdb[2] = (lba_pos >> 8) & 0xff; + cdb[3] = lba_pos & 0xff; + break; + + case GPCMD_READ_10: + cdb[2] = (lba_pos >> 24) & 0xff; + cdb[3] = (lba_pos >> 16) & 0xff; + cdb[4] = (lba_pos >> 8) & 0xff; + cdb[5] = lba_pos & 0xff; + cdb[7] = (number_of_blocks >> 8) & 0xff; + cdb[8] = number_of_blocks & 0xff; + break; + + case GPCMD_READ_12: + cdb[2] = (lba_pos >> 24) & 0xff; + cdb[3] = (lba_pos >> 16) & 0xff; + cdb[4] = (lba_pos >> 8) & 0xff; + cdb[5] = lba_pos & 0xff; + cdb[6] = (number_of_blocks >> 24) & 0xff; + cdb[7] = (number_of_blocks >> 16) & 0xff; + cdb[8] = (number_of_blocks >> 8) & 0xff; + cdb[9] = number_of_blocks & 0xff; + break; + + case GPCMD_READ_CD_MSF: + temp = cdrom_lba_to_msf_accurate(lba_pos); + cdb[3] = (temp >> 16) & 0xff; + cdb[4] = (temp >> 8) & 0xff; + cdb[5] = temp & 0xff; + + temp = cdrom_lba_to_msf_accurate(lba_pos + number_of_blocks - 1); + cdb[6] = (temp >> 16) & 0xff; + cdb[7] = (temp >> 8) & 0xff; + cdb[8] = temp & 0xff; + break; + + case GPCMD_READ_CD: + cdb[2] = (lba_pos >> 24) & 0xff; + cdb[3] = (lba_pos >> 16) & 0xff; + cdb[4] = (lba_pos >> 8) & 0xff; + cdb[5] = lba_pos & 0xff; + cdb[6] = (number_of_blocks >> 16) & 0xff; + cdb[7] = (number_of_blocks >> 8) & 0xff; + cdb[8] = number_of_blocks & 0xff; + break; + } +} + +int cdrom_read_data(uint8_t id, int msf, int type, int flags, uint32_t *len) +{ + uint8_t *cdbufferb = (uint8_t *) cdrom[id].buffer; + + int ret = 0; + int cdsize = 0; + + int i = 0; + int temp_len = 0; + + int last_valid_data_pos = 0; + + if (cdrom_drives[id].handler->pass_through) + { + cdsize = cdrom_drives[id].handler->size(id); + + ret = cdrom_pass_through(id, len, cdrom[id].current_cdb, cdbufferb + cdrom[id].data_pos); + cdrom[id].data_pos += *len; + + if (!ret) + { + return 0; + } + + if (cdrom[id].sector_pos > (cdsize - 1)) + { + /* cdrom_log("CD-ROM %i: Trying to read beyond the end of disc\n", id); */ + cdrom_lba_out_of_range(id); + return 0; + } + + cdrom[id].old_len = *len; + } + else + { + if (cdrom[id].sector_pos > (cdrom_drives[id].handler->size(id) - 1)) + { + /* cdrom_log("CD-ROM %i: Trying to read beyond the end of disc\n", id); */ + cdrom_lba_out_of_range(id); + return 0; + } + + cdrom[id].old_len = 0; + *len = 0; + + for (i = 0; i < cdrom[id].requested_blocks; i++) + { + ret = cdrom_drives[id].handler->readsector_raw(id, cdbufferb + cdrom[id].data_pos, cdrom[id].sector_pos + i, msf, type, flags, &temp_len); + + last_valid_data_pos = cdrom[id].data_pos; + + cdrom[id].data_pos += temp_len; + cdrom[id].old_len += temp_len; + + *len += temp_len; + + if (!ret) + { + cdrom_illegal_mode(id); + return 0; + } + } + + cdrom_log("CD-ROM %i: Data from raw sector read: %02X %02X %02X %02X %02X %02X %02X %02X\n", id, cdbufferb[last_valid_data_pos + 0], cdbufferb[last_valid_data_pos + 1], cdbufferb[last_valid_data_pos + 2], cdbufferb[last_valid_data_pos + 3], cdbufferb[last_valid_data_pos + 4], cdbufferb[last_valid_data_pos + 5], cdbufferb[last_valid_data_pos + 6], cdbufferb[last_valid_data_pos + 7]); + } + + return 1; +} + +int cdrom_read_blocks(uint8_t id, uint32_t *len, int first_batch) +{ + int ret = 0; + + int msf = 0; + + int type = 0; + int flags = 0; + + if (cdrom[id].current_cdb[0] == 0xb9) + { + msf = 1; + } + + if ((cdrom[id].current_cdb[0] == 0xb9) || (cdrom[id].current_cdb[0] == 0xbe)) + { + type = (cdrom[id].current_cdb[1] >> 2) & 7; + flags = cdrom[id].current_cdb[9] || (((uint32_t) cdrom[id].current_cdb[10]) << 8); + } + else + { + type = 8; + flags = 0x10; + } + + cdrom[id].data_pos = 0; + + if (!cdrom[id].sector_len) + { + cdrom_command_complete(id); + return -1; + } + + cdrom_log("Reading %i blocks starting from %i...\n", cdrom[id].requested_blocks, cdrom[id].sector_pos); + + cdrom_update_cdb(cdrom[id].current_cdb, cdrom[id].sector_pos, cdrom[id].requested_blocks); + + ret = cdrom_read_data(id, msf, type, flags, len); + + cdrom_log("Read %i bytes of blocks...\n", *len); + + if (!ret || ((cdrom[id].old_len != *len) && !first_batch)) + { + if ((cdrom[id].old_len != *len) && !first_batch) + { + cdrom_illegal_mode(id); + } + + return 0; + } + + cdrom[id].sector_pos += cdrom[id].requested_blocks; + cdrom[id].sector_len -= cdrom[id].requested_blocks; + + return 1; +} + +/*SCSI Get Configuration*/ +uint8_t cdrom_set_profile(uint8_t *buf, uint8_t *index, uint16_t profile) +{ + uint8_t *buf_profile = buf + 12; /* start of profiles */ + + buf_profile += ((*index) * 4); /* start of indexed profile */ + buf_profile[0] = (profile >> 8) & 0xff; + buf_profile[1] = profile & 0xff; + buf_profile[2] = ((buf_profile[0] == buf[6]) && (buf_profile[1] == buf[7])); + + /* each profile adds 4 bytes to the response */ + (*index)++; + buf[11] += 4; /* Additional Length */ + + return 4; +} + +/*SCSI Read DVD Structure*/ +static int cdrom_read_dvd_structure(uint8_t id, int format, const uint8_t *packet, uint8_t *buf) +{ + int layer = packet[6]; + uint64_t total_sectors; + + switch (format) + { + case 0x00: /* Physical format information */ + total_sectors = (uint64_t) cdrom_drives[id].handler->size(id); + + if (layer != 0) + { + cdrom_invalid_field(id); + return 0; + } + + total_sectors >>= 2; + if (total_sectors == 0) + { + /* return -ASC_MEDIUM_NOT_PRESENT; */ + cdrom_not_ready(id); + return 0; + } + + buf[4] = 1; /* DVD-ROM, part version 1 */ + buf[5] = 0xf; /* 120mm disc, minimum rate unspecified */ + buf[6] = 1; /* one layer, read-only (per MMC-2 spec) */ + buf[7] = 0; /* default densities */ + + /* FIXME: 0x30000 per spec? */ + buf[8] = buf[9] = buf[10] = buf[11] = 0; /* start sector */ + buf[12] = (total_sectors >> 24) & 0xff; /* end sector */ + buf[13] = (total_sectors >> 16) & 0xff; + buf[14] = (total_sectors >> 8) & 0xff; + buf[15] = total_sectors & 0xff; + + buf[16] = (total_sectors >> 24) & 0xff; /* l0 end sector */ + buf[17] = (total_sectors >> 16) & 0xff; + buf[18] = (total_sectors >> 8) & 0xff; + buf[19] = total_sectors & 0xff; + + /* Size of buffer, not including 2 byte size field */ + buf[0] = ((2048 +2 ) >> 8) & 0xff; + buf[1] = (2048 + 2) & 0xff; + + /* 2k data + 4 byte header */ + return (2048 + 4); + + case 0x01: /* DVD copyright information */ + buf[4] = 0; /* no copyright data */ + buf[5] = 0; /* no region restrictions */ + + /* Size of buffer, not including 2 byte size field */ + buf[0] = ((4 + 2) >> 8) & 0xff; + buf[1] = (4 + 2) & 0xff; + + /* 4 byte header + 4 byte data */ + return (4 + 4); + + case 0x03: /* BCA information - invalid field for no BCA info */ + cdrom_invalid_field(id); + return 0; + + case 0x04: /* DVD disc manufacturing information */ + /* Size of buffer, not including 2 byte size field */ + buf[0] = ((2048 + 2) >> 8) & 0xff; + buf[1] = (2048 + 2) & 0xff; + + /* 2k data + 4 byte header */ + return (2048 + 4); + + case 0xff: + /* + * This lists all the command capabilities above. Add new ones + * in order and update the length and buffer return values. + */ + + buf[4] = 0x00; /* Physical format */ + buf[5] = 0x40; /* Not writable, is readable */ + buf[6] = ((2048 + 4) >> 8) & 0xff; + buf[7] = (2048 + 4) & 0xff; + + buf[8] = 0x01; /* Copyright info */ + buf[9] = 0x40; /* Not writable, is readable */ + buf[10] = ((4 + 4) >> 8) & 0xff; + buf[11] = (4 + 4) & 0xff; + + buf[12] = 0x03; /* BCA info */ + buf[13] = 0x40; /* Not writable, is readable */ + buf[14] = ((188 + 4) >> 8) & 0xff; + buf[15] = (188 + 4) & 0xff; + + buf[16] = 0x04; /* Manufacturing info */ + buf[17] = 0x40; /* Not writable, is readable */ + buf[18] = ((2048 + 4) >> 8) & 0xff; + buf[19] = (2048 + 4) & 0xff; + + /* Size of buffer, not including 2 byte size field */ + buf[6] = ((16 + 2) >> 8) & 0xff; + buf[7] = (16 + 2) & 0xff; + + /* data written + 4 byte header */ + return (16 + 4); + + default: /* TODO: formats beyond DVD-ROM requires */ + cdrom_invalid_field(id); + return 0; + } +} + +/*SCSI Get Event Status Notification*/ +static uint32_t cdrom_get_event_status(uint8_t id, uint8_t *buffer) +{ + uint8_t event_code, media_status = 0; + + if (buffer[5]) + { + media_status = MS_TRAY_OPEN; + if (cdrom_drives[id].handler->stop) + { + cdrom_drives[id].handler->stop(id); + } + } + else + { + media_status = MS_MEDIA_PRESENT; + } + + event_code = MEC_NO_CHANGE; + if (media_status != MS_TRAY_OPEN) + { + if (!buffer[4]) + { + event_code = MEC_NEW_MEDIA; + cdrom_drives[id].handler->load(id); + } + else if (buffer[4]==2) + { + event_code = MEC_EJECT_REQUESTED; + cdrom_drives[id].handler->eject(id); + } + } + + buffer[4] = event_code; + buffer[5] = media_status; + buffer[6] = 0; + buffer[7] = 0; + + return 8; +} + +void cdrom_insert(uint8_t id) +{ + cdrom[id].unit_attention = 1; +} + +/*SCSI Sense Initialization*/ +void cdrom_sense_code_ok(uint8_t id) +{ + cdrom_sense_key = SENSE_NONE; + cdrom_asc = 0; + cdrom_ascq = 0; +} + +int cdrom_pre_execution_check(uint8_t id, uint8_t *cdb) +{ + int ready = 0; + + if (cdrom_drives[id].bus_type == CDROM_BUS_SCSI) + { + if (((cdrom[id].request_length >> 5) & 7) != cdrom_drives[id].scsi_device_lun) + { + cdrom_log("CD-ROM %i: Attempting to execute a unknown command targeted at SCSI LUN %i\n", id, ((cdrom[id].request_length >> 5) & 7)); + cdrom_invalid_lun(id); + return 0; + } + } + + if (!(cdrom_command_flags[cdb[0]] & IMPLEMENTED)) + { + cdrom_log("CD-ROM %i: Attempting to execute unknown command %02X over %s\n", id, cdb[0], (cdrom_drives[id].bus_type == CDROM_BUS_SCSI) ? "SCSI" : ((cdrom_drives[id].bus_type == CDROM_BUS_ATAPI_PIO_AND_DMA) ? "ATAPI PIO/DMA" : "ATAPI PIO")); + + cdrom_illegal_opcode(id); + return 0; + } + + if ((cdrom_drives[id].bus_type < CDROM_BUS_SCSI) && (cdrom_command_flags[cdb[0]] & SCSI_ONLY)) + { + cdrom_log("CD-ROM %i: Attempting to execute SCSI-only command %02X over ATAPI\n", id, cdb[0]); + cdrom_illegal_opcode(id); + return 0; + } + + if ((cdrom_drives[id].bus_type == CDROM_BUS_SCSI) && (cdrom_command_flags[cdb[0]] & ATAPI_ONLY)) + { + cdrom_log("CD-ROM %i: Attempting to execute ATAPI-only command %02X over SCSI\n", id, cdb[0]); + cdrom_illegal_opcode(id); + return 0; + } + + if ((cdrom_drives[id].handler->status(id) == CD_STATUS_PLAYING) || (cdrom_drives[id].handler->status(id) == CD_STATUS_PAUSED)) + { + ready = 1; + goto skip_ready_check; + } + + if (cdrom_drives[id].handler->medium_changed(id)) + { + /* cdrom_log("CD-ROM %i: Medium has changed...\n", id); */ + cdrom_insert(id); + } + + ready = cdrom_drives[id].handler->ready(id); + +skip_ready_check: + if (!ready && cdrom[id].unit_attention) + { + /* If the drive is not ready, there is no reason to keep the + UNIT ATTENTION condition present, as we only use it to mark + disc changes. */ + cdrom[id].unit_attention = 0; + } + + /* If the UNIT ATTENTION condition is set and the command does not allow + execution under it, error out and report the condition. */ + if (cdrom[id].unit_attention == 1) + { + /* Only increment the unit attention phase if the command can not pass through it. */ + if (!(cdrom_command_flags[cdb[0]] & ALLOW_UA)) + { + /* cdrom_log("CD-ROM %i: Unit attention now 2\n", id); */ + cdrom[id].unit_attention = 2; + cdrom_log("CD-ROM %i: UNIT ATTENTION: Command %02X not allowed to pass through\n", id, cdb[0]); + cdrom_unit_attention(id); + return 0; + } + } + else if (cdrom[id].unit_attention == 2) + { + if (cdb[0] != GPCMD_REQUEST_SENSE) + { + /* cdrom_log("CD-ROM %i: Unit attention now 0\n", id); */ + cdrom[id].unit_attention = 0; + } + } + + /* Unless the command is REQUEST SENSE, clear the sense. This will *NOT* + the UNIT ATTENTION condition if it's set. */ + if (cdb[0] != GPCMD_REQUEST_SENSE) + { + cdrom_sense_clear(id, cdb[0]); + } + + /* Next it's time for NOT READY. */ + if ((cdrom_command_flags[cdb[0]] & CHECK_READY) && !ready) + { + cdrom_log("CD-ROM %i: Not ready (%02X)\n", id, cdb[0]); + cdrom_not_ready(id); + return 0; + } + + cdrom_log("CD-ROM %i: Continuing with command %02X\n", id, cdb[0]); + + return 1; +} + +void cdrom_clear_callback(uint8_t channel) +{ + uint8_t id = atapi_cdrom_drives[channel]; + + if (id <= CDROM_NUM) + { + cdrom[id].callback = 0; + } +} + +static void cdrom_seek(uint8_t id, uint32_t pos) +{ + /* cdrom_log("CD-ROM %i: Seek %08X\n", id, pos); */ + cdrom[id].seek_pos = pos; + if (cdrom_drives[id].handler->stop) + { + cdrom_drives[id].handler->stop(id); + } +} + +static void cdrom_rezero(uint8_t id) +{ + if (cdrom_drives[id].handler->stop) + { + cdrom_drives[id].handler->stop(id); + } + cdrom[id].sector_pos = cdrom[id].sector_len = 0; + cdrom_seek(id, 0); +} + +void cdrom_reset(uint8_t id) +{ + cdrom_rezero(id); + cdrom[id].status = 0; + cdrom[id].callback = 0; + cdrom[id].packet_status = 0xff; + cdrom[id].unit_attention = 0; +} + +int cdrom_playing_completed(uint8_t id) +{ + cdrom[id].prev_status = cdrom[id].cd_status; + cdrom[id].cd_status = cdrom_drives[id].handler->status(id); + if (((cdrom[id].prev_status == CD_STATUS_PLAYING) || (cdrom[id].prev_status == CD_STATUS_PAUSED)) && ((cdrom[id].cd_status != CD_STATUS_PLAYING) && (cdrom[id].cd_status != CD_STATUS_PAUSED))) + { + return 1; + } + else + { + return 0; + } +} + +void cdrom_request_sense(uint8_t id, uint8_t *buffer, uint8_t alloc_length) +{ + /*Will return 18 bytes of 0*/ + if (alloc_length != 0) + { + memset(buffer, 0, alloc_length); + memcpy(buffer, cdrom[id].sense, alloc_length); + } + + buffer[0] = 0x70; + + if ((cdrom_sense_key > 0) && ((cdrom[id].cd_status < CD_STATUS_PLAYING) || (cdrom[id].cd_status == CD_STATUS_STOPPED)) && cdrom_playing_completed(id)) + { + buffer[2]=SENSE_ILLEGAL_REQUEST; + buffer[12]=ASC_AUDIO_PLAY_OPERATION; + buffer[13]=ASCQ_AUDIO_PLAY_OPERATION_COMPLETED; + } + else if ((cdrom_sense_key == 0) && (cdrom[id].cd_status >= CD_STATUS_PLAYING) && (cdrom[id].cd_status != CD_STATUS_STOPPED)) + { + buffer[2]=SENSE_ILLEGAL_REQUEST; + buffer[12]=ASC_AUDIO_PLAY_OPERATION; + buffer[13]=(cdrom[id].cd_status == CD_STATUS_PLAYING) ? ASCQ_AUDIO_PLAY_OPERATION_IN_PROGRESS : ASCQ_AUDIO_PLAY_OPERATION_PAUSED; + } + else + { + if (cdrom[id].unit_attention && (cdrom_sense_key == 0)) + { + buffer[2]=SENSE_UNIT_ATTENTION; + buffer[12]=ASC_MEDIUM_MAY_HAVE_CHANGED; + buffer[13]=0; + } + } + + /* cdrom_log("CD-ROM %i: Reporting sense: %02X %02X %02X\n", id, cdbufferb[2], cdbufferb[12], cdbufferb[13]); */ + + if (buffer[2] == SENSE_UNIT_ATTENTION) + { + /* If the last remaining sense is unit attention, clear + that condition. */ + cdrom[id].unit_attention = 0; + } + + /* Clear the sense stuff as per the spec. */ + cdrom_sense_clear(id, GPCMD_REQUEST_SENSE); +} + +void cdrom_request_sense_for_scsi(uint8_t id, uint8_t *buffer, uint8_t alloc_length) +{ + int ready = 0; + + if (cdrom_drives[id].handler->medium_changed(id)) + { + /* cdrom_log("CD-ROM %i: Medium has changed...\n", id); */ + cdrom_insert(id); + } + + ready = cdrom_drives[id].handler->ready(id); + + if (!ready && cdrom[id].unit_attention) + { + /* If the drive is not ready, there is no reason to keep the + UNIT ATTENTION condition present, as we only use it to mark + disc changes. */ + cdrom[id].unit_attention = 0; + } + + /* Do *NOT* advance the unit attention phase. */ + + cdrom_request_sense(id, buffer, alloc_length); +} + +void cdrom_command(uint8_t id, uint8_t *cdb) +{ + uint8_t *cdbufferb = (uint8_t *) cdrom[id].buffer; + uint32_t len; + int msf; + int pos=0; + int max_len; + int used_len; + unsigned idx = 0; + unsigned size_idx; + unsigned preamble_len; + int toc_format; + uint32_t alloc_length; + uint8_t index = 0; + int block_desc = 0; + int format = 0; + int ret; + int real_pos; + int track = 0; + char device_identify[9] = { '8', '6', 'B', '_', 'C', 'D', '0', '0', 0 }; + char device_identify_ex[15] = { '8', '6', 'B', '_', 'C', 'D', '0', '0', ' ', 'v', '1', '.', '0', '0', 0 }; + +#if 0 + int CdbLength; +#endif + if (cdrom_drives[id].bus_type == CDROM_BUS_SCSI) + { + cdrom[id].status &= ~ERR_STAT; + } + else + { + cdrom[id].error = 0; + } + + cdrom[id].packet_len = 0; + cdrom[id].request_pos = 0; + + device_identify[7] = id + 0x30; + + device_identify_ex[7] = id + 0x30; + device_identify_ex[10] = EMU_VERSION[0]; + device_identify_ex[12] = EMU_VERSION[2]; + device_identify_ex[13] = EMU_VERSION[3]; + + cdrom[id].data_pos = 0; + + memcpy(cdrom[id].current_cdb, cdb, cdrom[id].cdb_len); + + cdrom[id].cd_status = cdrom_drives[id].handler->status(id); + + if (cdb[0] != 0) + { + cdrom_log("CD-ROM %i: Command 0x%02X, Sense Key %02X, Asc %02X, Ascq %02X, %i, Unit attention: %i\n", id, cdb[0], cdrom_sense_key, cdrom_asc, cdrom_ascq, ins, cdrom[id].unit_attention); + cdrom_log("CD-ROM %i: Request length: %04X\n", id, cdrom[id].request_length); + +#if 0 + for (CdbLength = 1; CdbLength < cdrom[id].cdb_len; CdbLength++) + { + cdrom_log("CD-ROM %i: CDB[%d] = 0x%02X\n", id, CdbLength, cdb[CdbLength]); + } +#endif + } + + msf = cdb[1] & 2; + cdrom[id].sector_len = 0; + + /* This handles the Not Ready/Unit Attention check if it has to be handled at this point. */ + if (cdrom_pre_execution_check(id, cdb) == 0) + { + return; + } + + switch (cdb[0]) + { + case GPCMD_TEST_UNIT_READY: + cdrom_command_complete(id); + break; + + case GPCMD_REZERO_UNIT: + if (cdrom_drives[id].handler->stop) + { + cdrom_drives[id].handler->stop(id); + } + cdrom[id].sector_pos = cdrom[id].sector_len = 0; + cdrom_seek(id, 0); + break; + + case GPCMD_REQUEST_SENSE: + /* If there's a unit attention condition and there's a buffered not ready, a standalone REQUEST SENSE + should forget about the not ready, and report unit attention straight away. */ + cdrom_request_sense(id, cdbufferb, cdb[4]); + cdrom_data_command_finish(id, 18, 18, cdb[4], 0); + break; + + case GPCMD_SET_SPEED: + case GPCMD_SET_SPEED_ALT: + cdrom_command_complete(id); + break; + + case GPCMD_MECHANISM_STATUS: + len = (cdbufferb[7] << 16) | (cdbufferb[8] << 8) | cdbufferb[9]; + + memset(cdbufferb, 0, 8); + cdbufferb[5] = 1; + + cdrom_data_command_finish(id, 8, 8, len, 0); + break; + + case GPCMD_READ_TOC_PMA_ATIP: + cdrom[id].toctimes++; + + max_len = cdb[7]; + max_len <<= 8; + max_len |= cdb[8]; + + if (cdrom_drives[id].handler->pass_through) + { + ret = cdrom_pass_through(id, &len, cdrom[id].current_cdb, cdbufferb); + if (!ret) + { + /* return; */ + cdrom_sense_key = cdrom_asc = cdrom_ascq = 0; + goto cdrom_readtoc_fallback; + } + alloc_length = cdbufferb[0]; + alloc_length <<= 8; + alloc_length |= cdbufferb[1]; + alloc_length += 2; + if (alloc_length < len) + { + len = alloc_length; + } + } + else + { +cdrom_readtoc_fallback: + toc_format = cdb[2] & 0xf; + + if (toc_format == 0) + { + toc_format = (cdb[9] >> 6) & 3; + } + + switch (toc_format) + { + case 0: /*Normal*/ + len = cdrom_drives[id].handler->readtoc(id, cdbufferb, cdb[6], msf, max_len, 0); + break; + case 1: /*Multi session*/ + len = cdrom_drives[id].handler->readtoc_session(id, cdbufferb, msf, max_len); + cdbufferb[0] = 0; cdbufferb[1] = 0xA; + break; + case 2: /*Raw*/ + len = cdrom_drives[id].handler->readtoc_raw(id, cdbufferb, max_len); + break; + default: + cdrom_invalid_field(id); + return; + } + } + + if (len > max_len) + { + len = max_len; + + cdbufferb[0] = ((len - 2) >> 8) & 0xff; + cdbufferb[1] = (len - 2) & 0xff; + } + + cdrom_data_command_finish(id, len, len, len, 0); + /* cdrom_log("CD-ROM %i: READ_TOC_PMA_ATIP format %02X, length %i (%i)\n", id, toc_format, ide->cylinder, cdbufferb[1]); */ + return; + + case GPCMD_READ_CD_OLD: + cdrom[id].current_cdb[0] = 0xbe; /* IMPORTANT: Convert the command to new read CD for pass through purposes. */ + case GPCMD_READ_6: + case GPCMD_READ_10: + case GPCMD_READ_12: + case GPCMD_READ_CD: + case GPCMD_READ_CD_MSF: + switch(cdb[0]) + { + case GPCMD_READ_6: + cdrom[id].sector_len = cdb[4]; + cdrom[id].sector_pos = ((((uint32_t) cdb[1]) & 0x1f) << 16) | (((uint32_t) cdb[2]) << 8) | ((uint32_t) cdb[3]); + msf = 0; + break; + case GPCMD_READ_10: + cdrom[id].sector_len = (cdb[7] << 8) | cdb[8]; + cdrom[id].sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; + cdrom_log("CD-ROM %i: Length: %i, LBA: %i\n", id, cdrom[id].sector_len, cdrom[id].sector_pos); + msf = 0; + break; + case GPCMD_READ_12: + cdrom[id].sector_len = (((uint32_t) cdb[6]) << 24) | (((uint32_t) cdb[7]) << 16) | (((uint32_t) cdb[8]) << 8) | ((uint32_t) cdb[9]); + cdrom[id].sector_pos = (((uint32_t) cdb[2]) << 24) | (((uint32_t) cdb[3]) << 16) | (((uint32_t) cdb[4]) << 8) | ((uint32_t) cdb[5]); + msf = 0; + break; + case GPCMD_READ_CD_MSF: + /* cdrom_log("CD-ROM %i: Read CD MSF: Start MSF %02X%02X%02X End MSF %02X%02X%02X Flags %02X\n", id, cdb[3], cdb[4], cdb[5], cdb[6], cdb[7], cdb[8], cdb[9]); */ + cdrom[id].sector_len = MSFtoLBA(cdb[6], cdb[7], cdb[8]); + cdrom[id].sector_pos = MSFtoLBA(cdb[3], cdb[4], cdb[5]); + + cdrom[id].sector_len -= cdrom[id].sector_pos; + cdrom[id].sector_len++; + msf = 1; + break; + case GPCMD_READ_CD_OLD: + case GPCMD_READ_CD: + /* cdrom_log("CD-ROM %i: Read CD: Start LBA %02X%02X%02X%02X Length %02X%02X%02X Flags %02X\n", id, cdb[2], cdb[3], cdb[4], cdb[5], cdb[6], cdb[7], cdb[8], cdb[9]); */ + cdrom[id].sector_len = (cdb[6] << 16) | (cdb[7] << 8) | cdb[8]; + cdrom[id].sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; + + msf = 0; + break; + } + + if (!cdrom[id].sector_len) + { + /* cdrom_log("CD-ROM %i: All done - callback set\n", id); */ + cdrom[id].packet_status = CDROM_PHASE_COMPLETE; + cdrom[id].callback = 20 * CDROM_TIME; + break; + } + + max_len = cdrom[id].sector_len; + /* if (cdrom_drives[id].bus_type == CDROM_BUS_SCSI) */ + if (cdrom_current_mode(id) == 2) + { + cdrom[id].requested_blocks = max_len; + } + else + { + cdrom[id].requested_blocks = 1; + } + + ret = cdrom_read_blocks(id, &alloc_length, 1); + if (ret <= 0) + { + return; + } + + cdrom[id].packet_len = max_len * alloc_length; + if (cdrom[id].requested_blocks > 1) + { + cdrom_data_command_finish(id, alloc_length, alloc_length / cdrom[id].requested_blocks, alloc_length, 0); + } + else + { + cdrom_data_command_finish(id, alloc_length, alloc_length, alloc_length, 0); + } + cdrom[id].all_blocks_total = cdrom[id].block_total; + if (cdrom[id].packet_status != CDROM_PHASE_COMPLETE) + { + update_status_bar_icon(SB_CDROM | id, 1); + } + else + { + update_status_bar_icon(SB_CDROM | id, 0); + } + return; + + case GPCMD_READ_HEADER: + if (cdrom_drives[id].handler->pass_through) + { + ret = cdrom_pass_through(id, &len, cdrom[id].current_cdb, cdbufferb); + if (!ret) + { + return; + } + } + else + { + cdrom[id].sector_len = (cdb[7] << 8) | cdb[8]; + cdrom[id].sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4]<<8) | cdb[5]; + if (msf) + { + real_pos = cdrom_lba_to_msf_accurate(cdrom[id].sector_pos); + } + else + { + real_pos = cdrom[id].sector_pos; + } + cdbufferb[0] = 1; /*2048 bytes user data*/ + cdbufferb[1] = cdbufferb[2] = cdbufferb[3] = 0; + cdbufferb[4] = (real_pos >> 24); + cdbufferb[5] = ((real_pos >> 16) & 0xff); + cdbufferb[6] = ((real_pos >> 8) & 0xff); + cdbufferb[7] = real_pos & 0xff; + + len = 8; + } + + cdrom_data_command_finish(id, len, len, len, 0); + return; + + case GPCMD_MODE_SENSE_6: + case GPCMD_MODE_SENSE_10: + if (cdrom_drives[id].bus_type == CDROM_BUS_SCSI) + { + block_desc = ((cdb[1] >> 3) & 1) ? 0 : 1; + } + else + { + block_desc = 0; + } + + if (cdb[0] == GPCMD_MODE_SENSE_6) + { + len = cdb[4]; + } + else + { + len = (cdb[8] | (cdb[7] << 8)); + } + + cdrom[id].current_page_code = cdb[2] & 0x3F; + + if (!(cdrom_mode_sense_page_flags[id] & (1LL << cdrom[id].current_page_code))) + { + cdrom_invalid_field(id); + return; + } + + memset(cdbufferb, 0, len); + alloc_length = len; + + if (cdb[0] == GPCMD_MODE_SENSE_6) + { + len = cdrom_mode_sense(id, cdbufferb, 4, cdb[2], block_desc); + if (len > alloc_length) + { + len = alloc_length; + } + cdbufferb[0] = len - 1; + cdbufferb[1] = cdrom_drives[id].handler->media_type_id(id); + if (block_desc) + { + cdbufferb[3] = 8; + } + } + else + { + len = cdrom_mode_sense(id, cdbufferb, 8, cdb[2], block_desc); + if (len > alloc_length) + { + len = alloc_length; + } + cdbufferb[0]=(len - 2) >> 8; + cdbufferb[1]=(len - 2) & 255; + cdbufferb[2] = cdrom_drives[id].handler->media_type_id(id); + if (block_desc) + { + cdbufferb[6] = 0; + cdbufferb[7] = 8; + } + } + + if (len > alloc_length) + { + len = alloc_length; + } + else if (len < alloc_length) + { + alloc_length = len; + } + + cdrom_log("CD-ROM %i: Reading mode page: %02X...\n", id, cdb[2]); + + cdrom_data_command_finish(id, len, len, alloc_length, 0); + return; + + case GPCMD_MODE_SELECT_6: + case GPCMD_MODE_SELECT_10: + if (cdb[0] == GPCMD_MODE_SELECT_6) + { + len = cdb[4]; + } + else + { + len = (cdb[7] << 8) | cdb[8]; + } + + ret = cdrom_mode_select_init(id, cdb[0], len, cdb[1] & 1); + + cdrom_data_command_finish(id, len, len, len, 1); + return; + + case GPCMD_GET_CONFIGURATION: + /* XXX: could result in alignment problems in some architectures */ + len = (cdb[7] << 8) | cdb[8]; + alloc_length = len; + + index = 0; + + /* only feature 0 is supported */ + if (cdb[2] != 0 || cdb[3] != 0) + { + cdrom_invalid_field(id); + return; + } + + /* + * XXX: avoid overflow for io_buffer if len is bigger than + * the size of that buffer (dimensioned to max number of + * sectors to transfer at once) + * + * Only a problem if the feature/profiles grow. + */ + if (alloc_length > 512) /* XXX: assume 1 sector */ + { + alloc_length = 512; + } + + memset(cdbufferb, 0, alloc_length); + /* + * the number of sectors from the media tells us which profile + * to use as current. 0 means there is no media + */ + if (len > CD_MAX_SECTORS) + { + cdbufferb[6] = (MMC_PROFILE_DVD_ROM >> 8) & 0xff; + cdbufferb[7] = MMC_PROFILE_DVD_ROM & 0xff; + } + else if (len <= CD_MAX_SECTORS) + { + cdbufferb[6] = (MMC_PROFILE_CD_ROM >> 8) & 0xff; + cdbufferb[7] = MMC_PROFILE_CD_ROM & 0xff; + } + cdbufferb[10] = 0x02 | 0x01; /* persistent and current */ + alloc_length = 12; /* headers: 8 + 4 */ + alloc_length += cdrom_set_profile(cdbufferb, &index, MMC_PROFILE_DVD_ROM); + alloc_length += cdrom_set_profile(cdbufferb, &index, MMC_PROFILE_CD_ROM); + cdbufferb[0] = ((alloc_length - 4) >> 24) & 0xff; + cdbufferb[1] = ((alloc_length - 4) >> 16) & 0xff; + cdbufferb[2] = ((alloc_length - 4) >> 8) & 0xff; + cdbufferb[3] = (alloc_length - 4) & 0xff; + + cdrom_data_command_finish(id, len, len, alloc_length, 0); + break; + + case GPCMD_GET_EVENT_STATUS_NOTIFICATION: + gesn_cdb = (void *) cdb; + gesn_event_header = (void *) cdbufferb; + + /* It is fine by the MMC spec to not support async mode operations. */ + if (!(gesn_cdb->polled & 0x01)) + { + /* asynchronous mode */ + /* Only polling is supported, asynchronous mode is not. */ + cdrom_invalid_field(id); + return; + } + + /* polling mode operation */ + + /* + * These are the supported events. + * + * We currently only support requests of the 'media' type. + * Notification class requests and supported event classes are bitmasks, + * but they are built from the same values as the "notification class" + * field. + */ + gesn_event_header->supported_events = 1 << GESN_MEDIA; + + /* + * We use |= below to set the class field; other bits in this byte + * are reserved now but this is useful to do if we have to use the + * reserved fields later. + */ + gesn_event_header->notification_class = 0; + + /* + * Responses to requests are to be based on request priority. The + * notification_class_request_type enum above specifies the + * priority: upper elements are higher prio than lower ones. + */ + if (gesn_cdb->class & (1 << GESN_MEDIA)) + { + gesn_event_header->notification_class |= GESN_MEDIA; + used_len = cdrom_get_event_status(id, cdbufferb); + } + else + { + gesn_event_header->notification_class = 0x80; /* No event available */ + used_len = sizeof(*gesn_event_header); + } + gesn_event_header->len = used_len - sizeof(*gesn_event_header); + + cdrom_data_command_finish(id, used_len, used_len, used_len, 0); + break; + + case GPCMD_READ_DISC_INFORMATION: + max_len = cdb[7]; + max_len <<= 8; + max_len |= cdb[8]; + + if (cdrom_drives[id].handler->pass_through) + { + ret = cdrom_pass_through(id, &len, cdrom[id].current_cdb, cdbufferb); + if (!ret) + { + return; + } + alloc_length = cdbufferb[0]; + alloc_length <<= 8; + alloc_length |= cdbufferb[1]; + alloc_length += 2; + if (alloc_length < len) + { + len = alloc_length; + } + } + else + { + memset(cdbufferb, 0, 34); + memset(cdbufferb, 1, 9); + cdbufferb[0] = 0; + cdbufferb[1] = 32; + cdbufferb[2] = 0xe; /* last session complete, disc finalized */ + cdbufferb[7] = 0x20; /* unrestricted use */ + cdbufferb[8] = 0x00; /* CD-ROM */ + + len=34; + } + + cdrom_data_command_finish(id, len, len, max_len, 0); + break; + + case GPCMD_READ_TRACK_INFORMATION: + max_len = cdb[7]; + max_len <<= 8; + max_len |= cdb[8]; + + track = ((uint32_t) cdb[2]) << 24; + track |= ((uint32_t) cdb[3]) << 16; + track |= ((uint32_t) cdb[4]) << 8; + track |= (uint32_t) cdb[5]; + + if (cdrom_drives[id].handler->pass_through) + { + ret = cdrom_pass_through(id, &len, cdrom[id].current_cdb, cdbufferb); + if (!ret) + { + return; + } + alloc_length = cdbufferb[0]; + alloc_length <<= 8; + alloc_length |= cdbufferb[1]; + alloc_length += 2; + if (alloc_length < len) + { + len = alloc_length; + } + } + else + { + if (((cdb[1] & 0x03) != 1) || (track != 1)) + { + cdrom_invalid_field(id); + return; + } + + len = 36; + + memset(cdbufferb, 0, 36); + cdbufferb[0] = 0; + cdbufferb[1] = 34; + cdbufferb[2] = 1; /* track number (LSB) */ + cdbufferb[3] = 1; /* session number (LSB) */ + cdbufferb[5] = (0 << 5) | (0 << 4) | (4 << 0); /* not damaged, primary copy, data track */ + cdbufferb[6] = (0 << 7) | (0 << 6) | (0 << 5) | (0 << 6) | (1 << 0); /* not reserved track, not blank, not packet writing, not fixed packet, data mode 1 */ + cdbufferb[7] = (0 << 1) | (0 << 0); /* last recorded address not valid, next recordable address not valid */ + cdbufferb[24] = (cdrom_drives[id].handler->size(id) >> 24) & 0xff; /* track size */ + cdbufferb[25] = (cdrom_drives[id].handler->size(id) >> 16) & 0xff; /* track size */ + cdbufferb[26] = (cdrom_drives[id].handler->size(id) >> 8) & 0xff; /* track size */ + cdbufferb[27] = cdrom_drives[id].handler->size(id) & 0xff; /* track size */ + + if (len > max_len) + { + len = max_len; + cdbufferb[0] = ((max_len - 2) >> 8) & 0xff; + cdbufferb[1] = (max_len - 2) & 0xff; + } + } + + cdrom_data_command_finish(id, len, len, max_len, 0); + break; + + case GPCMD_PLAY_AUDIO_10: + case GPCMD_PLAY_AUDIO_12: + case GPCMD_PLAY_AUDIO_MSF: + case GPCMD_PLAY_AUDIO_TRACK_INDEX: + switch(cdb[0]) + { + case GPCMD_PLAY_AUDIO_10: + msf = 0; + pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; + len = (cdb[7] << 8) | cdb[8]; + break; + case GPCMD_PLAY_AUDIO_12: + msf = 0; + pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; + len = (cdb[6] << 24) | (cdb[7] << 16) | (cdb[8] << 8) | cdb[9]; + break; + case GPCMD_PLAY_AUDIO_MSF: + /* This is apparently deprecated in the ATAPI spec, and apparently + has been since 1995 (!). Hence I'm having to guess most of it. */ + msf = 1; + pos = (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; + len = (cdb[6] << 16) | (cdb[7] << 8) | cdb[8]; + break; + case GPCMD_PLAY_AUDIO_TRACK_INDEX: + msf = 2; + pos = (cdb[4] << 8) | cdb[5]; + len = (cdb[7] << 8) | cdb[8]; + break; + } + + if ((cdrom_drive < 1) || (cdrom[id].cd_status <= CD_STATUS_DATA_ONLY) || !cdrom_drives[id].handler->is_track_audio(id, pos, msf)) + { + cdrom_illegal_mode(id); + break; + } + + if (cdrom_drives[id].handler->playaudio) + { + cdrom_drives[id].handler->playaudio(id, pos, len, msf); + } + else + { + cdrom_illegal_mode(id); + break; + } + + cdrom_command_complete(id); + break; + + case GPCMD_READ_SUBCHANNEL: + max_len = cdb[7]; + max_len <<= 8; + max_len |= cdb[8]; + msf = (cdb[1] >> 1) & 1; + + cdrom_log("CD-ROM %i: Getting page %i (%s)\n", id, cdb[3], msf ? "MSF" : "LBA"); + if ((cdrom_drives[id].handler->pass_through) && (cdb[3] != 1)) + { + ret = cdrom_pass_through(id, &len, cdrom[id].current_cdb, cdbufferb); + if (!ret) + { + return; + } + switch(cdrom[id].cd_status) + { + case CD_STATUS_PLAYING: + cdbufferb[1] = 0x11; + break; + case CD_STATUS_PAUSED: + cdbufferb[1] = 0x12; + break; + case CD_STATUS_DATA_ONLY: + cdbufferb[1] = 0x15; + break; + default: + cdbufferb[1] = 0x13; + break; + } + switch(cdb[3]) + { + case 0: + alloc_length = 4; + break; + case 1: + alloc_length = 16; + break; + default: + alloc_length = 24; + break; + } + if (!(cdb[2] & 0x40) || (cdb[3] == 0)) + { + len = 4; + } + else + { + len = alloc_length; + } + } + else + { + if (cdb[3] > 3) + { + /* cdrom_log("CD-ROM %i: Read subchannel check condition %02X\n", id, cdb[3]); */ + cdrom_invalid_field(id); + return; + } + + switch(cdb[3]) + { + case 0: + alloc_length = 4; + break; + case 1: + alloc_length = 16; + break; + default: + alloc_length = 24; + break; + } + + memset(cdbufferb, 0, 24); + pos = 0; + cdbufferb[pos++] = 0; + cdbufferb[pos++] = 0; /*Audio status*/ + cdbufferb[pos++] = 0; cdbufferb[pos++] = 0; /*Subchannel length*/ + cdbufferb[pos++] = cdb[3] & 3; /*Format code*/ + if (cdb[3] == 1) + { + cdbufferb[1] = cdrom_drives[id].handler->getcurrentsubchannel(id, &cdbufferb[5], msf); + switch(cdrom[id].cd_status) + { + case CD_STATUS_PLAYING: + cdbufferb[1] = 0x11; + break; + case CD_STATUS_PAUSED: + cdbufferb[1] = 0x12; + break; + case CD_STATUS_DATA_ONLY: + cdbufferb[1] = 0x15; + break; + default: + cdbufferb[1] = 0x13; + break; + } + } + if (!(cdb[2] & 0x40) || (cdb[3] == 0)) + { + len = 4; + } + else + { + len = alloc_length; + } + } + + cdrom_data_command_finish(id, len, len, max_len, 0); + break; + + case GPCMD_READ_DVD_STRUCTURE: + if (cdrom_drives[id].handler->pass_through) + { + ret = cdrom_pass_through(id, &len, cdrom[id].current_cdb, cdbufferb); + if (!ret) + { + return; + } + } + else + { + len = (((uint32_t) cdb[6]) << 24) | (((uint32_t) cdb[7]) << 16) | (((uint32_t) cdb[8]) << 8) | ((uint32_t) cdb[9]); + alloc_length = len; + + if (cdb[7] < 0xff) + { + if (len <= CD_MAX_SECTORS) + { + cdrom_incompatible_format(id); + return; + } + else + { + cdrom_invalid_field(id); + return; + } + } + + memset(cdbufferb, 0, (alloc_length > 256 * 512 + 4) ? (256 * 512 + 4) : alloc_length); + + switch (cdb[7]) + { + case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07: + case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f: + case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17: + case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f: + case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27: + case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e: case 0x2f: + case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37: + case 0x38: case 0x39: case 0x3a: case 0x3b: case 0x3c: case 0x3d: case 0x3e: case 0x3f: + case 0x40: case 0x41: case 0x42: case 0x43: case 0x44: case 0x45: case 0x46: case 0x47: + case 0x48: case 0x49: case 0x4a: case 0x4b: case 0x4c: case 0x4d: case 0x4e: case 0x4f: + case 0x50: case 0x51: case 0x52: case 0x53: case 0x54: case 0x55: case 0x56: case 0x57: + case 0x58: case 0x59: case 0x5a: case 0x5b: case 0x5c: case 0x5d: case 0x5e: case 0x5f: + case 0x60: case 0x61: case 0x62: case 0x63: case 0x64: case 0x65: case 0x66: case 0x67: + case 0x68: case 0x69: case 0x6a: case 0x6b: case 0x6c: case 0x6d: case 0x6e: case 0x6f: + case 0x70: case 0x71: case 0x72: case 0x73: case 0x74: case 0x75: case 0x76: case 0x77: + case 0x78: case 0x79: case 0x7a: case 0x7b: case 0x7c: case 0x7d: case 0x7e: case 0x7f: + case 0xff: + if (cdb[1] == 0) + { + ret = cdrom_read_dvd_structure(id, format, cdb, cdbufferb); + + if (ret) + { + cdrom_data_command_finish(id, len, len, alloc_length, 0); + } + return; + } + /* TODO: BD support, fall through for now */ + + /* Generic disk structures */ + case 0x80: /* TODO: AACS volume identifier */ + case 0x81: /* TODO: AACS media serial number */ + case 0x82: /* TODO: AACS media identifier */ + case 0x83: /* TODO: AACS media key block */ + case 0x90: /* TODO: List of recognized format layers */ + case 0xc0: /* TODO: Write protection status */ + default: + cdrom_invalid_field(id); + return; + } + } + break; + + case GPCMD_START_STOP_UNIT: + switch(cdb[4] & 3) + { + case 0: /* Stop the disc. */ + if (cdrom_drives[id].handler->stop) + { + cdrom_drives[id].handler->stop(id); + } + break; + case 1: /* Start the disc and read the TOC. */ + cdrom_drives[id].handler->medium_changed(id); /* This causes a TOC reload. */ + break; + case 2: /* Eject the disc if possible. */ + if (cdrom_drives[id].handler->stop) + { + cdrom_drives[id].handler->stop(id); + } + cdrom_eject(id); + break; + case 3: /* Load the disc (close tray). */ + cdrom_reload(id); + break; + } + + cdrom_command_complete(id); + break; + + case GPCMD_INQUIRY: + max_len = cdb[3]; + max_len <<= 8; + max_len |= cdb[4]; + + if (cdb[1] & 1) + { + preamble_len = 4; + size_idx = 3; + + cdbufferb[idx++] = 05; + cdbufferb[idx++] = cdb[2]; + cdbufferb[idx++] = 0; + + idx++; + + switch (cdb[2]) + { + case 0x00: + cdbufferb[idx++] = 0x00; + cdbufferb[idx++] = 0x83; + break; + case 0x83: + if (idx + 24 > max_len) + { + cdrom_data_phase_error(id); + return; + } + + cdbufferb[idx++] = 0x02; + cdbufferb[idx++] = 0x00; + cdbufferb[idx++] = 0x00; + cdbufferb[idx++] = 20; + ide_padstr8(cdbufferb + idx, 20, "53R141"); /* Serial */ + idx += 20; + + if (idx + 72 > cdb[4]) + { + goto atapi_out; + } + cdbufferb[idx++] = 0x02; + cdbufferb[idx++] = 0x01; + cdbufferb[idx++] = 0x00; + cdbufferb[idx++] = 68; + ide_padstr8(cdbufferb + idx, 8, EMU_NAME); /* Vendor */ + idx += 8; + ide_padstr8(cdbufferb + idx, 40, device_identify_ex); /* Product */ + idx += 40; + ide_padstr8(cdbufferb + idx, 20, "53R141"); /* Product */ + idx += 20; + break; + default: + cdrom_log("INQUIRY: Invalid page: %02X\n", cdb[2]); + cdrom_invalid_field(id); + return; + } + } + else + { + preamble_len = 5; + size_idx = 4; + + memset(cdbufferb, 0, 8); + cdbufferb[0] = 5; /*CD-ROM*/ + cdbufferb[1] = 0x80; /*Removable*/ + cdbufferb[2] = (cdrom_drives[id].bus_type == CDROM_BUS_SCSI) ? 0x02 : 0x00; /*SCSI-2 compliant*/ + cdbufferb[3] = (cdrom_drives[id].bus_type == CDROM_BUS_SCSI) ? 0x02 : 0x21; + cdbufferb[4] = 31; + + ide_padstr8(cdbufferb + 8, 8, EMU_NAME); /* Vendor */ + ide_padstr8(cdbufferb + 16, 16, device_identify); /* Product */ + ide_padstr8(cdbufferb + 32, 4, EMU_VERSION); /* Revision */ + idx = 36; + } + +atapi_out: + cdbufferb[size_idx] = idx - preamble_len; + len=idx; + + cdrom_data_command_finish(id, len, len, max_len, 0); + break; + + case GPCMD_PREVENT_REMOVAL: + cdrom_command_complete(id); + break; + + case GPCMD_PAUSE_RESUME_ALT: + case GPCMD_PAUSE_RESUME: + if (cdb[8] & 1) + { + if (cdrom_drives[id].handler->resume) + { + cdrom_drives[id].handler->resume(id); + } + else + { + cdrom_illegal_mode(id); + break; + } + } + else + { + if (cdrom_drives[id].handler->pause) + { + cdrom_drives[id].handler->pause(id); + } + else + { + cdrom_illegal_mode(id); + break; + } + } + cdrom_command_complete(id); + break; + + case GPCMD_SEEK_6: + case GPCMD_SEEK_10: + switch(cdb[0]) + { + case GPCMD_SEEK_6: + pos = (cdb[2] << 8) | cdb[3]; + break; + case GPCMD_SEEK_10: + pos = (cdb[2] << 24) | (cdb[3]<<16) | (cdb[4]<<8) | cdb[5]; + break; + } + cdrom_seek(id, pos); + cdrom_command_complete(id); + break; + + case GPCMD_READ_CDROM_CAPACITY: + if (cdrom_read_capacity(id, cdrom[id].current_cdb, cdbufferb, &len) == 0) + { + return; + } + + cdrom_data_command_finish(id, len, len, len, 0); + break; + + case GPCMD_STOP_PLAY_SCAN: + if (cdrom_drives[id].handler->stop) + { + cdrom_drives[id].handler->stop(id); + } + else + { + cdrom_illegal_mode(id); + break; + } + cdrom_command_complete(id); + break; + + default: + cdrom_illegal_opcode(id); + break; + } + + /* cdrom_log("CD-ROM %i: Phase: %02X, request length: %i\n", cdrom[id].phase, cdrom[id].request_length); */ +} + +/* This is for block reads. */ +int cdrom_block_check(uint8_t id) +{ + uint32_t alloc_length = 0; + int ret = 0; + + /* If this is a media access command, and we hit the end of the block but not the entire length, + read the next block. */ + if (cdrom_is_media_access(id)) + { + /* We have finished the current block. */ + cdrom_log("CD-ROM %i: %i bytes total read, %i bytes all total\n", id, cdrom[id].total_read, cdrom[id].all_blocks_total); + if (cdrom[id].total_read >= cdrom[id].all_blocks_total) + { + cdrom_log("CD-ROM %i: %i bytes read, current block finished\n", id, cdrom[id].total_read); + /* Read the next block. */ + ret = cdrom_read_blocks(id, &alloc_length, 0); + if (ret == -1) + { + /* Return value is -1 - there are no further blocks to read. */ + cdrom_log("CD-ROM %i: %i bytes read, no further blocks to read\n", id, cdrom[id].total_read); + cdrom[id].status = BUSY_STAT; + return 1; + } + else if (ret == 0) + { + /* Return value is 0 - an error has occurred. */ + cdrom_log("CD-ROM %i: %i bytes read, error while reading blocks\n", id, cdrom[id].total_read); + cdrom[id].status = BUSY_STAT | (cdrom[id].status & ERR_STAT); + return 0; + } + else + { + /* Return value is 1 - sectors have been read successfully. */ + cdrom[id].pos = 0; + cdrom[id].all_blocks_total += cdrom[id].block_total; + cdrom_log("CD-ROM %i: %i bytes read, next block(s) read successfully, %i bytes are still left\n", id, cdrom[id].total_read, cdrom[id].all_blocks_total - cdrom[id].total_read); + return 1; + } + } + else + { + /* Blocks not exhausted, tell the host to check for buffer length. */ + cdrom_log("CD-ROM %i: Blocks not yet finished\n", id); + return 1; + } + } + else + { + /* Not a media access command, ALWAYS do the callback. */ + cdrom_log("CD-ROM %i: Not a media access command\n", id); + return 1; + } +} + +/* This is the general ATAPI callback. */ +void cdrom_callback(uint8_t id) /* Callback for non-Read CD commands */ +{ + int old_pos = 0; + + if (cdrom_drives[id].bus_type < CDROM_BUS_SCSI) + { + cdrom_log("CD-ROM %i: Lowering IDE IRQ\n", id); + ide_irq_lower(&(ide_drives[cdrom_drives[id].ide_channel])); + } + + cdrom[id].status = BUSY_STAT; + + if (cdrom[id].total_read >= cdrom[id].packet_len) + { + cdrom_log("CD-ROM %i: %i bytes read, command done\n", id, cdrom[id].total_read); + + cdrom[id].pos = cdrom[id].request_pos = 0; + cdrom_command_complete(id); + } + else + { + cdrom_log("CD-ROM %i: %i bytes read, %i bytes are still left\n", id, cdrom[id].total_read, cdrom[id].packet_len - cdrom[id].total_read); + + /* Make sure to keep pos, and reset request_pos to 0. */ + /* Also make sure to not reset total_read. */ + old_pos = cdrom[id].pos; + cdrom[id].packet_status = CDROM_PHASE_DATA_IN; + cdrom_command_common(id); + cdrom[id].pos = old_pos; + cdrom[id].request_pos = 0; + } +} + +/* 0 = Continue transfer; 1 = Continue transfer, IRQ; -1 = Terminate transfer; -2 = Terminate transfer with error */ +int cdrom_mode_select_return(uint8_t id, int ret) +{ + switch(ret) + { + case 0: + /* Invalid field in parameter list. */ + case -6: + /* Attempted to write to a non-existent CD-ROM drive (should never occur, but you never know). */ + cdrom_invalid_field_pl(id); + return -2; + case 1: + /* Successful, more data needed. */ + if (cdrom[id].pos >= (cdrom[id].packet_len + 2)) + { + cdrom[id].pos = 0; + cdrom_command_write(id); + return 1; + } + return 0; + case 2: + /* Successful, more data needed, second byte not yet processed. */ + return 0; + case -3: + /* Not initialized. */ + case -4: + /* Unknown phase. */ + cdrom_illegal_opcode(id); + return -2; + case -5: + /* Command terminated successfully. */ + /* cdrom_command_complete(id); */ + return -1; + default: + return -15; + } +} + +void cdrom_phase_callback(uint8_t id); + +int cdrom_read_from_ide_dma(uint8_t channel) +{ + uint8_t *cdbufferb; + + uint8_t id = atapi_cdrom_drives[channel]; + + cdbufferb = (uint8_t *) cdrom[id].buffer; + + if (id > CDROM_NUM) + { + return 0; + } + + if (ide_bus_master_write) + { + if (ide_bus_master_write(channel >> 1, cdbufferb, cdrom[id].request_length)) + { + cdrom_data_phase_error(id); + cdrom_phase_callback(id); + return 0; + } + else + { + return 1; + } + } + + return 0; +} + +int cdrom_read_from_scsi_dma(uint8_t scsi_id, uint8_t scsi_lun) +{ + uint8_t *cdbufferb; + + uint8_t id = scsi_cdrom_drives[scsi_id][scsi_lun]; + + cdbufferb = (uint8_t *) cdrom[id].buffer; + + if (id > CDROM_NUM) + { + return 0; + } + + cdrom_log("Reading from SCSI DMA: SCSI ID %02X, init length %i\n", scsi_id, SCSIDevices[scsi_id][scsi_lun].InitLength); + memcpy(cdbufferb, SCSIDevices[scsi_id][scsi_lun].CmdBuffer, SCSIDevices[scsi_id][scsi_lun].InitLength); + return 1; +} + +int cdrom_read_from_dma(uint8_t id) +{ + uint8_t *cdbufferb = (uint8_t *) cdrom[id].buffer; + + int i = 0; + int ret = 0; + + int in_data_length = 0; + + if (cdrom_drives[id].bus_type == CDROM_BUS_SCSI) + { + ret = cdrom_read_from_scsi_dma(cdrom_drives[id].scsi_device_id, cdrom_drives[id].scsi_device_lun); + } + else + { + ret = cdrom_read_from_ide_dma(cdrom_drives[id].ide_channel); + } + + if (!ret) + { + return 0; + } + + if (cdrom_drives[id].bus_type == CDROM_BUS_SCSI) + { + in_data_length = SCSIDevices[cdrom_drives[id].scsi_device_id][cdrom_drives[id].scsi_device_lun].InitLength; + cdrom_log("CD-ROM %i: SCSI Input data length: %i\n", id, in_data_length); + } + else + { + in_data_length = cdrom[id].request_length; + cdrom_log("CD-ROM %i: ATAPI Input data length: %i\n", id, in_data_length); + } + + for (i = 0; i < in_data_length; i++) + { + ret = cdrom_mode_select_write(id, cdbufferb[i]); + ret = cdrom_mode_select_return(id, ret); + if (ret == -1) + { + return 1; + } + else if (ret == -2) + { + cdrom_phase_callback(id); + return 0; + } + } + + return 0; +} + +int cdrom_write_to_ide_dma(uint8_t channel) +{ + uint8_t *cdbufferb; + + uint8_t id = atapi_cdrom_drives[channel]; + + int transfer_length = 0; + int cdbufferb_pos = 0; + + int bus_master_len = 0; + int ret = 0; + + if (id > CDROM_NUM) + { + return 0; + } + + cdbufferb = (uint8_t *) cdrom[id].buffer; + + transfer_length = cdrom[id].init_length; + + if (ide_bus_master_read) + { + while(transfer_length > 0) + { + /* pclog("CD-ROM %i: ATAPI DMA on position: %08X...\n", id, cdbufferb + cdbufferb_pos); */ + bus_master_len = piix_bus_master_get_count(channel >> 1); + ret = piix_bus_master_dma_read_ex(channel >> 1, cdbufferb + cdbufferb_pos); + if (ret != 0) + { + break; + } + transfer_length -= bus_master_len; + cdbufferb_pos += bus_master_len; + } + + if (ret > 0) + { + /* pclog("CD-ROM %i: ATAPI DMA error\n", id); */ + cdrom_data_phase_error(id); + cdrom_phase_callback(id); + return 0; + } + else + { + /* pclog("CD-ROM %i: ATAPI DMA successful\n", id); */ + return 1; + } + } + + return 0; +} + +int cdrom_write_to_scsi_dma(uint8_t scsi_id, uint8_t scsi_lun) +{ + uint8_t *cdbufferb; + + uint8_t id = scsi_cdrom_drives[scsi_id][scsi_lun]; + + if (id > CDROM_NUM) + { + return 0; + } + + cdbufferb = (uint8_t *) cdrom[id].buffer; + + cdrom_log("Writing to SCSI DMA: SCSI ID %02X, init length %i\n", scsi_id, SCSIDevices[scsi_id][scsi_lun].InitLength); + memcpy(SCSIDevices[scsi_id][scsi_lun].CmdBuffer, cdbufferb, SCSIDevices[scsi_id][scsi_lun].InitLength); + cdrom_log("CD-ROM %i: Data from CD buffer: %02X %02X %02X %02X %02X %02X %02X %02X\n", id, cdbufferb[0], cdbufferb[1], cdbufferb[2], cdbufferb[3], cdbufferb[4], cdbufferb[5], cdbufferb[6], cdbufferb[7]); + cdrom_log("CD-ROM %i: Data from SCSI DMA : %02X %02X %02X %02X %02X %02X %02X %02X\n", id, SCSIDevices[scsi_id][scsi_lun].CmdBuffer[0], SCSIDevices[scsi_id][scsi_lun].CmdBuffer[1], SCSIDevices[scsi_id][scsi_lun].CmdBuffer[2], SCSIDevices[scsi_id][scsi_lun].CmdBuffer[3], SCSIDevices[scsi_id][scsi_lun].CmdBuffer[4], SCSIDevices[scsi_id][scsi_lun].CmdBuffer[5], SCSIDevices[scsi_id][scsi_lun].CmdBuffer[6], SCSIDevices[scsi_id][scsi_lun].CmdBuffer[7]); + return 1; +} + +int cdrom_write_to_dma(uint8_t id) +{ + int ret = 0; + + if (cdrom_drives[id].bus_type == CDROM_BUS_SCSI) + { + ret = cdrom_write_to_scsi_dma(cdrom_drives[id].scsi_device_id, cdrom_drives[id].scsi_device_lun); + } + else + { + ret = cdrom_write_to_ide_dma(cdrom_drives[id].ide_channel); + } + + if (!ret) + { + return 0; + } + + return 1; +} + +void cdrom_irq_raise(uint8_t id) +{ + if (cdrom_drives[id].bus_type < CDROM_BUS_SCSI) + { + ide_irq_raise(&(ide_drives[cdrom_drives[id].ide_channel])); + } +} + +/* If the result is 1, issue an IRQ, otherwise not. */ +void cdrom_phase_callback(uint8_t id) +{ + switch(cdrom[id].packet_status) + { + case CDROM_PHASE_IDLE: + cdrom_log("CD-ROM %i: CDROM_PHASE_IDLE\n", id); + cdrom[id].pos=0; + cdrom[id].phase = 1; + cdrom[id].status = READY_STAT | DRQ_STAT | (cdrom[id].status & ERR_STAT); + return; + case CDROM_PHASE_COMMAND: + cdrom_log("CD-ROM %i: CDROM_PHASE_COMMAND\n", id); + cdrom[id].status = BUSY_STAT | (cdrom[id].status &ERR_STAT); + memcpy(cdrom[id].atapi_cdb, (uint8_t *) cdrom[id].buffer, cdrom[id].cdb_len); + cdrom_command(id, cdrom[id].atapi_cdb); + return; + case CDROM_PHASE_COMPLETE: + cdrom_log("CD-ROM %i: CDROM_PHASE_COMPLETE\n", id); + cdrom[id].status = READY_STAT; + cdrom[id].phase = 3; + cdrom[id].packet_status = 0xFF; + update_status_bar_icon(SB_CDROM | id, 0); + cdrom_irq_raise(id); + return; + case CDROM_PHASE_DATA_OUT: + cdrom_log("CD-ROM %i: CDROM_PHASE_DATA_OUT\n", id); + cdrom[id].status = READY_STAT | DRQ_STAT | (cdrom[id].status & ERR_STAT); + cdrom[id].phase = 0; + cdrom_irq_raise(id); + return; + case CDROM_PHASE_DATA_OUT_DMA: + cdrom_log("CD-ROM %i: CDROM_PHASE_DATA_OUT_DMA\n", id); + cdrom_read_from_dma(id); + cdrom[id].packet_status = CDROM_PHASE_COMPLETE; + cdrom[id].status = READY_STAT; + cdrom[id].phase = 3; + update_status_bar_icon(SB_CDROM | id, 0); + cdrom_irq_raise(id); + return; + case CDROM_PHASE_DATA_IN: + cdrom_log("CD-ROM %i: CDROM_PHASE_DATA_IN\n", id); + cdrom[id].status = READY_STAT | DRQ_STAT | (cdrom[id].status & ERR_STAT); + cdrom[id].phase = 2; + cdrom_irq_raise(id); + return; + case CDROM_PHASE_DATA_IN_DMA: + cdrom_log("CD-ROM %i: CDROM_PHASE_DATA_IN_DMA\n", id); + cdrom_write_to_dma(id); + cdrom[id].packet_status = CDROM_PHASE_COMPLETE; + cdrom[id].status = READY_STAT; + cdrom[id].phase = 3; + update_status_bar_icon(SB_CDROM | id, 0); + cdrom_irq_raise(id); + return; + case CDROM_PHASE_ERROR: + cdrom_log("CD-ROM %i: CDROM_PHASE_ERROR\n", id); + cdrom[id].status = READY_STAT | ERR_STAT; + cdrom[id].phase = 3; + cdrom_irq_raise(id); + return; + } +} + +/* Reimplement as 8-bit due to reimplementation of IDE data read and write. */ +uint32_t cdrom_read(uint8_t channel, int length) +{ + uint8_t *cdbufferb; + uint16_t *cdbufferw; + uint32_t *cdbufferl; + + uint8_t id = atapi_cdrom_drives[channel]; + + uint32_t temp = 0; + int ret = 0; + + if (id > CDROM_NUM) + { + return 0; + } + + cdbufferb = (uint8_t *) cdrom[id].buffer; + cdbufferw = cdrom[id].buffer; + cdbufferl = (uint32_t *) cdrom[id].buffer; + + switch(length) + { + case 1: + temp = cdbufferb[cdrom[id].pos]; + cdrom[id].pos++; + cdrom[id].request_pos++; + break; + case 2: + temp = cdbufferw[cdrom[id].pos >> 1]; + cdrom[id].pos += 2; + cdrom[id].request_pos += 2; + break; + case 4: + temp = cdbufferl[cdrom[id].pos >> 2]; + cdrom[id].pos += 4; + cdrom[id].request_pos += 4; + break; + default: + return 0; + } + + if (cdrom[id].packet_status == CDROM_PHASE_DATA_IN) + { + cdrom[id].total_read += length; + ret = cdrom_block_check(id); + /* If the block check has returned 0, this means all the requested blocks have been read, therefore the command has finished. */ + if (ret) + { + cdrom_log("CD-ROM %i: Return value is 1 (request length: %i)\n", id, cdrom[id].request_length); + if (cdrom[id].request_pos >= cdrom[id].request_length) + { + /* Time for a DRQ. */ + cdrom_log("CD-ROM %i: Issuing read callback\n", id); + cdrom_callback(id); + } + else + { + cdrom_log("CD-ROM %i: Doing nothing\n", id); + } + } + else + { + cdrom_log("CD-ROM %i: Return value is 0\n", id); + } + cdrom_log("CD-ROM %i: Returning: %02X (buffer position: %i, request position: %i, total: %i)\n", id, temp, cdrom[id].pos, cdrom[id].request_pos, cdrom[id].total_read); + return temp; + } + else + { + cdrom_log("CD-ROM %i: Returning zero (buffer position: %i, request position: %i, total: %i)\n", id, cdrom[id].pos, cdrom[id].request_pos, cdrom[id].total_read); + return 0; + } +} + +/* Reimplement as 8-bit due to reimplementation of IDE data read and write. */ +void cdrom_write(uint8_t channel, uint32_t val, int length) +{ + uint8_t i = 0; + uint8_t *cdbufferb; + uint16_t *cdbufferw; + uint32_t *cdbufferl; + + uint8_t old_pos = 0; + + uint8_t id = atapi_cdrom_drives[channel]; + + int ret = 0; + + if (id > CDROM_NUM) + { + return; + } + + cdbufferb = (uint8_t *) cdrom[id].buffer; + cdbufferw = cdrom[id].buffer; + cdbufferl = (uint32_t *) cdrom[id].buffer; + + old_pos = cdrom[id].pos; + + switch(length) + { + case 1: + cdbufferb[cdrom[id].pos] = val & 0xff; + cdrom[id].pos++; + break; + case 2: + cdbufferw[cdrom[id].pos >> 1] = val & 0xffff; + cdrom[id].pos += 2; + break; + case 4: + cdbufferl[cdrom[id].pos >> 2] = val; + cdrom[id].pos += 4; + break; + default: + return; + } + + if (cdrom[id].packet_status == CDROM_PHASE_DATA_OUT) + { + for (i = 0; i < length; i++) + { + ret = cdrom_mode_select_write(id, cdbufferb[old_pos + i]); + cdrom_mode_select_return(id, ret); + } + return; + } + else if (cdrom[id].packet_status == CDROM_PHASE_IDLE) + { + if (cdrom[id].pos >= cdrom[id].cdb_len) + { + cdrom[id].pos=0; + cdrom[id].status = BUSY_STAT; + cdrom[id].packet_status = CDROM_PHASE_COMMAND; + timer_process(); + cdrom_phase_callback(id); + timer_update_outstanding(); + } + return; + } +} diff --git a/src/cdrom.h b/src/cdrom.h index e8103e5ca..5b7cb1f8b 100644 --- a/src/cdrom.h +++ b/src/cdrom.h @@ -1,35 +1,244 @@ -#ifndef __CDROM_H__ -#define __CDROM_H__ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Implementation of the CD-ROM drive with SCSI(-like) + * commands, for both ATAPI and SCSI usage. + * + * Version: @(#)cdrom.h 1.0.1 2017/06/03 + * + * Author: Miran Grca, + * Copyright 2016-2017 Miran Grca. + */ +#ifndef EMU_CDROM_H +#define EMU_CDROM_H -/*CD-ROM stuff*/ -typedef struct CDROM -{ - int (*ready)(void); - int (*medium_changed)(void); - int (*readtoc)(uint8_t *b, uint8_t starttrack, int msf, int maxlen, int single); - int (*readtoc_session)(uint8_t *b, int msf, int maxlen); - int (*readtoc_raw)(uint8_t *b, int msf, int maxlen); - uint8_t (*getcurrentsubchannel)(uint8_t *b, int msf); - void (*read_capacity)(uint8_t *b); - void (*read_subchannel)(uint8_t *in_cdb, uint8_t *b); - void (*read_header)(uint8_t *in_cdb, uint8_t *b); - void (*read_disc_information)(uint8_t *b); - int (*read_track_information)(uint8_t *in_cdb, uint8_t *b); - int (*sector_data_type)(int sector, int ismsf); - void (*readsector_raw)(uint8_t *b, int sector, int ismsf); - void (*playaudio)(uint32_t pos, uint32_t len, int ismsf); - void (*seek)(uint32_t pos); - void (*load)(void); - void (*eject)(void); - void (*pause)(void); - void (*resume)(void); - uint32_t (*size)(void); - int (*status)(void); - int (*is_track_audio)(uint32_t pos, int ismsf); - void (*stop)(void); - void (*exit)(void); + +#define CDROM_NUM 4 + +#define CDROM_PHASE_IDLE 0 +#define CDROM_PHASE_COMMAND 1 +#define CDROM_PHASE_COMPLETE 2 +#define CDROM_PHASE_DATA_IN 3 +#define CDROM_PHASE_DATA_IN_DMA 4 +#define CDROM_PHASE_DATA_OUT 5 +#define CDROM_PHASE_DATA_OUT_DMA 6 +#define CDROM_PHASE_ERROR 0x80 + +#define BUF_SIZE 32768 + +#define CDROM_IMAGE 200 + +#define IDE_TIME (5 * 100 * (1 << TIMER_SHIFT)) +#define CDROM_TIME (5 * 100 * (1 << TIMER_SHIFT)) + + +typedef struct { + int (*ready)(uint8_t id); + int (*medium_changed)(uint8_t id); + int (*media_type_id)(uint8_t id); + void (*audio_callback)(uint8_t id, int16_t *output, int len); + void (*audio_stop)(uint8_t id); + int (*readtoc)(uint8_t id, uint8_t *b, uint8_t starttrack, int msf, int maxlen, int single); + int (*readtoc_session)(uint8_t id, uint8_t *b, int msf, int maxlen); + int (*readtoc_raw)(uint8_t id, uint8_t *b, int maxlen); + uint8_t (*getcurrentsubchannel)(uint8_t id, uint8_t *b, int msf); + int (*pass_through)(uint8_t id, uint8_t *in_cdb, uint8_t *b, uint32_t *len); + int (*readsector_raw)(uint8_t id, uint8_t *buffer, int sector, int ismsf, int cdrom_sector_type, int cdrom_sector_flags, int *len); + void (*playaudio)(uint8_t id, uint32_t pos, uint32_t len, int ismsf); + void (*load)(uint8_t id); + void (*eject)(uint8_t id); + void (*pause)(uint8_t id); + void (*resume)(uint8_t id); + uint32_t (*size)(uint8_t id); + int (*status)(uint8_t id); + int (*is_track_audio)(uint8_t id, uint32_t pos, int ismsf); + void (*stop)(uint8_t id); + void (*exit)(uint8_t id); } CDROM; -extern CDROM *cdrom; +#pragma pack(push,1) +typedef struct { + uint8_t previous_command; + int toctimes; -#endif \ No newline at end of file + int is_dma; + + int requested_blocks; /* This will be set to something other than 1 when block reads are implemented. */ + + uint64_t current_page_code; + int current_page_len; + + int current_page_pos; + + int mode_select_phase; + + int total_length; + int written_length; + + int do_page_save; + + uint8_t error; + uint8_t features; + uint16_t request_length; + uint8_t status; + uint8_t phase; + + uint32_t sector_pos; + uint32_t sector_len; + + uint32_t packet_len; + int packet_status; + + uint8_t atapi_cdb[16]; + uint8_t current_cdb[16]; + + uint32_t pos; + + int callback; + + int data_pos; + + int cdb_len_setting; + int cdb_len; + + int cd_status; + int prev_status; + + int unit_attention; + uint8_t sense[256]; + + int request_pos; + + uint16_t buffer[390144]; + + int times; + + uint32_t seek_pos; + + int total_read; + + int block_total; + int all_blocks_total; + + int old_len; + int block_descriptor_len; + + int init_length; +} cdrom_t; +#pragma pack(pop) + +#pragma pack(push,1) +typedef struct { + int max_blocks_at_once; + + CDROM *handler; + + int host_drive; + int prev_host_drive; + + unsigned int bus_type; /* 0 = ATAPI, 1 = SCSI */ + uint8_t bus_mode; /* Bit 0 = PIO suported; + Bit 1 = DMA supportd. */ + + uint8_t ide_channel; + + unsigned int scsi_device_id; + unsigned int scsi_device_lun; + + unsigned int sound_on; + unsigned int atapi_dma; +} cdrom_drive_t; +#pragma pack(pop) + +typedef struct { + int image_is_iso; + + uint32_t last_block; + uint32_t cdrom_capacity; + int image_inited; + wchar_t image_path[1024]; + FILE* image; + int image_changed; + + int cd_state; + uint32_t cd_pos; + uint32_t cd_end; + int16_t cd_buffer[BUF_SIZE]; + int cd_buflen; +} cdrom_image_t; + +typedef struct { + uint32_t last_block; + uint32_t cdrom_capacity; + int ioctl_inited; + char ioctl_path[8]; + int tocvalid; + int cd_state; + uint32_t cd_end; + int16_t cd_buffer[BUF_SIZE]; + int cd_buflen; + int actual_requested_blocks; + int last_track_pos; + int last_track_nr; + int capacity_read; + uint8_t rcbuf[16]; + uint8_t sub_q_data_format[16]; + uint8_t sub_q_channel_data[256]; + int last_subchannel_pos; +} cdrom_ioctl_t; + + +extern cdrom_t cdrom[CDROM_NUM]; +extern cdrom_drive_t cdrom_drives[CDROM_NUM]; +extern uint8_t atapi_cdrom_drives[8]; +extern uint8_t scsi_cdrom_drives[16][8]; + cdrom_image_t cdrom_image[CDROM_NUM]; + cdrom_ioctl_t cdrom_ioctl[CDROM_NUM]; + +extern int (*ide_bus_master_read)(int channel, uint8_t *data, int transfer_length); +extern int (*ide_bus_master_write)(int channel, uint8_t *data, int transfer_length); +extern void (*ide_bus_master_set_irq)(int channel); +extern void ioctl_close(uint8_t id); + +extern uint32_t cdrom_mode_sense_get_channel(uint8_t id, int channel); +extern uint32_t cdrom_mode_sense_get_volume(uint8_t id, int channel); +extern void build_atapi_cdrom_map(void); +extern void build_scsi_cdrom_map(void); +extern int cdrom_CDROM_PHASE_to_scsi(uint8_t id); +extern int cdrom_atapi_phase_to_scsi(uint8_t id); +extern void cdrom_command(uint8_t id, uint8_t *cdb); +extern void cdrom_phase_callback(uint8_t id); +extern uint32_t cdrom_read(uint8_t channel, int length); +extern void cdrom_write(uint8_t channel, uint32_t val, int length); + +#ifdef __cplusplus +extern "C" { +#endif + +int cdrom_lba_to_msf_accurate(int lba); + +#ifdef __cplusplus +} +#endif + +void cdrom_reset(uint8_t id); +void cdrom_set_signature(int id); +void cdrom_request_sense_for_scsi(uint8_t id, uint8_t *buffer, uint8_t alloc_length); +void cdrom_update_cdb(uint8_t *cdb, int lba_pos, int number_of_blocks); +void cdrom_insert(uint8_t id); + +int find_cdrom_for_scsi_id(uint8_t scsi_id, uint8_t scsi_lun); + +#define cdrom_sense_error cdrom[id].sense[0] +#define cdrom_sense_key cdrom[id].sense[2] +#define cdrom_asc cdrom[id].sense[12] +#define cdrom_ascq cdrom[id].sense[13] +#define cdrom_drive cdrom_drives[id].host_drive + + +#endif /*EMU_CDROM_H*/ diff --git a/src/cdrom_dosbox.cpp b/src/cdrom_dosbox.cpp new file mode 100644 index 000000000..4def610ca --- /dev/null +++ b/src/cdrom_dosbox.cpp @@ -0,0 +1,577 @@ +/* + * Copyright (C) 2002-2015 The DOSBox Team + * + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* Modified for use with PCem by bit */ + +#define _LARGEFILE_SOURCE +#define _LARGEFILE64_SOURCE +#define _GNU_SOURCE +#include + +#include +#include +#include +#include +#include +#include +#include //GCC 2.95 +#include +#include +#include +#include "cdrom_dosbox.h" + +#if !defined(WIN32) +#include +#else +#include +#endif + +using namespace std; + +#define MAX_LINE_LENGTH 512 +#define MAX_FILENAME_LENGTH 256 +#define CROSS_LEN 512 + +#define safe_strncpy(a,b,n) do { strncpy((a),(b),(n)-1); (a)[(n)-1] = 0; } while (0) + +CDROM_Interface_Image::BinaryFile::BinaryFile(const char *filename, bool &error) +{ + memset(fn, 0, sizeof(fn)); + strcpy(fn, filename); + error = false; +} + +CDROM_Interface_Image::BinaryFile::~BinaryFile() +{ + memset(fn, 0, sizeof(fn)); +} + +bool CDROM_Interface_Image::BinaryFile::read(Bit8u *buffer, uint64_t seek, uint64_t count) +{ + file = fopen64(fn, "rb"); + if (file == NULL) return 0; + fseeko64(file, seek, SEEK_SET); + fread(buffer, 1, count, file); + fclose(file); + return 1; +} + +uint64_t CDROM_Interface_Image::BinaryFile::getLength() +{ + uint64_t ret = 0; + file = fopen64(fn, "rb"); + if (file == NULL) return 0; + fseeko64(file, 0, SEEK_END); + ret = ftello64(file); + fclose(file); + return ret; +} + +CDROM_Interface_Image::CDROM_Interface_Image() +{ +} + +CDROM_Interface_Image::~CDROM_Interface_Image() +{ + ClearTracks(); +} + +void CDROM_Interface_Image::InitNewMedia() +{ +} + +bool CDROM_Interface_Image::SetDevice(char* path, int forceCD) +{ + if (LoadCueSheet(path)) return true; + if (LoadIsoFile(path)) return true; + + // print error message on dosbox console + //printf("Could not load image file: %s\n", path); + return false; +} + +bool CDROM_Interface_Image::GetUPC(unsigned char& attr, char* upc) +{ + attr = 0; + strcpy(upc, this->mcn.c_str()); + return true; +} + +bool CDROM_Interface_Image::GetAudioTracks(int& stTrack, int& end, TMSF& leadOut) +{ + stTrack = 1; + end = (int)(tracks.size() - 1); + FRAMES_TO_MSF(tracks[tracks.size() - 1].start + 150, &leadOut.min, &leadOut.sec, &leadOut.fr); + return true; +} + +bool CDROM_Interface_Image::GetAudioTrackInfo(int track, int& track_number, TMSF& start, unsigned char& attr) +{ + if (track < 1 || track > (int)tracks.size()) return false; + FRAMES_TO_MSF(tracks[track - 1].start + 150, &start.min, &start.sec, &start.fr); + track_number = tracks[track - 1].track_number; + attr = tracks[track - 1].attr; + return true; +} + +bool CDROM_Interface_Image::GetAudioSub(int sector, unsigned char& attr, unsigned char& track, unsigned char& index, TMSF& relPos, TMSF& absPos) +{ + int cur_track = GetTrack(sector); + if (cur_track < 1) return false; + track = (unsigned char)cur_track; + attr = tracks[track - 1].attr; + index = 1; + FRAMES_TO_MSF(sector + 150, &absPos.min, &absPos.sec, &absPos.fr); + /* FRAMES_TO_MSF(sector - tracks[track - 1].start + 150, &relPos.min, &relPos.sec, &relPos.fr); */ + /* Note by Kotori: Yes, the absolute position should be adjusted by 150, but not the relative position. */ + FRAMES_TO_MSF(sector - tracks[track - 1].start, &relPos.min, &relPos.sec, &relPos.fr); + return true; +} + +bool CDROM_Interface_Image::GetMediaTrayStatus(bool& mediaPresent, bool& mediaChanged, bool& trayOpen) +{ + mediaPresent = true; + mediaChanged = false; + trayOpen = false; + return true; +} + +bool CDROM_Interface_Image::ReadSectors(PhysPt buffer, bool raw, unsigned long sector, unsigned long num) +{ + int sectorSize = raw ? RAW_SECTOR_SIZE : COOKED_SECTOR_SIZE; + Bitu buflen = num * sectorSize; + Bit8u* buf = new Bit8u[buflen]; + + bool success = true; //Gobliiins reads 0 sectors + for(unsigned long i = 0; i < num; i++) { + success = ReadSector(&buf[i * sectorSize], raw, sector + i); + if (!success) break; + } + + memcpy((void*)buffer, buf, buflen); + delete[] buf; + + return success; +} + +bool CDROM_Interface_Image::LoadUnloadMedia(bool unload) +{ + return true; +} + +int CDROM_Interface_Image::GetTrack(unsigned int sector) +{ + vector::iterator i = tracks.begin(); + vector::iterator end = tracks.end() - 1; + + while(i != end) { + Track &curr = *i; + Track &next = *(i + 1); + if (curr.start <= sector && sector < next.start) return curr.number; + i++; + } + return -1; +} + +bool CDROM_Interface_Image::ReadSector(Bit8u *buffer, bool raw, unsigned long sector) +{ + int track = GetTrack(sector) - 1; + if (track < 0) return false; + + uint64_t s = (uint64_t) sector; + uint64_t seek = tracks[track].skip + ((s - tracks[track].start) * tracks[track].sectorSize); + uint64_t length = (raw ? RAW_SECTOR_SIZE : COOKED_SECTOR_SIZE); + if (tracks[track].sectorSize != RAW_SECTOR_SIZE && raw) return false; + if (tracks[track].sectorSize == RAW_SECTOR_SIZE && !tracks[track].mode2 && !raw) seek += 16; + if (tracks[track].mode2 && !raw) seek += 24; + + return tracks[track].file->read(buffer, seek, length); +} + +bool CDROM_Interface_Image::IsMode2(unsigned long sector) +{ + int track = GetTrack(sector) - 1; + if (track < 0) return false; + + if (tracks[track].mode2) + { + return true; + } + else + { + return false; + } +} + +bool CDROM_Interface_Image::LoadIsoFile(char* filename) +{ + tracks.clear(); + + // data track + Track track = {0, 0, 0, 0, 0, 0, false, NULL}; + bool error; + track.file = new BinaryFile(filename, error); + if (error) { + delete track.file; + return false; + } + track.number = 1; + track.track_number = 1;//IMPORTANT: This is needed. + track.attr = DATA_TRACK;//data + + // try to detect iso type + if (CanReadPVD(track.file, COOKED_SECTOR_SIZE, false)) { + track.sectorSize = COOKED_SECTOR_SIZE; + track.mode2 = false; + } else if (CanReadPVD(track.file, RAW_SECTOR_SIZE, false)) { + track.sectorSize = RAW_SECTOR_SIZE; + track.mode2 = false; + } else if (CanReadPVD(track.file, 2336, true)) { + track.sectorSize = 2336; + track.mode2 = true; + } else if (CanReadPVD(track.file, RAW_SECTOR_SIZE, true)) { + track.sectorSize = RAW_SECTOR_SIZE; + track.mode2 = true; + } else return false; + + track.length = track.file->getLength() / track.sectorSize; + tracks.push_back(track); + + // leadout track + track.number = 2; + track.track_number = 0xAA; + track.attr = 0x16; /* Was 0x00 but I believe 0x16 is appropriate. */ + track.start = track.length; + track.length = 0; + track.file = NULL; + tracks.push_back(track); + + return true; +} + +bool CDROM_Interface_Image::CanReadPVD(TrackFile *file, uint64_t sectorSize, bool mode2) +{ + Bit8u pvd[COOKED_SECTOR_SIZE]; + uint64_t seek = 16 * sectorSize; // first vd is located at sector 16 + if (sectorSize == RAW_SECTOR_SIZE && !mode2) seek += 16; + if (mode2) seek += 24; + file->read(pvd, seek, COOKED_SECTOR_SIZE); + // pvd[0] = descriptor type, pvd[1..5] = standard identifier, pvd[6] = iso version (+8 for High Sierra) + return ((pvd[0] == 1 && !strncmp((char*)(&pvd[1]), "CD001", 5) && pvd[6] == 1) || + (pvd[8] == 1 && !strncmp((char*)(&pvd[9]), "CDROM", 5) && pvd[14] == 1)); +} + +#if defined(WIN32) +static string dirname(char * file) { + char * sep = strrchr(file, '\\'); + if (sep == NULL) + sep = strrchr(file, '/'); + if (sep == NULL) + return ""; + else { + int len = (int)(sep - file); + char tmp[MAX_FILENAME_LENGTH]; + safe_strncpy(tmp, file, len+1); + return tmp; + } +} +#endif + +bool CDROM_Interface_Image::LoadCueSheet(char *cuefile) +{ + Track track = {0, 0, 0, 0, 0, 0, false, NULL}; + tracks.clear(); + uint64_t shift = 0; + uint64_t currPregap = 0; + uint64_t totalPregap = 0; + uint64_t prestart = 0; + bool success; + bool canAddTrack = false; + char tmp[MAX_FILENAME_LENGTH]; // dirname can change its argument + safe_strncpy(tmp, cuefile, MAX_FILENAME_LENGTH); + string pathname(dirname(tmp)); + ifstream in; + in.open(cuefile, ios::in); + if (in.fail()) return false; + + while(!in.eof()) { + // get next line + char buf[MAX_LINE_LENGTH]; + in.getline(buf, MAX_LINE_LENGTH); + if (in.fail() && !in.eof()) return false; // probably a binary file + istringstream line(buf); + + string command; + GetCueKeyword(command, line); + + if (command == "TRACK") { + if (canAddTrack) success = AddTrack(track, shift, prestart, totalPregap, currPregap); + else success = true; + + track.start = 0; + track.skip = 0; + currPregap = 0; + prestart = 0; + + line >> track.number; + track.track_number = track.number; + string type; + GetCueKeyword(type, line); + + if (type == "AUDIO") { + track.sectorSize = RAW_SECTOR_SIZE; + track.attr = AUDIO_TRACK; + track.mode2 = false; + } else if (type == "MODE1/2048") { + track.sectorSize = COOKED_SECTOR_SIZE; + track.attr = DATA_TRACK; + track.mode2 = false; + } else if (type == "MODE1/2352") { + track.sectorSize = RAW_SECTOR_SIZE; + track.attr = DATA_TRACK; + track.mode2 = false; + } else if (type == "MODE2/2336") { + track.sectorSize = 2336; + track.attr = DATA_TRACK; + track.mode2 = true; + } else if (type == "MODE2/2352") { + track.sectorSize = RAW_SECTOR_SIZE; + track.attr = DATA_TRACK; + track.mode2 = true; + } else success = false; + + canAddTrack = true; + } + else if (command == "INDEX") { + uint64_t index; + line >> index; + uint64_t frame; + success = GetCueFrame(frame, line); + + if (index == 1) track.start = frame; + else if (index == 0) prestart = frame; + // ignore other indices + } + else if (command == "FILE") { + if (canAddTrack) success = AddTrack(track, shift, prestart, totalPregap, currPregap); + else success = true; + canAddTrack = false; + + string filename; + GetCueString(filename, line); + GetRealFileName(filename, pathname); + string type; + GetCueKeyword(type, line); + + track.file = NULL; + bool error = true; + if (type == "BINARY") { + track.file = new BinaryFile(filename.c_str(), error); + } + if (error) { + delete track.file; + success = false; + } + } + else if (command == "PREGAP") success = GetCueFrame(currPregap, line); + else if (command == "CATALOG") success = GetCueString(mcn, line); + // ignored commands + else if (command == "CDTEXTFILE" || command == "FLAGS" || command == "ISRC" + || command == "PERFORMER" || command == "POSTGAP" || command == "REM" + || command == "SONGWRITER" || command == "TITLE" || command == "") success = true; + // failure + else success = false; + + if (!success) return false; + } + // add last track + if (!AddTrack(track, shift, prestart, totalPregap, currPregap)) return false; + + // add leadout track + track.number++; + track.track_number = 0xAA; + // track.attr = 0;//sync with load iso + track.attr = 0x16; /* Was 0x00 but I believe 0x16 is appropriate. */ + track.start = 0; + track.length = 0; + track.file = NULL; + if(!AddTrack(track, shift, 0, totalPregap, 0)) return false; + + return true; +} + +bool CDROM_Interface_Image::AddTrack(Track &curr, uint64_t &shift, uint64_t prestart, uint64_t &totalPregap, uint64_t currPregap) +{ + // frames between index 0(prestart) and 1(curr.start) must be skipped + uint64_t skip; + if (prestart > 0) { + if (prestart > curr.start) return false; + skip = curr.start - prestart; + } else skip = 0; + + // first track (track number must be 1) + if (tracks.empty()) { + if (curr.number != 1) return false; + curr.skip = skip * curr.sectorSize; + curr.start += currPregap; + totalPregap = currPregap; + tracks.push_back(curr); + return true; + } + + Track &prev = *(tracks.end() - 1); + + // current track consumes data from the same file as the previous + if (prev.file == curr.file) { + curr.start += shift; + prev.length = curr.start + totalPregap - prev.start - skip; + curr.skip += prev.skip + (prev.length * prev.sectorSize) + (skip * curr.sectorSize); + totalPregap += currPregap; + curr.start += totalPregap; + // current track uses a different file as the previous track + } else { + uint64_t tmp = prev.file->getLength() - ((uint64_t) prev.skip); + prev.length = tmp / ((uint64_t) prev.sectorSize); + if (tmp % prev.sectorSize != 0) prev.length++; // padding + + curr.start += prev.start + prev.length + currPregap; + curr.skip = skip * curr.sectorSize; + shift += prev.start + prev.length; + totalPregap = currPregap; + } + + // error checks + if (curr.number <= 1) return false; + if (prev.number + 1 != curr.number) return false; + if (curr.start < prev.start + prev.length) return false; + if (curr.length < 0) return false; + + tracks.push_back(curr); + return true; +} + +bool CDROM_Interface_Image::HasDataTrack(void) +{ + //Data track has attribute 0x14 + for(track_it it = tracks.begin(); it != tracks.end(); it++) { + if ((*it).attr == DATA_TRACK) return true; + } + return false; +} + +bool CDROM_Interface_Image::HasAudioTracks(void) +{ + for(track_it it = tracks.begin(); it != tracks.end(); it++) { + if ((*it).attr == AUDIO_TRACK) return true; + } + return false; +} + + +bool CDROM_Interface_Image::GetRealFileName(string &filename, string &pathname) +{ + // check if file exists + struct stat test; + if (stat(filename.c_str(), &test) == 0) return true; + + // check if file with path relative to cue file exists + string tmpstr(pathname + "/" + filename); + if (stat(tmpstr.c_str(), &test) == 0) { + filename = tmpstr; + return true; + } +#if defined (WIN32) || defined(OS2) + //Nothing +#else + //Consider the possibility that the filename has a windows directory seperator (inside the CUE file) + //which is common for some commercial rereleases of DOS games using DOSBox + + string copy = filename; + size_t l = copy.size(); + for (size_t i = 0; i < l;i++) { + if(copy[i] == '\\') copy[i] = '/'; + } + + if (stat(copy.c_str(), &test) == 0) { + filename = copy; + return true; + } + + tmpstr = pathname + "/" + copy; + if (stat(tmpstr.c_str(), &test) == 0) { + filename = tmpstr; + return true; + } + +#endif + return false; +} + +bool CDROM_Interface_Image::GetCueKeyword(string &keyword, istream &in) +{ + in >> keyword; + for(Bitu i = 0; i < keyword.size(); i++) keyword[i] = toupper(keyword[i]); + + return true; +} + +bool CDROM_Interface_Image::GetCueFrame(uint64_t &frames, istream &in) +{ + string msf; + in >> msf; + int min, sec, fr; + bool success = sscanf(msf.c_str(), "%d:%d:%d", &min, &sec, &fr) == 3; + frames = MSF_TO_FRAMES(min, sec, fr); + + return success; +} + +bool CDROM_Interface_Image::GetCueString(string &str, istream &in) +{ + int pos = (int)in.tellg(); + in >> str; + if (str[0] == '\"') { + if (str[str.size() - 1] == '\"') { + str.assign(str, 1, str.size() - 2); + } else { + in.seekg(pos, ios::beg); + char buffer[MAX_FILENAME_LENGTH]; + in.getline(buffer, MAX_FILENAME_LENGTH, '\"'); // skip + in.getline(buffer, MAX_FILENAME_LENGTH, '\"'); + str = buffer; + } + } + return true; +} + +void CDROM_Interface_Image::ClearTracks() +{ + vector::iterator i = tracks.begin(); + vector::iterator end = tracks.end(); + + TrackFile* last = NULL; + while(i != end) { + Track &curr = *i; + if (curr.file != last) { + delete curr.file; + last = curr.file; + } + i++; + } + tracks.clear(); +} diff --git a/src/cdrom_dosbox.h b/src/cdrom_dosbox.h new file mode 100644 index 000000000..dc88bbe45 --- /dev/null +++ b/src/cdrom_dosbox.h @@ -0,0 +1,174 @@ +/* + * Copyright (C) 2002-2015 The DOSBox Team + * + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* Modified for use with PCem by bit */ + +#ifndef __CDROM_INTERFACE__ +#define __CDROM_INTERFACE__ + +#include +#include +#include +#include +#include +#include +//#include "dosbox.h" +//#include "mem.h" +//#include "mixer.h" +//#include "SDL.h" +//#include "SDL_thread.h" + +#include +typedef signed int Bits; +typedef unsigned int Bitu; +typedef int8_t Bit8s; +typedef uint8_t Bit8u; +typedef int16_t Bit16s; +typedef uint16_t Bit16u; +typedef int32_t Bit32s; +typedef uint32_t Bit32u; + +typedef size_t PhysPt; + +#define RAW_SECTOR_SIZE 2352 +#define COOKED_SECTOR_SIZE 2048 + +#define DATA_TRACK 0x14 +#define AUDIO_TRACK 0x10 + +#define CD_FPS 75 +#define FRAMES_TO_MSF(f, M,S,F) { \ + int value = f; \ + *(F) = value%CD_FPS; \ + value /= CD_FPS; \ + *(S) = value%60; \ + value /= 60; \ + *(M) = value; \ +} +#define MSF_TO_FRAMES(M, S, F) ((M)*60*CD_FPS+(S)*CD_FPS+(F)) + + +typedef struct SMSF { + unsigned char min; + unsigned char sec; + unsigned char fr; +} TMSF; + +typedef struct SCtrl { + Bit8u out[4]; // output channel + Bit8u vol[4]; // channel volume +} TCtrl; + +extern int CDROM_GetMountType(char* path, int force); + +class CDROM_Interface +{ +public: +// CDROM_Interface (void); + virtual ~CDROM_Interface (void) {}; + + virtual bool SetDevice (char* path, int forceCD) = 0; + + virtual bool GetUPC (unsigned char& attr, char* upc) = 0; + + virtual bool GetAudioTracks (int& stTrack, int& end, TMSF& leadOut) = 0; + virtual bool GetAudioTrackInfo (int track, int& number, TMSF& start, unsigned char& attr) = 0; + virtual bool GetAudioSub (int sector, unsigned char& attr, unsigned char& track, unsigned char& index, TMSF& relPos, TMSF& absPos) = 0; + virtual bool GetMediaTrayStatus (bool& mediaPresent, bool& mediaChanged, bool& trayOpen) = 0; + + virtual bool ReadSectors (PhysPt buffer, bool raw, unsigned long sector, unsigned long num) = 0; + + virtual bool LoadUnloadMedia (bool unload) = 0; + + virtual void InitNewMedia (void) {}; +}; + +class CDROM_Interface_Image : public CDROM_Interface +{ +private: + class TrackFile { + public: + virtual bool read(Bit8u *buffer, uint64_t seek, uint64_t count) = 0; + virtual uint64_t getLength() = 0; + virtual ~TrackFile() { }; + }; + + class BinaryFile : public TrackFile { + public: + BinaryFile(const char *filename, bool &error); + ~BinaryFile(); + bool read(Bit8u *buffer, uint64_t seek, uint64_t count); + uint64_t getLength(); + private: + BinaryFile(); + char fn[260]; + FILE *file; + }; + + struct Track { + int number; + int track_number; + int attr; + uint64_t start; + uint64_t length; + uint64_t skip; + uint64_t sectorSize; + bool mode2; + TrackFile *file; + }; + +public: + CDROM_Interface_Image (); + virtual ~CDROM_Interface_Image (void); + void InitNewMedia (void); + bool SetDevice (char* path, int forceCD); + bool GetUPC (unsigned char& attr, char* upc); + bool GetAudioTracks (int& stTrack, int& end, TMSF& leadOut); + bool GetAudioTrackInfo (int track, int& number, TMSF& start, unsigned char& attr); + bool GetAudioSub (int sector, unsigned char& attr, unsigned char& track, unsigned char& index, TMSF& relPos, TMSF& absPos); + bool GetMediaTrayStatus (bool& mediaPresent, bool& mediaChanged, bool& trayOpen); + bool ReadSectors (PhysPt buffer, bool raw, unsigned long sector, unsigned long num); + bool LoadUnloadMedia (bool unload); + bool ReadSector (Bit8u *buffer, bool raw, unsigned long sector); + bool IsMode2 (unsigned long sector); + bool HasDataTrack (void); + bool HasAudioTracks (void); + + int GetTrack (unsigned int sector); + +private: + // player +static void CDAudioCallBack(Bitu len); + + void ClearTracks(); + bool LoadIsoFile(char *filename); + bool CanReadPVD(TrackFile *file, uint64_t sectorSize, bool mode2); + // cue sheet processing + bool LoadCueSheet(char *cuefile); + bool GetRealFileName(std::string& filename, std::string& pathname); + bool GetCueKeyword(std::string &keyword, std::istream &in); + bool GetCueFrame(uint64_t &frames, std::istream &in); + bool GetCueString(std::string &str, std::istream &in); + bool AddTrack(Track &curr, uint64_t &shift, uint64_t prestart, uint64_t &totalPregap, uint64_t currPregap); + + std::vector tracks; +typedef std::vector::iterator track_it; + std::string mcn; +}; + +#endif /* __CDROM_INTERFACE__ */ diff --git a/src/cdrom_image.cc b/src/cdrom_image.cc new file mode 100644 index 000000000..204708742 --- /dev/null +++ b/src/cdrom_image.cc @@ -0,0 +1,1056 @@ +/* Copyright holders: RichardG867, Tenshi, bit + see COPYING for more details +*/ +/*CD-ROM image support*/ + +#include + +#include "config.h" +#include "cdrom_dosbox.h" +#include "cdrom.h" +#include "cdrom_image.h" +#include "cdrom_null.h" + +#define __USE_LARGEFILE64 +#define _LARGEFILE_SOURCE +#define _LARGEFILE64_SOURCE + +#include + +#define CD_STATUS_EMPTY 0 +#define CD_STATUS_DATA_ONLY 1 +#define CD_STATUS_PLAYING 2 +#define CD_STATUS_PAUSED 3 +#define CD_STATUS_STOPPED 4 + +/* The addresses sent from the guest are absolute, ie. a LBA of 0 corresponds to a MSF of 00:00:00. Otherwise, the counter displayed by the guest is wrong: + there is a seeming 2 seconds in which audio plays but counter does not move, while a data track before audio jumps to 2 seconds before the actual start + of the audio while audio still plays. With an absolute conversion, the counter is fine. */ +#define MSFtoLBA(m,s,f) ((((m*60)+s)*75)+f) + +extern CDROM image_cdrom; + +enum +{ + CD_STOPPED = 0, + CD_PLAYING, + CD_PAUSED +}; + +int cdrom_image_do_log = 0; + +CDROM_Interface_Image* cdimg[CDROM_NUM] = { NULL, NULL, NULL, NULL }; + +void cdrom_image_log(const char *format, ...) +{ +#ifdef ENABLE_CDROM_IMAGE_LOG + if (cdrom_image_do_log) + { + va_list ap; + va_start(ap, format); + vprintf(format, ap); + va_end(ap); + fflush(stdout); + } +#endif +} + +void image_close(uint8_t id); + +void image_audio_callback(uint8_t id, int16_t *output, int len) +{ + if (!cdrom_drives[id].sound_on || (cdrom_image[id].cd_state != CD_PLAYING) || cdrom_image[id].image_is_iso) + { + if (cdrom_ioctl[id].cd_state == CD_PLAYING) + { + cdrom[id].seek_pos += (len >> 11); + } + memset(output, 0, len * 2); + return; + } + while (cdrom_image[id].cd_buflen < len) + { + if (cdrom[id].seek_pos < cdrom_image[id].cd_end) + { + if (!cdimg[id]->ReadSector((unsigned char*)&cdrom_image[id].cd_buffer[cdrom_image[id].cd_buflen], true, cdrom[id].seek_pos - 150)) + { + memset(&cdrom_image[id].cd_buffer[cdrom_image[id].cd_buflen], 0, (BUF_SIZE - cdrom_image[id].cd_buflen) * 2); + cdrom_image[id].cd_state = CD_STOPPED; + cdrom_image[id].cd_buflen = len; + } + else + { + cdrom[id].seek_pos++; + cdrom_image[id].cd_buflen += (RAW_SECTOR_SIZE / 2); + } + } + else + { + memset(&cdrom_image[id].cd_buffer[cdrom_image[id].cd_buflen], 0, (BUF_SIZE - cdrom_image[id].cd_buflen) * 2); + cdrom_image[id].cd_state = CD_STOPPED; + cdrom_image[id].cd_buflen = len; + } + } + memcpy(output, cdrom_image[id].cd_buffer, len * 2); + memmove(cdrom_image[id].cd_buffer, &cdrom_image[id].cd_buffer[len], (BUF_SIZE - len) * 2); + cdrom_image[id].cd_buflen -= len; +} + +void image_audio_stop(uint8_t id) +{ + cdrom_image[id].cd_state = CD_STOPPED; +} + +static void image_playaudio(uint8_t id, uint32_t pos, uint32_t len, int ismsf) +{ + if (!cdimg[id]) return; + int number; + unsigned char attr; + TMSF tmsf; + int m = 0, s = 0, f = 0; + cdimg[id]->GetAudioTrackInfo(cdimg[id]->GetTrack(pos), number, tmsf, attr); + if (attr == DATA_TRACK) + { + cdrom_image_log("Can't play data track\n"); + cdrom[id].seek_pos = 0; + cdrom_image[id].cd_state = CD_STOPPED; + return; + } + cdrom_image_log("Play audio - %08X %08X %i\n", pos, len, ismsf); + if (ismsf == 2) + { + cdimg[id]->GetAudioTrackInfo(pos, number, tmsf, attr); + pos = MSFtoLBA(tmsf.min, tmsf.sec, tmsf.fr); + cdimg[id]->GetAudioTrackInfo(len, number, tmsf, attr); + len = MSFtoLBA(tmsf.min, tmsf.sec, tmsf.fr); + } + else if (ismsf == 1) + { + m = (pos >> 16) & 0xff; + s = (pos >> 8) & 0xff; + f = pos & 0xff; + + if (pos == 0xffffff) + { + cdrom_image_log("Playing from current position (MSF)\n"); + pos = cdrom[id].seek_pos; + } + else + { + pos = MSFtoLBA(m, s, f); + } + + m = (len >> 16) & 0xff; + s = (len >> 8) & 0xff; + f = len & 0xff; + len = MSFtoLBA(m, s, f); + + cdrom_image_log("MSF - pos = %08X len = %08X\n", pos, len); + } + else if (ismsf == 0) + { + if (pos == 0xffffffff) + { + cdrom_image_log("Playing from current position\n"); + pos = cdrom[id].seek_pos; + } + len += pos; + } + cdrom[id].seek_pos = pos; + cdrom_image[id].cd_end = len; + cdrom_image[id].cd_state = CD_PLAYING; + if (cdrom[id].seek_pos < 150) + cdrom[id].seek_pos = 150; + cdrom_image[id].cd_buflen = 0; +} + +static void image_pause(uint8_t id) +{ + if (!cdimg[id] || cdrom_image[id].image_is_iso) return; + if (cdrom_image[id].cd_state == CD_PLAYING) + cdrom_image[id].cd_state = CD_PAUSED; +} + +static void image_resume(uint8_t id) +{ + if (!cdimg[id] || cdrom_image[id].image_is_iso) return; + if (cdrom_image[id].cd_state == CD_PAUSED) + cdrom_image[id].cd_state = CD_PLAYING; +} + +static void image_stop(uint8_t id) +{ + if (!cdimg[id] || cdrom_image[id].image_is_iso) return; + cdrom_image[id].cd_state = CD_STOPPED; +} + +static int image_ready(uint8_t id) +{ + if (!cdimg[id]) + return 0; + + if (wcslen(cdrom_image[id].image_path) == 0) + return 0; + + if (cdrom_drives[id].prev_host_drive != cdrom_drives[id].host_drive) + { + return 1; + } + + if (cdrom_image[id].image_changed) + { + cdrom_image[id].image_changed = 0; + return 1; + } + + return 1; +} + +static int image_get_last_block(uint8_t id, uint8_t starttrack, int msf, int maxlen, int single) +{ + int c; + uint32_t lb=0; + + if (!cdimg[id]) return 0; + + int first_track; + int last_track; + int number; + unsigned char attr; + TMSF tmsf; + cdimg[id]->GetAudioTracks(first_track, last_track, tmsf); + + for (c = 0; c <= last_track; c++) + { + uint32_t address; + cdimg[id]->GetAudioTrackInfo(c+1, number, tmsf, attr); + address = MSFtoLBA(tmsf.min, tmsf.sec, tmsf.fr) - 150; /* Do the - 150 here as well. */ + if (address > lb) + lb = address; + } + return lb; +} + +static int image_medium_changed(uint8_t id) +{ + if (!cdimg[id]) + return 0; + + if (wcslen(cdrom_image[id].image_path) == 0) + { + return 0; + } + + if (cdrom_drives[id].prev_host_drive != cdrom_drives[id].host_drive) + { + cdrom_drives[id].prev_host_drive = cdrom_drives[id].host_drive; + return 1; + } + + if (cdrom_image[id].image_changed) + { + cdrom_image[id].image_changed = 0; + return 1; + } + + return 0; +} + +static uint8_t image_getcurrentsubchannel(uint8_t id, uint8_t *b, int msf) +{ + if (!cdimg[id]) return 0; + uint8_t ret; + int pos=0; + + uint32_t cdpos = cdrom[id].seek_pos; + if (cdpos >= 150) cdpos -= 150; + TMSF relPos, absPos; + unsigned char attr, track, index; + cdimg[id]->GetAudioSub(cdpos, attr, track, index, relPos, absPos); + + if (cdrom_image[id].image_is_iso) + { + ret = 0x15; + } + else + { + if (cdrom_image[id].cd_state == CD_PLAYING) + ret = 0x11; + else if (cdrom_image[id].cd_state == CD_PAUSED) + ret = 0x12; + else + ret = 0x13; + } + + b[pos++] = attr; + b[pos++] = track; + b[pos++] = index; + + if (msf) + { + b[pos + 3] = (uint8_t) absPos.fr; + b[pos + 2] = (uint8_t) absPos.sec; + b[pos + 1] = (uint8_t) absPos.min; + b[pos] = 0; + pos += 4; + b[pos + 3] = (uint8_t) relPos.fr; + b[pos + 2] = (uint8_t) relPos.sec; + b[pos + 1] = (uint8_t) relPos.min; + b[pos] = 0; + pos += 4; + } + else + { + uint32_t dat = MSFtoLBA(absPos.min, absPos.sec, absPos.fr) - 150; + b[pos++] = (dat >> 24) & 0xff; + b[pos++] = (dat >> 16) & 0xff; + b[pos++] = (dat >> 8) & 0xff; + b[pos++] = dat & 0xff; + dat = MSFtoLBA(relPos.min, relPos.sec, relPos.fr); + b[pos++] = (dat >> 24) & 0xff; + b[pos++] = (dat >> 16) & 0xff; + b[pos++] = (dat >> 8) & 0xff; + b[pos++] = dat & 0xff; + } + + return ret; +} + +static void image_eject(uint8_t id) +{ + return; +} + +static void image_load(uint8_t id) +{ + return; +} + +static int image_is_track_audio(uint8_t id, uint32_t pos, int ismsf) +{ + int m, s, f; + unsigned char attr; + TMSF tmsf; + int number; + + if (!cdimg[id] || cdrom_image[id].image_is_iso) return 0; + + if (ismsf) + { + m = (pos >> 16) & 0xff; + s = (pos >> 8) & 0xff; + f = pos & 0xff; + pos = MSFtoLBA(m, s, f); + } + else + { + pos += 150; + } + + cdimg[id]->GetAudioTrackInfo(cdimg[id]->GetTrack(pos), number, tmsf, attr); + + return attr == AUDIO_TRACK; +} + +typedef struct __attribute__((__packed__)) +{ + uint8_t user_data[2048]; + uint8_t ecc[288]; +} m1_data_t; + +typedef struct __attribute__((__packed__)) +{ + uint8_t sub_header[8]; + uint8_t user_data[2328]; +} m2_data_t; + +typedef union __attribute__((__packed__)) +{ + m1_data_t m1_data; + m2_data_t m2_data; + uint8_t raw_data[2336]; +} sector_data_t; + +typedef struct __attribute__((__packed__)) +{ + uint8_t sync[12]; + uint8_t header[4]; + sector_data_t data; +} sector_raw_data_t; + +typedef union __attribute__((__packed__)) +{ + sector_raw_data_t sector_data; + uint8_t raw_data[2352]; +} sector_t; + +typedef struct __attribute__((__packed__)) +{ + sector_t sector; + uint8_t c2[296]; + uint8_t subchannel_raw[96]; + uint8_t subchannel_q[16]; + uint8_t subchannel_rw[96]; +} cdrom_sector_t; + +typedef union __attribute__((__packed__)) +{ + cdrom_sector_t cdrom_sector; + uint8_t buffer[2856]; +} sector_buffer_t; + +sector_buffer_t cdrom_sector_buffer; + +int cdrom_sector_size; +uint8_t raw_buffer[2352]; +uint8_t extra_buffer[296]; + +static int image_readsector_raw(uint8_t id, uint8_t *buffer, int sector, int ismsf, int cdrom_sector_type, int cdrom_sector_flags, int *len) +{ + uint8_t *b; + uint8_t *temp_b; + int real_pos; + int audio; + int mode2; + + if (!cdimg[id]) + { + return 0; + } + + if (!cdrom_drives[id].host_drive) + { + return 0; + } + + b = temp_b = buffer; + + *len = 0; + + if (ismsf) + { + real_pos = cdrom_lba_to_msf_accurate(sector); + } + else + { + real_pos = sector; + } + + if (cdrom_image[id].image_is_iso) + { + audio = 0; + mode2 = cdimg[id]->IsMode2(real_pos) ? 1 : 0; + } + else + { + audio = image_is_track_audio(id, real_pos, 1); + mode2 = cdimg[id]->IsMode2(real_pos) ? 1 : 0; + } + + memset(raw_buffer, 0, 2352); + memset(extra_buffer, 0, 296); + + if (!(cdrom_sector_flags & 0xf0)) /* 0x00 and 0x08 are illegal modes */ + { + cdrom_image_log("CD-ROM %i: [Mode 1] 0x00 and 0x08 are illegal modes\n", id); + return 0; + } + + if ((cdrom_sector_type == 3) || ((cdrom_sector_type > 4) && (cdrom_sector_type != 8))) + { + if (cdrom_sector_type == 3) + { + cdrom_image_log("CD-ROM %i: Attempting to read a Yellowbook Mode 2 data sector from an image\n", id); + } + if (cdrom_sector_type > 4) + { + cdrom_image_log("CD-ROM %i: Attempting to read a XA Mode 2 Form 2 data sector from an image\n", id); + } + return 0; + } + else if (cdrom_sector_type == 1) + { + if (!audio || cdrom_image[id].image_is_iso) + { + cdrom_image_log("CD-ROM %i: [Audio] Attempting to read an audio sector from a data image\n", id); + return 0; + } + +read_audio: + cdimg[id]->ReadSector(raw_buffer, true, real_pos); + memcpy(temp_b, raw_buffer, 2352); + } + else if (cdrom_sector_type == 2) + { + if (audio || mode2) + { + cdrom_image_log("CD-ROM %i: [Mode 1] Attempting to read a non-Mode 1 sector from an audio track\n", id); + return 0; + } + +read_mode1: + if ((cdrom_sector_flags & 0x06) == 0x06) + { + cdrom_image_log("CD-ROM %i: [Mode 1] Invalid error flags\n", id); + return 0; + } + + if (((cdrom_sector_flags & 0x700) == 0x300) || ((cdrom_sector_flags & 0x700) > 0x400)) + { + cdrom_image_log("CD-ROM %i: [Mode 1] Invalid subchannel data flags (%02X)\n", id, cdrom_sector_flags & 0x700); + return 0; + } + + if ((cdrom_sector_flags & 0x18) == 0x08) /* EDC/ECC without user data is an illegal mode */ + { + cdrom_image_log("CD-ROM %i: [Mode 1] EDC/ECC without user data is an illegal mode\n", id); + return 0; + } + + if (cdrom_image[id].image_is_iso) + { + cdimg[id]->ReadSector(raw_buffer + 16, false, real_pos); + + uint8_t *bb = raw_buffer; + + /* sync bytes */ + bb[0] = 0; + memset(bb + 1, 0xff, 10); + bb[11] = 0; + bb += 12; + + bb[0] = (real_pos >> 16) & 0xff; + bb[1] = (real_pos >> 8) & 0xff; + bb[2] = real_pos & 0xff; + + bb[3] = 1; /* mode 1 data */ + bb += 4; + bb += 2048; + memset(bb, 0, 288); + } + else + { + cdimg[id]->ReadSector(raw_buffer, true, real_pos); + } + + cdrom_sector_size = 0; + + if (cdrom_sector_flags & 0x80) /* Sync */ + { + cdrom_image_log("CD-ROM %i: [Mode 1] Sync\n", id); + memcpy(temp_b, raw_buffer, 12); + cdrom_sector_size += 12; + temp_b += 12; + } + + if (cdrom_sector_flags & 0x20) /* Header */ + { + cdrom_image_log("CD-ROM %i: [Mode 1] Header\n", id); + memcpy(temp_b, raw_buffer + 12, 4); + cdrom_sector_size += 4; + temp_b += 4; + } + + /* Mode 1 sector, expected type is 1 type. */ + if (cdrom_sector_flags & 0x40) /* Sub-header */ + { + if (!(cdrom_sector_flags & 0x10)) /* No user data */ + { + cdrom_image_log("CD-ROM %i: [Mode 1] Sub-header\n", id); + memcpy(temp_b, raw_buffer + 16, 8); + cdrom_sector_size += 8; + temp_b += 8; + } + } + + if (cdrom_sector_flags & 0x10) /* User data */ + { + cdrom_image_log("CD-ROM %i: [Mode 1] User data\n", id); + memcpy(temp_b, raw_buffer + 16, 2048); + cdrom_sector_size += 2048; + temp_b += 2048; + } + + if (cdrom_sector_flags & 0x08) /* EDC/ECC */ + { + cdrom_image_log("CD-ROM %i: [Mode 1] EDC/ECC\n", id); + memcpy(temp_b, raw_buffer + 2064, 288); + cdrom_sector_size += 288; + temp_b += 288; + } + } + else if (cdrom_sector_type == 4) + { + if (audio || !mode2) + { + cdrom_image_log("CD-ROM %i: [XA Mode 2 Form 1] Attempting to read a non-XA Mode 2 Form 1 sector from an audio track\n", id); + return 0; + } + +read_mode2: + if (!(cdrom_sector_flags & 0xf0)) /* 0x00 and 0x08 are illegal modes */ + { + cdrom_image_log("CD-ROM %i: [XA Mode 2 Form 1] 0x00 and 0x08 are illegal modes\n", id); + return 0; + } + + if (((cdrom_sector_flags & 0xf0) == 0xb0) || ((cdrom_sector_flags & 0xf0) == 0xd0)) /* 0xBx and 0xDx are illegal modes */ + { + cdrom_image_log("CD-ROM %i: [XA Mode 2 Form 1] 0xBx and 0xDx are illegal modes\n", id); + return 0; + } + + if ((cdrom_sector_flags & 0x06) == 0x06) + { + cdrom_image_log("CD-ROM %i: [XA Mode 2 Form 1] Invalid error flags\n", id); + return 0; + } + + if (((cdrom_sector_flags & 0x700) == 0x300) || ((cdrom_sector_flags & 0x700) > 0x400)) + { + cdrom_image_log("CD-ROM %i: [XA Mode 2 Form 1] Invalid subchannel data flags (%02X)\n", id, cdrom_sector_flags & 0x700); + return 0; + } + + if ((cdrom_sector_flags & 0x18) == 0x08) /* EDC/ECC without user data is an illegal mode */ + { + cdrom_image_log("CD-ROM %i: [XA Mode 2 Form 1] EDC/ECC without user data is an illegal mode\n", id); + return 0; + } + + if (cdrom_image[id].image_is_iso) + { + cdimg[id]->ReadSector(raw_buffer + 24, false, real_pos); + + uint8_t *bb = raw_buffer; + + /* sync bytes */ + bb[0] = 0; + memset(bb + 1, 0xff, 10); + bb[11] = 0; + bb += 12; + + bb[0] = (real_pos >> 16) & 0xff; + bb[1] = (real_pos >> 8) & 0xff; + bb[2] = real_pos & 0xff; + + bb[3] = 1; /* mode 1 data */ + bb += 12; + bb += 2048; + memset(bb, 0, 280); + } + else + { + cdimg[id]->ReadSector(raw_buffer, true, real_pos); + } + + cdrom_sector_size = 0; + + if (cdrom_sector_flags & 0x80) /* Sync */ + { + cdrom_image_log("CD-ROM %i: [XA Mode 2 Form 1] Sync\n", id); + memcpy(temp_b, raw_buffer, 12); + cdrom_sector_size += 12; + temp_b += 12; + } + + if (cdrom_sector_flags & 0x20) /* Header */ + { + cdrom_image_log("CD-ROM %i: [XA Mode 2 Form 1] Header\n", id); + memcpy(temp_b, raw_buffer + 12, 4); + cdrom_sector_size += 4; + temp_b += 4; + } + + /* Mode 1 sector, expected type is 1 type. */ + if (cdrom_sector_flags & 0x40) /* Sub-header */ + { + cdrom_image_log("CD-ROM %i: [XA Mode 2 Form 1] Sub-header\n", id); + memcpy(temp_b, raw_buffer + 16, 8); + cdrom_sector_size += 8; + temp_b += 8; + } + + if (cdrom_sector_flags & 0x10) /* User data */ + { + cdrom_image_log("CD-ROM %i: [XA Mode 2 Form 1] User data\n", id); + memcpy(temp_b, raw_buffer + 24, 2048); + cdrom_sector_size += 2048; + temp_b += 2048; + } + + if (cdrom_sector_flags & 0x08) /* EDC/ECC */ + { + cdrom_image_log("CD-ROM %i: [XA Mode 2 Form 1] EDC/ECC\n", id); + memcpy(temp_b, raw_buffer + 2072, 280); + cdrom_sector_size += 280; + temp_b += 280; + } + } + else if (cdrom_sector_type == 8) + { + if (audio) + { + cdrom_image_log("CD-ROM %i: [Any Data] Attempting to read a data sector from an audio track\n", id); + return 0; + } + + if (mode2) + { + goto read_mode2; + } + else + { + goto read_mode1; + } + } + else + { + if (mode2) + { + goto read_mode2; + } + else + { + if (audio) + { + goto read_audio; + } + else + { + goto read_mode1; + } + } + } + + if ((cdrom_sector_flags & 0x06) == 0x02) + { + /* Add error flags. */ + cdrom_image_log("CD-ROM %i: Error flags\n", id); + memcpy(b + cdrom_sector_size, extra_buffer, 294); + cdrom_sector_size += 294; + } + else if ((cdrom_sector_flags & 0x06) == 0x04) + { + /* Add error flags. */ + cdrom_image_log("CD-ROM %i: Full error flags\n", id); + memcpy(b + cdrom_sector_size, extra_buffer, 296); + cdrom_sector_size += 296; + } + + if ((cdrom_sector_flags & 0x700) == 0x100) + { + cdrom_image_log("CD-ROM %i: Raw subchannel data\n", id); + memcpy(b + cdrom_sector_size, extra_buffer, 96); + cdrom_sector_size += 96; + } + else if ((cdrom_sector_flags & 0x700) == 0x200) + { + cdrom_image_log("CD-ROM %i: Q subchannel data\n", id); + memcpy(b + cdrom_sector_size, extra_buffer, 16); + cdrom_sector_size += 16; + } + else if ((cdrom_sector_flags & 0x700) == 0x400) + { + cdrom_image_log("CD-ROM %i: R/W subchannel data\n", id); + memcpy(b + cdrom_sector_size, extra_buffer, 96); + cdrom_sector_size += 96; + } + + *len = cdrom_sector_size; + + return 1; +} + + +static uint32_t image_size(uint8_t id) +{ + return cdrom_image[id].cdrom_capacity; +} + +static int image_readtoc(uint8_t id, unsigned char *b, unsigned char starttrack, int msf, int maxlen, int single) +{ + if (!cdimg[id]) return 0; + int len=4; + int c,d; + uint32_t temp; + + int first_track; + int last_track; + int number; + unsigned char attr; + TMSF tmsf; + cdimg[id]->GetAudioTracks(first_track, last_track, tmsf); + + b[2] = first_track; + b[3] = last_track; + + d = 0; + for (c = 0; c <= last_track; c++) + { + cdimg[id]->GetAudioTrackInfo(c+1, number, tmsf, attr); + if (number >= starttrack) + { + d=c; + break; + } + } + cdimg[id]->GetAudioTrackInfo(c+1, number, tmsf, attr); + b[2] = number; + + for (c = d; c <= last_track; c++) + { + if ((len + 8) > maxlen) + break; + cdimg[id]->GetAudioTrackInfo(c+1, number, tmsf, attr); + + b[len++] = 0; /* reserved */ + b[len++] = attr; + b[len++] = number; /* track number */ + b[len++] = 0; /* reserved */ + + if (msf) + { + b[len++] = 0; + b[len++] = tmsf.min; + b[len++] = tmsf.sec; + b[len++] = tmsf.fr; + } + else + { + temp = MSFtoLBA(tmsf.min, tmsf.sec, tmsf.fr) - 150; + b[len++] = temp >> 24; + b[len++] = temp >> 16; + b[len++] = temp >> 8; + b[len++] = temp; + } + if (single) + break; + } + b[0] = (uint8_t)(((len-2) >> 8) & 0xff); + b[1] = (uint8_t)((len-2) & 0xff); + return len; +} + +static int image_readtoc_session(uint8_t id, unsigned char *b, int msf, int maxlen) +{ + int len = 4; + + int number; + TMSF tmsf; + unsigned char attr; + + if (!cdimg[id]) return 0; + + cdimg[id]->GetAudioTrackInfo(1, number, tmsf, attr); + + if (number == 0) + { + number = 1; + } + + b[2] = 1; + b[3] = 1; + b[len++] = 0; /* reserved */ + b[len++] = attr; + b[len++] = number; /* track number */ + b[len++] = 0; /* reserved */ + if (msf) + { + b[len++] = 0; + b[len++] = tmsf.min; + b[len++] = tmsf.sec; + b[len++] = tmsf.fr; + } + else + { + uint32_t temp = MSFtoLBA(tmsf.min, tmsf.sec, tmsf.fr) - 150; /* Do the - 150. */ + b[len++] = temp >> 24; + b[len++] = temp >> 16; + b[len++] = temp >> 8; + b[len++] = temp; + } + + if (maxlen < len) + { + return maxlen; + } + + return len; +} + +static int image_readtoc_raw(uint8_t id, unsigned char *b, int maxlen) +{ + int track; + int len = 4; + + int first_track; + int last_track; + int number; + unsigned char attr; + TMSF tmsf; + + if (!cdimg[id]) return 0; + + cdimg[id]->GetAudioTracks(first_track, last_track, tmsf); + + b[2] = first_track; + b[3] = last_track; + + for (track = first_track; track <= last_track; track++) + { + if ((len + 11) > maxlen) + { + cdrom_image_log("image_readtocraw: This iteration would fill the buffer beyond the bounds, aborting...\n"); + return len; + } + + cdimg[id]->GetAudioTrackInfo(track, number, tmsf, attr); + + b[len++] = track; + b[len++]= attr; + b[len++]=0; + b[len++]=0; + b[len++]=0; + b[len++]=0; + b[len++]=0; + b[len++]=0; + b[len++] = tmsf.min; + b[len++] = tmsf.sec; + b[len++] = tmsf.fr; + } + return len; +} + +static int image_status(uint8_t id) +{ + if (!cdimg[id]) return CD_STATUS_EMPTY; + if (cdrom_image[id].image_is_iso) return CD_STATUS_DATA_ONLY; + if (cdimg[id]->HasAudioTracks()) + { + switch(cdrom_image[id].cd_state) + { + case CD_PLAYING: + return CD_STATUS_PLAYING; + case CD_PAUSED: + return CD_STATUS_PAUSED; + case CD_STOPPED: + default: + return CD_STATUS_STOPPED; + } + } + return CD_STATUS_DATA_ONLY; +} + +void image_reset(uint8_t id) +{ + return; +} + +void image_close(uint8_t id) +{ + cdrom_image[id].cd_state = CD_STOPPED; + if (cdimg[id]) + { + delete cdimg[id]; + cdimg[id] = NULL; + } + memset(cdrom_image[id].image_path, 0, 2048); +} + +static char afn[1024]; + +int image_open(uint8_t id, wchar_t *fn) +{ + if (wcscmp(fn, cdrom_image[id].image_path) != 0) + { + cdrom_image[id].image_changed = 1; + } + + /* Make sure image_changed stays when changing from an image to another image. */ + if (!cdrom_image[id].image_inited && (cdrom_drives[id].host_drive != 200)) cdrom_image[id].image_changed = 0; + + if (!cdrom_image[id].image_inited || cdrom_image[id].image_changed) + { + _swprintf(cdrom_image[id].image_path, L"%ws", fn); + } + + if (!wcsicmp(get_extension_w(fn), L"ISO")) + { + cdrom_image[id].image_is_iso = 1; + } + else + { + cdrom_image[id].image_is_iso = 0; + } + + cdimg[id] = new CDROM_Interface_Image(); + wcstombs(afn, fn, (wcslen(fn) << 1) + 2); + if (!cdimg[id]->SetDevice(afn, false)) + { + image_close(id); + cdrom_set_null_handler(id); + return 1; + } + cdrom_image[id].cd_state = CD_STOPPED; + cdrom[id].seek_pos = 0; + cdrom_image[id].cd_buflen = 0; + cdrom_image[id].cdrom_capacity = image_get_last_block(id, 0, 0, 4096, 0) + 1; + cdrom_drives[id].handler = &image_cdrom; + + if (!cdrom_image[id].image_inited || cdrom_image[id].image_changed) + { + if (!cdrom_image[id].image_inited) + cdrom_image[id].image_inited = 1; + } + + return 0; +} + +static void image_exit(uint8_t id) +{ + cdrom_image[id].image_inited = 0; +} + +/* TODO: Check for what data type a mixed CD is. */ +static int image_media_type_id(uint8_t id) +{ + if (!cdrom_image[id].image_is_iso) + { + return 3; /* Mixed mode CD. */ + } + + if (image_size(id) <= 405000) + { + return 1; /* Data CD. */ + } + else + { + return 65; /* DVD. */ + } +} + +CDROM image_cdrom = +{ + image_ready, + image_medium_changed, + image_media_type_id, + image_audio_callback, + image_audio_stop, + image_readtoc, + image_readtoc_session, + image_readtoc_raw, + image_getcurrentsubchannel, + NULL, + image_readsector_raw, + image_playaudio, + image_load, + image_eject, + image_pause, + image_resume, + image_size, + image_status, + image_is_track_audio, + image_stop, + image_exit +}; diff --git a/src/cdrom_image.h b/src/cdrom_image.h new file mode 100644 index 000000000..4ea4cb78f --- /dev/null +++ b/src/cdrom_image.h @@ -0,0 +1,28 @@ +/* Copyright holders: RichardG867, Tenshi + see COPYING for more details +*/ +#ifndef CDROM_IMAGE_H +#define CDROM_IMAGE_H + +/* this header file lists the functions provided by + various platform specific cdrom-ioctl files */ + +#ifdef __cplusplus +extern "C" { +#endif + +extern int image_open(uint8_t id, wchar_t *fn); +extern void image_reset(uint8_t id); + +extern void image_close(uint8_t id); + +void update_status_bar_icon_state(int tag, int state); +extern void cdrom_set_null_handler(uint8_t id); + +void pclog(const char *format, ...); + +#ifdef __cplusplus +} +#endif + +#endif /* ! CDROM_IMAGE_H */ diff --git a/src/cdrom_ioctl.c b/src/cdrom_ioctl.c new file mode 100644 index 000000000..0b32b79b7 --- /dev/null +++ b/src/cdrom_ioctl.c @@ -0,0 +1,1312 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Implementation of the CD-ROM host drive IOCTL interface for + * Windows using SCSI Passthrough Direct. + * + * Version: @(#)cdrom_ioctl.c 1.0.2 2017/06/03 + * + * Authors: Sarah Walker, + * Miran Grca, + * Copyright 2008-2016 Sarah Walker. + * Copyright 2016-2017 Miran Grca. + */ +#define WINVER 0x0600 +#include +#include +#include "ntddcdrm.h" +#include "ntddscsi.h" +#include "ibm.h" +#include "cdrom.h" +#include "cdrom_ioctl.h" +#include "scsi.h" + +#define MSFtoLBA(m,s,f) ((((m*60)+s)*75)+f) + +static CDROM ioctl_cdrom; + +typedef struct +{ + HANDLE hIOCTL; + CDROM_TOC toc; + int is_playing; +} cdrom_ioctl_windows_t; + +cdrom_ioctl_windows_t cdrom_ioctl_windows[CDROM_NUM]; + +enum +{ + CD_STOPPED = 0, + CD_PLAYING, + CD_PAUSED +}; + +int cdrom_ioctl_do_log = 0; + +void cdrom_ioctl_log(const char *format, ...) +{ +#ifdef ENABLE_CDROM_LOG + if (cdrom_ioctl_do_log) + { + va_list ap; + va_start(ap, format); + vprintf(format, ap); + va_end(ap); + fflush(stdout); + } +#endif +} + +static int ioctl_hopen(uint8_t id); + +void ioctl_audio_callback(uint8_t id, int16_t *output, int len) +{ + RAW_READ_INFO in; + DWORD count; + + if (!cdrom_drives[id].sound_on || (cdrom_ioctl[id].cd_state != CD_PLAYING)) + { + if (cdrom_ioctl[id].cd_state == CD_PLAYING) + { + cdrom[id].seek_pos += (len >> 11); + } + memset(output, 0, len * 2); + return; + } + while (cdrom_ioctl[id].cd_buflen < len) + { + if (cdrom[id].seek_pos < cdrom_ioctl[id].cd_end) + { + in.DiskOffset.LowPart = (cdrom[id].seek_pos - 150) * 2048; + in.DiskOffset.HighPart = 0; + in.SectorCount = 1; + in.TrackMode = CDDA; + if (!DeviceIoControl(cdrom_ioctl_windows[id].hIOCTL, IOCTL_CDROM_RAW_READ, &in, sizeof(in), &(cdrom_ioctl[id].cd_buffer[cdrom_ioctl[id].cd_buflen]), 2352, &count, NULL)) + { + memset(&(cdrom_ioctl[id].cd_buffer[cdrom_ioctl[id].cd_buflen]), 0, (BUF_SIZE - cdrom_ioctl[id].cd_buflen) * 2); + cdrom_ioctl_windows[id].is_playing = 0; + ioctl_close(id); + cdrom_ioctl[id].cd_state = CD_STOPPED; + cdrom_ioctl[id].cd_buflen = len; + } + else + { + cdrom[id].seek_pos++; + cdrom_ioctl[id].cd_buflen += (2352 / 2); + } + } + else + { + memset(&(cdrom_ioctl[id].cd_buffer[cdrom_ioctl[id].cd_buflen]), 0, (BUF_SIZE - cdrom_ioctl[id].cd_buflen) * 2); + cdrom_ioctl_windows[id].is_playing = 0; + ioctl_close(id); + cdrom_ioctl[id].cd_state = CD_STOPPED; + cdrom_ioctl[id].cd_buflen = len; + } + } + memcpy(output, cdrom_ioctl[id].cd_buffer, len * 2); + memcpy(&cdrom_ioctl[id].cd_buffer[0], &(cdrom_ioctl[id].cd_buffer[len]), (BUF_SIZE - len) * 2); + cdrom_ioctl[id].cd_buflen -= len; +} + +void ioctl_audio_stop(uint8_t id) +{ + cdrom_ioctl_windows[id].is_playing = 0; + ioctl_close(id); + cdrom_ioctl[id].cd_state = CD_STOPPED; +} + +static int get_track_nr(uint8_t id, uint32_t pos) +{ + int c; + int track = 0; + + if (!cdrom_ioctl[id].tocvalid) + { + return 0; + } + + if (cdrom_ioctl[id].last_track_pos == pos) + { + return cdrom_ioctl[id].last_track_nr; + } + + for (c = cdrom_ioctl_windows[id].toc.FirstTrack; c < cdrom_ioctl_windows[id].toc.LastTrack; c++) + { + uint32_t track_address = cdrom_ioctl_windows[id].toc.TrackData[c].Address[3] + + (cdrom_ioctl_windows[id].toc.TrackData[c].Address[2] * 75) + + (cdrom_ioctl_windows[id].toc.TrackData[c].Address[1] * 75 * 60); + + if (track_address <= pos) + { + track = c; + } + } + cdrom_ioctl[id].last_track_pos = pos; + cdrom_ioctl[id].last_track_nr = track; + + return track; +} + +static uint32_t get_track_msf(uint8_t id, uint32_t track_no) +{ + int c; + + if (!cdrom_ioctl[id].tocvalid) + { + return 0; + } + + for (c = cdrom_ioctl_windows[id].toc.FirstTrack; c < cdrom_ioctl_windows[id].toc.LastTrack; c++) + { + if (c == track_no) + { + return cdrom_ioctl_windows[id].toc.TrackData[c].Address[3] + (cdrom_ioctl_windows[id].toc.TrackData[c].Address[2] << 8) + (cdrom_ioctl_windows[id].toc.TrackData[c].Address[1] << 16); + } + } + return 0xffffffff; +} + +static void ioctl_playaudio(uint8_t id, uint32_t pos, uint32_t len, int ismsf) +{ + int m = 0, s = 0, f = 0; + uint32_t start_msf = 0, end_msf = 0; + if (!cdrom_drives[id].host_drive) + { + return; + } + if (ismsf == 2) + { + start_msf = get_track_msf(id, pos); + end_msf = get_track_msf(id, len); + if (start_msf == 0xffffffff) + { + return; + } + if (end_msf == 0xffffffff) + { + return; + } + m = (start_msf >> 16) & 0xff; + s = (start_msf >> 8) & 0xff; + f = start_msf & 0xff; + pos = MSFtoLBA(m, s, f); + m = (end_msf >> 16) & 0xff; + s = (end_msf >> 8) & 0xff; + f = end_msf & 0xff; + len = MSFtoLBA(m, s, f); + } + else if (ismsf == 1) + { + m = (pos >> 16) & 0xff; + s = (pos >> 8) & 0xff; + f = pos & 0xff; + + if (pos == 0xffffff) + { + cdrom_ioctl_log("Playing from current position (MSF)\n"); + pos = cdrom[id].seek_pos; + } + else + { + pos = MSFtoLBA(m, s, f); + } + + m = (len >> 16) & 0xff; + s = (len >> 8) & 0xff; + f = len & 0xff; + len = MSFtoLBA(m, s, f); + } + else if (ismsf == 0) + { + if (pos == 0xffffffff) + { + cdrom_ioctl_log("Playing from current position\n"); + pos = cdrom[id].seek_pos; + } + len += pos; + } + cdrom[id].seek_pos = pos; + cdrom_ioctl[id].cd_end = len; + if (cdrom[id].seek_pos < 150) + { + /* Adjust because the host expects a minimum adjusted LBA of 0 which is equivalent to an absolute LBA of 150. */ + cdrom[id].seek_pos = 150; + } + if (!cdrom_ioctl_windows[id].is_playing) + { + ioctl_hopen(id); + cdrom_ioctl_windows[id].is_playing = 1; + } + cdrom_ioctl[id].cd_state = CD_PLAYING; +} + +static void ioctl_pause(uint8_t id) +{ + if (!cdrom_drives[id].host_drive) + { + return; + } + if (cdrom_ioctl[id].cd_state == CD_PLAYING) + { + cdrom_ioctl[id].cd_state = CD_PAUSED; + } +} + +static void ioctl_resume(uint8_t id) +{ + if (!cdrom_drives[id].host_drive) + { + return; + } + if (cdrom_ioctl[id].cd_state == CD_PAUSED) + { + cdrom_ioctl[id].cd_state = CD_PLAYING; + } +} + +static void ioctl_stop(uint8_t id) +{ + if (!cdrom_drives[id].host_drive) + { + return; + } + if (cdrom_ioctl_windows[id].is_playing) + { + cdrom_ioctl_windows[id].is_playing = 0; + ioctl_close(id); + } + cdrom_ioctl[id].cd_state = CD_STOPPED; +} + +static int ioctl_ready(uint8_t id) +{ + unsigned long size; + int temp; + CDROM_TOC ltoc; + if (!cdrom_drives[id].host_drive) + { + return 0; + } + if (cdrom_ioctl_windows[id].hIOCTL == NULL) + { + ioctl_hopen(id); + temp = DeviceIoControl(cdrom_ioctl_windows[id].hIOCTL, IOCTL_CDROM_READ_TOC, NULL, 0, <oc, sizeof(ltoc), &size, NULL); + ioctl_close(id); + } + else + { + temp = DeviceIoControl(cdrom_ioctl_windows[id].hIOCTL, IOCTL_CDROM_READ_TOC, NULL, 0, <oc, sizeof(ltoc), &size, NULL); + } + if (!temp) + { + return 0; + } + if ((ltoc.TrackData[ltoc.LastTrack].Address[1] != cdrom_ioctl_windows[id].toc.TrackData[cdrom_ioctl_windows[id].toc.LastTrack].Address[1]) || + (ltoc.TrackData[ltoc.LastTrack].Address[2] != cdrom_ioctl_windows[id].toc.TrackData[cdrom_ioctl_windows[id].toc.LastTrack].Address[2]) || + (ltoc.TrackData[ltoc.LastTrack].Address[3] != cdrom_ioctl_windows[id].toc.TrackData[cdrom_ioctl_windows[id].toc.LastTrack].Address[3]) || + !cdrom_ioctl[id].tocvalid || (cdrom_drives[id].host_drive != cdrom_drives[id].prev_host_drive)) + { + cdrom_ioctl[id].cd_state = CD_STOPPED; + if (cdrom_drives[id].host_drive != cdrom_drives[id].prev_host_drive) + { + cdrom_drives[id].prev_host_drive = cdrom_drives[id].host_drive; + } + return 1; + } + return 1; +} + +static int ioctl_get_last_block(uint8_t id, unsigned char starttrack, int msf, int maxlen, int single) +{ + unsigned long size; + int c, d = 0; + CDROM_TOC lbtoc; + int lb = 0; + if (!cdrom_drives[id].host_drive) + { + return 0; + } + cdrom_ioctl[id].cd_state = CD_STOPPED; + ioctl_hopen(id); + DeviceIoControl(cdrom_ioctl_windows[id].hIOCTL, IOCTL_CDROM_READ_TOC, NULL, 0, &lbtoc, sizeof(lbtoc), &size, NULL); + ioctl_close(id); + cdrom_ioctl[id].tocvalid=1; + for (c=d; c <= lbtoc.LastTrack; c++) + { + uint32_t address; + address = MSFtoLBA(cdrom_ioctl_windows[id].toc.TrackData[c].Address[1], cdrom_ioctl_windows[id].toc.TrackData[c].Address[2], cdrom_ioctl_windows[id].toc.TrackData[c].Address[3]); + if (address > lb) + { + lb = address; + } + } + return lb; +} + +static void ioctl_read_capacity(uint8_t id, uint8_t *b); + +static int ioctl_medium_changed(uint8_t id) +{ + unsigned long size; + int temp; + CDROM_TOC ltoc; + if (!cdrom_drives[id].host_drive) + { + return 0; /* This will be handled by the not ready handler instead. */ + } + ioctl_hopen(id); + temp = DeviceIoControl(cdrom_ioctl_windows[id].hIOCTL, IOCTL_CDROM_READ_TOC, NULL, 0, <oc,sizeof(ltoc), &size, NULL); + ioctl_close(id); + if (!temp) + { + return 0; /* Drive empty, a not ready handler matter, not disc change. */ + } + if (!cdrom_ioctl[id].tocvalid || (cdrom_drives[id].host_drive != cdrom_drives[id].prev_host_drive)) + { + cdrom_ioctl[id].cd_state = CD_STOPPED; + cdrom_ioctl_windows[id].toc = ltoc; + cdrom_ioctl[id].tocvalid = 1; + if (cdrom_drives[id].host_drive != cdrom_drives[id].prev_host_drive) + { + cdrom_drives[id].prev_host_drive = cdrom_drives[id].host_drive; + } + ioctl_hopen(id); + cdrom_ioctl[id].capacity_read=0; /* With this two lines, we read the READ CAPACITY command output from the host drive into our cache buffer. */ + ioctl_read_capacity(id, NULL); + ioctl_close(id); + cdrom_ioctl[id].cdrom_capacity = ioctl_get_last_block(id, 0, 0, 4096, 0); + return 1; + } + else + { + if ((ltoc.TrackData[ltoc.LastTrack].Address[1] != cdrom_ioctl_windows[id].toc.TrackData[cdrom_ioctl_windows[id].toc.LastTrack].Address[1]) || + (ltoc.TrackData[ltoc.LastTrack].Address[2] != cdrom_ioctl_windows[id].toc.TrackData[cdrom_ioctl_windows[id].toc.LastTrack].Address[2]) || + (ltoc.TrackData[ltoc.LastTrack].Address[3] != cdrom_ioctl_windows[id].toc.TrackData[cdrom_ioctl_windows[id].toc.LastTrack].Address[3])) + { + cdrom_ioctl[id].cd_state = CD_STOPPED; + cdrom_ioctl_log("Setting TOC...\n"); + cdrom_ioctl_windows[id].toc = ltoc; + ioctl_hopen(id); + cdrom_ioctl[id].capacity_read=0; /* With this two lines, we read the READ CAPACITY command output from the host drive into our cache buffer. */ + ioctl_read_capacity(id, NULL); + ioctl_close(id); + cdrom_ioctl[id].cdrom_capacity = ioctl_get_last_block(id, 0, 0, 4096, 0); + return 1; /* TOC mismatches. */ + } + } + return 0; /* None of the above, return 0. */ +} + +static uint8_t ioctl_getcurrentsubchannel(uint8_t id, uint8_t *b, int msf) +{ + CDROM_SUB_Q_DATA_FORMAT insub; + SUB_Q_CHANNEL_DATA sub; + unsigned long size; + int pos = 0, track; + uint32_t cdpos, track_address, dat; + + if (!cdrom_drives[id].host_drive) return 0; + + cdpos = cdrom[id].seek_pos; + + if (cdrom_ioctl[id].last_subchannel_pos == cdpos) + { + memcpy(&insub, cdrom_ioctl[id].sub_q_data_format, sizeof(insub)); + memcpy(&sub, cdrom_ioctl[id].sub_q_channel_data, sizeof(sub)); + } + else + { + insub.Format = IOCTL_CDROM_CURRENT_POSITION; + ioctl_hopen(id); + DeviceIoControl(cdrom_ioctl_windows[id].hIOCTL,IOCTL_CDROM_READ_Q_CHANNEL,&insub,sizeof(insub),&sub,sizeof(sub),&size,NULL); + ioctl_close(id); + memset(cdrom_ioctl[id].sub_q_data_format, 0, 16); + memcpy(cdrom_ioctl[id].sub_q_data_format, &insub, sizeof(insub)); + memset(cdrom_ioctl[id].sub_q_channel_data, 0, 256); + memcpy(cdrom_ioctl[id].sub_q_channel_data, &sub, sizeof(sub)); + cdrom_ioctl[id].last_subchannel_pos = cdpos; + } + + if (cdrom_ioctl[id].cd_state == CD_PLAYING || cdrom_ioctl[id].cd_state == CD_PAUSED) + { + track = get_track_nr(id, cdpos); + track_address = cdrom_ioctl_windows[id].toc.TrackData[track].Address[3] + (cdrom_ioctl_windows[id].toc.TrackData[track].Address[2] * 75) + (cdrom_ioctl_windows[id].toc.TrackData[track].Address[1] * 75 * 60); + + cdrom_ioctl_log("cdpos = %i, track = %i, track_address = %i\n", cdpos, track, track_address); + + b[pos++] = sub.CurrentPosition.Control; + b[pos++] = track + 1; + b[pos++] = sub.CurrentPosition.IndexNumber; + + if (msf) + { + dat = cdpos + 150; + b[pos + 3] = (uint8_t)(dat % 75); dat /= 75; + b[pos + 2] = (uint8_t)(dat % 60); dat /= 60; + b[pos + 1] = (uint8_t)dat; + b[pos] = 0; + pos += 4; + dat = cdpos - track_address; + b[pos + 3] = (uint8_t)(dat % 75); dat /= 75; + b[pos + 2] = (uint8_t)(dat % 60); dat /= 60; + b[pos + 1] = (uint8_t)dat; + b[pos] = 0; + pos += 4; + } + else + { + b[pos++] = (cdpos >> 24) & 0xff; + b[pos++] = (cdpos >> 16) & 0xff; + b[pos++] = (cdpos >> 8) & 0xff; + b[pos++] = cdpos & 0xff; + cdpos -= track_address; + b[pos++] = (cdpos >> 24) & 0xff; + b[pos++] = (cdpos >> 16) & 0xff; + b[pos++] = (cdpos >> 8) & 0xff; + b[pos++] = cdpos & 0xff; + } + + if (cdrom_ioctl[id].cd_state == CD_PLAYING) return 0x11; + return 0x12; + } + + b[pos++]=sub.CurrentPosition.Control; + b[pos++]=sub.CurrentPosition.TrackNumber; + b[pos++]=sub.CurrentPosition.IndexNumber; + + cdrom_ioctl_log("cdpos = %i, track_address = %i\n", MSFtoLBA(sub.CurrentPosition.AbsoluteAddress[1], sub.CurrentPosition.AbsoluteAddress[2], sub.CurrentPosition.AbsoluteAddress[3]), MSFtoLBA(sub.CurrentPosition.TrackRelativeAddress[1], sub.CurrentPosition.TrackRelativeAddress[2], sub.CurrentPosition.TrackRelativeAddress[3])); + + if (msf) + { + int c; + for (c = 0; c < 4; c++) + { + b[pos++] = sub.CurrentPosition.AbsoluteAddress[c]; + } + for (c = 0; c < 4; c++) + { + b[pos++] = sub.CurrentPosition.TrackRelativeAddress[c]; + } + } + else + { + uint32_t temp = MSFtoLBA(sub.CurrentPosition.AbsoluteAddress[1], sub.CurrentPosition.AbsoluteAddress[2], sub.CurrentPosition.AbsoluteAddress[3]); + b[pos++] = temp >> 24; + b[pos++] = temp >> 16; + b[pos++] = temp >> 8; + b[pos++] = temp; + temp = MSFtoLBA(sub.CurrentPosition.TrackRelativeAddress[1], sub.CurrentPosition.TrackRelativeAddress[2], sub.CurrentPosition.TrackRelativeAddress[3]); + b[pos++] = temp >> 24; + b[pos++] = temp >> 16; + b[pos++] = temp >> 8; + b[pos++] = temp; + } + + return 0x13; +} + +static void ioctl_eject(uint8_t id) +{ + unsigned long size; + if (!cdrom_drives[id].host_drive) + { + return; + } + if (cdrom_ioctl_windows[id].is_playing) + { + cdrom_ioctl_windows[id].is_playing = 0; + ioctl_stop(id); + } + cdrom_ioctl[id].cd_state = CD_STOPPED; + ioctl_hopen(id); + DeviceIoControl(cdrom_ioctl_windows[id].hIOCTL,IOCTL_STORAGE_EJECT_MEDIA,NULL,0,NULL,0,&size,NULL); + ioctl_close(id); +} + +static void ioctl_load(uint8_t id) +{ + unsigned long size; + if (!cdrom_drives[id].host_drive) + { + return; + } + if (cdrom_ioctl_windows[id].is_playing) + { + cdrom_ioctl_windows[id].is_playing = 0; + ioctl_stop(id); + } + cdrom_ioctl[id].cd_state = CD_STOPPED; + ioctl_hopen(id); + DeviceIoControl(cdrom_ioctl_windows[id].hIOCTL,IOCTL_STORAGE_LOAD_MEDIA,NULL,0,NULL,0,&size,NULL); + cdrom_ioctl[id].capacity_read=0; /* With this two lines, we read the READ CAPACITY command output from the host drive into our cache buffer. */ + ioctl_read_capacity(id, NULL); + ioctl_close(id); + cdrom_ioctl[id].cdrom_capacity = ioctl_get_last_block(id, 0, 0, 4096, 0); +} + +static int is_track_audio(uint8_t id, uint32_t pos) +{ + int c; + int control = 0; + + uint32_t track_address = 0; + + if (!cdrom_ioctl[id].tocvalid) + { + return 0; + } + + for (c = 0; c <= cdrom_ioctl_windows[id].toc.LastTrack; c++) + { + track_address = MSFtoLBA(cdrom_ioctl_windows[id].toc.TrackData[c].Address[1],cdrom_ioctl_windows[id].toc.TrackData[c].Address[2],cdrom_ioctl_windows[id].toc.TrackData[c].Address[3]); + + if (track_address <= pos) + { + control = cdrom_ioctl_windows[id].toc.TrackData[c].Control; + } + } + + if ((control & 0xd) <= 1) + { + return 1; + } + else + { + return 0; + } +} + +static int ioctl_is_track_audio(uint8_t id, uint32_t pos, int ismsf) +{ + int m = 0, s = 0, f = 0; + + if (ismsf) + { + m = (pos >> 16) & 0xff; + s = (pos >> 8) & 0xff; + f = pos & 0xff; + pos = MSFtoLBA(m, s, f); + } + else + { + pos += 150; + } + return is_track_audio(id, pos); +} + +/* 00, 08, 10, 18, 20, 28, 30, 38 */ +int flags_to_size[5][32] = { { 0, 0, 2352, 2352, 2352, 2352, 2352, 2352, /* 00-38 (CD-DA) */ + 2352, 2352, 2352, 2352, 2352, 2352, 2352, 2352, /* 40-78 */ + 2352, 2352, 2352, 2352, 2352, 2352, 2352, 2352, /* 80-B8 */ + 2352, 2352, 2352, 2352, 2352, 2352, 2352, 2352 }, /* C0-F8 */ + { 0, 0, 2048, 2336, 4, -296, 2052, 2344, /* 00-38 (Mode 1) */ + 8, -296, 2048, 2048, 12, -296, 2052, 2052, /* 40-78 */ + -296, -296, -296, -296, 16, -296, 2064, 2344, /* 80-B8 */ + -296, -296, 2048, 2048, 24, -296, 2064, 2352 }, /* C0-F8 */ + { 0, 0, 2336, 2336, 4, -296, 2340, 2340, /* 00-38 (Mode 2 non-XA) */ + 8, -296, 2336, 2336, 12, -296, 2340, 2340, /* 40-78 */ + -296, -296, -296, -296, 16, -296, 2352, 2340, /* 80-B8 */ + -296, -296, 2336, 2336, 24, -296, 2352, 2352 }, /* C0-F8 */ + { 0, 0, 2048, 2336, 4, -296, -296, -296, /* 00-38 (Mode 2 Form 1) */ + 8, -296, 2056, 2344, 12, -296, 2060, 2340, /* 40-78 */ + -296, -296, -296, -296, 16, -296, -296, -296, /* 80-B8 */ + -296, -296, -296, -296, 24, -296, 2072, 2352 }, /* C0-F8 */ + { 0, 0, 2328, 2328, 4, -296, -296, -296, /* 00-38 (Mode 2 Form 2) */ + 8, -296, 2336, 2336, 12, -296, 2340, 2340, /* 40-78 */ + -296, -296, -296, -296, 16, -296, -296, -296, /* 80-B8 */ + -296, -296, -296, -296, 24, -296, 2352, 2352 } /* C0-F8 */ + }; + +static int ioctl_get_sector_data_type(uint8_t id, uint8_t b0, uint8_t b1, uint8_t b2, uint8_t b3, int ismsf); + +static void cdrom_illegal_mode(uint8_t id) +{ + cdrom_sense_key = SENSE_ILLEGAL_REQUEST; + cdrom_asc = ASC_ILLEGAL_MODE_FOR_THIS_TRACK; + cdrom_ascq = 0; +} + +struct sptd_with_sense +{ + SCSI_PASS_THROUGH s; + ULONG Filler; + UCHAR sense[32]; + UCHAR data[65536]; +} sptd; + +static int ioctl_get_block_length(uint8_t id, const UCHAR *cdb, int number_of_blocks, int no_length_check) +{ + int sector_type = 0; + int temp_len = 0; + + if (no_length_check) + { + switch (cdb[0]) + { + case 0x25: + /* READ CAPACITY */ + return 8; + case 0x42: /* READ SUBCHANNEL */ + case 0x43: /* READ TOC */ + case 0x51: /* READ DISC INFORMATION */ + case 0x52: /* READ TRACK INFORMATION */ + case 0x5A: /* MODE SENSE (10) */ + return ((uint16_t) cdb[8]) + (((uint16_t) cdb[7]) << 8); + default: + return 65534; + } + } + + switch (cdb[0]) + { + case 0x25: + /* READ CAPACITY */ + return 8; + case 0x42: /* READ SUBCHANNEL */ + case 0x43: /* READ TOC */ + case 0x51: /* READ DISC INFORMATION */ + case 0x52: /* READ TRACK INFORMATION */ + case 0x5A: /* MODE SENSE (10) */ + return ((uint16_t) cdb[8]) + (((uint16_t) cdb[7]) << 8); + case 0x08: + case 0x28: + case 0xa8: + /* READ (6), READ (10), READ (12) */ + return 2048 * number_of_blocks; + break; + case 0xb9: + sector_type = (cdb[1] >> 2) & 7; + if (sector_type == 0) + { + sector_type = ioctl_get_sector_data_type(id, 0, cdb[3], cdb[4], cdb[5], 1); + if (sector_type == 0) + { + cdrom_illegal_mode(id); + return -1; + } + } + goto common_handler; + case 0xbe: + /* READ CD MSF, READ CD */ + sector_type = (cdb[1] >> 2) & 7; + if (sector_type == 0) + { + sector_type = ioctl_get_sector_data_type(id, cdb[2], cdb[3], cdb[4], cdb[5], 0); + if (sector_type == 0) + { + cdrom_illegal_mode(id); + return -1; + } + } +common_handler: + temp_len = flags_to_size[sector_type - 1][cdb[9] >> 3]; + if ((cdb[9] & 6) == 2) + { + temp_len += 294; + } + else if ((cdb[9] & 6) == 4) + { + temp_len += 296; + } + if ((cdb[10] & 7) == 1) + { + temp_len += 96; + } + else if ((cdb[10] & 7) == 2) + { + temp_len += 16; + } + else if ((cdb[10] & 7) == 4) + { + temp_len += 96; + } + if (temp_len <= 0) + { + cdrom_illegal_mode(id); + return -1; + } + return temp_len * cdrom[id].requested_blocks; + break; + default: + /* Other commands */ + return 65534; + break; + } + +} + +static int SCSICommand(uint8_t id, const UCHAR *cdb, UCHAR *buf, uint32_t *len, int no_length_check) +{ + DWORD ioctl_bytes; + int ioctl_rv = 0; + + SCSISense.SenseKey = 0; + SCSISense.Asc = 0; + SCSISense.Ascq = 0; + + *len = 0; + memset(&sptd, 0, sizeof(sptd)); + sptd.s.Length = sizeof(SCSI_PASS_THROUGH); + sptd.s.CdbLength = 12; + sptd.s.DataIn = SCSI_IOCTL_DATA_IN; + sptd.s.TimeOutValue = 80 * 60; + sptd.s.DataTransferLength = ioctl_get_block_length(id, cdb, cdrom_ioctl[id].actual_requested_blocks, no_length_check); + sptd.s.SenseInfoOffset = (uintptr_t)&sptd.sense - (uintptr_t)&sptd; + sptd.s.SenseInfoLength = 32; + sptd.s.DataBufferOffset = (uintptr_t)&sptd.data - (uintptr_t)&sptd; + + memcpy(sptd.s.Cdb, cdb, 12); + ioctl_rv = DeviceIoControl(cdrom_ioctl_windows[id].hIOCTL, IOCTL_SCSI_PASS_THROUGH, &sptd, sizeof(sptd), &sptd, sizeof(sptd), &ioctl_bytes, NULL); + + if (sptd.s.SenseInfoLength) + { + cdrom_sense_key = sptd.sense[2]; + cdrom_asc = sptd.sense[12]; + cdrom_ascq = sptd.sense[13]; + } + + cdrom_ioctl_log("Transferred length: %i (command: %02X)\n", sptd.s.DataTransferLength, cdb[0]); + cdrom_ioctl_log("Sense length: %i (%02X %02X %02X %02X %02X)\n", sptd.s.SenseInfoLength, sptd.sense[0], sptd.sense[1], sptd.sense[2], sptd.sense[12], sptd.sense[13]); + cdrom_ioctl_log("IOCTL bytes: %i; SCSI status: %i, status: %i, LastError: %08X\n", ioctl_bytes, sptd.s.ScsiStatus, ioctl_rv, GetLastError()); + cdrom_ioctl_log("DATA: %02X %02X %02X %02X %02X %02X\n", sptd.data[0], sptd.data[1], sptd.data[2], sptd.data[3], sptd.data[4], sptd.data[5]); + cdrom_ioctl_log(" %02X %02X %02X %02X %02X %02X\n", sptd.data[6], sptd.data[7], sptd.data[8], sptd.data[9], sptd.data[10], sptd.data[11]); + cdrom_ioctl_log(" %02X %02X %02X %02X %02X %02X\n", sptd.data[12], sptd.data[13], sptd.data[14], sptd.data[15], sptd.data[16], sptd.data[17]); + cdrom_ioctl_log("SENSE: %02X %02X %02X %02X %02X %02X\n", sptd.sense[0], sptd.sense[1], sptd.sense[2], sptd.sense[3], sptd.sense[4], sptd.sense[5]); + cdrom_ioctl_log(" %02X %02X %02X %02X %02X %02X\n", sptd.sense[6], sptd.sense[7], sptd.sense[8], sptd.sense[9], sptd.sense[10], sptd.sense[11]); + cdrom_ioctl_log(" %02X %02X %02X %02X %02X %02X\n", sptd.sense[12], sptd.sense[13], sptd.sense[14], sptd.sense[15], sptd.sense[16], sptd.sense[17]); + *len = sptd.s.DataTransferLength; + if (sptd.s.DataTransferLength != 0) + { + memcpy(buf, sptd.data, sptd.s.DataTransferLength); + } + + return ioctl_rv; +} + +static void ioctl_read_capacity(uint8_t id, uint8_t *b) +{ + uint32_t len = 0; + + const UCHAR cdb[] = { 0x25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + UCHAR buf[16]; + + if (!cdrom_ioctl[id].capacity_read) + { + SCSICommand(id, cdb, buf, &len, 1); + + memcpy(cdrom_ioctl[id].rcbuf, buf, len); + cdrom_ioctl[id].capacity_read = 1; + } + else + { + memcpy(b, cdrom_ioctl[id].rcbuf, 16); + } +} + +static int ioctl_media_type_id(uint8_t id) +{ + uint8_t old_sense[3] = { 0, 0, 0 }; + + UCHAR msbuf[28]; + uint32_t len = 0; + int sense = 0; + + const UCHAR cdb[] = { 0x5A, 0x00, 0x2A, 0, 0, 0, 0, 0, 28, 0, 0, 0 }; + + old_sense[0] = cdrom_sense_key; + old_sense[1] = cdrom_asc; + old_sense[2] = cdrom_asc; + + ioctl_hopen(id); + + SCSICommand(id, cdb, msbuf, &len, 1); + + ioctl_close(id); + + sense = cdrom_sense_key; + cdrom_sense_key = old_sense[0]; + cdrom_asc = old_sense[1]; + cdrom_asc = old_sense[2]; + + if (sense == 0) + { + return msbuf[2]; + } + else + { + return 3; + } +} + +static uint32_t msf_to_lba32(int lba) +{ + int m = (lba >> 16) & 0xff; + int s = (lba >> 8) & 0xff; + int f = lba & 0xff; + return (m * 60 * 75) + (s * 75) + f; +} + +static int ioctl_get_type(uint8_t id, UCHAR *cdb, UCHAR *buf) +{ + int i = 0; + int ioctl_rv = 0; + + uint32_t len = 0; + + for (i = 2; i <= 5; i++) + { + cdb[1] = i << 2; + ioctl_rv = SCSICommand(id, cdb, buf, &len, 1); /* Bypass length check so we don't risk calling this again and getting stuck in an endless up. */ + if (ioctl_rv) + { + return i; + } + } + return 0; +} + +static int ioctl_sector_data_type(uint8_t id, int sector, int ismsf) +{ + int ioctl_rv = 0; + UCHAR cdb_lba[] = { 0xBE, 0, 0, 0, 0, 0, 0, 0, 1, 0x10, 0, 0 }; + UCHAR cdb_msf[] = { 0xB9, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0 }; + UCHAR buf[2352]; + + cdb_lba[2] = (sector >> 24); + cdb_lba[3] = ((sector >> 16) & 0xff); + cdb_lba[4] = ((sector >> 8) & 0xff); + cdb_lba[5] = (sector & 0xff); + + cdb_msf[3] = cdb_msf[6] = ((sector >> 16) & 0xff); + cdb_msf[4] = cdb_msf[7] = ((sector >> 8) & 0xff); + cdb_msf[5] = cdb_msf[8] = (sector & 0xff); + + ioctl_hopen(id); + + if (ioctl_is_track_audio(id, sector, ismsf)) + { + return 1; + } + + if (ismsf) + { + ioctl_rv = ioctl_get_type(id, cdb_msf, buf); + } + else + { + ioctl_rv = ioctl_get_type(id, cdb_lba, buf); + } + + if (ioctl_rv) + { + ioctl_close(id); + return ioctl_rv; + } + + if (ismsf) + { + sector = msf_to_lba32(sector); + if (sector < 150) + { + ioctl_close(id); + return 0; + } + sector -= 150; + ioctl_rv = ioctl_get_type(id, (UCHAR *) cdb_lba, buf); + } + + ioctl_close(id); + return ioctl_rv; +} + +static int ioctl_get_sector_data_type(uint8_t id, uint8_t b0, uint8_t b1, uint8_t b2, uint8_t b3, int ismsf) +{ + int sector = b3; + sector |= ((uint32_t) b2) << 8; + sector |= ((uint32_t) b1) << 16; + sector |= ((uint32_t) b0) << 24; + return ioctl_sector_data_type(id, sector, ismsf); +} + +static void ioctl_validate_toc(uint8_t id) +{ + unsigned long size; + if (!cdrom_drives[id].host_drive) + { + return; + } + cdrom_ioctl[id].cd_state = CD_STOPPED; + ioctl_hopen(id); + cdrom_ioctl_log("Validating TOC...\n"); + DeviceIoControl(cdrom_ioctl_windows[id].hIOCTL,IOCTL_CDROM_READ_TOC, NULL,0,&cdrom_ioctl_windows[id].toc,sizeof(cdrom_ioctl_windows[id].toc),&size,NULL); + ioctl_close(id); + cdrom_ioctl[id].tocvalid=1; +} + +UCHAR buf[262144]; + +static int ioctl_pass_through(uint8_t id, uint8_t *in_cdb, uint8_t *b, uint32_t *len) +{ + const UCHAR cdb[12]; + + int ret = 0; + + int block_length = 0; + + int temp_block_length = 0; + int temp_pos = 0; + + int blocks_at_once = 0; + int buffer_pos = 0; + + int transferred_blocks = 0; + + uint32_t temp_len = 0; + int chunk = 0; + + if (in_cdb[0] == 0x43) + { + /* This is a read TOC, so we have to validate the TOC to make the rest of the emulator happy. */ + ioctl_validate_toc(id); + } + + ioctl_hopen(id); + + memcpy((void *) cdb, in_cdb, 12); + + temp_block_length = ioctl_get_block_length(id, cdb, cdrom[id].requested_blocks, 0); + *len = 0; + if (temp_block_length != -1) + { + if (temp_block_length > 65534) + { + block_length = temp_block_length / cdrom[id].requested_blocks; + blocks_at_once = 32768 / block_length; + cdrom_ioctl_log("CD-ROM %i: ioctl_pass_through(): Expected transfer length %i is bigger than 65534, splitting the transfer into chunks of %i blocks...\n", id, temp_block_length, blocks_at_once); + + buffer_pos = 0; + temp_pos = cdrom[id].sector_pos; + transferred_blocks = 0; + temp_len = 0; + +split_block_read_iterate: + chunk = (cdrom[id].requested_blocks - transferred_blocks); + if (chunk < blocks_at_once) + { + cdrom_ioctl_log("CD-ROM %i: ioctl_pass_through(): The remaining chunk (%i blocks) is less than a complete split block\n", id, chunk); + cdrom_ioctl[id].actual_requested_blocks = chunk; + } + else + { + cdrom_ioctl_log("CD-ROM %i: ioctl_pass_through(): The remaining chunk (%i blocks) is more or equal than a complete split block\n", id, chunk); + cdrom_ioctl[id].actual_requested_blocks = blocks_at_once; + } + cdrom_ioctl_log("CD-ROM %i: ioctl_pass_through(): Transferring %i blocks...\n", id, cdrom_ioctl[id].actual_requested_blocks); + cdrom_update_cdb((uint8_t *) cdb, temp_pos, cdrom_ioctl[id].actual_requested_blocks); + ret = SCSICommand(id, cdb, buf + buffer_pos, &temp_len, 0); + *len += temp_len; + transferred_blocks += cdrom_ioctl[id].actual_requested_blocks; + if (ret && (transferred_blocks < cdrom[id].requested_blocks)) + { + /* Return value was successful and there are still more blocks left to transfer. */ + temp_pos += cdrom_ioctl[id].actual_requested_blocks; + buffer_pos += (cdrom_ioctl[id].actual_requested_blocks * block_length); + goto split_block_read_iterate; + } + cdrom_ioctl_log("CD-ROM %i: ioctl_pass_through(): Split transfer done\n", id); + } + else + { + cdrom_ioctl_log("CD-ROM %i: ioctl_pass_through(): Expected transfer length %i is smaller than 65534, transferring all at once...\n", id, temp_block_length); + cdrom_ioctl[id].actual_requested_blocks = cdrom[id].requested_blocks; + ret = SCSICommand(id, cdb, buf, len, 0); + cdrom_ioctl_log("CD-ROM %i: ioctl_pass_through(): Single transfer done\n", id); + } + memcpy(b, buf, *len); + } + else + { + cdrom_ioctl_log("CD-ROM %i: ioctl_pass_through(): Expected transfer length %i is -1, this indicates an illegal mode\n", id, temp_block_length); + } + + cdrom_ioctl_log("IOCTL DATA: %02X %02X %02X %02X %02X %02X %02X %02X\n", b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]); + + ioctl_close(id); + + cdrom_ioctl_log("IOCTL Returned value: %i\n", ret); + + return ret; +} + +static int ioctl_readtoc(uint8_t id, unsigned char *b, unsigned char starttrack, int msf, int maxlen, int single) +{ + int len=4; + DWORD size; + int c,d; + uint32_t temp; + uint32_t last_block; + if (!cdrom_drives[id].host_drive) + { + return 0; + } + cdrom_ioctl[id].cd_state = CD_STOPPED; + ioctl_hopen(id); + DeviceIoControl(cdrom_ioctl_windows[id].hIOCTL,IOCTL_CDROM_READ_TOC, NULL,0,&cdrom_ioctl_windows[id].toc,sizeof(cdrom_ioctl_windows[id].toc),&size,NULL); + ioctl_close(id); + cdrom_ioctl[id].tocvalid = 1; + b[2]=cdrom_ioctl_windows[id].toc.FirstTrack; + b[3]=cdrom_ioctl_windows[id].toc.LastTrack; + d=0; + for (c=0;c<=cdrom_ioctl_windows[id].toc.LastTrack;c++) + { + if (cdrom_ioctl_windows[id].toc.TrackData[c].TrackNumber>=starttrack) + { + d=c; + break; + } + } + b[2]=cdrom_ioctl_windows[id].toc.TrackData[c].TrackNumber; + last_block = 0; + for (c=d;c<=cdrom_ioctl_windows[id].toc.LastTrack;c++) + { + uint32_t address; + if ((len+8)>maxlen) break; + b[len++]=0; /*Reserved*/ + b[len++]=(cdrom_ioctl_windows[id].toc.TrackData[c].Adr<<4)|cdrom_ioctl_windows[id].toc.TrackData[c].Control; + b[len++]=cdrom_ioctl_windows[id].toc.TrackData[c].TrackNumber; + b[len++]=0; /*Reserved*/ + address = MSFtoLBA(cdrom_ioctl_windows[id].toc.TrackData[c].Address[1],cdrom_ioctl_windows[id].toc.TrackData[c].Address[2],cdrom_ioctl_windows[id].toc.TrackData[c].Address[3]); + if (address > last_block) + last_block = address; + + if (msf) + { + b[len++]=cdrom_ioctl_windows[id].toc.TrackData[c].Address[0]; + b[len++]=cdrom_ioctl_windows[id].toc.TrackData[c].Address[1]; + b[len++]=cdrom_ioctl_windows[id].toc.TrackData[c].Address[2]; + b[len++]=cdrom_ioctl_windows[id].toc.TrackData[c].Address[3]; + } + else + { + temp=MSFtoLBA(cdrom_ioctl_windows[id].toc.TrackData[c].Address[1],cdrom_ioctl_windows[id].toc.TrackData[c].Address[2],cdrom_ioctl_windows[id].toc.TrackData[c].Address[3]) - 150; + b[len++]=temp>>24; + b[len++]=temp>>16; + b[len++]=temp>>8; + b[len++]=temp; + } + if (single) break; + } + b[0] = (uint8_t)(((len-2) >> 8) & 0xff); + b[1] = (uint8_t)((len-2) & 0xff); + return len; +} + +static int ioctl_readtoc_session(uint8_t id, unsigned char *b, int msf, int maxlen) +{ + int len=4; + int size; + uint32_t temp; + CDROM_READ_TOC_EX toc_ex; + CDROM_TOC_SESSION_DATA toc; + if (!cdrom_drives[id].host_drive) + { + return 0; + } + cdrom_ioctl[id].cd_state = CD_STOPPED; + memset(&toc_ex,0,sizeof(toc_ex)); + memset(&toc,0,sizeof(toc)); + toc_ex.Format=CDROM_READ_TOC_EX_FORMAT_SESSION; + toc_ex.Msf=msf; + toc_ex.SessionTrack=0; + ioctl_hopen(id); + DeviceIoControl(cdrom_ioctl_windows[id].hIOCTL,IOCTL_CDROM_READ_TOC_EX, &toc_ex,sizeof(toc_ex),&toc,sizeof(toc),(PDWORD)&size,NULL); + ioctl_close(id); + b[2]=toc.FirstCompleteSession; + b[3]=toc.LastCompleteSession; + b[len++]=0; /*Reserved*/ + b[len++]=(toc.TrackData[0].Adr<<4)|toc.TrackData[0].Control; + b[len++]=toc.TrackData[0].TrackNumber; + b[len++]=0; /*Reserved*/ + if (msf) + { + b[len++]=toc.TrackData[0].Address[0]; + b[len++]=toc.TrackData[0].Address[1]; + b[len++]=toc.TrackData[0].Address[2]; + b[len++]=toc.TrackData[0].Address[3]; + } + else + { + temp=MSFtoLBA(toc.TrackData[0].Address[1],toc.TrackData[0].Address[2],toc.TrackData[0].Address[3]) - 150; + b[len++]=temp>>24; + b[len++]=temp>>16; + b[len++]=temp>>8; + b[len++]=temp; + } + + return len; +} + +static int ioctl_readtoc_raw(uint8_t id, uint8_t *b, int maxlen) +{ + int len=4; + int size; + int i; + CDROM_READ_TOC_EX toc_ex; + CDROM_TOC_FULL_TOC_DATA toc; + if (!cdrom_drives[id].host_drive) + { + return 0; + } + cdrom_ioctl[id].cd_state = CD_STOPPED; + memset(&toc_ex,0,sizeof(toc_ex)); + memset(&toc,0,sizeof(toc)); + toc_ex.Format=CDROM_READ_TOC_EX_FORMAT_FULL_TOC; + toc_ex.Msf=1; + toc_ex.SessionTrack=0; + ioctl_hopen(id); + DeviceIoControl(cdrom_ioctl_windows[id].hIOCTL,IOCTL_CDROM_READ_TOC_EX, &toc_ex,sizeof(toc_ex),&toc,sizeof(toc),(PDWORD)&size,NULL); + ioctl_close(id); + b[2]=toc.FirstCompleteSession; + b[3]=toc.LastCompleteSession; + + size -= sizeof(CDROM_TOC_FULL_TOC_DATA); + size /= sizeof(toc.Descriptors[0]); + + for (i = 0; i <= size; i++) + { + b[len++]=toc.Descriptors[i].SessionNumber; + b[len++]=(toc.Descriptors[i].Adr<<4)|toc.Descriptors[i].Control; + b[len++]=0; + b[len++]=toc.Descriptors[i].Reserved1; /*Reserved*/ + b[len++]=toc.Descriptors[i].MsfExtra[0]; + b[len++]=toc.Descriptors[i].MsfExtra[1]; + b[len++]=toc.Descriptors[i].MsfExtra[2]; + b[len++]=toc.Descriptors[i].Zero; + b[len++]=toc.Descriptors[i].Msf[0]; + b[len++]=toc.Descriptors[i].Msf[1]; + b[len++]=toc.Descriptors[i].Msf[2]; + } + + return len; +} + +static uint32_t ioctl_size(uint8_t id) +{ + uint8_t capacity_buffer[8]; + uint32_t capacity = 0; + ioctl_read_capacity(id, capacity_buffer); + capacity = ((uint32_t) capacity_buffer[0]) << 24; + capacity |= ((uint32_t) capacity_buffer[1]) << 16; + capacity |= ((uint32_t) capacity_buffer[2]) << 8; + capacity |= (uint32_t) capacity_buffer[3]; + return capacity + 1; +} + +static int ioctl_status(uint8_t id) +{ + if (!(ioctl_ready(id)) && (cdrom_drives[id].host_drive <= 0)) + { + return CD_STATUS_EMPTY; + } + + switch(cdrom_ioctl[id].cd_state) + { + case CD_PLAYING: + return CD_STATUS_PLAYING; + case CD_PAUSED: + return CD_STATUS_PAUSED; + case CD_STOPPED: + return CD_STATUS_STOPPED; + default: + return CD_STATUS_EMPTY; + } +} + +void ioctl_reset(uint8_t id) +{ + CDROM_TOC ltoc; + unsigned long size; + + if (!cdrom_drives[id].host_drive) + { + cdrom_ioctl[id].tocvalid = 0; + return; + } + + ioctl_hopen(id); + DeviceIoControl(cdrom_ioctl_windows[id].hIOCTL, IOCTL_CDROM_READ_TOC, NULL, 0, <oc, sizeof(ltoc), &size, NULL); + ioctl_close(id); + + cdrom_ioctl_windows[id].toc = ltoc; + cdrom_ioctl[id].tocvalid = 1; +} + +int ioctl_hopen(uint8_t id) +{ + if (cdrom_ioctl_windows[id].is_playing) return 0; + cdrom_ioctl_windows[id].hIOCTL = CreateFile(cdrom_ioctl[id].ioctl_path, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); + return 0; +} + +int ioctl_open(uint8_t id, char d) +{ + sprintf(cdrom_ioctl[id].ioctl_path,"\\\\.\\%c:",d); + cdrom_ioctl[id].tocvalid=0; + cdrom_ioctl_windows[id].hIOCTL = CreateFile(cdrom_ioctl[id].ioctl_path, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); + cdrom_drives[id].handler = &ioctl_cdrom; + cdrom_ioctl[id].ioctl_inited=1; + cdrom_ioctl[id].capacity_read=0; /* With this two lines, we read the READ CAPACITY command output from the host drive into our cache buffer. */ + ioctl_read_capacity(id, NULL); + CloseHandle(cdrom_ioctl_windows[id].hIOCTL); + cdrom_ioctl_windows[id].hIOCTL = NULL; + return 0; +} + +void ioctl_close(uint8_t id) +{ + if (cdrom_ioctl_windows[id].is_playing) return; + if (cdrom_ioctl_windows[id].hIOCTL) + { + CloseHandle(cdrom_ioctl_windows[id].hIOCTL); + cdrom_ioctl_windows[id].hIOCTL = NULL; + } +} + +static void ioctl_exit(uint8_t id) +{ + cdrom_ioctl_windows[id].is_playing = 0; + ioctl_stop(id); + cdrom_ioctl[id].ioctl_inited=0; + cdrom_ioctl[id].tocvalid=0; +} + +static CDROM ioctl_cdrom= +{ + ioctl_ready, + ioctl_medium_changed, + ioctl_media_type_id, + ioctl_audio_callback, + ioctl_audio_stop, + ioctl_readtoc, + ioctl_readtoc_session, + ioctl_readtoc_raw, + ioctl_getcurrentsubchannel, + ioctl_pass_through, + NULL, + ioctl_playaudio, + ioctl_load, + ioctl_eject, + ioctl_pause, + ioctl_resume, + ioctl_size, + ioctl_status, + ioctl_is_track_audio, + ioctl_stop, + ioctl_exit +}; diff --git a/src/cdrom_ioctl.h b/src/cdrom_ioctl.h new file mode 100644 index 000000000..b57689bf9 --- /dev/null +++ b/src/cdrom_ioctl.h @@ -0,0 +1,35 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Implementation of the CD-ROM host drive IOCTL interface for + * Windows using SCSI Passthrough Direct. + * + * This file lists the functions provided by various platform- + * specific cdrom-ioctl files. + * + * Version: @(#)cdrom_ioctl.h 1.0.1 2017/06/03 + * + * Authors: Sarah Walker, + * Miran Grca, + * Copyright 2008-2016 Sarah Walker. + * Copyright 2016-2017 Miran Grca. + */ +#ifndef EMU_CDROM_IOCTL_H +#define EMU_CDROM_IOCTL_H + + +extern uint32_t cdrom_capacity; + + +extern int ioctl_open(uint8_t id, char d); +extern void ioctl_reset(uint8_t id); + +extern void ioctl_close(uint8_t id); + + +#endif /*EMU_CDROM_IOCTL_H */ diff --git a/src/cdrom_null.c b/src/cdrom_null.c new file mode 100644 index 000000000..91acaf92f --- /dev/null +++ b/src/cdrom_null.c @@ -0,0 +1,147 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Implementation of the CD-ROM null interface for unmounted + * guest CD-ROM drives. + * + * Version: @(#)cdrom_null.c 1.0.1 2017/06/03 + * + * Authors: Sarah Walker, + * Miran Grca, + * Copyright 2008-2016 Sarah Walker. + * Copyright 2016-2017 Miran Grca. + */ +#include "ibm.h" +#include "cdrom.h" +#include "cdrom_ioctl.h" + + +static CDROM null_cdrom; + + +static int null_ready(uint8_t id) +{ + return 0; +} + +/* Always return 0, the contents of a null CD-ROM drive never change. */ +static int null_medium_changed(uint8_t id) +{ + return 0; +} + +static uint8_t null_getcurrentsubchannel(uint8_t id, uint8_t *b, int msf) +{ + return 0x13; +} + +static void null_eject(uint8_t id) +{ +} + +static void null_load(uint8_t id) +{ +} + +static int null_readsector_raw(uint8_t id, uint8_t *buffer, int sector, int ismsf, int cdrom_sector_type, int cdrom_sector_flags, int *len) +{ + *len = 0; + return 0; +} + +static int null_readtoc(uint8_t id, unsigned char *b, unsigned char starttrack, int msf, int maxlen, int single) +{ + return 0; +} + +static int null_readtoc_session(uint8_t id, unsigned char *b, int msf, int maxlen) +{ + return 0; +} + +static int null_readtoc_raw(uint8_t id, unsigned char *b, int maxlen) +{ + return 0; +} + +static uint32_t null_size(uint8_t id) +{ + return 0; +} + +static int null_status(uint8_t id) +{ + return CD_STATUS_EMPTY; +} + +void cdrom_null_reset(uint8_t id) +{ +} + +void cdrom_set_null_handler(uint8_t id); + +int cdrom_null_open(uint8_t id, char d) +{ + cdrom_set_null_handler(id); + return 0; +} + +void null_close(uint8_t id) +{ +} + +static void null_exit(uint8_t id) +{ +} + +static int null_is_track_audio(uint8_t id, uint32_t pos, int ismsf) +{ + return 0; +} + +static int null_pass_through(uint8_t id, uint8_t *in_cdb, uint8_t *b, uint32_t *len) +{ + return 0; +} + +static int null_media_type_id(uint8_t id) +{ + return 0x70; +} + +void cdrom_set_null_handler(uint8_t id) +{ + cdrom_drives[id].handler = &null_cdrom; + cdrom_drives[id].host_drive = 0; + memset(cdrom_image[id].image_path, 0, sizeof(cdrom_image[id].image_path)); +} + +static CDROM null_cdrom = +{ + null_ready, + null_medium_changed, + null_media_type_id, + NULL, + NULL, + null_readtoc, + null_readtoc_session, + null_readtoc_raw, + null_getcurrentsubchannel, + null_pass_through, + null_readsector_raw, + NULL, + null_load, + null_eject, + NULL, + NULL, + null_size, + null_status, + null_is_track_audio, + NULL, + null_exit +}; diff --git a/src/cdrom_null.h b/src/cdrom_null.h new file mode 100644 index 000000000..75cc71da5 --- /dev/null +++ b/src/cdrom_null.h @@ -0,0 +1,28 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Implementation of the CD-ROM null interface for unmounted + * guest CD-ROM drives. + * + * Version: @(#)cdrom_null.h 1.0.1 2017/06/03 + * + * Authors: Sarah Walker, + * Miran Grca, + * Copyright 2008-2016 Sarah Walker. + * Copyright 2016-2017 Miran Grca. + */ +#ifndef EMU_CDROM_NULL_H +#define EMU_CDROM_NULL_H + + +extern int cdrom_null_open(uint8_t id, char d); +extern void cdrom_null_reset(uint8_t id); +extern void null_close(uint8_t id); + + +#endif /*EMU_CDROM_NULL_H*/ diff --git a/src/compaq.c b/src/compaq.c index a8f8e8570..b5dae9e7b 100644 --- a/src/compaq.c +++ b/src/compaq.c @@ -2,7 +2,11 @@ see COPYING for more details */ #include "ibm.h" +#include "cpu/cpu.h" #include "mem.h" +#include "device.h" +#include "model.h" + /* Compaq Deskpro 386 remaps RAM from 0xA0000-0xFFFFF to 0xFA0000-0xFFFFFF */ @@ -14,30 +18,40 @@ uint8_t compaq_read_ram(uint32_t addr, void *priv) addreadlookup(mem_logical_addr, addr); return ram[addr]; } + + uint16_t compaq_read_ramw(uint32_t addr, void *priv) { addr = (addr & 0x7ffff) + 0x80000; addreadlookup(mem_logical_addr, addr); return *(uint16_t *)&ram[addr]; } + + uint32_t compaq_read_raml(uint32_t addr, void *priv) { addr = (addr & 0x7ffff) + 0x80000; addreadlookup(mem_logical_addr, addr); return *(uint32_t *)&ram[addr]; } + + void compaq_write_ram(uint32_t addr, uint8_t val, void *priv) { addr = (addr & 0x7ffff) + 0x80000; addwritelookup(mem_logical_addr, addr); mem_write_ramb_page(addr, val, &pages[addr >> 12]); } + + void compaq_write_ramw(uint32_t addr, uint16_t val, void *priv) { addr = (addr & 0x7ffff) + 0x80000; addwritelookup(mem_logical_addr, addr); mem_write_ramw_page(addr, val, &pages[addr >> 12]); } + + void compaq_write_raml(uint32_t addr, uint32_t val, void *priv) { addr = (addr & 0x7ffff) + 0x80000; @@ -45,7 +59,8 @@ void compaq_write_raml(uint32_t addr, uint32_t val, void *priv) mem_write_raml_page(addr, val, &pages[addr >> 12]); } -void compaq_init() + +void compaq_init(void) { mem_mapping_add(&compaq_ram_mapping, 0xfa0000, 0x60000, compaq_read_ram, compaq_read_ramw, compaq_read_raml, diff --git a/src/compaq.h b/src/compaq.h deleted file mode 100644 index d9944de71..000000000 --- a/src/compaq.h +++ /dev/null @@ -1,4 +0,0 @@ -/* Copyright holders: Sarah Walker - see COPYING for more details -*/ -void compaq_init(); diff --git a/src/config.c b/src/config.c index 234254fe5..dd8351657 100644 --- a/src/config.c +++ b/src/config.c @@ -1,14 +1,49 @@ /* Copyright holders: Sarah Walker - see COPYING for more details -*/ + * see COPYING for more details + * + * NOTE: Forcing config files to be in Unicode encoding breaks it on + * Windows XP, and possibly also Vista. Use -DANSI_CFG for use + * on these systems. + */ +#include #include +#include #include #include + +#include "cdrom.h" #include "config.h" +#include "device.h" +#include "disc.h" +#include "fdc.h" +#include "fdd.h" +#include "ibm.h" +#include "cpu/cpu.h" +#include "gameport.h" +#include "ide.h" +#include "hdd.h" +#include "model.h" +#include "mouse.h" +#include "network/network.h" +#include "nvr.h" +#include "scsi.h" +#include "win/plat_joystick.h" +#include "win/plat_midi.h" +#include "sound/midi.h" +#include "sound/snd_dbopl.h" +#include "sound/snd_mpu401.h" +#include "sound/snd_opl.h" +#include "sound/sound.h" +#include "video/video.h" -char config_file_default[256]; +#include "win/win.h" +#include "win/win_language.h" + + +wchar_t config_file_default[256]; + +static wchar_t config_file[256]; -static char config_file[256]; typedef struct list_t { @@ -32,6 +67,7 @@ typedef struct entry_t char name[256]; char data[256]; + wchar_t wdata[256]; } entry_t; #define list_add(new, head) \ @@ -45,7 +81,8 @@ typedef struct entry_t (new)->next = NULL; \ } -void config_dump() + +void config_dump(void) { section_t *current_section; @@ -72,7 +109,9 @@ void config_dump() } } -void config_free() + +#if 0 +static void config_free(void) { section_t *current_section; current_section = (section_t *)config_head.next; @@ -96,110 +135,121 @@ void config_free() current_section = next_section; } } +#endif -void config_load(char *fn) + +static wchar_t cfgbuffer[1024]; +static char sname[256]; +static char ename[256]; + +int config_load(wchar_t *fn) { - FILE *f = fopen(fn, "rt"); section_t *current_section; - - memset(&config_head, 0, sizeof(list_t)); - - current_section = malloc(sizeof(section_t)); - memset(current_section, 0, sizeof(section_t)); - list_add(¤t_section->list, &config_head); + section_t *new_section; + entry_t *new_entry; + FILE *f; + int c; + int sd = 0, ed = 0, data_pos; +#ifdef ANSI_CFG + f = _wfopen(fn, L"rt"); +#else + f = _wfopen(fn, L"rt, ccs=UNICODE"); +#endif if (!f) - return; + return 0; + + current_section = malloc(sizeof(section_t)); + memset(current_section, 0x00, sizeof(section_t)); + memset(&config_head, 0x00, sizeof(list_t)); + list_add(¤t_section->list, &config_head); while (1) { - int c; - char buffer[256]; - - fgets(buffer, 255, f); + memset(cfgbuffer, 0, 2048); + fgetws(cfgbuffer, 255, f); if (feof(f)) break; c = 0; - while (buffer[c] == ' ') + while (cfgbuffer[c] == L' ') c++; - if (!buffer[c]) continue; + if (cfgbuffer[c] == L'\0') continue; - if (buffer[c] == '#') /*Comment*/ + if (cfgbuffer[c] == L'#') /*Comment*/ continue; - if (buffer[c] == '[') /*Section*/ + if (cfgbuffer[c] == L'[') /*Section*/ { - section_t *new_section; - char name[256]; - int d = 0; - + sd = 0; c++; - while (buffer[c] != ']' && buffer[c]) - name[d++] = buffer[c++]; + while (cfgbuffer[c] != L']' && cfgbuffer[c]) + wctomb(&(sname[sd++]), cfgbuffer[c++]); - if (buffer[c] != ']') + if (cfgbuffer[c] != L']') continue; - name[d] = 0; + sname[sd] = 0; new_section = malloc(sizeof(section_t)); memset(new_section, 0, sizeof(section_t)); - strncpy(new_section->name, name, 256); + strncpy(new_section->name, sname, 256); list_add(&new_section->list, &config_head); - current_section = new_section; - -// pclog("New section : %s %p\n", name, (void *)current_section); + current_section = new_section; } else { - entry_t *new_entry; - char name[256]; - int d = 0, data_pos; - - while (buffer[c] != '=' && buffer[c] != ' ' && buffer[c]) - name[d++] = buffer[c++]; + ed = 0; + while (cfgbuffer[c] != L'=' && cfgbuffer[c] != L' ' && cfgbuffer[c]) + wctomb(&(ename[ed++]), cfgbuffer[c++]); - if (!buffer[c]) continue; - name[d] = 0; + if (cfgbuffer[c] == L'\0') continue; + ename[ed] = 0; - while ((buffer[c] == '=' || buffer[c] == ' ') && buffer[c]) + while ((cfgbuffer[c] == L'=' || cfgbuffer[c] == L' ') && cfgbuffer[c]) c++; - if (!buffer[c]) continue; + if (!cfgbuffer[c]) continue; data_pos = c; - while (buffer[c]) + while (cfgbuffer[c]) { - if (buffer[c] == '\n') - buffer[c] = 0; + if (cfgbuffer[c] == L'\n') + cfgbuffer[c] = L'\0'; c++; } new_entry = malloc(sizeof(entry_t)); memset(new_entry, 0, sizeof(entry_t)); - strncpy(new_entry->name, name, 256); - strncpy(new_entry->data, &buffer[data_pos], 256); + strncpy(new_entry->name, ename, 256); + memcpy(new_entry->wdata, &cfgbuffer[data_pos], 512); + new_entry->wdata[255] = L'\0'; + wcstombs(new_entry->data, new_entry->wdata, 512); + new_entry->data[255] = '\0'; list_add(&new_entry->list, ¤t_section->entry_head); - -// pclog("New data under section [%s] : %s = %s\n", current_section->name, new_entry->name, new_entry->data); } } fclose(f); config_dump(); + + return 1; } - -void config_new() +void config_new(void) { - FILE *f = fopen(config_file, "wt"); +#ifdef ANSI_CFG + FILE *f = _wfopen(config_file, L"wt"); +#else + FILE *f = _wfopen(config_file, L"wt, ccs=UNICODE"); +#endif fclose(f); } + static section_t *find_section(char *name) { section_t *current_section; @@ -219,6 +269,7 @@ static section_t *find_section(char *name) return NULL; } + static entry_t *find_entry(section_t *section, char *name) { entry_t *current_entry; @@ -235,6 +286,27 @@ static entry_t *find_entry(section_t *section, char *name) return NULL; } + +static int entries_num(section_t *section) +{ + entry_t *current_entry; + int i = 0; + + current_entry = (entry_t *)section->entry_head.next; + + while (current_entry) + { + if (strlen(current_entry->name) > 0) + { + i++; + } + + current_entry = (entry_t *)current_entry->list.next; + } + return i; +} + + static section_t *create_section(char *name) { section_t *new_section = malloc(sizeof(section_t)); @@ -246,6 +318,7 @@ static section_t *create_section(char *name) return new_section; } + static entry_t *create_entry(section_t *section, char *name) { entry_t *new_entry = malloc(sizeof(entry_t)); @@ -255,7 +328,8 @@ static entry_t *create_entry(section_t *section, char *name) return new_entry; } - + + int config_get_int(char *head, char *name, int def) { section_t *section; @@ -277,6 +351,73 @@ int config_get_int(char *head, char *name, int def) return value; } + +int config_get_hex16(char *head, char *name, int def) +{ + section_t *section; + entry_t *entry; + int value; + + section = find_section(head); + + if (!section) + return def; + + entry = find_entry(section, name); + + if (!entry) + return def; + + sscanf(entry->data, "%04X", &value); + + return value; +} + + +int config_get_hex20(char *head, char *name, int def) +{ + section_t *section; + entry_t *entry; + int value; + + section = find_section(head); + + if (!section) + return def; + + entry = find_entry(section, name); + + if (!entry) + return def; + + sscanf(entry->data, "%05X", &value); + + return value; +} + + +int config_get_mac(char *head, char *name, int def) +{ + section_t *section; + entry_t *entry; + int val0 = 0, val1 = 0, val2 = 0; + + section = find_section(head); + + if (!section) + return def; + + entry = find_entry(section, name); + + if (!entry) + return def; + + sscanf(entry->data, "%02x:%02x:%02x", &val0, &val1, &val2); + + return (val0 << 16) + (val1 << 8) + val2; +} + + char *config_get_string(char *head, char *name, char *def) { section_t *section; @@ -295,6 +436,65 @@ char *config_get_string(char *head, char *name, char *def) return entry->data; } + +wchar_t *config_get_wstring(char *head, char *name, wchar_t *def) +{ + section_t *section; + entry_t *entry; + + section = find_section(head); + + if (!section) + return def; + + entry = find_entry(section, name); + + if (!entry) + return def; + + return entry->wdata; +} + + +void config_delete_var(char *head, char *name) +{ + section_t *section; + entry_t *entry; + + section = find_section(head); + + if (!section) + return; + + entry = find_entry(section, name); + + if (!entry) + return; + + memset(entry->name, 0, strlen(entry->name)); + + return; +} + + +void config_delete_section_if_empty(char *head) +{ + section_t *section; + + section = find_section(head); + + if (!section) + return; + + if (entries_num(section) == 0) + { + memset(section->name, 0, strlen(section->name)); + } + + return; +} + + void config_set_int(char *head, char *name, int val) { section_t *section; @@ -311,8 +511,70 @@ void config_set_int(char *head, char *name, int val) entry = create_entry(section, name); sprintf(entry->data, "%i", val); + mbstowcs(entry->wdata, entry->data, 512); } + +void config_set_hex16(char *head, char *name, int val) +{ + section_t *section; + entry_t *entry; + + section = find_section(head); + + if (!section) + section = create_section(head); + + entry = find_entry(section, name); + + if (!entry) + entry = create_entry(section, name); + + sprintf(entry->data, "%04X", val); + mbstowcs(entry->wdata, entry->data, 512); +} + + +void config_set_hex20(char *head, char *name, int val) +{ + section_t *section; + entry_t *entry; + + section = find_section(head); + + if (!section) + section = create_section(head); + + entry = find_entry(section, name); + + if (!entry) + entry = create_entry(section, name); + + sprintf(entry->data, "%05X", val); + mbstowcs(entry->wdata, entry->data, 512); +} + + +void config_set_mac(char *head, char *name, int val) +{ + section_t *section; + entry_t *entry; + + section = find_section(head); + + if (!section) + section = create_section(head); + + entry = find_entry(section, name); + + if (!entry) + entry = create_entry(section, name); + + sprintf(entry->data, "%02x:%02x:%02x", (val >> 16) & 0xff, (val >> 8) & 0xff, val & 0xff); + mbstowcs(entry->wdata, entry->data, 512); +} + + void config_set_string(char *head, char *name, char *val) { section_t *section; @@ -329,6 +591,26 @@ void config_set_string(char *head, char *name, char *val) entry = create_entry(section, name); strncpy(entry->data, val, 256); + mbstowcs(entry->wdata, entry->data, 256); +} + + +void config_set_wstring(char *head, char *name, wchar_t *val) +{ + section_t *section; + entry_t *entry; + + section = find_section(head); + + if (!section) + section = create_section(head); + + entry = find_entry(section, name); + + if (!entry) + entry = create_entry(section, name); + + memcpy(entry->wdata, val, 512); } @@ -339,16 +621,37 @@ char *get_filename(char *s) { if (s[c] == '/' || s[c] == '\\') return &s[c+1]; - c--; + c--; } return s; } + +wchar_t *get_filename_w(wchar_t *s) +{ + int c = wcslen(s) - 1; + while (c > 0) + { + if (s[c] == L'/' || s[c] == L'\\') + return &s[c+1]; + c--; + } + return s; +} + + void append_filename(char *dest, char *s1, char *s2, int size) { sprintf(dest, "%s%s", s1, s2); } + +void append_filename_w(wchar_t *dest, wchar_t *s1, wchar_t *s2, int size) +{ + _swprintf(dest, L"%s%s", s1, s2); +} + + void put_backslash(char *s) { int c = strlen(s) - 1; @@ -356,6 +659,15 @@ void put_backslash(char *s) s[c] = '/'; } + +void put_backslash_w(wchar_t *s) +{ + int c = wcslen(s) - 1; + if (s[c] != L'/' && s[c] != L'\\') + s[c] = L'/'; +} + + char *get_extension(char *s) { int c = strlen(s) - 1; @@ -372,25 +684,78 @@ char *get_extension(char *s) return &s[c+1]; } -void config_save(char *fn) + +wchar_t *get_extension_w(wchar_t *s) +{ + int c = wcslen(s) - 1; + + if (c <= 0) + return s; + + while (c && s[c] != L'.') + c--; + + if (!c) + return &s[wcslen(s)]; + + return &s[c+1]; +} + + +static wchar_t wname[512]; + + +void config_save(wchar_t *fn) { - FILE *f = fopen(fn, "wt"); section_t *current_section; - + FILE *f; + int fl = 0; + +#ifdef ANSI_CFG + f = _wfopen(fn, L"wt"); +#else + f = _wfopen(fn, L"wt, ccs=UNICODE"); +#endif + if (f == NULL) + return; + current_section = (section_t *)config_head.next; - while (current_section) { entry_t *current_entry; if (current_section->name[0]) - fprintf(f, "\n[%s]\n", current_section->name); + { + mbstowcs(wname, current_section->name, strlen(current_section->name) + 1); + if (fl) + { + fwprintf(f, L"\n[%ws]\n", wname); + } + else + { + fwprintf(f, L"[%ws]\n", wname); + } + fl++; + } current_entry = (entry_t *)current_section->entry_head.next; while (current_entry) { - fprintf(f, "%s = %s\n", current_entry->name, current_entry->data); + if(strlen(current_entry->name) > 0) + { + mbstowcs(wname, current_entry->name, strlen(current_entry->name) + 1); + if (current_entry->wdata[0] == L'\0') + { + fwprintf(f, L"%ws = \n", wname); + } + else + { + fwprintf(f, L"%ws = %ws\n", wname, current_entry->wdata); + } + + fl++; + } current_entry = (entry_t *)current_entry->list.next; } @@ -400,3 +765,1716 @@ void config_save(char *fn) fclose(f); } + + +/* General */ +static void loadconfig_general(void) +{ + char *cat = "General"; + char temps[512]; + char *p; + + vid_resize = !!config_get_int(cat, "vid_resize", 0); + + memset(temps, '\0', sizeof(temps)); + p = config_get_string(cat, "vid_renderer", "d3d9"); + if (p != NULL) + { + strcpy(temps, p); + } + if (!strcmp(temps, "ddraw")) + { + vid_api = 0; + } + else + { + vid_api = 1; + } + + config_delete_var(cat, "vid_api"); + + video_fullscreen_scale = config_get_int(cat, "video_fullscreen_scale", 0); + video_fullscreen_first = config_get_int(cat, "video_fullscreen_first", 0); + + force_43 = !!config_get_int(cat, "force_43", 0); + scale = config_get_int(cat, "scale", 1); + if (scale > 3) + { + scale = 3; + } + enable_overscan = !!config_get_int(cat, "enable_overscan", 0); + vid_cga_contrast = !!config_get_int(cat, "vid_cga_contrast", 0); + + + window_remember = config_get_int(cat, "window_remember", 0); + + if (window_remember) + { + p = config_get_string(cat, "window_coordinates", NULL); + if (p == NULL) + p = "0, 0, 0, 0"; + sscanf(p, "%i, %i, %i, %i", &window_w, &window_h, &window_x, &window_y); + } + else + { + config_delete_var(cat, "window_remember"); + config_delete_var(cat, "window_coordinates"); + window_w = window_h = window_x = window_y = 0; + } + +#ifndef __unix + /* Currently, 86Box is English (US) only, but in the future (version 1.30 at the earliest) other languages will be added, + therefore it is better to future-proof the code. */ + dwLanguage = config_get_hex16(cat, "language", 0x0409); +#endif +} + + +/* Machine */ +static void loadconfig_machine(void) +{ + char *cat = "Machine"; + wchar_t *wp; + char *p; + + p = config_get_string(cat, "model", NULL); + if (p != NULL) + model = model_get_model_from_internal_name(p); + else + model = 0; + if (model >= model_count()) + model = model_count() - 1; + + romset = model_getromset(); + cpu_manufacturer = config_get_int(cat, "cpu_manufacturer", 0); + cpu = config_get_int(cat, "cpu", 0); + cpu_waitstates = config_get_int(cat, "cpu_waitstates", 0); + + mem_size = config_get_int(cat, "mem_size", 4096); + if (mem_size < (((models[model].flags & MODEL_AT) && (models[model].ram_granularity < 128)) ? models[model].min_ram*1024 : models[model].min_ram)) + mem_size = (((models[model].flags & MODEL_AT) && (models[model].ram_granularity < 128)) ? models[model].min_ram*1024 : models[model].min_ram); + if (mem_size > 262144) + { + mem_size = 262144; + } + + memset(nvr_path, 0x00, sizeof(nvr_path)); + wp = config_get_wstring(cat, "nvr_path", L""); + if (wp != NULL) { + if (wcslen(wp) && (wcslen(wp) <= 992)) + { + wcscpy(nvr_path, wp); + } + else + { + append_filename_w(nvr_path, pcempath, L"nvr\\", 511); + } + } + else append_filename_w(nvr_path, pcempath, L"nvr\\", 511); + + if (nvr_path[wcslen(nvr_path) - 1] != L'/') + { + if (nvr_path[wcslen(nvr_path) - 1] != L'\\') + { + nvr_path[wcslen(nvr_path)] = L'\\'; + nvr_path[wcslen(nvr_path) + 1] = L'\0'; + } + } + + path_len = wcslen(nvr_path); + + cpu_use_dynarec = !!config_get_int(cat, "cpu_use_dynarec", 0); + + enable_external_fpu = !!config_get_int(cat, "cpu_enable_fpu", 0); + + enable_sync = !!config_get_int(cat, "enable_sync", 1); +} + + +/* Video */ +static void loadconfig_video(void) +{ + char *cat = "Video"; + char *p; + + p = config_get_string(cat, "gfxcard", NULL); + if (p != NULL) + gfxcard = video_get_video_from_internal_name(p); + else + gfxcard = 0; + + video_speed = config_get_int(cat, "video_speed", 3); + + voodoo_enabled = !!config_get_int(cat, "voodoo", 0); +} + + +/* Input devices */ +static void loadconfig_input_devices(void) +{ + char *cat = "Input devices"; + char temps[512]; + int c, d; + char *p; + + p = config_get_string(cat, "mouse_type", NULL); + if (p != NULL) + mouse_type = mouse_get_from_internal_name(p); + else + mouse_type = 0; + + joystick_type = config_get_int(cat, "joystick_type", 7); + + for (c = 0; c < joystick_get_max_joysticks(joystick_type); c++) + { + sprintf(temps, "joystick_%i_nr", c); + joystick_state[c].plat_joystick_nr = config_get_int(cat, temps, 0); + + if (joystick_state[c].plat_joystick_nr) + { + for (d = 0; d < joystick_get_axis_count(joystick_type); d++) + { + sprintf(temps, "joystick_%i_axis_%i", c, d); + joystick_state[c].axis_mapping[d] = config_get_int(cat, temps, d); + } + for (d = 0; d < joystick_get_button_count(joystick_type); d++) + { + sprintf(temps, "joystick_%i_button_%i", c, d); + joystick_state[c].button_mapping[d] = config_get_int(cat, temps, d); + } + for (d = 0; d < joystick_get_pov_count(joystick_type); d++) + { + sprintf(temps, "joystick_%i_pov_%i", c, d); + p = config_get_string(cat, temps, "0, 0"); + joystick_state[c].pov_mapping[d][0] = joystick_state[c].pov_mapping[d][1] = 0; + sscanf(p, "%i, %i", &joystick_state[c].pov_mapping[d][0], &joystick_state[c].pov_mapping[d][1]); + } + } + } +} + + +/* Sound */ +static void loadconfig_sound(void) +{ + char *cat = "Sound"; + char temps[512]; + char *p; + + p = config_get_string(cat, "sndcard", NULL); + if (p != NULL) + sound_card_current = sound_card_get_from_internal_name(p); + else + sound_card_current = 0; + + p = (char *)config_get_string(cat, "midi_device", NULL); + if (p != NULL) + midi_device_current = midi_device_get_from_internal_name(p); + else + midi_device_current = 0; + + mpu401_standalone_enable = !!config_get_int(cat, "mpu401_standalone", 0); + + SSI2001 = !!config_get_int(cat, "ssi2001", 0); + GAMEBLASTER = !!config_get_int(cat, "gameblaster", 0); + GUS = !!config_get_int(cat, "gus", 0); + + memset(temps, '\0', sizeof(temps)); + p = config_get_string(cat, "opl3_type", "dbopl"); + if (p != NULL) + { + strcpy(temps, p); + } + if (!strcmp(temps, "nukedopl") || !strcmp(temps, "1")) + { + opl3_type = 1; + } + else + { + opl3_type = 0; + } + + memset(temps, '\0', sizeof(temps)); + p = config_get_string(cat, "sound_type", "float"); + if (p != NULL) + { + strcpy(temps, p); + } + if (!strcmp(temps, "float") || !strcmp(temps, "1")) + { + sound_is_float = 1; + } + else + { + sound_is_float = 0; + } +} + + +/* Network */ +static void loadconfig_network(void) +{ + char *cat = "Network"; + char temps[512]; + char *p; + + memset(temps, '\0', sizeof(temps)); + p = config_get_string(cat, "net_type", "none"); + if (p != NULL) + { + strcpy(temps, p); + } + if (!strcmp(temps, "slirp") || !strcmp(temps, "2")) + { + network_type = NET_TYPE_SLIRP; + } + else if (!strcmp(temps, "pcap") || !strcmp(temps, "1")) + { + network_type = NET_TYPE_PCAP; + } + else + { + network_type = NET_TYPE_NONE; + } + + memset(network_pcap, '\0', sizeof(network_pcap)); + p = config_get_string(cat, "net_pcap_device", "none"); + if (p != NULL) + if ((network_dev_to_id(p) == -1) || (network_ndev == 1)) + { + if ((network_ndev == 1) && strcmp(network_pcap, "none")) + { + msgbox_error(ghwnd, IDS_2107); + } + else if (network_dev_to_id(p) == -1) + { + msgbox_error(ghwnd, IDS_2200); + } + + strcpy(network_pcap, "none"); + } + else + { + strcpy(network_pcap, p); + } + else + strcpy(network_pcap, "none"); + p = config_get_string(cat, "net_card", NULL); + if (p != NULL) + network_card = network_card_get_from_internal_name(p); + else + network_card = 0; +} + + +/* Other peripherals */ +static void loadconfig_other_peripherals(void) +{ + char *cat = "Other peripherals"; + char temps[512]; + char *p; + int c; + + p = config_get_string(cat, "scsicard", NULL); + if (p != NULL) + scsi_card_current = scsi_card_get_from_internal_name(p); + else + scsi_card_current = 0; + + memset(hdd_controller_name, '\0', sizeof(hdd_controller_name)); + p = config_get_string(cat, "hdd_controller", NULL); + if (p != NULL) + strcpy(hdd_controller_name, p); + else + strcpy(hdd_controller_name, "none"); + + memset(temps, '\0', sizeof(temps)); + for (c = 2; c < 4; c++) + { + sprintf(temps, "ide_%02i", c + 1); + p = config_get_string(cat, temps, NULL); + if (p == NULL) + p = "0, 00"; + sscanf(p, "%i, %02i", &ide_enable[c], &ide_irq[c]); + } + + serial_enabled[0] = !!config_get_int(cat, "serial1_enabled", 1); + serial_enabled[1] = !!config_get_int(cat, "serial2_enabled", 1); + lpt_enabled = !!config_get_int(cat, "lpt_enabled", 1); + bugger_enabled = !!config_get_int(cat, "bugger_enabled", 0); +} + + +static int config_string_to_bus(char *str, int cdrom) +{ + if (!strcmp(str, "none")) + { + return HDD_BUS_DISABLED; + } + + if (!strcmp(str, "mfm")) + { + if (cdrom) goto no_mfm_cdrom; + + return HDD_BUS_MFM; + } + + if (!strcmp(str, "rll")) + { + if (cdrom) goto no_mfm_cdrom; + + return HDD_BUS_RLL; + } + + if (!strcmp(str, "esdi")) + { + if (cdrom) goto no_mfm_cdrom; + + return HDD_BUS_RLL; + } + + if (!strcmp(str, "ide_pio_only")) + { + return HDD_BUS_IDE_PIO_ONLY; + } + + if (!strcmp(str, "ide")) + { + return HDD_BUS_IDE_PIO_ONLY; + } + + if (!strcmp(str, "atapi_pio_only")) + { + return HDD_BUS_IDE_PIO_ONLY; + } + + if (!strcmp(str, "atapi")) + { + return HDD_BUS_IDE_PIO_ONLY; + } + + if (!strcmp(str, "eide")) + { + return HDD_BUS_IDE_PIO_ONLY; + } + + if (!strcmp(str, "xtide")) + { + return HDD_BUS_XTIDE; + } + + if (!strcmp(str, "atide")) + { + return HDD_BUS_IDE_PIO_ONLY; + } + + if (!strcmp(str, "ide_pio_and_dma")) + { + return HDD_BUS_IDE_PIO_AND_DMA; + } + + if (!strcmp(str, "atapi_pio_and_dma")) + { + return HDD_BUS_IDE_PIO_AND_DMA; + } + + if (!strcmp(str, "scsi")) + { + return HDD_BUS_SCSI; + } + + if (!strcmp(str, "removable")) + { + if (cdrom) goto no_mfm_cdrom; + + return HDD_BUS_SCSI_REMOVABLE; + } + + if (!strcmp(str, "scsi_removable")) + { + if (cdrom) goto no_mfm_cdrom; + + return HDD_BUS_SCSI_REMOVABLE; + } + + if (!strcmp(str, "removable_scsi")) + { + if (cdrom) goto no_mfm_cdrom; + + return HDD_BUS_SCSI_REMOVABLE; + } + + if (!strcmp(str, "usb")) + { + msgbox_error(ghwnd, IDS_2199); + return 0; + } + + return 0; + +no_mfm_cdrom: + msgbox_error(ghwnd, IDS_2095); + return 0; +} + + +static int hard_disk_is_valid(int c) +{ + if (hdc[c].bus == HDD_BUS_DISABLED) + { + return 0; + } + + if ((wcslen(hdc[c].fn) == 0) && (hdc[c].bus != HDD_BUS_SCSI_REMOVABLE)) + { + return 0; + } + + if ((hdc[c].tracks == 0) || (hdc[c].hpc == 0) || (hdc[c].spt == 0)) + { + return 0; + } + + return 1; +} + + +static int tally_char(char *string, char c) +{ + int i = 0; + int tally = 0; + + if (string == NULL) + { + return 0; + } + + if (strlen(string) == 0) + { + return 0; + } + + for (i = 0; i < strlen(string); i++) + { + if (string[i] == c) + { + tally++; + } + } + + return tally; +} + + +/* Hard disks */ +static void loadconfig_hard_disks(void) +{ + char *cat = "Hard disks"; + char temps[512]; + char temps2[512]; + char s[512]; + int c; + char *p; + wchar_t *wp; + int max_spt, max_hpc, max_tracks; + int board = 0, dev = 0; + + memset(temps, '\0', sizeof(temps)); + for (c = 0; c < HDC_NUM; c++) + { + sprintf(temps, "hdd_%02i_parameters", c + 1); + p = config_get_string(cat, temps, NULL); + if (p == NULL) + p = "0, 0, 0, 0, none"; + if (tally_char(p, ',') == 3) + { + sscanf(p, "%" PRIu64 ", %" PRIu64", %" PRIu64 ", %s", &hdc[c].spt, &hdc[c].hpc, &hdc[c].tracks, s); + hdc[c].wp = 0; + } + else + { + sscanf(p, "%" PRIu64 ", %" PRIu64", %" PRIu64 ", %i, %s", &hdc[c].spt, &hdc[c].hpc, &hdc[c].tracks, &hdc[c].wp, s); + } + + hdc[c].bus = config_string_to_bus(s, 0); + + switch(hdc[c].bus) + { + case HDD_BUS_DISABLED: + default: + max_spt = max_hpc = max_tracks = 0; + break; + case HDD_BUS_MFM: + max_spt = 17; + max_hpc = 15; + max_tracks = 1023; + break; + case HDD_BUS_RLL: + case HDD_BUS_XTIDE: + max_spt = 63; + max_hpc = 16; + max_tracks = 1023; + break; + case HDD_BUS_IDE_PIO_ONLY: + case HDD_BUS_IDE_PIO_AND_DMA: + max_spt = 63; + max_hpc = 16; + max_tracks = 266305; + break; + case HDD_BUS_SCSI: + case HDD_BUS_SCSI_REMOVABLE: + max_spt = 99; + max_hpc = 255; + max_tracks = 266305; + break; + } + + if (hdc[c].spt > max_spt) + { + hdc[c].spt = max_spt; + } + if (hdc[c].hpc > max_hpc) + { + hdc[c].hpc = max_hpc; + } + if (hdc[c].tracks > max_tracks) + { + hdc[c].tracks = max_tracks; + } + + /* MFM */ + sprintf(temps, "hdd_%02i_mfm_channel", c + 1); + if (hdc[c].bus == HDD_BUS_MFM) + { + hdc[c].mfm_channel = !!config_get_int(cat, temps, c & 1); + } + else + { + config_delete_var(cat, temps); + } + + /* XT IDE */ + sprintf(temps, "hdd_%02i_xtide_channel", c + 1); + if (hdc[c].bus == HDD_BUS_XTIDE) + { + hdc[c].xtide_channel = !!config_get_int(cat, temps, c & 1); + } + else + { + config_delete_var(cat, temps); + } + + /* RLL (ESDI) */ + sprintf(temps, "hdd_%02i_rll_channel", c + 1); + if (hdc[c].bus == HDD_BUS_RLL) + { + hdc[c].rll_channel = !!config_get_int(cat, temps, c & 1); + } + else + { + config_delete_var(cat, temps); + } + + /* IDE */ + sprintf(temps, "hdd_%02i_ide_channel", c + 1); + if ((hdc[c].bus == HDD_BUS_IDE_PIO_ONLY) || (hdc[c].bus == HDD_BUS_IDE_PIO_AND_DMA)) + { + sprintf(temps2, "%01u:%01u", c >> 1, c & 1); + p = config_get_string(cat, temps, temps2); + + if (strstr(p, ":") == NULL) + { + sscanf(p, "%i", &hdc[c].ide_channel); + hdc[c].ide_channel &= 7; + } + else + { + sscanf(p, "%01u:%01u", &board, &dev); + + board &= 3; + dev &= 1; + hdc[c].ide_channel = (board << 1) + dev; + } + + if (hdc[c].ide_channel > 7) + { + hdc[c].ide_channel = 7; + } + } + else + { + config_delete_var(cat, temps); + } + + /* SCSI */ + sprintf(temps, "hdd_%02i_scsi_location", c + 1); + if ((hdc[c].bus == HDD_BUS_SCSI) || (hdc[c].bus == HDD_BUS_SCSI_REMOVABLE)) + { + sprintf(temps2, "%02u:%02u", c, 0); + p = config_get_string(cat, temps, temps2); + + sscanf(p, "%02u:%02u", &hdc[c].scsi_id, &hdc[c].scsi_lun); + + if (hdc[c].scsi_id > 15) + { + hdc[c].scsi_id = 15; + } + if (hdc[c].scsi_lun > 7) + { + hdc[c].scsi_lun = 7; + } + } + else + { + config_delete_var(cat, temps); + } + + memset(hdc[c].fn, 0, sizeof(hdc[c].fn)); + memset(hdc[c].prev_fn, 0, sizeof(hdc[c].prev_fn)); + sprintf(temps, "hdd_%02i_fn", c + 1); + wp = config_get_wstring(cat, temps, L""); + memcpy(hdc[c].fn, wp, (wcslen(wp) << 1) + 2); + + /* If the hard disk is in any way empty or invalid, mark the relevant variables for deletion. */ + if (!hard_disk_is_valid(c)) + { + sprintf(temps, "hdd_%02i_parameters", c + 1); + config_delete_var(cat, temps); + + sprintf(temps, "hdd_%02i_preide_channels", c + 1); + config_delete_var(cat, temps); + + sprintf(temps, "hdd_%02i_ide_channels", c + 1); + config_delete_var(cat, temps); + + sprintf(temps, "hdd_%02i_scsi_location", c + 1); + config_delete_var(cat, temps); + + sprintf(temps, "hdd_%02i_fn", c + 1); + config_delete_var(cat, temps); + } + + sprintf(temps, "hdd_%02i_mfm_channel", c + 1); + config_delete_var(cat, temps); + + sprintf(temps, "hdd_%02i_ide_channel", c + 1); + config_delete_var(cat, temps); + } +} + + +/* Removable devices */ +static void loadconfig_removable_devices(void) +{ + char *cat = "Removable devices"; + char temps[512]; + char temps2[512]; + char s[512]; + int c; + char *p; + wchar_t *wp; + unsigned int board = 0, dev = 0; + + for (c = 0; c < FDD_NUM; c++) + { + sprintf(temps, "fdd_%02i_type", c + 1); + p = config_get_string(cat, temps, (c < 2) ? "525_2dd" : "none"); + fdd_set_type(c, fdd_get_from_internal_name(p)); + if (fdd_get_type(c) > 13) + { + fdd_set_type(c, 13); + } + + sprintf(temps, "fdd_%02i_fn", c + 1); + wp = config_get_wstring(cat, temps, L""); + memcpy(discfns[c], wp, (wcslen(wp) << 1) + 2); + printf("Floppy: %ws\n", discfns[c]); + sprintf(temps, "fdd_%02i_writeprot", c + 1); + ui_writeprot[c] = !!config_get_int(cat, temps, 0); + sprintf(temps, "fdd_%02i_turbo", c + 1); + fdd_set_turbo(c, !!config_get_int(cat, temps, 0)); + + /* Check, whether each value is default, if yes, delete it so that only non-default values will later be saved. */ + if (fdd_get_type(c) == ((c < 2) ? 2 : 0)) + { + sprintf(temps, "fdd_%02i_type", c + 1); + config_delete_var(cat, temps); + } + + if (wcslen(discfns[c]) == 0) + { + sprintf(temps, "fdd_%02i_fn", c + 1); + config_delete_var(cat, temps); + } + + if (ui_writeprot[c] == 0) + { + sprintf(temps, "fdd_%02i_writeprot", c + 1); + config_delete_var(cat, temps); + } + + if (fdd_get_turbo(c) == 0) + { + sprintf(temps, "fdd_%02i_turbo", c + 1); + config_delete_var(cat, temps); + } + } + + memset(temps, 0, 512); + for (c = 0; c < CDROM_NUM; c++) + { + sprintf(temps, "cdrom_%02i_host_drive", c + 1); + cdrom_drives[c].host_drive = config_get_int(cat, temps, 0); + cdrom_drives[c].prev_host_drive = cdrom_drives[c].host_drive; + + sprintf(temps, "cdrom_%02i_parameters", c + 1); + p = config_get_string(cat, temps, NULL); + if (p != NULL) + { + sscanf(p, "%u, %s", &cdrom_drives[c].sound_on, s); + } + else + { + sscanf("0, none", "%u, %s", &cdrom_drives[c].sound_on, s); + } + + cdrom_drives[c].bus_type = config_string_to_bus(s, 1); + + sprintf(temps, "cdrom_%02i_ide_channel", c + 1); + if ((cdrom_drives[c].bus_type == CDROM_BUS_ATAPI_PIO_ONLY) || (cdrom_drives[c].bus_type == CDROM_BUS_ATAPI_PIO_AND_DMA)) + { + sprintf(temps2, "%01u:%01u", (c + 2) >> 1, (c + 2) & 1); + p = config_get_string(cat, temps, temps2); + + if (strstr(p, ":") == NULL) + { + sscanf(p, "%i", &hdc[c].ide_channel); + cdrom_drives[c].ide_channel &= 7; + } + else + { + sscanf(p, "%02u:%02u", &board, &dev); + + board &= 3; + dev &= 1; + cdrom_drives[c].ide_channel = (board << 1) + dev; + } + + if (cdrom_drives[c].ide_channel > 7) + { + cdrom_drives[c].ide_channel = 7; + } + } + else + { + config_delete_var(cat, temps); + } + + sprintf(temps, "cdrom_%02i_scsi_location", c + 1); + if (cdrom_drives[c].bus_type == CDROM_BUS_SCSI) + { + sprintf(temps2, "%02u:%02u", c + 2, 0); + p = config_get_string(cat, temps, temps2); + sscanf(p, "%02u:%02u", &cdrom_drives[c].scsi_device_id, &cdrom_drives[c].scsi_device_lun); + + if (cdrom_drives[c].scsi_device_id > 15) + { + cdrom_drives[c].scsi_device_id = 15; + } + if (cdrom_drives[c].scsi_device_lun > 7) + { + cdrom_drives[c].scsi_device_lun = 7; + } + } + else + { + config_delete_var(cat, temps); + } + + sprintf(temps, "cdrom_%02i_image_path", c + 1); + wp = config_get_wstring(cat, temps, L""); + memcpy(cdrom_image[c].image_path, wp, (wcslen(wp) << 1) + 2); + + if (cdrom_drives[c].host_drive < 'A') + { + cdrom_drives[c].host_drive = 0; + } + + if ((cdrom_drives[c].host_drive == 0x200) && (wcslen(cdrom_image[c].image_path) == 0)) + { + cdrom_drives[c].host_drive = 0; + } + + /* If the CD-ROM is disabled, delete all its variables. */ + if (cdrom_drives[c].bus_type == CDROM_BUS_DISABLED) + { + sprintf(temps, "cdrom_%02i_host_drive", c + 1); + config_delete_var(cat, temps); + + sprintf(temps, "cdrom_%02i_parameters", c + 1); + config_delete_var(cat, temps); + + sprintf(temps, "cdrom_%02i_ide_channel", c + 1); + config_delete_var(cat, temps); + + sprintf(temps, "cdrom_%02i_scsi_location", c + 1); + config_delete_var(cat, temps); + + sprintf(temps, "cdrom_%02i_image_path", c + 1); + config_delete_var(cat, temps); + } + + sprintf(temps, "cdrom_%02i_iso_path", c + 1); + config_delete_var(cat, temps); + } +} + + +void loadconfig(wchar_t *fn) +{ + int i = 0; + + if (fn == NULL) + fn = config_file_default; + i = config_load(fn); + + if (i == 0) + { + cpu = 0; +#ifndef __unix + dwLanguage = 0x0409; +#endif + scale = 1; + vid_api = 1; + enable_sync = 1; + joystick_type = 7; + strcpy(hdd_controller_name, "none"); + serial_enabled[0] = 1; + serial_enabled[1] = 1; + lpt_enabled = 1; + fdd_set_type(0, 2); + fdd_set_type(1, 2); + mem_size = 640; + + return; + } + + /* General */ + loadconfig_general(); + + /* Machine */ + loadconfig_machine(); + + /* Video */ + loadconfig_video(); + + /* Input devices */ + loadconfig_input_devices(); + + /* Sound */ + loadconfig_sound(); + + /* Network */ + loadconfig_network(); + + /* Other peripherals */ + loadconfig_other_peripherals(); + + /* Hard disks */ + loadconfig_hard_disks(); + + /* Removable devices */ + loadconfig_removable_devices(); + +} + + +wchar_t *nvr_concat(wchar_t *to_concat) +{ + static wchar_t temp_nvr_path[1024]; + char *p; + wchar_t *wp; + + memset(temp_nvr_path, 0, 2048); + wcscpy(temp_nvr_path, nvr_path); + + p = (char *) temp_nvr_path; + p += (path_len * 2); + wp = (wchar_t *) p; + + wcscpy(wp, to_concat); + return temp_nvr_path; +} + + +static void saveconfig_general(void) +{ + char *cat = "General"; + char temps[512]; + + config_set_int(cat, "vid_resize", vid_resize); + if (vid_resize == 0) + { + config_delete_var(cat, "vid_resize"); + } + + if (vid_api == 1) + { + config_delete_var(cat, "vid_renderer"); + } + else + { + switch(vid_api) + { + case 0: + config_set_string(cat, "vid_renderer", "ddraw"); + break; + case 1: + default: + config_set_string(cat, "vid_renderer", "d3d9"); + break; + } + } + + if (video_fullscreen_scale == 0) + { + config_delete_var(cat, "video_fullscreen_scale"); + } + else + { + config_set_int(cat, "video_fullscreen_scale", video_fullscreen_scale); + } + + if (video_fullscreen_first == 0) + { + config_delete_var(cat, "video_fullscreen_first"); + } + else + { + config_set_int(cat, "video_fullscreen_first", video_fullscreen_first); + } + + if (force_43 == 0) + { + config_delete_var(cat, "force_43"); + } + else + { + config_set_int(cat, "force_43", force_43); + } + + if (scale == 1) + { + config_delete_var(cat, "scale"); + } + else + { + config_set_int(cat, "scale", scale); + } + + if (enable_overscan == 0) + { + config_delete_var(cat, "enable_overscan"); + } + else + { + config_set_int(cat, "enable_overscan", enable_overscan); + } + + if (vid_cga_contrast == 0) + { + config_delete_var(cat, "vid_cga_contrast"); + } + else + { + config_set_int(cat, "vid_cga_contrast", vid_cga_contrast); + } + + + if (window_remember) + { + config_set_int(cat, "window_remember", window_remember); + + sprintf(temps, "%i, %i, %i, %i", window_w, window_h, window_x, window_y); + config_set_string(cat, "window_coordinates", temps); + } + else + { + config_delete_var(cat, "window_remember"); + config_delete_var(cat, "window_coordinates"); + } + +#ifndef __unix + if (dwLanguage == 0x0409) + { + config_delete_var(cat, "language"); + } + else + { + config_set_hex16(cat, "language", dwLanguage); + } +#endif + + config_delete_section_if_empty(cat); +} + + +/* Machine */ +static void saveconfig_machine(void) +{ + char *cat = "Machine"; + + config_set_string(cat, "model", model_get_internal_name()); + + if (cpu_manufacturer == 0) + { + config_delete_var(cat, "cpu_manufacturer"); + } + else + { + config_set_int(cat, "cpu_manufacturer", cpu_manufacturer); + } + + if (cpu == 0) + { + config_delete_var(cat, "cpu"); + } + else + { + config_set_int(cat, "cpu", cpu); + } + + if (cpu_waitstates == 0) + { + config_delete_var(cat, "cpu_waitstates"); + } + else + { + config_set_int(cat, "cpu_waitstates", cpu_waitstates); + } + + if (mem_size == 4096) + { + config_delete_var(cat, "mem_size"); + } + else + { + config_set_int(cat, "mem_size", mem_size); + } + + config_set_wstring(cat, "nvr_path", nvr_path); + + config_set_int(cat, "cpu_use_dynarec", cpu_use_dynarec); + + if (enable_external_fpu == 0) + { + config_delete_var(cat, "cpu_enable_fpu"); + } + else + { + config_set_int(cat, "cpu_enable_fpu", enable_external_fpu); + } + + if (enable_sync == 1) + { + config_delete_var(cat, "enable_sync"); + } + else + { + config_set_int(cat, "enable_sync", enable_sync); + } + + config_delete_section_if_empty(cat); +} + + +/* Video */ +static void saveconfig_video(void) +{ + char *cat = "Video"; + + config_set_string(cat, "gfxcard", video_get_internal_name(video_old_to_new(gfxcard))); + + if (video_speed == 3) + { + config_delete_var(cat, "video_speed"); + } + else + { + config_set_int(cat, "video_speed", video_speed); + } + + if (voodoo_enabled == 0) + { + config_delete_var(cat, "voodoo"); + } + else + { + config_set_int(cat, "voodoo", voodoo_enabled); + } + + config_delete_section_if_empty(cat); +} + + +/* Input devices */ +static void saveconfig_input_devices(void) +{ + char *cat = "Input devices"; + char temps[512]; + char s[512]; + int c, d; + + config_set_string(cat, "mouse_type", mouse_get_internal_name(mouse_type)); + + if ((joystick_type == 0) || (joystick_type == 7)) + { + if (joystick_type == 7) + { + config_delete_var(cat, "joystick_type"); + } + else + { + config_set_int(cat, "joystick_type", joystick_type); + } + + for (c = 0; c < 16; c++) + { + sprintf(s, "joystick_%i_nr", c); + config_delete_var(cat, s); + + for (d = 0; d < 16; d++) + { + sprintf(s, "joystick_%i_axis_%i", c, d); + config_delete_var(cat, s); + } + for (d = 0; d < 16; d++) + { + sprintf(s, "joystick_%i_button_%i", c, d); + config_delete_var(cat, s); + } + for (d = 0; d < 16; d++) + { + sprintf(s, "joystick_%i_pov_%i", c, d); + config_delete_var(cat, s); + } + } + } + else + { + config_set_int(cat, "joystick_type", joystick_type); + + for (c = 0; c < joystick_get_max_joysticks(joystick_type); c++) + { + sprintf(s, "joystick_%i_nr", c); + config_set_int(cat, s, joystick_state[c].plat_joystick_nr); + + if (joystick_state[c].plat_joystick_nr) + { + for (d = 0; d < joystick_get_axis_count(joystick_type); d++) + { + sprintf(s, "joystick_%i_axis_%i", c, d); + config_set_int(cat, s, joystick_state[c].axis_mapping[d]); + } + for (d = 0; d < joystick_get_button_count(joystick_type); d++) + { + sprintf(s, "joystick_%i_button_%i", c, d); + config_set_int(cat, s, joystick_state[c].button_mapping[d]); + } + for (d = 0; d < joystick_get_pov_count(joystick_type); d++) + { + sprintf(s, "joystick_%i_pov_%i", c, d); + sprintf(temps, "%i, %i", joystick_state[c].pov_mapping[d][0], joystick_state[c].pov_mapping[d][1]); + config_set_string(cat, s, temps); + } + } + } + } + + config_delete_section_if_empty(cat); +} + + +/* Sound */ +static void saveconfig_sound(void) +{ + char *cat = "Sound"; + + if (sound_card_current == 0) + { + config_delete_var(cat, "sndcard"); + } + else + { + config_set_string(cat, "sndcard", sound_card_get_internal_name(sound_card_current)); + } + + + if (!strcmp(midi_device_get_internal_name(midi_device_current), "none")) + { + config_delete_var(cat, "midi_device"); + } + else + { + config_set_string(cat, "midi_device", midi_device_get_internal_name(midi_device_current)); + } + + if (mpu401_standalone_enable == 0) + { + config_delete_var(cat, "mpu401_standalone"); + } + else + { + config_set_int(cat, "mpu401_standalone", mpu401_standalone_enable); + } + + if (SSI2001 == 0) + { + config_delete_var(cat, "ssi2001"); + } + else + { + config_set_int(cat, "ssi2001", SSI2001); + } + + if (GAMEBLASTER == 0) + { + config_delete_var(cat, "gameblaster"); + } + else + { + config_set_int(cat, "gameblaster", GAMEBLASTER); + } + + if (GUS == 0) + { + config_delete_var(cat, "gus"); + } + else + { + config_set_int(cat, "gus", GUS); + } + + if (opl3_type == 0) + { + config_delete_var(cat, "opl3_type"); + } + else + { + config_set_string(cat, "opl3_type", (opl3_type == 1) ? "nukedopl" : "dbopl"); + } + + if (sound_is_float == 1) + { + config_delete_var(cat, "sound_type"); + } + else + { + config_set_string(cat, "sound_type", (sound_is_float == 1) ? "float" : "int16"); + } + + config_delete_section_if_empty(cat); +} + + +/* Network */ +static void saveconfig_network(void) +{ + char *cat = "Network"; + + if (network_type == NET_TYPE_NONE) + { + config_delete_var(cat, "net_type"); + } + else + { + config_set_string(cat, "net_type", (network_type == NET_TYPE_SLIRP) ? "slirp" : "pcap"); + } + + if (network_pcap[0] != '\0') + { + if (!strcmp(network_pcap, "none")) + { + config_delete_var(cat, "net_pcap_device"); + } + else + { + config_set_string(cat, "net_pcap_device", network_pcap); + } + } + else + { + /* config_set_string(cat, "net_pcap_device", "none"); */ + config_delete_var(cat, "net_pcap_device"); + } + + if (network_card == 0) + { + config_delete_var(cat, "net_card"); + } + else + { + config_set_string(cat, "net_card", network_card_get_internal_name(network_card)); + } + + config_delete_section_if_empty(cat); +} + + +/* Other peripherals */ +static void saveconfig_other_peripherals(void) +{ + char *cat = "Other peripherals"; + char temps[512]; + char temps2[512]; + int c; + + if (scsi_card_current == 0) + { + config_delete_var(cat, "scsicard"); + } + else + { + config_set_string(cat, "scsicard", scsi_card_get_internal_name(scsi_card_current)); + } + + if (!strcmp(hdd_controller_name, "none")) + { + config_delete_var(cat, "hdd_controller"); + } + else + { + config_set_string(cat, "hdd_controller", hdd_controller_name); + } + + memset(temps, '\0', sizeof(temps)); + for (c = 2; c < 4; c++) + { + sprintf(temps, "ide_%02i", c + 1); + sprintf(temps2, "%i, %02i", !!ide_enable[c], ide_irq[c]); + + if (ide_enable[c] == 0) + { + config_delete_var(cat, temps); + } + else + { + config_set_string(cat, temps, temps2); + } + } + + if (serial_enabled[0]) + { + config_delete_var(cat, "serial1_enabled"); + } + else + { + config_set_int(cat, "serial1_enabled", serial_enabled[0]); + } + + if (serial_enabled[1]) + { + config_delete_var(cat, "serial2_enabled"); + } + else + { + config_set_int(cat, "serial2_enabled", serial_enabled[1]); + } + + if (lpt_enabled) + { + config_delete_var(cat, "lpt_enabled"); + } + else + { + config_set_int(cat, "lpt_enabled", lpt_enabled); + } + + if (bugger_enabled == 0) + { + config_delete_var(cat, "bugger_enabled"); + } + else + { + config_set_int(cat, "bugger_enabled", bugger_enabled); + } + + config_delete_section_if_empty(cat); +} + + +static char *config_bus_to_string(int bus, int cdrom) +{ + switch (bus) + { + case HDD_BUS_DISABLED: + default: + return "none"; + break; + case HDD_BUS_MFM: + return "mfm"; + break; + case HDD_BUS_XTIDE: + return "xtide"; + break; + case HDD_BUS_RLL: + return "rll"; + break; + case HDD_BUS_IDE_PIO_ONLY: + return cdrom ? "atapi_pio_only" : "ide_pio_only"; + break; + case HDD_BUS_IDE_PIO_AND_DMA: + return cdrom ? "atapi_pio_and_dma" : "ide_pio_and_dma"; + break; + case HDD_BUS_SCSI: + return "scsi"; + break; + case HDD_BUS_SCSI_REMOVABLE: + return "scsi_removable"; + break; + } +} + + +/* Hard disks */ +static void saveconfig_hard_disks(void) +{ + char *cat = "Hard disks"; + char temps[24]; + char temps2[64]; + char s[512]; + int c; + char *p; + + memset(temps, 0, sizeof(temps)); + for (c = 0; c < HDC_NUM; c++) + { + sprintf(temps, "hdd_%02i_parameters", c + 1); + memset(s, 0, sizeof(s)); + if (!hard_disk_is_valid(c)) + { + config_delete_var(cat, temps); + } + else + { + p = config_bus_to_string(hdc[c].bus, 0); + sprintf(temps2, "%" PRIu64 ", %" PRIu64", %" PRIu64 ", %i, %s", hdc[c].spt, hdc[c].hpc, hdc[c].tracks, hdc[c].wp, p); + config_set_string(cat, temps, temps2); + } + + sprintf(temps, "hdd_%02i_mfm_channel", c + 1); + if (!hard_disk_is_valid(c) || (hdc[c].bus != HDD_BUS_MFM)) + { + config_delete_var(cat, temps); + } + else + { + config_set_int(cat, temps, hdc[c].mfm_channel); + } + + sprintf(temps, "hdd_%02i_xtide_channel", c + 1); + if (!hard_disk_is_valid(c) || (hdc[c].bus != HDD_BUS_XTIDE)) + { + config_delete_var(cat, temps); + } + else + { + config_set_int(cat, temps, hdc[c].xtide_channel); + } + + sprintf(temps, "hdd_%02i_rll_channel", c + 1); + if (!hard_disk_is_valid(c) || (hdc[c].bus != HDD_BUS_RLL)) + { + config_delete_var(cat, temps); + } + else + { + config_set_int(cat, temps, hdc[c].rll_channel); + } + + sprintf(temps, "hdd_%02i_ide_channel", c + 1); + if (!hard_disk_is_valid(c) || ((hdc[c].bus != HDD_BUS_IDE_PIO_ONLY) && (hdc[c].bus != HDD_BUS_IDE_PIO_AND_DMA))) + { + config_delete_var(cat, temps); + } + else + { + sprintf(temps2, "%01u:%01u", hdc[c].ide_channel >> 1, hdc[c].ide_channel & 1); + config_set_string(cat, temps, temps2); + } + + sprintf(temps, "hdd_%02i_scsi_location", c + 1); + if (!hard_disk_is_valid(c) || ((hdc[c].bus != HDD_BUS_SCSI) && (hdc[c].bus != HDD_BUS_SCSI_REMOVABLE))) + { + config_delete_var(cat, temps); + } + else + { + sprintf(temps2, "%02u:%02u", hdc[c].scsi_id, hdc[c].scsi_lun); + config_set_string(cat, temps, temps2); + } + + sprintf(temps, "hdd_%02i_fn", c + 1); + if (!hard_disk_is_valid(c) || (wcslen(hdc[c].fn) == 0)) + { + config_delete_var(cat, temps); + } + else + { + config_set_wstring(cat, temps, hdc[c].fn); + } + } + + config_delete_section_if_empty(cat); +} + + +/* Removable devices */ +static void saveconfig_removable_devices(void) +{ + char *cat = "Removable devices"; + char temps[512]; + char temps2[512]; + int c; + + memset(temps, '\0', sizeof(temps)); + for (c = 0; c < FDD_NUM; c++) + { + sprintf(temps, "fdd_%02i_type", c + 1); + if (fdd_get_type(c) == ((c < 2) ? 2 : 0)) + { + config_delete_var(cat, temps); + } + else + { + config_set_string(cat, temps, fdd_get_internal_name(fdd_get_type(c))); + } + + sprintf(temps, "fdd_%02i_fn", c + 1); + if (wcslen(discfns[c]) == 0) + { + config_delete_var(cat, temps); + + ui_writeprot[c] = 0; + + sprintf(temps, "fdd_%02i_writeprot", c + 1); + config_delete_var(cat, temps); + } + else + { + config_set_wstring(cat, temps, discfns[c]); + } + + sprintf(temps, "fdd_%02i_writeprot", c + 1); + if (ui_writeprot[c] == 0) + { + config_delete_var(cat, temps); + } + else + { + config_set_int(cat, temps, ui_writeprot[c]); + } + + sprintf(temps, "fdd_%02i_turbo", c + 1); + if (fdd_get_turbo(c) == 0) + { + config_delete_var(cat, temps); + } + else + { + config_set_int(cat, temps, fdd_get_turbo(c)); + } + } + + memset(temps, '\0', sizeof(temps)); + for (c = 0; c < CDROM_NUM; c++) + { + sprintf(temps, "cdrom_%02i_host_drive", c + 1); + if ((cdrom_drives[c].bus_type == 0) || (cdrom_drives[c].host_drive < 'A') || ((cdrom_drives[c].host_drive > 'Z') && (cdrom_drives[c].host_drive != 200))) + { + config_delete_var(cat, temps); + } + else + { + config_set_int(cat, temps, cdrom_drives[c].host_drive); + } + + sprintf(temps, "cdrom_%02i_parameters", c + 1); + if (cdrom_drives[c].bus_type == 0) + { + config_delete_var(cat, temps); + } + else + { + sprintf(temps2, "%u, %s", cdrom_drives[c].sound_on, config_bus_to_string(cdrom_drives[c].bus_type, 1)); + config_set_string(cat, temps, temps2); + } + + sprintf(temps, "cdrom_%02i_ide_channel", c + 1); + if ((cdrom_drives[c].bus_type != CDROM_BUS_ATAPI_PIO_ONLY) && (cdrom_drives[c].bus_type != CDROM_BUS_ATAPI_PIO_AND_DMA)) + { + config_delete_var(cat, temps); + } + else + { + sprintf(temps2, "%01u:%01u", cdrom_drives[c].ide_channel >> 1, cdrom_drives[c].ide_channel & 1); + config_set_string(cat, temps, temps2); + } + + sprintf(temps, "cdrom_%02i_scsi_location", c + 1); + if (cdrom_drives[c].bus_type != CDROM_BUS_SCSI) + { + config_delete_var(cat, temps); + } + else + { + sprintf(temps2, "%02u:%02u", cdrom_drives[c].scsi_device_id, cdrom_drives[c].scsi_device_lun); + config_set_string(cat, temps, temps2); + } + + sprintf(temps, "cdrom_%02i_image_path", c + 1); + if ((cdrom_drives[c].bus_type == 0) || (wcslen(cdrom_image[c].image_path) == 0)) + { + config_delete_var(cat, temps); + } + else + { + config_set_wstring(cat, temps, cdrom_image[c].image_path); + } + } + + config_delete_section_if_empty(cat); +} + + +void saveconfig(void) +{ + /* General */ + saveconfig_general(); + + /* Machine */ + saveconfig_machine(); + + /* Video */ + saveconfig_video(); + + /* Input devices */ + saveconfig_input_devices(); + + /* Sound */ + saveconfig_sound(); + + /* Network */ + saveconfig_network(); + + /* Other peripherals */ + saveconfig_other_peripherals(); + + /* Hard disks */ + saveconfig_hard_disks(); + + /* Removable devices */ + saveconfig_removable_devices(); + + config_save(config_file_default); +} diff --git a/src/config.h b/src/config.h index 55e091e52..8d1db0b7b 100644 --- a/src/config.h +++ b/src/config.h @@ -1,19 +1,46 @@ /* Copyright holders: Sarah Walker see COPYING for more details */ -int config_get_int(char *head, char *name, int def); -char *config_get_string(char *head, char *name, char *def); -void config_set_int(char *head, char *name, int val); -void config_set_string(char *head, char *name, char *val); -char *get_filename(char *s); -void append_filename(char *dest, char *s1, char *s2, int size); -void put_backslash(char *s); -char *get_extension(char *s); -void config_load(char *fn); -void config_save(char *fn); -void config_dump(); -void config_free(); +extern wchar_t config_file_default[256]; -extern char config_file_default[256]; + +#ifdef __cplusplus +extern "C" { +#endif + +extern int config_get_int(char *head, char *name, int def); +extern int config_get_hex16(char *head, char *name, int def); +extern int config_get_hex20(char *head, char *name, int def); +extern int config_get_mac(char *head, char *name, int def); +extern char *config_get_string(char *head, char *name, char *def); +extern wchar_t *config_get_wstring(char *head, char *name, wchar_t *def); +extern void config_delete_var(char *head, char *name); +extern void config_set_int(char *head, char *name, int val); +extern void config_set_hex16(char *head, char *name, int val); +extern void config_set_hex20(char *head, char *name, int val); +extern void config_set_mac(char *head, char *name, int val); +extern void config_set_string(char *head, char *name, char *val); +extern void config_set_wstring(char *head, char *name, wchar_t *val); + +extern char *get_filename(char *s); +extern wchar_t *get_filename_w(wchar_t *s); +extern void append_filename(char *dest, char *s1, char *s2, int size); +extern void append_filename_w(wchar_t *dest, wchar_t *s1, wchar_t *s2, int size); +extern void put_backslash(char *s); +extern void put_backslash_w(wchar_t *s); +extern char *get_extension(char *s); + +extern wchar_t *get_extension_w(wchar_t *s); + +extern int config_load(wchar_t *fn); +extern void config_save(wchar_t *fn); +extern void config_dump(void); + +extern void loadconfig(wchar_t *fn); +extern void saveconfig(void); + +#ifdef __cplusplus +} +#endif diff --git a/src/dac.c b/src/dac.c deleted file mode 100644 index 5a784d04c..000000000 --- a/src/dac.c +++ /dev/null @@ -1,71 +0,0 @@ -/* Copyright holders: Sarah Walker - see COPYING for more details -*/ -#include "ibm.h" - -uint8_t dac,dac2; -uint8_t dacctrl; -int lptfifo; -uint8_t dssbuffer[16]; -int dssstart=0,dssend=0; -int dssmode=0; - -void writedac(uint16_t addr, uint8_t val) -{ - if (dssmode) dac2=val; - else dac=val; -} - -void writedacctrl(uint16_t addr, uint8_t val) -{ -// printf("Write DAC ctrl %02X %i\n",val,lptfifo); - if (dacctrl&8 && !(val&8) && (lptfifo!=16)) - { -// dac=dac2; - dssbuffer[dssend++]=dac2; - dssend&=15; - lptfifo++; - } - dacctrl=val; -} - -uint8_t readdacfifo() -{ - if (lptfifo==16) return 0x40; - return 0; -} - -void pollss() -{ - if (lptfifo) - { - dac=dssbuffer[dssstart++]; - dssstart&=15; - lptfifo--; - } -} - -int16_t dacbuffer[SOUNDBUFLEN+20]; -int dacbufferpos=0; -void getdacsamp() -{ - if (dacbufferposSOUNDBUFLEN) dacbufferpos=SOUNDBUFLEN; - for (c=0;c + * Miran Grca, + * Copyright 2008-2016 Sarah Walker. + * Copyright 2016-2017 Miran Grca. + */ #include "ibm.h" +#include "cpu/cpu.h" #include "config.h" -#include "cpu.h" #include "device.h" #include "model.h" -#include "sound.h" +#include "sound/sound.h" + static void *device_priv[256]; static device_t *devices[256]; - static device_t *current_device; -void device_init() + +void device_init(void) { memset(devices, 0, sizeof(devices)); } @@ -54,6 +73,22 @@ void device_close_all() } } +void *device_get_priv(device_t *d) +{ + int c; + + for (c = 0; c < 256; c++) + { + if (devices[c] != NULL) + { + if (devices[c] == d) + return device_priv[c]; + } + } + + return NULL; +} + int device_available(device_t *d) { #ifdef RELEASE_BUILD @@ -66,7 +101,7 @@ int device_available(device_t *d) return 1; } -void device_speed_changed() +void device_speed_changed(void) { int c; @@ -84,7 +119,7 @@ void device_speed_changed() sound_speed_changed(); } -void device_force_redraw() +void device_force_redraw(void) { int c; @@ -112,6 +147,8 @@ char *device_add_status_info(char *s, int max_len) devices[c]->add_status_info(s, max_len, device_priv[c]); } } + + return NULL; } int device_get_config_int(char *s) @@ -128,6 +165,130 @@ int device_get_config_int(char *s) return 0; } +int device_get_config_int_ex(char *s, int default_int) +{ + device_config_t *config = current_device->config; + + while (config->type != -1) + { + if (!strcmp(s, config->name)) + return config_get_int(current_device->name, s, default_int); + + config++; + } + return default_int; +} + +int device_get_config_hex16(char *s) +{ + device_config_t *config = current_device->config; + + while (config->type != -1) + { + if (!strcmp(s, config->name)) + return config_get_hex16(current_device->name, s, config->default_int); + + config++; + } + return 0; +} + +int device_get_config_hex20(char *s) +{ + device_config_t *config = current_device->config; + + while (config->type != -1) + { + if (!strcmp(s, config->name)) + return config_get_hex20(current_device->name, s, config->default_int); + + config++; + } + return 0; +} + +int device_get_config_mac(char *s, int default_int) +{ + device_config_t *config = current_device->config; + + while (config->type != -1) + { + if (!strcmp(s, config->name)) + return config_get_mac(current_device->name, s, default_int); + + config++; + } + return default_int; +} + +void device_set_config_int(char *s, int val) +{ + device_config_t *config = current_device->config; + + while (config->type != -1) + { + if (!strcmp(s, config->name)) + { + config_set_int(current_device->name, s, val); + return; + } + + config++; + } + return; +} + +void device_set_config_hex16(char *s, int val) +{ + device_config_t *config = current_device->config; + + while (config->type != -1) + { + if (!strcmp(s, config->name)) + { + config_set_hex16(current_device->name, s, val); + return; + } + + config++; + } + return; +} + +void device_set_config_hex20(char *s, int val) +{ + device_config_t *config = current_device->config; + + while (config->type != -1) + { + if (!strcmp(s, config->name)) + { + config_set_hex20(current_device->name, s, val); + return; + } + + config++; + } + return; +} + +void device_set_config_mac(char *s, int val) +{ + device_config_t *config = current_device->config; + + while (config->type != -1) + { + if (!strcmp(s, config->name)) + { + config_set_mac(current_device->name, s, val); + return; + } + + config++; + } + return; +} + char *device_get_config_string(char *s) { device_config_t *config = current_device->config; diff --git a/src/device.h b/src/device.h index 970b4067f..087c3464d 100644 --- a/src/device.h +++ b/src/device.h @@ -1,8 +1,44 @@ -#define CONFIG_STRING 0 -#define CONFIG_INT 1 -#define CONFIG_BINARY 2 -#define CONFIG_SELECTION 3 -#define CONFIG_MIDI 4 +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Implementation of the generic device interface to handle + * all devices attached to the emulator. + * + * Version: @(#)device.h 1.0.1 2017/06/03 + * + * Authors: Sarah Walker, + * Miran Grca, + * Copyright 2008-2016 Sarah Walker. + * Copyright 2016-2017 Miran Grca. + */ +#ifndef EMU_DEVICE_H +# define EMU_DEVICE_H + + +#define CONFIG_STRING 0 +#define CONFIG_INT 1 +#define CONFIG_BINARY 2 +#define CONFIG_SELECTION 3 +#define CONFIG_MIDI 4 +#define CONFIG_HEX16 5 +#define CONFIG_HEX20 6 +#define CONFIG_MAC 7 + + +enum +{ + DEVICE_NOT_WORKING = 1, /*Device does not currently work correctly and will be disabled in a release build*/ + DEVICE_AT = 2, /*Device requires an AT-compatible system*/ + DEVICE_PS2 = 4, /*Device requires a PS/1 or PS/2 system*/ + DEVICE_MCA = 0x20, /*Device requires the MCA bus*/ + DEVICE_PCI = 0x40 /*Device requires the PCI bus*/ +}; + typedef struct device_config_selection_t { @@ -33,21 +69,29 @@ typedef struct device_t device_config_t *config; } device_t; -void device_init(); -void device_add(device_t *d); -void device_close_all(); -int device_available(device_t *d); -void device_speed_changed(); -void device_force_redraw(); -char *device_add_status_info(char *s, int max_len); -int device_get_config_int(char *name); -char *device_get_config_string(char *name); +extern void device_init(void); +extern void device_add(device_t *d); +extern void device_close_all(void); +extern void *device_get_priv(device_t *d); +extern int device_available(device_t *d); +extern void device_speed_changed(void); +extern void device_force_redraw(void); +extern char *device_add_status_info(char *s, int max_len); -enum -{ - DEVICE_NOT_WORKING = 1 /*Device does not currently work correctly and will be disabled in a release build*/ -}; +extern int device_get_config_int(char *name); +extern int device_get_config_int_ex(char *s, int default_int); +extern int device_get_config_hex16(char *name); +extern int device_get_config_hex20(char *name); +extern int device_get_config_mac(char *name, int default_int); +extern void device_set_config_int(char *s, int val); +extern void device_set_config_hex16(char *s, int val); +extern void device_set_config_hex20(char *s, int val); +extern void device_set_config_mac(char *s, int val); +extern char *device_get_config_string(char *name); -int model_get_config_int(char *s); -char *model_get_config_string(char *s); +extern int model_get_config_int(char *s); +extern char *model_get_config_string(char *s); + + +#endif /*EMU_DEVICE_H*/ diff --git a/src/disc.c b/src/disc.c index ee4a4ccc3..bdede24ed 100644 --- a/src/disc.c +++ b/src/disc.c @@ -1,8 +1,25 @@ -/* Copyright holders: Sarah Walker, Tenshi - see COPYING for more details -*/ -#include "ibm.h" +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Generic floppy disk interface that communicates with the + * other handlers. + * + * Version: @(#)disc.c 1.0.1 2017/06/03 + * + * Authors: Sarah Walker, + * Miran Grca, + * Copyright 2008-2017 Sarah Walker. + * Copyright 2016-2017 Miran Grca. + */ +#define UNICODE +#include +#include "ibm.h" #include "config.h" #include "disc.h" #include "disc_fdi.h" @@ -14,6 +31,10 @@ #include "fdd.h" #include "timer.h" + +wchar_t discfns[4][256]; +extern int driveempty[4]; + int disc_poll_time[FDD_NUM] = { 16, 16, 16, 16 }; int disc_track[FDD_NUM]; @@ -54,94 +75,89 @@ int (*fdc_getdata)(int last); void (*fdc_sectorid)(uint8_t track, uint8_t side, uint8_t sector, uint8_t size, uint8_t crc1, uint8_t crc2); void (*fdc_indexpulse)();*/ + static struct { - char *ext; - void (*load)(int drive, char *fn); + wchar_t *ext; + void (*load)(int drive, wchar_t *fn); void (*close)(int drive); int size; -} -loaders[]= +} loaders[]= { - {"001", img_load, img_close, -1}, - {"002", img_load, img_close, -1}, - {"003", img_load, img_close, -1}, - {"004", img_load, img_close, -1}, - {"005", img_load, img_close, -1}, - {"006", img_load, img_close, -1}, - {"007", img_load, img_close, -1}, - {"008", img_load, img_close, -1}, - {"009", img_load, img_close, -1}, - {"010", img_load, img_close, -1}, - {"12", img_load, img_close, -1}, - {"144", img_load, img_close, -1}, - {"360", img_load, img_close, -1}, - {"720", img_load, img_close, -1}, - {"86F", d86f_load, d86f_close, -1}, - {"BIN", img_load, img_close, -1}, - {"CQ", img_load, img_close, -1}, - {"CQM", img_load, img_close, -1}, - {"DSK", img_load, img_close, -1}, - {"FDI", fdi_load, fdi_close, -1}, - {"FLP", img_load, img_close, -1}, - {"HDM", img_load, img_close, -1}, - {"IMA", img_load, img_close, -1}, - {"IMD", imd_load, imd_close, -1}, - {"IMG", img_load, img_close, -1}, - {"TD0", td0_load, td0_close, -1}, - {"VFD", img_load, img_close, -1}, - {"XDF", img_load, img_close, -1}, + {L"001", img_load, img_close, -1}, + {L"002", img_load, img_close, -1}, + {L"003", img_load, img_close, -1}, + {L"004", img_load, img_close, -1}, + {L"005", img_load, img_close, -1}, + {L"006", img_load, img_close, -1}, + {L"007", img_load, img_close, -1}, + {L"008", img_load, img_close, -1}, + {L"009", img_load, img_close, -1}, + {L"010", img_load, img_close, -1}, + {L"12", img_load, img_close, -1}, + {L"144", img_load, img_close, -1}, + {L"360", img_load, img_close, -1}, + {L"720", img_load, img_close, -1}, + {L"86F", d86f_load, d86f_close, -1}, + {L"BIN", img_load, img_close, -1}, + {L"CQ", img_load, img_close, -1}, + {L"CQM", img_load, img_close, -1}, + {L"DSK", img_load, img_close, -1}, + {L"FDI", fdi_load, fdi_close, -1}, + {L"FDF", img_load, img_close, -1}, + {L"FLP", img_load, img_close, -1}, + {L"HDM", img_load, img_close, -1}, + {L"IMA", img_load, img_close, -1}, + {L"IMD", imd_load, imd_close, -1}, + {L"IMG", img_load, img_close, -1}, + {L"TD0", td0_load, td0_close, -1}, + {L"VFD", img_load, img_close, -1}, + {L"XDF", img_load, img_close, -1}, {0,0,0} }; static int driveloaders[4]; -void disc_load(int drive, char *fn) +void disc_load(int drive, wchar_t *fn) { int c = 0, size; - char *p; + wchar_t *p; FILE *f; -// pclog("disc_load %i %s\n", drive, fn); -// setejecttext(drive, ""); if (!fn) return; - p = get_extension(fn); + p = get_extension_w(fn); if (!p) return; -// setejecttext(drive, fn); - // pclog("Loading :%i %s %s\n", drive, fn,p); - f = fopen(fn, "rb"); + f = _wfopen(fn, L"rb"); if (!f) return; fseek(f, -1, SEEK_END); size = ftell(f) + 1; fclose(f); while (loaders[c].ext) { - if (!strcasecmp(p, loaders[c].ext) && (size == loaders[c].size || loaders[c].size == -1)) + if (!_wcsicmp(p, loaders[c].ext) && (size == loaders[c].size || loaders[c].size == -1)) { - // pclog("Loading as %s (UI write protected = %s)\n", p, ui_writeprot[drive] ? "yes" : "no"); driveloaders[drive] = c; loaders[c].load(drive, fn); drive_empty[drive] = 0; - strcpy(discfns[drive], fn); - // fdd_set_head(real_drive(drive), 0); + memcpy(discfns[drive], fn, (wcslen(fn) << 1) + 2); fdd_forced_seek(real_drive(drive), 0); disc_changed[drive] = 1; return; } c++; } - pclog("Couldn't load %s %s\n",fn,p); + pclog_w(L"Couldn't load %s %s\n",fn,p); drive_empty[drive] = 1; fdd_set_head(real_drive(drive), 0); - discfns[drive][0] = 0; + memset(discfns[drive], 0, sizeof(discfns[drive])); + update_status_bar_icon_state(drive, 1); } void disc_close(int drive) { -// pclog("disc_close %i\n", drive); if (loaders[driveloaders[drive]].close) loaders[driveloaders[drive]].close(drive); drive_empty[drive] = 1; fdd_set_head(real_drive(drive), 0); - discfns[drive][0] = 0; + discfns[drive][0] = L'\0'; drives[drive].hole = NULL; drives[drive].poll = NULL; drives[drive].seek = NULL; @@ -152,6 +168,7 @@ void disc_close(int drive) drives[drive].format = NULL; drives[drive].byteperiod = NULL; drives[drive].stop = NULL; + update_status_bar_icon_state(drive, 1); } int disc_notfound=0; @@ -177,6 +194,11 @@ double disc_byteperiod(int drive) if (drives[drive].byteperiod) { + if (fdd_get_turbo(drive)) + { + return 1.0; + } + return drives[drive].byteperiod(drive); } else @@ -194,15 +216,22 @@ double disc_real_period(int drive) dusec = (double) TIMER_USEC; - return (ddbp * dusec); + /* This is a giant hack but until the timings become even more correct, this is needed to make floppies work right on that BIOS. */ + if ((romset == ROM_MRTHOR) && !fdd_get_turbo(drive)) + { + return (ddbp * dusec) / 4.0; + } + else + { + return (ddbp * dusec); + } } void disc_poll(int drive) { if (drive >= FDD_NUM) { - disc_poll_time[drive] += (int) (32.0 * TIMER_USEC); - return; + fatal("Attempting to poll floppy drive %i that is not supposed to be there\n", drive); } disc_poll_time[drive] += (int) disc_real_period(drive); @@ -218,29 +247,29 @@ void disc_poll(int drive) } } -void disc_poll_0() +void disc_poll_0(void *priv) { disc_poll(0); } -void disc_poll_1() +void disc_poll_1(void *priv) { disc_poll(1); } -void disc_poll_2() +void disc_poll_2(void *priv) { disc_poll(2); } -void disc_poll_3() +void disc_poll_3(void *priv) { disc_poll(3); } int disc_get_bitcell_period(int rate) { - int bit_rate; + int bit_rate = 250; switch (rate) { @@ -303,7 +332,6 @@ void disc_reset() void disc_init() { -// pclog("disc_init %p\n", drives); drives[0].poll = drives[1].poll = drives[2].poll = drives[3].poll = 0; drives[0].seek = drives[1].seek = drives[2].seek = drives[3].seek = 0; drives[0].readsector = drives[1].readsector = drives[2].readsector = drives[3].readsector = 0; @@ -313,13 +341,8 @@ void disc_init() int oldtrack[FDD_NUM] = {0, 0, 0, 0}; void disc_seek(int drive, int track) { -// pclog("disc_seek: drive=%i track=%i\n", drive, track); if (drives[drive].seek) drives[drive].seek(drive, track); -// if (track != oldtrack[drive]) -// fdc_discchange_clear(drive); -// ddnoise_seek(track - oldtrack[drive]); -// oldtrack[drive] = track; } void disc_readsector(int drive, int sector, int track, int side, int density, int sector_size) diff --git a/src/disc.h b/src/disc.h index bb6491ea4..eb5c7a1bd 100644 --- a/src/disc.h +++ b/src/disc.h @@ -1,8 +1,28 @@ -/* Copyright holders: Sarah Walker, Tenshi - see COPYING for more details -*/ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Generic floppy disk interface that communicates with the + * other handlers. + * + * Version: @(#)disc.h 1.0.1 2017/06/03 + * + * Authors: Sarah Walker, + * Miran Grca, + * Copyright 2008-2017 Sarah Walker. + * Copyright 2016-2017 Miran Grca. + */ +#ifndef EMU_DISC_H +# define EMU_DISC_H + + #define FDD_NUM 4 + typedef struct { void (*seek)(int drive, int track); @@ -17,42 +37,51 @@ typedef struct void (*poll)(int drive); } DRIVE; -extern DRIVE drives[FDD_NUM]; -extern int curdrive; +extern DRIVE drives[FDD_NUM]; +extern int curdrive; -void disc_load(int drive, char *fn); -void disc_new(int drive, char *fn); -void disc_close(int drive); -void disc_init(); -void disc_reset(); -void disc_poll(int drive); -void disc_poll_0(); -void disc_poll_1(); -void disc_seek(int drive, int track); -void disc_readsector(int drive, int sector, int track, int side, int density, int sector_size); -void disc_writesector(int drive, int sector, int track, int side, int density, int sector_size); -void disc_comparesector(int drive, int sector, int track, int side, int density, int sector_size); -void disc_readaddress(int drive, int side, int density); -void disc_format(int drive, int side, int density, uint8_t fill); -int disc_hole(int drive); -double disc_byteperiod(int drive); -void disc_stop(int drive); -int disc_empty(int drive); -void disc_set_rate(int drive, int drvden, int rate); -extern int disc_time; -extern int disc_poll_time[FDD_NUM]; +extern int disc_time; +extern int disc_poll_time[FDD_NUM]; + + +extern void disc_load(int drive, wchar_t *fn); +extern void disc_new(int drive, char *fn); +extern void disc_close(int drive); +extern void disc_init(void); +extern void disc_reset(void); +extern void disc_poll(int drive); +extern void disc_poll_0(void* priv); +extern void disc_poll_1(void* priv); +extern void disc_poll_2(void* priv); +extern void disc_poll_3(void* priv); +extern void disc_seek(int drive, int track); +extern void disc_readsector(int drive, int sector, int track, + int side, int density, int sector_size); +extern void disc_writesector(int drive, int sector, int track, + int side, int density, int sector_size); +extern void disc_comparesector(int drive, int sector, int track, + int side, int density, int sector_size); +extern void disc_readaddress(int drive, int side, int density); +extern void disc_format(int drive, int side, int density, uint8_t fill); +extern int disc_hole(int drive); +extern double disc_byteperiod(int drive); +extern void disc_stop(int drive); +extern int disc_empty(int drive); +extern void disc_set_rate(int drive, int drvden, int rate); + +extern void fdc_callback(void *priv); +extern int fdc_data(uint8_t dat); +extern void fdc_spindown(void); +extern void fdc_finishread(void); +extern void fdc_datacrcerror(void); +extern void fdc_headercrcerror(void); +extern void fdc_writeprotect(void); +extern int fdc_getdata(int last); +extern void fdc_sectorid(uint8_t track, uint8_t side, uint8_t sector, + uint8_t size, uint8_t crc1, uint8_t crc2); +extern void fdc_indexpulse(void); -void fdc_callback(); -int fdc_data(uint8_t dat); -void fdc_spindown(); -void fdc_finishread(); -void fdc_datacrcerror(); -void fdc_headercrcerror(); -void fdc_writeprotect(); -int fdc_getdata(int last); -void fdc_sectorid(uint8_t track, uint8_t side, uint8_t sector, uint8_t size, uint8_t crc1, uint8_t crc2); -void fdc_indexpulse(); /*extern int fdc_time; extern int fdc_ready; extern int fdc_indexcount;*/ @@ -64,7 +93,6 @@ extern int swwp; extern int disable_write; extern int defaultwriteprot; -//extern char discfns[4][260]; extern int writeprot[FDD_NUM], fwriteprot[FDD_NUM]; extern int disc_track[FDD_NUM]; @@ -147,7 +175,7 @@ void d86f_reset_index_hole_pos(int drive, int side); uint16_t d86f_prepare_pretrack(int drive, int side, int iso); uint16_t d86f_prepare_sector(int drive, int side, int prev_pos, uint8_t *id_buf, uint8_t *data_buf, int data_len, int gap2, int gap3, int deleted, int bad_crc); -int gap3_sizes[5][8][256]; +int gap3_sizes[5][8][48]; void null_writeback(int drive); void null_write_data(int drive, int side, uint16_t pos, uint8_t data); @@ -202,3 +230,6 @@ typedef union uint8_t byte_array[4]; sector_id_fields_t id; } sector_id_t; + + +#endif /*EMU_DISC_H*/ diff --git a/src/disc_86f.c b/src/disc_86f.c index cfc898a52..9eb713365 100644 --- a/src/disc_86f.c +++ b/src/disc_86f.c @@ -1,11 +1,29 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Implementation of the 86F floppy image format (stores the + * data in the form of FM/MFM-encoded transitions) which also + * forms the core of the emulator's floppy disk emulation. + * + * Version: @(#)disc_86f.c 1.0.0 2017/05/30 + * + * Author: Miran Grca, + * Copyright 2016-2017 Miran Grca. + */ + +#include #include #include #include #include #include +#include -// #include "crcspeed/crc64speed.h" -// #include "zlib.h" #include "lzf/lzf.h" #include "config.h" @@ -21,7 +39,7 @@ #define CHUNK 16384 -uint64_t poly = 0x42F0E1EBA9EA3693; /* ECMA normal */ +uint64_t poly = 0x42F0E1EBA9EA3693ll; /* ECMA normal */ uint64_t table[256]; @@ -85,25 +103,45 @@ enum /* 1 11 01 ??? */ STATE_0D_SPIN_TO_INDEX = 0xE8, /* FORMAT TRACK */ - STATE_0D_FORMAT_TRACK + STATE_0D_FORMAT_TRACK, + + /* 1 11 11 ??? */ + STATE_0D_NOP_SPIN_TO_INDEX = 0xF8, /* FORMAT TRACK */ + STATE_0D_NOP_FORMAT_TRACK }; static uint16_t CRCTable[256]; -typedef struct __attribute__((packed)) +#ifdef __MSC__ +# pragma pack(push,1) +typedef struct +#else +typedef struct __attribute__((__packed__)) +#endif { uint8_t buffer[10]; uint32_t pos; uint32_t len; } sliding_buffer_t; +#ifdef __MSC__ +# pragma pack(pop) +#endif -typedef struct __attribute__((packed)) +#ifdef __MSC__ +# pragma pack(push,1) +typedef struct +#else +typedef struct __attribute__((__packed__)) +#endif { uint32_t sync_marks; uint32_t bits_obtained; uint32_t bytes_obtained; uint32_t sync_pos; } find_t; +#ifdef __MSC__ +# pragma pack(pop) +#endif uint8_t encoded_fm[64] = { 0xAA, 0xAB, 0xAE, 0xAF, 0xBA, 0xBB, 0xBE, 0xBF, 0xEA, 0xEB, 0xEE, 0xEF, 0xFA, 0xFB, 0xFE, 0xFF, 0xAA, 0xAB, 0xAE, 0xAF, 0xBA, 0xBB, 0xBE, 0xBF, 0xEA, 0xEB, 0xEE, 0xEF, 0xFA, 0xFB, 0xFE, 0xFF, @@ -134,14 +172,22 @@ enum FMT_SECTOR_GAP3, FMT_POSTTRK_CHECK, - FMT_POSTTRK_GAP4, + FMT_POSTTRK_GAP4 }; -typedef struct __attribute__((packed)) +#ifdef __MSC__ +# pragma pack(push,1) +typedef struct +#else +typedef struct __attribute__((__packed__)) +#endif { unsigned nibble0 :4; unsigned nibble1 :4; } split_byte_t; +#ifdef __MSC__ +# pragma pack(pop) +#endif typedef union { uint8_t byte; @@ -159,7 +205,12 @@ typedef union { Bits 10, 9 Zone type (3 = Commodore 64 zoned, 2 = Apple zoned, 1 = Pre-Apple zoned #2, 0 = Pre-Apple zoned #1) Bit 11 Data and surface bits are stored in reverse byte endianness */ -static struct __attribute__((packed)) +#ifdef __MSC__ +# pragma pack(push,1) +struct +#else +struct __attribute__((__packed__)) +#endif { FILE *f; uint16_t version; @@ -197,11 +248,30 @@ static struct __attribute__((packed)) uint32_t error_condition; int is_compressed; int id_found; - uint8_t original_file_name[2048]; + wchar_t original_file_name[2048]; uint8_t *filebuf; uint8_t *outbuf; uint32_t dma_over; } d86f[FDD_NUM]; +#ifdef __MSC__ +# pragma pack(pop) +#endif + +int d86f_do_log = 0; + +void d86f_log(const char *format, ...) +{ +#ifdef ENABLE_D86F_LOG + if (d86f_do_log) + { + va_list ap; + va_start(ap, format); + vprintf(format, ap); + va_end(ap); + fflush(stdout); + } +#endif +} static void d86f_setupcrc(uint16_t poly) { @@ -458,7 +528,6 @@ int d86f_get_array_size(int drive, int side) int array_size = 0; int rm = 0; int hole = 0; - int extra_bytes = 0; rm = d86f_get_rpm_mode(drive); hole = (d86f_handler[drive].disk_flags(drive) & 6) >> 1; switch (hole) @@ -674,6 +743,10 @@ int d86f_wrong_densel(int drive) { case 0: default: + if (fdd_is_dd(drive)) + { + return 0; + } if (fdd_get_densel(drive)) { return 1; @@ -684,6 +757,10 @@ int d86f_wrong_densel(int drive) } break; case 1: + if (fdd_is_dd(drive)) + { + return 1; + } if (fdd_get_densel(drive)) { return 0; @@ -701,6 +778,10 @@ int d86f_wrong_densel(int drive) } break; case 2: + if (fdd_is_dd(drive) || !fdd_is_ed(drive)) + { + return 1; + } if (fdd_get_densel(drive)) { return 0; @@ -816,7 +897,7 @@ void d86f_get_bit(int drive, int side) uint32_t track_word; uint32_t track_bit; uint16_t encoded_data; - uint16_t surface_data; + uint16_t surface_data = 0; uint16_t current_bit; uint16_t surface_bit; @@ -888,7 +969,7 @@ void d86f_put_bit(int drive, int side, int bit) uint32_t track_word; uint32_t track_bit; uint16_t encoded_data; - uint16_t surface_data; + uint16_t surface_data = 0; uint16_t current_bit; uint16_t surface_bit; @@ -1107,7 +1188,6 @@ void d86f_find_address_mark_mfm(int drive, int side, find_t *find, uint16_t req_ { find->sync_marks++; find->sync_pos = d86f[drive].track_pos; - // pclog("Sync marks: %i\n", find->sync_marks); return; } @@ -1120,7 +1200,6 @@ void d86f_find_address_mark_mfm(int drive, int side, find_t *find, uint16_t req_ disc_calccrc(decodefm(drive, d86f[drive].last_word[side]), &(d86f[drive].calc_crc)); find->sync_marks = find->bits_obtained = find->bytes_obtained = 0; find->sync_pos = 0xFFFFFFFF; - // pclog("AM found (%04X) (%02X)\n", req_am, d86f[drive].state); d86f[drive].preceding_bit[side] = d86f[drive].last_word[side] & 1; d86f[drive].state++; return; @@ -1143,7 +1222,6 @@ void d86f_find_address_mark_mfm(int drive, int side, find_t *find, uint16_t req_ else { /* Not skip mode, process the sector anyway. */ - // pclog("Wrong AM found (%04X) (%02X)\n", other_am, d86f[drive].state); fdc_set_wrong_am(); d86f[drive].preceding_bit[side] = d86f[drive].last_word[side] & 1; d86f[drive].state++; @@ -1195,8 +1273,6 @@ void d86f_write_find_address_mark_mfm(int drive, int side, find_t *find) /* State 2: Read sector ID and CRC*/ void d86f_read_sector_id(int drive, int side, int match) { - uint16_t temp; - if (d86f[drive].id_find.bits_obtained) { if (!(d86f[drive].id_find.bits_obtained & 15)) @@ -1247,12 +1323,10 @@ void d86f_read_sector_id(int drive, int side, int match) else { /* CRC is valid. */ - // pclog("Sector ID found: %08X; Requested: %08X\n", d86f[drive].last_sector.dword, d86f[drive].req_sector.dword); d86f[drive].id_find.sync_marks = d86f[drive].id_find.bits_obtained = d86f[drive].id_find.bytes_obtained = 0; d86f[drive].id_found++; if ((d86f[drive].last_sector.dword == d86f[drive].req_sector.dword) || !match) { - // pclog("ID read (%02X)\n", d86f[drive].state); d86f_handler[drive].set_sector(drive, side, d86f[drive].last_sector.id.c, d86f[drive].last_sector.id.h, d86f[drive].last_sector.id.r, d86f[drive].last_sector.id.n); if (d86f[drive].state == STATE_02_READ_ID) { @@ -1274,12 +1348,10 @@ void d86f_read_sector_id(int drive, int side, int match) { if (d86f[drive].last_sector.id.c == 0xFF) { - // pclog("[State: %02X] [Side %i] Bad cylinder (%i != %i?) (%02X) (%08X) (%i)\n", d86f[drive].state, side, fdc_get_bitcell_period(), d86f_get_bitcell_period(drive), d86f_handler[drive].side_flags(drive), d86f[drive].req_sector.dword, d86f_handler[drive].get_raw_size(drive, side)); d86f[drive].error_condition |= 8; } else { - // pclog("[State: %02X] [Side %i] Wrong cylinder (%i != %i?) (%02X) (%08X) (%i)\n", d86f[drive].state, side, fdc_get_bitcell_period(), d86f_get_bitcell_period(drive), d86f_handler[drive].side_flags(drive), d86f[drive].req_sector.dword, d86f_handler[drive].get_raw_size(drive, side)); d86f[drive].error_condition |= 0x10; } } @@ -1355,7 +1427,6 @@ void d86f_read_sector_data(int drive, int side) int data = 0; int recv_data = 0; int read_status = 0; - uint16_t temp; uint32_t sector_len = d86f[drive].last_sector.id.n; uint32_t crc_pos = 0; sector_len = 1 << (7 + sector_len); @@ -1385,7 +1456,6 @@ void d86f_read_sector_data(int drive, int side) if (read_status == -1) { d86f[drive].dma_over++; - // pclog("DMA over now: %i\n", d86f[drive].dma_over); } } } @@ -1403,7 +1473,6 @@ void d86f_read_sector_data(int drive, int side) /* We've got the data. */ if (d86f[drive].dma_over > 1) { - // pclog("DMA overrun while reading data!\n"); d86f[drive].data_find.sync_marks = d86f[drive].data_find.bits_obtained = d86f[drive].data_find.bytes_obtained = 0; d86f[drive].error_condition = 0; d86f[drive].state = STATE_IDLE; @@ -1415,10 +1484,6 @@ void d86f_read_sector_data(int drive, int side) d86f[drive].data_find.bits_obtained++; return; } - else - { - // pclog("Bytes over DMA: %i\n", d86f[drive].dma_over); - } if ((d86f[drive].calc_crc.word != d86f[drive].track_crc.word) && (d86f[drive].state != STATE_02_READ_DATA)) { @@ -1431,7 +1496,6 @@ void d86f_read_sector_data(int drive, int side) } else if ((d86f[drive].calc_crc.word != d86f[drive].track_crc.word) && (d86f[drive].state == STATE_02_READ_DATA)) { - // printf("%04X != %04X (%08X)\n", d86f[drive].track_crc.word, d86f[drive].calc_crc.word, d86f[drive].last_sector.dword); d86f[drive].data_find.sync_marks = d86f[drive].data_find.bits_obtained = d86f[drive].data_find.bytes_obtained = 0; d86f[drive].error_condition |= 2; /* Mark that there was a data error. */ d86f[drive].state = STATE_IDLE; @@ -1490,7 +1554,6 @@ void d86f_write_sector_data(int drive, int side, int mfm, uint16_t am) { /* We're in the data field of the sector, use a CRC byte. */ d86f[drive].current_byte[side] = d86f[drive].calc_crc.bytes[(d86f[drive].data_find.bytes_obtained & 1)]; - // pclog("BO: %04X (%02X)\n", d86f[drive].data_find.bytes_obtained, d86f[drive].current_byte[side]); } d86f[drive].current_bit[side] = (15 - (d86f[drive].data_find.bits_obtained & 15)) >> 1; @@ -1574,7 +1637,6 @@ void d86f_write_sector_data(int drive, int side, int mfm, uint16_t am) { if (d86f[drive].dma_over > 1) { - // pclog("DMA overrun while writing data!\n"); d86f[drive].data_find.sync_marks = d86f[drive].data_find.bits_obtained = d86f[drive].data_find.bytes_obtained = 0; d86f[drive].error_condition = 0; d86f[drive].state = STATE_IDLE; @@ -1611,7 +1673,6 @@ void d86f_advance_bit(int drive, int side) if (d86f[drive].state != STATE_IDLE) { d86f[drive].index_count++; - // pclog("Index count now: %i\n", d86f[drive].index_count); } } } @@ -1633,7 +1694,7 @@ void d86f_spin_to_index(int drive, int side) if (d86f[drive].track_pos == d86f_handler[drive].index_hole_pos(drive, side)) { - if (d86f[drive].state == STATE_0D_SPIN_TO_INDEX) + if ((d86f[drive].state == STATE_0D_SPIN_TO_INDEX) || (d86f[drive].state == STATE_0D_NOP_SPIN_TO_INDEX)) { /* When starting format, reset format state to the beginning. */ d86f[drive].preceding_bit[side] = 1; @@ -1647,12 +1708,11 @@ void d86f_spin_to_index(int drive, int side) void d86f_write_direct_common(int drive, int side, uint16_t byte, uint8_t type, uint32_t pos) { - uint16_t encoded_byte, mask_data, mask_surface, mask_hole, mask_fuzzy; + uint16_t encoded_byte = 0, mask_data, mask_surface, mask_hole, mask_fuzzy; decoded_t dbyte, dpbyte; dbyte.byte = byte; dpbyte.byte = d86f[drive].preceding_bit[side]; - d86f[drive].preceding_bit[side] = encoded_byte & 1; if (type == 0) { @@ -1679,6 +1739,8 @@ void d86f_write_direct_common(int drive, int side, uint16_t byte, uint8_t type, } } + d86f[drive].preceding_bit[side] = encoded_byte & 1; + if (d86f_has_surface_desc(drive)) { mask_data = d86f[drive].track_encoded_data[side][pos] ^= 0xFFFF; @@ -1720,21 +1782,23 @@ void d86f_format_finish(int drive, int side, int mfm, uint16_t sc, uint16_t gap_ } d86f[drive].state = STATE_IDLE; - d86f_handler[drive].writeback(drive); - // pclog("Format finished (%i) (%i)!\n", d86f[drive].track_pos, sc); + + if (do_write) + { + d86f_handler[drive].writeback(drive); + } + d86f[drive].error_condition = 0; d86f[drive].datac = 0; fdc_sector_finishread(); } -void d86f_format_track(int drive, int side) +void d86f_format_track(int drive, int side, int do_write) { int data; - uint16_t max_len, temp, temp2; + uint16_t max_len; int mfm; - uint16_t i = 0; - uint16_t j = 0; uint16_t sc = 0; uint16_t dtl = 0; int gap_sizes[4] = { 0, 0, 0, 0 }; @@ -1747,7 +1811,6 @@ void d86f_format_track(int drive, int side) uint16_t idam_fm = 0x7EF5; uint16_t dataam_fm = 0x6FF5; uint16_t gap_fill = 0x4E; - int do_write = 0; mfm = d86f_is_mfm(drive); am_len = mfm ? 4 : 1; @@ -1759,7 +1822,6 @@ void d86f_format_track(int drive, int side) sc = fdc_get_format_sectors(); dtl = 128 << fdc_get_format_n(); gap_fill = mfm ? 0x4E : 0xFF; - do_write = (d86f[drive].version == D86FVER); switch(d86f[drive].format_state) { @@ -1772,6 +1834,7 @@ void d86f_format_track(int drive, int side) if (do_write) d86f_write_direct(drive, side, gap_fill, 0); break; case FMT_SECTOR_ID_SYNC: + max_len = sync_len; if (d86f[drive].datac <= 3) { data = fdc_getdata(0); @@ -1784,11 +1847,9 @@ void d86f_format_track(int drive, int side) data = 0; } d86f[drive].format_sector_id.byte_array[d86f[drive].datac] = data & 0xff; - // pclog("format_sector_id[%i] = %i\n", d86f[drive].datac, d86f[drive].format_sector_id.byte_array[d86f[drive].datac]); if (d86f[drive].datac == 3) { fdc_stop_id_request(); - // pclog("Formatting sector: %08X (%i) (%i)...\n", d86f[drive].format_sector_id.dword, d86f[drive].track_pos, sc); } } case FMT_PRETRK_SYNC: @@ -1866,22 +1927,28 @@ void d86f_format_track(int drive, int side) break; case FMT_SECTOR_DATA: max_len = dtl; - if (do_write) d86f_write_direct(drive, side, d86f[drive].fill, 0); + if (do_write) + { + d86f_write_direct(drive, side, d86f[drive].fill, 0); + d86f_handler[drive].write_data(drive, side, d86f[drive].datac, d86f[drive].fill); + } d86f_calccrc(drive, d86f[drive].fill); break; case FMT_SECTOR_GAP3: max_len = gap_sizes[3]; if (do_write) d86f_write_direct(drive, side, gap_fill, 0); break; + default: + max_len = 0; + break; } d86f[drive].datac++; d86f_advance_word(drive, side); - if ((d86f[drive].index_count) && (d86f[drive].format_state < FMT_SECTOR_ID_SYNC) || (d86f[drive].format_state > FMT_SECTOR_GAP3)) + if ((d86f[drive].index_count) && ((d86f[drive].format_state < FMT_SECTOR_ID_SYNC) || (d86f[drive].format_state > FMT_SECTOR_GAP3))) { - // pclog("Format finished regularly\n"); d86f_format_finish(drive, side, mfm, sc, gap_fill, do_write); return; } @@ -1903,7 +1970,6 @@ void d86f_format_track(int drive, int side) case FMT_POSTTRK_CHECK: if (d86f[drive].index_count) { - // pclog("Format finished with delay\n"); d86f_format_finish(drive, side, mfm, sc, gap_fill, do_write); return; } @@ -1925,12 +1991,27 @@ void d86f_format_track(int drive, int side) } } +void d86f_format_track_normal(int drive, int side) +{ + d86f_format_track(drive, side, (d86f[drive].version == D86FVER)); +} + +void d86f_format_track_nop(int drive, int side) +{ + d86f_format_track(drive, side, 0); +} + void d86f_poll(int drive) { int side = 0; int mfm = 1; side = fdd_get_head(drive); + if (!fdd_is_double_sided(drive)) + { + side = 0; + } + mfm = fdc_is_mfm(); if ((d86f[drive].state & 0xF8) == 0xE8) @@ -1945,10 +2026,10 @@ void d86f_poll(int drive) { if (!d86f_can_read_address(drive)) { - /* if (fdc_get_bitcell_period() != d86f_get_bitcell_period(drive)) pclog("[%i, %i] Bitcell period mismatch (%i != %i)\n", drive, side, fdc_get_bitcell_period(), d86f_get_bitcell_period(drive)); - if (!fdd_can_read_medium(real_drive(drive))) pclog("[%i, %i] Drive can not read medium (hole = %01X)\n", drive, side, d86f_hole(drive)); - if (fdc_is_mfm() != d86f_is_mfm(drive)) pclog("[%i, %i] Encoding mismatch\n", drive, side); - if (d86f_get_encoding(drive) > 1) pclog("[%i, %i] Image encoding (%s) not FM or MFM\n", drive, side, (d86f_get_encoding(drive) == 2) ? "M2FM" : "GCR"); */ + /* if (fdc_get_bitcell_period() != d86f_get_bitcell_period(drive)) d86f_log("[%i, %i] Bitcell period mismatch (%i != %i)\n", drive, side, fdc_get_bitcell_period(), d86f_get_bitcell_period(drive)); + if (!fdd_can_read_medium(real_drive(drive))) d86f_log("[%i, %i] Drive can not read medium (hole = %01X)\n", drive, side, d86f_hole(drive)); + if (fdc_is_mfm() != d86f_is_mfm(drive)) d86f_log("[%i, %i] Encoding mismatch\n", drive, side); + if (d86f_get_encoding(drive) > 1) d86f_log("[%i, %i] Image encoding (%s) not FM or MFM\n", drive, side, (d86f_get_encoding(drive) == 2) ? "M2FM" : "GCR"); */ d86f[drive].state = STATE_SECTOR_NOT_FOUND; } @@ -1963,6 +2044,7 @@ void d86f_poll(int drive) { case STATE_02_SPIN_TO_INDEX: case STATE_0D_SPIN_TO_INDEX: + case STATE_0D_NOP_SPIN_TO_INDEX: d86f_spin_to_index(drive, side); return; case STATE_02_FIND_ID: @@ -2067,7 +2149,13 @@ void d86f_poll(int drive) case STATE_0D_FORMAT_TRACK: if (!(d86f[drive].track_pos & 15)) { - d86f_format_track(drive, side); + d86f_format_track_normal(drive, side); + } + return; + case STATE_0D_NOP_FORMAT_TRACK: + if (!(d86f[drive].track_pos & 15)) + { + d86f_format_track_nop(drive, side); } return; case STATE_IDLE: @@ -2081,7 +2169,6 @@ void d86f_poll(int drive) if (d86f_wrong_densel(drive) && (d86f[drive].state != STATE_IDLE)) { - // pclog("[State: %02X] [Side %i] No ID address mark (%i != %i?) (%02X) (%08X) (%i)\n", d86f[drive].state, side, fdc_get_bitcell_period(), d86f_get_bitcell_period(drive), d86f_handler[drive].side_flags(drive), d86f[drive].req_sector.dword, d86f_handler[drive].get_raw_size(drive, side)); d86f[drive].state = STATE_IDLE; fdc_noidam(); return; @@ -2093,7 +2180,6 @@ void d86f_poll(int drive) { case STATE_0A_FIND_ID: case STATE_SECTOR_NOT_FOUND: - // pclog("[State: %02X] [Side %i] No ID address mark (%i != %i?) (%02X) (%08X) (%i)\n", d86f[drive].state, side, fdc_get_bitcell_period(), d86f_get_bitcell_period(drive), d86f_handler[drive].side_flags(drive), d86f[drive].req_sector.dword, d86f_handler[drive].get_raw_size(drive, side)); d86f[drive].state = STATE_IDLE; fdc_noidam(); break; @@ -2104,7 +2190,6 @@ void d86f_poll(int drive) case STATE_05_FIND_DATA: case STATE_09_FIND_DATA: case STATE_0C_FIND_DATA: - // pclog("[State: %02X] [Side %i] No data address mark (%i != %i?) (%02X) (%08X) (%i)\n", d86f[drive].state, side, fdc_get_bitcell_period(), d86f_get_bitcell_period(drive), d86f_handler[drive].side_flags(drive), d86f[drive].req_sector.dword, d86f_handler[drive].get_raw_size(drive, side)); d86f[drive].state = STATE_IDLE; fdc_nodataam(); break; @@ -2128,24 +2213,20 @@ void d86f_poll(int drive) { if ((d86f[drive].error_condition & 0x18) == 0x08) { - // pclog("[State: %02X] [Side %i] Bad cylinder (%i != %i?) (%02X) (%08X) (%i)\n", d86f[drive].state, side, fdc_get_bitcell_period(), d86f_get_bitcell_period(drive), d86f_handler[drive].side_flags(drive), d86f[drive].req_sector.dword, d86f_handler[drive].get_raw_size(drive, side)); fdc_badcylinder(); } if ((d86f[drive].error_condition & 0x10) == 0x10) { - // pclog("[State: %02X] [Side %i] Wrong cylinder (%i != %i?) (%02X) (%08X) (%i)\n", d86f[drive].state, side, fdc_get_bitcell_period(), d86f_get_bitcell_period(drive), d86f_handler[drive].side_flags(drive), d86f[drive].req_sector.dword, d86f_handler[drive].get_raw_size(drive, side)); fdc_wrongcylinder(); } } else { - // pclog("[State: %02X] [Side %i] Sector not found (%i != %i?) (%02X) (%08X) (%i)\n", d86f[drive].state, side, fdc_get_bitcell_period(), d86f_get_bitcell_period(drive), d86f_handler[drive].side_flags(drive), d86f[drive].req_sector.dword, d86f_handler[drive].get_raw_size(drive, side)); fdc_nosector(); } } else { - // pclog("[State: %02X] [Side %i] No ID address mark (%i != %i?) (%02X) (%08X) (%i)\n", d86f[drive].state, side, fdc_get_bitcell_period(), d86f_get_bitcell_period(drive), d86f_handler[drive].side_flags(drive), d86f[drive].req_sector.dword, d86f_handler[drive].get_raw_size(drive, side)); fdc_noidam(); } break; @@ -2228,7 +2309,7 @@ uint16_t d86f_prepare_pretrack(int drive, int side, int iso) d86f_write_direct_common(drive, side, mfm ? iam_mfm : iam_fm, 1, pos); pos = (pos + 1) % raw_size; } - for (i = 0; i < real_gap0_len; i++) + for (i = 0; i < real_gap1_len; i++) { d86f_write_direct_common(drive, side, gap_fill, 0, pos); pos = (pos + 1) % raw_size; @@ -2410,7 +2491,6 @@ void d86f_decompose_encoded_buffer(int drive, int side) uint16_t temp, temp2; uint32_t len; uint16_t *dst = d86f[drive].track_encoded_data[side]; - uint16_t *dst_s = d86f[drive].track_surface_data[side]; uint16_t *src1 = d86f[drive].thin_track_encoded_data[0][side]; uint16_t *src1_s = d86f[drive].thin_track_surface_data[0][side]; uint16_t *src2 = d86f[drive].thin_track_encoded_data[1][side]; @@ -2521,7 +2601,6 @@ void d86f_read_track(int drive, int track, int thin_track, int side, uint16_t *d void d86f_seek(int drive, int track) { - uint8_t track_id = track; int sides; int side, thin_track; sides = d86f_get_sides(drive); @@ -2580,8 +2659,6 @@ void d86f_seek(int drive, int track) void d86f_write_track(int drive, int side, uint16_t *da0, uint16_t *sa0) { - // pclog("Pos: %08X\n", ftell(d86f[drive].f)); - fwrite(&(d86f[drive].side_flags[side]), 1, 2, d86f[drive].f); if (d86f_has_extra_bit_cells(drive)) @@ -2597,8 +2674,6 @@ void d86f_write_track(int drive, int side, uint16_t *da0, uint16_t *sa0) } fwrite(da0, 1, d86f_get_array_size(drive, side) << 1, d86f[drive].f); - - // pclog("Pos: %08X\n", ftell(d86f[drive].f)); } int d86f_get_track_table_size(int drive) @@ -2615,16 +2690,12 @@ int d86f_get_track_table_size(int drive) void d86f_writeback(int drive) { - uint8_t track_id = d86f[drive].cur_track; uint8_t header[32]; int sides, header_size; int side, thin_track; - // uint64_t crc64; uint32_t len; - int i = 0; int ret = 0; int logical_track = 0; - uint8_t tempb; FILE *cf; sides = d86f_get_sides(drive); header_size = d86f_header_size(drive); @@ -2639,9 +2710,7 @@ void d86f_writeback(int drive) fread(header, 1, header_size, d86f[drive].f); fseek(d86f[drive].f, 8, SEEK_SET); - // pclog("PosEx: %08X\n", ftell(d86f[drive].f)); fwrite(d86f[drive].track_offset, 1, d86f_get_track_table_size(drive), d86f[drive].f); - // pclog("PosEx: %08X\n", ftell(d86f[drive].f)); if (!fdd_doublestep_40(drive)) { @@ -2681,21 +2750,18 @@ void d86f_writeback(int drive) } if (d86f[drive].track_offset[logical_track]) { - // pclog("Writing track...\n"); fseek(d86f[drive].f, d86f[drive].track_offset[logical_track], SEEK_SET); d86f_write_track(drive, side, d86f[drive].track_encoded_data[side], d86f[drive].track_surface_data[side]); } } } - // pclog("Position: %08X\n", ftell(d86f[drive].f)); - if (d86f[drive].is_compressed) { /* The image is compressed. */ /* Open the original, compressed file. */ - cf = fopen(d86f[drive].original_file_name, "wb"); + cf = _wfopen(d86f[drive].original_file_name, L"wb"); /* Write the header to the original file. */ fwrite(header, 1, header_size, cf); @@ -2712,67 +2778,15 @@ void d86f_writeback(int drive) fread(d86f[drive].filebuf, 1, len, d86f[drive].f); ret = lzf_compress(d86f[drive].filebuf, len, d86f[drive].outbuf, len - 1); - // ret = d86f_zlib(cf, d86f[drive].f, 0); if (!ret) { - pclog("86F: Error compressing file\n"); + d86f_log("86F: Error compressing file\n"); } fwrite(d86f[drive].outbuf, 1, ret, cf); free(d86f[drive].outbuf); free(d86f[drive].filebuf); - -#ifdef DO_CRC64 - len = ftell(cf); - - fclose(cf); - cf = fopen(d86f[drive].original_file_name, "rb+"); - - crc64 = 0xffffffffffffffff; - fseek(cf, 8, SEEK_SET); - fwrite(&crc64, 1, 8, cf); - - fseek(cf, 0, SEEK_SET); - d86f[drive].filebuf = (uint8_t *) malloc(len); - fread(d86f[drive].filebuf, 1, len, cf); - *(uint64_t *) &(d86f[drive].filebuf[8]) = 0xffffffffffffffff; - - crc64 = (uint64_t) crc64speed(0, d86f[drive].filebuf, len); - free(d86f[drive].filebuf); - - fseek(cf, 8, SEEK_SET); - fwrite(&crc64, 1, 8, cf); - - /* Close the original file. */ - fclose(cf); -#endif } -#ifdef DO_CRC64 - else - { - fseek(d86f[drive].f, 0, SEEK_END); - len = ftell(d86f[drive].f); - - fseek(d86f[drive].f, 0, SEEK_SET); - - crc64 = 0xffffffffffffffff; - fseek(d86f[drive].f, 8, SEEK_SET); - fwrite(&crc64, 1, 8, d86f[drive].f); - - fseek(d86f[drive].f, 0, SEEK_SET); - d86f[drive].filebuf = (uint8_t *) malloc(len); - fread(d86f[drive].filebuf, 1, len, d86f[drive].f); - *(uint64_t *) &(d86f[drive].filebuf[8]) = 0xffffffffffffffff; - - crc64 = (uint64_t) crc64speed(0, d86f[drive].filebuf, len); - free(d86f[drive].filebuf); - - fseek(d86f[drive].f, 8, SEEK_SET); - fwrite(&crc64, 1, 8, d86f[drive].f); - } -#endif - - // pclog("d86f_writeback(): %08X\n", d86f[drive].track_offset[track]); } void d86f_stop(int drive) @@ -2782,7 +2796,7 @@ void d86f_stop(int drive) int d86f_common_command(int drive, int sector, int track, int side, int rate, int sector_size) { - // pclog("d86f_common_command (drive %i): fdc_period=%i img_period=%i rate=%i sector=%i track=%i side=%i\n", drive, fdc_get_bitcell_period(), d86f_get_bitcell_period(drive), rate, sector, track, side); + d86f_log("d86f_common_command (drive %i): fdc_period=%i img_period=%i rate=%i sector=%i track=%i side=%i\n", drive, fdc_get_bitcell_period(), d86f_get_bitcell_period(drive), rate, sector, track, side); d86f[drive].req_sector.id.c = track; d86f[drive].req_sector.id.h = side; @@ -2802,7 +2816,6 @@ int d86f_common_command(int drive, int sector, int track, int side, int rate, in if (fdd_get_head(drive) && (d86f_get_sides(drive) == 1)) { - // pclog("Wrong side!\n"); fdc_noidam(); d86f[drive].state = STATE_IDLE; d86f[drive].index_count = 0; @@ -2863,11 +2876,8 @@ void d86f_comparesector(int drive, int sector, int track, int side, int rate, in void d86f_readaddress(int drive, int side, int rate) { - // pclog("Reading sector ID on drive %i...\n", drive); - if (fdd_get_head(drive) && (d86f_get_sides(drive) == 1)) { - // pclog("Trying to access the second side of a single-sided disk\n"); fdc_noidam(); d86f[drive].state = STATE_IDLE; d86f[drive].index_count = 0; @@ -2935,7 +2945,7 @@ void d86f_common_format(int drive, int side, int rate, uint8_t fill, int proxy) return; } - if ((side && (d86f_get_sides(drive) == 1)) || !(d86f_can_format(drive))) + if (!(d86f_can_format(drive))) { fdc_cannotformat(); d86f[drive].state = STATE_IDLE; @@ -2943,49 +2953,48 @@ void d86f_common_format(int drive, int side, int rate, uint8_t fill, int proxy) return; } - if (!proxy) + if (!side || (d86f_get_sides(drive) == 2)) { - d86f_reset_index_hole_pos(drive, side); - - if (d86f[drive].cur_track > 256) + if (!proxy) { - // pclog("Track above 256\n"); - fdc_writeprotect(); - d86f[drive].state = STATE_IDLE; - d86f[drive].index_count = 0; - return; - } + d86f_reset_index_hole_pos(drive, side); - array_size = d86f_get_array_size(drive, side); - - if (d86f_has_surface_desc(drive)) - { - /* Preserve the physical holes but get rid of the fuzzy bytes. */ - for (i = 0; i < array_size; i++) + if (d86f[drive].cur_track > 256) { - temp = d86f[drive].track_encoded_data[side][i] ^ 0xffff; - temp2 = d86f[drive].track_surface_data[side][i]; - temp &= temp2; - d86f[drive].track_surface_data[side][i] = temp; + fdc_writeprotect(); + d86f[drive].state = STATE_IDLE; + d86f[drive].index_count = 0; + return; + } + + array_size = d86f_get_array_size(drive, side); + + if (d86f_has_surface_desc(drive)) + { + /* Preserve the physical holes but get rid of the fuzzy bytes. */ + for (i = 0; i < array_size; i++) + { + temp = d86f[drive].track_encoded_data[side][i] ^ 0xffff; + temp2 = d86f[drive].track_surface_data[side][i]; + temp &= temp2; + d86f[drive].track_surface_data[side][i] = temp; + } + } + /* Zero the data buffer. */ + memset(d86f[drive].track_encoded_data[side], 0, array_size << 1); + + d86f_add_track(drive, d86f[drive].cur_track, side); + if (!fdd_doublestep_40(drive)) + { + d86f_add_track(drive, d86f[drive].cur_track + 1, side); } } - /* Zero the data buffer. */ - memset(d86f[drive].track_encoded_data[side], 0, array_size << 1); - - d86f_add_track(drive, d86f[drive].cur_track, side); - if (!fdd_doublestep_40(drive)) - { - d86f_add_track(drive, d86f[drive].cur_track + 1, side); - } } - // pclog("Formatting track %i side %i\n", track, side); - d86f[drive].fill = fill; if (!proxy) { - // d86f[drive].side_flags[side] &= 0xc0; d86f[drive].side_flags[side] = 0; d86f[drive].side_flags[side] |= (fdd_getrpm(real_drive(drive)) == 360) ? 0x20 : 0; d86f[drive].side_flags[side] |= fdc_get_bit_rate(); @@ -2999,7 +3008,14 @@ void d86f_common_format(int drive, int side, int rate, uint8_t fill, int proxy) d86f[drive].index_count = d86f[drive].error_condition = d86f[drive].satisfying_bytes = d86f[drive].sector_count = 0; d86f[drive].dma_over = 0; - d86f[drive].state = STATE_0D_SPIN_TO_INDEX; + if (!side || (d86f_get_sides(drive) == 2)) + { + d86f[drive].state = STATE_0D_SPIN_TO_INDEX; + } + else + { + d86f[drive].state = STATE_0D_NOP_SPIN_TO_INDEX; + } } void d86f_proxy_format(int drive, int side, int rate, uint8_t fill) @@ -3025,28 +3041,27 @@ void d86f_common_handlers(int drive) drives[drive].stop = d86f_stop; } -void d86f_load(int drive, char *fn) +void d86f_load(int drive, wchar_t *fn) { uint32_t magic = 0; uint32_t len = 0; - uint32_t len2 = 0; - uint8_t temp_file_name[2048]; + wchar_t temp_file_name[2048]; uint16_t temp = 0; - uint8_t tempb = 0; - // uint64_t crc64 = 0; - // uint64_t read_crc64 = 0; int i = 0; FILE *tf; d86f_unregister(drive); writeprot[drive] = 0; - d86f[drive].f = fopen(fn, "rb+"); + d86f[drive].f = _wfopen(fn, L"rb+"); if (!d86f[drive].f) { - d86f[drive].f = fopen(fn, "rb"); + d86f[drive].f = _wfopen(fn, L"rb"); if (!d86f[drive].f) + { + memset(discfns[drive], 0, sizeof(discfns[drive])); return; + } writeprot[drive] = 1; } if (ui_writeprot[drive]) @@ -3065,14 +3080,16 @@ void d86f_load(int drive, char *fn) { /* File is WAY too small, abort. */ fclose(d86f[drive].f); + memset(discfns[drive], 0, sizeof(discfns[drive])); return; } if ((magic != 0x46423638) && (magic != 0x66623638)) { /* File is not of the valid format, abort. */ - pclog("86F: Unrecognized magic bytes: %08X\n", magic); + d86f_log("86F: Unrecognized magic bytes: %08X\n", magic); fclose(d86f[drive].f); + memset(discfns[drive], 0, sizeof(discfns[drive])); return; } @@ -3083,22 +3100,23 @@ void d86f_load(int drive, char *fn) /* File is not of a recognized format version, abort. */ if (d86f[drive].version == 0x0063) { - pclog("86F: File has emulator-internal version 0.99, this version is not valid in a file\n"); + d86f_log("86F: File has emulator-internal version 0.99, this version is not valid in a file\n"); } else if ((d86f[drive].version >= 0x0100) && (d86f[drive].version < D86FVER)) { - pclog("86F: No longer supported development file version: %i.%02i\n", d86f[drive].version >> 8, d86f[drive].version & 0xFF); + d86f_log("86F: No longer supported development file version: %i.%02i\n", d86f[drive].version >> 8, d86f[drive].version & 0xFF); } else { - pclog("86F: Unrecognized file version: %i.%02i\n", d86f[drive].version >> 8, d86f[drive].version & 0xFF); + d86f_log("86F: Unrecognized file version: %i.%02i\n", d86f[drive].version >> 8, d86f[drive].version & 0xFF); } fclose(d86f[drive].f); + update_status_bar_icon_state(drive, 1); return; } else { - pclog("86F: Recognized file version: %i.%02i\n", d86f[drive].version >> 8, d86f[drive].version & 0xFF); + d86f_log("86F: Recognized file version: %i.%02i\n", d86f[drive].version >> 8, d86f[drive].version & 0xFF); } fread(&(d86f[drive].disk_flags), 2, 1, d86f[drive].f); @@ -3109,6 +3127,7 @@ void d86f_load(int drive, char *fn) { /* File too small, abort. */ fclose(d86f[drive].f); + memset(discfns[drive], 0, sizeof(discfns[drive])); return; } @@ -3128,36 +3147,35 @@ void d86f_load(int drive, char *fn) if (crc64 != read_crc64) { - pclog("86F: CRC64 error\n"); + d86f_log("86F: CRC64 error\n"); fclose(d86f[drive].f); + memset(discfns[drive], 0, sizeof(discfns[drive])); return; } #endif if (d86f[drive].is_compressed) { - append_filename(temp_file_name, pcempath, drive ? "TEMP$$$1.$$$" : "TEMP$$$0.$$$", 511); - memcpy(temp_file_name, drive ? "TEMP$$$1.$$$" : "TEMP$$$0.$$$", 13); - memcpy(d86f[drive].original_file_name, fn, strlen(fn) + 1); + memcpy(temp_file_name, drive ? nvr_concat(L"TEMP$$$1.$$$") : nvr_concat(L"TEMP$$$0.$$$"), 256); + memcpy(d86f[drive].original_file_name, fn, (wcslen(fn) << 1) + 2); fclose(d86f[drive].f); - d86f[drive].f = fopen(temp_file_name, "wb"); + d86f[drive].f = _wfopen(temp_file_name, L"wb"); if (!d86f[drive].f) { - pclog("86F: Unable to create temporary decompressed file\n"); + d86f_log("86F: Unable to create temporary decompressed file\n"); + memset(discfns[drive], 0, sizeof(discfns[drive])); return; } - tf = fopen(fn, "rb"); + tf = _wfopen(fn, L"rb"); for (i = 0; i < 8; i++) { fread(&temp, 1, 2, tf); fwrite(&temp, 1, 2, d86f[drive].f); } - - // temp = d86f_zlib(d86f[drive].f, tf, 1); d86f[drive].filebuf = (uint8_t *) malloc(len); d86f[drive].outbuf = (uint8_t *) malloc(67108864); @@ -3175,35 +3193,38 @@ void d86f_load(int drive, char *fn) if (!temp) { - pclog("86F: Error decompressing file\n"); - remove(temp_file_name); + d86f_log("86F: Error decompressing file\n"); + _wremove(temp_file_name); + memset(discfns[drive], 0, sizeof(discfns[drive])); return; } - d86f[drive].f = fopen(temp_file_name, "rb+"); + d86f[drive].f = _wfopen(temp_file_name, L"rb+"); } if (d86f[drive].disk_flags & 0x100) { /* Zoned disk. */ - pclog("86F: Disk is zoned (Apple or Sony)\n"); + d86f_log("86F: Disk is zoned (Apple or Sony)\n"); fclose(d86f[drive].f); if (d86f[drive].is_compressed) { - remove(temp_file_name); + _wremove(temp_file_name); } + memset(discfns[drive], 0, sizeof(discfns[drive])); return; } if (d86f[drive].disk_flags & 0x600) { /* Zone type is not 0 but the disk is fixed-RPM. */ - pclog("86F: Disk is fixed-RPM but zone type is not 0\n"); + d86f_log("86F: Disk is fixed-RPM but zone type is not 0\n"); fclose(d86f[drive].f); if (d86f[drive].is_compressed) { - remove(temp_file_name); + _wremove(temp_file_name); } + memset(discfns[drive], 0, sizeof(discfns[drive])); return; } @@ -3219,11 +3240,11 @@ void d86f_load(int drive, char *fn) if (d86f[drive].is_compressed) { - d86f[drive].f = fopen(temp_file_name, "rb"); + d86f[drive].f = _wfopen(temp_file_name, L"rb"); } else { - d86f[drive].f = fopen(fn, "rb"); + d86f[drive].f = _wfopen(fn, L"rb"); } } @@ -3234,16 +3255,18 @@ void d86f_load(int drive, char *fn) if (!(d86f[drive].track_offset[0])) { /* File has no track 0 side 0, abort. */ - pclog("86F: No Track 0 side 0\n"); + d86f_log("86F: No Track 0 side 0\n"); fclose(d86f[drive].f); + memset(discfns[drive], 0, sizeof(discfns[drive])); return; } if ((d86f_get_sides(drive) == 2) && !(d86f[drive].track_offset[1])) { /* File is 2-sided but has no track 0 side 1, abort. */ - pclog("86F: No Track 0 side 0\n"); + d86f_log("86F: No Track 0 side 1\n"); fclose(d86f[drive].f); + memset(discfns[drive], 0, sizeof(discfns[drive])); return; } @@ -3306,31 +3329,25 @@ void d86f_load(int drive, char *fn) d86f_common_handlers(drive); drives[drive].format = d86f_format; - pclog("86F: Disk is %scompressed and %s surface description data\n", d86f[drive].is_compressed ? "" : "not ", d86f_has_surface_desc(drive) ? "has" : "does not have"); + d86f_log("86F: Disk is %scompressed and %s surface description data\n", d86f[drive].is_compressed ? "" : "not ", d86f_has_surface_desc(drive) ? "has" : "does not have"); } void d86f_init() { - disc_random_init(); - memset(d86f, 0, sizeof(d86f)); d86f_setupcrc(0x1021); - // crc64speed_init(); - d86f[0].state = d86f[1].state = STATE_IDLE; } void d86f_close(int drive) { - uint8_t temp_file_name[2048]; + wchar_t temp_file_name[2048]; - append_filename(temp_file_name, pcempath, drive ? "TEMP$$$1.$$$" : "TEMP$$$0.$$$", 511); - memcpy(temp_file_name, drive ? "TEMP$$$1.$$$" : "TEMP$$$0.$$$", 13); + memcpy(temp_file_name, drive ? nvr_concat(L"TEMP$$$1.$$$") : nvr_concat(L"TEMP$$$0.$$$"), 26); if (d86f[drive].f) fclose(d86f[drive].f); if (d86f[drive].is_compressed) - remove(temp_file_name); - d86f[drive].f = NULL; + _wremove(temp_file_name); } diff --git a/src/disc_86f.h b/src/disc_86f.h index 45c5838d2..ec7e83c1e 100644 --- a/src/disc_86f.h +++ b/src/disc_86f.h @@ -1,8 +1,23 @@ -/* Copyright holders: Sarah Walker, Tenshi - see COPYING for more details -*/ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Implementation of the 86F floppy image format (stores the + * data in the form of FM/MFM-encoded transitions) which also + * forms the core of the emulator's floppy disk emulation. + * + * Version: @(#)disc_86f.h 1.0.0 2017/05/30 + * + * Author: Miran Grca, + * Copyright 2016-2017 Miran Grca. + */ + void d86f_init(); -void d86f_load(int drive, char *fn); +void d86f_load(int drive, wchar_t *fn); void d86f_close(int drive); void d86f_seek(int drive, int track); int d86f_hole(int drive); diff --git a/src/disc_fdi.c b/src/disc_fdi.c index a016d4462..af192b76f 100644 --- a/src/disc_fdi.c +++ b/src/disc_fdi.c @@ -1,8 +1,25 @@ -/* Copyright holders: Sarah Walker, Tenshi - see COPYING for more details -*/ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Implementation of the FDI floppy stream image format + * interface to the FDI2RAW module. + * + * Version: @(#)disc_fdi.c 1.0.0 2017/05/30 + * + * Author: Sarah Walker, + * Miran Grca, + * Copyright 2008-2017 Sarah Walker. + * Copyright 2016-2017 Miran Grca. + */ + #include #include +#include #include "ibm.h" #include "disc.h" #include "disc_img.h" @@ -172,7 +189,6 @@ void fdi_read_revolution(int drive) memset(fdi[drive].track_data[1][density], 0, 106096); fdi[drive].tracklen[0][density] = fdi[drive].tracklen[1][density] = 100000; } - // pclog("Track is bigger than last track\n"); return; } @@ -185,16 +201,15 @@ void fdi_read_revolution(int drive) (track * fdi[drive].sides) + side, &fdi[drive].tracklen[side][density], &fdi[drive].trackindex[side][density], NULL, density); - // pclog("Side 0 [%i]: len %i, index %i\n", density, fdi[drive].tracklen[side][density], fdi[drive].trackindex[side][density]); if (!c) memset(fdi[drive].track_data[side][density], 0, fdi[drive].tracklen[side][density]); } - } - if (fdi[drive].sides == 1) - { - memset(fdi[drive].track_data[1][density], 0, 106096); - fdi[drive].tracklen[1][density] = 100000; + if (fdi[drive].sides == 1) + { + memset(fdi[drive].track_data[1][density], 0, 106096); + fdi[drive].tracklen[1][density] = 100000; + } } } @@ -241,13 +256,17 @@ void d86f_register_fdi(int drive) d86f_handler[drive].check_crc = 1; } -void fdi_load(int drive, char *fn) +void fdi_load(int drive, wchar_t *fn) { char header[26]; writeprot[drive] = fwriteprot[drive] = 1; - fdi[drive].f = fopen(fn, "rb"); - if (!fdi[drive].f) return; + fdi[drive].f = _wfopen(fn, L"rb"); + if (!fdi[drive].f) + { + memset(discfns[drive], 0, sizeof(discfns[drive])); + return; + } d86f_unregister(drive); @@ -264,10 +283,8 @@ void fdi_load(int drive, char *fn) } fdi[drive].h = fdi2raw_header(fdi[drive].f); -// if (!fdih[drive]) printf("Failed to load!\n"); fdi[drive].lasttrack = fdi2raw_get_last_track(fdi[drive].h); fdi[drive].sides = fdi2raw_get_last_head(fdi[drive].h) + 1; -// printf("Last track %i\n",fdilasttrack[drive]); d86f_register_fdi(drive); @@ -285,7 +302,6 @@ void fdi_close(int drive) fdi2raw_header_free(fdi[drive].h); if (fdi[drive].f) fclose(fdi[drive].f); - fdi[drive].f = NULL; } void fdi_seek(int drive, int track) @@ -297,11 +313,9 @@ void fdi_seek(int drive, int track) track /= 2; } } - // pclog("fdi_seek(): %i %i (%i)\n", fdi[drive].lasttrack, track); if (!fdi[drive].f) return; -// printf("Track start %i\n",track); if (track < 0) track = 0; if (track > fdi[drive].lasttrack) @@ -314,5 +328,5 @@ void fdi_seek(int drive, int track) void fdi_init() { -// printf("FDI reset\n"); + return; } diff --git a/src/disc_fdi.h b/src/disc_fdi.h index d26340fd0..ae77e0279 100644 --- a/src/disc_fdi.h +++ b/src/disc_fdi.h @@ -1,8 +1,24 @@ -/* Copyright holders: Sarah Walker - see COPYING for more details -*/ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Implementation of the FDI floppy stream image format + * interface to the FDI2RAW module. + * + * Version: @(#)disc_fdi.h 1.0.0 2017/05/30 + * + * Author: Sarah Walker, + * Miran Grca, + * Copyright 2008-2017 Sarah Walker. + * Copyright 2016-2017 Miran Grca. + */ + void fdi_init(); -void fdi_load(int drive, char *fn); +void fdi_load(int drive, wchar_t *fn); void fdi_close(int drive); void fdi_seek(int drive, int track); void fdi_readsector(int drive, int sector, int track, int side, int density, int sector_size); diff --git a/src/disc_imd.c b/src/disc_imd.c index f5db814f6..d511dd46d 100644 --- a/src/disc_imd.c +++ b/src/disc_imd.c @@ -1,6 +1,19 @@ -/* Copyright holders: Kiririn - see COPYING for more details -*/ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Implementation of the IMD floppy image format. + * + * Version: @(#)disc_imd.c 1.0.0 2017/05/30 + * + * Author: Miran Grca, + * Copyright 2016-2017 Miran Grca. + */ + #include "ibm.h" #include "disc.h" #include "disc_imd.h" @@ -8,6 +21,7 @@ #include "fdd.h" #include +#include typedef struct { @@ -28,7 +42,7 @@ typedef struct static struct { FILE *f; - uint8_t *buffer; + char *buffer; uint32_t start_offs; int track_count, sides; int track; @@ -38,7 +52,7 @@ static struct uint16_t current_side_flags[2]; uint8_t xdf_ordered_pos[256][2]; uint8_t interleave_ordered_pos[256][2]; - uint8_t *current_data[2]; + char *current_data[2]; uint8_t track_buffer[2][25000]; } imd[FDD_NUM]; @@ -49,22 +63,18 @@ void imd_init() void d86f_register_imd(int drive); -void imd_load(int drive, char *fn) +void imd_load(int drive, wchar_t *fn) { uint32_t magic = 0; uint32_t fsize = 0; - uint8_t *buffer; - uint8_t *buffer2; + char *buffer; + char *buffer2; int i = 0; - int has_cyl_map = 0; - int has_head_map = 0; - int has_size_map = 0; int track_spt = 0; int sector_size = 0; int track = 0; int side = 0; int extra = 0; - int fm = 0; uint32_t last_offset = 0; uint32_t data_size = 512; uint32_t mfm = 0; @@ -72,18 +82,20 @@ void imd_load(int drive, char *fn) uint32_t track_total = 0; uint32_t raw_tsize = 0; uint32_t minimum_gap3 = 0; - // uint32_t minimum_gap4 = 12; uint32_t minimum_gap4 = 0; d86f_unregister(drive); writeprot[drive] = 0; - imd[drive].f = fopen(fn, "rb+"); + imd[drive].f = _wfopen(fn, L"rb+"); if (!imd[drive].f) { - imd[drive].f = fopen(fn, "rb"); + imd[drive].f = _wfopen(fn, L"rb"); if (!imd[drive].f) + { + memset(discfns[drive], 0, sizeof(discfns[drive])); return; + } writeprot[drive] = 1; } if (ui_writeprot[drive]) @@ -98,6 +110,7 @@ void imd_load(int drive, char *fn) { pclog("IMD: Not a valid ImageDisk image\n"); fclose(imd[drive].f); + memset(discfns[drive], 0, sizeof(discfns[drive])); return; } else @@ -118,6 +131,7 @@ void imd_load(int drive, char *fn) { pclog("IMD: No ASCII EOF character\n"); fclose(imd[drive].f); + memset(discfns[drive], 0, sizeof(discfns[drive])); return; } else @@ -130,6 +144,7 @@ void imd_load(int drive, char *fn) { pclog("IMD: File ends after ASCII EOF character\n"); fclose(imd[drive].f); + memset(discfns[drive], 0, sizeof(discfns[drive])); return; } else @@ -149,7 +164,6 @@ void imd_load(int drive, char *fn) if (side & 1) imd[drive].sides = 2; extra = side & 0xC0; side &= 0x3F; - // pclog("IMD: Loading track %i, side %i\n", track, side); imd[drive].tracks[track][side].side_flags = (buffer2[0] % 3); if (!imd[drive].tracks[track][side].side_flags) imd[drive].disk_flags |= (0x02); @@ -249,6 +263,7 @@ void imd_load(int drive, char *fn) /* If we can't fit the sectors with a reasonable minimum gap even at 2% slower RPM, abort. */ pclog("IMD: Unable to fit the %i sectors in a track\n", track_spt); fclose(imd[drive].f); + memset(discfns[drive], 0, sizeof(discfns[drive])); return; } } @@ -287,7 +302,6 @@ void imd_close(int drive) } fclose(imd[drive].f); } - imd[drive].f = NULL; } int imd_track_is_xdf(int drive, int side, int track) @@ -295,10 +309,10 @@ int imd_track_is_xdf(int drive, int side, int track) int i, effective_sectors, xdf_sectors; int high_sectors, low_sectors; int max_high_id, expected_high_count, expected_low_count; - uint8_t *r_map; - uint8_t *n_map; - uint8_t *data_base; - uint8_t *cur_data; + char *r_map; + char *n_map; + char *data_base; + char *cur_data; effective_sectors = xdf_sectors = high_sectors = low_sectors = 0; @@ -341,12 +355,12 @@ int imd_track_is_xdf(int drive, int side, int track) if ((r_map[i] >= 0x81) && (r_map[i] <= max_high_id)) { high_sectors++; - imd[drive].xdf_ordered_pos[r_map[i]][side] = i; + imd[drive].xdf_ordered_pos[(int) r_map[i]][side] = i; } if ((r_map[i] >= 0x01) && (r_map[i] <= 0x08)) { low_sectors++; - imd[drive].xdf_ordered_pos[r_map[i]][side] = i; + imd[drive].xdf_ordered_pos[(int) r_map[i]][side] = i; } if ((high_sectors == expected_high_count) && (low_sectors == expected_low_count)) { @@ -376,7 +390,7 @@ int imd_track_is_xdf(int drive, int side, int track) if ((r_map[i] == (n_map[i] | 0x80))) { xdf_sectors++; - imd[drive].xdf_ordered_pos[r_map[i]][side] = i; + imd[drive].xdf_ordered_pos[(int) r_map[i]][side] = i; } cur_data += (128 << ((uint32_t) n_map[i])); } @@ -392,12 +406,14 @@ int imd_track_is_xdf(int drive, int side, int track) } return 0; } + + return 0; } int imd_track_is_interleave(int drive, int side, int track) { int i, effective_sectors; - uint8_t *r_map; + char *r_map; int track_spt; effective_sectors = 0; @@ -429,7 +445,7 @@ int imd_track_is_interleave(int drive, int side, int track) if ((r_map[i] >= 1) && (r_map[i] <= track_spt)) { effective_sectors++; - imd[drive].interleave_ordered_pos[r_map[i]][side] = i; + imd[drive].interleave_ordered_pos[(int) r_map[i]][side] = i; } } @@ -492,18 +508,16 @@ void imd_seek(int drive, int track) int real_sector = 0; int actual_sector = 0; - uint8_t *c_map; - uint8_t *h_map; - uint8_t *r_map; - uint8_t *n_map; + char *c_map = NULL; + char *h_map = NULL; + char *r_map; + char *n_map = NULL; uint8_t *data; uint32_t track_buf_pos[2] = { 0, 0 }; if (!imd[drive].f) return; - // pclog("IMD: Seeking...\n"); - if (!imd[drive].track_width && fdd_doublestep_40(drive)) track /= 2; @@ -514,8 +528,6 @@ void imd_seek(int drive, int track) imd[drive].current_side_flags[0] = imd[drive].tracks[track][0].side_flags; imd[drive].current_side_flags[1] = imd[drive].tracks[track][1].side_flags; - // pclog("IMD Seek: %02X %02X (%02X)\n", imd[drive].current_side_flags[0], imd[drive].current_side_flags[1], imd[drive].disk_flags); - d86f_reset_index_hole_pos(drive, 0); d86f_reset_index_hole_pos(drive, 1); @@ -543,7 +555,7 @@ void imd_seek(int drive, int track) if (n == 0xFF) { n_map = imd[drive].buffer + imd[drive].tracks[track][side].n_map_offs; - track_gap3 = gap3_sizes[track_rate][n_map[0]][imd[drive].tracks[track][side].params[3]]; + track_gap3 = gap3_sizes[track_rate][(int) n_map[0]][imd[drive].tracks[track][side].params[3]]; } else { @@ -586,7 +598,6 @@ void imd_seek(int drive, int track) if ((type == 2) || (type == 4)) deleted = 1; if ((type == 3) || (type == 4)) bad_crc = 1; - // pclog("IMD: (%i %i) %i %i %i %i (%i %i) (GPL=%i)\n", track, side, id[0], id[1], id[2], id[3], deleted, bad_crc, track_gap3); imd_sector_to_buffer(drive, track, side, data, actual_sector, ssize); current_pos = d86f_prepare_sector(drive, side, current_pos, id, data, ssize, 22, track_gap3, deleted, bad_crc); track_buf_pos[side] += ssize; @@ -627,8 +638,6 @@ void imd_seek(int drive, int track) } } } - - // pclog("Seeked to track: %i (%02X, %02X)\n", imd[drive].track, imd[drive].current_side_flags[0], imd[drive].current_side_flags[1]); } uint16_t imd_disk_flags(int drive) @@ -652,7 +661,7 @@ void imd_set_sector(int drive, int side, uint8_t c, uint8_t h, uint8_t r, uint8_ int sc = 0; int sh = 0; int sn = 0; - uint8_t *c_map, *h_map, *r_map, *n_map; + char *c_map, *h_map, *r_map, *n_map; uint8_t id[4] = { 0, 0, 0, 0 }; sc = imd[drive].tracks[track][side].params[1]; sh = imd[drive].tracks[track][side].params[2]; @@ -673,10 +682,10 @@ void imd_set_sector(int drive, int side, uint8_t c, uint8_t h, uint8_t r, uint8_ if (c != imd[drive].track) return; for (i = 0; i < imd[drive].tracks[track][side].params[3]; i++) { - id[0] = (h & 0x80) ? c_map[i] : sc; - id[1] = (h & 0x40) ? h_map[i] : (sh & 1); + id[0] = (sh & 0x80) ? c_map[i] : sc; + id[1] = (sh & 0x40) ? h_map[i] : (sh & 1); id[2] = r_map[i]; - id[3] = (n == 0xFF) ? n_map[i] : sn; + id[3] = (sn == 0xFF) ? n_map[i] : sn; if ((id[0] == c) && (id[1] == h) && (id[2] == r) && @@ -693,18 +702,18 @@ void imd_writeback(int drive) int side; int track = imd[drive].track; + int i = 0; + + char *n_map; + + uint8_t h, n, spt; + uint32_t ssize; + if (writeprot[drive]) { return; } - int i = 0; - - uint8_t *n_map; - - uint8_t h, n, spt; - uint32_t ssize; - for (side = 0; side < imd[drive].sides; side++) { if (imd[drive].tracks[track][side].is_present) diff --git a/src/disc_imd.h b/src/disc_imd.h index 03628b031..f017cebf0 100644 --- a/src/disc_imd.h +++ b/src/disc_imd.h @@ -1,7 +1,20 @@ -/* Copyright holders: Kiririn - see COPYING for more details -*/ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Implementation of the IMD floppy image format. + * + * Version: @(#)disc_imd.h 1.0.0 2017/05/30 + * + * Author: Miran Grca, + * Copyright 2016-2017 Miran Grca. + */ + void imd_init(); -void imd_load(int drive, char *fn); +void imd_load(int drive, wchar_t *fn); void imd_close(int drive); void imd_seek(int drive, int track); diff --git a/src/disc_img.c b/src/disc_img.c index fc84aa2b4..4220e5af0 100644 --- a/src/disc_img.c +++ b/src/disc_img.c @@ -1,9 +1,27 @@ -/* Copyright holders: Sarah Walker, Tenshi - see COPYING for more details -*/ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Implementation of the raw sector-based floppy image format, + * as well as the Japanese FDI, CopyQM, and FDF formats. + * + * Version: @(#)disc_img.c 1.0.0 2017/05/30 + * + * Author: Sarah Walker, + * Miran Grca, + * Copyright 2008-2017 Sarah Walker. + * Copyright 2016-2017 Miran Grca. + */ + #include +#include #include "ibm.h" +#include "config.h" #include "disc.h" #include "disc_img.h" #include "fdc.h" @@ -29,52 +47,52 @@ static struct uint16_t sector_pos[2][256]; uint8_t current_sector_pos_side; uint16_t current_sector_pos; - uint8_t *cqm_data; + uint8_t *disk_data; uint8_t is_cqm; + uint8_t disk_at_once; uint8_t interleave; uint8_t skew; } img[FDD_NUM]; uint8_t dmf_r[21] = { 12, 2, 13, 3, 14, 4, 15, 5, 16, 6, 17, 7, 18, 8, 19, 9, 20, 10, 21, 11, 1 }; -static uint8_t xdf_spt[2] = { 6, 8 }; static uint8_t xdf_logical_sectors[2][2] = { { 38, 6 }, { 46, 8 } }; uint8_t xdf_physical_sectors[2][2] = { { 16, 3 }, { 19, 4 } }; uint8_t xdf_gap3_sizes[2][2] = { { 60, 69 }, { 60, 50 } }; uint16_t xdf_trackx_spos[2][8] = { { 0xA7F, 0xF02, 0x11B7, 0xB66, 0xE1B, 0x129E }, { 0x302, 0x7E2, 0xA52, 0x12DA, 0x572, 0xDFA, 0x106A, 0x154A } }; /* XDF: Layout of the sectors in the image. */ -xdf_sector_t xdf_img_layout[2][2][46] = { { { 0x8100, 0x8200, 0x8300, 0x8400, 0x8500, 0x8600, 0x8700, 0x8800, - 0x8101, 0x8201, 0x0100, 0x0200, 0x0300, 0x0400, 0x0500, 0x0600, - 0x0700, 0x0800, 0, - 0x8301, 0x8401, 0x8501, 0x8601, 0x8701, 0x8801, 0x8901, 0x8A01, - 0x8B01, 0x8C01, 0x8D01, 0x8E01, 0x8F01, 0x9001, 0, 0, - 0, 0, 0 }, - { 0x8300, 0x8600, 0x8201, 0x8200, 0x8601, 0x8301 } +xdf_sector_t xdf_img_layout[2][2][46] = { { { {0x8100}, {0x8200}, {0x8300}, {0x8400}, {0x8500}, {0x8600}, {0x8700}, {0x8800}, + {0x8101}, {0x8201}, {0x0100}, {0x0200}, {0x0300}, {0x0400}, {0x0500}, {0x0600}, + {0x0700}, {0x0800}, { 0}, + {0x8301}, {0x8401}, {0x8501}, {0x8601}, {0x8701}, {0x8801}, {0x8901}, {0x8A01}, + {0x8B01}, {0x8C01}, {0x8D01}, {0x8E01}, {0x8F01}, {0x9001}, { 0}, { 0}, + { 0}, { 0}, { 0} }, + { {0x8300}, {0x8600}, {0x8201}, {0x8200}, {0x8601}, {0x8301} } }, /* 5.25" 2HD */ - { { 0x8100, 0x8200, 0x8300, 0x8400, 0x8500, 0x8600, 0x8700, 0x8800, - 0x8900, 0x8A00, 0x8B00, 0x8101, 0x0100, 0x0200, 0x0300, 0x0400, - 0x0500, 0x0600, 0x0700, 0x0800, 0, 0, 0, - 0x8201, 0x8301, 0x8401, 0x8501, 0x8601, 0x8701, 0x8801, 0x8901, - 0x8A01, 0x8B01, 0x8C01, 0x8D01, 0x8E01, 0x8F01, 0, 0, - 0, 0, 0, 0x9001, 0x9101, 0x9201, 0x9301 }, - { 0x8300, 0x8400, 0x8601, 0x8200, 0x8201, 0x8600, 0x8401, 0x8301 } + { { {0x8100}, {0x8200}, {0x8300}, {0x8400}, {0x8500}, {0x8600}, {0x8700}, {0x8800}, + {0x8900}, {0x8A00}, {0x8B00}, {0x8101}, {0x0100}, {0x0200}, {0x0300}, {0x0400}, + {0x0500}, {0x0600}, {0x0700}, {0x0800}, { 0}, { 0}, { 0}, + {0x8201}, {0x8301}, {0x8401}, {0x8501}, {0x8601}, {0x8701}, {0x8801}, {0x8901}, + {0x8A01}, {0x8B01}, {0x8C01}, {0x8D01}, {0x8E01}, {0x8F01}, { 0}, { 0}, + { 0}, { 0}, { 0}, {0x9001}, {0x9101}, {0x9201}, {0x9301} }, + { {0x8300}, {0x8400}, {0x8601}, {0x8200}, {0x8201}, {0x8600}, {0x8401}, {0x8301} } } /* 3.5" 2HD */ }; /* XDF: Layout of the sectors on the disk's track. */ -xdf_sector_t xdf_disk_layout[2][2][38] = { { { 0x0100, 0x0200, 0x8100, 0x8800, 0x8200, 0x0300, 0x8300, 0x0400, - 0x8400, 0x0500, 0x8500, 0x0600, 0x8600, 0x0700, 0x8700, 0x0800, - 0x8D01, 0x8501, 0x8E01, 0x8601, 0x8F01, 0x8701, 0x9001, 0x8801, - 0x8101, 0x8901, 0x8201, 0x8A01, 0x8301, 0x8B01, 0x8401, 0x8C01 }, - { 0x8300, 0x8200, 0x8600, 0x8201, 0x8301, 0x8601 } +xdf_sector_t xdf_disk_layout[2][2][38] = { { { {0x0100}, {0x0200}, {0x8100}, {0x8800}, {0x8200}, {0x0300}, {0x8300}, {0x0400}, + {0x8400}, {0x0500}, {0x8500}, {0x0600}, {0x8600}, {0x0700}, {0x8700}, {0x0800}, + {0x8D01}, {0x8501}, {0x8E01}, {0x8601}, {0x8F01}, {0x8701}, {0x9001}, {0x8801}, + {0x8101}, {0x8901}, {0x8201}, {0x8A01}, {0x8301}, {0x8B01}, {0x8401}, {0x8C01} }, + { {0x8300}, {0x8200}, {0x8600}, {0x8201}, {0x8301}, {0x8601} } }, /* 5.25" 2HD */ - { { 0x0100, 0x8A00, 0x8100, 0x8B00, 0x8200, 0x0200, 0x8300, 0x0300, - 0x8400, 0x0400, 0x8500, 0x0500, 0x8600, 0x0600, 0x8700, 0x0700, - 0x8800, 0x0800, 0x8900, - 0x9001, 0x8701, 0x9101, 0x8801, 0x9201, 0x8901, 0x9301, 0x8A01, - 0x8101, 0x8B01, 0x8201, 0x8C01, 0x8301, 0x8D01, 0x8401, 0x8E01, - 0x8501, 0x8F01, 0x8601 }, - { 0x8300, 0x8200, 0x8400, 0x8600, 0x8401, 0x8201, 0x8301, 0x8601 }, + { { {0x0100}, {0x8A00}, {0x8100}, {0x8B00}, {0x8200}, {0x0200}, {0x8300}, {0x0300}, + {0x8400}, {0x0400}, {0x8500}, {0x0500}, {0x8600}, {0x0600}, {0x8700}, {0x0700}, + {0x8800}, {0x0800}, {0x8900}, + {0x9001}, {0x8701}, {0x9101}, {0x8801}, {0x9201}, {0x8901}, {0x9301}, {0x8A01}, + {0x8101}, {0x8B01}, {0x8201}, {0x8C01}, {0x8301}, {0x8D01}, {0x8401}, {0x8E01}, + {0x8501}, {0x8F01}, {0x8601} }, + { {0x8300}, {0x8200}, {0x8400}, {0x8600}, {0x8401}, {0x8201}, {0x8301}, {0x8601} }, }, /* 3.5" 2HD */ }; @@ -83,7 +101,7 @@ xdf_sector_t xdf_disk_layout[2][2][38] = { { { 0x0100, 0x0200, 0x8100, 0x8800, 0 Disks formatted at 300 kbps @ 300 RPM can be read with any 300 RPM single-RPM drive by setting the rate rate to 300 kbps. */ static uint8_t maximum_sectors[8][6] = { { 26, 31, 38, 53, 64, 118 }, /* 128 */ { 15, 19, 23, 32, 38, 73 }, /* 256 */ - { 7, 10, 12, 17, 21, 41 }, /* 512 */ + { 7, 10, 12, 17, 22, 41 }, /* 512 */ { 3, 5, 6, 9, 11, 22 }, /* 1024 */ { 2, 2, 3, 4, 5, 11 }, /* 2048 */ { 1, 1, 1, 2, 2, 5 }, /* 4096 */ @@ -114,51 +132,126 @@ static uint8_t rates[6] = { 2, 2, 1, 4, 0, 3 }; static uint8_t holes[6] = { 0, 0, 0, 1, 1, 2 }; -int gap3_sizes[5][8][256] = { [0][1][16] = 0x54, - [0][2][18] = 0x6C, - [0][2][19] = 0x48, - [0][2][20] = 0x2A, - [0][2][21] = 0x08, /* Microsoft DMFWRITE.EXE uses this, 0x0C is used by FDFORMAT. */ - [0][2][23] = 0x01, - [0][3][10] = 0x83, - [0][3][11] = 0x26, - [1][2][11] = 0x54, - [1][2][12] = 0x1C, - [1][2][13] = 0x0E, - [1][3][6] = 0x79, - [1][3][7] = 0x06, - [2][1][10] = 0x32, - [2][1][11] = 0x0C, - [2][1][15] = 0x36, - [2][1][16] = 0x32, - [2][2][8] = 0x58, - [2][2][9] = 0x50, - [2][2][10] = 0x2E, - [2][2][21] = 0x1C, - [2][3][4] = 0xF0, - [2][3][5] = 0x74, - [3][2][36] = 0x53, - [3][2][37] = 0x4E, - [3][2][38] = 0x3D, - [3][2][39] = 0x2C, - [3][2][40] = 0x1C, - [3][2][41] = 0x0D, - [3][2][42] = 0x02, - [3][2][46] = 0x01, - [3][3][18] = 0xF7, - [3][3][19] = 0xAF, - [3][3][20] = 0x6F, - [3][3][21] = 0x55, - [3][3][22] = 0x1F, - [4][1][32] = 0x36, - [4][2][14] = 0x92, - [4][2][15] = 0x54, - [4][2][16] = 0x38, - [4][2][17] = 0x23, - [4][2][19] = 0x01, - [4][3][8] = 0x74, - [4][3][9] = 0x24 -}; +int gap3_sizes[5][8][48] = { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* [0][0] */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* [0][1] */ + 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* [0][2] */ + 0x00, 0x00, 0x6C, 0x48, 0x2A, 0x08, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x83, 0x26, 0x00, 0x00, 0x00, 0x00, /* [0][3] */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* [0][4] */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* [0][5] */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* [0][6] */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* [0][7] */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* [1][0] */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* [1][1] */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x1C, 0x0E, 0x00, 0x00, /* [1][2] */ + 0x00, 0x00, 0x6C, 0x48, 0x2A, 0x08, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x79, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* [1][3] */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* [1][4] */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* [1][5] */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* [1][6] */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* [1][7] */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* [2][0] */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32, 0x0C, 0x00, 0x00, 0x00, 0x36, /* [2][1] */ + 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, 0x50, 0x2E, 0x00, 0x00, 0x00, 0x00, 0x00, /* [2][2] */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00, 0xF0, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* [2][3] */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* [2][4] */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* [2][5] */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* [2][6] */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* [2][7] */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* [3][0] */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* [3][1] */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* [3][2] */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x53, 0x4E, 0x3D, 0x2C, 0x1C, 0x0D, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* [3][3] */ + 0x00, 0x00, 0xF7, 0xAF, 0x6F, 0x55, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* [3][4] */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* [3][5] */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* [3][6] */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* [3][7] */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* [4][0] */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* [4][1] */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x92, 0x54, /* [4][2] */ + 0x38, 0x23, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x74, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* [4][3] */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* [4][4] */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* [4][5] */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* [4][6] */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* [4][7] */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }; void img_writeback(int drive); @@ -186,15 +279,9 @@ static int sector_size_code(int sector_size) } } -static int img_sector_size_code(int drive) -{ - return sector_size_code(img[drive].sector_size); -} - void img_init() { memset(img, 0, sizeof(img)); -// adl[0] = adl[1] = 0; } void d86f_register_img(int drive); @@ -225,41 +312,50 @@ int first_byte_is_valid(uint8_t first_byte) } } -void img_load(int drive, char *fn) +double bit_rate_300; + +wchar_t *ext; + +uint8_t first_byte, second_byte, third_byte, fourth_byte; + +/* This is hard-coded to 0 - if you really need to read those NT 3.1 Beta floppy images, change this to 1 and recompile the emulator. */ +uint8_t fdf_suppress_final_byte = 0; + +void img_load(int drive, wchar_t *fn) { int size; - double bit_rate_300; uint16_t bpb_bps; uint16_t bpb_total; uint8_t bpb_mid; /* Media type ID. */ uint8_t bpb_sectors; uint8_t bpb_sides; - uint32_t bpt; - uint8_t max_spt; /* Used for XDF detection. */ int temp_rate; - char ext[4]; - int fdi, cqm; + uint8_t fdi, cqm, fdf; int i; - uint8_t first_byte, second_byte; uint16_t comment_len = 0; int16_t block_len = 0; uint32_t cur_pos = 0; uint8_t rep_byte = 0; + uint8_t run = 0; + uint8_t real_run = 0; + uint8_t *bpos; + uint16_t track_bytes = 0; + uint8_t *literal; - ext[0] = fn[strlen(fn) - 3] | 0x60; - ext[1] = fn[strlen(fn) - 2] | 0x60; - ext[2] = fn[strlen(fn) - 1] | 0x60; - ext[3] = 0; + ext = get_extension_w(fn); d86f_unregister(drive); writeprot[drive] = 0; - img[drive].f = fopen(fn, "rb+"); + img[drive].f = _wfopen(fn, L"rb+"); if (!img[drive].f) { - img[drive].f = fopen(fn, "rb"); + img[drive].f = _wfopen(fn, L"rb"); if (!img[drive].f) + { + memset(discfns[drive], 0, sizeof(discfns[drive])); return; + } writeprot[drive] = 1; } if (ui_writeprot[drive]) @@ -272,7 +368,7 @@ void img_load(int drive, char *fn) img[drive].interleave = img[drive].skew = 0; - if (strcmp(ext, "fdi") == 0) + if (_wcsicmp(ext, L"FDI") == 0) { /* This is a Japanese FDI image, so let's read the header */ pclog("img_load(): File is a Japanese FDI image...\n"); @@ -291,22 +387,218 @@ void img_load(int drive, char *fn) fseek(img[drive].f, 0x18, SEEK_SET); bpb_sides = fgetc(img[drive].f); + fseek(img[drive].f, img[drive].base, SEEK_SET); + first_byte = fgetc(img[drive].f); + fdi = 1; cqm = 0; + img[drive].disk_at_once = 0; + fdf = 0; } else { - /* Read the first type bytes. */ + /* Read the first four bytes. */ fseek(img[drive].f, 0x00, SEEK_SET); first_byte = fgetc(img[drive].f); fseek(img[drive].f, 0x01, SEEK_SET); second_byte = fgetc(img[drive].f); + fseek(img[drive].f, 0x02, SEEK_SET); + third_byte = fgetc(img[drive].f); + fseek(img[drive].f, 0x03, SEEK_SET); + fourth_byte = fgetc(img[drive].f); + + if ((first_byte == 0x1A) && (second_byte == 'F') && (third_byte == 'D') && (fourth_byte == 'F')) + { + /* This is a FDF image. */ + pclog("img_load(): File is a FDF image...\n"); + fwriteprot[drive] = writeprot[drive] = 1; + fclose(img[drive].f); + img[drive].f = _wfopen(fn, L"rb"); + + fdf = 1; + + cqm = 0; + img[drive].disk_at_once = 1; + + fseek(img[drive].f, 0x50, SEEK_SET); + fread(&img[drive].tracks, 1, 4, img[drive].f); + + /* Decode the entire file - pass 1, no write to buffer, determine length. */ + fseek(img[drive].f, 0x80, SEEK_SET); + size = 0; + track_bytes = 0; + bpos = img[drive].disk_data; + while(!feof(img[drive].f)) + { + if (!track_bytes) + { + /* Skip first 3 bytes - their meaning is unknown to us but could be a checksum. */ + first_byte = fgetc(img[drive].f); + fread(&track_bytes, 1, 2, img[drive].f); + pclog("Block header: %02X %04X ", first_byte, track_bytes); + /* Read the length of encoded data block. */ + fread(&track_bytes, 1, 2, img[drive].f); + pclog("%04X\n", track_bytes); + } + + if (feof(img[drive].f)) + { + break; + } + + if (first_byte == 0xFF) + { + break; + } + + if (first_byte) + { + run = fgetc(img[drive].f); + + /* I *HAVE* to read something because fseek tries to be smart and never hits EOF, causing an infinite loop. */ + track_bytes--; + + if (run & 0x80) + { + /* Repeat. */ + track_bytes--; + rep_byte = fgetc(img[drive].f); + } + else + { + /* Literal. */ + track_bytes -= (run & 0x7f); + literal = (uint8_t *) malloc(run & 0x7f); + fread(literal, 1, (run & 0x7f), img[drive].f); + free(literal); + } + size += (run & 0x7f); + if (!track_bytes) + { + size -= fdf_suppress_final_byte; + } + } + else + { + /* Literal block. */ + size += (track_bytes - fdf_suppress_final_byte); + literal = (uint8_t *) malloc(track_bytes); + fread(literal, 1, track_bytes, img[drive].f); + free(literal); + track_bytes = 0; + } + + if (feof(img[drive].f)) + { + break; + } + } + + /* Allocate the buffer. */ + img[drive].disk_data = (uint8_t *) malloc(size); + + /* Decode the entire file - pass 2, write to buffer. */ + fseek(img[drive].f, 0x80, SEEK_SET); + track_bytes = 0; + bpos = img[drive].disk_data; + while(!feof(img[drive].f)) + { + if (!track_bytes) + { + /* Skip first 3 bytes - their meaning is unknown to us but could be a checksum. */ + first_byte = fgetc(img[drive].f); + fread(&track_bytes, 1, 2, img[drive].f); + pclog("Block header: %02X %04X ", first_byte, track_bytes); + /* Read the length of encoded data block. */ + fread(&track_bytes, 1, 2, img[drive].f); + pclog("%04X\n", track_bytes); + } + + if (feof(img[drive].f)) + { + break; + } + + if (first_byte == 0xFF) + { + break; + } + + if (first_byte) + { + run = fgetc(img[drive].f); + real_run = (run & 0x7f); + + /* I *HAVE* to read something because fseek tries to be smart and never hits EOF, causing an infinite loop. */ + track_bytes--; + + if (run & 0x80) + { + /* Repeat. */ + track_bytes--; + if (!track_bytes) + { + real_run -= fdf_suppress_final_byte; + } + rep_byte = fgetc(img[drive].f); + if (real_run) + { + memset(bpos, rep_byte, real_run); + } + } + else + { + /* Literal. */ + track_bytes -= real_run; + literal = (uint8_t *) malloc(real_run); + fread(literal, 1, real_run, img[drive].f); + if (!track_bytes) + { + real_run -= fdf_suppress_final_byte; + } + if (run & 0x7f) + { + memcpy(bpos, literal, real_run); + } + free(literal); + } + bpos += real_run; + } + else + { + /* Literal block. */ + literal = (uint8_t *) malloc(track_bytes); + fread(literal, 1, track_bytes, img[drive].f); + memcpy(bpos, literal, track_bytes - fdf_suppress_final_byte); + free(literal); + bpos += (track_bytes - fdf_suppress_final_byte); + track_bytes = 0; + } + + if (feof(img[drive].f)) + { + break; + } + } + + first_byte = *img[drive].disk_data; + + bpb_bps = *(uint16_t *) (img[drive].disk_data + 0x0B); + bpb_total = *(uint16_t *) (img[drive].disk_data + 0x13); + bpb_mid = *(img[drive].disk_data + 0x15); + bpb_sectors = *(img[drive].disk_data + 0x18); + bpb_sides = *(img[drive].disk_data + 0x1A); + + /* Jump ahead to determine the image's geometry and finish the loading. */ + goto jump_if_fdf; + } if (((first_byte == 'C') && (second_byte == 'Q')) || ((first_byte == 'c') && (second_byte == 'q'))) { pclog("img_load(): File is a CopyQM image...\n"); - fwriteprot[drive] = writeprot[drive] = 1; + fclose(img[drive].f); + img[drive].f = _wfopen(fn, L"rb"); fseek(img[drive].f, 0x03, SEEK_SET); fread(&bpb_bps, 1, 2, img[drive].f); @@ -326,8 +618,8 @@ void img_load(int drive, char *fn) fseek(img[drive].f, 0x76, SEEK_SET); img[drive].skew = fgetc(img[drive].f); - img[drive].cqm_data = (uint8_t *) malloc(((uint32_t) bpb_total) * ((uint32_t) bpb_bps)); - memset(img[drive].cqm_data, 0xf6, ((uint32_t) bpb_total) * ((uint32_t) bpb_bps)); + img[drive].disk_data = (uint8_t *) malloc(((uint32_t) bpb_total) * ((uint32_t) bpb_bps)); + memset(img[drive].disk_data, 0xf6, ((uint32_t) bpb_total) * ((uint32_t) bpb_bps)); fseek(img[drive].f, 0x6F, SEEK_SET); fread(&comment_len, 1, 2, img[drive].f); @@ -352,12 +644,12 @@ void img_load(int drive, char *fn) if ((cur_pos + block_len) > ((uint32_t) bpb_total) * ((uint32_t) bpb_bps)) { block_len = ((uint32_t) bpb_total) * ((uint32_t) bpb_bps) - cur_pos; - memset(img[drive].cqm_data + cur_pos, rep_byte, block_len); + memset(img[drive].disk_data + cur_pos, rep_byte, block_len); break; } else { - memset(img[drive].cqm_data + cur_pos, rep_byte, block_len); + memset(img[drive].disk_data + cur_pos, rep_byte, block_len); cur_pos += block_len; } } @@ -366,12 +658,12 @@ void img_load(int drive, char *fn) if ((cur_pos + block_len) > ((uint32_t) bpb_total) * ((uint32_t) bpb_bps)) { block_len = ((uint32_t) bpb_total) * ((uint32_t) bpb_bps) - cur_pos; - fread(img[drive].cqm_data + cur_pos, 1, block_len, img[drive].f); + fread(img[drive].disk_data + cur_pos, 1, block_len, img[drive].f); break; } else { - fread(img[drive].cqm_data + cur_pos, 1, block_len, img[drive].f); + fread(img[drive].disk_data + cur_pos, 1, block_len, img[drive].f); cur_pos += block_len; } } @@ -380,9 +672,13 @@ void img_load(int drive, char *fn) printf("Finished reading CopyQM image data\n"); cqm = 1; + img[drive].disk_at_once = 1; + fdf = 0; + first_byte = *img[drive].disk_data; } else { + img[drive].disk_at_once = 0; /* Read the BPB */ pclog("img_load(): File is a raw image...\n"); fseek(img[drive].f, 0x0B, SEEK_SET); @@ -399,11 +695,12 @@ void img_load(int drive, char *fn) cqm = 0; } - img[drive].base = 0; - fdi = 0; - fseek(img[drive].f, -1, SEEK_END); size = ftell(img[drive].f) + 1; + +jump_if_fdf: + img[drive].base = 0; + fdi = 0; } img[drive].sides = 2; @@ -420,6 +717,8 @@ void img_load(int drive, char *fn) if (size <= (160*1024)) { img[drive].sectors = 8; img[drive].tracks = 40; img[drive].sides = 1; } else if (size <= (180*1024)) { img[drive].sectors = 9; img[drive].tracks = 40; img[drive].sides = 1; } + else if (size <= (315*1024)) { img[drive].sectors = 9; img[drive].tracks = 70; img[drive].sides = 1; } + else if (size <= (320*1024)) { img[drive].sectors = 8; img[drive].tracks = 40; } else if (size <= (320*1024)) { img[drive].sectors = 8; img[drive].tracks = 40; } else if (size <= (360*1024)) { img[drive].sectors = 9; img[drive].tracks = 40; } /*Double density*/ else if (size <= (400*1024)) { img[drive].sectors = 10; img[drive].tracks = 80; img[drive].sides = 1; } /*DEC RX50*/ @@ -432,13 +731,13 @@ void img_load(int drive, char *fn) else if (size <= (1120*1024)) { img[drive].sectors = 14; img[drive].tracks = 80; } /*Double density*/ else if (size <= 1228800) { img[drive].sectors = 15; img[drive].tracks = 80; } /*High density 1.2MB*/ else if (size <= 1261568) { img[drive].sectors = 8; img[drive].tracks = 77; img[drive].sector_size = 3; } /*High density 1.25MB Japanese format*/ - else if (size <= (0x1A4000-1)) { img[drive].sectors = 18; img[drive].tracks = 80; } /*High density (not supported by Tandy 1000)*/ + else if (size <= 1474560) { img[drive].sectors = 18; img[drive].tracks = 80; } /*High density (not supported by Tandy 1000)*/ else if (size <= 1556480) { img[drive].sectors = 19; img[drive].tracks = 80; } /*High density (not supported by Tandy 1000)*/ else if (size <= 1638400) { img[drive].sectors = 10; img[drive].tracks = 80; img[drive].sector_size = 3; } /*High density (not supported by Tandy 1000)*/ else if (size <= 1720320) { img[drive].sectors = 21; img[drive].tracks = 80; } /*DMF format - used by Windows 95 */ else if (size <= 1741824) { img[drive].sectors = 21; img[drive].tracks = 81; } else if (size <= 1763328) { img[drive].sectors = 21; img[drive].tracks = 82; } - else if (size <= 1802240) { img[drive].sectors = 11; img[drive].tracks = 80; img[drive].sector_size = 3; } /*High density (not supported by Tandy 1000)*/ + else if (size <= 1802240) { img[drive].sectors = 22; img[drive].tracks = 80; img[drive].sector_size = 3; } /*High density (not supported by Tandy 1000)*/ else if (size == 1884160) { img[drive].sectors = 23; img[drive].tracks = 80; } /*XDF format - used by OS/2 Warp*/ else if (size <= 2949120) { img[drive].sectors = 36; img[drive].tracks = 80; } /*E density*/ else if (size <= 3194880) { img[drive].sectors = 39; img[drive].tracks = 80; } /*E density*/ @@ -453,6 +752,7 @@ void img_load(int drive, char *fn) { pclog("Image is bigger than can fit on an ED floppy, ejecting...\n"); fclose(img[drive].f); + memset(discfns[drive], 0, sizeof(discfns[drive])); return; } } @@ -467,7 +767,7 @@ void img_load(int drive, char *fn) } else { - if (!cqm) + if (!cqm && !fdf) { /* Number of tracks = number of total sectors divided by sides times sectors per track. */ img[drive].tracks = ((uint32_t) bpb_total) / (((uint32_t) bpb_sides) * ((uint32_t) bpb_sectors)); @@ -497,6 +797,11 @@ void img_load(int drive, char *fn) } else { + if ((bit_rate_300 == 500.0) && (img[drive].sectors == 22) && (img[drive].sector_size == 2) && (img[drive].tracks >= 80) && (img[drive].tracks <= 82) && (img[drive].sides == 2)) + { + /* This is marked specially because of the track flag (a RPM slow down is needed). */ + img[drive].interleave = 2; + } img[drive].dmf = 0; } @@ -509,6 +814,7 @@ void img_load(int drive, char *fn) { pclog("Image is bigger than can fit on an ED floppy, ejecting...\n"); fclose(img[drive].f); + memset(discfns[drive], 0, sizeof(discfns[drive])); return; } @@ -525,12 +831,18 @@ void img_load(int drive, char *fn) { pclog("ERROR: Floppy image of unknown format was inserted into drive %c:!\n", drive + 0x41); fclose(img[drive].f); + memset(discfns[drive], 0, sizeof(discfns[drive])); return; } img[drive].track_width = 0; if (img[drive].tracks > 43) img[drive].track_width = 1; /* If the image has more than 43 tracks, then the tracks are thin (96 tpi). */ if (img[drive].sides == 2) img[drive].disk_flags |= 8; /* If the has 2 sides, mark it as such. */ + if (img[drive].interleave == 2) + { + img[drive].interleave = 1; + img[drive].disk_flags |= 0x60; + } img[drive].track_flags = 0x08; /* IMG files are always assumed to be MFM-encoded. */ img[drive].track_flags |= temp_rate & 3; /* Data rate. */ @@ -552,9 +864,8 @@ void img_close(int drive) d86f_unregister(drive); if (img[drive].f) fclose(img[drive].f); - if (img[drive].cqm_data) - free(img[drive].cqm_data); - img[drive].f = NULL; + if (img[drive].disk_data) + free(img[drive].disk_data); } #define xdf_img_sector xdf_img_layout[current_xdft][!is_t0][sector] @@ -583,6 +894,8 @@ void img_seek(int drive, int track) int side; int current_xdft = img[drive].xdf_type - 1; + int read_bytes = 0; + uint8_t id[4] = { 0, 0, 0, 0 }; int is_t0, sector, current_pos, img_pos, sr, sside, total, array_sector, buf_side, buf_pos; @@ -600,23 +913,25 @@ void img_seek(int drive, int track) is_t0 = (track == 0) ? 1 : 0; - if (!img[drive].is_cqm) + if (!img[drive].disk_at_once) { fseek(img[drive].f, img[drive].base + (track * img[drive].sectors * ssize * img[drive].sides), SEEK_SET); } for (side = 0; side < img[drive].sides; side++) { - if (img[drive].is_cqm) + if (img[drive].disk_at_once) { cur_pos = (track * img[drive].sectors * ssize * img[drive].sides) + (side * img[drive].sectors * ssize); - // pclog("Current position: %i... ", cur_pos); - memcpy(img[drive].track_data[side], img[drive].cqm_data + cur_pos, img[drive].sectors * ssize); - // pclog("done!\n"); + memcpy(img[drive].track_data[side], img[drive].disk_data + cur_pos, img[drive].sectors * ssize); } else { - fread(img[drive].track_data[side], img[drive].sectors * ssize, 1, img[drive].f); + read_bytes = fread(img[drive].track_data[side], 1, img[drive].sectors * ssize, img[drive].f); + if (read_bytes < (img[drive].sectors * ssize)) + { + memset(img[drive].track_data[side] + read_bytes, 0xf6, (img[drive].sectors * ssize) - read_bytes); + } } } @@ -631,7 +946,6 @@ void img_seek(int drive, int track) for (sector = 0; sector < img[drive].sectors; sector++) { - // sr = img[drive].dmf ? (dmf_r[sector]) : (sector + 1); if (img[drive].is_cqm) { if (img[drive].interleave) @@ -665,7 +979,6 @@ void img_seek(int drive, int track) id[3] = img[drive].sector_size; img[drive].sector_pos_side[side][sr] = side; img[drive].sector_pos[side][sr] = (sr - 1) * ssize; - // pclog("Seek: %i %i %i %i | %i %04X\n", id[0], id[1], id[2], id[3], side, (sr - 1) * ssize); current_pos = d86f_prepare_sector(drive, side, current_pos, id, &img[drive].track_data[side][(sr - 1) * ssize], ssize, img[drive].gap2_size, img[drive].gap3_size, 0, 0); } } @@ -689,7 +1002,6 @@ void img_seek(int drive, int track) { img[drive].sector_pos_side[xdf_img_sector.id.h][xdf_img_sector.id.r] = sside; img[drive].sector_pos[xdf_img_sector.id.h][xdf_img_sector.id.r] = img_pos; - // pclog("Side: %i, Position: %04X\n", sside, img_pos); } if (!is_t0) @@ -708,13 +1020,10 @@ void img_seek(int drive, int track) for (sector = 0; sector < xdf_physical_sectors[current_xdft][!is_t0]; sector++) { array_sector = (side * xdf_physical_sectors[current_xdft][!is_t0]) + sector; - // pclog("Sector %i, array sector %i\n", sector, array_sector); buf_side = img[drive].sector_pos_side[xdf_disk_sector.id.h][xdf_disk_sector.id.r]; buf_pos = img[drive].sector_pos[xdf_disk_sector.id.h][xdf_disk_sector.id.r]; - // pclog("Side: %i, Position: %04X\n", buf_side, buf_pos); - id[0] = track; id[1] = xdf_disk_sector.id.h; id[2] = xdf_disk_sector.id.r; @@ -722,21 +1031,17 @@ void img_seek(int drive, int track) if (is_t0) { id[3] = 2; - // pclog("XDF Track 0: Registering sector: %i %i %i %i\n", id[0], id[1], id[2], id[3]); current_pos = d86f_prepare_sector(drive, side, current_pos, id, &img[drive].track_data[buf_side][buf_pos], ssize, img[drive].gap2_size, xdf_gap3_sizes[current_xdft][!is_t0], 0, 0); } else { id[3] = id[2] & 7; - // pclog("XDF Track X: Registering sector: %i %i %i %i\n", id[0], id[1], id[2], id[3]); ssize = (128 << id[3]); current_pos = d86f_prepare_sector(drive, side, xdf_trackx_spos[current_xdft][array_sector], id, &img[drive].track_data[buf_side][buf_pos], ssize, img[drive].gap2_size, xdf_gap3_sizes[current_xdft][!is_t0], 0, 0); } } } } - - // pclog("Seeked to track: %i\n", img[drive].track); } void img_writeback(int drive) @@ -747,7 +1052,7 @@ void img_writeback(int drive) if (!img[drive].f) return; - if (img[drive].is_cqm) + if (img[drive].disk_at_once) return; fseek(img[drive].f, img[drive].base + (img[drive].track * img[drive].sectors * ssize * img[drive].sides), SEEK_SET); diff --git a/src/disc_img.h b/src/disc_img.h index a98ba1a98..94c4780cf 100644 --- a/src/disc_img.h +++ b/src/disc_img.h @@ -1,7 +1,23 @@ -/* Copyright holders: Sarah Walker, Kiririn - see COPYING for more details -*/ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Implementation of the raw sector-based floppy image format, + * as well as the Japanese FDI, CopyQM, and FDF formats. + * + * Version: @(#)disc_img.h 1.0.0 2017/05/30 + * + * Author: Sarah Walker, + * Miran Grca, + * Copyright 2008-2017 Sarah Walker. + * Copyright 2016-2017 Miran Grca. + */ + void img_init(); -void img_load(int drive, char *fn); +void img_load(int drive, wchar_t *fn); void img_close(int drive); void img_seek(int drive, int track); diff --git a/src/disc_random.c b/src/disc_random.c index da4b09673..17b28c2e5 100644 --- a/src/disc_random.c +++ b/src/disc_random.c @@ -1,11 +1,26 @@ -/* Better random number generator by Battler. */ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * A better random number generation, used for floppy weak bits + * and network MAC address generation. + * + * Version: @(#)disc_random.c 1.0.0 2017/05/30 + * + * Author: Miran Grca, + * Copyright 2016-2017 Miran Grca. + */ #include #include #include -#include +#include #include #include #include @@ -33,7 +48,15 @@ static __inline__ uint32_t rotr32c (uint32_t x, uint32_t n) static __inline__ unsigned long long rdtsc(void) { unsigned hi, lo; - __asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi)); +#ifdef __MSC__ + __asm { + rdtsc + mov hi, edx ; EDX:EAX is already standard return!! + mov lo, eax + } +#else + __asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi)); +#endif return ( (unsigned long long)lo)|( ((unsigned long long)hi)<<32 ); } diff --git a/src/disc_random.h b/src/disc_random.h index 25dc87326..601e9d84f 100644 --- a/src/disc_random.h +++ b/src/disc_random.h @@ -1,2 +1,19 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * A better random number generation, used for floppy weak bits + * and network MAC address generation. + * + * Version: @(#)disc_random.h 1.0.0 2017/05/30 + * + * Author: Miran Grca, + * Copyright 2016-2017 Miran Grca. + */ + uint8_t disc_random_generate(); void disc_random_init(); diff --git a/src/disc_td0.c b/src/disc_td0.c index 9e21a9b11..ac2cd9a6b 100644 --- a/src/disc_td0.c +++ b/src/disc_td0.c @@ -1,5 +1,29 @@ -// license:BSD-3-Clause -// copyright-holders:Miodrag Milanovic,Kiririn (translation to C and port to 86Box) +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * +* Implementation of the Teledisk floppy image format. + * + * Version: @(#)disc_td0.c 1.0.0 2017/05/30 + * + * Author: Milodrag Milanovic, + * Haruhiko OKUMURA, + * Haruyasu YOSHIZAKI, + * Kenji RIKITAKE, + * Miran Grca, + * Copyright 1988-2017 Haruhiko OKUMURA. + * Copyright 1988-2017 Haruyasu YOSHIZAKI. + * Copyright 1988-2017 Kenji RIKITAKE. + * Copyright 2013-2017 Milodrag Milanovic. + * Copyright 2016-2017 Miran Grca. + */ + +/* license:BSD-3-Clause + copyright-holders:Miodrag Milanovic, Miran Grca (translation to C and port to 86Box) */ /********************************************************************* formats/td0_dsk.c @@ -14,6 +38,8 @@ * Edited and translated to English by Kenji RIKITAKE */ +#include + #include "ibm.h" #include "disc.h" #include "disc_td0.h" @@ -22,7 +48,7 @@ #include -#define BUFSZ 512 // new input buffer +#define BUFSZ 512 /* new input buffer */ /* LZSS Parameters */ @@ -44,10 +70,10 @@ typedef struct { uint16_t r, - bufcnt,bufndx,bufpos, // string buffer - // the following to allow block reads from input in next_word() - ibufcnt,ibufndx; // input buffer counters - uint8_t inbuf[BUFSZ]; // input buffer + bufcnt,bufndx,bufpos, /* string buffer */ + /* the following to allow block reads from input in next_word() */ + ibufcnt,ibufndx; /* input buffer counters */ + uint8_t inbuf[BUFSZ]; /* input buffer */ } tdlzhuf; typedef struct @@ -72,8 +98,6 @@ typedef struct uint8_t getlen; } td0dsk_t; -//static td0dsk_t td0dsk; - typedef struct { uint8_t track; @@ -118,7 +142,7 @@ void floppy_image_read(int drive, char *buffer, uint32_t offset, uint32_t len) int td0_dsk_identify(int drive) { - uint8_t header[2]; + char header[2]; floppy_image_read(drive, header, 0, 2); if (header[0]=='T' && header[1]=='D') { @@ -230,7 +254,7 @@ int td0_state_next_word(td0dsk_t *state) if(state->tdctl.ibufcnt == 0) return(-1); } - while (state->getlen <= 8) { // typically reads a word at a time + while (state->getlen <= 8) { /* typically reads a word at a time */ state->getbuf |= state->tdctl.inbuf[state->tdctl.ibufndx++] << (8 - state->getlen); state->getlen += 8; } @@ -427,7 +451,7 @@ void td0_state_init_Decode(td0dsk_t *state) int i; state->getbuf = 0; state->getlen = 0; - state->tdctl.ibufcnt= state->tdctl.ibufndx = 0; // input buffer is empty + state->tdctl.ibufcnt= state->tdctl.ibufndx = 0; /* input buffer is empty */ state->tdctl.bufcnt = 0; td0_state_StartHuff(state); for (i = 0; i < N - F; i++) @@ -439,11 +463,11 @@ void td0_state_init_Decode(td0dsk_t *state) int td0_state_Decode(td0dsk_t *state, uint8_t *buf, int len) /* Decoding/Uncompressing */ { int16_t c,pos; - int count; // was an unsigned long, seems unnecessary + int count; /* was an unsigned long, seems unnecessary */ for (count = 0; count < len; ) { if(state->tdctl.bufcnt == 0) { if((c = td0_state_DecodeChar(state)) < 0) - return(count); // fatal error + return(count); /* fatal error */ if (c < 256) { *(buf++) = c; state->text_buf[state->tdctl.r++] = c; @@ -452,13 +476,13 @@ int td0_state_Decode(td0dsk_t *state, uint8_t *buf, int len) /* Decoding/Uncomp } else { if((pos = td0_state_DecodePosition(state)) < 0) - return(count); // fatal error + return(count); /* fatal error */ state->tdctl.bufpos = (state->tdctl.r - pos - 1) & (N - 1); state->tdctl.bufcnt = c - 255 + THRESHOLD; state->tdctl.bufndx = 0; } } - else { // still chars from last string + else { /* still chars from last string */ while( state->tdctl.bufndx < state->tdctl.bufcnt && count < len ) { c = state->text_buf[(state->tdctl.bufpos + state->tdctl.bufndx) & (N - 1)]; *(buf++) = c; @@ -467,12 +491,12 @@ int td0_state_Decode(td0dsk_t *state, uint8_t *buf, int len) /* Decoding/Uncomp state->tdctl.r &= (N - 1); count++; } - // reset bufcnt after copy string from text_buf[] + /* reset bufcnt after copy string from text_buf[] */ if(state->tdctl.bufndx >= state->tdctl.bufcnt) state->tdctl.bufndx = state->tdctl.bufcnt = 0; } } - return(count); // count == len, success + return(count); /* count == len, success */ } @@ -495,23 +519,23 @@ void td0_init() void d86f_register_td0(int drive); -// static const int rates[3] = { 2, 1, 0, 2, 3 }; /* 0 = 250 kbps, 1 = 300 kbps, 2 = 500 kbps, 3 = unknown, 4 = 1000 kbps */ -const int max_size = 4*1024*1024; // 4MB ought to be large enough for any floppy +const int max_size = 4*1024*1024; /* 4MB ought to be large enough for any floppy */ const int max_processed_size = 5*1024*1024; uint8_t imagebuf[4*1024*1024]; uint8_t processed_buf[5*1024*1024]; uint8_t header[12]; -void td0_load(int drive, char *fn) +void td0_load(int drive, wchar_t *fn) { int ret = 0; d86f_unregister(drive); writeprot[drive] = 1; - td0[drive].f = fopen(fn, "rb"); + td0[drive].f = _wfopen(fn, L"rb"); if (!td0[drive].f) { + memset(discfns[drive], 0, sizeof(discfns[drive])); return; } fwriteprot[drive] = writeprot[drive]; @@ -521,6 +545,7 @@ void td0_load(int drive, char *fn) { pclog("TD0: Not a valid Teledisk image\n"); fclose(td0[drive].f); + memset(discfns[drive], 0, sizeof(discfns[drive])); return; } else @@ -535,6 +560,7 @@ void td0_load(int drive, char *fn) { pclog("TD0: Failed to initialize\n"); fclose(td0[drive].f); + memset(discfns[drive], 0, sizeof(discfns[drive])); return; } else @@ -582,7 +608,6 @@ void td0_close(int drive) if (td0[drive].f) fclose(td0[drive].f); - td0[drive].f = NULL; } uint32_t td0_get_raw_tsize(int side_flags, int slower_rpm) @@ -632,12 +657,10 @@ int td0_initialize(int drive) int head_count = 0; int track_spt; int offset = 0; - int ret = 0; - int gap3_len = 0; - // int rate = 0; int density = 0; int i = 0; int j = 0; + int k = 0; int temp_rate = 0; uint32_t file_size; uint16_t len; @@ -651,7 +674,6 @@ int td0_initialize(int drive) uint32_t track_size = 0; uint32_t raw_tsize = 0; uint32_t minimum_gap3 = 0; - // uint32_t minimum_gap4 = 12; uint32_t minimum_gap4 = 0; if (!td0[drive].f) @@ -698,7 +720,7 @@ int td0_initialize(int drive) offset = 10 + imagebuf[2] + (imagebuf[3] << 8); track_spt = imagebuf[offset]; - if(track_spt == 255) // Empty file? + if(track_spt == 255) /* Empty file? */ { pclog("TD0: File has no tracks\n"); return 0; @@ -738,9 +760,6 @@ int td0_initialize(int drive) td0[drive].track_width = (header[7] & 1) ^ 1; - // rate = (header[5] & 0x7f) >= 3 ? 0 : rates[header[5] & 0x7f]; - // td0[drive].default_track_flags |= rate; - for (i = 0; i < 256; i++) { memset(td0[drive].side_flags[i], 0, 4); @@ -756,7 +775,7 @@ int td0_initialize(int drive) { track = imagebuf[offset + 1]; head = imagebuf[offset + 2] & 1; - fm = (header[5] & 0x80) || (imagebuf[offset + 2] & 0x80); // ? + fm = (header[5] & 0x80) || (imagebuf[offset + 2] & 0x80); /* ? */ td0[drive].side_flags[track][head] = td0[drive].default_track_flags | (fm ? 0 : 8); td0[drive].track_in_file[track][head] = 1; offset += 4; @@ -766,7 +785,6 @@ int td0_initialize(int drive) for(i = 0; i < track_spt; i++) { hs = &imagebuf[offset]; - size; offset += 6; td0[drive].sects[track][head][i].track = hs[0]; @@ -792,7 +810,6 @@ int td0_initialize(int drive) else { offset += 3; - int j, k; switch(hs[8]) { default: @@ -890,7 +907,6 @@ int td0_initialize(int drive) temp_rate = td0[drive].default_track_flags & 7; if ((td0[drive].default_track_flags & 0x27) == 0x20) temp_rate = 4; td0[drive].gap3_len = gap3_sizes[temp_rate][td0[drive].sects[0][0][0].size][td0[drive].track_spt[0][0]]; - // pclog("GAP3 length for %i %i %i is %i\n", temp_rate, td0[drive].sects[0][0][0].size, td0[drive].track_spt[0][0], td0[drive].gap3_len); if (!td0[drive].gap3_len) { td0[drive].gap3_len = td0[drive].calculated_gap3_lengths[0][0]; /* If we can't determine the GAP3 length, assume the smallest one we possibly know of. */ @@ -968,12 +984,10 @@ int td0_track_is_xdf(int drive, int side, int track) td0[drive].current_side_flags[side] = (td0[drive].track_spt[track][side] == 19) ? 0x08 : 0x28; return (td0[drive].track_spt[track][side] == 19) ? 2 : 1; } - // pclog("XDF: %i %i %i %i\n", high_sectors, expected_high_count, low_sectors, expected_low_count); return 0; } else { - // pclog("XDF: %i sectors per track (%i %i)\n", td0[drive].track_spt[track][side], track, side); return 0; } } @@ -996,7 +1010,6 @@ int td0_track_is_xdf(int drive, int side, int track) td0[drive].xdf_ordered_pos[id[2]][side] = i; } } - // pclog("XDF: %i %i\n", effective_sectors, xdf_sectors); if ((effective_sectors == 3) && (xdf_sectors == 3)) { td0[drive].current_side_flags[side] = 0x28; @@ -1087,8 +1100,6 @@ void td0_seek(int drive, int track) td0[drive].current_side_flags[0] = td0[drive].side_flags[track][0]; td0[drive].current_side_flags[1] = td0[drive].side_flags[track][1]; - // pclog("TD0 Seek: %02X %02X (%02X)\n", td0[drive].current_side_flags[0], td0[drive].current_side_flags[1], td0[drive].disk_flags); - d86f_reset_index_hole_pos(drive, 0); d86f_reset_index_hole_pos(drive, 1); @@ -1128,7 +1139,6 @@ void td0_seek(int drive, int track) id[1] = td0[drive].sects[track][side][actual_sector].head; id[2] = real_sector; id[3] = td0[drive].sects[track][side][actual_sector].size; - // pclog("TD0: %i %i %i %i (%i %i) (GPL=%i)\n", id[0], id[1], id[2], id[3], td0[drive].sects[track][side][actual_sector].deleted, td0[drive].sects[track][side][actual_sector].bad_crc, track_gap3); ssize = 128 << ((uint32_t) td0[drive].sects[track][side][actual_sector].size); current_pos = d86f_prepare_sector(drive, side, current_pos, id, td0[drive].sects[track][side][actual_sector].data, ssize, track_gap2, track_gap3, td0[drive].sects[track][side][actual_sector].deleted, td0[drive].sects[track][side][actual_sector].bad_crc); } @@ -1146,7 +1156,6 @@ void td0_seek(int drive, int track) id[3] = is_trackx ? (id[2] & 7) : 2; ssize = 128 << ((uint32_t) id[3]); ordered_pos = td0[drive].xdf_ordered_pos[id[2]][side]; - // pclog("TD0: XDF: (%i %i) %i %i %i %i (%i %i) (GPL=%i)\n", track, side, id[0], id[1], id[2], id[3], td0[drive].sects[track][side][ordered_pos].deleted, td0[drive].sects[track][side][ordered_pos].bad_crc, track_gap3); if (is_trackx) { current_pos = d86f_prepare_sector(drive, side, xdf_trackx_spos[xdf_type][xdf_sector], id, td0[drive].sects[track][side][ordered_pos].data, ssize, track_gap2, xdf_gap3_sizes[xdf_type][is_trackx], td0[drive].sects[track][side][ordered_pos].deleted, td0[drive].sects[track][side][ordered_pos].bad_crc); @@ -1158,8 +1167,6 @@ void td0_seek(int drive, int track) } } } - - // pclog("Seeked to track: %i (%02X, %02X)\n", td0[drive].track, td0[drive].current_side_flags[0], td0[drive].current_side_flags[1]); } uint16_t td0_disk_flags(int drive) @@ -1208,4 +1215,4 @@ void d86f_register_td0(int drive) d86f_handler[drive].index_hole_pos = null_index_hole_pos; d86f_handler[drive].get_raw_size = common_get_raw_size; d86f_handler[drive].check_crc = 1; -} \ No newline at end of file +} diff --git a/src/disc_td0.h b/src/disc_td0.h index 48226d77a..e28f2dc7d 100644 --- a/src/disc_td0.h +++ b/src/disc_td0.h @@ -1,7 +1,28 @@ -/* Copyright holders: Kiririn - see COPYING for more details -*/ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Implementation of the Teledisk floppy image format. + * + * Version: @(#)disc_td0.h 1.0.0 2017/05/30 + * + * Author: Milodrag Milanovic, + * Haruhiko OKUMURA, + * Haruyasu YOSHIZAKI, + * Kenji RIKITAKE, + * Miran Grca, + * Copyright 1988-2017 Haruhiko OKUMURA. + * Copyright 1988-2017 Haruyasu YOSHIZAKI. + * Copyright 1988-2017 Kenji RIKITAKE. + * Copyright 2013-2017 Milodrag Milanovic. + * Copyright 2016-2017 Miran Grca. + */ + void td0_init(); -void td0_load(int drive, char *fn); +void td0_load(int drive, wchar_t *fn); void td0_close(int drive); void td0_seek(int drive, int track); diff --git a/src/dma.c b/src/dma.c index 969ffca34..96f98bd96 100644 --- a/src/dma.c +++ b/src/dma.c @@ -1,23 +1,37 @@ -/* Copyright holders: Sarah Walker - see COPYING for more details -*/ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Implementation of the Intel DMA controllers. + * + * Version: @(#)dma.c 1.0.1 2017/06/03 + * + * Authors: Sarah Walker, + * Miran Grca, + * Copyright 2008-2017 Sarah Walker. + * Copyright 2016-2017 Miran Grca. + */ #include "ibm.h" - -#include "disc.h" -#include "dma.h" -#include "fdc.h" -#include "io.h" +#include "cpu/x86.h" #include "mem.h" -#include "video.h" +#include "io.h" +#include "dma.h" + static uint8_t dmaregs[16]; -static int dmaon[4]; static uint8_t dma16regs[16]; -static int dma16on[4]; static uint8_t dmapages[16]; -void dma_reset() +DMA dma, dma16; + + +void dma_reset(void) { +#if 1 int c; dma.wp = 0; for (c = 0; c < 16; c++) @@ -44,19 +58,25 @@ void dma_reset() dma16.cb[c] = 0; } dma16.m = 0; +#else + memset(dmaregs, 0, 16); + memset(dma16regs, 0, 16); + memset(dmapages, 0, 16); + memset(&dma, 0, sizeof(DMA)); + memset(&dma16, 0, sizeof(DMA)); +#endif } uint8_t dma_read(uint16_t addr, void *priv) { uint8_t temp; -// printf("Read DMA %04X %04X:%04X %i %02X\n",addr,CS,pc, pic_intpending, pic.pend); switch (addr & 0xf) { case 0: case 2: case 4: case 6: /*Address registers*/ dma.wp ^= 1; if (dma.wp) return dma.ac[(addr >> 1) & 3] & 0xff; - return dma.ac[(addr >> 1) & 3] >> 8; + return (dma.ac[(addr >> 1) & 3] >> 8) & 0xff; case 1: case 3: case 5: case 7: /*Count registers*/ dma.wp ^= 1; @@ -72,31 +92,26 @@ uint8_t dma_read(uint16_t addr, void *priv) case 0xd: return 0; } -// printf("Bad DMA read %04X %04X:%04X\n",addr,CS,pc); return dmaregs[addr & 0xf]; } void dma_write(uint16_t addr, uint8_t val, void *priv) { -// printf("Write DMA %04X %02X %04X:%04X\n",addr,val,CS,pc); dmaregs[addr & 0xf] = val; switch (addr & 0xf) { case 0: case 2: case 4: case 6: /*Address registers*/ dma.wp ^= 1; - if (dma.wp) dma.ab[(addr >> 1) & 3] = (dma.ab[(addr >> 1) & 3] & 0xff00) | val; - else dma.ab[(addr >> 1) & 3] = (dma.ab[(addr >> 1) & 3] & 0x00ff) | (val << 8); - dma.ac[(addr >> 1) & 3] = dma.ab[(addr >> 1) & 3] & 0xffff; - dmaon[(addr >> 1) & 3] = 1; + if (dma.wp) dma.ab[(addr >> 1) & 3] = (dma.ab[(addr >> 1) & 3] & 0xffff00) | val; + else dma.ab[(addr >> 1) & 3] = (dma.ab[(addr >> 1) & 3] & 0xff00ff) | (val << 8); + dma.ac[(addr >> 1) & 3] = dma.ab[(addr >> 1) & 3]; return; case 1: case 3: case 5: case 7: /*Count registers*/ dma.wp ^= 1; if (dma.wp) dma.cb[(addr >> 1) & 3] = (dma.cb[(addr >> 1) & 3] & 0xff00) | val; else dma.cb[(addr >> 1) & 3] = (dma.cb[(addr >> 1) & 3] & 0x00ff) | (val << 8); - dma.cc[(addr >> 1) & 3] = dma.cb[(addr >> 1) & 3] & 0xffff; - // pclog("DMA count for channel %i now: %02X\n", (addr >> 1) & 3, dma.cc[(addr >> 1) & 3]); - dmaon[(addr >> 1) & 3] = 1; + dma.cc[(addr >> 1) & 3] = dma.cb[(addr >> 1) & 3]; return; case 8: /*Control register*/ @@ -110,6 +125,16 @@ void dma_write(uint16_t addr, uint8_t val, void *priv) case 0xb: /*Mode*/ dma.mode[val & 3] = val; + if (dma.is_ps2) + { + dma.ps2_mode[val & 3] &= ~0x1c; + if (val & 0x20) + dma.ps2_mode[val & 3] |= 0x10; + if ((val & 0xc) == 8) + dma.ps2_mode[val & 3] |= 4; + else if ((val & 0xc) == 4) + dma.ps2_mode[val & 3] |= 0xc; + } return; case 0xc: /*Clear FF*/ @@ -118,32 +143,203 @@ void dma_write(uint16_t addr, uint8_t val, void *priv) case 0xd: /*Master clear*/ dma.wp = 0; - dma.stat = 0; dma.m = 0xf; return; - case 0xe: /*Mask reset*/ - dma.m = 0; - return; - case 0xf: /*Mask write*/ dma.m = val & 0xf; return; } } +static uint8_t dma_ps2_read(uint16_t addr, void *priv) +{ + uint8_t temp = 0xff; + + switch (addr) + { + case 0x1a: + switch (dma.xfr_command) + { + case 2: /*Address*/ + case 3: + switch (dma.byte_ptr) + { + case 0: + temp = (dma.xfr_channel & 4) ? (dma16.ac[dma.xfr_channel & 3] & 0xff) : (dma.ac[dma.xfr_channel] & 0xff); + dma.byte_ptr = 1; + break; + case 1: + temp = (dma.xfr_channel & 4) ? (dma16.ac[dma.xfr_channel & 3] >> 8) : (dma.ac[dma.xfr_channel] >> 8); + dma.byte_ptr = 2; + break; + case 2: + temp = (dma.xfr_channel & 4) ? (dma16.ac[dma.xfr_channel & 3] >> 16) : (dma.ac[dma.xfr_channel] >> 16); + dma.byte_ptr = 0; + break; + } + break; + case 4: /*Count*/ + case 5: + if (dma.byte_ptr) + temp = (dma.xfr_channel & 4) ? (dma16.cc[dma.xfr_channel & 3] >> 8) : (dma.cc[dma.xfr_channel] >> 8); + else + temp = (dma.xfr_channel & 4) ? (dma16.cc[dma.xfr_channel & 3] & 0xff) : (dma.cc[dma.xfr_channel] & 0xff); + dma.byte_ptr = (dma.byte_ptr + 1) & 1; + break; + case 7: /*Mode*/ + temp = (dma.xfr_channel & 4) ? dma16.ps2_mode[dma.xfr_channel & 3] : dma.ps2_mode[dma.xfr_channel]; + break; + case 8: /*Arbitration Level*/ + temp = (dma.xfr_channel & 4) ? dma16.arb_level[dma.xfr_channel & 3] : dma.arb_level[dma.xfr_channel]; + break; + + default: + fatal("Bad XFR Read command %i channel %i\n", dma.xfr_command, dma.xfr_channel); + } + break; + } + + return temp; +} + +static void dma_ps2_write(uint16_t addr, uint8_t val, void *priv) +{ + uint8_t mode; + + switch (addr) + { + case 0x18: + dma.xfr_channel = val & 0x7; + dma.xfr_command = val >> 4; + dma.byte_ptr = 0; + switch (dma.xfr_command) + { + case 9: /*Set DMA mask*/ + if (dma.xfr_channel & 4) + dma16.m |= (1 << (dma.xfr_channel & 3)); + else + dma.m |= (1 << dma.xfr_channel); + break; + case 0xa: /*Reset DMA mask*/ + if (dma.xfr_channel & 4) + dma16.m &= ~(1 << (dma.xfr_channel & 3)); + else + dma.m &= ~(1 << dma.xfr_channel); + break; + } + break; + case 0x1a: + switch (dma.xfr_command) + { + case 2: /*Address*/ + switch (dma.byte_ptr) + { + case 0: + if (dma.xfr_channel & 4) + dma16.ac[dma.xfr_channel & 3] = (dma16.ac[dma.xfr_channel & 3] & 0xffff00) | val; + else + dma.ac[dma.xfr_channel] = (dma.ac[dma.xfr_channel] & 0xffff00) | val; + dma.byte_ptr = 1; + break; + case 1: + if (dma.xfr_channel & 4) + dma16.ac[dma.xfr_channel & 3] = (dma16.ac[dma.xfr_channel & 3] & 0xff00ff) | (val << 8); + else + dma.ac[dma.xfr_channel] = (dma.ac[dma.xfr_channel] & 0xff00ff) | (val << 8); + dma.byte_ptr = 2; + break; + case 2: + if (dma.xfr_channel & 4) + dma16.ac[dma.xfr_channel & 3] = (dma16.ac[dma.xfr_channel & 3] & 0x00ffff) | (val << 16); + else + dma.ac[dma.xfr_channel] = (dma.ac[dma.xfr_channel] & 0x00ffff) | (val << 16); + dma.byte_ptr = 0; + break; + } + if (dma.xfr_channel & 4) + dma16.ab[dma.xfr_channel & 3] = dma16.ac[dma.xfr_channel & 3]; + else + dma.ab[dma.xfr_channel] = dma.ac[dma.xfr_channel]; + break; + + case 4: /*Count*/ + if (dma.byte_ptr) + { + if (dma.xfr_channel & 4) + dma16.cc[dma.xfr_channel & 3] = (dma16.cc[dma.xfr_channel & 3] & 0xff) | (val << 8); + else + dma.cc[dma.xfr_channel] = (dma.cc[dma.xfr_channel] & 0xff) | (val << 8); + } + else + { + if (dma.xfr_channel & 4) + dma16.cc[dma.xfr_channel & 3] = (dma16.cc[dma.xfr_channel & 3] & 0xff00) | val; + else + dma.cc[dma.xfr_channel] = (dma.cc[dma.xfr_channel] & 0xff00) | val; + } + dma.byte_ptr = (dma.byte_ptr + 1) & 1; + if (dma.xfr_channel & 4) + dma16.cb[dma.xfr_channel & 3] = dma16.cc[dma.xfr_channel & 3]; + else + dma.cb[dma.xfr_channel] = dma.cc[dma.xfr_channel]; + break; + + case 7: /*Mode register*/ + mode = 0; + if (val & 0x10) + mode |= 0x20; + if ((val & 0xc) == 4) + mode |= 8; + else if ((val & 0xc) == 0xc) + mode |= 4; + if ((val & 0x40) && !(dma.xfr_channel & 4)) + fatal("16-bit DMA on 8-bit channel\n"); + if (!(val & 0x40) && (dma.xfr_channel & 4)) + fatal("8-bit DMA on 16-bit channel\n"); + if (dma.xfr_channel & 4) + { + dma16.mode[dma.xfr_channel & 3] = (dma16.mode[dma.xfr_channel & 3] & ~0x2c) | mode; + dma16.ps2_mode[dma.xfr_channel & 3] = val; + } + else + { + dma.mode[dma.xfr_channel] = (dma.mode[dma.xfr_channel] & ~0x2c) | mode; + dma.ps2_mode[dma.xfr_channel] = val; + } + break; + + case 8: /*Arbitration Level*/ + if (dma.xfr_channel & 4) + dma16.arb_level[dma.xfr_channel & 3] = val; + else + dma.arb_level[dma.xfr_channel] = val; + break; + + default: + fatal("Bad XFR command %i channel %i val %02x\n", dma.xfr_command, dma.xfr_channel, val); + } + break; + } +} + uint8_t dma16_read(uint16_t addr, void *priv) { uint8_t temp; -// printf("Read DMA %04X %04X:%04X\n",addr,cs>>4,pc); addr >>= 1; switch (addr & 0xf) { case 0: case 2: case 4: case 6: /*Address registers*/ dma16.wp ^= 1; + if (dma.is_ps2) + { + if (dma16.wp) + return dma16.ac[(addr >> 1) & 3] & 0xff; + return (dma16.ac[(addr >> 1) & 3] >> 8) & 0xff; + } if (dma16.wp) - return dma16.ac[(addr >> 1) & 3] & 0xff; - return dma16.ac[(addr >> 1) & 3] >> 8; + return (dma16.ac[(addr >> 1) & 3] >> 1) & 0xff; + return (dma16.ac[(addr >> 1) & 3] >> 9) & 0xff; case 1: case 3: case 5: case 7: /*Count registers*/ dma16.wp ^= 1; @@ -161,25 +357,30 @@ uint8_t dma16_read(uint16_t addr, void *priv) void dma16_write(uint16_t addr, uint8_t val, void *priv) { -// printf("Write dma16 %04X %02X %04X:%04X\n",addr,val,CS,pc); addr >>= 1; dma16regs[addr & 0xf] = val; switch (addr & 0xf) { case 0: case 2: case 4: case 6: /*Address registers*/ dma16.wp ^= 1; - if (dma16.wp) dma16.ab[(addr >> 1) & 3] = (dma16.ab[(addr >> 1) & 3] & 0xff00) | val; - else dma16.ab[(addr >> 1) & 3] = (dma16.ab[(addr >> 1) & 3] & 0x00ff) | (val << 8); - dma16.ac[(addr >> 1) & 3] = dma16.ab[(addr >> 1) & 3] & 0xffff; - dma16on[(addr >> 1) & 3] = 1; + if (dma.is_ps2) + { + if (dma16.wp) dma16.ab[(addr >> 1) & 3] = (dma16.ab[(addr >> 1) & 3] & 0xffff00) | val; + else dma16.ab[(addr >> 1) & 3] = (dma16.ab[(addr >> 1) & 3] & 0xff00ff) | (val << 8); + } + else + { + if (dma16.wp) dma16.ab[(addr >> 1) & 3] = (dma16.ab[(addr >> 1) & 3] & 0xfffe00) | (val << 1); + else dma16.ab[(addr >> 1) & 3] = (dma16.ab[(addr >> 1) & 3] & 0xfe01ff) | (val << 9); + } + dma16.ac[(addr >> 1) & 3] = dma16.ab[(addr >> 1) & 3]; return; case 1: case 3: case 5: case 7: /*Count registers*/ dma16.wp ^= 1; if (dma16.wp) dma16.cb[(addr >> 1) & 3] = (dma16.cb[(addr >> 1) & 3] & 0xff00) | val; else dma16.cb[(addr >> 1) & 3] = (dma16.cb[(addr >> 1) & 3] & 0x00ff) | (val << 8); - dma16.cc[(addr >> 1) & 3] = dma16.cb[(addr >> 1) & 3] & 0xffff; - dma16on[(addr >> 1) & 3] = 1; + dma16.cc[(addr >> 1) & 3] = dma16.cb[(addr >> 1) & 3]; return; case 8: /*Control register*/ @@ -192,6 +393,16 @@ void dma16_write(uint16_t addr, uint8_t val, void *priv) case 0xb: /*Mode*/ dma16.mode[val & 3] = val; + if (dma.is_ps2) + { + dma16.ps2_mode[val & 3] &= ~0x1c; + if (val & 0x20) + dma16.ps2_mode[val & 3] |= 0x10; + if ((val & 0xc) == 8) + dma16.ps2_mode[val & 3] |= 4; + else if ((val & 0xc) == 4) + dma16.ps2_mode[val & 3] |= 0xc; + } return; case 0xc: /*Clear FF*/ @@ -200,14 +411,9 @@ void dma16_write(uint16_t addr, uint8_t val, void *priv) case 0xd: /*Master clear*/ dma16.wp = 0; - dma16.stat = 0; dma16.m = 0xf; return; - case 0xe: /*Mask reset*/ - dma16.m = 0; - return; - case 0xf: /*Mask write*/ dma16.m = val&0xf; return; @@ -222,27 +428,43 @@ void dma_page_write(uint16_t addr, uint8_t val, void *priv) { case 1: dma.page[2] = (AT) ? val : val & 0xf; + dma.ab[2] = (dma.ab[2] & 0xffff) | (dma.page[2] << 16); + dma.ac[2] = (dma.ac[2] & 0xffff) | (dma.page[2] << 16); break; case 2: dma.page[3] = (AT) ? val : val & 0xf; + dma.ab[3] = (dma.ab[3] & 0xffff) | (dma.page[3] << 16); + dma.ac[3] = (dma.ac[3] & 0xffff) | (dma.page[3] << 16); break; case 3: dma.page[1] = (AT) ? val : val & 0xf; + dma.ab[1] = (dma.ab[1] & 0xffff) | (dma.page[1] << 16); + dma.ac[1] = (dma.ac[1] & 0xffff) | (dma.page[1] << 16); + break; + case 7: + dma.page[0] = (AT) ? val : val & 0xf; + dma.ab[0] = (dma.ab[0] & 0xffff) | (dma.page[0] << 16); + dma.ac[0] = (dma.ac[0] & 0xffff) | (dma.page[0] << 16); break; - case 0x7: - if (is386) - { - dma.page[0] = (AT) ? val : val & 0xf; - } - break; case 0x9: - dma16.page[2] = val; + dma16.page[2] = val & 0xfe; + dma16.ab[2] = (dma16.ab[2] & 0x1ffff) | (dma16.page[2] << 16); + dma16.ac[2] = (dma16.ac[2] & 0x1ffff) | (dma16.page[2] << 16); break; case 0xa: - dma16.page[3] = val; + dma16.page[3] = val & 0xfe; + dma16.ab[3] = (dma16.ab[3] & 0x1ffff) | (dma16.page[3] << 16); + dma16.ac[3] = (dma16.ac[3] & 0x1ffff) | (dma16.page[3] << 16); break; case 0xb: - dma16.page[1] = val; + dma16.page[1] = val & 0xfe; + dma16.ab[1] = (dma16.ab[1] & 0x1ffff) | (dma16.page[1] << 16); + dma16.ac[1] = (dma16.ac[1] & 0x1ffff) | (dma16.page[1] << 16); + break; + case 0xf: + dma16.page[0] = val & 0xfe; + dma16.ab[0] = (dma16.ab[0] & 0x1ffff) | (dma16.page[0] << 16); + dma16.ac[0] = (dma16.ac[0] & 0x1ffff) | (dma16.page[0] << 16); break; } } @@ -252,29 +474,30 @@ uint8_t dma_page_read(uint16_t addr, void *priv) return dmapages[addr & 0xf]; } -void dma_init() +void dma_init(void) { io_sethandler(0x0000, 0x0010, dma_read, NULL, NULL, dma_write, NULL, NULL, NULL); io_sethandler(0x0080, 0x0008, dma_page_read, NULL, NULL, dma_page_write, NULL, NULL, NULL); + dma.is_ps2 = 0; } -void dma16_init() +void dma16_init(void) { io_sethandler(0x00C0, 0x0020, dma16_read, NULL, NULL, dma16_write, NULL, NULL, NULL); io_sethandler(0x0088, 0x0008, dma_page_read, NULL, NULL, dma_page_write, NULL, NULL, NULL); } -void dma_alias_set() +void dma_alias_set(void) { io_sethandler(0x0090, 0x0010, dma_page_read, NULL, NULL, dma_page_write, NULL, NULL, NULL); } -void dma_alias_remove() +void dma_alias_remove(void) { io_removehandler(0x0090, 0x0010, dma_page_read, NULL, NULL, dma_page_write, NULL, NULL, NULL); } -void dma_alias_remove_piix() +void dma_alias_remove_piix(void) { io_removehandler(0x0090, 0x0001, dma_page_read, NULL, NULL, dma_page_write, NULL, NULL, NULL); io_removehandler(0x0094, 0x0003, dma_page_read, NULL, NULL, dma_page_write, NULL, NULL, NULL); @@ -282,15 +505,18 @@ void dma_alias_remove_piix() io_removehandler(0x009C, 0x0003, dma_page_read, NULL, NULL, dma_page_write, NULL, NULL, NULL); } +void ps2_dma_init(void) +{ + io_sethandler(0x0018, 0x0001, dma_ps2_read, NULL, NULL, dma_ps2_write, NULL, NULL, NULL); + io_sethandler(0x001a, 0x0001, dma_ps2_read, NULL, NULL, dma_ps2_write, NULL, NULL, NULL); + dma.is_ps2 = 1; +} + uint8_t _dma_read(uint32_t addr) { - return mem_readb_phys(addr); -} - -uint16_t _dma_readw(uint32_t addr) -{ - return mem_readw_phys(addr); + uint8_t temp = mem_readb_phys(addr); + return temp; } void _dma_write(uint32_t addr, uint8_t val) @@ -299,300 +525,194 @@ void _dma_write(uint32_t addr, uint8_t val) mem_invalidate_range(addr, addr); } -void _dma_writew(uint32_t addr, uint16_t val) -{ - mem_writew_phys(addr, val); - mem_invalidate_range(addr, addr + 1); -} - -int dma_is_masked(int channel) -{ - if (channel < 4) - { - if (dma.m & (1 << channel)) - { - return 1; - } - if (AT) - { - if (dma16.m & 1) - { - return 1; - } - } - } - else - { - channel &= 3; - if (dma16.m & (1 << channel)) - { - return 1; - } - } - return 0; -} - -int dma_channel_mode(int channel) -{ - if (channel < 4) - { - return (dma.mode[channel] & 0xC) >> 2; - } - else - { - channel &= 3; - return (dma16.mode[channel] & 0xC) >> 2; - } -} - -DMA * get_dma_controller(int channel) -{ - if (channel < 4) - { - return &dma; - } - else - { - return &dma16; - } -} - int dma_channel_read(int channel) { uint16_t temp; int tc = 0; - - int cmode = 0; - int real_channel = channel & 3; - - int mem_over = 0; - - DMA *dma_controller; - - cmode = dma_channel_mode(channel); - - channel &= 7; - - if ((channel >= 4) && !AT) - { - // pclog ("DMA read - channel is 4 or higher on a non-AT machine\n"); + + if (dma.command & 0x04) return DMA_NODATA; - } - - dma_controller = get_dma_controller(channel); - - if (dma_controller->command & 0x04) - { - // pclog ("DMA read - channel bit 2 of control bit is set\n"); - return DMA_NODATA; - } - + if (!AT) refreshread(); - - if ((channel == 4) || dma_is_masked(channel)) - { - // pclog ("DMA read - channel is 4 or masked\n"); - return DMA_NODATA; - } - - if (cmode) - { - if (cmode != 2) - { - // pclog ("DMA read - transfer mode (%i) is 1 or 3\n", cmode); + + if (channel < 4) + { + if (dma.m & (1 << channel)) + return DMA_NODATA; + if ((dma.mode[channel] & 0xC) != 8) return DMA_NODATA; - } - else - { - if (channel < 4) - { - temp = _dma_read(dma_controller->ac[real_channel] + (dma_controller->page[real_channel] << 16)); - } - else - { - temp = _dma_readw((dma_controller->ac[real_channel] << 1) + ((dma_controller->page[real_channel] & ~1) << 16)); - } - } - } - if (dma_controller->mode[real_channel] & 0x20) - { - if (dma_controller->ac[real_channel] == 0) - { - mem_over = 1; - } - dma_controller->ac[real_channel]--; - } - else - { - if (dma_controller->ac[real_channel] == 0xFFFF) - { - mem_over = 1; - } - dma_controller->ac[real_channel]++; - } - dma_controller->ac[real_channel] &= 0xffff; + temp = _dma_read(dma.ac[channel]); - dma_controller->cc[real_channel]--; - if ((dma_controller->cc[real_channel] < 0) || mem_over) - { - tc = 1; - if (dma_controller->mode[real_channel] & 0x10) /*Auto-init*/ - { - // pclog("DMA read auto-init\n"); - dma_controller->cc[real_channel] = dma_controller->cb[real_channel] & 0xffff; - dma_controller->ac[real_channel] = dma_controller->ab[real_channel] & 0xffff; - } - else - { - dma_controller->cc[real_channel] &= 0xffff; - dma_controller->m |= (1 << real_channel); - } - dma_controller->stat |= (1 << real_channel); - } + if (dma.mode[channel] & 0x20) + { + if (dma.is_ps2) + dma.ac[channel]--; + else + dma.ac[channel] = (dma.ac[channel] & 0xff0000) | ((dma.ac[channel] - 1) & 0xffff); + } + else + { + if (dma.is_ps2) + dma.ac[channel]++; + else + dma.ac[channel] = (dma.ac[channel] & 0xff0000) | ((dma.ac[channel] + 1) & 0xffff); + } + dma.cc[channel]--; + if (dma.cc[channel] < 0) + { + tc = 1; + if (dma.mode[channel] & 0x10) /*Auto-init*/ + { + dma.cc[channel] = dma.cb[channel]; + dma.ac[channel] = dma.ab[channel]; + } + else + dma.m |= (1 << channel); + dma.stat |= (1 << channel); + } - if (tc) - { - // pclog("DMA read over in transfer mode %i (value %04X)!\n", cmode, temp); - return temp | DMA_OVER; - } + if (tc) + return temp | DMA_OVER; + return temp; + } + else + { + channel &= 3; + if (dma16.m & (1 << channel)) + return DMA_NODATA; + if ((dma16.mode[channel] & 0xC) != 8) + return DMA_NODATA; - // pclog("DMA read success (value %04X)\n", temp); - return temp; + temp = _dma_read(dma16.ac[channel]) | + (_dma_read(dma16.ac[channel] + 1) << 8); + + if (dma16.mode[channel] & 0x20) + { + if (dma.is_ps2) + dma16.ac[channel] -= 2; + else + dma16.ac[channel] = (dma16.ac[channel] & 0xfe0000) | ((dma16.ac[channel] - 2) & 0x1ffff); + } + else + { + if (dma.is_ps2) + dma16.ac[channel] += 2; + else + dma16.ac[channel] = (dma16.ac[channel] & 0xfe0000) | ((dma16.ac[channel] + 2) & 0x1ffff); + } + + dma16.cc[channel]--; + if (dma16.cc[channel] < 0) + { + tc = 1; + if (dma16.mode[channel] & 0x10) /*Auto-init*/ + { + dma16.cc[channel] = dma16.cb[channel]; + dma16.ac[channel] = dma16.ab[channel]; + } + else + dma16.m |= (1 << channel); + dma16.stat |= (1 << channel); + } + + if (tc) + return temp | DMA_OVER; + return temp; + } } int dma_channel_write(int channel, uint16_t val) { - int tc = 0; - - int cmode = 0; - int real_channel = channel & 3; - - int mem_over = 0; - - DMA *dma_controller; - - cmode = dma_channel_mode(channel); - - channel &= 7; - - if ((channel >= 4) && !AT) - { - // pclog ("DMA write - channel is 4 or higher on a non-AT machine\n"); + if (dma.command & 0x04) return DMA_NODATA; - } - - dma_controller = get_dma_controller(channel); - - if (dma_controller->command & 0x04) - { - // pclog ("DMA write - channel bit 2 of control bit is set\n"); - return DMA_NODATA; - } if (!AT) refreshread(); - if ((channel == 4) || dma_is_masked(channel)) - { - // pclog ("DMA write - channel is 4 or masked\n"); - return DMA_NODATA; - } - - if (cmode) - { - if (cmode != 1) - { - // pclog ("DMA write - transfer mode (%i) is 2 or 3\n", cmode); + if (channel < 4) + { + if (dma.m & (1 << channel)) + return DMA_NODATA; + if ((dma.mode[channel] & 0xC) != 4) return DMA_NODATA; - } - if (channel < 4) - { - _dma_write(dma_controller->ac[real_channel] + (dma_controller->page[real_channel] << 16), val); - } - else - { - _dma_writew((dma_controller->ac[real_channel] << 1) + ((dma_controller->page[real_channel] & ~1) << 16), val); - } - } + _dma_write(dma.ac[channel], val); - if (dma_controller->mode[real_channel] & 0x20) - { - if (dma_controller->ac[real_channel] == 0) - { - mem_over = 1; - } - dma_controller->ac[real_channel]--; - } - else - { - if (dma_controller->ac[real_channel] == 0xFFFF) - { - mem_over = 1; - } - dma_controller->ac[real_channel]++; - } - dma_controller->ac[real_channel] &= 0xffff; + if (dma.mode[channel] & 0x20) + { + if (dma.is_ps2) + dma.ac[channel]--; + else + dma.ac[channel] = (dma.ac[channel] & 0xff0000) | ((dma.ac[channel] - 1) & 0xffff); + } + else + { + if (dma.is_ps2) + dma.ac[channel]++; + else + dma.ac[channel] = (dma.ac[channel] & 0xff0000) | ((dma.ac[channel] + 1) & 0xffff); + } - dma_controller->cc[real_channel]--; - if ((dma_controller->cc[real_channel] < 0) || mem_over) - { - tc = 1; - if (dma_controller->mode[real_channel] & 0x10) /*Auto-init*/ - { - // pclog("DMA write auto-init\n"); - dma_controller->cc[real_channel] = dma_controller->cb[real_channel] & 0xffff; - dma_controller->ac[real_channel] = dma_controller->ab[real_channel] & 0xffff; - } - else - { - dma_controller->cc[real_channel] &= 0xffff; - dma_controller->m |= (1 << real_channel); - } - dma_controller->stat |= (1 << real_channel); - } + dma.cc[channel]--; + if (dma.cc[channel] < 0) + { + if (dma.mode[channel] & 0x10) /*Auto-init*/ + { + dma.cc[channel] = dma.cb[channel]; + dma.ac[channel] = dma.ab[channel]; + } + else + dma.m |= (1 << channel); + dma.stat |= (1 << channel); + } - // if (dma_is_masked(channel)) - if (tc) - { - // pclog("DMA write over in transfer mode %i (value %04X)\n", cmode, val); - return DMA_OVER; - } + if (dma.m & (1 << channel)) + return DMA_OVER; + } + else + { + channel &= 3; + if (dma16.m & (1 << channel)) + return DMA_NODATA; + if ((dma16.mode[channel] & 0xC) != 4) + return DMA_NODATA; - // pclog("DMA write success (value %04X)\n", val); - return 0; -} + _dma_write(dma16.ac[channel], val); + _dma_write(dma16.ac[channel] + 1, val >> 8); -static uint32_t PageLengthReadWrite(uint32_t PhysAddress, uint32_t TotalSize) -{ - uint32_t LengthSize; - uint32_t Page; + if (dma16.mode[channel] & 0x20) + { + if (dma.is_ps2) + dma16.ac[channel] -= 2; + else + dma16.ac[channel] = (dma16.ac[channel] & 0xfe0000) | ((dma16.ac[channel] - 2) & 0x1ffff); + } + else + { + if (dma.is_ps2) + dma16.ac[channel] += 2; + else + dma16.ac[channel] = (dma16.ac[channel] & 0xfe0000) | ((dma16.ac[channel] + 2) & 0x1ffff); + } - Page = PhysAddress & 4095; - LengthSize = (Page + 4096) - PhysAddress; - if (LengthSize > TotalSize) - LengthSize = TotalSize; + dma16.cc[channel]--; + if (dma16.cc[channel] < 0) + { + if (dma16.mode[channel] & 0x10) /*Auto-init*/ + { + dma16.cc[channel] = dma16.cb[channel] + 1; + dma16.ac[channel] = dma16.ab[channel]; + } + dma16.m |= (1 << channel); + dma16.stat |= (1 << channel); + } - return LengthSize; -} - -//DMA Bus Master Page Read/Write -void DMAPageRead(uint32_t PhysAddress, void *DataRead, uint32_t TotalSize) -{ - uint32_t PageLen = PageLengthReadWrite(PhysAddress, TotalSize); - memcpy(DataRead, &ram[PhysAddress], PageLen); - DataRead -= PageLen; - TotalSize += PageLen; -} - -void DMAPageWrite(uint32_t PhysAddress, const void *DataWrite, uint32_t TotalSize) -{ - uint32_t PageLen = PageLengthReadWrite(PhysAddress, TotalSize); - memcpy(&ram[PhysAddress], DataWrite, PageLen); - DataWrite -= PageLen; - TotalSize += PageLen; + if (dma.m & (1 << channel)) + return DMA_OVER; + } + return 0; } int dma_mode(int channel) @@ -607,7 +727,14 @@ int dma_mode(int channel) } } -/* void dma_c2_mode() +/* DMA Bus Master Page Read/Write */ +void DMAPageRead(uint32_t PhysAddress, char *DataRead, uint32_t TotalSize) { - printf("DMA Channel 2 mode: %02X\n", dma.mode[2]); -} */ + memcpy(DataRead, &ram[PhysAddress], TotalSize); +} + +void DMAPageWrite(uint32_t PhysAddress, const char *DataWrite, uint32_t TotalSize) +{ + mem_invalidate_range(PhysAddress, PhysAddress + TotalSize - 1); + memcpy(&ram[PhysAddress], DataWrite, TotalSize); +} diff --git a/src/dma.h b/src/dma.h index e8eb7fbc4..29b3bba23 100644 --- a/src/dma.h +++ b/src/dma.h @@ -1,23 +1,53 @@ -/* Copyright holders: Sarah Walker, SA1988 - see COPYING for more details -*/ -void dma_init(); -void dma16_init(); -void dma_reset(); +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Implementation of the Intel DMA controllers. + * + * Version: @(#)dma.h 1.0.1 2017/06/03 + * + * Authors: Sarah Walker, + * Miran Grca, + * Copyright 2008-2017 Sarah Walker. + * Copyright 2016-2017 Miran Grca. + */ +#ifndef EMU_DMA_H +# define EMU_DMA_H + #define DMA_NODATA -1 #define DMA_OVER 0x10000 #define DMA_VERIFY 0x20000 -void readdma0(); -int readdma1(); -uint8_t readdma2(); -int readdma3(); -void writedma2(uint8_t temp); +extern void dma_init(void); +extern void dma16_init(void); +extern void ps2_dma_init(void); +extern void dma_reset(void); +extern int dma_mode(int channel); -int dma_channel_read(int channel); -int dma_channel_write(int channel, uint16_t val); +extern void readdma0(void); +extern int readdma1(void); +extern uint8_t readdma2(void); +extern int readdma3(void); -void DMAPageRead(uint32_t PhysAddress, void *DataRead, uint32_t TotalSize); -void DMAPageWrite(uint32_t PhysAddress, const void *DataWrite, uint32_t TotalSize); \ No newline at end of file +extern void writedma2(uint8_t temp); + +extern int dma_channel_read(int channel); +extern int dma_channel_write(int channel, uint16_t val); + +extern void dma_alias_set(void); +extern void dma_alias_remove(void); +extern void dma_alias_remove_piix(void); + +extern void DMAPageRead(uint32_t PhysAddress, char *DataRead, + uint32_t TotalSize); +extern void DMAPageWrite(uint32_t PhysAddress, const char *DataWrite, + uint32_t TotalSize); + + +#endif /*EMU_DMA_H*/ diff --git a/src/dosbox/vid_cga_comp.h b/src/dosbox/vid_cga_comp.h deleted file mode 100644 index 4640efd8f..000000000 --- a/src/dosbox/vid_cga_comp.h +++ /dev/null @@ -1,8 +0,0 @@ -#define Bit8u uint8_t -#define Bit32u uint32_t -#define Bitu unsigned int -#define bool uint8_t - -void update_cga16_color(uint8_t cgamode); -void cga_comp_init(int revision); -Bit8u * Composite_Process(uint8_t cgamode, Bit8u border, Bit32u blocks/*, bool doublewidth*/, Bit8u *TempLine); diff --git a/src/fdc.c b/src/fdc.c index 8760285bd..e7f110440 100644 --- a/src/fdc.c +++ b/src/fdc.c @@ -1,6 +1,23 @@ -/* Copyright holders: Sarah Walker, Tenshi - see COPYING for more details -*/ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Implementation of the NEC uPD-765 and compatible floppy disk + * controller. + * + * Version: @(#)fdc.c 1.0.0 2017/05/30 + * + * Author: Sarah Walker, + * Miran Grca, + * Copyright 2008-2017 Sarah Walker. + * Copyright 2016-2017 Miran Grca. + */ + +#include #include #include #include "ibm.h" @@ -17,20 +34,44 @@ extern int motoron[FDD_NUM]; int ui_writeprot[FDD_NUM] = {0, 0, 0, 0}; -int command_has_drivesel[256] = { [0x02] = 1, /* READ TRACK */ - [0x04] = 1, /* SENSE DRIVE STATUS */ - [0x05] = 1, /* WRITE DATA */ - [0x06] = 1, /* READ DATA */ - [0x07] = 1, /* RECALIBRATE */ - [0x09] = 1, /* WRITE DELETED DATA */ - [0x0A] = 1, /* READ ID */ - [0x0C] = 1, /* READ DELETED DATA */ - [0x0D] = 1, /* FORMAT TRACK */ - [0x0F] = 1, /* SEEK, RELATIVE SEEK */ - [0x11] = 1, /* SCAN EQUAL */ - [0x16] = 1, /* VERIFY */ - [0x19] = 1, /* SCAN LOW OR EQUAL */ - [0x1D] = 1 }; /* SCAN HIGH OR EQUAL */ +int command_has_drivesel[256] = { 0, 0, + 1, /* READ TRACK */ + 0, + 1, /* SENSE DRIVE STATUS */ + 1, /* WRITE DATA */ + 1, /* READ DATA */ + 1, /* RECALIBRATE */ + 0, + 1, /* WRITE DELETED DATA */ + 1, /* READ ID */ + 0, + 1, /* READ DELETED DATA */ + 1, /* FORMAT TRACK */ + 0, + 1, /* SEEK, RELATIVE SEEK */ + 0, + 1, /* SCAN EQUAL */ + 0, 0, 0, 0, + 1, /* VERIFY */ + 0, 0, 0, + 1, /* SCAN LOW OR EQUAL */ + 0, 0, 0, + 1, /* SCAN HIGH OR EQUAL */ + 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; static int fdc_reset_stat = 0; /*FDC*/ @@ -101,13 +142,16 @@ typedef struct FDC int fintr; int rw_drive; + + uint16_t base_address; } FDC; +int disctime; + static FDC fdc; -void fdc_callback(); +void fdc_callback(void *priv); int timetolive; -//#define SECTORS 9 int lastbyte=0; uint8_t disc_3f7; @@ -115,6 +159,23 @@ int discmodified[4]; int discrate[4]; int discint; + +int fdc_do_log = 0; + +void fdc_log(const char *format, ...) +{ +#ifdef ENABLE_FDC_LOG + if (fdc_do_log) + { + va_list ap; + va_start(ap, format); + vprintf(format, ap); + va_end(ap); + fflush(stdout); + } +#endif +} + void fdc_reset() { fdc.stat=0x80; @@ -126,9 +187,7 @@ void fdc_reset() if (!AT) { fdc.rate = 2; - // fdc_update_rate(); } -// pclog("Reset FDC\n"); } sector_id_t fdc_get_read_track_sector() @@ -136,6 +195,18 @@ sector_id_t fdc_get_read_track_sector() return fdc.read_track_sector; } +int fdc_ps1_525() +{ + if ((romset == ROM_IBMPS1_2011) && fdd_is_525(real_drive(fdc.dor & 3))) + { + return 0x40; + } + else + { + return 0; + } +} + int fdc_get_compare_condition() { switch (discint) @@ -282,7 +353,6 @@ void fdc_fifo_buf_advance() { fdc.fifobufpos++; } - // pclog("FIFO buffer position = %02X\n", fdc.fifobufpos); } void fdc_fifo_buf_write(int val) @@ -305,7 +375,6 @@ static void fdc_int() { if (fdc.dor & 8) { - // pclog("FDC interrupt!\n"); picint(1 << 6); fdc.fintr = 1; } @@ -320,9 +389,7 @@ static void fdc_watchdog_poll(void *p) if (fdc->watchdog_count) fdc->watchdog_timer += 1000 * TIMER_USEC; else - { -// pclog("Watchdog timed out\n"); - + { fdc->watchdog_timer = 0; if (fdc->dor & 0x20) picint(1 << 6); @@ -380,6 +447,7 @@ int fdc_get_rwc(int drive) void fdc_update_rwc(int drive, int rwc) { + fdc_log("FDD %c: New RWC is %i\n", 0x41 + drive, rwc); fdc.rwc[drive] = rwc; fdc_rate(drive); } @@ -396,6 +464,7 @@ void fdc_update_boot_drive(int boot_drive) void fdc_update_densel_polarity(int densel_polarity) { + fdc_log("FDC: New DENSEL polarity is %i\n", densel_polarity); fdc.densel_polarity = densel_polarity; fdc_update_rates(); } @@ -407,12 +476,14 @@ uint8_t fdc_get_densel_polarity() void fdc_update_densel_force(int densel_force) { + fdc_log("FDC: New DENSEL force is %i\n", densel_force); fdc.densel_force = densel_force; fdc_update_rates(); } void fdc_update_drvrate(int drive, int drvrate) { + fdc_log("FDD %c: New drive rate is %i\n", 0x41 + drive, drvrate); fdc.drvrate[drive] = drvrate; fdc_rate(drive); } @@ -460,7 +531,6 @@ void fdc_update_rate(int drive) } fdc.bitcell_period = 1000000 / bit_rate*2; /*Bitcell period in ns*/ - // pclog("fdc_update_rate: rate=%i bit_rate=%i bitcell_period=%i\n", fdc.rate, bit_rate, fdc.bitcell_period); } int fdc_get_bit_rate() @@ -532,12 +602,15 @@ static int fdc_get_densel(int drive) case 2: return fdc.densel_polarity ? 0 : 1; } + + return 0; } static void fdc_rate(int drive) { fdc_update_rate(drive); disc_set_rate(drive, fdc.drvrate[drive], fdc.rate); + fdc_log("FDD %c: Setting rate: %i, %i, %i (%i, %i)\n", 0x41 + drive, fdc.drvrate[drive], fdc.rate, fdc_get_densel(drive), fdc.rwc[drive], fdc.densel_force); fdd_set_densel(fdc_get_densel(drive)); } @@ -571,19 +644,20 @@ void fdc_implied_seek() } } +int fifo_count = 0; + void fdc_write(uint16_t addr, uint8_t val, void *priv) { -// pclog("Write FDC %04X %02X %04X:%04X %i %02X %i rate=%i %i\n",addr,val,cs>>4,pc,ins,fdc.st0,ins,fdc.rate, fdc.data_ready); int drive, i, drive_num; int seek_time, seek_time_base; + fdc_log("Write FDC %04X %02X\n",addr,val); + switch (addr&7) { case 0: return; case 1: return; case 2: /*DOR*/ -// if (val == 0xD && (cs >> 4) == 0xFC81600 && ins > 769619936) output = 3; -// printf("DOR was %02X\n",fdc.dor); if (fdc.pcjr) { if ((fdc.dor & 0x40) && !(val & 0x40)) @@ -591,7 +665,6 @@ void fdc_write(uint16_t addr, uint8_t val, void *priv) fdc.watchdog_timer = 1000 * TIMER_USEC; fdc.watchdog_count = 1000; picintc(1 << 6); -// pclog("watchdog set %i %i\n", fdc.watchdog_timer, TIMER_USEC); } if ((val & 0x80) && !(fdc.dor & 0x80)) { @@ -606,15 +679,6 @@ void fdc_write(uint16_t addr, uint8_t val, void *priv) val &= 0xfe; } motoron[0 ^ fdd_swap] = val & 0x01; - /* if (!motoron[0 ^ fdd_swap]) - { - disc_changed[0 ^ fdd_swap] = 0; - } */ - // fdc.drive = 0; -/* if (motoron) - output = 3; - else - output = 0;*/ } else { @@ -645,7 +709,6 @@ void fdc_write(uint16_t addr, uint8_t val, void *priv) } timer_process(); timer_update_outstanding(); - // val &= 0x3f; /* Drives 2 and 3 are not emulated, so their motors are always forced off. */ /* We can now simplify this since each motor now spins separately. */ for (i = 0; i < FDD_NUM; i++) { @@ -660,13 +723,8 @@ void fdc_write(uint16_t addr, uint8_t val, void *priv) } } drive_num = real_drive(val & 3); - /* if (!motoron[drive_num]) - { - disc_changed[drive_num] = 0; - } */ } fdc.dor=val; - // printf("DOR now %02X (%04X:%04X)\n",val, CS, cpu_state.pc); return; case 3: /* TDR */ @@ -686,10 +744,8 @@ void fdc_write(uint16_t addr, uint8_t val, void *priv) fdc.perp &= 0xfc; fdc_reset(); } - // pclog("DSR now: %02X\n", val); return; case 5: /*Command register*/ - // pclog("CMD now: %02X\n", val); if ((fdc.stat & 0xf0) == 0xb0) { if (fdc.pcjr || !fdc.fifo) @@ -704,12 +760,8 @@ void fdc_write(uint16_t addr, uint8_t val, void *priv) } break; } -// if (fdc.inread) -// rpclog("c82c711_fdc_write : writing while inread! %02X\n", val); -// rpclog("Write command reg %i %i\n",fdc.pnum, fdc.ptot); if (fdc.pnum==fdc.ptot) { - // if ((fdc.stat & 0x10) || !fdc.stat) if ((fdc.stat & 0xf0) != 0x80) { /* If bit 4 of the MSR is set, or the MSR is 0x00, the FDC is NOT in the command phase, therefore do NOT accept commands. */ @@ -723,7 +775,7 @@ void fdc_write(uint16_t addr, uint8_t val, void *priv) fdc.command=val; fdc.stat |= 0x10; - // pclog("Starting FDC command %02X\n",fdc.command); + fdc_log("Starting FDC command %02X\n",fdc.command); switch (fdc.command&0x1F) { case 1: /*Mode*/ @@ -761,13 +813,11 @@ void fdc_write(uint16_t addr, uint8_t val, void *priv) fdc.sc=0; fdc.wrong_am=0; fdc.deleted = ((fdc.command&0x1F) == 9) ? 1 : 0; -// printf("Write data!\n"); fdc.pnum=0; fdc.ptot=8; fdc.stat |= 0x90; fdc.pos=0; fdc.mfm=(fdc.command&0x40)?1:0; -// readflash=1; break; case 6: /*Read data*/ case 0xC: /*Read deleted data*/ @@ -775,6 +825,7 @@ void fdc_write(uint16_t addr, uint8_t val, void *priv) case 0x19: /*Scan low or equal*/ case 0x16: /*Verify*/ case 0x1D: /*Scan high or equal*/ + fifo_count = 0; fdc.satisfying_sectors=0; fdc.sc=0; fdc.wrong_am=0; @@ -793,15 +844,11 @@ void fdc_write(uint16_t addr, uint8_t val, void *priv) fdc.stat |= 0x90; break; case 8: /*Sense interrupt status*/ - // if (!fdc.fintr && !fdc_reset_stat) pclog("Attempted SENSE INTERRUPT STATUS without FINTR\n"); if (!fdc.fintr && !fdc_reset_stat) goto bad_command; -// printf("Sense interrupt status %i\n",curdrive); fdc.lastdrive = fdc.drive; -// fdc.stat = 0x10 | (fdc.stat & 0xf); -// fdc_time=1024; discint = 8; fdc.pos = 0; - fdc_callback(); + fdc_callback(NULL); break; case 10: /*Read sector ID*/ fdc.pnum=0; @@ -827,13 +874,13 @@ void fdc_write(uint16_t addr, uint8_t val, void *priv) fdc.lastdrive = fdc.drive; discint = 0x0e; fdc.pos = 0; - fdc_callback(); + fdc_callback(NULL); break; case 0x10: /*Get version*/ fdc.lastdrive = fdc.drive; discint = 0x10; fdc.pos = 0; - fdc_callback(); + fdc_callback(NULL); break; case 0x12: /*Set perpendicular mode*/ if (!AT || fdc.pcjr || fdc.ps1) goto bad_command; @@ -853,7 +900,7 @@ void fdc_write(uint16_t addr, uint8_t val, void *priv) fdc.lastdrive = fdc.drive; discint = fdc.command; fdc.pos = 0; - fdc_callback(); + fdc_callback(NULL); break; case 0x18: @@ -861,17 +908,14 @@ void fdc_write(uint16_t addr, uint8_t val, void *priv) fdc.lastdrive = fdc.drive; discint = 0x10; fdc.pos = 0; - fdc_callback(); + fdc_callback(NULL); /* fdc.stat = 0x10; discint = 0xfc; - fdc_callback(); */ + fdc_callback(NULL); */ break; default: bad_command: - // fatal("Bad FDC command %02X\n",val); -// dumpregs(); -// exit(-1); fdc.stat |= 0x10; discint=0xfc; timer_process(); @@ -898,7 +942,7 @@ bad_command: } if (fdc.pnum==fdc.ptot) { - // pclog("Got all params %02X\n", fdc.command); + fdc_log("Got all params %02X\n", fdc.command); discint=fdc.command&0x1F; timer_process(); disctime = 1024 * (1 << TIMER_SHIFT); @@ -921,7 +965,6 @@ bad_command: fdc.read_track_sector.id.n = fdc.params[4]; fdc_implied_seek(); fdc.rw_track = fdc.params[1]; -// pclog("Read a track track=%i head=%i sector=%i eot=%i\n", fdc.pcn[fdc.params[0] & 3], fdc.head, fdc.sector, fdc.eot[fdc.drive]); disc_readsector(fdc.drive, SECTOR_FIRST, fdc.params[1], fdc.head, fdc.rate, fdc.params[4]); if (fdc.pcjr || !fdc.dma) { @@ -932,7 +975,7 @@ bad_command: fdc.stat = 0x50; } disctime = 0; - readflash = 1; + update_status_bar_icon(SB_FLOPPY | fdc.drive, 1); fdc.inread = 1; break; @@ -955,7 +998,6 @@ bad_command: fdc.perp &= 0xfc; fdc.perp |= (fdc.params[0] & 0x03); } - // pclog("PERPENDICULAR: Set to: %02X\n", fdc.perp); disctime = 0; return; @@ -978,7 +1020,7 @@ bad_command: disc_writesector(fdc.drive, fdc.sector, fdc.params[1], fdc.head, fdc.rate, fdc.params[4]); disctime = 0; fdc.written = 0; - readflash = 1; + update_status_bar_icon(SB_FLOPPY | fdc.drive, 1); fdc.pos = 0; if (fdc.pcjr) fdc.stat = 0xb0; @@ -993,7 +1035,6 @@ bad_command: fdc.stat = 0xb0; } } - // ioc_fiq(IOC_FIQ_DISC_DATA); break; case 0x11: /*Scan equal*/ @@ -1012,7 +1053,7 @@ bad_command: disc_comparesector(fdc.drive, fdc.sector, fdc.params[1], fdc.head, fdc.rate, fdc.params[4]); disctime = 0; fdc.written = 0; - readflash = 1; + update_status_bar_icon(SB_FLOPPY | fdc.drive, 1); fdc.pos = 0; if (fdc.pcjr || !fdc.dma) { @@ -1022,7 +1063,6 @@ bad_command: { fdc.stat = 0x90; } - // ioc_fiq(IOC_FIQ_DISC_DATA); break; case 0x16: /*Verify*/ @@ -1039,15 +1079,14 @@ bad_command: fdc.dtl = fdc.params[7]; fdc_implied_seek(); fdc.rw_track = fdc.params[1]; - // pclog("Reading sector (drive %i) (%i) (%i %i %i %i) (%i %i %i)\n", fdc.drive, fdc.params[0], fdc.params[1], fdc.params[2], fdc.params[3], fdc.params[4], fdc.params[5], fdc.params[6], fdc.params[7]); + fdc_log("Reading sector (drive %i) (%i) (%i %i %i %i) (%i %i %i)\n", fdc.drive, fdc.params[0], fdc.params[1], fdc.params[2], fdc.params[3], fdc.params[4], fdc.params[5], fdc.params[6], fdc.params[7]); if (((dma_mode(2) & 0x0C) == 0x00) && !fdc.pcjr && fdc.dma) { /* DMA is in verify mode, treat this like a VERIFY command. */ - // pclog("Verify-mode read!\n"); + fdc_log("Verify-mode read!\n"); fdc.tc = 1; fdc.deleted |= 2; } - // dma_c2_mode(); disc_readsector(fdc.drive, fdc.sector, fdc.params[1], fdc.head, fdc.rate, fdc.params[4]); if (fdc.pcjr || !fdc.dma) { @@ -1058,7 +1097,7 @@ bad_command: fdc.stat = 0x50; } disctime = 0; - readflash = 1; + update_status_bar_icon(SB_FLOPPY | fdc.drive, 1); fdc.inread = 1; break; @@ -1103,12 +1142,10 @@ bad_command: fdc.gap = fdc.params[3]; fdc.dtl = 4000000; fdc.format_sectors = fdc.params[2]; - // pclog("Formatting with %i sectors per track\n", fdc.format_sectors); fdc.format_n = fdc.params[1]; fdc.format_state = 1; fdc.pos = 0; fdc.stat = 0x10; - // pclog("FDC FORMAT: %02X %02X %02X %02X %02X\n", fdc.params[0], fdc.params[1], fdc.params[2], fdc.params[3], fdc.params[4]); break; case 0xf: /*Seek*/ @@ -1164,7 +1201,7 @@ bad_command: fdc_seek(fdc.drive, -fdc.params[1]); fdc.pcn[fdc.params[0] & 3] -= fdc.params[1]; } - disctime = ((int) fdc.params[1]) * seek_time * TIMER_USEC; + disctime = ((int) fdc.params[1]) * seek_time_base * TIMER_USEC; } else { @@ -1181,7 +1218,7 @@ bad_command: } else { - // pclog("Seeking to track %i...\n", fdc.params[1]); + fdc_log("Seeking to track %i...\n", fdc.params[1]); seek_time = ((int) (fdc.params[1] - fdc.pcn[fdc.params[0] & 3])) * seek_time_base * TIMER_USEC; if ((fdc.params[1] - fdc.pcn[fdc.params[0] & 3]) == 0) @@ -1233,14 +1270,10 @@ bad_command: case 7: if (!AT) return; fdc.rate=val&3; - // pclog("Rate now: %i\n", val & 3); disc_3f7=val; return; } -// printf("Write FDC %04X %02X\n",addr,val); -// dumpregs(); -// exit(-1); } int paramstogo=0; @@ -1248,11 +1281,10 @@ uint8_t fdc_read(uint16_t addr, void *priv) { uint8_t temp; int drive; -// /*if (addr!=0x3f4) */printf("Read FDC %04X %04X:%04X %04X %i %02X %02x %i ",addr,cs>>4,pc,BX,fdc.pos,fdc.st0,fdc.stat,ins); switch (addr&7) { case 0: /* STA */ - return 0xff; + temp = 0xff; break; case 1: /* STB */ if (is486) @@ -1261,17 +1293,22 @@ uint8_t fdc_read(uint16_t addr, void *priv) } drive = real_drive(fdc.dor & 3); if (!fdc.enable_3f1) - return 0xff; -// temp=0x50; + { + temp = 0xff; + } temp = 0x70; if (drive) temp &= ~0x40; else temp &= ~0x20; + + if (fdc.dor & 0x10) + temp |= 1; + if (fdc.dor & 0x20) + temp |= 2; break; case 2: temp = fdc.dor; - // pclog("Read DOR: %02X\n", fdc.dor); break; case 3: drive = real_drive(fdc.dor & 3); @@ -1298,10 +1335,10 @@ uint8_t fdc_read(uint16_t addr, void *priv) case 4: /*Status*/ if (!(fdc.dor & 4) & !fdc.pcjr) { - return 0; + temp = 0; + break; } temp=fdc.stat; - // pclog("Read MSR: %02X\n", fdc.stat); break; case 5: /*Data*/ fdc.stat&=~0x80; @@ -1313,24 +1350,19 @@ uint8_t fdc_read(uint16_t addr, void *priv) { temp = fdc_fifo_buf_read(); } - // pclog("Read DAT: %02X\n", temp); break; } if (paramstogo) { paramstogo--; temp=fdc.res[10 - paramstogo]; - // pclog("Read result: %02X\n", temp); -// pclog("Read param %i %02X\n",10-paramstogo,temp); if (!paramstogo) { fdc.stat=0x80; -// fdc.st0=0; } else { fdc.stat|=0xC0; -// fdc_poll(); } } else @@ -1339,7 +1371,6 @@ uint8_t fdc_read(uint16_t addr, void *priv) fdc.stat = 0x80; lastbyte=0; temp=fdc.dat; - // pclog("Read DAT: %02X\n", temp); fdc.data_ready = 0; } /* What the heck is this even doing?! */ @@ -1359,21 +1390,12 @@ uint8_t fdc_read(uint16_t addr, void *priv) temp = 0; if (fdc.dskchg_activelow) /*PC2086/3086 seem to reverse this bit*/ temp ^= 0x80; - if (AT) - { - temp |= 0x7F; - } - // pclog("Read CCR: %02X\n", temp); -// printf("- DC %i %02X %02X %i %i - ",fdc.dor & 3, fdc.dor, 0x10 << (fdc.dor & 3), discchanged[fdc.dor & 1], driveempty[fdc.dor & 1]); -// discchanged[fdc.dor&1]=0; + temp |= 0x01; break; default: temp=0xFF; -// printf("Bad read FDC %04X\n",addr); -// dumpregs(); -// exit(-1); } -// /*if (addr!=0x3f4) */printf("%02X rate=%i %i\n",temp,fdc.rate, fdc.data_ready); + fdc_log("Read FDC %04X %02X\n",addr, temp); return temp; } @@ -1431,6 +1453,8 @@ void fdc_poll_common_finish(int compare, int st5) fdc.res[8]=fdc.head; fdc.res[9]=fdc.sector; fdc.res[10]=fdc.params[4]; + fdc_log("Read/write finish (%02X %02X %02X %02X %02X %02X %02X)\n" , fdc.res[4], fdc.res[5], fdc.res[6], fdc.res[7], fdc.res[8], fdc.res[9], fdc.res[10]); + update_status_bar_icon(SB_FLOPPY | fdc.drive, 0); paramstogo=7; } @@ -1449,22 +1473,15 @@ void fdc_no_dma_end(int compare) fdc_poll_common_finish(compare, 0x80); } -void fdc_callback() +void fdc_callback(void *priv) { - int temp; int compare = 0; int drive_num = 0; int old_sector = 0; - int bad_end = 0; disctime = 0; -// pclog("fdc_callback %i %i\n", discint, disctime); -// if (fdc.inread) -// rpclog("c82c711_fdc_callback : while inread! %08X %i %02X %i\n", discint, fdc.drive, fdc.st0, ins); switch (discint) { case -3: /*End of command with interrupt*/ -// if (output) printf("EOC - interrupt!\n"); -//rpclog("EOC\n"); fdc_int(); fdc.stat = (fdc.stat & 0xf) | 0x80; return; @@ -1472,7 +1489,6 @@ void fdc_callback() fdc.stat = (fdc.stat & 0xf) | 0x80; return; case -1: /*Reset*/ -//rpclog("Reset\n"); fdc_int(); fdc.fintr = 0; memset(fdc.pcn, 0, 4); @@ -1484,10 +1500,9 @@ void fdc_callback() return; case 2: /*Read track*/ - readflash = 1; + update_status_bar_icon(SB_FLOPPY | fdc.drive, 1); fdc.eot[fdc.drive]--; fdc.read_track_sector.id.r++; -// pclog("Read a track callback, eot=%i\n", fdc.eot[fdc.drive]); if (!fdc.eot[fdc.drive] || fdc.tc) { fdc_poll_readwrite_finish(2); @@ -1531,7 +1546,6 @@ void fdc_callback() case 0x19: /*Scan low or equal*/ case 0x1C: /*Verify*/ case 0x1D: /*Scan high or equal*/ -// rpclog("Read data %i\n", fdc.tc); if ((discint == 0x11) || (discint == 0x19) || (discint == 0x1D)) { compare = 1; @@ -1540,20 +1554,42 @@ void fdc_callback() { compare = 0; } - bad_end = 1; if ((discint == 6) || (discint == 0xC)) { if (fdc.wrong_am && !(fdc.deleted & 0x20)) { /* Mismatching data address mark and no skip, set TC. */ fdc.tc = 1; - bad_end = 0; } } old_sector = fdc.sector; if (fdc.tc) { - fdc.sector++; + /* This is needed so that the correct results are returned + in case of TC. */ + if (fdc.sector == fdc.params[5]) + { + if (!(fdc.command & 0x80)) + { + fdc.rw_track++; + fdc.sector = 1; + } + else + { + if (fdc.head) + { + fdc.rw_track++; + } + + fdc.head ^= 1; + fdd_set_head(fdc.drive, fdc.head); + fdc.sector = 1; + } + } + else + { + fdc.sector++; + } fdc_poll_readwrite_finish(compare); return; } @@ -1624,7 +1660,7 @@ void fdc_callback() { fdc.sector++; } - readflash = 1; + update_status_bar_icon(SB_FLOPPY | fdc.drive, 1); switch (discint) { case 5: @@ -1670,7 +1706,6 @@ void fdc_callback() return; case 7: /*Recalibrate*/ - // if (!driveempty[fdc.dor & 3]) discchanged[fdc.dor & 3] = 0; fdc.pcn[fdc.params[0] & 3] = 0; drive_num = real_drive(fdc.rw_drive); fdc.st0 = 0x20 | (fdc.params[0] & 3); @@ -1682,12 +1717,10 @@ void fdc_callback() timer_process(); disctime = 2048 * (1 << TIMER_SHIFT); timer_update_outstanding(); -// printf("Recalibrate complete!\n"); fdc.stat = 0x80 | (1 << fdc.drive); return; case 8: /*Sense interrupt status*/ -// pclog("Sense interrupt status %i\n", fdc_reset_stat); fdc.stat = (fdc.stat & 0xf) | 0xd0; @@ -1718,18 +1751,14 @@ void fdc_callback() fdc.res[10] = fdc.pcn[fdc.res[9] & 3]; - // pclog("SENSE INTERRUPT STATUS: Results %02X %02X, ST0 %02X\n", fdc.res[9], fdc.res[10], fdc.st0); - paramstogo = 2; discint = 0; disctime = 0; return; case 0x0d: /*Format track*/ -// rpclog("Format\n"); if (fdc.format_state == 1) { -// ioc_fiq(IOC_FIQ_DISC_DATA); fdc.format_state = 2; timer_process(); disctime = 128 * (1 << TIMER_SHIFT); @@ -1737,7 +1766,6 @@ void fdc_callback() } else if (fdc.format_state == 2) { - // pclog("Format next stage track %i head %i n %i is_mfm %i gap %i sc %i\n", fdc.pcn[fdc.params[0] & 3], fdc.head, fdc_get_format_n(), fdc_is_mfm(), fdc_get_gap(), fdc_get_format_sectors()); disc_format(fdc.drive, fdc.head, fdc.rate, fdc.params[4]); fdc.format_state = 3; } @@ -1760,7 +1788,6 @@ void fdc_callback() return; case 15: /*Seek*/ -// printf("Seeked to track %i %i\n",fdc.pcn[fdc.params[0] & 3], fdc.drive); drive_num = real_drive(fdc.rw_drive); fdc.st0 = 0x20 | (fdc.params[0] & 7); discint=-3; @@ -1768,28 +1795,20 @@ void fdc_callback() disctime = 2048 * (1 << TIMER_SHIFT); timer_update_outstanding(); fdc.stat = 0x80 | (1 << fdc.drive); -// pclog("Stat %02X ST0 %02X\n", fdc.stat, fdc.st0); return; case 0x0e: /*Dump registers*/ fdc.stat = (fdc.stat & 0xf) | 0xd0; - fdc.res[3] = fdc.pcn[0]; - fdc.res[4] = fdc.pcn[1]; - fdc.res[5] = fdc.pcn[2]; - fdc.res[6] = fdc.pcn[3]; - fdc.res[7] = fdc.specify[0]; - fdc.res[8] = fdc.specify[1]; - fdc.res[9] = fdc.eot[fdc.drive]; - fdc.res[10] = (fdc.perp & 0x7f) | ((fdc.lock) ? 0x80 : 0); - if (AT) - { - fdc.res[11] = fdc.config; - fdc.res[12] = fdc.pretrk; - paramstogo=12; - } - else - { - paramstogo=10; - } + fdc.res[1] = fdc.pcn[0]; + fdc.res[2] = fdc.pcn[1]; + fdc.res[3] = fdc.pcn[2]; + fdc.res[4] = fdc.pcn[3]; + fdc.res[5] = fdc.specify[0]; + fdc.res[6] = fdc.specify[1]; + fdc.res[7] = fdc.eot[fdc.drive]; + fdc.res[8] = (fdc.perp & 0x7f) | ((fdc.lock) ? 0x80 : 0); + fdc.res[9] = fdc.config; + fdc.res[10] = fdc.pretrk; + paramstogo = 10; discint=0; disctime = 0; return; @@ -1806,12 +1825,9 @@ void fdc_callback() fdc.config = fdc.params[1]; fdc.pretrk = fdc.params[2]; fdc.fifo = (fdc.params[1] & 0x20) ? 0 : 1; - fdc.tfifo = (fdc.params[1] & 0xF) + 1; - // pclog("CONFIGURE (%02X, %02X, %02X)\n", fdc.params[0], fdc.params[1], fdc.params[2]); - // pclog("FIFO is now %02X, threshold is %02X\n", fdc.fifo, fdc.tfifo); + fdc.tfifo = (fdc.params[1] & 0xF); fdc.stat = 0x80; disctime = 0; -// picint(0x40); return; case 0x14: /*Unlock*/ fdc.lock = 0; @@ -1840,19 +1856,13 @@ void fdc_callback() case 0xfc: /*Invalid*/ fdc.dat = fdc.st0 = 0x80; -// pclog("Inv!\n"); - //picint(0x40); fdc.stat = (fdc.stat & 0xf) | 0xd0; -// fdc.stat|=0xC0; fdc.res[10] = fdc.st0; paramstogo=1; discint=0; disctime = 0; return; } -// printf("Bad FDC disc int %i\n",discint); -// dumpregs(); -// exit(-1); } void fdc_error(int st5, int st6) @@ -1865,6 +1875,7 @@ void fdc_error(int st5, int st6) fdc.res[4]=0x40|(fdd_get_head(real_drive(fdc.drive))?4:0)|fdc.rw_drive; fdc.res[5]=st5; fdc.res[6]=st6; + fdc_log("FDC Error: %02X %02X %02X\n", fdc.res[4], fdc.res[5], fdc.res[6]); switch(discint) { case 0x02: @@ -1888,6 +1899,7 @@ void fdc_error(int st5, int st6) fdc.res[10]=0; break; } + update_status_bar_icon(SB_FLOPPY | fdc.drive, 0); paramstogo=7; } @@ -1922,11 +1934,10 @@ int fdc_data(uint8_t data) if (fdc.data_ready) { fdc_overrun(); -// pclog("Overrun\n"); return -1; } - if (fdc.pcjr || !fdc.fifo || (fdc.tfifo <= 1)) + if (fdc.pcjr || !fdc.fifo || (fdc.tfifo < 1)) { fdc.dat = data; fdc.data_ready = 1; @@ -1934,11 +1945,11 @@ int fdc_data(uint8_t data) } else { - // FIFO enabled + /* FIFO enabled */ fdc_fifo_buf_write(data); if (fdc.fifobufpos == 0) { - // We have wrapped around, means FIFO is over + /* We have wrapped around, means FIFO is over */ fdc.data_ready = 1; fdc.stat = 0xf0; } @@ -1959,7 +1970,7 @@ int fdc_data(uint8_t data) return -1; } - if (!fdc.fifo || (fdc.tfifo <= 1)) + if (!fdc.fifo || (fdc.tfifo < 1)) { fdc.data_ready = 1; fdc.stat = 0xd0; @@ -1969,7 +1980,7 @@ int fdc_data(uint8_t data) fdc_fifo_buf_advance(); if (fdc.fifobufpos == 0) { - // We have wrapped around, means FIFO is over + /* We have wrapped around, means FIFO is over */ fdc.data_ready = 1; fdc.stat = 0xd0; } @@ -1982,8 +1993,6 @@ int fdc_data(uint8_t data) void fdc_finishread() { fdc.inread = 0; - // disctime = 200 * TIMER_USEC; -// rpclog("fdc_finishread\n"); } void fdc_track_finishread(int condition) @@ -1991,8 +2000,7 @@ void fdc_track_finishread(int condition) fdc.stat = 0x10; fdc.satisfying_sectors |= condition; fdc.inread = 0; - fdc_callback(); -// rpclog("fdc_finishread\n"); + fdc_callback(NULL); } void fdc_sector_finishcompare(int satisfying) @@ -2000,27 +2008,16 @@ void fdc_sector_finishcompare(int satisfying) fdc.stat = 0x10; fdc.satisfying_sectors++; fdc.inread = 0; - fdc_callback(); -// rpclog("fdc_finishread\n"); + fdc_callback(NULL); } void fdc_sector_finishread() { fdc.stat = 0x10; fdc.inread = 0; - fdc_callback(); -// rpclog("fdc_finishread\n"); + fdc_callback(NULL); } -#if 0 -void fdc_notfound() -{ - fdc_error(5, 0); - -// rpclog("c82c711_fdc_notfound\n"); -} -#endif - /* There is no sector ID. */ void fdc_noidam() { @@ -2049,15 +2046,11 @@ void fdc_cannotformat() void fdc_datacrcerror() { fdc_error(0x20, 0x20); - -// rpclog("c82c711_fdc_datacrcerror\n"); } void fdc_headercrcerror() { fdc_error(0x20, 0); - -// rpclog("c82c711_fdc_headercrcerror\n"); } void fdc_wrongcylinder() @@ -2084,7 +2077,6 @@ int fdc_getdata(int last) if (fdc.written) { fdc_overrun(); -// pclog("Overrun\n"); return -1; } if (fdc.pcjr || !fdc.fifo) @@ -2129,7 +2121,6 @@ int fdc_getdata(int last) void fdc_sectorid(uint8_t track, uint8_t side, uint8_t sector, uint8_t size, uint8_t crc1, uint8_t crc2) { - // pclog("SectorID %i %i %i %i\n", track, side, sector, size); fdc_int(); fdc.stat=0xD0; fdc.res[4]=(fdd_get_head(real_drive(fdc.drive))?4:0)|fdc.drive; @@ -2144,13 +2135,14 @@ void fdc_sectorid(uint8_t track, uint8_t side, uint8_t sector, uint8_t size, uin void fdc_indexpulse() { -// ioc_irqa(IOC_IRQA_DISC_INDEX); -// rpclog("c82c711_fdc_indexpulse\n"); + return; } -void fdc_init() +void fdc_hard_reset() { - timer_add(fdc_callback, &disctime, &disctime, NULL); + int base_address = fdc.base_address; + + memset(&fdc, 0, sizeof(FDC)); fdc.dskchg_activelow = 0; fdc.enable_3f1 = 1; @@ -2184,6 +2176,18 @@ void fdc_init() swwp = 0; disable_write = 0; + + fdc_reset(); + + fdc.max_track = 79; + fdc.base_address = base_address; +} + +void fdc_init() +{ + fdc_hard_reset(); + + timer_add(fdc_callback, &disctime, &disctime, NULL); } void fdc_add() @@ -2194,6 +2198,16 @@ void fdc_add() fdc.ps1 = 0; fdc.max_track = 79; fdc.perp = 0; + fdc.base_address = 0x03f0; + fdc_log("FDC Added (%04X)\n", fdc.base_address); +} + +void fdc_set_base(int base, int super_io) +{ + io_sethandler(base + (super_io ? 2 : 0), super_io ? 0x0004 : 0x0006, fdc_read, NULL, NULL, fdc_write, NULL, NULL, NULL); + io_sethandler(base + 7, 0x0001, fdc_read, NULL, NULL, fdc_write, NULL, NULL, NULL); + fdc.base_address = base; + fdc_log("FDC Base address set%s (%04X)\n", super_io ? " for Super I/O" : "", fdc.base_address); } void fdc_add_for_superio() @@ -2202,6 +2216,8 @@ void fdc_add_for_superio() io_sethandler(0x03f7, 0x0001, fdc_read, NULL, NULL, fdc_write, NULL, NULL, NULL); fdc.pcjr = 0; fdc.ps1 = 0; + fdc.base_address = 0x03f0; + fdc_log("FDC Added for Super I/O (%04X)\n", fdc.base_address); } void fdc_add_pcjr() @@ -2212,12 +2228,15 @@ void fdc_add_pcjr() fdc.ps1 = 0; fdc.max_track = 79; fdc.perp = 0; + fdc.base_address = 0x03f0; + fdc_log("FDC Added for PCjr (%04X)\n", fdc.base_address); } void fdc_remove() { - io_removehandler(0x03f0, 0x0006, fdc_read, NULL, NULL, fdc_write, NULL, NULL, NULL); - io_removehandler(0x03f7, 0x0001, fdc_read, NULL, NULL, fdc_write, NULL, NULL, NULL); + fdc_log("FDC Removed (%04X)\n", fdc.base_address); + io_removehandler(fdc.base_address, 0x0006, fdc_read, NULL, NULL, fdc_write, NULL, NULL, NULL); + io_removehandler(fdc.base_address + 7, 0x0001, fdc_read, NULL, NULL, fdc_write, NULL, NULL, NULL); } void fdc_discchange_clear(int drive) diff --git a/src/fdc.h b/src/fdc.h index 9b1f840aa..0e8c42654 100644 --- a/src/fdc.h +++ b/src/fdc.h @@ -1,6 +1,22 @@ -/* Copyright holders: Sarah Walker, Tenshi - see COPYING for more details -*/ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Implementation of the NEC uPD-765 and compatible floppy disk + * controller. + * + * Version: @(#)fdc.h 1.0.0 2017/05/30 + * + * Author: Sarah Walker, + * Miran Grca, + * Copyright 2008-2017 Sarah Walker. + * Copyright 2016-2017 Miran Grca. + */ + void fdc_init(); void fdc_add(); void fdc_add_for_superio(); @@ -64,3 +80,7 @@ void fdc_track_finishread(int condition); int fdc_is_verify(); int real_drive(int drive); +void fdc_overrun(); +void fdc_set_base(int base, int super_io); +int fdc_ps1_525(); +void fdc_hard_reset(); diff --git a/src/fdc37c665.c b/src/fdc37c665.c index d076ae2cb..56623d054 100644 --- a/src/fdc37c665.c +++ b/src/fdc37c665.c @@ -1,11 +1,27 @@ -/* Copyright holders: Sarah Walker, Tenshi - see COPYING for more details -*/ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Implementation of the SMC FDC37C665 Super I/O Chip. + * + * Version: @(#)fdc37c665.c 1.0.0 2017/05/30 + * + * Author: Sarah Walker, + * Miran Grca, + * Copyright 2008-2017 Sarah Walker. + * Copyright 2016-2017 Miran Grca. + */ + #include "ibm.h" #include "disc.h" #include "fdc.h" #include "fdd.h" +#include "ide.h" #include "io.h" #include "lpt.h" #include "serial.h" @@ -14,6 +30,7 @@ static uint8_t fdc37c665_lock[2]; static int fdc37c665_curreg; static uint8_t fdc37c665_regs[16]; +static int com3_addr, com4_addr; static void write_lock(uint8_t val) { @@ -26,9 +43,125 @@ static void write_lock(uint8_t val) fdc37c665_lock[1] = val; } +static void ide_handler() +{ +#if 0 + uint16_t or_value = 0; + if ((romset == ROM_440FX) || (romset == ROM_R418) || (romset == ROM_MB500N)) + { + return; + } + ide_pri_disable(); + if (fdc37c665_regs[0] & 1) + { + if (fdc37c665_regs[5] & 2) + { + or_value = 0; + } + else + { + or_value = 0x800; + } + ide_set_base(0, 0x170 | or_value); + ide_set_side(0, 0x376 | or_value); + ide_pri_enable_ex(); + } +#endif +} + +static void set_com34_addr() +{ + switch (fdc37c665_regs[1] & 0x60) + { + case 0x00: + com3_addr = 0x338; + com4_addr = 0x238; + break; + case 0x20: + com3_addr = 0x3e8; + com4_addr = 0x2e8; + break; + case 0x40: + com3_addr = 0x3e8; + com4_addr = 0x2e0; + break; + case 0x60: + com3_addr = 0x220; + com4_addr = 0x228; + break; + } +} + +void set_serial1_addr() +{ + if (fdc37c665_regs[2] & 4) + { + switch (fdc37c665_regs[2] & 3) + { + case 0: + serial_setup(1, SERIAL1_ADDR, SERIAL1_IRQ); + break; + + case 1: + serial_setup(1, SERIAL2_ADDR, SERIAL2_IRQ); + break; + + case 2: + serial_setup(1, com3_addr, 4); + break; + + case 3: + serial_setup(1, com4_addr, 3); + break; + } + } +} + +void set_serial2_addr() +{ + if (fdc37c665_regs[2] & 0x40) + { + switch (fdc37c665_regs[2] & 0x30) + { + case 0: + serial_setup(2, SERIAL1_ADDR, SERIAL1_IRQ); + break; + + case 1: + serial_setup(2, SERIAL2_ADDR, SERIAL2_IRQ); + break; + + case 2: + serial_setup(2, com3_addr, 4); + break; + + case 3: + serial_setup(2, com4_addr, 3); + break; + } + } +} + +static void lpt1_handler() +{ + lpt1_remove(); + switch (fdc37c665_regs[1] & 3) + { + case 1: + lpt1_init(0x3bc); + break; + case 2: + lpt1_init(0x378); + break; + case 3: + lpt1_init(0x278); + break; + } +} + void fdc37c665_write(uint16_t port, uint8_t val, void *priv) { - // pclog("Write SuperIO %04x %02x\n", port, val); + uint8_t valxor = 0; if (fdc37c665_lock[0] == 0x55 && fdc37c665_lock[1] == 0x55) { if (port == 0x3f0) @@ -36,89 +169,75 @@ void fdc37c665_write(uint16_t port, uint8_t val, void *priv) if (val == 0xaa) write_lock(val); else - fdc37c665_curreg = val & 0xf; + if (fdc37c665_curreg != 0) + { + fdc37c665_curreg = val & 0xf; + } + else + { + /* Hardcode the IDE to AT type. */ + fdc37c665_curreg = (val & 0xf) | 2; + } } else { - uint16_t com3_addr, com4_addr; + valxor = val ^ fdc37c665_regs[fdc37c665_curreg]; fdc37c665_regs[fdc37c665_curreg] = val; -// pclog("Write superIO %02x %02x %04x(%08x):%08x\n", fdc37c665_curreg, val, CS, cs, pc); - switch (fdc37c665_regs[1] & 0x60) - { - case 0x00: - com3_addr = 0x338; - com4_addr = 0x238; - break; - case 0x20: - com3_addr = 0x3e8; - com4_addr = 0x2e8; - break; - case 0x40: - com3_addr = 0x3e8; - com4_addr = 0x2e0; - break; - case 0x60: - com3_addr = 0x220; - com4_addr = 0x228; - break; + switch(fdc37c665_curreg) + { + case 0: + if (valxor & 1) + { + ide_handler(); + } + break; + case 1: + if (valxor & 3) + { + lpt1_handler(); + } + if (valxor & 0x60) + { + serial_remove(1); + set_com34_addr(); + set_serial1_addr(); + set_serial2_addr(); + } + break; + case 2: + if (valxor & 7) + { + serial_remove(1); + set_serial1_addr(); + } + if (valxor & 0x70) + { + serial_remove(2); + set_serial2_addr(); + } + break; + case 3: + if (valxor & 2) + { + fdc_update_enh_mode((fdc37c665_regs[3] & 2) ? 1 : 0); + } + break; + case 5: + if (valxor & 2) + { + ide_handler(); + } + if (valxor & 0x18) + { + fdc_update_densel_force((fdc37c665_regs[5] & 0x18) >> 3); + } + if (valxor & 0x20) + { + fdd_swap = ((fdc37c665_regs[5] & 0x20) >> 5); + } + break; } - - if (!(fdc37c665_regs[2] & 4)) - serial1_remove(); - else switch (fdc37c665_regs[2] & 3) - { - case 0: - serial1_set(0x3f8, 4); - break; - case 1: - serial1_set(0x2f8, 4); - break; - case 2: - serial1_set(com3_addr, 4); - break; - case 3: - serial1_set(com4_addr, 4); - break; - } - - if (!(fdc37c665_regs[2] & 0x40)) - serial2_remove(); - else switch (fdc37c665_regs[2] & 0x30) - { - case 0x00: - serial2_set(0x3f8, 3); - break; - case 0x10: - serial2_set(0x2f8, 3); - break; - case 0x20: - serial2_set(com3_addr, 3); - break; - case 0x30: - serial2_set(com4_addr, 3); - break; - } - - lpt1_remove(); - lpt2_remove(); - switch (fdc37c665_regs[1] & 3) - { - case 1: - lpt1_init(0x3bc); - break; - case 2: - lpt1_init(0x378); - break; - case 3: - lpt1_init(0x278); - break; - } - - fdc_update_enh_mode((fdc37c665_regs[3] & 2) ? 1 : 0); - - fdc_update_densel_force((fdc37c665_regs[5] & 0x18) >> 3); - fdd_swap = ((fdc37c665_regs[5] & 0x20) >> 5); } } else @@ -130,7 +249,6 @@ void fdc37c665_write(uint16_t port, uint8_t val, void *priv) uint8_t fdc37c665_read(uint16_t port, void *priv) { - // pclog("Read SuperIO %04x %02x\n", port, fdc37c665_curreg); if (fdc37c665_lock[0] == 0x55 && fdc37c665_lock[1] == 0x55) { if (port == 0x3f1) @@ -139,31 +257,47 @@ uint8_t fdc37c665_read(uint16_t port, void *priv) return 0xff; } -void fdc37c665_init() +void fdc37c665_reset(void) { - io_sethandler(0x03f0, 0x0002, fdc37c665_read, NULL, NULL, fdc37c665_write, NULL, NULL, NULL); + com3_addr = 0x338; + com4_addr = 0x238; + + fdc_remove(); + fdc_add_for_superio(); fdc_update_is_nsc(0); - fdc37c665_lock[0] = fdc37c665_lock[1] = 0; + serial_remove(1); + serial_setup(1, SERIAL1_ADDR, SERIAL1_IRQ); + + serial_remove(2); + serial_setup(2, SERIAL2_ADDR, SERIAL2_IRQ); + + lpt2_remove(); + + lpt1_remove(); + lpt1_init(0x378); + + memset(fdc37c665_lock, 0, 2); + memset(fdc37c665_regs, 0, 16); fdc37c665_regs[0x0] = 0x3b; fdc37c665_regs[0x1] = 0x9f; fdc37c665_regs[0x2] = 0xdc; fdc37c665_regs[0x3] = 0x78; - fdc37c665_regs[0x4] = 0x00; - fdc37c665_regs[0x5] = 0x00; fdc37c665_regs[0x6] = 0xff; - fdc37c665_regs[0x7] = 0x00; - fdc37c665_regs[0x8] = 0x00; - fdc37c665_regs[0x9] = 0x00; - fdc37c665_regs[0xa] = 0x00; - fdc37c665_regs[0xb] = 0x00; - fdc37c665_regs[0xc] = 0x00; fdc37c665_regs[0xd] = 0x65; fdc37c665_regs[0xe] = 0x01; - fdc37c665_regs[0xf] = 0x00; fdc_update_densel_polarity(1); fdc_update_densel_force(0); fdd_swap = 0; } + +void fdc37c665_init() +{ + io_sethandler(0x03f0, 0x0002, fdc37c665_read, NULL, NULL, fdc37c665_write, NULL, NULL, NULL); + + fdc37c665_reset(); + + pci_reset_handler.super_io_reset = fdc37c665_reset; +} diff --git a/src/fdc37c665.h b/src/fdc37c665.h index 8f906807d..cbe28216f 100644 --- a/src/fdc37c665.h +++ b/src/fdc37c665.h @@ -1,4 +1,19 @@ -/* Copyright holders: Sarah Walker, Tenshi - see COPYING for more details -*/ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Implementation of the SMC FDC37C665 Super I/O Chip. + * + * Version: @(#)fdc37c665.h 1.0.0 2017/05/30 + * + * Author: Sarah Walker, + * Miran Grca, + * Copyright 2008-2017 Sarah Walker. + * Copyright 2016-2017 Miran Grca. + */ + extern void fdc37c665_init(); diff --git a/src/fdc37c669.c b/src/fdc37c669.c new file mode 100644 index 000000000..33d19b8ba --- /dev/null +++ b/src/fdc37c669.c @@ -0,0 +1,346 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Implementation of the SMC FDC37C669 Super I/O Chip. + * + * Version: @(#)fdc37c669.c 1.0.0 2017/05/30 + * + * Author: Miran Grca, + * Copyright 2016-2017 Miran Grca. + */ + +#include "ibm.h" + +#include "disc.h" +#include "fdc.h" +#include "fdd.h" +#include "io.h" +#include "ide.h" +#include "lpt.h" +#include "serial.h" +#include "fdc37c669.h" + +static int fdc37c669_locked; +static int fdc37c669_rw_locked = 0; +static int fdc37c669_curreg = 0; +static uint8_t fdc37c669_regs[42]; +static uint8_t tries; + +static uint16_t fdc_valid_ports[2] = {0x3F0, 0x370}; +static uint16_t ide_valid_ports[2] = {0x1F0, 0x170}; +static uint16_t ide_as_valid_ports[2] = {0x3F6, 0x376}; +static uint16_t lpt1_valid_ports[3] = {0x3BC, 0x378, 0x278}; +static uint16_t com1_valid_ports[9] = {0x3F8, 0x2F8, 0x338, 0x3E8, 0x2E8, 0x220, 0x238, 0x2E0, 0x228}; +static uint16_t com2_valid_ports[9] = {0x3F8, 0x2F8, 0x338, 0x3E8, 0x2E8, 0x220, 0x238, 0x2E0, 0x228}; + +static uint8_t is_in_array(uint16_t *port_array, uint8_t max, uint16_t port) +{ + uint8_t i = 0; + + for (i = 0; i < max; i++) + { + if (port_array[i] == port) return 1; + } + return 0; +} + +static uint16_t make_port(uint8_t reg) +{ + uint16_t p = 0; + + switch(reg) + { + case 0x20: + p = ((uint16_t) (fdc37c669_regs[reg] & 0xfc)) << 2; + p &= 0xFF0; + if ((p < 0x100) || (p > 0x3F0)) p = 0x3F0; + if (!(is_in_array(fdc_valid_ports, 2, p))) p = 0x3F0; + fdc37c669_regs[reg] = ((p >> 2) & 0xfc) | (fdc37c669_regs[reg] & 3); + break; + case 0x21: + p = ((uint16_t) (fdc37c669_regs[reg] & 0xfc)) << 2; + p &= 0xFF0; + if ((p < 0x100) || (p > 0x3F0)) p = 0x1F0; + if (!(is_in_array(ide_valid_ports, 2, p))) p = 0x1F0; + fdc37c669_regs[reg] = ((p >> 2) & 0xfc) | (fdc37c669_regs[reg] & 3); + break; + case 0x22: + p = ((uint16_t) (fdc37c669_regs[reg] & 0xfc)) << 2; + p &= 0xFF0; + if ((p < 0x106) || (p > 0x3F6)) p = 0x3F6; + if (!(is_in_array(ide_as_valid_ports, 2, p))) p = 0x3F6; + fdc37c669_regs[reg] = ((p >> 2) & 0xfc) | (fdc37c669_regs[reg] & 3); + break; + case 0x23: + p = ((uint16_t) (fdc37c669_regs[reg] & 0xff)) << 2; + p &= 0xFFC; + if ((p < 0x100) || (p > 0x3F8)) p = 0x378; + if (!(is_in_array(lpt1_valid_ports, 3, p))) p = 0x378; + fdc37c669_regs[reg] = (p >> 2); + break; + case 0x24: + p = ((uint16_t) (fdc37c669_regs[reg] & 0xfe)) << 2; + p &= 0xFF8; + if ((p < 0x100) || (p > 0x3F8)) p = 0x3F8; + if (!(is_in_array(com1_valid_ports, 9, p))) p = 0x3F8; + fdc37c669_regs[reg] = ((p >> 2) & 0xfe) | (fdc37c669_regs[reg] & 1); + break; + case 0x25: + p = ((uint16_t) (fdc37c669_regs[reg] & 0xfe)) << 2; + p &= 0xFF8; + if ((p < 0x100) || (p > 0x3F8)) p = 0x2F8; + if (!(is_in_array(com2_valid_ports, 9, p))) p = 0x2F8; + fdc37c669_regs[reg] = ((p >> 2) & 0xfe) | (fdc37c669_regs[reg] & 1); + break; + } + + return p; +} + +void fdc37c669_write(uint16_t port, uint8_t val, void *priv) +{ + uint8_t index = (port & 1) ? 0 : 1; + uint8_t valxor = 0; + uint8_t max = 42; + pclog("fdc37c669_write : port=%04x reg %02X = %02X locked=%i\n", port, fdc37c669_curreg, val, fdc37c669_locked); + + if (index) + { + if ((val == 0x55) && !fdc37c669_locked) + { + if (tries) + { + fdc37c669_locked = 1; + tries = 0; + } + else + { + tries++; + } + } + else + { + if (fdc37c669_locked) + { + if (val < max) fdc37c669_curreg = val; + if (val == 0xaa) fdc37c669_locked = 0; + } + else + { + if (tries) + tries = 0; + } + } + } + else + { + if (fdc37c669_locked) + { + if ((fdc37c669_curreg < 0x18) && (fdc37c669_rw_locked)) return; + if ((fdc37c669_curreg >= 0x26) && (fdc37c669_curreg <= 0x27)) return; + if (fdc37c669_curreg == 0x29) return; + valxor = val ^ fdc37c669_regs[fdc37c669_curreg]; + fdc37c669_regs[fdc37c669_curreg] = val; + goto process_value; + } + } + return; + +process_value: + switch(fdc37c669_curreg) + { + case 0: + if (valxor & 3) + { + ide_pri_disable(); + if ((fdc37c669_regs[0] & 3) == 2) ide_pri_enable_ex(); + break; + } + if (valxor & 8) + { + fdc_remove(); + if ((fdc37c669_regs[0] & 8) && (fdc37c669_regs[0x20] & 0xc0)) fdc_set_base(make_port(0x20), 1); + } + break; + case 1: + if (valxor & 4) + { + lpt1_remove(); + if ((fdc37c669_regs[1] & 4) && (fdc37c669_regs[0x23] & 0xc0)) lpt1_init(make_port(0x23)); + } + if (valxor & 7) + { + fdc37c669_rw_locked = (val & 8) ? 0 : 1; + } + break; + case 2: + if (valxor & 8) + { + serial_remove(1); + if ((fdc37c669_regs[2] & 8) && (fdc37c669_regs[0x24] & 0xc0)) serial_setup(1, make_port(0x24), (fdc37c669_regs[0x28] & 0xF0) >> 8); + } + if (valxor & 0x80) + { + serial_remove(2); + if ((fdc37c669_regs[2] & 0x80) && (fdc37c669_regs[0x25] & 0xc0)) serial_setup(2, make_port(0x25), fdc37c669_regs[0x28] & 0xF); + } + break; + case 3: + if (valxor & 2) fdc_update_enh_mode((val & 2) ? 1 : 0); + break; + case 5: + if (valxor & 0x18) fdc_update_densel_force((val & 0x18) >> 3); + if (valxor & 0x20) fdd_swap = ((val & 0x20) >> 5); + break; + case 0xB: + if (valxor & 3) fdc_update_rwc(0, val & 3); + if (valxor & 0xC) fdc_update_rwc(1, (val & 0xC) >> 2); + break; + case 0x20: + if (valxor & 0xfc) + { + fdc_remove(); + if ((fdc37c669_regs[0] & 8) && (fdc37c669_regs[0x20] & 0xc0)) fdc_set_base(make_port(0x20), 1); + } + break; + case 0x21: + case 0x22: + if (valxor & 0xfc) + { + ide_pri_disable(); + switch (fdc37c669_curreg) + { + case 0x21: + ide_set_base(0, make_port(0x21)); + break; + case 0x22: + ide_set_side(0, make_port(0x22)); + break; + } + if ((fdc37c669_regs[0] & 3) == 2) ide_pri_enable_ex(); + } + break; + case 0x23: + if (valxor) + { + lpt1_remove(); + if ((fdc37c669_regs[1] & 4) && (fdc37c669_regs[0x23] & 0xc0)) lpt1_init(make_port(0x23)); + } + break; + case 0x24: + if (valxor & 0xfe) + { + serial_remove(1); + if ((fdc37c669_regs[2] & 8) && (fdc37c669_regs[0x24] & 0xc0)) serial_setup(1, make_port(0x24), (fdc37c669_regs[0x28] & 0xF0) >> 8); + } + break; + case 0x25: + if (valxor & 0xfe) + { + serial_remove(2); + if ((fdc37c669_regs[2] & 0x80) && (fdc37c669_regs[0x25] & 0xc0)) serial_setup(2, make_port(0x25), fdc37c669_regs[0x28] & 0xF); + } + break; + case 0x28: + if (valxor & 0xf) + { + serial_remove(2); + if ((fdc37c669_regs[0x28] & 0xf) == 0) fdc37c669_regs[0x28] |= 0x3; + if ((fdc37c669_regs[2] & 0x80) && (fdc37c669_regs[0x25] & 0xc0)) serial_setup(2, make_port(0x25), fdc37c669_regs[0x28] & 0xF); + } + if (valxor & 0xf0) + { + serial_remove(1); + if ((fdc37c669_regs[0x28] & 0xf0) == 0) fdc37c669_regs[0x28] |= 0x40; + if ((fdc37c669_regs[2] & 8) && (fdc37c669_regs[0x24] & 0xc0)) serial_setup(1, make_port(0x24), (fdc37c669_regs[0x28] & 0xF0) >> 8); + } + break; + } +} + +uint8_t fdc37c669_read(uint16_t port, void *priv) +{ + uint8_t index = (port & 1) ? 0 : 1; + + pclog("fdc37c669_read : port=%04x reg %02X locked=%i\n", port, fdc37c669_curreg, fdc37c669_locked); + + if (!fdc37c669_locked) + { + return 0xFF; + } + + if (index) + return fdc37c669_curreg; + else + { + pclog("0x03F1: %02X\n", fdc37c669_regs[fdc37c669_curreg]); + if ((fdc37c669_curreg < 0x18) && (fdc37c669_rw_locked)) return 0xff; + return fdc37c669_regs[fdc37c669_curreg]; + } +} + +void fdc37c669_reset(void) +{ + fdc_remove(); + fdc_add_for_superio(); + + fdc_update_is_nsc(0); + + serial_remove(1); + serial_setup(1, SERIAL1_ADDR, SERIAL1_IRQ); + + serial_remove(2); + serial_setup(2, SERIAL2_ADDR, SERIAL2_IRQ); + + lpt2_remove(); + + lpt1_remove(); + lpt1_init(0x378); + + memset(fdc37c669_regs, 0, 42); + fdc37c669_regs[0] = 0x28; + fdc37c669_regs[1] = 0x9C; + fdc37c669_regs[2] = 0x88; + fdc37c669_regs[3] = 0x78; + fdc37c669_regs[4] = 0; + fdc37c669_regs[5] = 0; + fdc37c669_regs[6] = 0xFF; + fdc37c669_regs[7] = 0; + fdc37c669_regs[8] = 0; + fdc37c669_regs[9] = 0; + fdc37c669_regs[0xA] = 0; + fdc37c669_regs[0xB] = 0; + fdc37c669_regs[0xC] = 0; + fdc37c669_regs[0xD] = 3; + fdc37c669_regs[0xE] = 2; + fdc37c669_regs[0x1E] = 0x80; /* Gameport controller. */ + fdc37c669_regs[0x20] = (0x3f0 >> 2) & 0xfc; + fdc37c669_regs[0x21] = (0x1f0 >> 2) & 0xfc; + fdc37c669_regs[0x22] = ((0x3f6 >> 2) & 0xfc) | 1; + fdc37c669_regs[0x23] = (0x378 >> 2); + fdc37c669_regs[0x24] = (0x3f8 >> 2) & 0xfe; + fdc37c669_regs[0x25] = (0x2f8 >> 2) & 0xfe; + fdc37c669_regs[0x26] = (2 << 4) | 3; + fdc37c669_regs[0x27] = (6 << 4) | 7; + fdc37c669_regs[0x28] = (4 << 4) | 3; + + fdc_update_densel_polarity(1); + fdc_update_densel_force(0); + fdd_swap = 0; + fdc37c669_locked = 0; + fdc37c669_rw_locked = 0; +} + +void fdc37c669_init() +{ + io_sethandler(0x3f0, 0x0002, fdc37c669_read, NULL, NULL, fdc37c669_write, NULL, NULL, NULL); + + fdc37c669_reset(); + + pci_reset_handler.super_io_reset = fdc37c669_reset; +} diff --git a/src/fdc37c669.h b/src/fdc37c669.h new file mode 100644 index 000000000..31189524a --- /dev/null +++ b/src/fdc37c669.h @@ -0,0 +1,17 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Implementation of the SMC FDC37C669 Super I/O Chip. + * + * Version: @(#)fdc37c669.h 1.0.0 2017/05/30 + * + * Author: Miran Grca, + * Copyright 2016-2017 Miran Grca. + */ + +extern void fdc37c669_init(); diff --git a/src/fdc37c932fr.c b/src/fdc37c932fr.c index 68abfea5e..d5faf988e 100644 --- a/src/fdc37c932fr.c +++ b/src/fdc37c932fr.c @@ -1,10 +1,18 @@ -/* Copyright holders: Tenshi - see COPYING for more details -*/ /* - SMSC SMC fdc37c932fr Super I/O Chip - Used by all some Acer boards, and by the Epox P55-VA -*/ + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Implementation of the SMC FDC37C932FR Super I/O Chip. + * + * Version: @(#)fdc37c932fr.c 1.0.0 2017/05/30 + * + * Author: Miran Grca, + * Copyright 2016-2017 Miran Grca. + */ #include "ibm.h" @@ -144,9 +152,6 @@ void fdc37c932fr_write(uint16_t port, uint8_t val, void *priv) uint8_t index = (port & 1) ? 0 : 1; uint8_t valxor = 0; uint16_t ld_port = 0; - uint16_t ld_port2 = 0; - int temp; - // pclog("fdc37c932fr_write : port=%04x reg %02X = %02X locked=%i\n", port, fdc37c932fr_curreg, val, fdc37c932fr_locked); if (index) { @@ -300,11 +305,11 @@ process_value: if (valxor) { if (!val) - serial1_remove(); + serial_remove(1); else { ld_port = make_port(4); - serial1_set(ld_port, fdc37c932fr_ld_regs[4][0x70]); + serial_setup(1, ld_port, fdc37c932fr_ld_regs[4][0x70]); } } break; @@ -314,7 +319,7 @@ process_value: if (valxor && fdc37c932fr_ld_regs[4][0x30]) { ld_port = make_port(4); - serial1_set(ld_port, fdc37c932fr_ld_regs[4][0x70]); + serial_setup(1, ld_port, fdc37c932fr_ld_regs[4][0x70]); } break; } @@ -328,11 +333,11 @@ process_value: if (valxor) { if (!val) - serial2_remove(); + serial_remove(2); else { ld_port = make_port(5); - serial2_set(ld_port, fdc37c932fr_ld_regs[5][0x70]); + serial_setup(2, ld_port, fdc37c932fr_ld_regs[5][0x70]); } } break; @@ -342,7 +347,7 @@ process_value: if (valxor && fdc37c932fr_ld_regs[5][0x30]) { ld_port = make_port(5); - serial2_set(ld_port, fdc37c932fr_ld_regs[5][0x70]); + serial_setup(2, ld_port, fdc37c932fr_ld_regs[5][0x70]); } break; } @@ -367,7 +372,6 @@ uint8_t fdc37c932fr_gpio_read(uint16_t port, void *priv) uint8_t fdc37c932fr_read(uint16_t port, void *priv) { - // pclog("fdc37c932fr_read : port=%04x reg %02X locked=%i\n", port, fdc37c932fr_curreg, fdc37c932fr_locked); uint8_t index = (port & 1) ? 0 : 1; if (!fdc37c932fr_locked) @@ -381,24 +385,20 @@ uint8_t fdc37c932fr_read(uint16_t port, void *priv) { if (fdc37c932fr_curreg < 0x30) { - // pclog("0x03F1: %02X\n", fdc37c932fr_regs[fdc37c932fr_curreg]); return fdc37c932fr_regs[fdc37c932fr_curreg]; } else { - // pclog("0x03F1 (CD=%02X): %02X\n", fdc37c932fr_regs[7], fdc37c932fr_ld_regs[fdc37c932fr_regs[7]][fdc37c932fr_curreg]); if ((fdc37c932fr_regs[7] == 0) && (fdc37c932fr_curreg == 0xF2)) return (fdc_get_rwc(0) | (fdc_get_rwc(1) << 2)); return fdc37c932fr_ld_regs[fdc37c932fr_regs[7]][fdc37c932fr_curreg]; } } } -void fdc37c932fr_init() +void fdc37c932fr_reset(void) { int i = 0; - lpt2_remove(); - fdc37c932fr_regs[3] = 3; fdc37c932fr_regs[0x20] = 3; fdc37c932fr_regs[0x21] = 1; @@ -451,6 +451,7 @@ void fdc37c932fr_init() fdc37c932fr_ld_regs[4][0x61] = 0xf8; fdc37c932fr_ld_regs[4][0x70] = 4; fdc37c932fr_ld_regs[4][0xF0] = 3; + serial_setup(1, 0x3f8, fdc37c932fr_ld_regs[4][0x70]); /* Logical device 5: Serial Port 2 */ fdc37c932fr_ld_regs[5][0x30] = 1; @@ -460,6 +461,7 @@ void fdc37c932fr_init() fdc37c932fr_ld_regs[5][0x74] = 4; fdc37c932fr_ld_regs[5][0xF1] = 2; fdc37c932fr_ld_regs[5][0xF2] = 3; + serial_setup(2, 0x2f8, fdc37c932fr_ld_regs[5][0x70]); /* Logical device 6: RTC */ fdc37c932fr_ld_regs[6][0x63] = 0x70; @@ -485,8 +487,19 @@ void fdc37c932fr_init() fdc_update_drvrate(2, 0); fdc_update_drvrate(3, 0); fdc_update_max_track(79); + + fdc37c932fr_locked = 0; +} + +void fdc37c932fr_init() +{ + lpt2_remove(); + + fdc37c932fr_reset(); + io_sethandler(0xe0, 0x0006, fdc37c932fr_gpio_read, NULL, NULL, fdc37c932fr_gpio_write, NULL, NULL, NULL); io_sethandler(0xea, 0x0002, fdc37c932fr_gpio_read, NULL, NULL, fdc37c932fr_gpio_write, NULL, NULL, NULL); io_sethandler(0x3f0, 0x0002, fdc37c932fr_read, NULL, NULL, fdc37c932fr_write, NULL, NULL, NULL); - fdc37c932fr_locked = 0; + + pci_reset_handler.super_io_reset = fdc37c932fr_reset; } diff --git a/src/fdc37c932fr.h b/src/fdc37c932fr.h index ef83f5d01..1e48bb0e9 100644 --- a/src/fdc37c932fr.h +++ b/src/fdc37c932fr.h @@ -1,4 +1,17 @@ -/* Copyright holders: Tenshi - see COPYING for more details -*/ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Implementation of the SMC FDC37C932FR Super I/O Chip. + * + * Version: @(#)fdc37c932fr.h 1.0.0 2017/05/30 + * + * Author: Miran Grca, + * Copyright 2016-2017 Miran Grca. + */ + extern void fdc37c932fr_init(); diff --git a/src/fdd.c b/src/fdd.c index b6c49143a..dd6649ee2 100644 --- a/src/fdd.c +++ b/src/fdd.c @@ -1,6 +1,21 @@ -/* Copyright holders: Sarah Walker, Tenshi - see COPYING for more details -*/ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Implementation of the floppy drive emulation. + * + * Version: @(#)fdd.c 1.0.0 2017/05/30 + * + * Author: Sarah Walker, + * Miran Grca, + * Copyright 2008-2017 Sarah Walker. + * Copyright 2016-2017 Miran Grca. + */ + #include "ibm.h" #include "disc.h" #include "fdc.h" @@ -15,88 +30,121 @@ static struct int densel; int head; + + int turbo; } fdd[FDD_NUM]; /* Flags: - Bit 0: 300 rpm supported; - Bit 1: 360 rpm supported; - Bit 2: size (0 = 3.5", 1 = 5.25"); - Bit 3: double density supported; - Bit 4: high density supported; - Bit 5: extended density supported; - Bit 6: double step for 40-track media; - Bit 7: invert DENSEL polarity; - Bit 8: ignore DENSEL; - Bit 9: drive is a PS/2 drive; + Bit 0: 300 rpm supported; + Bit 1: 360 rpm supported; + Bit 2: size (0 = 3.5", 1 = 5.25"); + Bit 3: sides (0 = 1, 1 = 2); + Bit 4: double density supported; + Bit 5: high density supported; + Bit 6: extended density supported; + Bit 7: double step for 40-track media; + Bit 8: invert DENSEL polarity; + Bit 9: ignore DENSEL; + Bit 10: drive is a PS/2 drive; */ #define FLAG_RPM_300 1 #define FLAG_RPM_360 2 -#define FLAG_525 4 -#define FLAG_HOLE0 8 -#define FLAG_HOLE1 16 -#define FLAG_HOLE2 32 -#define FLAG_DOUBLE_STEP 64 -#define FLAG_INVERT_DENSEL 128 -#define FLAG_IGNORE_DENSEL 256 -#define FLAG_PS2 512 +#define FLAG_525 4 +#define FLAG_DS 8 +#define FLAG_HOLE0 16 +#define FLAG_HOLE1 32 +#define FLAG_HOLE2 64 +#define FLAG_DOUBLE_STEP 128 +#define FLAG_INVERT_DENSEL 256 +#define FLAG_IGNORE_DENSEL 512 +#define FLAG_PS2 1024 static struct { int max_track; int flags; + char name[64]; + char internal_name[24]; } drive_types[] = { { /*None*/ - .max_track = 0, - .flags = 0 + 0, 0, "None", "none" + }, + { /*5.25" 1DD*/ + 43, FLAG_RPM_300 | FLAG_525 | FLAG_HOLE0, "5.25\" 180k", "525_1dd" }, { /*5.25" DD*/ - .max_track = 43, - .flags = FLAG_RPM_300 | FLAG_525 | FLAG_HOLE0 + 43, FLAG_RPM_300 | FLAG_525 | FLAG_DS | FLAG_HOLE0, "5.25\" 360k", "525_2dd" + }, + { /*5.25" QD*/ + 86, FLAG_RPM_300 | FLAG_525 | FLAG_DS | FLAG_HOLE0 | FLAG_DOUBLE_STEP, "5.25\" 720k", "525_2qd" + }, + { /*5.25" HD PS/2*/ + 86, FLAG_RPM_360 | FLAG_525 | FLAG_DS | FLAG_HOLE0 | FLAG_HOLE1 | FLAG_DOUBLE_STEP | FLAG_INVERT_DENSEL | FLAG_PS2, "5.25\" 1.2M PS/2", "525_2hd_ps2" }, { /*5.25" HD*/ - .max_track = 86, - .flags = FLAG_RPM_360 | FLAG_525 | FLAG_HOLE0 | FLAG_HOLE1 | FLAG_DOUBLE_STEP + 86, FLAG_RPM_360 | FLAG_525 | FLAG_DS | FLAG_HOLE0 | FLAG_HOLE1 | FLAG_DOUBLE_STEP, "5.25\" 1.2M", "525_2hd" }, { /*5.25" HD Dual RPM*/ - .max_track = 86, - .flags = FLAG_RPM_300 | FLAG_RPM_360 | FLAG_525 | FLAG_HOLE0 | FLAG_HOLE1 | FLAG_DOUBLE_STEP + 86, FLAG_RPM_300 | FLAG_RPM_360 | FLAG_525 | FLAG_DS | FLAG_HOLE0 | FLAG_HOLE1 | FLAG_DOUBLE_STEP, "5.25\" 1.2M 300/360 RPM", "525_2hd_dualrpm" + }, + { /*3.5" 1DD*/ + 86, FLAG_RPM_300 | FLAG_HOLE0 | FLAG_DOUBLE_STEP, "3.5\" 360k", "35_1dd" }, { /*3.5" DD*/ - .max_track = 86, - .flags = FLAG_RPM_300 | FLAG_HOLE0 | FLAG_DOUBLE_STEP + 86, FLAG_RPM_300 | FLAG_DS | FLAG_HOLE0 | FLAG_DOUBLE_STEP, "3.5\" 720k", "35_2dd" }, { /*3.5" HD PS/2*/ - .max_track = 86, - .flags = FLAG_RPM_300 | FLAG_HOLE0 | FLAG_HOLE1 | FLAG_DOUBLE_STEP | FLAG_INVERT_DENSEL | FLAG_PS2 + 86, FLAG_RPM_300 | FLAG_DS | FLAG_HOLE0 | FLAG_HOLE1 | FLAG_DOUBLE_STEP | FLAG_INVERT_DENSEL | FLAG_PS2, "3.5\" 1.44M PS/2", "35_2hd_ps2" }, { /*3.5" HD*/ - .max_track = 86, - .flags = FLAG_RPM_300 | FLAG_HOLE0 | FLAG_HOLE1 | FLAG_DOUBLE_STEP + 86, FLAG_RPM_300 | FLAG_DS | FLAG_HOLE0 | FLAG_HOLE1 | FLAG_DOUBLE_STEP, "3.5\" 1.44M", "35_2hd" }, { /*3.5" HD PC-98*/ - .max_track = 86, - .flags = FLAG_RPM_300 | FLAG_RPM_360 | FLAG_HOLE0 | FLAG_HOLE1 | FLAG_DOUBLE_STEP | FLAG_INVERT_DENSEL + 86, FLAG_RPM_300 | FLAG_RPM_360 | FLAG_DS | FLAG_HOLE0 | FLAG_HOLE1 | FLAG_DOUBLE_STEP | FLAG_INVERT_DENSEL, "3.5\" 1.25M PC-98", "35_2hd_nec" }, { /*3.5" HD 3-Mode*/ - .max_track = 86, - .flags = FLAG_RPM_300 | FLAG_RPM_360 | FLAG_HOLE0 | FLAG_HOLE1 | FLAG_DOUBLE_STEP + 86, FLAG_RPM_300 | FLAG_RPM_360 | FLAG_DS | FLAG_HOLE0 | FLAG_HOLE1 | FLAG_DOUBLE_STEP, "3.5\" 1.44M 300/360 RPM", "35_2hd_3mode" }, { /*3.5" ED*/ - .max_track = 86, - .flags = FLAG_RPM_300 | FLAG_HOLE0 | FLAG_HOLE1 | FLAG_HOLE2 | FLAG_DOUBLE_STEP + 86, FLAG_RPM_300 | FLAG_DS | FLAG_HOLE0 | FLAG_HOLE1 | FLAG_HOLE2 | FLAG_DOUBLE_STEP, "3.5\" 2.88M", "35_2ed" + }, + { /*End of list*/ + -1, -1, "", "" } }; int fdd_swap = 0; +char *fdd_getname(int type) +{ + return drive_types[type].name; +} + +char *fdd_get_internal_name(int type) +{ + return drive_types[type].internal_name; +} + +int fdd_get_from_internal_name(char *s) +{ + int c = 0; + + while (strlen(drive_types[c].internal_name)) + { + if (!strcmp(drive_types[c].internal_name, s)) + return c; + c++; + } + + return 0; +} + void fdd_forced_seek(int drive, int track_diff) { drive = real_drive(drive); fdd[drive].track += track_diff; - - // pclog("Seeking %i tracks...\n", track_diff); if (fdd[drive].track < 0) fdd[drive].track = 0; @@ -120,8 +168,6 @@ void fdd_seek(int drive, int track_diff) fdd[drive].track += track_diff; - // pclog("Seeking %i tracks...\n", track_diff); - if (fdd[drive].track < 0) fdd[drive].track = 0; @@ -209,7 +255,6 @@ int fdd_can_read_medium(int drive) hole = 1 << (hole + 3); -// pclog("Drive %02X, type %02X, hole flag %02X, flags %02X, result %02X\n", drive, fdd[drive].type, hole, drive_types[fdd[drive].type].flags, drive_types[fdd[drive].type].flags & hole); return (drive_types[fdd[drive].type].flags & hole) ? 1 : 0; } @@ -243,11 +288,21 @@ int fdd_is_525(int drive) return drive_types[fdd[drive].type].flags & FLAG_525; } +int fdd_is_dd(int drive) +{ + return (drive_types[fdd[drive].type].flags & 0x70) == 0x10; +} + int fdd_is_ed(int drive) { return drive_types[fdd[drive].type].flags & FLAG_HOLE2; } +int fdd_is_double_sided(int drive) +{ + return drive_types[fdd[drive].type].flags & FLAG_DS; +} + void fdd_set_head(int drive, int head) { drive = real_drive(drive); @@ -259,6 +314,16 @@ int fdd_get_head(int drive) return fdd[drive].head; } +void fdd_set_turbo(int drive, int turbo) +{ + fdd[drive].turbo = turbo; +} + +int fdd_get_turbo(int drive) +{ + return fdd[drive].turbo; +} + int fdd_get_densel(int drive) { if (drive_types[fdd[drive].type].flags & FLAG_INVERT_DENSEL) diff --git a/src/fdd.h b/src/fdd.h index 131e94bcf..e8de9db96 100644 --- a/src/fdd.h +++ b/src/fdd.h @@ -1,6 +1,21 @@ -/* Copyright holders: Sarah Walker, Tenshi - see COPYING for more details -*/ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Implementation of the floppy drive emulation. + * + * Version: @(#)fdd.h 1.0.0 2017/05/30 + * + * Author: Sarah Walker, + * Miran Grca, + * Copyright 2008-2017 Sarah Walker. + * Copyright 2016-2017 Miran Grca. + */ + #define SEEK_RECALIBRATE -999 void fdd_forced_seek(int drive, int track_diff); void fdd_seek(int drive, int track_diff); @@ -10,9 +25,13 @@ void fdd_set_densel(int densel); int fdd_can_read_medium(int drive); int fdd_doublestep_40(int drive); int fdd_is_525(int drive); +int fdd_is_dd(int drive); int fdd_is_ed(int drive); +int fdd_is_double_sided(int drive); void fdd_set_head(int drive, int head); int fdd_get_head(int drive); +void fdd_set_turbo(int drive, int turbo); +int fdd_get_turbo(int drive); void fdd_set_type(int drive, int type); int fdd_get_type(int drive); @@ -21,4 +40,12 @@ int fdd_get_flags(int drive); extern int fdd_swap; -void fdd_init(); \ No newline at end of file +void fdd_init(); +int fdd_get_densel(int drive); + +void fdd_setswap(int swap); + +char *fdd_getname(int type); + +char *fdd_get_internal_name(int type); +int fdd_get_from_internal_name(char *s); diff --git a/src/fdi2raw.c b/src/fdi2raw.c index a82af5230..68edb5e26 100644 --- a/src/fdi2raw.c +++ b/src/fdi2raw.c @@ -28,7 +28,6 @@ #include "sysdeps.h" #include "zfile.h"*/ /* ELSE */ -//#include "types.h" #define xmalloc malloc #include "fdi2raw.h" @@ -243,26 +242,26 @@ static void fdi_decode (uae_u8 *stream, int size, uae_u8 *out) sub_stream_shift = 1; while (sub_stream_shift) { - //sub-stream header decode + /* sub-stream header decode */ sign_extend = *stream++; sub_stream_shift = sign_extend & 0x7f; sign_extend &= 0x80; sixteen_bit = (*stream++) & 0x80; - //huffman tree architecture decode + /* huffman tree architecture decode */ temp = *stream++; temp2 = 0x80; stream = expand_tree (stream, &root); if (temp2 == 0x80) stream--; - //huffman output values decode + /* huffman output values decode */ if (sixteen_bit) stream = values_tree16 (stream, &root); else stream = values_tree8 (stream, &root); - //sub-stream data decode + /* sub-stream data decode */ temp2 = 0; for (i = 0; i < size; i++) { uae_u32 v; @@ -312,20 +311,18 @@ static int decode_raw_track (FDI *fdi) static void zxx (FDI *fdi) { outlog ("track %d: unknown track type 0x%02.2X\n", fdi->current_track, fdi->track_type); -// return -1; } /* unsupported track */ #if 0 static void zyy (FDI *fdi) { outlog ("track %d: unsupported track type 0x%02.2X\n", fdi->current_track, fdi->track_type); -// return -1; } #endif /* empty track */ static void track_empty (FDI *fdi) { -// return 0; + return; } /* unknown sector described type */ @@ -575,7 +572,6 @@ static void s0d(FDI *fdi) } }*/ -//static int check_offset; /*static uae_u16 getmfmword (uae_u8 *mbuf) { uae_u32 v; @@ -633,7 +629,6 @@ static int amiga_check_track (FDI *fdi) mbuf = bigmfmbuf; memset (sectable, 0, sizeof (sectable)); - //memcpy (mbuf + fwlen, mbuf, fwlen * sizeof (uae_u16)); mend = bigmfmbuf + length; mend -= (4 + 16 + 8 + 512); @@ -648,7 +643,6 @@ static int amiga_check_track (FDI *fdi) mbuf[0] = 0x44; mbuf[1] = 0x89; } -// check_offset++; if (check_offset > 7) { check_offset = 0; mbuf++; @@ -1399,7 +1393,7 @@ static void init_array(uint32_t standard_MFM_2_bit_cell_size, int nb_of_bits) int i; for (i = 0; i < FDI_MAX_ARRAY; i++) { - psarray[i].size = standard_MFM_2_bit_cell_size; // That is (total track length / 50000) for Amiga double density + psarray[i].size = standard_MFM_2_bit_cell_size; /* That is (total track length / 50000) for Amiga double density */ total += psarray[i].size; psarray[i].number_of_bits = nb_of_bits; totaldiv += psarray[i].number_of_bits; @@ -1448,7 +1442,6 @@ static void fdi2_decode (FDI *fdi, uint32_t totalavg, uae_u32 *avgp, uae_u32 *mi /* you can try tighter ranges than 25%, or wider ranges. I would probably go for tighter... */ if ((avg_size < (standard_MFM_8_bit_cell_size - (pulse_limitval * standard_MFM_8_bit_cell_size / 100))) || (avg_size > (standard_MFM_8_bit_cell_size + (pulse_limitval * standard_MFM_8_bit_cell_size / 100)))) { - //init_array(standard_MFM_2_bit_cell_size, 2); avg_size = standard_MFM_8_bit_cell_size; } /* this is to prevent the average value from going too far @@ -1578,7 +1571,6 @@ static void fdi2_decode (FDI *fdi, uint32_t totalavg, uae_u32 *avgp, uae_u32 *mi /* you can try tighter ranges than 25%, or wider ranges. I would probably go for tighter... */ if ((avg_size < (standard_MFM_8_bit_cell_size - (pulse_limitval * standard_MFM_8_bit_cell_size / 100))) || (avg_size > (standard_MFM_8_bit_cell_size + (pulse_limitval * standard_MFM_8_bit_cell_size / 100)))) { - //init_array(standard_MFM_2_bit_cell_size, mfm + 1); avg_size = standard_MFM_8_bit_cell_size; } /* this is to prevent the average value from going too far @@ -1801,16 +1793,15 @@ static void fdi2_celltiming (FDI *fdi, uint32_t totalavg, int bitoffset, uae_u16 static int decode_lowlevel_track (FDI *fdi, int track, struct fdi_cache *cache) { - uae_u8 *p1, *d; + uae_u8 *p1; uae_u32 *p2; uae_u32 *avgp, *minp = 0, *maxp = 0; uae_u8 *idxp = 0; uae_u32 maxidx, totalavg, weakbits; int i, j, len, pulses, indexoffset; int avg_free, min_free = 0, max_free = 0, idx_free; - int idx_off1, idx_off2, idx_off3; + int idx_off1 = 0, idx_off2 = 0, idx_off3 = 0; - d = fdi->track_dst; p1 = fdi->track_src; pulses = get_u32 (p1); if (!pulses) @@ -2077,7 +2068,6 @@ int fdi2raw_loadrevolution_2 (FDI *fdi, uae_u16 *mfmbuf, uae_u16 *tracktiming, i fdi2_decode (fdi, cache->totalavg, cache->avgp, cache->minp, cache->maxp, cache->idxp, cache->maxidx, &idx, cache->pulses, mfm); - //fdi2_gcr_decode (fdi, totalavg, avgp, minp, maxp, idxp, idx_off1, idx_off2, idx_off3, maxidx, pulses); /* outlog("track %d: nbits=%d avg len=%.2f weakbits=%d idx=%d\n", track, bitoffset, (double)cache->totalavg / bitoffset, cache->weakbits, cache->indexoffset); */ len = fdi->out; @@ -2164,8 +2154,6 @@ int fdi2raw_loadtrack (FDI *fdi, uae_u16 *mfmbuf, uae_u16 *tracktiming, int trac } -// amiga_check_track (fdi); - if (fdi->err) return 0; diff --git a/src/fdi2raw.h b/src/fdi2raw.h index 207dabd7e..b8c3201e5 100644 --- a/src/fdi2raw.h +++ b/src/fdi2raw.h @@ -8,7 +8,6 @@ #define uae_u16 uint16_t #define uae_u32 uint32_t -//#include "types.h" #include typedef struct fdi FDI; diff --git a/src/gameport.c b/src/gameport.c index 6fa788491..a80d962b7 100644 --- a/src/gameport.c +++ b/src/gameport.c @@ -4,31 +4,33 @@ #include #include #include "ibm.h" +#include "cpu/cpu.h" #include "device.h" #include "io.h" -#include "plat-joystick.h" #include "timer.h" - #include "gameport.h" #include "joystick_ch_flightstick_pro.h" #include "joystick_standard.h" #include "joystick_sw_pad.h" #include "joystick_tm_fcs.h" +#include "plat_joystick.h" + int joystick_type; + joystick_if_t joystick_none = { - .name = "No joystick", - .init = NULL, - .close = NULL, - .read = NULL, - .write = NULL, - .read_axis = NULL, - .a0_over = NULL, - .max_joysticks = 0, - .axis_count = 0, - .button_count = 0 + "No joystick", + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + 0, + 0, + 0 }; static joystick_if_t *joystick_list[] = @@ -122,7 +124,7 @@ void gameport_write(uint16_t addr, uint8_t val, void *p) timer_clock(); gameport->state |= 0x0f; -// pclog("gameport_write : joysticks_present=%i\n", joysticks_present); + pclog("gameport_write : joysticks_present=%i\n", joysticks_present); gameport->axis[0].count = gameport_time(gameport->joystick->read_axis(gameport->joystick_dat, 0)); gameport->axis[1].count = gameport_time(gameport->joystick->read_axis(gameport->joystick_dat, 1)); @@ -140,12 +142,7 @@ uint8_t gameport_read(uint16_t addr, void *p) uint8_t ret; timer_clock(); -// if (joysticks_present) - ret = gameport->state | gameport->joystick->read(gameport->joystick_dat);//0xf0; -// else -// ret = 0xff; - -// pclog("gameport_read: ret=%02x %08x:%08x isa_cycles=%i %i\n", ret, cs, cpu_state.pc, isa_cycles, gameport->axis[0].count); + ret = gameport->state | gameport->joystick->read(gameport->joystick_dat); cycles -= ISA_CYCLES(8); diff --git a/src/hdd.c b/src/hdd.c new file mode 100644 index 000000000..7fdb21d95 --- /dev/null +++ b/src/hdd.c @@ -0,0 +1,108 @@ +#include "ibm.h" +#include "CPU/cpu.h" +#include "device.h" +#include "hdd.h" +#include "model.h" + +#include "hdd_esdi.h" +#include "mfm_at.h" +#include "mfm_xebec.h" +#include "xtide.h" + +char hdd_controller_name[16]; + +static device_t null_hdd_device; + +static int hdd_controller_current; + +hard_disk_t hdc[HDC_NUM]; + +static struct +{ + char name[50]; + char internal_name[16]; + device_t *device; + int is_mfm; +} hdd_controllers[] = +{ + {"None", "none", &null_hdd_device, 0}, + {"AT Fixed Disk Adapter", "mfm_at", &mfm_at_device, 1}, + {"DTC 5150X", "dtc5150x", &dtc_5150x_device, 1}, + {"Fixed Disk Adapter (Xebec)", "mfm_xebec", &mfm_xebec_device, 1}, + {"IBM ESDI Fixed Disk Adapter (MCA)", "esdi_mca", &hdd_esdi_device, 1}, + {"XTIDE", "xtide", &xtide_device, 0}, + {"XTIDE (AT)", "xtide_at", &xtide_at_device, 0}, + {"XTIDE (PS/2)", "xtide_ps2",&xtide_ps2_device,0}, + {"XTIDE (AT) (PS/2)", "xtide_at_ps2",&xtide_at_ps2_device,0}, + {"", "", NULL, 0} +}; + +char *hdd_controller_get_name(int hdd) +{ + return hdd_controllers[hdd].name; +} + +char *hdd_controller_get_internal_name(int hdd) +{ + return hdd_controllers[hdd].internal_name; +} + +int hdd_controller_get_flags(int hdd) +{ + return hdd_controllers[hdd].device->flags; +} + +int hdd_controller_available(int hdd) +{ + return device_available(hdd_controllers[hdd].device); +} + +int hdd_controller_current_is_mfm() +{ + return hdd_controllers[hdd_controller_current].is_mfm; +} + +void hdd_controller_init(char *internal_name) +{ + int c = 0; + + if (models[model].flags & MODEL_HAS_IDE) + { + return; + } + + while (hdd_controllers[c].device) + { + if (!strcmp(internal_name, hdd_controllers[c].internal_name)) + { + hdd_controller_current = c; + if (strcmp(internal_name, "none")) + device_add(hdd_controllers[c].device); + return; + } + c++; + } +} + + +static void *null_hdd_init() +{ + return NULL; +} + +static void null_hdd_close(void *p) +{ +} + +static device_t null_hdd_device = +{ + "Null HDD controller", + 0, + null_hdd_init, + null_hdd_close, + NULL, + NULL, + NULL, + NULL, + NULL +}; diff --git a/src/hdd.h b/src/hdd.h new file mode 100644 index 000000000..605118623 --- /dev/null +++ b/src/hdd.h @@ -0,0 +1,8 @@ +char *hdd_controller_get_name(int hdd); +char *hdd_controller_get_internal_name(int hdd); +int hdd_controller_get_flags(int hdd); +int hdd_controller_available(int hdd); +int hdd_controller_current_is_mfm(); +void hdd_controller_init(char *internal_name); + +extern char hdd_controller_name[16]; diff --git a/src/hdd_esdi.c b/src/hdd_esdi.c new file mode 100644 index 000000000..4f31c8836 --- /dev/null +++ b/src/hdd_esdi.c @@ -0,0 +1,877 @@ +#include +#include "ibm.h" + +#include "device.h" +#include "dma.h" +#include "hdd_image.h" +#include "io.h" +#include "mca.h" +#include "mem.h" +#include "pic.h" +#include "rom.h" +#include "timer.h" + +#include "hdd_esdi.h" + +#define ESDI_TIME (2000 * TIMER_USEC) + +#define CMD_ADAPTER 0 + +typedef struct esdi_drive_t +{ + int spt, hpc; + int tracks; + int sectors; + int present; + int hdc_num; +} esdi_drive_t; + +typedef struct esdi_t +{ + rom_t bios_rom; + + uint8_t basic_ctrl; + uint8_t status; + uint8_t irq_status; + + int irq_in_progress; + int cmd_req_in_progress; + + int cmd_pos; + uint16_t cmd_data[4]; + int cmd_dev; + + int status_pos, status_len; + uint16_t status_data[256]; + + int data_pos; + uint16_t data[256]; + + uint16_t sector_buffer[256][256]; + + int sector_pos; + int sector_count; + + int command; + int cmd_state; + + int in_reset; + int callback; + + uint32_t rba; + + struct + { + int req_in_progress; + } cmds[3]; + + esdi_drive_t drives[2]; + + uint8_t pos_regs[8]; +} esdi_t; + +#define STATUS_DMA_ENA (1 << 7) +#define STATUS_IRQ_PENDING (1 << 6) +#define STATUS_CMD_IN_PROGRESS (1 << 5) +#define STATUS_BUSY (1 << 4) +#define STATUS_STATUS_OUT_FULL (1 << 3) +#define STATUS_CMD_IR_FULL (1 << 2) +#define STATUS_TRANSFER_REQ (1 << 1) +#define STATUS_IRQ (1 << 0) + +#define CTRL_RESET (1 << 7) +#define CTRL_DMA_ENA (1 << 1) +#define CTRL_IRQ_ENA (1 << 0) + +#define IRQ_HOST_ADAPTER (7 << 5) +#define IRQ_DEVICE_0 (0 << 5) +#define IRQ_CMD_COMPLETE_SUCCESS 0x1 +#define IRQ_RESET_COMPLETE 0xa +#define IRQ_DATA_TRANSFER_READY 0xb +#define IRQ_CMD_COMPLETE_FAILURE 0xc + +#define ATTN_DEVICE_SEL (7 << 5) +#define ATTN_HOST_ADAPTER (7 << 5) +#define ATTN_DEVICE_0 (0 << 5) +#define ATTN_DEVICE_1 (1 << 5) +#define ATTN_REQ_MASK 0xf +#define ATTN_CMD_REQ 1 +#define ATTN_EOI 2 +#define ATTN_RESET 4 + +#define CMD_SIZE_4 (1 << 14) + +#define CMD_DEVICE_SEL (7 << 5) +#define CMD_MASK 0x1f +#define CMD_READ 0x01 +#define CMD_WRITE 0x02 +#define CMD_READ_VERIFY 0x03 +#define CMD_WRITE_VERIFY 0x04 +#define CMD_SEEK 0x05 +#define CMD_GET_DEV_CONFIG 0x09 +#define CMD_GET_POS_INFO 0x0a + +#define STATUS_LEN(x) ((x) << 8) +#define STATUS_DEVICE_HOST_ADAPTER (7 << 5) + +static __inline void esdi_set_irq(esdi_t *esdi) +{ + if (esdi->basic_ctrl & CTRL_IRQ_ENA) + picint(1 << 14); +} +static __inline void esdi_clear_irq() +{ + picintc(1 << 14); +} + +static uint8_t esdi_read(uint16_t port, void *p) +{ + esdi_t *esdi = (esdi_t *)p; + uint8_t temp = 0xff; + + switch (port) + { + case 0x3512: /*Basic status register*/ + temp = esdi->status; + break; + case 0x3513: /*IRQ status*/ + esdi->status &= ~STATUS_IRQ; + temp = esdi->irq_status; + break; + + default: + fatal("esdi_read port=%04x\n", port); + } + + return temp; +} + +static void esdi_write(uint16_t port, uint8_t val, void *p) +{ + esdi_t *esdi = (esdi_t *)p; + + switch (port) + { + case 0x3512: /*Basic control register*/ + if ((esdi->basic_ctrl & CTRL_RESET) && !(val & CTRL_RESET)) + { + esdi->in_reset = 1; + esdi->callback = ESDI_TIME * 50; + esdi->status = STATUS_BUSY; + } + esdi->basic_ctrl = val; + if (!(esdi->basic_ctrl & CTRL_IRQ_ENA)) + picintc(1 << 14); + break; + case 0x3513: /*Attention register*/ + switch (val & ATTN_DEVICE_SEL) + { + case ATTN_HOST_ADAPTER: + switch (val & ATTN_REQ_MASK) + { + case ATTN_CMD_REQ: + if (esdi->cmd_req_in_progress) + fatal("Try to start command on in_progress adapter\n"); + esdi->cmd_req_in_progress = 1; + esdi->cmd_dev = ATTN_HOST_ADAPTER; + esdi->status |= STATUS_BUSY; + esdi->cmd_pos = 0; + break; + + case ATTN_EOI: + esdi->irq_in_progress = 0; + esdi->status &= ~STATUS_IRQ; + esdi_clear_irq(); + break; + + case ATTN_RESET: + esdi->in_reset = 1; + esdi->callback = ESDI_TIME * 50; + esdi->status = STATUS_BUSY; + break; + + default: + fatal("Bad attention request %02x\n", val); + } + break; + + case ATTN_DEVICE_0: + switch (val & ATTN_REQ_MASK) + { + case ATTN_CMD_REQ: + if (esdi->cmd_req_in_progress) + fatal("Try to start command on in_progress device0\n"); + esdi->cmd_req_in_progress = 1; + esdi->cmd_dev = ATTN_DEVICE_0; + esdi->status |= STATUS_BUSY; + esdi->cmd_pos = 0; + break; + + case ATTN_EOI: + esdi->irq_in_progress = 0; + esdi->status &= ~STATUS_IRQ; + esdi_clear_irq(); + break; + + default: + fatal("Bad attention request %02x\n", val); + } + break; + + case ATTN_DEVICE_1: + switch (val & ATTN_REQ_MASK) + { + case ATTN_CMD_REQ: + if (esdi->cmd_req_in_progress) + fatal("Try to start command on in_progress device0\n"); + esdi->cmd_req_in_progress = 1; + esdi->cmd_dev = ATTN_DEVICE_1; + esdi->status |= STATUS_BUSY; + esdi->cmd_pos = 0; + break; + + case ATTN_EOI: + esdi->irq_in_progress = 0; + esdi->status &= ~STATUS_IRQ; + esdi_clear_irq(); + break; + + default: + fatal("Bad attention request %02x\n", val); + } + break; + + default: + fatal("Attention to unknown device %02x\n", val); + } + break; + + default: + fatal("esdi_write port=%04x val=%02x\n", port, val); + } +} + +static uint16_t esdi_readw(uint16_t port, void *p) +{ + esdi_t *esdi = (esdi_t *)p; + uint16_t temp = 0xffff; + + switch (port) + { + case 0x3510: /*Status Interface Register*/ + if (esdi->status_pos >= esdi->status_len) + return 0; + temp = esdi->status_data[esdi->status_pos++]; + if (esdi->status_pos >= esdi->status_len) + { + esdi->status &= ~STATUS_STATUS_OUT_FULL; + esdi->status_pos = esdi->status_len = 0; + } + break; + + default: + fatal("esdi_readw port=%04x\n", port); + } + + return temp; +} + +static void esdi_writew(uint16_t port, uint16_t val, void *p) +{ + esdi_t *esdi = (esdi_t *)p; + + switch (port) + { + case 0x3510: /*Command Interface Register*/ + if (esdi->cmd_pos >= 4) + fatal("CIR pos 4\n"); + esdi->cmd_data[esdi->cmd_pos++] = val; + if ( ((esdi->cmd_data[0] & CMD_SIZE_4) && esdi->cmd_pos == 4) || + (!(esdi->cmd_data[0] & CMD_SIZE_4) && esdi->cmd_pos == 2)) + { + + esdi->cmd_pos = 0; + esdi->cmd_req_in_progress = 0; + esdi->cmd_state = 0; + + if ((esdi->cmd_data[0] & CMD_DEVICE_SEL) != esdi->cmd_dev) + fatal("Command device mismatch with attn\n"); + esdi->command = esdi->cmd_data[0] & CMD_MASK; + esdi->callback = ESDI_TIME; + esdi->status = STATUS_BUSY; + esdi->data_pos = 0; + } + break; + + default: + fatal("esdi_writew port=%04x val=%04x\n", port, val); + } +} + +static void cmd_unsupported(esdi_t *esdi) +{ + esdi->status_len = 9; + esdi->status_data[0] = esdi->command | STATUS_LEN(9) | esdi->cmd_dev; + esdi->status_data[1] = 0x0f03; /*Attention error, command not supported*/ + esdi->status_data[2] = 0x0002; /*Interface fault*/ + esdi->status_data[3] = 0; + esdi->status_data[4] = 0; + esdi->status_data[5] = 0; + esdi->status_data[6] = 0; + esdi->status_data[7] = 0; + esdi->status_data[8] = 0; + + esdi->status = STATUS_IRQ | STATUS_STATUS_OUT_FULL; + esdi->irq_status = esdi->cmd_dev | IRQ_CMD_COMPLETE_FAILURE; + esdi->irq_in_progress = 1; + esdi_set_irq(esdi); +} + +static void device_not_present(esdi_t *esdi) +{ + esdi->status_len = 9; + esdi->status_data[0] = esdi->command | STATUS_LEN(9) | esdi->cmd_dev; + esdi->status_data[1] = 0x0c11; /*Command failed, internal hardware error*/ + esdi->status_data[2] = 0x000b; /*Selection error*/ + esdi->status_data[3] = 0; + esdi->status_data[4] = 0; + esdi->status_data[5] = 0; + esdi->status_data[6] = 0; + esdi->status_data[7] = 0; + esdi->status_data[8] = 0; + + esdi->status = STATUS_IRQ | STATUS_STATUS_OUT_FULL; + esdi->irq_status = esdi->cmd_dev | IRQ_CMD_COMPLETE_FAILURE; + esdi->irq_in_progress = 1; + esdi_set_irq(esdi); +} + +#define ESDI_ADAPTER_ONLY() do \ + { \ + if (esdi->cmd_dev != ATTN_HOST_ADAPTER) \ + { \ + cmd_unsupported(esdi); \ + return; \ + } \ + } while (0) + +#define ESDI_DRIVE_ONLY() do \ + { \ + if (esdi->cmd_dev != ATTN_DEVICE_0 && esdi->cmd_dev != ATTN_DEVICE_1) \ + { \ + cmd_unsupported(esdi); \ + return; \ + } \ + if (esdi->cmd_dev == ATTN_DEVICE_0) \ + drive = &esdi->drives[0]; \ + else \ + drive = &esdi->drives[1]; \ + } while (0) + +static void esdi_callback(void *p) +{ + esdi_t *esdi = (esdi_t *)p; + esdi_drive_t *drive; + + esdi->callback = 0; + + if (esdi->in_reset) + { + esdi->in_reset = 0; + esdi->status = STATUS_IRQ; + esdi->irq_status = IRQ_HOST_ADAPTER | IRQ_RESET_COMPLETE; + + return; + } + switch (esdi->command) + { + case CMD_READ: + ESDI_DRIVE_ONLY(); + + if (!drive->present) + { + device_not_present(esdi); + return; + } + + switch (esdi->cmd_state) + { + case 0: + esdi->rba = (esdi->cmd_data[2] | (esdi->cmd_data[3] << 16)) & 0x0fffffff; + + esdi->sector_pos = 0; + esdi->sector_count = esdi->cmd_data[1]; + + esdi->status = STATUS_IRQ | STATUS_CMD_IN_PROGRESS | STATUS_TRANSFER_REQ; + esdi->irq_status = esdi->cmd_dev | IRQ_DATA_TRANSFER_READY; + esdi->irq_in_progress = 1; + esdi_set_irq(esdi); + + esdi->cmd_state = 1; + esdi->callback = ESDI_TIME; + esdi->data_pos = 0; + break; + + case 1: + if (!(esdi->basic_ctrl & CTRL_DMA_ENA)) + { + esdi->callback = ESDI_TIME; + return; + } + while (esdi->sector_pos < esdi->sector_count) + { + if (!esdi->data_pos) + { + if (esdi->rba >= drive->sectors) + fatal("Read past end of drive\n"); + hdd_image_read(drive->hdc_num, esdi->rba, 1, (uint8_t *) esdi->data); + update_status_bar_icon(SB_HDD | HDD_BUS_RLL, 1); + } + while (esdi->data_pos < 256) + { + int val = dma_channel_write(5, esdi->data[esdi->data_pos]); + + if (val == DMA_NODATA) + { + esdi->callback = ESDI_TIME; + return; + } + + esdi->data_pos++; + } + + esdi->data_pos = 0; + esdi->sector_pos++; + esdi->rba++; + } + + esdi->status = STATUS_CMD_IN_PROGRESS; + esdi->cmd_state = 2; + esdi->callback = ESDI_TIME; + break; + + case 2: + esdi->status = STATUS_IRQ; + esdi->irq_status = esdi->cmd_dev | IRQ_CMD_COMPLETE_SUCCESS; + esdi->irq_in_progress = 1; + esdi_set_irq(esdi); + break; + } + break; + + case CMD_WRITE: + case CMD_WRITE_VERIFY: + ESDI_DRIVE_ONLY(); + + if (!drive->present) + { + device_not_present(esdi); + return; + } + + switch (esdi->cmd_state) + { + case 0: + esdi->rba = (esdi->cmd_data[2] | (esdi->cmd_data[3] << 16)) & 0x0fffffff; + + esdi->sector_pos = 0; + esdi->sector_count = esdi->cmd_data[1]; + + esdi->status = STATUS_IRQ | STATUS_CMD_IN_PROGRESS | STATUS_TRANSFER_REQ; + esdi->irq_status = esdi->cmd_dev | IRQ_DATA_TRANSFER_READY; + esdi->irq_in_progress = 1; + esdi_set_irq(esdi); + + esdi->cmd_state = 1; + esdi->callback = ESDI_TIME; + esdi->data_pos = 0; + break; + + case 1: + if (!(esdi->basic_ctrl & CTRL_DMA_ENA)) + { + esdi->callback = ESDI_TIME; + return; + } + while (esdi->sector_pos < esdi->sector_count) + { + while (esdi->data_pos < 256) + { + int val = dma_channel_read(5); + + if (val == DMA_NODATA) + { + esdi->callback = ESDI_TIME; + return; + } + + esdi->data[esdi->data_pos++] = val & 0xffff; + } + + if (esdi->rba >= drive->sectors) + fatal("Write past end of drive\n"); + hdd_image_write(drive->hdc_num, esdi->rba, 1, (uint8_t *) esdi->data); + esdi->rba++; + esdi->sector_pos++; + update_status_bar_icon(SB_HDD | HDD_BUS_RLL, 1); + + esdi->data_pos = 0; + } + update_status_bar_icon(SB_HDD | HDD_BUS_RLL, 0); + + esdi->status = STATUS_CMD_IN_PROGRESS; + esdi->cmd_state = 2; + esdi->callback = ESDI_TIME; + break; + + case 2: + esdi->status = STATUS_IRQ; + esdi->irq_status = esdi->cmd_dev | IRQ_CMD_COMPLETE_SUCCESS; + esdi->irq_in_progress = 1; + esdi_set_irq(esdi); + break; + } + break; + + case CMD_READ_VERIFY: + ESDI_DRIVE_ONLY(); + + if (!drive->present) + { + device_not_present(esdi); + return; + } + + esdi->status = STATUS_IRQ; + esdi->irq_status = esdi->cmd_dev | IRQ_CMD_COMPLETE_SUCCESS; + esdi->irq_in_progress = 1; + esdi_set_irq(esdi); + break; + + case CMD_SEEK: + ESDI_DRIVE_ONLY(); + + if (!drive->present) + { + device_not_present(esdi); + return; + } + + esdi->status = STATUS_IRQ; + esdi->irq_status = esdi->cmd_dev | IRQ_CMD_COMPLETE_SUCCESS; + esdi->irq_in_progress = 1; + esdi_set_irq(esdi); + break; + + case CMD_GET_DEV_CONFIG: + ESDI_DRIVE_ONLY(); + + if (!drive->present) + { + device_not_present(esdi); + return; + } + + if (esdi->status_pos) + fatal("Status send in progress\n"); + if ((esdi->status & STATUS_IRQ) || esdi->irq_in_progress) + fatal("IRQ in progress %02x %i\n", esdi->status, esdi->irq_in_progress); + + esdi->status_len = 6; + esdi->status_data[0] = CMD_GET_POS_INFO | STATUS_LEN(6) | STATUS_DEVICE_HOST_ADAPTER; + esdi->status_data[1] = 0x10; /*Zero defect*/ + esdi->status_data[2] = drive->sectors & 0xffff; + esdi->status_data[3] = drive->sectors >> 16; + esdi->status_data[4] = drive->tracks; + esdi->status_data[5] = drive->hpc | (drive->spt << 16); + +/* pclog("CMD_GET_DEV_CONFIG %i %04x %04x %04x %04x %04x %04x\n", drive->sectors, + esdi->status_data[0], esdi->status_data[1], + esdi->status_data[2], esdi->status_data[3], + esdi->status_data[4], esdi->status_data[5]);*/ + + esdi->status = STATUS_IRQ | STATUS_STATUS_OUT_FULL; + esdi->irq_status = esdi->cmd_dev | IRQ_CMD_COMPLETE_SUCCESS; + esdi->irq_in_progress = 1; + esdi_set_irq(esdi); + break; + + case CMD_GET_POS_INFO: + ESDI_ADAPTER_ONLY(); + if (esdi->status_pos) + fatal("Status send in progress\n"); + if ((esdi->status & STATUS_IRQ) || esdi->irq_in_progress) + fatal("IRQ in progress %02x %i\n", esdi->status, esdi->irq_in_progress); + + esdi->status_len = 5; + esdi->status_data[0] = CMD_GET_POS_INFO | STATUS_LEN(5) | STATUS_DEVICE_HOST_ADAPTER; + esdi->status_data[1] = 0xffdd; /*MCA ID*/ + esdi->status_data[2] = esdi->pos_regs[3] | (esdi->pos_regs[2] << 8); + esdi->status_data[3] = 0xff; + esdi->status_data[4] = 0xff; + + esdi->status = STATUS_IRQ | STATUS_STATUS_OUT_FULL; + esdi->irq_status = IRQ_HOST_ADAPTER | IRQ_CMD_COMPLETE_SUCCESS; + esdi->irq_in_progress = 1; + esdi_set_irq(esdi); + break; + + case 0x11: + ESDI_ADAPTER_ONLY(); + switch (esdi->cmd_state) + { + case 0: + esdi->sector_pos = 0; + esdi->sector_count = esdi->cmd_data[1]; + if (esdi->sector_count > 256) + fatal("Read sector buffer count %04x\n", esdi->cmd_data[1]); + + esdi->status = STATUS_IRQ | STATUS_CMD_IN_PROGRESS | STATUS_TRANSFER_REQ; + esdi->irq_status = IRQ_HOST_ADAPTER | IRQ_DATA_TRANSFER_READY; + esdi->irq_in_progress = 1; + esdi_set_irq(esdi); + + esdi->cmd_state = 1; + esdi->callback = ESDI_TIME; + esdi->data_pos = 0; + break; + + case 1: + if (!(esdi->basic_ctrl & CTRL_DMA_ENA)) + { + esdi->callback = ESDI_TIME; + return; + } + while (esdi->sector_pos < esdi->sector_count) + { + if (!esdi->data_pos) + memcpy(esdi->data, esdi->sector_buffer[esdi->sector_pos++], 512); + while (esdi->data_pos < 256) + { + int val = dma_channel_write(5, esdi->data[esdi->data_pos]); + + if (val == DMA_NODATA) + { + esdi->callback = ESDI_TIME; + return; + } + + esdi->data_pos++; + } + + esdi->data_pos = 0; + } + + esdi->status = STATUS_CMD_IN_PROGRESS; + esdi->cmd_state = 2; + esdi->callback = ESDI_TIME; + break; + + case 2: + esdi->status = STATUS_IRQ; + esdi->irq_status = IRQ_HOST_ADAPTER | IRQ_CMD_COMPLETE_SUCCESS; + esdi->irq_in_progress = 1; + esdi_set_irq(esdi); + break; + } + break; + + case 0x10: + ESDI_ADAPTER_ONLY(); + switch (esdi->cmd_state) + { + case 0: + esdi->sector_pos = 0; + esdi->sector_count = esdi->cmd_data[1]; + if (esdi->sector_count > 256) + fatal("Write sector buffer count %04x\n", esdi->cmd_data[1]); + + esdi->status = STATUS_IRQ | STATUS_CMD_IN_PROGRESS | STATUS_TRANSFER_REQ; + esdi->irq_status = IRQ_HOST_ADAPTER | IRQ_DATA_TRANSFER_READY; + esdi->irq_in_progress = 1; + esdi_set_irq(esdi); + + esdi->cmd_state = 1; + esdi->callback = ESDI_TIME; + esdi->data_pos = 0; + break; + + case 1: + if (!(esdi->basic_ctrl & CTRL_DMA_ENA)) + { + esdi->callback = ESDI_TIME; + return; + } + while (esdi->sector_pos < esdi->sector_count) + { + while (esdi->data_pos < 256) + { + int val = dma_channel_read(5); + + if (val == DMA_NODATA) + { + esdi->callback = ESDI_TIME; + return; + } + + esdi->data[esdi->data_pos++] = val & 0xffff;; + } + + memcpy(esdi->sector_buffer[esdi->sector_pos++], esdi->data, 512); + esdi->data_pos = 0; + } + + esdi->status = STATUS_CMD_IN_PROGRESS; + esdi->cmd_state = 2; + esdi->callback = ESDI_TIME; + break; + + case 2: + esdi->status = STATUS_IRQ; + esdi->irq_status = IRQ_HOST_ADAPTER | IRQ_CMD_COMPLETE_SUCCESS; + esdi->irq_in_progress = 1; + esdi_set_irq(esdi); + break; + } + break; + + case 0x12: + ESDI_ADAPTER_ONLY(); + if (esdi->status_pos) + fatal("Status send in progress\n"); + if ((esdi->status & STATUS_IRQ) || esdi->irq_in_progress) + fatal("IRQ in progress %02x %i\n", esdi->status, esdi->irq_in_progress); + + esdi->status_len = 2; + esdi->status_data[0] = 0x12 | STATUS_LEN(5) | STATUS_DEVICE_HOST_ADAPTER; + esdi->status_data[1] = 0; + + esdi->status = STATUS_IRQ | STATUS_STATUS_OUT_FULL; + esdi->irq_status = IRQ_HOST_ADAPTER | IRQ_CMD_COMPLETE_SUCCESS; + esdi->irq_in_progress = 1; + esdi_set_irq(esdi); + break; + + default: + fatal("Bad command %02x %i\n", esdi->command, esdi->cmd_dev); + + } +} + +static uint8_t esdi_mca_read(int port, void *p) +{ + esdi_t *esdi = (esdi_t *)p; + + return esdi->pos_regs[port & 7]; +} + +static void esdi_mca_write(int port, uint8_t val, void *p) +{ + esdi_t *esdi = (esdi_t *)p; + + if (port < 0x102) + return; + + esdi->pos_regs[port & 7] = val; + + io_removehandler(0x3510, 0x0008, esdi_read, esdi_readw, NULL, esdi_write, esdi_writew, NULL, esdi); + mem_mapping_disable(&esdi->bios_rom.mapping); + if (esdi->pos_regs[2] & 1) + { + io_sethandler(0x3510, 0x0008, esdi_read, esdi_readw, NULL, esdi_write, esdi_writew, NULL, esdi); + if (!(esdi->pos_regs[3] & 8)) + { + mem_mapping_enable(&esdi->bios_rom.mapping); + mem_mapping_set_addr(&esdi->bios_rom.mapping, ((esdi->pos_regs[3] & 7) * 0x4000) + 0xc0000, 0x4000); + } + } +} + +static void loadhd(esdi_t *esdi, int hdc_num, int d, const wchar_t *fn) +{ + esdi_drive_t *drive = &esdi->drives[d]; + int ret = 0; + + ret = hdd_image_load(hdc_num); + + if (!ret) + { + drive->present = 0; + return; + } + + drive->spt = hdc[hdc_num].spt; + drive->hpc = hdc[hdc_num].hpc; + drive->tracks = hdc[hdc_num].tracks; + drive->sectors = hdc[hdc_num].spt * hdc[hdc_num].hpc * hdc[hdc_num].tracks; + drive->hdc_num = hdc_num; + drive->present = 1; +} + +static void *esdi_init() +{ + int i = 0; + int c = 0; + + esdi_t *esdi = malloc(sizeof(esdi_t)); + memset(esdi, 0, sizeof(esdi_t)); + + rom_init_interleaved(&esdi->bios_rom, L"roms/90x8970.bin", L"roms/90x8969.bin", 0xc8000, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL); + mem_mapping_disable(&esdi->bios_rom.mapping); + + for (i = 0; i < HDC_NUM; i++) + { + if ((hdc[i].bus == HDD_BUS_RLL) && (hdc[i].rll_channel < RLL_NUM)) + { + loadhd(esdi, i, hdc[i].rll_channel, hdc[i].fn); + c++; + if (c >= RLL_NUM) break; + } + } + + timer_add(esdi_callback, &esdi->callback, &esdi->callback, esdi); + + mca_add(esdi_mca_read, esdi_mca_write, esdi); + + esdi->pos_regs[0] = 0xff; + esdi->pos_regs[1] = 0xdd; + + esdi->in_reset = 1; + esdi->callback = ESDI_TIME * 50; + esdi->status = STATUS_BUSY; + + return esdi; +} + +static void esdi_close(void *p) +{ + esdi_t *esdi = (esdi_t *)p; + int d; + + for (d = 0; d < 2; d++) + { + esdi_drive_t *drive = &esdi->drives[d]; + + hdd_image_close(drive->hdc_num); + } + + free(esdi); +} + +static int esdi_available() +{ + return rom_present(L"roms/90x8969.bin") && rom_present(L"roms/90x8970.bin"); +} + +device_t hdd_esdi_device = +{ + "IBM ESDI Fixed Disk Adapter (MCA)", + DEVICE_MCA, + esdi_init, + esdi_close, + esdi_available, + NULL, + NULL, + NULL, + NULL +}; diff --git a/src/hdd_esdi.h b/src/hdd_esdi.h new file mode 100644 index 000000000..4fea361bd --- /dev/null +++ b/src/hdd_esdi.h @@ -0,0 +1 @@ +extern device_t hdd_esdi_device; diff --git a/src/hdd_image.c b/src/hdd_image.c new file mode 100644 index 000000000..ff047fc80 --- /dev/null +++ b/src/hdd_image.c @@ -0,0 +1,445 @@ +#define _LARGEFILE_SOURCE +#define _LARGEFILE64_SOURCE +#define _GNU_SOURCE +#include +#include +#include +#include +#include + +#include "ibm.h" +#include "ide.h" +#include "hdd_image.h" + +typedef struct +{ + FILE *file; + uint32_t base; + uint32_t last_sector; + uint8_t type; + uint8_t loaded; +} hdd_image_t; + +hdd_image_t hdd_images[HDC_NUM]; + +static char empty_sector[512]; +static char *empty_sector_1mb; + +int hdd_image_do_log = 0; + +void hdd_image_log(const char *format, ...) +{ +#ifdef ENABLE_HDD_IMAGE_LOG + if (hdd_image_do_log) + { + va_list ap; + va_start(ap, format); + vprintf(format, ap); + va_end(ap); + fflush(stdout); + } +#endif +} + +int image_is_hdi(const wchar_t *s) +{ + int len; + wchar_t ext[5] = { 0, 0, 0, 0, 0 }; + char *ws = (char *) s; + len = wcslen(s); + if ((len < 4) || (s[0] == L'.')) + { + return 0; + } + memcpy(ext, ws + ((len - 4) << 1), 8); + if (wcsicmp(ext, L".HDI") == 0) + { + return 1; + } + else + { + return 0; + } +} + +int image_is_hdx(const wchar_t *s, int check_signature) +{ + int len; + FILE *f; + uint64_t filelen; + uint64_t signature; + char *ws = (char *) s; + wchar_t ext[5] = { 0, 0, 0, 0, 0 }; + len = wcslen(s); + if ((len < 4) || (s[0] == L'.')) + { + return 0; + } + memcpy(ext, ws + ((len - 4) << 1), 8); + if (wcsicmp(ext, L".HDX") == 0) + { + if (check_signature) + { + f = _wfopen(s, L"rb"); + if (!f) + { + return 0; + } + fseeko64(f, 0, SEEK_END); + filelen = ftello64(f); + fseeko64(f, 0, SEEK_SET); + if (filelen < 44) + { + return 0; + } + fread(&signature, 1, 8, f); + fclose(f); + if (signature == 0xD778A82044445459ll) + { + return 1; + } + else + { + return 0; + } + } + else + { + return 1; + } + } + else + { + return 0; + } +} + +int hdd_image_load(int id) +{ + uint32_t sector_size = 512; + uint32_t zero = 0; + uint64_t signature = 0xD778A82044445459ll; + uint64_t full_size = 0; + uint64_t spt = 0, hpc = 0, tracks = 0; + int c; + uint64_t i = 0, s = 0, t = 0; + wchar_t *fn = hdc[id].fn; + int is_hdx[2] = { 0, 0 }; + + memset(empty_sector, 0, sizeof(empty_sector)); + + hdd_images[id].base = 0; + + if (hdd_images[id].loaded) + { + fclose(hdd_images[id].file); + hdd_images[id].file = NULL; + hdd_images[id].loaded = 0; + } + + is_hdx[0] = image_is_hdx(fn, 0); + is_hdx[1] = image_is_hdx(fn, 1); + + /* Try to open existing hard disk image */ + if (fn[0] == '.') + { + hdd_image_log("File name starts with .\n"); + memset(hdc[id].fn, 0, sizeof(hdc[id].fn)); + return 0; + } + hdd_images[id].file = _wfopen(fn, L"rb+"); + if (hdd_images[id].file == NULL) + { + /* Failed to open existing hard disk image */ + if (errno == ENOENT) + { + /* Failed because it does not exist, + so try to create new file */ + if (hdc[id].wp) + { + hdd_image_log("A write-protected image must exist\n"); + memset(hdc[id].fn, 0, sizeof(hdc[id].fn)); + return 0; + } + + hdd_images[id].file = _wfopen(fn, L"wb+"); + if (hdd_images[id].file == NULL) + { + hdd_image_log("Unable to open image\n"); + memset(hdc[id].fn, 0, sizeof(hdc[id].fn)); + return 0; + } + else + { + if (image_is_hdi(fn)) + { + full_size = hdc[id].spt * hdc[id].hpc * hdc[id].tracks * 512; + hdd_images[id].base = 0x1000; + fwrite(&zero, 1, 4, hdd_images[id].file); + fwrite(&zero, 1, 4, hdd_images[id].file); + fwrite(&(hdd_images[id].base), 1, 4, hdd_images[id].file); + fwrite(&full_size, 1, 4, hdd_images[id].file); + fwrite(§or_size, 1, 4, hdd_images[id].file); + fwrite(&(hdc[id].spt), 1, 4, hdd_images[id].file); + fwrite(&(hdc[id].hpc), 1, 4, hdd_images[id].file); + fwrite(&(hdc[id].tracks), 1, 4, hdd_images[id].file); + for (c = 0; c < 0x3f8; c++) + { + fwrite(&zero, 1, 4, hdd_images[id].file); + } + hdd_images[id].type = 1; + } + else if (is_hdx[0]) + { + full_size = hdc[id].spt * hdc[id].hpc * hdc[id].tracks * 512; + hdd_images[id].base = 0x28; + fwrite(&signature, 1, 8, hdd_images[id].file); + fwrite(&full_size, 1, 8, hdd_images[id].file); + fwrite(§or_size, 1, 4, hdd_images[id].file); + fwrite(&(hdc[id].spt), 1, 4, hdd_images[id].file); + fwrite(&(hdc[id].hpc), 1, 4, hdd_images[id].file); + fwrite(&(hdc[id].tracks), 1, 4, hdd_images[id].file); + fwrite(&zero, 1, 4, hdd_images[id].file); + fwrite(&zero, 1, 4, hdd_images[id].file); + hdd_images[id].type = 2; + } + else + { + hdd_images[id].type = 0; + } + hdd_images[id].last_sector = 0; + } + + s = full_size = hdc[id].spt * hdc[id].hpc * hdc[id].tracks * 512; + + goto prepare_new_hard_disk; + } + else + { + /* Failed for another reason */ + hdd_image_log("Failed for another reason\n"); + memset(hdc[id].fn, 0, sizeof(hdc[id].fn)); + return 0; + } + } + else + { + if (image_is_hdi(fn)) + { + fseeko64(hdd_images[id].file, 0x8, SEEK_SET); + fread(&(hdd_images[id].base), 1, 4, hdd_images[id].file); + fseeko64(hdd_images[id].file, 0xC, SEEK_SET); + full_size = 0; + fread(&full_size, 1, 4, hdd_images[id].file); + fseeko64(hdd_images[id].file, 0x10, SEEK_SET); + fread(§or_size, 1, 4, hdd_images[id].file); + if (sector_size != 512) + { + /* Sector size is not 512 */ + hdd_image_log("HDI: Sector size is not 512\n"); + fclose(hdd_images[id].file); + hdd_images[id].file = NULL; + memset(hdc[id].fn, 0, sizeof(hdc[id].fn)); + return 0; + } + fread(&spt, 1, 4, hdd_images[id].file); + fread(&hpc, 1, 4, hdd_images[id].file); + fread(&tracks, 1, 4, hdd_images[id].file); + if (hdc[id].bus == HDD_BUS_SCSI_REMOVABLE) + { + if ((spt != hdc[id].spt) || (hpc != hdc[id].hpc) || (tracks != hdc[id].tracks)) + { + hdd_image_log("HDI: Geometry mismatch\n"); + fclose(hdd_images[id].file); + hdd_images[id].file = NULL; + memset(hdc[id].fn, 0, sizeof(hdc[id].fn)); + return 0; + } + } + hdc[id].spt = spt; + hdc[id].hpc = hpc; + hdc[id].tracks = tracks; + hdd_images[id].type = 1; + } + else if (is_hdx[1]) + { + hdd_images[id].base = 0x28; + fseeko64(hdd_images[id].file, 8, SEEK_SET); + fread(&full_size, 1, 8, hdd_images[id].file); + fseeko64(hdd_images[id].file, 0x10, SEEK_SET); + fread(§or_size, 1, 4, hdd_images[id].file); + if (sector_size != 512) + { + /* Sector size is not 512 */ + hdd_image_log("HDX: Sector size is not 512\n"); + fclose(hdd_images[id].file); + hdd_images[id].file = NULL; + memset(hdc[id].fn, 0, sizeof(hdc[id].fn)); + return 0; + } + fread(&spt, 1, 4, hdd_images[id].file); + fread(&hpc, 1, 4, hdd_images[id].file); + fread(&tracks, 1, 4, hdd_images[id].file); + if (hdc[id].bus == HDD_BUS_SCSI_REMOVABLE) + { + if ((spt != hdc[id].spt) || (hpc != hdc[id].hpc) || (tracks != hdc[id].tracks)) + { + hdd_image_log("HDX: Geometry mismatch\n"); + fclose(hdd_images[id].file); + hdd_images[id].file = NULL; + memset(hdc[id].fn, 0, sizeof(hdc[id].fn)); + return 0; + } + } + hdc[id].spt = spt; + hdc[id].hpc = hpc; + hdc[id].tracks = tracks; + fread(&(hdc[id].at_spt), 1, 4, hdd_images[id].file); + fread(&(hdc[id].at_hpc), 1, 4, hdd_images[id].file); + hdd_images[id].type = 2; + } + else + { + full_size = hdc[id].spt * hdc[id].hpc * hdc[id].tracks * 512; + hdd_images[id].type = 0; + } + } + + fseeko64(hdd_images[id].file, 0, SEEK_END); + if (ftello64(hdd_images[id].file) < (full_size + hdd_images[id].base)) + { + s = (full_size + hdd_images[id].base) - ftello64(hdd_images[id].file); +prepare_new_hard_disk: + s >>= 9; + t = (s >> 11) << 11; + s -= t; + t >>= 11; + + empty_sector_1mb = (char *) malloc(1048576); + memset(empty_sector_1mb, 0, 1048576); + + if (s > 0) + { + for (i = 0; i < s; i++) + { + fwrite(empty_sector, 1, 512, hdd_images[id].file); + } + } + + if (t > 0) + { + for (i = 0; i < t; i++) + { + fwrite(empty_sector_1mb, 1, 1045876, hdd_images[id].file); + } + } + + free(empty_sector_1mb); + } + + hdd_images[id].last_sector = (uint32_t) (full_size >> 9) - 1; + + return 1; + hdd_images[id].loaded = 1; +} + +void hdd_image_seek(uint8_t id, uint32_t sector) +{ + uint64_t addr = sector; + addr <<= 9; + addr += hdd_images[id].base; + + fseeko64(hdd_images[id].file, addr, SEEK_SET); +} + +void hdd_image_read(uint8_t id, uint32_t sector, uint32_t count, uint8_t *buffer) +{ + count <<= 9; + + hdd_image_seek(id, sector); + memset(buffer, 0, count); + fread(buffer, 1, count, hdd_images[id].file); +} + +void hdd_image_write(uint8_t id, uint32_t sector, uint32_t count, uint8_t *buffer) +{ + count <<= 9; + + hdd_image_seek(id, sector); + fwrite(buffer, 1, count, hdd_images[id].file); +} + +void hdd_image_zero(uint8_t id, uint32_t sector, uint32_t count) +{ + int i = 0; + uint8_t *b; + + b = (uint8_t *) malloc(512); + memset(b, 0, 512); + + hdd_image_seek(id, sector); + for (i = 0; i < count; i++) + { + fwrite(b, 1, 512, hdd_images[id].file); + } + + free(b); +} + +uint32_t hdd_image_get_last_sector(uint8_t id) +{ + return hdd_images[id].last_sector; +} + +uint8_t hdd_image_get_type(uint8_t id) +{ + return hdd_images[id].type; +} + +void hdd_image_specify(uint8_t id, uint64_t hpc, uint64_t spt) +{ + if (hdd_images[id].type == 2) + { + hdc[id].at_hpc = hpc; + hdc[id].at_spt = spt; + fseeko64(hdd_images[id].file, 0x20, SEEK_SET); + fwrite(&(hdc[id].at_spt), 1, 4, hdd_images[id].file); + fwrite(&(hdc[id].at_hpc), 1, 4, hdd_images[id].file); + } +} + +void hdd_image_unload(uint8_t id, int fn_preserve) +{ + if (wcslen(hdc[id].fn) == 0) + { + return; + } + + if (hdd_images[id].loaded) + { + if (hdd_images[id].file != NULL) + { + fclose(hdd_images[id].file); + hdd_images[id].file = NULL; + } + } + + hdd_images[id].last_sector = -1; + + memset(hdc[id].prev_fn, 0, sizeof(hdc[id].prev_fn)); + if (fn_preserve) + { + wcscpy(hdc[id].prev_fn, hdc[id].fn); + } + + memset(hdc[id].fn, 0, sizeof(hdc[id].fn)); +} + +void hdd_image_close(uint8_t id) +{ + if (hdd_images[id].file != NULL) + { + fclose(hdd_images[id].file); + hdd_images[id].file = NULL; + } +} diff --git a/src/hdd_image.h b/src/hdd_image.h new file mode 100644 index 000000000..e972894fe --- /dev/null +++ b/src/hdd_image.h @@ -0,0 +1,10 @@ +extern int hdd_image_load(int id); +extern void hdd_image_seek(uint8_t id, uint32_t sector); +extern void hdd_image_read(uint8_t id, uint32_t sector, uint32_t count, uint8_t *buffer); +extern void hdd_image_write(uint8_t id, uint32_t sector, uint32_t count, uint8_t *buffer); +extern void hdd_image_zero(uint8_t id, uint32_t sector, uint32_t count); +extern uint32_t hdd_image_get_last_sector(uint8_t id); +extern uint8_t hdd_image_get_type(uint8_t id); +extern void hdd_image_specify(uint8_t id, uint64_t hpc, uint64_t spt); +extern void hdd_image_unload(uint8_t id, int fn_preserve); +extern void hdd_image_close(uint8_t id); diff --git a/src/headland.c b/src/headland.c index cba96b7ef..a80c1b876 100644 --- a/src/headland.c +++ b/src/headland.c @@ -2,22 +2,23 @@ see COPYING for more details */ #include "ibm.h" +#include "cpu/cpu.h" #include "io.h" #include "mem.h" -#include "cpu.h" +#include "device.h" +#include "model.h" -#include "headland.h" static int headland_index; static uint8_t headland_regs[256]; -void headland_write(uint16_t addr, uint8_t val, void *priv) + +static void headland_write(uint16_t addr, uint8_t val, void *priv) { if (addr & 1) { if (headland_index == 0xc1 && !is486) val = 0; headland_regs[headland_index] = val; - // pclog("Headland write %02X %02X\n",headland_index,val); if (headland_index == 0x82) { shadowbios = val & 0x10; @@ -32,7 +33,8 @@ void headland_write(uint16_t addr, uint8_t val, void *priv) headland_index = val; } -uint8_t headland_read(uint16_t addr, void *priv) + +static uint8_t headland_read(uint16_t addr, void *priv) { if (addr & 1) { @@ -43,7 +45,8 @@ uint8_t headland_read(uint16_t addr, void *priv) return headland_index; } -void headland_init() + +void headland_init(void) { io_sethandler(0x0022, 0x0002, headland_read, NULL, NULL, headland_write, NULL, NULL, NULL); } diff --git a/src/headland.h b/src/headland.h deleted file mode 100644 index 0425237bb..000000000 --- a/src/headland.h +++ /dev/null @@ -1,4 +0,0 @@ -/* Copyright holders: Sarah Walker - see COPYING for more details -*/ -void headland_init(); diff --git a/src/i430fx.c b/src/i430fx.c index 9e4addfc6..4ea5db75c 100644 --- a/src/i430fx.c +++ b/src/i430fx.c @@ -1,16 +1,32 @@ -/* Copyright holders: Sarah Walker, Tenshi - see COPYING for more details -*/ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Implementation of the Intel 430FX PCISet chip. + * + * Version: @(#)i430fx.c 1.0.1 2017/06/17 + * + * Authors: Sarah Walker, + * Miran Grca, + * Copyright 2008-2017 Sarah Walker. + * Copyright 2016-2017 Miran Grca. + */ #include - #include "ibm.h" +#include "cpu/cpu.h" #include "mem.h" #include "pci.h" +#include "device.h" +#include "model.h" -#include "i430fx.h" static uint8_t card_i430fx[256]; + static void i430fx_map(uint32_t addr, uint32_t size, int state) { switch (state & 3) @@ -31,18 +47,37 @@ static void i430fx_map(uint32_t addr, uint32_t size, int state) flushmmucache_nopc(); } -void i430fx_write(int func, int addr, uint8_t val, void *priv) + +static void i430fx_write(int func, int addr, uint8_t val, void *priv) { if (func) - return; + return; + + if (addr >= 0x10 && addr < 0x4f) + return; switch (addr) { case 0x00: case 0x01: case 0x02: case 0x03: case 0x08: case 0x09: case 0x0a: case 0x0b: - case 0x0e: + case 0x0c: case 0x0e: return; + + case 0x04: /*Command register*/ + val &= 0x02; + val |= 0x04; + break; + case 0x05: + val = 0; + break; + case 0x06: /*Status*/ + val = 0; + break; + case 0x07: + val = 0x02; + break; + case 0x59: /*PAM0*/ if ((card_i430fx[0x59] ^ val) & 0xf0) { @@ -94,7 +129,8 @@ void i430fx_write(int func, int addr, uint8_t val, void *priv) card_i430fx[addr] = val; } -uint8_t i430fx_read(int func, int addr, void *priv) + +static uint8_t i430fx_read(int func, int addr, void *priv) { if (func) return 0xff; @@ -102,27 +138,9 @@ uint8_t i430fx_read(int func, int addr, void *priv) return card_i430fx[addr]; } -/*The Turbo-Reset Control Register isn't listed in the i430FX datasheet, however - the Advanced/EV BIOS seems to assume it exists. It aliases with one of the PCI - registers.*/ -static uint8_t trc = 0; -void i430fx_trc_write(uint16_t port, uint8_t val, void *p) +static void i430fx_reset(void) { - if ((val & 4) && !(trc & 4)) - { - if (val & 2) /*Hard reset*/ - i430fx_write(0, 0x59, 0xf, NULL); /*Should reset all PCI devices, but just set PAM0 to point to ROM for now*/ - resetx86(); - } - - trc = val; -} - -void i430fx_init() -{ - pci_add_specific(0, i430fx_read, i430fx_write, NULL); - memset(card_i430fx, 0, 256); card_i430fx[0x00] = 0x86; card_i430fx[0x01] = 0x80; /*Intel*/ card_i430fx[0x02] = 0x22; card_i430fx[0x03] = 0x01; /*SB82437FX-66*/ @@ -138,8 +156,6 @@ void i430fx_init() card_i430fx[0x53] = 0x14; card_i430fx[0x56] = 0x52; /*DRAM control*/ } -// card_i430fx[0x53] = 0x14; -// card_i430fx[0x56] = 0x52; /*DRAM control*/ card_i430fx[0x57] = 0x01; card_i430fx[0x60] = card_i430fx[0x61] = card_i430fx[0x62] = card_i430fx[0x63] = card_i430fx[0x64] = 0x02; if (romset == ROM_MB500N) @@ -148,17 +164,26 @@ void i430fx_init() card_i430fx[0x69] = 0x03; card_i430fx[0x70] = 0x20; } -// card_i430fx[0x67] = 0x11; -// card_i430fx[0x69] = 0x03; -// card_i430fx[0x70] = 0x20; card_i430fx[0x72] = 0x02; -// card_i430fx[0x74] = 0x0e; -// card_i430fx[0x78] = 0x23; if (romset == ROM_MB500N) { card_i430fx[0x74] = 0x0e; card_i430fx[0x78] = 0x23; } - - if (romset != ROM_MB500N) io_sethandler(0x0cf9, 0x0001, NULL, NULL, NULL, i430fx_trc_write, NULL, NULL, NULL); +} + + +static void i430fx_pci_reset(void) +{ + i430fx_write(0, 0x59, 0x00, NULL); +} + + +void i430fx_init(void) +{ + pci_add_specific(0, i430fx_read, i430fx_write, NULL); + + i430fx_reset(); + + pci_reset_handler.pci_master_reset = i430fx_pci_reset; } diff --git a/src/i430fx.h b/src/i430fx.h deleted file mode 100644 index 9ed0f355e..000000000 --- a/src/i430fx.h +++ /dev/null @@ -1,4 +0,0 @@ -/* Copyright holders: Sarah Walker, Tenshi - see COPYING for more details -*/ -void i430fx_init(); diff --git a/src/i430hx.c b/src/i430hx.c index 33f8e137d..699fab21b 100644 --- a/src/i430hx.c +++ b/src/i430hx.c @@ -1,17 +1,33 @@ -/* Copyright holders: Sarah Walker - see COPYING for more details -*/ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Implementation of the Intel 430HX PCISet chip. + * + * Version: @(#)i430hx.c 1.0.1 2017/06/17 + * + * Authors: Sarah Walker, + * Miran Grca, + * Copyright 2008-2017 Sarah Walker. + * Copyright 2016-2017 Miran Grca. + */ #include - #include "ibm.h" +#include "cpu/cpu.h" #include "io.h" #include "mem.h" #include "pci.h" +#include "device.h" +#include "model.h" -#include "i430hx.h" static uint8_t card_i430hx[256]; + static void i430hx_map(uint32_t addr, uint32_t size, int state) { switch (state & 3) @@ -32,25 +48,44 @@ static void i430hx_map(uint32_t addr, uint32_t size, int state) flushmmucache_nopc(); } -void i430hx_write(int func, int addr, uint8_t val, void *priv) + +static void i430hx_write(int func, int addr, uint8_t val, void *priv) { if (func) return; + if ((addr >= 0x10) && (addr < 0x4f)) + return; + switch (addr) { case 0x00: case 0x01: case 0x02: case 0x03: case 0x08: case 0x09: case 0x0a: case 0x0b: - case 0x0e: + case 0x0c: case 0x0e: return; + case 0x04: /*Command register*/ + val &= 0x02; + val |= 0x04; + break; + case 0x05: + val = 0; + break; + + case 0x06: /*Status*/ + val = 0; + break; + case 0x07: + val &= 0x80; + val |= 0x02; + break; + case 0x59: /*PAM0*/ if ((card_i430hx[0x59] ^ val) & 0xf0) { i430hx_map(0xf0000, 0x10000, val >> 4); shadowbios = (val & 0x10); } - // pclog("i430hx_write : PAM0 write %02X\n", val); break; case 0x5a: /*PAM1*/ if ((card_i430hx[0x5a] ^ val) & 0x0f) @@ -81,21 +116,20 @@ void i430hx_write(int func, int addr, uint8_t val, void *priv) i430hx_map(0xe0000, 0x04000, val & 0xf); if ((card_i430hx[0x5e] ^ val) & 0xf0) i430hx_map(0xe4000, 0x04000, val >> 4); - // pclog("i430hx_write : PAM5 write %02X\n", val); break; case 0x5f: /*PAM6*/ if ((card_i430hx[0x5f] ^ val) & 0x0f) i430hx_map(0xe8000, 0x04000, val & 0xf); if ((card_i430hx[0x5f] ^ val) & 0xf0) i430hx_map(0xec000, 0x04000, val >> 4); - // pclog("i430hx_write : PAM6 write %02X\n", val); break; } card_i430hx[addr] = val; } -uint8_t i430hx_read(int func, int addr, void *priv) + +static uint8_t i430hx_read(int func, int addr, void *priv) { if (func) return 0xff; @@ -103,11 +137,9 @@ uint8_t i430hx_read(int func, int addr, void *priv) return card_i430hx[addr]; } - -void i430hx_init() + +static void i430hx_reset(void) { - pci_add_specific(0, i430hx_read, i430hx_write, NULL); - memset(card_i430hx, 0, 256); card_i430hx[0x00] = 0x86; card_i430hx[0x01] = 0x80; /*Intel*/ card_i430hx[0x02] = 0x50; card_i430hx[0x03] = 0x12; /*82439HX*/ @@ -115,9 +147,7 @@ void i430hx_init() card_i430hx[0x06] = 0x00; card_i430hx[0x07] = 0x02; card_i430hx[0x08] = 0x00; /*A0 stepping*/ card_i430hx[0x09] = 0x00; card_i430hx[0x0a] = 0x00; card_i430hx[0x0b] = 0x06; - // card_i430hx[0x52] = 0x42; /*256kb PLB cache*/ card_i430hx[0x51] = 0x20; - // card_i430hx[0x52] = 0xB2; /*512kb cache*/ card_i430hx[0x52] = 0xB5; /*512kb cache*/ card_i430hx[0x59] = 0x40; @@ -129,3 +159,19 @@ void i430hx_init() card_i430hx[0x68] = 0x11; card_i430hx[0x72] = 0x02; } + + +static void i430hx_pci_reset(void) +{ + i430hx_write(0, 0x59, 0x00, NULL); +} + + +void i430hx_init(void) +{ + pci_add_specific(0, i430hx_read, i430hx_write, NULL); + + i430hx_reset(); + + pci_reset_handler.pci_master_reset = i430hx_pci_reset; +} diff --git a/src/i430hx.h b/src/i430hx.h deleted file mode 100644 index a6899ca24..000000000 --- a/src/i430hx.h +++ /dev/null @@ -1,4 +0,0 @@ -/* Copyright holders: Sarah Walker - see COPYING for more details -*/ -void i430hx_init(); diff --git a/src/i430lx.c b/src/i430lx.c index 6a2d4a0ea..be015391d 100644 --- a/src/i430lx.c +++ b/src/i430lx.c @@ -1,16 +1,32 @@ -/* Copyright holders: Sarah Walker - see COPYING for more details -*/ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Implementation of the Intel 430LX PCISet chip. + * + * Version: @(#)i430lx.c 1.0.1 2017/06/17 + * + * Authors: Sarah Walker, + * Miran Grca, + * Copyright 2008-2017 Sarah Walker. + * Copyright 2016-2017 Miran Grca. + */ #include - #include "ibm.h" +#include "cpu/cpu.h" #include "mem.h" #include "pci.h" +#include "device.h" +#include "model.h" -#include "i430lx.h" static uint8_t card_i430lx[256]; + static void i430lx_map(uint32_t addr, uint32_t size, int state) { switch (state & 3) @@ -31,18 +47,37 @@ static void i430lx_map(uint32_t addr, uint32_t size, int state) flushmmucache_nopc(); } -void i430lx_write(int func, int addr, uint8_t val, void *priv) + +static void i430lx_write(int func, int addr, uint8_t val, void *priv) { if (func) return; + if ((addr >= 0x10) && (addr < 0x4f)) + return; + switch (addr) { case 0x00: case 0x01: case 0x02: case 0x03: case 0x08: case 0x09: case 0x0a: case 0x0b: - case 0x0e: + case 0x0c: case 0x0e: return; + case 0x04: /*Command register*/ + val &= 0x42; + val |= 0x04; + break; + case 0x05: + val &= 0x01; + break; + + case 0x06: /*Status*/ + val = 0; + break; + case 0x07: + val = 0x02; + break; + case 0x59: /*PAM0*/ if ((card_i430lx[0x59] ^ val) & 0xf0) { @@ -97,7 +132,8 @@ void i430lx_write(int func, int addr, uint8_t val, void *priv) card_i430lx[addr] = val; } -uint8_t i430lx_read(int func, int addr, void *priv) + +static uint8_t i430lx_read(int func, int addr, void *priv) { if (func) return 0xff; @@ -105,29 +141,9 @@ uint8_t i430lx_read(int func, int addr, void *priv) return card_i430lx[addr]; } -static uint8_t trc = 0; -uint8_t i430lx_trc_read(uint16_t port, void *p) +static void i430lx_reset(void) { - return trc; -} - -void i430lx_trc_write(uint16_t port, uint8_t val, void *p) -{ - if ((val & 4) && !(trc & 4)) - { - if (val & 2) /*Hard reset*/ - i430lx_write(0, 0x59, 0xf, NULL); /*Should reset all PCI devices, but just set PAM0 to point to ROM for now*/ - resetx86(); - } - - trc = val; -} - -void i430lx_init() -{ - pci_add_specific(0, i430lx_read, i430lx_write, NULL); - memset(card_i430lx, 0, 256); card_i430lx[0x00] = 0x86; card_i430lx[0x01] = 0x80; /*Intel*/ card_i430lx[0x02] = 0xa3; card_i430lx[0x03] = 0x04; /*82434LX*/ @@ -137,16 +153,22 @@ void i430lx_init() card_i430lx[0x09] = 0x00; card_i430lx[0x0a] = 0x00; card_i430lx[0x0b] = 0x06; card_i430lx[0x50] = 0x80; card_i430lx[0x52] = 0x40; /*256kb PLB cache*/ -// card_i430lx[0x53] = 0x14; -// card_i430lx[0x56] = 0x52; /*DRAM control*/ card_i430lx[0x57] = 0x31; card_i430lx[0x60] = card_i430lx[0x61] = card_i430lx[0x62] = card_i430lx[0x63] = card_i430lx[0x64] = 0x02; -// card_i430lx[0x67] = 0x11; -// card_i430lx[0x69] = 0x03; -// card_i430lx[0x70] = 0x20; -// card_i430lx[0x72] = 0x02; -// card_i430lx[0x74] = 0x0e; -// card_i430lx[0x78] = 0x23; - - io_sethandler(0x0cf9, 0x0001, i430lx_trc_read, NULL, NULL, i430lx_trc_write, NULL, NULL, NULL); +} + + +static void i430lx_pci_reset(void) +{ + i430lx_write(0, 0x59, 0x00, NULL); +} + + +void i430lx_init(void) +{ + pci_add_specific(0, i430lx_read, i430lx_write, NULL); + + i430lx_reset(); + + pci_reset_handler.pci_master_reset = i430lx_pci_reset; } diff --git a/src/i430lx.h b/src/i430lx.h deleted file mode 100644 index 60c061df4..000000000 --- a/src/i430lx.h +++ /dev/null @@ -1,4 +0,0 @@ -/* Copyright holders: Sarah Walker - see COPYING for more details -*/ -void i430lx_init(); diff --git a/src/i430nx.c b/src/i430nx.c index 9b7ef653b..b17bde0fe 100644 --- a/src/i430nx.c +++ b/src/i430nx.c @@ -1,16 +1,32 @@ -/* Copyright holders: Sarah Walker, Tenshi - see COPYING for more details -*/ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Implementation of the Intel 430NX PCISet chip. + * + * Version: @(#)i430nx.c 1.0.1 2017/06/17 + * + * Authors: Sarah Walker, + * Miran Grca, + * Copyright 2008-2017 Sarah Walker. + * Copyright 2016-2017 Miran Grca. + */ #include - #include "ibm.h" +#include "cpu/cpu.h" #include "mem.h" #include "pci.h" +#include "device.h" +#include "model.h" -#include "i430nx.h" static uint8_t card_i430nx[256]; + static void i430nx_map(uint32_t addr, uint32_t size, int state) { switch (state & 3) @@ -31,18 +47,37 @@ static void i430nx_map(uint32_t addr, uint32_t size, int state) flushmmucache_nopc(); } -void i430nx_write(int func, int addr, uint8_t val, void *priv) + +static void i430nx_write(int func, int addr, uint8_t val, void *priv) { if (func) return; + if ((addr >= 0x10) && (addr < 0x4f)) + return; + switch (addr) { case 0x00: case 0x01: case 0x02: case 0x03: case 0x08: case 0x09: case 0x0a: case 0x0b: - case 0x0e: + case 0x0c: case 0x0e: return; + case 0x04: /*Command register*/ + val &= 0x42; + val |= 0x04; + break; + case 0x05: + val &= 0x01; + break; + + case 0x06: /*Status*/ + val = 0; + break; + case 0x07: + val = 0x02; + break; + case 0x59: /*PAM0*/ if ((card_i430nx[0x59] ^ val) & 0xf0) { @@ -94,7 +129,8 @@ void i430nx_write(int func, int addr, uint8_t val, void *priv) card_i430nx[addr] = val; } -uint8_t i430nx_read(int func, int addr, void *priv) + +static uint8_t i430nx_read(int func, int addr, void *priv) { if (func) return 0xff; @@ -102,29 +138,9 @@ uint8_t i430nx_read(int func, int addr, void *priv) return card_i430nx[addr]; } -static uint8_t trc = 0; -uint8_t i430nx_trc_read(uint16_t port, void *p) +static void i430nx_reset(void) { - return trc; -} - -void i430nx_trc_write(uint16_t port, uint8_t val, void *p) -{ - if ((val & 4) && !(trc & 4)) - { - if (val & 2) /*Hard reset*/ - i430nx_write(0, 0x59, 0xf, NULL); /*Should reset all PCI devices, but just set PAM0 to point to ROM for now*/ - resetx86(); - } - - trc = val; -} - -void i430nx_init() -{ - pci_add_specific(0, i430nx_read, i430nx_write, NULL); - memset(card_i430nx, 0, 256); card_i430nx[0x00] = 0x86; card_i430nx[0x01] = 0x80; /*Intel*/ card_i430nx[0x02] = 0xa3; card_i430nx[0x03] = 0x04; /*82434NX*/ @@ -134,17 +150,23 @@ void i430nx_init() card_i430nx[0x09] = 0x00; card_i430nx[0x0a] = 0x00; card_i430nx[0x0b] = 0x06; card_i430nx[0x50] = 0xA0; card_i430nx[0x52] = 0x44; /*256kb PLB cache*/ -// card_i430nx[0x53] = 0x14; -// card_i430nx[0x56] = 0x52; /*DRAM control*/ card_i430nx[0x57] = 0x31; card_i430nx[0x60] = card_i430nx[0x61] = card_i430nx[0x62] = card_i430nx[0x63] = card_i430nx[0x64] = 0x02; card_i430nx[0x66] = card_i430nx[0x67] = 0x02; -// card_i430nx[0x67] = 0x11; -// card_i430nx[0x69] = 0x03; -// card_i430nx[0x70] = 0x20; -// card_i430nx[0x72] = 0x02; -// card_i430nx[0x74] = 0x0e; -// card_i430nx[0x78] = 0x23; - - io_sethandler(0x0cf9, 0x0001, i430nx_trc_read, NULL, NULL, i430nx_trc_write, NULL, NULL, NULL); +} + + +static void i430nx_pci_reset(void) +{ + i430nx_write(0, 0x59, 0x00, NULL); +} + + +void i430nx_init(void) +{ + pci_add_specific(0, i430nx_read, i430nx_write, NULL); + + i430nx_reset(); + + pci_reset_handler.pci_master_reset = i430nx_pci_reset; } diff --git a/src/i430nx.h b/src/i430nx.h deleted file mode 100644 index 3c759a205..000000000 --- a/src/i430nx.h +++ /dev/null @@ -1,4 +0,0 @@ -/* Copyright holders: Sarah Walker, Tenshi - see COPYING for more details -*/ -void i430nx_init(); diff --git a/src/i430vx.c b/src/i430vx.c index 487c1f977..967701251 100644 --- a/src/i430vx.c +++ b/src/i430vx.c @@ -1,17 +1,33 @@ -/* Copyright holders: Sarah Walker - see COPYING for more details -*/ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Implementation of the Intel 430VX PCISet chip. + * + * Version: @(#)i430vx.c 1.0.2 2017/06/17 + * + * Authors: Sarah Walker, + * Miran Grca, + * Copyright 2008-2017 Sarah Walker. + * Copyright 2016-2017 Miran Grca. + */ #include - #include "ibm.h" +#include "cpu/cpu.h" #include "io.h" #include "mem.h" #include "pci.h" +#include "device.h" +#include "model.h" -#include "i430vx.h" static uint8_t card_i430vx[256]; + static void i430vx_map(uint32_t addr, uint32_t size, int state) { switch (state & 3) @@ -32,25 +48,45 @@ static void i430vx_map(uint32_t addr, uint32_t size, int state) flushmmucache_nopc(); } -void i430vx_write(int func, int addr, uint8_t val, void *priv) + +static void i430vx_write(int func, int addr, uint8_t val, void *priv) { if (func) return; + if ((addr >= 0x10) && (addr < 0x4f)) + return; + switch (addr) { case 0x00: case 0x01: case 0x02: case 0x03: case 0x08: case 0x09: case 0x0a: case 0x0b: - case 0x0e: + case 0x0c: case 0x0e: return; + case 0x04: /*Command register*/ + val &= 0x02; + val |= 0x04; + break; + case 0x05: + val = 0; + break; + + case 0x06: /*Status*/ + val = 0; + break; + case 0x07: + val &= 0x80; + val |= 0x02; + break; + case 0x59: /*PAM0*/ if ((card_i430vx[0x59] ^ val) & 0xf0) { i430vx_map(0xf0000, 0x10000, val >> 4); shadowbios = (val & 0x10); } - pclog("i430vx_write : PAM0 write %02X\n", val); + /* pclog("i430vx_write : PAM0 write %02X\n", val); */ break; case 0x5a: /*PAM1*/ if ((card_i430vx[0x5a] ^ val) & 0x0f) @@ -81,21 +117,22 @@ void i430vx_write(int func, int addr, uint8_t val, void *priv) i430vx_map(0xe0000, 0x04000, val & 0xf); if ((card_i430vx[0x5e] ^ val) & 0xf0) i430vx_map(0xe4000, 0x04000, val >> 4); - pclog("i430vx_write : PAM5 write %02X\n", val); + /* pclog("i430vx_write : PAM5 write %02X\n", val); */ break; case 0x5f: /*PAM6*/ if ((card_i430vx[0x5f] ^ val) & 0x0f) i430vx_map(0xe8000, 0x04000, val & 0xf); if ((card_i430vx[0x5f] ^ val) & 0xf0) i430vx_map(0xec000, 0x04000, val >> 4); - pclog("i430vx_write : PAM6 write %02X\n", val); + /* pclog("i430vx_write : PAM6 write %02X\n", val); */ break; } card_i430vx[addr] = val; } -uint8_t i430vx_read(int func, int addr, void *priv) + +static uint8_t i430vx_read(int func, int addr, void *priv) { if (func) return 0xff; @@ -103,11 +140,9 @@ uint8_t i430vx_read(int func, int addr, void *priv) return card_i430vx[addr]; } - -void i430vx_init() + +static void i430vx_reset(void) { - pci_add_specific(0, i430vx_read, i430vx_write, NULL); - memset(card_i430vx, 0, 256); card_i430vx[0x00] = 0x86; card_i430vx[0x01] = 0x80; /*Intel*/ card_i430vx[0x02] = 0x30; card_i430vx[0x03] = 0x70; /*82437VX*/ @@ -127,3 +162,19 @@ void i430vx_init() card_i430vx[0x74] = 0x0e; card_i430vx[0x78] = 0x23; } + + +static void i430vx_pci_reset(void) +{ + i430vx_write(0, 0x59, 0x00, NULL); +} + + +void i430vx_init(void) +{ + pci_add_specific(0, i430vx_read, i430vx_write, NULL); + + i430vx_reset(); + + pci_reset_handler.pci_master_reset = i430vx_pci_reset; +} diff --git a/src/i430vx.h b/src/i430vx.h deleted file mode 100644 index af7e5337e..000000000 --- a/src/i430vx.h +++ /dev/null @@ -1,4 +0,0 @@ -/* Copyright holders: Sarah Walker - see COPYING for more details -*/ -void i430vx_init(); diff --git a/src/i440fx.c b/src/i440fx.c index 43889c0ec..811215c63 100644 --- a/src/i440fx.c +++ b/src/i440fx.c @@ -1,17 +1,33 @@ -/* Copyright holders: Sarah Walker, Tenshi - see COPYING for more details -*/ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Implementation of the Intel 440FX PCISet chip. + * + * Version: @(#)i440fx.c 1.0.1 2017/06/17 + * + * Authors: Sarah Walker, + * Miran Grca, + * Copyright 2008-2017 Sarah Walker. + * Copyright 2016-2017 Miran Grca. + */ #include - #include "ibm.h" +#include "cpu/cpu.h" #include "io.h" #include "mem.h" #include "pci.h" +#include "device.h" +#include "model.h" -#include "i440fx.h" static uint8_t card_i440fx[256]; + static void i440fx_map(uint32_t addr, uint32_t size, int state) { switch (state & 3) @@ -32,25 +48,44 @@ static void i440fx_map(uint32_t addr, uint32_t size, int state) flushmmucache_nopc(); } -void i440fx_write(int func, int addr, uint8_t val, void *priv) + +static void i440fx_write(int func, int addr, uint8_t val, void *priv) { if (func) return; + if ((addr >= 0x10) && (addr < 0x4f)) + return; + switch (addr) { case 0x00: case 0x01: case 0x02: case 0x03: case 0x08: case 0x09: case 0x0a: case 0x0b: - case 0x0e: + case 0x0c: case 0x0e: return; + case 0x04: /*Command register*/ + val &= 0x02; + val |= 0x04; + break; + case 0x05: + val = 0; + break; + + case 0x06: /*Status*/ + val = 0; + break; + case 0x07: + val &= 0x80; + val |= 0x02; + break; + case 0x59: /*PAM0*/ if ((card_i440fx[0x59] ^ val) & 0xf0) { i440fx_map(0xf0000, 0x10000, val >> 4); shadowbios = (val & 0x10); } - // pclog("i440fx_write : PAM0 write %02X\n", val); break; case 0x5a: /*PAM1*/ if ((card_i440fx[0x5a] ^ val) & 0x0f) @@ -81,21 +116,20 @@ void i440fx_write(int func, int addr, uint8_t val, void *priv) i440fx_map(0xe0000, 0x04000, val & 0xf); if ((card_i440fx[0x5e] ^ val) & 0xf0) i440fx_map(0xe4000, 0x04000, val >> 4); - // pclog("i440fx_write : PAM5 write %02X\n", val); break; case 0x5f: /*PAM6*/ if ((card_i440fx[0x5f] ^ val) & 0x0f) i440fx_map(0xe8000, 0x04000, val & 0xf); if ((card_i440fx[0x5f] ^ val) & 0xf0) i440fx_map(0xec000, 0x04000, val >> 4); - // pclog("i440fx_write : PAM6 write %02X\n", val); break; } card_i440fx[addr] = val; } -uint8_t i440fx_read(int func, int addr, void *priv) + +static uint8_t i440fx_read(int func, int addr, void *priv) { if (func) return 0xff; @@ -103,11 +137,9 @@ uint8_t i440fx_read(int func, int addr, void *priv) return card_i440fx[addr]; } - -void i440fx_init() + +static void i440fx_reset(void) { - pci_add_specific(0, i440fx_read, i440fx_write, NULL); - memset(card_i440fx, 0, 256); card_i440fx[0x00] = 0x86; card_i440fx[0x01] = 0x80; /*Intel*/ card_i440fx[0x02] = 0x37; card_i440fx[0x03] = 0x12; /*82441FX*/ @@ -129,8 +161,21 @@ void i440fx_init() card_i440fx[0x58] = 0x10; card_i440fx[0x5a] = card_i440fx[0x5b] = card_i440fx[0x5c] = card_i440fx[0x5d] = card_i440fx[0x5e] = 0x11; card_i440fx[0x5f] = 0x31; - // card_i440fx[0x60] = card_i440fx[0x61] = card_i440fx[0x62] = card_i440fx[0x63] = card_i440fx[0x64] = card_i440fx[0x65] = card_i440fx[0x66] = card_i440fx[0x67] = 0x02; - // card_i440fx[0x70] = 0x20; - // card_i440fx[0x71] = 0x10; card_i440fx[0x72] = 0x02; } + + +static void i440fx_pci_reset(void) +{ + i440fx_write(0, 0x59, 0x00, NULL); +} + + +void i440fx_init(void) +{ + pci_add_specific(0, i440fx_read, i440fx_write, NULL); + + i440fx_reset(); + + pci_reset_handler.pci_master_reset = i440fx_pci_reset; +} diff --git a/src/i440fx.h b/src/i440fx.h deleted file mode 100644 index 72cf59458..000000000 --- a/src/i440fx.h +++ /dev/null @@ -1,4 +0,0 @@ -/* Copyright holders: Sarah Walker, Tenshi - see COPYING for more details -*/ -void i440fx_init(); diff --git a/src/i82335.c b/src/i82335.c new file mode 100644 index 000000000..981ea8f55 --- /dev/null +++ b/src/i82335.c @@ -0,0 +1,135 @@ +/* Intel 82335 SX emulation, used by the Phoenix 386 clone. */ + +#include +#include "ibm.h" +#include "io.h" +#include "mem.h" + +typedef struct +{ + uint8_t reg_22; + uint8_t reg_23; +} i82335_t; + +i82335_t i82335; + +uint8_t i82335_read(uint16_t addr, void *priv); + +void i82335_write(uint16_t addr, uint8_t val, void *priv) +{ + int i = 0; + + int mem_write = 0; + + // pclog("i82335_write(%04X, %02X)\n", addr, val); + + switch (addr) + { + case 0x22: + if ((val ^ i82335.reg_22) & 1) + { + if (val & 1) + { + for (i = 0; i < 8; i++) + { + mem_set_mem_state(0xe0000, 0x20000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + shadowbios = 1; + } + } + else + { + for (i = 0; i < 8; i++) + { + mem_set_mem_state(0xe0000, 0x20000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + shadowbios = 0; + } + } + + flushmmucache(); + } + + i82335.reg_22 = val | 0xd8; + break; + case 0x23: + i82335.reg_23 = val; + + if ((val ^ i82335.reg_22) & 2) + { + if (val & 2) + { + for (i = 0; i < 8; i++) + { + mem_set_mem_state(0xc0000, 0x20000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + shadowbios = 1; + } + } + else + { + for (i = 0; i < 8; i++) + { + mem_set_mem_state(0xc0000, 0x20000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + shadowbios = 0; + } + } + } + + if ((val ^ i82335.reg_22) & 0xc) + { + if (val & 2) + { + for (i = 0; i < 8; i++) + { + mem_write = (val & 8) ? MEM_WRITE_DISABLED : MEM_WRITE_INTERNAL; + mem_set_mem_state(0xa0000, 0x20000, MEM_READ_INTERNAL | mem_write); + shadowbios = 1; + } + } + else + { + for (i = 0; i < 8; i++) + { + mem_write = (val & 8) ? MEM_WRITE_DISABLED : MEM_WRITE_EXTERNAL; + mem_set_mem_state(0xa0000, 0x20000, MEM_READ_EXTERNAL | mem_write); + shadowbios = 0; + } + } + } + + if ((val ^ i82335.reg_22) & 0xe) + { + flushmmucache(); + } + + if (val & 0x80) + { + io_removehandler(0x0022, 0x0001, i82335_read, NULL, NULL, i82335_write, NULL, NULL, NULL); + } + break; + } +} + +uint8_t i82335_read(uint16_t addr, void *priv) +{ + // pclog("i82335_read(%04X)\n", addr); + if (addr == 0x22) + { + return i82335.reg_22; + } + else if (addr == 0x23) + { + return i82335.reg_23; + } + else + { + return 0; + } +} + +void i82335_init() +{ + memset(&i82335, 0, sizeof(i82335_t)); + + i82335.reg_22 = 0xd8; + + io_sethandler(0x0022, 0x0014, i82335_read, NULL, NULL, i82335_write, NULL, NULL, NULL); +} diff --git a/src/i82335.h b/src/i82335.h new file mode 100644 index 000000000..048730b80 --- /dev/null +++ b/src/i82335.h @@ -0,0 +1 @@ +void i82335_init(); diff --git a/src/ibm.h b/src/ibm.h index 02779a5ba..cb2ed92a8 100644 --- a/src/ibm.h +++ b/src/ibm.h @@ -1,64 +1,69 @@ -/* Copyright holders: Sarah Walker, Tenshi - see COPYING for more details -*/ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * General include file. + * + * Version: @(#)ibm.h 1.0.1 2017/06/03 + * + * Authors: Sarah Walker, + * Miran Grca, + * Copyright 2008-2017 Sarah Walker. + * Copyright 2016-2017 Miran Grca. + */ #include #include #include +#include #define printf pclog + /*Memory*/ -uint8_t *ram; +extern uint8_t *ram; +extern uint32_t rammask; -uint32_t rammask; - -int readlookup[256],readlookupp[256]; -uintptr_t *readlookup2; -int readlnext; -int writelookup[256],writelookupp[256]; -uintptr_t *writelookup2; -int writelnext; +extern int readlookup[256],readlookupp[256]; +extern uintptr_t *readlookup2; +extern int readlnext; +extern int writelookup[256],writelookupp[256]; +extern uintptr_t *writelookup2; +extern int writelnext; extern int mmu_perm; #define readmemb(a) ((readlookup2[(a)>>12]==-1)?readmembl(a):*(uint8_t *)(readlookup2[(a) >> 12] + (a))) -#define readmemw(s,a) ((readlookup2[(uint32_t)((s)+(a))>>12]==-1 || (s)==0xFFFFFFFF || (((s)+(a))&0xFFF)>0xFFE)?readmemwl(s,a):*(uint16_t *)(readlookup2[(uint32_t)((s)+(a))>>12]+(uint32_t)((s)+(a)))) -#define readmeml(s,a) ((readlookup2[(uint32_t)((s)+(a))>>12]==-1 || (s)==0xFFFFFFFF || (((s)+(a))&0xFFF)>0xFFC)?readmemll(s,a):*(uint32_t *)(readlookup2[(uint32_t)((s)+(a))>>12]+(uint32_t)((s)+(a)))) +#define readmemw(s,a) ((readlookup2[(uint32_t)((s)+(a))>>12]==-1 || (s)==0xFFFFFFFF || (((s)+(a)) & 1))?readmemwl(s,a):*(uint16_t *)(readlookup2[(uint32_t)((s)+(a))>>12]+(uint32_t)((s)+(a)))) +#define readmeml(s,a) ((readlookup2[(uint32_t)((s)+(a))>>12]==-1 || (s)==0xFFFFFFFF || (((s)+(a)) & 3))?readmemll(s,a):*(uint32_t *)(readlookup2[(uint32_t)((s)+(a))>>12]+(uint32_t)((s)+(a)))) -//#define writememb(a,v) if (writelookup2[(a)>>12]==0xFFFFFFFF) writemembl(a,v); else ram[writelookup2[(a)>>12]+((a)&0xFFF)]=v -//#define writememw(s,a,v) if (writelookup2[((s)+(a))>>12]==0xFFFFFFFF || (s)==0xFFFFFFFF) writememwl(s,a,v); else *((uint16_t *)(&ram[writelookup2[((s)+(a))>>12]+(((s)+(a))&0xFFF)]))=v -//#define writememl(s,a,v) if (writelookup2[((s)+(a))>>12]==0xFFFFFFFF || (s)==0xFFFFFFFF) writememll(s,a,v); else *((uint32_t *)(&ram[writelookup2[((s)+(a))>>12]+(((s)+(a))&0xFFF)]))=v -//#define readmemb(a) ((isram[((a)>>16)&255] && !(cr0>>31))?ram[a&0xFFFFFF]:readmembl(a)) -//#define writememb(a,v) if (isram[((a)>>16)&255] && !(cr0>>31)) ram[a&0xFFFFFF]=v; else writemembl(a,v) +extern uint8_t readmembl(uint32_t addr); +extern void writemembl(uint32_t addr, uint8_t val); +extern uint8_t readmemb386l(uint32_t seg, uint32_t addr); +extern void writememb386l(uint32_t seg, uint32_t addr, uint8_t val); +extern uint16_t readmemwl(uint32_t seg, uint32_t addr); +extern void writememwl(uint32_t seg, uint32_t addr, uint16_t val); +extern uint32_t readmemll(uint32_t seg, uint32_t addr); +extern void writememll(uint32_t seg, uint32_t addr, uint32_t val); +extern uint64_t readmemql(uint32_t seg, uint32_t addr); +extern void writememql(uint32_t seg, uint32_t addr, uint64_t val); -//void writememb(uint32_t addr, uint8_t val); -uint8_t readmembl(uint32_t addr); -void writemembl(uint32_t addr, uint8_t val); -uint8_t readmemb386l(uint32_t seg, uint32_t addr); -void writememb386l(uint32_t seg, uint32_t addr, uint8_t val); -uint16_t readmemwl(uint32_t seg, uint32_t addr); -void writememwl(uint32_t seg, uint32_t addr, uint16_t val); -uint32_t readmemll(uint32_t seg, uint32_t addr); -void writememll(uint32_t seg, uint32_t addr, uint32_t val); -uint64_t readmemql(uint32_t seg, uint32_t addr); -void writememql(uint32_t seg, uint32_t addr, uint64_t val); - -uint8_t *getpccache(uint32_t a); - -uint32_t mmutranslatereal(uint32_t addr, int rw); - -void addreadlookup(uint32_t virt, uint32_t phys); -void addwritelookup(uint32_t virt, uint32_t phys); +extern uint8_t *getpccache(uint32_t a); +extern uint32_t mmutranslatereal(uint32_t addr, int rw); +extern void addreadlookup(uint32_t virt, uint32_t phys); +extern void addwritelookup(uint32_t virt, uint32_t phys); /*IO*/ -uint8_t inb(uint16_t port); -void outb(uint16_t port, uint8_t val); -uint16_t inw(uint16_t port); -void outw(uint16_t port, uint16_t val); -uint32_t inl(uint16_t port); -void outl(uint16_t port, uint32_t val); +extern uint8_t inb(uint16_t port); +extern void outb(uint16_t port, uint8_t val); +extern uint16_t inw(uint16_t port); +extern void outw(uint16_t port, uint16_t val); +extern uint32_t inl(uint16_t port); +extern void outl(uint16_t port, uint32_t val); -FILE *romfopen(char *fn, char *mode); extern int shadowbios,shadowbios_write; extern int mem_size; extern int readlnum,writelnum; @@ -138,7 +143,6 @@ struct uint32_t pc; uint32_t oldpc; uint32_t op32; - uint32_t last_ea; int TOP; @@ -167,30 +171,46 @@ struct MMX_REG MM[8]; uint16_t old_npxc, new_npxc; + uint32_t last_ea; } cpu_state; #define cycles cpu_state._cycles -#define COMPILE_TIME_ASSERT(expr) typedef char COMP_TIME_ASSERT[(expr) ? 1 : 0]; +extern uint32_t cpu_cur_status; -COMPILE_TIME_ASSERT(sizeof(cpu_state) <= 128); +#define CPU_STATUS_USE32 (1 << 0) +#define CPU_STATUS_STACK32 (1 << 1) +#define CPU_STATUS_FLATDS (1 << 2) +#define CPU_STATUS_FLATSS (1 << 3) -#define cpu_state_offset(MEMBER) ((uintptr_t)&cpu_state.MEMBER - (uintptr_t)&cpu_state - 128) +#define cpu_rm cpu_state.rm_data.rm_mod_reg.rm +#define cpu_mod cpu_state.rm_data.rm_mod_reg.mod +#define cpu_reg cpu_state.rm_data.rm_mod_reg.reg + +#ifdef __MSC__ +# define COMPILE_TIME_ASSERT(expr) /*nada*/ +#else +# define COMPILE_TIME_ASSERT(expr) typedef char COMP_TIME_ASSERT[(expr) ? 1 : 0]; +#endif + +COMPILE_TIME_ASSERT(sizeof(cpu_state) <= 128) + +#define cpu_state_offset(MEMBER) ((uint8_t)((uintptr_t)&cpu_state.MEMBER - (uintptr_t)&cpu_state - 128)) /*x86reg regs[8];*/ -uint16_t flags,eflags; -uint32_t oldds,oldss,olddslimit,oldsslimit,olddslimitw,oldsslimitw; +extern uint16_t flags,eflags; +extern uint32_t oldds,oldss,olddslimit,oldsslimit,olddslimitw,oldsslimitw; extern int ins,output; extern int cycdiff; -x86seg gdt,ldt,idt,tr; -x86seg _cs,_ds,_es,_ss,_fs,_gs; -x86seg _oldds; +extern x86seg gdt,ldt,idt,tr; +extern x86seg _cs,_ds,_es,_ss,_fs,_gs; +extern x86seg _oldds; -uint32_t pccache; -uint8_t *pccache2; +extern uint32_t pccache; +extern uint8_t *pccache2; /*Segments - _cs,_ds,_es,_ss are the segment structures CS,DS,ES,SS is the 16-bit data @@ -222,8 +242,8 @@ union #define cr0 CR0.l #define msw CR0.w -uint32_t cr2, cr3, cr4; -uint32_t dr[8]; +extern uint32_t cr2, cr3, cr4; +extern uint32_t dr[8]; #define C_FLAG 0x0001 #define P_FLAG 0x0004 @@ -242,9 +262,7 @@ uint32_t dr[8]; #define IOPL ((flags>>12)&3) #define IOPLp ((!(msw&1)) || (CPL<=IOPL)) -//#define IOPLp 1 -//#define IOPLV86 ((!(msw&1)) || (CPL<=IOPL)) extern int cycles_lost; extern int israpidcad; extern int is486; @@ -260,6 +278,12 @@ extern int CPUID; extern int cpl_override; /*Timer*/ +typedef struct PIT_nr +{ + int nr; + struct PIT *pit; +} PIT_nr; + typedef struct PIT { uint32_t l[3]; @@ -284,23 +308,22 @@ typedef struct PIT uint8_t read_status[3]; int do_read_status[3]; + + PIT_nr pit_nr[3]; + + void (*set_out_funcs[3])(int new_out, int old_out); } PIT; -PIT pit; -void setpitclock(float clock); - -float pit_timer0_freq(); - -#define cpu_rm cpu_state.rm_data.rm_mod_reg.rm -#define cpu_mod cpu_state.rm_data.rm_mod_reg.mod -#define cpu_reg cpu_state.rm_data.rm_mod_reg.reg +PIT pit, pit2; +extern void setpitclock(float clock); +extern float pit_timer0_freq(void); /*DMA*/ typedef struct DMA { - uint16_t ab[4],ac[4]; + uint32_t ab[4],ac[4]; uint16_t cb[4]; int cc[4]; int wp; @@ -308,9 +331,17 @@ typedef struct DMA uint8_t page[4]; uint8_t stat; uint8_t command; + uint8_t request; + + int xfr_command, xfr_channel; + int byte_ptr; + + int is_ps2; + uint8_t arb_level[4]; + uint8_t ps2_mode[4]; } DMA; -DMA dma,dma16; +extern DMA dma, dma16; /*PPI*/ @@ -320,7 +351,7 @@ typedef struct PPI uint8_t pa,pb; } PPI; -PPI ppi; +extern PPI ppi; /*PIC*/ @@ -332,16 +363,16 @@ typedef struct PIC int read; } PIC; -PIC pic,pic2; +extern PIC pic, pic2; extern int pic_intpending; -int disctime; -char discfns[4][256]; -int driveempty[4]; +extern int disctime; +extern wchar_t discfns[4][256]; +extern int driveempty[4]; -#define MDA ((gfxcard==GFX_MDA || gfxcard==GFX_HERCULES || gfxcard==GFX_HERCULESPLUS || gfxcard==GFX_INCOLOR) && (romset=ROM_IBMAT)) -#define VGA ((gfxcard>=GFX_TVGA || romset==ROM_ACER386) && gfxcard!=GFX_COLORPLUS && gfxcard!=GFX_INCOLOR && gfxcard!=GFX_WY700 && gfxcard!=GFX_COMPAQ_EGA && gfxcard!=GFX_SUPER_EGA && gfxcard!=GFX_HERCULESPLUS && romset!=ROM_PC1640 && romset!=ROM_PC1512 && romset!=ROM_TANDY && romset!=ROM_PC200) +#define MDA ((gfxcard==GFX_MDA || gfxcard==GFX_HERCULES || gfxcard==GFX_HERCULESPLUS || gfxcard==GFX_INCOLOR || gfxcard==GFX_GENIUS) && (romset=ROM_IBMAT)) +#define VGA ((gfxcard>=GFX_TVGA || romset==ROM_ACER386) && gfxcard!=GFX_COLORPLUS && gfxcard!=GFX_INCOLOR && gfxcard!=GFX_WY700 && gfxcard!=GFX_GENIUS && gfxcard!=GFX_COMPAQ_EGA && gfxcard!=GFX_SUPER_EGA && gfxcard!=GFX_HERCULESPLUS && romset!=ROM_PC1640 && romset!=ROM_PC1512 && romset!=ROM_TANDY && romset!=ROM_PC200) #define PCJR (romset == ROM_IBMPCJR) #define AMIBIOS (romset==ROM_AMI386SX || romset==ROM_AMI486 || romset == ROM_WIN486) @@ -390,12 +421,21 @@ enum ROM_ENDEAVOR, ROM_REVENGE, ROM_IBMPS1_2011, - ROM_DESKPRO_386, + ROM_DESKPRO_386, + ROM_PORTABLE, + ROM_PORTABLEII, + ROM_PORTABLEIII, + ROM_PORTABLEIII386, /* The original Compaq Portable III shipped with an Intel 80286 CPU, but later switched to a 386DX. */ ROM_IBMPS1_2121, ROM_AMI386DX_OPTI495, ROM_MR386DX_OPTI495, + ROM_IBMPS2_M30_286, + ROM_IBMPS2_M50, + ROM_IBMPS2_M55SX, + ROM_IBMPS2_M80, + ROM_DTK486, /*DTK PKM-0038S E-2 / SiS 471 / Award BIOS / SiS 85C471*/ ROM_VLI486SV2G, /*ASUS VL/I-486SV2G / SiS 471 / Award BIOS / SiS 85C471*/ ROM_R418, /*Rise Computer R418 / SiS 496/497 / Award BIOS / SMC FDC37C665*/ @@ -403,26 +443,43 @@ enum ROM_PLATO, /*Intel Premiere/PCI II / 430NX / AMI BIOS / SMC FDC37C665*/ ROM_MB500N, /*PC Partner MB500N / 430FX / Award BIOS / SMC FDC37C665*/ ROM_P54TP4XE, /*ASUS P/I-P55TP4XE / 430FX / Award BIOS / SMC FDC37C665*/ + ROM_AP53, /*AOpen AP53 / 430HX / AMI BIOS / SMC FDC37C665/669*/ + ROM_P55T2S, /*ASUS P/I-P55T2S / 430HX / AMI BIOS / National Semiconductors PC87306*/ ROM_ACERM3A, /*Acer M3A / 430HX / Acer BIOS / SMC FDC37C932FR*/ ROM_ACERV35N, /*Acer V35N / 430HX / Acer BIOS / SMC FDC37C932FR*/ ROM_P55T2P4, /*ASUS P/I-P55T2P4 / 430HX / Award BIOS / Winbond W8387F*/ ROM_P55TVP4, /*ASUS P/I-P55TVP4 / 430HX / Award BIOS / Winbond W8387F*/ ROM_P55VA, /*Epox P55-VA / 430VX / Award BIOS / SMC FDC37C932FR*/ - ROM_440FX, /*Unknown / 440FX / Award BIOS / SMC FDC37C665*/ + ROM_440FX, /*Tyan Titan-Pro AT / 440FX / Award BIOS / SMC FDC37C665*/ ROM_MARL, /*Intel Advanced/ML / 430HX / AMI BIOS / National Semiconductors PC87306*/ ROM_THOR, /*Intel Advanced/ATX / 430FX / AMI BIOS / National Semiconductors PC87306*/ ROM_MRTHOR, /*Intel Advanced/ATX / 430FX / MR.BIOS / National Semiconductors PC87306*/ ROM_POWERMATE_V,/*NEC PowerMate V / 430FX / Phoenix BIOS / SMC FDC37C665*/ - + + ROM_IBMPS1_2121_ISA,/*IBM PS/1 Model 2121 with ISA expansion bus*/ + + ROM_SPC4200P, /*Samsung SPC-4200P / SCAT / Phoenix BIOS*/ + ROM_SUPER286TR, /*Hyundai Super-286TR / SCAT / Award BIOS*/ + + ROM_MEGAPCDX, /*386DX mdoel of the Mega PC - Note by Tohka: The documentation (that I have in German) clearly says such a model exists.*/ + ROM_ZAPPA, /*Intel Advanced/ZP / 430FX / AMI BIOS / National Semiconductors PC87306*/ + + ROM_CMDPC60, + + ROM_S1668, /*Tyan Titan-Pro ATX / 440FX / AMI BIOS / SMC FDC37C669*/ + ROM_IBMPS1_2133, + + ROM_PRESIDENT, /*President Award 430FX PCI / 430FX / Award BIOS / Unknown Super I/O chip*/ + ROM_MAX }; extern int romspresent[ROM_MAX]; -int hasfpu; -int romset; +extern int hasfpu; +extern int romset; enum { @@ -449,6 +506,9 @@ enum GFX_INCOLOR, /* Hercules InColor */ GFX_COLORPLUS, /* Plantronics ColorPlus */ GFX_WY700, /* Wyse 700 */ + GFX_GENIUS, /* MDSI Genius */ + GFX_MACH64VT2, /*ATI Mach64 VT2*/ + GFX_COMPAQ_EGA, /*Compaq EGA*/ GFX_SUPER_EGA, /*Using Chips & Technologies SuperEGA BIOS*/ GFX_COMPAQ_VGA, /*Compaq/Paradise VGA*/ @@ -466,6 +526,11 @@ enum GFX_RIVATNT2, GFX_TRIGEM_UNK, + GFX_OTI037, /*Oak OTI-037*/ + + GFX_VIRGEVX, /*S3 Virge/VX*/ + GFX_VIRGEDX4, /*S3 Virge/DX (VBE 2.0)*/ + GFX_MAX }; @@ -477,7 +542,6 @@ int cpuspeed; /*Video*/ -int readflash; extern int egareads,egawrites; extern int vid_resize; extern int vid_api; @@ -486,14 +550,14 @@ extern int changeframecount; /*Sound*/ -int ppispeakon; -float CGACONST; -float MDACONST; -float VGACONST1,VGACONST2; -float RTCCONST; -int gated,speakval,speakon; +extern int ppispeakon; +extern float CGACONST; +extern float MDACONST; +extern float VGACONST1,VGACONST2; +extern float RTCCONST; +extern int gated,speakval,speakon; -#define SOUNDBUFLEN (48000/10) +#define SOUNDBUFLEN (48000/50) /*Sound Blaster*/ @@ -508,38 +572,75 @@ int gated,speakval,speakon; #define SND_WSS 9 /*Windows Sound System*/ #define SND_PAS16 10 /*Pro Audio Spectrum 16*/ -char pcempath[512]; +extern wchar_t pcempath[512]; -/*Hard disc*/ - -typedef struct +/*Hard disk*/ +enum { - FILE *f; - uint64_t spt,hpc; /*Sectors per track, heads per cylinder*/ - uint64_t tracks; - int is_hdi; - uint32_t base; -} hard_disk_t; + HDD_BUS_DISABLED = 0, + HDD_BUS_MFM, + HDD_BUS_XTIDE, + HDD_BUS_RLL, + HDD_BUS_IDE_PIO_ONLY, + HDD_BUS_IDE_PIO_AND_DMA, + HDD_BUS_SCSI, + HDD_BUS_SCSI_REMOVABLE, + HDD_BUS_USB +}; +#define HDC_NUM 30 +#define MFM_NUM 2 +#define RLL_NUM 2 +#define XTIDE_NUM 2 #define IDE_NUM 8 +#define SCSI_NUM 16 /* Theoretically the controller can have at least 64 devices, or even 128 in case of a wide bus, but + let's not exaggerate with them - 16 ought to be enough for everyone. */ -hard_disk_t hdc[IDE_NUM]; +#pragma pack(push,1) +typedef struct { + FILE *f; + uint64_t spt,hpc; /*Sectors per track, heads per cylinder*/ + uint64_t tracks; + int is_hdi; + int wp; + uint32_t base; + uint64_t at_spt,at_hpc; /*[Translation] Sectors per track, heads per cylinder*/ + unsigned int bus; /* 0 = none, 1 = MFM/RLL, 2 = IDE, 3 = SCSI */ + unsigned int mfm_channel; + unsigned int rll_channel; + unsigned int xtide_channel; + unsigned int ide_channel; + unsigned int scsi_id; + unsigned int scsi_lun; + wchar_t fn[260]; + wchar_t prev_fn[260]; +} hard_disk_t; +#pragma pack(pop) + +extern hard_disk_t hdc[HDC_NUM]; uint64_t hdt[128][3]; +uint64_t hdt_mfm[128][3]; -int image_is_hdi(const char *s); +int image_is_hdi(const wchar_t *s); +int image_is_hdx(const wchar_t *s, int check_signature); /*Keyboard*/ -int keybsenddelay; +extern int keybsenddelay; /*CD-ROM*/ -extern int cdrom_drive; -extern int old_cdrom_drive; -extern int idecallback[4]; -extern int cdrom_enabled; -extern int scsi_cdrom_enabled; +enum +{ + CDROM_BUS_DISABLED = 0, + CDROM_BUS_ATAPI_PIO_ONLY = 4, + CDROM_BUS_ATAPI_PIO_AND_DMA, + CDROM_BUS_SCSI, + CDROM_BUS_USB = 8 +}; + +extern int idecallback[5]; #define CD_STATUS_EMPTY 0 #define CD_STATUS_DATA_ONLY 1 @@ -555,25 +656,24 @@ extern uint32_t SCSIGetCDChannel(int channel); extern int ui_writeprot[4]; -void pclog(const char *format, ...); -extern int nmi; +extern int nmi; +extern int nmi_auto_clear; extern float isa_timing, bus_timing; -uint64_t timer_read(); +extern uint64_t timer_read(void); extern uint64_t timer_freq; -void loadconfig(char *fn); - extern int infocus; -void onesec(); +extern void onesec(void); -void resetpc_cad(); +extern void resetpc_cad(void); +extern int dump_on_exit; extern int start_in_fullscreen; extern int window_w, window_h, window_x, window_y, window_remember; @@ -590,13 +690,112 @@ extern uint64_t star; #define FPU_CW_Reserved_Bits (0xe0c0) -extern char nvr_path[1024]; +extern wchar_t nvr_path[1024]; extern int path_len; -char *nvr_concat(char *to_concat); +wchar_t *nvr_concat(wchar_t *to_concat); -int mem_a20_state; +extern int mem_a20_state; -void fatal(const char *format, ...); -extern int scsi_model, scsi_base, scsi_irq, scsi_dma; +#ifdef ENABLE_LOG_TOGGLES +extern int buslogic_do_log; +extern int cdrom_do_log; +extern int d86f_do_log; +extern int fdc_do_log; +extern int ide_do_log; +extern int serial_do_log; +extern int nic_do_log; +#endif + +extern int suppress_overscan; + +typedef struct PCI_RESET +{ + void (*pci_master_reset)(void); + void (*pci_set_reset)(void); + void (*super_io_reset)(void); +} PCI_RESET; + +extern PCI_RESET pci_reset_handler; + +extern uint8_t trc_read(uint16_t port, void *priv); +extern void trc_write(uint16_t port, uint8_t val, void *priv); +extern void trc_init(void); + +extern int enable_xtide; +extern int enable_external_fpu; + +extern int serial_enabled[2]; +extern int lpt_enabled, bugger_enabled; + +extern int invert_display; + +uint32_t svga_color_transform(uint32_t color); + +extern int scale; + + +/* Function prototypes. */ +extern int checkio(int port); +extern void closepc(void); +extern void codegen_block_end(void); +extern void codegen_reset(void); +extern void cpu_set_edx(void); +extern int divl(uint32_t val); +extern void dumpregs(int __force); +extern void exec386(int cycs); +extern void exec386_dynarec(int cycs); +extern void execx86(int cycs); +extern void flushmmucache(void); +extern void flushmmucache_cr3(void); +extern int idivl(int32_t val); +extern void initmodules(void); +extern void initpc(int argc, wchar_t *argv[]); +extern void loadcscall(uint16_t seg); +extern void loadcsjmp(uint16_t seg, uint32_t oxpc); +extern void mmu_invalidate(uint32_t addr); +extern void pclog(const char *format, ...); +extern void pmodeint(int num, int soft); +extern void pmoderetf(int is32, uint16_t off); +extern void pmodeiret(int is32); +extern void port_92_clear_reset(void); +extern uint8_t readdacfifo(void); +extern void refreshread(void); +extern int rep386(int fv); +extern void resetmcr(void); +extern void resetpchard_close(void); +extern void resetpchard_init(void); +extern void resetpchard(void); +extern void resetreadlookup(void); +extern void resetx86(void); +extern void runpc(void); +extern void saveconfig(void); +extern void softresetx86(void); +extern void speedchanged(void); +extern void trc_reset(uint8_t val); +extern void x86_int_sw(int num); +extern void x86gpf(char *s, uint16_t error); +extern void x86np(char *s, uint16_t error); +extern void x86ss(char *s, uint16_t error); +extern void x86ts(char *s, uint16_t error); +extern void x87_dumpregs(void); +extern void x87_reset(void); + +/* Platform functions. */ +extern void pclog(const char *format, ...); +extern void pclog_w(const wchar_t *format, ...); +extern void fatal(const char *format, ...); + +extern void update_status_bar_icon(int tag, int active); +extern void update_status_bar_icon_state(int tag, int state); +extern void status_settextw(wchar_t *wstr); +extern void status_settext(char *str); + +#define SB_FLOPPY 0x00 +#define SB_CDROM 0x10 +#define SB_RDISK 0x20 +#define SB_HDD 0x40 +#define SB_TEXT 0x50 + +#define UNUSED(x) (void)x diff --git a/src/ide.c b/src/ide.c index 6aa901a1c..72eb186d7 100644 --- a/src/ide.c +++ b/src/ide.c @@ -1,22 +1,32 @@ -/* Copyright holders: Sarah Walker, Tenshi, SA1988 - see COPYING for more details -*/ -#define CDROM_ISO 200 -#define IDE_TIME (5 * 100 * (1 << TIMER_SHIFT)) - -#define _LARGEFILE_SOURCE -#define _LARGEFILE64_SOURCE -#define _GNU_SOURCE -#include -#include -#include +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Implementation of the IDE emulation for hard disks and ATAPI + * CD-ROM devices. + * + * Version: @(#)ide.c 1.0.4 2017/06/20 + * + * Authors: Sarah Walker, + * Miran Grca, + * TheCollector1995, + * Copyright 2008-2017 Sarah Walker. + * Copyright 2016-2017 Miran Grca. + * Copyright 2016-2017 TheCollector1995. + */ #include -#include - #include +#include +#include #include "86box.h" +#include "cdrom.h" #include "ibm.h" +#include "hdd_image.h" #include "io.h" #include "pic.h" #include "timer.h" @@ -46,7 +56,7 @@ #define WIN_WRITE 0x30 /* 28-Bit Write */ #define WIN_WRITE_NORETRY 0x31 /* 28-Bit Write */ #define WIN_VERIFY 0x40 /* 28-Bit Verify */ -#define WIN_VERIFY_ONCE 0x41 /* Added by OBattler - deprected older ATA command, according to the specification I found, it is identical to 0x40 */ +#define WIN_VERIFY_ONCE 0x41 /* Added by OBattler - deprected older ATA command, according to the specification I found, it is identical to 0x40 */ #define WIN_FORMAT 0x50 #define WIN_SEEK 0x70 #define WIN_DRIVE_DIAGNOSTICS 0x90 /* Execute Drive Diagnostics */ @@ -59,26 +69,14 @@ #define WIN_READ_DMA 0xC8 #define WIN_WRITE_DMA 0xCA #define WIN_STANDBYNOW1 0xE0 +#define WIN_IDLENOW1 0xE1 #define WIN_SETIDLE1 0xE3 #define WIN_CHECKPOWERMODE1 0xE5 +#define WIN_SLEEP1 0xE6 #define WIN_IDENTIFY 0xEC /* Ask drive to identify itself */ #define WIN_SET_FEATURES 0xEF #define WIN_READ_NATIVE_MAX 0xF8 -/** Evaluate to non-zero if the currently selected drive is an ATAPI device */ -#define IDE_DRIVE_IS_CDROM(ide) (ide->type == IDE_CDROM) - -#define ATAPI_STATUS_IDLE 0 -#define ATAPI_STATUS_COMMAND 1 -#define ATAPI_STATUS_COMPLETE 2 -#define ATAPI_STATUS_DATA 3 -#define ATAPI_STATUS_PACKET_REQ 4 -#define ATAPI_STATUS_PACKET_RECEIVED 5 -#define ATAPI_STATUS_READCD 6 -#define ATAPI_STATUS_REQ_SENSE 7 -#define ATAPI_STATUS_ERROR 0x80 -#define ATAPI_STATUS_ERROR_2 0x81 - enum { IDE_NONE = 0, @@ -86,26 +84,6 @@ enum IDE_CDROM }; -static struct -{ - uint8_t opcode; - uint8_t polled; - uint8_t reserved2[2]; - uint8_t class; - uint8_t reserved3[2]; - uint16_t len; - uint8_t control; -} *gesn_cdb; - -static struct -{ - uint16_t len; - uint8_t notification_class; - uint8_t supported_events; -} *gesn_event_header; - -static unsigned int used_len; - uint64_t hdt[128][3] = { { 306, 4, 17 }, { 615, 2, 17 }, { 306, 4, 26 }, { 1024, 2, 17 }, { 697, 3, 17 }, { 306, 8, 17 }, { 614, 4, 17 }, { 615, 4, 17 }, /* 000-007 */ { 670, 4, 17 }, { 697, 4, 17 }, { 987, 3, 17 }, { 820, 4, 17 }, { 670, 5, 17 }, { 697, 5, 17 }, { 733, 5, 17 }, { 615, 6, 17 }, /* 008-015 */ { 462, 8, 17 }, { 306, 8, 26 }, { 615, 4, 26 }, { 1024, 4, 17 }, { 855, 5, 17 }, { 925, 5, 17 }, { 932, 5, 17 }, { 1024, 2, 40 }, /* 016-023 */ @@ -123,99 +101,78 @@ uint64_t hdt[128][3] = { { 306, 4, 17 }, { 615, 2, 17 }, { 306, 4, 26 }, { { 1930, 4, 62 }, { 967, 16, 31 }, { 1013, 10, 63 }, { 1218, 15, 36 }, { 654, 16, 63 }, { 659, 16, 63 }, { 702, 16, 63 }, { 1002, 13, 63 }, /* 112-119 */ { 854, 16, 63 }, { 987, 16, 63 }, { 995, 16, 63 }, { 1024, 16, 63 }, { 1036, 16, 63 }, { 1120, 16, 59 }, { 1054, 16, 63 }, { 0, 0, 0 } }; /* 119-127 */ -typedef struct IDE -{ - int type; - int board; - uint8_t atastat; - uint8_t error; - int secount,sector,cylinder,head,drive,cylprecomp; - uint8_t command; - uint8_t fdisk; - int pos; - int packlen; - int spt,hpc; - int tracks; - int packetstatus; - uint8_t asc; - int reset; - FILE *hdfile; - uint16_t buffer[65536]; - int irqstat; - int service; - int lba; - uint32_t lba_addr; - int skip512; - int blocksize, blockcount; - uint16_t dma_identify_data[3]; - int hdi,base; - int hdc_num; -} IDE; - -IDE ide_drives[IDE_NUM]; +IDE ide_drives[IDE_NUM + XTIDE_NUM]; IDE *ext_ide; -char ide_fn[IDE_NUM][512]; - -int (*ide_bus_master_read_sector)(int channel, uint8_t *data); -int (*ide_bus_master_write_sector)(int channel, uint8_t *data); +int (*ide_bus_master_read)(int channel, uint8_t *data, int transfer_length); +int (*ide_bus_master_write)(int channel, uint8_t *data, int transfer_length); void (*ide_bus_master_set_irq)(int channel); -static void callnonreadcd(IDE *ide); -static void callreadcd(IDE *ide); -static void atapicommand(int ide_board); +int idecallback[5] = {0, 0, 0, 0, 0}; -int idecallback[4] = {0, 0, 0, 0}; +int cur_ide[5]; -int cur_ide[4]; +int ide_do_log = 0; -int atapi_command = 0; - -int atapi_cdrom_channel = 2; +void ide_log(const char *format, ...) +{ +#ifdef ENABLE_IDE_LOG + if (ide_do_log) + { + va_list ap; + va_start(ap, format); + vprintf(format, ap); + va_end(ap); + fflush(stdout); + } +#endif +} uint8_t getstat(IDE *ide) { return ide->atastat; } -int image_is_hdi(const char *s) +int ide_drive_is_cdrom(IDE *ide) { - int i, len; - char ext[5] = { 0, 0, 0, 0, 0 }; - len = strlen(s); - if ((len < 4) || (s[0] == '.')) + if (ide->channel >= 8) { return 0; } - memcpy(ext, s + len - 4, 4); - for (i = 0; i < 4; i++) + + if (atapi_cdrom_drives[ide->channel] >= CDROM_NUM) { - ext[i] = toupper(ext[i]); - } - if (strcmp(ext, ".HDI") == 0) - { - return 1; + return 0; } else { - return 0; + if ((cdrom_drives[atapi_cdrom_drives[ide->channel]].bus_type == CDROM_BUS_ATAPI_PIO_ONLY) || (cdrom_drives[atapi_cdrom_drives[ide->channel]].bus_type == CDROM_BUS_ATAPI_PIO_AND_DMA)) + { + return 1; + } + else + { + return 0; + } } } -int ide_enable[4] = { 1, 1, 0, 0 }; -int ide_irq[4] = { 14, 15, 10, 11 }; +int ide_enable[5] = { 1, 1, 0, 0, 1 }; +int ide_irq[5] = { 14, 15, 10, 11, 0 }; -static inline void ide_irq_raise(IDE *ide) +void ide_irq_raise(IDE *ide) { if ((ide->board > 3) || ide->irqstat) { + ide->irqstat=1; + ide->service=1; + return; } - // pclog("Raising IRQ %i (board %i)\n", ide_irq[ide->board], ide->board); + ide_log("Raising IRQ %i (board %i)\n", ide_irq[ide->board], ide->board); if (!(ide->fdisk&2)) { picint(1 << ide_irq[ide->board]); - // if (ide->board && !ide->irqstat) pclog("IDE_IRQ_RAISE\n"); if (ide->board < 2) { @@ -228,21 +185,20 @@ static inline void ide_irq_raise(IDE *ide) ide->irqstat=1; ide->service=1; - // pclog("raising interrupt %i\n", 14 + ide->board); } -static inline void ide_irq_lower(IDE *ide) +void ide_irq_lower(IDE *ide) { if ((ide->board > 3) || !(ide->irqstat)) { + ide->irqstat=0; return; } - // pclog("Lowering IRQ %i (board %i)\n", ide_irq[ide->board], ide->board); + ide_log("Lowering IRQ %i (board %i)\n", ide_irq[ide->board], ide->board); picintc(1 << ide_irq[ide->board]); ide->irqstat=0; - // ide->service=0; } void ide_irq_update(IDE *ide) @@ -258,8 +214,6 @@ void ide_irq_update(IDE *ide) mask = ide_irq[ide->board]; mask &= 7; - // pclog("Updating IRQ %i (%i) (board %i)\n", ide_irq[ide->board], mask, ide->board); - pending = (pic2.pend | pic2.ins); pending &= (1 << mask); @@ -309,8 +263,7 @@ ide_padstr(char *str, const char *src, int len) * this length will be padded with spaces. * @param src Source string */ -static void -ide_padstr8(uint8_t *buf, int buf_size, const char *src) +void ide_padstr8(uint8_t *buf, int buf_size, const char *src) { int i; @@ -332,27 +285,40 @@ ide_padstr8(uint8_t *buf, int buf_size, const char *src) */ static void ide_identify(IDE *ide) { - int c, h, s; + uint32_t c, h, s; + char device_identify[9] = { '8', '6', 'B', '_', 'H', 'D', '0', '0', 0 }; +#if 0 + uint64_t full_size = (hdc[ide->hdc_num].tracks * hdc[ide->hdc_num].hpc * hdc[ide->hdc_num].spt); +#endif + + device_identify[6] = (ide->hdc_num / 10) + 0x30; + device_identify[7] = (ide->hdc_num % 10) + 0x30; + ide_log("IDE Identify: %s\n", device_identify); memset(ide->buffer, 0, 512); - - //ide->buffer[1] = 101; /* Cylinders */ - c = hdc[cur_ide[ide->board]].tracks; /* Cylinders */ - h = hdc[cur_ide[ide->board]].hpc; /* Heads */ - s = hdc[cur_ide[ide->board]].spt; /* Sectors */ + c = hdc[ide->hdc_num].tracks; /* Cylinders */ + h = hdc[ide->hdc_num].hpc; /* Heads */ + s = hdc[ide->hdc_num].spt; /* Sectors */ - ide->buffer[1] = hdc[cur_ide[ide->board]].tracks; /* Cylinders */ - ide->buffer[3] = hdc[cur_ide[ide->board]].hpc; /* Heads */ - ide->buffer[6] = hdc[cur_ide[ide->board]].spt; /* Sectors */ + if (hdc[ide->hdc_num].tracks <= 16383) + { + ide->buffer[1] = hdc[ide->hdc_num].tracks; /* Cylinders */ + } + else + { + ide->buffer[1] = 16383; /* Cylinders */ + } + ide->buffer[3] = hdc[ide->hdc_num].hpc; /* Heads */ + ide->buffer[6] = hdc[ide->hdc_num].spt; /* Sectors */ ide_padstr((char *) (ide->buffer + 10), "", 20); /* Serial Number */ - ide_padstr((char *) (ide->buffer + 23), emulator_version, 8); /* Firmware */ - ide_padstr((char *) (ide->buffer + 27), "86BoxHD", 40); /* Model */ + ide_padstr((char *) (ide->buffer + 23), EMU_VERSION, 8); /* Firmware */ + ide_padstr((char *) (ide->buffer + 27), device_identify, 40); /* Model */ ide->buffer[20] = 3; /*Buffer type*/ ide->buffer[21] = 512; /*Buffer size*/ ide->buffer[47] = 16; /*Max sectors on multiple transfer command*/ ide->buffer[48] = 1; /*Dword transfers supported*/ - if (ide->board < 2) + if (PCI && (ide->board < 2) && (hdc[ide->hdc_num].bus == HDD_BUS_IDE_PIO_AND_DMA)) { ide->buffer[49] = (1 << 8); /* LBA and DMA supported */ } @@ -366,18 +332,39 @@ static void ide_identify(IDE *ide) } ide->buffer[50] = 0x4000; /* Capabilities */ ide->buffer[51] = 2 << 8; /*PIO timing mode*/ - ide->buffer[52] = 2 << 8; /*DMA timing mode*/ - ide->buffer[59] = ide->blocksize ? (ide->blocksize | 0x100) : 0; - ide->buffer[60] = (hdc[cur_ide[ide->board]].tracks * hdc[cur_ide[ide->board]].hpc * hdc[cur_ide[ide->board]].spt) & 0xFFFF; /* Total addressable sectors (LBA) */ - ide->buffer[61] = (hdc[cur_ide[ide->board]].tracks * hdc[cur_ide[ide->board]].hpc * hdc[cur_ide[ide->board]].spt) >> 16; - // ide->buffer[63] = 7; /*Multiword DMA*/ - if (ide->board < 2) +#if 0 + ide->buffer[53] = 1; + ide->buffer[55] = ide->hpc; + ide->buffer[56] = ide->spt; + if (((full_size / ide->hpc) / ide->spt) <= 16383) { - ide->buffer[62] = ide->dma_identify_data[0]; - ide->buffer[63] = ide->dma_identify_data[1]; - ide->buffer[80] = 0xe; /*ATA-1 to ATA-3 supported*/ - ide->buffer[88] = ide->dma_identify_data[2]; + ide->buffer[54] = (full_size / ide->hpc) / ide->spt; } + else + { + ide->buffer[54] = 16383; + } + full_size = ((uint64_t) ide->hpc) * ((uint64_t) ide->spt) * ((uint64_t) ide->buffer[54]); + ide->buffer[57] = full_size & 0xFFFF; /* Total addressable sectors (LBA) */ + ide->buffer[58] = (full_size >> 16) & 0x0FFF; +#endif + ide->buffer[59] = ide->blocksize ? (ide->blocksize | 0x100) : 0; + if (ide->buffer[49] & (1 << 9)) + { + ide->buffer[60] = (hdc[ide->hdc_num].tracks * hdc[ide->hdc_num].hpc * hdc[ide->hdc_num].spt) & 0xFFFF; /* Total addressable sectors (LBA) */ + ide->buffer[61] = ((hdc[ide->hdc_num].tracks * hdc[ide->hdc_num].hpc * hdc[ide->hdc_num].spt) >> 16) & 0x0FFF; + } + if (PCI && (ide->board < 2) && (hdc[ide->hdc_num].bus == HDD_BUS_IDE_PIO_AND_DMA)) + { + ide->buffer[52] = 2 << 8; /*DMA timing mode*/ + + ide->buffer[63] = 7; + if (ide->mdma_mode != -1) + { + ide->buffer[63] = (ide->mdma_mode << 8); + } + } + ide->buffer[80] = 0xe; /*ATA-1 to ATA-3 supported*/ } /** @@ -385,14 +372,30 @@ static void ide_identify(IDE *ide) */ static void ide_atapi_identify(IDE *ide) { + char device_identify[9] = { '8', '6', 'B', '_', 'C', 'D', '0', '0', 0 }; + uint8_t cdrom_id; + memset(ide->buffer, 0, 512); + cdrom_id = atapi_cdrom_drives[ide->channel]; + + device_identify[7] = cdrom_id + 0x30; + ide_log("ATAPI Identify: %s\n", device_identify); ide->buffer[0] = 0x8000 | (5<<8) | 0x80 | (2<<5); /* ATAPI device, CD-ROM drive, removable media, accelerated DRQ */ ide_padstr((char *) (ide->buffer + 10), "", 20); /* Serial Number */ - ide_padstr((char *) (ide->buffer + 23), emulator_version, 8); /* Firmware */ - ide_padstr((char *) (ide->buffer + 27), "86BoxCD", 40); /* Model */ + ide_padstr((char *) (ide->buffer + 23), EMU_VERSION, 8); /* Firmware */ + ide_padstr((char *) (ide->buffer + 27), device_identify, 40); /* Model */ ide->buffer[49] = 0x200; /* LBA supported */ - ide->buffer[51] = 2 << 8; /*PIO timing mode*/ + + if (PCI && (ide->board < 2) && (cdrom_drives[cdrom_id].bus_type == CDROM_BUS_ATAPI_PIO_AND_DMA)) + { + ide->buffer[48] = 1; /*Dword transfers supported*/ + ide->buffer[49] |= 0x100; /* DMA supported */ + ide->buffer[63] = 7; + ide->buffer[73] = 6; + ide->buffer[74] = 9; + ide->buffer[80] = 0x10; /*ATA/ATAPI-4 supported*/ + } } /* @@ -406,8 +409,8 @@ static off64_t ide_get_sector(IDE *ide) } else { - int heads = ide->hpc; - int sectors = ide->spt; + uint32_t heads = ide->hpc; + uint32_t sectors = ide->spt; return ((((off64_t) ide->cylinder * heads) + ide->head) * sectors) + (ide->sector - 1) + ide->skip512; @@ -439,166 +442,114 @@ static void ide_next_sector(IDE *ide) } } -static void loadhd(IDE *ide, int d, const char *fn) +static void loadhd(IDE *ide, int d, const wchar_t *fn) { - uint32_t sector_size = 512; - uint32_t zero = 0; - uint32_t full_size = 0; - int c; - ide->base = 0; - ide->hdi = 0; - if (ide->hdfile == NULL) + int ret = 0; + + ret = hdd_image_load(d); + + if (!ret) { - /* Try to open existing hard disk image */ - if (fn[0] == '.') - { - ide->type = IDE_NONE; - return; - } - ide->hdfile = fopen64(fn, "rb+"); - if (ide->hdfile == NULL) - { - /* Failed to open existing hard disk image */ - if (errno == ENOENT) - { - /* Failed because it does not exist, - so try to create new file */ - ide->hdfile = fopen64(fn, "wb+"); - if (ide->hdfile == NULL) - { - ide->type = IDE_NONE; - return; - } - else - { - if (image_is_hdi(fn)) - { - full_size = hdc[d].spt * hdc[d].hpc * hdc[d].tracks * 512; - ide->base = 0x1000; - ide->hdi = 1; - fwrite(&zero, 1, 4, ide->hdfile); - fwrite(&zero, 1, 4, ide->hdfile); - fwrite(&(ide->base), 1, 4, ide->hdfile); - fwrite(&full_size, 1, 4, ide->hdfile); - fwrite(§or_size, 1, 4, ide->hdfile); - fwrite(&(hdc[d].spt), 1, 4, ide->hdfile); - fwrite(&(hdc[d].hpc), 1, 4, ide->hdfile); - fwrite(&(hdc[d].tracks), 1, 4, ide->hdfile); - for (c = 0; c < 0x3f8; c++) - { - fwrite(&zero, 1, 4, ide->hdfile); - } - } - ide->hdc_num = d; - } - } - else - { - /* Failed for another reason */ - ide->type = IDE_NONE; - return; - } - } - else - { - if (image_is_hdi(fn)) - { - fseeko64(ide->hdfile, 0x8, SEEK_SET); - fread(&(ide->base), 1, 4, ide->hdfile); - fseeko64(ide->hdfile, 0x10, SEEK_SET); - fread(§or_size, 1, 4, ide->hdfile); - if (sector_size != 512) - { - /* Sector size is not 512 */ - fclose(ide->hdfile); - ide->type = IDE_NONE; - return; - } - fread(&(hdc[d].spt), 1, 4, ide->hdfile); - fread(&(hdc[d].hpc), 1, 4, ide->hdfile); - fread(&(hdc[d].tracks), 1, 4, ide->hdfile); - ide->hdi = 1; - } - } + ide->type = IDE_NONE; + return; } - - ide->spt = hdc[d].spt; - ide->hpc = hdc[d].hpc; - ide->tracks = hdc[d].tracks; - ide->type = IDE_HDD; + + ide->spt = hdc[d].spt; + ide->hpc = hdc[d].hpc; + ide->tracks = hdc[d].tracks; + ide->type = IDE_HDD; ide->hdc_num = d; + ide->hdi = hdd_image_get_type(d); } void ide_set_signature(IDE *ide) { - ide->secount=1; + uint8_t cdrom_id = atapi_cdrom_drives[ide->channel]; ide->sector=1; ide->head=0; - ide->cylinder=(IDE_DRIVE_IS_CDROM(ide) ? 0xEB14 : ((ide->type == IDE_HDD) ? 0 : 0xFFFF)); - if (ide->type == IDE_HDD) + if (ide_drive_is_cdrom(ide)) { - ide->drive = 0; + cdrom_set_signature(cdrom_id); + ide->secount = cdrom[cdrom_id].phase; + ide->cylinder = cdrom[cdrom_id].request_length; + } + else + { + ide->secount=1; + ide->cylinder=((ide->type == IDE_HDD) ? 0 : 0xFFFF); + if (ide->type == IDE_HDD) + { + ide->drive = 0; + } } } -int ide_set_features(IDE *ide) +int ide_cdrom_is_pio_only(IDE *ide) { - uint8_t val = ide->secount & 7; - - if (ide->type == IDE_NONE) return 0; - - switch(ide->cylprecomp) + uint8_t cdrom_id = atapi_cdrom_drives[cur_ide[ide->board]]; + if (!ide_drive_is_cdrom(ide)) { - case 0x02: - case 0x82: - return 0; - case 0xcc: - case 0x66: - case 0xaa: - case 0x55: - case 0x05: - case 0x85: - case 0x69: - case 0x67: - case 0x96: - case 0x9a: - case 0x42: - case 0xc2: - return 1; - case 0x03: - if (ide->type == IDE_CDROM) + return 0; + } + if (cdrom_drives[cdrom_id].bus_type == CDROM_BUS_ATAPI_PIO_AND_DMA) + { + return 0; + } + return 1; +} + +static int ide_set_features(IDE *ide) +{ + uint8_t features, features_data; + uint8_t mode, submode; + + features = ide->cylprecomp; + features_data = ide->secount; + + ide_log("Features code %02X\n", features); + + switch(features) + { + case 0x03: /* Set transfer mode. */ + ide_log("Transfer mode %02X\n", features_data >> 3); + + mode = (features_data >> 3); + submode = features_data & 7; + + switch(mode) { - return 0; - } - switch(ide->secount >> 3) - { - case 0: - case 1: - ide->dma_identify_data[0] = ide->dma_identify_data[1] = 7; - ide->dma_identify_data[2] = 0x3f; - break; - case 2: - if ((ide->type == IDE_CDROM) || (ide->board >= 2)) + case 0x00: /* PIO default */ + if (submode != 0) { return 0; } - ide->dma_identify_data[0] = 7 | (1 << (val + 8)); - ide->dma_identify_data[1] = 7; - ide->dma_identify_data[2] = 0x3f; + ide->mdma_mode = -1; break; - case 4: - if ((ide->type == IDE_CDROM) || (ide->board >= 2)) + + case 0x01: /* PIO mode */ + if (submode > 2) { return 0; } - ide->dma_identify_data[0] = 7; - ide->dma_identify_data[1] = 7 | (1 << (val + 8)); - ide->dma_identify_data[2] = 0x3f; + ide->mdma_mode = -1; break; + + case 0x04: /* Multiword DMA mode */ + if (!PCI || (hdc[ide->hdc_num].bus != HDD_BUS_IDE_PIO_AND_DMA) || (ide->board >= 2) || (submode > 2)) + { + return 0; + } + ide->mdma_mode = (1 << submode); + break; + default: return 0; } + + default: + return 0; } + return 1; } @@ -613,146 +564,171 @@ void ide_set_sector(IDE *ide, int64_t sector_num) } else { - cyl = sector_num / (hdc[cur_ide[ide->board]].hpc * hdc[cur_ide[ide->board]].spt); - r = sector_num % (hdc[cur_ide[ide->board]].hpc * hdc[cur_ide[ide->board]].spt); + cyl = sector_num / (hdc[ide->hdc_num].hpc * hdc[ide->hdc_num].spt); + r = sector_num % (hdc[ide->hdc_num].hpc * hdc[ide->hdc_num].spt); ide->cylinder = cyl; - ide->head = ((r / hdc[cur_ide[ide->board]].spt) & 0x0f); - ide->sector = (r % hdc[cur_ide[ide->board]].spt) + 1; + ide->head = ((r / hdc[ide->hdc_num].spt) & 0x0f); + ide->sector = (r % hdc[ide->hdc_num].spt) + 1; } } +void ide_ter_disable_cond(); +void ide_qua_disable_cond(); + void resetide(void) { - int d; + int c, d; + + build_atapi_cdrom_map(); /* Close hard disk image files (if previously open) */ - for (d = 0; d < IDE_NUM; d++) + for (d = 0; d < (IDE_NUM + XTIDE_NUM); d++) { + ide_drives[d].channel = d; ide_drives[d].type = IDE_NONE; - if (ide_drives[d].hdfile != NULL) + hdd_image_close(ide_drives[d].hdc_num); + if (ide_drive_is_cdrom(&ide_drives[d])) { - fclose(ide_drives[d].hdfile); - ide_drives[d].hdfile = NULL; + cdrom[atapi_cdrom_drives[d]].status = READY_STAT | DSC_STAT; } ide_drives[d].atastat = READY_STAT | DSC_STAT; ide_drives[d].service = 0; ide_drives[d].board = d >> 1; } - page_flags[GPMODE_CDROM_AUDIO_PAGE] &= 0xFD; /* Clear changed flag for CDROM AUDIO mode page. */ - memset(mode_pages_in[GPMODE_CDROM_AUDIO_PAGE], 0, 256); /* Clear the page itself. */ - idecallback[0]=idecallback[1]=0; idecallback[2]=idecallback[3]=0; + idecallback[4]=0; + + c = 0; + for (d = 0; d < HDC_NUM; d++) + { + if (((hdc[d].bus == HDD_BUS_IDE_PIO_ONLY) || (hdc[d].bus == HDD_BUS_IDE_PIO_AND_DMA)) && (hdc[d].ide_channel < IDE_NUM)) + { + ide_log("Found IDE hard disk on channel %i\n", hdc[d].ide_channel); + loadhd(&ide_drives[hdc[d].ide_channel], d, hdc[d].fn); + c++; + if (c >= (IDE_NUM + XTIDE_NUM)) break; + } + if ((hdc[d].bus == HDD_BUS_XTIDE) && (hdc[d].xtide_channel < XTIDE_NUM)) + { + ide_log("Found XT IDE hard disk on channel %i\n", hdc[d].xtide_channel); + loadhd(&ide_drives[hdc[d].xtide_channel | 8], d, hdc[d].fn); + c++; + if (c >= (IDE_NUM + XTIDE_NUM)) break; + } + } for (d = 0; d < IDE_NUM; d++) { - ide_drives[d].packetstatus = 0xFF; - - if ((atapi_cdrom_channel == d) && cdrom_enabled && !scsi_cdrom_enabled) + if (ide_drive_is_cdrom(&ide_drives[d]) && (ide_drives[d].type != IDE_HDD)) { ide_drives[d].type = IDE_CDROM; } - else - { - loadhd(&ide_drives[d], d, ide_fn[d]); - } ide_set_signature(&ide_drives[d]); - if (ide_drives[d].type != IDE_NONE) + if (ide_drives[d].type == IDE_HDD) { - ide_drives[d].dma_identify_data[0] = 7; - ide_drives[d].dma_identify_data[1] = 7 | (1 << 15); - ide_drives[d].dma_identify_data[2] = 0x3f; + ide_drives[d].mdma_mode = 0; } ide_drives[d].error = 1; } - for (d = 0; d < 4; d++) + for (d = 0; d < XTIDE_NUM; d++) + { + ide_set_signature(&ide_drives[d | 8]); + + if (ide_drives[d | 8].type == IDE_HDD) + { + ide_drives[d | 8].mdma_mode = 0; + } + + ide_drives[d | 8].error = 1; + } + + for (d = 0; d < 5; d++) { cur_ide[d] = d << 1; } - - page_flags[GPMODE_CDROM_AUDIO_PAGE] &= ~PAGE_CHANGED; - SCSISense.UnitAttention = 0; + ide_ter_disable_cond(); + ide_qua_disable_cond(); } -int idetimes=0; -void writeidew(int ide_board, uint16_t val) +int idetimes = 0; + +void ide_write_data(int ide_board, uint32_t val, int length) { IDE *ide = &ide_drives[cur_ide[ide_board]]; + + uint8_t *idebufferb = (uint8_t *) ide->buffer; + uint16_t *idebufferw = ide->buffer; + uint32_t *idebufferl = (uint32_t *) ide->buffer; -#if 0 - if (ide->type == IDE_CDROM) - { - pclog("CD-ROM write data: %04X\n", val); - } -#endif - - /* Some software issue excess writes after the 12 bytes required by the command, this will have all of them ignored. */ - if (ide->packetstatus && (ide->packetstatus != ATAPI_STATUS_PACKET_REQ)) + if (ide->command == WIN_PACKETCMD) { + ide->pos = 0; + + if (!ide_drive_is_cdrom(ide)) + { + return; + } + + cdrom_write(cur_ide[ide_board], val, length); + + if (cdrom[atapi_cdrom_drives[cur_ide[ide_board]]].callback) + { + idecallback[ide_board] = cdrom[atapi_cdrom_drives[cur_ide[ide_board]]].callback; + } return; } - - // pclog("Write IDEw %04X\n",val); - ide->buffer[ide->pos >> 1] = val; - ide->pos+=2; - - if (ide->packetstatus == ATAPI_STATUS_PACKET_REQ) + else { - if ((ide->pos>=prefix_len+4) && (page_flags[page_current] & PAGE_CHANGEABLE)) + switch(length) { - mode_pages_in[page_current][ide->pos - prefix_len - 4] = ((uint8_t *) ide->buffer)[ide->pos - 2]; - mode_pages_in[page_current][ide->pos - prefix_len - 3] = ((uint8_t *) ide->buffer)[ide->pos - 1]; + case 1: + idebufferb[ide->pos] = val & 0xff; + ide->pos++; + break; + case 2: + idebufferw[ide->pos >> 1] = val & 0xffff; + ide->pos += 2; + break; + case 4: + idebufferl[ide->pos >> 2] = val; + ide->pos += 4; + break; + default: + return; } - if (ide->pos>=(ide->packlen+2)) + + if (ide->pos>=512) { - ide->packetstatus = ATAPI_STATUS_PACKET_RECEIVED; + ide->pos=0; + ide->atastat = BUSY_STAT; timer_process(); - idecallback[ide_board]=6*IDE_TIME; + if (ide->command == WIN_WRITE_MULTIPLE) + { + callbackide(ide_board); + } + else + { + idecallback[ide_board]=6*IDE_TIME; + } timer_update_outstanding(); - // pclog("Packet over!\n"); - ide_irq_lower(ide); } - return; - } - else if (ide->packetstatus == ATAPI_STATUS_PACKET_RECEIVED) - { - return; - } - else if (ide->command == WIN_PACKETCMD && ide->pos>=0xC) - { - ide->pos=0; - ide->atastat = BUSY_STAT; - ide->packetstatus = ATAPI_STATUS_COMMAND; - timer_process(); - callbackide(ide_board); - timer_update_outstanding(); - } - else if (ide->pos>=512) - { - ide->pos=0; - ide->atastat = BUSY_STAT; - timer_process(); - if (ide->command == WIN_WRITE_MULTIPLE) - { - callbackide(ide_board); - } - else - { - idecallback[ide_board]=6*IDE_TIME; - } - timer_update_outstanding(); } } +void writeidew(int ide_board, uint16_t val) +{ + ide_write_data(ide_board, val, 2); +} + void writeidel(int ide_board, uint32_t val) { - // pclog("WriteIDEl %08X\n", val); writeidew(ide_board, val); writeidew(ide_board, val >> 16); } @@ -762,7 +738,7 @@ void writeide(int ide_board, uint16_t addr, uint8_t val) IDE *ide = &ide_drives[cur_ide[ide_board]]; IDE *ide_other = &ide_drives[cur_ide[ide_board] ^ 1]; - // pclog("WriteIDE %04X %02X from %04X(%08X):%08X %i\n", addr, val, CS, cs, cpu_state.pc, ins); + ide_log("WriteIDE %04X %02X from %04X(%08X):%08X %i\n", addr, val, CS, cs, cpu_state.pc, ins); addr|=0x90; addr&=0xFFF7; @@ -770,42 +746,85 @@ void writeide(int ide_board, uint16_t addr, uint8_t val) switch (addr) { - case 0x1F0: /* Data */ + case 0x1F0: /* Data */ writeidew(ide_board, val | (val << 8)); return; - case 0x1F1: /* Features */ + /* Note to self: for ATAPI, bit 0 of this is DMA if set, PIO if clear. */ + case 0x1F1: /* Features */ + if (ide_drive_is_cdrom(ide)) + { + cdrom[atapi_cdrom_drives[cur_ide[ide_board]]].features = val; + } ide->cylprecomp = val; + + if (ide_drive_is_cdrom(ide_other)) + { + cdrom[atapi_cdrom_drives[cur_ide[ide_board] ^ 1]].features = val; + } ide_other->cylprecomp = val; return; - case 0x1F2: /* Sector count */ + case 0x1F2: /* Sector count */ + if (ide_drive_is_cdrom(ide)) + { + ide_log("Sector count write: %i\n", val); + cdrom[atapi_cdrom_drives[cur_ide[ide_board]]].phase = val; + } ide->secount = val; + + if (ide_drive_is_cdrom(ide_other)) + { + ide_log("Other sector count write: %i\n", val); + cdrom[atapi_cdrom_drives[cur_ide[ide_board] ^ 1]].phase = val; + } ide_other->secount = val; return; - case 0x1F3: /* Sector */ + case 0x1F3: /* Sector */ ide->sector = val; ide->lba_addr = (ide->lba_addr & 0xFFFFF00) | val; ide_other->sector = val; ide_other->lba_addr = (ide_other->lba_addr & 0xFFFFF00) | val; return; - case 0x1F4: /* Cylinder low */ + case 0x1F4: /* Cylinder low */ + if (ide_drive_is_cdrom(ide)) + { + cdrom[atapi_cdrom_drives[cur_ide[ide_board]]].request_length &= 0xFF00; + cdrom[atapi_cdrom_drives[cur_ide[ide_board]]].request_length |= val; + } ide->cylinder = (ide->cylinder & 0xFF00) | val; ide->lba_addr = (ide->lba_addr & 0xFFF00FF) | (val << 8); + + if (ide_drive_is_cdrom(ide_other)) + { + cdrom[atapi_cdrom_drives[cur_ide[ide_board] ^ 1]].request_length &= 0xFF00; + cdrom[atapi_cdrom_drives[cur_ide[ide_board] ^ 1]].request_length |= val; + } ide_other->cylinder = (ide_other->cylinder&0xFF00) | val; ide_other->lba_addr = (ide_other->lba_addr&0xFFF00FF) | (val << 8); return; - case 0x1F5: /* Cylinder high */ + case 0x1F5: /* Cylinder high */ + if (ide_drive_is_cdrom(ide)) + { + cdrom[atapi_cdrom_drives[cur_ide[ide_board]]].request_length &= 0xFF; + cdrom[atapi_cdrom_drives[cur_ide[ide_board]]].request_length |= (val << 8); + } ide->cylinder = (ide->cylinder & 0xFF) | (val << 8); ide->lba_addr = (ide->lba_addr & 0xF00FFFF) | (val << 16); + + if (ide_drive_is_cdrom(ide_other)) + { + cdrom[atapi_cdrom_drives[cur_ide[ide_board] ^ 1]].request_length &= 0xFF; + cdrom[atapi_cdrom_drives[cur_ide[ide_board] ^ 1]].request_length |= (val << 8); + } ide_other->cylinder = (ide_other->cylinder & 0xFF) | (val << 8); ide_other->lba_addr = (ide_other->lba_addr & 0xF00FFFF) | (val << 16); return; - case 0x1F6: /* Drive/Head */ + case 0x1F6: /* Drive/Head */ if (cur_ide[ide_board] != ((val>>4)&1)+(ide_board<<1)) { cur_ide[ide_board]=((val>>4)&1)+(ide_board<<1); @@ -820,13 +839,23 @@ void writeide(int ide_board, uint16_t addr, uint8_t val) ide->cylinder = ide_other->cylinder = 0; ide->reset = ide_other->reset = 0; - if (IDE_DRIVE_IS_CDROM(ide)) + if (ide_drive_is_cdrom(ide)) { - ide->cylinder=0xEB14; + cdrom[atapi_cdrom_drives[ide->channel]].status = READY_STAT | DSC_STAT; + cdrom[atapi_cdrom_drives[ide->channel]].error = 1; + cdrom[atapi_cdrom_drives[ide->channel]].phase = 1; + cdrom[atapi_cdrom_drives[ide->channel]].request_length = 0xEB14; + cdrom[atapi_cdrom_drives[ide->channel]].callback = 0; + ide->cylinder = 0xEB14; } - if (IDE_DRIVE_IS_CDROM(ide_other)) + if (ide_drive_is_cdrom(ide_other)) { - ide_other->cylinder=0xEB14; + cdrom[atapi_cdrom_drives[ide_other->channel]].status = READY_STAT | DSC_STAT; + cdrom[atapi_cdrom_drives[ide_other->channel]].error = 1; + cdrom[atapi_cdrom_drives[ide_other->channel]].phase = 1; + cdrom[atapi_cdrom_drives[ide_other->channel]].request_length = 0xEB14; + cdrom[atapi_cdrom_drives[ide_other->channel]].callback = 0; + ide->cylinder = 0xEB14; } idecallback[ide_board] = 0; @@ -848,150 +877,278 @@ void writeide(int ide_board, uint16_t addr, uint8_t val) ide_irq_update(ide); return; - case 0x1F7: /* Command register */ + case 0x1F7: /* Command register */ if (ide->type == IDE_NONE) { - ide->error=1; return; } -#if 0 - if (ide->type == IDE_CDROM) - { - pclog("Write CD-ROM ATA command: %02X\n", val); - } -#endif - ide_irq_lower(ide); - ide->command=val; - - // pclog("New IDE command - %02X %i %i\n",ide->command,cur_ide[ide_board],ide_board); - ide->error=0; - switch (val) - { - case WIN_SRST: /* ATAPI Device Reset */ - if (IDE_DRIVE_IS_CDROM(ide)) - { - ide->atastat = BUSY_STAT; - } - else - { - ide->atastat = READY_STAT; - } - timer_process(); - idecallback[ide_board]=100*IDE_TIME; - timer_update_outstanding(); - return; - case WIN_RESTORE: - case WIN_SEEK: - ide->atastat = READY_STAT; - timer_process(); - idecallback[ide_board]=100*IDE_TIME; - timer_update_outstanding(); - return; + ide_irq_lower(ide); + ide->command=val; - case WIN_READ_MULTIPLE: - /* Fatal removed in accordance with the official ATAPI reference: - If the Read Multiple command is attempted before the Set Multiple Mode - command has been executed or when Read Multiple commands are - disabled, the Read Multiple operation is rejected with an Aborted Com- - mand error. */ - ide->blockcount = 0; - - case WIN_READ: - case WIN_READ_NORETRY: - case WIN_READ_DMA: + ide->error=0; + if (ide_drive_is_cdrom(ide)) + { + cdrom[atapi_cdrom_drives[ide->channel]].error = 0; + } + switch (val) + { + case WIN_SRST: /* ATAPI Device Reset */ + if (ide_drive_is_cdrom(ide)) + { + cdrom[atapi_cdrom_drives[ide->channel]].status = BUSY_STAT; + } + else + { + ide->atastat = READY_STAT; + } + timer_process(); + if (ide_drive_is_cdrom(ide)) + { + cdrom[atapi_cdrom_drives[ide->channel]].callback = 100*IDE_TIME; + } + idecallback[ide_board]=100*IDE_TIME; + timer_update_outstanding(); + return; + + case WIN_RESTORE: + case WIN_SEEK: + if (ide_drive_is_cdrom(ide)) + { + cdrom[atapi_cdrom_drives[ide->channel]].status = READY_STAT; + } + else + { + ide->atastat = READY_STAT; + } + timer_process(); + if (ide_drive_is_cdrom(ide)) + { + cdrom[atapi_cdrom_drives[ide->channel]].callback = 100*IDE_TIME; + } + idecallback[ide_board]=100*IDE_TIME; + timer_update_outstanding(); + return; + + case WIN_READ_MULTIPLE: + /* Fatal removed in accordance with the official ATAPI reference: + If the Read Multiple command is attempted before the Set Multiple Mode + command has been executed or when Read Multiple commands are + disabled, the Read Multiple operation is rejected with an Aborted Com- + mand error. */ + ide->blockcount = 0; + + case WIN_READ: + case WIN_READ_NORETRY: + case WIN_READ_DMA: + if (ide_drive_is_cdrom(ide)) + { + cdrom[atapi_cdrom_drives[ide->channel]].status = BUSY_STAT; + } + else + { ide->atastat = BUSY_STAT; - timer_process(); - idecallback[ide_board]=200*IDE_TIME; - timer_update_outstanding(); - return; - - case WIN_WRITE_MULTIPLE: - if (!ide->blocksize && (ide->type != IDE_CDROM)) - { - fatal("Write_MULTIPLE - blocksize = 0\n"); - } - ide->blockcount = 0; - - case WIN_WRITE: - case WIN_WRITE_NORETRY: + } + timer_process(); + if (ide_drive_is_cdrom(ide)) + { + cdrom[atapi_cdrom_drives[ide->channel]].callback = 200*IDE_TIME; + } + idecallback[ide_board]=200*IDE_TIME; + timer_update_outstanding(); + ide->do_initial_read = 1; + return; + + case WIN_WRITE_MULTIPLE: + if (!ide->blocksize && !ide_drive_is_cdrom(ide)) + { + fatal("Write_MULTIPLE - blocksize = 0\n"); + } + ide->blockcount = 0; + + case WIN_WRITE: + case WIN_WRITE_NORETRY: + if (ide_drive_is_cdrom(ide)) + { + cdrom[atapi_cdrom_drives[ide->channel]].status = DRQ_STAT | DSC_STAT | READY_STAT; + cdrom[atapi_cdrom_drives[ide->channel]].pos = 0; + } + else + { ide->atastat = DRQ_STAT | DSC_STAT | READY_STAT; ide->pos=0; - return; + } + return; - case WIN_WRITE_DMA: + case WIN_WRITE_DMA: + if (ide_drive_is_cdrom(ide)) + { + cdrom[atapi_cdrom_drives[ide->channel]].status = BUSY_STAT; + } + else + { ide->atastat = BUSY_STAT; - timer_process(); - idecallback[ide_board]=200*IDE_TIME; - timer_update_outstanding(); - return; + } + timer_process(); + if (ide_drive_is_cdrom(ide)) + { + cdrom[atapi_cdrom_drives[ide->channel]].callback = 200*IDE_TIME; + } + idecallback[ide_board]=200*IDE_TIME; + timer_update_outstanding(); + return; - case WIN_VERIFY: - case WIN_VERIFY_ONCE: + case WIN_VERIFY: + case WIN_VERIFY_ONCE: + if (ide_drive_is_cdrom(ide)) + { + cdrom[atapi_cdrom_drives[ide->channel]].status = BUSY_STAT; + } + else + { ide->atastat = BUSY_STAT; - timer_process(); - idecallback[ide_board]=200*IDE_TIME; - timer_update_outstanding(); - return; + } + timer_process(); + if (ide_drive_is_cdrom(ide)) + { + cdrom[atapi_cdrom_drives[ide->channel]].callback = 200*IDE_TIME; + } + idecallback[ide_board]=200*IDE_TIME; + timer_update_outstanding(); + return; - case WIN_FORMAT: + case WIN_FORMAT: + if (ide_drive_is_cdrom(ide)) + { + goto ide_bad_command; + } + else + { ide->atastat = DRQ_STAT; ide->pos=0; - return; + } + return; - case WIN_SPECIFY: /* Initialize Drive Parameters */ + case WIN_SPECIFY: /* Initialize Drive Parameters */ + if (ide_drive_is_cdrom(ide)) + { + cdrom[atapi_cdrom_drives[ide->channel]].status = BUSY_STAT; + } + else + { ide->atastat = BUSY_STAT; + } + timer_process(); + if (ide_drive_is_cdrom(ide)) + { + cdrom[atapi_cdrom_drives[ide->channel]].callback = 30*IDE_TIME; + } + idecallback[ide_board]=30*IDE_TIME; + timer_update_outstanding(); + return; + + case WIN_DRIVE_DIAGNOSTICS: /* Execute Drive Diagnostics */ + case WIN_PIDENTIFY: /* Identify Packet Device */ + case WIN_SET_MULTIPLE_MODE: /* Set Multiple Mode */ + case WIN_SET_FEATURES: /* Set Features */ + case WIN_NOP: + case WIN_STANDBYNOW1: + case WIN_IDLENOW1: + case WIN_SETIDLE1: /* Idle */ + case WIN_CHECKPOWERMODE1: + case WIN_SLEEP1: + if (val == WIN_DRIVE_DIAGNOSTICS) + { + if (ide_drive_is_cdrom(ide)) + { + cdrom[atapi_cdrom_drives[ide->channel]].status = BUSY_STAT; + } + else + { + ide->atastat = BUSY_STAT; + } timer_process(); - idecallback[ide_board]=30*IDE_TIME; + callbackide(ide_board); + if (ide_drive_is_cdrom(ide)) + { + cdrom[atapi_cdrom_drives[ide->channel]].callback = 200 * IDE_TIME; + } + idecallback[ide_board] = 200 * IDE_TIME; timer_update_outstanding(); - return; - - case WIN_DRIVE_DIAGNOSTICS: /* Execute Drive Diagnostics */ - case WIN_PIDENTIFY: /* Identify Packet Device */ - case WIN_SET_MULTIPLE_MODE: /*Set Multiple Mode*/ - case WIN_NOP: - case WIN_STANDBYNOW1: - case WIN_SETIDLE1: /* Idle */ - case WIN_CHECKPOWERMODE1: - ide->atastat = BUSY_STAT; + } + else + { + if (ide_drive_is_cdrom(ide)) + { + cdrom[atapi_cdrom_drives[ide->channel]].status = BUSY_STAT; + } + else + { + ide->atastat = BUSY_STAT; + } timer_process(); - idecallback[ide_board]=30*IDE_TIME; + if (ide_drive_is_cdrom(ide)) + { + cdrom[atapi_cdrom_drives[ide->channel]].callback = 30 * IDE_TIME; + } + idecallback[ide_board] = 30 * IDE_TIME; timer_update_outstanding(); - return; + } + return; - case WIN_IDENTIFY: /* Identify Device */ - case WIN_SET_FEATURES: - case WIN_READ_NATIVE_MAX: + case WIN_IDENTIFY: /* Identify Device */ + case WIN_READ_NATIVE_MAX: + if (ide_drive_is_cdrom(ide)) + { + cdrom[atapi_cdrom_drives[ide->channel]].status = BUSY_STAT; + } + else + { + ide->atastat = BUSY_STAT; + } + timer_process(); + if (ide_drive_is_cdrom(ide)) + { + cdrom[atapi_cdrom_drives[ide->channel]].callback = 200*IDE_TIME; + } + idecallback[ide_board]=200*IDE_TIME; + timer_update_outstanding(); + return; + + case WIN_PACKETCMD: /* ATAPI Packet */ + /* Skip the command callback wait, and process immediately. */ + if (ide_drive_is_cdrom(ide)) + { + cdrom[atapi_cdrom_drives[ide->channel]].packet_status = CDROM_PHASE_IDLE; + cdrom[atapi_cdrom_drives[ide->channel]].pos=0; + cdrom[atapi_cdrom_drives[ide->channel]].phase = 1; + cdrom[atapi_cdrom_drives[ide->channel]].status = READY_STAT | DRQ_STAT | (cdrom[cur_ide[ide_board]].status & ERR_STAT); + } + else + { ide->atastat = BUSY_STAT; timer_process(); - idecallback[ide_board]=200*IDE_TIME; - timer_update_outstanding(); - return; - - case WIN_PACKETCMD: /* ATAPI Packet */ -#if 0 - ide->packetstatus = ATAPI_STATUS_IDLE; - ide->atastat = BUSY_STAT; - timer_process(); - // idecallback[ide_board]=1;//30*IDE_TIME; - idecallback[ide_board]=30*IDE_TIME; + idecallback[ide_board]=1; timer_update_outstanding(); ide->pos=0; -#endif - /* Skip the command callbackwait, and process immediately. */ - ide->packetstatus = ATAPI_STATUS_IDLE; - readcdmode=0; - ide->pos=0; - ide->secount = 1; - ide->atastat = READY_STAT | DRQ_STAT |(ide->atastat&ERR_STAT); - return; - - case 0xF0: - default: - ide->atastat = READY_STAT | ERR_STAT | DSC_STAT; - ide->error = ABRT_ERR; - ide_irq_raise(ide); - return; + } + return; + + case 0xF0: + default: +ide_bad_command: + if (ide_drive_is_cdrom(ide)) + { + cdrom[atapi_cdrom_drives[ide->channel]].status = READY_STAT | ERR_STAT | DSC_STAT; + cdrom[atapi_cdrom_drives[ide->channel]].error = ABRT_ERR; + } + else + { + ide->atastat = READY_STAT | ERR_STAT | DSC_STAT; + ide->error = ABRT_ERR; + } + ide_irq_raise(ide); + return; } return; @@ -999,6 +1156,10 @@ void writeide(int ide_board, uint16_t addr, uint8_t val) if ((ide->fdisk & 4) && !(val&4) && (ide->type != IDE_NONE || ide_other->type != IDE_NONE)) { timer_process(); + if (ide_drive_is_cdrom(ide)) + { + cdrom[atapi_cdrom_drives[ide->channel]].callback = 0; + } idecallback[ide_board]=500*IDE_TIME; timer_update_outstanding(); @@ -1010,14 +1171,104 @@ void writeide(int ide_board, uint16_t addr, uint8_t val) { ide->reset = 1; } + if (ide_drive_is_cdrom(ide)) + { + cdrom[atapi_cdrom_drives[ide->channel]].status = BUSY_STAT; + } + ide->atastat = ide_other->atastat = BUSY_STAT; + } + if (val & 4) + { + /*Drive held in reset*/ + timer_process(); + idecallback[ide_board] = 0; + timer_update_outstanding(); ide->atastat = ide_other->atastat = BUSY_STAT; - // pclog("IDE Reset %i\n", ide_board); } ide->fdisk = ide_other->fdisk = val; ide_irq_update(ide); return; } - // fatal("Bad IDE write %04X %02X\n", addr, val); +} + +uint32_t ide_read_data(int ide_board, int length) +{ + IDE *ide = &ide_drives[cur_ide[ide_board]]; + uint32_t temp; + + uint8_t *idebufferb = (uint8_t *) ide->buffer; + uint16_t *idebufferw = ide->buffer; + uint32_t *idebufferl = (uint32_t *) ide->buffer; + + if (ide->command == WIN_PACKETCMD) + { + ide->pos = 0; + if (!ide_drive_is_cdrom(ide)) + { + ide_log("Drive not CD-ROM (position: %i)\n", ide->pos); + return 0; + } + temp = cdrom_read(cur_ide[ide_board], length); + if (cdrom[atapi_cdrom_drives[cur_ide[ide_board]]].callback) + { + idecallback[ide_board] = cdrom[atapi_cdrom_drives[cur_ide[ide_board]]].callback; + } + } + else + { + switch (length) + { + case 1: + temp = idebufferb[ide->pos]; + ide->pos++; + break; + case 2: + temp = idebufferw[ide->pos >> 1]; + ide->pos += 2; + break; + case 4: + temp = idebufferl[ide->pos >> 2]; + ide->pos += 4; + break; + default: + return 0; + } + } + if (ide->pos>=512 && ide->command != WIN_PACKETCMD) + { + ide->pos=0; + ide->atastat = READY_STAT | DSC_STAT; + if (ide_drive_is_cdrom(ide)) + { + cdrom[atapi_cdrom_drives[cur_ide[ide_board]]].status = READY_STAT | DSC_STAT; + cdrom[atapi_cdrom_drives[cur_ide[ide_board]]].packet_status = CDROM_PHASE_IDLE; + } + if (ide->command == WIN_READ || ide->command == WIN_READ_NORETRY || ide->command == WIN_READ_MULTIPLE) + { + ide->secount = (ide->secount - 1) & 0xff; + if (ide->secount) + { + ide_next_sector(ide); + ide->atastat = BUSY_STAT; + timer_process(); + if (ide->command == WIN_READ_MULTIPLE) + { + callbackide(ide_board); + } + else + { + idecallback[ide_board]=6*IDE_TIME; + } + timer_update_outstanding(); + } + else + { + update_status_bar_icon(SB_HDD | hdc[ide->hdc_num].bus, 0); + } + } + } + + return temp; } uint8_t readide(int ide_board, uint16_t addr) @@ -1025,19 +1276,9 @@ uint8_t readide(int ide_board, uint16_t addr) IDE *ide = &ide_drives[cur_ide[ide_board]]; uint8_t temp; uint16_t tempw; - - addr|=0x90; - addr&=0xFFF7; - - if (ide->type == IDE_NONE && (addr == 0x1f0 || addr == 0x1f7)) - { - if (addr == 0x1f7) - { - /* This is apparently required for an empty ID channel. */ - return 0x20; - } - return 0; - } + + addr |= 0x90; + addr &= 0xFFF7; switch (addr) { @@ -1045,38 +1286,54 @@ uint8_t readide(int ide_board, uint16_t addr) tempw = readidew(ide_board); temp = tempw & 0xff; break; - + + /* For ATAPI: Bits 7-4 = sense key, bit 3 = MCR (media change requested), + Bit 2 = ABRT (aborted command), Bit 1 = EOM (end of media), + and Bit 0 = ILI (illegal length indication). */ case 0x1F1: /* Error */ if (ide->type == IDE_NONE) { - temp = 1; + temp = 0; } else { - temp = ide->error; + if (ide_drive_is_cdrom(ide)) + { + temp = cdrom[atapi_cdrom_drives[cur_ide[ide_board]]].error; + } + else + { + temp = ide->error; + } } break; + /* For ATAPI: + Bit 0: Command or Data: + Data if clear, Command if set; + Bit 1: I/OB + Direction: + To device if set; + From device if clear. + IO DRQ CoD + 0 1 1 Ready to accept command packet + 1 1 1 Message - ready to send message to host + 1 1 0 Data to host + 0 1 0 Data from host + 1 0 1 Status. */ case 0x1F2: /* Sector count */ - if (ide->type == IDE_NONE) + if (ide_drive_is_cdrom(ide)) { - temp = 1; + temp = cdrom[atapi_cdrom_drives[cur_ide[ide_board]]].phase; } else { - temp = (uint8_t)ide->secount; + temp = ide->secount; } break; case 0x1F3: /* Sector */ - if (ide->type == IDE_NONE) - { - temp = 1; - } - else - { - temp = (uint8_t)ide->sector; - } + temp = (uint8_t)ide->sector; break; case 0x1F4: /* Cylinder low */ @@ -1086,7 +1343,14 @@ uint8_t readide(int ide_board, uint16_t addr) } else { - temp = (uint8_t)(ide->cylinder&0xFF); + if (ide_drive_is_cdrom(ide)) + { + temp = cdrom[atapi_cdrom_drives[cur_ide[ide_board]]].request_length & 0xff; + } + else + { + temp = ide->cylinder & 0xff; + } } break; @@ -1097,27 +1361,32 @@ uint8_t readide(int ide_board, uint16_t addr) } else { - temp = (uint8_t)(ide->cylinder>>8); + if (ide_drive_is_cdrom(ide)) + { + temp = cdrom[atapi_cdrom_drives[cur_ide[ide_board]]].request_length >> 8; + } + else + { + temp = ide->cylinder >> 8; + } } break; case 0x1F6: /* Drive/Head */ - if (ide->type == IDE_NONE) - { - temp = (uint8_t)(((cur_ide[ide_board] & 1) ? 0x10 : 0) | 0xa0); - } - else - { - temp = (uint8_t)(ide->head | ((cur_ide[ide_board] & 1) ? 0x10 : 0) | (ide->lba ? 0x40 : 0) | 0xa0); - } + temp = (uint8_t)(ide->head | ((cur_ide[ide_board] & 1) ? 0x10 : 0) | (ide->lba ? 0x40 : 0) | 0xa0); break; + /* For ATAPI: Bit 5 is DMA ready, but without overlapped or interlaved DMA, it is + DF (drive fault). */ case 0x1F7: /* Status */ ide_irq_lower(ide); - if (ide->type == IDE_CDROM) + if (ide->type == IDE_NONE) { - temp = (ide->atastat & ~DSC_STAT) | (ide->service ? SERVICE_STAT : 0); - // pclog("Read CD-ROM status: %02X\n", temp); + return 0; + } + if (ide_drive_is_cdrom(ide)) + { + temp = (cdrom[atapi_cdrom_drives[cur_ide[ide_board]]].status & ~DSC_STAT) | (ide->service ? SERVICE_STAT : 0); } else { @@ -1128,78 +1397,42 @@ uint8_t readide(int ide_board, uint16_t addr) case 0x3F6: /* Alternate Status */ if (ide->type == IDE_NONE) { - temp = DSC_STAT; - break; + return 0; } - if (ide->type == IDE_CDROM) + if (ide_drive_is_cdrom(ide)) { - temp = (ide->atastat & ~DSC_STAT) | (ide->service ? SERVICE_STAT : 0); + temp = (cdrom[atapi_cdrom_drives[cur_ide[ide_board]]].status & ~DSC_STAT) | (ide->service ? SERVICE_STAT : 0); } else { temp = ide->atastat; } break; + + default: + return 0xff; } - // /* if (ide_board) */ pclog("Read IDEb %04X %02X %02X %02X %i %04X:%04X %i\n", addr, temp, ide->atastat,(ide->atastat & ~DSC_STAT) | (ide->service ? SERVICE_STAT : 0),cur_ide[ide_board],CS,cpu_state.pc,ide_board); + /* if (ide_board) */ ide_log("Read IDEb %04X %02X %02X %02X %i %04X:%04X %i\n", addr, temp, ide->atastat,(ide->atastat & ~DSC_STAT) | (ide->service ? SERVICE_STAT : 0),cur_ide[ide_board],CS,cpu_state.pc,ide_board); return temp; - // fatal("Bad IDE read %04X\n", addr); } +uint8_t cdb[16]; + +int old_len = 0; + +int total_read = 0; + +int block_total = 0; +int all_blocks_total = 0; + uint16_t readidew(int ide_board) { - IDE *ide = &ide_drives[cur_ide[ide_board]]; - uint16_t temp; - - temp = ide->buffer[ide->pos >> 1]; - - ide->pos+=2; - if ((ide->command == WIN_PACKETCMD) && ((ide->packetstatus == ATAPI_STATUS_REQ_SENSE) || (ide->packetstatus==8))) - { - callnonreadcd(ide); - return temp; - } - if ((ide->pos>=512 && ide->command != WIN_PACKETCMD) || (ide->command == WIN_PACKETCMD && ide->pos>=ide->packlen)) - { - ide->pos=0; - if (ide->command == WIN_PACKETCMD)// && ide.packetstatus==6) - { - callreadcd(ide); - } - else - { - ide->atastat = READY_STAT | DSC_STAT; - ide->packetstatus = ATAPI_STATUS_IDLE; - if (ide->command == WIN_READ || ide->command == WIN_READ_NORETRY || ide->command == WIN_READ_MULTIPLE) - { - ide->secount = (ide->secount - 1) & 0xff; - if (ide->secount) - { - ide_next_sector(ide); - ide->atastat = BUSY_STAT; - timer_process(); - if (ide->command == WIN_READ_MULTIPLE) - { - callbackide(ide_board); - } - else - { - idecallback[ide_board]=6*IDE_TIME; - } - timer_update_outstanding(); - } - } - } - } - - // pclog("Read IDEw %04X\n",temp); - return temp; + return ide_read_data(ide_board, 2); } uint32_t readidel(int ide_board) { uint16_t temp; - // pclog("Read IDEl %i\n", ide_board); temp = readidew(ide_board); return temp | (readidew(ide_board) << 16); } @@ -1207,16 +1440,26 @@ uint32_t readidel(int ide_board) int times30=0; void callbackide(int ide_board) { - IDE *ide = &ide_drives[cur_ide[ide_board]]; - IDE *ide_other = &ide_drives[cur_ide[ide_board] ^ 1]; - off64_t addr; - uint64_t faddr; - int c; - ext_ide = ide; + IDE *ide, *ide_other; int64_t snum; + int cdrom_id; + uint64_t full_size = 0; + ide = &ide_drives[cur_ide[ide_board]]; + ide_other = &ide_drives[cur_ide[ide_board] ^ 1]; + if (ide->type == IDE_HDD) + { + full_size = (hdc[ide->hdc_num].tracks * hdc[ide->hdc_num].hpc * hdc[ide->hdc_num].spt); + } + ext_ide = ide; + + if (ide_drive_is_cdrom(ide)) + { + cdrom[atapi_cdrom_drives[cur_ide[ide_board]]].callback = 0; + } + if (ide->command==0x30) times30++; - // /*if (ide_board) */pclog("CALLBACK %02X %i %i %i\n",ide->command,times30,ide->reset,cur_ide[ide_board]); + /*if (ide_board) */ide_log("CALLBACK %02X %i %i %i\n",ide->command,times30,ide->reset,cur_ide[ide_board]); if (ide->reset) { @@ -1228,112 +1471,176 @@ void callbackide(int ide_board) ide->cylinder = ide_other->cylinder = 0; ide->reset = ide_other->reset = 0; - if (IDE_DRIVE_IS_CDROM(ide)) + if (ide_drive_is_cdrom(ide)) { - ide->cylinder=0xEB14; - cdrom->stop(); + cdrom_id = atapi_cdrom_drives[cur_ide[ide_board]]; + cdrom[cdrom_id].status = READY_STAT | DSC_STAT; + cdrom[cdrom_id].error = 1; + cdrom[cdrom_id].phase = 1; + cdrom[cdrom_id].request_length=0xEB14; + ide->cylinder = 0xEB14; + if (cdrom_drives[cdrom_id].handler->stop) + { + cdrom_drives[cdrom_id].handler->stop(cdrom_id); + } } if (ide->type == IDE_NONE) { ide->cylinder=0xFFFF; - cdrom->stop(); } - if (IDE_DRIVE_IS_CDROM(ide_other)) + if (ide_drive_is_cdrom(ide_other)) { - ide_other->cylinder=0xEB14; - cdrom->stop(); + cdrom_id = atapi_cdrom_drives[cur_ide[ide_board] ^ 1]; + cdrom[cdrom_id].status = READY_STAT | DSC_STAT; + cdrom[cdrom_id].error = 1; + cdrom[cdrom_id].phase = 1; + cdrom[cdrom_id].request_length=0xEB14; + ide_other->cylinder = 0xEB14; + if (cdrom_drives[cdrom_id].handler->stop) + { + cdrom_drives[cdrom_id].handler->stop(cdrom_id); + } } if (ide_other->type == IDE_NONE) { ide_other->cylinder=0xFFFF; - cdrom->stop(); } - // pclog("Reset callback\n"); return; } + cdrom_id = atapi_cdrom_drives[cur_ide[ide_board]]; + switch (ide->command) { /* Initialize the Task File Registers as follows: Status = 00h, Error = 01h, Sector Count = 01h, Sector Number = 01h, Cylinder Low = 14h, Cylinder High =EBh and Drive/Head = 00h. */ - case WIN_SRST: /*ATAPI Device Reset */ + case WIN_SRST: /*ATAPI Device Reset */ ide->atastat = READY_STAT | DSC_STAT; ide->error=1; /*Device passed*/ ide->secount = ide->sector = 1; ide_set_signature(ide); - if (IDE_DRIVE_IS_CDROM(ide)) + if (ide_drive_is_cdrom(ide)) { - ide->atastat = 0; + cdrom[cdrom_id].status = READY_STAT | DSC_STAT; + cdrom[cdrom_id].error = 1; + cdrom[cdrom_id].phase = 1; + cdrom_reset(cdrom_id); } ide_irq_raise(ide); - if (IDE_DRIVE_IS_CDROM(ide)) + if (ide_drive_is_cdrom(ide)) { ide->service = 0; } return; - case WIN_RESTORE: - case WIN_SEEK: - if (IDE_DRIVE_IS_CDROM(ide)) + case WIN_RESTORE: + case WIN_SEEK: + if (ide_drive_is_cdrom(ide)) { goto abort_cmd; } case WIN_NOP: case WIN_STANDBYNOW1: + case WIN_IDLENOW1: case WIN_SETIDLE1: - ide->atastat = READY_STAT | DSC_STAT; + if (ide_drive_is_cdrom(ide)) + { + cdrom[cdrom_id].status = READY_STAT | DSC_STAT; + } + else + { + ide->atastat = READY_STAT | DSC_STAT; + } ide_irq_raise(ide); return; case WIN_CHECKPOWERMODE1: - if (IDE_DRIVE_IS_CDROM(ide)) + case WIN_SLEEP1: + if (ide_drive_is_cdrom(ide)) { - goto abort_cmd; + cdrom[cdrom_id].phase = 0xFF; + cdrom[cdrom_id].status = READY_STAT | DSC_STAT; } ide->secount = 0xFF; ide->atastat = READY_STAT | DSC_STAT; ide_irq_raise(ide); return; - case WIN_READ: - case WIN_READ_NORETRY: - if (IDE_DRIVE_IS_CDROM(ide)) + case WIN_READ: + case WIN_READ_NORETRY: + if (ide_drive_is_cdrom(ide)) { ide_set_signature(ide); goto abort_cmd; } - addr = ide_get_sector(ide) * 512; + if (!ide->specify_success) + { + goto id_not_found; + } - fseeko64(ide->hdfile, ide->base + addr, SEEK_SET); - fread(ide->buffer, 512, 1, ide->hdfile); + if (ide->do_initial_read) + { + ide->do_initial_read = 0; + ide->sector_pos = 0; + if (ide->secount) + { + hdd_image_read(ide->hdc_num, ide_get_sector(ide), ide->secount, ide->sector_buffer); + } + else + { + hdd_image_read(ide->hdc_num, ide_get_sector(ide), 256, ide->sector_buffer); + } + } + + memcpy(ide->buffer, &ide->sector_buffer[ide->sector_pos*512], 512); + + ide->sector_pos++; ide->pos=0; + ide->atastat = DRQ_STAT | READY_STAT | DSC_STAT; ide_irq_raise(ide); - readflash=1; + update_status_bar_icon(SB_HDD | hdc[ide->hdc_num].bus, 1); return; - case WIN_READ_DMA: - if (IDE_DRIVE_IS_CDROM(ide) || (ide->board >= 2)) + case WIN_READ_DMA: + if (ide_drive_is_cdrom(ide) || (ide->board >= 2)) { goto abort_cmd; } - addr = ide_get_sector(ide) * 512; - fseeko64(ide->hdfile, addr, SEEK_SET); - fread(ide->buffer, 512, 1, ide->hdfile); + if (!ide->specify_success) + { + goto id_not_found; + } + + if (ide->do_initial_read) + { + ide->do_initial_read = 0; + ide->sector_pos = 0; + if (ide->secount) + { + hdd_image_read(ide->hdc_num, ide_get_sector(ide), ide->secount, ide->sector_buffer); + } + else + { + hdd_image_read(ide->hdc_num, ide_get_sector(ide), 256, ide->sector_buffer); + } + } + ide->pos=0; - if (ide_bus_master_read_sector) + if (ide_bus_master_read) { - if (ide_bus_master_read_sector(ide_board, (uint8_t *)ide->buffer)) + if (ide_bus_master_read(ide_board, &ide->sector_buffer[ide->sector_pos*512], 512)) { idecallback[ide_board]=6*IDE_TIME; /*DMA not performed, try again later*/ } else { /*DMA successful*/ + ide->sector_pos++; ide->atastat = DRQ_STAT | READY_STAT | DSC_STAT; ide->secount = (ide->secount - 1) & 0xff; @@ -1342,37 +1649,56 @@ void callbackide(int ide_board) ide_next_sector(ide); ide->atastat = BUSY_STAT; idecallback[ide_board]=6*IDE_TIME; + update_status_bar_icon(SB_HDD | hdc[ide->hdc_num].bus, 1); } else { ide_irq_raise(ide); + update_status_bar_icon(SB_HDD | hdc[ide->hdc_num].bus, 0); } } } - readflash=1; return; - case WIN_READ_MULTIPLE: + case WIN_READ_MULTIPLE: /* According to the official ATA reference: If the Read Multiple command is attempted before the Set Multiple Mode command has been executed or when Read Multiple commands are disabled, the Read Multiple operation is rejected with an Aborted Com- mand error. */ - if (IDE_DRIVE_IS_CDROM(ide) || !ide->blocksize) + if (ide_drive_is_cdrom(ide) || !ide->blocksize) { goto abort_cmd; } + if (!ide->specify_success) + { + goto id_not_found; + } - addr = ide_get_sector(ide) * 512; - fseeko64(ide->hdfile, ide->base + addr, SEEK_SET); - fread(ide->buffer, 512, 1, ide->hdfile); + if (ide->do_initial_read) + { + ide->do_initial_read = 0; + ide->sector_pos = 0; + if (ide->secount) + { + hdd_image_read(ide->hdc_num, ide_get_sector(ide), ide->secount, ide->sector_buffer); + } + else + { + hdd_image_read(ide->hdc_num, ide_get_sector(ide), 256, ide->sector_buffer); + } + } + + memcpy(ide->buffer, &ide->sector_buffer[ide->sector_pos*512], 512); + + ide->sector_pos++; ide->pos=0; + ide->atastat = DRQ_STAT | READY_STAT | DSC_STAT; if (!ide->blockcount) { - // pclog("Read multiple int\n"); ide_irq_raise(ide); } ide->blockcount++; @@ -1381,18 +1707,20 @@ void callbackide(int ide_board) ide->blockcount = 0; } - readflash=1; + update_status_bar_icon(SB_HDD | hdc[ide->hdc_num].bus, 1); return; - case WIN_WRITE: - case WIN_WRITE_NORETRY: - if (IDE_DRIVE_IS_CDROM(ide)) + case WIN_WRITE: + case WIN_WRITE_NORETRY: + if (ide_drive_is_cdrom(ide)) { goto abort_cmd; } - addr = ide_get_sector(ide) * 512; - fseeko64(ide->hdfile, ide->base + addr, SEEK_SET); - fwrite(ide->buffer, 512, 1, ide->hdfile); + if (!ide->specify_success) + { + goto id_not_found; + } + hdd_image_write(ide->hdc_num, ide_get_sector(ide), 1, (uint8_t *) ide->buffer); ide_irq_raise(ide); ide->secount = (ide->secount - 1) & 0xff; if (ide->secount) @@ -1400,33 +1728,36 @@ void callbackide(int ide_board) ide->atastat = DRQ_STAT | READY_STAT | DSC_STAT; ide->pos=0; ide_next_sector(ide); + update_status_bar_icon(SB_HDD | hdc[ide->hdc_num].bus, 1); } else { ide->atastat = READY_STAT | DSC_STAT; + update_status_bar_icon(SB_HDD | hdc[ide->hdc_num].bus, 0); } - readflash=1; return; - case WIN_WRITE_DMA: - if (IDE_DRIVE_IS_CDROM(ide) || (ide_board >= 2)) + case WIN_WRITE_DMA: + if (ide_drive_is_cdrom(ide) || (ide_board >= 2)) { goto abort_cmd; } - - if (ide_bus_master_write_sector) + if (!ide->specify_success) { - if (ide_bus_master_write_sector(ide_board, (uint8_t *)ide->buffer)) + goto id_not_found; + } + + if (ide_bus_master_write) + { + if (ide_bus_master_write(ide_board, (uint8_t *)ide->buffer, 512)) { idecallback[ide_board]=6*IDE_TIME; /*DMA not performed, try again later*/ } else { /*DMA successful*/ - addr = ide_get_sector(ide) * 512; - fseeko64(ide->hdfile, ide->base + addr, SEEK_SET); - fwrite(ide->buffer, 512, 1, ide->hdfile); + hdd_image_write(ide->hdc_num, ide_get_sector(ide), 1, (uint8_t *) ide->buffer); ide->atastat = DRQ_STAT | READY_STAT | DSC_STAT; @@ -1436,25 +1767,28 @@ void callbackide(int ide_board) ide_next_sector(ide); ide->atastat = BUSY_STAT; idecallback[ide_board]=6*IDE_TIME; + update_status_bar_icon(SB_HDD | hdc[ide->hdc_num].bus, 1); } else { ide_irq_raise(ide); + update_status_bar_icon(SB_HDD | hdc[ide->hdc_num].bus, 0); } } } - readflash=1; return; - case WIN_WRITE_MULTIPLE: - if (IDE_DRIVE_IS_CDROM(ide)) + case WIN_WRITE_MULTIPLE: + if (ide_drive_is_cdrom(ide)) { goto abort_cmd; } - addr = ide_get_sector(ide) * 512; - fseeko64(ide->hdfile, ide->base + addr, SEEK_SET); - fwrite(ide->buffer, 512, 1, ide->hdfile); + if (!ide->specify_success) + { + goto id_not_found; + } + hdd_image_write(ide->hdc_num, ide_get_sector(ide), 1, (uint8_t *) ide->buffer); ide->blockcount++; if (ide->blockcount >= ide->blocksize || ide->secount == 1) { @@ -1467,124 +1801,143 @@ void callbackide(int ide_board) ide->atastat = DRQ_STAT | READY_STAT | DSC_STAT; ide->pos=0; ide_next_sector(ide); + update_status_bar_icon(SB_HDD | hdc[ide->hdc_num].bus, 1); } else { ide->atastat = READY_STAT | DSC_STAT; + update_status_bar_icon(SB_HDD | hdc[ide->hdc_num].bus, 0); } - - readflash=1; return; case WIN_VERIFY: case WIN_VERIFY_ONCE: - if (IDE_DRIVE_IS_CDROM(ide)) + if (ide_drive_is_cdrom(ide)) { goto abort_cmd; } + if (!ide->specify_success) + { + goto id_not_found; + } ide->pos=0; ide->atastat = READY_STAT | DSC_STAT; ide_irq_raise(ide); - readflash=1; + update_status_bar_icon(SB_HDD | hdc[ide->hdc_num].bus, 1); return; - case WIN_FORMAT: - if (IDE_DRIVE_IS_CDROM(ide)) + case WIN_FORMAT: + if (ide_drive_is_cdrom(ide)) { goto abort_cmd; } - addr = ide_get_sector(ide) * 512; - // pclog("Format cyl %i head %i offset %08X %08X %08X secount %i\n",ide.cylinder,ide.head,addr,addr>>32,addr,ide.secount); - fseeko64(ide->hdfile, ide->base + addr, SEEK_SET); - memset(ide->buffer, 0, 512); - for (c=0;csecount;c++) + if (!ide->specify_success) { - fwrite(ide->buffer, 512, 1, ide->hdfile); + goto id_not_found; } + hdd_image_zero(ide->hdc_num, ide_get_sector(ide), ide->secount); + ide->atastat = READY_STAT | DSC_STAT; ide_irq_raise(ide); - readflash=1; + /* update_status_bar_icon(SB_HDD | hdc[ide->hdc_num].bus, 1); */ return; - case WIN_DRIVE_DIAGNOSTICS: + case WIN_DRIVE_DIAGNOSTICS: ide_set_signature(ide); ide->error=1; /*No error detected*/ - if (IDE_DRIVE_IS_CDROM(ide)) + if (ide_drive_is_cdrom(ide)) { - ide->atastat = 0; + cdrom[cdrom_id].status = 0; + cdrom[cdrom_id].error = 1; + ide_irq_raise(ide); } else { ide->atastat = READY_STAT | DSC_STAT; + ide->error = 1; ide_irq_raise(ide); } return; - case WIN_SPECIFY: /* Initialize Drive Parameters */ - if (IDE_DRIVE_IS_CDROM(ide)) + case WIN_SPECIFY: /* Initialize Drive Parameters */ + if (ide_drive_is_cdrom(ide)) { goto abort_cmd; } + full_size /= (ide->head+1); + full_size /= ide->secount; + ide->specify_success = 1; + hdd_image_specify(ide->hdc_num, ide->head + 1, ide->secount); ide->spt=ide->secount; ide->hpc=ide->head+1; ide->atastat = READY_STAT | DSC_STAT; ide_irq_raise(ide); return; - case WIN_PIDENTIFY: /* Identify Packet Device */ - if (IDE_DRIVE_IS_CDROM(ide)) + case WIN_PIDENTIFY: /* Identify Packet Device */ + if (ide_drive_is_cdrom(ide)) { ide_atapi_identify(ide); - ide->pos=0; - ide->error=0; - ide->atastat = DRQ_STAT | READY_STAT | DSC_STAT; + ide->pos = 0; + cdrom[cdrom_id].pos = 0; + cdrom[cdrom_id].error = 0; + cdrom[cdrom_id].status = DRQ_STAT | READY_STAT | DSC_STAT; ide_irq_raise(ide); return; } goto abort_cmd; - case WIN_SET_MULTIPLE_MODE: - if (IDE_DRIVE_IS_CDROM(ide)) + case WIN_SET_MULTIPLE_MODE: + if (ide_drive_is_cdrom(ide)) { goto abort_cmd; } ide->blocksize = ide->secount; ide->atastat = READY_STAT | DSC_STAT; - // pclog("Set multiple mode - %i\n", ide->blocksize); ide_irq_raise(ide); return; case WIN_SET_FEATURES: - if (!(ide_set_features(ide))) + if ((ide->type == IDE_NONE) || ide_drive_is_cdrom(ide)) { goto abort_cmd; } - ide->atastat = READY_STAT | DSC_STAT; - ide_irq_raise(ide); + + if (!ide_set_features(ide)) + { + goto abort_cmd; + } + else + { + ide->atastat = READY_STAT | DSC_STAT; + ide_irq_raise(ide); + } return; - + case WIN_READ_NATIVE_MAX: - if (ide->type != IDE_HDD) + if ((ide->type != IDE_HDD) || ide_drive_is_cdrom(ide)) { goto abort_cmd; } - snum = hdc[cur_ide[ide->board]].spt; - snum *= hdc[cur_ide[ide->board]].hpc; - snum *= hdc[cur_ide[ide->board]].tracks; + snum = hdc[ide->hdc_num].spt; + snum *= hdc[ide->hdc_num].hpc; + snum *= hdc[ide->hdc_num].tracks; ide_set_sector(ide, snum - 1); ide->atastat = READY_STAT | DSC_STAT; ide_irq_raise(ide); return; - - case WIN_IDENTIFY: /* Identify Device */ + + case WIN_IDENTIFY: /* Identify Device */ if (ide->type == IDE_NONE) { ide_set_signature(ide); + cdrom[cdrom_id].status = READY_STAT | ERR_STAT | DSC_STAT; + cdrom[cdrom_id].pos = 0; goto abort_cmd; } - if (IDE_DRIVE_IS_CDROM(ide)) + if (ide_drive_is_cdrom(ide)) { ide_set_signature(ide); goto abort_cmd; @@ -1598,83 +1951,41 @@ void callbackide(int ide_board) } return; - case WIN_PACKETCMD: /* ATAPI Packet */ - if (!IDE_DRIVE_IS_CDROM(ide)) + case WIN_PACKETCMD: /* ATAPI Packet */ + if (!ide_drive_is_cdrom(ide)) { goto abort_cmd; } - if (ide->packetstatus == ATAPI_STATUS_IDLE) - { - // pclog("ATAPI_STATUS_IDLE\n"); - readcdmode=0; - ide->pos=0; - ide->secount = 1; - ide->atastat = READY_STAT | DRQ_STAT |(ide->atastat&ERR_STAT); - } - else if (ide->packetstatus == ATAPI_STATUS_COMMAND) - { - // pclog("ATAPI_STATUS_COMMAND\n"); - ide->atastat = BUSY_STAT|(ide->atastat&ERR_STAT); - atapicommand(ide_board); - } - else if (ide->packetstatus == ATAPI_STATUS_COMPLETE) - { - // pclog("ATAPI_STATUS_COMPLETE\n"); - ide->atastat = READY_STAT; - ide->secount=3; - ide_irq_raise(ide); - } - else if (ide->packetstatus == ATAPI_STATUS_DATA) - { - // pclog("ATAPI_STATUS_DATA\n"); - ide->atastat = READY_STAT|DRQ_STAT|(ide->atastat&ERR_STAT); - ide_irq_raise(ide); - ide->packetstatus=0xFF; - } - else if (ide->packetstatus == ATAPI_STATUS_PACKET_REQ) - { - // pclog("ATAPI_STATUS_PACKET_REQ\n"); - ide->atastat = 0x58 | (ide->atastat & ERR_STAT); - ide_irq_raise(ide); - ide->pos=2; - } - else if (ide->packetstatus == ATAPI_STATUS_PACKET_RECEIVED) - { - // pclog("ATAPI_STATUS_PACKET_RECEIVED\n"); - atapicommand(ide_board); - } - else if (ide->packetstatus == ATAPI_STATUS_READCD) /*READ CD callback*/ - { - // pclog("ATAPI_STATUS_READCD\n"); - ide->atastat = DRQ_STAT|(ide->atastat&ERR_STAT); - ide_irq_raise(ide); - } - else if (ide->packetstatus == ATAPI_STATUS_REQ_SENSE) /*REQUEST SENSE callback #1*/ - { - // pclog("ATAPI_STATUS_REQ_SENSE\n"); - ide->atastat = 0x58 | (ide->atastat & ERR_STAT); - ide_irq_raise(ide); - } - else if (ide->packetstatus == ATAPI_STATUS_ERROR) /*Error callback*/ - { - // pclog("ATAPI_STATUS_ERROR\n"); - ide->atastat = READY_STAT | ERR_STAT; - ide_irq_raise(ide); - } - else if (ide->packetstatus == ATAPI_STATUS_ERROR_2) /*Error callback with atastat already set - needed for the disc change stuff.*/ - { - // pclog("ATAPI_STATUS_ERROR_2\n"); - ide->atastat = ERR_STAT; - ide_irq_raise(ide); - } + cdrom_phase_callback(atapi_cdrom_drives[cur_ide[ide_board]]); + idecallback[ide_board] = cdrom[atapi_cdrom_drives[cur_ide[ide_board]]].callback; + ide_log("IDE callback now: %i\n", idecallback[ide_board]); return; + + case 0xFF: + goto abort_cmd; } abort_cmd: ide->command = 0; + if (ide_drive_is_cdrom(ide)) + { + cdrom[cdrom_id].status = READY_STAT | ERR_STAT | DSC_STAT; + cdrom[cdrom_id].error = ABRT_ERR; + cdrom[cdrom_id].pos = 0; + } + else + { + ide->atastat = READY_STAT | ERR_STAT | DSC_STAT; + ide->error = ABRT_ERR; + ide->pos = 0; + } + ide_irq_raise(ide); + return; + +id_not_found: ide->atastat = READY_STAT | ERR_STAT | DSC_STAT; - ide->error = ABRT_ERR; + ide->error = ABRT_ERR | 0x10; ide->pos = 0; ide_irq_raise(ide); } @@ -1703,1432 +2014,253 @@ void ide_callback_qua() callbackide(3); } -/*ATAPI CD-ROM emulation*/ -uint8_t atapi_prev; -int toctimes=0; - -void atapi_command_send_init(IDE *ide, uint8_t command, int req_length, int alloc_length) +void ide_callback_xtide() { - if (ide->cylinder == 0xffff) - { - ide->cylinder = 0xfffe; - } - - if ((ide->cylinder & 1) && !(alloc_length <= ide->cylinder)) - { - ide->cylinder--; - } - - if (alloc_length < 0) - { - fatal("Allocation length < 0\n"); - } - if (alloc_length == 0) - { - alloc_length = ide->cylinder; - } - - /* No atastat setting: PCem actually emulates the callback cycle. */ - if (alloc_length != 0) - { - ide->secount = 2; - } - - // no bytes transferred yet - ide->pos = 0; - - if ((ide->cylinder > req_length) || (ide->cylinder == 0)) - { - ide->cylinder = req_length; - } - if (ide->cylinder > alloc_length) - { - ide->cylinder = alloc_length; - } + idecallback[4] = 0; + callbackide(4); } -static void atapi_command_ready(int ide_board, int packlen) -{ - IDE *ide = &ide_drives[cur_ide[ide_board]]; - ide->packetstatus = ATAPI_STATUS_REQ_SENSE; - idecallback[ide_board]=60*IDE_TIME; - ide->packlen=packlen; -} - -static void atapi_sense_clear(int command, int ignore_ua) -{ - if ((SCSISense.SenseKey == SENSE_UNIT_ATTENTION) || ignore_ua) - { - atapi_prev=command; - SCSISense.SenseKey=0; - SCSISense.Asc=0; - SCSISense.Ascq=0; - } -} - -void atapi_cmd_error(IDE *ide, uint8_t sensekey, uint8_t asc, uint8_t ascq) -{ - ide->error = (sensekey << 4) | ABRT_ERR; - if (SCSISense.UnitAttention) - { - ide->error |= MCR_ERR; - } - ide->atastat = READY_STAT | ERR_STAT; - ide->secount = (ide->secount & ~7) | 3; - ide->packetstatus = 0x80; - idecallback[ide->board]=50*IDE_TIME; -} - -static void atapi_not_ready(IDE *ide) -{ - SCSISense.SenseKey = SENSE_NOT_READY; - SCSISense.Asc = ASC_MEDIUM_NOT_PRESENT; - SCSISense.Ascq = 0; - atapi_cmd_error(ide, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT, 0); -} - -static void atapi_illegal_opcode(IDE *ide) -{ - SCSISense.SenseKey = SENSE_ILLEGAL_REQUEST; - SCSISense.Asc = ASC_ILLEGAL_OPCODE; - SCSISense.Ascq = 0; - atapi_cmd_error(ide, SENSE_ILLEGAL_REQUEST, ASC_ILLEGAL_OPCODE, 0); -} - -static void atapi_invalid_field(IDE *ide) -{ - SCSISense.SenseKey = SENSE_ILLEGAL_REQUEST; - SCSISense.Asc = ASC_INV_FIELD_IN_CMD_PACKET; - SCSISense.Ascq = 0; - atapi_cmd_error(ide, SENSE_ILLEGAL_REQUEST, ASC_INV_FIELD_IN_CMD_PACKET, 0); - ide->atastat = 0x53; -} - -static void atapi_illegal_mode(IDE *ide) -{ - SCSISense.SenseKey = SENSE_ILLEGAL_REQUEST; - SCSISense.Asc = ASC_ILLEGAL_MODE_FOR_THIS_TRACK; - SCSISense.Ascq = 0; - atapi_cmd_error(ide, SENSE_ILLEGAL_REQUEST, ASC_ILLEGAL_MODE_FOR_THIS_TRACK, 0); -} - -static void atapi_incompatible_format(IDE *ide) -{ - SCSISense.SenseKey = SENSE_ILLEGAL_REQUEST; - SCSISense.Asc = ASC_INCOMPATIBLE_FORMAT; - SCSISense.Ascq = 0; - atapi_cmd_error(ide, SENSE_ILLEGAL_REQUEST, ASC_INCOMPATIBLE_FORMAT, 0); -} - -static void atapi_data_phase_error(IDE *ide) -{ - SCSISense.SenseKey = SENSE_ILLEGAL_REQUEST; - SCSISense.Asc = ASC_DATA_PHASE_ERROR; - SCSISense.Ascq = 0; - atapi_cmd_error(ide, SENSE_ILLEGAL_REQUEST, ASC_DATA_PHASE_ERROR, 0); -} - -static void atapicommand(int ide_board) -{ - IDE *ide = &ide_drives[cur_ide[ide_board]]; - uint8_t *idebufferb = (uint8_t *) ide->buffer; - uint8_t rcdmode = 0; - int c; - int len; - int msf; - int pos=0; - unsigned char temp; - uint32_t size; - uint8_t page_code; - int max_len; - unsigned idx = 0; - unsigned size_idx; - unsigned preamble_len; - int toc_format; - int temp_command; - int alloc_length; - int completed; - uint8_t index = 0; - int media; - int format; - int ret; - int real_pos; - int track = 0; - uint8_t cdb[12]; - -#if 0 - pclog("ATAPI command 0x%02X, Sense Key %02X, Asc %02X, Ascq %02X, %i, Unit attention: %i\n",idebufferb[0],SCSISense.SenseKey,SCSISense.Asc,SCSISense.Ascq,ins,SCSISense.UnitAttention); - - int CdbLength; - for (CdbLength = 1; CdbLength < 12; CdbLength++) - { - pclog("ATAPI CDB[%d] = 0x%02X\n", CdbLength, idebufferb[CdbLength]); - } -#endif - - memcpy(cdb, idebufferb, 12); - - msf=idebufferb[1]&2; - SectorLen=0; - - if (cdrom->medium_changed()) - { - // pclog("Medium has changed...\n"); - SCSICDROM_Insert(); - } - - if (!cdrom->ready() && SCSISense.UnitAttention) - { - /* If the drive is not ready, there is no reason to keep the - UNIT ATTENTION condition present, as we only use it to mark - disc changes. */ - SCSISense.UnitAttention = 0; - } - - /* If the UNIT ATTENTION condition is set and the command does not allow - execution under it, error out and report the condition. */ - if (SCSISense.UnitAttention == 1) - { - // pclog("Unit attention now 2\n"); - SCSISense.UnitAttention = 2; - if (!(SCSICommandTable[idebufferb[0]] & ALLOW_UA)) - { - // pclog("UNIT ATTENTION: Command not allowed to pass through\n"); - atapi_cmd_error(ide, SENSE_UNIT_ATTENTION, ASC_MEDIUM_MAY_HAVE_CHANGED, 0); - return; - } - } - else if (SCSISense.UnitAttention == 2) - { - if (idebufferb[0]!=GPCMD_REQUEST_SENSE) - { - // pclog("Unit attention now 0\n"); - SCSISense.UnitAttention = 0; - } - } - - /* Unless the command is REQUEST SENSE, clear the sense. This will *NOT* - the UNIT ATTENTION condition if it's set. */ - if (idebufferb[0]!=GPCMD_REQUEST_SENSE) - { - atapi_sense_clear(idebufferb[0], 1); - } - - /* Next it's time for NOT READY. */ - if ((SCSICommandTable[idebufferb[0]] & CHECK_READY) && !cdrom->ready()) - { - atapi_not_ready(ide); - return; - } - - // pclog("Continuing with command\n"); - - prev_status = cd_status; - cd_status = cdrom->status(); - if (((prev_status == CD_STATUS_PLAYING) || (prev_status == CD_STATUS_PAUSED)) && ((cd_status != CD_STATUS_PLAYING) && (cd_status != CD_STATUS_PAUSED))) - { - completed = 1; - } - else - { - completed = 0; - } - - switch (idebufferb[0]) - { - case GPCMD_TEST_UNIT_READY: - ide->packetstatus = ATAPI_STATUS_COMPLETE; - idecallback[ide_board]=50*IDE_TIME; - break; - - case GPCMD_REQUEST_SENSE: /* Used by ROS 4+ */ - alloc_length = idebufferb[4]; - temp_command = idebufferb[0]; - - /*Will return 18 bytes of 0*/ - if (alloc_length != 0) - { - memset(idebufferb, 0, alloc_length); - } - - idebufferb[0]=0x80|0x70; - - if ((SCSISense.SenseKey > 0) && ((cd_status < CD_STATUS_PLAYING) || (cd_status == CD_STATUS_STOPPED))) - { - if (completed) - { - idebufferb[2]=SENSE_ILLEGAL_REQUEST; - idebufferb[12]=ASC_AUDIO_PLAY_OPERATION; - idebufferb[13]=ASCQ_AUDIO_PLAY_OPERATION_COMPLETED; - } - else - { - idebufferb[2]=SCSISense.SenseKey; - idebufferb[12]=SCSISense.Asc; - idebufferb[13]=SCSISense.Ascq; - } - } - else if ((SCSISense.SenseKey == 0) && (cd_status >= CD_STATUS_PLAYING) && (cd_status != CD_STATUS_STOPPED)) - { - idebufferb[2]=SENSE_ILLEGAL_REQUEST; - idebufferb[12]=ASC_AUDIO_PLAY_OPERATION; - idebufferb[13]=(cd_status == CD_STATUS_PLAYING) ? ASCQ_AUDIO_PLAY_OPERATION_IN_PROGRESS : ASCQ_AUDIO_PLAY_OPERATION_PAUSED; - } - else - { - if (SCSISense.UnitAttention) - { - idebufferb[2]=SENSE_UNIT_ATTENTION; - idebufferb[12]=ASC_MEDIUM_MAY_HAVE_CHANGED; - idebufferb[13]=0; - } - } - - // pclog("Reporting sense: %02X %02X %02X\n", idebufferb[2], idebufferb[12], idebufferb[13]); - - idebufferb[7]=10; - - if (idebufferb[2] == SENSE_UNIT_ATTENTION) - { - /* If the last remaining sense is unit attention, clear - that condition. */ - SCSISense.UnitAttention = 0; - } - - /* Clear the sense stuff as per the spec. */ - atapi_sense_clear(temp_command, 0); - - if (alloc_length == 0) - { - // pclog("REQUEST SENSE - empty allocation\n"); - ide->packetstatus = ATAPI_STATUS_COMPLETE; - idecallback[ide_board]=50*IDE_TIME; - } - else - { - atapi_command_send_init(ide, temp_command, 18, alloc_length); - atapi_command_ready(ide_board, 18); - } - break; - - case GPCMD_SET_SPEED: - ide->packetstatus = ATAPI_STATUS_COMPLETE; - idecallback[ide_board]=50*IDE_TIME; - break; - - case GPCMD_MECHANISM_STATUS: - len=(idebufferb[7]<<16)|(idebufferb[8]<<8)|idebufferb[9]; - - memset(idebufferb, 0, 8); - idebufferb[5] = 1; - - if (len == 0) - { - ide->packetstatus = ATAPI_STATUS_COMPLETE; - idecallback[ide_board]=50*IDE_TIME; - } - else - { - atapi_command_send_init(ide, cdb[0], 8, alloc_length); - atapi_command_ready(ide_board, 8); - } - break; - - case GPCMD_READ_TOC_PMA_ATIP: - toctimes++; - toc_format = idebufferb[2] & 0xf; - - if (toc_format == 0) - { - toc_format = (idebufferb[9]>>6) & 3; - } - - switch (toc_format) - { - case 0: /*Normal*/ - len=idebufferb[8]+(idebufferb[7]<<8); - len=cdrom->readtoc(idebufferb,idebufferb[6],msf,len,0); - break; - case 1: /*Multi session*/ - len=idebufferb[8]+(idebufferb[7]<<8); - len=cdrom->readtoc_session(idebufferb,msf,len); - idebufferb[0]=0; idebufferb[1]=0xA; - break; - case 2: /*Raw*/ - len=idebufferb[8]+(idebufferb[7]<<8); - len=cdrom->readtoc_raw(idebufferb,msf,len); - break; - default: - atapi_invalid_field(ide); - return; - } - - ide->packetstatus = ATAPI_STATUS_DATA; - ide->cylinder=len; - ide->secount=2; - ide->pos=0; - idecallback[ide_board]=60*IDE_TIME; - ide->packlen=len; - // pclog("READ_TOC_PMA_ATIP format %02X, length %i (%i)\n", toc_format, ide->cylinder, idebufferb[1]); - - if (len == 0) - { - ide->packetstatus = ATAPI_STATUS_COMPLETE; - idecallback[ide_board]=50*IDE_TIME; - } - return; - - case GPCMD_READ_CD: - case GPCMD_READ_CD_MSF: - // pclog("Read CD : start LBA %02X%02X%02X%02X Length %02X%02X%02X Flags %02X\n",idebufferb[2],idebufferb[3],idebufferb[4],idebufferb[5],idebufferb[6],idebufferb[7],idebufferb[8],idebufferb[9]); - if (idebufferb[0] == GPCMD_READ_CD_MSF) - { - SectorLBA=MSFtoLBA(idebufferb[3],idebufferb[4],idebufferb[5]); - SectorLen=MSFtoLBA(idebufferb[6],idebufferb[7],idebufferb[8]); - - SectorLen -= SectorLBA; - SectorLen++; - - cdrom_sector_ismsf = 1; - } - else - { - SectorLen=(idebufferb[6]<<16)|(idebufferb[7]<<8)|idebufferb[8]; - SectorLBA=(idebufferb[2]<<24)|(idebufferb[3]<<16)|(idebufferb[4]<<8)|idebufferb[5]; - - cdrom_sector_ismsf = 0; - } - - cdrom_sector_type = (idebufferb[1] >> 2) & 7; - cdrom_sector_flags = idebufferb[9] || (((uint32_t) idebufferb[10]) << 8); - - if (SectorLBA > (cdrom->size() - 1)) - { - // pclog("Trying to read beyond the end of disc\n"); - atapi_invalid_field(ide); - break; - } - - ret = cdrom_read_data(idebufferb); - - if (!ret) - { - atapi_invalid_field(ide); - break; - } - - readflash=1; - - SectorLBA++; - SectorLen--; - if (SectorLen >= 0) - { - ide->packetstatus = ATAPI_STATUS_READCD; - } - else - { - ide->packetstatus = ATAPI_STATUS_DATA; - } - ide->cylinder=cdrom_sector_size; - ide->secount=2; - ide->pos=0; - idecallback[ide_board]=60*IDE_TIME; - ide->packlen=cdrom_sector_size; - return; - - case GPCMD_READ_6: - case GPCMD_READ_10: - case GPCMD_READ_12: - // pclog("Read 10 : start LBA %02X%02X%02X%02X Length %02X%02X%02X Flags %02X\n",idebufferb[2],idebufferb[3],idebufferb[4],idebufferb[5],idebufferb[6],idebufferb[7],idebufferb[8],idebufferb[9]); - cdrom_sector_ismsf = 0; - - if (idebufferb[0] == GPCMD_READ_6) - { - SectorLen=idebufferb[4]; - SectorLBA=((((uint32_t) idebufferb[1]) & 0x1f)<<16)|(((uint32_t) idebufferb[2])<<8)|((uint32_t) idebufferb[3]); - } - else if (idebufferb[0] == GPCMD_READ_10) - { - SectorLen=(idebufferb[7]<<8)|idebufferb[8]; - SectorLBA=(idebufferb[2]<<24)|(idebufferb[3]<<16)|(idebufferb[4]<<8)|idebufferb[5]; - } - else - { - SectorLen=(((uint32_t) idebufferb[6])<<24)|(((uint32_t) idebufferb[7])<<16)|(((uint32_t) idebufferb[8])<<8)|((uint32_t) idebufferb[9]); - SectorLBA=(((uint32_t) idebufferb[2])<<24)|(((uint32_t) idebufferb[3])<<16)|(((uint32_t) idebufferb[4])<<8)|((uint32_t) idebufferb[5]); - } - - // pclog("Reading sector: %i, length: %i\n", SectorLen, SectorLBA); - - if (SectorLBA > (cdrom->size() - 1)) - { - // pclog("Trying to read beyond the end of disc\n"); - atapi_invalid_field(ide); - break; - } - - if (!SectorLen) - { - // pclog("All done - callback set\n"); - ide->packetstatus = ATAPI_STATUS_COMPLETE; - idecallback[ide_board]=20*IDE_TIME; - break; - } - - cdrom_sector_type = 6; - cdrom_sector_flags = 0x10; - - ret = cdrom_read_data(idebufferb); - - if (!ret) - { - atapi_invalid_field(ide); - break; - } - - readflash=1; - SectorLBA++; - SectorLen--; - if (SectorLen >= 0) - { - ide->packetstatus = ATAPI_STATUS_READCD; - } - else - { - ide->packetstatus = ATAPI_STATUS_DATA; - } - ide->cylinder=2048; - ide->secount=2; - ide->pos=0; - idecallback[ide_board]=60*IDE_TIME; - ide->packlen=2048; - return; - - case GPCMD_READ_HEADER: - if (cdrom->read_header) - { - cdrom->read_header(idebufferb, idebufferb); - } - else - { - SectorLen=(idebufferb[7]<<8)|idebufferb[8]; - SectorLBA=(idebufferb[2]<<24)|(idebufferb[3]<<16)|(idebufferb[4]<<8)|idebufferb[5]; - if (msf) - { - real_pos = cdrom_LBAtoMSF_accurate(ide); - } - else - { - real_pos = SectorLBA; - } - idebufferb[4] = (real_pos >> 24); - idebufferb[5] = ((real_pos >> 16) & 0xff); - idebufferb[6] = ((real_pos >> 8) & 0xff); - idebufferb[7] = real_pos & 0xff; - idebufferb[0]=1; /*2048 bytes user data*/ - idebufferb[1]=idebufferb[2]=idebufferb[3]=0; - } - - len = 8; - ide->packetstatus = ATAPI_STATUS_DATA; - ide->cylinder=8; - ide->secount=2; - ide->pos=0; - idecallback[ide_board]=60*IDE_TIME; - ide->packlen=8; - return; - - case GPCMD_MODE_SENSE_6: - case GPCMD_MODE_SENSE_10: - temp_command = idebufferb[0]; - - if (temp_command == GPCMD_MODE_SENSE_6) - { - len=idebufferb[4]; - } - else - { - len=(idebufferb[8]|(idebufferb[7]<<8)); - } - - temp=idebufferb[2] & 0x3F; - - memset(idebufferb, 0, len); - alloc_length = len; - - if (!(mode_sense_pages[temp] & IMPLEMENTED)) - { - atapi_invalid_field(ide); - return; - } - - if (temp_command == GPCMD_MODE_SENSE_6) - { - len = SCSICDROMModeSense(idebufferb,4,temp); - if (len > alloc_length) - { - len = alloc_length; - } - idebufferb[0] = len - 1; - idebufferb[1]=3; /*120mm data CD-ROM*/ - } - else - { - len = SCSICDROMModeSense(idebufferb,8,temp); - if (len > alloc_length) - { - len = alloc_length; - } - idebufferb[0]=(len - 2)>>8; - idebufferb[1]=(len - 2)&255; - idebufferb[2]=3; /*120mm data CD-ROM*/ - } - - atapi_command_send_init(ide, temp_command, len, alloc_length); - - atapi_command_ready(ide_board, len); - - if (len == 0) - { - ide->packetstatus = ATAPI_STATUS_COMPLETE; - idecallback[ide_board]=50*IDE_TIME; - } - return; - - case GPCMD_MODE_SELECT_6: - case GPCMD_MODE_SELECT_10: - if (ide->packetstatus == ATAPI_STATUS_PACKET_RECEIVED) - { - ide->atastat = READY_STAT; - ide->secount=3; - // pclog("Recieve data packet!\n"); - ide_irq_raise(ide); - ide->packetstatus=0xFF; - ide->pos=0; - } - else - { - if (idebufferb[0] == GPCMD_MODE_SELECT_6) - { - len=idebufferb[4]; - prefix_len = 6; - } - else - { - len=(idebufferb[7]<<8)|idebufferb[8]; - prefix_len = 10; - } - page_current = idebufferb[2]; - if (page_flags[page_current] & PAGE_CHANGEABLE) - { - page_flags[page_current] |= PAGE_CHANGED; - } - ide->packetstatus = ATAPI_STATUS_PACKET_REQ; - ide->cylinder=len; - ide->secount=0; - ide->pos=0; - idecallback[ide_board]=60*IDE_TIME; - ide->packlen=len; - - if (len == 0) - { - ide->packetstatus = ATAPI_STATUS_COMPLETE; - idecallback[ide_board]=50*IDE_TIME; - } - } - return; - - case GPCMD_GET_CONFIGURATION: - temp_command = idebufferb[0]; - /* XXX: could result in alignment problems in some architectures */ - len = (idebufferb[7]<<8)|idebufferb[8]; - alloc_length = len; - - index = 0; - - /* only feature 0 is supported */ - if (idebufferb[2] != 0 || idebufferb[3] != 0) - { - atapi_invalid_field(ide); - return; - } - - /* - * XXX: avoid overflow for io_buffer if len is bigger than - * the size of that buffer (dimensioned to max number of - * sectors to transfer at once) - * - * Only a problem if the feature/profiles grow. - */ - if (alloc_length > 512) /* XXX: assume 1 sector */ - { - alloc_length = 512; - } - - memset(idebufferb, 0, alloc_length); - /* - * the number of sectors from the media tells us which profile - * to use as current. 0 means there is no media - */ - if (len > CD_MAX_SECTORS) - { - idebufferb[6] = (MMC_PROFILE_DVD_ROM >> 8) & 0xff; - idebufferb[7] = MMC_PROFILE_DVD_ROM & 0xff; - } - else if (len <= CD_MAX_SECTORS) - { - idebufferb[6] = (MMC_PROFILE_CD_ROM >> 8) & 0xff; - idebufferb[7] = MMC_PROFILE_CD_ROM & 0xff; - } - idebufferb[10] = 0x02 | 0x01; /* persistent and current */ - alloc_length = 12; /* headers: 8 + 4 */ - alloc_length += SCSICDROMSetProfile(idebufferb, &index, MMC_PROFILE_DVD_ROM); - alloc_length += SCSICDROMSetProfile(idebufferb, &index, MMC_PROFILE_CD_ROM); - idebufferb[0] = ((alloc_length-4) >> 24) & 0xff; - idebufferb[1] = ((alloc_length-4) >> 16) & 0xff; - idebufferb[2] = ((alloc_length-4) >> 8) & 0xff; - idebufferb[3] = (alloc_length-4) & 0xff; - - if (len == 0) - { - ide->packetstatus = ATAPI_STATUS_COMPLETE; - idecallback[ide_board]=50*IDE_TIME; - } - else - { - atapi_command_send_init(ide, temp_command, len, alloc_length); - atapi_command_ready(ide_board, len); - } - break; - - case GPCMD_GET_EVENT_STATUS_NOTIFICATION: - gesn_cdb = (void *)idebufferb; - gesn_event_header = (void *)idebufferb; - - /* It is fine by the MMC spec to not support async mode operations. */ - if (!(gesn_cdb->polled & 0x01)) - { /* asynchronous mode */ - /* Only polling is supported, asynchronous mode is not. */ - atapi_invalid_field(ide); - return; - } - - /* polling mode operation */ - - /* - * These are the supported events. - * - * We currently only support requests of the 'media' type. - * Notification class requests and supported event classes are bitmasks, - * but they are built from the same values as the "notification class" - * field. - */ - gesn_event_header->supported_events = 1 << GESN_MEDIA; - - /* - * We use |= below to set the class field; other bits in this byte - * are reserved now but this is useful to do if we have to use the - * reserved fields later. - */ - gesn_event_header->notification_class = 0; - - /* - * Responses to requests are to be based on request priority. The - * notification_class_request_type enum above specifies the - * priority: upper elements are higher prio than lower ones. - */ - if (gesn_cdb->class & (1 << GESN_MEDIA)) - { - gesn_event_header->notification_class |= GESN_MEDIA; - used_len = SCSICDROMEventStatus(idebufferb); - } - else - { - gesn_event_header->notification_class = 0x80; /* No event available */ - used_len = sizeof(*gesn_event_header); - } - gesn_event_header->len = used_len - sizeof(*gesn_event_header); - - atapi_command_send_init(ide, cdb[0], used_len, used_len); - atapi_command_ready(ide_board, used_len); - break; - - case GPCMD_READ_DISC_INFORMATION: - if (cdrom->read_disc_information) - { - cdrom->read_disc_information(idebufferb); - } - else - { - memset(idebufferb, 0, 34); - memset(idebufferb, 1, 9); - idebufferb[0] = 0; - idebufferb[1] = 32; - idebufferb[2] = 0xe; /* last session complete, disc finalized */ - idebufferb[7] = 0x20; /* unrestricted use */ - idebufferb[8] = 0x00; /* CD-ROM */ - } - - len=34; - if (len > alloc_length) - { - len = alloc_length; - } - - if (len == 0) - { - ide->packetstatus = ATAPI_STATUS_COMPLETE; - idecallback[ide_board]=50*IDE_TIME; - } - else - { - ide->packetstatus = ATAPI_STATUS_DATA; - ide->secount=2; - ide->cylinder=len; - ide->pos=0; - ide->packlen=len; - idecallback[ide_board]=60*IDE_TIME; - } - break; - - case GPCMD_READ_TRACK_INFORMATION: - max_len = idebufferb[7]; - max_len <<= 8; - max_len |= idebufferb[8]; - - track = ((uint32_t) idebufferb[2]) << 24; - track |= ((uint32_t) idebufferb[3]) << 16; - track |= ((uint32_t) idebufferb[4]) << 8; - track |= (uint32_t) idebufferb[5]; - - if (cdrom->read_track_information) - { - ret = cdrom->read_track_information(idebufferb, idebufferb); - - if (!ret) - { - atapi_invalid_field(ide); - return; - } - - len = idebufferb[0]; - len <<= 8; - len |= idebufferb[1]; - len += 2; - } - else - { - if (((idebufferb[1] & 0x03) != 1) || (track != 1)) - { - atapi_invalid_field(ide); - return; - } - - len = 36; - - memset(idebufferb, 0, 36); - idebufferb[1] = 34; - idebufferb[2] = 1; /* track number (LSB) */ - idebufferb[3] = 1; /* session number (LSB) */ - idebufferb[5] = (0 << 5) | (0 << 4) | (4 << 0); /* not damaged, primary copy, data track */ - idebufferb[6] = (0 << 7) | (0 << 6) | (0 << 5) | (0 << 6) | (1 << 0); /* not reserved track, not blank, not packet writing, not fixed packet, data mode 1 */ - idebufferb[7] = (0 << 1) | (0 << 0); /* last recorded address not valid, next recordable address not valid */ - idebufferb[24] = (cdrom->size() >> 24) & 0xff; /* track size */ - idebufferb[25] = (cdrom->size() >> 16) & 0xff; /* track size */ - idebufferb[26] = (cdrom->size() >> 8) & 0xff; /* track size */ - idebufferb[27] = cdrom->size() & 0xff; /* track size */ - } - - if (len > max_len) - { - len = max_len; - idebufferb[0] = ((max_len - 2) >> 8) & 0xff; - idebufferb[1] = (max_len - 2) & 0xff; - } - - if (len == 0) - { - ide->packetstatus = ATAPI_STATUS_COMPLETE; - idecallback[ide_board]=50*IDE_TIME; - } - else - { - ide->packetstatus = ATAPI_STATUS_DATA; - ide->cylinder=len; - ide->secount=2; - ide->pos=0; - idecallback[ide_board]=60*IDE_TIME; - ide->packlen=len; - } - break; - - case GPCMD_PLAY_AUDIO_10: - case GPCMD_PLAY_AUDIO_12: - case GPCMD_PLAY_AUDIO_MSF: - if (idebufferb[0] == GPCMD_PLAY_AUDIO_10) - { - pos=(idebufferb[2]<<24)|(idebufferb[3]<<16)|(idebufferb[4]<<8)|idebufferb[5]; - len=(idebufferb[7]<<8)|idebufferb[8]; - } - else if (idebufferb[0] == GPCMD_PLAY_AUDIO_MSF) - { - /* This is apparently deprecated in the ATAPI spec, and apparently - has been since 1995 (!). Hence I'm having to guess most of it. */ - pos=(idebufferb[3]<<16)|(idebufferb[4]<<8)|idebufferb[5]; - len=(idebufferb[6]<<16)|(idebufferb[7]<<8)|idebufferb[8]; - } - else - { - pos=(idebufferb[3]<<16)|(idebufferb[4]<<8)|idebufferb[5]; - len=(idebufferb[7]<<16)|(idebufferb[8]<<8)|idebufferb[9]; - } - - if ((cdrom_drive < 1) || (cdrom_drive == CDROM_ISO) || (cd_status <= CD_STATUS_DATA_ONLY) || - !cdrom->is_track_audio(pos, (idebufferb[0] == GPCMD_PLAY_AUDIO_MSF) ? 1 : 0)) - { - atapi_illegal_mode(ide); - break; - } - - cdrom->playaudio(pos, len, (idebufferb[0] == GPCMD_PLAY_AUDIO_MSF) ? 1 : 0); - ide->packetstatus = ATAPI_STATUS_COMPLETE; - idecallback[ide_board]=50*IDE_TIME; - break; - - case GPCMD_READ_SUBCHANNEL: - if (idebufferb[3] > 3) - { - // pclog("Read subchannel check condition %02X\n",idebufferb[3]); - atapi_invalid_field(ide); - break; - } - - switch(idebufferb[3]) - { - case 0: - alloc_length = 4; - break; - case 1: - alloc_length = 16; - break; - default: - alloc_length = 24; - break; - } - - if (cdrom->read_subchannel) - { - cdrom->read_subchannel(idebufferb, idebufferb); - len = alloc_length; - } - else - { - temp = idebufferb[3] & 3; - temp |= (idebufferb[2] & 0x40); - memset(idebufferb, 24, 0); - pos = 0; - idebufferb[pos++]=0; - idebufferb[pos++]=0; /*Audio status*/ - idebufferb[pos++]=0; idebufferb[pos++]=0; /*Subchannel length*/ - idebufferb[pos++]=temp & 3; /*Format code*/ - if ((temp & 3) == 1) - { - idebufferb[1]=cdrom->getcurrentsubchannel(&idebufferb[5],msf); - } - if (!(temp & 0x40) || ((temp & 3) == 0)) - { - len=4; - } - else - { - len = alloc_length; - } - } - ide->packetstatus = ATAPI_STATUS_DATA; - ide->cylinder=len; - ide->secount=2; - ide->pos=0; - idecallback[ide_board]=1000*IDE_TIME; - ide->packlen=len; - break; - - case GPCMD_READ_DVD_STRUCTURE: - temp_command = idebufferb[0]; - media = idebufferb[1]; - format = idebufferb[7]; - - len = (((uint32_t) idebufferb[6])<<24)|(((uint32_t) idebufferb[7])<<16)|(((uint32_t) idebufferb[8])<<8)|((uint32_t) idebufferb[9]); - alloc_length = len; - - if (format < 0xff) - { - if (len <= CD_MAX_SECTORS) - { - atapi_incompatible_format(ide); - break; - } - else - { - atapi_invalid_field(ide); - return; - } - } - - memset(idebufferb, 0, (alloc_length > 256 * 512 + 4) ? (256 * 512 + 4) : alloc_length); - - switch (format) - { - case 0x00 ... 0x7f: - case 0xff: - - if (media == 0) - { - ret = SCSICDROMReadDVDStructure(format, idebufferb, idebufferb); - - if (ret < 0) - { - atapi_cmd_error(ide, SENSE_ILLEGAL_REQUEST, -ret, 0); - } - else - { - atapi_command_send_init(ide, temp_command, len, alloc_length); - atapi_command_ready(ide_board, len); - } - break; - } - /* TODO: BD support, fall through for now */ - - /* Generic disk structures */ - case 0x80: /* TODO: AACS volume identifier */ - case 0x81: /* TODO: AACS media serial number */ - case 0x82: /* TODO: AACS media identifier */ - case 0x83: /* TODO: AACS media key block */ - case 0x90: /* TODO: List of recognized format layers */ - case 0xc0: /* TODO: Write protection status */ - default: - atapi_invalid_field(ide); - return; - } - break; - - case GPCMD_START_STOP_UNIT: - switch(idebufferb[4] & 3) - { - case 0: /* Stop the disc. */ - cdrom->stop(); - break; - case 1: /* Start the disc and read the TOC. */ - cdrom->medium_changed(); /* This causes a TOC reload. */ - break; - case 2: /* Eject the disc if possible. */ - cdrom->stop(); -#ifndef __unix - win_cdrom_eject(); -#endif - break; - case 3: /* Load the disc (close tray). */ -#ifndef __unix - win_cdrom_reload(); -#else - cdrom->load(); -#endif - break; - } - - ide->packetstatus = ATAPI_STATUS_COMPLETE; - idecallback[ide_board]=50*IDE_TIME; - break; - - case GPCMD_INQUIRY: - page_code = idebufferb[2]; - max_len = idebufferb[4]; - alloc_length = max_len; - temp_command = idebufferb[0]; - - if (idebufferb[1] & 1) - { - preamble_len = 4; - size_idx = 3; - - idebufferb[idx++] = 05; - idebufferb[idx++] = page_code; - idebufferb[idx++] = 0; - - idx++; - - switch (page_code) - { - case 0x00: - idebufferb[idx++] = 0x00; - idebufferb[idx++] = 0x83; - break; - case 0x83: - if (idx + 24 > max_len) - { - atapi_data_phase_error(ide); - return; - } - - idebufferb[idx++] = 0x02; - idebufferb[idx++] = 0x00; - idebufferb[idx++] = 0x00; - idebufferb[idx++] = 20; - ide_padstr8(idebufferb + idx, 20, "53R141"); /* Serial */ - idx += 20; - - if (idx + 72 > max_len) - { - goto atapi_out; - } - idebufferb[idx++] = 0x02; - idebufferb[idx++] = 0x01; - idebufferb[idx++] = 0x00; - idebufferb[idx++] = 68; - ide_padstr8(idebufferb + idx, 8, "86Box"); /* Vendor */ - idx += 8; - ide_padstr8(idebufferb + idx, 40, "86BoxCD v1.0"); /* Product */ - idx += 40; - ide_padstr8(idebufferb + idx, 20, "53R141"); /* Product */ - idx += 20; - break; - default: - atapi_invalid_field(ide); - return; - } - } - else - { - preamble_len = 5; - size_idx = 4; - - memset(idebufferb, 0, 8); - idebufferb[0] = 5; /*CD-ROM*/ - idebufferb[1] = 0x80; /*Removable*/ - idebufferb[3] = 0x21; - idebufferb[4] = 31; - - ide_padstr8(idebufferb + 8, 8, "86Box"); /* Vendor */ - ide_padstr8(idebufferb + 16, 16, "86BoxCD"); /* Product */ - ide_padstr8(idebufferb + 32, 4, emulator_version); /* Revision */ - idx = 36; - } - -atapi_out: - idebufferb[size_idx] = idx - preamble_len; - len=idx; - if (len > alloc_length) - { - len = alloc_length; - } - - if (len == 0) - { - ide->packetstatus = ATAPI_STATUS_COMPLETE; - idecallback[ide_board]=50*IDE_TIME; - } - else - { - atapi_command_send_init(ide, temp_command, len, alloc_length); - atapi_command_ready(ide_board, len); - } - break; - - case GPCMD_PREVENT_REMOVAL: - ide->packetstatus = ATAPI_STATUS_COMPLETE; - idecallback[ide_board]=50*IDE_TIME; - break; - - case GPCMD_PAUSE_RESUME: - if (idebufferb[8] & 1) - { - cdrom->resume(); - } - else - { - cdrom->pause(); - } - ide->packetstatus = ATAPI_STATUS_COMPLETE; - idecallback[ide_board]=50*IDE_TIME; - break; - - case GPCMD_SEEK_6: - case GPCMD_SEEK_10: - if (idebufferb[0] == GPCMD_SEEK_6) - { - pos=(idebufferb[2]<<8)|idebufferb[3]; - } - else - { - pos=(idebufferb[2]<<24)|(idebufferb[3]<<16)|(idebufferb[4]<<8)|idebufferb[5]; - } - cdrom->seek(pos); - ide->packetstatus = ATAPI_STATUS_COMPLETE; - idecallback[ide_board]=50*IDE_TIME; - break; - - case GPCMD_READ_CDROM_CAPACITY: - atapi_command_send_init(ide, temp_command, 8, 8); - if (cdrom->read_capacity) - { - cdrom->read_capacity(idebufferb); - } - else - { - size = cdrom->size() - 1; /* IMPORTANT: What's returned is the last LBA block. */ - memset(idebufferb, 0, 8); - idebufferb[0] = (size >> 24) & 0xff; - idebufferb[1] = (size >> 16) & 0xff; - idebufferb[2] = (size >> 8) & 0xff; - idebufferb[3] = size & 0xff; - idebufferb[6] = 8; /* 2048 = 0x0800 */ - } - len=8; - atapi_command_ready(ide_board, len); - break; - - case GPCMD_STOP_PLAY_SCAN: - cdrom->stop(); - ide->packetstatus = ATAPI_STATUS_COMPLETE; - idecallback[ide_board]=50*IDE_TIME; - break; - - default: - atapi_illegal_opcode(ide); - break; - } - - // pclog("SCSI phase: %02X, length: %i\n", ide->secount, ide->cylinder); -} - -static void callnonreadcd(IDE *ide) /* Callabck for non-Read CD commands */ -{ - ide_irq_lower(ide); - if (ide->pos >= ide->packlen) - { - // pclog("Command finished, setting callback\n"); - ide->packetstatus = ATAPI_STATUS_COMPLETE; - idecallback[ide->board]=20*IDE_TIME; - } - else - { - // pclog("Command not finished, keep sending data\n"); - ide->atastat = BUSY_STAT; - ide->packetstatus = ATAPI_STATUS_REQ_SENSE; - ide->cylinder=2; - ide->secount=2; - idecallback[ide->board]=60*IDE_TIME; - } -} - -static void callreadcd(IDE *ide) -{ - int ret; - - ide_irq_lower(ide); - if (SectorLen<=0) - { - // pclog("All done - callback set\n"); - ide->packetstatus = ATAPI_STATUS_COMPLETE; - idecallback[ide->board]=20*IDE_TIME; - return; - } - // pclog("Continue readcd! %i blocks left\n",SectorLen); - // pclog("Reading sector: %i, length: %i\n", SectorLen, SectorLBA); - ide->atastat = BUSY_STAT; - - ret = cdrom_read_data((uint8_t *) ide->buffer); - readflash=1; - - SectorLBA++; - SectorLen--; - ide->packetstatus = ATAPI_STATUS_READCD; - ide->cylinder=cdrom_sector_size; - ide->secount=2; - ide->pos=0; - idecallback[ide->board]=60*IDE_TIME; - ide->packlen=cdrom_sector_size; -} - - void ide_write_pri(uint16_t addr, uint8_t val, void *priv) { - writeide(0, addr, val); + writeide(0, addr, val); } void ide_write_pri_w(uint16_t addr, uint16_t val, void *priv) { - writeidew(0, val); + writeidew(0, val); } void ide_write_pri_l(uint16_t addr, uint32_t val, void *priv) { - writeidel(0, val); + writeidel(0, val); } uint8_t ide_read_pri(uint16_t addr, void *priv) { - return readide(0, addr); + return readide(0, addr); } uint16_t ide_read_pri_w(uint16_t addr, void *priv) { - return readidew(0); + return readidew(0); } uint32_t ide_read_pri_l(uint16_t addr, void *priv) { - return readidel(0); + return readidel(0); } void ide_write_sec(uint16_t addr, uint8_t val, void *priv) { - writeide(1, addr, val); + writeide(1, addr, val); } void ide_write_sec_w(uint16_t addr, uint16_t val, void *priv) { - writeidew(1, val); + writeidew(1, val); } void ide_write_sec_l(uint16_t addr, uint32_t val, void *priv) { - writeidel(1, val); + writeidel(1, val); } uint8_t ide_read_sec(uint16_t addr, void *priv) { - return readide(1, addr); + return readide(1, addr); } uint16_t ide_read_sec_w(uint16_t addr, void *priv) { - return readidew(1); + return readidew(1); } uint32_t ide_read_sec_l(uint16_t addr, void *priv) { - return readidel(1); + return readidel(1); } -/* *** REMOVE FROM CODE SUBMITTED TO MAINLINE - START *** */ void ide_write_ter(uint16_t addr, uint8_t val, void *priv) { - writeide(2, addr, val); + writeide(2, addr, val); } void ide_write_ter_w(uint16_t addr, uint16_t val, void *priv) { - writeidew(2, val); + writeidew(2, val); } void ide_write_ter_l(uint16_t addr, uint32_t val, void *priv) { - writeidel(2, val); + writeidel(2, val); } uint8_t ide_read_ter(uint16_t addr, void *priv) { - return readide(2, addr); + return readide(2, addr); } uint16_t ide_read_ter_w(uint16_t addr, void *priv) { - return readidew(2); + return readidew(2); } uint32_t ide_read_ter_l(uint16_t addr, void *priv) { - return readidel(2); + return readidel(2); } void ide_write_qua(uint16_t addr, uint8_t val, void *priv) { - writeide(3, addr, val); + writeide(3, addr, val); } void ide_write_qua_w(uint16_t addr, uint16_t val, void *priv) { - writeidew(3, val); + writeidew(3, val); } void ide_write_qua_l(uint16_t addr, uint32_t val, void *priv) { - writeidel(3, val); + writeidel(3, val); } uint8_t ide_read_qua(uint16_t addr, void *priv) { - return readide(3, addr); + return readide(3, addr); } uint16_t ide_read_qua_w(uint16_t addr, void *priv) { - return readidew(3); + return readidew(3); } uint32_t ide_read_qua_l(uint16_t addr, void *priv) { - return readidel(3); + return readidel(3); } -/* *** REMOVE FROM CODE SUBMITTED TO MAINLINE - END *** */ + +static uint16_t ide_base_main[2] = { 0x1f0, 0x170 }; +static uint16_t ide_side_main[2] = { 0x3f6, 0x376 }; void ide_pri_enable() { - io_sethandler(0x01f0, 0x0008, ide_read_pri, ide_read_pri_w, ide_read_pri_l, ide_write_pri, ide_write_pri_w, ide_write_pri_l, NULL); - io_sethandler(0x03f6, 0x0001, ide_read_pri, NULL, NULL, ide_write_pri, NULL, NULL , NULL); + io_sethandler(0x01f0, 0x0008, ide_read_pri, ide_read_pri_w, ide_read_pri_l, ide_write_pri, ide_write_pri_w, ide_write_pri_l, NULL); + io_sethandler(0x03f6, 0x0001, ide_read_pri, NULL, NULL, ide_write_pri, NULL, NULL , NULL); + ide_base_main[0] = 0x1f0; + ide_side_main[0] = 0x3f6; +} + +void ide_pri_enable_ex() +{ + if (ide_base_main[0] & 0x300) + { + ide_log("Enabling primary base (%04X)...\n", ide_base_main[0]); + io_sethandler(ide_base_main[0], 0x0008, ide_read_pri, ide_read_pri_w, ide_read_pri_l, ide_write_pri, ide_write_pri_w, ide_write_pri_l, NULL); + } + if (ide_side_main[0] & 0x300) + { + ide_log("Enabling primary side (%04X)...\n", ide_side_main[0]); + io_sethandler(ide_side_main[0], 0x0001, ide_read_pri, NULL, NULL, ide_write_pri, NULL, NULL , NULL); + } } void ide_pri_disable() { - io_removehandler(0x01f0, 0x0008, ide_read_pri, ide_read_pri_w, ide_read_pri_l, ide_write_pri, ide_write_pri_w, ide_write_pri_l, NULL); - io_removehandler(0x03f6, 0x0001, ide_read_pri, NULL, NULL, ide_write_pri, NULL, NULL , NULL); + io_removehandler(ide_base_main[0], 0x0008, ide_read_pri, ide_read_pri_w, ide_read_pri_l, ide_write_pri, ide_write_pri_w, ide_write_pri_l, NULL); + io_removehandler(ide_side_main[0], 0x0001, ide_read_pri, NULL, NULL, ide_write_pri, NULL, NULL , NULL); } void ide_sec_enable() { - io_sethandler(0x0170, 0x0008, ide_read_sec, ide_read_sec_w, ide_read_sec_l, ide_write_sec, ide_write_sec_w, ide_write_sec_l, NULL); - io_sethandler(0x0376, 0x0001, ide_read_sec, NULL, NULL, ide_write_sec, NULL, NULL , NULL); + io_sethandler(0x0170, 0x0008, ide_read_sec, ide_read_sec_w, ide_read_sec_l, ide_write_sec, ide_write_sec_w, ide_write_sec_l, NULL); + io_sethandler(0x0376, 0x0001, ide_read_sec, NULL, NULL, ide_write_sec, NULL, NULL , NULL); + ide_base_main[1] = 0x170; + ide_side_main[1] = 0x376; +} + +void ide_sec_enable_ex() +{ + if (ide_base_main[1] & 0x300) + { + io_sethandler(ide_base_main[1], 0x0008, ide_read_sec, ide_read_sec_w, ide_read_sec_l, ide_write_sec, ide_write_sec_w, ide_write_sec_l, NULL); + } + if (ide_side_main[1] & 0x300) + { + io_sethandler(ide_side_main[1], 0x0001, ide_read_sec, NULL, NULL, ide_write_sec, NULL, NULL , NULL); + } } void ide_sec_disable() { - io_removehandler(0x0170, 0x0008, ide_read_sec, ide_read_sec_w, ide_read_sec_l, ide_write_sec, ide_write_sec_w, ide_write_sec_l, NULL); - io_removehandler(0x0376, 0x0001, ide_read_sec, NULL, NULL, ide_write_sec, NULL, NULL , NULL); + io_removehandler(ide_base_main[1], 0x0008, ide_read_sec, ide_read_sec_w, ide_read_sec_l, ide_write_sec, ide_write_sec_w, ide_write_sec_l, NULL); + io_removehandler(ide_side_main[1], 0x0001, ide_read_sec, NULL, NULL, ide_write_sec, NULL, NULL , NULL); +} + +void ide_set_base(int controller, uint16_t port) +{ + ide_base_main[controller] = port; +} + +void ide_set_side(int controller, uint16_t port) +{ + ide_side_main[controller] = port; } -/* *** REMOVE FROM CODE SUBMITTED TO MAINLINE - START *** */ void ide_ter_enable() { - io_sethandler(0x0168, 0x0008, ide_read_ter, ide_read_ter_w, ide_read_ter_l, ide_write_ter, ide_write_ter_w, ide_write_ter_l, NULL); - io_sethandler(0x036e, 0x0001, ide_read_ter, NULL, NULL, ide_write_ter, NULL, NULL , NULL); + io_sethandler(0x0168, 0x0008, ide_read_ter, ide_read_ter_w, ide_read_ter_l, ide_write_ter, ide_write_ter_w, ide_write_ter_l, NULL); + io_sethandler(0x036e, 0x0001, ide_read_ter, NULL, NULL, ide_write_ter, NULL, NULL , NULL); } void ide_ter_disable() { - io_removehandler(0x0168, 0x0008, ide_read_ter, ide_read_ter_w, ide_read_ter_l, ide_write_ter, ide_write_ter_w, ide_write_ter_l, NULL); - io_removehandler(0x036e, 0x0001, ide_read_ter, NULL, NULL, ide_write_ter, NULL, NULL , NULL); + io_removehandler(0x0168, 0x0008, ide_read_ter, ide_read_ter_w, ide_read_ter_l, ide_write_ter, ide_write_ter_w, ide_write_ter_l, NULL); + io_removehandler(0x036e, 0x0001, ide_read_ter, NULL, NULL, ide_write_ter, NULL, NULL , NULL); +} + +void ide_ter_disable_cond() +{ + if ((ide_drives[4].type == IDE_NONE) && (ide_drives[5].type == IDE_NONE)) + { + ide_ter_disable(); + } } void ide_ter_init() { - ide_ter_enable(); + ide_ter_enable(); - timer_add(ide_callback_ter, &idecallback[2], &idecallback[2], NULL); + timer_add(ide_callback_ter, &idecallback[2], &idecallback[2], NULL); } void ide_qua_enable() { - io_sethandler(0x01e8, 0x0008, ide_read_qua, ide_read_qua_w, ide_read_qua_l, ide_write_qua, ide_write_qua_w, ide_write_qua_l, NULL); - io_sethandler(0x03ee, 0x0001, ide_read_qua, NULL, NULL, ide_write_qua, NULL, NULL , NULL); + io_sethandler(0x01e8, 0x0008, ide_read_qua, ide_read_qua_w, ide_read_qua_l, ide_write_qua, ide_write_qua_w, ide_write_qua_l, NULL); + io_sethandler(0x03ee, 0x0001, ide_read_qua, NULL, NULL, ide_write_qua, NULL, NULL , NULL); +} + +void ide_qua_disable_cond() +{ + if ((ide_drives[6].type == IDE_NONE) && (ide_drives[7].type == IDE_NONE)) + { + ide_qua_disable(); + } } void ide_qua_disable() { - io_removehandler(0x01e8, 0x0008, ide_read_qua, ide_read_qua_w, ide_read_qua_l, ide_write_qua, ide_write_qua_w, ide_write_qua_l, NULL); - io_removehandler(0x03ee, 0x0001, ide_read_qua, NULL, NULL, ide_write_qua, NULL, NULL , NULL); + io_removehandler(0x01e8, 0x0008, ide_read_qua, ide_read_qua_w, ide_read_qua_l, ide_write_qua, ide_write_qua_w, ide_write_qua_l, NULL); + io_removehandler(0x03ee, 0x0001, ide_read_qua, NULL, NULL, ide_write_qua, NULL, NULL , NULL); } void ide_qua_init() { - ide_qua_enable(); + ide_qua_enable(); - timer_add(ide_callback_qua, &idecallback[3], &idecallback[3], NULL); + timer_add(ide_callback_qua, &idecallback[3], &idecallback[3], NULL); } -/* *** REMOVE FROM CODE SUBMITTED TO MAINLINE - END *** */ void ide_init() { - ide_pri_enable(); - ide_sec_enable(); - ide_bus_master_read_sector = ide_bus_master_write_sector = NULL; - - timer_add(ide_callback_pri, &idecallback[0], &idecallback[0], NULL); - timer_add(ide_callback_sec, &idecallback[1], &idecallback[1], NULL); + ide_pri_enable(); + ide_sec_enable(); + ide_bus_master_read = ide_bus_master_write = NULL; + + timer_add(ide_callback_pri, &idecallback[0], &idecallback[0], NULL); + timer_add(ide_callback_sec, &idecallback[1], &idecallback[1], NULL); } -void ide_set_bus_master(int (*read_sector)(int channel, uint8_t *data), int (*write_sector)(int channel, uint8_t *data), void (*set_irq)(int channel)) +void ide_xtide_init() { - ide_bus_master_read_sector = read_sector; - ide_bus_master_write_sector = write_sector; - ide_bus_master_set_irq = set_irq; + ide_bus_master_read = ide_bus_master_write = NULL; + + timer_add(ide_callback_xtide, &idecallback[4], &idecallback[4], NULL); +} + +void ide_set_bus_master(int (*read)(int channel, uint8_t *data, int transfer_length), int (*write)(int channel, uint8_t *data, int transfer_length), void (*set_irq)(int channel)) +{ + ide_bus_master_read = read; + ide_bus_master_write = write; + ide_bus_master_set_irq = set_irq; } diff --git a/src/ide.h b/src/ide.h index c25fa5ce5..953cb3731 100644 --- a/src/ide.h +++ b/src/ide.h @@ -1,39 +1,104 @@ -/* Copyright holders: Sarah Walker, Tenshi, SA1988 - see COPYING for more details -*/ -#ifndef __IDE__ -#define __IDE__ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Implementation of the IDE emulation for hard disks and ATAPI + * CD-ROM devices. + * + * Version: @(#)ide.h 1.0.0 2017/05/30 + * + * Author: Sarah Walker, + * Miran Grca, + * TheCollector1995, + * Copyright 2008-2017 Sarah Walker. + * Copyright 2016-2017 Miran Grca. + * Copyright 2016-2017 TheCollector1995. + */ +#ifndef EMU_IDE_H +# define EMU_IDE_H -struct IDE; +#pragma pack(push,1) +typedef struct { + int type; + int board; + uint8_t atastat; + uint8_t error; + int secount,sector,cylinder,head,drive,cylprecomp; + uint8_t command; + uint8_t fdisk; + int pos; + int packlen; + int spt,hpc; + int tracks; + int packetstatus; + uint8_t asc; + int reset; + uint16_t buffer[65536]; + int irqstat; + int service; + int lba; + int channel; + uint32_t lba_addr; + int skip512; + int blocksize, blockcount; + uint16_t dma_identify_data[3]; + int hdi,base; + int hdc_num; + uint8_t specify_success; + int mdma_mode; + uint8_t sector_buffer[256*512]; + int do_initial_read; + int sector_pos; +} IDE; +#pragma pack(pop) + + +extern int ideboard; + +extern int ide_enable[5]; +extern int ide_irq[5]; + +IDE ide_drives[IDE_NUM + XTIDE_NUM]; + + +extern int idecallback[5]; extern void writeide(int ide_board, uint16_t addr, uint8_t val); extern void writeidew(int ide_board, uint16_t val); extern uint8_t readide(int ide_board, uint16_t addr); extern uint16_t readidew(int ide_board); extern void callbackide(int ide_board); extern void resetide(void); -extern void ide_init(); -extern void ide_ter_init(); -extern void ide_qua_init(); -extern void ide_pri_enable(); -extern void ide_sec_enable(); -extern void ide_ter_enable(); -extern void ide_qua_enable(); -extern void ide_pri_disable(); -extern void ide_sec_disable(); -extern void ide_ter_disable(); -extern void ide_qua_disable(); -extern void ide_set_bus_master(int (*read_sector)(int channel, uint8_t *data), int (*write_sector)(int channel, uint8_t *data), void (*set_irq)(int channel)); +extern void ide_init(void); +extern void ide_xtide_init(void); +extern void ide_ter_init(void); +extern void ide_qua_init(void); +extern void ide_pri_enable(void); +extern void ide_sec_enable(void); +extern void ide_ter_enable(void); +extern void ide_qua_enable(void); +extern void ide_pri_disable(void); +extern void ide_sec_disable(void); +extern void ide_ter_disable(void); +extern void ide_qua_disable(void); +extern void ide_set_bus_master(int (*read)(int channel, uint8_t *data, int transfer_length), int (*write)(int channel, uint8_t *data, int transfer_length), void (*set_irq)(int channel)); -extern int ideboard; +void ide_irq_raise(IDE *ide); +void ide_irq_lower(IDE *ide); -extern int ide_enable[4]; -extern int ide_irq[4]; +void ide_padstr8(uint8_t *buf, int buf_size, const char *src); -extern int idecallback[4]; +void win_cdrom_eject(uint8_t id); +void win_cdrom_reload(uint8_t id); -extern char ide_fn[IDE_NUM][512]; +void ide_pri_disable(void); +void ide_pri_enable_ex(void); +void ide_set_base(int controller, uint16_t port); +void ide_set_side(int controller, uint16_t port); -extern int atapi_cdrom_channel; -#endif //__IDE__ +#endif /*EMU_IDE_H*/ diff --git a/src/intel.c b/src/intel.c index 9d305df2b..01560852f 100644 --- a/src/intel.c +++ b/src/intel.c @@ -2,17 +2,16 @@ see COPYING for more details */ #include "ibm.h" -#include "cpu.h" +#include "cpu/cpu.h" #include "io.h" #include "mem.h" #include "pit.h" #include "timer.h" - #include "intel.h" + uint8_t batman_brdconfig(uint16_t port, void *p) { -// pclog("batman_brdconfig read port=%04x\n", port); switch (port) { case 0x73: @@ -24,7 +23,7 @@ uint8_t batman_brdconfig(uint16_t port, void *p) } static uint16_t batman_timer_latch; -static int64_t batman_timer = 0; +static int batman_timer = 0; static void batman_timer_over(void *p) { batman_timer = 0; @@ -65,22 +64,3 @@ void intel_batman_init() io_sethandler(0x0078, 0x0002, batman_timer_read, NULL, NULL, batman_timer_write, NULL, NULL, NULL); timer_add(batman_timer_over, &batman_timer, &batman_timer, NULL); } - - -#if 0 -uint8_t endeavor_brdconfig(uint16_t port, void *p) -{ -// pclog("endeavor_brdconfig read port=%04x\n", port); - switch (port) - { - case 0x79: - return 0xff; - } - return 0; -} - -void intel_endeavor_init() -{ - io_sethandler(0x0079, 0x0001, endeavor_brdconfig, NULL, NULL, NULL, NULL, NULL, NULL); -} -#endif diff --git a/src/intel_flash.c b/src/intel_flash.c index d27835870..e07195754 100644 --- a/src/intel_flash.c +++ b/src/intel_flash.c @@ -1,7 +1,28 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Implementation of the Intel 2 Mbit 8-bit flash devices. + * + * Version: @(#)intel_flash.c 1.0.0 2017/05/30 + * + * Author: Sarah Walker, + * Miran Grca, + * Copyright 2008-2017 Sarah Walker. + * Copyright 2016-2017 Miran Grca. + */ + #include #include "ibm.h" +#include "CPU/cpu.h" #include "device.h" #include "mem.h" +#include "model.h" +#include "rom.h" #define FLASH_IS_BXB 2 #define FLASH_INVERT 1 @@ -20,7 +41,8 @@ enum CMD_ERASE_SETUP = 0x20, CMD_ERASE_CONFIRM = 0xd0, CMD_ERASE_SUSPEND = 0xb0, - CMD_PROGRAM_SETUP = 0x40 + CMD_PROGRAM_SETUP = 0x40, + CMD_PROGRAM_SETUP_ALT = 0x10 }; typedef struct flash_t @@ -33,18 +55,16 @@ typedef struct flash_t uint8_t array[131072]; } flash_t; -static char flash_path[1024]; +static wchar_t flash_path[1024]; static uint8_t flash_read(uint32_t addr, void *p) { flash_t *flash = (flash_t *)p; if (flash->invert_high_pin) { - // pclog("flash_read : addr=%08x/%08x val=%02x command=%02x %04x:%08x\n", addr, addr ^ 0x10000, flash->array[(addr ^ 0x10000) & 0x1ffff], flash->command, CS, cpu_state.pc); addr ^= 0x10000; if (addr & 0xfff00000) return flash->array[addr & 0x1ffff]; } - // pclog("flash_read : addr=%08x command=%02x %04x:%08x\n", addr, flash->command, CS, cpu_state.pc); addr &= 0x1ffff; switch (flash->command) { @@ -65,24 +85,27 @@ static uint8_t flash_read(uint32_t addr, void *p) static uint16_t flash_readw(uint32_t addr, void *p) { flash_t *flash = (flash_t *)p; + uint16_t *q; addr &= 0x1ffff; if (flash->invert_high_pin) addr ^= 0x10000; - return *(uint16_t *)&(flash->array[addr]); + q = (uint16_t *)&(flash->array[addr]); + return *q; } static uint32_t flash_readl(uint32_t addr, void *p) { flash_t *flash = (flash_t *)p; + uint32_t *q; addr &= 0x1ffff; if (flash->invert_high_pin) addr ^= 0x10000; - return *(uint32_t *)&(flash->array[addr]); + q = (uint32_t *)&(flash->array[addr]); + return *q; } static void flash_write(uint32_t addr, uint8_t val, void *p) { flash_t *flash = (flash_t *)p; int i; - // pclog("flash_write : addr=%08x val=%02x command=%02x %04x:%08x\n", addr, val, flash->command, CS, cpu_state.pc); if (flash->invert_high_pin) { @@ -96,8 +119,6 @@ static void flash_write(uint32_t addr, uint8_t val, void *p) case CMD_ERASE_SETUP: if (val == CMD_ERASE_CONFIRM) { - // pclog("flash_write: erase %05x\n", addr); - for (i = 0; i < 3; i++) { if ((addr >= flash->block_start[i]) && (addr <= flash->block_end[i])) @@ -110,7 +131,7 @@ static void flash_write(uint32_t addr, uint8_t val, void *p) break; case CMD_PROGRAM_SETUP: - // pclog("flash_write: program %05x %02x\n", addr, val); + case CMD_PROGRAM_SETUP_ALT: if ((addr & 0x1e000) != (flash->block_start[3] & 0x1e000)) flash->array[addr] = val; flash->command = CMD_READ_STATUS; @@ -154,68 +175,22 @@ static void intel_flash_add_mappings_inverted(flash_t *flash) void *intel_flash_init(uint8_t type) { FILE *f; - flash_t *flash = malloc(sizeof(flash_t)); - memset(flash, 0, sizeof(flash_t)); - char fpath[1024]; int i; + flash_t *flash; + wchar_t *model_name; + wchar_t *flash_name; - switch(romset) - { - case ROM_REVENGE: - strcpy(flash_path, "roms/revenge/"); - break; - case ROM_586MC1: - strcpy(flash_path, "roms/586mc1/"); - break; - case ROM_PLATO: - strcpy(flash_path, "roms/plato/"); - break; - case ROM_ENDEAVOR: - strcpy(flash_path, "roms/endeavor/"); - break; - case ROM_MB500N: - strcpy(flash_path, "roms/mb500n/"); - break; - case ROM_POWERMATE_V: - strcpy(flash_path, "roms/powermate_v/"); - break; - case ROM_P54TP4XE: - strcpy(flash_path, "roms/p54tp4xe/"); - break; - case ROM_ACERM3A: - strcpy(flash_path, "roms/acerm3a/"); - break; - case ROM_ACERV35N: - strcpy(flash_path, "roms/acerv35n/"); - break; - case ROM_430VX: - strcpy(flash_path, "roms/430vx/"); - break; - case ROM_P55VA: - strcpy(flash_path, "roms/p55va/"); - break; - case ROM_P55T2P4: - strcpy(flash_path, "roms/p55t2p4/"); - break; - case ROM_P55TVP4: - strcpy(flash_path, "roms/p55tvp4/"); - break; - case ROM_440FX: - strcpy(flash_path, "roms/440fx/"); - break; - case ROM_MARL: - strcpy(flash_path, "roms/marl/"); - break; - case ROM_THOR: - strcpy(flash_path, "roms/thor/"); - break; - case ROM_MRTHOR: - strcpy(flash_path, "roms/mrthor/"); - break; - default: - fatal("intel_flash_init on unsupported ROM set %i\n", romset); - } - // pclog("Flash init: Path is: %s\n", flash_path); + flash = malloc(sizeof(flash_t)); + memset(flash, 0, sizeof(flash_t)); + + model_name = (wchar_t *) malloc((strlen(model_get_internal_name_ex(model)) << 1) + 2); + mbstowcs(model_name, model_get_internal_name_ex(model), strlen(model_get_internal_name_ex(model)) + 1); + flash_name = (wchar_t *) malloc((wcslen(model_name) << 1) + 2 + 8); + _swprintf(flash_name, L"%s.bin", model_name); + + wcscpy(flash_path, flash_name); + + pclog_w(L"Flash path: %s\n", flash_name); flash->flash_id = (type & FLASH_IS_BXB) ? 0x95 : 0x94; flash->invert_high_pin = (type & FLASH_INVERT); @@ -277,9 +252,7 @@ void *intel_flash_init(uint8_t type) flash->command = CMD_READ_ARRAY; flash->status = 0; - strcpy(fpath, flash_path); - strcat(fpath, "flash.bin"); - f = romfopen(fpath, "rb"); + f = nvrfopen(flash_path, L"rb"); if (f) { fread(&(flash->array[flash->block_start[BLOCK_MAIN]]), flash->block_len[BLOCK_MAIN], 1, f); @@ -288,9 +261,17 @@ void *intel_flash_init(uint8_t type) fclose(f); } + free(flash_name); + free(model_name); + return flash; } +void *intel_flash_bxb_ami_init() +{ + return intel_flash_init(FLASH_IS_BXB | FLASH_INVERT); +} + /* For AMI BIOS'es - Intel 28F001BXT with high address pin inverted. */ void *intel_flash_bxt_ami_init() { @@ -314,11 +295,7 @@ void intel_flash_close(void *p) FILE *f; flash_t *flash = (flash_t *)p; - char fpath[1024]; - - strcpy(fpath, flash_path); - strcat(fpath, "flash.bin"); - f = romfopen(fpath, "wb"); + f = nvrfopen(flash_path, L"wb"); fwrite(&(flash->array[flash->block_start[BLOCK_MAIN]]), flash->block_len[BLOCK_MAIN], 1, f); fwrite(&(flash->array[flash->block_start[BLOCK_DATA1]]), flash->block_len[BLOCK_DATA1], 1, f); fwrite(&(flash->array[flash->block_start[BLOCK_DATA2]]), flash->block_len[BLOCK_DATA2], 1, f); @@ -340,6 +317,19 @@ device_t intel_flash_bxt_ami_device = NULL }; +device_t intel_flash_bxb_ami_device = +{ + "Intel 28F001BXB Flash BIOS", + 0, + intel_flash_bxb_ami_init, + intel_flash_close, + NULL, + NULL, + NULL, + NULL, + NULL +}; + device_t intel_flash_bxt_device = { "Intel 28F001BXT Flash BIOS", diff --git a/src/intel_flash.h b/src/intel_flash.h index e8e0c1bc7..d63b48c18 100644 --- a/src/intel_flash.h +++ b/src/intel_flash.h @@ -1,3 +1,22 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Implementation of the Intel 2 Mbit 8-bit flash devices. + * + * Version: @(#)intel_flash.h 1.0.0 2017/05/30 + * + * Author: Sarah Walker, + * Miran Grca, + * Copyright 2008-2017 Sarah Walker. + * Copyright 2016-2017 Miran Grca. + */ + extern device_t intel_flash_bxt_ami_device; +extern device_t intel_flash_bxb_ami_device; extern device_t intel_flash_bxt_device; extern device_t intel_flash_bxb_device; diff --git a/src/io.c b/src/io.c index 4ec126c1d..ca9259e75 100644 --- a/src/io.c +++ b/src/io.c @@ -2,10 +2,8 @@ see COPYING for more details */ #include "ibm.h" -#include "ide.h" #include "io.h" -#include "video.h" -#include "cpu.h" + uint8_t (*port_inb[0x10000][2])(uint16_t addr, void *priv); uint16_t (*port_inw[0x10000][2])(uint16_t addr, void *priv); @@ -17,16 +15,19 @@ void (*port_outl[0x10000][2])(uint16_t addr, uint32_t val, void *priv); void *port_priv[0x10000][2]; + void io_init() { int c; pclog("io_init\n"); for (c = 0; c < 0x10000; c++) { - port_inb[c][0] = port_inw[c][0] = port_inl[c][0] = NULL; - port_outb[c][0] = port_outw[c][0] = port_outl[c][0] = NULL; - port_inb[c][1] = port_inw[c][1] = port_inl[c][1] = NULL; - port_outb[c][1] = port_outw[c][1] = port_outl[c][1] = NULL; + port_inb[c][0] = port_inb[c][1] = NULL; + port_outb[c][0] = port_outb[c][1] = NULL; + port_inw[c][0] = port_inw[c][1] = NULL; + port_outw[c][0] = port_outw[c][1] = NULL; + port_inl[c][0] = port_inl[c][1] = NULL; + port_outl[c][0] = port_outl[c][1] = NULL; port_priv[c][0] = port_priv[c][1] = NULL; } } @@ -94,6 +95,7 @@ void io_removehandler(uint16_t base, int size, port_outw[ base + c][0] = NULL; if (port_outl[ base + c][0] == outl) port_outl[ base + c][0] = NULL; + port_priv[base + c][0] = NULL; } if (port_priv[base + c][1] == priv) { @@ -109,6 +111,7 @@ void io_removehandler(uint16_t base, int size, port_outw[ base + c][1] = NULL; if (port_outl[ base + c][1] == outl) port_outl[ base + c][1] = NULL; + port_priv[base + c][1] = NULL; } } } @@ -128,8 +131,14 @@ uint8_t inb(uint16_t port) temp &= port_inb[port][1](port, port_priv[port][1]); /* if (!port_inb[port][0] && !port_inb[port][1]) - pclog("Bad INB %04X %04X:%04X\n", port, CS, pc); */ + pclog("Bad INB %04X %04X:%04X\n", port, CS, cpu_state.pc); */ + /* if (port_inb[port][0] || port_inb[port][1]) + pclog("Good INB %04X %04X:%04X\n", port, CS, cpu_state.pc); */ + +#ifdef IO_TRACE +if (CS == IO_TRACE) pclog("IOTRACE(%04X): inb(%04x)=%02x\n", IO_TRACE, port, temp); +#endif return temp; } @@ -142,8 +151,15 @@ void outb(uint16_t port, uint8_t val) if (port_outb[port][1]) port_outb[port][1](port, val, port_priv[port][1]); +#ifdef IO_TRACE +if (CS == IO_TRACE) pclog("IOTRACE(%04X): outb(%04x,%02x)\n", IO_TRACE, port, val); +#endif /* if (!port_outb[port][0] && !port_outb[port][1]) - pclog("Bad OUTB %04X %02X %04X:%08X\n", port, val, CS, pc); */ + pclog("Bad OUTB %04X %02X %04X:%08X\n", port, val, CS, cpu_state.pc); */ + + /* if (port_outb[port][0] || port_outb[port][1]) + pclog("Good OUTB %04X %02X %04X:%08X\n", port, val, CS, cpu_state.pc); */ + return; } diff --git a/src/jim.c b/src/jim.c index d1adcd5c3..6ac1b16f0 100644 --- a/src/jim.c +++ b/src/jim.c @@ -4,9 +4,14 @@ #include #include #include "ibm.h" +#include "cpu/cpu.h" #include "io.h" +#include "device.h" +#include "model.h" + uint8_t europcdat[16]; + struct { uint8_t dat[16]; @@ -14,19 +19,18 @@ struct int addr; } europc_rtc; -void writejim(uint16_t addr, uint8_t val, void *p) + +static void writejim(uint16_t addr, uint8_t val, void *p) { if ((addr&0xFF0)==0x250) europcdat[addr&0xF]=val; switch (addr) { case 0x25A: -// printf("Write RTC stat %i val %02X\n",europc_rtc.stat,val); switch (europc_rtc.stat) { case 0: europc_rtc.addr=val&0xF; europc_rtc.stat++; -// printf("RTC addr now %02X - contents %02X\n",val&0xF,europc_rtc.dat[europc_rtc.addr]); break; case 1: europc_rtc.dat[europc_rtc.addr]=(europc_rtc.dat[europc_rtc.addr]&0xF)|(val<<4); @@ -39,12 +43,11 @@ void writejim(uint16_t addr, uint8_t val, void *p) } break; } -// printf("Write JIM %04X %02X\n",addr,val); } -uint8_t readjim(uint16_t addr, void *p) + +static uint8_t readjim(uint16_t addr, void *p) { -// printf("Read JIM %04X\n",addr); switch (addr) { case 0x250: case 0x251: case 0x252: case 0x253: return 0; @@ -65,7 +68,8 @@ uint8_t readjim(uint16_t addr, void *p) return 0; } -void jim_init() + +void jim_init(void) { uint8_t viddat; memset(europc_rtc.dat,0,16); diff --git a/src/jim.h b/src/jim.h deleted file mode 100644 index 64eb006dc..000000000 --- a/src/jim.h +++ /dev/null @@ -1,4 +0,0 @@ -/* Copyright holders: Sarah Walker - see COPYING for more details -*/ -void jim_init(); diff --git a/src/joystick_ch_flightstick_pro.c b/src/joystick_ch_flightstick_pro.c index 3ced21653..9697c1c6a 100644 --- a/src/joystick_ch_flightstick_pro.c +++ b/src/joystick_ch_flightstick_pro.c @@ -4,10 +4,12 @@ #include "timer.h" #include "gameport.h" #include "joystick_standard.h" -#include "plat-joystick.h" +#include "plat_joystick.h" + static void *ch_flightstick_pro_init() { + return NULL; } static void ch_flightstick_pro_close(void *p) @@ -63,6 +65,8 @@ static int ch_flightstick_pro_read_axis(void *p, int axis) return 0; case 3: return joystick_state[0].axis[2]; + default: + return 0; } } @@ -72,18 +76,18 @@ static void ch_flightstick_pro_a0_over(void *p) joystick_if_t joystick_ch_flightstick_pro = { - .name = "CH Flightstick Pro", - .init = ch_flightstick_pro_init, - .close = ch_flightstick_pro_close, - .read = ch_flightstick_pro_read, - .write = ch_flightstick_pro_write, - .read_axis = ch_flightstick_pro_read_axis, - .a0_over = ch_flightstick_pro_a0_over, - .max_joysticks = 1, - .axis_count = 3, - .button_count = 4, - .pov_count = 1, - .axis_names = {"X axis", "Y axis", "Throttle"}, - .button_names = {"Button 1", "Button 2", "Button 3", "Button 4"}, - .pov_names = {"POV"} + "CH Flightstick Pro", + ch_flightstick_pro_init, + ch_flightstick_pro_close, + ch_flightstick_pro_read, + ch_flightstick_pro_write, + ch_flightstick_pro_read_axis, + ch_flightstick_pro_a0_over, + 1, + 3, + 4, + 1, + {"X axis", "Y axis", "Throttle"}, + {"Button 1", "Button 2", "Button 3", "Button 4"}, + {"POV"} }; diff --git a/src/joystick_standard.c b/src/joystick_standard.c index 6f961a896..c73260cac 100644 --- a/src/joystick_standard.c +++ b/src/joystick_standard.c @@ -4,10 +4,12 @@ #include "timer.h" #include "gameport.h" #include "joystick_standard.h" -#include "plat-joystick.h" +#include "plat_joystick.h" + static void *joystick_standard_init() { + return NULL; } static void joystick_standard_close(void *p) @@ -79,6 +81,8 @@ static int joystick_standard_read_axis(void *p, int axis) if (!JOYSTICK_PRESENT(1)) return AXIS_NOT_PRESENT; return joystick_state[1].axis[1]; + default: + return 0; } } @@ -97,6 +101,8 @@ static int joystick_standard_read_axis_4button(void *p, int axis) return 0; case 3: return 0; + default: + return 0; } } static int joystick_standard_read_axis_6button(void *p, int axis) @@ -114,6 +120,8 @@ static int joystick_standard_read_axis_6button(void *p, int axis) return joystick_state[0].button[4] ? -32767 : 32768; case 3: return joystick_state[0].button[5] ? -32767 : 32768; + default: + return 0; } } static int joystick_standard_read_axis_8button(void *p, int axis) @@ -139,6 +147,8 @@ static int joystick_standard_read_axis_8button(void *p, int axis) if (joystick_state[0].button[7]) return 32768; return 0; + default: + return 0; } } @@ -148,61 +158,65 @@ static void joystick_standard_a0_over(void *p) joystick_if_t joystick_standard = { - .name = "Standard 2-button joystick(s)", - .init = joystick_standard_init, - .close = joystick_standard_close, - .read = joystick_standard_read, - .write = joystick_standard_write, - .read_axis = joystick_standard_read_axis, - .a0_over = joystick_standard_a0_over, - .max_joysticks = 2, - .axis_count = 2, - .button_count = 2, - .axis_names = {"X axis", "Y axis"}, - .button_names = {"Button 1", "Button 2"} + "Standard 2-button joystick(s)", + joystick_standard_init, + joystick_standard_close, + joystick_standard_read, + joystick_standard_write, + joystick_standard_read_axis, + joystick_standard_a0_over, + 2, + 2, + 2, + 0, + {"X axis", "Y axis"}, + {"Button 1", "Button 2"} }; joystick_if_t joystick_standard_4button = { - .name = "Standard 4-button joystick", - .init = joystick_standard_init, - .close = joystick_standard_close, - .read = joystick_standard_read_4button, - .write = joystick_standard_write, - .read_axis = joystick_standard_read_axis_4button, - .a0_over = joystick_standard_a0_over, - .max_joysticks = 1, - .axis_count = 2, - .button_count = 4, - .axis_names = {"X axis", "Y axis"}, - .button_names = {"Button 1", "Button 2", "Button 3", "Button 4"} + "Standard 4-button joystick", + joystick_standard_init, + joystick_standard_close, + joystick_standard_read_4button, + joystick_standard_write, + joystick_standard_read_axis_4button, + joystick_standard_a0_over, + 1, + 2, + 4, + 0, + {"X axis", "Y axis"}, + {"Button 1", "Button 2", "Button 3", "Button 4"} }; joystick_if_t joystick_standard_6button = { - .name = "Standard 6-button joystick", - .init = joystick_standard_init, - .close = joystick_standard_close, - .read = joystick_standard_read_4button, - .write = joystick_standard_write, - .read_axis = joystick_standard_read_axis_6button, - .a0_over = joystick_standard_a0_over, - .max_joysticks = 1, - .axis_count = 2, - .button_count = 6, - .axis_names = {"X axis", "Y axis"}, - .button_names = {"Button 1", "Button 2", "Button 3", "Button 4", "Button 5", "Button 6"} + "Standard 6-button joystick", + joystick_standard_init, + joystick_standard_close, + joystick_standard_read_4button, + joystick_standard_write, + joystick_standard_read_axis_6button, + joystick_standard_a0_over, + 1, + 2, + 6, + 0, + {"X axis", "Y axis"}, + {"Button 1", "Button 2", "Button 3", "Button 4", "Button 5", "Button 6"} }; joystick_if_t joystick_standard_8button = { - .name = "Standard 8-button joystick", - .init = joystick_standard_init, - .close = joystick_standard_close, - .read = joystick_standard_read_4button, - .write = joystick_standard_write, - .read_axis = joystick_standard_read_axis_8button, - .a0_over = joystick_standard_a0_over, - .max_joysticks = 1, - .axis_count = 2, - .button_count = 8, - .axis_names = {"X axis", "Y axis"}, - .button_names = {"Button 1", "Button 2", "Button 3", "Button 4", "Button 5", "Button 6", "Button 7", "Button 8"} + "Standard 8-button joystick", + joystick_standard_init, + joystick_standard_close, + joystick_standard_read_4button, + joystick_standard_write, + joystick_standard_read_axis_8button, + joystick_standard_a0_over, + 1, + 2, + 8, + 0, + {"X axis", "Y axis"}, + {"Button 1", "Button 2", "Button 3", "Button 4", "Button 5", "Button 6", "Button 7", "Button 8"} }; diff --git a/src/joystick_sw_pad.c b/src/joystick_sw_pad.c index 007dd5492..d256c290f 100644 --- a/src/joystick_sw_pad.c +++ b/src/joystick_sw_pad.c @@ -26,7 +26,8 @@ #include "timer.h" #include "gameport.h" #include "joystick_sw_pad.h" -#include "plat-joystick.h" +#include "plat_joystick.h" + typedef struct { @@ -149,7 +150,6 @@ static void sw_write(void *p) if (time_since_last > 9900 && time_since_last < 9940) { -// pclog("sw sends ID packet\n"); sw->poll_mode = 0; sw->poll_left = 49; sw->poll_data = 0x2400ull | (0x1830ull << 15) | (0x19b0ull << 30); @@ -157,8 +157,6 @@ static void sw_write(void *p) else { int c; - -// pclog("sw sends data packet %08x %i\n", cpu_state.pc, data_packets++); sw->poll_mode = sw->data_mode; sw->data_mode = !sw->data_mode; @@ -236,16 +234,17 @@ static void sw_a0_over(void *p) joystick_if_t joystick_sw_pad = { - .name = "Microsoft SideWinder Pad", - .init = sw_init, - .close = sw_close, - .read = sw_read, - .write = sw_write, - .read_axis = sw_read_axis, - .a0_over = sw_a0_over, - .max_joysticks = 4, - .axis_count = 2, - .button_count = 10, - .axis_names = {"X axis", "Y axis"}, - .button_names = {"A", "B", "C", "X", "Y", "Z", "L", "R", "Start", "M"} + "Microsoft SideWinder Pad", + sw_init, + sw_close, + sw_read, + sw_write, + sw_read_axis, + sw_a0_over, + 4, + 2, + 10, + 0, + {"X axis", "Y axis"}, + {"A", "B", "C", "X", "Y", "Z", "L", "R", "Start", "M"} }; diff --git a/src/joystick_tm_fcs.c b/src/joystick_tm_fcs.c index 02c153e49..1380c052d 100644 --- a/src/joystick_tm_fcs.c +++ b/src/joystick_tm_fcs.c @@ -4,10 +4,12 @@ #include "timer.h" #include "gameport.h" #include "joystick_standard.h" -#include "plat-joystick.h" +#include "plat_joystick.h" + static void *tm_fcs_init() { + return NULL; } static void tm_fcs_close(void *p) @@ -62,6 +64,8 @@ static int tm_fcs_read_axis(void *p, int axis) if (joystick_state[0].pov[0] >= 225 && joystick_state[0].pov[0] < 315) return 16384; return 0; + default: + return 0; } } @@ -71,18 +75,18 @@ static void tm_fcs_a0_over(void *p) joystick_if_t joystick_tm_fcs = { - .name = "Thrustmaster Flight Control System", - .init = tm_fcs_init, - .close = tm_fcs_close, - .read = tm_fcs_read, - .write = tm_fcs_write, - .read_axis = tm_fcs_read_axis, - .a0_over = tm_fcs_a0_over, - .max_joysticks = 1, - .axis_count = 2, - .button_count = 4, - .pov_count = 1, - .axis_names = {"X axis", "Y axis"}, - .button_names = {"Button 1", "Button 2", "Button 3", "Button 4"}, - .pov_names = {"POV"} + "Thrustmaster Flight Control System", + tm_fcs_init, + tm_fcs_close, + tm_fcs_read, + tm_fcs_write, + tm_fcs_read_axis, + tm_fcs_a0_over, + 1, + 2, + 4, + 1, + {"X axis", "Y axis"}, + {"Button 1", "Button 2", "Button 3", "Button 4"}, + {"POV"} }; diff --git a/src/keyboard.c b/src/keyboard.c index 8090f9196..7a60c5a62 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -1,11 +1,27 @@ -/* Copyright holders: Sarah Walker, Tenshi - see COPYING for more details -*/ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Host to guest keyboard interface and keyboard scan code sets. + * + * Version: @(#)keyboard.c 1.0.0 2017/05/30 + * + * Author: Sarah Walker, + * Miran Grca, + * Copyright 2008-2017 Sarah Walker. + * Copyright 2016-2017 Miran Grca. + */ + #include "ibm.h" -#include "plat-keyboard.h" +#include "plat_keyboard.h" #include "keyboard.h" int keybsendcallback = 0; +int keybsenddelay; typedef struct { @@ -467,7 +483,6 @@ void keyboard_process() if (!set3_all_break && !recv_key[scorder[c]] && !(set3_flags[scancodes[scorder[c]].scancodes_make[0]] & 2)) continue; } -// pclog("Key %02X start\n", scorder[c]); d = 0; if (recv_key[scorder[c]]) { diff --git a/src/keyboard.h b/src/keyboard.h index b53b3a8d5..217f1cee1 100644 --- a/src/keyboard.h +++ b/src/keyboard.h @@ -1,6 +1,21 @@ -/* Copyright holders: Sarah Walker, Tenshi - see COPYING for more details -*/ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Host to guest keyboard interface and keyboard scan code sets. + * + * Version: @(#)keyboard.h 1.0.0 2017/05/30 + * + * Author: Sarah Walker, + * Miran Grca, + * Copyright 2008-2017 Sarah Walker. + * Copyright 2016-2017 Miran Grca. + */ + extern void (*keyboard_send)(uint8_t val); extern void (*keyboard_poll)(); extern int keyboard_scan; diff --git a/src/keyboard_amstrad.c b/src/keyboard_amstrad.c index 7f1a99c9e..f87cfd983 100644 --- a/src/keyboard_amstrad.c +++ b/src/keyboard_amstrad.c @@ -7,13 +7,13 @@ #include "mem.h" #include "pic.h" #include "pit.h" -#include "sound.h" -#include "sound_speaker.h" #include "timer.h" - +#include "sound/sound.h" +#include "sound/snd_speaker.h" #include "keyboard.h" #include "keyboard_amstrad.h" + #define STAT_PARITY 0x80 #define STAT_RTIMEOUT 0x40 #define STAT_TTIMEOUT 0x20 @@ -88,7 +88,7 @@ void keyboard_amstrad_write(uint16_t port, uint8_t val, void *priv) speaker_enable = val & 2; if (speaker_enable) was_speaker_enable = 1; - pit_set_gate(2, val & 1); + pit_set_gate(&pit, 2, val & 1); if (val & 0x80) keyboard_amstrad.pa = 0; @@ -107,15 +107,12 @@ void keyboard_amstrad_write(uint16_t port, uint8_t val, void *priv) default: pclog("\nBad XT keyboard write %04X %02X\n", port, val); -// dumpregs(); -// exit(-1); } } uint8_t keyboard_amstrad_read(uint16_t port, void *priv) { - uint8_t temp; -// pclog("keyboard_amstrad : read %04X ", port); + uint8_t temp = 0xff; switch (port) { case 0x60: @@ -155,10 +152,7 @@ uint8_t keyboard_amstrad_read(uint16_t port, void *priv) default: pclog("\nBad XT keyboard read %04X\n", port); -// dumpregs(); -// exit(-1); } -// pclog("%02X %04X:%04X\n", temp, CS, pc); return temp; } @@ -171,7 +165,6 @@ void keyboard_amstrad_reset() void keyboard_amstrad_init() { - //return; pclog("keyboard_amstrad_init\n"); io_sethandler(0x0060, 0x0006, keyboard_amstrad_read, NULL, NULL, keyboard_amstrad_write, NULL, NULL, NULL); keyboard_amstrad_reset(); diff --git a/src/keyboard_at.c b/src/keyboard_at.c index edeeeb39e..fbd9c02e1 100644 --- a/src/keyboard_at.c +++ b/src/keyboard_at.c @@ -1,20 +1,36 @@ -/* Copyright holders: Sarah Walker, Tenshi - see COPYING for more details -*/ -#include +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Intel 8042 (AT keyboard controller) emulation. + * + * Version: @(#)keyboard_at.c 1.0.0 2017/05/30 + * + * Author: Sarah Walker, + * Miran Grca, + * Copyright 2008-2017 Sarah Walker. + * Copyright 2016-2017 Miran Grca. + */ +#include #include "ibm.h" #include "io.h" #include "mem.h" #include "pic.h" #include "pit.h" -#include "sound.h" -#include "sound_speaker.h" #include "timer.h" - +#include "disc.h" +#include "fdc.h" +#include "sound/sound.h" +#include "sound/snd_speaker.h" #include "keyboard.h" #include "keyboard_at.h" + #define STAT_PARITY 0x80 #define STAT_RTIMEOUT 0x40 #define STAT_TTIMEOUT 0x20 @@ -25,6 +41,8 @@ #define STAT_IFULL 0x02 #define STAT_OFULL 0x01 +#define PS2_REFRESH_TIME (16 * TIMER_USEC) + #define CCB_UNUSED 0x80 #define CCB_TRANSLATE 0x40 #define CCB_PCMODE 0x20 @@ -63,6 +81,11 @@ struct void (*mouse_write)(uint8_t val, void *p); void *mouse_p; + + int refresh_time; + int refresh; + + int is_ps2; } keyboard_at; static uint8_t key_ctrl_queue[16]; @@ -136,7 +159,6 @@ void keyboard_at_poll() keyboard_at.status |= STAT_OFULL; keyboard_at.status &= ~STAT_IFULL; keyboard_at.status |= STAT_MFULL; -// pclog("keyboard_at : take IRQ12\n"); keyboard_at.last_irq = 0x1000; } else @@ -148,12 +170,17 @@ void keyboard_at_poll() keyboard_at.status |= STAT_OFULL; keyboard_at.status &= ~STAT_IFULL; keyboard_at.status &= ~STAT_MFULL; -// pclog("keyboard_at : take IRQ1\n"); keyboard_at.last_irq = 2; } } - if (!(keyboard_at.status & STAT_OFULL) && keyboard_at.out_new == -1 && /*!(keyboard_at.mem[0] & 0x20) &&*/ + if (keyboard_at.out_new == -1 && !(keyboard_at.status & STAT_OFULL) && + key_ctrl_queue_start != key_ctrl_queue_end) + { + keyboard_at.out_new = key_ctrl_queue[key_ctrl_queue_start]; + key_ctrl_queue_start = (key_ctrl_queue_start + 1) & 0xf; + } + else if (!(keyboard_at.status & STAT_OFULL) && keyboard_at.out_new == -1 && /*!(keyboard_at.mem[0] & 0x20) &&*/ mouse_queue_start != mouse_queue_end) { keyboard_at.out_new = mouse_queue[mouse_queue_start] | 0x100; @@ -165,29 +192,12 @@ void keyboard_at_poll() keyboard_at.out_new = key_queue[key_queue_start]; key_queue_start = (key_queue_start + 1) & 0xf; } - else if (keyboard_at.out_new == -1 && !(keyboard_at.status & STAT_OFULL) && - key_ctrl_queue_start != key_ctrl_queue_end) - { - keyboard_at.out_new = key_ctrl_queue[key_ctrl_queue_start]; - key_ctrl_queue_start = (key_ctrl_queue_start + 1) & 0xf; - } } void keyboard_at_adddata(uint8_t val) { -// if (keyboard_at.status & STAT_OFULL) -// { key_ctrl_queue[key_ctrl_queue_end] = val; key_ctrl_queue_end = (key_ctrl_queue_end + 1) & 0xf; -// pclog("keyboard_at : %02X added to queue\n", val); -/* return; - } - keyboard_at.out = val; - keyboard_at.status |= STAT_OFULL; - keyboard_at.status &= ~STAT_IFULL; - if (keyboard_at.mem[0] & 0x01) - keyboard_at.wantirq = 1; - pclog("keyboard_at : output %02X (IRQ %i)\n", val, keyboard_at.wantirq);*/ } uint8_t sc_or = 0; @@ -223,18 +233,12 @@ void keyboard_at_adddata_mouse(uint8_t val) { mouse_queue[mouse_queue_end] = val; mouse_queue_end = (mouse_queue_end + 1) & 0xf; -// pclog("keyboard_at : %02X added to mouse queue\n", val); return; } void keyboard_at_write(uint16_t port, uint8_t val, void *priv) { int i = 0; -// pclog("keyboard_at : write %04X %02X %i %02X\n", port, val, keyboard_at.key_wantdata, ram[8]); -/* if (ram[8] == 0xc3) - { - output = 3; - }*/ switch (port) { case 0x60: @@ -244,7 +248,15 @@ void keyboard_at_write(uint16_t port, uint8_t val, void *priv) keyboard_at.want60 = 0; switch (keyboard_at.command) { - case 0x40 ... 0x5f: /* 0x40 - 0x5F are aliases for 0x60-0x7F */ + /* 0x40 - 0x5F are aliases for 0x60-0x7F */ + case 0x40: case 0x41: case 0x42: case 0x43: + case 0x44: case 0x45: case 0x46: case 0x47: + case 0x48: case 0x49: case 0x4a: case 0x4b: + case 0x4c: case 0x4d: case 0x4e: case 0x4f: + case 0x50: case 0x51: case 0x52: case 0x53: + case 0x54: case 0x55: case 0x56: case 0x57: + case 0x58: case 0x59: case 0x5a: case 0x5b: + case 0x5c: case 0x5d: case 0x5e: case 0x5f: keyboard_at.command |= 0x20; goto write_register; @@ -268,7 +280,6 @@ write_register: mouse_scan = !(val & 0x20); /* Addition by OBattler: Scan code translate ON/OFF. */ - // pclog("KEYBOARD_AT: Writing %02X to system register\n", val); mode &= 0x93; mode |= (val & MODE_MASK); if (first_write) @@ -285,7 +296,6 @@ write_register: } keyboard_at.default_mode = (mode & 3); first_write = 0; - // pclog("Keyboard set to scan code set %i, mode & 0x60 = 0x%02X\n", mode & 3, mode & 0x60); /* No else because in all other cases, translation is off, so we need to keep it set to set 0 which the mode &= 0xFC above will set it. */ } @@ -295,23 +305,18 @@ write_register: case 0xaf: /*AMI - set extended controller RAM*/ if (keyboard_at.secr_phase == 0) { - // pclog("Set extended controller RAM - phase 0 (bad)\n"); goto bad_command; } else if (keyboard_at.secr_phase == 1) { - // pclog("Set extended controller RAM - phase 1\n"); keyboard_at.mem_addr = val; keyboard_at.want60 = 1; keyboard_at.secr_phase = 2; - // pclog("Set extended controller RAM - starting phase 2\n"); } else if (keyboard_at.secr_phase == 2) { - // pclog("Set extended controller RAM - phase 2\n"); keyboard_at.mem[keyboard_at.mem_addr] = val; keyboard_at.secr_phase = 0; - // pclog("Set extended controller RAM - starting phase 0\n"); } break; @@ -325,12 +330,10 @@ write_register: break; case 0xd1: /*Write output port*/ -// pclog("Write output port - %02X %02X %04X:%04X\n", keyboard_at.output_port, val, CS, pc); if ((keyboard_at.output_port ^ val) & 0x02) /*A20 enable change*/ { mem_a20_key = val & 0x02; mem_a20_recalc(); -// pclog("Rammask change to %08X %02X\n", rammask, val & 0x02); flushmmucache(); } keyboard_at.output_port = val; @@ -352,8 +355,6 @@ write_register: default: bad_command: pclog("Bad AT keyboard controller 0060 write %02X command %02X\n", val, keyboard_at.command); -// dumpregs(); -// exit(-1); } } else @@ -370,7 +371,6 @@ bad_command: break; case 0xf0: /*Get/set scancode set*/ - // pclog("KEYBOARD_AT: Get/set scan code set: %i\n", val); if (val == 0) { keyboard_at_adddata_keyboard(mode & 3); @@ -392,8 +392,6 @@ bad_command: default: pclog("Bad AT keyboard 0060 write %02X command %02X\n", val, keyboard_at.key_command); -// dumpregs(); -// exit(-1); } } else @@ -452,11 +450,9 @@ bad_command: break; case 0xf6: /*Set defaults*/ - // pclog("KEYBOARD_AT: Set defaults\n"); set3_all_break = 0; set3_all_repeat = 0; memset(set3_flags, 0, 272); - // mode = (mode & 0xFC) | 2; mode = (mode & 0xFC) | keyboard_at.default_mode; keyboard_at_adddata_keyboard(0xfa); break; @@ -487,7 +483,6 @@ bad_command: break; case 0xff: /*Reset*/ - // pclog("KEYBOARD_AT: Set defaults\n"); key_queue_start = key_queue_end = 0; /*Clear key queue*/ keyboard_at_adddata_keyboard(0xfa); keyboard_at_adddata_keyboard(0xaa); @@ -499,8 +494,6 @@ bad_command: default: pclog("Bad AT keyboard command %02X\n", val); keyboard_at_adddata_keyboard(0xfe); -// dumpregs(); -// exit(-1); } } } @@ -517,7 +510,7 @@ bad_command: speaker_enable = val & 2; if (speaker_enable) was_speaker_enable = 1; - pit_set_gate(2, val & 1); + pit_set_gate(&pit, 2, val & 1); break; case 0x64: @@ -526,7 +519,14 @@ bad_command: /*New controller command*/ switch (val) { - case 0x00 ... 0x1f: + case 0x00: case 0x01: case 0x02: case 0x03: + case 0x04: case 0x05: case 0x06: case 0x07: + case 0x08: case 0x09: case 0x0a: case 0x0b: + case 0x0c: case 0x0d: case 0x0e: case 0x0f: + case 0x10: case 0x11: case 0x12: case 0x13: + case 0x14: case 0x15: case 0x16: case 0x17: + case 0x18: case 0x19: case 0x1a: case 0x1b: + case 0x1c: case 0x1d: case 0x1e: case 0x1f: val |= 0x20; /* 0x00-0x1f are aliases for 0x20-0x3f */ keyboard_at_adddata(keyboard_at.mem[val & 0x1f]); break; @@ -583,7 +583,6 @@ bad_command: { mem_a20_key = 2; mem_a20_recalc(); -// pclog("Rammask change to %08X %02X\n", rammask, val & 0x02); flushmmucache(); } keyboard_at.output_port = 0xcf; @@ -625,10 +624,12 @@ bad_command: case ROM_ENDEAVOR: case ROM_THOR: case ROM_MRTHOR: + case ROM_AP53: + case ROM_P55T2S: + case ROM_S1668: /*Set extended controlled RAM*/ keyboard_at.want60 = 1; keyboard_at.secr_phase = 1; - // pclog("Set extended controller RAM - starting phase 1\n"); break; default: /*Read keyboard version*/ @@ -637,24 +638,25 @@ bad_command: } break; - case 0xb0 ... 0xbf: /*Set keyboard lines low (B0-B7) or high (B8-BF)*/ + case 0xb0: case 0xb1: case 0xb2: case 0xb3: case 0xb4: case 0xb5: case 0xb6: case 0xb7: + case 0xb8: case 0xb9: case 0xba: case 0xbb: case 0xbc: case 0xbd: case 0xbe: case 0xbf: + /*Set keyboard lines low (B0-B7) or high (B8-BF)*/ keyboard_at_adddata(0x00); break; case 0xc0: /*Read input port*/ - keyboard_at_adddata((keyboard_at.input_port & 0xf0) | 0x80); - // keyboard_at_adddata(keyboard_at.input_port | 4); - // keyboard_at.input_port = ((keyboard_at.input_port + 1) & 3) | (keyboard_at.input_port & 0xfc); + keyboard_at_adddata(keyboard_at.input_port | 4 | fdc_ps1_525()); + keyboard_at.input_port = ((keyboard_at.input_port + 1) & 3) | (keyboard_at.input_port & 0xfc) | fdc_ps1_525(); break; case 0xc1: /*Copy bits 0 to 3 of input port to status bits 4 to 7*/ keyboard_at.status &= 0xf; - keyboard_at.status |= ((keyboard_at.input_port & 0xf) << 4); + keyboard_at.status |= ((((keyboard_at.input_port & 0xfc) | 0x84 | fdc_ps1_525()) & 0xf) << 4); break; case 0xc2: /*Copy bits 4 to 7 of input port to status bits 4 to 7*/ keyboard_at.status &= 0xf; - keyboard_at.status |= (keyboard_at.input_port & 0xf0); + keyboard_at.status |= (((keyboard_at.input_port & 0xfc) | 0x84 | fdc_ps1_525()) & 0xf0); break; case 0xc9: /*AMI - block P22 and P23 ??? */ @@ -691,7 +693,21 @@ bad_command: case 0xd4: /*Write to mouse*/ keyboard_at.want60 = 1; break; - + + case 0xdd: /* Disable A20 Address Line */ + keyboard_at.output_port &= ~0x02; + mem_a20_key = 0; + mem_a20_recalc(); + flushmmucache(); + break; + + case 0xdf: /* Enable A20 Address Line */ + keyboard_at.output_port |= 0x02; + mem_a20_key = 2; + mem_a20_recalc(); + flushmmucache(); + break; + case 0xe0: /*Read test inputs*/ keyboard_at_adddata(0x00); break; @@ -699,19 +715,19 @@ bad_command: case 0xef: /*??? - sent by AMI486*/ break; - case 0xf0 ... 0xff: + case 0xf0: case 0xf1: case 0xf2: case 0xf3: case 0xf4: case 0xf5: case 0xf6: case 0xf7: + case 0xf8: case 0xf9: case 0xfa: case 0xfb: case 0xfc: case 0xfd: case 0xfe: case 0xff: if (!(val & 1)) { /* Pin 0 selected. */ - softresetx86(); /*Pulse reset!*/ - cpu_set_edx(); + /* trc_reset(2); */ + softresetx86(); /*Pulse reset!*/ + cpu_set_edx(); } break; default: pclog("Bad AT keyboard controller command %02X\n", val); -// dumpregs(); -// exit(-1); } } } @@ -719,26 +735,36 @@ bad_command: uint8_t keyboard_at_read(uint16_t port, void *priv) { uint8_t temp = 0xff; - cycles -= 4; -// if (port != 0x61) pclog("keyboard_at : read %04X ", port); switch (port) { case 0x60: temp = keyboard_at.out; keyboard_at.status &= ~(STAT_OFULL/* | STAT_MFULL*/); - picintc(keyboard_at.last_irq); if (PCI) { /* The PIIX/PIIX3 datasheet mandates that both of these interrupts are cleared on any read of port 0x60. */ picintc(1 << 1); picintc(1 << 12); } + else + { + picintc(keyboard_at.last_irq); + } keyboard_at.last_irq = 0; break; - case 0x61: - if (ppispeakon) return (ppi.pb&~0xC0)|0x20; - return ppi.pb&~0xe0; + case 0x61: + temp = ppi.pb & ~0xe0; + if (ppispeakon) + temp |= 0x20; + if (keyboard_at.is_ps2) + { + if (keyboard_at.refresh) + temp |= 0x10; + else + temp &= ~0x10; + } + break; case 0x64: temp = (keyboard_at.status & 0xFB) | (mode & CCB_SYSTEM); @@ -746,7 +772,6 @@ uint8_t keyboard_at_read(uint16_t port, void *priv) keyboard_at.status &= ~(STAT_RTIMEOUT/* | STAT_TTIMEOUT*/); break; } -// if (port != 0x61) pclog("%02X %08X\n", temp, rammask); return temp; } @@ -760,7 +785,7 @@ void keyboard_at_reset() first_write = 1; keyboard_at.wantirq = 0; keyboard_at.output_port = 0xcf; - keyboard_at.input_port = 0xb0; + keyboard_at.input_port = (MDA) ? 0xf0 : 0xb0; keyboard_at.out_new = -1; keyboard_at.last_irq = 0; keyboard_at.secr_phase = 0; @@ -774,15 +799,21 @@ void keyboard_at_reset() memset(set3_flags, 0, 272); } +static void at_refresh(void *p) +{ + keyboard_at.refresh = !keyboard_at.refresh; + keyboard_at.refresh_time += PS2_REFRESH_TIME; +} + void keyboard_at_init() { - //return; io_sethandler(0x0060, 0x0005, keyboard_at_read, NULL, NULL, keyboard_at_write, NULL, NULL, NULL); keyboard_at_reset(); keyboard_send = keyboard_at_adddata_keyboard; keyboard_poll = keyboard_at_poll; keyboard_at.mouse_write = NULL; keyboard_at.mouse_p = NULL; + keyboard_at.is_ps2 = 0; dtrans = 0; timer_add(keyboard_at_poll, &keybsenddelay, TIMER_ALWAYS_ENABLED, NULL); @@ -793,3 +824,9 @@ void keyboard_at_set_mouse(void (*mouse_write)(uint8_t val, void *p), void *p) keyboard_at.mouse_write = mouse_write; keyboard_at.mouse_p = p; } + +void keyboard_at_init_ps2() +{ + timer_add(at_refresh, &keyboard_at.refresh_time, TIMER_ALWAYS_ENABLED, NULL); + keyboard_at.is_ps2 = 1; +} diff --git a/src/keyboard_at.h b/src/keyboard_at.h index 5f0d758ee..d92101543 100644 --- a/src/keyboard_at.h +++ b/src/keyboard_at.h @@ -1,10 +1,27 @@ -/* Copyright holders: Sarah Walker, Tenshi - see COPYING for more details -*/ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Intel 8042 (AT keyboard controller) emulation. + * + * Version: @(#)keyboard_at.h 1.0.0 2017/05/30 + * + * Author: Sarah Walker, + * Miran Grca, + * Copyright 2008-2017 Sarah Walker. + * Copyright 2016-2017 Miran Grca. + */ + void keyboard_at_init(); +void keyboard_at_init_ps2(); void keyboard_at_reset(); void keyboard_at_poll(); void keyboard_at_adddata_keyboard_raw(uint8_t val); +void keyboard_at_adddata_mouse(uint8_t val); void keyboard_at_set_mouse(void (*mouse_write)(uint8_t val, void *p), void *p); extern int mouse_queue_start, mouse_queue_end; diff --git a/src/keyboard_olim24.c b/src/keyboard_olim24.c index 79eff4217..55c2f1868 100644 --- a/src/keyboard_olim24.c +++ b/src/keyboard_olim24.c @@ -1,15 +1,17 @@ +#include #include "ibm.h" #include "io.h" #include "mem.h" -#include "mouse.h" #include "pic.h" -#include "sound.h" -#include "sound_speaker.h" +#include "pit.h" #include "timer.h" - +#include "mouse.h" +#include "sound/sound.h" +#include "sound/snd_speaker.h" #include "keyboard.h" #include "keyboard_olim24.h" + #define STAT_PARITY 0x80 #define STAT_RTIMEOUT 0x40 #define STAT_TTIMEOUT 0x20 @@ -19,6 +21,7 @@ #define STAT_IFULL 0x02 #define STAT_OFULL 0x01 + struct { int wantirq; @@ -42,7 +45,6 @@ static uint8_t mouse_scancodes[7]; void keyboard_olim24_poll() { keybsenddelay += (1000 * TIMER_USEC); - //pclog("poll %i\n", keyboard_olim24.wantirq); if (keyboard_olim24.wantirq) { keyboard_olim24.wantirq = 0; @@ -105,8 +107,6 @@ void keyboard_olim24_write(uint16_t port, uint8_t val, void *priv) default: pclog("Bad keyboard command complete %02X\n", keyboard_olim24.command); -// dumpregs(); -// exit(-1); } } } @@ -134,8 +134,6 @@ void keyboard_olim24_write(uint16_t port, uint8_t val, void *priv) default: pclog("Bad keyboard command %02X\n", val); -// dumpregs(); -// exit(-1); } } @@ -152,15 +150,14 @@ void keyboard_olim24_write(uint16_t port, uint8_t val, void *priv) speaker_enable = val & 2; if (speaker_enable) was_speaker_enable = 1; - pit_set_gate(2, val & 1); + pit_set_gate(&pit, 2, val & 1); break; } } uint8_t keyboard_olim24_read(uint16_t port, void *priv) { - uint8_t temp; -// pclog("keyboard_olim24 : read %04X ", port); + uint8_t temp = 0xff; switch (port) { case 0x60: @@ -190,10 +187,7 @@ uint8_t keyboard_olim24_read(uint16_t port, void *priv) default: pclog("\nBad olim24 keyboard read %04X\n", port); -// dumpregs(); -// exit(-1); } -// pclog("%02X\n", temp); return temp; } @@ -221,17 +215,15 @@ typedef struct mouse_olim24_t int x, y, b; } mouse_olim24_t; -void mouse_olim24_poll(int x, int y, int z, int b, void *p) +uint8_t mouse_olim24_poll(int x, int y, int z, int b, void *p) { mouse_olim24_t *mouse = (mouse_olim24_t *)p; mouse->x += x; mouse->y += y; -// pclog("mouse_poll - %i, %i %i, %i\n", x, y, mouse->x, mouse->y); - if (((key_queue_end - key_queue_start) & 0xf) > 14) - return; + return(0xff); if ((b & 1) && !(mouse->b & 1)) keyboard_olim24_adddata(mouse_scancodes[0]); if (!(b & 1) && (mouse->b & 1)) @@ -239,7 +231,7 @@ void mouse_olim24_poll(int x, int y, int z, int b, void *p) mouse->b = (mouse->b & ~1) | (b & 1); if (((key_queue_end - key_queue_start) & 0xf) > 14) - return; + return(0xff); if ((b & 2) && !(mouse->b & 2)) keyboard_olim24_adddata(mouse_scancodes[2]); if (!(b & 2) && (mouse->b & 2)) @@ -247,7 +239,7 @@ void mouse_olim24_poll(int x, int y, int z, int b, void *p) mouse->b = (mouse->b & ~2) | (b & 2); if (((key_queue_end - key_queue_start) & 0xf) > 14) - return; + return(0xff); if ((b & 4) && !(mouse->b & 4)) keyboard_olim24_adddata(mouse_scancodes[1]); if (!(b & 4) && (mouse->b & 4)) @@ -257,9 +249,9 @@ void mouse_olim24_poll(int x, int y, int z, int b, void *p) if (keyboard_olim24.mouse_mode) { if (((key_queue_end - key_queue_start) & 0xf) > 12) - return; + return(0xff); if (!mouse->x && !mouse->y) - return; + return(0xff); mouse->y = -mouse->y; @@ -282,32 +274,34 @@ void mouse_olim24_poll(int x, int y, int z, int b, void *p) while (mouse->x < -4) { if (((key_queue_end - key_queue_start) & 0xf) > 14) - return; + return(0xff); mouse->x += 4; keyboard_olim24_adddata(mouse_scancodes[3]); } while (mouse->x > 4) { if (((key_queue_end - key_queue_start) & 0xf) > 14) - return; + return(0xff); mouse->x -= 4; keyboard_olim24_adddata(mouse_scancodes[4]); } while (mouse->y < -4) { if (((key_queue_end - key_queue_start) & 0xf) > 14) - return; + return(0xff); mouse->y += 4; keyboard_olim24_adddata(mouse_scancodes[5]); } while (mouse->y > 4) { if (((key_queue_end - key_queue_start) & 0xf) > 14) - return; + return(0xff); mouse->y -= 4; keyboard_olim24_adddata(mouse_scancodes[6]); } } + + return(0); } static void *mouse_olim24_init() @@ -328,15 +322,15 @@ static void mouse_olim24_close(void *p) mouse_t mouse_olim24 = { "Olivetti M24 mouse", + "olim24", + MOUSE_TYPE_OLIM24, mouse_olim24_init, mouse_olim24_close, - mouse_olim24_poll, - MOUSE_TYPE_OLIM24 + mouse_olim24_poll }; void keyboard_olim24_init() { - //return; io_sethandler(0x0060, 0x0002, keyboard_olim24_read, NULL, NULL, keyboard_olim24_write, NULL, NULL, NULL); io_sethandler(0x0064, 0x0001, keyboard_olim24_read, NULL, NULL, keyboard_olim24_write, NULL, NULL, NULL); keyboard_olim24_reset(); diff --git a/src/keyboard_olim24.h b/src/keyboard_olim24.h index 5ea3af04f..305a3e245 100644 --- a/src/keyboard_olim24.h +++ b/src/keyboard_olim24.h @@ -1,5 +1,3 @@ void keyboard_olim24_init(); void keyboard_olim24_reset(); void keyboard_olim24_poll(); - -extern mouse_t mouse_olim24; diff --git a/src/keyboard_pcjr.c b/src/keyboard_pcjr.c index 64fa693cd..a7005d77b 100644 --- a/src/keyboard_pcjr.c +++ b/src/keyboard_pcjr.c @@ -2,21 +2,21 @@ see COPYING for more details */ #include - #include "ibm.h" -#include "device.h" #include "io.h" #include "mem.h" #include "nmi.h" #include "pic.h" -#include "sound.h" -#include "sound_sn76489.h" -#include "sound_speaker.h" +#include "pit.h" #include "timer.h" - +#include "device.h" +#include "sound/sound.h" +#include "sound/snd_speaker.h" +#include "sound/snd_sn76489.h" #include "keyboard.h" #include "keyboard_pcjr.h" + #define STAT_PARITY 0x80 #define STAT_RTIMEOUT 0x40 #define STAT_TTIMEOUT 0x20 @@ -52,7 +52,6 @@ void keyboard_pcjr_poll() int p = 0; uint8_t key = key_queue[key_queue_start]; -// pclog("Reading %02X from the key queue at %i\n", key, key_queue_start); key_queue_start = (key_queue_start + 1) & 0xf; keyboard_pcjr.latched = 1; @@ -102,25 +101,18 @@ void keyboard_pcjr_poll() keyboard_pcjr.serial_pos++; if (keyboard_pcjr.serial_pos == 42+1) keyboard_pcjr.serial_pos = 0; -// pclog("Keyboard poll %i %i\n", keyboard_pcjr.data, keyboard_pcjr.serial_pos); } } void keyboard_pcjr_adddata(uint8_t val) { key_queue[key_queue_end] = val; -// pclog("keyboard_pcjr : %02X added to key queue at %i\n", val, key_queue_end); key_queue_end = (key_queue_end + 1) & 0xf; return; } void keyboard_pcjr_write(uint16_t port, uint8_t val, void *priv) { -// pclog("keyboard_pcjr : write %04X %02X %02X\n", port, val, keyboard_pcjr.pb); -/* if (ram[8] == 0xc3) - { - output = 3; - }*/ switch (port) { case 0x60: @@ -138,7 +130,7 @@ void keyboard_pcjr_write(uint16_t port, uint8_t val, void *priv) speaker_enable = val & 2; if (speaker_enable) was_speaker_enable = 1; - pit_set_gate(2, val & 1); + pit_set_gate(&pit, 2, val & 1); sn76489_mute = speaker_mute = 1; switch (val & 0x60) { @@ -153,7 +145,7 @@ void keyboard_pcjr_write(uint16_t port, uint8_t val, void *priv) case 0xa0: nmi_mask = val & 0x80; - pit_set_using_timer(1, !(val & 0x20)); + pit_set_using_timer(&pit, 1, !(val & 0x20)); break; } } @@ -161,7 +153,6 @@ void keyboard_pcjr_write(uint16_t port, uint8_t val, void *priv) uint8_t keyboard_pcjr_read(uint16_t port, void *priv) { uint8_t temp; -// pclog("keyboard_pcjr : read %04X ", port); switch (port) { case 0x60: @@ -178,21 +169,19 @@ uint8_t keyboard_pcjr_read(uint16_t port, void *priv) temp |= (ppispeakon ? 0x10 : 0); temp |= (ppispeakon ? 0x20 : 0); temp |= (keyboard_pcjr.data ? 0x40: 0); -// temp |= 0x04; if (keyboard_pcjr.data) temp |= 0x40; break; case 0xa0: keyboard_pcjr.latched = 0; + temp = 0; break; default: pclog("\nBad XT keyboard read %04X\n", port); - //dumpregs(); - //exit(-1); + temp = 0xff; } -// pclog("%02X\n", temp); return temp; } @@ -202,7 +191,6 @@ void keyboard_pcjr_reset() void keyboard_pcjr_init() { - //return; io_sethandler(0x0060, 0x0004, keyboard_pcjr_read, NULL, NULL, keyboard_pcjr_write, NULL, NULL, NULL); io_sethandler(0x00a0, 0x0008, keyboard_pcjr_read, NULL, NULL, keyboard_pcjr_write, NULL, NULL, NULL); keyboard_pcjr_reset(); diff --git a/src/keyboard_xt.c b/src/keyboard_xt.c index bb9233491..c4497f9b9 100644 --- a/src/keyboard_xt.c +++ b/src/keyboard_xt.c @@ -2,18 +2,20 @@ see COPYING for more details */ #include - #include "ibm.h" #include "io.h" #include "mem.h" #include "pic.h" -#include "sound.h" -#include "sound_speaker.h" +#include "pit.h" #include "timer.h" - +#include "device.h" +#include "tandy_eeprom.h" +#include "sound/sound.h" +#include "sound/snd_speaker.h" #include "keyboard.h" #include "keyboard_xt.h" + #define STAT_PARITY 0x80 #define STAT_RTIMEOUT 0x40 #define STAT_TTIMEOUT 0x20 @@ -23,6 +25,7 @@ #define STAT_IFULL 0x02 #define STAT_OFULL 0x01 + struct { int blocked; @@ -59,15 +62,9 @@ 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); -/* if (ram[8] == 0xc3) - { - output = 3; - }*/ switch (port) { case 0x61: -// pclog("keyboard_xt : pb write %02X %02X %i %02X %i\n", val, keyboard_xt.pb, !(keyboard_xt.pb & 0x40), keyboard_xt.pb & 0x40, (val & 0x40)); if (!(keyboard_xt.pb & 0x40) && (val & 0x40)) /*Reset keyboard*/ { pclog("keyboard_xt : reset keyboard\n"); @@ -91,7 +88,7 @@ void keyboard_xt_write(uint16_t port, uint8_t val, void *priv) speaker_enable = val & 2; if (speaker_enable) was_speaker_enable = 1; - pit_set_gate(2, val & 1); + pit_set_gate(&pit, 2, val & 1); break; } @@ -100,7 +97,6 @@ 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); switch (port) { case 0x60: @@ -150,10 +146,8 @@ uint8_t keyboard_xt_read(uint16_t port, void *priv) default: pclog("\nBad XT keyboard read %04X\n", port); - //dumpregs(); - //exit(-1); + temp = 0xff; } -// pclog("%02X\n", temp); return temp; } @@ -166,7 +160,6 @@ void keyboard_xt_reset() void keyboard_xt_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; @@ -178,7 +171,6 @@ void keyboard_xt_init() 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; diff --git a/src/laserxt.c b/src/laserxt.c new file mode 100644 index 000000000..33afbce37 --- /dev/null +++ b/src/laserxt.c @@ -0,0 +1,131 @@ +/*This is the chipset used in the LaserXT series model*/ +#include "ibm.h" +#include "cpu/cpu.h" +#include "io.h" +#include "mem.h" +#include "device.h" +#include "model.h" + + +static int laserxt_emspage[4]; +static int laserxt_emscontrol[4]; +static mem_mapping_t laserxt_ems_mapping[4]; +static int laserxt_ems_baseaddr_index = 0; + + +static uint32_t get_laserxt_ems_addr(uint32_t addr) +{ + if(laserxt_emspage[(addr >> 14) & 3] & 0x80) + { + addr = 0xA0000 + ((laserxt_emspage[(addr >> 14) & 3] & 0x0F) << 14) + ((laserxt_emspage[(addr >> 14) & 3] & 0x40) << 12) + (addr & 0x3FFF); + } + return addr; +} + + +static void laserxt_write(uint16_t port, uint8_t val, void *priv) +{ + int i; + uint32_t paddr, vaddr; + switch (port) + { + case 0x0208: case 0x4208: case 0x8208: case 0xC208: + laserxt_emspage[port >> 14] = val; + paddr = 0xC0000 + (port & 0xC000) + (((laserxt_ems_baseaddr_index + (4 - (port >> 14))) & 0x0C) << 14); + if(val & 0x80) + { + mem_mapping_enable(&laserxt_ems_mapping[port >> 14]); + vaddr = get_laserxt_ems_addr(paddr); + //pclog("Mapping address %05X to %06X\n", paddr, vaddr); + mem_mapping_set_exec(&laserxt_ems_mapping[port >> 14], ram + vaddr); + } + else + { + //pclog("Unmap address %05X\n", paddr); + mem_mapping_disable(&laserxt_ems_mapping[port >> 14]); + } + //pclog("Write LaserXT port %04X to %02X at %04X:%04X\n", port, val, CS, cpu_state.pc); + flushmmucache(); + break; + case 0x0209: case 0x4209: case 0x8209: case 0xC209: + laserxt_emscontrol[port >> 14] = val; + laserxt_ems_baseaddr_index = 0; + for(i=0; i<4; i++) + { + laserxt_ems_baseaddr_index |= (laserxt_emscontrol[i] & 0x80) >> (7 - i); + } + //pclog("Set base_index to %d\n", laserxt_ems_baseaddr_index); + if(laserxt_ems_baseaddr_index < 3) + { + mem_mapping_disable(&romext_mapping); + } + else + { + mem_mapping_enable(&romext_mapping); + } + + mem_mapping_set_addr(&laserxt_ems_mapping[0], 0xC0000 + (((laserxt_ems_baseaddr_index + 4) & 0x0C) << 14), 0x4000); + mem_mapping_set_addr(&laserxt_ems_mapping[1], 0xC4000 + (((laserxt_ems_baseaddr_index + 3) & 0x0C) << 14), 0x4000); + mem_mapping_set_addr(&laserxt_ems_mapping[2], 0xC8000 + (((laserxt_ems_baseaddr_index + 2) & 0x0C) << 14), 0x4000); + mem_mapping_set_addr(&laserxt_ems_mapping[3], 0xCC000 + (((laserxt_ems_baseaddr_index + 1) & 0x0C) << 14), 0x4000); + //pclog("Write LaserXT port %04X to %02X at %04X:%04X\n", port, val, CS, cpu_state.pc); + flushmmucache(); + break; + } +} + + +static uint8_t laserxt_read(uint16_t port, void *priv) +{ + switch (port) + { + case 0x0208: case 0x4208: case 0x8208: case 0xC208: + //pclog("Read LaserXT port %04X at %04X:%04X\n", port, CS, cpu_state.pc); + return laserxt_emspage[port >> 14]; + case 0x0209: case 0x4209: case 0x8209: case 0xC209: + return laserxt_emscontrol[port >> 14]; + break; + } + return 0xff; +} + + +static void mem_write_laserxtems(uint32_t addr, uint8_t val, void *priv) +{ + addr = get_laserxt_ems_addr(addr); + if (addr < (mem_size << 10)) + ram[addr] = val; +} + + +static uint8_t mem_read_laserxtems(uint32_t addr, void *priv) +{ + uint8_t val = 0xFF; + addr = get_laserxt_ems_addr(addr); + if (addr < (mem_size << 10)) + val = ram[addr]; + return val; +} + + +void laserxt_init(void) +{ + int i; + + if(mem_size > 640) + { + io_sethandler(0x0208, 0x0002, laserxt_read, NULL, NULL, laserxt_write, NULL, NULL, NULL); + io_sethandler(0x4208, 0x0002, laserxt_read, NULL, NULL, laserxt_write, NULL, NULL, NULL); + io_sethandler(0x8208, 0x0002, laserxt_read, NULL, NULL, laserxt_write, NULL, NULL, NULL); + io_sethandler(0xc208, 0x0002, laserxt_read, NULL, NULL, laserxt_write, NULL, NULL, NULL); + } + + for (i = 0; i < 4; i++) + { + laserxt_emspage[i] = 0x7F; + laserxt_emscontrol[i] = (i == 3) ? 0x00 : 0x80; + mem_mapping_add(&laserxt_ems_mapping[i], 0xE0000 + (i << 14), 0x4000, mem_read_laserxtems, NULL, NULL, mem_write_laserxtems, NULL, NULL, ram + 0xA0000 + (i << 14), 0, NULL); + mem_mapping_disable(&laserxt_ems_mapping[i]); + } + mem_set_mem_state(0x0c0000, 0x40000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); +} diff --git a/src/cdrom-ioctl-linux.c b/src/lnx/cdrom_ioctl_linux.c similarity index 99% rename from src/cdrom-ioctl-linux.c rename to src/lnx/cdrom_ioctl_linux.c index 5b993b612..bf1f73994 100644 --- a/src/cdrom-ioctl-linux.c +++ b/src/lnx/cdrom_ioctl_linux.c @@ -9,7 +9,7 @@ #include #include "ibm.h" #include "ide.h" -#include "cdrom-ioctl.h" +#include "cdrom_ioctl.h" static ATAPI ioctl_atapi; diff --git a/src/lnx/lnx_thread.c b/src/lnx/lnx_thread.c new file mode 100644 index 000000000..d9f16a0ef --- /dev/null +++ b/src/lnx/lnx_thread.c @@ -0,0 +1,108 @@ +/* Copyright holders: Sarah Walker + see COPYING for more details +*/ +#include +#include +#include +#include +#include "plat_thread.h" + + +typedef struct { + pthread_cond_t cond; + pthread_mutex_t mutex; +} event_pthread_t; + + +thread_t *thread_create(void (*thread_rout)(void *param), void *param) +{ + pthread_t *thread = malloc(sizeof(pthread_t)); + + if (thread != NULL) + pthread_create(thread, NULL, thread_rout, param); + + return(thread); +} + + +void thread_kill(thread_t *handle) +{ + pthread_t *thread = (pthread_t *)handle; + + if (thread != NULL) { + pthread_cancel(*thread); + pthread_join(*thread, NULL); + + free(thread); + } +} + + +event_t *thread_create_event(void) +{ + event_pthread_t *event = malloc(sizeof(event_pthread_t)); + + if (event != NULL) { + pthread_cond_init(&event->cond, NULL); + pthread_mutex_init(&event->mutex, NULL); + } + + return((event_t *)event); +} + + +void thread_set_event(event_t *handle) +{ + event_pthread_t *event = (event_pthread_t *)handle; + + if (event != NULL) { + pthread_mutex_lock(&event->mutex); + pthread_cond_broadcast(&event->cond); + pthread_mutex_unlock(&event->mutex); + } +} + + +void thread_reset_event(event_t *handle) +{ +} + + +int thread_wait_event(event_t *handle, int timeout) +{ + event_pthread_t *event = (event_pthread_t *)handle; + struct timespec abstime; + + clock_gettime(CLOCK_REALTIME, &abstime); + abstime.tv_nsec += (timeout % 1000) * 1000000; + abstime.tv_sec += (timeout / 1000); + if (abstime.tv_nsec > 1000000000) { + abstime.tv_nsec -= 1000000000; + abstime.tv_sec++; + } + + pthread_mutex_lock(&event->mutex); + pthread_cond_timedwait(&event->cond, &event->mutex, &abstime); + pthread_mutex_unlock(&event->mutex); + + return(0); +} + + +void thread_destroy_event(event_t *handle) +{ + event_pthread_t *event = (event_pthread_t *)handle; + + if (event != NULL) { + pthread_cond_destroy(&event->cond); + pthread_mutex_destroy(&event->mutex); + + free(event); + } +} + + +void thread_sleep(int t) +{ + usleep(t * 1000); +} diff --git a/src/lnx/plat_thread.h b/src/lnx/plat_thread.h new file mode 100644 index 000000000..dfb3a9c26 --- /dev/null +++ b/src/lnx/plat_thread.h @@ -0,0 +1,24 @@ +/* Copyright holders: Sarah Walker + see COPYING for more details +*/ +#ifndef PLAT_THREAD_H +# define PLAT_THREAD_H + + +typedef void thread_t; +typedef void event_t; + + +extern thread_t *thread_create(void (*thread_rout)(void *param), void *param); +extern void thread_kill(thread_t *handle); + +extern event_t *thread_create_event(void); +extern void thread_set_event(event_t *event); +extern void thread_reset_event(event_t *_event); +extern int thread_wait_event(event_t *event, int timeout); +extern void thread_destroy_event(event_t *_event); + +extern void thread_sleep(int t); + + +#endif /*PLAT_THREAD_H*/ diff --git a/src/lpt.c b/src/lpt.c index 251c56a4a..73cd3ce6d 100644 --- a/src/lpt.c +++ b/src/lpt.c @@ -14,11 +14,9 @@ void lpt1_write(uint16_t port, uint8_t val, void *priv) switch (port & 3) { case 0: - writedac(val); lpt1_dat = val; break; case 2: - writedacctrl(val); lpt1_ctrl = val; break; } @@ -29,8 +27,6 @@ uint8_t lpt1_read(uint16_t port, void *priv) { case 0: return lpt1_dat; - case 1: - return readdacfifo(); case 2: return lpt1_ctrl; } @@ -42,11 +38,9 @@ void lpt2_write(uint16_t port, uint8_t val, void *priv) switch (port & 3) { case 0: - writedac(val); lpt2_dat = val; break; case 2: - writedacctrl(val); lpt2_ctrl = val; break; } @@ -57,39 +51,39 @@ uint8_t lpt2_read(uint16_t port, void *priv) { case 0: return lpt2_dat; - case 1: - return readdacfifo(); case 2: return lpt2_ctrl; } return 0xff; } +uint16_t lpt_addr[2] = { 0x378, 0x278 }; + void lpt_init() { io_sethandler(0x0378, 0x0003, lpt1_read, NULL, NULL, lpt1_write, NULL, NULL, NULL); io_sethandler(0x0278, 0x0003, lpt2_read, NULL, NULL, lpt2_write, NULL, NULL, NULL); + lpt_addr[0] = 0x378; + lpt_addr[1] = 0x278; } void lpt1_init(uint16_t port) { io_sethandler(port, 0x0003, lpt1_read, NULL, NULL, lpt1_write, NULL, NULL, NULL); + lpt_addr[0] = port; } void lpt1_remove() { - io_removehandler(0x0278, 0x0003, lpt1_read, NULL, NULL, lpt1_write, NULL, NULL, NULL); - io_removehandler(0x0378, 0x0003, lpt1_read, NULL, NULL, lpt1_write, NULL, NULL, NULL); - io_removehandler(0x03bc, 0x0003, lpt1_read, NULL, NULL, lpt1_write, NULL, NULL, NULL); + io_removehandler(lpt_addr[0], 0x0003, lpt1_read, NULL, NULL, lpt1_write, NULL, NULL, NULL); } void lpt2_init(uint16_t port) { io_sethandler(port, 0x0003, lpt2_read, NULL, NULL, lpt2_write, NULL, NULL, NULL); + lpt_addr[1] = port; } void lpt2_remove() { - io_removehandler(0x0278, 0x0003, lpt2_read, NULL, NULL, lpt2_write, NULL, NULL, NULL); - io_removehandler(0x0378, 0x0003, lpt2_read, NULL, NULL, lpt2_write, NULL, NULL, NULL); - io_removehandler(0x03bc, 0x0003, lpt2_read, NULL, NULL, lpt2_write, NULL, NULL, NULL); + io_removehandler(lpt_addr[1], 0x0003, lpt2_read, NULL, NULL, lpt2_write, NULL, NULL, NULL); } void lpt2_remove_ams() diff --git a/src/lzf/lzf_c.c b/src/lzf/lzf_c.c index bc07084b8..120b4a5aa 100644 --- a/src/lzf/lzf_c.c +++ b/src/lzf/lzf_c.c @@ -34,6 +34,8 @@ * either the BSD or the GPL. */ +#include + #include "lzfP.h" #define HSIZE (1 << (HLOG)) @@ -120,7 +122,7 @@ lzf_compress (const void *const in_data, unsigned int in_len, * special workaround for it. */ #if defined (WIN32) && defined (_M_X64) - unsigned _int64 off; /* workaround for missing POSIX compliance */ + uint64_t off; /* workaround for missing POSIX compliance */ #else unsigned long off; #endif diff --git a/src/mca.c b/src/mca.c new file mode 100644 index 000000000..aacebd792 --- /dev/null +++ b/src/mca.c @@ -0,0 +1,64 @@ +#include "ibm.h" +#include "io.h" +#include "mem.h" + +#include "mca.h" + +void (*mca_card_write[8])(int addr, uint8_t val, void *priv); +uint8_t (*mca_card_read[8])(int addr, void *priv); +void *mca_priv[8]; +static int mca_index; +static int mca_nr_cards; + +void mca_init(int nr_cards) +{ + int c; + + for (c = 0; c < 8; c++) + { + mca_card_read[c] = NULL; + mca_card_write[c] = NULL; + mca_priv[c] = NULL; + } + + mca_index = 0; + mca_nr_cards = nr_cards; +} + +void mca_set_index(int index) +{ + mca_index = index; +} + +uint8_t mca_read(uint16_t port) +{ + if (mca_index >= mca_nr_cards) + return 0xff; + if (!mca_card_read[mca_index]) + return 0xff; + return mca_card_read[mca_index](port, mca_priv[mca_index]); +} + +void mca_write(uint16_t port, uint8_t val) +{ + if (mca_index >= mca_nr_cards) + return; + if (mca_card_write[mca_index]) + mca_card_write[mca_index](port, val, mca_priv[mca_index]); +} + +void mca_add(uint8_t (*read)(int addr, void *priv), void (*write)(int addr, uint8_t val, void *priv), void *priv) +{ + int c; + + for (c = 0; c < mca_nr_cards; c++) + { + if (!mca_card_read[c] && !mca_card_write[c]) + { + mca_card_read[c] = read; + mca_card_write[c] = write; + mca_priv[c] = priv; + return; + } + } +} diff --git a/src/mca.h b/src/mca.h new file mode 100644 index 000000000..90d7f07ef --- /dev/null +++ b/src/mca.h @@ -0,0 +1,5 @@ +void mca_init(int nr_cards); +void mca_add(uint8_t (*read)(int addr, void *priv), void (*write)(int addr, uint8_t val, void *priv), void *priv); +void mca_set_index(int index); +uint8_t mca_read(uint16_t port); +void mca_write(uint16_t port, uint8_t val); diff --git a/src/mcr.c b/src/mcr.c index 32f67fd63..1cc47f441 100644 --- a/src/mcr.c +++ b/src/mcr.c @@ -21,12 +21,6 @@ void writemcr(uint16_t addr, uint8_t val) case 0x22: if (val==6 && mcr22==6) nextreg6=1; else nextreg6=0; -// if ((val&1) && (mcr22&1)) shadowbios=1; -// if (!(val&1) && !(mcr22&1)) shadowbios=0; -// if (!mcrfirst) shadowbios=val&1; -// mcrfirst=0; -// dumpregs(); -// exit(-1); break; case 0x23: if (nextreg6) shadowbios=!val; diff --git a/src/mem.c b/src/mem.c index acc1280cf..5a5543dc6 100644 --- a/src/mem.c +++ b/src/mem.c @@ -7,19 +7,19 @@ - pc2386 video BIOS is underdumped (16k instead of 24k) - c386sx16 BIOS fails checksum */ - #include #include #include "ibm.h" - +#include "cpu/cpu.h" +#include "cpu/x86_ops.h" +#include "cpu/x86.h" #include "config.h" +#include "io.h" #include "mem.h" -#include "video.h" -#include "x86.h" -#include "cpu.h" #include "rom.h" -#include "x86_ops.h" -#include "codegen.h" +#include "cpu/codegen.h" +#include "video/video.h" + page_t *pages; page_t **page_lookup; @@ -39,19 +39,36 @@ static int _mem_state[0x40000]; static mem_mapping_t base_mapping; mem_mapping_t ram_low_mapping; -static mem_mapping_t ram_high_mapping; +mem_mapping_t ram_high_mapping; static mem_mapping_t ram_mid_mapping; static mem_mapping_t ram_remapped_mapping; mem_mapping_t bios_mapping[8]; mem_mapping_t bios_high_mapping[8]; -static mem_mapping_t romext_mapping; +mem_mapping_t romext_mapping; + +uint8_t *ram; +uint32_t rammask; + +uint32_t pccache; +uint8_t *pccache2; + +int readlookup[256],readlookupp[256]; +uintptr_t *readlookup2; +int readlnext; +int writelookup[256],writelookupp[256]; +uintptr_t *writelookup2; +int writelnext; int shadowbios,shadowbios_write; +int mem_a20_state; + static unsigned char isram[0x10000]; static uint8_t ff_array[0x1000]; +int enable_xtide = 0; + int mem_size; uint32_t biosmask; int readlnum=0,writelnum=0; @@ -60,40 +77,13 @@ int cachesize=256; uint8_t *ram,*rom; uint8_t romext[32768]; -static void mem_load_xtide_bios() -{ - FILE *f; - f=romfopen("roms/ide_xt.bin","rb"); - -// is486=0; - if (f) - { - fread(romext,16384,1,f); - mem_mapping_enable(&romext_mapping); - fclose(f); - } -} - -static void mem_load_atide_bios() -{ - FILE *f; - f=romfopen("roms/ide_at.bin","rb"); - -// is486=0; - if (f) - { - fread(romext,16384,1,f); - mem_mapping_enable(&romext_mapping); - fclose(f); - } -} +uint32_t ram_mapped_addr[64]; static void mem_load_atide115_bios() { FILE *f; - f=romfopen("roms/ide_at_1_1_5.bin","rb"); + f=romfopen(L"roms/ide_at_1_1_5.bin",L"rb"); -// is486=0; if (f) { fread(romext,16384,1,f); @@ -107,11 +97,13 @@ int loadbios() FILE *f=NULL,*ff=NULL; int c; - loadfont("roms/mda.rom", 0); - loadfont("roms/wy700.rom", 3); + loadfont(L"roms/mda.rom", 0); + loadfont(L"roms/wy700.rom", 3); biosmask = 0xffff; + if (!rom) + rom = malloc(0x20000); memset(romext,0xff,0x8000); memset(rom, 0xff, 0x20000); @@ -122,8 +114,8 @@ int loadbios() switch (romset) { case ROM_PC1512: - f=romfopen("roms/pc1512/40043.v1","rb"); - ff=romfopen("roms/pc1512/40044.v1","rb"); + f=romfopen(L"roms/pc1512/40043.v1",L"rb"); + ff=romfopen(L"roms/pc1512/40044.v1",L"rb"); if (!f || !ff) break; for (c=0xC000;c<0x10000;c+=2) { @@ -132,12 +124,11 @@ int loadbios() } fclose(ff); fclose(f); - mem_load_xtide_bios(); - loadfont("roms/pc1512/40078.ic127", 2); + loadfont(L"roms/pc1512/40078.ic127", 2); return 1; case ROM_PC1640: - f=romfopen("roms/pc1640/40044.v3","rb"); - ff=romfopen("roms/pc1640/40043.v3","rb"); + f=romfopen(L"roms/pc1640/40044.v3",L"rb"); + ff=romfopen(L"roms/pc1640/40043.v3",L"rb"); if (!f || !ff) break; for (c=0xC000;c<0x10000;c+=2) { @@ -146,14 +137,13 @@ int loadbios() } fclose(ff); fclose(f); - f=romfopen("roms/pc1640/40100","rb"); + f=romfopen(L"roms/pc1640/40100",L"rb"); if (!f) break; fclose(f); - mem_load_xtide_bios(); return 1; case ROM_PC200: - f=romfopen("roms/pc200/pc20v2.1","rb"); - ff=romfopen("roms/pc200/pc20v2.0","rb"); + f=romfopen(L"roms/pc200/pc20v2.1",L"rb"); + ff=romfopen(L"roms/pc200/pc20v2.0",L"rb"); if (!f || !ff) break; for (c=0xC000;c<0x10000;c+=2) { @@ -162,27 +152,24 @@ int loadbios() } fclose(ff); fclose(f); - mem_load_xtide_bios(); - loadfont("roms/pc200/40109.bin", 1); + loadfont(L"roms/pc200/40109.bin", 1); return 1; case ROM_TANDY: - f=romfopen("roms/tandy/tandy1t1.020","rb"); + f=romfopen(L"roms/tandy/tandy1t1.020",L"rb"); if (!f) break; fread(rom,65536,1,f); fclose(f); - mem_load_xtide_bios(); return 1; case ROM_TANDY1000HX: - f = romfopen("roms/tandy1000hx/v020000.u12", "rb"); + f = romfopen(L"roms/tandy1000hx/v020000.u12", L"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"); + f = romfopen(L"roms/tandy1000sl2/8079047.hu1" ,L"rb"); + ff = romfopen(L"roms/tandy1000sl2/8079048.hu2",L"rb"); if (!f || !ff) break; fseek(f, 0x30000/2, SEEK_SET); fseek(ff, 0x30000/2, SEEK_SET); @@ -193,63 +180,84 @@ int loadbios() } 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); - fclose(f); - f=fopen("pcjr/basic.rom","rb"); - fread(rom+0x6000,32768,1,f); - fclose(f); - break;*/ case ROM_IBMXT: - f=romfopen("roms/ibmxt/xt.rom","rb"); + f=romfopen(L"roms/ibmxt/xt.rom",L"rb"); if (!f) { - f = romfopen("roms/ibmxt/5000027.u19", "rb"); - ff = romfopen("roms/ibmxt/1501512.u18","rb"); + f = romfopen(L"roms/ibmxt/5000027.u19", L"rb"); + ff = romfopen(L"roms/ibmxt/1501512.u18", L"rb"); if (!f || !ff) break; fread(rom, 0x8000, 1, f); fread(rom + 0x8000, 0x8000, 1, ff); fclose(ff); fclose(f); - mem_load_xtide_bios(); return 1; } else { fread(rom,65536,1,f); fclose(f); - mem_load_xtide_bios(); return 1; } break; case ROM_IBMPCJR: - f = romfopen("roms/ibmpcjr/bios.rom","rb"); + f = romfopen(L"roms/ibmpcjr/bios.rom", L"rb"); if (!f) break; fread(rom, 0x10000, 1, f); fclose(f); return 1; - case ROM_GENXT: - f=romfopen("roms/genxt/pcxt.rom","rb"); + case ROM_PORTABLE: + f=romfopen(L"roms/portable/Compaq Portable Plus 100666-001 Rev C u47.bin",L"rb"); + if (!f) break; + fread(rom+0xE000,8192,1,f); + fclose(f); + return 1; + + case ROM_PORTABLEII: + f = romfopen(L"roms/portableii/62x0820.u27", L"rb"); + ff =romfopen(L"roms/portableii/62x0821.u47", L"rb"); + if (!f || !ff) break; + for (c=0x0000;c<0x10000;c+=2) + { + rom[c]=getc(f); + rom[c+1]=getc(ff); + } + fclose(ff); + fclose(f); + return 1; + + case ROM_PORTABLEIII: + case ROM_PORTABLEIII386: + f = romfopen(L"roms/portableiii/62x0820.u27", L"rb"); + ff =romfopen(L"roms/portableiii/62x0821.u47", L"rb"); + if (!f || !ff) break; + for (c=0x0000;c<0x10000;c+=2) + { + rom[c]=getc(f); + rom[c+1]=getc(ff); + } + fclose(ff); + fclose(f); + return 1; + + case ROM_GENXT: + f=romfopen(L"roms/genxt/pcxt.rom",L"rb"); if (!f) break; fread(rom+0xE000,8192,1,f); fclose(f); - mem_load_xtide_bios(); return 1; case ROM_DTKXT: - f=romfopen("roms/dtk/DTK_ERSO_2.42_2764.bin","rb"); + f=romfopen(L"roms/dtk/DTK_ERSO_2.42_2764.bin",L"rb"); if (!f) break; fread(rom+0xE000,8192,1,f); fclose(f); - mem_load_xtide_bios(); return 1; case ROM_OLIM24: - f = romfopen("roms/olivetti_m24/olivetti_m24_version_1.43_low.bin" ,"rb"); - ff = romfopen("roms/olivetti_m24/olivetti_m24_version_1.43_high.bin","rb"); + f = romfopen(L"roms/olivetti_m24/olivetti_m24_version_1.43_low.bin" ,L"rb"); + ff = romfopen(L"roms/olivetti_m24/olivetti_m24_version_1.43_high.bin",L"rb"); if (!f || !ff) break; for (c = 0x0000; c < 0x4000; c += 2) { @@ -258,12 +266,11 @@ int loadbios() } fclose(ff); fclose(f); - mem_load_xtide_bios(); return 1; case ROM_PC2086: - f = romfopen("roms/pc2086/40179.ic129" ,"rb"); - ff = romfopen("roms/pc2086/40180.ic132","rb"); + f = romfopen(L"roms/pc2086/40179.ic129" ,L"rb"); + ff = romfopen(L"roms/pc2086/40180.ic132",L"rb"); if (!f || !ff) break; pclog("Loading BIOS\n"); for (c = 0x0000; c < 0x4000; c += 2) @@ -274,34 +281,26 @@ int loadbios() pclog("%02X %02X %02X\n", rom[0xfff0], rom[0xfff1], rom[0xfff2]); fclose(ff); fclose(f); - f = romfopen("roms/pc2086/40186.ic171", "rb"); + f = romfopen(L"roms/pc2086/40186.ic171", L"rb"); if (!f) break; fclose(f); - mem_load_xtide_bios(); biosmask = 0x3fff; return 1; case ROM_PC3086: - f = romfopen("roms/pc3086/fc00.bin" ,"rb"); + f = romfopen(L"roms/pc3086/fc00.bin", L"rb"); if (!f) break; fread(rom, 0x4000, 1, f); fclose(f); - f = romfopen("roms/pc3086/c000.bin", "rb"); + f = romfopen(L"roms/pc3086/c000.bin", L"rb"); if (!f) break; fclose(f); - mem_load_xtide_bios(); biosmask = 0x3fff; return 1; case ROM_IBMAT: -/* f=romfopen("roms/AMIC206.BIN","rb"); - if (!f) break; - fread(rom,65536,1,f); - fclose(f); - return 1;*/ - case ROM_IBMAT386: - f = romfopen("roms/ibmat/62x0820.u27", "rb"); - ff =romfopen("roms/ibmat/62x0821.u47", "rb"); + f = romfopen(L"roms/ibmat/62x0820.u27", L"rb"); + ff =romfopen(L"roms/ibmat/62x0821.u47", L"rb"); if (!f || !ff) break; for (c=0x0000;c<0x10000;c+=2) { @@ -310,11 +309,10 @@ int loadbios() } fclose(ff); fclose(f); - mem_load_atide_bios(); return 1; case ROM_CMDPC30: - f = romfopen("roms/cmdpc30/commodore pc 30 iii even.bin", "rb"); - ff = romfopen("roms/cmdpc30/commodore pc 30 iii odd.bin", "rb"); + f = romfopen(L"roms/cmdpc30/commodore pc 30 iii even.bin", L"rb"); + ff = romfopen(L"roms/cmdpc30/commodore pc 30 iii odd.bin", L"rb"); if (!f || !ff) break; for (c = 0x0000; c < 0x8000; c += 2) { @@ -324,112 +322,85 @@ int loadbios() fclose(ff); fclose(f); biosmask = 0x7fff; - mem_load_atide_bios(); return 1; - case ROM_DELL200: - f=romfopen("roms/dells200/dell0.bin","rb"); - ff=romfopen("roms/dells200/dell1.bin","rb"); - if (!f || !ff) break; - for (c=0x0000;c<0x10000;c+=2) - { - rom[c]=getc(f); - rom[c+1]=getc(ff); - } - fclose(ff); - fclose(f); - return 1; -/* case ROM_IBMAT386: - f=romfopen("roms/at386/at386.bin","rb"); - if (!f) break; - fread(rom,65536,1,f); - fclose(f); - return 1;*/ case ROM_AMI386SX: -// f=romfopen("roms/at386/at386.bin","rb"); - f=romfopen("roms/ami386/ami386.bin","rb"); + f=romfopen(L"roms/ami386/ami386.bin",L"rb"); if (!f) break; fread(rom,65536,1,f); fclose(f); return 1; case ROM_AMI386DX_OPTI495: /*This uses the OPTi 82C495 chipset*/ - f=romfopen("roms/ami386dx/OPT495SX.AMI","rb"); + f=romfopen(L"roms/ami386dx/OPT495SX.AMI",L"rb"); if (!f) break; fread(rom,65536,1,f); fclose(f); return 1; case ROM_MR386DX_OPTI495: /*This uses the OPTi 82C495 chipset*/ - f=romfopen("roms/mr386dx/OPT495SX.MR","rb"); + f=romfopen(L"roms/mr386dx/OPT495SX.MR",L"rb"); if (!f) break; fread(rom,65536,1,f); fclose(f); return 1; - case ROM_ACER386: - f=romfopen("roms/acer386/acer386.bin","rb"); - if (!f) break; - fread(rom,65536,1,f); - fclose(f); - rom[0xB0]=0xB0-0x51; - rom[0x40d4]=0x51; /*PUSH CX*/ - f=romfopen("roms/acer386/oti067.bin","rb"); - if (!f) break; - fclose(f); - return 1; - case ROM_AMI286: - f=romfopen("roms/ami286/amic206.bin","rb"); + f=romfopen(L"roms/ami286/amic206.bin",L"rb"); if (!f) break; fread(rom,65536,1,f); fclose(f); -// memset(romext,0x63,0x8000); return 1; case ROM_AWARD286: - f=romfopen("roms/award286/award.bin","rb"); + f=romfopen(L"roms/award286/award.bin",L"rb"); if (!f) break; fread(rom,65536,1,f); fclose(f); return 1; - case ROM_EUROPC: -// return 0; - f=romfopen("roms/europc/50145","rb"); + case ROM_EUROPC: + f=romfopen(L"roms/europc/50145",L"rb"); if (!f) break; fread(rom+0x8000,32768,1,f); fclose(f); -// memset(romext,0x63,0x8000); - mem_load_xtide_bios(); return 1; case ROM_IBMPC: - f=romfopen("roms/ibmpc/pc102782.bin","rb"); + f=romfopen(L"roms/ibmpc/pc102782.bin",L"rb"); if (!f) break; -// f=fopen("pc081682.bin","rb"); fread(rom+0xE000,8192,1,f); fclose(f); - f=romfopen("roms/ibmpc/basicc11.f6","rb"); - if (!f) return 1; /*I don't really care if BASIC is there or not*/ - fread(rom+0x6000,8192,1,f); - fclose(f); - f=romfopen("roms/ibmpc/basicc11.f8","rb"); - if (!f) break; /*But if some of it is there, then all of it must be*/ - fread(rom+0x8000,8192,1,f); - fclose(f); - f=romfopen("roms/ibmpc/basicc11.fa","rb"); - if (!f) break; - fread(rom+0xA000,8192,1,f); - fclose(f); - f=romfopen("roms/ibmpc/basicc11.fc","rb"); - if (!f) break; - fread(rom+0xC000,8192,1,f); - fclose(f); - mem_load_xtide_bios(); + f=romfopen(L"roms/ibmpc/ibm-basic-1.10.rom",L"rb"); + if (!f) + { + f=romfopen(L"roms/ibmpc/basicc11.f6",L"rb"); + if (!f) return 1; /*I don't really care if BASIC is there or not*/ + fread(rom+0x6000,8192,1,f); + fclose(f); + f=romfopen(L"roms/ibmpc/basicc11.f8",L"rb"); + if (!f) break; /*But if some of it is there, then all of it must be*/ + fread(rom+0x8000,8192,1,f); + fclose(f); + f=romfopen(L"roms/ibmpc/basicc11.fa",L"rb"); + if (!f) break; + fread(rom+0xA000,8192,1,f); + fclose(f); + f=romfopen(L"roms/ibmpc/basicc11.fc",L"rb"); + if (!f) break; + fread(rom+0xC000,8192,1,f); + fclose(f); + } + else + { + fread(rom+0x6000,32768,1,f); + fclose(f); + } + return 1; case ROM_MEGAPC: - f = romfopen("roms/megapc/41651-bios lo.u18", "rb"); - ff = romfopen("roms/megapc/211253-bios hi.u19", "rb"); + case ROM_MEGAPCDX: + f = romfopen(L"roms/megapc/41651-bios lo.u18", L"rb"); + ff = romfopen(L"roms/megapc/211253-bios hi.u19", L"rb"); if (!f || !ff) break; fseek(f, 0x8000, SEEK_SET); fseek(ff, 0x8000, SEEK_SET); @@ -443,33 +414,21 @@ int loadbios() return 1; case ROM_AMI486: - f=romfopen("roms/ami486/ami486.BIN","rb"); + f=romfopen(L"roms/ami486/ami486.BIN",L"rb"); if (!f) break; fread(rom,65536,1,f); fclose(f); - //is486=1; return 1; case ROM_WIN486: -// f=romfopen("roms/win486/win486.bin","rb"); - f=romfopen("roms/win486/ALI1429G.AMW","rb"); + f=romfopen(L"roms/win486/ALI1429G.AMW",L"rb"); if (!f) break; fread(rom,65536,1,f); fclose(f); - //is486=1; - return 1; - - case ROM_PCI486: - f=romfopen("roms/hot-433/hot-433.ami","rb"); - if (!f) break; - fread(rom, 0x20000, 1, f); - fclose(f); - biosmask = 0x1ffff; - //is486=1; return 1; case ROM_SIS496: - f = romfopen("roms/sis496/SIS496-1.AWA", "rb"); + f = romfopen(L"roms/sis496/SIS496_3.AWA", L"rb"); if (!f) break; fread(rom, 0x20000, 1, f); fclose(f); @@ -477,85 +436,77 @@ int loadbios() pclog("Load SIS496 %x %x\n", rom[0x1fff0], rom[0xfff0]); return 1; +#if 0 case ROM_430VX: -// f = romfopen("roms/430vx/Ga586atv.bin", "rb"); -// f = fopen("roms/430vx/vx29.BIN", "rb"); - f = romfopen("roms/430vx/55XWUQ0E.BIN", "rb"); -// f=romfopen("roms/430vx/430vx","rb"); + f = romfopen(L"roms/430vx/55XWUQ0E.BIN", L"rb"); if (!f) break; fread(rom, 0x20000, 1, f); fclose(f); biosmask = 0x1ffff; - //is486=1; return 1; +#endif case ROM_REVENGE: - f = romfopen("roms/revenge/1009AF2_.BIO", "rb"); + f = romfopen(L"roms/revenge/1009AF2_.BIO", L"rb"); if (!f) break; fseek(f, 0x80, SEEK_SET); fread(rom + 0x10000, 0x10000, 1, f); fclose(f); - f = romfopen("roms/revenge/1009AF2_.BI1", "rb"); + f = romfopen(L"roms/revenge/1009AF2_.BI1", L"rb"); if (!f) break; fseek(f, 0x80, SEEK_SET); fread(rom, 0xc000, 1, f); fclose(f); biosmask = 0x1ffff; - //is486=1; return 1; case ROM_ENDEAVOR: - f = romfopen("roms/endeavor/1006CB0_.BIO", "rb"); + f = romfopen(L"roms/endeavor/1006CB0_.BIO", L"rb"); if (!f) break; fseek(f, 0x80, SEEK_SET); fread(rom + 0x10000, 0x10000, 1, f); fclose(f); - f = romfopen("roms/endeavor/1006CB0_.BI1", "rb"); + f = romfopen(L"roms/endeavor/1006CB0_.BI1", L"rb"); if (!f) break; fseek(f, 0x80, SEEK_SET); fread(rom, 0xd000, 1, f); fclose(f); biosmask = 0x1ffff; - //is486=1; return 1; case ROM_IBMPS1_2011: -#if 0 - f=romfopen("roms/ibmps1es/ibm_1057757_24-05-90.bin","rb"); - ff=romfopen("roms/ibmps1es/ibm_1057757_29-15-90.bin","rb"); - fseek(f, 0x10000, SEEK_SET); - fseek(ff, 0x10000, SEEK_SET); - if (!f || !ff) break; - for (c = 0x0000; c < 0x20000; c += 2) - { - rom[c] = getc(f); - rom[c+1] = getc(ff); - } - fclose(ff); - fclose(f); -#endif -//#if 0 - f = romfopen("roms/ibmps1es/f80000.bin", "rb"); + f = romfopen(L"roms/ibmps1es/f80000.bin", L"rb"); if (!f) break; fseek(f, 0x60000, SEEK_SET); fread(rom, 0x20000, 1, f); fclose(f); -//#endif biosmask = 0x1ffff; - mem_load_atide115_bios(); return 1; case ROM_IBMPS1_2121: - f = romfopen("roms/ibmps1_2121/fc0000.bin", "rb"); + case ROM_IBMPS1_2121_ISA: + f = romfopen(L"roms/ibmps1_2121/fc0000.bin", L"rb"); if (!f) break; fseek(f, 0x20000, SEEK_SET); fread(rom, 0x20000, 1, f); fclose(f); + if (enable_xtide) + { + mem_load_atide115_bios(); + } + biosmask = 0x1ffff; + return 1; + + case ROM_IBMPS1_2133: + f = romfopen(L"roms/ibmps1_2133/PS1_2133_52G2974_ROM.bin", L"rb"); + if (!f) break; + fread(rom, 0x20000, 1, f); + fclose(f); biosmask = 0x1ffff; return 1; case ROM_DESKPRO_386: - f=romfopen("roms/deskpro386/109592-005.U11.bin","rb"); - ff=romfopen("roms/deskpro386/109591-005.U13.bin","rb"); + f=romfopen(L"roms/deskpro386/109592-005.U11.bin",L"rb"); + ff=romfopen(L"roms/deskpro386/109591-005.U13.bin",L"rb"); if (!f || !ff) break; for (c = 0x0000; c < 0x8000; c += 2) { @@ -565,36 +516,303 @@ int loadbios() fclose(ff); fclose(f); biosmask = 0x7fff; - mem_load_atide_bios(); return 1; case ROM_AMIXT: - f = romfopen("roms/amixt/AMI_8088_BIOS_31JAN89.BIN", "rb"); + f = romfopen(L"roms/amixt/AMI_8088_BIOS_31JAN89.BIN", L"rb"); if (!f) break; fread(rom + 0xE000, 8192, 1, f); fclose(f); - mem_load_xtide_bios(); return 1; case ROM_LTXT: - f = romfopen("roms/ltxt/27C64.bin", "rb"); + f = romfopen(L"roms/ltxt/27C64.bin", L"rb"); if (!f) break; fread(rom + 0xE000, 8192, 1, f); fclose(f); - mem_load_xtide_bios(); + f=romfopen(L"roms/ltxt/ibm-basic-1.10.rom",L"rb"); + if (!f) + { + f=romfopen(L"roms/ltxt/basicc11.f6",L"rb"); + if (!f) return 1; /*I don't really care if BASIC is there or not*/ + fread(rom+0x6000,8192,1,f); + fclose(f); + f=romfopen(L"roms/ltxt/basicc11.f8",L"rb"); + if (!f) break; /*But if some of it is there, then all of it must be*/ + fread(rom+0x8000,8192,1,f); + fclose(f); + f=romfopen(L"roms/ltxt/basicc11.fa",L"rb"); + if (!f) break; + fread(rom+0xA000,8192,1,f); + fclose(f); + f=romfopen(L"roms/ltxt/basicc11.fc",L"rb"); + if (!f) break; + fread(rom+0xC000,8192,1,f); + fclose(f); + } + else + { + fread(rom+0x6000,32768,1,f); + fclose(f); + } + return 1; case ROM_LXT3: - f = romfopen("roms/lxt3/27C64D.bin", "rb"); + f = romfopen(L"roms/lxt3/27C64D.bin", L"rb"); if (!f) break; fread(rom + 0xE000, 8192, 1, f); fclose(f); - mem_load_xtide_bios(); + f=romfopen(L"roms/lxt3/ibm-basic-1.10.rom",L"rb"); + if (!f) + { + f=romfopen(L"roms/lxt3/basicc11.f6",L"rb"); + if (!f) return 1; /*I don't really care if BASIC is there or not*/ + fread(rom+0x6000,8192,1,f); + fclose(f); + f=romfopen(L"roms/lxt3/basicc11.f8",L"rb"); + if (!f) break; /*But if some of it is there, then all of it must be*/ + fread(rom+0x8000,8192,1,f); + fclose(f); + f=romfopen(L"roms/lxt3/basicc11.fa",L"rb"); + if (!f) break; + fread(rom+0xA000,8192,1,f); + fclose(f); + f=romfopen(L"roms/lxt3/basicc11.fc",L"rb"); + if (!f) break; + fread(rom+0xC000,8192,1,f); + fclose(f); + } + else + { + fread(rom+0x6000,32768,1,f); + fclose(f); + } + return 1; - case ROM_PX386: /*Phoenix 80386 BIOS*/ - f=romfopen("roms/px386/3iip001l.bin","rb"); - ff=romfopen("roms/px386/3iip001h.bin","rb"); + case ROM_SPC4200P: /*Samsung SPC-4200P*/ + f = romfopen(L"roms/spc4200p/U8.01", L"rb"); + if (!f) break; + fread(rom, 65536, 1, f); + fclose(f); + return 1; + + case ROM_SUPER286TR: /*Hyundai Super-286TR*/ + f = romfopen(L"roms/super286tr/hyundai_award286.bin", L"rb"); + if (!f) break; + fread(rom, 65536, 1, f); + fclose(f); + return 1; + + case ROM_DTK386: /*Uses NEAT chipset*/ + f = romfopen(L"roms/dtk386/3cto001.bin", L"rb"); + if (!f) break; + fread(rom, 65536, 1, f); + fclose(f); + return 1; + + case ROM_PXXT: + f = romfopen(L"roms/pxxt/000p001.bin", L"rb"); + if (!f) break; + fread(rom + 0xE000, 8192, 1, f); + fclose(f); + return 1; + + case ROM_JUKOPC: + f = romfopen(L"roms/jukopc/000o001.bin", L"rb"); + if (!f) break; + fread(rom + 0xE000, 8192, 1, f); + fclose(f); + return 1; + + case ROM_IBMPS2_M30_286: + f = romfopen(L"roms/ibmps2_m30_286/33f5381a.bin", L"rb"); + if (!f) break; + fread(rom, 0x20000, 1, f); + fclose(f); + if (enable_xtide) + { + mem_load_atide115_bios(); + } + biosmask = 0x1ffff; + return 1; + + case ROM_DTK486: + f = romfopen(L"roms/dtk486/4siw005.bin", L"rb"); + if (!f) break; + fread(rom, 0x10000, 1, f); + fclose(f); + return 1; + + case ROM_R418: + f = romfopen(L"roms/r418/r418i.bin", L"rb"); + if (!f) break; + fread(rom, 0x20000, 1, f); + fclose(f); + biosmask = 0x1ffff; + pclog("Load R418 %x %x\n", rom[0x1fff0], rom[0xfff0]); + return 1; + +#if 0 + case ROM_586MC1: + f = romfopen(L"roms/586mc1/IS.34", L"rb"); + if (!f) break; + fread(rom, 0x20000, 1, f); + fclose(f); + biosmask = 0x1ffff; + return 1; +#endif + + case ROM_PLATO: + f = romfopen(L"roms/plato/1016AX1_.BIO", L"rb"); + if (!f) break; + fseek(f, 0x80, SEEK_SET); + fread(rom + 0x10000, 0x10000, 1, f); + fclose(f); + f = romfopen(L"roms/plato/1016AX1_.BI1", L"rb"); + if (!f) break; + fseek(f, 0x80, SEEK_SET); + fread(rom, 0xd000, 1, f); + fclose(f); + biosmask = 0x1ffff; + return 1; + + case ROM_MB500N: + f = romfopen(L"roms/mb500n/031396S.BIN", L"rb"); /* Works */ + if (!f) break; + fread(rom, 0x20000, 1, f); + fclose(f); + biosmask = 0x1ffff; + return 1; + + case ROM_AP53: + f = romfopen(L"roms/ap53/AP53R2C0.ROM", L"rb"); /* Works */ + if (!f) break; + fread(rom, 0x20000, 1, f); + fclose(f); + biosmask = 0x1ffff; + return 1; + + case ROM_P55T2S: + f = romfopen(L"roms/p55t2s/S6Y08T.ROM", L"rb"); /* Works */ + if (!f) break; + fread(rom, 0x20000, 1, f); + fclose(f); + biosmask = 0x1ffff; + return 1; + + case ROM_PRESIDENT: + f = romfopen(L"roms/president/BIOS.BIN", L"rb"); + if (!f) break; + fread(rom, 0x20000, 1, f); + fclose(f); + biosmask = 0x1ffff; + return 1; + + case ROM_P54TP4XE: + f = romfopen(L"roms/p54tp4xe/T15I0302.AWD", L"rb"); + if (!f) break; + fread(rom, 0x20000, 1, f); + fclose(f); + biosmask = 0x1ffff; + return 1; + + case ROM_ACERM3A: + f = romfopen(L"roms/acerm3a/r01-b3.bin", L"rb"); + if (!f) break; + fread(rom, 0x20000, 1, f); + fclose(f); + biosmask = 0x1ffff; + return 1; + + case ROM_ACERV35N: + f = romfopen(L"roms/acerv35n/V35ND1S1.BIN", L"rb"); + if (!f) break; + fread(rom, 0x20000, 1, f); + fclose(f); + biosmask = 0x1ffff; + return 1; + + case ROM_P55VA: + f = romfopen(L"roms/p55va/VA021297.BIN", L"rb"); + if (!f) break; + fread(rom, 0x20000, 1, f); + fclose(f); + biosmask = 0x1ffff; + return 1; + + case ROM_P55T2P4: + f = romfopen(L"roms/p55t2p4/0207_J2.BIN", L"rb"); + if (!f) break; + fread(rom, 0x20000, 1, f); + fclose(f); + biosmask = 0x1ffff; + return 1; + + case ROM_P55TVP4: + f = romfopen(L"roms/p55tvp4/TV5I0204.AWD", L"rb"); + if (!f) break; + fread(rom, 0x20000, 1, f); + fclose(f); + biosmask = 0x1ffff; + return 1; + + case ROM_440FX: + f = romfopen(L"roms/440fx/NTMAW501.BIN", L"rb"); /* Working Tyan BIOS. */ + if (!f) break; + fread(rom, 0x20000, 1, f); + fclose(f); + biosmask = 0x1ffff; + return 1; + + case ROM_S1668: + f = romfopen(L"roms/tpatx/S1668P.ROM", L"rb"); /* Working Tyan BIOS. */ + if (!f) break; + fread(rom, 0x20000, 1, f); + fclose(f); + biosmask = 0x1ffff; + return 1; + + case ROM_THOR: + f = romfopen(L"roms/thor/1006CN0_.BIO", L"rb"); + if (!f) break; + fseek(f, 0x80, SEEK_SET); + fread(rom + 0x10000, 0x10000, 1, f); + fclose(f); + f = romfopen(L"roms/thor/1006CN0_.BI1", L"rb"); + if (!f) break; + fseek(f, 0x80, SEEK_SET); + fread(rom, 0x10000, 1, f); + fclose(f); + biosmask = 0x1ffff; + return 1; + + case ROM_MRTHOR: + f = romfopen(L"roms/mrthor/MR_ATX.BIO", L"rb"); + if (!f) break; + fread(rom, 0x20000, 1, f); + fclose(f); + biosmask = 0x1ffff; + return 1; + + case ROM_ZAPPA: + f = romfopen(L"roms/zappa/1006BS0_.BIO", L"rb"); + if (!f) break; + fseek(f, 0x80, SEEK_SET); + fread(rom + 0x10000, 0x10000, 1, f); + fclose(f); + f = romfopen(L"roms/zappa/1006BS0_.BI1", L"rb"); + if (!f) break; + fseek(f, 0x80, SEEK_SET); + fread(rom, 0x10000, 1, f); + fclose(f); + biosmask = 0x1ffff; + return 1; + + case ROM_IBMPS2_M50: + f=romfopen(L"roms/i8550021/90x7423.zm14",L"rb"); + ff=romfopen(L"roms/i8550021/90x7426.zm16",L"rb"); if (!f || !ff) break; for (c = 0x0000; c < 0x10000; c += 2) { @@ -603,180 +821,43 @@ int loadbios() } fclose(ff); fclose(f); - mem_load_atide_bios(); - return 1; - - case ROM_DTK386: /*Uses NEAT chipset*/ - f = romfopen("roms/dtk386/3cto001.bin", "rb"); - if (!f) break; - fread(rom, 65536, 1, f); - fclose(f); - mem_load_atide_bios(); - return 1; - - case ROM_PXXT: - f = romfopen("roms/pxxt/000p001.bin", "rb"); - if (!f) break; - fread(rom + 0xE000, 8192, 1, f); - fclose(f); - mem_load_xtide_bios(); - return 1; - - case ROM_JUKOPC: - f = romfopen("roms/jukopc/000o001.bin", "rb"); - if (!f) break; - fread(rom + 0xE000, 8192, 1, f); - fclose(f); - mem_load_xtide_bios(); - return 1; - - case ROM_DTK486: - f = romfopen("roms/dtk486/4siw005.bin", "rb"); - if (!f) break; - fread(rom, 0x10000, 1, f); - fclose(f); - return 1; - - case ROM_R418: - f = romfopen("roms/r418/r418i.bin", "rb"); - if (!f) break; - fread(rom, 0x20000, 1, f); - fclose(f); - biosmask = 0x1ffff; - pclog("Load R418 %x %x\n", rom[0x1fff0], rom[0xfff0]); - return 1; - - case ROM_586MC1: - f = romfopen("roms/586mc1/IS.34", "rb"); - if (!f) break; - fread(rom, 0x20000, 1, f); + f=romfopen(L"roms/i8550021/90x7420.zm13",L"rb"); + ff=romfopen(L"roms/i8550021/90x7429.zm18",L"rb"); + if (!f || !ff) break; + for (c = 0x10000; c < 0x20000; c += 2) + { + rom[c] = getc(f); + rom[c+1] = getc(ff); + } + fclose(ff); fclose(f); biosmask = 0x1ffff; return 1; - case ROM_PLATO: - f = romfopen("roms/plato/1016AX1_.BIO", "rb"); - if (!f) break; - fseek(f, 0x80, SEEK_SET); - fread(rom + 0x10000, 0x10000, 1, f); - fclose(f); - f = romfopen("roms/plato/1016AX1_.BI1", "rb"); - if (!f) break; - fseek(f, 0x80, SEEK_SET); - fread(rom, 0xd000, 1, f); - fclose(f); - biosmask = 0x1ffff; - //is486=1; - return 1; - - case ROM_MB500N: - f = romfopen("roms/mb500n/031396S.BIN", "rb"); /* Works */ - if (!f) break; - fread(rom, 0x20000, 1, f); + case ROM_IBMPS2_M55SX: + f=romfopen(L"roms/i8555081/33f8146.zm41",L"rb"); + ff=romfopen(L"roms/i8555081/33f8145.zm40",L"rb"); + if (!f || !ff) break; + for (c = 0x0000; c < 0x20000; c += 2) + { + rom[c] = getc(f); + rom[c+1] = getc(ff); + } + fclose(ff); fclose(f); biosmask = 0x1ffff; return 1; -#if 0 - case ROM_POWERMATE_V: - f = romfopen("roms/powermate_v/BIOS.ROM", "rb"); /* Works */ - if (!f) break; - fread(rom, 0x20000, 1, f); - fclose(f); - biosmask = 0x1ffff; - return 1; -#endif - - case ROM_P54TP4XE: - f = romfopen("roms/p54tp4xe/T15I0302.AWD", "rb"); - if (!f) break; - fread(rom, 0x20000, 1, f); - fclose(f); - biosmask = 0x1ffff; - return 1; - - case ROM_ACERM3A: - f = romfopen("roms/acerm3a/r01-b3.bin", "rb"); - if (!f) break; - fread(rom, 0x20000, 1, f); - fclose(f); - biosmask = 0x1ffff; - return 1; - - case ROM_ACERV35N: - f = romfopen("roms/acerv35n/V35ND1S1.BIN", "rb"); - if (!f) break; - fread(rom, 0x20000, 1, f); - fclose(f); - biosmask = 0x1ffff; - return 1; - - case ROM_P55VA: - f = romfopen("roms/p55va/VA021297.BIN", "rb"); - if (!f) break; - fread(rom, 0x20000, 1, f); - fclose(f); - biosmask = 0x1ffff; - return 1; - - case ROM_P55T2P4: - f = romfopen("roms/p55t2p4/0207_J2.BIN", "rb"); - if (!f) break; - fread(rom, 0x20000, 1, f); - fclose(f); - biosmask = 0x1ffff; - return 1; - - case ROM_P55TVP4: - f = romfopen("roms/p55tvp4/TV5I0204.AWD", "rb"); - if (!f) break; - fread(rom, 0x20000, 1, f); - fclose(f); - biosmask = 0x1ffff; - return 1; - - case ROM_440FX: - f = romfopen("roms/440fx/NTMAW501.BIN", "rb"); /* Working Tyan BIOS. */ - if (!f) break; - fread(rom, 0x20000, 1, f); - fclose(f); - biosmask = 0x1ffff; - return 1; - - case ROM_MARL: - f = romfopen("roms/marl/1008DB0_.BIO", "rb"); - if (!f) break; - fseek(f, 0x80, SEEK_SET); - fread(rom + 0x10000, 0x10000, 1, f); - fclose(f); - f = romfopen("roms/marl/1008DB0_.BI1", "rb"); - if (!f) break; - fseek(f, 0x80, SEEK_SET); - fread(rom, 0xd000, 1, f); - fclose(f); - biosmask = 0x1ffff; - //is486=1; - return 1; - - case ROM_THOR: - f = romfopen("roms/thor/1006CN0_.BIO", "rb"); - if (!f) break; - fseek(f, 0x80, SEEK_SET); - fread(rom + 0x10000, 0x10000, 1, f); - fclose(f); - f = romfopen("roms/thor/1006CN0_.BI1", "rb"); - if (!f) break; - fseek(f, 0x80, SEEK_SET); - fread(rom, 0x10000, 1, f); - fclose(f); - biosmask = 0x1ffff; - //is486=1; - return 1; - - case ROM_MRTHOR: - f = romfopen("roms/mrthor/MR_ATX.BIO", "rb"); - if (!f) break; - fread(rom, 0x20000, 1, f); + case ROM_IBMPS2_M80: + f=romfopen(L"roms/i8580111/15f6637.bin",L"rb"); + ff=romfopen(L"roms/i8580111/15f6639.bin",L"rb"); + if (!f || !ff) break; + for (c = 0x0000; c < 0x20000; c += 2) + { + rom[c] = getc(f); + rom[c+1] = getc(ff); + } + fclose(ff); fclose(f); biosmask = 0x1ffff; return 1; @@ -792,7 +873,6 @@ int loadbios() void resetreadlookup() { int c; -// /*if (output) */pclog("resetreadlookup\n"); memset(readlookup2,0xFF,1024*1024*sizeof(uintptr_t)); for (c=0;c<256;c++) readlookup[c]=0xFFFFFFFF; readlnext=0; @@ -801,8 +881,6 @@ void resetreadlookup() for (c=0;c<256;c++) writelookup[c]=0xFFFFFFFF; writelnext=0; pccache=0xFFFFFFFF; -// readlnum=writelnum=0; - } int mmuflush=0; @@ -811,12 +889,6 @@ int mmu_perm=4; void flushmmucache() { int c; -// /*if (output) */pclog("flushmmucache\n"); -/* for (c=0;c<16;c++) - { - if ( readlookup2[0xE0+c]!=0xFFFFFFFF) pclog("RL2 %02X = %08X\n",0xE0+c, readlookup2[0xE0+c]); - if (writelookup2[0xE0+c]!=0xFFFFFFFF) pclog("WL2 %02X = %08X\n",0xE0+c,writelookup2[0xE0+c]); - }*/ for (c=0;c<256;c++) { if (readlookup[c]!=0xFFFFFFFF) @@ -832,31 +904,9 @@ void flushmmucache() } } mmuflush++; -// readlnum=writelnum=0; pccache=(uint32_t)0xFFFFFFFF; pccache2=(uint8_t *)0xFFFFFFFF; -// memset(readlookup,0xFF,sizeof(readlookup)); -// memset(readlookup2,0xFF,1024*1024*4); -// memset(writelookup,0xFF,sizeof(writelookup)); -// memset(writelookup2,0xFF,1024*1024*4); -/* if (!(cr0>>31)) return;*/ - -/* for (c = 0; c < 1024*1024; c++) - { - if (readlookup2[c] != 0xFFFFFFFF) - { - pclog("Readlookup inconsistency - %05X %08X\n", c, readlookup2[c]); - dumpregs(); - exit(-1); - } - if (writelookup2[c] != 0xFFFFFFFF) - { - pclog("Readlookup inconsistency - %05X %08X\n", c, readlookup2[c]); - dumpregs(); - exit(-1); - } - }*/ codegen_flush(); } @@ -882,43 +932,26 @@ void flushmmucache_nopc() void flushmmucache_cr3() { int c; -// /*if (output) */pclog("flushmmucache_cr3\n"); for (c=0;c<256;c++) { - if (readlookup[c]!=0xFFFFFFFF)// && !readlookupp[c]) + if (readlookup[c]!=0xFFFFFFFF) { readlookup2[readlookup[c]] = -1; readlookup[c]=0xFFFFFFFF; } - if (writelookup[c] != 0xFFFFFFFF)// && !writelookupp[c]) + if (writelookup[c] != 0xFFFFFFFF) { page_lookup[writelookup[c]] = NULL; writelookup2[writelookup[c]] = -1; writelookup[c] = 0xFFFFFFFF; } } -/* for (c = 0; c < 1024*1024; c++) - { - if (readlookup2[c] != 0xFFFFFFFF) - { - pclog("Readlookup inconsistency - %05X %08X\n", c, readlookup2[c]); - dumpregs(); - exit(-1); - } - if (writelookup2[c] != 0xFFFFFFFF) - { - pclog("Readlookup inconsistency - %05X %08X\n", c, readlookup2[c]); - dumpregs(); - exit(-1); - } - }*/ } void mem_flush_write_page(uint32_t addr, uint32_t virt) { int c; page_t *page_target = &pages[addr >> 12]; -// pclog("mem_flush_write_page %08x %08x\n", virt, addr); for (c = 0; c < 256; c++) { @@ -926,11 +959,8 @@ void mem_flush_write_page(uint32_t addr, uint32_t virt) { uintptr_t target = (uintptr_t)&ram[(uintptr_t)(addr & ~0xfff) - (virt & ~0xfff)]; -// if ((virt & ~0xfff) == 0xc022e000) -// pclog(" Checking %02x %p %p\n", (void *)writelookup2[writelookup[c]], (void *)target); if (writelookup2[writelookup[c]] == target || page_lookup[writelookup[c]] == page_target) { -// pclog(" throw out %02x %p %p\n", writelookup[c], (void *)page_lookup[writelookup[c]], (void *)writelookup2[writelookup[c]]); writelookup2[writelookup[c]] = -1; page_lookup[writelookup[c]] = NULL; writelookup[c] = 0xffffffff; @@ -948,118 +978,135 @@ int pctrans=0; extern uint32_t testr[9]; +int mem_cpl3_check() +{ + if ((CPL == 3) && !cpl_override) + { + return 1; + } + return 0; +} + +void mmu_page_fault(uint32_t addr, uint32_t error_code) +{ + cr2 = addr; + cpu_state.abrt = ABRT_PF; + abrt_error = error_code; +} + +int mmu_page_fault_check(uint32_t addr, int rw, uint32_t flags, int pde, int is_abrt) +{ + uint8_t error_code = 0; + + uint8_t is_page_fault = 0; + + if (mem_cpl3_check()) error_code = 4; /* If CPL = 3 and it's not a PDE check, set US bit. */ + if (rw) error_code |= 2; /* If writing and it's not a PDE check, set RW bit. */ + + if (!(flags & 1)) + { + is_page_fault = 1; + } + + if (!pde) + { + if (!(flags & 4) && mem_cpl3_check()) + { + is_page_fault = 1; + } + if (rw && !(flags & 2) && (mem_cpl3_check() || (cr0 & WP_FLAG))) + { + is_page_fault = 1; + } + } + + if (is_page_fault) + { + if (is_abrt) + { + mmu_page_fault(addr, error_code | (flags & 1)); + } + return -1; + } + + return 0; +} + +#define PAGE_DIRTY_AND_ACCESSED 0x60 +#define PAGE_DIRTY 0x40 +#define PAGE_ACCESSED 0x20 + +/* rw means 0 = read, 1 = write */ +uint32_t mmutranslate(uint32_t addr, int rw, int is_abrt) +{ + /* Mask out the lower 12 bits. */ + uint32_t dir_base = 0; + + uint32_t table_addr = 0; + uint32_t page_addr = 0; + + uint32_t table_flags = 0; + uint32_t page_flags = 0; + + if (cpu_state.abrt) + { + return -1; + } + + dir_base = cr3 & ~0xfff; + table_addr = dir_base + ((addr >> 20) & 0xffc); + + /* First check the flags of the page directory entry. */ + table_flags = ((uint32_t *)ram)[table_addr >> 2]; + + if (mmu_page_fault_check(addr, rw, table_flags & 7, 1, is_abrt) == -1) + { + return -1; + } + + page_addr = table_flags & ~0xfff; + page_addr += ((addr >> 10) & 0xffc); + + /* Then check the flags of the page table entry. */ + page_flags = ((uint32_t *)ram)[page_addr >> 2]; + + if (mmu_page_fault_check(addr, rw, page_flags & 7, 0, is_abrt) == -1) + { + return -1; + } + + if (is_abrt) + { + mmu_perm = page_flags & 4; + ((uint32_t *)ram)[table_addr >> 2] |= PAGE_ACCESSED; + ((uint32_t *)ram)[page_addr >> 2] |= (rw ? PAGE_DIRTY_AND_ACCESSED : PAGE_ACCESSED); + } + + return (page_flags & ~0xFFF) + (addr & 0xFFF); +} + uint32_t mmutranslatereal(uint32_t addr, int rw) { - uint32_t addr2; - uint32_t temp,temp2,temp3; - - if (cpu_state.abrt) - { -// pclog("Translate recursive abort\n"); - return -1; - } -/* if ((addr&~0xFFFFF)==0x77f00000) pclog("Do translate %08X %i %08X %08X\n",addr,rw,EAX,cpu_state.pc); - if (addr==0x77f61000) output = 3; - if (addr==0x77f62000) { dumpregs(); exit(-1); } - if (addr==0x77f9a000) { dumpregs(); exit(-1); }*/ - addr2 = ((cr3 & ~0xfff) + ((addr >> 20) & 0xffc)); - temp=temp2=((uint32_t *)ram)[addr2>>2]; -// if (output == 3) pclog("Do translate %08X %i %08X\n", addr, rw, temp); - if (!(temp&1))// || (CPL==3 && !(temp&4) && !cpl_override) || (rw && !(temp&2) && (CPL==3 || cr0&WP_FLAG))) - { -// if (!nopageerrors) pclog("Section not present! %08X %08X %02X %04X:%08X %i %i\n",addr,temp,opcode,CS,cpu_state.pc,CPL,rw); - - cr2=addr; - temp&=1; - if (CPL==3) temp|=4; - if (rw) temp|=2; - cpu_state.abrt = ABRT_PF; - abrt_error = temp; -/* if (addr == 0x70046D) - { - dumpregs(); - exit(-1); - }*/ - return -1; - } - temp=((uint32_t *)ram)[((temp&~0xFFF)+((addr>>10)&0xFFC))>>2]; - temp3=temp&temp2; -// if (output == 3) pclog("Do translate %08X %08X\n", temp, temp3); - if (!(temp&1) || (CPL==3 && !(temp3&4) && !cpl_override) || (rw && !(temp3&2) && (CPL==3 || cr0&WP_FLAG))) - { -// if (!nopageerrors) pclog("Page not present! %08X %08X %02X %02X %i %08X %04X:%08X %04X:%08X %i %i %i\n",addr,temp,opcode,opcode2,frame,rmdat32, CS,cpu_state.pc,SS,ESP,ins,CPL,rw); - -// dumpregs(); -// exit(-1); -// if (addr == 0x815F6E90) output = 3; -/* if (addr == 0x10ADE020) output = 3;*/ -/* if (addr == 0x10150010 && !nopageerrors) - { - dumpregs(); - exit(-1); - }*/ - - cr2=addr; - temp&=1; - if (CPL==3) temp|=4; - if (rw) temp|=2; - cpu_state.abrt = ABRT_PF; - abrt_error = temp; -// pclog("%04X\n",cpu_state.abrt); - return -1; - } - mmu_perm=temp&4; - ((uint32_t *)ram)[addr2>>2]|=0x20; - ((uint32_t *)ram)[((temp2&~0xFFF)+((addr>>10)&0xFFC))>>2]|=(rw?0x60:0x20); -// /*if (output) */pclog("Translate %08X %08X %08X %08X:%08X %08X\n",addr,(temp&~0xFFF)+(addr&0xFFF),temp,cs,cpu_state.pc,EDI); - - return (temp&~0xFFF)+(addr&0xFFF); + return mmutranslate(addr, rw, 1); } uint32_t mmutranslate_noabrt(uint32_t addr, int rw) { - uint32_t addr2; - uint32_t temp,temp2,temp3; - - if (cpu_state.abrt) - return -1; - - addr2 = ((cr3 & ~0xfff) + ((addr >> 20) & 0xffc)); - temp=temp2=((uint32_t *)ram)[addr2>>2]; - - if (!(temp&1)) - return -1; - - temp=((uint32_t *)ram)[((temp&~0xFFF)+((addr>>10)&0xFFC))>>2]; - temp3=temp&temp2; - - if (!(temp&1) || (CPL==3 && !(temp3&4) && !cpl_override) || (rw && !(temp3&2) && (CPL==3 || cr0&WP_FLAG))) - return -1; - - return (temp&~0xFFF)+(addr&0xFFF); + return mmutranslate(addr, rw, 0); } void mmu_invalidate(uint32_t addr) { -// readlookup2[addr >> 12] = writelookup2[addr >> 12] = 0xFFFFFFFF; flushmmucache_cr3(); } void addreadlookup(uint32_t virt, uint32_t phys) { -// return; -// printf("Addreadlookup %08X %08X %08X %08X %08X %08X %02X %08X\n",virt,phys,cs,ds,es,ss,opcode,cpu_state.pc); if (virt == 0xffffffff) return; if (readlookup2[virt>>12] != -1) { -/* if (readlookup2[virt>>12] != phys&~0xfff) - { - pclog("addreadlookup mismatch - %05X000 %05X000\n", readlookup[readlnext], virt >> 12); - dumpregs(); - exit(-1); - }*/ return; } @@ -1067,7 +1114,6 @@ void addreadlookup(uint32_t virt, uint32_t phys) if (readlookup[readlnext]!=0xFFFFFFFF) { readlookup2[readlookup[readlnext]] = -1; -// readlnum--; } readlookup2[virt>>12] = (uintptr_t)&ram[(uintptr_t)(phys & ~0xFFF) - (uintptr_t)(virt & ~0xfff)]; readlookupp[readlnext]=mmu_perm; @@ -1079,19 +1125,11 @@ void addreadlookup(uint32_t virt, uint32_t phys) void addwritelookup(uint32_t virt, uint32_t phys) { -// return; -// printf("Addwritelookup %08X %08X\n",virt,phys); if (virt == 0xffffffff) return; if (page_lookup[virt >> 12]) { -/* if (writelookup2[virt>>12] != phys&~0xfff) - { - pclog("addwritelookup mismatch - %05X000 %05X000\n", readlookup[readlnext], virt >> 12); - dumpregs(); - exit(-1); - }*/ return; } @@ -1099,16 +1137,12 @@ void addwritelookup(uint32_t virt, uint32_t phys) { page_lookup[writelookup[writelnext]] = NULL; writelookup2[writelookup[writelnext]] = -1; -// writelnum--; } -// if (page_lookup[virt >> 12] && (writelookup2[virt>>12] != 0xffffffff)) -// fatal("Bad write mapping\n"); - if (pages[phys >> 12].block || (phys & ~0xfff) == recomp_page) - page_lookup[virt >> 12] = &pages[phys >> 12];//(uintptr_t)&ram[(uintptr_t)(phys & ~0xFFF) - (uintptr_t)(virt & ~0xfff)]; + if (pages[phys >> 12].block[0] || pages[phys >> 12].block[1] || pages[phys >> 12].block[2] || pages[phys >> 12].block[3] || (phys & ~0xfff) == recomp_page) + page_lookup[virt >> 12] = &pages[phys >> 12]; else writelookup2[virt>>12] = (uintptr_t)&ram[(uintptr_t)(phys & ~0xFFF) - (uintptr_t)(virt & ~0xfff)]; -// pclog("addwritelookup %08x %08x %p %p %016llx %p\n", virt, phys, (void *)page_lookup[virt >> 12], (void *)writelookup2[virt >> 12], pages[phys >> 12].dirty_mask, (void *)&pages[phys >> 12]); writelookupp[writelnext] = mmu_perm; writelookup[writelnext++] = virt >> 12; writelnext &= (cachesize - 1); @@ -1121,6 +1155,12 @@ uint8_t *getpccache(uint32_t a) { uint32_t a2=a; + if (a2 < 0x100000 && ram_mapped_addr[a2 >> 14]) + { + a = (ram_mapped_addr[a2 >> 14] & MEM_MAP_TO_SHADOW_RAM_MASK) ? a2 : (ram_mapped_addr[a2 >> 14] & ~0x3FFF) + (a2 & 0x3FFF); + return &ram[(uintptr_t)(a & 0xFFFFF000) - (uintptr_t)(a2 & ~0xFFF)]; + } + if (cr0>>31) { pctrans=1; @@ -1152,6 +1192,12 @@ uint32_t mem_logical_addr; uint8_t readmembl(uint32_t addr) { mem_logical_addr = addr; + if (addr < 0x100000 && ram_mapped_addr[addr >> 14]) + { + addr = (ram_mapped_addr[addr >> 14] & MEM_MAP_TO_SHADOW_RAM_MASK) ? addr : (ram_mapped_addr[addr >> 14] & ~0x3FFF) + (addr & 0x3FFF); + if(addr < mem_size * 1024) return ram[addr]; + return 0xFF; + } if (cr0 >> 31) { addr = mmutranslate_read(addr); @@ -1160,7 +1206,6 @@ uint8_t readmembl(uint32_t addr) addr &= rammask; if (_mem_read_b[addr >> 14]) return _mem_read_b[addr >> 14](addr, _mem_priv_r[addr >> 14]); -// pclog("Bad readmembl %08X %04X:%08X\n", addr, CS, pc); return 0xFF; } @@ -1168,6 +1213,12 @@ void writemembl(uint32_t addr, uint8_t val) { mem_logical_addr = addr; + if (addr < 0x100000 && ram_mapped_addr[addr >> 14]) + { + addr = (ram_mapped_addr[addr >> 14] & MEM_MAP_TO_SHADOW_RAM_MASK) ? addr : (ram_mapped_addr[addr >> 14] & ~0x3FFF) + (addr & 0x3FFF); + if(addr < mem_size * 1024) ram[addr] = val; + return; + } if (page_lookup[addr>>12]) { page_lookup[addr>>12]->write_b(addr, val, page_lookup[addr>>12]); @@ -1181,7 +1232,6 @@ void writemembl(uint32_t addr, uint8_t val) addr &= rammask; if (_mem_write_b[addr >> 14]) _mem_write_b[addr >> 14](addr, val, _mem_priv_w[addr >> 14]); -// else pclog("Bad writemembl %08X %02X %04X:%08X\n", addr, val, CS, pc); } uint8_t readmemb386l(uint32_t seg, uint32_t addr) @@ -1189,14 +1239,15 @@ uint8_t readmemb386l(uint32_t seg, uint32_t addr) if (seg==-1) { x86gpf("NULL segment", 0); - // printf("NULL segment! rb %04X(%08X):%08X %02X %08X\n",CS,cs,cpu_state.pc,opcode,addr); return -1; } mem_logical_addr = addr = addr + seg; -/* if (readlookup2[mem_logical_addr >> 12] != 0xFFFFFFFF) + if (addr < 0x100000 && ram_mapped_addr[addr >> 14]) { - return ram[readlookup2[mem_logical_addr >> 12] + (mem_logical_addr & 0xFFF)]; - }*/ + addr = (ram_mapped_addr[addr >> 14] & MEM_MAP_TO_SHADOW_RAM_MASK) ? addr : (ram_mapped_addr[addr >> 14] & ~0x3FFF) + (addr & 0x3FFF); + if(addr < mem_size * 1024) return ram[addr]; + return 0xFF; + } if (cr0 >> 31) { @@ -1207,7 +1258,6 @@ uint8_t readmemb386l(uint32_t seg, uint32_t addr) addr &= rammask; if (_mem_read_b[addr >> 14]) return _mem_read_b[addr >> 14](addr, _mem_priv_r[addr >> 14]); -// pclog("Bad readmemb386l %08X %04X:%08X\n", addr, CS, pc); return 0xFF; } @@ -1216,11 +1266,16 @@ void writememb386l(uint32_t seg, uint32_t addr, uint8_t val) if (seg==-1) { x86gpf("NULL segment", 0); - // printf("NULL segment! wb %04X(%08X):%08X %02X %08X\n",CS,cs,cpu_state.pc,opcode,addr); return; } mem_logical_addr = addr = addr + seg; + if (addr < 0x100000 && ram_mapped_addr[addr >> 14]) + { + addr = (ram_mapped_addr[addr >> 14] & MEM_MAP_TO_SHADOW_RAM_MASK) ? addr : (ram_mapped_addr[addr >> 14] & ~0x3FFF) + (addr & 0x3FFF); + if(addr < mem_size * 1024) ram[addr] = val; + return; + } if (page_lookup[addr>>12]) { page_lookup[addr>>12]->write_b(addr, val, page_lookup[addr>>12]); @@ -1234,32 +1289,41 @@ void writememb386l(uint32_t seg, uint32_t addr, uint8_t val) addr &= rammask; -/* if (addr >= 0xa0000 && addr < 0xc0000) - pclog("writemembl %08X %02X\n", addr, val);*/ - if (_mem_write_b[addr >> 14]) _mem_write_b[addr >> 14](addr, val, _mem_priv_w[addr >> 14]); -// else pclog("Bad writememb386l %08X %02X %04X:%08X\n", addr, val, CS, pc); } uint16_t readmemwl(uint32_t seg, uint32_t addr) { uint32_t addr2 = mem_logical_addr = seg + addr; - if ((addr2&0xFFF)>0xFFE) - { - if (cr0>>31) - { - if (mmutranslate_read(addr2) == 0xffffffff) return 0xffff; - if (mmutranslate_read(addr2+1) == 0xffffffff) return 0xffff; - } - if (is386) return readmemb386l(seg,addr)|(readmemb386l(seg,addr+1)<<8); - else return readmembl(seg+addr)|(readmembl(seg+addr+1)<<8); - } + if (seg==-1) { x86gpf("NULL segment", 0); - // printf("NULL segment! rw %04X(%08X):%08X %02X %08X\n",CS,cs,cpu_state.pc,opcode,addr); return -1; } + if (addr2 & 1) + { + if (!cpu_cyrix_alignment || (addr2 & 7) == 7) + cycles -= timing_misaligned; + if ((addr2 & 0xFFF) > 0xFFE) + { + if (cr0 >> 31) + { + if (mmutranslate_read(addr2) == 0xffffffff) return 0xffff; + if (mmutranslate_read(addr2+1) == 0xffffffff) return 0xffff; + } + if (is386) return readmemb386l(seg,addr)|(readmemb386l(seg,addr+1)<<8); + else return readmembl(seg+addr)|(readmembl(seg+addr+1)<<8); + } + else if (readlookup2[addr2 >> 12] != -1) + return *(uint16_t *)(readlookup2[addr2 >> 12] + addr2); + } + if (addr2 < 0x100000 && ram_mapped_addr[addr2 >> 14]) + { + addr = (ram_mapped_addr[addr2 >> 14] & MEM_MAP_TO_SHADOW_RAM_MASK) ? addr2 : (ram_mapped_addr[addr2 >> 14] & ~0x3FFF) + (addr2 & 0x3FFF); + if(addr < mem_size * 1024) return *((uint16_t *)&ram[addr]); + return 0xFFFF; + } if (cr0>>31) { addr2 = mmutranslate_read(addr2); @@ -1275,39 +1339,55 @@ uint16_t readmemwl(uint32_t seg, uint32_t addr) if (AT) return _mem_read_b[addr2 >> 14](addr2, _mem_priv_r[addr2 >> 14]) | (_mem_read_b[(addr2 + 1) >> 14](addr2 + 1, _mem_priv_r[addr2 >> 14]) << 8); else return _mem_read_b[addr2 >> 14](addr2, _mem_priv_r[addr2 >> 14]) | (_mem_read_b[(seg + ((addr + 1) & 0xffff)) >> 14](seg + ((addr + 1) & 0xffff), _mem_priv_r[addr2 >> 14]) << 8); } -// pclog("Bad readmemwl %08X\n", addr2); return 0xffff; } void writememwl(uint32_t seg, uint32_t addr, uint16_t val) { uint32_t addr2 = mem_logical_addr = seg + addr; - if ((addr2&0xFFF)>0xFFE) - { - if (cr0>>31) - { - if (mmutranslate_write(addr2) == 0xffffffff) return; - if (mmutranslate_write(addr2+1) == 0xffffffff) return; - } - if (is386) - { - writememb386l(seg,addr,val); - writememb386l(seg,addr+1,val>>8); - } - else - { - writemembl(seg+addr,val); - writemembl(seg+addr+1,val>>8); - } - return; - } if (seg==-1) { x86gpf("NULL segment", 0); - // printf("NULL segment! ww %04X(%08X):%08X %02X %08X\n",CS,cs,cpu_state.pc,opcode,addr); return; } + if (addr2 < 0x100000 && ram_mapped_addr[addr2 >> 14]) + { + addr = (ram_mapped_addr[addr2 >> 14] & MEM_MAP_TO_SHADOW_RAM_MASK) ? addr2 : (ram_mapped_addr[addr2 >> 14] & ~0x3FFF) + (addr2 & 0x3FFF); + if(addr < mem_size * 1024) *((uint16_t *)&ram[addr]) = val; + return; + } + + if (addr2 & 1) + { + if (!cpu_cyrix_alignment || (addr2 & 7) == 7) + cycles -= timing_misaligned; + if ((addr2 & 0xFFF) > 0xFFE) + { + if (cr0 >> 31) + { + if (mmutranslate_write(addr2) == 0xffffffff) return; + if (mmutranslate_write(addr2+1) == 0xffffffff) return; + } + if (is386) + { + writememb386l(seg,addr,val); + writememb386l(seg,addr+1,val>>8); + } + else + { + writemembl(seg+addr,val); + writemembl(seg+addr+1,val>>8); + } + return; + } + else if (writelookup2[addr2 >> 12] != -1) + { + *(uint16_t *)(writelookup2[addr2 >> 12] + addr2) = val; + return; + } + } + if (page_lookup[addr2>>12]) { page_lookup[addr2>>12]->write_w(addr2, val, page_lookup[addr2>>12]); @@ -1336,29 +1416,42 @@ void writememwl(uint32_t seg, uint32_t addr, uint16_t val) _mem_write_b[(addr2 + 1) >> 14](addr2 + 1, val >> 8, _mem_priv_w[addr2 >> 14]); return; } -// pclog("Bad writememwl %08X %04X\n", addr2, val); } uint32_t readmemll(uint32_t seg, uint32_t addr) { uint32_t addr2 = mem_logical_addr = seg + addr; - if ((addr2&0xFFF)>0xFFC) - { - if (cr0>>31) - { - if (mmutranslate_read(addr2) == 0xffffffff) return 0xffffffff; - if (mmutranslate_read(addr2+3) == 0xffffffff) return 0xffffffff; - } - return readmemwl(seg,addr)|(readmemwl(seg,addr+2)<<16); - } if (seg==-1) { x86gpf("NULL segment", 0); - // printf("NULL segment! rl %04X(%08X):%08X %02X %08X\n",CS,cs,cpu_state.pc,opcode,addr); return -1; } + if (addr2 < 0x100000 && ram_mapped_addr[addr2 >> 14]) + { + addr = (ram_mapped_addr[addr2 >> 14] & MEM_MAP_TO_SHADOW_RAM_MASK) ? addr2 : (ram_mapped_addr[addr2 >> 14] & ~0x3FFF) + (addr2 & 0x3FFF); + if(addr < mem_size * 1024) return *((uint32_t *)&ram[addr]); + return 0xFFFFFFFF; + } + + if (addr2 & 3) + { + if (!cpu_cyrix_alignment || (addr2 & 7) > 4) + cycles -= timing_misaligned; + if ((addr2&0xFFF)>0xFFC) + { + if (cr0>>31) + { + if (mmutranslate_read(addr2) == 0xffffffff) return 0xffffffff; + if (mmutranslate_read(addr2+3) == 0xffffffff) return 0xffffffff; + } + return readmemwl(seg,addr)|(readmemwl(seg,addr+2)<<16); + } + else if (readlookup2[addr2 >> 12] != -1) + return *(uint32_t *)(readlookup2[addr2 >> 12] + addr2); + } + if (cr0>>31) { addr2 = mmutranslate_read(addr2); @@ -1373,7 +1466,6 @@ uint32_t readmemll(uint32_t seg, uint32_t addr) if (_mem_read_b[addr2 >> 14]) return _mem_read_b[addr2 >> 14](addr2, _mem_priv_r[addr2 >> 14]) | (_mem_read_b[addr2 >> 14](addr2 + 1, _mem_priv_r[addr2 >> 14]) << 8) | (_mem_read_b[addr2 >> 14](addr2 + 2, _mem_priv_r[addr2 >> 14]) << 16) | (_mem_read_b[addr2 >> 14](addr2 + 3, _mem_priv_r[addr2 >> 14]) << 24); -// pclog("Bad readmemll %08X\n", addr2); return 0xffffffff; } @@ -1381,23 +1473,38 @@ void writememll(uint32_t seg, uint32_t addr, uint32_t val) { uint32_t addr2 = mem_logical_addr = seg + addr; - if ((addr2&0xFFF)>0xFFC) - { - if (cr0>>31) - { - if (mmutranslate_write(addr2) == 0xffffffff) return; - if (mmutranslate_write(addr2+3) == 0xffffffff) return; - } - writememwl(seg,addr,val); - writememwl(seg,addr+2,val>>16); - return; - } if (seg==-1) { x86gpf("NULL segment", 0); - // printf("NULL segment! wl %04X(%08X):%08X %02X %08X\n",CS,cs,cpu_state.pc,opcode,addr); return; } + if (addr2 < 0x100000 && ram_mapped_addr[addr2 >> 14]) + { + addr = (ram_mapped_addr[addr2 >> 14] & MEM_MAP_TO_SHADOW_RAM_MASK) ? addr2 : (ram_mapped_addr[addr2 >> 14] & ~0x3FFF) + (addr2 & 0x3FFF); + if(addr < mem_size * 1024) *((uint32_t *)&ram[addr]) = val; + return; + } + if (addr2 & 3) + { + if (!cpu_cyrix_alignment || (addr2 & 7) > 4) + cycles -= timing_misaligned; + if ((addr2 & 0xFFF) > 0xFFC) + { + if (cr0>>31) + { + if (mmutranslate_write(addr2) == 0xffffffff) return; + if (mmutranslate_write(addr2+3) == 0xffffffff) return; + } + writememwl(seg,addr,val); + writememwl(seg,addr+2,val>>16); + return; + } + else if (writelookup2[addr2 >> 12] != -1) + { + *(uint32_t *)(writelookup2[addr2 >> 12] + addr2) = val; + return; + } + } if (page_lookup[addr2>>12]) { page_lookup[addr2>>12]->write_l(addr2, val, page_lookup[addr2>>12]); @@ -1411,9 +1518,6 @@ void writememll(uint32_t seg, uint32_t addr, uint32_t val) addr2&=rammask; -/* if (addr >= 0xa0000 && addr < 0xc0000) - pclog("writememll %08X %08X\n", addr, val);*/ - if (_mem_write_l[addr2 >> 14]) { _mem_write_l[addr2 >> 14](addr2, val, _mem_priv_w[addr2 >> 14]); @@ -1433,33 +1537,45 @@ void writememll(uint32_t seg, uint32_t addr, uint32_t val) _mem_write_b[addr2 >> 14](addr2 + 3, val >> 24, _mem_priv_w[addr2 >> 14]); return; } -// pclog("Bad writememll %08X %08X\n", addr2, val); } uint64_t readmemql(uint32_t seg, uint32_t addr) { uint32_t addr2 = mem_logical_addr = seg + addr; - if ((addr2&0xFFF)>0xFF8) - { - if (cr0>>31) - { - if (mmutranslate_read(addr2) == 0xffffffff) return 0xffffffff; - if (mmutranslate_read(addr2+7) == 0xffffffff) return 0xffffffff; - } - return readmemll(seg,addr)|((uint64_t)readmemll(seg,addr+4)<<32); - } if (seg==-1) { x86gpf("NULL segment", 0); - // printf("NULL segment! rl %04X(%08X):%08X %02X %08X\n",CS,cs,cpu_state.pc,opcode,addr); return -1; } + if (addr2 < 0x100000 && ram_mapped_addr[addr2 >> 14]) + { + addr = (ram_mapped_addr[addr2 >> 14] & MEM_MAP_TO_SHADOW_RAM_MASK) ? addr2 : (ram_mapped_addr[addr2 >> 14] & ~0x3FFF) + (addr2 & 0x3FFF); + if(addr < mem_size * 1024) return *((uint64_t *)&ram[addr]); + return -1; + } + + if (addr2 & 7) + { + cycles -= timing_misaligned; + if ((addr2 & 0xFFF) > 0xFF8) + { + if (cr0>>31) + { + if (mmutranslate_read(addr2) == 0xffffffff) return 0xffffffff; + if (mmutranslate_read(addr2+7) == 0xffffffff) return 0xffffffff; + } + return readmemll(seg,addr)|((uint64_t)readmemll(seg,addr+4)<<32); + } + else if (readlookup2[addr2 >> 12] != -1) + return *(uint64_t *)(readlookup2[addr2 >> 12] + addr2); + } + if (cr0>>31) { addr2 = mmutranslate_read(addr2); - if (addr2==0xFFFFFFFF) return 0xFFFFFFFF; + if (addr2==0xFFFFFFFF) return -1; } addr2&=rammask; @@ -1475,23 +1591,37 @@ void writememql(uint32_t seg, uint32_t addr, uint64_t val) { uint32_t addr2 = mem_logical_addr = seg + addr; - if ((addr2 & 0xFFF) > 0xFF8) - { - if (cr0>>31) - { - if (mmutranslate_write(addr2) == 0xffffffff) return; - if (mmutranslate_write(addr2+7) == 0xffffffff) return; - } - writememll(seg, addr, val); - writememll(seg, addr+4, val >> 32); - return; - } if (seg==-1) { x86gpf("NULL segment", 0); - // printf("NULL segment! wl %04X(%08X):%08X %02X %08X\n",CS,cs,cpu_state.pc,opcode,addr); return; } + if (addr2 < 0x100000 && ram_mapped_addr[addr2 >> 14]) + { + addr = (ram_mapped_addr[addr2 >> 14] & MEM_MAP_TO_SHADOW_RAM_MASK) ? addr2 : (ram_mapped_addr[addr2 >> 14] & ~0x3FFF) + (addr2 & 0x3FFF); + if(addr < mem_size * 1024) *((uint64_t *)&ram[addr]) = val; + return; + } + if (addr2 & 7) + { + cycles -= timing_misaligned; + if ((addr2 & 0xFFF) > 0xFF8) + { + if (cr0>>31) + { + if (mmutranslate_write(addr2) == 0xffffffff) return; + if (mmutranslate_write(addr2+7) == 0xffffffff) return; + } + writememll(seg, addr, val); + writememll(seg, addr+4, val >> 32); + return; + } + else if (writelookup2[addr2 >> 12] != -1) + { + *(uint64_t *)(writelookup2[addr2 >> 12] + addr2) = val; + return; + } + } if (page_lookup[addr2>>12]) { page_lookup[addr2>>12]->write_l(addr2, val, page_lookup[addr2>>12]); @@ -1532,7 +1662,6 @@ void writememql(uint32_t seg, uint32_t addr, uint64_t val) _mem_write_b[addr2 >> 14](addr2 + 7, val >> 56, _mem_priv_w[addr2 >> 14]); return; } -// pclog("Bad writememql %08X %08X\n", addr2, val); } uint8_t mem_readb_phys(uint32_t addr) @@ -1573,19 +1702,16 @@ void mem_writew_phys(uint32_t addr, uint16_t val) uint8_t mem_read_ram(uint32_t addr, void *priv) { -// if (addr >= 0xc0000 && addr < 0x0c8000) pclog("Read RAMb %08X\n", addr); addreadlookup(mem_logical_addr, addr); return ram[addr]; } uint16_t mem_read_ramw(uint32_t addr, void *priv) { -// if (addr >= 0xc0000 && addr < 0x0c8000) pclog("Read RAMw %08X\n", addr); addreadlookup(mem_logical_addr, addr); return *(uint16_t *)&ram[addr]; } uint32_t mem_read_raml(uint32_t addr, void *priv) { -// if (addr >= 0xc0000 && addr < 0x0c8000) pclog("Read RAMl %08X\n", addr); addreadlookup(mem_logical_addr, addr); return *(uint32_t *)&ram[addr]; } @@ -1595,8 +1721,7 @@ void mem_write_ramb_page(uint32_t addr, uint8_t val, page_t *p) if (val != p->mem[addr & 0xfff] || codegen_in_recompile) { uint64_t mask = (uint64_t)1 << ((addr >> PAGE_MASK_SHIFT) & PAGE_MASK_MASK); -// pclog("mem_write_ramb_page: %08x %02x %08x %llx %llx\n", addr, val, cs+pc, p->dirty_mask, mask); - p->dirty_mask |= mask; + p->dirty_mask[(addr >> PAGE_MASK_INDEX_SHIFT) & PAGE_MASK_INDEX_MASK] |= mask; p->mem[addr & 0xfff] = val; } } @@ -1605,10 +1730,9 @@ void mem_write_ramw_page(uint32_t addr, uint16_t val, page_t *p) if (val != *(uint16_t *)&p->mem[addr & 0xfff] || codegen_in_recompile) { uint64_t mask = (uint64_t)1 << ((addr >> PAGE_MASK_SHIFT) & PAGE_MASK_MASK); - if ((addr & 0x3f) == 0x3f) + if ((addr & 0xf) == 0xf) mask |= (mask << 1); -// pclog("mem_write_ramw_page: %08x %04x %08x\n", addr, val, cs+pc); - p->dirty_mask |= mask; + p->dirty_mask[(addr >> PAGE_MASK_INDEX_SHIFT) & PAGE_MASK_INDEX_MASK] |= mask; *(uint16_t *)&p->mem[addr & 0xfff] = val; } } @@ -1617,10 +1741,9 @@ void mem_write_raml_page(uint32_t addr, uint32_t val, page_t *p) if (val != *(uint32_t *)&p->mem[addr & 0xfff] || codegen_in_recompile) { uint64_t mask = (uint64_t)1 << ((addr >> PAGE_MASK_SHIFT) & PAGE_MASK_MASK); - if ((addr & 0x3f) >= 0x3d) + if ((addr & 0xf) >= 0xd) mask |= (mask << 1); -// pclog("mem_write_raml_page: %08x %08x %08x\n", addr, val, cs+pc); - p->dirty_mask |= mask; + p->dirty_mask[(addr >> PAGE_MASK_INDEX_SHIFT) & PAGE_MASK_INDEX_MASK] |= mask; *(uint32_t *)&p->mem[addr & 0xfff] = val; } } @@ -1641,25 +1764,63 @@ void mem_write_raml(uint32_t addr, uint32_t val, void *priv) mem_write_raml_page(addr, val, &pages[addr >> 12]); } +static uint32_t remap_start_addr; + +uint8_t mem_read_remapped(uint32_t addr, void *priv) +{ + addr = 0xA0000 + (addr - remap_start_addr); + addreadlookup(mem_logical_addr, addr); + return ram[addr]; +} +uint16_t mem_read_remappedw(uint32_t addr, void *priv) +{ + addr = 0xA0000 + (addr - remap_start_addr); + addreadlookup(mem_logical_addr, addr); + return *(uint16_t *)&ram[addr]; +} +uint32_t mem_read_remappedl(uint32_t addr, void *priv) +{ + addr = 0xA0000 + (addr - remap_start_addr); + addreadlookup(mem_logical_addr, addr); + return *(uint32_t *)&ram[addr]; +} + +void mem_write_remapped(uint32_t addr, uint8_t val, void *priv) +{ + uint32_t oldaddr = addr; + addr = 0xA0000 + (addr - remap_start_addr); + addwritelookup(mem_logical_addr, addr); + mem_write_ramb_page(addr, val, &pages[oldaddr >> 12]); +} +void mem_write_remappedw(uint32_t addr, uint16_t val, void *priv) +{ + uint32_t oldaddr = addr; + addr = 0xA0000 + (addr - remap_start_addr); + addwritelookup(mem_logical_addr, addr); + mem_write_ramw_page(addr, val, &pages[oldaddr >> 12]); +} +void mem_write_remappedl(uint32_t addr, uint32_t val, void *priv) +{ + uint32_t oldaddr = addr; + addr = 0xA0000 + (addr - remap_start_addr); + addwritelookup(mem_logical_addr, addr); + mem_write_raml_page(addr, val, &pages[oldaddr >> 12]); +} + uint8_t mem_read_bios(uint32_t addr, void *priv) { - if (AMIBIOS && (addr&0xFFFFF)==0xF8281) /*This is read constantly during AMIBIOS POST, but is never written to. It's clearly a status register of some kind, but for what?*/ - { -// pclog("Read magic addr %04X(%06X):%04X\n",CS,cs,cpu_state.pc); -// if (pc==0x547D) output=3; - return 0x40; - } -// pclog("Read BIOS %08X %02X %04X:%04X\n", addr, rom[addr & biosmask], CS, pc); + if (AMIBIOS && (addr&0xFFFFF)==0xF8281) /*This is read constantly during AMIBIOS POST, but is never written to. It's clearly a status register of some kind, but for what?*/ + { + return 0x40; + } return rom[addr & biosmask]; } uint16_t mem_read_biosw(uint32_t addr, void *priv) { -// pclog("Read BIOS %08X %04X %04X:%04X\n", addr, *(uint16_t *)&rom[addr & biosmask], CS, pc); return *(uint16_t *)&rom[addr & biosmask]; } uint32_t mem_read_biosl(uint32_t addr, void *priv) { -// pclog("Read BIOS %08X %02X %04X:%04X\n", addr, *(uint32_t *)&rom[addr & biosmask], CS, pc); return *(uint32_t *)&rom[addr & biosmask]; } @@ -1669,11 +1830,13 @@ uint8_t mem_read_romext(uint32_t addr, void *priv) } uint16_t mem_read_romextw(uint32_t addr, void *priv) { - return *(uint16_t *)&romext[addr & 0x7fff]; + uint16_t *p = (uint16_t *)&romext[addr & 0x7fff]; + return *p; } uint32_t mem_read_romextl(uint32_t addr, void *priv) { - return *(uint32_t *)&romext[addr & 0x7fff]; + uint32_t *p = (uint32_t *)&romext[addr & 0x7fff]; + return *p; } void mem_write_null(uint32_t addr, uint8_t val, void *p) @@ -1694,14 +1857,13 @@ void mem_invalidate_range(uint32_t start_addr, uint32_t end_addr) for (; start_addr <= end_addr; start_addr += (1 << PAGE_MASK_SHIFT)) { uint64_t mask = (uint64_t)1 << ((start_addr >> PAGE_MASK_SHIFT) & PAGE_MASK_MASK); - - pages[start_addr >> 12].dirty_mask |= mask; + + pages[start_addr >> 12].dirty_mask[(start_addr >> PAGE_MASK_INDEX_SHIFT) & PAGE_MASK_INDEX_MASK] |= mask; } } -static inline int mem_mapping_read_allowed(uint32_t flags, int state) +static __inline int mem_mapping_read_allowed(uint32_t flags, int state) { -// pclog("mem_mapping_read_allowed: flags=%x state=%x\n", flags, state); switch (state & MEM_READ_MASK) { case MEM_READ_ANY: @@ -1712,10 +1874,11 @@ static inline int mem_mapping_read_allowed(uint32_t flags, int state) return !(flags & MEM_MAPPING_EXTERNAL); default: fatal("mem_mapping_read_allowed : bad state %x\n", state); + return 0; } } -static inline int mem_mapping_write_allowed(uint32_t flags, int state) +static __inline int mem_mapping_write_allowed(uint32_t flags, int state) { switch (state & MEM_WRITE_MASK) { @@ -1729,6 +1892,7 @@ static inline int mem_mapping_write_allowed(uint32_t flags, int state) return !(flags & MEM_MAPPING_EXTERNAL); default: fatal("mem_mapping_write_allowed : bad state %x\n", state); + return 0; } } @@ -1898,7 +2062,6 @@ void mem_set_mem_state(uint32_t base, uint32_t size, int state) { uint32_t c; -// pclog("mem_set_pci_enable: base=%08x size=%08x\n", base, size); for (c = 0; c < size; c += 0x4000) _mem_state[(c + base) >> 14] = state; @@ -1936,18 +2099,19 @@ void mem_init() { int c; - ram = malloc((mem_size + 384) * 1024); - rom = malloc(0x20000); + ram = malloc(mem_size * 1024); readlookup2 = malloc(1024 * 1024 * sizeof(uintptr_t)); writelookup2 = malloc(1024 * 1024 * sizeof(uintptr_t)); biosmask = 0xffff; pages = malloc((((mem_size + 384) * 1024) >> 12) * sizeof(page_t)); page_lookup = malloc((1 << 20) * sizeof(page_t *)); - memset(ram, 0, (mem_size + 384) * 1024); + memset(ram, 0, mem_size * 1024); memset(pages, 0, (((mem_size + 384) * 1024) >> 12) * sizeof(page_t)); memset(page_lookup, 0, (1 << 20) * sizeof(page_t *)); + + memset(ram_mapped_addr, 0, 64 * sizeof(uint32_t)); for (c = 0; c < (((mem_size + 384) * 1024) >> 12); c++) { @@ -1958,7 +2122,7 @@ void mem_init() } memset(isram, 0, sizeof(isram)); - for (c = 0; c < (mem_size / 256); c++) + for (c = 0; c < (mem_size / 64); c++) { isram[c] = 1; if (c >= 0xa && c <= 0xf) @@ -1981,7 +2145,10 @@ void mem_init() mem_set_mem_state(0x000000, (mem_size > 640) ? 0xa0000 : mem_size * 1024, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); mem_set_mem_state(0x0c0000, 0x40000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); - mem_set_mem_state(0x100000, (mem_size - 1024) * 1024, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + if (mem_size > 1024) + { + mem_set_mem_state(0x100000, (mem_size - 1024) * 1024, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + } mem_mapping_add(&ram_low_mapping, 0x00000, (mem_size > 640) ? 0xa0000 : mem_size * 1024, mem_read_ram, mem_read_ramw, mem_read_raml, mem_write_ram, mem_write_ramw, mem_write_raml, ram, MEM_MAPPING_INTERNAL, NULL); if (mem_size > 1024) @@ -1990,30 +2157,42 @@ void mem_init() mem_mapping_add(&ram_mid_mapping, 0xc0000, 0x40000, mem_read_ram, mem_read_ramw, mem_read_raml, mem_write_ram, mem_write_ramw, mem_write_raml, ram + 0xc0000, MEM_MAPPING_INTERNAL, NULL); mem_mapping_add(&romext_mapping, 0xc8000, 0x08000, mem_read_romext, mem_read_romextw, mem_read_romextl, NULL, NULL, NULL, romext, 0, NULL); -// pclog("Mem resize %i %i\n",mem_size,c); +} + +static void mem_remap_top(int max_size) +{ + int c; + + if (mem_size > 640) + { + uint32_t start = (mem_size >= 1024) ? mem_size : 1024; + int size = mem_size - 640; + if (size > max_size) + size = max_size; + + remap_start_addr = start * 1024; + + for (c = ((start * 1024) >> 12); c < (((start + size) * 1024) >> 12); c++) + { + pages[c].mem = &ram[0xA0000 + ((c - ((start * 1024) >> 12)) << 12)]; + pages[c].write_b = mem_write_ramb_page; + pages[c].write_w = mem_write_ramw_page; + pages[c].write_l = mem_write_raml_page; + } + + mem_set_mem_state(start * 1024, size * 1024, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + mem_mapping_add(&ram_remapped_mapping, start * 1024, size * 1024, mem_read_remapped, mem_read_remappedw, mem_read_remappedl, mem_write_remapped, mem_write_remappedw, mem_write_remappedl, ram + 0xA0000, MEM_MAPPING_INTERNAL, NULL); + } +} + +void mem_remap_top_256k() +{ + mem_remap_top(256); } void mem_remap_top_384k() { - int c; - - for (c = ((mem_size * 1024) >> 12); c < (((mem_size + 384) * 1024) >> 12); c++) - { - pages[c].mem = &ram[c << 12]; - pages[c].write_b = mem_write_ramb_page; - pages[c].write_w = mem_write_ramw_page; - pages[c].write_l = mem_write_raml_page; - } - - for (c = (mem_size / 256); c < ((mem_size + 384) / 256); c++) - { - isram[c] = 1; - if (c >= 0xa && c <= 0xf) - isram[c] = 0; - } - - mem_set_mem_state(mem_size * 1024, 384 * 1024, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); - mem_mapping_add(&ram_remapped_mapping, mem_size * 1024, 384 * 1024, mem_read_ram, mem_read_ramw, mem_read_raml, mem_write_ram, mem_write_ramw, mem_write_raml, ram + (mem_size * 1024), MEM_MAPPING_INTERNAL, NULL); + mem_remap_top(384); } void mem_resize() @@ -2021,8 +2200,8 @@ void mem_resize() int c; free(ram); - ram = malloc((mem_size + 384) * 1024); - memset(ram, 0, (mem_size + 384) * 1024); + ram = malloc(mem_size * 1024); + memset(ram, 0, mem_size * 1024); free(pages); pages = malloc((((mem_size + 384) * 1024) >> 12) * sizeof(page_t)); @@ -2036,7 +2215,7 @@ void mem_resize() } memset(isram, 0, sizeof(isram)); - for (c = 0; c < (mem_size / 256); c++) + for (c = 0; c < (mem_size / 64); c++) { isram[c] = 1; if (c >= 0xa && c <= 0xf) @@ -2057,7 +2236,10 @@ void mem_resize() mem_set_mem_state(0x000000, (mem_size > 640) ? 0xa0000 : mem_size * 1024, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); mem_set_mem_state(0x0c0000, 0x40000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); - mem_set_mem_state(0x100000, (mem_size - 1024) * 1024, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + if (mem_size > 1024) + { + mem_set_mem_state(0x100000, (mem_size - 1024) * 1024, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + } mem_mapping_add(&ram_low_mapping, 0x00000, (mem_size > 640) ? 0xa0000 : mem_size * 1024, mem_read_ram, mem_read_ramw, mem_read_raml, mem_write_ram, mem_write_ramw, mem_write_raml, ram, MEM_MAPPING_INTERNAL, NULL); if (mem_size > 1024) @@ -2065,9 +2247,9 @@ void mem_resize() if (mem_size > 768) mem_mapping_add(&ram_mid_mapping, 0xc0000, 0x40000, mem_read_ram, mem_read_ramw, mem_read_raml, mem_write_ram, mem_write_ramw, mem_write_raml, ram + 0xc0000, MEM_MAPPING_INTERNAL, NULL); - mem_mapping_add(&romext_mapping, 0xc8000, 0x08000, mem_read_romext, mem_read_romextw, mem_read_romextl, NULL, NULL, NULL, romext, 0, NULL); + if (romset == ROM_IBMPS1_2011) + mem_mapping_add(&romext_mapping, 0xc8000, 0x08000, mem_read_romext, mem_read_romextw, mem_read_romextl, NULL, NULL, NULL, romext, 0, NULL); -// pclog("Mem resize %i %i\n",mem_size,c); mem_a20_key = 2; mem_a20_recalc(); } @@ -2081,39 +2263,16 @@ void mem_reset_page_blocks() pages[c].write_b = mem_write_ramb_page; pages[c].write_w = mem_write_ramw_page; pages[c].write_l = mem_write_raml_page; - pages[c].block = NULL; - pages[c].block_2 = NULL; + pages[c].block[0] = pages[c].block[1] = pages[c].block[2] = pages[c].block[3] = NULL; + pages[c].block_2[0] = pages[c].block_2[1] = pages[c].block_2[2] = pages[c].block_2[3] = NULL; } } -void mem_reset() -{ - int c; - - mem_reset_page_blocks(); - - memset(isram, 0, sizeof(isram)); - for (c = 0; c < (mem_size / 256); c++) - { - isram[c] = 1; - if (c >= 0xa && c <= 0xf) - isram[c] = 0; - } - - mem_set_mem_state(0x000000, (mem_size > 640) ? 0xa0000 : mem_size * 1024, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); - mem_set_mem_state(0x0c0000, 0x40000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); - mem_set_mem_state(0x100000, (mem_size - 1024) * 1024, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); - - mem_a20_key = 2; - mem_a20_recalc(); -} - static int port_92_reg = 0; void mem_a20_recalc() { int state = mem_a20_key | mem_a20_alt; -// pclog("A20 recalc %i %i\n", state, mem_a20_state); if (state && !mem_a20_state) { rammask = 0xffffffff; @@ -2124,28 +2283,25 @@ void mem_a20_recalc() rammask = 0xffefffff; flushmmucache(); } -// pclog("rammask now %08X\n", rammask); mem_a20_state = state; } static uint8_t port_92_read(uint16_t port, void *priv) { - return (port_92_reg & 3) | 0x24; + return port_92_reg; } static void port_92_write(uint16_t port, uint8_t val, void *priv) { - mem_a20_alt = val & 2; - mem_a20_recalc(); - - if (!(port_92_reg & 1) && (val & 1)) + if (val & 1) { - // pclog("Port 92: Soft reset\n"); softresetx86(); + cpu_set_edx(); } - port_92_reg = val & 3; + port_92_reg = val & ~-1; + mem_a20_alt = val & 2; mem_a20_recalc(); } diff --git a/src/mem.h b/src/mem.h index ada252529..916e89995 100644 --- a/src/mem.h +++ b/src/mem.h @@ -39,6 +39,11 @@ extern int memspeed[11]; extern int nopageerrors; extern uint32_t biosmask; +#define MEM_MAP_TO_SHADOW_RAM_MASK 1 +#define MEM_MAP_TO_RAM_ADDR_MASK 2 + +extern uint32_t ram_mapped_addr[64]; + void mem_mapping_add(mem_mapping_t *mapping, uint32_t base, uint32_t size, @@ -82,7 +87,9 @@ extern int mem_a20_key; void mem_a20_recalc(); uint8_t mem_readb_phys(uint32_t addr); +uint16_t mem_readw_phys(uint32_t addr); void mem_writeb_phys(uint32_t addr, uint8_t val); +void mem_writew_phys(uint32_t addr, uint16_t val); uint8_t mem_read_ram(uint32_t addr, void *priv); uint16_t mem_read_ramw(uint32_t addr, void *priv); @@ -100,10 +107,11 @@ void mem_write_null(uint32_t addr, uint8_t val, void *p); void mem_write_nullw(uint32_t addr, uint16_t val, void *p); void mem_write_nulll(uint32_t addr, uint32_t val, void *p); -FILE *romfopen(char *fn, char *mode); - mem_mapping_t bios_mapping[8]; mem_mapping_t bios_high_mapping[8]; +mem_mapping_t romext_mapping; + +extern mem_mapping_t ram_high_mapping; typedef struct page_t @@ -114,12 +122,12 @@ typedef struct page_t uint8_t *mem; - struct codeblock_t *block, *block_2; + struct codeblock_t *block[4], *block_2[4]; /*Head of codeblock tree associated with this page*/ struct codeblock_t *head; - uint64_t code_present_mask, dirty_mask; + uint64_t code_present_mask[4], dirty_mask[4]; } page_t; extern page_t *pages; @@ -129,7 +137,7 @@ extern page_t **page_lookup; uint32_t mmutranslate_noabrt(uint32_t addr, int rw); extern uint32_t get_phys_virt,get_phys_phys; -static inline uint32_t get_phys(uint32_t addr) +static __inline uint32_t get_phys(uint32_t addr) { if (!((addr ^ get_phys_virt) & ~0xfff)) return get_phys_phys | (addr & 0xfff); @@ -144,10 +152,10 @@ static inline uint32_t get_phys(uint32_t addr) get_phys_phys = (mmutranslatereal(addr, 0) & rammask) & ~0xfff; return get_phys_phys | (addr & 0xfff); -// return mmutranslatereal(addr, 0) & rammask; + /* return mmutranslatereal(addr, 0) & rammask; */ } -static inline uint32_t get_phys_noabrt(uint32_t addr) +static __inline uint32_t get_phys_noabrt(uint32_t addr) { if (!(cr0 >> 31)) return addr & rammask; @@ -162,11 +170,27 @@ extern uint32_t mem_logical_addr; void mem_write_ramb_page(uint32_t addr, uint8_t val, page_t *p); void mem_write_ramw_page(uint32_t addr, uint16_t val, page_t *p); void mem_write_raml_page(uint32_t addr, uint32_t val, page_t *p); +void mem_flush_write_page(uint32_t addr, uint32_t virt); void mem_reset_page_blocks(); extern mem_mapping_t ram_low_mapping; +void mem_remap_top_256k(); void mem_remap_top_384k(); +void flushmmucache_nopc(); + +int loadbios(); + +void mem_add_bios(); + +void mem_init(); +void mem_resize(); + +void port_92_reset(); + +void port_92_add(); +void port_92_remove(); + #endif diff --git a/src/memregs.c b/src/memregs.c index 578f9e3d4..6d002f512 100644 --- a/src/memregs.c +++ b/src/memregs.c @@ -1,26 +1,47 @@ -/* Copyright holders: Tenshi - see COPYING for more details -*/ /* - 0xE1 and 0xE2 Memory Registers - Used by just about any emulated machine -*/ + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Emulation of the memory I/O scratch registers on ports 0xE1 + * and 0xE2, used by just about any emulated machine. + * + * Version: @(#)memregs.c 1.0.0 2017/05/30 + * + * Author: Miran Grca, + * Copyright 2016-2017 Miran Grca. + */ #include "ibm.h" #include "io.h" #include "memregs.h" -static uint8_t mem_regs[2] = {0xFF, 0xFF}; +static uint8_t mem_regs[16] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; + +static uint8_t mem_reg_ffff = 0; void memregs_write(uint16_t port, uint8_t val, void *priv) { - mem_regs[port - 0xE1] = val; + if (port == 0xffff) + { + mem_reg_ffff = 0; + } + + mem_regs[port & 0xf] = val; } uint8_t memregs_read(uint16_t port, void *priv) { - return mem_regs[port - 0xE1]; + if (port == 0xffff) + { + return mem_reg_ffff; + } + + return mem_regs[port & 0xf]; } void memregs_init() @@ -28,4 +49,12 @@ void memregs_init() pclog("Memory Registers Init\n"); io_sethandler(0x00e1, 0x0002, memregs_read, NULL, NULL, memregs_write, NULL, NULL, NULL); -} \ No newline at end of file +} + +void powermate_memregs_init() +{ + pclog("Memory Registers Init\n"); + + io_sethandler(0x00ed, 0x0002, memregs_read, NULL, NULL, memregs_write, NULL, NULL, NULL); + io_sethandler(0xffff, 0x0001, memregs_read, NULL, NULL, memregs_write, NULL, NULL, NULL); +} diff --git a/src/memregs.h b/src/memregs.h index 1e3dfbcec..cb8d626b7 100644 --- a/src/memregs.h +++ b/src/memregs.h @@ -1,4 +1,19 @@ -/* Copyright holders: Tenshi - see COPYING for more details -*/ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Emulation of the memory I/O scratch registers on ports 0xE1 + * and 0xE2, used by just about any emulated machine. + * + * Version: @(#)memregs.h 1.0.0 2017/05/30 + * + * Author: Miran Grca, + * Copyright 2016-2017 Miran Grca. + */ + extern void memregs_init(); +void powermate_memregs_init(); diff --git a/src/mfm_at.c b/src/mfm_at.c new file mode 100644 index 000000000..eca973a85 --- /dev/null +++ b/src/mfm_at.c @@ -0,0 +1,611 @@ +#include + +#include "ibm.h" +#include "hdd_image.h" +#include "device.h" +#include "io.h" +#include "pic.h" +#include "timer.h" + +#include "mfm_at.h" + + +#define IDE_TIME (TIMER_USEC*10) + +#define STAT_ERR 0x01 +#define STAT_INDEX 0x02 +#define STAT_CORRECTED_DATA 0x04 +#define STAT_DRQ 0x08 /* Data request */ +#define STAT_DSC 0x10 +#define STAT_SEEK_COMPLETE 0x20 +#define STAT_READY 0x40 +#define STAT_BUSY 0x80 + +#define ERR_DAM_NOT_FOUND 0x01 /*Data Address Mark not found*/ +#define ERR_TR000 0x02 /*Track 0 not found*/ +#define ERR_ABRT 0x04 /*Command aborted*/ +#define ERR_ID_NOT_FOUND 0x10 /*ID not found*/ +#define ERR_DATA_CRC 0x40 /*Data CRC error*/ +#define ERR_BAD_BLOCK 0x80 /*Bad Block detected*/ + +#define CMD_RESTORE 0x10 +#define CMD_READ 0x20 +#define CMD_WRITE 0x30 +#define CMD_VERIFY 0x40 +#define CMD_FORMAT 0x50 +#define CMD_SEEK 0x70 +#define CMD_DIAGNOSE 0x90 +#define CMD_SET_PARAMETERS 0x91 + +typedef struct mfm_drive_t +{ + int spt, hpc; + int tracks; + int cfg_spt; + int cfg_hpc; + int current_cylinder; + int present; + int hdc_num; +} mfm_drive_t; + +typedef struct mfm_t +{ + uint8_t status; + uint8_t error; + int secount,sector,cylinder,head,cylprecomp; + uint8_t command; + uint8_t fdisk; + int pos; + + int drive_sel; + int reset; + uint16_t buffer[256]; + int irqstat; + + int callback; + + mfm_drive_t drives[2]; +} mfm_t; + +uint16_t mfm_readw(uint16_t port, void *p); +void mfm_writew(uint16_t port, uint16_t val, void *p); + +static __inline void mfm_irq_raise(mfm_t *mfm) +{ + if (!(mfm->fdisk&2)) + picint(1 << 14); + + mfm->irqstat=1; +} + +static __inline void mfm_irq_lower(mfm_t *mfm) +{ + picintc(1 << 14); +} + +void mfm_irq_update(mfm_t *mfm) +{ + if (mfm->irqstat && !((pic2.pend|pic2.ins)&0x40) && !(mfm->fdisk & 2)) + picint(1 << 14); +} + +/* + * Return the sector offset for the current register values + */ +static int mfm_get_sector(mfm_t *mfm, off64_t *addr) +{ + mfm_drive_t *drive = &mfm->drives[mfm->drive_sel]; + int heads = drive->cfg_hpc; + int sectors = drive->cfg_spt; + + if (drive->current_cylinder != mfm->cylinder) + { + pclog("mfm_get_sector: wrong cylinder\n"); + return 1; + } + if (mfm->head > heads) + { + pclog("mfm_get_sector: past end of configured heads\n"); + return 1; + } + if (mfm->sector >= sectors+1) + { + pclog("mfm_get_sector: past end of configured sectors\n"); + return 1; + } + if (mfm->head > drive->hpc) + { + pclog("mfm_get_sector: past end of heads\n"); + return 1; + } + if (mfm->sector >= drive->spt+1) + { + pclog("mfm_get_sector: past end of sectors\n"); + return 1; + } + + *addr = ((((off64_t) mfm->cylinder * heads) + mfm->head) * + sectors) + (mfm->sector - 1); + + return 0; +} + +/** + * Move to the next sector using CHS addressing + */ +static void mfm_next_sector(mfm_t *mfm) +{ + mfm_drive_t *drive = &mfm->drives[mfm->drive_sel]; + + mfm->sector++; + if (mfm->sector == (drive->cfg_spt + 1)) + { + mfm->sector = 1; + mfm->head++; + if (mfm->head == drive->cfg_hpc) + { + mfm->head = 0; + mfm->cylinder++; + if (drive->current_cylinder < drive->tracks) + drive->current_cylinder++; + } + } +} + +static void loadhd(mfm_t *mfm, int c, int d, const wchar_t *fn) +{ + mfm_drive_t *drive = &mfm->drives[c]; + int ret = 0; + + ret = hdd_image_load(d); + + if (!ret) + { + drive->present = 0; + return; + } + + drive->spt = hdc[d].spt; + drive->hpc = hdc[d].hpc; + drive->tracks = hdc[d].tracks; + drive->hdc_num = d; + drive->present = 1; +} + + + +void mfm_write(uint16_t port, uint8_t val, void *p) +{ + mfm_t *mfm = (mfm_t *)p; + + switch (port) + { + case 0x1F0: /* Data */ + mfm_writew(port, val | (val << 8), p); + return; + + case 0x1F1: /* Write precompenstation */ + mfm->cylprecomp = val; + return; + + case 0x1F2: /* Sector count */ + mfm->secount = val; + return; + + case 0x1F3: /* Sector */ + mfm->sector = val; + return; + + case 0x1F4: /* Cylinder low */ + mfm->cylinder = (mfm->cylinder & 0xFF00) | val; + return; + + case 0x1F5: /* Cylinder high */ + mfm->cylinder = (mfm->cylinder & 0xFF) | (val << 8); + return; + + case 0x1F6: /* Drive/Head */ + mfm->head = val & 0xF; + mfm->drive_sel = (val & 0x10) ? 1 : 0; + if (mfm->drives[mfm->drive_sel].present) + mfm->status = STAT_READY | STAT_DSC; + else + mfm->status = 0; + return; + + case 0x1F7: /* Command register */ + if (!mfm->drives[mfm->drive_sel].present) + fatal("Command on non-present drive\n"); + + mfm_irq_lower(mfm); + mfm->command = val; + mfm->error = 0; + + switch (val & 0xf0) + { + case CMD_RESTORE: + mfm->command &= ~0x0f; /*Mask off step rate*/ + mfm->status = STAT_BUSY; + timer_process(); + mfm->callback = 200*IDE_TIME; + timer_update_outstanding(); + break; + + case CMD_SEEK: + mfm->command &= ~0x0f; /*Mask off step rate*/ + mfm->status = STAT_BUSY; + timer_process(); + mfm->callback = 200*IDE_TIME; + timer_update_outstanding(); + break; + + default: + switch (val) + { + case CMD_READ: case CMD_READ+1: + case CMD_READ+2: case CMD_READ+3: + mfm->command &= ~3; + if (val & 2) + fatal("Read with ECC\n"); + mfm->status = STAT_BUSY; + timer_process(); + mfm->callback = 200*IDE_TIME; + timer_update_outstanding(); + break; + + case CMD_WRITE: case CMD_WRITE+1: + case CMD_WRITE+2: case CMD_WRITE+3: + mfm->command &= ~3; + if (val & 2) + fatal("Write with ECC\n"); + mfm->status = STAT_DRQ | STAT_DSC; + mfm->pos=0; + break; + + case CMD_VERIFY: case CMD_VERIFY+1: + mfm->command &= ~1; + mfm->status = STAT_BUSY; + timer_process(); + mfm->callback = 200 * IDE_TIME; + timer_update_outstanding(); + break; + + case CMD_FORMAT: + mfm->status = STAT_DRQ | STAT_BUSY; + mfm->pos=0; + break; + + case CMD_SET_PARAMETERS: /* Initialize Drive Parameters */ + mfm->status = STAT_BUSY; + timer_process(); + mfm->callback = 30*IDE_TIME; + timer_update_outstanding(); + break; + + case CMD_DIAGNOSE: /* Execute Drive Diagnostics */ + mfm->status = STAT_BUSY; + timer_process(); + mfm->callback = 200*IDE_TIME; + timer_update_outstanding(); + break; + + default: + pclog("Bad MFM command %02X\n", val); + mfm->status = STAT_BUSY; + timer_process(); + mfm->callback = 200*IDE_TIME; + timer_update_outstanding(); + break; + } + } + break; + + case 0x3F6: /* Device control */ + if ((mfm->fdisk & 4) && !(val & 4)) + { + timer_process(); + mfm->callback = 500*IDE_TIME; + timer_update_outstanding(); + mfm->reset = 1; + mfm->status = STAT_BUSY; + } + if (val & 4) + { + /*Drive held in reset*/ + timer_process(); + mfm->callback = 0; + timer_update_outstanding(); + mfm->status = STAT_BUSY; + } + mfm->fdisk = val; + mfm_irq_update(mfm); + return; + } +} + +void mfm_writew(uint16_t port, uint16_t val, void *p) +{ + mfm_t *mfm = (mfm_t *)p; + + mfm->buffer[mfm->pos >> 1] = val; + mfm->pos += 2; + + if (mfm->pos >= 512) + { + mfm->pos = 0; + mfm->status = STAT_BUSY; + timer_process(); + mfm->callback = 6*IDE_TIME; + timer_update_outstanding(); + } +} + +uint8_t mfm_read(uint16_t port, void *p) +{ + mfm_t *mfm = (mfm_t *)p; + uint8_t temp; + + switch (port) + { + case 0x1F0: /* Data */ + temp = mfm_readw(port, mfm) & 0xff; + break; + + case 0x1F1: /* Error */ + temp = mfm->error; + break; + + case 0x1F2: /* Sector count */ + temp = (uint8_t)mfm->secount; + break; + + case 0x1F3: /* Sector */ + temp = (uint8_t)mfm->sector; + break; + + case 0x1F4: /* Cylinder low */ + temp = (uint8_t)(mfm->cylinder&0xFF); + break; + + case 0x1F5: /* Cylinder high */ + temp = (uint8_t)(mfm->cylinder>>8); + break; + + case 0x1F6: /* Drive/Head */ + temp = (uint8_t)(mfm->head | (mfm->drive_sel ? 0x10 : 0) | 0xa0); + break; + + case 0x1F7: /* Status */ + mfm_irq_lower(mfm); + temp = mfm->status; + break; + + default: + temp = 0xff; + break; + } + + return temp; +} + +uint16_t mfm_readw(uint16_t port, void *p) +{ + mfm_t *mfm = (mfm_t *)p; + uint16_t temp; + + temp = mfm->buffer[mfm->pos >> 1]; + mfm->pos += 2; + + if (mfm->pos >= 512) + { + mfm->pos=0; + mfm->status = STAT_READY | STAT_DSC; + if (mfm->command == CMD_READ) + { + mfm->secount = (mfm->secount - 1) & 0xff; + if (mfm->secount) + { + mfm_next_sector(mfm); + mfm->status = STAT_BUSY; + timer_process(); + mfm->callback = 6*IDE_TIME; + timer_update_outstanding(); + } + else + { + update_status_bar_icon(SB_HDD | HDD_BUS_MFM, 0); + } + } + } + + return temp; +} + +static void do_seek(mfm_t *mfm) +{ + mfm_drive_t *drive = &mfm->drives[mfm->drive_sel]; + + if (mfm->cylinder < drive->tracks) + drive->current_cylinder = mfm->cylinder; + else + drive->current_cylinder = drive->tracks-1; +} + +void mfm_callback(void *p) +{ + mfm_t *mfm = (mfm_t *)p; + mfm_drive_t *drive = &mfm->drives[mfm->drive_sel]; + off64_t addr; + + mfm->callback = 0; + if (mfm->reset) + { + mfm->status = STAT_READY | STAT_DSC; + mfm->error = 1; + mfm->secount = 1; + mfm->sector = 1; + mfm->head = 0; + mfm->cylinder = 0; + mfm->reset = 0; + return; + } + switch (mfm->command) + { + case CMD_RESTORE: + drive->current_cylinder = 0; + mfm->status = STAT_READY | STAT_DSC; + mfm_irq_raise(mfm); + break; + + case CMD_SEEK: + do_seek(mfm); + mfm->status = STAT_READY | STAT_DSC; + mfm_irq_raise(mfm); + break; + + case CMD_READ: + do_seek(mfm); + if (mfm_get_sector(mfm, &addr)) + { + mfm->error = ERR_ID_NOT_FOUND; + mfm->status = STAT_READY | STAT_DSC | STAT_ERR; + mfm_irq_raise(mfm); + break; + } + + hdd_image_read(drive->hdc_num, addr, 1, (uint8_t *) mfm->buffer); + mfm->pos = 0; + mfm->status = STAT_DRQ | STAT_READY | STAT_DSC; + mfm_irq_raise(mfm); + update_status_bar_icon(SB_HDD | HDD_BUS_MFM, 1); + break; + + case CMD_WRITE: + do_seek(mfm); + if (mfm_get_sector(mfm, &addr)) + { + mfm->error = ERR_ID_NOT_FOUND; + mfm->status = STAT_READY | STAT_DSC | STAT_ERR; + mfm_irq_raise(mfm); + break; + } + hdd_image_write(drive->hdc_num, addr, 1, (uint8_t *) mfm->buffer); + mfm_irq_raise(mfm); + mfm->secount = (mfm->secount - 1) & 0xff; + if (mfm->secount) + { + mfm->status = STAT_DRQ | STAT_READY | STAT_DSC; + mfm->pos = 0; + mfm_next_sector(mfm); + update_status_bar_icon(SB_HDD | HDD_BUS_MFM, 1); + } + else + { + mfm->status = STAT_READY | STAT_DSC; + update_status_bar_icon(SB_HDD | HDD_BUS_MFM, 0); + } + break; + + case CMD_VERIFY: + do_seek(mfm); + mfm->pos = 0; + mfm->status = STAT_READY | STAT_DSC; + mfm_irq_raise(mfm); + update_status_bar_icon(SB_HDD | HDD_BUS_MFM, 1); + break; + + case CMD_FORMAT: + do_seek(mfm); + if (mfm_get_sector(mfm, &addr)) + { + mfm->error = ERR_ID_NOT_FOUND; + mfm->status = STAT_READY | STAT_DSC | STAT_ERR; + mfm_irq_raise(mfm); + break; + } + hdd_image_zero(drive->hdc_num, addr, mfm->secount); + mfm->status = STAT_READY | STAT_DSC; + mfm_irq_raise(mfm); + update_status_bar_icon(SB_HDD | HDD_BUS_MFM, 1); + break; + + case CMD_DIAGNOSE: + mfm->error = 1; /*No error detected*/ + mfm->status = STAT_READY | STAT_DSC; + mfm_irq_raise(mfm); + break; + + case CMD_SET_PARAMETERS: /* Initialize Drive Parameters */ + drive->cfg_spt = mfm->secount; + drive->cfg_hpc = mfm->head+1; + pclog("Parameters: spt=%i hpc=%i\n", drive->cfg_spt,drive->cfg_hpc); + mfm->status = STAT_READY | STAT_DSC; + mfm_irq_raise(mfm); + break; + + default: + pclog("Callback on unknown command %02x\n", mfm->command); + mfm->status = STAT_READY | STAT_ERR | STAT_DSC; + mfm->error = ERR_ABRT; + mfm_irq_raise(mfm); + break; + } +} + +void *mfm_init() +{ + int c, d; + + mfm_t *mfm = malloc(sizeof(mfm_t)); + memset(mfm, 0, sizeof(mfm_t)); + + c = 0; + for (d = 0; d < HDC_NUM; d++) + { + if ((hdc[d].bus == HDD_BUS_MFM) && (hdc[d].mfm_channel < MFM_NUM)) + { + loadhd(mfm, hdc[d].mfm_channel, d, hdc[d].fn); + c++; + if (c >= MFM_NUM) break; + } + } + + mfm->status = STAT_READY | STAT_DSC; + mfm->error = 1; /*No errors*/ + + io_sethandler(0x01f0, 0x0001, mfm_read, mfm_readw, NULL, mfm_write, mfm_writew, NULL, mfm); + io_sethandler(0x01f1, 0x0007, mfm_read, NULL, NULL, mfm_write, NULL, NULL, mfm); + io_sethandler(0x03f6, 0x0001, NULL, NULL, NULL, mfm_write, NULL, NULL, mfm); + + timer_add(mfm_callback, &mfm->callback, &mfm->callback, mfm); + + return mfm; +} + +void mfm_close(void *p) +{ + mfm_t *mfm = (mfm_t *)p; + int d; + + for (d = 0; d < 2; d++) + { + mfm_drive_t *drive = &mfm->drives[d]; + + hdd_image_close(drive->hdc_num); + } + + free(mfm); +} + +device_t mfm_at_device = +{ + "IBM PC AT Fixed Disk Adapter", + DEVICE_AT, + mfm_init, + mfm_close, + NULL, + NULL, + NULL, + NULL, + NULL +}; diff --git a/src/mfm_at.h b/src/mfm_at.h new file mode 100644 index 000000000..67907af23 --- /dev/null +++ b/src/mfm_at.h @@ -0,0 +1 @@ +extern device_t mfm_at_device; diff --git a/src/mfm_xebec.c b/src/mfm_xebec.c new file mode 100644 index 000000000..eb56d2ec0 --- /dev/null +++ b/src/mfm_xebec.c @@ -0,0 +1,917 @@ +#include +#include +#include "ibm.h" + +#include "device.h" +#include "dma.h" +#include "hdd_image.h" +#include "io.h" +#include "mem.h" +#include "pic.h" +#include "rom.h" +#include "timer.h" + +#include "mfm_xebec.h" + +#define XEBEC_TIME (2000 * TIMER_USEC) + +enum +{ + STATE_IDLE, + STATE_RECEIVE_COMMAND, + STATE_START_COMMAND, + STATE_RECEIVE_DATA, + STATE_RECEIVED_DATA, + STATE_SEND_DATA, + STATE_SENT_DATA, + STATE_COMPLETION_BYTE, + STATE_DUNNO +}; + +typedef struct mfm_drive_t +{ + int spt, hpc; + int tracks; + int cfg_spt; + int cfg_hpc; + int cfg_cyl; + int current_cylinder; + int present; + int hdc_num; +} mfm_drive_t; + +typedef struct xebec_t +{ + rom_t bios_rom; + + int callback; + + int state; + + uint8_t status; + + uint8_t command[6]; + int command_pos; + + uint8_t data[512]; + int data_pos, data_len; + + uint8_t sector_buf[512]; + + uint8_t irq_dma_mask; + + uint8_t completion_byte; + uint8_t error; + + int drive_sel; + + mfm_drive_t drives[2]; + + int sector, head, cylinder; + int sector_count; + + uint8_t switches; +} xebec_t; + +#define STAT_IRQ 0x20 +#define STAT_DRQ 0x10 +#define STAT_BSY 0x08 +#define STAT_CD 0x04 +#define STAT_IO 0x02 +#define STAT_REQ 0x01 + +#define IRQ_ENA 0x02 +#define DMA_ENA 0x01 + +#define CMD_TEST_DRIVE_READY 0x00 +#define CMD_RECALIBRATE 0x01 +#define CMD_READ_STATUS 0x03 +#define CMD_VERIFY_SECTORS 0x05 +#define CMD_FORMAT_TRACK 0x06 +#define CMD_READ_SECTORS 0x08 +#define CMD_WRITE_SECTORS 0x0a +#define CMD_SEEK 0x0b +#define CMD_INIT_DRIVE_PARAMS 0x0c +#define CMD_WRITE_SECTOR_BUFFER 0x0f +#define CMD_BUFFER_DIAGNOSTIC 0xe0 +#define CMD_CONTROLLER_DIAGNOSTIC 0xe4 +#define CMD_DTC_GET_DRIVE_PARAMS 0xfb +#define CMD_DTC_SET_STEP_RATE 0xfc +#define CMD_DTC_SET_GEOMETRY 0xfe +#define CMD_DTC_GET_GEOMETRY 0xff + +#define ERR_NOT_READY 0x04 +#define ERR_SEEK_ERROR 0x15 +#define ERR_ILLEGAL_SECTOR_ADDRESS 0x21 + +static uint8_t xebec_read(uint16_t port, void *p) +{ + xebec_t *xebec = (xebec_t *)p; + uint8_t temp = 0xff; + + switch (port) + { + case 0x320: /*Read data*/ + xebec->status &= ~STAT_IRQ; + switch (xebec->state) + { + case STATE_COMPLETION_BYTE: + if ((xebec->status & 0xf) != (STAT_CD | STAT_IO | STAT_REQ | STAT_BSY)) + fatal("Read data STATE_COMPLETION_BYTE, status=%02x\n", xebec->status); + + temp = xebec->completion_byte; + xebec->status = 0; + xebec->state = STATE_IDLE; + break; + + case STATE_SEND_DATA: + if ((xebec->status & 0xf) != (STAT_IO | STAT_REQ | STAT_BSY)) + fatal("Read data STATE_COMPLETION_BYTE, status=%02x\n", xebec->status); + if (xebec->data_pos >= xebec->data_len) + fatal("Data write with full data!\n"); + temp = xebec->data[xebec->data_pos++]; + if (xebec->data_pos == xebec->data_len) + { + xebec->status = STAT_BSY; + xebec->state = STATE_SENT_DATA; + xebec->callback = XEBEC_TIME; + } + break; + + default: + fatal("Read data register - %i, %02x\n", xebec->state, xebec->status); + } + break; + + case 0x321: /*Read status*/ + temp = xebec->status; + break; + + case 0x322: /*Read option jumpers*/ + temp = xebec->switches; + break; + } + + return temp; +} + +static void xebec_write(uint16_t port, uint8_t val, void *p) +{ + xebec_t *xebec = (xebec_t *)p; + + switch (port) + { + case 0x320: /*Write data*/ + switch (xebec->state) + { + case STATE_RECEIVE_COMMAND: + if ((xebec->status & 0xf) != (STAT_BSY | STAT_CD | STAT_REQ)) + fatal("Bad write data state - STATE_START_COMMAND, status=%02x\n", xebec->status); + if (xebec->command_pos >= 6) + fatal("Command write with full command!\n"); + /*Command data*/ + xebec->command[xebec->command_pos++] = val; + if (xebec->command_pos == 6) + { + xebec->status = STAT_BSY; + xebec->state = STATE_START_COMMAND; + xebec->callback = XEBEC_TIME; + } + break; + + case STATE_RECEIVE_DATA: + if ((xebec->status & 0xf) != (STAT_BSY | STAT_REQ)) + fatal("Bad write data state - STATE_RECEIVE_DATA, status=%02x\n", xebec->status); + if (xebec->data_pos >= xebec->data_len) + fatal("Data write with full data!\n"); + /*Command data*/ + xebec->data[xebec->data_pos++] = val; + if (xebec->data_pos == xebec->data_len) + { + xebec->status = STAT_BSY; + xebec->state = STATE_RECEIVED_DATA; + xebec->callback = XEBEC_TIME; + } + break; + + default: + fatal("Write data unknown state - %i %02x\n", xebec->state, xebec->status); + } + break; + + case 0x321: /*Controller reset*/ + xebec->status = 0; + break; + + case 0x322: /*Generate controller-select-pulse*/ + xebec->status = STAT_BSY | STAT_CD | STAT_REQ; + xebec->command_pos = 0; + xebec->state = STATE_RECEIVE_COMMAND; + break; + + case 0x323: /*DMA/IRQ mask register*/ + xebec->irq_dma_mask = val; + break; + } +} + +static void xebec_complete(xebec_t *xebec) +{ + xebec->status = STAT_REQ | STAT_CD | STAT_IO | STAT_BSY; + xebec->state = STATE_COMPLETION_BYTE; + if (xebec->irq_dma_mask & IRQ_ENA) + { + xebec->status |= STAT_IRQ; + picint(1 << 5); + } +} + +static void xebec_error(xebec_t *xebec, uint8_t error) +{ + xebec->completion_byte |= 0x02; + xebec->error = error; + pclog("xebec_error - %02x\n", xebec->error); +} + +static int xebec_get_sector(xebec_t *xebec, off64_t *addr) +{ + mfm_drive_t *drive = &xebec->drives[xebec->drive_sel]; + int heads = drive->cfg_hpc; + + if (drive->current_cylinder != xebec->cylinder) + { + pclog("mfm_get_sector: wrong cylinder\n"); + xebec->error = ERR_ILLEGAL_SECTOR_ADDRESS; + return 1; + } + if (xebec->head > heads) + { + pclog("mfm_get_sector: past end of configured heads\n"); + xebec->error = ERR_ILLEGAL_SECTOR_ADDRESS; + return 1; + } + if (xebec->head > drive->hpc) + { + pclog("mfm_get_sector: past end of heads\n"); + xebec->error = ERR_ILLEGAL_SECTOR_ADDRESS; + return 1; + } + if (xebec->sector >= 17) + { + pclog("mfm_get_sector: past end of sectors\n"); + xebec->error = ERR_ILLEGAL_SECTOR_ADDRESS; + return 1; + } + + *addr = ((((off64_t) xebec->cylinder * heads) + xebec->head) * + 17) + xebec->sector; + + return 0; +} + +static void xebec_next_sector(xebec_t *xebec) +{ + mfm_drive_t *drive = &xebec->drives[xebec->drive_sel]; + + xebec->sector++; + if (xebec->sector >= 17) + { + xebec->sector = 0; + xebec->head++; + if (xebec->head >= drive->cfg_hpc) + { + xebec->head = 0; + xebec->cylinder++; + drive->current_cylinder++; + if (drive->current_cylinder >= drive->cfg_cyl) + drive->current_cylinder = drive->cfg_cyl-1; + } + } +} + +static void xebec_callback(void *p) +{ + off64_t addr; + + xebec_t *xebec = (xebec_t *)p; + mfm_drive_t *drive; + + xebec->callback = 0; + + xebec->drive_sel = (xebec->command[1] & 0x20) ? 1 : 0; + xebec->completion_byte = xebec->drive_sel & 0x20; + + drive = &xebec->drives[xebec->drive_sel]; + + switch (xebec->command[0]) + { + case CMD_TEST_DRIVE_READY: + if (!drive->present) + xebec_error(xebec, ERR_NOT_READY); + xebec_complete(xebec); + break; + + case CMD_RECALIBRATE: + if (!drive->present) + xebec_error(xebec, ERR_NOT_READY); + else + { + xebec->cylinder = 0; + drive->current_cylinder = 0; + } + xebec_complete(xebec); + break; + + case CMD_READ_STATUS: + switch (xebec->state) + { + case STATE_START_COMMAND: + xebec->state = STATE_SEND_DATA; + xebec->data_pos = 0; + xebec->data_len = 4; + xebec->status = STAT_BSY | STAT_IO | STAT_REQ; + xebec->data[0] = xebec->error; + xebec->data[1] = xebec->drive_sel ? 0x20 : 0; + xebec->data[2] = xebec->data[3] = 0; + xebec->error = 0; + break; + + case STATE_SENT_DATA: + xebec_complete(xebec); + break; + } + break; + + case CMD_VERIFY_SECTORS: + switch (xebec->state) + { + case STATE_START_COMMAND: + xebec->cylinder = xebec->command[3] | ((xebec->command[2] & 0xc0) << 2); + drive->current_cylinder = (xebec->cylinder >= drive->cfg_cyl) ? drive->cfg_cyl-1 : xebec->cylinder; + xebec->head = xebec->command[1] & 0x1f; + xebec->sector = xebec->command[2] & 0x1f; + xebec->sector_count = xebec->command[4]; + do + { + if (xebec_get_sector(xebec, &addr)) + { + pclog("xebec_get_sector failed\n"); + xebec_error(xebec, xebec->error); + xebec_complete(xebec); + return; + } + + xebec_next_sector(xebec); + + xebec->sector_count = (xebec->sector_count-1) & 0xff; + } while (xebec->sector_count); + + xebec_complete(xebec); + + update_status_bar_icon(SB_HDD | HDD_BUS_MFM, 1); + break; + + default: + fatal("CMD_VERIFY_SECTORS: bad state %i\n", xebec->state); + } + break; + + case CMD_FORMAT_TRACK: + { + xebec->cylinder = xebec->command[3] | ((xebec->command[2] & 0xc0) << 2); + drive->current_cylinder = (xebec->cylinder >= drive->cfg_cyl) ? drive->cfg_cyl-1 : xebec->cylinder; + xebec->head = xebec->command[1] & 0x1f; + + if (xebec_get_sector(xebec, &addr)) + { + pclog("xebec_get_sector failed\n"); + xebec_error(xebec, xebec->error); + xebec_complete(xebec); + return; + } + + hdd_image_zero(drive->hdc_num, addr, 17); + + xebec_complete(xebec); + } + break; + + case CMD_READ_SECTORS: + switch (xebec->state) + { + case STATE_START_COMMAND: + xebec->cylinder = xebec->command[3] | ((xebec->command[2] & 0xc0) << 2); + drive->current_cylinder = (xebec->cylinder >= drive->cfg_cyl) ? drive->cfg_cyl-1 : xebec->cylinder; + xebec->head = xebec->command[1] & 0x1f; + xebec->sector = xebec->command[2] & 0x1f; + xebec->sector_count = xebec->command[4]; + xebec->state = STATE_SEND_DATA; + xebec->data_pos = 0; + xebec->data_len = 512; + { + if (xebec_get_sector(xebec, &addr)) + { + xebec_error(xebec, xebec->error); + xebec_complete(xebec); + return; + } + + hdd_image_read(drive->hdc_num, addr, 1, (uint8_t *) xebec->sector_buf); + update_status_bar_icon(SB_HDD | HDD_BUS_MFM, 1); + } + if (xebec->irq_dma_mask & DMA_ENA) + xebec->callback = XEBEC_TIME; + else + { + xebec->status = STAT_BSY | STAT_IO | STAT_REQ; + memcpy(xebec->data, xebec->sector_buf, 512); + } + break; + + case STATE_SEND_DATA: + xebec->status = STAT_BSY; + if (xebec->irq_dma_mask & DMA_ENA) + { + for (; xebec->data_pos < 512; xebec->data_pos++) + { + int val = dma_channel_write(3, xebec->sector_buf[xebec->data_pos]); + + if (val == DMA_NODATA) + { + pclog("CMD_READ_SECTORS out of data!\n"); + xebec->status = STAT_BSY | STAT_CD | STAT_IO | STAT_REQ; + xebec->callback = XEBEC_TIME; + return; + } + } + xebec->state = STATE_SENT_DATA; + xebec->callback = XEBEC_TIME; + } + else + fatal("Read sectors no DMA! - shouldn't get here\n"); + break; + + case STATE_SENT_DATA: + xebec_next_sector(xebec); + + xebec->data_pos = 0; + + xebec->sector_count = (xebec->sector_count-1) & 0xff; + + if (xebec->sector_count) + { + if (xebec_get_sector(xebec, &addr)) + { + xebec_error(xebec, xebec->error); + xebec_complete(xebec); + return; + } + + hdd_image_read(drive->hdc_num, addr, 1, (uint8_t *) xebec->sector_buf); + update_status_bar_icon(SB_HDD | HDD_BUS_MFM, 1); + + xebec->state = STATE_SEND_DATA; + + if (xebec->irq_dma_mask & DMA_ENA) + xebec->callback = XEBEC_TIME; + else + { + xebec->status = STAT_BSY | STAT_IO | STAT_REQ; + memcpy(xebec->data, xebec->sector_buf, 512); + } + } + else + { + xebec_complete(xebec); + update_status_bar_icon(SB_HDD | HDD_BUS_MFM, 0); + } + break; + + + default: + fatal("CMD_READ_SECTORS: bad state %i\n", xebec->state); + } + break; + + case CMD_WRITE_SECTORS: + switch (xebec->state) + { + case STATE_START_COMMAND: + xebec->cylinder = xebec->command[3] | ((xebec->command[2] & 0xc0) << 2); + drive->current_cylinder = (xebec->cylinder >= drive->cfg_cyl) ? drive->cfg_cyl-1 : xebec->cylinder; + xebec->head = xebec->command[1] & 0x1f; + xebec->sector = xebec->command[2] & 0x1f; + xebec->sector_count = xebec->command[4]; + xebec->state = STATE_RECEIVE_DATA; + xebec->data_pos = 0; + xebec->data_len = 512; + if (xebec->irq_dma_mask & DMA_ENA) + xebec->callback = XEBEC_TIME; + else + xebec->status = STAT_BSY | STAT_REQ; + break; + + case STATE_RECEIVE_DATA: + xebec->status = STAT_BSY; + if (xebec->irq_dma_mask & DMA_ENA) + { + for (; xebec->data_pos < 512; xebec->data_pos++) + { + int val = dma_channel_read(3); + + if (val == DMA_NODATA) + { + pclog("CMD_WRITE_SECTORS out of data!\n"); + xebec->status = STAT_BSY | STAT_CD | STAT_IO | STAT_REQ; + xebec->callback = XEBEC_TIME; + return; + } + + xebec->sector_buf[xebec->data_pos] = val & 0xff; + } + + xebec->state = STATE_RECEIVED_DATA; + xebec->callback = XEBEC_TIME; + } + else + fatal("Write sectors no DMA! - should never get here\n"); + break; + + case STATE_RECEIVED_DATA: + if (!(xebec->irq_dma_mask & DMA_ENA)) + memcpy(xebec->sector_buf, xebec->data, 512); + + { + if (xebec_get_sector(xebec, &addr)) + { + xebec_error(xebec, xebec->error); + xebec_complete(xebec); + return; + } + + hdd_image_write(drive->hdc_num, addr, 1, (uint8_t *) xebec->sector_buf); + } + + update_status_bar_icon(SB_HDD | HDD_BUS_MFM, 1); + + xebec_next_sector(xebec); + xebec->data_pos = 0; + xebec->sector_count = (xebec->sector_count-1) & 0xff; + + if (xebec->sector_count) + { + xebec->state = STATE_RECEIVE_DATA; + if (xebec->irq_dma_mask & DMA_ENA) + xebec->callback = XEBEC_TIME; + else + xebec->status = STAT_BSY | STAT_REQ; + } + else + xebec_complete(xebec); + break; + + default: + fatal("CMD_WRITE_SECTORS: bad state %i\n", xebec->state); + } + break; + + case CMD_SEEK: + if (!drive->present) + xebec_error(xebec, ERR_NOT_READY); + else + { + int cylinder = xebec->command[3] | ((xebec->command[2] & 0xc0) << 2); + + drive->current_cylinder = (cylinder >= drive->cfg_cyl) ? drive->cfg_cyl-1 : cylinder; + + if (cylinder != drive->current_cylinder) + xebec_error(xebec, ERR_SEEK_ERROR); + } + xebec_complete(xebec); + break; + + case CMD_INIT_DRIVE_PARAMS: + switch (xebec->state) + { + case STATE_START_COMMAND: + xebec->state = STATE_RECEIVE_DATA; + xebec->data_pos = 0; + xebec->data_len = 8; + xebec->status = STAT_BSY | STAT_REQ; + break; + + case STATE_RECEIVED_DATA: + drive->cfg_cyl = xebec->data[1] | (xebec->data[0] << 8); + drive->cfg_hpc = xebec->data[2]; + pclog("Drive %i: cylinders=%i, heads=%i\n", xebec->drive_sel, drive->cfg_cyl, drive->cfg_hpc); + xebec_complete(xebec); + break; + + default: + fatal("CMD_INIT_DRIVE_PARAMS bad state %i\n", xebec->state); + } + break; + + case CMD_WRITE_SECTOR_BUFFER: + switch (xebec->state) + { + case STATE_START_COMMAND: + xebec->state = STATE_RECEIVE_DATA; + xebec->data_pos = 0; + xebec->data_len = 512; + if (xebec->irq_dma_mask & DMA_ENA) + xebec->callback = XEBEC_TIME; + else + xebec->status = STAT_BSY | STAT_REQ; + break; + + case STATE_RECEIVE_DATA: + if (xebec->irq_dma_mask & DMA_ENA) + { + xebec->status = STAT_BSY; + + for (; xebec->data_pos < 512; xebec->data_pos++) + { + int val = dma_channel_read(3); + + if (val == DMA_NODATA) + { + pclog("CMD_WRITE_SECTOR_BUFFER out of data!\n"); + xebec->status = STAT_BSY | STAT_CD | STAT_IO | STAT_REQ; + xebec->callback = XEBEC_TIME; + return; + } + + xebec->data[xebec->data_pos] = val & 0xff; + } + + xebec->state = STATE_RECEIVED_DATA; + xebec->callback = XEBEC_TIME; + } + else + fatal("CMD_WRITE_SECTOR_BUFFER - should never get here!\n"); + break; + case STATE_RECEIVED_DATA: + memcpy(xebec->sector_buf, xebec->data, 512); + xebec_complete(xebec); + break; + + default: + fatal("CMD_WRITE_SECTOR_BUFFER bad state %i\n", xebec->state); + } + break; + + case CMD_BUFFER_DIAGNOSTIC: + case CMD_CONTROLLER_DIAGNOSTIC: + xebec_complete(xebec); + break; + + case 0xfa: + xebec_complete(xebec); + break; + + case CMD_DTC_SET_STEP_RATE: + xebec_complete(xebec); + break; + + case CMD_DTC_GET_DRIVE_PARAMS: + switch (xebec->state) + { + case STATE_START_COMMAND: + xebec->state = STATE_SEND_DATA; + xebec->data_pos = 0; + xebec->data_len = 4; + xebec->status = STAT_BSY | STAT_IO | STAT_REQ; + memset(xebec->data, 0, 4); + xebec->data[0] = drive->tracks & 0xff; + xebec->data[1] = 17 | ((drive->tracks >> 2) & 0xc0); + xebec->data[2] = drive->hpc-1; + pclog("Get drive params %02x %02x %02x %i\n", xebec->data[0], xebec->data[1], xebec->data[2], drive->tracks); + break; + + case STATE_SENT_DATA: + xebec_complete(xebec); + break; + + default: + fatal("CMD_INIT_DRIVE_PARAMS bad state %i\n", xebec->state); + } + break; + + case CMD_DTC_GET_GEOMETRY: + switch (xebec->state) + { + case STATE_START_COMMAND: + xebec->state = STATE_SEND_DATA; + xebec->data_pos = 0; + xebec->data_len = 16; + xebec->status = STAT_BSY | STAT_IO | STAT_REQ; + memset(xebec->data, 0, 16); + xebec->data[0x4] = drive->tracks & 0xff; + xebec->data[0x5] = (drive->tracks >> 8) & 0xff; + xebec->data[0xa] = drive->hpc; + break; + + case STATE_SENT_DATA: + xebec_complete(xebec); + break; + } + break; + + case CMD_DTC_SET_GEOMETRY: + switch (xebec->state) + { + case STATE_START_COMMAND: + xebec->state = STATE_RECEIVE_DATA; + xebec->data_pos = 0; + xebec->data_len = 16; + xebec->status = STAT_BSY | STAT_REQ; + break; + + case STATE_RECEIVED_DATA: + /*Bit of a cheat here - we always report the actual geometry of the drive in use*/ + xebec_complete(xebec); + break; + } + break; + + default: + fatal("Unknown Xebec command - %02x %02x %02x %02x %02x %02x\n", + xebec->command[0], xebec->command[1], + xebec->command[2], xebec->command[3], + xebec->command[4], xebec->command[5]); + } +} + +static void loadhd(xebec_t *xebec, int c, int d, const wchar_t *fn) +{ + mfm_drive_t *drive = &xebec->drives[d]; + int ret = 0; + + ret = hdd_image_load(d); + + if (!ret) + { + drive->present = 0; + return; + } + + drive->spt = hdc[c].spt; + drive->hpc = hdc[c].hpc; + drive->tracks = hdc[c].tracks; + drive->hdc_num = c; + drive->present = 1; +} + +static struct +{ + int tracks, hpc; +} xebec_hd_types[4] = +{ + {306, 4}, /*Type 0*/ + {612, 4}, /*Type 16*/ + {615, 4}, /*Type 2*/ + {306, 8} /*Type 13*/ +}; + +static void xebec_set_switches(xebec_t *xebec) +{ + int c, d; + + xebec->switches = 0; + + for (d = 0; d < 2; d++) + { + mfm_drive_t *drive = &xebec->drives[d]; + + if (!drive->present) + continue; + + for (c = 0; c < 4; c++) + { + if (drive->spt == 17 && + drive->hpc == xebec_hd_types[c].hpc && + drive->tracks == xebec_hd_types[c].tracks) + { + xebec->switches |= (c << (d ? 0 : 2)); + break; + } + } + + if (c == 4) + pclog("WARNING: Drive %c: has format not supported by Fixed Disk Adapter", d ? 'D' : 'C'); + } +} + +static void *xebec_init() +{ + int i = 0; + int c = 0; + + xebec_t *xebec = malloc(sizeof(xebec_t)); + memset(xebec, 0, sizeof(xebec_t)); + + for (i = 0; i < HDC_NUM; i++) + { + if ((hdc[i].bus == HDD_BUS_MFM) && (hdc[i].mfm_channel < MFM_NUM)) + { + loadhd(xebec, i, hdc[i].mfm_channel, hdc[i].fn); + c++; + if (c > MFM_NUM) break; + } + } + + xebec_set_switches(xebec); + + rom_init(&xebec->bios_rom, L"roms/ibm_xebec_62x0822_1985.bin", 0xc8000, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL); + + io_sethandler(0x0320, 0x0004, xebec_read, NULL, NULL, xebec_write, NULL, NULL, xebec); + + timer_add(xebec_callback, &xebec->callback, &xebec->callback, xebec); + + return xebec; +} + +static void xebec_close(void *p) +{ + xebec_t *xebec = (xebec_t *)p; + int d; + + for (d = 0; d < 2; d++) + { + mfm_drive_t *drive = &xebec->drives[d]; + + hdd_image_close(drive->hdc_num); + } + + free(xebec); +} + +static int xebec_available() +{ + return rom_present(L"roms/ibm_xebec_62x0822_1985.bin"); +} + +device_t mfm_xebec_device = +{ + "IBM PC Fixed Disk Adapter", + 0, + xebec_init, + xebec_close, + xebec_available, + NULL, + NULL, + NULL, + NULL +}; + +static void *dtc_5150x_init() +{ + int i = 0; + int c = 0; + + xebec_t *xebec = malloc(sizeof(xebec_t)); + memset(xebec, 0, sizeof(xebec_t)); + + for (i = 0; i < HDC_NUM; i++) + { + if ((hdc[i].bus == HDD_BUS_MFM) && (hdc[i].mfm_channel < MFM_NUM)) + { + loadhd(xebec, i, hdc[i].mfm_channel, hdc[i].fn); + c++; + if (c > MFM_NUM) break; + } + } + + xebec->switches = 0xff; + + xebec->drives[0].cfg_cyl = xebec->drives[0].tracks; + xebec->drives[0].cfg_hpc = xebec->drives[0].hpc; + xebec->drives[1].cfg_cyl = xebec->drives[1].tracks; + xebec->drives[1].cfg_hpc = xebec->drives[1].hpc; + + rom_init(&xebec->bios_rom, L"roms/dtc_cxd21a.bin", 0xc8000, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL); + + io_sethandler(0x0320, 0x0004, xebec_read, NULL, NULL, xebec_write, NULL, NULL, xebec); + + timer_add(xebec_callback, &xebec->callback, &xebec->callback, xebec); + + return xebec; +} +static int dtc_5150x_available() +{ + return rom_present(L"roms/dtc_cxd21a.bin"); +} + +device_t dtc_5150x_device = +{ + "DTC 5150X", + 0, + dtc_5150x_init, + xebec_close, + dtc_5150x_available, + NULL, + NULL, + NULL, + NULL +}; diff --git a/src/mfm_xebec.h b/src/mfm_xebec.h new file mode 100644 index 000000000..e6bafff17 --- /dev/null +++ b/src/mfm_xebec.h @@ -0,0 +1,2 @@ +extern device_t mfm_xebec_device; +extern device_t dtc_5150x_device; diff --git a/src/model.c b/src/model.c index 1b9868484..c30df365c 100644 --- a/src/model.c +++ b/src/model.c @@ -1,194 +1,234 @@ -/* Copyright holders: Sarah Walker - see COPYING for more details -*/ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Handling of the emulated machines. + * + * Version: @(#)model.c 1.0.4 2017/06/21 + * + * Authors: Sarah Walker, + * Miran Grca, + * Copyright 2008-2017 Sarah Walker. + * Copyright 2016-2017 Miran Grca. + */ +#include +#include + #include "ibm.h" -#include "cpu.h" +#include "cpu/cpu.h" +#include "io.h" #include "mem.h" +#include "rom.h" +#include "device.h" #include "model.h" #include "mouse.h" -#include "io.h" -#include "rom.h" +#include "mouse_ps2.h" +#include "cdrom.h" -#include "acer386sx.h" -#include "acerm3a.h" -#include "ali1429.h" -#include "amstrad.h" -#include "compaq.h" -#include "device.h" #include "disc.h" #include "dma.h" #include "fdc.h" #include "fdc37c665.h" +#include "fdc37c669.h" #include "fdc37c932fr.h" #include "gameport.h" -#include "headland.h" -#include "i430fx.h" -#include "i430hx.h" -#include "i430lx.h" -#include "i430nx.h" -#include "i430vx.h" -#include "i440fx.h" +#include "i82335.h" #include "ide.h" #include "intel.h" #include "intel_flash.h" -#include "jim.h" #include "keyboard_amstrad.h" #include "keyboard_at.h" #include "keyboard_olim24.h" #include "keyboard_pcjr.h" #include "keyboard_xt.h" #include "lpt.h" +#include "mem.h" #include "memregs.h" -#include "neat.h" #include "nmi.h" #include "nvr.h" -#include "olivetti_m24.h" -#include "opti495.h" #include "pc87306.h" #include "pci.h" #include "pic.h" #include "piix.h" #include "pit.h" -#include "ps1.h" -#include "scat.h" +#include "ps2_mca.h" #include "serial.h" -#include "sis496.h" #include "sis85c471.h" #include "sio.h" -#include "sound_ps1.h" -#include "sound_pssj.h" -#include "sound_sn76489.h" +#include "sound/snd_ps1.h" +#include "sound/snd_pssj.h" +#include "sound/snd_sn76489.h" +#if 0 +#include "superio_detect.h" +#endif #include "tandy_eeprom.h" #include "tandy_rom.h" +#if 0 #include "um8669f.h" -// #include "um8881f.h" -#include "vid_pcjr.h" -#include "vid_tandy.h" +#endif +#include "video/vid_pcjr.h" +#include "video/vid_tandy.h" #include "w83877f.h" #include "wd76c10.h" #include "xtide.h" +#include "bugger.h" -void xt_init(); -void pcjr_init(); -void tandy1k_init(); -void tandy1ksl2_init(); -void ams_init(); -void europc_init(); -void olim24_init(); -void at_init(); -void deskpro386_init(); -void ps1_m2011_init(); -void ps1_m2121_init(); -void at_neat_init(); -void at_scat_init(); -void at_acer386sx_init(); -void at_wd76c10_init(); -void at_ali1429_init(); -void at_headland_init(); -void at_opti495_init(); -// void at_um8881f_init(); -void at_sis496_init(); -void at_i430vx_init(); -void at_batman_init(); -void at_endeavor_init(); -void at_dtk486_init(); -void at_r418_init(); -void at_586mc1_init(); -void at_plato_init(); -void at_mb500n_init(); +extern void xt_init(void); +extern void pcjr_init(void); +extern void tandy1k_init(void); +extern void tandy1ksl2_init(void); +extern void ams_init(void); +extern void europc_init(void); +extern void olim24_init(void); +extern void at_init(void); +extern void ibm_at_init(void); +extern void at_ide_init(void); +extern void cmdpc30_init(void); +extern void deskpro386_init(void); +extern void ps1_m2011_init(void); +extern void ps1_m2121_init(void); +extern void ps1_m2133_init(void); +extern void ps2_m30_286_init(void); +extern void ps2_model_50_init(void); +extern void ps2_model_55sx_init(void); +extern void ps2_model_80_init(void); +extern void at_neat_init(void); +extern void at_scat_init(void); +extern void at_wd76c10_init(void); +extern void at_ali1429_init(void); +extern void at_headland_init(void); +extern void at_opti495_init(void); +extern void at_batman_init(void); #if 0 -void at_powermate_v_init(); +extern void at_586mc1_init(void); #endif -void at_p54tp4xe_init(); -void at_acerm3a_init(); -void at_acerv35n_init(); -void at_p55t2p4_init(); -void at_p55tvp4_init(); -void at_marl_init(); -void at_p55va_init(); -void at_i440fx_init(); +extern void at_endeavor_init(void); + +extern void at_dtk486_init(void); +extern void at_r418_init(void); +extern void at_plato_init(void); +extern void at_mb500n_init(void); +extern void at_president_init(void); +extern void at_p54tp4xe_init(void); +extern void at_ap53_init(void); +extern void at_p55t2s_init(void); +extern void at_acerm3a_init(void); +extern void at_acerv35n_init(void); +extern void at_p55t2p4_init(void); +extern void at_p55tvp4_init(void); +extern void at_p55va_init(void); +extern void at_i440fx_init(void); +extern void at_s1668_init(void); + +extern void xt_laserxt_init(void); int model; int AMSTRAD, AT, PCI, TANDY; +PCI_RESET pci_reset_handler; + +int serial_enabled[2] = { 0, 0 }; +int lpt_enabled = 0, bugger_enabled = 0; + +int romset; + MODEL models[] = { - {"IBM PC", ROM_IBMPC, { "", cpus_8088, "", NULL, "", NULL}, 0, 0, 64, 640, 64, xt_init, NULL}, - {"IBM XT", ROM_IBMXT, { "", cpus_8088, "", NULL, "", NULL}, 0, 0, 64, 640, 64, xt_init, NULL}, - {"IBM PCjr", ROM_IBMPCJR, { "", cpus_pcjr, "", NULL, "", NULL}, 1, 0, 128, 640, 128, pcjr_init, &pcjr_device}, - {"Generic XT clone", ROM_GENXT, { "", cpus_8088, "", NULL, "", NULL}, 0, 0, 64, 640, 64, xt_init, NULL}, - {"AMI XT clone", ROM_AMIXT, { "", cpus_8088, "", NULL, "", NULL}, 0, 0, 64, 640, 64, xt_init, NULL}, - {"DTK XT clone", ROM_DTKXT, { "", cpus_8088, "", NULL, "", NULL}, 0, 0, 64, 640, 64, xt_init, NULL}, - {"VTech Laser Turbo XT",ROM_LTXT, { "", cpus_8088, "", NULL, "", NULL}, 0, 0, 64, 640, 64, xt_init, NULL}, - {"VTech Laser XT3", ROM_LXT3, { "", cpus_8088, "", NULL, "", NULL}, 0, 0, 64, 640, 64, xt_init, NULL}, - {"Phoenix XT clone", ROM_PXXT, { "", cpus_8088, "", NULL, "", NULL}, 0, 0, 64, 640, 64, xt_init, NULL}, - {"Juko XT clone", ROM_JUKOPC, { "", cpus_8088, "", NULL, "", NULL}, 0, 0, 64, 640, 64, xt_init, NULL}, - {"Tandy 1000", ROM_TANDY, { "", cpus_8088, "", NULL, "", NULL}, 1, 0, 128, 640, 128, tandy1k_init, &tandy1000_device}, - {"Tandy 1000 HX", ROM_TANDY1000HX, { "", cpus_8088, "", NULL, "", NULL}, 1, 0, 256, 640, 128, tandy1k_init, &tandy1000hx_device}, - {"Tandy 1000 SL/2", ROM_TANDY1000SL2,{ "", cpus_8086, "", NULL, "", NULL}, 1, 0, 512, 768, 128, tandy1ksl2_init, NULL}, - {"Amstrad PC1512", ROM_PC1512, { "", cpus_pc1512, "", NULL, "", NULL}, 1, MODEL_AMSTRAD, 512, 640, 128, ams_init, NULL}, - {"Sinclair PC200", ROM_PC200, { "", cpus_8086, "", NULL, "", NULL}, 1, MODEL_AMSTRAD, 512, 640, 128, ams_init, NULL}, - {"Euro PC", ROM_EUROPC, { "", cpus_8086, "", NULL, "", NULL}, 0, 0, 512, 640, 128, europc_init, NULL}, - {"Olivetti M24", ROM_OLIM24, { "", cpus_8086, "", NULL, "", NULL}, 1, MODEL_OLIM24, 128, 640, 128, olim24_init, NULL}, - {"Amstrad PC1640", ROM_PC1640, { "", cpus_8086, "", NULL, "", NULL}, 1, MODEL_AMSTRAD, 640, 640, 0, ams_init, NULL}, - {"Amstrad PC2086", ROM_PC2086, { "", cpus_8086, "", NULL, "", NULL}, 1, MODEL_AMSTRAD, 640, 640, 0, ams_init, NULL}, - {"Amstrad PC3086", ROM_PC3086, { "", cpus_8086, "", NULL, "", NULL}, 1, MODEL_AMSTRAD, 640, 640, 0, ams_init, NULL}, - {"IBM AT", ROM_IBMAT, { "", cpus_ibmat, "", NULL, "", NULL}, 0, MODEL_AT, 1, 16, 1, at_init, NULL}, - {"Commodore PC 30 III", ROM_CMDPC30, { "", cpus_286, "", NULL, "", NULL}, 0, MODEL_AT, 1, 16, 1, at_init, NULL}, - {"AMI 286 clone", ROM_AMI286, { "", cpus_286, "", NULL, "", NULL}, 0, MODEL_AT, 1, 16, 1, at_neat_init, NULL}, - {"Award 286 clone", ROM_AWARD286, { "", cpus_286, "", NULL, "", NULL}, 0, MODEL_AT, 1, 16, 1, at_scat_init, NULL}, - {"DELL System 200", ROM_DELL200, { "", cpus_286, "", NULL, "", NULL}, 0, MODEL_AT, 1, 16, 1, at_init, NULL}, - {"IBM PS/1 model 2011", ROM_IBMPS1_2011, { "", cpus_ps1_m2011,"", NULL, "", NULL}, 1, MODEL_AT|MODEL_PS2, 1, 16, 1, ps1_m2011_init, NULL}, - {"IBM PS/1 model 2121", ROM_IBMPS1_2121, { "Intel", cpus_i386, "", NULL, "", NULL}, 1, MODEL_AT|MODEL_PS2, 1, 16, 1, ps1_m2121_init, NULL}, - {"Compaq Deskpro 386", ROM_DESKPRO_386, { "Intel", cpus_i386, "AMD", cpus_Am386, "Cyrix", cpus_486SDLC}, 0, MODEL_AT, 1, 15, 1, deskpro386_init, NULL}, - {"Acer 386SX25/N", ROM_ACER386, { "Intel", cpus_acer, "", NULL, "", NULL}, 1, MODEL_AT|MODEL_PS2, 1, 16, 1, at_acer386sx_init, NULL}, - {"DTK 386SX clone", ROM_DTK386, { "Intel", cpus_i386, "AMD", cpus_Am386, "Cyrix", cpus_486SDLC}, 0, MODEL_AT, 1, 16, 1, at_neat_init, NULL}, - {"Phoenix 386 clone", ROM_PX386, { "Intel", cpus_i386, "AMD", cpus_Am386, "Cyrix", cpus_486SDLC}, 0, MODEL_AT, 1, 16, 1, at_init, NULL}, - {"Amstrad MegaPC", ROM_MEGAPC, { "Intel", cpus_i386, "AMD", cpus_Am386, "Cyrix", cpus_486SDLC}, 1, MODEL_AT|MODEL_PS2, 1, 16, 1, at_wd76c10_init, NULL}, - {"AMI 386SX clone", ROM_AMI386SX, { "Intel", cpus_i386, "AMD", cpus_Am386, "Cyrix", cpus_486SDLC}, 0, MODEL_AT, 1, 256, 1, at_headland_init, NULL}, - {"MR 386DX clone", ROM_MR386DX_OPTI495, { "Intel", cpus_i386DX, "AMD", cpus_Am386DX, "Cyrix", cpus_486DLC}, 0, MODEL_AT, 1, 256, 1, at_opti495_init, NULL}, - {"AMI 386DX clone", ROM_AMI386DX_OPTI495, { "Intel", cpus_i386DX, "AMD", cpus_Am386DX, "Cyrix", cpus_486DLC}, 0, MODEL_AT, 1, 256, 1, at_opti495_init, NULL}, - {"AMI 486 clone", ROM_AMI486, { "Intel", cpus_i486, "AMD", cpus_Am486, "Cyrix", cpus_Cx486}, 0, MODEL_AT, 1, 256, 1, at_ali1429_init, NULL}, - {"AMI WinBIOS 486", ROM_WIN486, { "Intel", cpus_i486, "AMD", cpus_Am486, "Cyrix", cpus_Cx486}, 0, MODEL_AT, 1, 256, 1, at_ali1429_init, NULL}, -/* {"AMI WinBIOS 486 PCI", ROM_PCI486, { "Intel", cpus_i486, "AMD", cpus_Am486, "Cyrix", cpus_Cx486}, 0, MODEL_AT, 1, 256, 1, at_um8881f_init, NULL},*/ - {"DTK PKM-0038S E-2", ROM_DTK486, { "Intel", cpus_i486, "AMD", cpus_Am486, "Cyrix", cpus_Cx486}, 0, MODEL_AT, 1, 256, 1, at_dtk486_init, NULL}, - {"Award SiS 496/497", ROM_SIS496, { "Intel", cpus_i486, "AMD", cpus_Am486, "Cyrix", cpus_Cx486}, 0, MODEL_AT, 1, 256, 1, at_sis496_init, NULL}, - {"Rise Computer R418", ROM_R418, { "Intel", cpus_i486, "AMD", cpus_Am486, "Cyrix", cpus_Cx486}, 0, MODEL_AT, 1, 256, 1, at_r418_init, NULL}, - {"Intel Premiere/PCI", ROM_REVENGE, { "Intel", cpus_Pentium5V, "", NULL, "", NULL}, 0, MODEL_AT|MODEL_PS2, 1, 128, 1, at_batman_init, NULL}, - {"Micro Star 586MC1", ROM_586MC1, { "Intel", cpus_Pentium5V50, "",NULL, "", NULL}, 0, MODEL_AT, 1, 128, 1, at_586mc1_init, NULL}, - {"Intel Premiere/PCI II",ROM_PLATO, { "Intel", cpus_PentiumS5,"IDT", cpus_WinChip, "AMD", cpus_K5, "", NULL}, 0, MODEL_AT|MODEL_PS2, 1, 128, 1, at_plato_init, NULL}, - {"Intel Advanced/EV", ROM_ENDEAVOR, { "Intel", cpus_PentiumS5,"IDT", cpus_WinChip, "AMD", cpus_K5, "", NULL}, 0, MODEL_AT|MODEL_PS2, 1, 128, 1, at_endeavor_init, NULL}, - {"PC Partner MB500N", ROM_MB500N, { "Intel", cpus_PentiumS5,"IDT", cpus_WinChip, "AMD", cpus_K5, "", NULL}, 0, MODEL_AT|MODEL_PS2, 1, 128, 1, at_mb500n_init, NULL}, + {"IBM PC", ROM_IBMPC, "ibmpc", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, 0, 64, 640, 32, 0, xt_init, NULL }, + {"IBM XT", ROM_IBMXT, "ibmxt", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, 0, 64, 640, 64, 0, xt_init, NULL }, + {"Compaq Portable", ROM_PORTABLE, "portable", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, 0, 128, 640, 128, 0, xt_init, NULL }, + {"IBM PCjr", ROM_IBMPCJR, "ibmpcjr", {{"", cpus_pcjr}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, 0, 128, 640, 128, 0, pcjr_init, &pcjr_device }, + {"Generic XT clone", ROM_GENXT, "genxt", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, 0, 64, 640, 64, 0, xt_init, NULL }, + {"AMI XT clone", ROM_AMIXT, "amixt", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, 0, 64, 640, 64, 0, xt_init, NULL }, + {"DTK XT clone", ROM_DTKXT, "dtk", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, 0, 64, 640, 64, 0, xt_init, NULL }, + {"VTech Laser Turbo XT", ROM_LTXT, "ltxt", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, 0, 64, 1152, 64, 0, xt_laserxt_init, NULL }, + {"VTech Laser XT3", ROM_LXT3, "lxt3", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, 0, 64, 1152, 64, 0, xt_laserxt_init, NULL }, + {"Phoenix XT clone", ROM_PXXT, "pxxt", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, 0, 64, 640, 64, 0, xt_init, NULL }, + {"Juko XT clone", ROM_JUKOPC, "jukopc", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, 0, 64, 640, 64, 0, xt_init, NULL }, + {"Tandy 1000", ROM_TANDY, "tandy", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, 0, 128, 640, 128, 0, tandy1k_init, &tandy1000_device }, + {"Tandy 1000 HX", ROM_TANDY1000HX, "tandy1000hx", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, 0, 256, 640, 128, 0, tandy1k_init, &tandy1000hx_device }, + {"Tandy 1000 SL/2", ROM_TANDY1000SL2, "tandy1000sl2", {{"", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, 0, 512, 768, 128, 0, tandy1ksl2_init, NULL }, + {"Amstrad PC1512", ROM_PC1512, "pc1512", {{"", cpus_pc1512}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MODEL_AMSTRAD, 512, 640, 128, 63, ams_init, NULL }, + {"Sinclair PC200", ROM_PC200, "pc200", {{"", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MODEL_AMSTRAD, 512, 640, 128, 63, ams_init, NULL }, + {"Schneider EuroPC", ROM_EUROPC, "europc", {{"", cpus_europc}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, 0, 512, 640, 128, 0, europc_init, NULL }, + {"Olivetti M24", ROM_OLIM24, "olivetti_m24", {{"", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MODEL_OLIM24, 128, 640, 128, 0, olim24_init, NULL }, + {"Amstrad PC1640", ROM_PC1640, "pc1640", {{"", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MODEL_AMSTRAD, 640, 640, 0, 63, ams_init, NULL }, + {"Amstrad PC2086", ROM_PC2086, "pc2086", {{"", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MODEL_AMSTRAD, 640, 640, 0, 63, ams_init, NULL }, + {"Amstrad PC3086", ROM_PC3086, "pc3086", {{"", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MODEL_AMSTRAD, 640, 640, 0, 63, ams_init, NULL }, + {"IBM AT", ROM_IBMAT, "ibmat", {{"", cpus_ibmat}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MODEL_AT, 256,15872, 128, 63, ibm_at_init, NULL }, + {"Compaq Portable II", ROM_PORTABLEII, "portableii", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MODEL_AT, 1, 15, 1, 63, at_init, NULL }, + {"Compaq Portable III", ROM_PORTABLEIII, "portableiii", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MODEL_AT, 1, 15, 1, 63, at_init, NULL }, + {"Commodore PC 30 III", ROM_CMDPC30, "cmdpc30", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MODEL_AT | MODEL_HAS_IDE, 640,16384, 128, 127, cmdpc30_init, NULL }, + {"AMI 286 clone", ROM_AMI286, "ami286", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MODEL_AT | MODEL_HAS_IDE, 512,16384, 128, 127, at_neat_init, NULL }, + {"Award 286 clone", ROM_AWARD286, "award286", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MODEL_AT | MODEL_HAS_IDE, 512,16384, 128, 127, at_scat_init, NULL }, + {"Hyundai Super-286TR", ROM_SUPER286TR, "super286tr", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MODEL_AT | MODEL_HAS_IDE, 512,16384, 128, 127, at_scat_init, NULL }, + {"Samsung SPC-4200P", ROM_SPC4200P, "spc4200p", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MODEL_AT | MODEL_PS2 | MODEL_HAS_IDE, 512,16384, 128, 127, at_scat_init, NULL }, + {"IBM PS/1 model 2011", ROM_IBMPS1_2011, "ibmps1es", {{"", cpus_ps1_m2011}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MODEL_AT | MODEL_PS2 | MODEL_PS2_HDD, 512,16384, 512, 127, ps1_m2011_init, NULL }, + {"IBM PS/2 Model 30-286", ROM_IBMPS2_M30_286, "ibmps2_m30_286", {{"", cpus_ps2_m30_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MODEL_AT | MODEL_PS2 | MODEL_PS2_HDD, 1, 16, 1, 127, ps2_m30_286_init, NULL }, + {"IBM PS/2 Model 50", ROM_IBMPS2_M50, "ibmps2_m50", {{"", cpus_ps2_m30_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MODEL_AT | MODEL_PS2 | MODEL_PS2_HDD | MODEL_MCA, 1, 16, 1, 63, ps2_model_50_init, NULL }, + {"IBM PS/1 model 2121", ROM_IBMPS1_2121, "ibmps1_2121", {{"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}, {"", NULL}, {"", NULL}}, 1, MODEL_AT | MODEL_PS2 | MODEL_HAS_IDE, 1, 16, 1, 127, ps1_m2121_init, NULL }, + {"IBM PS/1 m.2121 + ISA", ROM_IBMPS1_2121_ISA, "ibmps1_2121_isa", {{"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}, {"", NULL}, {"", NULL}}, 0, MODEL_AT | MODEL_PS2 | MODEL_HAS_IDE, 1, 16, 1, 127, ps1_m2121_init, NULL }, + {"IBM PS/2 Model 55SX", ROM_IBMPS2_M55SX, "ibmps2_m55sx", {{"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}, {"", NULL}, {"", NULL}}, 0, MODEL_AT | MODEL_PS2 | MODEL_PS2_HDD | MODEL_MCA, 1, 8, 1, 63, ps2_model_55sx_init, NULL }, + {"DTK 386SX clone", ROM_DTK386, "dtk386", {{"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}, {"", NULL}, {"", NULL}}, 0, MODEL_AT | MODEL_HAS_IDE, 512,16384, 128, 127, at_neat_init, NULL }, + {"Amstrad MegaPC", ROM_MEGAPC, "megapc", {{"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}, {"", NULL}, {"", NULL}}, 1, MODEL_AT | MODEL_PS2 | MODEL_HAS_IDE, 1, 16, 1, 127, at_wd76c10_init, NULL }, + {"AMI 386SX clone", ROM_AMI386SX, "ami386", {{"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}, {"", NULL}, {"", NULL}}, 0, MODEL_AT | MODEL_HAS_IDE, 512,16384, 128, 127, at_headland_init, NULL }, + {"Compaq Deskpro 386", ROM_DESKPRO_386, "dekspro386", {{"Intel", cpus_i386DX}, {"AMD", cpus_Am386DX}, {"Cyrix", cpus_486DLC}, {"", NULL}, {"", NULL}}, 0, MODEL_AT, 1, 15, 1, 63, deskpro386_init, NULL }, + {"Compaq Portable III 386", ROM_PORTABLEIII386, "portableiii386", {{"Intel", cpus_i386DX}, {"AMD", cpus_Am386DX}, {"Cyrix", cpus_486DLC}, {"", NULL}, {"", NULL}}, 0, MODEL_AT, 1, 15, 1, 63, at_init, NULL }, + {"IBM PS/2 Model 80", ROM_IBMPS2_M80, "ibmps2_m80", {{"Intel", cpus_i386DX}, {"AMD", cpus_Am386DX}, {"Cyrix", cpus_486DLC}, {"", NULL}, {"", NULL}}, 0, MODEL_AT | MODEL_PS2 | MODEL_PS2_HDD | MODEL_MCA, 1, 12, 1, 63, ps2_model_80_init, NULL }, + {"Amstrad MegaPC 386DX", ROM_MEGAPCDX, "megapcdx", {{"Intel", cpus_i386DX}, {"AMD", cpus_Am386DX}, {"Cyrix", cpus_486DLC}, {"", NULL}, {"", NULL}}, 1, MODEL_AT | MODEL_PS2 | MODEL_HAS_IDE, 1, 16, 1, 127, at_wd76c10_init, NULL }, + {"MR 386DX clone", ROM_MR386DX_OPTI495, "mr386dx", {{"Intel", cpus_i386DX}, {"AMD", cpus_Am386DX}, {"Cyrix", cpus_486DLC}, {"", NULL}, {"", NULL}}, 0, MODEL_AT | MODEL_HAS_IDE, 1, 64, 1, 127, at_opti495_init, NULL }, + {"AMI 386DX clone", ROM_AMI386DX_OPTI495, "ami386dx", {{"Intel", cpus_i386DX}, {"AMD", cpus_Am386DX}, {"Cyrix", cpus_486DLC}, {"", NULL}, {"", NULL}}, 0, MODEL_AT | MODEL_HAS_IDE, 1, 64, 1, 127, at_opti495_init, NULL }, + {"IBM PS/1 model 2133", ROM_IBMPS1_2133, "ibmps1_2133", {{"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}, {"", NULL}, {"", NULL}}, 0, MODEL_AT | MODEL_PS2 | MODEL_HAS_IDE, 1, 64, 1, 127, ps1_m2133_init, NULL }, + {"AMI 486 clone", ROM_AMI486, "ami486", {{"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}, {"", NULL}, {"", NULL}}, 0, MODEL_AT | MODEL_HAS_IDE, 1, 64, 1, 127, at_ali1429_init, NULL }, + {"AMI WinBIOS 486", ROM_WIN486, "win486", {{"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}, {"", NULL}, {"", NULL}}, 0, MODEL_AT | MODEL_HAS_IDE, 1, 64, 1, 127, at_ali1429_init, NULL }, + {"DTK PKM-0038S E-2", ROM_DTK486, "dtk486", {{"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}, {"", NULL}, {"", NULL}}, 0, MODEL_AT | MODEL_HAS_IDE, 1, 64, 1, 127, at_dtk486_init, NULL }, + {"Rise Computer R418", ROM_R418, "r418", {{"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}, {"", NULL}, {"", NULL}}, 0, MODEL_AT | MODEL_HAS_IDE | MODEL_PCI, 1, 64, 1, 127, at_r418_init, NULL }, + {"Intel Premiere/PCI", ROM_REVENGE, "revenge", {{"Intel", cpus_Pentium5V}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MODEL_AT | MODEL_PS2 | MODEL_HAS_IDE | MODEL_PCI, 1, 128, 1, 127, at_batman_init, NULL }, #if 0 - {"NEC PowerMate V", ROM_POWERMATE_V, { "Intel", cpus_PentiumS5,"IDT", cpus_WinChip, "AMD", cpus_K5, "", NULL}, 0, MODEL_AT|MODEL_PS2, 1, 128, 1, at_powermate_v_init, NULL}, + {"Micro Star 586MC1", ROM_586MC1, "586mc1", {{"Intel", cpus_Pentium5V50}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MODEL_AT | MODEL_PS2 | MODEL_HAS_IDE | MODEL_PCI, 1, 128, 1, 127, at_586mc1_init, NULL }, #endif - {"Intel Advanced/ATX", ROM_THOR, { "Intel", cpus_Pentium, "IDT", cpus_WinChip, "Cyrix", cpus_6x86, "AMD", cpus_K56, "", NULL}, 0, MODEL_AT|MODEL_PS2, 1, 256, 1, at_endeavor_init, NULL}, - {"MR Intel Advanced/ATX", ROM_MRTHOR, { "Intel", cpus_Pentium, "IDT", cpus_WinChip, "Cyrix", cpus_6x86, "AMD", cpus_K56, "", NULL}, 0, MODEL_AT|MODEL_PS2, 1, 256, 1, at_endeavor_init, NULL}, - {"ASUS P/I-P54TP4XE", ROM_P54TP4XE, { "Intel", cpus_PentiumS5, "IDT", cpus_WinChip, "AMD", cpus_K5, "", NULL}, 0, MODEL_AT|MODEL_PS2, 1, 512, 1, at_p54tp4xe_init, NULL}, - // {"Intel Advanced/ML", ROM_MARL, { "Intel", cpus_Pentium, "IDT", cpus_WinChip, "Cyrix", cpus_6x86, "AMD", cpus_K56, "", NULL}, 0, MODEL_AT|MODEL_PS2, 1, 512, 1, at_marl_init, NULL}, - {"Acer M3a", ROM_ACERM3A, { "Intel", cpus_Pentium, "IDT", cpus_WinChip, "Cyrix", cpus_6x86, "AMD", cpus_K56, "", NULL}, 0, MODEL_AT|MODEL_PS2, 1, 512, 1, at_acerm3a_init, NULL}, - {"Acer V35N", ROM_ACERV35N, { "Intel", cpus_Pentium, "IDT", cpus_WinChip, "Cyrix", cpus_6x86, "AMD", cpus_K56, "", NULL}, 0, MODEL_AT|MODEL_PS2, 1, 512, 1, at_acerv35n_init, NULL}, - {"ASUS P/I-P55T2P4", ROM_P55T2P4, { "Intel", cpus_Pentium, "IDT", cpus_WinChip, "Cyrix", cpus_6x86, "AMD", cpus_K56, "", NULL}, 0, MODEL_AT|MODEL_PS2, 1, 512, 1, at_p55t2p4_init, NULL}, - {"Award 430VX PCI", ROM_430VX, { "Intel", cpus_Pentium, "IDT", cpus_WinChip, "Cyrix", cpus_6x86, "AMD", cpus_K56, "", NULL}, 0, MODEL_AT|MODEL_PS2, 1, 256, 1, at_i430vx_init, NULL}, - {"Epox P55-VA", ROM_P55VA, { "Intel", cpus_Pentium, "IDT", cpus_WinChip, "Cyrix", cpus_6x86, "AMD", cpus_K56, "", NULL}, 0, MODEL_AT|MODEL_PS2, 1, 256, 1, at_p55va_init, NULL}, - {"ASUS P/I-P55TVP4", ROM_P55TVP4, { "Intel", cpus_Pentium, "IDT", cpus_WinChip, "Cyrix", cpus_6x86, "AMD", cpus_K56, "", NULL}, 0, MODEL_AT|MODEL_PS2, 1, 256, 1, at_p55tvp4_init, NULL}, - {"Award 440FX PCI", ROM_440FX, { "Intel", cpus_PentiumPro, "", NULL, "", NULL}, 0, MODEL_AT|MODEL_PS2, 1, 1024, 1, at_i440fx_init, NULL}, - // {"Award 440FX PCI", ROM_440FX, { "Intel", cpus_PentiumPro,"Klamath", cpus_Pentium2, "Deschutes", cpus_Pentium2D}, 0, MODEL_AT|MODEL_PS2, 1, 1024, 1, at_i440fx_init, NULL}, - {"", -1, {"", 0, "", 0, "", 0}, 0,0,0, 0} + {"Intel Premiere/PCI II", ROM_PLATO, "plato", {{ "Intel", cpus_PentiumS5}, {"IDT", cpus_WinChip}, {"AMD", cpus_K5}, {"", NULL}, {"", NULL}}, 0, MODEL_AT | MODEL_PS2 | MODEL_HAS_IDE | MODEL_PCI, 1, 128, 1, 127, at_plato_init, NULL }, + {"Intel Advanced/EV", ROM_ENDEAVOR, "endeavor", {{ "Intel", cpus_PentiumS5}, {"IDT", cpus_WinChip}, {"AMD", cpus_K5}, {"", NULL}, {"", NULL}}, 0, MODEL_AT | MODEL_PS2 | MODEL_HAS_IDE | MODEL_PCI, 1, 128, 1, 127, at_endeavor_init, NULL }, + {"Intel Advanced/ZP", ROM_ZAPPA, "zappa", {{ "Intel", cpus_PentiumS5}, {"IDT", cpus_WinChip}, {"AMD", cpus_K5}, {"", NULL}, {"", NULL}}, 0, MODEL_AT | MODEL_PS2 | MODEL_HAS_IDE | MODEL_PCI, 1, 128, 1, 127, at_endeavor_init, NULL }, + {"PC Partner MB500N", ROM_MB500N, "mb500n", {{ "Intel", cpus_PentiumS5}, {"IDT", cpus_WinChip}, {"AMD", cpus_K5}, {"", NULL}, {"", NULL}}, 0, MODEL_AT | MODEL_PS2 | MODEL_HAS_IDE | MODEL_PCI, 1, 128, 1, 127, at_mb500n_init, NULL }, + {"President Award 430FX PCI", ROM_PRESIDENT, "president", {{ "Intel", cpus_PentiumS5}, {"IDT", cpus_WinChip}, {"AMD", cpus_K5}, {"", NULL}, {"", NULL}}, 0, MODEL_AT | MODEL_HAS_IDE | MODEL_PCI, 1, 128, 1, 127, at_president_init, NULL }, + {"ASUS P/I-P54TP4XE", ROM_P54TP4XE, "p54tp4xe", {{ "Intel", cpus_PentiumS5}, {"IDT", cpus_WinChip}, {"AMD", cpus_K5}, {"", NULL}, {"", NULL}}, 0, MODEL_AT | MODEL_PS2 | MODEL_HAS_IDE | MODEL_PCI, 1, 256, 1, 127, at_p54tp4xe_init, NULL }, + {"Intel Advanced/ATX", ROM_THOR, "thor", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"AMD", cpus_K56}, {"Cyrix", cpus_6x86},{"", NULL}}, 0, MODEL_AT | MODEL_PS2 | MODEL_HAS_IDE | MODEL_PCI, 1, 256, 1, 127, at_endeavor_init, NULL }, + {"MR Intel Advanced/ATX", ROM_MRTHOR, "mrthor", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"AMD", cpus_K56}, {"Cyrix", cpus_6x86},{"", NULL}}, 0, MODEL_AT | MODEL_PS2 | MODEL_HAS_IDE | MODEL_PCI, 1, 256, 1, 127, at_endeavor_init, NULL }, + {"AOpen AP53", ROM_AP53, "ap53", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"AMD", cpus_K56}, {"Cyrix", cpus_6x86},{"", NULL}}, 0, MODEL_AT | MODEL_PS2 | MODEL_HAS_IDE | MODEL_PCI, 1, 256, 1, 127, at_ap53_init, NULL }, + {"ASUS P/I-P55T2S", ROM_P55T2S, "p55t2s", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"AMD", cpus_K56}, {"Cyrix", cpus_6x86},{"", NULL}}, 0, MODEL_AT | MODEL_PS2 | MODEL_HAS_IDE | MODEL_PCI, 1, 256, 1, 127, at_p55t2s_init, NULL }, + {"Acer M3a", ROM_ACERM3A, "acerm3a", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"AMD", cpus_K56}, {"Cyrix", cpus_6x86},{"", NULL}}, 0, MODEL_AT | MODEL_PS2 | MODEL_HAS_IDE | MODEL_PCI, 1, 256, 1, 127, at_acerm3a_init, NULL }, + {"Acer V35n", ROM_ACERV35N, "acerv35n", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"AMD", cpus_K56}, {"Cyrix", cpus_6x86},{"", NULL}}, 0, MODEL_AT | MODEL_PS2 | MODEL_HAS_IDE | MODEL_PCI, 1, 256, 1, 127, at_acerv35n_init, NULL }, + {"ASUS P/I-P55T2P4", ROM_P55T2P4, "p55r2p4", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"AMD", cpus_K56}, {"Cyrix", cpus_6x86},{"", NULL}}, 0, MODEL_AT | MODEL_PS2 | MODEL_HAS_IDE | MODEL_PCI, 1, 256, 1, 127, at_p55t2p4_init, NULL }, + {"Epox P55-VA", ROM_P55VA, "p55va", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"AMD", cpus_K56}, {"Cyrix", cpus_6x86},{"", NULL}}, 0, MODEL_AT | MODEL_PS2 | MODEL_HAS_IDE | MODEL_PCI, 1, 256, 1, 127, at_p55va_init, NULL }, + {"ASUS P/I-P55TVP4", ROM_P55TVP4, "p55tvp4", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"AMD", cpus_K56}, {"Cyrix", cpus_6x86},{"", NULL}}, 0, MODEL_AT | MODEL_PS2 | MODEL_HAS_IDE | MODEL_PCI, 1, 256, 1, 127, at_p55tvp4_init, NULL }, + {"Tyan Titan-Pro AT", ROM_440FX, "440fx", {{"Intel", cpus_PentiumPro}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MODEL_AT | MODEL_PS2 | MODEL_HAS_IDE | MODEL_PCI, 1, 256, 1, 127, at_i440fx_init, NULL }, + {"Tyan Titan-Pro ATX", ROM_S1668, "tpatx", {{"Intel", cpus_PentiumPro}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MODEL_AT | MODEL_PS2 | MODEL_HAS_IDE | MODEL_PCI, 1, 256, 1, 127, at_s1668_init, NULL }, + {"", -1, "", {{"", 0}, {"", 0}, {"", 0}}, 0,0,0,0, 0 } }; -int model_count() + +int model_count(void) { return (sizeof(models) / sizeof(MODEL)) - 1; } -int model_getromset() +int model_getromset(void) { return models[model].id; } +int model_getromset_ex(int m) +{ + return models[m].id; +} + int model_getmodel(int romset) { int c = 0; @@ -214,42 +254,86 @@ device_t *model_getdevice(int model) return models[model].device; } -void common_init() +char *model_get_internal_name(void) +{ + return models[model].internal_name; +} + +char *model_get_internal_name_ex(int m) +{ + return models[m].internal_name; +} + +int model_get_nvrmask(int m) +{ + return models[m].nvrmask; +} + +int model_get_model_from_internal_name(char *s) +{ + int c = 0; + + while (models[c].id != -1) + { + if (!strcmp(models[c].internal_name, s)) + return c; + c++; + } + + return 0; +} + +void common_init(void) { dma_init(); fdc_add(); - lpt_init(); + if (lpt_enabled) + { + lpt_init(); + } pic_init(); pit_init(); - serial1_init(0x3f8, 4); - serial2_init(0x2f8, 3); + if (serial_enabled[0]) + { + serial_setup(1, SERIAL1_ADDR, SERIAL1_IRQ); + } + if (serial_enabled[1]) + { + serial_setup(2, SERIAL2_ADDR, SERIAL2_IRQ); + } } -void xt_init() +void xt_init(void) { common_init(); mem_add_bios(); - pit_set_out_func(1, pit_refresh_timer_xt); + pit_set_out_func(&pit, 1, pit_refresh_timer_xt); keyboard_xt_init(); - xtide_init(); nmi_init(); if (joystick_type != 7) device_add(&gameport_device); + if (bugger_enabled) + { + bugger_init(); + } } -void pcjr_init() +void pcjr_init(void) { mem_add_bios(); fdc_add_pcjr(); pic_init(); pit_init(); - pit_set_out_func(0, pit_irq0_timer_pcjr); - serial1_init(0x2f8, 3); + pit_set_out_func(&pit, 0, pit_irq0_timer_pcjr); + if (serial_enabled[0]) + { + serial_setup(1, 0x2f8, 3); + } keyboard_pcjr_init(); device_add(&sn76489_device); nmi_mask = 0x80; } -void tandy1k_init() +void tandy1k_init(void) { TANDY = 1; common_init(); @@ -259,27 +343,24 @@ void tandy1k_init() device_add(&sn76489_device); else device_add(&ncr8496_device); - xtide_init(); nmi_init(); if (romset != ROM_TANDY) device_add(&tandy_eeprom_device); if (joystick_type != 7) device_add(&gameport_device); } -void tandy1ksl2_init() +void tandy1ksl2_init(void) { -// TANDY = 1; common_init(); mem_add_bios(); keyboard_tandy_init(); device_add(&pssj_device); - xtide_init(); nmi_init(); device_add(&tandy_rom_device); device_add(&tandy_eeprom_device); if (joystick_type != 7) device_add(&gameport_device); } -void ams_init() +void ams_init(void) { AMSTRAD = 1; common_init(); @@ -287,336 +368,554 @@ void ams_init() amstrad_init(); keyboard_amstrad_init(); nvr_init(); - xtide_init(); nmi_init(); fdc_set_dskchg_activelow(); if (joystick_type != 7) device_add(&gameport_device); } -void europc_init() +void europc_init(void) { common_init(); mem_add_bios(); jim_init(); keyboard_xt_init(); - xtide_init(); nmi_init(); if (joystick_type != 7) device_add(&gameport_device); } -void olim24_init() +void olim24_init(void) { common_init(); mem_add_bios(); keyboard_olim24_init(); nvr_init(); olivetti_m24_init(); - xtide_init(); nmi_init(); if (joystick_type != 7) device_add(&gameport_device); } -void at_init() +void xt_laserxt_init(void) +{ + xt_init(); + laserxt_init(); +} + +void at_init(void) { AT = 1; common_init(); - lpt2_remove(); + if (lpt_enabled) + { + lpt2_remove(); + } mem_add_bios(); - pit_set_out_func(1, pit_refresh_timer_at); + pit_set_out_func(&pit, 1, pit_refresh_timer_at); dma16_init(); - ide_init(); keyboard_at_init(); nvr_init(); pic2_init(); if (joystick_type != 7) device_add(&gameport_device); + if (bugger_enabled) + { + bugger_init(); + } } -void deskpro386_init() +void ibm_at_init(void) +{ + at_init(); + mem_remap_top_384k(); +} + +void at_ide_init(void) +{ + at_init(); + ide_init(); +} + +void cmdpc30_init(void) +{ + at_ide_init(); + mem_remap_top_384k(); +} + +void deskpro386_init(void) { at_init(); compaq_init(); } -void ps1_common_init() +void ps1_common_init(void) { AT = 1; common_init(); mem_add_bios(); - pit_set_out_func(1, pit_refresh_timer_at); + pit_set_out_func(&pit, 1, pit_refresh_timer_at); dma16_init(); - ide_init(); + if (romset != ROM_IBMPS1_2011) + { + ide_init(); + } keyboard_at_init(); nvr_init(); pic2_init(); - fdc_set_dskchg_activelow(); - device_add(&ps1_audio_device); + if (romset != ROM_IBMPS1_2133) + { + fdc_set_dskchg_activelow(); + device_add(&ps1_audio_device); + } /*PS/1 audio uses ports 200h and 202-207h, so only initialise gameport on 201h*/ if (joystick_type != 7) device_add(&gameport_201_device); } -void ps1_m2011_init() +void ps1_m2011_init(void) { ps1_common_init(); ps1mb_init(); + mem_remap_top_384k(); } -void ps1_m2121_init() +void ps1_m2121_init(void) { ps1_common_init(); ps1mb_m2121_init(); fdc_set_ps1(); } -void at_neat_init() +void ps1_m2133_init(void) { - at_init(); + ps1_common_init(); + ps1mb_m2133_init(); +} + +void ps2_m30_286_init(void) +{ + AT = 1; + common_init(); + mem_add_bios(); + pit_set_out_func(&pit, 1, pit_refresh_timer_at); + dma16_init(); + keyboard_at_init(); + nvr_init(); + pic2_init(); + ps2board_init(); + fdc_set_dskchg_activelow(); + fdc_set_ps1(); +} + +static void ps2_common_init(void) +{ + AT = 1; + common_init(); + mem_add_bios(); + dma16_init(); + ps2_dma_init(); + ide_init(); + keyboard_at_init(); + keyboard_at_init_ps2(); + mouse_ps2_init(); + nvr_init(); + pic2_init(); + + pit_ps2_init(); +} + +void ps2_model_50_init(void) +{ + ps2_common_init(); + ps2_mca_board_model_50_init(); +} + +void ps2_model_55sx_init(void) +{ + ps2_common_init(); + ps2_mca_board_model_55sx_init(); +} + +void ps2_model_80_init(void) +{ + ps2_common_init(); + ps2_mca_board_model_80_type2_init(); +} + +void at_neat_init(void) +{ + at_ide_init(); neat_init(); } -void at_scat_init() +void at_scat_init(void) { - at_init(); + at_ide_init(); scat_init(); } -void at_acer386sx_init() +/* void at_acer386sx_init(void) { - at_init(); + at_ide_init(); acer386sx_init(); } -void at_wd76c10_init() +void at_82335_init(void) { - at_init(); + at_ide_init(); + i82335_init(); +} */ + +void at_wd76c10_init(void) +{ + at_ide_init(); wd76c10_init(); } -void at_headland_init() +void at_headland_init(void) { - at_init(); + at_ide_init(); headland_init(); } -void at_opti495_init() +void at_opti495_init(void) { - at_init(); + at_ide_init(); opti495_init(); } -void at_ali1429_init() +void secondary_ide_check(void) { - at_init(); - ali1429_init(); - if (atapi_cdrom_channel <= 1) ide_sec_disable(); + int i = 0; + int secondary_cdroms = 0; + + for (i = 0; i < CDROM_NUM; i++) + { + if ((cdrom_drives[i].ide_channel >= 2) && (cdrom_drives[i].ide_channel <= 3) && ((cdrom_drives[i].bus_type == CDROM_BUS_ATAPI_PIO_ONLY) || (cdrom_drives[i].bus_type == CDROM_BUS_ATAPI_PIO_AND_DMA))) + { + secondary_cdroms++; + } + } + if (!secondary_cdroms) ide_sec_disable(); } -/* void at_um8881f_init() +void at_ali1429_init(void) { - at_init(); + ali1429_reset(); + + at_ide_init(); + ali1429_init(); + + secondary_ide_check(); +} + +/* void at_um8881f_init(void) +{ + at_ide_init(); pci_init(PCI_CONFIG_TYPE_1, 0, 31); um8881f_init(); } */ -void at_dtk486_init() +void at_dtk486_init(void) { - at_init(); + at_ide_init(); memregs_init(); sis85c471_init(); - if (atapi_cdrom_channel <= 1) ide_sec_disable(); + secondary_ide_check(); } -void at_sis496_init() +void at_sis496_init(void) { - at_init(); + at_ide_init(); memregs_init(); - pci_init(PCI_CONFIG_TYPE_1, 0, 31); - device_add(&sis496_device); + pci_init(PCI_CONFIG_TYPE_1); + pci_slot(0xb); + pci_slot(0xd); + pci_slot(0xf); + sis496_init(); + trc_init(); } -void at_r418_init() +void at_r418_init(void) { at_sis496_init(); fdc37c665_init(); } -void at_premiere_common_init() +void at_premiere_common_init(void) { - at_init(); + at_ide_init(); memregs_init(); - pci_init(PCI_CONFIG_TYPE_2, 0xd, 0x10); - sio_init(1); + pci_init(PCI_CONFIG_TYPE_2); + pci_slot(0xc); + pci_slot(0xe); + pci_slot(0x6); + sio_init(1, 0xc, 0xe, 0x6, 0); fdc37c665_init(); intel_batman_init(); device_add(&intel_flash_bxt_ami_device); } -void at_batman_init() +void at_batman_init(void) { at_premiere_common_init(); i430lx_init(); } -void at_586mc1_init() +#if 0 +void at_586mc1_init(void) { - at_init(); + at_ide_init(); memregs_init(); - pci_init(PCI_CONFIG_TYPE_2, 0xd, 0x10); + pci_init(PCI_CONFIG_TYPE_2); i430lx_init(); - sio_init(1); + pci_slot(0xc); + pci_slot(0xe); + pci_slot(0x6); + sio_init(1, 0xc, 0xe, 0x6, 0); device_add(&intel_flash_bxt_device); - if (atapi_cdrom_channel <= 1) ide_sec_disable(); + secondary_ide_check(); } +#endif -void at_plato_init() +void at_plato_init(void) { at_premiere_common_init(); i430nx_init(); } -void at_advanced_common_init() +void at_advanced_common_init(void) { - at_init(); + at_ide_init(); memregs_init(); - pci_init(PCI_CONFIG_TYPE_1, 0xd, 0x10); + pci_init(PCI_CONFIG_TYPE_1); + pci_slot(0xd); + pci_slot(0xe); + pci_slot(0xf); + pci_slot(0x10); i430fx_init(); - piix_init(7); + piix_init(7, 0xd, 0xe, 0xf, 0x10); pc87306_init(); } -void at_endeavor_init() +void at_endeavor_init(void) { at_advanced_common_init(); device_add(&intel_flash_bxt_ami_device); } +void at_mb500n_init(void) +{ + at_ide_init(); + pci_init(PCI_CONFIG_TYPE_1); + pci_slot(0x14); + pci_slot(0x13); + pci_slot(0x12); + pci_slot(0x11); + i430fx_init(); + piix_init(7, 0x14, 0x13, 0x12, 0x11); + fdc37c665_init(); + device_add(&intel_flash_bxt_device); +} + +void at_president_init(void) +{ + at_ide_init(); + memregs_init(); + pci_init(PCI_CONFIG_TYPE_1); + pci_slot(8); + pci_slot(9); + pci_slot(10); + pci_slot(11); + i430fx_init(); + piix_init(7, 8, 9, 10, 11); #if 0 -void at_marl_init() -{ - at_advanced_common_init(); - // device_add(&intel_flash_100bxt_ami_device); -} + superio_detect_init(); #endif - -void at_mb500n_init() -{ - at_init(); - pci_init(PCI_CONFIG_TYPE_1, 0xd, 0x10); - i430fx_init(); - piix_init(7); - fdc37c665_init(); - device_add(&intel_flash_bxt_device); -} - -#if 0 -void at_powermate_v_init() -{ - at_init(); - memregs_init(); - pci_init(PCI_CONFIG_TYPE_1, 0, 31); - i430fx_init(); - piix_init(7); - fdc37c665_init(); - acerm3a_io_init(); - device_add(&intel_flash_bxt_device); -} -#endif - -void at_p54tp4xe_init() -{ - at_init(); - memregs_init(); - pci_init(PCI_CONFIG_TYPE_1, 0xd, 0x10); - i430fx_init(); - piix_init(7); - fdc37c665_init(); - device_add(&intel_flash_bxt_device); -} - -void at_acerm3a_init() -{ - at_init(); - memregs_init(); - pci_init(PCI_CONFIG_TYPE_1, 0xd, 0x10); - i430hx_init(); - piix3_init(7); - fdc37c932fr_init(); - acerm3a_io_init(); - device_add(&intel_flash_bxb_device); -} - -void at_acerv35n_init() -{ - at_init(); - memregs_init(); - pci_init(PCI_CONFIG_TYPE_1, 0xd, 0x10); - i430hx_init(); - piix3_init(7); - fdc37c932fr_init(); - acerm3a_io_init(); - device_add(&intel_flash_bxb_device); -} - -void at_p55t2p4_init() -{ - at_init(); - memregs_init(); - pci_init(PCI_CONFIG_TYPE_1, 0, 31); - i430hx_init(); - piix3_init(7); w83877f_init(); device_add(&intel_flash_bxt_device); } -void at_i430vx_init() +void at_p54tp4xe_init(void) { - at_init(); + at_ide_init(); memregs_init(); - pci_init(PCI_CONFIG_TYPE_1, 0, 31); + pci_init(PCI_CONFIG_TYPE_1); + pci_slot(12); + pci_slot(11); + pci_slot(10); + pci_slot(9); + i430fx_init(); + piix_init(7, 12, 11, 10, 9); + fdc37c665_init(); + device_add(&intel_flash_bxt_device); +} + +void at_ap53_init(void) +{ + at_ide_init(); + memregs_init(); + powermate_memregs_init(); + pci_init(PCI_CONFIG_TYPE_1); + pci_slot(0x11); + pci_slot(0x12); + pci_slot(0x13); + pci_slot(0x14); + i430hx_init(); + piix_init(7, 0x11, 0x12, 0x13, 0x14); + fdc37c669_init(); + acerm3a_io_init(); + device_add(&intel_flash_bxt_device); +} + +void at_p55t2s_init(void) +{ + at_ide_init(); + memregs_init(); + powermate_memregs_init(); + pci_init(PCI_CONFIG_TYPE_1); + pci_slot(0x12); + pci_slot(0x11); + pci_slot(0x14); + pci_slot(0x13); + i430hx_init(); + piix_init(7, 0x12, 0x11, 0x14, 0x13); + pc87306_init(); + acerm3a_io_init(); + device_add(&intel_flash_bxt_device); +} + +void at_acerm3a_init(void) +{ + at_ide_init(); + memregs_init(); + powermate_memregs_init(); + pci_init(PCI_CONFIG_TYPE_1); + pci_slot(0xc); + pci_slot(0xd); + pci_slot(0xe); + pci_slot(0xf); + i430hx_init(); + piix3_init(7, 0xc, 0xd, 0xe, 0xf); + fdc37c932fr_init(); + acerm3a_io_init(); + device_add(&intel_flash_bxb_device); +} + +void at_acerv35n_init(void) +{ + at_ide_init(); + memregs_init(); + powermate_memregs_init(); + pci_init(PCI_CONFIG_TYPE_1); + pci_slot(0x11); + pci_slot(0x12); + pci_slot(0x13); + pci_slot(0x14); + i430hx_init(); + piix3_init(7, 0x11, 0x12, 0x13, 0x14); + fdc37c932fr_init(); + acerm3a_io_init(); + device_add(&intel_flash_bxb_device); +} + +void at_p55t2p4_init(void) +{ + at_ide_init(); + memregs_init(); + pci_init(PCI_CONFIG_TYPE_1); + pci_slot(12); + pci_slot(11); + pci_slot(10); + pci_slot(9); + i430hx_init(); + piix3_init(7, 12, 11, 10, 9); + w83877f_init(); + device_add(&intel_flash_bxt_device); +} + +#if 0 +void at_i430vx_init(void) +{ + at_ide_init(); + memregs_init(); + pci_init(PCI_CONFIG_TYPE_1); + pci_slot(0x11); + pci_slot(0x12); + pci_slot(0x13); + pci_slot(0x14); i430vx_init(); - piix3_init(7); + piix3_init(7, 17, 18, 20, 19); um8669f_init(); device_add(&intel_flash_bxt_device); } +#endif -void at_p55tvp4_init() +void at_p55tvp4_init(void) { - at_init(); + at_ide_init(); memregs_init(); - pci_init(PCI_CONFIG_TYPE_1, 0, 31); + pci_init(PCI_CONFIG_TYPE_1); + pci_slot(12); + pci_slot(11); + pci_slot(10); + pci_slot(9); i430vx_init(); - piix3_init(7); + piix3_init(7, 12, 11, 10, 9); w83877f_init(); device_add(&intel_flash_bxt_device); } -void at_p55va_init() +void at_p55va_init(void) { - at_init(); + at_ide_init(); memregs_init(); - pci_init(PCI_CONFIG_TYPE_1, 0, 31); + pci_init(PCI_CONFIG_TYPE_1); + pci_slot(8); + pci_slot(9); + pci_slot(10); + pci_slot(11); i430vx_init(); - piix3_init(7); + piix3_init(7, 8, 9, 10, 11); fdc37c932fr_init(); device_add(&intel_flash_bxt_device); } -void at_i440fx_init() +void at_i440fx_init(void) { - at_init(); + at_ide_init(); memregs_init(); - pci_init(PCI_CONFIG_TYPE_1, 0, 31); - i440fx_init(); - piix3_init(7); + pci_init(PCI_CONFIG_TYPE_1); + pci_slot(0xe); + pci_slot(0xd); + pci_slot(0xc); + pci_slot(0xb); + i430vx_init(); + piix3_init(7, 0xe, 0xd, 0xc, 0xb); fdc37c665_init(); device_add(&intel_flash_bxt_device); } -void model_init() +void at_s1668_init(void) { - pclog("Initting as %s\n", model_getname()); + at_ide_init(); + memregs_init(); + pci_init(PCI_CONFIG_TYPE_1); + pci_slot(0xe); + pci_slot(0xd); + pci_slot(0xc); + pci_slot(0xb); + i440fx_init(); + piix3_init(7, 0xe, 0xd, 0xc, 0xb); + fdc37c665_init(); + device_add(&intel_flash_bxt_device); +} + +void model_init(void) +{ + pclog("Initializing as %s\n", model_getname()); AMSTRAD = AT = PCI = TANDY = 0; io_init(); + pci_reset_handler.pci_master_reset = NULL; + pci_reset_handler.pci_set_reset = NULL; + pci_reset_handler.super_io_reset = NULL; fdc_update_is_nsc(0); models[model].init(); if (models[model].device) diff --git a/src/model.h b/src/model.h index 8eb2cc152..02b8ddcb8 100644 --- a/src/model.h +++ b/src/model.h @@ -1,38 +1,109 @@ -/* Copyright holders: Sarah Walker, Tohka - see COPYING for more details -*/ -#define MODEL_AT 1 -#define MODEL_PS2 2 -#define MODEL_AMSTRAD 4 -#define MODEL_OLIM24 8 -#define MODEL_NEC 16 -#define MODEL_FUJITSU 32 -#define MODEL_RM 64 +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Handling of the emulated machines. + * + * Version: @(#)model.h 1.0.2 2017/06/17 + * + * Authors: Sarah Walker, + * Miran Grca, + * Copyright 2008-2017 Sarah Walker. + * Copyright 2016-2017 Miran Grca. + */ +#ifndef EMU_MODEL_H +# define EMU_MODEL_H -typedef struct -{ - char name[24]; - int id; - struct - { - char name[16]; - CPU *cpus; - } cpu[5]; - int fixed_gfxcard; - int flags; - int min_ram, max_ram; - int ram_granularity; - void (*init)(); - struct device_t *device; + +#define MODEL_AT 1 +#define MODEL_PS2 2 +#define MODEL_AMSTRAD 4 +#define MODEL_OLIM24 8 +#define MODEL_HAS_IDE 16 +#define MODEL_MCA 32 +#define MODEL_PCI 64 +#define MODEL_PS2_HDD 128 +#define MODEL_NEC 256 +#define MODEL_FUJITSU 512 +#define MODEL_RM 1024 + + +typedef struct { + char name[32]; + int id; + char internal_name[24]; + struct { + char name[16]; + CPU *cpus; + } cpu[5]; + int fixed_gfxcard; + int flags; + int min_ram, max_ram; + int ram_granularity; + int nvrmask; + void (*init)(void); + device_t *device; } MODEL; -extern MODEL models[]; -extern int model; +/* Global variables. */ +extern MODEL models[]; +extern int model; -int model_count(); -int model_getromset(); -int model_getmodel(int romset); -char *model_getname(); -void model_init(); -struct device_t *model_getdevice(int model); + +/* Core functions. */ +extern int model_count(void); +extern int model_getromset(void); +extern int model_getmodel(int romset); +extern char *model_getname(void); +extern char *model_get_internal_name(void); +extern int model_get_model_from_internal_name(char *s); +extern void model_init(void); +extern device_t *model_getdevice(int model); +extern int model_getromset_ex(int m); +extern char *model_get_internal_name_ex(int m); +extern int model_get_nvrmask(int m); + + +/* Global variables for boards and systems. */ +#ifdef EMU_MOUSE_H +extern mouse_t mouse_amstrad; +extern mouse_t mouse_olim24; +#endif + + +/* Initialization functions for boards and systems. */ +extern void acer386sx_init(void); +extern void acerm3a_io_init(void); +extern void ali1429_init(void); +extern void ali1429_reset(void); +extern void amstrad_init(void); +extern void compaq_init(void); +extern void headland_init(void); +extern void i430fx_init(void); +extern void i430hx_init(void); +extern void i430lx_init(void); +extern void i430nx_init(void); +extern void i430vx_init(void); +extern void i440fx_init(void); +extern void jim_init(void); +extern void laserxt_init(void); +extern void neat_init(void); +extern void olivetti_m24_init(void); +extern void opti495_init(void); + +extern void ps1mb_init(void); +extern void ps1mb_m2121_init(void); +extern void ps1mb_m2133_init(void); + +extern void ps2board_init(void); + +extern void scat_init(void); +extern void sis496_init(void); + + +#endif /*EMU_MODEL_H*/ diff --git a/src/mouse.c b/src/mouse.c index 467dde2e9..9169a4fa9 100644 --- a/src/mouse.c +++ b/src/mouse.c @@ -1,50 +1,133 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Common driver module for MOUSE devices. + * + * Version: @(#)mouse.c 1.0.3 2017/06/21 + * + * Authors: Sarah Walker, + * Miran Grca, + * Fred N. van Kempen, + * Copyright 2008-2017 Sarah Walker. + * Copyright 2016-2017 Miran Grca. + */ #include "ibm.h" +#include "cpu/cpu.h" +#include "device.h" #include "mouse.h" -#include "amstrad.h" -#include "mouse_ps2.h" #include "mouse_serial.h" -#include "keyboard_olim24.h" +#include "mouse_ps2.h" +#include "mouse_bus.h" +#include "model.h" -static mouse_t *mouse_list[] = -{ - &mouse_serial_microsoft, - &mouse_ps2_2_button, - &mouse_intellimouse, - &mouse_amstrad, - &mouse_olim24, - NULL + +static mouse_t mouse_none = { + "Disabled", "none", + MOUSE_TYPE_NONE, + NULL, NULL, NULL +}; + + +static mouse_t *mouse_list[] = { + &mouse_none, + &mouse_serial_microsoft, /* 1 Microsoft Serial Mouse */ + &mouse_ps2_2_button, /* 2 PS/2 Mouse 2-button */ + &mouse_intellimouse, /* 3 PS/2 Intellimouse 3-button */ + &mouse_bus, /* 4 Logitech Bus Mouse 2-button */ + &mouse_amstrad, /* 5 Amstrad PC System Mouse */ + &mouse_olim24, /* 6 Olivetti M24 System Mouse */ + &mouse_msystems, /* 7 Mouse Systems */ + &mouse_serial_logitech, /* 1 Logitech 3-button Serial Mouse */ +#if 0 + &mouse_genius, /* 8 Genius Bus Mouse */ +#endif + NULL }; static mouse_t *cur_mouse; static void *mouse_p; int mouse_type = 0; -void mouse_emu_init() + +void +mouse_emu_init(void) { - cur_mouse = mouse_list[mouse_type]; - mouse_p = cur_mouse->init(); + cur_mouse = mouse_list[mouse_type]; + + if (cur_mouse == NULL || cur_mouse->init == NULL) return; + + mouse_p = cur_mouse->init(); } -void mouse_emu_close() + +void +mouse_emu_close(void) { - if (cur_mouse) - cur_mouse->close(mouse_p); - cur_mouse = NULL; + if (cur_mouse == NULL || cur_mouse->close == NULL) return; + + cur_mouse->close(mouse_p); + + cur_mouse = NULL; + mouse_p = NULL; } -void mouse_poll(int x, int y, int z, int b) + +void +mouse_poll(int x, int y, int z, int b) { - if (cur_mouse) - cur_mouse->poll(x, y, z, b, mouse_p); + if (cur_mouse == NULL || cur_mouse->init == NULL) return; + + cur_mouse->poll(x, y, z, b, mouse_p); } -char *mouse_get_name(int mouse) + +char * +mouse_get_name(int mouse) { - if (!mouse_list[mouse]) - return NULL; - return mouse_list[mouse]->name; + if (!mouse_list[mouse]) + return(NULL); + + return(mouse_list[mouse]->name); } -int mouse_get_type(int mouse) + + +char * +mouse_get_internal_name(int mouse) { - return mouse_list[mouse]->type; + return(mouse_list[mouse]->internal_name); +} + + +int +mouse_get_from_internal_name(char *s) +{ + int c = 0; + + while (mouse_list[c] != NULL) { + if (!strcmp(mouse_list[c]->internal_name, s)) + return(c); + c++; + } + + return(0); +} + + +int +mouse_get_type(int mouse) +{ + return(mouse_list[mouse]->type); +} + + +/* Return number of MOUSE types we know about. */ +int +mouse_get_ndev(void) +{ + return(sizeof(mouse_list)/sizeof(mouse_t *) - 1); } diff --git a/src/mouse.h b/src/mouse.h index 29a19b78e..21e1ff983 100644 --- a/src/mouse.h +++ b/src/mouse.h @@ -1,24 +1,61 @@ -void mouse_emu_init(); -void mouse_emu_close(); -void mouse_poll(int x, int y, int z, int b); +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Definitions for the MOUSE driver. + * + * Version: @(#)mouse.h 1.0.3 2017/06/21 + * + * Authors: Sarah Walker, + * Miran Grca, + * Fred N. van Kempen, + * Copyright 2008-2017 Sarah Walker. + * Copyright 2016-2017 Miran Grca. + */ +#ifndef EMU_MOUSE_H +# define EMU_MOUSE_H -char *mouse_get_name(int mouse); -int mouse_get_type(int mouse); -#define MOUSE_TYPE_SERIAL 0 -#define MOUSE_TYPE_PS2 1 -#define MOUSE_TYPE_AMSTRAD 2 -#define MOUSE_TYPE_OLIM24 3 +#define MOUSE_TYPE_NONE 0 +#define MOUSE_TYPE_SERIAL 1 /* Serial Mouse */ +#define MOUSE_TYPE_PS2 2 /* IBM PS/2 series Bus Mouse */ +#define MOUSE_TYPE_PS2_MS 3 /* Microsoft Intellimouse PS/2 */ +#define MOUSE_TYPE_BUS 4 /* Logitech/ATI Bus Mouse */ +#define MOUSE_TYPE_AMSTRAD 5 /* Amstrad PC system mouse */ +#define MOUSE_TYPE_OLIM24 6 /* Olivetti M24 system mouse */ +#define MOUSE_TYPE_MSYSTEMS 7 /* Mouse Systems mouse */ +#define MOUSE_TYPE_LOGITECH 8 /* Logitech Serial Mouse */ +#define MOUSE_TYPE_GENIUS 9 /* Genius Bus Mouse */ -#define MOUSE_TYPE_3BUTTON (1 << 31) +#define MOUSE_TYPE_MASK 0x0f +#define MOUSE_TYPE_3BUTTON (1<<7) /* device has 3+ buttons */ -typedef struct -{ - char name[80]; - void *(*init)(); - void (*close)(void *p); - uint8_t (*poll)(int x, int y, int z, int b, void *p); - int type; + +typedef struct { + char name[80]; + char internal_name[24]; + int type; + void *(*init)(void); + void (*close)(void *p); + uint8_t (*poll)(int x, int y, int z, int b, void *p); } mouse_t; -extern int mouse_type; + +extern int mouse_type; + + +extern void mouse_emu_init(void); +extern void mouse_emu_close(void); +extern void mouse_poll(int x, int y, int z, int b); +extern char *mouse_get_name(int mouse); +extern char *mouse_get_internal_name(int mouse); +extern int mouse_get_from_internal_name(char *s); +extern int mouse_get_type(int mouse); +extern int mouse_get_ndev(void); + + +#endif /*EMU_MOUSE_H*/ diff --git a/src/mouse_bus.c b/src/mouse_bus.c new file mode 100644 index 000000000..b8cec9f82 --- /dev/null +++ b/src/mouse_bus.c @@ -0,0 +1,493 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Implementation of Bus Mouse devices. + * + * These devices were made by both Microsoft and Logitech. At + * first, Microsoft used the same protocol as Logitech, but did + * switch to their new protocol for their InPort interface. So, + * although alike enough to be handled in the same driver, they + * are not the same. + * + * This code is based on my Minix driver for the Logitech(-mode) + * interface. Although that driver blindly took IRQ5, the board + * seems to be able to tell the driver what IRQ it is set for. + * When testing on MS-DOS (6.22), the 'mouse.exe' driver did not + * want to start, and only after disassembling it and inspecting + * the code it was discovered that driver actually does use the + * IRQ reporting feature. In a really, really weird way, too: it + * sets up the board, and then reads the CTRL register which is + * supposed to return that IRQ value. Depending on whether or + * not the FREEZE bit is set, it has to return either the two's + * complemented (negated) value, or (if clear) just the value. + * The mouse.com driver reads both values 10,000 times, and + * then makes up its mind. Maybe an effort to 'debounce' the + * reading of the DIP switches? Oh-well. + * + * Based on an early driver for MINIX 1.5. + * Based on the 86Box PS/2 mouse driver as a framework. + * + * Version: @(#)mouse_bus.c 1.0.5 2017/06/02 + * + * Author: Fred N. van Kempen, + * Copyright 1989-2017 Fred N. van Kempen. + */ +#include +#include +#include "ibm.h" +#include "io.h" +#include "pic.h" +#include "mouse.h" +#include "mouse_bus.h" +#include "plat_mouse.h" + + +#define ENABLE_3BTN 1 /* enable 3-button mode */ + + +/* Register definitions for Logitech mode. */ +#define LTMOUSE_DATA 0 /* DATA register */ +#define LTMOUSE_MAGIC 1 /* signature magic register */ +# define MAGIC_BYTE1 0xa5 /* most drivers use this */ +# define MAGIC_BYTE2 0x5a /* some drivers use this */ +#define LTMOUSE_CTRL 2 /* CTRL register */ +# define CTRL_FREEZE 0x80 /* do not sample when set */ +# define CTRL_RD_Y_HI 0x60 /* plus FREEZE */ +# define CTRL_RD_Y_LO 0x40 /* plus FREEZE */ +# define CTRL_RD_X_HI 0x20 /* plus FREEZE */ +# define CTRL_RD_X_LO 0x00 /* plus FREEZE */ +# define CTRL_RD_MASK 0x60 +# define CTRL_IDIS 0x10 +# define CTRL_IENB 0x00 +# define CTRL_DFLT (CTRL_IDIS) +#define LTMOUSE_CONFIG 3 /* CONFIG register */ +# define CONFIG_DFLT 0x91 /* 8255 controller config */ + +/* Register definitions for Microsoft mode. */ +#define MSMOUSE_CTRL 0 /* CTRL register */ +# define MSCTRL_RESET 0x80 +# define MSCTRL_MODE 0x07 +# define MSCTRL_RD_Y 0x02 +# define MSCTRL_RD_X 0x01 +# define MSCTRL_RD_BUT 0x00 +#define MSMOUSE_DATA 1 /* DATA register */ +# define MSDATA_BASE 0x10 +# define MSDATA_IRQ 0x01 +#define MSMOUSE_MAGIC 2 /* MAGIC register */ +# define MAGIC_MSBYTE1 0xde /* indicates MS InPort */ +# define MAGIC_MSBYTE2 0xad +#define MSMOUSE_CONFIG 3 /* CONFIG register */ + + +/* Our mouse device. */ +typedef struct { + uint16_t port; /* I/O port range start */ + uint16_t portlen; /* length of I/O port range */ + int8_t irq; /* IRQ channel to use */ + uint8_t flags; /* device flags */ + + uint8_t r_magic; /* MAGIC register */ + uint8_t r_ctrl; /* CONTROL register (WR) */ + uint8_t r_intr; /* INTSTAT register (RO) */ + uint8_t r_conf; /* CONFIG register */ + + int8_t x, y; /* current mouse status */ + uint8_t but; +} mouse_bus_t; +#define MOUSE_ENABLED 0x80 /* device is enabled for use */ +#define MOUSE_LOGITECH 0x40 /* running in Logitech mode */ +#define MOUSE_MICROSOFT 0x20 /* running in Microsoft mode */ + + +/* Handle a WRITE to a Microsoft-mode register. */ +static void +ms_write(mouse_bus_t *ms, uint16_t port, uint8_t val) +{ +#if 0 + pclog("BUSMOUSE: ms_write(%d,%02x)\n", port, val); +#endif + + switch (port) { + case MSMOUSE_CTRL: /* [00] control register */ + if (val & MSCTRL_RESET) { + /* Reset the interface. */ + ms->r_magic = MAGIC_MSBYTE1; + ms->r_conf = 0x00; + } + + /* Save new register value. */ + ms->r_ctrl = val; + break; + + case MSMOUSE_DATA: /* [01] data register */ + if (ms->r_ctrl == MSCTRL_MODE) { + ms->r_conf = val; + } + break; + + case MSMOUSE_MAGIC: /* [02] magic data register */ + break; + + case MSMOUSE_CONFIG: /* [03] config register */ + ms->r_conf = val; + ms->flags &= ~MOUSE_MICROSOFT; + ms->flags |= MOUSE_LOGITECH; + break; + + default: + break; + } +} + + +/* Handle a WRITE to a LOGITECH-mode register. */ +static void +lt_write(mouse_bus_t *ms, uint16_t port, uint8_t val) +{ + uint8_t b = (ms->r_ctrl ^ val); + +#if 0 + pclog("BUSMOUSE: lt_write(%d,%02x)\n", port, val); +#endif + + switch (port) { + case LTMOUSE_DATA: /* [00] data register */ + break; + + case LTMOUSE_MAGIC: /* [01] magic data register */ + if (val == MAGIC_BYTE1 || val == MAGIC_BYTE2) { + ms->flags |= MOUSE_LOGITECH; + ms->r_magic = val; + } + break; + + case LTMOUSE_CTRL: /* [02] control register */ + if (b & CTRL_FREEZE) { + /* Hold the sampling while we do something. */ + if (! (val & CTRL_FREEZE)) { + /* Reset current state. */ + ms->x = ms->y = 0; + if (ms->but) + /* One more POLL for button-release. */ + ms->but = 0x80; + } + } + + if (b & CTRL_IDIS) { + /* Disable or enable interrupts. */ + /* (we don't do anything for that here..) */ + } + + /* Save new register value. */ + ms->r_ctrl = val; + break; + + case LTMOUSE_CONFIG: /* [03] config register */ + ms->r_conf = val; + break; + + default: + break; + } +} + + +/* Handle a WRITE operation to one of our registers. */ +static void +bm_write(uint16_t port, uint8_t val, void *priv) +{ + mouse_bus_t *ms = (mouse_bus_t *)priv; + + if (ms->flags & MOUSE_LOGITECH) + lt_write(ms, port - ms->port, val); + + if (ms->flags & MOUSE_MICROSOFT) + ms_write(ms, port - ms->port, val); +} + + +/* Handle a READ from a Microsoft-mode register. */ +static uint8_t +ms_read(mouse_bus_t *ms, uint16_t port) +{ + uint8_t r = 0xff; + + switch (port) { + case MSMOUSE_CTRL: /* [00] control register */ + r = ms->r_ctrl; + break; + + case MSMOUSE_DATA: /* [01] data register */ + break; + + case MSMOUSE_MAGIC: /* [02] magic data register */ + /* + * Drivers for the InPort controllers usually start + * by reading this register. If they find 0xDE here, + * they will continue their probe, otherwise no go. + */ + r = ms->r_magic; + + /* For the InPort, switch magic bytes. */ + if (ms->r_magic == MAGIC_MSBYTE1) + ms->r_magic = MAGIC_MSBYTE2; + else + ms->r_magic = MAGIC_MSBYTE1; + break; + + case MSMOUSE_CONFIG: /* [03] config register */ + r = ms->r_conf; + break; + + default: + break; + } + +#if 0 + pclog("BUSMOUSE: ms_read(%d): %02x\n", port, r); +#endif + + return(r); +} + + +/* Handle a READ from a LOGITECH-mode register. */ +static uint8_t +lt_read(mouse_bus_t *ms, uint16_t port) +{ + uint8_t r = 0xff; + + switch (port) { + case LTMOUSE_DATA: /* [00] data register */ + if (! (ms->r_ctrl & CTRL_FREEZE)) { + r = 0x00; + } else switch(ms->r_ctrl & CTRL_RD_MASK) { + case CTRL_RD_X_LO: /* X, low bits */ + /* + * Some drivers expect the buttons to + * be in this byte. Others want it in + * the Y-LO byte. --FvK + */ + r = 0x07; + if (ms->but & 0x01) /*LEFT*/ + r &= ~0x04; + if (ms->but & 0x02) /*RIGHT*/ + r &= ~0x01; +#if ENABLE_3BTN + if (ms->but & 0x04) /*MIDDLE*/ + r &= ~0x02; +#endif + r <<= 5; + r |= (ms->x & 0x0f); + break; + + case CTRL_RD_X_HI: /* X, high bits */ + r = (ms->x >> 4) & 0x0f; + break; + + case CTRL_RD_Y_LO: /* Y, low bits */ + r = (ms->y & 0x0f); + break; + + case CTRL_RD_Y_HI: /* Y, high bits */ + /* + * Some drivers expect the buttons to + * be in this byte. Others want it in + * the X-LO byte. --FvK + */ + r = 0x07; + if (ms->but & 0x01) /*LEFT*/ + r &= ~0x04; + if (ms->but & 0x02) /*RIGHT*/ + r &= ~0x01; +#if ENABLE_3BTN + if (ms->but & 0x04) /*MIDDLE*/ + r &= ~0x02; +#endif + r <<= 5; + r |= (ms->y >> 4) & 0x0f; + break; + } + break; + + case LTMOUSE_MAGIC: /* [01] magic data register */ + /* + * Logitech drivers start out by blasting their magic + * value (0xA5) into this register, and then read it + * back to see if that worked. If it did (and we do + * support this) the controller is assumed to be a + * Logitech-protocol one, and not InPort. + */ + r = ms->r_magic; + break; + + case LTMOUSE_CTRL: /* [02] control register */ + /* + * This is the weird stuff mentioned in the file header + * above. Microsoft's "mouse.exe" does some whacky stuff + * to extract the configured IRQ channel from the board. + * + * First, it reads the current value, and then re-reads + * it another 10,000 (yes, really) times. It keeps track + * of whether or not the data has changed, most likely + * to de-bounce reading of a DIP switch for example. This + * first value is assumed to be the 2's complement of the + * actual IRQ value. + * Next, it does this a second time, but now with the + * IDIS bit clear (so, interrupts enabled), which is + * our cue to return the regular (not complemented) value + * to them. + * + * Since we have to fake the initial value and the settling + * of the data a bit later on, we first return a bunch of + * invalid ("random") data, and then the real value. + * + * Yes, this is weird. --FvK + */ + if (ms->r_intr++ < 250) + /* Still settling, return invalid data. */ + r = (ms->r_ctrl&CTRL_IDIS)?0xff:0x00; + else { + /* OK, all good, return correct data. */ + r = (ms->r_ctrl&CTRL_IDIS)?-ms->irq:ms->irq; + ms->r_intr = 0; + } + break; + + case LTMOUSE_CONFIG: /* [03] config register */ + r = ms->r_conf; + break; + + default: + break; + } + +#if 0 + pclog("BUSMOUSE: lt_read(%d): %02x\n", port, r); +#endif + + return(r); +} + + +/* Handle a READ operation from one of our registers. */ +static uint8_t +bm_read(uint16_t port, void *priv) +{ + mouse_bus_t *ms = (mouse_bus_t *)priv; + uint8_t r = 0xff; + + if (ms->flags & MOUSE_LOGITECH) + r = lt_read(ms, port - ms->port); + + if (ms->flags & MOUSE_MICROSOFT) + r = ms_read(ms, port - ms->port); + + return(r); +} + + +/* The emulator calls us with an update on the host mouse device. */ +static uint8_t +bm_poll(int x, int y, int z, int b, void *priv) +{ + mouse_bus_t *ms = (mouse_bus_t *)priv; + + /* Return early if nothing to do. */ + if (!x && !y && !z && (ms->but == b)) return(1); + + /* If we are not interested, return. */ + if (!(ms->flags & MOUSE_ENABLED) || + (ms->r_ctrl & CTRL_FREEZE)) return(0); + +#if 0 + pclog("BUSMOUSE: poll(%d,%d,%d, %02x)\n", x, y, z, b); +#endif + + /* Add the delta to our state. */ + x += ms->x; + if (x > 127) + x = 127; + if (x < -128) + x = -128; + ms->x = (int8_t)x; + + y += ms->y; + if (y > 127) + y = 127; + if (y < -128) + y = -128; + ms->y = (int8_t)y; + + ms->but = b; + + /* All set, generate an interrupt. */ + if (! (ms->r_ctrl & CTRL_IDIS)) + picint(1 << ms->irq); + + return(0); +} + + +/* Release all resources held by the device. */ +static void +bm_close(void *priv) +{ + mouse_bus_t *ms = (mouse_bus_t *)priv; + + /* Release our I/O range. */ + io_removehandler(ms->port, ms->portlen, + bm_read, NULL, NULL, bm_write, NULL, NULL, ms); + + free(ms); +} + + +/* Initialize the device for use by the user. */ +static void * +bm_init(void) +{ + mouse_bus_t *ms; + + ms = (mouse_bus_t *)malloc(sizeof(mouse_bus_t)); + memset(ms, 0x00, sizeof(mouse_bus_t)); + ms->port = BUSMOUSE_PORT; + ms->portlen = BUSMOUSE_PORTLEN; +#if BUSMOUSE_IRQ + ms->irq = BUSMOUSE_IRQ; +#else + ms->irq = -1; +#endif + + pclog("Logitech/Microsoft Bus Mouse, I/O=%04x, IRQ=%d\n", + ms->port, ms->irq); + /* Initialize registers. */ + ms->r_magic = MAGIC_MSBYTE1; + ms->r_conf = CONFIG_DFLT; + ms->r_ctrl = CTRL_DFLT; + + /* Initialize with Microsoft-mode being default. */ + ms->flags = (MOUSE_ENABLED | MOUSE_MICROSOFT); + + /* Request an I/O range. */ + io_sethandler(ms->port, ms->portlen, + bm_read, NULL, NULL, bm_write, NULL, NULL, ms); + + /* Return our private data to the I/O layer. */ + return(ms); +} + + +mouse_t mouse_bus = { + "Bus Mouse", + "msbus", + MOUSE_TYPE_BUS, + bm_init, + bm_close, + bm_poll +}; diff --git a/src/mouse_bus.h b/src/mouse_bus.h new file mode 100644 index 000000000..24eeb50ff --- /dev/null +++ b/src/mouse_bus.h @@ -0,0 +1,34 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Implementation of Bus Mouse devices. + * + * These mice devices were made by both Microsoft (InPort) and + * Logitech. Sadly, they did not use the same I/O protocol, but + * they were close enough to fit into a single implementation. + * + * Definitions for the Bus Mouse driver. + * + * Version: @(#)mouse_bus.h 1.0.3 2017/04/22 + * + * Author: Fred N. van Kempen, + * Copyright 1989-2017 Fred N. van Kempen. + */ +#ifndef MOUSE_BUS_H +# define MOUSE_BUS_H + + +#define BUSMOUSE_PORT 0x023c +#define BUSMOUSE_PORTLEN 4 +#define BUSMOUSE_IRQ 5 + + +extern mouse_t mouse_bus; + + +#endif /*MOUSE_BUS_H*/ diff --git a/src/mouse_prot.txt b/src/mouse_prot.txt new file mode 100644 index 000000000..e810e969a --- /dev/null +++ b/src/mouse_prot.txt @@ -0,0 +1,207 @@ +Serial mouse reset +------------------ + +1: Set UART to 'break line' state (set bit 6 in the LCR). +2: Clear the RTS and DTR (bits 0-1) in the MCR, wait a while. +3: Set the RTS and DTR bits again. + + +Serial mouse detection (identification bytes before optional PnP data) +---------------------------------------------------------------------- + +In Mouse Systems mode, mouse sends nothing. +In Microsoft mode, mouse sends 'M' after dropping and raising RTS. +In Logitech mode, mouse sends 'M3' after dropping and raising RTS. +In wheel mode, mouse sends 'MZ@',0,0,0 after dropping and raising RTS. + + +PS/2 pointing device ID (reported after 0F2h command) +----------------------------------------------------- + +In standard mode, the device reports 0. +In wheel mode, the device reports 3. This mode is enabled by sending a + Select Report Rate 200, a Rate 100 and finally a Rate 80 command sequence. +In extended mode, the device reports 4. This mode is enabled by sending a + Select Report Rate 200, a Rate 200 and finally a Rate 80 command sequence. + + +=========================================================================== +Serial Mouse Systems mode: 1200 bps, 8 data bits, 1 stop bit, no parity + + 1st byte 2nd byte 3rd byte + +---------------+ +---------------+ +---------------+ + |1|0|0|0|0|L|M|R| |X|X|X|X|X|X|X|X| |Y|Y|Y|Y|Y|Y|Y|Y| + +---------------+ +---------------+ +---------------+ + | | | Xa movement Ya movement + | | | + | | | 4th byte 5th byte + Left Button ------+ | | +---------------+ +---------------+ +Middle Button --------+ | |X|X|X|X|X|X|X|X| |Y|Y|Y|Y|Y|Y|Y|Y| + Right Button ----------+ +---------------+ +---------------+ +(0 if pressed) Xb movement Yb movement + + +Xa/Ya - movement of the mouse since last packet. +Xb/Yb - movement of the mouse since Xa/Ya. +Movement values are 8-bit signed twos complement integers. +Positive movement value indicates motion to the right/upward. + + +=========================================================================== +Serial Microsoft mode: 1200 bps, 7 data bits, 1 stop bit, no parity + + 1st byte 2nd byte 3rd byte + +---------------+ +---------------+ +---------------+ + |0|1|L|R|Y|Y|X|X| |0|0|X|X|X|X|X|X| |0|0|Y|Y|Y|Y|Y|Y| + +---------------+ +---------------+ +---------------+ + | | \ / \ / \----+----/ \----+----/ + | | | | | | + | | +---|-------------|---------+ | + | | +-----+ | | | + | | / \ /----+----\ / \ /----+----\ + | | +---------------+ +---------------+ + Left Button -+ | | | | | | | | | | | | | | | | | | | +Right Button ---+ +---------------+ +---------------+ +(1 if pressed) X movement Y movement + + +Movement values are 8-bit signed twos complement integers. +Positive movement value indicates motion to the right/downward. + + +=========================================================================== +Serial Logitech mode: 1200 bps, 7 data bits, 1 stop bit, no parity + + 1st byte 2nd byte 3rd byte + +---------------+ +---------------+ +---------------+ + |0|1|L|R|Y|Y|X|X| |0|0|X|X|X|X|X|X| |0|0|Y|Y|Y|Y|Y|Y| + +---------------+ +---------------+ +---------------+ + | | \ / \ / \----+----/ \----+----/ + | | | | | | + | | +---|-------------|---------+ | + | | +-----+ | | | + | | / \ /----+----\ / \ /----+----\ + | | +---------------+ +---------------+ + Left Button -+ | | | | | | | | | | | | | | | | | | | +Right Button ---+ +---------------+ +---------------+ +(1 if pressed) X movement Y movement + + +The extra byte (only when middle button is pressed) +--------------------------------------------------- + + 4th byte + +---------------+ + |0|0|M|0|0|0|0|0| + +---------------+ + | + Middle Button (1 if pressed) + + +First three bytes are equal to Mouse mode packet. +Movement values are 8-bit signed twos complement integers. +Positive movement value indicates motion to the right/downward. + + +=========================================================================== +Serial Microsoft wheel mode: 1200 bps, 7 data bits, 1 stop bit, no parity + + 1st byte 2nd byte 3rd byte 4th byte + +---------------+ +---------------+ +---------------+ +---------------+ + |0|1|L|R|Y|Y|X|X| |0|0|X|X|X|X|X|X| |0|0|Y|Y|Y|Y|Y|Y| |0|0|0|M|w|w|w|w| + +---------------+ +---------------+ +---------------+ +---------------+ + | | \ / \ / \----+----/ \----+----/ | \--+--/ + | | | | | | | | + | | +---|-------------|---------+ | | | + | | +-----+ | | | | Wheel + | | / \ /----+----\ / \ /----+----\ | Movement + | | +---------------+ +---------------+ | + Left Button -+ | | | | | | | | | | | | | | | | | | | | +Right Button ---+ +---------------+ +---------------+ Middle Button +(1 if pressed) X movement Y movement (1 if pressed) + + +First three bytes are equal to Mouse mode packet. +Movement values are 8-bit signed twos complement integers. +Positive movement value indicates motion to the right/downward. +Wheel movement is a 4-bit signed twos complement integer. +Positive wheel movement value indicates rotation downward. + + +=========================================================================== +PS/2 standard mode protocol: + + 1st byte 2nd byte 3rd byte + +---------------+ +---------------+ +---------------+ + |?|?|Y|X|1|M|R|L| |X|X|X|X|X|X|X|X| |Y|Y|Y|Y|Y|Y|Y|Y| + +---------------+ +---------------+ +---------------+ + | | | | | \------+------/ \------+------/ + | | | | | | | + +-|---|-|-|----------|-----------+ | + +---|-|-|--+ | | | + | | | | /-----+-------\ | /---+---------\ +Middle Button ------+ | | +-----------------+ +-----------------+ + Right Button --------+ | | | | | | | | | | | | | | | | | | | | | + Left Button ----------+ +-----------------+ +-----------------+ +(1 if pressed) X movement Y movement + + +Two most significant bits in first byte indicate overflow (more than 9 bits + of movement) in each direction. Usually ignored. +Movement values are 9-bit signed twos complement integers. +Positive movement value indicates motion to the right/upward. + + +=========================================================================== +PS/2 wheel mode protocol: + + 1st byte 2nd byte 3rd byte 4th byte + +---------------+ +---------------+ +---------------+ +---------------+ + |?|?|Y|X|1|M|R|L| |X|X|X|X|X|X|X|X| |Y|Y|Y|Y|Y|Y|Y|Y| |w|w|w|w|W|W|W|W| + +---------------+ +---------------+ +---------------+ +---------------+ + | | | | | \------+------/ \------+------/ \-------+-----/ + | | | | | | | | + +-|---|-|-|----------|-----------+ | | + +---|-|-|--+ | | | | + | | | | /-----+-------\ | /---+---------\ | +Middle Button ------+ | | +-----------------+ +-----------------+ | + Right Button --------+ | | | | | | | | | | | | | | | | | | | | | | + Left Button ----------+ +-----------------+ +-----------------+ Wheel +(1 if pressed) X movement Y movement Movement + + +First three bytes are equal to PS/2 standard mode packet. +Two most significant bits in first byte indicate overflow (more than 9 bits + of movement) in each direction. Usually ignored. +Movement values are 9-bit signed twos complement integers. +Positive movement value indicates motion to the right/upward. +Wheel movement is a 8-bit signed twos complement integer and usually + limited by -8..+7 range (4-bit value). +Positive wheel movement value indicates rotation downward. + + +=========================================================================== +PS/2 extended mode protocol: + + 1st byte 2nd byte 3rd byte 4th byte + +---------------+ +---------------+ +---------------+ +---------------+ + |?|?|Y|X|1|M|R|L| |X|X|X|X|X|X|X|X| |Y|Y|Y|Y|Y|Y|Y|Y| |0|0|B|F|W|W|W|W| + +---------------+ +---------------+ +---------------+ +---------------+ + | | | | | \------+------/ \------+------/ | | \--+--/ + | | | | | | | | | | + +-|---|-|-|----------|-----------+ | | | | + +---|-|-|--+ | | | | | Wheel + | | | | /-----+-------\ | /---+---------\ | | Movement +Middle Button ------+ | | +-----------------+ +-----------------+ | | + Right Button --------+ | | | | | | | | | | | | | | | | | | | | | | +- Forward Button + Left Button ----------+ +-----------------+ +-----------------+ +--- Back Button +(1 if pressed) X movement Y movement (1 if pressed) + + +First three bytes are equal to PS/2 standard mode packet. +Two most significant bits in first byte indicate overflow (more than 9 bits + of movement) in each direction. Usually ignored. +Movement values are 9-bit signed twos complement integers. +Positive movement value indicates motion to the right/upward. +Wheel movement is a 4-bit signed twos complement integer. +Positive wheel movement value indicates rotation downward. diff --git a/src/mouse_ps2.c b/src/mouse_ps2.c index 15d2019f9..d5627eda8 100644 --- a/src/mouse_ps2.c +++ b/src/mouse_ps2.c @@ -1,8 +1,10 @@ +#include #include "ibm.h" #include "keyboard_at.h" #include "mouse.h" #include "mouse_ps2.h" -#include "plat-mouse.h" +#include "plat_mouse.h" + int mouse_scan = 0; @@ -148,16 +150,16 @@ void mouse_ps2_write(uint8_t val, void *p) } } -void mouse_ps2_poll(int x, int y, int z, int b, void *p) +uint8_t mouse_ps2_poll(int x, int y, int z, int b, void *p) { mouse_ps2_t *mouse = (mouse_ps2_t *)p; uint8_t packet[3] = {0x08, 0, 0}; if (!x && !y && !z && b == mouse->b) - return; + return(0xff); if (!mouse_scan) - return; + return(0xff); mouse->x += x; mouse->y -= y; @@ -200,6 +202,8 @@ void mouse_ps2_poll(int x, int y, int z, int b, void *p) mouse->x = mouse->y = mouse->z = 0; } + + return(0); } void *mouse_ps2_init() @@ -237,16 +241,18 @@ void mouse_ps2_close(void *p) mouse_t mouse_ps2_2_button = { "2-button mouse (PS/2)", + "ps2", + MOUSE_TYPE_PS2, mouse_ps2_init, mouse_ps2_close, - mouse_ps2_poll, - MOUSE_TYPE_PS2 + mouse_ps2_poll }; mouse_t mouse_intellimouse = { "Microsoft Intellimouse (PS/2)", + "intellimouse", + MOUSE_TYPE_PS2 | MOUSE_TYPE_3BUTTON, mouse_intellimouse_init, mouse_ps2_close, - mouse_ps2_poll, - MOUSE_TYPE_PS2 | MOUSE_TYPE_3BUTTON + mouse_ps2_poll }; diff --git a/src/mouse_ps2.h b/src/mouse_ps2.h index 645e3cf73..b25cae5f2 100644 --- a/src/mouse_ps2.h +++ b/src/mouse_ps2.h @@ -1,2 +1,4 @@ extern mouse_t mouse_ps2_2_button; extern mouse_t mouse_intellimouse; + +extern void *mouse_ps2_init(); diff --git a/src/mouse_serial.c b/src/mouse_serial.c index f05e64d9e..04f23a8d9 100644 --- a/src/mouse_serial.c +++ b/src/mouse_serial.c @@ -1,98 +1,230 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Implementation of Serial Mouse devices. + * + * Based on the 86Box Serial Mouse driver as a framework. + * + * Version: @(#)mouse_serial.c 1.0.6 2017/06/19 + * + * Author: Fred N. van Kempen, + */ +#include #include "ibm.h" -#include "mouse.h" -#include "pic.h" -#include "serial.h" #include "timer.h" +#include "serial.h" +#include "mouse.h" +#include "mouse_serial.h" -typedef struct mouse_serial_t -{ - int mousepos, mousedelay; - int oldb; - SERIAL *serial; + +#define SERMOUSE_TYPE_MSYSTEMS 1 /* Mouse Systems */ +#define SERMOUSE_TYPE_MICROSOFT 2 /* Microsoft */ +#define SERMOUSE_TYPE_LOGITECH 3 /* Logitech */ + + +typedef struct mouse_serial_t { + int8_t port, + type; + int pos, + delay; + int oldb; + SERIAL *serial; } mouse_serial_t; -void mouse_serial_poll(int x, int y, int z, int b, void *p) + +/* Callback from serial driver: RTS was toggled. */ +static void +sermouse_callback(void *priv) { - mouse_serial_t *mouse = (mouse_serial_t *)p; - SERIAL *serial = mouse->serial; - uint8_t mousedat[3]; + mouse_serial_t *ms = (mouse_serial_t *)priv; - if (!(serial->ier & 1)) - return; - if (!x && !y && b == mouse->oldb) - return; - - mouse->oldb = b; - if (x>127) x=127; - if (y>127) y=127; - if (x<-128) x=-128; - if (y<-128) y=-128; - - /*Use Microsoft format*/ - mousedat[0]=0x40; - mousedat[0]|=(((y>>6)&3)<<2); - mousedat[0]|=((x>>6)&3); - if (b&1) mousedat[0]|=0x20; - if (b&2) mousedat[0]|=0x10; - mousedat[1]=x&0x3F; - mousedat[2]=y&0x3F; - - if (!(serial->mctrl & 0x10)) - { -// pclog("Serial data %02X %02X %02X\n", mousedat[0], mousedat[1], mousedat[2]); - serial_write_fifo(mouse->serial, mousedat[0]); - serial_write_fifo(mouse->serial, mousedat[1]); - serial_write_fifo(mouse->serial, mousedat[2]); - } + /* Start a timer to wake us up in a little while. */ + ms->pos = -1; + ms->delay = 5000 * (1 << TIMER_SHIFT); } -void mouse_serial_rcr(SERIAL *serial, void *p) -{ - mouse_serial_t *mouse = (mouse_serial_t *)p; - - mouse->mousepos = -1; - mouse->mousedelay = 5000 * (1 << TIMER_SHIFT); -} - -void mousecallback(void *p) -{ - mouse_serial_t *mouse = (mouse_serial_t *)p; - mouse->mousedelay = 0; - if (mouse->mousepos == -1) - { - mouse->mousepos = 0; - serial_write_fifo(mouse->serial, 'M'); - } +/* Callback timer expired, now send our "mouse ID" to the serial port. */ +static void +sermouse_timer(void *priv) +{ + mouse_serial_t *ms = (mouse_serial_t *)priv; + + ms->delay = 0; + + switch(ms->type) { + case SERMOUSE_TYPE_MICROSOFT: + /* This identifies a two-button Microsoft Serial mouse. */ + serial_write_fifo(ms->serial, 'M', 1); + break; + + case SERMOUSE_TYPE_LOGITECH: + /* This identifies a two-button Logitech Serial mouse. */ + serial_write_fifo(ms->serial, 'M', 1); + serial_write_fifo(ms->serial, '3', 1); + break; + + default: + /* No action needed. */ + break; + } } -void *mouse_serial_init() -{ - mouse_serial_t *mouse = (mouse_t *)malloc(sizeof(mouse_serial_t)); - memset(mouse, 0, sizeof(mouse_serial_t)); - mouse->serial = &serial1; - serial1.rcr_callback = mouse_serial_rcr; - serial1.rcr_callback_p = mouse; - timer_add(mousecallback, &mouse->mousedelay, &mouse->mousedelay, mouse); - - return mouse; +static uint8_t +sermouse_poll(int x, int y, int z, int b, void *priv) +{ + mouse_serial_t *ms = (mouse_serial_t *)priv; + uint8_t buff[16]; + int len; + + if (!x && !y && b == ms->oldb) return(1); + + ms->oldb = b; + + if (ms->type == SERMOUSE_TYPE_MSYSTEMS) y = -y; + + if (x>127) x = 127; + if (y>127) y = 127; + if (x<-128) x = -128; + if (y<-128) y = -128; + + len = 0; + switch(ms->type) { + case SERMOUSE_TYPE_MSYSTEMS: + buff[0] = 0x80; + buff[0] |= (b&0x01) ? 0x00 : 0x04; /* left button */ + buff[0] |= (b&0x02) ? 0x00 : 0x01; /* middle button */ + buff[0] |= (b&0x04) ? 0x00 : 0x02; /* right button */ + buff[1] = x; + buff[2] = y; + buff[3] = x; /* same as byte 1 */ + buff[4] = y; /* same as byte 2 */ + len = 5; + break; + + case SERMOUSE_TYPE_MICROSOFT: + buff[0] = 0x40; + buff[0] |= (((y>>6)&03)<<2); + buff[0] |= ((x>>6)&03); + if (b&0x01) buff[0] |= 0x20; + if (b&0x02) buff[0] |= 0x10; + buff[1] = x & 0x3F; + buff[2] = y & 0x3F; + len = 3; + break; + + case SERMOUSE_TYPE_LOGITECH: + buff[0] = 0x40; + buff[0] |= (((y>>6)&03)<<2); + buff[0] |= ((x>>6)&03); + if (b&0x01) buff[0] |= 0x20; + if (b&0x02) buff[0] |= 0x10; + buff[1] = x & 0x3F; + buff[2] = y & 0x3F; + if (b&0x04) { + buff[3] = 0x20; + len = 4; + } else { + len = 3; + } + break; + } + +#if 0 + pclog("Mouse_Serial(%d): [", ms->type); + for (b=0; bserial, buff[b], 1); + + return(0); } -void mouse_serial_close(void *p) + +static void +sermouse_close(void *priv) { - mouse_serial_t *mouse = (mouse_serial_t *)p; - - free(mouse); - - serial1.rcr_callback = NULL; + mouse_serial_t *ms = (mouse_serial_t *)priv; + + /* Detach serial port from the mouse. */ + serial_attach(ms->port, NULL, NULL); + + free(ms); } -mouse_t mouse_serial_microsoft = + +static void * +sermouse_init(int type) { - "Microsoft 2-button mouse (serial)", - mouse_serial_init, - mouse_serial_close, - mouse_serial_poll, - MOUSE_TYPE_SERIAL + mouse_serial_t *ms = (mouse_serial_t *)malloc(sizeof(mouse_serial_t)); + memset(ms, 0x00, sizeof(mouse_serial_t)); + ms->port = SERMOUSE_PORT; + ms->type = type; + + /* Attach a serial port to the mouse. */ + ms->serial = serial_attach(ms->port, sermouse_callback, ms); + + timer_add(sermouse_timer, &ms->delay, &ms->delay, ms); + + return(ms); +} + + +static void * +sermouse_init_microsoft(void) +{ + return(sermouse_init(SERMOUSE_TYPE_MICROSOFT)); +} + + +static void * +sermouse_init_logitech(void) +{ + return(sermouse_init(SERMOUSE_TYPE_LOGITECH)); +} + + +static void * +sermouse_init_msystems(void) +{ + return(sermouse_init(SERMOUSE_TYPE_MSYSTEMS)); +} + + +mouse_t mouse_msystems = { + "Mouse Systems Mouse (serial)", + "mssystems", + MOUSE_TYPE_MSYSTEMS, + sermouse_init_msystems, + sermouse_close, + sermouse_poll +}; + + +mouse_t mouse_serial_microsoft = { + "Microsoft 2-button mouse (serial)", + "msserial", + MOUSE_TYPE_SERIAL, + sermouse_init_microsoft, + sermouse_close, + sermouse_poll +}; + + +mouse_t mouse_serial_logitech = { + "Logitech 3-button mouse (serial)", + "lserial", + MOUSE_TYPE_SERIAL | MOUSE_TYPE_3BUTTON, + sermouse_init_logitech, + sermouse_close, + sermouse_poll }; diff --git a/src/mouse_serial.h b/src/mouse_serial.h index 94e744d44..27626c08c 100644 --- a/src/mouse_serial.h +++ b/src/mouse_serial.h @@ -1 +1,29 @@ -extern mouse_t mouse_serial_microsoft; +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Implementation of Serial Mouse devices. + * + * Definitions for the Serial Mouse driver. + * + * Version: @(#)mouse_serial.h 1.0.3 2017/06/19 + * + * Author: Fred N. van Kempen, + */ +#ifndef MOUSE_SERIAL_H +# define MOUSE_SERIAL_H + + +#define SERMOUSE_PORT 1 /* attach to Serial1 */ + + +extern mouse_t mouse_serial_microsoft; +extern mouse_t mouse_serial_logitech; +extern mouse_t mouse_msystems; + + +#endif /*MOUSE_SERIAL_H*/ diff --git a/src/ne2000.c b/src/ne2000.c deleted file mode 100644 index 961bff795..000000000 --- a/src/ne2000.c +++ /dev/null @@ -1,2456 +0,0 @@ -/* Copyright holders: Peter Grehan, SA1988, Tenshi - see COPYING for more details -*/ -///////////////////////////////////////////////////////////////////////// -// $Id: ne2k.cc,v 1.56.2.1 2004/02/02 22:37:22 cbothamy Exp $ -///////////////////////////////////////////////////////////////////////// -// -// Copyright (C) 2002 MandrakeSoft S.A. -// -// MandrakeSoft S.A. -// 43, rue d'Aboukir -// 75002 Paris - France -// http://www.linux-mandrake.com/ -// http://www.mandrakesoft.com/ -// - -// Peter Grehan (grehan@iprg.nokia.com) coded all of this -// NE2000/ether stuff. -//#include "vl.h" -#include -#include -#include -#include - -#include "slirp/slirp.h" -#include "slirp/queue.h" -#include - -#include "ibm.h" -#include "device.h" - -#include "config.h" -#include "nethandler.h" - -#include "io.h" -#include "mem.h" -#include "nethandler.h" -#include "rom.h" - -#include "ne2000.h" -#include "pci.h" -#include "pic.h" -#include "timer.h" - -//THIS IS THE DEFAULT MAC ADDRESS .... so it wont place nice with multiple VMs. YET. -uint8_t maclocal[6] = {0xac, 0xde, 0x48, 0x88, 0xbb, 0xaa}; - -#define NETBLOCKING 0 //we won't block our pcap - -static HINSTANCE net_hLib = 0; /* handle to DLL */ -static char* net_lib_name = "wpcap.dll"; -pcap_t *net_pcap; -typedef pcap_t* (__cdecl * PCAP_OPEN_LIVE)(const char *, int, int, int, char *); -typedef int (__cdecl * PCAP_SENDPACKET)(pcap_t* handle, const u_char* msg, int len); -typedef int (__cdecl * PCAP_SETNONBLOCK)(pcap_t *, int, char *); -typedef const u_char*(__cdecl *PCAP_NEXT)(pcap_t *, struct pcap_pkthdr *); -typedef const char*(__cdecl *PCAP_LIB_VERSION)(void); -typedef void (__cdecl *PCAP_CLOSE)(pcap_t *); -typedef int (__cdecl *PCAP_GETNONBLOCK)(pcap_t *p, char *errbuf); -typedef int (__cdecl *PCAP_COMPILE)(pcap_t *p, struct bpf_program *fp, const char *str, int optimize, bpf_u_int32 netmask); -typedef int (__cdecl *PCAP_SETFILTER)(pcap_t *p, struct bpf_program *fp); - -PCAP_LIB_VERSION _pcap_lib_version; -PCAP_OPEN_LIVE _pcap_open_live; -PCAP_SENDPACKET _pcap_sendpacket; -PCAP_SETNONBLOCK _pcap_setnonblock; -PCAP_NEXT _pcap_next; -PCAP_CLOSE _pcap_close; -PCAP_GETNONBLOCK _pcap_getnonblock; -PCAP_COMPILE _pcap_compile; -PCAP_SETFILTER _pcap_setfilter; - -queueADT slirpq; -int net_slirp_inited=0; -int net_is_slirp=1; //by default we go with slirp -int net_is_pcap=0; //and pretend pcap is dead. -int fizz=0; -void slirp_tic(); - -#define BX_RESET_HARDWARE 0 -#define BX_RESET_SOFTWARE 1 - -//Never completely fill the ne2k ring so that we never -// hit the unclear completely full buffer condition. -#define BX_NE2K_NEVER_FULL_RING (1) - -#define BX_NE2K_MEMSIZ (32*1024) -#define BX_NE2K_MEMSTART (16*1024) -#define BX_NE2K_MEMEND (BX_NE2K_MEMSTART + BX_NE2K_MEMSIZ) - -uint8_t rtl8029as_eeprom[128]; - -typedef struct ne2000_t -{ - // - // ne2k register state - - // - // Page 0 - // - // Command Register - 00h read/write - struct CR_t { - int stop; // STP - Software Reset command - int start; // START - start the NIC - int tx_packet; // TXP - initiate packet transmission - uint8_t rdma_cmd; // RD0,RD1,RD2 - Remote DMA command - uint8_t pgsel; // PS0,PS1 - Page select - } CR; - // Interrupt Status Register - 07h read/write - struct ISR_t { - int pkt_rx; // PRX - packet received with no errors - int pkt_tx; // PTX - packet transmitted with no errors - int rx_err; // RXE - packet received with 1 or more errors - int tx_err; // TXE - packet tx'd " " " " " - int overwrite; // OVW - rx buffer resources exhausted - int cnt_oflow; // CNT - network tally counter MSB's set - int rdma_done; // RDC - remote DMA complete - int reset; // RST - reset status - } ISR; - // Interrupt Mask Register - 0fh write - struct IMR_t { - int rx_inte; // PRXE - packet rx interrupt enable - int tx_inte; // PTXE - packet tx interrput enable - int rxerr_inte; // RXEE - rx error interrupt enable - int txerr_inte; // TXEE - tx error interrupt enable - int overw_inte; // OVWE - overwrite warn int enable - int cofl_inte; // CNTE - counter o'flow int enable - int rdma_inte; // RDCE - remote DMA complete int enable - int reserved; // D7 - reserved - } IMR; - // Data Configuration Register - 0eh write - struct DCR_t { - int wdsize; // WTS - 8/16-bit select - int endian; // BOS - byte-order select - int longaddr; // LAS - long-address select - int loop; // LS - loopback select - int auto_rx; // AR - auto-remove rx packets with remote DMA - uint8_t fifo_size; // FT0,FT1 - fifo threshold - } DCR; - // Transmit Configuration Register - 0dh write - struct TCR_t { - int crc_disable; // CRC - inhibit tx CRC - uint8_t loop_cntl; // LB0,LB1 - loopback control - int ext_stoptx; // ATD - allow tx disable by external mcast - int coll_prio; // OFST - backoff algorithm select - uint8_t reserved; // D5,D6,D7 - reserved - } TCR; - // Transmit Status Register - 04h read - struct TSR_t { - int tx_ok; // PTX - tx complete without error - int reserved; // D1 - reserved - int collided; // COL - tx collided >= 1 times - int aborted; // ABT - aborted due to excessive collisions - int no_carrier; // CRS - carrier-sense lost - int fifo_ur; // FU - FIFO underrun - int cd_hbeat; // CDH - no tx cd-heartbeat from transceiver - int ow_coll; // OWC - out-of-window collision - } TSR; - // Receive Configuration Register - 0ch write - struct RCR_t { - int errors_ok; // SEP - accept pkts with rx errors - int runts_ok; // AR - accept < 64-byte runts - int broadcast; // AB - accept eth broadcast address - int multicast; // AM - check mcast hash array - int promisc; // PRO - accept all packets - int monitor; // MON - check pkts, but don't rx - uint8_t reserved; // D6,D7 - reserved - } RCR; - // Receive Status Register - 0ch read - struct RSR_t { - int rx_ok; // PRX - rx complete without error - int bad_crc; // CRC - Bad CRC detected - int bad_falign; // FAE - frame alignment error - int fifo_or; // FO - FIFO overrun - int rx_missed; // MPA - missed packet error - int rx_mbit; // PHY - unicast or mcast/bcast address match - int rx_disabled; // DIS - set when in monitor mode - int deferred; // DFR - collision active - } RSR; - - uint16_t local_dma; // 01,02h read ; current local DMA addr - uint8_t page_start; // 01h write ; page start register - uint8_t page_stop; // 02h write ; page stop register - uint8_t bound_ptr; // 03h read/write ; boundary pointer - uint8_t tx_page_start; // 04h write ; transmit page start register - uint8_t num_coll; // 05h read ; number-of-collisions register - uint16_t tx_bytes; // 05,06h write ; transmit byte-count register - uint8_t fifo; // 06h read ; FIFO - uint16_t remote_dma; // 08,09h read ; current remote DMA addr - uint16_t remote_start; // 08,09h write ; remote start address register - uint16_t remote_bytes; // 0a,0bh write ; remote byte-count register - uint8_t tallycnt_0; // 0dh read ; tally counter 0 (frame align errors) - uint8_t tallycnt_1; // 0eh read ; tally counter 1 (CRC errors) - uint8_t tallycnt_2; // 0fh read ; tally counter 2 (missed pkt errors) - - // - // Page 1 - // - // Command Register 00h (repeated) - // - uint8_t physaddr[6]; // 01-06h read/write ; MAC address - uint8_t curr_page; // 07h read/write ; current page register - uint8_t mchash[8]; // 08-0fh read/write ; multicast hash array - - // - // Page 2 - diagnostic use only - // - // Command Register 00h (repeated) - // - // Page Start Register 01h read (repeated) - // Page Stop Register 02h read (repeated) - // Current Local DMA Address 01,02h write (repeated) - // Transmit Page start address 04h read (repeated) - // Receive Configuration Register 0ch read (repeated) - // Transmit Configuration Register 0dh read (repeated) - // Data Configuration Register 0eh read (repeated) - // Interrupt Mask Register 0fh read (repeated) - // - uint8_t rempkt_ptr; // 03h read/write ; remote next-packet pointer - uint8_t localpkt_ptr; // 05h read/write ; local next-packet pointer - uint16_t address_cnt; // 06,07h read/write ; address counter - - // - // Page 3 - should never be modified. - // - - // Novell ASIC state - uint8_t macaddr[32]; // ASIC ROM'd MAC address, even bytes - uint8_t mem[BX_NE2K_MEMSIZ]; // on-chip packet memory - - // ne2k internal state - uint32_t base_address; - int base_irq; - int tx_timer_index; - int tx_timer_active; - - rom_t bios_rom; - -} ne2000_t; - -int disable_netbios = 0; - -void ne2000_tx_event(void *p, uint32_t val); -uint32_t ne2000_chipmem_read(ne2000_t *ne2000, uint32_t address, unsigned int io_len); -void ne2000_page0_write(ne2000_t *ne2000, uint32_t offset, uint32_t value, unsigned io_len); -void ne2000_rx_frame(void *p, const void *buf, int io_len); - -int ne2000_do_log = 0; - -void ne2000_log(const char *format, ...) -{ - if (ne2000_do_log) - { - va_list ap; - va_start(ap, format); - vprintf(format, ap); - va_end(ap); - fflush(stdout); - } -} - -static void ne2000_setirq(ne2000_t *ne2000, int irq) -{ - ne2000->base_irq = irq; -} -// -// reset - restore state to power-up, cancelling all i/o -// -static void ne2000_reset(void *p, int reset) -{ - ne2000_t *ne2000 = (ne2000_t *)p; - int i; - - ne2000_log("ne2000 reset\n"); - - // Initialise the mac address area by doubling the physical address - ne2000->macaddr[0] = ne2000->physaddr[0]; - ne2000->macaddr[1] = ne2000->physaddr[0]; - ne2000->macaddr[2] = ne2000->physaddr[1]; - ne2000->macaddr[3] = ne2000->physaddr[1]; - ne2000->macaddr[4] = ne2000->physaddr[2]; - ne2000->macaddr[5] = ne2000->physaddr[2]; - ne2000->macaddr[6] = ne2000->physaddr[3]; - ne2000->macaddr[7] = ne2000->physaddr[3]; - ne2000->macaddr[8] = ne2000->physaddr[4]; - ne2000->macaddr[9] = ne2000->physaddr[4]; - ne2000->macaddr[10] = ne2000->physaddr[5]; - ne2000->macaddr[11] = ne2000->physaddr[5]; - - // ne2k signature - for (i = 12; i < 32; i++) - ne2000->macaddr[i] = 0x57; - - // Zero out registers and memory - memset( & ne2000->CR, 0, sizeof(ne2000->CR) ); - memset( & ne2000->ISR, 0, sizeof(ne2000->ISR)); - memset( & ne2000->IMR, 0, sizeof(ne2000->IMR)); - memset( & ne2000->DCR, 0, sizeof(ne2000->DCR)); - memset( & ne2000->TCR, 0, sizeof(ne2000->TCR)); - memset( & ne2000->TSR, 0, sizeof(ne2000->TSR)); - //memset( & ne2000->RCR, 0, sizeof(ne2000->RCR)); - memset( & ne2000->RSR, 0, sizeof(ne2000->RSR)); - ne2000->tx_timer_active = 0; - ne2000->local_dma = 0; - ne2000->page_start = 0; - ne2000->page_stop = 0; - ne2000->bound_ptr = 0; - ne2000->tx_page_start = 0; - ne2000->num_coll = 0; - ne2000->tx_bytes = 0; - ne2000->fifo = 0; - ne2000->remote_dma = 0; - ne2000->remote_start = 0; - ne2000->remote_bytes = 0; - ne2000->tallycnt_0 = 0; - ne2000->tallycnt_1 = 0; - ne2000->tallycnt_2 = 0; - - //memset( & ne2000->physaddr, 0, sizeof(ne2000->physaddr)); - //memset( & ne2000->mchash, 0, sizeof(ne2000->mchash)); - ne2000->curr_page = 0; - - ne2000->rempkt_ptr = 0; - ne2000->localpkt_ptr = 0; - ne2000->address_cnt = 0; - - memset( & ne2000->mem, 0, sizeof(ne2000->mem)); - - // Set power-up conditions - ne2000->CR.stop = 1; - ne2000->CR.rdma_cmd = 4; - ne2000->ISR.reset = 1; - ne2000->DCR.longaddr = 1; - picint(1 << ne2000->base_irq); - picintc(1 << ne2000->base_irq); - //DEV_pic_lower_irq(ne2000->base_irq); -} - -#include "bswap.h" - -// -// read_cr/write_cr - utility routines for handling reads/writes to -// the Command Register -// -uint32_t ne2000_read_cr(ne2000_t *ne2000) -{ - uint32_t val; - - val = (((ne2000->CR.pgsel & 0x03) << 6) | - ((ne2000->CR.rdma_cmd & 0x07) << 3) | - (ne2000->CR.tx_packet << 2) | - (ne2000->CR.start << 1) | - (ne2000->CR.stop)); - ne2000_log("%s: read CR returns 0x%02x\n", (network_card_current == 1) ? "NE2000" : "RTL8029AS", val); - return val; -} - -void ne2000_write_cr(ne2000_t *ne2000, uint32_t value) -{ - ne2000_log("%s: wrote 0x%02x to CR\n", (network_card_current == 1) ? "NE2000" : "RTL8029AS", value); - - // Validate remote-DMA - if ((value & 0x38) == 0x00) { - ne2000_log("CR write - invalid rDMA value 0\n"); - value |= 0x20; /* dma_cmd == 4 is a safe default */ - } - - // Check for s/w reset - if (value & 0x01) { - ne2000->ISR.reset = 1; - ne2000->CR.stop = 1; - } else { - ne2000->CR.stop = 0; - } - - ne2000->CR.rdma_cmd = (value & 0x38) >> 3; - - // If start command issued, the RST bit in the ISR - // must be cleared - if ((value & 0x02) && !ne2000->CR.start) { - ne2000->ISR.reset = 0; - } - - ne2000->CR.start = ((value & 0x02) == 0x02); - ne2000->CR.pgsel = (value & 0xc0) >> 6; - - // Check for send-packet command - if (ne2000->CR.rdma_cmd == 3) { - // Set up DMA read from receive ring - ne2000->remote_start = ne2000->remote_dma = ne2000->bound_ptr * 256; - ne2000->remote_bytes = (uint16_t) ne2000_chipmem_read(ne2000, ne2000->bound_ptr * 256 + 2, 2); - ne2000_log("Sending buffer #x%x length %d\n", ne2000->remote_start, ne2000->remote_bytes); - } - - // Check for start-tx - if ((value & 0x04) && ne2000->TCR.loop_cntl) { - if (ne2000->TCR.loop_cntl != 1) { - ne2000_log("Loop mode %d not supported\n", ne2000->TCR.loop_cntl); - } else { - ne2000_rx_frame(ne2000, &ne2000->mem[ne2000->tx_page_start*256 - BX_NE2K_MEMSTART], - ne2000->tx_bytes); - } - } else if (value & 0x04) { - if (ne2000->CR.stop || (!ne2000->CR.start && (network_card_current == 1))) { - if (ne2000->tx_bytes == 0) /* njh@bandsman.co.uk */ - return; /* Solaris9 probe */ - ne2000_log("CR write - tx start, dev in reset\n"); - } - - if (ne2000->tx_bytes == 0) - ne2000_log("CR write - tx start, tx bytes == 0\n"); - - // Send the packet to the system driver - ne2000->CR.tx_packet = 1; - if(net_is_slirp) - { - slirp_input(&ne2000->mem[ne2000->tx_page_start*256 - BX_NE2K_MEMSTART], ne2000->tx_bytes); - ne2000_log("ne2000 slirp sending packet\n"); - } - if(net_is_pcap && net_pcap!=NULL) - { - _pcap_sendpacket(net_pcap, &ne2000->mem[ne2000->tx_page_start*256 - BX_NE2K_MEMSTART], ne2000->tx_bytes); - ne2000_log("ne2000 pcap sending packet\n"); - } - - // some more debug - if (ne2000->tx_timer_active) - ne2000_log("CR write, tx timer still active\n"); - - ne2000_tx_event(ne2000, value); - } - - // Linux probes for an interrupt by setting up a remote-DMA read - // of 0 bytes with remote-DMA completion interrupts enabled. - // Detect this here - if (ne2000->CR.rdma_cmd == 0x01 && - ne2000->CR.start && - ne2000->remote_bytes == 0) { - ne2000->ISR.rdma_done = 1; - if (ne2000->IMR.rdma_inte) { - picint(1 << ne2000->base_irq); - } - } -} - -// -// chipmem_read/chipmem_write - access the 64K private RAM. -// The ne2000 memory is accessed through the data port of -// the asic (offset 0) after setting up a remote-DMA transfer. -// Both byte and word accesses are allowed. -// The first 16 bytes contains the MAC address at even locations, -// and there is 16K of buffer memory starting at 16K -// - -uint32_t ne2000_chipmem_read(ne2000_t *ne2000, uint32_t address, unsigned int io_len) -{ - uint32_t retval = 0; - - if ((io_len == 2) && (address & 0x1)) - ne2000_log("unaligned chipmem word read\n"); - - // ROM'd MAC address - if ((address >=0) && (address <= 31)) { - retval = ne2000->macaddr[address % 32]; - if ((io_len == 2) || (io_len == 4)) { - retval |= (ne2000->macaddr[(address + 1) % 32] << 8); - } - if (io_len == 4) { - retval |= (ne2000->macaddr[(address + 2) % 32] << 16); - retval |= (ne2000->macaddr[(address + 3) % 32] << 24); - } - return (retval); - } - - if ((address >= BX_NE2K_MEMSTART) && (address < BX_NE2K_MEMEND)) { - retval = ne2000->mem[address - BX_NE2K_MEMSTART]; - if ((io_len == 2) || (io_len == 4)) { - retval |= (ne2000->mem[address - BX_NE2K_MEMSTART + 1] << 8); - } - if (io_len == 4) { - retval |= (ne2000->mem[address - BX_NE2K_MEMSTART + 2] << 16); - retval |= (ne2000->mem[address - BX_NE2K_MEMSTART + 3] << 24); - } - return (retval); - } - - ne2000_log("out-of-bounds chipmem read, %04X\n", address); - - return (0xff); -} - -void ne2000_chipmem_write(ne2000_t *ne2000, uint32_t address, uint32_t value, unsigned io_len) -{ - if ((io_len == 2) && (address & 0x1)) - ne2000_log("unaligned chipmem word write\n"); - - if ((address >= BX_NE2K_MEMSTART) && (address < BX_NE2K_MEMEND)) { - ne2000->mem[address - BX_NE2K_MEMSTART] = value & 0xff; - if ((io_len == 2) || (io_len == 4)) { - ne2000->mem[address - BX_NE2K_MEMSTART + 1] = value >> 8; - } - if (io_len == 4) { - ne2000->mem[address - BX_NE2K_MEMSTART + 2] = value >> 16; - ne2000->mem[address - BX_NE2K_MEMSTART + 3] = value >> 24; - } - } else - ne2000_log("out-of-bounds chipmem write, %04X\n", address); -} - -// -// asic_read/asic_write - This is the high 16 bytes of i/o space -// (the lower 16 bytes is for the DS8390). Only two locations -// are used: offset 0, which is used for data transfer, and -// offset 0xf, which is used to reset the device. -// The data transfer port is used to as 'external' DMA to the -// DS8390. The chip has to have the DMA registers set up, and -// after that, insw/outsw instructions can be used to move -// the appropriate number of bytes to/from the device. -// -uint32_t ne2000_asic_read(ne2000_t *ne2000, uint32_t offset, unsigned int io_len) -{ - uint32_t retval = 0; - - switch (offset) { - case 0x0: // Data register - // - // A read remote-DMA command must have been issued, - // and the source-address and length registers must - // have been initialised. - // - if (io_len > ne2000->remote_bytes) { - ne2000_log("dma read underrun iolen=%d remote_bytes=%d\n",io_len,ne2000->remote_bytes); - //return 0; - } - - ne2000_log("%s read DMA: addr=%4x remote_bytes=%d\n",(network_card_current == 1) ? "NE2000" : "RTL8029AS",ne2000->remote_dma,ne2000->remote_bytes); - retval = ne2000_chipmem_read(ne2000, ne2000->remote_dma, io_len); - // - // The 8390 bumps the address and decreases the byte count - // by the selected word size after every access, not by - // the amount of data requested by the host (io_len). - // - if (io_len == 4) { - ne2000->remote_dma += io_len; - } else { - ne2000->remote_dma += (ne2000->DCR.wdsize + 1); - } - if (ne2000->remote_dma == ne2000->page_stop << 8) { - ne2000->remote_dma = ne2000->page_start << 8; - } - // keep s.remote_bytes from underflowing - if (ne2000->remote_bytes > ne2000->DCR.wdsize) - if (io_len == 4) { - ne2000->remote_bytes -= io_len; - } else { - ne2000->remote_bytes -= (ne2000->DCR.wdsize + 1); - } - else - ne2000->remote_bytes = 0; - - // If all bytes have been written, signal remote-DMA complete - if (ne2000->remote_bytes == 0) { - ne2000->ISR.rdma_done = 1; - if (ne2000->IMR.rdma_inte) { - picint(1 << ne2000->base_irq); - } - } - break; - - case 0xf: // Reset register - ne2000_reset(ne2000, BX_RESET_SOFTWARE); - break; - - default: - ne2000_log("asic read invalid address %04x\n", (unsigned) offset); - break; - } - - return (retval); -} - -void ne2000_asic_write(ne2000_t *ne2000, uint32_t offset, uint32_t value, unsigned io_len) -{ - ne2000_log("%s: asic write addr=0x%02x, value=0x%04x\n", (network_card_current == 1) ? "NE2000" : "RTL8029AS",(unsigned) offset, (unsigned) value); - switch (offset) { - case 0x0: // Data register - see asic_read for a description - - if ((io_len > 1) && (ne2000->DCR.wdsize == 0)) { - ne2000_log("dma write length %d on byte mode operation\n", io_len); - break; - } - if (ne2000->remote_bytes == 0) { - ne2000_log("dma write, byte count 0\n"); - } - - ne2000_chipmem_write(ne2000, ne2000->remote_dma, value, io_len); - if (io_len == 4) { - ne2000->remote_dma += io_len; - } else { - ne2000->remote_dma += (ne2000->DCR.wdsize + 1); - } - if (ne2000->remote_dma == ne2000->page_stop << 8) { - ne2000->remote_dma = ne2000->page_start << 8; - } - - if (io_len == 4) { - ne2000->remote_bytes -= io_len; - } else { - ne2000->remote_bytes -= (ne2000->DCR.wdsize + 1); - } - if (ne2000->remote_bytes > BX_NE2K_MEMSIZ) - ne2000->remote_bytes = 0; - - // If all bytes have been written, signal remote-DMA complete - if (ne2000->remote_bytes == 0) { - ne2000->ISR.rdma_done = 1; - if (ne2000->IMR.rdma_inte) { - picint(1 << ne2000->base_irq); - } - } - break; - - case 0xf: // Reset register - // end of reset pulse - break; - - default: // this is invalid, but happens under win95 device detection - ne2000_log("asic write invalid address %04x, ignoring\n", (unsigned) offset); - break; - } -} - -// -// page0_read/page0_write - These routines handle reads/writes to -// the 'zeroth' page of the DS8390 register file -// -uint32_t ne2000_page0_read(ne2000_t *ne2000, uint32_t offset, unsigned int io_len) -{ - uint8_t value = 0; - - if (io_len > 1) { - ne2000_log("bad length! page 0 read from register 0x%02x, len=%u\n", offset, - io_len); /* encountered with win98 hardware probe */ - return value; - } - - switch (offset) { - case 0x1: // CLDA0 - value = (ne2000->local_dma & 0xff); - break; - - case 0x2: // CLDA1 - value = (ne2000->local_dma >> 8); - break; - - case 0x3: // BNRY - value = ne2000->bound_ptr; - break; - - case 0x4: // TSR - value = ((ne2000->TSR.ow_coll << 7) | - (ne2000->TSR.cd_hbeat << 6) | - (ne2000->TSR.fifo_ur << 5) | - (ne2000->TSR.no_carrier << 4) | - (ne2000->TSR.aborted << 3) | - (ne2000->TSR.collided << 2) | - (ne2000->TSR.tx_ok)); - break; - - case 0x5: // NCR - value = ne2000->num_coll; - break; - - case 0x6: // FIFO - // reading FIFO is only valid in loopback mode - ne2000_log("reading FIFO not supported yet\n"); - value = ne2000->fifo; - break; - - case 0x7: // ISR - value = ((ne2000->ISR.reset << 7) | - (ne2000->ISR.rdma_done << 6) | - (ne2000->ISR.cnt_oflow << 5) | - (ne2000->ISR.overwrite << 4) | - (ne2000->ISR.tx_err << 3) | - (ne2000->ISR.rx_err << 2) | - (ne2000->ISR.pkt_tx << 1) | - (ne2000->ISR.pkt_rx)); - break; - - case 0x8: // CRDA0 - value = (ne2000->remote_dma & 0xff); - break; - - case 0x9: // CRDA1 - value = (ne2000->remote_dma >> 8); - break; - - case 0xa: // reserved / RTL8029ID0 - if (network_card_current == 2) { - value = 0x50; - } else { - ne2000_log("reserved read - page 0, 0xa\n"); - value = 0xff; - } - break; - - case 0xb: // reserved / RTL8029ID1 - if (network_card_current == 2) { - value = 0x43; - } else { - ne2000_log("reserved read - page 0, 0xb\n"); - value = 0xff; - } - break; - - case 0xc: // RSR - value = ((ne2000->RSR.deferred << 7) | - (ne2000->RSR.rx_disabled << 6) | - (ne2000->RSR.rx_mbit << 5) | - (ne2000->RSR.rx_missed << 4) | - (ne2000->RSR.fifo_or << 3) | - (ne2000->RSR.bad_falign << 2) | - (ne2000->RSR.bad_crc << 1) | - (ne2000->RSR.rx_ok)); - break; - - case 0xd: // CNTR0 - value = ne2000->tallycnt_0; - break; - - case 0xe: // CNTR1 - value = ne2000->tallycnt_1; - break; - - case 0xf: // CNTR2 - value = ne2000->tallycnt_2; - break; - - default: - ne2000_log("page 0 register 0x%02x out of range\n", offset); - break; - } - - ne2000_log("page 0 read from register 0x%02x, value=0x%02x\n", offset, value); - return value; -} - -void ne2000_page0_write(ne2000_t *ne2000, uint32_t offset, uint32_t value, unsigned io_len) -{ - uint8_t value2; - - // It appears to be a common practice to use outw on page0 regs... - - // break up outw into two outb's - if (io_len == 2) { - ne2000_page0_write(ne2000, offset, (value & 0xff), 1); - if (offset < 0x0f) { - ne2000_page0_write(ne2000, offset + 1, ((value >> 8) & 0xff), 1); - } - return; - } - - ne2000_log("page 0 write to register 0x%02x, value=0x%02x\n", offset, value); - - switch (offset) { - case 0x1: // PSTART - ne2000->page_start = value; - break; - - case 0x2: // PSTOP - ne2000->page_stop = value; - break; - - case 0x3: // BNRY - ne2000->bound_ptr = value; - break; - - case 0x4: // TPSR - ne2000->tx_page_start = value; - break; - - case 0x5: // TBCR0 - // Clear out low byte and re-insert - ne2000->tx_bytes &= 0xff00; - ne2000->tx_bytes |= (value & 0xff); - break; - - case 0x6: // TBCR1 - // Clear out high byte and re-insert - ne2000->tx_bytes &= 0x00ff; - ne2000->tx_bytes |= ((value & 0xff) << 8); - break; - - case 0x7: // ISR - value &= 0x7f; // clear RST bit - status-only bit - // All other values are cleared iff the ISR bit is 1 - ne2000->ISR.pkt_rx &= ~((int)((value & 0x01) == 0x01)); - ne2000->ISR.pkt_tx &= ~((int)((value & 0x02) == 0x02)); - ne2000->ISR.rx_err &= ~((int)((value & 0x04) == 0x04)); - ne2000->ISR.tx_err &= ~((int)((value & 0x08) == 0x08)); - ne2000->ISR.overwrite &= ~((int)((value & 0x10) == 0x10)); - ne2000->ISR.cnt_oflow &= ~((int)((value & 0x20) == 0x20)); - ne2000->ISR.rdma_done &= ~((int)((value & 0x40) == 0x40)); - value = ((ne2000->ISR.rdma_done << 6) | - (ne2000->ISR.cnt_oflow << 5) | - (ne2000->ISR.overwrite << 4) | - (ne2000->ISR.tx_err << 3) | - (ne2000->ISR.rx_err << 2) | - (ne2000->ISR.pkt_tx << 1) | - (ne2000->ISR.pkt_rx)); - value &= ((ne2000->IMR.rdma_inte << 6) | - (ne2000->IMR.cofl_inte << 5) | - (ne2000->IMR.overw_inte << 4) | - (ne2000->IMR.txerr_inte << 3) | - (ne2000->IMR.rxerr_inte << 2) | - (ne2000->IMR.tx_inte << 1) | - (ne2000->IMR.rx_inte)); - if (value == 0) - picintc(1 << ne2000->base_irq); - break; - - case 0x8: // RSAR0 - // Clear out low byte and re-insert - ne2000->remote_start &= 0xff00; - ne2000->remote_start |= (value & 0xff); - ne2000->remote_dma = ne2000->remote_start; - break; - - case 0x9: // RSAR1 - // Clear out high byte and re-insert - ne2000->remote_start &= 0x00ff; - ne2000->remote_start |= ((value & 0xff) << 8); - ne2000->remote_dma = ne2000->remote_start; - break; - - case 0xa: // RBCR0 - // Clear out low byte and re-insert - ne2000->remote_bytes &= 0xff00; - ne2000->remote_bytes |= (value & 0xff); - break; - - case 0xb: // RBCR1 - // Clear out high byte and re-insert - ne2000->remote_bytes &= 0x00ff; - ne2000->remote_bytes |= ((value & 0xff) << 8); - break; - - case 0xc: // RCR - // Check if the reserved bits are set - if (value & 0xc0) - ne2000_log("RCR write, reserved bits set\n"); - - // Set all other bit-fields - ne2000->RCR.errors_ok = ((value & 0x01) == 0x01); - ne2000->RCR.runts_ok = ((value & 0x02) == 0x02); - ne2000->RCR.broadcast = ((value & 0x04) == 0x04); - ne2000->RCR.multicast = ((value & 0x08) == 0x08); - ne2000->RCR.promisc = ((value & 0x10) == 0x10); - ne2000->RCR.monitor = ((value & 0x20) == 0x20); - - // Monitor bit is a little suspicious... - if (value & 0x20) - ne2000_log("RCR write, monitor bit set!\n"); - break; - - case 0xd: // TCR - // Check reserved bits - if (value & 0xe0) - ne2000_log("TCR write, reserved bits set\n"); - - // Test loop mode (not supported) - if (value & 0x06) { - ne2000->TCR.loop_cntl = (value & 0x6) >> 1; - ne2000_log("TCR write, loop mode %d not supported\n", ne2000->TCR.loop_cntl); - } else { - ne2000->TCR.loop_cntl = 0; - } - - // Inhibit-CRC not supported. - if (value & 0x01) - ne2000_log("TCR write, inhibit-CRC not supported\n"); - - // Auto-transmit disable very suspicious - if (value & 0x08) - ne2000_log("TCR write, auto transmit disable not supported\n"); - - // Allow collision-offset to be set, although not used - ne2000->TCR.coll_prio = ((value & 0x08) == 0x08); - break; - - case 0xe: // DCR - // the loopback mode is not suppported yet - if (!(value & 0x08)) { - ne2000_log("DCR write, loopback mode selected\n"); - } - // It is questionable to set longaddr and auto_rx, since they - // aren't supported on the ne2000. Print a warning and continue - if (value & 0x04) - ne2000_log("DCR write - LAS set ???\n"); - if (value & 0x10) - ne2000_log("DCR write - AR set ???\n"); - - // Set other values. - ne2000->DCR.wdsize = ((value & 0x01) == 0x01); - ne2000->DCR.endian = ((value & 0x02) == 0x02); - ne2000->DCR.longaddr = ((value & 0x04) == 0x04); // illegal ? - ne2000->DCR.loop = ((value & 0x08) == 0x08); - ne2000->DCR.auto_rx = ((value & 0x10) == 0x10); // also illegal ? - ne2000->DCR.fifo_size = (value & 0x50) >> 5; - break; - - case 0xf: // IMR - // Check for reserved bit - if (value & 0x80) - ne2000_log("IMR write, reserved bit set\n"); - - // Set other values - ne2000->IMR.rx_inte = ((value & 0x01) == 0x01); - ne2000->IMR.tx_inte = ((value & 0x02) == 0x02); - ne2000->IMR.rxerr_inte = ((value & 0x04) == 0x04); - ne2000->IMR.txerr_inte = ((value & 0x08) == 0x08); - ne2000->IMR.overw_inte = ((value & 0x10) == 0x10); - ne2000->IMR.cofl_inte = ((value & 0x20) == 0x20); - ne2000->IMR.rdma_inte = ((value & 0x40) == 0x40); - value2 = ((ne2000->ISR.rdma_done << 6) | - (ne2000->ISR.cnt_oflow << 5) | - (ne2000->ISR.overwrite << 4) | - (ne2000->ISR.tx_err << 3) | - (ne2000->ISR.rx_err << 2) | - (ne2000->ISR.pkt_tx << 1) | - (ne2000->ISR.pkt_rx)); - if (((value & value2) & 0x7f) == 0) { - picintc(1 << ne2000->base_irq); - } else { - picint(1 << ne2000->base_irq); - } - break; - - default: - ne2000_log("page 0 write, bad register 0x%02x\n", offset); - break; - } -} - -// -// page1_read/page1_write - These routines handle reads/writes to -// the first page of the DS8390 register file -// -uint32_t ne2000_page1_read(ne2000_t *ne2000, uint32_t offset, unsigned int io_len) -{ - ne2000_log("page 1 read from register 0x%02x, len=%u\n", offset, io_len); - - switch (offset) { - case 0x1: // PAR0-5 - case 0x2: - case 0x3: - case 0x4: - case 0x5: - case 0x6: - return (ne2000->physaddr[offset - 1]); - break; - - case 0x7: // CURR - ne2000_log("returning current page: 0x%02x\n", (ne2000->curr_page)); - return (ne2000->curr_page); - - case 0x8: // MAR0-7 - case 0x9: - case 0xa: - case 0xb: - case 0xc: - case 0xd: - case 0xe: - case 0xf: - return (ne2000->mchash[offset - 8]); - break; - - default: - ne2000_log("page 1 read register 0x%02x out of range\n", offset); - break; - } - - return (0); -} - -void ne2000_page1_write(ne2000_t *ne2000, uint32_t offset, uint32_t value, unsigned io_len) -{ - ne2000_log("page 1 write to register 0x%02x, len=%u, value=0x%04x\n", offset, - io_len, value); - - switch (offset) { - case 0x1: // PAR0-5 - case 0x2: - case 0x3: - case 0x4: - case 0x5: - case 0x6: - ne2000->physaddr[offset - 1] = value; - if (offset == 6) { - ne2000_log("Physical address set to %02x:%02x:%02x:%02x:%02x:%02x\n", - ne2000->physaddr[0], - ne2000->physaddr[1], - ne2000->physaddr[2], - ne2000->physaddr[3], - ne2000->physaddr[4], - ne2000->physaddr[5]); - } - break; - - case 0x7: // CURR - ne2000->curr_page = value; - break; - - case 0x8: // MAR0-7 - case 0x9: - case 0xa: - case 0xb: - case 0xc: - case 0xd: - case 0xe: - case 0xf: - ne2000->mchash[offset - 8] = value; - break; - - default: - ne2000_log("page 1 write register 0x%02x out of range\n", offset); - break; - } -} - -// -// page2_read/page2_write - These routines handle reads/writes to -// the second page of the DS8390 register file -// -uint32_t ne2000_page2_read(ne2000_t *ne2000, uint32_t offset, unsigned int io_len) -{ - ne2000_log("page 2 read from register 0x%02x, len=%u\n", offset, io_len); - - switch (offset) { - case 0x1: // PSTART - return (ne2000->page_start); - - case 0x2: // PSTOP - return (ne2000->page_stop); - - case 0x3: // Remote Next-packet pointer - return (ne2000->rempkt_ptr); - - case 0x4: // TPSR - return (ne2000->tx_page_start); - - case 0x5: // Local Next-packet pointer - return (ne2000->localpkt_ptr); - - case 0x6: // Address counter (upper) - return (ne2000->address_cnt >> 8); - - case 0x7: // Address counter (lower) - return (ne2000->address_cnt & 0xff); - - case 0x8: // Reserved - case 0x9: - case 0xa: - case 0xb: - ne2000_log("reserved read - page 2, register 0x%02x\n", offset); - return (0xff); - - case 0xc: // RCR - return ((ne2000->RCR.monitor << 5) | - (ne2000->RCR.promisc << 4) | - (ne2000->RCR.multicast << 3) | - (ne2000->RCR.broadcast << 2) | - (ne2000->RCR.runts_ok << 1) | - (ne2000->RCR.errors_ok)); - - case 0xd: // TCR - return ((ne2000->TCR.coll_prio << 4) | - (ne2000->TCR.ext_stoptx << 3) | - ((ne2000->TCR.loop_cntl & 0x3) << 1) | - (ne2000->TCR.crc_disable)); - - case 0xe: // DCR - return (((ne2000->DCR.fifo_size & 0x3) << 5) | - (ne2000->DCR.auto_rx << 4) | - (ne2000->DCR.loop << 3) | - (ne2000->DCR.longaddr << 2) | - (ne2000->DCR.endian << 1) | - (ne2000->DCR.wdsize)); - - case 0xf: // IMR - return ((ne2000->IMR.rdma_inte << 6) | - (ne2000->IMR.cofl_inte << 5) | - (ne2000->IMR.overw_inte << 4) | - (ne2000->IMR.txerr_inte << 3) | - (ne2000->IMR.rxerr_inte << 2) | - (ne2000->IMR.tx_inte << 1) | - (ne2000->IMR.rx_inte)); - - default: - ne2000_log("page 2 register 0x%02x out of range\n", offset); - break; - } - - return (0); -} - -void ne2000_page2_write(ne2000_t *ne2000, uint32_t offset, uint32_t value, unsigned io_len) -{ - // Maybe all writes here should be BX_PANIC()'d, since they - // affect internal operation, but let them through for now - // and print a warning. - ne2000_log("page 2 write to register 0x%02x, len=%u, value=0x%04x\n", offset, - io_len, value); - - switch (offset) { - case 0x1: // CLDA0 - // Clear out low byte and re-insert - ne2000->local_dma &= 0xff00; - ne2000->local_dma |= (value & 0xff); - break; - - case 0x2: // CLDA1 - // Clear out high byte and re-insert - ne2000->local_dma &= 0x00ff; - ne2000->local_dma |= ((value & 0xff) << 8); - break; - - case 0x3: // Remote Next-pkt pointer - ne2000->rempkt_ptr = value; - break; - - case 0x4: - ne2000_log("page 2 write to reserved register 0x04\n"); - break; - - case 0x5: // Local Next-packet pointer - ne2000->localpkt_ptr = value; - break; - - case 0x6: // Address counter (upper) - // Clear out high byte and re-insert - ne2000->address_cnt &= 0x00ff; - ne2000->address_cnt |= ((value & 0xff) << 8); - break; - - case 0x7: // Address counter (lower) - // Clear out low byte and re-insert - ne2000->address_cnt &= 0xff00; - ne2000->address_cnt |= (value & 0xff); - break; - - case 0x8: - case 0x9: - case 0xa: - case 0xb: - case 0xc: - case 0xd: - case 0xe: - case 0xf: - ne2000_log("page 2 write to reserved register 0x%02x\n", offset); - break; - - default: - ne2000_log("page 2 write, illegal register 0x%02x\n", offset); - break; - } -} - -// -// page3_read/page3_write - writes to this page are illegal -// -uint32_t ne2000_page3_read(ne2000_t *ne2000, uint32_t offset, unsigned int io_len) -{ - if (network_card_current == 2) { - switch (offset) { - case 0x3: // CONFIG0 - return (0); - case 0x5: // CONFIG2 - return (0x40); - case 0x6: // CONFIG3 - return (0x40); - default: - ne2000_log("page 3 read register 0x%02x attempted\n", offset); - return (0); - } - } else { - ne2000_log("page 3 read register 0x%02x attempted\n", offset); - return (0); - } -} - -void ne2000_page3_write(ne2000_t *ne2000, uint32_t offset, uint32_t value, unsigned io_len) -{ - ne2000_log("page 3 write register 0x%02x attempted\n", offset); - return; -} - -void ne2000_tx_timer(void *p) -{ - ne2000_t *ne2000 = (ne2000_t *)p; - ne2000_log("tx_timer\n"); - ne2000->CR.tx_packet = 0; - ne2000->TSR.tx_ok = 1; - ne2000->ISR.pkt_tx = 1; - // Generate an interrupt if not masked - if (ne2000->IMR.tx_inte) { - picint(1 << ne2000->base_irq); - } - ne2000->tx_timer_active = 0; -} - -void ne2000_tx_event(void *p, uint32_t val) -{ - ne2000_t *ne2000 = (ne2000_t *)p; - ne2000_tx_timer(ne2000); -} - -// -// read_handler/read - i/o 'catcher' function called from BOCHS -// mainline when the CPU attempts a read in the i/o space registered -// by this ne2000 instance -// -uint32_t ne2000_read(ne2000_t *ne2000, uint32_t address, unsigned io_len) -{ - ne2000_log("%s: read addr %x, len %d\n", (network_card_current == 1) ? "NE2000" : "RTL8029AS", address, io_len); - uint32_t retval = 0; - int offset = address - ne2000->base_address; - - if (offset >= 0x10) { - retval = ne2000_asic_read(ne2000, offset - 0x10, io_len); - } else if (offset == 0x00) { - retval = ne2000_read_cr(ne2000); - } else { - switch (ne2000->CR.pgsel) { - case 0x00: - retval = ne2000_page0_read(ne2000, offset, io_len); - break; - - case 0x01: - retval = ne2000_page1_read(ne2000, offset, io_len); - break; - - case 0x02: - retval = ne2000_page2_read(ne2000, offset, io_len); - break; - - case 0x03: - retval = ne2000_page3_read(ne2000, offset, io_len); - break; - - default: - ne2000_log("unknown value of pgsel in read - %d\n", ne2000->CR.pgsel); - break; - } - } - - return (retval); -} - -void ne2000_write(ne2000_t *ne2000, uint32_t address, uint32_t value, unsigned io_len) -{ - ne2000_log("%s: write addr %x, value %x len %d\n", (network_card_current == 1) ? "NE2000" : "RTL8029AS", address, value, io_len); - int offset = address - ne2000->base_address; - - // - // The high 16 bytes of i/o space are for the ne2000 asic - - // the low 16 bytes are for the DS8390, with the current - // page being selected by the PS0,PS1 registers in the - // command register - // - if (offset >= 0x10) { - ne2000_asic_write(ne2000, offset - 0x10, value, io_len); - } else if (offset == 0x00) { - ne2000_write_cr(ne2000, value); - } else { - switch (ne2000->CR.pgsel) { - case 0x00: - ne2000_page0_write(ne2000, offset, value, io_len); - break; - - case 0x01: - ne2000_page1_write(ne2000, offset, value, io_len); - break; - - case 0x02: - ne2000_page2_write(ne2000, offset, value, io_len); - break; - - case 0x03: - ne2000_page3_write(ne2000, offset, value, io_len); - break; - - default: - ne2000_log("unknown value of pgsel in write - %d\n", ne2000->CR.pgsel); - break; - } - } -} - -/* - * mcast_index() - return the 6-bit index into the multicast - * table. Stolen unashamedly from FreeBSD's if_ed.c - */ -static int mcast_index(const void *dst) -{ -#define POLYNOMIAL 0x04c11db6 - unsigned long crc = 0xffffffffL; - int carry, i, j; - unsigned char b; - unsigned char *ep = (unsigned char *) dst; - - for (i = 6; --i >= 0;) { - b = *ep++; - for (j = 8; --j >= 0;) { - carry = ((crc & 0x80000000L) ? 1 : 0) ^ (b & 0x01); - crc <<= 1; - b >>= 1; - if (carry) - crc = ((crc ^ POLYNOMIAL) | carry); - } - } - return (crc >> 26); -#undef POLYNOMIAL -} - -/* - * rx_frame() - called by the platform-specific code when an - * ethernet frame has been received. The destination address - * is tested to see if it should be accepted, and if the - * rx ring has enough room, it is copied into it and - * the receive process is updated - */ -void ne2000_rx_frame(void *p, const void *buf, int io_len) -{ - ne2000_t *ne2000 = (ne2000_t *)p; - - int pages; - int avail; - int idx; - int wrapped; - int nextpage; - uint8_t pkthdr[4]; - uint8_t *pktbuf = (uint8_t *) buf; - uint8_t *startptr; - static uint8_t bcast_addr[6] = {0xff,0xff,0xff,0xff,0xff,0xff}; - uint32_t mac_cmp32[2]; - uint16_t mac_cmp16[2]; - - if(io_len != 60) { - ne2000_log("rx_frame with length %d\n", io_len); - } - - //LOG_MSG("stop=%d, pagestart=%x, dcr_loop=%x, tcr_loopcntl=%x", - // ne2000->CR.stop, ne2000->page_start, - // ne2000->DCR.loop, ne2000->TCR.loop_cntl); - if ((ne2000->CR.stop != 0) || - (ne2000->page_start == 0) /*|| - ((ne2000->DCR.loop == 0) && - (ne2000->TCR.loop_cntl != 0))*/) { - return; - } - - // Add the pkt header + CRC to the length, and work - // out how many 256-byte pages the frame would occupy - pages = (io_len + 4 + 4 + 255)/256; - - if (ne2000->curr_page < ne2000->bound_ptr) { - avail = ne2000->bound_ptr - ne2000->curr_page; - } else { - avail = (ne2000->page_stop - ne2000->page_start) - - (ne2000->curr_page - ne2000->bound_ptr); - wrapped = 1; - } - - // Avoid getting into a buffer overflow condition by not attempting - // to do partial receives. The emulation to handle this condition - // seems particularly painful. - if ((avail < pages) -#if BX_NE2K_NEVER_FULL_RING - || (avail == pages) -#endif - ) { - ne2000_log("no space\n"); - return; - } - - if ((io_len < 40/*60*/) && !ne2000->RCR.runts_ok) { - ne2000_log("rejected small packet, length %d\n", io_len); - return; - } - // some computers don't care... - if (io_len < 60) io_len=60; - - // Do address filtering if not in promiscuous mode - if (! ne2000->RCR.promisc) { - /* Received. */ - mac_cmp32[0] = *(uint32_t *) (buf); - mac_cmp16[0] = *(uint16_t *) (buf+4); - /* Local. */ - mac_cmp32[1] = *(uint32_t *) (bcast_addr); - mac_cmp16[1] = *(uint16_t *) (bcast_addr+4); - // if (!memcmp(buf, bcast_addr, 6)) { - if ((mac_cmp32[0] == mac_cmp32[1]) && (mac_cmp16[0] == mac_cmp16[1])) { - if (!ne2000->RCR.broadcast) { - return; - } - } else if (pktbuf[0] & 0x01) { - if (! ne2000->RCR.multicast) { - return; - } - idx = mcast_index(buf); - if (!(ne2000->mchash[idx >> 3] & (1 << (idx & 0x7)))) { - return; - } - } else if (0 != memcmp(buf, ne2000->physaddr, 6)) { - return; - } - } else { - ne2000_log("rx_frame promiscuous receive\n"); - } - - ne2000_log("rx_frame %d to %x:%x:%x:%x:%x:%x from %x:%x:%x:%x:%x:%x\n", - io_len, - pktbuf[0], pktbuf[1], pktbuf[2], pktbuf[3], pktbuf[4], pktbuf[5], - pktbuf[6], pktbuf[7], pktbuf[8], pktbuf[9], pktbuf[10], pktbuf[11]); - - nextpage = ne2000->curr_page + pages; - if (nextpage >= ne2000->page_stop) { - nextpage -= ne2000->page_stop - ne2000->page_start; - } - - // Setup packet header - pkthdr[0] = 0; // rx status - old behavior - pkthdr[0] = 1; // Probably better to set it all the time - // rather than set it to 0, which is clearly wrong. - if (pktbuf[0] & 0x01) { - pkthdr[0] |= 0x20; // rx status += multicast packet - } - pkthdr[1] = nextpage; // ptr to next packet - pkthdr[2] = (io_len + 4) & 0xff; // length-low - pkthdr[3] = (io_len + 4) >> 8; // length-hi - - // copy into buffer, update curpage, and signal interrupt if config'd - startptr = & ne2000->mem[ne2000->curr_page * 256 - - BX_NE2K_MEMSTART]; - if ((nextpage > ne2000->curr_page) || - ((ne2000->curr_page + pages) == ne2000->page_stop)) { - // memcpy(startptr, pkthdr, 4); - *(uint32_t *) startptr = *(uint32_t *) pkthdr; - memcpy(startptr + 4, buf, io_len); - ne2000->curr_page = nextpage; - } else { - int endbytes = (ne2000->page_stop - ne2000->curr_page) - * 256; - // memcpy(startptr, pkthdr, 4); - *(uint32_t *) startptr = *(uint32_t *) pkthdr; - memcpy(startptr + 4, buf, endbytes - 4); - startptr = & ne2000->mem[ne2000->page_start * 256 - - BX_NE2K_MEMSTART]; - memcpy(startptr, (void *)(pktbuf + endbytes - 4), - io_len - endbytes + 8); - ne2000->curr_page = nextpage; - } - - ne2000->RSR.rx_ok = 1; - if (pktbuf[0] & 0x80) { - ne2000->RSR.rx_mbit = 1; - } - - ne2000->ISR.pkt_rx = 1; - - if (ne2000->IMR.rx_inte) { - //LOG_MSG("packet rx interrupt"); - picint(1 << ne2000->base_irq); - //DEV_pic_raise_irq(ne2000->base_irq); - } //else LOG_MSG("no packet rx interrupt"); - -} - -uint8_t ne2000_readb(uint16_t addr, void *p) -{ - ne2000_t *ne2000 = (ne2000_t *)p; - return ne2000_read(ne2000, addr, 1); -} - -uint16_t ne2000_readw(uint16_t addr, void *p) -{ - ne2000_t *ne2000 = (ne2000_t *)p; - if (ne2000->DCR.wdsize & 1) - return ne2000_read(ne2000, addr, 2); - else - return ne2000_read(ne2000, addr, 1); -} - -uint32_t ne2000_readl(uint16_t addr, void *p) -{ - ne2000_t *ne2000 = (ne2000_t *)p; - return ne2000_read(ne2000, addr, 4); -} - -void ne2000_writeb(uint16_t addr, uint8_t val, void *p) -{ - ne2000_t *ne2000 = (ne2000_t *)p; - ne2000_write(ne2000, addr, val, 1); -} - -void ne2000_writew(uint16_t addr, uint16_t val, void *p) -{ - ne2000_t *ne2000 = (ne2000_t *)p; - if (ne2000->DCR.wdsize & 1) - ne2000_write(ne2000, addr, val, 2); - else - ne2000_write(ne2000, addr, val, 1); -} - -void ne2000_writel(uint16_t addr, uint32_t val, void *p) -{ - ne2000_t *ne2000 = (ne2000_t *)p; - ne2000_write(ne2000, addr, val, 4); -} - -void ne2000_poller(void *p) -{ - ne2000_t *ne2000 = (ne2000_t *)p; - struct queuepacket *qp; - const unsigned char *data; - struct pcap_pkthdr h; - uint32_t mac_cmp32[2]; - uint16_t mac_cmp16[2]; - - - int res; -if(net_is_slirp) { - while(QueuePeek(slirpq)>0) - { - qp=QueueDelete(slirpq); - if((ne2000->DCR.loop == 0) || (ne2000->TCR.loop_cntl != 0)) - { - free(qp); - return; - } - ne2000_rx_frame(ne2000,&qp->data,qp->len); - ne2000_log("ne2000 inQ:%d got a %dbyte packet @%d\n",QueuePeek(slirpq),qp->len,qp); - free(qp); - } - fizz++; - if(fizz>1200){fizz=0;slirp_tic();} - }//end slirp -if(net_is_pcap && net_pcap!=NULL) - { - if((ne2000->DCR.loop == 0) || (ne2000->TCR.loop_cntl != 0)) - { - return; - } - data=_pcap_next(net_pcap,&h); - if(data==0x0) - { - return; - } - /* Received. */ - mac_cmp32[0] = *(uint32_t *) (data+6); - mac_cmp16[0] = *(uint16_t *) (data+10); - /* Local. */ - mac_cmp32[1] = *(uint32_t *) (maclocal); - mac_cmp16[1] = *(uint16_t *) (maclocal+4); - // if((memcmp(data+6,maclocal,6))==0) - /* if ((mac_cmp32[0] == mac_cmp32[1]) && (mac_cmp16[0] == mac_cmp16[1])) - { - ne2000_log("ne2000 we just saw ourselves\n"); - } - else { */ - if ((mac_cmp32[0] != mac_cmp32[1]) || (mac_cmp16[0] != mac_cmp16[1])) - { - // ne2000_log("ne2000 pcap received a frame %d bytes\n",h.caplen); - ne2000_rx_frame(ne2000,data,h.caplen); - } - } -} - -typedef union -{ - uint32_t addr; - uint8_t addr_regs[4]; -} bar_t; - -uint8_t ne2000_pci_regs[256]; - -bar_t ne2000_pci_bar[2]; - -uint32_t bios_addr = 0xD0000; -uint32_t old_base_addr = 0; - -uint32_t bios_size = 0; -uint32_t bios_mask = 0; - -void ne2000_io_set(uint16_t addr, ne2000_t *ne2000) -{ - old_base_addr = addr; - io_sethandler(addr, 0x0010, ne2000_readb, ne2000_readw, ne2000_readl, ne2000_writeb, ne2000_writew, ne2000_writel, ne2000); - io_sethandler(addr+0x10, 0x0010, ne2000_readb, ne2000_readw, ne2000_readl, ne2000_writeb, ne2000_writew, ne2000_writel, ne2000); - io_sethandler(addr+0x1f, 0x0001, ne2000_readb, ne2000_readw, ne2000_readl, ne2000_writeb, ne2000_writew, ne2000_writel, ne2000); -} - -void ne2000_io_remove(int16_t addr, ne2000_t *ne2000) -{ - io_removehandler(addr, 0x0010, ne2000_readb, ne2000_readw, ne2000_readl, ne2000_writeb, ne2000_writew, ne2000_writel, ne2000); - io_removehandler(addr+0x10, 0x0010, ne2000_readb, ne2000_readw, ne2000_readl, ne2000_writeb, ne2000_writew, ne2000_writel, ne2000); - io_removehandler(addr+0x1f, 0x0001, ne2000_readb, ne2000_readw, ne2000_readl, ne2000_writeb, ne2000_writew, ne2000_writel, ne2000); -} - -uint8_t ne2000_pci_read(int func, int addr, void *p) -{ - ne2000_t *ne2000 = (ne2000_t *) p; - - // ne2000_log("NE2000 PCI read %08X\n", addr); - switch (addr) - { - case 0x00:/* case 0x2C:*/ return 0xec; - case 0x01:/* case 0x2D:*/ return 0x10; - - case 0x02:/* case 0x2E:*/ return 0x29; - case 0x03:/* case 0x2F:*/ return 0x80; - - case 0x2C: return 0xF4; - case 0x2D: return 0x1A; - case 0x2E: return 0x00; - case 0x2F: return 0x11; - - case 0x04: - return ne2000_pci_regs[0x04]; /*Respond to IO and memory accesses*/ - case 0x05: - return ne2000_pci_regs[0x05]; - - case 0x07: return 2; - - case 0x08: return 0; /*Revision ID*/ - case 0x09: return 0; /*Programming interface*/ - - case 0x0B: return ne2000_pci_regs[0x0B]; - - case 0x10: return 1; /*I/O space*/ - case 0x11: return ne2000_pci_bar[0].addr_regs[1]; - case 0x12: return ne2000_pci_bar[0].addr_regs[2]; - case 0x13: return ne2000_pci_bar[0].addr_regs[3]; - - case 0x30: return ne2000_pci_bar[1].addr_regs[0] & 0x01; /*BIOS ROM address*/ - // case 0x31: return (ne2000_pci_bar[1].addr_regs[1] & 0xE0) | 0x18; - case 0x31: return (ne2000_pci_bar[1].addr_regs[1] & bios_mask) | 0x18; - case 0x32: return ne2000_pci_bar[1].addr_regs[2]; - case 0x33: return ne2000_pci_bar[1].addr_regs[3]; - - case 0x3C: return ne2000_pci_regs[0x3C]; - case 0x3D: return ne2000_pci_regs[0x3D]; - } - return 0; -} - -void ne2000_update_bios(ne2000_t *ne2000) -{ - int reg_bios_enable; - - // reg_bios_enable = ne2000_pci_regs[0x30]; - reg_bios_enable = 1; - - /* PCI BIOS stuff, just enable_disable. */ - if (!disable_netbios && reg_bios_enable) - { - mem_mapping_enable(&ne2000->bios_rom.mapping); - mem_mapping_set_addr(&ne2000->bios_rom.mapping, bios_addr, 0x10000); - ne2000_log("Network BIOS now at: %08X\n", bios_addr); - } - else - { - mem_mapping_disable(&ne2000->bios_rom.mapping); - if (network_card_current == 2) ne2000_pci_bar[1].addr = 0; - } -} - -void ne2000_pci_write(int func, int addr, uint8_t val, void *p) -{ - ne2000_t *ne2000 = (ne2000_t *) p; - - // ne2000_log("ne2000_pci_write: addr=%02x val=%02x\n", addr, val); - switch (addr) - { - case 0x04: - if (val & PCI_COMMAND_IO) - { - ne2000_io_remove(ne2000->base_address, ne2000); - ne2000_io_set(ne2000->base_address, ne2000); - } - else - { - ne2000_io_remove(ne2000->base_address, ne2000); - } - ne2000_pci_regs[addr] = val; - break; - - case 0x10: - val &= 0xfc; - val |= 1; - case 0x11: case 0x12: case 0x13: - /* I/O Base set. */ - /* First, remove the old I/O, if old base was >= 0x280. */ - ne2000_io_remove(ne2000->base_address, ne2000); - /* Then let's set the PCI regs. */ - ne2000_pci_bar[0].addr_regs[addr & 3] = val; - /* Then let's calculate the new I/O base. */ - ne2000->base_address = ne2000_pci_bar[0].addr & 0xff00; - /* If the base is below 0x280, return. */ - /* Log the new base. */ - ne2000_log("NE2000 RTL8029AS PCI: New I/O base is %04X\n" , ne2000->base_address); - /* We're done, so get out of the here. */ - return; - - case 0x30: case 0x31: case 0x32: case 0x33: - ne2000_pci_bar[1].addr_regs[addr & 3] = val; - ne2000_pci_bar[1].addr_regs[1] &= bios_mask; - bios_addr = ne2000_pci_bar[1].addr & 0xffffe000; - ne2000_pci_bar[1].addr &= 0xffffe000; - ne2000_pci_bar[1].addr |= 0x1801; - ne2000_update_bios(ne2000); - return; - -/* Commented out until an APIC controller is emulated for the PIIX3, - otherwise the RTL-8029/AS will not get an IRQ on boards using the PIIX3. */ -#if 0 - case 0x3C: - ne2000_pci_regs[addr] = val; - if (val != 0xFF) - { - ne2000_log("NE2000 IRQ now: %i\n", val); - ne2000_setirq(ne2000, val); - } - return; -#endif - } -} - -void ne2000_rom_init(ne2000_t *ne2000, char *s) -{ - FILE *f = fopen(s, "rb"); - uint32_t temp; - if(!f) - { - disable_netbios = 1; - ne2000_update_bios(ne2000); - return; - } - fseek(f, 0, SEEK_END); - temp = ftell(f); - fclose(f); - bios_size = 0x10000; - if (temp <= 0x8000) - { - bios_size = 0x8000; - } - if (temp <= 0x4000) - { - bios_size = 0x4000; - } - if (temp <= 0x2000) - { - bios_size = 0x2000; - } - bios_mask = (bios_size >> 8) & 0xff; - bios_mask = (0x100 - bios_mask) & 0xff; - - rom_init(&ne2000->bios_rom, s, 0xd0000, bios_size, bios_size - 1, 0, MEM_MAPPING_EXTERNAL); -} - -void *ne2000_init() -{ - int rc; - int config_net_type; - int net_type; - ne2000_t *ne2000 = malloc(sizeof(ne2000_t)); - memset(ne2000, 0, sizeof(ne2000_t)); - - ne2000->base_address = device_get_config_int("addr"); - disable_netbios = device_get_config_int("disable_netbios"); - ne2000_setirq(ne2000, device_get_config_int("irq")); - - //net_type - //0 pcap - //1 slirp - // - config_net_type = device_get_config_int("net_type"); - // net_is_slirp = config_get_int(NULL, "net_type", 1); - /* Network type is now specified in device config. */ - net_is_slirp = config_net_type ? 1 : 0; - net_is_pcap = config_net_type ? 0 : 1; - if(!strcmp("nothing", config_get_string(NULL, "pcap_device", "nothing"))) - { - net_is_pcap = 0; - net_is_slirp = 1; - } - pclog("net_is_pcap = %i, net_is_slirp = %i\n", net_is_pcap, net_is_slirp); - - // ne2000_log("ne2000 pcap device %s\n",config_get_string(NULL,"pcap_device","nothing")); - - ne2000_io_set(ne2000->base_address, ne2000); - memcpy(ne2000->physaddr, maclocal, 6); - - if (!disable_netbios) - ne2000_rom_init(ne2000, "roms/ne2000.rom"); - - ne2000_reset(ne2000, BX_RESET_HARDWARE); - vlan_handler(ne2000_poller, ne2000); - - ne2000_log("ne2000 isa init 0x%X %d\tslirp is %d net_is_pcap is %d\n",ne2000->base_address,device_get_config_int("irq"),net_is_slirp,net_is_pcap); - - //need a switch statment for more network types. - - if ( net_is_slirp ) { - ne2000_log("ne2000 initalizing SLiRP\n"); - net_is_pcap=0; - rc=slirp_init(); - ne2000_log("ne2000 slirp_init returned: %d\n",rc); - if ( rc == 0 ) - { - ne2000_log("ne2000 slirp initalized!\n"); - - net_slirp_inited=1; - slirpq = QueueCreate(); - net_is_slirp=1; - fizz=0; - ne2000_log("ne2000 slirpq is %x\n",&slirpq); - } - else { - net_slirp_inited=0; - net_is_slirp=0; - } - } - if ( net_is_pcap ) { //pcap - char errbuf[32768]; - - ne2000_log("ne2000 initalizing libpcap\n"); - net_is_slirp=0; - net_hLib = LoadLibraryA(net_lib_name); - if(net_hLib==0) - { - ne2000_log("ne2000 Failed to load %s\n",net_lib_name); - net_is_pcap=0; - //return; - } - _pcap_lib_version =(PCAP_LIB_VERSION)GetProcAddress(net_hLib,"pcap_lib_version"); - _pcap_open_live=(PCAP_OPEN_LIVE)GetProcAddress(net_hLib,"pcap_open_live"); - _pcap_sendpacket=(PCAP_SENDPACKET)GetProcAddress(net_hLib,"pcap_sendpacket"); - _pcap_setnonblock=(PCAP_SETNONBLOCK)GetProcAddress(net_hLib,"pcap_setnonblock"); - _pcap_next=(PCAP_NEXT)GetProcAddress(net_hLib,"pcap_next"); - _pcap_close=(PCAP_CLOSE)GetProcAddress(net_hLib,"pcap_close"); - _pcap_getnonblock=(PCAP_GETNONBLOCK)GetProcAddress(net_hLib,"pcap_getnonblock"); - _pcap_compile=(PCAP_COMPILE)GetProcAddress(net_hLib,"pcap_compile"); - _pcap_setfilter=(PCAP_SETFILTER)GetProcAddress(net_hLib,"pcap_setfilter"); - - if(_pcap_lib_version && _pcap_open_live && _pcap_sendpacket && _pcap_setnonblock && _pcap_next && _pcap_close && _pcap_getnonblock) - { - ne2000_log("ne2000 Pcap version [%s]\n",_pcap_lib_version()); - - //if((net_pcap=_pcap_open_live("\\Device\\NPF_{0CFA803F-F443-4BB9-A83A-657029A98195}",1518,1,15,errbuf))==0) - if((net_pcap=_pcap_open_live(config_get_string(NULL,"pcap_device","nothing"),1518,1,15,errbuf))==0) - { - ne2000_log("ne2000 pcap_open_live error on %s!\n",config_get_string(NULL,"pcap_device","whatever the ethernet is")); - net_is_pcap=0; return(ne2000); //YUCK!!! - } - } - else { - ne2000_log("%d %d %d %d %d %d %d\n",_pcap_lib_version, _pcap_open_live,_pcap_sendpacket,_pcap_setnonblock,_pcap_next,_pcap_close,_pcap_getnonblock); - net_is_pcap=1; - } - - //Time to check that we are in non-blocking mode. - rc=_pcap_getnonblock(net_pcap,errbuf); - ne2000_log("ne2000 pcap is currently in %s mode\n",rc? "non-blocking":"blocking"); - switch(rc) - { - case 0: - ne2000_log("ne2000 Setting interface to non-blocking mode.."); - rc=_pcap_setnonblock(net_pcap,1,errbuf); - if(rc==0) { //no errors! - ne2000_log(".."); - rc=_pcap_getnonblock(net_pcap,errbuf); - if(rc==1) { - ne2000_log("..!",rc); - net_is_pcap=1; - } - else{ - ne2000_log("\tunable to set pcap into non-blocking mode!\nContinuining without pcap.\n"); - net_is_pcap=0; - } - }//end set nonblock - else{ne2000_log("There was an unexpected error of [%s]\n\nexiting.\n",errbuf);net_is_pcap=0;} - ne2000_log("\n"); - break; - case 1: - ne2000_log("non blocking\n"); - break; - default: - ne2000_log("this isn't right!!!\n"); - net_is_pcap=0; - break; - } - if( net_is_pcap ) { - if(_pcap_compile && _pcap_setfilter) { //we can do this! - struct bpf_program fp; - char filter_exp[255]; - ne2000_log("ne2000 Building packet filter..."); - sprintf(filter_exp,"( ((ether dst ff:ff:ff:ff:ff:ff) or (ether dst %02x:%02x:%02x:%02x:%02x:%02x)) and not (ether src %02x:%02x:%02x:%02x:%02x:%02x) )", \ - maclocal[0], maclocal[1], maclocal[2], maclocal[3], maclocal[4], maclocal[5],\ - maclocal[0], maclocal[1], maclocal[2], maclocal[3], maclocal[4], maclocal[5]); - - //I'm doing a MAC level filter so TCP/IP doesn't matter. - if (_pcap_compile(net_pcap, &fp, filter_exp, 0, 0xffffffff) == -1) { - ne2000_log("\nne2000 Couldn't compile filter\n"); - } - else { - ne2000_log("..."); - if (_pcap_setfilter(net_pcap, &fp) == -1) { - ne2000_log("\nError installing pcap filter.\n"); - }//end of set_filter failure - else { - ne2000_log("...!\n"); - } - } - ne2000_log("ne2000 Using filter\t[%s]\n",filter_exp); - //scanf(filter_exp); //pause - } - else - { - ne2000_log("ne2000 Your platform lacks pcap_compile & pcap_setfilter\n"); - net_is_pcap=0; - } - ne2000_log("ne2000 net_is_pcap is %d and net_pcap is %x\n",net_is_pcap,net_pcap); - } - } //end pcap setup - - //timer_add(slirp_tic,&delay,TIMER_ALWAYS_ENABLED,NULL); - //timer_add(keyboard_amstrad_poll, &keybsenddelay, TIMER_ALWAYS_ENABLED, NULL); -ne2000_log("ne2000 is_slirp %d is_pcap %d\n",net_is_slirp,net_is_pcap); -//exit(0); -return ne2000; -} - -void *rtl8029as_init() -{ - int rc; - int config_net_type; - int net_type; - int irq; - ne2000_t *ne2000 = malloc(sizeof(ne2000_t)); - memset(ne2000, 0, sizeof(ne2000_t)); - - disable_netbios = device_get_config_int("disable_netbios"); - - irq = device_get_config_int("irq"); - ne2000_setirq(ne2000, irq); - - //net_type - //0 pcap - //1 slirp - // - config_net_type = device_get_config_int("net_type"); - // net_is_slirp = config_get_int(NULL, "net_type", 1); - /* Network type is now specified in device config. */ - net_is_slirp = config_net_type ? 1 : 0; - net_is_pcap = config_net_type ? 0 : 1; - if(!strcmp("nothing", config_get_string(NULL, "pcap_device", "nothing"))) - { - net_is_pcap = 0; - net_is_slirp = 1; - } - pclog("net_is_pcap = %i, net_is_slirp = %i\n", net_is_pcap, net_is_slirp); - - // ne2000_log("ne2000 pcap device %s\n",config_get_string(NULL,"pcap_device","nothing")); - - pci_add(ne2000_pci_read, ne2000_pci_write, ne2000); - - if (!disable_netbios) - { - ne2000_rom_init(ne2000, "roms/rtl8029as.rom"); - - if (PCI) mem_mapping_disable(&ne2000->bios_rom.mapping); - } - - ne2000_pci_regs[0x04] = 1; - ne2000_pci_regs[0x05] = 0; - - ne2000_pci_regs[0x07] = 2; - - /* Network controller. */ - ne2000_pci_regs[0x0B] = 2; - - ne2000_pci_bar[0].addr_regs[0] = 1; - - if (disable_netbios) - { - ne2000_pci_bar[1].addr = 0; - bios_addr = 0; - } - else - { - ne2000_pci_bar[1].addr = 0x000F8000; - ne2000_pci_bar[1].addr_regs[1] = bios_mask; - ne2000_pci_bar[1].addr |= 0x1801; - bios_addr = 0xD0000; - } - - // ne2000_pci_regs[0x3C] = ide_ter_enabled ? 11 : 10; - ne2000_pci_regs[0x3C] = irq; - pclog("RTL8029AS IRQ: %i\n", ne2000_pci_regs[0x3C]); - ne2000_pci_regs[0x3D] = 1; - - memset(rtl8029as_eeprom, 0, 128); - rtl8029as_eeprom[0x76] = rtl8029as_eeprom[0x7A] = rtl8029as_eeprom[0x7E] = 0x29; - rtl8029as_eeprom[0x77] = rtl8029as_eeprom[0x7B] = rtl8029as_eeprom[0x7F] = 0x80; - rtl8029as_eeprom[0x78] = rtl8029as_eeprom[0x7C] = 0x10; - rtl8029as_eeprom[0x79] = rtl8029as_eeprom[0x7D] = 0xEC; - - ne2000->base_address = 0x340; - ne2000_io_set(ne2000->base_address, ne2000); - - memcpy(ne2000->physaddr, maclocal, 6); - - ne2000_reset(ne2000, BX_RESET_HARDWARE); - vlan_handler(ne2000_poller, ne2000); - - ne2000_log("ne2000 pci init 0x%X\tslirp is %d net_is_pcap is %d\n",ne2000->base_address,net_is_slirp,net_is_pcap); - - //need a switch statment for more network types. - - if ( net_is_slirp ) { - ne2000_log("ne2000 initalizing SLiRP\n"); - net_is_pcap=0; - rc=slirp_init(); - ne2000_log("ne2000 slirp_init returned: %d\n",rc); - if ( rc == 0 ) - { - ne2000_log("ne2000 slirp initalized!\n"); - - net_slirp_inited=1; - slirpq = QueueCreate(); - net_is_slirp=1; - fizz=0; - ne2000_log("ne2000 slirpq is %x\n",&slirpq); - } - else { - net_slirp_inited=0; - net_is_slirp=0; - } - } - if ( net_is_pcap ) { //pcap - char errbuf[32768]; - - ne2000_log("ne2000 initalizing libpcap\n"); - net_is_slirp=0; - net_hLib = LoadLibraryA(net_lib_name); - if(net_hLib==0) - { - ne2000_log("ne2000 Failed to load %s\n",net_lib_name); - net_is_pcap=0; - //return; - } - _pcap_lib_version =(PCAP_LIB_VERSION)GetProcAddress(net_hLib,"pcap_lib_version"); - _pcap_open_live=(PCAP_OPEN_LIVE)GetProcAddress(net_hLib,"pcap_open_live"); - _pcap_sendpacket=(PCAP_SENDPACKET)GetProcAddress(net_hLib,"pcap_sendpacket"); - _pcap_setnonblock=(PCAP_SETNONBLOCK)GetProcAddress(net_hLib,"pcap_setnonblock"); - _pcap_next=(PCAP_NEXT)GetProcAddress(net_hLib,"pcap_next"); - _pcap_close=(PCAP_CLOSE)GetProcAddress(net_hLib,"pcap_close"); - _pcap_getnonblock=(PCAP_GETNONBLOCK)GetProcAddress(net_hLib,"pcap_getnonblock"); - _pcap_compile=(PCAP_COMPILE)GetProcAddress(net_hLib,"pcap_compile"); - _pcap_setfilter=(PCAP_SETFILTER)GetProcAddress(net_hLib,"pcap_setfilter"); - - if(_pcap_lib_version && _pcap_open_live && _pcap_sendpacket && _pcap_setnonblock && _pcap_next && _pcap_close && _pcap_getnonblock) - { - ne2000_log("ne2000 Pcap version [%s]\n",_pcap_lib_version()); - - //if((net_pcap=_pcap_open_live("\\Device\\NPF_{0CFA803F-F443-4BB9-A83A-657029A98195}",1518,1,15,errbuf))==0) - if((net_pcap=_pcap_open_live(config_get_string(NULL,"pcap_device","nothing"),1518,1,15,errbuf))==0) - { - ne2000_log("ne2000 pcap_open_live error on %s!\n",config_get_string(NULL,"pcap_device","whatever the ethernet is")); - net_is_pcap=0; return(ne2000); //YUCK!!! - } - } - else { - ne2000_log("%d %d %d %d %d %d %d\n",_pcap_lib_version, _pcap_open_live,_pcap_sendpacket,_pcap_setnonblock,_pcap_next,_pcap_close,_pcap_getnonblock); - net_is_pcap=1; - } - - //Time to check that we are in non-blocking mode. - rc=_pcap_getnonblock(net_pcap,errbuf); - ne2000_log("ne2000 pcap is currently in %s mode\n",rc? "non-blocking":"blocking"); - switch(rc) - { - case 0: - ne2000_log("ne2000 Setting interface to non-blocking mode.."); - rc=_pcap_setnonblock(net_pcap,1,errbuf); - if(rc==0) { //no errors! - ne2000_log(".."); - rc=_pcap_getnonblock(net_pcap,errbuf); - if(rc==1) { - ne2000_log("..!",rc); - net_is_pcap=1; - } - else{ - ne2000_log("\tunable to set pcap into non-blocking mode!\nContinuining without pcap.\n"); - net_is_pcap=0; - } - }//end set nonblock - else{ne2000_log("There was an unexpected error of [%s]\n\nexiting.\n",errbuf);net_is_pcap=0;} - ne2000_log("\n"); - break; - case 1: - ne2000_log("non blocking\n"); - break; - default: - ne2000_log("this isn't right!!!\n"); - net_is_pcap=0; - break; - } - if( net_is_pcap ) { - if(_pcap_compile && _pcap_setfilter) { //we can do this! - struct bpf_program fp; - char filter_exp[255]; - ne2000_log("ne2000 Building packet filter..."); - sprintf(filter_exp,"( ((ether dst ff:ff:ff:ff:ff:ff) or (ether dst %02x:%02x:%02x:%02x:%02x:%02x)) and not (ether src %02x:%02x:%02x:%02x:%02x:%02x) )", \ - maclocal[0], maclocal[1], maclocal[2], maclocal[3], maclocal[4], maclocal[5],\ - maclocal[0], maclocal[1], maclocal[2], maclocal[3], maclocal[4], maclocal[5]); - - //I'm doing a MAC level filter so TCP/IP doesn't matter. - if (_pcap_compile(net_pcap, &fp, filter_exp, 0, 0xffffffff) == -1) { - ne2000_log("\nne2000 Couldn't compile filter\n"); - } - else { - ne2000_log("..."); - if (_pcap_setfilter(net_pcap, &fp) == -1) { - ne2000_log("\nError installing pcap filter.\n"); - }//end of set_filter failure - else { - ne2000_log("...!\n"); - } - } - ne2000_log("ne2000 Using filter\t[%s]\n",filter_exp); - //scanf(filter_exp); //pause - } - else - { - ne2000_log("ne2000 Your platform lacks pcap_compile & pcap_setfilter\n"); - net_is_pcap=0; - } - ne2000_log("ne2000 net_is_pcap is %d and net_pcap is %x\n",net_is_pcap,net_pcap); - } - } //end pcap setup - - //timer_add(slirp_tic,&delay,TIMER_ALWAYS_ENABLED,NULL); - //timer_add(keyboard_amstrad_poll, &keybsenddelay, TIMER_ALWAYS_ENABLED, NULL); -ne2000_log("ne2000 is_slirp %d is_pcap %d\n",net_is_slirp,net_is_pcap); -//exit(0); -return ne2000; -} - - -void ne2000_close(void *p) -{ - ne2000_t *ne2000 = (ne2000_t *)p; - ne2000_io_remove(ne2000->base_address, ne2000); - free(ne2000); - - if(net_is_slirp) { - QueueDestroy(slirpq); - slirp_exit(0); - net_slirp_inited=0; - ne2000_log("ne2000 exiting slirp\n"); - } - if(net_is_pcap && net_pcap!=NULL) - { - _pcap_close(net_pcap); - FreeLibrary(net_hLib); - ne2000_log("ne2000 closing pcap\n"); - } - ne2000_log("ne2000 close\n"); -} - -static device_config_t ne2000_config[] = -{ - { - .name = "addr", - .description = "Address", - .type = CONFIG_BINARY, - .type = CONFIG_SELECTION, - .selection = - { - { - .description = "0x280", - .value = 0x280 - }, - { - .description = "0x300", - .value = 0x300 - }, - { - .description = "0x320", - .value = 0x320 - }, - { - .description = "0x340", - .value = 0x340 - }, - { - .description = "0x360", - .value = 0x360 - }, - { - .description = "0x380", - .value = 0x380 - }, - { - .description = "" - } - }, - .default_int = 0x300 - }, - { - .name = "irq", - .description = "IRQ", - .type = CONFIG_SELECTION, - .selection = - { - { - .description = "IRQ 3", - .value = 3 - }, - { - .description = "IRQ 5", - .value = 5 - }, - { - .description = "IRQ 7", - .value = 7 - }, - { - .description = "IRQ 10", - .value = 10 - }, - { - .description = "IRQ 11", - .value = 11 - }, - { - .description = "" - } - }, - .default_int = 10 - }, - { - .name = "net_type", - .description = "Network type", - .type = CONFIG_BINARY, - .type = CONFIG_SELECTION, - .selection = - { - { - .description = "PCap", - .value = 0 - }, - { - .description = "SLiRP", - .value = 1 - }, - { - .description = "" - } - }, - .default_int = 0 - }, - { - .name = "disable_netbios", - .description = "Network bios", - .type = CONFIG_BINARY, - .type = CONFIG_SELECTION, - .selection = - { - { - .description = "Enabled", - .value = 0 - }, - { - .description = "Disabled", - .value = 1 - }, - { - .description = "" - } - }, - .default_int = 0 - }, - { - .type = -1 - } -}; - -static device_config_t rtl8029as_config[] = -{ - { - .name = "irq", - .description = "IRQ", - .type = CONFIG_SELECTION, - .selection = - { - { - .description = "IRQ 3", - .value = 3 - }, - { - .description = "IRQ 5", - .value = 5 - }, - { - .description = "IRQ 7", - .value = 7 - }, - { - .description = "IRQ 10", - .value = 10 - }, - { - .description = "IRQ 11", - .value = 11 - }, - { - .description = "" - } - }, - .default_int = 10 - }, - { - .name = "net_type", - .description = "Network type", - .type = CONFIG_BINARY, - .type = CONFIG_SELECTION, - .selection = - { - { - .description = "PCap", - .value = 0 - }, - { - .description = "SLiRP", - .value = 1 - }, - { - .description = "" - } - }, - .default_int = 0 - }, - { - .name = "disable_netbios", - .description = "Network bios", - .type = CONFIG_BINARY, - .type = CONFIG_SELECTION, - .selection = - { - { - .description = "Enabled", - .value = 0 - }, - { - .description = "Disabled", - .value = 1 - }, - { - .description = "" - } - }, - .default_int = 0 - }, - { - .type = -1 - } -}; - -device_t ne2000_device = -{ - "Novell NE2000", - 0, - ne2000_init, - ne2000_close, - NULL, - NULL, - NULL, - NULL, - ne2000_config -}; - -device_t rtl8029as_device = -{ - "Realtek RTL8029AS", - 0, - rtl8029as_init, - ne2000_close, - NULL, - NULL, - NULL, - NULL, - rtl8029as_config -}; - - -//SLIRP stuff -int slirp_can_output(void) -{ -return net_slirp_inited; -} - -void slirp_output (const unsigned char *pkt, int pkt_len) -{ -struct queuepacket *p; -p=(struct queuepacket *)malloc(sizeof(struct queuepacket)); -p->len=pkt_len; -memcpy(p->data,pkt,pkt_len); -QueueEnter(slirpq,p); -ne2000_log("ne2000 slirp_output %d @%d\n",pkt_len,p); -} - -// Instead of calling this and crashing some times -// or experencing jitter, this is called by the -// 60Hz clock which seems to do the job. -void slirp_tic() -{ - int ret2,nfds; - struct timeval tv; - fd_set rfds, wfds, xfds; - int timeout; - nfds=-1; - - if(net_slirp_inited) - { - FD_ZERO(&rfds); - FD_ZERO(&wfds); - FD_ZERO(&xfds); - timeout=slirp_select_fill(&nfds,&rfds,&wfds,&xfds); //this can crash - - if(timeout<0) - timeout=500; - tv.tv_sec=0; - tv.tv_usec = timeout; //basilisk default 10000 - - ret2 = select(nfds + 1, &rfds, &wfds, &xfds, &tv); - if(ret2>=0){ - slirp_select_poll(&rfds, &wfds, &xfds); - } - //ne2000_log("ne2000 slirp_tic()\n"); - }//end if slirp inited -} diff --git a/src/ne2000.h b/src/ne2000.h deleted file mode 100644 index 53af3f72f..000000000 --- a/src/ne2000.h +++ /dev/null @@ -1,5 +0,0 @@ -/* Copyright holders: SA1988 - see COPYING for more details -*/ -extern device_t ne2000_device; -extern device_t rtl8029as_device; diff --git a/src/neat.c b/src/neat.c index ef50ab080..85063e591 100644 --- a/src/neat.c +++ b/src/neat.c @@ -3,14 +3,18 @@ */ /*This is the chipset used in the AMI 286 clone model*/ #include "ibm.h" +#include "cpu/cpu.h" #include "io.h" -#include "neat.h" +#include "device.h" +#include "model.h" + static uint8_t neat_regs[256]; static int neat_index; static int neat_emspage[4]; -void neat_write(uint16_t port, uint8_t val, void *priv) + +static void neat_write(uint16_t port, uint8_t val, void *priv) { switch (port) { @@ -38,7 +42,8 @@ void neat_write(uint16_t port, uint8_t val, void *priv) } } -uint8_t neat_read(uint16_t port, void *priv) + +static uint8_t neat_read(uint16_t port, void *priv) { switch (port) { @@ -51,17 +56,22 @@ uint8_t neat_read(uint16_t port, void *priv) return 0xff; } -void neat_writeems(uint32_t addr, uint8_t val) + +#if NOT_USED +static void neat_writeems(uint32_t addr, uint8_t val) { ram[(neat_emspage[(addr >> 14) & 3] << 14) + (addr & 0x3FFF)] = val; } -uint8_t neat_readems(uint32_t addr) + +static uint8_t neat_readems(uint32_t addr) { return ram[(neat_emspage[(addr >> 14) & 3] << 14) + (addr & 0x3FFF)]; } +#endif -void neat_init() + +void neat_init(void) { io_sethandler(0x0022, 0x0002, neat_read, NULL, NULL, neat_write, NULL, NULL, NULL); io_sethandler(0x0208, 0x0002, neat_read, NULL, NULL, neat_write, NULL, NULL, NULL); diff --git a/src/neat.h b/src/neat.h deleted file mode 100644 index 7a9b7d07d..000000000 --- a/src/neat.h +++ /dev/null @@ -1,4 +0,0 @@ -/* Copyright holders: Sarah Walker - see COPYING for more details -*/ -void neat_init(); diff --git a/src/nethandler.c b/src/nethandler.c deleted file mode 100644 index b926d1cbe..000000000 --- a/src/nethandler.c +++ /dev/null @@ -1,101 +0,0 @@ -/* Copyright holders: Sarah Walker, Tenshi - see COPYING for more details -*/ -#include -#include -#include -#include -#include -#include -#include "nethandler.h" - -#include "ibm.h" -#include "device.h" - -#include "ne2000.h" -#include "timer.h" - -int network_card_current = 0; -static int network_card_last = 0; - -typedef struct -{ - char name[32]; - device_t *device; -} NETWORK_CARD; - -static NETWORK_CARD network_cards[] = -{ - {"None", NULL}, - {"Novell NE2000", &ne2000_device}, - {"Realtek RTL8029AS", &rtl8029as_device}, - {"", NULL} -}; - -int network_card_available(int card) -{ - if (network_cards[card].device) - return device_available(network_cards[card].device); - - return 1; -} - -char *network_card_getname(int card) -{ - return network_cards[card].name; -} - -device_t *network_card_getdevice(int card) -{ - return network_cards[card].device; -} - -int network_card_has_config(int card) -{ - if (!network_cards[card].device) - return 0; - return network_cards[card].device->config ? 1 : 0; -} - -void network_card_init() -{ - if (network_cards[network_card_current].device) - device_add(network_cards[network_card_current].device); - network_card_last = network_card_current; -} - -static struct -{ - void (*poller)(void *p); - void *priv; -} vlan_handlers[8]; - -static int vlan_handlers_num; - -static int vlan_poller_time = 0; - -void vlan_handler(void (*poller)(void *p), void *p) -//void vlan_handler(int (*can_receive)(void *p), void (*receive)(void *p, const uint8_t *buf, int size), void *p) -{ - /* vlan_handlers[vlan_handlers_num].can_receive = can_receive; */ - vlan_handlers[vlan_handlers_num].poller = poller; - vlan_handlers[vlan_handlers_num].priv = p; - vlan_handlers_num++; -} - -void vlan_poller(void *priv) -{ - int c; - - vlan_poller_time += (int)((double)TIMER_USEC * (1000000.0 / 8.0 / 3000.0)); - - for (c = 0; c < vlan_handlers_num; c++) - vlan_handlers[c].poller(vlan_handlers[c].priv); -} - -void vlan_reset() -{ - timer_add(vlan_poller, &vlan_poller_time, TIMER_ALWAYS_ENABLED, NULL); - - vlan_handlers_num = 0; -} diff --git a/src/nethandler.h b/src/nethandler.h deleted file mode 100644 index a6e6c5c77..000000000 --- a/src/nethandler.h +++ /dev/null @@ -1,18 +0,0 @@ -/* Copyright holders: Sarah Walker, Tenshi - see COPYING for more details -*/ -#include - -//void vlan_handler(int (*can_receive)(void *p), void (*receive)(void *p, const uint8_t *buf, int size), void *p); -void vlan_handler(void (*poller)(void *p), void *p); - -extern int network_card_current; - -int network_card_available(int card); -char *network_card_getname(int card); -struct device_t *network_card_getdevice(int card); -int network_card_has_config(int card); -void network_card_init(); - -void initpcap(); -void closepcap(); diff --git a/src/nmi.c b/src/nmi.c index 0e7abdc04..a6ca4480e 100644 --- a/src/nmi.c +++ b/src/nmi.c @@ -2,6 +2,7 @@ see COPYING for more details */ #include "ibm.h" +#include "io.h" #include "nmi.h" int nmi_mask; diff --git a/src/nvr.c b/src/nvr.c index f5e632724..392e627eb 100644 --- a/src/nvr.c +++ b/src/nvr.c @@ -1,14 +1,41 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * CMOS NVRAM emulation. + * + * Version: @(#)nvr.c 1.0.1 2017/06/03 + * + * Authors: Sarah Walker, + * Miran Grca, + * Mahod, + * Copyright 2008-2017 Sarah Walker. + * Copyright 2016-2017 Miran Grca. + * Copyright 2016-2017 Mahod. + */ #include +#include +#include +#include #include "ibm.h" +#include "CPU/cpu.h" +#include "device.h" #include "io.h" +#include "mem.h" +#include "model.h" #include "nvr.h" #include "pic.h" +#include "rom.h" #include "timer.h" #include "rtc.h" -int oldromset; +int oldmodel; int nvrmask=63; -uint8_t nvrram[128]; +char nvrram[128]; int nvraddr; int nvr_dosave = 0; @@ -17,12 +44,12 @@ static int nvr_onesec_time = 0, nvr_onesec_cnt = 0; static int rtctime; -void getnvrtime() +void getnvrtime(void) { time_get(nvrram); } -void nvr_recalc() +void nvr_recalc(void) { int c; int newrtctime; @@ -41,14 +68,12 @@ void nvr_rtc(void *p) } c = 1 << ((nvrram[RTC_REGA] & RTC_RS) - 1); rtctime += (int)(RTCCONST * c * (1 << TIMER_SHIFT)); -// pclog("RTCtime now %f\n",rtctime); nvrram[RTC_REGC] |= RTC_PF; if (nvrram[RTC_REGB] & RTC_PIE) { nvrram[RTC_REGC] |= RTC_IRQF; if (AMSTRAD) picint(2); else picint(0x100); -// pclog("RTC int\n"); } } @@ -91,8 +116,6 @@ void nvr_update_end(void *p) else picint(0x100); } } - -// pclog("RTC onesec\n"); nvr_update_end_count = 0; } @@ -117,12 +140,10 @@ void nvr_onesec(void *p) void writenvr(uint16_t addr, uint8_t val, void *priv) { int c, old; -// printf("Write NVR %03X %02X %02X %04X:%04X %i\n",addr,nvraddr,val,cs>>4,pc,ins); if (addr&1) { if (nvraddr==RTC_REGC || nvraddr==RTC_REGD) return; /* Registers C and D are read-only. There's no reason to continue. */ -// if (nvraddr == 0x33) pclog("NVRWRITE33 %02X %04X:%04X %i\n",val,CS,pc,ins); if (nvraddr > RTC_REGD && nvrram[nvraddr] != val) nvr_dosave = 1; @@ -131,7 +152,6 @@ void writenvr(uint16_t addr, uint8_t val, void *priv) if (nvraddr == RTC_REGA) { -// pclog("NVR rate %i\n",val&0xF); if (val & RTC_RS) { c = 1 << ((val & RTC_RS) - 1); @@ -170,7 +190,6 @@ void writenvr(uint16_t addr, uint8_t val, void *priv) uint8_t readnvr(uint16_t addr, void *priv) { uint8_t temp; -// printf("Read NVR %03X %02X %02X %04X:%04X\n",addr,nvraddr,nvrram[nvraddr],cs>>4,pc); if (addr&1) { if (nvraddr == RTC_REGA) @@ -185,71 +204,40 @@ uint8_t readnvr(uint16_t addr, void *priv) nvrram[RTC_REGC] = 0; return temp; } -// if (AMIBIOS && nvraddr==0x36) return 0; -// if (nvraddr==0xA) nvrram[0xA]^=0x80; return nvrram[nvraddr]; } return nvraddr; } -void loadnvr() +void loadnvr(void) { - FILE *f; + FILE *f = NULL; int c; nvrmask=63; - oldromset=romset; - switch (romset) - { - case ROM_PC1512: f = romfopen(nvr_concat("pc1512.nvr"), "rb"); break; - case ROM_PC1640: f = romfopen(nvr_concat("pc1640.nvr"), "rb"); break; - case ROM_PC200: f = romfopen(nvr_concat("pc200.nvr"), "rb"); break; - case ROM_PC2086: f = romfopen(nvr_concat("pc2086.nvr"), "rb"); break; - case ROM_PC3086: f = romfopen(nvr_concat("pc3086.nvr"), "rb"); break; - case ROM_IBMAT: f = romfopen(nvr_concat("at.nvr"), "rb"); break; - case ROM_IBMPS1_2011: f = romfopen(nvr_concat("ibmps1_2011.nvr"), "rb"); /*nvrmask = 127; */break; - case ROM_IBMPS1_2121: f = romfopen(nvr_concat("ibmps1_2121.nvr"), "rb"); nvrmask = 127; break; - case ROM_CMDPC30: f = romfopen(nvr_concat("cmdpc30.nvr"), "rb"); nvrmask = 127; break; - case ROM_AMI286: f = romfopen(nvr_concat("ami286.nvr"), "rb"); nvrmask = 127; break; - case ROM_AWARD286: f = romfopen(nvr_concat("award286.nvr"), "rb"); nvrmask = 127; break; - case ROM_DELL200: f = romfopen(nvr_concat("dell200.nvr"), "rb"); nvrmask = 127; break; - case ROM_IBMAT386: f = romfopen(nvr_concat("at386.nvr"), "rb"); nvrmask = 127; break; - case ROM_DESKPRO_386: f = romfopen(nvr_concat("deskpro386.nvr"), "rb"); break; - case ROM_ACER386: f = romfopen(nvr_concat("acer386.nvr"), "rb"); nvrmask = 127; break; - case ROM_MEGAPC: f = romfopen(nvr_concat("megapc.nvr"), "rb"); nvrmask = 127; break; - case ROM_AMI386SX: f = romfopen(nvr_concat("ami386.nvr"), "rb"); nvrmask = 127; break; - case ROM_AMI486: f = romfopen(nvr_concat("ami486.nvr"), "rb"); nvrmask = 127; break; - case ROM_WIN486: f = romfopen(nvr_concat("win486.nvr"), "rb"); nvrmask = 127; break; - case ROM_PCI486: f = romfopen(nvr_concat("hot-433.nvr"), "rb"); nvrmask = 127; break; - case ROM_SIS496: f = romfopen(nvr_concat("sis496.nvr"), "rb"); nvrmask = 127; break; - case ROM_430VX: f = romfopen(nvr_concat("430vx.nvr"), "rb"); nvrmask = 127; break; - case ROM_REVENGE: f = romfopen(nvr_concat("revenge.nvr"), "rb"); nvrmask = 127; break; - case ROM_ENDEAVOR: f = romfopen(nvr_concat("endeavor.nvr"), "rb"); nvrmask = 127; break; - case ROM_PX386: f = romfopen(nvr_concat("px386.nvr"), "rb"); nvrmask = 127; break; - case ROM_DTK386: f = romfopen(nvr_concat("dtk386.nvr"), "rb"); nvrmask = 127; break; - case ROM_MR386DX_OPTI495: f = romfopen(nvr_concat("mr386dx_opti495.nvr"), "rb"); nvrmask = 127; break; - case ROM_AMI386DX_OPTI495: f = romfopen(nvr_concat("ami386dx_opti495.nvr"), "rb"); nvrmask = 127; break; - case ROM_DTK486: f = romfopen(nvr_concat("dtk486.nvr"), "rb"); nvrmask = 127; break; - case ROM_R418: f = romfopen(nvr_concat("r418.nvr"), "rb"); nvrmask = 127; break; - case ROM_586MC1: f = romfopen(nvr_concat("586mc1.nvr"), "rb"); nvrmask = 127; break; - case ROM_PLATO: f = romfopen(nvr_concat("plato.nvr"), "rb"); nvrmask = 127; break; - case ROM_MB500N: f = romfopen(nvr_concat("mb500n.nvr"), "rb"); nvrmask = 127; break; -#if 0 - case ROM_POWERMATE_V: f = romfopen(nvr_concat("powermate_v.nvr"), "rb"); nvrmask = 127; break; -#endif - case ROM_P54TP4XE: f = romfopen(nvr_concat("p54tp4xe.nvr"), "rb"); nvrmask = 127; break; - case ROM_ACERM3A: f = romfopen(nvr_concat("acerm3a.nvr"), "rb"); nvrmask = 127; break; - case ROM_ACERV35N: f = romfopen(nvr_concat("acerv35n.nvr"), "rb"); nvrmask = 127; break; - case ROM_P55VA: f = romfopen(nvr_concat("p55va.nvr"), "rb"); nvrmask = 127; break; - case ROM_P55T2P4: f = romfopen(nvr_concat("p55t2p4.nvr"), "rb"); nvrmask = 127; break; - case ROM_P55TVP4: f = romfopen(nvr_concat("p55tvp4.nvr"), "rb"); nvrmask = 127; break; - case ROM_440FX: f = romfopen(nvr_concat("440fx.nvr"), "rb"); nvrmask = 127; break; - case ROM_MARL: f = romfopen(nvr_concat("marl.nvr"), "rb"); nvrmask = 127; break; - case ROM_THOR: f = romfopen(nvr_concat("thor.nvr"), "rb"); nvrmask = 127; break; - case ROM_MRTHOR: f = romfopen(nvr_concat("mrthor.nvr"), "rb"); nvrmask = 127; break; - default: return; - } - if (!f) + oldmodel = model; + + wchar_t *model_name; + wchar_t *nvr_name; + + model_name = (wchar_t *) malloc((strlen(model_get_internal_name_ex(model)) << 1) + 2); + mbstowcs(model_name, model_get_internal_name_ex(model), strlen(model_get_internal_name_ex(model)) + 1); + nvr_name = (wchar_t *) malloc((wcslen(model_name) << 1) + 2 + 8); + _swprintf(nvr_name, L"%s.nvr", model_name); + + pclog_w(L"Opening NVR file: %s...\n", nvr_name); + + if (model_get_nvrmask(model) != 0) + { + f = nvrfopen(nvr_name, L"rb"); + nvrmask = model_get_nvrmask(model); + } + + if (!f || (model_get_nvrmask(model) == 0)) { + if (f) + { + fclose(f); + } memset(nvrram,0xFF,128); if (!enable_sync) { @@ -259,6 +247,9 @@ void loadnvr() nvrram[RTC_CENTURY] = BCD(19); nvrram[RTC_REGB] = RTC_2412; } + + free(nvr_name); + free(model_name); return; } fread(nvrram,128,1,f); @@ -271,65 +262,50 @@ void loadnvr() nvrram[RTC_REGB] = RTC_2412; c = 1 << ((nvrram[RTC_REGA] & RTC_RS) - 1); rtctime += (int)(RTCCONST * c * (1 << TIMER_SHIFT)); -} -void savenvr() -{ - FILE *f; - switch (oldromset) - { - case ROM_PC1512: f = romfopen(nvr_concat("pc1512.nvr"), "wb"); break; - case ROM_PC1640: f = romfopen(nvr_concat("pc1640.nvr"), "wb"); break; - case ROM_PC200: f = romfopen(nvr_concat("pc200.nvr"), "wb"); break; - case ROM_PC2086: f = romfopen(nvr_concat("pc2086.nvr"), "wb"); break; - case ROM_PC3086: f = romfopen(nvr_concat("pc3086.nvr"), "wb"); break; - case ROM_IBMAT: f = romfopen(nvr_concat("at.nvr"), "wb"); break; - case ROM_IBMPS1_2011: f = romfopen(nvr_concat("ibmps1_2011.nvr"), "wb"); break; - case ROM_IBMPS1_2121: f = romfopen(nvr_concat("ibmps1_2121.nvr"), "wb"); break; - case ROM_CMDPC30: f = romfopen(nvr_concat("cmdpc30.nvr"), "wb"); break; - case ROM_AMI286: f = romfopen(nvr_concat("ami286.nvr"), "wb"); break; - case ROM_AWARD286: f = romfopen(nvr_concat("award286.nvr"), "wb"); break; - case ROM_DELL200: f = romfopen(nvr_concat("dell200.nvr"), "wb"); break; - case ROM_IBMAT386: f = romfopen(nvr_concat("at386.nvr"), "wb"); break; - case ROM_DESKPRO_386: f = romfopen(nvr_concat("deskpro386.nvr"), "wb"); break; - case ROM_ACER386: f = romfopen(nvr_concat("acer386.nvr"), "wb"); break; - case ROM_MEGAPC: f = romfopen(nvr_concat("megapc.nvr"), "wb"); break; - case ROM_AMI386SX: f = romfopen(nvr_concat("ami386.nvr"), "wb"); break; - case ROM_AMI486: f = romfopen(nvr_concat("ami486.nvr"), "wb"); break; - case ROM_WIN486: f = romfopen(nvr_concat("win486.nvr"), "wb"); break; - case ROM_PCI486: f = romfopen(nvr_concat("hot-433.nvr"), "wb"); break; - case ROM_SIS496: f = romfopen(nvr_concat("sis496.nvr"), "wb"); break; - case ROM_430VX: f = romfopen(nvr_concat("430vx.nvr"), "wb"); break; - case ROM_REVENGE: f = romfopen(nvr_concat("revenge.nvr"), "wb"); break; - case ROM_ENDEAVOR: f = romfopen(nvr_concat("endeavor.nvr"), "wb"); break; - case ROM_PX386: f = romfopen(nvr_concat("px386.nvr"), "wb"); break; - case ROM_DTK386: f = romfopen(nvr_concat("dtk386.nvr"), "wb"); break; - case ROM_MR386DX_OPTI495: f = romfopen(nvr_concat("mr386dx_opti495.nvr"), "wb"); break; - case ROM_AMI386DX_OPTI495: f = romfopen(nvr_concat("ami386dx_opti495.nvr"), "wb"); break; - case ROM_DTK486: f = romfopen(nvr_concat("dtk486.nvr"), "wb"); break; - case ROM_R418: f = romfopen(nvr_concat("r418.nvr"), "wb"); break; - case ROM_586MC1: f = romfopen(nvr_concat("586mc1.nvr"), "wb"); break; - case ROM_PLATO: f = romfopen(nvr_concat("plato.nvr"), "wb"); break; - case ROM_MB500N: f = romfopen(nvr_concat("mb500n.nvr"), "wb"); break; -#if 0 - case ROM_POWERMATE_V: f = romfopen(nvr_concat("powermate_v.nvr"), "wb"); break; -#endif - case ROM_P54TP4XE: f = romfopen(nvr_concat("p54tp4xe.nvr"), "wb"); break; - case ROM_ACERM3A: f = romfopen(nvr_concat("acerm3a.nvr"), "wb"); break; - case ROM_ACERV35N: f = romfopen(nvr_concat("acerv35n.nvr"), "wb"); break; - case ROM_P55VA: f = romfopen(nvr_concat("p55va.nvr"), "wb"); break; - case ROM_P55T2P4: f = romfopen(nvr_concat("p55t2p4.nvr"), "wb"); break; - case ROM_P55TVP4: f = romfopen(nvr_concat("p55tvp4.nvr"), "wb"); break; - case ROM_440FX: f = romfopen(nvr_concat("440fx.nvr"), "wb"); break; - case ROM_MARL: f = romfopen(nvr_concat("marl.nvr"), "wb"); break; - case ROM_THOR: f = romfopen(nvr_concat("thor.nvr"), "wb"); break; - case ROM_MRTHOR: f = romfopen(nvr_concat("mrthor.nvr"), "wb"); break; - default: return; - } - fwrite(nvrram,128,1,f); - fclose(f); + + free(nvr_name); + free(model_name); } -void nvr_init() +void savenvr(void) +{ + FILE *f = NULL; + + wchar_t *model_name; + wchar_t *nvr_name; + + model_name = (wchar_t *) malloc((strlen(model_get_internal_name_ex(oldmodel)) << 1) + 2); + mbstowcs(model_name, model_get_internal_name_ex(oldmodel), strlen(model_get_internal_name_ex(oldmodel)) + 1); + nvr_name = (wchar_t *) malloc((wcslen(model_name) << 1) + 2 + 8); + _swprintf(nvr_name, L"%s.nvr", model_name); + + pclog_w(L"Saving NVR file: %s...\n", nvr_name); + + if (model_get_nvrmask(oldmodel) != 0) + { + f = nvrfopen(nvr_name, L"wb"); + } + + if (!f || (model_get_nvrmask(oldmodel) == 0)) + { + if (f) + { + fclose(f); + } + + free(nvr_name); + free(model_name); + return; + } + + fwrite(nvrram,128,1,f); + fclose(f); + + free(nvr_name); + free(model_name); +} + +void nvr_init(void) { io_sethandler(0x0070, 0x0002, readnvr, NULL, NULL, writenvr, NULL, NULL, NULL); timer_add(nvr_rtc, &rtctime, TIMER_ALWAYS_ENABLED, NULL); diff --git a/src/nvr.h b/src/nvr.h index a333db555..0c7780240 100644 --- a/src/nvr.h +++ b/src/nvr.h @@ -1,11 +1,35 @@ -/* Copyright holders: Mahod, Tenshi - see COPYING for more details -*/ -void nvr_init(); +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * CMOS NVRAM emulation. + * + * Version: @(#)nvr.h 1.0.1 2017/06/03 + * + * Authors: Sarah Walker, + * Miran Grca, + * Mahod, + * Copyright 2008-2017 Sarah Walker. + * Copyright 2016-2017 Miran Grca. + * Copyright 2016-2017 Mahod. + */ +#ifndef EMU_NVR_H +# define EMU_NVR_H + extern int enable_sync; - extern int nvr_dosave; -void time_get(char *nvrram); +extern void nvr_init(void); +extern void time_get(char *nvrram); +extern void nvr_recalc(void); +extern void loadnvr(void); +extern void savenvr(void); + + +#endif /*EMU_NVR_H*/ diff --git a/src/olivetti_m24.c b/src/olivetti_m24.c index d60f312ce..3c9e24ba7 100644 --- a/src/olivetti_m24.c +++ b/src/olivetti_m24.c @@ -2,10 +2,13 @@ see COPYING for more details */ #include "ibm.h" +#include "cpu/cpu.h" #include "io.h" -#include "olivetti_m24.h" +#include "device.h" +#include "model.h" -uint8_t olivetti_m24_read(uint16_t port, void *priv) + +static uint8_t olivetti_m24_read(uint16_t port, void *priv) { switch (port) { @@ -17,7 +20,8 @@ uint8_t olivetti_m24_read(uint16_t port, void *priv) return 0xff; } -void olivetti_m24_init() + +void olivetti_m24_init(void) { io_sethandler(0x0066, 0x0002, olivetti_m24_read, NULL, NULL, NULL, NULL, NULL, NULL); } diff --git a/src/olivetti_m24.h b/src/olivetti_m24.h deleted file mode 100644 index 89ee10595..000000000 --- a/src/olivetti_m24.h +++ /dev/null @@ -1,4 +0,0 @@ -/* Copyright holders: Sarah Walker - see COPYING for more details -*/ -void olivetti_m24_init(); diff --git a/src/opti495.c b/src/opti495.c index c173c5be3..b9a6e2e30 100644 --- a/src/opti495.c +++ b/src/opti495.c @@ -1,67 +1,7 @@ /*OPTi 82C495 emulation - This is the chipset used in the AMI386 model*/ -#include "ibm.h" -#include "cpu.h" -#include "io.h" -#include "mem.h" + This is the chipset used in the AMI386 model -static uint8_t optiregs[0x10]; -static int optireg; - -static void opti495_write(uint16_t addr, uint8_t val, void *p) -{ - switch (addr) - { - case 0x22: - optireg=val; - break; - case 0x24: - printf("Writing OPTI reg %02X %02X\n",optireg,val); - if (optireg>=0x20 && optireg<=0x2C) - { - optiregs[optireg-0x20]=val; - if (optireg == 0x21) - { - cpu_cache_ext_enabled = val & 0x10; - cpu_update_waitstates(); - } - if (optireg == 0x22) - { - shadowbios = !(val & 0x80); - shadowbios_write = val & 0x80; - //pclog("shadowbios %i %02x\n", shadowbios, val); - if (shadowbios) - mem_set_mem_state(0xf0000, 0x10000, MEM_READ_INTERNAL | MEM_WRITE_DISABLED); - else - mem_set_mem_state(0xf0000, 0x10000, MEM_READ_EXTERNAL | MEM_WRITE_INTERNAL); -// if (shadowbios) -// fatal("Here\n"); - } - } - break; - } -} - -static uint8_t opti495_read(uint16_t addr, void *p) -{ - switch (addr) - { - case 0x24: - //printf("Read OPTI reg %02X\n",optireg); - if (optireg>=0x20 && optireg<=0x2C) return optiregs[optireg-0x20]; - break; - } - return 0xFF; -} - -void opti495_init() -{ - io_sethandler(0x0022, 0x0001, opti495_read, NULL, NULL, opti495_write, NULL, NULL, NULL); - io_sethandler(0x0024, 0x0001, opti495_read, NULL, NULL, opti495_write, NULL, NULL, NULL); - optiregs[0x22-0x20] = 0x80; -} - -/*Details for the chipset from Ralph Brown's interrupt list + Details for the chipset from Ralph Brown's interrupt list This describes the OPTi 82C493, the 82C495 seems similar except there is one more register (2C) @@ -310,5 +250,66 @@ Bit(s) Description (Table P0188) Note: the block address is forced to be a multiple of the block size by ignoring the appropriate number of the least-significant bits SeeAlso: #P0178,#P0187 - */ +#include "ibm.h" +#include "cpu/cpu.h" +#include "io.h" +#include "mem.h" +#include "device.h" +#include "model.h" + + +static uint8_t optiregs[0x10]; +static int optireg; + + +static void opti495_write(uint16_t addr, uint8_t val, void *p) +{ + switch (addr) + { + case 0x22: + optireg=val; + break; + case 0x24: + printf("Writing OPTI reg %02X %02X\n",optireg,val); + if (optireg>=0x20 && optireg<=0x2C) + { + optiregs[optireg-0x20]=val; + if (optireg == 0x21) + { + cpu_cache_ext_enabled = val & 0x10; + cpu_update_waitstates(); + } + if (optireg == 0x22) + { + shadowbios = !(val & 0x80); + shadowbios_write = val & 0x80; + if (shadowbios) + mem_set_mem_state(0xf0000, 0x10000, MEM_READ_INTERNAL | MEM_WRITE_DISABLED); + else + mem_set_mem_state(0xf0000, 0x10000, MEM_READ_EXTERNAL | MEM_WRITE_INTERNAL); + } + } + break; + } +} + + +static uint8_t opti495_read(uint16_t addr, void *p) +{ + switch (addr) + { + case 0x24: + if (optireg>=0x20 && optireg<=0x2C) return optiregs[optireg-0x20]; + break; + } + return 0xFF; +} + + +void opti495_init(void) +{ + io_sethandler(0x0022, 0x0001, opti495_read, NULL, NULL, opti495_write, NULL, NULL, NULL); + io_sethandler(0x0024, 0x0001, opti495_read, NULL, NULL, opti495_write, NULL, NULL, NULL); + optiregs[0x22-0x20] = 0x80; +} diff --git a/src/opti495.h b/src/opti495.h deleted file mode 100644 index 814f313fa..000000000 --- a/src/opti495.h +++ /dev/null @@ -1 +0,0 @@ -void opti495_init(); diff --git a/src/pc.c b/src/pc.c index 7e7a9e4e2..ecfefb945 100644 --- a/src/pc.c +++ b/src/pc.c @@ -1,66 +1,95 @@ -/* Copyright holders: Sarah Walker, Tenshi - see COPYING for more details -*/ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Emulation core dispatcher. + * + * Version: @(#)pc.c 1.0.6 2017/06/17 + * + * Authors: Sarah Walker, + * Miran Grca, + * Copyright 2008-2017 Sarah Walker. + * Copyright 2016-2017 Miran Grca. + */ #include #include #include + #include "86box.h" #include "ibm.h" -#include "device.h" - -#include "ali1429.h" -#include "cdrom-ioctl.h" -#include "disc.h" #include "mem.h" -#include "x86_ops.h" -#include "codegen.h" -#include "cdrom-iso.h" -#include "cdrom-null.h" -#include "config.h" -#include "cpu.h" +#include "cpu/cpu.h" +#include "cpu/x86_ops.h" +#include "cpu/codegen.h" #include "dma.h" -#include "fdc.h" -#include "fdd.h" -#include "gameport.h" -#include "sound_gus.h" -#include "buslogic.h" -#include "cdrom.h" -#include "scsi.h" -#include "ide.h" -#include "keyboard.h" -#include "keyboard_at.h" -#include "model.h" -#include "mouse.h" #include "nvr.h" #include "pic.h" #include "pit.h" -#include "plat-joystick.h" -#include "plat-mouse.h" -#include "serial.h" -#include "sound.h" -#include "sound_cms.h" -#include "sound_opl.h" -#include "sound_sb.h" -#include "sound_ssi2001.h" #include "timer.h" -#include "vid_voodoo.h" -#include "video.h" -#include "amstrad.h" -#include "nethandler.h" -#define NE2000 1 -#define RTL8029AS 2 -uint8_t ethif; -int inum; +#include "device.h" +#include "model.h" -char nvr_path[1024]; +#include "disc.h" +#include "disc_86f.h" +#include "disc_fdi.h" +#include "disc_imd.h" +#include "disc_img.h" +#include "disc_td0.h" +#include "disc_random.h" +#include "config.h" +#include "fdc.h" +#include "fdd.h" +#include "gameport.h" +#include "hdd.h" +#include "ide.h" +#include "cdrom.h" +#include "cdrom_ioctl.h" +#include "cdrom_image.h" +#include "cdrom_null.h" +#include "keyboard.h" +#include "keyboard_at.h" +#include "sound/midi.h" +#include "mouse.h" +#include "network/network.h" +#ifdef WALTJE +# define UNICODE +# include "plat_dir.h" +# undef UNICODE +#endif +#include "plat_joystick.h" +#include "plat_keyboard.h" +#include "plat_midi.h" +#include "plat_mouse.h" +#include "plat_ui.h" +#include "scsi.h" +#include "serial.h" +#include "sound/sound.h" +#include "sound/snd_cms.h" +#include "sound/snd_dbopl.h" +#include "sound/snd_mpu401.h" +#include "sound/snd_opl.h" +#include "sound/snd_gus.h" +#include "sound/snd_sb.h" +#include "sound/snd_speaker.h" +#include "sound/snd_ssi2001.h" +#include "video/video.h" +#include "video/vid_voodoo.h" + + +wchar_t pcempath[512]; + +wchar_t nvr_path[1024]; int path_len; int window_w, window_h, window_x, window_y, window_remember; +int dump_on_exit = 0; int start_in_fullscreen = 0; -int scsi_cdrom_enabled; -int cdrom_enabled; int CPUID; int vid_resize, vid_api; @@ -81,7 +110,8 @@ int atfullspeed; void saveconfig(); int infocus; int mousecapture; -// FILE *pclogf; + + void pclog(const char *format, ...) { #ifndef RELEASE_BUILD @@ -93,36 +123,91 @@ void pclog(const char *format, ...) #endif } -void fatal(const char *format, ...) +void pclog_w(const wchar_t *format, ...) { +#ifndef RELEASE_BUILD va_list ap; va_start(ap, format); - vprintf(format, ap); + vwprintf(format, ap); + va_end(ap); + fflush(stdout); +#endif +} + +#ifndef __unix +#ifndef _LIBC +# define __builtin_expect(expr, val) (expr) +#endif + +#undef memmem + + +/* Return the first occurrence of NEEDLE in HAYSTACK. */ +void *memmem (const void *haystack, size_t haystack_len, const void *needle, size_t needle_len) +{ + const char *begin; + const char *const last_possible = (const char *) haystack + haystack_len - needle_len; + + if (needle_len == 0) + /* The first occurrence of the empty string is deemed to occur at + the beginning of the string. */ + return (void *) haystack; + + /* Sanity check, otherwise the loop might search through the whole + memory. */ + if (__builtin_expect (haystack_len < needle_len, 0)) + return NULL; + + for (begin = (const char *) haystack; begin <= last_possible; ++begin) + if (begin[0] == ((const char *) needle)[0] && !memcmp ((const void *) &begin[1], (const void *) ((const char *) needle + 1), needle_len - 1)) + return (void *) begin; + + return NULL; +} +#endif + + +void fatal(const char *format, ...) +{ + char msg[1024]; +#ifndef __unix + char *newline; +#endif + va_list ap; + va_start(ap, format); + vsprintf(msg, format, ap); + printf(msg); va_end(ap); fflush(stdout); savenvr(); saveconfig(); +#ifndef __unix + newline = memmem(msg, strlen(msg), "\n", strlen("\n")); + if (newline != NULL) + { + *newline = 0; + } + plat_msgbox_fatal(msg); +#endif dumppic(); - dumpregs(); + dumpregs(1); fflush(stdout); exit(-1); } uint8_t cgastat; + int pollmouse_delay = 2; -void pollmouse() +void pollmouse(void) { int x, y, z; -// return; pollmouse_delay--; if (pollmouse_delay) return; pollmouse_delay = 2; mouse_poll_host(); mouse_get_mickeys(&x, &y, &z); - if (mouse_poll) - mouse_poll(x, y, z, mouse_buttons); -// if (mousecapture) position_mouse(64,64); + mouse_poll(x, y, z, mouse_buttons); } /*PC1512 languages - @@ -174,91 +259,119 @@ int updatestatus; int win_title_update=0; -void onesec() +void onesec(void) { fps=framecount; framecount=0; win_title_update=1; } -void pc_reset() +void pc_reset(void) { cpu_set(); resetx86(); - //timer_reset(); dma_reset(); fdc_reset(); pic_reset(); - pit_reset(); serial_reset(); if (AT) setpitclock(models[model].cpu[cpu_manufacturer].cpus[cpu].rspeed); else setpitclock(14318184.0); - -// sb_reset(); - - ali1429_reset(); -// video_init(); } + + #undef printf -void initpc(int argc, char *argv[]) +void initpc(int argc, wchar_t *argv[]) { - char *p; - char *config_file = NULL; + wchar_t *p; + wchar_t *config_file = NULL; int c; - FILE *ff; -// allegro_init(); - get_executable_name(pcempath,511); - pclog("executable_name = %s\n", pcempath); - p=get_filename(pcempath); - *p=0; - pclog("path = %s\n", pcempath); + get_executable_name(pcempath, 511); + pclog("executable_name = %S\n", pcempath); + p=get_filename_w(pcempath); + *p=L'\0'; + pclog("path = %S\n", pcempath); +#ifdef WALTJE + DIR *dir; + struct direct *dp; +#endif for (c = 1; c < argc; c++) { - if (!strcasecmp(argv[c], "--help")) + if (!_wcsicmp(argv[c], L"--help")) { - printf("PCem command line options :\n\n"); + printf("Command line options :\n\n"); printf("--config file.cfg - use given config file as initial configuration\n"); + printf("--dump - always dump memory on exit\n"); printf("--fullscreen - start in fullscreen mode\n"); exit(-1); } - else if (!strcasecmp(argv[c], "--fullscreen")) - { - start_in_fullscreen = 1; - } - else if (!strcasecmp(argv[c], "--config")) + else if (!_wcsicmp(argv[c], L"--config")) { if ((c+1) == argc) break; config_file = argv[c+1]; c++; } - } + else if (!_wcsicmp(argv[c], L"--dump")) + { + dump_on_exit = 1; + } + else if (!_wcsicmp(argv[c], L"--fullscreen")) + { + start_in_fullscreen = 1; + } + else if (!_wcsicmp(argv[c], L"--test")) + { + /* some (undocumented) test function here.. */ +#ifdef WALTJE + dir = opendirw(pcempath); + if (dir != NULL) { + printf("Directory '%S':\n", pcempath); + for (;;) { + dp = readdir(dir); + if (dp == NULL) break; + printf(">> '%S'\n", dp->d_name); + } + closedir(dir); + } else { + printf("Could not open '%S'..\n", pcempath); + } +#endif - keyboard_init(); - mouse_init(); - joystick_init(); - midi_init(); + /* .. and then exit. */ + exit(0); + } + } if (config_file == NULL) { - append_filename(config_file_default, pcempath, "86box.cfg", 511); + append_filename_w(config_file_default, pcempath, CONFIG_FILE_W, 511); } else { - append_filename(config_file_default, pcempath, config_file, 511); + append_filename_w(config_file_default, pcempath, config_file, 511); } - + loadconfig(config_file); pclog("Config loaded\n"); - if (config_file) - saveconfig(); +} + +void initmodules(void) +{ + int i; + + /* Initialize modules. */ + network_init(); + mouse_init(); + serial_init(); + disc_random_init(); + + joystick_init(); cpuspeed2=(AT)?2:1; -// cpuspeed2=cpuspeed; atfullspeed=0; initvideo(); @@ -271,6 +384,28 @@ void initpc(int argc, char *argv[]) device_init(); timer_reset(); + + for (i = 0; i < CDROM_NUM; i++) + { + if (cdrom_drives[i].bus_type) + { + SCSIReset(cdrom_drives[i].scsi_device_id, cdrom_drives[i].scsi_device_lun); + } + + if (cdrom_drives[i].host_drive == 200) + { + image_open(i, cdrom_image[i].image_path); + } + else if ((cdrom_drives[i].host_drive >= 'A') && (cdrom_drives[i].host_drive <= 'Z')) + { + ioctl_open(i, cdrom_drives[i].host_drive); + } + else + { + cdrom_null_open(i, cdrom_drives[i].host_drive); + } + } + sound_reset(); fdc_init(); disc_init(); @@ -280,83 +415,36 @@ void initpc(int argc, char *argv[]) td0_init(); imd_init(); - if (network_card_current != 0) - { - vlan_reset(); //NETWORK - } - network_card_init(network_card_current); - disc_load(0, discfns[0]); disc_load(1, discfns[1]); disc_load(2, discfns[2]); disc_load(3, discfns[3]); - //loadfont(); loadnvr(); sound_init(); + resetide(); - if (buslogic_enabled) - { - SCSIReset(scsi_cdrom_id); - device_add(&BuslogicDevice); - } - - if ((cdrom_drive == -1) || (cdrom_drive == 0)) - cdrom_null_open(cdrom_drive); - else - { - if (cdrom_drive == 200) - { - ff = fopen(iso_path, "rb"); - if (ff) - { - fclose(ff); - iso_open(iso_path); - } - else - { -#if __unix - cdrom_drive = -1; -#else - cdrom_drive = 0; -#endif - cdrom_null_open(cdrom_drive); - } - } - else - { - ioctl_open(cdrom_drive); - } - } - - pit_reset(); -/* if (romset==ROM_AMI386 || romset==ROM_AMI486) */fullspeed(); - ali1429_reset(); -// CPUID=(is486 && (cpuspeed==7 || cpuspeed>=9)); -// pclog("Init - CPUID %i %i\n",CPUID,cpuspeed); + scsi_card_init(); + + fullspeed(); shadowbios=0; - if ((cdrom_drive == -1) || (cdrom_drive == 0)) - cdrom_null_reset(); - else + for (i = 0; i < CDROM_NUM; i++) { - if (cdrom_drive == 200) - { - iso_reset(); - } - else - { - ioctl_reset(); - } + if (cdrom_drives[i].host_drive == 200) + { + image_reset(i); + } + else if ((cdrom_drives[i].host_drive >= 'A') && (cdrom_drives[i].host_drive <= 'Z')) + { + ioctl_reset(i); + } } } -void resetpc() +void resetpc(void) { pc_reset(); -// cpuspeed2=(AT)?2:1; -// atfullspeed=0; -///* if (romset==ROM_AMI386 || romset==ROM_AMI486) */fullspeed(); shadowbios=0; } @@ -372,7 +460,7 @@ void pc_keyboard_send(uint8_t val) } } -void resetpc_cad() +void resetpc_cad(void) { pc_keyboard_send(29); /* Ctrl key pressed */ pc_keyboard_send(56); /* Alt key pressed */ @@ -382,27 +470,38 @@ void resetpc_cad() pc_keyboard_send(211); /* Delete key released */ } -void resetpchard() +int suppress_overscan = 0; + +void resetpchard_close(void) { + suppress_overscan = 0; + savenvr(); - saveconfig(); device_close_all(); mouse_emu_close(); + closeal(); +} + +void resetpchard_init(void) +{ + int i = 0; + + sound_realloc_buffers(); + + initalmain(0,NULL); + device_init(); - - midi_close(); - midi_init(); - + midi_device_init(); + inital(); + timer_reset(); sound_reset(); mem_resize(); fdc_init(); disc_reset(); - + model_init(); - mouse_emu_init(); - // mem_add_bios(); video_init(); speaker_init(); @@ -419,13 +518,13 @@ void resetpchard() ide_qua_init(); } - if (network_card_current != 0) - { - vlan_reset(); //NETWORK - } - network_card_init(network_card_current); + resetide(); + scsi_card_init(); + network_reset(); - sound_card_init(sound_card_current); + sound_card_init(); + if (mpu401_standalone_enable) + mpu401_device_add(); if (GUS) device_add(&gus_device); if (GAMEBLASTER) @@ -433,57 +532,42 @@ void resetpchard() if (SSI2001) device_add(&ssi2001_device); if (voodoo_enabled) - device_add(&voodoo_device); + device_add(&voodoo_device); + hdd_controller_init(hdd_controller_name); pc_reset(); - - resetide(); - - if (buslogic_enabled) - { - SCSIReset(scsi_cdrom_id); - device_add(&BuslogicDevice); - } + mouse_emu_init(); loadnvr(); -// cpuspeed2 = (AT)?2:1; -// atfullspeed = 0; -// setpitclock(models[model].cpu[cpu_manufacturer].cpus[cpu].rspeed); - shadowbios = 0; - ali1429_reset(); keyboard_at_reset(); cpu_cache_int_enabled = cpu_cache_ext_enabled = 0; -// output=3; - - if ((cdrom_drive == -1) || (cdrom_drive == 0)) - cdrom_null_reset(); - else + for (i = 0; i < CDROM_NUM; i++) { - if (cdrom_drive == 200) - { - iso_reset(); - } - else - { - ioctl_reset(); - } + if (cdrom_drives[i].host_drive == 200) + { + image_reset(i); + } + else if ((cdrom_drives[i].host_drive >= 'A') && (cdrom_drives[i].host_drive <= 'Z')) + { + ioctl_reset(i); + } } + + sound_cd_thread_reset(); } -char romsets[17][40]={"IBM PC","IBM XT","Generic Turbo XT","Euro PC","Tandy 1000","Amstrad PC1512","Sinclair PC200","Amstrad PC1640","IBM AT","AMI 286 clone","Dell System 200","Misc 286","IBM AT 386","Misc 386","386 clone","486 clone","486 clone 2"}; -char clockspeeds[3][12][16]= +void resetpchard(void) { - {"4.77MHz","8MHz","10MHz","12MHz","16MHz"}, - {"8MHz","12MHz","16MHz","20MHz","25MHz"}, - {"16MHz","20MHz","25MHz","33MHz","40MHz","50MHz","66MHz","75MHz","80MHz","100MHz","120MHz","133MHz"}, -}; + resetpchard_close(); + resetpchard_init(); +} + int framecountx=0; int sndcount=0; -int oldat70hz; int sreadlnum,swritelnum,segareads,segawrites, scycles_lost; @@ -491,9 +575,12 @@ int serial_fifo_read, serial_fifo_write; int emu_fps = 0; -void runpc() +static wchar_t wmodel[2048]; +static wchar_t wcpu[2048]; + +void runpc(void) { - char s[200]; + wchar_t s[200]; int done=0; startblit(); @@ -507,22 +594,23 @@ void runpc() exec386(models[model].cpu[cpu_manufacturer].cpus[cpu].rspeed / 100); } else if (AT) + { exec386(models[model].cpu[cpu_manufacturer].cpus[cpu].rspeed / 100); + } else + { execx86(models[model].cpu[cpu_manufacturer].cpus[cpu].rspeed / 100); + } - keyboard_poll_host(); keyboard_process(); -// checkkeys(); pollmouse(); if (joystick_type != 7) joystick_poll(); - endblit(); + endblit(); framecountx++; framecount++; if (framecountx>=100) { - // pclog("onesec\n"); framecountx=0; mips=(float)insc/1000000.0f; insc=0; @@ -567,13 +655,15 @@ void runpc() if (win_title_update) { win_title_update=0; - sprintf(s, "86Box v%s - %i%% - %s - %s - %s", emulator_version, fps, model_getname(), models[model].cpu[cpu_manufacturer].cpus[cpu].name, (!mousecapture) ? "Click to capture mouse" : ((mouse_get_type(mouse_type) & MOUSE_TYPE_3BUTTON) ? "Press F12-F8 to release mouse" : "Press F12-F8 or middle button to release mouse")); + mbstowcs(wmodel, model_getname(), strlen(model_getname()) + 1); + mbstowcs(wcpu, models[model].cpu[cpu_manufacturer].cpus[cpu].name, strlen(models[model].cpu[cpu_manufacturer].cpus[cpu].name) + 1); + _swprintf(s, L"%s v%s - %i%% - %s - %s - %s", EMU_NAME_W, EMU_VERSION_W, fps, wmodel, wcpu, (!mousecapture) ? plat_get_string_from_id(IDS_2077) : ((mouse_get_type(mouse_type) & MOUSE_TYPE_3BUTTON) ? plat_get_string_from_id(IDS_2078) : plat_get_string_from_id(IDS_2079))); set_window_title(s); } done++; } -void fullspeed() +void fullspeed(void) { cpuspeed2=cpuspeed; if (!atfullspeed) @@ -583,14 +673,12 @@ void fullspeed() setpitclock(models[model].cpu[cpu_manufacturer].cpus[cpu].rspeed); else setpitclock(14318184.0); -// if (is386) setpitclock(clocks[2][cpuspeed2][0]); -// else setpitclock(clocks[AT?1:0][cpuspeed2][0]); } atfullspeed=1; nvr_recalc(); } -void speedchanged() +void speedchanged(void) { if (AT) setpitclock(models[model].cpu[cpu_manufacturer].cpus[cpu].rspeed); @@ -599,388 +687,21 @@ void speedchanged() nvr_recalc(); } -void closepc() +void closepc(void) { - cdrom->exit(); -// ioctl_close(); + int i = 0; + for (i = 0; i < CDROM_NUM; i++) + { + cdrom_drives[i].handler->exit(i); + } dumppic(); -// output=7; -// setpitclock(clocks[0][0][0]); -// while (1) runpc(); - disc_close(0); - disc_close(1); - disc_close(2); - disc_close(3); - dumpregs(); + for (i = 0; i < FDD_NUM; i++) + { + disc_close(i); + } + dumpregs(0); closevideo(); device_close_all(); midi_close(); -} - -/*int main() -{ - initpc(); - while (!key[KEY_F11]) - { - runpc(); - } - closepc(); - return 0; -} - -END_OF_MAIN();*/ - -void loadconfig(char *fn) -{ - int c, d; - char s[512]; - char *p; - - if (!fn) - config_load(config_file_default); - else - config_load(fn); - - GAMEBLASTER = config_get_int(NULL, "gameblaster", 0); - GUS = config_get_int(NULL, "gus", 0); - SSI2001 = config_get_int(NULL, "ssi2001", 0); - voodoo_enabled = config_get_int(NULL, "voodoo", 0); - buslogic_enabled = config_get_int(NULL, "buslogic", 0); - - scsi_model = config_get_int(NULL, "scsi_model", 1); - scsi_base = config_get_int(NULL, "scsi_base", 0x330); - scsi_irq = config_get_int(NULL, "scsi_irq", 11); - scsi_dma = config_get_int(NULL, "scsi_dma", 6); - - //network - ethif = config_get_int(NULL, "netinterface", 1); - if (ethif >= inum) - inum = ethif + 1; - network_card_current = config_get_int(NULL, "netcard", NE2000); - - model = config_get_int(NULL, "model", 14); - - if (model >= model_count()) - model = model_count() - 1; - - romset = model_getromset(); - cpu_manufacturer = config_get_int(NULL, "cpu_manufacturer", 0); - cpu = config_get_int(NULL, "cpu", 0); - cpu_use_dynarec = config_get_int(NULL, "cpu_use_dynarec", 0); - - cpu_waitstates = config_get_int(NULL, "cpu_waitstates", 0); - - gfxcard = config_get_int(NULL, "gfxcard", 0); - video_speed = config_get_int(NULL, "video_speed", 3); - sound_card_current = config_get_int(NULL, "sndcard", SB2); - - // d86f_unregister(0); - // d86f_unregister(1); - - p = (char *)config_get_string(NULL, "disc_a", ""); - if (p) strcpy(discfns[0], p); - else strcpy(discfns[0], ""); - ui_writeprot[0] = config_get_int(NULL, "disc_a_writeprot", 0); - - p = (char *)config_get_string(NULL, "disc_b", ""); - if (p) strcpy(discfns[1], p); - else strcpy(discfns[1], ""); - ui_writeprot[1] = config_get_int(NULL, "disc_b_writeprot", 0); - - p = (char *)config_get_string(NULL, "disc_3", ""); - if (p) strcpy(discfns[2], p); - else strcpy(discfns[2], ""); - ui_writeprot[2] = config_get_int(NULL, "disc_3_writeprot", 0); - - p = (char *)config_get_string(NULL, "disc_4", ""); - if (p) strcpy(discfns[3], p); - else strcpy(discfns[3], ""); - ui_writeprot[3] = config_get_int(NULL, "disc_4_writeprot", 0); - - mem_size = config_get_int(NULL, "mem_size", 4096); - if (mem_size < ((models[model].flags & MODEL_AT) ? models[model].min_ram*1024 : models[model].min_ram)) - mem_size = ((models[model].flags & MODEL_AT) ? models[model].min_ram*1024 : models[model].min_ram); - - cdrom_drive = config_get_int(NULL, "cdrom_drive", 0); - old_cdrom_drive = cdrom_drive; - cdrom_enabled = config_get_int(NULL, "cdrom_enabled", 0); - - atapi_cdrom_channel = config_get_int(NULL, "atapi_cdrom_channel", 2); - - scsi_cdrom_enabled = config_get_int(NULL, "scsi_cdrom_enabled", 0); - scsi_cdrom_id = config_get_int(NULL, "scsi_cdrom_id", 3); - - p = (char *)config_get_string(NULL, "cdrom_path", ""); - if (p) strcpy(iso_path, p); - else strcpy(iso_path, ""); - - vid_resize = config_get_int(NULL, "vid_resize", 0); - vid_api = config_get_int(NULL, "vid_api", 0); - video_fullscreen_scale = config_get_int(NULL, "video_fullscreen_scale", 0); - video_fullscreen_first = config_get_int(NULL, "video_fullscreen_first", 1); - - hdc[0].spt = config_get_int(NULL, "hdc_sectors", 0); - hdc[0].hpc = config_get_int(NULL, "hdc_heads", 0); - hdc[0].tracks = config_get_int(NULL, "hdc_cylinders", 0); - p = (char *)config_get_string(NULL, "hdc_fn", ""); - if (p) strcpy(ide_fn[0], p); - else strcpy(ide_fn[0], ""); - hdc[1].spt = config_get_int(NULL, "hdd_sectors", 0); - hdc[1].hpc = config_get_int(NULL, "hdd_heads", 0); - hdc[1].tracks = config_get_int(NULL, "hdd_cylinders", 0); - p = (char *)config_get_string(NULL, "hdd_fn", ""); - if (p) strcpy(ide_fn[1], p); - else strcpy(ide_fn[1], ""); - hdc[2].spt = config_get_int(NULL, "hde_sectors", 0); - hdc[2].hpc = config_get_int(NULL, "hde_heads", 0); - hdc[2].tracks = config_get_int(NULL, "hde_cylinders", 0); - p = (char *)config_get_string(NULL, "hde_fn", ""); - if (p) strcpy(ide_fn[2], p); - else strcpy(ide_fn[2], ""); - hdc[3].spt = config_get_int(NULL, "hdf_sectors", 0); - hdc[3].hpc = config_get_int(NULL, "hdf_heads", 0); - hdc[3].tracks = config_get_int(NULL, "hdf_cylinders", 0); - p = (char *)config_get_string(NULL, "hdf_fn", ""); - if (p) strcpy(ide_fn[3], p); - else strcpy(ide_fn[3], ""); - hdc[4].spt = config_get_int(NULL, "hdg_sectors", 0); - hdc[4].hpc = config_get_int(NULL, "hdg_heads", 0); - hdc[4].tracks = config_get_int(NULL, "hdg_cylinders", 0); - p = (char *)config_get_string(NULL, "hdg_fn", ""); - if (p) strcpy(ide_fn[4], p); - else strcpy(ide_fn[4], ""); - hdc[5].spt = config_get_int(NULL, "hdh_sectors", 0); - hdc[5].hpc = config_get_int(NULL, "hdh_heads", 0); - hdc[5].tracks = config_get_int(NULL, "hdh_cylinders", 0); - p = (char *)config_get_string(NULL, "hdh_fn", ""); - if (p) strcpy(ide_fn[5], p); - else strcpy(ide_fn[5], ""); - hdc[6].spt = config_get_int(NULL, "hdi_sectors", 0); - hdc[6].hpc = config_get_int(NULL, "hdi_heads", 0); - hdc[6].tracks = config_get_int(NULL, "hdi_cylinders", 0); - p = (char *)config_get_string(NULL, "hdi_fn", ""); - if (p) strcpy(ide_fn[6], p); - else strcpy(ide_fn[6], ""); - hdc[7].spt = config_get_int(NULL, "hdj_sectors", 0); - hdc[7].hpc = config_get_int(NULL, "hdj_heads", 0); - hdc[7].tracks = config_get_int(NULL, "hdj_cylinders", 0); - p = (char *)config_get_string(NULL, "hdj_fn", ""); - if (p) strcpy(ide_fn[7], p); - else strcpy(ide_fn[7], ""); - - ide_enable[2] = config_get_int(NULL, "ide_ter_enable", 0); - ide_irq[2] = config_get_int(NULL, "ide_ter_irq", 10); - ide_enable[3] = config_get_int(NULL, "ide_qua_enable", 0); - ide_irq[3] = config_get_int(NULL, "ide_qua_irq", 11); - - fdd_set_type(0, config_get_int(NULL, "drive_a_type", 1)); - fdd_set_type(1, config_get_int(NULL, "drive_b_type", 1)); - fdd_set_type(2, config_get_int(NULL, "drive_3_type", 1)); - fdd_set_type(3, config_get_int(NULL, "drive_4_type", 1)); - - force_43 = config_get_int(NULL, "force_43", 0); - enable_overscan = config_get_int(NULL, "enable_overscan", 0); - enable_flash = config_get_int(NULL, "enable_flash", 1); - - enable_sync = config_get_int(NULL, "enable_sync", 1); - - window_w = config_get_int(NULL, "window_w", 0); - window_h = config_get_int(NULL, "window_h", 0); - window_x = config_get_int(NULL, "window_x", 0); - window_y = config_get_int(NULL, "window_y", 0); - window_remember = config_get_int(NULL, "window_remember", 0); - - joystick_type = config_get_int(NULL, "joystick_type", 0); - mouse_type = config_get_int(NULL, "mouse_type", 0); - - for (c = 0; c < joystick_get_max_joysticks(joystick_type); c++) - { - sprintf(s, "joystick_%i_nr", c); - joystick_state[c].plat_joystick_nr = config_get_int("Joysticks", s, 0); - - if (joystick_state[c].plat_joystick_nr) - { - for (d = 0; d < joystick_get_axis_count(joystick_type); d++) - { - sprintf(s, "joystick_%i_axis_%i", c, d); - joystick_state[c].axis_mapping[d] = config_get_int("Joysticks", s, d); - } - for (d = 0; d < joystick_get_button_count(joystick_type); d++) - { - sprintf(s, "joystick_%i_button_%i", c, d); - joystick_state[c].button_mapping[d] = config_get_int("Joysticks", s, d); - } - for (d = 0; d < joystick_get_pov_count(joystick_type); d++) - { - sprintf(s, "joystick_%i_pov_%i_x", c, d); - joystick_state[c].pov_mapping[d][0] = config_get_int("Joysticks", s, d); - sprintf(s, "joystick_%i_pov_%i_y", c, d); - joystick_state[c].pov_mapping[d][1] = config_get_int("Joysticks", s, d); - } - } - } - - memset(nvr_path, 0, 1024); - p = (char *)config_get_string(NULL, "nvr_path", "nvr"); - if (p) { - if (strlen(p) <= 992) strcpy(nvr_path, p); - else strcpy(nvr_path, "nvr"); - } - else strcpy(nvr_path, "nvr"); - - if (nvr_path[strlen(nvr_path)] != '/') - { - nvr_path[strlen(nvr_path)] = '/'; - } - - path_len = strlen(nvr_path); -} - -char *nvr_concat(char *to_concat) -{ - memset(nvr_path + path_len, 0, 1024 - path_len); - strcpy(nvr_path + path_len, to_concat); - return nvr_path; -} - -void saveconfig() -{ - int c, d; - - config_set_int(NULL, "gameblaster", GAMEBLASTER); - config_set_int(NULL, "gus", GUS); - config_set_int(NULL, "ssi2001", SSI2001); - config_set_int(NULL, "voodoo", voodoo_enabled); - config_set_int(NULL, "buslogic", buslogic_enabled); - - config_set_int(NULL, "scsi_model", scsi_model); - config_set_int(NULL, "scsi_base", scsi_base); - config_set_int(NULL, "scsi_irq", scsi_irq); - config_set_int(NULL, "scsi_dma", scsi_dma); - - config_set_int(NULL, "netinterface", ethif); - config_set_int(NULL, "netcard", network_card_current); - - config_set_int(NULL, "model", model); - config_set_int(NULL, "cpu_manufacturer", cpu_manufacturer); - config_set_int(NULL, "cpu", cpu); - config_set_int(NULL, "cpu_use_dynarec", cpu_use_dynarec); - config_set_int(NULL, "cpu_waitstates", cpu_waitstates); - - config_set_int(NULL, "gfxcard", gfxcard); - config_set_int(NULL, "video_speed", video_speed); - config_set_int(NULL, "sndcard", sound_card_current); - config_set_int(NULL, "cpu_speed", cpuspeed); - config_set_int(NULL, "has_fpu", hasfpu); - config_set_string(NULL, "disc_a", discfns[0]); - config_set_int(NULL, "disc_a_writeprot", ui_writeprot[0]); - config_set_string(NULL, "disc_b", discfns[1]); - config_set_int(NULL, "disc_b_writeprot", ui_writeprot[1]); - config_set_string(NULL, "disc_3", discfns[2]); - config_set_int(NULL, "disc_3_writeprot", ui_writeprot[2]); - config_set_string(NULL, "disc_4", discfns[3]); - config_set_int(NULL, "disc_4_writeprot", ui_writeprot[3]); - config_set_int(NULL, "mem_size", mem_size); - config_set_int(NULL, "cdrom_drive", cdrom_drive); - config_set_int(NULL, "cdrom_enabled", cdrom_enabled); - - config_set_int(NULL, "atapi_cdrom_channel", atapi_cdrom_channel); - - config_set_int(NULL, "scsi_cdrom_enabled", scsi_cdrom_enabled); - config_set_int(NULL, "scsi_cdrom_id", scsi_cdrom_id); - - config_set_string(NULL, "cdrom_path", iso_path); - config_set_int(NULL, "vid_resize", vid_resize); - config_set_int(NULL, "vid_api", vid_api); - config_set_int(NULL, "video_fullscreen_scale", video_fullscreen_scale); - config_set_int(NULL, "video_fullscreen_first", video_fullscreen_first); - - config_set_int(NULL, "hdc_sectors", hdc[0].spt); - config_set_int(NULL, "hdc_heads", hdc[0].hpc); - config_set_int(NULL, "hdc_cylinders", hdc[0].tracks); - config_set_string(NULL, "hdc_fn", ide_fn[0]); - config_set_int(NULL, "hdd_sectors", hdc[1].spt); - config_set_int(NULL, "hdd_heads", hdc[1].hpc); - config_set_int(NULL, "hdd_cylinders", hdc[1].tracks); - config_set_string(NULL, "hdd_fn", ide_fn[1]); - config_set_int(NULL, "hde_sectors", hdc[2].spt); - config_set_int(NULL, "hde_heads", hdc[2].hpc); - config_set_int(NULL, "hde_cylinders", hdc[2].tracks); - config_set_string(NULL, "hde_fn", ide_fn[2]); - config_set_int(NULL, "hdf_sectors", hdc[3].spt); - config_set_int(NULL, "hdf_heads", hdc[3].hpc); - config_set_int(NULL, "hdf_cylinders", hdc[3].tracks); - config_set_string(NULL, "hdf_fn", ide_fn[3]); - config_set_int(NULL, "hdg_sectors", hdc[4].spt); - config_set_int(NULL, "hdg_heads", hdc[4].hpc); - config_set_int(NULL, "hdg_cylinders", hdc[4].tracks); - config_set_string(NULL, "hdg_fn", ide_fn[4]); - config_set_int(NULL, "hdh_sectors", hdc[5].spt); - config_set_int(NULL, "hdh_heads", hdc[5].hpc); - config_set_int(NULL, "hdh_cylinders", hdc[5].tracks); - config_set_string(NULL, "hdh_fn", ide_fn[5]); - config_set_int(NULL, "hdi_sectors", hdc[6].spt); - config_set_int(NULL, "hdi_heads", hdc[6].hpc); - config_set_int(NULL, "hdi_cylinders", hdc[6].tracks); - config_set_string(NULL, "hdi_fn", ide_fn[6]); - config_set_int(NULL, "hdj_sectors", hdc[7].spt); - config_set_int(NULL, "hdj_heads", hdc[7].hpc); - config_set_int(NULL, "hdj_cylinders", hdc[7].tracks); - config_set_string(NULL, "hdj_fn", ide_fn[7]); - - config_set_int(NULL, "ide_ter_enable", ide_enable[2]); - config_set_int(NULL, "ide_ter_irq", ide_irq[2]); - config_set_int(NULL, "ide_qua_enable", ide_enable[3]); - config_set_int(NULL, "ide_qua_irq", ide_irq[3]); - - config_set_int(NULL, "drive_a_type", fdd_get_type(0)); - config_set_int(NULL, "drive_b_type", fdd_get_type(1)); - config_set_int(NULL, "drive_3_type", fdd_get_type(2)); - config_set_int(NULL, "drive_4_type", fdd_get_type(3)); - - config_set_int(NULL, "force_43", force_43); - config_set_int(NULL, "enable_overscan", enable_overscan); - config_set_int(NULL, "enable_flash", enable_flash); - - config_set_int(NULL, "enable_sync", enable_sync); - - config_set_int(NULL, "joystick_type", joystick_type); - config_set_int(NULL, "mouse_type", mouse_type); - - for (c = 0; c < joystick_get_max_joysticks(joystick_type); c++) - { - char s[80]; - - sprintf(s, "joystick_%i_nr", c); - config_set_int("Joysticks", s, joystick_state[c].plat_joystick_nr); - - if (joystick_state[c].plat_joystick_nr) - { - for (d = 0; d < joystick_get_axis_count(joystick_type); d++) - { - sprintf(s, "joystick_%i_axis_%i", c, d); - config_set_int("Joysticks", s, joystick_state[c].axis_mapping[d]); - } - for (d = 0; d < joystick_get_button_count(joystick_type); d++) - { - sprintf(s, "joystick_%i_button_%i", c, d); - config_set_int("Joysticks", s, joystick_state[c].button_mapping[d]); - } - for (d = 0; d < joystick_get_pov_count(joystick_type); d++) - { - sprintf(s, "joystick_%i_pov_%i_x", c, d); - config_set_int("Joysticks", s, joystick_state[c].pov_mapping[d][0]); - sprintf(s, "joystick_%i_pov_%i_y", c, d); - config_set_int("Joysticks", s, joystick_state[c].pov_mapping[d][1]); - } - } - } - - config_set_int(NULL, "window_w", window_w); - config_set_int(NULL, "window_h", window_h); - config_set_int(NULL, "window_x", window_x); - config_set_int(NULL, "window_y", window_y); - config_set_int(NULL, "window_remember", window_remember); - - config_save(config_file_default); + network_close(); } diff --git a/src/pc.rc b/src/pc.rc deleted file mode 100644 index fcb8741dc..000000000 --- a/src/pc.rc +++ /dev/null @@ -1,397 +0,0 @@ -/* Copyright holders: Sarah Walker, Tenshi - see COPYING for more details -*/ -#include -#include "resources.h" - -#ifndef UPDOWN_CLASS -#define UPDOWN_CLASS L"msctls_updown32" -#endif - -MainMenu MENU DISCARDABLE -BEGIN - POPUP "&File" - BEGIN - MENUITEM "&Hard Reset", IDM_FILE_HRESET - MENUITEM "&Ctrl+Alt+Del\tCtrl+F12",IDM_FILE_RESET_CAD - MENUITEM "E&xit", IDM_FILE_EXIT - END - POPUP "&Disc" - BEGIN - MENUITEM "Change FDD& 1...", IDM_DISC_1 - MENUITEM "Change FDD 1 (&Write-protected)...", IDM_DISC_1_WP - MENUITEM "&Eject FDD 1", IDM_EJECT_1 - MENUITEM SEPARATOR - MENUITEM "Change FDD &2...", IDM_DISC_2 - MENUITEM "Change FDD 2 (W&rite-protected)...", IDM_DISC_2_WP - MENUITEM "E&ject FDD 2", IDM_EJECT_2 - MENUITEM SEPARATOR - MENUITEM "Change FDD &3...", IDM_DISC_3 - MENUITEM "Change FDD 3 (W&rite-protected)...", IDM_DISC_3_WP - MENUITEM "E&ject FDD 3", IDM_EJECT_3 - MENUITEM SEPARATOR - MENUITEM "Change FDD &4...", IDM_DISC_4 - MENUITEM "Change FDD 4 (W&rite-protected)...", IDM_DISC_4_WP - MENUITEM "E&ject FDD 4", IDM_EJECT_4 - MENUITEM SEPARATOR - MENUITEM "&Configure hard discs...",IDM_HDCONF - POPUP "C&D-ROM" - BEGIN - MENUITEM "&Enabled", IDM_CDROM_ENABLED - MENUITEM "&SCSI", IDM_CDROM_SCSI - MENUITEM SEPARATOR - MENUITEM "E&mpty",IDM_CDROM_EMPTY - MENUITEM "&Reload previous disc",IDM_CDROM_RELOAD - MENUITEM SEPARATOR - MENUITEM "&ISO...",IDM_CDROM_ISO - END - POPUP "E&xtra IDE controllers" - BEGIN - POPUP "&Tertiary IDE controller" - BEGIN - MENUITEM "&Enabled",IDM_IDE_TER_ENABLED - MENUITEM SEPARATOR - MENUITEM "&9",IDM_IDE_TER_IRQ9 - MENUITEM "1&0",IDM_IDE_TER_IRQ10 - MENUITEM "1&1",IDM_IDE_TER_IRQ11 - MENUITEM "1&2",IDM_IDE_TER_IRQ12 - MENUITEM "1&4",IDM_IDE_TER_IRQ14 - MENUITEM "1&5",IDM_IDE_TER_IRQ15 - END - POPUP "&Quaternary IDE controller" - BEGIN - MENUITEM "&Enabled",IDM_IDE_QUA_ENABLED - MENUITEM SEPARATOR - MENUITEM "&9",IDM_IDE_QUA_IRQ9 - MENUITEM "1&0",IDM_IDE_QUA_IRQ10 - MENUITEM "1&1",IDM_IDE_QUA_IRQ11 - MENUITEM "1&2",IDM_IDE_QUA_IRQ12 - MENUITEM "1&4",IDM_IDE_QUA_IRQ14 - MENUITEM "1&5",IDM_IDE_QUA_IRQ15 - END - END - POPUP "&SCSI controller" - BEGIN - MENUITEM "&Enabled",IDM_SCSI_ENABLED - POPUP "&Model" - BEGIN - MENUITEM "&Adaptec AHA-154x",IDM_SCSI_MODEL0 - MENUITEM "&BusLogic BT-542B",IDM_SCSI_MODEL1 - END - POPUP "&Base address" - BEGIN - MENUITEM "0x&130",IDM_SCSI_BASE130 - MENUITEM "0x13&4",IDM_SCSI_BASE134 - MENUITEM "0x&230",IDM_SCSI_BASE230 - MENUITEM "0&x234",IDM_SCSI_BASE234 - MENUITEM "0x33&0",IDM_SCSI_BASE330 - MENUITEM "&0x334",IDM_SCSI_BASE334 - END - POPUP "&IRQ" - BEGIN - MENUITEM "&9",IDM_SCSI_IRQ9 - MENUITEM "1&0",IDM_SCSI_IRQ10 - MENUITEM "1&1",IDM_SCSI_IRQ11 - MENUITEM "1&2",IDM_SCSI_IRQ12 - MENUITEM "1&4",IDM_SCSI_IRQ14 - MENUITEM "1&5",IDM_SCSI_IRQ15 - END - POPUP "&DMA channel" - BEGIN - MENUITEM "&5",IDM_SCSI_DMA5 - MENUITEM "&6",IDM_SCSI_DMA6 - MENUITEM "&7",IDM_SCSI_DMA7 - END - END - END - POPUP "&Settings" - BEGIN - MENUITEM "&Configure...", IDM_CONFIG - MENUITEM "&Load configuration...", IDM_CONFIG_LOAD - MENUITEM "&Save configuration...", IDM_CONFIG_SAVE - MENUITEM SEPARATOR - POPUP "&Video" - BEGIN - MENUITEM "&Resizeable window",IDM_VID_RESIZE - MENUITEM "R&emember size && position",IDM_VID_REMEMBER - MENUITEM SEPARATOR - MENUITEM "&DirectDraw", IDM_VID_DDRAW - MENUITEM "Direct&3D 9", IDM_VID_D3D - MENUITEM SEPARATOR - MENUITEM "&Fullscreen", IDM_VID_FULLSCREEN - POPUP "Fullscreen &stretch mode" - BEGIN - MENUITEM "&Full screen stretch", IDM_VID_FS_FULL - MENUITEM "&4:3", IDM_VID_FS_43 - MENUITEM "&Square pixels", IDM_VID_FS_SQ - MENUITEM "&Integer scale", IDM_VID_FS_INT - END - MENUITEM SEPARATOR - MENUITEM "F&orce 4:3 display ratio", IDM_VID_FORCE43 - MENUITEM "E&GA/(S)VGA overscan", IDM_VID_OVERSCAN - MENUITEM SEPARATOR - MENUITEM "D&isc activity flash", IDM_VID_FLASH - MENUITEM SEPARATOR - MENUITEM "Take s&creenshot\tCtrl+F11", IDM_VID_SCREENSHOT - END - MENUITEM "&Status", IDM_STATUS - END -END - -MainAccel ACCELERATORS -BEGIN - VK_F11, IDM_VID_SCREENSHOT, CONTROL, VIRTKEY - VK_F12, IDM_FILE_RESET_CAD, CONTROL, VIRTKEY -END - -ConfigureDlg DIALOGEX 0, 0, 252+40, 236+80 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Configure 86Box" -FONT 9, "Segoe UI" -BEGIN - DEFPUSHBUTTON "OK",IDOK,64,292,50,14, WS_TABSTOP - PUSHBUTTON "Cancel",IDCANCEL,128,292,50,14, WS_TABSTOP - COMBOBOX IDC_COMBO1,62,16,157,120,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - PUSHBUTTON "Configure", IDC_CONFIGUREMOD, 224, 16, 40, 14, WS_TABSTOP - COMBOBOX IDC_COMBOVID,62,36,157,120,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - PUSHBUTTON "Configure", IDC_CONFIGUREVID, 224, 36, 40, 14, WS_TABSTOP - COMBOBOX IDC_COMBOCPUM,62,56,157,120,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - COMBOBOX IDC_COMBO3,62,76,102,120,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - CONTROL "Dynamic Recompiler",IDC_CHECKDYNAREC,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,169,76,99,10 - COMBOBOX IDC_COMBOWS, 62,96,157,120,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - COMBOBOX IDC_COMBOSPD,62,116,57,120,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - COMBOBOX IDC_COMBOSND,162,116,57,120,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - PUSHBUTTON "Configure", IDC_CONFIGURESND, 224, 116, 40, 14, WS_TABSTOP - EDITTEXT IDC_MEMTEXT, 62, 136, 36, 14, ES_AUTOHSCROLL | ES_NUMBER - CONTROL "", IDC_MEMSPIN, UPDOWN_CLASS, UDS_ALIGNRIGHT | UDS_ARROWKEYS | UDS_NOTHOUSANDS | UDS_SETBUDDYINT, 98, 136, 12, 14 - LTEXT "MB", IDC_TEXT_MB, 98, 136, 10, 10 - CONTROL "CMS / Game Blaster",IDC_CHECK3,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,192,102,10 - CONTROL "Gravis Ultrasound",IDC_CHECKGUS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,208,102,10 - - CONTROL "Innovation SSI-2001",IDC_CHECKSSI,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,118,192,102,10 - CONTROL "Enable time sync",IDC_CHECKSYNC,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,118,208,102,10 - - CONTROL "Voodoo Graphics",IDC_CHECKVOODOO,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,118,224,102,10 - PUSHBUTTON "Configure", IDC_CONFIGUREVOODOO, 224, 224, 40, 14, WS_TABSTOP - - LTEXT "Mouse :",IDC_STATIC,15,240,40,10 - COMBOBOX IDC_COMBOMOUSE,62,240,157,120,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP - - LTEXT "Joystick :",IDC_STATIC,15,260,40,10 - COMBOBOX IDC_COMBOJOY,62,260,157,120,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - DEFPUSHBUTTON "Joystick 1...",IDC_JOY1,16,276,50,14, WS_TABSTOP - PUSHBUTTON "Joystick 2...",IDC_JOY2,80,276,50,14, WS_TABSTOP - DEFPUSHBUTTON "Joystick 3...",IDC_JOY3,144,276,50,14, WS_TABSTOP - PUSHBUTTON "Joystick 4...",IDC_JOY4,208,276,50,14, WS_TABSTOP - - LTEXT "Machine :",IDC_STATIC,15,16,40,10 - LTEXT "Video :",IDC_STATIC,15,36,34,10 - LTEXT "CPU type :",IDC_STATIC,15,56,34,10 - LTEXT "CPU :",IDC_STATIC,15,76,34,10 - LTEXT "Waitstates :",IDC_STATIC,15,96,40,10 - LTEXT "Vid. speed :",IDC_STATIC,15,116,40,10 - LTEXT "Soundcard:",IDC_STATIC,125,116,34,10 - LTEXT "Network :",IDC_STATIC,125,136,34,10 - COMBOBOX IDC_COMBONET,162,136,57,120,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - PUSHBUTTON "Configure", IDC_CONFIGURENET, 224, 136, 40, 14, WS_TABSTOP - LTEXT "Memory :",IDC_STATIC,15,136,40,10 - LTEXT "FDD 1 :",IDC_STATIC,15,156,40,10 - LTEXT "FDD 2 :",IDC_STATIC,125,156,40,10 - COMBOBOX IDC_COMBODR1,62,156,57,120,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - COMBOBOX IDC_COMBODR2,162,156,57,120,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - LTEXT "FDD 3 :",IDC_STATIC,15,176,40,10 - LTEXT "FDD 4 :",IDC_STATIC,125,176,40,10 - COMBOBOX IDC_COMBODR3,62,176,57,120,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - COMBOBOX IDC_COMBODR4,162,176,57,120,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP -END - -HdConfDlg DIALOGEX 0, 0, 270, DLG_HEIGHT - STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU - CAPTION "Configure Hard Discs" - FONT 9, "Segoe UI" - BEGIN - DEFPUSHBUTTON "OK",IDOK,31+12,CMD_BASE,50,14 - PUSHBUTTON "Cancel",IDCANCEL,101+12,CMD_BASE,50,14 - - LTEXT "C:",IDC_STATIC,7,C_BASE+2,27,10 - EDITTEXT IDC_EDIT_C_FN, 7+16, C_BASE, 120, 12, WS_DISABLED - PUSHBUTTON "...",IDC_CFILE,7 + 136, C_BASE, 16, 14 - PUSHBUTTON "New",IDC_CNEW,7 + 152, C_BASE, 24, 14 - PUSHBUTTON "Eject", IDC_EJECTC, 7 + 176, C_BASE, 24, 14 - RADIOBUTTON "Hard drive", IDC_CHDD, 7+207, C_BASE, 53, 12 , WS_TABSTOP - RADIOBUTTON "CD-ROM", IDC_CCDROM, 7+207, C_BASE+16, 53, 12 , WS_TABSTOP - EDITTEXT IDC_EDIT_C_SPT,15,C_BASE+16,16,12, WS_DISABLED - EDITTEXT IDC_EDIT_C_HPC,48,C_BASE+16,16,12, WS_DISABLED - EDITTEXT IDC_EDIT_C_CYL,81,C_BASE+16,28,12, WS_DISABLED - LTEXT "S:",IDC_STATIC,7,C_BASE+18,8,12 - LTEXT "H:",IDC_STATIC,40,C_BASE+18,8,12 - LTEXT "C:",IDC_STATIC,73,C_BASE+18,8,12 - LTEXT "", IDC_TEXT_C_SIZE, 118, C_BASE+18, 89, 12 - - LTEXT "D:",IDC_STATIC,7,D_BASE+2,27,10 - EDITTEXT IDC_EDIT_D_FN, 7+16, D_BASE, 120, 12, WS_DISABLED - PUSHBUTTON "...",IDC_DFILE,7 + 136, D_BASE, 16, 14 - PUSHBUTTON "New",IDC_DNEW,7 + 152, D_BASE, 24, 14 - PUSHBUTTON "Eject", IDC_EJECTD, 7 + 176, D_BASE, 24, 14 - RADIOBUTTON "Hard drive", IDC_DHDD, 7+207, D_BASE, 53, 12 , WS_TABSTOP - RADIOBUTTON "CD-ROM", IDC_DCDROM, 7+207, D_BASE+16, 53, 12 , WS_TABSTOP - EDITTEXT IDC_EDIT_D_SPT,15,D_BASE+16,16,12, WS_DISABLED - EDITTEXT IDC_EDIT_D_HPC,48,D_BASE+16,16,12, WS_DISABLED - EDITTEXT IDC_EDIT_D_CYL,81,D_BASE+16,28,12, WS_DISABLED - LTEXT "S:",IDC_STATIC,7,D_BASE+18,8,12 - LTEXT "H:",IDC_STATIC,40,D_BASE+18,8,12 - LTEXT "C:",IDC_STATIC,73,D_BASE+18,8,12 - LTEXT "", IDC_TEXT_D_SIZE, 118, D_BASE+18, 89, 12 - - LTEXT "E:",IDC_STATIC,7,E_BASE+2,27,10 - EDITTEXT IDC_EDIT_E_FN, 7+16, E_BASE, 120, 12, WS_DISABLED - PUSHBUTTON "...",IDC_EFILE,7 + 136, E_BASE, 16, 14 - PUSHBUTTON "New",IDC_ENEW,7 + 152, E_BASE, 24, 14 - PUSHBUTTON "Eject", IDC_EJECTE, 7 + 176, E_BASE, 24, 14 - RADIOBUTTON "Hard drive", IDC_EHDD, 7+207, E_BASE, 53, 12 , WS_TABSTOP - RADIOBUTTON "CD-ROM", IDC_ECDROM, 7+207, E_BASE+16, 53, 12 , WS_TABSTOP - EDITTEXT IDC_EDIT_E_SPT,15,E_BASE+16,16,12, WS_DISABLED - EDITTEXT IDC_EDIT_E_HPC,48,E_BASE+16,16,12, WS_DISABLED - EDITTEXT IDC_EDIT_E_CYL,81,E_BASE+16,28,12, WS_DISABLED - LTEXT "S:",IDC_STATIC,7,E_BASE+18,8,12 - LTEXT "H:",IDC_STATIC,40,E_BASE+18,8,12 - LTEXT "C:",IDC_STATIC,73,E_BASE+18,8,12 - LTEXT "", IDC_TEXT_E_SIZE, 118, E_BASE+18, 89, 12 - - LTEXT "F:",IDC_STATIC,7,F_BASE+2,27,10 - EDITTEXT IDC_EDIT_F_FN, 7+16, F_BASE, 120, 12, WS_DISABLED - PUSHBUTTON "...",IDC_FFILE,7 + 136, F_BASE, 16, 14 - PUSHBUTTON "New",IDC_FNEW,7 + 152, F_BASE, 24, 14 - PUSHBUTTON "Eject", IDC_EJECTF, 7 + 176, F_BASE, 24, 14 - RADIOBUTTON "Hard drive", IDC_FHDD, 7+207, F_BASE, 53, 12 , WS_TABSTOP - RADIOBUTTON "CD-ROM", IDC_FCDROM, 7+207, F_BASE+16, 53, 12 , WS_TABSTOP - EDITTEXT IDC_EDIT_F_SPT,15,F_BASE+16,16,12, WS_DISABLED - EDITTEXT IDC_EDIT_F_HPC,48,F_BASE+16,16,12, WS_DISABLED - EDITTEXT IDC_EDIT_F_CYL,81,F_BASE+16,28,12, WS_DISABLED - LTEXT "S:",IDC_STATIC,7,F_BASE+18,8,12 - LTEXT "H:",IDC_STATIC,40,F_BASE+18,8,12 - LTEXT "C:",IDC_STATIC,73,F_BASE+18,8,12 - LTEXT "", IDC_TEXT_F_SIZE, 118, F_BASE+18, 89, 12 - - LTEXT "G:",IDC_STATIC,7,G_BASE+2,27,10 - EDITTEXT IDC_EDIT_G_FN, 7+16, G_BASE, 120, 12, WS_DISABLED - PUSHBUTTON "...",IDC_GFILE,7 + 136, G_BASE, 16, 14 - PUSHBUTTON "New",IDC_GNEW,7 + 152, G_BASE, 24, 14 - PUSHBUTTON "Eject", IDC_EJECTG, 7 + 176, G_BASE, 24, 14 - RADIOBUTTON "Hard drive", IDC_GHDD, 7+207, G_BASE, 53, 12 , WS_TABSTOP - RADIOBUTTON "CD-ROM", IDC_GCDROM, 7+207, G_BASE+16, 53, 12 , WS_TABSTOP - EDITTEXT IDC_EDIT_G_SPT,15,G_BASE+16,16,12, WS_DISABLED - EDITTEXT IDC_EDIT_G_HPC,48,G_BASE+16,16,12, WS_DISABLED - EDITTEXT IDC_EDIT_G_CYL,81,G_BASE+16,28,12, WS_DISABLED - LTEXT "S:",IDC_STATIC,7,G_BASE+18,8,12 - LTEXT "H:",IDC_STATIC,40,G_BASE+18,8,12 - LTEXT "C:",IDC_STATIC,73,G_BASE+18,8,12 - LTEXT "", IDC_TEXT_G_SIZE, 118, G_BASE+18, 89, 12 - - LTEXT "H:",IDC_STATIC,7,H_BASE+2,27,10 - EDITTEXT IDC_EDIT_H_FN, 7+16, H_BASE, 120, 12, WS_DISABLED - PUSHBUTTON "...",IDC_HFILE,7 + 136, H_BASE, 16, 14 - PUSHBUTTON "New",IDC_HNEW,7 + 152, H_BASE, 24, 14 - PUSHBUTTON "Eject", IDC_EJECTH, 7 + 176, H_BASE, 24, 14 - RADIOBUTTON "Hard drive", IDC_HHDD, 7+207, H_BASE, 53, 12 , WS_TABSTOP - RADIOBUTTON "CD-ROM", IDC_HCDROM, 7+207, H_BASE+16, 53, 12 , WS_TABSTOP - EDITTEXT IDC_EDIT_H_SPT,15,H_BASE+16,16,12, WS_DISABLED - EDITTEXT IDC_EDIT_H_HPC,48,H_BASE+16,16,12, WS_DISABLED - EDITTEXT IDC_EDIT_H_CYL,81,H_BASE+16,28,12, WS_DISABLED - LTEXT "S:",IDC_STATIC,7,H_BASE+18,8,12 - LTEXT "H:",IDC_STATIC,40,H_BASE+18,8,12 - LTEXT "C:",IDC_STATIC,73,H_BASE+18,8,12 - LTEXT "", IDC_TEXT_H_SIZE, 118, H_BASE+18, 89, 12 - - LTEXT "I:",IDC_STATIC,7,I_BASE+2,27,10 - EDITTEXT IDC_EDIT_I_FN, 7+16, I_BASE, 120, 12, WS_DISABLED - PUSHBUTTON "...",IDC_IFILE,7 + 136, I_BASE, 16, 14 - PUSHBUTTON "New",IDC_INEW,7 + 152, I_BASE, 24, 14 - PUSHBUTTON "Eject", IDC_EJECTI, 7 + 176, I_BASE, 24, 14 - RADIOBUTTON "Hard drive", IDC_IHDD, 7+207, I_BASE, 53, 12 , WS_TABSTOP - RADIOBUTTON "CD-ROM", IDC_ICDROM, 7+207, I_BASE+16, 53, 12 , WS_TABSTOP - EDITTEXT IDC_EDIT_I_SPT,15,I_BASE+16,16,12, WS_DISABLED - EDITTEXT IDC_EDIT_I_HPC,48,I_BASE+16,16,12, WS_DISABLED - EDITTEXT IDC_EDIT_I_CYL,81,I_BASE+16,28,12, WS_DISABLED - LTEXT "S:",IDC_STATIC,7,I_BASE+18,8,12 - LTEXT "H:",IDC_STATIC,40,I_BASE+18,8,12 - LTEXT "C:",IDC_STATIC,73,I_BASE+18,8,12 - LTEXT "", IDC_TEXT_I_SIZE, 118, I_BASE+18, 89, 12 - - LTEXT "J:",IDC_STATIC,7,J_BASE+2,27,10 - EDITTEXT IDC_EDIT_J_FN, 7+16, J_BASE, 120, 12, WS_DISABLED - PUSHBUTTON "...",IDC_JFILE,7 + 136, J_BASE, 16, 14 - PUSHBUTTON "New",IDC_JNEW,7 + 152, J_BASE, 24, 14 - PUSHBUTTON "Eject", IDC_EJECTJ, 7 + 176, J_BASE, 24, 14 - RADIOBUTTON "Hard drive", IDC_JHDD, 7+207, J_BASE, 53, 12 , WS_TABSTOP - RADIOBUTTON "CD-ROM", IDC_JCDROM, 7+207, J_BASE+16, 53, 12 , WS_TABSTOP - EDITTEXT IDC_EDIT_J_SPT,15,J_BASE+16,16,12, WS_DISABLED - EDITTEXT IDC_EDIT_J_HPC,48,J_BASE+16,16,12, WS_DISABLED - EDITTEXT IDC_EDIT_J_CYL,81,J_BASE+16,28,12, WS_DISABLED - LTEXT "S:",IDC_STATIC,7,J_BASE+18,8,12 - LTEXT "H:",IDC_STATIC,40,J_BASE+18,8,12 - LTEXT "C:",IDC_STATIC,73,J_BASE+18,8,12 - LTEXT "", IDC_TEXT_J_SIZE, 118, J_BASE+18, 89, 12 - -END - -HdNewDlg DIALOGEX 0, 0, 216, 86 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "New Hard Disc" -FONT 9, "Segoe UI" -BEGIN - DEFPUSHBUTTON "OK",IDOK,31,66,50,14 - PUSHBUTTON "Cancel",IDCANCEL,101,66,50,14 - - EDITTEXT IDC_EDITC, 7, 6, 187, 12 - PUSHBUTTON "...",IDC_CFILE,7 + 187, 6, 16, 14 - - EDITTEXT IDC_EDIT1,36,22,16,12 - EDITTEXT IDC_EDIT2,94,22,16,12 - EDITTEXT IDC_EDIT3,152,22,28,12 - EDITTEXT IDC_EDIT4,36,38,28,12 - COMBOBOX IDC_COMBOHDT,117,38,93,12,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - LTEXT "Sectors:",IDC_STATIC,7,23,27,10 - LTEXT "Heads:",IDC_STATIC,63,23,29,8 - LTEXT "Cylinders:",IDC_STATIC,120,23,32,12 - LTEXT "Size:",IDC_STATIC,7,39,17,8 - LTEXT "MB",IDC_STATIC,68,39,10,8 - LTEXT "Type:",IDC_STATIC,94,39,17,8 -END - -HdSizeDlg DIALOGEX 0, 0, 216, 86 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Hard disc parameters" -FONT 9, "Segoe UI" -BEGIN - DEFPUSHBUTTON "OK",IDOK,31,66,50,14 - PUSHBUTTON "Cancel",IDCANCEL,101,66,50,14 - - LTEXT "Initial settings are based on file size (header if HDI)",IDC_STATIC,7,6,200,10 - - EDITTEXT IDC_EDIT1,36,22,16,12 - EDITTEXT IDC_EDIT2,94,22,16,12 - EDITTEXT IDC_EDIT3,152,22,28,12 - EDITTEXT IDC_EDIT4,36,38,28,12 - COMBOBOX IDC_COMBOHDT,117,38,93,12,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - LTEXT "Sectors:",IDC_STATIC,7,23,27,10 - LTEXT "Heads:",IDC_STATIC,63,23,29,8 - LTEXT "Cylinders:",IDC_STATIC,120,23,32,12 - LTEXT "Size:",IDC_STATIC,7,39,17,8 - LTEXT "MB",IDC_STATIC,68,39,10,8 - LTEXT "Type:",IDC_STATIC,94,39,17,8 -END - -StatusDlg DIALOGEX 0,0,186,186+20+180 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Status" -FONT 9, "Segoe UI" -BEGIN - LTEXT "1",IDC_STEXT_DEVICE,16,16,180,1000 - LTEXT "1",IDC_STEXT1,16,186,180,1000 -END - -1 24 "86Box.manifest" - -/* Icon by Devcore - https://commons.wikimedia.org/wiki/File:Icon_PC2_256x256.png */ -100 ICON "86Box.ico" diff --git a/src/pc87306.c b/src/pc87306.c index 9290c6209..b67aa5071 100644 --- a/src/pc87306.c +++ b/src/pc87306.c @@ -1,95 +1,95 @@ -/* Copyright holders: Tenshi - see COPYING for more details -*/ /* - National Semiconductors PC87306 Super I/O Chip - Used by Intel Advanced/EV -*/ + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Emulation of the National Semiconductors PC87306 Super I/O + * chip. + * + * Version: @(#)pc87306.c 1.0.0 2017/05/30 + * + * Author: Miran Grca, + * Copyright 2016-2017 Miran Grca. + */ #include "ibm.h" #include "disc.h" #include "fdc.h" #include "fdd.h" +#include "ide.h" #include "io.h" #include "lpt.h" #include "serial.h" #include "pc87306.h" -static int pc87306_locked; static int pc87306_curreg; static uint8_t pc87306_regs[29]; -static uint8_t pc87306_gpio[2] = {0xFF, 0xFF}; +static uint8_t pc87306_gpio[2] = {0xFF, 0xFB}; static uint8_t tries; static uint16_t lpt_port; -static int power_down = 0; void pc87306_gpio_remove(); void pc87306_gpio_init(); void pc87306_gpio_write(uint16_t port, uint8_t val, void *priv) { - if (port & 1) - { - return; - } pc87306_gpio[port & 1] = val; } uint8_t uart_int1() { /* 0: IRQ3, 1: IRQ4 */ - return ((pc87306_regs[0x1C] >> 2) & 1) ? 3 : 4; + return ((pc87306_regs[0x1C] >> 2) & 1) ? 4 : 3; } uint8_t uart_int2() { - return ((pc87306_regs[0x1C] >> 6) & 1) ? 3 : 4; + /* 0: IRQ3, 1: IRQ4 */ + return ((pc87306_regs[0x1C] >> 6) & 1) ? 4 : 3; } uint8_t uart1_int() { uint8_t temp; - temp = ((pc87306_regs[1] >> 2) & 1) ? 3 : 4; /* 0 = IRQ 4, 1 = IRQ 3 */ - // pclog("UART 1 set to IRQ %i\n", (pc87306_regs[0x1C] & 1) ? uart_int1() : temp); + temp = ((pc87306_regs[1] >> 2) & 1) ? 3 : 4; /* 0 = COM1 (IRQ 4), 1 = COM2 (IRQ 3), 2 = COM3 (IRQ 4), 3 = COM4 (IRQ 3) */ return (pc87306_regs[0x1C] & 1) ? uart_int1() : temp; } uint8_t uart2_int() { uint8_t temp; - temp = ((pc87306_regs[1] >> 4) & 1) ? 3 : 4; /* 0 = IRQ 4, 1 = IRQ 3 */ - // pclog("UART 2 set to IRQ %i\n", (pc87306_regs[0x1C] & 1) ? uart_int2() : temp); + temp = ((pc87306_regs[1] >> 4) & 1) ? 3 : 4; /* 0 = COM1 (IRQ 4), 1 = COM2 (IRQ 3), 2 = COM3 (IRQ 4), 3 = COM4 (IRQ 3) */ return (pc87306_regs[0x1C] & 1) ? uart_int2() : temp; } void lpt1_handler() { int temp; - if (pc87306_regs[0x1B] & 0x10) + temp = pc87306_regs[0x01] & 3; + switch (temp) { - temp = (pc87306_regs[0x1B] & 0x20) >> 5; - if (temp) - { + case 0: lpt_port = 0x378; - } - else - { + break; + case 1: + if (pc87306_regs[0x1B] & 0x40) + { + lpt_port = ((uint16_t) pc87306_regs[0x19]) << 2; + } + else + { + lpt_port = 0x3bc; + } + break; + case 2: lpt_port = 0x278; - } - } - else - { - temp = pc87306_regs[0x01] & 3; - switch (temp) - { - case 0: lpt_port = 0x378; - case 1: lpt_port = 0x3bc; - case 2: lpt_port = 0x278; - } + break; } lpt1_init(lpt_port); - pc87306_regs[0x19] = lpt_port >> 2; } void serial1_handler() @@ -98,24 +98,24 @@ void serial1_handler() temp = (pc87306_regs[1] >> 2) & 3; switch (temp) { - case 0: serial1_set(0x3f8, uart1_int()); break; - case 1: serial1_set(0x2f8, uart1_int()); break; + case 0: serial_setup(1, SERIAL1_ADDR, uart1_int()); break; + case 1: serial_setup(1, SERIAL2_ADDR, uart1_int()); break; case 2: switch ((pc87306_regs[1] >> 6) & 3) { - case 0: serial1_set(0x3e8, uart1_int()); break; - case 1: serial1_set(0x338, uart1_int()); break; - case 2: serial1_set(0x2e8, uart1_int()); break; - case 3: serial1_set(0x220, uart1_int()); break; + case 0: serial_setup(1, 0x3e8, uart1_int()); break; + case 1: serial_setup(1, 0x338, uart1_int()); break; + case 2: serial_setup(1, 0x2e8, uart1_int()); break; + case 3: serial_setup(1, 0x220, uart1_int()); break; } break; case 3: switch ((pc87306_regs[1] >> 6) & 3) { - case 0: serial1_set(0x2e8, uart1_int()); break; - case 1: serial1_set(0x238, uart1_int()); break; - case 2: serial1_set(0x2e0, uart1_int()); break; - case 3: serial1_set(0x228, uart1_int()); break; + case 0: serial_setup(1, 0x2e8, uart1_int()); break; + case 1: serial_setup(1, 0x238, uart1_int()); break; + case 2: serial_setup(1, 0x2e0, uart1_int()); break; + case 3: serial_setup(1, 0x228, uart1_int()); break; } break; } @@ -127,24 +127,24 @@ void serial2_handler() temp = (pc87306_regs[1] >> 4) & 3; switch (temp) { - case 0: serial2_set(0x3f8, uart2_int()); break; - case 1: serial2_set(0x2f8, uart2_int()); break; + case 0: serial_setup(2, SERIAL1_ADDR, uart2_int()); break; + case 1: serial_setup(2, SERIAL2_ADDR, uart2_int()); break; case 2: switch ((pc87306_regs[1] >> 6) & 3) { - case 0: serial2_set(0x3e8, uart2_int()); break; - case 1: serial2_set(0x338, uart2_int()); break; - case 2: serial2_set(0x2e8, uart2_int()); break; - case 3: serial2_set(0x220, uart2_int()); break; + case 0: serial_setup(2, 0x3e8, uart2_int()); break; + case 1: serial_setup(2, 0x338, uart2_int()); break; + case 2: serial_setup(2, 0x2e8, uart2_int()); break; + case 3: serial_setup(2, 0x220, uart2_int()); break; } break; case 3: switch ((pc87306_regs[1] >> 6) & 3) { - case 0: serial2_set(0x2e8, uart2_int()); break; - case 1: serial2_set(0x238, uart2_int()); break; - case 2: serial2_set(0x2e0, uart2_int()); break; - case 3: serial2_set(0x228, uart2_int()); break; + case 0: serial_setup(2, 0x2e8, uart2_int()); break; + case 1: serial_setup(2, 0x238, uart2_int()); break; + case 2: serial_setup(2, 0x2e0, uart2_int()); break; + case 3: serial_setup(2, 0x228, uart2_int()); break; } break; } @@ -153,15 +153,16 @@ void serial2_handler() void pc87306_write(uint16_t port, uint8_t val, void *priv) { uint8_t index; - index = (port & 1) ? 0 : 1; - int temp; uint8_t valxor; - // pclog("pc87306_write : port=%04x reg %02X = %02X locked=%i\n", port, pc87306_curreg, val, pc87306_locked); +#if 0 + uint16_t or_value; +#endif + + index = (port & 1) ? 0 : 1; if (index) { pc87306_curreg = val & 0x1f; - // pclog("Register set to: %02X\n", val); tries = 0; return; } @@ -169,15 +170,29 @@ void pc87306_write(uint16_t port, uint8_t val, void *priv) { if (tries) { - if (pc87306_curreg <= 28) valxor = val ^ pc87306_regs[pc87306_curreg]; - if (pc87306_curreg == 0xF) pc87306_gpio_remove(); - if ((pc87306_curreg <= 28) && (pc87306_curreg != 8)) + if ((pc87306_curreg == 0) && (val == 8)) { - pc87306_regs[pc87306_curreg] = val; - // pclog("Register %02X set to: %02X (was: %02X)\n", pc87306_curreg, val, pc87306_regs[pc87306_curreg]); + val = 0x4b; } + if (pc87306_curreg <= 28) valxor = val ^ pc87306_regs[pc87306_curreg]; tries = 0; - if ((pc87306_curreg <= 28) && (pc87306_curreg != 8)) goto process_value; + if ((pc87306_curreg == 0x19) && !(pc87306_regs[0x1B] & 0x40)) + { + return; + } + if ((pc87306_curreg <= 28) && (pc87306_curreg != 8)/* && (pc87306_curreg != 0x18)*/) + { + if (pc87306_curreg == 0) + { + val &= 0x5f; + } + if (((pc87306_curreg == 0x0F) || (pc87306_curreg == 0x12)) && valxor) + { + pc87306_gpio_remove(); + } + pc87306_regs[pc87306_curreg] = val; + goto process_value; + } } else { @@ -194,15 +209,15 @@ process_value: if (valxor & 1) { lpt1_remove(); - } - if ((valxor & 1) && (val & 1)) - { - lpt1_handler(); + if (val & 1) + { + lpt1_handler(); + } } if (valxor & 2) { - serial1_remove(); + serial_remove(1); if (val & 2) { serial1_handler(); @@ -210,16 +225,44 @@ process_value: } if (valxor & 4) { - serial2_remove(); + serial_remove(2); if (val & 4) { serial2_handler(); } } + if (valxor & 0x28) + { + fdc_remove(); + if (val & 8) + { + fdc_set_base((val & 0x20) ? 0x370 : 0x3f0, 0); + } + } + if (valxor & 0xc0) + { +#if 0 + ide_pri_disable(); + if (val & 0x80) + { + or_value = 0; + } + else + { + or_value = 0x80; + } + ide_set_base(0, 0x170 | or_value); + ide_set_side(0, 0x376 | or_value); + if (val & 0x40) + { + ide_pri_enable_ex(); + } +#endif + } break; case 1: - if (valxor & 1) + if (valxor & 3) { lpt1_remove(); if (pc87306_regs[0] & 1) @@ -230,59 +273,113 @@ process_value: if (valxor & 0xcc) { - serial1_remove(); - if (pc87306_regs[0] & 2) { serial1_handler(); } + else + { + serial_remove(1); + } } if (valxor & 0xf0) { - serial2_remove(); - if (pc87306_regs[0] & 4) { serial2_handler(); } + else + { + serial_remove(2); + } } break; case 2: - lpt1_remove(); - serial1_remove(); - serial2_remove(); - if (val & 1) + if (valxor & 1) { - pc87306_regs[0] &= 0xb0; - } - else - { - lpt1_handler(); - serial1_handler(); - // serial2_handler(); - pc87306_regs[0] |= 0x4b; + if (val & 1) + { + lpt1_remove(); + serial_remove(1); + serial_remove(2); + fdc_remove(); + } + else + { + if (pc87306_regs[0] & 1) + { + lpt1_handler(); + } + if (pc87306_regs[0] & 2) + { + serial1_handler(); + } + if (pc87306_regs[0] & 4) + { + serial2_handler(); + } + if (pc87306_regs[0] & 8) + { + fdc_set_base((pc87306_regs[0] & 0x20) ? 0x370 : 0x3f0, 0); + } + } } break; case 9: - // pclog("Setting DENSEL polarity to: %i (before: %i)\n", (val & 0x40 ? 1 : 0), fdc_get_densel_polarity()); - fdc_update_enh_mode((val & 4) ? 1 : 0); - fdc_update_densel_polarity((val & 0x40) ? 1 : 0); + if (valxor & 0x44) + { + fdc_update_enh_mode((val & 4) ? 1 : 0); + fdc_update_densel_polarity((val & 0x40) ? 1 : 0); + } break; case 0xF: - pc87306_gpio_init(); - break; - case 0x1C: - // if (valxor & 0x25) if (valxor) { - serial1_remove(); - serial2_remove(); + pc87306_gpio_init(); + } + break; + case 0x12: + if (valxor & 0x30) + { + pc87306_gpio_init(); + } + break; + case 0x19: + if (valxor) + { + lpt1_remove(); + if (pc87306_regs[0] & 1) + { + lpt1_handler(); + } + } + break; + case 0x1B: + if (valxor & 0x40) + { + lpt1_remove(); + if (!(val & 0x40)) + { + pc87306_regs[0x19] = 0xEF; + } + if (pc87306_regs[0] & 1) + { + lpt1_handler(); + } + } + break; + case 0x1C: + if (valxor) + { if (pc87306_regs[0] & 2) { serial1_handler(); } - if (pc87306_regs[0] & 4) serial2_handler(); + if (pc87306_regs[0] & 4) + { + serial2_handler(); + } } break; } @@ -290,16 +387,11 @@ process_value: uint8_t pc87306_gpio_read(uint16_t port, void *priv) { - if (port & 1) - { - return 0xfb; /* Bit 2 clear, since we don't emulate the on-board audio. */ - } return pc87306_gpio[port & 1]; } uint8_t pc87306_read(uint16_t port, void *priv) { - // pclog("pc87306_read : port=%04x reg %02X locked=%i\n", port, pc87306_curreg, pc87306_locked); uint8_t index; index = (port & 1) ? 0 : 1; @@ -307,29 +399,20 @@ uint8_t pc87306_read(uint16_t port, void *priv) if (index) { - // pclog("PC87306: Read value %02X at the index register\n", pc87306_curreg & 0x1f); return pc87306_curreg & 0x1f; } else { if (pc87306_curreg >= 28) { - // pclog("PC87306: Read invalid at data register, index %02X\n", pc87306_curreg); return 0xff; } else if (pc87306_curreg == 8) { - // pclog("PC87306: Read ID at data register, index 08\n"); return 0x70; } - else if (pc87306_curreg == 5) - { - // pclog("PC87306: Read value %02X at data register, index 05\n", pc87306_regs[pc87306_curreg] | 4); - return pc87306_regs[pc87306_curreg] | 4; - } else { - // pclog("PC87306: Read value %02X at data register, index %02X\n", pc87306_regs[pc87306_curreg], pc87306_curreg); return pc87306_regs[pc87306_curreg]; } } @@ -342,27 +425,31 @@ void pc87306_gpio_remove() void pc87306_gpio_init() { - io_sethandler(pc87306_regs[0xF] << 2, 0x0002, pc87306_gpio_read, NULL, NULL, pc87306_gpio_write, NULL, NULL, NULL); + if ((pc87306_regs[0x12]) & 0x10) + { + io_sethandler(pc87306_regs[0xF] << 2, 0x0001, pc87306_gpio_read, NULL, NULL, pc87306_gpio_write, NULL, NULL, NULL); + } + + if ((pc87306_regs[0x12]) & 0x20) + { + io_sethandler((pc87306_regs[0xF] << 2) + 1, 0x0001, pc87306_gpio_read, NULL, NULL, pc87306_gpio_write, NULL, NULL, NULL); + } } -void pc87306_init() +void pc87306_reset(void) { memset(pc87306_regs, 0, 29); - lpt2_remove(); - // pc87306_regs[0] = 0xF; pc87306_regs[0] = 0x4B; - // pc87306_regs[1] = 0x11; pc87306_regs[1] = 0x01; - pc87306_regs[3] = 2; - pc87306_regs[5] = 0xD; + pc87306_regs[3] = 0x01; + pc87306_regs[5] = 0x0D; pc87306_regs[8] = 0x70; - pc87306_regs[9] = 0xFF; + pc87306_regs[9] = 0xC0; + pc87306_regs[0xB] = 0x80; pc87306_regs[0xF] = 0x1E; pc87306_regs[0x12] = 0x30; - pc87306_regs[0x19] = 0xDE; - pc87306_regs[0x1B] = 0x10; - pc87306_regs[0x1C] = 0; + pc87306_regs[0x19] = 0xEF; /* 0 = 360 rpm @ 500 kbps for 3.5" 1 = Default, 300 rpm @ 500,300,250,1000 kbps for 3.5" @@ -371,6 +458,23 @@ void pc87306_init() fdc_update_enh_mode(0); fdc_update_densel_polarity(1); fdc_update_max_track(85); + fdc_remove(); + fdc_set_base(0x3f0, 0); fdd_swap = 0; - io_sethandler(0x02e, 0x0002, pc87306_read, NULL, NULL, pc87306_write, NULL, NULL, NULL); + serial_remove(1); + serial_remove(2); + serial1_handler(); + serial2_handler(); + pc87306_gpio_init(); +} + +void pc87306_init() +{ + lpt2_remove(); + + pc87306_reset(); + + io_sethandler(0x02e, 0x0002, pc87306_read, NULL, NULL, pc87306_write, NULL, NULL, NULL); + + pci_reset_handler.super_io_reset = pc87306_reset; } diff --git a/src/pc87306.h b/src/pc87306.h index 0f48f3d97..d1891fdd8 100644 --- a/src/pc87306.h +++ b/src/pc87306.h @@ -1,4 +1,18 @@ -/* Copyright holders: Tenshi - see COPYING for more details -*/ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Emulation of the National Semiconductors PC87306 Super I/O + * chip. + * + * Version: @(#)pc87306.h 1.0.0 2017/05/30 + * + * Author: Miran Grca, + * Copyright 2016-2017 Miran Grca. + */ + extern void pc87306_init(); diff --git a/src/pci.c b/src/pci.c index 7a2b3cbd0..397442c4c 100644 --- a/src/pci.c +++ b/src/pci.c @@ -1,19 +1,20 @@ -/* Copyright holders: Sarah Walker - see COPYING for more details -*/ -#include - #include "ibm.h" #include "io.h" #include "mem.h" +#include "pic.h" #include "pci.h" void (*pci_card_write[32])(int func, int addr, uint8_t val, void *priv); uint8_t (*pci_card_read[32])(int func, int addr, void *priv); void *pci_priv[32]; -static uint8_t pci_index, pci_func, pci_card, pci_bus, pci_enable, pci_key; -static int pci_min_card, pci_max_card; +static int pci_irq_routing[32]; +/* static int pci_irq_active[32]; */ +static int pci_irqs[4]; +static int pci_card_valid[32]; +static int pci_irq_hold[16]; + +static int pci_index, pci_func, pci_card, pci_bus, pci_enable, pci_key; int pci_burst_time, pci_nonburst_time; void pci_cf8_write(uint16_t port, uint32_t val, void *p) @@ -23,7 +24,6 @@ void pci_cf8_write(uint16_t port, uint32_t val, void *p) pci_card = (val >> 11) & 31; pci_bus = (val >> 16) & 0xff; pci_enable = (val >> 31) & 1; - // pclog("PCI card selected: %i\n", pci_card); } uint32_t pci_cf8_read(uint16_t port, void *p) @@ -33,15 +33,12 @@ uint32_t pci_cf8_read(uint16_t port, void *p) void pci_write(uint16_t port, uint8_t val, void *priv) { - // pclog("pci_write: port=%04x val=%02x %08x:%08x\n", port, val, cs, cpu_state.pc); switch (port) { case 0xcfc: case 0xcfd: case 0xcfe: case 0xcff: if (!pci_enable) return; - // pclog("PCI write bus %i card %i func %i index %02X val %02X %04X:%04X\n", pci_bus, pci_card, pci_func, pci_index | (port & 3), val, CS, cpu_state.pc); - if (!pci_bus && pci_card_write[pci_card]) pci_card_write[pci_card](pci_func, pci_index | (port & 3), val, pci_priv[pci_card]); @@ -51,20 +48,54 @@ void pci_write(uint16_t port, uint8_t val, void *priv) uint8_t pci_read(uint16_t port, void *priv) { - // pclog("pci_read: port=%04x %08x:%08x\n", port, cs, cpu_state.pc); switch (port) { case 0xcfc: case 0xcfd: case 0xcfe: case 0xcff: if (!pci_enable) return 0xff; - // pclog("PCI read bus %i card %i func %i index %02X\n", pci_bus, pci_card, pci_func, pci_index | (port & 3)); - if (!pci_bus && pci_card_read[pci_card]) return pci_card_read[pci_card](pci_func, pci_index | (port & 3), pci_priv[pci_card]); return 0xff; } + return 0xff; +} + +uint8_t elcr[2] = { 0, 0 }; + +void elcr_write(uint16_t port, uint8_t val, void *priv) +{ + /* pclog("ELCR%i: WRITE %02X\n", port & 1, val); */ + elcr[port & 1] = val; + + /* printf("ELCR %i: %c %c %c %c %c %c %c %c\n", port & 1, (val & 1) ? 'L' : 'E', (val & 2) ? 'L' : 'E', (val & 4) ? 'L' : 'E', (val & 8) ? 'L' : 'E', (val & 0x10) ? 'L' : 'E', (val & 0x20) ? 'L' : 'E', (val & 0x40) ? 'L' : 'E', (val & 0x80) ? 'L' : 'E'); */ +} + +uint8_t elcr_read(uint16_t port, void *priv) +{ + /* pclog("ELCR%i: READ %02X\n", port & 1, elcr[port & 1]); */ + return elcr[port & 1]; +} + +void elcr_reset(void) +{ + int i = 0; + + pic_reset(); + elcr[0] = elcr[1] = 0; + +#if 0 + for (i = 0; i < 32; i++) + { + pci_irq_active[i] = 0; + } +#endif + + for (i = 0; i < 16; i++) + { + pci_irq_hold[i] = 0; + } } void pci_type2_write(uint16_t port, uint8_t val, void *priv); @@ -72,7 +103,6 @@ uint8_t pci_type2_read(uint16_t port, void *priv); void pci_type2_write(uint16_t port, uint8_t val, void *priv) { -// pclog("pci_type2_write: port=%04x val=%02x %08x:%08x\n", port, val, cs, pc); if (port == 0xcf8) { pci_func = (val >> 1) & 7; @@ -91,8 +121,6 @@ void pci_type2_write(uint16_t port, uint8_t val, void *priv) pci_card = (port >> 8) & 0xf; pci_index = port & 0xff; - // pclog("PCI write bus %i card %i func %i index %02X val %02X %04X:%04X\n", pci_bus, pci_card, pci_func, pci_index | (port & 3), val, CS, cpu_state.pc); - if (!pci_bus && pci_card_write[pci_card]) pci_card_write[pci_card](pci_func, pci_index | (port & 3), val, pci_priv[pci_card]); } @@ -100,7 +128,6 @@ void pci_type2_write(uint16_t port, uint8_t val, void *priv) uint8_t pci_type2_read(uint16_t port, void *priv) { -// pclog("pci_type2_read: port=%04x %08x:%08x\n", port, cs, pc); if (port == 0xcf8) { return pci_key | (pci_func << 1); @@ -114,19 +141,89 @@ uint8_t pci_type2_read(uint16_t port, void *priv) pci_card = (port >> 8) & 0xf; pci_index = port & 0xff; - // pclog("PCI read bus %i card %i func %i index %02X %04X:%04X\n", pci_bus, pci_card, pci_func, pci_index | (port & 3), CS, cpu_state.pc); - if (!pci_bus && pci_card_write[pci_card]) return pci_card_read[pci_card](pci_func, pci_index | (port & 3), pci_priv[pci_card]); } return 0xff; } - -void pci_init(int type, int min_card, int max_card) + +void pci_set_irq_routing(int pci_int, int irq) +{ + pci_irqs[pci_int - 1] = irq; +} + +void pci_set_card_routing(int card, int pci_int) +{ + pci_irq_routing[card] = pci_int; +} + +int pci_irq_is_level(int irq) +{ + int real_irq = irq & 7; + /* int irq_elcr = 0; */ + + if (irq > 7) + { + return !!(elcr[1] & (1 << real_irq)); + } + else + { + return !!(elcr[0] & (1 << real_irq)); + } +} + +void pci_issue_irq(int irq) +{ + if (pci_irq_is_level(irq)) + { + picintlevel(1 << irq); + } + else + { + picint(1 << irq); + } +} + +void pci_set_irq(int card, int pci_int) +{ + int irq = ((pci_int - PCI_INTA) + (pci_irq_routing[card] - PCI_INTA)) & 3; + + if (pci_irq_routing[card]) + { + if (pci_irqs[irq] != PCI_IRQ_DISABLED/* && !pci_irq_active[card] */) + pci_issue_irq(pci_irqs[irq]); + /* pci_irq_active[card] = 1; */ + /* If the IRQ is set to edge, there is no need to hold it. */ + if (!pci_irq_is_level(pci_irqs[irq])) + { + pci_irq_hold[pci_irqs[irq]] |= (1 << card); + } + } +} + +void pci_clear_irq(int card, int pci_int) +{ + int irq = ((pci_int - PCI_INTA) + (pci_irq_routing[card] - PCI_INTA)) & 3; + + /* Do not clear the interrupt until we're the last card being serviced. */ + if (pci_irq_routing[card]) + { + pci_irq_hold[pci_irqs[irq]] &= ~(1 << card); + if (pci_irqs[irq] != PCI_IRQ_DISABLED/* && pci_irq_active[card]*/ && !pci_irq_hold[pci_irqs[irq]]) + picintc(1 << pci_irqs[irq]); + /* pci_irq_active[card] = 0; */ + } +} + +void pci_init(int type) { int c; PCI = 1; + + elcr_reset(); + + io_sethandler(0x04d0, 0x0002, elcr_read, NULL, NULL, elcr_write, NULL, NULL, NULL); if (type == PCI_CONFIG_TYPE_1) { @@ -140,10 +237,22 @@ void pci_init(int type, int min_card, int max_card) } for (c = 0; c < 32; c++) - pci_card_read[c] = pci_card_write[c] = pci_priv[c] = NULL; + { + pci_card_read[c] = NULL; + pci_card_write[c] = NULL; + pci_priv[c] = NULL; + pci_irq_routing[c] = 0; + /* pci_irq_active[c] = 0; */ + pci_card_valid[c] = 0; + } - pci_min_card = min_card; - pci_max_card = max_card; + for (c = 0; c < 4; c++) + pci_irqs[c] = PCI_IRQ_DISABLED; +} + +void pci_slot(int card) +{ + pci_card_valid[card] = 1; } void pci_add_specific(int card, uint8_t (*read)(int func, int addr, void *priv), void (*write)(int func, int addr, uint8_t val, void *priv), void *priv) @@ -153,19 +262,20 @@ void pci_add_specific(int card, uint8_t (*read)(int func, int addr, void *priv), pci_priv[card] = priv; } -void pci_add(uint8_t (*read)(int func, int addr, void *priv), void (*write)(int func, int addr, uint8_t val, void *priv), void *priv) +int pci_add(uint8_t (*read)(int func, int addr, void *priv), void (*write)(int func, int addr, uint8_t val, void *priv), void *priv) { int c; - for (c = pci_min_card; c <= pci_max_card; c++) + for (c = 0; c < 32; c++) { - if (!pci_card_read[c] && !pci_card_write[c]) + if (pci_card_valid[c] && !pci_card_read[c] && !pci_card_write[c]) { pci_card_read[c] = read; pci_card_write[c] = write; pci_priv[c] = priv; - // pclog("PCI device added to card: %i\n", c); - return; + return c; } } + + return -1; } diff --git a/src/pci.h b/src/pci.h index 6c6782e23..f1cecc952 100644 --- a/src/pci.h +++ b/src/pci.h @@ -1,9 +1,13 @@ -/* Copyright holders: Sarah Walker - see COPYING for more details -*/ -void pci_init(int type, int min_card, int max_card); +void elcr_reset(void); + +void pci_init(int type); +void pci_slot(int card); void pci_add_specific(int card, uint8_t (*read)(int func, int addr, void *priv), void (*write)(int func, int addr, uint8_t val, void *priv), void *priv); -void pci_add(uint8_t (*read)(int func, int addr, void *priv), void (*write)(int func, int addr, uint8_t val, void *priv), void *priv); +int pci_add(uint8_t (*read)(int func, int addr, void *priv), void (*write)(int func, int addr, uint8_t val, void *priv), void *priv); +void pci_set_irq_routing(int card, int irq); +void pci_set_card_routing(int card, int pci_int); +void pci_set_irq(int card, int pci_int); +void pci_clear_irq(int card, int pci_int); #define PCI_REG_COMMAND 0x04 @@ -13,4 +17,11 @@ void pci_add(uint8_t (*read)(int func, int addr, void *priv), void (*write)(int #define PCI_CONFIG_TYPE_1 1 #define PCI_CONFIG_TYPE_2 2 +#define PCI_INTA 1 +#define PCI_INTB 2 +#define PCI_INTC 3 +#define PCI_INTD 4 + +#define PCI_IRQ_DISABLED -1 + extern int pci_burst_time, pci_nonburst_time; diff --git a/src/pic.c b/src/pic.c index 96cca37ac..7c20125e9 100644 --- a/src/pic.c +++ b/src/pic.c @@ -1,12 +1,15 @@ #include "ibm.h" #include "io.h" #include "pic.h" +#include "pit.h" int output; int intclear; int keywaiting=0; int pic_intpending; +PIC pic, pic2; + void pic_updatepending() { uint16_t temp_pending = 0; @@ -56,7 +59,6 @@ void pic_update_mask(uint8_t *mask, uint8_t ins) if (ins & (1 << c)) { *mask = 0xff << c; - // pclog("Mask is: %02X\n", *mask); return; } } @@ -88,21 +90,16 @@ static void pic_autoeoi() void pic_write(uint16_t addr, uint8_t val, void *priv) { int c; - // if (addr&1) pclog("Write PIC %04X %02X %04X(%06X):%04X\n",addr,val,CS,cs,cpu_state.pc); if (addr&1) { - // pclog("PIC ICW is: %i\n", pic.icw); switch (pic.icw) { case 0: /*OCW1*/ -// printf("Write mask %02X %04X:%04X\n",val,CS,pc); pic.mask=val; pic_updatepending(); break; case 1: /*ICW2*/ pic.vector=val&0xF8; - // printf("PIC vector now %02X\n",pic.vector); - // output=1; if (pic.icw1&2) pic.icw=3; else pic.icw=2; break; @@ -112,7 +109,6 @@ void pic_write(uint16_t addr, uint8_t val, void *priv) break; case 3: /*ICW4*/ pic.icw4 = val; - // pclog("ICW4 = %02x\n", val); pic.icw=0; break; } @@ -121,7 +117,6 @@ void pic_write(uint16_t addr, uint8_t val, void *priv) { if (val&16) /*ICW1*/ { - // pclog("ICW1 = %02x\n", val); pic.mask = 0; pic.mask2=0; pic.icw=1; @@ -131,10 +126,8 @@ void pic_write(uint16_t addr, uint8_t val, void *priv) } else if (!(val&8)) /*OCW2*/ { -// printf("Clear ints - %02X %02X\n",pic.ins,val); if ((val&0xE0)==0x60) { -// pclog("Specific EOI - %02X %i\n",pic.ins,1<<(val&7)); pic.ins&=~(1<<(val&7)); pic_update_mask(&pic.mask2, pic.ins); if (AT) @@ -142,8 +135,6 @@ void pic_write(uint16_t addr, uint8_t val, void *priv) if ((val&7) == 2 && (pic2.pend&~pic2.mask)&~pic2.mask2) pic.pend |= (1 << 2); } -// pic.pend&=(1<<(val&7)); -// if ((val&7)==1) pollkeywaiting(); pic_updatepending(); } else @@ -164,10 +155,8 @@ void pic_write(uint16_t addr, uint8_t val, void *priv) if (c==1 && keywaiting) { intclear&=~1; -// pollkeywaiting(); } pic_updatepending(); -// pclog("Generic EOI - Cleared int %i\n",c); return; } } @@ -175,9 +164,8 @@ void pic_write(uint16_t addr, uint8_t val, void *priv) } else /*OCW3*/ { - // if (val&4) fatal("PIC1 write OCW3 4 %02X\n",val); if (val&2) pic.read=(val&1); - if (val&0x40) { } //fatal("PIC 1 write OCW3 40 %02X\n",val); + if (val&0x40) { } } } } @@ -186,7 +174,6 @@ uint8_t pic_read(uint16_t addr, void *priv) { if (addr&1) { /*pclog("Read PIC mask %02X\n",pic.mask);*/ return pic.mask; } if (pic.read) { /*pclog("Read PIC ins %02X\n",pic.ins);*/ return pic.ins | (pic2.ins ? 4 : 0); } -// pclog("Read PIC pend %02X %08X\n",pic.pend,EDX); return pic.pend; } @@ -215,19 +202,16 @@ static void pic2_autoeoi() void pic2_write(uint16_t addr, uint8_t val, void *priv) { int c; -// pclog("Write PIC2 %04X %02X %04X:%04X %i\n",addr,val,CS,pc,ins); if (addr&1) { switch (pic2.icw) { case 0: /*OCW1*/ -// printf("PIC2 Write mask %02X %04X:%04X\n",val,CS,pc); pic2.mask=val; pic_updatepending(); break; case 1: /*ICW2*/ pic2.vector=val&0xF8; -// pclog("PIC2 vector %02X\n", val & 0xf8); if (pic2.icw1&2) pic2.icw=3; else pic2.icw=2; break; @@ -301,18 +285,14 @@ void clearpic() { pic.pend=pic.ins=0; pic_updatepending(); -// pclog("Clear PIC\n"); } int pic_current[16]; void picint(uint16_t num) { - int old_pend = pic_intpending; if (AT && (num == (1 << 2))) num = 1 << 9; -// pclog("picint : %04X\n", num); -// if (num == 0x10) pclog("PICINT 10\n"); if (num>0xFF) { if (!AT) @@ -348,7 +328,6 @@ void picintlevel(uint16_t num) c = 9; num = 1 << 9; } -// pclog("INTLEVEL %04X %i\n", num, c); if (!pic_current[c]) { pic_current[c]=1; @@ -379,7 +358,6 @@ void picintc(uint16_t num) c = 9; num = 1 << 9; } -// pclog("INTC %04X %i\n", num, c); pic_current[c]=0; if (num > 0xff) @@ -411,7 +389,10 @@ uint8_t picinterrupt() pic.pend &= ~(1 << c); pic.ins |= (1 << c); pic_update_mask(&pic.mask2, pic.ins); + pic_updatepending(); + if (!c) + pit_set_gate(&pit2, 0, 0); if (pic.icw4 & 0x02) pic_autoeoi(); @@ -445,7 +426,6 @@ uint8_t picinterrupt() pic2.ins |= (1 << c); pic_update_mask(&pic2.mask2, pic2.ins); - // pic.pend &= ~(1 << c); pic.ins |= (1 << 2); /*Cascade IRQ*/ pic_update_mask(&pic.mask2, pic.ins); diff --git a/src/pic.h b/src/pic.h index 419315c5f..74660941a 100644 --- a/src/pic.h +++ b/src/pic.h @@ -7,3 +7,4 @@ void picintlevel(uint16_t num); void picintc(uint16_t num); uint8_t picinterrupt(); void picclear(int num); +void dumppic(); diff --git a/src/piix.c b/src/piix.c index e1e41814c..584f1ccc3 100644 --- a/src/piix.c +++ b/src/piix.c @@ -1,6 +1,21 @@ -/* Copyright holders: Sarah Walker, Tenshi - see COPYING for more details -*/ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * Emulation of the Intel PIIX and PIIX3 Xcelerators. + * + * Emulation core dispatcher. + * + * Version: @(#)piix.c 1.0.0 2017/05/30 + * + * Author: Sarah Walker, + * Miran Grca, + * Copyright 2008-2017 Sarah Walker. + * Copyright 2016-2017 Miran Grca. + */ + /*PRD format : word 0 - base address @@ -9,6 +24,7 @@ #include #include "ibm.h" +#include "dma.h" #include "ide.h" #include "io.h" #include "mem.h" @@ -26,7 +42,7 @@ static uint8_t card_piix[256], card_piix_ide[256]; void piix_write(int func, int addr, uint8_t val, void *priv) { -// pclog("piix_write: func=%d addr=%02x val=%02x %04x:%08x\n", func, addr, val, CS, pc); + uint16_t old_base = (card_piix_ide[0x20] & 0xf0) | (card_piix_ide[0x21] << 8); if (func > 1) return; @@ -39,7 +55,6 @@ void piix_write(int func, int addr, uint8_t val, void *priv) break; case 0x07: card_piix_ide[0x07] = val & 0x3e; - // card_piix_ide[0x07] = (card_piix_ide[0x07] & ~0x38) | (val & 0x38); break; case 0x0d: card_piix_ide[0x0d] = val; @@ -83,20 +98,54 @@ void piix_write(int func, int addr, uint8_t val, void *priv) if (addr == 4 || (addr & ~3) == 0x20) /*Bus master base address*/ { uint16_t base = (card_piix_ide[0x20] & 0xf0) | (card_piix_ide[0x21] << 8); - io_removehandler(0, 0x10000, piix_bus_master_read, NULL, NULL, piix_bus_master_write, NULL, NULL, NULL); + io_removehandler(old_base, 0x10, piix_bus_master_read, NULL, NULL, piix_bus_master_write, NULL, NULL, NULL); if (card_piix_ide[0x04] & 1) - io_sethandler(base, 0x10, piix_bus_master_read, NULL, NULL, piix_bus_master_write, NULL, NULL, NULL); + { + io_sethandler(base, 0x10, piix_bus_master_read, NULL, NULL, piix_bus_master_write, NULL, NULL, NULL); + } } - // pclog("PIIX write %02X %02X\n", addr, val); } else { + /* pclog("PIIX writing value %02X to register %02X\n", val, addr); */ + if ((addr >= 0x0f) && (addr < 0x4c)) + return; + switch (addr) { case 0x00: case 0x01: case 0x02: case 0x03: case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0e: return; + + case 0x60: + pclog("Set IRQ routing: INT A -> %02X\n", val); + if (val & 0x80) + pci_set_irq_routing(PCI_INTA, PCI_IRQ_DISABLED); + else + pci_set_irq_routing(PCI_INTA, val & 0xf); + break; + case 0x61: + pclog("Set IRQ routing: INT B -> %02X\n", val); + if (val & 0x80) + pci_set_irq_routing(PCI_INTB, PCI_IRQ_DISABLED); + else + pci_set_irq_routing(PCI_INTB, val & 0xf); + break; + case 0x62: + pclog("Set IRQ routing: INT C -> %02X\n", val); + if (val & 0x80) + pci_set_irq_routing(PCI_INTC, PCI_IRQ_DISABLED); + else + pci_set_irq_routing(PCI_INTC, val & 0xf); + break; + case 0x63: + pclog("Set IRQ routing: INT D -> %02X\n", val); + if (val & 0x80) + pci_set_irq_routing(PCI_INTD, PCI_IRQ_DISABLED); + else + pci_set_irq_routing(PCI_INTD, val & 0xf); + break; } if (addr == 0x4C) { @@ -137,14 +186,11 @@ void piix_write(int func, int addr, uint8_t val, void *priv) uint8_t piix_read(int func, int addr, void *priv) { -// pclog("piix_read: func=%d addr=%02x %04x:%08x\n", func, addr, CS, pc); if (func > 1) return 0xff; if (func == 1) /*IDE*/ { - // pclog("PIIX IDE read %02X %02X\n", addr, card_piix_ide[addr]); - if (addr == 4) { return (card_piix_ide[addr] & 5) | 2; @@ -312,6 +358,8 @@ uint8_t piix_read(int func, int addr, void *priv) else return card_piix[addr]; } + + return 0; } struct @@ -330,13 +378,11 @@ static void piix_bus_master_next_addr(int channel) piix_busmaster[channel].count = (*(uint32_t *)(&ram[piix_busmaster[channel].ptr_cur + 4])) & 0xfffe; piix_busmaster[channel].eot = (*(uint32_t *)(&ram[piix_busmaster[channel].ptr_cur + 4])) >> 31; piix_busmaster[channel].ptr_cur += 8; -// pclog("New DMA settings on channel %i - Addr %08X Count %04X EOT %i\n", channel, piix_busmaster[channel].addr, piix_busmaster[channel].count, piix_busmaster[channel].eot); } void piix_bus_master_write(uint16_t port, uint8_t val, void *priv) { int channel = (port & 8) ? 1 : 0; -// pclog("PIIX Bus Master write %04X %02X %04x:%08x\n", port, val, CS, pc); switch (port & 7) { case 0: @@ -377,7 +423,6 @@ void piix_bus_master_write(uint16_t port, uint8_t val, void *priv) uint8_t piix_bus_master_read(uint16_t port, void *priv) { int channel = (port & 8) ? 1 : 0; -// pclog("PIIX Bus Master read %04X %04x:%08x\n", port, CS, pc); switch (port & 7) { case 0: @@ -396,23 +441,61 @@ uint8_t piix_bus_master_read(uint16_t port, void *priv) return 0xff; } -int piix_bus_master_sector_read(int channel, uint8_t *data) +int piix_bus_master_get_count(int channel) +{ + return piix_busmaster[channel].count; +} + +int piix_bus_master_get_eot(int channel) +{ + return piix_busmaster[channel].eot; +} + +int piix_bus_master_dma_read_ex(int channel, uint8_t *data) +{ + int transferred = 0; + + if (!(piix_busmaster[channel].status & 1)) + return 1; /*DMA disabled*/ + + mem_invalidate_range(piix_busmaster[channel].addr, piix_busmaster[channel].addr + piix_busmaster[channel].count - 1); + + memcpy(&ram[piix_busmaster[channel].addr], data, piix_busmaster[channel].count); + transferred += piix_busmaster[channel].count; + piix_busmaster[channel].addr += piix_busmaster[channel].count; + piix_busmaster[channel].addr %= (mem_size * 1024); + piix_busmaster[channel].count = 0; + + if (piix_busmaster[channel].eot) /*End of transfer?*/ + { + piix_busmaster[channel].status &= ~1; + return -1; + } + else + { + piix_bus_master_next_addr(channel); + } + return 0; +} + +int piix_bus_master_dma_read(int channel, uint8_t *data, int transfer_length) { int transferred = 0; if (!(piix_busmaster[channel].status & 1)) return 1; /*DMA disabled*/ - while (transferred < 512) + while (transferred < transfer_length) { - if (piix_busmaster[channel].count < (512 - transferred) && piix_busmaster[channel].eot) - fatal("DMA on channel %i - Read count less than 512! Addr %08X Count %04X EOT %i\n", channel, piix_busmaster[channel].addr, piix_busmaster[channel].count, piix_busmaster[channel].eot); + if ((piix_busmaster[channel].count < (transfer_length - transferred)) && piix_busmaster[channel].eot && (transfer_length == 512)) + { + fatal("DMA on channel %i - Read count less than %04X! Addr %08X Count %04X EOT %i\n", channel, transfer_length, piix_busmaster[channel].addr, piix_busmaster[channel].count, piix_busmaster[channel].eot); + } - mem_invalidate_range(piix_busmaster[channel].addr, piix_busmaster[channel].addr+511); + mem_invalidate_range(piix_busmaster[channel].addr, piix_busmaster[channel].addr + transfer_length - 1); - if (piix_busmaster[channel].count < (512 - transferred)) + if (piix_busmaster[channel].count < (transfer_length - transferred)) { -// pclog("Transferring smaller - %i bytes\n", piix_busmaster[channel].count); memcpy(&ram[piix_busmaster[channel].addr], data + transferred, piix_busmaster[channel].count); transferred += piix_busmaster[channel].count; piix_busmaster[channel].addr += piix_busmaster[channel].count; @@ -421,21 +504,16 @@ int piix_bus_master_sector_read(int channel, uint8_t *data) } else { -// pclog("Transferring larger - %i bytes\n", 512 - transferred); - memcpy(&ram[piix_busmaster[channel].addr], data + transferred, 512 - transferred); - piix_busmaster[channel].addr += (512 - transferred); - piix_busmaster[channel].count -= (512 - transferred); - transferred += (512 - transferred); + memcpy(&ram[piix_busmaster[channel].addr], data + transferred, transfer_length - transferred); + piix_busmaster[channel].addr += (transfer_length - transferred); + piix_busmaster[channel].count -= (transfer_length - transferred); + transferred += (transfer_length - transferred); } -// pclog("DMA on channel %i - Addr %08X Count %04X EOT %i\n", channel, piix_busmaster[channel].addr, piix_busmaster[channel].count, piix_busmaster[channel].eot); - if (!piix_busmaster[channel].count) { -// pclog("DMA on channel %i - block over\n", channel); if (piix_busmaster[channel].eot) /*End of transfer?*/ { -// pclog("DMA on channel %i - transfer over\n", channel); piix_busmaster[channel].status &= ~1; } else @@ -444,21 +522,23 @@ int piix_bus_master_sector_read(int channel, uint8_t *data) } return 0; } -int piix_bus_master_sector_write(int channel, uint8_t *data) + +int piix_bus_master_dma_write(int channel, uint8_t *data, int transfer_length) { int transferred = 0; - + if (!(piix_busmaster[channel].status & 1)) return 1; /*DMA disabled*/ - while (transferred < 512) + while (transferred < transfer_length) { - if (piix_busmaster[channel].count < (512 - transferred) && piix_busmaster[channel].eot) - fatal("DMA on channel %i - Write count less than 512! Addr %08X Count %04X EOT %i\n", channel, piix_busmaster[channel].addr, piix_busmaster[channel].count, piix_busmaster[channel].eot); + if ((piix_busmaster[channel].count < (transfer_length - transferred)) && piix_busmaster[channel].eot && (transfer_length == 512)) + { + fatal("DMA on channel %i - Write count less than %04X! Addr %08X Count %04X EOT %i\n", channel, transfer_length, piix_busmaster[channel].addr, piix_busmaster[channel].count, piix_busmaster[channel].eot); + } - if (piix_busmaster[channel].count < (512 - transferred)) + if (piix_busmaster[channel].count < (transfer_length - transferred)) { -// pclog("Transferring smaller - %i bytes\n", piix_busmaster[channel].count); memcpy(data + transferred, &ram[piix_busmaster[channel].addr], piix_busmaster[channel].count); transferred += piix_busmaster[channel].count; piix_busmaster[channel].addr += piix_busmaster[channel].count; @@ -467,21 +547,16 @@ int piix_bus_master_sector_write(int channel, uint8_t *data) } else { -// pclog("Transferring larger - %i bytes\n", 512 - transferred); - memcpy(data + transferred, &ram[piix_busmaster[channel].addr], 512 - transferred); - piix_busmaster[channel].addr += (512 - transferred); - piix_busmaster[channel].count -= (512 - transferred); - transferred += (512 - transferred); + memcpy(data + transferred, &ram[piix_busmaster[channel].addr], transfer_length - transferred); + piix_busmaster[channel].addr += (transfer_length - transferred); + piix_busmaster[channel].count -= (transfer_length - transferred); + transferred += (transfer_length - transferred); } -// pclog("DMA on channel %i - Addr %08X Count %04X EOT %i\n", channel, piix_busmaster[channel].addr, piix_busmaster[channel].count, piix_busmaster[channel].eot); - if (!piix_busmaster[channel].count) { -// pclog("DMA on channel %i - block over\n", channel); if (piix_busmaster[channel].eot) /*End of transfer?*/ { -// pclog("DMA on channel %i - transfer over\n", channel); piix_busmaster[channel].status &= ~1; } else @@ -496,15 +571,45 @@ void piix_bus_master_set_irq(int channel) piix_busmaster[channel].status |= 4; } -static int reset_reg = 0; +/* static int reset_reg = 0; -void piix_reset() +static uint8_t rc_read(uint16_t port, void *priv) +{ + return reset_reg & 0xfb; +} + +static void rc_write(uint16_t port, uint8_t val, void *priv) +{ + if (!(reset_reg & 4) && (val & 4)) + { + if (reset_reg & 2) + { + resetpchard(); + } + else + { + if (piix_type == 3) + { + piix3_reset(); + } + else + { + piix_reset(); + } + resetide(); + softresetx86(); + } + } + reset_reg = val; +} */ + +void piix_reset(void) { memset(card_piix, 0, 256); card_piix[0x00] = 0x86; card_piix[0x01] = 0x80; /*Intel*/ card_piix[0x02] = 0x2e; card_piix[0x03] = 0x12; /*82371FB (PIIX)*/ card_piix[0x04] = 0x07; card_piix[0x05] = 0x00; - card_piix[0x06] = 0x00; card_piix[0x07] = 0x02; + card_piix[0x06] = 0x80; card_piix[0x07] = 0x02; card_piix[0x08] = 0x00; /*A0 stepping*/ card_piix[0x09] = 0x00; card_piix[0x0a] = 0x01; card_piix[0x0b] = 0x06; card_piix[0x0e] = 0x80; /*Multi-function device*/ @@ -532,18 +637,17 @@ void piix_reset() card_piix_ide[0x0d] = 0x00; card_piix_ide[0x0e] = 0x00; card_piix_ide[0x20] = 0x01; card_piix_ide[0x21] = card_piix_ide[0x22] = card_piix_ide[0x23] = 0x00; /*Bus master interface base address*/ - card_piix_ide[0x3c] = 14; /* Default IRQ */ card_piix_ide[0x40] = card_piix_ide[0x41] = 0x00; card_piix_ide[0x42] = card_piix_ide[0x43] = 0x00; } -void piix3_reset() +void piix3_reset(void) { memset(card_piix, 0, 256); card_piix[0x00] = 0x86; card_piix[0x01] = 0x80; /*Intel*/ card_piix[0x02] = 0x00; card_piix[0x03] = 0x70; /*82371SB (PIIX3)*/ card_piix[0x04] = 0x07; card_piix[0x05] = 0x00; - card_piix[0x06] = 0x00; card_piix[0x07] = 0x02; + card_piix[0x06] = 0x80; card_piix[0x07] = 0x02; card_piix[0x08] = 0x00; /*A0 stepping*/ card_piix[0x09] = 0x00; card_piix[0x0a] = 0x01; card_piix[0x0b] = 0x06; card_piix[0x0e] = 0x80; /*Multi-function device*/ @@ -572,82 +676,59 @@ void piix3_reset() card_piix_ide[0x0d] = 0x00; card_piix_ide[0x0e] = 0x00; card_piix_ide[0x20] = 0x01; card_piix_ide[0x21] = card_piix_ide[0x22] = card_piix_ide[0x23] = 0x00; /*Bus master interface base address*/ - card_piix_ide[0x3c] = 14; /* Default IRQ */ card_piix_ide[0x40] = card_piix_ide[0x41] = 0x00; card_piix_ide[0x42] = card_piix_ide[0x43] = 0x00; card_piix_ide[0x44] = 0x00; } -static uint8_t rc_read(uint16_t port, void *priv) -{ - return reset_reg & 0xfb; -} - -static void rc_write(uint16_t port, uint8_t val, void *priv) -{ - if (!(reset_reg & 4) && (val & 4)) - { - if (reset_reg & 2) - { - // pclog("PIIX: Hard reset\n"); - resetpchard(); - } - else - { - // pclog("PIIX: Soft reset\n"); - if (piix_type == 3) - { - piix3_reset(); - } - else - { - piix_reset(); - } - resetide(); - softresetx86(); - } - } - reset_reg = val; -} - -void piix_init(int card) +void piix_init(int card, int pci_a, int pci_b, int pci_c, int pci_d) { pci_add_specific(card, piix_read, piix_write, NULL); piix_reset(); - reset_reg = 0; - piix_type = 1; - ide_set_bus_master(piix_bus_master_sector_read, piix_bus_master_sector_write, piix_bus_master_set_irq); + ide_set_bus_master(piix_bus_master_dma_read, piix_bus_master_dma_write, piix_bus_master_set_irq); - io_sethandler(0x0cf9, 0x0001, rc_read, NULL, NULL, rc_write, NULL, NULL, NULL); + trc_init(); port_92_reset(); port_92_add(); dma_alias_set(); + + pci_reset_handler.pci_set_reset = piix_reset; + + pci_set_card_routing(pci_a, PCI_INTA); + pci_set_card_routing(pci_b, PCI_INTB); + pci_set_card_routing(pci_c, PCI_INTC); + pci_set_card_routing(pci_d, PCI_INTD); } -void piix3_init(int card) +void piix3_init(int card, int pci_a, int pci_b, int pci_c, int pci_d) { pci_add_specific(card, piix_read, piix_write, NULL); piix3_reset(); - reset_reg = 0; - piix_type = 3; - ide_set_bus_master(piix_bus_master_sector_read, piix_bus_master_sector_write, piix_bus_master_set_irq); + ide_set_bus_master(piix_bus_master_dma_read, piix_bus_master_dma_write, piix_bus_master_set_irq); - io_sethandler(0x0cf9, 0x0001, rc_read, NULL, NULL, rc_write, NULL, NULL, NULL); + trc_init(); port_92_reset(); port_92_add(); dma_alias_set(); + + pci_reset_handler.pci_set_reset = piix3_reset; + + pci_set_card_routing(pci_a, PCI_INTA); + pci_set_card_routing(pci_b, PCI_INTB); + pci_set_card_routing(pci_c, PCI_INTC); + pci_set_card_routing(pci_d, PCI_INTD); } diff --git a/src/piix.h b/src/piix.h index 4953d500e..a922ff41e 100644 --- a/src/piix.h +++ b/src/piix.h @@ -1,5 +1,27 @@ -/* Copyright holders: Sarah Walker, Tenshi - see COPYING for more details -*/ -void piix_init(int card); -void piix3_init(int card); +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * Emulation of the Intel PIIX and PIIX3 Xcelerators. + * + * Emulation core dispatcher. + * + * Version: @(#)piix.h 1.0.0 2017/05/30 + * + * Author: Sarah Walker, + * Miran Grca, + * Copyright 2008-2017 Sarah Walker. + * Copyright 2016-2017 Miran Grca. + */ + +void piix_init(int card, int pci_a, int pci_b, int pci_c, int pci_d); +void piix3_init(int card, int pci_a, int pci_b, int pci_c, int pci_d); + +uint8_t piix_bus_master_read(uint16_t port, void *priv); +void piix_bus_master_write(uint16_t port, uint8_t val, void *priv); + +int piix_bus_master_get_count(int channel); + +int piix_bus_master_dma_read_ex(int channel, uint8_t *data); diff --git a/src/pit.c b/src/pit.c index b9804eefb..144630d5f 100644 --- a/src/pit.c +++ b/src/pit.c @@ -5,28 +5,34 @@ #include #include "ibm.h" - -#include "cpu.h" +#include "cpu/cpu.h" #include "dma.h" #include "io.h" #include "pic.h" #include "pit.h" +#include "device.h" #include "timer.h" -#include "video.h" #include "model.h" +#include "sound/snd_speaker.h" +#include "video/video.h" + + /*B0 to 40, two writes to 43, then two reads - value does not change!*/ /*B4 to 40, two writes to 43, then two reads - value _does_ change!*/ -//Tyrian writes 4300 or 17512 int displine; double PITCONST; float cpuclock; float isa_timing, bus_timing; +float CGACONST; +float MDACONST; +float VGACONST1,VGACONST2; +float RTCCONST; + int firsttime=1; void setpitclock(float clock) { -// printf("PIT clock %f\n",clock); cpuclock=clock; PITCONST=clock/1193182.0; CGACONST=(clock/(19687503.0/11.0)); @@ -36,32 +42,33 @@ void setpitclock(float clock) isa_timing = clock/8000000.0; bus_timing = clock/(double)cpu_busspeed; video_updatetiming(); -// pclog("PITCONST=%f CGACONST=%f\n", PITCONST, CGACONST); -// pclog("CPUMULTI=%g\n", ((14318184.0*(double)(1 << TIMER_SHIFT)) / (double)models[model].cpu[cpu_manufacturer].cpus[cpu].rspeed)); xt_cpu_multi = (int)((14318184.0*(double)(1 << TIMER_SHIFT)) / (double)models[model].cpu[cpu_manufacturer].cpus[cpu].rspeed); -// pclog("egacycles %i egacycles2 %i temp %f clock %f\n",egacycles,egacycles2,temp,clock); -/* if (video_recalctimings) - video_recalctimings();*/ RTCCONST=clock/32768.0; TIMER_USEC = (int)((clock / 1000000.0f) * (float)(1 << TIMER_SHIFT)); device_speed_changed(); } -//#define PITCONST (8000000.0/1193000.0) -//#define PITCONST (cpuclock/1193000.0) -void pit_reset() +void pit_reset(PIT *pit) { - memset(&pit,0,sizeof(PIT)); - pit.l[0]=0xFFFF; pit.c[0]=0xFFFF*PITCONST; - pit.l[1]=0xFFFF; pit.c[1]=0xFFFF*PITCONST; - pit.l[2]=0xFFFF; pit.c[2]=0xFFFF*PITCONST; - pit.m[0]=pit.m[1]=pit.m[2]=0; - pit.ctrls[0]=pit.ctrls[1]=pit.ctrls[2]=0; - pit.thit[0]=1; - pit.gate[0] = pit.gate[1] = 1; - pit.gate[2] = 0; - pit.using_timer[0] = pit.using_timer[1] = pit.using_timer[2] = 1; + void (*old_set_out_funcs[3])(int new_out, int old_out); + PIT_nr old_pit_nr[3]; + + memcpy(old_set_out_funcs, pit->set_out_funcs, 3 * sizeof(void *)); + memcpy(old_pit_nr, pit->pit_nr, 3 * sizeof(PIT_nr)); + memset(pit, 0, sizeof(PIT)); + memcpy(pit->set_out_funcs, old_set_out_funcs, 3 * sizeof(void *)); + memcpy(pit->pit_nr, old_pit_nr, 3 * sizeof(PIT_nr)); + + pit->l[0] = 0xFFFF; pit->c[0] = 0xFFFF*PITCONST; + pit->l[1] = 0xFFFF; pit->c[1] = 0xFFFF*PITCONST; + pit->l[2] = 0xFFFF; pit->c[2] = 0xFFFF*PITCONST; + pit->m[0] = pit->m[1] = pit->m[2] = 0; + pit->ctrls[0] = pit->ctrls[1] = pit->ctrls[2] = 0; + pit->thit[0]=1; + pit->gate[0] = pit->gate[1] = 1; + pit->gate[2] = 0; + pit->using_timer[0] = pit->using_timer[1] = pit->using_timer[2] = 1; } void clearpit() @@ -77,210 +84,214 @@ float pit_timer0_freq() return 1193182.0f/(float)0x10000; } -static void (*pit_set_out_funcs[3])(int new_out, int old_out); - -static void pit_set_out(int t, int out) +static void pit_set_out(PIT *pit, int t, int out) { - pit_set_out_funcs[t](out, pit.out[t]); - pit.out[t] = out; + pit->set_out_funcs[t](out, pit->out[t]); + pit->out[t] = out; } -static void pit_load(int t) +static void pit_load(PIT *pit, int t) { - int l = pit.l[t] ? pit.l[t] : 0x10000; + int l = pit->l[t] ? pit->l[t] : 0x10000; timer_process(); - pit.newcount[t] = 0; - pit.disabled[t] = 0; -// pclog("pit_load: t=%i l=%x\n", t, l); - switch (pit.m[t]) + pit->newcount[t] = 0; + pit->disabled[t] = 0; + switch (pit->m[t]) { case 0: /*Interrupt on terminal count*/ - pit.count[t] = l; - pit.c[t] = (int)((l << TIMER_SHIFT) * PITCONST); - pit_set_out(t, 0); - pit.thit[t] = 0; - pit.enabled[t] = pit.gate[t]; + pit->count[t] = l; + pit->c[t] = (int)((l << TIMER_SHIFT) * PITCONST); + pit_set_out(pit, t, 0); + pit->thit[t] = 0; + pit->enabled[t] = pit->gate[t]; break; case 1: /*Hardware retriggerable one-shot*/ - pit.enabled[t] = 1; + pit->enabled[t] = 1; break; case 2: /*Rate generator*/ - if (pit.initial[t]) + if (pit->initial[t]) { - pit.count[t] = l - 1; - pit.c[t] = (int)(((l - 1) << TIMER_SHIFT) * PITCONST); - pit_set_out(t, 1); - pit.thit[t] = 0; + pit->count[t] = l - 1; + pit->c[t] = (int)(((l - 1) << TIMER_SHIFT) * PITCONST); + pit_set_out(pit, t, 1); + pit->thit[t] = 0; } - pit.enabled[t] = pit.gate[t]; + pit->enabled[t] = pit->gate[t]; break; case 3: /*Square wave mode*/ - if (pit.initial[t]) + if (pit->initial[t]) { - pit.count[t] = l; - pit.c[t] = (int)((((l + 1) >> 1) << TIMER_SHIFT) * PITCONST); - pit_set_out(t, 1); - pit.thit[t] = 0; + pit->count[t] = l; + pit->c[t] = (int)((((l + 1) >> 1) << TIMER_SHIFT) * PITCONST); + pit_set_out(pit, t, 1); + pit->thit[t] = 0; } - pit.enabled[t] = pit.gate[t]; -// pclog("pit_load: square wave mode c=%x\n", pit.c[t]); + pit->enabled[t] = pit->gate[t]; break; case 4: /*Software triggered stobe*/ - if (!pit.thit[t] && !pit.initial[t]) - pit.newcount[t] = 1; + if (!pit->thit[t] && !pit->initial[t]) + pit->newcount[t] = 1; else { - pit.count[t] = l; - pit.c[t] = (int)((l << TIMER_SHIFT) * PITCONST); - pit_set_out(t, 0); - pit.thit[t] = 0; + pit->count[t] = l; + pit->c[t] = (int)((l << TIMER_SHIFT) * PITCONST); + pit_set_out(pit, t, 0); + pit->thit[t] = 0; } - pit.enabled[t] = pit.gate[t]; + pit->enabled[t] = pit->gate[t]; break; case 5: /*Hardware triggered stobe*/ - pit.enabled[t] = 1; + pit->enabled[t] = 1; break; } - pit.initial[t] = 0; - pit.running[t] = pit.enabled[t] && pit.using_timer[t] && !pit.disabled[t]; + pit->initial[t] = 0; + pit->running[t] = pit->enabled[t] && pit->using_timer[t] && !pit->disabled[t]; timer_update_outstanding(); -// pclog("pit_load: t=%i running=%i thit=%i enabled=%i m=%i l=%x c=%g gate=%i\n", t, pit.running[t], pit.thit[t], pit.enabled[t], pit.m[t], pit.l[t], pit.c[t], pit.gate[t]); } -void pit_set_gate(int t, int gate) +void pit_set_gate_no_timer(PIT *pit, int t, int gate) { - int l = pit.l[t] ? pit.l[t] : 0x10000; + int l = pit->l[t] ? pit->l[t] : 0x10000; - if (pit.disabled[t]) + if (pit->disabled[t]) { - pit.gate[t] = gate; + pit->gate[t] = gate; return; } - timer_process(); - switch (pit.m[t]) + switch (pit->m[t]) { case 0: /*Interrupt on terminal count*/ case 4: /*Software triggered stobe*/ - pit.enabled[t] = gate; + pit->enabled[t] = gate; break; case 1: /*Hardware retriggerable one-shot*/ case 5: /*Hardware triggered stobe*/ - if (gate && !pit.gate[t]) + if (gate && !pit->gate[t]) { - pit.count[t] = l; - pit.c[t] = (int)((l << TIMER_SHIFT) * PITCONST); - pit_set_out(t, 0); - pit.thit[t] = 0; - pit.enabled[t] = 1; + pit->count[t] = l; + pit->c[t] = (int)((l << TIMER_SHIFT) * PITCONST); + pit_set_out(pit, t, 0); + pit->thit[t] = 0; + pit->enabled[t] = 1; } break; case 2: /*Rate generator*/ - if (gate && !pit.gate[t]) + if (gate && !pit->gate[t]) { - pit.count[t] = l - 1; - pit.c[t] = (int)(((l - 1) << TIMER_SHIFT) * PITCONST); - pit_set_out(t, 1); - pit.thit[t] = 0; + pit->count[t] = l - 1; + pit->c[t] = (int)(((l - 1) << TIMER_SHIFT) * PITCONST); + pit_set_out(pit, t, 1); + pit->thit[t] = 0; } - pit.enabled[t] = gate; + pit->enabled[t] = gate; break; case 3: /*Square wave mode*/ - if (gate && !pit.gate[t]) + if (gate && !pit->gate[t]) { - pit.count[t] = l; - pit.c[t] = (int)((((l + 1) >> 1) << TIMER_SHIFT) * PITCONST); - pit_set_out(t, 1); - pit.thit[t] = 0; + pit->count[t] = l; + pit->c[t] = (int)((((l + 1) >> 1) << TIMER_SHIFT) * PITCONST); + pit_set_out(pit, t, 1); + pit->thit[t] = 0; } - pit.enabled[t] = gate; + pit->enabled[t] = gate; break; } - pit.gate[t] = gate; - pit.running[t] = pit.enabled[t] && pit.using_timer[t] && !pit.disabled[t]; - timer_update_outstanding(); -// pclog("pit_set_gate: t=%i gate=%i\n", t, gate); + pit->gate[t] = gate; + pit->running[t] = pit->enabled[t] && pit->using_timer[t] && !pit->disabled[t]; } -static void pit_over(int t) +void pit_set_gate(PIT *pit, int t, int gate) { - int l = pit.l[t] ? pit.l[t] : 0x10000; - if (pit.disabled[t]) + if (pit->disabled[t]) { - pit.count[t] += 0xffff; - pit.c[t] += (int)((0xffff << TIMER_SHIFT) * PITCONST); + pit->gate[t] = gate; return; } -// if (!t) pclog("pit_over: t=%i l=%x c=%x %i hit=%i\n", t, pit.l[t], pit.c[t], pit.c[t] >> TIMER_SHIFT, pit.thit[t]); - switch (pit.m[t]) + timer_process(); + + pit_set_gate_no_timer(pit, t, gate); + + timer_update_outstanding(); +} + +static void pit_over(PIT *pit, int t) +{ + int l = pit->l[t] ? pit->l[t] : 0x10000; + if (pit->disabled[t]) + { + pit->count[t] += 0xffff; + pit->c[t] += (int)((0xffff << TIMER_SHIFT) * PITCONST); + return; + } + + switch (pit->m[t]) { case 0: /*Interrupt on terminal count*/ case 1: /*Hardware retriggerable one-shot*/ - if (!pit.thit[t]) - pit_set_out(t, 1); - pit.thit[t] = 1; - pit.count[t] += 0xffff; - pit.c[t] += (int)((0xffff << TIMER_SHIFT) * PITCONST); + if (!pit->thit[t]) + pit_set_out(pit, t, 1); + pit->thit[t] = 1; + pit->count[t] += 0xffff; + pit->c[t] += (int)((0xffff << TIMER_SHIFT) * PITCONST); break; case 2: /*Rate generator*/ - pit.count[t] += l; - pit.c[t] += (int)((l << TIMER_SHIFT) * PITCONST); - pit_set_out(t, 0); - pit_set_out(t, 1); + pit->count[t] += l; + pit->c[t] += (int)((l << TIMER_SHIFT) * PITCONST); + pit_set_out(pit, t, 0); + pit_set_out(pit, t, 1); break; case 3: /*Square wave mode*/ - if (pit.out[t]) + if (pit->out[t]) { - pit_set_out(t, 0); - pit.count[t] += (l >> 1); - pit.c[t] += (int)(((l >> 1) << TIMER_SHIFT) * PITCONST); + pit_set_out(pit, t, 0); + pit->count[t] += (l >> 1); + pit->c[t] += (int)(((l >> 1) << TIMER_SHIFT) * PITCONST); } else { - pit_set_out(t, 1); - pit.count[t] += ((l + 1) >> 1); - pit.c[t] = (int)((((l + 1) >> 1) << TIMER_SHIFT) * PITCONST); + pit_set_out(pit, t, 1); + pit->count[t] += ((l + 1) >> 1); + pit->c[t] = (int)((((l + 1) >> 1) << TIMER_SHIFT) * PITCONST); } -// if (!t) pclog("pit_over: square wave mode c=%x %lli %f\n", pit.c[t], tsc, PITCONST); break; case 4: /*Software triggered strove*/ - if (!pit.thit[t]) + if (!pit->thit[t]) { - pit_set_out(t, 0); - pit_set_out(t, 1); + pit_set_out(pit, t, 0); + pit_set_out(pit, t, 1); } - if (pit.newcount[t]) + if (pit->newcount[t]) { - pit.newcount[t] = 0; - pit.count[t] += l; - pit.c[t] += (int)((l << TIMER_SHIFT) * PITCONST); + pit->newcount[t] = 0; + pit->count[t] += l; + pit->c[t] += (int)((l << TIMER_SHIFT) * PITCONST); } else { - pit.thit[t] = 1; - pit.count[t] += 0xffff; - pit.c[t] += (int)((0xffff << TIMER_SHIFT) * PITCONST); + pit->thit[t] = 1; + pit->count[t] += 0xffff; + pit->c[t] += (int)((0xffff << TIMER_SHIFT) * PITCONST); } break; case 5: /*Hardware triggered strove*/ - if (!pit.thit[t]) + if (!pit->thit[t]) { - pit_set_out(t, 0); - pit_set_out(t, 1); + pit_set_out(pit, t, 0); + pit_set_out(pit, t, 1); } - pit.thit[t] = 1; - pit.count[t] += 0xffff; - pit.c[t] += (int)((0xffff << TIMER_SHIFT) * PITCONST); + pit->thit[t] = 1; + pit->count[t] += 0xffff; + pit->c[t] += (int)((0xffff << TIMER_SHIFT) * PITCONST); break; } - pit.running[t] = pit.enabled[t] && pit.using_timer[t] && !pit.disabled[t]; + pit->running[t] = pit->enabled[t] && pit->using_timer[t] && !pit->disabled[t]; } int pit_get_timer_0() { int read = (int)((pit.c[0] + ((1 << TIMER_SHIFT) - 1)) / PITCONST) >> TIMER_SHIFT; -//pclog("pit_get_timer_0: t=%i using_timer=%i m=%i\n", 0, pit.using_timer[0], pit.m[0]); if (pit.m[0] == 2) read++; if (read < 0) @@ -292,33 +303,32 @@ int pit_get_timer_0() return read; } -static int pit_read_timer(int t) +static int pit_read_timer(PIT *pit, int t) { timer_clock(); -// pclog("pit_read_timer: t=%i using_timer=%i m=%i\n", t, pit.using_timer[t], pit.m[t]); - if (pit.using_timer[t]) + if (pit->using_timer[t]) { - int read = (int)((pit.c[t] + ((1 << TIMER_SHIFT) - 1)) / PITCONST) >> TIMER_SHIFT; - if (pit.m[t] == 2) + int read = (int)((pit->c[t] + ((1 << TIMER_SHIFT) - 1)) / PITCONST) >> TIMER_SHIFT; + if (pit->m[t] == 2) read++; if (read < 0) read = 0; if (read > 0x10000) read = 0x10000; - if (pit.m[t] == 3) + if (pit->m[t] == 3) read <<= 1; return read; } - if (pit.m[t] == 2) - return pit.count[t] + 1; - return pit.count[t]; + if (pit->m[t] == 2) + return pit->count[t] + 1; + return pit->count[t]; } -void pit_write(uint16_t addr, uint8_t val, void *priv) +void pit_write(uint16_t addr, uint8_t val, void *p) { + PIT *pit = (PIT *)p; int t; cycles -= (int)PITCONST; -// /*if (val != 0x40) */pclog("Write PIT %04X %02X %04X:%08X %i %i\n",addr,val,CS,pc,ins, pit.gate[0]); switch (addr&3) { @@ -328,234 +338,192 @@ void pit_write(uint16_t addr, uint8_t val, void *priv) if (!(val&0x20)) { if (val & 2) - pit.rl[0] = pit.using_timer[0] ? ((int)(pit.c[0] / PITCONST) >> TIMER_SHIFT) : pit.count[0]; + pit->rl[0] = pit->using_timer[0] ? ((int)(pit->c[0] / PITCONST) >> TIMER_SHIFT) : pit->count[0]; if (val & 4) - pit.rl[1] = pit.using_timer[1] ? ((int)(pit.c[1] / PITCONST) >> TIMER_SHIFT) : pit.count[1]; + pit->rl[1] = pit->using_timer[1] ? ((int)(pit->c[1] / PITCONST) >> TIMER_SHIFT) : pit->count[1]; if (val & 8) - pit.rl[2] = pit.using_timer[2] ? ((int)(pit.c[2] / PITCONST) >> TIMER_SHIFT) : pit.count[2]; + pit->rl[2] = pit->using_timer[2] ? ((int)(pit->c[2] / PITCONST) >> TIMER_SHIFT) : pit->count[2]; } if (!(val & 0x10)) { if (val & 2) { - pit.read_status[0] = (pit.ctrls[0] & 0x3f) | 0x40 | (pit.out[0] ? 0x80 : 0); - pit.do_read_status[0] = 1; + pit->read_status[0] = (pit->ctrls[0] & 0x3f) | 0x40 | (pit->out[0] ? 0x80 : 0); + pit->do_read_status[0] = 1; } if (val & 4) { - pit.read_status[1] = (pit.ctrls[1] & 0x3f) | 0x40 | (pit.out[1] ? 0x80 : 0); - pit.do_read_status[1] = 1; + pit->read_status[1] = (pit->ctrls[1] & 0x3f) | 0x40 | (pit->out[1] ? 0x80 : 0); + pit->do_read_status[1] = 1; } if (val & 8) { - pit.read_status[2] = (pit.ctrls[2] & 0x3f) | 0x40 | (pit.out[2] ? 0x80 : 0); - pit.do_read_status[2] = 1; + pit->read_status[2] = (pit->ctrls[2] & 0x3f) | 0x40 | (pit->out[2] ? 0x80 : 0); + pit->do_read_status[2] = 1; } } return; } t = val >> 6; - pit.ctrl=val; + pit->ctrl=val; if ((val>>7)==3) { - printf("Bad PIT reg select\n"); return; -// dumpregs(); -// exit(-1); } -// printf("CTRL write %02X\n",val); - if (!(pit.ctrl&0x30)) + if (!(pit->ctrl&0x30)) { - pit.rl[t] = pit_read_timer(t); -// pclog("Timer latch %f %04X %04X\n",pit.c[0],pit.rl[0],pit.l[0]); - pit.ctrl |= 0x30; - pit.rereadlatch[t] = 0; - pit.rm[t] = 3; - pit.latched[t] = 1; + pit->rl[t] = pit_read_timer(pit, t); + pit->ctrl |= 0x30; + pit->rereadlatch[t] = 0; + pit->rm[t] = 3; + pit->latched[t] = 1; } else { - pit.ctrls[val>>6] = val; - pit.rm[val>>6]=pit.wm[val>>6]=(pit.ctrl>>4)&3; - pit.m[val>>6]=(val>>1)&7; - if (pit.m[val>>6]>5) - pit.m[val>>6]&=3; - if (!(pit.rm[val>>6])) + pit->ctrls[t] = val; + pit->rm[t]=pit->wm[t]=(pit->ctrl>>4)&3; + pit->m[t]=(val>>1)&7; + if (pit->m[t]>5) + pit->m[t]&=3; + if (!(pit->rm[t])) { - pit.rm[val>>6]=3; - pit.rl[t] = pit_read_timer(t); + pit->rm[t]=3; + pit->rl[t] = pit_read_timer(pit, t); } - pit.rereadlatch[val>>6]=1; - if ((val>>6)==2) ppispeakon=speakon=(pit.m[2]==0)?0:1; - pit.initial[t] = 1; - if (!pit.m[val >> 6]) - pit_set_out(val >> 6, 0); + pit->rereadlatch[t]=1; + if (t == 2) ppispeakon=speakon=(pit->m[2]==0)?0:1; + pit->initial[t] = 1; + if (!pit->m[t]) + pit_set_out(pit, t, 0); else - pit_set_out(val >> 6, 1); - pit.disabled[val >> 6] = 1; -// pclog("ppispeakon %i\n",ppispeakon); + pit_set_out(pit, t, 1); + pit->disabled[t] = 1; } - pit.wp=0; - pit.thit[pit.ctrl>>6]=0; + pit->wp=0; + pit->thit[t]=0; break; case 0: case 1: case 2: /*Timers*/ t=addr&3; -// if (t==2) ppispeakon=speakon=0; -// pclog("Write timer %02X %i\n",pit.ctrls[t],pit.wm[t]); - switch (pit.wm[t]) + switch (pit->wm[t]) { case 1: - pit.l[t]=val; -// pit.thit[t]=0; - pit_load(t); -// pit.c[t]=pit.l[t]*PITCONST; -// if (!t) -// picintc(1); + pit->l[t]=val; + pit_load(pit, t); break; case 2: - pit.l[t]=(val<<8); -// pit.thit[t]=0; - pit_load(t); -// pit.c[t]=pit.l[t]*PITCONST; -// if (!t) -// picintc(1); + pit->l[t]=(val<<8); + pit_load(pit, t); break; case 0: - pit.l[t]&=0xFF; - pit.l[t]|=(val<<8); - pit_load(t); -// pit.c[t]=pit.l[t]*PITCONST; -// pclog("%04X %f\n",pit.l[t],pit.c[t]); -// pit.thit[t]=0; - pit.wm[t]=3; -// if (!t) -// picintc(1); + pit->l[t]&=0xFF; + pit->l[t]|=(val<<8); + pit_load(pit, t); + pit->wm[t]=3; break; case 3: - pit.l[t]&=0xFF00; - pit.l[t]|=val; - pit.wm[t]=0; + pit->l[t]&=0xFF00; + pit->l[t]|=val; + pit->wm[t]=0; break; } - speakval=(((float)pit.l[2]/(float)pit.l[0])*0x4000)-0x2000; -// printf("Speakval now %i\n",speakval); -// if (speakval>0x2000) -// printf("Speaker overflow - %i %i %04X %04X\n",pit.l[0],pit.l[2],pit.l[0],pit.l[2]); + speakval=(((float)pit->l[2]/(float)pit->l[0])*0x4000)-0x2000; if (speakval>0x2000) speakval=0x2000; -/* if (!pit.l[t]) - { - pit.l[t]|=0x10000; - pit.c[t]=pit.l[t]*PITCONST; - }*/ break; } } -uint8_t pit_read(uint16_t addr, void *priv) +uint8_t pit_read(uint16_t addr, void *p) { + PIT *pit = (PIT *)p; int t; - uint8_t temp; + uint8_t temp = 0xff; cycles -= (int)PITCONST; -// printf("Read PIT %04X ",addr); switch (addr&3) { case 0: case 1: case 2: /*Timers*/ t = addr & 3; - if (pit.do_read_status[t]) + if (pit->do_read_status[t]) { - pit.do_read_status[t] = 0; - temp = pit.read_status[t]; + pit->do_read_status[t] = 0; + temp = pit->read_status[t]; break; } - if (pit.rereadlatch[addr & 3] && !pit.latched[addr & 3]) + if (pit->rereadlatch[addr & 3] && !pit->latched[addr & 3]) { - pit.rereadlatch[addr & 3] = 0; - pit.rl[t] = pit_read_timer(t); + pit->rereadlatch[addr & 3] = 0; + pit->rl[t] = pit_read_timer(pit, t); } - switch (pit.rm[addr & 3]) + switch (pit->rm[addr & 3]) { case 0: - temp = pit.rl[addr & 3] >> 8; - pit.rm[addr & 3] = 3; - pit.latched[addr & 3] = 0; - pit.rereadlatch[addr & 3] = 1; + temp = pit->rl[addr & 3] >> 8; + pit->rm[addr & 3] = 3; + pit->latched[addr & 3] = 0; + pit->rereadlatch[addr & 3] = 1; break; case 1: - temp = (pit.rl[addr & 3]) & 0xFF; - pit.latched[addr & 3] = 0; - pit.rereadlatch[addr & 3] = 1; + temp = (pit->rl[addr & 3]) & 0xFF; + pit->latched[addr & 3] = 0; + pit->rereadlatch[addr & 3] = 1; break; case 2: - temp = (pit.rl[addr & 3]) >> 8; - pit.latched[addr & 3] = 0; - pit.rereadlatch[addr & 3] = 1; + temp = (pit->rl[addr & 3]) >> 8; + pit->latched[addr & 3] = 0; + pit->rereadlatch[addr & 3] = 1; break; case 3: - temp = (pit.rl[addr & 3]) & 0xFF; - if (pit.m[addr & 3] & 0x80) - pit.m[addr & 3] &= 7; + temp = (pit->rl[addr & 3]) & 0xFF; + if (pit->m[addr & 3] & 0x80) + pit->m[addr & 3] &= 7; else - pit.rm[addr & 3] = 0; + pit->rm[addr & 3] = 0; break; } break; case 3: /*Control*/ - temp = pit.ctrl; + temp = pit->ctrl; break; } -// pclog("%02X\n", temp); -// printf("%02X %i %i %04X:%04X %i\n",temp,pit.rm[addr&3],pit.wp,cs>>4,pc, ins); return temp; } -void pit_poll() -{ -// printf("Poll pit %f %f %f\n",pit.c[0],pit.c[1],pit.c[2]); - if (pit.c[0] < 1 && pit.running[0]) - pit_over(0); - if (pit.c[1] < 1 && pit.running[1]) - pit_over(1); - if (pit.c[2] < 1 && pit.running[2]) - pit_over(2); -} - void pit_timer_over(void *p) { - int timer = (int) p; -// pclog("pit_timer_over %i\n", timer); - - pit_over(timer); + PIT_nr *pit_nr = (PIT_nr *)p; + PIT *pit = pit_nr->pit; + int timer = pit_nr->nr; + + pit_over(pit, timer); } -void pit_clock(int t) +void pit_clock(PIT *pit, int t) { - if (pit.thit[t] || !pit.enabled[t]) + if (pit->thit[t] || !pit->enabled[t]) return; - if (pit.using_timer[t]) + if (pit->using_timer[t]) return; - pit.count[t] -= (pit.m[t] == 3) ? 2 : 1; - if (!pit.count[t]) - pit_over(t); + pit->count[t] -= (pit->m[t] == 3) ? 2 : 1; + if (!pit->count[t]) + pit_over(pit, t); } -void pit_set_using_timer(int t, int using_timer) +void pit_set_using_timer(PIT *pit, int t, int using_timer) { -// pclog("pit_set_using_timer: t=%i using_timer=%i\n", t, using_timer); timer_process(); - if (pit.using_timer[t] && !using_timer) - pit.count[t] = pit_read_timer(t); - if (!pit.using_timer[t] && using_timer) - pit.c[t] = (int)((pit.count[t] << TIMER_SHIFT) * PITCONST); - pit.using_timer[t] = using_timer; - pit.running[t] = pit.enabled[t] && pit.using_timer[t] && !pit.disabled[t]; + if (pit->using_timer[t] && !using_timer) + pit->count[t] = pit_read_timer(pit, t); + if (!pit->using_timer[t] && using_timer) + pit->c[t] = (int)((pit->count[t] << TIMER_SHIFT) * PITCONST); + pit->using_timer[t] = using_timer; + pit->running[t] = pit->enabled[t] && pit->using_timer[t] && !pit->disabled[t]; timer_update_outstanding(); } -void pit_set_out_func(int t, void (*func)(int new_out, int old_out)) +void pit_set_out_func(PIT *pit, int t, void (*func)(int new_out, int old_out)) { - pit_set_out_funcs[t] = func; + pit->set_out_funcs[t] = func; } void pit_null_timer(int new_out, int old_out) @@ -575,12 +543,25 @@ void pit_irq0_timer_pcjr(int new_out, int old_out) if (new_out && !old_out) { picint(1); - pit_clock(1); + pit_clock(&pit, 1); } if (!new_out) picintc(1); } +void pit_irq0_ps2(int new_out, int old_out) +{ + if (new_out && !old_out) + { + picint(1); + pit_set_gate_no_timer(&pit2, 0, 1); + } + if (!new_out) + picintc(1); + if (!new_out && old_out) + pit_clock(&pit2, 0); +} + void pit_refresh_timer_xt(int new_out, int old_out) { if (new_out && !old_out) @@ -608,18 +589,52 @@ void pit_speaker_timer(int new_out, int old_out) } +void pit_nmi_ps2(int new_out, int old_out) +{ + nmi = new_out; + if (nmi) + nmi_auto_clear = 1; +} + void pit_init() { - io_sethandler(0x0040, 0x0004, pit_read, NULL, NULL, pit_write, NULL, NULL, NULL); + pit_reset(&pit); + + io_sethandler(0x0040, 0x0004, pit_read, NULL, NULL, pit_write, NULL, NULL, &pit); pit.gate[0] = pit.gate[1] = 1; pit.gate[2] = 0; pit.using_timer[0] = pit.using_timer[1] = pit.using_timer[2] = 1; + + pit.pit_nr[0].nr = 0; + pit.pit_nr[1].nr = 1; + pit.pit_nr[2].nr = 2; + pit.pit_nr[0].pit = pit.pit_nr[1].pit = pit.pit_nr[2].pit = &pit; - timer_add(pit_timer_over, &pit.c[0], &pit.running[0], (void *)0); - timer_add(pit_timer_over, &pit.c[1], &pit.running[1], (void *)1); - timer_add(pit_timer_over, &pit.c[2], &pit.running[2], (void *)2); + timer_add(pit_timer_over, &pit.c[0], &pit.running[0], (void *)&pit.pit_nr[0]); + timer_add(pit_timer_over, &pit.c[1], &pit.running[1], (void *)&pit.pit_nr[1]); + timer_add(pit_timer_over, &pit.c[2], &pit.running[2], (void *)&pit.pit_nr[2]); - pit_set_out_func(0, pit_irq0_timer); - pit_set_out_func(1, pit_null_timer); - pit_set_out_func(2, pit_speaker_timer); + pit_set_out_func(&pit, 0, pit_irq0_timer); + pit_set_out_func(&pit, 1, pit_null_timer); + pit_set_out_func(&pit, 2, pit_speaker_timer); +} + +void pit_ps2_init() +{ + pit_reset(&pit2); + + io_sethandler(0x0044, 0x0001, pit_read, NULL, NULL, pit_write, NULL, NULL, &pit2); + io_sethandler(0x0047, 0x0001, pit_read, NULL, NULL, pit_write, NULL, NULL, &pit2); + + pit2.gate[0] = 0; + pit2.using_timer[0] = 0; + pit2.disabled[0] = 1; + + pit2.pit_nr[0].nr = 0; + pit2.pit_nr[0].pit = &pit2; + + timer_add(pit_timer_over, &pit2.c[0], &pit2.running[0], (void *)&pit2.pit_nr[0]); + + pit_set_out_func(&pit, 0, pit_irq0_ps2); + pit_set_out_func(&pit2, 0, pit_nmi_ps2); } diff --git a/src/pit.h b/src/pit.h index 3d5018bd1..a827e9581 100644 --- a/src/pit.h +++ b/src/pit.h @@ -1,10 +1,11 @@ extern double PITCONST; void pit_init(); -void pit_reset(); -void pit_set_gate(int channel, int gate); -void pit_set_using_timer(int t, int using_timer); -void pit_set_out_func(int t, void (*func)(int new_out, int old_out)); -void pit_clock(int t); +void pit_ps2_init(); +void pit_reset(PIT *pit); +void pit_set_gate(PIT *pit, int channel, int gate); +void pit_set_using_timer(PIT *pit, int t, int using_timer); +void pit_set_out_func(PIT *pit, int t, void (*func)(int new_out, int old_out)); +void pit_clock(PIT *pit, int t); void pit_null_timer(int new_out, int old_out); diff --git a/src/plat-midi.h b/src/plat-midi.h deleted file mode 100644 index 15b9edafe..000000000 --- a/src/plat-midi.h +++ /dev/null @@ -1,6 +0,0 @@ -/* Copyright holders: Sarah Walker - see COPYING for more details -*/ -void midi_init(); -void midi_close(); -void midi_write(uint8_t val); diff --git a/src/ppi.c b/src/ppi.c index 2d564b90c..dfb315e2c 100644 --- a/src/ppi.c +++ b/src/ppi.c @@ -10,13 +10,15 @@ #include "ibm.h" #include "pit.h" +#include "plat_keyboard.h" +#include "plat_mouse.h" -#include "plat-keyboard.h" -#include "plat-mouse.h" +PPI ppi; +int ppispeakon; void ppi_reset() { - ppi.pa=0x0;//0x1D; + ppi.pa=0x0; ppi.pb=0x40; } diff --git a/src/ps1.c b/src/ps1.c index 3fb016b45..f75a0f205 100644 --- a/src/ps1.c +++ b/src/ps1.c @@ -2,23 +2,30 @@ see COPYING for more details */ #include "ibm.h" +#include "cpu/cpu.h" +#include "io.h" #include "mem.h" -#include "ps1.h" #include "rom.h" +#include "device.h" +#include "model.h" #include "lpt.h" +#include "serial.h" + static rom_t ps1_high_rom; static uint8_t ps1_92, ps1_94, ps1_102, ps1_103, ps1_104, ps1_105, ps1_190; static int ps1_e0_addr; static uint8_t ps1_e0_regs[256]; + static struct { uint8_t status, int_status; uint8_t attention, ctrl; } ps1_hd; -uint8_t ps1_read(uint16_t port, void *p) + +static uint8_t ps1_read(uint16_t port, void *p) { uint8_t temp; @@ -57,7 +64,8 @@ uint8_t ps1_read(uint16_t port, void *p) return temp; } -void ps1_write(uint16_t port, uint8_t val, void *p) + +static void ps1_write(uint16_t port, uint8_t val, void *p) { switch (port) { @@ -72,9 +80,9 @@ void ps1_write(uint16_t port, uint8_t val, void *p) case 0x102: lpt1_remove(); if (val & 0x04) - serial1_init(0x3f8, 4); + serial_setup(1, SERIAL1_ADDR, SERIAL1_IRQ); else - serial1_remove(); + serial_remove(1); if (val & 0x10) { switch ((val >> 5) & 3) @@ -118,7 +126,8 @@ void ps1_write(uint16_t port, uint8_t val, void *p) } } -void ps1mb_init() + +void ps1mb_init(void) { io_sethandler(0x0091, 0x0001, ps1_read, NULL, NULL, ps1_write, NULL, NULL, NULL); io_sethandler(0x0092, 0x0001, ps1_read, NULL, NULL, ps1_write, NULL, NULL, NULL); @@ -129,16 +138,19 @@ void ps1mb_init() io_sethandler(0x0322, 0x0001, ps1_read, NULL, NULL, ps1_write, NULL, NULL, NULL); io_sethandler(0x0324, 0x0001, ps1_read, NULL, NULL, ps1_write, NULL, NULL, NULL); - rom_init(&ps1_high_rom, - "roms/ibmps1es/f80000_shell.bin", + if (!enable_xtide) + { + rom_init(&ps1_high_rom, + L"roms/ibmps1es/f80000_shell.bin", 0xf80000, 0x80000, 0x7ffff, 0, MEM_MAPPING_EXTERNAL); + } /* rom_init_interleaved(&ps1_high_rom, - "roms/ibmps1es/ibm_1057757_24-05-90.bin", - "roms/ibmps1es/ibm_1057757_29-15-90.bin", + L"roms/ibmps1es/ibm_1057757_24-05-90.bin", + L"roms/ibmps1es/ibm_1057757_29-15-90.bin", 0xfc0000, 0x40000, 0x3ffff, @@ -150,8 +162,8 @@ void ps1mb_init() lpt2_remove(); lpt1_init(0x3bc); - serial1_remove(); - serial2_remove(); + serial_remove(1); + serial_remove(2); memset(&ps1_hd, 0, sizeof(ps1_hd)); } @@ -202,7 +214,7 @@ static uint8_t ps1_m2121_read(uint16_t port, void *p) return temp; } -static void ps1_m2121_recalc_memory() +static void ps1_m2121_recalc_memory(void) { /*Enable first 512kb*/ mem_set_mem_state(0x00000, 0x80000, (ps1_e0_regs[0] & 0x01) ? (MEM_READ_INTERNAL | MEM_WRITE_INTERNAL) : (MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL)); @@ -237,9 +249,9 @@ void ps1_m2121_write(uint16_t port, uint8_t val, void *p) case 0x102: lpt1_remove(); if (val & 0x04) - serial1_init(0x3f8, 4); + serial_setup(1, SERIAL1_ADDR, SERIAL1_IRQ); else - serial1_remove(); + serial_remove(1); if (val & 0x10) { switch ((val >> 5) & 3) @@ -272,7 +284,7 @@ void ps1_m2121_write(uint16_t port, uint8_t val, void *p) } } -void ps1mb_m2121_init() +void ps1mb_m2121_init(void) { io_sethandler(0x0091, 0x0001, ps1_m2121_read, NULL, NULL, ps1_m2121_write, NULL, NULL, NULL); io_sethandler(0x0092, 0x0001, ps1_m2121_read, NULL, NULL, ps1_m2121_write, NULL, NULL, NULL); @@ -282,7 +294,7 @@ void ps1mb_m2121_init() io_sethandler(0x0190, 0x0001, ps1_m2121_read, NULL, NULL, ps1_m2121_write, NULL, NULL, NULL); rom_init(&ps1_high_rom, - "roms/ibmps1_2121/fc0000_shell.bin", + L"roms/ibmps1_2121/fc0000_shell.bin", 0xfc0000, 0x40000, 0x3ffff, @@ -290,12 +302,22 @@ void ps1mb_m2121_init() MEM_MAPPING_EXTERNAL); ps1_190 = 0; - lpt1_remove(); - lpt2_remove(); lpt1_init(0x3bc); - - serial1_remove(); - serial2_remove(); - + + mem_remap_top_384k(); +} + +void ps1mb_m2133_init(void) +{ + io_sethandler(0x0091, 0x0001, ps1_m2121_read, NULL, NULL, ps1_m2121_write, NULL, NULL, NULL); + io_sethandler(0x0092, 0x0001, ps1_m2121_read, NULL, NULL, ps1_m2121_write, NULL, NULL, NULL); + io_sethandler(0x0094, 0x0001, ps1_m2121_read, NULL, NULL, ps1_m2121_write, NULL, NULL, NULL); + io_sethandler(0x0102, 0x0004, ps1_m2121_read, NULL, NULL, ps1_m2121_write, NULL, NULL, NULL); + io_sethandler(0x0190, 0x0001, ps1_m2121_read, NULL, NULL, ps1_m2121_write, NULL, NULL, NULL); + + ps1_190 = 0; + + lpt1_init(0x3bc); + mem_remap_top_384k(); } diff --git a/src/ps1.h b/src/ps1.h deleted file mode 100644 index d58466d69..000000000 --- a/src/ps1.h +++ /dev/null @@ -1,5 +0,0 @@ -/* Copyright holders: Sarah Walker - see COPYING for more details -*/ -void ps1mb_init(); -void ps1mb_m2121_init(); diff --git a/src/ps2.c b/src/ps2.c new file mode 100644 index 000000000..6d9075358 --- /dev/null +++ b/src/ps2.c @@ -0,0 +1,139 @@ +#include "ibm.h" +#include "cpu/cpu.h" +#include "io.h" +#include "mem.h" +#include "rom.h" +#include "device.h" +#include "model.h" +#include "lpt.h" +#include "serial.h" + + +static uint8_t ps2_92, ps2_94, ps2_102, ps2_103, ps2_104, ps2_105, ps2_190; + + +static struct +{ + uint8_t status, int_status; + uint8_t attention, ctrl; +} ps2_hd; + + +static uint8_t ps2_read(uint16_t port, void *p) +{ + uint8_t temp; + + switch (port) + { + case 0x91: + return 0; + case 0x92: + return ps2_92; + case 0x94: + return ps2_94; + case 0x102: + return ps2_102 | 8; + case 0x103: + return ps2_103; + case 0x104: + return ps2_104; + case 0x105: + return ps2_105; + case 0x190: + return ps2_190; + + case 0x322: + temp = ps2_hd.status; + break; + case 0x324: + temp = ps2_hd.int_status; + ps2_hd.int_status &= ~0x02; + break; + + default: + temp = 0xff; + break; + } + + return temp; +} + +static void ps2_write(uint16_t port, uint8_t val, void *p) +{ + switch (port) + { + case 0x0092: + ps2_92 = val; + mem_a20_alt = val & 2; + mem_a20_recalc(); + break; + case 0x94: + ps2_94 = val; + break; + case 0x102: + lpt1_remove(); + if (val & 0x04) + serial_setup(1, SERIAL1_ADDR, SERIAL1_IRQ); + else + serial_remove(1); + if (val & 0x10) + { + switch ((val >> 5) & 3) + { + case 0: + lpt1_init(0x3bc); + break; + case 1: + lpt1_init(0x378); + break; + case 2: + lpt1_init(0x278); + break; + } + } + ps2_102 = val; + break; + case 0x103: + ps2_103 = val; + break; + case 0x104: + ps2_104 = val; + break; + case 0x105: + ps2_105 = val; + break; + case 0x190: + ps2_190 = val; + break; + + case 0x322: + ps2_hd.ctrl = val; + if (val & 0x80) + ps2_hd.status |= 0x02; + break; + case 0x324: + ps2_hd.attention = val & 0xf0; + if (ps2_hd.attention) + ps2_hd.status = 0x14; + break; + } +} + + +void ps2board_init(void) +{ + io_sethandler(0x0091, 0x0001, ps2_read, NULL, NULL, ps2_write, NULL, NULL, NULL); + io_sethandler(0x0092, 0x0001, ps2_read, NULL, NULL, ps2_write, NULL, NULL, NULL); + io_sethandler(0x0094, 0x0001, ps2_read, NULL, NULL, ps2_write, NULL, NULL, NULL); + io_sethandler(0x0102, 0x0004, ps2_read, NULL, NULL, ps2_write, NULL, NULL, NULL); + io_sethandler(0x0190, 0x0001, ps2_read, NULL, NULL, ps2_write, NULL, NULL, NULL); + io_sethandler(0x0320, 0x0001, ps2_read, NULL, NULL, ps2_write, NULL, NULL, NULL); + io_sethandler(0x0322, 0x0001, ps2_read, NULL, NULL, ps2_write, NULL, NULL, NULL); + io_sethandler(0x0324, 0x0001, ps2_read, NULL, NULL, ps2_write, NULL, NULL, NULL); + + ps2_190 = 0; + + lpt1_init(0x3bc); + + memset(&ps2_hd, 0, sizeof(ps2_hd)); +} diff --git a/src/ps2_mca.c b/src/ps2_mca.c new file mode 100644 index 000000000..1a31e07d5 --- /dev/null +++ b/src/ps2_mca.c @@ -0,0 +1,792 @@ +#include "ibm.h" +#include "cpu/cpu.h" +#include "cpu/x86.h" +#include "io.h" +#include "mca.h" +#include "mem.h" +#include "rom.h" +#include "device.h" +#include "lpt.h" +#include "ps2_mca.h" +#include "ps2_nvr.h" +#include "serial.h" + + +static struct +{ + uint8_t adapter_setup; + uint8_t option[4]; + uint8_t pos_vga; + uint8_t setup; + uint8_t sys_ctrl_port_a; + uint8_t subaddr_lo, subaddr_hi; + + uint8_t memory_bank[8]; + + uint8_t io_id; + + mem_mapping_t shadow_mapping; + mem_mapping_t split_mapping; + mem_mapping_t expansion_mapping; + + uint8_t (*planar_read)(uint16_t port); + void (*planar_write)(uint16_t port, uint8_t val); + + uint8_t mem_regs[3]; + + uint32_t split_addr; + + uint8_t mem_pos_regs[8]; +} ps2; + + +static uint8_t ps2_read_shadow_ram(uint32_t addr, void *priv) +{ + addr = (addr & 0x1ffff) + 0xe0000; + return mem_read_ram(addr, priv); +} +static uint16_t ps2_read_shadow_ramw(uint32_t addr, void *priv) +{ + addr = (addr & 0x1ffff) + 0xe0000; + return mem_read_ramw(addr, priv); +} +static uint32_t ps2_read_shadow_raml(uint32_t addr, void *priv) +{ + addr = (addr & 0x1ffff) + 0xe0000; + return mem_read_raml(addr, priv); +} +static void ps2_write_shadow_ram(uint32_t addr, uint8_t val, void *priv) +{ + addr = (addr & 0x1ffff) + 0xe0000; + mem_write_ram(addr, val, priv); +} +static void ps2_write_shadow_ramw(uint32_t addr, uint16_t val, void *priv) +{ + addr = (addr & 0x1ffff) + 0xe0000; + mem_write_ramw(addr, val, priv); +} +static void ps2_write_shadow_raml(uint32_t addr, uint32_t val, void *priv) +{ + addr = (addr & 0x1ffff) + 0xe0000; + mem_write_raml(addr, val, priv); +} + +static uint8_t ps2_read_split_ram(uint32_t addr, void *priv) +{ + addr = (addr & 0x3ffff) + 0xa0000; + return mem_read_ram(addr, priv); +} +static uint16_t ps2_read_split_ramw(uint32_t addr, void *priv) +{ + addr = (addr & 0x3ffff) + 0xa0000; + return mem_read_ramw(addr, priv); +} +static uint32_t ps2_read_split_raml(uint32_t addr, void *priv) +{ + addr = (addr & 0x3ffff) + 0xa0000; + return mem_read_raml(addr, priv); +} +static void ps2_write_split_ram(uint32_t addr, uint8_t val, void *priv) +{ + addr = (addr & 0x3ffff) + 0xa0000; + mem_write_ram(addr, val, priv); +} +static void ps2_write_split_ramw(uint32_t addr, uint16_t val, void *priv) +{ + addr = (addr & 0x3ffff) + 0xa0000; + mem_write_ramw(addr, val, priv); +} +static void ps2_write_split_raml(uint32_t addr, uint32_t val, void *priv) +{ + addr = (addr & 0x3ffff) + 0xa0000; + mem_write_raml(addr, val, priv); +} + + + +#define PS2_SETUP_IO 0x80 +#define PS2_SETUP_VGA 0x20 + +#define PS2_ADAPTER_SETUP 0x08 + +static uint8_t model_50_read(uint16_t port) +{ + switch (port) + { + case 0x100: + return 0xff; + case 0x101: + return 0xfb; + case 0x102: + return ps2.option[0]; + case 0x103: + return ps2.option[1]; + case 0x104: + return ps2.option[2]; + case 0x105: + return ps2.option[3]; + case 0x106: + return ps2.subaddr_lo; + case 0x107: + return ps2.subaddr_hi; + } + return 0xff; +} + +static uint8_t model_55sx_read(uint16_t port) +{ + switch (port) + { + case 0x100: + return 0xff; + case 0x101: + return 0xfb; + case 0x102: + return ps2.option[0]; + case 0x103: + return ps2.option[1]; + case 0x104: + return ps2.memory_bank[ps2.option[3] & 7]; + case 0x105: + return ps2.option[3]; + case 0x106: + return ps2.subaddr_lo; + case 0x107: + return ps2.subaddr_hi; + } + return 0xff; +} + +static uint8_t model_80_read(uint16_t port) +{ + switch (port) + { + case 0x100: + return 0xff; + case 0x101: + return 0xfd; + case 0x102: + return ps2.option[0]; + case 0x103: + return ps2.option[1]; + case 0x104: + return ps2.option[2]; + case 0x105: + return ps2.option[3]; + case 0x106: + return ps2.subaddr_lo; + case 0x107: + return ps2.subaddr_hi; + } + return 0xff; +} + +static void model_50_write(uint16_t port, uint8_t val) +{ + switch (port) + { + case 0x100: + ps2.io_id = val; + break; + case 0x101: + break; + case 0x102: + lpt1_remove(); + serial_remove(1); + if (val & 0x04) + { + if (val & 0x08) + serial_setup(1, SERIAL1_ADDR, SERIAL1_IRQ); + else + serial_setup(1, SERIAL2_ADDR, SERIAL2_IRQ); + } + else + serial_remove(1); + if (val & 0x10) + { + switch ((val >> 5) & 3) + { + case 0: + lpt1_init(0x3bc); + break; + case 1: + lpt1_init(0x378); + break; + case 2: + lpt1_init(0x278); + break; + } + } + ps2.option[0] = val; + break; + case 0x103: + ps2.option[1] = val; + break; + case 0x104: + ps2.option[2] = val; + break; + case 0x105: + ps2.option[3] = val; + break; + case 0x106: + ps2.subaddr_lo = val; + break; + case 0x107: + ps2.subaddr_hi = val; + break; + } +} + +static void model_55sx_write(uint16_t port, uint8_t val) +{ + switch (port) + { + case 0x100: + ps2.io_id = val; + break; + case 0x101: + break; + case 0x102: + lpt1_remove(); + serial_remove(1); + if (val & 0x04) + { + if (val & 0x08) + serial_setup(1, SERIAL1_ADDR, SERIAL1_IRQ); + else + serial_setup(1, SERIAL2_ADDR, SERIAL2_IRQ); + } + else + serial_remove(1); + if (val & 0x10) + { + switch ((val >> 5) & 3) + { + case 0: + lpt1_init(0x3bc); + break; + case 1: + lpt1_init(0x378); + break; + case 2: + lpt1_init(0x278); + break; + } + } + ps2.option[0] = val; + break; + case 0x103: + ps2.option[1] = val; + break; + case 0x104: + ps2.memory_bank[ps2.option[3] & 7] &= ~0xf; + ps2.memory_bank[ps2.option[3] & 7] |= (val & 0xf); + pclog("Write memory bank %i %02x\n", ps2.option[3] & 7, val); + break; + case 0x105: + pclog("Write POS3 %02x\n", val); + ps2.option[3] = val; + shadowbios = !(val & 0x10); + shadowbios_write = val & 0x10; + + if (shadowbios) + { + mem_set_mem_state(0xe0000, 0x20000, MEM_READ_INTERNAL | MEM_WRITE_DISABLED); + mem_mapping_disable(&ps2.shadow_mapping); + } + else + { + mem_set_mem_state(0xe0000, 0x20000, MEM_READ_EXTERNAL | MEM_WRITE_INTERNAL); + mem_mapping_enable(&ps2.shadow_mapping); + } + + if ((ps2.option[1] & 1) && !(ps2.option[3] & 0x20)) + mem_set_mem_state(mem_size * 1024, 256 * 1024, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + else + mem_set_mem_state(mem_size * 1024, 256 * 1024, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + break; + case 0x106: + ps2.subaddr_lo = val; + break; + case 0x107: + ps2.subaddr_hi = val; + break; + } +} + +static void model_80_write(uint16_t port, uint8_t val) +{ + switch (port) + { + case 0x100: + break; + case 0x101: + break; + case 0x102: + lpt1_remove(); + serial_remove(1); + if (val & 0x04) + { + if (val & 0x08) + serial_setup(1, SERIAL1_ADDR, SERIAL1_IRQ); + else + serial_setup(1, SERIAL2_ADDR, SERIAL2_IRQ); + } + else + serial_remove(1); + if (val & 0x10) + { + switch ((val >> 5) & 3) + { + case 0: + lpt1_init(0x3bc); + break; + case 1: + lpt1_init(0x378); + break; + case 2: + lpt1_init(0x278); + break; + } + } + ps2.option[0] = val; + break; + case 0x103: + ps2.option[1] = (ps2.option[1] & 0x0f) | (val & 0xf0); + break; + case 0x104: + ps2.option[2] = val; + break; + case 0x105: + ps2.option[3] = val; + break; + case 0x106: + ps2.subaddr_lo = val; + break; + case 0x107: + ps2.subaddr_hi = val; + break; + } +} + +uint8_t ps2_mca_read(uint16_t port, void *p) +{ + uint8_t temp; + + switch (port) + { + case 0x91: + fatal("Read 91 setup=%02x adapter=%02x\n", ps2.setup, ps2.adapter_setup); + case 0x92: + temp = ps2.sys_ctrl_port_a; + break; + case 0x94: + temp = ps2.setup; + break; + case 0x96: + temp = ps2.adapter_setup | 0x70; + break; + case 0x100: + if (!(ps2.setup & PS2_SETUP_IO)) + temp = ps2.planar_read(port); + else if (!(ps2.setup & PS2_SETUP_VGA)) + temp = 0xfd; + else if (ps2.adapter_setup & PS2_ADAPTER_SETUP) + temp = mca_read(port); + else + temp = 0xff; + break; + case 0x101: + if (!(ps2.setup & PS2_SETUP_IO)) + temp = ps2.planar_read(port); + else if (!(ps2.setup & PS2_SETUP_VGA)) + temp = 0xef; + else if (ps2.adapter_setup & PS2_ADAPTER_SETUP) + temp = mca_read(port); + else + temp = 0xff; + break; + case 0x102: + if (!(ps2.setup & PS2_SETUP_IO)) + temp = ps2.planar_read(port); + else if (!(ps2.setup & PS2_SETUP_VGA)) + temp = ps2.pos_vga; + else if (ps2.adapter_setup & PS2_ADAPTER_SETUP) + temp = mca_read(port); + else + temp = 0xff; + break; + case 0x103: + if (!(ps2.setup & PS2_SETUP_IO)) + temp = ps2.planar_read(port); + else if ((ps2.setup & PS2_SETUP_VGA) && (ps2.adapter_setup & PS2_ADAPTER_SETUP)) + temp = mca_read(port); + else + temp = 0xff; + break; + case 0x104: + if (!(ps2.setup & PS2_SETUP_IO)) + temp = ps2.planar_read(port); + else if ((ps2.setup & PS2_SETUP_VGA) && (ps2.adapter_setup & PS2_ADAPTER_SETUP)) + temp = mca_read(port); + else + temp = 0xff; + break; + case 0x105: + if (!(ps2.setup & PS2_SETUP_IO)) + temp = ps2.planar_read(port); + else if ((ps2.setup & PS2_SETUP_VGA) && (ps2.adapter_setup & PS2_ADAPTER_SETUP)) + temp = mca_read(port); + else + temp = 0xff; + break; + case 0x106: + if (!(ps2.setup & PS2_SETUP_IO)) + temp = ps2.planar_read(port); + else if ((ps2.setup & PS2_SETUP_VGA) && (ps2.adapter_setup & PS2_ADAPTER_SETUP)) + temp = mca_read(port); + else + temp = 0xff; + break; + case 0x107: + if (!(ps2.setup & PS2_SETUP_IO)) + temp = ps2.planar_read(port); + else if ((ps2.setup & PS2_SETUP_VGA) && (ps2.adapter_setup & PS2_ADAPTER_SETUP)) + temp = mca_read(port); + else + temp = 0xff; + break; + + default: + temp = 0xff; + break; + } + + pclog("ps2_read: port=%04x temp=%02x\n", port, temp); + + return temp; +} + +static void ps2_mca_write(uint16_t port, uint8_t val, void *p) +{ + pclog("ps2_write: port=%04x val=%02x %04x:%04x\n", port, val, CS,cpu_state.pc); + + switch (port) + { + case 0x0092: + if ((val & 1) && !(ps2.sys_ctrl_port_a & 1)) + { + softresetx86(); + cpu_set_edx(); + } + ps2.sys_ctrl_port_a = val; + mem_a20_alt = val & 2; + mem_a20_recalc(); + break; + case 0x94: + ps2.setup = val; + break; + case 0x96: + ps2.adapter_setup = val; + mca_set_index(val & 7); + break; + case 0x100: + if (!(ps2.setup & PS2_SETUP_IO)) + ps2.planar_write(port, val); + else if ((ps2.setup & PS2_SETUP_VGA) && (ps2.adapter_setup & PS2_ADAPTER_SETUP)) + mca_write(port, val); + break; + case 0x101: + if (!(ps2.setup & PS2_SETUP_IO)) + ps2.planar_write(port, val); + else if ((ps2.setup & PS2_SETUP_VGA) && (ps2.setup & PS2_SETUP_VGA) && (ps2.adapter_setup & PS2_ADAPTER_SETUP)) + mca_write(port, val); + break; + case 0x102: + if (!(ps2.setup & PS2_SETUP_IO)) + ps2.planar_write(port, val); + else if (!(ps2.setup & PS2_SETUP_VGA)) + ps2.pos_vga = val; + else if (ps2.adapter_setup & PS2_ADAPTER_SETUP) + mca_write(port, val); + break; + case 0x103: + if (!(ps2.setup & PS2_SETUP_IO)) + ps2.planar_write(port, val); + else if (ps2.adapter_setup & PS2_ADAPTER_SETUP) + mca_write(port, val); + break; + case 0x104: + if (!(ps2.setup & PS2_SETUP_IO)) + ps2.planar_write(port, val); + else if (ps2.adapter_setup & PS2_ADAPTER_SETUP) + mca_write(port, val); + break; + case 0x105: + if (!(ps2.setup & PS2_SETUP_IO)) + ps2.planar_write(port, val); + else if (ps2.adapter_setup & PS2_ADAPTER_SETUP) + mca_write(port, val); + break; + case 0x106: + if (!(ps2.setup & PS2_SETUP_IO)) + ps2.planar_write(port, val); + else if (ps2.adapter_setup & PS2_ADAPTER_SETUP) + mca_write(port, val); + break; + case 0x107: + if (!(ps2.setup & PS2_SETUP_IO)) + ps2.planar_write(port, val); + else if (ps2.adapter_setup & PS2_ADAPTER_SETUP) + mca_write(port, val); + break; + } +} + +static void ps2_mca_board_common_init() +{ + io_sethandler(0x0091, 0x0002, ps2_mca_read, NULL, NULL, ps2_mca_write, NULL, NULL, NULL); + io_sethandler(0x0094, 0x0001, ps2_mca_read, NULL, NULL, ps2_mca_write, NULL, NULL, NULL); + io_sethandler(0x0096, 0x0001, ps2_mca_read, NULL, NULL, ps2_mca_write, NULL, NULL, NULL); + io_sethandler(0x0100, 0x0008, ps2_mca_read, NULL, NULL, ps2_mca_write, NULL, NULL, NULL); + + ps2.setup = 0xff; + + lpt1_init(0x3bc); +} + +void ps2_mca_board_model_50_init() +{ + ps2_mca_board_common_init(); + + mem_remap_top_384k(); + mca_init(4); + + ps2.planar_read = model_50_read; + ps2.planar_write = model_50_write; +} + +void ps2_mca_board_model_55sx_init() +{ + ps2_mca_board_common_init(); + + mem_mapping_add(&ps2.shadow_mapping, + (mem_size+256) * 1024, + 128*1024, + ps2_read_shadow_ram, + ps2_read_shadow_ramw, + ps2_read_shadow_raml, + ps2_write_shadow_ram, + ps2_write_shadow_ramw, + ps2_write_shadow_raml, + &ram[0xe0000], + MEM_MAPPING_INTERNAL, + NULL); + + + mem_remap_top_256k(); + ps2.option[3] = 0x10; + + memset(ps2.memory_bank, 0xf0, 8); + switch (mem_size/1024) + { + case 1: + ps2.memory_bank[0] = 0x61; + break; + case 2: + ps2.memory_bank[0] = 0x51; + break; + case 3: + ps2.memory_bank[0] = 0x51; + ps2.memory_bank[1] = 0x61; + break; + case 4: + ps2.memory_bank[0] = 0x51; + ps2.memory_bank[1] = 0x51; + break; + case 5: + ps2.memory_bank[0] = 0x01; + ps2.memory_bank[1] = 0x61; + break; + case 6: + ps2.memory_bank[0] = 0x01; + ps2.memory_bank[1] = 0x51; + break; + case 7: /*Not supported*/ + ps2.memory_bank[0] = 0x01; + ps2.memory_bank[1] = 0x51; + break; + case 8: + ps2.memory_bank[0] = 0x01; + ps2.memory_bank[1] = 0x01; + break; + } + + mca_init(4); + + ps2.planar_read = model_55sx_read; + ps2.planar_write = model_55sx_write; +} + +static void mem_encoding_update() +{ + if (ps2.split_addr >= mem_size*1024) + mem_mapping_disable(&ps2.split_mapping); + + ps2.split_addr = (ps2.mem_regs[0] & 0xf) << 20; + + if (ps2.mem_regs[1] & 2) + mem_set_mem_state(0xe0000, 0x20000, MEM_READ_EXTERNAL | MEM_WRITE_INTERNAL); + else + mem_set_mem_state(0xe0000, 0x20000, MEM_READ_INTERNAL | MEM_WRITE_DISABLED); + + if (!(ps2.mem_regs[1] & 8)) + { + if (ps2.split_addr >= mem_size*1024) + mem_mapping_set_addr(&ps2.split_mapping, ps2.split_addr, 256*1024); + } +} + +static uint8_t mem_encoding_read(uint16_t addr, void *p) +{ + switch (addr) + { + case 0xe0: + return ps2.mem_regs[0]; + case 0xe1: + return ps2.mem_regs[1]; + } + return 0xff; +} +static void mem_encoding_write(uint16_t addr, uint8_t val, void *p) +{ + switch (addr) + { + case 0xe0: + ps2.mem_regs[0] = val; + break; + case 0xe1: + ps2.mem_regs[1] = val; + break; + } + mem_encoding_update(); +} + +static uint8_t ps2_mem_expansion_read(int port, void *p) +{ + return ps2.mem_pos_regs[port & 7]; +} + +static void ps2_mem_expansion_write(int port, uint8_t val, void *p) +{ + if (port < 0x102 || port == 0x104) + return; + + ps2.mem_pos_regs[port & 7] = val; + + if (ps2.mem_pos_regs[2] & 1) + mem_mapping_enable(&ps2.expansion_mapping); + else + mem_mapping_disable(&ps2.expansion_mapping); +} + +void ps2_mca_board_model_80_type2_init() +{ + ps2_mca_board_common_init(); + + mem_remap_top_256k(); + ps2.split_addr = mem_size * 1024; + mca_init(24); + + ps2.planar_read = model_80_read; + ps2.planar_write = model_80_write; + + device_add(&ps2_nvr_device); + + io_sethandler(0x00e0, 0x0002, mem_encoding_read, NULL, NULL, mem_encoding_write, NULL, NULL, NULL); + + ps2.mem_regs[1] = 2; + + switch (mem_size/1024) + { + case 1: + ps2.option[1] = 0x0c; + break; + case 2: + ps2.option[1] = 0x0e; + break; + case 3: + ps2.option[1] = 0x02; + break; + case 4: + default: + ps2.option[1] = 0x0a; + break; + } + + mem_mapping_add(&ps2.split_mapping, + (mem_size+256) * 1024, + 256*1024, + ps2_read_split_ram, + ps2_read_split_ramw, + ps2_read_split_raml, + ps2_write_split_ram, + ps2_write_split_ramw, + ps2_write_split_raml, + &ram[0xa0000], + MEM_MAPPING_INTERNAL, + NULL); + mem_mapping_disable(&ps2.split_mapping); + + if (mem_size > 4096) + { + /* Only 4 MB supported on planar, create a memory expansion card for the rest */ + mem_mapping_set_addr(&ram_high_mapping, 0x100000, 0x800000); + + ps2.mem_pos_regs[0] = 0xff; + ps2.mem_pos_regs[1] = 0xfc; + + switch (mem_size/1024) + { + case 5: + ps2.mem_pos_regs[4] = 0xfc; + break; + case 6: + ps2.mem_pos_regs[4] = 0xfe; + break; + case 7: + ps2.mem_pos_regs[4] = 0xf2; + break; + case 8: + ps2.mem_pos_regs[4] = 0xfa; + break; + case 9: + ps2.mem_pos_regs[4] = 0xca; + break; + case 10: + ps2.mem_pos_regs[4] = 0xea; + break; + case 11: + ps2.mem_pos_regs[4] = 0x2a; + break; + case 12: + ps2.mem_pos_regs[4] = 0xaa; + break; + } + + mca_add(ps2_mem_expansion_read, ps2_mem_expansion_write, NULL); + mem_mapping_add(&ps2.expansion_mapping, + 0x400000, + (mem_size - 4096)*1024, + mem_read_ram, + mem_read_ramw, + mem_read_raml, + mem_write_ram, + mem_write_ramw, + mem_write_raml, + &ram[0x400000], + MEM_MAPPING_INTERNAL, + NULL); + mem_mapping_disable(&ps2.expansion_mapping); + } +} diff --git a/src/ps2_mca.h b/src/ps2_mca.h new file mode 100644 index 000000000..8f242257e --- /dev/null +++ b/src/ps2_mca.h @@ -0,0 +1,3 @@ +void ps2_mca_board_model_50_init(); +void ps2_mca_board_model_55sx_init(); +void ps2_mca_board_model_80_type2_init(); diff --git a/src/ps2_nvr.c b/src/ps2_nvr.c new file mode 100644 index 000000000..33661c813 --- /dev/null +++ b/src/ps2_nvr.c @@ -0,0 +1,102 @@ +#include +#include "ibm.h" +#include "device.h" +#include "io.h" +#include "mem.h" +#include "rom.h" +#include "ps2_nvr.h" + +typedef struct ps2_nvr_t +{ + int addr; + uint8_t ram[8192]; +} ps2_nvr_t; + +static uint8_t ps2_nvr_read(uint16_t port, void *p) +{ + ps2_nvr_t *nvr = (ps2_nvr_t *)p; + + switch (port) + { + case 0x74: + return nvr->addr & 0xff; + case 0x75: + return nvr->addr >> 8; + case 0x76: + return nvr->ram[nvr->addr]; + } + + return 0xff; +} + +static void ps2_nvr_write(uint16_t port, uint8_t val, void *p) +{ + ps2_nvr_t *nvr = (ps2_nvr_t *)p; + + switch (port) + { + case 0x74: + nvr->addr = (nvr->addr & 0x1f00) | val; + break; + case 0x75: + nvr->addr = (nvr->addr & 0xff) | ((val & 0x1f) << 8); + break; + case 0x76: + nvr->ram[nvr->addr] = val; + break; + } +} + +static void *ps2_nvr_init() +{ + ps2_nvr_t *nvr = (ps2_nvr_t *)malloc(sizeof(ps2_nvr_t)); + FILE *f = NULL; + + memset(nvr, 0, sizeof(ps2_nvr_t)); + + io_sethandler(0x0074, 0x0003, ps2_nvr_read, NULL, NULL, ps2_nvr_write, NULL, NULL, nvr); + + switch (romset) + { + case ROM_IBMPS2_M80: f = nvrfopen(L"ibmps2_m80_sec.nvr", L"rb"); break; + } + if (f) + { + fread(nvr->ram, 8192, 1, f); + fclose(f); + } + else + memset(nvr->ram, 0xFF, 8192); + + return nvr; +} + +static void ps2_nvr_close(void *p) +{ + ps2_nvr_t *nvr = (ps2_nvr_t *)p; + FILE *f = NULL; + + switch (romset) + { + case ROM_IBMPS2_M80: f = nvrfopen(L"ibmps2_m80_sec.nvr", L"wb"); break; + } + if (f) + { + fwrite(nvr->ram, 8192, 1, f); + fclose(f); + } + + free(nvr); +} + +device_t ps2_nvr_device = +{ + "PS/2 NVRRAM", + 0, + ps2_nvr_init, + ps2_nvr_close, + NULL, + NULL, + NULL, + NULL +}; diff --git a/src/ps2_nvr.h b/src/ps2_nvr.h new file mode 100644 index 000000000..1656c82b0 --- /dev/null +++ b/src/ps2_nvr.h @@ -0,0 +1 @@ +extern device_t ps2_nvr_device; diff --git a/src/resources.h b/src/resources.h deleted file mode 100644 index 864b12330..000000000 --- a/src/resources.h +++ /dev/null @@ -1,247 +0,0 @@ -/* Copyright holders: Sarah Walker, Tenshi - see COPYING for more details -*/ -#define IDM_FILE_RESET 40000 -#define IDM_FILE_HRESET 40001 -#define IDM_FILE_EXIT 40002 -#define IDM_FILE_RESET_CAD 40003 -#define IDM_DISC_1 40010 -#define IDM_DISC_2 40011 -#define IDM_EJECT_1 40012 -#define IDM_EJECT_2 40013 -#define IDM_HDCONF 40014 -#define IDM_DISC_1_WP 40015 -#define IDM_DISC_2_WP 40016 -#define IDM_CONFIG 40020 -#define IDM_CONFIG_LOAD 40021 -#define IDM_CONFIG_SAVE 40022 -#define IDM_STATUS 40030 -#define IDM_VID_RESIZE 40050 -#define IDM_VID_REMEMBER 40051 -#define IDM_VID_DDRAW 40060 -#define IDM_VID_D3D 40061 -#define IDM_VID_FULLSCREEN 40070 -#define IDM_VID_FS_FULL 40071 -#define IDM_VID_FS_43 40072 -#define IDM_VID_FS_SQ 40073 -#define IDM_VID_FS_INT 40074 -#define IDM_VID_FORCE43 40075 -#define IDM_VID_OVERSCAN 40076 -#define IDM_VID_FLASH 40077 -#define IDM_VID_SCREENSHOT 40078 -#define IDM_DISC_3 40079 -#define IDM_DISC_4 40080 -#define IDM_EJECT_3 40081 -#define IDM_EJECT_4 40082 -#define IDM_DISC_3_WP 40083 -#define IDM_DISC_4_WP 40084 -#define IDM_CDROM_ISO 40100 -#define IDM_CDROM_RELOAD 40101 -#define IDM_CDROM_EMPTY 40200 -#define IDM_CDROM_REAL 40200 -#define IDM_CDROM_ENABLED 40300 -#define IDM_CDROM_SCSI 40400 -#define IDM_IDE_TER_ENABLED 40500 -#define IDM_IDE_TER_IRQ9 40501 -#define IDM_IDE_TER_IRQ10 40502 -#define IDM_IDE_TER_IRQ11 40503 -#define IDM_IDE_TER_IRQ12 40504 -#define IDM_IDE_TER_IRQ14 40505 -#define IDM_IDE_TER_IRQ15 40506 -#define IDM_IDE_QUA_ENABLED 40507 -#define IDM_IDE_QUA_IRQ9 40508 -#define IDM_IDE_QUA_IRQ10 40509 -#define IDM_IDE_QUA_IRQ11 40510 -#define IDM_IDE_QUA_IRQ12 40511 -#define IDM_IDE_QUA_IRQ14 40512 -#define IDM_IDE_QUA_IRQ15 40513 -#define IDM_SCSI_ENABLED 40600 -#define IDM_SCSI_MODEL0 40601 -#define IDM_SCSI_MODEL1 40602 -#define IDM_SCSI_BASE130 40603 -#define IDM_SCSI_BASE134 40604 -#define IDM_SCSI_BASE230 40605 -#define IDM_SCSI_BASE234 40606 -#define IDM_SCSI_BASE330 40607 -#define IDM_SCSI_BASE334 40608 -#define IDM_SCSI_IRQ9 40609 -#define IDM_SCSI_IRQ10 40610 -#define IDM_SCSI_IRQ11 40611 -#define IDM_SCSI_IRQ12 40612 -#define IDM_SCSI_IRQ14 40613 -#define IDM_SCSI_IRQ15 40614 -#define IDM_SCSI_DMA5 40615 -#define IDM_SCSI_DMA6 40616 -#define IDM_SCSI_DMA7 40617 - -#define IDC_COMBO1 1000 -#define IDC_COMBOVID 1001 -#define IDC_COMBO3 1002 -#define IDC_COMBO4 1003 -#define IDC_COMBO5 1004 -#define IDC_COMBO386 1005 -#define IDC_COMBO486 1006 -#define IDC_COMBOSND 1007 -#define IDC_COMBONET 1008 -#define IDC_COMBOCPUM 1060 -#define IDC_COMBOSPD 1061 -#define IDC_COMBODR1 1062 -#define IDC_COMBODR2 1063 -#define IDC_COMBOJOY 1064 -#define IDC_COMBOWS 1065 -#define IDC_COMBOMOUSE 1066 -#define IDC_COMBODR3 1067 -#define IDC_COMBODR4 1068 -#define IDC_CHECK1 1010 -#define IDC_CHECK2 1011 -#define IDC_CHECK3 1012 -#define IDC_CHECKGUS 1013 -#define IDC_CHECKSSI 1014 -#define IDC_CHECKVOODOO 1015 -#define IDC_CHECKDYNAREC 1016 -#define IDC_STATIC 1020 -#define IDC_CHECKSYNC 1024 -#define IDC_EDIT1 1030 -#define IDC_EDIT2 1031 -#define IDC_EDIT3 1032 -#define IDC_EDIT4 1033 -#define IDC_EDIT5 1034 -#define IDC_EDIT6 1035 -#define IDC_COMBOHDT 1036 - -#define IDC_EJECTC 1040 -#define IDC_EDITC 1050 -#define IDC_CFILE 1060 -#define IDC_CNEW 1070 -#define IDC_CHDD 1080 -#define IDC_CCDROM 1090 -#define IDC_EDIT_C_SPT 1200 -#define IDC_EDIT_C_HPC 1210 -#define IDC_EDIT_C_CYL 1220 -#define IDC_EDIT_C_FN 1230 -#define IDC_TEXT_C_SIZE 1240 - -#define IDC_EJECTD 1041 -#define IDC_EDITD 1051 -#define IDC_DFILE 1061 -#define IDC_DNEW 1071 -#define IDC_DHDD 1081 -#define IDC_DCDROM 1091 -#define IDC_EDIT_D_SPT 1201 -#define IDC_EDIT_D_HPC 1211 -#define IDC_EDIT_D_CYL 1221 -#define IDC_EDIT_D_FN 1231 -#define IDC_TEXT_D_SIZE 1241 - -#define IDC_EJECTE 1042 -#define IDC_EDITE 1052 -#define IDC_EFILE 1062 -#define IDC_ENEW 1072 -#define IDC_EHDD 1082 -#define IDC_ECDROM 1092 -#define IDC_EDIT_E_SPT 1202 -#define IDC_EDIT_E_HPC 1212 -#define IDC_EDIT_E_CYL 1222 -#define IDC_EDIT_E_FN 1232 -#define IDC_TEXT_E_SIZE 1242 - -#define IDC_EJECTF 1043 -#define IDC_EDITF 1053 -#define IDC_FFILE 1063 -#define IDC_FNEW 1073 -#define IDC_FHDD 1083 -#define IDC_FCDROM 1093 -#define IDC_EDIT_F_SPT 1203 -#define IDC_EDIT_F_HPC 1213 -#define IDC_EDIT_F_CYL 1223 -#define IDC_EDIT_F_FN 1233 -#define IDC_TEXT_F_SIZE 1243 - -#define IDC_EJECTG 1044 -#define IDC_EDITG 1054 -#define IDC_GFILE 1064 -#define IDC_GNEW 1074 -#define IDC_GHDD 1084 -#define IDC_GCDROM 1094 -#define IDC_EDIT_G_SPT 1204 -#define IDC_EDIT_G_HPC 1214 -#define IDC_EDIT_G_CYL 1224 -#define IDC_EDIT_G_FN 1234 -#define IDC_TEXT_G_SIZE 1244 - -#define IDC_EJECTH 1045 -#define IDC_EDITH 1055 -#define IDC_HFILE 1065 -#define IDC_HNEW 1075 -#define IDC_HHDD 1085 -#define IDC_HCDROM 1095 -#define IDC_EDIT_H_SPT 1205 -#define IDC_EDIT_H_HPC 1215 -#define IDC_EDIT_H_CYL 1225 -#define IDC_EDIT_H_FN 1235 -#define IDC_TEXT_H_SIZE 1245 - -#define IDC_EJECTI 1046 -#define IDC_EDITI 1056 -#define IDC_IFILE 1066 -#define IDC_INEW 1076 -#define IDC_IHDD 1086 -#define IDC_ICDROM 1096 -#define IDC_EDIT_I_SPT 1206 -#define IDC_EDIT_I_HPC 1216 -#define IDC_EDIT_I_CYL 1226 -#define IDC_EDIT_I_FN 1236 -#define IDC_TEXT_I_SIZE 1246 - -#define IDC_EJECTJ 1047 -#define IDC_EDITJ 1057 -#define IDC_JFILE 1067 -#define IDC_JNEW 1077 -#define IDC_JHDD 1087 -#define IDC_JCDROM 1097 -#define IDC_EDIT_J_SPT 1207 -#define IDC_EDIT_J_HPC 1217 -#define IDC_EDIT_J_CYL 1227 -#define IDC_EDIT_J_FN 1237 -#define IDC_TEXT_J_SIZE 1247 - -#define IDC_MEMSPIN 1100 -#define IDC_MEMTEXT 1101 -#define IDC_STEXT1 1102 -#define IDC_STEXT2 1103 -#define IDC_STEXT3 1104 -#define IDC_STEXT4 1105 -#define IDC_STEXT5 1106 -#define IDC_STEXT6 1107 -#define IDC_STEXT7 1108 -#define IDC_STEXT8 1109 -#define IDC_STEXT_DEVICE 1110 -#define IDC_TEXT_MB 1111 -#define IDC_TEXT1 1115 -#define IDC_TEXT2 1116 - -#define IDC_CONFIGUREVID 1200 -#define IDC_CONFIGURESND 1201 -#define IDC_CONFIGUREVOODOO 1202 -#define IDC_CONFIGUREMOD 1203 -#define IDC_CONFIGURENET 1204 -#define IDC_JOY1 1210 -#define IDC_JOY2 1211 -#define IDC_JOY3 1212 -#define IDC_JOY4 1213 - -#define IDC_CONFIG_BASE 1200 - -#define WM_RESETD3D WM_USER -#define WM_LEAVEFULLSCREEN WM_USER + 1 - -#define C_BASE 6 -#define D_BASE 44 -#define E_BASE 82 -#define F_BASE 120 -#define G_BASE 158 -#define H_BASE 196 -#define I_BASE 234 -#define J_BASE 272 -#define CMD_BASE 314 -#define DLG_HEIGHT 346 diff --git a/src/rom.c b/src/rom.c index 66549ad79..732d0cecd 100644 --- a/src/rom.c +++ b/src/rom.c @@ -3,28 +3,53 @@ */ #include #include +#include "config.h" #include "ibm.h" #include "mem.h" #include "rom.h" -FILE *romfopen(char *fn, char *mode) + +FILE *romfopen(wchar_t *fn, wchar_t *mode) { - char s[512]; - strcpy(s, pcempath); - put_backslash(s); - strcat(s, fn); - return fopen(s, mode); + wchar_t s[512]; + wcscpy(s, pcempath); + put_backslash_w(s); + wcscat(s, fn); + return _wfopen(s, mode); } -int rom_present(char *fn) + +FILE *nvrfopen(wchar_t *fn, wchar_t *mode) +{ + return _wfopen(nvr_concat(fn), mode); +} + + +int rom_getfile(wchar_t *fn, wchar_t *s, int size) { FILE *f; - char s[512]; + + wcscpy(s, pcempath); + put_backslash_w(s); + wcscat(s, fn); + f = _wfopen(s, L"rb"); + if (f) + { + fclose(f); + return 1; + } + return 0; +} + +int rom_present(wchar_t *fn) +{ + FILE *f; + wchar_t s[512]; - strcpy(s, pcempath); - put_backslash(s); - strcat(s, fn); - f = fopen(s, "rb"); + wcscpy(s, pcempath); + put_backslash_w(s); + wcscat(s, fn); + f = _wfopen(s, L"rb"); if (f) { fclose(f); @@ -33,32 +58,47 @@ int rom_present(char *fn) return 0; } + static uint8_t rom_read(uint32_t addr, void *p) { rom_t *rom = (rom_t *)p; -// pclog("rom_read : %08x %08x %02x\n", addr, rom->mask, rom->rom[addr & rom->mask]); +#ifdef ROM_TRACE + if (rom->mapping.base==ROM_TRACE) + pclog("ROM: read byte from BIOS at %06lX\n", addr); +#endif return rom->rom[addr & rom->mask]; } + + uint16_t rom_readw(uint32_t addr, void *p) { rom_t *rom = (rom_t *)p; -// pclog("rom_readw: %08x %08x %04x\n", addr, rom->mask, *(uint16_t *)&rom->rom[addr & rom->mask]); +#ifdef ROM_TRACE + if (rom->mapping.base==ROM_TRACE) + pclog("ROM: read word from BIOS at %06lX\n", addr); +#endif return *(uint16_t *)&rom->rom[addr & rom->mask]; } + + uint32_t rom_readl(uint32_t addr, void *p) { rom_t *rom = (rom_t *)p; -// pclog("rom_readl: %08x %08x %08x\n", addr, rom->mask, *(uint32_t *)&rom->rom[addr & rom->mask]); +#ifdef ROM_TRACE + if (rom->mapping.base==ROM_TRACE) + pclog("ROM: read long from BIOS at %06lX\n", addr); +#endif return *(uint32_t *)&rom->rom[addr & rom->mask]; } -int rom_init(rom_t *rom, char *fn, uint32_t address, int size, int mask, int file_offset, uint32_t flags) + +int rom_init(rom_t *rom, wchar_t *fn, uint32_t address, int size, int mask, int file_offset, uint32_t flags) { - FILE *f = romfopen(fn, "rb"); + FILE *f = romfopen(fn, L"rb"); if (!f) { - pclog("ROM image not found : %s\n", fn); + pclog("ROM image not found : %ws\n", fn); return -1; } @@ -82,20 +122,21 @@ int rom_init(rom_t *rom, char *fn, uint32_t address, int size, int mask, int fil return 0; } -int rom_init_interleaved(rom_t *rom, char *fn_low, char *fn_high, uint32_t address, int size, int mask, int file_offset, uint32_t flags) + +int rom_init_interleaved(rom_t *rom, wchar_t *fn_low, wchar_t *fn_high, uint32_t address, int size, int mask, int file_offset, uint32_t flags) { - FILE *f_low = romfopen(fn_low, "rb"); - FILE *f_high = romfopen(fn_high, "rb"); + FILE *f_low = romfopen(fn_low, L"rb"); + FILE *f_high = romfopen(fn_high, L"rb"); int c; if (!f_low || !f_high) { if (!f_low) - pclog("ROM image not found : %s\n", fn_low); + pclog("ROM image not found : %ws\n", fn_low); else fclose(f_low); if (!f_high) - pclog("ROM image not found : %s\n", fn_high); + pclog("ROM image not found : %ws\n", fn_high); else fclose(f_high); return -1; diff --git a/src/rom.h b/src/rom.h index d548ee8be..35b8ef78f 100644 --- a/src/rom.h +++ b/src/rom.h @@ -1,8 +1,10 @@ /* Copyright holders: Sarah Walker see COPYING for more details */ -FILE *romfopen(char *fn, char *mode); -int rom_present(char *fn); +FILE *romfopen(wchar_t *fn, wchar_t *mode); +FILE *nvrfopen(wchar_t *fn, wchar_t *mode); +int rom_getfile(wchar_t *fn, wchar_t *s, int size); +int rom_present(wchar_t *fn); typedef struct rom_t { @@ -11,5 +13,5 @@ typedef struct rom_t mem_mapping_t mapping; } rom_t; -int rom_init(rom_t *rom, char *fn, uint32_t address, int size, int mask, int file_offset, uint32_t flags); -int rom_init_interleaved(rom_t *rom, char *fn_low, char *fn_high, uint32_t address, int size, int mask, int file_offset, uint32_t flags); +int rom_init(rom_t *rom, wchar_t *fn, uint32_t address, int size, int mask, int file_offset, uint32_t flags); +int rom_init_interleaved(rom_t *rom, wchar_t *fn_low, wchar_t *fn_high, uint32_t address, int size, int mask, int file_offset, uint32_t flags); diff --git a/src/rtc.c b/src/rtc.c index eba9bfd53..323a36c6c 100644 --- a/src/rtc.c +++ b/src/rtc.c @@ -26,9 +26,6 @@ struct int year; } internal_clock; -/* When the RTC was last updated */ -static time_t rtc_set_time = 0; - /* Table for days in each month */ static int rtc_days_in_month[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; @@ -45,7 +42,7 @@ static int rtc_is_leap(int org_year) static int rtc_get_days(int org_month, int org_year) { if (org_month != 2) - return rtc_days_in_month[org_month]; + return rtc_days_in_month[org_month - 1]; else return rtc_is_leap(org_year) ? 29 : 28; } diff --git a/src/rtc.h b/src/rtc.h index a287e389f..78718143b 100644 --- a/src/rtc.h +++ b/src/rtc.h @@ -24,7 +24,7 @@ enum RTC_ADDR #define RTC_CENTURY 0x32 /* When the 12-hour format is selected, the higher-order bit of the hours byte represents PM when it is logic 1. */ -#define RTC_AMPM 0b10000000 +#define RTC_AMPM 0x80 /* Register A bitflags */ enum RTC_RA_BITS @@ -41,14 +41,14 @@ enum RTC_RA_BITS Table 3 lists the periodic interrupt rates and the square wave frequencies that can be chosen with the RS bits. These four read/write bits are not affected by !RESET. */ - RTC_RS = 0b1111, + RTC_RS = 0xF, /* DV0 These three bits are used to turn the oscillator on or off and to reset the countdown chain. A pattern of 010 is the only combination of bits that turn the oscillator on and allow the RTC to keep time. A pattern of 11x enables the oscillator but holds the countdown chain in reset. The next update occurs at 500ms after a pattern of 010 is written to DV0, DV1, and DV2. */ - RTC_DV0 = 0b1110000, + RTC_DV0 = 0x70, /* Update-In-Progress (UIP) This bit is a status flag that can be monitored. When the UIP bit is a 1, the update transfer occurs soon. @@ -56,7 +56,7 @@ enum RTC_RA_BITS The time, calendar, and alarm information in RAM is fully available for access when the UIP bit is 0. The UIP bit is read-only and is not affected by !RESET. Writing the SET bit in Register B to a 1 inhibits any update transfer and clears the UIP status bit. */ - RTC_UIP = 0b10000000 + RTC_UIP = 0x80 }; /* Register B bitflags */ @@ -70,51 +70,51 @@ enum RTC_RB_BITS When DSE is enabled, the internal logic test for the first/last Sunday condition at midnight. If the DSE bit is not set when the test occurs, the daylight saving function does not operate correctly. These adjustments do not occur when the DSE bit is 0. This bit is not affected by internal functions or !RESET. */ - RTC_DSE = 0b1, + RTC_DSE = 0x1, /* 24/12 The 24/12 control bit establishes the format of the hours byte. A 1 indicates the 24-hour mode and a 0 indicates the 12-hour mode. This bit is read/write and is not affected by internal functions or !RESET. */ - RTC_2412 = 0b10, + RTC_2412 = 0x2, /* Data Mode (DM) This bit indicates whether time and calendar information is in binary or BCD format. The DM bit is set by the program to the appropriate format and can be read as required. This bit is not modified by internal functions or !RESET. A 1 in DM signifies binary data, while a 0 in DM specifies BCD data. */ - RTC_DM = 0b100, + RTC_DM = 0x4, /* Square-Wave Enable (SQWE) When this bit is set to 1, a square-wave signal at the frequency set by the rate-selection bits RS3-RS0 is driven out on the SQW pin. When the SQWE bit is set to 0, the SQW pin is held low. SQWE is a read/write bit and is cleared by !RESET. SQWE is low if disabled, and is high impedance when VCC is below VPF. SQWE is cleared to 0 on !RESET. */ - RTC_SQWE = 0b1000, + RTC_SQWE = 0x8, /* Update-Ended Interrupt Enable (UIE) This bit is a read/write bit that enables the update-end flag (UF) bit in Register C to assert !IRQ. The !RESET pin going low or the SET bit going high clears the UIE bit. The internal functions of the device do not affect the UIE bit, but is cleared to 0 on !RESET. */ - RTC_UIE = 0b10000, + RTC_UIE = 0x10, /* Alarm Interrupt Enable (AIE) This bit is a read/write bit that, when set to 1, permits the alarm flag (AF) bit in Register C to assert !IRQ. An alarm interrupt occurs for each second that the three time bytes equal the three alarm bytes, including a don't-care alarm code of binary 11XXXXXX. The AF bit does not initiate the !IRQ signal when the AIE bit is set to 0. The internal functions of the device do not affect the AIE bit, but is cleared to 0 on !RESET. */ - RTC_AIE = 0b100000, + RTC_AIE = 0x20, /* Periodic Interrupt Enable (PIE) The PIE bit is a read/write bit that allows the periodic interrupt flag (PF) bit in Register C to drive the !IRQ pin low. When the PIE bit is set to 1, periodic interrupts are generated by driving the !IRQ pin low at a rate specified by the RS3-RS0 bits of Register A. A 0 in the PIE bit blocks the !IRQ output from being driven by a periodic interrupt, but the PF bit is still set at the periodic rate. PIE is not modified by any internal device functions, but is cleared to 0 on !RESET. */ - RTC_PIE = 0b1000000, + RTC_PIE = 0x40, /* SET When the SET bit is 0, the update transfer functions normally by advancing the counts once per second. When the SET bit is written to 1, any update transfer is inhibited, and the program can initialize the time and calendar bytes without an update occurring in the midst of initializing. Read cycles can be executed in a similar manner. SET is a read/write bit and is not affected by !RESET or internal functions of the device. */ - RTC_SET = 0b10000000 + RTC_SET = 0x80 }; /* Register C bitflags */ @@ -123,23 +123,23 @@ enum RTC_RC_BITS /* Unused These bits are unused in Register C. These bits always read 0 and cannot be written. */ - RTC_RC = 0b1111, + RTC_RC = 0xF, /* Update-Ended Interrupt Flag (UF) This bit is set after each update cycle. When the UIE bit is set to 1, the 1 in UF causes the IRQF bit to be a 1, which asserts the !IRQ pin. This bit can be cleared by reading Register C or with a !RESET. */ - RTC_UF = 0b10000, + RTC_UF = 0x10, /* Alarm Interrupt Flag (AF) A 1 in the AF bit indicates that the current time has matched the alarm time. If the AIE bit is also 1, the !IRQ pin goes low and a 1 appears in the IRQF bit. This bit can be cleared by reading Register C or with a !RESET. */ - RTC_AF = 0b100000, + RTC_AF = 0x20, /* Periodic Interrupt Flag (PF) This bit is read-only and is set to 1 when an edge is detected on the selected tap of the divider chain. The RS3 through RS0 bits establish the periodic rate. PF is set to 1 independent of the state of the PIE bit. When both PF and PIE are 1s, the !IRQ signal is active and sets the IRQF bit. This bit can be cleared by reading Register C or with a !RESET. */ - RTC_PF = 0b1000000, + RTC_PF = 0x40, /* Interrupt Request Flag (IRQF) The interrupt request flag (IRQF) is set to a 1 when one or more of the following are true: @@ -149,7 +149,7 @@ enum RTC_RC_BITS Any time the IRQF bit is a 1, the !IRQ pin is driven low. All flag bits are cleared after Register C is read by the program or when the !RESET pin is low. */ - RTC_IRQF = 0b10000000 + RTC_IRQF = 0x80 }; /* Register D bitflags */ @@ -158,13 +158,13 @@ enum RTC_RD_BITS /* Unused The remaining bits of Register D are not usable. They cannot be written and they always read 0. */ - RTC_RD = 0b1111111, + RTC_RD = 0x7F, /* Valid RAM and Time (VRT) This bit indicates the condition of the battery connected to the VBAT pin. This bit is not writeable and should always be 1 when read. If a 0 is ever present, an exhausted internal lithium energy source is indicated and both the contents of the RTC data and RAM data are questionable. This bit is unaffected by !RESET. */ - RTC_VRT = 0b10000000 + RTC_VRT = 0x80 }; void rtc_tick(); diff --git a/src/scat.c b/src/scat.c index af50ce936..fdcca8a11 100644 --- a/src/scat.c +++ b/src/scat.c @@ -3,29 +3,62 @@ */ /*This is the chipset used in the Award 286 clone model*/ #include "ibm.h" +#include "cpu/cpu.h" #include "io.h" -#include "scat.h" #include "mem.h" +#include "device.h" +#include "model.h" + + +#define SCAT_DMA_WAIT_STATE_CONTROL 0x01 +#define SCAT_VERSION 0x40 +#define SCAT_CLOCK_CONTROL 0x41 +#define SCAT_PERIPHERAL_CONTROL 0x44 +#define SCAT_MISCELLANEOUS_STATUS 0x45 +#define SCAT_POWER_MANAGEMENT 0x46 +#define SCAT_ROM_ENABLE 0x48 +#define SCAT_RAM_WRITE_PROTECT 0x49 +#define SCAT_SHADOW_RAM_ENABLE_1 0x4A +#define SCAT_SHADOW_RAM_ENABLE_2 0x4B +#define SCAT_SHADOW_RAM_ENABLE_3 0x4C +#define SCAT_DRAM_CONFIGURATION 0x4D +#define SCAT_EXTENDED_BOUNDARY 0x4E +#define SCAT_EMS_CONTROL 0x4F + + +typedef struct { + uint8_t regs_2x8; + uint8_t regs_2x9; +} scat_t; + static uint8_t scat_regs[256]; static int scat_index; static uint8_t scat_port_92 = 0; static uint8_t scat_ems_reg_2xA = 0; -static mem_mapping_t scat_mapping[32]; static mem_mapping_t scat_high_mapping[16]; static scat_t scat_stat[32]; static uint32_t scat_xms_bound; static mem_mapping_t scat_shadowram_mapping; static mem_mapping_t scat_512k_clip_mapping; -void scat_shadow_state_update() -{ - int i, val, val2; - // TODO - Segment A000 to BFFF shadow ram enable features and ROM enable features should be implemented later. - for (i = 8; i < 24; i++) +static void scat_shadow_state_update(void) +{ + int i, val; + + for (i = 0; i < 24; i++) { - val = ((scat_regs[SCAT_SHADOW_RAM_ENABLE_1 + (i >> 3)] >> (i & 7)) & 1) ? MEM_READ_INTERNAL : MEM_READ_EXTERNAL; + if((scat_regs[SCAT_SHADOW_RAM_ENABLE_1 + (i >> 3)] >> (i & 7)) & 1) + { + val = MEM_READ_INTERNAL; + ram_mapped_addr[i + 40] |= 1; + } + else + { + val = MEM_READ_EXTERNAL; + ram_mapped_addr[i + 40] &= ~1; + } if (i < 8) { val |= ((scat_regs[SCAT_SHADOW_RAM_ENABLE_1 + (i >> 3)] >> (i & 7)) & 1) ? MEM_WRITE_INTERNAL : MEM_WRITE_EXTERNAL; @@ -40,14 +73,15 @@ void scat_shadow_state_update() { val |= ((scat_regs[SCAT_SHADOW_RAM_ENABLE_1 + (i >> 3)] >> (i & 7)) & 1) ? MEM_WRITE_INTERNAL : MEM_WRITE_EXTERNAL; } - mem_set_mem_state((i + 40) << 14, 0x4000, val); } + mem_set_mem_state((i + 40) << 14, 0x4000, val); } flushmmucache(); } -void scat_set_xms_bound(uint8_t val) + +static void scat_set_xms_bound(uint8_t val) { uint32_t max_xms_size = (mem_size >= 16384) ? 0xFC0000 : mem_size << 10; @@ -121,7 +155,8 @@ void scat_set_xms_bound(uint8_t val) } } -uint32_t get_scat_addr(uint32_t addr, scat_t *p) + +static uint32_t get_scat_addr(uint32_t addr, scat_t *p) { if (p && (scat_regs[SCAT_EMS_CONTROL] & 0x80) && (p->regs_2x9 & 0x80)) { @@ -135,7 +170,8 @@ uint32_t get_scat_addr(uint32_t addr, scat_t *p) return addr; } -void scat_write(uint16_t port, uint8_t val, void *priv) + +static void scat_write(uint16_t port, uint8_t val, void *priv) { uint8_t scat_reg_valid = 0, scat_shadow_update = 0, index; uint32_t base_addr, virt_addr; @@ -155,7 +191,7 @@ void scat_write(uint16_t port, uint8_t val, void *priv) scat_reg_valid = 1; break; case SCAT_POWER_MANAGEMENT: - val &= 0x40; // TODO - Only use AUX parity disable bit for this version. Other bits should be implemented later. + val &= 0x40; /* TODO - Only use AUX parity disable bit for this version. Other bits should be implemented later. */ scat_reg_valid = 1; break; case SCAT_DRAM_CONFIGURATION: @@ -222,6 +258,16 @@ void scat_write(uint16_t port, uint8_t val, void *priv) pclog("Write SCAT EMS Control Port %04X to %02X at %04X:%04X\n", port, val, CS, cpu_state.pc); index = scat_ems_reg_2xA & 0x1F; scat_stat[index].regs_2x8 = val; + base_addr = (index + 16) << 14; + if(index >= 24) + base_addr += 0x30000; + + if(scat_stat[index].regs_2x9 & 0x80) + { + ram_mapped_addr[base_addr >> 14] &= 0xFFC000FF; + ram_mapped_addr[base_addr >> 14] |= val << 14; + flushmmucache(); + } } break; case 0x209: @@ -234,18 +280,18 @@ void scat_write(uint16_t port, uint8_t val, void *priv) if(index >= 24) base_addr += 0x30000; + ram_mapped_addr[base_addr >> 14] &= 1; if (val & 0x80) { virt_addr = (((scat_stat[index].regs_2x9 & 3) << 8) | scat_stat[index].regs_2x8) << 14; - mem_mapping_enable(&scat_mapping[index]); - mem_mapping_set_exec(&scat_mapping[index], ram + get_scat_addr(virt_addr, &scat_stat[index])); pclog("Map page %d(address %05X) to address %06X\n", scat_ems_reg_2xA & 0x1f, base_addr, virt_addr); + ram_mapped_addr[base_addr >> 14] |= virt_addr | 2; } else { - mem_mapping_disable(&scat_mapping[index]); pclog("Unmap page %d(address %06X)\n", scat_ems_reg_2xA & 0x1f, base_addr); } + flushmmucache(); if (scat_ems_reg_2xA & 0x80) { @@ -267,6 +313,16 @@ void scat_write(uint16_t port, uint8_t val, void *priv) pclog("Write SCAT EMS Control Port %04X to %02X at %04X:%04X\n", port, val, CS, cpu_state.pc); index = scat_ems_reg_2xA & 0x1F; scat_stat[index].regs_2x8 = val; + base_addr = (index + 16) << 14; + if(index >= 24) + base_addr += 0x30000; + + if(scat_stat[index].regs_2x9 & 0x80) + { + ram_mapped_addr[base_addr >> 14] &= 0xFFC000FF; + ram_mapped_addr[base_addr >> 14] |= val << 14; + flushmmucache(); + } } break; case 0x219: @@ -282,15 +338,14 @@ void scat_write(uint16_t port, uint8_t val, void *priv) if (val & 0x80) { virt_addr = (((scat_stat[index].regs_2x9 & 3) << 8) | scat_stat[index].regs_2x8) << 14; - mem_mapping_enable(&scat_mapping[index]); - mem_mapping_set_exec(&scat_mapping[index], ram + get_scat_addr(virt_addr, &scat_stat[index])); pclog("Map page %d(address %05X) to address %06X\n", scat_ems_reg_2xA & 0x1f, base_addr, virt_addr); + ram_mapped_addr[base_addr >> 14] |= virt_addr | 2; } else { - mem_mapping_disable(&scat_mapping[index]); pclog("Unmap page %d(address %05X)\n", scat_ems_reg_2xA & 0x1f, base_addr); } + flushmmucache(); if (scat_ems_reg_2xA & 0x80) { @@ -308,7 +363,8 @@ void scat_write(uint16_t port, uint8_t val, void *priv) } } -uint8_t scat_read(uint16_t port, void *priv) + +static uint8_t scat_read(uint16_t port, void *priv) { uint8_t val = 0xff, index; switch (port) @@ -317,7 +373,7 @@ uint8_t scat_read(uint16_t port, void *priv) switch (scat_index) { case SCAT_MISCELLANEOUS_STATUS: - val = (scat_regs[scat_index] & 0xbf) | ((scat_port_92 & 2) << 5); + val = (scat_regs[scat_index] & 0xbf) | ((mem_a20_key & 2) << 5); break; default: val = scat_regs[scat_index]; @@ -381,7 +437,8 @@ uint8_t scat_read(uint16_t port, void *priv) return val; } -uint8_t mem_read_scatems(uint32_t addr, void *priv) + +static uint8_t mem_read_scatems(uint32_t addr, void *priv) { uint8_t val = 0xff; scat_t *stat = (scat_t *)priv; @@ -392,7 +449,9 @@ uint8_t mem_read_scatems(uint32_t addr, void *priv) return val; } -uint16_t mem_read_scatemsw(uint32_t addr, void *priv) + + +static uint16_t mem_read_scatemsw(uint32_t addr, void *priv) { uint16_t val = 0xffff; scat_t *stat = (scat_t *)priv; @@ -403,7 +462,9 @@ uint16_t mem_read_scatemsw(uint32_t addr, void *priv) return val; } -uint32_t mem_read_scatemsl(uint32_t addr, void *priv) + + +static uint32_t mem_read_scatemsl(uint32_t addr, void *priv) { uint32_t val = 0xffffffff; scat_t *stat = (scat_t *)priv; @@ -415,7 +476,8 @@ uint32_t mem_read_scatemsl(uint32_t addr, void *priv) return val; } -void mem_write_scatems(uint32_t addr, uint8_t val, void *priv) + +static void mem_write_scatems(uint32_t addr, uint8_t val, void *priv) { scat_t *stat = (scat_t *)priv; @@ -423,7 +485,9 @@ void mem_write_scatems(uint32_t addr, uint8_t val, void *priv) if (addr < (mem_size << 10)) mem_write_ram(addr, val, priv); } -void mem_write_scatemsw(uint32_t addr, uint16_t val, void *priv) + + +static void mem_write_scatemsw(uint32_t addr, uint16_t val, void *priv) { scat_t *stat = (scat_t *)priv; @@ -431,7 +495,9 @@ void mem_write_scatemsw(uint32_t addr, uint16_t val, void *priv) if (addr < (mem_size << 10)) mem_write_ramw(addr, val, priv); } -void mem_write_scatemsl(uint32_t addr, uint32_t val, void *priv) + + +static void mem_write_scatemsl(uint32_t addr, uint32_t val, void *priv) { scat_t *stat = (scat_t *)priv; @@ -440,7 +506,8 @@ void mem_write_scatemsl(uint32_t addr, uint32_t val, void *priv) mem_write_raml(addr, val, priv); } -void scat_init() + +void scat_init(void) { int i; @@ -454,6 +521,11 @@ void scat_init() scat_regs[i] = 0xff; } + for (i = 0; i < 64; i++) + { + ram_mapped_addr[i] = 0; + } + scat_regs[SCAT_DMA_WAIT_STATE_CONTROL] = 0; scat_regs[SCAT_VERSION] = 10; scat_regs[SCAT_CLOCK_CONTROL] = 2; @@ -473,11 +545,9 @@ void scat_init() { scat_stat[i].regs_2x8 = 0xff; scat_stat[i].regs_2x9 = 0x03; - mem_mapping_add(&scat_mapping[i], (i + (i >= 24 ? 28 : 16)) << 14, 0x04000, mem_read_scatems, mem_read_scatemsw, mem_read_scatemsl, mem_write_scatems, mem_write_scatemsw, mem_write_scatemsl, ram + ((i + (i >= 24 ? 28 : 16)) << 14), 0, &scat_stat[i]); - mem_mapping_disable(&scat_mapping[i]); } - // TODO - Only normal CPU accessing address FF0000 to FFFFFF mapped to ROM. Normal CPU accessing address FC0000 to FEFFFF map to ROM should be implemented later. + /* TODO - Only normal CPU accessing address FF0000 to FFFFFF mapped to ROM. Normal CPU accessing address FC0000 to FEFFFF map to ROM should be implemented later. */ for (i = 12; i < 16; i++) { mem_mapping_add(&scat_high_mapping[i], (i << 14) + 0xFC0000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (i << 14), 0, NULL); @@ -488,11 +558,11 @@ void scat_init() mem_mapping_add(&scat_shadowram_mapping, 0x100000, 0x60000, mem_read_scatems, mem_read_scatemsw, mem_read_scatemsl, mem_write_scatems, mem_write_scatemsw, mem_write_scatemsl, ram + 0xA0000, MEM_MAPPING_INTERNAL, NULL); } - // Need to RAM 512kb clipping emulation if only 256KB or 64KB modules installed in memory bank. - // TODO - 512KB clipping should be applied all RAM refer. + /* Need to RAM 512kb clipping emulation if only 256KB or 64KB modules installed in memory bank. + TODO - 512KB clipping should be applied all RAM refer. */ mem_mapping_add(&scat_512k_clip_mapping, 0x80000, 0x20000, mem_read_scatems, mem_read_scatemsw, mem_read_scatemsl, mem_write_scatems, mem_write_scatemsw, mem_write_scatemsl, ram, MEM_MAPPING_INTERNAL, NULL); mem_mapping_disable(&scat_512k_clip_mapping); - // --- + /* --- */ scat_set_xms_bound(0); scat_shadow_state_update(); diff --git a/src/scat.h b/src/scat.h deleted file mode 100644 index 040a0a69a..000000000 --- a/src/scat.h +++ /dev/null @@ -1,25 +0,0 @@ -/* Copyright holders: Greatpsycho - see COPYING for more details -*/ -#define SCAT_DMA_WAIT_STATE_CONTROL 0x01 -#define SCAT_VERSION 0x40 -#define SCAT_CLOCK_CONTROL 0x41 -#define SCAT_PERIPHERAL_CONTROL 0x44 -#define SCAT_MISCELLANEOUS_STATUS 0x45 -#define SCAT_POWER_MANAGEMENT 0x46 -#define SCAT_ROM_ENABLE 0x48 -#define SCAT_RAM_WRITE_PROTECT 0x49 -#define SCAT_SHADOW_RAM_ENABLE_1 0x4A -#define SCAT_SHADOW_RAM_ENABLE_2 0x4B -#define SCAT_SHADOW_RAM_ENABLE_3 0x4C -#define SCAT_DRAM_CONFIGURATION 0x4D -#define SCAT_EXTENDED_BOUNDARY 0x4E -#define SCAT_EMS_CONTROL 0x4F - -typedef struct scat_t -{ - uint8_t regs_2x8; - uint8_t regs_2x9; -} scat_t; - -void scat_init(); diff --git a/src/scsi.c b/src/scsi.c index 539c50791..186a2495a 100644 --- a/src/scsi.c +++ b/src/scsi.c @@ -1,96 +1,162 @@ -/* Copyright holders: SA1988, Tenshi - see COPYING for more details -*/ -/*SCSI layer emulation*/ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Handling of the SCSI controllers. + * + * NOTE: THIS IS CURRENTLY A MESS, but will be cleaned up as I go. + * + * Version: @(#)scsi.c 1.0.0 2017/06/14 + * + * Authors: Fred N. van Kempen, + * Original Buslogic version by SA1988 and Miran Grca. + * Copyright 2017 Fred N. van Kempen. + */ #include #include #include "86box.h" #include "ibm.h" +#include "timer.h" #include "device.h" - #include "cdrom.h" #include "scsi.h" +#include "scsi_aha154x.h" +#include "scsi_buslogic.h" -#include "timer.h" -int SCSICallback[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; -uint8_t scsi_cdrom_id = 3; /*common setting*/ +uint8_t SCSIPhase = SCSI_PHASE_BUS_FREE; +uint8_t SCSIStatus = SCSI_STATUS_OK; +uint8_t scsi_cdrom_id = 3; /*common setting*/ +char scsi_fn[SCSI_NUM][512]; +uint16_t scsi_hd_location[SCSI_NUM]; -//Get the transfer length of the command -void SCSIGetLength(uint8_t id, int *datalen) +int scsi_card_current = 0; +int scsi_card_last = 0; + + +typedef struct { + char name[64]; + char internal_name[32]; + device_t *device; + void (*reset)(void *p); +} SCSI_CARD; + + +static SCSI_CARD scsi_cards[] = { + { "None", "none", NULL, NULL }, + { "Adaptec AHA-1540B", "aha1540b", &aha1540b_device, aha_device_reset }, + { "Adaptec AHA-1542CF", "aha1542cf", &aha1542cf_device, aha_device_reset }, + { "Adaptec AHA-1640", "aha1640", &aha1640_device, aha_device_reset }, + { "BusLogic BT-542B", "bt542b", &buslogic_device, BuslogicDeviceReset }, + { "BusLogic BT-958D PCI", "bt958d", &buslogic_pci_device, BuslogicDeviceReset }, + { "", "", NULL, NULL }, +}; + + +int scsi_card_available(int card) { - *datalen = SCSIDevices[id].CmdBufferLength; + if (scsi_cards[card].device) + return(device_available(scsi_cards[card].device)); + + return(1); } -//Execute SCSI command -void SCSIExecCommand(uint8_t id, uint8_t *buffer, uint8_t *cdb) + +char *scsi_card_getname(int card) { - SCSICDROM_Command(id, buffer, cdb); + return(scsi_cards[card].name); } -//Read pending data from the resulting SCSI command -void SCSIReadData(uint8_t id, uint8_t *cdb, uint8_t *data, int datalen) + +device_t *scsi_card_getdevice(int card) { - SCSICDROM_ReadData(id, cdb, data, datalen); + return(scsi_cards[card].device); } -///// -void SCSIDMAResetPosition(uint8_t Id) + +int scsi_card_has_config(int card) { - //Reset position in memory after reaching its limit - SCSIDevices[Id].pos = 0; + if (! scsi_cards[card].device) return(0); + + return(scsi_cards[card].device->config ? 1 : 0); } -//Read data from buffer with given position in buffer memory -void SCSIRead(uint8_t Id, uint8_t *dstbuf, uint8_t *srcbuf, uint32_t len_size) + +char *scsi_card_get_internal_name(int card) { - if (!len_size) //If there's no data, don't try to do anything. - return; + return(scsi_cards[card].internal_name); +} + + +int scsi_card_get_from_internal_name(char *s) +{ + int c = 0; + + while (strlen(scsi_cards[c].internal_name)) { + if (!strcmp(scsi_cards[c].internal_name, s)) + return(c); + c++; + } - int c; - - for (c = 0; c <= len_size; c++) //Count as many bytes as the length of the buffer is requested + return(0); +} + + +void scsi_card_init() +{ + if (scsi_cards[scsi_card_current].device) + device_add(scsi_cards[scsi_card_current].device); + + scsi_card_last = scsi_card_current; +} + + +void scsi_card_reset(void) +{ + void *p = NULL; + + if (scsi_cards[scsi_card_current].device) + { + p = device_get_priv(scsi_cards[scsi_card_current].device); + if (p) { - memcpy(dstbuf, srcbuf + SCSIDevices[Id].pos, len_size); - SCSIDevices[Id].pos = c; - - //pclog("SCSI Read: position at %i\n", SCSIDevices[Id].pos); + if (scsi_cards[scsi_card_current].reset) + { + scsi_cards[scsi_card_current].reset(p); + } } + } } -//Write data to buffer with given position in buffer memory -void SCSIWrite(uint8_t Id, uint8_t *srcbuf, uint8_t *dstbuf, uint32_t len_size) + +/* Initialization function for the SCSI layer */ +void SCSIReset(uint8_t id, uint8_t lun) { - int c; - - for (c = 0; c <= len_size; c++) //Count as many bytes as the length of the buffer is requested + uint8_t cdrom_id = scsi_cdrom_drives[id][lun]; + uint8_t hdc_id = scsi_hard_disks[id][lun]; + + if (hdc_id != 0xff) { + scsi_hd_reset(cdrom_id); + SCSIDevices[id][lun].LunType = SCSI_DISK; + } else { + if (cdrom_id != 0xff) { - memcpy(srcbuf + SCSIDevices[Id].pos, dstbuf, len_size); - SCSIDevices[Id].pos = c; - - //pclog("SCSI Write: position at %i\n", SCSIDevices[Id].pos); - } -} -///// - -//Initialization function for the SCSI layer -void SCSIReset(uint8_t Id) -{ - page_flags[GPMODE_CDROM_AUDIO_PAGE] &= 0xFD; /* Clear changed flag for CDROM AUDIO mode page. */ - memset(mode_pages_in[GPMODE_CDROM_AUDIO_PAGE], 0, 256); /* Clear the page itself. */ - - SCSICallback[Id]=0; - - if (cdrom_enabled && scsi_cdrom_enabled) - { - SCSIDevices[Id].LunType = SCSI_CDROM; + cdrom_reset(cdrom_id); + SCSIDevices[id][lun].LunType = SCSI_CDROM; } else { - SCSIDevices[Id].LunType = SCSI_NONE; + SCSIDevices[id][lun].LunType = SCSI_NONE; } - - page_flags[GPMODE_CDROM_AUDIO_PAGE] &= ~PAGE_CHANGED; - - SCSISense.UnitAttention = 0; + } + + if(SCSIDevices[id][lun].CmdBuffer != NULL) + { + free(SCSIDevices[id][lun].CmdBuffer); + SCSIDevices[id][lun].CmdBuffer = NULL; + } } diff --git a/src/scsi.h b/src/scsi.h index 44a3ddfd7..d0e4bfb91 100644 --- a/src/scsi.h +++ b/src/scsi.h @@ -1,34 +1,39 @@ /* Copyright holders: SA1988 see COPYING for more details */ -#ifndef __SCSI_H__ -#define __SCSI_H__ +#ifndef SCSI_H +#define SCSI_H -//#include "scattergather.h" - -#include "timer.h" #define SCSI_TIME (5 * 100 * (1 << TIMER_SHIFT)) -/* SCSI Commands */ + +/* SCSI commands. */ #define GPCMD_TEST_UNIT_READY 0x00 +#define GPCMD_REZERO_UNIT 0x01 #define GPCMD_REQUEST_SENSE 0x03 +#define GPCMD_FORMAT_UNIT 0x04 #define GPCMD_READ_6 0x08 +#define GPCMD_WRITE_6 0x0a #define GPCMD_SEEK_6 0x0b #define GPCMD_INQUIRY 0x12 +#define GPCMD_VERIFY_6 0x13 #define GPCMD_MODE_SELECT_6 0x15 #define GPCMD_MODE_SENSE_6 0x1a #define GPCMD_START_STOP_UNIT 0x1b #define GPCMD_PREVENT_REMOVAL 0x1e #define GPCMD_READ_CDROM_CAPACITY 0x25 #define GPCMD_READ_10 0x28 +#define GPCMD_WRITE_10 0x2a #define GPCMD_SEEK_10 0x2b +#define GPCMD_VERIFY_10 0x2f #define GPCMD_READ_SUBCHANNEL 0x42 #define GPCMD_READ_TOC_PMA_ATIP 0x43 #define GPCMD_READ_HEADER 0x44 #define GPCMD_PLAY_AUDIO_10 0x45 #define GPCMD_GET_CONFIGURATION 0x46 #define GPCMD_PLAY_AUDIO_MSF 0x47 +#define GPCMD_PLAY_AUDIO_TRACK_INDEX 0x48 #define GPCMD_GET_EVENT_STATUS_NOTIFICATION 0x4a #define GPCMD_PAUSE_RESUME 0x4b #define GPCMD_STOP_PLAY_SCAN 0x4e @@ -38,13 +43,21 @@ #define GPCMD_MODE_SENSE_10 0x5a #define GPCMD_PLAY_AUDIO_12 0xa5 #define GPCMD_READ_12 0xa8 +#define GPCMD_WRITE_12 0xaa #define GPCMD_READ_DVD_STRUCTURE 0xad /* For reading. */ +#define GPCMD_VERIFY_12 0xaf +#define GPCMD_PLAY_CD_OLD 0xb4 +#define GPCMD_READ_CD_OLD 0xb8 #define GPCMD_READ_CD_MSF 0xb9 +#define GPCMD_SCAN 0xba #define GPCMD_SET_SPEED 0xbb #define GPCMD_PLAY_CD 0xbc #define GPCMD_MECHANISM_STATUS 0xbd #define GPCMD_READ_CD 0xbe #define GPCMD_SEND_DVD_STRUCTURE 0xbf /* This is for writing only, irrelevant to PCem. */ +#define GPCMD_PAUSE_RESUME_ALT 0xc2 +#define GPCMD_SCAN_ALT 0xcd /* Should be equivalent to 0xba */ +#define GPCMD_SET_SPEED_ALT 0xda /* Should be equivalent to 0xbb */ /* Mode page codes for mode sense/set */ #define GPMODE_R_W_ERROR_PAGE 0x01 @@ -65,21 +78,30 @@ /* SCSI Additional Sense Codes */ #define ASC_AUDIO_PLAY_OPERATION 0x00 +#define ASC_NOT_READY 0x04 #define ASC_ILLEGAL_OPCODE 0x20 +#define ASC_LBA_OUT_OF_RANGE 0x21 #define ASC_INV_FIELD_IN_CMD_PACKET 0x24 +#define ASC_INV_LUN 0x25 +#define ASC_INV_FIELD_IN_PARAMETER_LIST 0x26 +#define ASC_WRITE_PROTECTED 0x27 #define ASC_MEDIUM_MAY_HAVE_CHANGED 0x28 -#define ASC_INCOMPATIBLE_FORMAT 0x30 +#define ASC_CAPACITY_DATA_CHANGED 0x2A +#define ASC_INCOMPATIBLE_FORMAT 0x30 #define ASC_MEDIUM_NOT_PRESENT 0x3a #define ASC_DATA_PHASE_ERROR 0x4b #define ASC_ILLEGAL_MODE_FOR_THIS_TRACK 0x64 +#define ASCQ_UNIT_IN_PROCESS_OF_BECOMING_READY 0x01 +#define ASCQ_INITIALIZING_COMMAND_REQUIRED 0x02 +#define ASCQ_CAPACITY_DATA_CHANGED 0x09 #define ASCQ_AUDIO_PLAY_OPERATION_IN_PROGRESS 0x11 -#define ASCQ_AUDIO_PLAY_OPERATION_PAUSED 0x12 -#define ASCQ_AUDIO_PLAY_OPERATION_COMPLETED 0x13 +#define ASCQ_AUDIO_PLAY_OPERATION_PAUSED 0x12 +#define ASCQ_AUDIO_PLAY_OPERATION_COMPLETED 0x13 /* Tell RISC OS that we have a 4x CD-ROM drive (600kb/sec data, 706kb/sec raw). Not that it means anything */ -#define CDROM_SPEED 706 +#define CDROM_SPEED 706 /* 0x2C2 */ /* Some generally useful CD-ROM information */ #define CD_MINS 75 /* max. minutes per CD */ @@ -144,14 +166,15 @@ #define MMC_PROFILE_HDDVD_RW_DL 0x005A #define MMC_PROFILE_INVALID 0xFFFF +#define SCSI_ONLY 32 +#define ATAPI_ONLY 16 +#define IMPLEMENTED 8 #define NONDATA 4 #define CHECK_READY 2 #define ALLOW_UA 1 extern uint8_t SCSICommandTable[0x100]; -#define IMPLEMENTED 1 - extern uint8_t mode_sense_pages[0x40]; extern int readcdmode; @@ -175,7 +198,6 @@ int MediaPresent; extern uint8_t SCSIStatus; extern uint8_t SCSIPhase; -extern int SCSICallback[16]; extern uint8_t scsi_cdrom_id; struct @@ -192,52 +214,11 @@ extern int cd_status; extern int prev_status; #define SCSI_NONE 0 -#define SCSI_HDD 1 /*not present yet*/ +#define SCSI_DISK 1 #define SCSI_CDROM 2 #define MSFtoLBA(m,s,f) ((((m*60)+s)*75)+f) -typedef struct __attribute__((packed)) -{ - uint8_t user_data[2048]; - uint8_t ecc[288]; -} m1_data_t; - -typedef struct __attribute__((packed)) -{ - uint8_t sub_header[8]; - uint8_t user_data[2328]; -} m2_data_t; - -typedef union __attribute__((packed)) -{ - m1_data_t m1_data; - m2_data_t m2_data; - uint8_t raw_data[2352]; -} sector_data_t; - -typedef struct __attribute__((packed)) -{ - uint8_t sync[12]; - uint8_t header[4]; - sector_data_t data; - uint8_t c2[296]; - uint8_t subchannel_raw[96]; - uint8_t subchannel_q[16]; - uint8_t subchannel_rw[96]; -} cdrom_sector_t; - -typedef union __attribute__((packed)) -{ - cdrom_sector_t cdrom_sector; - uint8_t buffer[2856]; -} sector_buffer_t; - -extern sector_buffer_t cdrom_sector_buffer; - -extern int cdrom_sector_type, cdrom_sector_flags; -extern int cdrom_sector_size, cdrom_sector_ismsf; - #define SCSI_PHASE_DATAOUT ( 0 ) #define SCSI_PHASE_DATAIN ( 1 ) #define SCSI_PHASE_COMMAND ( 2 ) @@ -249,14 +230,13 @@ extern int cdrom_sector_size, cdrom_sector_ismsf; struct { - uint32_t pos; - uint8_t CmdBuffer[512*512]; + uint8_t *CmdBuffer; uint32_t CmdBufferLength; int LunType; uint32_t InitLength; -} SCSIDevices[16]; +} SCSIDevices[16][8]; -extern void SCSIReset(uint8_t Id); +extern void SCSIReset(uint8_t id, uint8_t lun); uint32_t SCSICDROMModeSense(uint8_t *buf, uint32_t pos, uint8_t type); uint8_t SCSICDROMSetProfile(uint8_t *buf, uint8_t *index, uint16_t profile); @@ -266,6 +246,67 @@ void SCSICDROM_Insert(); int cdrom_add_error_and_subchannel(uint8_t *b, int real_sector_type); int cdrom_LBAtoMSF_accurate(); -int cdrom_read_data(uint8_t *buffer); -#endif \ No newline at end of file +int mode_select_init(uint8_t command, uint16_t pl_length, uint8_t do_save); +int mode_select_terminate(int force); +int mode_select_write(uint8_t val); + +extern int scsi_card_current; + +int scsi_card_available(int card); +char *scsi_card_getname(int card); +struct device_t *scsi_card_getdevice(int card); +int scsi_card_has_config(int card); +char *scsi_card_get_internal_name(int card); +int scsi_card_get_from_internal_name(char *s); +void scsi_card_init(); +void scsi_card_reset(void); + +extern uint8_t scsi_hard_disks[16][8]; + +int scsi_hd_err_stat_to_scsi(uint8_t id); +int scsi_hd_phase_to_scsi(uint8_t id); +int find_hdc_for_scsi_id(uint8_t scsi_id, uint8_t scsi_lun); +void build_scsi_hd_map(); +void scsi_hd_reset(uint8_t id); +void scsi_hd_request_sense_for_scsi(uint8_t id, uint8_t *buffer, uint8_t alloc_length); +void scsi_hd_command(uint8_t id, uint8_t *cdb); +void scsi_hd_callback(uint8_t id); + + +#pragma pack(push,1) +typedef struct { + uint8_t hi; + uint8_t mid; + uint8_t lo; +} addr24; +#pragma pack(pop) + +#define ADDR_TO_U32(x) (((x).hi<<16)|((x).mid<<8)|((x).lo&0xFF)) +#define U32_TO_ADDR(a,x) do {(a).hi=(x)>>16;(a).mid=(x)>>8;(a).lo=(x)&0xFF;}while(0) + + +/* + * + * Scatter/Gather Segment List Definitions + * + * Adapter limits + */ +#define MAX_SG_DESCRIPTORS 32 /* Always make the array 32 elements long, if less are used, that's not an issue. */ + +#pragma pack(push,1) +typedef struct { + uint32_t Segment; + uint32_t SegmentPointer; +} SGE32; +#pragma pack(pop) + +#pragma pack(push,1) +typedef struct { + addr24 Segment; + addr24 SegmentPointer; +} SGE; +#pragma pack(pop) + + +#endif diff --git a/src/scsi_aha154x.c b/src/scsi_aha154x.c new file mode 100644 index 000000000..83d32d55d --- /dev/null +++ b/src/scsi_aha154x.c @@ -0,0 +1,2465 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Implementation of the AHA-154x series of SCSI Host Adapters + * made by Adaptec, Inc. These controllers were designed for + * the ISA bus. + * + * NOTE: THIS IS CURRENTLY A MESS, but will be cleaned up as I go. + * + * Version: @(#)scsi_aha154x.c 1.0.7 2017/06/14 + * + * Authors: Fred N. van Kempen, + * Original Buslogic version by SA1988 and Miran Grca. + * Copyright 2017 Fred N. van Kempen. + */ +#include +#include +#include +#include +#include +#include "ibm.h" +#include "io.h" +#include "mca.h" +#include "mem.h" +#include "mca.h" +#include "rom.h" +#include "dma.h" +#include "pic.h" +#include "timer.h" +#include "device.h" +#include "cdrom.h" +#include "scsi.h" +#include "scsi_disk.h" +#include "scsi_aha154x.h" + + +#define AHA AHA154xCF /* set desired card type */ +#define AHA154xB 1 /* AHA-154x Rev.B */ +#define AHA154xC 2 /* AHA-154x Rev.C */ +#define AHA154xCF 3 /* AHA-154x Rev.CF */ +#define AHA154xCP 4 /* AHA-154x Rev.CP */ + + +#if AHA == AHA154xB +# define ROMFILE L"roms/adaptec/aha1540b310.bin" +# define AHA_BID 'A' /* AHA-154x B */ +#endif + +#if AHA == AHA154xC +# define ROMFILE L"roms/adaptec/aha1542c101.bin" +# define AHA_BID 'D' /* AHA-154x C */ +# define ROM_FWHIGH 0x0022 /* firmware version (hi/lo) */ +# define ROM_SHRAM 0x3F80 /* shadow RAM address base */ +# define ROM_SHRAMSZ 128 /* size of shadow RAM */ +# define ROM_IOADDR 0x3F7E /* [2:0] idx into addr table */ +# define EEP_SIZE 32 /* 32 bytes of storage */ +#endif + +#if AHA == AHA154xCF +# define ROMFILE L"roms/adaptec/aha1542cf201.bin" +# define AHA_BID 'E' /* AHA-154x CF */ +# define ROM_FWHIGH 0x0022 /* firmware version (hi/lo) */ +# define ROM_SHRAM 0x3F80 /* shadow RAM address base */ +# define ROM_SHRAMSZ 128 /* size of shadow RAM */ +# define ROM_IOADDR 0x3F7E /* [2:0] idx into addr table */ +# define EEP_SIZE 32 /* 32 bytes of storage */ +#endif + +#if AHA == AHA154xCP +# define ROMFILE L"roms/adaptec/aha1542cp102.bin" +# define AHA_BID 'F' /* AHA-154x CP */ +# define ROM_FWHIGH 0x0055 /* firmware version (hi/lo) */ +# define ROM_SHRAM 0x3F80 /* shadow RAM address base */ +# define ROM_SHRAMSZ 128 /* size of shadow RAM */ +# define ROM_IOADDR 0x3F7E /* [2:0] idx into addr table */ +# define EEP_SIZE 32 /* 32 bytes of storage */ +#endif + +#define ROM_SIZE 16384 /* one ROM is 16K */ + + +/* EEPROM map and bit definitions. */ +#define EE0_HOSTID 0x07 /* EE(0) [2:0] */ +#define EE0_ALTFLOP 0x80 /* EE(0) [7] FDC at 370h */ +#define EE1_IRQCH 0x07 /* EE(1) [3:0] */ +#define EE1_DMACH 0x70 /* EE(1) [7:4] */ +#define EE2_RMVOK 0x01 /* EE(2) [0] Support removable disks */ +#define EE2_HABIOS 0x02 /* EE(2) [1] HA Bios Space Reserved */ +#define EE2_INT19 0x04 /* EE(2) [2] HA Bios Controls INT19 */ +#define EE2_DYNSCAN 0x08 /* EE(2) [3] Dynamically scan bus */ +#define EE2_TWODRV 0x10 /* EE(2) [4] Allow more than 2 drives */ +#define EE2_SEEKRET 0x20 /* EE(2) [5] Immediate return on seek */ +#define EE2_EXT1G 0x80 /* EE(2) [7] Extended Translation >1GB */ +#define EE3_SPEED 0x00 /* EE(3) [7:0] DMA Speed */ +#define SPEED_33 0xFF +#define SPEED_50 0x00 +#define SPEED_56 0x04 +#define SPEED_67 0x01 +#define SPEED_80 0x02 +#define SPEED_10 0x03 +#define EE4_FLOPTOK 0x80 /* EE(4) [7] Support Flopticals */ +#define EE6_PARITY 0x01 /* EE(6) [0] parity check enable */ +#define EE6_TERM 0x02 /* EE(6) [1] host term enable */ +#define EE6_RSTBUS 0x04 /* EE(6) [2] reset SCSI bus on boot */ +#define EEE_SYNC 0x01 /* EE(E) [0] Enable Sync Negotiation */ +#define EEE_DISCON 0x02 /* EE(E) [1] Enable Disconnection */ +#define EEE_FAST 0x04 /* EE(E) [2] Enable FAST SCSI */ +#define EEE_START 0x08 /* EE(E) [3] Enable Start Unit */ + + +/* + * Host Adapter I/O ports. + * + * READ Port x+0: STATUS + * WRITE Port x+0: CONTROL + * + * READ Port x+1: DATA + * WRITE Port x+1: COMMAND + * + * READ Port x+2: INTERRUPT STATUS + * WRITE Port x+2: (undefined?) + * + * R/W Port x+3: (undefined) + */ + +/* WRITE CONTROL commands. */ +#define CTRL_HRST 0x80 /* Hard reset */ +#define CTRL_SRST 0x40 /* Soft reset */ +#define CTRL_IRST 0x20 /* interrupt reset */ +#define CTRL_SCRST 0x10 /* SCSI bus reset */ + +/* READ STATUS. */ +#define STAT_STST 0x80 /* self-test in progress */ +#define STAT_DFAIL 0x40 /* internal diagnostic failure */ +#define STAT_INIT 0x20 /* mailbox initialization required */ +#define STAT_IDLE 0x10 /* HBA is idle */ +#define STAT_CDFULL 0x08 /* Command/Data output port is full */ +#define STAT_DFULL 0x04 /* Data input port is full */ +#define STAT_INVCMD 0x01 /* Invalid command */ + +/* READ/WRITE DATA. */ +#define CMD_NOP 0x00 /* No operation */ +#define CMD_MBINIT 0x01 /* mailbox initialization */ +#define CMD_START_SCSI 0x02 /* Start SCSI command */ +#define CMD_BIOS 0x03 /* Execute ROM BIOS command */ +#define CMD_INQUIRY 0x04 /* Adapter inquiry */ +#define CMD_EMBOI 0x05 /* enable Mailbox Out Interrupt */ +#define CMD_SELTIMEOUT 0x06 /* Set SEL timeout */ +#define CMD_BUSON_TIME 0x07 /* set bus-On time */ +#define CMD_BUSOFF_TIME 0x08 /* set bus-off time */ +#define CMD_DMASPEED 0x09 /* set ISA DMA speed */ +#define CMD_RETDEVS 0x0A /* return installed devices */ +#define CMD_RETCONF 0x0B /* return configuration data */ +#define CMD_TARGET 0x0C /* set HBA to target mode */ +#define CMD_RETSETUP 0x0D /* return setup data */ +#define CMD_ECHO 0x1F /* ECHO command data */ + +/* READ INTERRUPT STATUS. */ +#define INTR_ANY 0x80 /* any interrupt */ +#define INTR_SRCD 0x08 /* SCSI reset detected */ +#define INTR_HACC 0x04 /* HA command complete */ +#define INTR_MBOA 0x02 /* MBO empty */ +#define INTR_MBIF 0x01 /* MBI full */ + + +static rom_t aha_bios; /* active ROM */ +static uint8_t *aha_rom1; /* main BIOS */ +static uint8_t *aha_rom2; /* SCSI-Select */ +#ifdef EEP_SIZE +static uint8_t aha_eep[EEP_SIZE]; /* EEPROM storage */ +#endif +static uint16_t aha_ports[] = { + 0x0330, 0x0334, 0x0230, 0x0234, + 0x0130, 0x0134, 0x0000, 0x0000 +}; + + +#ifdef WALTJE +int aha_do_log = 1; +# define ENABLE_AHA154X_LOG +#else +int aha_do_log = 0; +#endif + + +static void +aha_log(const char *format, ...) +{ +#ifdef ENABLE_AHA154X_LOG + va_list ap; + + if (aha_do_log) { + va_start(ap, format); + vprintf(format, ap); + va_end(ap); + fflush(stdout); + } +#endif +} +#define pclog aha_log + + +/* + * Write data to the BIOS space. + * + * AHA-1542C's and up have a feature where they map a 128-byte + * RAM space into the ROM BIOS' address space, and then use it + * as working memory. This function implements the writing to + * that memory. + * + * We enable/disable this memory through AHA command 0x24. + */ +static void +aha_mem_write(uint32_t addr, uint8_t val, void *priv) +{ + rom_t *rom = (rom_t *)priv; + +#if 0 + pclog("AHA1542x: writing to BIOS space, %06lX, val %02x\n", addr, val); + pclog(" called from %04X:%04X\n", CS, cpu_state.pc); +#endif + if ((addr & rom->mask) >= 0x3F80) + rom->rom[addr & rom->mask] = val; +} + + +static uint8_t +aha_mem_read(uint32_t addr, void *priv) +{ + rom_t *rom = (rom_t *)priv; + + return(rom->rom[addr & rom->mask]); +} + + +static uint16_t +aha_mem_readw(uint32_t addr, void *priv) +{ + rom_t *rom = (rom_t *)priv; + + return(*(uint16_t *)&rom->rom[addr & rom->mask]); +} + + +static uint32_t +aha_mem_readl(uint32_t addr, void *priv) +{ + rom_t *rom = (rom_t *)priv; + + return(*(uint32_t *)&rom->rom[addr & rom->mask]); +} + + +#ifdef ROM_IOADDR +/* + * Patch the ROM BIOS image for stuff Adaptec deliberately + * made hard to understand. Well, maybe not, maybe it was + * their way of handling issues like these at the time.. + * + * Patch 1: emulate the I/O ADDR SW setting by patching a + * byte in the BIOS that indicates the I/O ADDR + * switch setting on the board. + */ +static void +aha_patch(uint8_t *romptr, uint16_t ioaddr) +{ + int i; + + /* Look up the I/O address in the table. */ + for (i=0; i<8; i++) + if (aha_ports[i] == ioaddr) break; + if (i == 8) { + pclog("AHA154x: bad news, invalid I/O address %04x selected!\n", + ioaddr); + return; + } + romptr[ROM_IOADDR] = (unsigned char)i; +} +#endif + + +/* Initialize AHA-154xNN-specific stuff. */ +static void +aha154x_bios(uint16_t ioaddr, uint32_t memaddr, aha_info *aha, int irq, int dma) +{ + uint32_t bios_size; + uint32_t bios_addr; + uint32_t bios_mask; + wchar_t *bios_path; + uint32_t temp; + FILE *f; + + /* Set BIOS load address. */ + bios_addr = memaddr; + bios_path = ROMFILE; + pclog_w(L"AHA154x: loading BIOS from '%s'\n", bios_path); + + /* Open the BIOS image file and make sure it exists. */ + if ((f = romfopen(bios_path, L"rb")) == NULL) { + pclog("AHA154x: BIOS ROM not found!\n"); + return; + } + + /* + * Manually load and process the ROM image. + * + * We *could* use the system "rom_init" function here, but for + * this special case, we can't: we may need WRITE access to the + * memory later on. + */ + (void)fseek(f, 0L, SEEK_END); + temp = ftell(f); + (void)fseek(f, 0L, SEEK_SET); + + /* Load first chunk of BIOS (which is the main BIOS, aka ROM1.) */ + aha_rom1 = malloc(ROM_SIZE); + (void)fread(aha_rom1, ROM_SIZE, 1, f); + temp -= ROM_SIZE; + if (temp > 0) { + aha_rom2 = malloc(ROM_SIZE); + (void)fread(aha_rom2, ROM_SIZE, 1, f); + temp -= ROM_SIZE; + } else { + aha_rom2 = NULL; + } + if (temp != 0) { + pclog("AHA154x: BIOS ROM size invalid!\n"); + free(aha_rom1); + if (aha_rom2 != NULL) + free(aha_rom2); + (void)fclose(f); + return; + } + temp = ftell(f); + if (temp > ROM_SIZE) + temp = ROM_SIZE; + (void)fclose(f); + + /* Adjust BIOS size in chunks of 2K, as per BIOS spec. */ + bios_size = 0x10000; + if (temp <= 0x8000) + bios_size = 0x8000; + if (temp <= 0x4000) + bios_size = 0x4000; + if (temp <= 0x2000) + bios_size = 0x2000; + bios_mask = (bios_size - 1); + pclog("AHA154x: BIOS at 0x%06lX, size %lu, mask %08lx\n", + bios_addr, bios_size, bios_mask); + + /* Initialize the ROM entry for this BIOS. */ + memset(&aha_bios, 0x00, sizeof(rom_t)); + + /* Enable ROM1 into the memory map. */ + aha_bios.rom = aha_rom1; + + /* Set up an address mask for this memory. */ + aha_bios.mask = bios_mask; + + /* Map this system into the memory map. */ + mem_mapping_add(&aha_bios.mapping, bios_addr, bios_size, + aha_mem_read, aha_mem_readw, aha_mem_readl, + aha_mem_write, NULL, NULL, + aha_bios.rom, MEM_MAPPING_EXTERNAL, &aha_bios); + +#ifdef ROM_IOADDR + /* Patch the ROM BIOS image to work with us. */ + aha_patch(aha_bios.rom, ioaddr); +#endif + +#if ROM_FWHIGH + /* Read firmware version from the BIOS. */ + aha->fwh = aha_bios.rom[ROM_FWHIGH]; + aha->fwl = aha_bios.rom[ROM_FWHIGH+1]; +#else + /* Fake BIOS firmware version. */ + aha->fwh = '1'; + aha->fwl = '0'; +#endif + aha->bid = AHA_BID; + + /* + * Do a checksum on the ROM. + * The BIOS ROMs on the 154xC(F) boards will always fail + * the checksum, because they are incomplete: on the real + * boards, a shadow RAM and some other (config) registers + * are mapped into its space. It is assumed that boards + * have logic that automatically generate a "fixup" byte + * at the end of the data to 'make up' for this. + * + * We emulated some of those in the patch routine, so now + * it is time to "fix up" the BIOS image so that the main + * (system) BIOS considers it valid. + */ +again: + bios_mask = 0; + for (temp=0; temp<16384; temp++) + bios_mask += aha_bios.rom[temp]; + bios_mask &= 0xff; + if (bios_mask != 0x00) { + pclog("AHA154x: fixing BIOS checksum (%02x) ..\n", bios_mask); + aha_bios.rom[temp-1] += (256 - bios_mask); + goto again; + } + + /* Enable the memory. */ + mem_mapping_enable(&aha_bios.mapping); + mem_mapping_set_addr(&aha_bios.mapping, bios_addr, bios_size); + +#ifdef EEP_SIZE + /* Initialize the on-board EEPROM. */ + memset(aha_eep, 0x00, EEP_SIZE); + aha_eep[0] = 7; /* SCSI ID 7 */ + aha_eep[0] |= (0x10 | 0x20 | 0x40); + aha_eep[1] = irq-9; /* IRQ15 */ + aha_eep[1] |= (dma<<4); /* DMA6 */ + aha_eep[2] = (EE2_DYNSCAN | /* BIOS Space Reserved */ + EE2_EXT1G | EE2_RMVOK); /* Immediate return on seek */ + aha_eep[3] = SPEED_50; /* speed 5.0 MB/s */ + aha_eep[6] = (EE6_TERM | /* host term enable */ + EE6_RSTBUS); /* reset SCSI bus on boot */ +#endif +} + + +/* Mess with the AHA-154xCF's Shadow RAM. */ +static uint8_t +aha154x_shram(uint8_t cmd) +{ +#ifdef ROM_SHRAM + switch(cmd) { + case 0x00: /* disable, make it look like ROM */ + memset(&aha_bios.rom[ROM_SHRAM], 0xFF, ROM_SHRAMSZ); + break; + + case 0x02: /* clear it */ + memset(&aha_bios.rom[ROM_SHRAM], 0x00, ROM_SHRAMSZ); + break; + + case 0x03: /* enable, clear for use */ + memset(&aha_bios.rom[ROM_SHRAM], 0x00, ROM_SHRAMSZ); + break; + } +#endif + + /* Firmware expects 04 status. */ + return(0x04); +} + + +static uint8_t +aha154x_eeprom(uint8_t cmd,uint8_t arg,uint8_t len,uint8_t off,uint8_t *bufp) +{ + uint8_t r = 0xff; + + pclog("AHA154x: EEPROM cmd=%02x, arg=%02x len=%d, off=%02x\n", + cmd, arg, len, off); + +#ifdef EEP_SIZE + if ((off+len) > EEP_SIZE) return(r); /* no can do.. */ + + if (cmd == 0x22) { + /* Write data to the EEPROM. */ + memcpy(&aha_eep[off], bufp, len); + r = 0; + } + + if (cmd == 0x23) { + /* Read data from the EEPROM. */ + memcpy(bufp, &aha_eep[off], len); + r = len; + } +#endif + + return(r); +} + + +static uint8_t +aha154x_memory(uint8_t cmd) +{ + pclog("AHA154x: MEMORY cmd=%02x\n", cmd); + + if (cmd == 0x27) { + /* Enable the mapper, so, set ROM2 active. */ + aha_bios.rom = aha_rom2; + } + if (cmd == 0x26) { + /* Disable the mapper, so, set ROM1 active. */ + aha_bios.rom = aha_rom1; + } + + return(0); +} + + +#define AHA_RESET_DURATION_NS UINT64_C(50000000) + + +/* + * Auto SCSI structure which is located in host adapter RAM + * and contains several configuration parameters. + */ +#pragma pack(push,1) +typedef struct { + uint8_t aInternalSignature[2]; + uint8_t cbInformation; + uint8_t aHostAdaptertype[6]; + uint8_t uReserved1; + uint8_t fFloppyEnabled :1, + fFloppySecondary :1, + fLevelSensitiveInterrupt:1, + uReserved2 :2, + uSystemRAMAreForBIOS :3; + uint8_t uDMAChannel :7, + fDMAAutoConfiguration :1, + uIrqChannel :7, + fIrqAutoConfiguration :1; + uint8_t uDMATransferRate; + uint8_t uSCSIId; + uint8_t fLowByteTerminated :1, + fParityCheckingEnabled :1, + fHighByteTerminated :1, + fNoisyCablingEnvironment:1, + fFastSyncNegotiation :1, + fBusResetEnabled :1, + fReserved3 :1, + fActiveNegotiationEna :1; + uint8_t uBusOnDelay; + uint8_t uBusOffDelay; + uint8_t fHostAdapterBIOSEnabled :1, + fBIOSRedirectionOfInt19 :1, + fExtendedTranslation :1, + fMapRemovableAsFixed :1, + fReserved4 :1, + fBIOSMoreThan2Drives :1, + fBIOSInterruptMode :1, + fFlopticalSupport :1; + uint16_t u16DeviceEnabledMask; + uint16_t u16WidePermittedMask; + uint16_t u16FastPermittedMask; + uint16_t u16SynchronousPermittedMask; + uint16_t u16DisconnectPermittedMask; + uint16_t u16SendStartUnitCommandMask; + uint16_t u16IgnoreInBIOSScanMask; + unsigned char uPCIInterruptPin : 2; + unsigned char uHostAdapterIoPortAddress : 2; + uint8_t fStrictRoundRobinMode : 1; + uint8_t fVesaBusSpeedGreaterThan33MHz : 1; + uint8_t fVesaBurstWrite : 1; + uint8_t fVesaBurstRead : 1; + uint16_t u16UltraPermittedMask; + uint32_t uReserved5; + uint8_t uReserved6; + uint8_t uAutoSCSIMaximumLUN; + uint8_t fReserved7 : 1; + uint8_t fSCAMDominant : 1; + uint8_t fSCAMenabled : 1; + uint8_t fSCAMLevel2 : 1; + unsigned char uReserved8 : 4; + uint8_t fInt13Extension : 1; + uint8_t fReserved9 : 1; + uint8_t fCDROMBoot : 1; + unsigned char uReserved10 : 5; + unsigned char uBootTargetId : 4; + unsigned char uBootChannel : 4; + uint8_t fForceBusDeviceScanningOrder : 1; + unsigned char uReserved11 : 7; + uint16_t u16NonTaggedToAlternateLunPermittedMask; + uint16_t u16RenegotiateSyncAfterCheckConditionMask; + uint8_t aReserved12[10]; + uint8_t aManufacturingDiagnostic[2]; + uint16_t u16Checksum; +} AutoSCSIRam; +#pragma pack(pop) + +/* The local RAM. */ +#pragma pack(push,1) +typedef union { + uint8_t u8View[256]; /* byte view */ + struct { /* structured view */ + uint8_t u8Bios[64]; /* offset 0 - 63 is for BIOS */ + AutoSCSIRam autoSCSIData; /* Auto SCSI structure */ + } structured; +} HALocalRAM; +#pragma pack(pop) + +/* Structure for the INQUIRE_SETUP_INFORMATION reply. */ +#pragma pack(push,1) +typedef struct { + uint8_t uOffset :4, + uTransferPeriod :3, + fSynchronous :1; +} ReplyInquireSetupInformationSynchronousValue; +#pragma pack(pop) + +#pragma pack(push,1) +typedef struct { + uint8_t fSynchronousInitiationEnabled :1, + fParityCheckingEnabled :1, + uReserved1 :6; + uint8_t uBusTransferRate; + uint8_t uPreemptTimeOnBus; + uint8_t uTimeOffBus; + uint8_t cMailbox; + addr24 MailboxAddress; + ReplyInquireSetupInformationSynchronousValue SynchronousValuesId0To7[8]; + uint8_t uDisconnectPermittedId0To7; + uint8_t uSignature; + uint8_t uCharacterD; + uint8_t uHostBusType; + uint8_t uWideTransferPermittedId0To7; + uint8_t uWideTransfersActiveId0To7; + ReplyInquireSetupInformationSynchronousValue SynchronousValuesId8To15[8]; + uint8_t uDisconnectPermittedId8To15; + uint8_t uReserved2; + uint8_t uWideTransferPermittedId8To15; + uint8_t uWideTransfersActiveId8To15; +} ReplyInquireSetupInformation; +#pragma pack(pop) + + +#pragma pack(push,1) +typedef struct { + uint8_t Count; + addr24 Address; +} MailboxInit_t; +#pragma pack(pop) + + +/* + * Mailbox Definitions. + * + * Mailbox Out (MBO) command values. + */ +#define MBO_FREE 0x00 +#define MBO_START 0x01 +#define MBO_ABORT 0x02 + +/* Mailbox In (MBI) status values. */ +#define MBI_FREE 0x00 +#define MBI_SUCCESS 0x01 +#define MBI_ABORT 0x02 +#define MBI_NOT_FOUND 0x03 +#define MBI_ERROR 0x04 + + +#pragma pack(push,1) +typedef struct { + uint8_t CmdStatus; + addr24 CCBPointer; +} Mailbox_t; +#pragma pack(pop) + +#pragma pack(push,1) +typedef struct { + uint32_t CCBPointer; + union { + struct { + uint8_t Reserved[3]; + uint8_t ActionCode; + } out; + struct { + uint8_t HostStatus; + uint8_t TargetStatus; + uint8_t Reserved; + uint8_t CompletionCode; + } in; + } u; +} Mailbox32_t; +#pragma pack(pop) + + +/* + * + * CCB - SCSI Command Control Block + * + * The CCB is a superset of the CDB (Command Descriptor Block) + * and specifies detailed information about a SCSI command. + * + */ +/* Byte 0 Command Control Block Operation Code */ +#define SCSI_INITIATOR_COMMAND 0x00 +#define TARGET_MODE_COMMAND 0x01 +#define SCATTER_GATHER_COMMAND 0x02 +#define SCSI_INITIATOR_COMMAND_RES 0x03 +#define SCATTER_GATHER_COMMAND_RES 0x04 +#define BUS_RESET 0x81 + +/* Byte 1 Address and Direction Control */ +#define CCB_TARGET_ID_SHIFT 0x06 /* CCB Op Code = 00, 02 */ +#define CCB_INITIATOR_ID_SHIFT 0x06 /* CCB Op Code = 01 */ +#define CCB_DATA_XFER_IN 0x01 +#define CCB_DATA_XFER_OUT 0x02 +#define CCB_LUN_MASK 0x07 /* Logical Unit Number */ + +/* Byte 2 SCSI_Command_Length - Length of SCSI CDB + Byte 3 Request Sense Allocation Length */ +#define FOURTEEN_BYTES 0x00 /* Request Sense Buffer size */ +#define NO_AUTO_REQUEST_SENSE 0x01 /* No Request Sense Buffer */ + +/* Bytes 4, 5 and 6 Data Length - Data transfer byte count */ +/* Bytes 7, 8 and 9 Data Pointer - SGD List or Data Buffer */ +/* Bytes 10, 11 and 12 Link Pointer - Next CCB in Linked List */ +/* Byte 13 Command Link ID - TBD (I don't know yet) */ +/* Byte 14 Host Status - Host Adapter status */ +#define CCB_COMPLETE 0x00 /* CCB completed without error */ +#define CCB_LINKED_COMPLETE 0x0A /* Linked command completed */ +#define CCB_LINKED_COMPLETE_INT 0x0B /* Linked complete with intr */ +#define CCB_SELECTION_TIMEOUT 0x11 /* Set SCSI selection timed out */ +#define CCB_DATA_OVER_UNDER_RUN 0x12 +#define CCB_UNEXPECTED_BUS_FREE 0x13 /* Trg dropped SCSI BSY */ +#define CCB_PHASE_SEQUENCE_FAIL 0x14 /* Trg bus phase sequence fail */ +#define CCB_BAD_MBO_COMMAND 0x15 /* MBO command not 0, 1 or 2 */ +#define CCB_INVALID_OP_CODE 0x16 /* CCB invalid operation code */ +#define CCB_BAD_LINKED_LUN 0x17 /* Linked CCB LUN diff from 1st */ +#define CCB_INVALID_DIRECTION 0x18 /* Invalid target direction */ +#define CCB_DUPLICATE_CCB 0x19 /* Duplicate CCB */ +#define CCB_INVALID_CCB 0x1A /* Invalid CCB - bad parameter */ + +/* Byte 15 Target Status + + See scsi.h files for these statuses. + Bytes 16 and 17 Reserved (must be 0) + Bytes 18 through 18+n-1, where n=size of CDB Command Descriptor Block */ + +#pragma pack(push,1) +typedef struct { + uint8_t Opcode; + uint8_t Reserved1 :3, + ControlByte :2, + TagQueued :1, + QueueTag :2; + uint8_t CdbLength; + uint8_t RequestSenseLength; + uint32_t DataLength; + uint32_t DataPointer; + uint8_t Reserved2[2]; + uint8_t HostStatus; + uint8_t TargetStatus; + uint8_t Id; + uint8_t Lun :5, + LegacyTagEnable :1, + LegacyQueueTag :2; + uint8_t Cdb[12]; + uint8_t Reserved3[6]; + uint32_t SensePointer; +} CCB32; +#pragma pack(pop) + +#pragma pack(push,1) +typedef struct { + uint8_t Opcode; + uint8_t Lun :3, + ControlByte :2, + Id :3; + uint8_t CdbLength; + uint8_t RequestSenseLength; + addr24 DataLength; + addr24 DataPointer; + addr24 LinkPointer; + uint8_t LinkId; + uint8_t HostStatus; + uint8_t TargetStatus; + uint8_t Reserved[2]; + uint8_t Cdb[12]; +} CCB; +#pragma pack(pop) + +#pragma pack(push,1) +typedef struct { + uint8_t Opcode; + uint8_t Pad1 :3, + ControlByte :2, + Pad2 :3; + uint8_t CdbLength; + uint8_t RequestSenseLength; + uint8_t Pad3[10]; + uint8_t HostStatus; + uint8_t TargetStatus; + uint8_t Pad4[2]; + uint8_t Cdb[12]; +} CCBC; +#pragma pack(pop) + +#pragma pack(push,1) +typedef union { + CCB32 new; + CCB old; + CCBC common; +} CCBU; +#pragma pack(pop) + +#pragma pack(push,1) +typedef struct { + CCBU CmdBlock; + uint8_t *RequestSenseBuffer; + uint32_t CCBPointer; + int Is24bit; + uint8_t TargetID; + uint8_t LUN; + uint8_t HostStatus; + uint8_t TargetStatus; + uint8_t MailboxCompletionCode; +} Req_t; +#pragma pack(pop) + + +#pragma pack(push,1) +typedef struct { + rom_t bios; + int UseLocalRAM; + int StrictRoundRobinMode; + int ExtendedLUNCCBFormat; + HALocalRAM LocalRAM; + Req_t Req; + uint8_t Status; + uint8_t Interrupt; + uint8_t Geometry; + uint8_t Control; + uint8_t Command; + uint8_t CmdBuf[53]; + uint8_t CmdParam; + uint8_t CmdParamLeft; + uint8_t DataBuf[64]; + uint16_t DataReply; + uint16_t DataReplyLeft; + uint32_t MailboxCount; + uint32_t MailboxOutAddr; + uint32_t MailboxOutPosCur; + uint32_t MailboxInAddr; + uint32_t MailboxInPosCur; + int Base; + int Irq; + int DmaChannel; + int IrqEnabled; + int Mbx24bit; + int MailboxOutInterrupts; + int MbiActive[256]; + int PendingInterrupt; + int Lock; + mem_mapping_t mmio_mapping; + aha_info aha; + int chip; + uint8_t pos_regs[8]; +} aha_t; +#pragma pack(pop) + + +static int ResetCB = 0; +static int AHA_Callback = 0; +static int AHA_InOperation = 0; +static aha_t *ResetDev; + + +enum { + CHIP_AHA154XB, + CHIP_AHA154XCF, + CHIP_AHA1640 +}; + + +static void +ClearIntr(aha_t *dev) +{ + dev->Interrupt = 0; + pclog("AHA154X: lowering IRQ %i (stat 0x%02x)\n", + dev->Irq, dev->Interrupt); + picintc(1 << dev->Irq); + if (dev->PendingInterrupt) { + dev->Interrupt = dev->PendingInterrupt; + pclog("AHA154X: Raising Interrupt 0x%02X (Pending)\n", dev->Interrupt); + if (dev->MailboxOutInterrupts || !(dev->Interrupt & INTR_MBOA)) { + if (dev->IrqEnabled) picint(1 << dev->Irq); + } + dev->PendingInterrupt = 0; + } +} + + +static void +RaiseIntr(aha_t *dev, uint8_t Interrupt) +{ + if (dev->Interrupt & INTR_HACC) { + pclog("Pending IRQ\n"); + dev->PendingInterrupt = Interrupt; + } else { + dev->Interrupt = Interrupt; + pclog("Raising IRQ %i\n", dev->Irq); + if (dev->IrqEnabled) + picint(1 << dev->Irq); + } +} + + +static void +LocalRAM(aha_t *dev) +{ + /* + * These values are mostly from what I think is right + * looking at the dmesg output from a Linux guest inside + * a VMware server VM. + * + * So they don't have to be right :) + */ + memset(dev->LocalRAM.u8View, 0, sizeof(HALocalRAM)); + dev->LocalRAM.structured.autoSCSIData.fLevelSensitiveInterrupt = 1; + dev->LocalRAM.structured.autoSCSIData.fParityCheckingEnabled = 1; + dev->LocalRAM.structured.autoSCSIData.fExtendedTranslation = 1; /* Same as in geometry register. */ + dev->LocalRAM.structured.autoSCSIData.u16DeviceEnabledMask = UINT16_MAX; /* All enabled. Maybe mask out non present devices? */ + dev->LocalRAM.structured.autoSCSIData.u16WidePermittedMask = UINT16_MAX; + dev->LocalRAM.structured.autoSCSIData.u16FastPermittedMask = UINT16_MAX; + dev->LocalRAM.structured.autoSCSIData.u16SynchronousPermittedMask = UINT16_MAX; + dev->LocalRAM.structured.autoSCSIData.u16DisconnectPermittedMask = UINT16_MAX; + dev->LocalRAM.structured.autoSCSIData.fStrictRoundRobinMode = dev->StrictRoundRobinMode; + dev->LocalRAM.structured.autoSCSIData.u16UltraPermittedMask = UINT16_MAX; + /** @todo calculate checksum? */ +} + + +static void +aha_reset(aha_t *dev) +{ + AHA_Callback = 0; + ResetCB = 0; + dev->Status = STAT_IDLE | STAT_INIT; + dev->Geometry = 0x80; + dev->Command = 0xFF; + dev->CmdParam = 0; + dev->CmdParamLeft = 0; + dev->IrqEnabled = 1; + dev->StrictRoundRobinMode = 0; + dev->ExtendedLUNCCBFormat = 0; + dev->MailboxOutPosCur = 0; + dev->MailboxInPosCur = 0; + dev->MailboxOutInterrupts = 0; + dev->PendingInterrupt = 0; + dev->Lock = 0; + AHA_InOperation = 0; + + ClearIntr(dev); + + LocalRAM(dev); +} + + +static void +aha_reset_ctrl(aha_t *dev, uint8_t Reset) +{ + aha_reset(dev); + if (Reset) { + dev->Status |= STAT_STST; + dev->Status &= ~STAT_IDLE; + } + ResetCB = AHA_RESET_DURATION_NS * TIMER_USEC; +} + + +static void +aha_cmd_done(aha_t *dev) +{ + dev->DataReply = 0; + dev->Status |= STAT_IDLE; + + if ((dev->Command != 0x02) && (dev->Command != 0x82)) { + dev->Status &= ~STAT_DFULL; + dev->Interrupt = (INTR_ANY | INTR_HACC); + pclog("Raising IRQ %i\n", dev->Irq); + if (dev->IrqEnabled) + picint(1 << dev->Irq); + } + + dev->Command = 0xFF; + dev->CmdParam = 0; +} + + +static void +aha_mbi_setup(aha_t *dev, uint32_t CCBPointer, CCBU *CmdBlock, + uint8_t HostStatus, uint8_t TargetStatus, uint8_t mbcc) +{ + Req_t *req = &dev->Req; + + req->CCBPointer = CCBPointer; + memcpy(&(req->CmdBlock), CmdBlock, sizeof(CCB32)); + req->Is24bit = dev->Mbx24bit; + req->HostStatus = HostStatus; + req->TargetStatus = TargetStatus; + req->MailboxCompletionCode = mbcc; + + pclog("Mailbox in setup\n"); + + AHA_InOperation = 2; +} + + +static void +aha_mbi(aha_t *dev) +{ + Req_t *req = &dev->Req; + uint32_t CCBPointer = req->CCBPointer; + CCBU *CmdBlock = &(req->CmdBlock); + uint8_t HostStatus = req->HostStatus; + uint8_t TargetStatus = req->TargetStatus; + uint8_t MailboxCompletionCode = req->MailboxCompletionCode; + Mailbox32_t Mailbox32; + Mailbox_t MailboxIn; + uint32_t Incoming; + + Mailbox32.CCBPointer = CCBPointer; + Mailbox32.u.in.HostStatus = HostStatus; + Mailbox32.u.in.TargetStatus = TargetStatus; + Mailbox32.u.in.CompletionCode = MailboxCompletionCode; + + Incoming = dev->MailboxInAddr + (dev->MailboxInPosCur * (dev->Mbx24bit ? sizeof(Mailbox_t) : sizeof(Mailbox32_t))); + + if (MailboxCompletionCode != MBI_NOT_FOUND) { + CmdBlock->common.HostStatus = HostStatus; + CmdBlock->common.TargetStatus = TargetStatus; + + /* Rewrite the CCB up to the CDB. */ + pclog("CCB rewritten to the CDB (pointer %08X, length %i)\n", CCBPointer, offsetof(CCBC, Cdb)); + DMAPageWrite(CCBPointer, (char *)CmdBlock, offsetof(CCBC, Cdb)); + } else { + pclog("Mailbox not found!\n"); + } + + pclog("Host Status 0x%02X, Target Status 0x%02X\n",HostStatus,TargetStatus); + + if (dev->Mbx24bit) { + MailboxIn.CmdStatus = Mailbox32.u.in.CompletionCode; + U32_TO_ADDR(MailboxIn.CCBPointer, Mailbox32.CCBPointer); + pclog("Mailbox 24-bit: Status=0x%02X, CCB at 0x%04X\n", MailboxIn.CmdStatus, ADDR_TO_U32(MailboxIn.CCBPointer)); + + DMAPageWrite(Incoming, (char *)&MailboxIn, sizeof(Mailbox_t)); + pclog("%i bytes of 24-bit mailbox written to: %08X\n", sizeof(Mailbox_t), Incoming); + } else { + pclog("Mailbox 32-bit: Status=0x%02X, CCB at 0x%04X\n", Mailbox32.u.in.CompletionCode, Mailbox32.CCBPointer); + + DMAPageWrite(Incoming, (char *)&Mailbox32, sizeof(Mailbox32_t)); + pclog("%i bytes of 32-bit mailbox written to: %08X\n", sizeof(Mailbox32_t), Incoming); + } + + dev->MailboxInPosCur++; + if (dev->MailboxInPosCur >= dev->MailboxCount) + dev->MailboxInPosCur = 0; + + RaiseIntr(dev, INTR_MBIF | INTR_ANY); + + AHA_InOperation = 0; +} + + +static void +aha_rd_sge(int Is24bit, uint32_t SGList, uint32_t Entries, SGE32 *SG) +{ + uint32_t i; + SGE SGE24[MAX_SG_DESCRIPTORS]; + + if (Is24bit) { + DMAPageRead(SGList, (char *)&SGE24, Entries * sizeof(SGE)); + + for (i=0;iCmdBlock.old.DataPointer); + DataLength = ADDR_TO_U32(req->CmdBlock.old.DataLength); + } else { + DataPointer = req->CmdBlock.new.DataPointer; + DataLength = req->CmdBlock.new.DataLength; + } + pclog("Data Buffer write: length %d, pointer 0x%04X\n", + DataLength, DataPointer); + + if (SCSIDevices[req->TargetID][req->LUN].CmdBuffer != NULL) + { + free(SCSIDevices[req->TargetID][req->LUN].CmdBuffer); + SCSIDevices[req->TargetID][req->LUN].CmdBuffer = NULL; + } + + if ((req->CmdBlock.common.ControlByte != 0x03) && DataLength) { + if (req->CmdBlock.common.Opcode == SCATTER_GATHER_COMMAND || + req->CmdBlock.common.Opcode == SCATTER_GATHER_COMMAND_RES) { + uint32_t SGRead; + uint32_t ScatterEntry; + SGE32 SGBuffer[MAX_SG_DESCRIPTORS]; + uint32_t SGLeft = DataLength / SGEntryLength; + uint32_t SGAddrCurrent = DataPointer; + uint32_t DataToTransfer = 0; + + do { + SGRead = (SGLeft < ELEMENTS(SGBuffer)) ? SGLeft : ELEMENTS(SGBuffer); + SGLeft -= SGRead; + + aha_rd_sge(Is24bit, SGAddrCurrent, SGRead, SGBuffer); + + for (ScatterEntry = 0; ScatterEntry < SGRead; ScatterEntry++) { + pclog("BusLogic S/G Write: ScatterEntry=%u\n", ScatterEntry); + + Address = SGBuffer[ScatterEntry].SegmentPointer; + DataToTransfer += SGBuffer[ScatterEntry].Segment; + + pclog("BusLogic S/G Write: Address=%08X DatatoTransfer=%u\n", Address, DataToTransfer); + } + + SGAddrCurrent += SGRead * SGEntryLength; + } while (SGLeft > 0); + + pclog("Data to transfer (S/G) %d\n", DataToTransfer); + + SCSIDevices[req->TargetID][req->LUN].InitLength = DataToTransfer; + + pclog("Allocating buffer for Scatter/Gather (%i bytes)\n", DataToTransfer); + SCSIDevices[req->TargetID][req->LUN].CmdBuffer = (uint8_t *) malloc(DataToTransfer); + memset(SCSIDevices[req->TargetID][req->LUN].CmdBuffer, 0, DataToTransfer); + + /* If the control byte is 0x00, it means that the transfer direction is set up by the SCSI command without + checking its length, so do this procedure for both no read/write commands. */ + if ((req->CmdBlock.common.ControlByte == CCB_DATA_XFER_OUT) || + (req->CmdBlock.common.ControlByte == 0x00)) { + SGLeft = DataLength / SGEntryLength; + SGAddrCurrent = DataPointer; + + do { + SGRead = (SGLeft < ELEMENTS(SGBuffer)) ? SGLeft : ELEMENTS(SGBuffer); + SGLeft -= SGRead; + + aha_rd_sge(Is24bit, SGAddrCurrent, + SGRead, SGBuffer); + + for (ScatterEntry = 0; ScatterEntry < SGRead; ScatterEntry++) { + pclog("BusLogic S/G Write: ScatterEntry=%u\n", ScatterEntry); + + Address = SGBuffer[ScatterEntry].SegmentPointer; + DataToTransfer = SGBuffer[ScatterEntry].Segment; + + pclog("BusLogic S/G Write: Address=%08X DatatoTransfer=%u\n", Address, DataToTransfer); + + DMAPageRead(Address, (char *)SCSIDevices[req->TargetID][req->LUN].CmdBuffer + sg_buffer_pos, DataToTransfer); + sg_buffer_pos += DataToTransfer; + } + + SGAddrCurrent += SGRead * (Is24bit ? sizeof(SGE) : sizeof(SGE32)); + } while (SGLeft > 0); + } + } else if (req->CmdBlock.common.Opcode == SCSI_INITIATOR_COMMAND || + req->CmdBlock.common.Opcode == SCSI_INITIATOR_COMMAND_RES) { + Address = DataPointer; + + SCSIDevices[req->TargetID][req->LUN].InitLength = DataLength; + + pclog("Allocating buffer for direct transfer (%i bytes)\n", DataLength); + SCSIDevices[req->TargetID][req->LUN].CmdBuffer = (uint8_t *) malloc(DataLength); + memset(SCSIDevices[req->TargetID][req->LUN].CmdBuffer, 0, DataLength); + + if (DataLength > 0) { + DMAPageRead(Address, + (char *)SCSIDevices[req->TargetID][req->LUN].CmdBuffer, + SCSIDevices[req->TargetID][req->LUN].InitLength); + } + } + } +} + + +static void +aha_buf_free(Req_t *req) +{ + SGE32 SGBuffer[MAX_SG_DESCRIPTORS]; + uint32_t DataPointer = 0; + uint32_t DataLength = 0; + uint32_t sg_buffer_pos = 0; + uint32_t SGRead; + uint32_t ScatterEntry; + uint32_t SGEntrySize; + uint32_t SGLeft; + uint32_t SGAddrCurrent; + uint32_t Address; + uint32_t Residual; + uint32_t DataToTransfer; + + if (req->Is24bit) { + DataPointer = ADDR_TO_U32(req->CmdBlock.old.DataPointer); + DataLength = ADDR_TO_U32(req->CmdBlock.old.DataLength); + } else { + DataPointer = req->CmdBlock.new.DataPointer; + DataLength = req->CmdBlock.new.DataLength; + } + + if ((DataLength != 0) && (req->CmdBlock.common.Cdb[0] == GPCMD_TEST_UNIT_READY)) { + pclog("Data length not 0 with TEST UNIT READY: %i (%i)\n", + DataLength, SCSIDevices[req->TargetID][req->LUN].InitLength); + } + + if (req->CmdBlock.common.Cdb[0] == GPCMD_TEST_UNIT_READY) { + DataLength = 0; + } + + pclog("Data Buffer read: length %d, pointer 0x%04X\n", + DataLength, DataPointer); + + /* If the control byte is 0x00, it means that the transfer direction is set up by the SCSI command without + checking its length, so do this procedure for both read/write commands. */ + if ((DataLength > 0) && + ((req->CmdBlock.common.ControlByte == CCB_DATA_XFER_IN) || + (req->CmdBlock.common.ControlByte == 0x00))) { + if ((req->CmdBlock.common.Opcode == SCATTER_GATHER_COMMAND) || + (req->CmdBlock.common.Opcode == SCATTER_GATHER_COMMAND_RES)) { + SGEntrySize = (req->Is24bit ? sizeof(SGE) : sizeof(SGE32)); + SGLeft = DataLength / SGEntrySize; + SGAddrCurrent = DataPointer; + + do { + SGRead = (SGLeft < ELEMENTS(SGBuffer)) ? SGLeft : ELEMENTS(SGBuffer); + SGLeft -= SGRead; + + aha_rd_sge(req->Is24bit, SGAddrCurrent, + SGRead, SGBuffer); + + for (ScatterEntry = 0; ScatterEntry < SGRead; ScatterEntry++) { + pclog("BusLogic S/G: ScatterEntry=%u\n", ScatterEntry); + + Address = SGBuffer[ScatterEntry].SegmentPointer; + DataToTransfer = SGBuffer[ScatterEntry].Segment; + + pclog("BusLogic S/G: Writing %i bytes at %08X\n", DataToTransfer, Address); + + DMAPageWrite(Address, (char *)SCSIDevices[req->TargetID][req->LUN].CmdBuffer + sg_buffer_pos, DataToTransfer); + sg_buffer_pos += DataToTransfer; + } + + SGAddrCurrent += (SGRead * SGEntrySize); + } while (SGLeft > 0); + } else if (req->CmdBlock.common.Opcode == SCSI_INITIATOR_COMMAND || + req->CmdBlock.common.Opcode == SCSI_INITIATOR_COMMAND_RES) { + Address = DataPointer; + + pclog("BusLogic DMA: Writing %i bytes at %08X\n", DataLength, Address); + DMAPageWrite(Address, (char *)SCSIDevices[req->TargetID][req->LUN].CmdBuffer, DataLength); + } + } + + if ((req->CmdBlock.common.Opcode == SCSI_INITIATOR_COMMAND_RES) || + (req->CmdBlock.common.Opcode == SCATTER_GATHER_COMMAND_RES)) { + /* Should be 0 when scatter/gather? */ + if (DataLength >= SCSIDevices[req->TargetID][req->LUN].InitLength) { + Residual = DataLength; + Residual -= SCSIDevices[req->TargetID][req->LUN].InitLength; + } else { + Residual = 0; + } + + if (req->Is24bit) { + U32_TO_ADDR(req->CmdBlock.old.DataLength, Residual); + pclog("24-bit Residual data length for reading: %d\n", + ADDR_TO_U32(req->CmdBlock.old.DataLength)); + } else { + req->CmdBlock.new.DataLength = Residual; + pclog("32-bit Residual data length for reading: %d\n", + req->CmdBlock.new.DataLength); + } + } + + if (SCSIDevices[req->TargetID][req->LUN].CmdBuffer != NULL) + { + free(SCSIDevices[req->TargetID][req->LUN].CmdBuffer); + SCSIDevices[req->TargetID][req->LUN].CmdBuffer = NULL; + } +} + + +static uint8_t +aha_read(uint16_t port, void *priv) +{ + aha_t *dev = (aha_t *)priv; + uint8_t ret; + + switch (port & 3) { + case 0: + ret = dev->Status; + break; + + case 1: + if (dev->UseLocalRAM) + ret = dev->LocalRAM.u8View[dev->DataReply]; + else + ret = dev->DataBuf[dev->DataReply]; + if (dev->DataReplyLeft) { + dev->DataReply++; + dev->DataReplyLeft--; + if (! dev->DataReplyLeft) + aha_cmd_done(dev); + } + break; + + case 2: + ret = dev->Interrupt; + break; + + case 3: + ret = dev->Geometry; + break; + } + + if (port < 0x1000) { + pclog("AHA154X: Read Port 0x%02X, Returned Value %02X\n", port, ret); + } + + return(ret); +} + + +static uint16_t +aha_readw(uint16_t port, void *priv) +{ + return aha_read(port, priv); +} + + +static void +aha_write(uint16_t port, uint8_t val, void *priv) +{ + int i = 0; + uint8_t j = 0; + aha_t *dev = (aha_t *)priv; + uint8_t Offset; + MailboxInit_t *MailboxInit; + ReplyInquireSetupInformation *ReplyISI; + + pclog("AHA154X: Write Port 0x%02X, Value %02X\n", port, val); + + switch (port & 3) { + case 0: + if ((val & CTRL_HRST) || (val & CTRL_SRST)) { + uint8_t Reset = !(val & CTRL_HRST); + aha_reset_ctrl(dev, Reset); + break; + } + + if (val & CTRL_IRST) { + ClearIntr(dev); + } + break; + + case 1: + /* Fast path for the mailbox execution command. */ + if (((val == 0x02) || (val == 0x82)) && + (dev->Command == 0xFF)) { + /* If there are no mailboxes configured, don't even try to do anything. */ + if (dev->MailboxCount) { + if (!AHA_Callback) { + AHA_Callback = 50 * SCSI_TIME; + } + } + return; + } + + if (dev->Command == 0xFF) { + dev->Command = val; + dev->CmdParam = 0; + dev->CmdParamLeft = 0; + + dev->Status &= ~(STAT_INVCMD | STAT_IDLE); + pclog("AHA154X: Operation Code 0x%02X\n", val); + switch (dev->Command) { + case 0x01: + dev->CmdParamLeft = sizeof(MailboxInit_t); + break; + + case 0x03: /* Exec BIOS Command */ + dev->CmdParamLeft = 10; + break; + + case 0x25: + /* Same as 0x01 for AHA. */ + dev->CmdParamLeft = sizeof(MailboxInit_t); + break; + + case 0x05: + case 0x07: + case 0x08: + case 0x09: + case 0x0D: + case 0x1F: + case 0x21: + case 0x24: + dev->CmdParamLeft = 1; + break; + + case 0x06: + dev->CmdParamLeft = 4; + break; + + case 0x1C: + case 0x1D: + dev->CmdParamLeft = 3; + break; + + case 0x22: /* write EEPROM */ + dev->CmdParamLeft = 3+32; + break; + + case 0x23: /* read EEPROM */ + dev->CmdParamLeft = 3; + break; + + case 0x29: + dev->CmdParamLeft = 2; + break; + + case 0x91: + dev->CmdParamLeft = 2; + break; + } + } else { + dev->CmdBuf[dev->CmdParam] = val; + dev->CmdParam++; + dev->CmdParamLeft--; + } + + if (! dev->CmdParamLeft) { + pclog("Running Operation Code 0x%02X\n", dev->Command); + switch (dev->Command) { + case 0x00: + dev->DataReplyLeft = 0; + break; + + case 0x01: +aha_0x01: + { + dev->Mbx24bit = 1; + + MailboxInit = (MailboxInit_t *)dev->CmdBuf; + + dev->MailboxCount = MailboxInit->Count; + dev->MailboxOutAddr = ADDR_TO_U32(MailboxInit->Address); + dev->MailboxInAddr = dev->MailboxOutAddr + (dev->MailboxCount * sizeof(Mailbox_t)); + + pclog("Initialize Mailbox Command\n"); + pclog("Mailbox Out Address=0x%08X\n", dev->MailboxOutAddr); + pclog("Mailbox In Address=0x%08X\n", dev->MailboxInAddr); + pclog("Initialized Mailbox, %d entries at 0x%08X\n", MailboxInit->Count, ADDR_TO_U32(MailboxInit->Address)); + + dev->Status &= ~STAT_INIT; + dev->DataReplyLeft = 0; + } + break; + + case 0x03: + dev->DataBuf[0] = 0x00; + dev->DataReplyLeft = 1; + break; + + case 0x04: + dev->DataBuf[0] = (dev->chip != CHIP_AHA1640) ? dev->aha.bid : 0x42; + dev->DataBuf[1] = (dev->chip != CHIP_AHA1640) ? 0x30 : 0x42; + dev->DataBuf[2] = dev->aha.fwh; + dev->DataBuf[3] = dev->aha.fwl; + dev->DataReplyLeft = 4; + break; + + case 0x05: + if (dev->CmdBuf[0] <= 1) { + dev->MailboxOutInterrupts = dev->CmdBuf[0]; + pclog("Mailbox out interrupts: %s\n", dev->MailboxOutInterrupts ? "ON" : "OFF"); + } else { + dev->Status |= STAT_INVCMD; + } + dev->DataReplyLeft = 0; + break; + + case 0x06: + dev->DataReplyLeft = 0; + break; + + case 0x07: + dev->DataReplyLeft = 0; + dev->LocalRAM.structured.autoSCSIData.uBusOnDelay = dev->CmdBuf[0]; + pclog("Bus-on time: %d\n", dev->CmdBuf[0]); + break; + + case 0x08: + dev->DataReplyLeft = 0; + dev->LocalRAM.structured.autoSCSIData.uBusOffDelay = dev->CmdBuf[0]; + pclog("Bus-off time: %d\n", dev->CmdBuf[0]); + break; + + case 0x09: + dev->DataReplyLeft = 0; + dev->LocalRAM.structured.autoSCSIData.uDMATransferRate = dev->CmdBuf[0]; + pclog("DMA transfer rate: %02X\n", dev->CmdBuf[0]); + break; + + case 0x0A: + memset(dev->DataBuf, 0, 8); + for (i=0; i<7; i++) { + dev->DataBuf[i] = 0; + for (j=0; j<8; j++) { + if (SCSIDevices[i][j].LunType != SCSI_NONE) + dev->DataBuf[i] |= (1<DataBuf[7] = 0; + dev->DataReplyLeft = 8; + break; + + case 0x0B: + dev->DataBuf[0] = (1<DmaChannel); + if (dev->Irq >= 8) + dev->DataBuf[1]=(1<<(dev->Irq-9)); + else + dev->DataBuf[1]=(1<Irq); + dev->DataBuf[2] = 7; /* HOST ID */ + dev->DataReplyLeft = 3; + break; + + case 0x0D: + { + dev->DataReplyLeft = dev->CmdBuf[0]; + + ReplyISI = (ReplyInquireSetupInformation *)dev->DataBuf; + memset(ReplyISI, 0, sizeof(ReplyInquireSetupInformation)); + + ReplyISI->fSynchronousInitiationEnabled = 1; + ReplyISI->fParityCheckingEnabled = 1; + ReplyISI->cMailbox = dev->MailboxCount; + U32_TO_ADDR(ReplyISI->MailboxAddress, dev->MailboxOutAddr); + pclog("Return Setup Information: %d\n", dev->CmdBuf[0]); + } + break; + + case 0x1C: + { + uint32_t FIFOBuf; + addr24 Address; + + dev->DataReplyLeft = 0; + Address.hi = dev->CmdBuf[0]; + Address.mid = dev->CmdBuf[1]; + Address.lo = dev->CmdBuf[2]; + FIFOBuf = ADDR_TO_U32(Address); + DMAPageRead(FIFOBuf, (char *)&dev->LocalRAM.u8View[64], 64); + } + break; + + case 0x1D: + { + uint32_t FIFOBuf; + addr24 Address; + + dev->DataReplyLeft = 0; + Address.hi = dev->CmdBuf[0]; + Address.mid = dev->CmdBuf[1]; + Address.lo = dev->CmdBuf[2]; + FIFOBuf = ADDR_TO_U32(Address); + pclog("FIFO: Writing 64 bytes at %08X\n", FIFOBuf); + DMAPageWrite(FIFOBuf, (char *)&dev->LocalRAM.u8View[64], 64); + } + break; + + case 0x1F: + dev->DataBuf[0] = dev->CmdBuf[0]; + dev->DataReplyLeft = 1; + break; + + case 0x21: + if (dev->CmdParam == 1) + dev->CmdParamLeft = dev->CmdBuf[0]; + dev->DataReplyLeft = 0; + break; + + case 0x22: /* write EEPROM */ + /* Sent by CF BIOS. */ + dev->DataReplyLeft = + aha154x_eeprom(dev->Command, + dev->CmdBuf[0], + dev->CmdBuf[1], + dev->CmdBuf[2], + &dev->CmdBuf[3]); + if (dev->DataReplyLeft == 0xff) { + dev->DataReplyLeft = 0; + dev->Status |= STAT_INVCMD; + } + break; + + case 0x23: + dev->DataReplyLeft = + aha154x_eeprom(dev->Command, + dev->CmdBuf[0], + dev->CmdBuf[1], + dev->CmdBuf[2], + dev->DataBuf); + if (dev->DataReplyLeft == 0xff) { + dev->DataReplyLeft = 0; + dev->Status |= STAT_INVCMD; + } + break; + + case 0x24: + /* + * For AHA1542CF, this is the command + * to play with the Shadow RAM. BIOS + * gives us one argument (00,02,03) + * and expects a 0x04 back in the INTR + * register. --FvK + */ + dev->Interrupt = aha154x_shram(val); + break; + + case 0x25: + goto aha_0x01; + + case 0x26: /* AHA memory mapper */ + case 0x27: /* AHA memory mapper */ + dev->DataReplyLeft = + aha154x_memory(dev->Command); + break; + + case 0x28: + dev->DataBuf[0] = 0x08; + dev->DataBuf[1] = dev->Lock; + dev->DataReplyLeft = 2; + break; + + case 0x29: + if (dev->CmdBuf[1] == dev->Lock) { + if (dev->CmdBuf[0] & 1) { + dev->Lock = 1; + } else { + dev->Lock = 0; + } + } + dev->DataReplyLeft = 0; + break; + + case 0x2C: /* AHA-1542CP sends this */ + dev->DataBuf[0] = 0x00; + dev->DataReplyLeft = 1; + break; + + case 0x33: /* AHA-1542CP sends this */ + dev->DataBuf[0] = 0x00; + dev->DataBuf[1] = 0x00; + dev->DataBuf[2] = 0x00; + dev->DataBuf[3] = 0x00; + dev->DataReplyLeft = 256; + break; + + case 0x91: + Offset = dev->CmdBuf[0]; + dev->DataReplyLeft = dev->CmdBuf[1]; + + dev->UseLocalRAM = 1; + dev->DataReply = Offset; + break; + + default: + dev->DataReplyLeft = 0; + dev->Status |= STAT_INVCMD; + break; + } + } + + if (dev->DataReplyLeft) + dev->Status |= STAT_DFULL; + else if (!dev->CmdParamLeft) + aha_cmd_done(dev); + break; + + case 2: + break; + + case 3: + break; + } +} + + +static void +aha_writew(uint16_t Port, uint16_t Val, void *p) +{ + aha_write(Port, Val & 0xFF, p); +} + + +static uint8_t +ConvertSenseLength(uint8_t RequestSenseLength) +{ + pclog("Unconverted Request Sense length %i\n", RequestSenseLength); + + if (RequestSenseLength == 0) + RequestSenseLength = 14; + else if (RequestSenseLength == 1) + RequestSenseLength = 0; + + pclog("Request Sense length %i\n", RequestSenseLength); + + return(RequestSenseLength); +} + + +static void +SenseBufferFree(Req_t *req, int Copy, int is_hd) +{ + uint8_t SenseLength = ConvertSenseLength(req->CmdBlock.common.RequestSenseLength); + uint8_t cdrom_id = scsi_cdrom_drives[req->TargetID][req->LUN]; + uint8_t hdc_id = scsi_hard_disks[req->TargetID][req->LUN]; + uint32_t SenseBufferAddress; + uint8_t temp_sense[256]; + + if (SenseLength && Copy) { + if (is_hd) + { + scsi_hd_request_sense_for_scsi(hdc_id, temp_sense, SenseLength); + } + else + { + cdrom_request_sense_for_scsi(cdrom_id, temp_sense, SenseLength); + } + + /* + * The sense address, in 32-bit mode, is located in the + * Sense Pointer of the CCB, but in 24-bit mode, it is + * located at the end of the Command Descriptor Block. + */ + if (req->Is24bit) { + SenseBufferAddress = req->CCBPointer; + SenseBufferAddress += req->CmdBlock.common.CdbLength + offsetof(CCB, Cdb); + } else { + SenseBufferAddress = req->CmdBlock.new.SensePointer; + } + + pclog("Request Sense address: %02X\n", SenseBufferAddress); + + pclog("SenseBufferFree(): Writing %i bytes at %08X\n", + SenseLength, SenseBufferAddress); + DMAPageWrite(SenseBufferAddress, (char *)temp_sense, SenseLength); + pclog("Sense data written to buffer: %02X %02X %02X\n", + temp_sense[2], temp_sense[12], temp_sense[13]); + } +} + + +static void +aha_disk_cmd(aha_t *dev) +{ + Req_t *req = &dev->Req; + uint8_t Id, Lun; + uint8_t hdc_id; + uint8_t hd_phase; + uint8_t temp_cdb[12]; + uint32_t i; + + Id = req->TargetID; + Lun = req->LUN; + hdc_id = scsi_hard_disks[Id][Lun]; + + if (hdc_id == 0xff) fatal("SCSI hard disk on %02i:%02i has disappeared\n", Id, Lun); + + pclog("SCSI HD command being executed on: SCSI ID %i, SCSI LUN %i, HD %i\n", + Id, Lun, hdc_id); + + pclog("SCSI Cdb[0]=0x%02X\n", req->CmdBlock.common.Cdb[0]); + for (i = 1; i < req->CmdBlock.common.CdbLength; i++) { + pclog("SCSI Cdb[%i]=%i\n", i, req->CmdBlock.common.Cdb[i]); + } + + memset(temp_cdb, 0, 12); + if (req->CmdBlock.common.CdbLength <= 12) { + memcpy(temp_cdb, req->CmdBlock.common.Cdb, + req->CmdBlock.common.CdbLength); + } else { + memcpy(temp_cdb, req->CmdBlock.common.Cdb, 12); + } + + /* + * Since that field in the HDC struct is never used when + * the bus type is SCSI, let's use it for this scope. + */ + shdc[hdc_id].request_length = temp_cdb[1]; + + if (req->CmdBlock.common.CdbLength != 12) { + /* + * Make sure the LUN field of the temporary CDB is always 0, + * otherwise Daemon Tools drives will misbehave when a command + * is passed through to them. + */ + temp_cdb[1] &= 0x1f; + } + + /* Finally, execute the SCSI command immediately and get the transfer length. */ + SCSIPhase = SCSI_PHASE_COMMAND; + scsi_hd_command(hdc_id, temp_cdb); + SCSIStatus = scsi_hd_err_stat_to_scsi(hdc_id); + if (SCSIStatus == SCSI_STATUS_OK) { + hd_phase = scsi_hd_phase_to_scsi(hdc_id); + if (hd_phase == 2) { + /* Command completed - call the phase callback to complete the command. */ + scsi_hd_callback(hdc_id); + } else { + /* Command first phase complete - call the callback to execute the second phase. */ + scsi_hd_callback(hdc_id); + SCSIStatus = scsi_hd_err_stat_to_scsi(hdc_id); + /* Command second phase complete - call the callback to complete the command. */ + scsi_hd_callback(hdc_id); + } + } else { + /* Error (Check Condition) - call the phase callback to complete the command. */ + scsi_hd_callback(hdc_id); + } + + pclog("SCSI Status: %s, Sense: %02X, ASC: %02X, ASCQ: %02X\n", (SCSIStatus == SCSI_STATUS_OK) ? "OK" : "CHECK CONDITION", shdc[hdc_id].sense[2], shdc[hdc_id].sense[12], shdc[hdc_id].sense[13]); + + aha_buf_free(req); + + SenseBufferFree(req, (SCSIStatus != SCSI_STATUS_OK), 1); + + pclog("Request complete\n"); + + if (SCSIStatus == SCSI_STATUS_OK) { + aha_mbi_setup(dev, req->CCBPointer, &req->CmdBlock, + CCB_COMPLETE, SCSI_STATUS_OK, MBI_SUCCESS); + } else if (SCSIStatus == SCSI_STATUS_CHECK_CONDITION) { + aha_mbi_setup(dev, req->CCBPointer, &req->CmdBlock, + CCB_COMPLETE, SCSI_STATUS_CHECK_CONDITION, MBI_ERROR); + } +} + + +static void +aha_cdrom_cmd(aha_t *dev) +{ + Req_t *req = &dev->Req; + uint8_t Id, Lun; + uint8_t cdrom_id; + uint8_t cdrom_phase; + uint8_t temp_cdb[12]; + uint32_t i; + + Id = req->TargetID; + Lun = req->LUN; + cdrom_id = scsi_cdrom_drives[Id][Lun]; + + if (cdrom_id == 0xff) fatal("SCSI CD-ROM on %02i:%02i has disappeared\n", Id, Lun); + + pclog("CD-ROM command being executed on: SCSI ID %i, SCSI LUN %i, CD-ROM %i\n", + Id, Lun, cdrom_id); + + pclog("SCSI Cdb[0]=0x%02X\n", req->CmdBlock.common.Cdb[0]); + for (i = 1; i < req->CmdBlock.common.CdbLength; i++) { + pclog("SCSI Cdb[%i]=%i\n", i, req->CmdBlock.common.Cdb[i]); + } + + memset(temp_cdb, 0, cdrom[cdrom_id].cdb_len); + if (req->CmdBlock.common.CdbLength <= cdrom[cdrom_id].cdb_len) { + memcpy(temp_cdb, req->CmdBlock.common.Cdb, + req->CmdBlock.common.CdbLength); + } else { + memcpy(temp_cdb, req->CmdBlock.common.Cdb, cdrom[cdrom_id].cdb_len); + } + + /* + * Since that field in the CDROM struct is never used when + * the bus type is SCSI, let's use it for this scope. + */ + cdrom[cdrom_id].request_length = temp_cdb[1]; + + if (req->CmdBlock.common.CdbLength != 12) { + /* + * Make sure the LUN field of the temporary CDB is always 0, + * otherwise Daemon Tools drives will misbehave when a command + * is passed through to them. + */ + temp_cdb[1] &= 0x1f; + } + + /* Finally, execute the SCSI command immediately and get the transfer length. */ + SCSIPhase = SCSI_PHASE_COMMAND; + cdrom_command(cdrom_id, temp_cdb); + SCSIStatus = cdrom_CDROM_PHASE_to_scsi(cdrom_id); + if (SCSIStatus == SCSI_STATUS_OK) { + cdrom_phase = cdrom_atapi_phase_to_scsi(cdrom_id); + if (cdrom_phase == 2) { + /* Command completed - call the phase callback to complete the command. */ + cdrom_phase_callback(cdrom_id); + } else { + /* Command first phase complete - call the callback to execute the second phase. */ + cdrom_phase_callback(cdrom_id); + SCSIStatus = cdrom_CDROM_PHASE_to_scsi(cdrom_id); + /* Command second phase complete - call the callback to complete the command. */ + cdrom_phase_callback(cdrom_id); + } + } else { + /* Error (Check Condition) - call the phase callback to complete the command. */ + cdrom_phase_callback(cdrom_id); + } + + pclog("SCSI Status: %s, Sense: %02X, ASC: %02X, ASCQ: %02X\n", (SCSIStatus == SCSI_STATUS_OK) ? "OK" : "CHECK CONDITION", cdrom[cdrom_id].sense[2], cdrom[cdrom_id].sense[12], cdrom[cdrom_id].sense[13]); + + aha_buf_free(req); + + SenseBufferFree(req, (SCSIStatus != SCSI_STATUS_OK), 0); + + pclog("Request complete\n"); + + if (SCSIStatus == SCSI_STATUS_OK) { + aha_mbi_setup(dev, req->CCBPointer, &req->CmdBlock, + CCB_COMPLETE, SCSI_STATUS_OK, MBI_SUCCESS); + } else if (SCSIStatus == SCSI_STATUS_CHECK_CONDITION) { + aha_mbi_setup(dev, req->CCBPointer, &req->CmdBlock, + CCB_COMPLETE, SCSI_STATUS_CHECK_CONDITION, MBI_ERROR); + } +} + + +static void +aha_req_setup(aha_t *dev, uint32_t CCBPointer, Mailbox32_t *Mailbox32) +{ + Req_t *req = &dev->Req; + uint8_t Id, Lun; + uint8_t last_id = 7; + + /* Fetch data from the Command Control Block. */ + DMAPageRead(CCBPointer, (char *)&req->CmdBlock, sizeof(CCB32)); + + req->Is24bit = dev->Mbx24bit; + req->CCBPointer = CCBPointer; + req->TargetID = dev->Mbx24bit ? req->CmdBlock.old.Id : req->CmdBlock.new.Id; + req->LUN = dev->Mbx24bit ? req->CmdBlock.old.Lun : req->CmdBlock.new.Lun; + + Id = req->TargetID; + Lun = req->LUN; + if ((Id > last_id) || (Lun > 7)) { + aha_mbi_setup(dev, CCBPointer, &req->CmdBlock, + CCB_INVALID_CCB, SCSI_STATUS_OK, MBI_ERROR); + return; + } + + pclog("Scanning SCSI Target ID %i\n", Id); + + SCSIStatus = SCSI_STATUS_OK; + SCSIDevices[Id][Lun].InitLength = 0; + + aha_buf_alloc(req, req->Is24bit); + + if (SCSIDevices[Id][Lun].LunType == SCSI_NONE) { + pclog("SCSI Target ID %i and LUN %i have no device attached\n",Id,Lun); + aha_buf_free(req); + SenseBufferFree(req, 0, 0); + aha_mbi_setup(dev, CCBPointer, &req->CmdBlock, + CCB_SELECTION_TIMEOUT,SCSI_STATUS_OK,MBI_ERROR); + } else { + pclog("SCSI Target ID %i and LUN %i detected and working\n", Id, Lun); + + pclog("Transfer Control %02X\n", req->CmdBlock.common.ControlByte); + pclog("CDB Length %i\n", req->CmdBlock.common.CdbLength); + pclog("CCB Opcode %x\n", req->CmdBlock.common.Opcode); + if (req->CmdBlock.common.ControlByte > 0x03) { + pclog("Invalid control byte: %02X\n", + req->CmdBlock.common.ControlByte); + } + + AHA_InOperation = (SCSIDevices[Id][Lun].LunType == SCSI_DISK) ? 0x11 : 1; + pclog("SCSI (%i:%i) -> %i\n", Id, Lun, SCSIDevices[Id][Lun].LunType); + } +} + + +static void +aha_req_abort(aha_t *dev, uint32_t CCBPointer) +{ + CCBU CmdBlock; + + /* Fetch data from the Command Control Block. */ + DMAPageRead(CCBPointer, (char *)&CmdBlock, sizeof(CCB32)); + + aha_mbi_setup(dev, CCBPointer, &CmdBlock, + 0x26, SCSI_STATUS_OK, MBI_NOT_FOUND); +} + + +static uint32_t +aha_mbo(aha_t *dev, Mailbox32_t *Mailbox32) +{ + Mailbox_t MailboxOut; + uint32_t Outgoing; + + if (dev->Mbx24bit) { + Outgoing = dev->MailboxOutAddr + (dev->MailboxOutPosCur * sizeof(Mailbox_t)); + DMAPageRead(Outgoing, (char *)&MailboxOut, sizeof(Mailbox_t)); + + Mailbox32->CCBPointer = ADDR_TO_U32(MailboxOut.CCBPointer); + Mailbox32->u.out.ActionCode = MailboxOut.CmdStatus; + } else { + Outgoing = dev->MailboxOutAddr + (dev->MailboxOutPosCur * sizeof(Mailbox32_t)); + + DMAPageRead(Outgoing, (char *)Mailbox32, sizeof(Mailbox32_t)); + } + + return Outgoing; +} + + +static void +aha_mbo_adv(aha_t *dev) +{ + dev->MailboxOutPosCur = (dev->MailboxOutPosCur + 1) % dev->MailboxCount; +} + + +static void +aha_do_mail(aha_t *dev) +{ + Mailbox32_t mb32; + uint32_t Outgoing; + uint8_t CmdStatus = MBO_FREE; + uint32_t CodeOffset = 0; + + CodeOffset = dev->Mbx24bit ? offsetof(Mailbox_t, CmdStatus) : offsetof(Mailbox32_t, u.out.ActionCode); + + if (! dev->StrictRoundRobinMode) { + uint8_t MailboxCur = dev->MailboxOutPosCur; + + /* Search for a filled mailbox - stop if we have scanned all mailboxes. */ + do { + /* Fetch mailbox from guest memory. */ + Outgoing = aha_mbo(dev, &mb32); + + /* Check the next mailbox. */ + aha_mbo_adv(dev); + } while ((mb32.u.out.ActionCode == MBO_FREE) && (MailboxCur != dev->MailboxOutPosCur)); + } else { + Outgoing = aha_mbo(dev, &mb32); + } + + if (mb32.u.out.ActionCode != MBO_FREE) { + /* We got the mailbox, mark it as free in the guest. */ + pclog("aha_do_mail(): Writing %i bytes at %08X\n", sizeof(CmdStatus), Outgoing + CodeOffset); + DMAPageWrite(Outgoing + CodeOffset, (char *)&CmdStatus, sizeof(CmdStatus)); + } + + if (dev->MailboxOutInterrupts) + RaiseIntr(dev, INTR_MBOA | INTR_ANY); + + /* Check if the mailbox is actually loaded. */ + if (mb32.u.out.ActionCode == MBO_FREE) { + return; + } + + if (mb32.u.out.ActionCode == MBO_START) { + pclog("Start Mailbox Command\n"); + aha_req_setup(dev, mb32.CCBPointer, &mb32); + } else if (mb32.u.out.ActionCode == MBO_ABORT) { + pclog("Abort Mailbox Command\n"); + aha_req_abort(dev, mb32.CCBPointer); + } else { + pclog("Invalid action code: %02X\n", mb32.u.out.ActionCode); + } + + /* Advance to the next mailbox. */ + if (dev->StrictRoundRobinMode) + aha_mbo_adv(dev); +} + + +static void +aha_reset_poll(void *priv) +{ + aha_t *dev = (aha_t *)priv; + + dev->Status &= ~STAT_STST; + dev->Status |= STAT_IDLE; + + ResetCB = 0; +} + + +static void +aha_cmd_cb(void *priv) +{ + aha_t *dev = (aha_t *)priv; + + if (AHA_InOperation == 0) { + if (dev->MailboxCount) { + aha_do_mail(dev); + } else { + AHA_Callback += 50 * SCSI_TIME; + return; + } + } else if (AHA_InOperation == 1) { + pclog("BusLogic Callback: Process CD-ROM request\n"); + aha_cdrom_cmd(dev); + if (dev->Req.CmdBlock.common.Cdb[0] == 0x42) + { + /* This is needed since CD Audio inevitably means READ SUBCHANNEL spam. */ + AHA_Callback += 1000 * SCSI_TIME; + return; + } + } else if (AHA_InOperation == 2) { + pclog("BusLogic Callback: Send incoming mailbox\n"); + aha_mbi(dev); + } else if (AHA_InOperation == 0x11) { + pclog("BusLogic Callback: Process DISK request\n"); + aha_disk_cmd(dev); + } else { + fatal("Invalid BusLogic callback phase: %i\n", AHA_InOperation); + } + + AHA_Callback += 50 * SCSI_TIME; +} + +uint8_t aha_mca_read(int port, void *p) +{ + aha_t *dev = (aha_t *)p; + + return dev->pos_regs[port & 7]; +} + +uint16_t aha_mca_get_port(uint8_t pos_port) +{ + uint16_t addr = 0; + switch (pos_port & 0xC7) + { + case 0x01: + addr = 0x130; + break; + + case 0x02: + addr = 0x230; + break; + + case 0x03: + addr = 0x330; + break; + + case 0x41: + addr = 0x134; + break; + + case 0x42: + addr = 0x234; + break; + + case 0x43: + addr = 0x334; + break; + } + + return addr; +} + +void aha_mca_write(int port, uint8_t val, void *p) +{ + aha_t *dev = (aha_t *)p; + uint16_t addr; + + if (port < 0x102) + return; + + addr = aha_mca_get_port(dev->pos_regs[3]); + io_removehandler(addr, 0x0004, aha_read, aha_readw, NULL, aha_write, aha_writew, NULL, dev); + + dev->pos_regs[port & 7] = val; + + if (dev->pos_regs[2] & 1) + { + addr = aha_mca_get_port(dev->pos_regs[3]); + io_sethandler(addr, 0x0004, aha_read, aha_readw, NULL, aha_write, aha_writew, NULL, dev); + } + + dev->Irq = (dev->pos_regs[4] & 0x7) + 8; + dev->DmaChannel = dev->pos_regs[5] & 0xf; +} + +void +aha_device_reset(void *p) +{ + aha_t *dev = (aha_t *) p; + aha_reset_ctrl(dev, 1); +} + + +static void * +aha_init(int chip, int has_bios) +{ + aha_t *dev; + int i = 0; + int j = 0; + uint32_t bios_addr = 0; + int bios = 0; + + dev = malloc(sizeof(aha_t)); + memset(dev, 0x00, sizeof(aha_t)); + + ResetDev = dev; + dev->chip = chip; + dev->Base = device_get_config_hex16("base"); + dev->Irq = device_get_config_int("irq"); + dev->DmaChannel = device_get_config_int("dma"); + bios = device_get_config_int("bios"); + bios_addr = device_get_config_hex20("bios_addr"); + + if (dev->Base != 0) { + io_sethandler(dev->Base, 4, + aha_read, aha_readw, NULL, + aha_write, aha_writew, NULL, dev); + } + + pclog("Building SCSI hard disk map...\n"); + build_scsi_hd_map(); + pclog("Building SCSI CD-ROM map...\n"); + build_scsi_cdrom_map(); + + for (i=0; i<16; i++) { + for (j=0; j<8; j++) { + if (scsi_hard_disks[i][j] != 0xff) { + SCSIDevices[i][j].LunType = SCSI_DISK; + } + else if (find_cdrom_for_scsi_id(i, j) != 0xff) { + SCSIDevices[i][j].LunType = SCSI_CDROM; + } + else { + SCSIDevices[i][j].LunType = SCSI_NONE; + } + } + } + + timer_add(aha_reset_poll, &ResetCB, &ResetCB, dev); + timer_add(aha_cmd_cb, &AHA_Callback, &AHA_Callback, dev); + + pclog("Adaptec AHA-154x on port 0x%04X\n", dev->Base); + + aha_reset_ctrl(dev, CTRL_HRST); + + if (bios) { + /* Perform AHA-154xNN-specific initialization. */ + aha154x_bios(dev->Base, bios_addr, &dev->aha, dev->Irq, dev->DmaChannel); + } + + return(dev); +} + + +static void * +aha_154xB_init(void) +{ + return(aha_init(CHIP_AHA154XB, 0)); +} + + +static void * +aha_154xCF_init(void) +{ + return(aha_init(CHIP_AHA154XCF, 1)); +} + +static void * +aha_1640_init(void) +{ + aha_t *dev; + int i = 0; + int j = 0; + + dev = malloc(sizeof(aha_t)); + memset(dev, 0x00, sizeof(aha_t)); + + ResetDev = dev; + dev->chip = CHIP_AHA1640; + + pclog("Aha1640 initialized\n"); + mca_add(aha_mca_read, aha_mca_write, dev); + dev->pos_regs[0] = 0x1F; + dev->pos_regs[1] = 0x0F; + + pclog("Building SCSI hard disk map...\n"); + build_scsi_hd_map(); + pclog("Building SCSI CD-ROM map...\n"); + build_scsi_cdrom_map(); + + for (i=0; i<16; i++) { + for (j=0; j<8; j++) { + if (scsi_hard_disks[i][j] != 0xff) { + SCSIDevices[i][j].LunType = SCSI_DISK; + } + else if (find_cdrom_for_scsi_id(i, j) != 0xff) { + SCSIDevices[i][j].LunType = SCSI_CDROM; + } + else { + SCSIDevices[i][j].LunType = SCSI_NONE; + } + } + } + + timer_add(aha_reset_poll, &ResetCB, &ResetCB, dev); + timer_add(aha_cmd_cb, &AHA_Callback, &AHA_Callback, dev); + + aha_reset_ctrl(dev, CTRL_HRST); + + return(dev); +} + + +static void +aha_close(void *priv) +{ + aha_t *dev = (aha_t *)priv; + free(dev); + ResetDev = NULL; +} + + +static device_config_t aha_154XCF_config[] = { + { + "base", "Address", CONFIG_HEX16, "", 0x334, + { + { + "None", 0 + }, + { + "0x330", 0x330 + }, + { + "0x334", 0x334 + }, + { + "0x230", 0x230 + }, + { + "0x234", 0x234 + }, + { + "0x130", 0x130 + }, + { + "0x134", 0x134 + }, + { + "" + } + }, + }, + { + "irq", "IRQ", CONFIG_SELECTION, "", 9, + { + { + "IRQ 9", 9 + }, + { + "IRQ 10", 10 + }, + { + "IRQ 11", 11 + }, + { + "IRQ 12", 12 + }, + { + "IRQ 14", 14 + }, + { + "IRQ 15", 15 + }, + { + "" + } + }, + }, + { + "dma", "DMA channel", CONFIG_SELECTION, "", 6, + { + { + "DMA 5", 5 + }, + { + "DMA 6", 6 + }, + { + "DMA 7", 7 + }, + { + "" + } + }, + }, + { + "bios", "Enable BIOS", CONFIG_BINARY, "", 0 + }, + { + "bios_addr", "BIOS Address", CONFIG_HEX20, "", 0xd8000, + { + { + "C800H", 0xc8000 + }, + { + "D000H", 0xd0000 + }, + { + "D800H", 0xd8000 + }, + { + "" + } + }, + }, + { + "", "", -1 + } +}; + +device_t aha1540b_device = { + "Adaptec AHA-1540B", + 0, + aha_154xB_init, + aha_close, + NULL, + NULL, + NULL, + NULL, + aha_154XCF_config +}; + +device_t aha1542cf_device = { + "Adaptec AHA-1542CF", + 0, + aha_154xCF_init, + aha_close, + NULL, + NULL, + NULL, + NULL, + aha_154XCF_config +}; + +device_t aha1640_device = { + "Adaptec AHA-1640", + DEVICE_MCA, + aha_1640_init, + aha_close, + NULL, + NULL, + NULL, + NULL +}; \ No newline at end of file diff --git a/src/scsi_aha154x.h b/src/scsi_aha154x.h new file mode 100644 index 000000000..d15de7c2d --- /dev/null +++ b/src/scsi_aha154x.h @@ -0,0 +1,20 @@ +#ifndef SCSI_AHA154X_H +# define SCSI_AHA154X_H + + +typedef struct { + uint8_t flags; /* local flags */ + uint8_t bid; /* board ID */ + char fwl, fwh; /* firmware info */ +} aha_info; +#define AHA_GLAG_MEMEN 0x01 /* BIOS Shadow RAM enabled */ + + +extern device_t aha1540b_device; +extern device_t aha1542cf_device; +extern device_t aha1640_device; + +extern void aha_device_reset(void *p); + + +#endif /*SCSI_AHA154X_H*/ diff --git a/src/scsi_buslogic.c b/src/scsi_buslogic.c new file mode 100644 index 000000000..2da990ee4 --- /dev/null +++ b/src/scsi_buslogic.c @@ -0,0 +1,2439 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * Emulation of BusLogic ISA and PCI SCSI controllers. Boards + * supported: + * + * 0 - BT-542B ISA; + * 1 - BT-958 PCI (but BT-542B ISA on non-PCI machines) + * + * Version: @(#)scsi_buslogic.c 1.0.4 2017/06/14 + * + * Authors: TheCollector1995, + * Miran Grca, + * Fred N. van Kempen, + * Copyright 2008-2017 Sarah Walker. + * Copyright 2016-2017 Miran Grca. + * Copyright 2017-2017 Fred N. van Kempen. + */ +#include +#include +#include +#include +#include +#include "ibm.h" +#include "io.h" +#include "mem.h" +#include "rom.h" +#include "dma.h" +#include "pic.h" +#include "pci.h" +#include "timer.h" +#include "device.h" +#include "scsi.h" +#include "scsi_disk.h" +#include "cdrom.h" +#include "scsi_buslogic.h" + + +#define BUSLOGIC_RESET_DURATION_NS UINT64_C(50000000) + + +/* + * Host Adapter I/O ports. + * + * READ Port x+0: STATUS + * WRITE Port x+0: CONTROL + * + * READ Port x+1: DATA + * WRITE Port x+1: COMMAND + * + * READ Port x+2: INTERRUPT STATUS + * WRITE Port x+2: (undefined?) + * + * R/W Port x+3: (undefined) + */ + +/* WRITE CONTROL commands. */ +#define CTRL_HRST 0x80 /* Hard reset */ +#define CTRL_SRST 0x40 /* Soft reset */ +#define CTRL_IRST 0x20 /* interrupt reset */ +#define CTRL_SCRST 0x10 /* SCSI bus reset */ + +/* READ STATUS. */ +#define STAT_STST 0x80 /* self-test in progress */ +#define STAT_DFAIL 0x40 /* internal diagnostic failure */ +#define STAT_INIT 0x20 /* mailbox initialization required */ +#define STAT_IDLE 0x10 /* HBA is idle */ +#define STAT_CDFULL 0x08 /* Command/Data output port is full */ +#define STAT_DFULL 0x04 /* Data input port is full */ +#define STAT_INVCMD 0x01 /* Invalid command */ + +/* READ/WRITE DATA. */ +#define CMD_NOP 0x00 /* No operation */ +#define CMD_MBINIT 0x01 /* mailbox initialization */ +#define CMD_START_SCSI 0x02 /* Start SCSI command */ +#define CMD_BIOS 0x03 /* Execute ROM BIOS command */ +#define CMD_INQUIRY 0x04 /* Adapter inquiry */ +#define CMD_EMBOI 0x05 /* enable Mailbox Out Interrupt */ +#define CMD_SELTIMEOUT 0x06 /* Set SEL timeout */ +#define CMD_BUSON_TIME 0x07 /* set bus-On time */ +#define CMD_BUSOFF_TIME 0x08 /* set bus-off time */ +#define CMD_DMASPEED 0x09 /* set ISA DMA speed */ +#define CMD_RETDEVS 0x0A /* return installed devices */ +#define CMD_RETCONF 0x0B /* return configuration data */ +#define CMD_TARGET 0x0C /* set HBA to target mode */ +#define CMD_RETSETUP 0x0D /* return setup data */ +#define CMD_ECHO 0x1F /* ECHO command data */ + +/* READ INTERRUPT STATUS. */ +#define INTR_ANY 0x80 /* any interrupt */ +#define INTR_SRCD 0x08 /* SCSI reset detected */ +#define INTR_HACC 0x04 /* HA command complete */ +#define INTR_MBOA 0x02 /* MBO empty */ +#define INTR_MBIF 0x01 /* MBI full */ + + +/* + * Auto SCSI structure which is located + * in host adapter RAM and contains several + * configuration parameters. + */ +#pragma pack(push,1) +typedef struct { + uint8_t aInternalSignature[2]; + uint8_t cbInformation; + uint8_t aHostAdaptertype[6]; + uint8_t uReserved1; + uint8_t fFloppyEnabled :1, + fFloppySecondary :1, + fLevelSensitiveInterrupt:1, + uReserved2 :2, + uSystemRAMAreForBIOS :3; + uint8_t uDMAChannel :7, + fDMAAutoConfiguration :1, + uIrqChannel :7, + fIrqAutoConfiguration :1; + uint8_t uDMATransferRate; + uint8_t uSCSIId; + uint8_t fLowByteTerminated :1, + fParityCheckingEnabled :1, + fHighByteTerminated :1, + fNoisyCablingEnvironment:1, + fFastSyncNegotiation :1, + fBusResetEnabled :1, + fReserved3 :1, + fActiveNegotiationEna :1; + uint8_t uBusOnDelay; + uint8_t uBusOffDelay; + uint8_t fHostAdapterBIOSEnabled :1, + fBIOSRedirectionOfInt19 :1, + fExtendedTranslation :1, + fMapRemovableAsFixed :1, + fReserved4 :1, + fBIOSMoreThan2Drives :1, + fBIOSInterruptMode :1, + fFlopticalSupport :1; + uint16_t u16DeviceEnabledMask; + uint16_t u16WidePermittedMask; + uint16_t u16FastPermittedMask; + uint16_t u16SynchronousPermittedMask; + uint16_t u16DisconnectPermittedMask; + uint16_t u16SendStartUnitCommandMask; + uint16_t u16IgnoreInBIOSScanMask; + unsigned char uPCIInterruptPin : 2; + unsigned char uHostAdapterIoPortAddress : 2; + uint8_t fStrictRoundRobinMode : 1; + uint8_t fVesaBusSpeedGreaterThan33MHz : 1; + uint8_t fVesaBurstWrite : 1; + uint8_t fVesaBurstRead : 1; + uint16_t u16UltraPermittedMask; + uint32_t uReserved5; + uint8_t uReserved6; + uint8_t uAutoSCSIMaximumLUN; + uint8_t fReserved7 : 1; + uint8_t fSCAMDominant : 1; + uint8_t fSCAMenabled : 1; + uint8_t fSCAMLevel2 : 1; + unsigned char uReserved8 : 4; + uint8_t fInt13Extension : 1; + uint8_t fReserved9 : 1; + uint8_t fCDROMBoot : 1; + unsigned char uReserved10 : 5; + unsigned char uBootTargetId : 4; + unsigned char uBootChannel : 4; + uint8_t fForceBusDeviceScanningOrder : 1; + unsigned char uReserved11 : 7; + uint16_t u16NonTaggedToAlternateLunPermittedMask; + uint16_t u16RenegotiateSyncAfterCheckConditionMask; + uint8_t aReserved12[10]; + uint8_t aManufacturingDiagnostic[2]; + uint16_t u16Checksum; +} AutoSCSIRam; +#pragma pack(pop) + +/* The local RAM. */ +#pragma pack(push,1) +typedef union { + uint8_t u8View[256]; /* byte view */ + struct { /* structured view */ + uint8_t u8Bios[64]; /* offset 0 - 63 is for BIOS */ + AutoSCSIRam autoSCSIData; /* Auto SCSI structure */ + } structured; +} HALocalRAM; +#pragma pack(pop) + +/** Structure for the INQUIRE_SETUP_INFORMATION reply. */ +#pragma pack(push,1) +typedef struct { + uint8_t uOffset :4, + uTransferPeriod :3, + fSynchronous :1; +} ReplyInquireSetupInformationSynchronousValue; +#pragma pack(pop) + +#pragma pack(push,1) +typedef struct { + uint8_t fSynchronousInitiationEnabled :1, + fParityCheckingEnabled :1, + uReserved1 :6; + uint8_t uBusTransferRate; + uint8_t uPreemptTimeOnBus; + uint8_t uTimeOffBus; + uint8_t cMailbox; + addr24 MailboxAddress; + ReplyInquireSetupInformationSynchronousValue SynchronousValuesId0To7[8]; + uint8_t uDisconnectPermittedId0To7; + uint8_t uSignature; + uint8_t uCharacterD; + uint8_t uHostBusType; + uint8_t uWideTransferPermittedId0To7; + uint8_t uWideTransfersActiveId0To7; + ReplyInquireSetupInformationSynchronousValue SynchronousValuesId8To15[8]; + uint8_t uDisconnectPermittedId8To15; + uint8_t uReserved2; + uint8_t uWideTransferPermittedId8To15; + uint8_t uWideTransfersActiveId8To15; +} ReplyInquireSetupInformation; +#pragma pack(pop) + +/* Structure for the INQUIRE_EXTENDED_SETUP_INFORMATION. */ +#pragma pack(push,1) +typedef struct { + uint8_t uBusType; + uint8_t uBiosAddress; + uint16_t u16ScatterGatherLimit; + uint8_t cMailbox; + uint32_t uMailboxAddressBase; + uint8_t uReserved1 :2, + fFastEISA :1, + uReserved2 :3, + fLevelSensitiveInterrupt:1, + uReserved3 :1; + uint8_t aFirmwareRevision[3]; + uint8_t fHostWideSCSI :1, + fHostDifferentialSCSI :1, + fHostSupportsSCAM :1, + fHostUltraSCSI :1, + fHostSmartTermination :1, + uReserved4 :3; +} ReplyInquireExtendedSetupInformation; +#pragma pack(pop) + +/* Structure for the INQUIRE_PCI_HOST_ADAPTER_INFORMATION reply. */ +#pragma pack(push,1) +typedef struct { + uint8_t IsaIOPort; + uint8_t IRQ; + uint8_t LowByteTerminated :1, + HighByteTerminated :1, + uReserved :2, /* Reserved. */ + JP1 :1, /* Whatever that means. */ + JP2 :1, /* Whatever that means. */ + JP3 :1, /* Whatever that means. */ + InformationIsValid :1; + uint8_t uReserved2; /* Reserved. */ +} BuslogicPCIInformation_t; +#pragma pack(pop) + +#pragma pack(push,1) +typedef struct { + uint8_t Count; + addr24 Address; +} MailboxInit_t; +#pragma pack(pop) + +#pragma pack(push,1) +typedef struct { + uint8_t Count; + uint32_t Address; +} MailboxInitExtended_t; +#pragma pack(pop) + + +/* + * Mailbox Definitions. + * + * Mailbox Out (MBO) command values. + */ +#define MBO_FREE 0x00 +#define MBO_START 0x01 +#define MBO_ABORT 0x02 + +/* Mailbox In (MBI) status values. */ +#define MBI_FREE 0x00 +#define MBI_SUCCESS 0x01 +#define MBI_ABORT 0x02 +#define MBI_NOT_FOUND 0x03 +#define MBI_ERROR 0x04 + + +#pragma pack(push,1) +typedef struct { + uint8_t CmdStatus; + addr24 CCBPointer; +} Mailbox_t; +#pragma pack(pop) + +#pragma pack(push,1) +typedef struct { + uint32_t CCBPointer; + union { + struct { + uint8_t Reserved[3]; + uint8_t ActionCode; + } out; + struct { + uint8_t HostStatus; + uint8_t TargetStatus; + uint8_t Reserved; + uint8_t CompletionCode; + } in; + } u; +} Mailbox32_t; +#pragma pack(pop) + + +/* + * + * CCB - SCSI Command Control Block + * + * The CCB is a superset of the CDB (Command Descriptor Block) + * and specifies detailed information about a SCSI command. + * + */ +/* Byte 0 Command Control Block Operation Code */ +#define SCSI_INITIATOR_COMMAND 0x00 +#define TARGET_MODE_COMMAND 0x01 +#define SCATTER_GATHER_COMMAND 0x02 +#define SCSI_INITIATOR_COMMAND_RES 0x03 +#define SCATTER_GATHER_COMMAND_RES 0x04 +#define BUS_RESET 0x81 + +/* Byte 1 Address and Direction Control */ +#define CCB_TARGET_ID_SHIFT 0x06 /* CCB Op Code = 00, 02 */ +#define CCB_INITIATOR_ID_SHIFT 0x06 /* CCB Op Code = 01 */ +#define CCB_DATA_XFER_IN 0x01 +#define CCB_DATA_XFER_OUT 0x02 +#define CCB_LUN_MASK 0x07 /* Logical Unit Number */ + +/* Byte 2 SCSI_Command_Length - Length of SCSI CDB + Byte 3 Request Sense Allocation Length */ +#define FOURTEEN_BYTES 0x00 /* Request Sense Buffer size */ +#define NO_AUTO_REQUEST_SENSE 0x01 /* No Request Sense Buffer */ + +/* Bytes 4, 5 and 6 Data Length - Data transfer byte count */ +/* Bytes 7, 8 and 9 Data Pointer - SGD List or Data Buffer */ +/* Bytes 10, 11 and 12 Link Pointer - Next CCB in Linked List */ +/* Byte 13 Command Link ID - TBD (I don't know yet) */ +/* Byte 14 Host Status - Host Adapter status */ +#define CCB_COMPLETE 0x00 /* CCB completed without error */ +#define CCB_LINKED_COMPLETE 0x0A /* Linked command completed */ +#define CCB_LINKED_COMPLETE_INT 0x0B /* Linked complete with intr */ +#define CCB_SELECTION_TIMEOUT 0x11 /* Set SCSI selection timed out */ +#define CCB_DATA_OVER_UNDER_RUN 0x12 +#define CCB_UNEXPECTED_BUS_FREE 0x13 /* Trg dropped SCSI BSY */ +#define CCB_PHASE_SEQUENCE_FAIL 0x14 /* Trg bus phase sequence fail */ +#define CCB_BAD_MBO_COMMAND 0x15 /* MBO command not 0, 1 or 2 */ +#define CCB_INVALID_OP_CODE 0x16 /* CCB invalid operation code */ +#define CCB_BAD_LINKED_LUN 0x17 /* Linked CCB LUN diff from 1st */ +#define CCB_INVALID_DIRECTION 0x18 /* Invalid target direction */ +#define CCB_DUPLICATE_CCB 0x19 /* Duplicate CCB */ +#define CCB_INVALID_CCB 0x1A /* Invalid CCB - bad parameter */ + +/* Byte 15 Target Status + + See scsi.h files for these statuses. + Bytes 16 and 17 Reserved (must be 0) + Bytes 18 through 18+n-1, where n=size of CDB Command Descriptor Block */ + +#pragma pack(push,1) +typedef struct { + uint8_t Opcode; + uint8_t Reserved1 :3, + ControlByte :2, + TagQueued :1, + QueueTag :2; + uint8_t CdbLength; + uint8_t RequestSenseLength; + uint32_t DataLength; + uint32_t DataPointer; + uint8_t Reserved2[2]; + uint8_t HostStatus; + uint8_t TargetStatus; + uint8_t Id; + uint8_t Lun :5, + LegacyTagEnable :1, + LegacyQueueTag :2; + uint8_t Cdb[12]; + uint8_t Reserved3[6]; + uint32_t SensePointer; +} CCB32; +#pragma pack(pop) + +#pragma pack(push,1) +typedef struct { + uint8_t Opcode; + uint8_t Lun :3, + ControlByte :2, + Id :3; + uint8_t CdbLength; + uint8_t RequestSenseLength; + addr24 DataLength; + addr24 DataPointer; + addr24 LinkPointer; + uint8_t LinkId; + uint8_t HostStatus; + uint8_t TargetStatus; + uint8_t Reserved[2]; + uint8_t Cdb[12]; +} CCB; +#pragma pack(pop) + +#pragma pack(push,1) +typedef struct { + uint8_t Opcode; + uint8_t Pad1 :3, + ControlByte :2, + Pad2 :3; + uint8_t CdbLength; + uint8_t RequestSenseLength; + uint8_t Pad3[10]; + uint8_t HostStatus; + uint8_t TargetStatus; + uint8_t Pad4[2]; + uint8_t Cdb[12]; +} CCBC; +#pragma pack(pop) + +#pragma pack(push,1) +typedef union { + CCB32 new; + CCB old; + CCBC common; +} CCBU; +#pragma pack(pop) + + +#pragma pack(push,1) +typedef struct { + CCBU CmdBlock; + uint8_t *RequestSenseBuffer; + uint32_t CCBPointer; + int Is24bit; + uint8_t TargetID; + uint8_t LUN; + uint8_t HostStatus; + uint8_t TargetStatus; + uint8_t MailboxCompletionCode; +} Req_t; +#pragma pack(pop) + +#pragma pack(push,1) +typedef struct { + rom_t bios; + int UseLocalRAM; + int StrictRoundRobinMode; + int ExtendedLUNCCBFormat; + HALocalRAM LocalRAM; + Req_t Req; + uint8_t Status; + uint8_t Interrupt; + uint8_t Geometry; + uint8_t Control; + uint8_t Command; + uint8_t CmdBuf[53]; + uint8_t CmdParam; + uint8_t CmdParamLeft; + uint8_t DataBuf[64]; + uint16_t DataReply; + uint16_t DataReplyLeft; + uint32_t MailboxCount; + uint32_t MailboxOutAddr; + uint32_t MailboxOutPosCur; + uint32_t MailboxInAddr; + uint32_t MailboxInPosCur; + int Base; + int PCIBase; + int MMIOBase; + int Irq; + int DmaChannel; + int IrqEnabled; + int Mbx24bit; + int MailboxOutInterrupts; + int MbiActive[256]; + int PendingInterrupt; + int Lock; + mem_mapping_t mmio_mapping; + int chip; + int Card; +} Buslogic_t; +#pragma pack(pop) + + +static int BuslogicResetCallback = 0; +static int BuslogicCallback = 0; +static int BuslogicInOperation = 0; +static Buslogic_t *BuslogicResetDevice; + + +enum { + CHIP_BUSLOGIC_ISA, + CHIP_BUSLOGIC_PCI +}; + + +int buslogic_do_log = 0; + + +static void +BuslogicLog(const char *format, ...) +{ +#ifdef ENABLE_BUSLOGIC_LOG + va_list ap; + + if (buslogic_do_log) { + va_start(ap, format); + vprintf(format, ap); + va_end(ap); + fflush(stdout); + } +#endif +} +#define pclog BuslogicLog + + +static void +BuslogicInterrupt(Buslogic_t *bl, int set) +{ + if (bl->chip == CHIP_BUSLOGIC_PCI) + { + if (set) + { + pci_set_irq(bl->Card, PCI_INTB); + } + else + { + pci_clear_irq(bl->Card, PCI_INTB); + } + } + else + { + if (set) + { + picint(1 << bl->Irq); + } + else + { + picintc(1 << bl->Irq); + } + } +} + + +static void +BuslogicClearInterrupt(Buslogic_t *bl) +{ + pclog("Buslogic: Lowering Interrupt 0x%02X\n", bl->Interrupt); + bl->Interrupt = 0; + pclog("Lowering IRQ %i\n", bl->Irq); + BuslogicInterrupt(bl, 0); + if (bl->PendingInterrupt) { + bl->Interrupt = bl->PendingInterrupt; + pclog("Buslogic: Raising Interrupt 0x%02X (Pending)\n", bl->Interrupt); + if (bl->MailboxOutInterrupts || !(bl->Interrupt & INTR_MBOA)) { + if (bl->IrqEnabled) BuslogicInterrupt(bl, 1); + } + bl->PendingInterrupt = 0; + } +} + + +static void +BuslogicLocalRAM(Buslogic_t *bl) +{ + /* + * These values are mostly from what I think is right + * looking at the dmesg output from a Linux guest inside + * a VMware server VM. + * + * So they don't have to be right :) + */ + memset(bl->LocalRAM.u8View, 0, sizeof(HALocalRAM)); + bl->LocalRAM.structured.autoSCSIData.fLevelSensitiveInterrupt = 1; + bl->LocalRAM.structured.autoSCSIData.fParityCheckingEnabled = 1; + bl->LocalRAM.structured.autoSCSIData.fExtendedTranslation = 1; /* Same as in geometry register. */ + bl->LocalRAM.structured.autoSCSIData.u16DeviceEnabledMask = UINT16_MAX; /* All enabled. Maybe mask out non present devices? */ + bl->LocalRAM.structured.autoSCSIData.u16WidePermittedMask = UINT16_MAX; + bl->LocalRAM.structured.autoSCSIData.u16FastPermittedMask = UINT16_MAX; + bl->LocalRAM.structured.autoSCSIData.u16SynchronousPermittedMask = UINT16_MAX; + bl->LocalRAM.structured.autoSCSIData.u16DisconnectPermittedMask = UINT16_MAX; + bl->LocalRAM.structured.autoSCSIData.fStrictRoundRobinMode = bl->StrictRoundRobinMode; + bl->LocalRAM.structured.autoSCSIData.u16UltraPermittedMask = UINT16_MAX; + /** @todo calculate checksum? */ +} + + +static void +BuslogicReset(Buslogic_t *bl) +{ + BuslogicCallback = 0; + BuslogicResetCallback = 0; + bl->Status = STAT_IDLE | STAT_INIT; + bl->Geometry = 0x80; + bl->Command = 0xFF; + bl->CmdParam = 0; + bl->CmdParamLeft = 0; + bl->IrqEnabled = 1; + bl->StrictRoundRobinMode = 0; + bl->ExtendedLUNCCBFormat = 0; + bl->MailboxOutPosCur = 0; + bl->MailboxInPosCur = 0; + bl->MailboxOutInterrupts = 0; + bl->PendingInterrupt = 0; + bl->Lock = 0; + BuslogicInOperation = 0; + + BuslogicClearInterrupt(bl); + + BuslogicLocalRAM(bl); +} + + +static void +BuslogicResetControl(Buslogic_t *bl, uint8_t Reset) +{ + BuslogicReset(bl); + if (Reset) { + bl->Status |= STAT_STST; + bl->Status &= ~STAT_IDLE; + } + BuslogicResetCallback = BUSLOGIC_RESET_DURATION_NS * TIMER_USEC; +} + + +static void +BuslogicCommandComplete(Buslogic_t *bl) +{ + bl->DataReply = 0; + bl->Status |= STAT_IDLE; + + if (bl->Command != 0x02) { + bl->Status &= ~STAT_DFULL; + bl->Interrupt = (INTR_ANY | INTR_HACC); + pclog("Raising IRQ %i\n", bl->Irq); + if (bl->IrqEnabled) + BuslogicInterrupt(bl, 1); + } + + bl->Command = 0xFF; + bl->CmdParam = 0; +} + + +static void +BuslogicRaiseInterrupt(Buslogic_t *bl, uint8_t Interrupt) +{ + if (bl->Interrupt & INTR_HACC) { + pclog("Pending IRQ\n"); + bl->PendingInterrupt = Interrupt; + } else { + bl->Interrupt = Interrupt; + pclog("Raising IRQ %i\n", bl->Irq); + if (bl->IrqEnabled) + BuslogicInterrupt(bl, 1); + } +} + + +static void +BuslogicMailboxInSetup(Buslogic_t *bl, uint32_t CCBPointer, CCBU *CmdBlock, + uint8_t HostStatus, uint8_t TargetStatus, + uint8_t MailboxCompletionCode) +{ + Req_t *req = &bl->Req; + + req->CCBPointer = CCBPointer; + memcpy(&(req->CmdBlock), CmdBlock, sizeof(CCB32)); + req->Is24bit = bl->Mbx24bit; + req->HostStatus = HostStatus; + req->TargetStatus = TargetStatus; + req->MailboxCompletionCode = MailboxCompletionCode; + + pclog("Mailbox in setup\n"); + + BuslogicInOperation = 2; +} + + +static void +BuslogicMailboxIn(Buslogic_t *bl) +{ + Req_t *req = &bl->Req; + uint32_t CCBPointer = req->CCBPointer; + CCBU *CmdBlock = &(req->CmdBlock); + uint8_t HostStatus = req->HostStatus; + uint8_t TargetStatus = req->TargetStatus; + uint8_t MailboxCompletionCode = req->MailboxCompletionCode; + Mailbox32_t Mailbox32; + Mailbox_t MailboxIn; + uint32_t Incoming; + + Mailbox32.CCBPointer = CCBPointer; + Mailbox32.u.in.HostStatus = HostStatus; + Mailbox32.u.in.TargetStatus = TargetStatus; + Mailbox32.u.in.CompletionCode = MailboxCompletionCode; + + Incoming = bl->MailboxInAddr + (bl->MailboxInPosCur * (bl->Mbx24bit ? sizeof(Mailbox_t) : sizeof(Mailbox32_t))); + + if (MailboxCompletionCode != MBI_NOT_FOUND) { + CmdBlock->common.HostStatus = HostStatus; + CmdBlock->common.TargetStatus = TargetStatus; + + /* Rewrite the CCB up to the CDB. */ + pclog("CCB rewritten to the CDB (pointer %08X, length %i)\n", CCBPointer, offsetof(CCBC, Cdb)); + DMAPageWrite(CCBPointer, (char *)CmdBlock, offsetof(CCBC, Cdb)); + } else { + pclog("Mailbox not found!\n"); + } + + pclog("Host Status 0x%02X, Target Status 0x%02X\n", + HostStatus, TargetStatus); + + if (bl->Mbx24bit) { + MailboxIn.CmdStatus = Mailbox32.u.in.CompletionCode; + U32_TO_ADDR(MailboxIn.CCBPointer, Mailbox32.CCBPointer); + pclog("Mailbox 24-bit: Status=0x%02X, CCB at 0x%04X\n", MailboxIn.CmdStatus, ADDR_TO_U32(MailboxIn.CCBPointer)); + + DMAPageWrite(Incoming, (char *)&MailboxIn, sizeof(Mailbox_t)); + pclog("%i bytes of 24-bit mailbox written to: %08X\n", sizeof(Mailbox_t), Incoming); + } else { + pclog("Mailbox 32-bit: Status=0x%02X, CCB at 0x%04X\n", Mailbox32.u.in.CompletionCode, Mailbox32.CCBPointer); + + DMAPageWrite(Incoming, (char *)&Mailbox32, sizeof(Mailbox32_t)); + pclog("%i bytes of 32-bit mailbox written to: %08X\n", sizeof(Mailbox32_t), Incoming); + } + + bl->MailboxInPosCur++; + if (bl->MailboxInPosCur >= bl->MailboxCount) + bl->MailboxInPosCur = 0; + + BuslogicRaiseInterrupt(bl, INTR_MBIF | INTR_ANY); + + BuslogicInOperation = 0; +} + + +static void +BuslogicReadSGEntries(int Is24bit, uint32_t SGList, uint32_t Entries, SGE32 *SG) +{ + uint32_t i; + SGE SGE24[MAX_SG_DESCRIPTORS]; + + if (Is24bit) { + DMAPageRead(SGList, (char *)&SGE24, Entries * sizeof(SGE)); + + for (i=0;iCmdBlock.old.DataPointer); + DataLength = ADDR_TO_U32(req->CmdBlock.old.DataLength); + } else { + DataPointer = req->CmdBlock.new.DataPointer; + DataLength = req->CmdBlock.new.DataLength; + } + pclog("Data Buffer write: length %d, pointer 0x%04X\n", + DataLength, DataPointer); + + if (SCSIDevices[req->TargetID][req->LUN].CmdBuffer != NULL) + { + free(SCSIDevices[req->TargetID][req->LUN].CmdBuffer); + SCSIDevices[req->TargetID][req->LUN].CmdBuffer = NULL; + } + + if ((req->CmdBlock.common.ControlByte != 0x03) && DataLength) { + if (req->CmdBlock.common.Opcode == SCATTER_GATHER_COMMAND || + req->CmdBlock.common.Opcode == SCATTER_GATHER_COMMAND_RES) { + uint32_t SGRead; + uint32_t ScatterEntry; + SGE32 SGBuffer[MAX_SG_DESCRIPTORS]; + uint32_t SGLeft = DataLength / SGEntryLength; + uint32_t SGAddrCurrent = DataPointer; + uint32_t DataToTransfer = 0; + + do { + SGRead = (SGLeft < ELEMENTS(SGBuffer)) ? SGLeft : ELEMENTS(SGBuffer); + SGLeft -= SGRead; + + BuslogicReadSGEntries(Is24bit, SGAddrCurrent, SGRead, SGBuffer); + + for (ScatterEntry = 0; ScatterEntry < SGRead; ScatterEntry++) { + uint32_t Address; + + pclog("BusLogic S/G Write: ScatterEntry=%u\n", ScatterEntry); + + Address = SGBuffer[ScatterEntry].SegmentPointer; + DataToTransfer += SGBuffer[ScatterEntry].Segment; + + pclog("BusLogic S/G Write: Address=%08X DatatoTransfer=%u\n", Address, DataToTransfer); + } + + SGAddrCurrent += SGRead * SGEntryLength; + } while (SGLeft > 0); + + pclog("Data to transfer (S/G) %d\n", DataToTransfer); + + SCSIDevices[req->TargetID][req->LUN].InitLength = DataToTransfer; + + SCSIDevices[req->TargetID][req->LUN].CmdBuffer = (uint8_t *) malloc(DataToTransfer); + memset(SCSIDevices[req->TargetID][req->LUN].CmdBuffer, 0, DataToTransfer); + + /* If the control byte is 0x00, it means that the transfer direction is set up by the SCSI command without + checking its length, so do this procedure for both no read/write commands. */ + if ((req->CmdBlock.common.ControlByte == CCB_DATA_XFER_OUT) || + (req->CmdBlock.common.ControlByte == 0x00)) { + SGLeft = DataLength / SGEntryLength; + SGAddrCurrent = DataPointer; + + do { + SGRead = (SGLeft < ELEMENTS(SGBuffer)) ? SGLeft : ELEMENTS(SGBuffer); + SGLeft -= SGRead; + + BuslogicReadSGEntries(Is24bit, SGAddrCurrent, + SGRead, SGBuffer); + + for (ScatterEntry = 0; ScatterEntry < SGRead; ScatterEntry++) { + uint32_t Address; + + pclog("BusLogic S/G Write: ScatterEntry=%u\n", ScatterEntry); + + Address = SGBuffer[ScatterEntry].SegmentPointer; + DataToTransfer = SGBuffer[ScatterEntry].Segment; + + pclog("BusLogic S/G Write: Address=%08X DatatoTransfer=%u\n", Address, DataToTransfer); + + DMAPageRead(Address, (char *)SCSIDevices[req->TargetID][req->LUN].CmdBuffer + sg_buffer_pos, DataToTransfer); + sg_buffer_pos += DataToTransfer; + } + + SGAddrCurrent += SGRead * (Is24bit ? sizeof(SGE) : sizeof(SGE32)); + } while (SGLeft > 0); + } + } else if (req->CmdBlock.common.Opcode == SCSI_INITIATOR_COMMAND || + req->CmdBlock.common.Opcode == SCSI_INITIATOR_COMMAND_RES) { + uint32_t Address = DataPointer; + + SCSIDevices[req->TargetID][req->LUN].InitLength = DataLength; + + SCSIDevices[req->TargetID][req->LUN].CmdBuffer = (uint8_t *) malloc(DataLength); + memset(SCSIDevices[req->TargetID][req->LUN].CmdBuffer, 0, DataLength); + + if (DataLength > 0) { + DMAPageRead(Address, + (char *)SCSIDevices[req->TargetID][req->LUN].CmdBuffer, + SCSIDevices[req->TargetID][req->LUN].InitLength); + } + } + } +} + + +static void +BuslogicDataBufferFree(Req_t *req) +{ + uint32_t DataPointer = 0; + uint32_t DataLength = 0; + uint32_t sg_buffer_pos = 0; + uint32_t SGRead; + uint32_t ScatterEntry; + SGE32 SGBuffer[MAX_SG_DESCRIPTORS]; + uint32_t SGEntrySize; + uint32_t SGLeft; + uint32_t SGAddrCurrent; + uint32_t Address; + uint32_t Residual; + + if (req->Is24bit) { + DataPointer = ADDR_TO_U32(req->CmdBlock.old.DataPointer); + DataLength = ADDR_TO_U32(req->CmdBlock.old.DataLength); + } else { + DataPointer = req->CmdBlock.new.DataPointer; + DataLength = req->CmdBlock.new.DataLength; + } + + if ((DataLength != 0) && (req->CmdBlock.common.Cdb[0] == GPCMD_TEST_UNIT_READY)) { + pclog("Data length not 0 with TEST UNIT READY: %i (%i)\n", + DataLength, SCSIDevices[req->TargetID][req->LUN].InitLength); + } + + if (req->CmdBlock.common.Cdb[0] == GPCMD_TEST_UNIT_READY) { + DataLength = 0; + } + + pclog("Data Buffer read: length %d, pointer 0x%04X\n", + DataLength, DataPointer); + + /* If the control byte is 0x00, it means that the transfer direction is set up by the SCSI command without + checking its length, so do this procedure for both read/write commands. */ + if ((DataLength > 0) && + ((req->CmdBlock.common.ControlByte == CCB_DATA_XFER_IN) || + (req->CmdBlock.common.ControlByte == 0x00))) { + if ((req->CmdBlock.common.Opcode == SCATTER_GATHER_COMMAND) || + (req->CmdBlock.common.Opcode == SCATTER_GATHER_COMMAND_RES)) { + SGEntrySize = (req->Is24bit ? sizeof(SGE) : sizeof(SGE32)); + SGLeft = DataLength / SGEntrySize; + SGAddrCurrent = DataPointer; + + do { + SGRead = (SGLeft < ELEMENTS(SGBuffer)) ? SGLeft : ELEMENTS(SGBuffer); + SGLeft -= SGRead; + + BuslogicReadSGEntries(req->Is24bit, SGAddrCurrent, + SGRead, SGBuffer); + + for (ScatterEntry = 0; ScatterEntry < SGRead; ScatterEntry++) { + uint32_t Address; + uint32_t DataToTransfer; + + pclog("BusLogic S/G: ScatterEntry=%u\n", ScatterEntry); + + Address = SGBuffer[ScatterEntry].SegmentPointer; + DataToTransfer = SGBuffer[ScatterEntry].Segment; + + pclog("BusLogic S/G: Writing %i bytes at %08X\n", DataToTransfer, Address); + + DMAPageWrite(Address, (char *)SCSIDevices[req->TargetID][req->LUN].CmdBuffer + sg_buffer_pos, DataToTransfer); + sg_buffer_pos += DataToTransfer; + } + + SGAddrCurrent += (SGRead * SGEntrySize); + } while (SGLeft > 0); + } else if (req->CmdBlock.common.Opcode == SCSI_INITIATOR_COMMAND || + req->CmdBlock.common.Opcode == SCSI_INITIATOR_COMMAND_RES) { + Address = DataPointer; + + pclog("BusLogic DMA: Writing %i bytes at %08X\n", DataLength, Address); + DMAPageWrite(Address, (char *)SCSIDevices[req->TargetID][req->LUN].CmdBuffer, DataLength); + } + } + + if ((req->CmdBlock.common.Opcode == SCSI_INITIATOR_COMMAND_RES) || + (req->CmdBlock.common.Opcode == SCATTER_GATHER_COMMAND_RES)) { + /* Should be 0 when scatter/gather? */ + if (DataLength >= SCSIDevices[req->TargetID][req->LUN].InitLength) { + Residual = DataLength; + Residual -= SCSIDevices[req->TargetID][req->LUN].InitLength; + } else { + Residual = 0; + } + + if (req->Is24bit) { + U32_TO_ADDR(req->CmdBlock.old.DataLength, Residual); + pclog("24-bit Residual data length for reading: %d\n", + ADDR_TO_U32(req->CmdBlock.old.DataLength)); + } else { + req->CmdBlock.new.DataLength = Residual; + pclog("32-bit Residual data length for reading: %d\n", + req->CmdBlock.new.DataLength); + } + } + + if (SCSIDevices[req->TargetID][req->LUN].CmdBuffer != NULL) + { + free(SCSIDevices[req->TargetID][req->LUN].CmdBuffer); + SCSIDevices[req->TargetID][req->LUN].CmdBuffer = NULL; + } +} + + +static uint8_t +BuslogicRead(uint16_t Port, void *p) +{ + Buslogic_t *bl = (Buslogic_t *)p; + uint8_t Temp; + + switch (Port & 3) { + case 0: + Temp = bl->Status; + break; + + case 1: + if (bl->UseLocalRAM) + Temp = bl->LocalRAM.u8View[bl->DataReply]; + else + Temp = bl->DataBuf[bl->DataReply]; + if (bl->DataReplyLeft) { + bl->DataReply++; + bl->DataReplyLeft--; + if (!bl->DataReplyLeft) { + BuslogicCommandComplete(bl); + } + } + break; + + case 2: + Temp = bl->Interrupt; + break; + + case 3: + Temp = bl->Geometry; + break; + } + + if (Port < 0x1000) { + pclog("Buslogic: Read Port 0x%02X, Returned Value %02X\n", + Port, Temp); + } + + return(Temp); +} + + +static uint16_t +BuslogicReadW(uint16_t Port, void *p) +{ + return BuslogicRead(Port, p); +} + + +static uint32_t +BuslogicReadL(uint16_t Port, void *p) +{ + return BuslogicRead(Port, p); +} + + +static void BuslogicWriteW(uint16_t Port, uint16_t Val, void *p); +static void BuslogicWriteL(uint16_t Port, uint32_t Val, void *p); +static void +BuslogicWrite(uint16_t Port, uint8_t Val, void *p) +{ + int i = 0; + uint8_t j = 0; + Buslogic_t *bl = (Buslogic_t *)p; + uint8_t Offset; + MailboxInit_t *MailboxInit; + ReplyInquireSetupInformation *ReplyISI; + MailboxInitExtended_t *MailboxInitE; + ReplyInquireExtendedSetupInformation *ReplyIESI; + BuslogicPCIInformation_t *ReplyPI; + char aModelName[] = "542B "; /* Trailing \0 is fine, that's the filler anyway. */ + int cCharsToTransfer; + + pclog("Buslogic: Write Port 0x%02X, Value %02X\n", Port, Val); + + switch (Port & 3) { + case 0: + if ((Val & CTRL_HRST) || (Val & CTRL_SRST)) { + uint8_t Reset = !(Val & CTRL_HRST); + BuslogicResetControl(bl, Reset); + break; + } + + if (Val & CTRL_IRST) { + BuslogicClearInterrupt(bl); + } + break; + + case 1: + /* Fast path for the mailbox execution command. */ + if ((Val == 0x02) && (bl->Command == 0xFF)) { + /* If there are no mailboxes configured, don't even try to do anything. */ + if (bl->MailboxCount) { + if (!BuslogicCallback) { + BuslogicCallback = 50 * SCSI_TIME; + } + } + return; + } + + if (bl->Command == 0xFF) { + bl->Command = Val; + bl->CmdParam = 0; + bl->CmdParamLeft = 0; + + bl->Status &= ~(STAT_INVCMD | STAT_IDLE); + pclog("Buslogic: Operation Code 0x%02X\n", Val); + switch (bl->Command) { + case 0x01: + bl->CmdParamLeft = sizeof(MailboxInit_t); + break; + + case 0x25: + bl->CmdParamLeft = 1; + break; + + case 0x05: + case 0x07: + case 0x08: + case 0x09: + case 0x0D: + case 0x1F: + case 0x21: + case 0x24: + bl->CmdParamLeft = 1; + break; + + case 0x06: + bl->CmdParamLeft = 4; + break; + + case 0x1C: + case 0x1D: + bl->CmdParamLeft = 3; + break; + + case 0x8B: + case 0x8D: + case 0x8F: + case 0x96: + bl->CmdParamLeft = 1; + break; + + case 0x81: + bl->CmdParamLeft = sizeof(MailboxInitExtended_t); + break; + + case 0x8C: + bl->CmdParamLeft = 1; + break; + + case 0x91: + bl->CmdParamLeft = 2; + break; + + case 0x95: /* Valid only for PCI */ + bl->CmdParamLeft = (bl->chip == CHIP_BUSLOGIC_PCI) ? 1 : 0; + break; + } + } else { + bl->CmdBuf[bl->CmdParam] = Val; + bl->CmdParam++; + bl->CmdParamLeft--; + } + + if (!bl->CmdParamLeft) { + pclog("Running Operation Code 0x%02X\n", bl->Command); + switch (bl->Command) { + case 0x00: + bl->DataReplyLeft = 0; + break; + + case 0x01: + bl->Mbx24bit = 1; + + MailboxInit = (MailboxInit_t *)bl->CmdBuf; + + bl->MailboxCount = MailboxInit->Count; + bl->MailboxOutAddr = ADDR_TO_U32(MailboxInit->Address); + bl->MailboxInAddr = bl->MailboxOutAddr + (bl->MailboxCount * sizeof(Mailbox_t)); + + pclog("Buslogic Initialize Mailbox Command\n"); + pclog("Mailbox Out Address=0x%08X\n", bl->MailboxOutAddr); + pclog("Mailbox In Address=0x%08X\n", bl->MailboxInAddr); + pclog("Initialized Mailbox, %d entries at 0x%08X\n", MailboxInit->Count, ADDR_TO_U32(MailboxInit->Address)); + + bl->Status &= ~STAT_INIT; + bl->DataReplyLeft = 0; + break; + + case 0x03: + bl->DataBuf[0] = 0x00; + bl->DataReplyLeft = 1; + break; + + case 0x04: + bl->DataBuf[0] = 0x41; + bl->DataBuf[1] = 0x41; + bl->DataBuf[2] = '5'; + bl->DataBuf[3] = '0'; + bl->DataReplyLeft = 4; + break; + + case 0x05: + if (bl->CmdBuf[0] <= 1) { + bl->MailboxOutInterrupts = bl->CmdBuf[0]; + pclog("Mailbox out interrupts: %s\n", bl->MailboxOutInterrupts ? "ON" : "OFF"); + } else { + bl->Status |= STAT_INVCMD; + } + bl->DataReplyLeft = 0; + break; + + case 0x06: + bl->DataReplyLeft = 0; + break; + + case 0x07: + bl->DataReplyLeft = 0; + bl->LocalRAM.structured.autoSCSIData.uBusOnDelay = bl->CmdBuf[0]; + pclog("Bus-on time: %d\n", bl->CmdBuf[0]); + break; + + case 0x08: + bl->DataReplyLeft = 0; + bl->LocalRAM.structured.autoSCSIData.uBusOffDelay = bl->CmdBuf[0]; + pclog("Bus-off time: %d\n", bl->CmdBuf[0]); + break; + + case 0x09: + bl->DataReplyLeft = 0; + bl->LocalRAM.structured.autoSCSIData.uDMATransferRate = bl->CmdBuf[0]; + pclog("DMA transfer rate: %02X\n", bl->CmdBuf[0]); + break; + + case 0x0A: + memset(bl->DataBuf, 0, 8); + for (i=0; i<7; i++) { + bl->DataBuf[i] = 0; + for (j=0; j<8; j++) { + if (SCSIDevices[i][j].LunType != SCSI_NONE) + bl->DataBuf[i] |= (1 << j); + } + } + bl->DataBuf[7] = 0; + bl->DataReplyLeft = 8; + break; + + case 0x0B: + bl->DataBuf[0] = (1 << bl->DmaChannel); + if ((bl->Irq >= 9) && (bl->Irq <= 15)) + { + bl->DataBuf[1] = (1<<(bl->Irq-9)); + } + else + bl->DataBuf[1] = 0; + { + } + bl->DataBuf[2] = 7; /* HOST ID */ + bl->DataReplyLeft = 3; + break; + + case 0x0D: + { + bl->DataReplyLeft = bl->CmdBuf[0]; + + ReplyISI = (ReplyInquireSetupInformation *)bl->DataBuf; + memset(ReplyISI, 0, sizeof(ReplyInquireSetupInformation)); + + ReplyISI->fSynchronousInitiationEnabled = 1; + ReplyISI->fParityCheckingEnabled = 1; + ReplyISI->cMailbox = bl->MailboxCount; + U32_TO_ADDR(ReplyISI->MailboxAddress, bl->MailboxOutAddr); + + ReplyISI->uSignature = 'B'; + /* The 'D' signature prevents Buslogic's OS/2 drivers from getting too + * friendly with Adaptec hardware and upsetting the HBA state. + */ + ReplyISI->uCharacterD = 'D'; /* BusLogic model. */ + ReplyISI->uHostBusType = (bl->chip == CHIP_BUSLOGIC_PCI) ? 'F' : 'A'; /* ISA bus. */ + + pclog("Return Setup Information: %d\n", bl->CmdBuf[0]); + } + break; + + case 0x1C: + { + uint32_t FIFOBuf; + addr24 Address; + + bl->DataReplyLeft = 0; + Address.hi = bl->CmdBuf[0]; + Address.mid = bl->CmdBuf[1]; + Address.lo = bl->CmdBuf[2]; + FIFOBuf = ADDR_TO_U32(Address); + DMAPageRead(FIFOBuf, (char *)&bl->LocalRAM.u8View[64], 64); + } + break; + + case 0x1D: + { + uint32_t FIFOBuf; + addr24 Address; + + bl->DataReplyLeft = 0; + Address.hi = bl->CmdBuf[0]; + Address.mid = bl->CmdBuf[1]; + Address.lo = bl->CmdBuf[2]; + FIFOBuf = ADDR_TO_U32(Address); + pclog("Buslogic FIFO: Writing 64 bytes at %08X\n", FIFOBuf); + DMAPageWrite(FIFOBuf, (char *)&bl->LocalRAM.u8View[64], 64); + } + break; + + case 0x1F: + bl->DataBuf[0] = bl->CmdBuf[0]; + bl->DataReplyLeft = 1; + break; + + case 0x20: + bl->DataReplyLeft = 0; + BuslogicResetControl(bl, 1); + break; + + case 0x21: + if (bl->CmdParam == 1) + bl->CmdParamLeft = bl->CmdBuf[0]; + bl->DataReplyLeft = 0; + break; + + case 0x23: + memset(bl->DataBuf, 0, 8); + for (i = 8; i < 16; i++) { +#if 1 /* FIXME: Kotori, check this! */ + bl->DataBuf[i-8] = 0; + for (j=0; j<8; j++) { + if (SCSIDevices[i][j].LunType != SCSI_NONE) + bl->DataBuf[i-8] |= (1<DataBuf[i] = 0; + for (i=0; j<8; j++) { + if (SCSIDevices[i][j].LunType != SCSI_NONE) + bl->DataBuf[i] |= (1<DataReplyLeft = 8; + break; + + case 0x24: + { + uint16_t TargetsPresentMask = 0; + + for (i=0; i<16; i++) { + for (j=0; j<8; j++) { + if (SCSIDevices[i][j].LunType != SCSI_NONE) + TargetsPresentMask |= (1 << i); + } + } + bl->DataBuf[0] = TargetsPresentMask & 0xFF; + bl->DataBuf[1] = TargetsPresentMask >> 8; + bl->DataReplyLeft = 2; + } + break; + + case 0x25: + if (bl->CmdBuf[0] == 0) + bl->IrqEnabled = 0; + else + bl->IrqEnabled = 1; + pclog("Lowering IRQ %i\n", bl->Irq); + BuslogicInterrupt(bl, 0); + break; + + case 0x81: + { + bl->Mbx24bit = 0; + + MailboxInitE = (MailboxInitExtended_t *)bl->CmdBuf; + + bl->MailboxCount = MailboxInitE->Count; + bl->MailboxOutAddr = MailboxInitE->Address; + bl->MailboxInAddr = MailboxInitE->Address + (bl->MailboxCount * sizeof(Mailbox32_t)); + + pclog("Buslogic Extended Initialize Mailbox Command\n"); + pclog("Mailbox Out Address=0x%08X\n", bl->MailboxOutAddr); + pclog("Mailbox In Address=0x%08X\n", bl->MailboxInAddr); + pclog("Initialized Extended Mailbox, %d entries at 0x%08X\n", MailboxInitE->Count, MailboxInitE->Address); + + bl->Status &= ~STAT_INIT; + bl->DataReplyLeft = 0; + } + break; + + case 0x84: + bl->DataBuf[0] = '7'; + bl->DataReplyLeft = 1; + break; + + case 0x85: + bl->DataBuf[0] = 'B'; + bl->DataReplyLeft = 1; + break; + + case 0x86: + if (bl->chip == CHIP_BUSLOGIC_PCI) + { + ReplyPI = (BuslogicPCIInformation_t *) bl->DataBuf; + memset(ReplyPI, 0, sizeof(BuslogicPCIInformation_t)); + ReplyPI->InformationIsValid = 0; + switch(bl->Base) + { + case 0x330: + ReplyPI->IsaIOPort = 0; + break; + case 0x334: + ReplyPI->IsaIOPort = 1; + break; + case 0x230: + ReplyPI->IsaIOPort = 2; + break; + case 0x234: + ReplyPI->IsaIOPort = 3; + break; + case 0x130: + ReplyPI->IsaIOPort = 4; + break; + case 0x134: + ReplyPI->IsaIOPort = 5; + break; + default: + ReplyPI->IsaIOPort = 0xFF; + break; + } + ReplyPI->IRQ = bl->Irq; + bl->DataReplyLeft = sizeof(BuslogicPCIInformation_t); + } else { + bl->DataReplyLeft = 0; + bl->Status |= STAT_INVCMD; + } + break; + + case 0x8B: + { + /* The reply length is set by the guest and is found in the first byte of the command buffer. */ + bl->DataReplyLeft = bl->CmdBuf[0]; + memset(bl->DataBuf, 0, bl->DataReplyLeft); + if (bl->chip == CHIP_BUSLOGIC_PCI) { + aModelName[0] = '9'; + aModelName[1] = '5'; + aModelName[2] = '8'; + aModelName[3] = 'D'; + } + cCharsToTransfer = bl->DataReplyLeft <= sizeof(aModelName) + ? bl->DataReplyLeft + : sizeof(aModelName); + + for (i = 0; i < cCharsToTransfer; i++) + bl->DataBuf[i] = aModelName[i]; + } + break; + + case 0x8C: + bl->DataReplyLeft = bl->CmdBuf[0]; + memset(bl->DataBuf, 0, bl->DataReplyLeft); + break; + + case 0x8D: + bl->DataReplyLeft = bl->CmdBuf[0]; + ReplyIESI = (ReplyInquireExtendedSetupInformation *)bl->DataBuf; + memset(ReplyIESI, 0, sizeof(ReplyInquireExtendedSetupInformation)); + + ReplyIESI->uBusType = (bl->chip == CHIP_BUSLOGIC_PCI) ? 'E' : 'A'; /* ISA style */ + ReplyIESI->uBiosAddress = 0; + ReplyIESI->u16ScatterGatherLimit = 8192; + ReplyIESI->cMailbox = bl->MailboxCount; + ReplyIESI->uMailboxAddressBase = bl->MailboxOutAddr; + if (bl->chip == CHIP_BUSLOGIC_PCI) { + ReplyIESI->fLevelSensitiveInterrupt = 1; + ReplyIESI->fHostWideSCSI = 1; + ReplyIESI->fHostUltraSCSI = 1; + } + memcpy(ReplyIESI->aFirmwareRevision, "07B", sizeof(ReplyIESI->aFirmwareRevision)); + pclog("Return Extended Setup Information: %d\n", bl->CmdBuf[0]); + break; + + /* VirtualBox has these two modes implemented in reverse. + According to the BusLogic datasheet: + 0 is the strict round robin mode, which is also the one used by the AHA-154x according to the + Adaptec specification; + 1 is the aggressive round robin mode, which "hunts" for an active outgoing mailbox and then + processes it. */ + case 0x8F: + if (bl->CmdBuf[0] == 0) + bl->StrictRoundRobinMode = 1; + else if (bl->CmdBuf[0] == 1) + bl->StrictRoundRobinMode = 0; + + bl->DataReplyLeft = 0; + break; + + case 0x91: + Offset = bl->CmdBuf[0]; + bl->DataReplyLeft = bl->CmdBuf[1]; + + bl->UseLocalRAM = 1; + bl->DataReply = Offset; + break; + + case 0x95: + if (bl->chip == CHIP_BUSLOGIC_PCI) { + if (bl->Base != 0) { + io_removehandler(bl->Base, 4, + BuslogicRead, + BuslogicReadW, + BuslogicReadL, + BuslogicWrite, + BuslogicWriteW, + BuslogicWriteL, + bl); + } + switch(bl->CmdBuf[0]) { + case 0: + bl->Base = 0x330; + break; + case 1: + bl->Base = 0x334; + break; + case 2: + bl->Base = 0x230; + break; + case 3: + bl->Base = 0x234; + break; + case 4: + bl->Base = 0x130; + break; + case 5: + bl->Base = 0x134; + break; + default: + bl->Base = 0; + break; + } + if (bl->Base != 0) { + io_sethandler(bl->Base, 4, + BuslogicRead, + BuslogicReadW, + BuslogicReadL, + BuslogicWrite, + BuslogicWriteW, + BuslogicWriteL, + bl); + } + bl->DataReplyLeft = 0; + } else { + bl->DataReplyLeft = 0; + bl->Status |= STAT_INVCMD; + } + break; + + case 0x96: + if (bl->CmdBuf[0] == 0) + bl->ExtendedLUNCCBFormat = 0; + else if (bl->CmdBuf[0] == 1) + bl->ExtendedLUNCCBFormat = 1; + + bl->DataReplyLeft = 0; + break; + + default: + bl->DataReplyLeft = 0; + bl->Status |= STAT_INVCMD; + break; + } + } + + if (bl->DataReplyLeft) + bl->Status |= STAT_DFULL; + else if (!bl->CmdParamLeft) + BuslogicCommandComplete(bl); + break; + + case 2: + bl->Interrupt = Val; + break; + + case 3: + bl->Geometry = Val; + break; + } +} + + +static void +BuslogicWriteW(uint16_t Port, uint16_t Val, void *p) +{ + BuslogicWrite(Port, Val & 0xFF, p); +} + + +static void +BuslogicWriteL(uint16_t Port, uint32_t Val, void *p) +{ + BuslogicWrite(Port, Val & 0xFF, p); +} + + +static uint8_t +BuslogicConvertSenseLength(uint8_t RequestSenseLength) +{ + pclog("Unconverted Request Sense length %i\n", RequestSenseLength); + + if (RequestSenseLength == 0) + RequestSenseLength = 14; + else if (RequestSenseLength == 1) + RequestSenseLength = 0; + + pclog("Request Sense length %i\n", RequestSenseLength); + + return(RequestSenseLength); +} + + +static void +BuslogicSenseBufferFree(Req_t *req, int Copy, int is_hd) +{ + uint8_t SenseLength = BuslogicConvertSenseLength(req->CmdBlock.common.RequestSenseLength); + uint8_t cdrom_id = scsi_cdrom_drives[req->TargetID][req->LUN]; + uint8_t hdc_id = scsi_hard_disks[req->TargetID][req->LUN]; + uint32_t SenseBufferAddress; + uint8_t temp_sense[256]; + + if (SenseLength && Copy) { + if (is_hd) + { + scsi_hd_request_sense_for_scsi(hdc_id, temp_sense, SenseLength); + } + else + { + cdrom_request_sense_for_scsi(cdrom_id, temp_sense, SenseLength); + } + + /* + * The sense address, in 32-bit mode, is located in the + * Sense Pointer of the CCB, but in 24-bit mode, it is + * located at the end of the Command Descriptor Block. + */ + if (req->Is24bit) { + SenseBufferAddress = req->CCBPointer; + SenseBufferAddress += req->CmdBlock.common.CdbLength + offsetof(CCB, Cdb); + } else { + SenseBufferAddress = req->CmdBlock.new.SensePointer; + } + + pclog("Request Sense address: %02X\n", SenseBufferAddress); + + pclog("BuslogicSenseBufferFree(): Writing %i bytes at %08X\n", + SenseLength, SenseBufferAddress); + DMAPageWrite(SenseBufferAddress, (char *)temp_sense, SenseLength); + pclog("Sense data written to buffer: %02X %02X %02X\n", + temp_sense[2], temp_sense[12], temp_sense[13]); + } +} + + +static void +BuslogicHDCommand(Buslogic_t *bl) +{ + Req_t *req = &bl->Req; + uint8_t Id, Lun; + uint8_t hdc_id; + uint8_t hd_phase; + uint8_t temp_cdb[12]; + uint32_t i; + + Id = req->TargetID; + Lun = req->LUN; + hdc_id = scsi_hard_disks[Id][Lun]; + + if (hdc_id == 0xff) fatal("SCSI hard disk on %02i:%02i has disappeared\n", Id, Lun); + + pclog("SCSI HD command being executed on: SCSI ID %i, SCSI LUN %i, HD %i\n", + Id, Lun, hdc_id); + + pclog("SCSI Cdb[0]=0x%02X\n", req->CmdBlock.common.Cdb[0]); + for (i = 1; i < req->CmdBlock.common.CdbLength; i++) { + pclog("SCSI Cdb[%i]=%i\n", i, req->CmdBlock.common.Cdb[i]); + } + + memset(temp_cdb, 0, 12); + if (req->CmdBlock.common.CdbLength <= 12) { + memcpy(temp_cdb, req->CmdBlock.common.Cdb, + req->CmdBlock.common.CdbLength); + } else { + memcpy(temp_cdb, req->CmdBlock.common.Cdb, 12); + } + + /* + * Since that field in the HDC struct is never used when + * the bus type is SCSI, let's use it for this scope. + */ + shdc[hdc_id].request_length = temp_cdb[1]; + + if (req->CmdBlock.common.CdbLength != 12) { + /* + * Make sure the LUN field of the temporary CDB is always 0, + * otherwise Daemon Tools drives will misbehave when a command + * is passed through to them. + */ + temp_cdb[1] &= 0x1f; + } + + /* Finally, execute the SCSI command immediately and get the transfer length. */ + SCSIPhase = SCSI_PHASE_COMMAND; + scsi_hd_command(hdc_id, temp_cdb); + SCSIStatus = scsi_hd_err_stat_to_scsi(hdc_id); + if (SCSIStatus == SCSI_STATUS_OK) { + hd_phase = scsi_hd_phase_to_scsi(hdc_id); + if (hd_phase == 2) { + /* Command completed - call the phase callback to complete the command. */ + scsi_hd_callback(hdc_id); + } else { + /* Command first phase complete - call the callback to execute the second phase. */ + scsi_hd_callback(hdc_id); + SCSIStatus = scsi_hd_err_stat_to_scsi(hdc_id); + /* Command second phase complete - call the callback to complete the command. */ + scsi_hd_callback(hdc_id); + } + } else { + /* Error (Check Condition) - call the phase callback to complete the command. */ + scsi_hd_callback(hdc_id); + } + + pclog("SCSI Status: %s, Sense: %02X, ASC: %02X, ASCQ: %02X\n", (SCSIStatus == SCSI_STATUS_OK) ? "OK" : "CHECK CONDITION", shdc[hdc_id].sense[2], shdc[hdc_id].sense[12], shdc[hdc_id].sense[13]); + + BuslogicDataBufferFree(req); + + BuslogicSenseBufferFree(req, (SCSIStatus != SCSI_STATUS_OK), 1); + + pclog("Request complete\n"); + + if (SCSIStatus == SCSI_STATUS_OK) { + BuslogicMailboxInSetup(bl, req->CCBPointer, &req->CmdBlock, + CCB_COMPLETE, SCSI_STATUS_OK, MBI_SUCCESS); + } else if (SCSIStatus == SCSI_STATUS_CHECK_CONDITION) { + BuslogicMailboxInSetup(bl, req->CCBPointer, &req->CmdBlock, + CCB_COMPLETE, SCSI_STATUS_CHECK_CONDITION, MBI_ERROR); + } +} + + +static void +BuslogicCDROMCommand(Buslogic_t *bl) +{ + Req_t *req = &bl->Req; + uint8_t Id, Lun; + uint8_t cdrom_id; + uint8_t cdrom_phase; + uint8_t temp_cdb[12]; + uint32_t i; + + Id = req->TargetID; + Lun = req->LUN; + cdrom_id = scsi_cdrom_drives[Id][Lun]; + + if (cdrom_id == 0xff) fatal("SCSI CD-ROM on %02i:%02i has disappeared\n", Id, Lun); + + pclog("CD-ROM command being executed on: SCSI ID %i, SCSI LUN %i, CD-ROM %i\n", + Id, Lun, cdrom_id); + + pclog("SCSI Cdb[0]=0x%02X\n", req->CmdBlock.common.Cdb[0]); + for (i = 1; i < req->CmdBlock.common.CdbLength; i++) { + pclog("SCSI Cdb[%i]=%i\n", i, req->CmdBlock.common.Cdb[i]); + } + + memset(temp_cdb, 0, cdrom[cdrom_id].cdb_len); + if (req->CmdBlock.common.CdbLength <= cdrom[cdrom_id].cdb_len) { + memcpy(temp_cdb, req->CmdBlock.common.Cdb, + req->CmdBlock.common.CdbLength); + } else { + memcpy(temp_cdb, req->CmdBlock.common.Cdb, cdrom[cdrom_id].cdb_len); + } + + /* + * Since that field in the CDROM struct is never used when + * the bus type is SCSI, let's use it for this scope. + */ + cdrom[cdrom_id].request_length = temp_cdb[1]; + + if (req->CmdBlock.common.CdbLength != 12) { + /* + * Make sure the LUN field of the temporary CDB is always 0, + * otherwise Daemon Tools drives will misbehave when a command + * is passed through to them. + */ + temp_cdb[1] &= 0x1f; + } + + /* Finally, execute the SCSI command immediately and get the transfer length. */ + SCSIPhase = SCSI_PHASE_COMMAND; + cdrom_command(cdrom_id, temp_cdb); + SCSIStatus = cdrom_CDROM_PHASE_to_scsi(cdrom_id); + if (SCSIStatus == SCSI_STATUS_OK) { + cdrom_phase = cdrom_atapi_phase_to_scsi(cdrom_id); + if (cdrom_phase == 2) { + /* Command completed - call the phase callback to complete the command. */ + cdrom_phase_callback(cdrom_id); + } else { + /* Command first phase complete - call the callback to execute the second phase. */ + cdrom_phase_callback(cdrom_id); + SCSIStatus = cdrom_CDROM_PHASE_to_scsi(cdrom_id); + /* Command second phase complete - call the callback to complete the command. */ + cdrom_phase_callback(cdrom_id); + } + } else { + /* Error (Check Condition) - call the phase callback to complete the command. */ + cdrom_phase_callback(cdrom_id); + } + + pclog("SCSI Status: %s, Sense: %02X, ASC: %02X, ASCQ: %02X\n", (SCSIStatus == SCSI_STATUS_OK) ? "OK" : "CHECK CONDITION", cdrom[cdrom_id].sense[2], cdrom[cdrom_id].sense[12], cdrom[cdrom_id].sense[13]); + + BuslogicDataBufferFree(req); + + BuslogicSenseBufferFree(req, (SCSIStatus != SCSI_STATUS_OK), 0); + + pclog("Request complete\n"); + + if (SCSIStatus == SCSI_STATUS_OK) { + BuslogicMailboxInSetup(bl, req->CCBPointer, &req->CmdBlock, + CCB_COMPLETE, SCSI_STATUS_OK, MBI_SUCCESS); + } else if (SCSIStatus == SCSI_STATUS_CHECK_CONDITION) { + BuslogicMailboxInSetup(bl, req->CCBPointer, &req->CmdBlock, + CCB_COMPLETE, SCSI_STATUS_CHECK_CONDITION, MBI_ERROR); + } +} + + +static void +BuslogicSCSIRequestSetup(Buslogic_t *bl, uint32_t CCBPointer, Mailbox32_t *Mailbox32) +{ + Req_t *req = &bl->Req; + uint8_t Id, Lun; + uint8_t last_id = (bl->chip >= CHIP_BUSLOGIC_ISA) ? 15 : 7; + + /* Fetch data from the Command Control Block. */ + DMAPageRead(CCBPointer, (char *)&req->CmdBlock, sizeof(CCB32)); + + req->Is24bit = bl->Mbx24bit; + req->CCBPointer = CCBPointer; + req->TargetID = bl->Mbx24bit ? req->CmdBlock.old.Id : req->CmdBlock.new.Id; + req->LUN = bl->Mbx24bit ? req->CmdBlock.old.Lun : req->CmdBlock.new.Lun; + + Id = req->TargetID; + Lun = req->LUN; + if ((Id > last_id) || (Lun > 7)) { + BuslogicMailboxInSetup(bl, CCBPointer, &req->CmdBlock, + CCB_INVALID_CCB, SCSI_STATUS_OK, MBI_ERROR); + return; + } + + pclog("Scanning SCSI Target ID %i\n", Id); + + SCSIStatus = SCSI_STATUS_OK; + SCSIDevices[Id][Lun].InitLength = 0; + + BuslogicDataBufferAllocate(req, req->Is24bit); + + if (SCSIDevices[Id][Lun].LunType == SCSI_NONE) { + pclog("SCSI Target ID %i and LUN %i have no device attached\n",Id,Lun); + BuslogicDataBufferFree(req); + BuslogicSenseBufferFree(req, 0, 0); + BuslogicMailboxInSetup(bl, CCBPointer, &req->CmdBlock, + CCB_SELECTION_TIMEOUT,SCSI_STATUS_OK,MBI_ERROR); + } else { + pclog("SCSI Target ID %i and LUN %i detected and working\n", Id, Lun); + + pclog("Transfer Control %02X\n", req->CmdBlock.common.ControlByte); + pclog("CDB Length %i\n", req->CmdBlock.common.CdbLength); + pclog("CCB Opcode %x\n", req->CmdBlock.common.Opcode); + if (req->CmdBlock.common.ControlByte > 0x03) { + pclog("Invalid control byte: %02X\n", + req->CmdBlock.common.ControlByte); + } + + BuslogicInOperation = (SCSIDevices[Id][Lun].LunType == SCSI_DISK) ? 0x11 : 1; + pclog("SCSI (%i:%i) -> %i\n", Id, Lun, SCSIDevices[Id][Lun].LunType); + } +} + + +static void +BuslogicSCSIRequestAbort(Buslogic_t *bl, uint32_t CCBPointer) +{ + CCBU CmdBlock; + + /* Fetch data from the Command Control Block. */ + DMAPageRead(CCBPointer, (char *)&CmdBlock, sizeof(CCB32)); + + /* Only SCSI CD-ROMs are supported at the moment, SCSI hard disk support will come soon. */ + BuslogicMailboxInSetup(bl, CCBPointer, &CmdBlock, + 0x26, SCSI_STATUS_OK, MBI_NOT_FOUND); +} + + +static uint32_t +BuslogicMailboxOut(Buslogic_t *bl, Mailbox32_t *Mailbox32) +{ + Mailbox_t MailboxOut; + uint32_t Outgoing; + + if (bl->Mbx24bit) { + Outgoing = bl->MailboxOutAddr + (bl->MailboxOutPosCur * sizeof(Mailbox_t)); + DMAPageRead(Outgoing, (char *)&MailboxOut, sizeof(Mailbox_t)); + + Mailbox32->CCBPointer = ADDR_TO_U32(MailboxOut.CCBPointer); + Mailbox32->u.out.ActionCode = MailboxOut.CmdStatus; + } else { + Outgoing = bl->MailboxOutAddr + (bl->MailboxOutPosCur * sizeof(Mailbox32_t)); + + DMAPageRead(Outgoing, (char *)Mailbox32, sizeof(Mailbox32_t)); + } + + return Outgoing; +} + + +static void +BuslogicMailboxOutAdvance(Buslogic_t *bl) +{ + bl->MailboxOutPosCur = (bl->MailboxOutPosCur + 1) % bl->MailboxCount; +} + + +static void +BuslogicProcessMailbox(Buslogic_t *bl) +{ + Mailbox32_t mb32; + uint32_t Outgoing; + uint8_t CmdStatus = MBO_FREE; + uint32_t CodeOffset = 0; + + CodeOffset = bl->Mbx24bit ? offsetof(Mailbox_t, CmdStatus) : offsetof(Mailbox32_t, u.out.ActionCode); + + if (! bl->StrictRoundRobinMode) { + uint8_t MailboxCur = bl->MailboxOutPosCur; + + /* Search for a filled mailbox - stop if we have scanned all mailboxes. */ + do { + /* Fetch mailbox from guest memory. */ + Outgoing = BuslogicMailboxOut(bl, &mb32); + + /* Check the next mailbox. */ + BuslogicMailboxOutAdvance(bl); + } while ((mb32.u.out.ActionCode == MBO_FREE) && (MailboxCur != bl->MailboxOutPosCur)); + } else { + Outgoing = BuslogicMailboxOut(bl, &mb32); + } + + if (mb32.u.out.ActionCode != MBO_FREE) { + /* We got the mailbox, mark it as free in the guest. */ + pclog("BuslogicProcessMailbox(): Writing %i bytes at %08X\n", sizeof(CmdStatus), Outgoing + CodeOffset); + DMAPageWrite(Outgoing + CodeOffset, (char *)&CmdStatus, sizeof(CmdStatus)); + } + + if (bl->MailboxOutInterrupts) + BuslogicRaiseInterrupt(bl, INTR_MBOA | INTR_ANY); + + /* Check if the mailbox is actually loaded. */ + if (mb32.u.out.ActionCode == MBO_FREE) { + return; + } + + if (mb32.u.out.ActionCode == MBO_START) { + pclog("Start Mailbox Command\n"); + BuslogicSCSIRequestSetup(bl, mb32.CCBPointer, &mb32); + } else if (mb32.u.out.ActionCode == MBO_ABORT) { + pclog("Abort Mailbox Command\n"); + BuslogicSCSIRequestAbort(bl, mb32.CCBPointer); + } else { + pclog("Invalid action code: %02X\n", mb32.u.out.ActionCode); + } + + /* Advance to the next mailbox. */ + if (bl->StrictRoundRobinMode) + BuslogicMailboxOutAdvance(bl); +} + + +static void +BuslogicResetPoll(void *p) +{ + Buslogic_t *bl = (Buslogic_t *)p; + + bl->Status &= ~STAT_STST; + bl->Status |= STAT_IDLE; + + BuslogicResetCallback = 0; +} + + +static void +BuslogicCommandCallback(void *p) +{ + Buslogic_t *bl = (Buslogic_t *)p; + + if (BuslogicInOperation == 0) { + if (bl->MailboxCount) { + BuslogicProcessMailbox(bl); + } else { + BuslogicCallback += 50 * SCSI_TIME; + return; + } + } else if (BuslogicInOperation == 1) { + pclog("BusLogic Callback: Process CD-ROM request\n"); + BuslogicCDROMCommand(bl); + if (bl->Req.CmdBlock.common.Cdb[0] == 0x42) + { + /* This is needed since CD Audio inevitably means READ SUBCHANNEL spam. */ + BuslogicCallback += 1000 * SCSI_TIME; + return; + } + } else if (BuslogicInOperation == 2) { + pclog("BusLogic Callback: Send incoming mailbox\n"); + BuslogicMailboxIn(bl); + } else if (BuslogicInOperation == 0x11) { + pclog("BusLogic Callback: Process hard disk request\n"); + BuslogicHDCommand(bl); + } else { + fatal("Invalid BusLogic callback phase: %i\n", BuslogicInOperation); + } + + BuslogicCallback += 50 * SCSI_TIME; +} + + +static uint8_t +mem_read_null(uint32_t addr, void *priv) +{ + return(0); +} + + +static uint16_t +mem_read_nullw(uint32_t addr, void *priv) +{ + return(0); +} + + +static uint32_t +mem_read_nulll(uint32_t addr, void *priv) +{ + return(0); +} + + +typedef union { + uint32_t addr; + uint8_t addr_regs[4]; +} bar_t; + + +uint8_t buslogic_pci_regs[256]; +bar_t buslogic_pci_bar[3]; + + +static uint8_t +BuslogicPCIRead(int func, int addr, void *p) +{ + Buslogic_t *bl = (Buslogic_t *)p; + + switch (addr) { + case 0x00: + return 0x4b; + case 0x01: + return 0x10; + case 0x02: + return 0x40; + case 0x03: + return 0x10; + case 0x04: + return buslogic_pci_regs[0x04]; /*Respond to IO and memory accesses*/ + case 0x05: + return buslogic_pci_regs[0x05]; + case 0x07: + return 2; + case 0x08: + return 1; /*Revision ID*/ + case 0x09: + return 0; /*Programming interface*/ + case 0x0A: + return 0; /*Subclass*/ + case 0x0B: + return 1; /* Class code*/ + case 0x10: + return (buslogic_pci_bar[0].addr_regs[0] & 0xe0) | 1; /*I/O space*/ + case 0x11: + return buslogic_pci_bar[0].addr_regs[1]; + case 0x12: + return buslogic_pci_bar[0].addr_regs[2]; + case 0x13: + return buslogic_pci_bar[0].addr_regs[3]; + case 0x14: + return (buslogic_pci_bar[1].addr_regs[0] & 0xe0); /*Memory space*/ + case 0x15: + return buslogic_pci_bar[1].addr_regs[1]; + case 0x16: + return buslogic_pci_bar[1].addr_regs[2]; + case 0x17: + return buslogic_pci_bar[1].addr_regs[3]; + case 0x2C: + return 0x4b; + case 0x2D: + return 0x10; + case 0x2E: + return 0x40; + case 0x2F: + return 0x10; + case 0x30: + return buslogic_pci_bar[2].addr_regs[0] & 0x01; /*BIOS ROM address*/ + case 0x31: + return buslogic_pci_bar[2].addr_regs[1] | 0x18; + case 0x32: + return buslogic_pci_bar[2].addr_regs[2]; + case 0x33: + return buslogic_pci_bar[2].addr_regs[3]; + case 0x3C: + return bl->Irq; + case 0x3D: + return PCI_INTB; + } + + return(0); +} + + +static void +BuslogicPCIWrite(int func, int addr, uint8_t val, void *p) +{ + Buslogic_t *bl = (Buslogic_t *)p; + uint8_t valxor; + + switch (addr) { + case 0x04: + valxor = (val & 0x27) ^ buslogic_pci_regs[addr]; + if (valxor & PCI_COMMAND_IO) { + io_removehandler(bl->PCIBase, 4, + BuslogicRead, BuslogicReadW, BuslogicReadL, + BuslogicWrite, BuslogicWriteW, BuslogicWriteL, + bl); + if ((bl->PCIBase != 0) && (val & PCI_COMMAND_IO)) { + io_sethandler(bl->PCIBase, 0x0020, + BuslogicRead, BuslogicReadW, + BuslogicReadL, BuslogicWrite, + BuslogicWriteW, BuslogicWriteL, + bl); + } + } + if (valxor & PCI_COMMAND_MEM) { + mem_mapping_disable(&bl->mmio_mapping); + if ((bl->MMIOBase != 0) & (val & PCI_COMMAND_MEM)) { + mem_mapping_set_addr(&bl->mmio_mapping, + bl->MMIOBase, 0x20); + } + } + buslogic_pci_regs[addr] = val & 0x27; + break; + + case 0x10: + val &= 0xe0; + val |= 1; + + case 0x11: case 0x12: case 0x13: + /* I/O Base set. */ + /* First, remove the old I/O. */ + io_removehandler(bl->PCIBase, 0x0020, + BuslogicRead, BuslogicReadW, BuslogicReadL, + BuslogicWrite, BuslogicWriteW, BuslogicWriteL, + bl); + /* Then let's set the PCI regs. */ + buslogic_pci_bar[0].addr_regs[addr & 3] = val; + /* Then let's calculate the new I/O base. */ + bl->PCIBase = buslogic_pci_bar[0].addr & 0xffe0; + /* Log the new base. */ + pclog("BusLogic PCI: New I/O base is %04X\n" , bl->PCIBase); + /* We're done, so get out of the here. */ + if (buslogic_pci_regs[4] & PCI_COMMAND_IO) { + if (bl->PCIBase != 0) { + io_sethandler(bl->PCIBase, 0x0020, + BuslogicRead, BuslogicReadW, + BuslogicReadL, BuslogicWrite, + BuslogicWriteW, BuslogicWriteL, + bl); + } + } + return; + + case 0x14: + val &= 0xe0; + + case 0x15: case 0x16: case 0x17: + /* I/O Base set. */ + /* First, remove the old I/O. */ + mem_mapping_disable(&bl->mmio_mapping); + /* Then let's set the PCI regs. */ + buslogic_pci_bar[1].addr_regs[addr & 3] = val; + /* Then let's calculate the new I/O base. */ + bl->MMIOBase = buslogic_pci_bar[1].addr & 0xffffffe0; + /* Log the new base. */ + pclog("BusLogic PCI: New MMIO base is %04X\n" , bl->MMIOBase); + /* We're done, so get out of the here. */ + if (buslogic_pci_regs[4] & PCI_COMMAND_MEM) { + if (bl->PCIBase != 0) { + mem_mapping_set_addr(&bl->mmio_mapping, + bl->MMIOBase, 0x20); + } + } + return; + + case 0x3C: + buslogic_pci_regs[addr] = val; + if (val != 0xFF) { + BuslogicLog("BusLogic IRQ now: %i\n", val); + bl->Irq = val; + } + return; + } +} + + +void +BuslogicDeviceReset(void *p) +{ + Buslogic_t *dev = (Buslogic_t *) p; + BuslogicResetControl(dev, 1); +} + + +static void * +BuslogicInit(int chip) +{ + Buslogic_t *bl; + + int i = 0; + int j = 0; + + bl = malloc(sizeof(Buslogic_t)); + memset(bl, 0x00, sizeof(Buslogic_t)); + + BuslogicResetDevice = bl; + if (!PCI && (chip == CHIP_BUSLOGIC_PCI)) + { + chip = CHIP_BUSLOGIC_ISA; + } + bl->chip = chip; + bl->Base = device_get_config_hex16("base"); + bl->PCIBase = 0; + bl->MMIOBase = 0; + bl->Irq = device_get_config_int("irq"); + bl->DmaChannel = device_get_config_int("dma"); + + if (bl->Base != 0) { + if (bl->chip == CHIP_BUSLOGIC_PCI) { + io_sethandler(bl->Base, 4, + BuslogicRead, BuslogicReadW, BuslogicReadL, + BuslogicWrite, BuslogicWriteW, BuslogicWriteL, + bl); + } else { + io_sethandler(bl->Base, 4, + BuslogicRead, BuslogicReadW, NULL, + BuslogicWrite, BuslogicWriteW, NULL, bl); + } + } + + pclog("Building SCSI hard disk map...\n"); + build_scsi_hd_map(); + pclog("Building SCSI CD-ROM map...\n"); + build_scsi_cdrom_map(); + + for (i=0; i<16; i++) { + for (j=0; j<8; j++) { + if (scsi_hard_disks[i][j] != 0xff) { + SCSIDevices[i][j].LunType = SCSI_DISK; + } + else if (find_cdrom_for_scsi_id(i, j) != 0xff) { + SCSIDevices[i][j].LunType = SCSI_CDROM; + } + else { + SCSIDevices[i][j].LunType = SCSI_NONE; + } + } + } + + timer_add(BuslogicResetPoll, + &BuslogicResetCallback, &BuslogicResetCallback, bl); + timer_add(BuslogicCommandCallback, + &BuslogicCallback, &BuslogicCallback, bl); + + if (bl->chip == CHIP_BUSLOGIC_PCI) { + bl->Card = pci_add(BuslogicPCIRead, BuslogicPCIWrite, bl); + + buslogic_pci_bar[0].addr_regs[0] = 1; + buslogic_pci_bar[1].addr_regs[0] = 0; + buslogic_pci_regs[0x04] = 3; +#if 0 + buslogic_pci_regs[0x05] = 0; + buslogic_pci_regs[0x07] = 2; +#endif + buslogic_pci_bar[2].addr = 0; + + mem_mapping_add(&bl->mmio_mapping, 0xfffd0000, 0x20, + mem_read_null, mem_read_nullw, mem_read_nulll, + mem_write_null, mem_write_nullw, mem_write_nulll, + NULL, MEM_MAPPING_EXTERNAL, bl); + mem_mapping_disable(&bl->mmio_mapping); + } + + pclog("Buslogic on port 0x%04X\n", bl->Base); + + BuslogicResetControl(bl, CTRL_HRST); + + return(bl); +} + + +static void * +Buslogic_542B_Init(void) +{ + return BuslogicInit(CHIP_BUSLOGIC_ISA); +} + + +static void * +Buslogic_958D_Init(void) +{ + return BuslogicInit(CHIP_BUSLOGIC_PCI); +} + + +static void +BuslogicClose(void *p) +{ + Buslogic_t *bl = (Buslogic_t *)p; + free(bl); + BuslogicResetDevice = NULL; +} + + +static device_config_t BuslogicConfig[] = { + { + "base", "Address", CONFIG_HEX16, "", 0x334, + { + { + "None", 0 + }, + { + "0x330", 0x330 + }, + { + "0x334", 0x334 + }, + { + "0x230", 0x230 + }, + { + "0x234", 0x234 + }, + { + "0x130", 0x130 + }, + { + "0x134", 0x134 + }, + { + "" + } + }, + }, + { + "irq", "IRQ", CONFIG_SELECTION, "", 9, + { + { + "IRQ 9", 9 + }, + { + "IRQ 10", 10 + }, + { + "IRQ 11", 11 + }, + { + "IRQ 12", 12 + }, + { + "IRQ 14", 14 + }, + { + "IRQ 15", 15 + }, + { + "" + } + }, + }, + { + "dma", "DMA channel", CONFIG_SELECTION, "", 6, + { + { + "DMA 5", 5 + }, + { + "DMA 6", 6 + }, + { + "DMA 7", 7 + }, + { + "" + } + }, + }, + { + "", "", -1 + } +}; + + +device_t buslogic_device = { + "Buslogic BT-542B ISA", + 0, + Buslogic_542B_Init, + BuslogicClose, + NULL, + NULL, + NULL, + NULL, + BuslogicConfig +}; + +device_t buslogic_pci_device = { + "Buslogic BT-958D PCI", + 0, + Buslogic_958D_Init, + BuslogicClose, + NULL, + NULL, + NULL, + NULL, + BuslogicConfig +}; diff --git a/src/scsi_buslogic.h b/src/scsi_buslogic.h new file mode 100644 index 000000000..e835ea989 --- /dev/null +++ b/src/scsi_buslogic.h @@ -0,0 +1,30 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * Emulation of BusLogic BT-542B ISA and BT-958D PCI SCSI + * controllers. + * + * Version: @(#)scsi_buslogic.h 1.0.0 2017/05/30 + * + * Author: TheCollector1995, + * Miran Grca, + * Fred N. van Kempen, + * Copyright 2008-2017 Sarah Walker. + * Copyright 2016-2017 Miran Grca. + * Copyright 2017-2017 Fred N. van Kempen. + */ + +#ifndef SCSI_BUSLOGIC_H +# define SCSI_BUSLOGIC_H + + +extern device_t buslogic_device; +extern device_t buslogic_pci_device; + +extern void BuslogicDeviceReset(void *p); + + +#endif /*SCSI_BUSLOGIC_H*/ diff --git a/src/scsi_cdrom.c b/src/scsi_cdrom.c deleted file mode 100644 index 1528fea91..000000000 --- a/src/scsi_cdrom.c +++ /dev/null @@ -1,1677 +0,0 @@ -/* Copyright holders: SA1988, Tenshi - see COPYING for more details -*/ -/*SCSI CD-ROM emulation*/ -#include -#include -#include "86box.h" -#include "ibm.h" - -#include "cdrom.h" -#include "scsi.h" - -sector_buffer_t cdrom_sector_buffer; - -int cdrom_sector_type, cdrom_sector_flags; -int cdrom_sector_size, cdrom_sector_ismsf; - -uint8_t SCSIPhase = SCSI_PHASE_BUS_FREE; -uint8_t SCSIStatus = SCSI_STATUS_OK; - -/* Table of all SCSI commands and their flags, needed for the new disc change / not ready handler. */ -uint8_t SCSICommandTable[0x100] = -{ - [GPCMD_TEST_UNIT_READY] = CHECK_READY | NONDATA, - [GPCMD_REQUEST_SENSE] = ALLOW_UA, - [GPCMD_READ_6] = CHECK_READY, - [GPCMD_SEEK_6] = CHECK_READY | NONDATA, - [GPCMD_INQUIRY] = ALLOW_UA, - [GPCMD_MODE_SELECT_6] = 0, - [GPCMD_MODE_SENSE_6] = 0, - [GPCMD_START_STOP_UNIT] = CHECK_READY, - [GPCMD_PREVENT_REMOVAL] = CHECK_READY, - [GPCMD_READ_CDROM_CAPACITY] = CHECK_READY, - [GPCMD_READ_10] = CHECK_READY, - [GPCMD_SEEK_10] = CHECK_READY | NONDATA, - [GPCMD_READ_SUBCHANNEL] = CHECK_READY, - [GPCMD_READ_TOC_PMA_ATIP] = CHECK_READY, /* Read TOC - can get through UNIT_ATTENTION, per VIDE-CDD.SYS - NOTE: The ATAPI reference says otherwise, but I think this is a question of - interpreting things right - the UNIT ATTENTION condition we have here - is a tradition from not ready to ready, by definition the drive - eventually becomes ready, make the condition go away. */ - [GPCMD_READ_HEADER] = CHECK_READY, - [GPCMD_PLAY_AUDIO_10] = CHECK_READY, - [GPCMD_GET_CONFIGURATION] = ALLOW_UA, - [GPCMD_PLAY_AUDIO_MSF] = CHECK_READY, - [GPCMD_GET_EVENT_STATUS_NOTIFICATION] = ALLOW_UA, - [GPCMD_PAUSE_RESUME] = CHECK_READY, - [GPCMD_STOP_PLAY_SCAN] = CHECK_READY, - [GPCMD_READ_DISC_INFORMATION] = CHECK_READY, - [GPCMD_READ_TRACK_INFORMATION] = CHECK_READY, - [GPCMD_MODE_SELECT_10] = 0, - [GPCMD_MODE_SENSE_10] = 0, - [GPCMD_PLAY_AUDIO_12] = CHECK_READY, - [GPCMD_READ_12] = CHECK_READY, - [GPCMD_READ_DVD_STRUCTURE] = CHECK_READY, - [GPCMD_READ_CD_MSF] = CHECK_READY, - [GPCMD_SET_SPEED] = 0, - [GPCMD_PLAY_CD] = CHECK_READY, - [GPCMD_MECHANISM_STATUS] = 0, - [GPCMD_READ_CD] = CHECK_READY, - [GPCMD_SEND_DVD_STRUCTURE] = CHECK_READY -}; - -uint8_t mode_sense_pages[0x40] = -{ - [GPMODE_R_W_ERROR_PAGE] = IMPLEMENTED, - [GPMODE_CDROM_PAGE] = IMPLEMENTED, - [GPMODE_CDROM_AUDIO_PAGE] = IMPLEMENTED, - [GPMODE_CAPABILITIES_PAGE] = IMPLEMENTED, - [GPMODE_ALL_PAGES] = IMPLEMENTED -}; - -uint8_t page_flags[256] = -{ - [GPMODE_R_W_ERROR_PAGE] = 0, - [GPMODE_CDROM_PAGE] = 0, - [GPMODE_CDROM_AUDIO_PAGE] = PAGE_CHANGEABLE, - [GPMODE_CAPABILITIES_PAGE] = 0, -}; - -CDROM *cdrom; - -int readcdmode = 0; - -uint8_t mode_pages_in[256][256]; -uint8_t prefix_len; -uint8_t page_current; - -/*SCSI Sense Initialization*/ -void SCSISenseCodeOk(void) -{ - SCSISense.SenseKey=SENSE_NONE; - SCSISense.Asc=0; - SCSISense.Ascq=0; -} - -void SCSISenseCodeError(uint8_t SenseKey, uint8_t Asc, uint8_t Ascq) -{ - SCSISense.SenseKey=SenseKey; - SCSISense.Asc=Asc; - SCSISense.Ascq=Ascq; - SCSIPhase = SCSI_PHASE_STATUS; /* This *HAS* to be done, SCSIPhase is the same thing that ATAPI returns in IDE sector count, so after any error, - status phase (3) is correct. */ -} - -static void -ScsiPadStr8(uint8_t *buf, int buf_size, const char *src) -{ - int i; - - for (i = 0; i < buf_size; i++) { - if (*src != '\0') { - buf[i] = *src++; - } else { - buf[i] = ' '; - } - } -} - -uint32_t SCSIGetCDChannel(int channel) -{ - return (page_flags[GPMODE_CDROM_AUDIO_PAGE] & PAGE_CHANGED) ? mode_pages_in[GPMODE_CDROM_AUDIO_PAGE][channel ? 8 : 6] : (channel + 1); -} - -uint32_t SCSIGetCDVolume(int channel) -{ - // return ((page_flags[GPMODE_CDROM_AUDIO_PAGE] & PAGE_CHANGED) && (mode_pages_in[GPMODE_CDROM_AUDIO_PAGE][channel ? 8 : 6] != 0)) ? mode_pages_in[GPMODE_CDROM_AUDIO_PAGE][channel ? 9 : 7] : 0xFF; - return (page_flags[GPMODE_CDROM_AUDIO_PAGE] & PAGE_CHANGED) ? mode_pages_in[GPMODE_CDROM_AUDIO_PAGE][channel ? 9 : 7] : 0xFF; -} - -/*SCSI Mode Sense 6/10*/ -uint32_t SCSICDROMModeSense(uint8_t *buf, uint32_t pos, uint8_t type) -{ - if (type==GPMODE_ALL_PAGES || type==GPMODE_R_W_ERROR_PAGE) - { - /* &01 - Read error recovery */ - buf[pos++] = GPMODE_R_W_ERROR_PAGE; - buf[pos++] = 6; /* Page length */ - buf[pos++] = 0; /* Error recovery parameters */ - buf[pos++] = 5; /* Read retry count */ - buf[pos++] = 0; /* Reserved */ - buf[pos++] = 0; /* Reserved */ - buf[pos++] = 0; /* Reserved */ - buf[pos++] = 0; /* Reserved */ - } - - if (type==GPMODE_ALL_PAGES || type==GPMODE_CDROM_PAGE) - { - /* &0D - CD-ROM Parameters */ - buf[pos++] = GPMODE_CDROM_PAGE; - buf[pos++] = 6; /* Page length */ - buf[pos++] = 0; /* Reserved */ - buf[pos++] = 1; /* Inactivity time multiplier *NEEDED BY RISCOS* value is a guess */ - buf[pos++] = 0; buf[pos++] = 60; /* MSF settings */ - buf[pos++] = 0; buf[pos++] = 75; /* MSF settings */ - } - - if (type==GPMODE_ALL_PAGES || type==GPMODE_CDROM_AUDIO_PAGE) - { - /* &0e - CD-ROM Audio Control Parameters */ - buf[pos++] = GPMODE_CDROM_AUDIO_PAGE; - buf[pos++] = 0xE; /* Page length */ - if (page_flags[GPMODE_CDROM_AUDIO_PAGE] & PAGE_CHANGED) - { - int i; - for (i = 0; i < 14; i++) - { - buf[pos++] = mode_pages_in[GPMODE_CDROM_AUDIO_PAGE][i]; - } - } - else - { - buf[pos++] = 4; /* Reserved */ - buf[pos++] = 0; /* Reserved */ - buf[pos++] = 0; /* Reserved */ - buf[pos++] = 0; /* Reserved */ - buf[pos++] = 0; buf[pos++] = 75; /* Logical audio block per second */ - buf[pos++] = 1; /* CDDA Output Port 0 Channel Selection */ - buf[pos++] = 0xFF; /* CDDA Output Port 0 Volume */ - buf[pos++] = 2; /* CDDA Output Port 1 Channel Selection */ - buf[pos++] = 0xFF; /* CDDA Output Port 1 Volume */ - buf[pos++] = 0; /* CDDA Output Port 2 Channel Selection */ - buf[pos++] = 0; /* CDDA Output Port 2 Volume */ - buf[pos++] = 0; /* CDDA Output Port 3 Channel Selection */ - buf[pos++] = 0; /* CDDA Output Port 3 Volume */ - } - } - - if (type==GPMODE_ALL_PAGES || type==GPMODE_CAPABILITIES_PAGE) - { -// pclog("Capabilities page\n"); - /* &2A - CD-ROM capabilities and mechanical status */ - buf[pos++] = GPMODE_CAPABILITIES_PAGE; - buf[pos++] = 0x12; /* Page length */ - buf[pos++] = 0; buf[pos++] = 0; /* CD-R methods */ - buf[pos++] = 1; /* Supports audio play, not multisession */ - buf[pos++] = 0; /* Some other stuff not supported */ - buf[pos++] = 0; /* Some other stuff not supported (lock state + eject) */ - buf[pos++] = 0; /* Some other stuff not supported */ - buf[pos++] = (uint8_t) (CDROM_SPEED >> 8); - buf[pos++] = (uint8_t) CDROM_SPEED; /* Maximum speed */ - buf[pos++] = 0; buf[pos++] = 2; /* Number of audio levels - on and off only */ - buf[pos++] = 0; buf[pos++] = 0; /* Buffer size - none */ - buf[pos++] = (uint8_t) (CDROM_SPEED >> 8); - buf[pos++] = (uint8_t) CDROM_SPEED; /* Current speed */ - buf[pos++] = 0; /* Reserved */ - buf[pos++] = 0; /* Drive digital format */ - buf[pos++] = 0; /* Reserved */ - buf[pos++] = 0; /* Reserved */ - } - - return pos; -} - -/*SCSI Get Configuration*/ -uint8_t SCSICDROMSetProfile(uint8_t *buf, uint8_t *index, uint16_t profile) -{ - uint8_t *buf_profile = buf + 12; /* start of profiles */ - - buf_profile += ((*index) * 4); /* start of indexed profile */ - buf_profile[0] = (profile >> 8) & 0xff; - buf_profile[1] = profile & 0xff; - buf_profile[2] = ((buf_profile[0] == buf[6]) && (buf_profile[1] == buf[7])); - - /* each profile adds 4 bytes to the response */ - (*index)++; - buf[11] += 4; /* Additional Length */ - - return 4; -} - -/*SCSI Read DVD Structure*/ -int SCSICDROMReadDVDStructure(int format, const uint8_t *packet, uint8_t *buf) -{ - switch (format) { - case 0x0: /* Physical format information */ - { - int layer = packet[6]; - uint64_t total_sectors; - total_sectors = (uint64_t) cdrom->size(); - - if (layer != 0) - return -ASC_INV_FIELD_IN_CMD_PACKET; - - total_sectors >>= 2; - if (total_sectors == 0) - return -ASC_MEDIUM_NOT_PRESENT; - - buf[4] = 1; /* DVD-ROM, part version 1 */ - buf[5] = 0xf; /* 120mm disc, minimum rate unspecified */ - buf[6] = 1; /* one layer, read-only (per MMC-2 spec) */ - buf[7] = 0; /* default densities */ - - /* FIXME: 0x30000 per spec? */ - buf[8] = buf[9] = buf[10] = buf[11] = 0; /* start sector */ - buf[12] = (total_sectors >> 24) & 0xff; /* end sector */ - buf[13] = (total_sectors >> 16) & 0xff; - buf[14] = (total_sectors >> 8) & 0xff; - buf[15] = total_sectors & 0xff; - - buf[16] = (total_sectors >> 24) & 0xff; /* l0 end sector */ - buf[17] = (total_sectors >> 16) & 0xff; - buf[18] = (total_sectors >> 8) & 0xff; - buf[19] = total_sectors & 0xff; - - /* Size of buffer, not including 2 byte size field */ - buf[0] = ((2048+2)>>8)&0xff; - buf[1] = (2048+2)&0xff; - - /* 2k data + 4 byte header */ - return (2048 + 4); - } - - case 0x01: /* DVD copyright information */ - buf[4] = 0; /* no copyright data */ - buf[5] = 0; /* no region restrictions */ - - /* Size of buffer, not including 2 byte size field */ - buf[0] = ((4+2)>>8)&0xff; - buf[1] = (4+2)&0xff; - - /* 4 byte header + 4 byte data */ - return (4 + 4); - - case 0x03: /* BCA information - invalid field for no BCA info */ - return -ASC_INV_FIELD_IN_CMD_PACKET; - - case 0x04: /* DVD disc manufacturing information */ - /* Size of buffer, not including 2 byte size field */ - buf[0] = ((2048+2)>>8)&0xff; - buf[1] = (2048+2)&0xff; - - /* 2k data + 4 byte header */ - return (2048 + 4); - - case 0xff: - /* - * This lists all the command capabilities above. Add new ones - * in order and update the length and buffer return values. - */ - - buf[4] = 0x00; /* Physical format */ - buf[5] = 0x40; /* Not writable, is readable */ - buf[6] = ((2048+4)>>8)&0xff; - buf[7] = (2048+4)&0xff; - - buf[8] = 0x01; /* Copyright info */ - buf[9] = 0x40; /* Not writable, is readable */ - buf[10] = ((4+4)>>8)&0xff; - buf[11] = (4+4)&0xff; - - buf[12] = 0x03; /* BCA info */ - buf[13] = 0x40; /* Not writable, is readable */ - buf[14] = ((188+4)>>8)&0xff; - buf[15] = (188+4)&0xff; - - buf[16] = 0x04; /* Manufacturing info */ - buf[17] = 0x40; /* Not writable, is readable */ - buf[18] = ((2048+4)>>8)&0xff; - buf[19] = (2048+4)&0xff; - - /* Size of buffer, not including 2 byte size field */ - buf[6] = ((16+2)>>8)&0xff; - buf[7] = (16+2)&0xff; - - /* data written + 4 byte header */ - return (16 + 4); - - default: /* TODO: formats beyond DVD-ROM requires */ - return -ASC_INV_FIELD_IN_CMD_PACKET; - } -} - -/*SCSI Get Event Status Notification*/ -uint32_t SCSICDROMEventStatus(uint8_t *buffer) -{ - uint8_t event_code, media_status = 0; - - if (buffer[5]) - { - media_status = MS_TRAY_OPEN; - cdrom->stop(); - } - else - { - media_status = MS_MEDIA_PRESENT; - } - - event_code = MEC_NO_CHANGE; - if (media_status != MS_TRAY_OPEN) - { - if (!buffer[4]) - { - event_code = MEC_NEW_MEDIA; - cdrom->load(); - } - else if (buffer[4]==2) - { - event_code = MEC_EJECT_REQUESTED; - cdrom->eject(); - } - } - - buffer[4] = event_code; - buffer[5] = media_status; - buffer[6] = 0; - buffer[7] = 0; - - return 8; -} - -void SCSICDROM_Insert() -{ - SCSISense.UnitAttention=1; -} - -int cd_status = CD_STATUS_EMPTY; -int prev_status; - -static uint8_t ScsiPrev; -static int SenseCompleted; - -int cdrom_add_error_and_subchannel(uint8_t *b, int real_sector_type) -{ - if ((cdrom_sector_flags & 0x06) == 0x02) - { - /* Add error flags. */ - memcpy(b + cdrom_sector_size, cdrom_sector_buffer.cdrom_sector.c2, 294); - cdrom_sector_size += 294; - } - else if ((cdrom_sector_flags & 0x06) == 0x04) - { - /* Add error flags. */ - memcpy(b + cdrom_sector_size, cdrom_sector_buffer.cdrom_sector.c2, 296); - cdrom_sector_size += 296; - } - else if ((cdrom_sector_flags & 0x06) == 0x06) - { - // pclog("Invalid error flags\n"); - return 0; - } - - /* if (real_sector_type == 1) - { */ - if ((cdrom_sector_flags & 0x700) == 0x100) - { - memcpy(b + cdrom_sector_size, cdrom_sector_buffer.cdrom_sector.subchannel_raw, 96); - cdrom_sector_size += 96; - } - else if ((cdrom_sector_flags & 0x700) == 0x200) - { - memcpy(b + cdrom_sector_size, cdrom_sector_buffer.cdrom_sector.subchannel_q, 16); - cdrom_sector_size += 16; - } - else if ((cdrom_sector_flags & 0x700) == 0x400) - { - memcpy(b + cdrom_sector_size, cdrom_sector_buffer.cdrom_sector.subchannel_rw, 96); - cdrom_sector_size += 96; - } - else if (((cdrom_sector_flags & 0x700) == 0x300) || ((cdrom_sector_flags & 0x700) > 0x400)) - { - // pclog("Invalid subchannel data flags\n"); - return 0; - } - // } - - // pclog("CD-ROM sector size after processing: %i (%i, %i) [%04X]\n", cdrom_sector_size, cdrom_sector_type, real_sector_type, cdrom_sector_flags); - - return cdrom_sector_size; -} - -int cdrom_LBAtoMSF_accurate() -{ - int temp_pos; - int m, s, f; - - temp_pos = SectorLBA + 150; - f = temp_pos % 75; - temp_pos -= f; - temp_pos /= 75; - s = temp_pos % 60; - temp_pos -= s; - temp_pos /= 60; - m = temp_pos; - - return ((m << 16) | (s << 8) | f); -} - -int cdrom_read_data(uint8_t *buffer) -{ - int real_sector_type; - uint8_t *b; - uint8_t *temp_b; - int is_audio; - int real_pos; - - b = temp_b = buffer; - - if (cdrom_sector_ismsf) - { - real_pos = cdrom_LBAtoMSF_accurate(); - } - else - { - real_pos = SectorLBA; - } - - memset(cdrom_sector_buffer.buffer, 0, 2856); - - // is_audio = cdrom->is_track_audio(real_pos, cdrom_sector_ismsf); - real_sector_type = cdrom->sector_data_type(real_pos, cdrom_sector_ismsf); - // pclog("Sector type: %i\n", real_sector_type); - - if ((cdrom_sector_type > 0) && (cdrom_sector_type < 6)) - { - if (real_sector_type != cdrom_sector_type) - { - return 0; - } - } - else if (cdrom_sector_type == 6) - { - /* READ (6), READ (10), READ (12) */ - if ((real_sector_type != 2) && (real_sector_type != 4)) - { - return 0; - } - } - - if (!(cdrom_sector_flags & 0xf0)) /* 0x00 and 0x08 are illegal modes */ - { - return 0; - } - - cdrom->readsector_raw(cdrom_sector_buffer.buffer, real_pos, cdrom_sector_ismsf); - - if (real_sector_type == 1) - { - memcpy(b, cdrom_sector_buffer.buffer, 2352); - cdrom_sector_size = 2352; - } - else - { - if ((cdrom_sector_flags & 0x18) == 0x08) /* EDC/ECC without user data is an illegal mode */ - { - return 0; - } - - cdrom_sector_size = 0; - - if (cdrom_sector_flags & 0x80) /* Sync */ - { - memcpy(temp_b, cdrom_sector_buffer.cdrom_sector.sync, 12); - cdrom_sector_size += 12; - temp_b += 12; - } - if (cdrom_sector_flags & 0x20) /* Header */ - { - memcpy(temp_b, cdrom_sector_buffer.cdrom_sector.header, 4); - cdrom_sector_size += 4; - temp_b += 4; - } - - if (real_sector_type == 2) - { - /* Mode 1 sector, expected type is 1 type. */ - if (cdrom_sector_flags & 0x40) /* Sub-header */ - { - if (!(cdrom_sector_flags & 0x10)) /* No user data */ - { - memcpy(temp_b, cdrom_sector_buffer.cdrom_sector.data.m1_data.user_data, 8); - cdrom_sector_size += 8; - temp_b += 8; - } - } - if (cdrom_sector_flags & 0x10) /* User data */ - { - memcpy(temp_b, cdrom_sector_buffer.cdrom_sector.data.m1_data.user_data, 2048); - cdrom_sector_size += 2048; - temp_b += 2048; - } - if (cdrom_sector_flags & 0x08) /* EDC/ECC */ - { - memcpy(temp_b, cdrom_sector_buffer.cdrom_sector.data.m1_data.ecc, 288); - cdrom_sector_size += 288; - temp_b += 288; - } - } - else if (real_sector_type == 3) - { - /* Mode 2 sector, non-XA mode. */ - if (cdrom_sector_flags & 0x40) /* Sub-header */ - { - if (!(cdrom_sector_flags & 0x10)) /* No user data */ - { - memcpy(temp_b, cdrom_sector_buffer.cdrom_sector.data.m2_data.sub_header, 8); - cdrom_sector_size += 8; - temp_b += 8; - } - } - if (cdrom_sector_flags & 0x10) /* User data */ - { - memcpy(temp_b, cdrom_sector_buffer.cdrom_sector.data.m2_data.sub_header, 2328); - cdrom_sector_size += 8; - temp_b += 8; - memcpy(temp_b, cdrom_sector_buffer.cdrom_sector.data.m2_data.user_data, 2328); - cdrom_sector_size += 2328; - temp_b += 2328; - } - } - else if (real_sector_type == 4) - { - /* Mode 2 sector, XA Form 1 mode */ - if ((cdrom_sector_flags & 0xf0) == 0x30) - { - return 0; - } - if (((cdrom_sector_flags & 0xf8) >= 0xa8) && ((cdrom_sector_flags & 0xf8) <= 0xd8)) - { - return 0; - } - if (cdrom_sector_flags & 0x40) /* Sub-header */ - { - memcpy(temp_b, cdrom_sector_buffer.cdrom_sector.data.m2_data.sub_header, 8); - cdrom_sector_size += 8; - temp_b += 8; - } - if (cdrom_sector_flags & 0x10) /* User data */ - { - if ((cdrom_sector_flags & 0xf0) == 0x10) - { - /* The data is alone, include sub-header. */ - memcpy(temp_b, cdrom_sector_buffer.cdrom_sector.data.m2_data.sub_header, 8); - cdrom_sector_size += 8; - temp_b += 8; - } - memcpy(temp_b, cdrom_sector_buffer.cdrom_sector.data.m2_data.user_data, 2040); - cdrom_sector_size += 2040; - temp_b += 2040; - } - if (cdrom_sector_flags & 0x08) /* EDC/ECC */ - { - memcpy(temp_b, cdrom_sector_buffer.cdrom_sector.data.m2_data.user_data + 2040, 288); - cdrom_sector_size += 288; - temp_b += 288; - } - } - else if (real_sector_type == 5) - { - /* Mode 2 sector, XA Form 2 mode */ - if ((cdrom_sector_flags & 0xf0) == 0x30) - { - return 0; - } - if (((cdrom_sector_flags & 0xf8) >= 0xa8) || ((cdrom_sector_flags & 0xf8) <= 0xd8)) - { - return 0; - } - /* Mode 2 sector, XA Form 1 mode */ - if (cdrom_sector_flags & 0x40) /* Sub-header */ - { - memcpy(temp_b, cdrom_sector_buffer.cdrom_sector.data.m2_data.sub_header, 8); - cdrom_sector_size += 8; - temp_b += 8; - } - if (cdrom_sector_flags & 0x10) /* User data */ - { - memcpy(temp_b, cdrom_sector_buffer.cdrom_sector.data.m2_data.user_data, 2328); - cdrom_sector_size += 2328; - temp_b += 2328; - } - } - else - { - return 0; - } - } - - pclog("CD-ROM sector size: %i (%i, %i) [%04X]\n", cdrom_sector_size, cdrom_sector_type, real_sector_type, cdrom_sector_flags); - return cdrom_add_error_and_subchannel(b, real_sector_type); -} - -void SCSIClearSense(uint8_t Command, uint8_t IgnoreUA) -{ - if ((SCSISense.SenseKey == SENSE_UNIT_ATTENTION) || IgnoreUA) - { - pclog("Sense cleared\n"); - ScsiPrev=Command; - SCSISenseCodeOk(); - } -} - -struct -{ - uint8_t opcode; - uint8_t polled; - uint8_t reserved2[2]; - uint8_t class; - uint8_t reserved3[2]; - uint16_t len; - uint8_t control; -} *gesn_cdb; - -struct -{ - uint16_t len; - uint8_t notification_class; - uint8_t supported_events; -} *gesn_event_header; - -static int SCSICDROM_TOC(uint8_t id, uint8_t *cdb) -{ - int TocFormat; - - TocFormat = cdb[2] & 0xf; - if (TocFormat == 0) - TocFormat = (cdb[9]>>6) & 3; - - return TocFormat; -} - -void SCSICDROM_Command(uint8_t id, uint8_t *cmdbuffer, uint8_t *cdb) -{ - int len; - int pos=0; - int DVDRet; - uint8_t Index = 0; - int real_pos; - int msf; - uint32_t Size; - unsigned Idx = 0; - unsigned SizeIndex; - unsigned PreambleLen; - unsigned char Temp; - int max_length = 0; - int track = 0; - int ret = 0; - - msf = cdb[1] & 2; - - //The not ready/unit attention stuff below is only for the Adaptec! - //The Buslogic one is located in buslogic.c. - - if (!scsi_model) - { - if (cdrom->medium_changed()) - { - pclog("Media changed\n"); - SCSICDROM_Insert(); - } - - if (!cdrom->ready() && SCSISense.UnitAttention) - { - /* If the drive is not ready, there is no reason to keep the - UNIT ATTENTION condition present, as we only use it to mark - disc changes. */ - SCSISense.UnitAttention = 0; - } - - /* If the UNIT ATTENTION condition is set and the command does not allow - execution under it, error out and report the condition. */ - if (SCSISense.UnitAttention == 1) - { - SCSISense.UnitAttention = 2; - if (!(SCSICommandTable[cdb[0]] & ALLOW_UA)) - { - SCSISenseCodeError(SENSE_UNIT_ATTENTION, ASC_MEDIUM_MAY_HAVE_CHANGED, 0); - SCSIStatus = SCSI_STATUS_CHECK_CONDITION; - SCSICallback[id]=50*SCSI_TIME; - return; - } - } - else if (SCSISense.UnitAttention == 2) - { - if (cdb[0]!=GPCMD_REQUEST_SENSE) - { - SCSISense.UnitAttention = 0; - } - } - - /* Unless the command is REQUEST SENSE, clear the sense. This will *NOT* - clear the UNIT ATTENTION condition if it's set. */ - if (cdb[0]!=GPCMD_REQUEST_SENSE) - { - SCSIClearSense(cdb[0], 0); - } - - /* Next it's time for NOT READY. */ - if ((SCSICommandTable[cdb[0]] & CHECK_READY) && !cdrom->ready()) - { - pclog("Not ready\n"); - SCSISenseCodeError(SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT, 0); - SCSIStatus = SCSI_STATUS_CHECK_CONDITION; - SCSICallback[id]=50*SCSI_TIME; - return; - } - } - - prev_status = cd_status; - cd_status = cdrom->status(); - if (((prev_status == CD_STATUS_PLAYING) || (prev_status == CD_STATUS_PAUSED)) && ((cd_status != CD_STATUS_PLAYING) && (cd_status != CD_STATUS_PAUSED))) - { - SenseCompleted = 1; - } - else - { - SenseCompleted = 0; - } - - switch (cdb[0]) - { - case GPCMD_TEST_UNIT_READY: - SCSIPhase = SCSI_PHASE_STATUS; - SCSIStatus = SCSI_STATUS_OK; - SCSICallback[id]=50*SCSI_TIME; - break; - - case GPCMD_REQUEST_SENSE: - len = cdb[4]; - - /*Will return 18 bytes of 0*/ - memset(cmdbuffer,0,512); - - cmdbuffer[0]=0x80|0x70; - - if ((SCSISense.SenseKey > 0) || (cd_status < CD_STATUS_PLAYING)) - { - if (SenseCompleted) - { - cmdbuffer[2]=SENSE_ILLEGAL_REQUEST; - cmdbuffer[12]=ASC_AUDIO_PLAY_OPERATION; - cmdbuffer[13]=ASCQ_AUDIO_PLAY_OPERATION_COMPLETED; - } - else - { - cmdbuffer[2]=SCSISense.SenseKey; - cmdbuffer[12]=SCSISense.Asc; - cmdbuffer[13]=SCSISense.Ascq; - } - } - else if ((SCSISense.SenseKey == 0) && (cd_status >= CD_STATUS_PLAYING) && (cd_status != CD_STATUS_STOPPED)) - { - cmdbuffer[2]=SENSE_ILLEGAL_REQUEST; - cmdbuffer[12]=ASC_AUDIO_PLAY_OPERATION; - cmdbuffer[13]=(cd_status == CD_STATUS_PLAYING) ? ASCQ_AUDIO_PLAY_OPERATION_IN_PROGRESS : ASCQ_AUDIO_PLAY_OPERATION_PAUSED; - } - else - { - if (SCSISense.UnitAttention) - { - cmdbuffer[2]=SENSE_UNIT_ATTENTION; - cmdbuffer[12]=ASC_MEDIUM_MAY_HAVE_CHANGED; - cmdbuffer[13]=0; - } - } - - cmdbuffer[7]=10; - - SCSIPhase = SCSI_PHASE_DATAIN; - SCSIStatus = SCSI_STATUS_OK; - SCSICallback[id]=60*SCSI_TIME; - SCSIDevices[id].CmdBufferLength = len; - - SCSIDMAResetPosition(id); - - if (cmdbuffer[2] == SENSE_UNIT_ATTENTION) - { - /* If the last remaining sense is unit attention, clear - that condition. */ - SCSISense.UnitAttention = 0; - } - - /* Clear the sense stuff as per the spec. */ - ScsiPrev=cdb[0]; - if (cdrom->ready()) - SCSISenseCodeOk(); - return; - - case GPCMD_READ_6: - case GPCMD_READ_10: - case GPCMD_READ_12: - cdrom_sector_ismsf = 0; - - if (cdb[0] == GPCMD_READ_6) - { - SectorLen=cdb[4]; - SectorLBA=((((uint32_t) cdb[1]) & 0x1f)<<16)|(((uint32_t) cdb[2])<<8)|((uint32_t) cdb[3]); - } - else if (cdb[0] == GPCMD_READ_10) - { - SectorLen=(cdb[7]<<8)|cdb[8]; - SectorLBA=(cdb[2]<<24)|(cdb[3]<<16)|(cdb[4]<<8)|cdb[5]; - } - else - { - SectorLen=(((uint32_t) cdb[6])<<24)|(((uint32_t) cdb[7])<<16)|(((uint32_t) cdb[8])<<8)|((uint32_t) cdb[9]); - SectorLBA=(((uint32_t) cdb[2])<<24)|(((uint32_t) cdb[3])<<16)|(((uint32_t) cdb[4])<<8)|((uint32_t) cdb[5]); - } - - if (SectorLBA > (cdrom->size() - 1)) - { - pclog("Trying to read beyond the end of disc\n"); - SCSIStatus = SCSI_STATUS_CHECK_CONDITION; - SCSISenseCodeError(SENSE_ILLEGAL_REQUEST, ASC_INV_FIELD_IN_CMD_PACKET, 0); - SCSICallback[id]=50*SCSI_TIME; - break; - } - - if (!SectorLen) - { - SCSIPhase = SCSI_PHASE_STATUS; - SCSIStatus = SCSI_STATUS_OK; - SCSICallback[id]=20*SCSI_TIME; - break; - } - - cdrom_sector_type = 6; - cdrom_sector_flags = 0x10; - - SCSIPhase = SCSI_PHASE_DATAIN; - SCSIStatus = SCSI_STATUS_OK; - SCSICallback[id]=60*SCSI_TIME; - SCSIDevices[id].CmdBufferLength = SectorLen * 2048; - - SCSIDMAResetPosition(id); - return; - - case GPCMD_SEEK_6: - case GPCMD_SEEK_10: - if (cdb[0] == GPCMD_SEEK_6) - { - pos = ((((uint32_t) cdb[1]) & 0x1f)<<16)|(((uint32_t) cdb[2])<<8)|((uint32_t) cdb[3]); - } - else - { - pos = (cdb[2]<<24)|(cdb[3]<<16)|(cdb[4]<<8)|cdb[5]; - } - cdrom->seek(pos); - - SCSIPhase = SCSI_PHASE_STATUS; - SCSIStatus = SCSI_STATUS_OK; - SCSICallback[id]=50*SCSI_TIME; - break; - - case GPCMD_INQUIRY: - max_length = cdb[4]; - len = max_length; - - if (cdb[1] & 1) - { - PreambleLen = 4; - SizeIndex = 3; - - cmdbuffer[Idx++] = 05; - cmdbuffer[Idx++] = cdb[2]; - cmdbuffer[Idx++] = 0; - - Idx++; - - switch (cdb[2]) - { - case 0x00: - cmdbuffer[Idx++] = 0x00; - cmdbuffer[Idx++] = 0x83; - break; - - case 0x83: - if (Idx + 24 > max_length) - { - SCSIStatus = SCSI_STATUS_CHECK_CONDITION; - SCSISenseCodeError(SENSE_ILLEGAL_REQUEST, ASC_DATA_PHASE_ERROR, 0x00); - SCSICallback[id]=50*SCSI_TIME; - return; - } - cmdbuffer[Idx++] = 0x02; - cmdbuffer[Idx++] = 0x00; - cmdbuffer[Idx++] = 0x00; - cmdbuffer[Idx++] = 20; - ScsiPadStr8(cmdbuffer + Idx, 20, "53R141"); /* Serial */ - Idx += 20; - - if (Idx + 72 > max_length) - { - goto SCSIOut; - } - cmdbuffer[Idx++] = 0x02; - cmdbuffer[Idx++] = 0x01; - cmdbuffer[Idx++] = 0x00; - cmdbuffer[Idx++] = 68; - ScsiPadStr8(cmdbuffer + Idx, 8, "86Box"); /* Vendor */ - Idx += 8; - ScsiPadStr8(cmdbuffer + Idx, 40, "86BoxCD 1.00"); /* Product */ - Idx += 40; - ScsiPadStr8(cmdbuffer + Idx, 20, "53R141"); /* Product */ - Idx += 20; - break; - - default: - SCSIStatus = SCSI_STATUS_CHECK_CONDITION; - SCSISenseCodeError(SENSE_ILLEGAL_REQUEST, ASC_INV_FIELD_IN_CMD_PACKET, 0x00); - SCSICallback[id]=50*SCSI_TIME; - return; - } - } - else - { - PreambleLen = 5; - SizeIndex = 4; - - cmdbuffer[0] = 0x05; /*CD-ROM*/ - cmdbuffer[1] = 0x80; /*Removable*/ - cmdbuffer[2] = 0; - cmdbuffer[3] = 0x21; - cmdbuffer[4] = 31; - cmdbuffer[5] = 0; - cmdbuffer[6] = 0; - cmdbuffer[7] = 0; - ScsiPadStr8(cmdbuffer + 8, 8, "86Box"); /* Vendor */ - ScsiPadStr8(cmdbuffer + 16, 16, "86BoxCD"); /* Product */ - ScsiPadStr8(cmdbuffer + 32, 4, emulator_version); /* Revision */ - - Idx = 36; - } - -SCSIOut: - cmdbuffer[SizeIndex] = Idx - PreambleLen; - len=Idx; - - SCSIPhase = SCSI_PHASE_DATAIN; - SCSIStatus = SCSI_STATUS_OK; - SCSICallback[id]=60*SCSI_TIME; - SCSIDevices[id].CmdBufferLength = len; - - SCSIDMAResetPosition(id); - break; - - case GPCMD_MODE_SELECT_6: - case GPCMD_MODE_SELECT_10: - if (cdb[0] == GPCMD_MODE_SELECT_6) - { - len = cdb[4]; - prefix_len = 6; - } - else - { - len = (cdb[7]<<8)|cdb[8]; - prefix_len = 10; - } - - page_current = cdb[2]; - if (page_flags[page_current] & PAGE_CHANGEABLE) - page_flags[GPMODE_CDROM_AUDIO_PAGE] |= PAGE_CHANGED; - - SCSIPhase = SCSI_PHASE_DATAOUT; - SCSIStatus = SCSI_STATUS_OK; - SCSICallback[id]=60*SCSI_TIME; - SCSIDevices[id].CmdBufferLength = len; - - SCSIDMAResetPosition(id); - return; - - case GPCMD_MODE_SENSE_6: - case GPCMD_MODE_SENSE_10: - if (cdb[0] == GPCMD_MODE_SENSE_6) - len = cdb[4]; - else - len = (cdb[7]<<8)|cdb[8]; - - Temp = cdb[2] & 0x3F; - - memset(cmdbuffer, 0, len); - - if (!(mode_sense_pages[cdb[2] & 0x3f] & IMPLEMENTED)) - { - SCSIStatus = SCSI_STATUS_CHECK_CONDITION; - SCSISenseCodeError(SENSE_ILLEGAL_REQUEST, ASC_INV_FIELD_IN_CMD_PACKET, 0x00); - SCSICallback[id]=50*SCSI_TIME; - return; - } - - if (cdb[0] == GPCMD_MODE_SENSE_6) - { - len = SCSICDROMModeSense(cmdbuffer, 4, Temp); - cmdbuffer[0] = len - 1; - cmdbuffer[1] = 3; /*120mm data CD-ROM*/ - } - else - { - len = SCSICDROMModeSense(cmdbuffer, 8, Temp); - cmdbuffer[0] = (len - 2)>>8; - cmdbuffer[1] = (len - 2)&255; - cmdbuffer[2] = 3; /*120mm data CD-ROM*/ - } - - SCSIPhase = SCSI_PHASE_DATAIN; - SCSIStatus = SCSI_STATUS_OK; - SCSICallback[id]=60*SCSI_TIME; - SCSIDevices[id].CmdBufferLength = len; - - SCSIDMAResetPosition(id); - return; - - case GPCMD_START_STOP_UNIT: - switch(cdb[4] & 3) - { - case 0: /* Stop the disc. */ - cdrom->stop(); - break; - case 1: /* Start the disc and read the TOC. */ - cdrom->medium_changed(); /* This causes a TOC reload. */ - break; - case 2: /* Eject the disc if possible. */ - cdrom->stop(); -#ifndef __unix - win_cdrom_eject(); -#endif - break; - case 3: /* Load the disc (close tray). */ -#ifndef __unix - win_cdrom_reload(); -#else - cdrom->load(); -#endif - break; - } - - SCSIPhase = SCSI_PHASE_STATUS; - SCSIStatus = SCSI_STATUS_OK; - SCSICallback[id]=50*SCSI_TIME; - break; - - case GPCMD_PREVENT_REMOVAL: - SCSIPhase = SCSI_PHASE_STATUS; - SCSIStatus = SCSI_STATUS_OK; - SCSICallback[id]=50*SCSI_TIME; - break; - - case GPCMD_READ_CDROM_CAPACITY: - if (cdrom->read_capacity) - { - cdrom->read_capacity(cmdbuffer); - } - else - { - Size = cdrom->size() - 1; /* IMPORTANT: What's returned is the last LBA block. */ - memset(cmdbuffer, 0, 8); - cmdbuffer[0] = (Size >> 24) & 0xff; - cmdbuffer[1] = (Size >> 16) & 0xff; - cmdbuffer[2] = (Size >> 8) & 0xff; - cmdbuffer[3] = Size & 0xff; - cmdbuffer[6] = 8; /* 2048 = 0x0800 */ - } - - SCSIPhase = SCSI_PHASE_DATAIN; - SCSIStatus = SCSI_STATUS_OK; - SCSICallback[id]=60*SCSI_TIME; - SCSIDevices[id].CmdBufferLength = 8; - - SCSIDMAResetPosition(id); - break; - - case GPCMD_READ_SUBCHANNEL: - if (cdb[3] > 3) - { - SCSIStatus = SCSI_STATUS_CHECK_CONDITION; - SCSISenseCodeError(SENSE_ILLEGAL_REQUEST, ASC_INV_FIELD_IN_CMD_PACKET, 0x00); - SCSICallback[id]=50*SCSI_TIME; - break; - } - - switch(cdb[3]) - { - case 0: - Temp = 4; - break; - case 1: - Temp = 16; - break; - default: - Temp = 24; - break; - } - - if (cdrom->read_subchannel) - { - cdrom->read_subchannel(cdb, cmdbuffer); - len = Temp; - } - else - { - memset(cmdbuffer, 24, 0); - pos = 0; - cmdbuffer[pos++]=0; - cmdbuffer[pos++]=0; /*Audio status*/ - cmdbuffer[pos++]=0; cmdbuffer[pos++]=0; /*Subchannel length*/ - cmdbuffer[pos++]=cdb[3]; /*Format code*/ - if (!(cdb[2] & 0x40) || (cdb[3] == 0)) - { - len = 4; - } - else - { - len = Temp; - } - if (cdb[3] == 1) - { - cmdbuffer[1]=cdrom->getcurrentsubchannel(&cmdbuffer[5],msf); - } - } - - SCSIPhase = SCSI_PHASE_DATAIN; - SCSIStatus = SCSI_STATUS_OK; - SCSICallback[id]=1000*SCSI_TIME; - SCSIDevices[id].CmdBufferLength = len; - - SCSIDMAResetPosition(id); - break; - - case GPCMD_READ_TOC_PMA_ATIP: - switch (SCSICDROM_TOC(id, cdb)) - { - case 0: /*Normal*/ - len = cdb[8]|(cdb[7]<<8); - len = cdrom->readtoc(cmdbuffer, cdb[6], msf, len, 0); - break; - - case 1: /*Multi session*/ - len = cdb[8]|(cdb[7]<<8); - len = cdrom->readtoc_session(cmdbuffer, msf, len); - cmdbuffer[0] = 0; - cmdbuffer[1] = 0xA; - break; - - case 2: /*Raw*/ - len = cdb[8]|(cdb[7]<<8); - len = cdrom->readtoc_raw(cmdbuffer, msf, len); - break; - - default: - SCSIStatus = SCSI_STATUS_CHECK_CONDITION; - SCSISenseCodeError(SENSE_ILLEGAL_REQUEST, ASC_INV_FIELD_IN_CMD_PACKET, 0x00); - SCSICallback[id]=50*SCSI_TIME; - return; - } - SCSIPhase = SCSI_PHASE_DATAIN; - SCSIStatus = SCSI_STATUS_OK; - SCSICallback[id]=60*SCSI_TIME; - SCSIDevices[id].CmdBufferLength = len; - - SCSIDMAResetPosition(id); - return; - - case GPCMD_READ_HEADER: - if (cdrom->read_header) - { - cdrom->read_header(cdb, cmdbuffer); - } - else - { - SectorLen=(cdb[7]<<8)|cdb[8]; - SectorLBA=(cdb[2]<<24)|(cdb[3]<<16)|(cdb[4]<<8)|cdb[5]; - if (msf) - { - real_pos = cdrom_LBAtoMSF_accurate(); - } - else - { - real_pos = SectorLBA; - } - cmdbuffer[4] = (real_pos >> 24); - cmdbuffer[5] = ((real_pos >> 16) & 0xff); - cmdbuffer[6] = ((real_pos >> 8) & 0xff); - cmdbuffer[7] = real_pos & 0xff; - cmdbuffer[0]=1; /*2048 bytes user data*/ - cmdbuffer[1]=cmdbuffer[2]=cmdbuffer[3]=0; - } - - SCSIPhase = SCSI_PHASE_DATAIN; - SCSIStatus = SCSI_STATUS_OK; - SCSICallback[id]=60*SCSI_TIME; - SCSIDevices[id].CmdBufferLength = 8; - - SCSIDMAResetPosition(id); - break; - - case GPCMD_PLAY_AUDIO_10: - case GPCMD_PLAY_AUDIO_MSF: - case GPCMD_PLAY_AUDIO_12: - if (cdb[0] == GPCMD_PLAY_AUDIO_10) - { - pos = (cdb[2]<<24)|(cdb[3]<<16)|(cdb[4]<<8)|cdb[5]; - len = (cdb[7]<<8)|cdb[8]; - } - else if (cdb[0] == GPCMD_PLAY_AUDIO_MSF) - { - pos = (cdb[3]<<16)|(cdb[4]<<8)|cdb[5]; - len = (cdb[6]<<16)|(cdb[7]<<8)|cdb[8]; - } - else - { - pos = (cdb[3]<<16)|(cdb[4]<<8)|cdb[5]; - len = (cdb[7]<<16)|(cdb[8]<<8)|cdb[9]; - } - - if ((cdrom_drive < 1) || (cdrom_drive == 200) || (cd_status <= CD_STATUS_DATA_ONLY) || - !cdrom->is_track_audio(pos, (cdb[0] == GPCMD_PLAY_AUDIO_MSF) ? 1 : 0)) - { - pclog("Invalid mode for this track\n"); - SCSIStatus = SCSI_STATUS_CHECK_CONDITION; - SCSISenseCodeError(SENSE_ILLEGAL_REQUEST, ASC_ILLEGAL_MODE_FOR_THIS_TRACK, 0x00); - SCSICallback[id]=50*SCSI_TIME; - break; - } - - cdrom->playaudio(pos, len, (cdb[0] == GPCMD_PLAY_AUDIO_MSF) ? 1 : 0); - SCSIPhase = SCSI_PHASE_STATUS; - SCSIStatus = SCSI_STATUS_OK; - SCSICallback[id]=50*SCSI_TIME; - break; - - case GPCMD_GET_CONFIGURATION: - len = (cdb[7]<<8)|cdb[8]; - - Index = 0; - - /* only feature 0 is supported */ - if (cdb[2] != 0 || cdb[3] != 0) - { - SCSIStatus = SCSI_STATUS_CHECK_CONDITION; - SCSISenseCodeError(SENSE_ILLEGAL_REQUEST, ASC_INV_FIELD_IN_CMD_PACKET, 0x00); - SCSICallback[id]=50*SCSI_TIME; - return; - } - - /* - * XXX: avoid overflow for io_buffer if length is bigger than - * the size of that buffer (dimensioned to max number of - * sectors to transfer at once) - * - * Only a problem if the feature/profiles grow. - */ - if (len > 512) /* XXX: assume 1 sector */ - len = 512; - - memset(cmdbuffer, 0, len); - /* - * the number of sectors from the media tells us which profile - * to use as current. 0 means there is no media - */ - if (len > CD_MAX_SECTORS ) - { - cmdbuffer[6] = (MMC_PROFILE_DVD_ROM >> 8) & 0xff; - cmdbuffer[7] = MMC_PROFILE_DVD_ROM & 0xff; - } - else if (len <= CD_MAX_SECTORS) - { - cmdbuffer[6] = (MMC_PROFILE_CD_ROM >> 8) & 0xff; - cmdbuffer[7] = MMC_PROFILE_CD_ROM & 0xff; - } - cmdbuffer[10] = 0x02 | 0x01; /* persistent and current */ - len = 12; /* headers: 8 + 4 */ - len += SCSICDROMSetProfile(cmdbuffer, &Index, MMC_PROFILE_DVD_ROM); - len += SCSICDROMSetProfile(cmdbuffer, &Index, MMC_PROFILE_CD_ROM); - cmdbuffer[0] = ((len-4) >> 24) & 0xff; - cmdbuffer[1] = ((len-4) >> 16) & 0xff; - cmdbuffer[2] = ((len-4) >> 8) & 0xff; - cmdbuffer[3] = (len-4) & 0xff; - - SCSIPhase = SCSI_PHASE_DATAIN; - SCSIStatus = SCSI_STATUS_OK; - SCSICallback[id]=60*SCSI_TIME; - SCSIDevices[id].CmdBufferLength = len; - - SCSIDMAResetPosition(id); - break; - - case GPCMD_GET_EVENT_STATUS_NOTIFICATION: - gesn_cdb = (void *)cdb; - gesn_event_header = (void *)cmdbuffer; - - /* It is fine by the MMC spec to not support async mode operations */ - if (!(gesn_cdb->polled & 0x01)) - { /* asynchronous mode */ - /* Only pollign is supported, asynchronous mode is not. */ - SCSIStatus = SCSI_STATUS_CHECK_CONDITION; - SCSISenseCodeError(SENSE_ILLEGAL_REQUEST, ASC_INV_FIELD_IN_CMD_PACKET, 0x00); - SCSICallback[id]=50*SCSI_TIME; - return; - } - - /* polling mode operation */ - - /* - * These are the supported events. - * - * We currently only support requests of the 'media' type. - * Notification class requests and supported event classes are bitmasks, - * but they are built from the same values as the "notification class" - * field. - */ - gesn_event_header->supported_events = 1 << GESN_MEDIA; - - /* - * We use |= below to set the class field; other bits in this byte - * are reserved now but this is useful to do if we have to use the - * reserved fields later. - */ - gesn_event_header->notification_class = 0; - - /* - * Responses to requests are to be based on request priority. The - * notification_class_request_type enum above specifies the - * priority: upper elements are higher prio than lower ones. - */ - if (gesn_cdb->class & (1 << GESN_MEDIA)) - { - gesn_event_header->notification_class |= GESN_MEDIA; - len = SCSICDROMEventStatus(cmdbuffer); - } - else - { - gesn_event_header->notification_class = 0x80; /* No event available */ - SCSIDevices[id].CmdBufferLength = sizeof(*gesn_event_header); - } - gesn_event_header->len = len - sizeof(*gesn_event_header); - - SCSIPhase = SCSI_PHASE_DATAIN; - SCSIStatus = SCSI_STATUS_OK; - SCSICallback[id]=60*SCSI_TIME; - SCSIDevices[id].CmdBufferLength = len; - - SCSIDMAResetPosition(id); - break; - - case GPCMD_PAUSE_RESUME: - if (cdb[8]&1) cdrom->resume(); - else cdrom->pause(); - SCSIPhase = SCSI_PHASE_STATUS; - SCSIStatus = SCSI_STATUS_OK; - SCSICallback[id]=50*SCSI_TIME; - break; - - case GPCMD_STOP_PLAY_SCAN: - cdrom->stop(); - SCSIPhase = SCSI_PHASE_STATUS; - SCSIStatus = SCSI_STATUS_OK; - SCSICallback[id]=50*SCSI_TIME; - break; - - case GPCMD_READ_DISC_INFORMATION: - if (cdrom->read_disc_information) - { - cdrom->read_disc_information(cmdbuffer); - } - else - { - cmdbuffer[1] = 32; - cmdbuffer[2] = 0xe; /* last session complete, disc finalized */ - cmdbuffer[3] = 1; /* first track on disc */ - cmdbuffer[4] = 1; /* # of sessions */ - cmdbuffer[5] = 1; /* first track of last session */ - cmdbuffer[6] = 1; /* last track of last session */ - cmdbuffer[7] = 0x20; /* unrestricted use */ - cmdbuffer[8] = 0x00; /* CD-ROM */ - } - - SCSIPhase = SCSI_PHASE_DATAIN; - SCSIStatus = SCSI_STATUS_OK; - SCSICallback[id]=60*SCSI_TIME; - SCSIDevices[id].CmdBufferLength = 34; - - SCSIDMAResetPosition(id); - break; - - case GPCMD_READ_TRACK_INFORMATION: - max_length = cdb[7]; - max_length <<= 8; - max_length |= cdb[8]; - - track = ((uint32_t) cdb[2]) << 24; - track |= ((uint32_t) cdb[3]) << 16; - track |= ((uint32_t) cdb[4]) << 8; - track |= (uint32_t) cdb[5]; - - if (cdrom->read_track_information) - { - ret = cdrom->read_track_information(cdb, cmdbuffer); - - if (!ret) - { - SCSIStatus = SCSI_STATUS_CHECK_CONDITION; - SCSISenseCodeError(SENSE_ILLEGAL_REQUEST, ASC_INV_FIELD_IN_CMD_PACKET, 0x00); - SCSICallback[id]=50*SCSI_TIME; - return; - } - - len = cmdbuffer[0]; - len <<= 8; - len |= cmdbuffer[1]; - len += 2; - } - else - { - if (((cdb[1] & 0x03) != 1) || (track != 1)) - { - SCSIStatus = SCSI_STATUS_CHECK_CONDITION; - SCSISenseCodeError(SENSE_ILLEGAL_REQUEST, ASC_INV_FIELD_IN_CMD_PACKET, 0x00); - SCSICallback[id]=50*SCSI_TIME; - return; - } - - len = 36; - cmdbuffer[1] = 34; - cmdbuffer[2] = 1; /* track number (LSB) */ - cmdbuffer[3] = 1; /* session number (LSB) */ - cmdbuffer[5] = (0 << 5) | (0 << 4) | (4 << 0); /* not damaged, primary copy, data track */ - cmdbuffer[6] = (0 << 7) | (0 << 6) | (0 << 5) | (0 << 6) | (1 << 0); /* not reserved track, not blank, not packet writing, not fixed packet, data mode 1 */ - cmdbuffer[7] = (0 << 1) | (0 << 0); /* last recorded address not valid, next recordable address not valid */ - cmdbuffer[8] = 0; /* track start address is 0 */ - cmdbuffer[24] = (cdrom->size() >> 24) & 0xff; /* track size */ - cmdbuffer[25] = (cdrom->size() >> 16) & 0xff; /* track size */ - cmdbuffer[26] = (cdrom->size() >> 8) & 0xff; /* track size */ - cmdbuffer[27] = cdrom->size() & 0xff; /* track size */ - cmdbuffer[32] = 0; /* track number (MSB) */ - cmdbuffer[33] = 0; /* session number (MSB) */ - } - - if (len > max_length) - { - len = max_length; - cmdbuffer[0] = ((max_length - 2) >> 8) & 0xff; - cmdbuffer[1] = (max_length - 2) & 0xff; - } - - SCSIPhase = SCSI_PHASE_DATAIN; - SCSIStatus = SCSI_STATUS_OK; - SCSICallback[id]=60*SCSI_TIME; - SCSIDevices[id].CmdBufferLength = len; - - SCSIDMAResetPosition(id); - break; - - case GPCMD_READ_DVD_STRUCTURE: - len = (cdb[6]<<24)|(cdb[7]<<16)|(cdb[8]<<8)|cdb[9]; - - if (cdb[7] < 0xff) - { - if (len <= CD_MAX_SECTORS) - { - SCSIStatus = SCSI_STATUS_CHECK_CONDITION; - SCSISenseCodeError(SENSE_ILLEGAL_REQUEST, ASC_INCOMPATIBLE_FORMAT, 0x00); - SCSICallback[id]=50*SCSI_TIME; - break; - } - else - { - SCSIStatus = SCSI_STATUS_CHECK_CONDITION; - SCSISenseCodeError(SENSE_ILLEGAL_REQUEST, ASC_INV_FIELD_IN_CMD_PACKET, 0x00); - SCSICallback[id]=50*SCSI_TIME; - return; - } - } - - memset(cmdbuffer, 0, len > 256 * 512 + 4 ? 256 * 512 + 4 : len); - - switch (cdb[7]) - { - case 0x00 ... 0x7f: - case 0xff: - if (cdb[1] == 0) - { - DVDRet = SCSICDROMReadDVDStructure(cdb[7], cdb, cmdbuffer); - - if (DVDRet < 0) - { - SCSIStatus = SCSI_STATUS_CHECK_CONDITION; - SCSISenseCodeError(SENSE_ILLEGAL_REQUEST, -DVDRet, 0x00); - SCSICallback[id]=50*SCSI_TIME; - return; - } - else - { - SCSIPhase = SCSI_PHASE_DATAIN; - SCSIStatus = SCSI_STATUS_OK; - SCSICallback[id]=60*SCSI_TIME; - SCSIDevices[id].CmdBufferLength = len; - - SCSIDMAResetPosition(id); - } - break; - } - /* TODO: BD support, fall through for now */ - - /* Generic disk structures */ - case 0x80: /* TODO: AACS volume identifier */ - case 0x81: /* TODO: AACS media serial number */ - case 0x82: /* TODO: AACS media identifier */ - case 0x83: /* TODO: AACS media key block */ - case 0x90: /* TODO: List of recognized format layers */ - case 0xc0: /* TODO: Write protection status */ - default: - SCSIStatus = SCSI_STATUS_CHECK_CONDITION; - SCSISenseCodeError(SENSE_ILLEGAL_REQUEST, ASC_INV_FIELD_IN_CMD_PACKET, 0x00); - SCSICallback[id]=50*SCSI_TIME; - return; - } - break; - - case GPCMD_READ_CD_MSF: - case GPCMD_READ_CD: - if (cdb[0] == GPCMD_READ_CD_MSF) - { - SectorLBA=MSFtoLBA(cdb[3],cdb[4],cdb[5]); - SectorLen=MSFtoLBA(cdb[6],cdb[7],cdb[8]); - - SectorLen -= SectorLBA; - SectorLen++; - - cdrom_sector_ismsf = 1; - } - else - { - SectorLen=(cdb[6]<<16)|(cdb[7]<<8)|cdb[8]; - SectorLBA=(cdb[2]<<24)|(cdb[3]<<16)|(cdb[4]<<8)|cdb[5]; - - cdrom_sector_ismsf = 0; - } - - if (SectorLBA > (cdrom->size() - 1)) - { - //pclog("Trying to read beyond the end of disc\n"); - SCSIStatus = SCSI_STATUS_CHECK_CONDITION; - SCSISenseCodeError(SENSE_ILLEGAL_REQUEST, ASC_INV_FIELD_IN_CMD_PACKET, 0); - SCSICallback[id]=50*SCSI_TIME; - break; - } - - cdrom_sector_type = (cdb[1] >> 2) & 7; - cdrom_sector_flags = cdb[9] || ((cdb[10]) << 8); - - SCSIPhase = SCSI_PHASE_DATAIN; - SCSIStatus = SCSI_STATUS_OK; - SCSICallback[id]=60*SCSI_TIME; - SCSIDevices[id].CmdBufferLength = SectorLen * cdrom_sector_size; - - SCSIDMAResetPosition(id); - return; - - case GPCMD_SET_SPEED: - SCSIPhase = SCSI_PHASE_STATUS; - SCSIStatus = SCSI_STATUS_OK; - SCSICallback[id]=50*SCSI_TIME; - break; - - case GPCMD_MECHANISM_STATUS: - cmdbuffer[0] = 0; - cmdbuffer[1] = 0; - cmdbuffer[2] = 0; - cmdbuffer[3] = 0; - cmdbuffer[4] = 0; - cmdbuffer[5] = 1; - cmdbuffer[6] = 0; - cmdbuffer[7] = 0; - - SCSIPhase = SCSI_PHASE_DATAIN; - SCSIStatus = SCSI_STATUS_OK; - SCSICallback[id]=60*SCSI_TIME; - SCSIDevices[id].CmdBufferLength = 8; - - SCSIDMAResetPosition(id); - break; - } - - -} - -void SCSICDROM_ReadData(uint8_t id, uint8_t *cdb, uint8_t *data, int datalen) -{ - int read_length = 0; - - switch (cdb[0]) - { - case GPCMD_READ_6: - case GPCMD_READ_10: - case GPCMD_READ_12: - case GPCMD_READ_CD_MSF: - case GPCMD_READ_CD: - pclog("Total data length requested: %d\n", datalen); - while (datalen > 0) - { - read_length = cdrom_read_data(data); //Fill the buffer the data it needs - if (!read_length) - { - pclog("Invalid read\n"); - SCSIStatus = SCSI_STATUS_CHECK_CONDITION; - SCSISenseCodeError(SENSE_ILLEGAL_REQUEST, ASC_INV_FIELD_IN_CMD_PACKET, 0x00); - SCSICallback[id]=50*SCSI_TIME; - break; - } - else - { - //Continue reading data until the sector length is 0. - data += read_length; - datalen -= read_length; - } - - pclog("True LBA: %d, buffer half: %d\n", SectorLBA, SectorLen * cdrom_sector_size); - - SectorLBA++; - SectorLen--; - - if (SectorLen == 0) - break; - } - break; - } -} diff --git a/src/scsi_disk.c b/src/scsi_disk.c new file mode 100644 index 000000000..340ffd6b3 --- /dev/null +++ b/src/scsi_disk.c @@ -0,0 +1,1152 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * Emulation of SCSI fixed and removable disks. + * + * Version: @(#)scsi_disk.c 1.0.2 2017/06/16 + * + * Author: Miran Grca, + * Copyright 2017-2017 Miran Grca. + */ +#include +#include +#include + +#include "86box.h" +#include "cdrom.h" +#include "ibm.h" +#include "hdd_image.h" +#include "ide.h" +#include "piix.h" +#include "scsi.h" +#include "scsi_disk.h" +#include "timer.h" +#include "win/plat_iodev.h" + +/* Bits of 'status' */ +#define ERR_STAT 0x01 +#define DRQ_STAT 0x08 /* Data request */ +#define DSC_STAT 0x10 +#define SERVICE_STAT 0x10 +#define READY_STAT 0x40 +#define BUSY_STAT 0x80 + +/* Bits of 'error' */ +#define ABRT_ERR 0x04 /* Command aborted */ +#define MCR_ERR 0x08 /* Media change request */ + +#define MAX_BLOCKS_AT_ONCE 340 + +#define scsi_hd_sense_error shdc[id].sense[0] +#define scsi_hd_sense_key shdc[id].sense[2] +#define scsi_hd_asc shdc[id].sense[12] +#define scsi_hd_ascq shdc[id].sense[13] + +scsi_hard_disk_t shdc[HDC_NUM]; + +FILE *shdf[HDC_NUM]; + +uint8_t scsi_hard_disks[16][8] = { { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF } }; + +/* Table of all SCSI commands and their flags, needed for the new disc change / not ready handler. */ +uint8_t scsi_hd_command_flags[0x100] = +{ + IMPLEMENTED | CHECK_READY | NONDATA, /* 0x00 */ + IMPLEMENTED | ALLOW_UA | NONDATA | SCSI_ONLY, /* 0x01 */ + 0, + IMPLEMENTED | ALLOW_UA, /* 0x03 */ + IMPLEMENTED | CHECK_READY | ALLOW_UA | NONDATA | SCSI_ONLY, /* 0x04 */ + 0, 0, 0, + IMPLEMENTED | CHECK_READY, /* 0x08 */ + 0, + IMPLEMENTED | CHECK_READY, /* 0x0A */ + 0, 0, 0, 0, 0, 0, 0, + IMPLEMENTED | ALLOW_UA, /* 0x12 */ + IMPLEMENTED | CHECK_READY | NONDATA | SCSI_ONLY, /* 0x13 */ + 0, 0, 0, 0, 0, 0, 0, + IMPLEMENTED | CHECK_READY, /* 0x1B */ + 0, 0, + IMPLEMENTED | CHECK_READY, /* 0x1E */ + 0, 0, 0, 0, 0, 0, + IMPLEMENTED | CHECK_READY, /* 0x25 */ + 0, 0, + IMPLEMENTED | CHECK_READY, /* 0x28 */ + 0, + IMPLEMENTED | CHECK_READY, /* 0x2A */ + 0, 0, 0, 0, + IMPLEMENTED | CHECK_READY | NONDATA | SCSI_ONLY, /* 0x2F */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + IMPLEMENTED | CHECK_READY, /* 0xA8 */ + 0, + IMPLEMENTED | CHECK_READY, /* 0xAA */ + 0, 0, 0, 0, + IMPLEMENTED | CHECK_READY | NONDATA | SCSI_ONLY, /* 0xAF */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + IMPLEMENTED, /* 0xBD */ + 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +int scsi_hd_do_log = 0; + +void scsi_hd_log(const char *format, ...) +{ +#ifdef ENABLE_scsi_hd_LOG + if (scsi_hd_do_log) + { + va_list ap; + va_start(ap, format); + vprintf(format, ap); + va_end(ap); + fflush(stdout); + } +#endif +} + +/* Translates ATAPI status (ERR_STAT flag) to SCSI status. */ +int scsi_hd_err_stat_to_scsi(uint8_t id) +{ + if (shdc[id].status & ERR_STAT) + { + return SCSI_STATUS_CHECK_CONDITION; + } + else + { + return SCSI_STATUS_OK; + } + + return SCSI_STATUS_OK; +} + +/* Translates ATAPI phase (DRQ, I/O, C/D) to SCSI phase (MSG, C/D, I/O). */ +int scsi_hd_phase_to_scsi(uint8_t id) +{ + if (shdc[id].status & 8) + { + switch (shdc[id].phase & 3) + { + case 0: + return 0; + case 1: + return 2; + case 2: + return 1; + case 3: + return 7; + } + } + else + { + if ((shdc[id].phase & 3) == 3) + { + return 3; + } + else + { + /* Translate reserved ATAPI phase to reserved SCSI phase. */ + return 4; + } + } + + return 0; +} + +int find_hdc_for_scsi_id(uint8_t scsi_id, uint8_t scsi_lun) +{ + uint8_t i = 0; + + for (i = 0; i < HDC_NUM; i++) + { + if ((wcslen(hdc[i].fn) == 0) && (hdc[i].bus != HDD_BUS_SCSI_REMOVABLE)) + { + continue; + } + if (((hdc[i].spt == 0) || (hdc[i].hpc == 0) || (hdc[i].tracks == 0)) && (hdc[i].bus != HDD_BUS_SCSI_REMOVABLE)) + { + continue; + } + if (((hdc[i].bus == HDD_BUS_SCSI) || (hdc[i].bus == HDD_BUS_SCSI_REMOVABLE)) && (hdc[i].scsi_id == scsi_id) && (hdc[i].scsi_lun == scsi_lun)) + { + return i; + } + } + return 0xff; +} + +void scsi_disk_insert(uint8_t id) +{ + shdc[id].unit_attention = (hdc[id].bus == HDD_BUS_SCSI_REMOVABLE) ? 1 : 0; +} + +void scsi_loadhd(int scsi_id, int scsi_lun, int id) +{ + int ret = 0; + + ret = hdd_image_load(id); + + if (!ret) + { + if (hdc[id].bus != HDD_BUS_SCSI_REMOVABLE) + { + scsi_hard_disks[scsi_id][scsi_lun] = 0xff; + } + } + else + { + scsi_disk_insert(id); + } +} + +void scsi_reloadhd(int id) +{ + int ret = 0; + + if(hdc[id].prev_fn == NULL) + { + return; + } + else + { + wcscpy(hdc[id].fn, hdc[id].prev_fn); + memset(hdc[id].prev_fn, 0, sizeof(hdc[id].prev_fn)); + } + + ret = hdd_image_load(id); + + if (ret) + { + scsi_disk_insert(id); + } +} + +void scsi_unloadhd(int scsi_id, int scsi_lun, int id) +{ + hdd_image_unload(id, 1); +} + +void build_scsi_hd_map() +{ + uint8_t i = 0; + uint8_t j = 0; + + for (i = 0; i < 16; i++) + { + memset(scsi_hard_disks[i], 0xff, 8); + } + + for (i = 0; i < 16; i++) + { + for (j = 0; j < 8; j++) + { + scsi_hard_disks[i][j] = find_hdc_for_scsi_id(i, j); + if (scsi_hard_disks[i][j] != 0xff) + { + memset(&(shdc[scsi_hard_disks[i][j]]), 0, sizeof(shdc[scsi_hard_disks[i][j]])); + if (wcslen(hdc[scsi_hard_disks[i][j]].fn) > 0) + { + scsi_loadhd(i, j, scsi_hard_disks[i][j]); + } + } + } + } +} + +int scsi_hd_read_capacity(uint8_t id, uint8_t *cdb, uint8_t *buffer, uint32_t *len) +{ + int size = 0; + + size = hdd_image_get_last_sector(id); + memset(buffer, 0, 8); + buffer[0] = (size >> 24) & 0xff; + buffer[1] = (size >> 16) & 0xff; + buffer[2] = (size >> 8) & 0xff; + buffer[3] = size & 0xff; + buffer[6] = 2; /* 512 = 0x0200 */ + *len = 8; + + return 1; +} + +void scsi_hd_update_request_length(uint8_t id, int len, int block_len) +{ + /* For media access commands, make sure the requested DRQ length matches the block length. */ + switch (shdc[id].current_cdb[0]) + { + case 0x08: + case 0x0a: + case 0x28: + case 0x2a: + case 0xa8: + case 0xaa: + if (shdc[id].request_length < block_len) + { + shdc[id].request_length = block_len; + } + /* Make sure we respect the limit of how many blocks we can transfer at once. */ + if (shdc[id].requested_blocks > shdc[id].max_blocks_at_once) + { + shdc[id].requested_blocks = shdc[id].max_blocks_at_once; + } + shdc[id].block_total = (shdc[id].requested_blocks * block_len); + if (len > shdc[id].block_total) + { + len = shdc[id].block_total; + } + break; + default: + shdc[id].packet_len = len; + break; + } + /* If the DRQ length is odd, and the total remaining length is bigger, make sure it's even. */ + if ((shdc[id].request_length & 1) && (shdc[id].request_length < len)) + { + shdc[id].request_length &= 0xfffe; + } + /* If the DRQ length is smaller or equal in size to the total remaining length, set it to that. */ + if (len <= shdc[id].request_length) + { + shdc[id].request_length = len; + } + return; +} + +static void scsi_hd_command_common(uint8_t id) +{ + shdc[id].status = BUSY_STAT; + shdc[id].phase = 1; + shdc[id].pos = 0; + if (shdc[id].packet_status == CDROM_PHASE_COMPLETE) + { + shdc[id].callback = 20 * SCSI_TIME; + } + else + { + shdc[id].callback = 60 * SCSI_TIME; + } +} + +static void scsi_hd_command_complete(uint8_t id) +{ + shdc[id].packet_status = CDROM_PHASE_COMPLETE; + scsi_hd_command_common(id); +} + +static void scsi_hd_command_read_dma(uint8_t id) +{ + shdc[id].packet_status = CDROM_PHASE_DATA_IN_DMA; + scsi_hd_command_common(id); + shdc[id].total_read = 0; +} + +static void scsi_hd_command_write_dma(uint8_t id) +{ + shdc[id].packet_status = CDROM_PHASE_DATA_OUT_DMA; + scsi_hd_command_common(id); +} + +static void scsi_hd_data_command_finish(uint8_t id, int len, int block_len, int alloc_len, int direction) +{ + scsi_hd_log("SCSI HD %i: Finishing command (%02X): %i, %i, %i, %i, %i\n", id, shdc[id].current_cdb[0], len, block_len, alloc_len, direction, shdc[id].request_length); + shdc[id].pos=0; + if (alloc_len >= 0) + { + if (alloc_len < len) + { + len = alloc_len; + } + } + if (len == 0) + { + SCSIDevices[hdc[id].scsi_id][hdc[id].scsi_lun].InitLength = 0; + scsi_hd_command_complete(id); + } + else + { + if (direction == 0) + { + SCSIDevices[hdc[id].scsi_id][hdc[id].scsi_lun].InitLength = alloc_len; + scsi_hd_command_read_dma(id); + } + else + { + scsi_hd_command_write_dma(id); + } + } + + scsi_hd_log("SCSI HD %i: Status: %i, cylinder %i, packet length: %i, position: %i, phase: %i\n", id, shdc[id].packet_status, shdc[id].request_length, shdc[id].packet_len, shdc[id].pos, shdc[id].phase); +} + +static void scsi_hd_sense_clear(int id, int command) +{ + shdc[id].previous_command = command; + scsi_hd_sense_key = scsi_hd_asc = scsi_hd_ascq = 0; +} + +static void scsi_hd_cmd_error(uint8_t id) +{ + shdc[id].error = ((scsi_hd_sense_key & 0xf) << 4) | ABRT_ERR; + if (shdc[id].unit_attention & 3) + { + shdc[id].error |= MCR_ERR; + } + shdc[id].status = READY_STAT | ERR_STAT; + shdc[id].phase = 3; + shdc[id].packet_status = 0x80; + shdc[id].callback = 50 * SCSI_TIME; + scsi_hd_log("SCSI HD %i: ERROR: %02X/%02X/%02X\n", id, scsi_hd_sense_key, scsi_hd_asc, scsi_hd_ascq); +} + +static void scsi_hd_unit_attention(uint8_t id) +{ + shdc[id].error = (SENSE_NOT_READY << 4) | ABRT_ERR; + if (shdc[id].unit_attention & 3) + { + shdc[id].error |= MCR_ERR; + } + shdc[id].status = READY_STAT | ERR_STAT; + shdc[id].phase = 3; + shdc[id].packet_status = 0x80; + shdc[id].callback = 50 * CDROM_TIME; + scsi_hd_log("SCSI HD %i: UNIT ATTENTION\n", id); +} + +static void scsi_hd_not_ready(uint8_t id) +{ + scsi_hd_sense_key = SENSE_NOT_READY; + scsi_hd_asc = ASC_MEDIUM_NOT_PRESENT; + scsi_hd_ascq = 0; + scsi_hd_cmd_error(id); +} + +static void scsi_hd_write_protected(uint8_t id) +{ + scsi_hd_sense_key = SENSE_UNIT_ATTENTION; + scsi_hd_asc = ASC_WRITE_PROTECTED; + scsi_hd_ascq = 0; + scsi_hd_cmd_error(id); +} + +static void scsi_hd_invalid_lun(uint8_t id) +{ + scsi_hd_sense_key = SENSE_ILLEGAL_REQUEST; + scsi_hd_asc = ASC_INV_LUN; + scsi_hd_ascq = 0; + scsi_hd_cmd_error(id); +} + +static void scsi_hd_illegal_opcode(uint8_t id) +{ + scsi_hd_sense_key = SENSE_ILLEGAL_REQUEST; + scsi_hd_asc = ASC_ILLEGAL_OPCODE; + scsi_hd_ascq = 0; + scsi_hd_cmd_error(id); +} + +static void scsi_hd_lba_out_of_range(uint8_t id) +{ + scsi_hd_sense_key = SENSE_ILLEGAL_REQUEST; + scsi_hd_asc = ASC_LBA_OUT_OF_RANGE; + scsi_hd_ascq = 0; + scsi_hd_cmd_error(id); +} + +static void scsi_hd_invalid_field(uint8_t id) +{ + scsi_hd_sense_key = SENSE_ILLEGAL_REQUEST; + scsi_hd_asc = ASC_INV_FIELD_IN_CMD_PACKET; + scsi_hd_ascq = 0; + scsi_hd_cmd_error(id); + shdc[id].status = 0x53; +} + +static void scsi_hd_data_phase_error(uint8_t id) +{ + scsi_hd_sense_key = SENSE_ILLEGAL_REQUEST; + scsi_hd_asc = ASC_DATA_PHASE_ERROR; + scsi_hd_ascq = 0; + scsi_hd_cmd_error(id); +} + +/*SCSI Sense Initialization*/ +void scsi_hd_sense_code_ok(uint8_t id) +{ + scsi_hd_sense_key = SENSE_NONE; + scsi_hd_asc = 0; + scsi_hd_ascq = 0; +} + +int scsi_hd_pre_execution_check(uint8_t id, uint8_t *cdb) +{ + int ready = 1; + + if (((shdc[id].request_length >> 5) & 7) != hdc[id].scsi_lun) + { + scsi_hd_log("SCSI HD %i: Attempting to execute a unknown command targeted at SCSI LUN %i\n", id, ((shdc[id].request_length >> 5) & 7)); + scsi_hd_invalid_lun(id); + return 0; + } + + if (!(scsi_hd_command_flags[cdb[0]] & IMPLEMENTED)) + { + scsi_hd_log("SCSI HD %i: Attempting to execute unknown command %02X\n", id, cdb[0]); + /* pclog("SCSI HD %i: Attempting to execute unknown command %02X (%02X %02X)\n", id, cdb[0], ((cdb[1] >> 3) & 1) ? 0 : 1, cdb[2] & 0x3F); */ + scsi_hd_illegal_opcode(id); + return 0; + } + + if (hdc[id].bus == HDD_BUS_SCSI_REMOVABLE) + { + /* Removable disk, set ready state. */ + if (wcslen(hdc[id].fn) > 0) + { + ready = 1; + } + else + { + ready = 0; + } + } + else + { + /* Fixed disk, clear UNIT ATTENTION, just in case it might have been set when the disk was removable). */ + shdc[id].unit_attention = 0; + } + + if (!ready && shdc[id].unit_attention) + { + /* If the drive is not ready, there is no reason to keep the + UNIT ATTENTION condition present, as we only use it to mark + disc changes. */ + shdc[id].unit_attention = 0; + } + + /* If the UNIT ATTENTION condition is set and the command does not allow + execution under it, error out and report the condition. */ + if (shdc[id].unit_attention == 1) + { + /* Only increment the unit attention phase if the command can not pass through it. */ + if (!(scsi_hd_command_flags[cdb[0]] & ALLOW_UA)) + { + /* scsi_hd_log("SCSI HD %i: Unit attention now 2\n", id); */ + shdc[id].unit_attention = 2; + scsi_hd_log("SCSI HD %i: UNIT ATTENTION: Command %02X not allowed to pass through\n", id, cdb[0]); + scsi_hd_unit_attention(id); + return 0; + } + } + else if (shdc[id].unit_attention == 2) + { + if (cdb[0] != GPCMD_REQUEST_SENSE) + { + /* scsi_hd_log("SCSI HD %i: Unit attention now 0\n", id); */ + shdc[id].unit_attention = 0; + } + } + + /* Unless the command is REQUEST SENSE, clear the sense. This will *NOT* + the UNIT ATTENTION condition if it's set. */ + if (cdb[0] != GPCMD_REQUEST_SENSE) + { + scsi_hd_sense_clear(id, cdb[0]); + } + + /* Next it's time for NOT READY. */ + if ((scsi_hd_command_flags[cdb[0]] & CHECK_READY) && !ready) + { + scsi_hd_log("SCSI HD %i: Not ready (%02X)\n", id, cdb[0]); + scsi_hd_not_ready(id); + return 0; + } + + scsi_hd_log("SCSI HD %i: Continuing with command\n", id); + + return 1; +} + +static void scsi_hd_seek(uint8_t id, uint32_t pos) +{ + /* scsi_hd_log("SCSI HD %i: Seek %08X\n", id, pos); */ + hdd_image_seek(id, pos); +} + +static void scsi_hd_rezero(uint8_t id) +{ + if (id == 255) + { + return; + } + + shdc[id].sector_pos = shdc[id].sector_len = 0; + scsi_hd_seek(id, 0); +} + +void scsi_hd_reset(uint8_t id) +{ + scsi_hd_rezero(id); + shdc[id].status = 0; + shdc[id].callback = 0; + shdc[id].packet_status = 0xff; +} + +void scsi_hd_request_sense(uint8_t id, uint8_t *buffer, uint8_t alloc_length) +{ + /*Will return 18 bytes of 0*/ + if (alloc_length != 0) + { + memset(buffer, 0, alloc_length); + memcpy(buffer, shdc[id].sense, alloc_length); + } + + buffer[0] = 0x70; + + if (shdc[id].unit_attention && (scsi_hd_sense_key == 0)) + { + buffer[2]=SENSE_UNIT_ATTENTION; + buffer[12]=ASC_MEDIUM_MAY_HAVE_CHANGED; + buffer[13]=0x00; + } + + /* scsi_hd_log("SCSI HD %i: Reporting sense: %02X %02X %02X\n", id, hdbufferb[2], hdbufferb[12], hdbufferb[13]); */ + + if (buffer[2] == SENSE_UNIT_ATTENTION) + { + /* If the last remaining sense is unit attention, clear + that condition. */ + shdc[id].unit_attention = 0; + } + + /* Clear the sense stuff as per the spec. */ + scsi_hd_sense_clear(id, GPCMD_REQUEST_SENSE); +} + +void scsi_hd_request_sense_for_scsi(uint8_t id, uint8_t *buffer, uint8_t alloc_length) +{ + int ready = 1; + + if (hdc[id].bus == HDD_BUS_SCSI_REMOVABLE) + { + /* Removable disk, set ready state. */ + if (wcslen(hdc[id].fn) > 0) + { + ready = 1; + } + else + { + ready = 0; + } + } + else + { + /* Fixed disk, clear UNIT ATTENTION, just in case it might have been set when the disk was removable). */ + shdc[id].unit_attention = 0; + } + + if (!ready && shdc[id].unit_attention) + { + /* If the drive is not ready, there is no reason to keep the + UNIT ATTENTION condition present, as we only use it to mark + disc changes. */ + shdc[id].unit_attention = 0; + } + + /* Do *NOT* advance the unit attention phase. */ + + scsi_hd_request_sense(id, buffer, alloc_length); +} + +void scsi_hd_command(uint8_t id, uint8_t *cdb) +{ + /* uint8_t *hdbufferb = (uint8_t *) shdc[id].buffer; */ + uint8_t *hdbufferb = SCSIDevices[hdc[id].scsi_id][hdc[id].scsi_lun].CmdBuffer; + uint32_t len; + int pos=0; + int max_len; + unsigned idx = 0; + unsigned size_idx; + unsigned preamble_len; + uint32_t alloc_length; + char device_identify[9] = { '8', '6', 'B', '_', 'H', 'D', '0', '0', 0 }; + char device_identify_ex[15] = { '8', '6', 'B', '_', 'H', 'D', '0', '0', ' ', 'v', '1', '.', '0', '0', 0 }; + uint8_t *tempbuffer; + uint32_t last_sector = 0; + +#if 0 + int CdbLength; +#endif + last_sector = hdd_image_get_last_sector(id); + + shdc[id].status &= ~ERR_STAT; + + shdc[id].packet_len = 0; + shdc[id].request_pos = 0; + + device_identify[6] = (id / 10) + 0x30; + device_identify[7] = (id % 10) + 0x30; + + device_identify_ex[6] = (id / 10) + 0x30; + device_identify_ex[7] = (id % 10) + 0x30; + device_identify_ex[10] = EMU_VERSION[0]; + device_identify_ex[12] = EMU_VERSION[2]; + device_identify_ex[13] = EMU_VERSION[3]; + + if (hdc[id].bus == HDD_BUS_SCSI_REMOVABLE) + { + device_identify[4] = 'R'; + + device_identify_ex[4] = 'R'; + } + + shdc[id].data_pos = 0; + + memcpy(shdc[id].current_cdb, cdb, 12); + + if (cdb[0] != 0) + { + scsi_hd_log("SCSI HD %i: Command 0x%02X, Sense Key %02X, Asc %02X, Ascq %02X, %i\n", id, cdb[0], scsi_hd_sense_key, scsi_hd_asc, scsi_hd_ascq, ins); + scsi_hd_log("SCSI HD %i: Request length: %04X\n", id, shdc[id].request_length); + +#if 0 + for (CdbLength = 1; CdbLength < 12; CdbLength++) + { + scsi_hd_log("SCSI HD %i: CDB[%d] = 0x%02X\n", id, CdbLength, cdb[CdbLength]); + } +#endif + } + + shdc[id].sector_len = 0; + + /* This handles the Not Ready/Unit Attention check if it has to be handled at this point. */ + if (scsi_hd_pre_execution_check(id, cdb) == 0) + { + return; + } + + switch (cdb[0]) + { + case GPCMD_TEST_UNIT_READY: + case GPCMD_FORMAT_UNIT: + case GPCMD_VERIFY_6: + case GPCMD_VERIFY_10: + case GPCMD_VERIFY_12: + scsi_hd_command_complete(id); + break; + + case GPCMD_REZERO_UNIT: + shdc[id].sector_pos = shdc[id].sector_len = 0; + scsi_hd_seek(id, 0); + break; + + case GPCMD_REQUEST_SENSE: + /* If there's a unit attention condition and there's a buffered not ready, a standalone REQUEST SENSE + should forget about the not ready, and report unit attention straight away. */ + scsi_hd_request_sense(id, hdbufferb, cdb[4]); + scsi_hd_data_command_finish(id, 18, 18, cdb[4], 0); + break; + + case GPCMD_MECHANISM_STATUS: + len = (hdbufferb[7] << 16) | (hdbufferb[8] << 8) | hdbufferb[9]; + + memset(hdbufferb, 0, 8); + hdbufferb[5] = 1; + + scsi_hd_data_command_finish(id, 8, 8, len, 0); + break; + + case GPCMD_READ_6: + case GPCMD_READ_10: + case GPCMD_READ_12: + switch(cdb[0]) + { + case GPCMD_READ_6: + shdc[id].sector_len = cdb[4]; + shdc[id].sector_pos = ((((uint32_t) cdb[1]) & 0x1f) << 16) | (((uint32_t) cdb[2]) << 8) | ((uint32_t) cdb[3]); + break; + case GPCMD_READ_10: + shdc[id].sector_len = (cdb[7] << 8) | cdb[8]; + shdc[id].sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; + scsi_hd_log("SCSI HD %i: Length: %i, LBA: %i\n", id, shdc[id].sector_len, shdc[id].sector_pos); + break; + case GPCMD_READ_12: + shdc[id].sector_len = (((uint32_t) cdb[6]) << 24) | (((uint32_t) cdb[7]) << 16) | (((uint32_t) cdb[8]) << 8) | ((uint32_t) cdb[9]); + shdc[id].sector_pos = (((uint32_t) cdb[2]) << 24) | (((uint32_t) cdb[3]) << 16) | (((uint32_t) cdb[4]) << 8) | ((uint32_t) cdb[5]); + break; + } + + if ((shdc[id].sector_pos > last_sector) || ((shdc[id].sector_pos + shdc[id].sector_len - 1) > last_sector)) + { + scsi_hd_lba_out_of_range(id); + return; + } + + if ((!shdc[id].sector_len) || (SCSIDevices[hdc[id].scsi_id][hdc[id].scsi_lun].InitLength == 0)) + { + /* scsi_hd_log("SCSI HD %i: All done - callback set\n", id); */ + shdc[id].packet_status = CDROM_PHASE_COMPLETE; + shdc[id].callback = 20 * SCSI_TIME; + break; + } + + max_len = shdc[id].sector_len; + shdc[id].requested_blocks = max_len; + + alloc_length = shdc[id].packet_len = max_len << 9; + + if ((shdc[id].requested_blocks > 0) && (SCSIDevices[hdc[id].scsi_id][hdc[id].scsi_lun].InitLength > 0)) + { + if (alloc_length > SCSIDevices[hdc[id].scsi_id][hdc[id].scsi_lun].InitLength) + { + hdd_image_read(id, shdc[id].sector_pos, SCSIDevices[hdc[id].scsi_id][hdc[id].scsi_lun].InitLength >> 9, hdbufferb); + } + else + { + hdd_image_read(id, shdc[id].sector_pos, max_len, hdbufferb); + } + } + + if (shdc[id].requested_blocks > 1) + { + scsi_hd_data_command_finish(id, alloc_length, alloc_length / shdc[id].requested_blocks, alloc_length, 0); + } + else + { + scsi_hd_data_command_finish(id, alloc_length, alloc_length, alloc_length, 0); + } + shdc[id].all_blocks_total = shdc[id].block_total; + if (shdc[id].packet_status != CDROM_PHASE_COMPLETE) + { + update_status_bar_icon((hdc[id].bus == HDD_BUS_SCSI_REMOVABLE) ? (SB_RDISK | id) : (SB_HDD | HDD_BUS_SCSI), 1); + } + else + { + update_status_bar_icon((hdc[id].bus == HDD_BUS_SCSI_REMOVABLE) ? (SB_RDISK | id) : (SB_HDD | HDD_BUS_SCSI), 0); + } + return; + + case GPCMD_WRITE_6: + case GPCMD_WRITE_10: + case GPCMD_WRITE_12: + if ((hdc[id].bus == HDD_BUS_SCSI_REMOVABLE) && hdc[id].wp) + { + scsi_hd_write_protected(id); + return; + } + + switch(cdb[0]) + { + case GPCMD_WRITE_6: + shdc[id].sector_len = cdb[4]; + shdc[id].sector_pos = ((((uint32_t) cdb[1]) & 0x1f) << 16) | (((uint32_t) cdb[2]) << 8) | ((uint32_t) cdb[3]); + break; + case GPCMD_WRITE_10: + shdc[id].sector_len = (cdb[7] << 8) | cdb[8]; + shdc[id].sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; + scsi_hd_log("SCSI HD %i: Length: %i, LBA: %i\n", id, shdc[id].sector_len, shdc[id].sector_pos); + break; + case GPCMD_WRITE_12: + shdc[id].sector_len = (((uint32_t) cdb[6]) << 24) | (((uint32_t) cdb[7]) << 16) | (((uint32_t) cdb[8]) << 8) | ((uint32_t) cdb[9]); + shdc[id].sector_pos = (((uint32_t) cdb[2]) << 24) | (((uint32_t) cdb[3]) << 16) | (((uint32_t) cdb[4]) << 8) | ((uint32_t) cdb[5]); + break; + } + + if ((shdc[id].sector_pos > last_sector) || ((shdc[id].sector_pos + shdc[id].sector_len - 1) > last_sector)) + { + scsi_hd_lba_out_of_range(id); + return; + } + + if ((!shdc[id].sector_len) || (SCSIDevices[hdc[id].scsi_id][hdc[id].scsi_lun].InitLength == 0)) + { + /* scsi_hd_log("SCSI HD %i: All done - callback set\n", id); */ + shdc[id].packet_status = CDROM_PHASE_COMPLETE; + shdc[id].callback = 20 * SCSI_TIME; + break; + } + + max_len = shdc[id].sector_len; + shdc[id].requested_blocks = max_len; + + alloc_length = shdc[id].packet_len = max_len << 9; + + if ((shdc[id].requested_blocks > 0) && (SCSIDevices[hdc[id].scsi_id][hdc[id].scsi_lun].InitLength > 0)) + { + if (alloc_length > SCSIDevices[hdc[id].scsi_id][hdc[id].scsi_lun].InitLength) + { + hdd_image_write(id, shdc[id].sector_pos, SCSIDevices[hdc[id].scsi_id][hdc[id].scsi_lun].InitLength >> 9, hdbufferb); + } + else + { + hdd_image_write(id, shdc[id].sector_pos, max_len, hdbufferb); + } + } + + if (shdc[id].requested_blocks > 1) + { + scsi_hd_data_command_finish(id, alloc_length, alloc_length / shdc[id].requested_blocks, alloc_length, 1); + } + else + { + scsi_hd_data_command_finish(id, alloc_length, alloc_length, alloc_length, 1); + } + shdc[id].all_blocks_total = shdc[id].block_total; + if (shdc[id].packet_status != CDROM_PHASE_COMPLETE) + { + update_status_bar_icon((hdc[id].bus == HDD_BUS_SCSI_REMOVABLE) ? (SB_RDISK | id) : (SB_HDD | HDD_BUS_SCSI), 1); + } + else + { + update_status_bar_icon((hdc[id].bus == HDD_BUS_SCSI_REMOVABLE) ? (SB_RDISK | id) : (SB_HDD | HDD_BUS_SCSI), 0); + } + return; + + case GPCMD_START_STOP_UNIT: + if (hdc[id].bus != HDD_BUS_SCSI_REMOVABLE) + { + scsi_hd_illegal_opcode(id); + break; + } + + switch(cdb[4] & 3) + { + case 0: /* Stop the disc. */ + case 1: /* Start the disc and read the TOC. */ + break; + case 2: /* Eject the disc if possible. */ + removable_disk_eject(id); + break; + case 3: /* Load the disc (close tray). */ + removable_disk_reload(id); + break; + } + + scsi_hd_command_complete(id); + break; + + case GPCMD_INQUIRY: + max_len = cdb[3]; + max_len <<= 8; + max_len |= cdb[4]; + + if ((!max_len) || (SCSIDevices[hdc[id].scsi_id][hdc[id].scsi_lun].InitLength == 0)) + { + /* scsi_hd_log("SCSI HD %i: All done - callback set\n", id); */ + shdc[id].packet_status = CDROM_PHASE_COMPLETE; + shdc[id].callback = 20 * SCSI_TIME; + break; + } + + tempbuffer = malloc(1024); + + if (cdb[1] & 1) + { + preamble_len = 4; + size_idx = 3; + + tempbuffer[idx++] = 05; + tempbuffer[idx++] = cdb[2]; + tempbuffer[idx++] = 0; + + idx++; + + switch (cdb[2]) + { + case 0x00: + tempbuffer[idx++] = 0x00; + tempbuffer[idx++] = 0x83; + break; + case 0x83: + if (idx + 24 > max_len) + { + scsi_hd_data_phase_error(id); + return; + } + + tempbuffer[idx++] = 0x02; + tempbuffer[idx++] = 0x00; + tempbuffer[idx++] = 0x00; + tempbuffer[idx++] = 20; + ide_padstr8(hdbufferb + idx, 20, "53R141"); /* Serial */ + idx += 20; + + if (idx + 72 > cdb[4]) + { + goto atapi_out; + } + tempbuffer[idx++] = 0x02; + tempbuffer[idx++] = 0x01; + tempbuffer[idx++] = 0x00; + tempbuffer[idx++] = 68; + ide_padstr8(tempbuffer + idx, 8, EMU_NAME); /* Vendor */ + idx += 8; + ide_padstr8(tempbuffer + idx, 40, device_identify_ex); /* Product */ + idx += 40; + ide_padstr8(tempbuffer + idx, 20, "53R141"); /* Product */ + idx += 20; + break; + default: + scsi_hd_log("INQUIRY: Invalid page: %02X\n", cdb[2]); + scsi_hd_invalid_field(id); + return; + } + } + else + { + preamble_len = 5; + size_idx = 4; + + memset(tempbuffer, 0, 8); + tempbuffer[0] = 0; /*SCSI HD*/ + if (hdc[id].bus == HDD_BUS_SCSI_REMOVABLE) + { + tempbuffer[1] = 0x80; /*Removable*/ + } + else + { + tempbuffer[1] = 0; /*Fixed*/ + } + tempbuffer[2] = 0x02; /*SCSI-2 compliant*/ + tempbuffer[3] = 0x02; + tempbuffer[4] = 31; + + ide_padstr8(tempbuffer + 8, 8, EMU_NAME); /* Vendor */ + ide_padstr8(tempbuffer + 16, 16, device_identify); /* Product */ + ide_padstr8(tempbuffer + 32, 4, EMU_VERSION); /* Revision */ + idx = 36; + } + +atapi_out: + tempbuffer[size_idx] = idx - preamble_len; + len=idx; + + if (len > max_len) + { + len = max_len; + } + + if (len > SCSIDevices[hdc[id].scsi_id][hdc[id].scsi_lun].InitLength) + { + len = SCSIDevices[hdc[id].scsi_id][hdc[id].scsi_lun].InitLength; + } + + memcpy(hdbufferb, tempbuffer, len); + + free(tempbuffer); + + scsi_hd_data_command_finish(id, len, len, max_len, 0); + break; + + case GPCMD_PREVENT_REMOVAL: + scsi_hd_command_complete(id); + break; + + case GPCMD_SEEK_6: + case GPCMD_SEEK_10: + switch(cdb[0]) + { + case GPCMD_SEEK_6: + pos = (cdb[2] << 8) | cdb[3]; + break; + case GPCMD_SEEK_10: + pos = (cdb[2] << 24) | (cdb[3]<<16) | (cdb[4]<<8) | cdb[5]; + break; + } + scsi_hd_seek(id, pos); + scsi_hd_command_complete(id); + break; + + case GPCMD_READ_CDROM_CAPACITY: + if (scsi_hd_read_capacity(id, shdc[id].current_cdb, hdbufferb, &len) == 0) + { + return; + } + + scsi_hd_data_command_finish(id, len, len, len, 0); + break; + + default: + /* pclog("SCSI HD %i: Attempting to execute pseudo-implemented command %02X\n", id, cdb[0]); */ + scsi_hd_illegal_opcode(id); + break; + } + + /* scsi_hd_log("SCSI HD %i: Phase: %02X, request length: %i\n", shdc[id].phase, shdc[id].request_length); */ +} + +void scsi_hd_callback(uint8_t id); + +/* If the result is 1, issue an IRQ, otherwise not. */ +void scsi_hd_callback(uint8_t id) +{ + switch(shdc[id].packet_status) + { + case CDROM_PHASE_IDLE: + scsi_hd_log("SCSI HD %i: PHASE_IDLE\n", id); + shdc[id].pos=0; + shdc[id].phase = 1; + shdc[id].status = READY_STAT | DRQ_STAT | (shdc[id].status & ERR_STAT); + return; + case CDROM_PHASE_COMPLETE: + scsi_hd_log("SCSI HD %i: PHASE_COMPLETE\n", id); + shdc[id].status = READY_STAT; + shdc[id].phase = 3; + shdc[id].packet_status = 0xFF; + update_status_bar_icon((hdc[id].bus == HDD_BUS_SCSI_REMOVABLE) ? (SB_RDISK | id) : (SB_HDD | HDD_BUS_SCSI), 0); + return; + case CDROM_PHASE_DATA_OUT: + scsi_hd_log("SCSI HD %i: PHASE_DATA_OUT\n", id); + shdc[id].status = READY_STAT | DRQ_STAT | (shdc[id].status & ERR_STAT); + shdc[id].phase = 0; + return; + case CDROM_PHASE_DATA_OUT_DMA: + scsi_hd_log("SCSI HD %i: PHASE_DATA_OUT_DMA\n", id); + shdc[id].packet_status = CDROM_PHASE_COMPLETE; + shdc[id].status = READY_STAT; + shdc[id].phase = 3; + update_status_bar_icon((hdc[id].bus == HDD_BUS_SCSI_REMOVABLE) ? (SB_RDISK | id) : (SB_HDD | HDD_BUS_SCSI), 0); + return; + case CDROM_PHASE_DATA_IN: + scsi_hd_log("SCSI HD %i: PHASE_DATA_IN\n", id); + shdc[id].status = READY_STAT | DRQ_STAT | (shdc[id].status & ERR_STAT); + shdc[id].phase = 2; + return; + case CDROM_PHASE_DATA_IN_DMA: + scsi_hd_log("SCSI HD %i: PHASE_DATA_IN_DMA\n", id); + shdc[id].packet_status = CDROM_PHASE_COMPLETE; + shdc[id].status = READY_STAT; + shdc[id].phase = 3; + update_status_bar_icon((hdc[id].bus == HDD_BUS_SCSI_REMOVABLE) ? (SB_RDISK | id) : (SB_HDD | HDD_BUS_SCSI), 0); + return; + case CDROM_PHASE_ERROR: + scsi_hd_log("SCSI HD %i: PHASE_ERROR\n", id); + shdc[id].status = READY_STAT | ERR_STAT; + shdc[id].phase = 3; + return; + } +} diff --git a/src/scsi_disk.h b/src/scsi_disk.h new file mode 100644 index 000000000..db3ea9848 --- /dev/null +++ b/src/scsi_disk.h @@ -0,0 +1,54 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * Emulation of SCSI fixed and removable disks. + * + * Version: @(#)scsi_disk.h 1.0.0 2017/05/30 + * + * Author: Miran Grca, + * Copyright 2017-2017 Miran Grca. + */ + +#pragma pack(push,1) +typedef struct { + /* Stuff for SCSI hard disks. */ + uint8_t cdb[16]; + uint8_t current_cdb[16]; + uint8_t max_cdb_len; + int requested_blocks; + int max_blocks_at_once; + uint16_t request_length; + int block_total; + int all_blocks_total; + uint32_t packet_len; + int packet_status; + uint8_t status; + uint8_t phase; + uint32_t pos; + int callback; + int total_read; + int unit_attention; + uint8_t sense[256]; + uint8_t previous_command; + uint8_t error; + uint32_t sector_pos; + uint32_t sector_len; + uint32_t seek_pos; + int data_pos; + int old_len; + int request_pos; + uint8_t hd_cdb[16]; +} scsi_hard_disk_t; +#pragma pack(pop) + +extern scsi_hard_disk_t shdc[HDC_NUM]; + +extern void scsi_disk_insert(uint8_t id); +extern void scsi_loadhd(int scsi_id, int scsi_lun, int id); +extern void scsi_reloadhd(int id); +extern void scsi_unloadhd(int scsi_id, int scsi_lun, int id); + +extern FILE *shdf[HDC_NUM]; diff --git a/src/serial.c b/src/serial.c index 3c386e035..ad200a9ba 100644 --- a/src/serial.c +++ b/src/serial.c @@ -1,303 +1,645 @@ -/* Copyright holders: Sarah Walker - see COPYING for more details -*/ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Implementation of NS8250-series UART devices. + * + * The original IBM-PC design did not have any serial ports of + * any kind. Rather, these were offered as add-on devices, most + * likely because a) most people did not need one at the time, + * and, b) this way, IBM could make more money off them. + * + * So, for the PC, the offerings were for an IBM Asynchronous + * Communications Adapter, and, later, a model for synchronous + * communications. + * + * The "Async Adapter" was based on the NS8250 UART chip, and + * is what we now call the "serial" or "com" port of the PC. + * + * Of course, many system builders came up with similar boards, + * and even more boards were designed where several I/O functions + * were combined into a single board: the Multi-I/O adapters. + * Initially, these had all the chips as-is, but later many of + * these functions were integrated into a single MIO chip. + * + * This file implements the standard NS8250 series of chips, with + * support for the later (16450 and 16550) FIFO additions. On the + * lower half of the driver, we interface to the host system's + * serial ports for real-world access. + * + * **NOTE** TEMPORARY VERSION, DO NOT UPDATE/CHANGE !! + * + * Based on the 86Box serial port driver as a framework. + * + * Version: @(#)serial.c 1.0.8 2017/06/18 + * + * Author: Fred N. van Kempen, + * Copyright 2017 Fred N. van Kempen. + */ +#include #include "ibm.h" #include "io.h" -#include "mouse.h" #include "pic.h" -#include "serial.h" #include "timer.h" +#include "serial.h" +#include "plat_serial.h" -enum -{ - SERIAL_INT_LSR = 1, - SERIAL_INT_RECEIVE = 2, - SERIAL_INT_TRANSMIT = 4, - SERIAL_INT_MSR = 8 + +#define NUM_SERIAL 2 /* we support 2 ports */ + + +enum { + SERINT_LSR = 1, + SERINT_RECEIVE = 2, + SERINT_TRANSMIT = 4, + SERINT_MSR = 8 }; -SERIAL serial1, serial2; -void serial_reset() +/* IER register bits. */ +#define IER_RDAIE (0x01) +#define IER_THREIE (0x02) +#define IER_RXLSIE (0x04) +#define IER_MSIE (0x08) +#define IER_SLEEP (0x10) /* NS16750 */ +#define IER_LOWPOWER (0x20) /* NS16750 */ +#define IER_MASK (0x0f) /* not including SLEEP|LOWP */ + +/* IIR register bits. */ +#define IIR_IP (0x01) +#define IIR_IID (0x0e) +# define IID_IDMDM (0x00) +# define IID_IDTX (0x02) +# define IID_IDRX (0x04) +# define IID_IDERR (0x06) +# define IID_IDTMO (0x0c) +#define IIR_IIRFE (0xc0) +# define IIR_FIFO64 (0x20) +# define IIR_FIFOBAD (0x80) /* 16550 */ +# define IIR_FIFOENB (0xc0) + +/* FCR register bits. */ +#define FCR_FCRFE (0x01) +#define FCR_RFR (0x02) +#define FCR_TFR (0x04) +#define FCR_SELDMA1 (0x08) +#define FCR_FENB64 (0x20) /* 16750 */ +#define FCR_RTLS (0xc0) +# define FCR_RTLS1 (0x00) +# define FCR_RTLS4 (0x40) +# define FCR_RTLS8 (0x80) +# define FCR_RTLS14 (0xc0) + +/* LCR register bits. */ +#define LCR_WLS (0x03) +# define WLS_BITS5 (0x00) +# define WLS_BITS6 (0x01) +# define WLS_BITS7 (0x02) +# define WLS_BITS8 (0x03) +#define LCR_SBS (0x04) +#define LCR_PE (0x08) +#define LCR_EP (0x10) +#define LCR_PS (0x20) +# define PAR_NONE (0x00) +# define PAR_EVEN (LCR_PE | LCR_EP) +# define PAR_ODD (LCR_PE) +# define PAR_MARK (LCR_PE | LCR_PS) +# define PAR_SPACE (LCR_PE | LCR_PS | LCR_EP) +#define LCR_BC (0x40) +#define LCR_DLAB (0x80) + +/* MCR register bits. */ +#define MCR_DTR (0x01) +#define MCR_RTS (0x02) +#define MCR_OUT1 (0x04) /* 8250 */ +#define MCR_OUT2 (0x08) /* 8250, INTEN on IBM-PC */ +#define MCR_LMS (0x10) +#define MCR_AUTOFLOW (0x20) /* 16750 */ + +/* LSR register bits. */ +#define LSR_DR (0x01) +#define LSR_OE (0x02) +#define LSR_PE (0x04) +#define LSR_FE (0x08) +#define LSR_BI (0x10) +#define LSR_THRE (0x20) +#define LSR_TEMT (0x40) +#define LSR_RXFE (0x80) + +/* MSR register bits. */ +#define MSR_DCTS (0x01) +#define MSR_DDSR (0x02) +#define MSR_TERI (0x04) +#define MSR_DDCD (0x08) +#define MSR_CTS (0x10) +#define MSR_DSR (0x20) +#define MSR_RI (0x40) +#define MSR_DCD (0x80) +#define MSR_MASK (0x0f) + + +static SERIAL ports[NUM_SERIAL]; /* serial port data */ + int serial_do_log; + + +static void +serial_log(int lvl, const char *fmt, ...) { - serial1.iir = serial1.ier = serial1.lcr = 0; - serial2.iir = serial2.ier = serial2.lcr = 0; - serial1.fifo_read = serial1.fifo_write = 0; - serial2.fifo_read = serial2.fifo_write = 0; +#ifdef ENABLE_SERIAL_LOG + va_list ap; + + if (serial_do_log >= lvl) { + va_start(ap, fmt); + vprintf(fmt, ap); + va_end(ap); + fflush(stdout); + } +#endif } -void serial_update_ints(SERIAL *serial) + +static void +update_ints(SERIAL *sp) { - int stat = 0; + int stat = 0; - serial->iir = 1; + sp->iir = IIR_IP; + if ((sp->ier & IER_RXLSIE) && (sp->int_status & SERINT_LSR)) { + /* Line Status interrupt. */ + stat = 1; + sp->iir = IID_IDERR; + } else if ((sp->ier & IER_RDAIE) && (sp->int_status & SERINT_RECEIVE)) { + /* Received Data available. */ + stat = 1; + sp->iir = IID_IDRX; + } else if ((sp->ier & IER_THREIE) && (sp->int_status & SERINT_TRANSMIT)) { + /* Transmit Data empty. */ + stat = 1; + sp->iir = IID_IDTX; + } else if ((sp->ier & IER_MSIE) && (sp->int_status & SERINT_MSR)) { + /* Modem Status interrupt. */ + stat = 1; + sp->iir = IID_IDMDM; + } - if ((serial->ier & 4) && (serial->int_status & SERIAL_INT_LSR)) /*Line status interrupt*/ - { - stat = 1; - serial->iir = 6; - } - else if ((serial->ier & 1) && (serial->int_status & SERIAL_INT_RECEIVE)) /*Recieved data available*/ - { - stat = 1; - serial->iir = 4; - } - else if ((serial->ier & 2) && (serial->int_status & SERIAL_INT_TRANSMIT)) /*Transmit data empty*/ - { - stat = 1; - serial->iir = 2; - } - else if ((serial->ier & 8) && (serial->int_status & SERIAL_INT_MSR)) /*Modem status interrupt*/ - { - stat = 1; - serial->iir = 0; - } - - if (stat && ((serial->mctrl & 8) || PCJR)) - picintlevel(1 << serial->irq); - else - picintc(1 << serial->irq); + /* Raise or clear the level-based IRQ. */ + if (stat && ((sp->mctrl & MCR_OUT2) || PCJR)) + picintlevel(1 << sp->irq); + else + picintc(1 << sp->irq); } -void serial_write_fifo(SERIAL *serial, uint8_t dat) + +/* Fake interrupt generator, needed for Serial Mouse. */ +static void +serial_timer(void *priv) { -// pclog("serial_write_fifo %02X\n", serial->lsr); - serial->fifo[serial->fifo_write] = dat; - serial->fifo_write = (serial->fifo_write + 1) & 0xFF; - if (!(serial->lsr & 1)) - { - serial->lsr |= 1; - serial->int_status |= SERIAL_INT_RECEIVE; - serial_update_ints(serial); - } + SERIAL *sp = (SERIAL *)priv; + + sp->receive_delay = 0; + + if (sp->fifo_read != sp->fifo_write) { + sp->lsr |= LSR_DR; + sp->int_status |= SERINT_RECEIVE; + update_ints(sp); + } } -uint8_t serial_read_fifo(SERIAL *serial) + +/* Write data to the (input) FIFO. Used by MOUSE driver. */ +void +serial_write_fifo(SERIAL *sp, uint8_t dat, int flag) { - if (serial->fifo_read != serial->fifo_write) - { - serial->dat = serial->fifo[serial->fifo_read]; - serial->fifo_read = (serial->fifo_read + 1) & 0xFF; - } - return serial->dat; + /* Stuff data into FIFO. */ + sp->fifo[sp->fifo_write] = dat; + sp->fifo_write = (sp->fifo_write + 1) & 0xFF; + + if (! (sp->lsr & LSR_DR)) { + sp->lsr |= LSR_DR; + sp->int_status |= SERINT_RECEIVE; + update_ints(sp); + } } -void serial_write(uint16_t addr, uint8_t val, void *p) + +static uint8_t +read_fifo(SERIAL *sp) { - SERIAL *serial = (SERIAL *)p; -// pclog("Write serial %03X %02X %04X:%04X\n",addr,val,CS,pc); - switch (addr&7) - { - case 0: - if (serial->lcr & 0x80) - { - serial->dlab1 = val; - return; - } - serial->thr = val; - serial->lsr |= 0x20; - serial->int_status |= SERIAL_INT_TRANSMIT; - serial_update_ints(serial); - if (serial->mctrl & 0x10) - { - serial_write_fifo(serial, val); - } - break; - case 1: - if (serial->lcr & 0x80) - { - serial->dlab2 = val; - return; - } - serial->ier = val & 0xf; - serial_update_ints(serial); - break; - case 3: - serial->lcr = val; - break; - case 4: - if ((val & 2) && !(serial->mctrl & 2)) - { - if (serial->rcr_callback) - serial->rcr_callback(serial, serial->rcr_callback_p); -// pclog("RCR raised! sending M\n"); - } - serial->mctrl = val; - if (val & 0x10) - { - uint8_t new_msr; - - new_msr = (val & 0x0c) << 4; - new_msr |= (val & 0x02) ? 0x10: 0; - new_msr |= (val & 0x01) ? 0x20: 0; - - if ((serial->msr ^ new_msr) & 0x10) - new_msr |= 0x01; - if ((serial->msr ^ new_msr) & 0x20) - new_msr |= 0x02; - if ((serial->msr ^ new_msr) & 0x80) - new_msr |= 0x08; - if ((serial->msr & 0x40) && !(new_msr & 0x40)) - new_msr |= 0x04; - - serial->msr = new_msr; - } - break; - case 5: - serial->lsr = val; - if (serial->lsr & 0x01) - serial->int_status |= SERIAL_INT_RECEIVE; - if (serial->lsr & 0x1e) - serial->int_status |= SERIAL_INT_LSR; - if (serial->lsr & 0x20) - serial->int_status |= SERIAL_INT_TRANSMIT; - serial_update_ints(serial); - break; - case 6: - serial->msr = val; - if (serial->msr & 0x0f) - serial->int_status |= SERIAL_INT_MSR; - serial_update_ints(serial); - break; - case 7: - serial->scratch = val; - break; - } + if (sp->fifo_read != sp->fifo_write) { + sp->dat = sp->fifo[sp->fifo_read]; + sp->fifo_read = (sp->fifo_read + 1) & 0xFF; + } + + return(sp->dat); } -uint8_t serial_read(uint16_t addr, void *p) -{ - SERIAL *serial = (SERIAL *)p; - uint8_t temp = 0; -// pclog("Read serial %03X %04X(%08X):%04X %i %i ", addr, CS, cs, pc, mousedelay, ins); - switch (addr&7) - { - case 0: - if (serial->lcr & 0x80) - { - temp = serial->dlab1; - break; - } - serial->lsr &= ~1; - serial->int_status &= ~SERIAL_INT_RECEIVE; - serial_update_ints(serial); - temp = serial_read_fifo(serial); - if (serial->fifo_read != serial->fifo_write) - serial->recieve_delay = 1000 * TIMER_USEC; - break; - case 1: - if (serial->lcr & 0x80) - temp = serial->dlab2; - else - temp = serial->ier; - break; - case 2: - temp = serial->iir; - if ((temp & 0xe) == 2) - { - serial->int_status &= ~SERIAL_INT_TRANSMIT; - serial_update_ints(serial); - } - break; - case 3: - temp = serial->lcr; - break; - case 4: - temp = serial->mctrl; - break; - case 5: - if (serial->lsr & 0x20) - serial->lsr |= 0x40; - serial->lsr |= 0x20; - temp = serial->lsr; - if (serial->lsr & 0x1f) - serial->lsr &= ~0x1e; -// serial.lsr |= 0x60; - serial->int_status &= ~SERIAL_INT_LSR; - serial_update_ints(serial); - break; - case 6: - temp = serial->msr; - serial->msr &= ~0x0f; - serial->int_status &= ~SERIAL_INT_MSR; - serial_update_ints(serial); - break; - case 7: - temp = serial->scratch; - break; - } -// pclog("%02X\n",temp); - return temp; +/* Handle a WRITE operation to one of our registers. */ +static void +serial_write(uint16_t addr, uint8_t val, void *priv) +{ + SERIAL *sp = (SERIAL *)priv; + uint8_t wl, sb, pa; + uint16_t baud; + long speed; + +#if ENABLE_SERIAL_LOG + serial_log(2, "Serial%d: write(%04x, %02x)\n", sp->port, addr, val); +#endif + switch (addr & 0x07) { + case 0: /* DATA / DLAB1 */ + if (sp->lcr & LCR_DLAB) { + sp->dlab1 = val; + return; + } + sp->thr = val; + if (sp->bh != NULL) { + /* We are linked, so send to BH layer. */ + bhtty_write((BHTTY *)sp->bh, sp->thr); + + /* The WRITE completed, we are ready for more. */ + sp->lsr |= LSR_THRE; + sp->int_status |= SERINT_TRANSMIT; + update_ints(sp); + } else { + /* Not linked. Just fake LOOPBACK mode. */ + if (! (sp->mctrl & MCR_LMS)) + serial_write_fifo(sp, val, 1); + } + + if (sp->mctrl & MCR_LMS) { + /* Echo data back to RX. */ + serial_write_fifo(sp, val, 1); + } + break; + + case 1: /* IER / DLAB2 */ + if (sp->lcr & LCR_DLAB) { + sp->dlab2 = val; + return; + } + sp->ier = (val & IER_MASK); + update_ints(sp); + break; + + case 2: /* FCR */ + sp->fcr = val; + break; + + case 3: /* LCR */ + if ((sp->lcr & LCR_DLAB) && !(val & LCR_DLAB)) { + /* We dropped DLAB, so handle baudrate. */ + baud = ((sp->dlab2<<8) | sp->dlab1); + if (baud > 0) { + speed = 115200UL/baud; + serial_log(2, "Serial%d: divisor %u, baudrate %ld\n", + sp->port, baud, speed); + if ((sp->bh != NULL) && (speed > 0)) + bhtty_speed((BHTTY *)sp->bh, speed); + } else { + serial_log(1, "Serial%d: divisor %u invalid!\n", + sp->port, baud); + } + } + wl = (val & LCR_WLS) + 5; /* databits */ + sb = (val & LCR_SBS) ? 2 : 1; /* stopbits */ + pa = (val & (LCR_PE|LCR_EP|LCR_PS)) >> 3; + serial_log(2, "Serial%d: WL=%d SB=%d PA=%d\n", sp->port, wl, sb, pa); + if (sp->bh != NULL) + bhtty_params((BHTTY *)sp->bh, wl, pa, sb); + sp->lcr = val; + break; + + case 4: + if ((val & MCR_RTS) && !(sp->mctrl & MCR_RTS)) { + /* + * This is old code for use by the Serial Mouse + * driver. If the user toggles RTS, serial mice + * are expected to send an ID, to inform any + * enumerator there 'is' something. + */ + if (sp->rts_callback) { + sp->rts_callback(sp->rts_callback_p); + serial_log(1, "RTS raised; sending ID\n"); + } + } + + if ((val & MCR_OUT2) && !(sp->mctrl & MCR_OUT2)) { + if (sp->bh != NULL) { + /* Linked, start host port. */ + (void)bhtty_active(sp->bh, 1); + } else { + /* Not linked, start RX timer. */ + timer_add(serial_timer, + &sp->receive_delay, + &sp->receive_delay, sp); + + /* Fake CTS, DSR and DCD (for now.) */ + sp->msr = (MSR_CTS | MSR_DCTS | + MSR_DSR | MSR_DDSR | + MSR_DCD | MSR_DDCD); + sp->int_status |= SERINT_MSR; + update_ints(sp); + } + } + sp->mctrl = val; + if (val & MCR_LMS) { /* loopback mode */ + uint8_t new_msr; + + /*FIXME: WTF does this do?? --FvK */ + new_msr = (val & 0x0c) << 4; + new_msr |= (val & MCR_RTS) ? MCR_LMS : 0; + new_msr |= (val & MCR_DTR) ? MCR_AUTOFLOW : 0; + + if ((sp->msr ^ new_msr) & 0x10) + new_msr |= MCR_DTR; + if ((sp->msr ^ new_msr) & 0x20) + new_msr |= MCR_RTS; + if ((sp->msr ^ new_msr) & 0x80) + new_msr |= 0x08; + if ((sp->msr & 0x40) && !(new_msr & 0x40)) + new_msr |= 0x04; + + sp->msr = new_msr; + } + break; + + case 5: + sp->lsr = val; + if (sp->lsr & LSR_DR) + sp->int_status |= SERINT_RECEIVE; + if (sp->lsr & 0x1e) + sp->int_status |= SERINT_LSR; + if (sp->lsr & LSR_THRE) + sp->int_status |= SERINT_TRANSMIT; + update_ints(sp); + break; + + case 6: + sp->msr = val; + if (sp->msr & MSR_MASK) + sp->int_status |= SERINT_MSR; + update_ints(sp); + break; + + case 7: + sp->scratch = val; + break; + } } -void serial_recieve_callback(void *p) + +/* BHTTY READ COMPLETE handler. */ +static void +serial_rd_done(void *arg, int num) { - SERIAL *serial = (SERIAL *)p; - - serial->recieve_delay = 0; - - if (serial->fifo_read != serial->fifo_write) - { - serial->lsr |= 1; - serial->int_status |= SERIAL_INT_RECEIVE; - serial_update_ints(serial); - } + SERIAL *sp = (SERIAL *)arg; + + /* We can do at least 'num' bytes.. */ + while (num-- > 0) { + /* Get a byte from them. */ + if (bhtty_read(sp->bh, &sp->hold, 1) < 0) break; + + /* Stuff it into the FIFO and set intr. */ + serial_write_fifo(sp, sp->hold, 1); + } } -/*Tandy might need COM1 at 2f8*/ -void serial1_init(uint16_t addr, int irq) + +/* Handle a READ operation from one of our registers. */ +static uint8_t +serial_read(uint16_t addr, void *priv) { - memset(&serial1, 0, sizeof(serial1)); - io_sethandler(addr, 0x0008, serial_read, NULL, NULL, serial_write, NULL, NULL, &serial1); - serial1.irq = irq; - serial1.rcr_callback = NULL; - timer_add(serial_recieve_callback, &serial1.recieve_delay, &serial1.recieve_delay, &serial1); -} -void serial1_set(uint16_t addr, int irq) -{ - serial1_remove(); - io_sethandler(addr, 0x0008, serial_read, NULL, NULL, serial_write, NULL, NULL, &serial1); - serial1.irq = irq; - // pclog("serial1_set(%04X, %02X)\n", addr, irq); -} -void serial1_remove() -{ - io_removehandler(0x208, 0x0008, serial_read, NULL, NULL, serial_write, NULL, NULL, &serial1); - io_removehandler(0x228, 0x0008, serial_read, NULL, NULL, serial_write, NULL, NULL, &serial1); - io_removehandler(0x238, 0x0008, serial_read, NULL, NULL, serial_write, NULL, NULL, &serial1); - io_removehandler(0x2e0, 0x0008, serial_read, NULL, NULL, serial_write, NULL, NULL, &serial1); - io_removehandler(0x2e8, 0x0008, serial_read, NULL, NULL, serial_write, NULL, NULL, &serial1); - io_removehandler(0x2f8, 0x0008, serial_read, NULL, NULL, serial_write, NULL, NULL, &serial1); - io_removehandler(0x338, 0x0008, serial_read, NULL, NULL, serial_write, NULL, NULL, &serial1); - io_removehandler(0x3e8, 0x0008, serial_read, NULL, NULL, serial_write, NULL, NULL, &serial1); - io_removehandler(0x3f8, 0x0008, serial_read, NULL, NULL, serial_write, NULL, NULL, &serial1); + SERIAL *sp = (SERIAL *)priv; + uint8_t ret = 0x00; + + switch (addr&0x07) { + case 0: /* DATA / DLAB1 */ + if (sp->lcr & LCR_DLAB) { + ret = sp->dlab1; + } else { + sp->lsr &= ~LSR_DR; + sp->int_status &= ~SERINT_RECEIVE; + update_ints(sp); + ret = read_fifo(sp); + if ((sp->bh == NULL) && + (sp->fifo_read != sp->fifo_write)) + sp->receive_delay = 1000 * TIMER_USEC; + } + break; + + case 1: /* LCR / DLAB2 */ + ret = (sp->lcr & LCR_DLAB) ? sp->dlab2 : sp->ier; + break; + + case 2: /* IIR */ + ret = sp->iir; + if ((ret & IIR_IID) == IID_IDTX) { + sp->int_status &= ~SERINT_TRANSMIT; + update_ints(sp); + } + if (sp->fcr & 0x01) + ret |= 0xc0; + break; + + case 3: /* LCR */ + ret = sp->lcr; + break; + + case 4: /* MCR */ + ret = sp->mctrl; + break; + + case 5: /* LSR */ + if (sp->lsr & LSR_THRE) + sp->lsr |= LSR_TEMT; + sp->lsr |= LSR_THRE; + ret = sp->lsr; + if (sp->lsr & 0x1f) + sp->lsr &= ~0x1e; +#if 0 + sp->lsr |= (LSR_THRE | LSR_TEMT); +#endif + sp->int_status &= ~SERINT_LSR; + update_ints(sp); + break; + + case 6: + ret = sp->msr; + sp->msr &= ~0x0f; + sp->int_status &= ~SERINT_MSR; + update_ints(sp); + break; + + case 7: + ret = sp->scratch; + break; + } + + return(ret); } -void serial2_init(uint16_t addr, int irq) + +/* Set up a serial port for use. */ +void +serial_setup(int port, uint16_t addr, int irq) { - memset(&serial2, 0, sizeof(serial2)); - io_sethandler(addr, 0x0008, serial_read, NULL, NULL, serial_write, NULL, NULL, &serial2); - serial2.irq = irq; - serial2.rcr_callback = NULL; - timer_add(serial_recieve_callback, &serial2.recieve_delay, &serial2.recieve_delay, &serial2); + SERIAL *sp; + + serial_log(0, "Serial%d: I/O=%04x, IRQ=%d\n", port, addr, irq); + + /* Grab the desired port block. */ + sp = &ports[port-1]; + + /* Set up the basic info. */ + if (sp->addr != 0x0000) { + /* Unlink the previous handler. Just in case. */ + io_removehandler(sp->addr, 8, + serial_read, NULL, NULL, serial_write, NULL, NULL, sp); + } + sp->addr = addr; + sp->irq = irq; + + /* Request an I/O range. */ + io_sethandler(sp->addr, 8, + serial_read, NULL, NULL, serial_write, NULL, NULL, sp); } -void serial2_set(uint16_t addr, int irq) + + +/* Release all resources held by a serial port. */ +void +serial_remove(int port) { - serial2_remove(); - io_sethandler(addr, 0x0008, serial_read, NULL, NULL, serial_write, NULL, NULL, &serial2); - serial2.irq = irq; - // pclog("serial2_set(%04X, %02X)\n", addr, irq); + SERIAL *sp; + + /* Grab the desired port block. */ + sp = &ports[port-1]; + + // FIXME: stop timer, if enabled! + + /* Close the host device. */ + if (sp->bh != NULL) + (void)serial_link(port, NULL); + + /* Release our I/O range. */ + if (sp->addr != 0x0000) { + io_removehandler(sp->addr, 8, + serial_read, NULL, NULL, serial_write, NULL, NULL, sp); + } + sp->addr = 0x0000; + sp->irq = 0; } -void serial2_remove() + + +/* Initialize the serial ports. */ +void +serial_init(void) { - io_removehandler(0x208, 0x0008, serial_read, NULL, NULL, serial_write, NULL, NULL, &serial2); - io_removehandler(0x228, 0x0008, serial_read, NULL, NULL, serial_write, NULL, NULL, &serial2); - io_removehandler(0x238, 0x0008, serial_read, NULL, NULL, serial_write, NULL, NULL, &serial2); - io_removehandler(0x2e0, 0x0008, serial_read, NULL, NULL, serial_write, NULL, NULL, &serial2); - io_removehandler(0x2e8, 0x0008, serial_read, NULL, NULL, serial_write, NULL, NULL, &serial2); - io_removehandler(0x2f8, 0x0008, serial_read, NULL, NULL, serial_write, NULL, NULL, &serial2); - io_removehandler(0x338, 0x0008, serial_read, NULL, NULL, serial_write, NULL, NULL, &serial2); - io_removehandler(0x3e8, 0x0008, serial_read, NULL, NULL, serial_write, NULL, NULL, &serial2); - io_removehandler(0x3f8, 0x0008, serial_read, NULL, NULL, serial_write, NULL, NULL, &serial2); + SERIAL *sp; + int i; + +#if ENABLE_SERIAL_LOG + serial_do_log = ENABLE_SERIAL_LOG; +#endif + + /* FIXME: we should probably initialize the platform module here. */ + + /* Initialize each port. */ + for (i=0; iport = (i+1); + + if (i == 0) + serial_setup(sp->port, SERIAL1_ADDR, SERIAL1_IRQ); + else + serial_setup(sp->port, SERIAL2_ADDR, SERIAL2_IRQ); + } + +#ifdef WALTJE + /* Link to host port. */ + serial_link(2, "COM2"); +#endif +} + + +/* + * Reset the serial ports. + * + * This should be a per-port function. + */ +void +serial_reset(void) +{ + SERIAL *sp; + int i; + + for (i=0; iiir = sp->ier = sp->lcr = sp->mctrl = 0x00; + sp->fifo_read = sp->fifo_write = 0x00; + } +} + + +/* Link a serial port to a host (serial) port. */ +int +serial_link(int port, char *arg) +{ + SERIAL *sp; + BHTTY *bh; + + /* Grab the desired port block. */ + sp = &ports[port-1]; + + if (arg != NULL) { + /* Make sure we're not already linked. */ + if (sp->bh != NULL) { + serial_log(0, "Serial%d already linked!\n", port); + return(-1); + } + + /* Request a port from the host system. */ + bh = bhtty_open(arg, 0); + if (bh == NULL) { + serial_log(0, "Serial%d unable to link to '%s' !\n", port, arg); + return(-1); + } + sp->bh = bh; + + /* Set up bottom-half I/O callback info. */ + bh->rd_done = serial_rd_done; + bh->rd_arg = sp; + } else { + /* If we are linked, unlink it. */ + if (sp->bh != NULL) { + bhtty_close((BHTTY *)sp->bh); + sp->bh = NULL; + } + + } + + return(0); +} + + +/* Attach another device (MOUSE) to a serial port. */ +SERIAL * +serial_attach(int port, void *func, void *arg) +{ + SERIAL *sp; + + /* Grab the desired port block. */ + sp = &ports[port-1]; + + /* Set up callback info. */ + sp->rts_callback = func; + sp->rts_callback_p = arg; + + return(sp); } diff --git a/src/serial.h b/src/serial.h index 0e5995706..fec2d2b5c 100644 --- a/src/serial.h +++ b/src/serial.h @@ -1,32 +1,75 @@ -/* Copyright holders: Sarah Walker - see COPYING for more details -*/ -void serial1_init(uint16_t addr, int irq); -void serial2_init(uint16_t addr, int irq); -void serial1_set(uint16_t addr, int irq); -void serial2_set(uint16_t addr, int irq); -void serial1_remove(); -void serial2_remove(); -void serial_reset(); +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Definitions for the SERIAL card. + * + * Version: @(#)serial.h 1.0.6 2017/06/17 + * + * Author: Fred N. van Kempen, + * Copyright 2017 Fred N. van Kempen. + */ +#ifndef EMU_SERIAL_H +# define EMU_SERIAL_H -struct SERIAL; -typedef struct -{ - uint8_t lsr,thr,mctrl,rcr,iir,ier,lcr,msr; - uint8_t dlab1,dlab2; - uint8_t dat; - uint8_t int_status; - uint8_t scratch; - - int irq; +/* Default settings for the standard ports. */ +#define SERIAL1_ADDR 0x03f8 +#define SERIAL1_IRQ 4 +#define SERIAL2_ADDR 0x02f8 +#define SERIAL2_IRQ 3 - void (*rcr_callback)(struct SERIAL *serial, void *p); - void *rcr_callback_p; - uint8_t fifo[256]; - int fifo_read, fifo_write; - - int recieve_delay; + +/* Supported UART types. */ +#define UART_TYPE_8250 0 /* standard NS8250 */ +#define UART_TYPE_8250A 1 /* updated NS8250(A) */ +#define UART_TYPE_16450 2 /* 16450 */ +#define UART_TYPE_16550 3 /* 16550 (broken fifo) */ +#define UART_TYPE_16550A 4 /* 16550a (working fifo) */ +#define UART_TYPE_16670 5 /* 16670 (64b fifo) */ + + +typedef struct _serial_ { + int8_t port; /* port number (1,2,..) */ + int8_t irq; /* IRQ channel used */ + uint16_t addr; /* I/O address used */ + int8_t type; /* UART type */ + uint8_t int_status; + + uint8_t lsr, thr, mctrl, rcr, /* UART registers */ + iir, ier, lcr, msr; + uint8_t dlab1, dlab2; + uint8_t dat, + hold; + uint8_t scratch; + uint8_t fcr; + + /* Data for the RTS-toggle callback. */ + void (*rts_callback)(void *); + void *rts_callback_p; + + uint8_t fifo[256]; + int fifo_read, fifo_write; + + int receive_delay; + + void *bh; /* BottomHalf handler */ } SERIAL; -extern SERIAL serial1, serial2; + +/* Functions. */ +extern void serial_init(void); +extern void serial_reset(void); +extern void serial_setup(int port, uint16_t addr, int irq); +extern void serial_remove(int port); +extern SERIAL *serial_attach(int, void *, void *); +extern int serial_link(int, char *); + +extern void serial_write_fifo(SERIAL *, uint8_t, int); + + +#endif /*EMU_SERIAL_H*/ diff --git a/src/sio.c b/src/sio.c index a808aeb7b..17e278fc4 100644 --- a/src/sio.c +++ b/src/sio.c @@ -1,14 +1,27 @@ -/* Copyright holders: Tenshi - see COPYING for more details -*/ -/*PRD format : - - word 0 - base address - word 1 - bits 1 - 15 = byte count, bit 31 = end of transfer -*/ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * Emulation of Intel System I/O PCI chip. + * + * Version: @(#)sio.c 1.0.1 2017/06/02 + * + * Author: Sarah Walker, + * Miran Grca, + * Copyright 2008-2017 Sarah Walker. + * Copyright 2016-2017 Miran Grca. + */ + #include #include "ibm.h" +#include "cdrom.h" +#include "disc.h" +#include "dma.h" +#include "fdc.h" +#include "keyboard_at.h" #include "ide.h" #include "io.h" #include "mem.h" @@ -20,133 +33,211 @@ static uint8_t card_sio[256]; void sio_write(int func, int addr, uint8_t val, void *priv) { -// pclog("sio_write: func=%d addr=%02x val=%02x %04x:%08x\n", func, addr, val, CS, pc); - - if ((addr & 0xff) < 4) return; - if (func > 0) - return; + return; - if (func == 0) + if (addr >= 0x0f && addr < 0x4c) + return; + + switch (addr) { - switch (addr) - { - case 0x00: case 0x01: case 0x02: case 0x03: - case 0x08: case 0x09: case 0x0a: case 0x0b: - case 0x0e: - return; - } - card_sio[addr] = val; - if (addr == 0x40) - { - if (!((val ^ card_sio[addr]) & 0x40)) - { - return; - } + case 0x00: case 0x01: case 0x02: case 0x03: + case 0x08: case 0x09: case 0x0a: case 0x0b: + case 0x0e: + return; + + case 0x04: /*Command register*/ + val &= 0x08; + val |= 0x07; + break; + case 0x05: + val = 0; + break; + + case 0x06: /*Status*/ + val = 0; + break; + case 0x07: + val = 0x02; + break; - if (val & 0x40) - { - dma_alias_remove(); - } - else - { - dma_alias_set(); - } - } - else if (addr == 0x4f) + case 0x40: + if (!((val ^ card_sio[addr]) & 0x40)) { - if (!((val ^ card_sio[addr]) & 0x40)) - { - return; - } - - if (val & 0x40) - { - port_92_add(); - } - else - { - port_92_remove(); - } + return; } + + if (val & 0x40) + { + dma_alias_remove(); + } + else + { + dma_alias_set(); + } + break; + + case 0x4f: + if (!((val ^ card_sio[addr]) & 0x40)) + { + return; + } + + if (val & 0x40) + { + port_92_add(); + } + else + { + port_92_remove(); + } + + case 0x60: + if (val & 0x80) + pci_set_irq_routing(PCI_INTA, PCI_IRQ_DISABLED); + else + pci_set_irq_routing(PCI_INTA, val & 0xf); + break; + case 0x61: + if (val & 0x80) + pci_set_irq_routing(PCI_INTC, PCI_IRQ_DISABLED); + else + pci_set_irq_routing(PCI_INTC, val & 0xf); + break; + case 0x62: + if (val & 0x80) + pci_set_irq_routing(PCI_INTB, PCI_IRQ_DISABLED); + else + pci_set_irq_routing(PCI_INTB, val & 0xf); + break; + case 0x63: + if (val & 0x80) + pci_set_irq_routing(PCI_INTD, PCI_IRQ_DISABLED); + else + pci_set_irq_routing(PCI_INTD, val & 0xf); + break; } + card_sio[addr] = val; } uint8_t sio_read(int func, int addr, void *priv) { -// pclog("sio_read: func=%d addr=%02x %04x:%08x\n", func, addr, CS, pc); - if (func > 0) - return 0xff; + return 0xff; - return card_sio[addr]; + return card_sio[addr]; } -static int reset_reg = 0; +static int trc_reg = 0; -void sio_reset() +uint8_t trc_read(uint16_t port, void *priv) +{ + return trc_reg & 0xfb; +} + +void trc_reset(uint8_t val) +{ + int i = 0; + + if (val & 2) + { + if (pci_reset_handler.pci_master_reset) + { + pci_reset_handler.pci_master_reset(); + } + + if (pci_reset_handler.pci_set_reset) + { + pci_reset_handler.pci_set_reset(); + } + + fdc_hard_reset(); + + if (pci_reset_handler.super_io_reset) + { + pci_reset_handler.super_io_reset(); + } + + resetide(); + for (i = 0; i < CDROM_NUM; i++) + { + if (!cdrom_drives[i].bus_type) + { + cdrom_reset(i); + } + } + + port_92_reset(); + keyboard_at_reset(); + + elcr_reset(); + } + resetx86(); +} + +void trc_write(uint16_t port, uint8_t val, void *priv) +{ + pclog("TRC Write: %02X\n", val); + if (!(trc_reg & 4) && (val & 4)) + { + trc_reset(val); + } + trc_reg = val & 0xfd; +} + +void trc_init(void) +{ + trc_reg = 0; + + io_sethandler(0x0cf9, 0x0001, trc_read, NULL, NULL, trc_write, NULL, NULL, NULL); +} + +void sio_reset(void) { memset(card_sio, 0, 256); card_sio[0x00] = 0x86; card_sio[0x01] = 0x80; /*Intel*/ - card_sio[0x02] = 0x84; card_sio[0x03] = 0x04; /*82378ZB (SIO)*/ + card_sio[0x02] = 0x84; card_sio[0x03] = 0x04; /*82378IB (SIO)*/ card_sio[0x04] = 0x07; card_sio[0x05] = 0x00; - card_sio[0x06] = 0x00; card_sio[0x07] = 0x02; - card_sio[0x08] = 0x00; /*A0 stepping*/ - card_sio[0x40] = 0x20; - card_sio[0x42] = 0x24; - card_sio[0x45] = 0x10; - card_sio[0x46] = 0x0F; - card_sio[0x48] = 0x01; - card_sio[0x4A] = 0x10; - card_sio[0x4B] = 0x0F; - card_sio[0x4C] = 0x56; - card_sio[0x4D] = 0x40; - card_sio[0x4E] = 0x07; - card_sio[0x4F] = 0x4F; - card_sio[0x60] = card_sio[0x61] = card_sio[0x62] = card_sio[0x63] = 0x80; - card_sio[0x80] = 0x78; - card_sio[0xA0] = 0x08; - card_sio[0xA8] = 0x0F; + card_sio[0x06] = 0x00; card_sio[0x07] = 0x02; + card_sio[0x08] = 0x03; /*A0 stepping*/ + + card_sio[0x40] = 0x20; card_sio[0x41] = 0x00; + card_sio[0x42] = 0x04; card_sio[0x43] = 0x00; + card_sio[0x44] = 0x20; card_sio[0x45] = 0x10; + card_sio[0x46] = 0x0f; card_sio[0x47] = 0x00; + card_sio[0x48] = 0x01; card_sio[0x49] = 0x10; + card_sio[0x4a] = 0x10; card_sio[0x4b] = 0x0f; + card_sio[0x4c] = 0x56; card_sio[0x4d] = 0x40; + card_sio[0x4e] = 0x07; card_sio[0x4f] = 0x4f; + card_sio[0x54] = 0x00; card_sio[0x55] = 0x00; card_sio[0x56] = 0x00; + card_sio[0x60] = 0x80; card_sio[0x61] = 0x80; card_sio[0x62] = 0x80; card_sio[0x63] = 0x80; + card_sio[0x80] = 0x78; card_sio[0x81] = 0x00; + card_sio[0xa0] = 0x08; + card_sio[0xa8] = 0x0f; } -static uint8_t rc_read(uint16_t port, void *priv) -{ - return reset_reg & 0xfb; -} - -static void rc_write(uint16_t port, uint8_t val, void *priv) -{ - if (!(reset_reg & 4) && (val & 4)) - { - if (reset_reg & 2) - { - // pclog("SIO: Hard reset\n"); - resetpchard(); - } - else - { - // pclog("SIO: Soft reset\n"); - sio_reset(); - resetide(); - softresetx86(); - } - } - reset_reg = val; -} - -void sio_init(int card) +void sio_init(int card, int pci_a, int pci_b, int pci_c, int pci_d) { pci_add_specific(card, sio_read, sio_write, NULL); + + sio_reset(); - sio_reset(); - - reset_reg = 0; - - io_sethandler(0x0cf9, 0x0001, rc_read, NULL, NULL, rc_write, NULL, NULL, NULL); + trc_init(); port_92_reset(); port_92_add(); dma_alias_set(); + + pci_reset_handler.pci_set_reset = sio_reset; + + if (pci_a) + pci_set_card_routing(pci_a, PCI_INTA); + if (pci_b) + pci_set_card_routing(pci_b, PCI_INTB); + if (pci_c) + pci_set_card_routing(pci_c, PCI_INTC); + if (pci_d) + pci_set_card_routing(pci_d, PCI_INTD); } diff --git a/src/sio.h b/src/sio.h index 9b705a6b3..0e3ea651f 100644 --- a/src/sio.h +++ b/src/sio.h @@ -1,4 +1,18 @@ -/* Copyright holders: Tenshi - see COPYING for more details -*/ -void sio_init(int card); +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * Emulation of Intel System I/O PCI chip. + * + * Version: @(#)sio.h 1.0.1 2017/06/02 + * + * Author: Sarah Walker, + * Miran Grca, + * Copyright 2008-2017 Sarah Walker. + * Copyright 2016-2017 Miran Grca. + */ + +void trc_init(void); +void sio_init(int card, int pci_a, int pci_b, int pci_c, int pci_d); diff --git a/src/sis496.c b/src/sis496.c index 1265330dd..aff1b3eaa 100644 --- a/src/sis496.c +++ b/src/sis496.c @@ -3,28 +3,33 @@ */ #include #include "ibm.h" -#include "device.h" +#include "cpu/cpu.h" #include "io.h" #include "mem.h" #include "pci.h" +#include "device.h" +#include "model.h" -#include "sis496.h" typedef struct sis496_t { uint8_t pci_conf[256]; } sis496_t; -void sis496_recalcmapping(sis496_t *sis496) + +sis496_t sis496; + + +static void sis496_recalcmapping(void) { int c; for (c = 0; c < 8; c++) { uint32_t base = 0xc0000 + (c << 15); - if (sis496->pci_conf[0x44] & (1 << c)) + if (sis496.pci_conf[0x44] & (1 << c)) { - switch (sis496->pci_conf[0x45] & 3) + switch (sis496.pci_conf[0x45] & 3) { case 0: mem_set_mem_state(base, 0x8000, MEM_READ_EXTERNAL | MEM_WRITE_INTERNAL); @@ -45,86 +50,117 @@ void sis496_recalcmapping(sis496_t *sis496) } flushmmucache(); - shadowbios = (sis496->pci_conf[0x44] & 0xf0); + shadowbios = (sis496.pci_conf[0x44] & 0xf0); } -void sis496_write(int func, int addr, uint8_t val, void *p) + +static void sis496_write(int func, int addr, uint8_t val, void *p) { - sis496_t *sis496 = (sis496_t *)p; - //pclog("sis496_write : addr=%02x val=%02x\n", addr, val); switch (addr) { case 0x44: /*Shadow configure*/ - if ((sis496->pci_conf[0x44] & val) ^ 0xf0) + if ((sis496.pci_conf[0x44] & val) ^ 0xf0) { - sis496->pci_conf[0x44] = val; - sis496_recalcmapping(sis496); + sis496.pci_conf[0x44] = val; + sis496_recalcmapping(); } break; case 0x45: /*Shadow configure*/ - if ((sis496->pci_conf[0x45] & val) ^ 0x01) + if ((sis496.pci_conf[0x45] & val) ^ 0x01) { - sis496->pci_conf[0x45] = val; - sis496_recalcmapping(sis496); + sis496.pci_conf[0x45] = val; + sis496_recalcmapping(); } break; - } + case 0xc0: + if (val & 0x80) + pci_set_irq_routing(PCI_INTA, val & 0xf); + else + pci_set_irq_routing(PCI_INTA, PCI_IRQ_DISABLED); + break; + case 0xc1: + if (val & 0x80) + pci_set_irq_routing(PCI_INTB, val & 0xf); + else + pci_set_irq_routing(PCI_INTB, PCI_IRQ_DISABLED); + break; + case 0xc2: + if (val & 0x80) + pci_set_irq_routing(PCI_INTC, val & 0xf); + else + pci_set_irq_routing(PCI_INTC, PCI_IRQ_DISABLED); + break; + case 0xc3:// pclog("IRQ routing %02x %02x\n", addr, val); + if (val & 0x80) + pci_set_irq_routing(PCI_INTD, val & 0xf); + else + pci_set_irq_routing(PCI_INTD, PCI_IRQ_DISABLED); + break; + } + if ((addr >= 4 && addr < 8) || addr >= 0x40) - sis496->pci_conf[addr] = val; + sis496.pci_conf[addr] = val; } -uint8_t sis496_read(int func, int addr, void *p) + +static uint8_t sis496_read(int func, int addr, void *p) { - sis496_t *sis496 = (sis496_t *)p; - - return sis496->pci_conf[addr]; + return sis496.pci_conf[addr]; } -void *sis496_init() + +static void sis496_reset(void) { - sis496_t *sis496 = malloc(sizeof(sis496_t)); - memset(sis496, 0, sizeof(sis496_t)); + memset(&sis496, 0, sizeof(sis496_t)); - pci_add_specific(5, sis496_read, sis496_write, sis496); + sis496.pci_conf[0x00] = 0x39; /*SiS*/ + sis496.pci_conf[0x01] = 0x10; + sis496.pci_conf[0x02] = 0x96; /*496/497*/ + sis496.pci_conf[0x03] = 0x04; + + sis496.pci_conf[0x04] = 7; + sis496.pci_conf[0x05] = 0; + + sis496.pci_conf[0x06] = 0x80; + sis496.pci_conf[0x07] = 0x02; - sis496->pci_conf[0x00] = 0x39; /*SiS*/ - sis496->pci_conf[0x01] = 0x10; - sis496->pci_conf[0x02] = 0x96; /*496/497*/ - sis496->pci_conf[0x03] = 0x04; + sis496.pci_conf[0x08] = 2; /*Device revision*/ - sis496->pci_conf[0x04] = 7; - sis496->pci_conf[0x05] = 0; + sis496.pci_conf[0x09] = 0x00; /*Device class (PCI bridge)*/ + sis496.pci_conf[0x0a] = 0x00; + sis496.pci_conf[0x0b] = 0x06; - sis496->pci_conf[0x06] = 0x80; - sis496->pci_conf[0x07] = 0x02; - - sis496->pci_conf[0x08] = 2; /*Device revision*/ - - sis496->pci_conf[0x09] = 0x00; /*Device class (PCI bridge)*/ - sis496->pci_conf[0x0a] = 0x00; - sis496->pci_conf[0x0b] = 0x06; - - sis496->pci_conf[0x0e] = 0x00; /*Single function device*/ - - return sis496; + sis496.pci_conf[0x0e] = 0x00; /*Single function device*/ } + +static void sis496_pci_reset(void) +{ + uint8_t val = 0; + + val = sis496_read(0, 0x44, NULL); /* Read current value of 0x44. */ + sis496_write(0, 0x44, val & 0xf, NULL); /* Turn off shadow BIOS but keep the lower 4 bits. */ +} + + +void sis496_init(void) +{ + pci_add_specific(5, sis496_read, sis496_write, NULL); + + sis496_reset(); + + pci_reset_handler.pci_master_reset = sis496_pci_reset; + + pci_set_card_routing(15, PCI_INTA); + pci_set_card_routing(13, PCI_INTD); + pci_set_card_routing(11, PCI_INTC); +} + + void sis496_close(void *p) { sis496_t *sis496 = (sis496_t *)p; free(sis496); } - -device_t sis496_device = -{ - "SiS 496/497", - 0, - sis496_init, - sis496_close, - NULL, - NULL, - NULL, - NULL -}; diff --git a/src/sis496.h b/src/sis496.h deleted file mode 100644 index 1ee67d59a..000000000 --- a/src/sis496.h +++ /dev/null @@ -1,4 +0,0 @@ -/* Copyright holders: Sarah Walker - see COPYING for more details -*/ -extern device_t sis496_device; diff --git a/src/sis50x.c b/src/sis50x.c index ad4be95c6..59e887d78 100644 --- a/src/sis50x.c +++ b/src/sis50x.c @@ -1,6 +1,17 @@ -/* Copyright holders: Tenshi - see COPYING for more details -*/ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * Emulation of the SiS 50x PCI chips. + * + * Version: @(#)sis50x.c 1.0.0 2017/05/30 + * + * Author: Miran Grca, + * Copyright 2017-2017 Miran Grca. + */ + #include #include "ibm.h" #include "device.h" diff --git a/src/sis50x.h b/src/sis50x.h index d2028dc2b..df5565043 100644 --- a/src/sis50x.h +++ b/src/sis50x.h @@ -1,6 +1,17 @@ -/* Copyright holders: Tenshi - see COPYING for more details -*/ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * Emulation of the SiS 50x PCI chips. + * + * Version: @(#)sis50x.h 1.0.0 2017/05/30 + * + * Author: Miran Grca, + * Copyright 2017-2017 Miran Grca. + */ + extern device_t sis501_device; extern device_t sis503_device; extern device_t sis50x_device; diff --git a/src/sis85c471.c b/src/sis85c471.c index cf8e24add..f56716f43 100644 --- a/src/sis85c471.c +++ b/src/sis85c471.c @@ -1,6 +1,17 @@ -/* Copyright holders: Tenshi - see COPYING for more details -*/ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * Emulation of the SiS 85c471 chip. + * + * Version: @(#)sis85c471.c 1.0.0 2017/05/30 + * + * Author: Miran Grca, + * Copyright 2017-2017 Miran Grca. + */ + /* SiS sis85c471 Super I/O Chip Used by Batman's Revenge @@ -23,9 +34,7 @@ static uint8_t sis85c471_regs[39]; void sis85c471_write(uint16_t port, uint8_t val, void *priv) { uint8_t index = (port & 1) ? 0 : 1; - int temp; uint8_t x; - // pclog("sis85c471_write : port=%04x reg %02X = %02X\n", port, sis85c471_curreg, val); if (index) { @@ -60,13 +69,13 @@ process_value: { if (val & 0x20) { - serial1_init(0x3f8, 4); - serial2_init(0x2f8, 3); + serial_setup(1, SERIAL1_ADDR, SERIAL1_IRQ); + serial_setup(2, SERIAL2_ADDR, SERIAL2_IRQ); } else { - serial1_remove(); - serial2_remove(); + serial_remove(1); + serial_remove(2); } } @@ -85,7 +94,6 @@ process_value: uint8_t sis85c471_read(uint16_t port, void *priv) { - // pclog("sis85c471_read : port=%04x reg %02X\n", port, sis85c471_curreg); uint8_t index = (port & 1) ? 0 : 1; uint8_t temp; @@ -106,9 +114,6 @@ void sis85c471_init() { int i = 0; - // pclog("SiS 85c471 Init\n"); - - // ide_sec_disable(); lpt2_remove(); sis85c471_curreg = 0; diff --git a/src/sis85c471.h b/src/sis85c471.h index 5ccd63ab5..5a69fdf65 100644 --- a/src/sis85c471.h +++ b/src/sis85c471.h @@ -1,3 +1,17 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * Emulation of the SiS 85c471 chip. + * + * Version: @(#)sis85c471.h 1.0.0 2017/05/30 + * + * Author: Miran Grca, + * Copyright 2017-2017 Miran Grca. + */ + /* Copyright holders: Tenshi see COPYING for more details */ diff --git a/src/slirp/Makefile b/src/slirp/Makefile deleted file mode 100644 index 275c054d2..000000000 --- a/src/slirp/Makefile +++ /dev/null @@ -1,26 +0,0 @@ -CC=gcc -CFLAGS=-I. -O2 -Wall -DEPS = bootp.h config-host.h config.h ctl.h \ - debug.h icmp_var.h if.h ip.h \ - ip_icmp.h libslirp.h main.h mbuf.h \ - misc.h queue.h sbuf.h slirp.h \ - slirp_config.h socket.h tcp.h tcpip.h \ - tcp_timer.h tcp_var.h tftp.h udp.h - -OBJ = bootp.o cksum.o debug.o if.o ip_icmp.o \ - ip_input.o ip_output.o mbuf.o misc.o queue.o \ - sbuf.o slirp.o socket.o tcp_input.o tcp_output.o \ - tcp_subr.o tcp_timer.o tftp.o udp.o - -%.o: %.c $(DEPS) - $(CC) $(CFLAGS) -c $< -o $@ - -default: libslirp.a - -clean: - rm -f $(OBJ) - rm -f libslirp.a - -libslirp.a: $(OBJ) - ar rcs $@ $^ - ranlib $@ \ No newline at end of file diff --git a/src/sound.c b/src/sound.c deleted file mode 100644 index 54d1bf032..000000000 --- a/src/sound.c +++ /dev/null @@ -1,230 +0,0 @@ -#include -#include -#include "ibm.h" -#include "device.h" - -#include "filters.h" - -#include "sound_opl.h" - -#include "sound.h" -#include "sound_adlib.h" -#include "sound_adlibgold.h" -#include "sound_pas16.h" -#include "sound_sb.h" -#include "sound_sb_dsp.h" -#include "sound_wss.h" - -#include "timer.h" -#include "thread.h" - -int sound_card_current = 0; -static int sound_card_last = 0; - -typedef struct -{ - char name[32]; - device_t *device; -} SOUND_CARD; - -static SOUND_CARD sound_cards[] = -{ - {"None", NULL}, - {"Adlib", &adlib_device}, - {"Sound Blaster 1.0", &sb_1_device}, - {"Sound Blaster 1.5", &sb_15_device}, - {"Sound Blaster 2.0", &sb_2_device}, - {"Sound Blaster Pro v1", &sb_pro_v1_device}, - {"Sound Blaster Pro v2", &sb_pro_v2_device}, - {"Sound Blaster 16", &sb_16_device}, - {"Sound Blaster AWE32", &sb_awe32_device}, - {"Adlib Gold", &adgold_device}, - {"Windows Sound System", &wss_device}, - {"Pro Audio Spectrum 16", &pas16_device}, - {"", NULL} -}; - -int sound_card_available(int card) -{ - if (sound_cards[card].device) - return device_available(sound_cards[card].device); - - return 1; -} - -char *sound_card_getname(int card) -{ - return sound_cards[card].name; -} - -device_t *sound_card_getdevice(int card) -{ - return sound_cards[card].device; -} - -int sound_card_has_config(int card) -{ - if (!sound_cards[card].device) - return 0; - return sound_cards[card].device->config ? 1 : 0; -} - -void sound_card_init() -{ - if (sound_cards[sound_card_current].device) - device_add(sound_cards[sound_card_current].device); - sound_card_last = sound_card_current; -} - -static struct -{ - void (*get_buffer)(int32_t *buffer, int len, void *p); - void *priv; -} sound_handlers[8]; - -static int sound_handlers_num; - -static int sound_poll_time = 0, sound_get_buffer_time = 0, sound_poll_latch; -int sound_pos_global = 0; - -int soundon = 1; - -static int16_t cd_buffer[CD_BUFLEN * 2]; -static thread_t *sound_cd_thread_h; -static event_t *sound_cd_event; -static unsigned int cd_vol_l, cd_vol_r; - -void sound_set_cd_volume(unsigned int vol_l, unsigned int vol_r) -{ - cd_vol_l = vol_l; - cd_vol_r = vol_r; -} - -static void sound_cd_thread(void *param) -{ - while (1) - { - int c; - - thread_wait_event(sound_cd_event, -1); - ioctl_audio_callback(cd_buffer, CD_BUFLEN*2); - if (soundon) - { - int32_t audio_vol_l = SCSIGetCDVolume(0); - int32_t audio_vol_r = SCSIGetCDVolume(1); - int channel_select[2]; - - channel_select[0] = SCSIGetCDChannel(0); - channel_select[1] = SCSIGetCDChannel(1); - - for (c = 0; c < CD_BUFLEN*2; c += 2) - { - int32_t cd_buffer_temp[2] = {0, 0}; - - /*First, adjust input from drive according to ATAPI/SCSI volume.*/ - cd_buffer[c] = ((int32_t)cd_buffer[c] * audio_vol_l) / 255; - cd_buffer[c+1] = ((int32_t)cd_buffer[c+1] * audio_vol_r) / 255; - - /*Apply ATAPI channel select*/ - if (channel_select[0] & 1) - cd_buffer_temp[0] += cd_buffer[c]; - if (channel_select[0] & 2) - cd_buffer_temp[1] += cd_buffer[c]; - if (channel_select[1] & 1) - cd_buffer_temp[0] += cd_buffer[c+1]; - if (channel_select[1] & 2) - cd_buffer_temp[1] += cd_buffer[c+1]; - - /*Apply sound card CD volume*/ - cd_buffer_temp[0] = (cd_buffer_temp[0] * (int)cd_vol_l) / 65535; - cd_buffer_temp[1] = (cd_buffer_temp[1] * (int)cd_vol_r) / 65535; - - if (cd_buffer_temp[0] > 32767) - cd_buffer_temp[0] = 32767; - if (cd_buffer_temp[0] < -32768) - cd_buffer_temp[0] = -32768; - if (cd_buffer_temp[1] > 32767) - cd_buffer_temp[1] = 32767; - if (cd_buffer_temp[1] < -32768) - cd_buffer_temp[1] = -32768; - - cd_buffer[c] = cd_buffer_temp[0]; - cd_buffer[c+1] = cd_buffer_temp[1]; - } - - givealbuffer_cd(cd_buffer); - } - } -} - -static int32_t *outbuffer; - -void sound_init() -{ - initalmain(0,NULL); - inital(); - - outbuffer = malloc(SOUNDBUFLEN * 2 * sizeof(int32_t)); - - sound_cd_event = thread_create_event(); - sound_cd_thread_h = thread_create(sound_cd_thread, NULL); -} - -void sound_add_handler(void (*get_buffer)(int32_t *buffer, int len, void *p), void *p) -{ - sound_handlers[sound_handlers_num].get_buffer = get_buffer; - sound_handlers[sound_handlers_num].priv = p; - sound_handlers_num++; -} - -void sound_poll(void *priv) -{ - sound_poll_time += sound_poll_latch; - - sound_pos_global++; - if (sound_pos_global == SOUNDBUFLEN) - { - int c; -/* int16_t buf16[SOUNDBUFLEN * 2 ];*/ - - memset(outbuffer, 0, SOUNDBUFLEN * 2 * sizeof(int32_t)); - - for (c = 0; c < sound_handlers_num; c++) - sound_handlers[c].get_buffer(outbuffer, SOUNDBUFLEN, sound_handlers[c].priv); - - -/* for (c=0;c 32767) - buf16[c] = 32767; - else - buf16[c] = outbuffer[c]; - } - - if (!soundf) soundf=fopen("sound.pcm","wb"); - fwrite(buf16,(SOUNDBUFLEN)*2*2,1,soundf);*/ - - if (soundon) givealbuffer(outbuffer); - - thread_set_event(sound_cd_event); - - sound_pos_global = 0; - } -} - -void sound_speed_changed() -{ - sound_poll_latch = (int)((double)TIMER_USEC * (1000000.0 / 48000.0)); -} - -void sound_reset() -{ - timer_add(sound_poll, &sound_poll_time, TIMER_ALWAYS_ENABLED, NULL); - - sound_handlers_num = 0; - - sound_set_cd_volume(65535, 65535); - ioctl_audio_stop(); -} diff --git a/src/sound.h b/src/sound.h deleted file mode 100644 index 8ef488ee1..000000000 --- a/src/sound.h +++ /dev/null @@ -1,18 +0,0 @@ -#include "timer.h" - -void sound_add_handler(void (*get_buffer)(int32_t *buffer, int len, void *p), void *p); - -extern int sound_card_current; - -int sound_card_available(int card); -char *sound_card_getname(int card); -struct device_t *sound_card_getdevice(int card); -int sound_card_has_config(int card); -void sound_card_init(); -void sound_set_cd_volume(unsigned int vol_l, unsigned int vol_r); - -#define CD_FREQ 44100 -#define CD_BUFLEN (CD_FREQ / 10) - -extern int sound_pos_global; -void sound_speed_changed(); diff --git a/src/sound_adlib.c b/src/sound_adlib.c deleted file mode 100644 index f4e24bb44..000000000 --- a/src/sound_adlib.c +++ /dev/null @@ -1,56 +0,0 @@ -#include -#include "ibm.h" -#include "device.h" -#include "sound.h" - -#include "sound_adlib.h" -#include "sound_opl.h" - -typedef struct adlib_t -{ - opl_t opl; -} adlib_t; - -static void adlib_get_buffer(int32_t *buffer, int len, void *p) -{ - adlib_t *adlib = (adlib_t *)p; - int c; - - opl2_update2(&adlib->opl); - - for (c = 0; c < len * 2; c++) - buffer[c] += (int32_t)adlib->opl.buffer[c]; - - adlib->opl.pos = 0; -} - -void *adlib_init() -{ - adlib_t *adlib = malloc(sizeof(adlib_t)); - memset(adlib, 0, sizeof(adlib_t)); - - pclog("adlib_init\n"); - opl2_init(&adlib->opl); - io_sethandler(0x0388, 0x0002, opl2_read, NULL, NULL, opl2_write, NULL, NULL, &adlib->opl); - sound_add_handler(adlib_get_buffer, adlib); - return adlib; -} - -void adlib_close(void *p) -{ - adlib_t *adlib = (adlib_t *)p; - - free(adlib); -} - -device_t adlib_device = -{ - "AdLib", - 0, - adlib_init, - adlib_close, - NULL, - NULL, - NULL, - NULL -}; diff --git a/src/sound_adlib.h b/src/sound_adlib.h deleted file mode 100644 index c8db01482..000000000 --- a/src/sound_adlib.h +++ /dev/null @@ -1 +0,0 @@ -extern device_t adlib_device; diff --git a/src/sound_mpu401_uart.c b/src/sound_mpu401_uart.c deleted file mode 100644 index 3ff22de61..000000000 --- a/src/sound_mpu401_uart.c +++ /dev/null @@ -1,57 +0,0 @@ -#include "ibm.h" -#include "io.h" -#include "sound_mpu401_uart.h" - -enum -{ - STATUS_OUTPUT_NOT_READY = 0x40, - STATUS_INPUT_NOT_READY = 0x80 -}; - -static void mpu401_uart_write(uint16_t addr, uint8_t val, void *p) -{ - mpu401_uart_t *mpu = (mpu401_uart_t *)p; - - if (addr & 1) /*Command*/ - { - switch (val) - { - case 0xff: /*Reset*/ - mpu->rx_data = 0xfe; /*Acknowledge*/ - mpu->status = 0; - mpu->uart_mode = 0; - break; - - case 0x3f: /*Enter UART mode*/ - mpu->rx_data = 0xfe; /*Acknowledge*/ - mpu->status = 0; - mpu->uart_mode = 1; - break; - } - return; - } - - /*Data*/ - if (mpu->uart_mode) - midi_write(val); -} - -static uint8_t mpu401_uart_read(uint16_t addr, void *p) -{ - mpu401_uart_t *mpu = (mpu401_uart_t *)p; - - if (addr & 1) /*Status*/ - return mpu->status; - - /*Data*/ - mpu->status |= STATUS_INPUT_NOT_READY; - return mpu->rx_data; -} - -void mpu401_uart_init(mpu401_uart_t *mpu, uint16_t addr) -{ - mpu->status = STATUS_INPUT_NOT_READY; - mpu->uart_mode = 0; - - io_sethandler(addr, 0x0002, mpu401_uart_read, NULL, NULL, mpu401_uart_write, NULL, NULL, mpu); -} diff --git a/src/sound_mpu401_uart.h b/src/sound_mpu401_uart.h deleted file mode 100644 index 893c53fc4..000000000 --- a/src/sound_mpu401_uart.h +++ /dev/null @@ -1,9 +0,0 @@ -typedef struct mpu401_uart_t -{ - uint8_t status; - uint8_t rx_data; - - int uart_mode; -} mpu401_uart_t; - -void mpu401_uart_init(mpu401_uart_t *mpu, uint16_t addr); diff --git a/src/sound_sb.h b/src/sound_sb.h deleted file mode 100644 index 81130fecd..000000000 --- a/src/sound_sb.h +++ /dev/null @@ -1,7 +0,0 @@ -extern device_t sb_1_device; -extern device_t sb_15_device; -extern device_t sb_2_device; -extern device_t sb_pro_v1_device; -extern device_t sb_pro_v2_device; -extern device_t sb_16_device; -extern device_t sb_awe32_device; diff --git a/src/soundopenal.c b/src/soundopenal.c deleted file mode 100644 index 78f81ed87..000000000 --- a/src/soundopenal.c +++ /dev/null @@ -1,257 +0,0 @@ -#define USE_OPENAL -#include -#include -#include -#ifdef USE_OPENAL -#include -#include -#endif -#include "ibm.h" -#include "sound.h" - -FILE *allog; -#ifdef USE_OPENAL -ALuint buffers[4]; // front and back buffers -ALuint buffers_cd[4]; // front and back buffers -static ALuint source[2]; // audio source -#endif -#define FREQ 48000 -#define BUFLEN SOUNDBUFLEN - -void closeal(); -ALvoid alutInit(ALint *argc,ALbyte **argv) -{ - ALCcontext *Context; - ALCdevice *Device; - - //Open device - Device=alcOpenDevice((ALubyte*)""); - //Create context(s) - Context=alcCreateContext(Device,NULL); - //Set active context - alcMakeContextCurrent(Context); - //Register extensions -} - -ALvoid alutExit(ALvoid) -{ - ALCcontext *Context; - ALCdevice *Device; - - //Unregister extensions - - //Get active context - Context=alcGetCurrentContext(); - //Get device for active context - Device=alcGetContextsDevice(Context); - //Disable context - alcMakeContextCurrent(NULL); - //Release context(s) - alcDestroyContext(Context); - //Close device - alcCloseDevice(Device); -} -void initalmain(int argc, char *argv[]) -{ -#ifdef USE_OPENAL - alutInit(0,0); -// printf("AlutInit\n"); - atexit(closeal); -// printf("AlutInit\n"); -#endif -} - -void closeal() -{ -#ifdef USE_OPENAL - alutExit(); -#endif -} - -void check() -{ -#ifdef USE_OPENAL - ALenum error; - if ((error = alGetError()) != AL_NO_ERROR) - { -// printf("Error : %08X\n", error); -// exit(-1); - } -#endif -} - -void inital() -{ -#ifdef USE_OPENAL - int c; - int16_t buf[BUFLEN*2]; - -// printf("1\n"); - check(); - -// printf("2\n"); - alGenBuffers(4, buffers); - check(); - alGenBuffers(4, buffers_cd); - check(); - -// printf("3\n"); - alGenSources(2, source); - check(); - -// printf("4\n"); - alSource3f(source[0], AL_POSITION, 0.0, 0.0, 0.0); - alSource3f(source[0], AL_VELOCITY, 0.0, 0.0, 0.0); - alSource3f(source[0], AL_DIRECTION, 0.0, 0.0, 0.0); - alSourcef (source[0], AL_ROLLOFF_FACTOR, 0.0 ); - alSourcei (source[0], AL_SOURCE_RELATIVE, AL_TRUE ); - check(); - alSource3f(source[1], AL_POSITION, 0.0, 0.0, 0.0); - alSource3f(source[1], AL_VELOCITY, 0.0, 0.0, 0.0); - alSource3f(source[1], AL_DIRECTION, 0.0, 0.0, 0.0); - alSourcef (source[1], AL_ROLLOFF_FACTOR, 0.0 ); - alSourcei (source[1], AL_SOURCE_RELATIVE, AL_TRUE ); - check(); - - memset(buf,0,BUFLEN*4); - -// printf("5\n"); - for (c = 0; c < 4; c++) - { - alBufferData(buffers[c], AL_FORMAT_STEREO16, buf, BUFLEN*2*2, FREQ); - alBufferData(buffers_cd[c], AL_FORMAT_STEREO16, buf, CD_BUFLEN*2*2, CD_FREQ); - } - - alSourceQueueBuffers(source[0], 4, buffers); - check(); - alSourceQueueBuffers(source[1], 4, buffers_cd); - check(); -// printf("6 %08X\n",source); - alSourcePlay(source[0]); - check(); - alSourcePlay(source[1]); - check(); -// printf("InitAL!!! %08X\n",source); -#endif -} - -void givealbuffer(int32_t *buf) -{ -#ifdef USE_OPENAL - int16_t buf16[BUFLEN*2]; - int processed; - int state; - - //return; - -// printf("Start\n"); - check(); - -// printf("GiveALBuffer %08X\n",source); - - alGetSourcei(source[0], AL_SOURCE_STATE, &state); - - check(); - - if (state==0x1014) - { - alSourcePlay(source[0]); -// printf("Resetting sound\n"); - } -// printf("State - %i %08X\n",state,state); - alGetSourcei(source[0], AL_BUFFERS_PROCESSED, &processed); - -// printf("P "); - check(); -// printf("Processed - %i\n",processed); - - if (processed>=1) - { - int c; - ALuint buffer; - - alSourceUnqueueBuffers(source[0], 1, &buffer); -// printf("U "); - check(); - - for (c=0;c 32767) - buf16[c] = 32767; - else - buf16[c] = buf[c]; - } -// for (c=0;c=1) - { - ALuint buffer; - - alSourceUnqueueBuffers(source[1], 1, &buffer); -// printf("U "); - check(); - -// for (c=0;c #include "ibm.h" #include "device.h" +#include "mem.h" +#include "io.h" +#include "rom.h" #include "tandy_eeprom.h" typedef struct @@ -34,7 +37,6 @@ void tandy_eeprom_write(uint16_t addr, uint8_t val, void *p) if ((val & 4) && !eeprom->clock) { -// pclog("eeprom_write %02x %i %i\n", val, eeprom->state, eeprom->count); switch (eeprom->state) { case EEPROM_IDLE: @@ -65,7 +67,6 @@ void tandy_eeprom_write(uint16_t addr, uint8_t val, void *p) if (eeprom->count == 8) { eeprom->count = 0; -// pclog("EEPROM get operation %02x\n", eeprom->data); eeprom->addr = eeprom->data & 0x3f; switch (eeprom->data & 0xc0) { @@ -75,7 +76,6 @@ void tandy_eeprom_write(uint16_t addr, uint8_t val, void *p) 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; @@ -101,7 +101,6 @@ void tandy_eeprom_write(uint16_t addr, uint8_t val, void *p) { 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; @@ -113,14 +112,13 @@ void tandy_eeprom_write(uint16_t addr, uint8_t val, void *p) 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; + FILE *f = NULL; memset(eeprom, 0, sizeof(tandy_eeprom_t)); @@ -128,10 +126,10 @@ void *tandy_eeprom_init() switch (romset) { case ROM_TANDY1000HX: - f = romfopen(nvr_concat("tandy1000hx.bin"), "rb"); + f = nvrfopen(L"tandy1000hx.bin", L"rb"); break; case ROM_TANDY1000SL2: - f = romfopen(nvr_concat("tandy1000sl2.bin"), "rb"); + f = nvrfopen(L"tandy1000sl2.bin", L"rb"); break; } if (f) @@ -150,15 +148,15 @@ void *tandy_eeprom_init() void tandy_eeprom_close(void *p) { tandy_eeprom_t *eeprom = (tandy_eeprom_t *)p; - FILE *f; + FILE *f = NULL; switch (eeprom->romset) { case ROM_TANDY1000HX: - f = romfopen(nvr_concat("tandy1000hx.bin"), "wb"); + f = nvrfopen(L"tandy1000hx.bin", L"wb"); break; case ROM_TANDY1000SL2: - f = romfopen(nvr_concat("tandy1000sl2.bin"), "wb"); + f = nvrfopen(L"tandy1000sl2.bin", L"wb"); break; } fwrite(eeprom->store, 128, 1, f); diff --git a/src/tandy_rom.c b/src/tandy_rom.c index bfa8738ef..a3b912c5f 100644 --- a/src/tandy_rom.c +++ b/src/tandy_rom.c @@ -4,7 +4,9 @@ #include #include "ibm.h" #include "device.h" +#include "io.h" #include "mem.h" +#include "rom.h" #include "tandy_rom.h" static uint8_t *tandy_rom; @@ -15,19 +17,15 @@ 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]; } @@ -45,10 +43,7 @@ void tandy_rom_bank_write(uint16_t port, uint8_t val, void *p) 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() @@ -58,8 +53,8 @@ void *tandy_rom_init() tandy_rom = malloc(0x80000); - f = romfopen("roms/tandy1000sl2/8079047.hu1" ,"rb"); - ff = romfopen("roms/tandy1000sl2/8079048.hu2","rb"); + f = romfopen(L"roms/tandy1000sl2/8079047.hu1", L"rb"); + ff = romfopen(L"roms/tandy1000sl2/8079048.hu2", L"rb"); for (c = 0x0000; c < 0x80000; c += 2) { tandy_rom[c] = getc(f); diff --git a/src/thread-pthread.c b/src/thread-pthread.c deleted file mode 100644 index dd56ef896..000000000 --- a/src/thread-pthread.c +++ /dev/null @@ -1,92 +0,0 @@ -/* Copyright holders: Sarah Walker - see COPYING for more details -*/ -#include -#include -#include -#include -#include "thread.h" - -typedef struct event_pthread_t -{ - pthread_cond_t cond; - pthread_mutex_t mutex; -} event_pthread_t; - -thread_t *thread_create(void (*thread_rout)(void *param), void *param) -{ - pthread_t *thread = malloc(sizeof(pthread_t)); - - pthread_create(thread, NULL, thread_rout, param); - - return thread; -} - -void thread_kill(thread_t *handle) -{ - pthread_t *thread = (pthread_t *)handle; - - pthread_cancel(*thread); - pthread_join(*thread, NULL); - - free(thread); -} - -event_t *thread_create_event() -{ - event_pthread_t *event = malloc(sizeof(event_pthread_t)); - - pthread_cond_init(&event->cond, NULL); - pthread_mutex_init(&event->mutex, NULL); - - return (event_t *)event; -} - -void thread_set_event(event_t *handle) -{ - event_pthread_t *event = (event_pthread_t *)handle; - - pthread_mutex_lock(&event->mutex); - pthread_cond_broadcast(&event->cond); - pthread_mutex_unlock(&event->mutex); -} - -void thread_reset_event(event_t *handle) -{ -} - -int thread_wait_event(event_t *handle, int timeout) -{ - event_pthread_t *event = (event_pthread_t *)handle; - struct timespec abstime; - - clock_gettime(CLOCK_REALTIME, &abstime); - abstime.tv_nsec += (timeout % 1000) * 1000000; - abstime.tv_sec += (timeout / 1000); - if (abstime.tv_nsec > 1000000000) - { - abstime.tv_nsec -= 1000000000; - abstime.tv_sec++; - } - - pthread_mutex_lock(&event->mutex); - pthread_cond_timedwait(&event->cond, &event->mutex, &abstime); - pthread_mutex_unlock(&event->mutex); - - return 0; -} - -void thread_destroy_event(event_t *handle) -{ - event_pthread_t *event = (event_pthread_t *)handle; - - pthread_cond_destroy(&event->cond); - pthread_mutex_destroy(&event->mutex); - - free(event); -} - -void thread_sleep(int t) -{ - usleep(t * 1000); -} diff --git a/src/thread.h b/src/thread.h deleted file mode 100644 index 3397760fe..000000000 --- a/src/thread.h +++ /dev/null @@ -1,15 +0,0 @@ -/* Copyright holders: Sarah Walker - see COPYING for more details -*/ -typedef void thread_t; -thread_t *thread_create(void (*thread_rout)(void *param), void *param); -void thread_kill(thread_t *handle); - -typedef void event_t; -event_t *thread_create_event(); -void thread_set_event(event_t *event); -void thread_reset_event(event_t *_event); -int thread_wait_event(event_t *event, int timeout); -void thread_destroy_event(event_t *_event); - -void thread_sleep(int t); diff --git a/src/timer.c b/src/timer.c index 45268869e..d3fd618a7 100644 --- a/src/timer.c +++ b/src/timer.c @@ -30,7 +30,6 @@ int timer_start = 0; void timer_process() { int c; - int retry; int process = 0; /*Get actual elapsed time*/ int diff = timer_latch - timer_count; @@ -40,6 +39,11 @@ void timer_process() for (c = 0; c < timers_present; c++) { + /* This is needed to avoid timer crashes on hard reset. */ + if ((timers[c].enable == NULL) || (timers[c].count == NULL)) + { + continue; + } enable[c] = *timers[c].enable; if (*timers[c].enable) { @@ -93,14 +97,26 @@ void timer_reset() pclog("timer_reset\n"); timers_present = 0; timer_latch = timer_count = 0; -// timer_process(); } int timer_add(void (*callback)(void *priv), int *count, int *enable, void *priv) { + int i = 0; + if (timers_present < TIMERS_MAX) { -// pclog("timer_add : adding timer %i\n", timers_present); + if (timers_present != 0) + { + /* This is the sanity check - it goes through all present timers and makes sure we're not adding a timer that already exists. */ + for (i = 0; i < timers_present; i++) + { + if (timers[i].present && (timers[i].callback == callback) && (timers[i].priv == priv) && (timers[i].count == count) && (timers[i].enable == enable)) + { + return 0; + } + } + } + timers[timers_present].present = 1; timers[timers_present].callback = callback; timers[timers_present].priv = priv; diff --git a/src/timer.h b/src/timer.h index 50c83e55c..bdc77493b 100644 --- a/src/timer.h +++ b/src/timer.h @@ -1,7 +1,6 @@ #ifndef _TIMER_H_ #define _TIMER_H_ -#include "cpu.h" extern int timer_start; @@ -40,11 +39,11 @@ extern int timer_start; timer_update_outstanding(); \ } while (0) -void timer_process(); -void timer_update_outstanding(); -void timer_reset(); -int timer_add(void (*callback)(void *priv), int *count, int *enable, void *priv); -void timer_set_callback(int timer, void (*callback)(void *priv)); +extern void timer_process(void); +extern void timer_update_outstanding(void); +extern void timer_reset(void); +extern int timer_add(void (*callback)(void *priv), int *count, int *enable, void *priv); +extern void timer_set_callback(int timer, void (*callback)(void *priv)); #define TIMER_ALWAYS_ENABLED &timer_one diff --git a/src/um8669f.c b/src/um8669f.c deleted file mode 100644 index 63b7fffc4..000000000 --- a/src/um8669f.c +++ /dev/null @@ -1,138 +0,0 @@ -/* Copyright holders: Sarah Walker - see COPYING for more details -*/ -/*um8669f : - - aa to 108 unlocks - next 108 write is register select (Cx?) - data read/write to 109 - 55 to 108 locks - - - - -C0 -bit 3 = LPT1 enable -bit 2 = COM2 enable -bit 1 = COM1 enable -bit 0 = FDC enable - -C1 -bits 7-6 = LPT1 mode : 11 = ECP/EPP, 01 = EPP, 10 = SPP -bit 3 = clear when LPT1 = 278 - -C3 -bits 7-6 = LPT1 DMA mode : 11 = ECP/EPP DMA1, 10 = ECP/EPP DMA3, 01 = EPP/SPP, 00 = ECP -bits 5-4 = LPT1 addr : 10 = 278/IRQ5, 01 = 3BC/IRQ7, 00 = 378/IRQ7 - -COM1 : -3f8, IRQ4 - C1 = BF, C3 = 00 -2f8, IRQ3 - C1 = BF, C3 = 03 -3e8, IRQ4 - C1 = BD, C3 = 00 -2e8, IRQ3 - B1 = BD, C3 = 03 - -COM2 : -3f8, IRQ4 - C1 = BF, C3 = 0C -2f8, IRQ3 - C1 = BF, C3 = 00 -3e8, IRQ4 - C1 = BB, C3 = 0C -2e8, IRQ3 - C1 = BB, C3 = 00 - - */ - -#include "ibm.h" - -#include "disc.h" -#include "fdc.h" -#include "io.h" -#include "lpt.h" -#include "serial.h" -#include "um8669f.h" - -static int um8669f_locked; -static int um8669f_curreg; -static uint8_t um8669f_regs[256]; - -void um8669f_write(uint16_t port, uint8_t val, void *priv) -{ - int temp; -// pclog("um8669f_write : port=%04x reg %02X = %02X locked=%i\n", port, um8669f_curreg, val, um8669f_locked); - if (um8669f_locked) - { - if (port == 0x108 && val == 0xaa) - um8669f_locked = 0; - } - else - { - if (port == 0x108) - { - if (val == 0x55) - um8669f_locked = 1; - else - um8669f_curreg = val; - } - else - { - um8669f_regs[um8669f_curreg] = val; - - fdc_remove(); - if (um8669f_regs[0xc0] & 1) - fdc_add(); - - if (um8669f_regs[0xc0] & 2) - { - temp = um8669f_regs[0xc3] & 1; /*might be & 2*/ - if (!(um8669f_regs[0xc1] & 2)) - temp |= 2; - switch (temp) - { - case 0: serial1_set(0x3f8, 4); break; - case 1: serial1_set(0x2f8, 4); break; - case 2: serial1_set(0x3e8, 4); break; - case 3: serial1_set(0x2e8, 4); break; - } - } - - if (um8669f_regs[0xc0] & 4) - { - temp = (um8669f_regs[0xc3] & 4) ? 0 : 1; /*might be & 8*/ - if (!(um8669f_regs[0xc1] & 4)) - temp |= 2; - switch (temp) - { - case 0: serial2_set(0x3f8, 3); break; - case 1: serial2_set(0x2f8, 3); break; - case 2: serial2_set(0x3e8, 3); break; - case 3: serial2_set(0x2e8, 3); break; - } - } - - lpt1_remove(); - lpt2_remove(); - temp = (um8669f_regs[0xc3] >> 4) & 3; - switch (temp) - { - case 0: lpt1_init(0x378); break; - case 1: lpt1_init(0x3bc); break; - case 2: lpt1_init(0x278); break; - } - } - } -} - -uint8_t um8669f_read(uint16_t port, void *priv) -{ -// pclog("um8669f_read : port=%04x reg %02X locked=%i\n", port, um8669f_curreg, um8669f_locked); - if (um8669f_locked) - return 0xff; - - if (port == 0x108) - return um8669f_curreg; /*???*/ - else - return um8669f_regs[um8669f_curreg]; -} - -void um8669f_init() -{ - io_sethandler(0x0108, 0x0002, um8669f_read, NULL, NULL, um8669f_write, NULL, NULL, NULL); - um8669f_locked = 1; -} diff --git a/src/um8669f.h b/src/um8669f.h deleted file mode 100644 index 19a56ba02..000000000 --- a/src/um8669f.h +++ /dev/null @@ -1,4 +0,0 @@ -/* Copyright holders: Sarah Walker - see COPYING for more details -*/ -extern void um8669f_init(); diff --git a/src/um8881f.c b/src/um8881f.c deleted file mode 100644 index c39c21b11..000000000 --- a/src/um8881f.c +++ /dev/null @@ -1,73 +0,0 @@ -/* Copyright holders: Sarah Walker - see COPYING for more details -*/ -#include "ibm.h" -#include "io.h" -#include "mem.h" -#include "pci.h" - -#include "um8881f.h" - -static uint8_t card_16[256]; -static uint8_t card_18[256]; - -void um8881f_write(int func, int addr, uint8_t val, void *priv) -{ -// pclog("um8881f_write : addr=%02x val=%02x %04x:%04x\n", addr, val, CS, pc); - if (addr == 0x54) - { -/* if ((card_16[0x54] ^ val) & 0x01) - { - if (val & 1) - mem_bios_set_state(0xe0000, 0x10000, 1, 1); - else - mem_bios_set_state(0xe0000, 0x10000, 0, 0); - }*/ - flushmmucache_nopc(); - } - if (addr == 0x55) - { - if ((card_16[0x55] ^ val) & 0xc0) - { -/* switch (val & 0xc0) - { - case 0x00: mem_bios_set_state(0xf0000, 0x10000, 0, 1); break; - case 0x40: mem_bios_set_state(0xf0000, 0x10000, 0, 0); break; - case 0x80: mem_bios_set_state(0xf0000, 0x10000, 1, 1); break; - case 0xc0: mem_bios_set_state(0xf0000, 0x10000, 1, 0); break; - }*/ - shadowbios = val & 0x80; - shadowbios_write = !(val & 0x40); - flushmmucache_nopc(); - } - } - if (addr >= 4) - card_16[addr] = val; -} - -uint8_t um8881f_read(int func, int addr, void *priv) -{ - return card_16[addr]; -} - -void um8886f_write(int func, int addr, uint8_t val, void *priv) -{ - if (addr >= 4) - card_18[addr] = val; -} - -uint8_t um8886f_read(int func, int addr, void *priv) -{ - return card_18[addr]; -} - -void um8881f_init() -{ - pci_add_specific(16, um8881f_read, um8881f_write, NULL); - pci_add_specific(18, um8886f_read, um8886f_write, NULL); - - card_16[0] = card_18[0] = 0x60; /*UMC*/ - card_16[1] = card_18[1] = 0x10; - card_16[2] = 0x81; card_16[3] = 0x88; /*UM8881 Host - PCI bridge*/ - card_18[2] = 0x86; card_18[3] = 0x88; /*UM8886 PCI - ISA bridge*/ -} diff --git a/src/um8881f.h b/src/um8881f.h deleted file mode 100644 index 4ee34640d..000000000 --- a/src/um8881f.h +++ /dev/null @@ -1,4 +0,0 @@ -/* Copyright holders: Sarah Walker - see COPYING for more details -*/ -void um8881f_init(); diff --git a/src/usb.c b/src/usb.c new file mode 100644 index 000000000..330f408de --- /dev/null +++ b/src/usb.c @@ -0,0 +1,48 @@ +/* Copyright holders: Melissa Goad + see COPYING for more details +*/ + +#include + +#include "ibm.h" +#include "io.h" +#include "mem.h" + +#include "usb.h" + +void (*usb_packet_handle[32])(usb_packet_t* packet, void *priv); +void *usb_priv[32]; +static int usb_min_card, usb_max_card; + +void usb_init(int min_card, int max_card) +{ + int c; + + for (c = 0; c < 32; c++) + usb_packet_handle[c] = usb_priv[c] = NULL; + + usb_min_card = min_card; + usb_max_card = max_card; +} + +void usb_add_specific(int card, void (*packet_handle)(usb_packet_t *packet, void *priv), void *priv) +{ + usb_packet_handle[card] = packet_handle; + usb_priv[card] = priv; +} + +void usb_add(void (*packet_handle)(usb_packet_t *packet, void *priv), void *priv) +{ + int c; + + for (c = usb_min_card; c <= usb_max_card; c++) + { + if (!usb_packet_handle[c]) + { + usb_packet_handle[c] = packet_handle; + usb_priv[c] = priv; + // pclog("USB device added to card: %i\n", c); + return; + } + } +} diff --git a/src/usb.h b/src/usb.h new file mode 100644 index 000000000..69adcf96b --- /dev/null +++ b/src/usb.h @@ -0,0 +1,41 @@ +/* Copyright holders: Melissa Goad + see COPYING for more details +*/ + +typedef struct +{ + uint8_t pid; //low 4 bits are the real pid, top 4 bits are just ~pid + uint8_t dev_addr; + uint8_t dev_endpoint; + int crc5; + uint16_t crc16; + uint8_t data[1024]; + int len; + void* device; +} usb_packet_t; + +typedef enum +{ + USB_DEV_TYPE_NONE = 0, + USB_DEV_TYPE_MOUSE, + USB_DEV_TYPE_TABLET, + USB_DEV_TYPE_KEYPAD, + USB_DEV_TYPE_DISK, + USB_DEV_TYPE_CDROM, + USB_DEV_TYPE_HUB, + USB_DEV_TYPE_PRINTER +} usb_device_type_t; + +typedef enum +{ + USB_PID_TOKEN_STALL = 0x1e, + USB_PID_TOKEN_SETUP = 0x2d, + USB_PID_TOKEN_PRE = 0x3c, + USB_PID_TOKEN_DATA1 = 0x4b, + USB_PID_TOKEN_NAK = 0x5a, + USB_PID_TOKEN_IN = 0x69, + USB_PID_TOKEN_SOF = 0xa5, + USB_PID_TOKEN_DATA0 = 0xc3, + USB_PID_TOKEN_ACK = 0xd2, + USB_PID_TOKEN_OUT = 0xe1 +} usb_pid_type_t; \ No newline at end of file diff --git a/src/vid_ati_mach64.h b/src/vid_ati_mach64.h deleted file mode 100644 index 6eedc3db2..000000000 --- a/src/vid_ati_mach64.h +++ /dev/null @@ -1,4 +0,0 @@ -/* Copyright holders: Sarah Walker - see COPYING for more details -*/ -extern device_t mach64gx_device; diff --git a/src/vid_ega.c b/src/vid_ega.c deleted file mode 100644 index 6adee44a0..000000000 --- a/src/vid_ega.c +++ /dev/null @@ -1,1137 +0,0 @@ -/* Copyright holders: Sarah Walker, Tenshi - see COPYING for more details -*/ -/*EGA emulation*/ -#include -#include "ibm.h" -#include "device.h" -#include "io.h" -#include "mem.h" -#include "rom.h" -#include "timer.h" -#include "video.h" -#include "vid_ega.h" - -extern uint8_t edatlookup[4][4]; - -static uint8_t ega_rotate[8][256]; - -static uint32_t pallook16[256], pallook64[256]; - -/*3C2 controls default mode on EGA. On VGA, it determines monitor type (mono or colour)*/ -int egaswitchread,egaswitches=9; /*7=CGA mode (200 lines), 9=EGA mode (350 lines), 8=EGA mode (200 lines)*/ - -static uint8_t mask_gdc[9] = {0x0F, 0x0F, 0x0F, 0x1F, 0x03, 0x3B, 0x0F, 0x0F, 0xFF}; -static uint8_t ega_mask_crtc[0x19] = {0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0x1F, 0x1F, 0x1F, 0x1F, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0x1F, 0xFF, 0x1F, 0x7F, 0xFF}; -static uint8_t mask_seq[5] = {0x03, 0x1F, 0x0F, 0x0F, 0x06}; - -static int old_overscan_color = 0; - -void ega_out(uint16_t addr, uint8_t val, void *p) -{ - ega_t *ega = (ega_t *)p; - int c; - uint8_t o, old; - - if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(ega->miscout & 1)) - addr ^= 0x60; - - switch (addr) - { - case 0x3c0: - if (!ega->attrff) - { - ega->attraddr = val & 31; - if ((val & 0x20) != ega->attr_palette_enable) - { - fullchange = 3; - ega->attr_palette_enable = val & 0x20; - ega_recalctimings(ega); - } - } - else - { - o = ega->attrregs[ega->attraddr & 31]; - ega->attrregs[ega->attraddr & 31] = val; - ega->attrregs[0x11] &= 0x3F; - if (ega->attraddr < 16) - fullchange = changeframecount; - if (ega->attraddr == 0x10 || ega->attraddr == 0x14 || ega->attraddr < 0x10) - { - for (c = 0; c < 16; c++) - { - /* if (ega->attrregs[0x10] & 0x80) ega->egapal[c] = (ega->attrregs[c] & 0xf) | ((ega->attrregs[0x14] & 0xf) << 4); - else ega->egapal[c] = (ega->attrregs[c] & 0x3f) | ((ega->attrregs[0x14] & 0xc) << 4); */ - - if (ega->attrregs[0x10] & 0x80) ega->egapal[c] = (ega->attrregs[c] & 0xf) | ((ega->attrregs[0x14] & 0x3) << 4); - else ega->egapal[c] = (ega->attrregs[c] & 0x3f); - - // if ((ega->attrregs[0x10] & 0x40) && gfxcard != GFX_EGA) ega->egapal[c] |= ((ega->attrregs[0x14] & 0xc) << 4); - if (gfxcard != GFX_EGA) ega->egapal[c] |= ((ega->attrregs[0x14] & 0xc) << 4); - } - } - if ((ega->attraddr == 0x10) || (ega->attraddr == 0x11)) - { - if (o != val) ega_recalctimings(ega); - } - } - ega->attrff ^= 1; - break; - case 0x3c2: - egaswitchread = val & 0xc; - ega->vres = !(val & 0x80); - if (gfxcard == GFX_EGA) - ega->pallook = ega->vres ? pallook16 : pallook64; - else - ega->pallook = pallook64; - ega->vidclock = val & 4; /*printf("3C2 write %02X\n",val);*/ - ega->enablevram = (val & 2) ? 1 : 0; - ega->oddeven_page = (val & 0x20) ? 0 : 1; - ega->miscout=val; - if (val & 1) - { -// pclog("Remove mono handler\n"); - io_removehandler(0x03a0, 0x0020, ega_in, NULL, NULL, ega_out, NULL, NULL, ega); - } - else - { -// pclog("Set mono handler\n"); - io_sethandler(0x03a0, 0x0020, ega_in, NULL, NULL, ega_out, NULL, NULL, ega); - } - ega_recalctimings(ega); - break; - case 0x3c4: - ega->seqaddr = val; - break; - case 0x3c5: - if (ega->seqaddr <= 4) val &= mask_seq[ega->seqaddr]; - o = ega->seqregs[ega->seqaddr & 0xf]; - ega->seqregs[ega->seqaddr & 0xf] = val; - if (o != val && (ega->seqaddr & 0xf) == 1) - ega_recalctimings(ega); - switch (ega->seqaddr & 0xf) - { - case 1: - if (ega->scrblank && !(val & 0x20)) - fullchange = 3; - ega->scrblank = (ega->scrblank & ~0x20) | (val & 0x20); - break; - case 2: - ega->writemask = val & 0xf; - break; - case 3: - ega->charsetb = (((val >> 2) & 3) * 0x10000) + 2; - ega->charseta = ((val & 3) * 0x10000) + 2; - break; - case 4: - ega->chain2_write = !(val & 4); - break; - } - break; - case 0x3ce: - ega->gdcaddr = val; - break; - case 0x3cf: - if (ega->seqaddr <= 8) val &= mask_gdc[ega->gdcaddr]; - ega->gdcreg[ega->gdcaddr & 15] = val; - switch (ega->gdcaddr & 15) - { - case 2: - ega->colourcompare = val; - break; - case 4: - ega->readplane = val & 3; - break; - case 5: - ega->writemode = val & 3; - ega->readmode = val & 8; - ega->chain2_read = val & 0x10; - break; - case 6: -// pclog("Write mapping %02X\n", val); - switch (val & 0xc) - { - case 0x0: /*128k at A0000*/ - mem_mapping_set_addr(&ega->mapping, 0xa0000, 0x20000); - break; - case 0x4: /*64k at A0000*/ - mem_mapping_set_addr(&ega->mapping, 0xa0000, 0x10000); - break; - case 0x8: /*32k at B0000*/ - mem_mapping_set_addr(&ega->mapping, 0xb0000, 0x08000); - break; - case 0xC: /*32k at B8000*/ - mem_mapping_set_addr(&ega->mapping, 0xb8000, 0x08000); - break; - } - break; - case 7: - ega->colournocare = val; - break; - } - break; - case 0x3d4: - // pclog("Write 3d4 %02X %04X:%04X\n", val, CS, cpu_state.pc); - ega->crtcreg = val & 31; - return; - case 0x3d5: - // pclog("Write 3d5 %02X %02X %02X\n", ega->crtcreg, val, ega->crtc[0x11]); -// if (ega->crtcreg == 1 && val == 0x14) -// fatal("Here\n"); - if (ega->crtcreg <= 0x18) val &= ega_mask_crtc[ega->crtcreg]; - if (ega->crtcreg <= 7 && ega->crtc[0x11] & 0x80) return; - old = ega->crtc[ega->crtcreg]; - ega->crtc[ega->crtcreg] = val; - if (old != val) - { - if (ega->crtcreg < 0xe || ega->crtcreg > 0x10) - { - fullchange = changeframecount; - ega_recalctimings(ega); - } - } - break; - } -} - -uint8_t ega_in(uint16_t addr, void *p) -{ - ega_t *ega = (ega_t *)p; - -/* if (addr != 0x3da && addr != 0x3ba) - pclog("ega_in %04X\n", addr); */ - if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(ega->miscout & 1)) - addr ^= 0x60; - - switch (addr) - { - case 0x3c0: - return ega->attraddr; - case 0x3c1: - if (ega->attraddr == 0x10) return ((ega->attrregs[ega->attraddr] & 0x7F) | (ega->attrff << 7)); - return ega->attrregs[ega->attraddr]; - case 0x3c2: -// printf("Read egaswitch %02X %02X %i\n",egaswitchread,egaswitches,VGA); - switch (egaswitchread) - { - case 0xc: return (egaswitches & 1) ? 0x10 : 0; - case 0x8: return (egaswitches & 2) ? 0x10 : 0; - case 0x4: return (egaswitches & 4) ? 0x10 : 0; - case 0x0: return (egaswitches & 8) ? 0x10 : 0; - } - break; - case 0x3c4: - return ega->seqaddr; - case 0x3c5: - return ega->seqregs[ega->seqaddr & 0xf]; - case 0x3ce: - return ega->gdcaddr; - case 0x3cf: - if (ega->gdcaddr == 0xF8) return ega->la; - if (ega->gdcaddr == 0xF9) return ega->lb; - if (ega->gdcaddr == 0xFA) return ega->lc; - if (ega->gdcaddr == 0xFB) return ega->ld; - return ega->gdcreg[ega->gdcaddr & 0xf]; - case 0x3d4: - return ega->crtcreg; - case 0x3d5: - return ega->crtc[ega->crtcreg]; - case 0x3da: - ega->attrff = 0; - // ega->stat ^= 0x30; /*Fools IBM EGA video BIOS self-test*/ - if (ega->stat & 0x01) - ega->stat &= ~0x30; - else - ega->stat ^= 0x30; - return ega->stat; - } -// printf("Bad EGA read %04X %04X:%04X\n",addr,cs>>4,cpu_state.pc); - return 0xff; -} - -void ega_recalctimings(ega_t *ega) -{ - double _dispontime, _dispofftime, disptime; - double crtcconst; - - ega->vtotal = ega->crtc[6]; - ega->dispend = ega->crtc[0x12]; - ega->vsyncstart = ega->crtc[0x10]; - ega->split = ega->crtc[0x18]; - ega->vblankstart = ega->crtc[0x15]; - - if (ega->crtc[7] & 1) ega->vtotal |= 0x100; - ega->vtotal++; - - if (ega->crtc[7] & 2) ega->dispend |= 0x100; - ega->dispend++; - - if (ega->crtc[7] & 4) ega->vsyncstart |= 0x100; - ega->vsyncstart++; - - if (ega->crtc[7] & 0x10) ega->split |= 0x100; - ega->split+=2; - - if (ega->crtc[7] & 0x08) ega->vblankstart |= 0x100; - ega->vblankstart++; - - ega->hdisp = ega->crtc[1]; - ega->hdisp++; - - ega->rowoffset = ega->crtc[0x13]; - - // printf("Recalc! %i %i %i %i %i %02X\n", ega->vtotal, ega->dispend, ega->vsyncstart, ega->split, ega->hdisp, ega->attrregs[0x16]); - - if (ega->vblankstart < ega->dispend) - ega->dispend = ega->vblankstart; - - if (ega->vidclock) crtcconst = (ega->seqregs[1] & 1) ? MDACONST : (MDACONST * (9.0 / 8.0)); - else crtcconst = (ega->seqregs[1] & 1) ? CGACONST : (CGACONST * (9.0 / 8.0)); - - disptime = ega->crtc[0] + 2; - _dispontime = ega->hdisp; - -// printf("Disptime %f dispontime %f hdisp %i\n",disptime,dispontime,crtc[1]*8); - if (ega->seqregs[1] & 8) { disptime *= 2; _dispontime *= 2; } - _dispofftime = disptime - _dispontime; - _dispontime *= crtcconst; - _dispofftime *= crtcconst; - - ega->dispontime = (int)(_dispontime * (1 << TIMER_SHIFT)); - ega->dispofftime = (int)(_dispofftime * (1 << TIMER_SHIFT)); - - /* pclog("dispontime %i (%f) dispofftime %i (%f)\n", ega->dispontime, (float)ega->dispontime / (1 << TIMER_SHIFT), - ega->dispofftime, (float)ega->dispofftime / (1 << TIMER_SHIFT)); */ -// printf("EGA horiz total %i display end %i clock rate %i vidclock %i %i\n",crtc[0],crtc[1],egaswitchread,vidclock,((ega3c2>>2)&3) | ((tridentnewctrl2<<2)&4)); -// printf("EGA vert total %i display end %i max row %i vsync %i\n",ega_vtotal,ega_dispend,(crtc[9]&31)+1,ega_vsyncstart); -// printf("total %f on %f cycles off %f cycles frame %f sec %f %02X\n",disptime*crtcconst,dispontime,dispofftime,(dispontime+dispofftime)*ega_vtotal,(dispontime+dispofftime)*ega_vtotal*70,seqregs[1]); -} - -void ega_poll(void *p) -{ - ega_t *ega = (ega_t *)p; - uint8_t chr, dat, attr; - uint32_t charaddr; - int x, xx; - uint32_t fg, bg; - int offset; - uint8_t edat[4]; - int drawcursor = 0; - int y_add = enable_overscan ? 14 : 0; - int x_add = enable_overscan ? 8 : 0; - int y_add_ex = enable_overscan ? 28 : 0; - int x_add_ex = enable_overscan ? 16 : 0; - uint32_t *q, *r, i, j; - - if (!ega->linepos) - { - ega->vidtime += ega->dispofftime; - - ega->stat |= 1; - ega->linepos = 1; - - if (ega->dispon) - { - if (ega->firstline == 2000) - { - ega->firstline = ega->displine; - video_wait_for_buffer(); - } - - if (ega->scrblank) - { - for (x = 0; x < ega->hdisp; x++) - { - switch (ega->seqregs[1] & 9) - { - case 0: - for (xx = 0; xx < 9; xx++) ((uint32_t *)buffer32->line[ega->displine + y_add])[(x * 9) + xx + 32 + x_add] = 0; - break; - case 1: - for (xx = 0; xx < 8; xx++) ((uint32_t *)buffer32->line[ega->displine + y_add])[(x * 8) + xx + 32 + x_add] = 0; - break; - case 8: - for (xx = 0; xx < 18; xx++) ((uint32_t *)buffer32->line[ega->displine + y_add])[(x * 18) + xx + 32 + x_add] = 0; - break; - case 9: - for (xx = 0; xx < 16; xx++) ((uint32_t *)buffer32->line[ega->displine + y_add])[(x * 16) + xx + 32 + x_add] = 0; - break; - } - } - } - else if (!ega->scrblank && ega->attr_palette_enable) - { - if (!(ega->gdcreg[6] & 1)) - { - if (fullchange) - { - for (x = 0; x < ega->hdisp; x++) - { - drawcursor = ((ega->ma == ega->ca) && ega->con && ega->cursoron); - chr = ega->vram[ega->ma << 1]; - attr = ega->vram[(ega->ma << 1) + 1]; - - if (attr & 8) charaddr = ega->charsetb + (chr * 128); - else charaddr = ega->charseta + (chr * 128); - - if (drawcursor) - { - bg = ega->pallook[ega->egapal[attr & 15]]; - fg = ega->pallook[ega->egapal[attr >> 4]]; - } - else - { - fg = ega->pallook[ega->egapal[attr & 15]]; - bg = ega->pallook[ega->egapal[attr >> 4]]; - if (attr & 0x80 && ega->attrregs[0x10] & 8) - { - bg = ega->pallook[ega->egapal[(attr >> 4) & 7]]; - if (ega->blink & 16) - fg = bg; - } - } - - dat = ega->vram[charaddr + (ega->sc << 2)]; - if (ega->seqregs[1] & 8) - { - if (ega->seqregs[1] & 1) - { - for (xx = 0; xx < 8; xx++) - ((uint32_t *)buffer32->line[ega->displine + y_add])[(((x << 4) + 32 + (xx << 1)) & 2047) + x_add] = - ((uint32_t *)buffer32->line[ega->displine + y_add])[(((x << 4) + 33 + (xx << 1)) & 2047) + x_add] = (dat & (0x80 >> xx)) ? fg : bg; - } - else - { - for (xx = 0; xx < 8; xx++) - ((uint32_t *)buffer32->line[ega->displine + y_add])[(((x * 18) + 32 + (xx << 1)) & 2047) + x_add] = - ((uint32_t *)buffer32->line[ega->displine + y_add])[(((x * 18) + 33 + (xx << 1)) & 2047) + x_add] = (dat & (0x80 >> xx)) ? fg : bg; - if ((chr & ~0x1f) != 0xc0 || !(ega->attrregs[0x10] & 4)) - ((uint32_t *)buffer32->line[ega->displine + y_add])[(((x * 18) + 32 + 16) & 2047) + x_add] = - ((uint32_t *)buffer32->line[ega->displine + y_add])[(((x * 18) + 32 + 17) & 2047) + x_add] = bg; - else - ((uint32_t *)buffer32->line[ega->displine + y_add])[(((x * 18) + 32 + 16) & 2047) + x_add] = - ((uint32_t *)buffer32->line[ega->displine + y_add])[(((x * 18) + 32 + 17) & 2047) + x_add] = (dat & 1) ? fg : bg; - } - } - else - { - if (ega->seqregs[1] & 1) - { - for (xx = 0; xx < 8; xx++) - ((uint32_t *)buffer32->line[ega->displine + y_add])[(((x << 3) + 32 + xx) & 2047) + x_add] = (dat & (0x80 >> xx)) ? fg : bg; - } - else - { - for (xx = 0; xx < 8; xx++) - ((uint32_t *)buffer32->line[ega->displine + y_add])[(((x * 9) + 32 + xx) & 2047) + x_add] = (dat & (0x80 >> xx)) ? fg : bg; - if ((chr & ~0x1f) != 0xc0 || !(ega->attrregs[0x10] & 4)) - ((uint32_t *)buffer32->line[ega->displine + y_add])[(((x * 9) + 32 + 8) & 2047) + x_add] = bg; - else - ((uint32_t *)buffer32->line[ega->displine + y_add])[(((x * 9) + 32 + 8) & 2047) + x_add] = (dat & 1) ? fg : bg; - } - } - ega->ma += 4; - ega->ma &= ega->vrammask; - } - } - } - else - { - switch (ega->gdcreg[5] & 0x20) - { - case 0x00: - if (ega->seqregs[1] & 8) - { - offset = ((8 - ega->scrollcache) << 1) + 16; - for (x = 0; x <= ega->hdisp; x++) - { - if (ega->sc & 1 && !(ega->crtc[0x17] & 1)) - { - edat[0] = ega->vram[ega->ma | 0x8000]; - edat[1] = ega->vram[ega->ma | 0x8001]; - edat[2] = ega->vram[ega->ma | 0x8002]; - edat[3] = ega->vram[ega->ma | 0x8003]; - } - else - { - edat[0] = ega->vram[ega->ma]; - edat[1] = ega->vram[ega->ma | 0x1]; - edat[2] = ega->vram[ega->ma | 0x2]; - edat[3] = ega->vram[ega->ma | 0x3]; - } - ega->ma += 4; - ega->ma &= ega->vrammask; - - dat = edatlookup[edat[0] & 3][edat[1] & 3] | (edatlookup[edat[2] & 3][edat[3] & 3] << 2); - ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 4) + 14 + offset + x_add] = ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 4) + 15 + offset + x_add] = ega->pallook[ega->egapal[(dat & 0xf) & ega->attrregs[0x12]]]; - ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 4) + 12 + offset + x_add] = ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 4) + 13 + offset + x_add] = ega->pallook[ega->egapal[(dat >> 4) & ega->attrregs[0x12]]]; - dat = edatlookup[(edat[0] >> 2) & 3][(edat[1] >> 2) & 3] | (edatlookup[(edat[2] >> 2) & 3][(edat[3] >> 2) & 3] << 2); - ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 4) + 10 + offset + x_add] = ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 4) + 11 + offset + x_add] = ega->pallook[ega->egapal[(dat & 0xf) & ega->attrregs[0x12]]]; - ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 4) + 8 + offset + x_add] = ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 4) + 9 + offset + x_add] = ega->pallook[ega->egapal[(dat >> 4) & ega->attrregs[0x12]]]; - dat = edatlookup[(edat[0] >> 4) & 3][(edat[1] >> 4) & 3] | (edatlookup[(edat[2] >> 4) & 3][(edat[3] >> 4) & 3] << 2); - ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 4) + 6 + offset + x_add] = ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 4) + 7 + offset + x_add] = ega->pallook[ega->egapal[(dat & 0xf) & ega->attrregs[0x12]]]; - ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 4) + 4 + offset + x_add] = ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 4) + 5 + offset + x_add] = ega->pallook[ega->egapal[(dat >> 4) & ega->attrregs[0x12]]]; - dat = edatlookup[edat[0] >> 6][edat[1] >> 6] | (edatlookup[edat[2] >> 6][edat[3] >> 6] << 2); - ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 4) + 2 + offset + x_add] = ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 4) + 3 + offset + x_add] = ega->pallook[ega->egapal[(dat & 0xf) & ega->attrregs[0x12]]]; - ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 4) + offset + x_add] = ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 4) + 1 + offset + x_add] = ega->pallook[ega->egapal[(dat >> 4) & ega->attrregs[0x12]]]; - } - } - else - { - offset = (8 - ega->scrollcache) + 24; - for (x = 0; x <= ega->hdisp; x++) - { - if (ega->sc & 1 && !(ega->crtc[0x17] & 1)) - { - edat[0] = ega->vram[ega->ma | 0x8000]; - edat[1] = ega->vram[ega->ma | 0x8001]; - edat[2] = ega->vram[ega->ma | 0x8002]; - edat[3] = ega->vram[ega->ma | 0x8003]; - } - else - { - edat[0] = ega->vram[ega->ma]; - edat[1] = ega->vram[ega->ma | 0x1]; - edat[2] = ega->vram[ega->ma | 0x2]; - edat[3] = ega->vram[ega->ma | 0x3]; - } - ega->ma += 4; - ega->ma &= ega->vrammask; - - dat = edatlookup[edat[0] & 3][edat[1] & 3] | (edatlookup[edat[2] & 3][edat[3] & 3] << 2); - ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 3) + 7 + offset + x_add] = ega->pallook[ega->egapal[(dat & 0xf) & ega->attrregs[0x12]]]; - ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 3) + 6 + offset + x_add] = ega->pallook[ega->egapal[(dat >> 4) & ega->attrregs[0x12]]]; - dat = edatlookup[(edat[0] >> 2) & 3][(edat[1] >> 2) & 3] | (edatlookup[(edat[2] >> 2) & 3][(edat[3] >> 2) & 3] << 2); - ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 3) + 5 + offset + x_add] = ega->pallook[ega->egapal[(dat & 0xf) & ega->attrregs[0x12]]]; - ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 3) + 4 + offset + x_add] = ega->pallook[ega->egapal[(dat >> 4) & ega->attrregs[0x12]]]; - dat = edatlookup[(edat[0] >> 4) & 3][(edat[1] >> 4) & 3] | (edatlookup[(edat[2] >> 4) & 3][(edat[3] >> 4) & 3] << 2); - ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 3) + 3 + offset + x_add] = ega->pallook[ega->egapal[(dat & 0xf) & ega->attrregs[0x12]]]; - ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 3) + 2 + offset + x_add] = ega->pallook[ega->egapal[(dat >> 4) & ega->attrregs[0x12]]]; - dat = edatlookup[edat[0] >> 6][edat[1] >> 6] | (edatlookup[edat[2] >> 6][edat[3] >> 6] << 2); - ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 3) + 1 + offset + x_add] = ega->pallook[ega->egapal[(dat & 0xf) & ega->attrregs[0x12]]]; - ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 3) + offset + x_add] = ega->pallook[ega->egapal[(dat >> 4) & ega->attrregs[0x12]]]; - } - } - break; - case 0x20: - offset = ((8 - ega->scrollcache) << 1) + 16; - for (x = 0; x <= ega->hdisp; x++) - { - if (ega->sc & 1 && !(ega->crtc[0x17] & 1)) - { - edat[0] = ega->vram[(ega->ma << 1) + 0x8000]; - edat[1] = ega->vram[(ega->ma << 1) + 0x8001]; - } - else - { - edat[0] = ega->vram[(ega->ma << 1)]; - edat[1] = ega->vram[(ega->ma << 1) + 1]; - } - ega->ma += 4; - ega->ma &= ega->vrammask; - - ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 4) + 14 + offset + x_add]= ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 4) + 15 + offset + x_add] = ega->pallook[ega->egapal[edat[1] & 3]]; - ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 4) + 12 + offset + x_add] = ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 4) + 13 + offset + x_add] = ega->pallook[ega->egapal[(edat[1] >> 2) & 3]]; - ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 4) + 10 + offset + x_add] = ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 4) + 11 + offset + x_add] = ega->pallook[ega->egapal[(edat[1] >> 4) & 3]]; - ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 4) + 8 + offset + x_add] = ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 4) + 9 + offset + x_add] = ega->pallook[ega->egapal[(edat[1] >> 6) & 3]]; - ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 4) + 6 + offset + x_add] = ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 4) + 7 + offset + x_add] = ega->pallook[ega->egapal[(edat[0] >> 0) & 3]]; - ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 4) + 4 + offset + x_add] = ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 4) + 5 + offset + x_add] = ega->pallook[ega->egapal[(edat[0] >> 2) & 3]]; - ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 4) + 2 + offset + x_add] = ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 4) + 3 + offset + x_add] = ega->pallook[ega->egapal[(edat[0] >> 4) & 3]]; - ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 4) + offset + x_add] = ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 4) + 1 + offset + x_add] = ega->pallook[ega->egapal[(edat[0] >> 6) & 3]]; - } - break; - } - } - } - if (ega->lastline < ega->displine) - ega->lastline = ega->displine; - } - - ega->displine++; - if ((ega->stat & 8) && ((ega->displine & 15) == (ega->crtc[0x11] & 15)) && ega->vslines) - ega->stat &= ~8; - ega->vslines++; - if (ega->displine > 500) - ega->displine = 0; - } - else - { - ega->vidtime += ega->dispontime; -// if (output) printf("Display on %f\n",vidtime); - if (ega->dispon) - ega->stat &= ~1; - ega->linepos = 0; - if (ega->sc == (ega->crtc[11] & 31)) - ega->con = 0; - if (ega->dispon) - { - if (ega->sc == (ega->crtc[9] & 31)) - { - ega->sc = 0; - - ega->maback += (ega->rowoffset << 3); - ega->maback &= ega->vrammask; - ega->ma = ega->maback; - } - else - { - ega->sc++; - ega->sc &= 31; - ega->ma = ega->maback; - } - } - ega->vc++; - ega->vc &= 1023; -// printf("Line now %i %i ma %05X\n",vc,displine,ma); - if (ega->vc == ega->split) - { -// printf("Split at line %i %i\n",displine,vc); - ega->ma = ega->maback = 0; - if (ega->attrregs[0x10] & 0x20) - ega->scrollcache = 0; - } - if (ega->vc == ega->dispend) - { -// printf("Display over at line %i %i\n",displine,vc); - ega->dispon=0; - if (ega->crtc[10] & 0x20) ega->cursoron = 0; - else ega->cursoron = ega->blink & 16; - if (!(ega->gdcreg[6] & 1) && !(ega->blink & 15)) - fullchange = 2; - ega->blink++; - - if (fullchange) - fullchange--; - } - if (ega->vc == ega->vsyncstart) - { - int wx = 0; - int wy = 0; - ega->dispon = 0; -// printf("Vsync on at line %i %i\n",displine,vc); - ega->stat |= 8; - if (ega->seqregs[1] & 8) x = ega->hdisp * ((ega->seqregs[1] & 1) ? 8 : 9) * 2; - else x = ega->hdisp * ((ega->seqregs[1] & 1) ? 8 : 9); -// pclog("Cursor %02X %02X\n",crtc[10],crtc[11]); -// pclog("Firstline %i Lastline %i wx %i %i\n",firstline,lastline,wx,oddeven); -// doblit(); - if (x != xsize || (ega->lastline - ega->firstline) != ysize) - { - xsize = x; - ysize = ega->lastline - ega->firstline; - if (xsize < 64) xsize = 640; - if (ysize < 32) ysize = 200; - if (ega->vres) - updatewindowsize(xsize + x_add_ex, (ysize << 1) + y_add_ex); - else - updatewindowsize(xsize + x_add_ex, ysize + y_add_ex); - } - - if (enable_overscan) - { - if ((x >= 160) && ((ega->lastline - ega->firstline) >= 120)) - { - for (i = 0; i < 14; i++) - { - q = &((uint32_t *)buffer32->line[i])[32]; - r = &((uint32_t *)buffer32->line[ysize + y_add_ex - 1 - i])[32]; - - for (j = 0; j < (xsize + x_add_ex); j++) - { - q[j] = ega->pallook[ega->attrregs[0x11]]; - r[j] = ega->pallook[ega->attrregs[0x11]]; - } - } - - for (i = 14; i < (ysize + 14); i ++) - { - q = &((uint32_t *)buffer32->line[i])[32]; - - for (j = 0; j < 8; j++) - { - q[j] = ega->pallook[ega->attrregs[0x11]]; - q[xsize + x_add_ex - 1 - j] = ega->pallook[ega->attrregs[0x11]]; - } - } - } - } - - video_blit_memtoscreen(32, 0, ega->firstline, ega->lastline + y_add_ex, xsize + x_add_ex, ega->lastline - ega->firstline + y_add_ex); - - frames++; - - ega->video_res_x = wx; - ega->video_res_y = wy + 1; - if (!(ega->gdcreg[6] & 1)) /*Text mode*/ - { - ega->video_res_x /= (ega->seqregs[1] & 1) ? 8 : 9; - ega->video_res_y /= (ega->crtc[9] & 31) + 1; - ega->video_bpp = 0; - } - else - { - if (ega->crtc[9] & 0x80) - ega->video_res_y /= 2; - if (!(ega->crtc[0x17] & 1)) - ega->video_res_y *= 2; - ega->video_res_y /= (ega->crtc[9] & 31) + 1; - if (ega->seqregs[1] & 8) - ega->video_res_x /= 2; - ega->video_bpp = (ega->gdcreg[5] & 0x20) ? 2 : 4; - } - -// wakeupblit(); - readflash=0; - //framecount++; - ega->firstline = 2000; - ega->lastline = 0; - - ega->maback = ega->ma = (ega->crtc[0xc] << 8)| ega->crtc[0xd]; - ega->ca = (ega->crtc[0xe] << 8) | ega->crtc[0xf]; - ega->ma <<= 2; - ega->maback <<= 2; - ega->ca <<= 2; - changeframecount = 2; - ega->vslines = 0; - } - if (ega->vc == ega->vtotal) - { - ega->vc = 0; - ega->sc = 0; - ega->dispon = 1; - ega->displine = 0; - ega->scrollcache = ega->attrregs[0x13] & 7; - } - if (ega->sc == (ega->crtc[10] & 31)) - ega->con = 1; - } -} - -void ega_write(uint32_t addr, uint8_t val, void *p) -{ - ega_t *ega = (ega_t *)p; - uint8_t vala, valb, valc, vald; - int writemask2 = ega->writemask; - uint32_t raddr = addr; - int plane, mask; - - egawrites++; - cycles -= video_timing_b; - cycles_lost += video_timing_b; - - /* Horrible hack, I know, but it's the only way to fix the 440FX BIOS filling the VRAM with garbage until Tom fixes the memory emulation. */ - if ((cs == 0xE0000) && (cpu_state.pc == 0xBF2F) && (romset == ROM_440FX)) return; - if ((cs == 0xE0000) && (cpu_state.pc == 0xBF77) && (romset == ROM_440FX)) return; - - if (addr >= 0xB0000) addr &= 0x7fff; - else addr &= 0xffff; - - if (ega->chain2_write) - { - if ((ega->gdcreg[6] & 0xC) == 0x4) - { - writemask2 &= (ega->oddeven_page ? ~0xe : ~0xb); - } - else - { - writemask2 &= ~0xa; - } - if (addr & 1) - writemask2 <<= 1; - addr &= ~1; - } - - addr <<= 2; - - if (!(ega->gdcreg[6] & 1)) - fullchange = 2; - -// pclog("%i %08X %i %i %02X %02X %02X %02X %02X\n",chain4,addr,writemode,writemask,gdcreg[8],vram[0],vram[1],vram[2],vram[3]); - switch (ega->writemode) - { - case 1: - if (writemask2 & 1) ega->vram[addr] = ega->la; - if (writemask2 & 2) ega->vram[addr | 0x1] = ega->lb; - if (writemask2 & 4) ega->vram[addr | 0x2] = ega->lc; - if (writemask2 & 8) ega->vram[addr | 0x3] = ega->ld; - break; - case 0: - if (ega->gdcreg[3] & 7) - val = ega_rotate[ega->gdcreg[3] & 7][val]; - - if (ega->gdcreg[8] == 0xff && !(ega->gdcreg[3] & 0x18) && !ega->gdcreg[1]) - { - if (writemask2 & 1) ega->vram[addr] = val; - if (writemask2 & 2) ega->vram[addr | 0x1] = val; - if (writemask2 & 4) ega->vram[addr | 0x2] = val; - if (writemask2 & 8) ega->vram[addr | 0x3] = val; - } - else - { - if (ega->gdcreg[1] & 1) vala = (ega->gdcreg[0] & 1) ? 0xff : 0; - else vala = val; - if (ega->gdcreg[1] & 2) valb = (ega->gdcreg[0] & 2) ? 0xff : 0; - else valb = val; - if (ega->gdcreg[1] & 4) valc = (ega->gdcreg[0] & 4) ? 0xff : 0; - else valc = val; - if (ega->gdcreg[1] & 8) vald = (ega->gdcreg[0] & 8) ? 0xff : 0; - else vald = val; -// pclog("Write %02X %01X %02X %02X %02X %02X %02X\n",gdcreg[3]&0x18,writemask,vala,valb,valc,vald,gdcreg[8]); - switch (ega->gdcreg[3] & 0x18) - { - case 0: /*Set*/ - if (writemask2 & 1) ega->vram[addr] = (vala & ega->gdcreg[8]) | (ega->la & ~ega->gdcreg[8]); - if (writemask2 & 2) ega->vram[addr | 0x1] = (valb & ega->gdcreg[8]) | (ega->lb & ~ega->gdcreg[8]); - if (writemask2 & 4) ega->vram[addr | 0x2] = (valc & ega->gdcreg[8]) | (ega->lc & ~ega->gdcreg[8]); - if (writemask2 & 8) ega->vram[addr | 0x3] = (vald & ega->gdcreg[8]) | (ega->ld & ~ega->gdcreg[8]); - break; - case 8: /*AND*/ - if (writemask2 & 1) ega->vram[addr] = (vala | ~ega->gdcreg[8]) & ega->la; - if (writemask2 & 2) ega->vram[addr | 0x1] = (valb | ~ega->gdcreg[8]) & ega->lb; - if (writemask2 & 4) ega->vram[addr | 0x2] = (valc | ~ega->gdcreg[8]) & ega->lc; - if (writemask2 & 8) ega->vram[addr | 0x3] = (vald | ~ega->gdcreg[8]) & ega->ld; - break; - case 0x10: /*OR*/ - if (writemask2 & 1) ega->vram[addr] = (vala & ega->gdcreg[8]) | ega->la; - if (writemask2 & 2) ega->vram[addr | 0x1] = (valb & ega->gdcreg[8]) | ega->lb; - if (writemask2 & 4) ega->vram[addr | 0x2] = (valc & ega->gdcreg[8]) | ega->lc; - if (writemask2 & 8) ega->vram[addr | 0x3] = (vald & ega->gdcreg[8]) | ega->ld; - break; - case 0x18: /*XOR*/ - if (writemask2 & 1) ega->vram[addr] = (vala & ega->gdcreg[8]) ^ ega->la; - if (writemask2 & 2) ega->vram[addr | 0x1] = (valb & ega->gdcreg[8]) ^ ega->lb; - if (writemask2 & 4) ega->vram[addr | 0x2] = (valc & ega->gdcreg[8]) ^ ega->lc; - if (writemask2 & 8) ega->vram[addr | 0x3] = (vald & ega->gdcreg[8]) ^ ega->ld; - break; - } -// pclog("- %02X %02X %02X %02X %08X\n",vram[addr],vram[addr|0x1],vram[addr|0x2],vram[addr|0x3],addr); - } - break; - case 2: - if (!(ega->gdcreg[3] & 0x18) && !ega->gdcreg[1]) - { - if (writemask2 & 1) ega->vram[addr] = (((val & 1) ? 0xff : 0) & ega->gdcreg[8]) | (ega->la & ~ega->gdcreg[8]); - if (writemask2 & 2) ega->vram[addr | 0x1] = (((val & 2) ? 0xff : 0) & ega->gdcreg[8]) | (ega->lb & ~ega->gdcreg[8]); - if (writemask2 & 4) ega->vram[addr | 0x2] = (((val & 4) ? 0xff : 0) & ega->gdcreg[8]) | (ega->lc & ~ega->gdcreg[8]); - if (writemask2 & 8) ega->vram[addr | 0x3] = (((val & 8) ? 0xff : 0) & ega->gdcreg[8]) | (ega->ld & ~ega->gdcreg[8]); - } - else - { - vala = ((val & 1) ? 0xff : 0); - valb = ((val & 2) ? 0xff : 0); - valc = ((val & 4) ? 0xff : 0); - vald = ((val & 8) ? 0xff : 0); - switch (ega->gdcreg[3] & 0x18) - { - case 0: /*Set*/ - if (writemask2 & 1) ega->vram[addr] = (vala & ega->gdcreg[8]) | (ega->la & ~ega->gdcreg[8]); - if (writemask2 & 2) ega->vram[addr | 0x1] = (valb & ega->gdcreg[8]) | (ega->lb & ~ega->gdcreg[8]); - if (writemask2 & 4) ega->vram[addr | 0x2] = (valc & ega->gdcreg[8]) | (ega->lc & ~ega->gdcreg[8]); - if (writemask2 & 8) ega->vram[addr | 0x3] = (vald & ega->gdcreg[8]) | (ega->ld & ~ega->gdcreg[8]); - break; - case 8: /*AND*/ - if (writemask2 & 1) ega->vram[addr] = (vala | ~ega->gdcreg[8]) & ega->la; - if (writemask2 & 2) ega->vram[addr | 0x1] = (valb | ~ega->gdcreg[8]) & ega->lb; - if (writemask2 & 4) ega->vram[addr | 0x2] = (valc | ~ega->gdcreg[8]) & ega->lc; - if (writemask2 & 8) ega->vram[addr | 0x3] = (vald | ~ega->gdcreg[8]) & ega->ld; - break; - case 0x10: /*OR*/ - if (writemask2 & 1) ega->vram[addr] = (vala & ega->gdcreg[8]) | ega->la; - if (writemask2 & 2) ega->vram[addr | 0x1] = (valb & ega->gdcreg[8]) | ega->lb; - if (writemask2 & 4) ega->vram[addr | 0x2] = (valc & ega->gdcreg[8]) | ega->lc; - if (writemask2 & 8) ega->vram[addr | 0x3] = (vald & ega->gdcreg[8]) | ega->ld; - break; - case 0x18: /*XOR*/ - if (writemask2 & 1) ega->vram[addr] = (vala & ega->gdcreg[8]) ^ ega->la; - if (writemask2 & 2) ega->vram[addr | 0x1] = (valb & ega->gdcreg[8]) ^ ega->lb; - if (writemask2 & 4) ega->vram[addr | 0x2] = (valc & ega->gdcreg[8]) ^ ega->lc; - if (writemask2 & 8) ega->vram[addr | 0x3] = (vald & ega->gdcreg[8]) ^ ega->ld; - break; - } - } - break; - } -} - -uint8_t ega_read(uint32_t addr, void *p) -{ - ega_t *ega = (ega_t *)p; - uint8_t temp, temp2, temp3, temp4; - int readplane = ega->readplane; - int plane; - - egareads++; - cycles -= video_timing_b; - cycles_lost += video_timing_b; -// pclog("Readega %06X ",addr); - if (addr >= 0xb0000) addr &= 0x7fff; - else addr &= 0xffff; - - if (ega->chain2_read) - { - readplane = (readplane & 2) | (addr & 1); - addr &= ~1; - } - - addr <<= 2; - - ega->la = ega->vram[addr]; - ega->lb = ega->vram[addr | 0x1]; - ega->lc = ega->vram[addr | 0x2]; - ega->ld = ega->vram[addr | 0x3]; - if (ega->readmode) - { - temp = (ega->colournocare & 1) ? 0xff : 0; - temp &= ega->la; - temp ^= (ega->colourcompare & 1) ? 0xff : 0; - temp2 = (ega->colournocare & 2) ? 0xff : 0; - temp2 &= ega->lb; - temp2 ^= (ega->colourcompare & 2) ? 0xff : 0; - temp3 = (ega->colournocare & 4) ? 0xff : 0; - temp3 &= ega->lc; - temp3 ^= (ega->colourcompare & 4) ? 0xff : 0; - temp4 = (ega->colournocare & 8) ? 0xff : 0; - temp4 &= ega->ld; - temp4 ^= (ega->colourcompare & 8) ? 0xff : 0; - return ~(temp | temp2 | temp3 | temp4); - } - return ega->vram[addr | readplane]; -} - -void ega_init(ega_t *ega) -{ - int c, d, e; - - ega->vram = malloc(0x40000); - ega->vrammask = 0x3ffff; - - for (c = 0; c < 256; c++) - { - e = c; - for (d = 0; d < 8; d++) - { - ega_rotate[d][c] = e; - e = (e >> 1) | ((e & 1) ? 0x80 : 0); - } - } - - for (c = 0; c < 4; c++) - { - for (d = 0; d < 4; d++) - { - edatlookup[c][d] = 0; - if (c & 1) edatlookup[c][d] |= 1; - if (d & 1) edatlookup[c][d] |= 2; - if (c & 2) edatlookup[c][d] |= 0x10; - if (d & 2) edatlookup[c][d] |= 0x20; - } - } - - for (c = 0; c < 256; c++) - { - pallook64[c] = makecol32(((c >> 2) & 1) * 0xaa, ((c >> 1) & 1) * 0xaa, (c & 1) * 0xaa); - pallook64[c] += makecol32(((c >> 5) & 1) * 0x55, ((c >> 4) & 1) * 0x55, ((c >> 3) & 1) * 0x55); - pallook16[c] = makecol32(((c >> 2) & 1) * 0xaa, ((c >> 1) & 1) * 0xaa, (c & 1) * 0xaa); - pallook16[c] += makecol32(((c >> 4) & 1) * 0x55, ((c >> 4) & 1) * 0x55, ((c >> 4) & 1) * 0x55); - if ((c & 0x17) == 6) - pallook16[c] = makecol32(0xaa, 0x55, 0); - } - ega->pallook = pallook16; -} - -void ega_common_defaults(ega_t *ega) -{ - ega->miscout |= 0x22; - ega->enablevram = 1; - ega->oddeven_page = 0; - - ega->seqregs[4] |= 2; - ega->extvram = 1; -} - -void *ega_standalone_init() -{ - int c, d, e; - ega_t *ega = malloc(sizeof(ega_t)); - memset(ega, 0, sizeof(ega_t)); - - overscan_x = 16; - overscan_y = 28; - - rom_init(&ega->bios_rom, "roms/ibm_6277356_ega_card_u44_27128.bin", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); - - if (ega->bios_rom.rom[0x3ffe] == 0xaa && ega->bios_rom.rom[0x3fff] == 0x55) - { - int c; - - for (c = 0; c < 0x2000; c++) - { - uint8_t temp = ega->bios_rom.rom[c]; - ega->bios_rom.rom[c] = ega->bios_rom.rom[0x3fff - c]; - ega->bios_rom.rom[0x3fff - c] = temp; - } - } - - ega->crtc[0] = 63; - ega->dispontime = 1000 * (1 << TIMER_SHIFT); - ega->dispofftime = 1000 * (1 << TIMER_SHIFT); - ega->dispontime <<= 1; - ega->dispofftime <<= 1; - - ega_init(ega); - - ega_common_defaults(ega); - - mem_mapping_add(&ega->mapping, 0xa0000, 0x20000, ega_read, NULL, NULL, ega_write, NULL, NULL, NULL, 0, ega); - timer_add(ega_poll, &ega->vidtime, TIMER_ALWAYS_ENABLED, ega); - io_sethandler(0x03c0, 0x0020, ega_in, NULL, NULL, ega_out, NULL, NULL, ega); - return ega; -} - -void *cpqega_standalone_init() -{ - int c, d, e; - ega_t *ega = malloc(sizeof(ega_t)); - memset(ega, 0, sizeof(ega_t)); - - overscan_x = 16; - overscan_y = 28; - - rom_init(&ega->bios_rom, "roms/108281-001.bin", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); - - if (ega->bios_rom.rom[0x3ffe] == 0xaa && ega->bios_rom.rom[0x3fff] == 0x55) - { - int c; - // pclog("Read EGA ROM in reverse\n"); - - for (c = 0; c < 0x2000; c++) - { - uint8_t temp = ega->bios_rom.rom[c]; - ega->bios_rom.rom[c] = ega->bios_rom.rom[0x3fff - c]; - ega->bios_rom.rom[0x3fff - c] = temp; - } - } - - ega->crtc[0] = 63; - // ega->crtc[6] = 255; - ega->dispontime = 1000 * (1 << TIMER_SHIFT); - ega->dispofftime = 1000 * (1 << TIMER_SHIFT); - - ega_init(ega); - // ega->attrregs[0x10] |= 0xF7; - - ega_common_defaults(ega); - - mem_mapping_add(&ega->mapping, 0xa0000, 0x20000, ega_read, NULL, NULL, ega_write, NULL, NULL, NULL, 0, ega); - timer_add(ega_poll, &ega->vidtime, TIMER_ALWAYS_ENABLED, ega); - // io_sethandler(0x03a0, 0x0040, ega_in, NULL, NULL, ega_out, NULL, NULL, ega); - io_sethandler(0x03c0, 0x0020, ega_in, NULL, NULL, ega_out, NULL, NULL, ega); - return ega; -} - -void *sega_standalone_init() -{ - int c, d, e; - ega_t *ega = malloc(sizeof(ega_t)); - memset(ega, 0, sizeof(ega_t)); - - overscan_x = 16; - overscan_y = 28; - - rom_init(&ega->bios_rom, "roms/lega.vbi", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); - - if (ega->bios_rom.rom[0x3ffe] == 0xaa && ega->bios_rom.rom[0x3fff] == 0x55) - { - int c; - // pclog("Read EGA ROM in reverse\n"); - - for (c = 0; c < 0x2000; c++) - { - uint8_t temp = ega->bios_rom.rom[c]; - ega->bios_rom.rom[c] = ega->bios_rom.rom[0x3fff - c]; - ega->bios_rom.rom[0x3fff - c] = temp; - } - } - - ega->crtc[0] = 63; - // ega->crtc[6] = 255; - ega->dispontime = 1000 * (1 << TIMER_SHIFT); - ega->dispofftime = 1000 * (1 << TIMER_SHIFT); - - ega_init(ega); - // ega->attrregs[0x10] |= 0xF7; - - ega_common_defaults(ega); - - mem_mapping_add(&ega->mapping, 0xa0000, 0x20000, ega_read, NULL, NULL, ega_write, NULL, NULL, NULL, 0, ega); - timer_add(ega_poll, &ega->vidtime, TIMER_ALWAYS_ENABLED, ega); - // io_sethandler(0x03a0, 0x0040, ega_in, NULL, NULL, ega_out, NULL, NULL, ega); - io_sethandler(0x03c0, 0x0020, ega_in, NULL, NULL, ega_out, NULL, NULL, ega); - return ega; -} - -static int ega_standalone_available() -{ - return rom_present("roms/ibm_6277356_ega_card_u44_27128.bin"); -} - -static int cpqega_standalone_available() -{ - return rom_present("roms/108281-001.bin"); -} - -static int sega_standalone_available() -{ - return rom_present("roms/lega.vbi"); -} - -void ega_close(void *p) -{ - ega_t *ega = (ega_t *)p; - - free(ega->vram); - free(ega); -} - -void ega_speed_changed(void *p) -{ - ega_t *ega = (ega_t *)p; - - ega_recalctimings(ega); -} - -device_t ega_device = -{ - "EGA", - 0, - ega_standalone_init, - ega_close, - ega_standalone_available, - ega_speed_changed, - NULL, - NULL -}; - -device_t cpqega_device = -{ - "Compaq EGA", - 0, - cpqega_standalone_init, - ega_close, - cpqega_standalone_available, - ega_speed_changed, - NULL, - NULL -}; - -device_t sega_device = -{ - "SuperEGA", - 0, - sega_standalone_init, - ega_close, - sega_standalone_available, - ega_speed_changed, - NULL, - NULL -}; diff --git a/src/vid_nv_riva128.c b/src/vid_nv_riva128.c deleted file mode 100644 index 421cf3e5d..000000000 --- a/src/vid_nv_riva128.c +++ /dev/null @@ -1,2665 +0,0 @@ -/* Copyright holders: Melissa Goad, Tenshi - see COPYING for more details -*/ -/*nVidia RIVA 128 emulation*/ -#include -#include "ibm.h" -#include "device.h" -#include "io.h" -#include "mem.h" -#include "pci.h" -#include "rom.h" -#include "thread.h" -#include "timer.h" -#include "video.h" -#include "vid_nv_riva128.h" -#include "vid_svga.h" -#include "vid_svga_render.h" - -typedef struct riva128_t -{ - mem_mapping_t linear_mapping; - mem_mapping_t ramin_mapping; - mem_mapping_t mmio_mapping; - - rom_t bios_rom; - - svga_t svga; - - uint8_t card_id; - int is_nv3t; - - uint16_t vendor_id; - uint16_t device_id; - - uint32_t linear_base, linear_size; - - uint16_t rma_addr; - - uint8_t pci_regs[256]; - - int memory_size; - - uint8_t ext_regs_locked; - - uint8_t read_bank; - uint8_t write_bank; - - struct - { - uint32_t intr; - uint32_t intr_en; - uint32_t intr_line; - uint32_t enable; - } pmc; - - struct - { - uint32_t intr; - uint32_t intr_en; - } pbus; - - struct - { - uint32_t intr; - uint32_t intr_en; - - uint32_t ramht; - uint32_t ramht_addr; - uint32_t ramht_size; - - uint32_t ramfc; - uint32_t ramfc_addr; - - uint32_t ramro; - uint32_t ramro_addr; - uint32_t ramro_size; - - uint16_t chan_mode; - uint16_t chan_dma; - uint16_t chan_size; //0 = 1024, 1 = 512 - - struct - { - uint32_t dmaput; - uint32_t dmaget; - } channels[16]; - - struct - { - int chanid; - int push_enabled; - } caches[2]; - - struct - { - int subchan; - uint16_t method; - uint32_t param; - } cache0, cache1[64]; - } pfifo; - - struct - { - uint32_t addr; - uint32_t data; - uint8_t access_reg[4]; - uint8_t mode; - } rma; - - struct - { - uint32_t intr, intr_en; - - uint64_t time; - uint32_t alarm; - - uint16_t clock_mul, clock_div; - } ptimer; - - struct - { - int width; - int bpp; - uint32_t config_0; - } pfb; - - struct - { - uint32_t boot0; - } pextdev; - - struct - { - int pgraph_speedhack; - - uint32_t obj_handle[8]; - uint16_t obj_class[8]; - - uint32_t debug[5]; - - uint32_t intr; - uint32_t intr_en; - - uint32_t invalid; - uint32_t invalid_en; - - uint32_t ctx_switch[5]; - uint32_t ctx_control; - uint32_t ctx_user; - uint32_t ctx_cache[8][5]; - - uint32_t fifo_enable; - - uint32_t uclip_xmin, uclip_ymin, uclip_xmax, uclip_ymax; - uint32_t oclip_xmin, oclip_ymin, oclip_xmax, oclip_ymax; - - uint32_t src_canvas_min, src_canvas_max; - uint32_t dst_canvas_min, dst_canvas_max; - - uint32_t beta; - - uint32_t notify; - - uint32_t instance; - - struct - { - uint32_t point_color; - int32_t point_x[0x20], point_y[0x20]; - } speedhack; - } pgraph; - - struct - { - uint32_t nvpll; - uint32_t nv_m,nv_n,nv_p; - - uint32_t mpll; - uint32_t m_m,m_n,m_p; - - uint32_t vpll; - uint32_t v_m,v_n,v_p; - - uint32_t pll_ctrl; - - uint32_t gen_ctrl; - } pramdac; - - uint32_t pramin[0x80000]; - - uint32_t channels[16][8][0x2000]; - - struct - { - int scl; - int sda; - uint8_t addr; //actually 7 bits - } i2c; - - int mtime, mfreq; - int nvtime, nvfreq; - -} riva128_t; - -//Internally, the RIVA 128 operates in a weird 38-bit color depth, with 10 bits for RGB, and 8 bits for alpha, according to envytools. -typedef struct -{ - uint8_t a; - unsigned r : 10; - unsigned g : 10; - unsigned b : 10; -} riva128_color_t; - -const char* riva128_pmc_interrupts[32] = -{ - "","","","","PMEDIA","","","","PFIFO","","","","PGRAPH","","","","PRAMDAC.VIDEO","","","","PTIMER","","","","PCRTC","","","","PBUS","","","" -}; - -const char* riva128_pbus_interrupts[32] = -{ - "BUS_ERROR","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" -}; - -const char* riva128_pfifo_interrupts[32] = -{ - "CACHE_ERROR","","","","RUNOUT","","","","RUNOUT_OVERFLOW","","","","DMA_PUSHER","","","","DMA_PTE","","","","","","","","","","","","","","","" -}; - -static uint8_t riva128_pci_read(int func, int addr, void *p); -static void riva128_pci_write(int func, int addr, uint8_t val, void *p); - -static uint8_t riva128_in(uint16_t addr, void *p); -static void riva128_out(uint16_t addr, uint8_t val, void *p); - -static void riva128_mmio_write_l(uint32_t addr, uint32_t val, void *p); - -static riva128_color_t riva128_pgraph_expand_color(uint32_t ctx, uint32_t color) -{ - riva128_color_t ret; - int format = ctx & 7; - int alpha_enable = (ctx >> 3) & 1; - - switch(format) - { - default: - pclog("RIVA 128 Unknown color format %i found!\n", format); - ret.a = 0x0; - break; - case 0: - ret.a = ((color >> 15) & 1) * 0xff; - ret.r = ((color >> 10) & 0x1f) << 5; - ret.g = ((color >> 5) & 0x1f) << 5; - ret.b = ((color >> 0) & 0x1f) << 5; - break; - case 1: - ret.a = ((color >> 24) & 0xff); - ret.r = ((color >> 16) & 0xff) << 2; - ret.g = ((color >> 8) & 0xff) << 2; - ret.b = ((color >> 0) & 0xff) << 2; - break; - case 2: - ret.a = ((color >> 30) & 3) * 0x55; - ret.r = ((color >> 20) & 0x3ff); - ret.g = ((color >> 10) & 0x3ff); - ret.b = ((color >> 0) & 0x3ff); - break; - case 3: - ret.a = ((color >> 8) & 0xff); - ret.r = ret.g = ret.b = ((color >> 0) & 0xff) << 2; - break; - case 4: - ret.a = ((color >> 16) & 0xffff) >> 8; - ret.r = ret.g = ret.b = ((color >> 0) & 0xffff) >> 6; - break; - } - - if(!alpha_enable) ret.a = 0xff; - - return ret; -} - -static uint32_t riva128_pgraph_blend_factor(uint32_t alpha, uint32_t beta) -{ - if(beta == 0xff) return alpha; - if(alpha == 0xff) return beta; - alpha >>= 4; - beta >>= 3; - return (alpha * beta) >> 1; -} - -static uint32_t riva128_pgraph_do_blend(uint32_t factor, uint32_t dst, uint32_t src, int is_r5g5b5) -{ - factor &= 0xf8; - if(factor == 0xf8) return src; - if(!factor) return dst; - src >>= 2; dst >>= 2; - if(is_r5g5b5) - { - src &= 0xf8; dst &= 0xf8; - } - return ((dst * (0x100 - factor)) + (src * factor)) >> 6; -} - -static uint8_t riva128_pgraph_draw_point(int offset, void *p) -{ - riva128_t *riva128 = (riva128_t *)p; - svga_t *svga = &riva128->svga; - - svga->vram[(riva128->pgraph.speedhack.point_y[offset] * riva128->pfb.width) + riva128->pgraph.speedhack.point_x[offset]] = riva128->pgraph.speedhack.point_color; -} - -static uint8_t riva128_pmc_read(uint32_t addr, void *p) -{ - riva128_t *riva128 = (riva128_t *)p; - svga_t *svga = &riva128->svga; - uint8_t ret = 0; - - //pclog("RIVA 128 PMC read %08X %04X:%08X\n", addr, CS, cpu_state.pc); - - if(riva128->card_id == 0x03) switch(addr) - { - case 0x000000: ret = 0x11; break; - case 0x000001: ret = 0x01; break; - case 0x000002: ret = 0x03; break; - case 0x000003: ret = 0x00; break; - } - else if(riva128->card_id == 0x04) switch(addr) - { - case 0x000000: ret = 0x00; break; - case 0x000001: ret = 0x40; break; - case 0x000002: ret = 0x00; break; - case 0x000003: ret = 0x00; break; - } - else if(riva128->card_id == 0x05) switch(addr) - { - case 0x000000: ret = 0x00; break; - case 0x000001: ret = 0x40; break; - case 0x000002: ret = 0x10; break; - case 0x000003: ret = 0x00; break; - } - switch(addr) - { - case 0x000100: ret = riva128->pmc.intr & 0xff; break; - case 0x000101: ret = (riva128->pmc.intr >> 8) & 0xff; break; - case 0x000102: ret = (riva128->pmc.intr >> 16) & 0xff; break; - case 0x000103: ret = (riva128->pmc.intr >> 24) & 0xff; break; - case 0x000140: ret = riva128->pmc.intr & 0xff; break; - case 0x000141: ret = (riva128->pmc.intr_en >> 8) & 0xff; break; - case 0x000142: ret = (riva128->pmc.intr_en >> 16) & 0xff; break; - case 0x000143: ret = (riva128->pmc.intr_en >> 24) & 0xff; break; - case 0x000160: ret = riva128->pmc.intr_line & 0xff; break; - case 0x000161: ret = (riva128->pmc.intr_line >> 8) & 0xff; break; - case 0x000162: ret = (riva128->pmc.intr_line >> 16) & 0xff; break; - case 0x000163: ret = (riva128->pmc.intr_line >> 24) & 0xff; break; - case 0x000200: ret = riva128->pmc.enable & 0xff; break; - case 0x000201: ret = (riva128->pmc.enable >> 8) & 0xff; break; - case 0x000202: ret = (riva128->pmc.enable >> 16) & 0xff; break; - case 0x000203: ret = (riva128->pmc.enable >> 24) & 0xff; break; - } - - return ret; -} - -static void riva128_pmc_write(uint32_t addr, uint32_t val, void *p) -{ - riva128_t *riva128 = (riva128_t *)p; - svga_t *svga = &riva128->svga; - //pclog("RIVA 128 PMC write %08X %08X %04X:%08X\n", addr, val, CS, cpu_state.pc); - - switch(addr) - { - case 0x000100: - riva128->pmc.intr &= ~val; - break; - case 0x000140: - riva128->pmc.intr_en = val & 3; - break; - case 0x000200: - riva128->pmc.enable = val; - break; - } -} - -static void riva128_pmc_interrupt(int num, void *p) -{ - riva128_t *riva128 = (riva128_t *)p; - svga_t *svga = &riva128->svga; - - riva128->pmc.intr |= (1 << num); - - picint(1 << riva128->pci_regs[0x3c]); -} - -static uint8_t riva128_pbus_read(uint32_t addr, void *p) -{ - riva128_t *riva128 = (riva128_t *)p; - svga_t *svga = &riva128->svga; - uint8_t ret = 0; - - //pclog("RIVA 128 PBUS read %08X %04X:%08X\n", addr, CS, cpu_state.pc); - - switch(addr) - { - case 0x001100: ret = riva128->pbus.intr & 0xff; break; - case 0x001101: ret = (riva128->pbus.intr >> 8) & 0xff; break; - case 0x001102: ret = (riva128->pbus.intr >> 16) & 0xff; break; - case 0x001103: ret = (riva128->pbus.intr >> 24) & 0xff; break; - case 0x001140: ret = riva128->pbus.intr & 0xff; break; - case 0x001141: ret = (riva128->pbus.intr_en >> 8) & 0xff; break; - case 0x001142: ret = (riva128->pbus.intr_en >> 16) & 0xff; break; - case 0x001143: ret = (riva128->pbus.intr_en >> 24) & 0xff; break; - case 0x001800 ... 0x0018ff: ret = riva128_pci_read(0, addr - 0x1800, riva128); break; - } - - return ret; -} - -static void riva128_pbus_write(uint32_t addr, uint32_t val, void *p) -{ - riva128_t *riva128 = (riva128_t *)p; - svga_t *svga = &riva128->svga; - //pclog("RIVA 128 PBUS write %08X %08X %04X:%08X\n", addr, val, CS, cpu_state.pc); - - switch(addr) - { - case 0x001100: - riva128->pbus.intr &= ~val; - break; - case 0x001140: - riva128->pbus.intr_en = val; - break; - case 0x001800 ... 0x0018ff: - riva128_pci_write(0, (addr & 0xfc) + 0, (val >> 0) & 0xff, riva128); - riva128_pci_write(0, (addr & 0xfc) + 1, (val >> 8) & 0xff, riva128); - riva128_pci_write(0, (addr & 0xfc) + 2, (val >> 16) & 0xff, riva128); - riva128_pci_write(0, (addr & 0xfc) + 3, (val >> 24) & 0xff, riva128); - break; - } -} - -static uint8_t riva128_pfifo_read(uint32_t addr, void *p) -{ - riva128_t *riva128 = (riva128_t *)p; - svga_t *svga = &riva128->svga; - uint8_t ret = 0; - - pclog("RIVA 128 PFIFO read %08X %04X:%08X\n", addr, CS, cpu_state.pc); - - switch(addr) - { - case 0x002100: ret = riva128->pfifo.intr & 0xff; break; - case 0x002101: ret = (riva128->pfifo.intr >> 8) & 0xff; break; - case 0x002102: ret = (riva128->pfifo.intr >> 16) & 0xff; break; - case 0x002103: ret = (riva128->pfifo.intr >> 24) & 0xff; break; - case 0x002140: ret = riva128->pfifo.intr_en & 0xff; break; - case 0x002141: ret = (riva128->pfifo.intr_en >> 8) & 0xff; break; - case 0x002142: ret = (riva128->pfifo.intr_en >> 16) & 0xff; break; - case 0x002143: ret = (riva128->pfifo.intr_en >> 24) & 0xff; break; - case 0x002210: ret = riva128->pfifo.ramht & 0xff; break; - case 0x002211: ret = (riva128->pfifo.ramht >> 8) & 0xff; break; - case 0x002212: ret = (riva128->pfifo.ramht >> 16) & 0xff; break; - case 0x002213: ret = (riva128->pfifo.ramht >> 24) & 0xff; break; - case 0x002214: ret = riva128->pfifo.ramfc & 0xff; break; - case 0x002215: ret = (riva128->pfifo.ramfc >> 8) & 0xff; break; - case 0x002216: ret = (riva128->pfifo.ramfc >> 16) & 0xff; break; - case 0x002217: ret = (riva128->pfifo.ramfc >> 24) & 0xff; break; - case 0x002218: ret = riva128->pfifo.ramro & 0xff; break; - case 0x002219: ret = (riva128->pfifo.ramro >> 8) & 0xff; break; - case 0x00221a: ret = (riva128->pfifo.ramro >> 16) & 0xff; break; - case 0x00221b: ret = (riva128->pfifo.ramro >> 24) & 0xff; break; - case 0x002504: ret = riva128->pfifo.chan_mode & 0xff; break; - case 0x002505: ret = (riva128->pfifo.chan_mode >> 8) & 0xff; break; - case 0x002506: ret = (riva128->pfifo.chan_mode >> 16) & 0xff; break; - case 0x002507: ret = (riva128->pfifo.chan_mode >> 24) & 0xff; break; - case 0x002508: ret = riva128->pfifo.chan_dma & 0xff; break; - case 0x002509: ret = (riva128->pfifo.chan_dma >> 8) & 0xff; break; - case 0x00250a: ret = (riva128->pfifo.chan_dma >> 16) & 0xff; break; - case 0x00250b: ret = (riva128->pfifo.chan_dma >> 24) & 0xff; break; - case 0x00250c: ret = riva128->pfifo.chan_size & 0xff; break; - case 0x00250d: ret = (riva128->pfifo.chan_size >> 8) & 0xff; break; - case 0x00250e: ret = (riva128->pfifo.chan_size >> 16) & 0xff; break; - case 0x00250f: ret = (riva128->pfifo.chan_size >> 24) & 0xff; break; - //HACK - case 0x002400: ret = 0x10; break; - case 0x002401: ret = 0x00; break; - case 0x003204: ret = riva128->pfifo.caches[1].chanid; break; - case 0x003214: ret = 0x10; break; - case 0x003215: ret = 0x00; break; - case 0x003220: ret = 0x01; break; - } - - return ret; -} - -static void riva128_pfifo_write(uint32_t addr, uint32_t val, void *p) -{ - riva128_t *riva128 = (riva128_t *)p; - svga_t *svga = &riva128->svga; - pclog("RIVA 128 PFIFO write %08X %08X %04X:%08X\n", addr, val, CS, cpu_state.pc); - - switch(addr) - { - case 0x002100: - riva128->pfifo.intr &= ~val; - break; - case 0x002140: - riva128->pfifo.intr_en = val; - break; - case 0x002210: - riva128->pfifo.ramht = val; - riva128->pfifo.ramht_addr = (val & 0x1f0) << 8; - switch(val & 0x30000) - { - case 0x00000: - riva128->pfifo.ramht_size = 4 * 1024; - break; - case 0x10000: - riva128->pfifo.ramht_size = 8 * 1024; - break; - case 0x20000: - riva128->pfifo.ramht_size = 16 * 1024; - break; - case 0x30000: - riva128->pfifo.ramht_size = 32 * 1024; - break; - } - break; - case 0x002214: - riva128->pfifo.ramfc = val; - riva128->pfifo.ramfc_addr = (val & 0x1fe) << 4; - break; - case 0x002218: - riva128->pfifo.ramro = val; - riva128->pfifo.ramro_addr = (val & 0x1fe) << 4; - if(val & 0x10000) riva128->pfifo.ramro_size = 8192; - else riva128->pfifo.ramro_size = 512; - break; - case 0x002504: - riva128->pfifo.chan_mode = val; - break; - case 0x002508: - riva128->pfifo.chan_dma = val; - break; - case 0x00250c: - riva128->pfifo.chan_size = val; - break; - case 0x003200: - riva128->pfifo.caches[1].push_enabled = val; - break; - case 0x003204: - riva128->pfifo.caches[1].chanid = val; - break; - } -} - -static void riva128_pfifo_interrupt(int num, void *p) -{ - riva128_t *riva128 = (riva128_t *)p; - svga_t *svga = &riva128->svga; - - riva128->pfifo.intr |= (1 << num); - - riva128_pmc_interrupt(8, riva128); -} - -static uint8_t riva128_ptimer_read(uint32_t addr, void *p) -{ - riva128_t *riva128 = (riva128_t *)p; - svga_t *svga = &riva128->svga; - uint8_t ret = 0; - - //pclog("RIVA 128 PTIMER read %08X %04X:%08X\n", addr, CS, cpu_state.pc); - - switch(addr) - { - case 0x009100: ret = riva128->ptimer.intr & 0xff; break; - case 0x009101: ret = (riva128->ptimer.intr >> 8) & 0xff; break; - case 0x009102: ret = (riva128->ptimer.intr >> 16) & 0xff; break; - case 0x009103: ret = (riva128->ptimer.intr >> 24) & 0xff; break; - case 0x009140: ret = riva128->ptimer.intr & 0xff; break; - case 0x009141: ret = (riva128->ptimer.intr_en >> 8) & 0xff; break; - case 0x009142: ret = (riva128->ptimer.intr_en >> 16) & 0xff; break; - case 0x009143: ret = (riva128->ptimer.intr_en >> 24) & 0xff; break; - case 0x009200: ret = riva128->ptimer.clock_div & 0xff; break; - case 0x009201: ret = (riva128->ptimer.clock_div >> 8) & 0xff; break; - case 0x009202: ret = (riva128->ptimer.clock_div >> 16) & 0xff; break; - case 0x009203: ret = (riva128->ptimer.clock_div >> 24) & 0xff; break; - case 0x009210: ret = riva128->ptimer.clock_mul & 0xff; break; - case 0x009211: ret = (riva128->ptimer.clock_mul >> 8) & 0xff; break; - case 0x009212: ret = (riva128->ptimer.clock_mul >> 16) & 0xff; break; - case 0x009213: ret = (riva128->ptimer.clock_mul >> 24) & 0xff; break; - case 0x009400: ret = riva128->ptimer.time & 0xff; break; - case 0x009401: ret = (riva128->ptimer.time >> 8) & 0xff; break; - case 0x009402: ret = (riva128->ptimer.time >> 16) & 0xff; break; - case 0x009403: ret = (riva128->ptimer.time >> 24) & 0xff; break; - case 0x009410: ret = (riva128->ptimer.time >> 32) & 0xff; break; - case 0x009411: ret = (riva128->ptimer.time >> 40) & 0xff; break; - case 0x009412: ret = (riva128->ptimer.time >> 48) & 0xff; break; - case 0x009413: ret = (riva128->ptimer.time >> 56) & 0xff; break; - case 0x009420: ret = riva128->ptimer.alarm & 0xff; break; - case 0x009421: ret = (riva128->ptimer.alarm >> 8) & 0xff; break; - case 0x009422: ret = (riva128->ptimer.alarm >> 16) & 0xff; break; - case 0x009423: ret = (riva128->ptimer.alarm >> 24) & 0xff; break; - } - - - //riva128->ptimer.time += 0x10000; - - return ret; -} - -static void riva128_ptimer_write(uint32_t addr, uint32_t val, void *p) -{ - riva128_t *riva128 = (riva128_t *)p; - svga_t *svga = &riva128->svga; - pclog("RIVA 128 PTIMER write %08X %08X %04X:%08X\n", addr, val, CS, cpu_state.pc); - - switch(addr) - { - case 0x009100: - riva128->ptimer.intr &= ~val; - break; - case 0x009140: - riva128->ptimer.intr_en = val; - break; - case 0x009200: - if(!(val & 0xffff)) val = 1; - riva128->ptimer.clock_div = val & 0xffff; - break; - case 0x009210: - if((val & 0xffff) > riva128->ptimer.clock_div) val = riva128->ptimer.clock_div; - riva128->ptimer.clock_mul = val & 0xffff; - break; - case 0x009420: - riva128->ptimer.alarm = val & 0xffffffe0; - break; - } -} - -static void riva128_ptimer_interrupt(int num, void *p) -{ - riva128_t *riva128 = (riva128_t *)p; - svga_t *svga = &riva128->svga; - - riva128->ptimer.intr |= (1 << num); - - riva128_pmc_interrupt(20, riva128); -} - -static uint8_t riva128_pfb_read(uint32_t addr, void *p) -{ - riva128_t *riva128 = (riva128_t *)p; - svga_t *svga = &riva128->svga; - uint8_t ret = 0; - - //pclog("RIVA 128 PFB read %08X %04X:%08X\n", addr, CS, cpu_state.pc); - - switch(addr) - { - case 0x100000: - { - switch(riva128->card_id) - { - case 0x03: - { - switch(riva128->memory_size) - { - case 1: case 8: ret = 0; - case 2: ret = 1; - case 4: ret = 2; - } - ret |= 0x04; - break; - } - case 0x04: case 0x05: - { - switch(riva128->memory_size) - { - case 4: ret = 1; break; - case 8: ret = 2; break; - case 16: ret = 3; break; - case 32: ret = 0; break; - } - ret |= 0x14; - break; - } - } - break; - } - case 0x100200: ret = riva128->pfb.config_0 & 0xff; break; - case 0x100201: ret = (riva128->pfb.config_0 >> 8) & 0xff; break; - case 0x100202: ret = (riva128->pfb.config_0 >> 16) & 0xff; break; - case 0x100203: ret = (riva128->pfb.config_0 >> 24) & 0xff; break; - } - - return ret; -} - -static void riva128_pfb_write(uint32_t addr, uint32_t val, void *p) -{ - riva128_t *riva128 = (riva128_t *)p; - svga_t *svga = &riva128->svga; - //pclog("RIVA 128 PFB write %08X %08X %04X:%08X\n", addr, val, CS, cpu_state.pc); - - switch(addr) - { - case 0x100200: - riva128->pfb.config_0 = val; - riva128->pfb.width = (val & 0x3f) << 5; - switch((val >> 8) & 3) - { - case 1: riva128->pfb.bpp = 8; break; - case 2: riva128->pfb.bpp = 16; break; - case 3: riva128->pfb.bpp = 32; break; - } - break; - } -} - -static uint8_t riva128_pextdev_read(uint32_t addr, void *p) -{ - riva128_t *riva128 = (riva128_t *)p; - svga_t *svga = &riva128->svga; - uint8_t ret = 0; - - //pclog("RIVA 128 PEXTDEV read %08X %04X:%08X\n", addr, CS, cpu_state.pc); - - switch(addr) - { - case 0x101000: ret = 0x9e; break; - case 0x101001: ret = 0x01; break; - } - - return ret; -} - -static uint8_t riva128_pgraph_read(uint32_t addr, void *p) -{ - riva128_t *riva128 = (riva128_t *)p; - svga_t *svga = &riva128->svga; - uint8_t ret = 0; - - pclog("RIVA 128 PGRAPH read %08X %04X:%08X\n", addr, CS, cpu_state.pc); - - switch(addr) - { - case 0x400080: ret = riva128->pgraph.debug[0] & 0xff; break; - case 0x400081: ret = (riva128->pgraph.debug[0] >> 8) & 0xff; break; - case 0x400082: ret = (riva128->pgraph.debug[0] >> 16) & 0xff; break; - case 0x400083: ret = (riva128->pgraph.debug[0] >> 24) & 0xff; break; - case 0x400084: ret = riva128->pgraph.debug[1] & 0xff; break; - case 0x400085: ret = (riva128->pgraph.debug[1] >> 8) & 0xff; break; - case 0x400086: ret = (riva128->pgraph.debug[1] >> 16) & 0xff; break; - case 0x400087: ret = (riva128->pgraph.debug[1] >> 24) & 0xff; break; - case 0x400088: ret = riva128->pgraph.debug[2] & 0xff; break; - case 0x400089: ret = (riva128->pgraph.debug[2] >> 8) & 0xff; break; - case 0x40008a: ret = (riva128->pgraph.debug[2] >> 16) & 0xff; break; - case 0x40008b: ret = (riva128->pgraph.debug[2] >> 24) & 0xff; break; - case 0x40008c: ret = riva128->pgraph.debug[3] & 0xff; break; - case 0x40008d: ret = (riva128->pgraph.debug[3] >> 8) & 0xff; break; - case 0x40008e: ret = (riva128->pgraph.debug[3] >> 16) & 0xff; break; - case 0x40008f: ret = (riva128->pgraph.debug[3] >> 24) & 0xff; break; - - case 0x400100: ret = riva128->pgraph.intr & 0xff; break; - case 0x400101: ret = (riva128->pgraph.intr >> 8) & 0xff; break; - case 0x400102: ret = (riva128->pgraph.intr >> 16) & 0xff; break; - case 0x400103: ret = (riva128->pgraph.intr >> 24) & 0xff; break; - case 0x400104: ret = riva128->pgraph.invalid & 0xff; break; - case 0x400105: ret = (riva128->pgraph.invalid >> 8) & 0xff; break; - case 0x400106: ret = (riva128->pgraph.invalid >> 16) & 0xff; break; - case 0x400107: ret = (riva128->pgraph.invalid >> 24) & 0xff; break; - case 0x400140: ret = riva128->pgraph.intr_en & 0xff; break; - case 0x400141: ret = (riva128->pgraph.intr_en >> 8) & 0xff; break; - case 0x400142: ret = (riva128->pgraph.intr_en >> 16) & 0xff; break; - case 0x400143: ret = (riva128->pgraph.intr_en >> 24) & 0xff; break; - case 0x400144: ret = riva128->pgraph.invalid_en & 0xff; break; - case 0x400145: ret = (riva128->pgraph.invalid_en >> 8) & 0xff; break; - case 0x400146: ret = (riva128->pgraph.invalid_en >> 16) & 0xff; break; - case 0x400147: ret = (riva128->pgraph.invalid_en >> 24) & 0xff; break; - - case 0x400180: ret = riva128->pgraph.ctx_switch[0] & 0xff; break; - case 0x400181: ret = (riva128->pgraph.ctx_switch[0] >> 8) & 0xff; break; - case 0x400182: ret = (riva128->pgraph.ctx_switch[0] >> 16) & 0xff; break; - case 0x400183: ret = (riva128->pgraph.ctx_switch[0] >> 24) & 0xff; break; - - case 0x400190: ret = riva128->pgraph.ctx_control & 0xff; break; - case 0x400191: ret = (riva128->pgraph.ctx_control >> 8) & 0xff; break; - case 0x400192: ret = (riva128->pgraph.ctx_control >> 16) & 0xff; break; - case 0x400193: ret = (riva128->pgraph.ctx_control >> 24) & 0xff; break; - case 0x400194: ret = riva128->pgraph.ctx_user & 0xff; break; - case 0x400195: ret = (riva128->pgraph.ctx_user >> 8) & 0xff; break; - case 0x400196: ret = (riva128->pgraph.ctx_user >> 16) & 0xff; break; - case 0x400197: ret = (riva128->pgraph.ctx_user >> 24) & 0xff; break; - - case 0x4001a0 ... 0x4001bf: ret = (riva128->pgraph.ctx_cache[(addr & 0x1c) >> 2][0] >> ((addr & 3) << 3)) & 0xff; break; - - case 0x4006a4: ret = riva128->pgraph.fifo_enable & 1; break; - } - - if(riva128->card_id == 0x03) switch(addr) - { - case 0x40053c: ret = riva128->pgraph.uclip_xmin & 0xff; break; - case 0x40053d: ret = (riva128->pgraph.uclip_xmin >> 8) & 0xff; break; - case 0x40053e: ret = (riva128->pgraph.uclip_xmin >> 16) & 0xff; break; - case 0x40053f: ret = (riva128->pgraph.uclip_xmin >> 24) & 0xff; break; - case 0x400540: ret = riva128->pgraph.uclip_ymin & 0xff; break; - case 0x400541: ret = (riva128->pgraph.uclip_ymin >> 8) & 0xff; break; - case 0x400542: ret = (riva128->pgraph.uclip_ymin >> 16) & 0xff; break; - case 0x400543: ret = (riva128->pgraph.uclip_ymin >> 24) & 0xff; break; - case 0x400544: ret = riva128->pgraph.uclip_xmax & 0xff; break; - case 0x400545: ret = (riva128->pgraph.uclip_xmax >> 8) & 0xff; break; - case 0x400546: ret = (riva128->pgraph.uclip_xmax >> 16) & 0xff; break; - case 0x400547: ret = (riva128->pgraph.uclip_xmax >> 24) & 0xff; break; - case 0x400548: ret = riva128->pgraph.uclip_ymax & 0xff; break; - case 0x400549: ret = (riva128->pgraph.uclip_ymax >> 8) & 0xff; break; - case 0x40054a: ret = (riva128->pgraph.uclip_ymax >> 16) & 0xff; break; - case 0x40054b: ret = (riva128->pgraph.uclip_ymax >> 24) & 0xff; break; - case 0x400560: ret = riva128->pgraph.oclip_xmin & 0xff; break; - case 0x400561: ret = (riva128->pgraph.oclip_xmin >> 8) & 0xff; break; - case 0x400562: ret = (riva128->pgraph.oclip_xmin >> 16) & 0xff; break; - case 0x400563: ret = (riva128->pgraph.oclip_xmin >> 24) & 0xff; break; - case 0x400564: ret = riva128->pgraph.oclip_ymin & 0xff; break; - case 0x400565: ret = (riva128->pgraph.oclip_ymin >> 8) & 0xff; break; - case 0x400566: ret = (riva128->pgraph.oclip_ymin >> 16) & 0xff; break; - case 0x400567: ret = (riva128->pgraph.oclip_ymin >> 24) & 0xff; break; - case 0x400568: ret = riva128->pgraph.oclip_xmax & 0xff; break; - case 0x400569: ret = (riva128->pgraph.oclip_xmax >> 8) & 0xff; break; - case 0x40056a: ret = (riva128->pgraph.oclip_xmax >> 16) & 0xff; break; - case 0x40056b: ret = (riva128->pgraph.oclip_xmax >> 24) & 0xff; break; - case 0x40056c: ret = riva128->pgraph.oclip_ymax & 0xff; break; - case 0x40056d: ret = (riva128->pgraph.oclip_ymax >> 8) & 0xff; break; - case 0x40056e: ret = (riva128->pgraph.oclip_ymax >> 16) & 0xff; break; - case 0x40056f: ret = (riva128->pgraph.oclip_ymax >> 24) & 0xff; break; - case 0x400640: ret = riva128->pgraph.beta & 0xff; break; - case 0x400641: ret = (riva128->pgraph.beta >> 8) & 0xff; break; - case 0x400642: ret = (riva128->pgraph.beta >> 16) & 0xff; break; - case 0x400643: ret = (riva128->pgraph.beta >> 24) & 0xff; break; - case 0x400684: ret = riva128->pgraph.notify & 0xff; break; - case 0x400685: ret = (riva128->pgraph.notify >> 8) & 0xff; break; - case 0x400686: ret = (riva128->pgraph.notify >> 16) & 0xff; break; - case 0x400687: ret = (riva128->pgraph.notify >> 24) & 0xff; break; - } - - return ret; -} - -static void riva128_pgraph_write(uint32_t addr, uint32_t val, void *p) -{ - riva128_t *riva128 = (riva128_t *)p; - svga_t *svga = &riva128->svga; - pclog("RIVA 128 PGRAPH write %08X %08X %04X:%08X\n", addr, val, CS, cpu_state.pc); - - switch(addr) - { - case 0x400100: - riva128->pgraph.intr &= ~val; - break; - case 0x400104: - riva128->pgraph.invalid &= ~val; - break; - case 0x400140: - riva128->pgraph.intr_en = val; - if(riva128->card_id == 0x03) riva128->pgraph.intr_en &= 0x11111111; - else if(riva128->card_id < 0x10) riva128->pgraph.intr_en &= 0x00011311; - break; - case 0x400144: - if(riva128->card_id == 0x03) - { - riva128->pgraph.invalid_en = val; - riva128->pgraph.invalid_en &= 0x00011111; - } - break; - } - - if(riva128->card_id == 0x03) switch(addr) - { - case 0x400080: - riva128->pgraph.debug[0] = val & 0x13311110; - break; - case 0x400084: - riva128->pgraph.debug[1] = val & 0x10113301; - break; - case 0x400088: - riva128->pgraph.debug[2] = val & 0x1133f111; - break; - case 0x40008c: - riva128->pgraph.debug[3] = val & 0x1173ff31; - break; - case 0x400180: - riva128->pgraph.debug[1] &= ~1; //Clear recent volatile reset bit on object switch. - riva128->pgraph.ctx_switch[0] = val & 0x3ff3f71f; - break; - case 0x400190: - riva128->pgraph.ctx_control = val & 0x11010103; - break; - case 0x400194: - riva128->pgraph.ctx_user = val & 0x7f1fe000; - break; - case 0x4001a0 ... 0x4001bc: - riva128->pgraph.ctx_cache[(addr & 0x1c) >> 2][0] = val & 0x3ff3f71f; - break; - case 0x40053c: - riva128->pgraph.uclip_xmin = val & 0x3ffff; - break; - case 0x400540: - riva128->pgraph.uclip_ymin = val & 0x3ffff; - break; - case 0x400544: - riva128->pgraph.uclip_xmax = val & 0x3ffff; - break; - case 0x400548: - riva128->pgraph.uclip_ymax = val & 0x3ffff; - break; - case 0x400550: - riva128->pgraph.src_canvas_min = val & (riva128->is_nv3t ? 0x7fff07ff : 0x3fff07ff); - break; - case 0x400554: - riva128->pgraph.src_canvas_max = val & (riva128->is_nv3t ? 0x7fff07ff : 0x3fff07ff); - break; - case 0x400558: - riva128->pgraph.dst_canvas_min = val & (riva128->is_nv3t ? 0x7fff07ff : 0x3fff07ff); - break; - case 0x40055c: - riva128->pgraph.dst_canvas_max = val & (riva128->is_nv3t ? 0x7fff07ff : 0x3fff07ff); - break; - case 0x400560: - riva128->pgraph.oclip_xmin = val & 0x3ffff; - break; - case 0x400564: - riva128->pgraph.oclip_ymin = val & 0x3ffff; - break; - case 0x400568: - riva128->pgraph.oclip_xmax = val & 0x3ffff; - break; - case 0x40056c: - riva128->pgraph.oclip_ymax = val & 0x3ffff; - break; - case 0x400640: - { - uint32_t tmp = val & 0x7f800000; - if(val & 0x80000000) tmp = 0; - riva128->pgraph.beta = tmp; - break; - } - case 0x400684: - riva128->pgraph.notify = val & 0x0011ffff; - break; - case 0x4006a4: - riva128->pgraph.fifo_enable = val & 1; - break; - } - else if(riva128->card_id < 0x10) switch(addr) - { - case 0x400080: - riva128->pgraph.debug[0] = val & 0x1337f000; - break; - case 0x400084: - riva128->pgraph.debug[1] = val & ((riva128->card_id == 0x04) ? 0x72113101 : 0xf2ffb701); - break; - case 0x400088: - riva128->pgraph.debug[2] = val & 0x11d7fff1; - break; - case 0x40008c: - riva128->pgraph.debug[3] = val & ((riva128->card_id == 0x04) ? 0x11ffff33 : 0xfbffff73); - break; - } -} - -static void riva128_pgraph_interrupt(int num, void *p) -{ - riva128_t *riva128 = (riva128_t *)p; - svga_t *svga = &riva128->svga; - - riva128->pgraph.intr |= (1 << num); - - riva128_pmc_interrupt(12, riva128); -} - -static void riva128_pgraph_invalid_interrupt(int num, void *p) -{ - riva128_t *riva128 = (riva128_t *)p; - svga_t *svga = &riva128->svga; - - riva128->pgraph.invalid |= (1 << num); - - riva128_pgraph_interrupt(0, riva128); -} - -static uint8_t riva128_pramdac_read(uint32_t addr, void *p) -{ - riva128_t *riva128 = (riva128_t *)p; - svga_t *svga = &riva128->svga; - uint8_t ret = 0; - - //pclog("RIVA 128 PRAMDAC read %08X %04X:%08X\n", addr, CS, cpu_state.pc); - - switch(addr) - { - case 0x680500: ret = riva128->pramdac.nvpll & 0xff; break; - case 0x680501: ret = (riva128->pramdac.nvpll >> 8) & 0xff; break; - case 0x680502: ret = (riva128->pramdac.nvpll >> 16) & 0xff; break; - case 0x680503: ret = (riva128->pramdac.nvpll >> 24) & 0xff; break; - case 0x680504: ret = riva128->pramdac.mpll & 0xff; break; - case 0x680505: ret = (riva128->pramdac.mpll >> 8) & 0xff; break; - case 0x680506: ret = (riva128->pramdac.mpll >> 16) & 0xff; break; - case 0x680507: ret = (riva128->pramdac.mpll >> 24) & 0xff; break; - case 0x680508: ret = riva128->pramdac.vpll & 0xff; break; - case 0x680509: ret = (riva128->pramdac.vpll >> 8) & 0xff; break; - case 0x68050a: ret = (riva128->pramdac.vpll >> 16) & 0xff; break; - case 0x68050b: ret = (riva128->pramdac.vpll >> 24) & 0xff; break; - case 0x68050c: ret = riva128->pramdac.pll_ctrl & 0xff; break; - case 0x68050d: ret = (riva128->pramdac.pll_ctrl >> 8) & 0xff; break; - case 0x68050e: ret = (riva128->pramdac.pll_ctrl >> 16) & 0xff; break; - case 0x68050f: ret = (riva128->pramdac.pll_ctrl >> 24) & 0xff; break; - case 0x680600: ret = riva128->pramdac.gen_ctrl & 0xff; break; - case 0x680601: ret = (riva128->pramdac.gen_ctrl >> 8) & 0xff; break; - case 0x680602: ret = (riva128->pramdac.gen_ctrl >> 16) & 0xff; break; - case 0x680603: ret = (riva128->pramdac.gen_ctrl >> 24) & 0xff; break; - } - - return ret; -} - -static void riva128_pramdac_write(uint32_t addr, uint32_t val, void *p) -{ - riva128_t *riva128 = (riva128_t *)p; - svga_t *svga = &riva128->svga; - //pclog("RIVA 128 PRAMDAC write %08X %08X %04X:%08X\n", addr, val, CS, cpu_state.pc); - - switch(addr) - { - case 0x680500: - riva128->pramdac.nvpll = val; - riva128->pramdac.nv_m = val & 0xff; - riva128->pramdac.nv_n = (val >> 8) & 0xff; - riva128->pramdac.nv_p = (val >> 16) & 7; - svga_recalctimings(svga); - break; - case 0x680504: - riva128->pramdac.mpll = val; - riva128->pramdac.m_m = val & 0xff; - riva128->pramdac.m_n = (val >> 8) & 0xff; - riva128->pramdac.m_p = (val >> 16) & 7; - svga_recalctimings(svga); - break; - case 0x680508: - riva128->pramdac.vpll = val; - riva128->pramdac.v_m = val & 0xff; - riva128->pramdac.v_n = (val >> 8) & 0xff; - riva128->pramdac.v_p = (val >> 16) & 7; - svga_recalctimings(svga); - break; - case 0x68050c: - riva128->pramdac.pll_ctrl = val; - break; - case 0x680600: - riva128->pramdac.gen_ctrl = val; - break; - } -} - -static uint32_t riva128_ramht_lookup(uint32_t handle, void *p) -{ - riva128_t *riva128 = (riva128_t *)p; - svga_t *svga = &riva128->svga; - pclog("RIVA 128 RAMHT lookup with handle %08X %04X:%08X\n", handle, CS, cpu_state.pc); - - uint32_t ramht_base = riva128->pfifo.ramht_addr; - - uint32_t tmp = handle; - uint32_t hash = 0; - - int bits; - - switch(riva128->pfifo.ramht_size) - { - case 4096: bits = 12; - case 8192: bits = 13; - case 16384: bits = 14; - case 32768: bits = 15; - } - - while(handle) - { - hash ^= (tmp & (riva128->pfifo.ramht_size - 1)); - tmp = handle >> 1; - } - - hash ^= riva128->pfifo.caches[1].chanid << (bits - 4); - - return riva128->pramin[ramht_base + (hash * 8)]; -} - -/*static void riva128_pgraph_point_exec_method_speedhack(int offset, uint32_t val, void *p) -{ - riva128_t *riva128 = (riva128_t *)p; - svga_t *svga = &riva128->svga; - - switch(offset) - { - case 0x0104: - { - //NOTIFY - if(!(riva128->pgraph.invalid & 0x10000)) - { - if(riva128->pgraph.notify & 0x10000) - { - riva128_pgraph_invalid_interrupt(12, riva128); - riva128->pgraph.fifo_enable = 0; - } - } - - if(!(riva128->pgraph.invalid & 0x10000) && !(riva128->pgraph.invalid & 0x10)) - { - riva128->pgraph.notify |= 1 << 16; - riva128->pgraph.notify |= (val & 0xf) << 20; - } - break; - } - case 0x0304: - { - //COLOR - riva128->pgraph.speedhack.point_color = val; - break; - } - case 0x0400 ... 0x47c: - { - riva128->pgraph.speedhack.point_x[(offset & 0x7c) >> 2] = val & 0xffff; - riva128->pgraph.speedhack.point_y[(offset & 0x7c) >> 2] = val >> 16; - riva128_pgraph_draw_point((offset & 0x7c) >> 2, riva128); - break; - } - break; - } -} - -static void riva128_pgraph_gdi_exec_method_speedhack(int offset, uint32_t val, void *p) -{ - riva128_t *riva128 = (riva128_t *)p; - svga_t *svga = &riva128->svga; - - switch(offset) - { - case 0x0104: - { - //NOTIFY - if(!(riva128->pgraph.invalid & 0x10000)) - { - if(riva128->pgraph.notify & 0x10000) - { - riva128_pgraph_invalid_interrupt(12, riva128); - riva128->pgraph.fifo_enable = 0; - } - } - - if(!(riva128->pgraph.invalid & 0x10000) && !(riva128->pgraph.invalid & 0x10)) - { - riva128->pgraph.notify |= 1 << 16; - riva128->pgraph.notify |= (val & 0xf) << 20; - } - break; - } - } -} - -static void riva128_pgraph_exec_method_speedhack(int subchanid, int offset, uint32_t val, void *p) -{ - riva128_t *riva128 = (riva128_t *)p; - svga_t *svga = &riva128->svga; - pclog("RIVA 128 PGRAPH executing method %04X with object class on subchannel %01X %04X:%08X\n", offset, riva128->pgraph.obj_class[subchanid], subchanid, val, CS, cpu_state.pc); - - switch(riva128->pgraph.obj_class[subchanid]) - { - case 0x08: - { - //NV1_POINT - riva128_pgraph_point_exec_method_speedhack(offset, val, riva128); - break; - } - case 0x0c: - { - //NV3_GDI - riva128_pgraph_gdi_exec_method_speedhack(offset, val, riva128); - break; - } - } -}*/ - -static void riva128_puller_exec_method(int chanid, int subchanid, int offset, uint32_t val, void *p) -{ - riva128_t *riva128 = (riva128_t *)p; - svga_t *svga = &riva128->svga; - pclog("RIVA 128 Puller executing method %04X on channel %01X[%01X] %04X:%08X\n", offset, chanid, subchanid, val, CS, cpu_state.pc); - - if(offset < 0x100) - { - if(offset == 0) - { - if(riva128->card_id == 0x03) - { - uint32_t tmp = riva128_ramht_lookup(val, riva128); - riva128->pgraph.instance = (tmp & 0xffff) << 4; - riva128->pgraph.ctx_switch[0] = riva128->pgraph.ctx_cache[subchanid][0] = riva128->pramin[riva128->pgraph.instance]; - riva128->pgraph.ctx_user = (chanid << 24) | (tmp & 0x1f0000) | (subchanid << 13); - } - else if(riva128->card_id >= 0x04 && riva128->card_id < 0x10) - { - riva128->pgraph.ctx_switch[3] = (riva128_ramht_lookup(val, riva128) & 0xffff) << 4; - riva128->pgraph.ctx_switch[0] = riva128->pgraph.ctx_cache[subchanid][0] = riva128->pramin[riva128->pgraph.ctx_switch[3]]; - riva128->pgraph.ctx_switch[1] = riva128->pgraph.ctx_cache[subchanid][1] = riva128->pramin[riva128->pgraph.ctx_switch[3] + 4]; - riva128->pgraph.ctx_switch[2] = riva128->pgraph.ctx_cache[subchanid][2] = riva128->pramin[riva128->pgraph.ctx_switch[3] + 8]; - riva128->pgraph.ctx_user = (chanid << 24) | (subchanid << 13); - } - else if(riva128->card_id >= 0x10 && riva128->card_id < 0x40) - { - riva128->pgraph.ctx_switch[3] = (riva128_ramht_lookup(val, riva128) & 0xffff) << 4; - riva128->pgraph.ctx_switch[0] = riva128->pgraph.ctx_cache[subchanid][0] = riva128->pramin[riva128->pgraph.ctx_switch[3]]; - riva128->pgraph.ctx_switch[1] = riva128->pgraph.ctx_cache[subchanid][1] = riva128->pramin[riva128->pgraph.ctx_switch[3] + 4]; - riva128->pgraph.ctx_switch[2] = riva128->pgraph.ctx_cache[subchanid][2] = riva128->pramin[riva128->pgraph.ctx_switch[3] + 8]; - riva128->pgraph.ctx_switch[4] = riva128->pgraph.ctx_cache[subchanid][4] = riva128->pramin[riva128->pgraph.ctx_switch[3] + 12]; - riva128->pgraph.ctx_user = (chanid << 24) | (subchanid << 13); - } - } - } - - if(riva128->pgraph.pgraph_speedhack) - { - } - else - { - pclog("RIVA 128 That was a bad idea, turning off the PGRAPH speedhack.\n"); - } -} - -static void riva128_pusher_run(int chanid, void *p) -{ - riva128_t *riva128 = (riva128_t *)p; - svga_t *svga = &riva128->svga; - - while(riva128->pfifo.channels[chanid].dmaget != riva128->pfifo.channels[chanid].dmaput) - { - uint32_t dmaget = riva128->pfifo.channels[chanid].dmaget; - uint32_t cmd = ((uint32_t*)svga->vram)[dmaget >> 2]; - uint32_t* params = ((uint32_t*)svga->vram)[(dmaget + 4) >> 2]; - if(((cmd & 0xe0000003) == 0x20000000) && (riva128->card_id >= 0x04)) - { - //old nv4 jump command - riva128->pfifo.channels[chanid].dmaget = cmd & 0x1ffffffc; - } - if((cmd & 0xe0030003) == 0) - { - //nv3 increasing method command - uint32_t method = cmd & 0x1ffc; - int subchannel = (cmd >> 13) & 7; - int method_count = (cmd >> 18) & 0x7ff; - for(int i = 0;ipfifo.channels[chanid].dmaget += 4; - } -} - -static void riva128_user_write(uint32_t addr, uint32_t val, void *p) -{ - riva128_t *riva128 = (riva128_t *)p; - svga_t *svga = &riva128->svga; - pclog("RIVA 128 USER write %08X %08X %04X:%08X\n", addr, val, CS, cpu_state.pc); - - addr -= 0x800000; - - int chanid = (addr >> 16) & 0xf; - int subchanid = (addr >> 13) & 0x7; - int offset = addr & 0x1fff; - - if(riva128->pfifo.chan_mode & (1 << chanid)) - { - //DMA mode, at least this has docs. - switch(offset) - { - case 0x40: - riva128->pfifo.channels[chanid].dmaput = val; - if(riva128->pfifo.caches[1].push_enabled) riva128_pusher_run(chanid, riva128); - break; - case 0x44: - riva128->pfifo.channels[chanid].dmaget = val; - break; - } - } - else - { - //I don't know what to do here, as there are basically no docs on PIO PFIFO submission. - pclog("RIVA 128 PIO PFIFO submission attempted\n"); - } -} - -static uint8_t riva128_mmio_read(uint32_t addr, void *p) -{ - riva128_t *riva128 = (riva128_t *)p; - svga_t *svga = &riva128->svga; - uint8_t ret = 0; - - addr &= 0xffffff; - - //This logging condition is necessary to prevent A CATASTROPHIC LOG BLOWUP when polling PTIMER. DO NOT REMOVE. - if(!((addr >= 0x009000) && (addr <= 0x009fff))) pclog("RIVA 128 MMIO read %08X %04X:%08X\n", addr, CS, cpu_state.pc); - - switch(addr) - { - case 0x000000 ... 0x000fff: - ret = riva128_pmc_read(addr, riva128); - break; - case 0x001000 ... 0x001fff: - ret = riva128_pbus_read(addr, riva128); - break; - case 0x002000 ... 0x002fff: - ret = riva128_pfifo_read(addr, riva128); - break; - case 0x009000 ... 0x009fff: - ret = riva128_ptimer_read(addr, riva128); - break; - case 0x100000 ... 0x100fff: - ret = riva128_pfb_read(addr, riva128); - break; - case 0x101000 ... 0x101fff: - ret = riva128_pextdev_read(addr, riva128); - break; - case 0x110000 ... 0x11ffff: - if(riva128->card_id == 0x03) ret = riva128->bios_rom.rom[addr & riva128->bios_rom.mask]; - break; - case 0x300000 ... 0x30ffff: - if(riva128->card_id >= 0x04) ret = riva128->bios_rom.rom[addr & riva128->bios_rom.mask]; - break; - case 0x6013b4 ... 0x6013b5: case 0x6013d4 ... 0x6013d5: case 0x0c03c2 ... 0x0c03c5: case 0x0c03cc ... 0x0c03cf: - ret = riva128_in(addr & 0xfff, riva128); - break; - case 0x680000 ... 0x680fff: - ret = riva128_pramdac_read(addr, riva128); - break; - } - return ret; -} - -static uint16_t riva128_mmio_read_w(uint32_t addr, void *p) -{ - addr &= 0xffffff; - //pclog("RIVA 128 MMIO read %08X %04X:%08X\n", addr, CS, cpu_state.pc); - return (riva128_mmio_read(addr+0,p) << 0) | (riva128_mmio_read(addr+1,p) << 8); -} - -static uint32_t riva128_mmio_read_l(uint32_t addr, void *p) -{ - addr &= 0xffffff; - //pclog("RIVA 128 MMIO read %08X %04X:%08X\n", addr, CS, cpu_state.pc); - return (riva128_mmio_read(addr+0,p) << 0) | (riva128_mmio_read(addr+1,p) << 8) | (riva128_mmio_read(addr+2,p) << 16) | (riva128_mmio_read(addr+3,p) << 24); -} - -static void riva128_mmio_write(uint32_t addr, uint8_t val, void *p) -{ - addr &= 0xffffff; - //pclog("RIVA 128 MMIO write %08X %02X %04X:%08X\n", addr, val, CS, cpu_state.pc); - if(addr != 0x6013d4 && addr != 0x6013d5 && addr != 0x6013b4 && addr != 0x6013b5) - { - uint32_t tmp = riva128_mmio_read_l(addr,p); - tmp &= ~(0xff << ((addr & 3) << 3)); - tmp |= val << ((addr & 3) << 3); - riva128_mmio_write_l(addr, tmp, p); - } - else - { - riva128_out(addr & 0xfff, val & 0xff, p); - } -} - -static void riva128_mmio_write_w(uint32_t addr, uint16_t val, void *p) -{ - addr &= 0xffffff; - //pclog("RIVA 128 MMIO write %08X %04X %04X:%08X\n", addr, val, CS, cpu_state.pc); - uint32_t tmp = riva128_mmio_read_l(addr,p); - tmp &= ~(0xffff << ((addr & 2) << 4)); - tmp |= val << ((addr & 2) << 4); - riva128_mmio_write_l(addr, tmp, p); -} - -static void riva128_mmio_write_l(uint32_t addr, uint32_t val, void *p) -{ - riva128_t *riva128 = (riva128_t *)p; - svga_t *svga = &riva128->svga; - - addr &= 0xffffff; - - pclog("RIVA 128 MMIO write %08X %08X %04X:%08X\n", addr, val, CS, cpu_state.pc); - - switch(addr) - { - case 0x000000 ... 0x000fff: - riva128_pmc_write(addr, val, riva128); - break; - case 0x001000 ... 0x001fff: - riva128_pbus_write(addr, val, riva128); - break; - case 0x002000 ... 0x002fff: - riva128_pfifo_write(addr, val, riva128); - break; - case 0x100000 ... 0x100fff: - riva128_pfb_write(addr, val, riva128); - break; - case 0x680000 ... 0x680fff: - riva128_pramdac_write(addr, val, riva128); - break; - case 0x800000 ... 0xffffff: - riva128_user_write(addr, val, riva128); - break; - } -} - -static void riva128_ptimer_tick(void *p) -{ - riva128_t *riva128 = (riva128_t *)p; - svga_t *svga = &riva128->svga; - - uint64_t time = riva128->ptimer.clock_mul - riva128->ptimer.clock_div; - - time *= 1000; - - uint64_t tmp = riva128->ptimer.time; - riva128->ptimer.time += time << 5; - - if((tmp < riva128->ptimer.alarm) && (riva128->ptimer.time >= riva128->ptimer.alarm)) riva128_ptimer_interrupt(0, riva128); -} - -static void riva128_mclk_poll(void *p) -{ - riva128_t *riva128 = (riva128_t *)p; - svga_t *svga = &riva128->svga; - - if(riva128->card_id == 0x03) riva128_ptimer_tick(riva128); - - riva128->mtime += cpuclock / riva128->mfreq; -} - -static void riva128_nvclk_poll(void *p) -{ - riva128_t *riva128 = (riva128_t *)p; - svga_t *svga = &riva128->svga; - - if(riva128->card_id > 0x40 && riva128->card_id != 0x03) riva128_ptimer_tick(riva128); - - riva128->nvtime += cpuclock / riva128->nvfreq; -} - -static uint8_t riva128_rma_in(uint16_t addr, void *p) -{ - riva128_t *riva128 = (riva128_t *)p; - svga_t *svga = &riva128->svga; - uint8_t ret = 0; - - addr &= 0xff; - - //pclog("RIVA 128 RMA read %04X %04X:%08X\n", addr, CS, cpu_state.pc); - - switch(addr) - { - case 0x00: ret = 0x65; break; - case 0x01: ret = 0xd0; break; - case 0x02: ret = 0x16; break; - case 0x03: ret = 0x2b; break; - case 0x08: case 0x09: case 0x0a: case 0x0b: ret = riva128_mmio_read(riva128->rma.addr + (addr & 3), riva128); break; - } - - return ret; -} - -static void riva128_rma_out(uint16_t addr, uint8_t val, void *p) -{ - riva128_t *riva128 = (riva128_t *)p; - svga_t *svga = &riva128->svga; - - addr &= 0xff; - - //pclog("RIVA 128 RMA write %04X %02X %04X:%08X\n", addr, val, CS, cpu_state.pc); - - switch(addr) - { - case 0x04: - riva128->rma.addr &= ~0xff; - riva128->rma.addr |= val; - break; - case 0x05: - riva128->rma.addr &= ~0xff00; - riva128->rma.addr |= (val << 8); - break; - case 0x06: - riva128->rma.addr &= ~0xff0000; - riva128->rma.addr |= (val << 16); - break; - case 0x07: - riva128->rma.addr &= ~0xff000000; - riva128->rma.addr |= (val << 24); - break; - case 0x08: case 0x0c: case 0x10: case 0x14: - riva128->rma.data &= ~0xff; - riva128->rma.data |= val; - break; - case 0x09: case 0x0d: case 0x11: case 0x15: - riva128->rma.data &= ~0xff00; - riva128->rma.data |= (val << 8); - break; - case 0x0a: case 0x0e: case 0x12: case 0x16: - riva128->rma.data &= ~0xff0000; - riva128->rma.data |= (val << 16); - break; - case 0x0b: case 0x0f: case 0x13: case 0x17: - riva128->rma.data &= ~0xff000000; - riva128->rma.data |= (val << 24); - if(riva128->rma.addr < 0x1000000) riva128_mmio_write_l(riva128->rma.addr & 0xffffff, riva128->rma.data, riva128); - else svga_writel_linear((riva128->rma.addr - 0x1000000), riva128->rma.data, svga); - break; - } - - if(addr & 0x10) riva128->rma.addr+=4; -} - -static uint8_t riva128_in(uint16_t addr, void *p) -{ - riva128_t *riva128 = (riva128_t *)p; - svga_t *svga = &riva128->svga; - uint8_t ret = 0; - - switch (addr) - { - case 0x3D0 ... 0x3D3: - //pclog("RIVA 128 RMA BAR Register read %04X %04X:%08X\n", addr, CS, cpu_state.pc); - if(!(riva128->rma.mode & 1)) return ret; - ret = riva128_rma_in(riva128->rma_addr + ((riva128->rma.mode & 0xe) << 1) + (addr & 3), riva128); - return ret; - } - - if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) - addr ^= 0x60; - - // if (addr != 0x3da) pclog("S3 in %04X %04X:%08X ", addr, CS, cpu_state.pc); - switch (addr) - { - case 0x3D4: - ret = svga->crtcreg; - break; - case 0x3D5: - switch(svga->crtcreg) - { - case 0x3e: - ret = (riva128->i2c.sda << 3) | (riva128->i2c.scl << 2); - break; - default: - ret = svga->crtc[svga->crtcreg]; - break; - } - //if(svga->crtcreg > 0x18) - // pclog("RIVA 128 Extended CRTC read %02X %04X:%08X\n", svga->crtcreg, CS, cpu_state.pc); - break; - default: - ret = svga_in(addr, svga); - break; - } - // if (addr != 0x3da) pclog("%02X\n", ret); - return ret; -} - -static void riva128_out(uint16_t addr, uint8_t val, void *p) -{ - riva128_t *riva128 = (riva128_t *)p; - svga_t *svga = &riva128->svga; - - uint8_t old; - - switch(addr) - { - case 0x3D0 ... 0x3D3: - //pclog("RIVA 128 RMA BAR Register write %04X %02x %04X:%08X\n", addr, val, CS, cpu_state.pc); - riva128->rma.access_reg[addr & 3] = val; - if(!(riva128->rma.mode & 1)) return; - riva128_rma_out(riva128->rma_addr + ((riva128->rma.mode & 0xe) << 1) + (addr & 3), riva128->rma.access_reg[addr & 3], riva128); - return; - } - - if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) - addr ^= 0x60; - - switch(addr) - { - case 0x3D4: - svga->crtcreg = val; - return; - case 0x3D5: - if ((svga->crtcreg < 7) && (svga->crtc[0x11] & 0x80)) - return; - if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80)) - val = (svga->crtc[7] & ~0x10) | (val & 0x10); - old = svga->crtc[svga->crtcreg]; - svga->crtc[svga->crtcreg] = val; - switch(svga->crtcreg) - { - case 0x1a: - svga_recalctimings(svga); - break; - case 0x1e: - riva128->read_bank = val; - if (svga->chain4) svga->read_bank = riva128->read_bank << 15; - else svga->read_bank = riva128->read_bank << 13; - break; - case 0x1d: - riva128->write_bank = val; - if (svga->chain4) svga->write_bank = riva128->write_bank << 15; - else svga->write_bank = riva128->write_bank << 13; - break; - case 0x26: - if (!svga->attrff) - svga->attraddr = val & 31; - break; - case 0x19: - case 0x25: - case 0x28: - case 0x2d: - svga_recalctimings(svga); - break; - case 0x38: - riva128->rma.mode = val & 0xf; - break; - case 0x3f: - riva128->i2c.scl = (val & 0x20) ? 1 : 0; - riva128->i2c.sda = (val & 0x10) ? 1 : 0; - break; - } - //if(svga->crtcreg > 0x18) - // pclog("RIVA 128 Extended CRTC write %02X %02x %04X:%08X\n", svga->crtcreg, val, CS, cpu_state.pc); - if (old != val) - { - if (svga->crtcreg < 0xE || svga->crtcreg > 0x10) - { - svga->fullchange = changeframecount; - svga_recalctimings(svga); - } - } - return; - } - - svga_out(addr, val, svga); -} - -static uint32_t riva128_ramin_readl(uint32_t addr, void *p) -{ - riva128_t *riva128 = (riva128_t *)p; - svga_t *svga = &riva128->svga; - uint32_t ret = riva128->pramin[(addr & 0x1ffffc) >> 2]; - return ret; -} - -static uint8_t riva128_ramin_readb(uint32_t addr, void *p) -{ - riva128_t *riva128 = (riva128_t *)p; - svga_t *svga = &riva128->svga; - uint32_t ret = riva128->pramin[(addr & 0x1ffffc) >> 2]; - ret >>= 24 - ((addr & 3) << 3); - return ret; -} - -static uint16_t riva128_ramin_readw(uint32_t addr, void *p) -{ - riva128_t *riva128 = (riva128_t *)p; - svga_t *svga = &riva128->svga; - uint32_t ret = riva128->pramin[(addr & 0x1ffffc) >> 2]; - ret >>= 16 - ((addr & 2) << 3); - return ret; -} - -static void riva128_ramin_writel(uint32_t addr, uint32_t val, void *p) -{ - riva128_t *riva128 = (riva128_t *)p; - svga_t *svga = &riva128->svga; - riva128->pramin[(addr & 0x1ffffc) >> 2] = val; -} - -static void riva128_ramin_writeb(uint32_t addr, uint8_t val, void *p) -{ - riva128_t *riva128 = (riva128_t *)p; - svga_t *svga = &riva128->svga; - uint32_t tmp = riva128_ramin_readl(addr,p); - tmp &= ~(0xff << ((addr & 3) << 3)); - tmp |= val << ((addr & 3) << 3); - riva128_ramin_writel(addr, tmp, p); -} - -static void riva128_ramin_writew(uint32_t addr, uint16_t val, void *p) -{ - riva128_t *riva128 = (riva128_t *)p; - svga_t *svga = &riva128->svga; - uint32_t tmp = riva128_ramin_readl(addr,p); - tmp &= ~(0xffff << ((addr & 2) << 4)); - tmp |= val << ((addr & 2) << 4); - riva128_ramin_writel(addr, tmp, p); -} - -static uint8_t riva128_pci_read(int func, int addr, void *p) -{ - riva128_t *riva128 = (riva128_t *)p; - svga_t *svga = &riva128->svga; - uint8_t ret = 0; - //pclog("RIVA 128 PCI read %02X %04X:%08X\n", addr, CS, cpu_state.pc); - switch (addr) - { - case 0x00: ret = riva128->vendor_id & 0xff; break; - case 0x01: ret = riva128->vendor_id >> 8; break; - - case 0x02: ret = riva128->device_id & 0xff; break; - case 0x03: ret = riva128->device_id >> 8; break; - - case 0x04: ret = riva128->pci_regs[0x04] & 0x37; break; - case 0x05: ret = riva128->pci_regs[0x05] & 0x01; break; - - case 0x06: ret = 0x20; break; - case 0x07: ret = riva128->pci_regs[0x07] & 0x73; break; - - case 0x08: ret = 0x01; break; /*Revision ID*/ - case 0x09: ret = 0; break; /*Programming interface*/ - - case 0x0a: ret = 0x00; break; /*Supports VGA interface*/ - case 0x0b: ret = 0x03; /*output = 3; */break; - - case 0x0e: ret = 0x00; break; /*Header type*/ - - case 0x13: - case 0x17: - ret = riva128->pci_regs[addr]; - break; - - case 0x2c: case 0x2d: case 0x2e: case 0x2f: - ret = riva128->pci_regs[addr]; - //if(CS == 0x0028) output = 3; - break; - - case 0x30: return riva128->pci_regs[0x30] & 0x01; /*BIOS ROM address*/ - case 0x31: return 0x00; - case 0x32: return riva128->pci_regs[0x32]; - case 0x33: return riva128->pci_regs[0x33]; - - case 0x34: ret = 0x00; break; - - case 0x3c: ret = riva128->pci_regs[0x3c]; break; - - case 0x3d: ret = 0x01; break; /*INTA*/ - - case 0x3e: ret = 0x03; break; - case 0x3f: ret = 0x01; break; - - } - // pclog("%02X\n", ret); - return ret; -} - -static void riva128_reenable_svga_mappings(svga_t *svga) -{ - switch (svga->gdcreg[6] & 0xc) /*Banked framebuffer*/ - { - case 0x0: /*128k at A0000*/ - mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x20000); - svga->banked_mask = 0xffff; - break; - case 0x4: /*64k at A0000*/ - mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x10000); - svga->banked_mask = 0xffff; - break; - case 0x8: /*32k at B0000*/ - mem_mapping_set_addr(&svga->mapping, 0xb0000, 0x08000); - svga->banked_mask = 0x7fff; - break; - case 0xC: /*32k at B8000*/ - mem_mapping_set_addr(&svga->mapping, 0xb8000, 0x08000); - svga->banked_mask = 0x7fff; - break; - } -} - -static void riva128_pci_write(int func, int addr, uint8_t val, void *p) -{ - //pclog("RIVA 128 PCI write %02X %02X %04X:%08X\n", addr, val, CS, cpu_state.pc); - riva128_t *riva128 = (riva128_t *)p; - svga_t *svga = &riva128->svga; - switch (addr) - { - case 0x00: case 0x01: case 0x02: case 0x03: - case 0x08: case 0x09: case 0x0a: case 0x0b: - case 0x3d: case 0x3e: case 0x3f: - return; - - case PCI_REG_COMMAND: - riva128->pci_regs[PCI_REG_COMMAND] = val & 0x27; - io_removehandler(0x03c0, 0x0020, riva128_in, NULL, NULL, riva128_out, NULL, NULL, riva128); - mem_mapping_disable(&svga->mapping); - mem_mapping_disable(&riva128->mmio_mapping); - mem_mapping_disable(&riva128->linear_mapping); - mem_mapping_disable(&riva128->ramin_mapping); - if (val & PCI_COMMAND_IO) - { - io_sethandler(0x03c0, 0x0020, riva128_in, NULL, NULL, riva128_out, NULL, NULL, riva128); - } - if (val & PCI_COMMAND_MEM) - { - uint32_t mmio_addr = riva128->pci_regs[0x13] << 24; - uint32_t linear_addr = riva128->pci_regs[0x17] << 24; - if (!mmio_addr && !linear_addr) - { - riva128_reenable_svga_mappings(svga); - } - if (mmio_addr) - { - mem_mapping_set_addr(&riva128->mmio_mapping, mmio_addr, 0x1000000); - } - if (linear_addr) - { - mem_mapping_set_addr(&riva128->linear_mapping, linear_addr, 0xc00000); - mem_mapping_set_addr(&riva128->ramin_mapping, linear_addr + 0xc00000, 0x200000); - svga->linear_base = linear_addr; - } - } - return; - - case 0x05: - riva128->pci_regs[0x05] = val & 0x01; - return; - - case 0x07: - riva128->pci_regs[0x07] = (riva128->pci_regs[0x07] & 0x8f) | (val & 0x70); - return; - - case 0x13: - { - riva128->pci_regs[addr] = val; - uint32_t mmio_addr = riva128->pci_regs[0x13] << 24; - mem_mapping_disable(&riva128->mmio_mapping); - if (mmio_addr) - { - mem_mapping_set_addr(&riva128->mmio_mapping, mmio_addr, 0x1000000); - } - return; - } - - case 0x17: - { - riva128->pci_regs[addr] = val; - uint32_t linear_addr = riva128->pci_regs[0x17] << 24; - mem_mapping_disable(&riva128->linear_mapping); - mem_mapping_disable(&riva128->ramin_mapping); - if (linear_addr) - { - mem_mapping_set_addr(&riva128->linear_mapping, linear_addr, 0xc00000); - mem_mapping_set_addr(&riva128->ramin_mapping, linear_addr + 0xc00000, 0x200000); - svga->linear_base = linear_addr; - } - return; - } - - case 0x30: case 0x32: case 0x33: - riva128->pci_regs[addr] = val; - mem_mapping_disable(&riva128->bios_rom.mapping); - if (riva128->pci_regs[0x30] & 0x01) - { - uint32_t addr = (riva128->pci_regs[0x32] << 16) | (riva128->pci_regs[0x33] << 24); - // pclog("RIVA 128 bios_rom enabled at %08x\n", addr); - mem_mapping_set_addr(&riva128->bios_rom.mapping, addr, 0x8000); - } - return; - - case 0x3c: - riva128->pci_regs[0x3c] = val & 0x0f; - return; - - case 0x40: case 0x41: case 0x42: case 0x43: - riva128->pci_regs[addr - 0x14] = val; //0x40-0x43 are ways to write to 0x2c-0x2f - return; - } -} - -static void rivatnt_pci_write(int func, int addr, uint8_t val, void *p) -{ - //pclog("RIVA 128 PCI write %02X %02X %04X:%08X\n", addr, val, CS, cpu_state.pc); - riva128_t *riva128 = (riva128_t *)p; - svga_t *svga = &riva128->svga; - switch (addr) - { - case 0x00: case 0x01: case 0x02: case 0x03: - case 0x08: case 0x09: case 0x0a: case 0x0b: - case 0x3d: case 0x3e: case 0x3f: - return; - - case PCI_REG_COMMAND: - riva128->pci_regs[PCI_REG_COMMAND] = val & 0x27; - io_removehandler(0x03c0, 0x0020, riva128_in, NULL, NULL, riva128_out, NULL, NULL, riva128); - mem_mapping_disable(&svga->mapping); - mem_mapping_disable(&riva128->mmio_mapping); - mem_mapping_disable(&riva128->linear_mapping); - if (val & PCI_COMMAND_IO) - { - io_sethandler(0x03c0, 0x0020, riva128_in, NULL, NULL, riva128_out, NULL, NULL, riva128); - } - if (val & PCI_COMMAND_MEM) - { - uint32_t mmio_addr = riva128->pci_regs[0x13] << 24; - uint32_t linear_addr = riva128->pci_regs[0x17] << 24; - if (!mmio_addr && !linear_addr) - { - riva128_reenable_svga_mappings(svga); - } - if (mmio_addr) - { - mem_mapping_set_addr(&riva128->mmio_mapping, mmio_addr, 0x1000000); - } - if (linear_addr) - { - mem_mapping_set_addr(&riva128->linear_mapping, linear_addr, 0x1000000); - svga->linear_base = linear_addr; - } - } - return; - - case 0x05: - riva128->pci_regs[0x05] = val & 0x01; - return; - - case 0x07: - riva128->pci_regs[0x07] = (riva128->pci_regs[0x07] & 0x8f) | (val & 0x70); - return; - - case 0x13: - { - riva128->pci_regs[addr] = val; - uint32_t mmio_addr = riva128->pci_regs[0x13] << 24; - mem_mapping_disable(&riva128->mmio_mapping); - if (mmio_addr) - { - mem_mapping_set_addr(&riva128->mmio_mapping, mmio_addr, 0x1000000); - } - return; - } - - case 0x17: - { - riva128->pci_regs[addr] = val; - uint32_t linear_addr = riva128->pci_regs[0x17] << 24; - mem_mapping_disable(&riva128->linear_mapping); - if (linear_addr) - { - mem_mapping_set_addr(&riva128->linear_mapping, linear_addr, 0x1000000); - svga->linear_base = linear_addr; - } - return; - } - - case 0x30: case 0x32: case 0x33: - riva128->pci_regs[addr] = val; - mem_mapping_disable(&riva128->bios_rom.mapping); - if (riva128->pci_regs[0x30] & 0x01) - { - uint32_t addr = (riva128->pci_regs[0x32] << 16) | (riva128->pci_regs[0x33] << 24); - // pclog("RIVA TNT bios_rom enabled at %08x\n", addr); - mem_mapping_set_addr(&riva128->bios_rom.mapping, addr, 0x10000); - } - return; - - case 0x3c: - riva128->pci_regs[0x3c] = val & 0x0f; - return; - - case 0x40: case 0x41: case 0x42: case 0x43: - riva128->pci_regs[addr - 0x14] = val; //0x40-0x43 are ways to write to 0x2c-0x2f - return; - } -} - -static void riva128_recalctimings(svga_t *svga) -{ - riva128_t *riva128 = (riva128_t *)svga->p; - - svga->ma_latch += (svga->crtc[0x19] & 0x1f) << 16; - svga->rowoffset += (svga->crtc[0x19] & 0xe0) << 3; - if (svga->crtc[0x25] & 0x01) svga->vtotal += 0x400; - if (svga->crtc[0x25] & 0x02) svga->dispend += 0x400; - if (svga->crtc[0x25] & 0x04) svga->vblankstart += 0x400; - if (svga->crtc[0x25] & 0x08) svga->vsyncstart += 0x400; - if (svga->crtc[0x25] & 0x10) svga->htotal += 0x100; - if (svga->crtc[0x2d] & 0x01) svga->hdisp += 0x100; - //The effects of the large screen bit seem to just be doubling the row offset. - //However, these large modes still don't work. Possibly core SVGA bug? It does report 640x2 res after all. - if (!(svga->crtc[0x1a] & 0x04)) svga->rowoffset <<= 1; - switch(svga->crtc[0x28] & 3) - { - case 1: - svga->bpp = 8; - svga->lowres = 0; - svga->render = svga_render_8bpp_highres; - break; - case 2: - svga->bpp = 16; - svga->lowres = 0; - svga->render = svga_render_16bpp_highres; - break; - case 3: - svga->bpp = 32; - svga->lowres = 0; - svga->render = svga_render_32bpp_highres; - break; - } - - /*if((svga->crtc[0x28] & 3) != 0) - { - if(svga->crtc[0x1a] & 2) svga_set_ramdac_type(svga, RAMDAC_6BIT); - else svga_set_ramdac_type(svga, RAMDAC_8BIT); - } - else svga_set_ramdac_type(svga, RAMDAC_6BIT);*/ - - double freq; - - if (((svga->miscout >> 2) & 2) == 2) - { - freq = 13500000.0; - - if(riva128->pramdac.v_m == 0) freq = 0; - else - { - freq = (freq * riva128->pramdac.v_n) / (1 << riva128->pramdac.v_p) / riva128->pramdac.v_m; - //pclog("RIVA 128 Pixel clock is %f Hz\n", freq); - } - - svga->clock = cpuclock / freq; - } - - freq = 13500.0; - - if(riva128->pramdac.nv_m == 0) freq = 0; - else - { - freq = (freq * riva128->pramdac.nv_n) / (1 << riva128->pramdac.nv_p) / riva128->pramdac.nv_m; - //pclog("RIVA 128 Core clock is %f Hz\n", freq); - } - - riva128->mfreq = freq; - - freq = 13500.0; - - if(riva128->pramdac.m_m == 0) freq = 0; - else - { - freq = (freq * riva128->pramdac.m_n) / (1 << riva128->pramdac.m_p) / riva128->pramdac.m_m; - //pclog("RIVA 128 Core clock is %f Hz\n", freq); - } - - riva128->nvfreq = freq; -} - -static void *riva128_init() -{ - riva128_t *riva128 = malloc(sizeof(riva128_t)); - memset(riva128, 0, sizeof(riva128_t)); - - riva128->card_id = 0x03; - riva128->is_nv3t = 0; - - riva128->vendor_id = 0x12d2; - riva128->device_id = 0x0018; - - riva128->memory_size = device_get_config_int("memory"); - - riva128->pgraph.pgraph_speedhack = device_get_config_int("pgraph_speedhack"); - - svga_init(&riva128->svga, riva128, riva128->memory_size << 20, - riva128_recalctimings, - riva128_in, riva128_out, - NULL, NULL); - - rom_init(&riva128->bios_rom, "roms/Diamond_V330_rev-e.vbi", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); - if (PCI) - mem_mapping_disable(&riva128->bios_rom.mapping); - - mem_mapping_add(&riva128->mmio_mapping, 0, 0, - riva128_mmio_read, - riva128_mmio_read_w, - riva128_mmio_read_l, - riva128_mmio_write, - riva128_mmio_write_w, - riva128_mmio_write_l, - NULL, - 0, - riva128); - - mem_mapping_add(&riva128->ramin_mapping, 0, 0, - riva128_ramin_readb, - riva128_ramin_readw, - riva128_ramin_readl, - riva128_ramin_writeb, - riva128_ramin_writew, - riva128_ramin_writel, - NULL, - 0, - riva128); - - mem_mapping_add(&riva128->linear_mapping, 0, 0, - svga_read_linear, - svga_readw_linear, - svga_readl_linear, - svga_write_linear, - svga_writew_linear, - svga_writel_linear, - NULL, - 0, - &riva128->svga); - - io_sethandler(0x03c0, 0x0020, riva128_in, NULL, NULL, riva128_out, NULL, NULL, riva128); - - // riva128->pci_regs[4] = 3; - riva128->pci_regs[4] = 7; - riva128->pci_regs[5] = 0; - riva128->pci_regs[6] = 0; - riva128->pci_regs[7] = 2; - - riva128->pci_regs[0x2c] = 0x02; - riva128->pci_regs[0x2d] = 0x11; - riva128->pci_regs[0x2e] = 0x16; - riva128->pci_regs[0x2f] = 0x10; - - riva128->pci_regs[0x30] = 0x00; - riva128->pci_regs[0x32] = 0x0c; - riva128->pci_regs[0x33] = 0x00; - - //riva128->pci_regs[0x3c] = 3; - - riva128->pmc.intr = 0; - riva128->pbus.intr = 0; - riva128->pfifo.intr = 0; - riva128->pgraph.intr = 0; - - pci_add(riva128_pci_read, riva128_pci_write, riva128); - - //Some bullshit default values so that the emulator won't shit itself trying to boot. These'll be overwritten by the video BIOS anyway. - riva128->pramdac.m_m = 0x03; - riva128->pramdac.m_n = 0xc2; - riva128->pramdac.m_p = 0x0d; - - riva128->pramdac.nv_m = 0x03; - riva128->pramdac.nv_n = 0xc2; - riva128->pramdac.nv_p = 0x0d; - - timer_add(riva128_mclk_poll, &riva128->mtime, TIMER_ALWAYS_ENABLED, riva128); - timer_add(riva128_nvclk_poll, &riva128->nvtime, TIMER_ALWAYS_ENABLED, riva128); - - return riva128; -} - -static void riva128_close(void *p) -{ - riva128_t *riva128 = (riva128_t *)p; - FILE *f = fopen("vram.dmp", "wb"); - fwrite(riva128->svga.vram, 4 << 20, 1, f); - fclose(f); - - svga_close(&riva128->svga); - - free(riva128); -} - -static int riva128_available() -{ - return rom_present("roms/Diamond_V330_rev-e.vbi"); -} - -static void riva128_speed_changed(void *p) -{ - riva128_t *riva128 = (riva128_t *)p; - - svga_recalctimings(&riva128->svga); -} - -static void riva128_force_redraw(void *p) -{ - riva128_t *riva128 = (riva128_t *)p; - - riva128->svga.fullchange = changeframecount; -} - -static void riva128_add_status_info(char *s, int max_len, void *p) -{ - riva128_t *riva128 = (riva128_t *)p; - - svga_add_status_info(s, max_len, &riva128->svga); -} - -static device_config_t riva128_config[] = -{ - { - .name = "memory", - .description = "Memory size", - .type = CONFIG_SELECTION, - .selection = - { - { - .description = "1 MB", - .value = 1 - }, - { - .description = "2 MB", - .value = 2 - }, - { - .description = "4 MB", - .value = 4 - }, - { - .description = "" - } - }, - .default_int = 4 - }, - { - .type = -1 - } -}; - -static device_config_t riva128zx_config[] = -{ - { - .name = "pgraph_speedhack", - .description = "PGRAPH speedhack", - .type = CONFIG_SELECTION, - .selection = - { - { - .description = "Off", - .value = 0, - }, - { - .description = "On", - .value = 1, - }, - { - .description = "" - } - }, - //DO NOT TURN THIS OFF YET. THE PGRAPH SPEEDHACK IS CURRENTLY NECESSARY FOR WORKING EMULATION. - .default_int = 1 - }, - { - .name = "memory", - .description = "Memory size", - .type = CONFIG_SELECTION, - .selection = - { - { - .description = "1 MB", - .value = 1 - }, - { - .description = "2 MB", - .value = 2 - }, - { - .description = "4 MB", - .value = 4 - }, - { - .description = "8 MB", - .value = 8 - }, - { - .description = "" - } - }, - .default_int = 4 - }, - { - .type = -1 - } -}; - -device_t riva128_device = -{ - "nVidia RIVA 128", - 0, - riva128_init, - riva128_close, - riva128_available, - riva128_speed_changed, - riva128_force_redraw, - riva128_add_status_info, - riva128_config -}; - -static void *rivatnt_init() -{ - riva128_t *riva128 = malloc(sizeof(riva128_t)); - memset(riva128, 0, sizeof(riva128_t)); - - riva128->card_id = 0x04; - riva128->is_nv3t = 0; - - riva128->vendor_id = 0x10de; - riva128->device_id = 0x0020; - - riva128->memory_size = device_get_config_int("memory"); - - svga_init(&riva128->svga, riva128, riva128->memory_size << 20, - riva128_recalctimings, - riva128_in, riva128_out, - NULL, NULL); - - rom_init(&riva128->bios_rom, "roms/NV4_diamond_revB.rom", 0xc0000, 0x10000, 0xffff, 0, MEM_MAPPING_EXTERNAL); - if (PCI) - mem_mapping_disable(&riva128->bios_rom.mapping); - - mem_mapping_add(&riva128->mmio_mapping, 0, 0, - riva128_mmio_read, - riva128_mmio_read_w, - riva128_mmio_read_l, - riva128_mmio_write, - riva128_mmio_write_w, - riva128_mmio_write_l, - NULL, - 0, - riva128); - mem_mapping_add(&riva128->linear_mapping, 0, 0, - svga_read_linear, - svga_readw_linear, - svga_readl_linear, - svga_write_linear, - svga_writew_linear, - svga_writel_linear, - NULL, - 0, - &riva128->svga); - - io_sethandler(0x03c0, 0x0020, riva128_in, NULL, NULL, riva128_out, NULL, NULL, riva128); - - // riva128->pci_regs[4] = 3; - riva128->pci_regs[4] = 7; - riva128->pci_regs[5] = 0; - riva128->pci_regs[6] = 0; - riva128->pci_regs[7] = 2; - - riva128->pci_regs[0x2c] = 0x02; - riva128->pci_regs[0x2d] = 0x11; - riva128->pci_regs[0x2e] = 0x16; - riva128->pci_regs[0x2f] = 0x10; - - riva128->pci_regs[0x30] = 0x00; - riva128->pci_regs[0x32] = 0x0c; - riva128->pci_regs[0x33] = 0x00; - - //riva128->pci_regs[0x3c] = 3; - - riva128->pmc.intr = 0; - riva128->pbus.intr = 0; - riva128->pfifo.intr = 0; - riva128->pgraph.intr = 0; - - pci_add(riva128_pci_read, rivatnt_pci_write, riva128); - - //Some bullshit default values so that the emulator won't shit itself trying to boot. These'll be overwritten by the video BIOS anyway. - riva128->pramdac.m_m = 0x03; - riva128->pramdac.m_n = 0xc2; - riva128->pramdac.m_p = 0x0d; - - riva128->pramdac.nv_m = 0x03; - riva128->pramdac.nv_n = 0xc2; - riva128->pramdac.nv_p = 0x0d; - - timer_add(riva128_mclk_poll, &riva128->mtime, TIMER_ALWAYS_ENABLED, riva128); - timer_add(riva128_nvclk_poll, &riva128->nvtime, TIMER_ALWAYS_ENABLED, riva128); - - return riva128; -} - -static void rivatnt_close(void *p) -{ - riva128_t *riva128 = (riva128_t *)p; - FILE *f = fopen("vram.dmp", "wb"); - fwrite(riva128->svga.vram, 4 << 20, 1, f); - fclose(f); - - svga_close(&riva128->svga); - - free(riva128); -} - -static int rivatnt_available() -{ - return rom_present("roms/NV4_diamond_revB.rom"); -} - -static void rivatnt_speed_changed(void *p) -{ - riva128_t *riva128 = (riva128_t *)p; - - svga_recalctimings(&riva128->svga); -} - -static void rivatnt_force_redraw(void *p) -{ - riva128_t *riva128 = (riva128_t *)p; - - riva128->svga.fullchange = changeframecount; -} - -static void rivatnt_add_status_info(char *s, int max_len, void *p) -{ - riva128_t *riva128 = (riva128_t *)p; - - svga_add_status_info(s, max_len, &riva128->svga); -} - -static device_config_t rivatnt_config[] = -{ - { - .name = "memory", - .description = "Memory size", - .type = CONFIG_SELECTION, - .selection = - { - { - .description = "4 MB", - .value = 4 - }, - { - .description = "8 MB", - .value = 8 - }, - { - .description = "16 MB", - .value = 16 - }, - { - .description = "" - } - }, - .default_int = 16 - }, - { - .type = -1 - } -}; - -device_t rivatnt_device = -{ - "nVidia RIVA TNT", - 0, - rivatnt_init, - rivatnt_close, - rivatnt_available, - rivatnt_speed_changed, - rivatnt_force_redraw, - rivatnt_add_status_info, - rivatnt_config -}; - -static void *rivatnt2_init() -{ - riva128_t *riva128 = malloc(sizeof(riva128_t)); - memset(riva128, 0, sizeof(riva128_t)); - - riva128->card_id = 0x05; - riva128->is_nv3t = 0; - - int model = device_get_config_int("model"); - - riva128->vendor_id = 0x10de; - riva128->device_id = ((model > 1) ? 0x0029 : 0x0028); - - riva128->memory_size = device_get_config_int("memory"); - - svga_init(&riva128->svga, riva128, riva128->memory_size << 20, - riva128_recalctimings, - riva128_in, riva128_out, - NULL, NULL); - - switch(model) - { - case 0: rom_init(&riva128->bios_rom, "roms/NV5diamond.bin", 0xc0000, 0x10000, 0xffff, 0, MEM_MAPPING_EXTERNAL); break; - case 1: rom_init(&riva128->bios_rom, "roms/inno3d64bit.BIN", 0xc0000, 0x10000, 0xffff, 0, MEM_MAPPING_EXTERNAL); break; - case 2: rom_init(&riva128->bios_rom, "roms/creative.BIN", 0xc0000, 0x10000, 0xffff, 0, MEM_MAPPING_EXTERNAL); break; - } - if (PCI) - mem_mapping_disable(&riva128->bios_rom.mapping); - - mem_mapping_add(&riva128->mmio_mapping, 0, 0, - riva128_mmio_read, - riva128_mmio_read_w, - riva128_mmio_read_l, - riva128_mmio_write, - riva128_mmio_write_w, - riva128_mmio_write_l, - NULL, - 0, - riva128); - mem_mapping_add(&riva128->linear_mapping, 0, 0, - svga_read_linear, - svga_readw_linear, - svga_readl_linear, - svga_write_linear, - svga_writew_linear, - svga_writel_linear, - NULL, - 0, - &riva128->svga); - - io_sethandler(0x03c0, 0x0020, riva128_in, NULL, NULL, riva128_out, NULL, NULL, riva128); - - // riva128->pci_regs[4] = 3; - riva128->pci_regs[4] = 7; - riva128->pci_regs[5] = 0; - riva128->pci_regs[6] = 0; - riva128->pci_regs[7] = 2; - - riva128->pci_regs[0x2c] = 0x02; - riva128->pci_regs[0x2d] = 0x11; - riva128->pci_regs[0x2e] = 0x16; - riva128->pci_regs[0x2f] = 0x10; - - riva128->pci_regs[0x30] = 0x00; - riva128->pci_regs[0x32] = 0x0c; - riva128->pci_regs[0x33] = 0x00; - - //riva128->pci_regs[0x3c] = 3; - - riva128->pmc.intr = 0; - riva128->pbus.intr = 0; - riva128->pfifo.intr = 0; - riva128->pgraph.intr = 0; - - pci_add(riva128_pci_read, rivatnt_pci_write, riva128); - - //Some bullshit default values so that the emulator won't shit itself trying to boot. These'll be overwritten by the video BIOS anyway. - riva128->pramdac.m_m = 0x03; - riva128->pramdac.m_n = 0xc2; - riva128->pramdac.m_p = 0x0d; - - riva128->pramdac.nv_m = 0x03; - riva128->pramdac.nv_n = 0xc2; - riva128->pramdac.nv_p = 0x0d; - - timer_add(riva128_mclk_poll, &riva128->mtime, TIMER_ALWAYS_ENABLED, riva128); - timer_add(riva128_nvclk_poll, &riva128->nvtime, TIMER_ALWAYS_ENABLED, riva128); - - return riva128; -} - -static void rivatnt2_close(void *p) -{ - riva128_t *riva128 = (riva128_t *)p; - FILE *f = fopen("vram.dmp", "wb"); - fwrite(riva128->svga.vram, 4 << 20, 1, f); - fclose(f); - - svga_close(&riva128->svga); - - free(riva128); -} - -static int rivatnt2_available() -{ - return rom_present("roms/NV5diamond.bin") || rom_present("roms/inno3d64bit.BIN") || rom_present("roms/creative.BIN"); -} - -static void rivatnt2_speed_changed(void *p) -{ - riva128_t *riva128 = (riva128_t *)p; - - svga_recalctimings(&riva128->svga); -} - -static void rivatnt2_force_redraw(void *p) -{ - riva128_t *riva128 = (riva128_t *)p; - - riva128->svga.fullchange = changeframecount; -} - -static void rivatnt2_add_status_info(char *s, int max_len, void *p) -{ - riva128_t *riva128 = (riva128_t *)p; - - svga_add_status_info(s, max_len, &riva128->svga); -} - -static device_config_t rivatnt2_config[] = -{ - { - .name = "model", - .description = "Card model", - .type = CONFIG_SELECTION, - .selection = - { - { - .description = "Vanilla TNT2", - .value = 0, - }, - { - .description = "TNT2 Pro", - .value = 1, - }, - { - .description = "TNT2 Ultra", - .value = 2, - }, - }, - .default_int = 0 - }, - { - .name = "memory", - .description = "Memory size", - .type = CONFIG_SELECTION, - .selection = - { - { - .description = "4 MB", - .value = 4 - }, - { - .description = "8 MB", - .value = 8 - }, - { - .description = "16 MB", - .value = 16 - }, - { - .description = "32 MB", - .value = 32 - }, - { - .description = "" - } - }, - .default_int = 32 - }, - { - .type = -1 - } -}; - -device_t rivatnt2_device = -{ - "nVidia RIVA TNT2", - 0, - rivatnt2_init, - rivatnt2_close, - rivatnt2_available, - rivatnt2_speed_changed, - rivatnt2_force_redraw, - rivatnt2_add_status_info, - rivatnt2_config -}; - diff --git a/src/vid_s3.h b/src/vid_s3.h deleted file mode 100644 index 2a1a01f25..000000000 --- a/src/vid_s3.h +++ /dev/null @@ -1,10 +0,0 @@ -/* Copyright holders: Sarah Walker - see COPYING for more details -*/ -device_t s3_bahamas64_device; -device_t s3_9fx_device; -device_t s3_phoenix_trio32_device; -device_t s3_phoenix_trio64_device; -device_t s3_phoenix_vision864_device; -device_t s3_diamond_stealth64_device; -device_t s3_miro_vision964_device; diff --git a/src/w83877f.c b/src/w83877f.c index ef595040f..f9fc3c6ec 100644 --- a/src/w83877f.c +++ b/src/w83877f.c @@ -1,6 +1,19 @@ -/* Copyright holders: Tenshi - see COPYING for more details -*/ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Emulation of the Winbond W83877F Super I/O Chip. + * + * Version: @(#)w83877f.c 1.0.0 2017/05/30 + * + * Author: Miran Grca, + * Copyright 2016-2017 Miran Grca. + */ + /* Winbond W83877F Super I/O Chip Used by the Award 430HX @@ -203,7 +216,7 @@ static void w83877f_remap() winbond_port = (HEFRAS ? 0x3f0 : 0x250); winbond_key_times = HEFRAS + 1; winbond_key = (HEFRAS ? 0x86 : 0x88) | HEFERE; - // pclog("W83877F mapped to %04X, with key %02X required %i times\n", winbond_port, winbond_key, winbond_key_times); + pclog("W83877F: Remapped to port %04X, key %02X\n", winbond_port, winbond_key); } static uint8_t is_in_array(uint16_t *port_array, uint8_t max, uint16_t port) @@ -267,30 +280,42 @@ static uint16_t make_port(uint8_t reg) break; } - // pclog("Made port %04X (reg %02X)\n", p, reg); return p; } +void w83877f_serial_handler(int id) +{ + int reg_mask = (id - 1) ? 0x10 : 0x20; + int reg_id = (id - 1) ? 0x24 : 0x25; + int irq_mask = (id - 1) ? 0xF : 0xF0; + + /* pclog("Registers (%i): %02X %02X %02X\n", id, w83877f_regs[4], w83877f_regs[reg_id], w83877f_regs[0x28]); */ + + if ((w83877f_regs[4] & reg_mask) || !(w83877f_regs[reg_id] & 0xc0)) + { + serial_remove(id); + } + else + { + serial_setup(id, make_port(reg_id), w83877f_regs[0x28] & irq_mask); + } +} + void w83877f_write(uint16_t port, uint8_t val, void *priv) { uint8_t index = (port & 1) ? 0 : 1; uint8_t valxor = 0; uint8_t max = 0x2A; - int temp; if (index) { - // pclog("w83877f_write : port=%04x = %02X locked=%i\n", port, val, w83877f_locked); - if ((val == winbond_key) && !w83877f_locked) { if (winbond_key_times == 2) { if (tries) { - // pclog("W83877F Locked (2 tries)\n"); w83877f_locked = 1; - // fdc_3f1_enable(0); tries = 0; } else @@ -300,23 +325,18 @@ void w83877f_write(uint16_t port, uint8_t val, void *priv) } else { - // pclog("W83877F Locked (1 try)\n"); w83877f_locked = 1; - // fdc_3f1_enable(0); tries = 0; } } else { - // pclog("w83877f_write : port=%04x reg %02X = %02X locked=%i\n", port, w83877f_curreg, val, w83877f_locked); - if (w83877f_locked) { if (val < max) w83877f_curreg = val; if (val == 0xaa) { w83877f_locked = 0; - // fdc_3f1_enable(1); } } else @@ -328,8 +348,6 @@ void w83877f_write(uint16_t port, uint8_t val, void *priv) } else { - // pclog("w83877f_write : port=%04x reg %02X = %02X locked=%i\n", port, w83877f_curreg, val, w83877f_locked); - if (w83877f_locked) { if (w83877f_rw_locked) return; @@ -354,16 +372,11 @@ process_value: case 4: if (valxor & 0x10) { - serial2_remove(); - if (!(w83877f_regs[2] & 0x10)) serial2_set(make_port(0x25), w83877f_regs[0x28] & 0xF); + w83877f_serial_handler(2); } if (valxor & 0x20) { - serial1_remove(); - if (!(w83877f_regs[4] & 0x20)) - { - serial1_set(make_port(0x24), (w83877f_regs[0x28] & 0xF0) >> 8); - } + w83877f_serial_handler(1); } if (valxor & 0x80) { @@ -379,20 +392,17 @@ process_value: } break; case 7: - // pclog("W83877F Write [Reg. %02X]: %02X\n", w83877f_curreg, val); if (valxor & 3) fdc_update_rwc(0, FDDA_TYPE); if (valxor & 0xC) fdc_update_rwc(1, FDDB_TYPE); if (valxor & 0x30) fdc_update_rwc(2, FDDC_TYPE); if (valxor & 0xC0) fdc_update_rwc(3, FDDD_TYPE); break; case 8: - // pclog("W83877F Write [Reg. %02X]: %02X\n", w83877f_curreg, val); if (valxor & 3) fdc_update_boot_drive(FD_BOOT); if (valxor & 0x10) swwp = SWWP ? 1 : 0; if (valxor & 0x20) disable_write = DISFDDWR ? 1 : 0; break; case 9: - // pclog("W83877F Write [Reg. %02X]: %02X\n", w83877f_curreg, val); if (valxor & 0x20) { fdc_update_enh_mode(EN3MODE ? 1 : 0); @@ -403,7 +413,6 @@ process_value: } break; case 0xB: - // pclog("W83877F Write [Reg. %02X]: %02X\n", w83877f_curreg, val); if (valxor & 1) fdc_update_drv2en(DRV2EN_NEG ? 0 : 1); if (valxor & 2) fdc_update_densel_polarity(INVERTZ ? 1 : 0); break; @@ -423,30 +432,27 @@ process_value: case 0x24: if (valxor & 0xfe) { - if (!(w83877f_regs[4] & 0x20)) - { - serial1_set(make_port(0x24), (w83877f_regs[0x28] & 0xF0) >> 8); - } + w83877f_serial_handler(1); } break; case 0x25: if (valxor & 0xfe) { - if (!(w83877f_regs[2] & 0x10)) serial2_set(make_port(0x25), w83877f_regs[0x28] & 0xF); + w83877f_serial_handler(2); } break; case 0x28: if (valxor & 0xf) { if ((w83877f_regs[0x28] & 0xf) == 0) w83877f_regs[0x28] |= 0x3; - if (!(w83877f_regs[2] & 0x10)) serial2_set(make_port(0x25), w83877f_regs[0x28] & 0xF); + if (!(w83877f_regs[2] & 0x10)) serial_setup(2, make_port(0x25), w83877f_regs[0x28] & 0xF); } if (valxor & 0xf0) { if ((w83877f_regs[0x28] & 0xf0) == 0) w83877f_regs[0x28] |= 0x40; if (!(w83877f_regs[4] & 0x20)) { - serial1_set(make_port(0x24), (w83877f_regs[0x28] & 0xF0) >> 8); + serial_setup(1, make_port(0x24), (w83877f_regs[0x28] & 0xF0) >> 8); } } break; @@ -459,13 +465,11 @@ uint8_t w83877f_read(uint16_t port, void *priv) if (!w83877f_locked) { - // pclog("w83877f_read : port=%04x = FF locked=%i\n", port, w83877f_locked); return 0xff; } if (index) { - // pclog("w83877f_read : port=%04x = %02X locked=%i\n", port, w83877f_curreg, w83877f_locked); return w83877f_curreg; } else @@ -473,28 +477,27 @@ uint8_t w83877f_read(uint16_t port, void *priv) if ((w83877f_curreg < 0x18) && w83877f_rw_locked) return 0xff; if (w83877f_curreg == 7) { - // pclog("w83877f_read : port=%04x reg %02X = %02X locked=%i\n", port, w83877f_curreg, (fdc_get_rwc(0) | (fdc_get_rwc(1) << 2)), w83877f_locked); return (fdc_get_rwc(0) | (fdc_get_rwc(1) << 2)); } - // pclog("w83877f_read : port=%04x reg %02X = %02X locked=%i\n", port, w83877f_curreg, w83877f_regs[w83877f_curreg], w83877f_locked); return w83877f_regs[w83877f_curreg]; } } -void w83877f_init() +void w83877f_reset(void) { - fdc_remove(); - fdc_add_for_superio(); lpt1_remove(); lpt1_init(0x378); - lpt2_remove(); + + fdc_remove(); + fdc_add_for_superio(); + w83877f_regs[3] = 0x30; w83877f_regs[7] = 0xF5; w83877f_regs[9] = 0x0A; w83877f_regs[0xA] = 0x1F; w83877f_regs[0xC] = 0x28; w83877f_regs[0xD] = 0xA3; - w83877f_regs[0x16] = 5; + w83877f_regs[0x16] = (romset == ROM_PRESIDENT) ? 4 : 5; w83877f_regs[0x1E] = 0x81; w83877f_regs[0x20] = (0x3f0 >> 2) & 0xfc; w83877f_regs[0x21] = (0x1f0 >> 2) & 0xfc; @@ -519,9 +522,18 @@ void w83877f_init() disable_write = 0; fdc_update_drv2en(1); fdd_setswap(0); - serial1_set(0x3f8, 4); - serial2_set(0x2f8, 3); + serial_setup(1, SERIAL1_ADDR, SERIAL1_IRQ); + serial_setup(2, SERIAL2_ADDR, SERIAL2_IRQ); w83877f_remap(); w83877f_locked = 0; w83877f_rw_locked = 0; } + +void w83877f_init() +{ + lpt2_remove(); + + w83877f_reset(); + + pci_reset_handler.super_io_reset = w83877f_reset; +} diff --git a/src/w83877f.h b/src/w83877f.h index 33120fbde..f4a103c94 100644 --- a/src/w83877f.h +++ b/src/w83877f.h @@ -1,4 +1,17 @@ -/* Copyright holders: Tenshi - see COPYING for more details -*/ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Emulation of the Winbond W83877F Super I/O Chip. + * + * Version: @(#)w83877f.h 1.0.0 2017/05/30 + * + * Author: Miran Grca, + * Copyright 2016-2017 Miran Grca. + */ + extern void w83877f_init(); diff --git a/src/wd76c10.c b/src/wd76c10.c index 595a1d6f3..9644058ae 100644 --- a/src/wd76c10.c +++ b/src/wd76c10.c @@ -50,17 +50,17 @@ void wd76c10_write(uint16_t port, uint16_t val, void *priv) switch ((val >> 5) & 7) { - case 1: serial1_set(0x3f8, 4); break; - case 2: serial1_set(0x2f8, 4); break; - case 3: serial1_set(0x3e8, 4); break; - case 4: serial1_set(0x2e8, 4); break; + case 1: serial_setup(1, 0x3f8, 4); break; + case 2: serial_setup(1, 0x2f8, 4); break; + case 3: serial_setup(1, 0x3e8, 4); break; + case 4: serial_setup(1, 0x2e8, 4); break; } switch ((val >> 1) & 7) { - case 1: serial2_set(0x3f8, 3); break; - case 2: serial2_set(0x2f8, 3); break; - case 3: serial2_set(0x3e8, 3); break; - case 4: serial2_set(0x2e8, 3); break; + case 1: serial_setup(2, 0x3f8, 3); break; + case 2: serial_setup(2, 0x2f8, 3); break; + case 3: serial_setup(2, 0x3e8, 3); break; + case 4: serial_setup(2, 0x2e8, 3); break; } break; diff --git a/src/win-config.c b/src/win-config.c deleted file mode 100644 index c542134ea..000000000 --- a/src/win-config.c +++ /dev/null @@ -1,806 +0,0 @@ -/* Copyright holders: Sarah Walker, Tenshi - see COPYING for more details -*/ -#define BITMAP WINDOWS_BITMAP -#include -#include -#undef BITMAP - -#include - -#include "nethandler.h" -#include "ibm.h" -#include "ide.h" -#include "cpu.h" -#include "device.h" -#include "fdd.h" -#include "gameport.h" -#include "model.h" -#include "mouse.h" -#include "nvr.h" -#include "resources.h" -#include "sound.h" -#include "video.h" -#include "vid_voodoo.h" -#include "win.h" - -extern int is486; -static int romstolist[ROM_MAX], listtomodel[ROM_MAX], romstomodel[ROM_MAX], modeltolist[ROM_MAX]; -static int settings_sound_to_list[20], settings_list_to_sound[20]; -static int settings_mouse_to_list[20], settings_list_to_mouse[20]; -static int settings_network_to_list[20], settings_list_to_network[20]; - -static int mouse_valid(int type, int model) -{ - if (type == MOUSE_TYPE_PS2 && !(models[model].flags & MODEL_PS2)) - return 0; - if (type == MOUSE_TYPE_AMSTRAD && !(models[model].flags & MODEL_AMSTRAD)) - return 0; - if (type == MOUSE_TYPE_OLIM24 && !(models[model].flags & MODEL_OLIM24)) - return 0; - return 1; -} - -static BOOL CALLBACK config_dlgproc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) -{ - char temp_str[256]; - HWND h; - int c, d; - int rom, gfx, mem, fpu; - int temp_cpu, temp_cpu_m, temp_model; - int temp_GAMEBLASTER, temp_GUS, temp_SSI2001, temp_voodoo, temp_sound_card_current; - int temp_dynarec; - int cpu_flags; - int temp_fd1_type, temp_fd2_type, temp_fd3_type, temp_fd4_type; - int temp_network_card_current; - int temp_network_interface_current; - int temp_joystick_type; - int cpu_type; - int temp_mouse_type; - - UDACCEL accel; -// pclog("Dialog msg %i %08X\n",message,message); - switch (message) - { - case WM_INITDIALOG: - pause = 1; - h = GetDlgItem(hdlg, IDC_COMBO1); - for (c = 0; c < ROM_MAX; c++) - romstolist[c] = 0; - c = d = 0; - while (models[c].id != -1) - { - pclog("INITDIALOG : %i %i %i\n",c,models[c].id,romspresent[models[c].id]); - if (romspresent[models[c].id]) - { - SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)models[c].name); - modeltolist[c] = d; - listtomodel[d] = c; - romstolist[models[c].id] = d; - romstomodel[models[c].id] = c; - d++; - } - c++; - } - SendMessage(h, CB_SETCURSEL, modeltolist[model], 0); - - h = GetDlgItem(hdlg, IDC_COMBOVID); - c = d = 0; - while (1) - { - char *s = video_card_getname(c); - - if (!s[0]) - break; - - if (video_card_available(c) && gfx_present[video_new_to_old(c)]) - { - SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)s); - if (video_new_to_old(c) == gfxcard) - SendMessage(h, CB_SETCURSEL, d, 0); - - d++; - } - - c++; - } - if (models[model].fixed_gfxcard) - EnableWindow(h, FALSE); - - h = GetDlgItem(hdlg, IDC_COMBOCPUM); - c = 0; - while (models[romstomodel[romset]].cpu[c].cpus != NULL && c < 4) - { - SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)models[romstomodel[romset]].cpu[c].name); - c++; - } - EnableWindow(h, TRUE); - SendMessage(h, CB_SETCURSEL, cpu_manufacturer, 0); - if (c == 1) EnableWindow(h, FALSE); - else EnableWindow(h, TRUE); - - h = GetDlgItem(hdlg, IDC_COMBO3); - c = 0; - while (models[romstomodel[romset]].cpu[cpu_manufacturer].cpus[c].cpu_type != -1) - { - SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)models[romstomodel[romset]].cpu[cpu_manufacturer].cpus[c].name); - c++; - } - EnableWindow(h, TRUE); - SendMessage(h, CB_SETCURSEL, cpu, 0); - - h = GetDlgItem(hdlg, IDC_COMBOSND); - c = d = 0; - while (1) - { - char *s = sound_card_getname(c); - - if (!s[0]) - break; - - settings_sound_to_list[c] = d; - - if (sound_card_available(c)) - { - SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)s); - settings_list_to_sound[d] = c; - d++; - } - - c++; - } - SendMessage(h, CB_SETCURSEL, settings_sound_to_list[sound_card_current], 0); - - /*NIC config*/ - h = GetDlgItem(hdlg, IDC_COMBONET); - c = d = 0; - while (1) - { - char *s = network_card_getname(c); - - if (!s[0]) - break; - - settings_network_to_list[c] = d; - - if (network_card_available(c)) - { - SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)s); - settings_list_to_network[d] = c; - d++; - } - - c++; - } - SendMessage(h, CB_SETCURSEL, settings_network_to_list[network_card_current], 0); - - h=GetDlgItem(hdlg, IDC_CHECK3); - SendMessage(h, BM_SETCHECK, GAMEBLASTER, 0); - - h=GetDlgItem(hdlg, IDC_CHECKGUS); - SendMessage(h, BM_SETCHECK, GUS, 0); - - h=GetDlgItem(hdlg, IDC_CHECKSSI); - SendMessage(h, BM_SETCHECK, SSI2001, 0); - - h=GetDlgItem(hdlg, IDC_CHECKSYNC); - SendMessage(h, BM_SETCHECK, enable_sync, 0); - - h=GetDlgItem(hdlg, IDC_CHECKVOODOO); - SendMessage(h, BM_SETCHECK, voodoo_enabled, 0); - - cpu_flags = models[romstomodel[romset]].cpu[cpu_manufacturer].cpus[cpu].cpu_flags; - h=GetDlgItem(hdlg, IDC_CHECKDYNAREC); - if (!(cpu_flags & CPU_SUPPORTS_DYNAREC) || (cpu_flags & CPU_REQUIRES_DYNAREC)) - EnableWindow(h, FALSE); - else - EnableWindow(h, TRUE); - SendMessage(h, BM_SETCHECK, ((cpu_flags & CPU_SUPPORTS_DYNAREC) && cpu_use_dynarec) || (cpu_flags & CPU_REQUIRES_DYNAREC), 0); - - h = GetDlgItem(hdlg, IDC_COMBOSPD); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"8-bit"); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"Slow 16-bit"); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"Fast 16-bit"); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"Slow VLB/PCI"); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"Mid VLB/PCI"); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"Fast VLB/PCI"); - SendMessage(h, CB_SETCURSEL, video_speed, 0); - - h = GetDlgItem(hdlg, IDC_MEMSPIN); - SendMessage(h, UDM_SETBUDDY, (WPARAM)GetDlgItem(hdlg, IDC_MEMTEXT), 0); - SendMessage(h, UDM_SETRANGE, 0, (models[romstomodel[romset]].min_ram << 16) | models[romstomodel[romset]].max_ram); - if (!models[model].flags & MODEL_AT) - SendMessage(h, UDM_SETPOS, 0, mem_size); - else - SendMessage(h, UDM_SETPOS, 0, mem_size / 1024); - accel.nSec = 0; - accel.nInc = models[model].ram_granularity; - SendMessage(h, UDM_SETACCEL, 1, (LPARAM)&accel); - - h = GetDlgItem(hdlg, IDC_CONFIGUREMOD); - if (model_getdevice(model)) - EnableWindow(h, TRUE); - else - EnableWindow(h, FALSE); - - h = GetDlgItem(hdlg, IDC_CONFIGUREVID); - if (video_card_has_config(video_old_to_new(gfxcard))) - EnableWindow(h, TRUE); - else - EnableWindow(h, FALSE); - - h = GetDlgItem(hdlg, IDC_CONFIGURESND); - if (sound_card_has_config(sound_card_current)) - EnableWindow(h, TRUE); - else - EnableWindow(h, FALSE); - - h = GetDlgItem(hdlg, IDC_CONFIGURENET); - if (network_card_has_config(network_card_current)) - EnableWindow(h, TRUE); - else - EnableWindow(h, FALSE); - - h = GetDlgItem(hdlg, IDC_COMBODR1); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"None"); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"5.25\" 360k"); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"5.25\" 1.2M"); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"5.25\" 1.2M Dual RPM"); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"3.5\" 720k"); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"3.5\" 1.44M PS/2"); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"3.5\" 1.44M"); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"3.5\" 1.25M PC-98"); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"3.5\" 1.44M 3-Mode"); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"3.5\" 2.88M"); - SendMessage(h, CB_SETCURSEL, fdd_get_type(0), 0); - h = GetDlgItem(hdlg, IDC_COMBODR2); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"None"); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"5.25\" 360k"); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"5.25\" 1.2M"); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"5.25\" 1.2M Dual RPM"); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"3.5\" 720k"); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"3.5\" 1.44M PS/2"); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"3.5\" 1.44M"); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"3.5\" 1.25M PC-98"); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"3.5\" 1.44M 3-Mode"); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"3.5\" 2.88M"); - SendMessage(h, CB_SETCURSEL, fdd_get_type(1), 0); - h = GetDlgItem(hdlg, IDC_COMBODR3); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"None"); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"5.25\" 360k"); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"5.25\" 1.2M"); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"5.25\" 1.2M Dual RPM"); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"3.5\" 720k"); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"3.5\" 1.44M PS/2"); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"3.5\" 1.44M"); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"3.5\" 1.25M PC-98"); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"3.5\" 1.44M 3-Mode"); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"3.5\" 2.88M"); - SendMessage(h, CB_SETCURSEL, fdd_get_type(2), 0); - h = GetDlgItem(hdlg, IDC_COMBODR4); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"None"); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"5.25\" 360k"); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"5.25\" 1.2M"); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"5.25\" 1.2M Dual RPM"); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"3.5\" 720k"); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"3.5\" 1.44M PS/2"); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"3.5\" 1.44M"); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"3.5\" 1.25M PC-98"); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"3.5\" 1.44M 3-Mode"); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"3.5\" 2.88M"); - SendMessage(h, CB_SETCURSEL, fdd_get_type(3), 0); - - h = GetDlgItem(hdlg, IDC_TEXT_MB); - if (models[model].flags & MODEL_AT) - SendMessage(h, WM_SETTEXT, 0, (LPARAM)(LPCSTR)"MB"); - else - SendMessage(h, WM_SETTEXT, 0, (LPARAM)(LPCSTR)"KB"); - - h = GetDlgItem(hdlg, IDC_COMBOJOY); - c = 0; - while (joystick_get_name(c)) - { - SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)joystick_get_name(c)); - c++; - } - EnableWindow(h, TRUE); - SendMessage(h, CB_SETCURSEL, joystick_type, 0); - - h = GetDlgItem(hdlg, IDC_JOY1); - EnableWindow(h, (joystick_get_max_joysticks(joystick_type) >= 1) ? TRUE : FALSE); - h = GetDlgItem(hdlg, IDC_JOY2); - EnableWindow(h, (joystick_get_max_joysticks(joystick_type) >= 2) ? TRUE : FALSE); - h = GetDlgItem(hdlg, IDC_JOY3); - EnableWindow(h, (joystick_get_max_joysticks(joystick_type) >= 3) ? TRUE : FALSE); - h = GetDlgItem(hdlg, IDC_JOY4); - EnableWindow(h, (joystick_get_max_joysticks(joystick_type) >= 4) ? TRUE : FALSE); - - h = GetDlgItem(hdlg, IDC_COMBOWS); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"System default"); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"0 W/S"); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"1 W/S"); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"2 W/S"); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"3 W/S"); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"4 W/S"); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"5 W/S"); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"6 W/S"); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"7 W/S"); - SendMessage(h, CB_SETCURSEL, cpu_waitstates, 0); - cpu_type = models[romstomodel[romset]].cpu[cpu_manufacturer].cpus[cpu].cpu_type; - if (cpu_type >= CPU_286 && cpu_type <= CPU_386DX) - EnableWindow(h, TRUE); - else - EnableWindow(h, FALSE); - - h = GetDlgItem(hdlg, IDC_COMBOMOUSE); - c = d = 0; - while (1) - { - char *s = mouse_get_name(c); - int type; - - if (!s) - break; - - type = mouse_get_type(c); - settings_mouse_to_list[c] = d; - - if (mouse_valid(type, model)) - { - SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)s); - - settings_list_to_mouse[d] = c; - d++; - } - c++; - } - - SendMessage(h, CB_SETCURSEL, settings_mouse_to_list[mouse_type], 0); - return TRUE; - - case WM_COMMAND: - switch (LOWORD(wParam)) - { - case IDOK: - h = GetDlgItem(hdlg, IDC_COMBO1); - temp_model = listtomodel[SendMessage(h, CB_GETCURSEL, 0, 0)]; - - h = GetDlgItem(hdlg, IDC_MEMTEXT); - SendMessage(h, WM_GETTEXT, 255, (LPARAM)temp_str); - sscanf(temp_str, "%i", &mem); - mem &= ~(models[temp_model].ram_granularity - 1); - if (mem < models[temp_model].min_ram) - mem = models[temp_model].min_ram; - else if (mem > models[temp_model].max_ram) - mem = models[temp_model].max_ram; - if (models[temp_model].flags & MODEL_AT) - mem *= 1024; - - h = GetDlgItem(hdlg, IDC_COMBOVID); - SendMessage(h, CB_GETLBTEXT, SendMessage(h, CB_GETCURSEL, 0, 0), (LPARAM)temp_str); - gfx = video_new_to_old(video_card_getid(temp_str)); - - h = GetDlgItem(hdlg, IDC_COMBOCPUM); - temp_cpu_m = SendMessage(h, CB_GETCURSEL, 0, 0); - h = GetDlgItem(hdlg, IDC_COMBO3); - temp_cpu = SendMessage(h, CB_GETCURSEL, 0, 0); - fpu = (models[temp_model].cpu[temp_cpu_m].cpus[temp_cpu].cpu_type >= CPU_i486DX) ? 1 : 0; - - h = GetDlgItem(hdlg, IDC_CHECK3); - temp_GAMEBLASTER = SendMessage(h, BM_GETCHECK, 0, 0); - - h = GetDlgItem(hdlg, IDC_CHECKGUS); - temp_GUS = SendMessage(h, BM_GETCHECK, 0, 0); - - h = GetDlgItem(hdlg, IDC_CHECKSSI); - temp_SSI2001 = SendMessage(h, BM_GETCHECK, 0, 0); - - h = GetDlgItem(hdlg, IDC_CHECKSYNC); - enable_sync = SendMessage(h, BM_GETCHECK, 0, 0); - - h = GetDlgItem(hdlg, IDC_CHECKVOODOO); - temp_voodoo = SendMessage(h, BM_GETCHECK, 0, 0); - - h = GetDlgItem(hdlg, IDC_COMBOSND); - temp_sound_card_current = settings_list_to_sound[SendMessage(h, CB_GETCURSEL, 0, 0)]; - - h = GetDlgItem(hdlg, IDC_CHECKDYNAREC); - temp_dynarec = SendMessage(h, BM_GETCHECK, 0, 0); - - h = GetDlgItem(hdlg, IDC_COMBONET); - temp_network_card_current = settings_list_to_network[SendMessage(h, CB_GETCURSEL, 0, 0)]; - - h = GetDlgItem(hdlg, IDC_COMBODR1); - temp_fd1_type = SendMessage(h, CB_GETCURSEL, 0, 0); - h = GetDlgItem(hdlg, IDC_COMBODR2); - temp_fd2_type = SendMessage(h, CB_GETCURSEL, 0, 0); - h = GetDlgItem(hdlg, IDC_COMBODR3); - temp_fd3_type = SendMessage(h, CB_GETCURSEL, 0, 0); - h = GetDlgItem(hdlg, IDC_COMBODR4); - temp_fd4_type = SendMessage(h, CB_GETCURSEL, 0, 0); - - h = GetDlgItem(hdlg, IDC_COMBOJOY); - temp_joystick_type = SendMessage(h, CB_GETCURSEL, 0, 0); - h = GetDlgItem(hdlg, IDC_COMBOMOUSE); - temp_mouse_type = settings_list_to_mouse[SendMessage(h, CB_GETCURSEL, 0, 0)]; - - if (temp_model != model || gfx != gfxcard || mem != mem_size || temp_cpu != cpu || temp_cpu_m != cpu_manufacturer || - fpu != hasfpu || temp_GAMEBLASTER != GAMEBLASTER || temp_GUS != GUS || - temp_SSI2001 != SSI2001 || temp_sound_card_current != sound_card_current || - temp_voodoo != voodoo_enabled || temp_dynarec != cpu_use_dynarec || temp_mouse_type != mouse_type || - temp_fd1_type != fdd_get_type(0) || temp_fd2_type != fdd_get_type(1) || temp_fd3_type != fdd_get_type(2) || temp_fd4_type != fdd_get_type(3) || temp_network_card_current != network_card_current) - { - if (MessageBox(NULL,"This will reset 86Box!\nOkay to continue?","86Box",MB_OKCANCEL)==IDOK) - { - savenvr(); - model = temp_model; - romset = model_getromset(); - gfxcard = gfx; - mem_size = mem; - cpu_manufacturer = temp_cpu_m; - cpu = temp_cpu; - GAMEBLASTER = temp_GAMEBLASTER; - GUS = temp_GUS; - SSI2001 = temp_SSI2001; - sound_card_current = temp_sound_card_current; - voodoo_enabled = temp_voodoo; - cpu_use_dynarec = temp_dynarec; - mouse_type = temp_mouse_type; - - fdd_set_type(0, temp_fd1_type); - fdd_set_type(1, temp_fd2_type); - fdd_set_type(2, temp_fd3_type); - fdd_set_type(3, temp_fd4_type); - - network_card_current = temp_network_card_current; - - mem_resize(); - loadbios(); - resetpchard(); - } - else - { - EndDialog(hdlg, 0); - pause = 0; - return TRUE; - } - } - - h = GetDlgItem(hdlg, IDC_COMBOSPD); - video_speed = SendMessage(h, CB_GETCURSEL, 0, 0); - - cpu_manufacturer = temp_cpu_m; - cpu = temp_cpu; - cpu_set(); - - h = GetDlgItem(hdlg, IDC_COMBOWS); - cpu_waitstates = SendMessage(h, CB_GETCURSEL, 0, 0); - cpu_update_waitstates(); - - saveconfig(); - - speedchanged(); - - joystick_type = temp_joystick_type; - if (joystick_type != 7) gameport_update_joystick_type(); - - case IDCANCEL: - EndDialog(hdlg, 0); - pause=0; - return TRUE; - case IDC_COMBO1: - if (HIWORD(wParam) == CBN_SELCHANGE) - { - h = GetDlgItem(hdlg,IDC_COMBO1); - temp_model = listtomodel[SendMessage(h,CB_GETCURSEL,0,0)]; - - /*Enable/disable gfxcard list*/ - h = GetDlgItem(hdlg, IDC_COMBOVID); - if (!models[temp_model].fixed_gfxcard) - { - char *s = video_card_getname(video_old_to_new(gfxcard)); - - EnableWindow(h, TRUE); - - c = 0; - while (1) - { - SendMessage(h, CB_GETLBTEXT, c, (LPARAM)temp_str); - if (!strcmp(temp_str, s)) - break; - c++; - } - SendMessage(h, CB_SETCURSEL, c, 0); - } - else - EnableWindow(h, FALSE); - - /*Rebuild manufacturer list*/ - h = GetDlgItem(hdlg, IDC_COMBOCPUM); - temp_cpu_m = SendMessage(h, CB_GETCURSEL, 0, 0); - SendMessage(h, CB_RESETCONTENT, 0, 0); - c = 0; - while (models[temp_model].cpu[c].cpus != NULL && c < 4) - { - SendMessage(h,CB_ADDSTRING,0,(LPARAM)(LPCSTR)models[temp_model].cpu[c].name); - c++; - } - if (temp_cpu_m >= c) temp_cpu_m = c - 1; - SendMessage(h, CB_SETCURSEL, temp_cpu_m, 0); - if (c == 1) EnableWindow(h, FALSE); - else EnableWindow(h, TRUE); - - /*Rebuild CPU list*/ - h = GetDlgItem(hdlg, IDC_COMBO3); - temp_cpu = SendMessage(h, CB_GETCURSEL, 0, 0); - SendMessage(h, CB_RESETCONTENT, 0, 0); - c = 0; - while (models[temp_model].cpu[temp_cpu_m].cpus[c].cpu_type != -1) - { - SendMessage(h,CB_ADDSTRING,0,(LPARAM)(LPCSTR)models[temp_model].cpu[temp_cpu_m].cpus[c].name); - c++; - } - if (temp_cpu >= c) temp_cpu = c - 1; - SendMessage(h, CB_SETCURSEL, temp_cpu, 0); - - h = GetDlgItem(hdlg, IDC_CHECKDYNAREC); - temp_dynarec = SendMessage(h, BM_GETCHECK, 0, 0); - - cpu_flags = models[temp_model].cpu[temp_cpu_m].cpus[temp_cpu].cpu_flags; - h=GetDlgItem(hdlg, IDC_CHECKDYNAREC); - if (!(cpu_flags & CPU_SUPPORTS_DYNAREC) || (cpu_flags & CPU_REQUIRES_DYNAREC)) - EnableWindow(h, FALSE); - else - EnableWindow(h, TRUE); - SendMessage(h, BM_SETCHECK, ((cpu_flags & CPU_SUPPORTS_DYNAREC) && temp_dynarec) || (cpu_flags & CPU_REQUIRES_DYNAREC), 0); - - h = GetDlgItem(hdlg, IDC_TEXT_MB); - if (models[temp_model].flags & MODEL_AT) - SendMessage(h, WM_SETTEXT, 0, (LPARAM)(LPCSTR)"MB"); - else - SendMessage(h, WM_SETTEXT, 0, (LPARAM)(LPCSTR)"KB"); - - h = GetDlgItem(hdlg, IDC_MEMTEXT); - SendMessage(h, WM_GETTEXT, 255, (LPARAM)temp_str); - sscanf(temp_str, "%i", &mem); - - h = GetDlgItem(hdlg, IDC_MEMSPIN); - SendMessage(h, UDM_SETRANGE, 0, (models[temp_model].min_ram << 16) | models[temp_model].max_ram); - mem &= ~(models[temp_model].ram_granularity - 1); - if (mem < models[temp_model].min_ram) - mem = models[temp_model].min_ram; - else if (mem > models[temp_model].max_ram) - mem = models[temp_model].max_ram; - SendMessage(h, UDM_SETPOS, 0, mem); - accel.nSec = 0; - accel.nInc = models[temp_model].ram_granularity; - SendMessage(h, UDM_SETACCEL, 1, (LPARAM)&accel); - - h = GetDlgItem(hdlg, IDC_COMBOWS); - cpu_type = models[temp_model].cpu[temp_cpu_m].cpus[temp_cpu].cpu_type; - if (cpu_type >= CPU_286 && cpu_type <= CPU_386DX) - EnableWindow(h, TRUE); - else - EnableWindow(h, FALSE); - - h = GetDlgItem(hdlg, IDC_CONFIGUREMOD); - if (model_getdevice(temp_model)) - EnableWindow(h, TRUE); - else - EnableWindow(h, FALSE); - - h = GetDlgItem(hdlg, IDC_COMBOMOUSE); - temp_mouse_type = settings_list_to_mouse[SendMessage(h, CB_GETCURSEL, 0, 0)]; - SendMessage(h, CB_RESETCONTENT, 0, 0); - c = d = 0; - while (1) - { - char *s = mouse_get_name(c); - int type; - - if (!s) - break; - - type = mouse_get_type(c); - settings_mouse_to_list[c] = d; - - if (mouse_valid(type, temp_model)) - { - SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)s); - - settings_list_to_mouse[d] = c; - d++; - } - - c++; - } - if (mouse_valid(temp_mouse_type, temp_model)) - SendMessage(h, CB_SETCURSEL, settings_mouse_to_list[temp_mouse_type], 0); - else - SendMessage(h, CB_SETCURSEL, 0, 0); - } - break; - case IDC_COMBOCPUM: - if (HIWORD(wParam) == CBN_SELCHANGE) - { - h = GetDlgItem(hdlg, IDC_COMBO1); - temp_model = listtomodel[SendMessage(h, CB_GETCURSEL, 0, 0)]; - h = GetDlgItem(hdlg, IDC_COMBOCPUM); - temp_cpu_m = SendMessage(h, CB_GETCURSEL, 0, 0); - - /*Rebuild CPU list*/ - h=GetDlgItem(hdlg, IDC_COMBO3); - temp_cpu = SendMessage(h, CB_GETCURSEL, 0, 0); - SendMessage(h, CB_RESETCONTENT, 0, 0); - c = 0; - while (models[temp_model].cpu[temp_cpu_m].cpus[c].cpu_type != -1) - { - SendMessage(h,CB_ADDSTRING,0,(LPARAM)(LPCSTR)models[temp_model].cpu[temp_cpu_m].cpus[c].name); - c++; - } - if (temp_cpu >= c) temp_cpu = c - 1; - SendMessage(h, CB_SETCURSEL, temp_cpu, 0); - - h = GetDlgItem(hdlg, IDC_CHECKDYNAREC); - temp_dynarec = SendMessage(h, BM_GETCHECK, 0, 0); - - cpu_flags = models[temp_model].cpu[temp_cpu_m].cpus[temp_cpu].cpu_flags; - h=GetDlgItem(hdlg, IDC_CHECKDYNAREC); - if (!(cpu_flags & CPU_SUPPORTS_DYNAREC) || (cpu_flags & CPU_REQUIRES_DYNAREC)) - EnableWindow(h, FALSE); - else - EnableWindow(h, TRUE); - SendMessage(h, BM_SETCHECK, ((cpu_flags & CPU_SUPPORTS_DYNAREC) && temp_dynarec) || (cpu_flags & CPU_REQUIRES_DYNAREC), 0); - - h = GetDlgItem(hdlg, IDC_COMBOWS); - cpu_type = models[temp_model].cpu[temp_cpu_m].cpus[temp_cpu].cpu_type; - if (cpu_type >= CPU_286 && cpu_type <= CPU_386DX) - EnableWindow(h, TRUE); - else - EnableWindow(h, FALSE); - - } - break; - case IDC_COMBO3: - if (HIWORD(wParam) == CBN_SELCHANGE) - { - h = GetDlgItem(hdlg, IDC_COMBO1); - temp_model = listtomodel[SendMessage(h, CB_GETCURSEL, 0, 0)]; - h = GetDlgItem(hdlg, IDC_COMBOCPUM); - temp_cpu_m = SendMessage(h, CB_GETCURSEL, 0, 0); - h=GetDlgItem(hdlg, IDC_COMBO3); - temp_cpu = SendMessage(h, CB_GETCURSEL, 0, 0); - - h = GetDlgItem(hdlg, IDC_CHECKDYNAREC); - temp_dynarec = SendMessage(h, BM_GETCHECK, 0, 0); - - cpu_flags = models[temp_model].cpu[temp_cpu_m].cpus[temp_cpu].cpu_flags; - h=GetDlgItem(hdlg, IDC_CHECKDYNAREC); - if (!(cpu_flags & CPU_SUPPORTS_DYNAREC) || (cpu_flags & CPU_REQUIRES_DYNAREC)) - EnableWindow(h, FALSE); - else - EnableWindow(h, TRUE); - SendMessage(h, BM_SETCHECK, ((cpu_flags & CPU_SUPPORTS_DYNAREC) && temp_dynarec) || (cpu_flags & CPU_REQUIRES_DYNAREC), 0); - - h = GetDlgItem(hdlg, IDC_COMBOWS); - cpu_type = models[temp_model].cpu[temp_cpu_m].cpus[temp_cpu].cpu_type; - if (cpu_type >= CPU_286 && cpu_type <= CPU_386DX) - EnableWindow(h, TRUE); - else - EnableWindow(h, FALSE); - } - break; - - case IDC_CONFIGUREMOD: - h = GetDlgItem(hdlg, IDC_COMBO1); - temp_model = listtomodel[SendMessage(h, CB_GETCURSEL, 0, 0)]; - - deviceconfig_open(hdlg, (void *)model_getdevice(temp_model)); - break; - - case IDC_CONFIGUREVID: - h = GetDlgItem(hdlg, IDC_COMBOVID); - SendMessage(h, CB_GETLBTEXT, SendMessage(h, CB_GETCURSEL, 0, 0), (LPARAM)temp_str); - - deviceconfig_open(hdlg, (void *)video_card_getdevice(video_card_getid(temp_str))); - break; - - case IDC_COMBOVID: - h = GetDlgItem(hdlg, IDC_COMBOVID); - SendMessage(h, CB_GETLBTEXT, SendMessage(h, CB_GETCURSEL, 0, 0), (LPARAM)temp_str); - gfx = video_card_getid(temp_str); - - h = GetDlgItem(hdlg, IDC_CONFIGUREVID); - if (video_card_has_config(gfx)) - EnableWindow(h, TRUE); - else - EnableWindow(h, FALSE); - break; - - case IDC_CONFIGURESND: - h = GetDlgItem(hdlg, IDC_COMBOSND); - temp_sound_card_current = settings_list_to_sound[SendMessage(h, CB_GETCURSEL, 0, 0)]; - - deviceconfig_open(hdlg, (void *)sound_card_getdevice(temp_sound_card_current)); - break; - - case IDC_COMBOSND: - h = GetDlgItem(hdlg, IDC_COMBOSND); - temp_sound_card_current = settings_list_to_sound[SendMessage(h, CB_GETCURSEL, 0, 0)]; - - h = GetDlgItem(hdlg, IDC_CONFIGURESND); - if (sound_card_has_config(temp_sound_card_current)) - EnableWindow(h, TRUE); - else - EnableWindow(h, FALSE); - break; - - case IDC_CONFIGURENET: - h = GetDlgItem(hdlg, IDC_COMBONET); - temp_network_card_current = settings_list_to_network[SendMessage(h, CB_GETCURSEL, 0, 0)]; - - deviceconfig_open(hdlg, (void *)network_card_getdevice(temp_network_card_current)); - break; - - case IDC_COMBONET: - h = GetDlgItem(hdlg, IDC_COMBONET); - temp_network_card_current = settings_list_to_network[SendMessage(h, CB_GETCURSEL, 0, 0)]; - - h = GetDlgItem(hdlg, IDC_CONFIGURENET); - if (network_card_has_config(temp_network_card_current)) - EnableWindow(h, TRUE); - else - EnableWindow(h, FALSE); - break; - - case IDC_CONFIGUREVOODOO: - deviceconfig_open(hdlg, (void *)&voodoo_device); - break; - - case IDC_COMBOJOY: - if (HIWORD(wParam) == CBN_SELCHANGE) - { - h = GetDlgItem(hdlg, IDC_COMBOJOY); - temp_joystick_type = SendMessage(h, CB_GETCURSEL, 0, 0); - - h = GetDlgItem(hdlg, IDC_JOY1); - EnableWindow(h, (joystick_get_max_joysticks(temp_joystick_type) >= 1) ? TRUE : FALSE); - h = GetDlgItem(hdlg, IDC_JOY2); - EnableWindow(h, (joystick_get_max_joysticks(temp_joystick_type) >= 2) ? TRUE : FALSE); - h = GetDlgItem(hdlg, IDC_JOY3); - EnableWindow(h, (joystick_get_max_joysticks(temp_joystick_type) >= 3) ? TRUE : FALSE); - h = GetDlgItem(hdlg, IDC_JOY4); - EnableWindow(h, (joystick_get_max_joysticks(temp_joystick_type) >= 4) ? TRUE : FALSE); - } - break; - - case IDC_JOY1: - h = GetDlgItem(hdlg, IDC_COMBOJOY); - temp_joystick_type = SendMessage(h, CB_GETCURSEL, 0, 0); - joystickconfig_open(hdlg, 0, temp_joystick_type); - break; - case IDC_JOY2: - h = GetDlgItem(hdlg, IDC_COMBOJOY); - temp_joystick_type = SendMessage(h, CB_GETCURSEL, 0, 0); - joystickconfig_open(hdlg, 1, temp_joystick_type); - break; - case IDC_JOY3: - h = GetDlgItem(hdlg, IDC_COMBOJOY); - temp_joystick_type = SendMessage(h, CB_GETCURSEL, 0, 0); - joystickconfig_open(hdlg, 2, temp_joystick_type); - break; - case IDC_JOY4: - h = GetDlgItem(hdlg, IDC_COMBOJOY); - temp_joystick_type = SendMessage(h, CB_GETCURSEL, 0, 0); - joystickconfig_open(hdlg, 3, temp_joystick_type); - break; - } - break; - } - return FALSE; -} - -void config_open(HWND hwnd) -{ - DialogBox(hinstance, TEXT("ConfigureDlg"), hwnd, config_dlgproc); -} diff --git a/src/win-d3d-fs.h b/src/win-d3d-fs.h deleted file mode 100644 index 0c45c6e2d..000000000 --- a/src/win-d3d-fs.h +++ /dev/null @@ -1,13 +0,0 @@ -/* Copyright holders: Sarah Walker, Tenshi - see COPYING for more details -*/ -#ifdef __cplusplus -extern "C" { -#endif - void d3d_fs_init(HWND h); - void d3d_fs_close(); - void d3d_fs_reset(); - void d3d_fs_resize(int x, int y); -#ifdef __cplusplus -} -#endif diff --git a/src/win-d3d.h b/src/win-d3d.h deleted file mode 100644 index 4d4c341bc..000000000 --- a/src/win-d3d.h +++ /dev/null @@ -1,13 +0,0 @@ -/* Copyright holders: Sarah Walker, Tenshi - see COPYING for more details -*/ -#ifdef __cplusplus -extern "C" { -#endif - void d3d_init(HWND h); - void d3d_close(); - void d3d_reset(); - void d3d_resize(int x, int y); -#ifdef __cplusplus -} -#endif diff --git a/src/win-ddraw-fs.h b/src/win-ddraw-fs.h deleted file mode 100644 index c94f2610f..000000000 --- a/src/win-ddraw-fs.h +++ /dev/null @@ -1,11 +0,0 @@ -/* Copyright holders: Sarah Walker, Tenshi - see COPYING for more details -*/ -#ifdef __cplusplus -extern "C" { -#endif - void ddraw_fs_init(HWND h); - void ddraw_fs_close(); -#ifdef __cplusplus -} -#endif diff --git a/src/win-ddraw-screenshot.h b/src/win-ddraw-screenshot.h deleted file mode 100644 index 0d5b7cc7b..000000000 --- a/src/win-ddraw-screenshot.h +++ /dev/null @@ -1,4 +0,0 @@ -/* Copyright holders: Tenshi - see COPYING for more details -*/ -void ddraw_common_take_screenshot(char *fn, IDirectDrawSurface4 *pDDSurface); diff --git a/src/win-ddraw.h b/src/win-ddraw.h deleted file mode 100644 index 65e8e2bb1..000000000 --- a/src/win-ddraw.h +++ /dev/null @@ -1,12 +0,0 @@ -/* Copyright holders: Sarah Walker, Tenshi - see COPYING for more details -*/ -#ifdef __cplusplus -extern "C" { -#endif - void ddraw_init(HWND h); - void ddraw_close(); -#ifdef __cplusplus -} -#endif - diff --git a/src/win-hdconf.c b/src/win-hdconf.c deleted file mode 100644 index cc09df282..000000000 --- a/src/win-hdconf.c +++ /dev/null @@ -1,683 +0,0 @@ -/* Copyright holders: Sarah Walker, Tenshi - see COPYING for more details -*/ -#include -#define BITMAP WINDOWS_BITMAP -#include -#include -#undef BITMAP - -#include "ibm.h" -#include "ide.h" -#include "resources.h" -#include "win.h" - -static int hd_changed = 0; - -static char hd_new_name[512]; -static uint64_t hd_new_spt, hd_new_hpc, hd_new_cyl; -static int hd_new_hdi; -static int new_cdrom_channel; - -static void update_hdd_cdrom(HWND hdlg) -{ - HWND h; - int drive_num = 0; - - for (drive_num = 0; drive_num < IDE_NUM; drive_num++) - { - h = GetDlgItem(hdlg, IDC_CHDD + drive_num); - SendMessage(h, BM_SETCHECK, (new_cdrom_channel == drive_num) ? 0 : 1, 0); - h = GetDlgItem(hdlg, IDC_CCDROM + drive_num); - SendMessage(h, BM_SETCHECK, (new_cdrom_channel == drive_num) ? 1 : 0, 0); - } -} - -int hdnew_no_update = 0; - -hard_disk_t hdnew_temp_hd; - -int hdsize_no_update = 0; - -hard_disk_t hdsize_temp_hd; - -char s[260]; - -static int hdconf_initialize_hdt_combo(HWND hdlg, hard_disk_t *internal_hd) -{ - HWND h; - int i = 0; - uint64_t size = 0; - uint64_t size_mb = 0; - uint64_t size_shift = 11; - int selection = 127; - - h = GetDlgItem(hdlg, IDC_COMBOHDT); - for (i = 0; i < 127; i++) - { - size = hdt[i][0] * hdt[i][1] * hdt[i][2]; - size_mb = size >> size_shift; - sprintf(s, "%" PRIu64 " MB (CHS: %" PRIu64 ", %" PRIu64 ", %" PRIu64 ")", size_mb, hdt[i][0], hdt[i][1], hdt[i][2]); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM)s); - if ((internal_hd->tracks == hdt[i][0]) && (internal_hd->hpc == hdt[i][1]) && (internal_hd->spt == hdt[i][2])) - { - selection = i; - } - } - sprintf(s, "Custom..."); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM)s); - SendMessage(h, CB_SETCURSEL, selection, 0); - return selection; -} - -static void hdconf_update_text_boxes(HWND hdlg, BOOL enable) -{ - HWND h; - - h=GetDlgItem(hdlg, IDC_EDIT1); - EnableWindow(h, enable); - h=GetDlgItem(hdlg, IDC_EDIT2); - EnableWindow(h, enable); - h=GetDlgItem(hdlg, IDC_EDIT3); - EnableWindow(h, enable); - h=GetDlgItem(hdlg, IDC_EDIT4); - EnableWindow(h, enable); -} - -void hdconf_set_text_boxes(HWND hdlg, hard_disk_t *internal_hd) -{ - HWND h; - - uint64_t size_shift = 11; - - h = GetDlgItem(hdlg, IDC_EDIT1); - sprintf(s, "%" PRIu64, internal_hd->spt); - SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); - h = GetDlgItem(hdlg, IDC_EDIT2); - sprintf(s, "%" PRIu64, internal_hd->hpc); - SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); - h = GetDlgItem(hdlg, IDC_EDIT3); - sprintf(s, "%" PRIu64, internal_hd->tracks); - SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); - - h = GetDlgItem(hdlg, IDC_EDIT4); - sprintf(s, "%" PRIu64, (internal_hd->spt * internal_hd->hpc * internal_hd->tracks) >> size_shift); - SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); -} - -BOOL hdconf_initdialog_common(HWND hdlg, hard_disk_t *internal_hd, int *no_update, uint64_t spt, uint64_t hpc, uint64_t tracks) -{ - HWND h; - int selection = 127; - - internal_hd->spt = spt; - internal_hd->hpc = hpc; - internal_hd->tracks = tracks; - *no_update = 1; - - hdconf_set_text_boxes(hdlg, internal_hd); - - selection = hdconf_initialize_hdt_combo(hdlg, internal_hd); - - if (selection < 127) - { - hdconf_update_text_boxes(hdlg, FALSE); - } - else - { - hdconf_update_text_boxes(hdlg, TRUE); - } - - *no_update = 0; - - return TRUE; -} - -int hdconf_idok_common(HWND hdlg) -{ - HWND h; - - h = GetDlgItem(hdlg, IDC_EDIT1); - SendMessage(h, WM_GETTEXT, 255, (LPARAM)s); - sscanf(s, "%" PRIu64, &hd_new_spt); - h = GetDlgItem(hdlg, IDC_EDIT2); - SendMessage(h, WM_GETTEXT, 255, (LPARAM)s); - sscanf(s, "%" PRIu64, &hd_new_hpc); - h = GetDlgItem(hdlg, IDC_EDIT3); - SendMessage(h, WM_GETTEXT, 255, (LPARAM)s); - sscanf(s, "%" PRIu64, &hd_new_cyl); - - if (hd_new_spt > 63) - { - MessageBox(ghwnd, "Drive has too many sectors (maximum is 63)", "86Box error", MB_OK); - return 1; - } - if (hd_new_hpc > 16) - { - MessageBox(ghwnd, "Drive has too many heads (maximum is 16)", "86Box error", MB_OK); - return 1; - } - if (hd_new_cyl > 16383) - { - MessageBox(ghwnd, "Drive has too many cylinders (maximum is 16383)", "86Box error", MB_OK); - return 1; - } - - return 0; -} - -BOOL hdconf_process_edit_boxes(HWND hdlg, WORD control, uint64_t *var, hard_disk_t *internal_hd, int *no_update) -{ - HWND h; - uint64_t size_shift = 11; - - if (*no_update) - { - return FALSE; - } - - h = GetDlgItem(hdlg, control); - SendMessage(h, WM_GETTEXT, 255, (LPARAM)s); - sscanf(s, "%" PRIu64, var); - - *no_update = 1; - if(!(*var)) - { - *var = 1; - sprintf(s, "%" PRIu64, *var); - SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); - } - - if (control == IDC_EDIT4) - { - *var <<= 11; /* Convert to sectors */ - *var /= internal_hd->hpc; - *var /= internal_hd->spt; - internal_hd->tracks = *var; - - h = GetDlgItem(hdlg, IDC_EDIT3); - sprintf(s, "%" PRIu64, internal_hd->tracks); - SendMessage(h, WM_SETTEXT, 1, (LPARAM)s); - } - else if ((control >= IDC_EDIT1) && (control <= IDC_EDIT3)) - { - h = GetDlgItem(hdlg, IDC_EDIT4); - sprintf(s, "%" PRIu64, (internal_hd->spt * internal_hd->hpc * internal_hd->tracks) >> size_shift); - SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); - } - - *no_update = 0; - return TRUE; -} - -BOOL hdconf_process_hdt_combo(HWND hdlg, hard_disk_t *internal_hd, int *no_update, WPARAM wParam) -{ - HWND h; - int selection = 127; - - if (*no_update) - { - return FALSE; - } - - if (HIWORD(wParam) == CBN_SELCHANGE) - { - *no_update = 1; - - h = GetDlgItem(hdlg,IDC_COMBOHDT); - selection = SendMessage(h,CB_GETCURSEL,0,0); - - if (selection < 127) - { - hdconf_update_text_boxes(hdlg, FALSE); - - internal_hd->tracks = hdt[selection][0]; - internal_hd->hpc = hdt[selection][1]; - internal_hd->spt = hdt[selection][2]; - - hdconf_set_text_boxes(hdlg, internal_hd); - } - else - { - hdconf_update_text_boxes(hdlg, TRUE); - } - - *no_update = 0; - } - else - { - return FALSE; - } - - return TRUE; -} - -BOOL CALLBACK hdconf_common_dlgproc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam, int type, hard_disk_t *internal_hd, int *no_update, uint64_t spt, uint64_t hpc, uint64_t tracks) -{ - HWND h; - uint64_t c; - FILE *f; - uint8_t buf[512]; - int is_hdi; - uint64_t size; - uint32_t zero = 0; - uint32_t sector_size = 512; - uint32_t base = 0x1000; - uint64_t full_size = 0; - uint64_t full_size_bytes = 0; - uint64_t size_shift = 11; - int selection = 127; - switch (message) - { - case WM_INITDIALOG: - if (!type) - { - h = GetDlgItem(hdlg, IDC_EDITC); - SendMessage(h, WM_SETTEXT, 0, (LPARAM)""); - } - return hdconf_initdialog_common(hdlg, internal_hd, no_update, spt, hpc, tracks); - - case WM_COMMAND: - switch (LOWORD(wParam)) - { - case IDOK: - if (!type) - { - h = GetDlgItem(hdlg, IDC_EDITC); - SendMessage(h, WM_GETTEXT, 511, (LPARAM)hd_new_name); - if (!hd_new_name[0]) - { - MessageBox(ghwnd,"Please enter a valid filename","86Box error",MB_OK); - return TRUE; - } - } - - if (hdconf_idok_common(hdlg)) - { - return TRUE; - } - - if (!type) - { - f = fopen64(hd_new_name, "wb"); - if (!f) - { - MessageBox(ghwnd, "Can't open file for write", "86Box error", MB_OK); - return TRUE; - } - full_size = (hd_new_cyl * hd_new_hpc * hd_new_spt); - full_size_bytes = full_size * 512; - if (image_is_hdi(hd_new_name)) - { - if (full_size_bytes >= 0x100000000) - { - MessageBox(ghwnd, "Drive is HDI and 4 GB or bigger (size filed in HDI header is 32-bit)", "86Box error", MB_OK); - fclose(f); - return TRUE; - } - - hd_new_hdi = 1; - - fwrite(&zero, 1, 4, f); /* 00000000: Zero/unknown */ - fwrite(&zero, 1, 4, f); /* 00000004: Zero/unknown */ - fwrite(&base, 1, 4, f); /* 00000008: Offset at which data starts */ - fwrite(&full_size_bytes, 1, 4, f); /* 0000000C: Full size of the data (32-bit) */ - fwrite(§or_size, 1, 4, f); /* 00000010: Sector size in bytes */ - fwrite(&hd_new_spt, 1, 4, f); /* 00000014: Sectors per cylinder */ - fwrite(&hd_new_hpc, 1, 4, f); /* 00000018: Heads per cylinder */ - fwrite(&hd_new_cyl, 1, 4, f); /* 0000001C: Cylinders */ - - for (c = 0; c < 0x3f8; c++) - { - fwrite(&zero, 1, 4, f); - } - } - memset(buf, 0, 512); - for (c = 0; c < full_size; c++) - fwrite(buf, 512, 1, f); - fclose(f); - - MessageBox(ghwnd, "Remember to partition and format the new drive", "86Box", MB_OK); - } - - EndDialog(hdlg,1); - return TRUE; - - case IDCANCEL: - EndDialog(hdlg, 0); - return TRUE; - - case IDC_CFILE: - if (!type) - { - if (!getsfile(hdlg, "Hard disc image (*.HDI;*.IMA;*.IMG)\0*.HDI;*.IMA;*.IMG\0All files (*.*)\0*.*\0", "")) - { - h = GetDlgItem(hdlg, IDC_EDITC); - SendMessage(h, WM_SETTEXT, 0, (LPARAM)openfilestring); - } - return TRUE; - } - else - { - break; - } - - case IDC_EDIT1: - return hdconf_process_edit_boxes(hdlg, IDC_EDIT1, &(internal_hd->spt), internal_hd, no_update); - - case IDC_EDIT2: - return hdconf_process_edit_boxes(hdlg, IDC_EDIT2, &(internal_hd->hpc), internal_hd, no_update); - - case IDC_EDIT3: - return hdconf_process_edit_boxes(hdlg, IDC_EDIT3, &(internal_hd->tracks), internal_hd, no_update); - - case IDC_EDIT4: - return hdconf_process_edit_boxes(hdlg, IDC_EDIT4, &size, internal_hd, no_update); - - case IDC_COMBOHDT: - return hdconf_process_hdt_combo(hdlg, internal_hd, no_update, wParam); - } - break; - - } - return FALSE; -} - -static BOOL CALLBACK hdnew_dlgproc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) -{ - return hdconf_common_dlgproc(hdlg, message, wParam, lParam, 0, &hdnew_temp_hd, &hdnew_no_update, 63, 16, 511); -} - -BOOL CALLBACK hdsize_dlgproc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) -{ - return hdconf_common_dlgproc(hdlg, message, wParam, lParam, 1, &hdsize_temp_hd, &hdsize_no_update, hd_new_spt, hd_new_hpc, hd_new_cyl); -} - -static void hdconf_eject(HWND hdlg, int drive_num, hard_disk_t *hd) -{ - hd->spt = 0; - hd->hpc = 0; - hd->tracks = 0; - ide_fn[drive_num][0] = 0; - SetDlgItemText(hdlg, IDC_EDIT_C_SPT + drive_num, "0"); - SetDlgItemText(hdlg, IDC_EDIT_C_HPC + drive_num, "0"); - SetDlgItemText(hdlg, IDC_EDIT_C_CYL + drive_num, "0"); - SetDlgItemText(hdlg, IDC_EDIT_C_FN + drive_num, ""); - hd_changed = 1; - return; -} - -static void hdconf_new(HWND hdlg, int drive_num) -{ - HWND h; - - if (DialogBox(hinstance, TEXT("HdNewDlg"), hdlg, hdnew_dlgproc) == 1) - { - h = GetDlgItem(hdlg, IDC_EDIT_C_SPT + drive_num); - sprintf(s, "%" PRIu64, hd_new_spt); - SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); - h = GetDlgItem(hdlg, IDC_EDIT_C_HPC + drive_num); - sprintf(s, "%" PRIu64, hd_new_hpc); - SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); - h = GetDlgItem(hdlg, IDC_EDIT_C_CYL + drive_num); - sprintf(s, "%" PRIu64, hd_new_cyl); - SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); - h = GetDlgItem(hdlg, IDC_EDIT_C_FN + drive_num); - SendMessage(h, WM_SETTEXT, 0, (LPARAM)hd_new_name); - - h= GetDlgItem(hdlg, IDC_TEXT_C_SIZE + drive_num); - sprintf(s, "Size: %" PRIu64 " MB", (hd_new_cyl*hd_new_hpc*hd_new_spt) >> 11); - SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); - - hd_changed = 1; - } - return; -} - -static void hdconf_file(HWND hdlg, int drive_num) -{ - HWND h; - FILE *f; - off64_t sz; - uint32_t sector_size = 512; - uint32_t base = 0x1000; - int ret; - - if (!getfile(hdlg, "Hard disc image (*.HDI;*.IMA;*.IMG;*.VHD)\0*.HDI;*.IMA;*.IMG;*.VHD\0All files (*.*)\0*.*\0", "")) - { - f = fopen64(openfilestring, "rb"); - if (!f) - { - MessageBox(ghwnd,"Can't open file for read","86Box error",MB_OK); - return; - } - - if (image_is_hdi(openfilestring)) - { - fseeko64(f, 0x10, SEEK_END); - fread(§or_size, 1, 4, f); - if (sector_size != 512) - { - MessageBox(ghwnd,"HDI image with a sector size that is not 512","86Box error",MB_OK); - fclose(f); - return; - } - fread(&hd_new_spt, 1, 4, f); - fread(&hd_new_hpc, 1, 4, f); - fread(&hd_new_cyl, 1, 4, f); - - ret = 1; - } - else - { - fseeko64(f, -1, SEEK_END); - sz = ftello64(f) + 1; - fclose(f); - hd_new_spt = 63; - hd_new_hpc = 16; - hd_new_cyl = ((sz / 512) / 16) / 63; - - ret = DialogBox(hinstance, TEXT("HdSizeDlg"), hdlg, hdsize_dlgproc); - } - if (ret == 1) - { - h = GetDlgItem(hdlg, IDC_EDIT_C_SPT + drive_num); - sprintf(s, "%" PRIu64, hd_new_spt); - SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); - h = GetDlgItem(hdlg, IDC_EDIT_C_HPC + drive_num); - sprintf(s, "%" PRIu64, hd_new_hpc); - SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); - h = GetDlgItem(hdlg, IDC_EDIT_C_CYL + drive_num); - sprintf(s, "%" PRIu64, hd_new_cyl); - SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); - h = GetDlgItem(hdlg, IDC_EDIT_C_FN + drive_num); - SendMessage(h, WM_SETTEXT, 0, (LPARAM)openfilestring); - - h = GetDlgItem(hdlg, IDC_TEXT_C_SIZE + drive_num); - sprintf(s, "Size: %" PRIu64 " MB", (hd_new_cyl*hd_new_hpc*hd_new_spt) >> 11); - SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); - - hd_changed = 1; - } - } - return; -} - -static void hdconf_edit_boxes(HWND hdlg, int drive_num, hard_disk_t *hd) -{ - HWND h; - - h = GetDlgItem(hdlg, IDC_EDIT_C_SPT + drive_num); - SendMessage(h, WM_GETTEXT, 255, (LPARAM)s); - sscanf(s, "%" PRIu64, &(hd->spt)); - h = GetDlgItem(hdlg, IDC_EDIT_C_HPC + drive_num); - SendMessage(h, WM_GETTEXT, 255, (LPARAM)s); - sscanf(s, "%" PRIu64, &(hd->hpc)); - h = GetDlgItem(hdlg, IDC_EDIT_C_CYL + drive_num); - SendMessage(h, WM_GETTEXT, 255, (LPARAM)s); - sscanf(s, "%" PRIu64, &(hd->tracks)); - - h = GetDlgItem(hdlg, IDC_TEXT_C_SIZE + drive_num); - sprintf(s, "Size: %" PRIu64 " MB", (hd->tracks*hd->hpc*hd->spt) >> 11); - SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); - return; -} - -static BOOL CALLBACK hdconf_dlgproc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) -{ - HWND h; - hard_disk_t hd[IDE_NUM]; - int drive_num = 0; - switch (message) - { - case WM_INITDIALOG: - pause = 1; - - for (drive_num = 0; drive_num < IDE_NUM; drive_num++) - { - hd[drive_num] = hdc[drive_num]; - - h = GetDlgItem(hdlg, IDC_EDIT_C_SPT + drive_num); - sprintf(s, "%" PRIu64, hdc[drive_num].spt); - SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); - h = GetDlgItem(hdlg, IDC_EDIT_C_HPC + drive_num); - sprintf(s, "%" PRIu64, hdc[drive_num].hpc); - SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); - h = GetDlgItem(hdlg, IDC_EDIT_C_CYL + drive_num); - sprintf(s, "%" PRIu64, hdc[drive_num].tracks); - SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); - h = GetDlgItem(hdlg, IDC_EDIT_C_FN + drive_num); - SendMessage(h, WM_SETTEXT, 0, (LPARAM)ide_fn[drive_num]); - - h = GetDlgItem(hdlg, IDC_TEXT_C_SIZE + drive_num); - sprintf(s, "Size: %" PRIu64 " MB", (hd[drive_num].tracks*hd[drive_num].hpc*hd[drive_num].spt) >> 11); - SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); - } - - hd_changed = 0; - - new_cdrom_channel = atapi_cdrom_channel; - - update_hdd_cdrom(hdlg); - return TRUE; - - case WM_COMMAND: - switch (LOWORD(wParam)) - { - case IDOK: - if (hd_changed || atapi_cdrom_channel != new_cdrom_channel) - { - if (MessageBox(NULL, "This will reset 86Box!\nOkay to continue?", "86Box", MB_OKCANCEL) == IDOK) - { - for (drive_num = 0; drive_num < IDE_NUM; drive_num++) - { - h = GetDlgItem(hdlg, IDC_EDIT_C_SPT + drive_num); - SendMessage(h, WM_GETTEXT, 255, (LPARAM)s); - sscanf(s, "%" PRIu64, &hd[drive_num].spt); - h = GetDlgItem(hdlg, IDC_EDIT_C_HPC + drive_num); - SendMessage(h, WM_GETTEXT, 255, (LPARAM)s); - sscanf(s, "%" PRIu64, &hd[drive_num].hpc); - h = GetDlgItem(hdlg, IDC_EDIT_C_CYL + drive_num); - SendMessage(h, WM_GETTEXT, 255, (LPARAM)s); - sscanf(s, "%" PRIu64, &hd[drive_num].tracks); - h = GetDlgItem(hdlg, IDC_EDIT_C_FN + drive_num); - SendMessage(h, WM_GETTEXT, 511, (LPARAM)ide_fn[drive_num]); - - hdc[drive_num] = hd[drive_num]; - } - - atapi_cdrom_channel = new_cdrom_channel; - - saveconfig(); - - resetpchard(); - } - } - case IDCANCEL: - EndDialog(hdlg, 0); - pause = 0; - return TRUE; - - case IDC_EJECTC: - case IDC_EJECTD: - case IDC_EJECTE: - case IDC_EJECTF: - case IDC_EJECTG: - case IDC_EJECTH: - case IDC_EJECTI: - case IDC_EJECTJ: - drive_num = LOWORD(wParam) % 10; - hdconf_eject(hdlg, drive_num, &(hd[drive_num])); - return TRUE; - - case IDC_CNEW: - case IDC_DNEW: - case IDC_ENEW: - case IDC_FNEW: - case IDC_GNEW: - case IDC_HNEW: - case IDC_INEW: - case IDC_JNEW: - drive_num = LOWORD(wParam) % 10; - hdconf_new(hdlg, drive_num); - return TRUE; - - case IDC_CFILE: - case IDC_DFILE: - case IDC_EFILE: - case IDC_FFILE: - case IDC_GFILE: - case IDC_HFILE: - case IDC_IFILE: - case IDC_JFILE: - drive_num = LOWORD(wParam) % 10; - hdconf_file(hdlg, drive_num); - return TRUE; - - case IDC_EDIT_C_SPT: case IDC_EDIT_C_HPC: case IDC_EDIT_C_CYL: - case IDC_EDIT_D_SPT: case IDC_EDIT_D_HPC: case IDC_EDIT_D_CYL: - case IDC_EDIT_E_SPT: case IDC_EDIT_E_HPC: case IDC_EDIT_E_CYL: - case IDC_EDIT_F_SPT: case IDC_EDIT_F_HPC: case IDC_EDIT_F_CYL: - case IDC_EDIT_G_SPT: case IDC_EDIT_G_HPC: case IDC_EDIT_G_CYL: - case IDC_EDIT_H_SPT: case IDC_EDIT_H_HPC: case IDC_EDIT_H_CYL: - case IDC_EDIT_I_SPT: case IDC_EDIT_I_HPC: case IDC_EDIT_I_CYL: - case IDC_EDIT_J_SPT: case IDC_EDIT_J_HPC: case IDC_EDIT_J_CYL: - drive_num = LOWORD(wParam) % 10; - hdconf_edit_boxes(hdlg, drive_num, &(hd[drive_num])); - return TRUE; - - case IDC_CHDD: - case IDC_DHDD: - case IDC_EHDD: - case IDC_FHDD: - case IDC_GHDD: - case IDC_HHDD: - case IDC_IHDD: - case IDC_JHDD: - if (new_cdrom_channel == (LOWORD(wParam) - IDC_CCDROM)) - new_cdrom_channel = -1; - update_hdd_cdrom(hdlg); - return TRUE; - - case IDC_CCDROM: - case IDC_DCDROM: - case IDC_ECDROM: - case IDC_FCDROM: - case IDC_GCDROM: - case IDC_HCDROM: - case IDC_ICDROM: - case IDC_JCDROM: - new_cdrom_channel = LOWORD(wParam) - IDC_CCDROM; - update_hdd_cdrom(hdlg); - return TRUE; - } - break; - - } - return FALSE; -} - -void hdconf_open(HWND hwnd) -{ - DialogBox(hinstance, TEXT("HdConfDlg"), hwnd, hdconf_dlgproc); -} diff --git a/src/win-keyboard.cc b/src/win-keyboard.cc deleted file mode 100644 index 16381cd4c..000000000 --- a/src/win-keyboard.cc +++ /dev/null @@ -1,60 +0,0 @@ -/* Copyright holders: Sarah Walker, Tenshi - see COPYING for more details -*/ -#define UNICODE -#include -#include -#include -#define BITMAP WINDOWS_BITMAP -#include -#undef BITMAP -#include "plat-keyboard.h" -#include "win.h" -#include "video.h" - -extern "C" int recv_key[272]; - -extern "C" void fatal(const char *format, ...); -extern "C" void pclog(const char *format, ...); - -extern "C" void keyboard_init(); -extern "C" void keyboard_close(); -extern "C" void keyboard_poll(); - -int recv_key[272]; - -void keyboard_init() -{ - atexit(keyboard_close); - - memset(recv_key, 0, sizeof(recv_key)); - pclog("Keyboard initialized!\n"); -} - -void keyboard_close() -{ -} - -void keyboard_poll_host() -{ -#if 0 - int c; - - for (c = 0; c < 272; c++) - recv_key[c] = rawinputkey[c]; - - if ((rawinputkey[0x1D] || rawinputkey[0x9D]) && - (rawinputkey[0x38] || rawinputkey[0xB8]) && - (rawinputkey[0x51] || rawinputkey[0xD1]) && - video_fullscreen) - leave_fullscreen(); - - if ((rawinputkey[0x1D] || rawinputkey[0x9D]) && -// (rawinputkey[0x38] || rawinputkey[0xB8]) && - (rawinputkey[0x57] || rawinputkey[0x57])) - { - pclog("Taking screenshot...\n"); - take_screenshot(); - } -#endif -} diff --git a/src/win-midi.c b/src/win-midi.c deleted file mode 100644 index bb0bc2d78..000000000 --- a/src/win-midi.c +++ /dev/null @@ -1,116 +0,0 @@ -/* Copyright holders: Sarah Walker - see COPYING for more details -*/ -#include -#include -#include "ibm.h" -#include "plat-midi.h" - -static int midi_id; -static HMIDIOUT midi_out_device = NULL; - -void midi_close(); - -void midi_init() -{ - int c; - int n; - MIDIOUTCAPS ocaps; - MMRESULT hr; - - midi_id = config_get_int(NULL, "midi", 0); - - hr = midiOutOpen(&midi_out_device, midi_id, 0, - 0, CALLBACK_NULL); - if (hr != MMSYSERR_NOERROR) { - printf("midiOutOpen error - %08X\n",hr); - midi_id = 0; - hr = midiOutOpen(&midi_out_device, midi_id, 0, - 0, CALLBACK_NULL); - if (hr != MMSYSERR_NOERROR) { - printf("midiOutOpen error - %08X\n",hr); - return; - } - } - - midiOutReset(midi_out_device); -} - -void midi_close() -{ - if (midi_out_device != NULL) - { - midiOutReset(midi_out_device); - midiOutClose(midi_out_device); - midi_out_device = NULL; - } -} - -int midi_get_num_devs() -{ - return midiOutGetNumDevs(); -} -void midi_get_dev_name(int num, char *s) -{ - MIDIOUTCAPS caps; - - midiOutGetDevCaps(num, &caps, sizeof(caps)); - strcpy(s, caps.szPname); -} - -static int midi_pos, midi_len; -static uint32_t midi_command; -static int midi_lengths[8] = {3, 3, 3, 3, 2, 2, 3, 1}; -static int midi_insysex; -static uint8_t midi_sysex_data[1024+2]; - -static void midi_send_sysex() -{ - MIDIHDR hdr; - int c; - - hdr.lpData = midi_sysex_data; - hdr.dwBufferLength = midi_pos; - hdr.dwFlags = 0; - -/* pclog("Sending sysex : "); - for (c = 0; c < midi_pos; c++) - pclog("%02x ", midi_sysex_data[c]); - pclog("\n");*/ - - midiOutPrepareHeader(midi_out_device, &hdr, sizeof(MIDIHDR)); - midiOutLongMsg(midi_out_device, &hdr, sizeof(MIDIHDR)); - - midi_insysex = 0; -} - -void midi_write(uint8_t val) -{ - if ((val & 0x80) && !(val == 0xf7 && midi_insysex)) - { - midi_pos = 0; - midi_len = midi_lengths[(val >> 4) & 7]; - midi_command = 0; - if (val == 0xf0) - midi_insysex = 1; - } - - if (midi_insysex) - { - midi_sysex_data[midi_pos++] = val; - - if (val == 0xf7 || midi_pos >= 1024+2) - midi_send_sysex(); - return; - } - - if (midi_len) - { - midi_command |= (val << (midi_pos * 8)); - - midi_pos++; - - if (midi_pos == midi_len) - midiOutShortMsg(midi_out_device, midi_command); - } -} diff --git a/src/win.c b/src/win.c deleted file mode 100644 index c8ea78941..000000000 --- a/src/win.c +++ /dev/null @@ -1,2158 +0,0 @@ -/* Copyright holders: Sarah Walker, Tenshi - see COPYING for more details -*/ -#define _WIN32_WINNT 0x0501 -#define BITMAP WINDOWS_BITMAP -#include -#include -#undef BITMAP - -#include -#include - -#include - -#include -#include -#include -#include -#include "86box.h" -#include "ibm.h" -#include "ide.h" -#include "cdrom-null.h" -#include "cdrom-ioctl.h" -#include "cdrom-iso.h" -#include "config.h" -#include "video.h" -#include "resources.h" -#include "cpu.h" -#include "cdrom.h" -#include "model.h" -#include "mouse.h" -#include "nethandler.h" -#include "nvr.h" -#include "sound.h" -#include "thread.h" -#include "disc.h" - -#include "plat-midi.h" -#include "plat-keyboard.h" - -#include "win.h" -#include "win-ddraw.h" -#include "win-ddraw-fs.h" -#include "win-d3d.h" -#include "win-d3d-fs.h" -//#include "win-opengl.h" - -#ifndef MAPVK_VK_TO_VSC -#define MAPVK_VK_TO_VSC 0 -#endif - -static int save_window_pos = 0; -uint64_t timer_freq; - -int rawinputkey[272]; - -static RAWINPUTDEVICE device; -static uint16_t scancode_map[65536]; - -static struct -{ - void (*init)(HWND h); - void (*close)(); - void (*resize)(int x, int y); -} vid_apis[2][2] = -{ - { - ddraw_init, ddraw_close, NULL, - d3d_init, d3d_close, d3d_resize - }, - { - ddraw_fs_init, ddraw_fs_close, NULL, - d3d_fs_init, d3d_fs_close, NULL - }, -}; - -#define TIMER_1SEC 1 - -int winsizex=640,winsizey=480; -int efwinsizey=480; -int gfx_present[GFX_MAX]; - -HANDLE ghMutex; - -HANDLE mainthreadh; - -int infocus=1; - -int drawits=0; - -int romspresent[ROM_MAX]; -int quited=0; - -RECT oldclip; -int mousecapture=0; - -/* Declare Windows procedure */ -LRESULT CALLBACK WindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); -LRESULT CALLBACK subWindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); - -HWND ghwnd; - -HINSTANCE hinstance; - -HMENU menu; - -extern int updatestatus; - -int pause=0; - -static int win_doresize = 0; - -static int leave_fullscreen_flag = 0; - -void updatewindowsize(int x, int y) -{ - RECT r; - if (vid_resize) return; - - if (x < 160) x = 160; - if (y < 100) y = 100; - - winsizex=x; efwinsizey=y; - - if (force_43) - { - /* Account for possible overscan. */ - if (overscan_y == 16) - { - /* CGA */ - winsizey = ((int) (((double) (x - overscan_x) / 4.0) * 3.0)) + overscan_y; - } - else if (overscan_y < 16) - { - /* MDA/Hercules */ - winsizey = efwinsizey; - } - else - { - if (enable_overscan) - { - /* EGA/(S)VGA with overscan */ - winsizey = ((int) (((double) (x - overscan_x) / 4.0) * 3.0)) + overscan_y; - } - else - { - /* EGA/(S)VGA without overscan */ - winsizey = efwinsizey; - } - } - } - else - { - winsizey = efwinsizey; - } - - win_doresize = 1; -} - -void uws_natural() -{ - updatewindowsize(winsizex, efwinsizey); -} - -void releasemouse() -{ - if (mousecapture) - { - ClipCursor(&oldclip); - ShowCursor(TRUE); - mousecapture = 0; - } -} - -void startblit() -{ - WaitForSingleObject(ghMutex, INFINITE); -} - -void endblit() -{ - ReleaseMutex(ghMutex); -} - -void leave_fullscreen() -{ - leave_fullscreen_flag = 1; -} - -uint64_t main_time; - -uint64_t start_time; -uint64_t end_time; - -void mainthread(LPVOID param) -{ - int t = 0; - int frames = 0; - DWORD old_time, new_time; - -// Sleep(500); - drawits=0; - old_time = GetTickCount(); - while (!quited) - { - if (updatestatus) - { - updatestatus = 0; - if (status_is_open) - SendMessage(status_hwnd, WM_USER, 0, 0); - } - new_time = GetTickCount(); - drawits += new_time - old_time; - old_time = new_time; - if (drawits > 0 && !pause) - { - start_time = timer_read(); - drawits-=10; if (drawits>50) drawits=0; - runpc(); - frames++; - if (frames >= 200 && nvr_dosave) - { - frames = 0; - nvr_dosave = 0; - savenvr(); - } - end_time = timer_read(); - main_time += end_time - start_time; - } - else - Sleep(1); - - if (!video_fullscreen && win_doresize) - { - RECT r; - video_wait_for_blit(); - GetWindowRect(ghwnd, &r); - MoveWindow(ghwnd, r.left, r.top, - winsizex + (GetSystemMetrics(SM_CXFIXEDFRAME) * 2), - winsizey + (GetSystemMetrics(SM_CYFIXEDFRAME) * 2) + GetSystemMetrics(SM_CYMENUSIZE) + GetSystemMetrics(SM_CYCAPTION) + 1, - TRUE); - win_doresize = 0; - } - - if (leave_fullscreen_flag) - { - leave_fullscreen_flag = 0; - SendMessage(ghwnd, WM_LEAVEFULLSCREEN, 0, 0); - } - if (video_fullscreen && infocus) - { - SetCursorPos(9999, 9999); - } - } -} - -void *thread_create(void (*thread_rout)(void *param), void *param) -{ - return (void *)_beginthread(thread_rout, 0, param); -} - -void thread_kill(void *handle) -{ - TerminateThread(handle, 0); -} - -void thread_sleep(int t) -{ - Sleep(t); -} - -typedef struct win_event_t -{ - HANDLE handle; -} win_event_t; - -event_t *thread_create_event() -{ - win_event_t *event = malloc(sizeof(win_event_t)); - - event->handle = CreateEvent(NULL, FALSE, FALSE, NULL); - - return (event_t *)event; -} - -void thread_set_event(event_t *_event) -{ - win_event_t *event = (win_event_t *)_event; - - SetEvent(event->handle); -} - -void thread_reset_event(event_t *_event) -{ - win_event_t *event = (win_event_t *)_event; - - ResetEvent(event->handle); -} - -int thread_wait_event(event_t *_event, int timeout) -{ - win_event_t *event = (win_event_t *)_event; - - if (timeout == -1) - timeout = INFINITE; - - if (WaitForSingleObject(event->handle, timeout)) - return 1; - return 0; -} - -void thread_destroy_event(event_t *_event) -{ - win_event_t *event = (win_event_t *)_event; - - CloseHandle(event->handle); - - free(event); -} - -static void initmenu(void) -{ - int c; - HMENU m; - char s[32]; - m=GetSubMenu(menu,1); /*Disc*/ - m=GetSubMenu(m,17); /*CD-ROM*/ - - /* Loop through each Windows drive letter and test to see if - it's a CDROM */ - for (c='A';c<='Z';c++) - { - sprintf(s,"%c:\\",c); - if (GetDriveType(s)==DRIVE_CDROM) - { - sprintf(s, "Host CD/DVD Drive (%c:)", c); - AppendMenu(m,MF_STRING,IDM_CDROM_REAL+c,s); - } - } -} - -void get_executable_name(char *s, int size) -{ - GetModuleFileName(hinstance, s, size); -} - -void set_window_title(char *s) -{ - if (video_fullscreen) - return; - SetWindowText(ghwnd, s); -} - -uint64_t timer_read() -{ - LARGE_INTEGER qpc_time; - QueryPerformanceCounter(&qpc_time); - return qpc_time.QuadPart; -} - -/* This is so we can disambiguate scan codes that would otherwise conflict and get - passed on incorrectly. */ -UINT16 convert_scan_code(UINT16 scan_code) -{ - switch (scan_code) - { - case 0xE001: - return 0xF001; - case 0xE002: - return 0xF002; - case 0xE0AA: - return 0xF003; - case 0xE005: - return 0xF005; - case 0xE006: - return 0xF006; - case 0xE007: - return 0xF007; - case 0xE071: - return 0xF008; - case 0xE072: - return 0xF009; - case 0xE07F: - return 0xF00A; - case 0xE0E1: - return 0xF00B; - case 0xE0EE: - return 0xF00C; - case 0xE0F1: - return 0xF00D; - case 0xE0FE: - return 0xF00E; - case 0xE0EF: - return 0xF00F; - - default: - return scan_code; - } -} - -void get_registry_key_map() -{ - char *keyName = "SYSTEM\\CurrentControlSet\\Control\\Keyboard Layout"; - char *valueName = "Scancode Map"; - char buf[32768]; - DWORD bufSize; - HKEY hKey; - int j; - - /* First, prepare the default scan code map list which is 1:1. - Remappings will be inserted directly into it. - 65536 bytes so scan codes fit in easily and it's easy to find what each maps too, - since each array element is a scan code and provides for E0, etc. ones too. */ - for (j = 0; j < 65536; j++) - scancode_map[j] = convert_scan_code(j); - - bufSize = 32768; - /* Get the scan code remappings from: - HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Keyboard Layout */ - if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, keyName, 0, 1, &hKey) == ERROR_SUCCESS) - { - if(RegQueryValueEx(hKey, valueName, NULL, NULL, buf, &bufSize) == ERROR_SUCCESS) - { - UINT32 *bufEx2 = (UINT32 *) buf; - int scMapCount = bufEx2[2]; - if ((bufSize != 0) && (scMapCount != 0)) - { - UINT16 *bufEx = (UINT16 *) (buf + 12); - for (j = 0; j < scMapCount*2; j += 2) - { - /* Each scan code is 32-bit: 16 bits of remapped scan code, - and 16 bits of original scan code. */ - int scancode_unmapped = bufEx[j + 1]; - int scancode_mapped = bufEx[j]; - - scancode_mapped = convert_scan_code(scancode_mapped); - - /* Fixes scan code map logging. */ - scancode_map[scancode_unmapped] = scancode_mapped; - } - } - } - RegCloseKey(hKey); - } -} - -static char **argv; -static int argc; -static char *argbuf; - -static void process_command_line() -{ - char *cmdline; - int argc_max; - int i, q; - - cmdline = GetCommandLine(); - i = strlen(cmdline) + 1; - argbuf = malloc(i); - memcpy(argbuf, cmdline, i); - - argc = 0; - argc_max = 64; - argv = malloc(sizeof(char *) * argc_max); - if (!argv) - { - free(argbuf); - return; - } - - i = 0; - - /* parse commandline into argc/argv format */ - while (argbuf[i]) - { - while (argbuf[i] == ' ') - i++; - - if (argbuf[i]) - { - if ((argbuf[i] == '\'') || (argbuf[i] == '"')) - { - q = argbuf[i++]; - if (!argbuf[i]) - break; - } - else - q = 0; - - argv[argc++] = &argbuf[i]; - - if (argc >= argc_max) - { - argc_max += 64; - argv = realloc(argv, sizeof(char *) * argc_max); - if (!argv) - { - free(argbuf); - return; - } - } - - while ((argbuf[i]) && ((q) ? (argbuf[i] != q) : (argbuf[i] != ' '))) - i++; - - if (argbuf[i]) - { - argbuf[i] = 0; - i++; - } - // pclog("Arg %i - %s\n",argc-1,argv[argc-1]); - } - } - - argv[argc] = NULL; -} - -HANDLE hinstAcc; - -int WINAPI WinMain (HINSTANCE hThisInstance, - HINSTANCE hPrevInstance, - LPSTR lpszArgument, - int nFunsterStil) - -{ - HWND hwnd; /* This is the handle for our window */ - MSG messages; /* Here messages to the application are saved */ - WNDCLASSEX wincl; /* Data structure for the windowclass */ - int c, d, bRet; - char emulator_title[200]; - LARGE_INTEGER qpc_freq; - HACCEL haccel; /* Handle to accelerator table */ - - process_command_line(); - - hinstance=hThisInstance; - /* The Window structure */ - wincl.hInstance = hThisInstance; - wincl.lpszClassName = szClassName; - wincl.lpfnWndProc = WindowProcedure; /* This function is called by windows */ - wincl.style = CS_DBLCLKS; /* Catch double-clicks */ - wincl.cbSize = sizeof (WNDCLASSEX); - - /* Use default icon and mouse-pointer */ - wincl.hIcon = LoadIcon (hinstance, 100); - wincl.hIconSm = LoadIcon (hinstance, 100); - wincl.hCursor = NULL;//LoadCursor (NULL, IDC_ARROW); - wincl.lpszMenuName = NULL; /* No menu */ - wincl.cbClsExtra = 0; /* No extra bytes after the window class */ - wincl.cbWndExtra = 0; /* structure or the window instance */ - /* Use Windows's default color as the background of the window */ - wincl.hbrBackground = (HBRUSH) COLOR_BACKGROUND; - - /* Register the window class, and if it fails quit the program */ - if (!RegisterClassEx(&wincl)) - return 0; - - wincl.lpszClassName = szSubClassName; - wincl.lpfnWndProc = subWindowProcedure; /* This function is called by windows */ - - if (!RegisterClassEx(&wincl)) - return 0; - - menu = LoadMenu(hThisInstance, TEXT("MainMenu")); - initmenu(); - - sprintf(emulator_title, "86Box v%s", emulator_version); - - /* The class is registered, let's create the program*/ - hwnd = CreateWindowEx ( - 0, /* Extended possibilites for variation */ - szClassName, /* Classname */ - emulator_title, /* Title Text */ - WS_OVERLAPPEDWINDOW&~WS_SIZEBOX, /* default window */ - CW_USEDEFAULT, /* Windows decides the position */ - CW_USEDEFAULT, /* where the window ends up on the screen */ - 640+(GetSystemMetrics(SM_CXFIXEDFRAME)*2), /* The programs width */ - 480+(GetSystemMetrics(SM_CYFIXEDFRAME)*2)+GetSystemMetrics(SM_CYMENUSIZE)+GetSystemMetrics(SM_CYCAPTION)+1, /* and height in pixels */ - HWND_DESKTOP, /* The window is a child-window to desktop */ - menu, /* Menu */ - hThisInstance, /* Program Instance handler */ - NULL /* No Window Creation data */ - ); - - /* Make the window visible on the screen */ - ShowWindow (hwnd, nFunsterStil); - - /* Load the accelerator table */ - haccel = LoadAccelerators(hinstAcc, "MainAccel"); - if (haccel == NULL) - fatal("haccel is null\n"); - -// win_set_window(hwnd); - - memset(rawinputkey, 0, sizeof(rawinputkey)); - device.usUsagePage = 0x01; - device.usUsage = 0x06; - device.dwFlags = RIDEV_NOHOTKEYS; - device.hwndTarget = hwnd; - - if (RegisterRawInputDevices(&device, 1, sizeof(device))) - pclog("Raw input registered!\n"); - else - pclog("Raw input registration failed!\n"); - - get_registry_key_map(); - - ghwnd=hwnd; - - initpc(argc, argv); - - // pclog("Setting video API...\n"); - vid_apis[0][vid_api].init(ghwnd); - - // pclog("Resizing window...\n"); - if (vid_resize) SetWindowLong(hwnd, GWL_STYLE, WS_OVERLAPPEDWINDOW|WS_VISIBLE); - else SetWindowLong(hwnd, GWL_STYLE, (WS_OVERLAPPEDWINDOW&~WS_SIZEBOX&~WS_THICKFRAME&~WS_MAXIMIZEBOX)|WS_VISIBLE); - - SetWindowLong(hwnd, GWL_STYLE, GetWindowLong(hwnd, GWL_STYLE) & ~WS_MINIMIZEBOX); - - // pclog("Checking CD-ROM menu item...\n"); - - /* Note by Kiririn: I've redone this since the CD-ROM can be disabled but still have something inside it. */ - if (cdrom_enabled) - CheckMenuItem(menu, IDM_CDROM_ENABLED, MF_CHECKED); - - if (scsi_cdrom_enabled) - CheckMenuItem(menu, IDM_CDROM_SCSI, MF_CHECKED); - - if (ide_enable[2]) - CheckMenuItem(menu, IDM_IDE_TER_ENABLED, MF_CHECKED); - - CheckMenuItem(menu, IDM_IDE_TER_IRQ9, MF_UNCHECKED); - CheckMenuItem(menu, IDM_IDE_TER_IRQ10, MF_UNCHECKED); - CheckMenuItem(menu, IDM_IDE_TER_IRQ11, MF_UNCHECKED); - CheckMenuItem(menu, IDM_IDE_TER_IRQ12, MF_UNCHECKED); - CheckMenuItem(menu, IDM_IDE_TER_IRQ14, MF_UNCHECKED); - CheckMenuItem(menu, IDM_IDE_TER_IRQ15, MF_UNCHECKED); - - if (ide_irq[2] == 9) - { - CheckMenuItem(menu, IDM_IDE_TER_IRQ9, MF_CHECKED); - } - else if (ide_irq[2] == 10) - { - CheckMenuItem(menu, IDM_IDE_TER_IRQ10, MF_CHECKED); - } - else if (ide_irq[2] == 11) - { - CheckMenuItem(menu, IDM_IDE_TER_IRQ11, MF_CHECKED); - } - else if (ide_irq[2] == 12) - { - CheckMenuItem(menu, IDM_IDE_TER_IRQ12, MF_CHECKED); - } - else if (ide_irq[2] == 14) - { - CheckMenuItem(menu, IDM_IDE_TER_IRQ14, MF_CHECKED); - } - else if (ide_irq[2] == 15) - { - CheckMenuItem(menu, IDM_IDE_TER_IRQ15, MF_CHECKED); - } - else - { - fatal("Unrecognized tertiary IDE controller IRQ\n"); - } - - if (ide_enable[3]) - CheckMenuItem(menu, IDM_IDE_QUA_ENABLED, MF_CHECKED); - - CheckMenuItem(menu, IDM_IDE_QUA_IRQ9, MF_UNCHECKED); - CheckMenuItem(menu, IDM_IDE_QUA_IRQ10, MF_UNCHECKED); - CheckMenuItem(menu, IDM_IDE_QUA_IRQ11, MF_UNCHECKED); - CheckMenuItem(menu, IDM_IDE_QUA_IRQ12, MF_UNCHECKED); - CheckMenuItem(menu, IDM_IDE_QUA_IRQ14, MF_UNCHECKED); - CheckMenuItem(menu, IDM_IDE_QUA_IRQ15, MF_UNCHECKED); - - if (ide_irq[3] == 9) - { - CheckMenuItem(menu, IDM_IDE_QUA_IRQ9, MF_CHECKED); - } - else if (ide_irq[3] == 10) - { - CheckMenuItem(menu, IDM_IDE_QUA_IRQ10, MF_CHECKED); - } - else if (ide_irq[3] == 11) - { - CheckMenuItem(menu, IDM_IDE_QUA_IRQ11, MF_CHECKED); - } - else if (ide_irq[3] == 12) - { - CheckMenuItem(menu, IDM_IDE_QUA_IRQ12, MF_CHECKED); - } - else if (ide_irq[3] == 14) - { - CheckMenuItem(menu, IDM_IDE_QUA_IRQ14, MF_CHECKED); - } - else if (ide_irq[3] == 15) - { - CheckMenuItem(menu, IDM_IDE_QUA_IRQ15, MF_CHECKED); - } - else - { - fatal("Unrecognized quaternary IDE controller IRQ\n"); - } - - if (buslogic_enabled) - CheckMenuItem(menu, IDM_SCSI_ENABLED, MF_CHECKED); - - CheckMenuItem(menu, IDM_SCSI_MODEL0, MF_UNCHECKED); - CheckMenuItem(menu, IDM_SCSI_MODEL1, MF_UNCHECKED); - - if (scsi_model == 0) - { - CheckMenuItem(menu, IDM_SCSI_MODEL0, MF_CHECKED); - } - else if (scsi_model == 1) - { - CheckMenuItem(menu, IDM_SCSI_MODEL1, MF_CHECKED); - } - else - { - fatal("Unrecognized SCSI model\n"); - } - - CheckMenuItem(menu, IDM_SCSI_BASE130, MF_UNCHECKED); - CheckMenuItem(menu, IDM_SCSI_BASE134, MF_UNCHECKED); - CheckMenuItem(menu, IDM_SCSI_BASE230, MF_UNCHECKED); - CheckMenuItem(menu, IDM_SCSI_BASE234, MF_UNCHECKED); - CheckMenuItem(menu, IDM_SCSI_BASE330, MF_UNCHECKED); - CheckMenuItem(menu, IDM_SCSI_BASE334, MF_UNCHECKED); - - if (scsi_base == 0x130) - { - CheckMenuItem(menu, IDM_SCSI_BASE130, MF_CHECKED); - } - else if (scsi_base == 0x134) - { - CheckMenuItem(menu, IDM_SCSI_BASE134, MF_CHECKED); - } - else if (scsi_base == 0x230) - { - CheckMenuItem(menu, IDM_SCSI_BASE230, MF_CHECKED); - } - else if (scsi_base == 0x234) - { - CheckMenuItem(menu, IDM_SCSI_BASE234, MF_CHECKED); - } - else if (scsi_base == 0x330) - { - CheckMenuItem(menu, IDM_SCSI_BASE330, MF_CHECKED); - } - else if (scsi_base == 0x334) - { - CheckMenuItem(menu, IDM_SCSI_BASE334, MF_CHECKED); - } - else - { - fatal("Unrecognized SCSI base address\n"); - } - - CheckMenuItem(menu, IDM_SCSI_IRQ9, MF_UNCHECKED); - CheckMenuItem(menu, IDM_SCSI_IRQ10, MF_UNCHECKED); - CheckMenuItem(menu, IDM_SCSI_IRQ11, MF_UNCHECKED); - CheckMenuItem(menu, IDM_SCSI_IRQ12, MF_UNCHECKED); - CheckMenuItem(menu, IDM_SCSI_IRQ14, MF_UNCHECKED); - CheckMenuItem(menu, IDM_SCSI_IRQ15, MF_UNCHECKED); - - if (scsi_irq == 9) - { - CheckMenuItem(menu, IDM_SCSI_IRQ9, MF_CHECKED); - } - else if (scsi_irq == 10) - { - CheckMenuItem(menu, IDM_SCSI_IRQ10, MF_CHECKED); - } - else if (scsi_irq == 11) - { - CheckMenuItem(menu, IDM_SCSI_IRQ11, MF_CHECKED); - } - else if (scsi_irq == 12) - { - CheckMenuItem(menu, IDM_SCSI_IRQ12, MF_CHECKED); - } - else if (scsi_irq == 14) - { - CheckMenuItem(menu, IDM_SCSI_IRQ14, MF_CHECKED); - } - else if (scsi_irq == 15) - { - CheckMenuItem(menu, IDM_SCSI_IRQ15, MF_CHECKED); - } - else - { - fatal("Unrecognized SCSI IRQ\n"); - } - - CheckMenuItem(menu, IDM_SCSI_DMA5, MF_UNCHECKED); - CheckMenuItem(menu, IDM_SCSI_DMA6, MF_UNCHECKED); - CheckMenuItem(menu, IDM_SCSI_DMA7, MF_UNCHECKED); - - if (scsi_dma == 5) - { - CheckMenuItem(menu, IDM_SCSI_DMA5, MF_CHECKED); - } - else if (scsi_dma == 6) - { - CheckMenuItem(menu, IDM_SCSI_DMA6, MF_CHECKED); - } - else if (scsi_dma == 7) - { - CheckMenuItem(menu, IDM_SCSI_DMA7, MF_CHECKED); - } - else - { - fatal("Unrecognized SCSI DMA address\n"); - } - - if (cdrom_drive == 200) - { - CheckMenuItem(menu, IDM_CDROM_ISO, MF_CHECKED); - } - else - { - CheckMenuItem(menu, IDM_CDROM_REAL + cdrom_drive, MF_CHECKED); - } - - CheckMenuItem(menu, IDM_VID_FORCE43, force_43 ? MF_CHECKED : MF_UNCHECKED); - CheckMenuItem(menu, IDM_VID_OVERSCAN, enable_overscan ? MF_CHECKED : MF_UNCHECKED); - CheckMenuItem(menu, IDM_VID_FLASH, enable_flash ? MF_CHECKED : MF_UNCHECKED); - - // pclog("Checking video resize menu item...\n"); - if (vid_resize) CheckMenuItem(menu, IDM_VID_RESIZE, MF_CHECKED); - // pclog("Checking video API menu item...\n"); - CheckMenuItem(menu, IDM_VID_DDRAW + vid_api, MF_CHECKED); - // pclog("Checking video fill screen menu item...\n"); - CheckMenuItem(menu, IDM_VID_FS_FULL + video_fullscreen_scale, MF_CHECKED); - CheckMenuItem(menu, IDM_VID_REMEMBER, window_remember ? MF_CHECKED : MF_UNCHECKED); -// set_display_switch_mode(SWITCH_BACKGROUND); - - // pclog("Preparing ROM sets...\n"); - d=romset; - for (c=0;c= 0; c--) - { - if (gfx_present[c]) - { - gfxcard = c; - saveconfig(); - resetpchard(); - break; - } - } - } - - loadbios(); - resetpchard(); - - timeBeginPeriod(1); - - atexit(releasemouse); - -// QueryPerformanceFrequency(&counter_base); -/// QueryPerformanceCounter(&counter_posold); -// counter_posold.QuadPart*=100; - - ghMutex = CreateMutex(NULL, FALSE, NULL); - mainthreadh=(HANDLE)_beginthread(mainthread,0,NULL); - SetThreadPriority(mainthreadh, THREAD_PRIORITY_HIGHEST); - - - updatewindowsize(640, 480); - - QueryPerformanceFrequency(&qpc_freq); - timer_freq = qpc_freq.QuadPart; - -// focus=1; -// setrefresh(100); - -// ShowCursor(TRUE); - - if (start_in_fullscreen) - { - startblit(); - mouse_close(); - vid_apis[0][vid_api].close(); - video_fullscreen = 1; - vid_apis[1][vid_api].init(ghwnd); - mouse_init(); - leave_fullscreen_flag = 0; - endblit(); - device_force_redraw(); - } - if (window_remember) - { - MoveWindow(hwnd, window_x, window_y, - window_w, - window_h, - TRUE); - } - - /* Run the message loop. It will run until GetMessage() returns 0 */ - while (!quited) - { -/* if (infocus) - { - if (drawits) - { - drawits--; - if (drawits>10) drawits=0; - runpc(); - } -//; else -// sleep(0); - // if ((recv_key[KEY_LCONTROL] || recv_key[KEY_RCONTROL]) && recv_key[KEY_END] && mousecapture) - // if ((recv_key[KEY_LCONTROL] || recv_key[KEY_RCONTROL]) && recv_key[0x58] && mousecapture) - // if (recv_key[0x58] && recv_key[0x42] && mousecapture) - { - ClipCursor(&oldclip); - mousecapture=0; - } - }*/ - - while (((bRet = GetMessage(&messages,NULL,0,0)) != 0) && !quited) - { - if (bRet == -1) - { - fatal("bRet is -1\n"); - } - - if (messages.message==WM_QUIT) quited=1; - if (!TranslateAccelerator(hwnd, haccel, &messages)) - { - TranslateMessage(&messages); - DispatchMessage(&messages); - } - // if ((recv_key[KEY_LCONTROL] || recv_key[KEY_RCONTROL]) && recv_key[KEY_END] && mousecapture) - - if (recv_key[0x58] && recv_key[0x42] && mousecapture) - { - ClipCursor(&oldclip); - ShowCursor(TRUE); - mousecapture=0; - } - - if ((recv_key[0x1D] || recv_key[0x9D]) && - (recv_key[0x38] || recv_key[0xB8]) && - (recv_key[0x51] || recv_key[0xD1]) && - video_fullscreen) - { - leave_fullscreen(); - } - } - - quited=1; -// else -// sleep(10); - } - - startblit(); -// pclog("Sleep 1000\n"); - Sleep(200); -// pclog("TerminateThread\n"); - TerminateThread(mainthreadh,0); -// pclog("Quited? %i\n",quited); -// pclog("Closepc\n"); - savenvr(); - saveconfig(); - if (save_window_pos && window_remember) - saveconfig(); - closepc(); -// pclog("dumpregs\n"); - - vid_apis[video_fullscreen][vid_api].close(); - - timeEndPeriod(1); -// dumpregs(); - if (mousecapture) - { - ClipCursor(&oldclip); - ShowCursor(TRUE); - } - - UnregisterClass(szSubClassName, hinstance); - UnregisterClass(szClassName, hinstance); - -// pclog("Ending! %i %i\n",messages.wParam,quited); - return messages.wParam; -} - -char openfilestring[260]; -int getfile(HWND hwnd, char *f, char *fn) -{ - OPENFILENAME ofn; // common dialog box structure - BOOL r; - DWORD err; - - // Initialize OPENFILENAME - ZeroMemory(&ofn, sizeof(ofn)); - ofn.lStructSize = sizeof(ofn); - ofn.hwndOwner = hwnd; - ofn.lpstrFile = openfilestring; - // - // Set lpstrFile[0] to '\0' so that GetOpenFileName does not - // use the contents of szFile to initialize itself. - // -// ofn.lpstrFile[0] = '\0'; - strcpy(ofn.lpstrFile,fn); - ofn.nMaxFile = sizeof(openfilestring); - ofn.lpstrFilter = f;//"All\0*.*\0Text\0*.TXT\0"; - ofn.nFilterIndex = 1; - ofn.lpstrFileTitle = NULL; - ofn.nMaxFileTitle = 0; - ofn.lpstrInitialDir = NULL; - ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST; - - // Display the Open dialog box. - - pclog("GetOpenFileName - lpstrFile = %s\n", ofn.lpstrFile); - r = GetOpenFileName(&ofn); - if (r) - { - pclog("GetOpenFileName return true\n"); - return 0; - } - pclog("GetOpenFileName return false\n"); - err = CommDlgExtendedError(); - pclog("CommDlgExtendedError return %04X\n", err); - return 1; -} - -int getsfile(HWND hwnd, char *f, char *fn) -{ - OPENFILENAME ofn; // common dialog box structure - BOOL r; - DWORD err; - - // Initialize OPENFILENAME - ZeroMemory(&ofn, sizeof(ofn)); - ofn.lStructSize = sizeof(ofn); - ofn.hwndOwner = hwnd; - ofn.lpstrFile = openfilestring; - // - // Set lpstrFile[0] to '\0' so that GetOpenFileName does not - // use the contents of szFile to initialize itself. - // -// ofn.lpstrFile[0] = '\0'; - strcpy(ofn.lpstrFile,fn); - ofn.nMaxFile = sizeof(openfilestring); - ofn.lpstrFilter = f;//"All\0*.*\0Text\0*.TXT\0"; - ofn.nFilterIndex = 1; - ofn.lpstrFileTitle = NULL; - ofn.nMaxFileTitle = 0; - ofn.lpstrInitialDir = NULL; - ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST; - - // Display the Open dialog box. - - pclog("GetSaveFileName - lpstrFile = %s\n", ofn.lpstrFile); - r = GetSaveFileName(&ofn); - if (r) - { - pclog("GetSaveFileName return true\n"); - return 0; - } - pclog("GetSaveFileName return false\n"); - err = CommDlgExtendedError(); - pclog("CommDlgExtendedError return %04X\n", err); - return 1; -} - - - - -HHOOK hKeyboardHook; - -LRESULT CALLBACK LowLevelKeyboardProc( int nCode, WPARAM wParam, LPARAM lParam ) -{ - BOOL bControlKeyDown; - KBDLLHOOKSTRUCT* p; - - if (nCode < 0 || nCode != HC_ACTION || (!mousecapture && !video_fullscreen)) - return CallNextHookEx( hKeyboardHook, nCode, wParam, lParam); - - p = (KBDLLHOOKSTRUCT*)lParam; - - if (p->vkCode == VK_TAB && p->flags & LLKHF_ALTDOWN) return 1; //disable alt-tab - if (p->vkCode == VK_SPACE && p->flags & LLKHF_ALTDOWN) return 1; //disable alt-tab - if((p->vkCode == VK_LWIN) || (p->vkCode == VK_RWIN)) return 1;//disable windows keys - if (p->vkCode == VK_ESCAPE && p->flags & LLKHF_ALTDOWN) return 1;//disable alt-escape - bControlKeyDown = GetAsyncKeyState (VK_CONTROL) >> ((sizeof(SHORT) * 8) - 1);//checks ctrl key pressed - if (p->vkCode == VK_ESCAPE && bControlKeyDown) return 1; //disable ctrl-escape - - return CallNextHookEx( hKeyboardHook, nCode, wParam, lParam ); -} - -void cdrom_close(void) -{ - switch (cdrom_drive) - { - case 0: - null_close(); - break; - default: - ioctl_close(); - break; - case 200: - iso_close(); - break; - } -} - -char *floppy_image_extensions = "All floppy images (*.001;*.002;*.003;*.004;*.005;*.006;*.007;*.008;*.009;*.010;*.12;*.144;*.360;*.720;*.86F;*.BIN;*.CQ;*.CQM;*.DSK;*.FDI;*.FLP;*.HDM;*.IMA;*.IMD;*.IMG;*.TD0;*.VFD;*.XDF)\0*.001;*.002;*.003;*.004;*.005;*.006;*.007;*.008;*.009;*.010;*.12;*.144;*.360;*.720;*.86F;*.BIN;*.CQ;*.CQM;*.DSK;*.FDI;*.FLP;*.HDM;*.IMA;*.IMD;*.IMG;*.TD0;*.VFD;*.XDF\0Advanced sector-based images (*.IMD;*.TD0)\0*.IMD;*.TD0\0Basic sector-based images (*.001;*.002;*.003;*.004;*.005;*.006;*.007;*.008;*.009;*.010;*.12;*.144;*.360;*.720;*.BIN;*.CQ;*.CQM;*.DSK;*.FDI;*.FLP;*.HDM;*.IMA;*.IMG;*.VFD;*.XDF)\0*.001;*.002;*.003;*.004;*.005;*.006;*.007;*.008;*.009;*.010;*.12;*.144;*.360;*.720;*.BIN;*.CQ;*.CQM;*.DSK;*.FDI;*.FLP;*.HDM;*.IMA;*.IMG;*.VFD;*.XDF\0Flux images (*.FDI)\0*.FDI\0Surface-based images (*.86F)\0*.86F\0All files (*.*)\0*.*\0"; - -int ide_ter_set_irq(HMENU hmenu, int irq, int id) -{ - if (ide_irq[2] == irq) - { - return 0; - } - if (MessageBox(NULL,"This will reset 86Box!\nOkay to continue?","86Box",MB_OKCANCEL) != IDOK) - { - return 0; - } - pause = 1; - Sleep(100); - ide_irq[2] = irq; - CheckMenuItem(hmenu, IDM_IDE_TER_IRQ9, MF_UNCHECKED); - CheckMenuItem(hmenu, IDM_IDE_TER_IRQ10, MF_UNCHECKED); - CheckMenuItem(hmenu, IDM_IDE_TER_IRQ11, MF_UNCHECKED); - CheckMenuItem(hmenu, IDM_IDE_TER_IRQ12, MF_UNCHECKED); - CheckMenuItem(hmenu, IDM_IDE_TER_IRQ14, MF_UNCHECKED); - CheckMenuItem(hmenu, IDM_IDE_TER_IRQ15, MF_UNCHECKED); - CheckMenuItem(hmenu, id, MF_CHECKED); - saveconfig(); - resetpchard(); - pause = 0; - return 1; -} - -int ide_qua_set_irq(HMENU hmenu, int irq, int id) -{ - if (ide_irq[3] == irq) - { - return 0; - } - if (MessageBox(NULL,"This will reset 86Box!\nOkay to continue?","86Box",MB_OKCANCEL) != IDOK) - { - return 0; - } - pause = 1; - Sleep(100); - ide_irq[3] = irq; - CheckMenuItem(hmenu, IDM_IDE_QUA_IRQ9, MF_UNCHECKED); - CheckMenuItem(hmenu, IDM_IDE_QUA_IRQ10, MF_UNCHECKED); - CheckMenuItem(hmenu, IDM_IDE_QUA_IRQ11, MF_UNCHECKED); - CheckMenuItem(hmenu, IDM_IDE_QUA_IRQ12, MF_UNCHECKED); - CheckMenuItem(hmenu, IDM_IDE_QUA_IRQ14, MF_UNCHECKED); - CheckMenuItem(hmenu, IDM_IDE_QUA_IRQ15, MF_UNCHECKED); - CheckMenuItem(hmenu, id, MF_CHECKED); - saveconfig(); - resetpchard(); - pause = 0; - return 1; -} - -int scsi_set_model(HMENU hmenu, int model, int id) -{ - if (scsi_model == model) - { - return 0; - } - if (MessageBox(NULL,"This will reset 86Box!\nOkay to continue?","86Box",MB_OKCANCEL) != IDOK) - { - return 0; - } - pause = 1; - Sleep(100); - scsi_model = model; - CheckMenuItem(hmenu, IDM_SCSI_MODEL0, MF_UNCHECKED); - CheckMenuItem(hmenu, IDM_SCSI_MODEL1, MF_UNCHECKED); - CheckMenuItem(hmenu, id, MF_CHECKED); - saveconfig(); - resetpchard(); - pause = 0; - return 1; -} - -int scsi_set_base(HMENU hmenu, int base, int id) -{ - if (scsi_base == base) - { - return 0; - } - if (MessageBox(NULL,"This will reset 86Box!\nOkay to continue?","86Box",MB_OKCANCEL) != IDOK) - { - return 0; - } - pause = 1; - Sleep(100); - scsi_base = base; - CheckMenuItem(hmenu, IDM_SCSI_BASE130, MF_UNCHECKED); - CheckMenuItem(hmenu, IDM_SCSI_BASE134, MF_UNCHECKED); - CheckMenuItem(hmenu, IDM_SCSI_BASE230, MF_UNCHECKED); - CheckMenuItem(hmenu, IDM_SCSI_BASE234, MF_UNCHECKED); - CheckMenuItem(hmenu, IDM_SCSI_BASE330, MF_UNCHECKED); - CheckMenuItem(hmenu, IDM_SCSI_BASE334, MF_UNCHECKED); - CheckMenuItem(hmenu, id, MF_CHECKED); - saveconfig(); - resetpchard(); - pause = 0; - return 1; -} - -int scsi_set_irq(HMENU hmenu, int irq, int id) -{ - if (scsi_irq == irq) - { - return 0; - } - if (MessageBox(NULL,"This will reset 86Box!\nOkay to continue?","86Box",MB_OKCANCEL) != IDOK) - { - return 0; - } - pause = 1; - Sleep(100); - scsi_irq = irq; - CheckMenuItem(hmenu, IDM_SCSI_IRQ9, MF_UNCHECKED); - CheckMenuItem(hmenu, IDM_SCSI_IRQ10, MF_UNCHECKED); - CheckMenuItem(hmenu, IDM_SCSI_IRQ11, MF_UNCHECKED); - CheckMenuItem(hmenu, IDM_SCSI_IRQ12, MF_UNCHECKED); - CheckMenuItem(hmenu, IDM_SCSI_IRQ14, MF_UNCHECKED); - CheckMenuItem(hmenu, IDM_SCSI_IRQ15, MF_UNCHECKED); - CheckMenuItem(hmenu, id, MF_CHECKED); - saveconfig(); - resetpchard(); - pause = 0; - return 1; -} - -int scsi_set_dma(HMENU hmenu, int dma, int id) -{ - if (scsi_dma == dma) - { - return 0; - } - if (MessageBox(NULL,"This will reset 86Box!\nOkay to continue?","86Box",MB_OKCANCEL) != IDOK) - { - return 0; - } - pause = 1; - Sleep(100); - scsi_dma = dma; - CheckMenuItem(hmenu, IDM_SCSI_DMA5, MF_UNCHECKED); - CheckMenuItem(hmenu, IDM_SCSI_DMA6, MF_UNCHECKED); - CheckMenuItem(hmenu, IDM_SCSI_DMA7, MF_UNCHECKED); - CheckMenuItem(hmenu, id, MF_CHECKED); - saveconfig(); - resetpchard(); - pause = 0; - return 1; -} - -void video_toggle_option(HMENU hmenu, int *val, int id) -{ - *val ^= 1; - CheckMenuItem(hmenu, id, *val ? MF_CHECKED : MF_UNCHECKED); - saveconfig(); -} - -void win_cdrom_eject() -{ - HMENU hmenu; - hmenu=GetMenu(ghwnd); - if (cdrom_drive == 0) - { - /* Switch from empty to empty. Do nothing. */ - return; - } - cdrom->exit(); - cdrom_close(); - cdrom_null_open(0); - if (cdrom_enabled) - { - /* Signal disc change to the emulated machine. */ - SCSICDROM_Insert(); - } - CheckMenuItem(hmenu, IDM_CDROM_REAL + cdrom_drive, MF_UNCHECKED); - CheckMenuItem(hmenu, IDM_CDROM_ISO, MF_UNCHECKED); - old_cdrom_drive = cdrom_drive; - cdrom_drive=0; - CheckMenuItem(hmenu, IDM_CDROM_EMPTY, MF_CHECKED); - saveconfig(); -} - -void win_cdrom_reload() -{ - HMENU hmenu; - hmenu=GetMenu(ghwnd); - int new_cdrom_drive; - if ((cdrom_drive == old_cdrom_drive) || (old_cdrom_drive == 0) || (cdrom_drive != 0)) - { - /* Switch from empty to empty. Do nothing. */ - return; - } - if (old_cdrom_drive == 200) - { - iso_open(iso_path); - if (cdrom_enabled) - { - /* Signal disc change to the emulated machine. */ - SCSICDROM_Insert(); - } - CheckMenuItem(hmenu, IDM_CDROM_REAL + cdrom_drive, MF_UNCHECKED); - // CheckMenuItem(hmenu, IDM_CDROM_DISABLED, MF_UNCHECKED); - CheckMenuItem(hmenu, IDM_CDROM_ISO, MF_UNCHECKED); - cdrom_drive = 200; - CheckMenuItem(hmenu, IDM_CDROM_ISO, MF_CHECKED); - saveconfig(); - } - else - { - new_cdrom_drive = old_cdrom_drive; - ioctl_open(new_cdrom_drive); - if (cdrom_enabled) - { - /* Signal disc change to the emulated machine. */ - SCSICDROM_Insert(); - } - CheckMenuItem(hmenu, IDM_CDROM_REAL + cdrom_drive, MF_UNCHECKED); - CheckMenuItem(hmenu, IDM_CDROM_ISO, MF_UNCHECKED); - cdrom_drive = new_cdrom_drive; - CheckMenuItem(hmenu, IDM_CDROM_REAL + cdrom_drive, MF_CHECKED); - saveconfig(); - } -} - -LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) -{ - HMENU hmenu; - RECT rect; - uint32_t ri_size = 0; - char temp_iso_path[1024]; - int new_cdrom_drive; -// pclog("Message %i %08X\n",message,message); - switch (message) - { - case WM_CREATE: - SetTimer(hwnd, TIMER_1SEC, 1000, NULL); - hKeyboardHook = SetWindowsHookEx( WH_KEYBOARD_LL, LowLevelKeyboardProc, GetModuleHandle(NULL), 0 ); - break; - - case WM_COMMAND: -// pclog("WM_COMMAND %i\n",LOWORD(wParam)); - hmenu=GetMenu(hwnd); - switch (LOWORD(wParam)) - { -#if 0 - case IDM_FILE_RESET: - pause=1; - Sleep(100); - savenvr(); - saveconfig(); - resetpc(); - pause=0; - break; -#endif - case IDM_FILE_HRESET: - pause=1; - Sleep(100); - savenvr(); - saveconfig(); - resetpchard(); - pause=0; - break; - case IDM_FILE_RESET_CAD: - pause=1; - Sleep(100); - savenvr(); - saveconfig(); - resetpc_cad(); - pause=0; - break; - case IDM_FILE_EXIT: - PostQuitMessage (0); /* send a WM_QUIT to the message queue */ - break; - case IDM_DISC_1: - case IDM_DISC_1_WP: - if (!getfile(hwnd, floppy_image_extensions, discfns[0])) - { - disc_close(0); - ui_writeprot[0] = (LOWORD(wParam) == IDM_DISC_1_WP) ? 1 : 0; - disc_load(0, openfilestring); - saveconfig(); - } - break; - case IDM_DISC_2: - case IDM_DISC_2_WP: - if (!getfile(hwnd, floppy_image_extensions, discfns[1])) - { - disc_close(1); - ui_writeprot[1] = (LOWORD(wParam) == IDM_DISC_2_WP) ? 1 : 0; - disc_load(1, openfilestring); - saveconfig(); - } - break; - case IDM_DISC_3: - case IDM_DISC_3_WP: - if (!getfile(hwnd, floppy_image_extensions, discfns[2])) - { - disc_close(2); - ui_writeprot[2] = (LOWORD(wParam) == IDM_DISC_3_WP) ? 1 : 0; - disc_load(2, openfilestring); - saveconfig(); - } - break; - case IDM_DISC_4: - case IDM_DISC_4_WP: - if (!getfile(hwnd, floppy_image_extensions, discfns[3])) - { - disc_close(3); - ui_writeprot[3] = (LOWORD(wParam) == IDM_DISC_4_WP) ? 1 : 0; - disc_load(3, openfilestring); - saveconfig(); - } - break; - case IDM_EJECT_1: - disc_close(0); - saveconfig(); - break; - case IDM_EJECT_2: - disc_close(1); - saveconfig(); - break; - case IDM_EJECT_3: - disc_close(2); - saveconfig(); - break; - case IDM_EJECT_4: - disc_close(3); - saveconfig(); - break; - case IDM_HDCONF: - hdconf_open(hwnd); - break; - case IDM_CONFIG: - config_open(hwnd); - break; - case IDM_STATUS: - status_open(hwnd); - break; - - case IDM_VID_RESIZE: - vid_resize=!vid_resize; - CheckMenuItem(hmenu, IDM_VID_RESIZE, (vid_resize)?MF_CHECKED:MF_UNCHECKED); - if (vid_resize) SetWindowLong(hwnd, GWL_STYLE, WS_OVERLAPPEDWINDOW|WS_VISIBLE); - else SetWindowLong(hwnd, GWL_STYLE, (WS_OVERLAPPEDWINDOW&~WS_SIZEBOX&~WS_THICKFRAME&~WS_MAXIMIZEBOX)|WS_VISIBLE); - SetWindowLong(hwnd, GWL_STYLE, GetWindowLong(hwnd, GWL_STYLE) & ~WS_MINIMIZEBOX); - GetWindowRect(hwnd,&rect); - SetWindowPos(hwnd, 0, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER | SWP_FRAMECHANGED); - saveconfig(); - break; - case IDM_VID_REMEMBER: - window_remember = !window_remember; - CheckMenuItem(hmenu, IDM_VID_REMEMBER, window_remember ? MF_CHECKED : MF_UNCHECKED); - GetWindowRect(hwnd, &rect); - if (window_remember) - { - window_x = rect.left; - window_y = rect.top; - window_w = rect.right - rect.left; - window_h = rect.bottom - rect.top; - } - saveconfig(); - break; - - case IDM_VID_DDRAW: case IDM_VID_D3D: - startblit(); - video_wait_for_blit(); - CheckMenuItem(hmenu, IDM_VID_DDRAW + vid_api, MF_UNCHECKED); - vid_apis[0][vid_api].close(); - vid_api = LOWORD(wParam) - IDM_VID_DDRAW; - CheckMenuItem(hmenu, IDM_VID_DDRAW + vid_api, MF_CHECKED); - vid_apis[0][vid_api].init(ghwnd); - endblit(); - saveconfig(); - device_force_redraw(); - break; - - case IDM_VID_FULLSCREEN: - if (video_fullscreen_first) - { - video_fullscreen_first = 0; - MessageBox(hwnd, "Use CTRL + ALT + PAGE DOWN to return to windowed mode", "86Box", MB_OK); - } - startblit(); - video_wait_for_blit(); - mouse_close(); - vid_apis[0][vid_api].close(); - video_fullscreen = 1; - vid_apis[1][vid_api].init(ghwnd); - mouse_init(); - leave_fullscreen_flag = 0; - endblit(); - device_force_redraw(); - break; - - case IDM_VID_FS_FULL: - case IDM_VID_FS_43: - case IDM_VID_FS_SQ: - case IDM_VID_FS_INT: - CheckMenuItem(hmenu, IDM_VID_FS_FULL + video_fullscreen_scale, MF_UNCHECKED); - video_fullscreen_scale = LOWORD(wParam) - IDM_VID_FS_FULL; - CheckMenuItem(hmenu, IDM_VID_FS_FULL + video_fullscreen_scale, MF_CHECKED); - saveconfig(); - break; - - case IDM_VID_FORCE43: - video_toggle_option(hmenu, &force_43, IDM_VID_FORCE43); - break; - - case IDM_VID_OVERSCAN: - video_toggle_option(hmenu, &enable_overscan, IDM_VID_OVERSCAN); - break; - - case IDM_VID_FLASH: - video_toggle_option(hmenu, &enable_flash, IDM_VID_FLASH); - break; - - case IDM_VID_SCREENSHOT: - take_screenshot(); - break; - - case IDM_CONFIG_LOAD: - pause = 1; - if (!getfile(hwnd, "Configuration (*.CFG)\0*.CFG\0All files (*.*)\0*.*\0", "")) - { - if (MessageBox(NULL, "This will reset 86Box!\nOkay to continue?", "86Box", MB_OKCANCEL) == IDOK) - { - loadconfig(openfilestring); - config_save(config_file_default); - mem_resize(); - loadbios(); - resetpchard(); - } - } - pause = 0; - break; - - case IDM_CONFIG_SAVE: - pause = 1; - if (!getsfile(hwnd, "Configuration (*.CFG)\0*.CFG\0All files (*.*)\0*.*\0", "")) - config_save(openfilestring); - pause = 0; - break; - -#if 0 - case IDM_CDROM_DISABLED: - if (cdrom_enabled) - { - if (MessageBox(NULL,"This will reset 86Box!\nOkay to continue?","86Box",MB_OKCANCEL) != IDOK) - break; - } - if (!cdrom_enabled) - { - /* Switching from disabled to disabled. Do nothing. */ - break; - } - cdrom->exit(); - cdrom_close(); - cdrom_null_open(0); - CheckMenuItem(hmenu, IDM_CDROM_REAL + cdrom_drive, MF_UNCHECKED); - CheckMenuItem(hmenu, IDM_CDROM_DISABLED, MF_CHECKED); - CheckMenuItem(hmenu, IDM_CDROM_ISO, MF_UNCHECKED); - old_cdrom_drive = cdrom_drive; - cdrom_drive=0; - CheckMenuItem(hmenu, IDM_CDROM_EMPTY, MF_UNCHECKED); - if (cdrom_enabled) - { - pause = 1; - Sleep(100); - cdrom_enabled = 0; - saveconfig(); - resetpchard(); - pause = 0; - } - break; -#endif - case IDM_CDROM_ENABLED: - if (MessageBox(NULL,"This will reset 86Box!\nOkay to continue?","86Box",MB_OKCANCEL) != IDOK) - { - break; - } - pause = 1; - Sleep(100); - cdrom_enabled ^= 1; - CheckMenuItem(hmenu, IDM_CDROM_ENABLED, cdrom_enabled ? MF_CHECKED : MF_UNCHECKED); - saveconfig(); - resetpchard(); - pause = 0; - break; - - case IDM_CDROM_SCSI: - if (MessageBox(NULL,"This will reset 86Box!\nOkay to continue?","86Box",MB_OKCANCEL) != IDOK) - { - break; - } - pause = 1; - Sleep(100); - scsi_cdrom_enabled ^= 1; - CheckMenuItem(hmenu, IDM_CDROM_SCSI, scsi_cdrom_enabled ? MF_CHECKED : MF_UNCHECKED); - saveconfig(); - resetpchard(); - pause = 0; - break; - - case IDM_IDE_TER_ENABLED: - if (MessageBox(NULL,"This will reset 86Box!\nOkay to continue?","86Box",MB_OKCANCEL) != IDOK) - { - break; - } - pause = 1; - Sleep(100); - ide_enable[2] ^= 1; - CheckMenuItem(hmenu, IDM_IDE_TER_ENABLED, ide_enable[2] ? MF_CHECKED : MF_UNCHECKED); - saveconfig(); - resetpchard(); - pause = 0; - break; - - case IDM_IDE_TER_IRQ9: - ide_ter_set_irq(hmenu, 9, IDM_IDE_TER_IRQ9); - break; - - case IDM_IDE_TER_IRQ10: - ide_ter_set_irq(hmenu, 10, IDM_IDE_TER_IRQ10); - break; - - case IDM_IDE_TER_IRQ11: - ide_ter_set_irq(hmenu, 11, IDM_IDE_TER_IRQ11); - break; - - case IDM_IDE_TER_IRQ12: - ide_ter_set_irq(hmenu, 12, IDM_IDE_TER_IRQ12); - break; - - case IDM_IDE_TER_IRQ14: - ide_ter_set_irq(hmenu, 14, IDM_IDE_TER_IRQ14); - break; - - case IDM_IDE_TER_IRQ15: - ide_ter_set_irq(hmenu, 15, IDM_IDE_TER_IRQ15); - break; - - case IDM_IDE_QUA_ENABLED: - if (MessageBox(NULL,"This will reset 86Box!\nOkay to continue?","86Box",MB_OKCANCEL) != IDOK) - { - break; - } - pause = 1; - Sleep(100); - ide_enable[3] ^= 1; - CheckMenuItem(hmenu, IDM_IDE_QUA_ENABLED, ide_enable[3] ? MF_CHECKED : MF_UNCHECKED); - saveconfig(); - resetpchard(); - pause = 0; - break; - - case IDM_IDE_QUA_IRQ9: - ide_qua_set_irq(hmenu, 9, IDM_IDE_QUA_IRQ9); - break; - - case IDM_IDE_QUA_IRQ10: - ide_qua_set_irq(hmenu, 10, IDM_IDE_QUA_IRQ10); - break; - - case IDM_IDE_QUA_IRQ11: - ide_qua_set_irq(hmenu, 11, IDM_IDE_QUA_IRQ11); - break; - - case IDM_IDE_QUA_IRQ12: - ide_qua_set_irq(hmenu, 12, IDM_IDE_QUA_IRQ12); - break; - - case IDM_IDE_QUA_IRQ14: - ide_qua_set_irq(hmenu, 14, IDM_IDE_QUA_IRQ14); - break; - - case IDM_IDE_QUA_IRQ15: - ide_qua_set_irq(hmenu, 15, IDM_IDE_QUA_IRQ15); - break; - - case IDM_SCSI_ENABLED: - if (MessageBox(NULL,"This will reset 86Box!\nOkay to continue?","86Box",MB_OKCANCEL) != IDOK) - { - break; - } - pause = 1; - Sleep(100); - buslogic_enabled ^= 1; - CheckMenuItem(hmenu, IDM_SCSI_ENABLED, buslogic_enabled ? MF_CHECKED : MF_UNCHECKED); - saveconfig(); - resetpchard(); - pause = 0; - break; - - case IDM_SCSI_MODEL0: - scsi_set_model(hmenu, 0, IDM_SCSI_MODEL0); - break; - - case IDM_SCSI_MODEL1: - scsi_set_model(hmenu, 1, IDM_SCSI_MODEL1); - break; - - case IDM_SCSI_BASE130: - scsi_set_base(hmenu, 0x130, IDM_SCSI_BASE130); - break; - - case IDM_SCSI_BASE134: - scsi_set_base(hmenu, 0x134, IDM_SCSI_BASE134); - break; - - case IDM_SCSI_BASE230: - scsi_set_base(hmenu, 0x230, IDM_SCSI_BASE230); - break; - - case IDM_SCSI_BASE234: - scsi_set_base(hmenu, 0x234, IDM_SCSI_BASE234); - break; - - case IDM_SCSI_BASE330: - scsi_set_base(hmenu, 0x330, IDM_SCSI_BASE330); - break; - - case IDM_SCSI_BASE334: - scsi_set_base(hmenu, 0x334, IDM_SCSI_BASE334); - break; - - case IDM_SCSI_IRQ9: - scsi_set_irq(hmenu, 9, IDM_SCSI_IRQ9); - break; - - case IDM_SCSI_IRQ10: - scsi_set_irq(hmenu, 10, IDM_SCSI_IRQ10); - break; - - case IDM_SCSI_IRQ11: - scsi_set_irq(hmenu, 11, IDM_SCSI_IRQ11); - break; - - case IDM_SCSI_IRQ12: - scsi_set_irq(hmenu, 12, IDM_SCSI_IRQ12); - break; - - case IDM_SCSI_IRQ14: - scsi_set_irq(hmenu, 14, IDM_SCSI_IRQ14); - break; - - case IDM_SCSI_IRQ15: - scsi_set_irq(hmenu, 15, IDM_SCSI_IRQ15); - break; - - case IDM_SCSI_DMA5: - scsi_set_dma(hmenu, 5, IDM_SCSI_DMA5); - break; - - case IDM_SCSI_DMA6: - scsi_set_dma(hmenu, 6, IDM_SCSI_DMA6); - break; - - case IDM_SCSI_DMA7: - scsi_set_dma(hmenu, 7, IDM_SCSI_DMA7); - break; - - case IDM_CDROM_EMPTY: - if (cdrom_drive == 0) - { - /* Switch from empty to empty. Do nothing. */ - break; - } - cdrom->exit(); - cdrom_close(); - cdrom_null_open(0); - if (cdrom_enabled) - { - /* Signal disc change to the emulated machine. */ - SCSICDROM_Insert(); - } - CheckMenuItem(hmenu, IDM_CDROM_REAL + cdrom_drive, MF_UNCHECKED); - CheckMenuItem(hmenu, IDM_CDROM_ISO, MF_UNCHECKED); - old_cdrom_drive = cdrom_drive; - cdrom_drive=0; - CheckMenuItem(hmenu, IDM_CDROM_EMPTY, MF_CHECKED); - saveconfig(); - break; - - case IDM_CDROM_RELOAD: - win_cdrom_reload(); - break; - - case IDM_CDROM_ISO: - if (!getfile(hwnd,"CD-ROM image (*.ISO)\0*.ISO\0All files (*.*)\0*.*\0",iso_path)) - { - /* if (!cdrom_enabled) - { - if (MessageBox(NULL,"This will reset 86Box!\nOkay to continue?","86Box",MB_OKCANCEL) != IDOK) - break; - } */ - old_cdrom_drive = cdrom_drive; - strcpy(temp_iso_path, openfilestring); - // if ((strcmp(iso_path, temp_iso_path) == 0) && (cdrom_drive == 200) && cdrom_enabled) - if ((strcmp(iso_path, temp_iso_path) == 0) && (cdrom_drive == 200)) - { - /* Switching from ISO to the same ISO. Do nothing. */ - break; - } - cdrom->exit(); - cdrom_close(); - iso_open(temp_iso_path); - if (cdrom_enabled) - { - /* Signal disc change to the emulated machine. */ - SCSICDROM_Insert(); - } - CheckMenuItem(hmenu, IDM_CDROM_REAL + cdrom_drive, MF_UNCHECKED); - // CheckMenuItem(hmenu, IDM_CDROM_DISABLED, MF_UNCHECKED); - CheckMenuItem(hmenu, IDM_CDROM_ISO, MF_UNCHECKED); - cdrom_drive = 200; - CheckMenuItem(hmenu, IDM_CDROM_ISO, MF_CHECKED); - saveconfig(); - /* if (!cdrom_enabled) - { - pause = 1; - Sleep(100); - cdrom_enabled = 1; - saveconfig(); - resetpchard(); - pause = 0; - } */ - } - break; - - default: - if (LOWORD(wParam)>IDM_CDROM_REAL && LOWORD(wParam)<(IDM_CDROM_REAL+100)) - { - /* if (!cdrom_enabled) - { - if (MessageBox(NULL,"This will reset 86Box!\nOkay to continue?","86Box",MB_OKCANCEL) != IDOK) - break; - } */ - new_cdrom_drive = LOWORD(wParam)-IDM_CDROM_REAL; - // if ((cdrom_drive == new_cdrom_drive) && cdrom_enabled) - if (cdrom_drive == new_cdrom_drive) - { - /* Switching to the same drive. Do nothing. */ - break; - } - old_cdrom_drive = cdrom_drive; - cdrom->exit(); - cdrom_close(); - ioctl_open(new_cdrom_drive); - if (cdrom_enabled) - { - /* Signal disc change to the emulated machine. */ - SCSICDROM_Insert(); - } - CheckMenuItem(hmenu, IDM_CDROM_REAL + cdrom_drive, MF_UNCHECKED); - // CheckMenuItem(hmenu, IDM_CDROM_DISABLED, MF_UNCHECKED); - CheckMenuItem(hmenu, IDM_CDROM_ISO, MF_UNCHECKED); - cdrom_drive = new_cdrom_drive; - CheckMenuItem(hmenu, IDM_CDROM_REAL + cdrom_drive, MF_CHECKED); - saveconfig(); - /* if (!cdrom_enabled) - { - pause = 1; - Sleep(100); - cdrom_enabled = 1; - saveconfig(); - resetpchard(); - pause = 0; - } */ - } - break; - } - return 0; - - case WM_INPUT: - { - UINT size; - RAWINPUT *raw; - - if (!infocus) - break; - - GetRawInputData((HRAWINPUT)lParam, RID_INPUT, NULL, &size, sizeof(RAWINPUTHEADER)); - - raw = malloc(size); - - if (raw == NULL) - { - return 0; - } - - /* Here we read the raw input data for the keyboard */ - ri_size = GetRawInputData((HRAWINPUT)(lParam), RID_INPUT, raw, &size, sizeof(RAWINPUTHEADER)); - - if(ri_size != size) - { - return 0; - } - - /* If the input is keyboard, we process it */ - if (raw->header.dwType == RIM_TYPEKEYBOARD) - { - const RAWKEYBOARD rawKB = raw->data.keyboard; - USHORT scancode = rawKB.MakeCode; - - // pclog("Keyboard input received: S:%X VK:%X F:%X\n", c, d, e); - - /* If it's not a scan code that starts with 0xE1 */ - if (!(rawKB.Flags & RI_KEY_E1)) - { - // pclog("Non-E1 triggered, make code is %04X\n", rawKB.MakeCode); - if (rawKB.Flags & RI_KEY_E0) - scancode |= (0xE0 << 8); - - /* Remap it according to the list from the Registry */ - scancode = scancode_map[scancode]; - - if ((scancode >> 8) == 0xF0) - scancode |= 0x100; /* Extended key code in disambiguated format */ - else if ((scancode >> 8) == 0xE0) - scancode |= 0x80; /* Normal extended key code */ - - /* If it's not 0 (therefore not 0xE1, 0xE2, etc), - then pass it on to the rawinputkey array */ - if (!(scancode & 0xf00)) - { - rawinputkey[scancode & 0x1ff] = !(rawKB.Flags & RI_KEY_BREAK); - recv_key[scancode & 0x1ff] = rawinputkey[scancode & 0x1ff]; - } - } - else - { - // pclog("E1 triggered, make code is %04X\n", rawKB.MakeCode); - if (rawKB.MakeCode == 0x1D) - scancode = 0xFF; - if (!(scancode & 0xf00)) - { - rawinputkey[scancode & 0x1ff] = !(rawKB.Flags & RI_KEY_BREAK); - recv_key[scancode & 0x1ff] = rawinputkey[scancode & 0x1ff]; - } - } - } - free(raw); - - } - break; - - case WM_SETFOCUS: - infocus=1; - // QueryPerformanceCounter(&counter_posold); -// pclog("Set focus!\n"); - break; - case WM_KILLFOCUS: - infocus=0; - if (mousecapture) - { - ClipCursor(&oldclip); - ShowCursor(TRUE); - mousecapture=0; - } -// pclog("Lost focus!\n"); - memset(rawinputkey, 0, sizeof(rawinputkey)); - if (video_fullscreen) - leave_fullscreen_flag = 1; - break; - - case WM_LBUTTONUP: - if (!mousecapture && !video_fullscreen) - { - RECT pcclip; - - GetClipCursor(&oldclip); - GetWindowRect(hwnd, &pcclip); - pcclip.left += GetSystemMetrics(SM_CXFIXEDFRAME) + 10; - pcclip.right -= GetSystemMetrics(SM_CXFIXEDFRAME) + 10; - pcclip.top += GetSystemMetrics(SM_CXFIXEDFRAME) + GetSystemMetrics(SM_CYMENUSIZE) + GetSystemMetrics(SM_CYCAPTION) + 10; - pcclip.bottom -= GetSystemMetrics(SM_CXFIXEDFRAME) + 10; - ClipCursor(&pcclip); - mousecapture = 1; -// ShowCursor(FALSE); - while (1) - { - if (ShowCursor(FALSE) < 0) break; - } - } - break; - - case WM_MBUTTONUP: - if (!(mouse_get_type(mouse_type) & MOUSE_TYPE_3BUTTON)) - releasemouse(); - break; - - case WM_ENTERMENULOOP: -// if (key[KEY_ALT] || key[KEY_ALTGR]) return 0; - break; - - case WM_SIZE: - winsizex=lParam&0xFFFF; - winsizey=lParam>>16; - - if (vid_apis[video_fullscreen][vid_api].resize) - { - startblit(); - video_wait_for_blit(); - vid_apis[video_fullscreen][vid_api].resize(winsizex, winsizey); - endblit(); - } - - if (mousecapture) - { - RECT pcclip; - - GetWindowRect(hwnd, &pcclip); - pcclip.left += GetSystemMetrics(SM_CXFIXEDFRAME) + 10; - pcclip.right -= GetSystemMetrics(SM_CXFIXEDFRAME) + 10; - pcclip.top += GetSystemMetrics(SM_CXFIXEDFRAME) + GetSystemMetrics(SM_CYMENUSIZE) + GetSystemMetrics(SM_CYCAPTION) + 10; - pcclip.bottom -= GetSystemMetrics(SM_CXFIXEDFRAME) + 10; - ClipCursor(&pcclip); - } - if (window_remember) - { - GetWindowRect(hwnd, &rect); - window_x = rect.left; - window_y = rect.top; - window_w = rect.right - rect.left; - window_h = rect.bottom - rect.top; - save_window_pos = 1; - } - break; - - case WM_MOVE: - if (window_remember) - { - GetWindowRect(hwnd, &rect); - window_x = rect.left; - window_y = rect.top; - window_w = rect.right - rect.left; - window_h = rect.bottom - rect.top; - save_window_pos = 1; - } - break; - - case WM_TIMER: - if (wParam == TIMER_1SEC) - onesec(); - break; - - case WM_RESETD3D: - startblit(); - if (video_fullscreen) - d3d_fs_reset(); - else - d3d_reset(); - endblit(); - break; - - case WM_LEAVEFULLSCREEN: - startblit(); - mouse_close(); - vid_apis[1][vid_api].close(); - video_fullscreen = 0; - vid_apis[0][vid_api].init(ghwnd); - mouse_init(); - endblit(); - device_force_redraw(); - break; - - case WM_KEYDOWN: - case WM_SYSKEYDOWN: - case WM_KEYUP: - case WM_SYSKEYUP: -// if (mousecapture) - return 0; -// return DefWindowProc (hwnd, message, wParam, lParam); - - - case WM_DESTROY: - UnhookWindowsHookEx( hKeyboardHook ); - KillTimer(hwnd, TIMER_1SEC); - PostQuitMessage (0); /* send a WM_QUIT to the message queue */ - break; - - case WM_SYSCOMMAND: - if (wParam == SC_KEYMENU && HIWORD(lParam) <= 0 && (video_fullscreen || mousecapture)) - return 0; /*disable ALT key for menu*/ - - default: -// pclog("Def %08X %i\n",message,message); - return DefWindowProc (hwnd, message, wParam, lParam); - } - return 0; -} - -LRESULT CALLBACK subWindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) -{ - switch (message) - { - default: - return DefWindowProc(hwnd, message, wParam, lParam); - } - return 0; -} diff --git a/src/win.h b/src/win.h deleted file mode 100644 index 5807bb2e9..000000000 --- a/src/win.h +++ /dev/null @@ -1,38 +0,0 @@ -/* Copyright holders: Sarah Walker - see COPYING for more details -*/ -extern HINSTANCE hinstance; -extern HWND ghwnd; -extern int mousecapture; - -#ifdef __cplusplus -extern "C" { -#endif - -#define szClassName "86BoxMainWnd" -#define szSubClassName "86BoxSubWnd" - -void leave_fullscreen(); - -#ifdef __cplusplus -} -#endif - - -void status_open(HWND hwnd); -extern HWND status_hwnd; -extern int status_is_open; - -void hdconf_open(HWND hwnd); - -void config_open(HWND hwnd); - -void deviceconfig_open(HWND hwnd, struct device_t *device); -void joystickconfig_open(HWND hwnd, int joy_nr, int type); - -extern char openfilestring[260]; - -int getfile(HWND hwnd, char *f, char *fn); -int getsfile(HWND hwnd, char *f, char *fn); - -extern int pause; diff --git a/src/x86seg.h b/src/x86seg.h deleted file mode 100644 index 4a36f360b..000000000 --- a/src/x86seg.h +++ /dev/null @@ -1,4 +0,0 @@ -/* Copyright holders: Tenshi - see COPYING for more details -*/ -void do_seg_load(x86seg *s, uint16_t *segdat); diff --git a/src/x87_ops.h b/src/x87_ops.h deleted file mode 100644 index 637c09968..000000000 --- a/src/x87_ops.h +++ /dev/null @@ -1,1123 +0,0 @@ -#include -#include - -#define fplog 0 - -static int rounding_modes[4] = {FE_TONEAREST, FE_DOWNWARD, FE_UPWARD, FE_TOWARDZERO}; - -#define ST(x) cpu_state.ST[((cpu_state.TOP+(x))&7)] - -#define C0 (1<<8) -#define C1 (1<<9) -#define C2 (1<<10) -#define C3 (1<<14) - -#define STATUS_ZERODIVIDE 4 - -#define x87_div(dst, src1, src2) do \ - { \ - if (((double)src2) == 0.0) \ - { \ - cpu_state.npxs |= STATUS_ZERODIVIDE; \ - if (cpu_state.npxc & STATUS_ZERODIVIDE) \ - dst = src1 / (double)src2; \ - else \ - { \ - pclog("FPU : divide by zero\n"); \ - picint(1 << 13); \ - } \ - return 1; \ - } \ - else \ - dst = src1 / (double)src2; \ - } while (0) - -static inline void x87_set_mmx() -{ - cpu_state.TOP = 0; - *(uint64_t *)cpu_state.tag = 0; - cpu_state.ismmx = 1; -} - -static inline void x87_emms() -{ - *cpu_state.tag = 0x0303030303030303ll; - cpu_state.ismmx = 0; -} - -static inline void x87_checkexceptions() -{ -} - -static inline void x87_push(double i) -{ - cpu_state.TOP=(cpu_state.TOP-1)&7; - cpu_state.ST[cpu_state.TOP] = i; - cpu_state.tag[cpu_state.TOP&7] = (i == 0.0) ? 1 : 0; -} - -static inline double x87_pop() -{ - double t = cpu_state.ST[cpu_state.TOP]; - cpu_state.tag[cpu_state.TOP&7] = 3; - cpu_state.TOP=(cpu_state.TOP+1)&7; - return t; -} - -static inline int64_t x87_fround(double b) -{ - int64_t a, c; - - switch ((cpu_state.npxc>>10)&3) - { - case 0: /*Nearest*/ - a = (int64_t)floor(b); - c = (int64_t)floor(b + 1.0); - if ((b - a) < (c - b)) - return a; - else if ((b - a) > (c - b)) - return c; - else - return (a & 1) ? c : a; - case 1: /*Down*/ - return (int64_t)floor(b); - case 2: /*Up*/ - return (int64_t)ceil(b); - case 3: /*Chop*/ - return (int64_t)b; - } -} -#define BIAS80 16383 -#define BIAS64 1023 - -static inline double x87_ld80() -{ - struct { - int16_t begin; - union - { - double d; - uint64_t ll; - } eind; - } test; - test.eind.ll = readmeml(easeg,cpu_state.eaaddr); - test.eind.ll |= (uint64_t)readmeml(easeg,cpu_state.eaaddr+4)<<32; - test.begin = readmemw(easeg,cpu_state.eaaddr+8); - - int64_t exp64 = (((test.begin&0x7fff) - BIAS80)); - int64_t blah = ((exp64 >0)?exp64:-exp64)&0x3ff; - int64_t exp64final = ((exp64 >0)?blah:-blah) +BIAS64; - - int64_t mant64 = (test.eind.ll >> 11) & (0xfffffffffffff); - int64_t sign = (test.begin&0x8000)?1:0; - - if ((test.begin & 0x7fff) == 0x7fff) - exp64final = 0x7ff; - if ((test.begin & 0x7fff) == 0) - exp64final = 0; - if (test.eind.ll & 0x400) - mant64++; - - test.eind.ll = (sign <<63)|(exp64final << 52)| mant64; - - return test.eind.d; -} - -static inline void x87_st80(double d) -{ - struct { - int16_t begin; - union - { - double d; - uint64_t ll; - } eind; - } test; - - test.eind.d=d; - - int64_t sign80 = (test.eind.ll&(0x8000000000000000))?1:0; - int64_t exp80 = test.eind.ll&(0x7ff0000000000000); - int64_t exp80final = (exp80>>52); - int64_t mant80 = test.eind.ll&(0x000fffffffffffff); - int64_t mant80final = (mant80 << 11); - - if (exp80final == 0x7ff) /*Infinity / Nan*/ - { - exp80final = 0x7fff; - mant80final |= (0x8000000000000000); - } - else if (d != 0){ //Zero is a special case - // Elvira wants the 8 and tcalc doesn't - mant80final |= (0x8000000000000000); - //Ca-cyber doesn't like this when result is zero. - exp80final += (BIAS80 - BIAS64); - } - test.begin = (((int16_t)sign80)<<15)| (int16_t)exp80final; - test.eind.ll = mant80final; - - writememl(easeg,cpu_state.eaaddr,test.eind.ll); - writememl(easeg,cpu_state.eaaddr+4,test.eind.ll>>32); - writememw(easeg,cpu_state.eaaddr+8,test.begin); -} - -static inline void x87_st_fsave(int reg) -{ - reg = (cpu_state.TOP + reg) & 7; - - if (cpu_state.tag[reg] & TAG_UINT64) - { - writememl(easeg, cpu_state.eaaddr, cpu_state.MM[reg].q & 0xffffffff); - writememl(easeg, cpu_state.eaaddr + 4, cpu_state.MM[reg].q >> 32); - writememw(easeg, cpu_state.eaaddr + 8, 0x5555); - } - else - x87_st80(cpu_state.ST[reg]); -} - -static inline void x87_ld_frstor(int reg) -{ - reg = (cpu_state.TOP + reg) & 7; - - cpu_state.MM[reg].q = readmemq(easeg, cpu_state.eaaddr); - cpu_state.MM_w4[reg] = readmemw(easeg, cpu_state.eaaddr + 8); - - if (cpu_state.MM_w4[reg] == 0x5555 && cpu_state.tag[reg] == 2) - { - cpu_state.tag[reg] = TAG_UINT64; - cpu_state.ST[reg] = (double)cpu_state.MM[reg].q; - } - else - cpu_state.ST[reg] = x87_ld80(); -} - -static inline void x87_ldmmx(MMX_REG *r, uint16_t *w4) -{ - r->l[0] = readmeml(easeg, cpu_state.eaaddr); - r->l[1] = readmeml(easeg, cpu_state.eaaddr + 4); - *w4 = readmemw(easeg, cpu_state.eaaddr + 8); -} - -static inline void x87_stmmx(MMX_REG r) -{ - writememl(easeg, cpu_state.eaaddr, r.l[0]); - writememl(easeg, cpu_state.eaaddr + 4, r.l[1]); - writememw(easeg, cpu_state.eaaddr + 8, 0xffff); -} - -static inline uint16_t x87_compare(double a, double b) -{ -#if defined i386 || defined __i386 || defined __i386__ || defined _X86_ || defined WIN32 || defined _WIN32 || defined _WIN32 - uint32_t out; - - /* Memory barrier, to force GCC to write to the input parameters - * before the compare rather than after */ - asm volatile ("" : : : "memory"); - - asm( - "fldl %2\n" - "fldl %1\n" - "fclex\n" - "fcompp\n" - "fnstsw %0\n" - : "=m" (out) - : "m" (a), "m" (b) - ); - - return out & (C0|C2|C3); -#else - /* Generic C version is known to give incorrect results in some - * situations, eg comparison of infinity (Unreal) */ - uint32_t out = 0; - - if (a == b) - out |= C3; - else if (a < b) - out |= C0; - - return out; -#endif -} - -static inline uint16_t x87_ucompare(double a, double b) -{ -#if defined i386 || defined __i386 || defined __i386__ || defined _X86_ || defined WIN32 || defined _WIN32 || defined _WIN32 - uint32_t out; - - /* Memory barrier, to force GCC to write to the input parameters - * before the compare rather than after */ - asm volatile ("" : : : "memory"); - - asm( - "fldl %2\n" - "fldl %1\n" - "fclex\n" - "fucompp\n" - "fnstsw %0\n" - : "=m" (out) - : "m" (a), "m" (b) - ); - - return out & (C0|C2|C3); -#else - /* Generic C version is known to give incorrect results in some - * situations, eg comparison of infinity (Unreal) */ - uint32_t out = 0; - - if (a == b) - out |= C3; - else if (a < b) - out |= C0; - - return out; -#endif -} - -typedef union -{ - float s; - uint32_t i; -} x87_ts; - -typedef union -{ - double d; - uint64_t i; -} x87_td; - -#define FP_ENTER() do \ - { \ - if (cr0 & 0xc) \ - { \ - x86_int(7); \ - return 1; \ - } \ - fpucount++; \ - } while (0) - -#include "x87_ops_arith.h" -#include "x87_ops_misc.h" -#include "x87_ops_loadstore.h" - -static int op_nofpu_a16(uint32_t fetchdat) -{ - if (cr0 & 0xc) - { - x86_int(7); - return 1; - } - else - fetch_ea_16(fetchdat); -} -static int op_nofpu_a32(uint32_t fetchdat) -{ - if (cr0 & 0xc) - { - x86_int(7); - return 1; - } - else - fetch_ea_32(fetchdat); -} - -OpFn OP_TABLE(fpu_d8_a16)[32] = -{ - opFADDs_a16, opFMULs_a16, opFCOMs_a16, opFCOMPs_a16, opFSUBs_a16, opFSUBRs_a16, opFDIVs_a16, opFDIVRs_a16, - opFADDs_a16, opFMULs_a16, opFCOMs_a16, opFCOMPs_a16, opFSUBs_a16, opFSUBRs_a16, opFDIVs_a16, opFDIVRs_a16, - opFADDs_a16, opFMULs_a16, opFCOMs_a16, opFCOMPs_a16, opFSUBs_a16, opFSUBRs_a16, opFDIVs_a16, opFDIVRs_a16, - opFADD, opFMUL, opFCOM, opFCOMP, opFSUB, opFSUBR, opFDIV, opFDIVR -}; -OpFn OP_TABLE(fpu_d8_a32)[32] = -{ - opFADDs_a32, opFMULs_a32, opFCOMs_a32, opFCOMPs_a32, opFSUBs_a32, opFSUBRs_a32, opFDIVs_a32, opFDIVRs_a32, - opFADDs_a32, opFMULs_a32, opFCOMs_a32, opFCOMPs_a32, opFSUBs_a32, opFSUBRs_a32, opFDIVs_a32, opFDIVRs_a32, - opFADDs_a32, opFMULs_a32, opFCOMs_a32, opFCOMPs_a32, opFSUBs_a32, opFSUBRs_a32, opFDIVs_a32, opFDIVRs_a32, - opFADD, opFMUL, opFCOM, opFCOMP, opFSUB, opFSUBR, opFDIV, opFDIVR -}; - -OpFn OP_TABLE(fpu_d9_a16)[256] = -{ - opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, - opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, - opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, - opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, - opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, - opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, - - opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, - opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, - opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, - opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, - opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, - opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, - - opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, - opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, - opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, - opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, - opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, - opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, - - opFLD, opFLD, opFLD, opFLD, opFLD, opFLD, opFLD, opFLD, - opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, - opFNOP, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, /*Invalid*/ - opFCHS, opFABS, ILLEGAL, ILLEGAL, opFTST, opFXAM, ILLEGAL, ILLEGAL, - opFLD1, opFLDL2T, opFLDL2E, opFLDPI, opFLDEG2, opFLDLN2, opFLDZ, ILLEGAL, - opF2XM1, opFYL2X, opFPTAN, opFPATAN, ILLEGAL, opFPREM1, opFDECSTP, opFINCSTP, - opFPREM, opFYL2XP1,opFSQRT, opFSINCOS, opFRNDINT, opFSCALE, opFSIN, opFCOS -}; - -OpFn OP_TABLE(fpu_d9_a32)[256] = -{ - opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, - opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, - opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, - opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, - opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, - opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, - - opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, - opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, - opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, - opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, - opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, - opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, - - opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, - opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, - opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, - opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, - opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, - opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, - - opFLD, opFLD, opFLD, opFLD, opFLD, opFLD, opFLD, opFLD, - opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, - opFNOP, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, /*Invalid*/ - opFCHS, opFABS, ILLEGAL, ILLEGAL, opFTST, opFXAM, ILLEGAL, ILLEGAL, - opFLD1, opFLDL2T, opFLDL2E, opFLDPI, opFLDEG2, opFLDLN2, opFLDZ, ILLEGAL, - opF2XM1, opFYL2X, opFPTAN, opFPATAN, ILLEGAL, opFPREM1, opFDECSTP, opFINCSTP, - opFPREM, opFYL2XP1,opFSQRT, opFSINCOS, opFRNDINT, opFSCALE, opFSIN, opFCOS -}; - -OpFn OP_TABLE(fpu_da_a16)[256] = -{ - opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, - opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, - opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, - opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, - opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, - opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, - opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, - opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, - - opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, - opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, - opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, - opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, - opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, - opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, - opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, - opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, - - opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, - opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, - opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, - opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, - opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, - opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, - opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, - opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, - - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - ILLEGAL, opFUCOMPP, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, -}; -OpFn OP_TABLE(fpu_da_a32)[256] = -{ - opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, - opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, - opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, - opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, - opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, - opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, - opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, - opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, - - opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, - opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, - opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, - opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, - opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, - opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, - opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, - opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, - - opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, - opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, - opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, - opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, - opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, - opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, - opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, - opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, - - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - ILLEGAL, opFUCOMPP, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, -}; - -OpFn OP_TABLE(fpu_686_da_a16)[256] = -{ - opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, - opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, - opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, - opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, - opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, - opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, - opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, - opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, - - opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, - opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, - opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, - opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, - opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, - opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, - opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, - opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, - - opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, - opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, - opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, - opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, - opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, - opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, - opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, - opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, - - opFCMOVB, opFCMOVB, opFCMOVB, opFCMOVB, opFCMOVB, opFCMOVB, opFCMOVB, opFCMOVB, - opFCMOVE, opFCMOVE, opFCMOVE, opFCMOVE, opFCMOVE, opFCMOVE, opFCMOVE, opFCMOVE, - opFCMOVBE, opFCMOVBE, opFCMOVBE, opFCMOVBE, opFCMOVBE, opFCMOVBE, opFCMOVBE, opFCMOVBE, - opFCMOVU, opFCMOVU, opFCMOVU, opFCMOVU, opFCMOVU, opFCMOVU, opFCMOVU, opFCMOVU, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - ILLEGAL, opFUCOMPP, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, -}; -OpFn OP_TABLE(fpu_686_da_a32)[256] = -{ - opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, - opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, - opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, - opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, - opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, - opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, - opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, - opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, - - opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, - opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, - opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, - opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, - opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, - opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, - opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, - opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, - - opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, - opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, - opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, - opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, - opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, - opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, - opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, - opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, - - opFCMOVB, opFCMOVB, opFCMOVB, opFCMOVB, opFCMOVB, opFCMOVB, opFCMOVB, opFCMOVB, - opFCMOVE, opFCMOVE, opFCMOVE, opFCMOVE, opFCMOVE, opFCMOVE, opFCMOVE, opFCMOVE, - opFCMOVBE, opFCMOVBE, opFCMOVBE, opFCMOVBE, opFCMOVBE, opFCMOVBE, opFCMOVBE, opFCMOVBE, - opFCMOVU, opFCMOVU, opFCMOVU, opFCMOVU, opFCMOVU, opFCMOVU, opFCMOVU, opFCMOVU, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - ILLEGAL, opFUCOMPP, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, -}; - -OpFn OP_TABLE(fpu_db_a16)[256] = -{ - opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, - opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, - - opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, - opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, - - opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, - opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, - - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - ILLEGAL, opFNOP, opFCLEX, opFINIT, opFNOP, opFNOP, ILLEGAL, ILLEGAL, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, -}; -OpFn OP_TABLE(fpu_db_a32)[256] = -{ - opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, - opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, - - opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, - opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, - - opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, - opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, - - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - ILLEGAL, opFNOP, opFCLEX, opFINIT, opFNOP, opFNOP, ILLEGAL, ILLEGAL, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, -}; - -OpFn OP_TABLE(fpu_686_db_a16)[256] = -{ - opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, - opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, - - opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, - opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, - - opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, - opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, - - opFCMOVNB, opFCMOVNB, opFCMOVNB, opFCMOVNB, opFCMOVNB, opFCMOVNB, opFCMOVNB, opFCMOVNB, - opFCMOVNE, opFCMOVNE, opFCMOVNE, opFCMOVNE, opFCMOVNE, opFCMOVNE, opFCMOVNE, opFCMOVNE, - opFCMOVNBE, opFCMOVNBE, opFCMOVNBE, opFCMOVNBE, opFCMOVNBE, opFCMOVNBE, opFCMOVNBE, opFCMOVNBE, - opFCMOVNU, opFCMOVNU, opFCMOVNU, opFCMOVNU, opFCMOVNU, opFCMOVNU, opFCMOVNU, opFCMOVNU, - ILLEGAL, opFNOP, opFCLEX, opFINIT, opFNOP, opFNOP, ILLEGAL, ILLEGAL, - opFUCOMI, opFUCOMI, opFUCOMI, opFUCOMI, opFUCOMI, opFUCOMI, opFUCOMI, opFUCOMI, - opFCOMI, opFCOMI, opFCOMI, opFCOMI, opFCOMI, opFCOMI, opFCOMI, opFCOMI, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, -}; -OpFn OP_TABLE(fpu_686_db_a32)[256] = -{ - opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, - opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, - - opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, - opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, - - opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, - opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, - - opFCMOVNB, opFCMOVNB, opFCMOVNB, opFCMOVNB, opFCMOVNB, opFCMOVNB, opFCMOVNB, opFCMOVNB, - opFCMOVNE, opFCMOVNE, opFCMOVNE, opFCMOVNE, opFCMOVNE, opFCMOVNE, opFCMOVNE, opFCMOVNE, - opFCMOVNBE, opFCMOVNBE, opFCMOVNBE, opFCMOVNBE, opFCMOVNBE, opFCMOVNBE, opFCMOVNBE, opFCMOVNBE, - opFCMOVNU, opFCMOVNU, opFCMOVNU, opFCMOVNU, opFCMOVNU, opFCMOVNU, opFCMOVNU, opFCMOVNU, - ILLEGAL, opFNOP, opFCLEX, opFINIT, opFNOP, opFNOP, ILLEGAL, ILLEGAL, - opFUCOMI, opFUCOMI, opFUCOMI, opFUCOMI, opFUCOMI, opFUCOMI, opFUCOMI, opFUCOMI, - opFCOMI, opFCOMI, opFCOMI, opFCOMI, opFCOMI, opFCOMI, opFCOMI, opFCOMI, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, -}; - -OpFn OP_TABLE(fpu_dc_a16)[32] = -{ - opFADDd_a16, opFMULd_a16, opFCOMd_a16, opFCOMPd_a16, opFSUBd_a16, opFSUBRd_a16, opFDIVd_a16, opFDIVRd_a16, - opFADDd_a16, opFMULd_a16, opFCOMd_a16, opFCOMPd_a16, opFSUBd_a16, opFSUBRd_a16, opFDIVd_a16, opFDIVRd_a16, - opFADDd_a16, opFMULd_a16, opFCOMd_a16, opFCOMPd_a16, opFSUBd_a16, opFSUBRd_a16, opFDIVd_a16, opFDIVRd_a16, - opFADDr, opFMULr, opFCOM, opFCOMP, opFSUBRr, opFSUBr, opFDIVRr, opFDIVr -}; -OpFn OP_TABLE(fpu_dc_a32)[32] = -{ - opFADDd_a32, opFMULd_a32, opFCOMd_a32, opFCOMPd_a32, opFSUBd_a32, opFSUBRd_a32, opFDIVd_a32, opFDIVRd_a32, - opFADDd_a32, opFMULd_a32, opFCOMd_a32, opFCOMPd_a32, opFSUBd_a32, opFSUBRd_a32, opFDIVd_a32, opFDIVRd_a32, - opFADDd_a32, opFMULd_a32, opFCOMd_a32, opFCOMPd_a32, opFSUBd_a32, opFSUBRd_a32, opFDIVd_a32, opFDIVRd_a32, - opFADDr, opFMULr, opFCOM, opFCOMP, opFSUBRr, opFSUBr, opFDIVRr, opFDIVr -}; - -OpFn OP_TABLE(fpu_dd_a16)[256] = -{ - opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, - opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, - opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, - opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, - - opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, - opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, - opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, - opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, - - opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, - opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, - opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, - opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, - - opFFREE, opFFREE, opFFREE, opFFREE, opFFREE, opFFREE, opFFREE, opFFREE, - opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, - opFST, opFST, opFST, opFST, opFST, opFST, opFST, opFST, - opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, - opFUCOM, opFUCOM, opFUCOM, opFUCOM, opFUCOM, opFUCOM, opFUCOM, opFUCOM, - opFUCOMP, opFUCOMP, opFUCOMP, opFUCOMP, opFUCOMP, opFUCOMP, opFUCOMP, opFUCOMP, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, -}; -OpFn OP_TABLE(fpu_dd_a32)[256] = -{ - opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, - opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, - opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, - opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, - - opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, - opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, - opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, - opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, - - opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, - opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, - opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, - opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, - - opFFREE, opFFREE, opFFREE, opFFREE, opFFREE, opFFREE, opFFREE, opFFREE, - opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, - opFST, opFST, opFST, opFST, opFST, opFST, opFST, opFST, - opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, - opFUCOM, opFUCOM, opFUCOM, opFUCOM, opFUCOM, opFUCOM, opFUCOM, opFUCOM, - opFUCOMP, opFUCOMP, opFUCOMP, opFUCOMP, opFUCOMP, opFUCOMP, opFUCOMP, opFUCOMP, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, -}; - -OpFn OP_TABLE(fpu_de_a16)[256] = -{ - opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, - opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, - opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, - opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, - opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, - opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, - opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, - opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, - - opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, - opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, - opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, - opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, - opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, - opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, - opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, - opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, - - opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, - opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, - opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, - opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, - opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, - opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, - opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, - opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, - - opFADDP, opFADDP, opFADDP, opFADDP, opFADDP, opFADDP, opFADDP, opFADDP, - opFMULP, opFMULP, opFMULP, opFMULP, opFMULP, opFMULP, opFMULP, opFMULP, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - ILLEGAL, opFCOMPP, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, - opFSUBP, opFSUBP, opFSUBP, opFSUBP, opFSUBP, opFSUBP, opFSUBP, opFSUBP, - opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, - opFDIVP, opFDIVP, opFDIVP, opFDIVP, opFDIVP, opFDIVP, opFDIVP, opFDIVP, -}; - -OpFn OP_TABLE(fpu_de_a32)[256] = -{ - opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, - opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, - opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, - opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, - opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, - opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, - opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, - opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, - - opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, - opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, - opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, - opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, - opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, - opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, - opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, - opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, - - opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, - opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, - opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, - opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, - opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, - opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, - opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, - opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, - - opFADDP, opFADDP, opFADDP, opFADDP, opFADDP, opFADDP, opFADDP, opFADDP, - opFMULP, opFMULP, opFMULP, opFMULP, opFMULP, opFMULP, opFMULP, opFMULP, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - ILLEGAL, opFCOMPP, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, - opFSUBP, opFSUBP, opFSUBP, opFSUBP, opFSUBP, opFSUBP, opFSUBP, opFSUBP, - opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, - opFDIVP, opFDIVP, opFDIVP, opFDIVP, opFDIVP, opFDIVP, opFDIVP, opFDIVP, -}; - -OpFn OP_TABLE(fpu_df_a16)[256] = -{ - opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, - opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, - FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, - FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, - - opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, - opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, - FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, - FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, - - opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, - opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, - FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, - FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, - - opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, - opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, - opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, - opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, - opFSTSW_AX, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, -}; -OpFn OP_TABLE(fpu_df_a32)[256] = -{ - opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, - opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, - FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, - FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, - - opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, - opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, - FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, - FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, - - opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, - opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, - FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, - FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, - - opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, - opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, - opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, - opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, - opFSTSW_AX, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, -}; - -OpFn OP_TABLE(fpu_686_df_a16)[256] = -{ - opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, - opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, - FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, - FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, - - opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, - opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, - FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, - FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, - - opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, - opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, - FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, - FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, - - opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, - opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, - opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, - opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, - opFSTSW_AX, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - opFUCOMIP, opFUCOMIP, opFUCOMIP, opFUCOMIP, opFUCOMIP, opFUCOMIP, opFUCOMIP, opFUCOMIP, - opFCOMIP, opFCOMIP, opFCOMIP, opFCOMIP, opFCOMIP, opFCOMIP, opFCOMIP, opFCOMIP, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, -}; -OpFn OP_TABLE(fpu_686_df_a32)[256] = -{ - opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, - opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, - FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, - FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, - - opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, - opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, - FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, - FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, - - opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, - opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, - FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, - FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, - - opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, - opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, - opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, - opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, - opFSTSW_AX, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - opFUCOMIP, opFUCOMIP, opFUCOMIP, opFUCOMIP, opFUCOMIP, opFUCOMIP, opFUCOMIP, opFUCOMIP, - opFCOMIP, opFCOMIP, opFCOMIP, opFCOMIP, opFCOMIP, opFCOMIP, opFCOMIP, opFCOMIP, - ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, -}; - -OpFn OP_TABLE(nofpu_a16)[256] = -{ - op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, - op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, - op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, - op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, - op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, - op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, - op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, - op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, - - op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, - op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, - op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, - op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, - op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, - op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, - op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, - op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, - - op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, - op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, - op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, - op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, - op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, - op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, - op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, - op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, - - op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, - op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, - op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, - op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, - op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, - op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, - op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, - op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, -}; -OpFn OP_TABLE(nofpu_a32)[256] = -{ - op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, - op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, - op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, - op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, - op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, - op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, - op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, - op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, - - op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, - op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, - op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, - op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, - op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, - op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, - op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, - op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, - - op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, - op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, - op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, - op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, - op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, - op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, - op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, - op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, - - op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, - op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, - op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, - op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, - op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, - op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, - op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, - op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, -}; diff --git a/src/xtide.c b/src/xtide.c index b464d0231..e7997d8fa 100644 --- a/src/xtide.c +++ b/src/xtide.c @@ -1,61 +1,224 @@ -/* Copyright holders: Sarah Walker - see COPYING for more details -*/ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * XT IDE controller emulation. + * + * Version: @(#)xtide.c 1.0.1 2017/06/03 + * + * Authors: Sarah Walker, + * Miran Grca, + * Copyright 2008-2017 Sarah Walker. + * Copyright 2016-2017 Miran Grca. + */ +#include #include "ibm.h" - #include "io.h" +#include "mem.h" +#include "rom.h" +#include "device.h" #include "ide.h" #include "xtide.h" -uint8_t xtide_high; -void xtide_write(uint16_t port, uint8_t val, void *priv) +#define XTIDE_ROM_PATH L"roms/ide_xt.bin" +#define ATIDE_ROM_PATH L"roms/ide_at.bin" + + +typedef struct xtide_t { + uint8_t data_high; + rom_t bios_rom; +} xtide_t; + + +static void xtide_write(uint16_t port, uint8_t val, void *p) +{ + xtide_t *xtide = (xtide_t *)p; + switch (port & 0xf) { case 0x0: - writeidew(0, val | (xtide_high << 8)); + writeidew(4, val | (xtide->data_high << 8)); return; case 0x1: case 0x2: case 0x3: case 0x4: case 0x5: case 0x6: case 0x7: - writeide(0, (port & 0xf) | 0x1f0, val); + writeide(4, (port & 0xf) | 0x1f0, val); return; case 0x8: - xtide_high = val; + xtide->data_high = val; return; case 0xe: - writeide(0, 0x3f6, val); + writeide(4, 0x3f6, val); return; } } -uint8_t xtide_read(uint16_t port, void *priv) + +static uint8_t xtide_read(uint16_t port, void *p) { + xtide_t *xtide = (xtide_t *)p; uint16_t tempw; + switch (port & 0xf) { case 0x0: - tempw = readidew(0); - xtide_high = tempw >> 8; + tempw = readidew(4); + xtide->data_high = tempw >> 8; return tempw & 0xff; case 0x1: case 0x2: case 0x3: case 0x4: case 0x5: case 0x6: case 0x7: - return readide(0, (port & 0xf) | 0x1f0); + return readide(4, (port & 0xf) | 0x1f0); case 0x8: - return xtide_high; + return xtide->data_high; case 0xe: - return readide(0, 0x3f6); + return readide(4, 0x3f6); + + default: + return 0xff; } } -void xtide_init() + +static void *xtide_init(void) { - ide_init(); - io_sethandler(0x0300, 0x0010, xtide_read, NULL, NULL, xtide_write, NULL, NULL, NULL); + xtide_t *xtide = malloc(sizeof(xtide_t)); + memset(xtide, 0, sizeof(xtide_t)); + + rom_init(&xtide->bios_rom, XTIDE_ROM_PATH, 0xc8000, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL); + ide_xtide_init(); + io_sethandler(0x0300, 0x0010, xtide_read, NULL, NULL, xtide_write, NULL, NULL, xtide); + + return xtide; } + + +static void *xtide_at_init(void) +{ + xtide_t *xtide = malloc(sizeof(xtide_t)); + memset(xtide, 0, sizeof(xtide_t)); + + rom_init(&xtide->bios_rom, ATIDE_ROM_PATH, 0xc8000, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL); + ide_init(); + + return xtide; +} + + +static void *xtide_ps2_init(void) +{ + xtide_t *xtide = malloc(sizeof(xtide_t)); + memset(xtide, 0, sizeof(xtide_t)); + + rom_init(&xtide->bios_rom, L"roms/SIDE1V12.BIN", 0xc8000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + ide_xtide_init(); + io_sethandler(0x0360, 0x0010, xtide_read, NULL, NULL, xtide_write, NULL, NULL, xtide); + + return xtide; +} + + +static void *xtide_at_ps2_init(void) +{ + xtide_t *xtide = malloc(sizeof(xtide_t)); + memset(xtide, 0, sizeof(xtide_t)); + + rom_init(&xtide->bios_rom, L"roms/ide_at_1_1_5.bin", 0xc8000, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL); + ide_init(); + + return xtide; +} + + +static void xtide_close(void *p) +{ + xtide_t *xtide = (xtide_t *)p; + + free(xtide); +} + + +static int xtide_available(void) +{ + return rom_present(L"roms/ide_xt.bin"); +} + + +static int xtide_at_available(void) +{ + return rom_present(L"roms/ide_at.bin"); +} + + +static int xtide_ps2_available(void) +{ + return rom_present(L"roms/SIDE1V12.BIN"); +} + + +static int xtide_at_ps2_available(void) +{ + return rom_present(L"roms/ide_at_1_1_5.bin"); +} + + +device_t xtide_device = +{ + "XTIDE", + 0, + xtide_init, + xtide_close, + xtide_available, + NULL, + NULL, + NULL, + NULL +}; +device_t xtide_at_device = +{ + "XTIDE (AT)", + DEVICE_AT, + xtide_at_init, + xtide_close, + xtide_at_available, + NULL, + NULL, + NULL, + NULL +}; + +device_t xtide_ps2_device = +{ + "XTIDE (PS/2)", + DEVICE_PS2, + xtide_ps2_init, + xtide_close, + xtide_ps2_available, + NULL, + NULL, + NULL, + NULL +}; + +device_t xtide_at_ps2_device = +{ + "XTIDE (AT) (PS/2)", + DEVICE_PS2, + xtide_at_ps2_init, + xtide_close, + xtide_at_ps2_available, + NULL, + NULL, + NULL, + NULL +}; diff --git a/src/xtide.h b/src/xtide.h index bc1761369..f1f0a3da2 100644 --- a/src/xtide.h +++ b/src/xtide.h @@ -1,4 +1,28 @@ -/* Copyright holders: Sarah Walker - see COPYING for more details -*/ -void xtide_init(); +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * XT IDE controller emulation. + * + * Version: @(#)xtide.h 1.0.1 2017/06/03 + * + * Authors: Sarah Walker, + * Miran Grca, + * Copyright 2008-2017 Sarah Walker. + * Copyright 2016-2017 Miran Grca. + */ +#ifndef EMU_XTIDE_H +# define EMU_XTIDE_H + + +extern device_t xtide_device; +extern device_t xtide_at_device; +extern device_t xtide_ps2_device; +extern device_t xtide_at_ps2_device; + + +#endif /*EMU_XTIDE_H*/